aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuka Perkov <luka.perkov@sartura.hr>2016-06-23 13:57:21 +0200
committerGitHub <noreply@github.com>2016-06-23 13:57:21 +0200
commit282b917e47d9ae5017e1e426face9b75cb7aabd0 (patch)
tree3284ca2d20d9c8d7a4563c6446675c1ecf3feac2
parent34d432b05312de6d9575c559db8209809489096d (diff)
parent441a9c879ba6562ea9f431cf33bbb0c0400d5fd0 (diff)
downloadmaster-187ad058-282b917e47d9ae5017e1e426face9b75cb7aabd0.tar.gz
master-187ad058-282b917e47d9ae5017e1e426face9b75cb7aabd0.tar.bz2
master-187ad058-282b917e47d9ae5017e1e426face9b75cb7aabd0.zip
Merge pull request #11 from wigyori/master
pull req for 4.4.12, ar71xx/mediatek updates, package upgrades
-rw-r--r--config/Config-build.in5
-rw-r--r--config/Config-kernel.in6
-rw-r--r--include/kernel-version.mk4
-rw-r--r--include/target.mk1
-rw-r--r--package/boot/uboot-envtools/files/ar71xx2
-rw-r--r--package/boot/uboot-socfpga/Makefile4
-rw-r--r--package/boot/uboot-socfpga/patches/0001-arm-socfpga-Drop-space-after-loadaddr-in-extra-env.patch101
-rw-r--r--package/boot/uboot-socfpga/patches/0001-arm-socfpga-Tweak-SoCkit-default-env-for-OpenWRT.patch65
-rw-r--r--package/boot/uboot-socfpga/patches/0002-arm-socfpga-Tweak-SoCkit-default-env-for-OpenWRT.patch65
-rw-r--r--package/devel/gdb-arc/Makefile94
-rw-r--r--package/devel/gdb-arc/patches/100-no_extern_inline.patch32
-rw-r--r--package/devel/gdb-arc/patches/110-no_testsuite.patch21
-rw-r--r--package/devel/gdb-arc/patches/120-fix-compile-flag-mismatch.patch11
-rw-r--r--package/devel/gdb/Makefile2
-rw-r--r--package/firmware/am33x-cm3/Makefile2
-rw-r--r--package/firmware/ath10k-firmware/Makefile95
-rw-r--r--package/firmware/ixp4xx-microcode/Makefile2
-rw-r--r--package/firmware/lantiq/dsl-vrx200-firmware-xdsl/Makefile2
-rw-r--r--package/firmware/vsc73x5-ucode/Makefile2
-rw-r--r--package/kernel/acx-mac80211/patches/300-api_sync.patch83
-rw-r--r--package/kernel/acx-mac80211/patches/300-kernel_4_2.patch67
-rw-r--r--package/kernel/ar7-atm/Makefile2
-rw-r--r--package/kernel/brcm2708-gpu-fw/Makefile74
-rw-r--r--package/kernel/broadcom-wl/Makefile1
-rw-r--r--package/kernel/dtc/Makefile36
-rw-r--r--package/kernel/dtc/patches/0001-scripts-dtc-Update-to-version-with-overlays.patch642
-rw-r--r--package/kernel/lantiq/ltq-adsl-fw/Makefile2
-rw-r--r--package/kernel/lantiq/ltq-vdsl-mei/Makefile1
-rw-r--r--package/kernel/mac80211/Makefile12
-rw-r--r--package/kernel/mac80211/patches/004-backports-add-skb_free_frag.patch21
-rw-r--r--package/kernel/mac80211/patches/004-header-backport-GENL_UNS_ADMIN_PERM.patch21
-rw-r--r--package/kernel/mac80211/patches/005-backports-add-napi_alloc_frag.patch20
-rw-r--r--package/kernel/mac80211/patches/005-header-backport-nla_put_u64_64bit-and-nla_put_64bit.patch158
-rw-r--r--package/kernel/mac80211/patches/006-compat-bump-rhashtable-backport-version-due-to-API-c.patch18
-rw-r--r--package/kernel/mac80211/patches/007-fix_duplicate_skcipher_backport.patch11
-rw-r--r--package/kernel/mac80211/patches/060-no_local_ssb_bcma.patch5
-rw-r--r--package/kernel/mac80211/patches/080-disable_clk_backport.patch20
-rw-r--r--package/kernel/mac80211/patches/100-remove-cryptoapi-dependencies.patch102
-rw-r--r--package/kernel/mac80211/patches/110-mac80211_keep_keys_on_stop_ap.patch2
-rw-r--r--package/kernel/mac80211/patches/150-disable_addr_notifier.patch6
-rw-r--r--package/kernel/mac80211/patches/210-ap_scan.patch2
-rw-r--r--package/kernel/mac80211/patches/302-Revert-ath9k-interpret-requested-txpower-in-EIRP-dom.patch37
-rw-r--r--package/kernel/mac80211/patches/302-ath9k_hw-add-low-power-tx-gain-table-for-AR953x.patch95
-rw-r--r--package/kernel/mac80211/patches/303-mac80211-mesh-flush-mesh-paths-unconditionally.patch146
-rw-r--r--package/kernel/mac80211/patches/303-rt2x00-fix-monitor-mode-regression.patch156
-rw-r--r--package/kernel/mac80211/patches/304-ath9k-avoid-ANI-restart-if-no-trigger.patch32
-rw-r--r--package/kernel/mac80211/patches/304-mac80211-fix-fast_tx-header-alignment.patch25
-rw-r--r--package/kernel/mac80211/patches/305-ath9k-clean-up-ANI-per-channel-pointer-checking.patch91
-rw-r--r--package/kernel/mac80211/patches/306-ath9k-do-not-reset-while-BB-panic-0x4000409-on-ar956.patch31
-rw-r--r--package/kernel/mac80211/patches/307-ath9k-fix-inconsistent-use-of-tab-and-space-in-inden.patch27
-rw-r--r--package/kernel/mac80211/patches/308-ath9k-fix-data-bus-error-on-ar9300-and-ar9580.patch65
-rw-r--r--package/kernel/mac80211/patches/309-01-brcmfmac-add-missing-include.patch19
-rw-r--r--package/kernel/mac80211/patches/309-02-brcmfmac-fix-sdio-sg-table-alloc-crash.patch118
-rw-r--r--package/kernel/mac80211/patches/310-ath9k_hw-ignore-eeprom-magic-mismatch-on-flash-based.patch38
-rw-r--r--package/kernel/mac80211/patches/311-ath9k-do-not-limit-the-number-of-DFS-interfaces-to-1.patch55
-rw-r--r--package/kernel/mac80211/patches/312-mac80211-fix-txq-queue-related-crashes.patch27
-rw-r--r--package/kernel/mac80211/patches/313-mac80211-fix-unnecessary-frame-drops-in-mesh-fwding.patch57
-rw-r--r--package/kernel/mac80211/patches/314-mac80211-Requeue-work-after-scan-complete-for-all-VI.patch103
-rw-r--r--package/kernel/mac80211/patches/315-mac80211-fix-ibss-scan-parameters.patch57
-rw-r--r--package/kernel/mac80211/patches/316-net-mac80211-agg-rx.c-fix-use-of-uninitialised-value.patch50
-rw-r--r--package/kernel/mac80211/patches/317-mac80211-minstrel_ht-fix-out-of-bound-in-minstrel_ht.patch45
-rw-r--r--package/kernel/mac80211/patches/318-mac80211-move-A-MSDU-skb_linearize-call-to-ieee80211.patch35
-rw-r--r--package/kernel/mac80211/patches/319-cfg80211-add-function-for-802.3-conversion-with-sepa.patch186
-rw-r--r--package/kernel/mac80211/patches/320-cfg80211-add-support-for-non-linear-skbs-in-ieee8021.patch159
-rw-r--r--package/kernel/mac80211/patches/321-mac80211-Parse-legacy-and-HT-rate-in-injected-frames.patch155
-rw-r--r--package/kernel/mac80211/patches/322-mac80211-add-A-MSDU-tx-support.patch317
-rw-r--r--package/kernel/mac80211/patches/323-0000-brcmfmac-fix-setting-primary-channel-for-80-MHz-widt.patch64
-rw-r--r--package/kernel/mac80211/patches/323-0001-brcmfmac-analyze-descriptors-of-current-component-on.patch51
-rw-r--r--package/kernel/mac80211/patches/323-0002-brcmfmac-allow-storing-PMU-core-without-wrapper-addr.patch28
-rw-r--r--package/kernel/mac80211/patches/323-0003-brcmfmac-read-extended-capabilities-of-ChipCommon-co.patch43
-rw-r--r--package/kernel/mac80211/patches/323-0004-brcmfmac-access-PMU-registers-using-standalone-PMU-c.patch148
-rw-r--r--package/kernel/mac80211/patches/323-0005-brcmfmac-add-support-for-14e4-4365-PCI-ID-with-BCM43.patch38
-rw-r--r--package/kernel/mac80211/patches/324-brcmfmac-treat-NULL-character-in-NVRAM-as-separator.patch32
-rw-r--r--package/kernel/mac80211/patches/325-brcmfmac-sdio-Increase-the-default-timeouts-a-bit.patch41
-rw-r--r--package/kernel/mac80211/patches/326-ath9k-make-NF-load-complete-quickly-and-reliably.patch87
-rw-r--r--package/kernel/mac80211/patches/327-mac80211-Remove-MPP-table-entries-with-MPath.patch54
-rw-r--r--package/kernel/mac80211/patches/328-mac80211-let-unused-MPP-table-entries-timeout.patch104
-rw-r--r--package/kernel/mac80211/patches/329-mac80211-Unify-mesh-and-mpp-path-removal-function.patch143
-rw-r--r--package/kernel/mac80211/patches/330-mac80211-minstrel-Change-expected-throughput-unit-ba.patch51
-rw-r--r--package/kernel/mac80211/patches/331-brcmfmac-Increase-nr-of-supported-flowrings.patch307
-rw-r--r--package/kernel/mac80211/patches/332-cfg80211-fix-faulty-variable-initialization-in-ieee8.patch22
-rw-r--r--package/kernel/mac80211/patches/333-cfg80211-reuse-existing-page-fragments-in-A-MSDU-rx.patch132
-rw-r--r--package/kernel/mac80211/patches/334-mac80211-fix-wiphy-supported_band-access.patch36
-rw-r--r--package/kernel/mac80211/patches/335-mac80211-minstrel_ht-set-A-MSDU-tx-limits-based-on-s.patch61
-rw-r--r--package/kernel/mac80211/patches/336-mac80211-minstrel_ht-set-default-tx-aggregation-time.patch31
-rw-r--r--package/kernel/mac80211/patches/337-mac80211-minstrel_ht-fix-a-logic-error-in-RTS-CTS-ha.patch26
-rw-r--r--package/kernel/mac80211/patches/338-mac80211-Fix-Public-Action-frame-RX-in-AP-mode.patch35
-rw-r--r--package/kernel/mac80211/patches/339-cfg80211-add-radiotap-VHT-info-to-rtap_namespace_siz.patch21
-rw-r--r--package/kernel/mac80211/patches/340-mac80211-fix-parsing-of-40Mhz-in-injected-radiotap-h.patch36
-rw-r--r--package/kernel/mac80211/patches/341-mac80211-parse-VHT-info-in-injected-frames.patch65
-rw-r--r--package/kernel/mac80211/patches/342-mac80211-do-not-pass-injected-frames-without-a-valid.patch23
-rw-r--r--package/kernel/mac80211/patches/343-mac80211-minstrel_ht-improve-sample-rate-skip-logic.patch77
-rw-r--r--package/kernel/mac80211/patches/344-0001-brcmfmac-change-function-name-for-brcmf_cfg80211_wai.patch99
-rw-r--r--package/kernel/mac80211/patches/344-0002-brcmfmac-Limit-memory-allocs-to-64K.patch127
-rw-r--r--package/kernel/mac80211/patches/344-0003-brcmfmac-check-for-wowl-support-before-enumerating-f.patch29
-rw-r--r--package/kernel/mac80211/patches/344-0004-brcmfmac-Configure-country-code-using-device-specifi.patch214
-rw-r--r--package/kernel/mac80211/patches/344-0005-brcmfmac-Add-length-checks-on-firmware-events.patch283
-rw-r--r--package/kernel/mac80211/patches/344-0006-brcmfmac-add-neighbor-discovery-offload-ip-address-t.patch333
-rw-r--r--package/kernel/mac80211/patches/344-0007-brcmfmac-check-return-for-ARP-ip-setting-iovar.patch38
-rw-r--r--package/kernel/mac80211/patches/344-0008-brcmfmac-use-device-memsize-config-from-fw-if-define.patch73
-rw-r--r--package/kernel/mac80211/patches/344-0009-brcmfmac-use-bar1-window-size-as-provided-by-pci-sub.patch58
-rw-r--r--package/kernel/mac80211/patches/344-0010-brcmfmac-add-support-for-the-PCIE-4366c0-chip.patch34
-rw-r--r--package/kernel/mac80211/patches/344-0011-brcmfmac-remove-pcie-gen1-support.patch221
-rw-r--r--package/kernel/mac80211/patches/344-0012-brcmfmac-increase-timeout-for-tx-eapol.patch30
-rw-r--r--package/kernel/mac80211/patches/344-0013-brcmfmac-move-module-init-and-exit-to-common.patch135
-rw-r--r--package/kernel/mac80211/patches/344-0014-brcmfmac-add-wowl-gtk-rekeying-offload-support.patch260
-rw-r--r--package/kernel/mac80211/patches/344-0015-brcmfmac-move-platform-data-retrieval-code-to-common.patch385
-rw-r--r--package/kernel/mac80211/patches/344-0016-brcmfmac-keep-ARP-and-ND-offload-enabled-during-WOWL.patch69
-rw-r--r--package/kernel/mac80211/patches/344-0017-brcmfmac-switch-to-new-platform-data.patch734
-rw-r--r--package/kernel/mac80211/patches/344-0018-brcmfmac-merge-platform-data-and-module-paramaters.patch607
-rw-r--r--package/kernel/mac80211/patches/344-0019-brcmfmac-integrate-add_keyext-in-add_key.patch227
-rw-r--r--package/kernel/mac80211/patches/344-0020-brcmfmac-add-802.11w-management-frame-protection-sup.patch509
-rw-r--r--package/kernel/mac80211/patches/345-brcmfmac-Remove-waitqueue_active-check.patch54
-rw-r--r--package/kernel/mac80211/patches/346-brcmfmac-uninitialized-ret-variable.patch21
-rw-r--r--package/kernel/mac80211/patches/347-brcmfmac-sdio-remove-unused-variable-retry_limit.patch24
-rw-r--r--package/kernel/mac80211/patches/348-brcmfmac-Delete-unnecessary-variable-initialisation.patch26
-rw-r--r--package/kernel/mac80211/patches/349-0001-brcmfmac-clear-eventmask-array-before-using-it.patch27
-rw-r--r--package/kernel/mac80211/patches/349-0002-brcmfmac-fix-clearing-wowl-wake-indicators.patch27
-rw-r--r--package/kernel/mac80211/patches/349-0003-brcmfmac-insert-default-boardrev-in-nvram-data-if-mi.patch114
-rw-r--r--package/kernel/mac80211/patches/349-0004-brcmfmac-fix-p2p-scan-abort-null-pointer-exception.patch29
-rw-r--r--package/kernel/mac80211/patches/349-0005-brcmfmac-screening-firmware-event-packet.patch297
-rw-r--r--package/kernel/mac80211/patches/349-0006-brcmfmac-cleanup-ampdu-rx-host-reorder-code.patch585
-rw-r--r--package/kernel/mac80211/patches/349-0007-brcmfmac-revise-handling-events-in-receive-path.patch139
-rw-r--r--package/kernel/mac80211/patches/349-0008-brcmfmac-create-common-function-for-handling-brcmf_p.patch88
-rw-r--r--package/kernel/mac80211/patches/351-0001-brcmfmac-testing-the-wrong-variable-in-brcmf_rx_hdrp.patch39
-rw-r--r--package/kernel/mac80211/patches/402-ath_regd_optional.patch8
-rw-r--r--package/kernel/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch2
-rw-r--r--package/kernel/mac80211/patches/500-ath9k_eeprom_debugfs.patch4
-rw-r--r--package/kernel/mac80211/patches/501-ath9k_ahb_init.patch2
-rw-r--r--package/kernel/mac80211/patches/512-ath9k_channelbw_debugfs.patch6
-rw-r--r--package/kernel/mac80211/patches/513-ath9k_add_pci_ids.patch2
-rw-r--r--package/kernel/mac80211/patches/522-mac80211_configure_antenna_gain.patch38
-rw-r--r--package/kernel/mac80211/patches/530-ath9k_extra_leds.patch89
-rw-r--r--package/kernel/mac80211/patches/531-ath9k_extra_platform_leds.patch14
-rw-r--r--package/kernel/mac80211/patches/532-ath9k_get_led_polarity_from_platform_data.patch4
-rw-r--r--package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch14
-rw-r--r--package/kernel/mac80211/patches/543-ath9k_entropy_from_adc.patch20
-rw-r--r--package/kernel/mac80211/patches/544-ath9k-ar933x-usb-hang-workaround.patch4
-rw-r--r--package/kernel/mac80211/patches/545-ath9k_ani_ws_detect.patch8
-rw-r--r--package/kernel/mac80211/patches/546-ath9k_platform_led_name.patch19
-rw-r--r--package/kernel/mac80211/patches/547-ath9k_led_defstate_fix.patch6
-rw-r--r--package/kernel/mac80211/patches/548-ath9k_enable_gpio_chip.patch34
-rw-r--r--package/kernel/mac80211/patches/549-ath9k_enable_gpio_buttons.patch21
-rw-r--r--package/kernel/mac80211/patches/550-ath9k_add_ar9280_gpio_chip.patch2
-rw-r--r--package/kernel/mac80211/patches/600-0002-rt2x00-rt2800lib-introduce-RT2800_HAS_HIGH_SHARED_ME.patch4
-rw-r--r--package/kernel/mac80211/patches/600-0003-rt2x00-rt2800-serialize-shared-memory-access.patch4
-rw-r--r--package/kernel/mac80211/patches/600-0005-rt2x00-rt2800lib-add-hw_beacon_count-field-to-struct.patch2
-rw-r--r--package/kernel/mac80211/patches/600-0007-rt2x00-rt2800lib-fix-max-supported-beacon-count-for-.patch2
-rw-r--r--package/kernel/mac80211/patches/600-0009-rt2x00-rt2800lib-enable-support-for-RT3883.patch2
-rw-r--r--package/kernel/mac80211/patches/600-0010-rt2x00-rt2800lib-add-rf_vals-for-RF3853.patch2
-rw-r--r--package/kernel/mac80211/patches/600-0011-rt2x00-rt2800lib-enable-VCO-calibration-for-RF3853.patch2
-rw-r--r--package/kernel/mac80211/patches/600-0026-rt2x00-rt2800lib-use-correct-beacon-count-for-RT3883.patch2
-rw-r--r--package/kernel/mac80211/patches/600-0032-rt2x00-rt2800lib-enable-RT2800_HAS_HIGH_SHARED_MEM-f.patch2
-rw-r--r--package/kernel/mac80211/patches/602-rt2x00-introduce-rt2x00_platform_h.patch4
-rw-r--r--package/kernel/mac80211/patches/603-rt2x00-introduce-rt2x00eeprom.patch8
-rw-r--r--package/kernel/mac80211/patches/607-rt2x00-allow_disabling_bands_through_platform_data.patch2
-rw-r--r--package/kernel/mac80211/patches/608-add_platform_data_mac_addr.patch2
-rw-r--r--package/kernel/mac80211/patches/610-rt2x00-fix-rt3352-ext-pa.patch2
-rw-r--r--package/kernel/mac80211/patches/611-rt2x00-rf_vals-rt3352-xtal20.patch10
-rw-r--r--package/kernel/mac80211/patches/615-rt2x00-fix_20mhz_clk.patch2
-rw-r--r--package/kernel/mac80211/patches/616-rt2x00-support-rt5350.patch8
-rw-r--r--package/kernel/mac80211/patches/620-rt2x00-add-AP+STA-support.patch2
-rw-r--r--package/kernel/mac80211/patches/801-libertas-configure-sysfs-links.patch2
-rw-r--r--package/kernel/mac80211/patches/802-libertas-set-wireless-macaddr.patch2
-rw-r--r--package/kernel/mac80211/patches/804-b43-sync-with-bcma.patch17
-rw-r--r--package/kernel/mac80211/patches/820-b43-add-antenna-control.patch8
-rw-r--r--package/kernel/mac80211/patches/910-01-add-support-for-mt7620.patch4
-rw-r--r--package/kernel/mac80211/patches/921-ath10k_init_devices_synchronously.patch2
-rw-r--r--package/kernel/mac80211/patches/930-ath10k_add_tpt_led_trigger.patch4
-rw-r--r--package/kernel/mac80211/patches/936-ath10k_skip_otp_check.patch42
-rw-r--r--package/kernel/mt76/Makefile6
-rw-r--r--package/kernel/mt76/patches/000-uninitialized.patch11
-rw-r--r--package/kernel/mwlwifi/patches/110-api_sync.patch250
-rw-r--r--package/kernel/om-watchdog/files/om-watchdog.init4
-rw-r--r--package/libs/cyassl/Makefile8
-rw-r--r--package/libs/cyassl/patches/300-SSL_set_tlsext_host_name.patch19
-rw-r--r--package/libs/cyassl/patches/300-debloat_move_SSL_set_tlsext_host_name_outside_STUNNEL.patch19
-rw-r--r--package/libs/cyassl/patches/400-additional_compatibility.patch2
-rw-r--r--package/libs/libusb/Makefile2
-rw-r--r--package/libs/nettle/Makefile4
-rw-r--r--package/network/config/ltq-vdsl-app/Makefile2
-rw-r--r--package/network/services/dnsmasq/Makefile6
-rw-r--r--package/network/services/dnsmasq/patches/100-fix-dhcp-no-address-warning.patch10
-rw-r--r--package/network/services/dnsmasq/patches/210-dnssec-improve-timestamp-heuristic.patch4
-rw-r--r--package/network/services/dnsmasq/patches/230-fix-poll-h-include-warning-on-musl.patch18
-rw-r--r--package/network/services/dropbear/Makefile6
-rw-r--r--package/network/services/dropbear/patches/120-openwrt_options.patch4
-rw-r--r--package/network/services/dropbear/patches/130-ssh_ignore_o_and_x_args.patch21
-rw-r--r--package/network/services/dropbear/patches/130-ssh_ignore_x_args.patch11
-rw-r--r--package/network/services/dropbear/patches/140-disable_assert.patch2
-rw-r--r--package/network/services/dropbear/patches/500-set-default-path.patch2
-rw-r--r--package/network/services/mdns/Makefile2
-rw-r--r--package/network/services/openvpn/Makefile5
-rw-r--r--package/network/services/openvpn/files/openvpn.init2
-rw-r--r--package/network/services/openvpn/patches/100-polarssl-disable-runtime-version-check.patch2
-rw-r--r--package/network/services/openvpn/patches/101-remove_polarssl_debug_call.patch21
-rw-r--r--package/network/utils/curl/Makefile15
-rw-r--r--package/network/utils/curl/patches/200-no_docs_tests.patch10
-rw-r--r--package/network/utils/curl/patches/300-fix-disable-crypto-auth.patch25
-rw-r--r--package/network/utils/curl/patches/310-polarssl-disable-runtime-version-check.patch4
-rw-r--r--package/network/utils/iperf/Makefile53
-rw-r--r--package/network/utils/iperf/patches/001-set-report-next-time-in-single-thread-mode.patch14
-rw-r--r--package/network/utils/iperf/patches/002-format-security.patch96
-rw-r--r--package/network/utils/iw/patches/001-nl80211_h_sync.patch273
-rw-r--r--package/network/utils/iw/patches/300-display_interface_TX_power.patch4
-rw-r--r--package/network/utils/iw/patches/301-ibss_add_VHT80.patch8
-rw-r--r--package/network/utils/iw/patches/302-ibss_use_MHz_instead_MHZ.patch4
-rw-r--r--package/network/utils/iw/patches/303-mesh_add_VHT80.patch20
-rw-r--r--package/system/fstools/Makefile4
-rw-r--r--package/utils/admswconfig/Makefile2
-rw-r--r--package/utils/busybox/patches/030-ip-fix-problem-on-mips64-n64-big-endian-musl-systems.patch75
-rw-r--r--package/utils/e2fsprogs/Makefile4
-rw-r--r--package/utils/nvram/Makefile1
-rw-r--r--package/utils/oseama/Makefile2
-rw-r--r--package/utils/otrx/Makefile1
-rw-r--r--package/utils/usbutils/Makefile2
-rwxr-xr-xscripts/diffconfig.sh1
-rwxr-xr-xscripts/metadata.pl9
-rw-r--r--target/linux/ar71xx/Makefile2
-rwxr-xr-xtarget/linux/ar71xx/base-files/etc/board.d/01_leds26
-rwxr-xr-xtarget/linux/ar71xx/base-files/etc/board.d/02_network17
-rwxr-xr-xtarget/linux/ar71xx/base-files/etc/board.d/03_gpio_switches5
-rw-r--r--target/linux/ar71xx/base-files/etc/diag.sh12
-rw-r--r--target/linux/ar71xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata4
-rwxr-xr-xtarget/linux/ar71xx/base-files/lib/ar71xx.sh31
-rw-r--r--target/linux/ar71xx/base-files/lib/upgrade/openmesh.sh75
-rwxr-xr-xtarget/linux/ar71xx/base-files/lib/upgrade/platform.sh14
-rw-r--r--target/linux/ar71xx/config-4.42
-rw-r--r--target/linux/ar71xx/files-4.1/arch/mips/ath79/dev-eth.c1315
-rw-r--r--target/linux/ar71xx/files/arch/mips/ath79/Kconfig.openwrt38
-rw-r--r--target/linux/ar71xx/files/arch/mips/ath79/Makefile2
-rw-r--r--target/linux/ar71xx/files/arch/mips/ath79/dev-eth.c89
-rw-r--r--target/linux/ar71xx/files/arch/mips/ath79/mach-archer-c7.c42
-rw-r--r--target/linux/ar71xx/files/arch/mips/ath79/mach-cpe510.c36
-rw-r--r--target/linux/ar71xx/files/arch/mips/ath79/mach-mr1750.c1
-rw-r--r--target/linux/ar71xx/files/arch/mips/ath79/mach-om2p.c1
-rw-r--r--target/linux/ar71xx/files/arch/mips/ath79/mach-som9331.c125
-rw-r--r--target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr841n-v9.c166
-rw-r--r--target/linux/ar71xx/files/arch/mips/ath79/mach-ubnt-unifiac.c83
-rw-r--r--target/linux/ar71xx/files/arch/mips/ath79/mach-ubnt-xm.c700
-rw-r--r--target/linux/ar71xx/files/arch/mips/ath79/mach-wrtnode2q.c126
-rw-r--r--target/linux/ar71xx/files/arch/mips/ath79/machtypes.h11
-rw-r--r--target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c10
-rw-r--r--target/linux/ar71xx/generic/profiles/00-default.mk1
-rw-r--r--target/linux/ar71xx/generic/profiles/01-minimal.mk1
-rw-r--r--target/linux/ar71xx/generic/profiles/02-ath5k.mk1
-rw-r--r--target/linux/ar71xx/generic/profiles/jjplus.mk2
-rw-r--r--target/linux/ar71xx/generic/profiles/openembed.mk13
-rw-r--r--target/linux/ar71xx/generic/profiles/openmesh.mk15
-rw-r--r--target/linux/ar71xx/generic/profiles/ubnt.mk21
-rw-r--r--target/linux/ar71xx/generic/profiles/wrtnode.mk17
-rw-r--r--target/linux/ar71xx/image/Makefile2552
-rw-r--r--target/linux/ar71xx/image/generic.mk344
-rw-r--r--target/linux/ar71xx/image/legacy.mk1231
-rw-r--r--target/linux/ar71xx/image/nand.mk19
-rw-r--r--target/linux/ar71xx/image/tp-link.mk752
-rw-r--r--target/linux/ar71xx/image/ubnt.mk247
-rw-r--r--target/linux/ar71xx/mikrotik/profiles/01-minimal.mk1
-rw-r--r--target/linux/ar71xx/mikrotik/profiles/02-ath5k.mk1
-rw-r--r--target/linux/ar71xx/patches-4.4/003-MIPS-ath79-make-bootconsole-wait-for-both-THRE-and-T.patch49
-rw-r--r--target/linux/ar71xx/patches-4.4/004-register_gpio_driver_earlier.patch15
-rw-r--r--target/linux/ar71xx/patches-4.4/101-MIPS-ath79-make-ath79_ddr_ctrl_init-compatible-for-n.patch31
-rw-r--r--target/linux/ar71xx/patches-4.4/102-MIPS-ath79-fix-regression-in-PCI-window-initializati.patch37
-rw-r--r--target/linux/ar71xx/patches-4.4/103-MIPS-ath79-fix-register-address-in-ath79_ddr_wb_flus.patch23
-rw-r--r--target/linux/ar71xx/patches-4.4/407-mtd-m25p80-allow-to-pass-probe-types-via-platform-data.patch2
-rw-r--r--target/linux/ar71xx/patches-4.4/412-mtd-m25p80-zero-partition-parser-data.patch2
-rw-r--r--target/linux/ar71xx/patches-4.4/431-spi-add-various-flags.patch4
-rw-r--r--target/linux/ar71xx/patches-4.4/461-spi-add-type-field-to-spi_transfer.patch4
-rw-r--r--target/linux/ar71xx/patches-4.4/462-mtd-m25p80-set-spi-transfer-type.patch2
-rw-r--r--target/linux/ar71xx/patches-4.4/464-spi-ath79-fix-fast-flash-read.patch4
-rw-r--r--target/linux/ar71xx/patches-4.4/607-MIPS-ath79-ubnt-xm-fixes.patch89
-rw-r--r--target/linux/ar71xx/patches-4.4/608-MIPS-ath79-ubnt-xm-add-more-boards.patch623
-rw-r--r--target/linux/ar71xx/patches-4.4/610-MIPS-ath79-UBNT-add-airGateway-pro-support.patch62
-rw-r--r--target/linux/ar71xx/patches-4.4/620-MIPS-ath79-add-support-for-QCA953x-SoC.patch4
-rw-r--r--target/linux/ar71xx/patches-4.4/910-unaligned_access_hacks.patch25
-rw-r--r--target/linux/arc770/image/Makefile44
-rw-r--r--target/linux/archs38/image/Makefile44
-rw-r--r--target/linux/at91/config-4.41
-rw-r--r--target/linux/at91/sama5d3/config-default17
-rw-r--r--target/linux/ath25/Makefile2
-rw-r--r--target/linux/ath25/base-files/etc/config/system14
-rw-r--r--target/linux/ath25/base-files/etc/hotplug.d/button/00-button24
-rw-r--r--target/linux/ath25/config-3.18136
-rw-r--r--target/linux/ath25/config-4.4155
-rw-r--r--target/linux/ath25/image/Makefile116
-rw-r--r--target/linux/ath25/patches-3.18/010-board.patch2189
-rw-r--r--target/linux/ath25/patches-3.18/020-early-printk-support.patch68
-rw-r--r--target/linux/ath25/patches-3.18/030-ar2315_pci.patch613
-rw-r--r--target/linux/ath25/patches-3.18/107-ar5312_gpio.patch212
-rw-r--r--target/linux/ath25/patches-3.18/108-ar2315_gpio.patch363
-rw-r--r--target/linux/ath25/patches-3.18/110-ar2313_ethernet.patch1828
-rw-r--r--target/linux/ath25/patches-3.18/120-spiflash.patch634
-rw-r--r--target/linux/ath25/patches-3.18/130-watchdog.patch277
-rw-r--r--target/linux/ath25/patches-3.18/210-reset_button.patch71
-rw-r--r--target/linux/ath25/patches-4.4/107-ar5312_gpio.patch212
-rw-r--r--target/linux/ath25/patches-4.4/108-ar2315_gpio.patch363
-rw-r--r--target/linux/ath25/patches-4.4/110-ar2313_ethernet.patch1828
-rw-r--r--target/linux/ath25/patches-4.4/120-spiflash.patch634
-rw-r--r--target/linux/ath25/patches-4.4/130-watchdog.patch277
-rw-r--r--target/linux/ath25/patches-4.4/140-redboot_boardconfig.patch (renamed from target/linux/ath25/patches-3.18/140-redboot_boardconfig.patch)0
-rw-r--r--target/linux/ath25/patches-4.4/141-redboot_partition_scan.patch (renamed from target/linux/ath25/patches-3.18/141-redboot_partition_scan.patch)0
-rw-r--r--target/linux/ath25/patches-4.4/142-redboot_various_erase_size_fix.patch (renamed from target/linux/ath25/patches-3.18/142-redboot_various_erase_size_fix.patch)0
-rw-r--r--target/linux/ath25/patches-4.4/210-reset_button.patch71
-rw-r--r--target/linux/ath25/patches-4.4/220-enet_micrel_workaround.patch (renamed from target/linux/ath25/patches-3.18/220-enet_micrel_workaround.patch)0
-rw-r--r--target/linux/ath25/patches-4.4/330-board_leds.patch (renamed from target/linux/ath25/patches-3.18/330-board_leds.patch)0
-rw-r--r--target/linux/ath25/profiles/00-default.mk16
-rw-r--r--target/linux/bcm53xx/patches-4.4/140-mtd-brcmnand-set-initial-ECC-params-based-on-info-fr.patch4
-rw-r--r--target/linux/bcm53xx/patches-4.4/191-usb-xhci-add-Broadcom-specific-fake-doorbell.patch6
-rw-r--r--target/linux/bcm53xx/patches-4.4/351-ARM-BCM5301X-Enable-ChipCommon-UART-on-untested-devi.patch6
-rw-r--r--target/linux/bcm53xx/patches-4.4/400-mtd-brcmnand-stop-special-treating-ECC-strength-1-as.patch2
-rw-r--r--target/linux/bcm53xx/patches-4.4/405-mtd-spi-nor-detect-JEDEC-incompatible-w25q128-using-.patch2
-rw-r--r--target/linux/bcm53xx/patches-4.4/406-mtd-m25p80-use-single-SPI-message-for-writing-data.patch2
-rw-r--r--target/linux/bcm53xx/patches-4.4/500-UBI-Detect-EOF-mark-and-erase-all-remaining-blocks.patch2
-rw-r--r--target/linux/bcm53xx/patches-4.4/820-spi-bcm53xx-let-DT-specify-SPI-device-s-instead-hard.patch6
-rw-r--r--target/linux/brcm2708/base-files/etc/diag.sh3
-rw-r--r--target/linux/brcm2708/base-files/lib/brcm2708.sh3
-rw-r--r--target/linux/brcm2708/bcm2708/config-4.45
-rw-r--r--target/linux/brcm2708/bcm2708/profiles/RaspberryPi.mk14
-rw-r--r--target/linux/brcm2708/bcm2709/config-4.45
-rw-r--r--target/linux/brcm2708/bcm2709/profiles/RaspberryPi2.mk14
-rw-r--r--target/linux/brcm2708/bcm2710/config-4.45
-rw-r--r--target/linux/brcm2708/bcm2710/profiles/RaspberryPi3.mk15
-rw-r--r--target/linux/brcm2708/image/Makefile48
-rw-r--r--target/linux/brcm2708/image/config.txt39
-rw-r--r--target/linux/brcm2708/modules.mk186
-rw-r--r--target/linux/brcm2708/patches-4.4/0001-smsx95xx-fix-crimes-against-truesize.patch4
-rw-r--r--target/linux/brcm2708/patches-4.4/0002-smsc95xx-Disable-turbo-mode-by-default.patch4
-rw-r--r--target/linux/brcm2708/patches-4.4/0003-vmstat-Workaround-for-issue-where-dirty-page-count-g.patch4
-rw-r--r--target/linux/brcm2708/patches-4.4/0004-BCM2835_DT-Fix-I2S-register-map.patch4
-rw-r--r--target/linux/brcm2708/patches-4.4/0005-irq-bcm2836-Prevent-spurious-interrupts-and-trap-the.patch4
-rw-r--r--target/linux/brcm2708/patches-4.4/0006-irqchip-bcm2835-Add-FIQ-support.patch4
-rw-r--r--target/linux/brcm2708/patches-4.4/0007-irqchip-irq-bcm2835-Add-2836-FIQ-support.patch4
-rw-r--r--target/linux/brcm2708/patches-4.4/0008-serial-8250-Don-t-crash-when-nr_uarts-is-0.patch4
-rw-r--r--target/linux/brcm2708/patches-4.4/0009-pinctrl-bcm2835-Set-base-to-0-give-expected-gpio-num.patch4
-rw-r--r--target/linux/brcm2708/patches-4.4/0010-pinctrl-bcm2835-Fix-interrupt-handling-for-GPIOs-28-.patch4
-rw-r--r--target/linux/brcm2708/patches-4.4/0011-pinctrl-bcm2835-Only-request-the-interrupts-listed-i.patch4
-rw-r--r--target/linux/brcm2708/patches-4.4/0012-spi-bcm2835-Support-pin-groups-other-than-7-11.patch4
-rw-r--r--target/linux/brcm2708/patches-4.4/0013-ARM-bcm2835-Set-Serial-number-and-Revision.patch4
-rw-r--r--target/linux/brcm2708/patches-4.4/0014-bcm2835-i2s-get-base-address-for-DMA-from-devicetree.patch4
-rw-r--r--target/linux/brcm2708/patches-4.4/0015-bcm2835-i2s-add-24bit-support-update-bclk_ratio-to-m.patch4
-rw-r--r--target/linux/brcm2708/patches-4.4/0016-bcm2835-i2s-setup-clock-only-if-CPU-is-clock-master.patch4
-rw-r--r--target/linux/brcm2708/patches-4.4/0017-bcm2835-i2s-Eliminate-debugfs-directory-error.patch4
-rw-r--r--target/linux/brcm2708/patches-4.4/0018-bcm2835-i2s-Register-PCM-device.patch4
-rw-r--r--target/linux/brcm2708/patches-4.4/0019-bcm2835-i2s-Enable-MMAP-support-via-a-DT-property.patch4
-rw-r--r--target/linux/brcm2708/patches-4.4/0020-dmaengine-bcm2835-Add-slave-dma-support.patch4
-rw-r--r--target/linux/brcm2708/patches-4.4/0021-dmaengine-bcm2835-set-residue_granularity-field.patch4
-rw-r--r--target/linux/brcm2708/patches-4.4/0022-dmaengine-bcm2835-Load-driver-early-and-support-lega.patch4
-rw-r--r--target/linux/brcm2708/patches-4.4/0023-bcm2835-dma-Fix-dreq-not-set-for-slave-transfers.patch4
-rw-r--r--target/linux/brcm2708/patches-4.4/0024-bcm2835-dma-Limit-cyclic-transfers-on-lite-channels-.patch4
-rw-r--r--target/linux/brcm2708/patches-4.4/0025-bcm2835-Add-support-for-uart1.patch4
-rw-r--r--target/linux/brcm2708/patches-4.4/0026-firmware-bcm2835-Add-missing-property-tags.patch4
-rw-r--r--target/linux/brcm2708/patches-4.4/0027-Main-bcm2708-bcm2709-linux-port.patch4
-rw-r--r--target/linux/brcm2708/patches-4.4/0028-squash-include-ARCH_BCM2708-ARCH_BCM2709.patch6
-rw-r--r--target/linux/brcm2708/patches-4.4/0029-Add-dwc_otg-driver.patch4
-rw-r--r--target/linux/brcm2708/patches-4.4/0030-bcm2708-framebuffer-driver.patch4
-rw-r--r--target/linux/brcm2708/patches-4.4/0031-dmaengine-Add-support-for-BCM2708.patch4
-rw-r--r--target/linux/brcm2708/patches-4.4/0032-Add-blk_pos-parameter-to-mmc-multi_io_quirk-callback.patch75
-rw-r--r--target/linux/brcm2708/patches-4.4/0032-MMC-added-alternative-MMC-driver.patch1691
-rw-r--r--target/linux/brcm2708/patches-4.4/0033-Adding-bcm2835-sdhost-driver-and-an-overlay-to-enabl.patch2022
-rw-r--r--target/linux/brcm2708/patches-4.4/0033-MMC-added-alternative-MMC-driver.patch1691
-rw-r--r--target/linux/brcm2708/patches-4.4/0034-Adding-bcm2835-sdhost-driver-and-an-overlay-to-enabl.patch2022
-rw-r--r--target/linux/brcm2708/patches-4.4/0034-cma-Add-vc_cma-driver-to-enable-use-of-CMA.patch1326
-rw-r--r--target/linux/brcm2708/patches-4.4/0035-bcm2708-alsa-sound-driver.patch2678
-rw-r--r--target/linux/brcm2708/patches-4.4/0035-cma-Add-vc_cma-driver-to-enable-use-of-CMA.patch1326
-rw-r--r--target/linux/brcm2708/patches-4.4/0036-bcm2708-alsa-sound-driver.patch2678
-rw-r--r--target/linux/brcm2708/patches-4.4/0036-bcm2708-vchiq-driver.patch13200
-rw-r--r--target/linux/brcm2708/patches-4.4/0037-bcm2708-vchiq-driver.patch13200
-rw-r--r--target/linux/brcm2708/patches-4.4/0037-vc_mem-Add-vc_mem-driver.patch991
-rw-r--r--target/linux/brcm2708/patches-4.4/0038-vc_mem-Add-vc_mem-driver.patch991
-rw-r--r--target/linux/brcm2708/patches-4.4/0038-vcsm-VideoCore-shared-memory-service-for-BCM2835.patch4393
-rw-r--r--target/linux/brcm2708/patches-4.4/0039-Add-dev-gpiomem-device-for-rootless-user-GPIO-access.patch306
-rw-r--r--target/linux/brcm2708/patches-4.4/0039-vcsm-VideoCore-shared-memory-service-for-BCM2835.patch4393
-rw-r--r--target/linux/brcm2708/patches-4.4/0040-Add-SMI-driver.patch1930
-rw-r--r--target/linux/brcm2708/patches-4.4/0040-Add-dev-gpiomem-device-for-rootless-user-GPIO-access.patch306
-rw-r--r--target/linux/brcm2708/patches-4.4/0041-Add-SMI-NAND-driver.patch358
-rw-r--r--target/linux/brcm2708/patches-4.4/0041-Add-SMI-driver.patch1930
-rw-r--r--target/linux/brcm2708/patches-4.4/0042-Add-SMI-NAND-driver.patch358
-rw-r--r--target/linux/brcm2708/patches-4.4/0042-lirc-added-support-for-RaspberryPi-GPIO.patch841
-rw-r--r--target/linux/brcm2708/patches-4.4/0043-Add-cpufreq-driver.patch257
-rw-r--r--target/linux/brcm2708/patches-4.4/0043-lirc-added-support-for-RaspberryPi-GPIO.patch841
-rw-r--r--target/linux/brcm2708/patches-4.4/0044-Add-cpufreq-driver.patch257
-rw-r--r--target/linux/brcm2708/patches-4.4/0044-Added-hwmon-thermal-driver-for-reporting-core-temper.patch193
-rw-r--r--target/linux/brcm2708/patches-4.4/0045-Add-Chris-Boot-s-i2c-driver.patch635
-rw-r--r--target/linux/brcm2708/patches-4.4/0045-Added-hwmon-thermal-driver-for-reporting-core-temper.patch193
-rw-r--r--target/linux/brcm2708/patches-4.4/0046-Add-Chris-Boot-s-i2c-driver.patch635
-rw-r--r--target/linux/brcm2708/patches-4.4/0046-char-broadcom-Add-vcio-module.patch221
-rw-r--r--target/linux/brcm2708/patches-4.4/0047-char-broadcom-Add-vcio-module.patch221
-rw-r--r--target/linux/brcm2708/patches-4.4/0047-firmware-bcm2835-Support-ARCH_BCM270x.patch106
-rw-r--r--target/linux/brcm2708/patches-4.4/0048-bcm2835-add-v4l2-camera-device.patch7338
-rw-r--r--target/linux/brcm2708/patches-4.4/0048-firmware-bcm2835-Support-ARCH_BCM270x.patch106
-rw-r--r--target/linux/brcm2708/patches-4.4/0049-bcm2835-add-v4l2-camera-device.patch7338
-rw-r--r--target/linux/brcm2708/patches-4.4/0049-scripts-Add-mkknlimg-and-knlinfo-scripts-from-tools-.patch461
-rw-r--r--target/linux/brcm2708/patches-4.4/0050-fdt-Add-support-for-the-CONFIG_CMDLINE_EXTEND-option.patch55
-rw-r--r--target/linux/brcm2708/patches-4.4/0050-scripts-Add-mkknlimg-and-knlinfo-scripts-from-tools-.patch461
-rw-r--r--target/linux/brcm2708/patches-4.4/0051-BCM2708-Add-core-Device-Tree-support.patch4564
-rw-r--r--target/linux/brcm2708/patches-4.4/0051-fdt-Add-support-for-the-CONFIG_CMDLINE_EXTEND-option.patch58
-rw-r--r--target/linux/brcm2708/patches-4.4/0052-BCM2708-Add-core-Device-Tree-support.patch4564
-rw-r--r--target/linux/brcm2708/patches-4.4/0052-bcm2835-Match-with-BCM2708-Device-Trees.patch515
-rw-r--r--target/linux/brcm2708/patches-4.4/0053-bcm2835-Match-with-BCM2708-Device-Trees.patch515
-rw-r--r--target/linux/brcm2708/patches-4.4/0053-fbdev-add-FBIOCOPYAREA-ioctl.patch91
-rw-r--r--target/linux/brcm2708/patches-4.4/0054-fbdev-add-FBIOCOPYAREA-ioctl.patch91
-rw-r--r--target/linux/brcm2708/patches-4.4/0057-Speed-up-console-framebuffer-imageblit-function.patch209
-rw-r--r--target/linux/brcm2708/patches-4.4/0058-Allow-mac-address-to-be-set-in-smsc95xx.patch91
-rw-r--r--target/linux/brcm2708/patches-4.4/0058-Speed-up-console-framebuffer-imageblit-function.patch209
-rw-r--r--target/linux/brcm2708/patches-4.4/0059-Allow-mac-address-to-be-set-in-smsc95xx.patch91
-rw-r--r--target/linux/brcm2708/patches-4.4/0059-enabling-the-realtime-clock-1-wire-chip-DS1307-and-1.patch242
-rw-r--r--target/linux/brcm2708/patches-4.4/0060-Added-Device-IDs-for-August-DVB-T-205.patch22
-rw-r--r--target/linux/brcm2708/patches-4.4/0060-enabling-the-realtime-clock-1-wire-chip-DS1307-and-1.patch242
-rw-r--r--target/linux/brcm2708/patches-4.4/0061-Added-Device-IDs-for-August-DVB-T-205.patch22
-rw-r--r--target/linux/brcm2708/patches-4.4/0061-config-Enable-CONFIG_MEMCG-but-leave-it-disabled-due.patch49
-rw-r--r--target/linux/brcm2708/patches-4.4/0062-ASoC-Add-support-for-PCM5102A-codec.patch128
-rw-r--r--target/linux/brcm2708/patches-4.4/0062-config-Enable-CONFIG_MEMCG-but-leave-it-disabled-due.patch49
-rw-r--r--target/linux/brcm2708/patches-4.4/0063-ASoC-Add-support-for-HifiBerry-DAC.patch165
-rw-r--r--target/linux/brcm2708/patches-4.4/0063-ASoC-Add-support-for-PCM5102A-codec.patch128
-rw-r--r--target/linux/brcm2708/patches-4.4/0064-ASoC-Add-support-for-HifiBerry-DAC.patch165
-rw-r--r--target/linux/brcm2708/patches-4.4/0064-ASoC-Add-support-for-Rpi-DAC.patch275
-rw-r--r--target/linux/brcm2708/patches-4.4/0065-ASoC-Add-support-for-Rpi-DAC.patch275
-rw-r--r--target/linux/brcm2708/patches-4.4/0065-ASoC-wm8804-Implement-MCLK-configuration-options-add.patch40
-rw-r--r--target/linux/brcm2708/patches-4.4/0066-ASoC-BCM-Add-support-for-HiFiBerry-Digi.-Driver-is-b.patch282
-rw-r--r--target/linux/brcm2708/patches-4.4/0066-ASoC-wm8804-Implement-MCLK-configuration-options-add.patch40
-rw-r--r--target/linux/brcm2708/patches-4.4/0067-ASoC-BCM-Add-support-for-HiFiBerry-Digi.-Driver-is-b.patch282
-rw-r--r--target/linux/brcm2708/patches-4.4/0067-ASoC-wm8804-Set-idle_bias_off-to-false-Idle-bias-has.patch22
-rw-r--r--target/linux/brcm2708/patches-4.4/0068-ASoC-wm8804-Set-idle_bias_off-to-false-Idle-bias-has.patch22
-rw-r--r--target/linux/brcm2708/patches-4.4/0068-Add-IQaudIO-Sound-Card-support-for-Raspberry-Pi.patch178
-rw-r--r--target/linux/brcm2708/patches-4.4/0069-Add-IQaudIO-Sound-Card-support-for-Raspberry-Pi.patch178
-rw-r--r--target/linux/brcm2708/patches-4.4/0069-hid-Reduce-default-mouse-polling-interval-to-60Hz.patch36
-rw-r--r--target/linux/brcm2708/patches-4.4/0070-Added-support-for-HiFiBerry-DAC.patch190
-rw-r--r--target/linux/brcm2708/patches-4.4/0070-hid-Reduce-default-mouse-polling-interval-to-60Hz.patch36
-rw-r--r--target/linux/brcm2708/patches-4.4/0071-Added-driver-for-HiFiBerry-Amp-amplifier-add-on-boar.patch816
-rw-r--r--target/linux/brcm2708/patches-4.4/0071-Added-support-for-HiFiBerry-DAC.patch190
-rw-r--r--target/linux/brcm2708/patches-4.4/0072-Added-driver-for-HiFiBerry-Amp-amplifier-add-on-boar.patch816
-rw-r--r--target/linux/brcm2708/patches-4.4/0072-Update-ds1307-driver-for-device-tree-support.patch27
-rw-r--r--target/linux/brcm2708/patches-4.4/0073-BCM270x_DT-Add-pwr_led-and-the-required-input-trigge.patch170
-rw-r--r--target/linux/brcm2708/patches-4.4/0073-Update-ds1307-driver-for-device-tree-support.patch27
-rw-r--r--target/linux/brcm2708/patches-4.4/0074-BCM270x_DT-Add-pwr_led-and-the-required-input-trigge.patch170
-rw-r--r--target/linux/brcm2708/patches-4.4/0074-enc28j60-Add-device-tree-compatible-string-and-an-ov.patch29
-rw-r--r--target/linux/brcm2708/patches-4.4/0075-Add-driver-for-rpi-proto.patch210
-rw-r--r--target/linux/brcm2708/patches-4.4/0075-enc28j60-Add-device-tree-compatible-string-and-an-ov.patch29
-rw-r--r--target/linux/brcm2708/patches-4.4/0076-Add-driver-for-rpi-proto.patch210
-rw-r--r--target/linux/brcm2708/patches-4.4/0076-config-Add-default-configs.patch2537
-rw-r--r--target/linux/brcm2708/patches-4.4/0077-bcm2835-bcm2835_defconfig.patch1426
-rw-r--r--target/linux/brcm2708/patches-4.4/0077-config-Add-default-configs.patch2537
-rw-r--r--target/linux/brcm2708/patches-4.4/0078-bcm2835-bcm2835_defconfig.patch1426
-rw-r--r--target/linux/brcm2708/patches-4.4/0078-rpi-ft5406-Add-touchscreen-driver-for-pi-LCD-display.patch290
-rw-r--r--target/linux/brcm2708/patches-4.4/0079-Improve-__copy_to_user-and-__copy_from_user-performa.patch1510
-rw-r--r--target/linux/brcm2708/patches-4.4/0079-rpi-ft5406-Add-touchscreen-driver-for-pi-LCD-display.patch290
-rw-r--r--target/linux/brcm2708/patches-4.4/0080-Improve-__copy_to_user-and-__copy_from_user-performa.patch1510
-rw-r--r--target/linux/brcm2708/patches-4.4/0080-gpio-poweroff-Allow-it-to-work-on-Raspberry-Pi.patch35
-rw-r--r--target/linux/brcm2708/patches-4.4/0081-gpio-poweroff-Allow-it-to-work-on-Raspberry-Pi.patch35
-rw-r--r--target/linux/brcm2708/patches-4.4/0081-spidev-Add-spidev-compatible-string-to-silence-warni.patch21
-rw-r--r--target/linux/brcm2708/patches-4.4/0082-scripts-dtc-Add-overlay-support.patch4389
-rw-r--r--target/linux/brcm2708/patches-4.4/0082-spidev-Add-spidev-compatible-string-to-silence-warni.patch21
-rw-r--r--target/linux/brcm2708/patches-4.4/0083-mfd-Add-Raspberry-Pi-Sense-HAT-core-driver.patch838
-rw-r--r--target/linux/brcm2708/patches-4.4/0083-scripts-dtc-Add-overlay-support.patch4389
-rw-r--r--target/linux/brcm2708/patches-4.4/0084-RaspiDAC3-support.patch243
-rw-r--r--target/linux/brcm2708/patches-4.4/0084-mfd-Add-Raspberry-Pi-Sense-HAT-core-driver.patch838
-rw-r--r--target/linux/brcm2708/patches-4.4/0085-RaspiDAC3-support.patch243
-rw-r--r--target/linux/brcm2708/patches-4.4/0085-tpa6130a2-Add-headphone-switch-control.patch91
-rw-r--r--target/linux/brcm2708/patches-4.4/0086-irq-bcm2835-Fix-building-with-2708.patch28
-rw-r--r--target/linux/brcm2708/patches-4.4/0086-tpa6130a2-Add-headphone-switch-control.patch91
-rw-r--r--target/linux/brcm2708/patches-4.4/0087-irq-bcm2835-Fix-building-with-2708.patch28
-rw-r--r--target/linux/brcm2708/patches-4.4/0087-rpi_display-add-backlight-driver-and-overlay.patch250
-rw-r--r--target/linux/brcm2708/patches-4.4/0088-bcm2835-dma-Fix-up-convert-to-DMA-pool.patch85
-rw-r--r--target/linux/brcm2708/patches-4.4/0088-rpi_display-add-backlight-driver-and-overlay.patch250
-rw-r--r--target/linux/brcm2708/patches-4.4/0089-bcm2835-dma-Fix-up-convert-to-DMA-pool.patch85
-rw-r--r--target/linux/brcm2708/patches-4.4/0089-scripts-Multi-platform-support-for-mkknlimg-and-knli.patch247
-rw-r--r--target/linux/brcm2708/patches-4.4/0090-drm-vc4-Add-suport-for-3D-rendering-using-the-V3D-en.patch5558
-rw-r--r--target/linux/brcm2708/patches-4.4/0090-scripts-Multi-platform-support-for-mkknlimg-and-knli.patch247
-rw-r--r--target/linux/brcm2708/patches-4.4/0091-drm-vc4-Add-suport-for-3D-rendering-using-the-V3D-en.patch5558
-rw-r--r--target/linux/brcm2708/patches-4.4/0091-drm-vc4-Force-HDMI-to-connected.patch23
-rw-r--r--target/linux/brcm2708/patches-4.4/0092-drm-vc4-Force-HDMI-to-connected.patch23
-rw-r--r--target/linux/brcm2708/patches-4.4/0092-drm-vc4-bo-cache-locking-fixes.patch147
-rw-r--r--target/linux/brcm2708/patches-4.4/0093-drm-vc4-bo-cache-locking-cleanup.patch92
-rw-r--r--target/linux/brcm2708/patches-4.4/0093-drm-vc4-bo-cache-locking-fixes.patch147
-rw-r--r--target/linux/brcm2708/patches-4.4/0094-drm-vc4-Use-job_lock-to-protect-seqno_cb_list.patch54
-rw-r--r--target/linux/brcm2708/patches-4.4/0094-drm-vc4-bo-cache-locking-cleanup.patch92
-rw-r--r--target/linux/brcm2708/patches-4.4/0095-drm-vc4-Drop-struct_mutex-around-CL-validation.patch63
-rw-r--r--target/linux/brcm2708/patches-4.4/0095-drm-vc4-Use-job_lock-to-protect-seqno_cb_list.patch54
-rw-r--r--target/linux/brcm2708/patches-4.4/0096-drm-vc4-Drop-struct_mutex-around-CL-validation.patch81
-rw-r--r--target/linux/brcm2708/patches-4.4/0097-drm-vc4-Add-support-for-more-display-plane-formats.patch35
-rw-r--r--target/linux/brcm2708/patches-4.4/0097-drm-vc4-Drop-struct_mutex-around-CL-validation.patch74
-rw-r--r--target/linux/brcm2708/patches-4.4/0098-drm-vc4-Add-support-for-more-display-plane-formats.patch35
-rw-r--r--target/linux/brcm2708/patches-4.4/0098-drm-vc4-No-need-to-stop-the-stopped-threads.patch26
-rw-r--r--target/linux/brcm2708/patches-4.4/0099-drm-vc4-No-need-to-stop-the-stopped-threads.patch26
-rw-r--r--target/linux/brcm2708/patches-4.4/0099-drm-vc4-Remove-extra-barrier-s-aroudn-CTnCA-CTnEA-se.patch33
-rw-r--r--target/linux/brcm2708/patches-4.4/0100-drm-vc4-Fix-a-typo-in-a-V3D-debug-register.patch33
-rw-r--r--target/linux/brcm2708/patches-4.4/0100-drm-vc4-Remove-extra-barrier-s-aroudn-CTnCA-CTnEA-se.patch33
-rw-r--r--target/linux/brcm2708/patches-4.4/0101-drm-vc4-Enable-VC4-modules-and-increase-CMA-size-wit.patch153
-rw-r--r--target/linux/brcm2708/patches-4.4/0101-drm-vc4-Fix-a-typo-in-a-V3D-debug-register.patch33
-rw-r--r--target/linux/brcm2708/patches-4.4/0102-drm-vc4-Enable-VC4-modules-and-increase-CMA-size-wit.patch153
-rw-r--r--target/linux/brcm2708/patches-4.4/0102-squash-fixups.patch43
-rw-r--r--target/linux/brcm2708/patches-4.4/0103-squash-add-missing-vc4-kms-v3d-overlay.dtb-to-makefi.patch20
-rw-r--r--target/linux/brcm2708/patches-4.4/0103-squash-fixups.patch43
-rw-r--r--target/linux/brcm2708/patches-4.4/0104-clk-bcm2835-Also-build-the-driver-for-downstream-ker.patch22
-rw-r--r--target/linux/brcm2708/patches-4.4/0104-squash-add-missing-vc4-kms-v3d-overlay.dtb-to-makefi.patch20
-rw-r--r--target/linux/brcm2708/patches-4.4/0105-clk-bcm2835-Also-build-the-driver-for-downstream-ker.patch22
-rw-r--r--target/linux/brcm2708/patches-4.4/0105-dts-Added-overlay-for-gpio_ir_recv-driver.patch104
-rw-r--r--target/linux/brcm2708/patches-4.4/0106-Build-i2c_gpio-module-and-add-a-device-tree-overlay-.patch100
-rw-r--r--target/linux/brcm2708/patches-4.4/0106-dts-Added-overlay-for-gpio_ir_recv-driver.patch104
-rw-r--r--target/linux/brcm2708/patches-4.4/0107-Build-i2c_gpio-module-and-add-a-device-tree-overlay-.patch100
-rw-r--r--target/linux/brcm2708/patches-4.4/0107-New-overlay-for-PiScreen2r.patch148
-rw-r--r--target/linux/brcm2708/patches-4.4/0108-New-overlay-for-PiScreen2r.patch148
-rw-r--r--target/linux/brcm2708/patches-4.4/0108-dts-Added-overlay-for-Adafruit-PiTFT-2.8-capacitive-.patch145
-rw-r--r--target/linux/brcm2708/patches-4.4/0109-Add-support-for-the-HiFiBerry-DAC-Pro.patch539
-rw-r--r--target/linux/brcm2708/patches-4.4/0109-dts-Added-overlay-for-Adafruit-PiTFT-2.8-capacitive-.patch145
-rw-r--r--target/linux/brcm2708/patches-4.4/0110-Add-support-for-the-HiFiBerry-DAC-Pro.patch539
-rw-r--r--target/linux/brcm2708/patches-4.4/0110-BCM270X_DT-Add-at86rf233-overlay.patch130
-rw-r--r--target/linux/brcm2708/patches-4.4/0111-BCM270X_DT-Add-at86rf233-overlay.patch130
-rw-r--r--target/linux/brcm2708/patches-4.4/0111-mm-Remove-the-PFN-busy-warning.patch25
-rw-r--r--target/linux/brcm2708/patches-4.4/0112-drm-Put-an-optional-field-in-the-driver-struct-for-G.patch40
-rw-r--r--target/linux/brcm2708/patches-4.4/0112-mm-Remove-the-PFN-busy-warning.patch25
-rw-r--r--target/linux/brcm2708/patches-4.4/0113-drm-Put-an-optional-field-in-the-driver-struct-for-G.patch40
-rw-r--r--target/linux/brcm2708/patches-4.4/0113-drm-vc4-Add-an-interface-for-capturing-the-GPU-state.patch333
-rw-r--r--target/linux/brcm2708/patches-4.4/0114-drm-vc4-Add-an-interface-for-capturing-the-GPU-state.patch333
-rw-r--r--target/linux/brcm2708/patches-4.4/0114-drm-vc4-Update-a-bunch-of-code-to-match-upstream-sub.patch1894
-rw-r--r--target/linux/brcm2708/patches-4.4/0115-drm-Use-the-driver-s-gem_object_free-function-from-C.patch59
-rw-r--r--target/linux/brcm2708/patches-4.4/0115-drm-vc4-Update-a-bunch-of-code-to-match-upstream-sub.patch1894
-rw-r--r--target/linux/brcm2708/patches-4.4/0116-drm-Use-the-driver-s-gem_object_free-function-from-C.patch59
-rw-r--r--target/linux/brcm2708/patches-4.4/0116-drm-vc4-Add-support-for-MSAA-rendering.patch518
-rw-r--r--target/linux/brcm2708/patches-4.4/0117-drm-vc4-A-few-more-non-functional-changes-to-sync-to.patch345
-rw-r--r--target/linux/brcm2708/patches-4.4/0117-drm-vc4-Add-support-for-MSAA-rendering.patch518
-rw-r--r--target/linux/brcm2708/patches-4.4/0118-drm-vc4-A-few-more-non-functional-changes-to-sync-to.patch345
-rw-r--r--target/linux/brcm2708/patches-4.4/0118-drm-vc4-Use-hpd-gpios-for-HDMI-GPIO-like-what-landed.patch22
-rw-r--r--target/linux/brcm2708/patches-4.4/0119-drm-vc4-Synchronize-validation-code-for-v2-submissio.patch612
-rw-r--r--target/linux/brcm2708/patches-4.4/0119-drm-vc4-Use-hpd-gpios-for-HDMI-GPIO-like-what-landed.patch22
-rw-r--r--target/linux/brcm2708/patches-4.4/0120-MMC-Do-not-use-mmc_debug-if-CONFIG_MMC_BCM2835-is-no.patch37
-rw-r--r--target/linux/brcm2708/patches-4.4/0120-drm-vc4-Synchronize-validation-code-for-v2-submissio.patch612
-rw-r--r--target/linux/brcm2708/patches-4.4/0121-Extend-clock-timeout-fix-modprobe-baudrate-parameter.patch108
-rw-r--r--target/linux/brcm2708/patches-4.4/0121-MMC-Do-not-use-mmc_debug-if-CONFIG_MMC_BCM2835-is-no.patch37
-rw-r--r--target/linux/brcm2708/patches-4.4/0122-Extend-clock-timeout-fix-modprobe-baudrate-parameter.patch108
-rw-r--r--target/linux/brcm2708/patches-4.4/0122-bcm270x_dt-Add-dwc2-and-dwc-otg-overlays.patch110
-rw-r--r--target/linux/brcm2708/patches-4.4/0123-BCM270X_DT-Add-the-sdtweak-overlay-for-tuning-sdhost.patch74
-rw-r--r--target/linux/brcm2708/patches-4.4/0123-bcm270x_dt-Add-dwc2-and-dwc-otg-overlays.patch110
-rw-r--r--target/linux/brcm2708/patches-4.4/0124-BCM270X_DT-Add-the-sdtweak-overlay-for-tuning-sdhost.patch74
-rw-r--r--target/linux/brcm2708/patches-4.4/0124-bcm2835-mmc-Don-t-override-bus-width-capabilities-fr.patch24
-rw-r--r--target/linux/brcm2708/patches-4.4/0125-SDIO-overlay-add-bus_width-parameter.patch42
-rw-r--r--target/linux/brcm2708/patches-4.4/0125-bcm2835-mmc-Don-t-override-bus-width-capabilities-fr.patch24
-rw-r--r--target/linux/brcm2708/patches-4.4/0126-SDIO-overlay-add-bus_width-parameter.patch42
-rw-r--r--target/linux/brcm2708/patches-4.4/0126-bcm2835-extend-allowed-range-of-channels-and-sampler.patch37
-rw-r--r--target/linux/brcm2708/patches-4.4/0127-FIXUP-BCM270X_DT-random-HWRNG-dtparam-default-is-on.patch21
-rw-r--r--target/linux/brcm2708/patches-4.4/0127-bcm2835-restrict-channels-rate-to-8-960000.patch80
-rw-r--r--target/linux/brcm2708/patches-4.4/0128-bcm2835-extend-allowed-range-of-channels-and-sampler.patch37
-rw-r--r--target/linux/brcm2708/patches-4.4/0128-rpi-update-vc_vchi_audioserv_defs.h.patch66
-rw-r--r--target/linux/brcm2708/patches-4.4/0129-bcm2835-implement-channel-map-API.patch421
-rw-r--r--target/linux/brcm2708/patches-4.4/0129-bcm2835-restrict-channels-rate-to-8-960000.patch80
-rw-r--r--target/linux/brcm2708/patches-4.4/0130-bcm2835-access-controls-under-the-audio-mutex.patch237
-rw-r--r--target/linux/brcm2708/patches-4.4/0130-rpi-update-vc_vchi_audioserv_defs.h.patch66
-rw-r--r--target/linux/brcm2708/patches-4.4/0131-bcm2835-always-use-2-4-8-channels-for-multichannel-l.patch139
-rw-r--r--target/linux/brcm2708/patches-4.4/0131-bcm2835-implement-channel-map-API.patch421
-rw-r--r--target/linux/brcm2708/patches-4.4/0132-bcm2835-access-controls-under-the-audio-mutex.patch237
-rw-r--r--target/linux/brcm2708/patches-4.4/0132-bcm2835-only-allow-stereo-if-analogue-jack-is-select.patch62
-rw-r--r--target/linux/brcm2708/patches-4.4/0133-bcm2835-always-use-2-4-8-channels-for-multichannel-l.patch139
-rw-r--r--target/linux/brcm2708/patches-4.4/0133-bcm2835-interpolate-audio-delay.patch90
-rw-r--r--target/linux/brcm2708/patches-4.4/0134-bcm2835-only-allow-stereo-if-analogue-jack-is-select.patch62
-rw-r--r--target/linux/brcm2708/patches-4.4/0134-bcm2835-sdhost-Add-workaround-for-odd-behaviour-on-s.patch137
-rw-r--r--target/linux/brcm2708/patches-4.4/0135-bcm2835-interpolate-audio-delay.patch90
-rw-r--r--target/linux/brcm2708/patches-4.4/0135-bcm2835-sdhost-Add-debug_flags-dtparam.patch120
-rw-r--r--target/linux/brcm2708/patches-4.4/0136-BCM270X_DT-Add-sdio_overclock-parameter-to-sdio-over.patch69
-rw-r--r--target/linux/brcm2708/patches-4.4/0136-bcm2835-sdhost-Add-workaround-for-odd-behaviour-on-s.patch137
-rw-r--r--target/linux/brcm2708/patches-4.4/0137-bcm2835-sdhost-Add-debug_flags-dtparam.patch120
-rw-r--r--target/linux/brcm2708/patches-4.4/0137-rtc-ds1307-add-support-for-the-DT-property-wakeup-so.patch94
-rw-r--r--target/linux/brcm2708/patches-4.4/0138-BCM270X_DT-Add-sdio_overclock-parameter-to-sdio-over.patch69
-rw-r--r--target/linux/brcm2708/patches-4.4/0138-dt-overlay-add-wittypi-overlay.dts.patch57
-rw-r--r--target/linux/brcm2708/patches-4.4/0139-FIXUP-i2c_bcm2708-Don-t-change-module-baudrate-param.patch99
-rw-r--r--target/linux/brcm2708/patches-4.4/0139-rtc-ds1307-add-support-for-the-DT-property-wakeup-so.patch94
-rw-r--r--target/linux/brcm2708/patches-4.4/0140-Allow-up-to-24dB-digital-gain-to-be-applied-when-usi.patch99
-rw-r--r--target/linux/brcm2708/patches-4.4/0140-dt-overlay-add-wittypi-overlay.dts.patch57
-rw-r--r--target/linux/brcm2708/patches-4.4/0141-BCM270X_DT-Disable-DMA-for-bcm2835-sdhost-on-Pi2.patch28
-rw-r--r--target/linux/brcm2708/patches-4.4/0141-Limit-PCM512x-Digital-gain-to-0dB-by-default-with-Hi.patch98
-rw-r--r--target/linux/brcm2708/patches-4.4/0142-BCM270X_DT-Adjust-overlay-README-formatting.patch729
-rw-r--r--target/linux/brcm2708/patches-4.4/0142-FIXUP-i2c_bcm2708-Don-t-change-module-baudrate-param.patch99
-rw-r--r--target/linux/brcm2708/patches-4.4/0143-Allow-up-to-24dB-digital-gain-to-be-applied-when-usi.patch99
-rw-r--r--target/linux/brcm2708/patches-4.4/0143-bcm2835-sdhost-Major-revision.patch2070
-rw-r--r--target/linux/brcm2708/patches-4.4/0144-BCM270X_DT-Add-dtparams-for-the-SD-interface.patch235
-rw-r--r--target/linux/brcm2708/patches-4.4/0144-Limit-PCM512x-Digital-gain-to-0dB-by-default-with-Hi.patch98
-rw-r--r--target/linux/brcm2708/patches-4.4/0145-BCM270X_DT-Adjust-overlay-README-formatting.patch746
-rw-r--r--target/linux/brcm2708/patches-4.4/0145-dcw_otg-trim-xfer-length-when-buffer-larger-than-all.patch37
-rw-r--r--target/linux/brcm2708/patches-4.4/0146-FIXUP-Overlay-README-Restore-spaces-deleted-in-error.patch39
-rw-r--r--target/linux/brcm2708/patches-4.4/0146-bcm2835-sdhost-Restore-ATOMIC-flag-to-PIO-sg-mapping.patch32
-rw-r--r--target/linux/brcm2708/patches-4.4/0147-Updated-smsc95xx-driver-to-check-for-a-valid-MAC-add.patch40
-rw-r--r--target/linux/brcm2708/patches-4.4/0148-Revert-BCM270X_DT-Disable-DMA-for-bcm2835-sdhost-on-.patch21
-rw-r--r--target/linux/brcm2708/patches-4.4/0148-dcw_otg-Make-trimming-messages-less-noisy.patch31
-rw-r--r--target/linux/brcm2708/patches-4.4/0149-BCM270X_DT-at86rf233-overlay-drop-to-3MHz.patch36
-rw-r--r--target/linux/brcm2708/patches-4.4/0149-bcm2835-sdhost-Major-revision.patch2070
-rw-r--r--target/linux/brcm2708/patches-4.4/0150-BCM270X_DT-Add-dtparams-for-the-SD-interface.patch235
-rw-r--r--target/linux/brcm2708/patches-4.4/0150-bcm2835-sdhost-Downgrade-log-message-status.patch22
-rw-r--r--target/linux/brcm2708/patches-4.4/0151-config-Enable-HCI-over-UARTs.patch33
-rw-r--r--target/linux/brcm2708/patches-4.4/0151-dcw_otg-trim-xfer-length-when-buffer-larger-than-all.patch37
-rw-r--r--target/linux/brcm2708/patches-4.4/0152-bcm2835-sdhost-Restore-ATOMIC-flag-to-PIO-sg-mapping.patch32
-rw-r--r--target/linux/brcm2708/patches-4.4/0152-hci_h5-Don-t-send-conf_req-when-ACTIVE.patch23
-rw-r--r--target/linux/brcm2708/patches-4.4/0153-Revert-Add-blk_pos-parameter-to-mmc-multi_io_quirk-c.patch79
-rw-r--r--target/linux/brcm2708/patches-4.4/0153-amba_pl011-Don-t-use-DT-aliases-for-numbering.patch29
-rw-r--r--target/linux/brcm2708/patches-4.4/0154-Updated-smsc95xx-driver-to-check-for-a-valid-MAC-add.patch40
-rw-r--r--target/linux/brcm2708/patches-4.4/0154-clk-bcm2835-Add-bindings-for-the-auxiliary-periphera.patch72
-rw-r--r--target/linux/brcm2708/patches-4.4/0155-clk-bcm2835-Add-a-driver-for-the-auxiliary-periphera.patch118
-rw-r--r--target/linux/brcm2708/patches-4.4/0155-dcw_otg-Make-trimming-messages-less-noisy.patch31
-rw-r--r--target/linux/brcm2708/patches-4.4/0156-Aux-SPI-1-2-implementation.patch700
-rw-r--r--target/linux/brcm2708/patches-4.4/0156-BCM270X_DT-at86rf233-overlay-drop-to-3MHz.patch36
-rw-r--r--target/linux/brcm2708/patches-4.4/0157-ASoC-bcm-add-missing-.owner-fields-in-sound-card-dri.patch108
-rw-r--r--target/linux/brcm2708/patches-4.4/0157-bcm2835-sdhost-Downgrade-log-message-status.patch22
-rw-r--r--target/linux/brcm2708/patches-4.4/0158-config-Enable-HCI-over-UARTs.patch33
-rw-r--r--target/linux/brcm2708/patches-4.4/0158-smsx95xx-Add-option-to-disable-the-crimes-against-tr.patch44
-rw-r--r--target/linux/brcm2708/patches-4.4/0159-bcm2835-virtgpio-Virtual-GPIO-driver.patch244
-rw-r--r--target/linux/brcm2708/patches-4.4/0159-hci_h5-Don-t-send-conf_req-when-ACTIVE.patch23
-rw-r--r--target/linux/brcm2708/patches-4.4/0160-BCM270X_DT-Add-Pi3-support.patch323
-rw-r--r--target/linux/brcm2708/patches-4.4/0160-amba_pl011-Don-t-use-DT-aliases-for-numbering.patch29
-rw-r--r--target/linux/brcm2708/patches-4.4/0161-DT-Add-overlays-to-configure-I2C-pins.patch134
-rw-r--r--target/linux/brcm2708/patches-4.4/0161-clk-bcm2835-Add-bindings-for-the-auxiliary-periphera.patch72
-rw-r--r--target/linux/brcm2708/patches-4.4/0162-bcm2835-camera-fix-a-bug-in-computation-of-frame-tim.patch23
-rw-r--r--target/linux/brcm2708/patches-4.4/0162-clk-bcm2835-Add-a-driver-for-the-auxiliary-periphera.patch118
-rw-r--r--target/linux/brcm2708/patches-4.4/0163-Aux-SPI-1-2-implementation.patch700
-rw-r--r--target/linux/brcm2708/patches-4.4/0163-BCM270X_DT-Add-pi3-disable-bt-overlay.patch96
-rw-r--r--target/linux/brcm2708/patches-4.4/0164-ASoC-bcm-add-missing-.owner-fields-in-sound-card-dri.patch108
-rw-r--r--target/linux/brcm2708/patches-4.4/0164-BCM270X_DT-Add-pi3-miniuart-bt-DT-overlay.patch117
-rw-r--r--target/linux/brcm2708/patches-4.4/0165-Pi3-DT-Add-dtparams-for-the-SD-interface.patch25
-rw-r--r--target/linux/brcm2708/patches-4.4/0165-smsx95xx-Add-option-to-disable-the-crimes-against-tr.patch44
-rw-r--r--target/linux/brcm2708/patches-4.4/0166-bcm2835-virtgpio-Virtual-GPIO-driver.patch244
-rw-r--r--target/linux/brcm2708/patches-4.4/0166-vchiq_arm-Tweak-the-logging-output.patch75
-rw-r--r--target/linux/brcm2708/patches-4.4/0167-BCM270X_DT-Add-Pi3-support.patch305
-rw-r--r--target/linux/brcm2708/patches-4.4/0167-bcm2835-sdhost-Only-claim-one-DMA-channel.patch160
-rw-r--r--target/linux/brcm2708/patches-4.4/0168-FIXUP-BCM270X_DT-Update-to-latest-Pi3-DTS.patch82
-rw-r--r--target/linux/brcm2708/patches-4.4/0168-bcm2835-mmc-Only-claim-one-DMA-channel.patch170
-rw-r--r--target/linux/brcm2708/patches-4.4/0169-DT-Add-overlays-to-configure-I2C-pins.patch134
-rw-r--r--target/linux/brcm2708/patches-4.4/0169-config-rebuild-with-savedefconfig.patch28
-rw-r--r--target/linux/brcm2708/patches-4.4/0170-bcm2835-camera-fix-a-bug-in-computation-of-frame-tim.patch23
-rw-r--r--target/linux/brcm2708/patches-4.4/0170-config-Add-module-for-mcp3422-ADC.patch30
-rw-r--r--target/linux/brcm2708/patches-4.4/0171-BCM270X_DT-Add-pi3-disable-bt-overlay.patch96
-rw-r--r--target/linux/brcm2708/patches-4.4/0171-Pi3-DT-Add-pull-ups-on-the-UART-RX-lines.patch40
-rw-r--r--target/linux/brcm2708/patches-4.4/0172-BCM270X_DT-Add-pi3-miniuart-bt-DT-overlay.patch117
-rw-r--r--target/linux/brcm2708/patches-4.4/0173-BCM270X_DT-rpi-display-overlay-add-swapxy-param.patch38
-rw-r--r--target/linux/brcm2708/patches-4.4/0173-Pi3-DT-Add-dtparams-for-the-SD-interface.patch25
-rw-r--r--target/linux/brcm2708/patches-4.4/0174-Remove-I2S-config-from-bt_pins.patch38
-rw-r--r--target/linux/brcm2708/patches-4.4/0174-vchiq_arm-Tweak-the-logging-output.patch75
-rw-r--r--target/linux/brcm2708/patches-4.4/0175-Revert-scripts-dtc-Add-overlay-support.patch4390
-rw-r--r--target/linux/brcm2708/patches-4.4/0175-bcm2835-sdhost-Only-claim-one-DMA-channel.patch160
-rw-r--r--target/linux/brcm2708/patches-4.4/0176-bcm2835-mmc-Only-claim-one-DMA-channel.patch170
-rw-r--r--target/linux/brcm2708/patches-4.4/0176-scripts-dtc-Update-to-upstream-version-1.4.1.patch2736
-rw-r--r--target/linux/brcm2708/patches-4.4/0177-config-rebuild-with-savedefconfig.patch28
-rw-r--r--target/linux/brcm2708/patches-4.4/0177-configfs-implement-binary-attributes.patch639
-rw-r--r--target/linux/brcm2708/patches-4.4/0178-OF-DT-Overlay-configfs-interface.patch408
-rw-r--r--target/linux/brcm2708/patches-4.4/0178-config-Add-module-for-mcp3422-ADC.patch30
-rw-r--r--target/linux/brcm2708/patches-4.4/0179-Pi3-DT-Add-pull-ups-on-the-UART-RX-lines.patch40
-rw-r--r--target/linux/brcm2708/patches-4.4/0179-Protect-__release_resource-against-resources-without.patch28
-rw-r--r--target/linux/brcm2708/patches-4.4/0180-BCM270X_DT-Add-a-.dtbo-target-use-for-overlays.patch193
-rw-r--r--target/linux/brcm2708/patches-4.4/0181-scripts-knlinfo-Decode-DDTK-atom.patch31
-rw-r--r--target/linux/brcm2708/patches-4.4/0182-Enable-Dynamic-Device-Tree-for-bcmrpi_defconfig-and-.patch40
-rw-r--r--target/linux/brcm2708/patches-4.4/0183-SQUASH-Add-CONFIG_OF_CONFIGFS-to-bcmrpi_defconfig.patch29
-rw-r--r--target/linux/brcm2708/patches-4.4/0184-dts-kbuild-dtbs_install-installs-.dtbo-files-too.patch42
-rw-r--r--target/linux/brcm2708/patches-4.4/0185-bcm2835-sdhost-Workaround-for-slow-sectors.patch118
-rw-r--r--target/linux/brcm2708/patches-4.4/0186-BCM270X_DT-Add-labels-to-spidev-nodes.patch114
-rw-r--r--target/linux/brcm2708/patches-4.4/0187-BCM270X_DT-Use-spidev-labels-in-overlays.patch628
-rw-r--r--target/linux/brcm2708/patches-4.4/0188-BCM270X_DT-Build-and-document-the-wittypi-overlay.patch50
-rw-r--r--target/linux/brcm2708/patches-4.4/0189-scripts-dtc-Fix-UMR-causing-corrupt-dtbo-overlay-fil.patch27
-rw-r--r--target/linux/brcm2708/patches-4.4/0190-BCM270X_DT-Add-dtparam-for-uart1.patch77
-rw-r--r--target/linux/brcm2708/patches-4.4/0191-dwc-overlay-Use-label-so-overrides-can-apply.patch34
-rw-r--r--target/linux/brcm2708/patches-4.4/0192-drm-vc4-Add-a-debugfs-node-for-tracking-execution-st.patch56
-rw-r--r--target/linux/brcm2708/patches-4.4/0193-drm-vc4-Include-vc4_drm.h-in-uapi-in-downstream-buil.patch21
-rw-r--r--target/linux/brcm2708/patches-4.4/0194-drm-vc4-Validate-that-WAIT_BO-padding-is-cleared.patch25
-rw-r--r--target/linux/brcm2708/patches-4.4/0195-drm-vc4-Fix-the-clear-color-for-the-first-tile-rende.patch49
-rw-r--r--target/linux/brcm2708/patches-4.4/0196-drm-vc4-Return-an-ERR_PTR-from-BO-creation-instead-o.patch137
-rw-r--r--target/linux/brcm2708/patches-4.4/0197-drm-vc4-Fix-ERESTARTSYS-error-return-from-BO-waits.patch32
-rw-r--r--target/linux/brcm2708/patches-4.4/0198-drm-vc4-Drop-error-message-on-seqno-wait-timeouts.patch27
-rw-r--r--target/linux/brcm2708/patches-4.4/0199-BCM270X_DT-Add-1-bit-SDIO-using-minimal-pins.patch81
-rw-r--r--target/linux/brcm2708/patches-4.4/0201-Add-overlay-and-enable-support-for-QCA7000-board.patch127
-rw-r--r--target/linux/brcm2708/patches-4.4/0202-serial-Take-care-starting-a-hung-up-tty-s-port.patch28
-rw-r--r--target/linux/brcm2708/patches-4.4/0203-pi3-miniuart-bt-overlay-Correct-and-clarify-info.patch41
-rw-r--r--target/linux/brcm2708/patches-4.4/0204-pwm-overlays-Params-must-have-in-overlay-targets.patch52
-rw-r--r--target/linux/brcm2708/patches-4.4/0205-BCM270X_DT-Switch-Compute-Module-to-MMC.patch53
-rw-r--r--target/linux/brcm2708/patches-4.4/0206-dwc_otg-Don-t-free-qh-align-buffers-in-atomic-contex.patch44
-rw-r--r--target/linux/brcm2708/patches-4.4/0207-dwc_otg-Enable-the-hack-for-Split-Interrupt-transact.patch28
-rw-r--r--target/linux/brcm2708/patches-4.4/0208-BCM270X_DT-Remove-explicit-claiming-of-UART-pins.patch89
-rw-r--r--target/linux/brcm2708/patches-4.4/0209-lirc_rpi-Lower-IR-reception-error-to-debug.patch21
-rw-r--r--target/linux/brcm2708/patches-4.4/0210-vchiq_arm-Access-the-dequeue_pending-flag-locked.patch58
-rw-r--r--target/linux/brcm2708/patches-4.4/0211-BCM270X_DT-Add-pi3-act-led-overlay.patch94
-rw-r--r--target/linux/brcm2708/patches-4.4/0212-vchiq_arm-Service-callbacks-must-not-fail.patch26
-rw-r--r--target/linux/brcm2708/patches-4.4/0213-Add-configs-and-overlay-for-PCA9548-I2C-mux.patch133
-rw-r--r--target/linux/brcm2708/patches-4.4/0214-BCM270X_DT-Add-DS1339-to-i2c-rtc-overlay.patch58
-rw-r--r--target/linux/brcm2708/patches-4.4/0215-copy_from_user-CPU_SW_DOMAIN_PAN-compatibility.patch53
-rw-r--r--target/linux/brcm2708/patches-4.4/0216-bcm2835-sdhost-Adjust-to-core-clock-changes.patch339
-rw-r--r--target/linux/brcm2708/patches-4.4/0217-BCM270X_DT-Document-hazards-of-sdhost-overlay.patch34
-rw-r--r--target/linux/brcm2708/patches-4.4/0218-cpufreq-Temporarily-ignore-io_is_busy-1.patch31
-rw-r--r--target/linux/brcm2708/patches-4.4/0219-Revert-cpufreq-Temporarily-ignore-io_is_busy-1.patch26
-rw-r--r--target/linux/brcm2708/patches-4.4/0220-net-sched-add-skb_at_tc_ingress-helper.patch50
-rw-r--r--target/linux/brcm2708/patches-4.4/0222-bcm2835-sdhost-Precalc-divisors-and-overclocks.patch270
-rw-r--r--target/linux/brcm2708/patches-4.4/0223-Revert-bcm2835-sdhost-Precalc-divisors-and-overclock.patch267
-rw-r--r--target/linux/brcm2708/patches-4.4/0224-Revert-bcm2835-sdhost-Adjust-to-core-clock-changes.patch327
-rw-r--r--target/linux/brcm2708/patches-4.4/0225-bcm2835-sdhost-Firmware-manages-the-clock-divisor.patch226
-rw-r--r--target/linux/brcm2708/patches-4.4/0226-Revert-Revert-cpufreq-Temporarily-ignore-io_is_busy-.patch27
-rw-r--r--target/linux/brcm2708/patches-4.4/0227-config-Enabled-IPV6_SUBTREES.patch30
-rw-r--r--target/linux/brcm2708/patches-4.4/0228-add-smsc95xx-packetsize-module_param.patch42
-rw-r--r--target/linux/brcm2708/patches-4.4/0229-reboot-Use-power-off-rather-than-busy-spinning-when-.patch25
-rw-r--r--target/linux/brcm2708/patches-4.4/0230-Revert-bcm2835-dma-Fix-dreq-not-set-for-slave-transf.patch32
-rw-r--r--target/linux/brcm2708/patches-4.4/0231-RPi-config-Add-CONFIG_PWM_PCA9685-for-NXP-PCA9685-dr.patch92
-rw-r--r--target/linux/brcm2708/patches-4.4/0232-BCM270X_DT-Don-t-generate-linux-phandle-props.patch36
-rw-r--r--target/linux/brcm2708/patches-4.4/0233-V4L2-driver-updates-1393.patch718
-rw-r--r--target/linux/brcm2708/patches-4.4/0234-bcm2835-sdhost-Reset-the-clock-in-task-context.patch107
-rw-r--r--target/linux/brcm2708/patches-4.4/0235-config-Enable-CONFIG_IPV6_ROUTER_PREF-for-networks-w.patch31
-rw-r--r--target/linux/brcm2708/patches-4.4/0236-Enable-hid-betopff-module.patch32
-rw-r--r--target/linux/brcm2708/patches-4.4/0237-config-Make-IPV6-a-module-and-regenerate-with-defcon.patch70
-rw-r--r--target/linux/brcm2708/patches-4.4/0238-BCM270X_DT-Add-dpi24-overlay.patch74
-rw-r--r--target/linux/brcm2708/patches-4.4/0239-Modify-IQAudIO-DAC-ASoC-driver-to-set-card-dai-confi.patch57
-rw-r--r--target/linux/brcm2708/patches-4.4/0240-Add-support-for-the-Digital-Dreamtime-Akkordion-musi.patch105
-rw-r--r--target/linux/brcm2708/patches-4.4/0241-Add-Support-for-BoomBerry-Audio-boards.patch605
-rw-r--r--target/linux/brcm2708/patches-4.4/0242-Add-support-for-mcp7940x-family-of-RTC.patch43
-rw-r--r--target/linux/brcm2708/patches-4.4/0243-bcm2709_defconfig-Fix-typo-on-BoomBerry-configuratio.patch22
-rw-r--r--target/linux/brcm2708/patches-4.4/0244-boomberry-dac-Adjust-for-ALSA-API-change.patch26
-rw-r--r--target/linux/brcm2708/patches-4.4/0245-vmcs-Remove-unused-sm_cache_map_vector-definition-14.patch35
-rw-r--r--target/linux/brcm2708/patches-4.4/0246-scripts-mkknlimg-Append-a-trailer-for-all-input.patch63
-rw-r--r--target/linux/brcm2708/patches-4.4/0247-bcm2835_thermal-Don-t-report-unsupported-trip-type.patch69
-rw-r--r--target/linux/brcm2708/patches-4.4/0248-scripts-dtc-Only-emit-local-fixups-for-overlays.patch21
-rw-r--r--target/linux/brcm2708/patches-4.4/0249-bcm2835-do-not-require-substream-for-accessing-chmap.patch51
-rw-r--r--target/linux/brcm2708/patches-4.4/0250-bcm2835-add-fallback-channel-layouts-if-channel-map-.patch41
-rw-r--r--target/linux/brcm2708/patches-4.4/0251-bcm2835-log-which-channel-map-is-set.patch32
-rw-r--r--target/linux/brcm2708/patches-4.4/0252-clk-bcm2835-add-a-round-up-ability-to-the-clock-divi.patch70
-rw-r--r--target/linux/brcm2708/patches-4.4/0253-clk-bcm2835-Support-for-clock-parent-selection.patch188
-rw-r--r--target/linux/brcm2708/patches-4.4/0254-clk-bcm2835-Add-PWM-clock-support.patch55
-rw-r--r--target/linux/brcm2708/patches-4.4/0255-clk-bcm2835-added-missing-clock-register-definitions.patch49
-rw-r--r--target/linux/brcm2708/patches-4.4/0258-clk-bcm2835-correctly-enable-fractional-clock-suppor.patch134
-rw-r--r--target/linux/brcm2708/patches-4.4/0259-clk-bcm2835-clean-up-coding-style-issues.patch52
-rw-r--r--target/linux/brcm2708/patches-4.4/0260-clk-bcm2835-expose-raw-clock-registers-via-debugfs.patch188
-rw-r--r--target/linux/brcm2708/patches-4.4/0261-clk-bcm2835-remove-use-of-BCM2835_CLOCK_COUNT-in-dri.patch237
-rw-r--r--target/linux/brcm2708/patches-4.4/0262-clk-bcm2835-reorganize-bcm2835_clock_array-assignmen.patch926
-rw-r--r--target/linux/brcm2708/patches-4.4/0263-clk-bcm2835-enable-management-of-PCM-clock.patch40
-rw-r--r--target/linux/brcm2708/patches-4.4/0264-clk-bcm2835-add-missing-PLL-clock-dividers.patch73
-rw-r--r--target/linux/brcm2708/patches-4.4/0265-clk-bcm2835-add-missing-osc-and-per-clocks.patch184
-rw-r--r--target/linux/brcm2708/patches-4.4/0266-clk-bcm2835-Fix-PLL-poweron.patch32
-rw-r--r--target/linux/brcm2708/patches-4.4/0267-ARM-bcm2835-Define-two-new-packets-from-the-latest-f.patch33
-rw-r--r--target/linux/brcm2708/patches-4.4/0268-ARM-bcm2835-add-rpi-power-domain-driver.patch361
-rw-r--r--target/linux/brcm2708/patches-4.4/0269-ARM-bcm2835-clarify-RASPBERRYPI_FIRMWARE-dependency.patch36
-rw-r--r--target/linux/brcm2708/patches-4.4/0270-ARM-bcm2708-Enable-building-power-domain-driver.patch20
-rw-r--r--target/linux/brcm2708/patches-4.4/0271-bcm2708-Add-RASPBERRYPI_POWER-to-the-defconfigs.patch50
-rw-r--r--target/linux/brcm2708/patches-4.4/0272-bcm2708-Add-the-power-domain-driver-to-the-device-tr.patch26
-rw-r--r--target/linux/brcm2708/patches-4.4/0273-bcm2708-Reference-the-HDMI-power-domain-for-the-HDMI.patch29
-rw-r--r--target/linux/brcm2708/patches-4.4/0274-drm-vc4-copy_to_user-returns-the-number-of-bytes-rem.patch87
-rw-r--r--target/linux/brcm2708/patches-4.4/0275-drm-vc4-allocate-enough-memory-in-vc4_save_hang_stat.patch27
-rw-r--r--target/linux/brcm2708/patches-4.4/0276-drm-vc4-fix-warning-in-validate-printf.patch32
-rw-r--r--target/linux/brcm2708/patches-4.4/0277-drm-vc4-Improve-comments-on-vc4_plane_state-members.patch36
-rw-r--r--target/linux/brcm2708/patches-4.4/0278-drm-vc4-Add-missing-__iomem-annotation-to-hw_dlist.patch25
-rw-r--r--target/linux/brcm2708/patches-4.4/0279-drm-vc4-Move-the-plane-clipping-scaling-setup-to-a-s.patch143
-rw-r--r--target/linux/brcm2708/patches-4.4/0280-drm-vc4-Add-a-proper-short-circut-path-for-legacy-cu.patch192
-rw-r--r--target/linux/brcm2708/patches-4.4/0281-drm-vc4-Make-the-CRTCs-cooperate-on-allocating-displ.patch248
-rw-r--r--target/linux/brcm2708/patches-4.4/0282-drm-vc4-Add-more-display-planes-to-each-CRTC.patch106
-rw-r--r--target/linux/brcm2708/patches-4.4/0283-drm-vc4-Fix-which-value-is-being-used-for-source-ima.patch77
-rw-r--r--target/linux/brcm2708/patches-4.4/0284-drm-vc4-Add-support-for-scaling-of-display-planes.patch579
-rw-r--r--target/linux/brcm2708/patches-4.4/0285-drm-vc4-Add-support-for-YUV-planes.patch519
-rw-r--r--target/linux/brcm2708/patches-4.4/0286-drm-vc4-Fix-spurious-GPU-resets-due-to-BO-reuse.patch81
-rw-r--r--target/linux/brcm2708/patches-4.4/0287-drm-vc4-Fix-a-framebuffer-reference-leak-on-async-fl.patch26
-rw-r--r--target/linux/brcm2708/patches-4.4/0288-drm-vc4-Bring-HDMI-up-from-power-off-if-necessary.patch72
-rw-r--r--target/linux/brcm2708/patches-4.4/0289-drm-vc4-Add-another-reg-to-HDMI-debug-dumping.patch24
-rw-r--r--target/linux/brcm2708/patches-4.4/0290-drm-vc4-Fix-the-name-of-the-VSYNCD_EVEN-register.patch36
-rw-r--r--target/linux/brcm2708/patches-4.4/0291-drm-vc4-Fix-setting-of-vertical-timings-in-the-CRTC.patch34
-rw-r--r--target/linux/brcm2708/patches-4.4/0292-drm-vc4-Initialize-scaler-DISPBKGND-on-modeset.patch68
-rw-r--r--target/linux/brcm2708/patches-4.4/0293-drm-vc4-improve-throughput-by-pipelining-binning-and.patch429
-rw-r--r--target/linux/brcm2708/patches-4.4/0294-drm-vc4-Let-gpiolib-know-that-we-re-OK-with-sleeping.patch27
-rw-r--r--target/linux/brcm2708/patches-4.4/0295-drm-vc4-Respect-GPIO_ACTIVE_LOW-on-HDMI-HPD-if-set-i.patch57
-rw-r--r--target/linux/brcm2708/patches-4.4/0296-drm-vc4-Return-EFAULT-on-copy_from_user-failure.patch36
-rw-r--r--target/linux/brcm2708/patches-4.4/0297-drm-vc4-Recognize-a-more-specific-compatible-string-.patch29
-rw-r--r--target/linux/brcm2708/patches-4.4/0298-ARM-bcm2708-Move-the-CMA-range-down-for-kernel-4.4.patch24
-rw-r--r--target/linux/brcm2708/patches-4.4/0299-clk-bcm2835-fix-check-of-error-code-returned-by-devm.patch33
-rw-r--r--target/linux/brcm2708/patches-4.4/0300-vchiq_arm-Add-completion-records-under-the-mutex.patch63
-rw-r--r--target/linux/brcm2708/patches-4.4/0301-config-Add-DRM_UDL-module.patch59
-rw-r--r--target/linux/brcm2708/patches-4.4/0302-bcm2835-i2s-Reduce-the-TX-DREQ-threshold.patch48
-rw-r--r--target/linux/brcm2708/patches-4.4/0303-V4L2-Request-maximum-resolution-from-GPU.patch193
-rw-r--r--target/linux/brcm2708/patches-4.4/0304-ARM-bcm2835-add-i2s-gpio28-31-for-cm.patch62
-rw-r--r--target/linux/brcm2708/patches-4.4/0305-drm-vc4-Add-DT-parameters-to-control-CMA-usage.patch75
-rw-r--r--target/linux/brcm2708/patches-4.4/0306-SQUASH-BCM270X_DT-Add-make-rule-for-sdio-1bit.patch22
-rw-r--r--target/linux/brcm2708/patches-4.4/0307-dts-add-overlay-for-pitft22.patch123
-rw-r--r--target/linux/brcm2708/patches-4.4/0308-BCM270X_DT-Sound-DT-adjustments-for-Dynamic-DT.patch578
-rw-r--r--target/linux/brcm2708/patches-4.4/0309-BCM270X_DT-Fix-codec-use-in-hifiberry-dac-overlay.patch21
-rw-r--r--target/linux/brcm2708/patches-4.4/0312-Revert-bcm2835-log-which-channel-map-is-set.patch33
-rw-r--r--target/linux/brcm2708/patches-4.4/0313-Revert-bcm2835-add-fallback-channel-layouts-if-chann.patch31
-rw-r--r--target/linux/brcm2708/patches-4.4/0314-Revert-bcm2835-do-not-require-substream-for-accessin.patch51
-rw-r--r--target/linux/brcm2708/patches-4.4/0315-Revert-bcm2835-interpolate-audio-delay.patch70
-rw-r--r--target/linux/brcm2708/patches-4.4/0316-Revert-bcm2835-only-allow-stereo-if-analogue-jack-is.patch49
-rw-r--r--target/linux/brcm2708/patches-4.4/0317-Revert-bcm2835-always-use-2-4-8-channels-for-multich.patch135
-rw-r--r--target/linux/brcm2708/patches-4.4/0318-Revert-bcm2835-implement-channel-map-API.patch496
-rw-r--r--target/linux/brcm2708/patches-4.4/0319-Revert-bcm2835-extend-allowed-range-of-channels-and-.patch37
-rw-r--r--target/linux/brcm2708/patches-4.4/0320-videobuf2-v4l2-Verify-planes-array-in-buffer-dequeue.patch53
-rw-r--r--target/linux/brcm2708/patches-4.4/0321-pinctrl-bcm2835-Return-pins-to-inputs-when-freed.patch40
-rw-r--r--target/linux/brcm2708/patches-4.4/0322-BCM270X_DT-i2c0-bcm2708-pin-group-params.patch99
-rw-r--r--target/linux/brcm2708/patches-4.4/0323-config-Add-CONFIG_DRM_LOAD_EDID_FIRMWARE.patch30
-rw-r--r--target/linux/brcm2708/patches-4.4/0324-Revert-rpi-update-vc_vchi_audioserv_defs.h.patch63
-rw-r--r--target/linux/brcm2708/patches-4.4/0325-Revert-config-Add-CONFIG_DRM_LOAD_EDID_FIRMWARE.patch31
-rw-r--r--target/linux/brcm2708/patches-4.4/0326-ARM-adau1977-adc-Add-basic-machine-driver-for-adau19.patch285
-rw-r--r--target/linux/brcm2708/patches-4.4/0327-Allow-up-to-24dB-digital-gain-to-be-applied-when-usi.patch60
-rw-r--r--target/linux/brcm2708/patches-4.4/0328-config-Add-CONFIG_DRM_LOAD_EDID_FIRMWARE.patch30
-rw-r--r--target/linux/brcm2708/patches-4.4/0329-BCM270X_DT-Move-vc4-node-contents-to-bcm2708_common..patch325
-rw-r--r--target/linux/brcm2708/patches-4.4/0330-BCM270X_DT-Set-correct-HDMI-HPD-GPIO-levels-for-vari.patch69
-rw-r--r--target/linux/brcm2708/patches-4.4/0331-Revert-drm-vc4-Force-HDMI-to-connected.patch26
-rw-r--r--target/linux/brcm2708/patches-4.4/0332-BCM270X-Include-DRM_PANEL_SIMPLE-in-the-defconfigs.patch33
-rw-r--r--target/linux/brcm2708/patches-4.4/0333-drm-Add-an-encoder-and-connector-type-enum-for-DPI.patch64
-rw-r--r--target/linux/brcm2708/patches-4.4/0334-dt-bindings-Add-binding-docs-for-V3D.patch42
-rw-r--r--target/linux/brcm2708/patches-4.4/0335-drm-vc4-Add-DPI-driver.patch673
-rw-r--r--target/linux/brcm2708/patches-4.4/0336-drm-vc4-Fix-NULL-deref-in-HDMI-init-error-path.patch25
-rw-r--r--target/linux/brcm2708/patches-4.4/0337-drm-vc4-Kick-out-the-simplefb-framebuffer-before-we-.patch53
-rw-r--r--target/linux/brcm2708/patches-4.4/0338-drm-vc4-Rename-async-to-nonblock.patch45
-rw-r--r--target/linux/brcm2708/patches-4.4/0339-drm-vc4-Add-support-for-gamma-ramps.patch137
-rw-r--r--target/linux/brcm2708/patches-4.4/0340-drm-vc4-Add-missing-render-node-support.patch26
-rw-r--r--target/linux/brcm2708/patches-4.4/0341-drm-panel-simple-Add-the-7-DPI-panel-from-Adafruit.patch86
-rw-r--r--target/linux/brcm2708/patches-4.4/0342-BCM270X_DT-Add-the-disabled-by-default-DPI-device-no.patch34
-rw-r--r--target/linux/brcm2708/patches-4.4/0343-drm-vc4-Fix-get_vblank_counter-with-proper-no-op-for.patch31
-rw-r--r--target/linux/brcm2708/patches-4.4/0344-drm-vc4-Fix-drm_vblank_put-get-imbalance-in-page-fli.patch48
-rw-r--r--target/linux/brcm2708/patches-4.4/0345-BCM270X_DT-Add-umbrella-I2C-Mux-overlay-i2c-mux.patch269
-rw-r--r--target/linux/brcm2708/patches-4.4/0346-BCM270X_DT-Include-address-override-for-pca9542.patch24
-rw-r--r--target/linux/brcm2708/patches-4.4/0347-BCM270X_DT-Fix-the-tinylcd35-overlay-RTC-support.patch68
-rw-r--r--target/linux/brcm2708/patches-4.4/0348-clk-Allow-clocks-to-be-marked-as-CRITICAL.patch43
-rw-r--r--target/linux/brcm2708/patches-4.4/0349-clk-bcm2835-Mark-the-VPU-clock-as-critical.patch46
-rw-r--r--target/linux/brcm2708/patches-4.4/0350-clk-bcm2835-Mark-GPIO-clocks-enabled-at-boot-as-crit.patch55
-rw-r--r--target/linux/brcm2708/patches-4.4/0351-clk-bcm2835-Skip-PLLC-clocks-when-deciding-on-a-new-.patch71
-rw-r--r--target/linux/brcm2708/patches-4.4/0352-mmc-Add-MMC_QUIRK_ERASE_BROKEN-for-some-cards.patch56
-rw-r--r--target/linux/brcm2708/patches-4.4/0353-New-AudioInjector.net-Pi-soundcard-with-low-jitter-a.patch284
-rw-r--r--target/linux/brcm2708/patches-4.4/0354-mmc-Apply-QUIRK_BROKEN_ERASE-to-other-capacities.patch23
-rw-r--r--target/linux/brcm2708/patches-4.4/0356-mmc-Add-card_quirks-module-parameter-log-quirks.patch76
-rw-r--r--target/linux/brcm2708/patches-4.4/0357-rtc-ds1307-ensure-that-any-pending-alarm-is-cleared-.patch58
-rw-r--r--target/linux/brcm2708/patches-4.4/0358-Revert-Revert-drm-vc4-Force-HDMI-to-connected.patch27
-rw-r--r--target/linux/brcm2708/patches-4.4/0359-config-Add-NF_MATCH_RPFILTER.patch46
-rw-r--r--target/linux/brcm2708/patches-4.4/0360-Added-Overlay-for-Microchip-MCP23017-I2C-gpio-expand.patch87
-rw-r--r--target/linux/brcm2708/patches-4.4/0361-bcm2835-camera-Fix-max-min-error-when-looping-over-c.patch24
-rw-r--r--target/linux/brcm2708/patches-4.4/0362-Change-BoomBerry-name-to-JustBoom-in-all-locations-d.patch1139
-rw-r--r--target/linux/brcm2708/patches-4.4/0363-Add-dt-param-to-force-HiFiBerry-DAC-Pro-into-slave-m.patch83
-rw-r--r--target/linux/brcm2708/patches-4.4/0364-simple-add-sound-dai-cells-to-I2S-def.patch33
-rw-r--r--target/linux/brcm2708/patches-4.4/0365-BCM2835-V4L2-Increase-minimum-resolution-to-32x32.patch31
-rw-r--r--target/linux/brcm2708/patches-4.4/0366-config-Add-support-for-Logitech-Rumblepad.patch36
-rw-r--r--target/linux/brcm2708/patches-4.4/0367-New-driver-for-RRA-DigiDAC1-soundcard-using-WM8741-W.patch603
-rw-r--r--target/linux/brcm2708/patches-4.4/0368-BCM2835-V4L2-Correct-handling-for-BGR24-vs-RGB24.patch170
-rw-r--r--target/linux/brcm2708/patches-4.4/0369-BCM270X_DT-Add-mcp23017-to-the-overlay-Makefile.patch20
-rw-r--r--target/linux/brcm2708/patches-4.4/0370-BCM270X_DT-Sort-entries-to-placate-check-script.patch56
-rw-r--r--target/linux/brcm2708/patches-4.4/0371-gpio-ir-overlay-gpio_pin-shouldn-t-change-pull-setti.patch23
-rw-r--r--target/linux/brcm2708/patches-4.4/0372-media-rc-core-define-a-default-timeout-for-drivers.patch25
-rw-r--r--target/linux/brcm2708/patches-4.4/0373-media-rc-gpio-ir-recv-add-timeout-on-idle.patch91
-rw-r--r--target/linux/brcm2708/patches-4.4/0374-smsir.h-remove-a-now-duplicated-definition-IR_DEFAUL.patch24
-rw-r--r--target/linux/brcm2708/patches-4.4/0375-Implement-a-wakeup-source-option-for-the-i2c-rtc-Dev.patch36
-rw-r--r--target/linux/brcm2708/patches-4.4/0376-BCM270X_DT-Fix-rpi-dac-overlay.patch34
-rw-r--r--target/linux/brcm2708/patches-4.4/0377-BCM270X_DT-Make-i2c-gpio-usable-by-other-overlays.patch37
-rw-r--r--target/linux/brcm2708/patches-4.4/0381-Add-ads1015-overlay.patch155
-rw-r--r--target/linux/brcm2708/patches-4.4/1001-smsc95xx-disable-hw-csum.patch11
-rw-r--r--target/linux/cns3xxx/patches-4.4/033-CNS3xxx-Fix-PCI-cns3xxx_write_config.patch19
-rw-r--r--target/linux/cns3xxx/patches-4.4/075-spi_support.patch2
-rw-r--r--target/linux/cns3xxx/patches-4.4/130-Extend-PCIE_BUS_PEER2PEER-to-set-MRSS-128-to-fix-CNS3xxx-BM-DMA..patch4
-rw-r--r--target/linux/generic/config-4.48
-rw-r--r--target/linux/generic/files/include/linux/ath9k_platform.h4
-rw-r--r--target/linux/generic/patches-3.18/660-fq_codel_defaults.patch6
-rw-r--r--target/linux/generic/patches-4.1/660-fq_codel_defaults.patch6
-rw-r--r--target/linux/generic/patches-4.4/032-fq_codel-add-batch-ability-to-fq_codel_drop.patch189
-rw-r--r--target/linux/generic/patches-4.4/045-mtd-devices-m25p80-add-support-for-mmap-read-request.patch2
-rw-r--r--target/linux/generic/patches-4.4/081-spi-bcm53xx-add-spi_flash_read-callback-for-MMIO-bas.patch12
-rw-r--r--target/linux/generic/patches-4.4/101-MIPS-fix-cache-flushing-for-highmem-pages.patch78
-rw-r--r--target/linux/generic/patches-4.4/206-mips-disable-vdso.patch2
-rw-r--r--target/linux/generic/patches-4.4/207-mips-vdso-dbg-rebuild-after-genvdso.patch27
-rw-r--r--target/linux/generic/patches-4.4/271-uapi-libc-compat.h-do-not-rely-on-__GLIBC__.patch27
-rw-r--r--target/linux/generic/patches-4.4/272-uapi-if_ether.h-prevent-redefinition-of-struct-ethhd.patch12
-rw-r--r--target/linux/generic/patches-4.4/465-m25p80-mx-disable-software-protection.patch14
-rw-r--r--target/linux/generic/patches-4.4/494-mtd-ubi-add-EOF-marker-support.patch2
-rw-r--r--target/linux/generic/patches-4.4/506-yaffs2-using-new-follow_link-and-put_link.patch47
-rw-r--r--target/linux/generic/patches-4.4/630-packet_socket_type.patch10
-rw-r--r--target/linux/generic/patches-4.4/642-bridge_port_isolate.patch6
-rw-r--r--target/linux/generic/patches-4.4/645-bridge_multicast_to_unicast.patch36
-rw-r--r--target/linux/generic/patches-4.4/655-increase_skb_pad.patch2
-rw-r--r--target/linux/generic/patches-4.4/656-skb_reduce_truesize-helper.patch41
-rw-r--r--target/linux/generic/patches-4.4/657-qdisc_reduce_truesize.patch63
-rw-r--r--target/linux/generic/patches-4.4/660-fq_codel_defaults.patch6
-rw-r--r--target/linux/generic/patches-4.4/661-fq_codel_keep_dropped_stats.patch2
-rw-r--r--target/linux/generic/patches-4.4/662-use_fq_codel_by_default.patch26
-rw-r--r--target/linux/generic/patches-4.4/663-remove_pfifo_fast.patch2
-rw-r--r--target/linux/generic/patches-4.4/664-codel_fix_3_12.patch22
-rw-r--r--target/linux/generic/patches-4.4/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch26
-rw-r--r--target/linux/generic/patches-4.4/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch18
-rw-r--r--target/linux/generic/patches-4.4/721-phy_packets.patch8
-rw-r--r--target/linux/generic/patches-4.4/903-debloat_direct_io.patch4
-rw-r--r--target/linux/generic/patches-4.4/997-device_tree_cmdline.patch24
-rw-r--r--target/linux/ixp4xx/Makefile2
-rw-r--r--target/linux/ixp4xx/config-4.4251
-rw-r--r--target/linux/ixp4xx/patches-4.4/001-arm-ixp4xx-set-cohorent_dma_mask-for-ethernet-platfo.patch136
-rw-r--r--target/linux/ixp4xx/patches-4.4/002-ixp4xx_eth-use-parent-device-for-dma-allocations.patch95
-rw-r--r--target/linux/ixp4xx/patches-4.4/020-gateworks_i2c_pld.patch424
-rw-r--r--target/linux/ixp4xx/patches-4.4/030-gpio_line_config.patch73
-rw-r--r--target/linux/ixp4xx/patches-4.4/090-increase_entropy_pools.patch17
-rw-r--r--target/linux/ixp4xx/patches-4.4/100-wg302v2_gateway7001_mac_plat_info.patch78
-rw-r--r--target/linux/ixp4xx/patches-4.4/105-wg302v1_support.patch261
-rw-r--r--target/linux/ixp4xx/patches-4.4/110-pronghorn_series_support.patch393
-rw-r--r--target/linux/ixp4xx/patches-4.4/111-pronghorn_swap_uarts.patch44
-rw-r--r--target/linux/ixp4xx/patches-4.4/115-sidewinder_support.patch286
-rw-r--r--target/linux/ixp4xx/patches-4.4/116-sidewinder_fis_location.patch30
-rw-r--r--target/linux/ixp4xx/patches-4.4/120-compex_support.patch199
-rw-r--r--target/linux/ixp4xx/patches-4.4/130-wrt300nv2_support.patch227
-rw-r--r--target/linux/ixp4xx/patches-4.4/131-wrt300nv2_mac_plat_info.patch42
-rw-r--r--target/linux/ixp4xx/patches-4.4/132-wrt300nv2_mac_fix.patch72
-rw-r--r--target/linux/ixp4xx/patches-4.4/150-lanready_ap1000_support.patch203
-rw-r--r--target/linux/ixp4xx/patches-4.4/151-lanready_ap1000_mac_plat_info.patch51
-rw-r--r--target/linux/ixp4xx/patches-4.4/160-delayed_uart_io.patch133
-rw-r--r--target/linux/ixp4xx/patches-4.4/162-wg302v1_mem_fixup.patch38
-rw-r--r--target/linux/ixp4xx/patches-4.4/170-ixdpg425_mac_plat_info.patch51
-rw-r--r--target/linux/ixp4xx/patches-4.4/175-avila_hss_audio_support.patch2093
-rw-r--r--target/linux/ixp4xx/patches-4.4/180-tw5334_support.patch287
-rw-r--r--target/linux/ixp4xx/patches-4.4/185-mi424wr_support.patch507
-rw-r--r--target/linux/ixp4xx/patches-4.4/190-cambria_support.patch1131
-rw-r--r--target/linux/ixp4xx/patches-4.4/201-npe_driver_print_license_location.patch11
-rw-r--r--target/linux/ixp4xx/patches-4.4/203-npe_driver_mask_phy_features.patch13
-rw-r--r--target/linux/ixp4xx/patches-4.4/205-npe_driver_separate_phy_functions.patch131
-rw-r--r--target/linux/ixp4xx/patches-4.4/206-npe_driver_add_update_link_function.patch98
-rw-r--r--target/linux/ixp4xx/patches-4.4/207-npe_driver_multiphy_support.patch145
-rw-r--r--target/linux/ixp4xx/patches-4.4/295-latch_led_driver.patch201
-rw-r--r--target/linux/ixp4xx/patches-4.4/300-avila_support.patch726
-rw-r--r--target/linux/ixp4xx/patches-4.4/304-ixp4xx_eth_jumboframe.patch80
-rw-r--r--target/linux/ixp4xx/patches-4.4/310-gtwx5717_spi_bus.patch52
-rw-r--r--target/linux/ixp4xx/patches-4.4/311-gtwx5717_mac_plat_info.patch50
-rw-r--r--target/linux/ixp4xx/patches-4.4/312-ixp4xx_pata_optimization.patch137
-rw-r--r--target/linux/ixp4xx/patches-4.4/500-usr8200_support.patch347
-rw-r--r--target/linux/ixp4xx/patches-4.4/520-tw2662_support.patch317
-rw-r--r--target/linux/ixp4xx/patches-4.4/530-ap42x_support.patch282
-rw-r--r--target/linux/ixp4xx/patches-4.4/600-skb_avoid_dmabounce.patch23
-rw-r--r--target/linux/ixp4xx/patches-4.4/900-ixp4xx-crypto-include-module.h.patch10
-rw-r--r--target/linux/ixp4xx/patches-4.4/910-ixp4xx-nr_irq_lines.patch22
-rw-r--r--target/linux/lantiq/dts/DGN3500.dtsi2
-rw-r--r--target/linux/lantiq/patches-4.4/0001-MIPS-lantiq-add-pcie-driver.patch2
-rw-r--r--target/linux/lantiq/patches-4.4/0022-MTD-m25p80-allow-loading-mtd-name-from-OF.patch4
-rw-r--r--target/linux/mediatek/Makefile4
-rwxr-xr-xtarget/linux/mediatek/base-files/etc/board.d/02_network2
-rw-r--r--target/linux/mediatek/config-4.49
-rw-r--r--target/linux/mediatek/files/arch/arm/boot/dts/_mt7623.dtsi615
-rw-r--r--target/linux/mediatek/files/arch/arm/boot/dts/mt7623-NAND.dts28
-rw-r--r--target/linux/mediatek/files/arch/arm/boot/dts/mt7623-eMMC.dts19
-rw-r--r--target/linux/mediatek/image/Makefile11
-rw-r--r--target/linux/mediatek/patches-4.4/0001-NET-multi-phy-support.patch17
-rw-r--r--target/linux/mediatek/patches-4.4/0002-soc-mediatek-Separate-scpsys-driver-common-code.patch34
-rw-r--r--target/linux/mediatek/patches-4.4/0003-soc-mediatek-Init-MT8173-scpsys-driver-earlier.patch11
-rw-r--r--target/linux/mediatek/patches-4.4/0004-soc-mediatek-Add-MT2701-power-dt-bindings.patch10
-rw-r--r--target/linux/mediatek/patches-4.4/0005-soc-mediatek-Add-MT2701-MT7623-scpsys-driver.patch16
-rw-r--r--target/linux/mediatek/patches-4.4/0006-clk-mediatek-Refine-the-makefile-to-support-multiple.patch16
-rw-r--r--target/linux/mediatek/patches-4.4/0007-dt-bindings-ARM-Mediatek-Document-bindings-for-MT270.patch40
-rw-r--r--target/linux/mediatek/patches-4.4/0008-clk-mediatek-Add-dt-bindings-for-MT2701-clocks.patch10
-rw-r--r--target/linux/mediatek/patches-4.4/0009-clk-mediatek-Add-MT2701-clock-support.patch32
-rw-r--r--target/linux/mediatek/patches-4.4/0010-reset-mediatek-mt2701-reset-controller-dt-binding-fi.patch10
-rw-r--r--target/linux/mediatek/patches-4.4/0011-reset-mediatek-mt2701-reset-driver.patch13
-rw-r--r--target/linux/mediatek/patches-4.4/0012-ARM-mediatek-Add-MT2701-config-options-for-mediatek-.patch11
-rw-r--r--target/linux/mediatek/patches-4.4/0013-dt-bindings-mediatek-Modify-pinctrl-bindings-for-mt2.patch11
-rw-r--r--target/linux/mediatek/patches-4.4/0014-pinctrl-dt-bindings-Add-pinfunc-header-file-for-mt27.patch34
-rw-r--r--target/linux/mediatek/patches-4.4/0015-dt-bindings-mediatek-Modify-pinctrl-bindings-for-mt7.patch12
-rw-r--r--target/linux/mediatek/patches-4.4/0016-pinctrl-dt-bindings-Add-pinctrl-file-for-mt7623.patch21
-rw-r--r--target/linux/mediatek/patches-4.4/0017-clk-add-hifsys-reset.patch13
-rw-r--r--target/linux/mediatek/patches-4.4/0018-dt-bindings-Add-a-binding-for-Mediatek-xHCI-host-con.patch10
-rw-r--r--target/linux/mediatek/patches-4.4/0019-xhci-mediatek-support-MTK-xHCI-host-controller.patch38
-rw-r--r--target/linux/mediatek/patches-4.4/0020-arm64-dts-mediatek-add-xHCI-usb-phy-for-mt8173.patch11
-rw-r--r--target/linux/mediatek/patches-4.4/0021-Document-DT-Add-bindings-for-mediatek-MT7623-SoC-Pla.patch13
-rw-r--r--target/linux/mediatek/patches-4.4/0022-soc-mediatek-add-compat-string-for-mt7623-to-scpsys.patch12
-rw-r--r--target/linux/mediatek/patches-4.4/0023-ARM-dts-mediatek-add-MT7623-basic-support.patch218
-rw-r--r--target/linux/mediatek/patches-4.4/0024-dt-bindings-add-MediaTek-PCIe-binding-documentation.patch10
-rw-r--r--target/linux/mediatek/patches-4.4/0025-PCI-mediatek-add-support-for-PCIe-found-on-MT7623-MT.patch20
-rw-r--r--target/linux/mediatek/patches-4.4/0026-scpsys-various-fixes.patch17
-rw-r--r--target/linux/mediatek/patches-4.4/0027-soc-mediatek-PMIC-wrap-Clear-the-vldclr-if-state-mac.patch15
-rw-r--r--target/linux/mediatek/patches-4.4/0028-ARM-mediatek-add-MT7623-smp-bringup-code.patch13
-rw-r--r--target/linux/mediatek/patches-4.4/0029-soc-mediatek-PMIC-wrap-clear-the-STAUPD_TRIG-bit-of-.patch15
-rw-r--r--target/linux/mediatek/patches-4.4/0030-ARM-mediatek-add-mt2701-smp-bringup-code.patch11
-rw-r--r--target/linux/mediatek/patches-4.4/0031-dt-bindings-ARM-Mediatek-add-MT2701-7623-string-to-t.patch11
-rw-r--r--target/linux/mediatek/patches-4.4/0032-soc-mediatek-PMIC-wrap-don-t-duplicate-the-wrapper-d.patch19
-rw-r--r--target/linux/mediatek/patches-4.4/0033-soc-mediatek-PMIC-wrap-add-wrapper-callbacks-for-ini.patch15
-rw-r--r--target/linux/mediatek/patches-4.4/0034-soc-mediatek-PMIC-wrap-split-SoC-specific-init-into-.patch19
-rw-r--r--target/linux/mediatek/patches-4.4/0035-soc-mediatek-PMIC-wrap-WRAP_INT_EN-needs-a-different.patch15
-rw-r--r--target/linux/mediatek/patches-4.4/0036-soc-mediatek-PMIC-wrap-SPI_WRITE-needs-a-different-b.patch17
-rw-r--r--target/linux/mediatek/patches-4.4/0037-soc-mediatek-PMIC-wrap-move-wdt_src-into-the-pmic_wr.patch17
-rw-r--r--target/linux/mediatek/patches-4.4/0038-soc-mediatek-PMIC-wrap-remove-pwrap_is_mt8135-and-pw.patch25
-rw-r--r--target/linux/mediatek/patches-4.4/0039-soc-mediatek-PMIC-wrap-add-a-slave-specific-struct.patch36
-rw-r--r--target/linux/mediatek/patches-4.4/0040-soc-mediatek-PMIC-wrap-add-mt6323-slave-support.patch15
-rw-r--r--target/linux/mediatek/patches-4.4/0041-soc-mediatek-PMIC-wrap-add-MT2701-7623-support.patch19
-rw-r--r--target/linux/mediatek/patches-4.4/0042-dt-bindings-mfd-Add-bindings-for-the-MediaTek-MT6323.patch13
-rw-r--r--target/linux/mediatek/patches-4.4/0043-mfd-mt6397-int_con-and-int_status-may-vary-in-locati.patch23
-rw-r--r--target/linux/mediatek/patches-4.4/0044-mfd-mt6397-add-support-for-different-Slave-types.patch11
-rw-r--r--target/linux/mediatek/patches-4.4/0045-mfd-mt6397-add-MT6323-support-to-MT6397-driver.patch21
-rw-r--r--target/linux/mediatek/patches-4.4/0046-regulator-Add-document-for-MT6323-regulator.patch10
-rw-r--r--target/linux/mediatek/patches-4.4/0047-regulator-mt6323-Add-support-for-MT6323-regulator.patch21
-rw-r--r--target/linux/mediatek/patches-4.4/0048-net-next-mediatek-document-MediaTek-SoC-ethernet-bin.patch10
-rw-r--r--target/linux/mediatek/patches-4.4/0049-net-next-mediatek-add-support-for-MT7623-ethernet.patch13
-rw-r--r--target/linux/mediatek/patches-4.4/0050-net-next-mediatek-add-Kconfig-and-Makefile.patch17
-rw-r--r--target/linux/mediatek/patches-4.4/0051-net-next-mediatek-add-an-entry-to-MAINTAINERS.patch11
-rw-r--r--target/linux/mediatek/patches-4.4/0052-clk-dont-disable-unused-clocks.patch21
-rw-r--r--target/linux/mediatek/patches-4.4/0052-mtd-nand-add-an-mtd_to_nand-helper.patch35
-rw-r--r--target/linux/mediatek/patches-4.4/0053-clk-mediatek-enable-critical-clocks.patch69
-rw-r--r--target/linux/mediatek/patches-4.4/0053-mtd-nand-add-nand_to_mtd-helper.patch32
-rw-r--r--target/linux/mediatek/patches-4.4/0054-clk-mediatek-Export-CPU-mux-clocks-for-CPU-frequency.patch287
-rw-r--r--target/linux/mediatek/patches-4.4/0054-mtd-nand-add-helpers-to-access-priv.patch39
-rw-r--r--target/linux/mediatek/patches-4.4/0055-cpufreq-mediatek-add-driver.patch433
-rw-r--r--target/linux/mediatek/patches-4.4/0055-mtd-nand-embed-an-mtd_info-structure-into-nand_chip.patch42
-rw-r--r--target/linux/mediatek/patches-4.4/0056-arm-mediatek-make-a7-timer-work-Signed-off-by-John-C.patch31
-rw-r--r--target/linux/mediatek/patches-4.4/0056-mtd-add-get-set-of_node-flash_node-helpers.patch87
-rw-r--r--target/linux/mediatek/patches-4.4/0057-mtd-mediatek-device-tree-docs-for-MTK-Smart-Device-G.patch64
-rw-r--r--target/linux/mediatek/patches-4.4/0057-net-mediatek-checking-for-IS_ERR-instead-of-NULL.patch27
-rw-r--r--target/linux/mediatek/patches-4.4/0058-mtd-mediatek-driver-for-MTK-Smart-Device-Gen1-NAND.patch1798
-rw-r--r--target/linux/mediatek/patches-4.4/0058-net-mediatek-unlock-on-error-in-mtk_tx_map.patch24
-rw-r--r--target/linux/mediatek/patches-4.4/0059-mtd-nand-backport-fixes.patch46
-rw-r--r--target/linux/mediatek/patches-4.4/0059-net-mediatek-use-dma_addr_t-correctly.patch30
-rw-r--r--target/linux/mediatek/patches-4.4/0060-clk-dont-disable-unused-clocks.patch26
-rw-r--r--target/linux/mediatek/patches-4.4/0060-net-mediatek-remove-incorrect-dma_mask-assignment.patch31
-rw-r--r--target/linux/mediatek/patches-4.4/0061-clk-mediatek-enable-critical-clocks.patch74
-rw-r--r--target/linux/mediatek/patches-4.4/0061-net-mediatek-check-device_reset-return-code.patch33
-rw-r--r--target/linux/mediatek/patches-4.4/0062-clk-mediatek-Export-CPU-mux-clocks-for-CPU-frequency.patch306
-rw-r--r--target/linux/mediatek/patches-4.4/0062-net-mediatek-watchdog_timeo-was-not-set.patch23
-rw-r--r--target/linux/mediatek/patches-4.4/0063-cpufreq-mediatek-add-driver.patch443
-rw-r--r--target/linux/mediatek/patches-4.4/0063-net-mediatek-mtk_cal_txd_req-returns-bad-value.patch25
-rw-r--r--target/linux/mediatek/patches-4.4/0064-arm-mediatek-make-a7-timer-work.patch38
-rw-r--r--target/linux/mediatek/patches-4.4/0064-net-mediatek-remove-superflous-reset-call.patch26
-rw-r--r--target/linux/mediatek/patches-4.4/0065-net-mediatek-checking-for-IS_ERR-instead-of-NULL.patch32
-rw-r--r--target/linux/mediatek/patches-4.4/0065-net-mediatek-fix-stop-and-wakeup-of-queue.patch84
-rw-r--r--target/linux/mediatek/patches-4.4/0066-net-mediatek-fix-mtk_pending_work.patch58
-rw-r--r--target/linux/mediatek/patches-4.4/0066-net-mediatek-unlock-on-error-in-mtk_tx_map.patch29
-rw-r--r--target/linux/mediatek/patches-4.4/0067-net-mediatek-fix-TX-locking.patch93
-rw-r--r--target/linux/mediatek/patches-4.4/0067-net-mediatek-use-dma_addr_t-correctly.patch35
-rw-r--r--target/linux/mediatek/patches-4.4/0068-net-mediatek-move-the-pending_work-struct-to-the-dev.patch102
-rw-r--r--target/linux/mediatek/patches-4.4/0068-net-mediatek-remove-incorrect-dma_mask-assignment.patch36
-rw-r--r--target/linux/mediatek/patches-4.4/0069-net-mediatek-check-device_reset-return-code.patch38
-rw-r--r--target/linux/mediatek/patches-4.4/0069-net-mediatek-do-not-set-the-QID-field-in-the-TX-DMA-.patch32
-rw-r--r--target/linux/mediatek/patches-4.4/0070-net-mediatek-update-the-IRQ-part-of-the-binding-docu.patch41
-rw-r--r--target/linux/mediatek/patches-4.4/0070-net-mediatek-watchdog_timeo-was-not-set.patch28
-rw-r--r--target/linux/mediatek/patches-4.4/0071-net-mediatek-mtk_cal_txd_req-returns-bad-value.patch30
-rw-r--r--target/linux/mediatek/patches-4.4/0071-pwm-add-pwm-mediatek.patch337
-rw-r--r--target/linux/mediatek/patches-4.4/0072-mtd-backport-v4.7-0day-patches-from-Boris.patch5489
-rw-r--r--target/linux/mediatek/patches-4.4/0072-net-mediatek-remove-superflous-reset-call.patch31
-rw-r--r--target/linux/mediatek/patches-4.4/0073-net-mediatek-fix-stop-and-wakeup-of-queue.patch89
-rw-r--r--target/linux/mediatek/patches-4.4/0073-of-mtd-prepare-helper-reading-NAND-ECC-algo-from-DT.patch91
-rw-r--r--target/linux/mediatek/patches-4.4/0074-mtd-mediatek-device-tree-docs-for-MTK-Smart-Device-G.patch179
-rw-r--r--target/linux/mediatek/patches-4.4/0074-net-mediatek-fix-mtk_pending_work.patch63
-rw-r--r--target/linux/mediatek/patches-4.4/0075-mtd-mediatek-driver-for-MTK-Smart-Device-Gen1-NAND.patch2064
-rw-r--r--target/linux/mediatek/patches-4.4/0075-net-mediatek-fix-TX-locking.patch98
-rw-r--r--target/linux/mediatek/patches-4.4/0076-mtd-nand-add-power-domains-to-the-mediatek-driver.patch67
-rw-r--r--target/linux/mediatek/patches-4.4/0076-net-mediatek-move-the-pending_work-struct-to-the-dev.patch109
-rw-r--r--target/linux/mediatek/patches-4.4/0077-net-mediatek-do-not-set-the-QID-field-in-the-TX-DMA-.patch37
-rw-r--r--target/linux/mediatek/patches-4.4/0077-net-next-mediatek-use-mdiobus_free-in-favour-of-kfre.patch36
-rw-r--r--target/linux/mediatek/patches-4.4/0078-net-mediatek-update-the-IRQ-part-of-the-binding-docu.patch46
-rw-r--r--target/linux/mediatek/patches-4.4/0078-net-next-mediatek-fix-gigabit-and-flow-control-adver.patch71
-rw-r--r--target/linux/mediatek/patches-4.4/0079-net-next-mediatek-add-fixed-phy-support.patch38
-rw-r--r--target/linux/mediatek/patches-4.4/0079-net-next-mediatek-fix-BQL-support.patch89
-rw-r--r--target/linux/mediatek/patches-4.4/0080-net-next-mediatek-fix-gigabit-and-flow-control-adver.patch59
-rw-r--r--target/linux/mediatek/patches-4.4/0080-net-next-mediatek-properly-handle-RGMII-modes.patch31
-rw-r--r--target/linux/mediatek/patches-4.4/0081-net-next-mediatek-add-fixed-phy-support.patch32
-rw-r--r--target/linux/mediatek/patches-4.4/0081-net-next-mediatek-fix-DQL-support.patch92
-rw-r--r--target/linux/mediatek/patches-4.4/0082-net-next-mediatek-add-RX-delay-support.patch29
-rw-r--r--target/linux/mediatek/patches-4.4/0082-net-next-mediatek-add-missing-return-code-check.patch26
-rw-r--r--target/linux/mediatek/patches-4.4/0083-net-next-mediatek-add-missing-return-code-check.patch30
-rw-r--r--target/linux/mediatek/patches-4.4/0083-net-next-mediatek-fix-missing-free-of-scratch-memory.patch92
-rw-r--r--target/linux/mediatek/patches-4.4/0084-net-next-mediatek-fix-missing-free-of-scratch-memory.patch96
-rw-r--r--target/linux/mediatek/patches-4.4/0084-net-next-mediatek-invalid-buffer-lookup-in-mtk_tx_ma.patch27
-rw-r--r--target/linux/mediatek/patches-4.4/0085-net-next-mediatek-dropped-rx-packets-are-not-being-c.patch34
-rw-r--r--target/linux/mediatek/patches-4.4/0085-net-next-mediatek-invalid-buffer-lookup-in-mtk_tx_ma.patch30
-rw-r--r--target/linux/mediatek/patches-4.4/0086-net-next-mediatek-add-next-data-pointer-coherency-pr.patch39
-rw-r--r--target/linux/mediatek/patches-4.4/0086-net-next-mediatek-dropped-rx-packets-are-not-being-c.patch38
-rw-r--r--target/linux/mediatek/patches-4.4/0087-net-next-mediatek-add-IRQ-locking.patch74
-rw-r--r--target/linux/mediatek/patches-4.4/0087-net-next-mediatek-disable-all-interrupts-during-prob.patch26
-rw-r--r--target/linux/mediatek/patches-4.4/0088-net-next-mediatek-add-support-for-IRQ-grouping.patch401
-rw-r--r--target/linux/mediatek/patches-4.4/0088-net-next-mediatek-fix-threshold-value.patch30
-rw-r--r--target/linux/mediatek/patches-4.4/0089-net-mediatek-add-gsw-mt7530-driver.patch2380
-rw-r--r--target/linux/mediatek/patches-4.4/0089-net-next-mediatek-increase-watchdog_timeo.patch26
-rw-r--r--target/linux/mediatek/patches-4.4/0090-net-mediatek-v4.4-backports.patch77
-rw-r--r--target/linux/mediatek/patches-4.4/0090-net-next-mediatek-fix-off-by-one-in-the-TX-ring-allo.patch36
-rw-r--r--target/linux/mediatek/patches-4.4/0091-net-next-mediatek-WIP.patch249
-rw-r--r--target/linux/mediatek/patches-4.4/0091-net-next-mediatek-only-wake-the-queue-if-it-is-stopp.patch48
-rw-r--r--target/linux/mediatek/patches-4.4/0092-net-next-mediatek-remove-superfluous-queue-wake-up-c.patch36
-rw-r--r--target/linux/mediatek/patches-4.4/0093-net-next-mediatek-remove-superfluous-register-reads.patch37
-rw-r--r--target/linux/mediatek/patches-4.4/0094-net-next-mediatek-don-t-use-intermediate-variables-t.patch82
-rw-r--r--target/linux/mediatek/patches-4.4/0095-net-next-mediatek-add-IRQ-locking.patch64
-rw-r--r--target/linux/mediatek/patches-4.4/0096-net-next-mediatek-add-support-for-IRQ-grouping.patch361
-rw-r--r--target/linux/mediatek/patches-4.4/0098-net-next-mediatek-only-trigger-the-tx-watchdog-reset.patch57
-rw-r--r--target/linux/mediatek/patches-4.4/0101-net-mediatek-add-gsw-mt7530-driver.patch2360
-rw-r--r--target/linux/mediatek/patches-4.4/0102-net-mediatek-v4.4-backports.patch46
-rw-r--r--target/linux/mediatek/patches-4.4/0200-devicetree.patch2
-rw-r--r--target/linux/mediatek/patches-4.4/0201-block2mtd.patch (renamed from target/linux/mediatek/patches-4.4/0100-block2mtd.patch)0
-rw-r--r--target/linux/mvebu/patches-4.4/001-fix_gpio_config_on_linksys_boards.patch58
-rw-r--r--target/linux/oxnas/patches-4.4/320-oxnas-irqchip.patch2
-rw-r--r--target/linux/ramips/patches-4.4/0010-MIPS-ralink-Add-a-few-missing-clocks.patch48
-rw-r--r--target/linux/ramips/patches-4.4/0010-arch-mips-ralink-add-spi1-clocks.patch44
-rw-r--r--target/linux/ramips/patches-4.4/0013-owrt-hack-fix-mt7688-cache-issue.patch2
-rw-r--r--target/linux/ramips/patches-4.4/0022-MIPS-ralink-Fix-vendor-string-for-mt7620.patch27
-rw-r--r--target/linux/ramips/patches-4.4/0022-arch-mips-ralink-proper-vendor-id-srtring.patch21
-rw-r--r--target/linux/ramips/patches-4.4/0033-xhci-mediatek-support-MTK-xHCI-host-controller.patch8
-rw-r--r--target/linux/ramips/patches-4.4/0049-watchdog-add-MT7621-support.patch2
-rw-r--r--target/linux/ramips/patches-4.4/0054-mtd-add-chunked-read-io-to-m25p80.patch6
-rw-r--r--target/linux/ramips/patches-4.4/0065-MIPS-ralink-MT7688-pinmux-fixes.patch166
-rw-r--r--target/linux/ramips/patches-4.4/0065-mt7688-fixes.patch73
-rw-r--r--target/linux/ramips/patches-4.4/0080-MIPS-ralink-fix-USB-frequency-scaling.patch9
-rw-r--r--target/linux/ramips/patches-4.4/0081-MIPS-ralink-Fix-invalid-assignment-of-SoC-type.patch25
-rw-r--r--target/linux/socfpga/config-4.42
-rw-r--r--target/linux/socfpga/patches-4.4/0001-dt-bindings-gpio-altera-Fix-altr-interrupt-type-prop.patch6
-rw-r--r--target/linux/socfpga/patches-4.4/0002-usb-dwc2-gadget-Repair-DSTS-register-decoding.patch6
-rw-r--r--target/linux/socfpga/patches-4.4/0003-ARM-socfpga-dts-Enable-MMC-support-at-correct-place-.patch8
-rw-r--r--target/linux/socfpga/patches-4.4/0004-ARM-socfpga-Add-support-for-HPS-LEDs-on-SoCKit.patch6
-rw-r--r--target/linux/socfpga/patches-4.4/0005-ARM-socfpga-Add-support-for-HPS-KEYs-SWs-on-SoCKit.patch6
-rw-r--r--target/linux/socfpga/patches-4.4/0006-mtd-add-get-set-of_node-flash_node-helpers.patch87
-rw-r--r--target/linux/socfpga/patches-4.4/0007-mtd-nand-spi-nor-assign-MTD-of_node.patch44
-rw-r--r--target/linux/socfpga/patches-4.4/0008-mtd-spi-nor-convert-to-spi_nor_-get-set-_flash_node.patch91
-rw-r--r--target/linux/socfpga/patches-4.4/0009-mtd-spi-nor-drop-flash_node-field.patch64
-rw-r--r--target/linux/socfpga/patches-4.4/0010-mtd-spi-nor-remove-unnecessary-leading-space-from-db.patch32
-rw-r--r--target/linux/socfpga/patches-4.4/0011-mtd-spi-nor-provide-default-erase_sector-implementat.patch112
-rw-r--r--target/linux/socfpga/patches-4.4/0012-mtd-spi-nor-mx25l3205d-mx25l6405d-append-SECT_4K.patch32
-rw-r--r--target/linux/socfpga/patches-4.4/0013-mtd-spi-nor-Fix-error-message-with-unrecognized-JEDE.patch35
-rw-r--r--target/linux/socfpga/patches-4.4/0014-mtd-spi-nor-fix-error-handling-in-spi_nor_erase.patch44
-rw-r--r--target/linux/socfpga/patches-4.4/0015-mtd-spi-nor-Check-the-return-value-from-read_sr.patch60
-rw-r--r--target/linux/socfpga/patches-4.4/0016-mtd-spi-nor-remove-micron_quad_enable.patch110
-rw-r--r--target/linux/socfpga/patches-4.4/0017-mtd-spi-nor-properly-detect-the-memory-when-it-boots.patch244
-rw-r--r--target/linux/socfpga/patches-4.4/0018-mtd-spi-nor-select-op-codes-and-SPI-NOR-protocols-by.patch203
-rw-r--r--target/linux/socfpga/patches-4.4/0019-mtd-spi-nor-fix-support-of-Macronix-memories.patch139
-rw-r--r--target/linux/socfpga/patches-4.4/0020-mtd-spi-nor-fix-support-of-Winbond-memories.patch179
-rw-r--r--target/linux/socfpga/patches-4.4/0021-mtd-spi-nor-fix-support-of-Micron-memories.patch224
-rw-r--r--target/linux/socfpga/patches-4.4/0022-mtd-spi-nor-fix-support-of-Spansion-memories.patch116
-rw-r--r--target/linux/socfpga/patches-4.4/0023-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch264
-rw-r--r--target/linux/socfpga/patches-4.4/0024-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch159
-rw-r--r--target/linux/socfpga/patches-4.4/0025-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch237
-rw-r--r--target/linux/socfpga/patches-4.4/0026-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch215
-rw-r--r--target/linux/socfpga/patches-4.4/0027-mtd-m25p80-add-support-of-dual-and-quad-spi-protocol.patch293
-rw-r--r--target/linux/socfpga/patches-4.4/0028-mtd-ofpart-grab-device-tree-node-directly-from-maste.patch81
-rw-r--r--target/linux/socfpga/patches-4.4/0029-Documentation-atmel-quadspi-add-binding-file-for-Atm.patch58
-rw-r--r--target/linux/socfpga/patches-4.4/0030-mtd-spi-nor-Bindings-for-Cadence-Quad-SPI-Flash-Cont.patch99
-rw-r--r--target/linux/socfpga/patches-4.4/0031-mtd-spi-nor-Add-driver-for-Cadence-Quad-SPI-Flash-Co.patch1431
-rw-r--r--target/linux/socfpga/patches-4.4/0032-ARM-socfpga-Add-Candence-QSPI-controller-DT-node.patch42
-rw-r--r--target/linux/socfpga/patches-4.4/0033-ARM-socfpga-Enable-QSPI-flash-on-SoCKit.patch47
-rw-r--r--toolchain/binutils/Config.in8
-rw-r--r--toolchain/binutils/Config.version4
-rw-r--r--toolchain/binutils/Makefile8
-rw-r--r--toolchain/binutils/patches/arc-2016.03/200-arc-fix-target-mask.patch13
-rw-r--r--toolchain/gcc/Config.version2
-rw-r--r--toolchain/gcc/common.mk8
-rw-r--r--toolchain/gcc/patches/arc-2016.03/001-revert_register_mode_search.patch (renamed from toolchain/gcc/patches/arc-2015.06/001-revert_register_mode_search.patch)0
-rw-r--r--toolchain/gcc/patches/arc-2016.03/002-weak_data_fix.patch (renamed from toolchain/gcc/patches/arc-2015.06/002-weak_data_fix.patch)0
-rw-r--r--toolchain/gcc/patches/arc-2016.03/003-universal_initializer.patch (renamed from toolchain/gcc/patches/arc-2015.06/003-universal_initializer.patch)0
-rw-r--r--toolchain/gcc/patches/arc-2016.03/004-case_insensitive.patch (renamed from toolchain/gcc/patches/arc-2015.06/004-case_insensitive.patch)0
-rw-r--r--toolchain/gcc/patches/arc-2016.03/010-documentation.patch (renamed from toolchain/gcc/patches/arc-2015.06/010-documentation.patch)0
-rw-r--r--toolchain/gcc/patches/arc-2016.03/020-no-plt-backport.patch (renamed from toolchain/gcc/patches/arc-2015.06/020-no-plt-backport.patch)0
-rw-r--r--toolchain/gcc/patches/arc-2016.03/100-uclibc-conf.patch (renamed from toolchain/gcc/patches/arc-2015.06/100-uclibc-conf.patch)0
-rw-r--r--toolchain/gcc/patches/arc-2016.03/210-disable_libsanitizer_off_t_check.patch (renamed from toolchain/gcc/patches/arc-2015.06/210-disable_libsanitizer_off_t_check.patch)0
-rw-r--r--toolchain/gcc/patches/arc-2016.03/800-arc-disablelibgmon.patch (renamed from toolchain/gcc/patches/arc-2015.06/800-arc-disablelibgmon.patch)0
-rw-r--r--toolchain/gcc/patches/arc-2016.03/820-libgcc_pic.patch (renamed from toolchain/gcc/patches/arc-2015.06/820-libgcc_pic.patch)0
-rw-r--r--toolchain/gcc/patches/arc-2016.03/850-use_shared_libgcc.patch (renamed from toolchain/gcc/patches/arc-2015.06/850-use_shared_libgcc.patch)0
-rw-r--r--toolchain/gcc/patches/arc-2016.03/851-libgcc_no_compat.patch (renamed from toolchain/gcc/patches/arc-2015.06/851-libgcc_no_compat.patch)0
-rw-r--r--toolchain/gcc/patches/arc-2016.03/860-use_eh_frame.patch (renamed from toolchain/gcc/patches/arc-2015.06/860-use_eh_frame.patch)0
-rw-r--r--toolchain/gcc/patches/arc-2016.03/870-ppc_no_crtsavres.patch (renamed from toolchain/gcc/patches/arc-2015.06/870-ppc_no_crtsavres.patch)0
-rw-r--r--toolchain/gcc/patches/arc-2016.03/880-no_java_section.patch (renamed from toolchain/gcc/patches/arc-2015.06/880-no_java_section.patch)0
-rw-r--r--toolchain/gcc/patches/arc-2016.03/910-mbsd_multi.patch (renamed from toolchain/gcc/patches/arc-2015.06/910-mbsd_multi.patch)0
-rw-r--r--toolchain/gcc/patches/arc-2016.03/920-specs_nonfatal_getenv.patch (renamed from toolchain/gcc/patches/arc-2015.06/920-specs_nonfatal_getenv.patch)0
-rw-r--r--toolchain/gcc/patches/arc-2016.03/940-no-clobber-stamp-bits.patch (renamed from toolchain/gcc/patches/arc-2015.06/940-no-clobber-stamp-bits.patch)0
-rw-r--r--toolchain/gdb/Makefile6
-rw-r--r--toolchain/gdb/patches/arc-2015.06-gdb/100-no_extern_inline.patch32
-rw-r--r--toolchain/gdb/patches/arc-2015.06-gdb/110-no_testsuite.patch21
-rw-r--r--toolchain/gdb/patches/arc-2015.06-gdb/120-fix-compile-flag-mismatch.patch11
-rw-r--r--toolchain/gdb/patches/arc-2016.03-gdb/100-no_extern_inline.patch32
-rw-r--r--toolchain/gdb/patches/arc-2016.03-gdb/110-no_testsuite.patch21
-rw-r--r--toolchain/gdb/patches/arc-2016.03-gdb/120-fix-compile-flag-mismatch.patch11
-rw-r--r--tools/cmake/Makefile4
1144 files changed, 150063 insertions, 108668 deletions
diff --git a/config/Config-build.in b/config/Config-build.in
index 5ad940ba6c..23cf83bc40 100644
--- a/config/Config-build.in
+++ b/config/Config-build.in
@@ -1,4 +1,5 @@
# Copyright (C) 2006-2013 OpenWrt.org
+# Copyright (C) 2016 LEDE Project
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
@@ -6,6 +7,10 @@
menu "Global build settings"
+ config ALL_NONSHARED
+ bool "Select all target specific packages by default"
+ default ALL
+
config ALL_KMODS
bool "Select all kernel module packages by default"
default ALL
diff --git a/config/Config-kernel.in b/config/Config-kernel.in
index 8ea11ed4d1..4c191f0955 100644
--- a/config/Config-kernel.in
+++ b/config/Config-kernel.in
@@ -42,9 +42,15 @@ config KERNEL_DEBUG_FS
write to these files. Many common debugging facilities, such as
ftrace, require the existence of debugfs.
+config KERNEL_ARM_PMU
+ bool
+ default n
+ depends on (arm || arm64)
+
config KERNEL_PERF_EVENTS
bool
default n
+ select KERNEL_ARM_PMU if (arm || arm64)
config KERNEL_PROFILING
bool "Compile the kernel with profiling enabled"
diff --git a/include/kernel-version.mk b/include/kernel-version.mk
index 97ff9a3824..c1dbd2330e 100644
--- a/include/kernel-version.mk
+++ b/include/kernel-version.mk
@@ -4,11 +4,11 @@ LINUX_RELEASE?=1
LINUX_VERSION-3.18 = .29
LINUX_VERSION-4.1 = .23
-LINUX_VERSION-4.4 = .7
+LINUX_VERSION-4.4 = .13
LINUX_KERNEL_MD5SUM-3.18.29 = b25737a0bc98e80d12200de93f239c28
LINUX_KERNEL_MD5SUM-4.1.23 = 5cb969fa874e110118722398b7c72c5d
-LINUX_KERNEL_MD5SUM-4.4.7 = 4345597c9a10bd73c28b6ae3a854d8d7
+LINUX_KERNEL_MD5SUM-4.4.13 = d70b6959d8db61bcea7070c089aace9b
ifdef KERNEL_PATCHVER
LINUX_VERSION:=$(KERNEL_PATCHVER)$(strip $(LINUX_VERSION-$(KERNEL_PATCHVER)))
diff --git a/include/target.mk b/include/target.mk
index a19edccc18..8211ba094f 100644
--- a/include/target.mk
+++ b/include/target.mk
@@ -216,6 +216,7 @@ ifeq ($(DUMP),1)
CPU_CFLAGS_24kec = -mips32r2 -mtune=24kec
CPU_CFLAGS_34kc = -mips32r2 -mtune=34kc
CPU_CFLAGS_74kc = -mips32r2 -mtune=74kc
+ CPU_CFLAGS_1004kc = -mips32r2 -mtune=1004kc
CPU_CFLAGS_octeon = -march=octeon -mabi=64
CPU_CFLAGS_dsp = -mdsp
CPU_CFLAGS_dsp2 = -mdspr2
diff --git a/package/boot/uboot-envtools/files/ar71xx b/package/boot/uboot-envtools/files/ar71xx
index 32e7269600..986fdef40a 100644
--- a/package/boot/uboot-envtools/files/ar71xx
+++ b/package/boot/uboot-envtools/files/ar71xx
@@ -25,6 +25,7 @@ eap300v2 | \
hornet-ub | \
hornet-ub-x2 | \
mr1750 | \
+mr1750v2 | \
mr600 | \
mr600v2 | \
mr900 | \
@@ -44,6 +45,7 @@ om2p | \
om2pv2 | \
om2p-hs | \
om2p-hsv2 | \
+om2p-hsv3 | \
om2p-lc)
ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x40000" "0x40000"
;;
diff --git a/package/boot/uboot-socfpga/Makefile b/package/boot/uboot-socfpga/Makefile
index 42fcb43af6..3fb017f2df 100644
--- a/package/boot/uboot-socfpga/Makefile
+++ b/package/boot/uboot-socfpga/Makefile
@@ -8,7 +8,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=u-boot
-PKG_VERSION:=2016.03
+PKG_VERSION:=2016.05
PKG_RELEASE:=1
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_VERSION)
@@ -16,7 +16,7 @@ PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
PKG_SOURCE_URL:= \
http://mirror2.openwrt.org/sources \
ftp://ftp.denx.de/pub/u-boot
-PKG_MD5SUM:=973c1d896be751321cc3aafa564f64b2
+PKG_MD5SUM:=3a8613d753dfa707c937991a35404510
PKG_LICENSE:=GPL-2.0 GPL-2.0+
PKG_LICENSE_FILES:=Licenses/README
diff --git a/package/boot/uboot-socfpga/patches/0001-arm-socfpga-Drop-space-after-loadaddr-in-extra-env.patch b/package/boot/uboot-socfpga/patches/0001-arm-socfpga-Drop-space-after-loadaddr-in-extra-env.patch
deleted file mode 100644
index 261afef827..0000000000
--- a/package/boot/uboot-socfpga/patches/0001-arm-socfpga-Drop-space-after-loadaddr-in-extra-env.patch
+++ /dev/null
@@ -1,101 +0,0 @@
-From 04a4c90fee75c95130af1e40880c0927d56b0b61 Mon Sep 17 00:00:00 2001
-From: Marek Vasut <marex@denx.de>
-Date: Sun, 3 Apr 2016 19:11:12 +0200
-Subject: [PATCH 1/2] arm: socfpga: Drop space after 'loadaddr=' in extra env
-
-There is an incorrect space after loadaddr= in the extra environment,
-so drop it.
-
-Signed-off-by: Marek Vasut <marex@denx.de>
-Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
-Cc: Chin Liang See <clsee@altera.com>
----
- include/configs/socfpga_arria5_socdk.h | 2 +-
- include/configs/socfpga_cyclone5_socdk.h | 2 +-
- include/configs/socfpga_de0_nano_soc.h | 2 +-
- include/configs/socfpga_sockit.h | 2 +-
- include/configs/socfpga_socrates.h | 2 +-
- include/configs/socfpga_sr1500.h | 2 +-
- 6 files changed, 6 insertions(+), 6 deletions(-)
-
-diff --git a/include/configs/socfpga_arria5_socdk.h b/include/configs/socfpga_arria5_socdk.h
-index a0161bc..153f9f8 100644
---- a/include/configs/socfpga_arria5_socdk.h
-+++ b/include/configs/socfpga_arria5_socdk.h
-@@ -56,7 +56,7 @@
- /* Extra Environment */
- #define CONFIG_EXTRA_ENV_SETTINGS \
- "verify=n\0" \
-- "loadaddr= " __stringify(CONFIG_SYS_LOAD_ADDR) "\0" \
-+ "loadaddr=" __stringify(CONFIG_SYS_LOAD_ADDR) "\0" \
- "ramboot=setenv bootargs " CONFIG_BOOTARGS ";" \
- "bootm ${loadaddr} - ${fdt_addr}\0" \
- "bootimage=zImage\0" \
-diff --git a/include/configs/socfpga_cyclone5_socdk.h b/include/configs/socfpga_cyclone5_socdk.h
-index c4c4ecb..d7c339e 100644
---- a/include/configs/socfpga_cyclone5_socdk.h
-+++ b/include/configs/socfpga_cyclone5_socdk.h
-@@ -56,7 +56,7 @@
- /* Extra Environment */
- #define CONFIG_EXTRA_ENV_SETTINGS \
- "verify=n\0" \
-- "loadaddr= " __stringify(CONFIG_SYS_LOAD_ADDR) "\0" \
-+ "loadaddr=" __stringify(CONFIG_SYS_LOAD_ADDR) "\0" \
- "ramboot=setenv bootargs " CONFIG_BOOTARGS ";" \
- "bootm ${loadaddr} - ${fdt_addr}\0" \
- "bootimage=zImage\0" \
-diff --git a/include/configs/socfpga_de0_nano_soc.h b/include/configs/socfpga_de0_nano_soc.h
-index cbc7396..314b9bf 100644
---- a/include/configs/socfpga_de0_nano_soc.h
-+++ b/include/configs/socfpga_de0_nano_soc.h
-@@ -51,7 +51,7 @@
-
- /* Extra Environment */
- #define CONFIG_EXTRA_ENV_SETTINGS \
-- "loadaddr= " __stringify(CONFIG_SYS_LOAD_ADDR) "\0" \
-+ "loadaddr=" __stringify(CONFIG_SYS_LOAD_ADDR) "\0" \
- "ramboot=setenv bootargs " CONFIG_BOOTARGS ";" \
- "bootm ${loadaddr} - ${fdt_addr}\0" \
- "bootimage=zImage\0" \
-diff --git a/include/configs/socfpga_sockit.h b/include/configs/socfpga_sockit.h
-index 95e7ba6..07cfcbf 100644
---- a/include/configs/socfpga_sockit.h
-+++ b/include/configs/socfpga_sockit.h
-@@ -52,7 +52,7 @@
- /* Extra Environment */
- #define CONFIG_EXTRA_ENV_SETTINGS \
- "verify=n\0" \
-- "loadaddr= " __stringify(CONFIG_SYS_LOAD_ADDR) "\0" \
-+ "loadaddr=" __stringify(CONFIG_SYS_LOAD_ADDR) "\0" \
- "ramboot=setenv bootargs " CONFIG_BOOTARGS ";" \
- "bootm ${loadaddr} - ${fdt_addr}\0" \
- "bootimage=zImage\0" \
-diff --git a/include/configs/socfpga_socrates.h b/include/configs/socfpga_socrates.h
-index c32a40a..02ea0c5 100644
---- a/include/configs/socfpga_socrates.h
-+++ b/include/configs/socfpga_socrates.h
-@@ -52,7 +52,7 @@
- /* Extra Environment */
- #define CONFIG_EXTRA_ENV_SETTINGS \
- "verify=n\0" \
-- "loadaddr= " __stringify(CONFIG_SYS_LOAD_ADDR) "\0" \
-+ "loadaddr=" __stringify(CONFIG_SYS_LOAD_ADDR) "\0" \
- "ramboot=setenv bootargs " CONFIG_BOOTARGS ";" \
- "bootm ${loadaddr} - ${fdt_addr}\0" \
- "bootimage=zImage\0" \
-diff --git a/include/configs/socfpga_sr1500.h b/include/configs/socfpga_sr1500.h
-index 6414eeb..e43b5cf 100644
---- a/include/configs/socfpga_sr1500.h
-+++ b/include/configs/socfpga_sr1500.h
-@@ -55,7 +55,7 @@
-
- #define CONFIG_EXTRA_ENV_SETTINGS \
- "verify=n\0" \
-- "loadaddr= " __stringify(CONFIG_SYS_LOAD_ADDR) "\0" \
-+ "loadaddr=" __stringify(CONFIG_SYS_LOAD_ADDR) "\0" \
- "ramboot=setenv bootargs " CONFIG_BOOTARGS ";" \
- "bootm ${loadaddr} - ${fdt_addr}\0" \
- "bootimage=zImage\0" \
---
-2.8.0.rc3
-
diff --git a/package/boot/uboot-socfpga/patches/0001-arm-socfpga-Tweak-SoCkit-default-env-for-OpenWRT.patch b/package/boot/uboot-socfpga/patches/0001-arm-socfpga-Tweak-SoCkit-default-env-for-OpenWRT.patch
new file mode 100644
index 0000000000..a46be2ee91
--- /dev/null
+++ b/package/boot/uboot-socfpga/patches/0001-arm-socfpga-Tweak-SoCkit-default-env-for-OpenWRT.patch
@@ -0,0 +1,65 @@
+From f17c641b74fa067c07295e20c4392664388ef7ac Mon Sep 17 00:00:00 2001
+From: Marek Vasut <marex@denx.de>
+Date: Sun, 3 Apr 2016 19:27:23 +0200
+Subject: [PATCH] arm: socfpga: Tweak SoCkit default env for OpenWRT
+
+Tweak the default environment on SoCFPGA SoCkit to match OpenWRT.
+This means switching to fitImage, which is already available, but
+not used by the environment and weeding out completely dysfunctional
+pieces of the environment.
+
+Signed-off-by: Marek Vasut <marex@denx.de>
+---
+ include/configs/socfpga_sockit.h | 20 ++++++--------------
+ 1 file changed, 6 insertions(+), 14 deletions(-)
+
+diff --git a/include/configs/socfpga_sockit.h b/include/configs/socfpga_sockit.h
+index 675f5d1..3111e46 100644
+--- a/include/configs/socfpga_sockit.h
++++ b/include/configs/socfpga_sockit.h
+@@ -19,7 +19,7 @@
+
+ /* Booting Linux */
+ #define CONFIG_BOOTDELAY 3
+-#define CONFIG_BOOTFILE "fitImage"
++#define CONFIG_BOOTFILE "openwrt-socfpga-socfpga_cyclone5_sockit-fit-uImage.itb"
+ #define CONFIG_BOOTARGS "console=ttyS0," __stringify(CONFIG_BAUDRATE)
+ #define CONFIG_BOOTCOMMAND "run mmcload; run mmcboot"
+ #define CONFIG_LOADADDR 0x01000000
+@@ -35,28 +35,20 @@
+
+ /* Extra Environment */
+ #define CONFIG_EXTRA_ENV_SETTINGS \
+- "verify=n\0" \
+ "loadaddr=" __stringify(CONFIG_SYS_LOAD_ADDR) "\0" \
+ "ramboot=setenv bootargs " CONFIG_BOOTARGS ";" \
+- "bootm ${loadaddr} - ${fdt_addr}\0" \
+- "bootimage=zImage\0" \
+- "fdt_addr=100\0" \
+- "fdtimage=socfpga.dtb\0" \
+- "bootm ${loadaddr} - ${fdt_addr}\0" \
++ "bootm ${loadaddr}\0" \
+ "mmcroot=/dev/mmcblk0p2\0" \
+ "mmcboot=setenv bootargs " CONFIG_BOOTARGS \
+ " root=${mmcroot} rw rootwait;" \
+- "bootz ${loadaddr} - ${fdt_addr}\0" \
+- "mmcload=mmc rescan;" \
+- "load mmc 0:1 ${loadaddr} ${bootimage};" \
+- "load mmc 0:1 ${fdt_addr} ${fdtimage}\0" \
++ "bootm ${loadaddr}\0" \
++ "mmcload=mmc rescan && load mmc 0:2 ${loadaddr} /boot/${bootfile}\0" \
+ "qspiload=sf probe && mtdparts default && run ubiload\0" \
+ "qspiboot=setenv bootargs " CONFIG_BOOTARGS \
+ " ubi.mtd=1,64 root=ubi0:rootfs rw rootfstype=ubifs;"\
+- "bootz ${loadaddr} - ${fdt_addr}\0" \
++ "bootz ${loadaddr}\0" \
+ "ubiload=ubi part UBI && ubifsmount ubi0 && " \
+- "ubifsload ${loadaddr} /boot/${bootimage} && " \
+- "ubifsload ${fdt_addr} /boot/${fdtimage}\0"
++ "ubifsload ${loadaddr} /boot/${bootfile}\0"
+
+ /* The rest of the configuration is shared */
+ #include <configs/socfpga_common.h>
+--
+2.8.1
+
diff --git a/package/boot/uboot-socfpga/patches/0002-arm-socfpga-Tweak-SoCkit-default-env-for-OpenWRT.patch b/package/boot/uboot-socfpga/patches/0002-arm-socfpga-Tweak-SoCkit-default-env-for-OpenWRT.patch
deleted file mode 100644
index 64ffea25b6..0000000000
--- a/package/boot/uboot-socfpga/patches/0002-arm-socfpga-Tweak-SoCkit-default-env-for-OpenWRT.patch
+++ /dev/null
@@ -1,65 +0,0 @@
-From 3a0e4875b00e9e487b0081116a81ed17cfd5143f Mon Sep 17 00:00:00 2001
-From: Marek Vasut <marex@denx.de>
-Date: Sun, 3 Apr 2016 19:27:23 +0200
-Subject: [PATCH 2/2] arm: socfpga: Tweak SoCkit default env for OpenWRT
-
-Tweak the default environment on SoCFPGA SoCkit to match OpenWRT.
-This means switching to fitImage, which is already available, but
-not used by the environment and weeding out completely dysfunctional
-pieces of the environment.
-
-Signed-off-by: Marek Vasut <marex@denx.de>
----
- include/configs/socfpga_sockit.h | 20 ++++++--------------
- 1 file changed, 6 insertions(+), 14 deletions(-)
-
-diff --git a/include/configs/socfpga_sockit.h b/include/configs/socfpga_sockit.h
-index 07cfcbf..5a90105 100644
---- a/include/configs/socfpga_sockit.h
-+++ b/include/configs/socfpga_sockit.h
-@@ -35,7 +35,7 @@
-
- /* Booting Linux */
- #define CONFIG_BOOTDELAY 3
--#define CONFIG_BOOTFILE "fitImage"
-+#define CONFIG_BOOTFILE "openwrt-socfpga-socfpga_cyclone5_sockit-fit-uImage.itb"
- #define CONFIG_BOOTARGS "console=ttyS0," __stringify(CONFIG_BAUDRATE)
- #define CONFIG_BOOTCOMMAND "run mmcload; run mmcboot"
- #define CONFIG_LOADADDR 0x01000000
-@@ -51,28 +51,20 @@
-
- /* Extra Environment */
- #define CONFIG_EXTRA_ENV_SETTINGS \
-- "verify=n\0" \
- "loadaddr=" __stringify(CONFIG_SYS_LOAD_ADDR) "\0" \
- "ramboot=setenv bootargs " CONFIG_BOOTARGS ";" \
-- "bootm ${loadaddr} - ${fdt_addr}\0" \
-- "bootimage=zImage\0" \
-- "fdt_addr=100\0" \
-- "fdtimage=socfpga.dtb\0" \
-- "bootm ${loadaddr} - ${fdt_addr}\0" \
-+ "bootm ${loadaddr}\0" \
- "mmcroot=/dev/mmcblk0p2\0" \
- "mmcboot=setenv bootargs " CONFIG_BOOTARGS \
- " root=${mmcroot} rw rootwait;" \
-- "bootz ${loadaddr} - ${fdt_addr}\0" \
-- "mmcload=mmc rescan;" \
-- "load mmc 0:1 ${loadaddr} ${bootimage};" \
-- "load mmc 0:1 ${fdt_addr} ${fdtimage}\0" \
-+ "bootm ${loadaddr}\0" \
-+ "mmcload=mmc rescan && load mmc 0:2 ${loadaddr} /boot/${bootfile}\0" \
- "qspiload=sf probe && mtdparts default && run ubiload\0" \
- "qspiboot=setenv bootargs " CONFIG_BOOTARGS \
- " ubi.mtd=1,64 root=ubi0:rootfs rw rootfstype=ubifs;"\
-- "bootz ${loadaddr} - ${fdt_addr}\0" \
-+ "bootz ${loadaddr}\0" \
- "ubiload=ubi part UBI && ubifsmount ubi0 && " \
-- "ubifsload ${loadaddr} /boot/${bootimage} && " \
-- "ubifsload ${fdt_addr} /boot/${fdtimage}\0"
-+ "ubifsload ${loadaddr} /boot/${bootfile}\0"
-
- /* The rest of the configuration is shared */
- #include <configs/socfpga_common.h>
---
-2.8.0.rc3
-
diff --git a/package/devel/gdb-arc/Makefile b/package/devel/gdb-arc/Makefile
new file mode 100644
index 0000000000..c42b108150
--- /dev/null
+++ b/package/devel/gdb-arc/Makefile
@@ -0,0 +1,94 @@
+#
+# Copyright (C) 2006-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=gdb-arc
+PKG_VERSION:=arc-2016.03-gdb
+PKG_RELEASE:=1
+
+PKG_SOURCE:=gdb-arc-2016.03-gdb.tar.gz
+PKG_SOURCE_URL:=https://github.com/foss-for-synopsys-dwc-arc-processors/binutils-gdb/archive/$(PKG_VERSION)
+PKG_MD5SUM:=775caaf6385c16f20b6f53c0a2b95f79
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/binutils-gdb-arc-2016.03-gdb
+
+PKG_BUILD_PARALLEL:=1
+PKG_INSTALL:=1
+PKG_LICENSE:=GPL-3.0+
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/gdb-arc/Default
+ SECTION:=devel
+ CATEGORY:=Development
+ DEPENDS:=+!USE_MUSL:libthread-db +PACKAGE_zlib:zlib @arc
+ URL:=http://www.gnu.org/software/gdb/
+endef
+
+define Package/gdb-arc
+$(call Package/gdb-arc/Default)
+ TITLE:=GNU Debugger for ARC
+ DEPENDS+=+libreadline +libncurses +zlib
+endef
+
+define Package/gdb-arc/description
+GDB, the GNU Project debugger, allows you to see what is going on `inside'
+another program while it executes -- or what another program was doing at the
+moment it crashed.
+endef
+
+define Package/gdbserver-arc
+$(call Package/gdb-arc/Default)
+ TITLE:=Remote server for GNU Debugger
+endef
+
+define Package/gdbserver-arc/description
+GDBSERVER is a program that allows you to run GDB on a different machine than the
+one which is running the program being debugged.
+endef
+
+# XXX: add --disable-werror to prevent build failure with arm
+CONFIGURE_ARGS+= \
+ --with-system-readline \
+ --without-expat \
+ --without-lzma \
+ --disable-werror \
+ --disable-binutils \
+ --disable-ld \
+ --disable-gas \
+ --disable-sim
+
+CONFIGURE_VARS+= \
+ ac_cv_search_tgetent="$(TARGET_LDFLAGS) -lncurses -lreadline"
+
+define Build/Compile
+ +$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
+ DESTDIR="$(PKG_INSTALL_DIR)" \
+ CPPFLAGS="$(TARGET_CPPFLAGS)" \
+ all
+endef
+
+define Build/Install
+ $(MAKE) -C $(PKG_BUILD_DIR) \
+ DESTDIR="$(PKG_INSTALL_DIR)" \
+ CPPFLAGS="$(TARGET_CPPFLAGS)" \
+ install-gdb
+endef
+
+define Package/gdb-arc/install
+ $(INSTALL_DIR) $(1)/usr/bin
+ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/gdb $(1)/usr/bin/
+endef
+
+define Package/gdbserver-arc/install
+ $(INSTALL_DIR) $(1)/usr/bin
+ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/gdbserver $(1)/usr/bin/
+endef
+
+$(eval $(call BuildPackage,gdb-arc))
+$(eval $(call BuildPackage,gdbserver-arc))
diff --git a/package/devel/gdb-arc/patches/100-no_extern_inline.patch b/package/devel/gdb-arc/patches/100-no_extern_inline.patch
new file mode 100644
index 0000000000..8c18c6e2e7
--- /dev/null
+++ b/package/devel/gdb-arc/patches/100-no_extern_inline.patch
@@ -0,0 +1,32 @@
+--- a/sim/common/sim-arange.c
++++ b/sim/common/sim-arange.c
+@@ -280,11 +280,7 @@ sim_addr_range_delete (ADDR_RANGE *ar, a
+ build_search_tree (ar);
+ }
+
+-#endif /* DEFINE_NON_INLINE_P */
+-
+-#if DEFINE_INLINE_P
+-
+-SIM_ARANGE_INLINE int
++int
+ sim_addr_range_hit_p (ADDR_RANGE *ar, address_word addr)
+ {
+ ADDR_RANGE_TREE *t = ar->range_tree;
+@@ -301,4 +297,4 @@ sim_addr_range_hit_p (ADDR_RANGE *ar, ad
+ return 0;
+ }
+
+-#endif /* DEFINE_INLINE_P */
++#endif /* DEFINE_NON_INLINE_P */
+--- a/sim/common/sim-arange.h
++++ b/sim/common/sim-arange.h
+@@ -73,7 +73,7 @@ extern void sim_addr_range_delete (ADDR_
+
+ /* Return non-zero if ADDR is in range AR, traversing the entire tree.
+ If no range is specified, that is defined to mean "everything". */
+-SIM_ARANGE_INLINE int
++extern int
+ sim_addr_range_hit_p (ADDR_RANGE * /*ar*/, address_word /*addr*/);
+ #define ADDR_RANGE_HIT_P(ar, addr) \
+ ((ar)->range_tree == NULL || sim_addr_range_hit_p ((ar), (addr)))
diff --git a/package/devel/gdb-arc/patches/110-no_testsuite.patch b/package/devel/gdb-arc/patches/110-no_testsuite.patch
new file mode 100644
index 0000000000..1b284ea767
--- /dev/null
+++ b/package/devel/gdb-arc/patches/110-no_testsuite.patch
@@ -0,0 +1,21 @@
+--- a/gdb/configure
++++ b/gdb/configure
+@@ -870,8 +870,7 @@ MAKEINFOFLAGS
+ YACC
+ YFLAGS
+ XMKMF'
+-ac_subdirs_all='testsuite
+-gdbtk
++ac_subdirs_all='gdbtk
+ multi-ice
+ gdbserver'
+
+@@ -5610,7 +5610,7 @@ $as_echo "$with_auto_load_safe_path" >&6
+
+
+
+-subdirs="$subdirs testsuite"
++subdirs="$subdirs"
+
+
+ # Check whether to support alternative target configurations
diff --git a/package/devel/gdb-arc/patches/120-fix-compile-flag-mismatch.patch b/package/devel/gdb-arc/patches/120-fix-compile-flag-mismatch.patch
new file mode 100644
index 0000000000..c8b41f264a
--- /dev/null
+++ b/package/devel/gdb-arc/patches/120-fix-compile-flag-mismatch.patch
@@ -0,0 +1,11 @@
+--- a/gdb/gdbserver/configure
++++ b/gdb/gdbserver/configure
+@@ -2468,7 +2468,7 @@ $as_echo "$as_me: error: \`$ac_var' was
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+- if test "x$ac_old_val" != "x$ac_new_val"; then
++ if test "`echo x$ac_old_val`" != "`echo x$ac_new_val`"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
diff --git a/package/devel/gdb/Makefile b/package/devel/gdb/Makefile
index f6d5fec2ff..5678b5bb00 100644
--- a/package/devel/gdb/Makefile
+++ b/package/devel/gdb/Makefile
@@ -24,7 +24,7 @@ include $(INCLUDE_DIR)/package.mk
define Package/gdb/Default
SECTION:=devel
CATEGORY:=Development
- DEPENDS:=+!USE_MUSL:libthread-db +PACKAGE_zlib:zlib
+ DEPENDS:=+!USE_MUSL:libthread-db +PACKAGE_zlib:zlib @!arc
URL:=http://www.gnu.org/software/gdb/
endef
diff --git a/package/firmware/am33x-cm3/Makefile b/package/firmware/am33x-cm3/Makefile
index bd7e2ae536..6f6d050013 100644
--- a/package/firmware/am33x-cm3/Makefile
+++ b/package/firmware/am33x-cm3/Makefile
@@ -20,6 +20,8 @@ PKG_MD5SUM:=40a6b7edae5e5cfff99bebde2bf20b97
PKG_MAINTAINER:=Imre Kaloz <kaloz@openwrt.org>
+PKG_FLAGS:=nonshared
+
include $(INCLUDE_DIR)/package.mk
define Package/am33x-cm3
diff --git a/package/firmware/ath10k-firmware/Makefile b/package/firmware/ath10k-firmware/Makefile
index 05dce467fa..c196e32d24 100644
--- a/package/firmware/ath10k-firmware/Makefile
+++ b/package/firmware/ath10k-firmware/Makefile
@@ -8,7 +8,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=ath10k-firmware
-PKG_SOURCE_VERSION:=77f72b5f7dd940386d9e619a17904987759b7186
+PKG_SOURCE_VERSION:=b00eb8d30fbebb6a5047ccacefa8c37e072fca9c
PKG_VERSION:=2014-11-13-$(PKG_SOURCE_VERSION)
PKG_RELEASE:=1
@@ -38,6 +38,8 @@ $(Package/ath10k-firmware-default)
endef
QCA988X_FIRMWARE_FILE:=firmware-5.bin_10.2.4.97-1
+QCA988X_FIRMWARE_FILE_CT:=firmware-2-ct-full-community-16.bin-lede
+QCA99X0_FIRMWARE_FILE_CT:=firmware-5-ct-full-community-7.bin-lede.001
define Download/ath10k-firmware-qca988x
URL:=https://www.codeaurora.org/cgit/quic/qsdk/oss/firmware/ath10k-firmware/plain/10.2.4/
@@ -46,11 +48,63 @@ define Download/ath10k-firmware-qca988x
endef
$(eval $(call Download,ath10k-firmware-qca988x))
+define Download/ath10k-firmware-qca988x-ct
+ URL:=https://www.candelatech.com/downloads/
+ FILE:=$(QCA988X_FIRMWARE_FILE_CT)
+ MD5SUM:=5b651c0458bcf5c20701308b5e519976
+endef
+$(eval $(call Download,ath10k-firmware-qca988x-ct))
+
+define Download/ath10k-firmware-qca99x0-ct
+ URL:=https://www.candelatech.com/downloads/ath10k-10-4/
+ FILE:=$(QCA99X0_FIRMWARE_FILE_CT)
+ MD5SUM:=eb710949ff79142954aadae24616169c
+endef
+$(eval $(call Download,ath10k-firmware-qca99x0-ct))
+
define Package/ath10k-firmware-qca99x0
$(Package/ath10k-firmware-default)
TITLE:=ath10k firmware for QCA99x0 devices
endef
+define Package/ath10k-firmware-qca988x-ct
+$(Package/ath10k-firmware-default)
+ TITLE:=ath10k CT 10.1 firmware for QCA988x devices
+endef
+
+define Package/ath10k-firmware-qca988x-ct/description
+Alternative ath10k firmware for QCA988X from Candela Technologies.
+Enables IBSS and other features. See:
+http://www.candelatech.com/ath10k-10.1.php
+This firmware will NOT be used unless the standard ath10k-firmware-qca988x
+is un-selected since the driver will try to load firmware-5.bin before
+firmware-2.bin
+endef
+
+define Package/ath10k-firmware-qca99x0-ct/description
+Alternative ath10k firmware for QCA99x0 from Candela Technologies.
+Enables IBSS and other features. See:
+http://www.candelatech.com/ath10k-10.4.php
+This firmware conflicts with the standard 99x0 firmware, so select only
+one.
+endef
+
+define Package/ath10k-firmware-qca99x0/description
+Standard ath10k firmware for QCA99x0 from QCA
+This firmware conflicts with the CT 99x0 firmware, so select only
+one.
+endef
+
+define Package/ath10k-firmware-qca99x0-ct
+$(Package/ath10k-firmware-default)
+ TITLE:=ath10k CT 10.4.3 firmware for QCA99x0 devices
+endef
+
+define Package/ath10k-firmware-qca9984
+$(Package/ath10k-firmware-default)
+ TITLE:=ath10k firmware for QCA9984 devices
+endef
+
define Package/ath10k-firmware-qca6174
$(Package/ath10k-firmware-default)
TITLE:=ath10k firmware for QCA6174 devices
@@ -60,7 +114,7 @@ QCA99X0_BOARD_REV:=ddcec9efd245da9365c474f513a855a55f3ac7fe
QCA99X0_BOARD_FILE:=board-2.bin.$(QCA99X0_BOARD_REV)
define Download/qca99x0-board
- URL:=https://www.codeaurora.org/cgit/quic/qsdk/oss/firmware/ath10k-firmware/plain/ath10k/QCA99X0/hw2.0
+ URL:=https://source.codeaurora.org/quic/qsdk/oss/firmware/ath10k-firmware/plain/ath10k/QCA99X0/hw2.0
URL_FILE:=board-2.bin?id=ddcec9efd245da9365c474f513a855a55f3ac7fe
FILE:=$(QCA99X0_BOARD_FILE)
MD5SUM:=a2b3c653c2363a5641200051d6333d0a
@@ -81,6 +135,16 @@ define Package/ath10k-firmware-qca988x/install
$(1)/lib/firmware/ath10k/QCA988X/hw2.0/firmware-5.bin
endef
+define Package/ath10k-firmware-qca988x-ct/install
+ $(INSTALL_DIR) $(1)/lib/firmware/ath10k/QCA988X/hw2.0
+ $(INSTALL_DATA) \
+ $(PKG_BUILD_DIR)/QCA988X/board.bin \
+ $(1)/lib/firmware/ath10k/QCA988X/hw2.0/
+ $(INSTALL_DATA) \
+ $(DL_DIR)/$(QCA988X_FIRMWARE_FILE_CT) \
+ $(1)/lib/firmware/ath10k/QCA988X/hw2.0/firmware-2.bin
+endef
+
define Package/ath10k-firmware-qca6174/install
$(INSTALL_DIR) $(1)/lib/firmware/ath10k
$(CP) $(PKG_BUILD_DIR)/QCA6174 $(1)/lib/firmware/ath10k/
@@ -99,6 +163,33 @@ define Package/ath10k-firmware-qca99x0/install
$(1)/lib/firmware/ath10k/QCA99X0/hw2.0/firmware-5.bin
endef
+define Package/ath10k-firmware-qca99x0-ct/install
+ $(INSTALL_DIR) $(1)/lib/firmware/ath10k/QCA99X0/hw2.0
+ $(INSTALL_DATA) \
+ $(DL_DIR)/$(QCA99X0_BOARD_FILE) \
+ $(1)/lib/firmware/ath10k/QCA99X0/hw2.0/board-2.bin
+ $(INSTALL_DATA) \
+ $(PKG_BUILD_DIR)/QCA99X0/hw2.0/boardData_AR900B_CUS239_5G_v2_001.bin \
+ $(1)/lib/firmware/ath10k/QCA99X0/hw2.0/board.bin
+ $(INSTALL_DATA) \
+ $(DL_DIR)/$(QCA99X0_FIRMWARE_FILE_CT) \
+ $(1)/lib/firmware/ath10k/QCA99X0/hw2.0/firmware-5.bin
+endef
+
+define Package/ath10k-firmware-qca9984/install
+ $(INSTALL_DIR) $(1)/lib/firmware/ath10k/QCA9984/hw1.0
+ $(INSTALL_DATA) \
+ $(PKG_BUILD_DIR)/QCA9984/hw1.0/board-2.bin \
+ $(1)/lib/firmware/ath10k/QCA9984/hw1.0/board-2.bin
+ $(INSTALL_DATA) \
+ $(PKG_BUILD_DIR)/QCA9984/hw1.0/firmware-5.bin_10.4-3.2-00072 \
+ $(1)/lib/firmware/ath10k/QCA9984/hw1.0/firmware-5.bin
+endef
+
$(eval $(call BuildPackage,ath10k-firmware-qca988x))
$(eval $(call BuildPackage,ath10k-firmware-qca99x0))
$(eval $(call BuildPackage,ath10k-firmware-qca6174))
+$(eval $(call BuildPackage,ath10k-firmware-qca9984))
+
+$(eval $(call BuildPackage,ath10k-firmware-qca988x-ct))
+$(eval $(call BuildPackage,ath10k-firmware-qca99x0-ct))
diff --git a/package/firmware/ixp4xx-microcode/Makefile b/package/firmware/ixp4xx-microcode/Makefile
index 1af12480c1..502424d678 100644
--- a/package/firmware/ixp4xx-microcode/Makefile
+++ b/package/firmware/ixp4xx-microcode/Makefile
@@ -15,6 +15,8 @@ PKG_SOURCE:=IPL_ixp400NpeLibraryWithCrypto-2_4.zip
PKG_SOURCE_URL:=http://downloads.openwrt.org/sources
PKG_MD5SUM:=dd5f6482e625ecb334469958bcd54b37
+PKG_FLAGS:=nonshared
+
include $(INCLUDE_DIR)/package.mk
define Package/ixp4xx-microcode
diff --git a/package/firmware/lantiq/dsl-vrx200-firmware-xdsl/Makefile b/package/firmware/lantiq/dsl-vrx200-firmware-xdsl/Makefile
index 7e94d49246..a39bf412de 100644
--- a/package/firmware/lantiq/dsl-vrx200-firmware-xdsl/Makefile
+++ b/package/firmware/lantiq/dsl-vrx200-firmware-xdsl/Makefile
@@ -14,6 +14,8 @@ PKG_SOURCE_URL:=http://mirror2.openwrt.org/sources
PKG_MD5SUM:=4c8d9ca68dda88d3cfc0ca0fb946a63e
PKG_BUILD_DEPENDS:=bsdiff/host
+PKG_FLAGS:=nonshared
+
include $(INCLUDE_DIR)/package.mk
PKG_B_NAME:=dsl_vr9_firmware_xdsl
diff --git a/package/firmware/vsc73x5-ucode/Makefile b/package/firmware/vsc73x5-ucode/Makefile
index 3a07121107..e3379a1f95 100644
--- a/package/firmware/vsc73x5-ucode/Makefile
+++ b/package/firmware/vsc73x5-ucode/Makefile
@@ -17,6 +17,8 @@ PKG_BUILD_DIR:=$(BUILD_DIR)/vsc73x5-ucode
PKG_MD5SUM:=b32e3debcd118f263c79199a7b5afa68
+PKG_FLAGS:=nonshared
+
include $(INCLUDE_DIR)/package.mk
define Package/vsc73x5-defaults
diff --git a/package/kernel/acx-mac80211/patches/300-api_sync.patch b/package/kernel/acx-mac80211/patches/300-api_sync.patch
new file mode 100644
index 0000000000..94d61351aa
--- /dev/null
+++ b/package/kernel/acx-mac80211/patches/300-api_sync.patch
@@ -0,0 +1,83 @@
+--- a/main.c
++++ b/main.c
+@@ -497,7 +497,7 @@ int acx_free_mechanics(acx_device_t *ade
+
+ int acx_init_ieee80211(acx_device_t *adev, struct ieee80211_hw *hw)
+ {
+- hw->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS;
++ __clear_bit(IEEE80211_HW_RX_INCLUDES_FCS, hw->flags);
+ hw->queues = 1;
+ hw->wiphy->max_scan_ssids = 1;
+
+@@ -525,14 +525,14 @@ int acx_init_ieee80211(acx_device_t *ade
+ /* We base signal quality on winlevel approach of previous driver
+ * TODO OW 20100615 This should into a common init code
+ */
+- hw->flags |= IEEE80211_HW_SIGNAL_UNSPEC;
++ __set_bit(IEEE80211_HW_SIGNAL_UNSPEC, hw->flags);
+ hw->max_signal = 100;
+
+ if (IS_ACX100(adev)) {
+- adev->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
++ adev->hw->wiphy->bands[NL80211_BAND_2GHZ] =
+ &acx100_band_2GHz;
+ } else if (IS_ACX111(adev))
+- adev->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
++ adev->hw->wiphy->bands[NL80211_BAND_2GHZ] =
+ &acx111_band_2GHz;
+ else {
+ log(L_ANY, "Error: Unknown device");
+@@ -945,8 +945,8 @@ void acx_op_configure_filter(struct ieee
+ changed_flags, *total_flags);
+
+ /* OWI TODO: Set also FIF_PROBE_REQ ? */
+- *total_flags &= (FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL
+- | FIF_CONTROL | FIF_OTHER_BSS);
++ *total_flags &= (FIF_ALLMULTI | FIF_FCSFAIL | FIF_CONTROL
++ | FIF_OTHER_BSS);
+
+ logf1(L_DEBUG, "2: *total_flags=0x%08x\n", *total_flags);
+
+@@ -1045,9 +1045,10 @@ void acx_op_tx(struct ieee80211_hw *hw,
+ }
+
+ int acx_op_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+- struct cfg80211_scan_request *req)
++ struct ieee80211_scan_request *hw_req)
+ {
+ acx_device_t *adev = hw2adev(hw);
++ struct cfg80211_scan_request *req = &hw_req->req;
+ struct sk_buff *skb;
+ size_t ssid_len = 0;
+ u8 *ssid = NULL;
+@@ -1082,7 +1083,7 @@ int acx_op_hw_scan(struct ieee80211_hw *
+ goto out;
+ }
+ #else
+- skb = ieee80211_probereq_get(adev->hw, adev->vif, ssid, ssid_len,
++ skb = ieee80211_probereq_get(adev->hw, vif->addr, ssid, ssid_len,
+ req->ie_len);
+ if (!skb) {
+ ret = -ENOMEM;
+--- a/main.h
++++ b/main.h
+@@ -62,7 +62,7 @@ void acx_op_tx(struct ieee80211_hw *hw,
+ #endif
+
+ int acx_op_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+- struct cfg80211_scan_request *req);
++ struct ieee80211_scan_request *req);
+
+ int acx_recover_hw(acx_device_t *adev);
+
+--- a/cardsetting.c
++++ b/cardsetting.c
+@@ -159,7 +159,7 @@ int acx_set_channel(acx_device_t *adev,
+ int res = 0;
+
+ adev->rx_status.freq = freq;
+- adev->rx_status.band = IEEE80211_BAND_2GHZ;
++ adev->rx_status.band = NL80211_BAND_2GHZ;
+
+ adev->channel = channel;
+
diff --git a/package/kernel/acx-mac80211/patches/300-kernel_4_2.patch b/package/kernel/acx-mac80211/patches/300-kernel_4_2.patch
deleted file mode 100644
index ee92b943e5..0000000000
--- a/package/kernel/acx-mac80211/patches/300-kernel_4_2.patch
+++ /dev/null
@@ -1,67 +0,0 @@
-diff --git a/main.c b/main.c
-index bfec856..3c482d9 100644
---- a/main.c
-+++ b/main.c
-@@ -497,7 +497,7 @@ int acx_free_mechanics(acx_device_t *adev)
-
- int acx_init_ieee80211(acx_device_t *adev, struct ieee80211_hw *hw)
- {
-- hw->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS;
-+ __clear_bit(IEEE80211_HW_RX_INCLUDES_FCS, hw->flags);
- hw->queues = 1;
- hw->wiphy->max_scan_ssids = 1;
-
-@@ -525,7 +525,7 @@ int acx_init_ieee80211(acx_device_t *adev, struct ieee80211_hw *hw)
- /* We base signal quality on winlevel approach of previous driver
- * TODO OW 20100615 This should into a common init code
- */
-- hw->flags |= IEEE80211_HW_SIGNAL_UNSPEC;
-+ __set_bit(IEEE80211_HW_SIGNAL_UNSPEC, hw->flags);
- hw->max_signal = 100;
-
- if (IS_ACX100(adev)) {
-@@ -945,8 +945,8 @@ void acx_op_configure_filter(struct ieee80211_hw *hw,
- changed_flags, *total_flags);
-
- /* OWI TODO: Set also FIF_PROBE_REQ ? */
-- *total_flags &= (FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL
-- | FIF_CONTROL | FIF_OTHER_BSS);
-+ *total_flags &= (FIF_ALLMULTI | FIF_FCSFAIL | FIF_CONTROL
-+ | FIF_OTHER_BSS);
-
- logf1(L_DEBUG, "2: *total_flags=0x%08x\n", *total_flags);
-
-@@ -1045,9 +1045,10 @@ void acx_op_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
- }
-
- int acx_op_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-- struct cfg80211_scan_request *req)
-+ struct ieee80211_scan_request *hw_req)
- {
- acx_device_t *adev = hw2adev(hw);
-+ struct cfg80211_scan_request *req = &hw_req->req;
- struct sk_buff *skb;
- size_t ssid_len = 0;
- u8 *ssid = NULL;
-@@ -1082,7 +1083,7 @@ int acx_op_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- goto out;
- }
- #else
-- skb = ieee80211_probereq_get(adev->hw, adev->vif, ssid, ssid_len,
-+ skb = ieee80211_probereq_get(adev->hw, vif->addr, ssid, ssid_len,
- req->ie_len);
- if (!skb) {
- ret = -ENOMEM;
-diff --git a/main.h b/main.h
-index 293f5c8..84ecb9a 100644
---- a/main.h
-+++ b/main.h
-@@ -62,7 +62,7 @@ void acx_op_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
- #endif
-
- int acx_op_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-- struct cfg80211_scan_request *req);
-+ struct ieee80211_scan_request *req);
-
- int acx_recover_hw(acx_device_t *adev);
-
diff --git a/package/kernel/ar7-atm/Makefile b/package/kernel/ar7-atm/Makefile
index 74d334cb83..12ea031bbb 100644
--- a/package/kernel/ar7-atm/Makefile
+++ b/package/kernel/ar7-atm/Makefile
@@ -34,6 +34,8 @@ endif
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_RELEASE).tar.bz2
PKG_SOURCE_URL:=http://mirror2.openwrt.org/sources
+PKG_FLAGS:=nonshared
+
include $(INCLUDE_DIR)/package.mk
define KernelPackage/sangam-atm/Default
diff --git a/package/kernel/brcm2708-gpu-fw/Makefile b/package/kernel/brcm2708-gpu-fw/Makefile
index dc70585f18..f4b4ad5ca7 100644
--- a/package/kernel/brcm2708-gpu-fw/Makefile
+++ b/package/kernel/brcm2708-gpu-fw/Makefile
@@ -8,18 +8,66 @@ include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=brcm2708-gpu-fw
-PKG_REV:=30fe8178d61c1ff9bc168edaafdbcb101aa6245e
-PKG_VERSION:=20160304
-PKG_RELEASE:=1
+PKG_VERSION:=2016-06-08
+PKG_RELEASE:=70143fe9d371cd6486a80d6765e93b5574212b64
-PKG_SOURCE:=$(PKG_REV).tar.gz
-PKG_SOURCE_URL:=https://github.com/Hexxeh/rpi-firmware/archive/
-PKG_MD5SUM:=5707f4d9ffd8d10018c68ecb8b363308
+PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(PKG_NAME)/rpi-firmware-$(PKG_RELEASE)
-PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(PKG_NAME)/rpi-firmware-$(PKG_REV)
+PKG_FLAGS:=nonshared
include $(INCLUDE_DIR)/package.mk
+RPI_FIRMWARE_URL:=@GITHUB/raspberrypi/firmware/$(PKG_RELEASE)/boot/
+RPI_FIRMWARE_FILE:=rpi-firmware-$(PKG_RELEASE)
+
+define Download/LICENCE_broadcom
+ FILE:=$(RPI_FIRMWARE_FILE)-LICENCE.broadcom
+ URL:=$(RPI_FIRMWARE_URL)
+ URL_FILE:=LICENCE.broadcom
+ MD5SUM:=4a4d169737c0786fb9482bb6d30401d1
+endef
+$(eval $(call Download,LICENCE_broadcom))
+
+define Download/bootcode_bin
+ FILE:=$(RPI_FIRMWARE_FILE)-bootcode.bin
+ URL:=$(RPI_FIRMWARE_URL)
+ URL_FILE:=bootcode.bin
+ MD5SUM:=5bbb5f25dfe16f2871d5defcc48ac9ff
+endef
+$(eval $(call Download,bootcode_bin))
+
+define Download/fixup_dat
+ FILE:=$(RPI_FIRMWARE_FILE)-fixup.dat
+ URL:=$(RPI_FIRMWARE_URL)
+ URL_FILE:=fixup.dat
+ MD5SUM:=c85a8a7fd6f1012dedb979d5a5350135
+endef
+$(eval $(call Download,fixup_dat))
+
+define Download/fixup_cd_dat
+ FILE:=$(RPI_FIRMWARE_FILE)-fixup_cd.dat
+ URL:=$(RPI_FIRMWARE_URL)
+ URL_FILE:=fixup_cd.dat
+ MD5SUM:=1e6c0d6c576956282b498f255eb12d3b
+endef
+$(eval $(call Download,fixup_cd_dat))
+
+define Download/start_elf
+ FILE:=$(RPI_FIRMWARE_FILE)-start.elf
+ URL:=$(RPI_FIRMWARE_URL)
+ URL_FILE:=start.elf
+ MD5SUM:=94f8e421d6e46e89a60aa001af63844e
+endef
+$(eval $(call Download,start_elf))
+
+define Download/start_cd_elf
+ FILE:=$(RPI_FIRMWARE_FILE)-start_cd.elf
+ URL:=$(RPI_FIRMWARE_URL)
+ URL_FILE:=start_cd.elf
+ MD5SUM:=0a9082c25af181cbf16338de2362d5d6
+endef
+$(eval $(call Download,start_cd_elf))
+
define Package/brcm2708-gpu-fw
SECTION:=boot
CATEGORY:=Boot Loaders
@@ -32,6 +80,17 @@ define Package/brcm2708-gpu-fw/description
GPU and kernel boot firmware for brcm2708.
endef
+define Build/Prepare
+ rm -rf $(PKG_BUILD_DIR)
+ mkdir -p $(PKG_BUILD_DIR)
+ cp $(DL_DIR)/$(RPI_FIRMWARE_FILE)-LICENCE.broadcom $(PKG_BUILD_DIR)/LICENCE.broadcom
+ cp $(DL_DIR)/$(RPI_FIRMWARE_FILE)-bootcode.bin $(PKG_BUILD_DIR)/bootcode.bin
+ cp $(DL_DIR)/$(RPI_FIRMWARE_FILE)-fixup.dat $(PKG_BUILD_DIR)/fixup.dat
+ cp $(DL_DIR)/$(RPI_FIRMWARE_FILE)-fixup_cd.dat $(PKG_BUILD_DIR)/fixup_cd.dat
+ cp $(DL_DIR)/$(RPI_FIRMWARE_FILE)-start.elf $(PKG_BUILD_DIR)/start.elf
+ cp $(DL_DIR)/$(RPI_FIRMWARE_FILE)-start_cd.elf $(PKG_BUILD_DIR)/start_cd.elf
+endef
+
define Build/Compile
true
endef
@@ -42,7 +101,6 @@ endef
define Build/InstallDev
$(CP) $(PKG_BUILD_DIR)/bootcode.bin $(KERNEL_BUILD_DIR)
- $(CP) $(PKG_BUILD_DIR)/COPYING.linux $(KERNEL_BUILD_DIR)
$(CP) $(PKG_BUILD_DIR)/LICENCE.broadcom $(KERNEL_BUILD_DIR)
$(CP) $(PKG_BUILD_DIR)/start.elf $(KERNEL_BUILD_DIR)
$(CP) $(PKG_BUILD_DIR)/start_cd.elf $(KERNEL_BUILD_DIR)
diff --git a/package/kernel/broadcom-wl/Makefile b/package/kernel/broadcom-wl/Makefile
index 003986ccbe..78cbdf0590 100644
--- a/package/kernel/broadcom-wl/Makefile
+++ b/package/kernel/broadcom-wl/Makefile
@@ -20,6 +20,7 @@ PKG_MD5SUM.mips:=f8de63debc75333d6b4e28193eb051ff
PKG_MD5SUM:=$(PKG_MD5SUM.$(ARCH))
PKG_USE_MIPS16:=0
+PKG_FLAGS:=nonshared
include $(INCLUDE_DIR)/package.mk
diff --git a/package/kernel/dtc/Makefile b/package/kernel/dtc/Makefile
new file mode 100644
index 0000000000..5155323c42
--- /dev/null
+++ b/package/kernel/dtc/Makefile
@@ -0,0 +1,36 @@
+#
+# Copyright (C) 2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=dtc
+PKG_VERSION:=1.4.1
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_URL:=git://git.kernel.org/pub/scm/utils/dtc/dtc.git
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_VERSION:=302fca9f4c283e1994cf0a5a9ce1cf43ca15e6d2
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
+
+PKG_MAINTAINER:=Marek Vasut <marex@denx.de>
+PKG_LICENSE:=GPL-2.0+
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/dtc
+ SECTION:=utils
+ CATEGORY:=Utilities
+ TITLE:=Device Tree Compiler
+endef
+
+define Package/dtc/install
+ $(INSTALL_DIR) $(1)/usr/bin
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/dtc $(1)/usr/bin/
+endef
+
+$(eval $(call BuildPackage,dtc))
diff --git a/package/kernel/dtc/patches/0001-scripts-dtc-Update-to-version-with-overlays.patch b/package/kernel/dtc/patches/0001-scripts-dtc-Update-to-version-with-overlays.patch
new file mode 100644
index 0000000000..605d303c47
--- /dev/null
+++ b/package/kernel/dtc/patches/0001-scripts-dtc-Update-to-version-with-overlays.patch
@@ -0,0 +1,642 @@
+From 5f84cb93eef9f8a8ff7f49d593893f252744d0fe Mon Sep 17 00:00:00 2001
+From: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
+Date: Wed, 26 Aug 2015 18:28:08 +0300
+Subject: [PATCH] scripts/dtc: Update to version with overlays
+
+Update to mainline dtc with overlay support
+
+Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
+---
+ checks.c | 20 +++++-
+ dtc-lexer.l | 5 ++
+ dtc-parser.y | 54 ++++++++++++++--
+ dtc.c | 83 ++++++++++++++++++++++--
+ dtc.h | 13 +++-
+ livetree.c | 202 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ treesource.c | 3 +
+ util.c | 2 +-
+ 8 files changed, 367 insertions(+), 15 deletions(-)
+
+diff --git a/checks.c b/checks.c
+index 3bf0fa4..af25c2b 100644
+--- a/checks.c
++++ b/checks.c
+@@ -465,8 +465,12 @@ static void fixup_phandle_references(struct check *c, struct node *dt,
+
+ refnode = get_node_by_ref(dt, m->ref);
+ if (! refnode) {
+- FAIL(c, "Reference to non-existent node or label \"%s\"\n",
+- m->ref);
++ if (!source_is_plugin)
++ FAIL(c, "Reference to non-existent node or "
++ "label \"%s\"\n", m->ref);
++ else /* mark the entry as unresolved */
++ *((cell_t *)(prop->val.val + m->offset)) =
++ cpu_to_fdt32(0xffffffff);
+ continue;
+ }
+
+@@ -559,7 +563,7 @@ static void check_reg_format(struct check *c, struct node *dt,
+ size_cells = node_size_cells(node->parent);
+ entrylen = (addr_cells + size_cells) * sizeof(cell_t);
+
+- if ((prop->val.len % entrylen) != 0)
++ if (!entrylen || (prop->val.len % entrylen) != 0)
+ FAIL(c, "\"reg\" property in %s has invalid length (%d bytes) "
+ "(#address-cells == %d, #size-cells == %d)",
+ node->fullpath, prop->val.len, addr_cells, size_cells);
+@@ -651,6 +655,15 @@ static void check_obsolete_chosen_interrupt_controller(struct check *c,
+ }
+ TREE_WARNING(obsolete_chosen_interrupt_controller, NULL);
+
++static void check_deprecated_plugin_syntax(struct check *c,
++ struct node *dt)
++{
++ if (deprecated_plugin_syntax_warning)
++ FAIL(c, "Use '/dts-v1/ /plugin/'; syntax. /dts-v1/; /plugin/; "
++ "is going to be removed in next versions");
++}
++TREE_WARNING(deprecated_plugin_syntax, NULL);
++
+ static struct check *check_table[] = {
+ &duplicate_node_names, &duplicate_property_names,
+ &node_name_chars, &node_name_format, &property_name_chars,
+@@ -668,6 +681,7 @@ static struct check *check_table[] = {
+
+ &avoid_default_addr_size,
+ &obsolete_chosen_interrupt_controller,
++ &deprecated_plugin_syntax,
+
+ &always_fail,
+ };
+diff --git a/dtc-lexer.l b/dtc-lexer.l
+index 0ee1caf..dd44ba2 100644
+--- a/dtc-lexer.l
++++ b/dtc-lexer.l
+@@ -113,6 +113,11 @@ static void lexical_error(const char *fmt, ...);
+ return DT_V1;
+ }
+
++<*>"/plugin/" {
++ DPRINT("Keyword: /plugin/\n");
++ return DT_PLUGIN;
++ }
++
+ <*>"/memreserve/" {
+ DPRINT("Keyword: /memreserve/\n");
+ BEGIN_DEFAULT();
+diff --git a/dtc-parser.y b/dtc-parser.y
+index ea57e0a..7d9652d 100644
+--- a/dtc-parser.y
++++ b/dtc-parser.y
+@@ -19,6 +19,7 @@
+ */
+ %{
+ #include <stdio.h>
++#include <inttypes.h>
+
+ #include "dtc.h"
+ #include "srcpos.h"
+@@ -52,9 +53,11 @@ extern bool treesource_error;
+ struct node *nodelist;
+ struct reserve_info *re;
+ uint64_t integer;
++ bool is_plugin;
+ }
+
+ %token DT_V1
++%token DT_PLUGIN
+ %token DT_MEMRESERVE
+ %token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR
+ %token DT_BITS
+@@ -71,6 +74,7 @@ extern bool treesource_error;
+
+ %type <data> propdata
+ %type <data> propdataprefix
++%type <is_plugin> plugindecl
+ %type <re> memreserve
+ %type <re> memreserves
+ %type <array> arrayprefix
+@@ -101,10 +105,39 @@ extern bool treesource_error;
+ %%
+
+ sourcefile:
+- DT_V1 ';' memreserves devicetree
++ basesource
++ | pluginsource
++ ;
++
++basesource:
++ DT_V1 ';' plugindecl memreserves devicetree
++ {
++ source_is_plugin = $3;
++ if (source_is_plugin)
++ deprecated_plugin_syntax_warning = true;
++ the_boot_info = build_boot_info($4, $5,
++ guess_boot_cpuid($5));
++ }
++ ;
++
++plugindecl:
++ /* empty */
++ {
++ $$ = false;
++ }
++ | DT_PLUGIN ';'
++ {
++ $$ = true;
++ }
++ ;
++
++pluginsource:
++ DT_V1 DT_PLUGIN ';' memreserves devicetree
+ {
+- the_boot_info = build_boot_info($3, $4,
+- guess_boot_cpuid($4));
++ source_is_plugin = true;
++ deprecated_plugin_syntax_warning = false;
++ the_boot_info = build_boot_info($4, $5,
++ guess_boot_cpuid($5));
+ }
+ ;
+
+@@ -144,10 +177,14 @@ devicetree:
+ {
+ struct node *target = get_node_by_ref($1, $2);
+
+- if (target)
++ if (target) {
+ merge_nodes(target, $3);
+- else
+- ERROR(&@2, "Label or path %s not found", $2);
++ } else {
++ if (symbol_fixup_support)
++ add_orphan_node($1, $3, $2);
++ else
++ ERROR(&@2, "Label or path %s not found", $2);
++ }
+ $$ = $1;
+ }
+ | devicetree DT_DEL_NODE DT_REF ';'
+@@ -162,6 +199,11 @@ devicetree:
+
+ $$ = $1;
+ }
++ | /* empty */
++ {
++ /* build empty node */
++ $$ = name_node(build_node(NULL, NULL), "");
++ }
+ ;
+
+ nodedef:
+diff --git a/dtc.c b/dtc.c
+index 8c4add6..ee37be9 100644
+--- a/dtc.c
++++ b/dtc.c
+@@ -18,6 +18,8 @@
+ * USA
+ */
+
++#include <sys/stat.h>
++
+ #include "dtc.h"
+ #include "srcpos.h"
+
+@@ -29,6 +31,8 @@ int reservenum; /* Number of memory reservation slots */
+ int minsize; /* Minimum blob size */
+ int padsize; /* Additional padding to blob */
+ int phandle_format = PHANDLE_BOTH; /* Use linux,phandle or phandle properties */
++int symbol_fixup_support;
++int auto_label_aliases;
+
+ static void fill_fullpaths(struct node *tree, const char *prefix)
+ {
+@@ -51,7 +55,7 @@ static void fill_fullpaths(struct node *tree, const char *prefix)
+ #define FDT_VERSION(version) _FDT_VERSION(version)
+ #define _FDT_VERSION(version) #version
+ static const char usage_synopsis[] = "dtc [options] <input file>";
+-static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:hv";
++static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:@Ahv";
+ static struct option const usage_long_opts[] = {
+ {"quiet", no_argument, NULL, 'q'},
+ {"in-format", a_argument, NULL, 'I'},
+@@ -69,6 +73,8 @@ static struct option const usage_long_opts[] = {
+ {"phandle", a_argument, NULL, 'H'},
+ {"warning", a_argument, NULL, 'W'},
+ {"error", a_argument, NULL, 'E'},
++ {"symbols", no_argument, NULL, '@'},
++ {"auto-alias", no_argument, NULL, 'A'},
+ {"help", no_argument, NULL, 'h'},
+ {"version", no_argument, NULL, 'v'},
+ {NULL, no_argument, NULL, 0x0},
+@@ -99,16 +105,63 @@ static const char * const usage_opts_help[] = {
+ "\t\tboth - Both \"linux,phandle\" and \"phandle\" properties",
+ "\n\tEnable/disable warnings (prefix with \"no-\")",
+ "\n\tEnable/disable errors (prefix with \"no-\")",
++ "\n\tEnable symbols/fixup support",
++ "\n\tEnable auto-alias of labels",
+ "\n\tPrint this help and exit",
+ "\n\tPrint version and exit",
+ NULL,
+ };
+
++static const char *guess_type_by_name(const char *fname, const char *fallback)
++{
++ const char *s;
++
++ s = strrchr(fname, '.');
++ if (s == NULL)
++ return fallback;
++ if (!strcasecmp(s, ".dts"))
++ return "dts";
++ if (!strcasecmp(s, ".dtb"))
++ return "dtb";
++ return fallback;
++}
++
++static const char *guess_input_format(const char *fname, const char *fallback)
++{
++ struct stat statbuf;
++ uint32_t magic;
++ FILE *f;
++
++ if (stat(fname, &statbuf) != 0)
++ return fallback;
++
++ if (S_ISDIR(statbuf.st_mode))
++ return "fs";
++
++ if (!S_ISREG(statbuf.st_mode))
++ return fallback;
++
++ f = fopen(fname, "r");
++ if (f == NULL)
++ return fallback;
++ if (fread(&magic, 4, 1, f) != 1) {
++ fclose(f);
++ return fallback;
++ }
++ fclose(f);
++
++ magic = fdt32_to_cpu(magic);
++ if (magic == FDT_MAGIC)
++ return "dtb";
++
++ return guess_type_by_name(fname, fallback);
++}
++
+ int main(int argc, char *argv[])
+ {
+ struct boot_info *bi;
+- const char *inform = "dts";
+- const char *outform = "dts";
++ const char *inform = NULL;
++ const char *outform = NULL;
+ const char *outname = "-";
+ const char *depname = NULL;
+ bool force = false, sort = false;
+@@ -186,7 +239,12 @@ int main(int argc, char *argv[])
+ case 'E':
+ parse_checks_option(false, true, optarg);
+ break;
+-
++ case '@':
++ symbol_fixup_support = 1;
++ break;
++ case 'A':
++ auto_label_aliases = 1;
++ break;
+ case 'h':
+ usage(NULL);
+ default:
+@@ -213,6 +271,17 @@ int main(int argc, char *argv[])
+ fprintf(depfile, "%s:", outname);
+ }
+
++ if (inform == NULL)
++ inform = guess_input_format(arg, "dts");
++ if (outform == NULL) {
++ outform = guess_type_by_name(outname, NULL);
++ if (outform == NULL) {
++ if (streq(inform, "dts"))
++ outform = "dtb";
++ else
++ outform = "dts";
++ }
++ }
+ if (streq(inform, "dts"))
+ bi = dt_from_source(arg);
+ else if (streq(inform, "fs"))
+@@ -236,6 +305,12 @@ int main(int argc, char *argv[])
+ if (sort)
+ sort_tree(bi);
+
++ if (symbol_fixup_support || auto_label_aliases)
++ generate_label_node(bi->dt, bi->dt);
++
++ if (symbol_fixup_support)
++ generate_fixups_node(bi->dt, bi->dt);
++
+ if (streq(outname, "-")) {
+ outf = stdout;
+ } else {
+diff --git a/dtc.h b/dtc.h
+index 56212c8..d025111 100644
+--- a/dtc.h
++++ b/dtc.h
+@@ -20,7 +20,7 @@
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+-
++#define _GNU_SOURCE
+ #include <stdio.h>
+ #include <string.h>
+ #include <stdlib.h>
+@@ -54,6 +54,14 @@ extern int reservenum; /* Number of memory reservation slots */
+ extern int minsize; /* Minimum blob size */
+ extern int padsize; /* Additional padding to blob */
+ extern int phandle_format; /* Use linux,phandle or phandle properties */
++extern int symbol_fixup_support;/* enable symbols & fixup support */
++extern int auto_label_aliases; /* auto generate labels -> aliases */
++
++/*
++ * Tree source globals
++ */
++extern bool source_is_plugin;
++extern bool deprecated_plugin_syntax_warning;
+
+ #define PHANDLE_LEGACY 0x1
+ #define PHANDLE_EPAPR 0x2
+@@ -194,6 +202,7 @@ struct node *build_node_delete(void);
+ struct node *name_node(struct node *node, char *name);
+ struct node *chain_node(struct node *first, struct node *list);
+ struct node *merge_nodes(struct node *old_node, struct node *new_node);
++void add_orphan_node(struct node *old_node, struct node *new_node, char *ref);
+
+ void add_property(struct node *node, struct property *prop);
+ void delete_property_by_name(struct node *node, char *name);
+@@ -244,6 +253,8 @@ struct boot_info {
+ struct boot_info *build_boot_info(struct reserve_info *reservelist,
+ struct node *tree, uint32_t boot_cpuid_phys);
+ void sort_tree(struct boot_info *bi);
++void generate_label_node(struct node *node, struct node *dt);
++void generate_fixups_node(struct node *node, struct node *dt);
+
+ /* Checks */
+
+diff --git a/livetree.c b/livetree.c
+index e229b84..1ef9fc4 100644
+--- a/livetree.c
++++ b/livetree.c
+@@ -216,6 +216,34 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
+ return old_node;
+ }
+
++void add_orphan_node(struct node *dt, struct node *new_node, char *ref)
++{
++ static unsigned int next_orphan_fragment = 0;
++ struct node *ovl = xmalloc(sizeof(*ovl));
++ struct property *p;
++ struct data d = empty_data;
++ char *name;
++ int ret;
++
++ memset(ovl, 0, sizeof(*ovl));
++
++ d = data_add_marker(d, REF_PHANDLE, ref);
++ d = data_append_integer(d, 0xffffffff, 32);
++
++ p = build_property("target", d);
++ add_property(ovl, p);
++
++ ret = asprintf(&name, "fragment@%u",
++ next_orphan_fragment++);
++ if (ret == -1)
++ die("asprintf() failed\n");
++ name_node(ovl, name);
++ name_node(new_node, "__overlay__");
++
++ add_child(dt, ovl);
++ add_child(ovl, new_node);
++}
++
+ struct node *chain_node(struct node *first, struct node *list)
+ {
+ assert(first->next_sibling == NULL);
+@@ -709,3 +737,177 @@ void sort_tree(struct boot_info *bi)
+ sort_reserve_entries(bi);
+ sort_node(bi->dt);
+ }
++
++void generate_label_node(struct node *node, struct node *dt)
++{
++ struct node *c, *an;
++ struct property *p;
++ struct label *l;
++ int has_label;
++ char *gen_node_name;
++
++ if (auto_label_aliases)
++ gen_node_name = "aliases";
++ else
++ gen_node_name = "__symbols__";
++
++ /* Make sure the label isn't already there */
++ has_label = 0;
++ for_each_label(node->labels, l) {
++ has_label = 1;
++ break;
++ }
++
++ if (has_label) {
++
++ /* an is the aliases/__symbols__ node */
++ an = get_subnode(dt, gen_node_name);
++ /* if no node exists, create it */
++ if (!an) {
++ an = build_node(NULL, NULL);
++ name_node(an, gen_node_name);
++ add_child(dt, an);
++ }
++
++ /* now add the label in the node */
++ for_each_label(node->labels, l) {
++ /* check whether the label already exists */
++ p = get_property(an, l->label);
++ if (p) {
++ fprintf(stderr, "WARNING: label %s already"
++ " exists in /%s", l->label,
++ gen_node_name);
++ continue;
++ }
++
++ /* insert it */
++ p = build_property(l->label,
++ data_copy_escape_string(node->fullpath,
++ strlen(node->fullpath)));
++ add_property(an, p);
++ }
++
++ /* force allocation of a phandle for this node */
++ if (symbol_fixup_support)
++ (void)get_node_phandle(dt, node);
++ }
++
++ for_each_child(node, c)
++ generate_label_node(c, dt);
++}
++
++static void add_fixup_entry(struct node *dt, struct node *node,
++ struct property *prop, struct marker *m)
++{
++ struct node *fn; /* local fixup node */
++ struct property *p;
++ char *fixups_name = "__fixups__";
++ struct data d;
++ char *entry;
++ int ret;
++
++ /* fn is the node we're putting entries in */
++ fn = get_subnode(dt, fixups_name);
++ /* if no node exists, create it */
++ if (!fn) {
++ fn = build_node(NULL, NULL);
++ name_node(fn, fixups_name);
++ add_child(dt, fn);
++ }
++
++ ret = asprintf(&entry, "%s:%s:%u",
++ node->fullpath, prop->name, m->offset);
++ if (ret == -1)
++ die("asprintf() failed\n");
++
++ p = get_property(fn, m->ref);
++ d = data_append_data(p ? p->val : empty_data, entry, strlen(entry) + 1);
++ if (!p)
++ add_property(fn, build_property(m->ref, d));
++ else
++ p->val = d;
++}
++
++static void add_local_fixup_entry(struct node *dt, struct node *node,
++ struct property *prop, struct marker *m,
++ struct node *refnode)
++{
++ struct node *lfn, *wn, *nwn; /* local fixup node, walk node, new */
++ struct property *p;
++ struct data d;
++ char *local_fixups_name = "__local_fixups__";
++ char *s, *e, *comp;
++ int len;
++
++ /* fn is the node we're putting entries in */
++ lfn = get_subnode(dt, local_fixups_name);
++ /* if no node exists, create it */
++ if (!lfn) {
++ lfn = build_node(NULL, NULL);
++ name_node(lfn, local_fixups_name);
++ add_child(dt, lfn);
++ }
++
++ /* walk the path components creating nodes if they don't exist */
++ comp = NULL;
++ /* start skipping the first / */
++ s = node->fullpath + 1;
++ wn = lfn;
++ while (*s) {
++ /* retrieve path component */
++ e = strchr(s, '/');
++ if (e == NULL)
++ e = s + strlen(s);
++ len = e - s;
++ comp = xrealloc(comp, len + 1);
++ memcpy(comp, s, len);
++ comp[len] = '\0';
++
++ /* if no node exists, create it */
++ nwn = get_subnode(wn, comp);
++ if (!nwn) {
++ nwn = build_node(NULL, NULL);
++ name_node(nwn, strdup(comp));
++ add_child(wn, nwn);
++ }
++ wn = nwn;
++
++ /* last path component */
++ if (!*e)
++ break;
++
++ /* next path component */
++ s = e + 1;
++ }
++ free(comp);
++
++ p = get_property(wn, prop->name);
++ d = data_append_cell(p ? p->val : empty_data, (cell_t)m->offset);
++ if (!p)
++ add_property(wn, build_property(prop->name, d));
++ else
++ p->val = d;
++}
++
++void generate_fixups_node(struct node *node, struct node *dt)
++{
++ struct node *c;
++ struct property *prop;
++ struct marker *m;
++ struct node *refnode;
++
++ for_each_property(node, prop) {
++ m = prop->val.markers;
++ for_each_marker_of_type(m, REF_PHANDLE) {
++ refnode = get_node_by_ref(dt, m->ref);
++ if (!refnode)
++ add_fixup_entry(dt, node, prop, m);
++ else
++ add_local_fixup_entry(dt, node, prop, m,
++ refnode);
++ }
++ }
++
++ for_each_child(node, c)
++ generate_fixups_node(c, dt);
++}
+diff --git a/treesource.c b/treesource.c
+index a55d1d1..e1d6657 100644
+--- a/treesource.c
++++ b/treesource.c
+@@ -28,6 +28,9 @@ extern YYLTYPE yylloc;
+ struct boot_info *the_boot_info;
+ bool treesource_error;
+
++bool source_is_plugin;
++bool deprecated_plugin_syntax_warning;
++
+ struct boot_info *dt_from_source(const char *fname)
+ {
+ the_boot_info = NULL;
+diff --git a/util.c b/util.c
+index 9d65226..cbb945b 100644
+--- a/util.c
++++ b/util.c
+@@ -349,7 +349,6 @@ int utilfdt_decode_type(const char *fmt, int *type, int *size)
+ void utilfdt_print_data(const char *data, int len)
+ {
+ int i;
+- const char *p = data;
+ const char *s;
+
+ /* no data, don't print */
+@@ -376,6 +375,7 @@ void utilfdt_print_data(const char *data, int len)
+ i < (len - 1) ? " " : "");
+ printf(">");
+ } else {
++ const unsigned char *p = (const unsigned char *)data;
+ printf(" = [");
+ for (i = 0; i < len; i++)
+ printf("%02x%s", *p++, i < len - 1 ? " " : "");
+--
+2.7.0
+
diff --git a/package/kernel/lantiq/ltq-adsl-fw/Makefile b/package/kernel/lantiq/ltq-adsl-fw/Makefile
index 53d223b609..a26e595023 100644
--- a/package/kernel/lantiq/ltq-adsl-fw/Makefile
+++ b/package/kernel/lantiq/ltq-adsl-fw/Makefile
@@ -17,6 +17,8 @@ PKG_SOURCE_URL:=http://mirror2.openwrt.org/sources/
PKG_MD5SUM:=4700a36b66b955b4c5544227267356f4
PKG_MAINTAINER:=John Crispin <blogic@openwrt.org>
+PKG_FLAGS:=nonshared
+
include $(INCLUDE_DIR)/package.mk
define Package/kmod-ltq-adsl-fw-template
diff --git a/package/kernel/lantiq/ltq-vdsl-mei/Makefile b/package/kernel/lantiq/ltq-vdsl-mei/Makefile
index e0617aeb57..6c7cca0c1d 100644
--- a/package/kernel/lantiq/ltq-vdsl-mei/Makefile
+++ b/package/kernel/lantiq/ltq-vdsl-mei/Makefile
@@ -17,6 +17,7 @@ PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(PKG_BASE_NAME)-$(PKG_VERSION)
PKG_SOURCE_URL:=http://mirror2.openwrt.org/sources
PKG_MD5SUM:=78bf61dbc3421123c6716b874a930759
PKG_FIXUP:=autoreconf
+PKG_FLAGS:=nonshared
PKG_MAINTAINER:=John Crispin <blogic@openwrt.org>
PKG_USE_MIPS16:=0
diff --git a/package/kernel/mac80211/Makefile b/package/kernel/mac80211/Makefile
index 2ab4b7b81c..72184f61c8 100644
--- a/package/kernel/mac80211/Makefile
+++ b/package/kernel/mac80211/Makefile
@@ -10,11 +10,11 @@ include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=mac80211
-PKG_VERSION:=2016-01-10
+PKG_VERSION:=2016-05-12
PKG_RELEASE:=1
PKG_SOURCE_URL:=http://mirror2.openwrt.org/sources
PKG_BACKPORT_VERSION:=
-PKG_MD5SUM:=be5fae2e8d6f7490f9b073374fb895ba
+PKG_MD5SUM:=2142cf38509896dca108624e7c193611
PKG_SOURCE:=compat-wireless-$(PKG_VERSION)$(PKG_BACKPORT_VERSION).tar.bz2
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/compat-wireless-$(PKG_VERSION)
@@ -53,6 +53,7 @@ PKG_CONFIG_DEPENDS:= \
$(patsubst %,CONFIG_PACKAGE_kmod-%,$(PKG_DRIVERS)) \
CONFIG_PACKAGE_MAC80211_DEBUGFS \
CONFIG_PACKAGE_MAC80211_MESH \
+ CONFIG_PACKAGE_MAC80211_TRACING \
CONFIG_PACKAGE_ATH_DEBUG \
CONFIG_PACKAGE_ATH_DFS \
CONFIG_PACKAGE_B43_DEBUG \
@@ -64,7 +65,12 @@ PKG_CONFIG_DEPENDS:= \
CONFIG_PACKAGE_B43_BUSES_BCMA_AND_SSB \
CONFIG_PACKAGE_B43_BUSES_BCMA \
CONFIG_PACKAGE_B43_BUSES_SSB \
+ CONFIG_PACKAGE_BRCM80211_DEBUG \
+ CONFIG_PACKAGE_IWLWIFI_DEBUG \
+ CONFIG_PACKAGE_IWLWIFI_DEBUGFS \
CONFIG_PACKAGE_RTLWIFI_DEBUG \
+ CONFIG_ATH9K_SUPPORT_PCOEM \
+ CONFIG_ATH9K_TX99 \
CONFIG_ATH_USER_REGD \
include $(INCLUDE_DIR)/package.mk
@@ -884,7 +890,7 @@ endef
define KernelPackage/lib80211
$(call KernelPackage/mac80211/Default)
TITLE:=802.11 Networking stack
- DEPENDS:=+kmod-cfg80211
+ DEPENDS:=+kmod-cfg80211 +kmod-crypto-hash
FILES:= \
$(PKG_BUILD_DIR)/net/wireless/lib80211.ko \
$(PKG_BUILD_DIR)/net/wireless/lib80211_crypt_wep.ko \
diff --git a/package/kernel/mac80211/patches/004-backports-add-skb_free_frag.patch b/package/kernel/mac80211/patches/004-backports-add-skb_free_frag.patch
deleted file mode 100644
index 8ac65c22cf..0000000000
--- a/package/kernel/mac80211/patches/004-backports-add-skb_free_frag.patch
+++ /dev/null
@@ -1,21 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Thu, 28 Jan 2016 15:16:35 +0100
-Subject: [PATCH] backports: add skb_free_frag()
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/backport-include/linux/skbuff.h
-+++ b/backport-include/linux/skbuff.h
-@@ -300,4 +300,11 @@ int skb_ensure_writable(struct sk_buff *
-
- #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0) */
-
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,2,0)
-+static inline void skb_free_frag(void *data)
-+{
-+ put_page(virt_to_head_page(data));
-+}
-+#endif
-+
- #endif /* __BACKPORT_SKBUFF_H */
diff --git a/package/kernel/mac80211/patches/004-header-backport-GENL_UNS_ADMIN_PERM.patch b/package/kernel/mac80211/patches/004-header-backport-GENL_UNS_ADMIN_PERM.patch
new file mode 100644
index 0000000000..38d655fe05
--- /dev/null
+++ b/package/kernel/mac80211/patches/004-header-backport-GENL_UNS_ADMIN_PERM.patch
@@ -0,0 +1,21 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sat, 14 May 2016 16:39:35 +0200
+Subject: [PATCH] header: backport GENL_UNS_ADMIN_PERM
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ create mode 100644 backport-include/uapi/linux/genetlink.h
+
+--- /dev/null
++++ b/backport-include/uapi/linux/genetlink.h
+@@ -0,0 +1,10 @@
++#ifndef __COMPAT_UAPI_LINUX_GENETLINK_H
++#define __COMPAT_UAPI_LINUX_GENETLINK_H
++
++#include_next <uapi/linux/genetlink.h>
++
++#ifndef GENL_UNS_ADMIN_PERM
++#define GENL_UNS_ADMIN_PERM GENL_ADMIN_PERM
++#endif
++
++#endif
diff --git a/package/kernel/mac80211/patches/005-backports-add-napi_alloc_frag.patch b/package/kernel/mac80211/patches/005-backports-add-napi_alloc_frag.patch
deleted file mode 100644
index 11d26b1b29..0000000000
--- a/package/kernel/mac80211/patches/005-backports-add-napi_alloc_frag.patch
+++ /dev/null
@@ -1,20 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Thu, 28 Jan 2016 15:19:22 +0100
-Subject: [PATCH] backports: add napi_alloc_frag
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/backport-include/linux/netdevice.h
-+++ b/backport-include/linux/netdevice.h
-@@ -232,6 +232,10 @@ static inline void backport_unregister_n
- #define unregister_netdevice_many LINUX_BACKPORT(unregister_netdevice_many)
- #endif
-
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
-+#define napi_alloc_frag netdev_alloc_frag
-+#endif
-+
- /*
- * Complicated way of saying: We only backport netdev_rss_key stuff on kernels
- * that either already have net_get_random_once() (>= 3.13) or where we've been
diff --git a/package/kernel/mac80211/patches/005-header-backport-nla_put_u64_64bit-and-nla_put_64bit.patch b/package/kernel/mac80211/patches/005-header-backport-nla_put_u64_64bit-and-nla_put_64bit.patch
new file mode 100644
index 0000000000..e20d87a7fd
--- /dev/null
+++ b/package/kernel/mac80211/patches/005-header-backport-nla_put_u64_64bit-and-nla_put_64bit.patch
@@ -0,0 +1,158 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sat, 14 May 2016 16:40:16 +0200
+Subject: [PATCH] header: backport nla_put_u64_64bit and nla_put_64bit
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/backport-include/net/netlink.h
++++ b/backport-include/net/netlink.h
+@@ -189,4 +189,148 @@ static inline __le64 nla_get_le64(const
+ }
+ #endif /* < 4.4 */
+
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0)
++
++/**
++ * nla_need_padding_for_64bit - test 64-bit alignment of the next attribute
++ * @skb: socket buffer the message is stored in
++ *
++ * Return true if padding is needed to align the next attribute (nla_data()) to
++ * a 64-bit aligned area.
++ */
++static inline bool nla_need_padding_for_64bit(struct sk_buff *skb)
++{
++#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
++ /* The nlattr header is 4 bytes in size, that's why we test
++ * if the skb->data _is_ aligned. A NOP attribute, plus
++ * nlattr header for next attribute, will make nla_data()
++ * 8-byte aligned.
++ */
++ if (IS_ALIGNED((unsigned long)skb_tail_pointer(skb), 8))
++ return true;
++#endif
++ return false;
++}
++
++/**
++ * nla_align_64bit - 64-bit align the nla_data() of next attribute
++ * @skb: socket buffer the message is stored in
++ * @padattr: attribute type for the padding
++ *
++ * Conditionally emit a padding netlink attribute in order to make
++ * the next attribute we emit have a 64-bit aligned nla_data() area.
++ * This will only be done in architectures which do not have
++ * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS defined.
++ *
++ * Returns zero on success or a negative error code.
++ */
++static inline int nla_align_64bit(struct sk_buff *skb, int padattr)
++{
++ if (nla_need_padding_for_64bit(skb) &&
++ !nla_reserve(skb, padattr, 0))
++ return -EMSGSIZE;
++
++ return 0;
++}
++
++/**
++ * __nla_reserve_64bit - reserve room for attribute on the skb and align it
++ * @skb: socket buffer to reserve room on
++ * @attrtype: attribute type
++ * @attrlen: length of attribute payload
++ * @padattr: attribute type for the padding
++ *
++ * Adds a netlink attribute header to a socket buffer and reserves
++ * room for the payload but does not copy it. It also ensure that this
++ * attribute will have a 64-bit aligned nla_data() area.
++ *
++ * The caller is responsible to ensure that the skb provides enough
++ * tailroom for the attribute header and payload.
++ */
++static inline struct nlattr *__nla_reserve_64bit(struct sk_buff *skb, int attrtype,
++ int attrlen, int padattr)
++{
++ if (nla_need_padding_for_64bit(skb))
++ nla_align_64bit(skb, padattr);
++
++ return __nla_reserve(skb, attrtype, attrlen);
++}
++
++/**
++ * __nla_put_64bit - Add a netlink attribute to a socket buffer and align it
++ * @skb: socket buffer to add attribute to
++ * @attrtype: attribute type
++ * @attrlen: length of attribute payload
++ * @data: head of attribute payload
++ * @padattr: attribute type for the padding
++ *
++ * The caller is responsible to ensure that the skb provides enough
++ * tailroom for the attribute header and payload.
++ */
++static inline void __nla_put_64bit(struct sk_buff *skb, int attrtype, int attrlen,
++ const void *data, int padattr)
++{
++ struct nlattr *nla;
++
++ nla = __nla_reserve_64bit(skb, attrtype, attrlen, padattr);
++ memcpy(nla_data(nla), data, attrlen);
++}
++
++/**
++ * nla_total_size_64bit - total length of attribute including padding
++ * @payload: length of payload
++ */
++static inline int nla_total_size_64bit(int payload)
++{
++ return NLA_ALIGN(nla_attr_size(payload))
++#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
++ + NLA_ALIGN(nla_attr_size(0))
++#endif
++ ;
++}
++
++/**
++ * nla_put_64bit - Add a netlink attribute to a socket buffer and align it
++ * @skb: socket buffer to add attribute to
++ * @attrtype: attribute type
++ * @attrlen: length of attribute payload
++ * @data: head of attribute payload
++ * @padattr: attribute type for the padding
++ *
++ * Returns -EMSGSIZE if the tailroom of the skb is insufficient to store
++ * the attribute header and payload.
++ */
++static inline int nla_put_64bit(struct sk_buff *skb, int attrtype, int attrlen,
++ const void *data, int padattr)
++{
++ size_t len;
++
++ if (nla_need_padding_for_64bit(skb))
++ len = nla_total_size_64bit(attrlen);
++ else
++ len = nla_total_size(attrlen);
++ if (unlikely(skb_tailroom(skb) < len))
++ return -EMSGSIZE;
++
++ __nla_put_64bit(skb, attrtype, attrlen, data, padattr);
++ return 0;
++}
++
++/**
++ * nla_put_u64_64bit - Add a u64 netlink attribute to a skb and align it
++ * @skb: socket buffer to add attribute to
++ * @attrtype: attribute type
++ * @value: numeric value
++ * @padattr: attribute type for the padding
++ */
++static inline int nla_put_u64_64bit(struct sk_buff *skb, int attrtype,
++ u64 value, int padattr)
++{
++ return nla_put_64bit(skb, attrtype, sizeof(u64), &value, padattr);
++}
++
++
++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0) */
++
+ #endif /* __BACKPORT_NET_NETLINK_H */
diff --git a/package/kernel/mac80211/patches/006-compat-bump-rhashtable-backport-version-due-to-API-c.patch b/package/kernel/mac80211/patches/006-compat-bump-rhashtable-backport-version-due-to-API-c.patch
new file mode 100644
index 0000000000..1fdad3c633
--- /dev/null
+++ b/package/kernel/mac80211/patches/006-compat-bump-rhashtable-backport-version-due-to-API-c.patch
@@ -0,0 +1,18 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sat, 14 May 2016 16:44:57 +0200
+Subject: [PATCH] compat: bump rhashtable backport version due to API changes
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/compat/Kconfig
++++ b/compat/Kconfig
+@@ -139,7 +139,7 @@ config BPAUTO_BUILD_WANT_DEV_COREDUMP
+ config BPAUTO_RHASHTABLE
+ bool
+ # current API of rhashtable was introduced in version 4.1
+- depends on KERNEL_4_1
++ depends on KERNEL_4_7
+ # not very nice - but better than always having it
+ default y if MAC80211
+ #h-file linux/rhashtable.h
diff --git a/package/kernel/mac80211/patches/007-fix_duplicate_skcipher_backport.patch b/package/kernel/mac80211/patches/007-fix_duplicate_skcipher_backport.patch
new file mode 100644
index 0000000000..38b31795a4
--- /dev/null
+++ b/package/kernel/mac80211/patches/007-fix_duplicate_skcipher_backport.patch
@@ -0,0 +1,11 @@
+--- a/compat/Makefile
++++ b/compat/Makefile
+@@ -35,8 +35,6 @@ compat-$(CPTCFG_KERNEL_4_6) += backport-
+
+ compat-$(CPTCFG_BPAUTO_BUILD_CRYPTO_CCM) += crypto-ccm.o
+ compat-$(CPTCFG_BPAUTO_CRYPTO_SKCIPHER) += crypto-skcipher.o
+-skcipher-objs += crypto-skcipher.o
+-obj-$(CPTCFG_BPAUTO_CRYPTO_SKCIPHER) += skcipher.o
+ compat-$(CPTCFG_BPAUTO_BUILD_WANT_DEV_COREDUMP) += drivers-base-devcoredump.o
+ compat-$(CPTCFG_BPAUTO_RHASHTABLE) += lib-rhashtable.o
+ cordic-objs += lib-cordic.o
diff --git a/package/kernel/mac80211/patches/060-no_local_ssb_bcma.patch b/package/kernel/mac80211/patches/060-no_local_ssb_bcma.patch
index fd1e1cff30..e9a140c26f 100644
--- a/package/kernel/mac80211/patches/060-no_local_ssb_bcma.patch
+++ b/package/kernel/mac80211/patches/060-no_local_ssb_bcma.patch
@@ -1,6 +1,6 @@
--- a/.local-symbols
+++ b/.local-symbols
-@@ -476,44 +476,6 @@ USB_IPHETH=
+@@ -481,45 +481,6 @@ USB_IPHETH=
USB_SIERRA_NET=
USB_VL600=
USB_NET_CH9200=
@@ -37,6 +37,7 @@
-BCMA_DRIVER_PCI=
-BCMA_DRIVER_PCI_HOSTMODE=
-BCMA_DRIVER_MIPS=
+-BCMA_PFLASH=
-BCMA_SFLASH=
-BCMA_NFLASH=
-BCMA_DRIVER_GMAC_CMN=
@@ -56,7 +57,7 @@
return (bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev);
#else
return bus->chipco.dev;
-@@ -4903,7 +4903,7 @@ static int b43_wireless_core_init(struct
+@@ -4901,7 +4901,7 @@ static int b43_wireless_core_init(struct
}
if (sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW)
hf |= B43_HF_DSCRQ; /* Disable slowclock requests from ucode. */
diff --git a/package/kernel/mac80211/patches/080-disable_clk_backport.patch b/package/kernel/mac80211/patches/080-disable_clk_backport.patch
deleted file mode 100644
index 3765591ebb..0000000000
--- a/package/kernel/mac80211/patches/080-disable_clk_backport.patch
+++ /dev/null
@@ -1,20 +0,0 @@
---- a/compat/compat-3.6.c
-+++ b/compat/compat-3.6.c
-@@ -147,17 +147,3 @@ int sg_alloc_table_from_pages(struct sg_
- return 0;
- }
- EXPORT_SYMBOL_GPL(sg_alloc_table_from_pages);
--
--/* whoopsie ! */
--#ifndef CONFIG_COMMON_CLK
--int clk_enable(struct clk *clk)
--{
-- return 0;
--}
--EXPORT_SYMBOL_GPL(clk_enable);
--
--void clk_disable(struct clk *clk)
--{
--}
--EXPORT_SYMBOL_GPL(clk_disable);
--#endif
diff --git a/package/kernel/mac80211/patches/100-remove-cryptoapi-dependencies.patch b/package/kernel/mac80211/patches/100-remove-cryptoapi-dependencies.patch
index 02f46c778d..b65b0bd00e 100644
--- a/package/kernel/mac80211/patches/100-remove-cryptoapi-dependencies.patch
+++ b/package/kernel/mac80211/patches/100-remove-cryptoapi-dependencies.patch
@@ -34,12 +34,9 @@
#include "aes_ccm.h"
-void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
-- u8 *data, size_t data_len, u8 *mic,
-- size_t mic_len)
+static void aes_ccm_prepare(struct crypto_cipher *tfm, u8 *b_0, u8 *aad, u8 *s_0,
+ u8 *a, u8 *b)
- {
-- struct scatterlist sg[3];
++{
+ int i;
+
+ crypto_cipher_encrypt_one(tfm, b, b_0);
@@ -54,55 +51,56 @@
+ for (i = 0; i < AES_BLOCK_SIZE; i++)
+ aad[i] ^= b[i];
+ crypto_cipher_encrypt_one(tfm, a, aad);
-
-- char aead_req_data[sizeof(struct aead_request) +
-- crypto_aead_reqsize(tfm)]
-- __aligned(__alignof__(struct aead_request));
-- struct aead_request *aead_req = (void *) aead_req_data;
++
+ /* Mask out bits from auth-only-b_0 */
+ b_0[0] &= 0x07;
-
-- memset(aead_req, 0, sizeof(aead_req_data));
++
+ /* S_0 is used to encrypt T (= MIC) */
+ b_0[14] = 0;
+ b_0[15] = 0;
+ crypto_cipher_encrypt_one(tfm, s_0, b_0);
+}
-
-- sg_init_table(sg, 3);
-- sg_set_buf(&sg[0], &aad[2], be16_to_cpup((__be16 *)aad));
-- sg_set_buf(&sg[1], data, data_len);
-- sg_set_buf(&sg[2], mic, mic_len);
-
-- aead_request_set_tfm(aead_req, tfm);
-- aead_request_set_crypt(aead_req, sg, sg, data_len, b_0);
-- aead_request_set_ad(aead_req, sg[0].length);
++
++
+void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *b_0, u8 *aad,
-+ u8 *data, size_t data_len, u8 *mic,
-+ size_t mic_len)
-+{
+ u8 *data, size_t data_len, u8 *mic,
+ size_t mic_len)
+ {
+- struct scatterlist sg[3];
+ int i, j, last_len, num_blocks;
+ u8 b[AES_BLOCK_SIZE];
+ u8 s_0[AES_BLOCK_SIZE];
+ u8 e[AES_BLOCK_SIZE];
+ u8 *pos, *cpos;
-+
+
+- char aead_req_data[sizeof(struct aead_request) +
+- crypto_aead_reqsize(tfm)]
+- __aligned(__alignof__(struct aead_request));
+- struct aead_request *aead_req = (void *) aead_req_data;
+ num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE);
+ last_len = data_len % AES_BLOCK_SIZE;
+ aes_ccm_prepare(tfm, b_0, aad, s_0, b, b);
-+
+
+- memset(aead_req, 0, sizeof(aead_req_data));
+ /* Process payload blocks */
+ pos = data;
+ cpos = data;
+ for (j = 1; j <= num_blocks; j++) {
+ int blen = (j == num_blocks && last_len) ?
+ last_len : AES_BLOCK_SIZE;
-+
+
+- sg_init_table(sg, 3);
+- sg_set_buf(&sg[0], &aad[2], be16_to_cpup((__be16 *)aad));
+- sg_set_buf(&sg[1], data, data_len);
+- sg_set_buf(&sg[2], mic, mic_len);
+ /* Authentication followed by encryption */
+ for (i = 0; i < blen; i++)
+ b[i] ^= pos[i];
+ crypto_cipher_encrypt_one(tfm, b, b);
-+
+
+- aead_request_set_tfm(aead_req, tfm);
+- aead_request_set_crypt(aead_req, sg, sg, data_len, b_0);
+- aead_request_set_ad(aead_req, sg[0].length);
+ b_0[14] = (j >> 8) & 0xff;
+ b_0[15] = j & 0xff;
+ crypto_cipher_encrypt_one(tfm, e, b_0);
@@ -125,37 +123,30 @@
- crypto_aead_reqsize(tfm)]
- __aligned(__alignof__(struct aead_request));
- struct aead_request *aead_req = (void *) aead_req_data;
--
-- if (data_len == 0)
-- return -EINVAL;
--
-- memset(aead_req, 0, sizeof(aead_req_data));
--
-- sg_init_table(sg, 3);
-- sg_set_buf(&sg[0], &aad[2], be16_to_cpup((__be16 *)aad));
-- sg_set_buf(&sg[1], data, data_len);
-- sg_set_buf(&sg[2], mic, mic_len);
--
-- aead_request_set_tfm(aead_req, tfm);
-- aead_request_set_crypt(aead_req, sg, sg, data_len + mic_len, b_0);
-- aead_request_set_ad(aead_req, sg[0].length);
+ int i, j, last_len, num_blocks;
+ u8 *pos, *cpos;
+ u8 a[AES_BLOCK_SIZE];
+ u8 b[AES_BLOCK_SIZE];
+ u8 s_0[AES_BLOCK_SIZE];
-+
+
+- if (data_len == 0)
+- return -EINVAL;
+ num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE);
+ last_len = data_len % AES_BLOCK_SIZE;
+ aes_ccm_prepare(tfm, b_0, aad, s_0, a, b);
-+
+
+- memset(aead_req, 0, sizeof(aead_req_data));
+ /* Process payload blocks */
+ cpos = data;
+ pos = data;
+ for (j = 1; j <= num_blocks; j++) {
+ int blen = (j == num_blocks && last_len) ?
+ last_len : AES_BLOCK_SIZE;
-+
+
+- sg_init_table(sg, 3);
+- sg_set_buf(&sg[0], &aad[2], be16_to_cpup((__be16 *)aad));
+- sg_set_buf(&sg[1], data, data_len);
+- sg_set_buf(&sg[2], mic, mic_len);
+ /* Decryption followed by authentication */
+ b_0[14] = (j >> 8) & 0xff;
+ b_0[15] = j & 0xff;
@@ -166,7 +157,10 @@
+ }
+ crypto_cipher_encrypt_one(tfm, a, a);
+ }
-+
+
+- aead_request_set_tfm(aead_req, tfm);
+- aead_request_set_crypt(aead_req, sg, sg, data_len + mic_len, b_0);
+- aead_request_set_ad(aead_req, sg[0].length);
+ for (i = 0; i < mic_len; i++) {
+ if ((mic[i] ^ s_0[i]) != a[i])
+ return -1;
@@ -185,12 +179,12 @@
{
- struct crypto_aead *tfm;
- int err;
-+ struct crypto_cipher *tfm;
-
+-
- tfm = crypto_alloc_aead("ccm(aes)", 0, CRYPTO_ALG_ASYNC);
- if (IS_ERR(tfm))
- return tfm;
--
++ struct crypto_cipher *tfm;
+
- err = crypto_aead_setkey(tfm, key, key_len);
- if (err)
- goto free_aead;
@@ -309,7 +303,7 @@
#endif /* AES_GMAC_H */
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
-@@ -84,7 +84,7 @@ struct ieee80211_key {
+@@ -88,7 +88,7 @@ struct ieee80211_key {
* Management frames.
*/
u8 rx_pn[IEEE80211_NUM_TIDS + 1][IEEE80211_CCMP_PN_LEN];
@@ -320,7 +314,7 @@
struct {
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
-@@ -307,7 +307,8 @@ ieee80211_crypto_tkip_decrypt(struct iee
+@@ -304,7 +304,8 @@ ieee80211_crypto_tkip_decrypt(struct iee
}
@@ -330,7 +324,7 @@
{
__le16 mask_fc;
int a4_included, mgmt;
-@@ -337,14 +338,8 @@ static void ccmp_special_blocks(struct s
+@@ -334,14 +335,8 @@ static void ccmp_special_blocks(struct s
else
qos_tid = 0;
@@ -347,7 +341,7 @@
/* Nonce: Nonce Flags | A2 | PN
* Nonce Flags: Priority (b0..b3) | Management (b4) | Reserved (b5..b7)
-@@ -352,6 +347,8 @@ static void ccmp_special_blocks(struct s
+@@ -349,6 +344,8 @@ static void ccmp_special_blocks(struct s
b_0[1] = qos_tid | (mgmt << 4);
memcpy(&b_0[2], hdr->addr2, ETH_ALEN);
memcpy(&b_0[8], pn, IEEE80211_CCMP_PN_LEN);
@@ -356,7 +350,7 @@
/* AAD (extra authenticate-only data) / masked 802.11 header
* FC | A1 | A2 | A3 | SC | [A4] | [QC] */
-@@ -463,7 +460,7 @@ static int ccmp_encrypt_skb(struct ieee8
+@@ -460,7 +457,7 @@ static int ccmp_encrypt_skb(struct ieee8
return 0;
pos += IEEE80211_CCMP_HDR_LEN;
@@ -365,7 +359,7 @@
ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len,
skb_put(skb, mic_len), mic_len);
-@@ -534,7 +531,7 @@ ieee80211_crypto_ccmp_decrypt(struct iee
+@@ -537,7 +534,7 @@ ieee80211_crypto_ccmp_decrypt(struct iee
u8 aad[2 * AES_BLOCK_SIZE];
u8 b_0[AES_BLOCK_SIZE];
/* hardware didn't decrypt/verify MIC */
diff --git a/package/kernel/mac80211/patches/110-mac80211_keep_keys_on_stop_ap.patch b/package/kernel/mac80211/patches/110-mac80211_keep_keys_on_stop_ap.patch
index d1d9fbd9b1..3ca166ff45 100644
--- a/package/kernel/mac80211/patches/110-mac80211_keep_keys_on_stop_ap.patch
+++ b/package/kernel/mac80211/patches/110-mac80211_keep_keys_on_stop_ap.patch
@@ -2,7 +2,7 @@ Used for AP+STA support in OpenWrt - preserve AP mode keys across STA reconnects
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
-@@ -846,7 +846,6 @@ static int ieee80211_stop_ap(struct wiph
+@@ -850,7 +850,6 @@ static int ieee80211_stop_ap(struct wiph
sdata->u.ap.driver_smps_mode = IEEE80211_SMPS_OFF;
__sta_info_flush(sdata, true);
diff --git a/package/kernel/mac80211/patches/150-disable_addr_notifier.patch b/package/kernel/mac80211/patches/150-disable_addr_notifier.patch
index 2855a88af7..3029598437 100644
--- a/package/kernel/mac80211/patches/150-disable_addr_notifier.patch
+++ b/package/kernel/mac80211/patches/150-disable_addr_notifier.patch
@@ -18,7 +18,7 @@
static int ieee80211_ifa6_changed(struct notifier_block *nb,
unsigned long data, void *arg)
{
-@@ -1087,14 +1087,14 @@ int ieee80211_register_hw(struct ieee802
+@@ -1089,14 +1089,14 @@ int ieee80211_register_hw(struct ieee802
rtnl_unlock();
@@ -35,7 +35,7 @@
local->ifa6_notifier.notifier_call = ieee80211_ifa6_changed;
result = register_inet6addr_notifier(&local->ifa6_notifier);
if (result)
-@@ -1103,13 +1103,13 @@ int ieee80211_register_hw(struct ieee802
+@@ -1105,13 +1105,13 @@ int ieee80211_register_hw(struct ieee802
return 0;
@@ -52,7 +52,7 @@
fail_ifa:
#endif
rtnl_lock();
-@@ -1137,10 +1137,10 @@ void ieee80211_unregister_hw(struct ieee
+@@ -1139,10 +1139,10 @@ void ieee80211_unregister_hw(struct ieee
tasklet_kill(&local->tx_pending_tasklet);
tasklet_kill(&local->tasklet);
diff --git a/package/kernel/mac80211/patches/210-ap_scan.patch b/package/kernel/mac80211/patches/210-ap_scan.patch
index a99cbd2bee..29f05c44d6 100644
--- a/package/kernel/mac80211/patches/210-ap_scan.patch
+++ b/package/kernel/mac80211/patches/210-ap_scan.patch
@@ -1,6 +1,6 @@
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
-@@ -1999,7 +1999,7 @@ static int ieee80211_scan(struct wiphy *
+@@ -2008,7 +2008,7 @@ static int ieee80211_scan(struct wiphy *
* the frames sent while scanning on other channel will be
* lost)
*/
diff --git a/package/kernel/mac80211/patches/302-Revert-ath9k-interpret-requested-txpower-in-EIRP-dom.patch b/package/kernel/mac80211/patches/302-Revert-ath9k-interpret-requested-txpower-in-EIRP-dom.patch
new file mode 100644
index 0000000000..7caa9be5a8
--- /dev/null
+++ b/package/kernel/mac80211/patches/302-Revert-ath9k-interpret-requested-txpower-in-EIRP-dom.patch
@@ -0,0 +1,37 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sat, 14 May 2016 14:51:02 +0200
+Subject: [PATCH] Revert "ath9k: interpret requested txpower in EIRP
+ domain"
+
+This reverts commit 71f5137bf010c6faffab50c0ec15374c59c4a411.
+---
+
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -2914,7 +2914,8 @@ void ath9k_hw_apply_txpower(struct ath_h
+ {
+ struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
+ struct ieee80211_channel *channel;
+- int chan_pwr, new_pwr;
++ int chan_pwr, new_pwr, max_gain;
++ int ant_gain, ant_reduction = 0;
+
+ if (!chan)
+ return;
+@@ -2922,10 +2923,15 @@ void ath9k_hw_apply_txpower(struct ath_h
+ channel = chan->chan;
+ chan_pwr = min_t(int, channel->max_power * 2, MAX_RATE_POWER);
+ new_pwr = min_t(int, chan_pwr, reg->power_limit);
++ max_gain = chan_pwr - new_pwr + channel->max_antenna_gain * 2;
++
++ ant_gain = get_antenna_gain(ah, chan);
++ if (ant_gain > max_gain)
++ ant_reduction = ant_gain - max_gain;
+
+ ah->eep_ops->set_txpower(ah, chan,
+ ath9k_regd_get_ctl(reg, chan),
+- get_antenna_gain(ah, chan), new_pwr, test);
++ ant_reduction, new_pwr, test);
+ }
+
+ void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test)
diff --git a/package/kernel/mac80211/patches/302-ath9k_hw-add-low-power-tx-gain-table-for-AR953x.patch b/package/kernel/mac80211/patches/302-ath9k_hw-add-low-power-tx-gain-table-for-AR953x.patch
deleted file mode 100644
index 00d07b63ee..0000000000
--- a/package/kernel/mac80211/patches/302-ath9k_hw-add-low-power-tx-gain-table-for-AR953x.patch
+++ /dev/null
@@ -1,95 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Thu, 14 Jan 2016 03:14:03 +0100
-Subject: [PATCH] ath9k_hw: add low power tx gain table for AR953x
-
-Used in some newer TP-Link AR9533 devices.
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c
-+++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
-@@ -698,6 +698,9 @@ static void ar9003_tx_gain_table_mode2(s
- else if (AR_SREV_9340(ah))
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9340Modes_low_ob_db_tx_gain_table_1p0);
-+ else if (AR_SREV_9531_11(ah))
-+ INIT_INI_ARRAY(&ah->iniModesTxGain,
-+ qca953x_1p1_modes_no_xpa_low_power_tx_gain_table);
- else if (AR_SREV_9485_11_OR_LATER(ah))
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9485Modes_low_ob_db_tx_gain_1_1);
---- a/drivers/net/wireless/ath/ath9k/ar953x_initvals.h
-+++ b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h
-@@ -757,6 +757,71 @@ static const u32 qca953x_1p1_modes_xpa_t
- {0x00016448, 0x6c927a70},
- };
-
-+static const u32 qca953x_1p1_modes_no_xpa_low_power_tx_gain_table[][2] = {
-+ /* Addr allmodes */
-+ {0x0000a2dc, 0xfff55592},
-+ {0x0000a2e0, 0xfff99924},
-+ {0x0000a2e4, 0xfffe1e00},
-+ {0x0000a2e8, 0xffffe000},
-+ {0x0000a410, 0x000050d6},
-+ {0x0000a500, 0x00000069},
-+ {0x0000a504, 0x0400006b},
-+ {0x0000a508, 0x0800006d},
-+ {0x0000a50c, 0x0c000269},
-+ {0x0000a510, 0x1000026b},
-+ {0x0000a514, 0x1400026d},
-+ {0x0000a518, 0x18000669},
-+ {0x0000a51c, 0x1c00066b},
-+ {0x0000a520, 0x1d000a68},
-+ {0x0000a524, 0x21000a6a},
-+ {0x0000a528, 0x25000a6c},
-+ {0x0000a52c, 0x29000a6e},
-+ {0x0000a530, 0x2d0012a9},
-+ {0x0000a534, 0x310012ab},
-+ {0x0000a538, 0x350012ad},
-+ {0x0000a53c, 0x39001b0a},
-+ {0x0000a540, 0x3d001b0c},
-+ {0x0000a544, 0x41001b0e},
-+ {0x0000a548, 0x43001bae},
-+ {0x0000a54c, 0x45001914},
-+ {0x0000a550, 0x47001916},
-+ {0x0000a554, 0x49001b96},
-+ {0x0000a558, 0x49001b96},
-+ {0x0000a55c, 0x49001b96},
-+ {0x0000a560, 0x49001b96},
-+ {0x0000a564, 0x49001b96},
-+ {0x0000a568, 0x49001b96},
-+ {0x0000a56c, 0x49001b96},
-+ {0x0000a570, 0x49001b96},
-+ {0x0000a574, 0x49001b96},
-+ {0x0000a578, 0x49001b96},
-+ {0x0000a57c, 0x49001b96},
-+ {0x0000a600, 0x00000000},
-+ {0x0000a604, 0x00000000},
-+ {0x0000a608, 0x00000000},
-+ {0x0000a60c, 0x00000000},
-+ {0x0000a610, 0x00000000},
-+ {0x0000a614, 0x00000000},
-+ {0x0000a618, 0x00804201},
-+ {0x0000a61c, 0x01408201},
-+ {0x0000a620, 0x01408502},
-+ {0x0000a624, 0x01408502},
-+ {0x0000a628, 0x01408502},
-+ {0x0000a62c, 0x01408502},
-+ {0x0000a630, 0x01408502},
-+ {0x0000a634, 0x01408502},
-+ {0x0000a638, 0x01408502},
-+ {0x0000a63c, 0x01408502},
-+ {0x0000b2dc, 0xfff55592},
-+ {0x0000b2e0, 0xfff99924},
-+ {0x0000b2e4, 0xfffe1e00},
-+ {0x0000b2e8, 0xffffe000},
-+ {0x00016044, 0x044922db},
-+ {0x00016048, 0x6c927a70},
-+ {0x00016444, 0x044922db},
-+ {0x00016448, 0x6c927a70},
-+};
-+
- static const u32 qca953x_2p0_baseband_core[][2] = {
- /* Addr allmodes */
- {0x00009800, 0xafe68e30},
diff --git a/package/kernel/mac80211/patches/303-mac80211-mesh-flush-mesh-paths-unconditionally.patch b/package/kernel/mac80211/patches/303-mac80211-mesh-flush-mesh-paths-unconditionally.patch
new file mode 100644
index 0000000000..518d0a31da
--- /dev/null
+++ b/package/kernel/mac80211/patches/303-mac80211-mesh-flush-mesh-paths-unconditionally.patch
@@ -0,0 +1,146 @@
+From: Bob Copeland <me@bobcopeland.com>
+Date: Sun, 15 May 2016 13:19:16 -0400
+Subject: [PATCH] mac80211: mesh: flush mesh paths unconditionally
+
+Currently, the mesh paths associated with a nexthop station are cleaned
+up in the following code path:
+
+ __sta_info_destroy_part1
+ synchronize_net()
+ __sta_info_destroy_part2
+ -> cleanup_single_sta
+ -> mesh_sta_cleanup
+ -> mesh_plink_deactivate
+ -> mesh_path_flush_by_nexthop
+
+However, there are a couple of problems here:
+
+1) the paths aren't flushed at all if the MPM is running in userspace
+ (e.g. when using wpa_supplicant or authsae)
+
+2) there is no synchronize_rcu between removing the path and readers
+ accessing the nexthop, which means the following race is possible:
+
+CPU0 CPU1
+~~~~ ~~~~
+ sta_info_destroy_part1()
+ synchronize_net()
+rcu_read_lock()
+mesh_nexthop_resolve()
+ mpath = mesh_path_lookup()
+ [...] -> mesh_path_flush_by_nexthop()
+ sta = rcu_dereference(
+ mpath->next_hop)
+ kfree(sta)
+ access sta <-- CRASH
+
+Fix both of these by unconditionally flushing paths before destroying
+the sta, and by adding a synchronize_net() after path flush to ensure
+no active readers can still dereference the sta.
+
+Fixes this crash:
+
+[ 348.529295] BUG: unable to handle kernel paging request at 00020040
+[ 348.530014] IP: [<f929245d>] ieee80211_mps_set_frame_flags+0x40/0xaa [mac80211]
+[ 348.530014] *pde = 00000000
+[ 348.530014] Oops: 0000 [#1] PREEMPT
+[ 348.530014] Modules linked in: drbg ansi_cprng ctr ccm ppp_generic slhc ipt_MASQUERADE nf_nat_masquerade_ipv4 8021q ]
+[ 348.530014] CPU: 0 PID: 20597 Comm: wget Tainted: G O 4.6.0-rc5-wt=V1 #1
+[ 348.530014] Hardware name: To Be Filled By O.E.M./To be filled by O.E.M., BIOS 080016 11/07/2014
+[ 348.530014] task: f64fa280 ti: f4f9c000 task.ti: f4f9c000
+[ 348.530014] EIP: 0060:[<f929245d>] EFLAGS: 00010246 CPU: 0
+[ 348.530014] EIP is at ieee80211_mps_set_frame_flags+0x40/0xaa [mac80211]
+[ 348.530014] EAX: f4ce63e0 EBX: 00000088 ECX: f3788416 EDX: 00020008
+[ 348.530014] ESI: 00000000 EDI: 00000088 EBP: f6409a4c ESP: f6409a40
+[ 348.530014] DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 0068
+[ 348.530014] CR0: 80050033 CR2: 00020040 CR3: 33190000 CR4: 00000690
+[ 348.530014] Stack:
+[ 348.530014] 00000000 f4ce63e0 f5f9bd80 f6409a64 f9291d80 0000ce67 f5d51e00 f4ce63e0
+[ 348.530014] f3788416 f6409a80 f9291dc1 f4ce8320 f4ce63e0 f5d51e00 f4ce63e0 f4ce8320
+[ 348.530014] f6409a98 f9277f6f 00000000 00000000 0000007c 00000000 f6409b2c f9278dd1
+[ 348.530014] Call Trace:
+[ 348.530014] [<f9291d80>] mesh_nexthop_lookup+0xbb/0xc8 [mac80211]
+[ 348.530014] [<f9291dc1>] mesh_nexthop_resolve+0x34/0xd8 [mac80211]
+[ 348.530014] [<f9277f6f>] ieee80211_xmit+0x92/0xc1 [mac80211]
+[ 348.530014] [<f9278dd1>] __ieee80211_subif_start_xmit+0x807/0x83c [mac80211]
+[ 348.530014] [<c04df012>] ? sch_direct_xmit+0xd7/0x1b3
+[ 348.530014] [<c022a8c6>] ? __local_bh_enable_ip+0x5d/0x7b
+[ 348.530014] [<f956870c>] ? nf_nat_ipv4_out+0x4c/0xd0 [nf_nat_ipv4]
+[ 348.530014] [<f957e036>] ? iptable_nat_ipv4_fn+0xf/0xf [iptable_nat]
+[ 348.530014] [<c04c6f45>] ? netif_skb_features+0x14d/0x30a
+[ 348.530014] [<f9278e10>] ieee80211_subif_start_xmit+0xa/0xe [mac80211]
+[ 348.530014] [<c04c769c>] dev_hard_start_xmit+0x1f8/0x267
+[ 348.530014] [<c04c7261>] ? validate_xmit_skb.isra.120.part.121+0x10/0x253
+[ 348.530014] [<c04defc6>] sch_direct_xmit+0x8b/0x1b3
+[ 348.530014] [<c04c7a9c>] __dev_queue_xmit+0x2c8/0x513
+[ 348.530014] [<c04c7cfb>] dev_queue_xmit+0xa/0xc
+[ 348.530014] [<f91bfc7a>] batadv_send_skb_packet+0xd6/0xec [batman_adv]
+[ 348.530014] [<f91bfdc4>] batadv_send_unicast_skb+0x15/0x4a [batman_adv]
+[ 348.530014] [<f91b5938>] batadv_dat_send_data+0x27e/0x310 [batman_adv]
+[ 348.530014] [<f91c30b5>] ? batadv_tt_global_hash_find.isra.11+0x8/0xa [batman_adv]
+[ 348.530014] [<f91b63f3>] batadv_dat_snoop_outgoing_arp_request+0x208/0x23d [batman_adv]
+[ 348.530014] [<f91c0cd9>] batadv_interface_tx+0x206/0x385 [batman_adv]
+[ 348.530014] [<c04c769c>] dev_hard_start_xmit+0x1f8/0x267
+[ 348.530014] [<c04c7261>] ? validate_xmit_skb.isra.120.part.121+0x10/0x253
+[ 348.530014] [<c04defc6>] sch_direct_xmit+0x8b/0x1b3
+[ 348.530014] [<c04c7a9c>] __dev_queue_xmit+0x2c8/0x513
+[ 348.530014] [<f80cbd2a>] ? igb_xmit_frame+0x57/0x72 [igb]
+[ 348.530014] [<c04c7cfb>] dev_queue_xmit+0xa/0xc
+[ 348.530014] [<f843a326>] br_dev_queue_push_xmit+0xeb/0xfb [bridge]
+[ 348.530014] [<f843a35f>] br_forward_finish+0x29/0x74 [bridge]
+[ 348.530014] [<f843a23b>] ? deliver_clone+0x3b/0x3b [bridge]
+[ 348.530014] [<f843a714>] __br_forward+0x89/0xe7 [bridge]
+[ 348.530014] [<f843a336>] ? br_dev_queue_push_xmit+0xfb/0xfb [bridge]
+[ 348.530014] [<f843a234>] deliver_clone+0x34/0x3b [bridge]
+[ 348.530014] [<f843a68b>] ? br_flood+0x95/0x95 [bridge]
+[ 348.530014] [<f843a66d>] br_flood+0x77/0x95 [bridge]
+[ 348.530014] [<f843a809>] br_flood_forward+0x13/0x1a [bridge]
+[ 348.530014] [<f843a68b>] ? br_flood+0x95/0x95 [bridge]
+[ 348.530014] [<f843b877>] br_handle_frame_finish+0x392/0x3db [bridge]
+[ 348.530014] [<c04e9b2b>] ? nf_iterate+0x2b/0x6b
+[ 348.530014] [<f843baa6>] br_handle_frame+0x1e6/0x240 [bridge]
+[ 348.530014] [<f843b4e5>] ? br_handle_local_finish+0x6a/0x6a [bridge]
+[ 348.530014] [<c04c4ba0>] __netif_receive_skb_core+0x43a/0x66b
+[ 348.530014] [<f843b8c0>] ? br_handle_frame_finish+0x3db/0x3db [bridge]
+[ 348.530014] [<c023cea4>] ? resched_curr+0x19/0x37
+[ 348.530014] [<c0240707>] ? check_preempt_wakeup+0xbf/0xfe
+[ 348.530014] [<c0255dec>] ? ktime_get_with_offset+0x5c/0xfc
+[ 348.530014] [<c04c4fc1>] __netif_receive_skb+0x47/0x55
+[ 348.530014] [<c04c57ba>] netif_receive_skb_internal+0x40/0x5a
+[ 348.530014] [<c04c61ef>] napi_gro_receive+0x3a/0x94
+[ 348.530014] [<f80ce8d5>] igb_poll+0x6fd/0x9ad [igb]
+[ 348.530014] [<c0242bd8>] ? swake_up_locked+0x14/0x26
+[ 348.530014] [<c04c5d29>] net_rx_action+0xde/0x250
+[ 348.530014] [<c022a743>] __do_softirq+0x8a/0x163
+[ 348.530014] [<c022a6b9>] ? __hrtimer_tasklet_trampoline+0x19/0x19
+[ 348.530014] [<c021100f>] do_softirq_own_stack+0x26/0x2c
+[ 348.530014] <IRQ>
+[ 348.530014] [<c022a957>] irq_exit+0x31/0x6f
+[ 348.530014] [<c0210eb2>] do_IRQ+0x8d/0xa0
+[ 348.530014] [<c058152c>] common_interrupt+0x2c/0x40
+[ 348.530014] Code: e7 8c 00 66 81 ff 88 00 75 12 85 d2 75 0e b2 c3 b8 83 e9 29 f9 e8 a7 5f f9 c6 eb 74 66 81 e3 8c 005
+[ 348.530014] EIP: [<f929245d>] ieee80211_mps_set_frame_flags+0x40/0xaa [mac80211] SS:ESP 0068:f6409a40
+[ 348.530014] CR2: 0000000000020040
+[ 348.530014] ---[ end trace 48556ac26779732e ]---
+[ 348.530014] Kernel panic - not syncing: Fatal exception in interrupt
+[ 348.530014] Kernel Offset: disabled
+
+Cc: stable@vger.kernel.org
+Reported-by: Fred Veldini <fred.veldini@gmail.com>
+Tested-by: Fred Veldini <fred.veldini@gmail.com>
+Signed-off-by: Bob Copeland <me@bobcopeland.com>
+---
+
+--- a/net/mac80211/mesh.c
++++ b/net/mac80211/mesh.c
+@@ -161,6 +161,10 @@ void mesh_sta_cleanup(struct sta_info *s
+ del_timer_sync(&sta->mesh->plink_timer);
+ }
+
++ /* make sure no readers can access nexthop sta from here on */
++ mesh_path_flush_by_nexthop(sta);
++ synchronize_net();
++
+ if (changed)
+ ieee80211_mbss_info_change_notify(sdata, changed);
+ }
diff --git a/package/kernel/mac80211/patches/303-rt2x00-fix-monitor-mode-regression.patch b/package/kernel/mac80211/patches/303-rt2x00-fix-monitor-mode-regression.patch
deleted file mode 100644
index 7bb74353eb..0000000000
--- a/package/kernel/mac80211/patches/303-rt2x00-fix-monitor-mode-regression.patch
+++ /dev/null
@@ -1,156 +0,0 @@
-From: Eli Cooper <elicooper@gmx.com>
-Date: Thu, 14 Jan 2016 00:07:12 +0800
-Subject: [PATCH] rt2x00: fix monitor mode regression
-
-Since commit df1404650ccbfeb76a84f301f22316be0d00a864 monitor mode for rt2x00
-has been made effectively useless because the hardware filter is configured to
-drop packets whose intended recipient is not the device, regardless of the
-presence of monitor mode interfaces.
-
-This patch fixes this regression by adding explicit monitor mode support, and
-configuring the hardware filter accordingly.
-
-Signed-off-by: Eli Cooper <elicooper@gmx.com>
----
-
---- a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c
-@@ -273,8 +273,10 @@ static void rt2400pci_config_filter(stru
- !(filter_flags & FIF_PLCPFAIL));
- rt2x00_set_field32(&reg, RXCSR0_DROP_CONTROL,
- !(filter_flags & FIF_CONTROL));
-- rt2x00_set_field32(&reg, RXCSR0_DROP_NOT_TO_ME, 1);
-+ rt2x00_set_field32(&reg, RXCSR0_DROP_NOT_TO_ME,
-+ !rt2x00dev->is_monitoring);
- rt2x00_set_field32(&reg, RXCSR0_DROP_TODS,
-+ !rt2x00dev->is_monitoring &&
- !rt2x00dev->intf_ap_count);
- rt2x00_set_field32(&reg, RXCSR0_DROP_VERSION_ERROR, 1);
- rt2x00mmio_register_write(rt2x00dev, RXCSR0, reg);
---- a/drivers/net/wireless/ralink/rt2x00/rt2500pci.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2500pci.c
-@@ -274,8 +274,10 @@ static void rt2500pci_config_filter(stru
- !(filter_flags & FIF_PLCPFAIL));
- rt2x00_set_field32(&reg, RXCSR0_DROP_CONTROL,
- !(filter_flags & FIF_CONTROL));
-- rt2x00_set_field32(&reg, RXCSR0_DROP_NOT_TO_ME, 1);
-+ rt2x00_set_field32(&reg, RXCSR0_DROP_NOT_TO_ME,
-+ !rt2x00dev->is_monitoring);
- rt2x00_set_field32(&reg, RXCSR0_DROP_TODS,
-+ !rt2x00dev->is_monitoring &&
- !rt2x00dev->intf_ap_count);
- rt2x00_set_field32(&reg, RXCSR0_DROP_VERSION_ERROR, 1);
- rt2x00_set_field32(&reg, RXCSR0_DROP_MCAST,
---- a/drivers/net/wireless/ralink/rt2x00/rt2500usb.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2500usb.c
-@@ -437,8 +437,10 @@ static void rt2500usb_config_filter(stru
- !(filter_flags & FIF_PLCPFAIL));
- rt2x00_set_field16(&reg, TXRX_CSR2_DROP_CONTROL,
- !(filter_flags & FIF_CONTROL));
-- rt2x00_set_field16(&reg, TXRX_CSR2_DROP_NOT_TO_ME, 1);
-+ rt2x00_set_field16(&reg, TXRX_CSR2_DROP_NOT_TO_ME,
-+ !rt2x00dev->is_monitoring);
- rt2x00_set_field16(&reg, TXRX_CSR2_DROP_TODS,
-+ !rt2x00dev->is_monitoring &&
- !rt2x00dev->intf_ap_count);
- rt2x00_set_field16(&reg, TXRX_CSR2_DROP_VERSION_ERROR, 1);
- rt2x00_set_field16(&reg, TXRX_CSR2_DROP_MULTICAST,
---- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-@@ -1490,7 +1490,8 @@ void rt2800_config_filter(struct rt2x00_
- !(filter_flags & FIF_FCSFAIL));
- rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_PHY_ERROR,
- !(filter_flags & FIF_PLCPFAIL));
-- rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_NOT_TO_ME, 1);
-+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_NOT_TO_ME,
-+ !rt2x00dev->is_monitoring);
- rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_NOT_MY_BSSD, 0);
- rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_VER_ERROR, 1);
- rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_MULTICAST,
---- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
-@@ -844,11 +844,13 @@ struct rt2x00_dev {
- * - Open sta interface count.
- * - Association count.
- * - Beaconing enabled count.
-+ * - Whether the device is monitoring.
- */
- unsigned int intf_ap_count;
- unsigned int intf_sta_count;
- unsigned int intf_associated;
- unsigned int intf_beaconing;
-+ bool is_monitoring;
-
- /*
- * Interface combinations
---- a/drivers/net/wireless/ralink/rt2x00/rt2x00config.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00config.c
-@@ -244,6 +244,16 @@ void rt2x00lib_config(struct rt2x00_dev
- (ieee80211_flags & IEEE80211_CONF_CHANGE_PS))
- cancel_delayed_work_sync(&rt2x00dev->autowakeup_work);
-
-+ if (ieee80211_flags & IEEE80211_CONF_CHANGE_MONITOR) {
-+ if (conf->flags & IEEE80211_CONF_MONITOR) {
-+ rt2x00_dbg(rt2x00dev, "Monitor mode is enabled\n");
-+ rt2x00dev->is_monitoring = true;
-+ } else {
-+ rt2x00_dbg(rt2x00dev, "Monitor mode is disabled\n");
-+ rt2x00dev->is_monitoring = false;
-+ }
-+ }
-+
- /*
- * Start configuration.
- */
---- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
-@@ -1204,6 +1204,7 @@ int rt2x00lib_start(struct rt2x00_dev *r
- rt2x00dev->intf_ap_count = 0;
- rt2x00dev->intf_sta_count = 0;
- rt2x00dev->intf_associated = 0;
-+ rt2x00dev->is_monitoring = false;
-
- /* Enable the radio */
- retval = rt2x00lib_enable_radio(rt2x00dev);
---- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
-@@ -385,11 +385,6 @@ void rt2x00mac_configure_filter(struct i
- *total_flags |= FIF_PSPOLL;
- }
-
-- /*
-- * Check if there is any work left for us.
-- */
-- if (rt2x00dev->packet_filter == *total_flags)
-- return;
- rt2x00dev->packet_filter = *total_flags;
-
- rt2x00dev->ops->lib->config_filter(rt2x00dev, *total_flags);
---- a/drivers/net/wireless/ralink/rt2x00/rt61pci.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt61pci.c
-@@ -530,8 +530,10 @@ static void rt61pci_config_filter(struct
- !(filter_flags & FIF_PLCPFAIL));
- rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CONTROL,
- !(filter_flags & (FIF_CONTROL | FIF_PSPOLL)));
-- rt2x00_set_field32(&reg, TXRX_CSR0_DROP_NOT_TO_ME, 1);
-+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_NOT_TO_ME,
-+ !rt2x00dev->is_monitoring);
- rt2x00_set_field32(&reg, TXRX_CSR0_DROP_TO_DS,
-+ !rt2x00dev->is_monitoring &&
- !rt2x00dev->intf_ap_count);
- rt2x00_set_field32(&reg, TXRX_CSR0_DROP_VERSION_ERROR, 1);
- rt2x00_set_field32(&reg, TXRX_CSR0_DROP_MULTICAST,
---- a/drivers/net/wireless/ralink/rt2x00/rt73usb.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt73usb.c
-@@ -480,8 +480,10 @@ static void rt73usb_config_filter(struct
- !(filter_flags & FIF_PLCPFAIL));
- rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CONTROL,
- !(filter_flags & (FIF_CONTROL | FIF_PSPOLL)));
-- rt2x00_set_field32(&reg, TXRX_CSR0_DROP_NOT_TO_ME, 1);
-+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_NOT_TO_ME,
-+ !rt2x00dev->is_monitoring);
- rt2x00_set_field32(&reg, TXRX_CSR0_DROP_TO_DS,
-+ !rt2x00dev->is_monitoring &&
- !rt2x00dev->intf_ap_count);
- rt2x00_set_field32(&reg, TXRX_CSR0_DROP_VERSION_ERROR, 1);
- rt2x00_set_field32(&reg, TXRX_CSR0_DROP_MULTICAST,
diff --git a/package/kernel/mac80211/patches/304-ath9k-avoid-ANI-restart-if-no-trigger.patch b/package/kernel/mac80211/patches/304-ath9k-avoid-ANI-restart-if-no-trigger.patch
deleted file mode 100644
index 049059aa24..0000000000
--- a/package/kernel/mac80211/patches/304-ath9k-avoid-ANI-restart-if-no-trigger.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-From: Miaoqing Pan <miaoqing@codeaurora.org>
-Date: Fri, 15 Jan 2016 18:17:17 +0800
-Subject: [PATCH] ath9k: avoid ANI restart if no trigger
-
-Fixes commit 54da20d83f0e ("ath9k_hw: improve ANI processing and rx desensitizing parameters")
-
-Call ath9k_ani_restart() only when the phy error rate reach the
-ANI immunity threshold. Sync the logic with internal code base.
-
-Signed-off-by: Miaoqing Pan <miaoqing@codeaurora.org>
----
-
---- a/drivers/net/wireless/ath/ath9k/ani.c
-+++ b/drivers/net/wireless/ath/ath9k/ani.c
-@@ -444,14 +444,16 @@ void ath9k_hw_ani_monitor(struct ath_hw
- ofdmPhyErrRate < ah->config.ofdm_trig_low) {
- ath9k_hw_ani_lower_immunity(ah);
- aniState->ofdmsTurn = !aniState->ofdmsTurn;
-+ ath9k_ani_restart(ah);
- } else if (ofdmPhyErrRate > ah->config.ofdm_trig_high) {
- ath9k_hw_ani_ofdm_err_trigger(ah);
- aniState->ofdmsTurn = false;
-+ ath9k_ani_restart(ah);
- } else if (cckPhyErrRate > ah->config.cck_trig_high) {
- ath9k_hw_ani_cck_err_trigger(ah);
- aniState->ofdmsTurn = true;
-+ ath9k_ani_restart(ah);
- }
-- ath9k_ani_restart(ah);
- }
- }
- EXPORT_SYMBOL(ath9k_hw_ani_monitor);
diff --git a/package/kernel/mac80211/patches/304-mac80211-fix-fast_tx-header-alignment.patch b/package/kernel/mac80211/patches/304-mac80211-fix-fast_tx-header-alignment.patch
new file mode 100644
index 0000000000..6316d81729
--- /dev/null
+++ b/package/kernel/mac80211/patches/304-mac80211-fix-fast_tx-header-alignment.patch
@@ -0,0 +1,25 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Thu, 19 May 2016 17:32:13 +0200
+Subject: [PATCH] mac80211: fix fast_tx header alignment
+
+The header field is defined as u8[] but also accessed as struct
+ieee80211_hdr. Enforce an alignment of 2 to prevent unnecessary
+unaligned accesses, which can be very harmful for performance on many
+platforms.
+
+Fixes: e495c24731a2 ("mac80211: extend fast-xmit for more ciphers")
+Cc: stable@vger.kernel.org
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/mac80211/sta_info.h
++++ b/net/mac80211/sta_info.h
+@@ -280,7 +280,7 @@ struct ieee80211_fast_tx {
+ u8 sa_offs, da_offs, pn_offs;
+ u8 band;
+ u8 hdr[30 + 2 + IEEE80211_FAST_XMIT_MAX_IV +
+- sizeof(rfc1042_header)];
++ sizeof(rfc1042_header)] __aligned(2);
+
+ struct rcu_head rcu_head;
+ };
diff --git a/package/kernel/mac80211/patches/305-ath9k-clean-up-ANI-per-channel-pointer-checking.patch b/package/kernel/mac80211/patches/305-ath9k-clean-up-ANI-per-channel-pointer-checking.patch
deleted file mode 100644
index a1ac67c828..0000000000
--- a/package/kernel/mac80211/patches/305-ath9k-clean-up-ANI-per-channel-pointer-checking.patch
+++ /dev/null
@@ -1,91 +0,0 @@
-From: Miaoqing Pan <miaoqing@codeaurora.org>
-Date: Fri, 15 Jan 2016 18:17:18 +0800
-Subject: [PATCH] ath9k: clean up ANI per-channel pointer checking
-
-commit c24bd3620c50 ("ath9k: Do not maintain ANI state per-channel")
-removed per-channel handling, the code to check 'curchan' also
-should be removed as never used.
-
-Signed-off-by: Miaoqing Pan <miaoqing@codeaurora.org>
----
-
---- a/drivers/net/wireless/ath/ath9k/ani.c
-+++ b/drivers/net/wireless/ath/ath9k/ani.c
-@@ -126,12 +126,8 @@ static void ath9k_hw_update_mibstats(str
-
- static void ath9k_ani_restart(struct ath_hw *ah)
- {
-- struct ar5416AniState *aniState;
--
-- if (!ah->curchan)
-- return;
-+ struct ar5416AniState *aniState = &ah->ani;
-
-- aniState = &ah->ani;
- aniState->listenTime = 0;
-
- ENABLE_REGWRITE_BUFFER(ah);
-@@ -221,12 +217,7 @@ static void ath9k_hw_set_ofdm_nil(struct
-
- static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
- {
-- struct ar5416AniState *aniState;
--
-- if (!ah->curchan)
-- return;
--
-- aniState = &ah->ani;
-+ struct ar5416AniState *aniState = &ah->ani;
-
- if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL)
- ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1, false);
-@@ -281,12 +272,7 @@ static void ath9k_hw_set_cck_nil(struct
-
- static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
- {
-- struct ar5416AniState *aniState;
--
-- if (!ah->curchan)
-- return;
--
-- aniState = &ah->ani;
-+ struct ar5416AniState *aniState = &ah->ani;
-
- if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL)
- ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1,
-@@ -299,9 +285,7 @@ static void ath9k_hw_ani_cck_err_trigger
- */
- static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
- {
-- struct ar5416AniState *aniState;
--
-- aniState = &ah->ani;
-+ struct ar5416AniState *aniState = &ah->ani;
-
- /* lower OFDM noise immunity */
- if (aniState->ofdmNoiseImmunityLevel > 0 &&
-@@ -329,7 +313,7 @@ void ath9k_ani_reset(struct ath_hw *ah,
- struct ath_common *common = ath9k_hw_common(ah);
- int ofdm_nil, cck_nil;
-
-- if (!ah->curchan)
-+ if (!chan)
- return;
-
- BUG_ON(aniState == NULL);
-@@ -416,14 +400,10 @@ static bool ath9k_hw_ani_read_counters(s
-
- void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan)
- {
-- struct ar5416AniState *aniState;
-+ struct ar5416AniState *aniState = &ah->ani;
- struct ath_common *common = ath9k_hw_common(ah);
- u32 ofdmPhyErrRate, cckPhyErrRate;
-
-- if (!ah->curchan)
-- return;
--
-- aniState = &ah->ani;
- if (!ath9k_hw_ani_read_counters(ah))
- return;
-
diff --git a/package/kernel/mac80211/patches/306-ath9k-do-not-reset-while-BB-panic-0x4000409-on-ar956.patch b/package/kernel/mac80211/patches/306-ath9k-do-not-reset-while-BB-panic-0x4000409-on-ar956.patch
deleted file mode 100644
index cf8194aa33..0000000000
--- a/package/kernel/mac80211/patches/306-ath9k-do-not-reset-while-BB-panic-0x4000409-on-ar956.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-From: Miaoqing Pan <miaoqing@codeaurora.org>
-Date: Fri, 15 Jan 2016 18:17:19 +0800
-Subject: [PATCH] ath9k: do not reset while BB panic(0x4000409) on ar9561
-
-BB panic(0x4000409) observed while AP enabling/disabling
-bursting.
-
-Signed-off-by: Miaoqing Pan <miaoqing@codeaurora.org>
----
-
---- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
-+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
-@@ -2071,7 +2071,8 @@ void ar9003_hw_attach_phy_ops(struct ath
- * to be disabled.
- *
- * 0x04000409: Packet stuck on receive.
-- * Full chip reset is required for all chips except AR9340.
-+ * Full chip reset is required for all chips except
-+ * AR9340, AR9531 and AR9561.
- */
-
- /*
-@@ -2100,7 +2101,7 @@ bool ar9003_hw_bb_watchdog_check(struct
- case 0x04000b09:
- return true;
- case 0x04000409:
-- if (AR_SREV_9340(ah) || AR_SREV_9531(ah))
-+ if (AR_SREV_9340(ah) || AR_SREV_9531(ah) || AR_SREV_9561(ah))
- return false;
- else
- return true;
diff --git a/package/kernel/mac80211/patches/307-ath9k-fix-inconsistent-use-of-tab-and-space-in-inden.patch b/package/kernel/mac80211/patches/307-ath9k-fix-inconsistent-use-of-tab-and-space-in-inden.patch
deleted file mode 100644
index 80b781ca54..0000000000
--- a/package/kernel/mac80211/patches/307-ath9k-fix-inconsistent-use-of-tab-and-space-in-inden.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-From: Miaoqing Pan <miaoqing@codeaurora.org>
-Date: Fri, 15 Jan 2016 18:17:20 +0800
-Subject: [PATCH] ath9k: fix inconsistent use of tab and space in
- indentation
-
-Minor changes for indenting.
-
-Signed-off-by: Miaoqing Pan <miaoqing@codeaurora.org>
----
-
---- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
-+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
-@@ -5485,11 +5485,11 @@ unsigned int ar9003_get_paprd_scale_fact
- AR9300_PAPRD_SCALE_1);
- else {
- if (chan->channel >= 5700)
-- return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt20),
-- AR9300_PAPRD_SCALE_1);
-+ return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt20),
-+ AR9300_PAPRD_SCALE_1);
- else if (chan->channel >= 5400)
- return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt40),
-- AR9300_PAPRD_SCALE_2);
-+ AR9300_PAPRD_SCALE_2);
- else
- return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt40),
- AR9300_PAPRD_SCALE_1);
diff --git a/package/kernel/mac80211/patches/308-ath9k-fix-data-bus-error-on-ar9300-and-ar9580.patch b/package/kernel/mac80211/patches/308-ath9k-fix-data-bus-error-on-ar9300-and-ar9580.patch
deleted file mode 100644
index d4088664bf..0000000000
--- a/package/kernel/mac80211/patches/308-ath9k-fix-data-bus-error-on-ar9300-and-ar9580.patch
+++ /dev/null
@@ -1,65 +0,0 @@
-From: Miaoqing Pan <miaoqing@codeaurora.org>
-Date: Fri, 15 Jan 2016 18:17:21 +0800
-Subject: [PATCH] ath9k: fix data bus error on ar9300 and ar9580
-
-One crash issue be found on ar9300: RTC_RC reg read leads crash, leading
-the data bus error, due to RTC_RC reg write not happen properly.
-
-Warm Reset trigger in continuous beacon stuck for one of the customer for
-other chip, noticed the MAC was stuck in RTC reset. After analysis noticed
-DMA did not complete when RTC was put in reset.
-
-So, before resetting the MAC need to make sure there are no pending DMA
-transactions because this reset does not reset all parts of the chip.
-
-The 12th and 11th bit of MAC _DMA_CFG register used to do that.
- 12 cfg_halt_ack 0x0
- 0 DMA has not yet halted
- 1 DMA has halted
- 11 cfg_halt_req 0x0
- 0 DMA logic operates normally
- 1 Request DMA logic to stop so software can reset the MAC
-
-The Bit [12] of this register indicates when the halt has taken effect or
-not. the DMA halt IS NOT recoverable; once software sets bit [11] to
-request a DMA halt, software must wait for bit [12] to be set and reset
-the MAC.
-
-So, the same thing we implemented for ar9580 chip.
-
-Signed-off-by: Miaoqing Pan <miaoqing@codeaurora.org>
----
-
---- a/drivers/net/wireless/ath/ath9k/hw.c
-+++ b/drivers/net/wireless/ath/ath9k/hw.c
-@@ -1368,6 +1368,16 @@ static bool ath9k_hw_set_reset(struct at
- if (ath9k_hw_mci_is_enabled(ah))
- ar9003_mci_check_gpm_offset(ah);
-
-+ /* DMA HALT added to resolve ar9300 and ar9580 bus error during
-+ * RTC_RC reg read
-+ */
-+ if (AR_SREV_9300(ah) || AR_SREV_9580(ah)) {
-+ REG_SET_BIT(ah, AR_CFG, AR_CFG_HALT_REQ);
-+ ath9k_hw_wait(ah, AR_CFG, AR_CFG_HALT_ACK, AR_CFG_HALT_ACK,
-+ 20 * AH_WAIT_TIMEOUT);
-+ REG_CLR_BIT(ah, AR_CFG, AR_CFG_HALT_REQ);
-+ }
-+
- REG_WRITE(ah, AR_RTC_RC, rst_flags);
-
- REGWRITE_BUFFER_FLUSH(ah);
---- a/drivers/net/wireless/ath/ath9k/reg.h
-+++ b/drivers/net/wireless/ath/ath9k/reg.h
-@@ -34,8 +34,10 @@
- #define AR_CFG_SWRG 0x00000010
- #define AR_CFG_AP_ADHOC_INDICATION 0x00000020
- #define AR_CFG_PHOK 0x00000100
--#define AR_CFG_CLK_GATE_DIS 0x00000400
- #define AR_CFG_EEBS 0x00000200
-+#define AR_CFG_CLK_GATE_DIS 0x00000400
-+#define AR_CFG_HALT_REQ 0x00000800
-+#define AR_CFG_HALT_ACK 0x00001000
- #define AR_CFG_PCI_MASTER_REQ_Q_THRESH 0x00060000
- #define AR_CFG_PCI_MASTER_REQ_Q_THRESH_S 17
-
diff --git a/package/kernel/mac80211/patches/309-01-brcmfmac-add-missing-include.patch b/package/kernel/mac80211/patches/309-01-brcmfmac-add-missing-include.patch
deleted file mode 100644
index 48706e23c2..0000000000
--- a/package/kernel/mac80211/patches/309-01-brcmfmac-add-missing-include.patch
+++ /dev/null
@@ -1,19 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Fri, 15 Jan 2016 15:59:45 +0100
-Subject: [PATCH] brcmfmac: add missing include
-
-linux/module.h is required for defining module parameters
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
-@@ -17,6 +17,7 @@
- #include <linux/kernel.h>
- #include <linux/string.h>
- #include <linux/netdevice.h>
-+#include <linux/module.h>
- #include <brcmu_wifi.h>
- #include <brcmu_utils.h>
- #include "core.h"
diff --git a/package/kernel/mac80211/patches/309-02-brcmfmac-fix-sdio-sg-table-alloc-crash.patch b/package/kernel/mac80211/patches/309-02-brcmfmac-fix-sdio-sg-table-alloc-crash.patch
deleted file mode 100644
index 711e019e2b..0000000000
--- a/package/kernel/mac80211/patches/309-02-brcmfmac-fix-sdio-sg-table-alloc-crash.patch
+++ /dev/null
@@ -1,118 +0,0 @@
-From: Hante Meuleman <meuleman@broadcom.com>
-Date: Tue, 19 Jan 2016 12:39:24 +0100
-Subject: [PATCH] brcmfmac: fix sdio sg table alloc crash
-
-With commit 7d34b0560567 ("brcmfmac: Move all module parameters to
-one place") a bug was introduced causing a null pointer exception.
-This patch fixes the bug by initializing the sg table till after
-the settings have been initialized.
-
-Fixes: 7d34b0560567 ("brcmfmac: Move all module parameters to one place")
-Reported-by: Marc Zyngier <marc.zyngier@arm.com>
-Tested-by: Marc Zyngier <marc.zyngier@arm.com>
-Reviewed-by: Arend Van Spriel <arend@broadcom.com>
-Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
-Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
-@@ -879,11 +879,24 @@ int brcmf_sdiod_abort(struct brcmf_sdio_
- return 0;
- }
-
--static void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev)
-+void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev)
- {
-+ struct sdio_func *func;
-+ struct mmc_host *host;
-+ uint max_blocks;
- uint nents;
- int err;
-
-+ func = sdiodev->func[2];
-+ host = func->card->host;
-+ sdiodev->sg_support = host->max_segs > 1;
-+ max_blocks = min_t(uint, host->max_blk_count, 511u);
-+ sdiodev->max_request_size = min_t(uint, host->max_req_size,
-+ max_blocks * func->cur_blksize);
-+ sdiodev->max_segment_count = min_t(uint, host->max_segs,
-+ SG_MAX_SINGLE_ALLOC);
-+ sdiodev->max_segment_size = host->max_seg_size;
-+
- if (!sdiodev->sg_support)
- return;
-
-@@ -1021,9 +1034,6 @@ static void brcmf_sdiod_host_fixup(struc
-
- static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
- {
-- struct sdio_func *func;
-- struct mmc_host *host;
-- uint max_blocks;
- int ret = 0;
-
- sdiodev->num_funcs = 2;
-@@ -1054,26 +1064,6 @@ static int brcmf_sdiod_probe(struct brcm
- goto out;
- }
-
-- /*
-- * determine host related variables after brcmf_sdiod_probe()
-- * as func->cur_blksize is properly set and F2 init has been
-- * completed successfully.
-- */
-- func = sdiodev->func[2];
-- host = func->card->host;
-- sdiodev->sg_support = host->max_segs > 1;
-- max_blocks = min_t(uint, host->max_blk_count, 511u);
-- sdiodev->max_request_size = min_t(uint, host->max_req_size,
-- max_blocks * func->cur_blksize);
-- sdiodev->max_segment_count = min_t(uint, host->max_segs,
-- SG_MAX_SINGLE_ALLOC);
-- sdiodev->max_segment_size = host->max_seg_size;
--
-- /* allocate scatter-gather table. sg support
-- * will be disabled upon allocation failure.
-- */
-- brcmf_sdiod_sgtable_alloc(sdiodev);
--
- ret = brcmf_sdiod_freezer_attach(sdiodev);
- if (ret)
- goto out;
-@@ -1084,7 +1074,7 @@ static int brcmf_sdiod_probe(struct brcm
- ret = -ENODEV;
- goto out;
- }
-- brcmf_sdiod_host_fixup(host);
-+ brcmf_sdiod_host_fixup(sdiodev->func[2]->card->host);
- out:
- if (ret)
- brcmf_sdiod_remove(sdiodev);
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
-@@ -4114,6 +4114,11 @@ struct brcmf_sdio *brcmf_sdio_probe(stru
- goto fail;
- }
-
-+ /* allocate scatter-gather table. sg support
-+ * will be disabled upon allocation failure.
-+ */
-+ brcmf_sdiod_sgtable_alloc(bus->sdiodev);
-+
- /* Query the F2 block size, set roundup accordingly */
- bus->blocksize = bus->sdiodev->func[2]->cur_blksize;
- bus->roundup = min(max_roundup, bus->blocksize);
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
-@@ -342,6 +342,7 @@ int brcmf_sdiod_ramrw(struct brcmf_sdio_
-
- /* Issue an abort to the specified function */
- int brcmf_sdiod_abort(struct brcmf_sdio_dev *sdiodev, uint fn);
-+void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev);
- void brcmf_sdiod_change_state(struct brcmf_sdio_dev *sdiodev,
- enum brcmf_sdiod_state state);
- #ifdef CONFIG_PM_SLEEP
diff --git a/package/kernel/mac80211/patches/310-ath9k_hw-ignore-eeprom-magic-mismatch-on-flash-based.patch b/package/kernel/mac80211/patches/310-ath9k_hw-ignore-eeprom-magic-mismatch-on-flash-based.patch
deleted file mode 100644
index 34106441af..0000000000
--- a/package/kernel/mac80211/patches/310-ath9k_hw-ignore-eeprom-magic-mismatch-on-flash-based.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Thu, 21 Jan 2016 16:28:44 +0100
-Subject: [PATCH] ath9k_hw: ignore eeprom magic mismatch on flash based devices
-
-Many AR913x based devices (maybe others too) do not have a valid EEPROM
-magic in their calibration data partition.
-
-Fixes: 6fa658fd5ab2 ("ath9k: Simplify and fix eeprom endianness swapping")
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/drivers/net/wireless/ath/ath9k/eeprom.c
-+++ b/drivers/net/wireless/ath/ath9k/eeprom.c
-@@ -150,18 +150,18 @@ int ath9k_hw_nvram_swap_data(struct ath_
- return -EIO;
- }
-
-- if (magic == AR5416_EEPROM_MAGIC) {
-- *swap_needed = false;
-- } else if (swab16(magic) == AR5416_EEPROM_MAGIC) {
-+ *swap_needed = false;
-+ if (swab16(magic) == AR5416_EEPROM_MAGIC) {
- if (ah->ah_flags & AH_NO_EEP_SWAP) {
- ath_info(common,
- "Ignoring endianness difference in EEPROM magic bytes.\n");
--
-- *swap_needed = false;
- } else {
- *swap_needed = true;
- }
-- } else {
-+ } else if (magic != AR5416_EEPROM_MAGIC) {
-+ if (ath9k_hw_use_flash(ah))
-+ return 0;
-+
- ath_err(common,
- "Invalid EEPROM Magic (0x%04x).\n", magic);
- return -EINVAL;
diff --git a/package/kernel/mac80211/patches/311-ath9k-do-not-limit-the-number-of-DFS-interfaces-to-1.patch b/package/kernel/mac80211/patches/311-ath9k-do-not-limit-the-number-of-DFS-interfaces-to-1.patch
deleted file mode 100644
index 73c1ec28c6..0000000000
--- a/package/kernel/mac80211/patches/311-ath9k-do-not-limit-the-number-of-DFS-interfaces-to-1.patch
+++ /dev/null
@@ -1,55 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Fri, 22 Jan 2016 01:05:56 +0100
-Subject: [PATCH] ath9k: do not limit the number of DFS interfaces to 1
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/drivers/net/wireless/ath/ath9k/init.c
-+++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -751,14 +751,6 @@ static const struct ieee80211_iface_comb
-
- #endif /* CPTCFG_ATH9K_CHANNEL_CONTEXT */
-
--static const struct ieee80211_iface_limit if_dfs_limits[] = {
-- { .max = 1, .types = BIT(NL80211_IFTYPE_AP) |
--#ifdef CPTCFG_MAC80211_MESH
-- BIT(NL80211_IFTYPE_MESH_POINT) |
--#endif
-- BIT(NL80211_IFTYPE_ADHOC) },
--};
--
- static const struct ieee80211_iface_combination if_comb[] = {
- {
- .limits = if_limits,
-@@ -766,6 +758,11 @@ static const struct ieee80211_iface_comb
- .max_interfaces = 2048,
- .num_different_channels = 1,
- .beacon_int_infra_match = true,
-+#ifdef CPTCFG_ATH9K_DFS_CERTIFIED
-+ .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
-+ BIT(NL80211_CHAN_WIDTH_20) |
-+ BIT(NL80211_CHAN_WIDTH_40),
-+#endif
- },
- {
- .limits = wds_limits,
-@@ -774,18 +771,6 @@ static const struct ieee80211_iface_comb
- .num_different_channels = 1,
- .beacon_int_infra_match = true,
- },
--#ifdef CPTCFG_ATH9K_DFS_CERTIFIED
-- {
-- .limits = if_dfs_limits,
-- .n_limits = ARRAY_SIZE(if_dfs_limits),
-- .max_interfaces = 1,
-- .num_different_channels = 1,
-- .beacon_int_infra_match = true,
-- .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
-- BIT(NL80211_CHAN_WIDTH_20) |
-- BIT(NL80211_CHAN_WIDTH_40),
-- }
--#endif
- };
-
- #ifdef CPTCFG_ATH9K_CHANNEL_CONTEXT
diff --git a/package/kernel/mac80211/patches/312-mac80211-fix-txq-queue-related-crashes.patch b/package/kernel/mac80211/patches/312-mac80211-fix-txq-queue-related-crashes.patch
deleted file mode 100644
index 61cafc7625..0000000000
--- a/package/kernel/mac80211/patches/312-mac80211-fix-txq-queue-related-crashes.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-From: Michal Kazior <michal.kazior@tieto.com>
-Date: Thu, 21 Jan 2016 14:23:07 +0100
-Subject: [PATCH] mac80211: fix txq queue related crashes
-
-The driver can access the queue simultanously
-while mac80211 tears down the interface. Without
-spinlock protection this could lead to corrupting
-sk_buff_head and subsequently to an invalid
-pointer dereference.
-
-Fixes: ba8c3d6f16a1 ("mac80211: add an intermediate software queue implementation")
-Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
----
-
---- a/net/mac80211/iface.c
-+++ b/net/mac80211/iface.c
-@@ -977,7 +977,10 @@ static void ieee80211_do_stop(struct iee
- if (sdata->vif.txq) {
- struct txq_info *txqi = to_txq_info(sdata->vif.txq);
-
-+ spin_lock_bh(&txqi->queue.lock);
- ieee80211_purge_tx_queue(&local->hw, &txqi->queue);
-+ spin_unlock_bh(&txqi->queue.lock);
-+
- atomic_set(&sdata->txqs_len[txqi->txq.ac], 0);
- }
-
diff --git a/package/kernel/mac80211/patches/313-mac80211-fix-unnecessary-frame-drops-in-mesh-fwding.patch b/package/kernel/mac80211/patches/313-mac80211-fix-unnecessary-frame-drops-in-mesh-fwding.patch
deleted file mode 100644
index 844d43bfc7..0000000000
--- a/package/kernel/mac80211/patches/313-mac80211-fix-unnecessary-frame-drops-in-mesh-fwding.patch
+++ /dev/null
@@ -1,57 +0,0 @@
-From: Michal Kazior <michal.kazior@tieto.com>
-Date: Mon, 25 Jan 2016 14:43:24 +0100
-Subject: [PATCH] mac80211: fix unnecessary frame drops in mesh fwding
-
-The ieee80211_queue_stopped() expects hw queue
-number but it was given raw WMM AC number instead.
-
-This could cause frame drops and problems with
-traffic in some cases - most notably if driver
-doesn't map AC numbers to queue numbers 1:1 and
-uses ieee80211_stop_queues() and
-ieee80211_wake_queue() only without ever calling
-ieee80211_wake_queues().
-
-On ath10k it was possible to hit this problem in
-the following case:
-
- 1. wlan0 uses queue 0
- (ath10k maps queues per vif)
- 2. offchannel uses queue 15
- 3. queues 1-14 are unused
- 4. ieee80211_stop_queues()
- 5. ieee80211_wake_queue(q=0)
- 6. ieee80211_wake_queue(q=15)
- (other queues are not woken up because both
- driver and mac80211 know other queues are
- unused)
- 7. ieee80211_rx_h_mesh_fwding()
- 8. ieee80211_select_queue_80211() returns 2
- 9. ieee80211_queue_stopped(q=2) returns true
- 10. frame is dropped (oops!)
-
-Fixes: d3c1597b8d1b ("mac80211: fix forwarded mesh frame queue mapping")
-Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
----
-
---- a/net/mac80211/rx.c
-+++ b/net/mac80211/rx.c
-@@ -2235,7 +2235,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
- struct ieee80211_local *local = rx->local;
- struct ieee80211_sub_if_data *sdata = rx->sdata;
- struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
-- u16 q, hdrlen;
-+ u16 ac, q, hdrlen;
-
- hdr = (struct ieee80211_hdr *) skb->data;
- hdrlen = ieee80211_hdrlen(hdr->frame_control);
-@@ -2304,7 +2304,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
- ether_addr_equal(sdata->vif.addr, hdr->addr3))
- return RX_CONTINUE;
-
-- q = ieee80211_select_queue_80211(sdata, skb, hdr);
-+ ac = ieee80211_select_queue_80211(sdata, skb, hdr);
-+ q = sdata->vif.hw_queue[ac];
- if (ieee80211_queue_stopped(&local->hw, q)) {
- IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_congestion);
- return RX_DROP_MONITOR;
diff --git a/package/kernel/mac80211/patches/314-mac80211-Requeue-work-after-scan-complete-for-all-VI.patch b/package/kernel/mac80211/patches/314-mac80211-Requeue-work-after-scan-complete-for-all-VI.patch
deleted file mode 100644
index 5b3efbdc5a..0000000000
--- a/package/kernel/mac80211/patches/314-mac80211-Requeue-work-after-scan-complete-for-all-VI.patch
+++ /dev/null
@@ -1,103 +0,0 @@
-From: Sachin Kulkarni <Sachin.Kulkarni@imgtec.com>
-Date: Tue, 12 Jan 2016 14:30:19 +0530
-Subject: [PATCH] mac80211: Requeue work after scan complete for all VIF
- types.
-
-During a sw scan ieee80211_iface_work ignores work items for all vifs.
-However after the scan complete work is requeued only for STA, ADHOC
-and MESH iftypes.
-
-This occasionally results in event processing getting delayed/not
-processed for iftype AP when it coexists with a STA. This can result
-in data halt and eventually disconnection on the AP interface.
-
-Signed-off-by: Sachin Kulkarni <Sachin.Kulkarni@imgtec.com>
-Cc: linux-wireless@vger.kernel.org
-Cc: johannes@sipsolutions.net
----
-
---- a/net/mac80211/ibss.c
-+++ b/net/mac80211/ibss.c
-@@ -1731,7 +1731,6 @@ void ieee80211_ibss_notify_scan_complete
- if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
- continue;
- sdata->u.ibss.last_scan_completed = jiffies;
-- ieee80211_queue_work(&local->hw, &sdata->work);
- }
- mutex_unlock(&local->iflist_mtx);
- }
---- a/net/mac80211/mesh.c
-+++ b/net/mac80211/mesh.c
-@@ -1369,17 +1369,6 @@ out:
- sdata_unlock(sdata);
- }
-
--void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local)
--{
-- struct ieee80211_sub_if_data *sdata;
--
-- rcu_read_lock();
-- list_for_each_entry_rcu(sdata, &local->interfaces, list)
-- if (ieee80211_vif_is_mesh(&sdata->vif) &&
-- ieee80211_sdata_running(sdata))
-- ieee80211_queue_work(&local->hw, &sdata->work);
-- rcu_read_unlock();
--}
-
- void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
- {
---- a/net/mac80211/mesh.h
-+++ b/net/mac80211/mesh.h
-@@ -362,14 +362,10 @@ static inline bool mesh_path_sel_is_hwmp
- return sdata->u.mesh.mesh_pp_id == IEEE80211_PATH_PROTOCOL_HWMP;
- }
-
--void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local);
--
- void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata);
- void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata);
- void ieee80211s_stop(void);
- #else
--static inline void
--ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) {}
- static inline bool mesh_path_sel_is_hwmp(struct ieee80211_sub_if_data *sdata)
- { return false; }
- static inline void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata)
---- a/net/mac80211/mlme.c
-+++ b/net/mac80211/mlme.c
-@@ -3978,8 +3978,6 @@ static void ieee80211_restart_sta_timer(
- if (!ieee80211_hw_check(&sdata->local->hw, CONNECTION_MONITOR))
- ieee80211_queue_work(&sdata->local->hw,
- &sdata->u.mgd.monitor_work);
-- /* and do all the other regular work too */
-- ieee80211_queue_work(&sdata->local->hw, &sdata->work);
- }
- }
-
---- a/net/mac80211/scan.c
-+++ b/net/mac80211/scan.c
-@@ -314,6 +314,7 @@ static void __ieee80211_scan_completed(s
- bool was_scanning = local->scanning;
- struct cfg80211_scan_request *scan_req;
- struct ieee80211_sub_if_data *scan_sdata;
-+ struct ieee80211_sub_if_data *sdata;
-
- lockdep_assert_held(&local->mtx);
-
-@@ -373,7 +374,15 @@ static void __ieee80211_scan_completed(s
-
- ieee80211_mlme_notify_scan_completed(local);
- ieee80211_ibss_notify_scan_completed(local);
-- ieee80211_mesh_notify_scan_completed(local);
-+
-+ /* Requeue all the work that might have been ignored while
-+ * the scan was in progress
-+ */
-+ list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-+ if (ieee80211_sdata_running(sdata))
-+ ieee80211_queue_work(&sdata->local->hw, &sdata->work);
-+ }
-+
- if (was_scanning)
- ieee80211_start_next_roc(local);
- }
diff --git a/package/kernel/mac80211/patches/315-mac80211-fix-ibss-scan-parameters.patch b/package/kernel/mac80211/patches/315-mac80211-fix-ibss-scan-parameters.patch
deleted file mode 100644
index 52fecb96b0..0000000000
--- a/package/kernel/mac80211/patches/315-mac80211-fix-ibss-scan-parameters.patch
+++ /dev/null
@@ -1,57 +0,0 @@
-From: Sara Sharon <sara.sharon@intel.com>
-Date: Mon, 25 Jan 2016 15:46:35 +0200
-Subject: [PATCH] mac80211: fix ibss scan parameters
-
-When joining IBSS a full scan should be initiated in order to search
-for existing cell, unless the fixed_channel parameter was set.
-A default channel to create the IBSS on if no cell was found is
-provided as well.
-However - a scan is initiated only on the default channel provided
-regardless of whether ifibss->fixed_channel is set or not, with the
-obvious result of the cell not joining existing IBSS cell that is
-on another channel.
-
-Fixes: 76bed0f43b27 ("mac80211: IBSS fix scan request")
-Signed-off-by: Sara Sharon <sara.sharon@intel.com>
-Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
----
-
---- a/net/mac80211/ibss.c
-+++ b/net/mac80211/ibss.c
-@@ -7,6 +7,7 @@
- * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
- * Copyright 2009, Johannes Berg <johannes@sipsolutions.net>
- * Copyright 2013-2014 Intel Mobile Communications GmbH
-+ * Copyright(c) 2016 Intel Deutschland GmbH
- *
- * 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
-@@ -1483,14 +1484,21 @@ static void ieee80211_sta_find_ibss(stru
-
- sdata_info(sdata, "Trigger new scan to find an IBSS to join\n");
-
-- num = ieee80211_ibss_setup_scan_channels(local->hw.wiphy,
-- &ifibss->chandef,
-- channels,
-- ARRAY_SIZE(channels));
- scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef);
-- ieee80211_request_ibss_scan(sdata, ifibss->ssid,
-- ifibss->ssid_len, channels, num,
-- scan_width);
-+
-+ if (ifibss->fixed_channel) {
-+ num = ieee80211_ibss_setup_scan_channels(local->hw.wiphy,
-+ &ifibss->chandef,
-+ channels,
-+ ARRAY_SIZE(channels));
-+ ieee80211_request_ibss_scan(sdata, ifibss->ssid,
-+ ifibss->ssid_len, channels,
-+ num, scan_width);
-+ } else {
-+ ieee80211_request_ibss_scan(sdata, ifibss->ssid,
-+ ifibss->ssid_len, NULL,
-+ 0, scan_width);
-+ }
- } else {
- int interval = IEEE80211_SCAN_INTERVAL;
-
diff --git a/package/kernel/mac80211/patches/316-net-mac80211-agg-rx.c-fix-use-of-uninitialised-value.patch b/package/kernel/mac80211/patches/316-net-mac80211-agg-rx.c-fix-use-of-uninitialised-value.patch
deleted file mode 100644
index e78df36600..0000000000
--- a/package/kernel/mac80211/patches/316-net-mac80211-agg-rx.c-fix-use-of-uninitialised-value.patch
+++ /dev/null
@@ -1,50 +0,0 @@
-From: Chris Bainbridge <chris.bainbridge@gmail.com>
-Date: Wed, 27 Jan 2016 15:46:18 +0000
-Subject: [PATCH] net/mac80211/agg-rx.c: fix use of uninitialised values
-
-Use kzalloc instead of kmalloc for struct tid_ampdu_rx. Fixes:
-
-[ 7.976605] UBSAN: Undefined behaviour in net/mac80211/rx.c:932:29
-[ 7.976608] load of value 2 is not a valid value for type '_Bool'
-[ 7.976611] CPU: 3 PID: 1134 Comm: kworker/u16:7 Not tainted 4.5.0-rc1+ #265
-[ 7.976613] Hardware name: Apple Inc. MacBookPro10,2/Mac-AFD8A9D944EA4843, BIOS MBP102.88Z.0106.B0A.1509130955 09/13/2015
-[ 7.976616] Workqueue: phy0 rt2x00usb_work_rxdone
-[ 7.976619] 0000000000000004 ffff880254a7ba50 ffffffff8181d866 0000000000000007
-[ 7.976622] ffff880254a7ba78 ffff880254a7ba68 ffffffff8188422d ffffffff8379b500
-[ 7.976626] ffff880254a7bab8 ffffffff81884747 0000000000000202 0000000348620032
-[ 7.976629] Call Trace:
-[ 7.976633] [<ffffffff8181d866>] dump_stack+0x45/0x5f
-[ 7.976637] [<ffffffff8188422d>] ubsan_epilogue+0xd/0x40
-[ 7.976642] [<ffffffff81884747>] __ubsan_handle_load_invalid_value+0x67/0x70
-[ 7.976646] [<ffffffff82227b4d>] ieee80211_sta_reorder_release.isra.16+0x5ed/0x730
-[ 7.976650] [<ffffffff8222ca14>] ieee80211_prepare_and_rx_handle+0xd04/0x1c00
-[ 7.976654] [<ffffffff81cb27ce>] ? usb_hcd_map_urb_for_dma+0x65e/0x960
-[ 7.976659] [<ffffffff8222db03>] __ieee80211_rx_handle_packet+0x1f3/0x750
-[ 7.976663] [<ffffffff8222e4a7>] ieee80211_rx_napi+0x447/0x990
-[ 7.976667] [<ffffffff81c5fb85>] rt2x00lib_rxdone+0x305/0xbd0
-[ 7.976670] [<ffffffff811ac23f>] ? dequeue_task_fair+0x64f/0x1de0
-[ 7.976674] [<ffffffff811a1516>] ? sched_clock_cpu+0xe6/0x150
-[ 7.976678] [<ffffffff81c6c45c>] rt2x00usb_work_rxdone+0x7c/0x140
-[ 7.976682] [<ffffffff8117aef6>] process_one_work+0x226/0x860
-[ 7.976686] [<ffffffff8117b58c>] worker_thread+0x5c/0x680
-[ 7.976690] [<ffffffff8117b530>] ? process_one_work+0x860/0x860
-[ 7.976693] [<ffffffff81184f86>] kthread+0xf6/0x150
-[ 7.976697] [<ffffffff81184e90>] ? kthread_worker_fn+0x310/0x310
-[ 7.976700] [<ffffffff822a94df>] ret_from_fork+0x3f/0x70
-[ 7.976703] [<ffffffff81184e90>] ? kthread_worker_fn+0x310/0x310
-
-Link: https://lkml.org/lkml/2016/1/26/230
-Signed-off-by: Chris Bainbridge <chris.bainbridge@gmail.com>
----
-
---- a/net/mac80211/agg-rx.c
-+++ b/net/mac80211/agg-rx.c
-@@ -327,7 +327,7 @@ void __ieee80211_start_rx_ba_session(str
- }
-
- /* prepare A-MPDU MLME for Rx aggregation */
-- tid_agg_rx = kmalloc(sizeof(struct tid_ampdu_rx), GFP_KERNEL);
-+ tid_agg_rx = kzalloc(sizeof(struct tid_ampdu_rx), GFP_KERNEL);
- if (!tid_agg_rx)
- goto end;
-
diff --git a/package/kernel/mac80211/patches/317-mac80211-minstrel_ht-fix-out-of-bound-in-minstrel_ht.patch b/package/kernel/mac80211/patches/317-mac80211-minstrel_ht-fix-out-of-bound-in-minstrel_ht.patch
deleted file mode 100644
index 5bf53b918c..0000000000
--- a/package/kernel/mac80211/patches/317-mac80211-minstrel_ht-fix-out-of-bound-in-minstrel_ht.patch
+++ /dev/null
@@ -1,45 +0,0 @@
-From: Konstantin Khlebnikov <koct9i@gmail.com>
-Date: Fri, 29 Jan 2016 11:35:12 +0300
-Subject: [PATCH] mac80211: minstrel_ht: fix out-of-bound in
- minstrel_ht_set_best_prob_rate
-
-Patch fixes this splat
-
-BUG: KASAN: slab-out-of-bounds in minstrel_ht_update_stats.isra.7+0x6e1/0x9e0
-[mac80211] at addr ffff8800cee640f4 Read of size 4 by task swapper/3/0
-
-Signed-off-by: Konstantin Khlebnikov <koct9i@gmail.com>
-Link: http://lkml.kernel.org/r/CALYGNiNyJhSaVnE35qS6UCGaSb2Dx1_i5HcRavuOX14oTz2P+w@mail.gmail.com
----
-
---- a/net/mac80211/rc80211_minstrel_ht.c
-+++ b/net/mac80211/rc80211_minstrel_ht.c
-@@ -414,15 +414,16 @@ minstrel_ht_set_best_prob_rate(struct mi
- (max_tp_group != MINSTREL_CCK_GROUP))
- return;
-
-+ max_gpr_group = mg->max_group_prob_rate / MCS_GROUP_RATES;
-+ max_gpr_idx = mg->max_group_prob_rate % MCS_GROUP_RATES;
-+ max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_ewma;
-+
- if (mrs->prob_ewma > MINSTREL_FRAC(75, 100)) {
- cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx,
- mrs->prob_ewma);
- if (cur_tp_avg > tmp_tp_avg)
- mi->max_prob_rate = index;
-
-- max_gpr_group = mg->max_group_prob_rate / MCS_GROUP_RATES;
-- max_gpr_idx = mg->max_group_prob_rate % MCS_GROUP_RATES;
-- max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_ewma;
- max_gpr_tp_avg = minstrel_ht_get_tp_avg(mi, max_gpr_group,
- max_gpr_idx,
- max_gpr_prob);
-@@ -431,7 +432,7 @@ minstrel_ht_set_best_prob_rate(struct mi
- } else {
- if (mrs->prob_ewma > tmp_prob)
- mi->max_prob_rate = index;
-- if (mrs->prob_ewma > mg->rates[mg->max_group_prob_rate].prob_ewma)
-+ if (mrs->prob_ewma > max_gpr_prob)
- mg->max_group_prob_rate = index;
- }
- }
diff --git a/package/kernel/mac80211/patches/318-mac80211-move-A-MSDU-skb_linearize-call-to-ieee80211.patch b/package/kernel/mac80211/patches/318-mac80211-move-A-MSDU-skb_linearize-call-to-ieee80211.patch
deleted file mode 100644
index 881fcf4591..0000000000
--- a/package/kernel/mac80211/patches/318-mac80211-move-A-MSDU-skb_linearize-call-to-ieee80211.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Tue, 2 Feb 2016 14:39:08 +0100
-Subject: [PATCH] mac80211: move A-MSDU skb_linearize call to
- ieee80211_amsdu_to_8023s
-
-Prepararation for zero-copy A-MSDU support with page fragment SKBs
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
-
---- a/net/mac80211/rx.c
-+++ b/net/mac80211/rx.c
-@@ -2203,9 +2203,6 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx
- skb->dev = dev;
- __skb_queue_head_init(&frame_list);
-
-- if (skb_linearize(skb))
-- return RX_DROP_UNUSABLE;
--
- ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
- rx->sdata->vif.type,
- rx->local->hw.extra_tx_headroom, true);
---- a/net/wireless/util.c
-+++ b/net/wireless/util.c
-@@ -657,6 +657,9 @@ void ieee80211_amsdu_to_8023s(struct sk_
- int remaining, err;
- u8 dst[ETH_ALEN], src[ETH_ALEN];
-
-+ if (skb_linearize(skb))
-+ goto out;
-+
- if (has_80211_header) {
- err = ieee80211_data_to_8023(skb, addr, iftype);
- if (err)
diff --git a/package/kernel/mac80211/patches/319-cfg80211-add-function-for-802.3-conversion-with-sepa.patch b/package/kernel/mac80211/patches/319-cfg80211-add-function-for-802.3-conversion-with-sepa.patch
deleted file mode 100644
index b3516079e1..0000000000
--- a/package/kernel/mac80211/patches/319-cfg80211-add-function-for-802.3-conversion-with-sepa.patch
+++ /dev/null
@@ -1,186 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Tue, 2 Feb 2016 14:39:09 +0100
-Subject: [PATCH] cfg80211: add function for 802.3 conversion with separate
- output buffer
-
-Use skb_copy_bits in preparation for allowing fragmented skbs
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
-
---- a/net/wireless/util.c
-+++ b/net/wireless/util.c
-@@ -393,9 +393,9 @@ unsigned int ieee80211_get_hdrlen_from_s
- }
- EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
-
--unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
-+static unsigned int __ieee80211_get_mesh_hdrlen(u8 flags)
- {
-- int ae = meshhdr->flags & MESH_FLAGS_AE;
-+ int ae = flags & MESH_FLAGS_AE;
- /* 802.11-2012, 8.2.4.7.3 */
- switch (ae) {
- default:
-@@ -407,21 +407,31 @@ unsigned int ieee80211_get_mesh_hdrlen(s
- return 18;
- }
- }
-+
-+unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
-+{
-+ return __ieee80211_get_mesh_hdrlen(meshhdr->flags);
-+}
- EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen);
-
--int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
-- enum nl80211_iftype iftype)
-+static int __ieee80211_data_to_8023(struct sk_buff *skb, struct ethhdr *ehdr,
-+ const u8 *addr, enum nl80211_iftype iftype)
- {
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-- u16 hdrlen, ethertype;
-- u8 *payload;
-- u8 dst[ETH_ALEN];
-- u8 src[ETH_ALEN] __aligned(2);
-+ struct {
-+ u8 hdr[ETH_ALEN] __aligned(2);
-+ __be16 proto;
-+ } payload;
-+ struct ethhdr tmp;
-+ u16 hdrlen;
-+ u8 mesh_flags = 0;
-
- if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
- return -1;
-
- hdrlen = ieee80211_hdrlen(hdr->frame_control);
-+ if (skb->len < hdrlen + 8)
-+ return -1;
-
- /* convert IEEE 802.11 header + possible LLC headers into Ethernet
- * header
-@@ -432,8 +442,11 @@ int ieee80211_data_to_8023(struct sk_buf
- * 1 0 BSSID SA DA n/a
- * 1 1 RA TA DA SA
- */
-- memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN);
-- memcpy(src, ieee80211_get_SA(hdr), ETH_ALEN);
-+ memcpy(tmp.h_dest, ieee80211_get_DA(hdr), ETH_ALEN);
-+ memcpy(tmp.h_source, ieee80211_get_SA(hdr), ETH_ALEN);
-+
-+ if (iftype == NL80211_IFTYPE_MESH_POINT)
-+ skb_copy_bits(skb, hdrlen, &mesh_flags, 1);
-
- switch (hdr->frame_control &
- cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
-@@ -450,44 +463,31 @@ int ieee80211_data_to_8023(struct sk_buf
- iftype != NL80211_IFTYPE_STATION))
- return -1;
- if (iftype == NL80211_IFTYPE_MESH_POINT) {
-- struct ieee80211s_hdr *meshdr =
-- (struct ieee80211s_hdr *) (skb->data + hdrlen);
-- /* make sure meshdr->flags is on the linear part */
-- if (!pskb_may_pull(skb, hdrlen + 1))
-- return -1;
-- if (meshdr->flags & MESH_FLAGS_AE_A4)
-+ if (mesh_flags & MESH_FLAGS_AE_A4)
- return -1;
-- if (meshdr->flags & MESH_FLAGS_AE_A5_A6) {
-+ if (mesh_flags & MESH_FLAGS_AE_A5_A6) {
- skb_copy_bits(skb, hdrlen +
- offsetof(struct ieee80211s_hdr, eaddr1),
-- dst, ETH_ALEN);
-- skb_copy_bits(skb, hdrlen +
-- offsetof(struct ieee80211s_hdr, eaddr2),
-- src, ETH_ALEN);
-+ tmp.h_dest, 2 * ETH_ALEN);
- }
-- hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
-+ hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags);
- }
- break;
- case cpu_to_le16(IEEE80211_FCTL_FROMDS):
- if ((iftype != NL80211_IFTYPE_STATION &&
- iftype != NL80211_IFTYPE_P2P_CLIENT &&
- iftype != NL80211_IFTYPE_MESH_POINT) ||
-- (is_multicast_ether_addr(dst) &&
-- ether_addr_equal(src, addr)))
-+ (is_multicast_ether_addr(tmp.h_dest) &&
-+ ether_addr_equal(tmp.h_source, addr)))
- return -1;
- if (iftype == NL80211_IFTYPE_MESH_POINT) {
-- struct ieee80211s_hdr *meshdr =
-- (struct ieee80211s_hdr *) (skb->data + hdrlen);
-- /* make sure meshdr->flags is on the linear part */
-- if (!pskb_may_pull(skb, hdrlen + 1))
-- return -1;
-- if (meshdr->flags & MESH_FLAGS_AE_A5_A6)
-+ if (mesh_flags & MESH_FLAGS_AE_A5_A6)
- return -1;
-- if (meshdr->flags & MESH_FLAGS_AE_A4)
-+ if (mesh_flags & MESH_FLAGS_AE_A4)
- skb_copy_bits(skb, hdrlen +
- offsetof(struct ieee80211s_hdr, eaddr1),
-- src, ETH_ALEN);
-- hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
-+ tmp.h_source, ETH_ALEN);
-+ hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags);
- }
- break;
- case cpu_to_le16(0):
-@@ -498,33 +498,33 @@ int ieee80211_data_to_8023(struct sk_buf
- break;
- }
-
-- if (!pskb_may_pull(skb, hdrlen + 8))
-- return -1;
--
-- payload = skb->data + hdrlen;
-- ethertype = (payload[6] << 8) | payload[7];
-+ skb_copy_bits(skb, hdrlen, &payload, sizeof(payload));
-+ tmp.h_proto = payload.proto;
-
-- if (likely((ether_addr_equal(payload, rfc1042_header) &&
-- ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
-- ether_addr_equal(payload, bridge_tunnel_header))) {
-+ if (likely((ether_addr_equal(payload.hdr, rfc1042_header) &&
-+ tmp.h_proto != htons(ETH_P_AARP) &&
-+ tmp.h_proto != htons(ETH_P_IPX)) ||
-+ ether_addr_equal(payload.hdr, bridge_tunnel_header)))
- /* remove RFC1042 or Bridge-Tunnel encapsulation and
- * replace EtherType */
-- skb_pull(skb, hdrlen + 6);
-- memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
-- memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
-- } else {
-- struct ethhdr *ehdr;
-- __be16 len;
-+ hdrlen += ETH_ALEN + 2;
-+ else
-+ tmp.h_proto = htons(skb->len);
-
-- skb_pull(skb, hdrlen);
-- len = htons(skb->len);
-+ pskb_pull(skb, hdrlen);
-+
-+ if (!ehdr)
- ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr));
-- memcpy(ehdr->h_dest, dst, ETH_ALEN);
-- memcpy(ehdr->h_source, src, ETH_ALEN);
-- ehdr->h_proto = len;
-- }
-+ memcpy(ehdr, &tmp, sizeof(tmp));
-+
- return 0;
- }
-+
-+int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
-+ enum nl80211_iftype iftype)
-+{
-+ return __ieee80211_data_to_8023(skb, NULL, addr, iftype);
-+}
- EXPORT_SYMBOL(ieee80211_data_to_8023);
-
- int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
diff --git a/package/kernel/mac80211/patches/320-cfg80211-add-support-for-non-linear-skbs-in-ieee8021.patch b/package/kernel/mac80211/patches/320-cfg80211-add-support-for-non-linear-skbs-in-ieee8021.patch
deleted file mode 100644
index 8081f4b643..0000000000
--- a/package/kernel/mac80211/patches/320-cfg80211-add-support-for-non-linear-skbs-in-ieee8021.patch
+++ /dev/null
@@ -1,159 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Tue, 2 Feb 2016 14:39:10 +0100
-Subject: [PATCH] cfg80211: add support for non-linear skbs in
- ieee80211_amsdu_to_8023s
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
-
---- a/net/wireless/util.c
-+++ b/net/wireless/util.c
-@@ -644,73 +644,75 @@ int ieee80211_data_from_8023(struct sk_b
- }
- EXPORT_SYMBOL(ieee80211_data_from_8023);
-
-+static struct sk_buff *
-+__ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen,
-+ int offset, int len)
-+{
-+ struct sk_buff *frame;
-+
-+ if (skb->len - offset < len)
-+ return NULL;
-+
-+ /*
-+ * Allocate and reserve two bytes more for payload
-+ * alignment since sizeof(struct ethhdr) is 14.
-+ */
-+ frame = dev_alloc_skb(hlen + sizeof(struct ethhdr) + 2 + len);
-+
-+ skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2);
-+ skb_copy_bits(skb, offset, skb_put(frame, len), len);
-+
-+ return frame;
-+}
-
- void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
- const u8 *addr, enum nl80211_iftype iftype,
- const unsigned int extra_headroom,
- bool has_80211_header)
- {
-+ unsigned int hlen = ALIGN(extra_headroom, 4);
- struct sk_buff *frame = NULL;
- u16 ethertype;
- u8 *payload;
-- const struct ethhdr *eth;
-- int remaining, err;
-- u8 dst[ETH_ALEN], src[ETH_ALEN];
--
-- if (skb_linearize(skb))
-- goto out;
-+ int offset = 0, remaining, err;
-+ struct ethhdr eth;
-+ bool reuse_skb = true;
-+ bool last = false;
-
- if (has_80211_header) {
-- err = ieee80211_data_to_8023(skb, addr, iftype);
-+ err = __ieee80211_data_to_8023(skb, &eth, addr, iftype);
- if (err)
- goto out;
--
-- /* skip the wrapping header */
-- eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr));
-- if (!eth)
-- goto out;
-- } else {
-- eth = (struct ethhdr *) skb->data;
- }
-
-- while (skb != frame) {
-+ while (!last) {
-+ unsigned int subframe_len;
-+ int len;
- u8 padding;
-- __be16 len = eth->h_proto;
-- unsigned int subframe_len = sizeof(struct ethhdr) + ntohs(len);
--
-- remaining = skb->len;
-- memcpy(dst, eth->h_dest, ETH_ALEN);
-- memcpy(src, eth->h_source, ETH_ALEN);
-
-+ skb_copy_bits(skb, offset, &eth, sizeof(eth));
-+ len = ntohs(eth.h_proto);
-+ subframe_len = sizeof(struct ethhdr) + len;
- padding = (4 - subframe_len) & 0x3;
-+
- /* the last MSDU has no padding */
-+ remaining = skb->len - offset;
- if (subframe_len > remaining)
- goto purge;
-
-- skb_pull(skb, sizeof(struct ethhdr));
-+ offset += sizeof(struct ethhdr);
- /* reuse skb for the last subframe */
-- if (remaining <= subframe_len + padding)
-+ last = remaining <= subframe_len + padding;
-+ if (!skb_is_nonlinear(skb) && last) {
-+ skb_pull(skb, offset);
- frame = skb;
-- else {
-- unsigned int hlen = ALIGN(extra_headroom, 4);
-- /*
-- * Allocate and reserve two bytes more for payload
-- * alignment since sizeof(struct ethhdr) is 14.
-- */
-- frame = dev_alloc_skb(hlen + subframe_len + 2);
-+ reuse_skb = true;
-+ } else {
-+ frame = __ieee80211_amsdu_copy(skb, hlen, offset, len);
- if (!frame)
- goto purge;
-
-- skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2);
-- memcpy(skb_put(frame, ntohs(len)), skb->data,
-- ntohs(len));
--
-- eth = (struct ethhdr *)skb_pull(skb, ntohs(len) +
-- padding);
-- if (!eth) {
-- dev_kfree_skb(frame);
-- goto purge;
-- }
-+ offset += len + padding;
- }
-
- skb_reset_network_header(frame);
-@@ -719,24 +721,20 @@ void ieee80211_amsdu_to_8023s(struct sk_
-
- payload = frame->data;
- ethertype = (payload[6] << 8) | payload[7];
--
- if (likely((ether_addr_equal(payload, rfc1042_header) &&
- ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
- ether_addr_equal(payload, bridge_tunnel_header))) {
-- /* remove RFC1042 or Bridge-Tunnel
-- * encapsulation and replace EtherType */
-- skb_pull(frame, 6);
-- memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
-- memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
-- } else {
-- memcpy(skb_push(frame, sizeof(__be16)), &len,
-- sizeof(__be16));
-- memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
-- memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
-+ eth.h_proto = htons(ethertype);
-+ skb_pull(frame, ETH_ALEN + 2);
- }
-+
-+ memcpy(skb_push(frame, sizeof(eth)), &eth, sizeof(eth));
- __skb_queue_tail(list, frame);
- }
-
-+ if (!reuse_skb)
-+ dev_kfree_skb(skb);
-+
- return;
-
- purge:
diff --git a/package/kernel/mac80211/patches/321-mac80211-Parse-legacy-and-HT-rate-in-injected-frames.patch b/package/kernel/mac80211/patches/321-mac80211-Parse-legacy-and-HT-rate-in-injected-frames.patch
deleted file mode 100644
index c4155a1181..0000000000
--- a/package/kernel/mac80211/patches/321-mac80211-Parse-legacy-and-HT-rate-in-injected-frames.patch
+++ /dev/null
@@ -1,155 +0,0 @@
-From: Sven Eckelmann <sven@narfation.org>
-Date: Tue, 26 Jan 2016 17:11:13 +0100
-Subject: [PATCH] mac80211: Parse legacy and HT rate in injected frames
-
-Drivers/devices without their own rate control algorithm can get the
-information what rates they should use from either the radiotap header of
-injected frames or from the rate control algorithm. But the parsing of the
-legacy rate information from the radiotap header was removed in commit
-e6a9854b05c1 ("mac80211/drivers: rewrite the rate control API").
-
-The removal of this feature heavily reduced the usefulness of frame
-injection when wanting to simulate specific transmission behavior. Having
-rate parsing together with MCS rates and retry support allows a fine
-grained selection of the tx behavior of injected frames for these kind of
-tests.
-
-Signed-off-by: Sven Eckelmann <sven@narfation.org>
-Cc: Simon Wunderlich <sw@simonwunderlich.de>
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
-
---- a/include/net/mac80211.h
-+++ b/include/net/mac80211.h
-@@ -708,12 +708,14 @@ enum mac80211_tx_info_flags {
- * protocol frame (e.g. EAP)
- * @IEEE80211_TX_CTRL_PS_RESPONSE: This frame is a response to a poll
- * frame (PS-Poll or uAPSD).
-+ * @IEEE80211_TX_CTRL_RATE_INJECT: This frame is injected with rate information
- *
- * These flags are used in tx_info->control.flags.
- */
- enum mac80211_tx_control_flags {
- IEEE80211_TX_CTRL_PORT_CTRL_PROTO = BIT(0),
- IEEE80211_TX_CTRL_PS_RESPONSE = BIT(1),
-+ IEEE80211_TX_CTRL_RATE_INJECT = BIT(2),
- };
-
- /*
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -710,6 +710,10 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021
-
- info->control.short_preamble = txrc.short_preamble;
-
-+ /* don't ask rate control when rate already injected via radiotap */
-+ if (info->control.flags & IEEE80211_TX_CTRL_RATE_INJECT)
-+ return TX_CONTINUE;
-+
- if (tx->sta)
- assoc = test_sta_flag(tx->sta, WLAN_STA_ASSOC);
-
-@@ -1665,15 +1669,24 @@ void ieee80211_xmit(struct ieee80211_sub
- ieee80211_tx(sdata, sta, skb, false);
- }
-
--static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb)
-+static bool ieee80211_parse_tx_radiotap(struct ieee80211_local *local,
-+ struct sk_buff *skb)
- {
- struct ieee80211_radiotap_iterator iterator;
- struct ieee80211_radiotap_header *rthdr =
- (struct ieee80211_radiotap_header *) skb->data;
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-+ struct ieee80211_supported_band *sband =
-+ local->hw.wiphy->bands[info->band];
- int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len,
- NULL);
- u16 txflags;
-+ u16 rate = 0;
-+ bool rate_found = false;
-+ u8 rate_retries = 0;
-+ u16 rate_flags = 0;
-+ u8 mcs_known, mcs_flags;
-+ int i;
-
- info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
- IEEE80211_TX_CTL_DONTFRAG;
-@@ -1724,6 +1737,35 @@ static bool ieee80211_parse_tx_radiotap(
- info->flags |= IEEE80211_TX_CTL_NO_ACK;
- break;
-
-+ case IEEE80211_RADIOTAP_RATE:
-+ rate = *iterator.this_arg;
-+ rate_flags = 0;
-+ rate_found = true;
-+ break;
-+
-+ case IEEE80211_RADIOTAP_DATA_RETRIES:
-+ rate_retries = *iterator.this_arg;
-+ break;
-+
-+ case IEEE80211_RADIOTAP_MCS:
-+ mcs_known = iterator.this_arg[0];
-+ mcs_flags = iterator.this_arg[1];
-+ if (!(mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_MCS))
-+ break;
-+
-+ rate_found = true;
-+ rate = iterator.this_arg[2];
-+ rate_flags = IEEE80211_TX_RC_MCS;
-+
-+ if (mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_GI &&
-+ mcs_flags & IEEE80211_RADIOTAP_MCS_SGI)
-+ rate_flags |= IEEE80211_TX_RC_SHORT_GI;
-+
-+ if (mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_BW &&
-+ mcs_flags & IEEE80211_RADIOTAP_MCS_BW_40)
-+ rate_flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
-+ break;
-+
- /*
- * Please update the file
- * Documentation/networking/mac80211-injection.txt
-@@ -1738,6 +1780,32 @@ static bool ieee80211_parse_tx_radiotap(
- if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */
- return false;
-
-+ if (rate_found) {
-+ info->control.flags |= IEEE80211_TX_CTRL_RATE_INJECT;
-+
-+ for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
-+ info->control.rates[i].idx = -1;
-+ info->control.rates[i].flags = 0;
-+ info->control.rates[i].count = 0;
-+ }
-+
-+ if (rate_flags & IEEE80211_TX_RC_MCS) {
-+ info->control.rates[0].idx = rate;
-+ } else {
-+ for (i = 0; i < sband->n_bitrates; i++) {
-+ if (rate * 5 != sband->bitrates[i].bitrate)
-+ continue;
-+
-+ info->control.rates[0].idx = i;
-+ break;
-+ }
-+ }
-+
-+ info->control.rates[0].flags = rate_flags;
-+ info->control.rates[0].count = min_t(u8, rate_retries + 1,
-+ local->hw.max_rate_tries);
-+ }
-+
- /*
- * remove the radiotap header
- * iterator->_max_length was sanity-checked against
-@@ -1819,7 +1887,7 @@ netdev_tx_t ieee80211_monitor_start_xmit
- IEEE80211_TX_CTL_INJECTED;
-
- /* process and remove the injection radiotap header */
-- if (!ieee80211_parse_tx_radiotap(skb))
-+ if (!ieee80211_parse_tx_radiotap(local, skb))
- goto fail;
-
- rcu_read_lock();
diff --git a/package/kernel/mac80211/patches/322-mac80211-add-A-MSDU-tx-support.patch b/package/kernel/mac80211/patches/322-mac80211-add-A-MSDU-tx-support.patch
deleted file mode 100644
index cf3988ea9c..0000000000
--- a/package/kernel/mac80211/patches/322-mac80211-add-A-MSDU-tx-support.patch
+++ /dev/null
@@ -1,317 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Fri, 5 Feb 2016 01:38:51 +0100
-Subject: [PATCH] mac80211: add A-MSDU tx support
-
-Requires software tx queueing support. frag_list support (for zero-copy)
-is optional.
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/include/net/mac80211.h
-+++ b/include/net/mac80211.h
-@@ -709,6 +709,7 @@ enum mac80211_tx_info_flags {
- * @IEEE80211_TX_CTRL_PS_RESPONSE: This frame is a response to a poll
- * frame (PS-Poll or uAPSD).
- * @IEEE80211_TX_CTRL_RATE_INJECT: This frame is injected with rate information
-+ * @IEEE80211_TX_CTRL_AMSDU: This frame is an A-MSDU frame
- *
- * These flags are used in tx_info->control.flags.
- */
-@@ -716,6 +717,7 @@ enum mac80211_tx_control_flags {
- IEEE80211_TX_CTRL_PORT_CTRL_PROTO = BIT(0),
- IEEE80211_TX_CTRL_PS_RESPONSE = BIT(1),
- IEEE80211_TX_CTRL_RATE_INJECT = BIT(2),
-+ IEEE80211_TX_CTRL_AMSDU = BIT(3),
- };
-
- /*
-@@ -1728,6 +1730,7 @@ struct ieee80211_sta_rates {
- * size is min(max_amsdu_len, 7935) bytes.
- * Both additional HT limits must be enforced by the low level driver.
- * This is defined by the spec (IEEE 802.11-2012 section 8.3.2.2 NOTE 2).
-+ * @max_rc_amsdu_len: Maximum A-MSDU size in bytes recommended by rate control.
- * @txq: per-TID data TX queues (if driver uses the TXQ abstraction)
- */
- struct ieee80211_sta {
-@@ -1748,6 +1751,7 @@ struct ieee80211_sta {
- bool mfp;
- u8 max_amsdu_subframes;
- u16 max_amsdu_len;
-+ u16 max_rc_amsdu_len;
-
- struct ieee80211_txq *txq[IEEE80211_NUM_TIDS];
-
-@@ -1961,6 +1965,15 @@ struct ieee80211_txq {
- * order and does not need to manage its own reorder buffer or BA session
- * timeout.
- *
-+ * @IEEE80211_HW_TX_AMSDU: Hardware (or driver) supports software aggregated
-+ * A-MSDU frames. Requires software tx queueing and fast-xmit support.
-+ * When not using minstrel/minstrel_ht rate control, the driver should
-+ * limit the maximum A-MSDU size based on the current tx rate by setting
-+ * max_rc_amsdu_len in struct ieee80211_sta.
-+ *
-+ * @IEEE80211_HW_TX_FRAG_LIST: Hardware (or driver) supports sending frag_list
-+ * skbs, needed for zero-copy software A-MSDU.
-+ *
- * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
- */
- enum ieee80211_hw_flags {
-@@ -1998,6 +2011,8 @@ enum ieee80211_hw_flags {
- IEEE80211_HW_BEACON_TX_STATUS,
- IEEE80211_HW_NEEDS_UNIQUE_STA_ADDR,
- IEEE80211_HW_SUPPORTS_REORDERING_BUFFER,
-+ IEEE80211_HW_TX_AMSDU,
-+ IEEE80211_HW_TX_FRAG_LIST,
-
- /* keep last, obviously */
- NUM_IEEE80211_HW_FLAGS
-@@ -2070,6 +2085,9 @@ enum ieee80211_hw_flags {
- * size is smaller (an example is LinkSys WRT120N with FW v1.0.07
- * build 002 Jun 18 2012).
- *
-+ * @max_tx_fragments: maximum number of tx buffers per (A)-MSDU, sum
-+ * of 1 + skb_shinfo(skb)->nr_frags for each skb in the frag_list.
-+ *
- * @offchannel_tx_hw_queue: HW queue ID to use for offchannel TX
- * (if %IEEE80211_HW_QUEUE_CONTROL is set)
- *
-@@ -2124,6 +2142,7 @@ struct ieee80211_hw {
- u8 max_rate_tries;
- u8 max_rx_aggregation_subframes;
- u8 max_tx_aggregation_subframes;
-+ u8 max_tx_fragments;
- u8 offchannel_tx_hw_queue;
- u8 radiotap_mcs_details;
- u16 radiotap_vht_details;
---- a/net/mac80211/agg-tx.c
-+++ b/net/mac80211/agg-tx.c
-@@ -935,6 +935,7 @@ void ieee80211_process_addba_resp(struct
- size_t len)
- {
- struct tid_ampdu_tx *tid_tx;
-+ struct ieee80211_txq *txq;
- u16 capab, tid;
- u8 buf_size;
- bool amsdu;
-@@ -945,6 +946,10 @@ void ieee80211_process_addba_resp(struct
- buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
- buf_size = min(buf_size, local->hw.max_tx_aggregation_subframes);
-
-+ txq = sta->sta.txq[tid];
-+ if (!amsdu && txq)
-+ set_bit(IEEE80211_TXQ_NO_AMSDU, &to_txq_info(txq)->flags);
-+
- mutex_lock(&sta->ampdu_mlme.mtx);
-
- tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
---- a/net/mac80211/debugfs.c
-+++ b/net/mac80211/debugfs.c
-@@ -127,6 +127,8 @@ static const char *hw_flag_names[NUM_IEE
- FLAG(BEACON_TX_STATUS),
- FLAG(NEEDS_UNIQUE_STA_ADDR),
- FLAG(SUPPORTS_REORDERING_BUFFER),
-+ FLAG(TX_AMSDU),
-+ FLAG(TX_FRAG_LIST),
-
- /* keep last for the build bug below */
- (void *)0x1
---- a/net/mac80211/ieee80211_i.h
-+++ b/net/mac80211/ieee80211_i.h
-@@ -799,6 +799,7 @@ struct mac80211_qos_map {
- enum txq_info_flags {
- IEEE80211_TXQ_STOP,
- IEEE80211_TXQ_AMPDU,
-+ IEEE80211_TXQ_NO_AMSDU,
- };
-
- struct txq_info {
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -1318,6 +1318,10 @@ struct sk_buff *ieee80211_tx_dequeue(str
- out:
- spin_unlock_bh(&txqi->queue.lock);
-
-+ if (skb && skb_has_frag_list(skb) &&
-+ !ieee80211_hw_check(&local->hw, TX_FRAG_LIST))
-+ skb_linearize(skb);
-+
- return skb;
- }
- EXPORT_SYMBOL(ieee80211_tx_dequeue);
-@@ -2757,6 +2761,163 @@ void ieee80211_clear_fast_xmit(struct st
- kfree_rcu(fast_tx, rcu_head);
- }
-
-+static bool ieee80211_amsdu_realloc_pad(struct ieee80211_local *local,
-+ struct sk_buff *skb, int headroom,
-+ int *subframe_len)
-+{
-+ int amsdu_len = *subframe_len + sizeof(struct ethhdr);
-+ int padding = (4 - amsdu_len) & 3;
-+
-+ if (skb_headroom(skb) < headroom || skb_tailroom(skb) < padding) {
-+ I802_DEBUG_INC(local->tx_expand_skb_head);
-+
-+ if (pskb_expand_head(skb, headroom, padding, GFP_ATOMIC)) {
-+ wiphy_debug(local->hw.wiphy,
-+ "failed to reallocate TX buffer\n");
-+ return false;
-+ }
-+ }
-+
-+ if (padding) {
-+ *subframe_len += padding;
-+ memset(skb_put(skb, padding), 0, padding);
-+ }
-+
-+ return true;
-+}
-+
-+static bool ieee80211_amsdu_prepare_head(struct ieee80211_sub_if_data *sdata,
-+ struct ieee80211_fast_tx *fast_tx,
-+ struct sk_buff *skb)
-+{
-+ struct ieee80211_local *local = sdata->local;
-+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-+ struct ieee80211_hdr *hdr;
-+ struct ethhdr amsdu_hdr;
-+ int hdr_len = fast_tx->hdr_len - sizeof(rfc1042_header);
-+ int subframe_len = skb->len - hdr_len;
-+ void *data;
-+ u8 *qc;
-+
-+ if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)
-+ return false;
-+
-+ if (info->control.flags & IEEE80211_TX_CTRL_AMSDU)
-+ return true;
-+
-+ if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(amsdu_hdr),
-+ &subframe_len))
-+ return false;
-+
-+ amsdu_hdr.h_proto = cpu_to_be16(subframe_len);
-+ memcpy(amsdu_hdr.h_source, skb->data + fast_tx->sa_offs, ETH_ALEN);
-+ memcpy(amsdu_hdr.h_dest, skb->data + fast_tx->da_offs, ETH_ALEN);
-+
-+ data = skb_push(skb, sizeof(amsdu_hdr));
-+ memmove(data, data + sizeof(amsdu_hdr), hdr_len);
-+ memcpy(data + hdr_len, &amsdu_hdr, sizeof(amsdu_hdr));
-+
-+ hdr = data;
-+ qc = ieee80211_get_qos_ctl(hdr);
-+ *qc |= IEEE80211_QOS_CTL_A_MSDU_PRESENT;
-+
-+ info->control.flags |= IEEE80211_TX_CTRL_AMSDU;
-+
-+ return true;
-+}
-+
-+static bool ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data *sdata,
-+ struct sta_info *sta,
-+ struct ieee80211_fast_tx *fast_tx,
-+ struct sk_buff *skb)
-+{
-+ struct ieee80211_local *local = sdata->local;
-+ u8 tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
-+ struct ieee80211_txq *txq = sta->sta.txq[tid];
-+ struct txq_info *txqi;
-+ struct sk_buff **frag_tail, *head;
-+ int subframe_len = skb->len - ETH_ALEN;
-+ u8 max_subframes = sta->sta.max_amsdu_subframes;
-+ int max_frags = local->hw.max_tx_fragments;
-+ int max_amsdu_len = sta->sta.max_amsdu_len;
-+ __be16 len;
-+ void *data;
-+ bool ret = false;
-+ int n = 1, nfrags;
-+
-+ if (!ieee80211_hw_check(&local->hw, TX_AMSDU))
-+ return false;
-+
-+ if (!txq)
-+ return false;
-+
-+ txqi = to_txq_info(txq);
-+ if (test_bit(IEEE80211_TXQ_NO_AMSDU, &txqi->flags))
-+ return false;
-+
-+ if (sta->sta.max_rc_amsdu_len)
-+ max_amsdu_len = min_t(int, max_amsdu_len,
-+ sta->sta.max_rc_amsdu_len);
-+
-+ spin_lock_bh(&txqi->queue.lock);
-+
-+ head = skb_peek_tail(&txqi->queue);
-+ if (!head)
-+ goto out;
-+
-+ if (skb->len + head->len > max_amsdu_len)
-+ goto out;
-+
-+ /*
-+ * HT A-MPDU limits maximum MPDU size to 4095 bytes. Since aggregation
-+ * sessions are started/stopped without txq flush, use the limit here
-+ * to avoid having to de-aggregate later.
-+ */
-+ if (skb->len + head->len > 4095 &&
-+ !sta->sta.vht_cap.vht_supported)
-+ goto out;
-+
-+ if (!ieee80211_amsdu_prepare_head(sdata, fast_tx, head))
-+ goto out;
-+
-+ nfrags = 1 + skb_shinfo(skb)->nr_frags;
-+ nfrags += 1 + skb_shinfo(head)->nr_frags;
-+ frag_tail = &skb_shinfo(head)->frag_list;
-+ while (*frag_tail) {
-+ nfrags += 1 + skb_shinfo(*frag_tail)->nr_frags;
-+ frag_tail = &(*frag_tail)->next;
-+ n++;
-+ }
-+
-+ if (max_subframes && n > max_subframes)
-+ goto out;
-+
-+ if (max_frags && nfrags > max_frags)
-+ goto out;
-+
-+ if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(rfc1042_header) + 2,
-+ &subframe_len))
-+ return false;
-+
-+ ret = true;
-+ data = skb_push(skb, ETH_ALEN + 2);
-+ memmove(data, data + ETH_ALEN + 2, 2 * ETH_ALEN);
-+
-+ data += 2 * ETH_ALEN;
-+ len = cpu_to_be16(subframe_len);
-+ memcpy(data, &len, 2);
-+ memcpy(data + 2, rfc1042_header, sizeof(rfc1042_header));
-+
-+ head->len += skb->len;
-+ head->data_len += skb->len;
-+ *frag_tail = skb;
-+
-+out:
-+ spin_unlock_bh(&txqi->queue.lock);
-+
-+ return ret;
-+}
-+
- static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
- struct net_device *dev, struct sta_info *sta,
- struct ieee80211_fast_tx *fast_tx,
-@@ -2811,6 +2972,10 @@ static bool ieee80211_xmit_fast(struct i
-
- ieee80211_tx_stats(dev, skb->len + extra_head);
-
-+ if ((hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) &&
-+ ieee80211_amsdu_aggregate(sdata, sta, fast_tx, skb))
-+ return true;
-+
- /* will not be crypto-handled beyond what we do here, so use false
- * as the may-encrypt argument for the resize to not account for
- * more room than we already have in 'extra_head'
diff --git a/package/kernel/mac80211/patches/323-0000-brcmfmac-fix-setting-primary-channel-for-80-MHz-widt.patch b/package/kernel/mac80211/patches/323-0000-brcmfmac-fix-setting-primary-channel-for-80-MHz-widt.patch
deleted file mode 100644
index 9277b2cabc..0000000000
--- a/package/kernel/mac80211/patches/323-0000-brcmfmac-fix-setting-primary-channel-for-80-MHz-widt.patch
+++ /dev/null
@@ -1,64 +0,0 @@
-From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
-Date: Wed, 20 Jan 2016 16:46:04 +0100
-Subject: [PATCH] brcmfmac: fix setting primary channel for 80 MHz width
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-First of all it changes the way we calculate primary channel offset. If
-we use e.g. 80 MHz channel with primary frequency 5180 MHz (which means
-center frequency is 5210 MHz) it makes sense to calculate primary offset
-as -30 MHz.
-Then it fixes values we compare primary_offset with. We were comparing
-offset in MHz against -2 or 2 which was resulting in picking a wrong
-primary channel.
-
-Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -247,7 +247,7 @@ static u16 chandef_to_chanspec(struct br
- brcmf_dbg(TRACE, "chandef: control %d center %d width %d\n",
- ch->chan->center_freq, ch->center_freq1, ch->width);
- ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq1);
-- primary_offset = ch->center_freq1 - ch->chan->center_freq;
-+ primary_offset = ch->chan->center_freq - ch->center_freq1;
- switch (ch->width) {
- case NL80211_CHAN_WIDTH_20:
- case NL80211_CHAN_WIDTH_20_NOHT:
-@@ -256,24 +256,21 @@ static u16 chandef_to_chanspec(struct br
- break;
- case NL80211_CHAN_WIDTH_40:
- ch_inf.bw = BRCMU_CHAN_BW_40;
-- if (primary_offset < 0)
-+ if (primary_offset > 0)
- ch_inf.sb = BRCMU_CHAN_SB_U;
- else
- ch_inf.sb = BRCMU_CHAN_SB_L;
- break;
- case NL80211_CHAN_WIDTH_80:
- ch_inf.bw = BRCMU_CHAN_BW_80;
-- if (primary_offset < 0) {
-- if (primary_offset < -CH_10MHZ_APART)
-- ch_inf.sb = BRCMU_CHAN_SB_UU;
-- else
-- ch_inf.sb = BRCMU_CHAN_SB_UL;
-- } else {
-- if (primary_offset > CH_10MHZ_APART)
-- ch_inf.sb = BRCMU_CHAN_SB_LL;
-- else
-- ch_inf.sb = BRCMU_CHAN_SB_LU;
-- }
-+ if (primary_offset == -30)
-+ ch_inf.sb = BRCMU_CHAN_SB_LL;
-+ else if (primary_offset == -10)
-+ ch_inf.sb = BRCMU_CHAN_SB_LU;
-+ else if (primary_offset == 10)
-+ ch_inf.sb = BRCMU_CHAN_SB_UL;
-+ else
-+ ch_inf.sb = BRCMU_CHAN_SB_UU;
- break;
- case NL80211_CHAN_WIDTH_80P80:
- case NL80211_CHAN_WIDTH_160:
diff --git a/package/kernel/mac80211/patches/323-0001-brcmfmac-analyze-descriptors-of-current-component-on.patch b/package/kernel/mac80211/patches/323-0001-brcmfmac-analyze-descriptors-of-current-component-on.patch
deleted file mode 100644
index d7018dab3d..0000000000
--- a/package/kernel/mac80211/patches/323-0001-brcmfmac-analyze-descriptors-of-current-component-on.patch
+++ /dev/null
@@ -1,51 +0,0 @@
-From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
-Date: Tue, 26 Jan 2016 17:57:01 +0100
-Subject: [PATCH] brcmfmac: analyze descriptors of current component only
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-So far we were looking for address descriptors without a check for
-crossing current component border. In case of dealing with unsupported
-descriptor or descriptor missing at all the code would incorrectly get
-data from another component.
-
-Consider this binary-described component from BCM4366 EROM:
-4bf83b01 TAG==CI CID==0x83b
-20080201 TAG==CI PORTS==0+1 WRAPPERS==0+1
-18400035 TAG==ADDR SZ_SZD TYPE_SLAVE
-00050000
-18107085 TAG==ADDR SZ_4K TYPE_SWRAP
-
-Driver was assigning invalid base address to this core:
-brcmfmac: [6 ] core 0x83b:32 base 0x18109000 wrap 0x18107000
-which came from totally different component defined in EROM:
-43b36701 TAG==CI CID==0x367
-00000201 TAG==CI PORTS==0+1 WRAPPERS==0+0
-18109005 TAG==ADDR SZ_4K TYPE_SLAVE
-
-This change will also allow us to support components without wrapper
-address in the future.
-
-Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
-@@ -803,7 +803,14 @@ static int brcmf_chip_dmp_get_regaddr(st
- *eromaddr -= 4;
- return -EFAULT;
- }
-- } while (desc != DMP_DESC_ADDRESS);
-+ } while (desc != DMP_DESC_ADDRESS &&
-+ desc != DMP_DESC_COMPONENT);
-+
-+ /* stop if we crossed current component border */
-+ if (desc == DMP_DESC_COMPONENT) {
-+ *eromaddr -= 4;
-+ return 0;
-+ }
-
- /* skip upper 32-bit address descriptor */
- if (val & DMP_DESC_ADDRSIZE_GT32)
diff --git a/package/kernel/mac80211/patches/323-0002-brcmfmac-allow-storing-PMU-core-without-wrapper-addr.patch b/package/kernel/mac80211/patches/323-0002-brcmfmac-allow-storing-PMU-core-without-wrapper-addr.patch
deleted file mode 100644
index 045ab4953b..0000000000
--- a/package/kernel/mac80211/patches/323-0002-brcmfmac-allow-storing-PMU-core-without-wrapper-addr.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
-Date: Tue, 26 Jan 2016 17:57:02 +0100
-Subject: [PATCH] brcmfmac: allow storing PMU core without wrapper address
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Separated PMU core can be found in new devices and should be used for
-accessing PMU registers (which were routed through ChipCommon so far).
-This core is one of exceptions that doesn't have or need wrapper address
-to be still safely accessible.
-
-Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
-@@ -883,7 +883,8 @@ int brcmf_chip_dmp_erom_scan(struct brcm
- rev = (val & DMP_COMP_REVISION) >> DMP_COMP_REVISION_S;
-
- /* need core with ports */
-- if (nmw + nsw == 0)
-+ if (nmw + nsw == 0 &&
-+ id != BCMA_CORE_PMU)
- continue;
-
- /* try to obtain register address info */
diff --git a/package/kernel/mac80211/patches/323-0003-brcmfmac-read-extended-capabilities-of-ChipCommon-co.patch b/package/kernel/mac80211/patches/323-0003-brcmfmac-read-extended-capabilities-of-ChipCommon-co.patch
deleted file mode 100644
index 7b7ba4f743..0000000000
--- a/package/kernel/mac80211/patches/323-0003-brcmfmac-read-extended-capabilities-of-ChipCommon-co.patch
+++ /dev/null
@@ -1,43 +0,0 @@
-From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
-Date: Tue, 26 Jan 2016 17:57:03 +0100
-Subject: [PATCH] brcmfmac: read extended capabilities of ChipCommon core
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This is an extra bitfield with info about some present hardware.
-
-Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
-@@ -1025,6 +1025,9 @@ static int brcmf_chip_setup(struct brcmf
- /* get chipcommon capabilites */
- pub->cc_caps = chip->ops->read32(chip->ctx,
- CORE_CC_REG(base, capabilities));
-+ pub->cc_caps_ext = chip->ops->read32(chip->ctx,
-+ CORE_CC_REG(base,
-+ capabilities_ext));
-
- /* get pmu caps & rev */
- if (pub->cc_caps & CC_CAP_PMU) {
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h
-@@ -27,6 +27,7 @@
- * @chip: chip identifier.
- * @chiprev: chip revision.
- * @cc_caps: chipcommon core capabilities.
-+ * @cc_caps_ext: chipcommon core extended capabilities.
- * @pmucaps: PMU capabilities.
- * @pmurev: PMU revision.
- * @rambase: RAM base address (only applicable for ARM CR4 chips).
-@@ -38,6 +39,7 @@ struct brcmf_chip {
- u32 chip;
- u32 chiprev;
- u32 cc_caps;
-+ u32 cc_caps_ext;
- u32 pmucaps;
- u32 pmurev;
- u32 rambase;
diff --git a/package/kernel/mac80211/patches/323-0004-brcmfmac-access-PMU-registers-using-standalone-PMU-c.patch b/package/kernel/mac80211/patches/323-0004-brcmfmac-access-PMU-registers-using-standalone-PMU-c.patch
deleted file mode 100644
index 2af6fd93bc..0000000000
--- a/package/kernel/mac80211/patches/323-0004-brcmfmac-access-PMU-registers-using-standalone-PMU-c.patch
+++ /dev/null
@@ -1,148 +0,0 @@
-From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
-Date: Tue, 26 Jan 2016 17:57:04 +0100
-Subject: [PATCH] brcmfmac: access PMU registers using standalone PMU core if
- available
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-On recent Broadcom chipsets PMU is present as separated core and it
-can't be accessed using ChipCommon anymore as it fails with e.g.:
-[ 18.198412] Unhandled fault: imprecise external abort (0x1406) at 0xb6da200f
-
-Add a new helper function that will return a proper core that should be
-used for accessing PMU registers.
-
-Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
-@@ -1014,6 +1014,7 @@ static int brcmf_chip_setup(struct brcmf
- {
- struct brcmf_chip *pub;
- struct brcmf_core_priv *cc;
-+ struct brcmf_core *pmu;
- u32 base;
- u32 val;
- int ret = 0;
-@@ -1030,9 +1031,10 @@ static int brcmf_chip_setup(struct brcmf
- capabilities_ext));
-
- /* get pmu caps & rev */
-+ pmu = brcmf_chip_get_pmu(pub); /* after reading cc_caps_ext */
- if (pub->cc_caps & CC_CAP_PMU) {
- val = chip->ops->read32(chip->ctx,
-- CORE_CC_REG(base, pmucapabilities));
-+ CORE_CC_REG(pmu->base, pmucapabilities));
- pub->pmurev = val & PCAP_REV_MASK;
- pub->pmucaps = val;
- }
-@@ -1131,6 +1133,23 @@ struct brcmf_core *brcmf_chip_get_chipco
- return &cc->pub;
- }
-
-+struct brcmf_core *brcmf_chip_get_pmu(struct brcmf_chip *pub)
-+{
-+ struct brcmf_core *cc = brcmf_chip_get_chipcommon(pub);
-+ struct brcmf_core *pmu;
-+
-+ /* See if there is separated PMU core available */
-+ if (cc->rev >= 35 &&
-+ pub->cc_caps_ext & BCMA_CC_CAP_EXT_AOB_PRESENT) {
-+ pmu = brcmf_chip_get_core(pub, BCMA_CORE_PMU);
-+ if (pmu)
-+ return pmu;
-+ }
-+
-+ /* Fallback to ChipCommon core for older hardware */
-+ return cc;
-+}
-+
- bool brcmf_chip_iscoreup(struct brcmf_core *pub)
- {
- struct brcmf_core_priv *core;
-@@ -1301,6 +1320,7 @@ bool brcmf_chip_sr_capable(struct brcmf_
- {
- u32 base, addr, reg, pmu_cc3_mask = ~0;
- struct brcmf_chip_priv *chip;
-+ struct brcmf_core *pmu = brcmf_chip_get_pmu(pub);
-
- brcmf_dbg(TRACE, "Enter\n");
-
-@@ -1320,9 +1340,9 @@ bool brcmf_chip_sr_capable(struct brcmf_
- case BRCM_CC_4335_CHIP_ID:
- case BRCM_CC_4339_CHIP_ID:
- /* read PMU chipcontrol register 3 */
-- addr = CORE_CC_REG(base, chipcontrol_addr);
-+ addr = CORE_CC_REG(pmu->base, chipcontrol_addr);
- chip->ops->write32(chip->ctx, addr, 3);
-- addr = CORE_CC_REG(base, chipcontrol_data);
-+ addr = CORE_CC_REG(pmu->base, chipcontrol_data);
- reg = chip->ops->read32(chip->ctx, addr);
- return (reg & pmu_cc3_mask) != 0;
- case BRCM_CC_43430_CHIP_ID:
-@@ -1330,12 +1350,12 @@ bool brcmf_chip_sr_capable(struct brcmf_
- reg = chip->ops->read32(chip->ctx, addr);
- return reg != 0;
- default:
-- addr = CORE_CC_REG(base, pmucapabilities_ext);
-+ addr = CORE_CC_REG(pmu->base, pmucapabilities_ext);
- reg = chip->ops->read32(chip->ctx, addr);
- if ((reg & PCAPEXT_SR_SUPPORTED_MASK) == 0)
- return false;
-
-- addr = CORE_CC_REG(base, retention_ctl);
-+ addr = CORE_CC_REG(pmu->base, retention_ctl);
- reg = chip->ops->read32(chip->ctx, addr);
- return (reg & (PMU_RCTL_MACPHY_DISABLE_MASK |
- PMU_RCTL_LOGIC_DISABLE_MASK)) == 0;
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h
-@@ -85,6 +85,7 @@ struct brcmf_chip *brcmf_chip_attach(voi
- void brcmf_chip_detach(struct brcmf_chip *chip);
- struct brcmf_core *brcmf_chip_get_core(struct brcmf_chip *chip, u16 coreid);
- struct brcmf_core *brcmf_chip_get_chipcommon(struct brcmf_chip *chip);
-+struct brcmf_core *brcmf_chip_get_pmu(struct brcmf_chip *pub);
- bool brcmf_chip_iscoreup(struct brcmf_core *core);
- void brcmf_chip_coredisable(struct brcmf_core *core, u32 prereset, u32 reset);
- void brcmf_chip_resetcore(struct brcmf_core *core, u32 prereset, u32 reset,
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
-@@ -3615,7 +3615,6 @@ brcmf_sdio_drivestrengthinit(struct brcm
- const struct sdiod_drive_str *str_tab = NULL;
- u32 str_mask;
- u32 str_shift;
-- u32 base;
- u32 i;
- u32 drivestrength_sel = 0;
- u32 cc_data_temp;
-@@ -3658,14 +3657,15 @@ brcmf_sdio_drivestrengthinit(struct brcm
- }
-
- if (str_tab != NULL) {
-+ struct brcmf_core *pmu = brcmf_chip_get_pmu(ci);
-+
- for (i = 0; str_tab[i].strength != 0; i++) {
- if (drivestrength >= str_tab[i].strength) {
- drivestrength_sel = str_tab[i].sel;
- break;
- }
- }
-- base = brcmf_chip_get_chipcommon(ci)->base;
-- addr = CORE_CC_REG(base, chipcontrol_addr);
-+ addr = CORE_CC_REG(pmu->base, chipcontrol_addr);
- brcmf_sdiod_regwl(sdiodev, addr, 1, NULL);
- cc_data_temp = brcmf_sdiod_regrl(sdiodev, addr, NULL);
- cc_data_temp &= ~str_mask;
-@@ -3835,8 +3835,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdi
- goto fail;
-
- /* set PMUControl so a backplane reset does PMU state reload */
-- reg_addr = CORE_CC_REG(brcmf_chip_get_chipcommon(bus->ci)->base,
-- pmucontrol);
-+ reg_addr = CORE_CC_REG(brcmf_chip_get_pmu(bus->ci)->base, pmucontrol);
- reg_val = brcmf_sdiod_regrl(bus->sdiodev, reg_addr, &err);
- if (err)
- goto fail;
diff --git a/package/kernel/mac80211/patches/323-0005-brcmfmac-add-support-for-14e4-4365-PCI-ID-with-BCM43.patch b/package/kernel/mac80211/patches/323-0005-brcmfmac-add-support-for-14e4-4365-PCI-ID-with-BCM43.patch
deleted file mode 100644
index 35887fcb59..0000000000
--- a/package/kernel/mac80211/patches/323-0005-brcmfmac-add-support-for-14e4-4365-PCI-ID-with-BCM43.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
-Date: Tue, 26 Jan 2016 17:57:05 +0100
-Subject: [PATCH] brcmfmac: add support for 14e4:4365 PCI ID with BCM4366
- chipset
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-On Broadcom ARM routers BCM4366 cards are available with 14e4:4365 ID.
-Unfortunately this ID was already used by Broadcom for cards with
-BCM43142, a totally different chipset requiring SoftMAC driver. To avoid
-a conflict between brcmfmac and bcma use more specific ID entry with
-subvendor and subdevice specified.
-
-Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
-@@ -1951,6 +1951,9 @@ static const struct dev_pm_ops brcmf_pci
-
- #define BRCMF_PCIE_DEVICE(dev_id) { BRCM_PCIE_VENDOR_ID_BROADCOM, dev_id,\
- PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, 0 }
-+#define BRCMF_PCIE_DEVICE_SUB(dev_id, subvend, subdev) { \
-+ BRCM_PCIE_VENDOR_ID_BROADCOM, dev_id,\
-+ subvend, subdev, PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, 0 }
-
- static struct pci_device_id brcmf_pcie_devid_table[] = {
- BRCMF_PCIE_DEVICE(BRCM_PCIE_4350_DEVICE_ID),
-@@ -1966,6 +1969,7 @@ static struct pci_device_id brcmf_pcie_d
- BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_DEVICE_ID),
- BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_2G_DEVICE_ID),
- BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_5G_DEVICE_ID),
-+ BRCMF_PCIE_DEVICE_SUB(0x4365, BRCM_PCIE_VENDOR_ID_BROADCOM, 0x4365),
- BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_DEVICE_ID),
- BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_2G_DEVICE_ID),
- BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_5G_DEVICE_ID),
diff --git a/package/kernel/mac80211/patches/324-brcmfmac-treat-NULL-character-in-NVRAM-as-separator.patch b/package/kernel/mac80211/patches/324-brcmfmac-treat-NULL-character-in-NVRAM-as-separator.patch
deleted file mode 100644
index 6ce60f1960..0000000000
--- a/package/kernel/mac80211/patches/324-brcmfmac-treat-NULL-character-in-NVRAM-as-separator.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
-Date: Sun, 31 Jan 2016 12:14:34 +0100
-Subject: [PATCH] brcmfmac: treat NULL character in NVRAM as separator
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Platform NVRAM (stored on a flash partition) has entries separated by a
-NULL (\0) char. Our parsing code switches from VALUE state to IDLE
-whenever it meets a NULL (\0). When that happens our IDLE handler should
-simply consume it and analyze whatever is placed ahead.
-
-This fixes harmless warnings spamming debugging output:
-[ 155.165624] brcmfmac: brcmf_nvram_handle_idle warning: ln=1:col=20: ignoring invalid character
-[ 155.180806] brcmfmac: brcmf_nvram_handle_idle warning: ln=1:col=44: ignoring invalid character
-[ 155.195971] brcmfmac: brcmf_nvram_handle_idle warning: ln=1:col=63: ignoring invalid character
-
-Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
-@@ -93,7 +93,7 @@ static enum nvram_parser_state brcmf_nvr
- c = nvp->data[nvp->pos];
- if (c == '\n')
- return COMMENT;
-- if (is_whitespace(c))
-+ if (is_whitespace(c) || c == '\0')
- goto proceed;
- if (c == '#')
- return COMMENT;
diff --git a/package/kernel/mac80211/patches/325-brcmfmac-sdio-Increase-the-default-timeouts-a-bit.patch b/package/kernel/mac80211/patches/325-brcmfmac-sdio-Increase-the-default-timeouts-a-bit.patch
deleted file mode 100644
index 012dea1e3a..0000000000
--- a/package/kernel/mac80211/patches/325-brcmfmac-sdio-Increase-the-default-timeouts-a-bit.patch
+++ /dev/null
@@ -1,41 +0,0 @@
-From: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
-Date: Mon, 25 Jan 2016 11:47:29 +0100
-Subject: [PATCH] brcmfmac: sdio: Increase the default timeouts a bit
-
-On a Radxa Rock2 board with a Ampak AP6335 (Broadcom 4339 core) it seems
-the card responds very quickly most of the time, unfortunately during
-initialisation it sometimes seems to take just a bit over 2 seconds to
-respond.
-
-This results intialization failing with message like:
- brcmf_c_preinit_dcmds: Retreiving cur_etheraddr failed, -52
- brcmf_bus_start: failed: -52
- brcmf_sdio_firmware_callback: dongle is not responding
-
-Increasing the timeout to allow for a bit more headroom allows the
-card to initialize reliably.
-
-A quick search online after diagnosing/fixing this showed that Google
-has a similar patch in their ChromeOS tree, so this doesn't seem
-specific to the board I'm using.
-
-Signed-off-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
-Reviewed-by: Julian Calaby <julian.calaby@gmail.com>
-Acked-by: Arend van Spriel <arend@broadcom.com>
-Reviewed-by: Douglas Anderson <dianders@chromium.org>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
-@@ -45,8 +45,8 @@
- #include "chip.h"
- #include "firmware.h"
-
--#define DCMD_RESP_TIMEOUT msecs_to_jiffies(2000)
--#define CTL_DONE_TIMEOUT msecs_to_jiffies(2000)
-+#define DCMD_RESP_TIMEOUT msecs_to_jiffies(2500)
-+#define CTL_DONE_TIMEOUT msecs_to_jiffies(2500)
-
- #ifdef DEBUG
-
diff --git a/package/kernel/mac80211/patches/326-ath9k-make-NF-load-complete-quickly-and-reliably.patch b/package/kernel/mac80211/patches/326-ath9k-make-NF-load-complete-quickly-and-reliably.patch
deleted file mode 100644
index 71f7a40433..0000000000
--- a/package/kernel/mac80211/patches/326-ath9k-make-NF-load-complete-quickly-and-reliably.patch
+++ /dev/null
@@ -1,87 +0,0 @@
-From: Miaoqing Pan <miaoqing@codeaurora.org>
-Date: Fri, 5 Feb 2016 09:45:50 +0800
-Subject: [PATCH] ath9k: make NF load complete quickly and reliably
-
-Make NF load complete quickly and reliably. NF load execution
-is delayed by HW to end of frame if frame Rx or Tx is ongoing.
-Increasing timeout to max frame duration. If NF cal is ongoing
-before NF load, stop it before load, and restart it afterwards.
-
-Signed-off-by: Miaoqing Pan <miaoqing@codeaurora.org>
----
-
---- a/drivers/net/wireless/ath/ath9k/calib.c
-+++ b/drivers/net/wireless/ath/ath9k/calib.c
-@@ -241,6 +241,7 @@ int ath9k_hw_loadnf(struct ath_hw *ah, s
- u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
- struct ath_common *common = ath9k_hw_common(ah);
- s16 default_nf = ath9k_hw_get_default_nf(ah, chan);
-+ u32 bb_agc_ctl = REG_READ(ah, AR_PHY_AGC_CONTROL);
-
- if (ah->caldata)
- h = ah->caldata->nfCalHist;
-@@ -264,6 +265,16 @@ int ath9k_hw_loadnf(struct ath_hw *ah, s
- }
-
- /*
-+ * stop NF cal if ongoing to ensure NF load completes immediately
-+ * (or after end rx/tx frame if ongoing)
-+ */
-+ if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NF) {
-+ REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
-+ REG_RMW_BUFFER_FLUSH(ah);
-+ ENABLE_REG_RMW_BUFFER(ah);
-+ }
-+
-+ /*
- * Load software filtered NF value into baseband internal minCCApwr
- * variable.
- */
-@@ -276,18 +287,33 @@ int ath9k_hw_loadnf(struct ath_hw *ah, s
-
- /*
- * Wait for load to complete, should be fast, a few 10s of us.
-- * The max delay was changed from an original 250us to 10000us
-- * since 250us often results in NF load timeout and causes deaf
-- * condition during stress testing 12/12/2009
-+ * The max delay was changed from an original 250us to 22.2 msec.
-+ * This would increase timeout to the longest possible frame
-+ * (11n max length 22.1 msec)
- */
-- for (j = 0; j < 10000; j++) {
-+ for (j = 0; j < 22200; j++) {
- if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
-- AR_PHY_AGC_CONTROL_NF) == 0)
-+ AR_PHY_AGC_CONTROL_NF) == 0)
- break;
- udelay(10);
- }
-
- /*
-+ * Restart NF so it can continue.
-+ */
-+ if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NF) {
-+ ENABLE_REG_RMW_BUFFER(ah);
-+ if (bb_agc_ctl & AR_PHY_AGC_CONTROL_ENABLE_NF)
-+ REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
-+ AR_PHY_AGC_CONTROL_ENABLE_NF);
-+ if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NO_UPDATE_NF)
-+ REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
-+ AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
-+ REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
-+ REG_RMW_BUFFER_FLUSH(ah);
-+ }
-+
-+ /*
- * We timed out waiting for the noisefloor to load, probably due to an
- * in-progress rx. Simply return here and allow the load plenty of time
- * to complete before the next calibration interval. We need to avoid
-@@ -296,7 +322,7 @@ int ath9k_hw_loadnf(struct ath_hw *ah, s
- * here, the baseband nf cal will just be capped by our present
- * noisefloor until the next calibration timer.
- */
-- if (j == 10000) {
-+ if (j == 22200) {
- ath_dbg(common, ANY,
- "Timeout while waiting for nf to load: AR_PHY_AGC_CONTROL=0x%x\n",
- REG_READ(ah, AR_PHY_AGC_CONTROL));
diff --git a/package/kernel/mac80211/patches/327-mac80211-Remove-MPP-table-entries-with-MPath.patch b/package/kernel/mac80211/patches/327-mac80211-Remove-MPP-table-entries-with-MPath.patch
deleted file mode 100644
index f7f9df946a..0000000000
--- a/package/kernel/mac80211/patches/327-mac80211-Remove-MPP-table-entries-with-MPath.patch
+++ /dev/null
@@ -1,54 +0,0 @@
-From: Henning Rogge <hrogge@gmail.com>
-Date: Wed, 3 Feb 2016 13:58:36 +0100
-Subject: [PATCH] mac80211: Remove MPP table entries with MPath
-
-Make the mesh_path_del() function remove all mpp table entries
-that are proxied by the removed mesh path.
-
-Acked-by: Bob Copeland <me@bobcopeland.com>
-Signed-off-by: Henning Rogge <henning.rogge@fkie.fraunhofer.de>
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
-
---- a/net/mac80211/mesh_pathtbl.c
-+++ b/net/mac80211/mesh_pathtbl.c
-@@ -835,6 +835,29 @@ void mesh_path_flush_by_nexthop(struct s
- rcu_read_unlock();
- }
-
-+static void mpp_flush_by_proxy(struct ieee80211_sub_if_data *sdata,
-+ const u8 *proxy)
-+{
-+ struct mesh_table *tbl;
-+ struct mesh_path *mpp;
-+ struct mpath_node *node;
-+ int i;
-+
-+ rcu_read_lock();
-+ read_lock_bh(&pathtbl_resize_lock);
-+ tbl = resize_dereference_mpp_paths();
-+ for_each_mesh_entry(tbl, node, i) {
-+ mpp = node->mpath;
-+ if (ether_addr_equal(mpp->mpp, proxy)) {
-+ spin_lock(&tbl->hashwlock[i]);
-+ __mesh_path_del(tbl, node);
-+ spin_unlock(&tbl->hashwlock[i]);
-+ }
-+ }
-+ read_unlock_bh(&pathtbl_resize_lock);
-+ rcu_read_unlock();
-+}
-+
- static void table_flush_by_iface(struct mesh_table *tbl,
- struct ieee80211_sub_if_data *sdata)
- {
-@@ -892,6 +915,9 @@ int mesh_path_del(struct ieee80211_sub_i
- int hash_idx;
- int err = 0;
-
-+ /* flush relevant mpp entries first */
-+ mpp_flush_by_proxy(sdata, addr);
-+
- read_lock_bh(&pathtbl_resize_lock);
- tbl = resize_dereference_mesh_paths();
- hash_idx = mesh_table_hash(addr, sdata, tbl);
diff --git a/package/kernel/mac80211/patches/328-mac80211-let-unused-MPP-table-entries-timeout.patch b/package/kernel/mac80211/patches/328-mac80211-let-unused-MPP-table-entries-timeout.patch
deleted file mode 100644
index 740993c9e0..0000000000
--- a/package/kernel/mac80211/patches/328-mac80211-let-unused-MPP-table-entries-timeout.patch
+++ /dev/null
@@ -1,104 +0,0 @@
-From: Henning Rogge <hrogge@gmail.com>
-Date: Wed, 3 Feb 2016 13:58:37 +0100
-Subject: [PATCH] mac80211: let unused MPP table entries timeout
-
-Remember the last time when a mpp table entry is used for
-rx or tx and remove them after MESH_PATH_EXPIRE time.
-
-Acked-by: Bob Copeland <me@bobcopeland.com>
-Signed-off-by: Henning Rogge <henning.rogge@fkie.fraunhofer.de>
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
-
---- a/net/mac80211/mesh_pathtbl.c
-+++ b/net/mac80211/mesh_pathtbl.c
-@@ -942,6 +942,46 @@ enddel:
- }
-
- /**
-+ * mpp_path_del - delete a mesh proxy path from the table
-+ *
-+ * @addr: addr address (ETH_ALEN length)
-+ * @sdata: local subif
-+ *
-+ * Returns: 0 if successful
-+ */
-+static int mpp_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr)
-+{
-+ struct mesh_table *tbl;
-+ struct mesh_path *mpath;
-+ struct mpath_node *node;
-+ struct hlist_head *bucket;
-+ int hash_idx;
-+ int err = 0;
-+
-+ read_lock_bh(&pathtbl_resize_lock);
-+ tbl = resize_dereference_mpp_paths();
-+ hash_idx = mesh_table_hash(addr, sdata, tbl);
-+ bucket = &tbl->hash_buckets[hash_idx];
-+
-+ spin_lock(&tbl->hashwlock[hash_idx]);
-+ hlist_for_each_entry(node, bucket, list) {
-+ mpath = node->mpath;
-+ if (mpath->sdata == sdata &&
-+ ether_addr_equal(addr, mpath->dst)) {
-+ __mesh_path_del(tbl, node);
-+ goto enddel;
-+ }
-+ }
-+
-+ err = -ENXIO;
-+enddel:
-+ mesh_paths_generation++;
-+ spin_unlock(&tbl->hashwlock[hash_idx]);
-+ read_unlock_bh(&pathtbl_resize_lock);
-+ return err;
-+}
-+
-+/**
- * mesh_path_tx_pending - sends pending frames in a mesh path queue
- *
- * @mpath: mesh path to activate
-@@ -1157,6 +1197,17 @@ void mesh_path_expire(struct ieee80211_s
- time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE))
- mesh_path_del(mpath->sdata, mpath->dst);
- }
-+
-+ tbl = rcu_dereference(mpp_paths);
-+ for_each_mesh_entry(tbl, node, i) {
-+ if (node->mpath->sdata != sdata)
-+ continue;
-+ mpath = node->mpath;
-+ if ((!(mpath->flags & MESH_PATH_FIXED)) &&
-+ time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE))
-+ mpp_path_del(mpath->sdata, mpath->dst);
-+ }
-+
- rcu_read_unlock();
- }
-
---- a/net/mac80211/rx.c
-+++ b/net/mac80211/rx.c
-@@ -2291,6 +2291,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
- spin_lock_bh(&mppath->state_lock);
- if (!ether_addr_equal(mppath->mpp, mpp_addr))
- memcpy(mppath->mpp, mpp_addr, ETH_ALEN);
-+ mppath->exp_time = jiffies;
- spin_unlock_bh(&mppath->state_lock);
- }
- rcu_read_unlock();
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -2171,8 +2171,11 @@ static struct sk_buff *ieee80211_build_h
- mpp_lookup = true;
- }
-
-- if (mpp_lookup)
-+ if (mpp_lookup) {
- mppath = mpp_path_lookup(sdata, skb->data);
-+ if (mppath)
-+ mppath->exp_time = jiffies;
-+ }
-
- if (mppath && mpath)
- mesh_path_del(mpath->sdata, mpath->dst);
diff --git a/package/kernel/mac80211/patches/329-mac80211-Unify-mesh-and-mpp-path-removal-function.patch b/package/kernel/mac80211/patches/329-mac80211-Unify-mesh-and-mpp-path-removal-function.patch
deleted file mode 100644
index 0c36b1d568..0000000000
--- a/package/kernel/mac80211/patches/329-mac80211-Unify-mesh-and-mpp-path-removal-function.patch
+++ /dev/null
@@ -1,143 +0,0 @@
-From: Henning Rogge <hrogge@gmail.com>
-Date: Wed, 3 Feb 2016 13:58:38 +0100
-Subject: [PATCH] mac80211: Unify mesh and mpp path removal function
-
-mpp_path_del() and mesh_path_del() are mostly the same function.
-Move common code into a new static function.
-
-Acked-by: Bob Copeland <me@bobcopeland.com>
-Signed-off-by: Henning Rogge <henning.rogge@fkie.fraunhofer.de>
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
-
---- a/net/mac80211/mesh_pathtbl.c
-+++ b/net/mac80211/mesh_pathtbl.c
-@@ -55,16 +55,21 @@ int mpp_paths_generation;
- static DEFINE_RWLOCK(pathtbl_resize_lock);
-
-
-+static inline struct mesh_table *resize_dereference_paths(
-+ struct mesh_table __rcu *table)
-+{
-+ return rcu_dereference_protected(table,
-+ lockdep_is_held(&pathtbl_resize_lock));
-+}
-+
- static inline struct mesh_table *resize_dereference_mesh_paths(void)
- {
-- return rcu_dereference_protected(mesh_paths,
-- lockdep_is_held(&pathtbl_resize_lock));
-+ return resize_dereference_paths(mesh_paths);
- }
-
- static inline struct mesh_table *resize_dereference_mpp_paths(void)
- {
-- return rcu_dereference_protected(mpp_paths,
-- lockdep_is_held(&pathtbl_resize_lock));
-+ return resize_dereference_paths(mpp_paths);
- }
-
- /*
-@@ -899,14 +904,17 @@ void mesh_path_flush_by_iface(struct iee
- }
-
- /**
-- * mesh_path_del - delete a mesh path from the table
-+ * table_path_del - delete a path from the mesh or mpp table
- *
-- * @addr: dst address (ETH_ALEN length)
-+ * @tbl: mesh or mpp path table
- * @sdata: local subif
-+ * @addr: dst address (ETH_ALEN length)
- *
- * Returns: 0 if successful
- */
--int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr)
-+static int table_path_del(struct mesh_table __rcu *rcu_tbl,
-+ struct ieee80211_sub_if_data *sdata,
-+ const u8 *addr)
- {
- struct mesh_table *tbl;
- struct mesh_path *mpath;
-@@ -915,11 +923,7 @@ int mesh_path_del(struct ieee80211_sub_i
- int hash_idx;
- int err = 0;
-
-- /* flush relevant mpp entries first */
-- mpp_flush_by_proxy(sdata, addr);
--
-- read_lock_bh(&pathtbl_resize_lock);
-- tbl = resize_dereference_mesh_paths();
-+ tbl = resize_dereference_paths(rcu_tbl);
- hash_idx = mesh_table_hash(addr, sdata, tbl);
- bucket = &tbl->hash_buckets[hash_idx];
-
-@@ -935,9 +939,30 @@ int mesh_path_del(struct ieee80211_sub_i
-
- err = -ENXIO;
- enddel:
-- mesh_paths_generation++;
- spin_unlock(&tbl->hashwlock[hash_idx]);
-+ return err;
-+}
-+
-+/**
-+ * mesh_path_del - delete a mesh path from the table
-+ *
-+ * @addr: dst address (ETH_ALEN length)
-+ * @sdata: local subif
-+ *
-+ * Returns: 0 if successful
-+ */
-+int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr)
-+{
-+ int err = 0;
-+
-+ /* flush relevant mpp entries first */
-+ mpp_flush_by_proxy(sdata, addr);
-+
-+ read_lock_bh(&pathtbl_resize_lock);
-+ err = table_path_del(mesh_paths, sdata, addr);
-+ mesh_paths_generation++;
- read_unlock_bh(&pathtbl_resize_lock);
-+
- return err;
- }
-
-@@ -951,33 +976,13 @@ enddel:
- */
- static int mpp_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr)
- {
-- struct mesh_table *tbl;
-- struct mesh_path *mpath;
-- struct mpath_node *node;
-- struct hlist_head *bucket;
-- int hash_idx;
- int err = 0;
-
- read_lock_bh(&pathtbl_resize_lock);
-- tbl = resize_dereference_mpp_paths();
-- hash_idx = mesh_table_hash(addr, sdata, tbl);
-- bucket = &tbl->hash_buckets[hash_idx];
--
-- spin_lock(&tbl->hashwlock[hash_idx]);
-- hlist_for_each_entry(node, bucket, list) {
-- mpath = node->mpath;
-- if (mpath->sdata == sdata &&
-- ether_addr_equal(addr, mpath->dst)) {
-- __mesh_path_del(tbl, node);
-- goto enddel;
-- }
-- }
--
-- err = -ENXIO;
--enddel:
-- mesh_paths_generation++;
-- spin_unlock(&tbl->hashwlock[hash_idx]);
-+ err = table_path_del(mpp_paths, sdata, addr);
-+ mpp_paths_generation++;
- read_unlock_bh(&pathtbl_resize_lock);
-+
- return err;
- }
-
diff --git a/package/kernel/mac80211/patches/330-mac80211-minstrel-Change-expected-throughput-unit-ba.patch b/package/kernel/mac80211/patches/330-mac80211-minstrel-Change-expected-throughput-unit-ba.patch
deleted file mode 100644
index 4dc6d663ed..0000000000
--- a/package/kernel/mac80211/patches/330-mac80211-minstrel-Change-expected-throughput-unit-ba.patch
+++ /dev/null
@@ -1,51 +0,0 @@
-From: Sven Eckelmann <sven.eckelmann@open-mesh.com>
-Date: Tue, 2 Feb 2016 08:12:26 +0100
-Subject: [PATCH] mac80211: minstrel: Change expected throughput unit back to
- Kbps
-
-The change from cur_tp to the function
-minstrel_get_tp_avg/minstrel_ht_get_tp_avg changed the unit used for the
-current throughput. For example in minstrel_ht the correct
-conversion between them would be:
-
- mrs->cur_tp / 10 == minstrel_ht_get_tp_avg(..).
-
-This factor 10 must also be included in the calculation of
-minstrel_get_expected_throughput and minstrel_ht_get_expected_throughput to
-return values with the unit [Kbps] instead of [10Kbps]. Otherwise routing
-algorithms like B.A.T.M.A.N. V will make incorrect decision based on these
-values. Its kernel based implementation expects expected_throughput always
-to have the unit [Kbps] and not sometimes [10Kbps] and sometimes [Kbps].
-
-The same requirement has iw or olsrdv2's nl80211 based statistics module
-which retrieve the same data via NL80211_STA_INFO_TX_BITRATE.
-
-Cc: stable@vger.kernel.org
-Fixes: 6a27b2c40b48 ("mac80211: restructure per-rate throughput calculation into function")
-Signed-off-by: Sven Eckelmann <sven@open-mesh.com>
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
-
---- a/net/mac80211/rc80211_minstrel.c
-+++ b/net/mac80211/rc80211_minstrel.c
-@@ -711,7 +711,7 @@ static u32 minstrel_get_expected_through
- * computing cur_tp
- */
- tmp_mrs = &mi->r[idx].stats;
-- tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx], tmp_mrs->prob_ewma);
-+ tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx], tmp_mrs->prob_ewma) * 10;
- tmp_cur_tp = tmp_cur_tp * 1200 * 8 / 1024;
-
- return tmp_cur_tp;
---- a/net/mac80211/rc80211_minstrel_ht.c
-+++ b/net/mac80211/rc80211_minstrel_ht.c
-@@ -1335,7 +1335,8 @@ static u32 minstrel_ht_get_expected_thro
- prob = mi->groups[i].rates[j].prob_ewma;
-
- /* convert tp_avg from pkt per second in kbps */
-- tp_avg = minstrel_ht_get_tp_avg(mi, i, j, prob) * AVG_PKT_SIZE * 8 / 1024;
-+ tp_avg = minstrel_ht_get_tp_avg(mi, i, j, prob) * 10;
-+ tp_avg = tp_avg * AVG_PKT_SIZE * 8 / 1024;
-
- return tp_avg;
- }
diff --git a/package/kernel/mac80211/patches/331-brcmfmac-Increase-nr-of-supported-flowrings.patch b/package/kernel/mac80211/patches/331-brcmfmac-Increase-nr-of-supported-flowrings.patch
deleted file mode 100644
index 1fd016f7f6..0000000000
--- a/package/kernel/mac80211/patches/331-brcmfmac-Increase-nr-of-supported-flowrings.patch
+++ /dev/null
@@ -1,307 +0,0 @@
-From: Hante Meuleman <meuleman@broadcom.com>
-Date: Sun, 7 Feb 2016 18:08:24 +0100
-Subject: [PATCH] brcmfmac: Increase nr of supported flowrings.
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-New generation devices have firmware which has more than 256 flowrings.
-E.g. following debugging message comes from 14e4:4365 BCM4366:
-[ 194.606245] brcmfmac: brcmf_pcie_init_ringbuffers Nr of flowrings is 264
-
-At various code places (related to flowrings) we were using u8 which
-could lead to storing wrong number or infinite loops when indexing with
-this type. This issue was quite easy to spot in brcmf_flowring_detach
-where it led to infinite loop e.g. on failed initialization.
-
-This patch switches code to proper types and increases the maximum
-number of supported flowrings to 512.
-
-Originally this change was sent in September 2015, but back it was
-causing a regression on BCM43602 resulting in:
-Unable to handle kernel NULL pointer dereference at virtual address ...
-
-The reason for this regression was missing update (s/u8/u16) of struct
-brcmf_flowring_ring. This problem was handled in 9f64df9 ("brcmfmac: Fix
-bug in flowring management."). Starting with that it's safe to apply
-this original patch as it doesn't cause a regression anymore.
-
-This patch fixes an infinite loop on BCM4366 which is supported since
-4.4 so it makes sense to apply it to stable 4.4+.
-
-Cc: <stable@vger.kernel.org> # 4.4+
-Reviewed-by: Arend Van Spriel <arend@broadcom.com>
-Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
-Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c
-@@ -32,7 +32,7 @@
- #define BRCMF_FLOWRING_LOW (BRCMF_FLOWRING_HIGH - 256)
- #define BRCMF_FLOWRING_INVALID_IFIDX 0xff
-
--#define BRCMF_FLOWRING_HASH_AP(da, fifo, ifidx) (da[5] + fifo + ifidx * 16)
-+#define BRCMF_FLOWRING_HASH_AP(da, fifo, ifidx) (da[5] * 2 + fifo + ifidx * 16)
- #define BRCMF_FLOWRING_HASH_STA(fifo, ifidx) (fifo + ifidx * 16)
-
- static const u8 brcmf_flowring_prio2fifo[] = {
-@@ -68,7 +68,7 @@ u32 brcmf_flowring_lookup(struct brcmf_f
- u8 prio, u8 ifidx)
- {
- struct brcmf_flowring_hash *hash;
-- u8 hash_idx;
-+ u16 hash_idx;
- u32 i;
- bool found;
- bool sta;
-@@ -88,6 +88,7 @@ u32 brcmf_flowring_lookup(struct brcmf_f
- }
- hash_idx = sta ? BRCMF_FLOWRING_HASH_STA(fifo, ifidx) :
- BRCMF_FLOWRING_HASH_AP(mac, fifo, ifidx);
-+ hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1);
- found = false;
- hash = flow->hash;
- for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) {
-@@ -98,6 +99,7 @@ u32 brcmf_flowring_lookup(struct brcmf_f
- break;
- }
- hash_idx++;
-+ hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1);
- }
- if (found)
- return hash[hash_idx].flowid;
-@@ -111,7 +113,7 @@ u32 brcmf_flowring_create(struct brcmf_f
- {
- struct brcmf_flowring_ring *ring;
- struct brcmf_flowring_hash *hash;
-- u8 hash_idx;
-+ u16 hash_idx;
- u32 i;
- bool found;
- u8 fifo;
-@@ -131,6 +133,7 @@ u32 brcmf_flowring_create(struct brcmf_f
- }
- hash_idx = sta ? BRCMF_FLOWRING_HASH_STA(fifo, ifidx) :
- BRCMF_FLOWRING_HASH_AP(mac, fifo, ifidx);
-+ hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1);
- found = false;
- hash = flow->hash;
- for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) {
-@@ -140,6 +143,7 @@ u32 brcmf_flowring_create(struct brcmf_f
- break;
- }
- hash_idx++;
-+ hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1);
- }
- if (found) {
- for (i = 0; i < flow->nrofrings; i++) {
-@@ -169,7 +173,7 @@ u32 brcmf_flowring_create(struct brcmf_f
- }
-
-
--u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u8 flowid)
-+u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u16 flowid)
- {
- struct brcmf_flowring_ring *ring;
-
-@@ -179,7 +183,7 @@ u8 brcmf_flowring_tid(struct brcmf_flowr
- }
-
-
--static void brcmf_flowring_block(struct brcmf_flowring *flow, u8 flowid,
-+static void brcmf_flowring_block(struct brcmf_flowring *flow, u16 flowid,
- bool blocked)
- {
- struct brcmf_flowring_ring *ring;
-@@ -228,10 +232,10 @@ static void brcmf_flowring_block(struct
- }
-
-
--void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid)
-+void brcmf_flowring_delete(struct brcmf_flowring *flow, u16 flowid)
- {
- struct brcmf_flowring_ring *ring;
-- u8 hash_idx;
-+ u16 hash_idx;
- struct sk_buff *skb;
-
- ring = flow->rings[flowid];
-@@ -253,7 +257,7 @@ void brcmf_flowring_delete(struct brcmf_
- }
-
-
--u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid,
-+u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u16 flowid,
- struct sk_buff *skb)
- {
- struct brcmf_flowring_ring *ring;
-@@ -279,7 +283,7 @@ u32 brcmf_flowring_enqueue(struct brcmf_
- }
-
-
--struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u8 flowid)
-+struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u16 flowid)
- {
- struct brcmf_flowring_ring *ring;
- struct sk_buff *skb;
-@@ -300,7 +304,7 @@ struct sk_buff *brcmf_flowring_dequeue(s
- }
-
-
--void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u8 flowid,
-+void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u16 flowid,
- struct sk_buff *skb)
- {
- struct brcmf_flowring_ring *ring;
-@@ -311,7 +315,7 @@ void brcmf_flowring_reinsert(struct brcm
- }
-
-
--u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u8 flowid)
-+u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u16 flowid)
- {
- struct brcmf_flowring_ring *ring;
-
-@@ -326,7 +330,7 @@ u32 brcmf_flowring_qlen(struct brcmf_flo
- }
-
-
--void brcmf_flowring_open(struct brcmf_flowring *flow, u8 flowid)
-+void brcmf_flowring_open(struct brcmf_flowring *flow, u16 flowid)
- {
- struct brcmf_flowring_ring *ring;
-
-@@ -340,10 +344,10 @@ void brcmf_flowring_open(struct brcmf_fl
- }
-
-
--u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u8 flowid)
-+u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u16 flowid)
- {
- struct brcmf_flowring_ring *ring;
-- u8 hash_idx;
-+ u16 hash_idx;
-
- ring = flow->rings[flowid];
- hash_idx = ring->hash_id;
-@@ -384,7 +388,7 @@ void brcmf_flowring_detach(struct brcmf_
- struct brcmf_pub *drvr = bus_if->drvr;
- struct brcmf_flowring_tdls_entry *search;
- struct brcmf_flowring_tdls_entry *remove;
-- u8 flowid;
-+ u16 flowid;
-
- for (flowid = 0; flowid < flow->nrofrings; flowid++) {
- if (flow->rings[flowid])
-@@ -408,7 +412,7 @@ void brcmf_flowring_configure_addr_mode(
- struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev);
- struct brcmf_pub *drvr = bus_if->drvr;
- u32 i;
-- u8 flowid;
-+ u16 flowid;
-
- if (flow->addr_mode[ifidx] != addr_mode) {
- for (i = 0; i < ARRAY_SIZE(flow->hash); i++) {
-@@ -434,7 +438,7 @@ void brcmf_flowring_delete_peer(struct b
- struct brcmf_flowring_tdls_entry *prev;
- struct brcmf_flowring_tdls_entry *search;
- u32 i;
-- u8 flowid;
-+ u16 flowid;
- bool sta;
-
- sta = (flow->addr_mode[ifidx] == ADDR_INDIRECT);
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h
-@@ -16,7 +16,7 @@
- #define BRCMFMAC_FLOWRING_H
-
-
--#define BRCMF_FLOWRING_HASHSIZE 256
-+#define BRCMF_FLOWRING_HASHSIZE 512 /* has to be 2^x */
- #define BRCMF_FLOWRING_INVALID_ID 0xFFFFFFFF
-
-
-@@ -24,7 +24,7 @@ struct brcmf_flowring_hash {
- u8 mac[ETH_ALEN];
- u8 fifo;
- u8 ifidx;
-- u8 flowid;
-+ u16 flowid;
- };
-
- enum ring_status {
-@@ -61,16 +61,16 @@ u32 brcmf_flowring_lookup(struct brcmf_f
- u8 prio, u8 ifidx);
- u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
- u8 prio, u8 ifidx);
--void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid);
--void brcmf_flowring_open(struct brcmf_flowring *flow, u8 flowid);
--u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u8 flowid);
--u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid,
-+void brcmf_flowring_delete(struct brcmf_flowring *flow, u16 flowid);
-+void brcmf_flowring_open(struct brcmf_flowring *flow, u16 flowid);
-+u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u16 flowid);
-+u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u16 flowid,
- struct sk_buff *skb);
--struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u8 flowid);
--void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u8 flowid,
-+struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u16 flowid);
-+void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u16 flowid,
- struct sk_buff *skb);
--u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u8 flowid);
--u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u8 flowid);
-+u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u16 flowid);
-+u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u16 flowid);
- struct brcmf_flowring *brcmf_flowring_attach(struct device *dev, u16 nrofrings);
- void brcmf_flowring_detach(struct brcmf_flowring *flow);
- void brcmf_flowring_configure_addr_mode(struct brcmf_flowring *flow, int ifidx,
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
-@@ -677,7 +677,7 @@ static u32 brcmf_msgbuf_flowring_create(
- }
-
-
--static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u8 flowid)
-+static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u16 flowid)
- {
- struct brcmf_flowring *flow = msgbuf->flow;
- struct brcmf_commonring *commonring;
-@@ -1310,7 +1310,7 @@ int brcmf_proto_msgbuf_rx_trigger(struct
- }
-
-
--void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u8 flowid)
-+void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u16 flowid)
- {
- struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;
- struct msgbuf_tx_flowring_delete_req *delete;
-@@ -1415,6 +1415,13 @@ int brcmf_proto_msgbuf_attach(struct brc
- u32 count;
-
- if_msgbuf = drvr->bus_if->msgbuf;
-+
-+ if (if_msgbuf->nrof_flowrings >= BRCMF_FLOWRING_HASHSIZE) {
-+ brcmf_err("driver not configured for this many flowrings %d\n",
-+ if_msgbuf->nrof_flowrings);
-+ if_msgbuf->nrof_flowrings = BRCMF_FLOWRING_HASHSIZE - 1;
-+ }
-+
- msgbuf = kzalloc(sizeof(*msgbuf), GFP_KERNEL);
- if (!msgbuf)
- goto fail;
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h
-@@ -33,7 +33,7 @@
-
-
- int brcmf_proto_msgbuf_rx_trigger(struct device *dev);
--void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u8 flowid);
-+void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u16 flowid);
- int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr);
- void brcmf_proto_msgbuf_detach(struct brcmf_pub *drvr);
- #else
diff --git a/package/kernel/mac80211/patches/332-cfg80211-fix-faulty-variable-initialization-in-ieee8.patch b/package/kernel/mac80211/patches/332-cfg80211-fix-faulty-variable-initialization-in-ieee8.patch
deleted file mode 100644
index 620d616058..0000000000
--- a/package/kernel/mac80211/patches/332-cfg80211-fix-faulty-variable-initialization-in-ieee8.patch
+++ /dev/null
@@ -1,22 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Mon, 8 Feb 2016 14:24:36 +0100
-Subject: [PATCH] cfg80211: fix faulty variable initialization in
- ieee80211_amsdu_to_8023s
-
-reuse_skb is set to true if the code decides to use the last segment.
-Fixes a memory leak
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/wireless/util.c
-+++ b/net/wireless/util.c
-@@ -676,7 +676,7 @@ void ieee80211_amsdu_to_8023s(struct sk_
- u8 *payload;
- int offset = 0, remaining, err;
- struct ethhdr eth;
-- bool reuse_skb = true;
-+ bool reuse_skb = false;
- bool last = false;
-
- if (has_80211_header) {
diff --git a/package/kernel/mac80211/patches/333-cfg80211-reuse-existing-page-fragments-in-A-MSDU-rx.patch b/package/kernel/mac80211/patches/333-cfg80211-reuse-existing-page-fragments-in-A-MSDU-rx.patch
deleted file mode 100644
index 23fdb40252..0000000000
--- a/package/kernel/mac80211/patches/333-cfg80211-reuse-existing-page-fragments-in-A-MSDU-rx.patch
+++ /dev/null
@@ -1,132 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Mon, 8 Feb 2016 14:33:19 +0100
-Subject: [PATCH] cfg80211: reuse existing page fragments in A-MSDU rx
-
-This massively reduces data copying and thus improves rx performance
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/wireless/util.c
-+++ b/net/wireless/util.c
-@@ -644,23 +644,93 @@ int ieee80211_data_from_8023(struct sk_b
- }
- EXPORT_SYMBOL(ieee80211_data_from_8023);
-
-+static void
-+__frame_add_frag(struct sk_buff *skb, struct page *page,
-+ void *ptr, int len, int size)
-+{
-+ struct skb_shared_info *sh = skb_shinfo(skb);
-+ int page_offset;
-+
-+ atomic_inc(&page->_count);
-+ page_offset = ptr - page_address(page);
-+ skb_add_rx_frag(skb, sh->nr_frags, page, page_offset, len, size);
-+}
-+
-+static void
-+__ieee80211_amsdu_copy_frag(struct sk_buff *skb, struct sk_buff *frame,
-+ int offset, int len)
-+{
-+ struct skb_shared_info *sh = skb_shinfo(skb);
-+ const skb_frag_t *frag = &sh->frags[-1];
-+ struct page *frag_page;
-+ void *frag_ptr;
-+ int frag_len, frag_size;
-+ int head_size = skb->len - skb->data_len;
-+ int cur_len;
-+
-+ frag_page = virt_to_head_page(skb->head);
-+ frag_ptr = skb->data;
-+ frag_size = head_size;
-+
-+ while (offset >= frag_size) {
-+ offset -= frag_size;
-+ frag++;
-+ frag_page = skb_frag_page(frag);
-+ frag_ptr = skb_frag_address(frag);
-+ frag_size = skb_frag_size(frag);
-+ }
-+
-+ frag_ptr += offset;
-+ frag_len = frag_size - offset;
-+
-+ cur_len = min(len, frag_len);
-+
-+ __frame_add_frag(frame, frag_page, frag_ptr, cur_len, frag_size);
-+ len -= cur_len;
-+
-+ while (len > 0) {
-+ frag++;
-+ frag_len = skb_frag_size(frag);
-+ cur_len = min(len, frag_len);
-+ __frame_add_frag(frame, skb_frag_page(frag),
-+ skb_frag_address(frag), cur_len, frag_len);
-+ len -= cur_len;
-+ }
-+}
-+
- static struct sk_buff *
- __ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen,
-- int offset, int len)
-+ int offset, int len, bool reuse_frag)
- {
- struct sk_buff *frame;
-+ int cur_len = len;
-
- if (skb->len - offset < len)
- return NULL;
-
- /*
-+ * When reusing framents, copy some data to the head to simplify
-+ * ethernet header handling and speed up protocol header processing
-+ * in the stack later.
-+ */
-+ if (reuse_frag)
-+ cur_len = min_t(int, len, 32);
-+
-+ /*
- * Allocate and reserve two bytes more for payload
- * alignment since sizeof(struct ethhdr) is 14.
- */
-- frame = dev_alloc_skb(hlen + sizeof(struct ethhdr) + 2 + len);
-+ frame = dev_alloc_skb(hlen + sizeof(struct ethhdr) + 2 + cur_len);
-
- skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2);
-- skb_copy_bits(skb, offset, skb_put(frame, len), len);
-+ skb_copy_bits(skb, offset, skb_put(frame, cur_len), cur_len);
-+
-+ len -= cur_len;
-+ if (!len)
-+ return frame;
-+
-+ offset += cur_len;
-+ __ieee80211_amsdu_copy_frag(skb, frame, offset, len);
-
- return frame;
- }
-@@ -676,6 +746,7 @@ void ieee80211_amsdu_to_8023s(struct sk_
- u8 *payload;
- int offset = 0, remaining, err;
- struct ethhdr eth;
-+ bool reuse_frag = skb->head_frag && !skb_has_frag_list(skb);
- bool reuse_skb = false;
- bool last = false;
-
-@@ -703,12 +774,13 @@ void ieee80211_amsdu_to_8023s(struct sk_
- offset += sizeof(struct ethhdr);
- /* reuse skb for the last subframe */
- last = remaining <= subframe_len + padding;
-- if (!skb_is_nonlinear(skb) && last) {
-+ if (!skb_is_nonlinear(skb) && !reuse_frag && last) {
- skb_pull(skb, offset);
- frame = skb;
- reuse_skb = true;
- } else {
-- frame = __ieee80211_amsdu_copy(skb, hlen, offset, len);
-+ frame = __ieee80211_amsdu_copy(skb, hlen, offset, len,
-+ reuse_frag);
- if (!frame)
- goto purge;
-
diff --git a/package/kernel/mac80211/patches/334-mac80211-fix-wiphy-supported_band-access.patch b/package/kernel/mac80211/patches/334-mac80211-fix-wiphy-supported_band-access.patch
deleted file mode 100644
index f8f4f0999d..0000000000
--- a/package/kernel/mac80211/patches/334-mac80211-fix-wiphy-supported_band-access.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
-Date: Wed, 10 Feb 2016 16:08:17 +0100
-Subject: [PATCH] mac80211: fix wiphy supported_band access
-
-Fix wiphy supported_band access in tx radiotap parsing. In particular,
-info->band is always set to 0 (IEEE80211_BAND_2GHZ) since it has not
-assigned yet. This cause a kernel crash on 5GHz only devices.
-Move ieee80211_parse_tx_radiotap() after info->band assignment
-
-Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
----
-
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -1890,10 +1890,6 @@ netdev_tx_t ieee80211_monitor_start_xmit
- info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
- IEEE80211_TX_CTL_INJECTED;
-
-- /* process and remove the injection radiotap header */
-- if (!ieee80211_parse_tx_radiotap(local, skb))
-- goto fail;
--
- rcu_read_lock();
-
- /*
-@@ -1955,6 +1951,10 @@ netdev_tx_t ieee80211_monitor_start_xmit
- goto fail_rcu;
-
- info->band = chandef->chan->band;
-+ /* process and remove the injection radiotap header */
-+ if (!ieee80211_parse_tx_radiotap(local, skb))
-+ goto fail_rcu;
-+
- ieee80211_xmit(sdata, NULL, skb);
- rcu_read_unlock();
-
diff --git a/package/kernel/mac80211/patches/335-mac80211-minstrel_ht-set-A-MSDU-tx-limits-based-on-s.patch b/package/kernel/mac80211/patches/335-mac80211-minstrel_ht-set-A-MSDU-tx-limits-based-on-s.patch
deleted file mode 100644
index 4d90ab09cd..0000000000
--- a/package/kernel/mac80211/patches/335-mac80211-minstrel_ht-set-A-MSDU-tx-limits-based-on-s.patch
+++ /dev/null
@@ -1,61 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Thu, 18 Feb 2016 19:30:05 +0100
-Subject: [PATCH] mac80211: minstrel_ht: set A-MSDU tx limits based on selected
- max_prob_rate
-
-Prevents excessive A-MSDU aggregation at low data rates or bad
-conditions.
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/rc80211_minstrel_ht.c
-+++ b/net/mac80211/rc80211_minstrel_ht.c
-@@ -883,6 +883,39 @@ minstrel_ht_set_rate(struct minstrel_pri
- ratetbl->rate[offset].flags = flags;
- }
-
-+static int
-+minstrel_ht_get_max_amsdu_len(struct minstrel_ht_sta *mi)
-+{
-+ int group = mi->max_prob_rate / MCS_GROUP_RATES;
-+ const struct mcs_group *g = &minstrel_mcs_groups[group];
-+ int rate = mi->max_prob_rate % MCS_GROUP_RATES;
-+
-+ /* Disable A-MSDU if max_prob_rate is bad */
-+ if (mi->groups[group].rates[rate].prob_ewma < MINSTREL_FRAC(50, 100))
-+ return 1;
-+
-+ /* If the rate is slower than single-stream MCS1, make A-MSDU limit small */
-+ if (g->duration[rate] > MCS_DURATION(1, 0, 52))
-+ return 500;
-+
-+ /*
-+ * If the rate is slower than single-stream MCS4, limit A-MSDU to usual
-+ * data packet size
-+ */
-+ if (g->duration[rate] > MCS_DURATION(1, 0, 104))
-+ return 1500;
-+
-+ /*
-+ * If the rate is slower than single-stream MCS7, limit A-MSDU to twice
-+ * the usual data packet size
-+ */
-+ if (g->duration[rate] > MCS_DURATION(1, 0, 260))
-+ return 3000;
-+
-+ /* unlimited */
-+ return 0;
-+}
-+
- static void
- minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
- {
-@@ -907,6 +940,7 @@ minstrel_ht_update_rates(struct minstrel
- minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_prob_rate);
- }
-
-+ mi->sta->max_rc_amsdu_len = minstrel_ht_get_max_amsdu_len(mi);
- rates->rate[i].idx = -1;
- rate_control_set_rates(mp->hw, mi->sta, rates);
- }
diff --git a/package/kernel/mac80211/patches/336-mac80211-minstrel_ht-set-default-tx-aggregation-time.patch b/package/kernel/mac80211/patches/336-mac80211-minstrel_ht-set-default-tx-aggregation-time.patch
deleted file mode 100644
index b956687bab..0000000000
--- a/package/kernel/mac80211/patches/336-mac80211-minstrel_ht-set-default-tx-aggregation-time.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Thu, 18 Feb 2016 19:45:33 +0100
-Subject: [PATCH] mac80211: minstrel_ht: set default tx aggregation timeout to
- 0
-
-The value 5000 was put here with the addition of the timeout field to
-ieee80211_start_tx_ba_session. It was originally added in mac80211 to
-save resources for drivers like iwlwifi, which only supports a limited
-number of concurrent aggregation sessions.
-
-Since iwlwifi does not use minstrel_ht and other drivers don't need
-this, 0 is a better default - especially since there have been
-recent reports of aggregation setup related issues reproduced with
-ath9k. This should improve stability without causing any adverse
-effects.
-
-Cc: stable@vger.kernel.org
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/rc80211_minstrel_ht.c
-+++ b/net/mac80211/rc80211_minstrel_ht.c
-@@ -692,7 +692,7 @@ minstrel_aggr_check(struct ieee80211_sta
- if (likely(sta->ampdu_mlme.tid_tx[tid]))
- return;
-
-- ieee80211_start_tx_ba_session(pubsta, tid, 5000);
-+ ieee80211_start_tx_ba_session(pubsta, tid, 0);
- }
-
- static void
diff --git a/package/kernel/mac80211/patches/337-mac80211-minstrel_ht-fix-a-logic-error-in-RTS-CTS-ha.patch b/package/kernel/mac80211/patches/337-mac80211-minstrel_ht-fix-a-logic-error-in-RTS-CTS-ha.patch
deleted file mode 100644
index 76a6b6994d..0000000000
--- a/package/kernel/mac80211/patches/337-mac80211-minstrel_ht-fix-a-logic-error-in-RTS-CTS-ha.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Wed, 24 Feb 2016 12:03:13 +0100
-Subject: [PATCH] mac80211: minstrel_ht: fix a logic error in RTS/CTS handling
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-RTS/CTS needs to be enabled if the rate is a fallback rate *or* if it's
-a dual-stream rate and the sta is in dynamic SMPS mode.
-
-Fixes: a3ebb4e1b763 ("mac80211: minstrel_ht: handle peers in dynamic SMPS")
-Reported-by: Matías Richart <mrichart@fing.edu.uy>
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/rc80211_minstrel_ht.c
-+++ b/net/mac80211/rc80211_minstrel_ht.c
-@@ -872,7 +872,7 @@ minstrel_ht_set_rate(struct minstrel_pri
- * - if station is in dynamic SMPS (and streams > 1)
- * - for fallback rates, to increase chances of getting through
- */
-- if (offset > 0 &&
-+ if (offset > 0 ||
- (mi->sta->smps_mode == IEEE80211_SMPS_DYNAMIC &&
- group->streams > 1)) {
- ratetbl->rate[offset].count = ratetbl->rate[offset].count_rts;
diff --git a/package/kernel/mac80211/patches/338-mac80211-Fix-Public-Action-frame-RX-in-AP-mode.patch b/package/kernel/mac80211/patches/338-mac80211-Fix-Public-Action-frame-RX-in-AP-mode.patch
deleted file mode 100644
index 56cd94aa15..0000000000
--- a/package/kernel/mac80211/patches/338-mac80211-Fix-Public-Action-frame-RX-in-AP-mode.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-From: Jouni Malinen <jouni@qca.qualcomm.com>
-Date: Tue, 1 Mar 2016 00:29:00 +0200
-Subject: [PATCH] mac80211: Fix Public Action frame RX in AP mode
-
-Public Action frames use special rules for how the BSSID field (Address
-3) is set. A wildcard BSSID is used in cases where the transmitter and
-recipient are not members of the same BSS. As such, we need to accept
-Public Action frames with wildcard BSSID.
-
-Commit db8e17324553 ("mac80211: ignore frames between TDLS peers when
-operating as AP") added a rule that drops Action frames to TDLS-peers
-based on an Action frame having different DA (Address 1) and BSSID
-(Address 3) values. This is not correct since it misses the possibility
-of BSSID being a wildcard BSSID in which case the Address 1 would not
-necessarily match.
-
-Fix this by allowing mac80211 to accept wildcard BSSID in an Action
-frame when in AP mode.
-
-Fixes: db8e17324553 ("mac80211: ignore frames between TDLS peers when operating as AP")
-Cc: stable@vger.kernel.org
-Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
-
---- a/net/mac80211/rx.c
-+++ b/net/mac80211/rx.c
-@@ -3374,6 +3374,7 @@ static bool ieee80211_accept_frame(struc
- return false;
- /* ignore action frames to TDLS-peers */
- if (ieee80211_is_action(hdr->frame_control) &&
-+ !is_broadcast_ether_addr(bssid) &&
- !ether_addr_equal(bssid, hdr->addr1))
- return false;
- }
diff --git a/package/kernel/mac80211/patches/339-cfg80211-add-radiotap-VHT-info-to-rtap_namespace_siz.patch b/package/kernel/mac80211/patches/339-cfg80211-add-radiotap-VHT-info-to-rtap_namespace_siz.patch
deleted file mode 100644
index 15d6cd03ea..0000000000
--- a/package/kernel/mac80211/patches/339-cfg80211-add-radiotap-VHT-info-to-rtap_namespace_siz.patch
+++ /dev/null
@@ -1,21 +0,0 @@
-From: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
-Date: Fri, 19 Feb 2016 11:43:04 +0100
-Subject: [PATCH] cfg80211: add radiotap VHT info to rtap_namespace_sizes
-
-Add IEEE80211_RADIOTAP_VHT entry to rtap_namespace_sizes array in order to
-define alignment and size of VHT info in tx radiotap
-
-Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
-
---- a/net/wireless/radiotap.c
-+++ b/net/wireless/radiotap.c
-@@ -43,6 +43,7 @@ static const struct radiotap_align_size
- [IEEE80211_RADIOTAP_DATA_RETRIES] = { .align = 1, .size = 1, },
- [IEEE80211_RADIOTAP_MCS] = { .align = 1, .size = 3, },
- [IEEE80211_RADIOTAP_AMPDU_STATUS] = { .align = 4, .size = 8, },
-+ [IEEE80211_RADIOTAP_VHT] = { .align = 2, .size = 12, },
- /*
- * add more here as they are defined in radiotap.h
- */
diff --git a/package/kernel/mac80211/patches/340-mac80211-fix-parsing-of-40Mhz-in-injected-radiotap-h.patch b/package/kernel/mac80211/patches/340-mac80211-fix-parsing-of-40Mhz-in-injected-radiotap-h.patch
deleted file mode 100644
index de1b38625c..0000000000
--- a/package/kernel/mac80211/patches/340-mac80211-fix-parsing-of-40Mhz-in-injected-radiotap-h.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From: Sven Eckelmann <sven@narfation.org>
-Date: Wed, 24 Feb 2016 16:25:49 +0100
-Subject: [PATCH] mac80211: fix parsing of 40Mhz in injected radiotap
- header
-
-The MCS bandwidth part of the radiotap header is 2 bits wide. The full 2
-bit have to compared against IEEE80211_RADIOTAP_MCS_BW_40 and not only if
-the first bit is set. Otherwise IEEE80211_RADIOTAP_MCS_BW_40 can be
-confused with IEEE80211_RADIOTAP_MCS_BW_20U.
-
-Fixes: 5ec3aed9ba4c ("mac80211: Parse legacy and HT rate in injected frames")
-Signed-off-by: Sven Eckelmann <sven@narfation.org>
----
-
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -1689,7 +1689,7 @@ static bool ieee80211_parse_tx_radiotap(
- bool rate_found = false;
- u8 rate_retries = 0;
- u16 rate_flags = 0;
-- u8 mcs_known, mcs_flags;
-+ u8 mcs_known, mcs_flags, mcs_bw;
- int i;
-
- info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
-@@ -1765,8 +1765,9 @@ static bool ieee80211_parse_tx_radiotap(
- mcs_flags & IEEE80211_RADIOTAP_MCS_SGI)
- rate_flags |= IEEE80211_TX_RC_SHORT_GI;
-
-+ mcs_bw = mcs_flags & IEEE80211_RADIOTAP_MCS_BW_MASK;
- if (mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_BW &&
-- mcs_flags & IEEE80211_RADIOTAP_MCS_BW_40)
-+ mcs_bw == IEEE80211_RADIOTAP_MCS_BW_40)
- rate_flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
- break;
-
diff --git a/package/kernel/mac80211/patches/341-mac80211-parse-VHT-info-in-injected-frames.patch b/package/kernel/mac80211/patches/341-mac80211-parse-VHT-info-in-injected-frames.patch
deleted file mode 100644
index ac1f2517f2..0000000000
--- a/package/kernel/mac80211/patches/341-mac80211-parse-VHT-info-in-injected-frames.patch
+++ /dev/null
@@ -1,65 +0,0 @@
-From: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
-Date: Tue, 23 Feb 2016 15:43:35 +0100
-Subject: [PATCH] mac80211: parse VHT info in injected frames
-
-Add VHT radiotap parsing support to ieee80211_parse_tx_radiotap().
-That capability has been tested using a d-link dir-860l rev b1 running
-OpenWrt trunk and mt76 driver
-
-Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
----
-
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -1690,6 +1690,8 @@ static bool ieee80211_parse_tx_radiotap(
- u8 rate_retries = 0;
- u16 rate_flags = 0;
- u8 mcs_known, mcs_flags, mcs_bw;
-+ u16 vht_known;
-+ u8 vht_mcs = 0, vht_nss = 0;
- int i;
-
- info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
-@@ -1771,6 +1773,32 @@ static bool ieee80211_parse_tx_radiotap(
- rate_flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
- break;
-
-+ case IEEE80211_RADIOTAP_VHT:
-+ vht_known = get_unaligned_le16(iterator.this_arg);
-+ rate_found = true;
-+
-+ rate_flags = IEEE80211_TX_RC_VHT_MCS;
-+ if ((vht_known & IEEE80211_RADIOTAP_VHT_KNOWN_GI) &&
-+ (iterator.this_arg[2] &
-+ IEEE80211_RADIOTAP_VHT_FLAG_SGI))
-+ rate_flags |= IEEE80211_TX_RC_SHORT_GI;
-+ if (vht_known &
-+ IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH) {
-+ if (iterator.this_arg[3] == 1)
-+ rate_flags |=
-+ IEEE80211_TX_RC_40_MHZ_WIDTH;
-+ else if (iterator.this_arg[3] == 4)
-+ rate_flags |=
-+ IEEE80211_TX_RC_80_MHZ_WIDTH;
-+ else if (iterator.this_arg[3] == 11)
-+ rate_flags |=
-+ IEEE80211_TX_RC_160_MHZ_WIDTH;
-+ }
-+
-+ vht_mcs = iterator.this_arg[4] >> 4;
-+ vht_nss = iterator.this_arg[4] & 0xF;
-+ break;
-+
- /*
- * Please update the file
- * Documentation/networking/mac80211-injection.txt
-@@ -1796,6 +1824,9 @@ static bool ieee80211_parse_tx_radiotap(
-
- if (rate_flags & IEEE80211_TX_RC_MCS) {
- info->control.rates[0].idx = rate;
-+ } else if (rate_flags & IEEE80211_TX_RC_VHT_MCS) {
-+ ieee80211_rate_set_vht(info->control.rates, vht_mcs,
-+ vht_nss);
- } else {
- for (i = 0; i < sband->n_bitrates; i++) {
- if (rate * 5 != sband->bitrates[i].bitrate)
diff --git a/package/kernel/mac80211/patches/342-mac80211-do-not-pass-injected-frames-without-a-valid.patch b/package/kernel/mac80211/patches/342-mac80211-do-not-pass-injected-frames-without-a-valid.patch
deleted file mode 100644
index 4f00b50426..0000000000
--- a/package/kernel/mac80211/patches/342-mac80211-do-not-pass-injected-frames-without-a-valid.patch
+++ /dev/null
@@ -1,23 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Wed, 2 Mar 2016 15:51:40 +0100
-Subject: [PATCH] mac80211: do not pass injected frames without a valid rate to
- the driver
-
-Fall back to rate control if the requested bitrate was not found.
-
-Fixes: dfdfc2beb0dd ("mac80211: Parse legacy and HT rate in injected frames")
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -1837,6 +1837,9 @@ static bool ieee80211_parse_tx_radiotap(
- }
- }
-
-+ if (info->control.rates[0].idx < 0)
-+ info->control.flags &= ~IEEE80211_TX_CTRL_RATE_INJECT;
-+
- info->control.rates[0].flags = rate_flags;
- info->control.rates[0].count = min_t(u8, rate_retries + 1,
- local->hw.max_rate_tries);
diff --git a/package/kernel/mac80211/patches/343-mac80211-minstrel_ht-improve-sample-rate-skip-logic.patch b/package/kernel/mac80211/patches/343-mac80211-minstrel_ht-improve-sample-rate-skip-logic.patch
deleted file mode 100644
index c3db6eb545..0000000000
--- a/package/kernel/mac80211/patches/343-mac80211-minstrel_ht-improve-sample-rate-skip-logic.patch
+++ /dev/null
@@ -1,77 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Thu, 3 Mar 2016 23:20:06 +0100
-Subject: [PATCH] mac80211: minstrel_ht: improve sample rate skip logic
-
-There were a few issues that were slowing down the process of finding
-the optimal rate, especially on devices with multi-rate retry
-limitations:
-
-When max_tp_rate[0] was slower than max_tp_rate[1], the code did not
-sample max_tp_rate[1], which would often allow it to switch places with
-max_tp_rate[0] (e.g. if only the first sampling attempts were bad, but the
-rate is otherwise good).
-
-Also, sample attempts of rates between max_tp_rate[0] and [1] were being
-ignored in this case, because the code only checked if the rate was
-slower than [1].
-
-Fix this by checking against the fastest / second fastest max_tp_rate
-instead of assuming a specific order between the two.
-
-In my tests this patch significantly reduces the time until minstrel_ht
-finds the optimal rate right after assoc
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/rc80211_minstrel_ht.c
-+++ b/net/mac80211/rc80211_minstrel_ht.c
-@@ -958,6 +958,7 @@ minstrel_get_sample_rate(struct minstrel
- struct minstrel_rate_stats *mrs;
- struct minstrel_mcs_group_data *mg;
- unsigned int sample_dur, sample_group, cur_max_tp_streams;
-+ int tp_rate1, tp_rate2;
- int sample_idx = 0;
-
- if (mi->sample_wait > 0) {
-@@ -979,14 +980,22 @@ minstrel_get_sample_rate(struct minstrel
- mrs = &mg->rates[sample_idx];
- sample_idx += sample_group * MCS_GROUP_RATES;
-
-+ /* Set tp_rate1, tp_rate2 to the highest / second highest max_tp_rate */
-+ if (minstrel_get_duration(mi->max_tp_rate[0]) >
-+ minstrel_get_duration(mi->max_tp_rate[1])) {
-+ tp_rate1 = mi->max_tp_rate[1];
-+ tp_rate2 = mi->max_tp_rate[0];
-+ } else {
-+ tp_rate1 = mi->max_tp_rate[0];
-+ tp_rate2 = mi->max_tp_rate[1];
-+ }
-+
- /*
- * Sampling might add some overhead (RTS, no aggregation)
-- * to the frame. Hence, don't use sampling for the currently
-- * used rates.
-+ * to the frame. Hence, don't use sampling for the highest currently
-+ * used highest throughput or probability rate.
- */
-- if (sample_idx == mi->max_tp_rate[0] ||
-- sample_idx == mi->max_tp_rate[1] ||
-- sample_idx == mi->max_prob_rate)
-+ if (sample_idx == mi->max_tp_rate[0] || sample_idx == mi->max_prob_rate)
- return -1;
-
- /*
-@@ -1001,10 +1010,10 @@ minstrel_get_sample_rate(struct minstrel
- * if the link is working perfectly.
- */
-
-- cur_max_tp_streams = minstrel_mcs_groups[mi->max_tp_rate[0] /
-+ cur_max_tp_streams = minstrel_mcs_groups[tp_rate1 /
- MCS_GROUP_RATES].streams;
- sample_dur = minstrel_get_duration(sample_idx);
-- if (sample_dur >= minstrel_get_duration(mi->max_tp_rate[1]) &&
-+ if (sample_dur >= minstrel_get_duration(tp_rate2) &&
- (cur_max_tp_streams - 1 <
- minstrel_mcs_groups[sample_group].streams ||
- sample_dur >= minstrel_get_duration(mi->max_prob_rate))) {
diff --git a/package/kernel/mac80211/patches/344-0001-brcmfmac-change-function-name-for-brcmf_cfg80211_wai.patch b/package/kernel/mac80211/patches/344-0001-brcmfmac-change-function-name-for-brcmf_cfg80211_wai.patch
deleted file mode 100644
index e3427de732..0000000000
--- a/package/kernel/mac80211/patches/344-0001-brcmfmac-change-function-name-for-brcmf_cfg80211_wai.patch
+++ /dev/null
@@ -1,99 +0,0 @@
-From: Arend van Spriel <arend@broadcom.com>
-Date: Wed, 17 Feb 2016 11:26:50 +0100
-Subject: [PATCH] brcmfmac: change function name for
- brcmf_cfg80211_wait_vif_event_timeout()
-
-Dropping the '_timeout' from the function name as the fact that a timeout
-value is passed makes it obvious a timeout is used. Also helps to keep code
-lines a bit shorter and easier to stick to 80 char boundary.
-
-Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -564,8 +564,8 @@ struct wireless_dev *brcmf_ap_add_vif(st
- }
-
- /* wait for firmware event */
-- err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_ADD,
-- BRCMF_VIF_EVENT_TIMEOUT);
-+ err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_ADD,
-+ BRCMF_VIF_EVENT_TIMEOUT);
- brcmf_cfg80211_arm_vif_event(cfg, NULL);
- if (!err) {
- brcmf_err("timeout occurred\n");
-@@ -6395,8 +6395,9 @@ bool brcmf_cfg80211_vif_event_armed(stru
-
- return armed;
- }
--int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
-- u8 action, ulong timeout)
-+
-+int brcmf_cfg80211_wait_vif_event(struct brcmf_cfg80211_info *cfg,
-+ u8 action, ulong timeout)
- {
- struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
-@@ -402,8 +402,8 @@ bool brcmf_get_vif_state_any(struct brcm
- void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
- struct brcmf_cfg80211_vif *vif);
- bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg);
--int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
-- u8 action, ulong timeout);
-+int brcmf_cfg80211_wait_vif_event(struct brcmf_cfg80211_info *cfg,
-+ u8 action, ulong timeout);
- s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
- struct brcmf_if *ifp, bool aborted,
- bool fw_abort);
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
-@@ -1988,8 +1988,8 @@ int brcmf_p2p_ifchange(struct brcmf_cfg8
- brcmf_cfg80211_arm_vif_event(cfg, NULL);
- return err;
- }
-- err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_CHANGE,
-- BRCMF_VIF_EVENT_TIMEOUT);
-+ err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_CHANGE,
-+ BRCMF_VIF_EVENT_TIMEOUT);
- brcmf_cfg80211_arm_vif_event(cfg, NULL);
- if (!err) {
- brcmf_err("No BRCMF_E_IF_CHANGE event received\n");
-@@ -2090,8 +2090,8 @@ static struct wireless_dev *brcmf_p2p_cr
- }
-
- /* wait for firmware event */
-- err = brcmf_cfg80211_wait_vif_event_timeout(p2p->cfg, BRCMF_E_IF_ADD,
-- BRCMF_VIF_EVENT_TIMEOUT);
-+ err = brcmf_cfg80211_wait_vif_event(p2p->cfg, BRCMF_E_IF_ADD,
-+ BRCMF_VIF_EVENT_TIMEOUT);
- brcmf_cfg80211_arm_vif_event(p2p->cfg, NULL);
- brcmf_fweh_p2pdev_setup(pri_ifp, false);
- if (!err) {
-@@ -2180,8 +2180,8 @@ struct wireless_dev *brcmf_p2p_add_vif(s
- }
-
- /* wait for firmware event */
-- err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_ADD,
-- BRCMF_VIF_EVENT_TIMEOUT);
-+ err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_ADD,
-+ BRCMF_VIF_EVENT_TIMEOUT);
- brcmf_cfg80211_arm_vif_event(cfg, NULL);
- if (!err) {
- brcmf_err("timeout occurred\n");
-@@ -2274,8 +2274,8 @@ int brcmf_p2p_del_vif(struct wiphy *wiph
- }
- if (!err) {
- /* wait for firmware event */
-- err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_DEL,
-- BRCMF_VIF_EVENT_TIMEOUT);
-+ err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_DEL,
-+ BRCMF_VIF_EVENT_TIMEOUT);
- if (!err)
- err = -EIO;
- else
diff --git a/package/kernel/mac80211/patches/344-0002-brcmfmac-Limit-memory-allocs-to-64K.patch b/package/kernel/mac80211/patches/344-0002-brcmfmac-Limit-memory-allocs-to-64K.patch
deleted file mode 100644
index 9c336f774f..0000000000
--- a/package/kernel/mac80211/patches/344-0002-brcmfmac-Limit-memory-allocs-to-64K.patch
+++ /dev/null
@@ -1,127 +0,0 @@
-From: Hante Meuleman <meuleman@broadcom.com>
-Date: Wed, 17 Feb 2016 11:26:51 +0100
-Subject: [PATCH] brcmfmac: Limit memory allocs to <64K
-
-Some systems have problems with allocating memory allocation larger
-then 64K. Often on unload/load or suspend/resume a failure is
-reported: Could not allocate wiphy device. This patch makes the
-escan intermediate storage buf dynamically allocated, and smaller
-than 64K.
-
-Reviewed-by: Arend Van Spriel <arend@broadcom.com>
-Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
-Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -1125,7 +1125,7 @@ brcmf_cfg80211_escan(struct wiphy *wiphy
-
- /* Arm scan timeout timer */
- mod_timer(&cfg->escan_timeout, jiffies +
-- WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
-+ BRCMF_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
-
- return 0;
-
-@@ -3020,7 +3020,7 @@ brcmf_cfg80211_escan_handler(struct brcm
-
- list = (struct brcmf_scan_results *)
- cfg->escan_info.escan_buf;
-- if (bi_length > WL_ESCAN_BUF_SIZE - list->buflen) {
-+ if (bi_length > BRCMF_ESCAN_BUF_SIZE - list->buflen) {
- brcmf_err("Buffer is too small: ignoring\n");
- goto exit;
- }
-@@ -3033,8 +3033,8 @@ brcmf_cfg80211_escan_handler(struct brcm
- bss_info_le))
- goto exit;
- }
-- memcpy(&(cfg->escan_info.escan_buf[list->buflen]),
-- bss_info_le, bi_length);
-+ memcpy(&cfg->escan_info.escan_buf[list->buflen], bss_info_le,
-+ bi_length);
- list->version = le32_to_cpu(bss_info_le->version);
- list->buflen += bi_length;
- list->count++;
-@@ -5402,14 +5402,14 @@ static void brcmf_deinit_priv_mem(struct
- {
- kfree(cfg->conf);
- cfg->conf = NULL;
-- kfree(cfg->escan_ioctl_buf);
-- cfg->escan_ioctl_buf = NULL;
- kfree(cfg->extra_buf);
- cfg->extra_buf = NULL;
- kfree(cfg->wowl.nd);
- cfg->wowl.nd = NULL;
- kfree(cfg->wowl.nd_info);
- cfg->wowl.nd_info = NULL;
-+ kfree(cfg->escan_info.escan_buf);
-+ cfg->escan_info.escan_buf = NULL;
- }
-
- static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
-@@ -5417,9 +5417,6 @@ static s32 brcmf_init_priv_mem(struct br
- cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
- if (!cfg->conf)
- goto init_priv_mem_out;
-- cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
-- if (!cfg->escan_ioctl_buf)
-- goto init_priv_mem_out;
- cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
- if (!cfg->extra_buf)
- goto init_priv_mem_out;
-@@ -5431,6 +5428,9 @@ static s32 brcmf_init_priv_mem(struct br
- GFP_KERNEL);
- if (!cfg->wowl.nd_info)
- goto init_priv_mem_out;
-+ cfg->escan_info.escan_buf = kzalloc(BRCMF_ESCAN_BUF_SIZE, GFP_KERNEL);
-+ if (!cfg->escan_info.escan_buf)
-+ goto init_priv_mem_out;
-
- return 0;
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
-@@ -28,8 +28,11 @@
- #define WL_ROAM_TRIGGER_LEVEL -75
- #define WL_ROAM_DELTA 20
-
--#define WL_ESCAN_BUF_SIZE (1024 * 64)
--#define WL_ESCAN_TIMER_INTERVAL_MS 10000 /* E-Scan timeout */
-+/* Keep BRCMF_ESCAN_BUF_SIZE below 64K (65536). Allocing over 64K can be
-+ * problematic on some systems and should be avoided.
-+ */
-+#define BRCMF_ESCAN_BUF_SIZE 65000
-+#define BRCMF_ESCAN_TIMER_INTERVAL_MS 10000 /* E-Scan timeout */
-
- #define WL_ESCAN_ACTION_START 1
- #define WL_ESCAN_ACTION_CONTINUE 2
-@@ -205,7 +208,7 @@ enum wl_escan_state {
-
- struct escan_info {
- u32 escan_state;
-- u8 escan_buf[WL_ESCAN_BUF_SIZE];
-+ u8 *escan_buf;
- struct wiphy *wiphy;
- struct brcmf_if *ifp;
- s32 (*run)(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
-@@ -278,7 +281,6 @@ struct brcmf_cfg80211_wowl {
- * @escan_info: escan information.
- * @escan_timeout: Timer for catch scan timeout.
- * @escan_timeout_work: scan timeout worker.
-- * @escan_ioctl_buf: dongle command buffer for escan commands.
- * @vif_list: linked list of vif instances.
- * @vif_cnt: number of vif instances.
- * @vif_event: vif event signalling.
-@@ -309,7 +311,6 @@ struct brcmf_cfg80211_info {
- struct escan_info escan_info;
- struct timer_list escan_timeout;
- struct work_struct escan_timeout_work;
-- u8 *escan_ioctl_buf;
- struct list_head vif_list;
- struct brcmf_cfg80211_vif_event vif_event;
- struct completion vif_disabled;
diff --git a/package/kernel/mac80211/patches/344-0003-brcmfmac-check-for-wowl-support-before-enumerating-f.patch b/package/kernel/mac80211/patches/344-0003-brcmfmac-check-for-wowl-support-before-enumerating-f.patch
deleted file mode 100644
index ee3d9f37a8..0000000000
--- a/package/kernel/mac80211/patches/344-0003-brcmfmac-check-for-wowl-support-before-enumerating-f.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-From: Franky Lin <frankyl@broadcom.com>
-Date: Wed, 17 Feb 2016 11:26:52 +0100
-Subject: [PATCH] brcmfmac: check for wowl support before enumerating feature
- flag
-
-In some cases wiphy->wowlan could be NULL if firmware doesn't have the
-support. Driver should check for support before walking down the feature
-flags.
-
-Reviewed-by: Arend Van Spriel <arend@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
-Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
-Signed-off-by: Franky Lin <frankyl@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -6594,7 +6594,8 @@ struct brcmf_cfg80211_info *brcmf_cfg802
- if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_RANDOM_MAC)) {
- wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR;
- #ifdef CONFIG_PM
-- if (wiphy->wowlan->flags & WIPHY_WOWLAN_NET_DETECT)
-+ if (wiphy->wowlan &&
-+ wiphy->wowlan->flags & WIPHY_WOWLAN_NET_DETECT)
- wiphy->features |= NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
- #endif
- }
diff --git a/package/kernel/mac80211/patches/344-0004-brcmfmac-Configure-country-code-using-device-specifi.patch b/package/kernel/mac80211/patches/344-0004-brcmfmac-Configure-country-code-using-device-specifi.patch
deleted file mode 100644
index c52cac87b9..0000000000
--- a/package/kernel/mac80211/patches/344-0004-brcmfmac-Configure-country-code-using-device-specifi.patch
+++ /dev/null
@@ -1,214 +0,0 @@
-From: Hante Meuleman <meuleman@broadcom.com>
-Date: Wed, 17 Feb 2016 11:26:53 +0100
-Subject: [PATCH] brcmfmac: Configure country code using device specific
- settings
-
-Country code configuration in a device is a device specific
-operation. For this the country code as specified by reg notifier
-(iso3166 alpha2) needs to be translated to a device specific
-country locale and revision number. This patch adds this
-translation and puts a placeholder in the device specific settings
-where the translation table can be stored. Additional patches will
-be needed to read these tables from for example device platform
-data.
-
-Reviewed-by: Arend Van Spriel <arend@broadcom.com>
-Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
-Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -6405,28 +6405,85 @@ int brcmf_cfg80211_wait_vif_event(struct
- vif_event_equals(event, action), timeout);
- }
-
-+static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha2[2],
-+ struct brcmf_fil_country_le *ccreq)
-+{
-+ struct cc_translate *country_codes;
-+ struct cc_entry *cc;
-+ s32 found_index;
-+ int i;
-+
-+ country_codes = drvr->settings->country_codes;
-+ if (!country_codes) {
-+ brcmf_dbg(TRACE, "No country codes configured for device\n");
-+ return -EINVAL;
-+ }
-+
-+ if ((alpha2[0] == ccreq->country_abbrev[0]) &&
-+ (alpha2[1] == ccreq->country_abbrev[1])) {
-+ brcmf_dbg(TRACE, "Country code already set\n");
-+ return -EAGAIN;
-+ }
-+
-+ found_index = -1;
-+ for (i = 0; i < country_codes->table_size; i++) {
-+ cc = &country_codes->table[i];
-+ if ((cc->iso3166[0] == '\0') && (found_index == -1))
-+ found_index = i;
-+ if ((cc->iso3166[0] == alpha2[0]) &&
-+ (cc->iso3166[1] == alpha2[1])) {
-+ found_index = i;
-+ break;
-+ }
-+ }
-+ if (found_index == -1) {
-+ brcmf_dbg(TRACE, "No country code match found\n");
-+ return -EINVAL;
-+ }
-+ memset(ccreq, 0, sizeof(*ccreq));
-+ ccreq->rev = cpu_to_le32(country_codes->table[found_index].rev);
-+ memcpy(ccreq->ccode, country_codes->table[found_index].cc,
-+ BRCMF_COUNTRY_BUF_SZ);
-+ ccreq->country_abbrev[0] = alpha2[0];
-+ ccreq->country_abbrev[1] = alpha2[1];
-+ ccreq->country_abbrev[2] = 0;
-+
-+ return 0;
-+}
-+
- static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
- struct regulatory_request *req)
- {
- struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
- struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
- struct brcmf_fil_country_le ccreq;
-+ s32 err;
- int i;
-
-- brcmf_dbg(TRACE, "enter: initiator=%d, alpha=%c%c\n", req->initiator,
-- req->alpha2[0], req->alpha2[1]);
--
- /* ignore non-ISO3166 country codes */
- for (i = 0; i < sizeof(req->alpha2); i++)
- if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
-- brcmf_err("not a ISO3166 code\n");
-+ brcmf_err("not a ISO3166 code (0x%02x 0x%02x)\n",
-+ req->alpha2[0], req->alpha2[1]);
- return;
- }
-- memset(&ccreq, 0, sizeof(ccreq));
-- ccreq.rev = cpu_to_le32(-1);
-- memcpy(ccreq.ccode, req->alpha2, sizeof(req->alpha2));
-- if (brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq))) {
-- brcmf_err("firmware rejected country setting\n");
-+
-+ brcmf_dbg(TRACE, "Enter: initiator=%d, alpha=%c%c\n", req->initiator,
-+ req->alpha2[0], req->alpha2[1]);
-+
-+ err = brcmf_fil_iovar_data_get(ifp, "country", &ccreq, sizeof(ccreq));
-+ if (err) {
-+ brcmf_err("Country code iovar returned err = %d\n", err);
-+ return;
-+ }
-+
-+ err = brcmf_translate_country_code(ifp->drvr, req->alpha2, &ccreq);
-+ if (err)
-+ return;
-+
-+ err = brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq));
-+ if (err) {
-+ brcmf_err("Firmware rejected country setting\n");
- return;
- }
- brcmf_setup_wiphybands(wiphy);
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
-@@ -230,10 +230,8 @@ void brcmf_mp_attach(void)
- int brcmf_mp_device_attach(struct brcmf_pub *drvr)
- {
- drvr->settings = kzalloc(sizeof(*drvr->settings), GFP_ATOMIC);
-- if (!drvr->settings) {
-- brcmf_err("Failed to alloca storage space for settings\n");
-+ if (!drvr->settings)
- return -ENOMEM;
-- }
-
- drvr->settings->sdiod_txglomsz = brcmf_sdiod_txglomsz;
- drvr->settings->p2p_enable = !!brcmf_p2p_enable;
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
-@@ -15,6 +15,8 @@
- #ifndef BRCMFMAC_COMMON_H
- #define BRCMFMAC_COMMON_H
-
-+#include "fwil_types.h"
-+
- extern const u8 ALLFFMAC[ETH_ALEN];
-
- #define BRCMF_FW_ALTPATH_LEN 256
-@@ -39,6 +41,33 @@ struct brcmf_mp_global_t {
- extern struct brcmf_mp_global_t brcmf_mp_global;
-
- /**
-+ * struct cc_entry - Struct for translating user space country code (iso3166) to
-+ * firmware country code and revision.
-+ *
-+ * @iso3166: iso3166 alpha 2 country code string.
-+ * @cc: firmware country code string.
-+ * @rev: firmware country code revision.
-+ */
-+struct cc_entry {
-+ char iso3166[BRCMF_COUNTRY_BUF_SZ];
-+ char cc[BRCMF_COUNTRY_BUF_SZ];
-+ s32 rev;
-+};
-+
-+/**
-+ * struct cc_translate - Struct for translating country codes as set by user
-+ * space to a country code and rev which can be used by
-+ * firmware.
-+ *
-+ * @table_size: number of entries in table (> 0)
-+ * @table: dynamic array of 1 or more elements with translation information.
-+ */
-+struct cc_translate {
-+ int table_size;
-+ struct cc_entry table[0];
-+};
-+
-+/**
- * struct brcmf_mp_device - Device module paramaters.
- *
- * @sdiod_txglomsz: SDIO txglom size.
-@@ -47,6 +76,7 @@ extern struct brcmf_mp_global_t brcmf_mp
- * @feature_disable: Feature_disable bitmask.
- * @fcmode: FWS flow control.
- * @roamoff: Firmware roaming off?
-+ * @country_codes: If available, pointer to struct for translating country codes
- */
- struct brcmf_mp_device {
- int sdiod_txglomsz;
-@@ -56,6 +86,7 @@ struct brcmf_mp_device {
- int fcmode;
- bool roamoff;
- bool ignore_probe_fail;
-+ struct cc_translate *country_codes;
- };
-
- void brcmf_mp_attach(void);
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
-@@ -134,6 +134,8 @@
- #define BRCMF_PFN_MAC_OUI_ONLY BIT(0)
- #define BRCMF_PFN_SET_MAC_UNASSOC BIT(1)
-
-+#define BRCMF_MCSSET_LEN 16
-+
- /* join preference types for join_pref iovar */
- enum brcmf_join_pref_types {
- BRCMF_JOIN_PREF_RSSI = 1,
-@@ -279,7 +281,7 @@ struct brcmf_bss_info_le {
- __le32 reserved32[1]; /* Reserved for expansion of BSS properties */
- u8 flags; /* flags */
- u8 reserved[3]; /* Reserved for expansion of BSS properties */
-- u8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */
-+ u8 basic_mcs[BRCMF_MCSSET_LEN]; /* 802.11N BSS required MCS set */
-
- __le16 ie_offset; /* offset at which IEs start, from beginning */
- __le32 ie_length; /* byte length of Information Elements */
diff --git a/package/kernel/mac80211/patches/344-0005-brcmfmac-Add-length-checks-on-firmware-events.patch b/package/kernel/mac80211/patches/344-0005-brcmfmac-Add-length-checks-on-firmware-events.patch
deleted file mode 100644
index 3e2e3503b6..0000000000
--- a/package/kernel/mac80211/patches/344-0005-brcmfmac-Add-length-checks-on-firmware-events.patch
+++ /dev/null
@@ -1,283 +0,0 @@
-From: Hante Meuleman <meuleman@broadcom.com>
-Date: Wed, 17 Feb 2016 11:26:54 +0100
-Subject: [PATCH] brcmfmac: Add length checks on firmware events
-
-Add additional length checks on firmware events to create more
-robust code.
-
-Reviewed-by: Arend Van Spriel <arend@broadcom.com>
-Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
-Reviewed-by: Lei Zhang <leizh@broadcom.com>
-Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -3092,6 +3092,11 @@ brcmf_notify_sched_scan_results(struct b
-
- brcmf_dbg(SCAN, "Enter\n");
-
-+ if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
-+ brcmf_dbg(SCAN, "Event data to small. Ignore\n");
-+ return 0;
-+ }
-+
- if (e->event_code == BRCMF_E_PFN_NET_LOST) {
- brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
- return 0;
-@@ -3415,6 +3420,11 @@ brcmf_wowl_nd_results(struct brcmf_if *i
-
- brcmf_dbg(SCAN, "Enter\n");
-
-+ if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
-+ brcmf_dbg(SCAN, "Event data to small. Ignore\n");
-+ return 0;
-+ }
-+
- pfn_result = (struct brcmf_pno_scanresults_le *)data;
-
- if (e->event_code == BRCMF_E_PFN_NET_LOST) {
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
-@@ -26,50 +26,6 @@
- #include "fwil.h"
-
- /**
-- * struct brcm_ethhdr - broadcom specific ether header.
-- *
-- * @subtype: subtype for this packet.
-- * @length: TODO: length of appended data.
-- * @version: version indication.
-- * @oui: OUI of this packet.
-- * @usr_subtype: subtype for this OUI.
-- */
--struct brcm_ethhdr {
-- __be16 subtype;
-- __be16 length;
-- u8 version;
-- u8 oui[3];
-- __be16 usr_subtype;
--} __packed;
--
--struct brcmf_event_msg_be {
-- __be16 version;
-- __be16 flags;
-- __be32 event_type;
-- __be32 status;
-- __be32 reason;
-- __be32 auth_type;
-- __be32 datalen;
-- u8 addr[ETH_ALEN];
-- char ifname[IFNAMSIZ];
-- u8 ifidx;
-- u8 bsscfgidx;
--} __packed;
--
--/**
-- * struct brcmf_event - contents of broadcom event packet.
-- *
-- * @eth: standard ether header.
-- * @hdr: broadcom specific ether header.
-- * @msg: common part of the actual event message.
-- */
--struct brcmf_event {
-- struct ethhdr eth;
-- struct brcm_ethhdr hdr;
-- struct brcmf_event_msg_be msg;
--} __packed;
--
--/**
- * struct brcmf_fweh_queue_item - event item on event queue.
- *
- * @q: list element for queuing.
-@@ -85,6 +41,7 @@ struct brcmf_fweh_queue_item {
- u8 ifidx;
- u8 ifaddr[ETH_ALEN];
- struct brcmf_event_msg_be emsg;
-+ u32 datalen;
- u8 data[0];
- };
-
-@@ -294,6 +251,11 @@ static void brcmf_fweh_event_worker(stru
- brcmf_dbg_hex_dump(BRCMF_EVENT_ON(), event->data,
- min_t(u32, emsg.datalen, 64),
- "event payload, len=%d\n", emsg.datalen);
-+ if (emsg.datalen > event->datalen) {
-+ brcmf_err("event invalid length header=%d, msg=%d\n",
-+ event->datalen, emsg.datalen);
-+ goto event_free;
-+ }
-
- /* special handling of interface event */
- if (event->code == BRCMF_E_IF) {
-@@ -439,7 +401,8 @@ int brcmf_fweh_activate_events(struct br
- * dispatch the event to a registered handler (using worker).
- */
- void brcmf_fweh_process_event(struct brcmf_pub *drvr,
-- struct brcmf_event *event_packet)
-+ struct brcmf_event *event_packet,
-+ u32 packet_len)
- {
- enum brcmf_fweh_event_code code;
- struct brcmf_fweh_info *fweh = &drvr->fweh;
-@@ -459,6 +422,9 @@ void brcmf_fweh_process_event(struct brc
- if (code != BRCMF_E_IF && !fweh->evt_handler[code])
- return;
-
-+ if (datalen > BRCMF_DCMD_MAXLEN)
-+ return;
-+
- if (in_interrupt())
- alloc_flag = GFP_ATOMIC;
-
-@@ -472,6 +438,7 @@ void brcmf_fweh_process_event(struct brc
- /* use memcpy to get aligned event message */
- memcpy(&event->emsg, &event_packet->msg, sizeof(event->emsg));
- memcpy(event->data, data, datalen);
-+ event->datalen = datalen;
- memcpy(event->ifaddr, event_packet->eth.h_dest, ETH_ALEN);
-
- brcmf_fweh_queue_event(fweh, event);
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h
-@@ -27,7 +27,6 @@
- struct brcmf_pub;
- struct brcmf_if;
- struct brcmf_cfg80211_info;
--struct brcmf_event;
-
- /* list of firmware events */
- #define BRCMF_FWEH_EVENT_ENUM_DEFLIST \
-@@ -180,13 +179,55 @@ enum brcmf_fweh_event_code {
- /**
- * definitions for event packet validation.
- */
--#define BRCMF_EVENT_OUI_OFFSET 19
--#define BRCM_OUI "\x00\x10\x18"
--#define DOT11_OUI_LEN 3
--#define BCMILCP_BCM_SUBTYPE_EVENT 1
-+#define BRCM_OUI "\x00\x10\x18"
-+#define BCMILCP_BCM_SUBTYPE_EVENT 1
-
-
- /**
-+ * struct brcm_ethhdr - broadcom specific ether header.
-+ *
-+ * @subtype: subtype for this packet.
-+ * @length: TODO: length of appended data.
-+ * @version: version indication.
-+ * @oui: OUI of this packet.
-+ * @usr_subtype: subtype for this OUI.
-+ */
-+struct brcm_ethhdr {
-+ __be16 subtype;
-+ __be16 length;
-+ u8 version;
-+ u8 oui[3];
-+ __be16 usr_subtype;
-+} __packed;
-+
-+struct brcmf_event_msg_be {
-+ __be16 version;
-+ __be16 flags;
-+ __be32 event_type;
-+ __be32 status;
-+ __be32 reason;
-+ __be32 auth_type;
-+ __be32 datalen;
-+ u8 addr[ETH_ALEN];
-+ char ifname[IFNAMSIZ];
-+ u8 ifidx;
-+ u8 bsscfgidx;
-+} __packed;
-+
-+/**
-+ * struct brcmf_event - contents of broadcom event packet.
-+ *
-+ * @eth: standard ether header.
-+ * @hdr: broadcom specific ether header.
-+ * @msg: common part of the actual event message.
-+ */
-+struct brcmf_event {
-+ struct ethhdr eth;
-+ struct brcm_ethhdr hdr;
-+ struct brcmf_event_msg_be msg;
-+} __packed;
-+
-+/**
- * struct brcmf_event_msg - firmware event message.
- *
- * @version: version information.
-@@ -256,34 +297,35 @@ void brcmf_fweh_unregister(struct brcmf_
- enum brcmf_fweh_event_code code);
- int brcmf_fweh_activate_events(struct brcmf_if *ifp);
- void brcmf_fweh_process_event(struct brcmf_pub *drvr,
-- struct brcmf_event *event_packet);
-+ struct brcmf_event *event_packet,
-+ u32 packet_len);
- void brcmf_fweh_p2pdev_setup(struct brcmf_if *ifp, bool ongoing);
-
- static inline void brcmf_fweh_process_skb(struct brcmf_pub *drvr,
- struct sk_buff *skb)
- {
- struct brcmf_event *event_packet;
-- u8 *data;
- u16 usr_stype;
-
- /* only process events when protocol matches */
- if (skb->protocol != cpu_to_be16(ETH_P_LINK_CTL))
- return;
-
-+ if ((skb->len + ETH_HLEN) < sizeof(*event_packet))
-+ return;
-+
- /* check for BRCM oui match */
- event_packet = (struct brcmf_event *)skb_mac_header(skb);
-- data = (u8 *)event_packet;
-- data += BRCMF_EVENT_OUI_OFFSET;
-- if (memcmp(BRCM_OUI, data, DOT11_OUI_LEN))
-+ if (memcmp(BRCM_OUI, &event_packet->hdr.oui[0],
-+ sizeof(event_packet->hdr.oui)))
- return;
-
- /* final match on usr_subtype */
-- data += DOT11_OUI_LEN;
-- usr_stype = get_unaligned_be16(data);
-+ usr_stype = get_unaligned_be16(&event_packet->hdr.usr_subtype);
- if (usr_stype != BCMILCP_BCM_SUBTYPE_EVENT)
- return;
-
-- brcmf_fweh_process_event(drvr, event_packet);
-+ brcmf_fweh_process_event(drvr, event_packet, skb->len + ETH_HLEN);
- }
-
- #endif /* FWEH_H_ */
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
-@@ -1361,6 +1361,11 @@ int brcmf_p2p_notify_action_frame_rx(str
- u16 mgmt_type;
- u8 action;
-
-+ if (e->datalen < sizeof(*rxframe)) {
-+ brcmf_dbg(SCAN, "Event data to small. Ignore\n");
-+ return 0;
-+ }
-+
- ch.chspec = be16_to_cpu(rxframe->chanspec);
- cfg->d11inf.decchspec(&ch);
- /* Check if wpa_supplicant has registered for this frame */
-@@ -1858,6 +1863,11 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probere
- brcmf_dbg(INFO, "Enter: event %d reason %d\n", e->event_code,
- e->reason);
-
-+ if (e->datalen < sizeof(*rxframe)) {
-+ brcmf_dbg(SCAN, "Event data to small. Ignore\n");
-+ return 0;
-+ }
-+
- ch.chspec = be16_to_cpu(rxframe->chanspec);
- cfg->d11inf.decchspec(&ch);
-
diff --git a/package/kernel/mac80211/patches/344-0006-brcmfmac-add-neighbor-discovery-offload-ip-address-t.patch b/package/kernel/mac80211/patches/344-0006-brcmfmac-add-neighbor-discovery-offload-ip-address-t.patch
deleted file mode 100644
index 888ad5b050..0000000000
--- a/package/kernel/mac80211/patches/344-0006-brcmfmac-add-neighbor-discovery-offload-ip-address-t.patch
+++ /dev/null
@@ -1,333 +0,0 @@
-From: Franky Lin <frankyl@broadcom.com>
-Date: Wed, 17 Feb 2016 11:26:55 +0100
-Subject: [PATCH] brcmfmac: add neighbor discovery offload ip address table
- configuration
-
-Configure ipv6 address for neighbor discovery offload ip table in
-firmware obtained through ipv6 address notification callback.
-
-Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
-Signed-off-by: Franky Lin <frankyl@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -456,7 +456,7 @@ send_key_to_dongle(struct brcmf_if *ifp,
- }
-
- static s32
--brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable)
-+brcmf_configure_arp_nd_offload(struct brcmf_if *ifp, bool enable)
- {
- s32 err;
- u32 mode;
-@@ -484,6 +484,15 @@ brcmf_configure_arp_offload(struct brcmf
- enable, mode);
- }
-
-+ err = brcmf_fil_iovar_int_set(ifp, "ndoe", enable);
-+ if (err) {
-+ brcmf_dbg(TRACE, "failed to configure (%d) ND offload err = %d\n",
-+ enable, err);
-+ err = 0;
-+ } else
-+ brcmf_dbg(TRACE, "successfully configured (%d) ND offload to 0x%x\n",
-+ enable, mode);
-+
- return err;
- }
-
-@@ -3543,7 +3552,7 @@ static s32 brcmf_cfg80211_resume(struct
- brcmf_report_wowl_wakeind(wiphy, ifp);
- brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
- brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0);
-- brcmf_configure_arp_offload(ifp, true);
-+ brcmf_configure_arp_nd_offload(ifp, true);
- brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
- cfg->wowl.pre_pmmode);
- cfg->wowl.active = false;
-@@ -3567,7 +3576,7 @@ static void brcmf_configure_wowl(struct
-
- brcmf_dbg(TRACE, "Suspend, wowl config.\n");
-
-- brcmf_configure_arp_offload(ifp, false);
-+ brcmf_configure_arp_nd_offload(ifp, false);
- brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->wowl.pre_pmmode);
- brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX);
-
-@@ -4336,7 +4345,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
-
- if (!mbss) {
- brcmf_set_mpc(ifp, 0);
-- brcmf_configure_arp_offload(ifp, false);
-+ brcmf_configure_arp_nd_offload(ifp, false);
- }
-
- /* find the RSN_IE */
-@@ -4482,7 +4491,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
- exit:
- if ((err) && (!mbss)) {
- brcmf_set_mpc(ifp, 1);
-- brcmf_configure_arp_offload(ifp, true);
-+ brcmf_configure_arp_nd_offload(ifp, true);
- }
- return err;
- }
-@@ -4540,7 +4549,7 @@ static int brcmf_cfg80211_stop_ap(struct
- brcmf_err("bss_enable config failed %d\n", err);
- }
- brcmf_set_mpc(ifp, 1);
-- brcmf_configure_arp_offload(ifp, true);
-+ brcmf_configure_arp_nd_offload(ifp, true);
- clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
- brcmf_net_setcarrier(ifp, false);
-
-@@ -6287,7 +6296,7 @@ static s32 brcmf_config_dongle(struct br
- if (err)
- goto default_conf_out;
-
-- brcmf_configure_arp_offload(ifp, true);
-+ brcmf_configure_arp_nd_offload(ifp, true);
-
- cfg->dongle_up = true;
- default_conf_out:
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
-@@ -20,6 +20,8 @@
- #include <linux/inetdevice.h>
- #include <net/cfg80211.h>
- #include <net/rtnetlink.h>
-+#include <net/addrconf.h>
-+#include <net/ipv6.h>
- #include <brcmu_utils.h>
- #include <brcmu_wifi.h>
-
-@@ -172,6 +174,35 @@ _brcmf_set_mac_address(struct work_struc
- }
- }
-
-+#if IS_ENABLED(CONFIG_IPV6)
-+static void _brcmf_update_ndtable(struct work_struct *work)
-+{
-+ struct brcmf_if *ifp;
-+ int i, ret;
-+
-+ ifp = container_of(work, struct brcmf_if, ndoffload_work);
-+
-+ /* clear the table in firmware */
-+ ret = brcmf_fil_iovar_data_set(ifp, "nd_hostip_clear", NULL, 0);
-+ if (ret) {
-+ brcmf_dbg(TRACE, "fail to clear nd ip table err:%d\n", ret);
-+ return;
-+ }
-+
-+ for (i = 0; i < ifp->ipv6addr_idx; i++) {
-+ ret = brcmf_fil_iovar_data_set(ifp, "nd_hostip",
-+ &ifp->ipv6_addr_tbl[i],
-+ sizeof(struct in6_addr));
-+ if (ret)
-+ brcmf_err("add nd ip err %d\n", ret);
-+ }
-+}
-+#else
-+static void _brcmf_update_ndtable(struct work_struct *work)
-+{
-+}
-+#endif
-+
- static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr)
- {
- struct brcmf_if *ifp = netdev_priv(ndev);
-@@ -685,6 +716,7 @@ int brcmf_net_attach(struct brcmf_if *if
-
- INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address);
- INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list);
-+ INIT_WORK(&ifp->ndoffload_work, _brcmf_update_ndtable);
-
- if (rtnl_locked)
- err = register_netdevice(ndev);
-@@ -884,6 +916,7 @@ static void brcmf_del_if(struct brcmf_pu
- if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
- cancel_work_sync(&ifp->setmacaddr_work);
- cancel_work_sync(&ifp->multicast_work);
-+ cancel_work_sync(&ifp->ndoffload_work);
- }
- brcmf_net_detach(ifp->ndev);
- } else {
-@@ -1025,6 +1058,56 @@ static int brcmf_inetaddr_changed(struct
- }
- #endif
-
-+#if IS_ENABLED(CONFIG_IPV6)
-+static int brcmf_inet6addr_changed(struct notifier_block *nb,
-+ unsigned long action, void *data)
-+{
-+ struct brcmf_pub *drvr = container_of(nb, struct brcmf_pub,
-+ inet6addr_notifier);
-+ struct inet6_ifaddr *ifa = data;
-+ struct brcmf_if *ifp;
-+ int i;
-+ struct in6_addr *table;
-+
-+ /* Only handle primary interface */
-+ ifp = drvr->iflist[0];
-+ if (!ifp)
-+ return NOTIFY_DONE;
-+ if (ifp->ndev != ifa->idev->dev)
-+ return NOTIFY_DONE;
-+
-+ table = ifp->ipv6_addr_tbl;
-+ for (i = 0; i < NDOL_MAX_ENTRIES; i++)
-+ if (ipv6_addr_equal(&ifa->addr, &table[i]))
-+ break;
-+
-+ switch (action) {
-+ case NETDEV_UP:
-+ if (i == NDOL_MAX_ENTRIES) {
-+ if (ifp->ipv6addr_idx < NDOL_MAX_ENTRIES) {
-+ table[ifp->ipv6addr_idx++] = ifa->addr;
-+ } else {
-+ for (i = 0; i < NDOL_MAX_ENTRIES - 1; i++)
-+ table[i] = table[i + 1];
-+ table[NDOL_MAX_ENTRIES - 1] = ifa->addr;
-+ }
-+ }
-+ break;
-+ case NETDEV_DOWN:
-+ if (i < NDOL_MAX_ENTRIES)
-+ for (; i < ifp->ipv6addr_idx; i++)
-+ table[i] = table[i + 1];
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ schedule_work(&ifp->ndoffload_work);
-+
-+ return NOTIFY_OK;
-+}
-+#endif
-+
- int brcmf_attach(struct device *dev)
- {
- struct brcmf_pub *drvr = NULL;
-@@ -1164,30 +1247,41 @@ int brcmf_bus_start(struct device *dev)
- #ifdef CONFIG_INET
- drvr->inetaddr_notifier.notifier_call = brcmf_inetaddr_changed;
- ret = register_inetaddr_notifier(&drvr->inetaddr_notifier);
-+ if (ret)
-+ goto fail;
-+
-+#if IS_ENABLED(CONFIG_IPV6)
-+ drvr->inet6addr_notifier.notifier_call = brcmf_inet6addr_changed;
-+ ret = register_inet6addr_notifier(&drvr->inet6addr_notifier);
-+ if (ret) {
-+ unregister_inetaddr_notifier(&drvr->inetaddr_notifier);
-+ goto fail;
-+ }
- #endif
-+#endif /* CONFIG_INET */
-+
-+ return 0;
-
- fail:
-- if (ret < 0) {
-- brcmf_err("failed: %d\n", ret);
-- if (drvr->config) {
-- brcmf_cfg80211_detach(drvr->config);
-- drvr->config = NULL;
-- }
-- if (drvr->fws) {
-- brcmf_fws_del_interface(ifp);
-- brcmf_fws_deinit(drvr);
-- }
-- if (ifp)
-- brcmf_net_detach(ifp->ndev);
-- if (p2p_ifp)
-- brcmf_net_detach(p2p_ifp->ndev);
-- drvr->iflist[0] = NULL;
-- drvr->iflist[1] = NULL;
-- if (brcmf_ignoring_probe_fail(drvr))
-- ret = 0;
-- return ret;
-+ brcmf_err("failed: %d\n", ret);
-+ if (drvr->config) {
-+ brcmf_cfg80211_detach(drvr->config);
-+ drvr->config = NULL;
-+ }
-+ if (drvr->fws) {
-+ brcmf_fws_del_interface(ifp);
-+ brcmf_fws_deinit(drvr);
- }
-- return 0;
-+ if (ifp)
-+ brcmf_net_detach(ifp->ndev);
-+ if (p2p_ifp)
-+ brcmf_net_detach(p2p_ifp->ndev);
-+ drvr->iflist[0] = NULL;
-+ drvr->iflist[1] = NULL;
-+ if (brcmf_ignoring_probe_fail(drvr))
-+ ret = 0;
-+
-+ return ret;
- }
-
- void brcmf_bus_add_txhdrlen(struct device *dev, uint len)
-@@ -1237,6 +1331,10 @@ void brcmf_detach(struct device *dev)
- unregister_inetaddr_notifier(&drvr->inetaddr_notifier);
- #endif
-
-+#if IS_ENABLED(CONFIG_IPV6)
-+ unregister_inet6addr_notifier(&drvr->inet6addr_notifier);
-+#endif
-+
- /* stop firmware event handling */
- brcmf_fweh_detach(drvr);
- if (drvr->config)
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
-@@ -48,6 +48,8 @@
- */
- #define BRCMF_DRIVER_FIRMWARE_VERSION_LEN 32
-
-+#define NDOL_MAX_ENTRIES 8
-+
- /**
- * struct brcmf_ampdu_rx_reorder - AMPDU receive reorder info
- *
-@@ -143,6 +145,7 @@ struct brcmf_pub {
- #endif
-
- struct notifier_block inetaddr_notifier;
-+ struct notifier_block inet6addr_notifier;
- struct brcmf_mp_device *settings;
- };
-
-@@ -175,6 +178,7 @@ enum brcmf_netif_stop_reason {
- * @stats: interface specific network statistics.
- * @setmacaddr_work: worker object for setting mac address.
- * @multicast_work: worker object for multicast provisioning.
-+ * @ndoffload_work: worker object for neighbor discovery offload configuration.
- * @fws_desc: interface specific firmware-signalling descriptor.
- * @ifidx: interface index in device firmware.
- * @bsscfgidx: index of bss associated with this interface.
-@@ -191,6 +195,7 @@ struct brcmf_if {
- struct net_device_stats stats;
- struct work_struct setmacaddr_work;
- struct work_struct multicast_work;
-+ struct work_struct ndoffload_work;
- struct brcmf_fws_mac_descriptor *fws_desc;
- int ifidx;
- s32 bsscfgidx;
-@@ -199,6 +204,8 @@ struct brcmf_if {
- spinlock_t netif_stop_lock;
- atomic_t pend_8021x_cnt;
- wait_queue_head_t pend_8021x_wait;
-+ struct in6_addr ipv6_addr_tbl[NDOL_MAX_ENTRIES];
-+ u8 ipv6addr_idx;
- };
-
- struct brcmf_skb_reorder_data {
diff --git a/package/kernel/mac80211/patches/344-0007-brcmfmac-check-return-for-ARP-ip-setting-iovar.patch b/package/kernel/mac80211/patches/344-0007-brcmfmac-check-return-for-ARP-ip-setting-iovar.patch
deleted file mode 100644
index 68de8ed2a2..0000000000
--- a/package/kernel/mac80211/patches/344-0007-brcmfmac-check-return-for-ARP-ip-setting-iovar.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-From: Franky Lin <frankyl@broadcom.com>
-Date: Wed, 17 Feb 2016 11:26:56 +0100
-Subject: [PATCH] brcmfmac: check return for ARP ip setting iovar
-
-The return value of iovar set function should be saved and checked.
-
-Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
-Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
-Signed-off-by: Franky Lin <frankyl@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
-@@ -1039,14 +1039,14 @@ static int brcmf_inetaddr_changed(struct
- return NOTIFY_OK;
- }
- for (i = 0; i < ARPOL_MAX_ENTRIES; i++) {
-- if (addr_table[i] != 0) {
-- brcmf_fil_iovar_data_set(ifp,
-- "arp_hostip", &addr_table[i],
-- sizeof(addr_table[i]));
-- if (ret)
-- brcmf_err("add arp ip err %d\n",
-- ret);
-- }
-+ if (addr_table[i] == 0)
-+ continue;
-+ ret = brcmf_fil_iovar_data_set(ifp, "arp_hostip",
-+ &addr_table[i],
-+ sizeof(addr_table[i]));
-+ if (ret)
-+ brcmf_err("add arp ip err %d\n",
-+ ret);
- }
- }
- break;
diff --git a/package/kernel/mac80211/patches/344-0008-brcmfmac-use-device-memsize-config-from-fw-if-define.patch b/package/kernel/mac80211/patches/344-0008-brcmfmac-use-device-memsize-config-from-fw-if-define.patch
deleted file mode 100644
index 3de0f64d56..0000000000
--- a/package/kernel/mac80211/patches/344-0008-brcmfmac-use-device-memsize-config-from-fw-if-define.patch
+++ /dev/null
@@ -1,73 +0,0 @@
-From: Hante Meuleman <meuleman@broadcom.com>
-Date: Wed, 17 Feb 2016 11:26:57 +0100
-Subject: [PATCH] brcmfmac: use device memsize config from fw if defined
-
-Newer type pcie devices have memory which get shared between fw and
-hw. The division of this memory is done firmware compile time. As a
-result the ramsize as used by driver needs to be adjusted for this.
-This is done by reading the memory size from the firmware.
-
-Reviewed-by: Arend Van Spriel <arend@broadcom.com>
-Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
-Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
-@@ -207,6 +207,10 @@ static struct brcmf_firmware_mapping brc
- #define BRCMF_PCIE_CFGREG_REG_BAR3_CONFIG 0x4F4
- #define BRCMF_PCIE_LINK_STATUS_CTRL_ASPM_ENAB 3
-
-+/* Magic number at a magic location to find RAM size */
-+#define BRCMF_RAMSIZE_MAGIC 0x534d4152 /* SMAR */
-+#define BRCMF_RAMSIZE_OFFSET 0x6c
-+
-
- struct brcmf_pcie_console {
- u32 base_addr;
-@@ -1412,6 +1416,28 @@ static const struct brcmf_bus_ops brcmf_
- };
-
-
-+static void
-+brcmf_pcie_adjust_ramsize(struct brcmf_pciedev_info *devinfo, u8 *data,
-+ u32 data_len)
-+{
-+ __le32 *field;
-+ u32 newsize;
-+
-+ if (data_len < BRCMF_RAMSIZE_OFFSET + 8)
-+ return;
-+
-+ field = (__le32 *)&data[BRCMF_RAMSIZE_OFFSET];
-+ if (le32_to_cpup(field) != BRCMF_RAMSIZE_MAGIC)
-+ return;
-+ field++;
-+ newsize = le32_to_cpup(field);
-+
-+ brcmf_dbg(PCIE, "Found ramsize info in FW, adjusting to 0x%x\n",
-+ newsize);
-+ devinfo->ci->ramsize = newsize;
-+}
-+
-+
- static int
- brcmf_pcie_init_share_ram_info(struct brcmf_pciedev_info *devinfo,
- u32 sharedram_addr)
-@@ -1694,6 +1720,13 @@ static void brcmf_pcie_setup(struct devi
-
- brcmf_pcie_attach(devinfo);
-
-+ /* Some of the firmwares have the size of the memory of the device
-+ * defined inside the firmware. This is because part of the memory in
-+ * the device is shared and the devision is determined by FW. Parse
-+ * the firmware and adjust the chip memory size now.
-+ */
-+ brcmf_pcie_adjust_ramsize(devinfo, (u8 *)fw->data, fw->size);
-+
- ret = brcmf_pcie_download_fw_nvram(devinfo, fw, nvram, nvram_len);
- if (ret)
- goto fail;
diff --git a/package/kernel/mac80211/patches/344-0009-brcmfmac-use-bar1-window-size-as-provided-by-pci-sub.patch b/package/kernel/mac80211/patches/344-0009-brcmfmac-use-bar1-window-size-as-provided-by-pci-sub.patch
deleted file mode 100644
index ca03ffe4b0..0000000000
--- a/package/kernel/mac80211/patches/344-0009-brcmfmac-use-bar1-window-size-as-provided-by-pci-sub.patch
+++ /dev/null
@@ -1,58 +0,0 @@
-From: Hante Meuleman <meuleman@broadcom.com>
-Date: Wed, 17 Feb 2016 11:26:58 +0100
-Subject: [PATCH] brcmfmac: use bar1 window size as provided by pci subsystem
-
-The PCIE bar1 window size is specified by chip. Currently the
-ioremap of bar1 was using a define which always matched the size
-of bar1, but newer chips can have a different bar1 sizes. With
-this patch the ioremap will be called with the by chip provided
-window size.
-
-Reviewed-by: Arend Van Spriel <arend@broadcom.com>
-Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
-Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
-@@ -72,7 +72,6 @@ static struct brcmf_firmware_mapping brc
-
- #define BRCMF_PCIE_FW_UP_TIMEOUT 2000 /* msec */
-
--#define BRCMF_PCIE_TCM_MAP_SIZE (4096 * 1024)
- #define BRCMF_PCIE_REG_MAP_SIZE (32 * 1024)
-
- /* backplane addres space accessed by BAR0 */
-@@ -252,7 +251,6 @@ struct brcmf_pciedev_info {
- char nvram_name[BRCMF_FW_NAME_LEN];
- void __iomem *regs;
- void __iomem *tcm;
-- u32 tcm_size;
- u32 ram_base;
- u32 ram_size;
- struct brcmf_chip *ci;
-@@ -1592,8 +1590,7 @@ static int brcmf_pcie_get_resource(struc
- }
-
- devinfo->regs = ioremap_nocache(bar0_addr, BRCMF_PCIE_REG_MAP_SIZE);
-- devinfo->tcm = ioremap_nocache(bar1_addr, BRCMF_PCIE_TCM_MAP_SIZE);
-- devinfo->tcm_size = BRCMF_PCIE_TCM_MAP_SIZE;
-+ devinfo->tcm = ioremap_nocache(bar1_addr, bar1_size);
-
- if (!devinfo->regs || !devinfo->tcm) {
- brcmf_err("ioremap() failed (%p,%p)\n", devinfo->regs,
-@@ -1602,8 +1599,9 @@ static int brcmf_pcie_get_resource(struc
- }
- brcmf_dbg(PCIE, "Phys addr : reg space = %p base addr %#016llx\n",
- devinfo->regs, (unsigned long long)bar0_addr);
-- brcmf_dbg(PCIE, "Phys addr : mem space = %p base addr %#016llx\n",
-- devinfo->tcm, (unsigned long long)bar1_addr);
-+ brcmf_dbg(PCIE, "Phys addr : mem space = %p base addr %#016llx size 0x%x\n",
-+ devinfo->tcm, (unsigned long long)bar1_addr,
-+ (unsigned int)bar1_size);
-
- return 0;
- }
diff --git a/package/kernel/mac80211/patches/344-0010-brcmfmac-add-support-for-the-PCIE-4366c0-chip.patch b/package/kernel/mac80211/patches/344-0010-brcmfmac-add-support-for-the-PCIE-4366c0-chip.patch
deleted file mode 100644
index e4a8f305cf..0000000000
--- a/package/kernel/mac80211/patches/344-0010-brcmfmac-add-support-for-the-PCIE-4366c0-chip.patch
+++ /dev/null
@@ -1,34 +0,0 @@
-From: Hante Meuleman <meuleman@broadcom.com>
-Date: Wed, 17 Feb 2016 11:26:59 +0100
-Subject: [PATCH] brcmfmac: add support for the PCIE 4366c0 chip
-
-A newer version of the 4366 PCIE chip has been released. Add
-support for this version of the chip.
-
-Reviewed-by: Arend Van Spriel <arend@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
-Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
-@@ -53,6 +53,7 @@ BRCMF_FW_NVRAM_DEF(4358, "brcmfmac4358-p
- BRCMF_FW_NVRAM_DEF(4359, "brcmfmac4359-pcie.bin", "brcmfmac4359-pcie.txt");
- BRCMF_FW_NVRAM_DEF(4365B, "brcmfmac4365b-pcie.bin", "brcmfmac4365b-pcie.txt");
- BRCMF_FW_NVRAM_DEF(4366B, "brcmfmac4366b-pcie.bin", "brcmfmac4366b-pcie.txt");
-+BRCMF_FW_NVRAM_DEF(4366C, "brcmfmac4366c-pcie.bin", "brcmfmac4366c-pcie.txt");
- BRCMF_FW_NVRAM_DEF(4371, "brcmfmac4371-pcie.bin", "brcmfmac4371-pcie.txt");
-
- static struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
-@@ -66,7 +67,8 @@ static struct brcmf_firmware_mapping brc
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4358_CHIP_ID, 0xFFFFFFFF, 4358),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4359_CHIP_ID, 0xFFFFFFFF, 4359),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4365_CHIP_ID, 0xFFFFFFFF, 4365B),
-- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4366_CHIP_ID, 0xFFFFFFFF, 4366B),
-+ BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4366_CHIP_ID, 0x0000000F, 4366B),
-+ BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4366_CHIP_ID, 0xFFFFFFF0, 4366C),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4371_CHIP_ID, 0xFFFFFFFF, 4371),
- };
-
diff --git a/package/kernel/mac80211/patches/344-0011-brcmfmac-remove-pcie-gen1-support.patch b/package/kernel/mac80211/patches/344-0011-brcmfmac-remove-pcie-gen1-support.patch
deleted file mode 100644
index f99f6dbf07..0000000000
--- a/package/kernel/mac80211/patches/344-0011-brcmfmac-remove-pcie-gen1-support.patch
+++ /dev/null
@@ -1,221 +0,0 @@
-From: Hante Meuleman <meuleman@broadcom.com>
-Date: Wed, 17 Feb 2016 11:27:00 +0100
-Subject: [PATCH] brcmfmac: remove pcie gen1 support
-
-The PCIE bus driver supports older gen1 (v1) chips, but there is no
-actual device which is using this older pcie core which is supported
-by brcmfmac. Remove all gen1 related code.
-
-Reviewed-by: Arend Van Spriel <arend@broadcom.com>
-Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
-Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
-@@ -100,9 +100,6 @@ static struct brcmf_firmware_mapping brc
- #define BRCMF_PCIE_PCIE2REG_CONFIGDATA 0x124
- #define BRCMF_PCIE_PCIE2REG_H2D_MAILBOX 0x140
-
--#define BRCMF_PCIE_GENREV1 1
--#define BRCMF_PCIE_GENREV2 2
--
- #define BRCMF_PCIE2_INTA 0x01
- #define BRCMF_PCIE2_INTB 0x02
-
-@@ -257,9 +254,7 @@ struct brcmf_pciedev_info {
- u32 ram_size;
- struct brcmf_chip *ci;
- u32 coreid;
-- u32 generic_corerev;
- struct brcmf_pcie_shared_info shared;
-- void (*ringbell)(struct brcmf_pciedev_info *devinfo);
- wait_queue_head_t mbdata_resp_wait;
- bool mbdata_completed;
- bool irq_allocated;
-@@ -746,68 +741,22 @@ static void brcmf_pcie_bus_console_read(
- }
-
-
--static __used void brcmf_pcie_ringbell_v1(struct brcmf_pciedev_info *devinfo)
--{
-- u32 reg_value;
--
-- brcmf_dbg(PCIE, "RING !\n");
-- reg_value = brcmf_pcie_read_reg32(devinfo,
-- BRCMF_PCIE_PCIE2REG_MAILBOXINT);
-- reg_value |= BRCMF_PCIE2_INTB;
-- brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT,
-- reg_value);
--}
--
--
--static void brcmf_pcie_ringbell_v2(struct brcmf_pciedev_info *devinfo)
--{
-- brcmf_dbg(PCIE, "RING !\n");
-- /* Any arbitrary value will do, lets use 1 */
-- brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_H2D_MAILBOX, 1);
--}
--
--
- static void brcmf_pcie_intr_disable(struct brcmf_pciedev_info *devinfo)
- {
-- if (devinfo->generic_corerev == BRCMF_PCIE_GENREV1)
-- pci_write_config_dword(devinfo->pdev, BRCMF_PCIE_REG_INTMASK,
-- 0);
-- else
-- brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK,
-- 0);
-+ brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK, 0);
- }
-
-
- static void brcmf_pcie_intr_enable(struct brcmf_pciedev_info *devinfo)
- {
-- if (devinfo->generic_corerev == BRCMF_PCIE_GENREV1)
-- pci_write_config_dword(devinfo->pdev, BRCMF_PCIE_REG_INTMASK,
-- BRCMF_PCIE_INT_DEF);
-- else
-- brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK,
-- BRCMF_PCIE_MB_INT_D2H_DB |
-- BRCMF_PCIE_MB_INT_FN0_0 |
-- BRCMF_PCIE_MB_INT_FN0_1);
-+ brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK,
-+ BRCMF_PCIE_MB_INT_D2H_DB |
-+ BRCMF_PCIE_MB_INT_FN0_0 |
-+ BRCMF_PCIE_MB_INT_FN0_1);
- }
-
-
--static irqreturn_t brcmf_pcie_quick_check_isr_v1(int irq, void *arg)
--{
-- struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)arg;
-- u32 status;
--
-- status = 0;
-- pci_read_config_dword(devinfo->pdev, BRCMF_PCIE_REG_INTSTATUS, &status);
-- if (status) {
-- brcmf_pcie_intr_disable(devinfo);
-- brcmf_dbg(PCIE, "Enter\n");
-- return IRQ_WAKE_THREAD;
-- }
-- return IRQ_NONE;
--}
--
--
--static irqreturn_t brcmf_pcie_quick_check_isr_v2(int irq, void *arg)
-+static irqreturn_t brcmf_pcie_quick_check_isr(int irq, void *arg)
- {
- struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)arg;
-
-@@ -820,29 +769,7 @@ static irqreturn_t brcmf_pcie_quick_chec
- }
-
-
--static irqreturn_t brcmf_pcie_isr_thread_v1(int irq, void *arg)
--{
-- struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)arg;
-- const struct pci_dev *pdev = devinfo->pdev;
-- u32 status;
--
-- devinfo->in_irq = true;
-- status = 0;
-- pci_read_config_dword(pdev, BRCMF_PCIE_REG_INTSTATUS, &status);
-- brcmf_dbg(PCIE, "Enter %x\n", status);
-- if (status) {
-- pci_write_config_dword(pdev, BRCMF_PCIE_REG_INTSTATUS, status);
-- if (devinfo->state == BRCMFMAC_PCIE_STATE_UP)
-- brcmf_proto_msgbuf_rx_trigger(&devinfo->pdev->dev);
-- }
-- if (devinfo->state == BRCMFMAC_PCIE_STATE_UP)
-- brcmf_pcie_intr_enable(devinfo);
-- devinfo->in_irq = false;
-- return IRQ_HANDLED;
--}
--
--
--static irqreturn_t brcmf_pcie_isr_thread_v2(int irq, void *arg)
-+static irqreturn_t brcmf_pcie_isr_thread(int irq, void *arg)
- {
- struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)arg;
- u32 status;
-@@ -879,28 +806,14 @@ static int brcmf_pcie_request_irq(struct
- brcmf_pcie_intr_disable(devinfo);
-
- brcmf_dbg(PCIE, "Enter\n");
-- /* is it a v1 or v2 implementation */
-+
- pci_enable_msi(pdev);
-- if (devinfo->generic_corerev == BRCMF_PCIE_GENREV1) {
-- if (request_threaded_irq(pdev->irq,
-- brcmf_pcie_quick_check_isr_v1,
-- brcmf_pcie_isr_thread_v1,
-- IRQF_SHARED, "brcmf_pcie_intr",
-- devinfo)) {
-- pci_disable_msi(pdev);
-- brcmf_err("Failed to request IRQ %d\n", pdev->irq);
-- return -EIO;
-- }
-- } else {
-- if (request_threaded_irq(pdev->irq,
-- brcmf_pcie_quick_check_isr_v2,
-- brcmf_pcie_isr_thread_v2,
-- IRQF_SHARED, "brcmf_pcie_intr",
-- devinfo)) {
-- pci_disable_msi(pdev);
-- brcmf_err("Failed to request IRQ %d\n", pdev->irq);
-- return -EIO;
-- }
-+ if (request_threaded_irq(pdev->irq, brcmf_pcie_quick_check_isr,
-+ brcmf_pcie_isr_thread, IRQF_SHARED,
-+ "brcmf_pcie_intr", devinfo)) {
-+ pci_disable_msi(pdev);
-+ brcmf_err("Failed to request IRQ %d\n", pdev->irq);
-+ return -EIO;
- }
- devinfo->irq_allocated = true;
- return 0;
-@@ -931,16 +844,9 @@ static void brcmf_pcie_release_irq(struc
- if (devinfo->in_irq)
- brcmf_err("Still in IRQ (processing) !!!\n");
-
-- if (devinfo->generic_corerev == BRCMF_PCIE_GENREV1) {
-- status = 0;
-- pci_read_config_dword(pdev, BRCMF_PCIE_REG_INTSTATUS, &status);
-- pci_write_config_dword(pdev, BRCMF_PCIE_REG_INTSTATUS, status);
-- } else {
-- status = brcmf_pcie_read_reg32(devinfo,
-- BRCMF_PCIE_PCIE2REG_MAILBOXINT);
-- brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT,
-- status);
-- }
-+ status = brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT);
-+ brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT, status);
-+
- devinfo->irq_allocated = false;
- }
-
-@@ -989,7 +895,9 @@ static int brcmf_pcie_ring_mb_ring_bell(
- if (devinfo->state != BRCMFMAC_PCIE_STATE_UP)
- return -EIO;
-
-- devinfo->ringbell(devinfo);
-+ brcmf_dbg(PCIE, "RING !\n");
-+ /* Any arbitrary value will do, lets use 1 */
-+ brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_H2D_MAILBOX, 1);
-
- return 0;
- }
-@@ -1503,9 +1411,6 @@ static int brcmf_pcie_download_fw_nvram(
- u32 address;
- u32 resetintr;
-
-- devinfo->ringbell = brcmf_pcie_ringbell_v2;
-- devinfo->generic_corerev = BRCMF_PCIE_GENREV2;
--
- brcmf_dbg(PCIE, "Halt ARM.\n");
- err = brcmf_pcie_enter_download_state(devinfo);
- if (err)
diff --git a/package/kernel/mac80211/patches/344-0012-brcmfmac-increase-timeout-for-tx-eapol.patch b/package/kernel/mac80211/patches/344-0012-brcmfmac-increase-timeout-for-tx-eapol.patch
deleted file mode 100644
index 4adfc2dc64..0000000000
--- a/package/kernel/mac80211/patches/344-0012-brcmfmac-increase-timeout-for-tx-eapol.patch
+++ /dev/null
@@ -1,30 +0,0 @@
-From: Hante Meuleman <meuleman@broadcom.com>
-Date: Wed, 17 Feb 2016 11:27:01 +0100
-Subject: [PATCH] brcmfmac: increase timeout for tx eapol
-
-When keys get set and updated this has to happen after eapol got
-transmitted (without key or old key) before the key can be updated.
-To make sure the order of sending eapol and configuring key is done
-correctly a timeout for tx of eapol is applied. This timeout is set
-to 50 msec, which is not always enough. Especially in AP mode and
-key updates the timeout may need to be much longer because client(s)
-can be in powersave. Increase the timeout from 50 to 950 msec.
-
-Reviewed-by: Arend Van Spriel <arend@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
-Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
-@@ -42,7 +42,7 @@ MODULE_AUTHOR("Broadcom Corporation");
- MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver.");
- MODULE_LICENSE("Dual BSD/GPL");
-
--#define MAX_WAIT_FOR_8021X_TX msecs_to_jiffies(50)
-+#define MAX_WAIT_FOR_8021X_TX msecs_to_jiffies(950)
-
- /* AMPDU rx reordering definitions */
- #define BRCMF_RXREORDER_FLOWID_OFFSET 0
diff --git a/package/kernel/mac80211/patches/344-0013-brcmfmac-move-module-init-and-exit-to-common.patch b/package/kernel/mac80211/patches/344-0013-brcmfmac-move-module-init-and-exit-to-common.patch
deleted file mode 100644
index bd62781188..0000000000
--- a/package/kernel/mac80211/patches/344-0013-brcmfmac-move-module-init-and-exit-to-common.patch
+++ /dev/null
@@ -1,135 +0,0 @@
-From: Hante Meuleman <meuleman@broadcom.com>
-Date: Wed, 17 Feb 2016 11:27:02 +0100
-Subject: [PATCH] brcmfmac: move module init and exit to common
-
-In preparation of module parameters for all devices the module init
-and exit routines are moved to the common file.
-
-Reviewed-by: Arend Van Spriel <arend@broadcom.com>
-Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
-Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
-@@ -28,6 +28,10 @@
- #include "tracepoint.h"
- #include "common.h"
-
-+MODULE_AUTHOR("Broadcom Corporation");
-+MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver.");
-+MODULE_LICENSE("Dual BSD/GPL");
-+
- const u8 ALLFFMAC[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-
- #define BRCMF_DEFAULT_SCAN_CHANNEL_TIME 40
-@@ -221,7 +225,7 @@ void __brcmf_dbg(u32 level, const char *
- }
- #endif
-
--void brcmf_mp_attach(void)
-+static void brcmf_mp_attach(void)
- {
- strlcpy(brcmf_mp_global.firmware_path, brcmf_firmware_path,
- BRCMF_FW_ALTPATH_LEN);
-@@ -249,3 +253,33 @@ void brcmf_mp_device_detach(struct brcmf
- kfree(drvr->settings);
- }
-
-+static int __init brcmfmac_module_init(void)
-+{
-+ int err;
-+
-+ /* Initialize debug system first */
-+ brcmf_debugfs_init();
-+
-+#ifdef CPTCFG_BRCMFMAC_SDIO
-+ brcmf_sdio_init();
-+#endif
-+ /* Initialize global module paramaters */
-+ brcmf_mp_attach();
-+
-+ /* Continue the initialization by registering the different busses */
-+ err = brcmf_core_init();
-+ if (err)
-+ brcmf_debugfs_exit();
-+
-+ return err;
-+}
-+
-+static void __exit brcmfmac_module_exit(void)
-+{
-+ brcmf_core_exit();
-+ brcmf_debugfs_exit();
-+}
-+
-+module_init(brcmfmac_module_init);
-+module_exit(brcmfmac_module_exit);
-+
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
-@@ -89,7 +89,6 @@ struct brcmf_mp_device {
- struct cc_translate *country_codes;
- };
-
--void brcmf_mp_attach(void);
- int brcmf_mp_device_attach(struct brcmf_pub *drvr);
- void brcmf_mp_device_detach(struct brcmf_pub *drvr);
- #ifdef DEBUG
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
-@@ -38,10 +38,6 @@
- #include "pcie.h"
- #include "common.h"
-
--MODULE_AUTHOR("Broadcom Corporation");
--MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver.");
--MODULE_LICENSE("Dual BSD/GPL");
--
- #define MAX_WAIT_FOR_8021X_TX msecs_to_jiffies(950)
-
- /* AMPDU rx reordering definitions */
-@@ -1422,19 +1418,15 @@ static void brcmf_driver_register(struct
- }
- static DECLARE_WORK(brcmf_driver_work, brcmf_driver_register);
-
--static int __init brcmfmac_module_init(void)
-+int __init brcmf_core_init(void)
- {
-- brcmf_debugfs_init();
--#ifdef CPTCFG_BRCMFMAC_SDIO
-- brcmf_sdio_init();
--#endif
- if (!schedule_work(&brcmf_driver_work))
- return -EBUSY;
-
- return 0;
- }
-
--static void __exit brcmfmac_module_exit(void)
-+void __exit brcmf_core_exit(void)
- {
- cancel_work_sync(&brcmf_driver_work);
-
-@@ -1447,8 +1439,5 @@ static void __exit brcmfmac_module_exit(
- #ifdef CPTCFG_BRCMFMAC_PCIE
- brcmf_pcie_exit();
- #endif
-- brcmf_debugfs_exit();
- }
-
--module_init(brcmfmac_module_init);
--module_exit(brcmfmac_module_exit);
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
-@@ -227,5 +227,7 @@ void brcmf_txflowblock_if(struct brcmf_i
- void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success);
- void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb);
- void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on);
-+int __init brcmf_core_init(void);
-+void __exit brcmf_core_exit(void);
-
- #endif /* BRCMFMAC_CORE_H */
diff --git a/package/kernel/mac80211/patches/344-0014-brcmfmac-add-wowl-gtk-rekeying-offload-support.patch b/package/kernel/mac80211/patches/344-0014-brcmfmac-add-wowl-gtk-rekeying-offload-support.patch
deleted file mode 100644
index 577ca8ed28..0000000000
--- a/package/kernel/mac80211/patches/344-0014-brcmfmac-add-wowl-gtk-rekeying-offload-support.patch
+++ /dev/null
@@ -1,260 +0,0 @@
-From: Hante Meuleman <meuleman@broadcom.com>
-Date: Wed, 17 Feb 2016 11:27:03 +0100
-Subject: [PATCH] brcmfmac: add wowl gtk rekeying offload support
-
-This patch adds support for gtk rekeying offload and for gtk
-rekeying failure during wowl mode.
-
-Reviewed-by: Arend Van Spriel <arend@broadcom.com>
-Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
-Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -3526,6 +3526,10 @@ static void brcmf_report_wowl_wakeind(st
- else
- wakeup_data.net_detect = cfg->wowl.nd_info;
- }
-+ if (wakeind & BRCMF_WOWL_GTK_FAILURE) {
-+ brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_GTK_FAILURE\n");
-+ wakeup_data.gtk_rekey_failure = true;
-+ }
- } else {
- wakeup = NULL;
- }
-@@ -3607,6 +3611,8 @@ static void brcmf_configure_wowl(struct
- brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
- brcmf_wowl_nd_results);
- }
-+ if (wowl->gtk_rekey_failure)
-+ wowl_config |= BRCMF_WOWL_GTK_FAILURE;
- if (!test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
- wowl_config |= BRCMF_WOWL_UNASSOC;
-
-@@ -4874,7 +4880,32 @@ static int brcmf_cfg80211_tdls_oper(stru
- return ret;
- }
-
--static struct cfg80211_ops wl_cfg80211_ops = {
-+#ifdef CONFIG_PM
-+static int
-+brcmf_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *ndev,
-+ struct cfg80211_gtk_rekey_data *gtk)
-+{
-+ struct brcmf_if *ifp = netdev_priv(ndev);
-+ struct brcmf_gtk_keyinfo_le gtk_le;
-+ int ret;
-+
-+ brcmf_dbg(TRACE, "Enter, bssidx=%d\n", ifp->bsscfgidx);
-+
-+ memcpy(gtk_le.kck, gtk->kck, sizeof(gtk_le.kck));
-+ memcpy(gtk_le.kek, gtk->kek, sizeof(gtk_le.kek));
-+ memcpy(gtk_le.replay_counter, gtk->replay_ctr,
-+ sizeof(gtk_le.replay_counter));
-+
-+ ret = brcmf_fil_iovar_data_set(ifp, "gtk_key_info", &gtk_le,
-+ sizeof(gtk_le));
-+ if (ret < 0)
-+ brcmf_err("gtk_key_info iovar failed: ret=%d\n", ret);
-+
-+ return ret;
-+}
-+#endif
-+
-+static struct cfg80211_ops brcmf_cfg80211_ops = {
- .add_virtual_intf = brcmf_cfg80211_add_iface,
- .del_virtual_intf = brcmf_cfg80211_del_iface,
- .change_virtual_intf = brcmf_cfg80211_change_iface,
-@@ -6139,19 +6170,18 @@ static void brcmf_wiphy_wowl_params(stru
- {
- #ifdef CONFIG_PM
- struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
-- s32 err;
-- u32 wowl_cap;
-
- if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) {
-- err = brcmf_fil_iovar_int_get(ifp, "wowl_cap", &wowl_cap);
-- if (!err) {
-- if (wowl_cap & BRCMF_WOWL_PFN_FOUND) {
-- brcmf_wowlan_support.flags |=
-- WIPHY_WOWLAN_NET_DETECT;
-- init_waitqueue_head(&cfg->wowl.nd_data_wait);
-- }
-+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ND)) {
-+ brcmf_wowlan_support.flags |= WIPHY_WOWLAN_NET_DETECT;
-+ init_waitqueue_head(&cfg->wowl.nd_data_wait);
- }
- }
-+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK)) {
-+ brcmf_wowlan_support.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY;
-+ brcmf_wowlan_support.flags |= WIPHY_WOWLAN_GTK_REKEY_FAILURE;
-+ }
-+
- wiphy->wowlan = &brcmf_wowlan_support;
- #endif
- }
-@@ -6538,6 +6568,7 @@ struct brcmf_cfg80211_info *brcmf_cfg802
- struct net_device *ndev = brcmf_get_ifp(drvr, 0)->ndev;
- struct brcmf_cfg80211_info *cfg;
- struct wiphy *wiphy;
-+ struct cfg80211_ops *ops;
- struct brcmf_cfg80211_vif *vif;
- struct brcmf_if *ifp;
- s32 err = 0;
-@@ -6549,8 +6580,17 @@ struct brcmf_cfg80211_info *brcmf_cfg802
- return NULL;
- }
-
-+ ops = kzalloc(sizeof(*ops), GFP_KERNEL);
-+ if (!ops)
-+ return NULL;
-+
-+ memcpy(ops, &brcmf_cfg80211_ops, sizeof(*ops));
- ifp = netdev_priv(ndev);
-- wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
-+#ifdef CONFIG_PM
-+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK))
-+ ops->set_rekey_data = brcmf_cfg80211_set_rekey_data;
-+#endif
-+ wiphy = wiphy_new(ops, sizeof(struct brcmf_cfg80211_info));
- if (!wiphy) {
- brcmf_err("Could not allocate wiphy device\n");
- return NULL;
-@@ -6560,6 +6600,7 @@ struct brcmf_cfg80211_info *brcmf_cfg802
-
- cfg = wiphy_priv(wiphy);
- cfg->wiphy = wiphy;
-+ cfg->ops = ops;
- cfg->pub = drvr;
- init_vif_event(&cfg->vif_event);
- INIT_LIST_HEAD(&cfg->vif_list);
-@@ -6686,6 +6727,7 @@ priv_out:
- ifp->vif = NULL;
- wiphy_out:
- brcmf_free_wiphy(wiphy);
-+ kfree(ops);
- return NULL;
- }
-
-@@ -6696,6 +6738,7 @@ void brcmf_cfg80211_detach(struct brcmf_
-
- brcmf_btcoex_detach(cfg);
- wiphy_unregister(cfg->wiphy);
-+ kfree(cfg->ops);
- wl_deinit_priv(cfg);
- brcmf_free_wiphy(cfg->wiphy);
- }
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
-@@ -256,6 +256,7 @@ struct brcmf_cfg80211_wowl {
- * struct brcmf_cfg80211_info - dongle private data of cfg80211 interface
- *
- * @wiphy: wiphy object for cfg80211 interface.
-+ * @ops: pointer to copy of ops as registered with wiphy object.
- * @conf: dongle configuration.
- * @p2p: peer-to-peer specific information.
- * @btcoex: Bluetooth coexistence information.
-@@ -288,6 +289,7 @@ struct brcmf_cfg80211_wowl {
- */
- struct brcmf_cfg80211_info {
- struct wiphy *wiphy;
-+ struct cfg80211_ops *ops;
- struct brcmf_cfg80211_conf *conf;
- struct brcmf_p2p_info p2p;
- struct brcmf_btcoex_info *btcoex;
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
-@@ -136,6 +136,7 @@ void brcmf_feat_attach(struct brcmf_pub
- {
- struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0);
- struct brcmf_pno_macaddr_le pfn_mac;
-+ u32 wowl_cap;
- s32 err;
-
- brcmf_feat_firmware_capabilities(ifp);
-@@ -143,6 +144,17 @@ void brcmf_feat_attach(struct brcmf_pub
- brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_PNO, "pfn");
- if (drvr->bus_if->wowl_supported)
- brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl");
-+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL)) {
-+ err = brcmf_fil_iovar_int_get(ifp, "wowl_cap", &wowl_cap);
-+ if (!err) {
-+ if (wowl_cap & BRCMF_WOWL_PFN_FOUND)
-+ ifp->drvr->feat_flags |=
-+ BIT(BRCMF_FEAT_WOWL_ND);
-+ if (wowl_cap & BRCMF_WOWL_GTK_FAILURE)
-+ ifp->drvr->feat_flags |=
-+ BIT(BRCMF_FEAT_WOWL_GTK);
-+ }
-+ }
- /* MBSS does not work for 43362 */
- if (drvr->bus_if->chip == BRCM_CC_43362_CHIP_ID)
- ifp->drvr->feat_flags &= ~BIT(BRCMF_FEAT_MBSS);
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
-@@ -27,6 +27,8 @@
- * RSDB: Real Simultaneous Dual Band
- * TDLS: Tunneled Direct Link Setup
- * SCAN_RANDOM_MAC: Random MAC during (net detect) scheduled scan.
-+ * WOWL_ND: WOWL net detect (PNO)
-+ * WOWL_GTK: (WOWL) GTK rekeying offload
- */
- #define BRCMF_FEAT_LIST \
- BRCMF_FEAT_DEF(MBSS) \
-@@ -36,7 +38,9 @@
- BRCMF_FEAT_DEF(P2P) \
- BRCMF_FEAT_DEF(RSDB) \
- BRCMF_FEAT_DEF(TDLS) \
-- BRCMF_FEAT_DEF(SCAN_RANDOM_MAC)
-+ BRCMF_FEAT_DEF(SCAN_RANDOM_MAC) \
-+ BRCMF_FEAT_DEF(WOWL_ND) \
-+ BRCMF_FEAT_DEF(WOWL_GTK)
-
- /*
- * Quirks:
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
-@@ -111,7 +111,9 @@
- /* Wakeup if received matched secured pattern: */
- #define BRCMF_WOWL_SECURE (1 << 25)
- /* Wakeup on finding preferred network */
--#define BRCMF_WOWL_PFN_FOUND (1 << 26)
-+#define BRCMF_WOWL_PFN_FOUND (1 << 27)
-+/* Wakeup on receiving pairwise key EAP packets: */
-+#define WIPHY_WOWL_EAP_PK (1 << 28)
- /* Link Down indication in WoWL mode: */
- #define BRCMF_WOWL_LINKDOWN (1 << 31)
-
-@@ -136,6 +138,10 @@
-
- #define BRCMF_MCSSET_LEN 16
-
-+#define BRCMF_RSN_KCK_LENGTH 16
-+#define BRCMF_RSN_KEK_LENGTH 16
-+#define BRCMF_RSN_REPLAY_LEN 8
-+
- /* join preference types for join_pref iovar */
- enum brcmf_join_pref_types {
- BRCMF_JOIN_PREF_RSSI = 1,
-@@ -789,4 +795,17 @@ struct brcmf_pktcnt_le {
- __le32 rx_ocast_good_pkt;
- };
-
-+/**
-+ * struct brcmf_gtk_keyinfo_le - GTP rekey data
-+ *
-+ * @kck: key confirmation key.
-+ * @kek: key encryption key.
-+ * @replay_counter: replay counter.
-+ */
-+struct brcmf_gtk_keyinfo_le {
-+ u8 kck[BRCMF_RSN_KCK_LENGTH];
-+ u8 kek[BRCMF_RSN_KEK_LENGTH];
-+ u8 replay_counter[BRCMF_RSN_REPLAY_LEN];
-+};
-+
- #endif /* FWIL_TYPES_H_ */
diff --git a/package/kernel/mac80211/patches/344-0015-brcmfmac-move-platform-data-retrieval-code-to-common.patch b/package/kernel/mac80211/patches/344-0015-brcmfmac-move-platform-data-retrieval-code-to-common.patch
deleted file mode 100644
index 2685238925..0000000000
--- a/package/kernel/mac80211/patches/344-0015-brcmfmac-move-platform-data-retrieval-code-to-common.patch
+++ /dev/null
@@ -1,385 +0,0 @@
-From: Hante Meuleman <meuleman@broadcom.com>
-Date: Wed, 17 Feb 2016 11:27:04 +0100
-Subject: [PATCH] brcmfmac: move platform data retrieval code to common
-
-In preparation of module parameters for all devices the module
-platform data retrieval is moved from sdio to common. It is still
-only used for sdio devices.
-
-Reviewed-by: Arend Van Spriel <arend@broadcom.com>
-Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
-Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
-@@ -27,8 +27,6 @@
- #include <linux/mmc/sdio_func.h>
- #include <linux/mmc/card.h>
- #include <linux/mmc/host.h>
--#include <linux/platform_device.h>
--#include <linux/platform_data/brcmfmac-sdio.h>
- #include <linux/pm_runtime.h>
- #include <linux/suspend.h>
- #include <linux/errno.h>
-@@ -46,7 +44,6 @@
- #include "bus.h"
- #include "debug.h"
- #include "sdio.h"
--#include "of.h"
- #include "core.h"
- #include "common.h"
-
-@@ -106,18 +103,18 @@ static void brcmf_sdiod_dummy_irqhandler
-
- int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
- {
-+ struct brcmfmac_sdio_platform_data *pdata;
- int ret = 0;
- u8 data;
- u32 addr, gpiocontrol;
- unsigned long flags;
-
-- if ((sdiodev->pdata) && (sdiodev->pdata->oob_irq_supported)) {
-+ pdata = sdiodev->pdata;
-+ if ((pdata) && (pdata->oob_irq_supported)) {
- brcmf_dbg(SDIO, "Enter, register OOB IRQ %d\n",
-- sdiodev->pdata->oob_irq_nr);
-- ret = request_irq(sdiodev->pdata->oob_irq_nr,
-- brcmf_sdiod_oob_irqhandler,
-- sdiodev->pdata->oob_irq_flags,
-- "brcmf_oob_intr",
-+ pdata->oob_irq_nr);
-+ ret = request_irq(pdata->oob_irq_nr, brcmf_sdiod_oob_irqhandler,
-+ pdata->oob_irq_flags, "brcmf_oob_intr",
- &sdiodev->func[1]->dev);
- if (ret != 0) {
- brcmf_err("request_irq failed %d\n", ret);
-@@ -129,7 +126,7 @@ int brcmf_sdiod_intr_register(struct brc
- sdiodev->irq_en = true;
- spin_unlock_irqrestore(&sdiodev->irq_en_lock, flags);
-
-- ret = enable_irq_wake(sdiodev->pdata->oob_irq_nr);
-+ ret = enable_irq_wake(pdata->oob_irq_nr);
- if (ret != 0) {
- brcmf_err("enable_irq_wake failed %d\n", ret);
- return ret;
-@@ -158,7 +155,7 @@ int brcmf_sdiod_intr_register(struct brc
-
- /* redirect, configure and enable io for interrupt signal */
- data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE;
-- if (sdiodev->pdata->oob_irq_flags & IRQF_TRIGGER_HIGH)
-+ if (pdata->oob_irq_flags & IRQF_TRIGGER_HIGH)
- data |= SDIO_SEPINT_ACT_HI;
- brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret);
-
-@@ -176,9 +173,12 @@ int brcmf_sdiod_intr_register(struct brc
-
- int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev)
- {
-+ struct brcmfmac_sdio_platform_data *pdata;
-+
- brcmf_dbg(SDIO, "Entering\n");
-
-- if ((sdiodev->pdata) && (sdiodev->pdata->oob_irq_supported)) {
-+ pdata = sdiodev->pdata;
-+ if ((pdata) && (pdata->oob_irq_supported)) {
- sdio_claim_host(sdiodev->func[1]);
- brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL);
- brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL);
-@@ -187,11 +187,10 @@ int brcmf_sdiod_intr_unregister(struct b
- if (sdiodev->oob_irq_requested) {
- sdiodev->oob_irq_requested = false;
- if (sdiodev->irq_wake) {
-- disable_irq_wake(sdiodev->pdata->oob_irq_nr);
-+ disable_irq_wake(pdata->oob_irq_nr);
- sdiodev->irq_wake = false;
- }
-- free_irq(sdiodev->pdata->oob_irq_nr,
-- &sdiodev->func[1]->dev);
-+ free_irq(pdata->oob_irq_nr, &sdiodev->func[1]->dev);
- sdiodev->irq_en = false;
- }
- } else {
-@@ -1103,8 +1102,6 @@ static const struct sdio_device_id brcmf
- };
- MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids);
-
--static struct brcmfmac_sdio_platform_data *brcmfmac_sdio_pdata;
--
-
- static void brcmf_sdiod_acpi_set_power_manageable(struct device *dev,
- int val)
-@@ -1167,10 +1164,7 @@ static int brcmf_ops_sdio_probe(struct s
- dev_set_drvdata(&func->dev, bus_if);
- dev_set_drvdata(&sdiodev->func[1]->dev, bus_if);
- sdiodev->dev = &sdiodev->func[1]->dev;
-- sdiodev->pdata = brcmfmac_sdio_pdata;
--
-- if (!sdiodev->pdata)
-- brcmf_of_probe(sdiodev);
-+ sdiodev->pdata = brcmf_get_module_param(sdiodev->dev);
-
- #ifdef CONFIG_PM_SLEEP
- /* wowl can be supported when KEEP_POWER is true and (WAKE_SDIO_IRQ
-@@ -1296,7 +1290,7 @@ static const struct dev_pm_ops brcmf_sdi
- static struct sdio_driver brcmf_sdmmc_driver = {
- .probe = brcmf_ops_sdio_probe,
- .remove = brcmf_ops_sdio_remove,
-- .name = BRCMFMAC_SDIO_PDATA_NAME,
-+ .name = KBUILD_MODNAME,
- .id_table = brcmf_sdmmc_ids,
- .drv = {
- .owner = THIS_MODULE,
-@@ -1306,37 +1300,6 @@ static struct sdio_driver brcmf_sdmmc_dr
- },
- };
-
--static int __init brcmf_sdio_pd_probe(struct platform_device *pdev)
--{
-- brcmf_dbg(SDIO, "Enter\n");
--
-- brcmfmac_sdio_pdata = dev_get_platdata(&pdev->dev);
--
-- if (brcmfmac_sdio_pdata->power_on)
-- brcmfmac_sdio_pdata->power_on();
--
-- return 0;
--}
--
--static int brcmf_sdio_pd_remove(struct platform_device *pdev)
--{
-- brcmf_dbg(SDIO, "Enter\n");
--
-- if (brcmfmac_sdio_pdata->power_off)
-- brcmfmac_sdio_pdata->power_off();
--
-- sdio_unregister_driver(&brcmf_sdmmc_driver);
--
-- return 0;
--}
--
--static struct platform_driver brcmf_sdio_pd = {
-- .remove = brcmf_sdio_pd_remove,
-- .driver = {
-- .name = BRCMFMAC_SDIO_PDATA_NAME,
-- }
--};
--
- void brcmf_sdio_register(void)
- {
- int ret;
-@@ -1350,19 +1313,6 @@ void brcmf_sdio_exit(void)
- {
- brcmf_dbg(SDIO, "Enter\n");
-
-- if (brcmfmac_sdio_pdata)
-- platform_driver_unregister(&brcmf_sdio_pd);
-- else
-- sdio_unregister_driver(&brcmf_sdmmc_driver);
-+ sdio_unregister_driver(&brcmf_sdmmc_driver);
- }
-
--void __init brcmf_sdio_init(void)
--{
-- int ret;
--
-- brcmf_dbg(SDIO, "Enter\n");
--
-- ret = platform_driver_probe(&brcmf_sdio_pd, brcmf_sdio_pd_probe);
-- if (ret == -ENODEV)
-- brcmf_dbg(SDIO, "No platform data available.\n");
--}
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
-@@ -27,6 +27,7 @@
- #include "fwil_types.h"
- #include "tracepoint.h"
- #include "common.h"
-+#include "of.h"
-
- MODULE_AUTHOR("Broadcom Corporation");
- MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver.");
-@@ -79,6 +80,7 @@ module_param_named(ignore_probe_fail, br
- MODULE_PARM_DESC(ignore_probe_fail, "always succeed probe for debugging");
- #endif
-
-+static struct brcmfmac_sdio_platform_data *brcmfmac_pdata;
- struct brcmf_mp_global_t brcmf_mp_global;
-
- int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
-@@ -231,6 +233,13 @@ static void brcmf_mp_attach(void)
- BRCMF_FW_ALTPATH_LEN);
- }
-
-+struct brcmfmac_sdio_platform_data *brcmf_get_module_param(struct device *dev)
-+{
-+ if (!brcmfmac_pdata)
-+ brcmf_of_probe(dev, &brcmfmac_pdata);
-+ return brcmfmac_pdata;
-+}
-+
- int brcmf_mp_device_attach(struct brcmf_pub *drvr)
- {
- drvr->settings = kzalloc(sizeof(*drvr->settings), GFP_ATOMIC);
-@@ -253,6 +262,35 @@ void brcmf_mp_device_detach(struct brcmf
- kfree(drvr->settings);
- }
-
-+static int __init brcmf_common_pd_probe(struct platform_device *pdev)
-+{
-+ brcmf_dbg(INFO, "Enter\n");
-+
-+ brcmfmac_pdata = dev_get_platdata(&pdev->dev);
-+
-+ if (brcmfmac_pdata->power_on)
-+ brcmfmac_pdata->power_on();
-+
-+ return 0;
-+}
-+
-+static int brcmf_common_pd_remove(struct platform_device *pdev)
-+{
-+ brcmf_dbg(INFO, "Enter\n");
-+
-+ if (brcmfmac_pdata->power_off)
-+ brcmfmac_pdata->power_off();
-+
-+ return 0;
-+}
-+
-+static struct platform_driver brcmf_pd = {
-+ .remove = brcmf_common_pd_remove,
-+ .driver = {
-+ .name = BRCMFMAC_SDIO_PDATA_NAME,
-+ }
-+};
-+
- static int __init brcmfmac_module_init(void)
- {
- int err;
-@@ -260,16 +298,21 @@ static int __init brcmfmac_module_init(v
- /* Initialize debug system first */
- brcmf_debugfs_init();
-
--#ifdef CPTCFG_BRCMFMAC_SDIO
-- brcmf_sdio_init();
--#endif
-+ /* Get the platform data (if available) for our devices */
-+ err = platform_driver_probe(&brcmf_pd, brcmf_common_pd_probe);
-+ if (err == -ENODEV)
-+ brcmf_dbg(INFO, "No platform data available.\n");
-+
- /* Initialize global module paramaters */
- brcmf_mp_attach();
-
- /* Continue the initialization by registering the different busses */
- err = brcmf_core_init();
-- if (err)
-+ if (err) {
- brcmf_debugfs_exit();
-+ if (brcmfmac_pdata)
-+ platform_driver_unregister(&brcmf_pd);
-+ }
-
- return err;
- }
-@@ -277,6 +320,8 @@ static int __init brcmfmac_module_init(v
- static void __exit brcmfmac_module_exit(void)
- {
- brcmf_core_exit();
-+ if (brcmfmac_pdata)
-+ platform_driver_unregister(&brcmf_pd);
- brcmf_debugfs_exit();
- }
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
-@@ -15,6 +15,8 @@
- #ifndef BRCMFMAC_COMMON_H
- #define BRCMFMAC_COMMON_H
-
-+#include <linux/platform_device.h>
-+#include <linux/platform_data/brcmfmac-sdio.h>
- #include "fwil_types.h"
-
- extern const u8 ALLFFMAC[ETH_ALEN];
-@@ -89,6 +91,7 @@ struct brcmf_mp_device {
- struct cc_translate *country_codes;
- };
-
-+struct brcmfmac_sdio_platform_data *brcmf_get_module_param(struct device *dev);
- int brcmf_mp_device_attach(struct brcmf_pub *drvr);
- void brcmf_mp_device_detach(struct brcmf_pub *drvr);
- #ifdef DEBUG
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
-@@ -16,17 +16,16 @@
- #include <linux/init.h>
- #include <linux/of.h>
- #include <linux/of_irq.h>
--#include <linux/mmc/card.h>
--#include <linux/platform_data/brcmfmac-sdio.h>
--#include <linux/mmc/sdio_func.h>
-
- #include <defs.h>
- #include "debug.h"
--#include "sdio.h"
-+#include "core.h"
-+#include "common.h"
-+#include "of.h"
-
--void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev)
-+void
-+brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_platform_data **sdio)
- {
-- struct device *dev = sdiodev->dev;
- struct device_node *np = dev->of_node;
- int irq;
- u32 irqf;
-@@ -35,12 +34,12 @@ void brcmf_of_probe(struct brcmf_sdio_de
- if (!np || !of_device_is_compatible(np, "brcm,bcm4329-fmac"))
- return;
-
-- sdiodev->pdata = devm_kzalloc(dev, sizeof(*sdiodev->pdata), GFP_KERNEL);
-- if (!sdiodev->pdata)
-+ *sdio = devm_kzalloc(dev, sizeof(*sdio), GFP_KERNEL);
-+ if (!(*sdio))
- return;
-
- if (of_property_read_u32(np, "brcm,drive-strength", &val) == 0)
-- sdiodev->pdata->drive_strength = val;
-+ (*sdio)->drive_strength = val;
-
- /* make sure there are interrupts defined in the node */
- if (!of_find_property(np, "interrupts", NULL))
-@@ -53,7 +52,7 @@ void brcmf_of_probe(struct brcmf_sdio_de
- }
- irqf = irqd_get_trigger_type(irq_get_irq_data(irq));
-
-- sdiodev->pdata->oob_irq_supported = true;
-- sdiodev->pdata->oob_irq_nr = irq;
-- sdiodev->pdata->oob_irq_flags = irqf;
-+ (*sdio)->oob_irq_supported = true;
-+ (*sdio)->oob_irq_nr = irq;
-+ (*sdio)->oob_irq_flags = irqf;
- }
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h
-@@ -14,9 +14,11 @@
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- #ifdef CONFIG_OF
--void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev);
-+void
-+brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_platform_data **sdio);
- #else
--static void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev)
-+static void brcmf_of_probe(struct device *dev,
-+ struct brcmfmac_sdio_platform_data **sdio)
- {
- }
- #endif /* CONFIG_OF */
diff --git a/package/kernel/mac80211/patches/344-0016-brcmfmac-keep-ARP-and-ND-offload-enabled-during-WOWL.patch b/package/kernel/mac80211/patches/344-0016-brcmfmac-keep-ARP-and-ND-offload-enabled-during-WOWL.patch
deleted file mode 100644
index 4e789cfc5a..0000000000
--- a/package/kernel/mac80211/patches/344-0016-brcmfmac-keep-ARP-and-ND-offload-enabled-during-WOWL.patch
+++ /dev/null
@@ -1,69 +0,0 @@
-From: Hante Meuleman <meuleman@broadcom.com>
-Date: Wed, 17 Feb 2016 11:27:05 +0100
-Subject: [PATCH] brcmfmac: keep ARP and ND offload enabled during WOWL
-
-Currently ARP and ND (IPv6 Neigbor Discovery) offload get disabled
-on entering suspend. However when firmwares support the wowl_cap
-iovar then these offload routines can be kept enabled as they
-will work during WOWL as well.
-
-Reviewed-by: Arend Van Spriel <arend@broadcom.com>
-Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
-Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -3556,7 +3556,8 @@ static s32 brcmf_cfg80211_resume(struct
- brcmf_report_wowl_wakeind(wiphy, ifp);
- brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
- brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0);
-- brcmf_configure_arp_nd_offload(ifp, true);
-+ if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND))
-+ brcmf_configure_arp_nd_offload(ifp, true);
- brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
- cfg->wowl.pre_pmmode);
- cfg->wowl.active = false;
-@@ -3580,7 +3581,8 @@ static void brcmf_configure_wowl(struct
-
- brcmf_dbg(TRACE, "Suspend, wowl config.\n");
-
-- brcmf_configure_arp_nd_offload(ifp, false);
-+ if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND))
-+ brcmf_configure_arp_nd_offload(ifp, false);
- brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->wowl.pre_pmmode);
- brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX);
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
-@@ -147,6 +147,7 @@ void brcmf_feat_attach(struct brcmf_pub
- if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL)) {
- err = brcmf_fil_iovar_int_get(ifp, "wowl_cap", &wowl_cap);
- if (!err) {
-+ ifp->drvr->feat_flags |= BIT(BRCMF_FEAT_WOWL_ARP_ND);
- if (wowl_cap & BRCMF_WOWL_PFN_FOUND)
- ifp->drvr->feat_flags |=
- BIT(BRCMF_FEAT_WOWL_ND);
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
-@@ -29,6 +29,7 @@
- * SCAN_RANDOM_MAC: Random MAC during (net detect) scheduled scan.
- * WOWL_ND: WOWL net detect (PNO)
- * WOWL_GTK: (WOWL) GTK rekeying offload
-+ * WOWL_ARP_ND: ARP and Neighbor Discovery offload support during WOWL.
- */
- #define BRCMF_FEAT_LIST \
- BRCMF_FEAT_DEF(MBSS) \
-@@ -40,7 +41,8 @@
- BRCMF_FEAT_DEF(TDLS) \
- BRCMF_FEAT_DEF(SCAN_RANDOM_MAC) \
- BRCMF_FEAT_DEF(WOWL_ND) \
-- BRCMF_FEAT_DEF(WOWL_GTK)
-+ BRCMF_FEAT_DEF(WOWL_GTK) \
-+ BRCMF_FEAT_DEF(WOWL_ARP_ND)
-
- /*
- * Quirks:
diff --git a/package/kernel/mac80211/patches/344-0017-brcmfmac-switch-to-new-platform-data.patch b/package/kernel/mac80211/patches/344-0017-brcmfmac-switch-to-new-platform-data.patch
deleted file mode 100644
index 37b68552cc..0000000000
--- a/package/kernel/mac80211/patches/344-0017-brcmfmac-switch-to-new-platform-data.patch
+++ /dev/null
@@ -1,734 +0,0 @@
-From: Hante Meuleman <meuleman@broadcom.com>
-Date: Wed, 17 Feb 2016 11:27:07 +0100
-Subject: [PATCH] brcmfmac: switch to new platform data
-
-Platform data is only available for sdio. With this patch a new
-platform data structure is being used which allows for platform
-data for any device and configurable per device. This patch only
-switches to the new structure and adds support for SDIO devices.
-
-Reviewed-by: Arend Van Spriel <arend@broadcom.com>
-Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
-Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
-@@ -103,7 +103,7 @@ static void brcmf_sdiod_dummy_irqhandler
-
- int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
- {
-- struct brcmfmac_sdio_platform_data *pdata;
-+ struct brcmfmac_sdio_pd *pdata;
- int ret = 0;
- u8 data;
- u32 addr, gpiocontrol;
-@@ -173,7 +173,7 @@ int brcmf_sdiod_intr_register(struct brc
-
- int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev)
- {
-- struct brcmfmac_sdio_platform_data *pdata;
-+ struct brcmfmac_sdio_pd *pdata;
-
- brcmf_dbg(SDIO, "Entering\n");
-
-@@ -1164,17 +1164,6 @@ static int brcmf_ops_sdio_probe(struct s
- dev_set_drvdata(&func->dev, bus_if);
- dev_set_drvdata(&sdiodev->func[1]->dev, bus_if);
- sdiodev->dev = &sdiodev->func[1]->dev;
-- sdiodev->pdata = brcmf_get_module_param(sdiodev->dev);
--
--#ifdef CONFIG_PM_SLEEP
-- /* wowl can be supported when KEEP_POWER is true and (WAKE_SDIO_IRQ
-- * is true or when platform data OOB irq is true).
-- */
-- if ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_KEEP_POWER) &&
-- ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_WAKE_SDIO_IRQ) ||
-- (sdiodev->pdata && sdiodev->pdata->oob_irq_supported)))
-- bus_if->wowl_supported = true;
--#endif
-
- brcmf_sdiod_change_state(sdiodev, BRCMF_SDIOD_DOWN);
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -6459,8 +6459,8 @@ int brcmf_cfg80211_wait_vif_event(struct
- static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha2[2],
- struct brcmf_fil_country_le *ccreq)
- {
-- struct cc_translate *country_codes;
-- struct cc_entry *cc;
-+ struct brcmfmac_pd_cc *country_codes;
-+ struct brcmfmac_pd_cc_entry *cc;
- s32 found_index;
- int i;
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
-@@ -80,7 +80,7 @@ module_param_named(ignore_probe_fail, br
- MODULE_PARM_DESC(ignore_probe_fail, "always succeed probe for debugging");
- #endif
-
--static struct brcmfmac_sdio_platform_data *brcmfmac_pdata;
-+static struct brcmfmac_platform_data *brcmfmac_pdata;
- struct brcmf_mp_global_t brcmf_mp_global;
-
- int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
-@@ -229,15 +229,46 @@ void __brcmf_dbg(u32 level, const char *
-
- static void brcmf_mp_attach(void)
- {
-+ /* If module param firmware path is set then this will always be used,
-+ * if not set then if available use the platform data version. To make
-+ * sure it gets initialized at all, always copy the module param version
-+ */
- strlcpy(brcmf_mp_global.firmware_path, brcmf_firmware_path,
- BRCMF_FW_ALTPATH_LEN);
-+ if ((brcmfmac_pdata) && (brcmfmac_pdata->fw_alternative_path) &&
-+ (brcmf_mp_global.firmware_path[0] == '\0')) {
-+ strlcpy(brcmf_mp_global.firmware_path,
-+ brcmfmac_pdata->fw_alternative_path,
-+ BRCMF_FW_ALTPATH_LEN);
-+ }
- }
-
--struct brcmfmac_sdio_platform_data *brcmf_get_module_param(struct device *dev)
--{
-- if (!brcmfmac_pdata)
-- brcmf_of_probe(dev, &brcmfmac_pdata);
-- return brcmfmac_pdata;
-+struct brcmfmac_sdio_pd *brcmf_get_module_param(struct device *dev,
-+ enum brcmf_bus_type bus_type,
-+ u32 chip, u32 chiprev)
-+{
-+ struct brcmfmac_sdio_pd *pdata;
-+ struct brcmfmac_pd_device *device_pd;
-+ int i;
-+
-+ if (brcmfmac_pdata) {
-+ for (i = 0; i < brcmfmac_pdata->device_count; i++) {
-+ device_pd = &brcmfmac_pdata->devices[i];
-+ if ((device_pd->bus_type == bus_type) &&
-+ (device_pd->id == chip) &&
-+ ((device_pd->rev == chiprev) ||
-+ (device_pd->rev == -1))) {
-+ brcmf_dbg(INFO, "Platform data for device found\n");
-+ if (device_pd->bus_type == BRCMF_BUSTYPE_SDIO)
-+ return &device_pd->bus.sdio;
-+ break;
-+ }
-+ }
-+ }
-+ pdata = NULL;
-+ brcmf_of_probe(dev, &pdata);
-+
-+ return pdata;
- }
-
- int brcmf_mp_device_attach(struct brcmf_pub *drvr)
-@@ -287,7 +318,7 @@ static int brcmf_common_pd_remove(struct
- static struct platform_driver brcmf_pd = {
- .remove = brcmf_common_pd_remove,
- .driver = {
-- .name = BRCMFMAC_SDIO_PDATA_NAME,
-+ .name = BRCMFMAC_PDATA_NAME,
- }
- };
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
-@@ -16,7 +16,7 @@
- #define BRCMFMAC_COMMON_H
-
- #include <linux/platform_device.h>
--#include <linux/platform_data/brcmfmac-sdio.h>
-+#include <linux/platform_data/brcmfmac.h>
- #include "fwil_types.h"
-
- extern const u8 ALLFFMAC[ETH_ALEN];
-@@ -43,33 +43,6 @@ struct brcmf_mp_global_t {
- extern struct brcmf_mp_global_t brcmf_mp_global;
-
- /**
-- * struct cc_entry - Struct for translating user space country code (iso3166) to
-- * firmware country code and revision.
-- *
-- * @iso3166: iso3166 alpha 2 country code string.
-- * @cc: firmware country code string.
-- * @rev: firmware country code revision.
-- */
--struct cc_entry {
-- char iso3166[BRCMF_COUNTRY_BUF_SZ];
-- char cc[BRCMF_COUNTRY_BUF_SZ];
-- s32 rev;
--};
--
--/**
-- * struct cc_translate - Struct for translating country codes as set by user
-- * space to a country code and rev which can be used by
-- * firmware.
-- *
-- * @table_size: number of entries in table (> 0)
-- * @table: dynamic array of 1 or more elements with translation information.
-- */
--struct cc_translate {
-- int table_size;
-- struct cc_entry table[0];
--};
--
--/**
- * struct brcmf_mp_device - Device module paramaters.
- *
- * @sdiod_txglomsz: SDIO txglom size.
-@@ -88,10 +61,12 @@ struct brcmf_mp_device {
- int fcmode;
- bool roamoff;
- bool ignore_probe_fail;
-- struct cc_translate *country_codes;
-+ struct brcmfmac_pd_cc *country_codes;
- };
-
--struct brcmfmac_sdio_platform_data *brcmf_get_module_param(struct device *dev);
-+struct brcmfmac_sdio_pd *brcmf_get_module_param(struct device *dev,
-+ enum brcmf_bus_type bus_type,
-+ u32 chip, u32 chiprev);
- int brcmf_mp_device_attach(struct brcmf_pub *drvr);
- void brcmf_mp_device_detach(struct brcmf_pub *drvr);
- #ifdef DEBUG
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
-@@ -23,8 +23,7 @@
- #include "common.h"
- #include "of.h"
-
--void
--brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_platform_data **sdio)
-+void brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd **sdio)
- {
- struct device_node *np = dev->of_node;
- int irq;
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h
-@@ -15,10 +15,9 @@
- */
- #ifdef CONFIG_OF
- void
--brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_platform_data **sdio);
-+brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd **sdio);
- #else
--static void brcmf_of_probe(struct device *dev,
-- struct brcmfmac_sdio_platform_data **sdio)
-+static void brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd **sdio)
- {
- }
- #endif /* CONFIG_OF */
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
-@@ -33,8 +33,6 @@
- #include <linux/bcma/bcma.h>
- #include <linux/debugfs.h>
- #include <linux/vmalloc.h>
--#include <linux/platform_data/brcmfmac-sdio.h>
--#include <linux/moduleparam.h>
- #include <asm/unaligned.h>
- #include <defs.h>
- #include <brcmu_wifi.h>
-@@ -44,6 +42,8 @@
- #include "sdio.h"
- #include "chip.h"
- #include "firmware.h"
-+#include "core.h"
-+#include "common.h"
-
- #define DCMD_RESP_TIMEOUT msecs_to_jiffies(2500)
- #define CTL_DONE_TIMEOUT msecs_to_jiffies(2500)
-@@ -3775,26 +3775,28 @@ static const struct brcmf_buscore_ops br
- static bool
- brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
- {
-+ struct brcmf_sdio_dev *sdiodev;
- u8 clkctl = 0;
- int err = 0;
- int reg_addr;
- u32 reg_val;
- u32 drivestrength;
-
-- sdio_claim_host(bus->sdiodev->func[1]);
-+ sdiodev = bus->sdiodev;
-+ sdio_claim_host(sdiodev->func[1]);
-
- pr_debug("F1 signature read @0x18000000=0x%4x\n",
-- brcmf_sdiod_regrl(bus->sdiodev, SI_ENUM_BASE, NULL));
-+ brcmf_sdiod_regrl(sdiodev, SI_ENUM_BASE, NULL));
-
- /*
- * Force PLL off until brcmf_chip_attach()
- * programs PLL control regs
- */
-
-- brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
-+ brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
- BRCMF_INIT_CLKCTL1, &err);
- if (!err)
-- clkctl = brcmf_sdiod_regrb(bus->sdiodev,
-+ clkctl = brcmf_sdiod_regrb(sdiodev,
- SBSDIO_FUNC1_CHIPCLKCSR, &err);
-
- if (err || ((clkctl & ~SBSDIO_AVBITS) != BRCMF_INIT_CLKCTL1)) {
-@@ -3803,50 +3805,77 @@ brcmf_sdio_probe_attach(struct brcmf_sdi
- goto fail;
- }
-
-- bus->ci = brcmf_chip_attach(bus->sdiodev, &brcmf_sdio_buscore_ops);
-+ bus->ci = brcmf_chip_attach(sdiodev, &brcmf_sdio_buscore_ops);
- if (IS_ERR(bus->ci)) {
- brcmf_err("brcmf_chip_attach failed!\n");
- bus->ci = NULL;
- goto fail;
- }
-+ sdiodev->pdata = brcmf_get_module_param(sdiodev->dev,
-+ BRCMF_BUSTYPE_SDIO,
-+ bus->ci->chip,
-+ bus->ci->chiprev);
-+ /* platform specific configuration:
-+ * alignments must be at least 4 bytes for ADMA
-+ */
-+ bus->head_align = ALIGNMENT;
-+ bus->sgentry_align = ALIGNMENT;
-+ if (sdiodev->pdata) {
-+ if (sdiodev->pdata->sd_head_align > ALIGNMENT)
-+ bus->head_align = sdiodev->pdata->sd_head_align;
-+ if (sdiodev->pdata->sd_sgentry_align > ALIGNMENT)
-+ bus->sgentry_align = sdiodev->pdata->sd_sgentry_align;
-+ }
-+ /* allocate scatter-gather table. sg support
-+ * will be disabled upon allocation failure.
-+ */
-+ brcmf_sdiod_sgtable_alloc(sdiodev);
-+
-+#ifdef CONFIG_PM_SLEEP
-+ /* wowl can be supported when KEEP_POWER is true and (WAKE_SDIO_IRQ
-+ * is true or when platform data OOB irq is true).
-+ */
-+ if ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_KEEP_POWER) &&
-+ ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_WAKE_SDIO_IRQ) ||
-+ (sdiodev->pdata && sdiodev->pdata->oob_irq_supported)))
-+ sdiodev->bus_if->wowl_supported = true;
-+#endif
-
- if (brcmf_sdio_kso_init(bus)) {
- brcmf_err("error enabling KSO\n");
- goto fail;
- }
-
-- if ((bus->sdiodev->pdata) && (bus->sdiodev->pdata->drive_strength))
-- drivestrength = bus->sdiodev->pdata->drive_strength;
-+ if ((sdiodev->pdata) && (sdiodev->pdata->drive_strength))
-+ drivestrength = sdiodev->pdata->drive_strength;
- else
- drivestrength = DEFAULT_SDIO_DRIVE_STRENGTH;
-- brcmf_sdio_drivestrengthinit(bus->sdiodev, bus->ci, drivestrength);
-+ brcmf_sdio_drivestrengthinit(sdiodev, bus->ci, drivestrength);
-
- /* Set card control so an SDIO card reset does a WLAN backplane reset */
-- reg_val = brcmf_sdiod_regrb(bus->sdiodev,
-- SDIO_CCCR_BRCM_CARDCTRL, &err);
-+ reg_val = brcmf_sdiod_regrb(sdiodev, SDIO_CCCR_BRCM_CARDCTRL, &err);
- if (err)
- goto fail;
-
- reg_val |= SDIO_CCCR_BRCM_CARDCTRL_WLANRESET;
-
-- brcmf_sdiod_regwb(bus->sdiodev,
-- SDIO_CCCR_BRCM_CARDCTRL, reg_val, &err);
-+ brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_BRCM_CARDCTRL, reg_val, &err);
- if (err)
- goto fail;
-
- /* set PMUControl so a backplane reset does PMU state reload */
- reg_addr = CORE_CC_REG(brcmf_chip_get_pmu(bus->ci)->base, pmucontrol);
-- reg_val = brcmf_sdiod_regrl(bus->sdiodev, reg_addr, &err);
-+ reg_val = brcmf_sdiod_regrl(sdiodev, reg_addr, &err);
- if (err)
- goto fail;
-
- reg_val |= (BCMA_CC_PMU_CTL_RES_RELOAD << BCMA_CC_PMU_CTL_RES_SHIFT);
-
-- brcmf_sdiod_regwl(bus->sdiodev, reg_addr, reg_val, &err);
-+ brcmf_sdiod_regwl(sdiodev, reg_addr, reg_val, &err);
- if (err)
- goto fail;
-
-- sdio_release_host(bus->sdiodev->func[1]);
-+ sdio_release_host(sdiodev->func[1]);
-
- brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN);
-
-@@ -3867,7 +3896,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdi
- return true;
-
- fail:
-- sdio_release_host(bus->sdiodev->func[1]);
-+ sdio_release_host(sdiodev->func[1]);
- return false;
- }
-
-@@ -4045,18 +4074,6 @@ struct brcmf_sdio *brcmf_sdio_probe(stru
- bus->txminmax = BRCMF_TXMINMAX;
- bus->tx_seq = SDPCM_SEQ_WRAP - 1;
-
-- /* platform specific configuration:
-- * alignments must be at least 4 bytes for ADMA
-- */
-- bus->head_align = ALIGNMENT;
-- bus->sgentry_align = ALIGNMENT;
-- if (sdiodev->pdata) {
-- if (sdiodev->pdata->sd_head_align > ALIGNMENT)
-- bus->head_align = sdiodev->pdata->sd_head_align;
-- if (sdiodev->pdata->sd_sgentry_align > ALIGNMENT)
-- bus->sgentry_align = sdiodev->pdata->sd_sgentry_align;
-- }
--
- /* single-threaded workqueue */
- wq = alloc_ordered_workqueue("brcmf_wq/%s", WQ_MEM_RECLAIM,
- dev_name(&sdiodev->func[1]->dev));
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
-@@ -184,7 +184,7 @@ struct brcmf_sdio_dev {
- struct brcmf_sdio *bus;
- struct device *dev;
- struct brcmf_bus *bus_if;
-- struct brcmfmac_sdio_platform_data *pdata;
-+ struct brcmfmac_sdio_pd *pdata;
- bool oob_irq_requested;
- bool irq_en; /* irq enable flags */
- spinlock_t irq_en_lock;
---- a/include/linux/platform_data/brcmfmac-sdio.h
-+++ /dev/null
-@@ -1,135 +0,0 @@
--/*
-- * Copyright (c) 2013 Broadcom Corporation
-- *
-- * Permission to use, copy, modify, and/or distribute this software for any
-- * purpose with or without fee is hereby granted, provided that the above
-- * copyright notice and this permission notice appear in all copies.
-- *
-- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
-- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
-- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-- */
--
--#ifndef _LINUX_BRCMFMAC_PLATFORM_H
--#define _LINUX_BRCMFMAC_PLATFORM_H
--
--/*
-- * Platform specific driver functions and data. Through the platform specific
-- * device data functions can be provided to help the brcmfmac driver to
-- * operate with the device in combination with the used platform.
-- *
-- * Use the platform data in the following (similar) way:
-- *
-- *
--#include <brcmfmac_platform.h>
--
--
--static void brcmfmac_power_on(void)
--{
--}
--
--static void brcmfmac_power_off(void)
--{
--}
--
--static void brcmfmac_reset(void)
--{
--}
--
--static struct brcmfmac_sdio_platform_data brcmfmac_sdio_pdata = {
-- .power_on = brcmfmac_power_on,
-- .power_off = brcmfmac_power_off,
-- .reset = brcmfmac_reset
--};
--
--static struct platform_device brcmfmac_device = {
-- .name = BRCMFMAC_SDIO_PDATA_NAME,
-- .id = PLATFORM_DEVID_NONE,
-- .dev.platform_data = &brcmfmac_sdio_pdata
--};
--
--void __init brcmfmac_init_pdata(void)
--{
-- brcmfmac_sdio_pdata.oob_irq_supported = true;
-- brcmfmac_sdio_pdata.oob_irq_nr = gpio_to_irq(GPIO_BRCMF_SDIO_OOB);
-- brcmfmac_sdio_pdata.oob_irq_flags = IORESOURCE_IRQ |
-- IORESOURCE_IRQ_HIGHLEVEL;
-- platform_device_register(&brcmfmac_device);
--}
-- *
-- *
-- * Note: the brcmfmac can be loaded as module or be statically built-in into
-- * the kernel. If built-in then do note that it uses module_init (and
-- * module_exit) routines which equal device_initcall. So if you intend to
-- * create a module with the platform specific data for the brcmfmac and have
-- * it built-in to the kernel then use a higher initcall then device_initcall
-- * (see init.h). If this is not done then brcmfmac will load without problems
-- * but will not pickup the platform data.
-- *
-- * When the driver does not "detect" platform driver data then it will continue
-- * without reporting anything and just assume there is no data needed. Which is
-- * probably true for most platforms.
-- *
-- * Explanation of the platform_data fields:
-- *
-- * drive_strength: is the preferred drive_strength to be used for the SDIO
-- * pins. If 0 then a default value will be used. This is the target drive
-- * strength, the exact drive strength which will be used depends on the
-- * capabilities of the device.
-- *
-- * oob_irq_supported: does the board have support for OOB interrupts. SDIO
-- * in-band interrupts are relatively slow and for having less overhead on
-- * interrupt processing an out of band interrupt can be used. If the HW
-- * supports this then enable this by setting this field to true and configure
-- * the oob related fields.
-- *
-- * oob_irq_nr, oob_irq_flags: the OOB interrupt information. The values are
-- * used for registering the irq using request_irq function.
-- *
-- * broken_sg_support: flag for broken sg list support of SDIO host controller.
-- * Set this to true if the SDIO host controller has higher align requirement
-- * than 32 bytes for each scatterlist item.
-- *
-- * sd_head_align: alignment requirement for start of data buffer
-- *
-- * sd_sgentry_align: length alignment requirement for each sg entry
-- *
-- * power_on: This function is called by the brcmfmac when the module gets
-- * loaded. This can be particularly useful for low power devices. The platform
-- * spcific routine may for example decide to power up the complete device.
-- * If there is no use-case for this function then provide NULL.
-- *
-- * power_off: This function is called by the brcmfmac when the module gets
-- * unloaded. At this point the device can be powered down or otherwise be reset.
-- * So if an actual power_off is not supported but reset is then reset the device
-- * when this function gets called. This can be particularly useful for low power
-- * devices. If there is no use-case for this function (either power-down or
-- * reset) then provide NULL.
-- *
-- * reset: This function can get called if the device communication broke down.
-- * This functionality is particularly useful in case of SDIO type devices. It is
-- * possible to reset a dongle via sdio data interface, but it requires that
-- * this is fully functional. This function is chip/module specific and this
-- * function should return only after the complete reset has completed.
-- */
--
--#define BRCMFMAC_SDIO_PDATA_NAME "brcmfmac_sdio"
--
--struct brcmfmac_sdio_platform_data {
-- unsigned int drive_strength;
-- bool oob_irq_supported;
-- unsigned int oob_irq_nr;
-- unsigned long oob_irq_flags;
-- bool broken_sg_support;
-- unsigned short sd_head_align;
-- unsigned short sd_sgentry_align;
-- void (*power_on)(void);
-- void (*power_off)(void);
-- void (*reset)(void);
--};
--
--#endif /* _LINUX_BRCMFMAC_PLATFORM_H */
---- /dev/null
-+++ b/include/linux/platform_data/brcmfmac.h
-@@ -0,0 +1,185 @@
-+/*
-+ * Copyright (c) 201 Broadcom Corporation
-+ *
-+ * Permission to use, copy, modify, and/or distribute this software for any
-+ * purpose with or without fee is hereby granted, provided that the above
-+ * copyright notice and this permission notice appear in all copies.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
-+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
-+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+ */
-+
-+#ifndef _LINUX_BRCMFMAC_PLATFORM_H
-+#define _LINUX_BRCMFMAC_PLATFORM_H
-+
-+
-+#define BRCMFMAC_PDATA_NAME "brcmfmac"
-+
-+#define BRCMFMAC_COUNTRY_BUF_SZ 4
-+
-+
-+/*
-+ * Platform specific driver functions and data. Through the platform specific
-+ * device data functions and data can be provided to help the brcmfmac driver to
-+ * operate with the device in combination with the used platform.
-+ */
-+
-+
-+/**
-+ * Note: the brcmfmac can be loaded as module or be statically built-in into
-+ * the kernel. If built-in then do note that it uses module_init (and
-+ * module_exit) routines which equal device_initcall. So if you intend to
-+ * create a module with the platform specific data for the brcmfmac and have
-+ * it built-in to the kernel then use a higher initcall then device_initcall
-+ * (see init.h). If this is not done then brcmfmac will load without problems
-+ * but will not pickup the platform data.
-+ *
-+ * When the driver does not "detect" platform driver data then it will continue
-+ * without reporting anything and just assume there is no data needed. Which is
-+ * probably true for most platforms.
-+ */
-+
-+/**
-+ * enum brcmf_bus_type - Bus type identifier. Currently SDIO, USB and PCIE are
-+ * supported.
-+ */
-+enum brcmf_bus_type {
-+ BRCMF_BUSTYPE_SDIO,
-+ BRCMF_BUSTYPE_USB,
-+ BRCMF_BUSTYPE_PCIE
-+};
-+
-+
-+/**
-+ * struct brcmfmac_sdio_pd - SDIO Device specific platform data.
-+ *
-+ * @txglomsz: SDIO txglom size. Use 0 if default of driver is to be
-+ * used.
-+ * @drive_strength: is the preferred drive_strength to be used for the SDIO
-+ * pins. If 0 then a default value will be used. This is
-+ * the target drive strength, the exact drive strength
-+ * which will be used depends on the capabilities of the
-+ * device.
-+ * @oob_irq_supported: does the board have support for OOB interrupts. SDIO
-+ * in-band interrupts are relatively slow and for having
-+ * less overhead on interrupt processing an out of band
-+ * interrupt can be used. If the HW supports this then
-+ * enable this by setting this field to true and configure
-+ * the oob related fields.
-+ * @oob_irq_nr,
-+ * @oob_irq_flags: the OOB interrupt information. The values are used for
-+ * registering the irq using request_irq function.
-+ * @broken_sg_support: flag for broken sg list support of SDIO host controller.
-+ * Set this to true if the SDIO host controller has higher
-+ * align requirement than 32 bytes for each scatterlist
-+ * item.
-+ * @sd_head_align: alignment requirement for start of data buffer.
-+ * @sd_sgentry_align: length alignment requirement for each sg entry.
-+ * @reset: This function can get called if the device communication
-+ * broke down. This functionality is particularly useful in
-+ * case of SDIO type devices. It is possible to reset a
-+ * dongle via sdio data interface, but it requires that
-+ * this is fully functional. This function is chip/module
-+ * specific and this function should return only after the
-+ * complete reset has completed.
-+ */
-+struct brcmfmac_sdio_pd {
-+ int txglomsz;
-+ unsigned int drive_strength;
-+ bool oob_irq_supported;
-+ unsigned int oob_irq_nr;
-+ unsigned long oob_irq_flags;
-+ bool broken_sg_support;
-+ unsigned short sd_head_align;
-+ unsigned short sd_sgentry_align;
-+ void (*reset)(void);
-+};
-+
-+/**
-+ * struct brcmfmac_pd_cc_entry - Struct for translating user space country code
-+ * (iso3166) to firmware country code and
-+ * revision.
-+ *
-+ * @iso3166: iso3166 alpha 2 country code string.
-+ * @cc: firmware country code string.
-+ * @rev: firmware country code revision.
-+ */
-+struct brcmfmac_pd_cc_entry {
-+ char iso3166[BRCMFMAC_COUNTRY_BUF_SZ];
-+ char cc[BRCMFMAC_COUNTRY_BUF_SZ];
-+ s32 rev;
-+};
-+
-+/**
-+ * struct brcmfmac_pd_cc - Struct for translating country codes as set by user
-+ * space to a country code and rev which can be used by
-+ * firmware.
-+ *
-+ * @table_size: number of entries in table (> 0)
-+ * @table: array of 1 or more elements with translation information.
-+ */
-+struct brcmfmac_pd_cc {
-+ int table_size;
-+ struct brcmfmac_pd_cc_entry table[0];
-+};
-+
-+/**
-+ * struct brcmfmac_pd_device - Device specific platform data. (id/rev/bus_type)
-+ * is the unique identifier of the device.
-+ *
-+ * @id: ID of the device for which this data is. In case of SDIO
-+ * or PCIE this is the chipid as identified by chip.c In
-+ * case of USB this is the chipid as identified by the
-+ * device query.
-+ * @rev: chip revision, see id.
-+ * @bus_type: The type of bus. Some chipid/rev exist for different bus
-+ * types. Each bus type has its own set of settings.
-+ * @feature_disable: Bitmask of features to disable (override), See feature.c
-+ * in brcmfmac for details.
-+ * @country_codes: If available, pointer to struct for translating country
-+ * codes.
-+ * @bus: Bus specific (union) device settings. Currently only
-+ * SDIO.
-+ */
-+struct brcmfmac_pd_device {
-+ unsigned int id;
-+ unsigned int rev;
-+ enum brcmf_bus_type bus_type;
-+ unsigned int feature_disable;
-+ struct brcmfmac_pd_cc *country_codes;
-+ union {
-+ struct brcmfmac_sdio_pd sdio;
-+ } bus;
-+};
-+
-+/**
-+ * struct brcmfmac_platform_data - BRCMFMAC specific platform data.
-+ *
-+ * @power_on: This function is called by the brcmfmac driver when the module
-+ * gets loaded. This can be particularly useful for low power
-+ * devices. The platform spcific routine may for example decide to
-+ * power up the complete device. If there is no use-case for this
-+ * function then provide NULL.
-+ * @power_off: This function is called by the brcmfmac when the module gets
-+ * unloaded. At this point the devices can be powered down or
-+ * otherwise be reset. So if an actual power_off is not supported
-+ * but reset is supported by the devices then reset the devices
-+ * when this function gets called. This can be particularly useful
-+ * for low power devices. If there is no use-case for this
-+ * function then provide NULL.
-+ */
-+struct brcmfmac_platform_data {
-+ void (*power_on)(void);
-+ void (*power_off)(void);
-+ char *fw_alternative_path;
-+ int device_count;
-+ struct brcmfmac_pd_device devices[0];
-+};
-+
-+
-+#endif /* _LINUX_BRCMFMAC_PLATFORM_H */
diff --git a/package/kernel/mac80211/patches/344-0018-brcmfmac-merge-platform-data-and-module-paramaters.patch b/package/kernel/mac80211/patches/344-0018-brcmfmac-merge-platform-data-and-module-paramaters.patch
deleted file mode 100644
index 34341d7f18..0000000000
--- a/package/kernel/mac80211/patches/344-0018-brcmfmac-merge-platform-data-and-module-paramaters.patch
+++ /dev/null
@@ -1,607 +0,0 @@
-From: Hante Meuleman <meuleman@broadcom.com>
-Date: Wed, 17 Feb 2016 11:27:08 +0100
-Subject: [PATCH] brcmfmac: merge platform data and module paramaters
-
-Merge module parameters and platform data in one struct. This is the
-last step to move to the new platform data per device. Now parameters
-of platform data will be merged with module parameters per device.
-
-Reviewed-by: Arend Van Spriel <arend@broadcom.com>
-Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
-Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
-@@ -109,8 +109,8 @@ int brcmf_sdiod_intr_register(struct brc
- u32 addr, gpiocontrol;
- unsigned long flags;
-
-- pdata = sdiodev->pdata;
-- if ((pdata) && (pdata->oob_irq_supported)) {
-+ pdata = &sdiodev->settings->bus.sdio;
-+ if (pdata->oob_irq_supported) {
- brcmf_dbg(SDIO, "Enter, register OOB IRQ %d\n",
- pdata->oob_irq_nr);
- ret = request_irq(pdata->oob_irq_nr, brcmf_sdiod_oob_irqhandler,
-@@ -177,8 +177,8 @@ int brcmf_sdiod_intr_unregister(struct b
-
- brcmf_dbg(SDIO, "Entering\n");
-
-- pdata = sdiodev->pdata;
-- if ((pdata) && (pdata->oob_irq_supported)) {
-+ pdata = &sdiodev->settings->bus.sdio;
-+ if (pdata->oob_irq_supported) {
- sdio_claim_host(sdiodev->func[1]);
- brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL);
- brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL);
-@@ -522,7 +522,7 @@ static int brcmf_sdiod_sglist_rw(struct
- target_list = pktlist;
- /* for host with broken sg support, prepare a page aligned list */
- __skb_queue_head_init(&local_list);
-- if (sdiodev->pdata && sdiodev->pdata->broken_sg_support && !write) {
-+ if (!write && sdiodev->settings->bus.sdio.broken_sg_support) {
- req_sz = 0;
- skb_queue_walk(pktlist, pkt_next)
- req_sz += pkt_next->len;
-@@ -629,7 +629,7 @@ static int brcmf_sdiod_sglist_rw(struct
- }
- }
-
-- if (sdiodev->pdata && sdiodev->pdata->broken_sg_support && !write) {
-+ if (!write && sdiodev->settings->bus.sdio.broken_sg_support) {
- local_pkt_next = local_list.next;
- orig_offset = 0;
- skb_queue_walk(pktlist, pkt_next) {
-@@ -900,7 +900,7 @@ void brcmf_sdiod_sgtable_alloc(struct br
- return;
-
- nents = max_t(uint, BRCMF_DEFAULT_RXGLOM_SIZE,
-- sdiodev->bus_if->drvr->settings->sdiod_txglomsz);
-+ sdiodev->settings->bus.sdio.txglomsz);
- nents += (nents >> 4) + 1;
-
- WARN_ON(nents > sdiodev->max_segment_count);
-@@ -912,7 +912,7 @@ void brcmf_sdiod_sgtable_alloc(struct br
- sdiodev->sg_support = false;
- }
-
-- sdiodev->txglomsz = sdiodev->bus_if->drvr->settings->sdiod_txglomsz;
-+ sdiodev->txglomsz = sdiodev->settings->bus.sdio.txglomsz;
- }
-
- #ifdef CONFIG_PM_SLEEP
-@@ -1246,8 +1246,8 @@ static int brcmf_ops_sdio_suspend(struct
-
- sdio_flags = MMC_PM_KEEP_POWER;
- if (sdiodev->wowl_enabled) {
-- if (sdiodev->pdata->oob_irq_supported)
-- enable_irq_wake(sdiodev->pdata->oob_irq_nr);
-+ if (sdiodev->settings->bus.sdio.oob_irq_supported)
-+ enable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr);
- else
- sdio_flags |= MMC_PM_WAKE_SDIO_IRQ;
- }
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
-@@ -43,6 +43,8 @@ enum brcmf_bus_protocol_type {
- BRCMF_PROTO_MSGBUF
- };
-
-+struct brcmf_mp_device;
-+
- struct brcmf_bus_dcmd {
- char *name;
- char *param;
-@@ -217,7 +219,7 @@ bool brcmf_c_prec_enq(struct device *dev
- void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp);
-
- /* Indication from bus module regarding presence/insertion of dongle. */
--int brcmf_attach(struct device *dev);
-+int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings);
- /* Indication from bus module regarding removal/absence of dongle */
- void brcmf_detach(struct device *dev);
- /* Indication from bus module that dongle should be reset */
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
-@@ -243,14 +243,35 @@ static void brcmf_mp_attach(void)
- }
- }
-
--struct brcmfmac_sdio_pd *brcmf_get_module_param(struct device *dev,
-- enum brcmf_bus_type bus_type,
-- u32 chip, u32 chiprev)
-+struct brcmf_mp_device *brcmf_get_module_param(struct device *dev,
-+ enum brcmf_bus_type bus_type,
-+ u32 chip, u32 chiprev)
- {
-- struct brcmfmac_sdio_pd *pdata;
-+ struct brcmf_mp_device *settings;
- struct brcmfmac_pd_device *device_pd;
-+ bool found;
- int i;
-
-+ brcmf_dbg(INFO, "Enter, bus=%d, chip=%d, rev=%d\n", bus_type, chip,
-+ chiprev);
-+ settings = kzalloc(sizeof(*settings), GFP_ATOMIC);
-+ if (!settings)
-+ return NULL;
-+
-+ /* start by using the module paramaters */
-+ settings->p2p_enable = !!brcmf_p2p_enable;
-+ settings->feature_disable = brcmf_feature_disable;
-+ settings->fcmode = brcmf_fcmode;
-+ settings->roamoff = !!brcmf_roamoff;
-+#ifdef DEBUG
-+ settings->ignore_probe_fail = !!brcmf_ignore_probe_fail;
-+#endif
-+
-+ if (bus_type == BRCMF_BUSTYPE_SDIO)
-+ settings->bus.sdio.txglomsz = brcmf_sdiod_txglomsz;
-+
-+ /* See if there is any device specific platform data configured */
-+ found = false;
- if (brcmfmac_pdata) {
- for (i = 0; i < brcmfmac_pdata->device_count; i++) {
- device_pd = &brcmfmac_pdata->devices[i];
-@@ -259,38 +280,29 @@ struct brcmfmac_sdio_pd *brcmf_get_modul
- ((device_pd->rev == chiprev) ||
- (device_pd->rev == -1))) {
- brcmf_dbg(INFO, "Platform data for device found\n");
-+ settings->country_codes =
-+ device_pd->country_codes;
- if (device_pd->bus_type == BRCMF_BUSTYPE_SDIO)
-- return &device_pd->bus.sdio;
-+ memcpy(&settings->bus.sdio,
-+ &device_pd->bus.sdio,
-+ sizeof(settings->bus.sdio));
-+ found = true;
- break;
- }
- }
- }
-- pdata = NULL;
-- brcmf_of_probe(dev, &pdata);
--
-- return pdata;
--}
--
--int brcmf_mp_device_attach(struct brcmf_pub *drvr)
--{
-- drvr->settings = kzalloc(sizeof(*drvr->settings), GFP_ATOMIC);
-- if (!drvr->settings)
-- return -ENOMEM;
--
-- drvr->settings->sdiod_txglomsz = brcmf_sdiod_txglomsz;
-- drvr->settings->p2p_enable = !!brcmf_p2p_enable;
-- drvr->settings->feature_disable = brcmf_feature_disable;
-- drvr->settings->fcmode = brcmf_fcmode;
-- drvr->settings->roamoff = !!brcmf_roamoff;
--#ifdef DEBUG
-- drvr->settings->ignore_probe_fail = !!brcmf_ignore_probe_fail;
--#endif
-- return 0;
-+ if ((bus_type == BRCMF_BUSTYPE_SDIO) && (!found)) {
-+ /* No platform data for this device. In case of SDIO try OF
-+ * (Open Firwmare) Device Tree.
-+ */
-+ brcmf_of_probe(dev, &settings->bus.sdio);
-+ }
-+ return settings;
- }
-
--void brcmf_mp_device_detach(struct brcmf_pub *drvr)
-+void brcmf_release_module_param(struct brcmf_mp_device *module_param)
- {
-- kfree(drvr->settings);
-+ kfree(module_param);
- }
-
- static int __init brcmf_common_pd_probe(struct platform_device *pdev)
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
-@@ -45,41 +45,30 @@ extern struct brcmf_mp_global_t brcmf_mp
- /**
- * struct brcmf_mp_device - Device module paramaters.
- *
-- * @sdiod_txglomsz: SDIO txglom size.
-- * @joinboost_5g_rssi: 5g rssi booost for preferred join selection.
- * @p2p_enable: Legacy P2P0 enable (old wpa_supplicant).
- * @feature_disable: Feature_disable bitmask.
- * @fcmode: FWS flow control.
- * @roamoff: Firmware roaming off?
-+ * @ignore_probe_fail: Ignore probe failure.
- * @country_codes: If available, pointer to struct for translating country codes
-+ * @bus: Bus specific platform data. Only SDIO at the mmoment.
- */
- struct brcmf_mp_device {
-- int sdiod_txglomsz;
-- int joinboost_5g_rssi;
-- bool p2p_enable;
-- int feature_disable;
-- int fcmode;
-- bool roamoff;
-- bool ignore_probe_fail;
-+ bool p2p_enable;
-+ unsigned int feature_disable;
-+ int fcmode;
-+ bool roamoff;
-+ bool ignore_probe_fail;
- struct brcmfmac_pd_cc *country_codes;
-+ union {
-+ struct brcmfmac_sdio_pd sdio;
-+ } bus;
- };
-
--struct brcmfmac_sdio_pd *brcmf_get_module_param(struct device *dev,
-- enum brcmf_bus_type bus_type,
-- u32 chip, u32 chiprev);
--int brcmf_mp_device_attach(struct brcmf_pub *drvr);
--void brcmf_mp_device_detach(struct brcmf_pub *drvr);
--#ifdef DEBUG
--static inline bool brcmf_ignoring_probe_fail(struct brcmf_pub *drvr)
--{
-- return drvr->settings->ignore_probe_fail;
--}
--#else
--static inline bool brcmf_ignoring_probe_fail(struct brcmf_pub *drvr)
--{
-- return false;
--}
--#endif
-+struct brcmf_mp_device *brcmf_get_module_param(struct device *dev,
-+ enum brcmf_bus_type bus_type,
-+ u32 chip, u32 chiprev);
-+void brcmf_release_module_param(struct brcmf_mp_device *module_param);
-
- /* Sets dongle media info (drv_version, mac address). */
- int brcmf_c_preinit_dcmds(struct brcmf_if *ifp);
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
-@@ -1104,7 +1104,7 @@ static int brcmf_inet6addr_changed(struc
- }
- #endif
-
--int brcmf_attach(struct device *dev)
-+int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings)
- {
- struct brcmf_pub *drvr = NULL;
- int ret = 0;
-@@ -1126,10 +1126,7 @@ int brcmf_attach(struct device *dev)
- drvr->hdrlen = 0;
- drvr->bus_if = dev_get_drvdata(dev);
- drvr->bus_if->drvr = drvr;
--
-- /* Initialize device specific settings */
-- if (brcmf_mp_device_attach(drvr))
-- goto fail;
-+ drvr->settings = settings;
-
- /* attach debug facilities */
- brcmf_debug_attach(drvr);
-@@ -1274,7 +1271,7 @@ fail:
- brcmf_net_detach(p2p_ifp->ndev);
- drvr->iflist[0] = NULL;
- drvr->iflist[1] = NULL;
-- if (brcmf_ignoring_probe_fail(drvr))
-+ if (drvr->settings->ignore_probe_fail)
- ret = 0;
-
- return ret;
-@@ -1350,8 +1347,6 @@ void brcmf_detach(struct device *dev)
-
- brcmf_proto_detach(drvr);
-
-- brcmf_mp_device_detach(drvr);
--
- brcmf_debug_detach(drvr);
- bus_if->drvr = NULL;
- kfree(drvr);
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
-@@ -23,7 +23,7 @@
- #include "common.h"
- #include "of.h"
-
--void brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd **sdio)
-+void brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd *sdio)
- {
- struct device_node *np = dev->of_node;
- int irq;
-@@ -33,12 +33,8 @@ void brcmf_of_probe(struct device *dev,
- if (!np || !of_device_is_compatible(np, "brcm,bcm4329-fmac"))
- return;
-
-- *sdio = devm_kzalloc(dev, sizeof(*sdio), GFP_KERNEL);
-- if (!(*sdio))
-- return;
--
- if (of_property_read_u32(np, "brcm,drive-strength", &val) == 0)
-- (*sdio)->drive_strength = val;
-+ sdio->drive_strength = val;
-
- /* make sure there are interrupts defined in the node */
- if (!of_find_property(np, "interrupts", NULL))
-@@ -51,7 +47,7 @@ void brcmf_of_probe(struct device *dev,
- }
- irqf = irqd_get_trigger_type(irq_get_irq_data(irq));
-
-- (*sdio)->oob_irq_supported = true;
-- (*sdio)->oob_irq_nr = irq;
-- (*sdio)->oob_irq_flags = irqf;
-+ sdio->oob_irq_supported = true;
-+ sdio->oob_irq_nr = irq;
-+ sdio->oob_irq_flags = irqf;
- }
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h
-@@ -14,10 +14,9 @@
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- #ifdef CONFIG_OF
--void
--brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd **sdio);
-+void brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd *sdio);
- #else
--static void brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd **sdio)
-+static void brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd *sdio)
- {
- }
- #endif /* CONFIG_OF */
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
-@@ -37,6 +37,8 @@
- #include "pcie.h"
- #include "firmware.h"
- #include "chip.h"
-+#include "core.h"
-+#include "common.h"
-
-
- enum brcmf_pcie_state {
-@@ -266,6 +268,7 @@ struct brcmf_pciedev_info {
- u16 (*read_ptr)(struct brcmf_pciedev_info *devinfo, u32 mem_offset);
- void (*write_ptr)(struct brcmf_pciedev_info *devinfo, u32 mem_offset,
- u16 value);
-+ struct brcmf_mp_device *settings;
- };
-
- struct brcmf_pcie_ringbuf {
-@@ -1525,16 +1528,16 @@ static void brcmf_pcie_release_resource(
- }
-
-
--static int brcmf_pcie_attach_bus(struct device *dev)
-+static int brcmf_pcie_attach_bus(struct brcmf_pciedev_info *devinfo)
- {
- int ret;
-
- /* Attach to the common driver interface */
-- ret = brcmf_attach(dev);
-+ ret = brcmf_attach(&devinfo->pdev->dev, devinfo->settings);
- if (ret) {
- brcmf_err("brcmf_attach failed\n");
- } else {
-- ret = brcmf_bus_start(dev);
-+ ret = brcmf_bus_start(&devinfo->pdev->dev);
- if (ret)
- brcmf_err("dongle is not responding\n");
- }
-@@ -1672,7 +1675,7 @@ static void brcmf_pcie_setup(struct devi
- init_waitqueue_head(&devinfo->mbdata_resp_wait);
-
- brcmf_pcie_intr_enable(devinfo);
-- if (brcmf_pcie_attach_bus(bus->dev) == 0)
-+ if (brcmf_pcie_attach_bus(devinfo) == 0)
- return;
-
- brcmf_pcie_bus_console_read(devinfo);
-@@ -1716,6 +1719,15 @@ brcmf_pcie_probe(struct pci_dev *pdev, c
- goto fail;
- }
-
-+ devinfo->settings = brcmf_get_module_param(&devinfo->pdev->dev,
-+ BRCMF_BUSTYPE_PCIE,
-+ devinfo->ci->chip,
-+ devinfo->ci->chiprev);
-+ if (!devinfo->settings) {
-+ ret = -ENOMEM;
-+ goto fail;
-+ }
-+
- bus = kzalloc(sizeof(*bus), GFP_KERNEL);
- if (!bus) {
- ret = -ENOMEM;
-@@ -1760,6 +1772,8 @@ fail:
- brcmf_pcie_release_resource(devinfo);
- if (devinfo->ci)
- brcmf_chip_detach(devinfo->ci);
-+ if (devinfo->settings)
-+ brcmf_release_module_param(devinfo->settings);
- kfree(pcie_bus_dev);
- kfree(devinfo);
- return ret;
-@@ -1799,6 +1813,8 @@ brcmf_pcie_remove(struct pci_dev *pdev)
-
- if (devinfo->ci)
- brcmf_chip_detach(devinfo->ci);
-+ if (devinfo->settings)
-+ brcmf_release_module_param(devinfo->settings);
-
- kfree(devinfo);
- dev_set_drvdata(&pdev->dev, NULL);
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
-@@ -2442,15 +2442,17 @@ static void brcmf_sdio_bus_stop(struct d
-
- static inline void brcmf_sdio_clrintr(struct brcmf_sdio *bus)
- {
-+ struct brcmf_sdio_dev *sdiodev;
- unsigned long flags;
-
-- if (bus->sdiodev->oob_irq_requested) {
-- spin_lock_irqsave(&bus->sdiodev->irq_en_lock, flags);
-- if (!bus->sdiodev->irq_en && !atomic_read(&bus->ipend)) {
-- enable_irq(bus->sdiodev->pdata->oob_irq_nr);
-- bus->sdiodev->irq_en = true;
-+ sdiodev = bus->sdiodev;
-+ if (sdiodev->oob_irq_requested) {
-+ spin_lock_irqsave(&sdiodev->irq_en_lock, flags);
-+ if (!sdiodev->irq_en && !atomic_read(&bus->ipend)) {
-+ enable_irq(sdiodev->settings->bus.sdio.oob_irq_nr);
-+ sdiodev->irq_en = true;
- }
-- spin_unlock_irqrestore(&bus->sdiodev->irq_en_lock, flags);
-+ spin_unlock_irqrestore(&sdiodev->irq_en_lock, flags);
- }
- }
-
-@@ -3394,9 +3396,7 @@ static int brcmf_sdio_bus_preinit(struct
- sizeof(u32));
- } else {
- /* otherwise, set txglomalign */
-- value = 4;
-- if (sdiodev->pdata)
-- value = sdiodev->pdata->sd_sgentry_align;
-+ value = sdiodev->settings->bus.sdio.sd_sgentry_align;
- /* SDIO ADMA requires at least 32 bit alignment */
- value = max_t(u32, value, 4);
- err = brcmf_iovar_data_set(dev, "bus:txglomalign", &value,
-@@ -3811,21 +3811,25 @@ brcmf_sdio_probe_attach(struct brcmf_sdi
- bus->ci = NULL;
- goto fail;
- }
-- sdiodev->pdata = brcmf_get_module_param(sdiodev->dev,
-+ sdiodev->settings = brcmf_get_module_param(sdiodev->dev,
- BRCMF_BUSTYPE_SDIO,
- bus->ci->chip,
- bus->ci->chiprev);
-+ if (!sdiodev->settings) {
-+ brcmf_err("Failed to get device parameters\n");
-+ goto fail;
-+ }
- /* platform specific configuration:
- * alignments must be at least 4 bytes for ADMA
- */
- bus->head_align = ALIGNMENT;
- bus->sgentry_align = ALIGNMENT;
-- if (sdiodev->pdata) {
-- if (sdiodev->pdata->sd_head_align > ALIGNMENT)
-- bus->head_align = sdiodev->pdata->sd_head_align;
-- if (sdiodev->pdata->sd_sgentry_align > ALIGNMENT)
-- bus->sgentry_align = sdiodev->pdata->sd_sgentry_align;
-- }
-+ if (sdiodev->settings->bus.sdio.sd_head_align > ALIGNMENT)
-+ bus->head_align = sdiodev->settings->bus.sdio.sd_head_align;
-+ if (sdiodev->settings->bus.sdio.sd_sgentry_align > ALIGNMENT)
-+ bus->sgentry_align =
-+ sdiodev->settings->bus.sdio.sd_sgentry_align;
-+
- /* allocate scatter-gather table. sg support
- * will be disabled upon allocation failure.
- */
-@@ -3837,7 +3841,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdi
- */
- if ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_KEEP_POWER) &&
- ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_WAKE_SDIO_IRQ) ||
-- (sdiodev->pdata && sdiodev->pdata->oob_irq_supported)))
-+ (sdiodev->settings->bus.sdio.oob_irq_supported)))
- sdiodev->bus_if->wowl_supported = true;
- #endif
-
-@@ -3846,8 +3850,8 @@ brcmf_sdio_probe_attach(struct brcmf_sdi
- goto fail;
- }
-
-- if ((sdiodev->pdata) && (sdiodev->pdata->drive_strength))
-- drivestrength = sdiodev->pdata->drive_strength;
-+ if (sdiodev->settings->bus.sdio.drive_strength)
-+ drivestrength = sdiodev->settings->bus.sdio.drive_strength;
- else
- drivestrength = DEFAULT_SDIO_DRIVE_STRENGTH;
- brcmf_sdio_drivestrengthinit(sdiodev, bus->ci, drivestrength);
-@@ -4124,7 +4128,7 @@ struct brcmf_sdio *brcmf_sdio_probe(stru
- bus->tx_hdrlen = SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN;
-
- /* Attach to the common layer, reserve hdr space */
-- ret = brcmf_attach(bus->sdiodev->dev);
-+ ret = brcmf_attach(bus->sdiodev->dev, bus->sdiodev->settings);
- if (ret != 0) {
- brcmf_err("brcmf_attach failed\n");
- goto fail;
-@@ -4228,6 +4232,8 @@ void brcmf_sdio_remove(struct brcmf_sdio
- }
- brcmf_chip_detach(bus->ci);
- }
-+ if (bus->sdiodev->settings)
-+ brcmf_release_module_param(bus->sdiodev->settings);
-
- kfree(bus->rxbuf);
- kfree(bus->hdrbuf);
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
-@@ -184,7 +184,7 @@ struct brcmf_sdio_dev {
- struct brcmf_sdio *bus;
- struct device *dev;
- struct brcmf_bus *bus_if;
-- struct brcmfmac_sdio_pd *pdata;
-+ struct brcmf_mp_device *settings;
- bool oob_irq_requested;
- bool irq_en; /* irq enable flags */
- spinlock_t irq_en_lock;
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
-@@ -27,6 +27,8 @@
- #include "debug.h"
- #include "firmware.h"
- #include "usb.h"
-+#include "core.h"
-+#include "common.h"
-
-
- #define IOCTL_RESP_TIMEOUT msecs_to_jiffies(2000)
-@@ -171,6 +173,7 @@ struct brcmf_usbdev_info {
- struct urb *bulk_urb; /* used for FW download */
-
- bool wowl_enabled;
-+ struct brcmf_mp_device *settings;
- };
-
- static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo,
-@@ -1027,6 +1030,9 @@ static void brcmf_usb_detach(struct brcm
-
- kfree(devinfo->tx_reqs);
- kfree(devinfo->rx_reqs);
-+
-+ if (devinfo->settings)
-+ brcmf_release_module_param(devinfo->settings);
- }
-
-
-@@ -1136,7 +1142,7 @@ static int brcmf_usb_bus_setup(struct br
- int ret;
-
- /* Attach to the common driver interface */
-- ret = brcmf_attach(devinfo->dev);
-+ ret = brcmf_attach(devinfo->dev, devinfo->settings);
- if (ret) {
- brcmf_err("brcmf_attach failed\n");
- return ret;
-@@ -1223,6 +1229,14 @@ static int brcmf_usb_probe_cb(struct brc
- bus->wowl_supported = true;
- #endif
-
-+ devinfo->settings = brcmf_get_module_param(bus->dev, BRCMF_BUSTYPE_USB,
-+ bus_pub->devid,
-+ bus_pub->chiprev);
-+ if (!devinfo->settings) {
-+ ret = -ENOMEM;
-+ goto fail;
-+ }
-+
- if (!brcmf_usb_dlneeded(devinfo)) {
- ret = brcmf_usb_bus_setup(devinfo);
- if (ret)
diff --git a/package/kernel/mac80211/patches/344-0019-brcmfmac-integrate-add_keyext-in-add_key.patch b/package/kernel/mac80211/patches/344-0019-brcmfmac-integrate-add_keyext-in-add_key.patch
deleted file mode 100644
index eb680fccfc..0000000000
--- a/package/kernel/mac80211/patches/344-0019-brcmfmac-integrate-add_keyext-in-add_key.patch
+++ /dev/null
@@ -1,227 +0,0 @@
-From: Hante Meuleman <hante.meuleman@broadcom.com>
-Date: Wed, 17 Feb 2016 11:27:09 +0100
-Subject: [PATCH] brcmfmac: integrate add_keyext in add_key
-
-brcmf_add_keyext is called when a key is configured for a specific
-mac address. This function is very similar to the calling function
-brcmf_add_key. Integrate this function and also use existing del_key
-function in case key is to be cleared.
-
-Reviewed-by: Arend Van Spriel <arend.van@broadcom.com>
-Reviewed-by: Franky (Zhenhui) Lin <franky.lin@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
-Signed-off-by: Hante Meuleman <hante.meuleman@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -2073,84 +2073,34 @@ done:
- }
-
- static s32
--brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
-- u8 key_idx, const u8 *mac_addr, struct key_params *params)
-+brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
-+ u8 key_idx, bool pairwise, const u8 *mac_addr)
- {
- struct brcmf_if *ifp = netdev_priv(ndev);
- struct brcmf_wsec_key key;
- s32 err = 0;
-- u8 keybuf[8];
-+
-+ brcmf_dbg(TRACE, "Enter\n");
-+ if (!check_vif_up(ifp->vif))
-+ return -EIO;
-+
-+ if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
-+ /* we ignore this key index in this case */
-+ return -EINVAL;
-+ }
-
- memset(&key, 0, sizeof(key));
-- key.index = (u32) key_idx;
-- /* Instead of bcast for ea address for default wep keys,
-- driver needs it to be Null */
-- if (!is_multicast_ether_addr(mac_addr))
-- memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN);
-- key.len = (u32) params->key_len;
-- /* check for key index change */
-- if (key.len == 0) {
-- /* key delete */
-- err = send_key_to_dongle(ifp, &key);
-- if (err)
-- brcmf_err("key delete error (%d)\n", err);
-- } else {
-- if (key.len > sizeof(key.data)) {
-- brcmf_err("Invalid key length (%d)\n", key.len);
-- return -EINVAL;
-- }
-
-- brcmf_dbg(CONN, "Setting the key index %d\n", key.index);
-- memcpy(key.data, params->key, key.len);
-+ key.index = (u32)key_idx;
-+ key.flags = BRCMF_PRIMARY_KEY;
-+ key.algo = CRYPTO_ALGO_OFF;
-
-- if (!brcmf_is_apmode(ifp->vif) &&
-- (params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
-- brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
-- memcpy(keybuf, &key.data[24], sizeof(keybuf));
-- memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
-- memcpy(&key.data[16], keybuf, sizeof(keybuf));
-- }
-+ brcmf_dbg(CONN, "key index (%d)\n", key_idx);
-
-- /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
-- if (params->seq && params->seq_len == 6) {
-- /* rx iv */
-- u8 *ivptr;
-- ivptr = (u8 *) params->seq;
-- key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
-- (ivptr[3] << 8) | ivptr[2];
-- key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
-- key.iv_initialized = true;
-- }
-+ /* Set the new key/index */
-+ err = send_key_to_dongle(ifp, &key);
-
-- switch (params->cipher) {
-- case WLAN_CIPHER_SUITE_WEP40:
-- key.algo = CRYPTO_ALGO_WEP1;
-- brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
-- break;
-- case WLAN_CIPHER_SUITE_WEP104:
-- key.algo = CRYPTO_ALGO_WEP128;
-- brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
-- break;
-- case WLAN_CIPHER_SUITE_TKIP:
-- key.algo = CRYPTO_ALGO_TKIP;
-- brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
-- break;
-- case WLAN_CIPHER_SUITE_AES_CMAC:
-- key.algo = CRYPTO_ALGO_AES_CCM;
-- brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
-- break;
-- case WLAN_CIPHER_SUITE_CCMP:
-- key.algo = CRYPTO_ALGO_AES_CCM;
-- brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
-- break;
-- default:
-- brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
-- return -EINVAL;
-- }
-- err = send_key_to_dongle(ifp, &key);
-- if (err)
-- brcmf_err("wsec_key error (%d)\n", err);
-- }
-+ brcmf_dbg(TRACE, "Exit\n");
- return err;
- }
-
-@@ -2163,8 +2113,9 @@ brcmf_cfg80211_add_key(struct wiphy *wip
- struct brcmf_wsec_key *key;
- s32 val;
- s32 wsec;
-- s32 err = 0;
-+ s32 err;
- u8 keybuf[8];
-+ bool ext_key;
-
- brcmf_dbg(TRACE, "Enter\n");
- brcmf_dbg(CONN, "key index (%d)\n", key_idx);
-@@ -2177,27 +2128,32 @@ brcmf_cfg80211_add_key(struct wiphy *wip
- return -EINVAL;
- }
-
-- if (mac_addr &&
-- (params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
-- (params->cipher != WLAN_CIPHER_SUITE_WEP104)) {
-- brcmf_dbg(TRACE, "Exit");
-- return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params);
-- }
--
-- key = &ifp->vif->profile.key[key_idx];
-- memset(key, 0, sizeof(*key));
-+ if (params->key_len == 0)
-+ return brcmf_cfg80211_del_key(wiphy, ndev, key_idx, pairwise,
-+ mac_addr);
-
- if (params->key_len > sizeof(key->data)) {
- brcmf_err("Too long key length (%u)\n", params->key_len);
-- err = -EINVAL;
-- goto done;
-+ return -EINVAL;
-+ }
-+
-+ ext_key = false;
-+ if (mac_addr && (params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
-+ (params->cipher != WLAN_CIPHER_SUITE_WEP104)) {
-+ brcmf_dbg(TRACE, "Ext key, mac %pM", mac_addr);
-+ ext_key = true;
- }
-+
-+ key = &ifp->vif->profile.key[key_idx];
-+ memset(key, 0, sizeof(*key));
-+ if ((ext_key) && (!is_multicast_ether_addr(mac_addr)))
-+ memcpy((char *)&key->ea, (void *)mac_addr, ETH_ALEN);
- key->len = params->key_len;
- key->index = key_idx;
--
- memcpy(key->data, params->key, key->len);
-+ if (!ext_key)
-+ key->flags = BRCMF_PRIMARY_KEY;
-
-- key->flags = BRCMF_PRIMARY_KEY;
- switch (params->cipher) {
- case WLAN_CIPHER_SUITE_WEP40:
- key->algo = CRYPTO_ALGO_WEP1;
-@@ -2237,7 +2193,7 @@ brcmf_cfg80211_add_key(struct wiphy *wip
- }
-
- err = send_key_to_dongle(ifp, key);
-- if (err)
-+ if (ext_key || err)
- goto done;
-
- err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
-@@ -2256,38 +2212,6 @@ done:
- brcmf_dbg(TRACE, "Exit\n");
- return err;
- }
--
--static s32
--brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
-- u8 key_idx, bool pairwise, const u8 *mac_addr)
--{
-- struct brcmf_if *ifp = netdev_priv(ndev);
-- struct brcmf_wsec_key key;
-- s32 err = 0;
--
-- brcmf_dbg(TRACE, "Enter\n");
-- if (!check_vif_up(ifp->vif))
-- return -EIO;
--
-- if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
-- /* we ignore this key index in this case */
-- return -EINVAL;
-- }
--
-- memset(&key, 0, sizeof(key));
--
-- key.index = (u32) key_idx;
-- key.flags = BRCMF_PRIMARY_KEY;
-- key.algo = CRYPTO_ALGO_OFF;
--
-- brcmf_dbg(CONN, "key index (%d)\n", key_idx);
--
-- /* Set the new key/index */
-- err = send_key_to_dongle(ifp, &key);
--
-- brcmf_dbg(TRACE, "Exit\n");
-- return err;
--}
-
- static s32
- brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
diff --git a/package/kernel/mac80211/patches/344-0020-brcmfmac-add-802.11w-management-frame-protection-sup.patch b/package/kernel/mac80211/patches/344-0020-brcmfmac-add-802.11w-management-frame-protection-sup.patch
deleted file mode 100644
index c20d40c049..0000000000
--- a/package/kernel/mac80211/patches/344-0020-brcmfmac-add-802.11w-management-frame-protection-sup.patch
+++ /dev/null
@@ -1,509 +0,0 @@
-From: Hante Meuleman <hante.meuleman@broadcom.com>
-Date: Wed, 17 Feb 2016 11:27:10 +0100
-Subject: [PATCH] brcmfmac: add 802.11w management frame protection support
-
-Add full support for both AP and STA for management frame protection.
-
-Reviewed-by: Arend Van Spriel <arend.van@broadcom.com>
-Reviewed-by: Franky (Zhenhui) Lin <franky.lin@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
-Signed-off-by: Hante Meuleman <hante.meuleman@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -72,8 +72,13 @@
- #define RSN_AKM_NONE 0 /* None (IBSS) */
- #define RSN_AKM_UNSPECIFIED 1 /* Over 802.1x */
- #define RSN_AKM_PSK 2 /* Pre-shared Key */
-+#define RSN_AKM_SHA256_1X 5 /* SHA256, 802.1X */
-+#define RSN_AKM_SHA256_PSK 6 /* SHA256, Pre-shared Key */
- #define RSN_CAP_LEN 2 /* Length of RSN capabilities */
--#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C
-+#define RSN_CAP_PTK_REPLAY_CNTR_MASK (BIT(2) | BIT(3))
-+#define RSN_CAP_MFPR_MASK BIT(6)
-+#define RSN_CAP_MFPC_MASK BIT(7)
-+#define RSN_PMKID_COUNT_LEN 2
-
- #define VNDR_IE_CMD_LEN 4 /* length of the set command
- * string :"add", "del" (+ NUL)
-@@ -211,12 +216,19 @@ static const struct ieee80211_regdomain
- REG_RULE(5470-10, 5850+10, 80, 6, 20, 0), }
- };
-
--static const u32 __wl_cipher_suites[] = {
-+/* Note: brcmf_cipher_suites is an array of int defining which cipher suites
-+ * are supported. A pointer to this array and the number of entries is passed
-+ * on to upper layers. AES_CMAC defines whether or not the driver supports MFP.
-+ * So the cipher suite AES_CMAC has to be the last one in the array, and when
-+ * device does not support MFP then the number of suites will be decreased by 1
-+ */
-+static const u32 brcmf_cipher_suites[] = {
- WLAN_CIPHER_SUITE_WEP40,
- WLAN_CIPHER_SUITE_WEP104,
- WLAN_CIPHER_SUITE_TKIP,
- WLAN_CIPHER_SUITE_CCMP,
-- WLAN_CIPHER_SUITE_AES_CMAC,
-+ /* Keep as last entry: */
-+ WLAN_CIPHER_SUITE_AES_CMAC
- };
-
- /* Vendor specific ie. id = 221, oui and type defines exact ie */
-@@ -1533,7 +1545,7 @@ static s32 brcmf_set_auth_type(struct ne
-
- static s32
- brcmf_set_wsec_mode(struct net_device *ndev,
-- struct cfg80211_connect_params *sme, bool mfp)
-+ struct cfg80211_connect_params *sme)
- {
- struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
- struct brcmf_cfg80211_security *sec;
-@@ -1592,10 +1604,7 @@ brcmf_set_wsec_mode(struct net_device *n
- sme->privacy)
- pval = AES_ENABLED;
-
-- if (mfp)
-- wsec = pval | gval | MFP_CAPABLE;
-- else
-- wsec = pval | gval;
-+ wsec = pval | gval;
- err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", wsec);
- if (err) {
- brcmf_err("error (%d)\n", err);
-@@ -1612,56 +1621,100 @@ brcmf_set_wsec_mode(struct net_device *n
- static s32
- brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
- {
-- struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
-- struct brcmf_cfg80211_security *sec;
-- s32 val = 0;
-- s32 err = 0;
-+ struct brcmf_if *ifp = netdev_priv(ndev);
-+ s32 val;
-+ s32 err;
-+ const struct brcmf_tlv *rsn_ie;
-+ const u8 *ie;
-+ u32 ie_len;
-+ u32 offset;
-+ u16 rsn_cap;
-+ u32 mfp;
-+ u16 count;
-
-- if (sme->crypto.n_akm_suites) {
-- err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev),
-- "wpa_auth", &val);
-- if (err) {
-- brcmf_err("could not get wpa_auth (%d)\n", err);
-- return err;
-+ if (!sme->crypto.n_akm_suites)
-+ return 0;
-+
-+ err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev), "wpa_auth", &val);
-+ if (err) {
-+ brcmf_err("could not get wpa_auth (%d)\n", err);
-+ return err;
-+ }
-+ if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
-+ switch (sme->crypto.akm_suites[0]) {
-+ case WLAN_AKM_SUITE_8021X:
-+ val = WPA_AUTH_UNSPECIFIED;
-+ break;
-+ case WLAN_AKM_SUITE_PSK:
-+ val = WPA_AUTH_PSK;
-+ break;
-+ default:
-+ brcmf_err("invalid cipher group (%d)\n",
-+ sme->crypto.cipher_group);
-+ return -EINVAL;
- }
-- if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
-- switch (sme->crypto.akm_suites[0]) {
-- case WLAN_AKM_SUITE_8021X:
-- val = WPA_AUTH_UNSPECIFIED;
-- break;
-- case WLAN_AKM_SUITE_PSK:
-- val = WPA_AUTH_PSK;
-- break;
-- default:
-- brcmf_err("invalid cipher group (%d)\n",
-- sme->crypto.cipher_group);
-- return -EINVAL;
-- }
-- } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
-- switch (sme->crypto.akm_suites[0]) {
-- case WLAN_AKM_SUITE_8021X:
-- val = WPA2_AUTH_UNSPECIFIED;
-- break;
-- case WLAN_AKM_SUITE_PSK:
-- val = WPA2_AUTH_PSK;
-- break;
-- default:
-- brcmf_err("invalid cipher group (%d)\n",
-- sme->crypto.cipher_group);
-- return -EINVAL;
-- }
-+ } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
-+ switch (sme->crypto.akm_suites[0]) {
-+ case WLAN_AKM_SUITE_8021X:
-+ val = WPA2_AUTH_UNSPECIFIED;
-+ break;
-+ case WLAN_AKM_SUITE_8021X_SHA256:
-+ val = WPA2_AUTH_1X_SHA256;
-+ break;
-+ case WLAN_AKM_SUITE_PSK_SHA256:
-+ val = WPA2_AUTH_PSK_SHA256;
-+ break;
-+ case WLAN_AKM_SUITE_PSK:
-+ val = WPA2_AUTH_PSK;
-+ break;
-+ default:
-+ brcmf_err("invalid cipher group (%d)\n",
-+ sme->crypto.cipher_group);
-+ return -EINVAL;
- }
-+ }
-
-- brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
-- err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev),
-- "wpa_auth", val);
-- if (err) {
-- brcmf_err("could not set wpa_auth (%d)\n", err);
-- return err;
-- }
-+ if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
-+ goto skip_mfp_config;
-+ /* The MFP mode (1 or 2) needs to be determined, parse IEs. The
-+ * IE will not be verified, just a quick search for MFP config
-+ */
-+ rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie, sme->ie_len,
-+ WLAN_EID_RSN);
-+ if (!rsn_ie)
-+ goto skip_mfp_config;
-+ ie = (const u8 *)rsn_ie;
-+ ie_len = rsn_ie->len + TLV_HDR_LEN;
-+ /* Skip unicast suite */
-+ offset = TLV_HDR_LEN + WPA_IE_VERSION_LEN + WPA_IE_MIN_OUI_LEN;
-+ if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
-+ goto skip_mfp_config;
-+ /* Skip multicast suite */
-+ count = ie[offset] + (ie[offset + 1] << 8);
-+ offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN);
-+ if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
-+ goto skip_mfp_config;
-+ /* Skip auth key management suite(s) */
-+ count = ie[offset] + (ie[offset + 1] << 8);
-+ offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN);
-+ if (offset + WPA_IE_SUITE_COUNT_LEN > ie_len)
-+ goto skip_mfp_config;
-+ /* Ready to read capabilities */
-+ mfp = BRCMF_MFP_NONE;
-+ rsn_cap = ie[offset] + (ie[offset + 1] << 8);
-+ if (rsn_cap & RSN_CAP_MFPR_MASK)
-+ mfp = BRCMF_MFP_REQUIRED;
-+ else if (rsn_cap & RSN_CAP_MFPC_MASK)
-+ mfp = BRCMF_MFP_CAPABLE;
-+ brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "mfp", mfp);
-+
-+skip_mfp_config:
-+ brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
-+ err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
-+ if (err) {
-+ brcmf_err("could not set wpa_auth (%d)\n", err);
-+ return err;
- }
-- sec = &profile->sec;
-- sec->wpa_auth = sme->crypto.akm_suites[0];
-
- return err;
- }
-@@ -1827,7 +1880,7 @@ brcmf_cfg80211_connect(struct wiphy *wip
- goto done;
- }
-
-- err = brcmf_set_wsec_mode(ndev, sme, sme->mfp == NL80211_MFP_REQUIRED);
-+ err = brcmf_set_wsec_mode(ndev, sme);
- if (err) {
- brcmf_err("wl_set_set_cipher failed (%d)\n", err);
- goto done;
-@@ -2077,10 +2130,12 @@ brcmf_cfg80211_del_key(struct wiphy *wip
- u8 key_idx, bool pairwise, const u8 *mac_addr)
- {
- struct brcmf_if *ifp = netdev_priv(ndev);
-- struct brcmf_wsec_key key;
-- s32 err = 0;
-+ struct brcmf_wsec_key *key;
-+ s32 err;
-
- brcmf_dbg(TRACE, "Enter\n");
-+ brcmf_dbg(CONN, "key index (%d)\n", key_idx);
-+
- if (!check_vif_up(ifp->vif))
- return -EIO;
-
-@@ -2089,16 +2144,19 @@ brcmf_cfg80211_del_key(struct wiphy *wip
- return -EINVAL;
- }
-
-- memset(&key, 0, sizeof(key));
-+ key = &ifp->vif->profile.key[key_idx];
-
-- key.index = (u32)key_idx;
-- key.flags = BRCMF_PRIMARY_KEY;
-- key.algo = CRYPTO_ALGO_OFF;
-+ if (key->algo == CRYPTO_ALGO_OFF) {
-+ brcmf_dbg(CONN, "Ignore clearing of (never configured) key\n");
-+ return -EINVAL;
-+ }
-
-- brcmf_dbg(CONN, "key index (%d)\n", key_idx);
-+ memset(key, 0, sizeof(*key));
-+ key->index = (u32)key_idx;
-+ key->flags = BRCMF_PRIMARY_KEY;
-
-- /* Set the new key/index */
-- err = send_key_to_dongle(ifp, &key);
-+ /* Clear the key/index */
-+ err = send_key_to_dongle(ifp, key);
-
- brcmf_dbg(TRACE, "Exit\n");
- return err;
-@@ -2106,8 +2164,8 @@ brcmf_cfg80211_del_key(struct wiphy *wip
-
- static s32
- brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
-- u8 key_idx, bool pairwise, const u8 *mac_addr,
-- struct key_params *params)
-+ u8 key_idx, bool pairwise, const u8 *mac_addr,
-+ struct key_params *params)
- {
- struct brcmf_if *ifp = netdev_priv(ndev);
- struct brcmf_wsec_key *key;
-@@ -2214,9 +2272,10 @@ done:
- }
-
- static s32
--brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
-- u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
-- void (*callback) (void *cookie, struct key_params * params))
-+brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_idx,
-+ bool pairwise, const u8 *mac_addr, void *cookie,
-+ void (*callback)(void *cookie,
-+ struct key_params *params))
- {
- struct key_params params;
- struct brcmf_if *ifp = netdev_priv(ndev);
-@@ -2268,8 +2327,15 @@ done:
-
- static s32
- brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
-- struct net_device *ndev, u8 key_idx)
-+ struct net_device *ndev, u8 key_idx)
- {
-+ struct brcmf_if *ifp = netdev_priv(ndev);
-+
-+ brcmf_dbg(TRACE, "Enter key_idx %d\n", key_idx);
-+
-+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
-+ return 0;
-+
- brcmf_dbg(INFO, "Not supported\n");
-
- return -EOPNOTSUPP;
-@@ -3769,7 +3835,7 @@ brcmf_configure_wpaie(struct brcmf_if *i
- u32 auth = 0; /* d11 open authentication */
- u16 count;
- s32 err = 0;
-- s32 len = 0;
-+ s32 len;
- u32 i;
- u32 wsec;
- u32 pval = 0;
-@@ -3779,6 +3845,7 @@ brcmf_configure_wpaie(struct brcmf_if *i
- u8 *data;
- u16 rsn_cap;
- u32 wme_bss_disable;
-+ u32 mfp;
-
- brcmf_dbg(TRACE, "Enter\n");
- if (wpa_ie == NULL)
-@@ -3893,19 +3960,53 @@ brcmf_configure_wpaie(struct brcmf_if *i
- is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
- (wpa_auth |= WPA_AUTH_PSK);
- break;
-+ case RSN_AKM_SHA256_PSK:
-+ brcmf_dbg(TRACE, "RSN_AKM_MFP_PSK\n");
-+ wpa_auth |= WPA2_AUTH_PSK_SHA256;
-+ break;
-+ case RSN_AKM_SHA256_1X:
-+ brcmf_dbg(TRACE, "RSN_AKM_MFP_1X\n");
-+ wpa_auth |= WPA2_AUTH_1X_SHA256;
-+ break;
- default:
- brcmf_err("Ivalid key mgmt info\n");
- }
- offset++;
- }
-
-+ mfp = BRCMF_MFP_NONE;
- if (is_rsn_ie) {
- wme_bss_disable = 1;
- if ((offset + RSN_CAP_LEN) <= len) {
- rsn_cap = data[offset] + (data[offset + 1] << 8);
- if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
- wme_bss_disable = 0;
-+ if (rsn_cap & RSN_CAP_MFPR_MASK) {
-+ brcmf_dbg(TRACE, "MFP Required\n");
-+ mfp = BRCMF_MFP_REQUIRED;
-+ /* Firmware only supports mfp required in
-+ * combination with WPA2_AUTH_PSK_SHA256 or
-+ * WPA2_AUTH_1X_SHA256.
-+ */
-+ if (!(wpa_auth & (WPA2_AUTH_PSK_SHA256 |
-+ WPA2_AUTH_1X_SHA256))) {
-+ err = -EINVAL;
-+ goto exit;
-+ }
-+ /* Firmware has requirement that WPA2_AUTH_PSK/
-+ * WPA2_AUTH_UNSPECIFIED be set, if SHA256 OUI
-+ * is to be included in the rsn ie.
-+ */
-+ if (wpa_auth & WPA2_AUTH_PSK_SHA256)
-+ wpa_auth |= WPA2_AUTH_PSK;
-+ else if (wpa_auth & WPA2_AUTH_1X_SHA256)
-+ wpa_auth |= WPA2_AUTH_UNSPECIFIED;
-+ } else if (rsn_cap & RSN_CAP_MFPC_MASK) {
-+ brcmf_dbg(TRACE, "MFP Capable\n");
-+ mfp = BRCMF_MFP_CAPABLE;
-+ }
- }
-+ offset += RSN_CAP_LEN;
- /* set wme_bss_disable to sync RSN Capabilities */
- err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
- wme_bss_disable);
-@@ -3913,6 +4014,21 @@ brcmf_configure_wpaie(struct brcmf_if *i
- brcmf_err("wme_bss_disable error %d\n", err);
- goto exit;
- }
-+
-+ /* Skip PMKID cnt as it is know to be 0 for AP. */
-+ offset += RSN_PMKID_COUNT_LEN;
-+
-+ /* See if there is BIP wpa suite left for MFP */
-+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP) &&
-+ ((offset + WPA_IE_MIN_OUI_LEN) <= len)) {
-+ err = brcmf_fil_bsscfg_data_set(ifp, "bip",
-+ &data[offset],
-+ WPA_IE_MIN_OUI_LEN);
-+ if (err < 0) {
-+ brcmf_err("bip error %d\n", err);
-+ goto exit;
-+ }
-+ }
- }
- /* FOR WPS , set SES_OW_ENABLED */
- wsec = (pval | gval | SES_OW_ENABLED);
-@@ -3929,6 +4045,16 @@ brcmf_configure_wpaie(struct brcmf_if *i
- brcmf_err("wsec error %d\n", err);
- goto exit;
- }
-+ /* Configure MFP, this needs to go after wsec otherwise the wsec command
-+ * will overwrite the values set by MFP
-+ */
-+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP)) {
-+ err = brcmf_fil_bsscfg_int_set(ifp, "mfp", mfp);
-+ if (err < 0) {
-+ brcmf_err("mfp error %d\n", err);
-+ goto exit;
-+ }
-+ }
- /* set upper-layer auth */
- err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
- if (err < 0) {
-@@ -6149,8 +6275,10 @@ static int brcmf_setup_wiphy(struct wiph
- wiphy->n_addresses = i;
-
- wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
-- wiphy->cipher_suites = __wl_cipher_suites;
-- wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
-+ wiphy->cipher_suites = brcmf_cipher_suites;
-+ wiphy->n_cipher_suites = ARRAY_SIZE(brcmf_cipher_suites);
-+ if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
-+ wiphy->n_cipher_suites--;
- wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
- WIPHY_FLAG_OFFCHAN_TX |
- WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
-@@ -72,7 +72,7 @@
-
- #define BRCMF_VNDR_IE_P2PAF_SHIFT 12
-
--#define BRCMF_MAX_DEFAULT_KEYS 4
-+#define BRCMF_MAX_DEFAULT_KEYS 6
-
- /* beacon loss timeout defaults */
- #define BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_ON 2
-@@ -107,7 +107,6 @@ struct brcmf_cfg80211_security {
- u32 auth_type;
- u32 cipher_pairwise;
- u32 cipher_group;
-- u32 wpa_auth;
- };
-
- /**
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
-@@ -161,6 +161,7 @@ void brcmf_feat_attach(struct brcmf_pub
- ifp->drvr->feat_flags &= ~BIT(BRCMF_FEAT_MBSS);
- brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_RSDB, "rsdb_mode");
- brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_TDLS, "tdls_enable");
-+ brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MFP, "mfp");
-
- pfn_mac.version = BRCMF_PFN_MACADDR_CFG_VER;
- err = brcmf_fil_iovar_data_get(ifp, "pfn_macaddr", &pfn_mac,
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
-@@ -30,6 +30,7 @@
- * WOWL_ND: WOWL net detect (PNO)
- * WOWL_GTK: (WOWL) GTK rekeying offload
- * WOWL_ARP_ND: ARP and Neighbor Discovery offload support during WOWL.
-+ * MFP: 802.11w Management Frame Protection.
- */
- #define BRCMF_FEAT_LIST \
- BRCMF_FEAT_DEF(MBSS) \
-@@ -42,7 +43,8 @@
- BRCMF_FEAT_DEF(SCAN_RANDOM_MAC) \
- BRCMF_FEAT_DEF(WOWL_ND) \
- BRCMF_FEAT_DEF(WOWL_GTK) \
-- BRCMF_FEAT_DEF(WOWL_ARP_ND)
-+ BRCMF_FEAT_DEF(WOWL_ARP_ND) \
-+ BRCMF_FEAT_DEF(MFP)
-
- /*
- * Quirks:
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
-@@ -142,6 +142,10 @@
- #define BRCMF_RSN_KEK_LENGTH 16
- #define BRCMF_RSN_REPLAY_LEN 8
-
-+#define BRCMF_MFP_NONE 0
-+#define BRCMF_MFP_CAPABLE 1
-+#define BRCMF_MFP_REQUIRED 2
-+
- /* join preference types for join_pref iovar */
- enum brcmf_join_pref_types {
- BRCMF_JOIN_PREF_RSSI = 1,
---- a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h
-@@ -236,6 +236,8 @@ static inline bool ac_bitmap_tst(u8 bitm
- #define WPA2_AUTH_RESERVED3 0x0200
- #define WPA2_AUTH_RESERVED4 0x0400
- #define WPA2_AUTH_RESERVED5 0x0800
-+#define WPA2_AUTH_1X_SHA256 0x1000 /* 1X with SHA256 key derivation */
-+#define WPA2_AUTH_PSK_SHA256 0x8000 /* PSK with SHA256 key derivation */
-
- #define DOT11_DEFAULT_RTS_LEN 2347
- #define DOT11_DEFAULT_FRAG_LEN 2346
diff --git a/package/kernel/mac80211/patches/345-brcmfmac-Remove-waitqueue_active-check.patch b/package/kernel/mac80211/patches/345-brcmfmac-Remove-waitqueue_active-check.patch
deleted file mode 100644
index 39f438321e..0000000000
--- a/package/kernel/mac80211/patches/345-brcmfmac-Remove-waitqueue_active-check.patch
+++ /dev/null
@@ -1,54 +0,0 @@
-From: Hui Wang <hui.wang@canonical.com>
-Date: Wed, 9 Mar 2016 15:25:26 +0800
-Subject: [PATCH] brcmfmac: Remove waitqueue_active check
-
-We met a problem of pm_suspend when repeated closing/opening the lid
-on a Lenovo laptop (1/20 reproduce rate), below is the log:
-
-[ 199.735876] PM: Entering mem sleep
-[ 199.750516] e1000e: EEE TX LPI TIMER: 00000011
-[ 199.856638] Trying to free nonexistent resource <000000000000d000-000000000000d0ff>
-[ 201.753566] brcmfmac: brcmf_pcie_suspend: Timeout on response for entering D3 substate
-[ 201.753581] pci_legacy_suspend(): brcmf_pcie_suspend+0x0/0x1f0 [brcmfmac] returns -5
-[ 201.753585] dpm_run_callback(): pci_pm_suspend+0x0/0x160 returns -5
-[ 201.753589] PM: Device 0000:04:00.0 failed to suspend async: error -5
-
-Through debugging, we found when problem happens, it is not the device
-fails to enter D3, but the signal D3_ACK comes too early to pass the
-waitqueue_active() check.
-
-Just like this:
-brcmf_pcie_send_mb_data(devinfo, BRCMF_H2D_HOST_D3_INFORM);
-// signal is triggered here
-wait_event_timeout(devinfo->mbdata_resp_wait, devinfo->mbdata_completed,
- BRCMF_PCIE_MBDATA_TIMEOUT);
-
-So far I think it is safe to remove waitqueue_active check since there
-is only one place to trigger this signal (sending
-BRCMF_H2D_HOST_D3_INFORM). And it is not a problem calling wake_up
-event earlier than calling wait_event.
-
-Cc: Brett Rudley <brudley@broadcom.com>
-Cc: Hante Meuleman <meuleman@broadcom.com>
-Cc: Franky (Zhenhui) Lin <frankyl@broadcom.com>
-Cc: Pieter-Paul Giesberts <pieterpg@broadcom.com>
-Cc: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Hui Wang <hui.wang@canonical.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
-@@ -677,10 +677,8 @@ static void brcmf_pcie_handle_mb_data(st
- brcmf_dbg(PCIE, "D2H_MB_DATA: DEEP SLEEP EXIT\n");
- if (dtoh_mb_data & BRCMF_D2H_DEV_D3_ACK) {
- brcmf_dbg(PCIE, "D2H_MB_DATA: D3 ACK\n");
-- if (waitqueue_active(&devinfo->mbdata_resp_wait)) {
-- devinfo->mbdata_completed = true;
-- wake_up(&devinfo->mbdata_resp_wait);
-- }
-+ devinfo->mbdata_completed = true;
-+ wake_up(&devinfo->mbdata_resp_wait);
- }
- }
-
diff --git a/package/kernel/mac80211/patches/346-brcmfmac-uninitialized-ret-variable.patch b/package/kernel/mac80211/patches/346-brcmfmac-uninitialized-ret-variable.patch
deleted file mode 100644
index 3c9ed425da..0000000000
--- a/package/kernel/mac80211/patches/346-brcmfmac-uninitialized-ret-variable.patch
+++ /dev/null
@@ -1,21 +0,0 @@
-From: Dan Carpenter <dan.carpenter@oracle.com>
-Date: Tue, 15 Mar 2016 10:06:10 +0300
-Subject: [PATCH] brcmfmac: uninitialized "ret" variable
-
-There is an error path where "ret" isn't initialized.
-
-Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
-@@ -250,7 +250,7 @@ static int brcmf_sdiod_request_data(stru
- u32 addr, u8 regsz, void *data, bool write)
- {
- struct sdio_func *func;
-- int ret;
-+ int ret = -EINVAL;
-
- brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
- write, fn, addr, regsz);
diff --git a/package/kernel/mac80211/patches/347-brcmfmac-sdio-remove-unused-variable-retry_limit.patch b/package/kernel/mac80211/patches/347-brcmfmac-sdio-remove-unused-variable-retry_limit.patch
deleted file mode 100644
index d1deb6ee5c..0000000000
--- a/package/kernel/mac80211/patches/347-brcmfmac-sdio-remove-unused-variable-retry_limit.patch
+++ /dev/null
@@ -1,24 +0,0 @@
-From: Colin Ian King <colin.king@canonical.com>
-Date: Sun, 20 Mar 2016 17:34:52 +0000
-Subject: [PATCH] brcmfmac: sdio: remove unused variable retry_limit
-
-retry_limit has never been used during the life of this driver, so
-we may as well remove it as it is redundant.
-
-Signed-off-by: Colin Ian King <colin.king@canonical.com>
-Reviewed-by: Julian Calaby <julian.calaby@gmail.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
-@@ -535,9 +535,6 @@ static int qcount[NUMPRIO];
-
- #define RETRYCHAN(chan) ((chan) == SDPCM_EVENT_CHANNEL)
-
--/* Retry count for register access failures */
--static const uint retry_limit = 2;
--
- /* Limit on rounding up frames */
- static const uint max_roundup = 512;
-
diff --git a/package/kernel/mac80211/patches/348-brcmfmac-Delete-unnecessary-variable-initialisation.patch b/package/kernel/mac80211/patches/348-brcmfmac-Delete-unnecessary-variable-initialisation.patch
deleted file mode 100644
index d399b264ea..0000000000
--- a/package/kernel/mac80211/patches/348-brcmfmac-Delete-unnecessary-variable-initialisation.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-From: Markus Elfring <elfring@users.sourceforge.net>
-Date: Fri, 18 Mar 2016 13:23:24 +1100
-Subject: [PATCH] brcmfmac: Delete unnecessary variable initialisation
-
-In brcmf_sdio_download_firmware(), bcmerror is set by the call to
-brcmf_sdio_download_code_file(), before it's checked in the following
-line.
-
-Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>
-Acked-by: Arend van Spriel <arend@broadcom.com>
-[Rewrote commit message]
-Signed-off-by: Julian Calaby <julian.calaby@gmail.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
-@@ -3258,7 +3258,7 @@ static int brcmf_sdio_download_firmware(
- const struct firmware *fw,
- void *nvram, u32 nvlen)
- {
-- int bcmerror = -EFAULT;
-+ int bcmerror;
- u32 rstvec;
-
- sdio_claim_host(bus->sdiodev->func[1]);
diff --git a/package/kernel/mac80211/patches/349-0001-brcmfmac-clear-eventmask-array-before-using-it.patch b/package/kernel/mac80211/patches/349-0001-brcmfmac-clear-eventmask-array-before-using-it.patch
deleted file mode 100644
index 0acb4faaf1..0000000000
--- a/package/kernel/mac80211/patches/349-0001-brcmfmac-clear-eventmask-array-before-using-it.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-From: Hante Meuleman <hante.meuleman@broadcom.com>
-Date: Mon, 11 Apr 2016 11:35:21 +0200
-Subject: [PATCH] brcmfmac: clear eventmask array before using it
-
-When the event_msgs iovar is set an array is used to configure the
-enabled events. This arrays needs to nulled before configuring
-otherwise unhandled events will be enabled. This solves a problem
-where in case of wowl the host got woken by an incorrectly enabled
-event.
-
-Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
-Reviewed-by: Arend Van Spriel <arend@broadcom.com>
-Signed-off-by: Hante Meuleman <hante.meuleman@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
-@@ -371,6 +371,7 @@ int brcmf_fweh_activate_events(struct br
- int i, err;
- s8 eventmask[BRCMF_EVENTING_MASK_LEN];
-
-+ memset(eventmask, 0, sizeof(eventmask));
- for (i = 0; i < BRCMF_E_LAST; i++) {
- if (ifp->drvr->fweh.evt_handler[i]) {
- brcmf_dbg(EVENT, "enable event %s\n",
diff --git a/package/kernel/mac80211/patches/349-0002-brcmfmac-fix-clearing-wowl-wake-indicators.patch b/package/kernel/mac80211/patches/349-0002-brcmfmac-fix-clearing-wowl-wake-indicators.patch
deleted file mode 100644
index 8d3067890c..0000000000
--- a/package/kernel/mac80211/patches/349-0002-brcmfmac-fix-clearing-wowl-wake-indicators.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-From: Hante Meuleman <hante.meuleman@broadcom.com>
-Date: Mon, 11 Apr 2016 11:35:22 +0200
-Subject: [PATCH] brcmfmac: fix clearing wowl wake indicators
-
-Newer firmwares require the usage of the wowl wakeind struct as size
-for the iovar to clear the wake indicators. Older firmwares do not
-care, so change the used size.
-
-Reviewed-by: Arend Van Spriel <arend@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
-Signed-off-by: Hante Meuleman <hante.meuleman@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -3608,7 +3608,8 @@ static void brcmf_configure_wowl(struct
- if (!test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
- wowl_config |= BRCMF_WOWL_UNASSOC;
-
-- brcmf_fil_iovar_data_set(ifp, "wowl_wakeind", "clear", strlen("clear"));
-+ brcmf_fil_iovar_data_set(ifp, "wowl_wakeind", "clear",
-+ sizeof(struct brcmf_wowl_wakeind_le));
- brcmf_fil_iovar_int_set(ifp, "wowl", wowl_config);
- brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1);
- brcmf_bus_wowl_config(cfg->pub->bus_if, true);
diff --git a/package/kernel/mac80211/patches/349-0003-brcmfmac-insert-default-boardrev-in-nvram-data-if-mi.patch b/package/kernel/mac80211/patches/349-0003-brcmfmac-insert-default-boardrev-in-nvram-data-if-mi.patch
deleted file mode 100644
index f293401ca8..0000000000
--- a/package/kernel/mac80211/patches/349-0003-brcmfmac-insert-default-boardrev-in-nvram-data-if-mi.patch
+++ /dev/null
@@ -1,114 +0,0 @@
-From: Hante Meuleman <hante.meuleman@broadcom.com>
-Date: Mon, 11 Apr 2016 11:35:23 +0200
-Subject: [PATCH] brcmfmac: insert default boardrev in nvram data if
- missing
-
-Some nvram files/stores come without the boardrev information,
-but firmware requires this to be set. When not found in nvram then
-add a default boardrev string to the nvram data.
-
-Reported-by: Rafal Milecki <zajec5@gmail.com>
-Reviewed-by: Arend Van Spriel <arend@broadcom.com>
-Reviewed-by: Franky (Zhenhui) Lin <franky.lin@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
-Signed-off-by: Hante Meuleman <hante.meuleman@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
-@@ -29,6 +29,7 @@
- #define BRCMF_FW_MAX_NVRAM_SIZE 64000
- #define BRCMF_FW_NVRAM_DEVPATH_LEN 19 /* devpath0=pcie/1/4/ */
- #define BRCMF_FW_NVRAM_PCIEDEV_LEN 10 /* pcie/1/4/ + \0 */
-+#define BRCMF_FW_DEFAULT_BOARDREV "boardrev=0xff"
-
- enum nvram_parser_state {
- IDLE,
-@@ -51,6 +52,7 @@ enum nvram_parser_state {
- * @entry: start position of key,value entry.
- * @multi_dev_v1: detect pcie multi device v1 (compressed).
- * @multi_dev_v2: detect pcie multi device v2.
-+ * @boardrev_found: nvram contains boardrev information.
- */
- struct nvram_parser {
- enum nvram_parser_state state;
-@@ -63,6 +65,7 @@ struct nvram_parser {
- u32 entry;
- bool multi_dev_v1;
- bool multi_dev_v2;
-+ bool boardrev_found;
- };
-
- /**
-@@ -125,6 +128,8 @@ static enum nvram_parser_state brcmf_nvr
- nvp->multi_dev_v1 = true;
- if (strncmp(&nvp->data[nvp->entry], "pcie/", 5) == 0)
- nvp->multi_dev_v2 = true;
-+ if (strncmp(&nvp->data[nvp->entry], "boardrev", 8) == 0)
-+ nvp->boardrev_found = true;
- } else if (!is_nvram_char(c) || c == ' ') {
- brcmf_dbg(INFO, "warning: ln=%d:col=%d: '=' expected, skip invalid key entry\n",
- nvp->line, nvp->column);
-@@ -284,6 +289,8 @@ static void brcmf_fw_strip_multi_v1(stru
- while (i < nvp->nvram_len) {
- if ((nvp->nvram[i] - '0' == id) && (nvp->nvram[i + 1] == ':')) {
- i += 2;
-+ if (strncmp(&nvp->nvram[i], "boardrev", 8) == 0)
-+ nvp->boardrev_found = true;
- while (nvp->nvram[i] != 0) {
- nvram[j] = nvp->nvram[i];
- i++;
-@@ -335,6 +342,8 @@ static void brcmf_fw_strip_multi_v2(stru
- while (i < nvp->nvram_len - len) {
- if (strncmp(&nvp->nvram[i], prefix, len) == 0) {
- i += len;
-+ if (strncmp(&nvp->nvram[i], "boardrev", 8) == 0)
-+ nvp->boardrev_found = true;
- while (nvp->nvram[i] != 0) {
- nvram[j] = nvp->nvram[i];
- i++;
-@@ -356,6 +365,18 @@ fail:
- nvp->nvram_len = 0;
- }
-
-+static void brcmf_fw_add_defaults(struct nvram_parser *nvp)
-+{
-+ if (nvp->boardrev_found)
-+ return;
-+
-+ memcpy(&nvp->nvram[nvp->nvram_len], &BRCMF_FW_DEFAULT_BOARDREV,
-+ strlen(BRCMF_FW_DEFAULT_BOARDREV));
-+ nvp->nvram_len += strlen(BRCMF_FW_DEFAULT_BOARDREV);
-+ nvp->nvram[nvp->nvram_len] = '\0';
-+ nvp->nvram_len++;
-+}
-+
- /* brcmf_nvram_strip :Takes a buffer of "<var>=<value>\n" lines read from a fil
- * and ending in a NUL. Removes carriage returns, empty lines, comment lines,
- * and converts newlines to NULs. Shortens buffer as needed and pads with NULs.
-@@ -377,16 +398,21 @@ static void *brcmf_fw_nvram_strip(const
- if (nvp.state == END)
- break;
- }
-- if (nvp.multi_dev_v1)
-+ if (nvp.multi_dev_v1) {
-+ nvp.boardrev_found = false;
- brcmf_fw_strip_multi_v1(&nvp, domain_nr, bus_nr);
-- else if (nvp.multi_dev_v2)
-+ } else if (nvp.multi_dev_v2) {
-+ nvp.boardrev_found = false;
- brcmf_fw_strip_multi_v2(&nvp, domain_nr, bus_nr);
-+ }
-
- if (nvp.nvram_len == 0) {
- kfree(nvp.nvram);
- return NULL;
- }
-
-+ brcmf_fw_add_defaults(&nvp);
-+
- pad = nvp.nvram_len;
- *new_length = roundup(nvp.nvram_len + 1, 4);
- while (pad != *new_length) {
diff --git a/package/kernel/mac80211/patches/349-0004-brcmfmac-fix-p2p-scan-abort-null-pointer-exception.patch b/package/kernel/mac80211/patches/349-0004-brcmfmac-fix-p2p-scan-abort-null-pointer-exception.patch
deleted file mode 100644
index ed0c83f9bb..0000000000
--- a/package/kernel/mac80211/patches/349-0004-brcmfmac-fix-p2p-scan-abort-null-pointer-exception.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-From: Hante Meuleman <hante.meuleman@broadcom.com>
-Date: Mon, 11 Apr 2016 11:35:24 +0200
-Subject: [PATCH] brcmfmac: fix p2p scan abort null pointer exception
-
-When p2p connection setup is performed without having ever done an
-escan a null pointer exception can occur. This is because the ifp
-to abort scanning is taken from escan struct while it was never
-initialized. Fix this by using the primary ifp for scan abort. The
-abort should still be performed and all scan related commands are
-performed on primary ifp.
-
-Reviewed-by: Arend Van Spriel <arend@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
-Signed-off-by: Hante Meuleman <hante.meuleman@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
-@@ -1266,7 +1266,7 @@ static void
- brcmf_p2p_stop_wait_next_action_frame(struct brcmf_cfg80211_info *cfg)
- {
- struct brcmf_p2p_info *p2p = &cfg->p2p;
-- struct brcmf_if *ifp = cfg->escan_info.ifp;
-+ struct brcmf_if *ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
-
- if (test_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status) &&
- (test_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status) ||
diff --git a/package/kernel/mac80211/patches/349-0005-brcmfmac-screening-firmware-event-packet.patch b/package/kernel/mac80211/patches/349-0005-brcmfmac-screening-firmware-event-packet.patch
deleted file mode 100644
index 4d26404f51..0000000000
--- a/package/kernel/mac80211/patches/349-0005-brcmfmac-screening-firmware-event-packet.patch
+++ /dev/null
@@ -1,297 +0,0 @@
-From: Franky Lin <franky.lin@broadcom.com>
-Date: Mon, 11 Apr 2016 11:35:25 +0200
-Subject: [PATCH] brcmfmac: screening firmware event packet
-
-Firmware uses asynchronized events as a communication method to the
-host. The event packets are marked as ETH_P_LINK_CTL protocol type. For
-SDIO and PCIe bus, this kind of packets are delivered through virtual
-event channel not data channel. This patch adds a screening logic to
-make sure the event handler only processes the events coming from the
-correct channel.
-
-Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
-Signed-off-by: Franky Lin <franky.lin@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
-@@ -216,7 +216,9 @@ bool brcmf_c_prec_enq(struct device *dev
- int prec);
-
- /* Receive frame for delivery to OS. Callee disposes of rxp. */
--void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp);
-+void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp, bool handle_evnt);
-+/* Receive async event packet from firmware. Callee disposes of rxp. */
-+void brcmf_rx_event(struct device *dev, struct sk_buff *rxp);
-
- /* Indication from bus module regarding presence/insertion of dongle. */
- int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings);
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
-@@ -311,16 +311,17 @@ void brcmf_txflowblock(struct device *de
- brcmf_fws_bus_blocked(drvr, state);
- }
-
--void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb)
-+void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb,
-+ bool handle_event)
- {
-- skb->dev = ifp->ndev;
-- skb->protocol = eth_type_trans(skb, skb->dev);
-+ skb->protocol = eth_type_trans(skb, ifp->ndev);
-
- if (skb->pkt_type == PACKET_MULTICAST)
- ifp->stats.multicast++;
-
- /* Process special event packets */
-- brcmf_fweh_process_skb(ifp->drvr, skb);
-+ if (handle_event)
-+ brcmf_fweh_process_skb(ifp->drvr, skb);
-
- if (!(ifp->ndev->flags & IFF_UP)) {
- brcmu_pkt_buf_free_skb(skb);
-@@ -381,7 +382,7 @@ static void brcmf_rxreorder_process_info
- /* validate flags and flow id */
- if (flags == 0xFF) {
- brcmf_err("invalid flags...so ignore this packet\n");
-- brcmf_netif_rx(ifp, pkt);
-+ brcmf_netif_rx(ifp, pkt, false);
- return;
- }
-
-@@ -393,7 +394,7 @@ static void brcmf_rxreorder_process_info
- if (rfi == NULL) {
- brcmf_dbg(INFO, "received flags to cleanup, but no flow (%d) yet\n",
- flow_id);
-- brcmf_netif_rx(ifp, pkt);
-+ brcmf_netif_rx(ifp, pkt, false);
- return;
- }
-
-@@ -418,7 +419,7 @@ static void brcmf_rxreorder_process_info
- rfi = kzalloc(buf_size, GFP_ATOMIC);
- if (rfi == NULL) {
- brcmf_err("failed to alloc buffer\n");
-- brcmf_netif_rx(ifp, pkt);
-+ brcmf_netif_rx(ifp, pkt, false);
- return;
- }
-
-@@ -532,11 +533,11 @@ static void brcmf_rxreorder_process_info
- netif_rx:
- skb_queue_walk_safe(&reorder_list, pkt, pnext) {
- __skb_unlink(pkt, &reorder_list);
-- brcmf_netif_rx(ifp, pkt);
-+ brcmf_netif_rx(ifp, pkt, false);
- }
- }
-
--void brcmf_rx_frame(struct device *dev, struct sk_buff *skb)
-+void brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_evnt)
- {
- struct brcmf_if *ifp;
- struct brcmf_bus *bus_if = dev_get_drvdata(dev);
-@@ -560,7 +561,32 @@ void brcmf_rx_frame(struct device *dev,
- if (rd->reorder)
- brcmf_rxreorder_process_info(ifp, rd->reorder, skb);
- else
-- brcmf_netif_rx(ifp, skb);
-+ brcmf_netif_rx(ifp, skb, handle_evnt);
-+}
-+
-+void brcmf_rx_event(struct device *dev, struct sk_buff *skb)
-+{
-+ struct brcmf_if *ifp;
-+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
-+ struct brcmf_pub *drvr = bus_if->drvr;
-+ int ret;
-+
-+ brcmf_dbg(EVENT, "Enter: %s: rxp=%p\n", dev_name(dev), skb);
-+
-+ /* process and remove protocol-specific header */
-+ ret = brcmf_proto_hdrpull(drvr, true, skb, &ifp);
-+
-+ if (ret || !ifp || !ifp->ndev) {
-+ if (ret != -ENODATA && ifp)
-+ ifp->stats.rx_errors++;
-+ brcmu_pkt_buf_free_skb(skb);
-+ return;
-+ }
-+
-+ skb->protocol = eth_type_trans(skb, ifp->ndev);
-+
-+ brcmf_fweh_process_skb(ifp->drvr, skb);
-+ brcmu_pkt_buf_free_skb(skb);
- }
-
- void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success)
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
-@@ -225,7 +225,8 @@ int brcmf_get_next_free_bsscfgidx(struct
- void brcmf_txflowblock_if(struct brcmf_if *ifp,
- enum brcmf_netif_stop_reason reason, bool state);
- void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success);
--void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb);
-+void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb,
-+ bool handle_event);
- void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on);
- int __init brcmf_core_init(void);
- void __exit brcmf_core_exit(void);
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
-@@ -20,6 +20,7 @@
-
- #include <linux/types.h>
- #include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-
- #include <brcmu_utils.h>
- #include <brcmu_wifi.h>
-@@ -1075,28 +1076,13 @@ static void brcmf_msgbuf_rxbuf_event_pos
- }
-
-
--static void
--brcmf_msgbuf_rx_skb(struct brcmf_msgbuf *msgbuf, struct sk_buff *skb,
-- u8 ifidx)
--{
-- struct brcmf_if *ifp;
--
-- ifp = brcmf_get_ifp(msgbuf->drvr, ifidx);
-- if (!ifp || !ifp->ndev) {
-- brcmf_err("Received pkt for invalid ifidx %d\n", ifidx);
-- brcmu_pkt_buf_free_skb(skb);
-- return;
-- }
-- brcmf_netif_rx(ifp, skb);
--}
--
--
- static void brcmf_msgbuf_process_event(struct brcmf_msgbuf *msgbuf, void *buf)
- {
- struct msgbuf_rx_event *event;
- u32 idx;
- u16 buflen;
- struct sk_buff *skb;
-+ struct brcmf_if *ifp;
-
- event = (struct msgbuf_rx_event *)buf;
- idx = le32_to_cpu(event->msg.request_id);
-@@ -1116,7 +1102,19 @@ static void brcmf_msgbuf_process_event(s
-
- skb_trim(skb, buflen);
-
-- brcmf_msgbuf_rx_skb(msgbuf, skb, event->msg.ifidx);
-+ ifp = brcmf_get_ifp(msgbuf->drvr, event->msg.ifidx);
-+ if (!ifp || !ifp->ndev) {
-+ brcmf_err("Received pkt for invalid ifidx %d\n",
-+ event->msg.ifidx);
-+ goto exit;
-+ }
-+
-+ skb->protocol = eth_type_trans(skb, ifp->ndev);
-+
-+ brcmf_fweh_process_skb(ifp->drvr, skb);
-+
-+exit:
-+ brcmu_pkt_buf_free_skb(skb);
- }
-
-
-@@ -1128,6 +1126,7 @@ brcmf_msgbuf_process_rx_complete(struct
- u16 data_offset;
- u16 buflen;
- u32 idx;
-+ struct brcmf_if *ifp;
-
- brcmf_msgbuf_update_rxbufpost_count(msgbuf, 1);
-
-@@ -1148,7 +1147,14 @@ brcmf_msgbuf_process_rx_complete(struct
-
- skb_trim(skb, buflen);
-
-- brcmf_msgbuf_rx_skb(msgbuf, skb, rx_complete->msg.ifidx);
-+ ifp = brcmf_get_ifp(msgbuf->drvr, rx_complete->msg.ifidx);
-+ if (!ifp || !ifp->ndev) {
-+ brcmf_err("Received pkt for invalid ifidx %d\n",
-+ rx_complete->msg.ifidx);
-+ brcmu_pkt_buf_free_skb(skb);
-+ return;
-+ }
-+ brcmf_netif_rx(ifp, skb, false);
- }
-
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
-@@ -1294,6 +1294,17 @@ static inline u8 brcmf_sdio_getdatoffset
- return (u8)((hdrvalue & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT);
- }
-
-+static inline bool brcmf_sdio_fromevntchan(u8 *swheader)
-+{
-+ u32 hdrvalue;
-+ u8 ret;
-+
-+ hdrvalue = *(u32 *)swheader;
-+ ret = (u8)((hdrvalue & SDPCM_CHANNEL_MASK) >> SDPCM_CHANNEL_SHIFT);
-+
-+ return (ret == SDPCM_EVENT_CHANNEL);
-+}
-+
- static int brcmf_sdio_hdparse(struct brcmf_sdio *bus, u8 *header,
- struct brcmf_sdio_hdrinfo *rd,
- enum brcmf_sdio_frmtype type)
-@@ -1641,7 +1652,11 @@ static u8 brcmf_sdio_rxglom(struct brcmf
- pfirst->len, pfirst->next,
- pfirst->prev);
- skb_unlink(pfirst, &bus->glom);
-- brcmf_rx_frame(bus->sdiodev->dev, pfirst);
-+ if (brcmf_sdio_fromevntchan(pfirst->data))
-+ brcmf_rx_event(bus->sdiodev->dev, pfirst);
-+ else
-+ brcmf_rx_frame(bus->sdiodev->dev, pfirst,
-+ false);
- bus->sdcnt.rxglompkts++;
- }
-
-@@ -1967,18 +1982,19 @@ static uint brcmf_sdio_readframes(struct
- __skb_trim(pkt, rd->len);
- skb_pull(pkt, rd->dat_offset);
-
-+ if (pkt->len == 0)
-+ brcmu_pkt_buf_free_skb(pkt);
-+ else if (rd->channel == SDPCM_EVENT_CHANNEL)
-+ brcmf_rx_event(bus->sdiodev->dev, pkt);
-+ else
-+ brcmf_rx_frame(bus->sdiodev->dev, pkt,
-+ false);
-+
- /* prepare the descriptor for the next read */
- rd->len = rd->len_nxtfrm << 4;
- rd->len_nxtfrm = 0;
- /* treat all packet as event if we don't know */
- rd->channel = SDPCM_EVENT_CHANNEL;
--
-- if (pkt->len == 0) {
-- brcmu_pkt_buf_free_skb(pkt);
-- continue;
-- }
--
-- brcmf_rx_frame(bus->sdiodev->dev, pkt);
- }
-
- rxcount = maxframes - rxleft;
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
-@@ -514,7 +514,7 @@ static void brcmf_usb_rx_complete(struct
-
- if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) {
- skb_put(skb, urb->actual_length);
-- brcmf_rx_frame(devinfo->dev, skb);
-+ brcmf_rx_frame(devinfo->dev, skb, true);
- brcmf_usb_rx_refill(devinfo, req);
- } else {
- brcmu_pkt_buf_free_skb(skb);
diff --git a/package/kernel/mac80211/patches/349-0006-brcmfmac-cleanup-ampdu-rx-host-reorder-code.patch b/package/kernel/mac80211/patches/349-0006-brcmfmac-cleanup-ampdu-rx-host-reorder-code.patch
deleted file mode 100644
index 33b263df3a..0000000000
--- a/package/kernel/mac80211/patches/349-0006-brcmfmac-cleanup-ampdu-rx-host-reorder-code.patch
+++ /dev/null
@@ -1,585 +0,0 @@
-From: Arend van Spriel <arend@broadcom.com>
-Date: Mon, 11 Apr 2016 11:35:26 +0200
-Subject: [PATCH] brcmfmac: cleanup ampdu-rx host reorder code
-
-The code for ampdu-rx host reorder is related to the firmware signalling
-supported in BCDC protocol. This change moves the code to fwsignal module.
-
-Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
-Reviewed-by: Franky Lin <franky.lin@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
-@@ -351,6 +351,12 @@ brcmf_proto_bcdc_add_tdls_peer(struct br
- {
- }
-
-+static void brcmf_proto_bcdc_rxreorder(struct brcmf_if *ifp,
-+ struct sk_buff *skb)
-+{
-+ brcmf_fws_rxreorder(ifp, skb);
-+}
-+
- int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr)
- {
- struct brcmf_bcdc *bcdc;
-@@ -372,6 +378,7 @@ int brcmf_proto_bcdc_attach(struct brcmf
- drvr->proto->configure_addr_mode = brcmf_proto_bcdc_configure_addr_mode;
- drvr->proto->delete_peer = brcmf_proto_bcdc_delete_peer;
- drvr->proto->add_tdls_peer = brcmf_proto_bcdc_add_tdls_peer;
-+ drvr->proto->rxreorder = brcmf_proto_bcdc_rxreorder;
- drvr->proto->pd = bcdc;
-
- drvr->hdrlen += BCDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES;
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
-@@ -40,19 +40,6 @@
-
- #define MAX_WAIT_FOR_8021X_TX msecs_to_jiffies(950)
-
--/* AMPDU rx reordering definitions */
--#define BRCMF_RXREORDER_FLOWID_OFFSET 0
--#define BRCMF_RXREORDER_MAXIDX_OFFSET 2
--#define BRCMF_RXREORDER_FLAGS_OFFSET 4
--#define BRCMF_RXREORDER_CURIDX_OFFSET 6
--#define BRCMF_RXREORDER_EXPIDX_OFFSET 8
--
--#define BRCMF_RXREORDER_DEL_FLOW 0x01
--#define BRCMF_RXREORDER_FLUSH_ALL 0x02
--#define BRCMF_RXREORDER_CURIDX_VALID 0x04
--#define BRCMF_RXREORDER_EXPIDX_VALID 0x08
--#define BRCMF_RXREORDER_NEW_HOLE 0x10
--
- #define BRCMF_BSSIDX_INVALID -1
-
- char *brcmf_ifname(struct brcmf_if *ifp)
-@@ -342,207 +329,11 @@ void brcmf_netif_rx(struct brcmf_if *ifp
- netif_rx_ni(skb);
- }
-
--static void brcmf_rxreorder_get_skb_list(struct brcmf_ampdu_rx_reorder *rfi,
-- u8 start, u8 end,
-- struct sk_buff_head *skb_list)
--{
-- /* initialize return list */
-- __skb_queue_head_init(skb_list);
--
-- if (rfi->pend_pkts == 0) {
-- brcmf_dbg(INFO, "no packets in reorder queue\n");
-- return;
-- }
--
-- do {
-- if (rfi->pktslots[start]) {
-- __skb_queue_tail(skb_list, rfi->pktslots[start]);
-- rfi->pktslots[start] = NULL;
-- }
-- start++;
-- if (start > rfi->max_idx)
-- start = 0;
-- } while (start != end);
-- rfi->pend_pkts -= skb_queue_len(skb_list);
--}
--
--static void brcmf_rxreorder_process_info(struct brcmf_if *ifp, u8 *reorder_data,
-- struct sk_buff *pkt)
--{
-- u8 flow_id, max_idx, cur_idx, exp_idx, end_idx;
-- struct brcmf_ampdu_rx_reorder *rfi;
-- struct sk_buff_head reorder_list;
-- struct sk_buff *pnext;
-- u8 flags;
-- u32 buf_size;
--
-- flow_id = reorder_data[BRCMF_RXREORDER_FLOWID_OFFSET];
-- flags = reorder_data[BRCMF_RXREORDER_FLAGS_OFFSET];
--
-- /* validate flags and flow id */
-- if (flags == 0xFF) {
-- brcmf_err("invalid flags...so ignore this packet\n");
-- brcmf_netif_rx(ifp, pkt, false);
-- return;
-- }
--
-- rfi = ifp->drvr->reorder_flows[flow_id];
-- if (flags & BRCMF_RXREORDER_DEL_FLOW) {
-- brcmf_dbg(INFO, "flow-%d: delete\n",
-- flow_id);
--
-- if (rfi == NULL) {
-- brcmf_dbg(INFO, "received flags to cleanup, but no flow (%d) yet\n",
-- flow_id);
-- brcmf_netif_rx(ifp, pkt, false);
-- return;
-- }
--
-- brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, rfi->exp_idx,
-- &reorder_list);
-- /* add the last packet */
-- __skb_queue_tail(&reorder_list, pkt);
-- kfree(rfi);
-- ifp->drvr->reorder_flows[flow_id] = NULL;
-- goto netif_rx;
-- }
-- /* from here on we need a flow reorder instance */
-- if (rfi == NULL) {
-- buf_size = sizeof(*rfi);
-- max_idx = reorder_data[BRCMF_RXREORDER_MAXIDX_OFFSET];
--
-- buf_size += (max_idx + 1) * sizeof(pkt);
--
-- /* allocate space for flow reorder info */
-- brcmf_dbg(INFO, "flow-%d: start, maxidx %d\n",
-- flow_id, max_idx);
-- rfi = kzalloc(buf_size, GFP_ATOMIC);
-- if (rfi == NULL) {
-- brcmf_err("failed to alloc buffer\n");
-- brcmf_netif_rx(ifp, pkt, false);
-- return;
-- }
--
-- ifp->drvr->reorder_flows[flow_id] = rfi;
-- rfi->pktslots = (struct sk_buff **)(rfi+1);
-- rfi->max_idx = max_idx;
-- }
-- if (flags & BRCMF_RXREORDER_NEW_HOLE) {
-- if (rfi->pend_pkts) {
-- brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx,
-- rfi->exp_idx,
-- &reorder_list);
-- WARN_ON(rfi->pend_pkts);
-- } else {
-- __skb_queue_head_init(&reorder_list);
-- }
-- rfi->cur_idx = reorder_data[BRCMF_RXREORDER_CURIDX_OFFSET];
-- rfi->exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
-- rfi->max_idx = reorder_data[BRCMF_RXREORDER_MAXIDX_OFFSET];
-- rfi->pktslots[rfi->cur_idx] = pkt;
-- rfi->pend_pkts++;
-- brcmf_dbg(DATA, "flow-%d: new hole %d (%d), pending %d\n",
-- flow_id, rfi->cur_idx, rfi->exp_idx, rfi->pend_pkts);
-- } else if (flags & BRCMF_RXREORDER_CURIDX_VALID) {
-- cur_idx = reorder_data[BRCMF_RXREORDER_CURIDX_OFFSET];
-- exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
--
-- if ((exp_idx == rfi->exp_idx) && (cur_idx != rfi->exp_idx)) {
-- /* still in the current hole */
-- /* enqueue the current on the buffer chain */
-- if (rfi->pktslots[cur_idx] != NULL) {
-- brcmf_dbg(INFO, "HOLE: ERROR buffer pending..free it\n");
-- brcmu_pkt_buf_free_skb(rfi->pktslots[cur_idx]);
-- rfi->pktslots[cur_idx] = NULL;
-- }
-- rfi->pktslots[cur_idx] = pkt;
-- rfi->pend_pkts++;
-- rfi->cur_idx = cur_idx;
-- brcmf_dbg(DATA, "flow-%d: store pkt %d (%d), pending %d\n",
-- flow_id, cur_idx, exp_idx, rfi->pend_pkts);
--
-- /* can return now as there is no reorder
-- * list to process.
-- */
-- return;
-- }
-- if (rfi->exp_idx == cur_idx) {
-- if (rfi->pktslots[cur_idx] != NULL) {
-- brcmf_dbg(INFO, "error buffer pending..free it\n");
-- brcmu_pkt_buf_free_skb(rfi->pktslots[cur_idx]);
-- rfi->pktslots[cur_idx] = NULL;
-- }
-- rfi->pktslots[cur_idx] = pkt;
-- rfi->pend_pkts++;
--
-- /* got the expected one. flush from current to expected
-- * and update expected
-- */
-- brcmf_dbg(DATA, "flow-%d: expected %d (%d), pending %d\n",
-- flow_id, cur_idx, exp_idx, rfi->pend_pkts);
--
-- rfi->cur_idx = cur_idx;
-- rfi->exp_idx = exp_idx;
--
-- brcmf_rxreorder_get_skb_list(rfi, cur_idx, exp_idx,
-- &reorder_list);
-- brcmf_dbg(DATA, "flow-%d: freeing buffers %d, pending %d\n",
-- flow_id, skb_queue_len(&reorder_list),
-- rfi->pend_pkts);
-- } else {
-- u8 end_idx;
--
-- brcmf_dbg(DATA, "flow-%d (0x%x): both moved, old %d/%d, new %d/%d\n",
-- flow_id, flags, rfi->cur_idx, rfi->exp_idx,
-- cur_idx, exp_idx);
-- if (flags & BRCMF_RXREORDER_FLUSH_ALL)
-- end_idx = rfi->exp_idx;
-- else
-- end_idx = exp_idx;
--
-- /* flush pkts first */
-- brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx,
-- &reorder_list);
--
-- if (exp_idx == ((cur_idx + 1) % (rfi->max_idx + 1))) {
-- __skb_queue_tail(&reorder_list, pkt);
-- } else {
-- rfi->pktslots[cur_idx] = pkt;
-- rfi->pend_pkts++;
-- }
-- rfi->exp_idx = exp_idx;
-- rfi->cur_idx = cur_idx;
-- }
-- } else {
-- /* explicity window move updating the expected index */
-- exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
--
-- brcmf_dbg(DATA, "flow-%d (0x%x): change expected: %d -> %d\n",
-- flow_id, flags, rfi->exp_idx, exp_idx);
-- if (flags & BRCMF_RXREORDER_FLUSH_ALL)
-- end_idx = rfi->exp_idx;
-- else
-- end_idx = exp_idx;
--
-- brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx,
-- &reorder_list);
-- __skb_queue_tail(&reorder_list, pkt);
-- /* set the new expected idx */
-- rfi->exp_idx = exp_idx;
-- }
--netif_rx:
-- skb_queue_walk_safe(&reorder_list, pkt, pnext) {
-- __skb_unlink(pkt, &reorder_list);
-- brcmf_netif_rx(ifp, pkt, false);
-- }
--}
--
- void brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_evnt)
- {
- struct brcmf_if *ifp;
- struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_pub *drvr = bus_if->drvr;
-- struct brcmf_skb_reorder_data *rd;
- int ret;
-
- brcmf_dbg(DATA, "Enter: %s: rxp=%p\n", dev_name(dev), skb);
-@@ -557,9 +348,8 @@ void brcmf_rx_frame(struct device *dev,
- return;
- }
-
-- rd = (struct brcmf_skb_reorder_data *)skb->cb;
-- if (rd->reorder)
-- brcmf_rxreorder_process_info(ifp, rd->reorder, skb);
-+ if (brcmf_proto_is_reorder_skb(skb))
-+ brcmf_proto_rxreorder(ifp, skb);
- else
- brcmf_netif_rx(ifp, skb, handle_evnt);
- }
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
-@@ -208,10 +208,6 @@ struct brcmf_if {
- u8 ipv6addr_idx;
- };
-
--struct brcmf_skb_reorder_data {
-- u8 *reorder;
--};
--
- int brcmf_netdev_wait_pend8021x(struct brcmf_if *ifp);
-
- /* Return pointer to interface name */
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
-@@ -92,6 +92,19 @@ enum brcmf_fws_tlv_len {
- };
- #undef BRCMF_FWS_TLV_DEF
-
-+/* AMPDU rx reordering definitions */
-+#define BRCMF_RXREORDER_FLOWID_OFFSET 0
-+#define BRCMF_RXREORDER_MAXIDX_OFFSET 2
-+#define BRCMF_RXREORDER_FLAGS_OFFSET 4
-+#define BRCMF_RXREORDER_CURIDX_OFFSET 6
-+#define BRCMF_RXREORDER_EXPIDX_OFFSET 8
-+
-+#define BRCMF_RXREORDER_DEL_FLOW 0x01
-+#define BRCMF_RXREORDER_FLUSH_ALL 0x02
-+#define BRCMF_RXREORDER_CURIDX_VALID 0x04
-+#define BRCMF_RXREORDER_EXPIDX_VALID 0x08
-+#define BRCMF_RXREORDER_NEW_HOLE 0x10
-+
- #ifdef DEBUG
- /*
- * brcmf_fws_tlv_names - array of tlv names.
-@@ -1614,6 +1627,202 @@ static int brcmf_fws_notify_bcmc_credit_
- return 0;
- }
-
-+static void brcmf_rxreorder_get_skb_list(struct brcmf_ampdu_rx_reorder *rfi,
-+ u8 start, u8 end,
-+ struct sk_buff_head *skb_list)
-+{
-+ /* initialize return list */
-+ __skb_queue_head_init(skb_list);
-+
-+ if (rfi->pend_pkts == 0) {
-+ brcmf_dbg(INFO, "no packets in reorder queue\n");
-+ return;
-+ }
-+
-+ do {
-+ if (rfi->pktslots[start]) {
-+ __skb_queue_tail(skb_list, rfi->pktslots[start]);
-+ rfi->pktslots[start] = NULL;
-+ }
-+ start++;
-+ if (start > rfi->max_idx)
-+ start = 0;
-+ } while (start != end);
-+ rfi->pend_pkts -= skb_queue_len(skb_list);
-+}
-+
-+void brcmf_fws_rxreorder(struct brcmf_if *ifp, struct sk_buff *pkt)
-+{
-+ u8 *reorder_data;
-+ u8 flow_id, max_idx, cur_idx, exp_idx, end_idx;
-+ struct brcmf_ampdu_rx_reorder *rfi;
-+ struct sk_buff_head reorder_list;
-+ struct sk_buff *pnext;
-+ u8 flags;
-+ u32 buf_size;
-+
-+ reorder_data = ((struct brcmf_skb_reorder_data *)pkt->cb)->reorder;
-+ flow_id = reorder_data[BRCMF_RXREORDER_FLOWID_OFFSET];
-+ flags = reorder_data[BRCMF_RXREORDER_FLAGS_OFFSET];
-+
-+ /* validate flags and flow id */
-+ if (flags == 0xFF) {
-+ brcmf_err("invalid flags...so ignore this packet\n");
-+ brcmf_netif_rx(ifp, pkt, false);
-+ return;
-+ }
-+
-+ rfi = ifp->drvr->reorder_flows[flow_id];
-+ if (flags & BRCMF_RXREORDER_DEL_FLOW) {
-+ brcmf_dbg(INFO, "flow-%d: delete\n",
-+ flow_id);
-+
-+ if (rfi == NULL) {
-+ brcmf_dbg(INFO, "received flags to cleanup, but no flow (%d) yet\n",
-+ flow_id);
-+ brcmf_netif_rx(ifp, pkt, false);
-+ return;
-+ }
-+
-+ brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, rfi->exp_idx,
-+ &reorder_list);
-+ /* add the last packet */
-+ __skb_queue_tail(&reorder_list, pkt);
-+ kfree(rfi);
-+ ifp->drvr->reorder_flows[flow_id] = NULL;
-+ goto netif_rx;
-+ }
-+ /* from here on we need a flow reorder instance */
-+ if (rfi == NULL) {
-+ buf_size = sizeof(*rfi);
-+ max_idx = reorder_data[BRCMF_RXREORDER_MAXIDX_OFFSET];
-+
-+ buf_size += (max_idx + 1) * sizeof(pkt);
-+
-+ /* allocate space for flow reorder info */
-+ brcmf_dbg(INFO, "flow-%d: start, maxidx %d\n",
-+ flow_id, max_idx);
-+ rfi = kzalloc(buf_size, GFP_ATOMIC);
-+ if (rfi == NULL) {
-+ brcmf_err("failed to alloc buffer\n");
-+ brcmf_netif_rx(ifp, pkt, false);
-+ return;
-+ }
-+
-+ ifp->drvr->reorder_flows[flow_id] = rfi;
-+ rfi->pktslots = (struct sk_buff **)(rfi + 1);
-+ rfi->max_idx = max_idx;
-+ }
-+ if (flags & BRCMF_RXREORDER_NEW_HOLE) {
-+ if (rfi->pend_pkts) {
-+ brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx,
-+ rfi->exp_idx,
-+ &reorder_list);
-+ WARN_ON(rfi->pend_pkts);
-+ } else {
-+ __skb_queue_head_init(&reorder_list);
-+ }
-+ rfi->cur_idx = reorder_data[BRCMF_RXREORDER_CURIDX_OFFSET];
-+ rfi->exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
-+ rfi->max_idx = reorder_data[BRCMF_RXREORDER_MAXIDX_OFFSET];
-+ rfi->pktslots[rfi->cur_idx] = pkt;
-+ rfi->pend_pkts++;
-+ brcmf_dbg(DATA, "flow-%d: new hole %d (%d), pending %d\n",
-+ flow_id, rfi->cur_idx, rfi->exp_idx, rfi->pend_pkts);
-+ } else if (flags & BRCMF_RXREORDER_CURIDX_VALID) {
-+ cur_idx = reorder_data[BRCMF_RXREORDER_CURIDX_OFFSET];
-+ exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
-+
-+ if ((exp_idx == rfi->exp_idx) && (cur_idx != rfi->exp_idx)) {
-+ /* still in the current hole */
-+ /* enqueue the current on the buffer chain */
-+ if (rfi->pktslots[cur_idx] != NULL) {
-+ brcmf_dbg(INFO, "HOLE: ERROR buffer pending..free it\n");
-+ brcmu_pkt_buf_free_skb(rfi->pktslots[cur_idx]);
-+ rfi->pktslots[cur_idx] = NULL;
-+ }
-+ rfi->pktslots[cur_idx] = pkt;
-+ rfi->pend_pkts++;
-+ rfi->cur_idx = cur_idx;
-+ brcmf_dbg(DATA, "flow-%d: store pkt %d (%d), pending %d\n",
-+ flow_id, cur_idx, exp_idx, rfi->pend_pkts);
-+
-+ /* can return now as there is no reorder
-+ * list to process.
-+ */
-+ return;
-+ }
-+ if (rfi->exp_idx == cur_idx) {
-+ if (rfi->pktslots[cur_idx] != NULL) {
-+ brcmf_dbg(INFO, "error buffer pending..free it\n");
-+ brcmu_pkt_buf_free_skb(rfi->pktslots[cur_idx]);
-+ rfi->pktslots[cur_idx] = NULL;
-+ }
-+ rfi->pktslots[cur_idx] = pkt;
-+ rfi->pend_pkts++;
-+
-+ /* got the expected one. flush from current to expected
-+ * and update expected
-+ */
-+ brcmf_dbg(DATA, "flow-%d: expected %d (%d), pending %d\n",
-+ flow_id, cur_idx, exp_idx, rfi->pend_pkts);
-+
-+ rfi->cur_idx = cur_idx;
-+ rfi->exp_idx = exp_idx;
-+
-+ brcmf_rxreorder_get_skb_list(rfi, cur_idx, exp_idx,
-+ &reorder_list);
-+ brcmf_dbg(DATA, "flow-%d: freeing buffers %d, pending %d\n",
-+ flow_id, skb_queue_len(&reorder_list),
-+ rfi->pend_pkts);
-+ } else {
-+ u8 end_idx;
-+
-+ brcmf_dbg(DATA, "flow-%d (0x%x): both moved, old %d/%d, new %d/%d\n",
-+ flow_id, flags, rfi->cur_idx, rfi->exp_idx,
-+ cur_idx, exp_idx);
-+ if (flags & BRCMF_RXREORDER_FLUSH_ALL)
-+ end_idx = rfi->exp_idx;
-+ else
-+ end_idx = exp_idx;
-+
-+ /* flush pkts first */
-+ brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx,
-+ &reorder_list);
-+
-+ if (exp_idx == ((cur_idx + 1) % (rfi->max_idx + 1))) {
-+ __skb_queue_tail(&reorder_list, pkt);
-+ } else {
-+ rfi->pktslots[cur_idx] = pkt;
-+ rfi->pend_pkts++;
-+ }
-+ rfi->exp_idx = exp_idx;
-+ rfi->cur_idx = cur_idx;
-+ }
-+ } else {
-+ /* explicity window move updating the expected index */
-+ exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
-+
-+ brcmf_dbg(DATA, "flow-%d (0x%x): change expected: %d -> %d\n",
-+ flow_id, flags, rfi->exp_idx, exp_idx);
-+ if (flags & BRCMF_RXREORDER_FLUSH_ALL)
-+ end_idx = rfi->exp_idx;
-+ else
-+ end_idx = exp_idx;
-+
-+ brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx,
-+ &reorder_list);
-+ __skb_queue_tail(&reorder_list, pkt);
-+ /* set the new expected idx */
-+ rfi->exp_idx = exp_idx;
-+ }
-+netif_rx:
-+ skb_queue_walk_safe(&reorder_list, pkt, pnext) {
-+ __skb_unlink(pkt, &reorder_list);
-+ brcmf_netif_rx(ifp, pkt, false);
-+ }
-+}
-+
- void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb)
- {
- struct brcmf_skb_reorder_data *rd;
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h
-@@ -29,5 +29,6 @@ void brcmf_fws_add_interface(struct brcm
- void brcmf_fws_del_interface(struct brcmf_if *ifp);
- void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb);
- void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked);
-+void brcmf_fws_rxreorder(struct brcmf_if *ifp, struct sk_buff *skb);
-
- #endif /* FWSIGNAL_H_ */
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
-@@ -527,6 +527,9 @@ static int brcmf_msgbuf_hdrpull(struct b
- return -ENODEV;
- }
-
-+static void brcmf_msgbuf_rxreorder(struct brcmf_if *ifp, struct sk_buff *skb)
-+{
-+}
-
- static void
- brcmf_msgbuf_remove_flowring(struct brcmf_msgbuf *msgbuf, u16 flowid)
-@@ -1466,6 +1469,7 @@ int brcmf_proto_msgbuf_attach(struct brc
- drvr->proto->configure_addr_mode = brcmf_msgbuf_configure_addr_mode;
- drvr->proto->delete_peer = brcmf_msgbuf_delete_peer;
- drvr->proto->add_tdls_peer = brcmf_msgbuf_add_tdls_peer;
-+ drvr->proto->rxreorder = brcmf_msgbuf_rxreorder;
- drvr->proto->pd = msgbuf;
-
- init_waitqueue_head(&msgbuf->ioctl_resp_wait);
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h
-@@ -22,6 +22,9 @@ enum proto_addr_mode {
- ADDR_DIRECT
- };
-
-+struct brcmf_skb_reorder_data {
-+ u8 *reorder;
-+};
-
- struct brcmf_proto {
- int (*hdrpull)(struct brcmf_pub *drvr, bool do_fws,
-@@ -38,6 +41,7 @@ struct brcmf_proto {
- u8 peer[ETH_ALEN]);
- void (*add_tdls_peer)(struct brcmf_pub *drvr, int ifidx,
- u8 peer[ETH_ALEN]);
-+ void (*rxreorder)(struct brcmf_if *ifp, struct sk_buff *skb);
- void *pd;
- };
-
-@@ -91,6 +95,18 @@ brcmf_proto_add_tdls_peer(struct brcmf_p
- {
- drvr->proto->add_tdls_peer(drvr, ifidx, peer);
- }
-+static inline bool brcmf_proto_is_reorder_skb(struct sk_buff *skb)
-+{
-+ struct brcmf_skb_reorder_data *rd;
-+
-+ rd = (struct brcmf_skb_reorder_data *)skb->cb;
-+ return !!rd->reorder;
-+}
-
-+static inline void
-+brcmf_proto_rxreorder(struct brcmf_if *ifp, struct sk_buff *skb)
-+{
-+ ifp->drvr->proto->rxreorder(ifp, skb);
-+}
-
- #endif /* BRCMFMAC_PROTO_H */
diff --git a/package/kernel/mac80211/patches/349-0007-brcmfmac-revise-handling-events-in-receive-path.patch b/package/kernel/mac80211/patches/349-0007-brcmfmac-revise-handling-events-in-receive-path.patch
deleted file mode 100644
index a43feffe17..0000000000
--- a/package/kernel/mac80211/patches/349-0007-brcmfmac-revise-handling-events-in-receive-path.patch
+++ /dev/null
@@ -1,139 +0,0 @@
-From: Arend van Spriel <arend@broadcom.com>
-Date: Mon, 11 Apr 2016 11:35:27 +0200
-Subject: [PATCH] brcmfmac: revise handling events in receive path
-
-Move event handling out of brcmf_netif_rx() avoiding the need
-to pass a flag. This flag is only ever true for USB hosts as
-other interface use separate brcmf_rx_event() function.
-
-Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
-Reviewed-by: Franky Lin <franky.lin@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
-@@ -216,7 +216,7 @@ bool brcmf_c_prec_enq(struct device *dev
- int prec);
-
- /* Receive frame for delivery to OS. Callee disposes of rxp. */
--void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp, bool handle_evnt);
-+void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp, bool handle_event);
- /* Receive async event packet from firmware. Callee disposes of rxp. */
- void brcmf_rx_event(struct device *dev, struct sk_buff *rxp);
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
-@@ -298,18 +298,11 @@ void brcmf_txflowblock(struct device *de
- brcmf_fws_bus_blocked(drvr, state);
- }
-
--void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb,
-- bool handle_event)
-+void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb)
- {
-- skb->protocol = eth_type_trans(skb, ifp->ndev);
--
- if (skb->pkt_type == PACKET_MULTICAST)
- ifp->stats.multicast++;
-
-- /* Process special event packets */
-- if (handle_event)
-- brcmf_fweh_process_skb(ifp->drvr, skb);
--
- if (!(ifp->ndev->flags & IFF_UP)) {
- brcmu_pkt_buf_free_skb(skb);
- return;
-@@ -329,7 +322,7 @@ void brcmf_netif_rx(struct brcmf_if *ifp
- netif_rx_ni(skb);
- }
-
--void brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_evnt)
-+void brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_event)
- {
- struct brcmf_if *ifp;
- struct brcmf_bus *bus_if = dev_get_drvdata(dev);
-@@ -348,10 +341,17 @@ void brcmf_rx_frame(struct device *dev,
- return;
- }
-
-- if (brcmf_proto_is_reorder_skb(skb))
-+ skb->protocol = eth_type_trans(skb, ifp->ndev);
-+
-+ if (brcmf_proto_is_reorder_skb(skb)) {
- brcmf_proto_rxreorder(ifp, skb);
-- else
-- brcmf_netif_rx(ifp, skb, handle_evnt);
-+ } else {
-+ /* Process special event packets */
-+ if (handle_event)
-+ brcmf_fweh_process_skb(ifp->drvr, skb);
-+
-+ brcmf_netif_rx(ifp, skb);
-+ }
- }
-
- void brcmf_rx_event(struct device *dev, struct sk_buff *skb)
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
-@@ -221,8 +221,7 @@ int brcmf_get_next_free_bsscfgidx(struct
- void brcmf_txflowblock_if(struct brcmf_if *ifp,
- enum brcmf_netif_stop_reason reason, bool state);
- void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success);
--void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb,
-- bool handle_event);
-+void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb);
- void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on);
- int __init brcmf_core_init(void);
- void __exit brcmf_core_exit(void);
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
-@@ -1668,7 +1668,7 @@ void brcmf_fws_rxreorder(struct brcmf_if
- /* validate flags and flow id */
- if (flags == 0xFF) {
- brcmf_err("invalid flags...so ignore this packet\n");
-- brcmf_netif_rx(ifp, pkt, false);
-+ brcmf_netif_rx(ifp, pkt);
- return;
- }
-
-@@ -1680,7 +1680,7 @@ void brcmf_fws_rxreorder(struct brcmf_if
- if (rfi == NULL) {
- brcmf_dbg(INFO, "received flags to cleanup, but no flow (%d) yet\n",
- flow_id);
-- brcmf_netif_rx(ifp, pkt, false);
-+ brcmf_netif_rx(ifp, pkt);
- return;
- }
-
-@@ -1705,7 +1705,7 @@ void brcmf_fws_rxreorder(struct brcmf_if
- rfi = kzalloc(buf_size, GFP_ATOMIC);
- if (rfi == NULL) {
- brcmf_err("failed to alloc buffer\n");
-- brcmf_netif_rx(ifp, pkt, false);
-+ brcmf_netif_rx(ifp, pkt);
- return;
- }
-
-@@ -1819,7 +1819,7 @@ void brcmf_fws_rxreorder(struct brcmf_if
- netif_rx:
- skb_queue_walk_safe(&reorder_list, pkt, pnext) {
- __skb_unlink(pkt, &reorder_list);
-- brcmf_netif_rx(ifp, pkt, false);
-+ brcmf_netif_rx(ifp, pkt);
- }
- }
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
-@@ -1157,7 +1157,7 @@ brcmf_msgbuf_process_rx_complete(struct
- brcmu_pkt_buf_free_skb(skb);
- return;
- }
-- brcmf_netif_rx(ifp, skb, false);
-+ brcmf_netif_rx(ifp, skb);
- }
-
-
diff --git a/package/kernel/mac80211/patches/349-0008-brcmfmac-create-common-function-for-handling-brcmf_p.patch b/package/kernel/mac80211/patches/349-0008-brcmfmac-create-common-function-for-handling-brcmf_p.patch
deleted file mode 100644
index 08ea235fdd..0000000000
--- a/package/kernel/mac80211/patches/349-0008-brcmfmac-create-common-function-for-handling-brcmf_p.patch
+++ /dev/null
@@ -1,88 +0,0 @@
-From: Arend van Spriel <arend@broadcom.com>
-Date: Mon, 11 Apr 2016 11:35:28 +0200
-Subject: [PATCH] brcmfmac: create common function for handling
- brcmf_proto_hdrpull()
-
-In receive path brcmf_proto_hdrpull() needs to be called and handled
-similar in brcmf_rx_frame() and brcmf_rx_event(). Move that duplicated
-code in separate function.
-
-Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
-Reviewed-by: Franky Lin <franky.lin@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
-@@ -322,26 +322,35 @@ void brcmf_netif_rx(struct brcmf_if *ifp
- netif_rx_ni(skb);
- }
-
--void brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_event)
-+static int brcmf_rx_hdrpull(struct brcmf_pub *drvr, struct sk_buff *skb,
-+ struct brcmf_if **ifp)
- {
-- struct brcmf_if *ifp;
-- struct brcmf_bus *bus_if = dev_get_drvdata(dev);
-- struct brcmf_pub *drvr = bus_if->drvr;
- int ret;
-
-- brcmf_dbg(DATA, "Enter: %s: rxp=%p\n", dev_name(dev), skb);
--
- /* process and remove protocol-specific header */
-- ret = brcmf_proto_hdrpull(drvr, true, skb, &ifp);
-+ ret = brcmf_proto_hdrpull(drvr, true, skb, ifp);
-
-- if (ret || !ifp || !ifp->ndev) {
-+ if (ret || !(*ifp) || !(*ifp)->ndev) {
- if (ret != -ENODATA && ifp)
-- ifp->stats.rx_errors++;
-+ (*ifp)->stats.rx_errors++;
- brcmu_pkt_buf_free_skb(skb);
-- return;
-+ return -ENODATA;
- }
-
-- skb->protocol = eth_type_trans(skb, ifp->ndev);
-+ skb->protocol = eth_type_trans(skb, (*ifp)->ndev);
-+ return 0;
-+}
-+
-+void brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_event)
-+{
-+ struct brcmf_if *ifp;
-+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
-+ struct brcmf_pub *drvr = bus_if->drvr;
-+
-+ brcmf_dbg(DATA, "Enter: %s: rxp=%p\n", dev_name(dev), skb);
-+
-+ if (brcmf_rx_hdrpull(drvr, skb, &ifp))
-+ return;
-
- if (brcmf_proto_is_reorder_skb(skb)) {
- brcmf_proto_rxreorder(ifp, skb);
-@@ -359,21 +368,11 @@ void brcmf_rx_event(struct device *dev,
- struct brcmf_if *ifp;
- struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_pub *drvr = bus_if->drvr;
-- int ret;
-
- brcmf_dbg(EVENT, "Enter: %s: rxp=%p\n", dev_name(dev), skb);
-
-- /* process and remove protocol-specific header */
-- ret = brcmf_proto_hdrpull(drvr, true, skb, &ifp);
--
-- if (ret || !ifp || !ifp->ndev) {
-- if (ret != -ENODATA && ifp)
-- ifp->stats.rx_errors++;
-- brcmu_pkt_buf_free_skb(skb);
-+ if (brcmf_rx_hdrpull(drvr, skb, &ifp))
- return;
-- }
--
-- skb->protocol = eth_type_trans(skb, ifp->ndev);
-
- brcmf_fweh_process_skb(ifp->drvr, skb);
- brcmu_pkt_buf_free_skb(skb);
diff --git a/package/kernel/mac80211/patches/351-0001-brcmfmac-testing-the-wrong-variable-in-brcmf_rx_hdrp.patch b/package/kernel/mac80211/patches/351-0001-brcmfmac-testing-the-wrong-variable-in-brcmf_rx_hdrp.patch
deleted file mode 100644
index 11c65a49ed..0000000000
--- a/package/kernel/mac80211/patches/351-0001-brcmfmac-testing-the-wrong-variable-in-brcmf_rx_hdrp.patch
+++ /dev/null
@@ -1,39 +0,0 @@
-From: Dan Carpenter <dan.carpenter@oracle.com>
-Date: Tue, 19 Apr 2016 07:25:43 -0700
-Subject: [PATCH] brcmfmac: testing the wrong variable in brcmf_rx_hdrpull()
-
-Smatch complains about this code:
-
- drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c:335 brcmf_rx_hdrpull()
- error: we previously assumed '*ifp' could be null (see line 333)
-
-The problem is that we recently changed these from "ifp" to "*ifp" but
-there was one that we didn't update.
-
-- if (ret || !ifp || !ifp->ndev) {
-+ if (ret || !(*ifp) || !(*ifp)->ndev) {
- if (ret != -ENODATA && ifp)
- ^^^
-- ifp->stats.rx_errors++;
-+ (*ifp)->stats.rx_errors++;
-
-I have updated it to *ifp as well. We always call this function is a
-non-NULL "ifp" pointer, btw.
-
-Fixes: c462ebcdfe42 ('brcmfmac: create common function for handling brcmf_proto_hdrpull()')
-Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
-Acked-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
-@@ -331,7 +331,7 @@ static int brcmf_rx_hdrpull(struct brcmf
- ret = brcmf_proto_hdrpull(drvr, true, skb, ifp);
-
- if (ret || !(*ifp) || !(*ifp)->ndev) {
-- if (ret != -ENODATA && ifp)
-+ if (ret != -ENODATA && *ifp)
- (*ifp)->stats.rx_errors++;
- brcmu_pkt_buf_free_skb(skb);
- return -ENODATA;
diff --git a/package/kernel/mac80211/patches/402-ath_regd_optional.patch b/package/kernel/mac80211/patches/402-ath_regd_optional.patch
index 7351353076..463428371b 100644
--- a/package/kernel/mac80211/patches/402-ath_regd_optional.patch
+++ b/package/kernel/mac80211/patches/402-ath_regd_optional.patch
@@ -8,7 +8,7 @@
+ return;
+#endif
+
- for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+ for (band = 0; band < NUM_NL80211_BANDS; band++) {
if (!wiphy->bands[band])
continue;
@@ -374,6 +378,10 @@ ath_reg_apply_ir_flags(struct wiphy *wip
@@ -19,7 +19,7 @@
+ return;
+#endif
+
- sband = wiphy->bands[IEEE80211_BAND_2GHZ];
+ sband = wiphy->bands[NL80211_BAND_2GHZ];
if (!sband)
return;
@@ -402,6 +410,10 @@ static void ath_reg_apply_radar_flags(st
@@ -30,7 +30,7 @@
+ return;
+#endif
+
- if (!wiphy->bands[IEEE80211_BAND_5GHZ])
+ if (!wiphy->bands[NL80211_BAND_5GHZ])
return;
@@ -633,6 +645,11 @@ ath_regd_init_wiphy(struct ath_regulator
@@ -59,7 +59,7 @@
---help---
--- a/.local-symbols
+++ b/.local-symbols
-@@ -125,6 +125,7 @@ ADM8211=
+@@ -127,6 +127,7 @@ ADM8211=
ATH_COMMON=
WLAN_VENDOR_ATH=
ATH_DEBUG=
diff --git a/package/kernel/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch b/package/kernel/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch
index 1a62484954..819e64f370 100644
--- a/package/kernel/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch
+++ b/package/kernel/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch
@@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -722,6 +722,7 @@ static const struct ieee80211_iface_limi
+@@ -728,6 +728,7 @@ static const struct ieee80211_iface_limi
BIT(NL80211_IFTYPE_AP) },
{ .max = 1, .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO) },
diff --git a/package/kernel/mac80211/patches/500-ath9k_eeprom_debugfs.patch b/package/kernel/mac80211/patches/500-ath9k_eeprom_debugfs.patch
index a7f9d9f8b9..4b6da975b3 100644
--- a/package/kernel/mac80211/patches/500-ath9k_eeprom_debugfs.patch
+++ b/package/kernel/mac80211/patches/500-ath9k_eeprom_debugfs.patch
@@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -1301,6 +1301,53 @@ void ath9k_deinit_debug(struct ath_softc
+@@ -1319,6 +1319,53 @@ void ath9k_deinit_debug(struct ath_softc
ath9k_cmn_spectral_deinit_debug(&sc->spec_priv);
}
@@ -54,7 +54,7 @@
int ath9k_init_debug(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
-@@ -1320,6 +1367,8 @@ int ath9k_init_debug(struct ath_hw *ah)
+@@ -1338,6 +1385,8 @@ int ath9k_init_debug(struct ath_hw *ah)
ath9k_tx99_init_debug(sc);
ath9k_cmn_spectral_init_debug(&sc->spec_priv, sc->debug.debugfs_phy);
diff --git a/package/kernel/mac80211/patches/501-ath9k_ahb_init.patch b/package/kernel/mac80211/patches/501-ath9k_ahb_init.patch
index 5892c3e17a..1825d77b7f 100644
--- a/package/kernel/mac80211/patches/501-ath9k_ahb_init.patch
+++ b/package/kernel/mac80211/patches/501-ath9k_ahb_init.patch
@@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -1024,23 +1024,23 @@ static int __init ath9k_init(void)
+@@ -1030,23 +1030,23 @@ static int __init ath9k_init(void)
{
int error;
diff --git a/package/kernel/mac80211/patches/512-ath9k_channelbw_debugfs.patch b/package/kernel/mac80211/patches/512-ath9k_channelbw_debugfs.patch
index 5ecf528e59..a105d40662 100644
--- a/package/kernel/mac80211/patches/512-ath9k_channelbw_debugfs.patch
+++ b/package/kernel/mac80211/patches/512-ath9k_channelbw_debugfs.patch
@@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -1348,6 +1348,52 @@ static const struct file_operations fops
+@@ -1366,6 +1366,52 @@ static const struct file_operations fops
.owner = THIS_MODULE
};
@@ -53,7 +53,7 @@
int ath9k_init_debug(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
-@@ -1369,6 +1415,8 @@ int ath9k_init_debug(struct ath_hw *ah)
+@@ -1387,6 +1433,8 @@ int ath9k_init_debug(struct ath_hw *ah)
debugfs_create_file("eeprom", S_IRUSR, sc->debug.debugfs_phy, sc,
&fops_eeprom);
@@ -90,7 +90,7 @@
ichan->channel = chan->center_freq;
ichan->chan = chan;
@@ -308,7 +310,19 @@ static void ath9k_cmn_update_ichannel(st
- if (chan->band == IEEE80211_BAND_5GHZ)
+ if (chan->band == NL80211_BAND_5GHZ)
flags |= CHANNEL_5GHZ;
- switch (chandef->width) {
diff --git a/package/kernel/mac80211/patches/513-ath9k_add_pci_ids.patch b/package/kernel/mac80211/patches/513-ath9k_add_pci_ids.patch
index c84d1bc829..167eeff2d2 100644
--- a/package/kernel/mac80211/patches/513-ath9k_add_pci_ids.patch
+++ b/package/kernel/mac80211/patches/513-ath9k_add_pci_ids.patch
@@ -20,7 +20,7 @@
#define AR9160_DEVID_PCI 0x0027
--- a/drivers/net/wireless/ath/ath9k/pci.c
+++ b/drivers/net/wireless/ath/ath9k/pci.c
-@@ -751,6 +751,7 @@ static const struct pci_device_id ath_pc
+@@ -761,6 +761,7 @@ static const struct pci_device_id ath_pc
.driver_data = ATH9K_PCI_BT_ANT_DIV },
#endif
diff --git a/package/kernel/mac80211/patches/522-mac80211_configure_antenna_gain.patch b/package/kernel/mac80211/patches/522-mac80211_configure_antenna_gain.patch
index e151a12967..28f5dcca90 100644
--- a/package/kernel/mac80211/patches/522-mac80211_configure_antenna_gain.patch
+++ b/package/kernel/mac80211/patches/522-mac80211_configure_antenna_gain.patch
@@ -1,6 +1,6 @@
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
-@@ -2363,6 +2363,7 @@ struct cfg80211_qos_map {
+@@ -2406,6 +2406,7 @@ struct cfg80211_qos_map {
* (as advertised by the nl80211 feature flag.)
* @get_tx_power: store the current TX power into the dbm variable;
* return 0 if successful
@@ -8,7 +8,7 @@
*
* @set_wds_peer: set the WDS peer for a WDS interface
*
-@@ -2624,6 +2625,7 @@ struct cfg80211_ops {
+@@ -2667,6 +2668,7 @@ struct cfg80211_ops {
enum nl80211_tx_power_setting type, int mbm);
int (*get_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev,
int *dbm);
@@ -18,7 +18,7 @@
const u8 *addr);
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
-@@ -1286,6 +1286,7 @@ enum ieee80211_smps_mode {
+@@ -1305,6 +1305,7 @@ enum ieee80211_smps_mode {
*
* @power_level: requested transmit power (in dBm), backward compatibility
* value only that is set to the minimum of all interfaces
@@ -26,7 +26,7 @@
*
* @chandef: the channel definition to tune to
* @radar_enabled: whether radar detection is enabled
-@@ -1306,6 +1307,7 @@ enum ieee80211_smps_mode {
+@@ -1325,6 +1326,7 @@ enum ieee80211_smps_mode {
struct ieee80211_conf {
u32 flags;
int power_level, dynamic_ps_timeout;
@@ -36,9 +36,9 @@
u8 ps_dtim_period;
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
-@@ -1790,6 +1790,9 @@ enum nl80211_commands {
- * between scans. The scan plans are executed sequentially.
- * Each scan plan is a nested attribute of &enum nl80211_sched_scan_plan.
+@@ -1819,6 +1819,9 @@ enum nl80211_commands {
+ *
+ * @NL80211_ATTR_PAD: attribute used for padding for 64-bit alignment
*
+ * @NL80211_ATTR_WIPHY_ANTENNA_GAIN: Configured antenna gain. Used to reduce
+ * transmit power to stay within regulatory limits. u32, dBi.
@@ -46,9 +46,9 @@
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
-@@ -2164,6 +2167,8 @@ enum nl80211_attrs {
- NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS,
- NL80211_ATTR_SCHED_SCAN_PLANS,
+@@ -2201,6 +2204,8 @@ enum nl80211_attrs {
+
+ NL80211_ATTR_PAD,
+ NL80211_ATTR_WIPHY_ANTENNA_GAIN,
+
@@ -57,7 +57,7 @@
__NL80211_ATTR_AFTER_LAST,
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
-@@ -2229,6 +2229,19 @@ static int ieee80211_get_tx_power(struct
+@@ -2238,6 +2238,19 @@ static int ieee80211_get_tx_power(struct
return 0;
}
@@ -77,7 +77,7 @@
static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
const u8 *addr)
{
-@@ -3403,6 +3416,7 @@ const struct cfg80211_ops mac80211_confi
+@@ -3412,6 +3425,7 @@ const struct cfg80211_ops mac80211_confi
.set_wiphy_params = ieee80211_set_wiphy_params,
.set_tx_power = ieee80211_set_tx_power,
.get_tx_power = ieee80211_get_tx_power,
@@ -87,7 +87,7 @@
CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
-@@ -1318,6 +1318,7 @@ struct ieee80211_local {
+@@ -1322,6 +1322,7 @@ struct ieee80211_local {
int dynamic_ps_forced_timeout;
int user_power_level; /* in dBm, for all interfaces */
@@ -119,7 +119,7 @@
if (local->hw.conf.power_level != power) {
changed |= IEEE80211_CONF_CHANGE_POWER;
local->hw.conf.power_level = power;
-@@ -586,6 +592,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_
+@@ -588,6 +594,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_
IEEE80211_RADIOTAP_MCS_HAVE_BW;
local->hw.radiotap_vht_details = IEEE80211_RADIOTAP_VHT_KNOWN_GI |
IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH;
@@ -129,15 +129,15 @@
local->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
-@@ -403,6 +403,7 @@ static const struct nla_policy nl80211_p
- [NL80211_ATTR_NETNS_FD] = { .type = NLA_U32 },
- [NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 },
- [NL80211_ATTR_REG_INDOOR] = { .type = NLA_FLAG },
+@@ -406,6 +406,7 @@ static const struct nla_policy nl80211_p
+ [NL80211_ATTR_PBSS] = { .type = NLA_FLAG },
+ [NL80211_ATTR_BSS_SELECT] = { .type = NLA_NESTED },
+ [NL80211_ATTR_STA_SUPPORT_P2P_PS] = { .type = NLA_U8 },
+ [NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 },
};
/* policy for the key attributes */
-@@ -2220,6 +2221,20 @@ static int nl80211_set_wiphy(struct sk_b
+@@ -2251,6 +2252,20 @@ static int nl80211_set_wiphy(struct sk_b
if (result)
return result;
}
diff --git a/package/kernel/mac80211/patches/530-ath9k_extra_leds.patch b/package/kernel/mac80211/patches/530-ath9k_extra_leds.patch
index 5a5e4643f5..60012662e1 100644
--- a/package/kernel/mac80211/patches/530-ath9k_extra_leds.patch
+++ b/package/kernel/mac80211/patches/530-ath9k_extra_leds.patch
@@ -1,16 +1,16 @@
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
-@@ -814,6 +814,9 @@ static inline int ath9k_dump_btcoex(stru
+@@ -813,6 +813,9 @@ static inline int ath9k_dump_btcoex(stru
+ #ifdef CPTCFG_MAC80211_LEDS
void ath_init_leds(struct ath_softc *sc);
void ath_deinit_leds(struct ath_softc *sc);
- void ath_fill_led_pin(struct ath_softc *sc);
+int ath_create_gpio_led(struct ath_softc *sc, int gpio, const char *name,
-+ const char *trigger, bool active_low);
++ const char *trigger, bool active_low);
+
#else
static inline void ath_init_leds(struct ath_softc *sc)
{
-@@ -953,6 +956,13 @@ void ath_ant_comb_scan(struct ath_softc
+@@ -949,6 +952,13 @@ void ath_ant_comb_scan(struct ath_softc
#define ATH9K_NUM_CHANCTX 2 /* supports 2 operating channels */
@@ -24,7 +24,7 @@
struct ath_softc {
struct ieee80211_hw *hw;
struct device *dev;
-@@ -1005,9 +1015,8 @@ struct ath_softc {
+@@ -1001,9 +1011,8 @@ struct ath_softc {
spinlock_t chan_lock;
#ifdef CPTCFG_MAC80211_LEDS
@@ -38,24 +38,33 @@
#ifdef CPTCFG_ATH9K_DEBUGFS
--- a/drivers/net/wireless/ath/ath9k/gpio.c
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
-@@ -24,45 +24,102 @@
- static void ath_led_brightness(struct led_classdev *led_cdev,
- enum led_brightness brightness)
+@@ -22,7 +22,7 @@
+
+ #ifdef CPTCFG_MAC80211_LEDS
+
+-void ath_fill_led_pin(struct ath_softc *sc)
++static void ath_fill_led_pin(struct ath_softc *sc)
{
-- struct ath_softc *sc = container_of(led_cdev, struct ath_softc, led_cdev);
-- u32 val = (brightness == LED_OFF);
+ struct ath_hw *ah = sc->sc_ah;
+
+@@ -39,61 +39,111 @@ void ath_fill_led_pin(struct ath_softc *
+ else
+ ah->led_pin = ATH_LED_PIN_DEF;
+ }
++}
++
++static void ath_led_brightness(struct led_classdev *led_cdev,
++ enum led_brightness brightness)
++{
+ struct ath_led *led = container_of(led_cdev, struct ath_led, cdev);
+ struct ath_softc *sc = led->sc;
-
-- if (sc->sc_ah->config.led_active_high)
-- val = !val;
++
+ ath9k_ps_wakeup(sc);
+ ath9k_hw_set_gpio(sc->sc_ah, led->gpio->gpio,
+ (brightness != LED_OFF) ^ led->gpio->active_low);
+ ath9k_ps_restore(sc);
+}
-
-- ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, val);
++
+static int ath_add_led(struct ath_softc *sc, struct ath_led *led)
+{
+ const struct gpio_led *gpio = led->gpio;
@@ -71,30 +80,40 @@
+
+ led->sc = sc;
+ list_add(&led->list, &sc->leds);
-+
-+ /* Configure gpio for output */
-+ ath9k_hw_cfg_output(sc->sc_ah, gpio->gpio,
-+ AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
-+
+
+ /* Configure gpio for output */
+- ath9k_hw_gpio_request_out(ah, ah->led_pin, "ath9k-led",
++ ath9k_hw_gpio_request_out(sc->sc_ah, gpio->gpio, gpio->name,
+ AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+
+- /* LED off, active low */
+- ath9k_hw_set_gpio(ah, ah->led_pin, ah->config.led_active_high ? 0 : 1);
+ /* LED off */
+ ath9k_hw_set_gpio(sc->sc_ah, gpio->gpio, gpio->active_low);
+
+ return 0;
-+}
-+
+ }
+
+-static void ath_led_brightness(struct led_classdev *led_cdev,
+- enum led_brightness brightness)
+int ath_create_gpio_led(struct ath_softc *sc, int gpio_num, const char *name,
+ const char *trigger, bool active_low)
-+{
+ {
+- struct ath_softc *sc = container_of(led_cdev, struct ath_softc, led_cdev);
+- u32 val = (brightness == LED_OFF);
+ struct ath_led *led;
+ struct gpio_led *gpio;
+ char *_name;
+ int ret;
-+
+
+- if (sc->sc_ah->config.led_active_high)
+- val = !val;
+ led = kzalloc(sizeof(*led) + sizeof(*gpio) + strlen(name) + 1,
+ GFP_KERNEL);
+ if (!led)
+ return -ENOMEM;
-+
+
+- ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, val);
+ led->gpio = gpio = (struct gpio_led *) (led + 1);
+ _name = (char *) (led->gpio + 1);
+
@@ -115,15 +134,18 @@
{
- if (!sc->led_registered)
- return;
-+ struct ath_led *led;
-
+-
- ath_led_brightness(&sc->led_cdev, LED_OFF);
- led_classdev_unregister(&sc->led_cdev);
++ struct ath_led *led;
+
+- ath9k_hw_gpio_free(sc->sc_ah, sc->sc_ah->led_pin);
+ while (!list_empty(&sc->leds)) {
+ led = list_first_entry(&sc->leds, struct ath_led, list);
+ list_del(&led->list);
+ ath_led_brightness(&led->cdev, LED_OFF);
+ led_classdev_unregister(&led->cdev);
++ ath9k_hw_gpio_free(sc->sc_ah, led->gpio->gpio);
+ kfree(led);
+ }
}
@@ -139,6 +161,8 @@
if (AR_SREV_9100(sc->sc_ah))
return;
+ ath_fill_led_pin(sc);
+
- if (!ath9k_led_blink)
- sc->led_cdev.default_trigger =
- ieee80211_get_radio_led_name(sc->hw);
@@ -159,13 +183,14 @@
+ trigger = ieee80211_get_radio_led_name(sc->hw);
- sc->led_registered = true;
-+ ath_create_gpio_led(sc, sc->sc_ah->led_pin, led_name, trigger, !sc->sc_ah->config.led_active_high);
++ ath_create_gpio_led(sc, sc->sc_ah->led_pin, led_name, trigger,
++ !sc->sc_ah->config.led_active_high);
}
+ #endif
- void ath_fill_led_pin(struct ath_softc *sc)
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -936,7 +936,7 @@ int ath9k_init_device(u16 devid, struct
+@@ -942,7 +942,7 @@ int ath9k_init_device(u16 devid, struct
#ifdef CPTCFG_MAC80211_LEDS
/* must be initialized before ieee80211_register_hw */
@@ -176,7 +201,7 @@
#endif
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -1393,6 +1393,61 @@ static const struct file_operations fops
+@@ -1411,6 +1411,61 @@ static const struct file_operations fops
.llseek = default_llseek,
};
@@ -238,7 +263,7 @@
int ath9k_init_debug(struct ath_hw *ah)
{
-@@ -1417,6 +1472,10 @@ int ath9k_init_debug(struct ath_hw *ah)
+@@ -1435,6 +1490,10 @@ int ath9k_init_debug(struct ath_hw *ah)
&fops_eeprom);
debugfs_create_file("chanbw", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
sc, &fops_chanbw);
diff --git a/package/kernel/mac80211/patches/531-ath9k_extra_platform_leds.patch b/package/kernel/mac80211/patches/531-ath9k_extra_platform_leds.patch
index 7c10ea6b0d..f656697a07 100644
--- a/package/kernel/mac80211/patches/531-ath9k_extra_platform_leds.patch
+++ b/package/kernel/mac80211/patches/531-ath9k_extra_platform_leds.patch
@@ -1,6 +1,6 @@
--- a/include/linux/ath9k_platform.h
+++ b/include/linux/ath9k_platform.h
-@@ -41,6 +41,9 @@ struct ath9k_platform_data {
+@@ -45,6 +45,9 @@ struct ath9k_platform_data {
int (*external_reset)(void);
bool use_eeprom;
@@ -20,7 +20,7 @@
/********************************/
/* LED functions */
-@@ -88,6 +89,24 @@ int ath_create_gpio_led(struct ath_softc
+@@ -108,6 +109,24 @@ int ath_create_gpio_led(struct ath_softc
return ret;
}
@@ -45,7 +45,7 @@
void ath_deinit_leds(struct ath_softc *sc)
{
struct ath_led *led;
-@@ -103,8 +122,10 @@ void ath_deinit_leds(struct ath_softc *s
+@@ -124,8 +143,10 @@ void ath_deinit_leds(struct ath_softc *s
void ath_init_leds(struct ath_softc *sc)
{
@@ -56,10 +56,10 @@
INIT_LIST_HEAD(&sc->leds);
-@@ -120,6 +141,12 @@ void ath_init_leds(struct ath_softc *sc)
- trigger = ieee80211_get_radio_led_name(sc->hw);
+@@ -144,6 +165,12 @@ void ath_init_leds(struct ath_softc *sc)
- ath_create_gpio_led(sc, sc->sc_ah->led_pin, led_name, trigger, !sc->sc_ah->config.led_active_high);
+ ath_create_gpio_led(sc, sc->sc_ah->led_pin, led_name, trigger,
+ !sc->sc_ah->config.led_active_high);
+
+ if (!pdata)
+ return;
@@ -67,5 +67,5 @@
+ for (i = 0; i < pdata->num_leds; i++)
+ ath_create_platform_led(sc, &pdata->leds[i]);
}
+ #endif
- void ath_fill_led_pin(struct ath_softc *sc)
diff --git a/package/kernel/mac80211/patches/532-ath9k_get_led_polarity_from_platform_data.patch b/package/kernel/mac80211/patches/532-ath9k_get_led_polarity_from_platform_data.patch
index 6d62a2b1c2..986f155192 100644
--- a/package/kernel/mac80211/patches/532-ath9k_get_led_polarity_from_platform_data.patch
+++ b/package/kernel/mac80211/patches/532-ath9k_get_led_polarity_from_platform_data.patch
@@ -1,6 +1,6 @@
--- a/include/linux/ath9k_platform.h
+++ b/include/linux/ath9k_platform.h
-@@ -36,6 +36,7 @@ struct ath9k_platform_data {
+@@ -40,6 +40,7 @@ struct ath9k_platform_data {
bool tx_gain_buffalo;
bool disable_2ghz;
bool disable_5ghz;
@@ -10,7 +10,7 @@
int (*external_reset)(void);
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -577,6 +577,7 @@ static int ath9k_init_softc(u16 devid, s
+@@ -581,6 +581,7 @@ static int ath9k_init_softc(u16 devid, s
ah->external_reset = pdata->external_reset;
ah->disable_2ghz = pdata->disable_2ghz;
ah->disable_5ghz = pdata->disable_5ghz;
diff --git a/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch b/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch
index e83c6bfbf9..f4bb0f2d90 100644
--- a/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch
+++ b/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch
@@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -1449,6 +1449,50 @@ static const struct file_operations fops
+@@ -1467,6 +1467,50 @@ static const struct file_operations fops
#endif
@@ -51,7 +51,7 @@
int ath9k_init_debug(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
-@@ -1476,6 +1520,8 @@ int ath9k_init_debug(struct ath_hw *ah)
+@@ -1494,6 +1538,8 @@ int ath9k_init_debug(struct ath_hw *ah)
debugfs_create_file("gpio_led", S_IWUSR,
sc->debug.debugfs_phy, sc, &fops_gpio_led);
#endif
@@ -62,7 +62,7 @@
debugfs_create_devm_seqfile(sc->dev, "interrupt", sc->debug.debugfs_phy,
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
-@@ -519,6 +519,12 @@ enum {
+@@ -520,6 +520,12 @@ enum {
ATH9K_RESET_COLD,
};
@@ -75,7 +75,7 @@
struct ath9k_hw_version {
u32 magic;
u16 devid;
-@@ -804,6 +810,8 @@ struct ath_hw {
+@@ -805,6 +811,8 @@ struct ath_hw {
u32 rfkill_polarity;
u32 ah_flags;
@@ -84,7 +84,7 @@
bool reset_power_on;
bool htc_reset_init;
-@@ -1066,6 +1074,7 @@ void ath9k_hw_check_nav(struct ath_hw *a
+@@ -1067,6 +1075,7 @@ void ath9k_hw_check_nav(struct ath_hw *a
bool ath9k_hw_check_alive(struct ath_hw *ah);
bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode);
@@ -94,7 +94,7 @@
struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
-@@ -1819,6 +1819,20 @@ u32 ath9k_hw_get_tsf_offset(struct times
+@@ -1821,6 +1821,20 @@ u32 ath9k_hw_get_tsf_offset(struct times
}
EXPORT_SYMBOL(ath9k_hw_get_tsf_offset);
@@ -115,7 +115,7 @@
int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
struct ath9k_hw_cal_data *caldata, bool fastcc)
{
-@@ -2027,6 +2041,7 @@ int ath9k_hw_reset(struct ath_hw *ah, st
+@@ -2029,6 +2043,7 @@ int ath9k_hw_reset(struct ath_hw *ah, st
ar9003_hw_disable_phy_restart(ah);
ath9k_hw_apply_gpio_override(ah);
diff --git a/package/kernel/mac80211/patches/543-ath9k_entropy_from_adc.patch b/package/kernel/mac80211/patches/543-ath9k_entropy_from_adc.patch
index d7bb5a12ce..7da71653a9 100644
--- a/package/kernel/mac80211/patches/543-ath9k_entropy_from_adc.patch
+++ b/package/kernel/mac80211/patches/543-ath9k_entropy_from_adc.patch
@@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
-@@ -720,6 +720,7 @@ struct ath_spec_scan {
+@@ -721,6 +721,7 @@ struct ath_spec_scan {
* @config_pci_powersave:
* @calibrate: periodic calibration for NF, ANI, IQ, ADC gain, ADC-DC
*
@@ -8,7 +8,7 @@
* @spectral_scan_config: set parameters for spectral scan and enable/disable it
* @spectral_scan_trigger: trigger a spectral scan run
* @spectral_scan_wait: wait for a spectral scan run to finish
-@@ -742,6 +743,7 @@ struct ath_hw_ops {
+@@ -743,6 +744,7 @@ struct ath_hw_ops {
struct ath_hw_antcomb_conf *antconf);
void (*antdiv_comb_conf_set)(struct ath_hw *ah,
struct ath_hw_antcomb_conf *antconf);
@@ -18,7 +18,7 @@
void (*spectral_scan_trigger)(struct ath_hw *ah);
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
-@@ -1998,6 +1998,26 @@ void ar9003_hw_init_rate_txpower(struct
+@@ -1945,6 +1945,26 @@ void ar9003_hw_init_rate_txpower(struct
}
}
@@ -45,7 +45,7 @@
void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
{
struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
-@@ -2034,6 +2054,7 @@ void ar9003_hw_attach_phy_ops(struct ath
+@@ -1981,6 +2001,7 @@ void ar9003_hw_attach_phy_ops(struct ath
priv_ops->set_radar_params = ar9003_hw_set_radar_params;
priv_ops->fast_chan_change = ar9003_hw_fast_chan_change;
@@ -55,9 +55,9 @@
ops->spectral_scan_config = ar9003_hw_spectral_scan_config;
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -711,7 +711,8 @@ static void ath9k_init_txpower_limits(st
+@@ -717,7 +717,8 @@ static void ath9k_init_txpower_limits(st
if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
- ath9k_init_band_txpower(sc, IEEE80211_BAND_5GHZ);
+ ath9k_init_band_txpower(sc, NL80211_BAND_5GHZ);
- ah->curchan = curchan;
+ if (curchan)
@@ -65,7 +65,7 @@
}
static const struct ieee80211_iface_limit if_limits[] = {
-@@ -897,6 +898,18 @@ static void ath9k_set_hw_capab(struct at
+@@ -903,6 +904,18 @@ static void ath9k_set_hw_capab(struct at
SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
}
@@ -84,7 +84,7 @@
int ath9k_init_device(u16 devid, struct ath_softc *sc,
const struct ath_bus_ops *bus_ops)
{
-@@ -942,6 +955,8 @@ int ath9k_init_device(u16 devid, struct
+@@ -948,6 +961,8 @@ int ath9k_init_device(u16 devid, struct
ARRAY_SIZE(ath9k_tpt_blink));
#endif
@@ -110,7 +110,7 @@
static inline void ath9k_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable)
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
-@@ -1327,9 +1327,30 @@ void ar5008_hw_init_rate_txpower(struct
+@@ -1325,9 +1325,30 @@ void ar5008_hw_init_rate_txpower(struct
}
}
@@ -141,7 +141,7 @@
static const u32 ar5416_cca_regs[6] = {
AR_PHY_CCA,
AR_PHY_CH1_CCA,
-@@ -1344,6 +1365,8 @@ int ar5008_hw_attach_phy_ops(struct ath_
+@@ -1342,6 +1363,8 @@ int ar5008_hw_attach_phy_ops(struct ath_
if (ret)
return ret;
diff --git a/package/kernel/mac80211/patches/544-ath9k-ar933x-usb-hang-workaround.patch b/package/kernel/mac80211/patches/544-ath9k-ar933x-usb-hang-workaround.patch
index 8768c5d89a..9462fcaafa 100644
--- a/package/kernel/mac80211/patches/544-ath9k-ar933x-usb-hang-workaround.patch
+++ b/package/kernel/mac80211/patches/544-ath9k-ar933x-usb-hang-workaround.patch
@@ -40,7 +40,7 @@
return true;
}
-@@ -1797,8 +1816,14 @@ static int ath9k_hw_do_fastcc(struct ath
+@@ -1799,8 +1818,14 @@ static int ath9k_hw_do_fastcc(struct ath
if (AR_SREV_9271(ah))
ar9002_hw_load_ani_reg(ah, chan);
@@ -55,7 +55,7 @@
return -EINVAL;
}
-@@ -2052,6 +2077,9 @@ int ath9k_hw_reset(struct ath_hw *ah, st
+@@ -2054,6 +2079,9 @@ int ath9k_hw_reset(struct ath_hw *ah, st
ath9k_hw_set_radar_params(ah);
}
diff --git a/package/kernel/mac80211/patches/545-ath9k_ani_ws_detect.patch b/package/kernel/mac80211/patches/545-ath9k_ani_ws_detect.patch
index 3d24ccda1f..b639f972d8 100644
--- a/package/kernel/mac80211/patches/545-ath9k_ani_ws_detect.patch
+++ b/package/kernel/mac80211/patches/545-ath9k_ani_ws_detect.patch
@@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
-@@ -956,55 +956,6 @@ static bool ar5008_hw_ani_control_new(st
+@@ -954,55 +954,6 @@ static bool ar5008_hw_ani_control_new(st
* on == 0 means more noise imm
*/
u32 on = param ? 1 : 0;
@@ -58,7 +58,7 @@
REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
-@@ -41,20 +41,6 @@ static const int cycpwrThr1_table[] =
+@@ -42,20 +42,6 @@ static const int cycpwrThr1_table[] =
/* level: 0 1 2 3 4 5 6 7 8 */
{ -6, -4, -2, 0, 2, 4, 6, 8 }; /* lvl 0-7, default 3 */
@@ -79,7 +79,7 @@
static const u8 ofdm2pwr[] = {
ALL_TARGET_LEGACY_6_24,
ALL_TARGET_LEGACY_6_24,
-@@ -1089,11 +1075,6 @@ static bool ar9003_hw_ani_control(struct
+@@ -1095,11 +1081,6 @@ static bool ar9003_hw_ani_control(struct
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_channel *chan = ah->curchan;
struct ar5416AniState *aniState = &ah->ani;
@@ -91,7 +91,7 @@
s32 value, value2;
switch (cmd & ah->ani_function) {
-@@ -1107,61 +1088,6 @@ static bool ar9003_hw_ani_control(struct
+@@ -1113,61 +1094,6 @@ static bool ar9003_hw_ani_control(struct
*/
u32 on = param ? 1 : 0;
diff --git a/package/kernel/mac80211/patches/546-ath9k_platform_led_name.patch b/package/kernel/mac80211/patches/546-ath9k_platform_led_name.patch
index 8d2d899112..ced72c6c69 100644
--- a/package/kernel/mac80211/patches/546-ath9k_platform_led_name.patch
+++ b/package/kernel/mac80211/patches/546-ath9k_platform_led_name.patch
@@ -13,9 +13,9 @@ Signed-off-by: Michal Cieslakiewicz <michal.cieslakiewicz@wp.pl>
--- a/drivers/net/wireless/ath/ath9k/gpio.c
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
-@@ -132,15 +132,19 @@ void ath_init_leds(struct ath_softc *sc)
- if (AR_SREV_9100(sc->sc_ah))
- return;
+@@ -155,8 +155,11 @@ void ath_init_leds(struct ath_softc *sc)
+
+ ath_fill_led_pin(sc);
- snprintf(led_name, sizeof(led_name), "ath9k-%s",
- wiphy_name(sc->hw->wiphy));
@@ -23,22 +23,13 @@ Signed-off-by: Michal Cieslakiewicz <michal.cieslakiewicz@wp.pl>
+ strncpy(led_name, pdata->led_name, sizeof(led_name));
+ else
+ snprintf(led_name, sizeof(led_name), "ath9k-%s",
-+ wiphy_name(sc->hw->wiphy));
++ wiphy_name(sc->hw->wiphy));
if (ath9k_led_blink)
trigger = sc->led_default_trigger;
- else
- trigger = ieee80211_get_radio_led_name(sc->hw);
-
-- ath_create_gpio_led(sc, sc->sc_ah->led_pin, led_name, trigger, !sc->sc_ah->config.led_active_high);
-+ ath_create_gpio_led(sc, sc->sc_ah->led_pin, led_name, trigger,
-+ !sc->sc_ah->config.led_active_high);
-
- if (!pdata)
- return;
--- a/include/linux/ath9k_platform.h
+++ b/include/linux/ath9k_platform.h
-@@ -45,6 +45,7 @@ struct ath9k_platform_data {
+@@ -49,6 +49,7 @@ struct ath9k_platform_data {
int num_leds;
const struct gpio_led *leds;
diff --git a/package/kernel/mac80211/patches/547-ath9k_led_defstate_fix.patch b/package/kernel/mac80211/patches/547-ath9k_led_defstate_fix.patch
index db0b61996f..5d84cf0c42 100644
--- a/package/kernel/mac80211/patches/547-ath9k_led_defstate_fix.patch
+++ b/package/kernel/mac80211/patches/547-ath9k_led_defstate_fix.patch
@@ -13,9 +13,9 @@ Signed-off-by: Michal Cieslakiewicz <michal.cieslakiewicz@wp.pl>
--- a/drivers/net/wireless/ath/ath9k/gpio.c
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
-@@ -54,8 +54,11 @@ static int ath_add_led(struct ath_softc
- ath9k_hw_cfg_output(sc->sc_ah, gpio->gpio,
- AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+@@ -74,8 +74,11 @@ static int ath_add_led(struct ath_softc
+ ath9k_hw_gpio_request_out(sc->sc_ah, gpio->gpio, gpio->name,
+ AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
- /* LED off */
- ath9k_hw_set_gpio(sc->sc_ah, gpio->gpio, gpio->active_low);
diff --git a/package/kernel/mac80211/patches/548-ath9k_enable_gpio_chip.patch b/package/kernel/mac80211/patches/548-ath9k_enable_gpio_chip.patch
index 5203471c7e..1c89e42c7b 100644
--- a/package/kernel/mac80211/patches/548-ath9k_enable_gpio_chip.patch
+++ b/package/kernel/mac80211/patches/548-ath9k_enable_gpio_chip.patch
@@ -18,7 +18,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
#include "common.h"
#include "debug.h"
-@@ -963,6 +964,14 @@ struct ath_led {
+@@ -959,6 +960,14 @@ struct ath_led {
struct led_classdev cdev;
};
@@ -33,7 +33,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
struct ath_softc {
struct ieee80211_hw *hw;
struct device *dev;
-@@ -1017,6 +1026,9 @@ struct ath_softc {
+@@ -1013,6 +1022,9 @@ struct ath_softc {
#ifdef CPTCFG_MAC80211_LEDS
const char *led_default_trigger;
struct list_head leds;
@@ -45,7 +45,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
#ifdef CPTCFG_ATH9K_DEBUGFS
--- a/drivers/net/wireless/ath/ath9k/gpio.c
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
-@@ -16,12 +16,138 @@
+@@ -16,13 +16,138 @@
#include "ath9k.h"
#include <linux/ath9k_platform.h>
@@ -65,7 +65,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
+ struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip,
+ gchip);
+
-+ ath9k_hw_cfg_gpio_input(gc->sc->sc_ah, offset);
++ ath9k_hw_gpio_request_in(gc->sc->sc_ah, offset, "ath9k-gpio");
+
+ return 0;
+}
@@ -77,8 +77,8 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
+ struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip,
+ gchip);
+
-+ ath9k_hw_cfg_output(gc->sc->sc_ah, offset,
-+ AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
++ ath9k_hw_gpio_request_out(gc->sc->sc_ah, offset, "ath9k-gpio",
++ AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+ ath9k_hw_set_gpio(gc->sc->sc_ah, offset, value);
+
+ return 0;
@@ -182,10 +182,11 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
/********************************/
-#ifdef CPTCFG_MAC80211_LEDS
- static void ath_led_brightness(struct led_classdev *led_cdev,
- enum led_brightness brightness)
+-
+ static void ath_fill_led_pin(struct ath_softc *sc)
{
-@@ -60,6 +186,12 @@ static int ath_add_led(struct ath_softc
+ struct ath_hw *ah = sc->sc_ah;
+@@ -80,6 +205,12 @@ static int ath_add_led(struct ath_softc
else
ath9k_hw_set_gpio(sc->sc_ah, gpio->gpio, gpio->active_low);
@@ -198,7 +199,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
return 0;
}
-@@ -116,11 +248,17 @@ void ath_deinit_leds(struct ath_softc *s
+@@ -136,12 +267,18 @@ void ath_deinit_leds(struct ath_softc *s
while (!list_empty(&sc->leds)) {
led = list_first_entry(&sc->leds, struct ath_led, list);
@@ -210,24 +211,25 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
list_del(&led->list);
ath_led_brightness(&led->cdev, LED_OFF);
led_classdev_unregister(&led->cdev);
+ ath9k_hw_gpio_free(sc->sc_ah, led->gpio->gpio);
kfree(led);
}
+ ath9k_unregister_gpio_chip(sc);
}
void ath_init_leds(struct ath_softc *sc)
-@@ -135,6 +273,8 @@ void ath_init_leds(struct ath_softc *sc)
- if (AR_SREV_9100(sc->sc_ah))
- return;
+@@ -158,6 +295,8 @@ void ath_init_leds(struct ath_softc *sc)
+
+ ath_fill_led_pin(sc);
+ ath9k_register_gpio_chip(sc);
+
if (pdata && pdata->led_name)
strncpy(led_name, pdata->led_name, sizeof(led_name));
else
-@@ -186,6 +326,7 @@ void ath_fill_led_pin(struct ath_softc *
- /* LED off, active low */
- ath9k_hw_set_gpio(ah, ah->led_pin, (ah->config.led_active_high) ? 0 : 1);
+@@ -178,6 +317,7 @@ void ath_init_leds(struct ath_softc *sc)
+ for (i = 0; i < pdata->num_leds; i++)
+ ath_create_platform_led(sc, &pdata->leds[i]);
}
+
#endif
diff --git a/package/kernel/mac80211/patches/549-ath9k_enable_gpio_buttons.patch b/package/kernel/mac80211/patches/549-ath9k_enable_gpio_buttons.patch
index 64a9c31cd8..c7973bb039 100644
--- a/package/kernel/mac80211/patches/549-ath9k_enable_gpio_buttons.patch
+++ b/package/kernel/mac80211/patches/549-ath9k_enable_gpio_buttons.patch
@@ -10,7 +10,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
-@@ -1028,6 +1028,7 @@ struct ath_softc {
+@@ -1024,6 +1024,7 @@ struct ath_softc {
struct list_head leds;
#ifdef CONFIG_GPIOLIB
struct ath9k_gpio_chip *gpiochip;
@@ -29,7 +29,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
#ifdef CPTCFG_MAC80211_LEDS
-@@ -132,6 +134,63 @@ static void ath9k_unregister_gpio_chip(s
+@@ -132,6 +134,64 @@ static void ath9k_unregister_gpio_chip(s
sc->gpiochip = NULL;
}
@@ -59,7 +59,8 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
+ return;
+
+ for (i = 0; i < pdata->num_btns; i++) {
-+ ath9k_hw_cfg_gpio_input(sc->sc_ah, pdata->btns[i].gpio);
++ ath9k_hw_gpio_request_in(sc->sc_ah, pdata->btns[i].gpio,
++ "ath9k-gpio");
+ bt[i].gpio = sc->gpiochip->gchip.base + pdata->btns[i].gpio;
+ }
+
@@ -93,7 +94,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
#else /* CONFIG_GPIOLIB */
static inline void ath9k_register_gpio_chip(struct ath_softc *sc)
-@@ -142,6 +201,14 @@ static inline void ath9k_unregister_gpio
+@@ -142,6 +202,14 @@ static inline void ath9k_unregister_gpio
{
}
@@ -108,7 +109,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
#endif /* CONFIG_GPIOLIB */
/********************************/
-@@ -246,6 +313,7 @@ void ath_deinit_leds(struct ath_softc *s
+@@ -265,6 +333,7 @@ void ath_deinit_leds(struct ath_softc *s
{
struct ath_led *led;
@@ -116,17 +117,17 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
while (!list_empty(&sc->leds)) {
led = list_first_entry(&sc->leds, struct ath_led, list);
#ifdef CONFIG_GPIOLIB
-@@ -274,6 +342,7 @@ void ath_init_leds(struct ath_softc *sc)
- return;
+@@ -296,6 +365,7 @@ void ath_init_leds(struct ath_softc *sc)
+ ath_fill_led_pin(sc);
ath9k_register_gpio_chip(sc);
+ ath9k_init_buttons(sc);
if (pdata && pdata->led_name)
strncpy(led_name, pdata->led_name, sizeof(led_name));
-@@ -289,7 +358,7 @@ void ath_init_leds(struct ath_softc *sc)
+@@ -311,7 +381,7 @@ void ath_init_leds(struct ath_softc *sc)
ath_create_gpio_led(sc, sc->sc_ah->led_pin, led_name, trigger,
- !sc->sc_ah->config.led_active_high);
+ !sc->sc_ah->config.led_active_high);
- if (!pdata)
+ if (!pdata || !pdata->leds || !pdata->num_leds)
@@ -135,7 +136,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
for (i = 0; i < pdata->num_leds; i++)
--- a/include/linux/ath9k_platform.h
+++ b/include/linux/ath9k_platform.h
-@@ -46,6 +46,10 @@ struct ath9k_platform_data {
+@@ -50,6 +50,10 @@ struct ath9k_platform_data {
int num_leds;
const struct gpio_led *leds;
const char *led_name;
diff --git a/package/kernel/mac80211/patches/550-ath9k_add_ar9280_gpio_chip.patch b/package/kernel/mac80211/patches/550-ath9k_add_ar9280_gpio_chip.patch
index 3fe7e43209..22e2c66747 100644
--- a/package/kernel/mac80211/patches/550-ath9k_add_ar9280_gpio_chip.patch
+++ b/package/kernel/mac80211/patches/550-ath9k_add_ar9280_gpio_chip.patch
@@ -21,7 +21,7 @@ Signed-off-by: Michal Cieslakiewicz <michal.cieslakiewicz@wp.pl>
else if (AR_SREV_9285(sc->sc_ah))
ng = AR9285_NUM_GPIO;
+ else if (AR_SREV_9280(sc->sc_ah))
-+ ng = AR928X_NUM_GPIO;
++ ng = AR9280_NUM_GPIO;
else
return;
diff --git a/package/kernel/mac80211/patches/600-0002-rt2x00-rt2800lib-introduce-RT2800_HAS_HIGH_SHARED_ME.patch b/package/kernel/mac80211/patches/600-0002-rt2x00-rt2800lib-introduce-RT2800_HAS_HIGH_SHARED_ME.patch
index 82459091fe..db70a334bd 100644
--- a/package/kernel/mac80211/patches/600-0002-rt2x00-rt2800lib-introduce-RT2800_HAS_HIGH_SHARED_ME.patch
+++ b/package/kernel/mac80211/patches/600-0002-rt2x00-rt2800lib-introduce-RT2800_HAS_HIGH_SHARED_ME.patch
@@ -24,7 +24,7 @@ Changes since v1:
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-@@ -7722,6 +7722,7 @@ static int rt2800_probe_rt(struct rt2x00
+@@ -7726,6 +7726,7 @@ static int rt2800_probe_rt(struct rt2x00
int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev)
{
@@ -32,7 +32,7 @@ Changes since v1:
int retval;
u32 reg;
-@@ -7729,6 +7730,9 @@ int rt2800_probe_hw(struct rt2x00_dev *r
+@@ -7733,6 +7734,9 @@ int rt2800_probe_hw(struct rt2x00_dev *r
if (retval)
return retval;
diff --git a/package/kernel/mac80211/patches/600-0003-rt2x00-rt2800-serialize-shared-memory-access.patch b/package/kernel/mac80211/patches/600-0003-rt2x00-rt2800-serialize-shared-memory-access.patch
index 7abfcd16f2..a3b62bcc14 100644
--- a/package/kernel/mac80211/patches/600-0003-rt2x00-rt2800-serialize-shared-memory-access.patch
+++ b/package/kernel/mac80211/patches/600-0003-rt2x00-rt2800-serialize-shared-memory-access.patch
@@ -239,7 +239,7 @@ Changes since v1: ---
msleep(1);
/*
-@@ -7726,6 +7774,8 @@ int rt2800_probe_hw(struct rt2x00_dev *r
+@@ -7730,6 +7778,8 @@ int rt2800_probe_hw(struct rt2x00_dev *r
int retval;
u32 reg;
@@ -248,7 +248,7 @@ Changes since v1: ---
retval = rt2800_probe_rt(rt2x00dev);
if (retval)
return retval;
-@@ -7809,8 +7859,11 @@ void rt2800_get_key_seq(struct ieee80211
+@@ -7813,8 +7863,11 @@ void rt2800_get_key_seq(struct ieee80211
return;
offset = MAC_IVEIV_ENTRY(key->hw_key_idx);
diff --git a/package/kernel/mac80211/patches/600-0005-rt2x00-rt2800lib-add-hw_beacon_count-field-to-struct.patch b/package/kernel/mac80211/patches/600-0005-rt2x00-rt2800lib-add-hw_beacon_count-field-to-struct.patch
index 02b2acfeee..f41a160d3f 100644
--- a/package/kernel/mac80211/patches/600-0005-rt2x00-rt2800lib-add-hw_beacon_count-field-to-struct.patch
+++ b/package/kernel/mac80211/patches/600-0005-rt2x00-rt2800lib-add-hw_beacon_count-field-to-struct.patch
@@ -41,7 +41,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
rt2800_clear_beacon_register(rt2x00dev, i);
if (rt2x00_is_usb(rt2x00dev)) {
-@@ -7827,6 +7828,8 @@ int rt2800_probe_hw(struct rt2x00_dev *r
+@@ -7831,6 +7832,8 @@ int rt2800_probe_hw(struct rt2x00_dev *r
if (rt2x00_rt(rt2x00dev, RT3593))
__set_bit(RT2800_HAS_HIGH_SHARED_MEM, &drv_data->rt2800_flags);
diff --git a/package/kernel/mac80211/patches/600-0007-rt2x00-rt2800lib-fix-max-supported-beacon-count-for-.patch b/package/kernel/mac80211/patches/600-0007-rt2x00-rt2800lib-fix-max-supported-beacon-count-for-.patch
index e909272710..5099c64492 100644
--- a/package/kernel/mac80211/patches/600-0007-rt2x00-rt2800lib-fix-max-supported-beacon-count-for-.patch
+++ b/package/kernel/mac80211/patches/600-0007-rt2x00-rt2800lib-fix-max-supported-beacon-count-for-.patch
@@ -10,7 +10,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-@@ -7852,7 +7852,10 @@ int rt2800_probe_hw(struct rt2x00_dev *r
+@@ -7856,7 +7856,10 @@ int rt2800_probe_hw(struct rt2x00_dev *r
if (rt2x00_rt(rt2x00dev, RT3593))
__set_bit(RT2800_HAS_HIGH_SHARED_MEM, &drv_data->rt2800_flags);
diff --git a/package/kernel/mac80211/patches/600-0009-rt2x00-rt2800lib-enable-support-for-RT3883.patch b/package/kernel/mac80211/patches/600-0009-rt2x00-rt2800lib-enable-support-for-RT3883.patch
index 7fe38e0958..a2e701527b 100644
--- a/package/kernel/mac80211/patches/600-0009-rt2x00-rt2800lib-enable-support-for-RT3883.patch
+++ b/package/kernel/mac80211/patches/600-0009-rt2x00-rt2800lib-enable-support-for-RT3883.patch
@@ -10,7 +10,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-@@ -7822,6 +7822,7 @@ static int rt2800_probe_rt(struct rt2x00
+@@ -7826,6 +7826,7 @@ static int rt2800_probe_rt(struct rt2x00
case RT3390:
case RT3572:
case RT3593:
diff --git a/package/kernel/mac80211/patches/600-0010-rt2x00-rt2800lib-add-rf_vals-for-RF3853.patch b/package/kernel/mac80211/patches/600-0010-rt2x00-rt2800lib-add-rf_vals-for-RF3853.patch
index 253a0c0c1e..89bd0acb87 100644
--- a/package/kernel/mac80211/patches/600-0010-rt2x00-rt2800lib-add-rf_vals-for-RF3853.patch
+++ b/package/kernel/mac80211/patches/600-0010-rt2x00-rt2800lib-add-rf_vals-for-RF3853.patch
@@ -98,7 +98,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
static const struct rf_channel rf_vals_5592_xtal20[] = {
/* Channel, N, K, mod, R */
{1, 482, 4, 10, 3},
-@@ -7669,6 +7729,11 @@ static int rt2800_probe_hw_mode(struct r
+@@ -7673,6 +7733,11 @@ static int rt2800_probe_hw_mode(struct r
spec->channels = rf_vals_3x;
break;
diff --git a/package/kernel/mac80211/patches/600-0011-rt2x00-rt2800lib-enable-VCO-calibration-for-RF3853.patch b/package/kernel/mac80211/patches/600-0011-rt2x00-rt2800lib-enable-VCO-calibration-for-RF3853.patch
index f15c22b30f..b7efc9f31b 100644
--- a/package/kernel/mac80211/patches/600-0011-rt2x00-rt2800lib-enable-VCO-calibration-for-RF3853.patch
+++ b/package/kernel/mac80211/patches/600-0011-rt2x00-rt2800lib-enable-VCO-calibration-for-RF3853.patch
@@ -18,7 +18,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
case RF5360:
case RF5362:
case RF5370:
-@@ -7848,6 +7849,7 @@ static int rt2800_probe_hw_mode(struct r
+@@ -7852,6 +7853,7 @@ static int rt2800_probe_hw_mode(struct r
case RF3053:
case RF3070:
case RF3290:
diff --git a/package/kernel/mac80211/patches/600-0026-rt2x00-rt2800lib-use-correct-beacon-count-for-RT3883.patch b/package/kernel/mac80211/patches/600-0026-rt2x00-rt2800lib-use-correct-beacon-count-for-RT3883.patch
index 6ce224aba2..220e35fe4c 100644
--- a/package/kernel/mac80211/patches/600-0026-rt2x00-rt2800lib-use-correct-beacon-count-for-RT3883.patch
+++ b/package/kernel/mac80211/patches/600-0026-rt2x00-rt2800lib-use-correct-beacon-count-for-RT3883.patch
@@ -10,7 +10,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-@@ -8403,7 +8403,8 @@ int rt2800_probe_hw(struct rt2x00_dev *r
+@@ -8407,7 +8407,8 @@ int rt2800_probe_hw(struct rt2x00_dev *r
if (rt2x00_rt(rt2x00dev, RT3593))
__set_bit(RT2800_HAS_HIGH_SHARED_MEM, &drv_data->rt2800_flags);
diff --git a/package/kernel/mac80211/patches/600-0032-rt2x00-rt2800lib-enable-RT2800_HAS_HIGH_SHARED_MEM-f.patch b/package/kernel/mac80211/patches/600-0032-rt2x00-rt2800lib-enable-RT2800_HAS_HIGH_SHARED_MEM-f.patch
index 25753af81b..2ffa5a4162 100644
--- a/package/kernel/mac80211/patches/600-0032-rt2x00-rt2800lib-enable-RT2800_HAS_HIGH_SHARED_MEM-f.patch
+++ b/package/kernel/mac80211/patches/600-0032-rt2x00-rt2800lib-enable-RT2800_HAS_HIGH_SHARED_MEM-f.patch
@@ -11,7 +11,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-@@ -8416,7 +8416,8 @@ int rt2800_probe_hw(struct rt2x00_dev *r
+@@ -8420,7 +8420,8 @@ int rt2800_probe_hw(struct rt2x00_dev *r
if (retval)
return retval;
diff --git a/package/kernel/mac80211/patches/602-rt2x00-introduce-rt2x00_platform_h.patch b/package/kernel/mac80211/patches/602-rt2x00-introduce-rt2x00_platform_h.patch
index 7a183a404b..daa5dc61f9 100644
--- a/package/kernel/mac80211/patches/602-rt2x00-introduce-rt2x00_platform_h.patch
+++ b/package/kernel/mac80211/patches/602-rt2x00-introduce-rt2x00_platform_h.patch
@@ -22,10 +22,10 @@
+#endif /* _RT2X00_PLATFORM_H */
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
-@@ -38,6 +38,7 @@
- #include <linux/kfifo.h>
+@@ -39,6 +39,7 @@
#include <linux/hrtimer.h>
#include <linux/average.h>
+ #include <linux/usb.h>
+#include <linux/rt2x00_platform.h>
#include <net/mac80211.h>
diff --git a/package/kernel/mac80211/patches/603-rt2x00-introduce-rt2x00eeprom.patch b/package/kernel/mac80211/patches/603-rt2x00-introduce-rt2x00eeprom.patch
index bc056cd735..8ae5da3879 100644
--- a/package/kernel/mac80211/patches/603-rt2x00-introduce-rt2x00eeprom.patch
+++ b/package/kernel/mac80211/patches/603-rt2x00-introduce-rt2x00eeprom.patch
@@ -1,6 +1,6 @@
--- a/.local-symbols
+++ b/.local-symbols
-@@ -329,6 +329,7 @@ RT2X00_LIB_FIRMWARE=
+@@ -331,6 +331,7 @@ RT2X00_LIB_FIRMWARE=
RT2X00_LIB_CRYPTO=
RT2X00_LIB_LEDS=
RT2X00_LIB_DEBUGFS=
@@ -105,7 +105,7 @@
.drv_init_registers = rt2800mmio_init_registers,
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
-@@ -697,6 +697,7 @@ enum rt2x00_capability_flags {
+@@ -699,6 +699,7 @@ enum rt2x00_capability_flags {
REQUIRE_HT_TX_DESC,
REQUIRE_PS_AUTOWAKE,
REQUIRE_DELAYED_RFKILL,
@@ -127,7 +127,7 @@
DECLARE_KFIFO_PTR(txstatus_fifo, u32);
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
-@@ -1335,6 +1335,10 @@ int rt2x00lib_probe_dev(struct rt2x00_de
+@@ -1334,6 +1334,10 @@ int rt2x00lib_probe_dev(struct rt2x00_de
INIT_DELAYED_WORK(&rt2x00dev->autowakeup_work, rt2x00lib_autowakeup);
INIT_WORK(&rt2x00dev->sleep_work, rt2x00lib_sleep);
@@ -138,7 +138,7 @@
/*
* Let the driver probe the device to detect the capabilities.
*/
-@@ -1475,6 +1479,11 @@ void rt2x00lib_remove_dev(struct rt2x00_
+@@ -1477,6 +1481,11 @@ void rt2x00lib_remove_dev(struct rt2x00_
* Free the driver data.
*/
kfree(rt2x00dev->drv_data);
diff --git a/package/kernel/mac80211/patches/607-rt2x00-allow_disabling_bands_through_platform_data.patch b/package/kernel/mac80211/patches/607-rt2x00-allow_disabling_bands_through_platform_data.patch
index d923e05c77..a2e1faf9c3 100644
--- a/package/kernel/mac80211/patches/607-rt2x00-allow_disabling_bands_through_platform_data.patch
+++ b/package/kernel/mac80211/patches/607-rt2x00-allow_disabling_bands_through_platform_data.patch
@@ -37,7 +37,7 @@
num_rates += 4;
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
-@@ -405,6 +405,7 @@ struct hw_mode_spec {
+@@ -406,6 +406,7 @@ struct hw_mode_spec {
unsigned int supported_bands;
#define SUPPORT_BAND_2GHZ 0x00000001
#define SUPPORT_BAND_5GHZ 0x00000002
diff --git a/package/kernel/mac80211/patches/608-add_platform_data_mac_addr.patch b/package/kernel/mac80211/patches/608-add_platform_data_mac_addr.patch
index a645ba176e..6704ff835c 100644
--- a/package/kernel/mac80211/patches/608-add_platform_data_mac_addr.patch
+++ b/package/kernel/mac80211/patches/608-add_platform_data_mac_addr.patch
@@ -31,7 +31,7 @@
{
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
-@@ -1414,6 +1414,7 @@ static inline void rt2x00debug_dump_fram
+@@ -1416,6 +1416,7 @@ static inline void rt2x00debug_dump_fram
*/
u32 rt2x00lib_get_bssidx(struct rt2x00_dev *rt2x00dev,
struct ieee80211_vif *vif);
diff --git a/package/kernel/mac80211/patches/610-rt2x00-fix-rt3352-ext-pa.patch b/package/kernel/mac80211/patches/610-rt2x00-fix-rt3352-ext-pa.patch
index c69d33025d..9f10fe35c3 100644
--- a/package/kernel/mac80211/patches/610-rt2x00-fix-rt3352-ext-pa.patch
+++ b/package/kernel/mac80211/patches/610-rt2x00-fix-rt3352-ext-pa.patch
@@ -200,7 +200,7 @@
* EEPROM frequency
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
-@@ -717,6 +717,8 @@ enum rt2x00_capability_flags {
+@@ -719,6 +719,8 @@ enum rt2x00_capability_flags {
CAPABILITY_DOUBLE_ANTENNA,
CAPABILITY_BT_COEXIST,
CAPABILITY_VCO_RECALIBRATION,
diff --git a/package/kernel/mac80211/patches/611-rt2x00-rf_vals-rt3352-xtal20.patch b/package/kernel/mac80211/patches/611-rt2x00-rf_vals-rt3352-xtal20.patch
index b44fe900d5..860fdc07ed 100644
--- a/package/kernel/mac80211/patches/611-rt2x00-rf_vals-rt3352-xtal20.patch
+++ b/package/kernel/mac80211/patches/611-rt2x00-rf_vals-rt3352-xtal20.patch
@@ -28,7 +28,7 @@
static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
{
struct hw_mode_spec *spec = &rt2x00dev->spec;
-@@ -8272,7 +8293,10 @@ static int rt2800_probe_hw_mode(struct r
+@@ -8276,7 +8297,10 @@ static int rt2800_probe_hw_mode(struct r
case RF5390:
case RF5392:
spec->num_channels = 14;
@@ -40,7 +40,7 @@
break;
case RF3052:
-@@ -8456,6 +8480,19 @@ static int rt2800_probe_rt(struct rt2x00
+@@ -8460,6 +8484,19 @@ static int rt2800_probe_rt(struct rt2x00
return 0;
}
@@ -60,7 +60,7 @@
int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev)
{
struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
-@@ -8498,6 +8535,15 @@ int rt2800_probe_hw(struct rt2x00_dev *r
+@@ -8502,6 +8539,15 @@ int rt2800_probe_hw(struct rt2x00_dev *r
rt2800_register_write(rt2x00dev, GPIO_CTRL, reg);
/*
@@ -78,7 +78,7 @@
retval = rt2800_probe_hw_mode(rt2x00dev);
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
-@@ -400,6 +400,7 @@ static inline struct rt2x00_intf* vif_to
+@@ -401,6 +401,7 @@ static inline struct rt2x00_intf* vif_to
* @channels: Device/chipset specific channel values (See &struct rf_channel).
* @channels_info: Additional information for channels (See &struct channel_info).
* @ht: Driver HT Capabilities (See &ieee80211_sta_ht_cap).
@@ -86,7 +86,7 @@
*/
struct hw_mode_spec {
unsigned int supported_bands;
-@@ -416,6 +417,7 @@ struct hw_mode_spec {
+@@ -417,6 +418,7 @@ struct hw_mode_spec {
const struct channel_info *channels_info;
struct ieee80211_sta_ht_cap ht;
diff --git a/package/kernel/mac80211/patches/615-rt2x00-fix_20mhz_clk.patch b/package/kernel/mac80211/patches/615-rt2x00-fix_20mhz_clk.patch
index 8e3bd2a362..e7b2a8ca89 100644
--- a/package/kernel/mac80211/patches/615-rt2x00-fix_20mhz_clk.patch
+++ b/package/kernel/mac80211/patches/615-rt2x00-fix_20mhz_clk.patch
@@ -8,7 +8,7 @@
#include "rt2x00.h"
#include "rt2800lib.h"
-@@ -8482,13 +8483,14 @@ static int rt2800_probe_rt(struct rt2x00
+@@ -8486,13 +8487,14 @@ static int rt2800_probe_rt(struct rt2x00
int rt2800_probe_clk(struct rt2x00_dev *rt2x00dev)
{
diff --git a/package/kernel/mac80211/patches/616-rt2x00-support-rt5350.patch b/package/kernel/mac80211/patches/616-rt2x00-support-rt5350.patch
index faa5879de6..44bd8a194b 100644
--- a/package/kernel/mac80211/patches/616-rt2x00-support-rt5350.patch
+++ b/package/kernel/mac80211/patches/616-rt2x00-support-rt5350.patch
@@ -240,7 +240,7 @@
case RF5360:
case RF5362:
case RF5370:
-@@ -8287,6 +8398,7 @@ static int rt2800_probe_hw_mode(struct r
+@@ -8291,6 +8402,7 @@ static int rt2800_probe_hw_mode(struct r
case RF3290:
case RF3320:
case RF3322:
@@ -248,7 +248,7 @@
case RF5360:
case RF5362:
case RF5370:
-@@ -8426,6 +8538,7 @@ static int rt2800_probe_hw_mode(struct r
+@@ -8430,6 +8542,7 @@ static int rt2800_probe_hw_mode(struct r
case RF3070:
case RF3290:
case RF3853:
@@ -256,7 +256,7 @@
case RF5360:
case RF5362:
case RF5370:
-@@ -8466,6 +8579,7 @@ static int rt2800_probe_rt(struct rt2x00
+@@ -8470,6 +8583,7 @@ static int rt2800_probe_rt(struct rt2x00
case RT3572:
case RT3593:
case RT3883:
@@ -266,7 +266,7 @@
case RT5592:
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
-@@ -169,6 +169,7 @@ struct rt2x00_chip {
+@@ -170,6 +170,7 @@ struct rt2x00_chip {
#define RT3572 0x3572
#define RT3593 0x3593
#define RT3883 0x3883 /* WSOC */
diff --git a/package/kernel/mac80211/patches/620-rt2x00-add-AP+STA-support.patch b/package/kernel/mac80211/patches/620-rt2x00-add-AP+STA-support.patch
index 55452b9ebd..dba6033edb 100644
--- a/package/kernel/mac80211/patches/620-rt2x00-add-AP+STA-support.patch
+++ b/package/kernel/mac80211/patches/620-rt2x00-add-AP+STA-support.patch
@@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
-@@ -1284,7 +1284,7 @@ static inline void rt2x00lib_set_if_comb
+@@ -1283,7 +1283,7 @@ static inline void rt2x00lib_set_if_comb
*/
if_limit = &rt2x00dev->if_limits_ap;
if_limit->max = rt2x00dev->ops->max_ap_intf;
diff --git a/package/kernel/mac80211/patches/801-libertas-configure-sysfs-links.patch b/package/kernel/mac80211/patches/801-libertas-configure-sysfs-links.patch
index fd885cc002..02f3053b2f 100644
--- a/package/kernel/mac80211/patches/801-libertas-configure-sysfs-links.patch
+++ b/package/kernel/mac80211/patches/801-libertas-configure-sysfs-links.patch
@@ -1,6 +1,6 @@
--- a/drivers/net/wireless/marvell/libertas/cfg.c
+++ b/drivers/net/wireless/marvell/libertas/cfg.c
-@@ -2084,6 +2084,8 @@ struct wireless_dev *lbs_cfg_alloc(struc
+@@ -2122,6 +2122,8 @@ struct wireless_dev *lbs_cfg_alloc(struc
goto err_wiphy_new;
}
diff --git a/package/kernel/mac80211/patches/802-libertas-set-wireless-macaddr.patch b/package/kernel/mac80211/patches/802-libertas-set-wireless-macaddr.patch
index b67a95f948..ad306083da 100644
--- a/package/kernel/mac80211/patches/802-libertas-set-wireless-macaddr.patch
+++ b/package/kernel/mac80211/patches/802-libertas-set-wireless-macaddr.patch
@@ -1,6 +1,6 @@
--- a/drivers/net/wireless/marvell/libertas/cfg.c
+++ b/drivers/net/wireless/marvell/libertas/cfg.c
-@@ -2174,6 +2174,8 @@ int lbs_cfg_register(struct lbs_private
+@@ -2212,6 +2212,8 @@ int lbs_cfg_register(struct lbs_private
wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
wdev->wiphy->reg_notifier = lbs_reg_notifier;
diff --git a/package/kernel/mac80211/patches/804-b43-sync-with-bcma.patch b/package/kernel/mac80211/patches/804-b43-sync-with-bcma.patch
deleted file mode 100644
index 74cd4489f1..0000000000
--- a/package/kernel/mac80211/patches/804-b43-sync-with-bcma.patch
+++ /dev/null
@@ -1,17 +0,0 @@
---- a/drivers/net/wireless/broadcom/b43/main.c
-+++ b/drivers/net/wireless/broadcom/b43/main.c
-@@ -1215,10 +1215,10 @@ void b43_wireless_core_phy_pll_reset(str
- case B43_BUS_BCMA:
- bcma_cc = &dev->dev->bdev->bus->drv_cc;
-
-- bcma_cc_write32(bcma_cc, BCMA_CC_CHIPCTL_ADDR, 0);
-- bcma_cc_mask32(bcma_cc, BCMA_CC_CHIPCTL_DATA, ~0x4);
-- bcma_cc_set32(bcma_cc, BCMA_CC_CHIPCTL_DATA, 0x4);
-- bcma_cc_mask32(bcma_cc, BCMA_CC_CHIPCTL_DATA, ~0x4);
-+ bcma_cc_write32(bcma_cc, BCMA_CC_PMU_CHIPCTL_ADDR, 0);
-+ bcma_cc_mask32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, ~0x4);
-+ bcma_cc_set32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, 0x4);
-+ bcma_cc_mask32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, ~0x4);
- break;
- #endif
- #ifdef CPTCFG_B43_SSB
diff --git a/package/kernel/mac80211/patches/820-b43-add-antenna-control.patch b/package/kernel/mac80211/patches/820-b43-add-antenna-control.patch
index 06c731fce6..b60ef76a65 100644
--- a/package/kernel/mac80211/patches/820-b43-add-antenna-control.patch
+++ b/package/kernel/mac80211/patches/820-b43-add-antenna-control.patch
@@ -42,7 +42,7 @@
if (wl->radio_enabled != phy->radio_on) {
if (wl->radio_enabled) {
-@@ -5209,6 +5206,47 @@ static int b43_op_get_survey(struct ieee
+@@ -5207,6 +5204,47 @@ static int b43_op_get_survey(struct ieee
return 0;
}
@@ -90,7 +90,7 @@
static const struct ieee80211_ops b43_hw_ops = {
.tx = b43_op_tx,
.conf_tx = b43_op_conf_tx,
-@@ -5230,6 +5268,8 @@ static const struct ieee80211_ops b43_hw
+@@ -5228,6 +5266,8 @@ static const struct ieee80211_ops b43_hw
.sw_scan_complete = b43_op_sw_scan_complete_notifier,
.get_survey = b43_op_get_survey,
.rfkill_poll = b43_rfkill_poll,
@@ -99,7 +99,7 @@
};
/* Hard-reset the chip. Do not call this directly.
-@@ -5538,6 +5578,8 @@ static int b43_one_core_attach(struct b4
+@@ -5536,6 +5576,8 @@ static int b43_one_core_attach(struct b4
if (!wldev)
goto out;
@@ -108,7 +108,7 @@
wldev->use_pio = b43_modparam_pio;
wldev->dev = dev;
wldev->wl = wl;
-@@ -5628,6 +5670,9 @@ static struct b43_wl *b43_wireless_init(
+@@ -5626,6 +5668,9 @@ static struct b43_wl *b43_wireless_init(
hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
diff --git a/package/kernel/mac80211/patches/910-01-add-support-for-mt7620.patch b/package/kernel/mac80211/patches/910-01-add-support-for-mt7620.patch
index f2e21ea49f..be210f2d4b 100644
--- a/package/kernel/mac80211/patches/910-01-add-support-for-mt7620.patch
+++ b/package/kernel/mac80211/patches/910-01-add-support-for-mt7620.patch
@@ -1184,7 +1184,7 @@
break;
default:
rt2x00_err(rt2x00dev, "Invalid RF chipset 0x%04x detected\n",
-@@ -8423,6 +9363,7 @@ static int rt2800_probe_hw_mode(struct r
+@@ -8427,6 +9367,7 @@ static int rt2800_probe_hw_mode(struct r
case RF5372:
case RF5390:
case RF5392:
@@ -1192,7 +1192,7 @@
spec->num_channels = 14;
if (spec->clk_is_20mhz)
spec->channels = rf_vals_xtal20mhz_3x;
-@@ -8563,6 +9504,7 @@ static int rt2800_probe_hw_mode(struct r
+@@ -8567,6 +9508,7 @@ static int rt2800_probe_hw_mode(struct r
case RF5372:
case RF5390:
case RF5392:
diff --git a/package/kernel/mac80211/patches/921-ath10k_init_devices_synchronously.patch b/package/kernel/mac80211/patches/921-ath10k_init_devices_synchronously.patch
index 8c6d720a73..6a904ec7ce 100644
--- a/package/kernel/mac80211/patches/921-ath10k_init_devices_synchronously.patch
+++ b/package/kernel/mac80211/patches/921-ath10k_init_devices_synchronously.patch
@@ -14,7 +14,7 @@ Signed-off-by: Sven Eckelmann <sven@open-mesh.com>
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
-@@ -1914,6 +1914,16 @@ int ath10k_core_register(struct ath10k *
+@@ -2009,6 +2009,16 @@ int ath10k_core_register(struct ath10k *
ar->chip_id = chip_id;
queue_work(ar->workqueue, &ar->register_work);
diff --git a/package/kernel/mac80211/patches/930-ath10k_add_tpt_led_trigger.patch b/package/kernel/mac80211/patches/930-ath10k_add_tpt_led_trigger.patch
index 281b4475ad..60b5b1be0c 100644
--- a/package/kernel/mac80211/patches/930-ath10k_add_tpt_led_trigger.patch
+++ b/package/kernel/mac80211/patches/930-ath10k_add_tpt_led_trigger.patch
@@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
-@@ -7141,6 +7141,21 @@ struct ath10k_vif *ath10k_get_arvif(stru
+@@ -7662,6 +7662,21 @@ struct ath10k_vif *ath10k_get_arvif(stru
return arvif_iter.arvif;
}
@@ -22,7 +22,7 @@
int ath10k_mac_register(struct ath10k *ar)
{
static const u32 cipher_suites[] = {
-@@ -7357,6 +7372,12 @@ int ath10k_mac_register(struct ath10k *a
+@@ -7880,6 +7895,12 @@ int ath10k_mac_register(struct ath10k *a
ar->hw->wiphy->cipher_suites = cipher_suites;
ar->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
diff --git a/package/kernel/mac80211/patches/936-ath10k_skip_otp_check.patch b/package/kernel/mac80211/patches/936-ath10k_skip_otp_check.patch
new file mode 100644
index 0000000000..39aba41df4
--- /dev/null
+++ b/package/kernel/mac80211/patches/936-ath10k_skip_otp_check.patch
@@ -0,0 +1,42 @@
+--- a/drivers/net/wireless/ath/ath10k/core.c
++++ b/drivers/net/wireless/ath/ath10k/core.c
+@@ -1165,9 +1165,6 @@ static int ath10k_core_fetch_firmware_fi
+ {
+ int ret;
+
+- /* calibration file is optional, don't check for any errors */
+- ath10k_fetch_cal_file(ar);
+-
+ ar->fw_api = 5;
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
+
+@@ -1870,6 +1867,9 @@ static int ath10k_core_probe_fw(struct a
+ goto err_power_down;
+ }
+
++ /* calibration file is optional, don't check for any errors */
++ int calret = ath10k_fetch_cal_file(ar);
++
+ ret = ath10k_core_fetch_firmware_files(ar);
+ if (ret) {
+ ath10k_err(ar, "could not fetch firmware files (%d)\n", ret);
+@@ -1892,11 +1892,14 @@ static int ath10k_core_probe_fw(struct a
+ "could not load pre cal data: %d\n", ret);
+ }
+
+- ret = ath10k_core_get_board_id_from_otp(ar);
+- if (ret && ret != -EOPNOTSUPP) {
+- ath10k_err(ar, "failed to get board id from otp: %d\n",
+- ret);
+- goto err_free_firmware_files;
++ /* otp and board file not needed if calibration data is present */
++ if (calret) {
++ ret = ath10k_core_get_board_id_from_otp(ar);
++ if (ret && ret != -EOPNOTSUPP) {
++ ath10k_err(ar, "failed to get board id from otp: %d\n",
++ ret);
++ return ret;
++ }
+ }
+
+ ret = ath10k_core_fetch_board_file(ar);
diff --git a/package/kernel/mt76/Makefile b/package/kernel/mt76/Makefile
index 5569a5ca3e..4a81142f7a 100644
--- a/package/kernel/mt76/Makefile
+++ b/package/kernel/mt76/Makefile
@@ -1,7 +1,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=mt76
-PKG_VERSION:=2016-03-04
+PKG_VERSION:=2016-05-14
PKG_RELEASE=1
PKG_LICENSE:=GPLv2
@@ -10,12 +10,14 @@ PKG_LICENSE_FILES:=
PKG_SOURCE_URL:=https://github.com/openwrt/mt76
PKG_SOURCE_PROTO:=git
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
-PKG_SOURCE_VERSION:=7059cc27df894a4b845b6deb7c51425ffb4b7c5c
+PKG_SOURCE_VERSION:=810eef8383cf2669cd4354135fc560ccfe71786c
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.xz
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
PKG_BUILD_PARALLEL:=1
+STAMP_CONFIGURED_DEPENDS := $(STAGING_DIR)/usr/include/mac80211-backport/backport/autoconf.h
+
include $(INCLUDE_DIR)/kernel.mk
include $(INCLUDE_DIR)/package.mk
diff --git a/package/kernel/mt76/patches/000-uninitialized.patch b/package/kernel/mt76/patches/000-uninitialized.patch
deleted file mode 100644
index f27c9a2994..0000000000
--- a/package/kernel/mt76/patches/000-uninitialized.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- a/mt7603_mac.c
-+++ b/mt7603_mac.c
-@@ -474,7 +474,7 @@
- bool stbc = false;
- int n_rates = sta->n_rates;
- u8 bw, bw_prev, bw_idx = 0;
-- u16 val[8];
-+ u16 val[8] = { 0 };
- u32 w9 = mt76_rr(dev, addr + 9 * 4);
- int count;
- int i;
diff --git a/package/kernel/mwlwifi/patches/110-api_sync.patch b/package/kernel/mwlwifi/patches/110-api_sync.patch
index ed3e06a1c1..920cb8cd66 100644
--- a/package/kernel/mwlwifi/patches/110-api_sync.patch
+++ b/package/kernel/mwlwifi/patches/110-api_sync.patch
@@ -1,6 +1,30 @@
--- a/mac80211.c
+++ b/mac80211.c
-@@ -597,10 +597,13 @@ static int mwl_mac80211_get_survey(struc
+@@ -260,12 +260,12 @@ static int mwl_mac80211_config(struct ie
+ if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+ int rate = 0;
+
+- if (conf->chandef.chan->band == IEEE80211_BAND_2GHZ) {
++ if (conf->chandef.chan->band == NL80211_BAND_2GHZ) {
+ mwl_fwcmd_set_apmode(hw, AP_MODE_2_4GHZ_11AC_MIXED);
+ mwl_fwcmd_set_linkadapt_cs_mode(hw,
+ LINK_CS_STATE_CONSERV);
+ rate = mwl_rates_24[0].hw_value;
+- } else if (conf->chandef.chan->band == IEEE80211_BAND_5GHZ) {
++ } else if (conf->chandef.chan->band == NL80211_BAND_5GHZ) {
+ mwl_fwcmd_set_apmode(hw, AP_MODE_11AC);
+ mwl_fwcmd_set_linkadapt_cs_mode(hw,
+ LINK_CS_STATE_AUTO);
+@@ -333,7 +333,7 @@ static void mwl_mac80211_bss_info_change
+ if (idx)
+ idx--;
+
+- if (hw->conf.chandef.chan->band == IEEE80211_BAND_2GHZ)
++ if (hw->conf.chandef.chan->band == NL80211_BAND_2GHZ)
+ rate = mwl_rates_24[idx].hw_value;
+ else
+ rate = mwl_rates_50[idx].hw_value;
+@@ -600,10 +600,13 @@ static int mwl_mac80211_get_survey(struc
static int mwl_mac80211_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
@@ -17,3 +41,227 @@
int rc = 0;
struct mwl_priv *priv = hw->priv;
struct mwl_ampdu_stream *stream;
+--- a/fwcmd.c
++++ b/fwcmd.c
+@@ -730,9 +730,9 @@ static int mwl_fwcmd_set_country_code(st
+ bool enable = false;
+
+ if (b_inf->ie_country_ptr) {
+- if (bss_conf->chandef.chan->band == IEEE80211_BAND_2GHZ)
++ if (bss_conf->chandef.chan->band == NL80211_BAND_2GHZ)
+ a_band = false;
+- else if (bss_conf->chandef.chan->band == IEEE80211_BAND_5GHZ)
++ else if (bss_conf->chandef.chan->band == NL80211_BAND_5GHZ)
+ a_band = true;
+ else
+ return -EINVAL;
+@@ -1075,9 +1075,9 @@ int mwl_fwcmd_max_tx_power(struct ieee80
+ break;
+ }
+
+- if (channel->band == IEEE80211_BAND_2GHZ)
++ if (channel->band == NL80211_BAND_2GHZ)
+ band = FREQ_BAND_2DOT4GHZ;
+- else if (channel->band == IEEE80211_BAND_5GHZ)
++ else if (channel->band == NL80211_BAND_5GHZ)
+ band = FREQ_BAND_5GHZ;
+
+ switch (conf->chandef.width) {
+@@ -1161,9 +1161,9 @@ int mwl_fwcmd_tx_power(struct ieee80211_
+ break;
+ }
+
+- if (channel->band == IEEE80211_BAND_2GHZ)
++ if (channel->band == NL80211_BAND_2GHZ)
+ band = FREQ_BAND_2DOT4GHZ;
+- else if (channel->band == IEEE80211_BAND_5GHZ)
++ else if (channel->band == NL80211_BAND_5GHZ)
+ band = FREQ_BAND_5GHZ;
+
+ switch (conf->chandef.width) {
+@@ -1354,9 +1354,9 @@ int mwl_fwcmd_set_rf_channel(struct ieee
+ pcmd->action = cpu_to_le16(WL_SET);
+ pcmd->curr_chnl = channel->hw_value;
+
+- if (channel->band == IEEE80211_BAND_2GHZ) {
++ if (channel->band == NL80211_BAND_2GHZ) {
+ freq_band = FREQ_BAND_2DOT4GHZ;
+- } else if (channel->band == IEEE80211_BAND_5GHZ) {
++ } else if (channel->band == NL80211_BAND_5GHZ) {
+ freq_band = FREQ_BAND_5GHZ;
+ } else {
+ mutex_unlock(&priv->fwcmd_mutex);
+@@ -1923,10 +1923,10 @@ int mwl_fwcmd_set_new_stn_add(struct iee
+ }
+ ether_addr_copy(pcmd->mac_addr, sta->addr);
+
+- if (hw->conf.chandef.chan->band == IEEE80211_BAND_2GHZ)
+- rates = sta->supp_rates[IEEE80211_BAND_2GHZ];
++ if (hw->conf.chandef.chan->band == NL80211_BAND_2GHZ)
++ rates = sta->supp_rates[NL80211_BAND_2GHZ];
+ else
+- rates = sta->supp_rates[IEEE80211_BAND_5GHZ] << 5;
++ rates = sta->supp_rates[NL80211_BAND_5GHZ] << 5;
+ pcmd->peer_info.legacy_rate_bitmap = cpu_to_le32(rates);
+
+ if (sta->ht_cap.ht_supported) {
+@@ -2097,9 +2097,9 @@ int mwl_fwcmd_set_switch_channel(struct
+ if (priv->csa_active)
+ return 0;
+
+- if (channel->band == IEEE80211_BAND_2GHZ)
++ if (channel->band == NL80211_BAND_2GHZ)
+ freq_band = FREQ_BAND_2DOT4GHZ;
+- else if (channel->band == IEEE80211_BAND_5GHZ)
++ else if (channel->band == NL80211_BAND_5GHZ)
+ freq_band = FREQ_BAND_5GHZ;
+ else
+ return -EINVAL;
+--- a/main.c
++++ b/main.c
+@@ -63,20 +63,20 @@ static struct mwl_chip_info mwl_chip_tbl
+ };
+
+ static const struct ieee80211_channel mwl_channels_24[] = {
+- { .band = IEEE80211_BAND_2GHZ, .center_freq = 2412, .hw_value = 1, },
+- { .band = IEEE80211_BAND_2GHZ, .center_freq = 2417, .hw_value = 2, },
+- { .band = IEEE80211_BAND_2GHZ, .center_freq = 2422, .hw_value = 3, },
+- { .band = IEEE80211_BAND_2GHZ, .center_freq = 2427, .hw_value = 4, },
+- { .band = IEEE80211_BAND_2GHZ, .center_freq = 2432, .hw_value = 5, },
+- { .band = IEEE80211_BAND_2GHZ, .center_freq = 2437, .hw_value = 6, },
+- { .band = IEEE80211_BAND_2GHZ, .center_freq = 2442, .hw_value = 7, },
+- { .band = IEEE80211_BAND_2GHZ, .center_freq = 2447, .hw_value = 8, },
+- { .band = IEEE80211_BAND_2GHZ, .center_freq = 2452, .hw_value = 9, },
+- { .band = IEEE80211_BAND_2GHZ, .center_freq = 2457, .hw_value = 10, },
+- { .band = IEEE80211_BAND_2GHZ, .center_freq = 2462, .hw_value = 11, },
+- { .band = IEEE80211_BAND_2GHZ, .center_freq = 2467, .hw_value = 12, },
+- { .band = IEEE80211_BAND_2GHZ, .center_freq = 2472, .hw_value = 13, },
+- { .band = IEEE80211_BAND_2GHZ, .center_freq = 2484, .hw_value = 14, },
++ { .band = NL80211_BAND_2GHZ, .center_freq = 2412, .hw_value = 1, },
++ { .band = NL80211_BAND_2GHZ, .center_freq = 2417, .hw_value = 2, },
++ { .band = NL80211_BAND_2GHZ, .center_freq = 2422, .hw_value = 3, },
++ { .band = NL80211_BAND_2GHZ, .center_freq = 2427, .hw_value = 4, },
++ { .band = NL80211_BAND_2GHZ, .center_freq = 2432, .hw_value = 5, },
++ { .band = NL80211_BAND_2GHZ, .center_freq = 2437, .hw_value = 6, },
++ { .band = NL80211_BAND_2GHZ, .center_freq = 2442, .hw_value = 7, },
++ { .band = NL80211_BAND_2GHZ, .center_freq = 2447, .hw_value = 8, },
++ { .band = NL80211_BAND_2GHZ, .center_freq = 2452, .hw_value = 9, },
++ { .band = NL80211_BAND_2GHZ, .center_freq = 2457, .hw_value = 10, },
++ { .band = NL80211_BAND_2GHZ, .center_freq = 2462, .hw_value = 11, },
++ { .band = NL80211_BAND_2GHZ, .center_freq = 2467, .hw_value = 12, },
++ { .band = NL80211_BAND_2GHZ, .center_freq = 2472, .hw_value = 13, },
++ { .band = NL80211_BAND_2GHZ, .center_freq = 2484, .hw_value = 14, },
+ };
+
+ static const struct ieee80211_rate mwl_rates_24[] = {
+@@ -96,30 +96,30 @@ static const struct ieee80211_rate mwl_r
+ };
+
+ static const struct ieee80211_channel mwl_channels_50[] = {
+- { .band = IEEE80211_BAND_5GHZ, .center_freq = 5180, .hw_value = 36, },
+- { .band = IEEE80211_BAND_5GHZ, .center_freq = 5200, .hw_value = 40, },
+- { .band = IEEE80211_BAND_5GHZ, .center_freq = 5220, .hw_value = 44, },
+- { .band = IEEE80211_BAND_5GHZ, .center_freq = 5240, .hw_value = 48, },
+- { .band = IEEE80211_BAND_5GHZ, .center_freq = 5260, .hw_value = 52, },
+- { .band = IEEE80211_BAND_5GHZ, .center_freq = 5280, .hw_value = 56, },
+- { .band = IEEE80211_BAND_5GHZ, .center_freq = 5300, .hw_value = 60, },
+- { .band = IEEE80211_BAND_5GHZ, .center_freq = 5320, .hw_value = 64, },
+- { .band = IEEE80211_BAND_5GHZ, .center_freq = 5500, .hw_value = 100, },
+- { .band = IEEE80211_BAND_5GHZ, .center_freq = 5520, .hw_value = 104, },
+- { .band = IEEE80211_BAND_5GHZ, .center_freq = 5540, .hw_value = 108, },
+- { .band = IEEE80211_BAND_5GHZ, .center_freq = 5560, .hw_value = 112, },
+- { .band = IEEE80211_BAND_5GHZ, .center_freq = 5580, .hw_value = 116, },
+- { .band = IEEE80211_BAND_5GHZ, .center_freq = 5600, .hw_value = 120, },
+- { .band = IEEE80211_BAND_5GHZ, .center_freq = 5620, .hw_value = 124, },
+- { .band = IEEE80211_BAND_5GHZ, .center_freq = 5640, .hw_value = 128, },
+- { .band = IEEE80211_BAND_5GHZ, .center_freq = 5660, .hw_value = 132, },
+- { .band = IEEE80211_BAND_5GHZ, .center_freq = 5680, .hw_value = 136, },
+- { .band = IEEE80211_BAND_5GHZ, .center_freq = 5700, .hw_value = 140, },
+- { .band = IEEE80211_BAND_5GHZ, .center_freq = 5720, .hw_value = 144, },
+- { .band = IEEE80211_BAND_5GHZ, .center_freq = 5745, .hw_value = 149, },
+- { .band = IEEE80211_BAND_5GHZ, .center_freq = 5765, .hw_value = 153, },
+- { .band = IEEE80211_BAND_5GHZ, .center_freq = 5785, .hw_value = 157, },
+- { .band = IEEE80211_BAND_5GHZ, .center_freq = 5805, .hw_value = 161, },
++ { .band = NL80211_BAND_5GHZ, .center_freq = 5180, .hw_value = 36, },
++ { .band = NL80211_BAND_5GHZ, .center_freq = 5200, .hw_value = 40, },
++ { .band = NL80211_BAND_5GHZ, .center_freq = 5220, .hw_value = 44, },
++ { .band = NL80211_BAND_5GHZ, .center_freq = 5240, .hw_value = 48, },
++ { .band = NL80211_BAND_5GHZ, .center_freq = 5260, .hw_value = 52, },
++ { .band = NL80211_BAND_5GHZ, .center_freq = 5280, .hw_value = 56, },
++ { .band = NL80211_BAND_5GHZ, .center_freq = 5300, .hw_value = 60, },
++ { .band = NL80211_BAND_5GHZ, .center_freq = 5320, .hw_value = 64, },
++ { .band = NL80211_BAND_5GHZ, .center_freq = 5500, .hw_value = 100, },
++ { .band = NL80211_BAND_5GHZ, .center_freq = 5520, .hw_value = 104, },
++ { .band = NL80211_BAND_5GHZ, .center_freq = 5540, .hw_value = 108, },
++ { .band = NL80211_BAND_5GHZ, .center_freq = 5560, .hw_value = 112, },
++ { .band = NL80211_BAND_5GHZ, .center_freq = 5580, .hw_value = 116, },
++ { .band = NL80211_BAND_5GHZ, .center_freq = 5600, .hw_value = 120, },
++ { .band = NL80211_BAND_5GHZ, .center_freq = 5620, .hw_value = 124, },
++ { .band = NL80211_BAND_5GHZ, .center_freq = 5640, .hw_value = 128, },
++ { .band = NL80211_BAND_5GHZ, .center_freq = 5660, .hw_value = 132, },
++ { .band = NL80211_BAND_5GHZ, .center_freq = 5680, .hw_value = 136, },
++ { .band = NL80211_BAND_5GHZ, .center_freq = 5700, .hw_value = 140, },
++ { .band = NL80211_BAND_5GHZ, .center_freq = 5720, .hw_value = 144, },
++ { .band = NL80211_BAND_5GHZ, .center_freq = 5745, .hw_value = 149, },
++ { .band = NL80211_BAND_5GHZ, .center_freq = 5765, .hw_value = 153, },
++ { .band = NL80211_BAND_5GHZ, .center_freq = 5785, .hw_value = 157, },
++ { .band = NL80211_BAND_5GHZ, .center_freq = 5805, .hw_value = 161, },
+ };
+
+ static const struct ieee80211_rate mwl_rates_50[] = {
+@@ -478,7 +478,7 @@ static void mwl_set_caps(struct mwl_priv
+ BUILD_BUG_ON(sizeof(priv->rates_24) != sizeof(mwl_rates_24));
+ memcpy(priv->rates_24, mwl_rates_24, sizeof(mwl_rates_24));
+
+- priv->band_24.band = IEEE80211_BAND_2GHZ;
++ priv->band_24.band = NL80211_BAND_2GHZ;
+ priv->band_24.channels = priv->channels_24;
+ priv->band_24.n_channels = ARRAY_SIZE(mwl_channels_24);
+ priv->band_24.bitrates = priv->rates_24;
+@@ -487,7 +487,7 @@ static void mwl_set_caps(struct mwl_priv
+ mwl_set_ht_caps(priv, &priv->band_24);
+ mwl_set_vht_caps(priv, &priv->band_24);
+
+- hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band_24;
++ hw->wiphy->bands[NL80211_BAND_2GHZ] = &priv->band_24;
+ }
+
+ /* set up band information for 5G */
+@@ -500,7 +500,7 @@ static void mwl_set_caps(struct mwl_priv
+ BUILD_BUG_ON(sizeof(priv->rates_50) != sizeof(mwl_rates_50));
+ memcpy(priv->rates_50, mwl_rates_50, sizeof(mwl_rates_50));
+
+- priv->band_50.band = IEEE80211_BAND_5GHZ;
++ priv->band_50.band = NL80211_BAND_5GHZ;
+ priv->band_50.channels = priv->channels_50;
+ priv->band_50.n_channels = ARRAY_SIZE(mwl_channels_50);
+ priv->band_50.bitrates = priv->rates_50;
+@@ -509,7 +509,7 @@ static void mwl_set_caps(struct mwl_priv
+ mwl_set_ht_caps(priv, &priv->band_50);
+ mwl_set_vht_caps(priv, &priv->band_50);
+
+- hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &priv->band_50;
++ hw->wiphy->bands[NL80211_BAND_5GHZ] = &priv->band_50;
+ }
+ }
+
+--- a/rx.c
++++ b/rx.c
+@@ -243,7 +243,7 @@ static inline void mwl_rx_prepare_status
+ status->rate_idx = rt;
+
+ if (pdesc->channel > BAND_24_CHANNEL_NUM) {
+- status->band = IEEE80211_BAND_5GHZ;
++ status->band = NL80211_BAND_5GHZ;
+ if ((!(status->flag & RX_FLAG_HT)) &&
+ (!(status->flag & RX_FLAG_VHT))) {
+ status->rate_idx -= 5;
+@@ -251,7 +251,7 @@ static inline void mwl_rx_prepare_status
+ status->rate_idx = BAND_50_RATE_NUM - 1;
+ }
+ } else {
+- status->band = IEEE80211_BAND_2GHZ;
++ status->band = NL80211_BAND_2GHZ;
+ if ((!(status->flag & RX_FLAG_HT)) &&
+ (!(status->flag & RX_FLAG_VHT))) {
+ if (status->rate_idx >= BAND_24_RATE_NUM)
diff --git a/package/kernel/om-watchdog/files/om-watchdog.init b/package/kernel/om-watchdog/files/om-watchdog.init
index 79819ad96c..4ed178db7e 100644
--- a/package/kernel/om-watchdog/files/om-watchdog.init
+++ b/package/kernel/om-watchdog/files/om-watchdog.init
@@ -19,6 +19,7 @@ get_gpio() {
"om2p" | \
"om2p-hs" | \
"om2p-hsv2" | \
+ "om2p-hsv3" | \
"om5p-acv2")
return 12
;;
@@ -38,7 +39,8 @@ get_gpio() {
;;
"mr900" | \
"mr900v2" | \
- "mr1750")
+ "mr1750" | \
+ "mr1750v2")
return 16
;;
esac
diff --git a/package/libs/cyassl/Makefile b/package/libs/cyassl/Makefile
index 7384a3d1db..b6440f3a85 100644
--- a/package/libs/cyassl/Makefile
+++ b/package/libs/cyassl/Makefile
@@ -8,12 +8,12 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=wolfssl
-PKG_VERSION:=3.8.0
-PKG_RELEASE:=2
+PKG_VERSION:=3.9.0
+PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).zip
PKG_SOURCE_URL:=https://www.wolfssl.com/
-PKG_MD5SUM:=a73d90c5439adea97a5002a73b46ddeb
+PKG_MD5SUM:=f3396726a9befd61443c2cce216e39ba
PKG_FIXUP:=libtool
PKG_INSTALL:=1
@@ -38,12 +38,10 @@ endef
TARGET_CFLAGS += $(FPIC)
CONFIGURE_ARGS += \
- --without-zlib \
--enable-singlethreaded \
--enable-opensslextra \
--enable-sni \
--enable-ecc \
- --enable-sslv3 \
--disable-examples
#ifneq ($(CONFIG_TARGET_x86),)
diff --git a/package/libs/cyassl/patches/300-SSL_set_tlsext_host_name.patch b/package/libs/cyassl/patches/300-SSL_set_tlsext_host_name.patch
deleted file mode 100644
index a35cdadc8e..0000000000
--- a/package/libs/cyassl/patches/300-SSL_set_tlsext_host_name.patch
+++ /dev/null
@@ -1,19 +0,0 @@
---- a/wolfssl/openssl/ssl.h
-+++ b/wolfssl/openssl/ssl.h
-@@ -401,6 +401,8 @@ typedef WOLFSSL_X509_STORE_CTX X509_STOR
- /* yassl had set the default to be 500 */
- #define SSL_get_default_timeout(ctx) 500
-
-+#define SSL_set_tlsext_host_name(x, y) wolfSSL_UseSNI(x, WOLFSSL_SNI_HOST_NAME, y, strlen(y))
-+
- /* Lighthttp compatability */
-
- #ifdef HAVE_LIGHTY
-@@ -487,7 +489,6 @@ typedef WOLFSSL_ASN1_BIT_STRING ASN1_
- #define SSL_TLSEXT_ERR_NOACK alert_warning
- #define TLSEXT_NAMETYPE_host_name WOLFSSL_SNI_HOST_NAME
-
--#define SSL_set_tlsext_host_name wolfSSL_set_tlsext_host_name
- #define SSL_get_servername wolfSSL_get_servername
- #define SSL_set_SSL_CTX wolfSSL_set_SSL_CTX
- #define SSL_CTX_get_verify_callback wolfSSL_CTX_get_verify_callback
diff --git a/package/libs/cyassl/patches/300-debloat_move_SSL_set_tlsext_host_name_outside_STUNNEL.patch b/package/libs/cyassl/patches/300-debloat_move_SSL_set_tlsext_host_name_outside_STUNNEL.patch
new file mode 100644
index 0000000000..51d89f7ece
--- /dev/null
+++ b/package/libs/cyassl/patches/300-debloat_move_SSL_set_tlsext_host_name_outside_STUNNEL.patch
@@ -0,0 +1,19 @@
+--- a/wolfssl/openssl/ssl.h
++++ b/wolfssl/openssl/ssl.h
+@@ -402,6 +402,8 @@ typedef WOLFSSL_X509_STORE_CTX X509_STOR
+ /* yassl had set the default to be 500 */
+ #define SSL_get_default_timeout(ctx) 500
+
++#define SSL_set_tlsext_host_name(x, y) wolfSSL_UseSNI(x, WOLFSSL_SNI_HOST_NAME, y, strlen(y))
++
+ /* Lighthttp compatibility */
+
+ #ifdef HAVE_LIGHTY
+@@ -488,7 +490,6 @@ typedef WOLFSSL_ASN1_BIT_STRING ASN1_
+ #define SSL_TLSEXT_ERR_NOACK alert_warning
+ #define TLSEXT_NAMETYPE_host_name WOLFSSL_SNI_HOST_NAME
+
+-#define SSL_set_tlsext_host_name wolfSSL_set_tlsext_host_name
+ #define SSL_get_servername wolfSSL_get_servername
+ #define SSL_set_SSL_CTX wolfSSL_set_SSL_CTX
+ #define SSL_CTX_get_verify_callback wolfSSL_CTX_get_verify_callback
diff --git a/package/libs/cyassl/patches/400-additional_compatibility.patch b/package/libs/cyassl/patches/400-additional_compatibility.patch
index 4d75d98906..1464e9d2a8 100644
--- a/package/libs/cyassl/patches/400-additional_compatibility.patch
+++ b/package/libs/cyassl/patches/400-additional_compatibility.patch
@@ -1,6 +1,6 @@
--- a/cyassl/openssl/ssl.h
+++ b/cyassl/openssl/ssl.h
-@@ -27,6 +27,9 @@
+@@ -28,6 +28,9 @@
#define CYASSL_OPENSSL_H_
#include <cyassl/ssl.h>
diff --git a/package/libs/libusb/Makefile b/package/libs/libusb/Makefile
index cbf2935841..1b1edeef37 100644
--- a/package/libs/libusb/Makefile
+++ b/package/libs/libusb/Makefile
@@ -16,7 +16,7 @@ PKG_SOURCE_URL:=@SF/$(PKG_NAME)
PKG_MD5SUM:=1d4eb194eaaa2bcfbba28102768c7dbf
PKG_INSTALL:=1
-PKG_BUILD_PARALLEL:=1
+PKG_BUILD_PARALLEL:=0
PKG_LICENSE:=LGPL-2.1
PKG_MAINTAINER := Felix Fietkau <nbd@nbd.name>
diff --git a/package/libs/nettle/Makefile b/package/libs/nettle/Makefile
index dacf7a2b06..ecc16100cd 100644
--- a/package/libs/nettle/Makefile
+++ b/package/libs/nettle/Makefile
@@ -8,13 +8,13 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=nettle
-PKG_VERSION:=3.1.1
+PKG_VERSION:=3.2
PKG_RELEASE:=1
PKG_USE_MIPS16:=0
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=@GNU/nettle
-PKG_MD5SUM:=b40fa88dc32f37a182b6b42092ebb144
+PKG_MD5SUM:=afb15b4764ebf1b4e6d06c62bd4d29e4
PKG_LICENSE:=GPL-2.0+
PKG_LICENSE_FILES:=COPYING
diff --git a/package/network/config/ltq-vdsl-app/Makefile b/package/network/config/ltq-vdsl-app/Makefile
index ffaf942e54..6c2e2680fe 100644
--- a/package/network/config/ltq-vdsl-app/Makefile
+++ b/package/network/config/ltq-vdsl-app/Makefile
@@ -19,6 +19,8 @@ PKG_LICENSE:=BSD-2-Clause
PKG_BUILD_DEPENDS:=kmod-ltq-vdsl-vr9
+PKG_FLAGS:=nonshared
+
include $(INCLUDE_DIR)/package.mk
define Package/ltq-vdsl-app
diff --git a/package/network/services/dnsmasq/Makefile b/package/network/services/dnsmasq/Makefile
index 3f12a40cd3..3f70275b92 100644
--- a/package/network/services/dnsmasq/Makefile
+++ b/package/network/services/dnsmasq/Makefile
@@ -8,12 +8,12 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=dnsmasq
-PKG_VERSION:=2.75
-PKG_RELEASE:=7
+PKG_VERSION:=2.76
+PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
PKG_SOURCE_URL:=http://thekelleys.org.uk/dnsmasq
-PKG_MD5SUM:=887236f1ddde6eb57cdb9d01916c9f72
+PKG_MD5SUM:=00f5ee66b4e4b7f14538bf62ae3c9461
PKG_LICENSE:=GPL-2.0
PKG_LICENSE_FILES:=COPYING
diff --git a/package/network/services/dnsmasq/patches/100-fix-dhcp-no-address-warning.patch b/package/network/services/dnsmasq/patches/100-fix-dhcp-no-address-warning.patch
index f5b5ca04ec..5fc62ffab3 100644
--- a/package/network/services/dnsmasq/patches/100-fix-dhcp-no-address-warning.patch
+++ b/package/network/services/dnsmasq/patches/100-fix-dhcp-no-address-warning.patch
@@ -1,15 +1,15 @@
--- a/src/dhcp.c
+++ b/src/dhcp.c
-@@ -146,7 +146,7 @@ void dhcp_packet(time_t now, int pxe_fd)
- struct iovec iov;
+@@ -147,7 +147,7 @@ void dhcp_packet(time_t now, int pxe_fd)
ssize_t sz;
int iface_index = 0, unicast_dest = 0, is_inform = 0;
+ int rcvd_iface_index;
- struct in_addr iface_addr;
+ struct in_addr iface_addr, *addrp = NULL;
struct iface_param parm;
#ifdef HAVE_LINUX_NETWORK
struct arpreq arp_req;
-@@ -275,11 +275,9 @@ void dhcp_packet(time_t now, int pxe_fd)
+@@ -277,11 +277,9 @@ void dhcp_packet(time_t now, int pxe_fd)
{
ifr.ifr_addr.sa_family = AF_INET;
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
@@ -23,7 +23,7 @@
}
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
-@@ -298,7 +296,7 @@ void dhcp_packet(time_t now, int pxe_fd)
+@@ -300,7 +298,7 @@ void dhcp_packet(time_t now, int pxe_fd)
parm.relay_local.s_addr = 0;
parm.ind = iface_index;
@@ -32,7 +32,7 @@
{
/* If we failed to match the primary address of the interface, see if we've got a --listen-address
for a secondary */
-@@ -318,6 +316,12 @@ void dhcp_packet(time_t now, int pxe_fd)
+@@ -320,6 +318,12 @@ void dhcp_packet(time_t now, int pxe_fd)
complete_context(match.addr, iface_index, NULL, match.netmask, match.broadcast, &parm);
}
diff --git a/package/network/services/dnsmasq/patches/210-dnssec-improve-timestamp-heuristic.patch b/package/network/services/dnsmasq/patches/210-dnssec-improve-timestamp-heuristic.patch
index 81fbf185b1..ca5a806696 100644
--- a/package/network/services/dnsmasq/patches/210-dnssec-improve-timestamp-heuristic.patch
+++ b/package/network/services/dnsmasq/patches/210-dnssec-improve-timestamp-heuristic.patch
@@ -10,7 +10,7 @@ Signed-off-by: Steven Barth <steven@midlink.org>
--- a/src/dnssec.c
+++ b/src/dnssec.c
-@@ -429,17 +429,24 @@ static time_t timestamp_time;
+@@ -462,17 +462,24 @@ static time_t timestamp_time;
int setup_timestamp(void)
{
struct stat statbuf;
@@ -36,7 +36,7 @@ Signed-off-by: Steven Barth <steven@midlink.org>
{
/* time already OK, update timestamp, and do key checking from the start. */
if (utime(daemon->timestamp_file, NULL) == -1)
-@@ -460,7 +467,7 @@ int setup_timestamp(void)
+@@ -493,7 +500,7 @@ int setup_timestamp(void)
close(fd);
diff --git a/package/network/services/dnsmasq/patches/230-fix-poll-h-include-warning-on-musl.patch b/package/network/services/dnsmasq/patches/230-fix-poll-h-include-warning-on-musl.patch
new file mode 100644
index 0000000000..19300f7d66
--- /dev/null
+++ b/package/network/services/dnsmasq/patches/230-fix-poll-h-include-warning-on-musl.patch
@@ -0,0 +1,18 @@
+dnsmasq: fix warning with poll.h include on musl
+
+Warning is:
+ #warning redirecting incorrect #include <sys/poll.h> to <poll.h>
+
+Signed-off-by: Kevin Darbyshire-Bryant <kevin@darbyshire-bryant.me.uk>
+
+--- a/src/dnsmasq.h
++++ b/src/dnsmasq.h
+@@ -82,7 +82,7 @@ typedef unsigned long long u64;
+ #if defined(HAVE_SOLARIS_NETWORK)
+ # include <sys/sockio.h>
+ #endif
+-#include <sys/poll.h>
++#include <poll.h>
+ #include <sys/wait.h>
+ #include <sys/time.h>
+ #include <sys/un.h>
diff --git a/package/network/services/dropbear/Makefile b/package/network/services/dropbear/Makefile
index 8d4e7bc7fa..c873611688 100644
--- a/package/network/services/dropbear/Makefile
+++ b/package/network/services/dropbear/Makefile
@@ -8,14 +8,14 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=dropbear
-PKG_VERSION:=2015.71
-PKG_RELEASE:=3
+PKG_VERSION:=2016.73
+PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
PKG_SOURCE_URL:= \
http://matt.ucc.asn.au/dropbear/releases/ \
https://dropbear.nl/mirror/releases/
-PKG_MD5SUM:=2ccc0a2f3e37ca221db12c5af6a88137
+PKG_MD5SUM:=8d6d78ce60ca52350ec04fcbd711ce9b
PKG_LICENSE:=MIT
PKG_LICENSE_FILES:=LICENSE libtomcrypt/LICENSE libtommath/LICENSE
diff --git a/package/network/services/dropbear/patches/120-openwrt_options.patch b/package/network/services/dropbear/patches/120-openwrt_options.patch
index f020208090..f16aaf001e 100644
--- a/package/network/services/dropbear/patches/120-openwrt_options.patch
+++ b/package/network/services/dropbear/patches/120-openwrt_options.patch
@@ -61,7 +61,7 @@
/* ECDSA is significantly faster than RSA or DSS. Compiling in ECC
* code (either ECDSA or ECDH) increases binary size - around 30kB
* on x86-64 */
-@@ -189,7 +189,7 @@ If you test it please contact the Dropbe
+@@ -194,7 +194,7 @@ If you test it please contact the Dropbe
/* Whether to print the message of the day (MOTD). This doesn't add much code
* size */
@@ -70,7 +70,7 @@
/* The MOTD file path */
#ifndef MOTD_FILENAME
-@@ -237,7 +237,7 @@ Homedir is prepended unless path begins
+@@ -242,7 +242,7 @@ Homedir is prepended unless path begins
* note that it will be provided for all "hidden" client-interactive
* style prompts - if you want something more sophisticated, use
* SSH_ASKPASS instead. Comment out this var to remove this functionality.*/
diff --git a/package/network/services/dropbear/patches/130-ssh_ignore_o_and_x_args.patch b/package/network/services/dropbear/patches/130-ssh_ignore_o_and_x_args.patch
deleted file mode 100644
index bf1641b8bf..0000000000
--- a/package/network/services/dropbear/patches/130-ssh_ignore_o_and_x_args.patch
+++ /dev/null
@@ -1,21 +0,0 @@
---- a/cli-runopts.c
-+++ b/cli-runopts.c
-@@ -284,6 +284,10 @@ void cli_getopts(int argc, char ** argv)
- debug_trace = 1;
- break;
- #endif
-+ case 'o':
-+ next = &dummy;
-+ case 'x':
-+ break;
- case 'F':
- case 'e':
- #ifndef ENABLE_USER_ALGO_LIST
-@@ -301,7 +305,6 @@ void cli_getopts(int argc, char ** argv)
- print_version();
- exit(EXIT_SUCCESS);
- break;
-- case 'o':
- case 'b':
- next = &dummy;
- default:
diff --git a/package/network/services/dropbear/patches/130-ssh_ignore_x_args.patch b/package/network/services/dropbear/patches/130-ssh_ignore_x_args.patch
new file mode 100644
index 0000000000..ab09c2f3dc
--- /dev/null
+++ b/package/network/services/dropbear/patches/130-ssh_ignore_x_args.patch
@@ -0,0 +1,11 @@
+--- a/cli-runopts.c
++++ b/cli-runopts.c
+@@ -296,6 +296,8 @@ void cli_getopts(int argc, char ** argv)
+ debug_trace = 1;
+ break;
+ #endif
++ case 'x':
++ break;
+ case 'F':
+ case 'e':
+ #ifndef ENABLE_USER_ALGO_LIST
diff --git a/package/network/services/dropbear/patches/140-disable_assert.patch b/package/network/services/dropbear/patches/140-disable_assert.patch
index 667d69cb38..78b54acfa0 100644
--- a/package/network/services/dropbear/patches/140-disable_assert.patch
+++ b/package/network/services/dropbear/patches/140-disable_assert.patch
@@ -1,6 +1,6 @@
--- a/dbutil.h
+++ b/dbutil.h
-@@ -88,7 +88,11 @@ int m_str_to_uint(const char* str, unsig
+@@ -78,7 +78,11 @@ int m_str_to_uint(const char* str, unsig
#define DEF_MP_INT(X) mp_int X = {0, 0, 0, NULL}
/* Dropbear assertion */
diff --git a/package/network/services/dropbear/patches/500-set-default-path.patch b/package/network/services/dropbear/patches/500-set-default-path.patch
index 3f65250a97..da6b9ae0ce 100644
--- a/package/network/services/dropbear/patches/500-set-default-path.patch
+++ b/package/network/services/dropbear/patches/500-set-default-path.patch
@@ -1,6 +1,6 @@
--- a/options.h
+++ b/options.h
-@@ -347,7 +347,9 @@ be overridden at runtime with -I. 0 disa
+@@ -352,7 +352,9 @@ be overridden at runtime with -I. 0 disa
#define DEFAULT_IDLE_TIMEOUT 0
/* The default path. This will often get replaced by the shell */
diff --git a/package/network/services/mdns/Makefile b/package/network/services/mdns/Makefile
index 2f467e3e4c..ec4efa7d4c 100644
--- a/package/network/services/mdns/Makefile
+++ b/package/network/services/mdns/Makefile
@@ -17,7 +17,7 @@ PKG_SOURCE_URL=$(OPENWRT_GIT)/project/mdnsd.git
PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=ae8773477c31b741ba8b47f8898e4c0a1c834b85
-PKG_MAINTAINER:=John Crispin <blogic@openwrt.org>
+PKG_MAINTAINER:=John Crispin <john@phrozen.org>
PKG_LICENSE:=LGPL-2.1
include $(INCLUDE_DIR)/package-seccomp.mk
diff --git a/package/network/services/openvpn/Makefile b/package/network/services/openvpn/Makefile
index 6c68b49ac4..19f78bc508 100644
--- a/package/network/services/openvpn/Makefile
+++ b/package/network/services/openvpn/Makefile
@@ -9,12 +9,12 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=openvpn
-PKG_VERSION:=2.3.10
+PKG_VERSION:=2.3.11
PKG_RELEASE:=1
PKG_SOURCE_URL:=http://swupdate.openvpn.net/community/releases
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
-PKG_MD5SUM:=8831ded42db4317e287157b6b8cba74c
+PKG_MD5SUM:=0f5f1ca1dc5743fa166d93dd4ec952f014b5f33bafd88f0ea34b455cae1434a7
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_VERSION)
@@ -73,7 +73,6 @@ define Build/Configure
--disable-plugins \
--disable-debug \
--disable-pkcs11 \
- --enable-password-save \
$(if $(CONFIG_OPENVPN_$(BUILD_VARIANT)_ENABLE_LZO),--enable,--disable)-lzo \
$(if $(CONFIG_OPENVPN_$(BUILD_VARIANT)_ENABLE_X509_ALT_USERNAME),enable,disable-x509-alt-username)-ssl \
$(if $(CONFIG_OPENVPN_$(BUILD_VARIANT)_ENABLE_SERVER),--enable,--disable)-server \
diff --git a/package/network/services/openvpn/files/openvpn.init b/package/network/services/openvpn/files/openvpn.init
index 5396d0bf47..6dac7b3fa1 100644
--- a/package/network/services/openvpn/files/openvpn.init
+++ b/package/network/services/openvpn/files/openvpn.init
@@ -121,7 +121,7 @@ start_instance() {
reneg_bytes reneg_pkts reneg_sec \
replay_persist replay_window resolv_retry route route_delay route_gateway \
route_metric route_pre_down route_up rport script_security secret server server_bridge setenv shaper sndbuf \
- socks_proxy status status_version syslog tcp_queue_limit tls_auth \
+ socks_proxy status status_version syslog tcp_queue_limit tls_auth tls_version_min \
tls_cipher tls_remote tls_timeout tls_verify tmp_dir topology tran_window \
tun_mtu tun_mtu_extra txqueuelen user verb down push up \
verify_x509_name x509_username_field \
diff --git a/package/network/services/openvpn/patches/100-polarssl-disable-runtime-version-check.patch b/package/network/services/openvpn/patches/100-polarssl-disable-runtime-version-check.patch
index 73ab40649d..bd8e5b780d 100644
--- a/package/network/services/openvpn/patches/100-polarssl-disable-runtime-version-check.patch
+++ b/package/network/services/openvpn/patches/100-polarssl-disable-runtime-version-check.patch
@@ -1,6 +1,6 @@
--- a/src/openvpn/ssl_polarssl.c
+++ b/src/openvpn/ssl_polarssl.c
-@@ -1153,7 +1153,7 @@ const char *
+@@ -1151,7 +1151,7 @@ const char *
get_ssl_library_version(void)
{
static char polar_version[30];
diff --git a/package/network/services/openvpn/patches/101-remove_polarssl_debug_call.patch b/package/network/services/openvpn/patches/101-remove_polarssl_debug_call.patch
new file mode 100644
index 0000000000..3cef32395e
--- /dev/null
+++ b/package/network/services/openvpn/patches/101-remove_polarssl_debug_call.patch
@@ -0,0 +1,21 @@
+openvpn: remove call to PolarSSL debug function
+
+OpenVPN >=2.3.11 uses PolarSSL debug functions for improved logging.
+This requires that PolarSSL is built with POLARSSL_DEBUG_C, which increases
+its size significantly.
+
+This change does not impact OpenVPN operation, see:
+https://sourceforge.net/p/openvpn/mailman/message/35153943/
+
+Signed-off-by: Magnus Kroken <mkroken@gmail.com>
+
+--- a/src/openvpn/ssl_polarssl.c
++++ b/src/openvpn/ssl_polarssl.c
+@@ -742,7 +742,7 @@ void key_state_ssl_init(struct key_state
+ if (polar_ok(ssl_init(ks_ssl->ctx)))
+ {
+ /* Initialise SSL context */
+- debug_set_threshold(3);
++ /*debug_set_threshold(3);*/
+ ssl_set_dbg (ks_ssl->ctx, my_debug, NULL);
+ ssl_set_endpoint (ks_ssl->ctx, ssl_ctx->endpoint);
diff --git a/package/network/utils/curl/Makefile b/package/network/utils/curl/Makefile
index af38ed4aed..4b41ac33e9 100644
--- a/package/network/utils/curl/Makefile
+++ b/package/network/utils/curl/Makefile
@@ -8,7 +8,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=curl
-PKG_VERSION:=7.48.0
+PKG_VERSION:=7.49.0
PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
@@ -18,7 +18,7 @@ PKG_SOURCE_URL:=http://curl.haxx.se/download/ \
ftp://ftp.planetmirror.com/pub/curl/ \
http://www.mirrormonster.com/curl/download/ \
http://curl.mirrors.cyberservers.net/download/
-PKG_MD5SUM:=d42e0fc34a5cace5739631cc040974fe
+PKG_MD5SUM:=7416aaff4a9210b43edda7615ffa4169
PKG_LICENSE:=MIT
PKG_LICENSE_FILES:=COPYING
@@ -109,7 +109,6 @@ CONFIGURE_ARGS += \
--enable-shared \
--enable-static \
--disable-manual \
- --without-ca-bundle \
--without-nss \
--without-libmetalink \
--without-librtmp \
@@ -117,11 +116,11 @@ CONFIGURE_ARGS += \
$(call autoconf_bool,CONFIG_IPV6,ipv6) \
\
$(if $(CONFIG_LIBCURL_AXTLS),--with-axtls="$(STAGING_DIR)/usr" --without-ca-path,--without-axtls) \
- $(if $(CONFIG_LIBCURL_CYASSL),--with-cyassl="$(STAGING_DIR)/usr" --without-ca-path,--without-cyassl) \
- $(if $(CONFIG_LIBCURL_GNUTLS),--with-gnutls="$(STAGING_DIR)/usr" --with-ca-path=/etc/ssl/certs,--without-gnutls) \
- $(if $(CONFIG_LIBCURL_OPENSSL),--with-ssl="$(STAGING_DIR)/usr" --with-ca-path=/etc/ssl/certs,--without-ssl) \
- $(if $(CONFIG_LIBCURL_POLARSSL),--with-polarssl="$(STAGING_DIR)/usr" --with-ca-path=/etc/ssl/certs,--without-polarssl) \
- $(if $(CONFIG_LIBCURL_MBEDTLS),--with-mbedtls="$(STAGING_DIR)/usr" --without-ca-path,--without-mbedtls) \
+ $(if $(CONFIG_LIBCURL_CYASSL),--with-cyassl="$(STAGING_DIR)/usr" --without-ca-path --with-ca-bundle=/etc/ssl/certs/ca-certificates.crt,--without-cyassl) \
+ $(if $(CONFIG_LIBCURL_GNUTLS),--with-gnutls="$(STAGING_DIR)/usr" --without-ca-bundle --with-ca-path=/etc/ssl/certs,--without-gnutls) \
+ $(if $(CONFIG_LIBCURL_OPENSSL),--with-ssl="$(STAGING_DIR)/usr" --without-ca-bundle --with-ca-path=/etc/ssl/certs,--without-ssl) \
+ $(if $(CONFIG_LIBCURL_POLARSSL),--with-polarssl="$(STAGING_DIR)/usr" --without-ca-bundle --with-ca-path=/etc/ssl/certs,--without-polarssl) \
+ $(if $(CONFIG_LIBCURL_MBEDTLS),--with-mbedtls="$(STAGING_DIR)/usr" --without-ca-path --with-ca-bundle=/etc/ssl/certs/ca-certificates.crt,--without-mbedtls) \
\
$(if $(CONFIG_LIBCURL_LIBIDN),--with-libidn="$(STAGING_DIR)/usr",--without-libidn) \
$(if $(CONFIG_LIBCURL_SSH2),--with-libssh2="$(STAGING_DIR)/usr",--without-libssh2) \
diff --git a/package/network/utils/curl/patches/200-no_docs_tests.patch b/package/network/utils/curl/patches/200-no_docs_tests.patch
index 4ac5badf60..6f86d4c6cb 100644
--- a/package/network/utils/curl/patches/200-no_docs_tests.patch
+++ b/package/network/utils/curl/patches/200-no_docs_tests.patch
@@ -3,8 +3,8 @@
@@ -150,7 +150,7 @@ CLEANFILES = $(VC6_LIBDSP) $(VC6_SRCDSP)
bin_SCRIPTS = curl-config
- SUBDIRS = lib src include scripts
--DIST_SUBDIRS = $(SUBDIRS) tests packages docs
+ SUBDIRS = lib src include
+-DIST_SUBDIRS = $(SUBDIRS) tests packages docs scripts
+DIST_SUBDIRS = $(SUBDIRS) packages
pkgconfigdir = $(libdir)/pkgconfig
@@ -14,9 +14,9 @@
@@ -611,7 +611,7 @@ CLEANFILES = $(VC6_LIBDSP) $(VC6_SRCDSP)
bin_SCRIPTS = curl-config
- SUBDIRS = lib src include scripts
--DIST_SUBDIRS = $(SUBDIRS) tests packages docs
+ SUBDIRS = lib src include
+-DIST_SUBDIRS = $(SUBDIRS) tests packages docs scripts
+DIST_SUBDIRS = $(SUBDIRS) packages
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libcurl.pc
- LIB_VTLS_CFILES = vtls/openssl.c vtls/gtls.c vtls/vtls.c vtls/nss.c \
+ LIB_VAUTH_CFILES = vauth/vauth.c vauth/cleartext.c vauth/cram.c \
diff --git a/package/network/utils/curl/patches/300-fix-disable-crypto-auth.patch b/package/network/utils/curl/patches/300-fix-disable-crypto-auth.patch
deleted file mode 100644
index 5c0a37e760..0000000000
--- a/package/network/utils/curl/patches/300-fix-disable-crypto-auth.patch
+++ /dev/null
@@ -1,25 +0,0 @@
---- a/lib/curl_ntlm_msgs.c
-+++ b/lib/curl_ntlm_msgs.c
-@@ -573,7 +573,7 @@ CURLcode Curl_sasl_create_ntlm_type3_mes
- else
- #endif
-
--#if USE_NTRESPONSES && USE_NTLM2SESSION
-+#if USE_NTRESPONSES && USE_NTLM2SESSION && !defined(CURL_DISABLE_CRYPTO_AUTH)
- /* We don't support NTLM2 if we don't have USE_NTRESPONSES */
- if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) {
- unsigned char ntbuffer[0x18];
---- a/lib/vtls/vtls.c
-+++ b/lib/vtls/vtls.c
-@@ -921,9 +921,9 @@ CURLcode Curl_ssl_md5sum(unsigned char *
- unsigned char *md5sum, /* output */
- size_t md5len)
- {
--#ifdef curlssl_md5sum
-+#if defined(curlssl_md5sum)
- curlssl_md5sum(tmp, tmplen, md5sum, md5len);
--#else
-+#elif !defined(CURL_DISABLE_CRYPTO_AUTH)
- MD5_context *MD5pw;
-
- (void) md5len;
diff --git a/package/network/utils/curl/patches/310-polarssl-disable-runtime-version-check.patch b/package/network/utils/curl/patches/310-polarssl-disable-runtime-version-check.patch
index 7f7937b950..bb622ee78d 100644
--- a/package/network/utils/curl/patches/310-polarssl-disable-runtime-version-check.patch
+++ b/package/network/utils/curl/patches/310-polarssl-disable-runtime-version-check.patch
@@ -1,6 +1,6 @@
--- a/lib/vtls/polarssl.c
+++ b/lib/vtls/polarssl.c
-@@ -592,7 +592,7 @@ void Curl_polarssl_session_free(void *pt
+@@ -653,7 +653,7 @@ void Curl_polarssl_session_free(void *pt
size_t Curl_polarssl_version(char *buffer, size_t size)
{
@@ -11,7 +11,7 @@
version>>24, (version>>16)&0xff, (version>>8)&0xff);
--- a/lib/vtls/mbedtls.c
+++ b/lib/vtls/mbedtls.c
-@@ -712,7 +712,7 @@ void Curl_mbedtls_session_free(void *ptr
+@@ -701,7 +701,7 @@ void Curl_mbedtls_session_free(void *ptr
size_t Curl_mbedtls_version(char *buffer, size_t size)
{
diff --git a/package/network/utils/iperf/Makefile b/package/network/utils/iperf/Makefile
index 614384916c..cfd069ff54 100644
--- a/package/network/utils/iperf/Makefile
+++ b/package/network/utils/iperf/Makefile
@@ -8,13 +8,13 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=iperf
-PKG_VERSION:=2.0.5
+PKG_VERSION:=2.0.8
PKG_RELEASE:=1
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_VERSION)
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
-PKG_SOURCE_URL:=@SF/$(PKG_NAME)
-PKG_MD5SUM:=44b5536b67719f4250faed632a3cd016
+PKG_SOURCE_URL:=@SF/iperf2
+PKG_MD5SUM:=e5887f799d8dc64a974c6c2f2e5cc339
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
PKG_LICENSE:=BSD-3-Clause
@@ -24,64 +24,29 @@ PKG_BUILD_PARALLEL:=1
include $(INCLUDE_DIR)/uclibc++.mk
include $(INCLUDE_DIR)/package.mk
-define Package/iperf/Default
+define Package/iperf
SECTION:=net
CATEGORY:=Network
- DEPENDS:= $(CXX_DEPENDS)
+ DEPENDS:= $(CXX_DEPENDS) +libpthread
TITLE:=Internet Protocol bandwidth measuring tool
- URL:=http://sourceforge.net/projects/iperf/
+ URL:=http://sourceforge.net/projects/iperf2/
endef
-define Package/iperf/Default/description
+define Package/iperf/description
Iperf is a modern alternative for measuring TCP and UDP bandwidth
performance, allowing the tuning of various parameters and
characteristics.
endef
-define Package/iperf
-$(call Package/iperf/Default)
- TITLE+= (with single thread support)
- VARIANT:=single
-endef
-
-define Package/iperf/description
-$(call Package/iperf/Default/description)
- This package is built with single thread support.
-endef
-
-define Package/iperf-mt
-$(call Package/iperf/Default)
- DEPENDS+= +libpthread
- TITLE+= (with multithread support)
- VARIANT:=mt
-endef
-
-define Package/iperf-mt/description
-$(call Package/iperf/Default/description)
- This package is built with multithread support.
-endef
-
+TARGET_CFLAGS += -D_GNU_SOURCE
CONFIGURE_ARGS += --disable-multicast
-CONFIGURE_VARS += ac_cv_func_malloc_0_nonnull=yes
-
-ifeq ($(BUILD_VARIANT),single)
- CONFIGURE_ARGS += --disable-threads
-else
- CONFIGURE_ARGS += --enable-threads=posix
- CONFIGURE_VARS += ac_cv_func_pthread_cancel=no
-endif
CONFIGURE_VARS += CXXFLAGS="$$$$CXXFLAGS -fno-rtti"
-
-ifeq ($(BUILD_VARIANT),mt)
- CONFIGURE_VARS += LIBS="-lpthread"
-endif
+CONFIGURE_VARS += LIBS="-lpthread"
define Package/iperf/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/iperf $(1)/usr/bin/iperf
endef
-Package/iperf-mt/install = $(Package/iperf/install)
$(eval $(call BuildPackage,iperf))
-$(eval $(call BuildPackage,iperf-mt))
diff --git a/package/network/utils/iperf/patches/001-set-report-next-time-in-single-thread-mode.patch b/package/network/utils/iperf/patches/001-set-report-next-time-in-single-thread-mode.patch
deleted file mode 100644
index c61c75494a..0000000000
--- a/package/network/utils/iperf/patches/001-set-report-next-time-in-single-thread-mode.patch
+++ /dev/null
@@ -1,14 +0,0 @@
---- a/src/Reporter.c
-+++ b/src/Reporter.c
-@@ -308,6 +308,11 @@ ReportHeader* InitReport( thread_Setting
- #else
- // set start time
- gettimeofday( &(reporthdr->report.startTime), NULL );
-+
-+ // set next time
-+ reporthdr->report.nextTime = reporthdr->report.startTime;
-+ TimeAdd( reporthdr->report.nextTime, reporthdr->report.intervalTime );
-+
- /*
- * Process the report in this thread
- */
diff --git a/package/network/utils/iperf/patches/002-format-security.patch b/package/network/utils/iperf/patches/002-format-security.patch
deleted file mode 100644
index 9331e54f5b..0000000000
--- a/package/network/utils/iperf/patches/002-format-security.patch
+++ /dev/null
@@ -1,96 +0,0 @@
-Description: iperf format string FTBFS with -Werror=format-security
- Reported by Didier Raboud <odyx@debian.org>
-Author: Simon Paillard <spaillard@debian.org>
-Bug-Debian: http://bugs.debian.org/643408
-
---- a/compat/Thread.c
-+++ b/compat/Thread.c
-@@ -381,7 +381,7 @@ int thread_release_nonterm( int interrup
- Condition_Lock( thread_sNum_cond );
- thread_sNum -= nonterminating_num;
- if ( thread_sNum > 1 && nonterminating_num > 0 && interrupt != 0 ) {
-- fprintf( stderr, wait_server_threads );
-+ fprintf( stderr, "%s", wait_server_threads );
- }
- nonterminating_num = 0;
- Condition_Signal( &thread_sNum_cond );
---- a/src/ReportDefault.c
-+++ b/src/ReportDefault.c
-@@ -78,7 +78,7 @@ void reporter_printstats( Transfer_Info
- if ( stats->mUDP != (char)kMode_Server ) {
- // TCP Reporting
- if( !header_printed ) {
-- printf( report_bw_header);
-+ printf( "%s", report_bw_header);
- header_printed = 1;
- }
- printf( report_bw_format, stats->transferID,
-@@ -87,7 +87,7 @@ void reporter_printstats( Transfer_Info
- } else {
- // UDP Reporting
- if( !header_printed ) {
-- printf( report_bw_jitter_loss_header);
-+ printf( "%s", report_bw_jitter_loss_header);
- header_printed = 1;
- }
- printf( report_bw_jitter_loss_format, stats->transferID,
-@@ -159,7 +159,7 @@ void reporter_reportsettings( ReporterDa
- (data->mThreadMode == kMode_Listener ? 0 : 1) );
- win_requested = data->mTCPWin;
-
-- printf( separator_line );
-+ printf( "%s", separator_line );
- if ( data->mThreadMode == kMode_Listener ) {
- printf( server_port,
- (isUDP( data ) ? "UDP" : "TCP"),
-@@ -198,7 +198,7 @@ void reporter_reportsettings( ReporterDa
- printf( warn_window_requested, buffer );
- }
- printf( "\n" );
-- printf( separator_line );
-+ printf( "%s", separator_line );
- }
-
- /*
-@@ -286,7 +286,7 @@ void reporter_reportMSS( int inMSS, thre
- } else if ( checkMSS_MTU( inMSS, 576 ) ) {
- net = "minimum";
- mtu = 576;
-- printf( warn_no_pathmtu );
-+ printf( "%s", warn_no_pathmtu );
- } else {
- mtu = inMSS + 40;
- net = "unknown interface";
---- a/src/Reporter.c
-+++ b/src/Reporter.c
-@@ -901,7 +901,7 @@ void PrintMSS( ReporterData *stats ) {
- } else if ( checkMSS_MTU( inMSS, 576 ) ) {
- net = "minimum";
- mtu = 576;
-- printf( warn_no_pathmtu );
-+ printf( "%s", warn_no_pathmtu );
- } else {
- mtu = inMSS + 40;
- net = "unknown interface";
---- a/src/Settings.cpp
-+++ b/src/Settings.cpp
-@@ -375,8 +375,8 @@ void Settings_Interpret( char option, co
- break;
-
- case 'h': // print help and exit
-- fprintf(stderr, usage_long1);
-- fprintf(stderr, usage_long2);
-+ fprintf(stderr, "%s", usage_long1);
-+ fprintf(stderr, "%s", usage_long2);
- exit(1);
- break;
-
-@@ -482,7 +482,7 @@ void Settings_Interpret( char option, co
- break;
-
- case 'v': // print version and exit
-- fprintf( stderr, version );
-+ fprintf( stderr, "%s", version );
- exit(1);
- break;
-
diff --git a/package/network/utils/iw/patches/001-nl80211_h_sync.patch b/package/network/utils/iw/patches/001-nl80211_h_sync.patch
index 7de225859b..e5ea8f7c8a 100644
--- a/package/network/utils/iw/patches/001-nl80211_h_sync.patch
+++ b/package/network/utils/iw/patches/001-nl80211_h_sync.patch
@@ -8,7 +8,17 @@
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
-@@ -328,7 +329,15 @@
+@@ -321,14 +322,24 @@
+ * @NL80211_CMD_GET_SCAN: get scan results
+ * @NL80211_CMD_TRIGGER_SCAN: trigger a new scan with the given parameters
+ * %NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the
+- * probe requests at CCK rate or not.
++ * probe requests at CCK rate or not. %NL80211_ATTR_MAC can be used to
++ * specify a BSSID to scan for; if not included, the wildcard BSSID will
++ * be used.
+ * @NL80211_CMD_NEW_SCAN_RESULTS: scan notification (as a reply to
+ * NL80211_CMD_GET_SCAN and on the "scan" multicast group)
+ * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons,
* partial scan results may be available
*
* @NL80211_CMD_START_SCHED_SCAN: start a scheduled scan at certain
@@ -25,7 +35,82 @@
* Like with normal scans, if SSIDs (%NL80211_ATTR_SCAN_SSIDS)
* are passed, they are used in the probe requests. For
* broadcast, a broadcast SSID must be passed (ie. an empty
-@@ -1761,6 +1770,22 @@ enum nl80211_commands {
+@@ -418,7 +429,11 @@
+ * @NL80211_CMD_ASSOCIATE: association request and notification; like
+ * NL80211_CMD_AUTHENTICATE but for Association and Reassociation
+ * (similar to MLME-ASSOCIATE.request, MLME-REASSOCIATE.request,
+- * MLME-ASSOCIATE.confirm or MLME-REASSOCIATE.confirm primitives).
++ * MLME-ASSOCIATE.confirm or MLME-REASSOCIATE.confirm primitives). The
++ * %NL80211_ATTR_PREV_BSSID attribute is used to specify whether the
++ * request is for the initial association to an ESS (that attribute not
++ * included) or for reassociation within the ESS (that attribute is
++ * included).
+ * @NL80211_CMD_DEAUTHENTICATE: deauthentication request and notification; like
+ * NL80211_CMD_AUTHENTICATE but for Deauthentication frames (similar to
+ * MLME-DEAUTHENTICATION.request and MLME-DEAUTHENTICATE.indication
+@@ -468,6 +483,9 @@
+ * set of BSSID,frequency parameters is used (i.e., either the enforcing
+ * %NL80211_ATTR_MAC,%NL80211_ATTR_WIPHY_FREQ or the less strict
+ * %NL80211_ATTR_MAC_HINT and %NL80211_ATTR_WIPHY_FREQ_HINT).
++ * %NL80211_ATTR_PREV_BSSID can be used to request a reassociation within
++ * the ESS in case the device is already associated and an association with
++ * a different BSS is desired.
+ * Background scan period can optionally be
+ * specified in %NL80211_ATTR_BG_SCAN_PERIOD,
+ * if not specified default background scan configuration
+@@ -811,6 +829,10 @@
+ * as an event to indicate changes for devices with wiphy-specific regdom
+ * management.
+ *
++ * @NL80211_CMD_ABORT_SCAN: Stop an ongoing scan. Returns -ENOENT if a scan is
++ * not running. The driver indicates the status of the scan through
++ * cfg80211_scan_done().
++ *
+ * @NL80211_CMD_MAX: highest used command number
+ * @__NL80211_CMD_AFTER_LAST: internal use
+ */
+@@ -997,6 +1019,8 @@ enum nl80211_commands {
+
+ NL80211_CMD_WIPHY_REG_CHANGE,
+
++ NL80211_CMD_ABORT_SCAN,
++
+ /* add new commands above here */
+
+ /* used to define NL80211_CMD_MAX below */
+@@ -1270,8 +1294,11 @@ enum nl80211_commands {
+ * @NL80211_ATTR_RESP_IE: (Re)association response information elements as
+ * sent by peer, for ROAM and successful CONNECT events.
+ *
+- * @NL80211_ATTR_PREV_BSSID: previous BSSID, to be used by in ASSOCIATE
+- * commands to specify using a reassociate frame
++ * @NL80211_ATTR_PREV_BSSID: previous BSSID, to be used in ASSOCIATE and CONNECT
++ * commands to specify a request to reassociate within an ESS, i.e., to use
++ * Reassociate Request frame (with the value of this attribute in the
++ * Current AP address field) instead of Association Request frame which is
++ * used for the initial association to an ESS.
+ *
+ * @NL80211_ATTR_KEY: key information in a nested attribute with
+ * %NL80211_KEY_* sub-attributes
+@@ -1712,6 +1739,8 @@ enum nl80211_commands {
+ * underlying device supports these minimal RRM features:
+ * %NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES,
+ * %NL80211_FEATURE_QUIET,
++ * Or, if global RRM is supported, see:
++ * %NL80211_EXT_FEATURE_RRM
+ * If this flag is used, driver must add the Power Capabilities IE to the
+ * association request. In addition, it must also set the RRM capability
+ * flag in the association request's Capability Info field.
+@@ -1755,12 +1784,44 @@ enum nl80211_commands {
+ * over all channels.
+ *
+ * @NL80211_ATTR_SCHED_SCAN_DELAY: delay before the first cycle of a
+- * scheduled scan (or a WoWLAN net-detect scan) is started, u32
+- * in seconds.
++ * scheduled scan is started. Or the delay before a WoWLAN
++ * net-detect scan is started, counting from the moment the
++ * system is suspended. This value is a u32, in seconds.
+
* @NL80211_ATTR_REG_INDOOR: flag attribute, if set indicates that the device
* is operating in an indoor environment.
*
@@ -41,6 +126,21 @@
+ * thus it must not specify the number of iterations, only the interval
+ * between scans. The scan plans are executed sequentially.
+ * Each scan plan is a nested attribute of &enum nl80211_sched_scan_plan.
++ * @NL80211_ATTR_PBSS: flag attribute. If set it means operate
++ * in a PBSS. Specified in %NL80211_CMD_CONNECT to request
++ * connecting to a PCP, and in %NL80211_CMD_START_AP to start
++ * a PCP instead of AP. Relevant for DMG networks only.
++ * @NL80211_ATTR_BSS_SELECT: nested attribute for driver supporting the
++ * BSS selection feature. When used with %NL80211_CMD_GET_WIPHY it contains
++ * attributes according &enum nl80211_bss_select_attr to indicate what
++ * BSS selection behaviours are supported. When used with %NL80211_CMD_CONNECT
++ * it contains the behaviour-specific attribute containing the parameters for
++ * BSS selection to be done by driver and/or firmware.
++ *
++ * @NL80211_ATTR_STA_SUPPORT_P2P_PS: whether P2P PS mechanism supported
++ * or not. u8, one of the values of &enum nl80211_sta_p2p_ps_status
++ *
++ * @NL80211_ATTR_PAD: attribute used for padding for 64-bit alignment
+ *
+ * @NL80211_ATTR_WIPHY_ANTENNA_GAIN: Configured antenna gain. Used to reduce
+ * transmit power to stay within regulatory limits. u32, dBi.
@@ -48,7 +148,7 @@
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
-@@ -2130,6 +2155,13 @@ enum nl80211_attrs {
+@@ -2130,6 +2191,21 @@ enum nl80211_attrs {
NL80211_ATTR_REG_INDOOR,
@@ -57,30 +157,147 @@
+ NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS,
+ NL80211_ATTR_SCHED_SCAN_PLANS,
+
++ NL80211_ATTR_PBSS,
++
++ NL80211_ATTR_BSS_SELECT,
++
++ NL80211_ATTR_STA_SUPPORT_P2P_PS,
++
++ NL80211_ATTR_PAD,
++
+ NL80211_ATTR_WIPHY_ANTENNA_GAIN,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
-@@ -3364,6 +3396,9 @@ enum nl80211_bss_scan_width {
+@@ -2273,6 +2349,20 @@ enum nl80211_sta_flags {
+ NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1
+ };
+
++/**
++ * enum nl80211_sta_p2p_ps_status - station support of P2P PS
++ *
++ * @NL80211_P2P_PS_UNSUPPORTED: station doesn't support P2P PS mechanism
++ * @@NL80211_P2P_PS_SUPPORTED: station supports P2P PS mechanism
++ * @NUM_NL80211_P2P_PS_STATUS: number of values
++ */
++enum nl80211_sta_p2p_ps_status {
++ NL80211_P2P_PS_UNSUPPORTED = 0,
++ NL80211_P2P_PS_SUPPORTED,
++
++ NUM_NL80211_P2P_PS_STATUS,
++};
++
+ #define NL80211_STA_FLAG_MAX_OLD_API NL80211_STA_FLAG_TDLS_PEER
+
+ /**
+@@ -2430,6 +2520,9 @@ enum nl80211_sta_bss_param {
+ * TID+1 and the special TID 16 (i.e. value 17) is used for non-QoS frames;
+ * each one of those is again nested with &enum nl80211_tid_stats
+ * attributes carrying the actual values.
++ * @NL80211_STA_INFO_RX_DURATION: aggregate PPDU duration for all frames
++ * received from the station (u64, usec)
++ * @NL80211_STA_INFO_PAD: attribute used for padding for 64-bit alignment
+ * @__NL80211_STA_INFO_AFTER_LAST: internal
+ * @NL80211_STA_INFO_MAX: highest possible station info attribute
+ */
+@@ -2466,6 +2559,8 @@ enum nl80211_sta_info {
+ NL80211_STA_INFO_BEACON_RX,
+ NL80211_STA_INFO_BEACON_SIGNAL_AVG,
+ NL80211_STA_INFO_TID_STATS,
++ NL80211_STA_INFO_RX_DURATION,
++ NL80211_STA_INFO_PAD,
+
+ /* keep last */
+ __NL80211_STA_INFO_AFTER_LAST,
+@@ -2482,6 +2577,7 @@ enum nl80211_sta_info {
+ * transmitted MSDUs (not counting the first attempt; u64)
+ * @NL80211_TID_STATS_TX_MSDU_FAILED: number of failed transmitted
+ * MSDUs (u64)
++ * @NL80211_TID_STATS_PAD: attribute used for padding for 64-bit alignment
+ * @NUM_NL80211_TID_STATS: number of attributes here
+ * @NL80211_TID_STATS_MAX: highest numbered attribute here
+ */
+@@ -2491,6 +2587,7 @@ enum nl80211_tid_stats {
+ NL80211_TID_STATS_TX_MSDU,
+ NL80211_TID_STATS_TX_MSDU_RETRIES,
+ NL80211_TID_STATS_TX_MSDU_FAILED,
++ NL80211_TID_STATS_PAD,
+
+ /* keep last */
+ NUM_NL80211_TID_STATS,
+@@ -2927,6 +3024,7 @@ enum nl80211_user_reg_hint_type {
+ * transmitting data (on channel or globally)
+ * @NL80211_SURVEY_INFO_TIME_SCAN: time the radio spent for scan
+ * (on this channel or globally)
++ * @NL80211_SURVEY_INFO_PAD: attribute used for padding for 64-bit alignment
+ * @NL80211_SURVEY_INFO_MAX: highest survey info attribute number
+ * currently defined
+ * @__NL80211_SURVEY_INFO_AFTER_LAST: internal use
+@@ -2942,6 +3040,7 @@ enum nl80211_survey_info {
+ NL80211_SURVEY_INFO_TIME_RX,
+ NL80211_SURVEY_INFO_TIME_TX,
+ NL80211_SURVEY_INFO_TIME_SCAN,
++ NL80211_SURVEY_INFO_PAD,
+
+ /* keep last */
+ __NL80211_SURVEY_INFO_AFTER_LAST,
+@@ -3364,6 +3463,10 @@ enum nl80211_bss_scan_width {
* (not present if no beacon frame has been received yet)
* @NL80211_BSS_PRESP_DATA: the data in @NL80211_BSS_INFORMATION_ELEMENTS and
* @NL80211_BSS_TSF is known to be from a probe response (flag attribute)
+ * @NL80211_BSS_LAST_SEEN_BOOTTIME: CLOCK_BOOTTIME timestamp when this entry
+ * was last updated by a received frame. The value is expected to be
+ * accurate to about 10ms. (u64, nanoseconds)
++ * @NL80211_BSS_PAD: attribute used for padding for 64-bit alignment
* @__NL80211_BSS_AFTER_LAST: internal
* @NL80211_BSS_MAX: highest BSS attribute
*/
-@@ -3383,6 +3418,7 @@ enum nl80211_bss {
+@@ -3383,6 +3486,8 @@ enum nl80211_bss {
NL80211_BSS_CHAN_WIDTH,
NL80211_BSS_BEACON_TSF,
NL80211_BSS_PRESP_DATA,
+ NL80211_BSS_LAST_SEEN_BOOTTIME,
++ NL80211_BSS_PAD,
/* keep last */
__NL80211_BSS_AFTER_LAST,
-@@ -4589,4 +4625,28 @@ enum nl80211_tdls_peer_capability {
+@@ -3568,11 +3673,15 @@ enum nl80211_txrate_gi {
+ * @NL80211_BAND_2GHZ: 2.4 GHz ISM band
+ * @NL80211_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz)
+ * @NL80211_BAND_60GHZ: around 60 GHz band (58.32 - 64.80 GHz)
++ * @NUM_NL80211_BANDS: number of bands, avoid using this in userspace
++ * since newer kernel versions may support more bands
+ */
+ enum nl80211_band {
+ NL80211_BAND_2GHZ,
+ NL80211_BAND_5GHZ,
+ NL80211_BAND_60GHZ,
++
++ NUM_NL80211_BANDS,
+ };
+
+ /**
+@@ -4358,12 +4467,18 @@ enum nl80211_feature_flags {
+ /**
+ * enum nl80211_ext_feature_index - bit index of extended features.
+ * @NL80211_EXT_FEATURE_VHT_IBSS: This driver supports IBSS with VHT datarates.
++ * @NL80211_EXT_FEATURE_RRM: This driver supports RRM. When featured, user can
++ * can request to use RRM (see %NL80211_ATTR_USE_RRM) with
++ * %NL80211_CMD_ASSOCIATE and %NL80211_CMD_CONNECT requests, which will set
++ * the ASSOC_REQ_USE_RRM flag in the association request even if
++ * NL80211_FEATURE_QUIET is not advertized.
+ *
+ * @NUM_NL80211_EXT_FEATURES: number of extended features.
+ * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
+ */
+ enum nl80211_ext_feature_index {
+ NL80211_EXT_FEATURE_VHT_IBSS,
++ NL80211_EXT_FEATURE_RRM,
+
+ /* add new features before the definition below */
+ NUM_NL80211_EXT_FEATURES,
+@@ -4589,4 +4704,72 @@ enum nl80211_tdls_peer_capability {
NL80211_TDLS_PEER_WMM = 1<<2,
};
@@ -108,4 +325,48 @@
+ __NL80211_SCHED_SCAN_PLAN_AFTER_LAST - 1
+};
+
++/**
++ * struct nl80211_bss_select_rssi_adjust - RSSI adjustment parameters.
++ *
++ * @band: band of BSS that must match for RSSI value adjustment.
++ * @delta: value used to adjust the RSSI value of matching BSS.
++ */
++struct nl80211_bss_select_rssi_adjust {
++ __u8 band;
++ __s8 delta;
++} __attribute__((packed));
++
++/**
++ * enum nl80211_bss_select_attr - attributes for bss selection.
++ *
++ * @__NL80211_BSS_SELECT_ATTR_INVALID: reserved.
++ * @NL80211_BSS_SELECT_ATTR_RSSI: Flag indicating only RSSI-based BSS selection
++ * is requested.
++ * @NL80211_BSS_SELECT_ATTR_BAND_PREF: attribute indicating BSS
++ * selection should be done such that the specified band is preferred.
++ * When there are multiple BSS-es in the preferred band, the driver
++ * shall use RSSI-based BSS selection as a second step. The value of
++ * this attribute is according to &enum nl80211_band (u32).
++ * @NL80211_BSS_SELECT_ATTR_RSSI_ADJUST: When present the RSSI level for
++ * BSS-es in the specified band is to be adjusted before doing
++ * RSSI-based BSS selection. The attribute value is a packed structure
++ * value as specified by &struct nl80211_bss_select_rssi_adjust.
++ * @NL80211_BSS_SELECT_ATTR_MAX: highest bss select attribute number.
++ * @__NL80211_BSS_SELECT_ATTR_AFTER_LAST: internal use.
++ *
++ * One and only one of these attributes are found within %NL80211_ATTR_BSS_SELECT
++ * for %NL80211_CMD_CONNECT. It specifies the required BSS selection behaviour
++ * which the driver shall use.
++ */
++enum nl80211_bss_select_attr {
++ __NL80211_BSS_SELECT_ATTR_INVALID,
++ NL80211_BSS_SELECT_ATTR_RSSI,
++ NL80211_BSS_SELECT_ATTR_BAND_PREF,
++ NL80211_BSS_SELECT_ATTR_RSSI_ADJUST,
++
++ /* keep last */
++ __NL80211_BSS_SELECT_ATTR_AFTER_LAST,
++ NL80211_BSS_SELECT_ATTR_MAX = __NL80211_BSS_SELECT_ATTR_AFTER_LAST - 1
++};
++
#endif /* __LINUX_NL80211_H */
diff --git a/package/network/utils/iw/patches/300-display_interface_TX_power.patch b/package/network/utils/iw/patches/300-display_interface_TX_power.patch
index 574c490318..2cdf360cc5 100644
--- a/package/network/utils/iw/patches/300-display_interface_TX_power.patch
+++ b/package/network/utils/iw/patches/300-display_interface_TX_power.patch
@@ -12,11 +12,9 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
interface.c | 7 +++++++
1 file changed, 7 insertions(+)
-diff --git a/interface.c b/interface.c
-index 73ccecd..4f0821d 100644
--- a/interface.c
+++ b/interface.c
-@@ -368,6 +368,13 @@ static int print_iface_handler(struct nl_msg *msg, void *arg)
+@@ -368,6 +368,13 @@ static int print_iface_handler(struct nl
printf("\n");
}
diff --git a/package/network/utils/iw/patches/301-ibss_add_VHT80.patch b/package/network/utils/iw/patches/301-ibss_add_VHT80.patch
index 709fbb2914..0627bccb46 100644
--- a/package/network/utils/iw/patches/301-ibss_add_VHT80.patch
+++ b/package/network/utils/iw/patches/301-ibss_add_VHT80.patch
@@ -14,8 +14,6 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
ibss.c | 49 +++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 41 insertions(+), 8 deletions(-)
-diff --git a/ibss.c b/ibss.c
-index 7a0b707..a99a262 100644
--- a/ibss.c
+++ b/ibss.c
@@ -16,6 +16,39 @@
@@ -58,7 +56,7 @@ index 7a0b707..a99a262 100644
static int join_ibss(struct nl80211_state *state,
struct nl_msg *msg,
int argc, char **argv,
-@@ -30,12 +63,8 @@ static int join_ibss(struct nl80211_state *state,
+@@ -30,12 +63,8 @@ static int join_ibss(struct nl80211_stat
int bintval;
int i;
unsigned long freq;
@@ -73,7 +71,7 @@ index 7a0b707..a99a262 100644
{ .name = "HT20",
.width = NL80211_CHAN_WIDTH_20,
.freq1_diff = 0,
-@@ -60,6 +89,10 @@ static int join_ibss(struct nl80211_state *state,
+@@ -60,6 +89,10 @@ static int join_ibss(struct nl80211_stat
.width = NL80211_CHAN_WIDTH_10,
.freq1_diff = 0,
.chantype = -1 },
@@ -84,7 +82,7 @@ index 7a0b707..a99a262 100644
};
if (argc < 2)
-@@ -90,7 +123,7 @@ static int join_ibss(struct nl80211_state *state,
+@@ -90,7 +123,7 @@ static int join_ibss(struct nl80211_stat
NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
chanmode_selected->width);
NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1,
diff --git a/package/network/utils/iw/patches/302-ibss_use_MHz_instead_MHZ.patch b/package/network/utils/iw/patches/302-ibss_use_MHz_instead_MHZ.patch
index fc4442792d..f96d5eafda 100644
--- a/package/network/utils/iw/patches/302-ibss_use_MHz_instead_MHZ.patch
+++ b/package/network/utils/iw/patches/302-ibss_use_MHz_instead_MHZ.patch
@@ -7,11 +7,9 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
ibss.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
-diff --git a/ibss.c b/ibss.c
-index a99a262..23bda70 100644
--- a/ibss.c
+++ b/ibss.c
-@@ -81,15 +81,15 @@ static int join_ibss(struct nl80211_state *state,
+@@ -81,15 +81,15 @@ static int join_ibss(struct nl80211_stat
.width = NL80211_CHAN_WIDTH_20_NOHT,
.freq1_diff = 0,
.chantype = NL80211_CHAN_NO_HT },
diff --git a/package/network/utils/iw/patches/303-mesh_add_VHT80.patch b/package/network/utils/iw/patches/303-mesh_add_VHT80.patch
index fe8dc21a19..956b0505e6 100644
--- a/package/network/utils/iw/patches/303-mesh_add_VHT80.patch
+++ b/package/network/utils/iw/patches/303-mesh_add_VHT80.patch
@@ -15,8 +15,6 @@ Signed-off-by: Sven Eckelmann <sven@open-mesh.com>
util.c | 26 ++++++++++++++++++++++++++
4 files changed, 43 insertions(+), 41 deletions(-)
-diff --git a/ibss.c b/ibss.c
-index 23bda70..ac06fc5 100644
--- a/ibss.c
+++ b/ibss.c
@@ -16,39 +16,6 @@
@@ -59,8 +57,6 @@ index 23bda70..ac06fc5 100644
static int join_ibss(struct nl80211_state *state,
struct nl_msg *msg,
int argc, char **argv,
-diff --git a/iw.h b/iw.h
-index cef9da8..8e1a37a 100644
--- a/iw.h
+++ b/iw.h
@@ -59,6 +59,13 @@ struct cmd {
@@ -77,7 +73,7 @@ index cef9da8..8e1a37a 100644
#define ARRAY_SIZE(ar) (sizeof(ar)/sizeof(ar[0]))
#define DIV_ROUND_UP(x, y) (((x) + (y - 1)) / (y))
-@@ -174,6 +181,8 @@ void print_ies(unsigned char *ie, int ielen, bool unknown,
+@@ -174,6 +181,8 @@ void print_ies(unsigned char *ie, int ie
void parse_bitrate(struct nlattr *bitrate_attr, char *buf, int buflen);
void iw_hexdump(const char *prefix, const __u8 *data, size_t len);
@@ -86,11 +82,9 @@ index cef9da8..8e1a37a 100644
#define SCHED_SCAN_OPTIONS "interval <in_msecs> [delay <in_secs>] " \
"[freqs <freq>+] [matches [ssid <ssid>]+]] [active [ssid <ssid>]+|passive] [randomise[=<addr>/<mask>]]"
int parse_sched_scan(struct nl_msg *msg, int *argc, char ***argv);
-diff --git a/mesh.c b/mesh.c
-index 0090530..930d58f 100644
--- a/mesh.c
+++ b/mesh.c
-@@ -439,12 +439,8 @@ static int join_mesh(struct nl80211_state *state,
+@@ -439,12 +439,8 @@ static int join_mesh(struct nl80211_stat
int bintval, dtim_period, i, n_rates = 0;
char *end, *value = NULL, *sptr = NULL;
unsigned long freq = 0;
@@ -105,7 +99,7 @@ index 0090530..930d58f 100644
{ .name = "HT20",
.width = NL80211_CHAN_WIDTH_20,
.freq1_diff = 0,
-@@ -461,6 +457,10 @@ static int join_mesh(struct nl80211_state *state,
+@@ -461,6 +457,10 @@ static int join_mesh(struct nl80211_stat
.width = NL80211_CHAN_WIDTH_20_NOHT,
.freq1_diff = 0,
.chantype = NL80211_CHAN_NO_HT },
@@ -116,7 +110,7 @@ index 0090530..930d58f 100644
};
if (argc < 1)
-@@ -497,7 +497,7 @@ static int join_mesh(struct nl80211_state *state,
+@@ -497,7 +497,7 @@ static int join_mesh(struct nl80211_stat
NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
chanmode_selected->width);
NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1,
@@ -125,7 +119,7 @@ index 0090530..930d58f 100644
if (chanmode_selected->chantype != -1)
NLA_PUT_U32(msg,
NL80211_ATTR_WIPHY_CHANNEL_TYPE,
-@@ -599,7 +599,7 @@ static int join_mesh(struct nl80211_state *state,
+@@ -599,7 +599,7 @@ static int join_mesh(struct nl80211_stat
nla_put_failure:
return -ENOBUFS;
}
@@ -134,11 +128,9 @@ index 0090530..930d58f 100644
" [basic-rates <rate in Mbps,rate2,...>]], [mcast-rate <rate in Mbps>]"
" [beacon-interval <time in TUs>] [dtim-period <value>]"
" [vendor_sync on|off] [<param>=<value>]*",
-diff --git a/util.c b/util.c
-index 4efc4c8..d75ffe0 100644
--- a/util.c
+++ b/util.c
-@@ -728,3 +728,29 @@ void iw_hexdump(const char *prefix, const __u8 *buf, size_t size)
+@@ -728,3 +728,29 @@ void iw_hexdump(const char *prefix, cons
}
printf("\n\n");
}
diff --git a/package/system/fstools/Makefile b/package/system/fstools/Makefile
index 4a1108164f..556d4b08cb 100644
--- a/package/system/fstools/Makefile
+++ b/package/system/fstools/Makefile
@@ -8,14 +8,14 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=fstools
-PKG_VERSION:=2016-04-30
+PKG_VERSION:=2016-05-12
PKG_RELEASE=$(PKG_SOURCE_VERSION)
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(OPENWRT_GIT)/project/fstools.git
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
-PKG_SOURCE_VERSION:=bb92c29fc4cd90d396fc79078eba75fcb01c92ae
+PKG_SOURCE_VERSION:=ed224f0b1f9cfb3f8c5766cba3a60343c0eda586
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
CMAKE_INSTALL:=1
diff --git a/package/utils/admswconfig/Makefile b/package/utils/admswconfig/Makefile
index 820f854ff8..6f4b6049e2 100644
--- a/package/utils/admswconfig/Makefile
+++ b/package/utils/admswconfig/Makefile
@@ -15,6 +15,8 @@ PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=http://downloads.openwrt.org/sources
PKG_MD5SUM:=faafd4618f970119a665b11b21ac6a26
+PKG_FLAGS:=nonshared
+
include $(INCLUDE_DIR)/package.mk
define Package/admswconfig
diff --git a/package/utils/busybox/patches/030-ip-fix-problem-on-mips64-n64-big-endian-musl-systems.patch b/package/utils/busybox/patches/030-ip-fix-problem-on-mips64-n64-big-endian-musl-systems.patch
new file mode 100644
index 0000000000..6e25f55881
--- /dev/null
+++ b/package/utils/busybox/patches/030-ip-fix-problem-on-mips64-n64-big-endian-musl-systems.patch
@@ -0,0 +1,75 @@
+From: Szabolcs Nagy <nsz@port70.net>
+Date: Sun, 24 Apr 2016 17:39:02 +0200
+Subject: [PATCH] ip: fix problem on mips64 n64 big endian musl systems
+
+Use designated initializers for struct msghdr.
+The struct layout is non-portable and musl libc does not match what busybox expects.
+
+Signed-off-by: Szabolcs Nagy <nsz@port70.net>
+Tested-by: Waldemar Brodkorb <wbx@openadk.org>
+Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
+---
+
+--- a/networking/libiproute/libnetlink.c
++++ b/networking/libiproute/libnetlink.c
+@@ -71,11 +71,15 @@ int FAST_FUNC rtnl_dump_request(struct r
+ struct nlmsghdr nlh;
+ struct sockaddr_nl nladdr;
+ struct iovec iov[2] = { { &nlh, sizeof(nlh) }, { req, len } };
++ /* Use designated initializers, struct layout is non-portable */
+ struct msghdr msg = {
+- (void*)&nladdr, sizeof(nladdr),
+- iov, 2,
+- NULL, 0,
+- 0
++ .msg_name = (void*)&nladdr,
++ .msg_namelen = sizeof(nladdr),
++ .msg_iov = iov,
++ .msg_iovlen = 2,
++ .msg_control = NULL,
++ .msg_controllen = 0,
++ .msg_flags = 0
+ };
+
+ memset(&nladdr, 0, sizeof(nladdr));
+@@ -104,12 +108,15 @@ static int rtnl_dump_filter(struct rtnl_
+ while (1) {
+ int status;
+ struct nlmsghdr *h;
+-
++ /* Use designated initializers, struct layout is non-portable */
+ struct msghdr msg = {
+- (void*)&nladdr, sizeof(nladdr),
+- &iov, 1,
+- NULL, 0,
+- 0
++ .msg_name = (void*)&nladdr,
++ .msg_namelen = sizeof(nladdr),
++ .msg_iov = &iov,
++ .msg_iovlen = 1,
++ .msg_control = NULL,
++ .msg_controllen = 0,
++ .msg_flags = 0
+ };
+
+ status = recvmsg(rth->fd, &msg, 0);
+@@ -211,11 +218,15 @@ int FAST_FUNC rtnl_talk(struct rtnl_hand
+ struct sockaddr_nl nladdr;
+ struct iovec iov = { (void*)n, n->nlmsg_len };
+ char *buf = xmalloc(8*1024); /* avoid big stack buffer */
++ /* Use designated initializers, struct layout is non-portable */
+ struct msghdr msg = {
+- (void*)&nladdr, sizeof(nladdr),
+- &iov, 1,
+- NULL, 0,
+- 0
++ .msg_name = (void*)&nladdr,
++ .msg_namelen = sizeof(nladdr),
++ .msg_iov = &iov,
++ .msg_iovlen = 1,
++ .msg_control = NULL,
++ .msg_controllen = 0,
++ .msg_flags = 0
+ };
+
+ memset(&nladdr, 0, sizeof(nladdr));
diff --git a/package/utils/e2fsprogs/Makefile b/package/utils/e2fsprogs/Makefile
index bc1e5ed5ca..e90a752080 100644
--- a/package/utils/e2fsprogs/Makefile
+++ b/package/utils/e2fsprogs/Makefile
@@ -8,8 +8,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=e2fsprogs
-PKG_VERSION:=1.42.12
-PKG_MD5SUM:=68255f51be017a93f2f6402fab06c2bf
+PKG_VERSION:=1.42.13
+PKG_MD5SUM:=bc759fc62666786f5436e2075beb3265
PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
diff --git a/package/utils/nvram/Makefile b/package/utils/nvram/Makefile
index 992f3366ba..040d953582 100644
--- a/package/utils/nvram/Makefile
+++ b/package/utils/nvram/Makefile
@@ -11,6 +11,7 @@ PKG_NAME:=nvram
PKG_RELEASE:=9
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
+PKG_FLAGS:=nonshared
include $(INCLUDE_DIR)/package.mk
diff --git a/package/utils/oseama/Makefile b/package/utils/oseama/Makefile
index ad1395c7be..8957a69967 100644
--- a/package/utils/oseama/Makefile
+++ b/package/utils/oseama/Makefile
@@ -10,6 +10,8 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=oseama
PKG_RELEASE:=1
+PKG_FLAGS:=nonshared
+
include $(INCLUDE_DIR)/package.mk
define Package/oseama
diff --git a/package/utils/otrx/Makefile b/package/utils/otrx/Makefile
index 360fb1790d..ba981fcc84 100644
--- a/package/utils/otrx/Makefile
+++ b/package/utils/otrx/Makefile
@@ -9,6 +9,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=otrx
PKG_RELEASE:=1
+PKG_FLAGS:=nonshared
include $(INCLUDE_DIR)/package.mk
diff --git a/package/utils/usbutils/Makefile b/package/utils/usbutils/Makefile
index ff737847d1..2b44df9e90 100644
--- a/package/utils/usbutils/Makefile
+++ b/package/utils/usbutils/Makefile
@@ -36,7 +36,7 @@ endef
define Download/usb_ids
FILE:=$(USB_IDS_FILE)
- URL:=https://raw.githubusercontent.com/gentoo/hwids/d9e840aa3d5cedf5637d59ef0dc555c380a0e822
+ URL:=@GITHUB/gentoo/hwids/d9e840aa3d5cedf5637d59ef0dc555c380a0e822
MD5SUM:=$(USB_IDS_MD5SUM)
endef
$(eval $(call Download,usb_ids))
diff --git a/scripts/diffconfig.sh b/scripts/diffconfig.sh
index f195d1849b..9972a39132 100755
--- a/scripts/diffconfig.sh
+++ b/scripts/diffconfig.sh
@@ -2,6 +2,7 @@
grep \^CONFIG_TARGET_ .config | head -n3 > tmp/.diffconfig.head
grep '^CONFIG_ALL=y' .config >> tmp/.diffconfig.head
grep '^CONFIG_ALL_KMODS=y' .config >> tmp/.diffconfig.head
+grep '^CONFIG_ALL_NONSHARED=y' .config >> tmp/.diffconfig.head
grep '^CONFIG_DEVEL=y' .config >> tmp/.diffconfig.head
grep '^CONFIG_TOOLCHAINOPTS=y' .config >> tmp/.diffconfig.head
grep '^CONFIG_BUSYBOX_CUSTOM=y' .config >> tmp/.diffconfig.head
diff --git a/scripts/metadata.pl b/scripts/metadata.pl
index 96d5ee4208..b17403f51f 100755
--- a/scripts/metadata.pl
+++ b/scripts/metadata.pl
@@ -568,11 +568,14 @@ sub print_package_config_category($) {
print "\t\t".($pkg->{tristate} ? 'tristate' : 'bool')." $title\n";
print "\t\tdefault y if DEFAULT_".$pkg->{name}."\n";
unless ($pkg->{hidden}) {
+ my @def = ("ALL");
+ if (!exists($pkg->{repository})) {
+ push @def, "ALL_NONSHARED";
+ }
if ($pkg->{name} =~ /^kmod-/) {
- $pkg->{default} ||= "m if ALL_KMODS";
- } else {
- $pkg->{default} ||= "m if ALL";
+ push @def, "ALL_KMODS";
}
+ $pkg->{default} ||= "m if " . join("||", @def);
}
if ($pkg->{default}) {
foreach my $default (split /\s*,\s*/, $pkg->{default}) {
diff --git a/target/linux/ar71xx/Makefile b/target/linux/ar71xx/Makefile
index 24d7d5c692..594b48ef2c 100644
--- a/target/linux/ar71xx/Makefile
+++ b/target/linux/ar71xx/Makefile
@@ -13,7 +13,7 @@ FEATURES:=mips16
CPU_TYPE=34kc
SUBTARGETS:=generic nand mikrotik
-KERNEL_PATCHVER:=4.1
+KERNEL_PATCHVER:=4.4
include $(INCLUDE_DIR)/target.mk
diff --git a/target/linux/ar71xx/base-files/etc/board.d/01_leds b/target/linux/ar71xx/base-files/etc/board.d/01_leds
index 39b21ca519..6936b8c873 100755
--- a/target/linux/ar71xx/base-files/etc/board.d/01_leds
+++ b/target/linux/ar71xx/base-files/etc/board.d/01_leds
@@ -127,6 +127,7 @@ cf-e316n-v2)
ucidef_set_led_wlan "wlan" "WLAN" "$board:blue:wlan" "phy0tpt"
;;
+cpe210|\
cpe510)
ucidef_set_led_switch "lan0" "LAN0" "tp-link:green:lan0" "switch0" "0x20"
ucidef_set_led_switch "lan1" "LAN1" "tp-link:green:lan1" "switch0" "0x10"
@@ -322,7 +323,8 @@ mr600)
ucidef_set_led_wlan "wlan58" "WLAN58" "mr600:green:wlan58" "phy0tpt"
;;
-mr1750)
+mr1750 | \
+mr1750v2)
ucidef_set_led_netdev "lan" "LAN" "mr1750:blue:wan" "eth0"
ucidef_set_led_wlan "wlan58" "WLAN58" "mr1750:blue:wlan58" "phy0tpt"
ucidef_set_led_wlan "wlan24" "WLAN24" "mr1750:blue:wlan24" "phy1tpt"
@@ -383,6 +385,7 @@ om2p | \
om2pv2 | \
om2p-hs | \
om2p-hsv2 | \
+om2p-hsv3 | \
om2p-lc)
ucidef_set_led_netdev "port1" "port1" "om2p:blue:wan" "eth0"
ucidef_set_led_netdev "port2" "port2" "om2p:blue:lan" "eth1"
@@ -423,6 +426,14 @@ smart-300)
ucidef_set_led_wlan "wlan" "WLAN" "nc-link:green:wlan" "phy0tpt"
;;
+som9331)
+ ucidef_set_led_netdev "wan" "WAN" "som9331:orange:wan" "eth1"
+ ucidef_set_led_switch "lan1" "LAN1" "som9331:orange:lan1" "switch0" "0x08"
+ ucidef_set_led_switch "lan2" "LAN2" "som9331:orange:lan2" "switch0" "0x02"
+ ucidef_set_led_wlan "wlan" "WLAN" "som9331:red:wlan" "phy0tpt"
+ ucidef_set_led_usbdev "usb" "USB" "som9331:green:system" "1-1"
+ ;;
+
tellstick-znet-lite)
ucidef_set_led_netdev "lan_act" "LANACT" "tellstick:green:lan" "eth0" "tx rx"
ucidef_set_led_netdev "lan_link" "LANLINK" "tellstick:orange:lan" "eth0" "link"
@@ -607,7 +618,8 @@ tl-wa830re-v2)
ucidef_set_led_wlan "wlan" "WLAN" "tp-link:green:wlan" "phy0tpt"
;;
-tl-wr841n-v9)
+tl-wr841n-v9 | \
+tl-wr841n-v11)
ucidef_set_led_netdev "wan" "WAN" "tp-link:green:wan" "eth1"
ucidef_set_led_switch "lan1" "LAN1" "tp-link:green:lan1" "switch0" "0x10"
ucidef_set_led_switch "lan2" "LAN2" "tp-link:green:lan2" "switch0" "0x08"
@@ -626,6 +638,16 @@ tl-wr842n-v2)
ucidef_set_led_usbdev "usb" "USB" "tp-link:green:3g" "1-1"
;;
+tl-wr842n-v3)
+ ucidef_set_led_netdev "wan" "WAN" "tp-link:green:wan" "eth1"
+ ucidef_set_led_switch "lan1" "LAN1" "tp-link:green:lan1" "switch0" "0x10"
+ ucidef_set_led_switch "lan2" "LAN2" "tp-link:green:lan2" "switch0" "0x08"
+ ucidef_set_led_switch "lan3" "LAN3" "tp-link:green:lan3" "switch0" "0x04"
+ ucidef_set_led_switch "lan4" "LAN4" "tp-link:green:lan4" "switch0" "0x02"
+ ucidef_set_led_wlan "wlan" "WLAN" "tp-link:green:wlan" "phy0tpt"
+ ucidef_set_led_usbdev "usb" "USB" "tp-link:green:3g" "1-1"
+ ;;
+
tl-wa801nd-v2 | \
tl-wa901nd-v3)
ucidef_set_led_netdev "lan" "LAN" "tp-link:green:lan" "eth0"
diff --git a/target/linux/ar71xx/base-files/etc/board.d/02_network b/target/linux/ar71xx/base-files/etc/board.d/02_network
index 67adf334aa..1ed593cc55 100755
--- a/target/linux/ar71xx/base-files/etc/board.d/02_network
+++ b/target/linux/ar71xx/base-files/etc/board.d/02_network
@@ -72,6 +72,7 @@ bsb)
ucidef_set_interface_wlan
;;
+cpe210|\
cpe510)
ucidef_add_switch "switch0" \
"0@eth0" "5:lan" "4:wan"
@@ -200,7 +201,7 @@ tellstick-znet-lite)
tl-wdr4300|\
tl-wr1041n-v2)
ucidef_add_switch "switch0" \
- "0@eth0" "1:wan" "2:lan:1" "3:lan:2" "4:lan:3" "5:lan:4"
+ "0@eth0" "2:lan:1" "3:lan:2" "4:lan:3" "5:lan:4" "1:wan"
;;
tl-wr1043nd)
@@ -335,6 +336,7 @@ eap7660d |\
el-mini |\
loco-m-xw |\
mr1750 |\
+mr1750v2 |\
mr18 |\
mr600 |\
mr600v2 |\
@@ -368,7 +370,7 @@ tl-wa901nd-v3 |\
tl-wa901nd-v4 |\
tl-wr703n |\
tube2h |\
-unifiac |\
+unifiac-lite |\
wndap360 |\
mynet-rext |\
wp543)
@@ -398,7 +400,8 @@ routerstation|\
tl-wr710n |\
tl-wr720n-v3|\
tl-wr810n |\
-wpe72)
+wpe72 |\
+wrtnode2q)
ucidef_set_interfaces_lan_wan "eth1" "eth0"
;;
@@ -418,6 +421,11 @@ wpj344)
"0@eth0" "3:lan" "2:wan"
;;
+unifiac-pro)
+ ucidef_add_switch "switch0" \
+ "0@eth0" "2:lan" "3:wan"
+ ;;
+
wpj531)
ucidef_set_interfaces_lan_wan "eth0" "eth1"
;;
@@ -444,6 +452,7 @@ oolite |\
qihoo-c301 |\
rb-750 |\
rb-751 |\
+som9331 |\
tew-632brp |\
tew-712br |\
tew-732br |\
@@ -456,6 +465,8 @@ tl-wr741nd |\
tl-wr741nd-v4 |\
tl-wr841n-v7 |\
tl-wr841n-v9 |\
+tl-wr841n-v11 |\
+tl-wr842n-v3 |\
whr-g301n |\
whr-hp-g300n |\
whr-hp-gn |\
diff --git a/target/linux/ar71xx/base-files/etc/board.d/03_gpio_switches b/target/linux/ar71xx/base-files/etc/board.d/03_gpio_switches
index 8abcfc0db0..5b95f155cf 100755
--- a/target/linux/ar71xx/base-files/etc/board.d/03_gpio_switches
+++ b/target/linux/ar71xx/base-files/etc/board.d/03_gpio_switches
@@ -17,9 +17,14 @@ nanostation-m)
nanostation-m-xw)
ucidef_add_gpio_switch "poe_passthrough" "PoE Passthrough" "2"
;;
+cpe210|\
cpe510)
ucidef_add_gpio_switch "poe_passthrough" "PoE Passthrough" "20"
;;
+rb-912uag-2hpnd|\
+rb-912uag-5hpnd)
+ ucidef_add_gpio_switch "usb_power_switch" "USB Power Switch" "52"
+ ;;
esac
board_config_flush
diff --git a/target/linux/ar71xx/base-files/etc/diag.sh b/target/linux/ar71xx/base-files/etc/diag.sh
index f95a72d295..520fef8097 100644
--- a/target/linux/ar71xx/base-files/etc/diag.sh
+++ b/target/linux/ar71xx/base-files/etc/diag.sh
@@ -176,7 +176,8 @@ get_status_led() {
mr600v2)
status_led="mr600:blue:power"
;;
- mr1750)
+ mr1750 | \
+ mr1750v2)
status_led="mr1750:blue:power"
;;
mr900 | \
@@ -207,6 +208,7 @@ get_status_led() {
om2pv2 | \
om2p-hs | \
om2p-hsv2 | \
+ om2p-hsv3 | \
om2p-lc)
status_led="om2p:blue:power"
;;
@@ -276,6 +278,9 @@ get_status_led() {
tellstick-znet-lite)
status_led="tellstick:white:system"
;;
+ som9331)
+ status_led="som9331:green:system"
+ ;;
tew-632brp)
status_led="tew-632brp:green:status"
;;
@@ -319,8 +324,10 @@ get_status_led() {
tl-wr841n-v1 | \
tl-wr841n-v7 | \
tl-wr841n-v8 | \
+ tl-wr841n-v11 | \
tl-wa830re-v2 | \
tl-wr842n-v2 | \
+ tl-wr842n-v3 | \
tl-wr941nd | \
tl-wr941nd-v5)
status_led="tp-link:green:system"
@@ -355,7 +362,8 @@ get_status_led() {
status_led="ubnt:green:dome"
;;
uap-pro | \
- unifiac)
+ unifiac-lite | \
+ unifiac-pro)
status_led="ubnt:white:dome"
;;
unifi-outdoor-plus)
diff --git a/target/linux/ar71xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata b/target/linux/ar71xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
index 8fc3ab3cd4..0e93feb19c 100644
--- a/target/linux/ar71xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
+++ b/target/linux/ar71xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
@@ -72,11 +72,13 @@ case "$FIRMWARE" in
ath10kcal_patch_mac $(macaddr_add $(cat /sys/class/net/eth0/address) +1)
;;
mr1750 | \
+ mr1750v2 | \
om5p-acv2)
ath10kcal_extract "ART" 20480 2116
ath10kcal_patch_mac $(macaddr_add $(cat /sys/class/net/eth0/address) +16)
;;
- unifiac)
+ unifiac-lite | \
+ unifiac-pro)
ath10kcal_extract "EEPROM" 20480 2116
;;
esac
diff --git a/target/linux/ar71xx/base-files/lib/ar71xx.sh b/target/linux/ar71xx/base-files/lib/ar71xx.sh
index d71b8ba838..5b81f739f4 100755
--- a/target/linux/ar71xx/base-files/lib/ar71xx.sh
+++ b/target/linux/ar71xx/base-files/lib/ar71xx.sh
@@ -446,7 +446,11 @@ ar71xx_board_detect() {
*"COMFAST CF-E316N v2")
name="cf-e316n-v2"
;;
- *"CPE210/220/510/520")
+ *"CPE210/220")
+ name="cpe210"
+ tplink_pharos_board_detect
+ ;;
+ *"CPE510/520")
name="cpe510"
tplink_pharos_board_detect
;;
@@ -595,6 +599,9 @@ ar71xx_board_detect() {
*MR1750)
name="mr1750"
;;
+ *MR1750v2)
+ name="mr1750v2"
+ ;;
*MR600)
name="mr600"
;;
@@ -640,6 +647,9 @@ ar71xx_board_detect() {
*"OM2P HSv2")
name="om2p-hsv2"
;;
+ *"OM2P HSv3")
+ name="om2p-hsv3"
+ ;;
*"OM2P LC")
name="om2p-lc"
;;
@@ -784,6 +794,9 @@ ar71xx_board_detect() {
*"Telldus TellStick ZNet Lite")
name="tellstick-znet-lite"
;;
+ *SOM9331)
+ name="som9331"
+ ;;
*TEW-632BRP)
name="tew-632brp"
;;
@@ -907,9 +920,15 @@ ar71xx_board_detect() {
*"TL-WR841N/ND v9")
name="tl-wr841n-v9"
;;
+ *"TL-WR841N/ND v11")
+ name="tl-wr841n-v11"
+ ;;
*"TL-WR842N/ND v2")
name="tl-wr842n-v2"
;;
+ *"TL-WR842N/ND v3")
+ name="tl-wr842n-v3"
+ ;;
*TL-WR941ND)
name="tl-wr941nd"
;;
@@ -949,8 +968,11 @@ ar71xx_board_detect() {
*UniFi)
name="unifi"
;;
- *"UniFi-AC")
- name="unifiac"
+ *"UniFi-AC-LITE")
+ name="unifiac-lite"
+ ;;
+ *"UniFi-AC-PRO")
+ name="unifiac-pro"
;;
*"UniFi AP Pro")
name="uap-pro"
@@ -1033,6 +1055,9 @@ ar71xx_board_detect() {
*WRT400N)
name="wrt400n"
;;
+ *"WRTnode2Q board")
+ name="wrtnode2q"
+ ;;
*"WZR-450HP2")
name="wzr-450hp2"
;;
diff --git a/target/linux/ar71xx/base-files/lib/upgrade/openmesh.sh b/target/linux/ar71xx/base-files/lib/upgrade/openmesh.sh
index 209cdaaf90..87b65165b4 100644
--- a/target/linux/ar71xx/base-files/lib/upgrade/openmesh.sh
+++ b/target/linux/ar71xx/base-files/lib/upgrade/openmesh.sh
@@ -36,62 +36,48 @@ platform_add_ramfs_ubootenv()
}
append sysupgrade_pre_upgrade platform_add_ramfs_ubootenv
-platform_check_image_openmesh()
+platform_check_image_target_openmesh()
{
- local img_magic=$1
- local img_path=$2
- local fw_printenv=/usr/sbin/fw_printenv
- local img_board_target= img_num_files= i=0
- local cfg_name= kernel_name= rootfs_name=
-
- case "$img_magic" in
- # Combined Extended Image v1
- 43453031)
- img_board_target=$(trim $(dd if="$img_path" bs=4 skip=1 count=8 2>/dev/null))
- img_num_files=$(trim $(dd if="$img_path" bs=2 skip=18 count=1 2>/dev/null))
- ;;
- *)
- echo "Invalid image ($img_magic). Use combined extended images on this platform"
- return 1
- ;;
- esac
+ img_board_target="$1"
case "$img_board_target" in
OM2P)
- [ "$board" = "om2p" ] && break
- [ "$board" = "om2pv2" ] && break
- [ "$board" = "om2p-lc" ] && break
- [ "$board" = "om2p-hs" ] && break
- [ "$board" = "om2p-hsv2" ] && break
+ [ "$board" = "om2p" ] && return 0
+ [ "$board" = "om2pv2" ] && return 0
+ [ "$board" = "om2p-lc" ] && return 0
+ [ "$board" = "om2p-hs" ] && return 0
+ [ "$board" = "om2p-hsv2" ] && return 0
+ [ "$board" = "om2p-hsv3" ] && return 0
echo "Invalid image board target ($img_board_target) for this platform: $board. Use the correct image for this platform"
return 1
;;
OM5P)
- [ "$board" = "om5p" ] && break
- [ "$board" = "om5p-an" ] && break
+ [ "$board" = "om5p" ] && return 0
+ [ "$board" = "om5p-an" ] && return 0
echo "Invalid image board target ($img_board_target) for this platform: $board. Use the correct image for this platform"
return 1
;;
OM5PAC)
- [ "$board" = "om5p-ac" ] && break
- [ "$board" = "om5p-acv2" ] && break
+ [ "$board" = "om5p-ac" ] && return 0
+ [ "$board" = "om5p-acv2" ] && return 0
echo "Invalid image board target ($img_board_target) for this platform: $board. Use the correct image for this platform"
return 1
;;
MR1750)
- [ "$board" = "mr1750" ] && break
+ [ "$board" = "mr1750" ] && return 0
+ [ "$board" = "mr1750v2" ] && return 0
echo "Invalid image board target ($img_board_target) for this platform: $board. Use the correct image for this platform"
return 1
;;
MR600)
- [ "$board" = "mr600" ] && break
- [ "$board" = "mr600v2" ] && break
+ [ "$board" = "mr600" ] && return 0
+ [ "$board" = "mr600v2" ] && return 0
echo "Invalid image board target ($img_board_target) for this platform: $board. Use the correct image for this platform"
return 1
;;
MR900)
- [ "$board" = "mr900" ] && break
- [ "$board" = "mr900v2" ] && break
+ [ "$board" = "mr900" ] && return 0
+ [ "$board" = "mr900v2" ] && return 0
echo "Invalid image board target ($img_board_target) for this platform: $board. Use the correct image for this platform"
return 1
;;
@@ -100,8 +86,31 @@ platform_check_image_openmesh()
return 1
;;
esac
+}
+
+platform_check_image_openmesh()
+{
+ local img_magic=$1
+ local img_path=$2
+ local fw_printenv=/usr/sbin/fw_printenv
+ local img_board_target= img_num_files= i=0
+ local cfg_name= kernel_name= rootfs_name=
+
+ case "$img_magic" in
+ # Combined Extended Image v1
+ 43453031)
+ img_board_target=$(trim $(dd if="$img_path" bs=4 skip=1 count=8 2>/dev/null))
+ img_num_files=$(trim $(dd if="$img_path" bs=2 skip=18 count=1 2>/dev/null))
+ ;;
+ *)
+ echo "Invalid image ($img_magic). Use combined extended images on this platform"
+ return 1
+ ;;
+ esac
+
+ platform_check_image_target_openmesh "$img_board_target" || return 1
- [ $img_num_files -ne 3 ] && {
+ [ $img_num_files -lt 3 ] && {
echo "Invalid number of embedded images ($img_num_files). Use the correct image for this platform"
return 1
}
diff --git a/target/linux/ar71xx/base-files/lib/upgrade/platform.sh b/target/linux/ar71xx/base-files/lib/upgrade/platform.sh
index 9f8a14b2bc..313e2e639b 100755
--- a/target/linux/ar71xx/base-files/lib/upgrade/platform.sh
+++ b/target/linux/ar71xx/base-files/lib/upgrade/platform.sh
@@ -268,10 +268,12 @@ platform_check_image() {
wlae-ag300n | \
nbg460n_550n_550nh | \
unifi | \
- unifiac | \
+ unifiac-lite | \
+ unifiac-pro | \
unifi-outdoor | \
carambola2 | \
- weio )
+ weio | \
+ wrtnode2q)
[ "$magic" != "2705" ] && {
echo "Invalid image type."
return 1
@@ -279,6 +281,7 @@ platform_check_image() {
return 0
;;
+ cpe210|\
cpe510)
tplink_pharos_check_image "$1" && return 0
return 1
@@ -313,6 +316,7 @@ platform_check_image() {
return 0;
;;
mr1750 | \
+ mr1750v2 | \
mr600 | \
mr600v2 | \
mr900 | \
@@ -321,6 +325,7 @@ platform_check_image() {
om2pv2 | \
om2p-hs | \
om2p-hsv2 | \
+ om2p-hsv3 | \
om2p-lc | \
om5p | \
om5p-an | \
@@ -345,6 +350,7 @@ platform_check_image() {
onion-omega | \
oolite | \
smart-300 | \
+ som9331 | \
tellstick-znet-lite | \
tl-mr10u | \
tl-mr11u | \
@@ -384,7 +390,9 @@ platform_check_image() {
tl-wr841n-v7 | \
tl-wr841n-v8 | \
tl-wr841n-v9 | \
+ tl-wr841n-v11 | \
tl-wr842n-v2 | \
+ tl-wr842n-v3 | \
tl-wr941nd | \
tl-wr941nd-v5 | \
tl-wr941nd-v6 | \
@@ -571,6 +579,7 @@ platform_do_upgrade() {
platform_do_upgrade_dir825b "$ARGV"
;;
mr1750 | \
+ mr1750v2 | \
mr600 | \
mr600v2 | \
mr900 | \
@@ -579,6 +588,7 @@ platform_do_upgrade() {
om2pv2 | \
om2p-hs | \
om2p-hsv2 | \
+ om2p-hsv3 | \
om2p-lc | \
om5p | \
om5p-an | \
diff --git a/target/linux/ar71xx/config-4.4 b/target/linux/ar71xx/config-4.4
index 57ac5d825f..79d703b3db 100644
--- a/target/linux/ar71xx/config-4.4
+++ b/target/linux/ar71xx/config-4.4
@@ -131,6 +131,7 @@ CONFIG_ATH79_MACH_R6100=y
# CONFIG_ATH79_MACH_RBSXTLITE is not set
CONFIG_ATH79_MACH_RW2458N=y
CONFIG_ATH79_MACH_SMART_300=y
+CONFIG_ATH79_MACH_SOM9331=y
CONFIG_ATH79_MACH_TELLSTICK_ZNET_LITE=y
CONFIG_ATH79_MACH_TEW_632BRP=y
CONFIG_ATH79_MACH_TEW_673GRU=y
@@ -190,6 +191,7 @@ CONFIG_ATH79_MACH_WPJ531=y
CONFIG_ATH79_MACH_WPJ558=y
CONFIG_ATH79_MACH_WRT160NL=y
CONFIG_ATH79_MACH_WRT400N=y
+CONFIG_ATH79_MACH_WRTNODE2Q=y
CONFIG_ATH79_MACH_WZR_450HP2=y
CONFIG_ATH79_MACH_WZR_HP_AG300H=y
CONFIG_ATH79_MACH_WZR_HP_G300NH=y
diff --git a/target/linux/ar71xx/files-4.1/arch/mips/ath79/dev-eth.c b/target/linux/ar71xx/files-4.1/arch/mips/ath79/dev-eth.c
new file mode 100644
index 0000000000..b43c80a376
--- /dev/null
+++ b/target/linux/ar71xx/files-4.1/arch/mips/ath79/dev-eth.c
@@ -0,0 +1,1315 @@
+/*
+ * Atheros AR71xx SoC platform devices
+ *
+ * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com>
+ * Copyright (C) 2008-2012 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * Parts of this file are based on Atheros 2.6.15 BSP
+ * Parts of this file are based on Atheros 2.6.31 BSP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/platform_device.h>
+#include <linux/serial_8250.h>
+#include <linux/clk.h>
+#include <linux/sizes.h>
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/irq.h>
+
+#include "common.h"
+#include "dev-eth.h"
+
+unsigned char ath79_mac_base[ETH_ALEN] __initdata;
+
+static struct resource ath79_mdio0_resources[] = {
+ {
+ .name = "mdio_base",
+ .flags = IORESOURCE_MEM,
+ .start = AR71XX_GE0_BASE,
+ .end = AR71XX_GE0_BASE + 0x200 - 1,
+ }
+};
+
+struct ag71xx_mdio_platform_data ath79_mdio0_data;
+
+struct platform_device ath79_mdio0_device = {
+ .name = "ag71xx-mdio",
+ .id = 0,
+ .resource = ath79_mdio0_resources,
+ .num_resources = ARRAY_SIZE(ath79_mdio0_resources),
+ .dev = {
+ .platform_data = &ath79_mdio0_data,
+ },
+};
+
+static struct resource ath79_mdio1_resources[] = {
+ {
+ .name = "mdio_base",
+ .flags = IORESOURCE_MEM,
+ .start = AR71XX_GE1_BASE,
+ .end = AR71XX_GE1_BASE + 0x200 - 1,
+ }
+};
+
+struct ag71xx_mdio_platform_data ath79_mdio1_data;
+
+struct platform_device ath79_mdio1_device = {
+ .name = "ag71xx-mdio",
+ .id = 1,
+ .resource = ath79_mdio1_resources,
+ .num_resources = ARRAY_SIZE(ath79_mdio1_resources),
+ .dev = {
+ .platform_data = &ath79_mdio1_data,
+ },
+};
+
+static void ath79_set_pll(u32 cfg_reg, u32 pll_reg, u32 pll_val, u32 shift)
+{
+ void __iomem *base;
+ u32 t;
+
+ base = ioremap_nocache(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
+
+ t = __raw_readl(base + cfg_reg);
+ t &= ~(3 << shift);
+ t |= (2 << shift);
+ __raw_writel(t, base + cfg_reg);
+ udelay(100);
+
+ __raw_writel(pll_val, base + pll_reg);
+
+ t |= (3 << shift);
+ __raw_writel(t, base + cfg_reg);
+ udelay(100);
+
+ t &= ~(3 << shift);
+ __raw_writel(t, base + cfg_reg);
+ udelay(100);
+
+ printk(KERN_DEBUG "ar71xx: pll_reg %#x: %#x\n",
+ (unsigned int)(base + pll_reg), __raw_readl(base + pll_reg));
+
+ iounmap(base);
+}
+
+static void __init ath79_mii_ctrl_set_if(unsigned int reg,
+ unsigned int mii_if)
+{
+ void __iomem *base;
+ u32 t;
+
+ base = ioremap(AR71XX_MII_BASE, AR71XX_MII_SIZE);
+
+ t = __raw_readl(base + reg);
+ t &= ~(AR71XX_MII_CTRL_IF_MASK);
+ t |= (mii_if & AR71XX_MII_CTRL_IF_MASK);
+ __raw_writel(t, base + reg);
+
+ iounmap(base);
+}
+
+static void ath79_mii_ctrl_set_speed(unsigned int reg, unsigned int speed)
+{
+ void __iomem *base;
+ unsigned int mii_speed;
+ u32 t;
+
+ switch (speed) {
+ case SPEED_10:
+ mii_speed = AR71XX_MII_CTRL_SPEED_10;
+ break;
+ case SPEED_100:
+ mii_speed = AR71XX_MII_CTRL_SPEED_100;
+ break;
+ case SPEED_1000:
+ mii_speed = AR71XX_MII_CTRL_SPEED_1000;
+ break;
+ default:
+ BUG();
+ }
+
+ base = ioremap(AR71XX_MII_BASE, AR71XX_MII_SIZE);
+
+ t = __raw_readl(base + reg);
+ t &= ~(AR71XX_MII_CTRL_SPEED_MASK << AR71XX_MII_CTRL_SPEED_SHIFT);
+ t |= mii_speed << AR71XX_MII_CTRL_SPEED_SHIFT;
+ __raw_writel(t, base + reg);
+
+ iounmap(base);
+}
+
+static unsigned long ar934x_get_mdio_ref_clock(void)
+{
+ void __iomem *base;
+ unsigned long ret;
+ u32 t;
+
+ base = ioremap(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
+
+ ret = 0;
+ t = __raw_readl(base + AR934X_PLL_SWITCH_CLOCK_CONTROL_REG);
+ if (t & AR934X_PLL_SWITCH_CLOCK_CONTROL_MDIO_CLK_SEL) {
+ ret = 100 * 1000 * 1000;
+ } else {
+ struct clk *clk;
+
+ clk = clk_get(NULL, "ref");
+ if (!IS_ERR(clk))
+ ret = clk_get_rate(clk);
+ }
+
+ iounmap(base);
+
+ return ret;
+}
+
+void __init ath79_register_mdio(unsigned int id, u32 phy_mask)
+{
+ struct platform_device *mdio_dev;
+ struct ag71xx_mdio_platform_data *mdio_data;
+ unsigned int max_id;
+
+ if (ath79_soc == ATH79_SOC_AR9341 ||
+ ath79_soc == ATH79_SOC_AR9342 ||
+ ath79_soc == ATH79_SOC_AR9344 ||
+ ath79_soc == ATH79_SOC_QCA9556 ||
+ ath79_soc == ATH79_SOC_QCA9558 ||
+ ath79_soc == ATH79_SOC_QCA956X)
+ max_id = 1;
+ else
+ max_id = 0;
+
+ if (id > max_id) {
+ printk(KERN_ERR "ar71xx: invalid MDIO id %u\n", id);
+ return;
+ }
+
+ switch (ath79_soc) {
+ case ATH79_SOC_AR7241:
+ case ATH79_SOC_AR9330:
+ case ATH79_SOC_AR9331:
+ case ATH79_SOC_QCA9533:
+ case ATH79_SOC_TP9343:
+ mdio_dev = &ath79_mdio1_device;
+ mdio_data = &ath79_mdio1_data;
+ break;
+
+ case ATH79_SOC_AR9341:
+ case ATH79_SOC_AR9342:
+ case ATH79_SOC_AR9344:
+ case ATH79_SOC_QCA9556:
+ case ATH79_SOC_QCA9558:
+ case ATH79_SOC_QCA956X:
+ if (id == 0) {
+ mdio_dev = &ath79_mdio0_device;
+ mdio_data = &ath79_mdio0_data;
+ } else {
+ mdio_dev = &ath79_mdio1_device;
+ mdio_data = &ath79_mdio1_data;
+ }
+ break;
+
+ case ATH79_SOC_AR7242:
+ ath79_set_pll(AR71XX_PLL_REG_SEC_CONFIG,
+ AR7242_PLL_REG_ETH0_INT_CLOCK, 0x62000000,
+ AR71XX_ETH0_PLL_SHIFT);
+ /* fall through */
+ default:
+ mdio_dev = &ath79_mdio0_device;
+ mdio_data = &ath79_mdio0_data;
+ break;
+ }
+
+ mdio_data->phy_mask = phy_mask;
+
+ switch (ath79_soc) {
+ case ATH79_SOC_AR7240:
+ mdio_data->is_ar7240 = 1;
+ /* fall through */
+ case ATH79_SOC_AR7241:
+ mdio_data->builtin_switch = 1;
+ break;
+
+ case ATH79_SOC_AR9330:
+ mdio_data->is_ar9330 = 1;
+ /* fall through */
+ case ATH79_SOC_AR9331:
+ mdio_data->builtin_switch = 1;
+ break;
+
+ case ATH79_SOC_AR9341:
+ case ATH79_SOC_AR9342:
+ case ATH79_SOC_AR9344:
+ if (id == 1) {
+ mdio_data->builtin_switch = 1;
+ mdio_data->ref_clock = ar934x_get_mdio_ref_clock();
+ mdio_data->mdio_clock = 6250000;
+ }
+ mdio_data->is_ar934x = 1;
+ break;
+
+ case ATH79_SOC_QCA9533:
+ case ATH79_SOC_TP9343:
+ mdio_data->builtin_switch = 1;
+ break;
+
+ case ATH79_SOC_QCA9556:
+ case ATH79_SOC_QCA9558:
+ mdio_data->is_ar934x = 1;
+ break;
+
+ case ATH79_SOC_QCA956X:
+ if (id == 1)
+ mdio_data->builtin_switch = 1;
+ mdio_data->is_ar934x = 1;
+ break;
+
+ default:
+ break;
+ }
+
+ platform_device_register(mdio_dev);
+}
+
+struct ath79_eth_pll_data ath79_eth0_pll_data;
+struct ath79_eth_pll_data ath79_eth1_pll_data;
+
+static u32 ath79_get_eth_pll(unsigned int mac, int speed)
+{
+ struct ath79_eth_pll_data *pll_data;
+ u32 pll_val;
+
+ switch (mac) {
+ case 0:
+ pll_data = &ath79_eth0_pll_data;
+ break;
+ case 1:
+ pll_data = &ath79_eth1_pll_data;
+ break;
+ default:
+ BUG();
+ }
+
+ switch (speed) {
+ case SPEED_10:
+ pll_val = pll_data->pll_10;
+ break;
+ case SPEED_100:
+ pll_val = pll_data->pll_100;
+ break;
+ case SPEED_1000:
+ pll_val = pll_data->pll_1000;
+ break;
+ default:
+ BUG();
+ }
+
+ return pll_val;
+}
+
+static void ath79_set_speed_ge0(int speed)
+{
+ u32 val = ath79_get_eth_pll(0, speed);
+
+ ath79_set_pll(AR71XX_PLL_REG_SEC_CONFIG, AR71XX_PLL_REG_ETH0_INT_CLOCK,
+ val, AR71XX_ETH0_PLL_SHIFT);
+ ath79_mii_ctrl_set_speed(AR71XX_MII_REG_MII0_CTRL, speed);
+}
+
+static void ath79_set_speed_ge1(int speed)
+{
+ u32 val = ath79_get_eth_pll(1, speed);
+
+ ath79_set_pll(AR71XX_PLL_REG_SEC_CONFIG, AR71XX_PLL_REG_ETH1_INT_CLOCK,
+ val, AR71XX_ETH1_PLL_SHIFT);
+ ath79_mii_ctrl_set_speed(AR71XX_MII_REG_MII1_CTRL, speed);
+}
+
+static void ar7242_set_speed_ge0(int speed)
+{
+ u32 val = ath79_get_eth_pll(0, speed);
+ void __iomem *base;
+
+ base = ioremap_nocache(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
+ __raw_writel(val, base + AR7242_PLL_REG_ETH0_INT_CLOCK);
+ iounmap(base);
+}
+
+static void ar91xx_set_speed_ge0(int speed)
+{
+ u32 val = ath79_get_eth_pll(0, speed);
+
+ ath79_set_pll(AR913X_PLL_REG_ETH_CONFIG, AR913X_PLL_REG_ETH0_INT_CLOCK,
+ val, AR913X_ETH0_PLL_SHIFT);
+ ath79_mii_ctrl_set_speed(AR71XX_MII_REG_MII0_CTRL, speed);
+}
+
+static void ar91xx_set_speed_ge1(int speed)
+{
+ u32 val = ath79_get_eth_pll(1, speed);
+
+ ath79_set_pll(AR913X_PLL_REG_ETH_CONFIG, AR913X_PLL_REG_ETH1_INT_CLOCK,
+ val, AR913X_ETH1_PLL_SHIFT);
+ ath79_mii_ctrl_set_speed(AR71XX_MII_REG_MII1_CTRL, speed);
+}
+
+static void ar934x_set_speed_ge0(int speed)
+{
+ void __iomem *base;
+ u32 val = ath79_get_eth_pll(0, speed);
+
+ base = ioremap_nocache(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
+ __raw_writel(val, base + AR934X_PLL_ETH_XMII_CONTROL_REG);
+ iounmap(base);
+}
+
+static void qca955x_set_speed_xmii(int speed)
+{
+ void __iomem *base;
+ u32 val = ath79_get_eth_pll(0, speed);
+
+ base = ioremap_nocache(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
+ __raw_writel(val, base + QCA955X_PLL_ETH_XMII_CONTROL_REG);
+ iounmap(base);
+}
+
+static void qca955x_set_speed_sgmii(int speed)
+{
+ void __iomem *base;
+ u32 val = ath79_get_eth_pll(1, speed);
+
+ base = ioremap_nocache(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
+ __raw_writel(val, base + QCA955X_PLL_ETH_SGMII_CONTROL_REG);
+ iounmap(base);
+}
+
+static void qca956x_set_speed_sgmii(int speed)
+{
+ void __iomem *base;
+ u32 val = ath79_get_eth_pll(0, speed);
+
+ base = ioremap_nocache(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
+ __raw_writel(val, base + QCA955X_PLL_ETH_SGMII_CONTROL_REG);
+ iounmap(base);
+}
+
+static void ath79_set_speed_dummy(int speed)
+{
+}
+
+static void ath79_ddr_no_flush(void)
+{
+}
+
+static void ath79_ddr_flush_ge0(void)
+{
+ ath79_ddr_wb_flush(AR71XX_DDR_REG_FLUSH_GE0);
+}
+
+static void ath79_ddr_flush_ge1(void)
+{
+ ath79_ddr_wb_flush(AR71XX_DDR_REG_FLUSH_GE1);
+}
+
+static void ar724x_ddr_flush_ge0(void)
+{
+ ath79_ddr_wb_flush(AR724X_DDR_REG_FLUSH_GE0);
+}
+
+static void ar724x_ddr_flush_ge1(void)
+{
+ ath79_ddr_wb_flush(AR724X_DDR_REG_FLUSH_GE1);
+}
+
+static void ar91xx_ddr_flush_ge0(void)
+{
+ ath79_ddr_wb_flush(AR913X_DDR_REG_FLUSH_GE0);
+}
+
+static void ar91xx_ddr_flush_ge1(void)
+{
+ ath79_ddr_wb_flush(AR913X_DDR_REG_FLUSH_GE1);
+}
+
+static void ar933x_ddr_flush_ge0(void)
+{
+ ath79_ddr_wb_flush(AR933X_DDR_REG_FLUSH_GE0);
+}
+
+static void ar933x_ddr_flush_ge1(void)
+{
+ ath79_ddr_wb_flush(AR933X_DDR_REG_FLUSH_GE1);
+}
+
+static struct resource ath79_eth0_resources[] = {
+ {
+ .name = "mac_base",
+ .flags = IORESOURCE_MEM,
+ .start = AR71XX_GE0_BASE,
+ .end = AR71XX_GE0_BASE + 0x200 - 1,
+ }, {
+ .name = "mac_irq",
+ .flags = IORESOURCE_IRQ,
+ .start = ATH79_CPU_IRQ(4),
+ .end = ATH79_CPU_IRQ(4),
+ },
+};
+
+struct ag71xx_platform_data ath79_eth0_data = {
+ .reset_bit = AR71XX_RESET_GE0_MAC,
+};
+
+struct platform_device ath79_eth0_device = {
+ .name = "ag71xx",
+ .id = 0,
+ .resource = ath79_eth0_resources,
+ .num_resources = ARRAY_SIZE(ath79_eth0_resources),
+ .dev = {
+ .platform_data = &ath79_eth0_data,
+ },
+};
+
+static struct resource ath79_eth1_resources[] = {
+ {
+ .name = "mac_base",
+ .flags = IORESOURCE_MEM,
+ .start = AR71XX_GE1_BASE,
+ .end = AR71XX_GE1_BASE + 0x200 - 1,
+ }, {
+ .name = "mac_irq",
+ .flags = IORESOURCE_IRQ,
+ .start = ATH79_CPU_IRQ(5),
+ .end = ATH79_CPU_IRQ(5),
+ },
+};
+
+struct ag71xx_platform_data ath79_eth1_data = {
+ .reset_bit = AR71XX_RESET_GE1_MAC,
+};
+
+struct platform_device ath79_eth1_device = {
+ .name = "ag71xx",
+ .id = 1,
+ .resource = ath79_eth1_resources,
+ .num_resources = ARRAY_SIZE(ath79_eth1_resources),
+ .dev = {
+ .platform_data = &ath79_eth1_data,
+ },
+};
+
+struct ag71xx_switch_platform_data ath79_switch_data;
+
+#define AR71XX_PLL_VAL_1000 0x00110000
+#define AR71XX_PLL_VAL_100 0x00001099
+#define AR71XX_PLL_VAL_10 0x00991099
+
+#define AR724X_PLL_VAL_1000 0x00110000
+#define AR724X_PLL_VAL_100 0x00001099
+#define AR724X_PLL_VAL_10 0x00991099
+
+#define AR7242_PLL_VAL_1000 0x16000000
+#define AR7242_PLL_VAL_100 0x00000101
+#define AR7242_PLL_VAL_10 0x00001616
+
+#define AR913X_PLL_VAL_1000 0x1a000000
+#define AR913X_PLL_VAL_100 0x13000a44
+#define AR913X_PLL_VAL_10 0x00441099
+
+#define AR933X_PLL_VAL_1000 0x00110000
+#define AR933X_PLL_VAL_100 0x00001099
+#define AR933X_PLL_VAL_10 0x00991099
+
+#define AR934X_PLL_VAL_1000 0x16000000
+#define AR934X_PLL_VAL_100 0x00000101
+#define AR934X_PLL_VAL_10 0x00001616
+
+#define QCA956X_PLL_VAL_1000 0x03000000
+#define QCA956X_PLL_VAL_100 0x00000101
+#define QCA956X_PLL_VAL_10 0x00001919
+
+static void __init ath79_init_eth_pll_data(unsigned int id)
+{
+ struct ath79_eth_pll_data *pll_data;
+ u32 pll_10, pll_100, pll_1000;
+
+ switch (id) {
+ case 0:
+ pll_data = &ath79_eth0_pll_data;
+ break;
+ case 1:
+ pll_data = &ath79_eth1_pll_data;
+ break;
+ default:
+ BUG();
+ }
+
+ switch (ath79_soc) {
+ case ATH79_SOC_AR7130:
+ case ATH79_SOC_AR7141:
+ case ATH79_SOC_AR7161:
+ pll_10 = AR71XX_PLL_VAL_10;
+ pll_100 = AR71XX_PLL_VAL_100;
+ pll_1000 = AR71XX_PLL_VAL_1000;
+ break;
+
+ case ATH79_SOC_AR7240:
+ case ATH79_SOC_AR7241:
+ pll_10 = AR724X_PLL_VAL_10;
+ pll_100 = AR724X_PLL_VAL_100;
+ pll_1000 = AR724X_PLL_VAL_1000;
+ break;
+
+ case ATH79_SOC_AR7242:
+ pll_10 = AR7242_PLL_VAL_10;
+ pll_100 = AR7242_PLL_VAL_100;
+ pll_1000 = AR7242_PLL_VAL_1000;
+ break;
+
+ case ATH79_SOC_AR9130:
+ case ATH79_SOC_AR9132:
+ pll_10 = AR913X_PLL_VAL_10;
+ pll_100 = AR913X_PLL_VAL_100;
+ pll_1000 = AR913X_PLL_VAL_1000;
+ break;
+
+ case ATH79_SOC_AR9330:
+ case ATH79_SOC_AR9331:
+ pll_10 = AR933X_PLL_VAL_10;
+ pll_100 = AR933X_PLL_VAL_100;
+ pll_1000 = AR933X_PLL_VAL_1000;
+ break;
+
+ case ATH79_SOC_AR9341:
+ case ATH79_SOC_AR9342:
+ case ATH79_SOC_AR9344:
+ case ATH79_SOC_QCA9533:
+ case ATH79_SOC_QCA9556:
+ case ATH79_SOC_QCA9558:
+ case ATH79_SOC_TP9343:
+ pll_10 = AR934X_PLL_VAL_10;
+ pll_100 = AR934X_PLL_VAL_100;
+ pll_1000 = AR934X_PLL_VAL_1000;
+ break;
+
+ case ATH79_SOC_QCA956X:
+ pll_10 = QCA956X_PLL_VAL_10;
+ pll_100 = QCA956X_PLL_VAL_100;
+ pll_1000 = QCA956X_PLL_VAL_1000;
+ break;
+
+ default:
+ BUG();
+ }
+
+ if (!pll_data->pll_10)
+ pll_data->pll_10 = pll_10;
+
+ if (!pll_data->pll_100)
+ pll_data->pll_100 = pll_100;
+
+ if (!pll_data->pll_1000)
+ pll_data->pll_1000 = pll_1000;
+}
+
+static int __init ath79_setup_phy_if_mode(unsigned int id,
+ struct ag71xx_platform_data *pdata)
+{
+ unsigned int mii_if;
+
+ switch (id) {
+ case 0:
+ switch (ath79_soc) {
+ case ATH79_SOC_AR7130:
+ case ATH79_SOC_AR7141:
+ case ATH79_SOC_AR7161:
+ case ATH79_SOC_AR9130:
+ case ATH79_SOC_AR9132:
+ switch (pdata->phy_if_mode) {
+ case PHY_INTERFACE_MODE_MII:
+ mii_if = AR71XX_MII0_CTRL_IF_MII;
+ break;
+ case PHY_INTERFACE_MODE_GMII:
+ mii_if = AR71XX_MII0_CTRL_IF_GMII;
+ break;
+ case PHY_INTERFACE_MODE_RGMII:
+ mii_if = AR71XX_MII0_CTRL_IF_RGMII;
+ break;
+ case PHY_INTERFACE_MODE_RMII:
+ mii_if = AR71XX_MII0_CTRL_IF_RMII;
+ break;
+ default:
+ return -EINVAL;
+ }
+ ath79_mii_ctrl_set_if(AR71XX_MII_REG_MII0_CTRL, mii_if);
+ break;
+
+ case ATH79_SOC_AR7240:
+ case ATH79_SOC_AR7241:
+ case ATH79_SOC_AR9330:
+ case ATH79_SOC_AR9331:
+ case ATH79_SOC_QCA9533:
+ case ATH79_SOC_TP9343:
+ pdata->phy_if_mode = PHY_INTERFACE_MODE_MII;
+ break;
+
+ case ATH79_SOC_AR7242:
+ /* FIXME */
+
+ case ATH79_SOC_AR9341:
+ case ATH79_SOC_AR9342:
+ case ATH79_SOC_AR9344:
+ switch (pdata->phy_if_mode) {
+ case PHY_INTERFACE_MODE_MII:
+ case PHY_INTERFACE_MODE_GMII:
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RMII:
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+
+ case ATH79_SOC_QCA9556:
+ case ATH79_SOC_QCA9558:
+ case ATH79_SOC_QCA956X:
+ switch (pdata->phy_if_mode) {
+ case PHY_INTERFACE_MODE_MII:
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_SGMII:
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+
+ default:
+ BUG();
+ }
+ break;
+ case 1:
+ switch (ath79_soc) {
+ case ATH79_SOC_AR7130:
+ case ATH79_SOC_AR7141:
+ case ATH79_SOC_AR7161:
+ case ATH79_SOC_AR9130:
+ case ATH79_SOC_AR9132:
+ switch (pdata->phy_if_mode) {
+ case PHY_INTERFACE_MODE_RMII:
+ mii_if = AR71XX_MII1_CTRL_IF_RMII;
+ break;
+ case PHY_INTERFACE_MODE_RGMII:
+ mii_if = AR71XX_MII1_CTRL_IF_RGMII;
+ break;
+ default:
+ return -EINVAL;
+ }
+ ath79_mii_ctrl_set_if(AR71XX_MII_REG_MII1_CTRL, mii_if);
+ break;
+
+ case ATH79_SOC_AR7240:
+ case ATH79_SOC_AR7241:
+ case ATH79_SOC_AR9330:
+ case ATH79_SOC_AR9331:
+ case ATH79_SOC_QCA956X:
+ case ATH79_SOC_TP9343:
+ pdata->phy_if_mode = PHY_INTERFACE_MODE_GMII;
+ break;
+
+ case ATH79_SOC_AR7242:
+ /* FIXME */
+
+ case ATH79_SOC_AR9341:
+ case ATH79_SOC_AR9342:
+ case ATH79_SOC_AR9344:
+ case ATH79_SOC_QCA9533:
+ switch (pdata->phy_if_mode) {
+ case PHY_INTERFACE_MODE_MII:
+ case PHY_INTERFACE_MODE_GMII:
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+
+ case ATH79_SOC_QCA9556:
+ case ATH79_SOC_QCA9558:
+ switch (pdata->phy_if_mode) {
+ case PHY_INTERFACE_MODE_MII:
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_SGMII:
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+
+ default:
+ BUG();
+ }
+ break;
+ }
+
+ return 0;
+}
+
+void __init ath79_setup_ar933x_phy4_switch(bool mac, bool mdio)
+{
+ void __iomem *base;
+ u32 t;
+
+ base = ioremap(AR933X_GMAC_BASE, AR933X_GMAC_SIZE);
+
+ t = __raw_readl(base + AR933X_GMAC_REG_ETH_CFG);
+ t &= ~(AR933X_ETH_CFG_SW_PHY_SWAP | AR933X_ETH_CFG_SW_PHY_ADDR_SWAP);
+ if (mac)
+ t |= AR933X_ETH_CFG_SW_PHY_SWAP;
+ if (mdio)
+ t |= AR933X_ETH_CFG_SW_PHY_ADDR_SWAP;
+ __raw_writel(t, base + AR933X_GMAC_REG_ETH_CFG);
+
+ iounmap(base);
+}
+
+void __init ath79_setup_ar934x_eth_cfg(u32 mask)
+{
+ void __iomem *base;
+ u32 t;
+
+ base = ioremap(AR934X_GMAC_BASE, AR934X_GMAC_SIZE);
+
+ t = __raw_readl(base + AR934X_GMAC_REG_ETH_CFG);
+
+ t &= ~(AR934X_ETH_CFG_RGMII_GMAC0 |
+ AR934X_ETH_CFG_MII_GMAC0 |
+ AR934X_ETH_CFG_GMII_GMAC0 |
+ AR934X_ETH_CFG_SW_ONLY_MODE |
+ AR934X_ETH_CFG_SW_PHY_SWAP);
+
+ t |= mask;
+
+ __raw_writel(t, base + AR934X_GMAC_REG_ETH_CFG);
+ /* flush write */
+ __raw_readl(base + AR934X_GMAC_REG_ETH_CFG);
+
+ iounmap(base);
+}
+
+void __init ath79_setup_ar934x_eth_rx_delay(unsigned int rxd,
+ unsigned int rxdv)
+{
+ void __iomem *base;
+ u32 t;
+
+ rxd &= AR934X_ETH_CFG_RXD_DELAY_MASK;
+ rxdv &= AR934X_ETH_CFG_RDV_DELAY_MASK;
+
+ base = ioremap(AR934X_GMAC_BASE, AR934X_GMAC_SIZE);
+
+ t = __raw_readl(base + AR934X_GMAC_REG_ETH_CFG);
+
+ t &= ~(AR934X_ETH_CFG_RXD_DELAY_MASK << AR934X_ETH_CFG_RXD_DELAY_SHIFT |
+ AR934X_ETH_CFG_RDV_DELAY_MASK << AR934X_ETH_CFG_RDV_DELAY_SHIFT);
+
+ t |= (rxd << AR934X_ETH_CFG_RXD_DELAY_SHIFT |
+ rxdv << AR934X_ETH_CFG_RDV_DELAY_SHIFT);
+
+ __raw_writel(t, base + AR934X_GMAC_REG_ETH_CFG);
+ /* flush write */
+ __raw_readl(base + AR934X_GMAC_REG_ETH_CFG);
+
+ iounmap(base);
+}
+
+void __init ath79_setup_qca955x_eth_cfg(u32 mask)
+{
+ void __iomem *base;
+ u32 t;
+
+ base = ioremap(QCA955X_GMAC_BASE, QCA955X_GMAC_SIZE);
+
+ t = __raw_readl(base + QCA955X_GMAC_REG_ETH_CFG);
+
+ t &= ~(QCA955X_ETH_CFG_RGMII_EN | QCA955X_ETH_CFG_GE0_SGMII);
+
+ t |= mask;
+
+ __raw_writel(t, base + QCA955X_GMAC_REG_ETH_CFG);
+
+ iounmap(base);
+}
+
+static int ath79_eth_instance __initdata;
+void __init ath79_register_eth(unsigned int id)
+{
+ struct platform_device *pdev;
+ struct ag71xx_platform_data *pdata;
+ int err;
+
+ if (id > 1) {
+ printk(KERN_ERR "ar71xx: invalid ethernet id %d\n", id);
+ return;
+ }
+
+ ath79_init_eth_pll_data(id);
+
+ if (id == 0)
+ pdev = &ath79_eth0_device;
+ else
+ pdev = &ath79_eth1_device;
+
+ pdata = pdev->dev.platform_data;
+
+ pdata->max_frame_len = 1540;
+ pdata->desc_pktlen_mask = 0xfff;
+
+ err = ath79_setup_phy_if_mode(id, pdata);
+ if (err) {
+ printk(KERN_ERR
+ "ar71xx: invalid PHY interface mode for GE%u\n", id);
+ return;
+ }
+
+ switch (ath79_soc) {
+ case ATH79_SOC_AR7130:
+ if (id == 0) {
+ pdata->ddr_flush = ath79_ddr_flush_ge0;
+ pdata->set_speed = ath79_set_speed_ge0;
+ } else {
+ pdata->ddr_flush = ath79_ddr_flush_ge1;
+ pdata->set_speed = ath79_set_speed_ge1;
+ }
+ break;
+
+ case ATH79_SOC_AR7141:
+ case ATH79_SOC_AR7161:
+ if (id == 0) {
+ pdata->ddr_flush = ath79_ddr_flush_ge0;
+ pdata->set_speed = ath79_set_speed_ge0;
+ } else {
+ pdata->ddr_flush = ath79_ddr_flush_ge1;
+ pdata->set_speed = ath79_set_speed_ge1;
+ }
+ pdata->has_gbit = 1;
+ break;
+
+ case ATH79_SOC_AR7242:
+ if (id == 0) {
+ pdata->reset_bit |= AR724X_RESET_GE0_MDIO |
+ AR71XX_RESET_GE0_PHY;
+ pdata->ddr_flush = ar724x_ddr_flush_ge0;
+ pdata->set_speed = ar7242_set_speed_ge0;
+ } else {
+ pdata->reset_bit |= AR724X_RESET_GE1_MDIO |
+ AR71XX_RESET_GE1_PHY;
+ pdata->ddr_flush = ar724x_ddr_flush_ge1;
+ pdata->set_speed = ath79_set_speed_dummy;
+ }
+ pdata->has_gbit = 1;
+ pdata->is_ar724x = 1;
+
+ if (!pdata->fifo_cfg1)
+ pdata->fifo_cfg1 = 0x0010ffff;
+ if (!pdata->fifo_cfg2)
+ pdata->fifo_cfg2 = 0x015500aa;
+ if (!pdata->fifo_cfg3)
+ pdata->fifo_cfg3 = 0x01f00140;
+ break;
+
+ case ATH79_SOC_AR7241:
+ if (id == 0)
+ pdata->reset_bit |= AR724X_RESET_GE0_MDIO;
+ else
+ pdata->reset_bit |= AR724X_RESET_GE1_MDIO;
+ /* fall through */
+ case ATH79_SOC_AR7240:
+ if (id == 0) {
+ pdata->reset_bit |= AR71XX_RESET_GE0_PHY;
+ pdata->ddr_flush = ar724x_ddr_flush_ge0;
+ pdata->set_speed = ath79_set_speed_dummy;
+
+ pdata->phy_mask = BIT(4);
+ } else {
+ pdata->reset_bit |= AR71XX_RESET_GE1_PHY;
+ pdata->ddr_flush = ar724x_ddr_flush_ge1;
+ pdata->set_speed = ath79_set_speed_dummy;
+
+ pdata->speed = SPEED_1000;
+ pdata->duplex = DUPLEX_FULL;
+ pdata->switch_data = &ath79_switch_data;
+
+ ath79_switch_data.phy_poll_mask |= BIT(4);
+ }
+ pdata->has_gbit = 1;
+ pdata->is_ar724x = 1;
+ if (ath79_soc == ATH79_SOC_AR7240)
+ pdata->is_ar7240 = 1;
+
+ if (!pdata->fifo_cfg1)
+ pdata->fifo_cfg1 = 0x0010ffff;
+ if (!pdata->fifo_cfg2)
+ pdata->fifo_cfg2 = 0x015500aa;
+ if (!pdata->fifo_cfg3)
+ pdata->fifo_cfg3 = 0x01f00140;
+ break;
+
+ case ATH79_SOC_AR9130:
+ if (id == 0) {
+ pdata->ddr_flush = ar91xx_ddr_flush_ge0;
+ pdata->set_speed = ar91xx_set_speed_ge0;
+ } else {
+ pdata->ddr_flush = ar91xx_ddr_flush_ge1;
+ pdata->set_speed = ar91xx_set_speed_ge1;
+ }
+ pdata->is_ar91xx = 1;
+ break;
+
+ case ATH79_SOC_AR9132:
+ if (id == 0) {
+ pdata->ddr_flush = ar91xx_ddr_flush_ge0;
+ pdata->set_speed = ar91xx_set_speed_ge0;
+ } else {
+ pdata->ddr_flush = ar91xx_ddr_flush_ge1;
+ pdata->set_speed = ar91xx_set_speed_ge1;
+ }
+ pdata->is_ar91xx = 1;
+ pdata->has_gbit = 1;
+ break;
+
+ case ATH79_SOC_AR9330:
+ case ATH79_SOC_AR9331:
+ if (id == 0) {
+ pdata->reset_bit = AR933X_RESET_GE0_MAC |
+ AR933X_RESET_GE0_MDIO;
+ pdata->ddr_flush = ar933x_ddr_flush_ge0;
+ pdata->set_speed = ath79_set_speed_dummy;
+
+ pdata->phy_mask = BIT(4);
+ } else {
+ pdata->reset_bit = AR933X_RESET_GE1_MAC |
+ AR933X_RESET_GE1_MDIO;
+ pdata->ddr_flush = ar933x_ddr_flush_ge1;
+ pdata->set_speed = ath79_set_speed_dummy;
+
+ pdata->speed = SPEED_1000;
+ pdata->has_gbit = 1;
+ pdata->duplex = DUPLEX_FULL;
+ pdata->switch_data = &ath79_switch_data;
+
+ ath79_switch_data.phy_poll_mask |= BIT(4);
+ }
+
+ pdata->is_ar724x = 1;
+
+ if (!pdata->fifo_cfg1)
+ pdata->fifo_cfg1 = 0x0010ffff;
+ if (!pdata->fifo_cfg2)
+ pdata->fifo_cfg2 = 0x015500aa;
+ if (!pdata->fifo_cfg3)
+ pdata->fifo_cfg3 = 0x01f00140;
+ break;
+
+ case ATH79_SOC_AR9341:
+ case ATH79_SOC_AR9342:
+ case ATH79_SOC_AR9344:
+ case ATH79_SOC_QCA9533:
+ if (id == 0) {
+ pdata->reset_bit = AR934X_RESET_GE0_MAC |
+ AR934X_RESET_GE0_MDIO;
+ pdata->set_speed = ar934x_set_speed_ge0;
+ } else {
+ pdata->reset_bit = AR934X_RESET_GE1_MAC |
+ AR934X_RESET_GE1_MDIO;
+ pdata->set_speed = ath79_set_speed_dummy;
+
+ pdata->switch_data = &ath79_switch_data;
+
+ /* reset the built-in switch */
+ ath79_device_reset_set(AR934X_RESET_ETH_SWITCH);
+ ath79_device_reset_clear(AR934X_RESET_ETH_SWITCH);
+ }
+
+ pdata->ddr_flush = ath79_ddr_no_flush;
+ pdata->has_gbit = 1;
+ pdata->is_ar724x = 1;
+
+ pdata->max_frame_len = SZ_16K - 1;
+ pdata->desc_pktlen_mask = SZ_16K - 1;
+
+ if (!pdata->fifo_cfg1)
+ pdata->fifo_cfg1 = 0x0010ffff;
+ if (!pdata->fifo_cfg2)
+ pdata->fifo_cfg2 = 0x015500aa;
+ if (!pdata->fifo_cfg3)
+ pdata->fifo_cfg3 = 0x01f00140;
+ break;
+
+ case ATH79_SOC_TP9343:
+ if (id == 0) {
+ pdata->reset_bit = AR933X_RESET_GE0_MAC |
+ AR933X_RESET_GE0_MDIO;
+ pdata->set_speed = ath79_set_speed_dummy;
+
+ if (!pdata->phy_mask)
+ pdata->phy_mask = BIT(4);
+ } else {
+ pdata->reset_bit = AR933X_RESET_GE1_MAC |
+ AR933X_RESET_GE1_MDIO;
+ pdata->set_speed = ath79_set_speed_dummy;
+
+ pdata->speed = SPEED_1000;
+ pdata->duplex = DUPLEX_FULL;
+ pdata->switch_data = &ath79_switch_data;
+
+ ath79_switch_data.phy_poll_mask |= BIT(4);
+ }
+
+ pdata->ddr_flush = ath79_ddr_no_flush;
+ pdata->has_gbit = 1;
+ pdata->is_ar724x = 1;
+
+ if (!pdata->fifo_cfg1)
+ pdata->fifo_cfg1 = 0x0010ffff;
+ if (!pdata->fifo_cfg2)
+ pdata->fifo_cfg2 = 0x015500aa;
+ if (!pdata->fifo_cfg3)
+ pdata->fifo_cfg3 = 0x01f00140;
+ break;
+
+ case ATH79_SOC_QCA9556:
+ case ATH79_SOC_QCA9558:
+ if (id == 0) {
+ pdata->reset_bit = QCA955X_RESET_GE0_MAC |
+ QCA955X_RESET_GE0_MDIO;
+ pdata->set_speed = qca955x_set_speed_xmii;
+ } else {
+ pdata->reset_bit = QCA955X_RESET_GE1_MAC |
+ QCA955X_RESET_GE1_MDIO;
+ pdata->set_speed = qca955x_set_speed_sgmii;
+ }
+
+ pdata->ddr_flush = ath79_ddr_no_flush;
+ pdata->has_gbit = 1;
+ pdata->is_ar724x = 1;
+
+ /*
+ * Limit the maximum frame length to 4095 bytes.
+ * Although the documentation says that the hardware
+ * limit is 16383 bytes but that does not work in
+ * practice. It seems that the hardware only updates
+ * the lowest 12 bits of the packet length field
+ * in the RX descriptor.
+ */
+ pdata->max_frame_len = SZ_4K - 1;
+ pdata->desc_pktlen_mask = SZ_16K - 1;
+
+ if (!pdata->fifo_cfg1)
+ pdata->fifo_cfg1 = 0x0010ffff;
+ if (!pdata->fifo_cfg2)
+ pdata->fifo_cfg2 = 0x015500aa;
+ if (!pdata->fifo_cfg3)
+ pdata->fifo_cfg3 = 0x01f00140;
+ break;
+
+ case ATH79_SOC_QCA956X:
+ if (id == 0) {
+ pdata->reset_bit = QCA955X_RESET_GE0_MAC |
+ QCA955X_RESET_GE0_MDIO;
+
+ if (pdata->phy_if_mode == PHY_INTERFACE_MODE_SGMII)
+ pdata->set_speed = qca956x_set_speed_sgmii;
+ else
+ pdata->set_speed = ath79_set_speed_ge0;
+ } else {
+ pdata->reset_bit = QCA955X_RESET_GE1_MAC |
+ QCA955X_RESET_GE1_MDIO;
+
+ pdata->set_speed = ath79_set_speed_dummy;
+
+ pdata->switch_data = &ath79_switch_data;
+
+ pdata->speed = SPEED_1000;
+ pdata->duplex = DUPLEX_FULL;
+
+ /* reset the built-in switch */
+ ath79_device_reset_set(AR934X_RESET_ETH_SWITCH);
+ ath79_device_reset_clear(AR934X_RESET_ETH_SWITCH);
+ }
+
+ pdata->ddr_flush = ath79_ddr_no_flush;
+ pdata->has_gbit = 1;
+ pdata->is_ar724x = 1;
+
+ if (!pdata->fifo_cfg1)
+ pdata->fifo_cfg1 = 0x0010ffff;
+ if (!pdata->fifo_cfg2)
+ pdata->fifo_cfg2 = 0x015500aa;
+ if (!pdata->fifo_cfg3)
+ pdata->fifo_cfg3 = 0x01f00140;
+ break;
+
+ default:
+ BUG();
+ }
+
+ switch (pdata->phy_if_mode) {
+ case PHY_INTERFACE_MODE_GMII:
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_SGMII:
+ if (!pdata->has_gbit) {
+ printk(KERN_ERR "ar71xx: no gbit available on eth%d\n",
+ id);
+ return;
+ }
+ /* fallthrough */
+ default:
+ break;
+ }
+
+ if (!is_valid_ether_addr(pdata->mac_addr)) {
+ random_ether_addr(pdata->mac_addr);
+ printk(KERN_DEBUG
+ "ar71xx: using random MAC address for eth%d\n",
+ ath79_eth_instance);
+ }
+
+ if (pdata->mii_bus_dev == NULL) {
+ switch (ath79_soc) {
+ case ATH79_SOC_AR9341:
+ case ATH79_SOC_AR9342:
+ case ATH79_SOC_AR9344:
+ if (id == 0)
+ pdata->mii_bus_dev = &ath79_mdio0_device.dev;
+ else
+ pdata->mii_bus_dev = &ath79_mdio1_device.dev;
+ break;
+
+ case ATH79_SOC_AR7241:
+ case ATH79_SOC_AR9330:
+ case ATH79_SOC_AR9331:
+ case ATH79_SOC_QCA9533:
+ case ATH79_SOC_TP9343:
+ pdata->mii_bus_dev = &ath79_mdio1_device.dev;
+ break;
+
+ case ATH79_SOC_QCA9556:
+ case ATH79_SOC_QCA9558:
+ /* don't assign any MDIO device by default */
+ break;
+
+ case ATH79_SOC_QCA956X:
+ if (pdata->phy_if_mode != PHY_INTERFACE_MODE_SGMII)
+ pdata->mii_bus_dev = &ath79_mdio1_device.dev;
+ break;
+
+ default:
+ pdata->mii_bus_dev = &ath79_mdio0_device.dev;
+ break;
+ }
+ }
+
+ /* Reset the device */
+ ath79_device_reset_set(pdata->reset_bit);
+ msleep(100);
+
+ ath79_device_reset_clear(pdata->reset_bit);
+ msleep(100);
+
+ platform_device_register(pdev);
+ ath79_eth_instance++;
+}
+
+void __init ath79_set_mac_base(unsigned char *mac)
+{
+ memcpy(ath79_mac_base, mac, ETH_ALEN);
+}
+
+void __init ath79_parse_ascii_mac(char *mac_str, u8 *mac)
+{
+ int t;
+
+ t = sscanf(mac_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
+ &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
+
+ if (t != ETH_ALEN)
+ t = sscanf(mac_str, "%02hhx.%02hhx.%02hhx.%02hhx.%02hhx.%02hhx",
+ &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
+
+ if (t != ETH_ALEN || !is_valid_ether_addr(mac)) {
+ memset(mac, 0, ETH_ALEN);
+ printk(KERN_DEBUG "ar71xx: invalid mac address \"%s\"\n",
+ mac_str);
+ }
+}
+
+static void __init ath79_set_mac_base_ascii(char *str)
+{
+ u8 mac[ETH_ALEN];
+
+ ath79_parse_ascii_mac(str, mac);
+ ath79_set_mac_base(mac);
+}
+
+static int __init ath79_ethaddr_setup(char *str)
+{
+ ath79_set_mac_base_ascii(str);
+ return 1;
+}
+__setup("ethaddr=", ath79_ethaddr_setup);
+
+static int __init ath79_kmac_setup(char *str)
+{
+ ath79_set_mac_base_ascii(str);
+ return 1;
+}
+__setup("kmac=", ath79_kmac_setup);
+
+void __init ath79_init_mac(unsigned char *dst, const unsigned char *src,
+ int offset)
+{
+ int t;
+
+ if (!dst)
+ return;
+
+ if (!src || !is_valid_ether_addr(src)) {
+ memset(dst, '\0', ETH_ALEN);
+ return;
+ }
+
+ t = (((u32) src[3]) << 16) + (((u32) src[4]) << 8) + ((u32) src[5]);
+ t += offset;
+
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = (t >> 16) & 0xff;
+ dst[4] = (t >> 8) & 0xff;
+ dst[5] = t & 0xff;
+}
+
+void __init ath79_init_local_mac(unsigned char *dst, const unsigned char *src)
+{
+ int i;
+
+ if (!dst)
+ return;
+
+ if (!src || !is_valid_ether_addr(src)) {
+ memset(dst, '\0', ETH_ALEN);
+ return;
+ }
+
+ for (i = 0; i < ETH_ALEN; i++)
+ dst[i] = src[i];
+ dst[0] |= 0x02;
+}
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/Kconfig.openwrt b/target/linux/ar71xx/files/arch/mips/ath79/Kconfig.openwrt
index 0fb2df26d4..52b9b5527e 100644
--- a/target/linux/ar71xx/files/arch/mips/ath79/Kconfig.openwrt
+++ b/target/linux/ar71xx/files/arch/mips/ath79/Kconfig.openwrt
@@ -249,6 +249,16 @@ config ATH79_MACH_ESR1750
select ATH79_DEV_USB
select ATH79_DEV_WMAC
+config ATH79_MACH_SOM9331
+ bool "SOM9331 support"
+ select SOC_AR933X
+ select ATH79_DEV_ETH
+ select ATH79_DEV_GPIO_BUTTONS
+ select ATH79_DEV_LEDS_GPIO
+ select ATH79_DEV_M25P80
+ select ATH79_DEV_USB
+ select ATH79_DEV_WMAC
+
config ATH79_MACH_WHR_HP_G300N
bool "Buffalo WHR-HP-G300N board support"
select SOC_AR724X
@@ -680,6 +690,16 @@ config ATH79_MACH_WRT400N
select ATH79_DEV_LEDS_GPIO
select ATH79_DEV_M25P80
+config ATH79_MACH_WRTNODE2Q
+ bool "WRTnode2Q board support"
+ select SOC_QCA953X
+ select ATH79_DEV_AP9X_PCI if PCI
+ select ATH79_DEV_ETH
+ select ATH79_DEV_GPIO_BUTTONS
+ select ATH79_DEV_LEDS_GPIO
+ select ATH79_DEV_M25P80
+ select ATH79_DEV_WMAC
+
config ATH79_MACH_R6100
bool "NETGEAR R6100 board support"
select SOC_AR934X
@@ -1314,13 +1334,14 @@ config ATH79_MACH_TL_WR841N_V8
select ATH79_DEV_WMAC
config ATH79_MACH_TL_WR841N_V9
- bool "TP-LINK TL-WR841N/ND v9 support"
- select SOC_QCA953X
- select ATH79_DEV_ETH
- select ATH79_DEV_GPIO_BUTTONS
- select ATH79_DEV_LEDS_GPIO
- select ATH79_DEV_M25P80
- select ATH79_DEV_WMAC
+ bool "TP-LINK TL-WR841N/ND v9/TL-WR842N/ND v3 support"
+ select SOC_QCA953X
+ select ATH79_DEV_ETH
+ select ATH79_DEV_GPIO_BUTTONS
+ select ATH79_DEV_LEDS_GPIO
+ select ATH79_DEV_M25P80
+ select ATH79_DEV_USB
+ select ATH79_DEV_WMAC
config ATH79_MACH_TL_WR941ND
bool "TP-LINK TL-WR941ND support"
@@ -1442,7 +1463,7 @@ config ATH79_MACH_UBNT
select ATH79_DEV_USB
config ATH79_MACH_UBNT_UNIFIAC
- bool "Ubiquiti UniFi AC (LITE) support"
+ bool "Ubiquiti UniFi AC (LITE/LR/PRO) support"
select SOC_QCA956X
select ATH79_DEV_AP9X_PCI if PCI
select ATH79_DEV_ETH
@@ -1450,6 +1471,7 @@ config ATH79_MACH_UBNT_UNIFIAC
select ATH79_DEV_LEDS_GPIO
select ATH79_DEV_M25P80
select ATH79_DEV_WMAC
+ select ATH79_DEV_USB
config ATH79_MACH_WEIO
bool "WeIO board"
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/Makefile b/target/linux/ar71xx/files/arch/mips/ath79/Makefile
index 6144e29157..f8b0b2bb5a 100644
--- a/target/linux/ar71xx/files/arch/mips/ath79/Makefile
+++ b/target/linux/ar71xx/files/arch/mips/ath79/Makefile
@@ -135,6 +135,7 @@ obj-$(CONFIG_ATH79_MACH_RB2011) += mach-rb2011.o
obj-$(CONFIG_ATH79_MACH_RBSXTLITE) += mach-rbsxtlite.o
obj-$(CONFIG_ATH79_MACH_RW2458N) += mach-rw2458n.o
obj-$(CONFIG_ATH79_MACH_SMART_300) += mach-smart-300.o
+obj-$(CONFIG_ATH79_MACH_SOM9331) += mach-som9331.o
obj-$(CONFIG_ATH79_MACH_TELLSTICK_ZNET_LITE) += mach-tellstick-znet-lite.o
obj-$(CONFIG_ATH79_MACH_TEW_632BRP) += mach-tew-632brp.o
obj-$(CONFIG_ATH79_MACH_TEW_673GRU) += mach-tew-673gru.o
@@ -194,6 +195,7 @@ obj-$(CONFIG_ATH79_MACH_WPJ531) += mach-wpj531.o
obj-$(CONFIG_ATH79_MACH_WPJ558) += mach-wpj558.o
obj-$(CONFIG_ATH79_MACH_WRT160NL) += mach-wrt160nl.o
obj-$(CONFIG_ATH79_MACH_WRT400N) += mach-wrt400n.o
+obj-$(CONFIG_ATH79_MACH_WRTNODE2Q) += mach-wrtnode2q.o
obj-$(CONFIG_ATH79_MACH_WZR_HP_G300NH) += mach-wzr-hp-g300nh.o
obj-$(CONFIG_ATH79_MACH_WZR_HP_G300NH2) += mach-wzr-hp-g300nh2.o
obj-$(CONFIG_ATH79_MACH_WZR_HP_AG300H) += mach-wzr-hp-ag300h.o
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/dev-eth.c b/target/linux/ar71xx/files/arch/mips/ath79/dev-eth.c
index b43c80a376..17dd3ac6b1 100644
--- a/target/linux/ar71xx/files/arch/mips/ath79/dev-eth.c
+++ b/target/linux/ar71xx/files/arch/mips/ath79/dev-eth.c
@@ -407,48 +407,14 @@ static void ath79_set_speed_dummy(int speed)
{
}
-static void ath79_ddr_no_flush(void)
-{
-}
-
static void ath79_ddr_flush_ge0(void)
{
- ath79_ddr_wb_flush(AR71XX_DDR_REG_FLUSH_GE0);
+ ath79_ddr_wb_flush(0);
}
static void ath79_ddr_flush_ge1(void)
{
- ath79_ddr_wb_flush(AR71XX_DDR_REG_FLUSH_GE1);
-}
-
-static void ar724x_ddr_flush_ge0(void)
-{
- ath79_ddr_wb_flush(AR724X_DDR_REG_FLUSH_GE0);
-}
-
-static void ar724x_ddr_flush_ge1(void)
-{
- ath79_ddr_wb_flush(AR724X_DDR_REG_FLUSH_GE1);
-}
-
-static void ar91xx_ddr_flush_ge0(void)
-{
- ath79_ddr_wb_flush(AR913X_DDR_REG_FLUSH_GE0);
-}
-
-static void ar91xx_ddr_flush_ge1(void)
-{
- ath79_ddr_wb_flush(AR913X_DDR_REG_FLUSH_GE1);
-}
-
-static void ar933x_ddr_flush_ge0(void)
-{
- ath79_ddr_wb_flush(AR933X_DDR_REG_FLUSH_GE0);
-}
-
-static void ar933x_ddr_flush_ge1(void)
-{
- ath79_ddr_wb_flush(AR933X_DDR_REG_FLUSH_GE1);
+ ath79_ddr_wb_flush(1);
}
static struct resource ath79_eth0_resources[] = {
@@ -879,26 +845,25 @@ void __init ath79_register_eth(unsigned int id)
return;
}
+ if (id == 0)
+ pdata->ddr_flush = ath79_ddr_flush_ge0;
+ else
+ pdata->ddr_flush = ath79_ddr_flush_ge1;
+
switch (ath79_soc) {
case ATH79_SOC_AR7130:
- if (id == 0) {
- pdata->ddr_flush = ath79_ddr_flush_ge0;
+ if (id == 0)
pdata->set_speed = ath79_set_speed_ge0;
- } else {
- pdata->ddr_flush = ath79_ddr_flush_ge1;
+ else
pdata->set_speed = ath79_set_speed_ge1;
- }
break;
case ATH79_SOC_AR7141:
case ATH79_SOC_AR7161:
- if (id == 0) {
- pdata->ddr_flush = ath79_ddr_flush_ge0;
+ if (id == 0)
pdata->set_speed = ath79_set_speed_ge0;
- } else {
- pdata->ddr_flush = ath79_ddr_flush_ge1;
+ else
pdata->set_speed = ath79_set_speed_ge1;
- }
pdata->has_gbit = 1;
break;
@@ -906,12 +871,10 @@ void __init ath79_register_eth(unsigned int id)
if (id == 0) {
pdata->reset_bit |= AR724X_RESET_GE0_MDIO |
AR71XX_RESET_GE0_PHY;
- pdata->ddr_flush = ar724x_ddr_flush_ge0;
pdata->set_speed = ar7242_set_speed_ge0;
} else {
pdata->reset_bit |= AR724X_RESET_GE1_MDIO |
AR71XX_RESET_GE1_PHY;
- pdata->ddr_flush = ar724x_ddr_flush_ge1;
pdata->set_speed = ath79_set_speed_dummy;
}
pdata->has_gbit = 1;
@@ -934,13 +897,11 @@ void __init ath79_register_eth(unsigned int id)
case ATH79_SOC_AR7240:
if (id == 0) {
pdata->reset_bit |= AR71XX_RESET_GE0_PHY;
- pdata->ddr_flush = ar724x_ddr_flush_ge0;
pdata->set_speed = ath79_set_speed_dummy;
pdata->phy_mask = BIT(4);
} else {
pdata->reset_bit |= AR71XX_RESET_GE1_PHY;
- pdata->ddr_flush = ar724x_ddr_flush_ge1;
pdata->set_speed = ath79_set_speed_dummy;
pdata->speed = SPEED_1000;
@@ -962,27 +923,15 @@ void __init ath79_register_eth(unsigned int id)
pdata->fifo_cfg3 = 0x01f00140;
break;
- case ATH79_SOC_AR9130:
- if (id == 0) {
- pdata->ddr_flush = ar91xx_ddr_flush_ge0;
- pdata->set_speed = ar91xx_set_speed_ge0;
- } else {
- pdata->ddr_flush = ar91xx_ddr_flush_ge1;
- pdata->set_speed = ar91xx_set_speed_ge1;
- }
- pdata->is_ar91xx = 1;
- break;
-
case ATH79_SOC_AR9132:
- if (id == 0) {
- pdata->ddr_flush = ar91xx_ddr_flush_ge0;
+ pdata->has_gbit = 1;
+ /* fall through */
+ case ATH79_SOC_AR9130:
+ if (id == 0)
pdata->set_speed = ar91xx_set_speed_ge0;
- } else {
- pdata->ddr_flush = ar91xx_ddr_flush_ge1;
+ else
pdata->set_speed = ar91xx_set_speed_ge1;
- }
pdata->is_ar91xx = 1;
- pdata->has_gbit = 1;
break;
case ATH79_SOC_AR9330:
@@ -990,14 +939,12 @@ void __init ath79_register_eth(unsigned int id)
if (id == 0) {
pdata->reset_bit = AR933X_RESET_GE0_MAC |
AR933X_RESET_GE0_MDIO;
- pdata->ddr_flush = ar933x_ddr_flush_ge0;
pdata->set_speed = ath79_set_speed_dummy;
pdata->phy_mask = BIT(4);
} else {
pdata->reset_bit = AR933X_RESET_GE1_MAC |
AR933X_RESET_GE1_MDIO;
- pdata->ddr_flush = ar933x_ddr_flush_ge1;
pdata->set_speed = ath79_set_speed_dummy;
pdata->speed = SPEED_1000;
@@ -1038,7 +985,6 @@ void __init ath79_register_eth(unsigned int id)
ath79_device_reset_clear(AR934X_RESET_ETH_SWITCH);
}
- pdata->ddr_flush = ath79_ddr_no_flush;
pdata->has_gbit = 1;
pdata->is_ar724x = 1;
@@ -1073,7 +1019,6 @@ void __init ath79_register_eth(unsigned int id)
ath79_switch_data.phy_poll_mask |= BIT(4);
}
- pdata->ddr_flush = ath79_ddr_no_flush;
pdata->has_gbit = 1;
pdata->is_ar724x = 1;
@@ -1097,7 +1042,6 @@ void __init ath79_register_eth(unsigned int id)
pdata->set_speed = qca955x_set_speed_sgmii;
}
- pdata->ddr_flush = ath79_ddr_no_flush;
pdata->has_gbit = 1;
pdata->is_ar724x = 1;
@@ -1145,7 +1089,6 @@ void __init ath79_register_eth(unsigned int id)
ath79_device_reset_clear(AR934X_RESET_ETH_SWITCH);
}
- pdata->ddr_flush = ath79_ddr_no_flush;
pdata->has_gbit = 1;
pdata->is_ar724x = 1;
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-archer-c7.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-archer-c7.c
index fc1251303e..f00998c669 100644
--- a/target/linux/ar71xx/files/arch/mips/ath79/mach-archer-c7.c
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-archer-c7.c
@@ -51,6 +51,7 @@
#define ARCHER_C7_GPIO_LED_USB2 19
#define ARCHER_C7_GPIO_BTN_RFKILL 13
+#define ARCHER_C7_V2_GPIO_BTN_RFKILL 23
#define ARCHER_C7_GPIO_BTN_RESET 16
#define ARCHER_C7_GPIO_USB1_POWER 22
@@ -122,6 +123,24 @@ static struct gpio_keys_button archer_c7_gpio_keys[] __initdata = {
},
};
+static struct gpio_keys_button archer_c7_v2_gpio_keys[] __initdata = {
+ {
+ .desc = "Reset button",
+ .type = EV_KEY,
+ .code = KEY_WPS_BUTTON,
+ .debounce_interval = ARCHER_C7_KEYS_DEBOUNCE_INTERVAL,
+ .gpio = ARCHER_C7_GPIO_BTN_RESET,
+ .active_low = 1,
+ },
+ {
+ .desc = "RFKILL switch",
+ .type = EV_SW,
+ .code = KEY_RFKILL,
+ .debounce_interval = ARCHER_C7_KEYS_DEBOUNCE_INTERVAL,
+ .gpio = ARCHER_C7_V2_GPIO_BTN_RFKILL,
+ },
+};
+
static const struct ar8327_led_info archer_c7_leds_ar8327[] __initconst = {
AR8327_LED_INFO(PHY0_0, HW, "tp-link:blue:wan"),
AR8327_LED_INFO(PHY1_0, HW, "tp-link:blue:lan1"),
@@ -192,9 +211,6 @@ static void __init common_setup(bool pcie_slot)
ath79_register_m25p80(&archer_c7_flash_data);
ath79_register_leds_gpio(-1, ARRAY_SIZE(archer_c7_leds_gpio),
archer_c7_leds_gpio);
- ath79_register_gpio_keys_polled(-1, ARCHER_C7_KEYS_POLL_INTERVAL,
- ARRAY_SIZE(archer_c7_gpio_keys),
- archer_c7_gpio_keys);
ath79_init_mac(tmpmac, mac, -1);
ath79_register_wmac(art + ARCHER_C7_WMAC_CALDATA_OFFSET, tmpmac);
@@ -242,6 +258,9 @@ static void __init common_setup(bool pcie_slot)
static void __init archer_c5_setup(void)
{
+ ath79_register_gpio_keys_polled(-1, ARCHER_C7_KEYS_POLL_INTERVAL,
+ ARRAY_SIZE(archer_c7_gpio_keys),
+ archer_c7_gpio_keys);
common_setup(true);
}
@@ -250,14 +269,31 @@ MIPS_MACHINE(ATH79_MACH_ARCHER_C5, "ARCHER-C5", "TP-LINK Archer C5",
static void __init archer_c7_setup(void)
{
+ ath79_register_gpio_keys_polled(-1, ARCHER_C7_KEYS_POLL_INTERVAL,
+ ARRAY_SIZE(archer_c7_gpio_keys),
+ archer_c7_gpio_keys);
common_setup(true);
}
MIPS_MACHINE(ATH79_MACH_ARCHER_C7, "ARCHER-C7", "TP-LINK Archer C7",
archer_c7_setup);
+static void __init archer_c7_v2_setup(void)
+{
+ ath79_register_gpio_keys_polled(-1, ARCHER_C7_KEYS_POLL_INTERVAL,
+ ARRAY_SIZE(archer_c7_v2_gpio_keys),
+ archer_c7_v2_gpio_keys);
+ common_setup(true);
+}
+
+MIPS_MACHINE(ATH79_MACH_ARCHER_C7_V2, "ARCHER-C7-V2", "TP-LINK Archer C7",
+ archer_c7_v2_setup);
+
static void __init tl_wdr4900_v2_setup(void)
{
+ ath79_register_gpio_keys_polled(-1, ARCHER_C7_KEYS_POLL_INTERVAL,
+ ARRAY_SIZE(archer_c7_gpio_keys),
+ archer_c7_gpio_keys);
common_setup(false);
}
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-cpe510.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-cpe510.c
index 8bf5c0f622..875589dde8 100644
--- a/target/linux/ar71xx/files/arch/mips/ath79/mach-cpe510.c
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-cpe510.c
@@ -30,6 +30,9 @@
#define CPE510_GPIO_LED_L3 15
#define CPE510_GPIO_LED_L4 16
+#define CPE510_GPIO_EXTERNAL_LNA0 18
+#define CPE510_GPIO_EXTERNAL_LNA1 19
+
#define CPE510_GPIO_BTN_RESET 4
#define CPE510_KEYS_POLL_INTERVAL 20 /* msecs */
@@ -75,12 +78,8 @@ static struct gpio_keys_button cpe510_gpio_keys[] __initdata = {
}
};
-
-static void __init cpe510_setup(void)
+static void __init cpe_setup(u8 *mac)
{
- u8 *mac = (u8 *) KSEG1ADDR(0x1f830008);
- u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
-
/* Disable JTAG, enabling GPIOs 0-3 */
/* Configure OBS4 line, for GPIO 4*/
ath79_gpio_function_setup(AR934X_GPIO_FUNC_JTAG_DISABLE,
@@ -93,15 +92,40 @@ static void __init cpe510_setup(void)
ARRAY_SIZE(cpe510_gpio_keys),
cpe510_gpio_keys);
+ ath79_wmac_set_ext_lna_gpio(0, CPE510_GPIO_EXTERNAL_LNA0);
+ ath79_wmac_set_ext_lna_gpio(1, CPE510_GPIO_EXTERNAL_LNA1);
+
ath79_register_m25p80(NULL);
ath79_register_mdio(1, 0);
ath79_init_mac(ath79_eth1_data.mac_addr, mac, 0);
ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
ath79_register_eth(1);
+}
+
+
+static void __init cpe210_setup(void)
+{
+ u8 *mac = (u8 *) KSEG1ADDR(0x1f830008);
+ u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+ cpe_setup(mac);
ath79_register_wmac(ee, mac);
}
-MIPS_MACHINE(ATH79_MACH_CPE510, "CPE510", "TP-LINK CPE210/220/510/520",
+static void __init cpe510_setup(void)
+{
+ u8 *mac = (u8 *) KSEG1ADDR(0x1f830008);
+ u8 *ee = (u8 *) KSEG1ADDR(0x1fff5000);
+
+ cpe_setup(mac);
+
+ ath79_register_wmac(ee, mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_CPE210, "CPE210", "TP-LINK CPE210/220",
+ cpe210_setup);
+
+MIPS_MACHINE(ATH79_MACH_CPE510, "CPE510", "TP-LINK CPE510/520",
cpe510_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-mr1750.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-mr1750.c
index e3c04e7756..18101ce8e4 100644
--- a/target/linux/ar71xx/files/arch/mips/ath79/mach-mr1750.c
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-mr1750.c
@@ -168,3 +168,4 @@ static void __init mr1750_setup(void)
}
MIPS_MACHINE(ATH79_MACH_MR1750, "MR1750", "OpenMesh MR1750", mr1750_setup);
+MIPS_MACHINE(ATH79_MACH_MR1750V2, "MR1750v2", "OpenMesh MR1750v2", mr1750_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-om2p.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-om2p.c
index 6b0bdc3dcd..3b282a36ea 100644
--- a/target/linux/ar71xx/files/arch/mips/ath79/mach-om2p.c
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-om2p.c
@@ -223,3 +223,4 @@ static void __init om2p_hs_setup(void)
MIPS_MACHINE(ATH79_MACH_OM2P_HS, "OM2P-HS", "OpenMesh OM2P HS", om2p_hs_setup);
MIPS_MACHINE(ATH79_MACH_OM2P_HSv2, "OM2P-HSv2", "OpenMesh OM2P HSv2", om2p_hs_setup);
+MIPS_MACHINE(ATH79_MACH_OM2P_HSv3, "OM2P-HSv3", "OpenMesh OM2P HSv3", om2p_hs_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-som9331.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-som9331.c
new file mode 100644
index 0000000000..eef5bcedc2
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-som9331.c
@@ -0,0 +1,125 @@
+/*
+ * OpenEmbed SOM9331 board support
+ *
+ * Copyright (C) 2011 dongyuqi <729650915@qq.com>
+ * Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 5/27/2016 - Modified by Allan Nick Pedrana <nik9993@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/gpio.h>
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define SOM9331_GPIO_LED_WLAN 27
+#define SOM9331_GPIO_LED_SYSTEM 0
+#define SOM9331_GPIO_LED_2 13
+#define SOM9331_GPIO_LED_3 14
+#define SOM9331_GPIO_LED_5 16
+#define SOM9331_GPIO_LED_WAN SOM9331_GPIO_LED_2
+#define SOM9331_GPIO_LED_LAN1 SOM9331_GPIO_LED_3
+#define SOM9331_GPIO_LED_LAN2 SOM9331_GPIO_LED_5
+#define SOM9331_GPIO_BTN_RESET 11
+
+#define SOM9331_KEYS_POLL_INTERVAL 20 /* msecs */
+#define SOM9331_KEYS_DEBOUNCE_INTERVAL (3 * SOM9331_KEYS_POLL_INTERVAL)
+
+static const char *som9331_part_probes[] = {
+ "tp-link",
+ NULL,
+};
+
+static struct flash_platform_data som9331_flash_data = {
+ .part_probes = som9331_part_probes,
+};
+
+static struct gpio_led som9331_leds_gpio[] __initdata = {
+ {
+ .name = "som9331:red:wlan",
+ .gpio = SOM9331_GPIO_LED_WLAN,
+ .active_low = 1,
+ },
+ {
+ .name = "som9331:orange:wan",
+ .gpio = SOM9331_GPIO_LED_WAN,
+ .active_low = 0,
+ },
+ {
+ .name = "som9331:orange:lan1",
+ .gpio = SOM9331_GPIO_LED_LAN1,
+ .active_low = 0,
+ },
+ {
+ .name = "som9331:orange:lan2",
+ .gpio = SOM9331_GPIO_LED_LAN2,
+ .active_low = 0,
+ },
+ {
+ .name = "som9331:blue:system",
+ .gpio = SOM9331_GPIO_LED_SYSTEM,
+ .active_low = 0,
+ },
+};
+
+static struct gpio_keys_button som9331_gpio_keys[] __initdata = {
+ {
+ .desc = "reset",
+ .type = EV_KEY,
+ .code = KEY_RESTART,
+ .debounce_interval = SOM9331_KEYS_DEBOUNCE_INTERVAL,
+ .gpio = SOM9331_GPIO_BTN_RESET,
+ .active_low = 0,
+ }
+};
+
+static void __init som9331_setup(void)
+{
+ u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+ u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+ ath79_setup_ar933x_phy4_switch(true, true);
+
+ ath79_gpio_function_disable(AR933X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
+ AR933X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
+ AR933X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
+ AR933X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
+ AR933X_GPIO_FUNC_ETH_SWITCH_LED4_EN);
+
+ ath79_register_m25p80(&som9331_flash_data);
+ ath79_register_leds_gpio(-1, ARRAY_SIZE(som9331_leds_gpio),
+ som9331_leds_gpio);
+ ath79_register_gpio_keys_polled(-1, SOM9331_KEYS_POLL_INTERVAL,
+ ARRAY_SIZE(som9331_gpio_keys),
+ som9331_gpio_keys);
+
+ ath79_register_usb();
+
+ ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+ ath79_init_mac(ath79_eth1_data.mac_addr, mac, -1);
+
+ ath79_register_mdio(0, 0x0);
+
+ /* LAN ports */
+ ath79_register_eth(1);
+
+ /* WAN port */
+ ath79_register_eth(0);
+
+ ath79_register_wmac(ee, mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_SOM9331, "SOM9331", "OpenEmbed SOM9331", som9331_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr841n-v9.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr841n-v9.c
index 3e5c2a2522..f806568f98 100644
--- a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr841n-v9.c
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr841n-v9.c
@@ -1,7 +1,9 @@
/*
- * TP-LINK TL-WR841N/ND v9
+ * TP-LINK TL-WR841N/ND v9/v11 / TL-WR842N/ND v3
*
* Copyright (C) 2014 Matthias Schiffer <mschiffer@universe-factory.net>
+ * Copyright (C) 2016 Cezary Jackiewicz <cezary@eko.one.pl>
+ * Copyright (C) 2016 Stijn Segers <francesco.borromini@gmail.com>
*
* 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
@@ -19,6 +21,7 @@
#include "dev-gpio-buttons.h"
#include "dev-leds-gpio.h"
#include "dev-m25p80.h"
+#include "dev-usb.h"
#include "dev-wmac.h"
#include "machtypes.h"
@@ -33,6 +36,33 @@
#define TL_WR841NV9_GPIO_BTN_RESET 12
#define TL_WR841NV9_GPIO_BTN_WIFI 17
+#define TL_WR841NV11_GPIO_LED_SYSTEM 1
+#define TL_WR841NV11_GPIO_LED_QSS 3
+#define TL_WR841NV11_GPIO_LED_WAN 4
+#define TL_WR841NV11_GPIO_LED_WAN_STATUS 2
+#define TL_WR841NV11_GPIO_LED_WLAN 13
+#define TL_WR841NV11_GPIO_LED_LAN1 16
+#define TL_WR841NV11_GPIO_LED_LAN2 15
+#define TL_WR841NV11_GPIO_LED_LAN3 14
+#define TL_WR841NV11_GPIO_LED_LAN4 11
+
+#define TL_WR841NV11_GPIO_BTN_RESET 12
+#define TL_WR841NV11_GPIO_BTN_WIFI 17
+
+#define TL_WR842NV3_GPIO_LED_SYSTEM 2
+#define TL_WR842NV3_GPIO_LED_WLAN 3
+#define TL_WR842NV3_GPIO_LED_WAN_RED 4
+#define TL_WR842NV3_GPIO_LED_WAN_GREEN 11
+#define TL_WR842NV3_GPIO_LED_LAN1 12
+#define TL_WR842NV3_GPIO_LED_LAN2 13
+#define TL_WR842NV3_GPIO_LED_LAN3 14
+#define TL_WR842NV3_GPIO_LED_LAN4 15
+#define TL_WR842NV3_GPIO_LED_3G 16
+#define TL_WR842NV3_GPIO_LED_WPS 17
+
+#define TL_WR842NV3_GPIO_BTN_RESET 1
+#define TL_WR842NV3_GPIO_BTN_WIFI 0
+
#define TL_WR841NV9_KEYS_POLL_INTERVAL 20 /* msecs */
#define TL_WR841NV9_KEYS_DEBOUNCE_INTERVAL (3 * TL_WR841NV9_KEYS_POLL_INTERVAL)
@@ -95,6 +125,108 @@ static struct gpio_keys_button tl_wr841n_v9_gpio_keys[] __initdata = {
}
};
+static struct gpio_led tl_wr841n_v11_leds_gpio[] __initdata = {
+ {
+ .name = "tp-link:green:lan1",
+ .gpio = TL_WR841NV9_GPIO_LED_LAN1,
+ .active_low = 1,
+ }, {
+ .name = "tp-link:green:lan2",
+ .gpio = TL_WR841NV9_GPIO_LED_LAN2,
+ .active_low = 1,
+ }, {
+ .name = "tp-link:green:lan3",
+ .gpio = TL_WR841NV9_GPIO_LED_LAN3,
+ .active_low = 1,
+ }, {
+ .name = "tp-link:green:lan4",
+ .gpio = TL_WR841NV9_GPIO_LED_LAN4,
+ .active_low = 1,
+ }, {
+ .name = "tp-link:green:qss",
+ .gpio = TL_WR841NV9_GPIO_LED_QSS,
+ .active_low = 1,
+ }, {
+ .name = "tp-link:green:system",
+ .gpio = TL_WR841NV11_GPIO_LED_SYSTEM,
+ .active_low = 1,
+ }, {
+ .name = "tp-link:green:wan",
+ .gpio = TL_WR841NV9_GPIO_LED_WAN,
+ .active_low = 1,
+ }, {
+ .name = "tp-link:green:wan_status",
+ .gpio = TL_WR841NV11_GPIO_LED_WAN_STATUS,
+ .active_low = 1,
+ }, {
+ .name = "tp-link:green:wlan",
+ .gpio = TL_WR841NV9_GPIO_LED_WLAN,
+ .active_low = 1,
+ },
+};
+
+static struct gpio_led tl_wr842n_v3_leds_gpio[] __initdata = {
+ {
+ .name = "tp-link:green:lan1",
+ .gpio = TL_WR842NV3_GPIO_LED_LAN1,
+ .active_low = 1,
+ }, {
+ .name = "tp-link:green:lan2",
+ .gpio = TL_WR842NV3_GPIO_LED_LAN2,
+ .active_low = 1,
+ }, {
+ .name = "tp-link:green:lan3",
+ .gpio = TL_WR842NV3_GPIO_LED_LAN3,
+ .active_low = 1,
+ }, {
+ .name = "tp-link:green:lan4",
+ .gpio = TL_WR842NV3_GPIO_LED_LAN4,
+ .active_low = 1,
+ }, {
+ .name = "tp-link:green:wan",
+ .gpio = TL_WR842NV3_GPIO_LED_WAN_GREEN,
+ .active_low = 1,
+ }, {
+ .name = "tp-link:red:wan",
+ .gpio = TL_WR842NV3_GPIO_LED_WAN_RED,
+ .active_low = 1,
+ }, {
+ .name = "tp-link:green:wlan",
+ .gpio = TL_WR842NV3_GPIO_LED_WLAN,
+ .active_low = 1,
+ }, {
+ .name = "tp-link:green:system",
+ .gpio = TL_WR842NV3_GPIO_LED_SYSTEM,
+ .active_low = 1,
+ }, {
+ .name = "tp-link:green:3g",
+ .gpio = TL_WR842NV3_GPIO_LED_3G,
+ .active_low = 1,
+ }, {
+ .name = "tp-link:green:wps",
+ .gpio = TL_WR842NV3_GPIO_LED_WPS,
+ .active_low = 1,
+ },
+};
+
+static struct gpio_keys_button tl_wr842n_v3_gpio_keys[] __initdata = {
+ {
+ .desc = "Reset button",
+ .type = EV_KEY,
+ .code = KEY_RESTART,
+ .debounce_interval = TL_WR841NV9_KEYS_DEBOUNCE_INTERVAL,
+ .gpio = TL_WR842NV3_GPIO_BTN_RESET,
+ .active_low = 1,
+ }, {
+ .desc = "WIFI button",
+ .type = EV_KEY,
+ .code = KEY_RFKILL,
+ .debounce_interval = TL_WR841NV9_KEYS_DEBOUNCE_INTERVAL,
+ .gpio = TL_WR842NV3_GPIO_BTN_WIFI,
+ .active_low = 1,
+ }
+};
+
static void __init tl_ap143_setup(void)
{
@@ -142,3 +274,35 @@ static void __init tl_wr841n_v9_setup(void)
MIPS_MACHINE(ATH79_MACH_TL_WR841N_V9, "TL-WR841N-v9", "TP-LINK TL-WR841N/ND v9",
tl_wr841n_v9_setup);
+
+static void __init tl_wr841n_v11_setup(void)
+{
+ tl_ap143_setup();
+
+ ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wr841n_v11_leds_gpio),
+ tl_wr841n_v11_leds_gpio);
+
+ ath79_register_gpio_keys_polled(1, TL_WR841NV9_KEYS_POLL_INTERVAL,
+ ARRAY_SIZE(tl_wr841n_v9_gpio_keys),
+ tl_wr841n_v9_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WR841N_V11, "TL-WR841N-v11", "TP-LINK TL-WR841N/ND v11",
+ tl_wr841n_v11_setup);
+
+static void __init tl_wr842n_v3_setup(void)
+{
+ tl_ap143_setup();
+
+ ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wr842n_v3_leds_gpio),
+ tl_wr842n_v3_leds_gpio);
+
+ ath79_register_gpio_keys_polled(1, TL_WR841NV9_KEYS_POLL_INTERVAL,
+ ARRAY_SIZE(tl_wr842n_v3_gpio_keys),
+ tl_wr842n_v3_gpio_keys);
+
+ ath79_register_usb();
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WR842N_V3, "TL-WR842N-v3", "TP-LINK TL-WR842N/ND v3",
+ tl_wr842n_v3_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-ubnt-unifiac.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-ubnt-unifiac.c
index 072cf12a31..9194bc1c07 100644
--- a/target/linux/ar71xx/files/arch/mips/ath79/mach-ubnt-unifiac.c
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-ubnt-unifiac.c
@@ -21,6 +21,7 @@
#include <asm/mach-ath79/ar71xx_regs.h>
#include <linux/platform_data/phy-at803x.h>
+#include <linux/ar8216_platform.h>
#include "common.h"
#include "dev-ap9x-pci.h"
@@ -29,6 +30,7 @@
#include "dev-leds-gpio.h"
#include "dev-m25p80.h"
#include "dev-wmac.h"
+#include "dev-usb.h"
#include "machtypes.h"
@@ -73,7 +75,7 @@ static struct gpio_keys_button ubnt_unifiac_gpio_keys[] __initdata = {
}
};
-static void __init ubnt_unifiac_setup(void)
+static void __init ubnt_unifiac_lite_setup(void)
{
u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff0000);
@@ -81,7 +83,7 @@ static void __init ubnt_unifiac_setup(void)
ath79_init_mac(ath79_eth0_data.mac_addr,
- eeprom + UNIFIAC_MAC0_OFFSET, 0);
+ eeprom + UNIFIAC_MAC0_OFFSET, 0);
ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_SGMII;
ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
@@ -99,12 +101,79 @@ static void __init ubnt_unifiac_setup(void)
ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_unifiac_leds_gpio),
- ubnt_unifiac_leds_gpio);
+ ubnt_unifiac_leds_gpio);
ath79_register_gpio_keys_polled(-1, UNIFIAC_KEYS_POLL_INTERVAL,
- ARRAY_SIZE(ubnt_unifiac_gpio_keys),
- ubnt_unifiac_gpio_keys);
+ ARRAY_SIZE(ubnt_unifiac_gpio_keys),
+ ubnt_unifiac_gpio_keys);
}
-MIPS_MACHINE(ATH79_MACH_UBNT_UNIFIAC, "UBNT-UF-AC", "Ubiquiti UniFi-AC",
- ubnt_unifiac_setup);
+MIPS_MACHINE(ATH79_MACH_UBNT_UNIFIAC_LITE, "UBNT-UF-AC-LITE", "Ubiquiti UniFi-AC-LITE",
+ ubnt_unifiac_lite_setup);
+
+static struct ar8327_pad_cfg ubnt_unifiac_pro_ar8327_pad0_cfg = {
+ .mode = AR8327_PAD_MAC_SGMII,
+ .sgmii_delay_en = true,
+};
+
+static struct ar8327_platform_data ubnt_unifiac_pro_ar8327_data = {
+ .pad0_cfg = &ubnt_unifiac_pro_ar8327_pad0_cfg,
+ .port0_cfg = {
+ .force_link = 1,
+ .speed = AR8327_PORT_SPEED_1000,
+ .duplex = 1,
+ .txpause = 1,
+ .rxpause = 1,
+ },
+};
+
+
+static struct mdio_board_info ubnt_unifiac_pro_mdio0_info[] = {
+ {
+ .bus_id = "ag71xx-mdio.0",
+ .phy_addr = 0,
+ .platform_data = &ubnt_unifiac_pro_ar8327_data,
+ },
+};
+
+static void __init ubnt_unifiac_pro_setup(void)
+{
+ u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff0000);
+
+ ath79_register_m25p80(&ubnt_unifiac_flash_data);
+
+
+ ath79_init_mac(ath79_eth0_data.mac_addr,
+ eeprom + UNIFIAC_MAC0_OFFSET, 0);
+
+ ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_SGMII;
+ ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+ ath79_eth0_data.phy_mask = BIT(0);
+
+ mdiobus_register_board_info(ubnt_unifiac_pro_mdio0_info,
+ ARRAY_SIZE(ubnt_unifiac_pro_mdio0_info));
+
+ ath79_register_mdio(0, 0x00);
+ ath79_register_eth(0);
+
+
+ ath79_register_usb();
+
+
+ ath79_register_wmac(eeprom + UNIFIAC_WMAC_CALDATA_OFFSET, NULL);
+
+
+ ap91_pci_init(eeprom + UNIFIAC_PCI_CALDATA_OFFSET, NULL);
+
+
+ ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_unifiac_leds_gpio),
+ ubnt_unifiac_leds_gpio);
+
+ ath79_register_gpio_keys_polled(-1, UNIFIAC_KEYS_POLL_INTERVAL,
+ ARRAY_SIZE(ubnt_unifiac_gpio_keys),
+ ubnt_unifiac_gpio_keys);
+}
+
+
+MIPS_MACHINE(ATH79_MACH_UBNT_UNIFIAC_PRO, "UBNT-UF-AC-PRO", "Ubiquiti UniFi-AC-PRO",
+ ubnt_unifiac_pro_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-ubnt-xm.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-ubnt-xm.c
new file mode 100644
index 0000000000..622c81f107
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-ubnt-xm.c
@@ -0,0 +1,700 @@
+/*
+ * Ubiquiti Networks XM (rev 1.0) board support
+ *
+ * Copyright (C) 2011 René Bolldorf <xsecute@googlemail.com>
+ *
+ * Derived from: mach-pb44.c
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/etherdevice.h>
+#include <linux/ar8216_platform.h>
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/irq.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include <linux/platform_data/phy-at803x.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define UBNT_XM_GPIO_LED_L1 0
+#define UBNT_XM_GPIO_LED_L2 1
+#define UBNT_XM_GPIO_LED_L3 11
+#define UBNT_XM_GPIO_LED_L4 7
+
+#define UBNT_XM_GPIO_BTN_RESET 12
+
+#define UBNT_XM_KEYS_POLL_INTERVAL 20
+#define UBNT_XM_KEYS_DEBOUNCE_INTERVAL (3 * UBNT_XM_KEYS_POLL_INTERVAL)
+
+#define UBNT_XM_EEPROM_ADDR 0x1fff1000
+
+static struct gpio_led ubnt_xm_leds_gpio[] __initdata = {
+ {
+ .name = "ubnt:red:link1",
+ .gpio = UBNT_XM_GPIO_LED_L1,
+ .active_low = 0,
+ }, {
+ .name = "ubnt:orange:link2",
+ .gpio = UBNT_XM_GPIO_LED_L2,
+ .active_low = 0,
+ }, {
+ .name = "ubnt:green:link3",
+ .gpio = UBNT_XM_GPIO_LED_L3,
+ .active_low = 0,
+ }, {
+ .name = "ubnt:green:link4",
+ .gpio = UBNT_XM_GPIO_LED_L4,
+ .active_low = 0,
+ },
+};
+
+static struct gpio_keys_button ubnt_xm_gpio_keys[] __initdata = {
+ {
+ .desc = "reset",
+ .type = EV_KEY,
+ .code = KEY_RESTART,
+ .debounce_interval = UBNT_XM_KEYS_DEBOUNCE_INTERVAL,
+ .gpio = UBNT_XM_GPIO_BTN_RESET,
+ .active_low = 1,
+ }
+};
+
+#define UBNT_M_WAN_PHYMASK BIT(4)
+
+static void __init ubnt_xm_init(void)
+{
+ u8 *eeprom = (u8 *) KSEG1ADDR(UBNT_XM_EEPROM_ADDR);
+ u8 *mac1 = (u8 *) KSEG1ADDR(0x1fff0000);
+ u8 *mac2 = (u8 *) KSEG1ADDR(0x1fff0000 + ETH_ALEN);
+
+ ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_xm_leds_gpio),
+ ubnt_xm_leds_gpio);
+
+ ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
+ ARRAY_SIZE(ubnt_xm_gpio_keys),
+ ubnt_xm_gpio_keys);
+
+ ath79_register_m25p80(NULL);
+ ap91_pci_init(eeprom, NULL);
+
+ ath79_register_mdio(0, ~UBNT_M_WAN_PHYMASK);
+ ath79_init_mac(ath79_eth0_data.mac_addr, mac1, 0);
+ ath79_init_mac(ath79_eth1_data.mac_addr, mac2, 0);
+ ath79_register_eth(0);
+}
+
+MIPS_MACHINE(ATH79_MACH_UBNT_XM,
+ "UBNT-XM",
+ "Ubiquiti Networks XM (rev 1.0) board",
+ ubnt_xm_init);
+
+MIPS_MACHINE(ATH79_MACH_UBNT_BULLET_M, "UBNT-BM", "Ubiquiti Bullet M",
+ ubnt_xm_init);
+
+static void __init ubnt_rocket_m_setup(void)
+{
+ ubnt_xm_init();
+ ath79_register_usb();
+}
+
+MIPS_MACHINE(ATH79_MACH_UBNT_ROCKET_M, "UBNT-RM", "Ubiquiti Rocket M",
+ ubnt_rocket_m_setup);
+
+static void __init ubnt_nano_m_setup(void)
+{
+ ubnt_xm_init();
+ ath79_register_eth(1);
+}
+
+MIPS_MACHINE(ATH79_MACH_UBNT_NANO_M, "UBNT-NM", "Ubiquiti Nanostation M",
+ ubnt_nano_m_setup);
+
+static struct gpio_led ubnt_airrouter_leds_gpio[] __initdata = {
+ {
+ .name = "ubnt:green:globe",
+ .gpio = 0,
+ .active_low = 1,
+ }, {
+ .name = "ubnt:green:power",
+ .gpio = 11,
+ .active_low = 1,
+ .default_state = LEDS_GPIO_DEFSTATE_ON,
+ }
+};
+
+static void __init ubnt_airrouter_setup(void)
+{
+ u8 *mac1 = (u8 *) KSEG1ADDR(0x1fff0000);
+ u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+ ath79_register_m25p80(NULL);
+ ath79_register_mdio(0, ~UBNT_M_WAN_PHYMASK);
+
+ ath79_init_mac(ath79_eth0_data.mac_addr, mac1, 0);
+ ath79_init_local_mac(ath79_eth1_data.mac_addr, mac1);
+
+ ath79_register_eth(1);
+ ath79_register_eth(0);
+ ath79_register_usb();
+
+ ap91_pci_init(ee, NULL);
+ ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_airrouter_leds_gpio),
+ ubnt_airrouter_leds_gpio);
+
+ ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
+ ARRAY_SIZE(ubnt_xm_gpio_keys),
+ ubnt_xm_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_UBNT_AIRROUTER, "UBNT-AR", "Ubiquiti AirRouter",
+ ubnt_airrouter_setup);
+
+static struct gpio_led ubnt_unifi_leds_gpio[] __initdata = {
+ {
+ .name = "ubnt:orange:dome",
+ .gpio = 1,
+ .active_low = 0,
+ }, {
+ .name = "ubnt:green:dome",
+ .gpio = 0,
+ .active_low = 0,
+ }
+};
+
+static struct gpio_led ubnt_unifi_outdoor_leds_gpio[] __initdata = {
+ {
+ .name = "ubnt:orange:front",
+ .gpio = 1,
+ .active_low = 0,
+ }, {
+ .name = "ubnt:green:front",
+ .gpio = 0,
+ .active_low = 0,
+ }
+};
+
+static struct gpio_led ubnt_unifi_outdoor_plus_leds_gpio[] __initdata = {
+ {
+ .name = "ubnt:white:front",
+ .gpio = 1,
+ .active_low = 0,
+ }, {
+ .name = "ubnt:blue:front",
+ .gpio = 0,
+ .active_low = 0,
+ }
+};
+
+
+static void __init ubnt_unifi_setup(void)
+{
+ u8 *mac = (u8 *) KSEG1ADDR(0x1fff0000);
+ u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+ ath79_register_m25p80(NULL);
+
+ ath79_register_mdio(0, ~UBNT_M_WAN_PHYMASK);
+
+ ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+ ath79_register_eth(0);
+
+ ap91_pci_init(ee, NULL);
+
+ ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_unifi_leds_gpio),
+ ubnt_unifi_leds_gpio);
+
+ ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
+ ARRAY_SIZE(ubnt_xm_gpio_keys),
+ ubnt_xm_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_UBNT_UNIFI, "UBNT-UF", "Ubiquiti UniFi",
+ ubnt_unifi_setup);
+
+
+#define UBNT_UNIFIOD_PRI_PHYMASK BIT(4)
+#define UBNT_UNIFIOD_2ND_PHYMASK (BIT(0) | BIT(1) | BIT(2) | BIT(3))
+
+static void __init ubnt_unifi_outdoor_setup(void)
+{
+ u8 *mac1 = (u8 *) KSEG1ADDR(0x1fff0000);
+ u8 *mac2 = (u8 *) KSEG1ADDR(0x1fff0000 + ETH_ALEN);
+ u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+ ath79_register_m25p80(NULL);
+
+ ath79_register_mdio(0, ~(UBNT_UNIFIOD_PRI_PHYMASK |
+ UBNT_UNIFIOD_2ND_PHYMASK));
+
+ ath79_init_mac(ath79_eth0_data.mac_addr, mac1, 0);
+ ath79_init_mac(ath79_eth1_data.mac_addr, mac2, 0);
+ ath79_register_eth(0);
+ ath79_register_eth(1);
+
+ ap91_pci_init(ee, NULL);
+
+ ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_unifi_outdoor_leds_gpio),
+ ubnt_unifi_outdoor_leds_gpio);
+
+ ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
+ ARRAY_SIZE(ubnt_xm_gpio_keys),
+ ubnt_xm_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_UBNT_UNIFI_OUTDOOR, "UBNT-U20",
+ "Ubiquiti UniFiAP Outdoor",
+ ubnt_unifi_outdoor_setup);
+
+
+static void __init ubnt_unifi_outdoor_plus_setup(void)
+{
+ u8 *mac1 = (u8 *) KSEG1ADDR(0x1fff0000);
+ u8 *mac2 = (u8 *) KSEG1ADDR(0x1fff0000 + ETH_ALEN);
+ u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+ ath79_register_m25p80(NULL);
+
+ ath79_register_mdio(0, ~(UBNT_UNIFIOD_PRI_PHYMASK |
+ UBNT_UNIFIOD_2ND_PHYMASK));
+
+ ath79_init_mac(ath79_eth0_data.mac_addr, mac1, 0);
+ ath79_init_mac(ath79_eth1_data.mac_addr, mac2, 0);
+ ath79_register_eth(0);
+ ath79_register_eth(1);
+
+ ap91_pci_init(ee, NULL);
+
+ ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_unifi_outdoor_plus_leds_gpio),
+ ubnt_unifi_outdoor_plus_leds_gpio);
+
+ ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
+ ARRAY_SIZE(ubnt_xm_gpio_keys),
+ ubnt_xm_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_UBNT_UNIFI_OUTDOOR_PLUS, "UBNT-UOP",
+ "Ubiquiti UniFiAP Outdoor+",
+ ubnt_unifi_outdoor_plus_setup);
+
+
+static struct gpio_led ubnt_uap_pro_gpio_leds[] __initdata = {
+ {
+ .name = "ubnt:white:dome",
+ .gpio = 12,
+ }, {
+ .name = "ubnt:blue:dome",
+ .gpio = 13,
+ }
+};
+
+static struct gpio_keys_button uap_pro_gpio_keys[] __initdata = {
+ {
+ .desc = "reset",
+ .type = EV_KEY,
+ .code = KEY_RESTART,
+ .debounce_interval = UBNT_XM_KEYS_DEBOUNCE_INTERVAL,
+ .gpio = 17,
+ .active_low = 1,
+ }
+};
+
+static struct ar8327_pad_cfg uap_pro_ar8327_pad0_cfg = {
+ .mode = AR8327_PAD_MAC_RGMII,
+ .txclk_delay_en = true,
+ .rxclk_delay_en = true,
+ .txclk_delay_sel = AR8327_CLK_DELAY_SEL1,
+ .rxclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+};
+
+static struct ar8327_platform_data uap_pro_ar8327_data = {
+ .pad0_cfg = &uap_pro_ar8327_pad0_cfg,
+ .port0_cfg = {
+ .force_link = 1,
+ .speed = AR8327_PORT_SPEED_1000,
+ .duplex = 1,
+ .txpause = 1,
+ .rxpause = 1,
+ },
+};
+
+static struct mdio_board_info uap_pro_mdio0_info[] = {
+ {
+ .bus_id = "ag71xx-mdio.0",
+ .phy_addr = 0,
+ .platform_data = &uap_pro_ar8327_data,
+ },
+};
+
+#define UAP_PRO_MAC0_OFFSET 0x0000
+#define UAP_PRO_MAC1_OFFSET 0x0006
+#define UAP_PRO_WMAC_CALDATA_OFFSET 0x1000
+#define UAP_PRO_PCI_CALDATA_OFFSET 0x5000
+
+static void __init ubnt_uap_pro_setup(void)
+{
+ u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff0000);
+
+ ath79_register_m25p80(NULL);
+
+ ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_uap_pro_gpio_leds),
+ ubnt_uap_pro_gpio_leds);
+ ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
+ ARRAY_SIZE(uap_pro_gpio_keys),
+ uap_pro_gpio_keys);
+
+ ath79_register_wmac(eeprom + UAP_PRO_WMAC_CALDATA_OFFSET, NULL);
+ ap91_pci_init(eeprom + UAP_PRO_PCI_CALDATA_OFFSET, NULL);
+
+ ath79_register_mdio(0, 0x0);
+ mdiobus_register_board_info(uap_pro_mdio0_info,
+ ARRAY_SIZE(uap_pro_mdio0_info));
+
+ ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0);
+ ath79_init_mac(ath79_eth0_data.mac_addr,
+ eeprom + UAP_PRO_MAC0_OFFSET, 0);
+
+ /* GMAC0 is connected to an AR8327 switch */
+ ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+ ath79_eth0_data.phy_mask = BIT(0);
+ ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+ ath79_eth0_pll_data.pll_1000 = 0x06000000;
+ ath79_register_eth(0);
+}
+
+MIPS_MACHINE(ATH79_MACH_UBNT_UAP_PRO, "UAP-PRO", "Ubiquiti UniFi AP Pro",
+ ubnt_uap_pro_setup);
+
+#define UBNT_XW_GPIO_LED_L1 11
+#define UBNT_XW_GPIO_LED_L2 16
+#define UBNT_XW_GPIO_LED_L3 13
+#define UBNT_XW_GPIO_LED_L4 14
+
+static struct gpio_led ubnt_xw_leds_gpio[] __initdata = {
+ {
+ .name = "ubnt:red:link1",
+ .gpio = UBNT_XW_GPIO_LED_L1,
+ .active_low = 1,
+ }, {
+ .name = "ubnt:orange:link2",
+ .gpio = UBNT_XW_GPIO_LED_L2,
+ .active_low = 1,
+ }, {
+ .name = "ubnt:green:link3",
+ .gpio = UBNT_XW_GPIO_LED_L3,
+ .active_low = 1,
+ }, {
+ .name = "ubnt:green:link4",
+ .gpio = UBNT_XW_GPIO_LED_L4,
+ .active_low = 1,
+ },
+};
+
+#define UBNT_ROCKET_TI_GPIO_LED_L1 16
+#define UBNT_ROCKET_TI_GPIO_LED_L2 17
+#define UBNT_ROCKET_TI_GPIO_LED_L3 18
+#define UBNT_ROCKET_TI_GPIO_LED_L4 19
+#define UBNT_ROCKET_TI_GPIO_LED_L5 20
+#define UBNT_ROCKET_TI_GPIO_LED_L6 21
+static struct gpio_led ubnt_rocket_ti_leds_gpio[] __initdata = {
+ {
+ .name = "ubnt:green:link1",
+ .gpio = UBNT_ROCKET_TI_GPIO_LED_L1,
+ .active_low = 1,
+ }, {
+ .name = "ubnt:green:link2",
+ .gpio = UBNT_ROCKET_TI_GPIO_LED_L2,
+ .active_low = 1,
+ }, {
+ .name = "ubnt:green:link3",
+ .gpio = UBNT_ROCKET_TI_GPIO_LED_L3,
+ .active_low = 1,
+ }, {
+ .name = "ubnt:green:link4",
+ .gpio = UBNT_ROCKET_TI_GPIO_LED_L4,
+ .active_low = 0,
+ }, {
+ .name = "ubnt:green:link5",
+ .gpio = UBNT_ROCKET_TI_GPIO_LED_L5,
+ .active_low = 0,
+ }, {
+ .name = "ubnt:green:link6",
+ .gpio = UBNT_ROCKET_TI_GPIO_LED_L6,
+ .active_low = 0,
+ },
+};
+
+static void __init ubnt_xw_init(void)
+{
+ u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff0000);
+
+ ath79_register_m25p80(NULL);
+
+ ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_xw_leds_gpio),
+ ubnt_xw_leds_gpio);
+ ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
+ ARRAY_SIZE(ubnt_xm_gpio_keys),
+ ubnt_xm_gpio_keys);
+
+ ath79_register_wmac(eeprom + UAP_PRO_WMAC_CALDATA_OFFSET, NULL);
+ ap91_pci_init(eeprom + UAP_PRO_PCI_CALDATA_OFFSET, NULL);
+
+
+ ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_MII_GMAC0 | AR934X_ETH_CFG_MII_GMAC0_SLAVE);
+ ath79_init_mac(ath79_eth0_data.mac_addr,
+ eeprom + UAP_PRO_MAC0_OFFSET, 0);
+
+ ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+ ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+}
+
+static void __init ubnt_nano_m_xw_setup(void)
+{
+ ubnt_xw_init();
+
+ /* GMAC0 is connected to an AR8326 switch */
+ ath79_register_mdio(0, ~(BIT(0) | BIT(1) | BIT(5)));
+ ath79_eth0_data.phy_mask = (BIT(0) | BIT(1) | BIT(5));
+ ath79_eth0_data.speed = SPEED_100;
+ ath79_eth0_data.duplex = DUPLEX_FULL;
+ ath79_register_eth(0);
+}
+
+static void __init ubnt_loco_m_xw_setup(void)
+{
+ ubnt_xw_init();
+
+ ath79_register_mdio(0, ~BIT(1));
+ ath79_eth0_data.phy_mask = BIT(1);
+ ath79_register_eth(0);
+}
+
+static void __init ubnt_rocket_m_xw_setup(void)
+{
+ u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff0000);
+
+ ath79_register_m25p80(NULL);
+
+ ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_xw_leds_gpio),
+ ubnt_xw_leds_gpio);
+ ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
+ ARRAY_SIZE(ubnt_xm_gpio_keys),
+ ubnt_xm_gpio_keys);
+
+ ath79_register_wmac(eeprom + UAP_PRO_WMAC_CALDATA_OFFSET, NULL);
+ ap91_pci_init(eeprom + UAP_PRO_PCI_CALDATA_OFFSET, NULL);
+
+ ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0);
+ ath79_init_mac(ath79_eth0_data.mac_addr,
+ eeprom + UAP_PRO_MAC0_OFFSET, 0);
+
+ ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+ ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+
+ ath79_register_mdio(0, ~BIT(4));
+ ath79_eth0_data.phy_mask = BIT(4);
+ ath79_eth0_pll_data.pll_1000 = 0x06000000;
+ ath79_register_eth(0);
+}
+
+static struct at803x_platform_data ubnt_rocket_m_ti_at803_data = {
+ .disable_smarteee = 1,
+ .enable_rgmii_rx_delay = 1,
+ .enable_rgmii_tx_delay = 1,
+};
+static struct mdio_board_info ubnt_rocket_m_ti_mdio_info[] = {
+ {
+ .bus_id = "ag71xx-mdio.0",
+ .phy_addr = 4,
+ .platform_data = &ubnt_rocket_m_ti_at803_data,
+ },
+};
+
+static void __init ubnt_rocket_m_ti_setup(void)
+{
+ u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff0000);
+
+ ath79_register_m25p80(NULL);
+
+ ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_rocket_ti_leds_gpio),
+ ubnt_rocket_ti_leds_gpio);
+ ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
+ ARRAY_SIZE(ubnt_xm_gpio_keys),
+ ubnt_xm_gpio_keys);
+
+ ap91_pci_init(eeprom + 0x1000, NULL);
+
+ ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0);
+ ath79_setup_ar934x_eth_rx_delay(3, 3);
+ ath79_init_mac(ath79_eth0_data.mac_addr,
+ eeprom + UAP_PRO_MAC0_OFFSET, 0);
+ ath79_init_mac(ath79_eth1_data.mac_addr,
+ eeprom + UAP_PRO_MAC1_OFFSET, 0);
+
+ ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+ ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+ ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+ ath79_eth1_data.mii_bus_dev = &ath79_mdio1_device.dev;
+
+ mdiobus_register_board_info(ubnt_rocket_m_ti_mdio_info,
+ ARRAY_SIZE(ubnt_rocket_m_ti_mdio_info));
+ ath79_register_mdio(0, 0x0);
+
+
+ ath79_eth0_data.phy_mask = BIT(4);
+ /* read out from vendor */
+ ath79_eth0_pll_data.pll_1000 = 0x2000000;
+ ath79_eth0_pll_data.pll_10 = 0x1313;
+ ath79_register_eth(0);
+
+ ath79_register_mdio(1, 0x0);
+ ath79_eth1_data.phy_mask = BIT(3);
+ ath79_register_eth(1);
+}
+
+
+MIPS_MACHINE(ATH79_MACH_UBNT_NANO_M_XW, "UBNT-NM-XW", "Ubiquiti Nanostation M XW",
+ ubnt_nano_m_xw_setup);
+
+MIPS_MACHINE(ATH79_MACH_UBNT_LOCO_M_XW, "UBNT-LOCO-XW", "Ubiquiti Loco M XW",
+ ubnt_loco_m_xw_setup);
+
+MIPS_MACHINE(ATH79_MACH_UBNT_ROCKET_M_XW, "UBNT-RM-XW", "Ubiquiti Rocket M XW",
+ ubnt_rocket_m_xw_setup);
+
+MIPS_MACHINE(ATH79_MACH_UBNT_ROCKET_M_TI, "UBNT-RM-TI", "Ubiquiti Rocket M TI",
+ ubnt_rocket_m_ti_setup);
+
+static struct gpio_led ubnt_airgateway_gpio_leds[] __initdata = {
+ {
+ .name = "ubnt:blue:wlan",
+ .gpio = 0,
+ }, {
+ .name = "ubnt:white:status",
+ .gpio = 1,
+ },
+};
+
+static struct gpio_keys_button airgateway_gpio_keys[] __initdata = {
+ {
+ .desc = "reset",
+ .type = EV_KEY,
+ .code = KEY_RESTART,
+ .debounce_interval = UBNT_XM_KEYS_DEBOUNCE_INTERVAL,
+ .gpio = 12,
+ .active_low = 1,
+ }
+};
+
+static void __init ubnt_airgateway_setup(void)
+{
+ u32 t;
+ u8 *mac0 = (u8 *) KSEG1ADDR(0x1fff0000);
+ u8 *mac1 = (u8 *) KSEG1ADDR(0x1fff0000 + ETH_ALEN);
+ u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+
+ ath79_gpio_function_disable(AR933X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
+ AR933X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
+ AR933X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
+ AR933X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
+ AR933X_GPIO_FUNC_ETH_SWITCH_LED4_EN);
+
+ t = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP);
+ t |= AR933X_BOOTSTRAP_MDIO_GPIO_EN;
+ ath79_reset_wr(AR933X_RESET_REG_BOOTSTRAP, t);
+
+ ath79_register_m25p80(NULL);
+ ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_airgateway_gpio_leds),
+ ubnt_airgateway_gpio_leds);
+
+ ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
+ ARRAY_SIZE(airgateway_gpio_keys),
+ airgateway_gpio_keys);
+
+ ath79_init_mac(ath79_eth1_data.mac_addr, mac0, 0);
+ ath79_init_mac(ath79_eth0_data.mac_addr, mac1, 0);
+
+ ath79_register_mdio(0, 0x0);
+
+ ath79_register_eth(1);
+ ath79_register_eth(0);
+
+ ath79_register_wmac(ee, NULL);
+}
+
+MIPS_MACHINE(ATH79_MACH_UBNT_AIRGW, "UBNT-AGW", "Ubiquiti AirGateway",
+ ubnt_airgateway_setup);
+
+static struct gpio_led ubnt_airgateway_pro_gpio_leds[] __initdata = {
+ {
+ .name = "ubnt:blue:wlan",
+ .gpio = 13,
+ }, {
+ .name = "ubnt:white:status",
+ .gpio = 17,
+ },
+};
+
+
+static struct gpio_keys_button airgateway_pro_gpio_keys[] __initdata = {
+ {
+ .desc = "reset",
+ .type = EV_KEY,
+ .code = KEY_RESTART,
+ .debounce_interval = UBNT_XM_KEYS_DEBOUNCE_INTERVAL,
+ .gpio = 12,
+ .active_low = 1,
+ }
+};
+
+static void __init ubnt_airgateway_pro_setup(void)
+{
+ u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff0000);
+ u8 *mac0 = (u8 *) KSEG1ADDR(0x1fff0000);
+
+ ath79_register_m25p80(NULL);
+ ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_airgateway_pro_gpio_leds),
+ ubnt_airgateway_pro_gpio_leds);
+
+ ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
+ ARRAY_SIZE(airgateway_pro_gpio_keys),
+ airgateway_pro_gpio_keys);
+
+ ath79_register_wmac(eeprom + UAP_PRO_WMAC_CALDATA_OFFSET, NULL);
+ ap91_pci_init(eeprom + UAP_PRO_PCI_CALDATA_OFFSET, NULL);
+
+
+ ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_SW_ONLY_MODE);
+
+ ath79_register_mdio(1, 0x0);
+
+ /* GMAC0 is left unused in this configuration */
+
+ /* GMAC1 is connected to MAC0 on the internal switch */
+ /* The PoE/WAN port connects to port 5 on the internal switch */
+ /* The LAN port connects to port 4 on the internal switch */
+ ath79_init_mac(ath79_eth1_data.mac_addr, mac0, 0);
+ ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+ ath79_register_eth(1);
+
+}
+
+MIPS_MACHINE(ATH79_MACH_UBNT_AIRGWP, "UBNT-AGWP", "Ubiquiti AirGateway Pro",
+ ubnt_airgateway_pro_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-wrtnode2q.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-wrtnode2q.c
new file mode 100644
index 0000000000..150a28b0d7
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-wrtnode2q.c
@@ -0,0 +1,126 @@
+/*
+ * WRTnode2Q board support
+ *
+ * Copyright (c) 2013 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (c) 2015 Kelei <xzmu@wrtnode.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/ar8216_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-spi.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+#include "pci.h"
+
+#define WRTNODE2Q_GPIO_LED_WLAN 12
+#define WRTNODE2Q_GPIO_LED_WPS 13
+#define WRTNODE2Q_GPIO_LED_STATUS 13
+
+#define WRTNODE2Q_GPIO_LED_WAN 4
+#define WRTNODE2Q_GPIO_LED_LAN1 16
+#define WRTNODE2Q_GPIO_LED_LAN2 15
+#define WRTNODE2Q_GPIO_LED_LAN3 14
+#define WRTNODE2Q_GPIO_LED_LAN4 11
+
+#define WRTNODE2Q_GPIO_BTN_WPS 17
+
+#define WRTNODE2Q_KEYS_POLL_INTERVAL 20 /* msecs */
+#define WRTNODE2Q_KEYS_DEBOUNCE_INTERVAL (3 * WRTNODE2Q_KEYS_POLL_INTERVAL)
+
+#define WRTNODE2Q_MAC0_OFFSET 0
+#define WRTNODE2Q_WMAC_CALDATA_OFFSET 0x1000
+
+static struct gpio_led wrtnode2q_leds_gpio[] __initdata = {
+ {
+ .name = "wrtnode2q:green:status",
+ .gpio = WRTNODE2Q_GPIO_LED_STATUS,
+ .active_low = 1,
+ },
+ {
+ .name = "wrtnode2q:green:wlan",
+ .gpio = WRTNODE2Q_GPIO_LED_WLAN,
+ .active_low = 1,
+ }
+};
+
+static struct gpio_keys_button wrtnode2q_gpio_keys[] __initdata = {
+ {
+ .desc = "WPS button",
+ .type = EV_KEY,
+ .code = KEY_WPS_BUTTON,
+ .debounce_interval = WRTNODE2Q_KEYS_DEBOUNCE_INTERVAL,
+ .gpio = WRTNODE2Q_GPIO_BTN_WPS,
+ .active_low = 1,
+ },
+};
+
+static void __init wrtnode2q_gpio_led_setup(void)
+{
+ ath79_register_leds_gpio(-1, ARRAY_SIZE(wrtnode2q_leds_gpio),
+ wrtnode2q_leds_gpio);
+ ath79_register_gpio_keys_polled(-1, WRTNODE2Q_KEYS_POLL_INTERVAL,
+ ARRAY_SIZE(wrtnode2q_gpio_keys),
+ wrtnode2q_gpio_keys);
+}
+
+static void __init wrtnode2q_setup(void)
+{
+ u8 *art = (u8 *) KSEG1ADDR(0x1f040000);
+
+ ath79_register_m25p80(NULL);
+
+ wrtnode2q_gpio_led_setup();
+
+ ath79_register_pci();
+ ath79_register_usb();
+
+ ath79_register_wmac(art + WRTNODE2Q_WMAC_CALDATA_OFFSET, NULL);
+
+ ath79_register_mdio(0, 0x0);
+ ath79_register_mdio(1, 0x0);
+
+ ath79_init_mac(ath79_eth0_data.mac_addr, art + WRTNODE2Q_MAC0_OFFSET, 0);
+ ath79_init_mac(ath79_eth1_data.mac_addr, art + WRTNODE2Q_MAC0_OFFSET, 1);
+
+ /* LAN ports */
+ ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+ ath79_eth1_data.speed = SPEED_1000;
+ ath79_eth1_data.duplex = DUPLEX_FULL;
+ ath79_switch_data.phy_poll_mask |= BIT(4);
+ ath79_switch_data.phy4_mii_en = 1;
+ ath79_register_eth(1);
+
+ /* WAN port */
+ ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+ ath79_eth0_data.speed = SPEED_100;
+ ath79_eth0_data.duplex = DUPLEX_FULL;
+ ath79_eth0_data.phy_mask = BIT(4);
+ ath79_register_eth(0);
+}
+
+MIPS_MACHINE(ATH79_MACH_WRTNODE2Q, "WRTNODE2Q", "WRTnode2Q board",
+ wrtnode2q_setup); \ No newline at end of file
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/machtypes.h b/target/linux/ar71xx/files/arch/mips/ath79/machtypes.h
index 4879255231..f40b4a43b5 100644
--- a/target/linux/ar71xx/files/arch/mips/ath79/machtypes.h
+++ b/target/linux/ar71xx/files/arch/mips/ath79/machtypes.h
@@ -42,6 +42,7 @@ enum ath79_mach_type {
ATH79_MACH_AP96, /* Atheros AP96 */
ATH79_MACH_ARCHER_C5, /* TP-LINK Archer C5 board */
ATH79_MACH_ARCHER_C7, /* TP-LINK Archer C7 board */
+ ATH79_MACH_ARCHER_C7_V2, /* TP-LINK Archer C7 V2 board */
ATH79_MACH_AW_NR580, /* AzureWave AW-NR580 */
ATH79_MACH_BHU_BXU2000N2_A1, /* BHU BXU2000n-2 A1 */
ATH79_MACH_BSB, /* Smart Electronics Black Swift board */
@@ -50,6 +51,7 @@ enum ath79_mach_type {
ATH79_MACH_CAP4200AG, /* Senao CAP4200AG */
ATH79_MACH_CARAMBOLA2, /* 8devices Carambola2 */
ATH79_MACH_CF_E316N_V2, /* COMFAST CF-E316N v2 */
+ ATH79_MACH_CPE210, /* TP-LINK CPE210 */
ATH79_MACH_CPE510, /* TP-LINK CPE510 */
ATH79_MACH_CR3000, /* PowerCloud CR3000 */
ATH79_MACH_CR5000, /* PowerCloud CR5000 */
@@ -96,6 +98,7 @@ enum ath79_mach_type {
ATH79_MACH_MR16, /* Cisco Meraki MR16 */
ATH79_MACH_MR18, /* Cisco Meraki MR18 */
ATH79_MACH_MR1750, /* OpenMesh MR1750 */
+ ATH79_MACH_MR1750V2, /* OpenMesh MR1750v2 */
ATH79_MACH_MR600V2, /* OpenMesh MR600v2 */
ATH79_MACH_MR600, /* OpenMesh MR600 */
ATH79_MACH_MR900, /* OpenMesh MR900 */
@@ -109,6 +112,7 @@ enum ath79_mach_type {
ATH79_MACH_NBG6616, /* Zyxel NBG6616 */
ATH79_MACH_NBG6716, /* Zyxel NBG6716 */
ATH79_MACH_OM2P_HSv2, /* OpenMesh OM2P-HSv2 */
+ ATH79_MACH_OM2P_HSv3, /* OpenMesh OM2P-HSv3 */
ATH79_MACH_OM2P_HS, /* OpenMesh OM2P-HS */
ATH79_MACH_OM2P_LC, /* OpenMesh OM2P-LC */
ATH79_MACH_OM2Pv2, /* OpenMesh OM2Pv2 */
@@ -149,6 +153,7 @@ enum ath79_mach_type {
ATH79_MACH_RB_SXTLITE5ND, /* Mikrotik RouterBOARD SXT Lite 5nD */
ATH79_MACH_RW2458N, /* Redwave RW2458N */
ATH79_MACH_SMART_300, /* NC-LINK SMART-300 */
+ ATH79_MACH_SOM9331, /* OpenEmbed SOM9331 */
ATH79_MACH_TELLSTICK_ZNET_LITE, /* TellStick ZNet Lite */
ATH79_MACH_TEW_632BRP, /* TRENDnet TEW-632BRP */
ATH79_MACH_TEW_673GRU, /* TRENDnet TEW-673GRU */
@@ -198,7 +203,9 @@ enum ath79_mach_type {
ATH79_MACH_TL_WR841N_V7, /* TP-LINK TL-WR841N/ND v7 */
ATH79_MACH_TL_WR841N_V8, /* TP-LINK TL-WR841N/ND v8 */
ATH79_MACH_TL_WR841N_V9, /* TP-LINK TL-WR841N/ND v9 */
+ ATH79_MACH_TL_WR841N_V11, /* TP-LINK TL-WR841N/ND v11 */
ATH79_MACH_TL_WR842N_V2, /* TP-LINK TL-WR842N/ND v2 */
+ ATH79_MACH_TL_WR842N_V3, /* TP-LINK TL-WR842N/ND v3 */
ATH79_MACH_TL_WR941ND, /* TP-LINK TL-WR941ND */
ATH79_MACH_TL_WR941ND_V5, /* TP-LINK TL-WR941ND v5 */
ATH79_MACH_TL_WR941ND_V6, /* TP-LINK TL-WR941ND v6 */
@@ -219,7 +226,8 @@ enum ath79_mach_type {
ATH79_MACH_UBNT_RS, /* Ubiquiti RouterStation */
ATH79_MACH_UBNT_UAP_PRO, /* Ubiquiti UniFi AP Pro */
ATH79_MACH_UBNT_UNIFI, /* Ubiquiti Unifi */
- ATH79_MACH_UBNT_UNIFIAC, /* Ubiquiti Unifi AC */
+ ATH79_MACH_UBNT_UNIFIAC_LITE, /* Ubiquiti Unifi AC LITE/LR */
+ ATH79_MACH_UBNT_UNIFIAC_PRO, /* Ubiquiti Unifi AC PRO */
ATH79_MACH_UBNT_UNIFI_OUTDOOR, /* Ubiquiti UnifiAP Outdoor */
ATH79_MACH_UBNT_UNIFI_OUTDOOR_PLUS, /* Ubiquiti UnifiAP Outdoor+ */
ATH79_MACH_UBNT_XM, /* Ubiquiti Networks XM board rev 1.0 */
@@ -248,6 +256,7 @@ enum ath79_mach_type {
ATH79_MACH_WPJ558, /* Compex WPJ558 */
ATH79_MACH_WRT160NL, /* Linksys WRT160NL */
ATH79_MACH_WRT400N, /* Linksys WRT400N */
+ ATH79_MACH_WRTNODE2Q, /* WRTnode2Q */
ATH79_MACH_WZR_HP_AG300H, /* Buffalo WZR-HP-AG300H */
ATH79_MACH_WZR_HP_G300NH, /* Buffalo WZR-HP-G300NH */
ATH79_MACH_WZR_HP_G300NH2, /* Buffalo WZR-HP-G300NH2 */
diff --git a/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c
index 38226cf22e..d5253609cd 100644
--- a/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c
+++ b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c
@@ -453,9 +453,17 @@ static void ag71xx_hw_stop(struct ag71xx *ag)
static void ag71xx_hw_setup(struct ag71xx *ag)
{
struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
+ struct ag71xx_mdio_platform_data *mpdata;
+ u32 init = MAC_CFG1_INIT;
+
+ if (pdata->mii_bus_dev && ag->pdev->id == 0) {
+ mpdata = pdata->mii_bus_dev->platform_data;
+ if (mpdata && mpdata->builtin_switch)
+ init |= MAC_CFG1_TFC | MAC_CFG1_RFC;
+ }
/* setup MAC configuration registers */
- ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, MAC_CFG1_INIT);
+ ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, init);
ag71xx_sb(ag, AG71XX_REG_MAC_CFG2,
MAC_CFG2_PAD_CRC_EN | MAC_CFG2_LEN_CHECK);
diff --git a/target/linux/ar71xx/generic/profiles/00-default.mk b/target/linux/ar71xx/generic/profiles/00-default.mk
index 36c4aa61b9..bf0f3fa5e6 100644
--- a/target/linux/ar71xx/generic/profiles/00-default.mk
+++ b/target/linux/ar71xx/generic/profiles/00-default.mk
@@ -9,6 +9,7 @@ define Profile/Default
NAME:=Default Profile (all drivers)
PACKAGES:= \
kmod-usb-core kmod-usb-ohci kmod-usb2 kmod-ledtrig-usbdev
+ PRIORITY := 1
endef
define Profile/Default/Description
diff --git a/target/linux/ar71xx/generic/profiles/01-minimal.mk b/target/linux/ar71xx/generic/profiles/01-minimal.mk
index dfaa3b0b37..54e6c6ddfb 100644
--- a/target/linux/ar71xx/generic/profiles/01-minimal.mk
+++ b/target/linux/ar71xx/generic/profiles/01-minimal.mk
@@ -8,6 +8,7 @@
define Profile/Minimal
NAME:=Minimal Profile (no drivers)
PACKAGES:=-kmod-ath9k -wpad-mini
+ PRIORITY := 2
endef
define Profile/Minimal/Description
diff --git a/target/linux/ar71xx/generic/profiles/02-ath5k.mk b/target/linux/ar71xx/generic/profiles/02-ath5k.mk
index 78203497f3..baa92b3391 100644
--- a/target/linux/ar71xx/generic/profiles/02-ath5k.mk
+++ b/target/linux/ar71xx/generic/profiles/02-ath5k.mk
@@ -8,6 +8,7 @@
define Profile/ath5k
NAME:=Atheros 802.11abg WiFi (ath5k)
PACKAGES:=kmod-ath5k -kmod-ath9k
+ PRIORITY := 3
endef
define Profile/ath5k/Description
diff --git a/target/linux/ar71xx/generic/profiles/jjplus.mk b/target/linux/ar71xx/generic/profiles/jjplus.mk
index 3f97dbf02e..c157fcbfac 100644
--- a/target/linux/ar71xx/generic/profiles/jjplus.mk
+++ b/target/linux/ar71xx/generic/profiles/jjplus.mk
@@ -28,7 +28,7 @@ endef
$(eval $(call Profile,JA76PF2))
define Profile/JWAP003
- NAME:=jjPlus JWAP0003
+ NAME:=jjPlus JWAP003
PACKAGES:=kmod-usb-core kmod-usb-ohci kmod-usb2
endef
diff --git a/target/linux/ar71xx/generic/profiles/openembed.mk b/target/linux/ar71xx/generic/profiles/openembed.mk
new file mode 100644
index 0000000000..2603e0a4cb
--- /dev/null
+++ b/target/linux/ar71xx/generic/profiles/openembed.mk
@@ -0,0 +1,13 @@
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+
+define Profile/SOM9331
+ NAME:=OpenEmbed SOM9331
+ PACKAGES:=kmod-usb-core kmod-usb2 kmod-usb-storage kmod-i2c-core kmod-i2c-gpio-custom kmod-spi-bitbang kmod-spi-dev kmod-spi-gpio kmod-spi-gpio-custom kmod-usb-serial
+endef
+
+define Profile/SOM9331/Description
+ Package set optimized for the OpenEmbed SOM9331.
+endef
+$(eval $(call Profile,SOM9331))
+
diff --git a/target/linux/ar71xx/generic/profiles/openmesh.mk b/target/linux/ar71xx/generic/profiles/openmesh.mk
index 6817c597b0..dbdf16959f 100644
--- a/target/linux/ar71xx/generic/profiles/openmesh.mk
+++ b/target/linux/ar71xx/generic/profiles/openmesh.mk
@@ -5,17 +5,6 @@
# See /LICENSE for more information.
#
-define Profile/OM2P
- NAME:=OpenMesh OM2P/OM2Pv2/OM2P-HS/OM2P-HSv2/OM2P-LC
- PACKAGES:=kmod-ath9k om-watchdog
-endef
-
-define Profile/OM2P/Description
- Package set optimized for the OpenMesh OM2P/OM2Pv2/OM2P-HS/OM2P-HSv2/OM2P-LC.
-endef
-
-$(eval $(call Profile,OM2P))
-
define Profile/OM5P
NAME:=OpenMesh OM5P/OM5P-AN
PACKAGES:=kmod-ath9k om-watchdog
@@ -61,12 +50,12 @@ endef
$(eval $(call Profile,MR900))
define Profile/MR1750
- NAME:=OpenMesh MR1750
+ NAME:=OpenMesh MR1750/MR1750v2
PACKAGES:=kmod-ath9k kmod-ath10k
endef
define Profile/MR1750/Description
- Package set optimized for the OpenMesh MR1750.
+ Package set optimized for the OpenMesh MR1750/MR1750v2.
endef
$(eval $(call Profile,MR1750))
diff --git a/target/linux/ar71xx/generic/profiles/ubnt.mk b/target/linux/ar71xx/generic/profiles/ubnt.mk
index 94eff18318..69b83985bd 100644
--- a/target/linux/ar71xx/generic/profiles/ubnt.mk
+++ b/target/linux/ar71xx/generic/profiles/ubnt.mk
@@ -38,16 +38,27 @@ endef
$(eval $(call Profile,UBNTUNIFI))
-define Profile/UBNTUNIFIAC
- NAME:=Ubiquiti UniFi AP AC
+define Profile/UBNTUNIFIACLITE
+ NAME:=Ubiquiti UniFi AP AC LITE/LR
PACKAGES:=kmod-ath10k ath10k-firmware-qca988x
endef
-define Profile/UBNTUNIFIAC/Description
- Package set optimized for the Ubiquiti UniFi AP AC.
+define Profile/UBNTUNIFIACLITE/Description
+ Package set optimized for the Ubiquiti UniFi AP AC LITE/LR.
endef
-$(eval $(call Profile,UBNTUNIFIAC))
+$(eval $(call Profile,UBNTUNIFIACLITE))
+
+define Profile/UBNTUNIFIACPRO
+ NAME:=Ubiquiti UniFi AP AC PRO
+ PACKAGES:=kmod-ath10k ath10k-firmware-qca988x kmod-usb-core kmod-usb-ohci kmod-usb2
+endef
+
+define Profile/UBNTUNIFIACPRO/Description
+ Package set optimized for the Ubiquiti UniFi AP AC PRO.
+endef
+
+$(eval $(call Profile,UBNTUNIFIACPRO))
define Profile/UBNTUNIFIOUTDOOR
NAME:=Ubiquiti UniFiAP Outdoor
diff --git a/target/linux/ar71xx/generic/profiles/wrtnode.mk b/target/linux/ar71xx/generic/profiles/wrtnode.mk
new file mode 100644
index 0000000000..35e6f92481
--- /dev/null
+++ b/target/linux/ar71xx/generic/profiles/wrtnode.mk
@@ -0,0 +1,17 @@
+#
+# Copyright (C) 2009 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/WRTNODE2Q
+ NAME:=WRTnode2Q board
+ PACKAGES:=kmod-usb-core kmod-usb2 kmod-usb-storage
+endef
+
+define Profile/WRTNODE2Q/Description
+ Package set optimized for the WRTnode2Q board.
+endef
+
+$(eval $(call Profile,WRTNODE2Q)) \ No newline at end of file
diff --git a/target/linux/ar71xx/image/Makefile b/target/linux/ar71xx/image/Makefile
index bc8a4a8ec7..2380a62cb4 100644
--- a/target/linux/ar71xx/image/Makefile
+++ b/target/linux/ar71xx/image/Makefile
@@ -16,6 +16,16 @@ KERNEL_LOADADDR = 0x80060000
DEVICE_VARS += NETGEAR_KERNEL_MAGIC NETGEAR_BOARD_ID NETGEAR_HW_ID CMDLINE CONSOLE IMAGE_SIZE BOARDNAME LOADER_FLASH_OFFS LOADER_TYPE
+ifeq ($(SUBTARGET),generic)
+include ./tp-link.mk
+include ./ubnt.mk
+include ./generic.mk
+endif
+ifeq ($(SUBTARGET),nand)
+include ./nand.mk
+endif
+include ./legacy.mk
+
define Build/netgear-squashfs
rm -rf $@.fs $@.squashfs
mkdir -p $@.fs/image
@@ -39,53 +49,6 @@ define Build/netgear-uImage
$(call Build/uImage,$(1) -M $(NETGEAR_KERNEL_MAGIC))
endef
-# combine kernel and rootfs into one image
-# mktplinkfw <type> <optional extra arguments to mktplinkfw binary>
-# <type> is "sysupgrade" or "factory"
-#
-# -a align the rootfs start on an <align> bytes boundary
-# -j add jffs2 end-of-filesystem markers
-# -s strip padding from end of the image
-# -X reserve <size> bytes in the firmware image (hexval prefixed with 0x)
-define Build/mktplinkfw
- -$(STAGING_DIR_HOST)/bin/mktplinkfw \
- -H $(TPLINK_HWID) -W $(TPLINK_HWREV) -F $(TPLINK_FLASHLAYOUT) -N OpenWrt -V $(REVISION) \
- -m $(TPLINK_HEADER_VERSION) \
- -k $(word 1,$^) \
- -r $@ \
- -o $@.new \
- -j -X 0x40000 \
- -a $(call rootfs_align,$(FILESYSTEM)) \
- $(wordlist 2,$(words $(1)),$(1)) \
- $(if $(findstring sysupgrade,$(word 1,$(1))),-s) && mv $@.new $@ || rm -f $@
-endef
-
-# mktplinkfw-initramfs <optional extra arguments to mktplinkfw binary>
-#
-# -c combined image
-define Build/mktplinkfw-initramfs
- $(STAGING_DIR_HOST)/bin/mktplinkfw \
- -H $(TPLINK_HWID) -W $(TPLINK_HWREV) -F $(TPLINK_FLASHLAYOUT) -N OpenWrt -V $(REVISION) $(1) \
- -m $(TPLINK_HEADER_VERSION) \
- -k $@ \
- -o $@.new \
- -s -S \
- -c
- @mv $@.new $@
-endef
-
-define Build/tplink-safeloader
- -$(STAGING_DIR_HOST)/bin/tplink-safeloader \
- -B $(TPLINK_BOARD_NAME) \
- -V $(REVISION) \
- -k $(word 1,$^) \
- -r $@ \
- -o $@.new \
- -j \
- $(wordlist 2,$(words $(1)),$(1)) \
- $(if $(findstring sysupgrade,$(word 1,$(1))),-S) && mv $@.new $@ || rm -f $@
-endef
-
define Build/loader-common
rm -rf $@.src
$(MAKE) -C lzma-loader \
@@ -120,45 +83,6 @@ define Build/copy-file
cat "$(1)" > "$@"
endef
-DEVICE_VARS += TPLINK_HWID TPLINK_HWREV TPLINK_FLASHLAYOUT TPLINK_HEADER_VERSION TPLINK_BOARD_NAME
-
-# UBNT_BOARD e.g. one of (XS2, XS5, RS, XM)
-# UBNT_TYPE e.g. one of (BZ, XM, XW)
-# UBNT_CHIP e.g. one of (ar7240, ar933x, ar934x)
-
-# mkubntimage is using the kernel image direct
-# routerboard creates partitions out of the ubnt header
-define Build/mkubntimage
- $(STAGING_DIR_HOST)/bin/mkfwimage \
- -B $(UBNT_BOARD) -v $(UBNT_TYPE).$(UBNT_CHIP).v6.0.0-OpenWrt-$(REVISION) \
- -k $(word 1,$^) \
- -r $@ \
- -o $@
-endef
-
-# all UBNT XM device expect the kernel image to have 1024k while flash, when
-# booting the image, the size doesn't matter.
-define Build/mkubntimage-split
- dd if=$@ of=$@.old1 bs=1024k count=1
- dd if=$@ of=$@.old2 bs=1024k skip=1
- $(STAGING_DIR_HOST)/bin/mkfwimage \
- -B $(UBNT_BOARD) -v $(UBNT_TYPE).$(UBNT_CHIP).v6.0.0-OpenWrt-$(REVISION) \
- -k $@.old1 \
- -r $@.old2 \
- -o $@
- rm $@.old1 $@.old2
-endef
-
-define Build/mkubntimage2
- $(STAGING_DIR_HOST)/bin/mkfwimage2 -f 0x9f000000 \
- -v $(UBNT_TYPE).$(UBNT_CHIP).v6.0.0-OpenWrt-$(REVISION) \
- -p jffs2:0x50000:0xf60000:0:0:$@ \
- -o $@.new
- @mv $@.new $@
-endef
-
-DEVICE_VARS += UBNT_BOARD UBNT_CHIP UBNT_TYPE
-
define Device/Default
BOARDNAME :=
DEVICE_PROFILE = $$(BOARDNAME)
@@ -175,2460 +99,4 @@ define Device/Default
IMAGE/sysupgrade.bin = append-kernel $$$$(BLOCKSIZE) | append-rootfs | pad-rootfs | check-size $$$$(IMAGE_SIZE)
endef
-define Device/bsb
- BOARDNAME = BSB
- IMAGE_SIZE = 16000k
- CONSOLE = ttyATH0,115200
- MTDPARTS = spi0.0:128k(u-boot)ro,64k(u-boot-env)ro,16128k(firmware),64k(art)ro
-endef
-TARGET_DEVICES += bsb
-
-define Device/carambola2
- BOARDNAME = CARAMBOLA2
- IMAGE_SIZE = 16000k
- CONSOLE = ttyATH0,115200
- MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,16000k(firmware),64k(art)ro
-endef
-TARGET_DEVICES += carambola2
-
-define Device/cf-e316n-v2
- BOARDNAME = CF-E316N-V2
- IMAGE_SIZE = 16192k
- CONSOLE = ttyS0,115200
- MTDPARTS = spi0.0:64k(u-boot)ro,64k(art)ro,16192k(firmware),64k(nvram)ro
-endef
-TARGET_DEVICES += cf-e316n-v2
-
-define Device/weio
- BOARDNAME = WEIO
- IMAGE_SIZE = 16000k
- CONSOLE = ttyATH0,115200
- MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,16000k(firmware),64k(art)ro
-endef
-TARGET_DEVICES += weio
-
-define Device/gl-ar150
- BOARDNAME = GL-AR150
- IMAGE_SIZE = 16000k
- CONSOLE = ttyATH0,115200
- MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,16000k(firmware),64k(art)ro
-endef
-TARGET_DEVICES += gl-ar150
-
-define Device/gl-ar300
- BOARDNAME = GL-AR300
- IMAGE_SIZE = 16000k
- CONSOLE = ttyS0,115200
- MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,16000k(firmware),64k(art)ro
-endef
-TARGET_DEVICES += gl-ar300
-
-define Device/gl-domino
- BOARDNAME = DOMINO
- IMAGE_SIZE = 16000k
- CONSOLE = ttyATH0,115200
- MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,16000k(firmware),64k(art)ro
-endef
-TARGET_DEVICES += gl-domino
-
-define Device/wndr3700
- BOARDNAME = WNDR3700
- NETGEAR_KERNEL_MAGIC = 0x33373030
- NETGEAR_BOARD_ID = WNDR3700
- IMAGE_SIZE = 7680k
- MTDPARTS = spi0.0:320k(u-boot)ro,128k(u-boot-env)ro,7680k(firmware),64k(art)ro
- IMAGES := sysupgrade.bin factory.img factory-NA.img
- KERNEL := kernel-bin | patch-cmdline | lzma -d20 | netgear-uImage lzma
- IMAGE/default = append-kernel $$$$(BLOCKSIZE) | netgear-squashfs | append-rootfs | pad-rootfs
- IMAGE/sysupgrade.bin = $$(IMAGE/default) | check-size $$$$(IMAGE_SIZE)
- IMAGE/factory.img = $$(IMAGE/default) | netgear-dni | check-size $$$$(IMAGE_SIZE)
- IMAGE/factory-NA.img = $$(IMAGE/default) | netgear-dni NA | check-size $$$$(IMAGE_SIZE)
-endef
-
-define Device/wndr3700v2
-$(Device/wndr3700)
- NETGEAR_BOARD_ID = WNDR3700v2
- NETGEAR_KERNEL_MAGIC = 0x33373031
- NETGEAR_HW_ID = 29763654+16+64
- IMAGE_SIZE = 15872k
- MTDPARTS = spi0.0:320k(u-boot)ro,128k(u-boot-env)ro,15872k(firmware),64k(art)ro
- IMAGES := sysupgrade.bin factory.img
-endef
-
-define Device/wndr3800
-$(Device/wndr3700v2)
- NETGEAR_BOARD_ID = WNDR3800
- NETGEAR_HW_ID = 29763654+16+128
-endef
-
-define Device/wndr3800ch
-$(Device/wndr3800)
- NETGEAR_BOARD_ID = WNDR3800CH
-endef
-
-define Device/wndrmac
-$(Device/wndr3700v2)
- NETGEAR_BOARD_ID = WNDRMAC
-endef
-
-define Device/wndrmacv2
-$(Device/wndr3800)
- NETGEAR_BOARD_ID = WNDRMACv2
-endef
-
-TARGET_DEVICES += wndr3700 wndr3700v2 wndr3800 wndr3800ch wndrmac wndrmacv2
-
-define Device/tplink
- TPLINK_HWREV := 0x1
- TPLINK_HEADER_VERSION := 1
- LOADER_TYPE := gz
- KERNEL := kernel-bin | patch-cmdline | lzma
- KERNEL_INITRAMFS := kernel-bin | patch-cmdline | lzma | mktplinkfw-initramfs
- IMAGES := sysupgrade.bin factory.bin
- IMAGE/sysupgrade.bin := append-rootfs | mktplinkfw sysupgrade
- IMAGE/factory.bin := append-rootfs | mktplinkfw factory
-endef
-
-define Device/tplink-nolzma
-$(Device/tplink)
- LOADER_FLASH_OFFS := 0x22000
- COMPILE := loader-$(1).gz
- COMPILE/loader-$(1).gz := loader-okli-compile
- KERNEL := copy-file $(KDIR)/vmlinux.bin.lzma | uImage lzma -M 0x4f4b4c49 | loader-okli $(1)
- KERNEL_INITRAMFS := copy-file $(KDIR)/vmlinux-initramfs.bin.lzma | loader-kernel-cmdline | mktplinkfw-initramfs
-endef
-
-define Device/tplink-4m
-$(Device/tplink-nolzma)
- TPLINK_FLASHLAYOUT := 4M
- IMAGE_SIZE := 3904k
-endef
-
-define Device/tplink-8m
-$(Device/tplink-nolzma)
- TPLINK_FLASHLAYOUT := 8M
- IMAGE_SIZE := 7936k
-endef
-
-define Device/tplink-4mlzma
-$(Device/tplink)
- TPLINK_FLASHLAYOUT := 4Mlzma
- IMAGE_SIZE := 3904k
-endef
-
-define Device/tplink-8mlzma
-$(Device/tplink)
- TPLINK_FLASHLAYOUT := 8Mlzma
- IMAGE_SIZE := 7936k
-endef
-
-define Device/tplink-16mlzma
-$(Device/tplink)
- TPLINK_FLASHLAYOUT := 16Mlzma
- IMAGE_SIZE := 15872k
-endef
-
-define Device/cpe210-220-510-520
- MTDPARTS := spi0.0:128k(u-boot)ro,64k(pation-table)ro,64k(product-info)ro,1536k(kernel),6144k(rootfs),192k(config)ro,64k(ART)ro,7680k@0x40000(firmware)
- IMAGE_SIZE := 7680k
- BOARDNAME := CPE510
- TPLINK_BOARD_NAME := CPE510
- LOADER_TYPE := elf
- KERNEL := kernel-bin | patch-cmdline | lzma | loader-kernel
- IMAGES := sysupgrade.bin factory.bin
- IMAGE/sysupgrade.bin := append-rootfs | tplink-safeloader sysupgrade
- IMAGE/factory.bin := append-rootfs | tplink-safeloader factory
-endef
-TARGET_DEVICES += cpe210-220-510-520
-
-define Device/tl-wdr4300-v1
-$(Device/tplink-8mlzma)
- BOARDNAME = TL-WDR4300
- DEVICE_PROFILE = TLWDR4300
- TPLINK_HWID := 0x43000001
-endef
-
-define Device/tl-wdr3500-v1
-$(Device/tl-wdr4300-v1)
- BOARDNAME = TL-WDR3500
- TPLINK_HWID := 0x35000001
-endef
-
-define Device/tl-wdr3600-v1
-$(Device/tl-wdr4300-v1)
- TPLINK_HWID := 0x36000001
-endef
-
-define Device/tl-wdr4300-v1-il
-$(Device/tl-wdr4300-v1)
- TPLINK_HWID := 0x43008001
-endef
-
-define Device/tl-wdr4310-v1
-$(Device/tl-wdr4300-v1)
- TPLINK_HWID := 0x43100001
-endef
-
-define Device/mw4530r-v1
-$(Device/tl-wdr4300-v1)
- TPLINK_HWID := 0x45300001
-endef
-TARGET_DEVICES += tl-wdr3500-v1 tl-wdr3600-v1 tl-wdr4300-v1 tl-wdr4300-v1-il tl-wdr4310-v1 mw4530r-v1
-
-define Device/tl-wdr6500-v2
-$(Device/tplink-8mlzma)
- KERNEL := kernel-bin | patch-cmdline | lzma | uImage lzma
- KERNEL_INITRAMFS := kernel-bin | patch-cmdline | lzma | uImage lzma | mktplinkfw-initramfs
- BOARDNAME = TL-WDR6500-v2
- DEVICE_PROFILE = TLWDR6500V2
- TPLINK_HWID := 0x65000002
- TPLINK_HEADER_VERSION := 2
-endef
-TARGET_DEVICES += tl-wdr6500-v2
-
-define Device/tl-wdr3320-v2
-$(Device/tplink-4mlzma)
- BOARDNAME = TL-WDR3320-v2
- DEVICE_PROFILE = TLWDR3320V2
- TPLINK_HWID := 0x33200002
- TPLINK_HEADER_VERSION := 2
-endef
-TARGET_DEVICES += tl-wdr3320-v2
-
-define Device/archer-c5-v1
- $(Device/tplink-16mlzma)
- BOARDNAME := ARCHER-C5
- DEVICE_PROFILE := ARCHERC7
- TPLINK_HWID := 0xc5000001
-endef
-
-define Device/archer-c7-v1
- $(Device/tplink-8mlzma)
- BOARDNAME := ARCHER-C7
- DEVICE_PROFILE := ARCHERC7
- TPLINK_HWID := 0x75000001
-endef
-
-define Device/archer-c7-v2
- $(Device/tplink-16mlzma)
- BOARDNAME := ARCHER-C7
- DEVICE_PROFILE := ARCHERC7
- TPLINK_HWID := 0xc7000002
- IMAGE/factory.bin := append-rootfs | mktplinkfw factory -C US
-endef
-
-define Device/tl-wdr7500-v3
- $(Device/tplink-8mlzma)
- BOARDNAME := ARCHER-C7
- DEVICE_PROFILE := ARCHERC7
- TPLINK_HWID := 0x75000003
-endef
-TARGET_DEVICES += archer-c5-v1 archer-c7-v1 archer-c7-v2 tl-wdr7500-v3
-
-define Device/cap324
- BOARDNAME := CAP324
- DEVICE_PROFILE := CAP324
- IMAGE_SIZE = 15296k
- MTDPARTS = spi0.0:256k(u-boot),64k(u-boot-env)ro,15296k(firmware),640k(certs),64k(nvram),64k(art)
-endef
-
-TARGET_DEVICES += cap324
-
-define Device/cap324-nocloud
- BOARDNAME := CAP324
- DEVICE_PROFILE := CAP324
- IMAGE_SIZE = 16000k
- MTDPARTS = spi0.0:256k(u-boot),64k(u-boot-env)ro,16000k(firmware),64k(art)
-endef
-
-TARGET_DEVICES += cap324-nocloud
-
-define Device/cr3000
- BOARDNAME := CR3000
- DEVICE_PROFILE := CR3000
- IMAGE_SIZE = 7104k
- MTDPARTS = spi0.0:256k(u-boot),64k(u-boot-env)ro,7104k(firmware),640k(certs),64k(nvram),64k(art)
-endef
-
-TARGET_DEVICES += cr3000
-
-define Device/cr3000-nocloud
- BOARDNAME := CR3000
- DEVICE_PROFILE := CR3000
- IMAGE_SIZE = 7808k
- MTDPARTS = spi0.0:256k(u-boot),64k(u-boot-env)ro,7808k(firmware),64k(art)
-endef
-
-TARGET_DEVICES += cr3000-nocloud
-
-define Device/cr5000
- BOARDNAME := CR5000
- DEVICE_PROFILE := CR5000
- IMAGE_SIZE = 7104k
- MTDPARTS = spi0.0:256k(u-boot),64k(u-boot-env)ro,7104k(firmware),640k(certs),64k(nvram),64k(art)
-endef
-
-TARGET_DEVICES += cr5000
-
-define Device/cr5000-nocloud
- BOARDNAME := CR5000
- DEVICE_PROFILE := CR5000
- IMAGE_SIZE = 7808k
- MTDPARTS = spi0.0:256k(u-boot),64k(u-boot-env)ro,7808k(firmware),64k(art)
-endef
-
-TARGET_DEVICES += cr5000-nocloud
-
-define Device/antminer-s1
- $(Device/tplink-8mlzma)
- BOARDNAME := ANTMINER-S1
- DEVICE_PROFILE := ANTMINERS1
- TPLINK_HWID := 0x04440101
- CONSOLE := ttyATH0,115200
-endef
-
-define Device/antminer-s3
- $(Device/tplink-8mlzma)
- BOARDNAME := ANTMINER-S3
- DEVICE_PROFILE := ANTMINERS3
- TPLINK_HWID := 0x04440301
- CONSOLE := ttyATH0,115200
-endef
-
-define Device/antrouter-r1
- $(Device/tplink-8mlzma)
- BOARDNAME := ANTROUTER-R1
- DEVICE_PROFILE := ANTROUTERR1
- TPLINK_HWID := 0x44440101
- CONSOLE := ttyATH0,115200
-endef
-
-define Device/el-m150
- $(Device/tplink-8mlzma)
- BOARDNAME := EL-M150
- DEVICE_PROFILE := ELM150
- TPLINK_HWID := 0x01500101
- CONSOLE := ttyATH0,115200
-endef
-
-define Device/el-mini
- $(Device/tplink-8mlzma)
- BOARDNAME := EL-MINI
- DEVICE_PROFILE := ELMINI
- TPLINK_HWID := 0x01530001
- CONSOLE := ttyATH0,115200
-endef
-TARGET_DEVICES += antminer-s1 antminer-s3 antrouter-r1 el-m150 el-mini
-
-define Device/gl-inet-6408A-v1
- $(Device/tplink-8mlzma)
- BOARDNAME := GL-INET
- DEVICE_PROFILE := GLINET
- TPLINK_HWID := 0x08000001
- CONSOLE := ttyATH0,115200
-endef
-
-define Device/gl-inet-6416A-v1
- $(Device/tplink-16mlzma)
- BOARDNAME := GL-INET
- DEVICE_PROFILE := GLINET
- TPLINK_HWID := 0x08000001
- CONSOLE := ttyATH0,115200
-endef
-TARGET_DEVICES += gl-inet-6408A-v1 gl-inet-6416A-v1
-
-define Device/rnx-n360rt
- $(Device/tplink-4m)
- BOARDNAME := TL-WR941ND
- DEVICE_PROFILE := RNXN360RT
- TPLINK_HWID := 0x09410002
- TPLINK_HWREV := 0x00420001
-endef
-TARGET_DEVICES += rnx-n360rt
-
-define Device/mc-mac1200r
- $(Device/tplink-8mlzma)
- BOARDNAME := MC-MAC1200R
- DEVICE_PROFILE := MAC1200R
- TPLINK_HWID := 0x12000001
-endef
-TARGET_DEVICES += mc-mac1200r
-
-define Device/minibox-v1
- $(Device/tplink-16mlzma)
- BOARDNAME := MINIBOX-V1
- DEVICE_PROFILE := MINIBOXV1
- TPLINK_HWID := 0x3C000201
- CONSOLE := ttyATH0,115200
-endef
-TARGET_DEVICES += minibox-v1
-
-define Device/omy-g1
- $(Device/tplink-16mlzma)
- BOARDNAME := OMY-G1
- DEVICE_PROFILE := OMYG1
- TPLINK_HWID := 0x06660101
-endef
-
-define Device/omy-x1
- $(Device/tplink-8mlzma)
- BOARDNAME := OMY-X1
- DEVICE_PROFILE := OMYX1
- TPLINK_HWID := 0x06660201
-endef
-TARGET_DEVICES += omy-g1 omy-x1
-
-define Device/onion-omega
- $(Device/tplink-16mlzma)
- BOARDNAME := ONION-OMEGA
- DEVICE_PROFILE := OMEGA
- TPLINK_HWID := 0x04700001
- CONSOLE := ttyATH0,115200
-endef
-TARGET_DEVICES += onion-omega
-
-define Device/tl-mr10u-v1
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-MR10U
- DEVICE_PROFILE := TLMR10U
- TPLINK_HWID := 0x00100101
- CONSOLE := ttyATH0,115200
-endef
-
-define Device/tl-mr11u-v1
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-MR11U
- DEVICE_PROFILE := TLMR11U
- TPLINK_HWID := 0x00110101
- CONSOLE := ttyATH0,115200
-endef
-
-define Device/tl-mr11u-v2
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-MR11U
- DEVICE_PROFILE := TLMR11U
- TPLINK_HWID := 0x00110102
- CONSOLE := ttyATH0,115200
-endef
-
-define Device/tl-mr12u-v1
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-MR13U
- DEVICE_PROFILE := TLMR12U
- TPLINK_HWID := 0x00120101
- CONSOLE := ttyATH0,115200
-endef
-
-define Device/tl-mr13u-v1
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-MR13U
- DEVICE_PROFILE := TLMR13U
- TPLINK_HWID := 0x00130101
- CONSOLE := ttyATH0,115200
-endef
-TARGET_DEVICES += tl-mr10u-v1 tl-mr11u-v1 tl-mr11u-v2 tl-mr12u-v1 tl-mr13u-v1
-
-define Device/tl-mr3020-v1
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-MR3020
- DEVICE_PROFILE := TLMR3020
- TPLINK_HWID := 0x30200001
- CONSOLE := ttyATH0,115200
-endef
-
-define Device/tl-mr3040-v1
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-MR3040
- DEVICE_PROFILE := TLMR3040
- TPLINK_HWID := 0x30400001
- CONSOLE := ttyATH0,115200
-endef
-
-define Device/tl-mr3040-v2
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-MR3040-v2
- DEVICE_PROFILE := TLMR3040
- TPLINK_HWID := 0x30400002
- CONSOLE := ttyATH0,115200
-endef
-
-define Device/tl-mr3220-v1
- $(Device/tplink-4m)
- BOARDNAME := TL-MR3220
- DEVICE_PROFILE := TLMR3220
- TPLINK_HWID := 0x32200001
-endef
-
-define Device/tl-mr3220-v2
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-MR3220-v2
- DEVICE_PROFILE := TLMR3220
- TPLINK_HWID := 0x32200002
- CONSOLE := ttyATH0,115200
-endef
-
-define Device/tl-mr3420-v1
- $(Device/tplink-4m)
- BOARDNAME := TL-MR3420
- DEVICE_PROFILE := TLMR3420
- TPLINK_HWID := 0x34200001
-endef
-
-define Device/tl-mr3420-v2
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-MR3420-v2
- DEVICE_PROFILE := TLMR3420
- TPLINK_HWID := 0x34200002
-endef
-TARGET_DEVICES += tl-mr3020-v1 tl-mr3040-v1 tl-mr3040-v2 tl-mr3220-v1 tl-mr3220-v2 tl-mr3420-v1 tl-mr3420-v2
-
-define Device/tl-wr703n-v1
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-WR703N
- DEVICE_PROFILE := TLWR703
- TPLINK_HWID := 0x07030101
- CONSOLE := ttyATH0,115200
-endef
-
-define Device/tl-wr710n-v1
- $(Device/tplink-8mlzma)
- BOARDNAME := TL-WR710N
- DEVICE_PROFILE := TLWR710
- TPLINK_HWID := 0x07100001
- CONSOLE := ttyATH0,115200
-endef
-
-define Device/tl-wr710n-v2
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-WR710N
- DEVICE_PROFILE := TLWR710
- TPLINK_HWID := 0x07100002
- CONSOLE := ttyATH0,115200
-endef
-
-define Device/tl-wr710n-v2.1
- $(Device/tplink-8mlzma)
- BOARDNAME := TL-WR710N
- DEVICE_PROFILE := TLWR710
- TPLINK_HWID := 0x07100002
- TPLINK_HWREV := 0x00000002
- CONSOLE := ttyATH0,115200
-endef
-
-define Device/tl-wr720n-v3
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-WR720N-v3
- DEVICE_PROFILE := TLWR720
- TPLINK_HWID := 0x07200103
- CONSOLE := ttyATH0,115200
-endef
-
-define Device/tl-wr720n-v4
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-WR720N-v3
- DEVICE_PROFILE := TLWR720
- TPLINK_HWID := 0x07200104
- CONSOLE := ttyATH0,115200
-endef
-TARGET_DEVICES += tl-wr703n-v1 tl-wr710n-v1 tl-wr710n-v2 tl-wr710n-v2.1 tl-wr720n-v3 tl-wr720n-v4
-
-define Device/tl-wr740n-v1
- $(Device/tplink-4m)
- BOARDNAME := TL-WR741ND
- DEVICE_PROFILE := TLWR740
- TPLINK_HWID := 0x07400001
-endef
-
-define Device/tl-wr740n-v3
- $(Device/tplink-4m)
- BOARDNAME := TL-WR741ND
- DEVICE_PROFILE := TLWR740
- TPLINK_HWID := 0x07400003
-endef
-
-define Device/tl-wr740n-v4
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-WR741ND-v4
- DEVICE_PROFILE := TLWR740
- TPLINK_HWID := 0x07400004
- CONSOLE := ttyATH0,115200
-endef
-
-define Device/tl-wr740n-v5
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-WR741ND-v4
- DEVICE_PROFILE := TLWR740
- TPLINK_HWID := 0x07400005
- CONSOLE := ttyATH0,115200
-endef
-
-define Device/tl-wr740n-v6
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-WR841N-v9
- DEVICE_PROFILE := TLWR740
- TPLINK_HWID := 0x07400006
-endef
-
-define Device/tl-wr741nd-v1
- $(Device/tplink-4m)
- BOARDNAME := TL-WR741ND
- DEVICE_PROFILE := TLWR741
- TPLINK_HWID := 0x07410001
-endef
-
-define Device/tl-wr741nd-v2
- $(Device/tplink-4m)
- BOARDNAME := TL-WR741ND
- DEVICE_PROFILE := TLWR741
- TPLINK_HWID := 0x07410001
-endef
-
-define Device/tl-wr741nd-v4
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-WR741ND-v4
- DEVICE_PROFILE := TLWR741
- TPLINK_HWID := 0x07410004
- CONSOLE := ttyATH0,115200
-endef
-
-define Device/tl-wr741nd-v5
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-WR741ND-v4
- DEVICE_PROFILE := TLWR741
- TPLINK_HWID := 0x07400005
- CONSOLE := ttyATH0,115200
-endef
-
-define Device/tl-wr810n
- $(Device/tplink-8mlzma)
- BOARDNAME := TL-WR810N
- DEVICE_PROFILE := TLWR810
- TPLINK_HWID := 0x08100001
-endef
-TARGET_DEVICES += tl-wr810n
-
-define Device/tl-wr743nd-v1
- $(Device/tplink-4m)
- BOARDNAME := TL-WR741ND
- DEVICE_PROFILE := TLWR743
- TPLINK_HWID := 0x07430001
-endef
-
-define Device/tl-wr743nd-v2
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-WR741ND-v4
- DEVICE_PROFILE := TLWR743
- TPLINK_HWID := 0x07430002
- CONSOLE := ttyATH0,115200
-endef
-TARGET_DEVICES += tl-wr740n-v1 tl-wr740n-v3 tl-wr740n-v4 tl-wr740n-v5 tl-wr740n-v6 tl-wr741nd-v1 tl-wr741nd-v2 tl-wr741nd-v4 tl-wr741nd-v5 tl-wr743nd-v1 tl-wr743nd-v2
-
-define Device/tl-wr841-v1.5
- $(Device/tplink-4m)
- BOARDNAME := TL-WR841N-v1.5
- DEVICE_PROFILE := TLWR841
- TPLINK_HWID := 0x08410002
- TPLINK_HWREV := 2
-endef
-
-define Device/tl-wr841-v3
- $(Device/tplink-4m)
- BOARDNAME := TL-WR941ND
- DEVICE_PROFILE := TLWR841
- TPLINK_HWID := 0x08410003
- TPLINK_HWREV := 3
-endef
-
-define Device/tl-wr841-v5
- $(Device/tplink-4m)
- BOARDNAME := TL-WR741ND
- DEVICE_PROFILE := TLWR841
- TPLINK_HWID := 0x08410005
-endef
-
-define Device/tl-wr841-v7
- $(Device/tplink-4m)
- BOARDNAME := TL-WR841N-v7
- DEVICE_PROFILE := TLWR841
- TPLINK_HWID := 0x08410007
-endef
-
-define Device/tl-wr841-v8
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-WR841N-v8
- DEVICE_PROFILE := TLWR841
- TPLINK_HWID := 0x08410008
-endef
-
-define Device/tl-wr841-v9
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-WR841N-v9
- DEVICE_PROFILE := TLWR841
- TPLINK_HWID := 0x08410009
-endef
-
-define Device/tl-wr841-v10
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-WR841N-v9
- DEVICE_PROFILE := TLWR841
- TPLINK_HWID := 0x08410010
-endef
-
-define Device/tl-wr841-v11
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-WR841N-v9
- DEVICE_PROFILE := TLWR841
- TPLINK_HWID := 0x08410011
-endef
-
-define Device/tl-wr842n-v1
- $(Device/tplink-8m)
- BOARDNAME := TL-MR3420
- DEVICE_PROFILE := TLWR842
- TPLINK_HWID := 0x08420001
-endef
-
-define Device/tl-wr842n-v2
- $(Device/tplink-8mlzma)
- BOARDNAME := TL-WR842N-v2
- DEVICE_PROFILE := TLWR842
- TPLINK_HWID := 0x8420002
-endef
-
-define Device/tl-wr843nd-v1
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-WR841N-v8
- DEVICE_PROFILE := TLWR843
- TPLINK_HWID := 0x08430001
-endef
-
-define Device/tl-wr847n-v8
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-WR841N-v8
- DEVICE_PROFILE := TLWR841
- TPLINK_HWID := 0x08470008
-endef
-TARGET_DEVICES += tl-wr841-v1.5 tl-wr841-v3 tl-wr841-v5 tl-wr841-v7 tl-wr841-v8 tl-wr841-v9 tl-wr841-v10 tl-wr841-v11 tl-wr842n-v1 tl-wr842n-v2 tl-wr843nd-v1 tl-wr847n-v8
-
-define Device/tl-wr941nd-v2
- $(Device/tplink-4m)
- BOARDNAME := TL-WR941ND
- DEVICE_PROFILE := TLWR941
- TPLINK_HWID := 0x09410002
- TPLINK_HWREV := 2
-endef
-
-define Device/tl-wr941nd-v3
- $(Device/tplink-4m)
- BOARDNAME := TL-WR941ND
- DEVICE_PROFILE := TLWR941
- TPLINK_HWID := 0x09410002
- TPLINK_HWREV := 2
-endef
-
-define Device/tl-wr941nd-v4
- $(Device/tplink-4m)
- BOARDNAME := TL-WR741ND
- DEVICE_PROFILE := TLWR941
- TPLINK_HWID := 0x09410004
-endef
-
-define Device/tl-wr941nd-v5
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-WR941ND-v5
- DEVICE_PROFILE := TLWR941
- TPLINK_HWID := 0x09410005
-endef
-
-define Device/tl-wr941nd-v6
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-WR941ND-v6
- DEVICE_PROFILE := TLWR941
- TPLINK_HWID := 0x09410006
-endef
-
-# Chinese version (unlike European) is similar to the TL-WDR3500
-define Device/tl-wr941nd-v6-cn
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-WDR3500
- DEVICE_PROFILE := TLWR941
- TPLINK_HWID := 0x09410006
-endef
-TARGET_DEVICES += tl-wr941nd-v2 tl-wr941nd-v3 tl-wr941nd-v4 tl-wr941nd-v5 tl-wr941nd-v6 tl-wr941nd-v6-cn
-
-define Device/tl-wr1041n-v2
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-WR1041N-v2
- DEVICE_PROFILE := TLWR1041
- TPLINK_HWID := 0x10410002
-endef
-TARGET_DEVICES += tl-wr1041n-v2
-
-define Device/tl-wr1043nd-v1
- $(Device/tplink-8m)
- BOARDNAME := TL-WR1043ND
- DEVICE_PROFILE := TLWR1043
- TPLINK_HWID := 0x10430001
-endef
-
-define Device/tl-wr1043nd-v2
- $(Device/tplink-8mlzma)
- BOARDNAME := TL-WR1043ND-v2
- DEVICE_PROFILE := TLWR1043
- TPLINK_HWID := 0x10430002
-endef
-
-define Device/tl-wr1043nd-v3
- $(Device/tplink-8mlzma)
- BOARDNAME := TL-WR1043ND-v2
- DEVICE_PROFILE := TLWR1043
- TPLINK_HWID := 0x10430003
-endef
-TARGET_DEVICES += tl-wr1043nd-v1 tl-wr1043nd-v2 tl-wr1043nd-v3
-
-define Device/tl-wr2543-v1
- $(Device/tplink-8mlzma)
- BOARDNAME := TL-WR2543N
- DEVICE_PROFILE := TLWR2543
- TPLINK_HWID := 0x25430001
- IMAGE/sysupgrade.bin := append-rootfs | mktplinkfw sysupgrade -v 3.13.99
- IMAGE/factory.bin := append-rootfs | mktplinkfw factory -v 3.13.99
-endef
-TARGET_DEVICES += tl-wr2543-v1
-
-define Device/tl-wdr4900-v2
- $(Device/tplink-8mlzma)
- BOARDNAME := TL-WDR4900-v2
- DEVICE_PROFILE := TLWDR4900V2
- TPLINK_HWID := 0x49000002
-endef
-TARGET_DEVICES += tl-wdr4900-v2
-
-define Device/tl-wa701nd-v1
- $(Device/tplink-4m)
- BOARDNAME := TL-WA901ND
- DEVICE_PROFILE := TLWA701
- TPLINK_HWID := 0x07010001
-endef
-
-define Device/tl-wa701nd-v2
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-WA701ND-v2
- DEVICE_PROFILE := TLWA701
- TPLINK_HWID := 0x07010002
- CONSOLE := ttyATH0,115200
-endef
-
-define Device/tl-wa730re-v1
- $(Device/tplink-4m)
- BOARDNAME := TL-WA901ND
- DEVICE_PROFILE := TLWA730RE
- TPLINK_HWID := 0x07300001
-endef
-
-define Device/tl-wa750re-v1
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-WA750RE
- DEVICE_PROFILE := TLWA750
- TPLINK_HWID := 0x07500001
-endef
-
-define Device/tl-wa7510n
- $(Device/tplink-4m)
- BOARDNAME := TL-WA7510N
- DEVICE_PROFILE := TLWA7510
- TPLINK_HWID := 0x75100001
-endef
-TARGET_DEVICES += tl-wa701nd-v1 tl-wa701nd-v2 tl-wa730re-v1 tl-wa750re-v1 tl-wa7510n
-
-define Device/tl-wa801nd-v1
- $(Device/tplink-4m)
- BOARDNAME := TL-WA901ND
- DEVICE_PROFILE := TLWA801
- TPLINK_HWID := 0x08010001
-endef
-
-define Device/tl-wa801nd-v2
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-WA801ND-v2
- DEVICE_PROFILE := TLWA801
- TPLINK_HWID := 0x08010002
-endef
-
-define Device/tl-wa801nd-v3
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-WA801ND-v3
- DEVICE_PROFILE := TLWA801
- TPLINK_HWID := 0x08010003
-endef
-
-define Device/tl-wa830re-v1
- $(Device/tplink-4m)
- BOARDNAME := TL-WA901ND
- DEVICE_PROFILE := TLWA830
- TPLINK_HWID := 0x08300010
-endef
-
-define Device/tl-wa830re-v2
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-WA830RE-v2
- DEVICE_PROFILE := TLWA830
- TPLINK_HWID := 0x08300002
-endef
-
-define Device/tl-wa850re-v1
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-WA850RE
- DEVICE_PROFILE := TLWA850
- TPLINK_HWID := 0x08500001
-endef
-
-define Device/tl-wa860re-v1
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-WA860RE
- DEVICE_PROFILE := TLWA860
- TPLINK_HWID := 0x08600001
-endef
-TARGET_DEVICES += tl-wa801nd-v1 tl-wa801nd-v2 tl-wa801nd-v3 tl-wa830re-v1 tl-wa830re-v2 tl-wa850re-v1 tl-wa860re-v1
-
-define Device/tl-wa901nd-v1
- $(Device/tplink-4m)
- BOARDNAME := TL-WA901ND
- DEVICE_PROFILE := TLWA901
- TPLINK_HWID := 0x09010001
-endef
-
-define Device/tl-wa901nd-v2
- $(Device/tplink-4m)
- BOARDNAME := TL-WA901ND-v2
- DEVICE_PROFILE := TLWA901
- TPLINK_HWID := 0x09010002
-endef
-
-define Device/tl-wa901nd-v3
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-WA901ND-v3
- DEVICE_PROFILE := TLWA901
- TPLINK_HWID := 0x09010003
-endef
-
-define Device/tl-wa901nd-v4
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-WA901ND-v4
- DEVICE_PROFILE := TLWA901
- TPLINK_HWID := 0x09010004
-endef
-
-TARGET_DEVICES += tl-wa901nd-v1 tl-wa901nd-v2 tl-wa901nd-v3 tl-wa901nd-v4
-
-define Device/tl-wa7210n-v2
- $(Device/tplink-4mlzma)
- BOARDNAME := TL-WA7210N-v2
- DEVICE_PROFILE := TLWA7210
- TPLINK_HWID := 0x72100002
- CONSOLE := ttyATH0,115200
-endef
-TARGET_DEVICES += tl-wa7210n-v2
-
-define Device/smart-300
- $(Device/tplink-8mlzma)
- BOARDNAME := SMART-300
- DEVICE_PROFILE := SMART-300
- TPLINK_HWID := 0x93410001
-endef
-TARGET_DEVICES += smart-300
-
-define Device/tellstick-znet-lite
- $(Device/tplink-16mlzma)
- BOARDNAME := TELLSTICK-ZNET-LITE
- DEVICE_PROFILE := TELLSTICKZNETLITE
- TPLINK_HWID := 0x00726001
- CONSOLE := ttyATH0,115200
-endef
-TARGET_DEVICES += tellstick-znet-lite
-
-define Device/oolite
- $(Device/tplink-16mlzma)
- BOARDNAME := GS-OOLITE
- DEVICE_PROFILE := OOLITE
- TPLINK_HWID := 0x3C000101
- CONSOLE := ttyATH0,115200
-endef
-TARGET_DEVICES += oolite
-
-# UBNT_BOARD e.g. one of (XS2, XS5, RS, XM)
-# UBNT_TYPE e.g. one of (BZ, XM, XW)
-# UBNT_CHIP e.g. one of (ar7240, ar933x, ar934x)
-define Device/ubnt-xm
- DEVICE_PROFILE := UBNT
- IMAGE_SIZE := 7552k
- MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,7552k(firmware),256k(cfg)ro,64k(EEPROM)ro
- UBNT_TYPE := XM
- UBNT_BOARD := XM
- UBNT_CHIP := ar7240
- IMAGES := sysupgrade.bin factory.bin
- IMAGE/factory.bin = $$(IMAGE/sysupgrade.bin) | mkubntimage-split
- IMAGE/sysupgrade.bin = append-kernel $$$$(BLOCKSIZE) | append-rootfs | pad-rootfs | check-size $$$$(IMAGE_SIZE)
-endef
-
-define Device/ubnt-xw
- DEVICE_PROFILE := UBNT
- IMAGE_SIZE := 7552k
- MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,7552k(firmware),256k(cfg)ro,64k(EEPROM)ro
- UBNT_TYPE := XW
- UBNT_BOARD := XM
- UBNT_CHIP := ar934x
- IMAGES := sysupgrade.bin factory.bin
- IMAGE/factory.bin = $$(IMAGE/sysupgrade.bin) | mkubntimage-split
- IMAGE/sysupgrade.bin = append-kernel $$$$(BLOCKSIZE) | append-rootfs | pad-rootfs | check-size $$$$(IMAGE_SIZE)
-endef
-
-define Device/ubnt-bz
- DEVICE_PROFILE := UBNT
- IMAGE_SIZE := 7552k
- MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,7552k(firmware),256k(cfg)ro,64k(EEPROM)ro
- UBNT_TYPE := BZ
- UBNT_BOARD := XM
- UBNT_CHIP := ar934x
- IMAGES := sysupgrade.bin factory.bin
- IMAGE/factory.bin = $$(IMAGE/sysupgrade.bin) | mkubntimage-split
- IMAGE/sysupgrade.bin = append-kernel $$$$(BLOCKSIZE) | append-rootfs | pad-rootfs | check-size $$$$(IMAGE_SIZE)
-endef
-
-define Device/rw2458n
- $(Device/ubnt-xm)
- BOARDNAME := RW2458N
-endef
-
-define Device/ubnt-airrouter
- $(Device/ubnt-xm)
- BOARDNAME := UBNT-AR
-endef
-
-define Device/ubnt-bullet-m
- $(Device/ubnt-xm)
- BOARDNAME := UBNT-BM
-endef
-
-define Device/ubnt-rocket-m
- $(Device/ubnt-xm)
- BOARDNAME := UBNT-RM
-endef
-
-define Device/ubnt-nano-m
- $(Device/ubnt-xm)
- BOARDNAME := UBNT-NM
-endef
-TARGET_DEVICES += rw2458n ubnt-airrouter ubnt-bullet-m ubnt-rocket-m ubnt-nano-m
-
-define Device/ubnt-unifi
- $(Device/ubnt-bz)
- BOARDNAME := UBNT-UF
- DEVICE_PROFILE := UBNT UBNTUNIFI
-endef
-
-define Device/ubnt-unifiac
- DEVICE_PROFILE := UBNT UBNTUNIFIAC
- IMAGE_SIZE := 7744k
- MTDPARTS = spi0.0:384k(u-boot)ro,64k(u-boot-env)ro,7744k(firmware),7744k(ubnt-airos)ro,128k(bs)ro,256k(cfg)ro,64k(EEPROM)ro
- IMAGES := sysupgrade.bin
- IMAGE/sysupgrade.bin = append-kernel $$$$(BLOCKSIZE) | append-rootfs | pad-rootfs | check-size $$$$(IMAGE_SIZE)
- BOARDNAME := UBNT-UF-AC
-endef
-
-define Device/ubnt-unifi-outdoor
- $(Device/ubnt-bz)
- BOARDNAME := UBNT-U20
- DEVICE_PROFILE := UBNT UBNTUNIFIOUTDOOR
-endef
-TARGET_DEVICES += ubnt-unifi ubnt-unifiac ubnt-unifi-outdoor
-
-define Device/ubnt-nano-m-xw
- $(Device/ubnt-xw)
- BOARDNAME := UBNT-NM-XW
-endef
-
-define Device/ubnt-loco-m-xw
- $(Device/ubnt-xw)
- BOARDNAME := UBNT-LOCO-XW
-endef
-
-define Device/ubnt-rocket-m-xw
- $(Device/ubnt-xw)
- BOARDNAME := UBNT-RM-XW
-endef
-
-define Device/ubnt-rocket-m-ti
- $(Device/ubnt-xw)
- BOARDNAME := UBNT-RM-TI
- UBNT_TYPE := TI
- UBNT_BOARD := XM
-endef
-TARGET_DEVICES += ubnt-nano-m-xw ubnt-loco-m-xw ubnt-rocket-m-xw ubnt-rocket-m-ti
-
-define Device/ubnt-air-gateway
- $(Device/ubnt-xm)
- BOARDNAME := UBNT-AGW
- UBNT_BOARD := XM
- UBNT_TYPE := AirGW
- UBNT_CHIP := ar933x
- CONSOLE = ttyATH0,115200
-endef
-TARGET_DEVICES += ubnt-air-gateway
-
-define Device/ubnt-air-gateway-pro
- $(Device/ubnt-xm)
- BOARDNAME := UBNT-AGWP
- UBNT_TYPE := AirGWP
- UBNT_CHIP := ar934x
- CONSOLE = ttyS0,115200
-endef
-TARGET_DEVICES += ubnt-air-gateway-pro
-
-define Device/ubdev01
- $(Device/ubnt-xm)
- MTDPARTS := spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,7488k(firmware),64k(certs),256k(cfg)ro,64k(EEPROM)ro
- BOARDNAME := UBNT-UF
- UBNT_BOARD := UBDEV01
- UBNT_TYPE := XM
- UBNT_CHIP := ar7240
-endef
-
-TARGET_DEVICES += ubdev01
-
-define Device/ubnt-routerstation
- IMAGE_SIZE := 16128k
- IMAGES := sysupgrade.bin factory.bin
- IMAGE/factory.bin = append-rootfs | pad-rootfs | mkubntimage
- IMAGE/sysupgrade.bin = append-rootfs | pad-rootfs | combined-image | check-size $$$$(IMAGE_SIZE)
- KERNEL := kernel-bin | patch-cmdline | lzma | pad-to $$(BLOCKSIZE)
-endef
-
-define Device/ubnt-rs
-$(Device/ubnt-routerstation)
- BOARDNAME := UBNT-RS
- DEVICE_PROFILE := Madwifi UBNT UBNTRS
- UBNT_BOARD := RS
- UBNT_TYPE := RSx
- UBNT_CHIP := ar7100
-endef
-
-define Device/ubnt-rspro
-$(Device/ubnt-routerstation)
- BOARDNAME := UBNT-RSPRO
- DEVICE_PROFILE := Madwifi UBNT UBNTRSPRO
- UBNT_BOARD := RSPRO
- UBNT_TYPE := RSPRO
- UBNT_CHIP := ar7100pro
-endef
-
-define Device/ubnt-ls-sr71
-$(Device/ubnt-routerstation)
- BOARDNAME := UBNT-LS-SR71
- DEVICE_PROFILE := Madwifi UBNT
- UBNT_BOARD := LS-SR71
- UBNT_TYPE := LS-SR71
- UBNT_CHIP := ar7100
-endef
-
-TARGET_DEVICES += ubnt-rs ubnt-rspro ubnt-ls-sr71
-
-define Device/ubnt-uap-pro
- KERNEL_SIZE := 1536k
- IMAGE_SIZE := 15744k
- MTDPARTS := spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,1536k(kernel),14208k(rootfs),256k(cfg)ro,64k(EEPROM)ro,15744k@0x50000(firmware)
- UBNT_TYPE := BZ
- UBNT_CHIP := ar934x
- BOARDNAME := UAP-PRO
- DEVICE_PROFILE := UBNT UAPPRO
- KERNEL := kernel-bin | patch-cmdline | lzma | uImage lzma | jffs2 kernel0
- IMAGES := sysupgrade.bin factory.bin
- IMAGE/sysupgrade.bin = append-kernel $$$$(KERNEL_SIZE) | append-rootfs | pad-rootfs | check-size $$$$(IMAGE_SIZE)
- IMAGE/factory.bin = $$(IMAGE/sysupgrade.bin) | mkubntimage2
-endef
-
-define Device/ubnt-unifi-outdoor-plus
-$(Device/ubnt-uap-pro)
- UBNT_CHIP := ar7240
- BOARDNAME := UBNT-UOP
- DEVICE_PROFILE := UBNT
-endef
-
-TARGET_DEVICES += ubnt-uap-pro ubnt-unifi-outdoor-plus
-
-rootfs_type=$(patsubst jffs2-%,jffs2,$(patsubst squashfs-%,squashfs,$(1)))
-
-# $(1): rootfs type.
-# $(2): board name.
-define imgname
-$(BIN_DIR)/$(IMG_PREFIX)-$(2)-$(call rootfs_type,$(1))
-endef
-
-define rootfs_align
-$(patsubst %-256k,0x40000,$(patsubst %-128k,0x20000,$(patsubst %-64k,0x10000,$(patsubst squashfs%,0x4,$(patsubst root.%,%,$(1))))))
-endef
-
-define sysupname
-$(call imgname,$(1),$(2))-sysupgrade.bin
-endef
-
-define factoryname
-$(call imgname,$(1),$(2))-factory.bin
-endef
-
-COMMA:=,
-
-define mkcmdline
-$(if $(1),board=$(1) )$(if $(2),console=$(2)$(COMMA)$(3))
-endef
-
-define mtdpartsize
-$(shell sz=`echo '$(2)' | sed -ne 's/.*[:$(COMMA)]\([0-9]*\)k[@]*[0-9a-zx]*($(1)).*/\1/p'`; [ -n "$$sz" ] && echo $$(($$sz * 1024)))
-endef
-
-SINGLE_PROFILES:=
-
-# $(1) : name of image build method to be used, e.g., AthLzma.
-# $(2) : name of the build template to be used, e.g. 64k, 64kraw, 128k, etc.
-# $(3) : name of the profile to be defined.
-# $(4) : board name.
-# $(5)~$(7) : arguments for $(mkcmdline)
-# board=$(1) console=$(2),$(3)
-# $(8)~$(14): extra arguments.
-define SingleProfile
- # $(1): action name, e.g. loader, buildkernel, squashfs, etc.
- define Image/Build/Profile/$(3)
- $$(call Image/Build/Template/$(2)/$$(1),$(1),$(4),$$(call mkcmdline,$(5),$(6),$(7)),$(8),$(9),$(10),$(11),$(12),$(13),$(14))
- endef
- SINGLE_PROFILES += $(3)
-endef
-
-# $(1), name of the MultiProfile to be added.
-# $(2), name of Profiles to be included in the MultiProfile.
-define MultiProfile
- define Image/Build/Profile/$(1)
- $(foreach p,$(2),
- $$(call Image/Build/Profile/$p,$$(1))
- )
- endef
-endef
-
-LOADER_MAKE := $(NO_TRACE_MAKE) -C lzma-loader KDIR=$(KDIR)
-
-VMLINUX:=$(BIN_DIR)/$(IMG_PREFIX)-vmlinux
-UIMAGE:=$(BIN_DIR)/$(IMG_PREFIX)-uImage
-
-# $(1): input file.
-# $(2): output file.
-# $(3): extra arguments for lzma.
-define CompressLzma
- $(STAGING_DIR_HOST)/bin/lzma e $(1) -lc1 -lp2 -pb2 $(3) $(2)
-endef
-
-define PatchKernel
- cp $(KDIR)/vmlinux$(3) $(KDIR_TMP)/vmlinux$(3)-$(1)
- $(STAGING_DIR_HOST)/bin/patch-cmdline $(KDIR_TMP)/vmlinux$(3)-$(1) "$(strip $(2))"
-endef
-
-define PatchKernel/initramfs
- $(call PatchKernel,$(1),$(2),-initramfs)
- cp $(KDIR_TMP)/vmlinux-initramfs-$(1) $(call imgname,initramfs,$(1)).bin
-endef
-
-# $(1): board name.
-# $(2): kernel command line.
-# $(3): extra argumetns for lzma.
-# $(4): name suffix, e.g. "-initramfs".
-define PatchKernelLzma
- cp $(KDIR)/vmlinux$(4) $(KDIR_TMP)/vmlinux$(4)-$(1)
- $(STAGING_DIR_HOST)/bin/patch-cmdline $(KDIR_TMP)/vmlinux$(4)-$(1) "$(strip $(2))"
- $(call CompressLzma,$(KDIR_TMP)/vmlinux$(4)-$(1),$(KDIR_TMP)/vmlinux$(4)-$(1).bin.lzma,$(3))
-endef
-
-define PatchKernelGzip
- cp $(KDIR)/vmlinux$(3) $(KDIR_TMP)/vmlinux$(3)-$(1)
- $(STAGING_DIR_HOST)/bin/patch-cmdline $(KDIR_TMP)/vmlinux$(3)-$(1) "$(strip $(2))"
- gzip -9n -c $(KDIR_TMP)/vmlinux$(3)-$(1) > $(KDIR_TMP)/vmlinux$(3)-$(1).bin.gz
-endef
-
-ifneq ($(SUBTARGET),mikrotik)
-# $(1): compression method of the data.
-# $(2): extra arguments.
-# $(3): input data file.
-# $(4): output file.
-define MkuImage
- mkimage -A mips -O linux -T kernel -a 0x80060000 -C $(1) $(2) \
- -e 0x80060000 -n 'MIPS OpenWrt Linux-$(LINUX_VERSION)' \
- -d $(3) $(4)
-endef
-
-# $(1): board name.
-# $(2): kernel command line.
-# $(3): extra arguments for lzma.
-# $(4): name suffix, e.g. "-initramfs".
-# $(5): extra arguments for mkimage.
-define MkuImageLzma
- $(call PatchKernelLzma,$(1),$(2),$(3),$(4))
- $(call MkuImage,lzma,$(5),$(KDIR_TMP)/vmlinux$(4)-$(1).bin.lzma,$(KDIR_TMP)/vmlinux$(4)-$(1).uImage)
-endef
-
-define MkuImageLzma/initramfs
- $(call PatchKernelLzma,$(1),$(2),$(3),-initramfs)
- $(call MkuImage,lzma,$(4),$(KDIR_TMP)/vmlinux-initramfs-$(1).bin.lzma,$(call imgname,initramfs,$(1))-uImage.bin)
-endef
-
-define MkuImageGzip
- $(call PatchKernelGzip,$(1),$(2))
- $(call MkuImage,gzip,,$(KDIR_TMP)/vmlinux-$(1).bin.gz,$(KDIR_TMP)/vmlinux-$(1).uImage)
-endef
-
-define MkuImageGzip/initramfs
- $(call PatchKernelGzip,$(1),$(2),-initramfs)
- $(call MkuImage,gzip,,$(KDIR_TMP)/vmlinux-initramfs-$(1).bin.gz,$(call imgname,initramfs,$(1))-uImage.bin)
-endef
-
-define MkuImageOKLI
- $(call MkuImage,lzma,-M 0x4f4b4c49,$(KDIR)/vmlinux.bin.lzma,$(KDIR_TMP)/vmlinux-$(1).okli)
-endef
-endif
-
-# $(1): name of the 1st file.
-# $(2): size limit of the 1st file if it is greater than 262144, or
-# the erase size of the flash if it is greater than zero and less
-# than 262144
-# $(3): name of the 2nd file.
-# $(4): size limit of the 2nd file if $(2) is greater than 262144, otherwise
-# it is the size limit of the output file
-# $(5): name of the output file.
-# $(6): padding size.
-define CatFiles
- if [ $(2) -eq 0 ]; then \
- filename="$(3)"; fstype=$$$${filename##*\.}; \
- case "$$$${fstype}" in \
- "jffs2-64k") bs=65536;; \
- "jffs2-128k") bs=131072;; \
- "jffs2-256k") bs=262144;; \
- *) bs=`stat -c%s $(1)`;; \
- esac; \
- ( dd if=$(1) bs=$$$${bs} conv=sync; cat $(3) ) > $(5); \
- if [ -n "$(6)" ]; then \
- case "$$$${fstype}" in \
- squashfs*) \
- padjffs2 $(5) $(6); \
- ;; \
- esac; \
- fi; \
- if [ `stat -c%s $(5)` -gt $(4) ]; then \
- echo "Warning: $(5) is too big (> $(4) bytes)" >&2; \
- rm -f $(5); \
- fi; \
- else if [ $(2) -gt 262144 ]; then \
- if [ `stat -c%s "$(1)"` -gt $(2) ]; then \
- echo "Warning: $(1) is too big (> $(2) bytes)" >&2; \
- else if [ `stat -c%s $(3)` -gt $(4) ]; then \
- echo "Warning: $(3) is too big (> $(4) bytes)" >&2; \
- else \
- ( dd if=$(1) bs=$(2) conv=sync; dd if=$(3) ) > $(5); \
- fi; fi; \
- else \
- ( dd if=$(1) bs=$(2) conv=sync; dd if=$(3) ) > $(5); \
- if [ `stat -c%s $(5)` -gt $(4) ]; then \
- echo "Warning: $(5) is too big (> $(4) bytes)" >&2; \
- rm -f $(5); \
- fi; \
- fi; fi
-endef
-
-# $(1): rootfs type.
-# $(2): board name.
-# $(3): kernel image size limit.
-# $(4): rootfs image size limit.
-# $(5): padding argument for padjffs2.
-Sysupgrade/KR=$(call CatFiles,$(2),$(3),$(KDIR)/root.$(1),$(4),$(call sysupname,$(1),$(5)))
-Sysupgrade/KRuImage=$(call CatFiles,$(KDIR_TMP)/vmlinux-$(2).uImage,$(3),$(KDIR)/root.$(1),$(4),$(call sysupname,$(1),$(2)),$(5))
-Sysupgrade/RKuImage=$(call CatFiles,$(KDIR)/root.$(1),$(4),$(KDIR_TMP)/vmlinux-$(2).uImage,$(3),$(call sysupname,$(1),$(2)))
-
-# $(1): ubinize ini file
-# $(2): working directory
-# $(3): output file
-# $(4): physical erase block size
-# $(5): minimum I/O unit size
-# $(6): custom options
-define ubinize
- $(CP) $(1) $(2)
- ( cd $(2); $(STAGING_DIR_HOST)/bin/ubinize -o $(3) -p $(4) -m $(5) $(6) $(1))
-endef
-
-#
-# Embed lzma-compressed kernel inside lzma-loader.
-#
-# $(1), suffix of output filename, e.g. generic, lowercase board name, etc.
-# $(2), suffix of target file to build, e.g. bin, gz, elf
-# $(3), kernel command line to pass from lzma-loader to kernel
-# $(4), unused here
-# $(5), suffix of kernel filename, e.g. -initramfs, or empty
-define Image/BuildLoader
- -rm -rf $(KDIR)/lzma-loader
- $(LOADER_MAKE) LOADER=loader-$(1).$(2) KERNEL_CMDLINE="$(3)"\
- LZMA_TEXT_START=0x80a00000 LOADADDR=0x80060000 \
- LOADER_DATA="$(KDIR)/vmlinux$(5).bin.lzma" BOARD="$(1)" \
- compile loader.$(2)
- -$(CP) $(KDIR)/loader-$(1).$(2) $(KDIR)/loader-$(1)$(5).$(2)
-endef
-
-#
-# Build lzma-loader alone which will search for lzma-compressed kernel identified by
-# uImage header with magic "OKLI" at boot time.
-#
-# $(4), offset into the flash space to start searching uImage magic "OKLI".
-# $(5), size of search range starting at $(4). With 0 as the value, uImage
-# header is expected to be at precisely $(4)
-define Image/BuildLoaderAlone
- -rm -rf $(KDIR)/lzma-loader
- $(LOADER_MAKE) LOADER=loader-$(1).$(2) KERNEL_CMDLINE="$(3)" \
- LZMA_TEXT_START=0x80a00000 LOADADDR=0x80060000 \
- BOARD="$(1)" FLASH_OFFS=$(4) FLASH_MAX=$(5) \
- compile loader.$(2)
-endef
-
-define Build/Clean
- $(LOADER_MAKE) clean
-endef
-
-alfa_ap120c_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,13312k(rootfs),1536k(kernel),1152k(unknown)ro,64k(art)ro;spi0.1:-(unknown)
-alfa_ap96_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,256k(u-boot-env)ro,13312k(rootfs),2048k(kernel),512k(caldata)ro,15360k@0x80000(firmware)
-alfa_mtdlayout_8M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,6144k(rootfs),1600k(kernel),64k(nvram),64k(art)ro,7744k@0x50000(firmware)
-alfa_mtdlayout_16M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,15936k(firmware),64k(nvram),64k(art)ro
-all0258n_mtdlayout=mtdparts=spi0.0:256k(u-boot),64k(u-boot-env),6272k(firmware),1536k(failsafe),64k(art)
-all0315n_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,256k(u-boot-env),13568k(firmware),2048k(failsafe),256k(art)ro
-ap81_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,5120k(rootfs),2688k(kernel),64k(art)ro,7808k@0x50000(firmware)
-ap83_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,128k(u-boot-env)ro,4096k(rootfs),3648k(kernel),64k(art)ro,7744k@0x60000(firmware)
-ap96_mtdlayout=mtdparts=spi0.0:192k(u-boot)ro,64k(u-boot-env)ro,6144k(rootfs),1728k(kernel),64k(art)ro,7872k@0x40000(firmware)
-ap113_mtd_layout=mtdparts=spi0.0:64k(u-boot),3008k(rootfs),896k(uImage),64k(NVRAM),64k(ART),3904k@0x10000(firmware)
-ap121_mtdlayout_2M=mtdparts=spi0.0:64k(u-boot)ro,1216k(rootfs),704k(kernel),64k(art)ro,1920k@0x10000(firmware)
-ap121_mtdlayout_4M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,2448k(rootfs),1200k(kernel),64k(nvram),64k(art)ro,3648k@0x50000(firmware)
-ap121_mtdlayout_8M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,6144k(rootfs),1600k(kernel),64k(nvram),64k(art)ro,7744k@0x50000(firmware)
-ap121_mtdlayout_16M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,10944k(rootfs),4992k(kernel),64k(nvram),64k(art)ro,15936k@0x50000(firmware)
-ap132_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,1408k(kernel),6400k(rootfs),64k(art),7808k@0x50000(firmware)
-ap135_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,14528k(rootfs),1472k(kernel),64k(art)ro,16000k@0x50000(firmware)
-ap136_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,6336k(rootfs),1408k(kernel),64k(mib0),64k(art)ro,7744k@0x50000(firmware)
-ap143_mtdlayout_8M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,6336k(rootfs),1472k(kernel),64k(art)ro,7744k@0x50000(firmware)
-ap143_mtdlayout_16M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,14528k(rootfs),1472k(kernel),64k(art)ro,16000k@0x50000(firmware)
-ap147_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,14528k(rootfs),1472k(kernel),64k(art),16000k@0x50000(firmware)
-ap152_mtdlayout_16M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,14528k(rootfs),1472k(kernel),64k(art)ro,16000k@0x50000(firmware)
-bxu2000n2_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,1408k(kernel),8448k(rootfs),6016k(user),64k(cfg),64k(oem),64k(art)ro
-cameo_ap81_mtdlayout=mtdparts=spi0.0:128k(u-boot)ro,64k(config)ro,3840k(firmware),64k(art)ro
-cameo_ap91_mtdlayout=mtdparts=spi0.0:192k(u-boot)ro,64k(nvram)ro,3712k(firmware),64k(mac)ro,64k(art)ro
-cameo_ap99_mtdlayout=mtdparts=spi0.0:192k(u-boot)ro,64k(nvram)ro,3520k(firmware),64k(mac)ro,192k(lp)ro,64k(art)ro
-cameo_ap121_mtdlayout=mtdparts=spi0.0:64k(u-boot)ro,64k(art)ro,64k(mac)ro,64k(nvram)ro,192k(language)ro,3648k(firmware)
-cameo_ap121_mtdlayout_8M=mtdparts=spi0.0:64k(u-boot)ro,64k(art)ro,64k(mac)ro,64k(nvram)ro,256k(language)ro,7680k@0x80000(firmware)
-cameo_ap123_mtdlayout_4M=mtdparts=spi0.0:64k(u-boot)ro,64k(nvram)ro,3712k(firmware),192k(lang)ro,64k(art)ro
-cameo_db120_mtdlayout=mtdparts=spi0.0:64k(uboot)ro,64k(nvram)ro,15936k(firmware),192k(lang)ro,64k(mac)ro,64k(art)ro
-cameo_db120_mtdlayout_8M=mtdparts=spi0.0:64k(uboot)ro,64k(nvram)ro,7872k(firmware),128k(lang)ro,64k(art)ro
-cap4200ag_mtdlayout=mtdparts=spi0.0:256k(u-boot),64k(u-boot-env),320k(custom)ro,1536k(kernel),12096k(rootfs),2048k(failsafe),64k(art),13632k@0xa0000(firmware)
-eap300v2_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env),320k(custom),13632k(firmware),2048k(failsafe),64k(art)ro
-db120_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,6336k(rootfs),1408k(kernel),64k(nvram),64k(art)ro,7744k@0x50000(firmware)
-dgl_5500_mtdlayout=mtdparts=spi0.0:192k(u-boot)ro,64k(nvram)ro,15296k(firmware),192k(lang)ro,512k(my-dlink)ro,64k(mac)ro,64k(art)ro
-dlan_hotspot_mtdlayout=mtdparts=spi0.0:128k(u-boot)ro,64k(Config1)ro,64k(Config2)ro,7872k@0x40000(firmware),64k(art)ro
-dlan_pro_500_wp_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,64k(Config1)ro,64k(Config2)ro,7680k@0x70000(firmware),64k(art)ro
-dlan_pro_1200_ac_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,64k(Config1)ro,64k(Config2)ro,15872k@0x70000(firmware),64k(art)ro
-cameo_ap94_mtdlayout=mtdparts=spi0.0:256k(uboot)ro,64k(config)ro,6208k(firmware),64k(caldata)ro,1600k(unknown)ro,64k@0x7f0000(caldata_copy)
-cameo_ap94_mtdlayout_fat=mtdparts=spi0.0:256k(uboot)ro,64k(config)ro,7808k(firmware),64k(caldata)ro,64k@0x660000(caldata_orig),6208k@0x50000(firmware_orig)
-esr900_mtdlayout=mtdparts=spi0.0:192k(u-boot)ro,64k(u-boot-env)ro,1408k(kernel),13248k(rootfs),1024k(manufacture)ro,64k(backup)ro,320k(storage)ro,64k(caldata)ro,14656k@0x40000(firmware)
-esr1750_mtdlayout=mtdparts=spi0.0:192k(u-boot)ro,64k(u-boot-env)ro,1408k(kernel),13248k(rootfs),1024k(manufacture)ro,64k(backup)ro,320k(storage)ro,64k(caldata)ro,14656k@0x40000(firmware)
-epg5000_mtdlayout=mtdparts=spi0.0:192k(u-boot)ro,64k(u-boot-env)ro,1408k(kernel),13248k(rootfs),1024k(manufacture)ro,64k(backup)ro,320k(storage)ro,64k(caldata)ro,14656k@0x40000(firmware)
-ew-dorin_mtdlayout_4M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env),3712k(firmware),64k(art)
-ew-dorin_mtdlayout_16M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env),16000k(firmware),64k(art)ro
-f9k1115v2_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env),14464k(rootfs),1408k(kernel),64k(nvram)ro,64k(envram)ro,64k(art)ro,15872k@0x50000(firmware)
-dlrtdev_mtdlayout=mtdparts=spi0.0:256k(uboot)ro,64k(config)ro,6208k(firmware),64k(caldata)ro,640k(certs),960k(unknown)ro,64k@0x7f0000(caldata_copy)
-dlrtdev_mtdlayout_fat=mtdparts=spi0.0:256k(uboot)ro,64k(config)ro,7168k(firmware),640k(certs),64k(caldata)ro,64k@0x660000(caldata_orig),6208k@0x50000(firmware_orig)
-dragino2_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,16000k(firmware),64k(config)ro,64k(art)ro
-hiwifi_hc6361_mtdlayout=mtdparts=spi0.0:64k(u-boot)ro,64k(bdinfo)ro,1280k(kernel),14848k(rootfs),64k(backup)ro,64k(art)ro,16128k@0x20000(firmware)
-mr12_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,256k(u-boot-env)ro,13440k(rootfs),2304k(kernel),128k(art)ro,15744k@0x80000(firmware)
-mr16_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,256k(u-boot-env)ro,13440k(rootfs),2304k(kernel),128k(art)ro,15744k@0x80000(firmware)
-pb92_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,2752k(rootfs),896k(kernel),64k(nvram),64k(art)ro,3648k@0x50000(firmware)
-planex_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,7744k(firmware),128k(art)ro
-ubntxm_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,7552k(firmware),256k(cfg)ro,64k(EEPROM)ro
-uap_pro_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,1536k(kernel),14208k(rootfs),256k(cfg)ro,64k(EEPROM)ro,15744k@0x50000(firmware)
-ubdev_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,7488k(firmware),64k(certs),256k(cfg)ro,64k(EEPROM)ro
-whrhpg300n_mtdlayout=mtdparts=spi0.0:248k(u-boot)ro,8k(u-boot-env)ro,3712k(firmware),64k(art)ro
-wlr8100_mtdlayout=mtdparts=spi0.0:192k(u-boot)ro,64k(u-boot-env)ro,1408k(kernel),14080k(rootfs),192k(unknown)ro,64k(art)ro,384k(unknown2)ro,15488k@0x40000(firmware)
-wpj342_mtdlayout_16M=mtdparts=spi0.0:192k(u-boot)ro,16128k(firmware),64k(art)ro
-wpj344_mtdlayout_16M=mtdparts=spi0.0:192k(u-boot)ro,16128k(firmware),64k(art)ro
-dr344_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,6336k(rootfs),1408k(kernel),64k(nvram),64k(art)ro,7744k@0x50000(firmware)
-wpj531_mtdlayout_16M=mtdparts=spi0.0:192k(u-boot)ro,16128k(firmware),64k(art)ro
-wpj558_mtdlayout_16M=mtdparts=spi0.0:192k(u-boot)ro,16128k(firmware),64k(art)ro
-wndap360_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,1728k(kernel),6016k(rootfs),64k(nvram)ro,64k(art)ro,7744k@0x50000(firmware)
-wnr2200_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,7808k(firmware),64k(art)ro
-wnr2000v3_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,3712k(firmware),64k(art)ro
-wnr2000v4_mtdlayout=mtdparts=spi0.0:192k(u-boot)ro,64k(u-boot-env)ro,3776k(firmware),64k(art)ro
-r6100_mtdlayout=mtdparts=ar934x-nfc:128k(u-boot)ro,256k(caldata),256k(caldata-backup),512k(config),512k(pot),2048k(kernel),122240k(ubi),25600k@0x1a0000(firmware),2048k(language),3072k(traffic_meter)
-tew823dru_mtdlayout=mtdparts=spi0.0:192k(u-boot)ro,64k(nvram)ro,15296k(firmware),192k(lang)ro,512k(my-dlink)ro,64k(mac)ro,64k(art)ro
-wndr4300_mtdlayout=mtdparts=ar934x-nfc:256k(u-boot)ro,256k(u-boot-env)ro,256k(caldata),512k(pot),2048k(language),512k(config),3072k(traffic_meter),2048k(kernel),23552k(ubi),25600k@0x6c0000(firmware),256k(caldata_backup),-(reserved)
-zcn1523h_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,6208k(rootfs),1472k(kernel),64k(configure)ro,64k(mfg)ro,64k(art)ro,7680k@0x50000(firmware)
-mynet_n600_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,64k(devdata)ro,64k(devconf)ro,15872k(firmware),64k(radiocfg)ro
-mynet_rext_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,7808k(firmware),64k(nvram)ro,64k(ART)ro
-zyx_nbg6716_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(env)ro,64k(RFdata)ro,-(nbu);ar934x-nfc:2048k(zyxel_rfsd),2048k(romd),1024k(header),2048k(kernel),-(ubi)
-qihoo_c301_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env),64k(devdata),64k(devconf),15744k(firmware),64k(warm_start),64k(action_image_config),64k(radiocfg)ro;spi0.1:15360k(upgrade2),1024k(privatedata)
-yun_mtdlayout_8M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,6464k(rootfs),1280k(kernel),64k(nvram),64k(art),7744k@0x50000(firmware)
-yun_mtdlayout_16M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,14656k(rootfs),1280k(kernel),64k(nvram),64k(art),15936k@0x50000(firmware)
-
-
-define Image/BuildKernel
- cp $(KDIR)/vmlinux.elf $(VMLINUX).elf
- cp $(KDIR)/vmlinux $(VMLINUX).bin
- dd if=$(KDIR)/vmlinux.bin.lzma of=$(VMLINUX).lzma bs=65536 conv=sync
- dd if=$(KDIR)/vmlinux.bin.gz of=$(VMLINUX).gz bs=65536 conv=sync
- $(call MkuImage,gzip,,$(KDIR)/vmlinux.bin.gz,$(UIMAGE)-gzip.bin)
- $(call MkuImage,lzma,,$(KDIR)/vmlinux.bin.lzma,$(UIMAGE)-lzma.bin)
- cp $(KDIR)/loader-generic.elf $(VMLINUX)-lzma.elf
- -mkdir -p $(KDIR_TMP)
- $(call Image/Build/Profile/$(IMAGE_PROFILE),buildkernel)
-endef
-
-define Image/BuildKernel/Initramfs
- cp $(KDIR)/vmlinux-initramfs.elf $(VMLINUX)-initramfs.elf
- cp $(KDIR)/vmlinux-initramfs $(VMLINUX)-initramfs.bin
- dd if=$(KDIR)/vmlinux-initramfs.bin.lzma of=$(VMLINUX)-initramfs.lzma bs=65536 conv=sync
- dd if=$(KDIR)/vmlinux-initramfs.bin.gz of=$(VMLINUX)-initramfs.gz bs=65536 conv=sync
- $(call MkuImage,gzip,,$(KDIR)/vmlinux-initramfs.bin.gz,$(UIMAGE)-initramfs-gzip.bin)
- $(call MkuImage,lzma,,$(KDIR)/vmlinux-initramfs.bin.lzma,$(UIMAGE)-initramfs-lzma.bin)
- cp $(KDIR)/loader-generic-initramfs.elf $(VMLINUX)-initramfs-lzma.elf
- $(call Image/Build/Initramfs)
-endef
-
-Image/Build/WRT400N/buildkernel=$(call MkuImageLzma,$(2),$(3))
-
-define Image/Build/WRT400N
- $(call Sysupgrade/KRuImage,$(1),$(2),1310720,6488064)
- if [ -e "$(call sysupname,$(1),$(2))" ]; then \
- wrt400n $(KDIR_TMP)/vmlinux-$(2).uImage $(KDIR)/root.$(1) $(call factoryname,$(1),$(2)); \
- fi
-endef
-
-
-define Image/Build/CameoAP94/buildkernel
- $(call MkuImageLzma,$(2),$(3) $(4))
- $(call MkuImageLzma,$(2)-fat,$(3) $(5))
-endef
-
-define Image/Build/CameoAP94
- $(eval fwsize=$(call mtdpartsize,firmware,$(4)))
- $(eval fwsize_fat=$(call mtdpartsize,firmware,$(5)))
- $(call Sysupgrade/KRuImage,$(1),$(2),0,$$$$(($(fwsize)-4*64*1024)),64)
- if [ -e "$(call sysupname,$(1),$(2))" ]; then \
- ( \
- dd if=$(call sysupname,$(1),$(2)); \
- echo -n "$(6)"; \
- ) > $(call imgname,$(1),$(2))-backup-loader.bin; \
- if [ `stat -c%s $(call sysupname,$(1),$(2))` -gt 4194304 ]; then \
- echo "Warning: $(call sysupname,$(1),$(2)) is too big" >&2; \
- else \
- ( \
- dd if=$(call sysupname,$(1),$(2)) bs=4096k conv=sync; \
- echo -n "$(7)"; \
- ) > $(call factoryname,$(1),$(2)); \
- fi; \
- fi
- $(call CatFiles,$(KDIR_TMP)/vmlinux-$(2)-fat.uImage,0,$(KDIR)/root.$(1),$$$$(($(fwsize_fat)-4*64*1024)),$(KDIR_TMP)/$(2)-fat.bin,64)
- if [ -e "$(KDIR_TMP)/$(2)-fat.bin" ]; then \
- echo -n "" > $(KDIR_TMP)/$(2)-fat.dummy; \
- sh $(TOPDIR)/scripts/combined-image.sh \
- "$(KDIR_TMP)/$(2)-fat.bin" \
- "$(KDIR_TMP)/$(2)-fat.dummy" \
- $(call sysupname,$(1),$(2)-fat); \
- fi
-endef
-
-define Image/Build/WZRHP
- $(call Sysupgrade/KRuImage,$(1),$(2),0,$$$$(($(3)-4*$(4)*1024)),$(4))
- if [ -e "$(call sysupname,$(1),$(2))" ]; then \
- ( \
- echo -n -e "# Airstation Public Fmt1\x00\x00\x00\x00\x00\x00\x00\x00"; \
- dd if=$(call sysupname,$(1),$(2)); \
- ) > $(call imgname,$(1),$(2))-tftp.bin; \
- buffalo-enc -p $(5) -v 1.99 \
- -i $(call sysupname,$(1),$(2)) \
- -o $(KDIR_TMP)/$(2).enc; \
- buffalo-tag -b $(5) -p $(5) -a ath -v 1.99 -m 1.01 -l mlang8 \
- -w 3 -c 0x80041000 -d 0x801e8000 -f 1 -r M_ \
- -i $(KDIR_TMP)/$(2).enc \
- -o $(call factoryname,$(1),$(2)); \
- fi
-endef
-
-Image/Build/WZRHP64K/buildkernel=$(call MkuImageLzma,$(2),$(3))
-Image/Build/WZRHP64K/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
-Image/Build/WZRHP64K=$(call Image/Build/WZRHP,$(1),$(2),33095680,64,$(4))
-
-Image/Build/WZRHP128K/buildkernel=$(call MkuImageLzma,$(2),$(3))
-Image/Build/WZRHP128K/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
-Image/Build/WZRHP128K=$(call Image/Build/WZRHP,$(1),$(2),33030144,128,$(4))
-
-
-Image/Build/WHRHPG300N/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4))
-Image/Build/WHRHPG300N/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
-
-define Image/Build/WHRHPG300N
- $(eval fwsize=$(call mtdpartsize,firmware,$(4)))
- $(call Sysupgrade/KRuImage,$(1),$(2),0,$$$$(($(fwsize)-4*64*1024)),64)
- if [ -e "$(call sysupname,$(1),$(2))" ]; then \
- ( \
- echo -n -e "# Airstation Public Fmt1\x00\x00\x00\x00\x00\x00\x00\x00"; \
- dd if=$(call sysupname,$(1),$(2)); \
- ) > $(call imgname,$(1),$(2))-tftp.bin; \
- buffalo-enc -p $(5) -v 1.99 \
- -i $(call sysupname,$(1),$(2)) \
- -o $(KDIR_TMP)/$(2).enc; \
- buffalo-tag -b $(5) -p $(5) -a ath -v 1.99 -m 1.01 -l mlang8 \
- -w 3 -c 0x80041000 -d 0x801e8000 -f 1 -r M_ \
- -i $(KDIR_TMP)/$(2).enc \
- -o $(call factoryname,$(1),$(2)); \
- fi
-endef
-
-
-define Image/Build/Cameo
- $(eval fwsize=$(call mtdpartsize,firmware,$(4)))
- $(call Sysupgrade/KRuImage,$(1),$(2),0,$$$$(($(fwsize)-4*64*1024)),64)
- if [ -e "$(call sysupname,$(1),$(2))" ]; then \
- factory_size=$$$$(($(fwsize) - $(6))); \
- ( \
- dd if=$(call sysupname,$(1),$(2)) bs=$$$${factory_size} conv=sync; \
- echo -n $(5); \
- ) > $(call factoryname,$(1),$(2)); \
- fi
-endef
-
-Image/Build/CameoAP81/buildkernel=$(call MkuImageLzma,$(2),$(3) $(cameo_ap81_mtdlayout))
-Image/Build/CameoAP81=$(call Image/Build/Cameo,$(1),$(2),$(3),$(cameo_ap81_mtdlayout),$(4),65536)
-Image/Build/CameoAP81/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(cameo_ap81_mtdlayout))
-
-Image/Build/CameoAP91/buildkernel=$(call MkuImageLzma,$(2),$(3) $(cameo_ap91_mtdlayout))
-Image/Build/CameoAP91=$(call Image/Build/Cameo,$(1),$(2),$(3),$(cameo_ap91_mtdlayout),$(4),65536)
-Image/Build/CameoAP91/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(cameo_ap91_mtdlayout))
-
-Image/Build/CameoAP99/buildkernel=$(call MkuImageLzma,$(2),$(3) $(cameo_ap99_mtdlayout))
-Image/Build/CameoAP99=$(call Image/Build/Cameo,$(1),$(2),$(3),$(cameo_ap99_mtdlayout),$(4),65536)
-Image/Build/CameoAP99/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(cameo_ap99_mtdlayout))
-
-Image/Build/CameoAP123_4M/buildkernel=$(call MkuImageLzma,$(2),$(3) $(cameo_ap123_mtdlayout_4M))
-Image/Build/CameoAP123_4M=$(call Image/Build/Cameo,$(1),$(2),$(3),$(cameo_ap123_mtdlayout_4M),$(4),26)
-Image/Build/CameoAP123_4M/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(cameo_ap123_mtdlayout_4M))
-
-Image/Build/CameoAP135/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4))
-Image/Build/CameoAP135=$(call Image/Build/Cameo,$(1),$(2),$(3),$(4),$(5),26)
-Image/Build/CameoAP135/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
-
-Image/Build/CameoDB120/buildkernel=$(call MkuImageLzma,$(2),$(3) $(cameo_db120_mtdlayout))
-Image/Build/CameoDB120=$(call Image/Build/Cameo,$(1),$(2),$(3),$(cameo_db120_mtdlayout),$(4),26)
-Image/Build/CameoDB120/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(cameo_db120_mtdlayout))
-
-Image/Build/CameoDB120_8M/buildkernel=$(call MkuImageLzma,$(2),$(3) $(cameo_db120_mtdlayout_8M))
-Image/Build/CameoDB120_8M=$(call Image/Build/Cameo,$(1),$(2),$(3),$(cameo_db120_mtdlayout_8M),$(4),26)
-Image/Build/CameoDB120_8M/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(cameo_db120_mtdlayout_8M))
-
-define Image/Build/CameoHornet
- $(eval fwsize=$(call mtdpartsize,firmware,$(4)))
- $(call Sysupgrade/KRuImage,$(1),$(2),0,$$$$(($(fwsize)-4*64*1024)),64)
- if [ -e "$(call sysupname,$(1),$(2))" ]; then \
- for r in $(7); do \
- [ -n "$$$$r" ] && dashr="-$$$$r" || dashr=; \
- [ -z "$$$$r" ] && r="DEF"; \
- mkcameofw -M HORNET -R "$$$$r" -S $(5) -V $(6) -c \
- -K $(8) -I $(fwsize) \
- -k "$(call sysupname,$(1),$(2))" \
- -o $(call imgname,$(1),$(2))-factory$$$$dashr.bin; \
- true; \
- done; \
- fi
-endef
-
-Image/Build/CameoAP121/buildkernel=$(call MkuImageLzma,$(2),$(3) $(cameo_ap121_mtdlayout))
-Image/Build/CameoAP121=$(call Image/Build/CameoHornet,$(1),$(2),$(3),$(cameo_ap121_mtdlayout),$(4),$(5),$(6),0xe0000)
-Image/Build/CameoAP121/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(cameo_ap121_mtdlayout))
-
-Image/Build/CameoAP121_8M/buildkernel=$(call MkuImageLzma,$(2),$(3) $(cameo_ap121_mtdlayout_8M))
-Image/Build/CameoAP121_8M=$(call Image/Build/CameoHornet,$(1),$(2),$(3),$(cameo_ap121_mtdlayout_8M),$(4),$(5),$(6),0x100000)
-Image/Build/CameoAP121_8M/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(cameo_ap121_mtdlayout_8M))
-
-define Image/Build/dLAN
- $(eval fwsize=$(call mtdpartsize,firmware,$(4)))
- $(eval rootsize=$(call mtdpartsize,rootfs,$(4)))
- $(eval kernsize=$(call mtdpartsize,kernel,$(4)))
- $(call Sysupgrade/$(5),$(1),$(2),$(if $(6),$(6),$(kernsize)),$(if $(rootsize),$(rootsize),$(fwsize)))
- if [ -e "$(call factoryname,$(1),$(2))" ]; then \
- dd if=$(KDIR_TMP)/vmlinux-$(2).uImage \
- of=$(call imgname,kernel,$(2)).bin bs=64k conv=sync; \
- dd if=$(KDIR)/root.$(1) \
- of=$(call imgname,$(1),$(2)-rootfs).bin bs=128k conv=sync; \
- fi
-endef
-
-Image/Build/dLANLzma/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4))
-Image/Build/dLANLzma=$(call Image/Build/dLAN,$(1),$(2),$(3),$(4),$(5),$(6),$(7))
-Image/Build/dLANLzma/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
-
-define Image/Build/Ath
- $(eval fwsize=$(call mtdpartsize,firmware,$(4)))
- $(eval rootsize=$(call mtdpartsize,rootfs,$(4)))
- $(eval kernsize=$(call mtdpartsize,kernel,$(4)))
- $(call Sysupgrade/$(5),$(1),$(2),$(if $(6),$(6),$(kernsize)),$(if $(rootsize),$(rootsize),$(fwsize)))
- if [ -e "$(call sysupname,$(1),$(2))" ]; then \
- dd if=$(KDIR_TMP)/vmlinux-$(2).uImage \
- of=$(call imgname,kernel,$(2)).bin bs=64k conv=sync; \
- dd if=$(KDIR)/root.$(1) \
- of=$(call imgname,$(1),$(2)-rootfs).bin bs=128k conv=sync; \
- fi
-endef
-
-Image/Build/AthGzip/buildkernel=$(call MkuImageGzip,$(2),$(3) $(4))
-Image/Build/AthGzip=$(call Image/Build/Ath,$(1),$(2),$(3),$(4),$(5),$(6),$(7))
-Image/Build/AthGzip/initramfs=$(call MkuImageGzip/initramfs,$(2),$(3) $(4))
-
-Image/Build/AthLzma/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4))
-Image/Build/AthLzma=$(call Image/Build/Ath,$(1),$(2),$(3),$(4),$(5),$(6),$(7))
-Image/Build/AthLzma/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
-
-
-Image/Build/Belkin/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4))
-Image/Build/Belkin/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
-
-define Image/Build/Belkin
- $(eval fwsize=$(call mtdpartsize,firmware,$(4)))
- $(eval kernsize=$(call mtdpartsize,kernel,$(4)))
- $(eval rootsize=$(call mtdpartsize,rootfs,$(4)))
- $(call Sysupgrade/RKuImage,$(1),$(2),$(kernsize),$(rootsize))
- if [ -e "$(call sysupname,$(1),$(2))" ]; then \
- edimax_fw_header -m $(5) -v "OpenWrt$(REVISION)" \
- -n "uImage" \
- -i $(KDIR_TMP)/vmlinux-$(2).uImage \
- -o $(KDIR_TMP)/$(2)-uImage; \
- edimax_fw_header -m $(5) -v "OpenWrt$(REVISION)" \
- -n "rootfs" \
- -i $(KDIR)/root.$(1) \
- -o $(KDIR_TMP)/$(2)-rootfs; \
- ( \
- dd if=$(KDIR_TMP)/$(2)-rootfs; \
- dd if=$(KDIR_TMP)/$(2)-uImage; \
- ) > "$(call factoryname,$(1),$(2))"; \
- fi
-endef
-
-define Image/Build/EnGenius
- $(eval fwsize=$(call mtdpartsize,firmware,$(4)))
- $(eval rootsize=$(call mtdpartsize,rootfs,$(4)))
- $(eval kernsize=$(call mtdpartsize,kernel,$(4)))
- $(call Sysupgrade/$(5),$(1),$(2),$(if $(6),$(6),$(kernsize)),$(if $(rootsize),$(rootsize),$(fwsize)))
- if [ -e "$(call sysupname,$(1),$(2))" ]; then \
- dd if=$(KDIR_TMP)/vmlinux-$(2).uImage \
- of=$(call imgname,kernel,$(2)).bin bs=64k conv=sync; \
- dd if=$(KDIR)/root.$(1) \
- of=$(call imgname,$(1),$(2)-rootfs).bin bs=128k conv=sync; \
- mksenaofw -e $(call sysupname,$(1),$(2)) \
- -o $(call imgname,$(1),$(2))-factory.dlf \
- -r 0x101 -p $(7) -t 2; \
- fi
-endef
-
-Image/Build/EnGenius/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4))
-Image/Build/EnGenius/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
-
-
-define MkuImageHiWiFi
- # Field ih_name needs to start with "tw150v1"
- mkimage -A mips -O linux -T kernel -a 0x80060000 -C $(1) $(2) \
- -e 0x80060000 -n 'tw150v1 MIPS OpenWrt Linux-$(LINUX_VERSION)' \
- -d $(3) $(4)
-endef
-
-define MkuImageLzmaHiWiFi
- $(call PatchKernelLzma,$(1),$(2),$(3),$(4))
- $(call MkuImageHiWiFi,lzma,$(5),$(KDIR_TMP)/vmlinux$(4)-$(1).bin.lzma,$(KDIR_TMP)/vmlinux$(4)-$(1).uImage)
-endef
-
-Image/Build/HiWiFi/buildkernel=$(call MkuImageLzmaHiWiFi,$(2),$(3) $(4))
-Image/Build/HiWiFi=$(call Image/Build/Ath,$(1),$(2),$(3),$(4),$(5),$(6),$(7))
-Image/Build/HiWiFi/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
-
-Image/Build/PB4X/buildkernel=$(call PatchKernelLzma,$(2),$(3))
-
-define Image/Build/PB4X
- dd if=$(KDIR_TMP)/vmlinux-$(2).bin.lzma \
- of=$(call imgname,kernel,$(2)).bin bs=64k conv=sync
- dd if=$(KDIR)/root.$(1) \
- of=$(call imgname,$(1),$(2)-rootfs).bin bs=128k conv=sync
- -sh $(TOPDIR)/scripts/combined-image.sh \
- "$(call imgname,kernel,$(2)).bin" \
- "$(call imgname,$(1),$(2)-rootfs).bin" \
- $(call sysupname,$(1),$(2))
-endef
-
-
-Image/Build/MyLoader/buildkernel=$(call PatchKernelLzma,$(2),$(3))
-Image/Build/MyLoader/initramfs=$(call PatchKernel/initramfs,$(2),$(3))
-
-define Image/Build/MyLoader
- $(eval fwsize=$(shell echo $$(($(4)-0x30000-4*64*1024))))
- $(eval fwimage=$(KDIR_TMP)/$(2)-$(5)-firmware.bin)
- $(call CatFiles,$(KDIR_TMP)/vmlinux-$(2).bin.lzma,65536,$(KDIR)/root.$(1),$(fwsize),$(fwimage))
- if [ -e "$(fwimage)" ]; then \
- $(STAGING_DIR_HOST)/bin/mkmylofw -B $(2) -s $(4) -v \
- -p0x00030000:0:al:0x80060000:firmware:$(fwimage) \
- $(call imgname,$(1),$(2))-$(5)-factory.img; \
- echo -n "" > $(KDIR_TMP)/empty.bin; \
- sh $(TOPDIR)/scripts/combined-image.sh \
- $(fwimage) $(KDIR_TMP)/empty.bin \
- $(call imgname,$(1),$(2))-$(5)-sysupgrade.bin; \
- fi
-endef
-
-Image/Build/Planex/initramfs=$(call MkuImageGzip/initramfs,$(2),$(3) $(planex_mtdlayout))
-Image/Build/Planex/loader=$(call Image/BuildLoaderAlone,$(1),gz,$(2) $(planex_mtdlayout),0x52000,0)
-
-define Image/Build/Planex/buildkernel
- [ -e "$(KDIR)/loader-$(2).gz" ]
- $(call MkuImageOKLI,$(2))
- ( \
- dd if=$(KDIR)/loader-$(2).gz bs=8128 count=1 conv=sync; \
- dd if=$(KDIR_TMP)/vmlinux-$(2).okli; \
- ) > $(KDIR_TMP)/kernel-$(2).bin
- $(call MkuImage,gzip,,$(KDIR_TMP)/kernel-$(2).bin,$(KDIR_TMP)/vmlinux-$(2).uImage)
-endef
-
-define Image/Build/Planex
- $(eval fwsize=$(call mtdpartsize,firmware,$(planex_mtdlayout)))
- $(call Sysupgrade/KRuImage,$(1),$(2),0,$$$$(($(fwsize)-4*64*1024)),64)
- if [ -e "$(call sysupname,$(1),$(2))" ]; then \
- $(STAGING_DIR_HOST)/bin/mkplanexfw \
- -B $(2) \
- -v 2.00.00 \
- -i $(call sysupname,$(1),$(2)) \
- -o $(call factoryname,$(1),$(2)); \
- fi
-endef
-
-
-Image/Build/ALFA/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4))
-Image/Build/ALFA/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
-
-define Image/Build/ALFA
- $(call Sysupgrade/RKuImage,$(1),$(2),$(5),$(6))
- if [ -e "$(call sysupname,$(1),$(2))" ]; then \
- rm -rf $(KDIR)/$(1); \
- mkdir -p $(KDIR)/$(1); \
- cd $(KDIR)/$(1); \
- cp $(KDIR_TMP)/vmlinux-$(2).uImage $(KDIR)/$(1)/$(7); \
- cp $(KDIR)/root.$(1) $(KDIR)/$(1)/$(8); \
- $(TAR) zcf $(call factoryname,$(1),$(2)) -C $(KDIR)/$(1) $(7) $(8); \
- ( \
- echo WRM7222C | dd bs=32 count=1 conv=sync; \
- echo -ne '\xfe'; \
- ) >> $(call factoryname,$(1),$(2)); \
- fi
-endef
-
-
-Image/Build/Seama/loader=$(call Image/BuildLoader,$(1),bin,$(2) $(3),0x80060000)
-
-define Image/Build/Seama
- [ -e "$(KDIR)/loader-$(2).bin" ]
- $(call CompressLzma,$(KDIR)/loader-$(2).bin,$(KDIR_TMP)/loader-$(2).bin.lzma)
- -rm -f $(KDIR_TMP)/image-$(2).tmp
- $(call CatFiles,$(KDIR_TMP)/loader-$(2).bin.lzma,$$$$(($(6) - 64)),$(KDIR)/root.$(1),$(7),$(KDIR_TMP)/image-$(2).tmp)
- [ -e "$(KDIR_TMP)/image-$(2).tmp" ] && { \
- head -c -4 "$(KDIR_TMP)/image-$(2).tmp" > "$(KDIR_TMP)/image-$(2).no-jffs2mark.tmp"; \
- $(STAGING_DIR_HOST)/bin/seama \
- -i $(KDIR_TMP)/image-$(2).no-jffs2mark.tmp \
- -m "dev=/dev/mtdblock/1" -m "type=firmware"; \
- $(STAGING_DIR_HOST)/bin/seama \
- -s $(call imgname,$(1),$(2))-factory.bin \
- -m "signature=$(5)" \
- -i $(KDIR_TMP)/image-$(2).no-jffs2mark.tmp.seama; \
- tail -c 4 "$(KDIR_TMP)/image-$(2).tmp" >> $(call imgname,$(1),$(2))-factory.bin; \
- }
- cat $(KDIR_TMP)/loader-$(2).bin.lzma > $(KDIR_TMP)/image-$(2)-sysupgrade.tmp
- $(STAGING_DIR_HOST)/bin/seama \
- -i $(KDIR_TMP)/image-$(2)-sysupgrade.tmp \
- -m "dev=/dev/mtdblock/1" -m "type=firmware"
- $(call CatFiles,$(KDIR_TMP)/image-$(2)-sysupgrade.tmp.seama,$(6),$(KDIR)/root.$(1),$(7),$(call sysupname,$(1),$(2)))
-endef
-
-define Image/Build/Seama/initramfs
- $(call PatchKernelLzma,$(2),$(3) $(4),,-initramfs)
- $(STAGING_DIR_HOST)/bin/seama \
- -i $(KDIR_TMP)/vmlinux-initramfs-$(2).bin.lzma \
- -m "dev=/dev/mtdblock/1" -m "type=firmware"
- cat $(KDIR_TMP)/vmlinux-initramfs-$(2).bin.lzma.seama > $(call imgname,initramfs,$(2))-seama.bin
-endef
-
-Image/Build/Senao/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4))
-Image/Build/Senao/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
-
-define Image/Build/Senao
- mkdir -p $(KDIR_TMP)/$(2)/
- touch $(KDIR_TMP)/$(2)/FWINFO-OpenWrt-$(REVISION)-$(2)
- -$(CP) ./$(2)/* $(KDIR_TMP)/$(2)/
- dd if=$(KDIR_TMP)/vmlinux-$(2).uImage \
- of=$(KDIR_TMP)/$(2)/openwrt-senao-$(2)-uImage-lzma.bin bs=64k conv=sync
- dd if=$(KDIR)/root.$(1) \
- of=$(KDIR_TMP)/$(2)/openwrt-senao-$(2)-root.$(1) bs=64k conv=sync
- ( \
- cd $(KDIR_TMP)/$(2)/; \
- $(TAR) -cz -f $(call factoryname,$(1),$(2)) * \
- )
- -rm -rf $(KDIR_TMP)/$(2)/
- -sh $(TOPDIR)/scripts/combined-image.sh \
- $(KDIR_TMP)/vmlinux-$(2).uImage \
- $(KDIR)/root.$(1) \
- $(call sysupname,$(1),$(2))
-endef
-
-define Image/Build/CyberTAN
- echo -n '' > $(KDIR_TMP)/empty.bin
- $(STAGING_DIR_HOST)/bin/trx -o $(KDIR)/image.tmp \
- -f $(KDIR_TMP)/vmlinux-$(2).uImage -F $(KDIR_TMP)/empty.bin \
- -x 32 -a 0x10000 -x -32 -f $(KDIR)/root.$(1)
- -$(STAGING_DIR_HOST)/bin/addpattern -B $(2) -v v$(5) \
- -i $(KDIR)/image.tmp \
- -o $(call sysupname,$(1),$(2))
- $(STAGING_DIR_HOST)/bin/trx -o $(KDIR)/image.tmp -f $(KDIR_TMP)/vmlinux-$(2).uImage \
- -x 32 -a 0x10000 -x -32 -f $(KDIR)/root.$(1)
- -$(STAGING_DIR_HOST)/bin/addpattern -B $(2) -v v$(5) -g \
- -i $(KDIR)/image.tmp \
- -o $(call factoryname,$(1),$(2))
- rm $(KDIR)/image.tmp
-endef
-
-Image/Build/CyberTANGZIP/loader=$(call Image/BuildLoader,$(1),gz,$(2),0x80060000)
-Image/Build/CyberTANGZIP/buildkernel=$(call MkuImage,gzip,,$(KDIR)/loader-$(2).gz,$(KDIR_TMP)/vmlinux-$(2).uImage)
-Image/Build/CyberTANGZIP=$(call Image/Build/CyberTAN,$(1),$(2),$(3),$(4),$(5))
-
-Image/Build/CyberTANLZMA/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4))
-Image/Build/CyberTANLZMA=$(call Image/Build/CyberTAN,$(1),$(2),$(3),$(4),$(5))
-
-
-define Build/MerakiNAND
- -$(STAGING_DIR_HOST)/bin/mkmerakifw \
- -B $(BOARDNAME) -s \
- -i $@ \
- -o $@.new
- @mv $@.new $@
-endef
-
-Image/Build/Netgear/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4),,-M $(5))
-
-define Image/Build/Netgear/buildkernel
- $(call MkuImageLzma,$(2),$(3) $(4),-d20,,-M $(5))
- -rm -rf $(KDIR_TMP)/$(2)
- mkdir -p $(KDIR_TMP)/$(2)/image
- cat $(KDIR_TMP)/vmlinux-$(2).uImage > $(KDIR_TMP)/$(2)/image/uImage
- $(STAGING_DIR_HOST)/bin/mksquashfs-lzma \
- $(KDIR_TMP)/$(2) $(KDIR_TMP)/vmlinux-$(2).uImage.squashfs.tmp1 \
- -noappend -root-owned -be -b 65536 \
- $(if $(SOURCE_DATE_EPOCH),-fixed-time $(SOURCE_DATE_EPOCH))
- ( \
- cat $(KDIR_TMP)/vmlinux-$(2).uImage.squashfs.tmp1; \
- dd if=/dev/zero bs=1k count=1 \
- ) > $(KDIR_TMP)/vmlinux-$(2).uImage.squashfs.tmp2
- mkimage -A mips -O linux -T filesystem -C none -M $(5) \
- -a 0xbf070000 -e 0xbf070000 \
- -n 'MIPS OpenWrt Linux-$(LINUX_VERSION)' \
- -d $(KDIR_TMP)/vmlinux-$(2).uImage.squashfs.tmp2 \
- $(KDIR_TMP)/vmlinux-$(2).uImage.squashfs
-endef
-
-define Image/Build/Netgear
- $(eval fwsize=$(call mtdpartsize,firmware,$(4)))
- $(call CatFiles,$(KDIR_TMP)/vmlinux-$(2).uImage.squashfs,0,$(KDIR)/root.$(1),$(fwsize),$(call sysupname,$(1),$(2)),64)
- if [ -e $(call sysupname,$(1),$(2)) ]; then \
- for r in $(7) ; do \
- [ -n "$$$$r" ] && dashr="-$$$$r" || dashr= ; \
- $(STAGING_DIR_HOST)/bin/mkdniimg \
- -B $(6) -v OpenWrt.$(REVISION) -r "$$$$r" $(8) \
- -i $(call sysupname,$(1),$(2)) \
- -o $(call imgname,$(1),$(2))-factory$$$$dashr.img; \
- done; \
- fi
-endef
-
-
-Image/Build/NetgearLzma/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4),,-M $(5))
-Image/Build/NetgearLzma/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4),-d20,,-M $(5))
-
-define Image/Build/NetgearLzma
- $(eval fwsize=$(call mtdpartsize,firmware,$(4)))
- $(call CatFiles,$(KDIR_TMP)/vmlinux-$(2).uImage,0,$(KDIR)/root.$(1),$(fwsize),$(call sysupname,$(1),$(2)),64)
-endef
-
-
-Image/Build/NetgearNAND/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4),,-M $(5))
-
-# $(1): (empty)
-# $(2): Board name (small caps)
-# $(3): Kernel board specific cmdline
-# $(4): Kernel mtdparts definition
-# $(5): U-Boot magic
-define Image/Build/NetgearNAND/buildkernel
- $(eval kernelsize=$(call mtdpartsize,kernel,$(4)))
- $(call PatchKernelLzma,$(2),$(3) $(4),-d20)
- dd if=$(KDIR_TMP)/vmlinux-$(2).bin.lzma \
- of=$(KDIR_TMP)/vmlinux-$(2).bin.tmp \
- bs=$$$$(($(kernelsize)-131072-2*64-1)) \
- count=1 conv=sync
- $(call MkuImage,lzma,-M $(5),$(KDIR_TMP)/vmlinux-$(2).bin.tmp,$(KDIR_TMP)/vmlinux-$(2).uImage)
- echo -ne '\xff' >> $(KDIR_TMP)/vmlinux-$(2).uImage
- # create a fake rootfs image
- dd if=/dev/zero of=$(KDIR_TMP)/fakeroot-$(2) bs=131072 count=1
- mkimage -A mips -O linux -T filesystem -C none \
- -a 0xbf070000 -e 0xbf070000 \
- -n 'MIPS OpenWrt fakeroot' \
- -d $(KDIR_TMP)/fakeroot-$(2) \
- -M $(5) \
- $(KDIR_TMP)/fakeroot-$(2).uImage
- # append the fake rootfs image to the kernel, it will reside in the last
- # erase block of the kernel partition
- cat $(KDIR_TMP)/fakeroot-$(2).uImage >> $(KDIR_TMP)/vmlinux-$(2).uImage
-endef
-
-
-# $(1): rootfs image suffix
-# $(2): Board name (small caps)
-# $(3): Kernel board specific cmdline
-# $(4): Kernel mtdparts definition
-# $(5): U-Boot magic
-# $(6): Board name (upper caps)
-# $(7): firmware region code (not used yet)
-# $(8): DNI Hardware version
-# $(9): suffix of the configuration file for ubinize
-define Image/Build/NetgearNAND
- $(eval firmwaresize=$(call mtdpartsize,firmware,$(4)))
- $(eval kernelsize=$(call mtdpartsize,kernel,$(4)))
- $(eval imageraw=$(KDIR_TMP)/$(2)-raw.img)
- $(CP) $(KDIR)/root.squashfs-raw $(KDIR_TMP)/root.squashfs
- echo -ne '\xde\xad\xc0\xde' > $(KDIR_TMP)/jffs2.eof
- $(call ubinize,ubinize-$(9).ini,$(KDIR_TMP),$(KDIR_TMP)/$(2)-root.ubi,128KiB,2048,-E 5)
- ( \
- dd if=$(KDIR_TMP)/vmlinux-$(2).uImage; \
- dd if=$(KDIR_TMP)/$(2)-root.ubi \
- ) > $(imageraw)
- $(STAGING_DIR_HOST)/bin/mkdniimg \
- -B $(6) -v OpenWrt.$(REVISION) -r "$$$$r" $(8) \
- -i $(imageraw) \
- -o $(call imgname,ubi,$(2))-factory.img
-
- $(call Image/Build/SysupgradeNAND,$(2),squashfs,$(KDIR_TMP)/vmlinux-$(2).uImage)
-endef
-
-
-ifdef CONFIG_PACKAGE_uboot-ar71xx-nbg460n_550n_550nh
- Image/Build/ZyXEL/buildkernel=$(call MkuImageLzma,$(2),$(3))
-
- define Image/Build/ZyXEL
- $(call Sysupgrade/KRuImage,$(1),$(2),917504,2752512)
- if [ -e "$(call sysupname,$(1),$(2))" ]; then \
- if [ ! -f $(BIN_DIR)/$(IMG_PREFIX)-$(2)-u-boot.bin ]; then \
- echo "Warning: $(IMG_PREFIX)-$(2)-u-boot.bin not found" >&2; \
- else \
- $(STAGING_DIR_HOST)/bin/mkzynfw \
- -B $(4) \
- -b $(BIN_DIR)/$(IMG_PREFIX)-$(2)-u-boot.bin \
- -r $(call sysupname,$(1),$(2)):0x10000 \
- -o $(call factoryname,$(1),$(2)); \
- fi; fi
- endef
-endif
-
-define Device/NBG6616
- BOARDNAME = NBG6616
- KERNEL_SIZE = 2048k
- IMAGE_SIZE = 15323k
- MTDPARTS = spi0.0:192k(u-boot)ro,64k(env)ro,64k(RFdata)ro,384k(zyxel_rfsd),384k(romd),64k(header),2048k(kernel),13184k(rootfs),15232k@0x120000(firmware)
- CMDLINE += mem=128M
- IMAGES := sysupgrade.bin
- KERNEL := kernel-bin | patch-cmdline | lzma | uImage lzma | jffs2 boot/vmlinux.lzma.uImage
- IMAGE/sysupgrade.bin = append-kernel $$$$(KERNEL_SIZE) | append-rootfs | pad-rootfs | check-size $$$$(IMAGE_SIZE)
- # We cannot currently build a factory image. It is the sysupgrade image
- # prefixed with a header (which is actually written into the MTD device).
- # The header is 2kiB and is filled with 0xff. The format seems to be:
- # 2 bytes: 0x0000
- # 2 bytes: checksum of the data partition (big endian)
- # 4 bytes: length of the contained image file (big endian)
- # 32 bytes: Firmware Version string (NUL terminated, 0xff padded)
- # 2 bytes: 0x0000
- # 2 bytes: checksum over the header partition (big endian)
- # 32 bytes: Model (e.g. "NBG6616", NUL termiated, 0xff padded)
- # rest: 0xff padding
- #
- # The checksums are calculated by adding up all bytes and if a 16bit
- # overflow occurs, one is added and the sum is masked to 16 bit:
- # csum = csum + databyte; if (csum > 0xffff) { csum += 1; csum &= 0xffff };
- # Should the file have an odd number of bytes then the byte len-0x800 is
- # used additionally.
- # The checksum for the header is calcualted over the first 2048 bytes with
- # the firmware checksum as the placeholder during calculation.
- #
- # The header is padded with 0xff to the erase block size of the device.
-endef
-
-TARGET_DEVICES += NBG6616
-
-define Image/Build/ZyXELNAND/buildkernel
- $(eval kernelsize=$(call mtdpartsize,kernel,$(5)))
- $(call MkuImageLzma,$(2),$(3) $(5) $(6))
- mkdir -p $(KDIR_TMP)/$(2)/image/boot
- cp $(KDIR_TMP)/vmlinux-$(2).uImage $(KDIR_TMP)/$(2)/image/boot/vmlinux.lzma.uImage
- $(STAGING_DIR_HOST)/bin/mkfs.jffs2 \
- --pad=$(kernelsize) --big-endian --squash-uids -v -e 128KiB \
- -o $(KDIR_TMP)/$(2)-kernel.jffs2 \
- -d $(KDIR_TMP)/$(2)/image \
- 2>&1 1>/dev/null | awk '/^.+$$$$/'
- -rm -rf $(KDIR_TMP)/$(2)
-endef
-
-define Image/Build/ZyXELNAND
- if [ "$(1)" != "squashfs" ]; then \
- echo Only squashfs is supported; \
- return 0; \
- fi
- $(eval firmwaresize=$(call mtdpartsize,firmware,$(4)))
- $(eval kernelsize=$(call mtdpartsize,kernel,$(4)))
- $(eval imageraw=$(KDIR_TMP)/$(2)-raw.img)
- $(CP) $(KDIR)/root.$(1) $(KDIR_TMP)/ubi_root.img
- $(call ubinize,ubinize-$(2).ini,$(KDIR_TMP),$(KDIR_TMP)/$(2)-root.ubi,128KiB,2048,-E 5)
- ( \
- dd if=$(KDIR_TMP)/$(2)-kernel.jffs2; \
- dd if=$(KDIR_TMP)/$(2)-root.ubi \
- ) > $(imageraw)
- dd if=$(imageraw) of=$(BIN_DIR)/$(IMG_PREFIX)-$(2)-$(1)-factory.bin \
- bs=128k conv=sync
- $(call Image/Build/SysupgradeNAND,$(2),squashfs,$(KDIR_TMP)/$(2)-kernel.jffs2)
-endef
-
-
-Image/Build/OpenMesh/buildkernel=$(call MkuImageLzma,$(2))
-
-define Image/Build/OpenMesh
- -sh $(TOPDIR)/scripts/om-fwupgradecfg-gen.sh \
- "$(4)" \
- "$(BUILD_DIR)/fwupgrade.cfg-$(4)" \
- "$(KDIR_TMP)/vmlinux-$(2).uImage" \
- "$(KDIR)/root.$(1)"
- -sh $(TOPDIR)/scripts/combined-ext-image.sh \
- "$(4)" "$(call factoryname,$(1),$(2))" \
- "$(BUILD_DIR)/fwupgrade.cfg-$(4)" "fwupgrade.cfg" \
- "$(KDIR_TMP)/vmlinux-$(2).uImage" "kernel" \
- "$(KDIR)/root.$(1)" "rootfs"
-endef
-
-
-Image/Build/Zcomax/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4))
-Image/Build/Zcomax/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
-
-define Image/Build/Zcomax
- $(call Sysupgrade/RKuImage,$(1),$(2),1507328,6356992)
- if [ -e "$(call sysupname,$(1),$(2))" ]; then \
- $(STAGING_DIR_HOST)/bin/mkzcfw \
- -B $(2) \
- -k $(KDIR_TMP)/vmlinux-$(2).uImage \
- -r $(BIN_DIR)/$(IMG_PREFIX)-root.$(1) \
- -o $(call imgname,$(1),$(2))-factory.img; \
- fi
-endef
-
-
-# $(1): template name to be defined, etc. squashfs-only, 64k, 64kraw, etc.
-# $(2): jffs2 blocksize.
-define Jffs2Template
- define Image/Build/Template/$(1)/jffs2-$(2)
- $$(call Image/Build/$$(1),jffs2-$(2),$$(2),$$(3),$$(4),$$(5),$$(6),$$(7),$$(8),$$(9),$$(10))
- endef
-endef
-
-# $(1): template name to be defined.
-# $(2): squashfs suffix to be used.
-# $(3): jffs2 suffix to be used.
-define BuildTemplate
- # $(1) : name of build method.
- # $(2) : board name.
- # $(3) : kernel command line.
- # $(4)~$(8): extra arguments.
- define Image/Build/Template/$(1)/initramfs
- $$(call Image/Build/$$(1)/initramfs,initramfs,$$(2),$$(3),$$(4),$$(5),$$(6),$$(7),$$(8),$$(9),$$(10))
- endef
- define Image/Build/Template/$(1)/loader
- $$(call Image/Build/$$(1)/loader,$$(2),$$(3),$$(4),$$(5),$$(6),$$(7),$$(8),$$(9),$$(10))
- endef
- define Image/Build/Template/$(1)/buildkernel
- $$(call Image/Build/$$(1)/buildkernel,,$$(2),$$(3),$$(4),$$(5),$$(6),$$(7),$$(8),$$(9),$$(10))
- endef
- define Image/Build/Template/$(1)/squashfs
- $$(call Image/Build/$$(1),squashfs$(2),$$(2),$$(3),$$(4),$$(5),$$(6),$$(7),$$(8),$$(9),$$(10))
- endef
- $(if $(3),$(foreach bs,$(3),$(eval $(call Jffs2Template,$(1),$(bs)))))
-endef
-
-$(eval $(call BuildTemplate,squashfs-only))
-$(eval $(call BuildTemplate,64k,-64k,64k))
-$(eval $(call BuildTemplate,64kraw,-raw,64k))
-$(eval $(call BuildTemplate,64kraw-nojffs,-raw))
-$(eval $(call BuildTemplate,128k,,128k))
-$(eval $(call BuildTemplate,128kraw,-raw,128k))
-$(eval $(call BuildTemplate,256k,,256k))
-$(eval $(call BuildTemplate,all,,64k 128k 256k))
-
-ifeq ($(SUBTARGET),generic)
-define Device/c-55
- BOARDNAME = C-55
- KERNEL_SIZE = 2048k
- IMAGE_SIZE = 15872k
- MTDPARTS = spi0.0:256k(u-boot)ro,128k(u-boot-env)ro,2048k(kernel),13824k(rootfs),13824k(opt)ro,2624k(failsafe)ro,64k(art)ro,15872k@0x60000(firmware)
- IMAGE/sysupgrade.bin = append-kernel $$$$(KERNEL_SIZE) | append-rootfs | pad-rootfs | check-size $$$$(IMAGE_SIZE)
-endef
-
-TARGET_DEVICES += c-55
-
-$(eval $(call SingleProfile,ALFA,64k,ALFANX,alfa-nx,ALFA-NX,ttyS0,115200,$$(alfa_mtdlayout_8M),1638400,6291456,vmlinux.gz.uImage,pb9x-2.6.31-jffs2))
-$(eval $(call SingleProfile,ALFA,64k,HORNETUB,hornet-ub,HORNET-UB,ttyATH0,115200,$$(alfa_mtdlayout_8M),1638400,6291456,kernel_image,rootfs_image))
-$(eval $(call SingleProfile,ALFA,64k,TUBE2H8M,tube2h-8M,TUBE2H,ttyATH0,115200,$$(alfa_mtdlayout_8M),1638400,6291456,kernel.image,rootfs.image))
-
-$(eval $(call SingleProfile,AthGzip,64k,AP81,ap81,AP81,ttyS0,115200,$$(ap81_mtdlayout),RKuImage))
-$(eval $(call SingleProfile,AthGzip,64k,AP83,ap83,AP83,ttyS0,115200,$$(ap83_mtdlayout),RKuImage))
-$(eval $(call SingleProfile,AthGzip,64k,AP96,ap96,AP96,ttyS0,115200,$$(ap96_mtdlayout),RKuImage))
-$(eval $(call SingleProfile,AthGzip,64k,WNDAP360,wndap360,WNDAP360,ttyS0,9600,$$(wndap360_mtdlayout),KRuImage))
-
-$(eval $(call SingleProfile,AthLzma,64k,ALFAAP120C,alfa-ap120c,ALFA-AP120C,ttyS0,115200,$$(alfa_ap120c_mtdlayout),RKuImage))
-$(eval $(call SingleProfile,AthLzma,64k,ALFAAP96,alfa-ap96,ALFA-AP96,ttyS0,115200,$$(alfa_ap96_mtdlayout),RKuImage))
-$(eval $(call SingleProfile,AthLzma,64k,ALL0258N,all0258n,ALL0258N,ttyS0,115200,$$(all0258n_mtdlayout),KRuImage,65536))
-$(eval $(call SingleProfile,AthLzma,256k,ALL0315N,all0315n,ALL0315N,ttyS0,115200,$$(all0315n_mtdlayout),KRuImage,262144))
-$(eval $(call SingleProfile,AthLzma,64k,AP113,ap113,AP113,ttyS0,115200,$$(ap113_mtd_layout),RK))
-$(eval $(call SingleProfile,AthLzma,64k,AP121_2M,ap121-2M,AP121,ttyATH0,115200,$$(ap121_mtdlayout_2M),RKuImage))
-$(eval $(call SingleProfile,AthLzma,64k,AP121_4M,ap121-4M,AP121,ttyATH0,115200,$$(ap121_mtdlayout_4M),RKuImage))
-$(eval $(call SingleProfile,AthLzma,64k,AP121_8M,ap121-8M,AP121,ttyATH0,115200,$$(ap121_mtdlayout_8M),RKuImage))
-$(eval $(call SingleProfile,AthLzma,64k,AP121_16M,ap121-16M,AP121,ttyATH0,115200,$$(ap121_mtdlayout_16M),RKuImage))
-$(eval $(call SingleProfile,AthLzma,64k,AP121MINI,ap121-mini,AP121-MINI,ttyATH0,115200,$$(ap121_mtdlayout_4M),RKuImage))
-$(eval $(call SingleProfile,AthLzma,64k,AP132,ap132,AP132,ttyS0,115200,$$(ap132_mtdlayout),KRuImage))
-$(eval $(call SingleProfile,AthLzma,64k,AP135,ap135-020,AP135-020,ttyS0,115200,$$(ap135_mtdlayout),RKuImage))
-$(eval $(call SingleProfile,AthLzma,64k,AP136_010,ap136-010,AP136-010,ttyS0,115200,$$(ap136_mtdlayout),RKuImage))
-$(eval $(call SingleProfile,AthLzma,64k,AP136_020,ap136-020,AP136-020,ttyS0,115200,$$(ap136_mtdlayout),RKuImage))
-$(eval $(call SingleProfile,AthLzma,64k,AP143_8M,ap143-8M,AP143,ttyS0,115200,$$(ap143_mtdlayout_8M),RKuImage))
-$(eval $(call SingleProfile,AthLzma,64k,AP143_16M,ap143-16M,AP143,ttyS0,115200,$$(ap143_mtdlayout_16M),RKuImage))
-$(eval $(call SingleProfile,AthLzma,64k,AP147_010,ap147-010,AP147-010,ttyS0,115200,$$(ap147_mtdlayout),RKuImage))
-$(eval $(call SingleProfile,AthLzma,64k,AP152_16M,ap152-16M,AP152,ttyS0,115200,$$(ap152_mtdlayout_16M),RKuImage))
-$(eval $(call SingleProfile,AthLzma,64k,BXU2000N2,bxu2000n-2-a1,BXU2000n-2-A1,ttyS0,115200,$$(bxu2000n2_mtdlayout),RKuImage))
-$(eval $(call SingleProfile,AthLzma,64k,CAP4200AG,cap4200ag,CAP4200AG,ttyS0,115200,$$(cap4200ag_mtdlayout),KRuImage))
-$(eval $(call SingleProfile,AthLzma,64k,DB120,db120,DB120,ttyS0,115200,$$(db120_mtdlayout),RKuImage))
-$(eval $(call SingleProfile,AthLzma,64k,DRAGINO2,dragino2,DRAGINO2,ttyATH0,115200,$$(dragino2_mtdlayout),KRuImage,65536))
-$(eval $(call SingleProfile,AthLzma,64k,EWDORINAP,ew-dorin,EW-DORIN,ttyATH0,115200,$$(ew-dorin_mtdlayout_4M),KRuImage,65536))
-$(eval $(call SingleProfile,AthLzma,64k,EWDORINRT,ew-dorin-router,EW-DORIN-ROUTER,ttyATH0,115200,$$(ew-dorin_mtdlayout_4M),KRuImage,65536))
-$(eval $(call SingleProfile,AthLzma,64k,EWDORIN16M,ew-dorin-16M,EW-DORIN,ttyATH0,115200,$$(ew-dorin_mtdlayout_16M),KRuImage,65536))
-$(eval $(call SingleProfile,AthLzma,64k,HORNETUBx2,hornet-ub-x2,HORNET-UB,ttyATH0,115200,$$(alfa_mtdlayout_16M),KRuImage,65536))
-$(eval $(call SingleProfile,AthLzma,64k,MR12,mr12,MR12,ttyS0,115200,$$(mr12_mtdlayout),RKuImage))
-$(eval $(call SingleProfile,AthLzma,64k,MR16,mr16,MR16,ttyS0,115200,$$(mr16_mtdlayout),RKuImage))
-$(eval $(call SingleProfile,AthLzma,64k,PB92,pb92,PB92,ttyS0,115200,$$(pb92_mtdlayout),KRuImage))
-$(eval $(call SingleProfile,AthLzma,64k,TUBE2H16M,tube2h-16M,TUBE2H,ttyATH0,115200,$$(alfa_mtdlayout_16M),KRuImage,65536))
-$(eval $(call SingleProfile,AthLzma,64k,WLR8100,wlr8100,WLR8100,ttyS0,115200,$$(wlr8100_mtdlayout),KRuImage))
-$(eval $(call SingleProfile,AthLzma,64k,WPJ342_16M,wpj342-16M,WPJ342,ttyS0,115200,$$(wpj342_mtdlayout_16M),KRuImage,65536))
-$(eval $(call SingleProfile,AthLzma,64k,WPJ344_16M,wpj344-16M,WPJ344,ttyS0,115200,$$(wpj344_mtdlayout_16M),KRuImage,65536))
-$(eval $(call SingleProfile,AthLzma,64k,DR344,dr344,DR344,ttyS0,115200,$$(dr344_mtdlayout),RKuImage))
-$(eval $(call SingleProfile,AthLzma,64k,WPJ531_16M,wpj531-16M,WPJ531,ttyS0,115200,$$(wpj531_mtdlayout_16M),KRuImage,65536))
-$(eval $(call SingleProfile,AthLzma,64k,WPJ558_16M,wpj558-16M,WPJ558,ttyS0,115200,$$(wpj558_mtdlayout_16M),KRuImage,65536))
-$(eval $(call SingleProfile,AthLzma,64k,YUN_8M,yun-8M,Yun,ttyATH0,250000,$$(yun_mtdlayout_8M),RKuImage))
-$(eval $(call SingleProfile,AthLzma,64k,YUN_16M,yun-16M,Yun,ttyATH0,250000,$$(yun_mtdlayout_16M),RKuImage))
-
-$(eval $(call SingleProfile,Belkin,64k,F9K1115V2,f9k1115v2,F9K1115V2,ttyS0,115200,$$(f9k1115v2_mtdlayout),BR-6679BAC))
-
-$(eval $(call SingleProfile,CameoAP91,64kraw,DIR600A1,dir-600-a1,DIR-600-A1,ttyS0,115200,"AP91-AR7240-RT-090223-00"))
-$(eval $(call SingleProfile,CameoAP91,64kraw,DIR601A1,dir-601-a1,DIR-600-A1,ttyS0,115200,"AP91-AR7240-RT-090223-02"))
-$(eval $(call SingleProfile,CameoAP91,64kraw,FR54RTR,fr-54rtr,DIR-600-A1,ttyS0,115200,"AP91-AR7240-RT-090223-01"))
-
-$(eval $(call SingleProfile,CameoAP99,64kraw,DIR615E1,dir-615-e1,DIR-615-E1,ttyS0,115200,"AP93-AR7240-RT-081028-00"))
-$(eval $(call SingleProfile,CameoAP99,64kraw,DIR615E4,dir-615-e4,DIR-615-E4,ttyS0,115200,"AP99-AR7240-RT-091105-05"))
-
-$(eval $(call SingleProfile,CameoAP123_4M,64kraw,DIR615I1,dir-615-i1,DIR-615-I1,ttyS0,115200,"00DB120AR9341-RT-1012I1-00"))
-$(eval $(call SingleProfile,CameoAP123_4M,64kraw,DIR615I3,dir-615-i3,DIR-615-I1,ttyS0,115200,"00DB120AR9341-RT-101214-00"))
-
-$(eval $(call SingleProfile,CameoAP81,64kraw-nojffs,A02RBW300N,a02-rb-w300n,TEW-632BRP,ttyS0,115200,"AP81-AR9130-RT-070614-03"))
-$(eval $(call SingleProfile,CameoAP81,64kraw-nojffs,DIR615C1,dir-615-c1,DIR-615-C1,ttyS0,115200,"AP81-AR9130-RT-070614-02"))
-$(eval $(call SingleProfile,CameoAP81,64kraw-nojffs,TEW632BRP,tew-632brp,TEW-632BRP,ttyS0,115200,"AP81-AR9130-RT-070614-00"))
-$(eval $(call SingleProfile,CameoAP81,64kraw-nojffs,TEW652BRP_FW,tew-652brp,TEW-632BRP,ttyS0,115200,"AP81-AR9130-RT-080609-05"))
-$(eval $(call SingleProfile,CameoAP81,64kraw-nojffs,TEW652BRP_RECOVERY,tew-652brp-recovery,TEW-632BRP,ttyS0,115200,"AP81-AR9130-RT-070614-02"))
-
-$(eval $(call SingleProfile,CameoAP121,64kraw-nojffs,TEW712BR,tew-712br,TEW-712BR,ttyATH0,115200,"HORNET-RT-TEW712BR-3",1.99,""))
-$(eval $(call SingleProfile,CameoAP121,64kraw-nojffs,DIR601B1,dir-601-b1,TEW-712BR,ttyATH0,115200,"HORNET-RT-DIR601B1-3",2.99.99,"" "NA"))
-$(eval $(call SingleProfile,CameoAP121_8M,64kraw-nojffs,DIR505A1,dir-505-a1,DIR-505-A1,ttyATH0,115200,"HORNET-PACKET-DIR505A1-3",1.99.99,""))
-
-$(eval $(call SingleProfile,CameoAP135,64kraw,DGL5500A1,dgl-5500-a1,DGL-5500-A1,ttyS0,115200,$$(dgl_5500_mtdlayout),"00AP135AR9558-RT-130508-00"))
-$(eval $(call SingleProfile,CameoAP135,64kraw,TEW823DRU,tew-823dru,TEW-823DRU,ttyS0,115200,$$(tew823dru_mtdlayout) mem=256M,"00AP135AR9558-RT-131129-00"))
-
-$(eval $(call SingleProfile,CameoDB120,64kraw,DHP1565A1,dhp-1565-a1,DHP-1565-A1,ttyS0,115200,"00DB120AR9344-RT-101214-00"))
-$(eval $(call SingleProfile,CameoDB120,64kraw,DIR825C1,dir-825-c1,DIR-825-C1,ttyS0,115200,"00DB120AR9344-RT-101214-00"))
-$(eval $(call SingleProfile,CameoDB120,64kraw,DIR835A1,dir-835-a1,DIR-835-A1,ttyS0,115200,"00DB120AR9344-RT-101214-00"))
-
-$(eval $(call SingleProfile,CameoDB120_8M,64kraw,TEW732BR,tew-732br,TEW-732BR,ttyS0,115200,"00DB120AR9341-RT-120906-NA"))
-
-$(eval $(call SingleProfile,CyberTANGZIP,64k,WRT160NL,wrt160nl,WRT160NL,ttyS0,115200,,1.00.01))
-
-$(eval $(call SingleProfile,CyberTANLZMA,64k,MYNETREXT,mynet-rext,MYNET-REXT,ttyS0,115200,$$(mynet_rext_mtdlayout) root=31:2,1.00.01))
-
-$(eval $(call SingleProfile,CameoAP94,64kraw,DIR825B1,dir-825-b1,DIR-825-B1,ttyS0,115200,$$(cameo_ap94_mtdlayout),$$(cameo_ap94_mtdlayout_fat),01AP94-AR7161-RT-080619-00,00AP94-AR7161-RT-080619-00))
-$(eval $(call SingleProfile,CameoAP94,64kraw,TEW673GRU,tew-673gru,TEW-673GRU,ttyS0,115200,$$(cameo_ap94_mtdlayout),$$(cameo_ap94_mtdlayout_fat),01AP94-AR7161-RT-080619-01,00AP94-AR7161-RT-080619-01))
-$(eval $(call SingleProfile,CameoAP94,64kraw,DLRTDEV01,dlrtdev01,DIR-825-B1,ttyS0,115200,$$(dlrtdev_mtdlayout),$$(dlrtdev_mtdlayout_fat),01AP94-AR7161-RT-080619-00,00AP94-AR7161-RT-080619-00))
-
-$(eval $(call SingleProfile,dLANLzma,64k,dLAN_Hotspot,dlan-hotspot,dLAN-Hotspot,ttyATH0,115200,$$(dlan_hotspot_mtdlayout) mem=64M,KRuImage,65536))
-$(eval $(call SingleProfile,dLANLzma,64k,dLAN_pro_500_wp,dlan-pro-500-wp,dLAN-pro-500-wp,ttyS0,115200,$$(dlan_pro_500_wp_mtdlayout) mem=128M,KRuImage,65536))
-$(eval $(call SingleProfile,dLANLzma,64k,dLAN_pro_1200_ac,dlan-pro-1200-ac,dLAN-pro-1200-ac,ttyS0,115200,$$(dlan_pro_1200_ac_mtdlayout) mem=128M,KRuImage,65536))
-
-$(eval $(call SingleProfile,EnGenius,64k,ESR900,esr900,ESR900,ttyS0,115200,$$(esr900_mtdlayout),KRuImage,,0x4e))
-$(eval $(call SingleProfile,EnGenius,64k,ESR1750,esr1750,ESR1750,ttyS0,115200,$$(esr1750_mtdlayout),KRuImage,,0x61))
-$(eval $(call SingleProfile,EnGenius,64k,EPG5000,epg5000,EPG5000,ttyS0,115200,$$(epg5000_mtdlayout),KRuImage,,0x71))
-
-$(eval $(call SingleProfile,HiWiFi,64k,HIWIFI_HC6361,hiwifi-hc6361,HiWiFi-HC6361,ttyATH0,115200,$$(hiwifi_hc6361_mtdlayout),KRuImage))
-
-$(eval $(call SingleProfile,MyLoader,64k,WP543_2M,wp543,,ttyS0,115200,0x200000,2M))
-$(eval $(call SingleProfile,MyLoader,64k,WP543_4M,wp543,,ttyS0,115200,0x400000,4M))
-$(eval $(call SingleProfile,MyLoader,64k,WP543_8M,wp543,,ttyS0,115200,0x800000,8M))
-$(eval $(call SingleProfile,MyLoader,64k,WP543_16M,wp543,,ttyS0,115200,0x1000000,16M))
-$(eval $(call SingleProfile,MyLoader,64k,WPE72_4M,wpe72,,ttyS0,115200,0x400000,4M))
-$(eval $(call SingleProfile,MyLoader,64k,WPE72_8M,wpe72,,ttyS0,115200,0x800000,8M))
-$(eval $(call SingleProfile,MyLoader,64k,WPE72_16M,wpe72,,ttyS0,115200,0x1000000,16M))
-
-$(eval $(call SingleProfile,Netgear,64kraw,WNR2000V3,wnr2000v3,WNR2000V3,ttyS0,115200,$$(wnr2000v3_mtdlayout),0x32303033,WNR2000V3,"" NA,-H 29763551+04+32))
-$(eval $(call SingleProfile,NetgearLzma,64kraw,WNR2000V4,wnr2000v4,WNR2000V4,ttyS0,115200,$$(wnr2000v4_mtdlayout),0x32303034,WNR2000V4,"" NA,))
-$(eval $(call SingleProfile,Netgear,64kraw,WNR2200,wnr2200,WNR2200,ttyS0,115200,$$(wnr2200_mtdlayout),0x32323030,wnr2200,"" NA,))
-$(eval $(call SingleProfile,Netgear,64kraw,REALWNR612V2,wnr612v2,WNR612V2,ttyS0,115200,$$(wnr2000v3_mtdlayout),0x32303631,WNR612V2,"",))
-$(eval $(call SingleProfile,Netgear,64kraw,N150R,n150r,WNR612V2,ttyS0,115200,$$(wnr2000v3_mtdlayout),0x32303631,N150R,"",))
-$(eval $(call SingleProfile,Netgear,64kraw,REALWNR1000V2,wnr1000v2,WNR1000V2,ttyS0,115200,$$(wnr2000v3_mtdlayout),0x31303031,WNR1000V2,"",))
-$(eval $(call SingleProfile,Netgear,64kraw,WNR1000V2_VC,wnr1000v2-vc,WNR1000V2,ttyS0,115200,$$(wnr2000v3_mtdlayout),0x31303030,WNR1000V2-VC,"",))
-$(eval $(call SingleProfile,Netgear,64kraw,WPN824N,wpn824n,WPN824N,ttyS0,115200,$$(wnr2000v3_mtdlayout),0x31313030,WPN824N,"" NA,))
-
-$(eval $(call SingleProfile,OpenMesh,squashfs-only,OM2P,om2p,,,,OM2P))
-$(eval $(call SingleProfile,OpenMesh,squashfs-only,OM5P,om5p,,,,OM5P))
-$(eval $(call SingleProfile,OpenMesh,squashfs-only,OM5PAC,om5pac,,,,OM5PAC))
-$(eval $(call SingleProfile,OpenMesh,squashfs-only,MR600,mr600,,,,MR600))
-$(eval $(call SingleProfile,OpenMesh,squashfs-only,MR900,mr900,,,,MR900))
-$(eval $(call SingleProfile,OpenMesh,squashfs-only,MR1750,mr1750,,,,MR1750))
-
-$(eval $(call SingleProfile,PB4X,128k,ALL0305,all0305,ALL0305,ttyS0,115200))
-$(eval $(call SingleProfile,PB4X,128k,EAP7660D,eap7660d,EAP7660D,ttyS0,115200))
-$(eval $(call SingleProfile,PB4X,64k,JA76PF,ja76pf,JA76PF,ttyS0,115200))
-$(eval $(call SingleProfile,PB4X,64k,JA76PF2,ja76pf2,JA76PF2,ttyS0,115200))
-$(eval $(call SingleProfile,PB4X,64k,JWAP003,jwap003,JWAP003,ttyS0,115200))
-$(eval $(call SingleProfile,PB4X,64k,PB42,pb42,PB42,ttyS0,115200))
-$(eval $(call SingleProfile,PB4X,64k,PB44,pb44,PB44,ttyS0,115200))
-
-$(eval $(call SingleProfile,Planex,64kraw,MZKW04NU,mzk-w04nu,MZK-W04NU,ttyS0,115200))
-$(eval $(call SingleProfile,Planex,64kraw,MZKW300NH,mzk-w300nh,MZK-W300NH,ttyS0,115200))
-
-$(eval $(call SingleProfile,Seama,64k,MYNETN600,mynet-n600,MYNET-N600,ttyS0,115200,$$(mynet_n600_mtdlayout),wrgnd16_wd_db600,65536,16187392))
-$(eval $(call SingleProfile,Seama,64k,MYNETN750,mynet-n750,MYNET-N750,ttyS0,115200,$$(mynet_n600_mtdlayout),wrgnd13_wd_av,65536,16187392))
-
-$(eval $(call SingleProfile,Seama,64k,QIHOO360,qihoo-c301,QIHOO-C301,ttyS0,115200,$$(qihoo_c301_mtdlayout),wrgac26_qihoo360_360rg,65536,16121856))
-
-$(eval $(call SingleProfile,Senao,squashfs-only,EAP300V2,eap300v2,EAP300V2,ttyS0,115200,$$(eap300v2_mtdlayout)))
-
-$(eval $(call SingleProfile,WHRHPG300N,64kraw,WHRG301N,whr-g301n,WHR-G301N,ttyS0,115200,$$(whrhpg300n_mtdlayout),WHR-G301N))
-$(eval $(call SingleProfile,WHRHPG300N,64kraw,WHRHPG300N,whr-hp-g300n,WHR-HP-G300N,ttyS0,115200,$$(whrhpg300n_mtdlayout),WHR-HP-G300N))
-$(eval $(call SingleProfile,WHRHPG300N,64kraw,WHRHPGN,whr-hp-gn,WHR-HP-GN,ttyS0,115200,$$(whrhpg300n_mtdlayout),WHR-HP-GN))
-$(eval $(call SingleProfile,WHRHPG300N,64kraw,WLAEAG300N,wlae-ag300n,WLAE-AG300N,ttyS0,115200,$$(whrhpg300n_mtdlayout),WLAE-AG300N))
-
-$(eval $(call SingleProfile,WRT400N,64k,WRT400N,wrt400n,WRT400N,ttyS0,115200))
-
-$(eval $(call SingleProfile,WZRHP128K,128kraw,WZRHPG300NH,wzr-hp-g300nh,WZR-HP-G300NH,ttyS0,115200,WZR-HP-G300NH))
-$(eval $(call SingleProfile,WZRHP64K,64kraw,WZRHPG300NH2,wzr-hp-g300nh2,WZR-HP-G300NH2,ttyS0,115200,WZR-HP-G300NH2))
-$(eval $(call SingleProfile,WZRHP64K,64kraw,WZRHPAG300H,wzr-hp-ag300h,WZR-HP-AG300H,ttyS0,115200,WZR-HP-AG300H))
-$(eval $(call SingleProfile,WZRHP64K,64kraw,WZRHPG450H,wzr-hp-g450h,WZR-HP-G450H,ttyS0,115200,WZR-HP-AG450H))
-$(eval $(call SingleProfile,WZRHP64K,64kraw,WZR600DHP,wzr-600dhp,WZR-HP-AG300H,ttyS0,115200,WZR-600DHP))
-$(eval $(call SingleProfile,WZRHP64K,64kraw,WZR450HP2,wzr-450hp2,WZR-450HP2,ttyS0,115200,WZR-450HP2))
-
-$(eval $(call SingleProfile,Zcomax,64k,ZCN1523H28,zcn-1523h-2-8,ZCN-1523H-2,ttyS0,115200,$$(zcn1523h_mtdlayout)))
-$(eval $(call SingleProfile,Zcomax,64k,ZCN1523H516,zcn-1523h-5-16,ZCN-1523H-5,ttyS0,115200,$$(zcn1523h_mtdlayout)))
-
-$(eval $(call SingleProfile,ZyXEL,64k,NBG_460N_550N_550NH,nbg460n_550n_550nh,NBG460N,ttyS0,115200,NBG-460N))
-
-$(eval $(call MultiProfile,AP121,AP121_2M AP121_4M AP121_8M AP121_16M))
-$(eval $(call MultiProfile,AP136,AP136_010 AP136_020))
-$(eval $(call MultiProfile,AP143,AP143_8M AP143_16M))
-$(eval $(call MultiProfile,AP147,AP147_010))
-$(eval $(call MultiProfile,AP152,AP152_16M))
-$(eval $(call MultiProfile,DIR615IX,DIR615I1 DIR615I3))
-$(eval $(call MultiProfile,EWDORIN, EWDORINAP EWDORINRT EWDORIN16M))
-$(eval $(call MultiProfile,OPENMESH,OM2P OM5P OM5PAC MR600 MR900 MR1750))
-$(eval $(call MultiProfile,TEW652BRP,TEW652BRP_FW TEW652BRP_RECOVERY))
-$(eval $(call MultiProfile,TUBE2H,TUBE2H8M TUBE2H16M))
-$(eval $(call MultiProfile,WNR612V2,REALWNR612V2 N150R))
-$(eval $(call MultiProfile,WNR1000V2,REALWNR1000V2 WNR1000V2_VC))
-$(eval $(call MultiProfile,WP543,WP543_2M WP543_4M WP543_8M WP543_16M))
-$(eval $(call MultiProfile,WPE72,WPE72_4M WPE72_8M WPE72_16M))
-$(eval $(call MultiProfile,WPJ342,WPJ342_16M))
-$(eval $(call MultiProfile,WPJ344,WPJ344_16M))
-$(eval $(call MultiProfile,WPJ531,WPJ531_16M))
-$(eval $(call MultiProfile,WPJ558,WPJ558_16M))
-$(eval $(call MultiProfile,Yun,YUN_16M YUN_8M))
-
-$(eval $(call MultiProfile,Minimal,$(SINGLE_PROFILES)))
-$(eval $(call MultiProfile,Madwifi,EAP7660D WP543))
-endif # ifeq ($(SUBTARGET),generic)
-
-ifeq ($(SUBTARGET),nand)
-
-define Device/mr18
- BOARDNAME = MR18
- BLOCKSIZE := 64k
- CONSOLE = ttyS0,115200
- MTDPARTS = ar934x-nfc:512k(nandloader)ro,8M(kernel),8M(recovery),113664k(ubi),128k@130944k(odm-caldata)ro
- IMAGES := sysupgrade.tar
- KERNEL := kernel-bin | patch-cmdline | MerakiNAND
- KERNEL_INITRAMFS := kernel-bin | patch-cmdline | MerakiNAND
- IMAGE/sysupgrade.tar := sysupgrade-nand
-endef
-TARGET_DEVICES += mr18
-
-$(eval $(call SingleProfile,NetgearNAND,64k,WNDR3700V4,wndr3700v4,WNDR3700_V4,ttyS0,115200,$$(wndr4300_mtdlayout),0x33373033,WNDR3700v4,"",-H 29763948+128+128,wndr4300))
-$(eval $(call SingleProfile,NetgearNAND,64k,WNDR4300V1,wndr4300,WNDR4300,ttyS0,115200,$$(wndr4300_mtdlayout),0x33373033,WNDR4300,"",-H 29763948+0+128+128+2x2+3x3,wndr4300))
-$(eval $(call SingleProfile,NetgearNAND,64k,R6100,r6100,R6100,ttyS0,115200,$$(r6100_mtdlayout),0x36303030,R6100,"",-H 29764434+0+128+128+2x2+2x2,wndr4300))
-
-$(eval $(call SingleProfile,ZyXELNAND,128k,NBG6716,nbg6716,NBG6716,ttyS0,115200,NBG6716,$$(zyx_nbg6716_mtdlayout),mem=256M))
-
-$(eval $(call MultiProfile,WNDR4300,WNDR3700V4 WNDR4300V1))
-endif # ifeq ($(SUBTARGET),nand)
-
-
-$(eval $(call MultiProfile,Default,$(SINGLE_PROFILES)))
-
-define Image/Build/squashfs
- cp $(KDIR)/root.squashfs $(KDIR)/root.squashfs-raw
- cp $(KDIR)/root.squashfs $(KDIR)/root.squashfs-64k
- $(STAGING_DIR_HOST)/bin/padjffs2 $(KDIR)/root.squashfs-64k 64
- cp $(KDIR)/root.squashfs-64k $(BIN_DIR)/$(IMG_PREFIX)-root.squashfs-64k
- $(call prepare_generic_squashfs,$(KDIR)/root.squashfs)
- dd if=$(KDIR)/root.$(1) of=$(BIN_DIR)/$(IMG_PREFIX)-root.$(1) bs=128k conv=sync
-endef
-
-define Image/Build/jffs2
- dd if=$(KDIR)/root.$(1) of=$(BIN_DIR)/$(IMG_PREFIX)-root.$(1) bs=128k conv=sync
-endef
-
-define Image/Build/Initramfs
- $(call Image/Build/Profile/$(IMAGE_PROFILE),initramfs)
-endef
-
-define Image/Prepare
- gzip -9n -c $(KDIR)/vmlinux > $(KDIR)/vmlinux.bin.gz
- $(call CompressLzma,$(KDIR)/vmlinux,$(KDIR)/vmlinux.bin.lzma)
-ifneq ($(CONFIG_TARGET_ROOTFS_INITRAMFS),)
- gzip -9n -c $(KDIR)/vmlinux-initramfs > $(KDIR)/vmlinux-initramfs.bin.gz
- $(call CompressLzma,$(KDIR)/vmlinux-initramfs,$(KDIR)/vmlinux-initramfs.bin.lzma)
- $(call Image/BuildLoader,generic,elf,,,-initramfs)
-endif
- $(call Image/BuildLoader,generic,elf)
- $(call Image/Build/Profile/$(if $(CONFIG_IB),Default,$(IMAGE_PROFILE)),loader)
-endef
-
-# $(1): filesystem type.
-define Image/Build
- $(call Image/Build/$(call rootfs_type,$(1)),$(1))
- $(call Image/Build/Profile/$(IMAGE_PROFILE),$(1))
-endef
-
$(eval $(call BuildImage))
diff --git a/target/linux/ar71xx/image/generic.mk b/target/linux/ar71xx/image/generic.mk
new file mode 100644
index 0000000000..ca79f98c97
--- /dev/null
+++ b/target/linux/ar71xx/image/generic.mk
@@ -0,0 +1,344 @@
+define Device/bsb
+ BOARDNAME = BSB
+ IMAGE_SIZE = 16000k
+ CONSOLE = ttyATH0,115200
+ MTDPARTS = spi0.0:128k(u-boot)ro,64k(u-boot-env)ro,16128k(firmware),64k(art)ro
+endef
+TARGET_DEVICES += bsb
+
+define Device/carambola2
+ BOARDNAME = CARAMBOLA2
+ IMAGE_SIZE = 16000k
+ CONSOLE = ttyATH0,115200
+ MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,16000k(firmware),64k(art)ro
+endef
+TARGET_DEVICES += carambola2
+
+define Device/cf-e316n-v2
+ BOARDNAME = CF-E316N-V2
+ IMAGE_SIZE = 16192k
+ CONSOLE = ttyS0,115200
+ MTDPARTS = spi0.0:64k(u-boot)ro,64k(art)ro,16192k(firmware),64k(nvram)ro
+endef
+TARGET_DEVICES += cf-e316n-v2
+
+define Device/weio
+ BOARDNAME = WEIO
+ IMAGE_SIZE = 16000k
+ CONSOLE = ttyATH0,115200
+ MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,16000k(firmware),64k(art)ro
+endef
+TARGET_DEVICES += weio
+
+define Device/gl-ar150
+ BOARDNAME = GL-AR150
+ IMAGE_SIZE = 16000k
+ CONSOLE = ttyATH0,115200
+ MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,16000k(firmware),64k(art)ro
+endef
+TARGET_DEVICES += gl-ar150
+
+define Device/gl-ar300
+ BOARDNAME = GL-AR300
+ IMAGE_SIZE = 16000k
+ CONSOLE = ttyS0,115200
+ MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,16000k(firmware),64k(art)ro
+endef
+TARGET_DEVICES += gl-ar300
+
+define Device/gl-domino
+ BOARDNAME = DOMINO
+ IMAGE_SIZE = 16000k
+ CONSOLE = ttyATH0,115200
+ MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,16000k(firmware),64k(art)ro
+endef
+TARGET_DEVICES += gl-domino
+
+define Device/wndr3700
+ BOARDNAME = WNDR3700
+ NETGEAR_KERNEL_MAGIC = 0x33373030
+ NETGEAR_BOARD_ID = WNDR3700
+ IMAGE_SIZE = 7680k
+ MTDPARTS = spi0.0:320k(u-boot)ro,128k(u-boot-env)ro,7680k(firmware),64k(art)ro
+ IMAGES := sysupgrade.bin factory.img factory-NA.img
+ KERNEL := kernel-bin | patch-cmdline | lzma -d20 | netgear-uImage lzma
+ IMAGE/default = append-kernel $$$$(BLOCKSIZE) | netgear-squashfs | append-rootfs | pad-rootfs
+ IMAGE/sysupgrade.bin = $$(IMAGE/default) | check-size $$$$(IMAGE_SIZE)
+ IMAGE/factory.img = $$(IMAGE/default) | netgear-dni | check-size $$$$(IMAGE_SIZE)
+ IMAGE/factory-NA.img = $$(IMAGE/default) | netgear-dni NA | check-size $$$$(IMAGE_SIZE)
+endef
+
+define Device/wndr3700v2
+$(Device/wndr3700)
+ NETGEAR_BOARD_ID = WNDR3700v2
+ NETGEAR_KERNEL_MAGIC = 0x33373031
+ NETGEAR_HW_ID = 29763654+16+64
+ IMAGE_SIZE = 15872k
+ MTDPARTS = spi0.0:320k(u-boot)ro,128k(u-boot-env)ro,15872k(firmware),64k(art)ro
+ IMAGES := sysupgrade.bin factory.img
+endef
+
+define Device/wndr3800
+$(Device/wndr3700v2)
+ NETGEAR_BOARD_ID = WNDR3800
+ NETGEAR_HW_ID = 29763654+16+128
+endef
+
+define Device/wndr3800ch
+$(Device/wndr3800)
+ NETGEAR_BOARD_ID = WNDR3800CH
+endef
+
+define Device/wndrmac
+$(Device/wndr3700v2)
+ NETGEAR_BOARD_ID = WNDRMAC
+endef
+
+define Device/wndrmacv2
+$(Device/wndr3800)
+ NETGEAR_BOARD_ID = WNDRMACv2
+endef
+
+TARGET_DEVICES += wndr3700 wndr3700v2 wndr3800 wndr3800ch wndrmac wndrmacv2
+
+define Device/cap324
+ BOARDNAME := CAP324
+ DEVICE_PROFILE := CAP324
+ IMAGE_SIZE = 15296k
+ MTDPARTS = spi0.0:256k(u-boot),64k(u-boot-env)ro,15296k(firmware),640k(certs),64k(nvram),64k(art)
+endef
+
+TARGET_DEVICES += cap324
+
+define Device/cap324-nocloud
+ BOARDNAME := CAP324
+ DEVICE_PROFILE := CAP324
+ IMAGE_SIZE = 16000k
+ MTDPARTS = spi0.0:256k(u-boot),64k(u-boot-env)ro,16000k(firmware),64k(art)
+endef
+
+TARGET_DEVICES += cap324-nocloud
+
+define Device/cr3000
+ BOARDNAME := CR3000
+ DEVICE_PROFILE := CR3000
+ IMAGE_SIZE = 7104k
+ MTDPARTS = spi0.0:256k(u-boot),64k(u-boot-env)ro,7104k(firmware),640k(certs),64k(nvram),64k(art)
+endef
+
+TARGET_DEVICES += cr3000
+
+define Device/cr3000-nocloud
+ BOARDNAME := CR3000
+ DEVICE_PROFILE := CR3000
+ IMAGE_SIZE = 7808k
+ MTDPARTS = spi0.0:256k(u-boot),64k(u-boot-env)ro,7808k(firmware),64k(art)
+endef
+
+TARGET_DEVICES += cr3000-nocloud
+
+define Device/cr5000
+ BOARDNAME := CR5000
+ DEVICE_PROFILE := CR5000
+ IMAGE_SIZE = 7104k
+ MTDPARTS = spi0.0:256k(u-boot),64k(u-boot-env)ro,7104k(firmware),640k(certs),64k(nvram),64k(art)
+endef
+
+TARGET_DEVICES += cr5000
+
+define Device/cr5000-nocloud
+ BOARDNAME := CR5000
+ DEVICE_PROFILE := CR5000
+ IMAGE_SIZE = 7808k
+ MTDPARTS = spi0.0:256k(u-boot),64k(u-boot-env)ro,7808k(firmware),64k(art)
+endef
+
+TARGET_DEVICES += cr5000-nocloud
+
+define Device/antminer-s1
+ $(Device/tplink-8mlzma)
+ BOARDNAME := ANTMINER-S1
+ DEVICE_PROFILE := ANTMINERS1
+ TPLINK_HWID := 0x04440101
+ CONSOLE := ttyATH0,115200
+endef
+
+define Device/antminer-s3
+ $(Device/tplink-8mlzma)
+ BOARDNAME := ANTMINER-S3
+ DEVICE_PROFILE := ANTMINERS3
+ TPLINK_HWID := 0x04440301
+ CONSOLE := ttyATH0,115200
+endef
+
+define Device/antrouter-r1
+ $(Device/tplink-8mlzma)
+ BOARDNAME := ANTROUTER-R1
+ DEVICE_PROFILE := ANTROUTERR1
+ TPLINK_HWID := 0x44440101
+ CONSOLE := ttyATH0,115200
+endef
+
+define Device/el-m150
+ $(Device/tplink-8mlzma)
+ BOARDNAME := EL-M150
+ DEVICE_PROFILE := ELM150
+ TPLINK_HWID := 0x01500101
+ CONSOLE := ttyATH0,115200
+endef
+
+define Device/el-mini
+ $(Device/tplink-8mlzma)
+ BOARDNAME := EL-MINI
+ DEVICE_PROFILE := ELMINI
+ TPLINK_HWID := 0x01530001
+ CONSOLE := ttyATH0,115200
+endef
+TARGET_DEVICES += antminer-s1 antminer-s3 antrouter-r1 el-m150 el-mini
+
+define Device/gl-inet-6408A-v1
+ $(Device/tplink-8mlzma)
+ BOARDNAME := GL-INET
+ DEVICE_PROFILE := GLINET
+ TPLINK_HWID := 0x08000001
+ CONSOLE := ttyATH0,115200
+endef
+
+define Device/gl-inet-6416A-v1
+ $(Device/tplink-16mlzma)
+ BOARDNAME := GL-INET
+ DEVICE_PROFILE := GLINET
+ TPLINK_HWID := 0x08000001
+ CONSOLE := ttyATH0,115200
+endef
+TARGET_DEVICES += gl-inet-6408A-v1 gl-inet-6416A-v1
+
+define Device/rnx-n360rt
+ $(Device/tplink-4m)
+ BOARDNAME := TL-WR941ND
+ DEVICE_PROFILE := RNXN360RT
+ TPLINK_HWID := 0x09410002
+ TPLINK_HWREV := 0x00420001
+endef
+TARGET_DEVICES += rnx-n360rt
+
+define Device/mc-mac1200r
+ $(Device/tplink-8mlzma)
+ BOARDNAME := MC-MAC1200R
+ DEVICE_PROFILE := MAC1200R
+ TPLINK_HWID := 0x12000001
+endef
+TARGET_DEVICES += mc-mac1200r
+
+define Device/minibox-v1
+ $(Device/tplink-16mlzma)
+ BOARDNAME := MINIBOX-V1
+ DEVICE_PROFILE := MINIBOXV1
+ TPLINK_HWID := 0x3C000201
+ CONSOLE := ttyATH0,115200
+endef
+TARGET_DEVICES += minibox-v1
+
+define Device/omy-g1
+ $(Device/tplink-16mlzma)
+ BOARDNAME := OMY-G1
+ DEVICE_PROFILE := OMYG1
+ TPLINK_HWID := 0x06660101
+endef
+
+define Device/omy-x1
+ $(Device/tplink-8mlzma)
+ BOARDNAME := OMY-X1
+ DEVICE_PROFILE := OMYX1
+ TPLINK_HWID := 0x06660201
+endef
+TARGET_DEVICES += omy-g1 omy-x1
+
+define Device/onion-omega
+ $(Device/tplink-16mlzma)
+ BOARDNAME := ONION-OMEGA
+ DEVICE_PROFILE := OMEGA
+ TPLINK_HWID := 0x04700001
+ CONSOLE := ttyATH0,115200
+endef
+TARGET_DEVICES += onion-omega
+
+define Device/smart-300
+ $(Device/tplink-8mlzma)
+ BOARDNAME := SMART-300
+ DEVICE_PROFILE := SMART-300
+ TPLINK_HWID := 0x93410001
+endef
+TARGET_DEVICES += smart-300
+
+define Device/som9331
+ $(Device/tplink-8mlzma)
+ BOARDNAME := SOM9331
+ DEVICE_PROFILE := SOM9331
+ TPLINK_HWID := 0x04800054
+ CONSOLE := ttyATH0,115200
+endef
+TARGET_DEVICES += som9331
+
+define Device/tellstick-znet-lite
+ $(Device/tplink-16mlzma)
+ BOARDNAME := TELLSTICK-ZNET-LITE
+ DEVICE_PROFILE := TELLSTICKZNETLITE
+ TPLINK_HWID := 0x00726001
+ CONSOLE := ttyATH0,115200
+endef
+TARGET_DEVICES += tellstick-znet-lite
+
+define Device/oolite
+ $(Device/tplink-16mlzma)
+ BOARDNAME := GS-OOLITE
+ DEVICE_PROFILE := OOLITE
+ TPLINK_HWID := 0x3C000101
+ CONSOLE := ttyATH0,115200
+endef
+TARGET_DEVICES += oolite
+
+
+define Device/NBG6616
+ BOARDNAME = NBG6616
+ KERNEL_SIZE = 2048k
+ IMAGE_SIZE = 15323k
+ MTDPARTS = spi0.0:192k(u-boot)ro,64k(env)ro,64k(RFdata)ro,384k(zyxel_rfsd),384k(romd),64k(header),2048k(kernel),13184k(rootfs),15232k@0x120000(firmware)
+ CMDLINE += mem=128M
+ IMAGES := sysupgrade.bin
+ KERNEL := kernel-bin | patch-cmdline | lzma | uImage lzma | jffs2 boot/vmlinux.lzma.uImage
+ IMAGE/sysupgrade.bin = append-kernel $$$$(KERNEL_SIZE) | append-rootfs | pad-rootfs | check-size $$$$(IMAGE_SIZE)
+ # We cannot currently build a factory image. It is the sysupgrade image
+ # prefixed with a header (which is actually written into the MTD device).
+ # The header is 2kiB and is filled with 0xff. The format seems to be:
+ # 2 bytes: 0x0000
+ # 2 bytes: checksum of the data partition (big endian)
+ # 4 bytes: length of the contained image file (big endian)
+ # 32 bytes: Firmware Version string (NUL terminated, 0xff padded)
+ # 2 bytes: 0x0000
+ # 2 bytes: checksum over the header partition (big endian)
+ # 32 bytes: Model (e.g. "NBG6616", NUL termiated, 0xff padded)
+ # rest: 0xff padding
+ #
+ # The checksums are calculated by adding up all bytes and if a 16bit
+ # overflow occurs, one is added and the sum is masked to 16 bit:
+ # csum = csum + databyte; if (csum > 0xffff) { csum += 1; csum &= 0xffff };
+ # Should the file have an odd number of bytes then the byte len-0x800 is
+ # used additionally.
+ # The checksum for the header is calcualted over the first 2048 bytes with
+ # the firmware checksum as the placeholder during calculation.
+ #
+ # The header is padded with 0xff to the erase block size of the device.
+endef
+
+TARGET_DEVICES += NBG6616
+
+define Device/c-55
+ BOARDNAME = C-55
+ KERNEL_SIZE = 2048k
+ IMAGE_SIZE = 15872k
+ MTDPARTS = spi0.0:256k(u-boot)ro,128k(u-boot-env)ro,2048k(kernel),13824k(rootfs),13824k(opt)ro,2624k(failsafe)ro,64k(art)ro,15872k@0x60000(firmware)
+ IMAGE/sysupgrade.bin = append-kernel $$$$(KERNEL_SIZE) | append-rootfs | pad-rootfs | check-size $$$$(IMAGE_SIZE)
+endef
+
+TARGET_DEVICES += c-55
diff --git a/target/linux/ar71xx/image/legacy.mk b/target/linux/ar71xx/image/legacy.mk
new file mode 100644
index 0000000000..12e2f55463
--- /dev/null
+++ b/target/linux/ar71xx/image/legacy.mk
@@ -0,0 +1,1231 @@
+rootfs_type=$(patsubst jffs2-%,jffs2,$(patsubst squashfs-%,squashfs,$(1)))
+
+# $(1): rootfs type.
+# $(2): board name.
+define imgname
+$(BIN_DIR)/$(IMG_PREFIX)-$(2)-$(call rootfs_type,$(1))
+endef
+
+define rootfs_align
+$(patsubst %-256k,0x40000,$(patsubst %-128k,0x20000,$(patsubst %-64k,0x10000,$(patsubst squashfs%,0x4,$(patsubst root.%,%,$(1))))))
+endef
+
+define sysupname
+$(call imgname,$(1),$(2))-sysupgrade.bin
+endef
+
+define factoryname
+$(call imgname,$(1),$(2))-factory.bin
+endef
+
+COMMA:=,
+
+define mkcmdline
+$(if $(1),board=$(1) )$(if $(2),console=$(2)$(COMMA)$(3))
+endef
+
+define mtdpartsize
+$(shell sz=`echo '$(2)' | sed -ne 's/.*[:$(COMMA)]\([0-9]*\)k[@]*[0-9a-zx]*($(1)).*/\1/p'`; [ -n "$$sz" ] && echo $$(($$sz * 1024)))
+endef
+
+SINGLE_PROFILES:=
+
+# $(1) : name of image build method to be used, e.g., AthLzma.
+# $(2) : name of the build template to be used, e.g. 64k, 64kraw, 128k, etc.
+# $(3) : name of the profile to be defined.
+# $(4) : board name.
+# $(5)~$(7) : arguments for $(mkcmdline)
+# board=$(1) console=$(2),$(3)
+# $(8)~$(14): extra arguments.
+define SingleProfile
+ # $(1): action name, e.g. loader, buildkernel, squashfs, etc.
+ define Image/Build/Profile/$(3)
+ $$(call Image/Build/Template/$(2)/$$(1),$(1),$(4),$$(call mkcmdline,$(5),$(6),$(7)),$(8),$(9),$(10),$(11),$(12),$(13),$(14))
+ endef
+ SINGLE_PROFILES += $(3)
+endef
+
+# $(1), name of the MultiProfile to be added.
+# $(2), name of Profiles to be included in the MultiProfile.
+define MultiProfile
+ define Image/Build/Profile/$(1)
+ $(foreach p,$(2),
+ $$(call Image/Build/Profile/$p,$$(1))
+ )
+ endef
+endef
+
+LOADER_MAKE := $(NO_TRACE_MAKE) -C lzma-loader KDIR=$(KDIR)
+
+VMLINUX:=$(BIN_DIR)/$(IMG_PREFIX)-vmlinux
+UIMAGE:=$(BIN_DIR)/$(IMG_PREFIX)-uImage
+
+# $(1): input file.
+# $(2): output file.
+# $(3): extra arguments for lzma.
+define CompressLzma
+ $(STAGING_DIR_HOST)/bin/lzma e $(1) -lc1 -lp2 -pb2 $(3) $(2)
+endef
+
+define PatchKernel
+ cp $(KDIR)/vmlinux$(3) $(KDIR_TMP)/vmlinux$(3)-$(1)
+ $(STAGING_DIR_HOST)/bin/patch-cmdline $(KDIR_TMP)/vmlinux$(3)-$(1) "$(strip $(2))"
+endef
+
+define PatchKernel/initramfs
+ $(call PatchKernel,$(1),$(2),-initramfs)
+ cp $(KDIR_TMP)/vmlinux-initramfs-$(1) $(call imgname,initramfs,$(1)).bin
+endef
+
+# $(1): board name.
+# $(2): kernel command line.
+# $(3): extra argumetns for lzma.
+# $(4): name suffix, e.g. "-initramfs".
+define PatchKernelLzma
+ cp $(KDIR)/vmlinux$(4) $(KDIR_TMP)/vmlinux$(4)-$(1)
+ $(STAGING_DIR_HOST)/bin/patch-cmdline $(KDIR_TMP)/vmlinux$(4)-$(1) "$(strip $(2))"
+ $(call CompressLzma,$(KDIR_TMP)/vmlinux$(4)-$(1),$(KDIR_TMP)/vmlinux$(4)-$(1).bin.lzma,$(3))
+endef
+
+define PatchKernelGzip
+ cp $(KDIR)/vmlinux$(3) $(KDIR_TMP)/vmlinux$(3)-$(1)
+ $(STAGING_DIR_HOST)/bin/patch-cmdline $(KDIR_TMP)/vmlinux$(3)-$(1) "$(strip $(2))"
+ gzip -9n -c $(KDIR_TMP)/vmlinux$(3)-$(1) > $(KDIR_TMP)/vmlinux$(3)-$(1).bin.gz
+endef
+
+ifneq ($(SUBTARGET),mikrotik)
+# $(1): compression method of the data.
+# $(2): extra arguments.
+# $(3): input data file.
+# $(4): output file.
+define MkuImage
+ mkimage -A mips -O linux -T kernel -a 0x80060000 -C $(1) $(2) \
+ -e 0x80060000 -n 'MIPS OpenWrt Linux-$(LINUX_VERSION)' \
+ -d $(3) $(4)
+endef
+
+# $(1): board name.
+# $(2): kernel command line.
+# $(3): extra arguments for lzma.
+# $(4): name suffix, e.g. "-initramfs".
+# $(5): extra arguments for mkimage.
+define MkuImageLzma
+ $(call PatchKernelLzma,$(1),$(2),$(3),$(4))
+ $(call MkuImage,lzma,$(5),$(KDIR_TMP)/vmlinux$(4)-$(1).bin.lzma,$(KDIR_TMP)/vmlinux$(4)-$(1).uImage)
+endef
+
+define MkuImageLzma/initramfs
+ $(call PatchKernelLzma,$(1),$(2),$(3),-initramfs)
+ $(call MkuImage,lzma,$(4),$(KDIR_TMP)/vmlinux-initramfs-$(1).bin.lzma,$(call imgname,initramfs,$(1))-uImage.bin)
+endef
+
+define MkuImageGzip
+ $(call PatchKernelGzip,$(1),$(2))
+ $(call MkuImage,gzip,,$(KDIR_TMP)/vmlinux-$(1).bin.gz,$(KDIR_TMP)/vmlinux-$(1).uImage)
+endef
+
+define MkuImageGzip/initramfs
+ $(call PatchKernelGzip,$(1),$(2),-initramfs)
+ $(call MkuImage,gzip,,$(KDIR_TMP)/vmlinux-initramfs-$(1).bin.gz,$(call imgname,initramfs,$(1))-uImage.bin)
+endef
+
+define MkuImageOKLI
+ $(call MkuImage,lzma,-M 0x4f4b4c49,$(KDIR)/vmlinux.bin.lzma,$(KDIR_TMP)/vmlinux-$(1).okli)
+endef
+endif
+
+# $(1): name of the 1st file.
+# $(2): size limit of the 1st file if it is greater than 262144, or
+# the erase size of the flash if it is greater than zero and less
+# than 262144
+# $(3): name of the 2nd file.
+# $(4): size limit of the 2nd file if $(2) is greater than 262144, otherwise
+# it is the size limit of the output file
+# $(5): name of the output file.
+# $(6): padding size.
+define CatFiles
+ if [ $(2) -eq 0 ]; then \
+ filename="$(3)"; fstype=$$$${filename##*\.}; \
+ case "$$$${fstype}" in \
+ "jffs2-64k") bs=65536;; \
+ "jffs2-128k") bs=131072;; \
+ "jffs2-256k") bs=262144;; \
+ *) bs=`stat -c%s $(1)`;; \
+ esac; \
+ ( dd if=$(1) bs=$$$${bs} conv=sync; cat $(3) ) > $(5); \
+ if [ -n "$(6)" ]; then \
+ case "$$$${fstype}" in \
+ squashfs*) \
+ padjffs2 $(5) $(6); \
+ ;; \
+ esac; \
+ fi; \
+ if [ `stat -c%s $(5)` -gt $(4) ]; then \
+ echo "Warning: $(5) is too big (> $(4) bytes)" >&2; \
+ rm -f $(5); \
+ fi; \
+ else if [ $(2) -gt 262144 ]; then \
+ if [ `stat -c%s "$(1)"` -gt $(2) ]; then \
+ echo "Warning: $(1) is too big (> $(2) bytes)" >&2; \
+ else if [ `stat -c%s $(3)` -gt $(4) ]; then \
+ echo "Warning: $(3) is too big (> $(4) bytes)" >&2; \
+ else \
+ ( dd if=$(1) bs=$(2) conv=sync; dd if=$(3) ) > $(5); \
+ fi; fi; \
+ else \
+ ( dd if=$(1) bs=$(2) conv=sync; dd if=$(3) ) > $(5); \
+ if [ `stat -c%s $(5)` -gt $(4) ]; then \
+ echo "Warning: $(5) is too big (> $(4) bytes)" >&2; \
+ rm -f $(5); \
+ fi; \
+ fi; fi
+endef
+
+# $(1): rootfs type.
+# $(2): board name.
+# $(3): kernel image size limit.
+# $(4): rootfs image size limit.
+# $(5): padding argument for padjffs2.
+Sysupgrade/KR=$(call CatFiles,$(2),$(3),$(KDIR)/root.$(1),$(4),$(call sysupname,$(1),$(5)))
+Sysupgrade/KRuImage=$(call CatFiles,$(KDIR_TMP)/vmlinux-$(2).uImage,$(3),$(KDIR)/root.$(1),$(4),$(call sysupname,$(1),$(2)),$(5))
+Sysupgrade/RKuImage=$(call CatFiles,$(KDIR)/root.$(1),$(4),$(KDIR_TMP)/vmlinux-$(2).uImage,$(3),$(call sysupname,$(1),$(2)))
+
+# $(1): ubinize ini file
+# $(2): working directory
+# $(3): output file
+# $(4): physical erase block size
+# $(5): minimum I/O unit size
+# $(6): custom options
+define ubinize
+ $(CP) $(1) $(2)
+ ( cd $(2); $(STAGING_DIR_HOST)/bin/ubinize -o $(3) -p $(4) -m $(5) $(6) $(1))
+endef
+
+#
+# Embed lzma-compressed kernel inside lzma-loader.
+#
+# $(1), suffix of output filename, e.g. generic, lowercase board name, etc.
+# $(2), suffix of target file to build, e.g. bin, gz, elf
+# $(3), kernel command line to pass from lzma-loader to kernel
+# $(4), unused here
+# $(5), suffix of kernel filename, e.g. -initramfs, or empty
+define Image/BuildLoader
+ -rm -rf $(KDIR)/lzma-loader
+ $(LOADER_MAKE) LOADER=loader-$(1).$(2) KERNEL_CMDLINE="$(3)"\
+ LZMA_TEXT_START=0x80a00000 LOADADDR=0x80060000 \
+ LOADER_DATA="$(KDIR)/vmlinux$(5).bin.lzma" BOARD="$(1)" \
+ compile loader.$(2)
+ -$(CP) $(KDIR)/loader-$(1).$(2) $(KDIR)/loader-$(1)$(5).$(2)
+endef
+
+#
+# Build lzma-loader alone which will search for lzma-compressed kernel identified by
+# uImage header with magic "OKLI" at boot time.
+#
+# $(4), offset into the flash space to start searching uImage magic "OKLI".
+# $(5), size of search range starting at $(4). With 0 as the value, uImage
+# header is expected to be at precisely $(4)
+define Image/BuildLoaderAlone
+ -rm -rf $(KDIR)/lzma-loader
+ $(LOADER_MAKE) LOADER=loader-$(1).$(2) KERNEL_CMDLINE="$(3)" \
+ LZMA_TEXT_START=0x80a00000 LOADADDR=0x80060000 \
+ BOARD="$(1)" FLASH_OFFS=$(4) FLASH_MAX=$(5) \
+ compile loader.$(2)
+endef
+
+define Build/Clean
+ $(LOADER_MAKE) clean
+endef
+
+alfa_ap120c_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,13312k(rootfs),1536k(kernel),1152k(unknown)ro,64k(art)ro;spi0.1:-(unknown)
+alfa_ap96_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,256k(u-boot-env)ro,13312k(rootfs),2048k(kernel),512k(caldata)ro,15360k@0x80000(firmware)
+alfa_mtdlayout_8M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,6144k(rootfs),1600k(kernel),64k(nvram),64k(art)ro,7744k@0x50000(firmware)
+alfa_mtdlayout_16M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,15936k(firmware),64k(nvram),64k(art)ro
+all0258n_mtdlayout=mtdparts=spi0.0:256k(u-boot),64k(u-boot-env),6272k(firmware),1536k(failsafe),64k(art)
+all0315n_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,256k(u-boot-env),13568k(firmware),2048k(failsafe),256k(art)ro
+ap81_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,5120k(rootfs),2688k(kernel),64k(art)ro,7808k@0x50000(firmware)
+ap83_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,128k(u-boot-env)ro,4096k(rootfs),3648k(kernel),64k(art)ro,7744k@0x60000(firmware)
+ap96_mtdlayout=mtdparts=spi0.0:192k(u-boot)ro,64k(u-boot-env)ro,6144k(rootfs),1728k(kernel),64k(art)ro,7872k@0x40000(firmware)
+ap113_mtd_layout=mtdparts=spi0.0:64k(u-boot),3008k(rootfs),896k(uImage),64k(NVRAM),64k(ART),3904k@0x10000(firmware)
+ap121_mtdlayout_2M=mtdparts=spi0.0:64k(u-boot)ro,1216k(rootfs),704k(kernel),64k(art)ro,1920k@0x10000(firmware)
+ap121_mtdlayout_4M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,2448k(rootfs),1200k(kernel),64k(nvram),64k(art)ro,3648k@0x50000(firmware)
+ap121_mtdlayout_8M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,6144k(rootfs),1600k(kernel),64k(nvram),64k(art)ro,7744k@0x50000(firmware)
+ap121_mtdlayout_16M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,10944k(rootfs),4992k(kernel),64k(nvram),64k(art)ro,15936k@0x50000(firmware)
+ap132_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,1408k(kernel),6400k(rootfs),64k(art),7808k@0x50000(firmware)
+ap135_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,14528k(rootfs),1472k(kernel),64k(art)ro,16000k@0x50000(firmware)
+ap136_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,6336k(rootfs),1408k(kernel),64k(mib0),64k(art)ro,7744k@0x50000(firmware)
+ap143_mtdlayout_8M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,6336k(rootfs),1472k(kernel),64k(art)ro,7744k@0x50000(firmware)
+ap143_mtdlayout_16M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,14528k(rootfs),1472k(kernel),64k(art)ro,16000k@0x50000(firmware)
+ap147_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,14528k(rootfs),1472k(kernel),64k(art),16000k@0x50000(firmware)
+ap152_mtdlayout_16M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,14528k(rootfs),1472k(kernel),64k(art)ro,16000k@0x50000(firmware)
+bxu2000n2_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,1408k(kernel),8448k(rootfs),6016k(user),64k(cfg),64k(oem),64k(art)ro
+cameo_ap81_mtdlayout=mtdparts=spi0.0:128k(u-boot)ro,64k(config)ro,3840k(firmware),64k(art)ro
+cameo_ap91_mtdlayout=mtdparts=spi0.0:192k(u-boot)ro,64k(nvram)ro,3712k(firmware),64k(mac)ro,64k(art)ro
+cameo_ap99_mtdlayout=mtdparts=spi0.0:192k(u-boot)ro,64k(nvram)ro,3520k(firmware),64k(mac)ro,192k(lp)ro,64k(art)ro
+cameo_ap121_mtdlayout=mtdparts=spi0.0:64k(u-boot)ro,64k(art)ro,64k(mac)ro,64k(nvram)ro,192k(language)ro,3648k(firmware)
+cameo_ap121_mtdlayout_8M=mtdparts=spi0.0:64k(u-boot)ro,64k(art)ro,64k(mac)ro,64k(nvram)ro,256k(language)ro,7680k@0x80000(firmware)
+cameo_ap123_mtdlayout_4M=mtdparts=spi0.0:64k(u-boot)ro,64k(nvram)ro,3712k(firmware),192k(lang)ro,64k(art)ro
+cameo_db120_mtdlayout=mtdparts=spi0.0:64k(uboot)ro,64k(nvram)ro,15936k(firmware),192k(lang)ro,64k(mac)ro,64k(art)ro
+cameo_db120_mtdlayout_8M=mtdparts=spi0.0:64k(uboot)ro,64k(nvram)ro,7872k(firmware),128k(lang)ro,64k(art)ro
+cap4200ag_mtdlayout=mtdparts=spi0.0:256k(u-boot),64k(u-boot-env),320k(custom)ro,1536k(kernel),12096k(rootfs),2048k(failsafe),64k(art),13632k@0xa0000(firmware)
+eap300v2_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env),320k(custom),13632k(firmware),2048k(failsafe),64k(art)ro
+db120_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,6336k(rootfs),1408k(kernel),64k(nvram),64k(art)ro,7744k@0x50000(firmware)
+dgl_5500_mtdlayout=mtdparts=spi0.0:192k(u-boot)ro,64k(nvram)ro,15296k(firmware),192k(lang)ro,512k(my-dlink)ro,64k(mac)ro,64k(art)ro
+dlan_hotspot_mtdlayout=mtdparts=spi0.0:128k(u-boot)ro,64k(Config1)ro,64k(Config2)ro,7872k@0x40000(firmware),64k(art)ro
+dlan_pro_500_wp_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,64k(Config1)ro,64k(Config2)ro,7680k@0x70000(firmware),64k(art)ro
+dlan_pro_1200_ac_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,64k(Config1)ro,64k(Config2)ro,15872k@0x70000(firmware),64k(art)ro
+cameo_ap94_mtdlayout=mtdparts=spi0.0:256k(uboot)ro,64k(config)ro,6208k(firmware),64k(caldata)ro,1600k(unknown)ro,64k@0x7f0000(caldata_copy)
+cameo_ap94_mtdlayout_fat=mtdparts=spi0.0:256k(uboot)ro,64k(config)ro,7808k(firmware),64k(caldata)ro,64k@0x660000(caldata_orig),6208k@0x50000(firmware_orig)
+esr900_mtdlayout=mtdparts=spi0.0:192k(u-boot)ro,64k(u-boot-env)ro,1408k(kernel),13248k(rootfs),1024k(manufacture)ro,64k(backup)ro,320k(storage)ro,64k(caldata)ro,14656k@0x40000(firmware)
+esr1750_mtdlayout=mtdparts=spi0.0:192k(u-boot)ro,64k(u-boot-env)ro,1408k(kernel),13248k(rootfs),1024k(manufacture)ro,64k(backup)ro,320k(storage)ro,64k(caldata)ro,14656k@0x40000(firmware)
+epg5000_mtdlayout=mtdparts=spi0.0:192k(u-boot)ro,64k(u-boot-env)ro,1408k(kernel),13248k(rootfs),1024k(manufacture)ro,64k(backup)ro,320k(storage)ro,64k(caldata)ro,14656k@0x40000(firmware)
+ew-dorin_mtdlayout_4M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env),3712k(firmware),64k(art)
+ew-dorin_mtdlayout_16M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env),16000k(firmware),64k(art)ro
+f9k1115v2_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env),14464k(rootfs),1408k(kernel),64k(nvram)ro,64k(envram)ro,64k(art)ro,15872k@0x50000(firmware)
+dlrtdev_mtdlayout=mtdparts=spi0.0:256k(uboot)ro,64k(config)ro,6208k(firmware),64k(caldata)ro,640k(certs),960k(unknown)ro,64k@0x7f0000(caldata_copy)
+dlrtdev_mtdlayout_fat=mtdparts=spi0.0:256k(uboot)ro,64k(config)ro,7168k(firmware),640k(certs),64k(caldata)ro,64k@0x660000(caldata_orig),6208k@0x50000(firmware_orig)
+dragino2_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,16000k(firmware),64k(config)ro,64k(art)ro
+hiwifi_hc6361_mtdlayout=mtdparts=spi0.0:64k(u-boot)ro,64k(bdinfo)ro,1280k(kernel),14848k(rootfs),64k(backup)ro,64k(art)ro,16128k@0x20000(firmware)
+mr12_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,256k(u-boot-env)ro,13440k(rootfs),2304k(kernel),128k(art)ro,15744k@0x80000(firmware)
+mr16_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,256k(u-boot-env)ro,13440k(rootfs),2304k(kernel),128k(art)ro,15744k@0x80000(firmware)
+pb92_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,2752k(rootfs),896k(kernel),64k(nvram),64k(art)ro,3648k@0x50000(firmware)
+planex_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,7744k(firmware),128k(art)ro
+ubntxm_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,7552k(firmware),256k(cfg)ro,64k(EEPROM)ro
+uap_pro_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,1536k(kernel),14208k(rootfs),256k(cfg)ro,64k(EEPROM)ro,15744k@0x50000(firmware)
+ubdev_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,7488k(firmware),64k(certs),256k(cfg)ro,64k(EEPROM)ro
+whrhpg300n_mtdlayout=mtdparts=spi0.0:248k(u-boot)ro,8k(u-boot-env)ro,3712k(firmware),64k(art)ro
+wlr8100_mtdlayout=mtdparts=spi0.0:192k(u-boot)ro,64k(u-boot-env)ro,1408k(kernel),14080k(rootfs),192k(unknown)ro,64k(art)ro,384k(unknown2)ro,15488k@0x40000(firmware)
+wpj342_mtdlayout_16M=mtdparts=spi0.0:192k(u-boot)ro,16128k(firmware),64k(art)ro
+wpj344_mtdlayout_16M=mtdparts=spi0.0:192k(u-boot)ro,16128k(firmware),64k(art)ro
+dr344_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,6336k(rootfs),1408k(kernel),64k(nvram),64k(art)ro,7744k@0x50000(firmware)
+wpj531_mtdlayout_16M=mtdparts=spi0.0:192k(u-boot)ro,16128k(firmware),64k(art)ro
+wpj558_mtdlayout_16M=mtdparts=spi0.0:192k(u-boot)ro,16128k(firmware),64k(art)ro
+wndap360_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,1728k(kernel),6016k(rootfs),64k(nvram)ro,64k(art)ro,7744k@0x50000(firmware)
+wnr2200_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,7808k(firmware),64k(art)ro
+wnr2000v3_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,3712k(firmware),64k(art)ro
+wnr2000v4_mtdlayout=mtdparts=spi0.0:192k(u-boot)ro,64k(u-boot-env)ro,3776k(firmware),64k(art)ro
+r6100_mtdlayout=mtdparts=ar934x-nfc:128k(u-boot)ro,256k(caldata),256k(caldata-backup),512k(config),512k(pot),2048k(kernel),122240k(ubi),25600k@0x1a0000(firmware),2048k(language),3072k(traffic_meter)
+tew823dru_mtdlayout=mtdparts=spi0.0:192k(u-boot)ro,64k(nvram)ro,15296k(firmware),192k(lang)ro,512k(my-dlink)ro,64k(mac)ro,64k(art)ro
+wndr4300_mtdlayout=mtdparts=ar934x-nfc:256k(u-boot)ro,256k(u-boot-env)ro,256k(caldata),512k(pot),2048k(language),512k(config),3072k(traffic_meter),2048k(kernel),23552k(ubi),25600k@0x6c0000(firmware),256k(caldata_backup),-(reserved)
+zcn1523h_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,6208k(rootfs),1472k(kernel),64k(configure)ro,64k(mfg)ro,64k(art)ro,7680k@0x50000(firmware)
+mynet_n600_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,64k(devdata)ro,64k(devconf)ro,15872k(firmware),64k(radiocfg)ro
+mynet_rext_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,7808k(firmware),64k(nvram)ro,64k(ART)ro
+zyx_nbg6716_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(env)ro,64k(RFdata)ro,-(nbu);ar934x-nfc:2048k(zyxel_rfsd),2048k(romd),1024k(header),2048k(kernel),-(ubi)
+qihoo_c301_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env),64k(devdata),64k(devconf),15744k(firmware),64k(warm_start),64k(action_image_config),64k(radiocfg)ro;spi0.1:15360k(upgrade2),1024k(privatedata)
+yun_mtdlayout_8M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,6464k(rootfs),1280k(kernel),64k(nvram),64k(art),7744k@0x50000(firmware)
+yun_mtdlayout_16M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,14656k(rootfs),1280k(kernel),64k(nvram),64k(art),15936k@0x50000(firmware)
+wrtnode2q_mtdlayout=mtdparts=spi0.0:192k(u-boot),64k(u-boot-env),64k(art),1472k(kernel),14592k(rootfs),16064k@0x50000(firmware),16384k@0x0(fullflash)
+
+define Image/BuildKernel
+ cp $(KDIR)/vmlinux.elf $(VMLINUX).elf
+ cp $(KDIR)/vmlinux $(VMLINUX).bin
+ dd if=$(KDIR)/vmlinux.bin.lzma of=$(VMLINUX).lzma bs=65536 conv=sync
+ dd if=$(KDIR)/vmlinux.bin.gz of=$(VMLINUX).gz bs=65536 conv=sync
+ $(call MkuImage,gzip,,$(KDIR)/vmlinux.bin.gz,$(UIMAGE)-gzip.bin)
+ $(call MkuImage,lzma,,$(KDIR)/vmlinux.bin.lzma,$(UIMAGE)-lzma.bin)
+ cp $(KDIR)/loader-generic.elf $(VMLINUX)-lzma.elf
+ -mkdir -p $(KDIR_TMP)
+ $(call Image/Build/Profile/$(IMAGE_PROFILE),buildkernel)
+endef
+
+define Image/BuildKernel/Initramfs
+ cp $(KDIR)/vmlinux-initramfs.elf $(VMLINUX)-initramfs.elf
+ cp $(KDIR)/vmlinux-initramfs $(VMLINUX)-initramfs.bin
+ dd if=$(KDIR)/vmlinux-initramfs.bin.lzma of=$(VMLINUX)-initramfs.lzma bs=65536 conv=sync
+ dd if=$(KDIR)/vmlinux-initramfs.bin.gz of=$(VMLINUX)-initramfs.gz bs=65536 conv=sync
+ $(call MkuImage,gzip,,$(KDIR)/vmlinux-initramfs.bin.gz,$(UIMAGE)-initramfs-gzip.bin)
+ $(call MkuImage,lzma,,$(KDIR)/vmlinux-initramfs.bin.lzma,$(UIMAGE)-initramfs-lzma.bin)
+ cp $(KDIR)/loader-generic-initramfs.elf $(VMLINUX)-initramfs-lzma.elf
+ $(call Image/Build/Initramfs)
+endef
+
+Image/Build/WRT400N/buildkernel=$(call MkuImageLzma,$(2),$(3))
+
+define Image/Build/WRT400N
+ $(call Sysupgrade/KRuImage,$(1),$(2),1310720,6488064)
+ if [ -e "$(call sysupname,$(1),$(2))" ]; then \
+ wrt400n $(KDIR_TMP)/vmlinux-$(2).uImage $(KDIR)/root.$(1) $(call factoryname,$(1),$(2)); \
+ fi
+endef
+
+
+define Image/Build/CameoAP94/buildkernel
+ $(call MkuImageLzma,$(2),$(3) $(4))
+ $(call MkuImageLzma,$(2)-fat,$(3) $(5))
+endef
+
+define Image/Build/CameoAP94
+ $(eval fwsize=$(call mtdpartsize,firmware,$(4)))
+ $(eval fwsize_fat=$(call mtdpartsize,firmware,$(5)))
+ $(call Sysupgrade/KRuImage,$(1),$(2),0,$$$$(($(fwsize)-4*64*1024)),64)
+ if [ -e "$(call sysupname,$(1),$(2))" ]; then \
+ ( \
+ dd if=$(call sysupname,$(1),$(2)); \
+ echo -n "$(6)"; \
+ ) > $(call imgname,$(1),$(2))-backup-loader.bin; \
+ if [ `stat -c%s $(call sysupname,$(1),$(2))` -gt 4194304 ]; then \
+ echo "Warning: $(call sysupname,$(1),$(2)) is too big" >&2; \
+ else \
+ ( \
+ dd if=$(call sysupname,$(1),$(2)) bs=4096k conv=sync; \
+ echo -n "$(7)"; \
+ ) > $(call factoryname,$(1),$(2)); \
+ fi; \
+ fi
+ $(call CatFiles,$(KDIR_TMP)/vmlinux-$(2)-fat.uImage,0,$(KDIR)/root.$(1),$$$$(($(fwsize_fat)-4*64*1024)),$(KDIR_TMP)/$(2)-fat.bin,64)
+ if [ -e "$(KDIR_TMP)/$(2)-fat.bin" ]; then \
+ echo -n "" > $(KDIR_TMP)/$(2)-fat.dummy; \
+ sh $(TOPDIR)/scripts/combined-image.sh \
+ "$(KDIR_TMP)/$(2)-fat.bin" \
+ "$(KDIR_TMP)/$(2)-fat.dummy" \
+ $(call sysupname,$(1),$(2)-fat); \
+ fi
+endef
+
+define Image/Build/WZRHP
+ $(call Sysupgrade/KRuImage,$(1),$(2),0,$$$$(($(3)-4*$(4)*1024)),$(4))
+ if [ -e "$(call sysupname,$(1),$(2))" ]; then \
+ ( \
+ echo -n -e "# Airstation Public Fmt1\x00\x00\x00\x00\x00\x00\x00\x00"; \
+ dd if=$(call sysupname,$(1),$(2)); \
+ ) > $(call imgname,$(1),$(2))-tftp.bin; \
+ buffalo-enc -p $(5) -v 1.99 \
+ -i $(call sysupname,$(1),$(2)) \
+ -o $(KDIR_TMP)/$(2).enc; \
+ buffalo-tag -b $(5) -p $(5) -a ath -v 1.99 -m 1.01 -l mlang8 \
+ -w 3 -c 0x80041000 -d 0x801e8000 -f 1 -r M_ \
+ -i $(KDIR_TMP)/$(2).enc \
+ -o $(call factoryname,$(1),$(2)); \
+ fi
+endef
+
+Image/Build/WZRHP64K/buildkernel=$(call MkuImageLzma,$(2),$(3))
+Image/Build/WZRHP64K/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
+Image/Build/WZRHP64K=$(call Image/Build/WZRHP,$(1),$(2),33095680,64,$(4))
+
+Image/Build/WZRHP128K/buildkernel=$(call MkuImageLzma,$(2),$(3))
+Image/Build/WZRHP128K/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
+Image/Build/WZRHP128K=$(call Image/Build/WZRHP,$(1),$(2),33030144,128,$(4))
+
+
+Image/Build/WHRHPG300N/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4))
+Image/Build/WHRHPG300N/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
+
+define Image/Build/WHRHPG300N
+ $(eval fwsize=$(call mtdpartsize,firmware,$(4)))
+ $(call Sysupgrade/KRuImage,$(1),$(2),0,$$$$(($(fwsize)-4*64*1024)),64)
+ if [ -e "$(call sysupname,$(1),$(2))" ]; then \
+ ( \
+ echo -n -e "# Airstation Public Fmt1\x00\x00\x00\x00\x00\x00\x00\x00"; \
+ dd if=$(call sysupname,$(1),$(2)); \
+ ) > $(call imgname,$(1),$(2))-tftp.bin; \
+ buffalo-enc -p $(5) -v 1.99 \
+ -i $(call sysupname,$(1),$(2)) \
+ -o $(KDIR_TMP)/$(2).enc; \
+ buffalo-tag -b $(5) -p $(5) -a ath -v 1.99 -m 1.01 -l mlang8 \
+ -w 3 -c 0x80041000 -d 0x801e8000 -f 1 -r M_ \
+ -i $(KDIR_TMP)/$(2).enc \
+ -o $(call factoryname,$(1),$(2)); \
+ fi
+endef
+
+
+define Image/Build/Cameo
+ $(eval fwsize=$(call mtdpartsize,firmware,$(4)))
+ $(call Sysupgrade/KRuImage,$(1),$(2),0,$$$$(($(fwsize)-4*64*1024)),64)
+ if [ -e "$(call sysupname,$(1),$(2))" ]; then \
+ factory_size=$$$$(($(fwsize) - $(6))); \
+ ( \
+ dd if=$(call sysupname,$(1),$(2)) bs=$$$${factory_size} conv=sync; \
+ echo -n $(5); \
+ ) > $(call factoryname,$(1),$(2)); \
+ fi
+endef
+
+Image/Build/CameoAP81/buildkernel=$(call MkuImageLzma,$(2),$(3) $(cameo_ap81_mtdlayout))
+Image/Build/CameoAP81=$(call Image/Build/Cameo,$(1),$(2),$(3),$(cameo_ap81_mtdlayout),$(4),65536)
+Image/Build/CameoAP81/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(cameo_ap81_mtdlayout))
+
+Image/Build/CameoAP91/buildkernel=$(call MkuImageLzma,$(2),$(3) $(cameo_ap91_mtdlayout))
+Image/Build/CameoAP91=$(call Image/Build/Cameo,$(1),$(2),$(3),$(cameo_ap91_mtdlayout),$(4),65536)
+Image/Build/CameoAP91/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(cameo_ap91_mtdlayout))
+
+Image/Build/CameoAP99/buildkernel=$(call MkuImageLzma,$(2),$(3) $(cameo_ap99_mtdlayout))
+Image/Build/CameoAP99=$(call Image/Build/Cameo,$(1),$(2),$(3),$(cameo_ap99_mtdlayout),$(4),65536)
+Image/Build/CameoAP99/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(cameo_ap99_mtdlayout))
+
+Image/Build/CameoAP123_4M/buildkernel=$(call MkuImageLzma,$(2),$(3) $(cameo_ap123_mtdlayout_4M))
+Image/Build/CameoAP123_4M=$(call Image/Build/Cameo,$(1),$(2),$(3),$(cameo_ap123_mtdlayout_4M),$(4),26)
+Image/Build/CameoAP123_4M/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(cameo_ap123_mtdlayout_4M))
+
+Image/Build/CameoAP135/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4))
+Image/Build/CameoAP135=$(call Image/Build/Cameo,$(1),$(2),$(3),$(4),$(5),26)
+Image/Build/CameoAP135/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
+
+Image/Build/CameoDB120/buildkernel=$(call MkuImageLzma,$(2),$(3) $(cameo_db120_mtdlayout))
+Image/Build/CameoDB120=$(call Image/Build/Cameo,$(1),$(2),$(3),$(cameo_db120_mtdlayout),$(4),26)
+Image/Build/CameoDB120/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(cameo_db120_mtdlayout))
+
+Image/Build/CameoDB120_8M/buildkernel=$(call MkuImageLzma,$(2),$(3) $(cameo_db120_mtdlayout_8M))
+Image/Build/CameoDB120_8M=$(call Image/Build/Cameo,$(1),$(2),$(3),$(cameo_db120_mtdlayout_8M),$(4),26)
+Image/Build/CameoDB120_8M/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(cameo_db120_mtdlayout_8M))
+
+define Image/Build/CameoHornet
+ $(eval fwsize=$(call mtdpartsize,firmware,$(4)))
+ $(call Sysupgrade/KRuImage,$(1),$(2),0,$$$$(($(fwsize)-4*64*1024)),64)
+ if [ -e "$(call sysupname,$(1),$(2))" ]; then \
+ for r in $(7); do \
+ [ -n "$$$$r" ] && dashr="-$$$$r" || dashr=; \
+ [ -z "$$$$r" ] && r="DEF"; \
+ mkcameofw -M HORNET -R "$$$$r" -S $(5) -V $(6) -c \
+ -K $(8) -I $(fwsize) \
+ -k "$(call sysupname,$(1),$(2))" \
+ -o $(call imgname,$(1),$(2))-factory$$$$dashr.bin; \
+ true; \
+ done; \
+ fi
+endef
+
+Image/Build/CameoAP121/buildkernel=$(call MkuImageLzma,$(2),$(3) $(cameo_ap121_mtdlayout))
+Image/Build/CameoAP121=$(call Image/Build/CameoHornet,$(1),$(2),$(3),$(cameo_ap121_mtdlayout),$(4),$(5),$(6),0xe0000)
+Image/Build/CameoAP121/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(cameo_ap121_mtdlayout))
+
+Image/Build/CameoAP121_8M/buildkernel=$(call MkuImageLzma,$(2),$(3) $(cameo_ap121_mtdlayout_8M))
+Image/Build/CameoAP121_8M=$(call Image/Build/CameoHornet,$(1),$(2),$(3),$(cameo_ap121_mtdlayout_8M),$(4),$(5),$(6),0x100000)
+Image/Build/CameoAP121_8M/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(cameo_ap121_mtdlayout_8M))
+
+define Image/Build/dLAN
+ $(eval fwsize=$(call mtdpartsize,firmware,$(4)))
+ $(eval rootsize=$(call mtdpartsize,rootfs,$(4)))
+ $(eval kernsize=$(call mtdpartsize,kernel,$(4)))
+ $(call Sysupgrade/$(5),$(1),$(2),$(if $(6),$(6),$(kernsize)),$(if $(rootsize),$(rootsize),$(fwsize)))
+ if [ -e "$(call factoryname,$(1),$(2))" ]; then \
+ dd if=$(KDIR_TMP)/vmlinux-$(2).uImage \
+ of=$(call imgname,kernel,$(2)).bin bs=64k conv=sync; \
+ dd if=$(KDIR)/root.$(1) \
+ of=$(call imgname,$(1),$(2)-rootfs).bin bs=128k conv=sync; \
+ fi
+endef
+
+Image/Build/dLANLzma/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4))
+Image/Build/dLANLzma=$(call Image/Build/dLAN,$(1),$(2),$(3),$(4),$(5),$(6),$(7))
+Image/Build/dLANLzma/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
+
+define Image/Build/Ath
+ $(eval fwsize=$(call mtdpartsize,firmware,$(4)))
+ $(eval rootsize=$(call mtdpartsize,rootfs,$(4)))
+ $(eval kernsize=$(call mtdpartsize,kernel,$(4)))
+ $(call Sysupgrade/$(5),$(1),$(2),$(if $(6),$(6),$(kernsize)),$(if $(rootsize),$(rootsize),$(fwsize)))
+ if [ -e "$(call sysupname,$(1),$(2))" ]; then \
+ dd if=$(KDIR_TMP)/vmlinux-$(2).uImage \
+ of=$(call imgname,kernel,$(2)).bin bs=64k conv=sync; \
+ dd if=$(KDIR)/root.$(1) \
+ of=$(call imgname,$(1),$(2)-rootfs).bin bs=128k conv=sync; \
+ fi
+endef
+
+Image/Build/AthGzip/buildkernel=$(call MkuImageGzip,$(2),$(3) $(4))
+Image/Build/AthGzip=$(call Image/Build/Ath,$(1),$(2),$(3),$(4),$(5),$(6),$(7))
+Image/Build/AthGzip/initramfs=$(call MkuImageGzip/initramfs,$(2),$(3) $(4))
+
+Image/Build/AthLzma/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4))
+Image/Build/AthLzma=$(call Image/Build/Ath,$(1),$(2),$(3),$(4),$(5),$(6),$(7))
+Image/Build/AthLzma/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
+
+
+Image/Build/Belkin/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4))
+Image/Build/Belkin/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
+
+define Image/Build/Belkin
+ $(eval fwsize=$(call mtdpartsize,firmware,$(4)))
+ $(eval kernsize=$(call mtdpartsize,kernel,$(4)))
+ $(eval rootsize=$(call mtdpartsize,rootfs,$(4)))
+ $(call Sysupgrade/RKuImage,$(1),$(2),$(kernsize),$(rootsize))
+ if [ -e "$(call sysupname,$(1),$(2))" ]; then \
+ edimax_fw_header -m $(5) -v "OpenWrt$(REVISION)" \
+ -n "uImage" \
+ -i $(KDIR_TMP)/vmlinux-$(2).uImage \
+ -o $(KDIR_TMP)/$(2)-uImage; \
+ edimax_fw_header -m $(5) -v "OpenWrt$(REVISION)" \
+ -n "rootfs" \
+ -i $(KDIR)/root.$(1) \
+ -o $(KDIR_TMP)/$(2)-rootfs; \
+ ( \
+ dd if=$(KDIR_TMP)/$(2)-rootfs; \
+ dd if=$(KDIR_TMP)/$(2)-uImage; \
+ ) > "$(call factoryname,$(1),$(2))"; \
+ fi
+endef
+
+define Image/Build/EnGenius
+ $(eval fwsize=$(call mtdpartsize,firmware,$(4)))
+ $(eval rootsize=$(call mtdpartsize,rootfs,$(4)))
+ $(eval kernsize=$(call mtdpartsize,kernel,$(4)))
+ $(call Sysupgrade/$(5),$(1),$(2),$(if $(6),$(6),$(kernsize)),$(if $(rootsize),$(rootsize),$(fwsize)))
+ if [ -e "$(call sysupname,$(1),$(2))" ]; then \
+ dd if=$(KDIR_TMP)/vmlinux-$(2).uImage \
+ of=$(call imgname,kernel,$(2)).bin bs=64k conv=sync; \
+ dd if=$(KDIR)/root.$(1) \
+ of=$(call imgname,$(1),$(2)-rootfs).bin bs=128k conv=sync; \
+ mksenaofw -e $(call sysupname,$(1),$(2)) \
+ -o $(call imgname,$(1),$(2))-factory.dlf \
+ -r 0x101 -p $(7) -t 2; \
+ fi
+endef
+
+Image/Build/EnGenius/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4))
+Image/Build/EnGenius/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
+
+
+define MkuImageHiWiFi
+ # Field ih_name needs to start with "tw150v1"
+ mkimage -A mips -O linux -T kernel -a 0x80060000 -C $(1) $(2) \
+ -e 0x80060000 -n 'tw150v1 MIPS OpenWrt Linux-$(LINUX_VERSION)' \
+ -d $(3) $(4)
+endef
+
+define MkuImageLzmaHiWiFi
+ $(call PatchKernelLzma,$(1),$(2),$(3),$(4))
+ $(call MkuImageHiWiFi,lzma,$(5),$(KDIR_TMP)/vmlinux$(4)-$(1).bin.lzma,$(KDIR_TMP)/vmlinux$(4)-$(1).uImage)
+endef
+
+Image/Build/HiWiFi/buildkernel=$(call MkuImageLzmaHiWiFi,$(2),$(3) $(4))
+Image/Build/HiWiFi=$(call Image/Build/Ath,$(1),$(2),$(3),$(4),$(5),$(6),$(7))
+Image/Build/HiWiFi/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
+
+Image/Build/PB4X/buildkernel=$(call PatchKernelLzma,$(2),$(3))
+
+define Image/Build/PB4X
+ dd if=$(KDIR_TMP)/vmlinux-$(2).bin.lzma \
+ of=$(call imgname,kernel,$(2)).bin bs=64k conv=sync
+ dd if=$(KDIR)/root.$(1) \
+ of=$(call imgname,$(1),$(2)-rootfs).bin bs=128k conv=sync
+ -sh $(TOPDIR)/scripts/combined-image.sh \
+ "$(call imgname,kernel,$(2)).bin" \
+ "$(call imgname,$(1),$(2)-rootfs).bin" \
+ $(call sysupname,$(1),$(2))
+endef
+
+
+Image/Build/MyLoader/buildkernel=$(call PatchKernelLzma,$(2),$(3))
+Image/Build/MyLoader/initramfs=$(call PatchKernel/initramfs,$(2),$(3))
+
+define Image/Build/MyLoader
+ $(eval fwsize=$(shell echo $$(($(4)-0x30000-4*64*1024))))
+ $(eval fwimage=$(KDIR_TMP)/$(2)-$(5)-firmware.bin)
+ $(call CatFiles,$(KDIR_TMP)/vmlinux-$(2).bin.lzma,65536,$(KDIR)/root.$(1),$(fwsize),$(fwimage))
+ if [ -e "$(fwimage)" ]; then \
+ $(STAGING_DIR_HOST)/bin/mkmylofw -B $(2) -s $(4) -v \
+ -p0x00030000:0:al:0x80060000:firmware:$(fwimage) \
+ $(call imgname,$(1),$(2))-$(5)-factory.img; \
+ echo -n "" > $(KDIR_TMP)/empty.bin; \
+ sh $(TOPDIR)/scripts/combined-image.sh \
+ $(fwimage) $(KDIR_TMP)/empty.bin \
+ $(call imgname,$(1),$(2))-$(5)-sysupgrade.bin; \
+ fi
+endef
+
+Image/Build/Planex/initramfs=$(call MkuImageGzip/initramfs,$(2),$(3) $(planex_mtdlayout))
+Image/Build/Planex/loader=$(call Image/BuildLoaderAlone,$(1),gz,$(2) $(planex_mtdlayout),0x52000,0)
+
+define Image/Build/Planex/buildkernel
+ [ -e "$(KDIR)/loader-$(2).gz" ]
+ $(call MkuImageOKLI,$(2))
+ ( \
+ dd if=$(KDIR)/loader-$(2).gz bs=8128 count=1 conv=sync; \
+ dd if=$(KDIR_TMP)/vmlinux-$(2).okli; \
+ ) > $(KDIR_TMP)/kernel-$(2).bin
+ $(call MkuImage,gzip,,$(KDIR_TMP)/kernel-$(2).bin,$(KDIR_TMP)/vmlinux-$(2).uImage)
+endef
+
+define Image/Build/Planex
+ $(eval fwsize=$(call mtdpartsize,firmware,$(planex_mtdlayout)))
+ $(call Sysupgrade/KRuImage,$(1),$(2),0,$$$$(($(fwsize)-4*64*1024)),64)
+ if [ -e "$(call sysupname,$(1),$(2))" ]; then \
+ $(STAGING_DIR_HOST)/bin/mkplanexfw \
+ -B $(2) \
+ -v 2.00.00 \
+ -i $(call sysupname,$(1),$(2)) \
+ -o $(call factoryname,$(1),$(2)); \
+ fi
+endef
+
+
+Image/Build/ALFA/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4))
+Image/Build/ALFA/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
+
+define Image/Build/ALFA
+ $(call Sysupgrade/RKuImage,$(1),$(2),$(5),$(6))
+ if [ -e "$(call sysupname,$(1),$(2))" ]; then \
+ rm -rf $(KDIR)/$(1); \
+ mkdir -p $(KDIR)/$(1); \
+ cd $(KDIR)/$(1); \
+ cp $(KDIR_TMP)/vmlinux-$(2).uImage $(KDIR)/$(1)/$(7); \
+ cp $(KDIR)/root.$(1) $(KDIR)/$(1)/$(8); \
+ $(TAR) zcf $(call factoryname,$(1),$(2)) -C $(KDIR)/$(1) $(7) $(8); \
+ ( \
+ echo WRM7222C | dd bs=32 count=1 conv=sync; \
+ echo -ne '\xfe'; \
+ ) >> $(call factoryname,$(1),$(2)); \
+ fi
+endef
+
+
+Image/Build/Seama/loader=$(call Image/BuildLoader,$(1),bin,$(2) $(3),0x80060000)
+
+define Image/Build/Seama
+ [ -e "$(KDIR)/loader-$(2).bin" ]
+ $(call CompressLzma,$(KDIR)/loader-$(2).bin,$(KDIR_TMP)/loader-$(2).bin.lzma)
+ -rm -f $(KDIR_TMP)/image-$(2).tmp
+ $(call CatFiles,$(KDIR_TMP)/loader-$(2).bin.lzma,$$$$(($(6) - 64)),$(KDIR)/root.$(1),$(7),$(KDIR_TMP)/image-$(2).tmp)
+ [ -e "$(KDIR_TMP)/image-$(2).tmp" ] && { \
+ head -c -4 "$(KDIR_TMP)/image-$(2).tmp" > "$(KDIR_TMP)/image-$(2).no-jffs2mark.tmp"; \
+ $(STAGING_DIR_HOST)/bin/seama \
+ -i $(KDIR_TMP)/image-$(2).no-jffs2mark.tmp \
+ -m "dev=/dev/mtdblock/1" -m "type=firmware"; \
+ $(STAGING_DIR_HOST)/bin/seama \
+ -s $(call imgname,$(1),$(2))-factory.bin \
+ -m "signature=$(5)" \
+ -i $(KDIR_TMP)/image-$(2).no-jffs2mark.tmp.seama; \
+ tail -c 4 "$(KDIR_TMP)/image-$(2).tmp" >> $(call imgname,$(1),$(2))-factory.bin; \
+ }
+ cat $(KDIR_TMP)/loader-$(2).bin.lzma > $(KDIR_TMP)/image-$(2)-sysupgrade.tmp
+ $(STAGING_DIR_HOST)/bin/seama \
+ -i $(KDIR_TMP)/image-$(2)-sysupgrade.tmp \
+ -m "dev=/dev/mtdblock/1" -m "type=firmware"
+ $(call CatFiles,$(KDIR_TMP)/image-$(2)-sysupgrade.tmp.seama,$(6),$(KDIR)/root.$(1),$(7),$(call sysupname,$(1),$(2)))
+endef
+
+define Image/Build/Seama/initramfs
+ $(call PatchKernelLzma,$(2),$(3) $(4),,-initramfs)
+ $(STAGING_DIR_HOST)/bin/seama \
+ -i $(KDIR_TMP)/vmlinux-initramfs-$(2).bin.lzma \
+ -m "dev=/dev/mtdblock/1" -m "type=firmware"
+ cat $(KDIR_TMP)/vmlinux-initramfs-$(2).bin.lzma.seama > $(call imgname,initramfs,$(2))-seama.bin
+endef
+
+Image/Build/Senao/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4))
+Image/Build/Senao/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
+
+define Image/Build/Senao
+ mkdir -p $(KDIR_TMP)/$(2)/
+ touch $(KDIR_TMP)/$(2)/FWINFO-OpenWrt-$(REVISION)-$(2)
+ -$(CP) ./$(2)/* $(KDIR_TMP)/$(2)/
+ dd if=$(KDIR_TMP)/vmlinux-$(2).uImage \
+ of=$(KDIR_TMP)/$(2)/openwrt-senao-$(2)-uImage-lzma.bin bs=64k conv=sync
+ dd if=$(KDIR)/root.$(1) \
+ of=$(KDIR_TMP)/$(2)/openwrt-senao-$(2)-root.$(1) bs=64k conv=sync
+ ( \
+ cd $(KDIR_TMP)/$(2)/; \
+ $(TAR) -cz -f $(call factoryname,$(1),$(2)) * \
+ )
+ -rm -rf $(KDIR_TMP)/$(2)/
+ -sh $(TOPDIR)/scripts/combined-image.sh \
+ $(KDIR_TMP)/vmlinux-$(2).uImage \
+ $(KDIR)/root.$(1) \
+ $(call sysupname,$(1),$(2))
+endef
+
+define Image/Build/CyberTAN
+ echo -n '' > $(KDIR_TMP)/empty.bin
+ $(STAGING_DIR_HOST)/bin/trx -o $(KDIR)/image.tmp \
+ -f $(KDIR_TMP)/vmlinux-$(2).uImage -F $(KDIR_TMP)/empty.bin \
+ -x 32 -a 0x10000 -x -32 -f $(KDIR)/root.$(1)
+ -$(STAGING_DIR_HOST)/bin/addpattern -B $(2) -v v$(5) \
+ -i $(KDIR)/image.tmp \
+ -o $(call sysupname,$(1),$(2))
+ $(STAGING_DIR_HOST)/bin/trx -o $(KDIR)/image.tmp -f $(KDIR_TMP)/vmlinux-$(2).uImage \
+ -x 32 -a 0x10000 -x -32 -f $(KDIR)/root.$(1)
+ -$(STAGING_DIR_HOST)/bin/addpattern -B $(2) -v v$(5) -g \
+ -i $(KDIR)/image.tmp \
+ -o $(call factoryname,$(1),$(2))
+ rm $(KDIR)/image.tmp
+endef
+
+Image/Build/CyberTANGZIP/loader=$(call Image/BuildLoader,$(1),gz,$(2),0x80060000)
+Image/Build/CyberTANGZIP/buildkernel=$(call MkuImage,gzip,,$(KDIR)/loader-$(2).gz,$(KDIR_TMP)/vmlinux-$(2).uImage)
+Image/Build/CyberTANGZIP=$(call Image/Build/CyberTAN,$(1),$(2),$(3),$(4),$(5))
+
+Image/Build/CyberTANLZMA/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4))
+Image/Build/CyberTANLZMA=$(call Image/Build/CyberTAN,$(1),$(2),$(3),$(4),$(5))
+
+
+Image/Build/Netgear/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4),,-M $(5))
+
+define Image/Build/Netgear/buildkernel
+ $(call MkuImageLzma,$(2),$(3) $(4),-d20,,-M $(5))
+ -rm -rf $(KDIR_TMP)/$(2)
+ mkdir -p $(KDIR_TMP)/$(2)/image
+ cat $(KDIR_TMP)/vmlinux-$(2).uImage > $(KDIR_TMP)/$(2)/image/uImage
+ $(STAGING_DIR_HOST)/bin/mksquashfs-lzma \
+ $(KDIR_TMP)/$(2) $(KDIR_TMP)/vmlinux-$(2).uImage.squashfs.tmp1 \
+ -noappend -root-owned -be -b 65536 \
+ $(if $(SOURCE_DATE_EPOCH),-fixed-time $(SOURCE_DATE_EPOCH))
+ ( \
+ cat $(KDIR_TMP)/vmlinux-$(2).uImage.squashfs.tmp1; \
+ dd if=/dev/zero bs=1k count=1 \
+ ) > $(KDIR_TMP)/vmlinux-$(2).uImage.squashfs.tmp2
+ mkimage -A mips -O linux -T filesystem -C none -M $(5) \
+ -a 0xbf070000 -e 0xbf070000 \
+ -n 'MIPS OpenWrt Linux-$(LINUX_VERSION)' \
+ -d $(KDIR_TMP)/vmlinux-$(2).uImage.squashfs.tmp2 \
+ $(KDIR_TMP)/vmlinux-$(2).uImage.squashfs
+endef
+
+define Image/Build/Netgear
+ $(eval fwsize=$(call mtdpartsize,firmware,$(4)))
+ $(call CatFiles,$(KDIR_TMP)/vmlinux-$(2).uImage.squashfs,0,$(KDIR)/root.$(1),$(fwsize),$(call sysupname,$(1),$(2)),64)
+ if [ -e $(call sysupname,$(1),$(2)) ]; then \
+ for r in $(7) ; do \
+ [ -n "$$$$r" ] && dashr="-$$$$r" || dashr= ; \
+ $(STAGING_DIR_HOST)/bin/mkdniimg \
+ -B $(6) -v OpenWrt.$(REVISION) -r "$$$$r" $(8) \
+ -i $(call sysupname,$(1),$(2)) \
+ -o $(call imgname,$(1),$(2))-factory$$$$dashr.img; \
+ done; \
+ fi
+endef
+
+
+Image/Build/NetgearLzma/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4),,-M $(5))
+Image/Build/NetgearLzma/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4),-d20,,-M $(5))
+
+define Image/Build/NetgearLzma
+ $(eval fwsize=$(call mtdpartsize,firmware,$(4)))
+ $(call CatFiles,$(KDIR_TMP)/vmlinux-$(2).uImage,0,$(KDIR)/root.$(1),$(fwsize),$(call sysupname,$(1),$(2)),64)
+endef
+
+
+Image/Build/NetgearNAND/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4),,-M $(5))
+
+# $(1): (empty)
+# $(2): Board name (small caps)
+# $(3): Kernel board specific cmdline
+# $(4): Kernel mtdparts definition
+# $(5): U-Boot magic
+define Image/Build/NetgearNAND/buildkernel
+ $(eval kernelsize=$(call mtdpartsize,kernel,$(4)))
+ $(call PatchKernelLzma,$(2),$(3) $(4),-d20)
+ dd if=$(KDIR_TMP)/vmlinux-$(2).bin.lzma \
+ of=$(KDIR_TMP)/vmlinux-$(2).bin.tmp \
+ bs=$$$$(($(kernelsize)-131072-2*64-1)) \
+ count=1 conv=sync
+ $(call MkuImage,lzma,-M $(5),$(KDIR_TMP)/vmlinux-$(2).bin.tmp,$(KDIR_TMP)/vmlinux-$(2).uImage)
+ echo -ne '\xff' >> $(KDIR_TMP)/vmlinux-$(2).uImage
+ # create a fake rootfs image
+ dd if=/dev/zero of=$(KDIR_TMP)/fakeroot-$(2) bs=131072 count=1
+ mkimage -A mips -O linux -T filesystem -C none \
+ -a 0xbf070000 -e 0xbf070000 \
+ -n 'MIPS OpenWrt fakeroot' \
+ -d $(KDIR_TMP)/fakeroot-$(2) \
+ -M $(5) \
+ $(KDIR_TMP)/fakeroot-$(2).uImage
+ # append the fake rootfs image to the kernel, it will reside in the last
+ # erase block of the kernel partition
+ cat $(KDIR_TMP)/fakeroot-$(2).uImage >> $(KDIR_TMP)/vmlinux-$(2).uImage
+endef
+
+
+# $(1): rootfs image suffix
+# $(2): Board name (small caps)
+# $(3): Kernel board specific cmdline
+# $(4): Kernel mtdparts definition
+# $(5): U-Boot magic
+# $(6): Board name (upper caps)
+# $(7): firmware region code (not used yet)
+# $(8): DNI Hardware version
+# $(9): suffix of the configuration file for ubinize
+define Image/Build/NetgearNAND
+ $(eval firmwaresize=$(call mtdpartsize,firmware,$(4)))
+ $(eval kernelsize=$(call mtdpartsize,kernel,$(4)))
+ $(eval imageraw=$(KDIR_TMP)/$(2)-raw.img)
+ $(CP) $(KDIR)/root.squashfs-raw $(KDIR_TMP)/root.squashfs
+ echo -ne '\xde\xad\xc0\xde' > $(KDIR_TMP)/jffs2.eof
+ $(call ubinize,ubinize-$(9).ini,$(KDIR_TMP),$(KDIR_TMP)/$(2)-root.ubi,128KiB,2048,-E 5)
+ ( \
+ dd if=$(KDIR_TMP)/vmlinux-$(2).uImage; \
+ dd if=$(KDIR_TMP)/$(2)-root.ubi \
+ ) > $(imageraw)
+ $(STAGING_DIR_HOST)/bin/mkdniimg \
+ -B $(6) -v OpenWrt.$(REVISION) -r "$$$$r" $(8) \
+ -i $(imageraw) \
+ -o $(call imgname,ubi,$(2))-factory.img
+
+ $(call Image/Build/SysupgradeNAND,$(2),squashfs,$(KDIR_TMP)/vmlinux-$(2).uImage)
+endef
+
+
+ifdef CONFIG_PACKAGE_uboot-ar71xx-nbg460n_550n_550nh
+ Image/Build/ZyXEL/buildkernel=$(call MkuImageLzma,$(2),$(3))
+
+ define Image/Build/ZyXEL
+ $(call Sysupgrade/KRuImage,$(1),$(2),917504,2752512)
+ if [ -e "$(call sysupname,$(1),$(2))" ]; then \
+ if [ ! -f $(BIN_DIR)/$(IMG_PREFIX)-$(2)-u-boot.bin ]; then \
+ echo "Warning: $(IMG_PREFIX)-$(2)-u-boot.bin not found" >&2; \
+ else \
+ $(STAGING_DIR_HOST)/bin/mkzynfw \
+ -B $(4) \
+ -b $(BIN_DIR)/$(IMG_PREFIX)-$(2)-u-boot.bin \
+ -r $(call sysupname,$(1),$(2)):0x10000 \
+ -o $(call factoryname,$(1),$(2)); \
+ fi; fi
+ endef
+endif
+
+define Image/Build/ZyXELNAND/buildkernel
+ $(eval kernelsize=$(call mtdpartsize,kernel,$(5)))
+ $(call MkuImageLzma,$(2),$(3) $(5) $(6))
+ mkdir -p $(KDIR_TMP)/$(2)/image/boot
+ cp $(KDIR_TMP)/vmlinux-$(2).uImage $(KDIR_TMP)/$(2)/image/boot/vmlinux.lzma.uImage
+ $(STAGING_DIR_HOST)/bin/mkfs.jffs2 \
+ --pad=$(kernelsize) --big-endian --squash-uids -v -e 128KiB \
+ -o $(KDIR_TMP)/$(2)-kernel.jffs2 \
+ -d $(KDIR_TMP)/$(2)/image \
+ 2>&1 1>/dev/null | awk '/^.+$$$$/'
+ -rm -rf $(KDIR_TMP)/$(2)
+endef
+
+define Image/Build/ZyXELNAND
+ if [ "$(1)" != "squashfs" ]; then \
+ echo Only squashfs is supported; \
+ return 0; \
+ fi
+ $(eval firmwaresize=$(call mtdpartsize,firmware,$(4)))
+ $(eval kernelsize=$(call mtdpartsize,kernel,$(4)))
+ $(eval imageraw=$(KDIR_TMP)/$(2)-raw.img)
+ $(CP) $(KDIR)/root.$(1) $(KDIR_TMP)/ubi_root.img
+ $(call ubinize,ubinize-$(2).ini,$(KDIR_TMP),$(KDIR_TMP)/$(2)-root.ubi,128KiB,2048,-E 5)
+ ( \
+ dd if=$(KDIR_TMP)/$(2)-kernel.jffs2; \
+ dd if=$(KDIR_TMP)/$(2)-root.ubi \
+ ) > $(imageraw)
+ dd if=$(imageraw) of=$(BIN_DIR)/$(IMG_PREFIX)-$(2)-$(1)-factory.bin \
+ bs=128k conv=sync
+ $(call Image/Build/SysupgradeNAND,$(2),squashfs,$(KDIR_TMP)/$(2)-kernel.jffs2)
+endef
+
+
+Image/Build/OpenMesh/buildkernel=$(call MkuImageLzma,$(2))
+Image/Build/OpenMesh/initramfs=$(call MkuImageLzma/initramfs,$(2),)
+
+define Image/Build/OpenMesh
+ -sh $(TOPDIR)/scripts/om-fwupgradecfg-gen.sh \
+ "$(4)" \
+ "$(BUILD_DIR)/fwupgrade.cfg-$(4)" \
+ "$(KDIR_TMP)/vmlinux-$(2).uImage" \
+ "$(KDIR)/root.$(1)"
+ -sh $(TOPDIR)/scripts/combined-ext-image.sh \
+ "$(4)" "$(call factoryname,$(1),$(2))" \
+ "$(BUILD_DIR)/fwupgrade.cfg-$(4)" "fwupgrade.cfg" \
+ "$(KDIR_TMP)/vmlinux-$(2).uImage" "kernel" \
+ "$(KDIR)/root.$(1)" "rootfs"
+ if [ -e "$(call factoryname,$(1),$(2))" ]; then \
+ cp "$(call factoryname,$(1),$(2))" "$(call sysupname,$(1),$(2))"; \
+ fi
+endef
+
+
+Image/Build/Zcomax/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4))
+Image/Build/Zcomax/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
+
+define Image/Build/Zcomax
+ $(call Sysupgrade/RKuImage,$(1),$(2),1507328,6356992)
+ if [ -e "$(call sysupname,$(1),$(2))" ]; then \
+ $(STAGING_DIR_HOST)/bin/mkzcfw \
+ -B $(2) \
+ -k $(KDIR_TMP)/vmlinux-$(2).uImage \
+ -r $(BIN_DIR)/$(IMG_PREFIX)-root.$(1) \
+ -o $(call imgname,$(1),$(2))-factory.img; \
+ fi
+endef
+
+
+# $(1): template name to be defined, etc. squashfs-only, 64k, 64kraw, etc.
+# $(2): jffs2 blocksize.
+define Jffs2Template
+ define Image/Build/Template/$(1)/jffs2-$(2)
+ $$(call Image/Build/$$(1),jffs2-$(2),$$(2),$$(3),$$(4),$$(5),$$(6),$$(7),$$(8),$$(9),$$(10))
+ endef
+endef
+
+# $(1): template name to be defined.
+# $(2): squashfs suffix to be used.
+# $(3): jffs2 suffix to be used.
+define BuildTemplate
+ # $(1) : name of build method.
+ # $(2) : board name.
+ # $(3) : kernel command line.
+ # $(4)~$(8): extra arguments.
+ define Image/Build/Template/$(1)/initramfs
+ $$(call Image/Build/$$(1)/initramfs,initramfs,$$(2),$$(3),$$(4),$$(5),$$(6),$$(7),$$(8),$$(9),$$(10))
+ endef
+ define Image/Build/Template/$(1)/loader
+ $$(call Image/Build/$$(1)/loader,$$(2),$$(3),$$(4),$$(5),$$(6),$$(7),$$(8),$$(9),$$(10))
+ endef
+ define Image/Build/Template/$(1)/buildkernel
+ $$(call Image/Build/$$(1)/buildkernel,,$$(2),$$(3),$$(4),$$(5),$$(6),$$(7),$$(8),$$(9),$$(10))
+ endef
+ define Image/Build/Template/$(1)/squashfs
+ $$(call Image/Build/$$(1),squashfs$(2),$$(2),$$(3),$$(4),$$(5),$$(6),$$(7),$$(8),$$(9),$$(10))
+ endef
+ $(if $(3),$(foreach bs,$(3),$(eval $(call Jffs2Template,$(1),$(bs)))))
+endef
+
+$(eval $(call BuildTemplate,squashfs-only))
+$(eval $(call BuildTemplate,64k,-64k,64k))
+$(eval $(call BuildTemplate,64kraw,-raw,64k))
+$(eval $(call BuildTemplate,64kraw-nojffs,-raw))
+$(eval $(call BuildTemplate,128k,,128k))
+$(eval $(call BuildTemplate,128kraw,-raw,128k))
+$(eval $(call BuildTemplate,256k,,256k))
+$(eval $(call BuildTemplate,all,,64k 128k 256k))
+
+ifeq ($(SUBTARGET),generic)
+$(eval $(call SingleProfile,ALFA,64k,ALFANX,alfa-nx,ALFA-NX,ttyS0,115200,$$(alfa_mtdlayout_8M),1638400,6291456,vmlinux.gz.uImage,pb9x-2.6.31-jffs2))
+$(eval $(call SingleProfile,ALFA,64k,HORNETUB,hornet-ub,HORNET-UB,ttyATH0,115200,$$(alfa_mtdlayout_8M),1638400,6291456,kernel_image,rootfs_image))
+$(eval $(call SingleProfile,ALFA,64k,TUBE2H8M,tube2h-8M,TUBE2H,ttyATH0,115200,$$(alfa_mtdlayout_8M),1638400,6291456,kernel.image,rootfs.image))
+
+$(eval $(call SingleProfile,AthGzip,64k,AP81,ap81,AP81,ttyS0,115200,$$(ap81_mtdlayout),RKuImage))
+$(eval $(call SingleProfile,AthGzip,64k,AP83,ap83,AP83,ttyS0,115200,$$(ap83_mtdlayout),RKuImage))
+$(eval $(call SingleProfile,AthGzip,64k,AP96,ap96,AP96,ttyS0,115200,$$(ap96_mtdlayout),RKuImage))
+$(eval $(call SingleProfile,AthGzip,64k,WNDAP360,wndap360,WNDAP360,ttyS0,9600,$$(wndap360_mtdlayout),KRuImage))
+
+$(eval $(call SingleProfile,AthLzma,64k,ALFAAP120C,alfa-ap120c,ALFA-AP120C,ttyS0,115200,$$(alfa_ap120c_mtdlayout),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,ALFAAP96,alfa-ap96,ALFA-AP96,ttyS0,115200,$$(alfa_ap96_mtdlayout),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,ALL0258N,all0258n,ALL0258N,ttyS0,115200,$$(all0258n_mtdlayout),KRuImage,65536))
+$(eval $(call SingleProfile,AthLzma,256k,ALL0315N,all0315n,ALL0315N,ttyS0,115200,$$(all0315n_mtdlayout),KRuImage,262144))
+$(eval $(call SingleProfile,AthLzma,64k,AP113,ap113,AP113,ttyS0,115200,$$(ap113_mtd_layout),RK))
+$(eval $(call SingleProfile,AthLzma,64k,AP121_2M,ap121-2M,AP121,ttyATH0,115200,$$(ap121_mtdlayout_2M),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,AP121_4M,ap121-4M,AP121,ttyATH0,115200,$$(ap121_mtdlayout_4M),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,AP121_8M,ap121-8M,AP121,ttyATH0,115200,$$(ap121_mtdlayout_8M),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,AP121_16M,ap121-16M,AP121,ttyATH0,115200,$$(ap121_mtdlayout_16M),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,AP121MINI,ap121-mini,AP121-MINI,ttyATH0,115200,$$(ap121_mtdlayout_4M),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,AP132,ap132,AP132,ttyS0,115200,$$(ap132_mtdlayout),KRuImage))
+$(eval $(call SingleProfile,AthLzma,64k,AP135,ap135-020,AP135-020,ttyS0,115200,$$(ap135_mtdlayout),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,AP136_010,ap136-010,AP136-010,ttyS0,115200,$$(ap136_mtdlayout),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,AP136_020,ap136-020,AP136-020,ttyS0,115200,$$(ap136_mtdlayout),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,AP143_8M,ap143-8M,AP143,ttyS0,115200,$$(ap143_mtdlayout_8M),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,AP143_16M,ap143-16M,AP143,ttyS0,115200,$$(ap143_mtdlayout_16M),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,AP147_010,ap147-010,AP147-010,ttyS0,115200,$$(ap147_mtdlayout),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,AP152_16M,ap152-16M,AP152,ttyS0,115200,$$(ap152_mtdlayout_16M),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,BXU2000N2,bxu2000n-2-a1,BXU2000n-2-A1,ttyS0,115200,$$(bxu2000n2_mtdlayout),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,CAP4200AG,cap4200ag,CAP4200AG,ttyS0,115200,$$(cap4200ag_mtdlayout),KRuImage))
+$(eval $(call SingleProfile,AthLzma,64k,DB120,db120,DB120,ttyS0,115200,$$(db120_mtdlayout),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,DRAGINO2,dragino2,DRAGINO2,ttyATH0,115200,$$(dragino2_mtdlayout),KRuImage,65536))
+$(eval $(call SingleProfile,AthLzma,64k,EWDORINAP,ew-dorin,EW-DORIN,ttyATH0,115200,$$(ew-dorin_mtdlayout_4M),KRuImage,65536))
+$(eval $(call SingleProfile,AthLzma,64k,EWDORINRT,ew-dorin-router,EW-DORIN-ROUTER,ttyATH0,115200,$$(ew-dorin_mtdlayout_4M),KRuImage,65536))
+$(eval $(call SingleProfile,AthLzma,64k,EWDORIN16M,ew-dorin-16M,EW-DORIN,ttyATH0,115200,$$(ew-dorin_mtdlayout_16M),KRuImage,65536))
+$(eval $(call SingleProfile,AthLzma,64k,HORNETUBx2,hornet-ub-x2,HORNET-UB,ttyATH0,115200,$$(alfa_mtdlayout_16M),KRuImage,65536))
+$(eval $(call SingleProfile,AthLzma,64k,MR12,mr12,MR12,ttyS0,115200,$$(mr12_mtdlayout),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,MR16,mr16,MR16,ttyS0,115200,$$(mr16_mtdlayout),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,PB92,pb92,PB92,ttyS0,115200,$$(pb92_mtdlayout),KRuImage))
+$(eval $(call SingleProfile,AthLzma,64k,TUBE2H16M,tube2h-16M,TUBE2H,ttyATH0,115200,$$(alfa_mtdlayout_16M),KRuImage,65536))
+$(eval $(call SingleProfile,AthLzma,64k,WLR8100,wlr8100,WLR8100,ttyS0,115200,$$(wlr8100_mtdlayout),KRuImage))
+$(eval $(call SingleProfile,AthLzma,64k,WPJ342_16M,wpj342-16M,WPJ342,ttyS0,115200,$$(wpj342_mtdlayout_16M),KRuImage,65536))
+$(eval $(call SingleProfile,AthLzma,64k,WPJ344_16M,wpj344-16M,WPJ344,ttyS0,115200,$$(wpj344_mtdlayout_16M),KRuImage,65536))
+$(eval $(call SingleProfile,AthLzma,64k,DR344,dr344,DR344,ttyS0,115200,$$(dr344_mtdlayout),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,WPJ531_16M,wpj531-16M,WPJ531,ttyS0,115200,$$(wpj531_mtdlayout_16M),KRuImage,65536))
+$(eval $(call SingleProfile,AthLzma,64k,WPJ558_16M,wpj558-16M,WPJ558,ttyS0,115200,$$(wpj558_mtdlayout_16M),KRuImage,65536))
+$(eval $(call SingleProfile,AthLzma,64k,WRTNODE2Q,wrtnode2q,WRTNODE2Q,ttyS0,115200,$$(wrtnode2q_mtdlayout),KRuImage))
+$(eval $(call SingleProfile,AthLzma,64k,YUN_8M,yun-8M,Yun,ttyATH0,250000,$$(yun_mtdlayout_8M),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,YUN_16M,yun-16M,Yun,ttyATH0,250000,$$(yun_mtdlayout_16M),RKuImage))
+
+$(eval $(call SingleProfile,Belkin,64k,F9K1115V2,f9k1115v2,F9K1115V2,ttyS0,115200,$$(f9k1115v2_mtdlayout),BR-6679BAC))
+
+$(eval $(call SingleProfile,CameoAP91,64kraw,DIR600A1,dir-600-a1,DIR-600-A1,ttyS0,115200,"AP91-AR7240-RT-090223-00"))
+$(eval $(call SingleProfile,CameoAP91,64kraw,DIR601A1,dir-601-a1,DIR-600-A1,ttyS0,115200,"AP91-AR7240-RT-090223-02"))
+$(eval $(call SingleProfile,CameoAP91,64kraw,FR54RTR,fr-54rtr,DIR-600-A1,ttyS0,115200,"AP91-AR7240-RT-090223-01"))
+
+$(eval $(call SingleProfile,CameoAP99,64kraw,DIR615E1,dir-615-e1,DIR-615-E1,ttyS0,115200,"AP93-AR7240-RT-081028-00"))
+$(eval $(call SingleProfile,CameoAP99,64kraw,DIR615E4,dir-615-e4,DIR-615-E4,ttyS0,115200,"AP99-AR7240-RT-091105-05"))
+
+$(eval $(call SingleProfile,CameoAP123_4M,64kraw,DIR615I1,dir-615-i1,DIR-615-I1,ttyS0,115200,"00DB120AR9341-RT-1012I1-00"))
+$(eval $(call SingleProfile,CameoAP123_4M,64kraw,DIR615I3,dir-615-i3,DIR-615-I1,ttyS0,115200,"00DB120AR9341-RT-101214-00"))
+
+$(eval $(call SingleProfile,CameoAP81,64kraw-nojffs,A02RBW300N,a02-rb-w300n,TEW-632BRP,ttyS0,115200,"AP81-AR9130-RT-070614-03"))
+$(eval $(call SingleProfile,CameoAP81,64kraw-nojffs,DIR615C1,dir-615-c1,DIR-615-C1,ttyS0,115200,"AP81-AR9130-RT-070614-02"))
+$(eval $(call SingleProfile,CameoAP81,64kraw-nojffs,TEW632BRP,tew-632brp,TEW-632BRP,ttyS0,115200,"AP81-AR9130-RT-070614-00"))
+$(eval $(call SingleProfile,CameoAP81,64kraw-nojffs,TEW652BRP_FW,tew-652brp,TEW-632BRP,ttyS0,115200,"AP81-AR9130-RT-080609-05"))
+$(eval $(call SingleProfile,CameoAP81,64kraw-nojffs,TEW652BRP_RECOVERY,tew-652brp-recovery,TEW-632BRP,ttyS0,115200,"AP81-AR9130-RT-070614-02"))
+
+$(eval $(call SingleProfile,CameoAP121,64kraw-nojffs,TEW712BR,tew-712br,TEW-712BR,ttyATH0,115200,"HORNET-RT-TEW712BR-3",1.99,""))
+$(eval $(call SingleProfile,CameoAP121,64kraw-nojffs,DIR601B1,dir-601-b1,TEW-712BR,ttyATH0,115200,"HORNET-RT-DIR601B1-3",2.99.99,"" "NA"))
+$(eval $(call SingleProfile,CameoAP121_8M,64kraw-nojffs,DIR505A1,dir-505-a1,DIR-505-A1,ttyATH0,115200,"HORNET-PACKET-DIR505A1-3",1.99.99,""))
+
+$(eval $(call SingleProfile,CameoAP135,64kraw,DGL5500A1,dgl-5500-a1,DGL-5500-A1,ttyS0,115200,$$(dgl_5500_mtdlayout),"00AP135AR9558-RT-130508-00"))
+$(eval $(call SingleProfile,CameoAP135,64kraw,TEW823DRU,tew-823dru,TEW-823DRU,ttyS0,115200,$$(tew823dru_mtdlayout) mem=256M,"00AP135AR9558-RT-131129-00"))
+
+$(eval $(call SingleProfile,CameoDB120,64kraw,DHP1565A1,dhp-1565-a1,DHP-1565-A1,ttyS0,115200,"00DB120AR9344-RT-101214-00"))
+$(eval $(call SingleProfile,CameoDB120,64kraw,DIR825C1,dir-825-c1,DIR-825-C1,ttyS0,115200,"00DB120AR9344-RT-101214-00"))
+$(eval $(call SingleProfile,CameoDB120,64kraw,DIR835A1,dir-835-a1,DIR-835-A1,ttyS0,115200,"00DB120AR9344-RT-101214-00"))
+
+$(eval $(call SingleProfile,CameoDB120_8M,64kraw,TEW732BR,tew-732br,TEW-732BR,ttyS0,115200,"00DB120AR9341-RT-120906-NA"))
+
+$(eval $(call SingleProfile,CyberTANGZIP,64k,WRT160NL,wrt160nl,WRT160NL,ttyS0,115200,,1.00.01))
+
+$(eval $(call SingleProfile,CyberTANLZMA,64k,MYNETREXT,mynet-rext,MYNET-REXT,ttyS0,115200,$$(mynet_rext_mtdlayout) root=31:2,1.00.01))
+
+$(eval $(call SingleProfile,CameoAP94,64kraw,DIR825B1,dir-825-b1,DIR-825-B1,ttyS0,115200,$$(cameo_ap94_mtdlayout),$$(cameo_ap94_mtdlayout_fat),01AP94-AR7161-RT-080619-00,00AP94-AR7161-RT-080619-00))
+$(eval $(call SingleProfile,CameoAP94,64kraw,TEW673GRU,tew-673gru,TEW-673GRU,ttyS0,115200,$$(cameo_ap94_mtdlayout),$$(cameo_ap94_mtdlayout_fat),01AP94-AR7161-RT-080619-01,00AP94-AR7161-RT-080619-01))
+$(eval $(call SingleProfile,CameoAP94,64kraw,DLRTDEV01,dlrtdev01,DIR-825-B1,ttyS0,115200,$$(dlrtdev_mtdlayout),$$(dlrtdev_mtdlayout_fat),01AP94-AR7161-RT-080619-00,00AP94-AR7161-RT-080619-00))
+
+$(eval $(call SingleProfile,dLANLzma,64k,dLAN_Hotspot,dlan-hotspot,dLAN-Hotspot,ttyATH0,115200,$$(dlan_hotspot_mtdlayout) mem=64M,KRuImage,65536))
+$(eval $(call SingleProfile,dLANLzma,64k,dLAN_pro_500_wp,dlan-pro-500-wp,dLAN-pro-500-wp,ttyS0,115200,$$(dlan_pro_500_wp_mtdlayout) mem=128M,KRuImage,65536))
+$(eval $(call SingleProfile,dLANLzma,64k,dLAN_pro_1200_ac,dlan-pro-1200-ac,dLAN-pro-1200-ac,ttyS0,115200,$$(dlan_pro_1200_ac_mtdlayout) mem=128M,KRuImage,65536))
+
+$(eval $(call SingleProfile,EnGenius,64k,ESR900,esr900,ESR900,ttyS0,115200,$$(esr900_mtdlayout),KRuImage,,0x4e))
+$(eval $(call SingleProfile,EnGenius,64k,ESR1750,esr1750,ESR1750,ttyS0,115200,$$(esr1750_mtdlayout),KRuImage,,0x61))
+$(eval $(call SingleProfile,EnGenius,64k,EPG5000,epg5000,EPG5000,ttyS0,115200,$$(epg5000_mtdlayout),KRuImage,,0x71))
+
+$(eval $(call SingleProfile,HiWiFi,64k,HIWIFI_HC6361,hiwifi-hc6361,HiWiFi-HC6361,ttyATH0,115200,$$(hiwifi_hc6361_mtdlayout),KRuImage))
+
+$(eval $(call SingleProfile,MyLoader,64k,WP543_2M,wp543,,ttyS0,115200,0x200000,2M))
+$(eval $(call SingleProfile,MyLoader,64k,WP543_4M,wp543,,ttyS0,115200,0x400000,4M))
+$(eval $(call SingleProfile,MyLoader,64k,WP543_8M,wp543,,ttyS0,115200,0x800000,8M))
+$(eval $(call SingleProfile,MyLoader,64k,WP543_16M,wp543,,ttyS0,115200,0x1000000,16M))
+$(eval $(call SingleProfile,MyLoader,64k,WPE72_4M,wpe72,,ttyS0,115200,0x400000,4M))
+$(eval $(call SingleProfile,MyLoader,64k,WPE72_8M,wpe72,,ttyS0,115200,0x800000,8M))
+$(eval $(call SingleProfile,MyLoader,64k,WPE72_16M,wpe72,,ttyS0,115200,0x1000000,16M))
+
+$(eval $(call SingleProfile,Netgear,64kraw,WNR2000V3,wnr2000v3,WNR2000V3,ttyS0,115200,$$(wnr2000v3_mtdlayout),0x32303033,WNR2000V3,"" NA,-H 29763551+04+32))
+$(eval $(call SingleProfile,NetgearLzma,64kraw,WNR2000V4,wnr2000v4,WNR2000V4,ttyS0,115200,$$(wnr2000v4_mtdlayout),0x32303034,WNR2000V4,"" NA,))
+$(eval $(call SingleProfile,Netgear,64kraw,WNR2200,wnr2200,WNR2200,ttyS0,115200,$$(wnr2200_mtdlayout),0x32323030,wnr2200,"" NA,))
+$(eval $(call SingleProfile,Netgear,64kraw,REALWNR612V2,wnr612v2,WNR612V2,ttyS0,115200,$$(wnr2000v3_mtdlayout),0x32303631,WNR612V2,"",))
+$(eval $(call SingleProfile,Netgear,64kraw,N150R,n150r,WNR612V2,ttyS0,115200,$$(wnr2000v3_mtdlayout),0x32303631,N150R,"",))
+$(eval $(call SingleProfile,Netgear,64kraw,REALWNR1000V2,wnr1000v2,WNR1000V2,ttyS0,115200,$$(wnr2000v3_mtdlayout),0x31303031,WNR1000V2,"",))
+$(eval $(call SingleProfile,Netgear,64kraw,WNR1000V2_VC,wnr1000v2-vc,WNR1000V2,ttyS0,115200,$$(wnr2000v3_mtdlayout),0x31303030,WNR1000V2-VC,"",))
+$(eval $(call SingleProfile,Netgear,64kraw,WPN824N,wpn824n,WPN824N,ttyS0,115200,$$(wnr2000v3_mtdlayout),0x31313030,WPN824N,"" NA,))
+
+$(eval $(call SingleProfile,OpenMesh,squashfs-only,OM2P,om2p,,,,OM2P))
+$(eval $(call SingleProfile,OpenMesh,squashfs-only,OM5P,om5p,,,,OM5P))
+$(eval $(call SingleProfile,OpenMesh,squashfs-only,OM5PAC,om5pac,,,,OM5PAC))
+$(eval $(call SingleProfile,OpenMesh,squashfs-only,MR600,mr600,,,,MR600))
+$(eval $(call SingleProfile,OpenMesh,squashfs-only,MR900,mr900,,,,MR900))
+$(eval $(call SingleProfile,OpenMesh,squashfs-only,MR1750,mr1750,,,,MR1750))
+
+$(eval $(call SingleProfile,PB4X,128k,ALL0305,all0305,ALL0305,ttyS0,115200))
+$(eval $(call SingleProfile,PB4X,128k,EAP7660D,eap7660d,EAP7660D,ttyS0,115200))
+$(eval $(call SingleProfile,PB4X,64k,JA76PF,ja76pf,JA76PF,ttyS0,115200))
+$(eval $(call SingleProfile,PB4X,64k,JA76PF2,ja76pf2,JA76PF2,ttyS0,115200))
+$(eval $(call SingleProfile,PB4X,64k,JWAP003,jwap003,JWAP003,ttyS0,115200))
+$(eval $(call SingleProfile,PB4X,64k,PB42,pb42,PB42,ttyS0,115200))
+$(eval $(call SingleProfile,PB4X,64k,PB44,pb44,PB44,ttyS0,115200))
+
+$(eval $(call SingleProfile,Planex,64kraw,MZKW04NU,mzk-w04nu,MZK-W04NU,ttyS0,115200))
+$(eval $(call SingleProfile,Planex,64kraw,MZKW300NH,mzk-w300nh,MZK-W300NH,ttyS0,115200))
+
+$(eval $(call SingleProfile,Seama,64k,MYNETN600,mynet-n600,MYNET-N600,ttyS0,115200,$$(mynet_n600_mtdlayout),wrgnd16_wd_db600,65536,16187392))
+$(eval $(call SingleProfile,Seama,64k,MYNETN750,mynet-n750,MYNET-N750,ttyS0,115200,$$(mynet_n600_mtdlayout),wrgnd13_wd_av,65536,16187392))
+
+$(eval $(call SingleProfile,Seama,64k,QIHOO360,qihoo-c301,QIHOO-C301,ttyS0,115200,$$(qihoo_c301_mtdlayout),wrgac26_qihoo360_360rg,65536,16121856))
+
+$(eval $(call SingleProfile,Senao,squashfs-only,EAP300V2,eap300v2,EAP300V2,ttyS0,115200,$$(eap300v2_mtdlayout)))
+
+$(eval $(call SingleProfile,WHRHPG300N,64kraw,WHRG301N,whr-g301n,WHR-G301N,ttyS0,115200,$$(whrhpg300n_mtdlayout),WHR-G301N))
+$(eval $(call SingleProfile,WHRHPG300N,64kraw,WHRHPG300N,whr-hp-g300n,WHR-HP-G300N,ttyS0,115200,$$(whrhpg300n_mtdlayout),WHR-HP-G300N))
+$(eval $(call SingleProfile,WHRHPG300N,64kraw,WHRHPGN,whr-hp-gn,WHR-HP-GN,ttyS0,115200,$$(whrhpg300n_mtdlayout),WHR-HP-GN))
+$(eval $(call SingleProfile,WHRHPG300N,64kraw,WLAEAG300N,wlae-ag300n,WLAE-AG300N,ttyS0,115200,$$(whrhpg300n_mtdlayout),WLAE-AG300N))
+
+$(eval $(call SingleProfile,WRT400N,64k,WRT400N,wrt400n,WRT400N,ttyS0,115200))
+
+$(eval $(call SingleProfile,WZRHP128K,128kraw,WZRHPG300NH,wzr-hp-g300nh,WZR-HP-G300NH,ttyS0,115200,WZR-HP-G300NH))
+$(eval $(call SingleProfile,WZRHP64K,64kraw,WZRHPG300NH2,wzr-hp-g300nh2,WZR-HP-G300NH2,ttyS0,115200,WZR-HP-G300NH2))
+$(eval $(call SingleProfile,WZRHP64K,64kraw,WZRHPAG300H,wzr-hp-ag300h,WZR-HP-AG300H,ttyS0,115200,WZR-HP-AG300H))
+$(eval $(call SingleProfile,WZRHP64K,64kraw,WZRHPG450H,wzr-hp-g450h,WZR-HP-G450H,ttyS0,115200,WZR-HP-AG450H))
+$(eval $(call SingleProfile,WZRHP64K,64kraw,WZR600DHP,wzr-600dhp,WZR-HP-AG300H,ttyS0,115200,WZR-600DHP))
+$(eval $(call SingleProfile,WZRHP64K,64kraw,WZR450HP2,wzr-450hp2,WZR-450HP2,ttyS0,115200,WZR-450HP2))
+
+$(eval $(call SingleProfile,Zcomax,64k,ZCN1523H28,zcn-1523h-2-8,ZCN-1523H-2,ttyS0,115200,$$(zcn1523h_mtdlayout)))
+$(eval $(call SingleProfile,Zcomax,64k,ZCN1523H516,zcn-1523h-5-16,ZCN-1523H-5,ttyS0,115200,$$(zcn1523h_mtdlayout)))
+
+$(eval $(call SingleProfile,ZyXEL,64k,NBG_460N_550N_550NH,nbg460n_550n_550nh,NBG460N,ttyS0,115200,NBG-460N))
+
+$(eval $(call MultiProfile,AP121,AP121_2M AP121_4M AP121_8M AP121_16M))
+$(eval $(call MultiProfile,AP136,AP136_010 AP136_020))
+$(eval $(call MultiProfile,AP143,AP143_8M AP143_16M))
+$(eval $(call MultiProfile,AP147,AP147_010))
+$(eval $(call MultiProfile,AP152,AP152_16M))
+$(eval $(call MultiProfile,DIR615IX,DIR615I1 DIR615I3))
+$(eval $(call MultiProfile,EWDORIN, EWDORINAP EWDORINRT EWDORIN16M))
+$(eval $(call MultiProfile,OPENMESH,OM2P OM5P OM5PAC MR600 MR900 MR1750))
+$(eval $(call MultiProfile,TEW652BRP,TEW652BRP_FW TEW652BRP_RECOVERY))
+$(eval $(call MultiProfile,TUBE2H,TUBE2H8M TUBE2H16M))
+$(eval $(call MultiProfile,WNR612V2,REALWNR612V2 N150R))
+$(eval $(call MultiProfile,WNR1000V2,REALWNR1000V2 WNR1000V2_VC))
+$(eval $(call MultiProfile,WP543,WP543_2M WP543_4M WP543_8M WP543_16M))
+$(eval $(call MultiProfile,WPE72,WPE72_4M WPE72_8M WPE72_16M))
+$(eval $(call MultiProfile,WPJ342,WPJ342_16M))
+$(eval $(call MultiProfile,WPJ344,WPJ344_16M))
+$(eval $(call MultiProfile,WPJ531,WPJ531_16M))
+$(eval $(call MultiProfile,WPJ558,WPJ558_16M))
+$(eval $(call MultiProfile,Yun,YUN_16M YUN_8M))
+
+$(eval $(call MultiProfile,Minimal,$(SINGLE_PROFILES)))
+$(eval $(call MultiProfile,Madwifi,EAP7660D WP543))
+
+define LegacyDevice/OM2P
+ DEVICE_TITLE := OpenMesh OM2P/OM2Pv2/OM2P-HS/OM2P-HSv2/OM2P-HSv3/OM2P-LC
+ DEVICE_PACKAGES := kmod-ath9k om-watchdog
+endef
+LEGACY_DEVICES += OM2P
+
+endif # ifeq ($(SUBTARGET),generic)
+
+ifeq ($(SUBTARGET),nand)
+
+$(eval $(call SingleProfile,NetgearNAND,64k,WNDR3700V4,wndr3700v4,WNDR3700_V4,ttyS0,115200,$$(wndr4300_mtdlayout),0x33373033,WNDR3700v4,"",-H 29763948+128+128,wndr4300))
+$(eval $(call SingleProfile,NetgearNAND,64k,WNDR4300V1,wndr4300,WNDR4300,ttyS0,115200,$$(wndr4300_mtdlayout),0x33373033,WNDR4300,"",-H 29763948+0+128+128+2x2+3x3,wndr4300))
+$(eval $(call SingleProfile,NetgearNAND,64k,R6100,r6100,R6100,ttyS0,115200,$$(r6100_mtdlayout),0x36303030,R6100,"",-H 29764434+0+128+128+2x2+2x2,wndr4300))
+
+$(eval $(call SingleProfile,ZyXELNAND,128k,NBG6716,nbg6716,NBG6716,ttyS0,115200,NBG6716,$$(zyx_nbg6716_mtdlayout),mem=256M))
+
+$(eval $(call MultiProfile,WNDR4300,WNDR3700V4 WNDR4300V1))
+
+endif # ifeq ($(SUBTARGET),nand)
+
+$(eval $(call MultiProfile,Default,$(SINGLE_PROFILES)))
+
+define Image/Build/squashfs
+ cp $(KDIR)/root.squashfs $(KDIR)/root.squashfs-raw
+ cp $(KDIR)/root.squashfs $(KDIR)/root.squashfs-64k
+ $(STAGING_DIR_HOST)/bin/padjffs2 $(KDIR)/root.squashfs-64k 64
+ cp $(KDIR)/root.squashfs-64k $(BIN_DIR)/$(IMG_PREFIX)-root.squashfs-64k
+ $(call prepare_generic_squashfs,$(KDIR)/root.squashfs)
+ dd if=$(KDIR)/root.$(1) of=$(BIN_DIR)/$(IMG_PREFIX)-root.$(1) bs=128k conv=sync
+endef
+
+define Image/Build/jffs2
+ dd if=$(KDIR)/root.$(1) of=$(BIN_DIR)/$(IMG_PREFIX)-root.$(1) bs=128k conv=sync
+endef
+
+define Image/Build/Initramfs
+ $(call Image/Build/Profile/$(IMAGE_PROFILE),initramfs)
+endef
+
+define Image/Prepare
+ gzip -9n -c $(KDIR)/vmlinux > $(KDIR)/vmlinux.bin.gz
+ $(call CompressLzma,$(KDIR)/vmlinux,$(KDIR)/vmlinux.bin.lzma)
+ifneq ($(CONFIG_TARGET_ROOTFS_INITRAMFS),)
+ gzip -9n -c $(KDIR)/vmlinux-initramfs > $(KDIR)/vmlinux-initramfs.bin.gz
+ $(call CompressLzma,$(KDIR)/vmlinux-initramfs,$(KDIR)/vmlinux-initramfs.bin.lzma)
+ $(call Image/BuildLoader,generic,elf,,,-initramfs)
+endif
+ $(call Image/BuildLoader,generic,elf)
+ $(call Image/Build/Profile/$(if $(CONFIG_IB),Default,$(IMAGE_PROFILE)),loader)
+endef
+
+define Image/Prepare/Profile
+ $(call Image/Build/Profile/$(1),loader)
+endef
+
+define Image/Build/Profile
+ $(call Image/Build/Profile/$(1),buildkernel)
+ $(call Image/Build/Profile/$(1),$(2))
+endef
+
+# $(1): filesystem type.
+define Image/Build
+ $(call Image/Build/$(call rootfs_type,$(1)),$(1))
+ $(call Image/Build/Profile/$(IMAGE_PROFILE),$(1))
+endef
diff --git a/target/linux/ar71xx/image/nand.mk b/target/linux/ar71xx/image/nand.mk
new file mode 100644
index 0000000000..ec97271c75
--- /dev/null
+++ b/target/linux/ar71xx/image/nand.mk
@@ -0,0 +1,19 @@
+define Build/MerakiNAND
+ -$(STAGING_DIR_HOST)/bin/mkmerakifw \
+ -B $(BOARDNAME) -s \
+ -i $@ \
+ -o $@.new
+ @mv $@.new $@
+endef
+
+define Device/mr18
+ BOARDNAME = MR18
+ BLOCKSIZE := 64k
+ CONSOLE = ttyS0,115200
+ MTDPARTS = ar934x-nfc:512k(nandloader)ro,8M(kernel),8M(recovery),113664k(ubi),128k@130944k(odm-caldata)ro
+ IMAGES := sysupgrade.tar
+ KERNEL := kernel-bin | patch-cmdline | MerakiNAND
+ KERNEL_INITRAMFS := kernel-bin | patch-cmdline | MerakiNAND
+ IMAGE/sysupgrade.tar := sysupgrade-nand
+endef
+TARGET_DEVICES += mr18
diff --git a/target/linux/ar71xx/image/tp-link.mk b/target/linux/ar71xx/image/tp-link.mk
new file mode 100644
index 0000000000..71220f3141
--- /dev/null
+++ b/target/linux/ar71xx/image/tp-link.mk
@@ -0,0 +1,752 @@
+DEVICE_VARS += TPLINK_HWID TPLINK_HWREV TPLINK_FLASHLAYOUT TPLINK_HEADER_VERSION TPLINK_BOARD_NAME
+
+# combine kernel and rootfs into one image
+# mktplinkfw <type> <optional extra arguments to mktplinkfw binary>
+# <type> is "sysupgrade" or "factory"
+#
+# -a align the rootfs start on an <align> bytes boundary
+# -j add jffs2 end-of-filesystem markers
+# -s strip padding from end of the image
+# -X reserve <size> bytes in the firmware image (hexval prefixed with 0x)
+define Build/mktplinkfw
+ -$(STAGING_DIR_HOST)/bin/mktplinkfw \
+ -H $(TPLINK_HWID) -W $(TPLINK_HWREV) -F $(TPLINK_FLASHLAYOUT) -N OpenWrt -V $(REVISION) \
+ -m $(TPLINK_HEADER_VERSION) \
+ -k $(word 1,$^) \
+ -r $@ \
+ -o $@.new \
+ -j -X 0x40000 \
+ -a $(call rootfs_align,$(FILESYSTEM)) \
+ $(wordlist 2,$(words $(1)),$(1)) \
+ $(if $(findstring sysupgrade,$(word 1,$(1))),-s) && mv $@.new $@ || rm -f $@
+endef
+
+# mktplinkfw-initramfs <optional extra arguments to mktplinkfw binary>
+#
+# -c combined image
+define Build/mktplinkfw-initramfs
+ $(STAGING_DIR_HOST)/bin/mktplinkfw \
+ -H $(TPLINK_HWID) -W $(TPLINK_HWREV) -F $(TPLINK_FLASHLAYOUT) -N OpenWrt -V $(REVISION) $(1) \
+ -m $(TPLINK_HEADER_VERSION) \
+ -k $@ \
+ -o $@.new \
+ -s -S \
+ -c
+ @mv $@.new $@
+endef
+
+define Build/tplink-safeloader
+ -$(STAGING_DIR_HOST)/bin/tplink-safeloader \
+ -B $(TPLINK_BOARD_NAME) \
+ -V $(REVISION) \
+ -k $(word 1,$^) \
+ -r $@ \
+ -o $@.new \
+ -j \
+ $(wordlist 2,$(words $(1)),$(1)) \
+ $(if $(findstring sysupgrade,$(word 1,$(1))),-S) && mv $@.new $@ || rm -f $@
+endef
+
+define Device/tplink
+ TPLINK_HWREV := 0x1
+ TPLINK_HEADER_VERSION := 1
+ LOADER_TYPE := gz
+ KERNEL := kernel-bin | patch-cmdline | lzma
+ KERNEL_INITRAMFS := kernel-bin | patch-cmdline | lzma | mktplinkfw-initramfs
+ IMAGES := sysupgrade.bin factory.bin
+ IMAGE/sysupgrade.bin := append-rootfs | mktplinkfw sysupgrade
+ IMAGE/factory.bin := append-rootfs | mktplinkfw factory
+endef
+
+define Device/tplink-nolzma
+$(Device/tplink)
+ LOADER_FLASH_OFFS := 0x22000
+ COMPILE := loader-$(1).gz
+ COMPILE/loader-$(1).gz := loader-okli-compile
+ KERNEL := copy-file $(KDIR)/vmlinux.bin.lzma | uImage lzma -M 0x4f4b4c49 | loader-okli $(1)
+ KERNEL_INITRAMFS := copy-file $(KDIR)/vmlinux-initramfs.bin.lzma | loader-kernel-cmdline | mktplinkfw-initramfs
+endef
+
+define Device/tplink-4m
+$(Device/tplink-nolzma)
+ TPLINK_FLASHLAYOUT := 4M
+ IMAGE_SIZE := 3904k
+endef
+
+define Device/tplink-8m
+$(Device/tplink-nolzma)
+ TPLINK_FLASHLAYOUT := 8M
+ IMAGE_SIZE := 7936k
+endef
+
+define Device/tplink-4mlzma
+$(Device/tplink)
+ TPLINK_FLASHLAYOUT := 4Mlzma
+ IMAGE_SIZE := 3904k
+endef
+
+define Device/tplink-8mlzma
+$(Device/tplink)
+ TPLINK_FLASHLAYOUT := 8Mlzma
+ IMAGE_SIZE := 7936k
+endef
+
+define Device/tplink-16mlzma
+$(Device/tplink)
+ TPLINK_FLASHLAYOUT := 16Mlzma
+ IMAGE_SIZE := 15872k
+endef
+
+define Device/cpe510-520
+ MTDPARTS := spi0.0:128k(u-boot)ro,64k(pation-table)ro,64k(product-info)ro,1536k(kernel),6144k(rootfs),192k(config)ro,64k(ART)ro,7680k@0x40000(firmware)
+ IMAGE_SIZE := 7680k
+ BOARDNAME := CPE510
+ TPLINK_BOARD_NAME := CPE510
+ DEVICE_PROFILE := CPE510
+ LOADER_TYPE := elf
+ KERNEL := kernel-bin | patch-cmdline | lzma | loader-kernel
+ IMAGES := sysupgrade.bin factory.bin
+ IMAGE/sysupgrade.bin := append-rootfs | tplink-safeloader sysupgrade
+ IMAGE/factory.bin := append-rootfs | tplink-safeloader factory
+endef
+
+define Device/cpe210-220
+$(Device/cpe510-520)
+ BOARDNAME := CPE210
+endef
+TARGET_DEVICES += cpe210-220 cpe510-520
+
+define Device/tl-wdr4300-v1
+$(Device/tplink-8mlzma)
+ BOARDNAME = TL-WDR4300
+ DEVICE_PROFILE = TLWDR4300
+ TPLINK_HWID := 0x43000001
+endef
+
+define Device/tl-wdr3500-v1
+$(Device/tl-wdr4300-v1)
+ BOARDNAME = TL-WDR3500
+ TPLINK_HWID := 0x35000001
+endef
+
+define Device/tl-wdr3600-v1
+$(Device/tl-wdr4300-v1)
+ TPLINK_HWID := 0x36000001
+endef
+
+define Device/tl-wdr4300-v1-il
+$(Device/tl-wdr4300-v1)
+ TPLINK_HWID := 0x43008001
+endef
+
+define Device/tl-wdr4310-v1
+$(Device/tl-wdr4300-v1)
+ TPLINK_HWID := 0x43100001
+endef
+
+define Device/mw4530r-v1
+$(Device/tl-wdr4300-v1)
+ TPLINK_HWID := 0x45300001
+endef
+TARGET_DEVICES += tl-wdr3500-v1 tl-wdr3600-v1 tl-wdr4300-v1 tl-wdr4300-v1-il tl-wdr4310-v1 mw4530r-v1
+
+define Device/tl-wdr6500-v2
+$(Device/tplink-8mlzma)
+ KERNEL := kernel-bin | patch-cmdline | lzma | uImage lzma
+ KERNEL_INITRAMFS := kernel-bin | patch-cmdline | lzma | uImage lzma | mktplinkfw-initramfs
+ BOARDNAME = TL-WDR6500-v2
+ DEVICE_PROFILE = TLWDR6500V2
+ TPLINK_HWID := 0x65000002
+ TPLINK_HEADER_VERSION := 2
+endef
+TARGET_DEVICES += tl-wdr6500-v2
+
+define Device/tl-wdr3320-v2
+$(Device/tplink-4mlzma)
+ BOARDNAME = TL-WDR3320-v2
+ DEVICE_PROFILE = TLWDR3320V2
+ TPLINK_HWID := 0x33200002
+ TPLINK_HEADER_VERSION := 2
+endef
+TARGET_DEVICES += tl-wdr3320-v2
+
+define Device/archer-c5-v1
+ $(Device/tplink-16mlzma)
+ BOARDNAME := ARCHER-C5
+ DEVICE_PROFILE := ARCHERC7
+ TPLINK_HWID := 0xc5000001
+endef
+
+define Device/archer-c7-v1
+ $(Device/tplink-8mlzma)
+ BOARDNAME := ARCHER-C7
+ DEVICE_PROFILE := ARCHERC7
+ TPLINK_HWID := 0x75000001
+endef
+
+define Device/archer-c7-v2
+ $(Device/tplink-16mlzma)
+ BOARDNAME := ARCHER-C7-V2
+ DEVICE_PROFILE := ARCHERC7
+ TPLINK_HWID := 0xc7000002
+ IMAGE/factory.bin := append-rootfs | mktplinkfw factory -C US
+endef
+
+define Device/tl-wdr7500-v3
+ $(Device/tplink-8mlzma)
+ BOARDNAME := ARCHER-C7
+ DEVICE_PROFILE := ARCHERC7
+ TPLINK_HWID := 0x75000003
+endef
+TARGET_DEVICES += archer-c5-v1 archer-c7-v1 archer-c7-v2 tl-wdr7500-v3
+
+define Device/tl-mr10u-v1
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-MR10U
+ DEVICE_PROFILE := TLMR10U
+ TPLINK_HWID := 0x00100101
+ CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-mr11u-v1
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-MR11U
+ DEVICE_PROFILE := TLMR11U
+ TPLINK_HWID := 0x00110101
+ CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-mr11u-v2
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-MR11U
+ DEVICE_PROFILE := TLMR11U
+ TPLINK_HWID := 0x00110102
+ CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-mr12u-v1
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-MR13U
+ DEVICE_PROFILE := TLMR12U
+ TPLINK_HWID := 0x00120101
+ CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-mr13u-v1
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-MR13U
+ DEVICE_PROFILE := TLMR13U
+ TPLINK_HWID := 0x00130101
+ CONSOLE := ttyATH0,115200
+endef
+TARGET_DEVICES += tl-mr10u-v1 tl-mr11u-v1 tl-mr11u-v2 tl-mr12u-v1 tl-mr13u-v1
+
+define Device/tl-mr3020-v1
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-MR3020
+ DEVICE_PROFILE := TLMR3020
+ TPLINK_HWID := 0x30200001
+ CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-mr3040-v1
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-MR3040
+ DEVICE_PROFILE := TLMR3040
+ TPLINK_HWID := 0x30400001
+ CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-mr3040-v2
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-MR3040-v2
+ DEVICE_PROFILE := TLMR3040
+ TPLINK_HWID := 0x30400002
+ CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-mr3220-v1
+ $(Device/tplink-4m)
+ BOARDNAME := TL-MR3220
+ DEVICE_PROFILE := TLMR3220
+ TPLINK_HWID := 0x32200001
+endef
+
+define Device/tl-mr3220-v2
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-MR3220-v2
+ DEVICE_PROFILE := TLMR3220
+ TPLINK_HWID := 0x32200002
+ CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-mr3420-v1
+ $(Device/tplink-4m)
+ BOARDNAME := TL-MR3420
+ DEVICE_PROFILE := TLMR3420
+ TPLINK_HWID := 0x34200001
+endef
+
+define Device/tl-mr3420-v2
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-MR3420-v2
+ DEVICE_PROFILE := TLMR3420
+ TPLINK_HWID := 0x34200002
+endef
+TARGET_DEVICES += tl-mr3020-v1 tl-mr3040-v1 tl-mr3040-v2 tl-mr3220-v1 tl-mr3220-v2 tl-mr3420-v1 tl-mr3420-v2
+
+define Device/tl-wr703n-v1
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-WR703N
+ DEVICE_PROFILE := TLWR703
+ TPLINK_HWID := 0x07030101
+ CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-wr710n-v1
+ $(Device/tplink-8mlzma)
+ BOARDNAME := TL-WR710N
+ DEVICE_PROFILE := TLWR710
+ TPLINK_HWID := 0x07100001
+ CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-wr710n-v2
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-WR710N
+ DEVICE_PROFILE := TLWR710
+ TPLINK_HWID := 0x07100002
+ CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-wr710n-v2.1
+ $(Device/tplink-8mlzma)
+ BOARDNAME := TL-WR710N
+ DEVICE_PROFILE := TLWR710
+ TPLINK_HWID := 0x07100002
+ TPLINK_HWREV := 0x00000002
+ CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-wr720n-v3
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-WR720N-v3
+ DEVICE_PROFILE := TLWR720
+ TPLINK_HWID := 0x07200103
+ CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-wr720n-v4
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-WR720N-v3
+ DEVICE_PROFILE := TLWR720
+ TPLINK_HWID := 0x07200104
+ CONSOLE := ttyATH0,115200
+endef
+TARGET_DEVICES += tl-wr703n-v1 tl-wr710n-v1 tl-wr710n-v2 tl-wr710n-v2.1 tl-wr720n-v3 tl-wr720n-v4
+
+define Device/tl-wr740n-v1
+ $(Device/tplink-4m)
+ BOARDNAME := TL-WR741ND
+ DEVICE_PROFILE := TLWR740
+ TPLINK_HWID := 0x07400001
+endef
+
+define Device/tl-wr740n-v3
+ $(Device/tplink-4m)
+ BOARDNAME := TL-WR741ND
+ DEVICE_PROFILE := TLWR740
+ TPLINK_HWID := 0x07400003
+endef
+
+define Device/tl-wr740n-v4
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-WR741ND-v4
+ DEVICE_PROFILE := TLWR740
+ TPLINK_HWID := 0x07400004
+ CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-wr740n-v5
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-WR741ND-v4
+ DEVICE_PROFILE := TLWR740
+ TPLINK_HWID := 0x07400005
+ CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-wr740n-v6
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-WR841N-v9
+ DEVICE_PROFILE := TLWR740
+ TPLINK_HWID := 0x07400006
+endef
+
+define Device/tl-wr741nd-v1
+ $(Device/tplink-4m)
+ BOARDNAME := TL-WR741ND
+ DEVICE_PROFILE := TLWR741
+ TPLINK_HWID := 0x07410001
+endef
+
+define Device/tl-wr741nd-v2
+ $(Device/tplink-4m)
+ BOARDNAME := TL-WR741ND
+ DEVICE_PROFILE := TLWR741
+ TPLINK_HWID := 0x07410001
+endef
+
+define Device/tl-wr741nd-v4
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-WR741ND-v4
+ DEVICE_PROFILE := TLWR741
+ TPLINK_HWID := 0x07410004
+ CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-wr741nd-v5
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-WR741ND-v4
+ DEVICE_PROFILE := TLWR741
+ TPLINK_HWID := 0x07400005
+ CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-wr810n
+ $(Device/tplink-8mlzma)
+ BOARDNAME := TL-WR810N
+ DEVICE_PROFILE := TLWR810
+ TPLINK_HWID := 0x08100001
+endef
+TARGET_DEVICES += tl-wr810n
+
+define Device/tl-wr743nd-v1
+ $(Device/tplink-4m)
+ BOARDNAME := TL-WR741ND
+ DEVICE_PROFILE := TLWR743
+ TPLINK_HWID := 0x07430001
+endef
+
+define Device/tl-wr743nd-v2
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-WR741ND-v4
+ DEVICE_PROFILE := TLWR743
+ TPLINK_HWID := 0x07430002
+ CONSOLE := ttyATH0,115200
+endef
+TARGET_DEVICES += tl-wr740n-v1 tl-wr740n-v3 tl-wr740n-v4 tl-wr740n-v5 tl-wr740n-v6 tl-wr741nd-v1 tl-wr741nd-v2 tl-wr741nd-v4 tl-wr741nd-v5 tl-wr743nd-v1 tl-wr743nd-v2
+
+define Device/tl-wr841-v1.5
+ $(Device/tplink-4m)
+ BOARDNAME := TL-WR841N-v1.5
+ DEVICE_PROFILE := TLWR841
+ TPLINK_HWID := 0x08410002
+ TPLINK_HWREV := 2
+endef
+
+define Device/tl-wr841-v3
+ $(Device/tplink-4m)
+ BOARDNAME := TL-WR941ND
+ DEVICE_PROFILE := TLWR841
+ TPLINK_HWID := 0x08410003
+ TPLINK_HWREV := 3
+endef
+
+define Device/tl-wr841-v5
+ $(Device/tplink-4m)
+ BOARDNAME := TL-WR741ND
+ DEVICE_PROFILE := TLWR841
+ TPLINK_HWID := 0x08410005
+endef
+
+define Device/tl-wr841-v7
+ $(Device/tplink-4m)
+ BOARDNAME := TL-WR841N-v7
+ DEVICE_PROFILE := TLWR841
+ TPLINK_HWID := 0x08410007
+endef
+
+define Device/tl-wr841-v8
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-WR841N-v8
+ DEVICE_PROFILE := TLWR841
+ TPLINK_HWID := 0x08410008
+endef
+
+define Device/tl-wr841-v9
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-WR841N-v9
+ DEVICE_PROFILE := TLWR841
+ TPLINK_HWID := 0x08410009
+endef
+
+define Device/tl-wr841-v10
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-WR841N-v9
+ DEVICE_PROFILE := TLWR841
+ TPLINK_HWID := 0x08410010
+endef
+
+define Device/tl-wr841-v11
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-WR841N-v11
+ DEVICE_PROFILE := TLWR841
+ TPLINK_HWID := 0x08410011
+endef
+
+define Device/tl-wr842n-v1
+ $(Device/tplink-8m)
+ BOARDNAME := TL-MR3420
+ DEVICE_PROFILE := TLWR842
+ TPLINK_HWID := 0x08420001
+endef
+
+define Device/tl-wr842n-v2
+ $(Device/tplink-8mlzma)
+ BOARDNAME := TL-WR842N-v2
+ DEVICE_PROFILE := TLWR842
+ TPLINK_HWID := 0x8420002
+endef
+
+define Device/tl-wr842n-v3
+ $(Device/tplink-16mlzma)
+ BOARDNAME := TL-WR842N-v3
+ DEVICE_PROFILE := TLWR842
+ TPLINK_HWID := 0x08420003
+endef
+
+define Device/tl-wr843nd-v1
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-WR841N-v8
+ DEVICE_PROFILE := TLWR843
+ TPLINK_HWID := 0x08430001
+endef
+
+define Device/tl-wr847n-v8
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-WR841N-v8
+ DEVICE_PROFILE := TLWR841
+ TPLINK_HWID := 0x08470008
+endef
+TARGET_DEVICES += tl-wr841-v1.5 tl-wr841-v3 tl-wr841-v5 tl-wr841-v7 tl-wr841-v8 tl-wr841-v9 tl-wr841-v10 tl-wr841-v11 tl-wr842n-v1 tl-wr842n-v2 tl-wr842n-v3 tl-wr843nd-v1 tl-wr847n-v8
+
+define Device/tl-wr941nd-v2
+ $(Device/tplink-4m)
+ BOARDNAME := TL-WR941ND
+ DEVICE_PROFILE := TLWR941
+ TPLINK_HWID := 0x09410002
+ TPLINK_HWREV := 2
+endef
+
+define Device/tl-wr941nd-v3
+ $(Device/tplink-4m)
+ BOARDNAME := TL-WR941ND
+ DEVICE_PROFILE := TLWR941
+ TPLINK_HWID := 0x09410002
+ TPLINK_HWREV := 2
+endef
+
+define Device/tl-wr941nd-v4
+ $(Device/tplink-4m)
+ BOARDNAME := TL-WR741ND
+ DEVICE_PROFILE := TLWR941
+ TPLINK_HWID := 0x09410004
+endef
+
+define Device/tl-wr941nd-v5
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-WR941ND-v5
+ DEVICE_PROFILE := TLWR941
+ TPLINK_HWID := 0x09410005
+endef
+
+define Device/tl-wr941nd-v6
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-WR941ND-v6
+ DEVICE_PROFILE := TLWR941
+ TPLINK_HWID := 0x09410006
+endef
+
+# Chinese version (unlike European) is similar to the TL-WDR3500
+define Device/tl-wr941nd-v6-cn
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-WDR3500
+ DEVICE_PROFILE := TLWR941
+ TPLINK_HWID := 0x09410006
+endef
+TARGET_DEVICES += tl-wr941nd-v2 tl-wr941nd-v3 tl-wr941nd-v4 tl-wr941nd-v5 tl-wr941nd-v6 tl-wr941nd-v6-cn
+
+define Device/tl-wr1041n-v2
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-WR1041N-v2
+ DEVICE_PROFILE := TLWR1041
+ TPLINK_HWID := 0x10410002
+endef
+TARGET_DEVICES += tl-wr1041n-v2
+
+define Device/tl-wr1043nd-v1
+ $(Device/tplink-8m)
+ BOARDNAME := TL-WR1043ND
+ DEVICE_PROFILE := TLWR1043
+ TPLINK_HWID := 0x10430001
+endef
+
+define Device/tl-wr1043nd-v2
+ $(Device/tplink-8mlzma)
+ BOARDNAME := TL-WR1043ND-v2
+ DEVICE_PROFILE := TLWR1043
+ TPLINK_HWID := 0x10430002
+endef
+
+define Device/tl-wr1043nd-v3
+ $(Device/tplink-8mlzma)
+ BOARDNAME := TL-WR1043ND-v2
+ DEVICE_PROFILE := TLWR1043
+ TPLINK_HWID := 0x10430003
+endef
+TARGET_DEVICES += tl-wr1043nd-v1 tl-wr1043nd-v2 tl-wr1043nd-v3
+
+define Device/tl-wr2543-v1
+ $(Device/tplink-8mlzma)
+ BOARDNAME := TL-WR2543N
+ DEVICE_PROFILE := TLWR2543
+ TPLINK_HWID := 0x25430001
+ IMAGE/sysupgrade.bin := append-rootfs | mktplinkfw sysupgrade -v 3.13.99
+ IMAGE/factory.bin := append-rootfs | mktplinkfw factory -v 3.13.99
+endef
+TARGET_DEVICES += tl-wr2543-v1
+
+define Device/tl-wdr4900-v2
+ $(Device/tplink-8mlzma)
+ BOARDNAME := TL-WDR4900-v2
+ DEVICE_PROFILE := TLWDR4900V2
+ TPLINK_HWID := 0x49000002
+endef
+TARGET_DEVICES += tl-wdr4900-v2
+
+define Device/tl-wa701nd-v1
+ $(Device/tplink-4m)
+ BOARDNAME := TL-WA901ND
+ DEVICE_PROFILE := TLWA701
+ TPLINK_HWID := 0x07010001
+endef
+
+define Device/tl-wa701nd-v2
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-WA701ND-v2
+ DEVICE_PROFILE := TLWA701
+ TPLINK_HWID := 0x07010002
+ CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-wa730re-v1
+ $(Device/tplink-4m)
+ BOARDNAME := TL-WA901ND
+ DEVICE_PROFILE := TLWA730RE
+ TPLINK_HWID := 0x07300001
+endef
+
+define Device/tl-wa750re-v1
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-WA750RE
+ DEVICE_PROFILE := TLWA750
+ TPLINK_HWID := 0x07500001
+endef
+
+define Device/tl-wa7510n
+ $(Device/tplink-4m)
+ BOARDNAME := TL-WA7510N
+ DEVICE_PROFILE := TLWA7510
+ TPLINK_HWID := 0x75100001
+endef
+TARGET_DEVICES += tl-wa701nd-v1 tl-wa701nd-v2 tl-wa730re-v1 tl-wa750re-v1 tl-wa7510n
+
+define Device/tl-wa801nd-v1
+ $(Device/tplink-4m)
+ BOARDNAME := TL-WA901ND
+ DEVICE_PROFILE := TLWA801
+ TPLINK_HWID := 0x08010001
+endef
+
+define Device/tl-wa801nd-v2
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-WA801ND-v2
+ DEVICE_PROFILE := TLWA801
+ TPLINK_HWID := 0x08010002
+endef
+
+define Device/tl-wa801nd-v3
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-WA801ND-v3
+ DEVICE_PROFILE := TLWA801
+ TPLINK_HWID := 0x08010003
+endef
+
+define Device/tl-wa830re-v1
+ $(Device/tplink-4m)
+ BOARDNAME := TL-WA901ND
+ DEVICE_PROFILE := TLWA830
+ TPLINK_HWID := 0x08300010
+endef
+
+define Device/tl-wa830re-v2
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-WA830RE-v2
+ DEVICE_PROFILE := TLWA830
+ TPLINK_HWID := 0x08300002
+endef
+
+define Device/tl-wa850re-v1
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-WA850RE
+ DEVICE_PROFILE := TLWA850
+ TPLINK_HWID := 0x08500001
+endef
+
+define Device/tl-wa860re-v1
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-WA860RE
+ DEVICE_PROFILE := TLWA860
+ TPLINK_HWID := 0x08600001
+endef
+TARGET_DEVICES += tl-wa801nd-v1 tl-wa801nd-v2 tl-wa801nd-v3 tl-wa830re-v1 tl-wa830re-v2 tl-wa850re-v1 tl-wa860re-v1
+
+define Device/tl-wa901nd-v1
+ $(Device/tplink-4m)
+ BOARDNAME := TL-WA901ND
+ DEVICE_PROFILE := TLWA901
+ TPLINK_HWID := 0x09010001
+endef
+
+define Device/tl-wa901nd-v2
+ $(Device/tplink-4m)
+ BOARDNAME := TL-WA901ND-v2
+ DEVICE_PROFILE := TLWA901
+ TPLINK_HWID := 0x09010002
+endef
+
+define Device/tl-wa901nd-v3
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-WA901ND-v3
+ DEVICE_PROFILE := TLWA901
+ TPLINK_HWID := 0x09010003
+endef
+
+define Device/tl-wa901nd-v4
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-WA901ND-v4
+ DEVICE_PROFILE := TLWA901
+ TPLINK_HWID := 0x09010004
+endef
+
+TARGET_DEVICES += tl-wa901nd-v1 tl-wa901nd-v2 tl-wa901nd-v3 tl-wa901nd-v4
+
+define Device/tl-wa7210n-v2
+ $(Device/tplink-4mlzma)
+ BOARDNAME := TL-WA7210N-v2
+ DEVICE_PROFILE := TLWA7210
+ TPLINK_HWID := 0x72100002
+ CONSOLE := ttyATH0,115200
+endef
+TARGET_DEVICES += tl-wa7210n-v2
+
diff --git a/target/linux/ar71xx/image/ubnt.mk b/target/linux/ar71xx/image/ubnt.mk
new file mode 100644
index 0000000000..4589345d40
--- /dev/null
+++ b/target/linux/ar71xx/image/ubnt.mk
@@ -0,0 +1,247 @@
+# UBNT_BOARD e.g. one of (XS2, XS5, RS, XM)
+# UBNT_TYPE e.g. one of (BZ, XM, XW)
+# UBNT_CHIP e.g. one of (ar7240, ar933x, ar934x)
+
+# mkubntimage is using the kernel image direct
+# routerboard creates partitions out of the ubnt header
+define Build/mkubntimage
+ $(STAGING_DIR_HOST)/bin/mkfwimage \
+ -B $(UBNT_BOARD) -v $(UBNT_TYPE).$(UBNT_CHIP).v6.0.0-OpenWrt-$(REVISION) \
+ -k $(word 1,$^) \
+ -r $@ \
+ -o $@
+endef
+
+# all UBNT XM device expect the kernel image to have 1024k while flash, when
+# booting the image, the size doesn't matter.
+define Build/mkubntimage-split
+ dd if=$@ of=$@.old1 bs=1024k count=1
+ dd if=$@ of=$@.old2 bs=1024k skip=1
+ $(STAGING_DIR_HOST)/bin/mkfwimage \
+ -B $(UBNT_BOARD) -v $(UBNT_TYPE).$(UBNT_CHIP).v6.0.0-OpenWrt-$(REVISION) \
+ -k $@.old1 \
+ -r $@.old2 \
+ -o $@
+ rm $@.old1 $@.old2
+endef
+
+define Build/mkubntimage2
+ $(STAGING_DIR_HOST)/bin/mkfwimage2 -f 0x9f000000 \
+ -v $(UBNT_TYPE).$(UBNT_CHIP).v6.0.0-OpenWrt-$(REVISION) \
+ -p jffs2:0x50000:0xf60000:0:0:$@ \
+ -o $@.new
+ @mv $@.new $@
+endef
+
+DEVICE_VARS += UBNT_BOARD UBNT_CHIP UBNT_TYPE
+
+# UBNT_BOARD e.g. one of (XS2, XS5, RS, XM)
+# UBNT_TYPE e.g. one of (BZ, XM, XW)
+# UBNT_CHIP e.g. one of (ar7240, ar933x, ar934x)
+define Device/ubnt-xm
+ DEVICE_PROFILE := UBNT
+ IMAGE_SIZE := 7552k
+ MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,7552k(firmware),256k(cfg)ro,64k(EEPROM)ro
+ UBNT_TYPE := XM
+ UBNT_BOARD := XM
+ UBNT_CHIP := ar7240
+ IMAGES := sysupgrade.bin factory.bin
+ IMAGE/factory.bin = $$(IMAGE/sysupgrade.bin) | mkubntimage-split
+ IMAGE/sysupgrade.bin = append-kernel $$$$(BLOCKSIZE) | append-rootfs | pad-rootfs | check-size $$$$(IMAGE_SIZE)
+endef
+
+define Device/ubnt-xw
+ DEVICE_PROFILE := UBNT
+ IMAGE_SIZE := 7552k
+ MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,7552k(firmware),256k(cfg)ro,64k(EEPROM)ro
+ UBNT_TYPE := XW
+ UBNT_BOARD := XM
+ UBNT_CHIP := ar934x
+ IMAGES := sysupgrade.bin factory.bin
+ IMAGE/factory.bin = $$(IMAGE/sysupgrade.bin) | mkubntimage-split
+ IMAGE/sysupgrade.bin = append-kernel $$$$(BLOCKSIZE) | append-rootfs | pad-rootfs | check-size $$$$(IMAGE_SIZE)
+endef
+
+define Device/ubnt-bz
+ DEVICE_PROFILE := UBNT
+ IMAGE_SIZE := 7552k
+ MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,7552k(firmware),256k(cfg)ro,64k(EEPROM)ro
+ UBNT_TYPE := BZ
+ UBNT_BOARD := XM
+ UBNT_CHIP := ar934x
+ IMAGES := sysupgrade.bin factory.bin
+ IMAGE/factory.bin = $$(IMAGE/sysupgrade.bin) | mkubntimage-split
+ IMAGE/sysupgrade.bin = append-kernel $$$$(BLOCKSIZE) | append-rootfs | pad-rootfs | check-size $$$$(IMAGE_SIZE)
+endef
+
+define Device/ubnt-unifiac
+ DEVICE_PROFILE := UBNT
+ IMAGE_SIZE := 7744k
+ MTDPARTS = spi0.0:384k(u-boot)ro,64k(u-boot-env)ro,7744k(firmware),7744k(ubnt-airos)ro,128k(bs)ro,256k(cfg)ro,64k(EEPROM)ro
+ IMAGES := sysupgrade.bin
+ IMAGE/sysupgrade.bin = append-kernel $$$$(BLOCKSIZE) | append-rootfs | pad-rootfs | check-size $$$$(IMAGE_SIZE)
+endef
+
+define Device/rw2458n
+ $(Device/ubnt-xm)
+ BOARDNAME := RW2458N
+endef
+
+define Device/ubnt-airrouter
+ $(Device/ubnt-xm)
+ BOARDNAME := UBNT-AR
+endef
+
+define Device/ubnt-bullet-m
+ $(Device/ubnt-xm)
+ BOARDNAME := UBNT-BM
+endef
+
+define Device/ubnt-rocket-m
+ $(Device/ubnt-xm)
+ BOARDNAME := UBNT-RM
+endef
+
+define Device/ubnt-nano-m
+ $(Device/ubnt-xm)
+ BOARDNAME := UBNT-NM
+endef
+TARGET_DEVICES += rw2458n ubnt-airrouter ubnt-bullet-m ubnt-rocket-m ubnt-nano-m
+
+define Device/ubnt-unifi
+ $(Device/ubnt-bz)
+ BOARDNAME := UBNT-UF
+ DEVICE_PROFILE := UBNT UBNTUNIFI
+endef
+
+define Device/ubnt-unifiac-lite
+ $(Device/ubnt-unifiac)
+ DEVICE_PROFILE := UBNT UBNTUNIFIACLITE
+ BOARDNAME := UBNT-UF-AC-LITE
+endef
+
+define Device/ubnt-unifiac-pro
+ $(Device/ubnt-unifiac)
+ DEVICE_PROFILE := UBNT UBNTUNIFIACPRO
+ BOARDNAME := UBNT-UF-AC-PRO
+endef
+
+define Device/ubnt-unifi-outdoor
+ $(Device/ubnt-bz)
+ BOARDNAME := UBNT-U20
+ DEVICE_PROFILE := UBNT UBNTUNIFIOUTDOOR
+endef
+TARGET_DEVICES += ubnt-unifi ubnt-unifiac-lite ubnt-unifiac-pro ubnt-unifi-outdoor
+
+define Device/ubnt-nano-m-xw
+ $(Device/ubnt-xw)
+ BOARDNAME := UBNT-NM-XW
+endef
+
+define Device/ubnt-loco-m-xw
+ $(Device/ubnt-xw)
+ BOARDNAME := UBNT-LOCO-XW
+endef
+
+define Device/ubnt-rocket-m-xw
+ $(Device/ubnt-xw)
+ BOARDNAME := UBNT-RM-XW
+endef
+
+define Device/ubnt-rocket-m-ti
+ $(Device/ubnt-xw)
+ BOARDNAME := UBNT-RM-TI
+ UBNT_TYPE := TI
+ UBNT_BOARD := XM
+endef
+TARGET_DEVICES += ubnt-nano-m-xw ubnt-loco-m-xw ubnt-rocket-m-xw ubnt-rocket-m-ti
+
+define Device/ubnt-air-gateway
+ $(Device/ubnt-xm)
+ BOARDNAME := UBNT-AGW
+ UBNT_BOARD := XM
+ UBNT_TYPE := AirGW
+ UBNT_CHIP := ar933x
+ CONSOLE = ttyATH0,115200
+endef
+TARGET_DEVICES += ubnt-air-gateway
+
+define Device/ubnt-air-gateway-pro
+ $(Device/ubnt-xm)
+ BOARDNAME := UBNT-AGWP
+ UBNT_TYPE := AirGWP
+ UBNT_CHIP := ar934x
+ CONSOLE = ttyS0,115200
+endef
+TARGET_DEVICES += ubnt-air-gateway-pro
+
+define Device/ubdev01
+ $(Device/ubnt-xm)
+ MTDPARTS := spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,7488k(firmware),64k(certs),256k(cfg)ro,64k(EEPROM)ro
+ BOARDNAME := UBNT-UF
+ UBNT_BOARD := UBDEV01
+ UBNT_TYPE := XM
+ UBNT_CHIP := ar7240
+endef
+
+TARGET_DEVICES += ubdev01
+
+define Device/ubnt-routerstation
+ IMAGE_SIZE := 16128k
+ IMAGES := sysupgrade.bin factory.bin
+ IMAGE/factory.bin = append-rootfs | pad-rootfs | mkubntimage
+ IMAGE/sysupgrade.bin = append-rootfs | pad-rootfs | combined-image | check-size $$$$(IMAGE_SIZE)
+ KERNEL := kernel-bin | patch-cmdline | lzma | pad-to $$(BLOCKSIZE)
+endef
+
+define Device/ubnt-rs
+$(Device/ubnt-routerstation)
+ BOARDNAME := UBNT-RS
+ DEVICE_PROFILE := Madwifi UBNT UBNTRS
+ UBNT_BOARD := RS
+ UBNT_TYPE := RSx
+ UBNT_CHIP := ar7100
+endef
+
+define Device/ubnt-rspro
+$(Device/ubnt-routerstation)
+ BOARDNAME := UBNT-RSPRO
+ DEVICE_PROFILE := Madwifi UBNT UBNTRSPRO
+ UBNT_BOARD := RSPRO
+ UBNT_TYPE := RSPRO
+ UBNT_CHIP := ar7100pro
+endef
+
+define Device/ubnt-ls-sr71
+$(Device/ubnt-routerstation)
+ BOARDNAME := UBNT-LS-SR71
+ DEVICE_PROFILE := Madwifi UBNT
+ UBNT_BOARD := LS-SR71
+ UBNT_TYPE := LS-SR71
+ UBNT_CHIP := ar7100
+endef
+
+TARGET_DEVICES += ubnt-rs ubnt-rspro ubnt-ls-sr71
+
+define Device/ubnt-uap-pro
+ KERNEL_SIZE := 1536k
+ IMAGE_SIZE := 15744k
+ MTDPARTS := spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,1536k(kernel),14208k(rootfs),256k(cfg)ro,64k(EEPROM)ro,15744k@0x50000(firmware)
+ UBNT_TYPE := BZ
+ UBNT_CHIP := ar934x
+ BOARDNAME := UAP-PRO
+ DEVICE_PROFILE := UBNT UAPPRO
+ KERNEL := kernel-bin | patch-cmdline | lzma | uImage lzma | jffs2 kernel0
+ IMAGES := sysupgrade.bin factory.bin
+ IMAGE/sysupgrade.bin = append-kernel $$$$(KERNEL_SIZE) | append-rootfs | pad-rootfs | check-size $$$$(IMAGE_SIZE)
+ IMAGE/factory.bin = $$(IMAGE/sysupgrade.bin) | mkubntimage2
+endef
+
+define Device/ubnt-unifi-outdoor-plus
+$(Device/ubnt-uap-pro)
+ UBNT_CHIP := ar7240
+ BOARDNAME := UBNT-UOP
+ DEVICE_PROFILE := UBNT
+endef
+
+TARGET_DEVICES += ubnt-uap-pro ubnt-unifi-outdoor-plus
diff --git a/target/linux/ar71xx/mikrotik/profiles/01-minimal.mk b/target/linux/ar71xx/mikrotik/profiles/01-minimal.mk
index 3651c88ab2..a334977d48 100644
--- a/target/linux/ar71xx/mikrotik/profiles/01-minimal.mk
+++ b/target/linux/ar71xx/mikrotik/profiles/01-minimal.mk
@@ -8,6 +8,7 @@
define Profile/DefaultNoWifi
NAME:=Default Profile (no WiFi)
PACKAGES:=
+ PRIORITY := 2
endef
define Profile/DefaultNoWifi/Description
diff --git a/target/linux/ar71xx/mikrotik/profiles/02-ath5k.mk b/target/linux/ar71xx/mikrotik/profiles/02-ath5k.mk
index a291ff68ae..fa304b7d4c 100644
--- a/target/linux/ar71xx/mikrotik/profiles/02-ath5k.mk
+++ b/target/linux/ar71xx/mikrotik/profiles/02-ath5k.mk
@@ -8,6 +8,7 @@
define Profile/Ath5k
NAME:=Atheros WiFi (ath5k)
PACKAGES:=kmod-ath5k -kmod-ath9k
+ PRIORITY := 3
endef
define Profile/Ath5k/Description
diff --git a/target/linux/ar71xx/patches-4.4/003-MIPS-ath79-make-bootconsole-wait-for-both-THRE-and-T.patch b/target/linux/ar71xx/patches-4.4/003-MIPS-ath79-make-bootconsole-wait-for-both-THRE-and-T.patch
deleted file mode 100644
index 2eba263732..0000000000
--- a/target/linux/ar71xx/patches-4.4/003-MIPS-ath79-make-bootconsole-wait-for-both-THRE-and-T.patch
+++ /dev/null
@@ -1,49 +0,0 @@
-From f1ba020af5076172c9d29006a747ccf40027fedc Mon Sep 17 00:00:00 2001
-Message-Id: <f1ba020af5076172c9d29006a747ccf40027fedc.1458840219.git.mschiffer@universe-factory.net>
-From: Matthias Schiffer <mschiffer@universe-factory.net>
-Date: Thu, 24 Mar 2016 15:34:05 +0100
-Subject: [PATCH] MIPS: ath79: make bootconsole wait for both THRE and TEMT
-
-This makes the ath79 bootconsole behave the same way as the generic 8250
-bootconsole.
-
-Also waiting for TEMT (transmit buffer is empty) instead of just THRE
-(transmit buffer is not full) ensures that all characters have been
-transmitted before the real serial driver starts reconfiguring the serial
-controller (which would sometimes result in garbage being transmitted.)
-This change does not cause a visible performance loss.
-
-In addition, this seems to fix a hang observed in certain configurations on
-many AR7xxx/AR9xxx SoCs during autoconfig of the real serial driver.
-
-A more complete follow-up patch will disable 8250 autoconfig for ath79
-altogether (the serial controller is detected as a 16550A, which is not
-fully compatible with the ath79 serial, and the autoconfig may lead to
-undefined behavior on ath79.)
-
-Cc: <stable@vger.kernel.org>
-Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
----
- arch/mips/ath79/early_printk.c | 6 ++++--
- 1 file changed, 4 insertions(+), 2 deletions(-)
-
---- a/arch/mips/ath79/early_printk.c
-+++ b/arch/mips/ath79/early_printk.c
-@@ -31,13 +31,15 @@ static inline void prom_putchar_wait(voi
- } while (1);
- }
-
-+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
-+
- static void prom_putchar_ar71xx(unsigned char ch)
- {
- void __iomem *base = (void __iomem *)(KSEG1ADDR(AR71XX_UART_BASE));
-
-- prom_putchar_wait(base + UART_LSR * 4, UART_LSR_THRE, UART_LSR_THRE);
-+ prom_putchar_wait(base + UART_LSR * 4, BOTH_EMPTY, BOTH_EMPTY);
- __raw_writel(ch, base + UART_TX * 4);
-- prom_putchar_wait(base + UART_LSR * 4, UART_LSR_THRE, UART_LSR_THRE);
-+ prom_putchar_wait(base + UART_LSR * 4, BOTH_EMPTY, BOTH_EMPTY);
- }
-
- static void prom_putchar_ar933x(unsigned char ch)
diff --git a/target/linux/ar71xx/patches-4.4/004-register_gpio_driver_earlier.patch b/target/linux/ar71xx/patches-4.4/004-register_gpio_driver_earlier.patch
new file mode 100644
index 0000000000..0c07cb18c7
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/004-register_gpio_driver_earlier.patch
@@ -0,0 +1,15 @@
+HACK: register the GPIO driver earlier to ensure that gpio_request calls
+from mach files succeed.
+
+--- a/drivers/gpio/gpio-ath79.c
++++ b/drivers/gpio/gpio-ath79.c
+@@ -202,4 +202,8 @@ static struct platform_driver ath79_gpio
+ .probe = ath79_gpio_probe,
+ };
+
+-module_platform_driver(ath79_gpio_driver);
++static int __init ath79_gpio_init(void)
++{
++ return platform_driver_register(&ath79_gpio_driver);
++}
++postcore_initcall(ath79_gpio_init);
diff --git a/target/linux/ar71xx/patches-4.4/101-MIPS-ath79-make-ath79_ddr_ctrl_init-compatible-for-n.patch b/target/linux/ar71xx/patches-4.4/101-MIPS-ath79-make-ath79_ddr_ctrl_init-compatible-for-n.patch
new file mode 100644
index 0000000000..09e6617b90
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/101-MIPS-ath79-make-ath79_ddr_ctrl_init-compatible-for-n.patch
@@ -0,0 +1,31 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sat, 14 May 2016 20:20:04 +0200
+Subject: [PATCH] MIPS: ath79: make ath79_ddr_ctrl_init() compatible for newer
+ SoCs
+
+AR913x, AR724x and AR933x are the only SoCs where the
+ath79_ddr_wb_flush_base starts at 0x7c, all newer SoCs use 0x9c
+Invert the logic to make the code compatible with AR95xx
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/arch/mips/ath79/common.c
++++ b/arch/mips/ath79/common.c
+@@ -46,12 +46,12 @@ void ath79_ddr_ctrl_init(void)
+ {
+ ath79_ddr_base = ioremap_nocache(AR71XX_DDR_CTRL_BASE,
+ AR71XX_DDR_CTRL_SIZE);
+- if (soc_is_ar71xx() || soc_is_ar934x()) {
+- ath79_ddr_wb_flush_base = ath79_ddr_base + 0x9c;
+- ath79_ddr_pci_win_base = ath79_ddr_base + 0x7c;
+- } else {
++ if (soc_is_ar913x() || soc_is_ar724x() || soc_is_ar933x()) {
+ ath79_ddr_wb_flush_base = ath79_ddr_base + 0x7c;
+ ath79_ddr_pci_win_base = 0;
++ } else {
++ ath79_ddr_wb_flush_base = ath79_ddr_base + 0x9c;
++ ath79_ddr_pci_win_base = ath79_ddr_base + 0x7c;
+ }
+ }
+ EXPORT_SYMBOL_GPL(ath79_ddr_ctrl_init);
diff --git a/target/linux/ar71xx/patches-4.4/102-MIPS-ath79-fix-regression-in-PCI-window-initializati.patch b/target/linux/ar71xx/patches-4.4/102-MIPS-ath79-fix-regression-in-PCI-window-initializati.patch
new file mode 100644
index 0000000000..e5226a5dc3
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/102-MIPS-ath79-fix-regression-in-PCI-window-initializati.patch
@@ -0,0 +1,37 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sun, 15 May 2016 13:09:20 +0200
+Subject: [PATCH] MIPS: ath79: fix regression in PCI window initialization
+
+ath79_ddr_pci_win_base has the type void __iomem *, so register offsets
+need to be a multiple of 4.
+
+Cc: Alban Bedel <albeu@free.fr>
+Fixes: 24b0e3e84fbf ("MIPS: ath79: Improve the DDR controller interface")
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/arch/mips/ath79/common.c
++++ b/arch/mips/ath79/common.c
+@@ -76,14 +76,14 @@ void ath79_ddr_set_pci_windows(void)
+ {
+ BUG_ON(!ath79_ddr_pci_win_base);
+
+- __raw_writel(AR71XX_PCI_WIN0_OFFS, ath79_ddr_pci_win_base + 0);
+- __raw_writel(AR71XX_PCI_WIN1_OFFS, ath79_ddr_pci_win_base + 1);
+- __raw_writel(AR71XX_PCI_WIN2_OFFS, ath79_ddr_pci_win_base + 2);
+- __raw_writel(AR71XX_PCI_WIN3_OFFS, ath79_ddr_pci_win_base + 3);
+- __raw_writel(AR71XX_PCI_WIN4_OFFS, ath79_ddr_pci_win_base + 4);
+- __raw_writel(AR71XX_PCI_WIN5_OFFS, ath79_ddr_pci_win_base + 5);
+- __raw_writel(AR71XX_PCI_WIN6_OFFS, ath79_ddr_pci_win_base + 6);
+- __raw_writel(AR71XX_PCI_WIN7_OFFS, ath79_ddr_pci_win_base + 7);
++ __raw_writel(AR71XX_PCI_WIN0_OFFS, ath79_ddr_pci_win_base + 0x0);
++ __raw_writel(AR71XX_PCI_WIN1_OFFS, ath79_ddr_pci_win_base + 0x4);
++ __raw_writel(AR71XX_PCI_WIN2_OFFS, ath79_ddr_pci_win_base + 0x8);
++ __raw_writel(AR71XX_PCI_WIN3_OFFS, ath79_ddr_pci_win_base + 0xc);
++ __raw_writel(AR71XX_PCI_WIN4_OFFS, ath79_ddr_pci_win_base + 0x10);
++ __raw_writel(AR71XX_PCI_WIN5_OFFS, ath79_ddr_pci_win_base + 0x14);
++ __raw_writel(AR71XX_PCI_WIN6_OFFS, ath79_ddr_pci_win_base + 0x18);
++ __raw_writel(AR71XX_PCI_WIN7_OFFS, ath79_ddr_pci_win_base + 0x1c);
+ }
+ EXPORT_SYMBOL_GPL(ath79_ddr_set_pci_windows);
+
diff --git a/target/linux/ar71xx/patches-4.4/103-MIPS-ath79-fix-register-address-in-ath79_ddr_wb_flus.patch b/target/linux/ar71xx/patches-4.4/103-MIPS-ath79-fix-register-address-in-ath79_ddr_wb_flus.patch
new file mode 100644
index 0000000000..64fb545b24
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/103-MIPS-ath79-fix-register-address-in-ath79_ddr_wb_flus.patch
@@ -0,0 +1,23 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Wed, 18 May 2016 18:03:31 +0200
+Subject: [PATCH] MIPS: ath79: fix register address in ath79_ddr_wb_flush()
+
+ath79_ddr_wb_flush_base has the type void __iomem *, so register offsets
+need to be a multiple of 4.
+
+Cc: Alban Bedel <albeu@free.fr>
+Fixes: 24b0e3e84fbf ("MIPS: ath79: Improve the DDR controller interface")
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/arch/mips/ath79/common.c
++++ b/arch/mips/ath79/common.c
+@@ -58,7 +58,7 @@ EXPORT_SYMBOL_GPL(ath79_ddr_ctrl_init);
+
+ void ath79_ddr_wb_flush(u32 reg)
+ {
+- void __iomem *flush_reg = ath79_ddr_wb_flush_base + reg;
++ void __iomem *flush_reg = ath79_ddr_wb_flush_base + reg * 4;
+
+ /* Flush the DDR write buffer. */
+ __raw_writel(0x1, flush_reg);
diff --git a/target/linux/ar71xx/patches-4.4/407-mtd-m25p80-allow-to-pass-probe-types-via-platform-data.patch b/target/linux/ar71xx/patches-4.4/407-mtd-m25p80-allow-to-pass-probe-types-via-platform-data.patch
index 6a9132032f..04acdb6d9e 100644
--- a/target/linux/ar71xx/patches-4.4/407-mtd-m25p80-allow-to-pass-probe-types-via-platform-data.patch
+++ b/target/linux/ar71xx/patches-4.4/407-mtd-m25p80-allow-to-pass-probe-types-via-platform-data.patch
@@ -1,6 +1,6 @@
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
-@@ -229,7 +229,9 @@ static int m25p_probe(struct spi_device
+@@ -251,7 +251,9 @@ static int m25p_probe(struct spi_device
ppdata.of_node = spi->dev.of_node;
diff --git a/target/linux/ar71xx/patches-4.4/412-mtd-m25p80-zero-partition-parser-data.patch b/target/linux/ar71xx/patches-4.4/412-mtd-m25p80-zero-partition-parser-data.patch
index 175acf630e..866920a249 100644
--- a/target/linux/ar71xx/patches-4.4/412-mtd-m25p80-zero-partition-parser-data.patch
+++ b/target/linux/ar71xx/patches-4.4/412-mtd-m25p80-zero-partition-parser-data.patch
@@ -1,6 +1,6 @@
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
-@@ -227,6 +227,7 @@ static int m25p_probe(struct spi_device
+@@ -249,6 +249,7 @@ static int m25p_probe(struct spi_device
if (ret)
return ret;
diff --git a/target/linux/ar71xx/patches-4.4/431-spi-add-various-flags.patch b/target/linux/ar71xx/patches-4.4/431-spi-add-various-flags.patch
index 5824a04284..bf5aff5c7e 100644
--- a/target/linux/ar71xx/patches-4.4/431-spi-add-various-flags.patch
+++ b/target/linux/ar71xx/patches-4.4/431-spi-add-various-flags.patch
@@ -1,6 +1,6 @@
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
-@@ -690,6 +690,8 @@ struct spi_transfer {
+@@ -695,6 +695,8 @@ struct spi_transfer {
unsigned cs_change:1;
unsigned tx_nbits:3;
unsigned rx_nbits:3;
@@ -9,7 +9,7 @@
#define SPI_NBITS_SINGLE 0x01 /* 1bit transfer */
#define SPI_NBITS_DUAL 0x02 /* 2bits transfer */
#define SPI_NBITS_QUAD 0x04 /* 4bits transfer */
-@@ -735,6 +737,7 @@ struct spi_message {
+@@ -740,6 +742,7 @@ struct spi_message {
struct spi_device *spi;
unsigned is_dma_mapped:1;
diff --git a/target/linux/ar71xx/patches-4.4/461-spi-add-type-field-to-spi_transfer.patch b/target/linux/ar71xx/patches-4.4/461-spi-add-type-field-to-spi_transfer.patch
index be6233c19c..6ccb632ecc 100644
--- a/target/linux/ar71xx/patches-4.4/461-spi-add-type-field-to-spi_transfer.patch
+++ b/target/linux/ar71xx/patches-4.4/461-spi-add-type-field-to-spi_transfer.patch
@@ -1,6 +1,6 @@
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
-@@ -578,6 +578,12 @@ extern struct spi_master *spi_busnum_to_
+@@ -583,6 +583,12 @@ extern struct spi_master *spi_busnum_to_
/*---------------------------------------------------------------------------*/
@@ -13,7 +13,7 @@
/*
* I/O INTERFACE between SPI controller and protocol drivers
*
-@@ -698,6 +704,7 @@ struct spi_transfer {
+@@ -703,6 +709,7 @@ struct spi_transfer {
u8 bits_per_word;
u16 delay_usecs;
u32 speed_hz;
diff --git a/target/linux/ar71xx/patches-4.4/462-mtd-m25p80-set-spi-transfer-type.patch b/target/linux/ar71xx/patches-4.4/462-mtd-m25p80-set-spi-transfer-type.patch
index 11bf9ff71b..f949235966 100644
--- a/target/linux/ar71xx/patches-4.4/462-mtd-m25p80-set-spi-transfer-type.patch
+++ b/target/linux/ar71xx/patches-4.4/462-mtd-m25p80-set-spi-transfer-type.patch
@@ -1,6 +1,6 @@
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
-@@ -137,10 +137,12 @@ static int m25p80_read(struct spi_nor *n
+@@ -159,10 +159,12 @@ static int m25p80_read(struct spi_nor *n
flash->command[0] = nor->read_opcode;
m25p_addr2cmd(nor, from, flash->command);
diff --git a/target/linux/ar71xx/patches-4.4/464-spi-ath79-fix-fast-flash-read.patch b/target/linux/ar71xx/patches-4.4/464-spi-ath79-fix-fast-flash-read.patch
index f8ae4e00bb..03483e82a6 100644
--- a/target/linux/ar71xx/patches-4.4/464-spi-ath79-fix-fast-flash-read.patch
+++ b/target/linux/ar71xx/patches-4.4/464-spi-ath79-fix-fast-flash-read.patch
@@ -1,6 +1,6 @@
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
-@@ -137,6 +137,9 @@ static int m25p80_read(struct spi_nor *n
+@@ -159,6 +159,9 @@ static int m25p80_read(struct spi_nor *n
flash->command[0] = nor->read_opcode;
m25p_addr2cmd(nor, from, flash->command);
@@ -25,7 +25,7 @@
while (len--) {
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
-@@ -705,6 +705,7 @@ struct spi_transfer {
+@@ -710,6 +710,7 @@ struct spi_transfer {
u16 delay_usecs;
u32 speed_hz;
enum spi_transfer_type type;
diff --git a/target/linux/ar71xx/patches-4.4/607-MIPS-ath79-ubnt-xm-fixes.patch b/target/linux/ar71xx/patches-4.4/607-MIPS-ath79-ubnt-xm-fixes.patch
index 50be509e6c..4699c82746 100644
--- a/target/linux/ar71xx/patches-4.4/607-MIPS-ath79-ubnt-xm-fixes.patch
+++ b/target/linux/ar71xx/patches-4.4/607-MIPS-ath79-ubnt-xm-fixes.patch
@@ -12,92 +12,3 @@
help
Say 'Y' here if you want your kernel to support the
Ubiquiti Networks XM (rev 1.0) board.
---- a/arch/mips/ath79/mach-ubnt-xm.c
-+++ b/arch/mips/ath79/mach-ubnt-xm.c
-@@ -16,10 +16,11 @@
-
- #include <asm/mach-ath79/irq.h>
-
--#include "machtypes.h"
-+#include "dev-ap9x-pci.h"
- #include "dev-gpio-buttons.h"
- #include "dev-leds-gpio.h"
--#include "dev-spi.h"
-+#include "dev-m25p80.h"
-+#include "machtypes.h"
- #include "pci.h"
-
- #define UBNT_XM_GPIO_LED_L1 0
-@@ -32,7 +33,7 @@
- #define UBNT_XM_KEYS_POLL_INTERVAL 20
- #define UBNT_XM_KEYS_DEBOUNCE_INTERVAL (3 * UBNT_XM_KEYS_POLL_INTERVAL)
-
--#define UBNT_XM_EEPROM_ADDR (u8 *) KSEG1ADDR(0x1fff1000)
-+#define UBNT_XM_EEPROM_ADDR 0x1fff1000
-
- static struct gpio_led ubnt_xm_leds_gpio[] __initdata = {
- {
-@@ -65,48 +66,10 @@ static struct gpio_keys_button ubnt_xm_g
- }
- };
-
--static struct spi_board_info ubnt_xm_spi_info[] = {
-- {
-- .bus_num = 0,
-- .chip_select = 0,
-- .max_speed_hz = 25000000,
-- .modalias = "mx25l6405d",
-- }
--};
--
--static struct ath79_spi_platform_data ubnt_xm_spi_data = {
-- .bus_num = 0,
-- .num_chipselect = 1,
--};
--
--#ifdef CONFIG_PCI
--static struct ath9k_platform_data ubnt_xm_eeprom_data;
--
--static int ubnt_xm_pci_plat_dev_init(struct pci_dev *dev)
--{
-- switch (PCI_SLOT(dev->devfn)) {
-- case 0:
-- dev->dev.platform_data = &ubnt_xm_eeprom_data;
-- break;
-- }
--
-- return 0;
--}
--
--static void __init ubnt_xm_pci_init(void)
--{
-- memcpy(ubnt_xm_eeprom_data.eeprom_data, UBNT_XM_EEPROM_ADDR,
-- sizeof(ubnt_xm_eeprom_data.eeprom_data));
--
-- ath79_pci_set_plat_dev_init(ubnt_xm_pci_plat_dev_init);
-- ath79_register_pci();
--}
--#else
--static inline void ubnt_xm_pci_init(void) {}
--#endif /* CONFIG_PCI */
--
- static void __init ubnt_xm_init(void)
- {
-+ u8 *eeprom = (u8 *) KSEG1ADDR(UBNT_XM_EEPROM_ADDR);
-+
- ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_xm_leds_gpio),
- ubnt_xm_leds_gpio);
-
-@@ -114,10 +77,8 @@ static void __init ubnt_xm_init(void)
- ARRAY_SIZE(ubnt_xm_gpio_keys),
- ubnt_xm_gpio_keys);
-
-- ath79_register_spi(&ubnt_xm_spi_data, ubnt_xm_spi_info,
-- ARRAY_SIZE(ubnt_xm_spi_info));
--
-- ubnt_xm_pci_init();
-+ ath79_register_m25p80(NULL);
-+ ap91_pci_init(eeprom, NULL);
- }
-
- MIPS_MACHINE(ATH79_MACH_UBNT_XM,
diff --git a/target/linux/ar71xx/patches-4.4/608-MIPS-ath79-ubnt-xm-add-more-boards.patch b/target/linux/ar71xx/patches-4.4/608-MIPS-ath79-ubnt-xm-add-more-boards.patch
index b463d14156..2bfd58d4e8 100644
--- a/target/linux/ar71xx/patches-4.4/608-MIPS-ath79-ubnt-xm-add-more-boards.patch
+++ b/target/linux/ar71xx/patches-4.4/608-MIPS-ath79-ubnt-xm-add-more-boards.patch
@@ -1,629 +1,8 @@
---- a/arch/mips/ath79/mach-ubnt-xm.c
-+++ b/arch/mips/ath79/mach-ubnt-xm.c
-@@ -12,16 +12,26 @@
-
- #include <linux/init.h>
- #include <linux/pci.h>
-+#include <linux/platform_device.h>
- #include <linux/ath9k_platform.h>
-+#include <linux/etherdevice.h>
-+#include <linux/ar8216_platform.h>
-
-+#include <asm/mach-ath79/ath79.h>
- #include <asm/mach-ath79/irq.h>
-+#include <asm/mach-ath79/ar71xx_regs.h>
-
-+#include <linux/platform_data/phy-at803x.h>
-+
-+#include "common.h"
- #include "dev-ap9x-pci.h"
-+#include "dev-eth.h"
- #include "dev-gpio-buttons.h"
- #include "dev-leds-gpio.h"
- #include "dev-m25p80.h"
-+#include "dev-usb.h"
-+#include "dev-wmac.h"
- #include "machtypes.h"
--#include "pci.h"
-
- #define UBNT_XM_GPIO_LED_L1 0
- #define UBNT_XM_GPIO_LED_L2 1
-@@ -37,19 +47,19 @@
-
- static struct gpio_led ubnt_xm_leds_gpio[] __initdata = {
- {
-- .name = "ubnt-xm:red:link1",
-+ .name = "ubnt:red:link1",
- .gpio = UBNT_XM_GPIO_LED_L1,
- .active_low = 0,
- }, {
-- .name = "ubnt-xm:orange:link2",
-+ .name = "ubnt:orange:link2",
- .gpio = UBNT_XM_GPIO_LED_L2,
- .active_low = 0,
- }, {
-- .name = "ubnt-xm:green:link3",
-+ .name = "ubnt:green:link3",
- .gpio = UBNT_XM_GPIO_LED_L3,
- .active_low = 0,
- }, {
-- .name = "ubnt-xm:green:link4",
-+ .name = "ubnt:green:link4",
- .gpio = UBNT_XM_GPIO_LED_L4,
- .active_low = 0,
- },
-@@ -66,9 +76,13 @@ static struct gpio_keys_button ubnt_xm_g
- }
- };
-
-+#define UBNT_M_WAN_PHYMASK BIT(4)
-+
- static void __init ubnt_xm_init(void)
- {
- u8 *eeprom = (u8 *) KSEG1ADDR(UBNT_XM_EEPROM_ADDR);
-+ u8 *mac1 = (u8 *) KSEG1ADDR(0x1fff0000);
-+ u8 *mac2 = (u8 *) KSEG1ADDR(0x1fff0000 + ETH_ALEN);
-
- ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_xm_leds_gpio),
- ubnt_xm_leds_gpio);
-@@ -79,9 +93,552 @@ static void __init ubnt_xm_init(void)
-
- ath79_register_m25p80(NULL);
- ap91_pci_init(eeprom, NULL);
-+
-+ ath79_register_mdio(0, ~UBNT_M_WAN_PHYMASK);
-+ ath79_init_mac(ath79_eth0_data.mac_addr, mac1, 0);
-+ ath79_init_mac(ath79_eth1_data.mac_addr, mac2, 0);
-+ ath79_register_eth(0);
- }
-
- MIPS_MACHINE(ATH79_MACH_UBNT_XM,
- "UBNT-XM",
- "Ubiquiti Networks XM (rev 1.0) board",
- ubnt_xm_init);
-+
-+MIPS_MACHINE(ATH79_MACH_UBNT_BULLET_M, "UBNT-BM", "Ubiquiti Bullet M",
-+ ubnt_xm_init);
-+
-+static void __init ubnt_rocket_m_setup(void)
-+{
-+ ubnt_xm_init();
-+ ath79_register_usb();
-+}
-+
-+MIPS_MACHINE(ATH79_MACH_UBNT_ROCKET_M, "UBNT-RM", "Ubiquiti Rocket M",
-+ ubnt_rocket_m_setup);
-+
-+static void __init ubnt_nano_m_setup(void)
-+{
-+ ubnt_xm_init();
-+ ath79_register_eth(1);
-+}
-+
-+MIPS_MACHINE(ATH79_MACH_UBNT_NANO_M, "UBNT-NM", "Ubiquiti Nanostation M",
-+ ubnt_nano_m_setup);
-+
-+static struct gpio_led ubnt_airrouter_leds_gpio[] __initdata = {
-+ {
-+ .name = "ubnt:green:globe",
-+ .gpio = 0,
-+ .active_low = 1,
-+ }, {
-+ .name = "ubnt:green:power",
-+ .gpio = 11,
-+ .active_low = 1,
-+ .default_state = LEDS_GPIO_DEFSTATE_ON,
-+ }
-+};
-+
-+static void __init ubnt_airrouter_setup(void)
-+{
-+ u8 *mac1 = (u8 *) KSEG1ADDR(0x1fff0000);
-+ u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
-+
-+ ath79_register_m25p80(NULL);
-+ ath79_register_mdio(0, ~UBNT_M_WAN_PHYMASK);
-+
-+ ath79_init_mac(ath79_eth0_data.mac_addr, mac1, 0);
-+ ath79_init_local_mac(ath79_eth1_data.mac_addr, mac1);
-+
-+ ath79_register_eth(1);
-+ ath79_register_eth(0);
-+ ath79_register_usb();
-+
-+ ap91_pci_init(ee, NULL);
-+ ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_airrouter_leds_gpio),
-+ ubnt_airrouter_leds_gpio);
-+
-+ ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
-+ ARRAY_SIZE(ubnt_xm_gpio_keys),
-+ ubnt_xm_gpio_keys);
-+}
-+
-+MIPS_MACHINE(ATH79_MACH_UBNT_AIRROUTER, "UBNT-AR", "Ubiquiti AirRouter",
-+ ubnt_airrouter_setup);
-+
-+static struct gpio_led ubnt_unifi_leds_gpio[] __initdata = {
-+ {
-+ .name = "ubnt:orange:dome",
-+ .gpio = 1,
-+ .active_low = 0,
-+ }, {
-+ .name = "ubnt:green:dome",
-+ .gpio = 0,
-+ .active_low = 0,
-+ }
-+};
-+
-+static struct gpio_led ubnt_unifi_outdoor_leds_gpio[] __initdata = {
-+ {
-+ .name = "ubnt:orange:front",
-+ .gpio = 1,
-+ .active_low = 0,
-+ }, {
-+ .name = "ubnt:green:front",
-+ .gpio = 0,
-+ .active_low = 0,
-+ }
-+};
-+
-+static struct gpio_led ubnt_unifi_outdoor_plus_leds_gpio[] __initdata = {
-+ {
-+ .name = "ubnt:white:front",
-+ .gpio = 1,
-+ .active_low = 0,
-+ }, {
-+ .name = "ubnt:blue:front",
-+ .gpio = 0,
-+ .active_low = 0,
-+ }
-+};
-+
-+
-+static void __init ubnt_unifi_setup(void)
-+{
-+ u8 *mac = (u8 *) KSEG1ADDR(0x1fff0000);
-+ u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
-+
-+ ath79_register_m25p80(NULL);
-+
-+ ath79_register_mdio(0, ~UBNT_M_WAN_PHYMASK);
-+
-+ ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
-+ ath79_register_eth(0);
-+
-+ ap91_pci_init(ee, NULL);
-+
-+ ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_unifi_leds_gpio),
-+ ubnt_unifi_leds_gpio);
-+
-+ ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
-+ ARRAY_SIZE(ubnt_xm_gpio_keys),
-+ ubnt_xm_gpio_keys);
-+}
-+
-+MIPS_MACHINE(ATH79_MACH_UBNT_UNIFI, "UBNT-UF", "Ubiquiti UniFi",
-+ ubnt_unifi_setup);
-+
-+
-+#define UBNT_UNIFIOD_PRI_PHYMASK BIT(4)
-+#define UBNT_UNIFIOD_2ND_PHYMASK (BIT(0) | BIT(1) | BIT(2) | BIT(3))
-+
-+static void __init ubnt_unifi_outdoor_setup(void)
-+{
-+ u8 *mac1 = (u8 *) KSEG1ADDR(0x1fff0000);
-+ u8 *mac2 = (u8 *) KSEG1ADDR(0x1fff0000 + ETH_ALEN);
-+ u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
-+
-+ ath79_register_m25p80(NULL);
-+
-+ ath79_register_mdio(0, ~(UBNT_UNIFIOD_PRI_PHYMASK |
-+ UBNT_UNIFIOD_2ND_PHYMASK));
-+
-+ ath79_init_mac(ath79_eth0_data.mac_addr, mac1, 0);
-+ ath79_init_mac(ath79_eth1_data.mac_addr, mac2, 0);
-+ ath79_register_eth(0);
-+ ath79_register_eth(1);
-+
-+ ap91_pci_init(ee, NULL);
-+
-+ ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_unifi_outdoor_leds_gpio),
-+ ubnt_unifi_outdoor_leds_gpio);
-+
-+ ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
-+ ARRAY_SIZE(ubnt_xm_gpio_keys),
-+ ubnt_xm_gpio_keys);
-+}
-+
-+MIPS_MACHINE(ATH79_MACH_UBNT_UNIFI_OUTDOOR, "UBNT-U20",
-+ "Ubiquiti UniFiAP Outdoor",
-+ ubnt_unifi_outdoor_setup);
-+
-+
-+static void __init ubnt_unifi_outdoor_plus_setup(void)
-+{
-+ u8 *mac1 = (u8 *) KSEG1ADDR(0x1fff0000);
-+ u8 *mac2 = (u8 *) KSEG1ADDR(0x1fff0000 + ETH_ALEN);
-+ u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
-+
-+ ath79_register_m25p80(NULL);
-+
-+ ath79_register_mdio(0, ~(UBNT_UNIFIOD_PRI_PHYMASK |
-+ UBNT_UNIFIOD_2ND_PHYMASK));
-+
-+ ath79_init_mac(ath79_eth0_data.mac_addr, mac1, 0);
-+ ath79_init_mac(ath79_eth1_data.mac_addr, mac2, 0);
-+ ath79_register_eth(0);
-+ ath79_register_eth(1);
-+
-+ ap91_pci_init(ee, NULL);
-+
-+ ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_unifi_outdoor_plus_leds_gpio),
-+ ubnt_unifi_outdoor_plus_leds_gpio);
-+
-+ ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
-+ ARRAY_SIZE(ubnt_xm_gpio_keys),
-+ ubnt_xm_gpio_keys);
-+}
-+
-+MIPS_MACHINE(ATH79_MACH_UBNT_UNIFI_OUTDOOR_PLUS, "UBNT-UOP",
-+ "Ubiquiti UniFiAP Outdoor+",
-+ ubnt_unifi_outdoor_plus_setup);
-+
-+
-+static struct gpio_led ubnt_uap_pro_gpio_leds[] __initdata = {
-+ {
-+ .name = "ubnt:white:dome",
-+ .gpio = 12,
-+ }, {
-+ .name = "ubnt:blue:dome",
-+ .gpio = 13,
-+ }
-+};
-+
-+static struct gpio_keys_button uap_pro_gpio_keys[] __initdata = {
-+ {
-+ .desc = "reset",
-+ .type = EV_KEY,
-+ .code = KEY_RESTART,
-+ .debounce_interval = UBNT_XM_KEYS_DEBOUNCE_INTERVAL,
-+ .gpio = 17,
-+ .active_low = 1,
-+ }
-+};
-+
-+static struct ar8327_pad_cfg uap_pro_ar8327_pad0_cfg = {
-+ .mode = AR8327_PAD_MAC_RGMII,
-+ .txclk_delay_en = true,
-+ .rxclk_delay_en = true,
-+ .txclk_delay_sel = AR8327_CLK_DELAY_SEL1,
-+ .rxclk_delay_sel = AR8327_CLK_DELAY_SEL2,
-+};
-+
-+static struct ar8327_platform_data uap_pro_ar8327_data = {
-+ .pad0_cfg = &uap_pro_ar8327_pad0_cfg,
-+ .port0_cfg = {
-+ .force_link = 1,
-+ .speed = AR8327_PORT_SPEED_1000,
-+ .duplex = 1,
-+ .txpause = 1,
-+ .rxpause = 1,
-+ },
-+};
-+
-+static struct mdio_board_info uap_pro_mdio0_info[] = {
-+ {
-+ .bus_id = "ag71xx-mdio.0",
-+ .phy_addr = 0,
-+ .platform_data = &uap_pro_ar8327_data,
-+ },
-+};
-+
-+#define UAP_PRO_MAC0_OFFSET 0x0000
-+#define UAP_PRO_MAC1_OFFSET 0x0006
-+#define UAP_PRO_WMAC_CALDATA_OFFSET 0x1000
-+#define UAP_PRO_PCI_CALDATA_OFFSET 0x5000
-+
-+static void __init ubnt_uap_pro_setup(void)
-+{
-+ u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff0000);
-+
-+ ath79_register_m25p80(NULL);
-+
-+ ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_uap_pro_gpio_leds),
-+ ubnt_uap_pro_gpio_leds);
-+ ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
-+ ARRAY_SIZE(uap_pro_gpio_keys),
-+ uap_pro_gpio_keys);
-+
-+ ath79_register_wmac(eeprom + UAP_PRO_WMAC_CALDATA_OFFSET, NULL);
-+ ap91_pci_init(eeprom + UAP_PRO_PCI_CALDATA_OFFSET, NULL);
-+
-+ ath79_register_mdio(0, 0x0);
-+ mdiobus_register_board_info(uap_pro_mdio0_info,
-+ ARRAY_SIZE(uap_pro_mdio0_info));
-+
-+ ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0);
-+ ath79_init_mac(ath79_eth0_data.mac_addr,
-+ eeprom + UAP_PRO_MAC0_OFFSET, 0);
-+
-+ /* GMAC0 is connected to an AR8327 switch */
-+ ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
-+ ath79_eth0_data.phy_mask = BIT(0);
-+ ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
-+ ath79_eth0_pll_data.pll_1000 = 0x06000000;
-+ ath79_register_eth(0);
-+}
-+
-+MIPS_MACHINE(ATH79_MACH_UBNT_UAP_PRO, "UAP-PRO", "Ubiquiti UniFi AP Pro",
-+ ubnt_uap_pro_setup);
-+
-+#define UBNT_XW_GPIO_LED_L1 11
-+#define UBNT_XW_GPIO_LED_L2 16
-+#define UBNT_XW_GPIO_LED_L3 13
-+#define UBNT_XW_GPIO_LED_L4 14
-+
-+static struct gpio_led ubnt_xw_leds_gpio[] __initdata = {
-+ {
-+ .name = "ubnt:red:link1",
-+ .gpio = UBNT_XW_GPIO_LED_L1,
-+ .active_low = 1,
-+ }, {
-+ .name = "ubnt:orange:link2",
-+ .gpio = UBNT_XW_GPIO_LED_L2,
-+ .active_low = 1,
-+ }, {
-+ .name = "ubnt:green:link3",
-+ .gpio = UBNT_XW_GPIO_LED_L3,
-+ .active_low = 1,
-+ }, {
-+ .name = "ubnt:green:link4",
-+ .gpio = UBNT_XW_GPIO_LED_L4,
-+ .active_low = 1,
-+ },
-+};
-+
-+#define UBNT_ROCKET_TI_GPIO_LED_L1 16
-+#define UBNT_ROCKET_TI_GPIO_LED_L2 17
-+#define UBNT_ROCKET_TI_GPIO_LED_L3 18
-+#define UBNT_ROCKET_TI_GPIO_LED_L4 19
-+#define UBNT_ROCKET_TI_GPIO_LED_L5 20
-+#define UBNT_ROCKET_TI_GPIO_LED_L6 21
-+static struct gpio_led ubnt_rocket_ti_leds_gpio[] __initdata = {
-+ {
-+ .name = "ubnt:green:link1",
-+ .gpio = UBNT_ROCKET_TI_GPIO_LED_L1,
-+ .active_low = 1,
-+ }, {
-+ .name = "ubnt:green:link2",
-+ .gpio = UBNT_ROCKET_TI_GPIO_LED_L2,
-+ .active_low = 1,
-+ }, {
-+ .name = "ubnt:green:link3",
-+ .gpio = UBNT_ROCKET_TI_GPIO_LED_L3,
-+ .active_low = 1,
-+ }, {
-+ .name = "ubnt:green:link4",
-+ .gpio = UBNT_ROCKET_TI_GPIO_LED_L4,
-+ .active_low = 0,
-+ }, {
-+ .name = "ubnt:green:link5",
-+ .gpio = UBNT_ROCKET_TI_GPIO_LED_L5,
-+ .active_low = 0,
-+ }, {
-+ .name = "ubnt:green:link6",
-+ .gpio = UBNT_ROCKET_TI_GPIO_LED_L6,
-+ .active_low = 0,
-+ },
-+};
-+
-+static void __init ubnt_xw_init(void)
-+{
-+ u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff0000);
-+
-+ ath79_register_m25p80(NULL);
-+
-+ ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_xw_leds_gpio),
-+ ubnt_xw_leds_gpio);
-+ ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
-+ ARRAY_SIZE(ubnt_xm_gpio_keys),
-+ ubnt_xm_gpio_keys);
-+
-+ ath79_register_wmac(eeprom + UAP_PRO_WMAC_CALDATA_OFFSET, NULL);
-+ ap91_pci_init(eeprom + UAP_PRO_PCI_CALDATA_OFFSET, NULL);
-+
-+
-+ ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_MII_GMAC0 | AR934X_ETH_CFG_MII_GMAC0_SLAVE);
-+ ath79_init_mac(ath79_eth0_data.mac_addr,
-+ eeprom + UAP_PRO_MAC0_OFFSET, 0);
-+
-+ ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
-+ ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
-+}
-+
-+static void __init ubnt_nano_m_xw_setup(void)
-+{
-+ ubnt_xw_init();
-+
-+ /* GMAC0 is connected to an AR8326 switch */
-+ ath79_register_mdio(0, ~(BIT(0) | BIT(1) | BIT(5)));
-+ ath79_eth0_data.phy_mask = (BIT(0) | BIT(1) | BIT(5));
-+ ath79_eth0_data.speed = SPEED_100;
-+ ath79_eth0_data.duplex = DUPLEX_FULL;
-+ ath79_register_eth(0);
-+}
-+
-+static void __init ubnt_loco_m_xw_setup(void)
-+{
-+ ubnt_xw_init();
-+
-+ ath79_register_mdio(0, ~BIT(1));
-+ ath79_eth0_data.phy_mask = BIT(1);
-+ ath79_register_eth(0);
-+}
-+
-+static void __init ubnt_rocket_m_xw_setup(void)
-+{
-+ u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff0000);
-+
-+ ath79_register_m25p80(NULL);
-+
-+ ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_xw_leds_gpio),
-+ ubnt_xw_leds_gpio);
-+ ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
-+ ARRAY_SIZE(ubnt_xm_gpio_keys),
-+ ubnt_xm_gpio_keys);
-+
-+ ath79_register_wmac(eeprom + UAP_PRO_WMAC_CALDATA_OFFSET, NULL);
-+ ap91_pci_init(eeprom + UAP_PRO_PCI_CALDATA_OFFSET, NULL);
-+
-+ ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0);
-+ ath79_init_mac(ath79_eth0_data.mac_addr,
-+ eeprom + UAP_PRO_MAC0_OFFSET, 0);
-+
-+ ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
-+ ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
-+
-+ ath79_register_mdio(0, ~BIT(4));
-+ ath79_eth0_data.phy_mask = BIT(4);
-+ ath79_eth0_pll_data.pll_1000 = 0x06000000;
-+ ath79_register_eth(0);
-+}
-+
-+static struct at803x_platform_data ubnt_rocket_m_ti_at803_data = {
-+ .disable_smarteee = 1,
-+ .enable_rgmii_rx_delay = 1,
-+ .enable_rgmii_tx_delay = 1,
-+};
-+static struct mdio_board_info ubnt_rocket_m_ti_mdio_info[] = {
-+ {
-+ .bus_id = "ag71xx-mdio.0",
-+ .phy_addr = 4,
-+ .platform_data = &ubnt_rocket_m_ti_at803_data,
-+ },
-+};
-+
-+static void __init ubnt_rocket_m_ti_setup(void)
-+{
-+ u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff0000);
-+
-+ ath79_register_m25p80(NULL);
-+
-+ ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_rocket_ti_leds_gpio),
-+ ubnt_rocket_ti_leds_gpio);
-+ ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
-+ ARRAY_SIZE(ubnt_xm_gpio_keys),
-+ ubnt_xm_gpio_keys);
-+
-+ ap91_pci_init(eeprom + 0x1000, NULL);
-+
-+ ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0);
-+ ath79_setup_ar934x_eth_rx_delay(3, 3);
-+ ath79_init_mac(ath79_eth0_data.mac_addr,
-+ eeprom + UAP_PRO_MAC0_OFFSET, 0);
-+ ath79_init_mac(ath79_eth1_data.mac_addr,
-+ eeprom + UAP_PRO_MAC1_OFFSET, 0);
-+
-+ ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
-+ ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
-+ ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
-+ ath79_eth1_data.mii_bus_dev = &ath79_mdio1_device.dev;
-+
-+ mdiobus_register_board_info(ubnt_rocket_m_ti_mdio_info,
-+ ARRAY_SIZE(ubnt_rocket_m_ti_mdio_info));
-+ ath79_register_mdio(0, 0x0);
-+
-+
-+ ath79_eth0_data.phy_mask = BIT(4);
-+ /* read out from vendor */
-+ ath79_eth0_pll_data.pll_1000 = 0x2000000;
-+ ath79_eth0_pll_data.pll_10 = 0x1313;
-+ ath79_register_eth(0);
-+
-+ ath79_register_mdio(1, 0x0);
-+ ath79_eth1_data.phy_mask = BIT(3);
-+ ath79_register_eth(1);
-+}
-+
-+
-+MIPS_MACHINE(ATH79_MACH_UBNT_NANO_M_XW, "UBNT-NM-XW", "Ubiquiti Nanostation M XW",
-+ ubnt_nano_m_xw_setup);
-+
-+MIPS_MACHINE(ATH79_MACH_UBNT_LOCO_M_XW, "UBNT-LOCO-XW", "Ubiquiti Loco M XW",
-+ ubnt_loco_m_xw_setup);
-+
-+MIPS_MACHINE(ATH79_MACH_UBNT_ROCKET_M_XW, "UBNT-RM-XW", "Ubiquiti Rocket M XW",
-+ ubnt_rocket_m_xw_setup);
-+
-+MIPS_MACHINE(ATH79_MACH_UBNT_ROCKET_M_TI, "UBNT-RM-TI", "Ubiquiti Rocket M TI",
-+ ubnt_rocket_m_ti_setup);
-+
-+static struct gpio_led ubnt_airgateway_gpio_leds[] __initdata = {
-+ {
-+ .name = "ubnt:blue:wlan",
-+ .gpio = 0,
-+ }, {
-+ .name = "ubnt:white:status",
-+ .gpio = 1,
-+ },
-+};
-+
-+static struct gpio_keys_button airgateway_gpio_keys[] __initdata = {
-+ {
-+ .desc = "reset",
-+ .type = EV_KEY,
-+ .code = KEY_RESTART,
-+ .debounce_interval = UBNT_XM_KEYS_DEBOUNCE_INTERVAL,
-+ .gpio = 12,
-+ .active_low = 1,
-+ }
-+};
-+
-+static void __init ubnt_airgateway_setup(void)
-+{
-+ u32 t;
-+ u8 *mac0 = (u8 *) KSEG1ADDR(0x1fff0000);
-+ u8 *mac1 = (u8 *) KSEG1ADDR(0x1fff0000 + ETH_ALEN);
-+ u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
-+
-+
-+ ath79_gpio_function_disable(AR933X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
-+ AR933X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
-+ AR933X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
-+ AR933X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
-+ AR933X_GPIO_FUNC_ETH_SWITCH_LED4_EN);
-+
-+ t = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP);
-+ t |= AR933X_BOOTSTRAP_MDIO_GPIO_EN;
-+ ath79_reset_wr(AR933X_RESET_REG_BOOTSTRAP, t);
-+
-+ ath79_register_m25p80(NULL);
-+ ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_airgateway_gpio_leds),
-+ ubnt_airgateway_gpio_leds);
-+
-+ ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
-+ ARRAY_SIZE(airgateway_gpio_keys),
-+ airgateway_gpio_keys);
-+
-+ ath79_init_mac(ath79_eth1_data.mac_addr, mac0, 0);
-+ ath79_init_mac(ath79_eth0_data.mac_addr, mac1, 0);
-+
-+ ath79_register_mdio(0, 0x0);
-+
-+ ath79_register_eth(1);
-+ ath79_register_eth(0);
-+
-+ ath79_register_wmac(ee, NULL);
-+}
-+
-+MIPS_MACHINE(ATH79_MACH_UBNT_AIRGW, "UBNT-AGW", "Ubiquiti AirGateway",
-+ ubnt_airgateway_setup);
-+
--- a/arch/mips/ath79/Kconfig
+++ b/arch/mips/ath79/Kconfig
@@ -68,12 +68,16 @@ config ATH79_MACH_PB44
Atheros PB44 reference board.
-
+
config ATH79_MACH_UBNT_XM
- bool "Ubiquiti Networks XM (rev 1.0) board"
+ bool "Ubiquiti Networks XM/UniFi boards"
diff --git a/target/linux/ar71xx/patches-4.4/610-MIPS-ath79-UBNT-add-airGateway-pro-support.patch b/target/linux/ar71xx/patches-4.4/610-MIPS-ath79-UBNT-add-airGateway-pro-support.patch
deleted file mode 100644
index 27cc1e50a7..0000000000
--- a/target/linux/ar71xx/patches-4.4/610-MIPS-ath79-UBNT-add-airGateway-pro-support.patch
+++ /dev/null
@@ -1,62 +0,0 @@
---- a/arch/mips/ath79/mach-ubnt-xm.c
-+++ b/arch/mips/ath79/mach-ubnt-xm.c
-@@ -642,3 +642,59 @@ static void __init ubnt_airgateway_setup
- MIPS_MACHINE(ATH79_MACH_UBNT_AIRGW, "UBNT-AGW", "Ubiquiti AirGateway",
- ubnt_airgateway_setup);
-
-+static struct gpio_led ubnt_airgateway_pro_gpio_leds[] __initdata = {
-+ {
-+ .name = "ubnt:blue:wlan",
-+ .gpio = 13,
-+ }, {
-+ .name = "ubnt:white:status",
-+ .gpio = 17,
-+ },
-+};
-+
-+
-+static struct gpio_keys_button airgateway_pro_gpio_keys[] __initdata = {
-+ {
-+ .desc = "reset",
-+ .type = EV_KEY,
-+ .code = KEY_RESTART,
-+ .debounce_interval = UBNT_XM_KEYS_DEBOUNCE_INTERVAL,
-+ .gpio = 12,
-+ .active_low = 1,
-+ }
-+};
-+
-+static void __init ubnt_airgateway_pro_setup(void)
-+{
-+ u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff0000);
-+ u8 *mac0 = (u8 *) KSEG1ADDR(0x1fff0000);
-+
-+ ath79_register_m25p80(NULL);
-+ ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_airgateway_pro_gpio_leds),
-+ ubnt_airgateway_pro_gpio_leds);
-+
-+ ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
-+ ARRAY_SIZE(airgateway_pro_gpio_keys),
-+ airgateway_pro_gpio_keys);
-+
-+ ath79_register_wmac(eeprom + UAP_PRO_WMAC_CALDATA_OFFSET, NULL);
-+ ap91_pci_init(eeprom + UAP_PRO_PCI_CALDATA_OFFSET, NULL);
-+
-+
-+ ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_SW_ONLY_MODE);
-+
-+ ath79_register_mdio(1, 0x0);
-+
-+ /* GMAC0 is left unused in this configuration */
-+
-+ /* GMAC1 is connected to MAC0 on the internal switch */
-+ /* The PoE/WAN port connects to port 5 on the internal switch */
-+ /* The LAN port connects to port 4 on the internal switch */
-+ ath79_init_mac(ath79_eth1_data.mac_addr, mac0, 0);
-+ ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
-+ ath79_register_eth(1);
-+
-+}
-+
-+MIPS_MACHINE(ATH79_MACH_UBNT_AIRGWP, "UBNT-AGWP", "Ubiquiti AirGateway Pro",
-+ ubnt_airgateway_pro_setup);
diff --git a/target/linux/ar71xx/patches-4.4/620-MIPS-ath79-add-support-for-QCA953x-SoC.patch b/target/linux/ar71xx/patches-4.4/620-MIPS-ath79-add-support-for-QCA953x-SoC.patch
index 6fd6dafd47..08a684becd 100644
--- a/target/linux/ar71xx/patches-4.4/620-MIPS-ath79-add-support-for-QCA953x-SoC.patch
+++ b/target/linux/ar71xx/patches-4.4/620-MIPS-ath79-add-support-for-QCA953x-SoC.patch
@@ -335,10 +335,10 @@ meaning of the bits CPUCLK_FROM_CPUPLL and DDRCLK_FROM_DDRPLL is reversed.
+ status = ath79_reset_rr(QCA953X_RESET_REG_PCIE_WMAC_INT_STATUS);
+
+ if (status & QCA953X_PCIE_WMAC_INT_PCIE_ALL) {
-+ ath79_ddr_wb_flush(QCA953X_DDR_REG_FLUSH_PCIE);
++ ath79_ddr_wb_flush(3);
+ generic_handle_irq(ATH79_IP2_IRQ(0));
+ } else if (status & QCA953X_PCIE_WMAC_INT_WMAC_ALL) {
-+ ath79_ddr_wb_flush(QCA953X_DDR_REG_FLUSH_WMAC);
++ ath79_ddr_wb_flush(4);
+ generic_handle_irq(ATH79_IP2_IRQ(1));
+ } else {
+ spurious_interrupt();
diff --git a/target/linux/ar71xx/patches-4.4/910-unaligned_access_hacks.patch b/target/linux/ar71xx/patches-4.4/910-unaligned_access_hacks.patch
index b4b749e4b9..17a53ed6e6 100644
--- a/target/linux/ar71xx/patches-4.4/910-unaligned_access_hacks.patch
+++ b/target/linux/ar71xx/patches-4.4/910-unaligned_access_hacks.patch
@@ -299,7 +299,7 @@
ptr--;
}
if (tunnel->parms.o_flags&GRE_KEY) {
-@@ -836,7 +836,7 @@ static inline int ip6gre_xmit_ipv6(struc
+@@ -838,7 +838,7 @@ static inline int ip6gre_xmit_ipv6(struc
dsfield = ipv6_get_dsfield(ipv6h);
if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)
@@ -310,7 +310,7 @@
if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
-@@ -1396,7 +1396,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, str
+@@ -1386,7 +1386,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, str
dsfield = ipv6_get_dsfield(ipv6h);
if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)
@@ -491,7 +491,7 @@
memcpy(p, foc->val, foc->len);
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
-@@ -501,7 +501,7 @@ static struct sk_buff *add_grec(struct s
+@@ -500,7 +500,7 @@ static struct sk_buff *add_grec(struct s
if (!skb)
return NULL;
psrc = (__be32 *)skb_put(skb, sizeof(__be32));
@@ -910,3 +910,22 @@
/* Values for "flag" field in struct arpt_ip (general arp structure).
* No flags defined yet.
+--- a/net/core/utils.c
++++ b/net/core/utils.c
+@@ -321,8 +321,14 @@ void inet_proto_csum_replace16(__sum16 *
+ bool pseudohdr)
+ {
+ __be32 diff[] = {
+- ~from[0], ~from[1], ~from[2], ~from[3],
+- to[0], to[1], to[2], to[3],
++ ~net_hdr_word(&from[0]),
++ ~net_hdr_word(&from[1]),
++ ~net_hdr_word(&from[2]),
++ ~net_hdr_word(&from[3]),
++ net_hdr_word(&to[0]),
++ net_hdr_word(&to[1]),
++ net_hdr_word(&to[2]),
++ net_hdr_word(&to[3]),
+ };
+ if (skb->ip_summed != CHECKSUM_PARTIAL) {
+ *sum = csum_fold(csum_partial(diff, sizeof(diff),
diff --git a/target/linux/arc770/image/Makefile b/target/linux/arc770/image/Makefile
index 6b9c5e4524..47c936e556 100644
--- a/target/linux/arc770/image/Makefile
+++ b/target/linux/arc770/image/Makefile
@@ -7,6 +7,13 @@
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/image.mk
+# On ARC initramfs is put before entry point and so entry point moves
+# in memory from build to built. Thus we need to extract EP from vmlinux
+# every time late in building process.
+define Build/calculate-ep
+ $(eval KERNEL_ENTRY=$(shell $(KERNEL_CROSS)readelf -h $(LINUX_DIR)/vmlinux | grep "Entry point address" | grep -o 0x.*))
+endef
+
define Build/patch-dtb
$(call Image/BuildDTB,../dts/$(DEVICE_DTS).dts,$@.dtb)
$(STAGING_DIR_HOST)/bin/patch-dtb $@ $@.dtb
@@ -16,26 +23,47 @@ endef
define Device/Default
PROFILES = Default $$(DEVICE_PROFILE)
KERNEL_DEPENDS = $$(wildcard ../dts/$$(DEVICE_DTS).dts)
- KERNEL_SUFFIX := .elf
- KERNEL_INITRAMFS := kernel-bin | patch-dtb
- KERNEL_INITRAMFS_NAME = $$(KERNEL_NAME)-initramfs.elf
DEVICE_PROFILE :=
DEVICE_DTS :=
endef
DEVICE_VARS += DEVICE_PROFILE DEVICE_DTS
-define add_arc770
- define Device/$(1)
+define Device/vmlinux
+ KERNEL_SUFFIX := .elf
+ KERNEL_INITRAMFS := kernel-bin | patch-dtb
+ KERNEL_INITRAMFS_NAME = vmlinux-initramfs.elf
+endef
+
+define Device/uImage
+ KERNEL_SUFFIX := .bin
+ KERNEL_INITRAMFS := kernel-bin | patch-dtb | calculate-ep | uImage none
+ KERNEL_LOADADDR := 0x80000000
+endef
+
+define add_arc770_uImage
+ define Device/$(1)-uImage
+ $(call Device/uImage)
+ DEVICE_PROFILE := $(1)
+ DEVICE_DTS := $(1)
+ endef
+ TARGET_DEVICES += $(1)-uImage
+endef
+
+define add_arc770_vmlinux
+ define Device/$(1)-vmlinux
+ $(call Device/vmlinux)
DEVICE_PROFILE := $(1)
DEVICE_DTS := $(1)
endef
- TARGET_DEVICES += $(1)
+ TARGET_DEVICES += $(1)-vmlinux
endef
# DesignWare AXS101
-$(eval $(call add_arc770,axs101))
+$(eval $(call add_arc770_vmlinux,axs101))
+$(eval $(call add_arc770_uImage,axs101))
# nSIM with ARC770
-$(eval $(call add_arc770,nsim_700))
+$(eval $(call add_arc770_vmlinux,nsim_700))
+$(eval $(call add_arc770_uImage,nsim_700))
$(eval $(call BuildImage))
diff --git a/target/linux/archs38/image/Makefile b/target/linux/archs38/image/Makefile
index 9b0e53f64c..03bd8ee8eb 100644
--- a/target/linux/archs38/image/Makefile
+++ b/target/linux/archs38/image/Makefile
@@ -7,6 +7,13 @@
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/image.mk
+# On ARC initramfs is put before entry point and so entry point moves
+# in memory from build to built. Thus we need to extract EP from vmlinux
+# every time before generation of uImage.
+define Build/calculate-ep
+ $(eval KERNEL_ENTRY=$(shell $(KERNEL_CROSS)readelf -h $(LINUX_DIR)/vmlinux | grep "Entry point address" | grep -o 0x.*))
+endef
+
define Build/patch-dtb
$(call Image/BuildDTB,../dts/$(DEVICE_DTS).dts,$@.dtb)
$(STAGING_DIR_HOST)/bin/patch-dtb $@ $@.dtb
@@ -16,26 +23,47 @@ endef
define Device/Default
PROFILES = Default $$(DEVICE_PROFILE)
KERNEL_DEPENDS = $$(wildcard ../dts/$$(DEVICE_DTS).dts)
- KERNEL_SUFFIX := .elf
- KERNEL_INITRAMFS := kernel-bin | patch-dtb
- KERNEL_INITRAMFS_NAME = $$(KERNEL_NAME)-initramfs.elf
DEVICE_PROFILE :=
DEVICE_DTS :=
endef
DEVICE_VARS += DEVICE_PROFILE DEVICE_DTS
-define add_archs38
- define Device/$(1)
+define Device/vmlinux
+ KERNEL_SUFFIX := .elf
+ KERNEL_INITRAMFS := kernel-bin | patch-dtb
+ KERNEL_INITRAMFS_NAME = vmlinux-initramfs.elf
+endef
+
+define Device/uImage
+ KERNEL_SUFFIX := .bin
+ KERNEL_INITRAMFS := kernel-bin | patch-dtb | calculate-ep | uImage none
+ KERNEL_LOADADDR := 0x80000000
+endef
+
+define add_archs38_uImage
+ define Device/$(1)-uImage
+ $(call Device/uImage)
+ DEVICE_PROFILE := $(1)
+ DEVICE_DTS := $(1)
+ endef
+ TARGET_DEVICES += $(1)-uImage
+endef
+
+define add_archs38_vmlinux
+ define Device/$(1)-vmlinux
+ $(call Device/vmlinux)
DEVICE_PROFILE := $(1)
DEVICE_DTS := $(1)
endef
- TARGET_DEVICES += $(1)
+ TARGET_DEVICES += $(1)-vmlinux
endef
# DesignWare AXS103
-$(eval $(call add_archs38,axs103_idu))
+$(eval $(call add_archs38_vmlinux,axs103_idu))
+$(eval $(call add_archs38_uImage,axs103_idu))
# nSIM with ARCHS38
-$(eval $(call add_archs38,nsim_hs_idu))
+$(eval $(call add_archs38_vmlinux,nsim_hs_idu))
+$(eval $(call add_archs38_uImage,nsim_hs_idu))
$(eval $(call BuildImage))
diff --git a/target/linux/at91/config-4.4 b/target/linux/at91/config-4.4
index 033d0ad6d9..37b98c1246 100644
--- a/target/linux/at91/config-4.4
+++ b/target/linux/at91/config-4.4
@@ -251,7 +251,6 @@ CONFIG_SPI_SPIDEV=y
CONFIG_SPLIT_PTLOCK_CPUS=999999
CONFIG_SRCU=y
# CONFIG_STAGING is not set
-# CONFIG_SUNXI_SRAM is not set
CONFIG_SWIOTLB=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
CONFIG_TICK_CPU_ACCOUNTING=y
diff --git a/target/linux/at91/sama5d3/config-default b/target/linux/at91/sama5d3/config-default
index 62aef01668..660e27e8aa 100644
--- a/target/linux/at91/sama5d3/config-default
+++ b/target/linux/at91/sama5d3/config-default
@@ -1,13 +1,20 @@
+# CONFIG_ARCH_MULTI_V4_V5 is not set
+# CONFIG_ARCH_MULTI_V5 is not set
+CONFIG_ARCH_MULTI_V7=y
+# CONFIG_ARM_LPAE is not set
+# CONFIG_ARM_THUMBEE is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
CONFIG_SOC_SAMA5=y
# CONFIG_SOC_SAM_V4_V5 is not set
CONFIG_SOC_SAM_V7=y
+CONFIG_SOC_SAMA5D2=y
CONFIG_SOC_SAMA5D3=y
CONFIG_SOC_SAMA5D4=y
CONFIG_MACH_SAMA5_DT=y
-# CONFIG_ARM_LPAE is not set
-# CONFIG_ARM_THUMBEE is not set
+CONFIG_PL310_ERRATA_588369=y
+CONFIG_PL310_ERRATA_727915=y
+CONFIG_PL310_ERRATA_753970=y
+CONFIG_PL310_ERRATA_769419=y
# CONFIG_SWP_EMULATE is not set
-# CONFIG_CPU_ICACHE_DISABLE is not set
-# CONFIG_CPU_BPREDICT_DISABLE is not set
# CONFIG_THUMB2_KERNEL is not set
-# CONFIG_XEN is not set
diff --git a/target/linux/ath25/Makefile b/target/linux/ath25/Makefile
index ae867e9039..03aa2a9355 100644
--- a/target/linux/ath25/Makefile
+++ b/target/linux/ath25/Makefile
@@ -12,7 +12,7 @@ BOARDNAME:=Atheros AR231x/AR5312
FEATURES:=squashfs low_mem
MAINTAINER:=Sergey Ryazanov <ryazanov.s.a@gmail.com>
-KERNEL_PATCHVER:=3.18
+KERNEL_PATCHVER:=4.4
include $(INCLUDE_DIR)/target.mk
diff --git a/target/linux/ath25/base-files/etc/config/system b/target/linux/ath25/base-files/etc/config/system
index 1d29ad8c39..0834b5260f 100644
--- a/target/linux/ath25/base-files/etc/config/system
+++ b/target/linux/ath25/base-files/etc/config/system
@@ -7,17 +7,3 @@ config timeserver ntp
list server 1.openwrt.pool.ntp.org
list server 2.openwrt.pool.ntp.org
list server 3.openwrt.pool.ntp.org
-
-config button
- option button reset
- option action released
- option handler "logger reboot"
- option min 0
- option max 4
-
-config button
- option button reset
- option action released
- option handler "logger factory default"
- option min 5
- option max 30
diff --git a/target/linux/ath25/base-files/etc/hotplug.d/button/00-button b/target/linux/ath25/base-files/etc/hotplug.d/button/00-button
deleted file mode 100644
index 63cc217d5d..0000000000
--- a/target/linux/ath25/base-files/etc/hotplug.d/button/00-button
+++ /dev/null
@@ -1,24 +0,0 @@
-. /lib/functions.sh
-do_button () {
- local button
- local action
- local handler
- local min
- local max
-
- config_get button $1 button
- config_get action $1 action
- config_get handler $1 handler
- config_get min $1 min
- config_get max $1 max
-
- [ "$ACTION" = "$action" -a "$BUTTON" = "$button" -a -n "$handler" ] && {
- [ -z "$min" -o -z "$max" ] && eval $handler
- [ -n "$min" -a -n "$max" ] && {
- [ $min -le $SEEN -a $max -ge $SEEN ] && eval $handler
- }
- }
-}
-
-config_load system
-config_foreach do_button button
diff --git a/target/linux/ath25/config-3.18 b/target/linux/ath25/config-3.18
deleted file mode 100644
index 885604199e..0000000000
--- a/target/linux/ath25/config-3.18
+++ /dev/null
@@ -1,136 +0,0 @@
-CONFIG_ADM6996_PHY=y
-CONFIG_AR2315_WDT=y
-CONFIG_AR8216_PHY=y
-CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
-CONFIG_ARCH_DISCARD_MEMBLOCK=y
-CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=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_MIGHT_HAVE_PC_SERIO=y
-CONFIG_ARCH_REQUIRE_GPIOLIB=y
-CONFIG_ARCH_SUSPEND_POSSIBLE=y
-CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
-CONFIG_ATH25=y
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_CEVT_R4K=y
-CONFIG_CLONE_BACKWARDS=y
-CONFIG_CMDLINE="console=ttyS0,9600 rootfstype=squashfs,jffs2"
-CONFIG_CMDLINE_BOOL=y
-# CONFIG_CMDLINE_OVERRIDE is not set
-CONFIG_CPU_BIG_ENDIAN=y
-CONFIG_CPU_GENERIC_DUMP_TLB=y
-CONFIG_CPU_HAS_PREFETCH=y
-CONFIG_CPU_HAS_SYNC=y
-CONFIG_CPU_MIPS32=y
-CONFIG_CPU_MIPS32_R1=y
-CONFIG_CPU_MIPSR1=y
-CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y
-CONFIG_CPU_R4K_CACHE_TLB=y
-CONFIG_CPU_R4K_FPU=y
-CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_HIGHMEM=y
-CONFIG_CSRC_R4K=y
-CONFIG_DMA_NONCOHERENT=y
-CONFIG_EARLY_PRINTK=y
-CONFIG_ETHERNET_PACKET_MANGLE=y
-CONFIG_GENERIC_ATOMIC64=y
-CONFIG_GENERIC_CLOCKEVENTS=y
-CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
-CONFIG_GENERIC_CMOS_UPDATE=y
-CONFIG_GENERIC_IO=y
-CONFIG_GENERIC_IRQ_SHOW=y
-CONFIG_GENERIC_PCI_IOMAP=y
-CONFIG_GENERIC_SMP_IDLE_THREAD=y
-CONFIG_GPIOLIB=y
-CONFIG_GPIO_AR2315=y
-CONFIG_GPIO_AR5312=y
-CONFIG_GPIO_DEVRES=y
-CONFIG_GPIO_SYSFS=y
-CONFIG_HARDWARE_WATCHPOINTS=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_JUMP_LABEL=y
-CONFIG_HAVE_ARCH_KGDB=y
-CONFIG_HAVE_ARCH_SECCOMP_FILTER=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_CONTEXT_TRACKING=y
-CONFIG_HAVE_C_RECORDMCOUNT=y
-CONFIG_HAVE_DEBUG_KMEMLEAK=y
-CONFIG_HAVE_DEBUG_STACKOVERFLOW=y
-CONFIG_HAVE_DMA_API_DEBUG=y
-CONFIG_HAVE_DMA_ATTRS=y
-CONFIG_HAVE_DMA_CONTIGUOUS=y
-CONFIG_HAVE_DYNAMIC_FTRACE=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_IDE=y
-CONFIG_HAVE_MEMBLOCK=y
-CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
-CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
-CONFIG_HAVE_NET_DSA=y
-CONFIG_HAVE_OPROFILE=y
-CONFIG_HAVE_PERF_EVENTS=y
-CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
-CONFIG_HW_HAS_PCI=y
-CONFIG_HW_RANDOM=y
-CONFIG_HZ_PERIODIC=y
-CONFIG_INITRAMFS_SOURCE=""
-CONFIG_IP17XX_PHY=y
-CONFIG_IRQ_CPU=y
-CONFIG_IRQ_DOMAIN=y
-CONFIG_IRQ_FORCED_THREADING=y
-CONFIG_IRQ_WORK=y
-CONFIG_LEDS_GPIO=y
-CONFIG_MDIO_BOARDINFO=y
-CONFIG_MIPS=y
-# CONFIG_MIPS_HUGE_TLB_SUPPORT is not set
-CONFIG_MIPS_L1_CACHE_SHIFT=5
-# CONFIG_MIPS_MACHINE is not set
-CONFIG_MODULES_USE_ELF_REL=y
-CONFIG_MTD_AR2315=y
-CONFIG_MTD_CFI_ADV_OPTIONS=y
-# CONFIG_MTD_CFI_GEOMETRY is not set
-# CONFIG_MTD_CFI_INTELEXT is not set
-CONFIG_MTD_MYLOADER_PARTS=y
-CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-3
-CONFIG_MTD_REDBOOT_PARTS=y
-CONFIG_MVSWITCH_PHY=y
-CONFIG_NEED_DMA_MAP_STATE=y
-CONFIG_NEED_PER_CPU_KM=y
-CONFIG_NET_AR231X=y
-CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y
-# CONFIG_NO_IOPORT_MAP is not set
-CONFIG_PAGEFLAGS_EXTENDED=y
-CONFIG_PCI=y
-CONFIG_PCI_AR2315=y
-CONFIG_PCI_DISABLE_COMMON_QUIRKS=y
-CONFIG_PCI_DOMAINS=y
-CONFIG_PERF_USE_VMALLOC=y
-CONFIG_PHYLIB=y
-# CONFIG_PREEMPT_RCU is not set
-# CONFIG_RCU_STALL_COMMON is not set
-# CONFIG_SCSI_DMA is not set
-CONFIG_SERIAL_8250_NR_UARTS=1
-CONFIG_SERIAL_8250_RUNTIME_UARTS=1
-CONFIG_SOC_AR2315=y
-CONFIG_SOC_AR5312=y
-# CONFIG_SWAP is not set
-CONFIG_SWCONFIG=y
-CONFIG_SYS_HAS_CPU_MIPS32_R1=y
-CONFIG_SYS_HAS_EARLY_PRINTK=y
-CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
-CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
-CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
-CONFIG_TICK_CPU_ACCOUNTING=y
-CONFIG_USB_SUPPORT=y
-CONFIG_ZONE_DMA_FLAG=0
diff --git a/target/linux/ath25/config-4.4 b/target/linux/ath25/config-4.4
new file mode 100644
index 0000000000..3985437253
--- /dev/null
+++ b/target/linux/ath25/config-4.4
@@ -0,0 +1,155 @@
+CONFIG_ADM6996_PHY=y
+CONFIG_AR2315_WDT=y
+CONFIG_AR8216_PHY=y
+CONFIG_ARCH_BINFMT_ELF_STATE=y
+CONFIG_ARCH_CLOCKSOURCE_DATA=y
+CONFIG_ARCH_DISCARD_MEMBLOCK=y
+CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
+CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
+# CONFIG_ARCH_HAS_GCOV_PROFILE_ALL is not set
+# CONFIG_ARCH_HAS_SG_CHAIN is not set
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
+CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_ARCH_SUPPORTS_UPROBES=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ARCH_USE_BUILTIN_BSWAP=y
+CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
+CONFIG_ATH25=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_CEVT_R4K=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_CMDLINE="console=ttyS0,9600 rootfstype=squashfs,jffs2"
+CONFIG_CMDLINE_BOOL=y
+# CONFIG_CMDLINE_OVERRIDE is not set
+CONFIG_CPU_BIG_ENDIAN=y
+CONFIG_CPU_GENERIC_DUMP_TLB=y
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y
+CONFIG_CPU_R4K_CACHE_TLB=y
+CONFIG_CPU_R4K_FPU=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_WORKQUEUE=y
+CONFIG_CSRC_R4K=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_ETHERNET_PACKET_MANGLE=y
+CONFIG_GENERIC_ATOMIC64=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_IO=y
+CONFIG_GENERIC_IRQ_CHIP=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_AR2315=y
+CONFIG_GPIO_AR5312=y
+CONFIG_GPIO_DEVRES=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_HARDWARE_WATCHPOINTS=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_SECCOMP_FILTER=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_CONTEXT_TRACKING=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_HAVE_DEBUG_KMEMLEAK=y
+CONFIG_HAVE_DEBUG_STACKOVERFLOW=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_DMA_CONTIGUOUS=y
+CONFIG_HAVE_DYNAMIC_FTRACE=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_IDE=y
+CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
+CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
+CONFIG_HAVE_NET_DSA=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
+CONFIG_HW_HAS_PCI=y
+CONFIG_HW_RANDOM=y
+CONFIG_HZ_PERIODIC=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_IP17XX_PHY=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_MIPS_CPU=y
+CONFIG_IRQ_WORK=y
+CONFIG_LEDS_GPIO=y
+CONFIG_MDIO_BOARDINFO=y
+CONFIG_MIPS=y
+CONFIG_MIPS_CLOCK_VSYSCALL=y
+CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER=y
+# CONFIG_MIPS_HUGE_TLB_SUPPORT is not set
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+# CONFIG_MIPS_MACHINE is not set
+CONFIG_MODULES_USE_ELF_REL=y
+CONFIG_MTD_AR2315=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+# CONFIG_MTD_CFI_GEOMETRY is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_MYLOADER_PARTS=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-3
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MVSWITCH_PHY=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEED_PER_CPU_KM=y
+CONFIG_NET_AR231X=y
+CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y
+# CONFIG_NO_IOPORT_MAP is not set
+# CONFIG_OF is not set
+CONFIG_PCI=y
+CONFIG_PCI_AR2315=y
+CONFIG_PCI_DISABLE_COMMON_QUIRKS=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PGTABLE_LEVELS=2
+CONFIG_PHYLIB=y
+# CONFIG_RCU_STALL_COMMON is not set
+CONFIG_SCHED_HRTICK=y
+# CONFIG_SCHED_INFO is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SERIAL_8250_FSL is not set
+CONFIG_SERIAL_8250_NR_UARTS=1
+CONFIG_SERIAL_8250_RUNTIME_UARTS=1
+CONFIG_SOC_AR2315=y
+CONFIG_SOC_AR5312=y
+CONFIG_SRCU=y
+# CONFIG_SWAP is not set
+CONFIG_SWCONFIG=y
+CONFIG_SYSCTL_EXCEPTION_TRACE=y
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_SYS_HAS_EARLY_PRINTK=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_USB_SUPPORT=y
+CONFIG_ZONE_DMA_FLAG=0
diff --git a/target/linux/ath25/image/Makefile b/target/linux/ath25/image/Makefile
index 6bdb3c4755..94d38e8d69 100644
--- a/target/linux/ath25/image/Makefile
+++ b/target/linux/ath25/image/Makefile
@@ -7,54 +7,104 @@
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/image.mk
+DEVICE_VARS += KERNEL_PREFIX FILESYSTEMS
+
define Image/BuildKernel
cp $(KDIR)/vmlinux.elf $(BIN_DIR)/$(IMG_PREFIX)-vmlinux.elf
gzip -9n -c $(KDIR)/vmlinux > $(KDIR)/vmlinux.bin.gz
- $(STAGING_DIR_HOST)/bin/lzma e $(KDIR)/vmlinux $(KDIR)/vmlinux.bin.l7
- dd if=$(KDIR)/vmlinux.bin.l7 of=$(BIN_DIR)/$(IMG_PREFIX)-vmlinux.lzma bs=65536 conv=sync
+ $(STAGING_DIR_HOST)/bin/lzma e $(KDIR)/vmlinux $(KDIR)/vmlinux.bin.lzma
dd if=$(KDIR)/vmlinux.bin.gz of=$(BIN_DIR)/$(IMG_PREFIX)-vmlinux.gz bs=65536 conv=sync
+ dd if=$(KDIR)/vmlinux.bin.lzma of=$(BIN_DIR)/$(IMG_PREFIX)-vmlinux.lzma bs=65536 conv=sync
endef
define Image/Build/squashfs
- $(call prepare_generic_squashfs,$(KDIR)/root.squashfs)
+ $(call prepare_generic_squashfs,$(KDIR)/root.squashfs)
endef
define Image/Build
$(call Image/Build/$(1))
dd if=$(KDIR)/root.$(1) of=$(BIN_DIR)/$(IMG_PREFIX)-root.$(1) bs=128k conv=sync
+endef
+
+define Device/Default
+ PROFILES = Default $$(DEVICE_NAME)
+ KERNEL := lzma-kernel
+ IMAGES := sysupgrade.bin
+ FILESYSTEMS := squashfs
+endef
- -$(STAGING_DIR_HOST)/bin/mkfwimage \
- -B XS2 -v XS2.ar2316.OpenWrt.$(REVISION) \
- -k $(BIN_DIR)/$(IMG_PREFIX)-vmlinux.lzma \
- -r $(BIN_DIR)/$(IMG_PREFIX)-root.$(1) \
- -o $(BIN_DIR)/$(IMG_PREFIX)-ubnt2-$(1).bin
-
- -$(STAGING_DIR_HOST)/bin/mkfwimage \
- -B XS5 -v XS5.ar2313.OpenWrt.$(REVISION) \
- -k $(BIN_DIR)/$(IMG_PREFIX)-vmlinux.lzma \
- -r $(BIN_DIR)/$(IMG_PREFIX)-root.$(1) \
- -o $(BIN_DIR)/$(IMG_PREFIX)-ubnt5-$(1).bin
-
- -$(STAGING_DIR_HOST)/bin/mkfwimage \
- -B XS2-8 -v XS2.ar2316.OpenWrt.$(REVISION) \
- -k $(BIN_DIR)/$(IMG_PREFIX)-vmlinux.lzma \
- -r $(BIN_DIR)/$(IMG_PREFIX)-root.$(1) \
- -o $(BIN_DIR)/$(IMG_PREFIX)-ubnt2-pico2-$(1).bin
-
- -$(STAGING_DIR_HOST)/bin/mkmylofw -B np25g \
- -p0x020000:0x130000:ah:0x80041000:linux:$(KDIR)/vmlinux.bin.gz \
- -p0x150000:0x2a0000:::rootfs:$(BIN_DIR)/$(IMG_PREFIX)-root.$(1) \
- $(BIN_DIR)/$(IMG_PREFIX)-np25g-$(1).bin
-
- -$(STAGING_DIR_HOST)/bin/mkmylofw -B wpe53g \
- -p0x020000:0x130000:ah:0x80041000:linux:$(KDIR)/vmlinux.bin.gz \
- -p0x150000:0x2a0000:::rootfs:$(BIN_DIR)/$(IMG_PREFIX)-root.$(1) \
- $(BIN_DIR)/$(IMG_PREFIX)-wpe53g-$(1).bin
+define Build/mkfwimage
+ $(STAGING_DIR_HOST)/bin/mkfwimage \
+ -B $(1).OpenWrt.$(REVISION) \
+ -k $(KDIR)/$(KERNEL_IMAGE) \
+ -r $@ \
+ -o $@.new && \
+ mv $@.new $@
+endef
+define Build/combined-image
-sh $(TOPDIR)/scripts/combined-image.sh \
- "$(BIN_DIR)/$(IMG_PREFIX)-vmlinux.lzma" \
- "$(BIN_DIR)/$(IMG_PREFIX)-root.$(1)" \
- "$(BIN_DIR)/$(IMG_PREFIX)-combined.$(1).img"
+ "$(KDIR)/$(KERNEL_IMAGE)" \
+ "$@" \
+ "$@.new" && \
+ mv $@.new $@
+endef
+
+define Build/mkmylofw
+ $(STAGING_DIR_HOST)/bin/mkmylofw -B $(1) \
+ -p0x020000:0x130000:ah:0x80041000:linux:$(KDIR)/$(KERNEL_IMAGE) \
+ -p0x150000:0x2a0000:::rootfs:$@ \
+ $@.new && \
+ mv $@.new $@
+endef
+
+define Build/gzip-kernel
+ gzip -9n -c $(KDIR)/vmlinux > $@
+ dd if=$@ of=$@.new bs=65536 conv=sync
+ mv $@.new $@
+endef
+
+define Build/lzma-kernel
+ $(STAGING_DIR_HOST)/bin/lzma e $(KDIR)/vmlinux $@.l7
+ dd if=$@.l7 of=$@ bs=65536 conv=sync
+endef
+
+define Device/combined
+ DEVICE_TITLE := Combined Image
+ IMAGE/sysupgrade.bin := append-rootfs | pad-rootfs | pad-to 128k | combined-image
+endef
+TARGET_DEVICES += combined
+
+define Device/ubnt2-pico2
+ DEVICE_TITLE := Ubiquiti XS2-8
+ IMAGE/sysupgrade.bin := append-rootfs | pad-rootfs | pad-to 128k | mkfwimage XS2-8 -v XS2.ar2316
+endef
+TARGET_DEVICES += ubnt2-pico2
+
+define Device/ubnt2
+ DEVICE_TITLE := Ubiquiti XS2
+ IMAGE/sysupgrade.bin := append-rootfs | pad-rootfs | pad-to 128k | mkfwimage XS2 -v XS2.ar2316
+endef
+TARGET_DEVICES += ubnt2
+
+define Device/ubnt5
+ DEVICE_TITLE := Ubiquiti XS5
+ IMAGE/sysupgrade.bin := append-rootfs | pad-rootfs | pad-to 128k | mkfwimage XS5 -v XS5.ar2313
+endef
+TARGET_DEVICES += ubnt5
+
+define Device/np25g
+ DEVICE_TITLE := np25g
+ KERNEL := gzip-kernel
+ IMAGE/sysupgrade.bin := append-rootfs | pad-rootfs | pad-to 128k | mkmylofw np25g
+endef
+#TARGET_DEVICES += np25g
+
+define Device/wpe53g
+ DEVICE_TITLE := wpe53g
+ KERNEL := gzip-kernel
+ IMAGE/sysupgrade.bin := append-rootfs | pad-rootfs | pad-to 128k | mkmylofw wpe53g
endef
+#TARGET_DEVICES += wpe53g
$(eval $(call BuildImage))
diff --git a/target/linux/ath25/patches-3.18/010-board.patch b/target/linux/ath25/patches-3.18/010-board.patch
deleted file mode 100644
index 8e3fdf47e0..0000000000
--- a/target/linux/ath25/patches-3.18/010-board.patch
+++ /dev/null
@@ -1,2189 +0,0 @@
---- a/arch/mips/Kconfig
-+++ b/arch/mips/Kconfig
-@@ -96,6 +96,19 @@ config AR7
- Support for the Texas Instruments AR7 System-on-a-Chip
- family: TNETD7100, 7200 and 7300.
-
-+config ATH25
-+ bool "Atheros AR231x/AR531x SoC support"
-+ select CEVT_R4K
-+ select CSRC_R4K
-+ select DMA_NONCOHERENT
-+ select IRQ_CPU
-+ select IRQ_DOMAIN
-+ select SYS_HAS_CPU_MIPS32_R1
-+ select SYS_SUPPORTS_BIG_ENDIAN
-+ select SYS_SUPPORTS_32BIT_KERNEL
-+ help
-+ Support for Atheros AR231x and Atheros AR531x based boards
-+
- config ATH79
- bool "Atheros AR71XX/AR724X/AR913X based boards"
- select ARCH_REQUIRE_GPIOLIB
-@@ -835,6 +848,7 @@ config MIPS_PARAVIRT
- endchoice
-
- source "arch/mips/alchemy/Kconfig"
-+source "arch/mips/ath25/Kconfig"
- source "arch/mips/ath79/Kconfig"
- source "arch/mips/bcm47xx/Kconfig"
- source "arch/mips/bcm63xx/Kconfig"
---- a/arch/mips/Kbuild.platforms
-+++ b/arch/mips/Kbuild.platforms
-@@ -2,6 +2,7 @@
-
- platforms += alchemy
- platforms += ar7
-+platforms += ath25
- platforms += ath79
- platforms += bcm47xx
- platforms += bcm63xx
---- /dev/null
-+++ b/arch/mips/ath25/Platform
-@@ -0,0 +1,6 @@
-+#
-+# Atheros AR531X/AR231X WiSoC
-+#
-+platform-$(CONFIG_ATH25) += ath25/
-+cflags-$(CONFIG_ATH25) += -I$(srctree)/arch/mips/include/asm/mach-ath25
-+load-$(CONFIG_ATH25) += 0xffffffff80041000
---- /dev/null
-+++ b/arch/mips/ath25/Kconfig
-@@ -0,0 +1,9 @@
-+config SOC_AR5312
-+ bool "Atheros AR5312/AR2312+ SoC support"
-+ depends on ATH25
-+ default y
-+
-+config SOC_AR2315
-+ bool "Atheros AR2315+ SoC support"
-+ depends on ATH25
-+ default y
---- /dev/null
-+++ b/arch/mips/ath25/Makefile
-@@ -0,0 +1,13 @@
-+#
-+# This file is subject to the terms and conditions of the GNU General Public
-+# License. See the file "COPYING" in the main directory of this archive
-+# for more details.
-+#
-+# Copyright (C) 2006 FON Technology, SL.
-+# Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
-+# Copyright (C) 2006-2009 Felix Fietkau <nbd@nbd.name>
-+#
-+
-+obj-y += board.o prom.o devices.o
-+obj-$(CONFIG_SOC_AR5312) += ar5312.o
-+obj-$(CONFIG_SOC_AR2315) += ar2315.o
---- /dev/null
-+++ b/arch/mips/ath25/board.c
-@@ -0,0 +1,234 @@
-+/*
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file "COPYING" in the main directory of this archive
-+ * for more details.
-+ *
-+ * Copyright (C) 2003 Atheros Communications, Inc., All Rights Reserved.
-+ * Copyright (C) 2006 FON Technology, SL.
-+ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
-+ * Copyright (C) 2006-2009 Felix Fietkau <nbd@nbd.name>
-+ */
-+
-+#include <linux/init.h>
-+#include <linux/interrupt.h>
-+#include <asm/irq_cpu.h>
-+#include <asm/reboot.h>
-+#include <asm/bootinfo.h>
-+#include <asm/time.h>
-+
-+#include <ath25_platform.h>
-+#include "devices.h"
-+#include "ar5312.h"
-+#include "ar2315.h"
-+
-+void (*ath25_irq_dispatch)(void);
-+
-+static inline bool check_radio_magic(const void __iomem *addr)
-+{
-+ addr += 0x7a; /* offset for flash magic */
-+ return (__raw_readb(addr) == 0x5a) && (__raw_readb(addr + 1) == 0xa5);
-+}
-+
-+static inline bool check_notempty(const void __iomem *addr)
-+{
-+ return __raw_readl(addr) != 0xffffffff;
-+}
-+
-+static inline bool check_board_data(const void __iomem *addr, bool broken)
-+{
-+ /* config magic found */
-+ if (__raw_readl(addr) == ATH25_BD_MAGIC)
-+ return true;
-+
-+ if (!broken)
-+ return false;
-+
-+ /* broken board data detected, use radio data to find the
-+ * offset, user will fix this */
-+
-+ if (check_radio_magic(addr + 0x1000))
-+ return true;
-+ if (check_radio_magic(addr + 0xf8))
-+ return true;
-+
-+ return false;
-+}
-+
-+static const void __iomem * __init find_board_config(const void __iomem *limit,
-+ const bool broken)
-+{
-+ const void __iomem *addr;
-+ const void __iomem *begin = limit - 0x1000;
-+ const void __iomem *end = limit - 0x30000;
-+
-+ for (addr = begin; addr >= end; addr -= 0x1000)
-+ if (check_board_data(addr, broken))
-+ return addr;
-+
-+ return NULL;
-+}
-+
-+static const void __iomem * __init find_radio_config(const void __iomem *limit,
-+ const void __iomem *bcfg)
-+{
-+ const void __iomem *rcfg, *begin, *end;
-+
-+ /*
-+ * Now find the start of Radio Configuration data, using heuristics:
-+ * Search forward from Board Configuration data by 0x1000 bytes
-+ * at a time until we find non-0xffffffff.
-+ */
-+ begin = bcfg + 0x1000;
-+ end = limit;
-+ for (rcfg = begin; rcfg < end; rcfg += 0x1000)
-+ if (check_notempty(rcfg) && check_radio_magic(rcfg))
-+ return rcfg;
-+
-+ /* AR2316 relocates radio config to new location */
-+ begin = bcfg + 0xf8;
-+ end = limit - 0x1000 + 0xf8;
-+ for (rcfg = begin; rcfg < end; rcfg += 0x1000)
-+ if (check_notempty(rcfg) && check_radio_magic(rcfg))
-+ return rcfg;
-+
-+ return NULL;
-+}
-+
-+/*
-+ * NB: Search region size could be larger than the actual flash size,
-+ * but this shouldn't be a problem here, because the flash
-+ * will simply be mapped multiple times.
-+ */
-+int __init ath25_find_config(phys_addr_t base, unsigned long size)
-+{
-+ const void __iomem *flash_base, *flash_limit;
-+ struct ath25_boarddata *config;
-+ unsigned int rcfg_size;
-+ int broken_boarddata = 0;
-+ const void __iomem *bcfg, *rcfg;
-+ u8 *board_data;
-+ u8 *radio_data;
-+ u8 *mac_addr;
-+ u32 offset;
-+
-+ flash_base = ioremap_nocache(base, size);
-+ flash_limit = flash_base + size;
-+
-+ ath25_board.config = NULL;
-+ ath25_board.radio = NULL;
-+
-+ /* Copy the board and radio data to RAM, because accessing the mapped
-+ * memory of the flash directly after booting is not safe */
-+
-+ /* Try to find valid board and radio data */
-+ bcfg = find_board_config(flash_limit, false);
-+
-+ /* If that fails, try to at least find valid radio data */
-+ if (!bcfg) {
-+ bcfg = find_board_config(flash_limit, true);
-+ broken_boarddata = 1;
-+ }
-+
-+ if (!bcfg) {
-+ pr_warn("WARNING: No board configuration data found!\n");
-+ goto error;
-+ }
-+
-+ board_data = kzalloc(BOARD_CONFIG_BUFSZ, GFP_KERNEL);
-+ ath25_board.config = (struct ath25_boarddata *)board_data;
-+ memcpy_fromio(board_data, bcfg, 0x100);
-+ if (broken_boarddata) {
-+ pr_warn("WARNING: broken board data detected\n");
-+ config = ath25_board.config;
-+ if (is_zero_ether_addr(config->enet0_mac)) {
-+ pr_info("Fixing up empty mac addresses\n");
-+ config->reset_config_gpio = 0xffff;
-+ config->sys_led_gpio = 0xffff;
-+ random_ether_addr(config->wlan0_mac);
-+ config->wlan0_mac[0] &= ~0x06;
-+ random_ether_addr(config->enet0_mac);
-+ random_ether_addr(config->enet1_mac);
-+ }
-+ }
-+
-+ /* Radio config starts 0x100 bytes after board config, regardless
-+ * of what the physical layout on the flash chip looks like */
-+
-+ rcfg = find_radio_config(flash_limit, bcfg);
-+ if (!rcfg) {
-+ pr_warn("WARNING: Could not find Radio Configuration data\n");
-+ goto error;
-+ }
-+
-+ radio_data = board_data + 0x100 + ((rcfg - bcfg) & 0xfff);
-+ ath25_board.radio = radio_data;
-+ offset = radio_data - board_data;
-+ pr_info("Radio config found at offset 0x%x (0x%x)\n", rcfg - bcfg,
-+ offset);
-+ rcfg_size = BOARD_CONFIG_BUFSZ - offset;
-+ memcpy_fromio(radio_data, rcfg, rcfg_size);
-+
-+ mac_addr = &radio_data[0x1d * 2];
-+ if (is_broadcast_ether_addr(mac_addr)) {
-+ pr_info("Radio MAC is blank; using board-data\n");
-+ ether_addr_copy(mac_addr, ath25_board.config->wlan0_mac);
-+ }
-+
-+ iounmap(flash_base);
-+
-+ return 0;
-+
-+error:
-+ iounmap(flash_base);
-+ return -ENODEV;
-+}
-+
-+static void ath25_halt(void)
-+{
-+ local_irq_disable();
-+ unreachable();
-+}
-+
-+void __init plat_mem_setup(void)
-+{
-+ _machine_halt = ath25_halt;
-+ pm_power_off = ath25_halt;
-+
-+ if (is_ar5312())
-+ ar5312_plat_mem_setup();
-+ else
-+ ar2315_plat_mem_setup();
-+
-+ /* Disable data watchpoints */
-+ write_c0_watchlo0(0);
-+}
-+
-+asmlinkage void plat_irq_dispatch(void)
-+{
-+ ath25_irq_dispatch();
-+}
-+
-+void __init plat_time_init(void)
-+{
-+ if (is_ar5312())
-+ ar5312_plat_time_init();
-+ else
-+ ar2315_plat_time_init();
-+}
-+
-+unsigned int __cpuinit get_c0_compare_int(void)
-+{
-+ return CP0_LEGACY_COMPARE_IRQ;
-+}
-+
-+void __init arch_init_irq(void)
-+{
-+ clear_c0_status(ST0_IM);
-+ mips_cpu_irq_init();
-+
-+ /* Initialize interrupt controllers */
-+ if (is_ar5312())
-+ ar5312_arch_init_irq();
-+ else
-+ ar2315_arch_init_irq();
-+}
---- /dev/null
-+++ b/arch/mips/ath25/prom.c
-@@ -0,0 +1,26 @@
-+/*
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file "COPYING" in the main directory of this archive
-+ * for more details.
-+ *
-+ * Copyright MontaVista Software Inc
-+ * Copyright (C) 2003 Atheros Communications, Inc., All Rights Reserved.
-+ * Copyright (C) 2006 FON Technology, SL.
-+ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
-+ * Copyright (C) 2006 Felix Fietkau <nbd@nbd.name>
-+ */
-+
-+/*
-+ * Prom setup file for AR5312/AR231x SoCs
-+ */
-+
-+#include <linux/init.h>
-+#include <asm/bootinfo.h>
-+
-+void __init prom_init(void)
-+{
-+}
-+
-+void __init prom_free_prom_memory(void)
-+{
-+}
---- /dev/null
-+++ b/arch/mips/include/asm/mach-ath25/ath25_platform.h
-@@ -0,0 +1,73 @@
-+#ifndef __ASM_MACH_ATH25_PLATFORM_H
-+#define __ASM_MACH_ATH25_PLATFORM_H
-+
-+#include <linux/etherdevice.h>
-+
-+/*
-+ * This is board-specific data that is stored in a "fixed" location in flash.
-+ * It is shared across operating systems, so it should not be changed lightly.
-+ * The main reason we need it is in order to extract the ethernet MAC
-+ * address(es).
-+ */
-+struct ath25_boarddata {
-+ u32 magic; /* board data is valid */
-+#define ATH25_BD_MAGIC 0x35333131 /* "5311", for all 531x/231x platforms */
-+ u16 cksum; /* checksum (starting with BD_REV 2) */
-+ u16 rev; /* revision of this struct */
-+#define BD_REV 4
-+ char board_name[64]; /* Name of board */
-+ u16 major; /* Board major number */
-+ u16 minor; /* Board minor number */
-+ u32 flags; /* Board configuration */
-+#define BD_ENET0 0x00000001 /* ENET0 is stuffed */
-+#define BD_ENET1 0x00000002 /* ENET1 is stuffed */
-+#define BD_UART1 0x00000004 /* UART1 is stuffed */
-+#define BD_UART0 0x00000008 /* UART0 is stuffed (dma) */
-+#define BD_RSTFACTORY 0x00000010 /* Reset factory defaults stuffed */
-+#define BD_SYSLED 0x00000020 /* System LED stuffed */
-+#define BD_EXTUARTCLK 0x00000040 /* External UART clock */
-+#define BD_CPUFREQ 0x00000080 /* cpu freq is valid in nvram */
-+#define BD_SYSFREQ 0x00000100 /* sys freq is set in nvram */
-+#define BD_WLAN0 0x00000200 /* Enable WLAN0 */
-+#define BD_MEMCAP 0x00000400 /* CAP SDRAM @ mem_cap for testing */
-+#define BD_DISWATCHDOG 0x00000800 /* disable system watchdog */
-+#define BD_WLAN1 0x00001000 /* Enable WLAN1 (ar5212) */
-+#define BD_ISCASPER 0x00002000 /* FLAG for AR2312 */
-+#define BD_WLAN0_2G_EN 0x00004000 /* FLAG for radio0_2G */
-+#define BD_WLAN0_5G_EN 0x00008000 /* FLAG for radio0_2G */
-+#define BD_WLAN1_2G_EN 0x00020000 /* FLAG for radio0_2G */
-+#define BD_WLAN1_5G_EN 0x00040000 /* FLAG for radio0_2G */
-+ u16 reset_config_gpio; /* Reset factory GPIO pin */
-+ u16 sys_led_gpio; /* System LED GPIO pin */
-+
-+ u32 cpu_freq; /* CPU core frequency in Hz */
-+ u32 sys_freq; /* System frequency in Hz */
-+ u32 cnt_freq; /* Calculated C0_COUNT frequency */
-+
-+ u8 wlan0_mac[ETH_ALEN];
-+ u8 enet0_mac[ETH_ALEN];
-+ u8 enet1_mac[ETH_ALEN];
-+
-+ u16 pci_id; /* Pseudo PCIID for common code */
-+ u16 mem_cap; /* cap bank1 in MB */
-+
-+ /* version 3 */
-+ u8 wlan1_mac[ETH_ALEN]; /* (ar5212) */
-+};
-+
-+#define BOARD_CONFIG_BUFSZ 0x1000
-+
-+/*
-+ * Platform device information for the Wireless MAC
-+ */
-+struct ar231x_board_config {
-+ u16 devid;
-+
-+ /* board config data */
-+ struct ath25_boarddata *config;
-+
-+ /* radio calibration data */
-+ const char *radio;
-+};
-+
-+#endif /* __ASM_MACH_ATH25_PLATFORM_H */
---- /dev/null
-+++ b/arch/mips/include/asm/mach-ath25/cpu-feature-overrides.h
-@@ -0,0 +1,64 @@
-+/*
-+ * Atheros AR231x/AR531x SoC specific CPU feature overrides
-+ *
-+ * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
-+ *
-+ * This file was derived from: include/asm-mips/cpu-features.h
-+ * Copyright (C) 2003, 2004 Ralf Baechle
-+ * Copyright (C) 2004 Maciej W. Rozycki
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License version 2 as published
-+ * by the Free Software Foundation.
-+ *
-+ */
-+#ifndef __ASM_MACH_ATH25_CPU_FEATURE_OVERRIDES_H
-+#define __ASM_MACH_ATH25_CPU_FEATURE_OVERRIDES_H
-+
-+/*
-+ * The Atheros AR531x/AR231x SoCs have MIPS 4Kc/4KEc core.
-+ */
-+#define cpu_has_tlb 1
-+#define cpu_has_4kex 1
-+#define cpu_has_3k_cache 0
-+#define cpu_has_4k_cache 1
-+#define cpu_has_tx39_cache 0
-+#define cpu_has_sb1_cache 0
-+#define cpu_has_fpu 0
-+#define cpu_has_32fpr 0
-+#define cpu_has_counter 1
-+#define cpu_has_ejtag 1
-+
-+#if !defined(CONFIG_SOC_AR5312)
-+# define cpu_has_llsc 1
-+#else
-+/*
-+ * The MIPS 4Kc V0.9 core in the AR5312/AR2312 have problems with the
-+ * ll/sc instructions.
-+ */
-+# define cpu_has_llsc 0
-+#endif
-+
-+#define cpu_has_mips16 0
-+#define cpu_has_mdmx 0
-+#define cpu_has_mips3d 0
-+#define cpu_has_smartmips 0
-+
-+#define cpu_has_mips32r1 1
-+
-+#if !defined(CONFIG_SOC_AR5312)
-+# define cpu_has_mips32r2 1
-+#endif
-+
-+#define cpu_has_mips64r1 0
-+#define cpu_has_mips64r2 0
-+
-+#define cpu_has_dsp 0
-+#define cpu_has_mipsmt 0
-+
-+#define cpu_has_64bits 0
-+#define cpu_has_64bit_zero_reg 0
-+#define cpu_has_64bit_gp_regs 0
-+#define cpu_has_64bit_addresses 0
-+
-+#endif /* __ASM_MACH_ATH25_CPU_FEATURE_OVERRIDES_H */
---- /dev/null
-+++ b/arch/mips/include/asm/mach-ath25/dma-coherence.h
-@@ -0,0 +1,82 @@
-+/*
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file "COPYING" in the main directory of this archive
-+ * for more details.
-+ *
-+ * Copyright (C) 2006 Ralf Baechle <ralf@linux-mips.org>
-+ * Copyright (C) 2007 Felix Fietkau <nbd@nbd.name>
-+ *
-+ */
-+#ifndef __ASM_MACH_ATH25_DMA_COHERENCE_H
-+#define __ASM_MACH_ATH25_DMA_COHERENCE_H
-+
-+#include <linux/device.h>
-+
-+/*
-+ * We need some arbitrary non-zero value to be programmed to the BAR1 register
-+ * of PCI host controller to enable DMA. The same value should be used as the
-+ * offset to calculate the physical address of DMA buffer for PCI devices.
-+ */
-+#define AR2315_PCI_HOST_SDRAM_BASEADDR 0x20000000
-+
-+static inline dma_addr_t ath25_dev_offset(struct device *dev)
-+{
-+#ifdef CONFIG_PCI
-+ extern struct bus_type pci_bus_type;
-+
-+ if (dev && dev->bus == &pci_bus_type)
-+ return AR2315_PCI_HOST_SDRAM_BASEADDR;
-+#endif
-+ return 0;
-+}
-+
-+static inline dma_addr_t
-+plat_map_dma_mem(struct device *dev, void *addr, size_t size)
-+{
-+ return virt_to_phys(addr) + ath25_dev_offset(dev);
-+}
-+
-+static inline dma_addr_t
-+plat_map_dma_mem_page(struct device *dev, struct page *page)
-+{
-+ return page_to_phys(page) + ath25_dev_offset(dev);
-+}
-+
-+static inline unsigned long
-+plat_dma_addr_to_phys(struct device *dev, dma_addr_t dma_addr)
-+{
-+ return dma_addr - ath25_dev_offset(dev);
-+}
-+
-+static inline void
-+plat_unmap_dma_mem(struct device *dev, dma_addr_t dma_addr, size_t size,
-+ enum dma_data_direction direction)
-+{
-+}
-+
-+static inline int plat_dma_supported(struct device *dev, u64 mask)
-+{
-+ return 1;
-+}
-+
-+static inline void plat_extra_sync_for_device(struct device *dev)
-+{
-+}
-+
-+static inline int plat_dma_mapping_error(struct device *dev,
-+ dma_addr_t dma_addr)
-+{
-+ return 0;
-+}
-+
-+static inline int plat_device_is_coherent(struct device *dev)
-+{
-+#ifdef CONFIG_DMA_COHERENT
-+ return 1;
-+#endif
-+#ifdef CONFIG_DMA_NONCOHERENT
-+ return 0;
-+#endif
-+}
-+
-+#endif /* __ASM_MACH_ATH25_DMA_COHERENCE_H */
---- /dev/null
-+++ b/arch/mips/include/asm/mach-ath25/gpio.h
-@@ -0,0 +1,16 @@
-+#ifndef __ASM_MACH_ATH25_GPIO_H
-+#define __ASM_MACH_ATH25_GPIO_H
-+
-+#include <asm-generic/gpio.h>
-+
-+#define gpio_get_value __gpio_get_value
-+#define gpio_set_value __gpio_set_value
-+#define gpio_cansleep __gpio_cansleep
-+#define gpio_to_irq __gpio_to_irq
-+
-+static inline int irq_to_gpio(unsigned irq)
-+{
-+ return -EINVAL;
-+}
-+
-+#endif /* __ASM_MACH_ATH25_GPIO_H */
---- /dev/null
-+++ b/arch/mips/include/asm/mach-ath25/war.h
-@@ -0,0 +1,25 @@
-+/*
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file "COPYING" in the main directory of this archive
-+ * for more details.
-+ *
-+ * Copyright (C) 2008 Felix Fietkau <nbd@nbd.name>
-+ */
-+#ifndef __ASM_MACH_ATH25_WAR_H
-+#define __ASM_MACH_ATH25_WAR_H
-+
-+#define R4600_V1_INDEX_ICACHEOP_WAR 0
-+#define R4600_V1_HIT_CACHEOP_WAR 0
-+#define R4600_V2_HIT_CACHEOP_WAR 0
-+#define R5432_CP0_INTERRUPT_WAR 0
-+#define BCM1250_M3_WAR 0
-+#define SIBYTE_1956_WAR 0
-+#define MIPS4K_ICACHE_REFILL_WAR 0
-+#define MIPS_CACHE_SYNC_WAR 0
-+#define TX49XX_ICACHE_INDEX_INV_WAR 0
-+#define RM9000_CDEX_SMP_WAR 0
-+#define ICACHE_REFILLS_WORKAROUND_WAR 0
-+#define R10000_LLSC_WAR 0
-+#define MIPS34K_MISSED_ITLB_WAR 0
-+
-+#endif /* __ASM_MACH_ATH25_WAR_H */
---- /dev/null
-+++ b/arch/mips/ath25/ar2315_regs.h
-@@ -0,0 +1,410 @@
-+/*
-+ * Register definitions for AR2315+
-+ *
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file "COPYING" in the main directory of this archive
-+ * for more details.
-+ *
-+ * Copyright (C) 2003 Atheros Communications, Inc., All Rights Reserved.
-+ * Copyright (C) 2006 FON Technology, SL.
-+ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
-+ * Copyright (C) 2006-2008 Felix Fietkau <nbd@nbd.name>
-+ */
-+
-+#ifndef __ASM_MACH_ATH25_AR2315_REGS_H
-+#define __ASM_MACH_ATH25_AR2315_REGS_H
-+
-+/*
-+ * IRQs
-+ */
-+#define AR2315_IRQ_MISC (MIPS_CPU_IRQ_BASE + 2) /* C0_CAUSE: 0x0400 */
-+#define AR2315_IRQ_WLAN0 (MIPS_CPU_IRQ_BASE + 3) /* C0_CAUSE: 0x0800 */
-+#define AR2315_IRQ_ENET0 (MIPS_CPU_IRQ_BASE + 4) /* C0_CAUSE: 0x1000 */
-+#define AR2315_IRQ_LCBUS_PCI (MIPS_CPU_IRQ_BASE + 5) /* C0_CAUSE: 0x2000 */
-+#define AR2315_IRQ_WLAN0_POLL (MIPS_CPU_IRQ_BASE + 6) /* C0_CAUSE: 0x4000 */
-+
-+/*
-+ * Miscellaneous interrupts, which share IP2.
-+ */
-+#define AR2315_MISC_IRQ_UART0 0
-+#define AR2315_MISC_IRQ_I2C_RSVD 1
-+#define AR2315_MISC_IRQ_SPI 2
-+#define AR2315_MISC_IRQ_AHB 3
-+#define AR2315_MISC_IRQ_APB 4
-+#define AR2315_MISC_IRQ_TIMER 5
-+#define AR2315_MISC_IRQ_GPIO 6
-+#define AR2315_MISC_IRQ_WATCHDOG 7
-+#define AR2315_MISC_IRQ_IR_RSVD 8
-+#define AR2315_MISC_IRQ_COUNT 9
-+
-+/*
-+ * Address map
-+ */
-+#define AR2315_SPI_READ_BASE 0x08000000 /* SPI flash */
-+#define AR2315_SPI_READ_SIZE 0x01000000
-+#define AR2315_WLAN0_BASE 0x10000000 /* Wireless MMR */
-+#define AR2315_PCI_BASE 0x10100000 /* PCI MMR */
-+#define AR2315_PCI_SIZE 0x00001000
-+#define AR2315_SDRAMCTL_BASE 0x10300000 /* SDRAM MMR */
-+#define AR2315_SDRAMCTL_SIZE 0x00000020
-+#define AR2315_LOCAL_BASE 0x10400000 /* Local bus MMR */
-+#define AR2315_ENET0_BASE 0x10500000 /* Ethernet MMR */
-+#define AR2315_RST_BASE 0x11000000 /* Reset control MMR */
-+#define AR2315_RST_SIZE 0x00000100
-+#define AR2315_UART0_BASE 0x11100000 /* UART MMR */
-+#define AR2315_SPI_MMR_BASE 0x11300000 /* SPI flash MMR */
-+#define AR2315_SPI_MMR_SIZE 0x00000010
-+#define AR2315_PCI_EXT_BASE 0x80000000 /* PCI external */
-+#define AR2315_PCI_EXT_SIZE 0x40000000
-+
-+/*
-+ * Configuration registers
-+ */
-+
-+/* Cold reset register */
-+#define AR2315_COLD_RESET 0x0000
-+
-+#define AR2315_RESET_COLD_AHB 0x00000001
-+#define AR2315_RESET_COLD_APB 0x00000002
-+#define AR2315_RESET_COLD_CPU 0x00000004
-+#define AR2315_RESET_COLD_CPUWARM 0x00000008
-+#define AR2315_RESET_SYSTEM (RESET_COLD_CPU |\
-+ RESET_COLD_APB |\
-+ RESET_COLD_AHB) /* full system */
-+#define AR2317_RESET_SYSTEM 0x00000010
-+
-+/* Reset register */
-+#define AR2315_RESET 0x0004
-+
-+#define AR2315_RESET_WARM_WLAN0_MAC 0x00000001 /* warm reset WLAN0 MAC */
-+#define AR2315_RESET_WARM_WLAN0_BB 0x00000002 /* warm reset WLAN0 BB */
-+#define AR2315_RESET_MPEGTS_RSVD 0x00000004 /* warm reset MPEG-TS */
-+#define AR2315_RESET_PCIDMA 0x00000008 /* warm reset PCI ahb/dma */
-+#define AR2315_RESET_MEMCTL 0x00000010 /* warm reset mem control */
-+#define AR2315_RESET_LOCAL 0x00000020 /* warm reset local bus */
-+#define AR2315_RESET_I2C_RSVD 0x00000040 /* warm reset I2C bus */
-+#define AR2315_RESET_SPI 0x00000080 /* warm reset SPI iface */
-+#define AR2315_RESET_UART0 0x00000100 /* warm reset UART0 */
-+#define AR2315_RESET_IR_RSVD 0x00000200 /* warm reset IR iface */
-+#define AR2315_RESET_EPHY0 0x00000400 /* cold reset ENET0 phy */
-+#define AR2315_RESET_ENET0 0x00000800 /* cold reset ENET0 MAC */
-+
-+/* AHB master arbitration control */
-+#define AR2315_AHB_ARB_CTL 0x0008
-+
-+#define AR2315_ARB_CPU 0x00000001 /* CPU, default */
-+#define AR2315_ARB_WLAN 0x00000002 /* WLAN */
-+#define AR2315_ARB_MPEGTS_RSVD 0x00000004 /* MPEG-TS */
-+#define AR2315_ARB_LOCAL 0x00000008 /* Local bus */
-+#define AR2315_ARB_PCI 0x00000010 /* PCI bus */
-+#define AR2315_ARB_ETHERNET 0x00000020 /* Ethernet */
-+#define AR2315_ARB_RETRY 0x00000100 /* Retry policy (debug) */
-+
-+/* Config Register */
-+#define AR2315_ENDIAN_CTL 0x000c
-+
-+#define AR2315_CONFIG_AHB 0x00000001 /* EC-AHB bridge endian */
-+#define AR2315_CONFIG_WLAN 0x00000002 /* WLAN byteswap */
-+#define AR2315_CONFIG_MPEGTS_RSVD 0x00000004 /* MPEG-TS byteswap */
-+#define AR2315_CONFIG_PCI 0x00000008 /* PCI byteswap */
-+#define AR2315_CONFIG_MEMCTL 0x00000010 /* Mem controller endian */
-+#define AR2315_CONFIG_LOCAL 0x00000020 /* Local bus byteswap */
-+#define AR2315_CONFIG_ETHERNET 0x00000040 /* Ethernet byteswap */
-+#define AR2315_CONFIG_MERGE 0x00000200 /* CPU write buffer merge */
-+#define AR2315_CONFIG_CPU 0x00000400 /* CPU big endian */
-+#define AR2315_CONFIG_BIG 0x00000400
-+#define AR2315_CONFIG_PCIAHB 0x00000800
-+#define AR2315_CONFIG_PCIAHB_BRIDGE 0x00001000
-+#define AR2315_CONFIG_SPI 0x00008000 /* SPI byteswap */
-+#define AR2315_CONFIG_CPU_DRAM 0x00010000
-+#define AR2315_CONFIG_CPU_PCI 0x00020000
-+#define AR2315_CONFIG_CPU_MMR 0x00040000
-+
-+/* NMI control */
-+#define AR2315_NMI_CTL 0x0010
-+
-+#define AR2315_NMI_EN 1
-+
-+/* Revision Register - Initial value is 0x3010 (WMAC 3.0, AR231X 1.0). */
-+#define AR2315_SREV 0x0014
-+
-+#define AR2315_REV_MAJ 0x000000f0
-+#define AR2315_REV_MAJ_S 4
-+#define AR2315_REV_MIN 0x0000000f
-+#define AR2315_REV_MIN_S 0
-+#define AR2315_REV_CHIP (AR2315_REV_MAJ | AR2315_REV_MIN)
-+
-+/* Interface Enable */
-+#define AR2315_IF_CTL 0x0018
-+
-+#define AR2315_IF_MASK 0x00000007
-+#define AR2315_IF_DISABLED 0 /* Disable all */
-+#define AR2315_IF_PCI 1 /* PCI */
-+#define AR2315_IF_TS_LOCAL 2 /* Local bus */
-+#define AR2315_IF_ALL 3 /* Emulation only */
-+#define AR2315_IF_LOCAL_HOST 0x00000008
-+#define AR2315_IF_PCI_HOST 0x00000010
-+#define AR2315_IF_PCI_INTR 0x00000020
-+#define AR2315_IF_PCI_CLK_MASK 0x00030000
-+#define AR2315_IF_PCI_CLK_INPUT 0
-+#define AR2315_IF_PCI_CLK_OUTPUT_LOW 1
-+#define AR2315_IF_PCI_CLK_OUTPUT_CLK 2
-+#define AR2315_IF_PCI_CLK_OUTPUT_HIGH 3
-+#define AR2315_IF_PCI_CLK_SHIFT 16
-+
-+/* APB Interrupt control */
-+#define AR2315_ISR 0x0020
-+#define AR2315_IMR 0x0024
-+#define AR2315_GISR 0x0028
-+
-+#define AR2315_ISR_UART0 0x00000001 /* high speed UART */
-+#define AR2315_ISR_I2C_RSVD 0x00000002 /* I2C bus */
-+#define AR2315_ISR_SPI 0x00000004 /* SPI bus */
-+#define AR2315_ISR_AHB 0x00000008 /* AHB error */
-+#define AR2315_ISR_APB 0x00000010 /* APB error */
-+#define AR2315_ISR_TIMER 0x00000020 /* Timer */
-+#define AR2315_ISR_GPIO 0x00000040 /* GPIO */
-+#define AR2315_ISR_WD 0x00000080 /* Watchdog */
-+#define AR2315_ISR_IR_RSVD 0x00000100 /* IR */
-+
-+#define AR2315_GISR_MISC 0x00000001 /* Misc */
-+#define AR2315_GISR_WLAN0 0x00000002 /* WLAN0 */
-+#define AR2315_GISR_MPEGTS_RSVD 0x00000004 /* MPEG-TS */
-+#define AR2315_GISR_LOCALPCI 0x00000008 /* Local/PCI bus */
-+#define AR2315_GISR_WMACPOLL 0x00000010
-+#define AR2315_GISR_TIMER 0x00000020
-+#define AR2315_GISR_ETHERNET 0x00000040 /* Ethernet */
-+
-+/* Generic timer */
-+#define AR2315_TIMER 0x0030
-+#define AR2315_RELOAD 0x0034
-+
-+/* Watchdog timer */
-+#define AR2315_WDT_TIMER 0x0038
-+#define AR2315_WDT_CTRL 0x003c
-+
-+#define AR2315_WDT_CTRL_IGNORE 0x00000000 /* ignore expiration */
-+#define AR2315_WDT_CTRL_NMI 0x00000001 /* NMI on watchdog */
-+#define AR2315_WDT_CTRL_RESET 0x00000002 /* reset on watchdog */
-+
-+/* CPU Performance Counters */
-+#define AR2315_PERFCNT0 0x0048
-+#define AR2315_PERFCNT1 0x004c
-+
-+#define AR2315_PERF0_DATAHIT 0x00000001 /* Count Data Cache Hits */
-+#define AR2315_PERF0_DATAMISS 0x00000002 /* Count Data Cache Misses */
-+#define AR2315_PERF0_INSTHIT 0x00000004 /* Count Instruction Cache Hits */
-+#define AR2315_PERF0_INSTMISS 0x00000008 /* Count Instruction Cache Misses */
-+#define AR2315_PERF0_ACTIVE 0x00000010 /* Count Active Processor Cycles */
-+#define AR2315_PERF0_WBHIT 0x00000020 /* Count CPU Write Buffer Hits */
-+#define AR2315_PERF0_WBMISS 0x00000040 /* Count CPU Write Buffer Misses */
-+
-+#define AR2315_PERF1_EB_ARDY 0x00000001 /* Count EB_ARdy signal */
-+#define AR2315_PERF1_EB_AVALID 0x00000002 /* Count EB_AValid signal */
-+#define AR2315_PERF1_EB_WDRDY 0x00000004 /* Count EB_WDRdy signal */
-+#define AR2315_PERF1_EB_RDVAL 0x00000008 /* Count EB_RdVal signal */
-+#define AR2315_PERF1_VRADDR 0x00000010 /* Count valid read address cycles*/
-+#define AR2315_PERF1_VWADDR 0x00000020 /* Count valid write address cycl.*/
-+#define AR2315_PERF1_VWDATA 0x00000040 /* Count valid write data cycles */
-+
-+/* AHB Error Reporting */
-+#define AR2315_AHB_ERR0 0x0050 /* error */
-+#define AR2315_AHB_ERR1 0x0054 /* haddr */
-+#define AR2315_AHB_ERR2 0x0058 /* hwdata */
-+#define AR2315_AHB_ERR3 0x005c /* hrdata */
-+#define AR2315_AHB_ERR4 0x0060 /* status */
-+
-+#define AR2315_AHB_ERROR_DET 1 /* AHB Error has been detected, */
-+ /* write 1 to clear all bits in ERR0 */
-+#define AR2315_AHB_ERROR_OVR 2 /* AHB Error overflow has been detected */
-+#define AR2315_AHB_ERROR_WDT 4 /* AHB Error due to wdt instead of hresp */
-+
-+#define AR2315_PROCERR_HMAST 0x0000000f
-+#define AR2315_PROCERR_HMAST_DFLT 0
-+#define AR2315_PROCERR_HMAST_WMAC 1
-+#define AR2315_PROCERR_HMAST_ENET 2
-+#define AR2315_PROCERR_HMAST_PCIENDPT 3
-+#define AR2315_PROCERR_HMAST_LOCAL 4
-+#define AR2315_PROCERR_HMAST_CPU 5
-+#define AR2315_PROCERR_HMAST_PCITGT 6
-+#define AR2315_PROCERR_HMAST_S 0
-+#define AR2315_PROCERR_HWRITE 0x00000010
-+#define AR2315_PROCERR_HSIZE 0x00000060
-+#define AR2315_PROCERR_HSIZE_S 5
-+#define AR2315_PROCERR_HTRANS 0x00000180
-+#define AR2315_PROCERR_HTRANS_S 7
-+#define AR2315_PROCERR_HBURST 0x00000e00
-+#define AR2315_PROCERR_HBURST_S 9
-+
-+/* Clock Control */
-+#define AR2315_PLLC_CTL 0x0064
-+#define AR2315_PLLV_CTL 0x0068
-+#define AR2315_CPUCLK 0x006c
-+#define AR2315_AMBACLK 0x0070
-+#define AR2315_SYNCCLK 0x0074
-+#define AR2315_DSL_SLEEP_CTL 0x0080
-+#define AR2315_DSL_SLEEP_DUR 0x0084
-+
-+/* PLLc Control fields */
-+#define AR2315_PLLC_REF_DIV_M 0x00000003
-+#define AR2315_PLLC_REF_DIV_S 0
-+#define AR2315_PLLC_FDBACK_DIV_M 0x0000007c
-+#define AR2315_PLLC_FDBACK_DIV_S 2
-+#define AR2315_PLLC_ADD_FDBACK_DIV_M 0x00000080
-+#define AR2315_PLLC_ADD_FDBACK_DIV_S 7
-+#define AR2315_PLLC_CLKC_DIV_M 0x0001c000
-+#define AR2315_PLLC_CLKC_DIV_S 14
-+#define AR2315_PLLC_CLKM_DIV_M 0x00700000
-+#define AR2315_PLLC_CLKM_DIV_S 20
-+
-+/* CPU CLK Control fields */
-+#define AR2315_CPUCLK_CLK_SEL_M 0x00000003
-+#define AR2315_CPUCLK_CLK_SEL_S 0
-+#define AR2315_CPUCLK_CLK_DIV_M 0x0000000c
-+#define AR2315_CPUCLK_CLK_DIV_S 2
-+
-+/* AMBA CLK Control fields */
-+#define AR2315_AMBACLK_CLK_SEL_M 0x00000003
-+#define AR2315_AMBACLK_CLK_SEL_S 0
-+#define AR2315_AMBACLK_CLK_DIV_M 0x0000000c
-+#define AR2315_AMBACLK_CLK_DIV_S 2
-+
-+/* PCI Clock Control */
-+#define AR2315_PCICLK 0x00a4
-+
-+#define AR2315_PCICLK_INPUT_M 0x00000003
-+#define AR2315_PCICLK_INPUT_S 0
-+#define AR2315_PCICLK_PLLC_CLKM 0
-+#define AR2315_PCICLK_PLLC_CLKM1 1
-+#define AR2315_PCICLK_PLLC_CLKC 2
-+#define AR2315_PCICLK_REF_CLK 3
-+#define AR2315_PCICLK_DIV_M 0x0000000c
-+#define AR2315_PCICLK_DIV_S 2
-+#define AR2315_PCICLK_IN_FREQ 0
-+#define AR2315_PCICLK_IN_FREQ_DIV_6 1
-+#define AR2315_PCICLK_IN_FREQ_DIV_8 2
-+#define AR2315_PCICLK_IN_FREQ_DIV_10 3
-+
-+/* Observation Control Register */
-+#define AR2315_OCR 0x00b0
-+
-+#define AR2315_OCR_GPIO0_IRIN 0x00000040
-+#define AR2315_OCR_GPIO1_IROUT 0x00000080
-+#define AR2315_OCR_GPIO3_RXCLR 0x00000200
-+
-+/* General Clock Control */
-+#define AR2315_MISCCLK 0x00b4
-+
-+#define AR2315_MISCCLK_PLLBYPASS_EN 0x00000001
-+#define AR2315_MISCCLK_PROCREFCLK 0x00000002
-+
-+/*
-+ * SDRAM Controller
-+ * - No read or write buffers are included.
-+ */
-+#define AR2315_MEM_CFG 0x0000
-+#define AR2315_MEM_CTRL 0x000c
-+#define AR2315_MEM_REF 0x0010
-+
-+#define AR2315_MEM_CFG_DATA_WIDTH_M 0x00006000
-+#define AR2315_MEM_CFG_DATA_WIDTH_S 13
-+#define AR2315_MEM_CFG_COL_WIDTH_M 0x00001e00
-+#define AR2315_MEM_CFG_COL_WIDTH_S 9
-+#define AR2315_MEM_CFG_ROW_WIDTH_M 0x000001e0
-+#define AR2315_MEM_CFG_ROW_WIDTH_S 5
-+#define AR2315_MEM_CFG_BANKADDR_BITS_M 0x00000018
-+#define AR2315_MEM_CFG_BANKADDR_BITS_S 3
-+
-+/*
-+ * Local Bus Interface Registers
-+ */
-+#define AR2315_LB_CONFIG 0x0000
-+
-+#define AR2315_LBCONF_OE 0x00000001 /* =1 OE is low-true */
-+#define AR2315_LBCONF_CS0 0x00000002 /* =1 first CS is low-true */
-+#define AR2315_LBCONF_CS1 0x00000004 /* =1 2nd CS is low-true */
-+#define AR2315_LBCONF_RDY 0x00000008 /* =1 RDY is low-true */
-+#define AR2315_LBCONF_WE 0x00000010 /* =1 Write En is low-true */
-+#define AR2315_LBCONF_WAIT 0x00000020 /* =1 WAIT is low-true */
-+#define AR2315_LBCONF_ADS 0x00000040 /* =1 Adr Strobe is low-true */
-+#define AR2315_LBCONF_MOT 0x00000080 /* =0 Intel, =1 Motorola */
-+#define AR2315_LBCONF_8CS 0x00000100 /* =1 8 bits CS, 0= 16bits */
-+#define AR2315_LBCONF_8DS 0x00000200 /* =1 8 bits Data S, 0=16bits */
-+#define AR2315_LBCONF_ADS_EN 0x00000400 /* =1 Enable ADS */
-+#define AR2315_LBCONF_ADR_OE 0x00000800 /* =1 Adr cap on OE, WE or DS */
-+#define AR2315_LBCONF_ADDT_MUX 0x00001000 /* =1 Adr and Data share bus */
-+#define AR2315_LBCONF_DATA_OE 0x00002000 /* =1 Data cap on OE, WE, DS */
-+#define AR2315_LBCONF_16DATA 0x00004000 /* =1 Data is 16 bits wide */
-+#define AR2315_LBCONF_SWAPDT 0x00008000 /* =1 Byte swap data */
-+#define AR2315_LBCONF_SYNC 0x00010000 /* =1 Bus synchronous to clk */
-+#define AR2315_LBCONF_INT 0x00020000 /* =1 Intr is low true */
-+#define AR2315_LBCONF_INT_CTR0 0x00000000 /* GND high-Z, Vdd is high-Z */
-+#define AR2315_LBCONF_INT_CTR1 0x00040000 /* GND drive, Vdd is high-Z */
-+#define AR2315_LBCONF_INT_CTR2 0x00080000 /* GND high-Z, Vdd drive */
-+#define AR2315_LBCONF_INT_CTR3 0x000c0000 /* GND drive, Vdd drive */
-+#define AR2315_LBCONF_RDY_WAIT 0x00100000 /* =1 RDY is negative of WAIT */
-+#define AR2315_LBCONF_INT_PULSE 0x00200000 /* =1 Interrupt is a pulse */
-+#define AR2315_LBCONF_ENABLE 0x00400000 /* =1 Falcon respond to LB */
-+
-+#define AR2315_LB_CLKSEL 0x0004
-+
-+#define AR2315_LBCLK_EXT 0x00000001 /* use external clk for lb */
-+
-+#define AR2315_LB_1MS 0x0008
-+
-+#define AR2315_LB1MS_MASK 0x0003ffff /* # of AHB clk cycles in 1ms */
-+
-+#define AR2315_LB_MISCCFG 0x000c
-+
-+#define AR2315_LBM_TXD_EN 0x00000001 /* Enable TXD for fragments */
-+#define AR2315_LBM_RX_INTEN 0x00000002 /* Enable LB ints on RX ready */
-+#define AR2315_LBM_MBOXWR_INTEN 0x00000004 /* Enable LB ints on mbox wr */
-+#define AR2315_LBM_MBOXRD_INTEN 0x00000008 /* Enable LB ints on mbox rd */
-+#define AR2315_LMB_DESCSWAP_EN 0x00000010 /* Byte swap desc enable */
-+#define AR2315_LBM_TIMEOUT_M 0x00ffff80
-+#define AR2315_LBM_TIMEOUT_S 7
-+#define AR2315_LBM_PORTMUX 0x07000000
-+
-+#define AR2315_LB_RXTSOFF 0x0010
-+
-+#define AR2315_LB_TX_CHAIN_EN 0x0100
-+
-+#define AR2315_LB_TXEN_0 0x00000001
-+#define AR2315_LB_TXEN_1 0x00000002
-+#define AR2315_LB_TXEN_2 0x00000004
-+#define AR2315_LB_TXEN_3 0x00000008
-+
-+#define AR2315_LB_TX_CHAIN_DIS 0x0104
-+#define AR2315_LB_TX_DESC_PTR 0x0200
-+
-+#define AR2315_LB_RX_CHAIN_EN 0x0400
-+
-+#define AR2315_LB_RXEN 0x00000001
-+
-+#define AR2315_LB_RX_CHAIN_DIS 0x0404
-+#define AR2315_LB_RX_DESC_PTR 0x0408
-+
-+#define AR2315_LB_INT_STATUS 0x0500
-+
-+#define AR2315_LB_INT_TX_DESC 0x00000001
-+#define AR2315_LB_INT_TX_OK 0x00000002
-+#define AR2315_LB_INT_TX_ERR 0x00000004
-+#define AR2315_LB_INT_TX_EOF 0x00000008
-+#define AR2315_LB_INT_RX_DESC 0x00000010
-+#define AR2315_LB_INT_RX_OK 0x00000020
-+#define AR2315_LB_INT_RX_ERR 0x00000040
-+#define AR2315_LB_INT_RX_EOF 0x00000080
-+#define AR2315_LB_INT_TX_TRUNC 0x00000100
-+#define AR2315_LB_INT_TX_STARVE 0x00000200
-+#define AR2315_LB_INT_LB_TIMEOUT 0x00000400
-+#define AR2315_LB_INT_LB_ERR 0x00000800
-+#define AR2315_LB_INT_MBOX_WR 0x00001000
-+#define AR2315_LB_INT_MBOX_RD 0x00002000
-+
-+/* Bit definitions for INT MASK are the same as INT_STATUS */
-+#define AR2315_LB_INT_MASK 0x0504
-+
-+#define AR2315_LB_INT_EN 0x0508
-+#define AR2315_LB_MBOX 0x0600
-+
-+#endif /* __ASM_MACH_ATH25_AR2315_REGS_H */
---- /dev/null
-+++ b/arch/mips/ath25/ar5312_regs.h
-@@ -0,0 +1,224 @@
-+/*
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file "COPYING" in the main directory of this archive
-+ * for more details.
-+ *
-+ * Copyright (C) 2003 Atheros Communications, Inc., All Rights Reserved.
-+ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
-+ * Copyright (C) 2006 Felix Fietkau <nbd@nbd.name>
-+ */
-+
-+#ifndef __ASM_MACH_ATH25_AR5312_REGS_H
-+#define __ASM_MACH_ATH25_AR5312_REGS_H
-+
-+/*
-+ * IRQs
-+ */
-+#define AR5312_IRQ_WLAN0 (MIPS_CPU_IRQ_BASE + 2) /* C0_CAUSE: 0x0400 */
-+#define AR5312_IRQ_ENET0 (MIPS_CPU_IRQ_BASE + 3) /* C0_CAUSE: 0x0800 */
-+#define AR5312_IRQ_ENET1 (MIPS_CPU_IRQ_BASE + 4) /* C0_CAUSE: 0x1000 */
-+#define AR5312_IRQ_WLAN1 (MIPS_CPU_IRQ_BASE + 5) /* C0_CAUSE: 0x2000 */
-+#define AR5312_IRQ_MISC (MIPS_CPU_IRQ_BASE + 6) /* C0_CAUSE: 0x4000 */
-+
-+/*
-+ * Miscellaneous interrupts, which share IP6.
-+ */
-+#define AR5312_MISC_IRQ_TIMER 0
-+#define AR5312_MISC_IRQ_AHB_PROC 1
-+#define AR5312_MISC_IRQ_AHB_DMA 2
-+#define AR5312_MISC_IRQ_GPIO 3
-+#define AR5312_MISC_IRQ_UART0 4
-+#define AR5312_MISC_IRQ_UART0_DMA 5
-+#define AR5312_MISC_IRQ_WATCHDOG 6
-+#define AR5312_MISC_IRQ_LOCAL 7
-+#define AR5312_MISC_IRQ_SPI 8
-+#define AR5312_MISC_IRQ_COUNT 9
-+
-+/*
-+ * Address Map
-+ *
-+ * The AR5312 supports 2 enet MACS, even though many reference boards only
-+ * actually use 1 of them (i.e. Only MAC 0 is actually connected to an enet
-+ * PHY or PHY switch. The AR2312 supports 1 enet MAC.
-+ */
-+#define AR5312_WLAN0_BASE 0x18000000
-+#define AR5312_ENET0_BASE 0x18100000
-+#define AR5312_ENET1_BASE 0x18200000
-+#define AR5312_SDRAMCTL_BASE 0x18300000
-+#define AR5312_SDRAMCTL_SIZE 0x00000010
-+#define AR5312_FLASHCTL_BASE 0x18400000
-+#define AR5312_FLASHCTL_SIZE 0x00000010
-+#define AR5312_WLAN1_BASE 0x18500000
-+#define AR5312_UART0_BASE 0x1c000000 /* UART MMR */
-+#define AR5312_GPIO_BASE 0x1c002000
-+#define AR5312_GPIO_SIZE 0x00000010
-+#define AR5312_RST_BASE 0x1c003000
-+#define AR5312_RST_SIZE 0x00000100
-+#define AR5312_FLASH_BASE 0x1e000000
-+#define AR5312_FLASH_SIZE 0x00800000
-+
-+/*
-+ * Need these defines to determine true number of ethernet MACs
-+ */
-+#define AR5312_AR5312_REV2 0x0052 /* AR5312 WMAC (AP31) */
-+#define AR5312_AR5312_REV7 0x0057 /* AR5312 WMAC (AP30-040) */
-+#define AR5312_AR2313_REV8 0x0058 /* AR2313 WMAC (AP43-030) */
-+
-+/* Reset/Timer Block Address Map */
-+#define AR5312_TIMER 0x0000 /* countdown timer */
-+#define AR5312_RELOAD 0x0004 /* timer reload value */
-+#define AR5312_WDT_CTRL 0x0008 /* watchdog cntrl */
-+#define AR5312_WDT_TIMER 0x000c /* watchdog timer */
-+#define AR5312_ISR 0x0010 /* Intr Status Reg */
-+#define AR5312_IMR 0x0014 /* Intr Mask Reg */
-+#define AR5312_RESET 0x0020
-+#define AR5312_CLOCKCTL1 0x0064
-+#define AR5312_SCRATCH 0x006c
-+#define AR5312_PROCADDR 0x0070
-+#define AR5312_PROC1 0x0074
-+#define AR5312_DMAADDR 0x0078
-+#define AR5312_DMA1 0x007c
-+#define AR5312_ENABLE 0x0080 /* interface enb */
-+#define AR5312_REV 0x0090 /* revision */
-+
-+/* AR5312_WDT_CTRL register bit field definitions */
-+#define AR5312_WDT_CTRL_IGNORE 0x00000000 /* ignore expiration */
-+#define AR5312_WDT_CTRL_NMI 0x00000001
-+#define AR5312_WDT_CTRL_RESET 0x00000002
-+
-+/* AR5312_ISR register bit field definitions */
-+#define AR5312_ISR_TIMER 0x00000001
-+#define AR5312_ISR_AHBPROC 0x00000002
-+#define AR5312_ISR_AHBDMA 0x00000004
-+#define AR5312_ISR_GPIO 0x00000008
-+#define AR5312_ISR_UART0 0x00000010
-+#define AR5312_ISR_UART0DMA 0x00000020
-+#define AR5312_ISR_WD 0x00000040
-+#define AR5312_ISR_LOCAL 0x00000080
-+
-+/* AR5312_RESET register bit field definitions */
-+#define AR5312_RESET_SYSTEM 0x00000001 /* cold reset full system */
-+#define AR5312_RESET_PROC 0x00000002 /* cold reset MIPS core */
-+#define AR5312_RESET_WLAN0 0x00000004 /* cold reset WLAN MAC/BB */
-+#define AR5312_RESET_EPHY0 0x00000008 /* cold reset ENET0 phy */
-+#define AR5312_RESET_EPHY1 0x00000010 /* cold reset ENET1 phy */
-+#define AR5312_RESET_ENET0 0x00000020 /* cold reset ENET0 MAC */
-+#define AR5312_RESET_ENET1 0x00000040 /* cold reset ENET1 MAC */
-+#define AR5312_RESET_UART0 0x00000100 /* cold reset UART0 */
-+#define AR5312_RESET_WLAN1 0x00000200 /* cold reset WLAN MAC/BB */
-+#define AR5312_RESET_APB 0x00000400 /* cold reset APB ar5312 */
-+#define AR5312_RESET_WARM_PROC 0x00001000 /* warm reset MIPS core */
-+#define AR5312_RESET_WARM_WLAN0_MAC 0x00002000 /* warm reset WLAN0 MAC */
-+#define AR5312_RESET_WARM_WLAN0_BB 0x00004000 /* warm reset WLAN0 BB */
-+#define AR5312_RESET_NMI 0x00010000 /* send an NMI to the CPU */
-+#define AR5312_RESET_WARM_WLAN1_MAC 0x00020000 /* warm reset WLAN1 MAC */
-+#define AR5312_RESET_WARM_WLAN1_BB 0x00040000 /* warm reset WLAN1 BB */
-+#define AR5312_RESET_LOCAL_BUS 0x00080000 /* reset local bus */
-+#define AR5312_RESET_WDOG 0x00100000 /* last reset was a wdt */
-+
-+#define AR5312_RESET_WMAC0_BITS (AR5312_RESET_WLAN0 |\
-+ AR5312_RESET_WARM_WLAN0_MAC |\
-+ AR5312_RESET_WARM_WLAN0_BB)
-+
-+#define AR5312_RESET_WMAC1_BITS (AR5312_RESET_WLAN1 |\
-+ AR5312_RESET_WARM_WLAN1_MAC |\
-+ AR5312_RESET_WARM_WLAN1_BB)
-+
-+/* AR5312_CLOCKCTL1 register bit field definitions */
-+#define AR5312_CLOCKCTL1_PREDIVIDE_MASK 0x00000030
-+#define AR5312_CLOCKCTL1_PREDIVIDE_SHIFT 4
-+#define AR5312_CLOCKCTL1_MULTIPLIER_MASK 0x00001f00
-+#define AR5312_CLOCKCTL1_MULTIPLIER_SHIFT 8
-+#define AR5312_CLOCKCTL1_DOUBLER_MASK 0x00010000
-+
-+/* Valid for AR5312 and AR2312 */
-+#define AR5312_CLOCKCTL1_PREDIVIDE_MASK 0x00000030
-+#define AR5312_CLOCKCTL1_PREDIVIDE_SHIFT 4
-+#define AR5312_CLOCKCTL1_MULTIPLIER_MASK 0x00001f00
-+#define AR5312_CLOCKCTL1_MULTIPLIER_SHIFT 8
-+#define AR5312_CLOCKCTL1_DOUBLER_MASK 0x00010000
-+
-+/* Valid for AR2313 */
-+#define AR2313_CLOCKCTL1_PREDIVIDE_MASK 0x00003000
-+#define AR2313_CLOCKCTL1_PREDIVIDE_SHIFT 12
-+#define AR2313_CLOCKCTL1_MULTIPLIER_MASK 0x001f0000
-+#define AR2313_CLOCKCTL1_MULTIPLIER_SHIFT 16
-+#define AR2313_CLOCKCTL1_DOUBLER_MASK 0x00000000
-+
-+/* AR5312_ENABLE register bit field definitions */
-+#define AR5312_ENABLE_WLAN0 0x00000001
-+#define AR5312_ENABLE_ENET0 0x00000002
-+#define AR5312_ENABLE_ENET1 0x00000004
-+#define AR5312_ENABLE_UART_AND_WLAN1_PIO 0x00000008/* UART & WLAN1 PIO */
-+#define AR5312_ENABLE_WLAN1_DMA 0x00000010/* WLAN1 DMAs */
-+#define AR5312_ENABLE_WLAN1 (AR5312_ENABLE_UART_AND_WLAN1_PIO |\
-+ AR5312_ENABLE_WLAN1_DMA)
-+
-+/* AR5312_REV register bit field definitions */
-+#define AR5312_REV_WMAC_MAJ 0x0000f000
-+#define AR5312_REV_WMAC_MAJ_S 12
-+#define AR5312_REV_WMAC_MIN 0x00000f00
-+#define AR5312_REV_WMAC_MIN_S 8
-+#define AR5312_REV_MAJ 0x000000f0
-+#define AR5312_REV_MAJ_S 4
-+#define AR5312_REV_MIN 0x0000000f
-+#define AR5312_REV_MIN_S 0
-+#define AR5312_REV_CHIP (AR5312_REV_MAJ|AR5312_REV_MIN)
-+
-+/* Major revision numbers, bits 7..4 of Revision ID register */
-+#define AR5312_REV_MAJ_AR5312 0x4
-+#define AR5312_REV_MAJ_AR2313 0x5
-+
-+/* Minor revision numbers, bits 3..0 of Revision ID register */
-+#define AR5312_REV_MIN_DUAL 0x0 /* Dual WLAN version */
-+#define AR5312_REV_MIN_SINGLE 0x1 /* Single WLAN version */
-+
-+/*
-+ * ARM Flash Controller -- 3 flash banks with either x8 or x16 devices
-+ */
-+#define AR5312_FLASHCTL0 0x0000
-+#define AR5312_FLASHCTL1 0x0004
-+#define AR5312_FLASHCTL2 0x0008
-+
-+/* AR5312_FLASHCTL register bit field definitions */
-+#define AR5312_FLASHCTL_IDCY 0x0000000f /* Idle cycle turnaround time */
-+#define AR5312_FLASHCTL_IDCY_S 0
-+#define AR5312_FLASHCTL_WST1 0x000003e0 /* Wait state 1 */
-+#define AR5312_FLASHCTL_WST1_S 5
-+#define AR5312_FLASHCTL_RBLE 0x00000400 /* Read byte lane enable */
-+#define AR5312_FLASHCTL_WST2 0x0000f800 /* Wait state 2 */
-+#define AR5312_FLASHCTL_WST2_S 11
-+#define AR5312_FLASHCTL_AC 0x00070000 /* Flash addr check (added) */
-+#define AR5312_FLASHCTL_AC_S 16
-+#define AR5312_FLASHCTL_AC_128K 0x00000000
-+#define AR5312_FLASHCTL_AC_256K 0x00010000
-+#define AR5312_FLASHCTL_AC_512K 0x00020000
-+#define AR5312_FLASHCTL_AC_1M 0x00030000
-+#define AR5312_FLASHCTL_AC_2M 0x00040000
-+#define AR5312_FLASHCTL_AC_4M 0x00050000
-+#define AR5312_FLASHCTL_AC_8M 0x00060000
-+#define AR5312_FLASHCTL_AC_RES 0x00070000 /* 16MB is not supported */
-+#define AR5312_FLASHCTL_E 0x00080000 /* Flash bank enable (added) */
-+#define AR5312_FLASHCTL_BUSERR 0x01000000 /* Bus transfer error flag */
-+#define AR5312_FLASHCTL_WPERR 0x02000000 /* Write protect error flag */
-+#define AR5312_FLASHCTL_WP 0x04000000 /* Write protect */
-+#define AR5312_FLASHCTL_BM 0x08000000 /* Burst mode */
-+#define AR5312_FLASHCTL_MW 0x30000000 /* Mem width */
-+#define AR5312_FLASHCTL_MW8 0x00000000 /* Mem width x8 */
-+#define AR5312_FLASHCTL_MW16 0x10000000 /* Mem width x16 */
-+#define AR5312_FLASHCTL_MW32 0x20000000 /* Mem width x32 (not supp) */
-+#define AR5312_FLASHCTL_ATNR 0x00000000 /* Access == no retry */
-+#define AR5312_FLASHCTL_ATR 0x80000000 /* Access == retry every */
-+#define AR5312_FLASHCTL_ATR4 0xc0000000 /* Access == retry every 4 */
-+
-+/*
-+ * ARM SDRAM Controller -- just enough to determine memory size
-+ */
-+#define AR5312_MEM_CFG1 0x0004
-+
-+#define AR5312_MEM_CFG1_AC0_M 0x00000700 /* bank 0: SDRAM addr check */
-+#define AR5312_MEM_CFG1_AC0_S 8
-+#define AR5312_MEM_CFG1_AC1_M 0x00007000 /* bank 1: SDRAM addr check */
-+#define AR5312_MEM_CFG1_AC1_S 12
-+
-+#endif /* __ASM_MACH_ATH25_AR5312_REGS_H */
---- /dev/null
-+++ b/arch/mips/ath25/ar5312.c
-@@ -0,0 +1,393 @@
-+/*
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file "COPYING" in the main directory of this archive
-+ * for more details.
-+ *
-+ * Copyright (C) 2003 Atheros Communications, Inc., All Rights Reserved.
-+ * Copyright (C) 2006 FON Technology, SL.
-+ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
-+ * Copyright (C) 2006-2009 Felix Fietkau <nbd@nbd.name>
-+ * Copyright (C) 2012 Alexandros C. Couloumbis <alex@ozo.com>
-+ */
-+
-+/*
-+ * Platform devices for Atheros AR5312 SoCs
-+ */
-+
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/bitops.h>
-+#include <linux/irqdomain.h>
-+#include <linux/interrupt.h>
-+#include <linux/platform_device.h>
-+#include <linux/mtd/physmap.h>
-+#include <linux/reboot.h>
-+#include <asm/bootinfo.h>
-+#include <asm/reboot.h>
-+#include <asm/time.h>
-+
-+#include <ath25_platform.h>
-+
-+#include "devices.h"
-+#include "ar5312.h"
-+#include "ar5312_regs.h"
-+
-+static void __iomem *ar5312_rst_base;
-+static struct irq_domain *ar5312_misc_irq_domain;
-+
-+static inline u32 ar5312_rst_reg_read(u32 reg)
-+{
-+ return __raw_readl(ar5312_rst_base + reg);
-+}
-+
-+static inline void ar5312_rst_reg_write(u32 reg, u32 val)
-+{
-+ __raw_writel(val, ar5312_rst_base + reg);
-+}
-+
-+static inline void ar5312_rst_reg_mask(u32 reg, u32 mask, u32 val)
-+{
-+ u32 ret = ar5312_rst_reg_read(reg);
-+
-+ ret &= ~mask;
-+ ret |= val;
-+ ar5312_rst_reg_write(reg, ret);
-+}
-+
-+static irqreturn_t ar5312_ahb_err_handler(int cpl, void *dev_id)
-+{
-+ u32 proc1 = ar5312_rst_reg_read(AR5312_PROC1);
-+ u32 proc_addr = ar5312_rst_reg_read(AR5312_PROCADDR); /* clears error */
-+ u32 dma1 = ar5312_rst_reg_read(AR5312_DMA1);
-+ u32 dma_addr = ar5312_rst_reg_read(AR5312_DMAADDR); /* clears error */
-+
-+ pr_emerg("AHB interrupt: PROCADDR=0x%8.8x PROC1=0x%8.8x DMAADDR=0x%8.8x DMA1=0x%8.8x\n",
-+ proc_addr, proc1, dma_addr, dma1);
-+
-+ machine_restart("AHB error"); /* Catastrophic failure */
-+ return IRQ_HANDLED;
-+}
-+
-+static struct irqaction ar5312_ahb_err_interrupt = {
-+ .handler = ar5312_ahb_err_handler,
-+ .name = "ar5312-ahb-error",
-+};
-+
-+static void ar5312_misc_irq_handler(unsigned irq, struct irq_desc *desc)
-+{
-+ u32 pending = ar5312_rst_reg_read(AR5312_ISR) &
-+ ar5312_rst_reg_read(AR5312_IMR);
-+ unsigned nr, misc_irq = 0;
-+
-+ if (pending) {
-+ struct irq_domain *domain = irq_get_handler_data(irq);
-+
-+ nr = __ffs(pending);
-+ misc_irq = irq_find_mapping(domain, nr);
-+ }
-+
-+ if (misc_irq) {
-+ generic_handle_irq(misc_irq);
-+ if (nr == AR5312_MISC_IRQ_TIMER)
-+ ar5312_rst_reg_read(AR5312_TIMER);
-+ } else {
-+ spurious_interrupt();
-+ }
-+}
-+
-+/* Enable the specified AR5312_MISC_IRQ interrupt */
-+static void ar5312_misc_irq_unmask(struct irq_data *d)
-+{
-+ ar5312_rst_reg_mask(AR5312_IMR, 0, BIT(d->hwirq));
-+}
-+
-+/* Disable the specified AR5312_MISC_IRQ interrupt */
-+static void ar5312_misc_irq_mask(struct irq_data *d)
-+{
-+ ar5312_rst_reg_mask(AR5312_IMR, BIT(d->hwirq), 0);
-+ ar5312_rst_reg_read(AR5312_IMR); /* flush write buffer */
-+}
-+
-+static struct irq_chip ar5312_misc_irq_chip = {
-+ .name = "ar5312-misc",
-+ .irq_unmask = ar5312_misc_irq_unmask,
-+ .irq_mask = ar5312_misc_irq_mask,
-+};
-+
-+static int ar5312_misc_irq_map(struct irq_domain *d, unsigned irq,
-+ irq_hw_number_t hw)
-+{
-+ irq_set_chip_and_handler(irq, &ar5312_misc_irq_chip, handle_level_irq);
-+ return 0;
-+}
-+
-+static struct irq_domain_ops ar5312_misc_irq_domain_ops = {
-+ .map = ar5312_misc_irq_map,
-+};
-+
-+static void ar5312_irq_dispatch(void)
-+{
-+ u32 pending = read_c0_status() & read_c0_cause();
-+
-+ if (pending & CAUSEF_IP2)
-+ do_IRQ(AR5312_IRQ_WLAN0);
-+ else if (pending & CAUSEF_IP5)
-+ do_IRQ(AR5312_IRQ_WLAN1);
-+ else if (pending & CAUSEF_IP6)
-+ do_IRQ(AR5312_IRQ_MISC);
-+ else if (pending & CAUSEF_IP7)
-+ do_IRQ(ATH25_IRQ_CPU_CLOCK);
-+ else
-+ spurious_interrupt();
-+}
-+
-+void __init ar5312_arch_init_irq(void)
-+{
-+ struct irq_domain *domain;
-+ unsigned irq;
-+
-+ ath25_irq_dispatch = ar5312_irq_dispatch;
-+
-+ domain = irq_domain_add_linear(NULL, AR5312_MISC_IRQ_COUNT,
-+ &ar5312_misc_irq_domain_ops, NULL);
-+ if (!domain)
-+ panic("Failed to add IRQ domain");
-+
-+ irq = irq_create_mapping(domain, AR5312_MISC_IRQ_AHB_PROC);
-+ setup_irq(irq, &ar5312_ahb_err_interrupt);
-+
-+ irq_set_chained_handler(AR5312_IRQ_MISC, ar5312_misc_irq_handler);
-+ irq_set_handler_data(AR5312_IRQ_MISC, domain);
-+
-+ ar5312_misc_irq_domain = domain;
-+}
-+
-+static struct physmap_flash_data ar5312_flash_data = {
-+ .width = 2,
-+};
-+
-+static struct resource ar5312_flash_resource = {
-+ .start = AR5312_FLASH_BASE,
-+ .end = AR5312_FLASH_BASE + AR5312_FLASH_SIZE - 1,
-+ .flags = IORESOURCE_MEM,
-+};
-+
-+static struct platform_device ar5312_physmap_flash = {
-+ .name = "physmap-flash",
-+ .id = 0,
-+ .dev.platform_data = &ar5312_flash_data,
-+ .resource = &ar5312_flash_resource,
-+ .num_resources = 1,
-+};
-+
-+static void __init ar5312_flash_init(void)
-+{
-+ void __iomem *flashctl_base;
-+ u32 ctl;
-+
-+ flashctl_base = ioremap_nocache(AR5312_FLASHCTL_BASE,
-+ AR5312_FLASHCTL_SIZE);
-+
-+ ctl = __raw_readl(flashctl_base + AR5312_FLASHCTL0);
-+ ctl &= AR5312_FLASHCTL_MW;
-+
-+ /* fixup flash width */
-+ switch (ctl) {
-+ case AR5312_FLASHCTL_MW16:
-+ ar5312_flash_data.width = 2;
-+ break;
-+ case AR5312_FLASHCTL_MW8:
-+ default:
-+ ar5312_flash_data.width = 1;
-+ break;
-+ }
-+
-+ /*
-+ * Configure flash bank 0.
-+ * Assume 8M window size. Flash will be aliased if it's smaller
-+ */
-+ ctl |= AR5312_FLASHCTL_E | AR5312_FLASHCTL_AC_8M | AR5312_FLASHCTL_RBLE;
-+ ctl |= 0x01 << AR5312_FLASHCTL_IDCY_S;
-+ ctl |= 0x07 << AR5312_FLASHCTL_WST1_S;
-+ ctl |= 0x07 << AR5312_FLASHCTL_WST2_S;
-+ __raw_writel(ctl, flashctl_base + AR5312_FLASHCTL0);
-+
-+ /* Disable other flash banks */
-+ ctl = __raw_readl(flashctl_base + AR5312_FLASHCTL1);
-+ ctl &= ~(AR5312_FLASHCTL_E | AR5312_FLASHCTL_AC);
-+ __raw_writel(ctl, flashctl_base + AR5312_FLASHCTL1);
-+ ctl = __raw_readl(flashctl_base + AR5312_FLASHCTL2);
-+ ctl &= ~(AR5312_FLASHCTL_E | AR5312_FLASHCTL_AC);
-+ __raw_writel(ctl, flashctl_base + AR5312_FLASHCTL2);
-+
-+ iounmap(flashctl_base);
-+}
-+
-+void __init ar5312_init_devices(void)
-+{
-+ struct ath25_boarddata *config;
-+
-+ ar5312_flash_init();
-+
-+ /* Locate board/radio config data */
-+ ath25_find_config(AR5312_FLASH_BASE, AR5312_FLASH_SIZE);
-+ config = ath25_board.config;
-+
-+ /* AR2313 has CPU minor rev. 10 */
-+ if ((current_cpu_data.processor_id & 0xff) == 0x0a)
-+ ath25_soc = ATH25_SOC_AR2313;
-+
-+ /* AR2312 shares the same Silicon ID as AR5312 */
-+ else if (config->flags & BD_ISCASPER)
-+ ath25_soc = ATH25_SOC_AR2312;
-+
-+ /* Everything else is probably AR5312 or compatible */
-+ else
-+ ath25_soc = ATH25_SOC_AR5312;
-+
-+ platform_device_register(&ar5312_physmap_flash);
-+
-+ switch (ath25_soc) {
-+ case ATH25_SOC_AR5312:
-+ if (!ath25_board.radio)
-+ return;
-+
-+ if (!(config->flags & BD_WLAN0))
-+ break;
-+
-+ ath25_add_wmac(0, AR5312_WLAN0_BASE, AR5312_IRQ_WLAN0);
-+ break;
-+ case ATH25_SOC_AR2312:
-+ case ATH25_SOC_AR2313:
-+ if (!ath25_board.radio)
-+ return;
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ if (config->flags & BD_WLAN1)
-+ ath25_add_wmac(1, AR5312_WLAN1_BASE, AR5312_IRQ_WLAN1);
-+}
-+
-+static void ar5312_restart(char *command)
-+{
-+ /* reset the system */
-+ local_irq_disable();
-+ while (1)
-+ ar5312_rst_reg_write(AR5312_RESET, AR5312_RESET_SYSTEM);
-+}
-+
-+/*
-+ * This table is indexed by bits 5..4 of the CLOCKCTL1 register
-+ * to determine the predevisor value.
-+ */
-+static unsigned clockctl1_predivide_table[4] __initdata = { 1, 2, 4, 5 };
-+
-+static unsigned __init ar5312_cpu_frequency(void)
-+{
-+ u32 scratch, devid, clock_ctl1;
-+ u32 predivide_mask, multiplier_mask, doubler_mask;
-+ unsigned predivide_shift, multiplier_shift;
-+ unsigned predivide_select, predivisor, multiplier;
-+
-+ /* Trust the bootrom's idea of cpu frequency. */
-+ scratch = ar5312_rst_reg_read(AR5312_SCRATCH);
-+ if (scratch)
-+ return scratch;
-+
-+ devid = ar5312_rst_reg_read(AR5312_REV);
-+ devid = (devid & AR5312_REV_MAJ) >> AR5312_REV_MAJ_S;
-+ if (devid == AR5312_REV_MAJ_AR2313) {
-+ predivide_mask = AR2313_CLOCKCTL1_PREDIVIDE_MASK;
-+ predivide_shift = AR2313_CLOCKCTL1_PREDIVIDE_SHIFT;
-+ multiplier_mask = AR2313_CLOCKCTL1_MULTIPLIER_MASK;
-+ multiplier_shift = AR2313_CLOCKCTL1_MULTIPLIER_SHIFT;
-+ doubler_mask = AR2313_CLOCKCTL1_DOUBLER_MASK;
-+ } else { /* AR5312 and AR2312 */
-+ predivide_mask = AR5312_CLOCKCTL1_PREDIVIDE_MASK;
-+ predivide_shift = AR5312_CLOCKCTL1_PREDIVIDE_SHIFT;
-+ multiplier_mask = AR5312_CLOCKCTL1_MULTIPLIER_MASK;
-+ multiplier_shift = AR5312_CLOCKCTL1_MULTIPLIER_SHIFT;
-+ doubler_mask = AR5312_CLOCKCTL1_DOUBLER_MASK;
-+ }
-+
-+ /*
-+ * Clocking is derived from a fixed 40MHz input clock.
-+ *
-+ * cpu_freq = input_clock * MULT (where MULT is PLL multiplier)
-+ * sys_freq = cpu_freq / 4 (used for APB clock, serial,
-+ * flash, Timer, Watchdog Timer)
-+ *
-+ * cnt_freq = cpu_freq / 2 (use for CPU count/compare)
-+ *
-+ * So, for example, with a PLL multiplier of 5, we have
-+ *
-+ * cpu_freq = 200MHz
-+ * sys_freq = 50MHz
-+ * cnt_freq = 100MHz
-+ *
-+ * We compute the CPU frequency, based on PLL settings.
-+ */
-+
-+ clock_ctl1 = ar5312_rst_reg_read(AR5312_CLOCKCTL1);
-+ predivide_select = (clock_ctl1 & predivide_mask) >> predivide_shift;
-+ predivisor = clockctl1_predivide_table[predivide_select];
-+ multiplier = (clock_ctl1 & multiplier_mask) >> multiplier_shift;
-+
-+ if (clock_ctl1 & doubler_mask)
-+ multiplier <<= 1;
-+
-+ return (40000000 / predivisor) * multiplier;
-+}
-+
-+static inline unsigned ar5312_sys_frequency(void)
-+{
-+ return ar5312_cpu_frequency() / 4;
-+}
-+
-+void __init ar5312_plat_time_init(void)
-+{
-+ mips_hpt_frequency = ar5312_cpu_frequency() / 2;
-+}
-+
-+void __init ar5312_plat_mem_setup(void)
-+{
-+ void __iomem *sdram_base;
-+ u32 memsize, memcfg, bank0_ac, bank1_ac;
-+ u32 devid;
-+
-+ /* Detect memory size */
-+ sdram_base = ioremap_nocache(AR5312_SDRAMCTL_BASE,
-+ AR5312_SDRAMCTL_SIZE);
-+ memcfg = __raw_readl(sdram_base + AR5312_MEM_CFG1);
-+ bank0_ac = ATH25_REG_MS(memcfg, AR5312_MEM_CFG1_AC0);
-+ bank1_ac = ATH25_REG_MS(memcfg, AR5312_MEM_CFG1_AC1);
-+ memsize = (bank0_ac ? (1 << (bank0_ac + 1)) : 0) +
-+ (bank1_ac ? (1 << (bank1_ac + 1)) : 0);
-+ memsize <<= 20;
-+ add_memory_region(0, memsize, BOOT_MEM_RAM);
-+ iounmap(sdram_base);
-+
-+ ar5312_rst_base = ioremap_nocache(AR5312_RST_BASE, AR5312_RST_SIZE);
-+
-+ devid = ar5312_rst_reg_read(AR5312_REV);
-+ devid >>= AR5312_REV_WMAC_MIN_S;
-+ devid &= AR5312_REV_CHIP;
-+ ath25_board.devid = (u16)devid;
-+
-+ /* Clear any lingering AHB errors */
-+ ar5312_rst_reg_read(AR5312_PROCADDR);
-+ ar5312_rst_reg_read(AR5312_DMAADDR);
-+ ar5312_rst_reg_write(AR5312_WDT_CTRL, AR5312_WDT_CTRL_IGNORE);
-+
-+ _machine_restart = ar5312_restart;
-+}
-+
-+void __init ar5312_arch_init(void)
-+{
-+ unsigned irq = irq_create_mapping(ar5312_misc_irq_domain,
-+ AR5312_MISC_IRQ_UART0);
-+
-+ ath25_serial_setup(AR5312_UART0_BASE, irq, ar5312_sys_frequency());
-+}
---- /dev/null
-+++ b/arch/mips/ath25/ar2315.c
-@@ -0,0 +1,308 @@
-+/*
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file "COPYING" in the main directory of this archive
-+ * for more details.
-+ *
-+ * Copyright (C) 2003 Atheros Communications, Inc., All Rights Reserved.
-+ * Copyright (C) 2006 FON Technology, SL.
-+ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
-+ * Copyright (C) 2006 Felix Fietkau <nbd@nbd.name>
-+ * Copyright (C) 2012 Alexandros C. Couloumbis <alex@ozo.com>
-+ */
-+
-+/*
-+ * Platform devices for Atheros AR2315 SoCs
-+ */
-+
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/bitops.h>
-+#include <linux/irqdomain.h>
-+#include <linux/interrupt.h>
-+#include <linux/platform_device.h>
-+#include <linux/reboot.h>
-+#include <asm/bootinfo.h>
-+#include <asm/reboot.h>
-+#include <asm/time.h>
-+
-+#include <ath25_platform.h>
-+
-+#include "devices.h"
-+#include "ar2315.h"
-+#include "ar2315_regs.h"
-+
-+static void __iomem *ar2315_rst_base;
-+static struct irq_domain *ar2315_misc_irq_domain;
-+
-+static inline u32 ar2315_rst_reg_read(u32 reg)
-+{
-+ return __raw_readl(ar2315_rst_base + reg);
-+}
-+
-+static inline void ar2315_rst_reg_write(u32 reg, u32 val)
-+{
-+ __raw_writel(val, ar2315_rst_base + reg);
-+}
-+
-+static inline void ar2315_rst_reg_mask(u32 reg, u32 mask, u32 val)
-+{
-+ u32 ret = ar2315_rst_reg_read(reg);
-+
-+ ret &= ~mask;
-+ ret |= val;
-+ ar2315_rst_reg_write(reg, ret);
-+}
-+
-+static irqreturn_t ar2315_ahb_err_handler(int cpl, void *dev_id)
-+{
-+ ar2315_rst_reg_write(AR2315_AHB_ERR0, AR2315_AHB_ERROR_DET);
-+ ar2315_rst_reg_read(AR2315_AHB_ERR1);
-+
-+ pr_emerg("AHB fatal error\n");
-+ machine_restart("AHB error"); /* Catastrophic failure */
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static struct irqaction ar2315_ahb_err_interrupt = {
-+ .handler = ar2315_ahb_err_handler,
-+ .name = "ar2315-ahb-error",
-+};
-+
-+static void ar2315_misc_irq_handler(unsigned irq, struct irq_desc *desc)
-+{
-+ u32 pending = ar2315_rst_reg_read(AR2315_ISR) &
-+ ar2315_rst_reg_read(AR2315_IMR);
-+ unsigned nr, misc_irq = 0;
-+
-+ if (pending) {
-+ struct irq_domain *domain = irq_get_handler_data(irq);
-+
-+ nr = __ffs(pending);
-+ misc_irq = irq_find_mapping(domain, nr);
-+ }
-+
-+ if (misc_irq) {
-+ if (nr == AR2315_MISC_IRQ_GPIO)
-+ ar2315_rst_reg_write(AR2315_ISR, AR2315_ISR_GPIO);
-+ else if (nr == AR2315_MISC_IRQ_WATCHDOG)
-+ ar2315_rst_reg_write(AR2315_ISR, AR2315_ISR_WD);
-+ generic_handle_irq(misc_irq);
-+ } else {
-+ spurious_interrupt();
-+ }
-+}
-+
-+static void ar2315_misc_irq_unmask(struct irq_data *d)
-+{
-+ ar2315_rst_reg_mask(AR2315_IMR, 0, BIT(d->hwirq));
-+}
-+
-+static void ar2315_misc_irq_mask(struct irq_data *d)
-+{
-+ ar2315_rst_reg_mask(AR2315_IMR, BIT(d->hwirq), 0);
-+}
-+
-+static struct irq_chip ar2315_misc_irq_chip = {
-+ .name = "ar2315-misc",
-+ .irq_unmask = ar2315_misc_irq_unmask,
-+ .irq_mask = ar2315_misc_irq_mask,
-+};
-+
-+static int ar2315_misc_irq_map(struct irq_domain *d, unsigned irq,
-+ irq_hw_number_t hw)
-+{
-+ irq_set_chip_and_handler(irq, &ar2315_misc_irq_chip, handle_level_irq);
-+ return 0;
-+}
-+
-+static struct irq_domain_ops ar2315_misc_irq_domain_ops = {
-+ .map = ar2315_misc_irq_map,
-+};
-+
-+/*
-+ * Called when an interrupt is received, this function
-+ * determines exactly which interrupt it was, and it
-+ * invokes the appropriate handler.
-+ *
-+ * Implicitly, we also define interrupt priority by
-+ * choosing which to dispatch first.
-+ */
-+static void ar2315_irq_dispatch(void)
-+{
-+ u32 pending = read_c0_status() & read_c0_cause();
-+
-+ if (pending & CAUSEF_IP3)
-+ do_IRQ(AR2315_IRQ_WLAN0);
-+ else if (pending & CAUSEF_IP2)
-+ do_IRQ(AR2315_IRQ_MISC);
-+ else if (pending & CAUSEF_IP7)
-+ do_IRQ(ATH25_IRQ_CPU_CLOCK);
-+ else
-+ spurious_interrupt();
-+}
-+
-+void __init ar2315_arch_init_irq(void)
-+{
-+ struct irq_domain *domain;
-+ unsigned irq;
-+
-+ ath25_irq_dispatch = ar2315_irq_dispatch;
-+
-+ domain = irq_domain_add_linear(NULL, AR2315_MISC_IRQ_COUNT,
-+ &ar2315_misc_irq_domain_ops, NULL);
-+ if (!domain)
-+ panic("Failed to add IRQ domain");
-+
-+ irq = irq_create_mapping(domain, AR2315_MISC_IRQ_AHB);
-+ setup_irq(irq, &ar2315_ahb_err_interrupt);
-+
-+ irq_set_chained_handler(AR2315_IRQ_MISC, ar2315_misc_irq_handler);
-+ irq_set_handler_data(AR2315_IRQ_MISC, domain);
-+
-+ ar2315_misc_irq_domain = domain;
-+}
-+
-+void __init ar2315_init_devices(void)
-+{
-+ /* Find board configuration */
-+ ath25_find_config(AR2315_SPI_READ_BASE, AR2315_SPI_READ_SIZE);
-+
-+ ath25_add_wmac(0, AR2315_WLAN0_BASE, AR2315_IRQ_WLAN0);
-+}
-+
-+static void ar2315_restart(char *command)
-+{
-+ void (*mips_reset_vec)(void) = (void *)0xbfc00000;
-+
-+ local_irq_disable();
-+
-+ /* try reset the system via reset control */
-+ ar2315_rst_reg_write(AR2315_COLD_RESET, AR2317_RESET_SYSTEM);
-+
-+ /* Cold reset does not work on the AR2315/6, use the GPIO reset bits
-+ * a workaround. Give it some time to attempt a gpio based hardware
-+ * reset (atheros reference design workaround) */
-+
-+ /* TODO: implement the GPIO reset workaround */
-+
-+ /* Some boards (e.g. Senao EOC-2610) don't implement the reset logic
-+ * workaround. Attempt to jump to the mips reset location -
-+ * the boot loader itself might be able to recover the system */
-+ mips_reset_vec();
-+}
-+
-+/*
-+ * This table is indexed by bits 5..4 of the CLOCKCTL1 register
-+ * to determine the predevisor value.
-+ */
-+static int clockctl1_predivide_table[4] __initdata = { 1, 2, 4, 5 };
-+static int pllc_divide_table[5] __initdata = { 2, 3, 4, 6, 3 };
-+
-+static unsigned __init ar2315_sys_clk(u32 clock_ctl)
-+{
-+ unsigned int pllc_ctrl, cpu_div;
-+ unsigned int pllc_out, refdiv, fdiv, divby2;
-+ unsigned int clk_div;
-+
-+ pllc_ctrl = ar2315_rst_reg_read(AR2315_PLLC_CTL);
-+ refdiv = ATH25_REG_MS(pllc_ctrl, AR2315_PLLC_REF_DIV);
-+ refdiv = clockctl1_predivide_table[refdiv];
-+ fdiv = ATH25_REG_MS(pllc_ctrl, AR2315_PLLC_FDBACK_DIV);
-+ divby2 = ATH25_REG_MS(pllc_ctrl, AR2315_PLLC_ADD_FDBACK_DIV) + 1;
-+ pllc_out = (40000000 / refdiv) * (2 * divby2) * fdiv;
-+
-+ /* clkm input selected */
-+ switch (clock_ctl & AR2315_CPUCLK_CLK_SEL_M) {
-+ case 0:
-+ case 1:
-+ clk_div = ATH25_REG_MS(pllc_ctrl, AR2315_PLLC_CLKM_DIV);
-+ clk_div = pllc_divide_table[clk_div];
-+ break;
-+ case 2:
-+ clk_div = ATH25_REG_MS(pllc_ctrl, AR2315_PLLC_CLKC_DIV);
-+ clk_div = pllc_divide_table[clk_div];
-+ break;
-+ default:
-+ pllc_out = 40000000;
-+ clk_div = 1;
-+ break;
-+ }
-+
-+ cpu_div = ATH25_REG_MS(clock_ctl, AR2315_CPUCLK_CLK_DIV);
-+ cpu_div = cpu_div * 2 ?: 1;
-+
-+ return pllc_out / (clk_div * cpu_div);
-+}
-+
-+static inline unsigned ar2315_cpu_frequency(void)
-+{
-+ return ar2315_sys_clk(ar2315_rst_reg_read(AR2315_CPUCLK));
-+}
-+
-+static inline unsigned ar2315_apb_frequency(void)
-+{
-+ return ar2315_sys_clk(ar2315_rst_reg_read(AR2315_AMBACLK));
-+}
-+
-+void __init ar2315_plat_time_init(void)
-+{
-+ mips_hpt_frequency = ar2315_cpu_frequency() / 2;
-+}
-+
-+void __init ar2315_plat_mem_setup(void)
-+{
-+ void __iomem *sdram_base;
-+ u32 memsize, memcfg;
-+ u32 devid;
-+ u32 config;
-+
-+ /* Detect memory size */
-+ sdram_base = ioremap_nocache(AR2315_SDRAMCTL_BASE,
-+ AR2315_SDRAMCTL_SIZE);
-+ memcfg = __raw_readl(sdram_base + AR2315_MEM_CFG);
-+ memsize = 1 + ATH25_REG_MS(memcfg, AR2315_MEM_CFG_DATA_WIDTH);
-+ memsize <<= 1 + ATH25_REG_MS(memcfg, AR2315_MEM_CFG_COL_WIDTH);
-+ memsize <<= 1 + ATH25_REG_MS(memcfg, AR2315_MEM_CFG_ROW_WIDTH);
-+ memsize <<= 3;
-+ add_memory_region(0, memsize, BOOT_MEM_RAM);
-+ iounmap(sdram_base);
-+
-+ ar2315_rst_base = ioremap_nocache(AR2315_RST_BASE, AR2315_RST_SIZE);
-+
-+ /* Detect the hardware based on the device ID */
-+ devid = ar2315_rst_reg_read(AR2315_SREV) & AR2315_REV_CHIP;
-+ switch (devid) {
-+ case 0x91: /* Need to check */
-+ ath25_soc = ATH25_SOC_AR2318;
-+ break;
-+ case 0x90:
-+ ath25_soc = ATH25_SOC_AR2317;
-+ break;
-+ case 0x87:
-+ ath25_soc = ATH25_SOC_AR2316;
-+ break;
-+ case 0x86:
-+ default:
-+ ath25_soc = ATH25_SOC_AR2315;
-+ break;
-+ }
-+ ath25_board.devid = devid;
-+
-+ /* Clear any lingering AHB errors */
-+ config = read_c0_config();
-+ write_c0_config(config & ~0x3);
-+ ar2315_rst_reg_write(AR2315_AHB_ERR0, AR2315_AHB_ERROR_DET);
-+ ar2315_rst_reg_read(AR2315_AHB_ERR1);
-+ ar2315_rst_reg_write(AR2315_WDT_CTRL, AR2315_WDT_CTRL_IGNORE);
-+
-+ _machine_restart = ar2315_restart;
-+}
-+
-+void __init ar2315_arch_init(void)
-+{
-+ unsigned irq = irq_create_mapping(ar2315_misc_irq_domain,
-+ AR2315_MISC_IRQ_UART0);
-+
-+ ath25_serial_setup(AR2315_UART0_BASE, irq, ar2315_apb_frequency());
-+}
---- /dev/null
-+++ b/arch/mips/ath25/ar2315.h
-@@ -0,0 +1,22 @@
-+#ifndef __AR2315_H
-+#define __AR2315_H
-+
-+#ifdef CONFIG_SOC_AR2315
-+
-+void ar2315_arch_init_irq(void);
-+void ar2315_init_devices(void);
-+void ar2315_plat_time_init(void);
-+void ar2315_plat_mem_setup(void);
-+void ar2315_arch_init(void);
-+
-+#else
-+
-+static inline void ar2315_arch_init_irq(void) {}
-+static inline void ar2315_init_devices(void) {}
-+static inline void ar2315_plat_time_init(void) {}
-+static inline void ar2315_plat_mem_setup(void) {}
-+static inline void ar2315_arch_init(void) {}
-+
-+#endif
-+
-+#endif /* __AR2315_H */
---- /dev/null
-+++ b/arch/mips/ath25/ar5312.h
-@@ -0,0 +1,22 @@
-+#ifndef __AR5312_H
-+#define __AR5312_H
-+
-+#ifdef CONFIG_SOC_AR5312
-+
-+void ar5312_arch_init_irq(void);
-+void ar5312_init_devices(void);
-+void ar5312_plat_time_init(void);
-+void ar5312_plat_mem_setup(void);
-+void ar5312_arch_init(void);
-+
-+#else
-+
-+static inline void ar5312_arch_init_irq(void) {}
-+static inline void ar5312_init_devices(void) {}
-+static inline void ar5312_plat_time_init(void) {}
-+static inline void ar5312_plat_mem_setup(void) {}
-+static inline void ar5312_arch_init(void) {}
-+
-+#endif
-+
-+#endif /* __AR5312_H */
---- /dev/null
-+++ b/arch/mips/ath25/devices.h
-@@ -0,0 +1,43 @@
-+#ifndef __ATH25_DEVICES_H
-+#define __ATH25_DEVICES_H
-+
-+#include <linux/cpu.h>
-+
-+#define ATH25_REG_MS(_val, _field) (((_val) & _field##_M) >> _field##_S)
-+
-+#define ATH25_IRQ_CPU_CLOCK (MIPS_CPU_IRQ_BASE + 7) /* C0_CAUSE: 0x8000 */
-+
-+enum ath25_soc_type {
-+ /* handled by ar5312.c */
-+ ATH25_SOC_AR2312,
-+ ATH25_SOC_AR2313,
-+ ATH25_SOC_AR5312,
-+
-+ /* handled by ar2315.c */
-+ ATH25_SOC_AR2315,
-+ ATH25_SOC_AR2316,
-+ ATH25_SOC_AR2317,
-+ ATH25_SOC_AR2318,
-+
-+ ATH25_SOC_UNKNOWN
-+};
-+
-+extern enum ath25_soc_type ath25_soc;
-+extern struct ar231x_board_config ath25_board;
-+extern void (*ath25_irq_dispatch)(void);
-+
-+int ath25_find_config(phys_addr_t offset, unsigned long size);
-+void ath25_serial_setup(u32 mapbase, int irq, unsigned int uartclk);
-+int ath25_add_wmac(int nr, u32 base, int irq);
-+
-+static inline bool is_ar2315(void)
-+{
-+ return (current_cpu_data.cputype == CPU_4KEC);
-+}
-+
-+static inline bool is_ar5312(void)
-+{
-+ return !is_ar2315();
-+}
-+
-+#endif
---- /dev/null
-+++ b/arch/mips/ath25/devices.c
-@@ -0,0 +1,125 @@
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/serial_8250.h>
-+#include <linux/platform_device.h>
-+#include <asm/bootinfo.h>
-+
-+#include <ath25_platform.h>
-+#include "devices.h"
-+#include "ar5312.h"
-+#include "ar2315.h"
-+
-+struct ar231x_board_config ath25_board;
-+enum ath25_soc_type ath25_soc = ATH25_SOC_UNKNOWN;
-+
-+static struct resource ath25_wmac0_res[] = {
-+ {
-+ .name = "wmac0_membase",
-+ .flags = IORESOURCE_MEM,
-+ },
-+ {
-+ .name = "wmac0_irq",
-+ .flags = IORESOURCE_IRQ,
-+ }
-+};
-+
-+static struct resource ath25_wmac1_res[] = {
-+ {
-+ .name = "wmac1_membase",
-+ .flags = IORESOURCE_MEM,
-+ },
-+ {
-+ .name = "wmac1_irq",
-+ .flags = IORESOURCE_IRQ,
-+ }
-+};
-+
-+static struct platform_device ath25_wmac[] = {
-+ {
-+ .id = 0,
-+ .name = "ar231x-wmac",
-+ .resource = ath25_wmac0_res,
-+ .num_resources = ARRAY_SIZE(ath25_wmac0_res),
-+ .dev.platform_data = &ath25_board,
-+ },
-+ {
-+ .id = 1,
-+ .name = "ar231x-wmac",
-+ .resource = ath25_wmac1_res,
-+ .num_resources = ARRAY_SIZE(ath25_wmac1_res),
-+ .dev.platform_data = &ath25_board,
-+ },
-+};
-+
-+static const char * const soc_type_strings[] = {
-+ [ATH25_SOC_AR5312] = "Atheros AR5312",
-+ [ATH25_SOC_AR2312] = "Atheros AR2312",
-+ [ATH25_SOC_AR2313] = "Atheros AR2313",
-+ [ATH25_SOC_AR2315] = "Atheros AR2315",
-+ [ATH25_SOC_AR2316] = "Atheros AR2316",
-+ [ATH25_SOC_AR2317] = "Atheros AR2317",
-+ [ATH25_SOC_AR2318] = "Atheros AR2318",
-+ [ATH25_SOC_UNKNOWN] = "Atheros (unknown)",
-+};
-+
-+const char *get_system_type(void)
-+{
-+ if ((ath25_soc >= ARRAY_SIZE(soc_type_strings)) ||
-+ !soc_type_strings[ath25_soc])
-+ return soc_type_strings[ATH25_SOC_UNKNOWN];
-+ return soc_type_strings[ath25_soc];
-+}
-+
-+void __init ath25_serial_setup(u32 mapbase, int irq, unsigned int uartclk)
-+{
-+ struct uart_port s;
-+
-+ memset(&s, 0, sizeof(s));
-+
-+ s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP;
-+ s.iotype = UPIO_MEM32;
-+ s.irq = irq;
-+ s.regshift = 2;
-+ s.mapbase = mapbase;
-+ s.uartclk = uartclk;
-+
-+ early_serial_setup(&s);
-+}
-+
-+int __init ath25_add_wmac(int nr, u32 base, int irq)
-+{
-+ struct resource *res;
-+
-+ ath25_wmac[nr].dev.platform_data = &ath25_board;
-+ res = &ath25_wmac[nr].resource[0];
-+ res->start = base;
-+ res->end = base + 0x10000 - 1;
-+ res++;
-+ res->start = irq;
-+ res->end = irq;
-+ return platform_device_register(&ath25_wmac[nr]);
-+}
-+
-+static int __init ath25_register_devices(void)
-+{
-+ if (is_ar5312())
-+ ar5312_init_devices();
-+ else
-+ ar2315_init_devices();
-+
-+ return 0;
-+}
-+
-+device_initcall(ath25_register_devices);
-+
-+static int __init ath25_arch_init(void)
-+{
-+ if (is_ar5312())
-+ ar5312_arch_init();
-+ else
-+ ar2315_arch_init();
-+
-+ return 0;
-+}
-+
-+arch_initcall(ath25_arch_init);
diff --git a/target/linux/ath25/patches-3.18/020-early-printk-support.patch b/target/linux/ath25/patches-3.18/020-early-printk-support.patch
deleted file mode 100644
index bd937d34a6..0000000000
--- a/target/linux/ath25/patches-3.18/020-early-printk-support.patch
+++ /dev/null
@@ -1,68 +0,0 @@
---- /dev/null
-+++ b/arch/mips/ath25/early_printk.c
-@@ -0,0 +1,44 @@
-+/*
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file "COPYING" in the main directory of this archive
-+ * for more details.
-+ *
-+ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
-+ */
-+
-+#include <linux/mm.h>
-+#include <linux/io.h>
-+#include <linux/serial_reg.h>
-+
-+#include "devices.h"
-+#include "ar2315_regs.h"
-+#include "ar5312_regs.h"
-+
-+static inline void prom_uart_wr(void __iomem *base, unsigned reg,
-+ unsigned char ch)
-+{
-+ __raw_writel(ch, base + 4 * reg);
-+}
-+
-+static inline unsigned char prom_uart_rr(void __iomem *base, unsigned reg)
-+{
-+ return __raw_readl(base + 4 * reg);
-+}
-+
-+void prom_putchar(unsigned char ch)
-+{
-+ static void __iomem *base;
-+
-+ if (unlikely(base == NULL)) {
-+ if (is_ar2315())
-+ base = (void __iomem *)(KSEG1ADDR(AR2315_UART0_BASE));
-+ else
-+ base = (void __iomem *)(KSEG1ADDR(AR5312_UART0_BASE));
-+ }
-+
-+ while ((prom_uart_rr(base, UART_LSR) & UART_LSR_THRE) == 0)
-+ ;
-+ prom_uart_wr(base, UART_TX, ch);
-+ while ((prom_uart_rr(base, UART_LSR) & UART_LSR_THRE) == 0)
-+ ;
-+}
---- a/arch/mips/ath25/Makefile
-+++ b/arch/mips/ath25/Makefile
-@@ -9,5 +9,8 @@
- #
-
- obj-y += board.o prom.o devices.o
-+
-+obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
-+
- obj-$(CONFIG_SOC_AR5312) += ar5312.o
- obj-$(CONFIG_SOC_AR2315) += ar2315.o
---- a/arch/mips/Kconfig
-+++ b/arch/mips/Kconfig
-@@ -106,6 +106,7 @@ config ATH25
- select SYS_HAS_CPU_MIPS32_R1
- select SYS_SUPPORTS_BIG_ENDIAN
- select SYS_SUPPORTS_32BIT_KERNEL
-+ select SYS_HAS_EARLY_PRINTK
- help
- Support for Atheros AR231x and Atheros AR531x based boards
-
diff --git a/target/linux/ath25/patches-3.18/030-ar2315_pci.patch b/target/linux/ath25/patches-3.18/030-ar2315_pci.patch
deleted file mode 100644
index 08b74636dd..0000000000
--- a/target/linux/ath25/patches-3.18/030-ar2315_pci.patch
+++ /dev/null
@@ -1,613 +0,0 @@
---- a/arch/mips/pci/Makefile
-+++ b/arch/mips/pci/Makefile
-@@ -19,6 +19,7 @@ obj-$(CONFIG_BCM47XX) += pci-bcm47xx.o
- obj-$(CONFIG_BCM63XX) += pci-bcm63xx.o fixup-bcm63xx.o \
- ops-bcm63xx.o
- obj-$(CONFIG_MIPS_ALCHEMY) += pci-alchemy.o
-+obj-$(CONFIG_PCI_AR2315) += pci-ar2315.o
- obj-$(CONFIG_SOC_AR71XX) += pci-ar71xx.o
- obj-$(CONFIG_PCI_AR724X) += pci-ar724x.o
- obj-$(CONFIG_MIPS_PCI_VIRTIO) += pci-virtio-guest.o
---- /dev/null
-+++ b/arch/mips/pci/pci-ar2315.c
-@@ -0,0 +1,511 @@
-+/*
-+ * 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, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+/**
-+ * Both AR2315 and AR2316 chips have PCI interface unit, which supports DMA
-+ * and interrupt. PCI interface supports MMIO access method, but does not
-+ * seem to support I/O ports.
-+ *
-+ * Read/write operation in the region 0x80000000-0xBFFFFFFF causes
-+ * a memory read/write command on the PCI bus. 30 LSBs of address on
-+ * the bus are taken from memory read/write request and 2 MSBs are
-+ * determined by PCI unit configuration.
-+ *
-+ * To work with the configuration space instead of memory is necessary set
-+ * the CFG_SEL bit in the PCI_MISC_CONFIG register.
-+ *
-+ * Devices on the bus can perform DMA requests via chip BAR1. PCI host
-+ * controller BARs are programmend as if an external device is programmed.
-+ * Which means that during configuration, IDSEL pin of the chip should be
-+ * asserted.
-+ *
-+ * We know (and support) only one board that uses the PCI interface -
-+ * Fonera 2.0g (FON2202). It has a USB EHCI controller connected to the
-+ * AR2315 PCI bus. IDSEL pin of USB controller is connected to AD[13] line
-+ * and IDSEL pin of AR2315 is connected to AD[16] line.
-+ */
-+
-+#include <linux/types.h>
-+#include <linux/pci.h>
-+#include <linux/platform_device.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/mm.h>
-+#include <linux/delay.h>
-+#include <linux/bitops.h>
-+#include <linux/irq.h>
-+#include <linux/irqdomain.h>
-+#include <linux/io.h>
-+#include <asm/paccess.h>
-+
-+/*
-+ * PCI Bus Interface Registers
-+ */
-+#define AR2315_PCI_1MS_REG 0x0008
-+
-+#define AR2315_PCI_1MS_MASK 0x3FFFF /* # of AHB clk cycles in 1ms */
-+
-+#define AR2315_PCI_MISC_CONFIG 0x000c
-+
-+#define AR2315_PCIMISC_TXD_EN 0x00000001 /* Enable TXD for fragments */
-+#define AR2315_PCIMISC_CFG_SEL 0x00000002 /* Mem or Config cycles */
-+#define AR2315_PCIMISC_GIG_MASK 0x0000000C /* bits 31-30 for pci req */
-+#define AR2315_PCIMISC_RST_MODE 0x00000030
-+#define AR2315_PCIRST_INPUT 0x00000000 /* 4:5=0 rst is input */
-+#define AR2315_PCIRST_LOW 0x00000010 /* 4:5=1 rst to GND */
-+#define AR2315_PCIRST_HIGH 0x00000020 /* 4:5=2 rst to VDD */
-+#define AR2315_PCIGRANT_EN 0x00000000 /* 6:7=0 early grant en */
-+#define AR2315_PCIGRANT_FRAME 0x00000040 /* 6:7=1 grant waits 4 frame */
-+#define AR2315_PCIGRANT_IDLE 0x00000080 /* 6:7=2 grant waits 4 idle */
-+#define AR2315_PCIGRANT_GAP 0x00000000 /* 6:7=2 grant waits 4 idle */
-+#define AR2315_PCICACHE_DIS 0x00001000 /* PCI external access cache
-+ * disable */
-+
-+#define AR2315_PCI_OUT_TSTAMP 0x0010
-+
-+#define AR2315_PCI_UNCACHE_CFG 0x0014
-+
-+#define AR2315_PCI_IN_EN 0x0100
-+
-+#define AR2315_PCI_IN_EN0 0x01 /* Enable chain 0 */
-+#define AR2315_PCI_IN_EN1 0x02 /* Enable chain 1 */
-+#define AR2315_PCI_IN_EN2 0x04 /* Enable chain 2 */
-+#define AR2315_PCI_IN_EN3 0x08 /* Enable chain 3 */
-+
-+#define AR2315_PCI_IN_DIS 0x0104
-+
-+#define AR2315_PCI_IN_DIS0 0x01 /* Disable chain 0 */
-+#define AR2315_PCI_IN_DIS1 0x02 /* Disable chain 1 */
-+#define AR2315_PCI_IN_DIS2 0x04 /* Disable chain 2 */
-+#define AR2315_PCI_IN_DIS3 0x08 /* Disable chain 3 */
-+
-+#define AR2315_PCI_IN_PTR 0x0200
-+
-+#define AR2315_PCI_OUT_EN 0x0400
-+
-+#define AR2315_PCI_OUT_EN0 0x01 /* Enable chain 0 */
-+
-+#define AR2315_PCI_OUT_DIS 0x0404
-+
-+#define AR2315_PCI_OUT_DIS0 0x01 /* Disable chain 0 */
-+
-+#define AR2315_PCI_OUT_PTR 0x0408
-+
-+/* PCI interrupt status (write one to clear) */
-+#define AR2315_PCI_ISR 0x0500
-+
-+#define AR2315_PCI_INT_TX 0x00000001 /* Desc In Completed */
-+#define AR2315_PCI_INT_TXOK 0x00000002 /* Desc In OK */
-+#define AR2315_PCI_INT_TXERR 0x00000004 /* Desc In ERR */
-+#define AR2315_PCI_INT_TXEOL 0x00000008 /* Desc In End-of-List */
-+#define AR2315_PCI_INT_RX 0x00000010 /* Desc Out Completed */
-+#define AR2315_PCI_INT_RXOK 0x00000020 /* Desc Out OK */
-+#define AR2315_PCI_INT_RXERR 0x00000040 /* Desc Out ERR */
-+#define AR2315_PCI_INT_RXEOL 0x00000080 /* Desc Out EOL */
-+#define AR2315_PCI_INT_TXOOD 0x00000200 /* Desc In Out-of-Desc */
-+#define AR2315_PCI_INT_DESCMASK 0x0000FFFF /* Desc Mask */
-+#define AR2315_PCI_INT_EXT 0x02000000 /* Extern PCI INTA */
-+#define AR2315_PCI_INT_ABORT 0x04000000 /* PCI bus abort event */
-+
-+/* PCI interrupt mask */
-+#define AR2315_PCI_IMR 0x0504
-+
-+/* Global PCI interrupt enable */
-+#define AR2315_PCI_IER 0x0508
-+
-+#define AR2315_PCI_IER_DISABLE 0x00 /* disable pci interrupts */
-+#define AR2315_PCI_IER_ENABLE 0x01 /* enable pci interrupts */
-+
-+#define AR2315_PCI_HOST_IN_EN 0x0800
-+#define AR2315_PCI_HOST_IN_DIS 0x0804
-+#define AR2315_PCI_HOST_IN_PTR 0x0810
-+#define AR2315_PCI_HOST_OUT_EN 0x0900
-+#define AR2315_PCI_HOST_OUT_DIS 0x0904
-+#define AR2315_PCI_HOST_OUT_PTR 0x0908
-+
-+/*
-+ * PCI interrupts, which share IP5
-+ * Keep ordered according to AR2315_PCI_INT_XXX bits
-+ */
-+#define AR2315_PCI_IRQ_EXT 25
-+#define AR2315_PCI_IRQ_ABORT 26
-+#define AR2315_PCI_IRQ_COUNT 27
-+
-+/* Arbitrary size of memory region to access the configuration space */
-+#define AR2315_PCI_CFG_SIZE 0x00100000
-+
-+#define AR2315_PCI_HOST_SLOT 3
-+#define AR2315_PCI_HOST_DEVID ((0xff18 << 16) | PCI_VENDOR_ID_ATHEROS)
-+
-+/* ??? access BAR */
-+#define AR2315_PCI_HOST_MBAR0 0x10000000
-+/* RAM access BAR */
-+#define AR2315_PCI_HOST_MBAR1 AR2315_PCI_HOST_SDRAM_BASEADDR
-+/* ??? access BAR */
-+#define AR2315_PCI_HOST_MBAR2 0x30000000
-+
-+struct ar2315_pci_ctrl {
-+ void __iomem *cfg_mem;
-+ void __iomem *mmr_mem;
-+ unsigned irq;
-+ unsigned irq_ext;
-+ struct irq_domain *domain;
-+ struct pci_controller pci_ctrl;
-+ struct resource mem_res;
-+ struct resource io_res;
-+};
-+
-+static inline struct ar2315_pci_ctrl *ar2315_pci_bus_to_apc(struct pci_bus *bus)
-+{
-+ struct pci_controller *hose = bus->sysdata;
-+
-+ return container_of(hose, struct ar2315_pci_ctrl, pci_ctrl);
-+}
-+
-+static inline u32 ar2315_pci_reg_read(struct ar2315_pci_ctrl *apc, u32 reg)
-+{
-+ return __raw_readl(apc->mmr_mem + reg);
-+}
-+
-+static inline void ar2315_pci_reg_write(struct ar2315_pci_ctrl *apc, u32 reg,
-+ u32 val)
-+{
-+ __raw_writel(val, apc->mmr_mem + reg);
-+}
-+
-+static inline void ar2315_pci_reg_mask(struct ar2315_pci_ctrl *apc, u32 reg,
-+ u32 mask, u32 val)
-+{
-+ u32 ret = ar2315_pci_reg_read(apc, reg);
-+
-+ ret &= ~mask;
-+ ret |= val;
-+ ar2315_pci_reg_write(apc, reg, ret);
-+}
-+
-+static int ar2315_pci_cfg_access(struct ar2315_pci_ctrl *apc, unsigned devfn,
-+ int where, int size, u32 *ptr, bool write)
-+{
-+ int func = PCI_FUNC(devfn);
-+ int dev = PCI_SLOT(devfn);
-+ u32 addr = (1 << (13 + dev)) | (func << 8) | (where & ~3);
-+ u32 mask = 0xffffffff >> 8 * (4 - size);
-+ u32 sh = (where & 3) * 8;
-+ u32 value, isr;
-+
-+ /* Prevent access past the remapped area */
-+ if (addr >= AR2315_PCI_CFG_SIZE || dev > 18)
-+ return PCIBIOS_DEVICE_NOT_FOUND;
-+
-+ /* Clear pending errors */
-+ ar2315_pci_reg_write(apc, AR2315_PCI_ISR, AR2315_PCI_INT_ABORT);
-+ /* Select Configuration access */
-+ ar2315_pci_reg_mask(apc, AR2315_PCI_MISC_CONFIG, 0,
-+ AR2315_PCIMISC_CFG_SEL);
-+
-+ mb(); /* PCI must see space change before we begin */
-+
-+ value = __raw_readl(apc->cfg_mem + addr);
-+
-+ isr = ar2315_pci_reg_read(apc, AR2315_PCI_ISR);
-+
-+ if (isr & AR2315_PCI_INT_ABORT)
-+ goto exit_err;
-+
-+ if (write) {
-+ value = (value & ~(mask << sh)) | *ptr << sh;
-+ __raw_writel(value, apc->cfg_mem + addr);
-+ isr = ar2315_pci_reg_read(apc, AR2315_PCI_ISR);
-+ if (isr & AR2315_PCI_INT_ABORT)
-+ goto exit_err;
-+ } else {
-+ *ptr = (value >> sh) & mask;
-+ }
-+
-+ goto exit;
-+
-+exit_err:
-+ ar2315_pci_reg_write(apc, AR2315_PCI_ISR, AR2315_PCI_INT_ABORT);
-+ if (!write)
-+ *ptr = 0xffffffff;
-+
-+exit:
-+ /* Select Memory access */
-+ ar2315_pci_reg_mask(apc, AR2315_PCI_MISC_CONFIG, AR2315_PCIMISC_CFG_SEL,
-+ 0);
-+
-+ return isr & AR2315_PCI_INT_ABORT ? PCIBIOS_DEVICE_NOT_FOUND :
-+ PCIBIOS_SUCCESSFUL;
-+}
-+
-+static inline int ar2315_pci_local_cfg_rd(struct ar2315_pci_ctrl *apc,
-+ unsigned devfn, int where, u32 *val)
-+{
-+ return ar2315_pci_cfg_access(apc, devfn, where, sizeof(u32), val,
-+ false);
-+}
-+
-+static inline int ar2315_pci_local_cfg_wr(struct ar2315_pci_ctrl *apc,
-+ unsigned devfn, int where, u32 val)
-+{
-+ return ar2315_pci_cfg_access(apc, devfn, where, sizeof(u32), &val,
-+ true);
-+}
-+
-+static int ar2315_pci_cfg_read(struct pci_bus *bus, unsigned devfn, int where,
-+ int size, u32 *value)
-+{
-+ struct ar2315_pci_ctrl *apc = ar2315_pci_bus_to_apc(bus);
-+
-+ if (PCI_SLOT(devfn) == AR2315_PCI_HOST_SLOT)
-+ return PCIBIOS_DEVICE_NOT_FOUND;
-+
-+ return ar2315_pci_cfg_access(apc, devfn, where, size, value, false);
-+}
-+
-+static int ar2315_pci_cfg_write(struct pci_bus *bus, unsigned devfn, int where,
-+ int size, u32 value)
-+{
-+ struct ar2315_pci_ctrl *apc = ar2315_pci_bus_to_apc(bus);
-+
-+ if (PCI_SLOT(devfn) == AR2315_PCI_HOST_SLOT)
-+ return PCIBIOS_DEVICE_NOT_FOUND;
-+
-+ return ar2315_pci_cfg_access(apc, devfn, where, size, &value, true);
-+}
-+
-+static struct pci_ops ar2315_pci_ops = {
-+ .read = ar2315_pci_cfg_read,
-+ .write = ar2315_pci_cfg_write,
-+};
-+
-+static int ar2315_pci_host_setup(struct ar2315_pci_ctrl *apc)
-+{
-+ unsigned devfn = PCI_DEVFN(AR2315_PCI_HOST_SLOT, 0);
-+ int res;
-+ u32 id;
-+
-+ res = ar2315_pci_local_cfg_rd(apc, devfn, PCI_VENDOR_ID, &id);
-+ if (res != PCIBIOS_SUCCESSFUL || id != AR2315_PCI_HOST_DEVID)
-+ return -ENODEV;
-+
-+ /* Program MBARs */
-+ ar2315_pci_local_cfg_wr(apc, devfn, PCI_BASE_ADDRESS_0,
-+ AR2315_PCI_HOST_MBAR0);
-+ ar2315_pci_local_cfg_wr(apc, devfn, PCI_BASE_ADDRESS_1,
-+ AR2315_PCI_HOST_MBAR1);
-+ ar2315_pci_local_cfg_wr(apc, devfn, PCI_BASE_ADDRESS_2,
-+ AR2315_PCI_HOST_MBAR2);
-+
-+ /* Run */
-+ ar2315_pci_local_cfg_wr(apc, devfn, PCI_COMMAND, PCI_COMMAND_MEMORY |
-+ PCI_COMMAND_MASTER | PCI_COMMAND_SPECIAL |
-+ PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY |
-+ PCI_COMMAND_SERR | PCI_COMMAND_FAST_BACK);
-+
-+ return 0;
-+}
-+
-+static void ar2315_pci_irq_handler(unsigned irq, struct irq_desc *desc)
-+{
-+ struct ar2315_pci_ctrl *apc = irq_get_handler_data(irq);
-+ u32 pending = ar2315_pci_reg_read(apc, AR2315_PCI_ISR) &
-+ ar2315_pci_reg_read(apc, AR2315_PCI_IMR);
-+ unsigned pci_irq = 0;
-+
-+ if (pending)
-+ pci_irq = irq_find_mapping(apc->domain, __ffs(pending));
-+
-+ if (pci_irq)
-+ generic_handle_irq(pci_irq);
-+ else
-+ spurious_interrupt();
-+}
-+
-+static void ar2315_pci_irq_mask(struct irq_data *d)
-+{
-+ struct ar2315_pci_ctrl *apc = irq_data_get_irq_chip_data(d);
-+
-+ ar2315_pci_reg_mask(apc, AR2315_PCI_IMR, BIT(d->hwirq), 0);
-+}
-+
-+static void ar2315_pci_irq_mask_ack(struct irq_data *d)
-+{
-+ struct ar2315_pci_ctrl *apc = irq_data_get_irq_chip_data(d);
-+ u32 m = BIT(d->hwirq);
-+
-+ ar2315_pci_reg_mask(apc, AR2315_PCI_IMR, m, 0);
-+ ar2315_pci_reg_write(apc, AR2315_PCI_ISR, m);
-+}
-+
-+static void ar2315_pci_irq_unmask(struct irq_data *d)
-+{
-+ struct ar2315_pci_ctrl *apc = irq_data_get_irq_chip_data(d);
-+
-+ ar2315_pci_reg_mask(apc, AR2315_PCI_IMR, 0, BIT(d->hwirq));
-+}
-+
-+static struct irq_chip ar2315_pci_irq_chip = {
-+ .name = "AR2315-PCI",
-+ .irq_mask = ar2315_pci_irq_mask,
-+ .irq_mask_ack = ar2315_pci_irq_mask_ack,
-+ .irq_unmask = ar2315_pci_irq_unmask,
-+};
-+
-+static int ar2315_pci_irq_map(struct irq_domain *d, unsigned irq,
-+ irq_hw_number_t hw)
-+{
-+ irq_set_chip_and_handler(irq, &ar2315_pci_irq_chip, handle_level_irq);
-+ irq_set_chip_data(irq, d->host_data);
-+ return 0;
-+}
-+
-+static struct irq_domain_ops ar2315_pci_irq_domain_ops = {
-+ .map = ar2315_pci_irq_map,
-+};
-+
-+static void ar2315_pci_irq_init(struct ar2315_pci_ctrl *apc)
-+{
-+ ar2315_pci_reg_mask(apc, AR2315_PCI_IER, AR2315_PCI_IER_ENABLE, 0);
-+ ar2315_pci_reg_mask(apc, AR2315_PCI_IMR, (AR2315_PCI_INT_ABORT |
-+ AR2315_PCI_INT_EXT), 0);
-+
-+ apc->irq_ext = irq_create_mapping(apc->domain, AR2315_PCI_IRQ_EXT);
-+
-+ irq_set_chained_handler(apc->irq, ar2315_pci_irq_handler);
-+ irq_set_handler_data(apc->irq, apc);
-+
-+ /* Clear any pending Abort or external Interrupts
-+ * and enable interrupt processing */
-+ ar2315_pci_reg_write(apc, AR2315_PCI_ISR, AR2315_PCI_INT_ABORT |
-+ AR2315_PCI_INT_EXT);
-+ ar2315_pci_reg_mask(apc, AR2315_PCI_IER, 0, AR2315_PCI_IER_ENABLE);
-+}
-+
-+static int ar2315_pci_probe(struct platform_device *pdev)
-+{
-+ struct ar2315_pci_ctrl *apc;
-+ struct device *dev = &pdev->dev;
-+ struct resource *res;
-+ int irq, err;
-+
-+ apc = devm_kzalloc(dev, sizeof(*apc), GFP_KERNEL);
-+ if (!apc)
-+ return -ENOMEM;
-+
-+ irq = platform_get_irq(pdev, 0);
-+ if (irq < 0)
-+ return -EINVAL;
-+ apc->irq = irq;
-+
-+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-+ "ar2315-pci-ctrl");
-+ apc->mmr_mem = devm_ioremap_resource(dev, res);
-+ if (IS_ERR(apc->mmr_mem))
-+ return PTR_ERR(apc->mmr_mem);
-+
-+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-+ "ar2315-pci-ext");
-+ if (!res)
-+ return -EINVAL;
-+
-+ apc->mem_res.name = "AR2315 PCI mem space";
-+ apc->mem_res.parent = res;
-+ apc->mem_res.start = res->start;
-+ apc->mem_res.end = res->end;
-+ apc->mem_res.flags = IORESOURCE_MEM;
-+
-+ /* Remap PCI config space */
-+ apc->cfg_mem = devm_ioremap_nocache(dev, res->start,
-+ AR2315_PCI_CFG_SIZE);
-+ if (!apc->cfg_mem) {
-+ dev_err(dev, "failed to remap PCI config space\n");
-+ return -ENOMEM;
-+ }
-+
-+ /* Reset the PCI bus by setting bits 5-4 in PCI_MCFG */
-+ ar2315_pci_reg_mask(apc, AR2315_PCI_MISC_CONFIG,
-+ AR2315_PCIMISC_RST_MODE,
-+ AR2315_PCIRST_LOW);
-+ msleep(100);
-+
-+ /* Bring the PCI out of reset */
-+ ar2315_pci_reg_mask(apc, AR2315_PCI_MISC_CONFIG,
-+ AR2315_PCIMISC_RST_MODE,
-+ AR2315_PCIRST_HIGH | AR2315_PCICACHE_DIS | 0x8);
-+
-+ ar2315_pci_reg_write(apc, AR2315_PCI_UNCACHE_CFG,
-+ 0x1E | /* 1GB uncached */
-+ (1 << 5) | /* Enable uncached */
-+ (0x2 << 30) /* Base: 0x80000000 */);
-+ ar2315_pci_reg_read(apc, AR2315_PCI_UNCACHE_CFG);
-+
-+ msleep(500);
-+
-+ err = ar2315_pci_host_setup(apc);
-+ if (err)
-+ return err;
-+
-+ apc->domain = irq_domain_add_linear(NULL, AR2315_PCI_IRQ_COUNT,
-+ &ar2315_pci_irq_domain_ops, apc);
-+ if (!apc->domain) {
-+ dev_err(dev, "failed to add IRQ domain\n");
-+ return -ENOMEM;
-+ }
-+
-+ ar2315_pci_irq_init(apc);
-+
-+ /* PCI controller does not support I/O ports */
-+ apc->io_res.name = "AR2315 IO space";
-+ apc->io_res.start = 0;
-+ apc->io_res.end = 0;
-+ apc->io_res.flags = IORESOURCE_IO,
-+
-+ apc->pci_ctrl.pci_ops = &ar2315_pci_ops;
-+ apc->pci_ctrl.mem_resource = &apc->mem_res,
-+ apc->pci_ctrl.io_resource = &apc->io_res,
-+
-+ register_pci_controller(&apc->pci_ctrl);
-+
-+ dev_info(dev, "register PCI controller\n");
-+
-+ return 0;
-+}
-+
-+static struct platform_driver ar2315_pci_driver = {
-+ .probe = ar2315_pci_probe,
-+ .driver = {
-+ .name = "ar2315-pci",
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+static int __init ar2315_pci_init(void)
-+{
-+ return platform_driver_register(&ar2315_pci_driver);
-+}
-+arch_initcall(ar2315_pci_init);
-+
-+int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
-+{
-+ struct ar2315_pci_ctrl *apc = ar2315_pci_bus_to_apc(dev->bus);
-+
-+ return slot ? 0 : apc->irq_ext;
-+}
-+
-+int pcibios_plat_dev_init(struct pci_dev *dev)
-+{
-+ return 0;
-+}
---- a/arch/mips/ath25/Kconfig
-+++ b/arch/mips/ath25/Kconfig
-@@ -7,3 +7,10 @@ config SOC_AR2315
- bool "Atheros AR2315+ SoC support"
- depends on ATH25
- default y
-+
-+config PCI_AR2315
-+ bool "Atheros AR2315 PCI controller support"
-+ depends on SOC_AR2315
-+ select HW_HAS_PCI
-+ select PCI
-+ default y
---- a/arch/mips/ath25/ar2315.c
-+++ b/arch/mips/ath25/ar2315.c
-@@ -134,6 +134,10 @@ static void ar2315_irq_dispatch(void)
-
- if (pending & CAUSEF_IP3)
- do_IRQ(AR2315_IRQ_WLAN0);
-+#ifdef CONFIG_PCI_AR2315
-+ else if (pending & CAUSEF_IP5)
-+ do_IRQ(AR2315_IRQ_LCBUS_PCI);
-+#endif
- else if (pending & CAUSEF_IP2)
- do_IRQ(AR2315_IRQ_MISC);
- else if (pending & CAUSEF_IP7)
-@@ -299,10 +303,62 @@ void __init ar2315_plat_mem_setup(void)
- _machine_restart = ar2315_restart;
- }
-
-+#ifdef CONFIG_PCI_AR2315
-+static struct resource ar2315_pci_res[] = {
-+ {
-+ .name = "ar2315-pci-ctrl",
-+ .flags = IORESOURCE_MEM,
-+ .start = AR2315_PCI_BASE,
-+ .end = AR2315_PCI_BASE + AR2315_PCI_SIZE - 1,
-+ },
-+ {
-+ .name = "ar2315-pci-ext",
-+ .flags = IORESOURCE_MEM,
-+ .start = AR2315_PCI_EXT_BASE,
-+ .end = AR2315_PCI_EXT_BASE + AR2315_PCI_EXT_SIZE - 1,
-+ },
-+ {
-+ .name = "ar2315-pci",
-+ .flags = IORESOURCE_IRQ,
-+ .start = AR2315_IRQ_LCBUS_PCI,
-+ .end = AR2315_IRQ_LCBUS_PCI,
-+ },
-+};
-+#endif
-+
- void __init ar2315_arch_init(void)
- {
- unsigned irq = irq_create_mapping(ar2315_misc_irq_domain,
- AR2315_MISC_IRQ_UART0);
-
- ath25_serial_setup(AR2315_UART0_BASE, irq, ar2315_apb_frequency());
-+
-+#ifdef CONFIG_PCI_AR2315
-+ if (ath25_soc == ATH25_SOC_AR2315) {
-+ /* Reset PCI DMA logic */
-+ ar2315_rst_reg_mask(AR2315_RESET, 0, AR2315_RESET_PCIDMA);
-+ msleep(20);
-+ ar2315_rst_reg_mask(AR2315_RESET, AR2315_RESET_PCIDMA, 0);
-+ msleep(20);
-+
-+ /* Configure endians */
-+ ar2315_rst_reg_mask(AR2315_ENDIAN_CTL, 0, AR2315_CONFIG_PCIAHB |
-+ AR2315_CONFIG_PCIAHB_BRIDGE);
-+
-+ /* Configure as PCI host with DMA */
-+ ar2315_rst_reg_write(AR2315_PCICLK, AR2315_PCICLK_PLLC_CLKM |
-+ (AR2315_PCICLK_IN_FREQ_DIV_6 <<
-+ AR2315_PCICLK_DIV_S));
-+ ar2315_rst_reg_mask(AR2315_AHB_ARB_CTL, 0, AR2315_ARB_PCI);
-+ ar2315_rst_reg_mask(AR2315_IF_CTL, AR2315_IF_PCI_CLK_MASK |
-+ AR2315_IF_MASK, AR2315_IF_PCI |
-+ AR2315_IF_PCI_HOST | AR2315_IF_PCI_INTR |
-+ (AR2315_IF_PCI_CLK_OUTPUT_CLK <<
-+ AR2315_IF_PCI_CLK_SHIFT));
-+
-+ platform_device_register_simple("ar2315-pci", -1,
-+ ar2315_pci_res,
-+ ARRAY_SIZE(ar2315_pci_res));
-+ }
-+#endif
- }
diff --git a/target/linux/ath25/patches-3.18/107-ar5312_gpio.patch b/target/linux/ath25/patches-3.18/107-ar5312_gpio.patch
deleted file mode 100644
index bb0bead513..0000000000
--- a/target/linux/ath25/patches-3.18/107-ar5312_gpio.patch
+++ /dev/null
@@ -1,212 +0,0 @@
---- a/arch/mips/ath25/Kconfig
-+++ b/arch/mips/ath25/Kconfig
-@@ -1,6 +1,7 @@
- config SOC_AR5312
- bool "Atheros AR5312/AR2312+ SoC support"
- depends on ATH25
-+ select GPIO_AR5312
- default y
-
- config SOC_AR2315
---- a/arch/mips/ath25/ar5312.c
-+++ b/arch/mips/ath25/ar5312.c
-@@ -22,6 +22,7 @@
- #include <linux/platform_device.h>
- #include <linux/mtd/physmap.h>
- #include <linux/reboot.h>
-+#include <linux/gpio.h>
- #include <asm/bootinfo.h>
- #include <asm/reboot.h>
- #include <asm/time.h>
-@@ -180,6 +181,22 @@ static struct platform_device ar5312_phy
- .num_resources = 1,
- };
-
-+static struct resource ar5312_gpio_res[] = {
-+ {
-+ .name = "ar5312-gpio",
-+ .flags = IORESOURCE_MEM,
-+ .start = AR5312_GPIO_BASE,
-+ .end = AR5312_GPIO_BASE + AR5312_GPIO_SIZE - 1,
-+ },
-+};
-+
-+static struct platform_device ar5312_gpio = {
-+ .name = "ar5312-gpio",
-+ .id = -1,
-+ .resource = ar5312_gpio_res,
-+ .num_resources = ARRAY_SIZE(ar5312_gpio_res),
-+};
-+
- static void __init ar5312_flash_init(void)
- {
- void __iomem *flashctl_base;
-@@ -247,6 +264,8 @@ void __init ar5312_init_devices(void)
-
- platform_device_register(&ar5312_physmap_flash);
-
-+ platform_device_register(&ar5312_gpio);
-+
- switch (ath25_soc) {
- case ATH25_SOC_AR5312:
- if (!ath25_board.radio)
---- a/drivers/gpio/Kconfig
-+++ b/drivers/gpio/Kconfig
-@@ -112,6 +112,13 @@ config GPIO_MAX730X
-
- comment "Memory mapped GPIO drivers:"
-
-+config GPIO_AR5312
-+ bool "AR5312 SoC GPIO support"
-+ default y if SOC_AR5312
-+ depends on SOC_AR5312
-+ help
-+ Say yes here to enable GPIO support for Atheros AR5312/AR2312+ SoCs.
-+
- config GPIO_CLPS711X
- tristate "CLPS711X GPIO support"
- depends on ARCH_CLPS711X || COMPILE_TEST
---- a/drivers/gpio/Makefile
-+++ b/drivers/gpio/Makefile
-@@ -17,6 +17,7 @@ obj-$(CONFIG_GPIO_ADNP) += gpio-adnp.o
- obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o
- obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o
- obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o
-+obj-$(CONFIG_GPIO_AR5312) += gpio-ar5312.o
- obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
- obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
- obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
---- /dev/null
-+++ b/drivers/gpio/gpio-ar5312.c
-@@ -0,0 +1,121 @@
-+/*
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file "COPYING" in the main directory of this archive
-+ * for more details.
-+ *
-+ * Copyright (C) 2003 Atheros Communications, Inc., All Rights Reserved.
-+ * Copyright (C) 2006 FON Technology, SL.
-+ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
-+ * Copyright (C) 2006-2009 Felix Fietkau <nbd@nbd.name>
-+ * Copyright (C) 2012 Alexandros C. Couloumbis <alex@ozo.com>
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/platform_device.h>
-+#include <linux/gpio.h>
-+
-+#define DRIVER_NAME "ar5312-gpio"
-+
-+#define AR5312_GPIO_DO 0x00 /* output register */
-+#define AR5312_GPIO_DI 0x04 /* intput register */
-+#define AR5312_GPIO_CR 0x08 /* control register */
-+
-+#define AR5312_GPIO_CR_M(x) (1 << (x)) /* mask for i/o */
-+#define AR5312_GPIO_CR_O(x) (0 << (x)) /* mask for output */
-+#define AR5312_GPIO_CR_I(x) (1 << (x)) /* mask for input */
-+#define AR5312_GPIO_CR_INT(x) (1 << ((x)+8)) /* mask for interrupt */
-+#define AR5312_GPIO_CR_UART(x) (1 << ((x)+16)) /* uart multiplex */
-+
-+#define AR5312_GPIO_NUM 8
-+
-+static void __iomem *ar5312_mem;
-+
-+static inline u32 ar5312_gpio_reg_read(unsigned reg)
-+{
-+ return __raw_readl(ar5312_mem + reg);
-+}
-+
-+static inline void ar5312_gpio_reg_write(unsigned reg, u32 val)
-+{
-+ __raw_writel(val, ar5312_mem + reg);
-+}
-+
-+static inline void ar5312_gpio_reg_mask(unsigned reg, u32 mask, u32 val)
-+{
-+ ar5312_gpio_reg_write(reg, (ar5312_gpio_reg_read(reg) & ~mask) | val);
-+}
-+
-+static int ar5312_gpio_get_val(struct gpio_chip *chip, unsigned gpio)
-+{
-+ return (ar5312_gpio_reg_read(AR5312_GPIO_DI) >> gpio) & 1;
-+}
-+
-+static void ar5312_gpio_set_val(struct gpio_chip *chip, unsigned gpio, int val)
-+{
-+ u32 reg = ar5312_gpio_reg_read(AR5312_GPIO_DO);
-+
-+ reg = val ? reg | (1 << gpio) : reg & ~(1 << gpio);
-+ ar5312_gpio_reg_write(AR5312_GPIO_DO, reg);
-+}
-+
-+static int ar5312_gpio_dir_in(struct gpio_chip *chip, unsigned gpio)
-+{
-+ ar5312_gpio_reg_mask(AR5312_GPIO_CR, 0, 1 << gpio);
-+ return 0;
-+}
-+
-+static int ar5312_gpio_dir_out(struct gpio_chip *chip, unsigned gpio, int val)
-+{
-+ ar5312_gpio_reg_mask(AR5312_GPIO_CR, 1 << gpio, 0);
-+ ar5312_gpio_set_val(chip, gpio, val);
-+ return 0;
-+}
-+
-+static struct gpio_chip ar5312_gpio_chip = {
-+ .label = DRIVER_NAME,
-+ .direction_input = ar5312_gpio_dir_in,
-+ .direction_output = ar5312_gpio_dir_out,
-+ .set = ar5312_gpio_set_val,
-+ .get = ar5312_gpio_get_val,
-+ .base = 0,
-+ .ngpio = AR5312_GPIO_NUM,
-+};
-+
-+static int ar5312_gpio_probe(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ struct resource *res;
-+ int ret;
-+
-+ if (ar5312_mem)
-+ return -EBUSY;
-+
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ ar5312_mem = devm_ioremap_resource(dev, res);
-+ if (IS_ERR(ar5312_mem))
-+ return PTR_ERR(ar5312_mem);
-+
-+ ar5312_gpio_chip.dev = dev;
-+ ret = gpiochip_add(&ar5312_gpio_chip);
-+ if (ret) {
-+ dev_err(dev, "failed to add gpiochip\n");
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static struct platform_driver ar5312_gpio_driver = {
-+ .probe = ar5312_gpio_probe,
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ }
-+};
-+
-+static int __init ar5312_gpio_init(void)
-+{
-+ return platform_driver_register(&ar5312_gpio_driver);
-+}
-+subsys_initcall(ar5312_gpio_init);
---- a/arch/mips/Kconfig
-+++ b/arch/mips/Kconfig
-@@ -107,6 +107,7 @@ config ATH25
- select SYS_SUPPORTS_BIG_ENDIAN
- select SYS_SUPPORTS_32BIT_KERNEL
- select SYS_HAS_EARLY_PRINTK
-+ select ARCH_REQUIRE_GPIOLIB
- help
- Support for Atheros AR231x and Atheros AR531x based boards
-
diff --git a/target/linux/ath25/patches-3.18/108-ar2315_gpio.patch b/target/linux/ath25/patches-3.18/108-ar2315_gpio.patch
deleted file mode 100644
index cc08f1711f..0000000000
--- a/target/linux/ath25/patches-3.18/108-ar2315_gpio.patch
+++ /dev/null
@@ -1,363 +0,0 @@
---- a/arch/mips/ath25/Kconfig
-+++ b/arch/mips/ath25/Kconfig
-@@ -7,6 +7,7 @@ config SOC_AR5312
- config SOC_AR2315
- bool "Atheros AR2315+ SoC support"
- depends on ATH25
-+ select GPIO_AR2315
- default y
-
- config PCI_AR2315
---- a/arch/mips/ath25/ar2315.c
-+++ b/arch/mips/ath25/ar2315.c
-@@ -21,6 +21,8 @@
- #include <linux/interrupt.h>
- #include <linux/platform_device.h>
- #include <linux/reboot.h>
-+#include <linux/delay.h>
-+#include <linux/gpio.h>
- #include <asm/bootinfo.h>
- #include <asm/reboot.h>
- #include <asm/time.h>
-@@ -167,11 +169,42 @@ void __init ar2315_arch_init_irq(void)
- ar2315_misc_irq_domain = domain;
- }
-
-+static struct resource ar2315_gpio_res[] = {
-+ {
-+ .name = "ar2315-gpio",
-+ .flags = IORESOURCE_MEM,
-+ .start = AR2315_RST_BASE + AR2315_GPIO,
-+ .end = AR2315_RST_BASE + AR2315_GPIO + 0x10 - 1,
-+ },
-+ {
-+ .name = "ar2315-gpio",
-+ .flags = IORESOURCE_IRQ,
-+ },
-+ {
-+ .name = "ar2315-gpio-irq-base",
-+ .flags = IORESOURCE_IRQ,
-+ .start = AR231X_GPIO_IRQ_BASE,
-+ .end = AR231X_GPIO_IRQ_BASE,
-+ }
-+};
-+
-+static struct platform_device ar2315_gpio = {
-+ .id = -1,
-+ .name = "ar2315-gpio",
-+ .resource = ar2315_gpio_res,
-+ .num_resources = ARRAY_SIZE(ar2315_gpio_res)
-+};
-+
- void __init ar2315_init_devices(void)
- {
- /* Find board configuration */
- ath25_find_config(AR2315_SPI_READ_BASE, AR2315_SPI_READ_SIZE);
-
-+ ar2315_gpio_res[1].start = irq_create_mapping(ar2315_misc_irq_domain,
-+ AR2315_MISC_IRQ_GPIO);
-+ ar2315_gpio_res[1].end = ar2315_gpio_res[1].start;
-+ platform_device_register(&ar2315_gpio);
-+
- ath25_add_wmac(0, AR2315_WLAN0_BASE, AR2315_IRQ_WLAN0);
- }
-
-@@ -187,8 +220,8 @@ static void ar2315_restart(char *command
- /* Cold reset does not work on the AR2315/6, use the GPIO reset bits
- * a workaround. Give it some time to attempt a gpio based hardware
- * reset (atheros reference design workaround) */
--
-- /* TODO: implement the GPIO reset workaround */
-+ gpio_request_one(AR2315_RESET_GPIO, GPIOF_OUT_INIT_LOW, "Reset");
-+ mdelay(100);
-
- /* Some boards (e.g. Senao EOC-2610) don't implement the reset logic
- * workaround. Attempt to jump to the mips reset location -
---- a/drivers/gpio/Kconfig
-+++ b/drivers/gpio/Kconfig
-@@ -112,6 +112,13 @@ config GPIO_MAX730X
-
- comment "Memory mapped GPIO drivers:"
-
-+config GPIO_AR2315
-+ bool "AR2315 SoC GPIO support"
-+ default y if SOC_AR2315
-+ depends on SOC_AR2315
-+ help
-+ Say yes here to enable GPIO support for Atheros AR2315+ SoCs.
-+
- config GPIO_AR5312
- bool "AR5312 SoC GPIO support"
- default y if SOC_AR5312
---- a/drivers/gpio/Makefile
-+++ b/drivers/gpio/Makefile
-@@ -17,6 +17,7 @@ obj-$(CONFIG_GPIO_ADNP) += gpio-adnp.o
- obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o
- obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o
- obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o
-+obj-$(CONFIG_GPIO_AR2315) += gpio-ar2315.o
- obj-$(CONFIG_GPIO_AR5312) += gpio-ar5312.o
- obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
- obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
---- /dev/null
-+++ b/drivers/gpio/gpio-ar2315.c
-@@ -0,0 +1,233 @@
-+/*
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file "COPYING" in the main directory of this archive
-+ * for more details.
-+ *
-+ * Copyright (C) 2003 Atheros Communications, Inc., All Rights Reserved.
-+ * Copyright (C) 2006 FON Technology, SL.
-+ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
-+ * Copyright (C) 2006 Felix Fietkau <nbd@nbd.name>
-+ * Copyright (C) 2012 Alexandros C. Couloumbis <alex@ozo.com>
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/platform_device.h>
-+#include <linux/gpio.h>
-+#include <linux/irq.h>
-+
-+#define DRIVER_NAME "ar2315-gpio"
-+
-+#define AR2315_GPIO_DI 0x0000
-+#define AR2315_GPIO_DO 0x0008
-+#define AR2315_GPIO_DIR 0x0010
-+#define AR2315_GPIO_INT 0x0018
-+
-+#define AR2315_GPIO_DIR_M(x) (1 << (x)) /* mask for i/o */
-+#define AR2315_GPIO_DIR_O(x) (1 << (x)) /* output */
-+#define AR2315_GPIO_DIR_I(x) (0) /* input */
-+
-+#define AR2315_GPIO_INT_NUM_M 0x3F /* mask for GPIO num */
-+#define AR2315_GPIO_INT_TRIG(x) ((x) << 6) /* interrupt trigger */
-+#define AR2315_GPIO_INT_TRIG_M (0x3 << 6) /* mask for int trig */
-+
-+#define AR2315_GPIO_INT_TRIG_OFF 0 /* Triggerring off */
-+#define AR2315_GPIO_INT_TRIG_LOW 1 /* Low Level Triggered */
-+#define AR2315_GPIO_INT_TRIG_HIGH 2 /* High Level Triggered */
-+#define AR2315_GPIO_INT_TRIG_EDGE 3 /* Edge Triggered */
-+
-+#define AR2315_GPIO_NUM 22
-+
-+static u32 ar2315_gpio_intmask;
-+static u32 ar2315_gpio_intval;
-+static unsigned ar2315_gpio_irq_base;
-+static void __iomem *ar2315_mem;
-+
-+static inline u32 ar2315_gpio_reg_read(unsigned reg)
-+{
-+ return __raw_readl(ar2315_mem + reg);
-+}
-+
-+static inline void ar2315_gpio_reg_write(unsigned reg, u32 val)
-+{
-+ __raw_writel(val, ar2315_mem + reg);
-+}
-+
-+static inline void ar2315_gpio_reg_mask(unsigned reg, u32 mask, u32 val)
-+{
-+ ar2315_gpio_reg_write(reg, (ar2315_gpio_reg_read(reg) & ~mask) | val);
-+}
-+
-+static void ar2315_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
-+{
-+ u32 pend;
-+ int bit = -1;
-+
-+ /* only do one gpio interrupt at a time */
-+ pend = ar2315_gpio_reg_read(AR2315_GPIO_DI);
-+ pend ^= ar2315_gpio_intval;
-+ pend &= ar2315_gpio_intmask;
-+
-+ if (pend) {
-+ bit = fls(pend) - 1;
-+ pend &= ~(1 << bit);
-+ ar2315_gpio_intval ^= (1 << bit);
-+ }
-+
-+ /* Enable interrupt with edge detection */
-+ if ((ar2315_gpio_reg_read(AR2315_GPIO_DIR) & AR2315_GPIO_DIR_M(bit)) !=
-+ AR2315_GPIO_DIR_I(bit))
-+ return;
-+
-+ if (bit >= 0)
-+ generic_handle_irq(ar2315_gpio_irq_base + bit);
-+}
-+
-+static void ar2315_gpio_int_setup(unsigned gpio, int trig)
-+{
-+ u32 reg = ar2315_gpio_reg_read(AR2315_GPIO_INT);
-+
-+ reg &= ~(AR2315_GPIO_INT_NUM_M | AR2315_GPIO_INT_TRIG_M);
-+ reg |= gpio | AR2315_GPIO_INT_TRIG(trig);
-+ ar2315_gpio_reg_write(AR2315_GPIO_INT, reg);
-+}
-+
-+static void ar2315_gpio_irq_unmask(struct irq_data *d)
-+{
-+ unsigned gpio = d->irq - ar2315_gpio_irq_base;
-+ u32 dir = ar2315_gpio_reg_read(AR2315_GPIO_DIR);
-+
-+ /* Enable interrupt with edge detection */
-+ if ((dir & AR2315_GPIO_DIR_M(gpio)) != AR2315_GPIO_DIR_I(gpio))
-+ return;
-+
-+ ar2315_gpio_intmask |= (1 << gpio);
-+ ar2315_gpio_int_setup(gpio, AR2315_GPIO_INT_TRIG_EDGE);
-+}
-+
-+static void ar2315_gpio_irq_mask(struct irq_data *d)
-+{
-+ unsigned gpio = d->irq - ar2315_gpio_irq_base;
-+
-+ /* Disable interrupt */
-+ ar2315_gpio_intmask &= ~(1 << gpio);
-+ ar2315_gpio_int_setup(gpio, AR2315_GPIO_INT_TRIG_OFF);
-+}
-+
-+static struct irq_chip ar2315_gpio_irq_chip = {
-+ .name = DRIVER_NAME,
-+ .irq_unmask = ar2315_gpio_irq_unmask,
-+ .irq_mask = ar2315_gpio_irq_mask,
-+};
-+
-+static void ar2315_gpio_irq_init(unsigned irq)
-+{
-+ unsigned i;
-+
-+ ar2315_gpio_intval = ar2315_gpio_reg_read(AR2315_GPIO_DI);
-+ for (i = 0; i < AR2315_GPIO_NUM; i++) {
-+ unsigned _irq = ar2315_gpio_irq_base + i;
-+
-+ irq_set_chip_and_handler(_irq, &ar2315_gpio_irq_chip,
-+ handle_level_irq);
-+ }
-+ irq_set_chained_handler(irq, ar2315_gpio_irq_handler);
-+}
-+
-+static int ar2315_gpio_get_val(struct gpio_chip *chip, unsigned gpio)
-+{
-+ return (ar2315_gpio_reg_read(AR2315_GPIO_DI) >> gpio) & 1;
-+}
-+
-+static void ar2315_gpio_set_val(struct gpio_chip *chip, unsigned gpio, int val)
-+{
-+ u32 reg = ar2315_gpio_reg_read(AR2315_GPIO_DO);
-+
-+ reg = val ? reg | (1 << gpio) : reg & ~(1 << gpio);
-+ ar2315_gpio_reg_write(AR2315_GPIO_DO, reg);
-+}
-+
-+static int ar2315_gpio_dir_in(struct gpio_chip *chip, unsigned gpio)
-+{
-+ ar2315_gpio_reg_mask(AR2315_GPIO_DIR, 1 << gpio, 0);
-+ return 0;
-+}
-+
-+static int ar2315_gpio_dir_out(struct gpio_chip *chip, unsigned gpio, int val)
-+{
-+ ar2315_gpio_reg_mask(AR2315_GPIO_DIR, 0, 1 << gpio);
-+ ar2315_gpio_set_val(chip, gpio, val);
-+ return 0;
-+}
-+
-+static int ar2315_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
-+{
-+ return ar2315_gpio_irq_base + gpio;
-+}
-+
-+static struct gpio_chip ar2315_gpio_chip = {
-+ .label = DRIVER_NAME,
-+ .direction_input = ar2315_gpio_dir_in,
-+ .direction_output = ar2315_gpio_dir_out,
-+ .set = ar2315_gpio_set_val,
-+ .get = ar2315_gpio_get_val,
-+ .to_irq = ar2315_gpio_to_irq,
-+ .base = 0,
-+ .ngpio = AR2315_GPIO_NUM,
-+};
-+
-+static int ar2315_gpio_probe(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ struct resource *res;
-+ unsigned irq;
-+ int ret;
-+
-+ if (ar2315_mem)
-+ return -EBUSY;
-+
-+ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
-+ "ar2315-gpio-irq-base");
-+ if (!res) {
-+ dev_err(dev, "not found GPIO IRQ base\n");
-+ return -ENXIO;
-+ }
-+ ar2315_gpio_irq_base = res->start;
-+
-+ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, DRIVER_NAME);
-+ if (!res) {
-+ dev_err(dev, "not found IRQ number\n");
-+ return -ENXIO;
-+ }
-+ irq = res->start;
-+
-+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, DRIVER_NAME);
-+ ar2315_mem = devm_ioremap_resource(dev, res);
-+ if (IS_ERR(ar2315_mem))
-+ return PTR_ERR(ar2315_mem);
-+
-+ ar2315_gpio_chip.dev = dev;
-+ ret = gpiochip_add(&ar2315_gpio_chip);
-+ if (ret) {
-+ dev_err(dev, "failed to add gpiochip\n");
-+ return ret;
-+ }
-+
-+ ar2315_gpio_irq_init(irq);
-+
-+ return 0;
-+}
-+
-+static struct platform_driver ar2315_gpio_driver = {
-+ .probe = ar2315_gpio_probe,
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ }
-+};
-+
-+static int __init ar2315_gpio_init(void)
-+{
-+ return platform_driver_register(&ar2315_gpio_driver);
-+}
-+subsys_initcall(ar2315_gpio_init);
---- a/arch/mips/ath25/devices.h
-+++ b/arch/mips/ath25/devices.h
-@@ -3,6 +3,11 @@
-
- #include <linux/cpu.h>
-
-+#define AR231X_GPIO_IRQ_BASE 0x30
-+
-+/* GPIO number for AR2315/16 reset issue workaround */
-+#define AR2315_RESET_GPIO 5
-+
- #define ATH25_REG_MS(_val, _field) (((_val) & _field##_M) >> _field##_S)
-
- #define ATH25_IRQ_CPU_CLOCK (MIPS_CPU_IRQ_BASE + 7) /* C0_CAUSE: 0x8000 */
---- a/arch/mips/ath25/ar2315_regs.h
-+++ b/arch/mips/ath25/ar2315_regs.h
-@@ -315,6 +315,9 @@
- #define AR2315_MEM_CFG_BANKADDR_BITS_M 0x00000018
- #define AR2315_MEM_CFG_BANKADDR_BITS_S 3
-
-+/* GPIO MMR base address */
-+#define AR2315_GPIO 0x0088
-+
- /*
- * Local Bus Interface Registers
- */
diff --git a/target/linux/ath25/patches-3.18/110-ar2313_ethernet.patch b/target/linux/ath25/patches-3.18/110-ar2313_ethernet.patch
deleted file mode 100644
index 23c0fb1cd9..0000000000
--- a/target/linux/ath25/patches-3.18/110-ar2313_ethernet.patch
+++ /dev/null
@@ -1,1828 +0,0 @@
---- a/drivers/net/ethernet/atheros/Makefile
-+++ b/drivers/net/ethernet/atheros/Makefile
-@@ -7,3 +7,4 @@ obj-$(CONFIG_ATL2) += atlx/
- obj-$(CONFIG_ATL1E) += atl1e/
- obj-$(CONFIG_ATL1C) += atl1c/
- obj-$(CONFIG_ALX) += alx/
-+obj-$(CONFIG_NET_AR231X) += ar231x/
---- a/drivers/net/ethernet/atheros/Kconfig
-+++ b/drivers/net/ethernet/atheros/Kconfig
-@@ -5,7 +5,7 @@
- config NET_VENDOR_ATHEROS
- bool "Atheros devices"
- default y
-- depends on PCI
-+ depends on (PCI || ATH25)
- ---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
-@@ -80,4 +80,10 @@ config ALX
- To compile this driver as a module, choose M here. The module
- will be called alx.
-
-+config NET_AR231X
-+ tristate "Atheros AR231X built-in Ethernet support"
-+ depends on ATH25
-+ help
-+ Support for the AR231x/531x ethernet controller
-+
- endif # NET_VENDOR_ATHEROS
---- /dev/null
-+++ b/drivers/net/ethernet/atheros/ar231x/Makefile
-@@ -0,0 +1 @@
-+obj-$(CONFIG_NET_AR231X) += ar231x.o
---- /dev/null
-+++ b/drivers/net/ethernet/atheros/ar231x/ar231x.c
-@@ -0,0 +1,1206 @@
-+/*
-+ * ar231x.c: Linux driver for the Atheros AR231x Ethernet device.
-+ *
-+ * Copyright (C) 2004 by Sameer Dekate <sdekate@arubanetworks.com>
-+ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
-+ * Copyright (C) 2006-2009 Felix Fietkau <nbd@nbd.name>
-+ *
-+ * Thanks to Atheros for providing hardware and documentation
-+ * enabling me to write this driver.
-+ *
-+ * 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.
-+ *
-+ * Additional credits:
-+ * This code is taken from John Taylor's Sibyte driver and then
-+ * modified for the AR2313.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/errno.h>
-+#include <linux/ioport.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/interrupt.h>
-+#include <linux/skbuff.h>
-+#include <linux/init.h>
-+#include <linux/delay.h>
-+#include <linux/mm.h>
-+#include <linux/mii.h>
-+#include <linux/phy.h>
-+#include <linux/platform_device.h>
-+#include <linux/io.h>
-+
-+#define AR2313_MTU 1692
-+#define AR2313_PRIOS 1
-+#define AR2313_QUEUES (2*AR2313_PRIOS)
-+#define AR2313_DESCR_ENTRIES 64
-+
-+#ifndef min
-+#define min(a, b) (((a) < (b)) ? (a) : (b))
-+#endif
-+
-+#ifndef SMP_CACHE_BYTES
-+#define SMP_CACHE_BYTES L1_CACHE_BYTES
-+#endif
-+
-+#define AR2313_MBOX_SET_BIT 0x8
-+
-+#include "ar231x.h"
-+
-+/**
-+ * New interrupt handler strategy:
-+ *
-+ * An old interrupt handler worked using the traditional method of
-+ * replacing an skbuff with a new one when a packet arrives. However
-+ * the rx rings do not need to contain a static number of buffer
-+ * descriptors, thus it makes sense to move the memory allocation out
-+ * of the main interrupt handler and do it in a bottom half handler
-+ * and only allocate new buffers when the number of buffers in the
-+ * ring is below a certain threshold. In order to avoid starving the
-+ * NIC under heavy load it is however necessary to force allocation
-+ * when hitting a minimum threshold. The strategy for alloction is as
-+ * follows:
-+ *
-+ * RX_LOW_BUF_THRES - allocate buffers in the bottom half
-+ * RX_PANIC_LOW_THRES - we are very low on buffers, allocate
-+ * the buffers in the interrupt handler
-+ * RX_RING_THRES - maximum number of buffers in the rx ring
-+ *
-+ * One advantagous side effect of this allocation approach is that the
-+ * entire rx processing can be done without holding any spin lock
-+ * since the rx rings and registers are totally independent of the tx
-+ * ring and its registers. This of course includes the kmalloc's of
-+ * new skb's. Thus start_xmit can run in parallel with rx processing
-+ * and the memory allocation on SMP systems.
-+ *
-+ * Note that running the skb reallocation in a bottom half opens up
-+ * another can of races which needs to be handled properly. In
-+ * particular it can happen that the interrupt handler tries to run
-+ * the reallocation while the bottom half is either running on another
-+ * CPU or was interrupted on the same CPU. To get around this the
-+ * driver uses bitops to prevent the reallocation routines from being
-+ * reentered.
-+ *
-+ * TX handling can also be done without holding any spin lock, wheee
-+ * this is fun! since tx_csm is only written to by the interrupt
-+ * handler.
-+ */
-+
-+/**
-+ * Threshold values for RX buffer allocation - the low water marks for
-+ * when to start refilling the rings are set to 75% of the ring
-+ * sizes. It seems to make sense to refill the rings entirely from the
-+ * intrrupt handler once it gets below the panic threshold, that way
-+ * we don't risk that the refilling is moved to another CPU when the
-+ * one running the interrupt handler just got the slab code hot in its
-+ * cache.
-+ */
-+#define RX_RING_SIZE AR2313_DESCR_ENTRIES
-+#define RX_PANIC_THRES (RX_RING_SIZE/4)
-+#define RX_LOW_THRES ((3*RX_RING_SIZE)/4)
-+#define CRC_LEN 4
-+#define RX_OFFSET 2
-+
-+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
-+#define VLAN_HDR 4
-+#else
-+#define VLAN_HDR 0
-+#endif
-+
-+#define AR2313_BUFSIZE (AR2313_MTU + VLAN_HDR + ETH_HLEN + CRC_LEN + \
-+ RX_OFFSET)
-+
-+#ifdef MODULE
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Sameer Dekate <sdekate@arubanetworks.com>, Imre Kaloz <kaloz@openwrt.org>, Felix Fietkau <nbd@nbd.name>");
-+MODULE_DESCRIPTION("AR231x Ethernet driver");
-+#endif
-+
-+#define virt_to_phys(x) ((u32)(x) & 0x1fffffff)
-+
-+/* prototypes */
-+static void ar231x_halt(struct net_device *dev);
-+static void rx_tasklet_func(unsigned long data);
-+static void rx_tasklet_cleanup(struct net_device *dev);
-+static void ar231x_multicast_list(struct net_device *dev);
-+static void ar231x_tx_timeout(struct net_device *dev);
-+
-+static int ar231x_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum);
-+static int ar231x_mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum,
-+ u16 value);
-+static int ar231x_mdiobus_reset(struct mii_bus *bus);
-+static int ar231x_mdiobus_probe(struct net_device *dev);
-+static void ar231x_adjust_link(struct net_device *dev);
-+
-+#ifndef ERR
-+#define ERR(fmt, args...) printk("%s: " fmt, __func__, ##args)
-+#endif
-+
-+#ifdef CONFIG_NET_POLL_CONTROLLER
-+static void
-+ar231x_netpoll(struct net_device *dev)
-+{
-+ unsigned long flags;
-+
-+ local_irq_save(flags);
-+ ar231x_interrupt(dev->irq, dev);
-+ local_irq_restore(flags);
-+}
-+#endif
-+
-+static const struct net_device_ops ar231x_ops = {
-+ .ndo_open = ar231x_open,
-+ .ndo_stop = ar231x_close,
-+ .ndo_start_xmit = ar231x_start_xmit,
-+ .ndo_set_rx_mode = ar231x_multicast_list,
-+ .ndo_do_ioctl = ar231x_ioctl,
-+ .ndo_change_mtu = eth_change_mtu,
-+ .ndo_validate_addr = eth_validate_addr,
-+ .ndo_set_mac_address = eth_mac_addr,
-+ .ndo_tx_timeout = ar231x_tx_timeout,
-+#ifdef CONFIG_NET_POLL_CONTROLLER
-+ .ndo_poll_controller = ar231x_netpoll,
-+#endif
-+};
-+
-+static int ar231x_probe(struct platform_device *pdev)
-+{
-+ struct net_device *dev;
-+ struct ar231x_private *sp;
-+ struct resource *res;
-+ unsigned long ar_eth_base;
-+ char buf[64];
-+
-+ dev = alloc_etherdev(sizeof(struct ar231x_private));
-+
-+ if (dev == NULL) {
-+ printk(KERN_ERR
-+ "ar231x: Unable to allocate net_device structure!\n");
-+ return -ENOMEM;
-+ }
-+
-+ platform_set_drvdata(pdev, dev);
-+
-+ sp = netdev_priv(dev);
-+ sp->dev = dev;
-+ sp->cfg = pdev->dev.platform_data;
-+
-+ sprintf(buf, "eth%d_membase", pdev->id);
-+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, buf);
-+ if (!res)
-+ return -ENODEV;
-+
-+ sp->link = 0;
-+ ar_eth_base = res->start;
-+
-+ sprintf(buf, "eth%d_irq", pdev->id);
-+ dev->irq = platform_get_irq_byname(pdev, buf);
-+
-+ spin_lock_init(&sp->lock);
-+
-+ dev->features |= NETIF_F_HIGHDMA;
-+ dev->netdev_ops = &ar231x_ops;
-+
-+ tasklet_init(&sp->rx_tasklet, rx_tasklet_func, (unsigned long)dev);
-+ tasklet_disable(&sp->rx_tasklet);
-+
-+ sp->eth_regs = ioremap_nocache(ar_eth_base, sizeof(*sp->eth_regs));
-+ if (!sp->eth_regs) {
-+ printk("Can't remap eth registers\n");
-+ return -ENXIO;
-+ }
-+
-+ /**
-+ * When there's only one MAC, PHY regs are typically on ENET0,
-+ * even though the MAC might be on ENET1.
-+ * So remap PHY regs separately.
-+ */
-+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eth0_mii");
-+ if (!res) {
-+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-+ "eth1_mii");
-+ if (!res)
-+ return -ENODEV;
-+ }
-+ sp->phy_regs = ioremap_nocache(res->start, resource_size(res));
-+ if (!sp->phy_regs) {
-+ printk("Can't remap phy registers\n");
-+ return -ENXIO;
-+ }
-+
-+ sp->dma_regs = ioremap_nocache(ar_eth_base + 0x1000,
-+ sizeof(*sp->dma_regs));
-+ if (!sp->dma_regs) {
-+ printk("Can't remap DMA registers\n");
-+ return -ENXIO;
-+ }
-+ dev->base_addr = ar_eth_base + 0x1000;
-+
-+ strncpy(sp->name, "Atheros AR231x", sizeof(sp->name) - 1);
-+ sp->name[sizeof(sp->name) - 1] = '\0';
-+ memcpy(dev->dev_addr, sp->cfg->macaddr, 6);
-+
-+ if (ar231x_init(dev)) {
-+ /* ar231x_init() calls ar231x_init_cleanup() on error */
-+ kfree(dev);
-+ return -ENODEV;
-+ }
-+
-+ if (register_netdev(dev)) {
-+ printk("%s: register_netdev failed\n", __func__);
-+ return -1;
-+ }
-+
-+ printk("%s: %s: %pM, irq %d\n", dev->name, sp->name, dev->dev_addr,
-+ dev->irq);
-+
-+ sp->mii_bus = mdiobus_alloc();
-+ if (sp->mii_bus == NULL)
-+ return -1;
-+
-+ sp->mii_bus->priv = dev;
-+ sp->mii_bus->read = ar231x_mdiobus_read;
-+ sp->mii_bus->write = ar231x_mdiobus_write;
-+ sp->mii_bus->reset = ar231x_mdiobus_reset;
-+ sp->mii_bus->name = "ar231x_eth_mii";
-+ snprintf(sp->mii_bus->id, MII_BUS_ID_SIZE, "%d", pdev->id);
-+ sp->mii_bus->irq = kmalloc(sizeof(int), GFP_KERNEL);
-+ *sp->mii_bus->irq = PHY_POLL;
-+
-+ mdiobus_register(sp->mii_bus);
-+
-+ if (ar231x_mdiobus_probe(dev) != 0) {
-+ printk(KERN_ERR "%s: mdiobus_probe failed\n", dev->name);
-+ rx_tasklet_cleanup(dev);
-+ ar231x_init_cleanup(dev);
-+ unregister_netdev(dev);
-+ kfree(dev);
-+ return -ENODEV;
-+ }
-+
-+ /* start link poll timer */
-+ ar231x_setup_timer(dev);
-+
-+ return 0;
-+}
-+
-+static void ar231x_multicast_list(struct net_device *dev)
-+{
-+ struct ar231x_private *sp = netdev_priv(dev);
-+ unsigned int filter;
-+
-+ filter = sp->eth_regs->mac_control;
-+
-+ if (dev->flags & IFF_PROMISC)
-+ filter |= MAC_CONTROL_PR;
-+ else
-+ filter &= ~MAC_CONTROL_PR;
-+ if ((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 0))
-+ filter |= MAC_CONTROL_PM;
-+ else
-+ filter &= ~MAC_CONTROL_PM;
-+
-+ sp->eth_regs->mac_control = filter;
-+}
-+
-+static void rx_tasklet_cleanup(struct net_device *dev)
-+{
-+ struct ar231x_private *sp = netdev_priv(dev);
-+
-+ /**
-+ * Tasklet may be scheduled. Need to get it removed from the list
-+ * since we're about to free the struct.
-+ */
-+
-+ sp->unloading = 1;
-+ tasklet_enable(&sp->rx_tasklet);
-+ tasklet_kill(&sp->rx_tasklet);
-+}
-+
-+static int ar231x_remove(struct platform_device *pdev)
-+{
-+ struct net_device *dev = platform_get_drvdata(pdev);
-+ struct ar231x_private *sp = netdev_priv(dev);
-+
-+ rx_tasklet_cleanup(dev);
-+ ar231x_init_cleanup(dev);
-+ unregister_netdev(dev);
-+ mdiobus_unregister(sp->mii_bus);
-+ mdiobus_free(sp->mii_bus);
-+ kfree(dev);
-+ return 0;
-+}
-+
-+/**
-+ * Restart the AR2313 ethernet controller.
-+ */
-+static int ar231x_restart(struct net_device *dev)
-+{
-+ /* disable interrupts */
-+ disable_irq(dev->irq);
-+
-+ /* stop mac */
-+ ar231x_halt(dev);
-+
-+ /* initialize */
-+ ar231x_init(dev);
-+
-+ /* enable interrupts */
-+ enable_irq(dev->irq);
-+
-+ return 0;
-+}
-+
-+static struct platform_driver ar231x_driver = {
-+ .driver.name = "ar231x-eth",
-+ .probe = ar231x_probe,
-+ .remove = ar231x_remove,
-+};
-+
-+module_platform_driver(ar231x_driver);
-+
-+static void ar231x_free_descriptors(struct net_device *dev)
-+{
-+ struct ar231x_private *sp = netdev_priv(dev);
-+
-+ if (sp->rx_ring != NULL) {
-+ kfree((void *)KSEG0ADDR(sp->rx_ring));
-+ sp->rx_ring = NULL;
-+ sp->tx_ring = NULL;
-+ }
-+}
-+
-+static int ar231x_allocate_descriptors(struct net_device *dev)
-+{
-+ struct ar231x_private *sp = netdev_priv(dev);
-+ int size;
-+ int j;
-+ ar231x_descr_t *space;
-+
-+ if (sp->rx_ring != NULL) {
-+ printk("%s: already done.\n", __func__);
-+ return 0;
-+ }
-+
-+ size = sizeof(ar231x_descr_t) * (AR2313_DESCR_ENTRIES * AR2313_QUEUES);
-+ space = kmalloc(size, GFP_KERNEL);
-+ if (space == NULL)
-+ return 1;
-+
-+ /* invalidate caches */
-+ dma_cache_inv((unsigned int)space, size);
-+
-+ /* now convert pointer to KSEG1 */
-+ space = (ar231x_descr_t *)KSEG1ADDR(space);
-+
-+ memset((void *)space, 0, size);
-+
-+ sp->rx_ring = space;
-+ space += AR2313_DESCR_ENTRIES;
-+
-+ sp->tx_ring = space;
-+ space += AR2313_DESCR_ENTRIES;
-+
-+ /* Initialize the transmit Descriptors */
-+ for (j = 0; j < AR2313_DESCR_ENTRIES; j++) {
-+ ar231x_descr_t *td = &sp->tx_ring[j];
-+
-+ td->status = 0;
-+ td->devcs = DMA_TX1_CHAINED;
-+ td->addr = 0;
-+ td->descr = virt_to_phys(&sp->tx_ring[DSC_NEXT(j)]);
-+ }
-+
-+ return 0;
-+}
-+
-+/**
-+ * Generic cleanup handling data allocated during init. Used when the
-+ * module is unloaded or if an error occurs during initialization
-+ */
-+static void ar231x_init_cleanup(struct net_device *dev)
-+{
-+ struct ar231x_private *sp = netdev_priv(dev);
-+ struct sk_buff *skb;
-+ int j;
-+
-+ ar231x_free_descriptors(dev);
-+
-+ if (sp->eth_regs)
-+ iounmap((void *)sp->eth_regs);
-+ if (sp->dma_regs)
-+ iounmap((void *)sp->dma_regs);
-+ if (sp->phy_regs)
-+ iounmap((void *)sp->phy_regs);
-+
-+ if (sp->rx_skb) {
-+ for (j = 0; j < AR2313_DESCR_ENTRIES; j++) {
-+ skb = sp->rx_skb[j];
-+ if (skb) {
-+ sp->rx_skb[j] = NULL;
-+ dev_kfree_skb(skb);
-+ }
-+ }
-+ kfree(sp->rx_skb);
-+ sp->rx_skb = NULL;
-+ }
-+
-+ if (sp->tx_skb) {
-+ for (j = 0; j < AR2313_DESCR_ENTRIES; j++) {
-+ skb = sp->tx_skb[j];
-+ if (skb) {
-+ sp->tx_skb[j] = NULL;
-+ dev_kfree_skb(skb);
-+ }
-+ }
-+ kfree(sp->tx_skb);
-+ sp->tx_skb = NULL;
-+ }
-+}
-+
-+static int ar231x_setup_timer(struct net_device *dev)
-+{
-+ struct ar231x_private *sp = netdev_priv(dev);
-+
-+ init_timer(&sp->link_timer);
-+
-+ sp->link_timer.function = ar231x_link_timer_fn;
-+ sp->link_timer.data = (int)dev;
-+ sp->link_timer.expires = jiffies + HZ;
-+
-+ add_timer(&sp->link_timer);
-+ return 0;
-+}
-+
-+static void ar231x_link_timer_fn(unsigned long data)
-+{
-+ struct net_device *dev = (struct net_device *)data;
-+ struct ar231x_private *sp = netdev_priv(dev);
-+
-+ /**
-+ * See if the link status changed.
-+ * This was needed to make sure we set the PHY to the
-+ * autonegotiated value of half or full duplex.
-+ */
-+ ar231x_check_link(dev);
-+
-+ /**
-+ * Loop faster when we don't have link.
-+ * This was needed to speed up the AP bootstrap time.
-+ */
-+ if (sp->link == 0)
-+ mod_timer(&sp->link_timer, jiffies + HZ / 2);
-+ else
-+ mod_timer(&sp->link_timer, jiffies + LINK_TIMER);
-+}
-+
-+static void ar231x_check_link(struct net_device *dev)
-+{
-+ struct ar231x_private *sp = netdev_priv(dev);
-+ u16 phy_data;
-+
-+ phy_data = ar231x_mdiobus_read(sp->mii_bus, sp->phy, MII_BMSR);
-+ if (sp->phy_data != phy_data) {
-+ if (phy_data & BMSR_LSTATUS) {
-+ /**
-+ * Link is present, ready link partner ability to
-+ * deterine duplexity.
-+ */
-+ int duplex = 0;
-+ u16 reg;
-+
-+ sp->link = 1;
-+ reg = ar231x_mdiobus_read(sp->mii_bus, sp->phy,
-+ MII_BMCR);
-+ if (reg & BMCR_ANENABLE) {
-+ /* auto neg enabled */
-+ reg = ar231x_mdiobus_read(sp->mii_bus, sp->phy,
-+ MII_LPA);
-+ duplex = reg & (LPA_100FULL | LPA_10FULL) ?
-+ 1 : 0;
-+ } else {
-+ /* no auto neg, just read duplex config */
-+ duplex = (reg & BMCR_FULLDPLX) ? 1 : 0;
-+ }
-+
-+ printk(KERN_INFO "%s: Configuring MAC for %s duplex\n",
-+ dev->name, (duplex) ? "full" : "half");
-+
-+ if (duplex) {
-+ /* full duplex */
-+ sp->eth_regs->mac_control =
-+ (sp->eth_regs->mac_control |
-+ MAC_CONTROL_F) & ~MAC_CONTROL_DRO;
-+ } else {
-+ /* half duplex */
-+ sp->eth_regs->mac_control =
-+ (sp->eth_regs->mac_control |
-+ MAC_CONTROL_DRO) & ~MAC_CONTROL_F;
-+ }
-+ } else {
-+ /* no link */
-+ sp->link = 0;
-+ }
-+ sp->phy_data = phy_data;
-+ }
-+}
-+
-+static int ar231x_reset_reg(struct net_device *dev)
-+{
-+ struct ar231x_private *sp = netdev_priv(dev);
-+ unsigned int ethsal, ethsah;
-+ unsigned int flags;
-+
-+ sp->cfg->reset_set(sp->cfg->reset_mac);
-+ mdelay(10);
-+ sp->cfg->reset_clear(sp->cfg->reset_mac);
-+ mdelay(10);
-+ sp->cfg->reset_set(sp->cfg->reset_phy);
-+ mdelay(10);
-+ sp->cfg->reset_clear(sp->cfg->reset_phy);
-+ mdelay(10);
-+
-+ sp->dma_regs->bus_mode = (DMA_BUS_MODE_SWR);
-+ mdelay(10);
-+ sp->dma_regs->bus_mode =
-+ ((32 << DMA_BUS_MODE_PBL_SHIFT) | DMA_BUS_MODE_BLE);
-+
-+ /* enable interrupts */
-+ sp->dma_regs->intr_ena = DMA_STATUS_AIS | DMA_STATUS_NIS |
-+ DMA_STATUS_RI | DMA_STATUS_TI |
-+ DMA_STATUS_FBE;
-+ sp->dma_regs->xmt_base = virt_to_phys(sp->tx_ring);
-+ sp->dma_regs->rcv_base = virt_to_phys(sp->rx_ring);
-+ sp->dma_regs->control =
-+ (DMA_CONTROL_SR | DMA_CONTROL_ST | DMA_CONTROL_SF);
-+
-+ sp->eth_regs->flow_control = (FLOW_CONTROL_FCE);
-+ sp->eth_regs->vlan_tag = (0x8100);
-+
-+ /* Enable Ethernet Interface */
-+ flags = (MAC_CONTROL_TE | /* transmit enable */
-+ MAC_CONTROL_PM | /* pass mcast */
-+ MAC_CONTROL_F | /* full duplex */
-+ MAC_CONTROL_HBD); /* heart beat disabled */
-+
-+ if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */
-+ flags |= MAC_CONTROL_PR;
-+ }
-+ sp->eth_regs->mac_control = flags;
-+
-+ /* Set all Ethernet station address registers to their initial values */
-+ ethsah = (((u_int) (dev->dev_addr[5]) << 8) & (u_int) 0x0000FF00) |
-+ (((u_int) (dev->dev_addr[4]) << 0) & (u_int) 0x000000FF);
-+
-+ ethsal = (((u_int) (dev->dev_addr[3]) << 24) & (u_int) 0xFF000000) |
-+ (((u_int) (dev->dev_addr[2]) << 16) & (u_int) 0x00FF0000) |
-+ (((u_int) (dev->dev_addr[1]) << 8) & (u_int) 0x0000FF00) |
-+ (((u_int) (dev->dev_addr[0]) << 0) & (u_int) 0x000000FF);
-+
-+ sp->eth_regs->mac_addr[0] = ethsah;
-+ sp->eth_regs->mac_addr[1] = ethsal;
-+
-+ mdelay(10);
-+
-+ return 0;
-+}
-+
-+static int ar231x_init(struct net_device *dev)
-+{
-+ struct ar231x_private *sp = netdev_priv(dev);
-+ int ecode = 0;
-+
-+ /* Allocate descriptors */
-+ if (ar231x_allocate_descriptors(dev)) {
-+ printk("%s: %s: ar231x_allocate_descriptors failed\n",
-+ dev->name, __func__);
-+ ecode = -EAGAIN;
-+ goto init_error;
-+ }
-+
-+ /* Get the memory for the skb rings */
-+ if (sp->rx_skb == NULL) {
-+ sp->rx_skb =
-+ kmalloc(sizeof(struct sk_buff *) * AR2313_DESCR_ENTRIES,
-+ GFP_KERNEL);
-+ if (!(sp->rx_skb)) {
-+ printk("%s: %s: rx_skb kmalloc failed\n",
-+ dev->name, __func__);
-+ ecode = -EAGAIN;
-+ goto init_error;
-+ }
-+ }
-+ memset(sp->rx_skb, 0, sizeof(struct sk_buff *) * AR2313_DESCR_ENTRIES);
-+
-+ if (sp->tx_skb == NULL) {
-+ sp->tx_skb =
-+ kmalloc(sizeof(struct sk_buff *) * AR2313_DESCR_ENTRIES,
-+ GFP_KERNEL);
-+ if (!(sp->tx_skb)) {
-+ printk("%s: %s: tx_skb kmalloc failed\n",
-+ dev->name, __func__);
-+ ecode = -EAGAIN;
-+ goto init_error;
-+ }
-+ }
-+ memset(sp->tx_skb, 0, sizeof(struct sk_buff *) * AR2313_DESCR_ENTRIES);
-+
-+ /**
-+ * Set tx_csm before we start receiving interrupts, otherwise
-+ * the interrupt handler might think it is supposed to process
-+ * tx ints before we are up and running, which may cause a null
-+ * pointer access in the int handler.
-+ */
-+ sp->rx_skbprd = 0;
-+ sp->cur_rx = 0;
-+ sp->tx_prd = 0;
-+ sp->tx_csm = 0;
-+
-+ /* Zero the stats before starting the interface */
-+ memset(&dev->stats, 0, sizeof(dev->stats));
-+
-+ /**
-+ * We load the ring here as there seem to be no way to tell the
-+ * firmware to wipe the ring without re-initializing it.
-+ */
-+ ar231x_load_rx_ring(dev, RX_RING_SIZE);
-+
-+ /* Init hardware */
-+ ar231x_reset_reg(dev);
-+
-+ /* Get the IRQ */
-+ ecode = request_irq(dev->irq, &ar231x_interrupt, IRQF_DISABLED,
-+ dev->name, dev);
-+ if (ecode) {
-+ printk(KERN_WARNING "%s: %s: Requested IRQ %d is busy\n",
-+ dev->name, __func__, dev->irq);
-+ goto init_error;
-+ }
-+
-+ tasklet_enable(&sp->rx_tasklet);
-+
-+ return 0;
-+
-+init_error:
-+ ar231x_init_cleanup(dev);
-+ return ecode;
-+}
-+
-+/**
-+ * Load the rx ring.
-+ *
-+ * Loading rings is safe without holding the spin lock since this is
-+ * done only before the device is enabled, thus no interrupts are
-+ * generated and by the interrupt handler/tasklet handler.
-+ */
-+static void ar231x_load_rx_ring(struct net_device *dev, int nr_bufs)
-+{
-+ struct ar231x_private *sp = netdev_priv(dev);
-+ short i, idx;
-+
-+ idx = sp->rx_skbprd;
-+
-+ for (i = 0; i < nr_bufs; i++) {
-+ struct sk_buff *skb;
-+ ar231x_descr_t *rd;
-+
-+ if (sp->rx_skb[idx])
-+ break;
-+
-+ skb = netdev_alloc_skb_ip_align(dev, AR2313_BUFSIZE);
-+ if (!skb) {
-+ printk("\n\n\n\n %s: No memory in system\n\n\n\n",
-+ __func__);
-+ break;
-+ }
-+
-+ /* Make sure IP header starts on a fresh cache line */
-+ skb->dev = dev;
-+ sp->rx_skb[idx] = skb;
-+
-+ rd = (ar231x_descr_t *)&sp->rx_ring[idx];
-+
-+ /* initialize dma descriptor */
-+ rd->devcs = ((AR2313_BUFSIZE << DMA_RX1_BSIZE_SHIFT) |
-+ DMA_RX1_CHAINED);
-+ rd->addr = virt_to_phys(skb->data);
-+ rd->descr = virt_to_phys(&sp->rx_ring[DSC_NEXT(idx)]);
-+ rd->status = DMA_RX_OWN;
-+
-+ idx = DSC_NEXT(idx);
-+ }
-+
-+ if (i)
-+ sp->rx_skbprd = idx;
-+}
-+
-+#define AR2313_MAX_PKTS_PER_CALL 64
-+
-+static int ar231x_rx_int(struct net_device *dev)
-+{
-+ struct ar231x_private *sp = netdev_priv(dev);
-+ struct sk_buff *skb, *skb_new;
-+ ar231x_descr_t *rxdesc;
-+ unsigned int status;
-+ u32 idx;
-+ int pkts = 0;
-+ int rval;
-+
-+ idx = sp->cur_rx;
-+
-+ /* process at most the entire ring and then wait for another int */
-+ while (1) {
-+ rxdesc = &sp->rx_ring[idx];
-+ status = rxdesc->status;
-+
-+ if (status & DMA_RX_OWN) {
-+ /* SiByte owns descriptor or descr not yet filled in */
-+ rval = 0;
-+ break;
-+ }
-+
-+ if (++pkts > AR2313_MAX_PKTS_PER_CALL) {
-+ rval = 1;
-+ break;
-+ }
-+
-+ if ((status & DMA_RX_ERROR) && !(status & DMA_RX_LONG)) {
-+ dev->stats.rx_errors++;
-+ dev->stats.rx_dropped++;
-+
-+ /* add statistics counters */
-+ if (status & DMA_RX_ERR_CRC)
-+ dev->stats.rx_crc_errors++;
-+ if (status & DMA_RX_ERR_COL)
-+ dev->stats.rx_over_errors++;
-+ if (status & DMA_RX_ERR_LENGTH)
-+ dev->stats.rx_length_errors++;
-+ if (status & DMA_RX_ERR_RUNT)
-+ dev->stats.rx_over_errors++;
-+ if (status & DMA_RX_ERR_DESC)
-+ dev->stats.rx_over_errors++;
-+
-+ } else {
-+ /* alloc new buffer. */
-+ skb_new = netdev_alloc_skb_ip_align(dev,
-+ AR2313_BUFSIZE);
-+ if (skb_new != NULL) {
-+ skb = sp->rx_skb[idx];
-+ /* set skb */
-+ skb_put(skb, ((status >> DMA_RX_LEN_SHIFT) &
-+ 0x3fff) - CRC_LEN);
-+
-+ dev->stats.rx_bytes += skb->len;
-+ skb->protocol = eth_type_trans(skb, dev);
-+ /* pass the packet to upper layers */
-+ netif_rx(skb);
-+
-+ skb_new->dev = dev;
-+ /* reset descriptor's curr_addr */
-+ rxdesc->addr = virt_to_phys(skb_new->data);
-+
-+ dev->stats.rx_packets++;
-+ sp->rx_skb[idx] = skb_new;
-+ } else {
-+ dev->stats.rx_dropped++;
-+ }
-+ }
-+
-+ rxdesc->devcs = ((AR2313_BUFSIZE << DMA_RX1_BSIZE_SHIFT) |
-+ DMA_RX1_CHAINED);
-+ rxdesc->status = DMA_RX_OWN;
-+
-+ idx = DSC_NEXT(idx);
-+ }
-+
-+ sp->cur_rx = idx;
-+
-+ return rval;
-+}
-+
-+static void ar231x_tx_int(struct net_device *dev)
-+{
-+ struct ar231x_private *sp = netdev_priv(dev);
-+ u32 idx;
-+ struct sk_buff *skb;
-+ ar231x_descr_t *txdesc;
-+ unsigned int status = 0;
-+
-+ idx = sp->tx_csm;
-+
-+ while (idx != sp->tx_prd) {
-+ txdesc = &sp->tx_ring[idx];
-+ status = txdesc->status;
-+
-+ if (status & DMA_TX_OWN) {
-+ /* ar231x dma still owns descr */
-+ break;
-+ }
-+ /* done with this descriptor */
-+ dma_unmap_single(NULL, txdesc->addr,
-+ txdesc->devcs & DMA_TX1_BSIZE_MASK,
-+ DMA_TO_DEVICE);
-+ txdesc->status = 0;
-+
-+ if (status & DMA_TX_ERROR) {
-+ dev->stats.tx_errors++;
-+ dev->stats.tx_dropped++;
-+ if (status & DMA_TX_ERR_UNDER)
-+ dev->stats.tx_fifo_errors++;
-+ if (status & DMA_TX_ERR_HB)
-+ dev->stats.tx_heartbeat_errors++;
-+ if (status & (DMA_TX_ERR_LOSS | DMA_TX_ERR_LINK))
-+ dev->stats.tx_carrier_errors++;
-+ if (status & (DMA_TX_ERR_LATE | DMA_TX_ERR_COL |
-+ DMA_TX_ERR_JABBER | DMA_TX_ERR_DEFER))
-+ dev->stats.tx_aborted_errors++;
-+ } else {
-+ /* transmit OK */
-+ dev->stats.tx_packets++;
-+ }
-+
-+ skb = sp->tx_skb[idx];
-+ sp->tx_skb[idx] = NULL;
-+ idx = DSC_NEXT(idx);
-+ dev->stats.tx_bytes += skb->len;
-+ dev_kfree_skb_irq(skb);
-+ }
-+
-+ sp->tx_csm = idx;
-+}
-+
-+static void rx_tasklet_func(unsigned long data)
-+{
-+ struct net_device *dev = (struct net_device *)data;
-+ struct ar231x_private *sp = netdev_priv(dev);
-+
-+ if (sp->unloading)
-+ return;
-+
-+ if (ar231x_rx_int(dev)) {
-+ tasklet_hi_schedule(&sp->rx_tasklet);
-+ } else {
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&sp->lock, flags);
-+ sp->dma_regs->intr_ena |= DMA_STATUS_RI;
-+ spin_unlock_irqrestore(&sp->lock, flags);
-+ }
-+}
-+
-+static void rx_schedule(struct net_device *dev)
-+{
-+ struct ar231x_private *sp = netdev_priv(dev);
-+
-+ sp->dma_regs->intr_ena &= ~DMA_STATUS_RI;
-+
-+ tasklet_hi_schedule(&sp->rx_tasklet);
-+}
-+
-+static irqreturn_t ar231x_interrupt(int irq, void *dev_id)
-+{
-+ struct net_device *dev = (struct net_device *)dev_id;
-+ struct ar231x_private *sp = netdev_priv(dev);
-+ unsigned int status, enabled;
-+
-+ /* clear interrupt */
-+ /* Don't clear RI bit if currently disabled */
-+ status = sp->dma_regs->status;
-+ enabled = sp->dma_regs->intr_ena;
-+ sp->dma_regs->status = status & enabled;
-+
-+ if (status & DMA_STATUS_NIS) {
-+ /* normal status */
-+ /**
-+ * Don't schedule rx processing if interrupt
-+ * is already disabled.
-+ */
-+ if (status & enabled & DMA_STATUS_RI) {
-+ /* receive interrupt */
-+ rx_schedule(dev);
-+ }
-+ if (status & DMA_STATUS_TI) {
-+ /* transmit interrupt */
-+ ar231x_tx_int(dev);
-+ }
-+ }
-+
-+ /* abnormal status */
-+ if (status & (DMA_STATUS_FBE | DMA_STATUS_TPS))
-+ ar231x_restart(dev);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static int ar231x_open(struct net_device *dev)
-+{
-+ struct ar231x_private *sp = netdev_priv(dev);
-+ unsigned int ethsal, ethsah;
-+
-+ /* reset the hardware, in case the MAC address changed */
-+ ethsah = (((u_int) (dev->dev_addr[5]) << 8) & (u_int) 0x0000FF00) |
-+ (((u_int) (dev->dev_addr[4]) << 0) & (u_int) 0x000000FF);
-+
-+ ethsal = (((u_int) (dev->dev_addr[3]) << 24) & (u_int) 0xFF000000) |
-+ (((u_int) (dev->dev_addr[2]) << 16) & (u_int) 0x00FF0000) |
-+ (((u_int) (dev->dev_addr[1]) << 8) & (u_int) 0x0000FF00) |
-+ (((u_int) (dev->dev_addr[0]) << 0) & (u_int) 0x000000FF);
-+
-+ sp->eth_regs->mac_addr[0] = ethsah;
-+ sp->eth_regs->mac_addr[1] = ethsal;
-+
-+ mdelay(10);
-+
-+ dev->mtu = 1500;
-+ netif_start_queue(dev);
-+
-+ sp->eth_regs->mac_control |= MAC_CONTROL_RE;
-+
-+ return 0;
-+}
-+
-+static void ar231x_tx_timeout(struct net_device *dev)
-+{
-+ struct ar231x_private *sp = netdev_priv(dev);
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&sp->lock, flags);
-+ ar231x_restart(dev);
-+ spin_unlock_irqrestore(&sp->lock, flags);
-+}
-+
-+static void ar231x_halt(struct net_device *dev)
-+{
-+ struct ar231x_private *sp = netdev_priv(dev);
-+ int j;
-+
-+ tasklet_disable(&sp->rx_tasklet);
-+
-+ /* kill the MAC */
-+ sp->eth_regs->mac_control &= ~(MAC_CONTROL_RE | /* disable Receives */
-+ MAC_CONTROL_TE); /* disable Transmits */
-+ /* stop dma */
-+ sp->dma_regs->control = 0;
-+ sp->dma_regs->bus_mode = DMA_BUS_MODE_SWR;
-+
-+ /* place phy and MAC in reset */
-+ sp->cfg->reset_set(sp->cfg->reset_mac);
-+ sp->cfg->reset_set(sp->cfg->reset_phy);
-+
-+ /* free buffers on tx ring */
-+ for (j = 0; j < AR2313_DESCR_ENTRIES; j++) {
-+ struct sk_buff *skb;
-+ ar231x_descr_t *txdesc;
-+
-+ txdesc = &sp->tx_ring[j];
-+ txdesc->descr = 0;
-+
-+ skb = sp->tx_skb[j];
-+ if (skb) {
-+ dev_kfree_skb(skb);
-+ sp->tx_skb[j] = NULL;
-+ }
-+ }
-+}
-+
-+/**
-+ * close should do nothing. Here's why. It's called when
-+ * 'ifconfig bond0 down' is run. If it calls free_irq then
-+ * the irq is gone forever ! When bond0 is made 'up' again,
-+ * the ar231x_open () does not call request_irq (). Worse,
-+ * the call to ar231x_halt() generates a WDOG reset due to
-+ * the write to reset register and the box reboots.
-+ * Commenting this out is good since it allows the
-+ * system to resume when bond0 is made up again.
-+ */
-+static int ar231x_close(struct net_device *dev)
-+{
-+#if 0
-+ /* Disable interrupts */
-+ disable_irq(dev->irq);
-+
-+ /**
-+ * Without (or before) releasing irq and stopping hardware, this
-+ * is an absolute non-sense, by the way. It will be reset instantly
-+ * by the first irq.
-+ */
-+ netif_stop_queue(dev);
-+
-+ /* stop the MAC and DMA engines */
-+ ar231x_halt(dev);
-+
-+ /* release the interrupt */
-+ free_irq(dev->irq, dev);
-+
-+#endif
-+ return 0;
-+}
-+
-+static int ar231x_start_xmit(struct sk_buff *skb, struct net_device *dev)
-+{
-+ struct ar231x_private *sp = netdev_priv(dev);
-+ ar231x_descr_t *td;
-+ u32 idx;
-+
-+ idx = sp->tx_prd;
-+ td = &sp->tx_ring[idx];
-+
-+ if (td->status & DMA_TX_OWN) {
-+ /* free skbuf and lie to the caller that we sent it out */
-+ dev->stats.tx_dropped++;
-+ dev_kfree_skb(skb);
-+
-+ /* restart transmitter in case locked */
-+ sp->dma_regs->xmt_poll = 0;
-+ return 0;
-+ }
-+
-+ /* Setup the transmit descriptor. */
-+ td->devcs = ((skb->len << DMA_TX1_BSIZE_SHIFT) |
-+ (DMA_TX1_LS | DMA_TX1_IC | DMA_TX1_CHAINED));
-+ td->addr = dma_map_single(NULL, skb->data, skb->len, DMA_TO_DEVICE);
-+ td->status = DMA_TX_OWN;
-+
-+ /* kick transmitter last */
-+ sp->dma_regs->xmt_poll = 0;
-+
-+ sp->tx_skb[idx] = skb;
-+ idx = DSC_NEXT(idx);
-+ sp->tx_prd = idx;
-+
-+ return 0;
-+}
-+
-+static int ar231x_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-+{
-+ struct ar231x_private *sp = netdev_priv(dev);
-+
-+ switch (cmd) {
-+ case SIOCGMIIPHY:
-+ case SIOCGMIIREG:
-+ case SIOCSMIIREG:
-+ return phy_mii_ioctl(sp->phy_dev, ifr, cmd);
-+
-+ default:
-+ break;
-+ }
-+
-+ return -EOPNOTSUPP;
-+}
-+
-+static void ar231x_adjust_link(struct net_device *dev)
-+{
-+ struct ar231x_private *sp = netdev_priv(dev);
-+ unsigned int mc;
-+
-+ if (!sp->phy_dev->link)
-+ return;
-+
-+ if (sp->phy_dev->duplex != sp->oldduplex) {
-+ mc = readl(&sp->eth_regs->mac_control);
-+ mc &= ~(MAC_CONTROL_F | MAC_CONTROL_DRO);
-+ if (sp->phy_dev->duplex)
-+ mc |= MAC_CONTROL_F;
-+ else
-+ mc |= MAC_CONTROL_DRO;
-+ writel(mc, &sp->eth_regs->mac_control);
-+ sp->oldduplex = sp->phy_dev->duplex;
-+ }
-+}
-+
-+#define MII_ADDR(phy, reg) \
-+ ((reg << MII_ADDR_REG_SHIFT) | (phy << MII_ADDR_PHY_SHIFT))
-+
-+static int
-+ar231x_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
-+{
-+ struct net_device *const dev = bus->priv;
-+ struct ar231x_private *sp = netdev_priv(dev);
-+ volatile MII *ethernet = sp->phy_regs;
-+
-+ ethernet->mii_addr = MII_ADDR(phy_addr, regnum);
-+ while (ethernet->mii_addr & MII_ADDR_BUSY)
-+ ;
-+ return ethernet->mii_data >> MII_DATA_SHIFT;
-+}
-+
-+static int
-+ar231x_mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum, u16 value)
-+{
-+ struct net_device *const dev = bus->priv;
-+ struct ar231x_private *sp = netdev_priv(dev);
-+ volatile MII *ethernet = sp->phy_regs;
-+
-+ while (ethernet->mii_addr & MII_ADDR_BUSY)
-+ ;
-+ ethernet->mii_data = value << MII_DATA_SHIFT;
-+ ethernet->mii_addr = MII_ADDR(phy_addr, regnum) | MII_ADDR_WRITE;
-+
-+ return 0;
-+}
-+
-+static int ar231x_mdiobus_reset(struct mii_bus *bus)
-+{
-+ struct net_device *const dev = bus->priv;
-+
-+ ar231x_reset_reg(dev);
-+
-+ return 0;
-+}
-+
-+static int ar231x_mdiobus_probe(struct net_device *dev)
-+{
-+ struct ar231x_private *const sp = netdev_priv(dev);
-+ struct phy_device *phydev = NULL;
-+ int phy_addr;
-+
-+ /* find the first (lowest address) PHY on the current MAC's MII bus */
-+ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++)
-+ if (sp->mii_bus->phy_map[phy_addr]) {
-+ phydev = sp->mii_bus->phy_map[phy_addr];
-+ sp->phy = phy_addr;
-+ break; /* break out with first one found */
-+ }
-+
-+ if (!phydev) {
-+ printk(KERN_ERR "ar231x: %s: no PHY found\n", dev->name);
-+ return -1;
-+ }
-+
-+ /* now we are supposed to have a proper phydev, to attach to... */
-+ BUG_ON(!phydev);
-+ BUG_ON(phydev->attached_dev);
-+
-+ phydev = phy_connect(dev, dev_name(&phydev->dev), &ar231x_adjust_link,
-+ PHY_INTERFACE_MODE_MII);
-+
-+ if (IS_ERR(phydev)) {
-+ printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
-+ return PTR_ERR(phydev);
-+ }
-+
-+ /* mask with MAC supported features */
-+ phydev->supported &= (SUPPORTED_10baseT_Half
-+ | SUPPORTED_10baseT_Full
-+ | SUPPORTED_100baseT_Half
-+ | SUPPORTED_100baseT_Full
-+ | SUPPORTED_Autoneg
-+ /* | SUPPORTED_Pause | SUPPORTED_Asym_Pause */
-+ | SUPPORTED_MII
-+ | SUPPORTED_TP);
-+
-+ phydev->advertising = phydev->supported;
-+
-+ sp->oldduplex = -1;
-+ sp->phy_dev = phydev;
-+
-+ printk(KERN_INFO "%s: attached PHY driver [%s] (mii_bus:phy_addr=%s)\n",
-+ dev->name, phydev->drv->name, dev_name(&phydev->dev));
-+
-+ return 0;
-+}
-+
---- /dev/null
-+++ b/drivers/net/ethernet/atheros/ar231x/ar231x.h
-@@ -0,0 +1,288 @@
-+/*
-+ * ar231x.h: Linux driver for the Atheros AR231x Ethernet device.
-+ *
-+ * Copyright (C) 2004 by Sameer Dekate <sdekate@arubanetworks.com>
-+ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
-+ * Copyright (C) 2006-2009 Felix Fietkau <nbd@nbd.name>
-+ *
-+ * Thanks to Atheros for providing hardware and documentation
-+ * enabling me to write this driver.
-+ *
-+ * 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.
-+ */
-+
-+#ifndef _AR2313_H_
-+#define _AR2313_H_
-+
-+#include <linux/interrupt.h>
-+#include <generated/autoconf.h>
-+#include <linux/bitops.h>
-+#include <ath25_platform.h>
-+
-+/* probe link timer - 5 secs */
-+#define LINK_TIMER (5*HZ)
-+
-+#define IS_DMA_TX_INT(X) (((X) & (DMA_STATUS_TI)) != 0)
-+#define IS_DMA_RX_INT(X) (((X) & (DMA_STATUS_RI)) != 0)
-+#define IS_DRIVER_OWNED(X) (((X) & (DMA_TX_OWN)) == 0)
-+
-+#define AR2313_TX_TIMEOUT (HZ/4)
-+
-+/* Rings */
-+#define DSC_RING_ENTRIES_SIZE (AR2313_DESCR_ENTRIES * sizeof(struct desc))
-+#define DSC_NEXT(idx) ((idx + 1) & (AR2313_DESCR_ENTRIES - 1))
-+
-+#define AR2313_MBGET 2
-+#define AR2313_MBSET 3
-+#define AR2313_PCI_RECONFIG 4
-+#define AR2313_PCI_DUMP 5
-+#define AR2313_TEST_PANIC 6
-+#define AR2313_TEST_NULLPTR 7
-+#define AR2313_READ_DATA 8
-+#define AR2313_WRITE_DATA 9
-+#define AR2313_GET_VERSION 10
-+#define AR2313_TEST_HANG 11
-+#define AR2313_SYNC 12
-+
-+#define DMA_RX_ERR_CRC BIT(1)
-+#define DMA_RX_ERR_DRIB BIT(2)
-+#define DMA_RX_ERR_MII BIT(3)
-+#define DMA_RX_EV2 BIT(5)
-+#define DMA_RX_ERR_COL BIT(6)
-+#define DMA_RX_LONG BIT(7)
-+#define DMA_RX_LS BIT(8) /* last descriptor */
-+#define DMA_RX_FS BIT(9) /* first descriptor */
-+#define DMA_RX_MF BIT(10) /* multicast frame */
-+#define DMA_RX_ERR_RUNT BIT(11) /* runt frame */
-+#define DMA_RX_ERR_LENGTH BIT(12) /* length error */
-+#define DMA_RX_ERR_DESC BIT(14) /* descriptor error */
-+#define DMA_RX_ERROR BIT(15) /* error summary */
-+#define DMA_RX_LEN_MASK 0x3fff0000
-+#define DMA_RX_LEN_SHIFT 16
-+#define DMA_RX_FILT BIT(30)
-+#define DMA_RX_OWN BIT(31) /* desc owned by DMA controller */
-+
-+#define DMA_RX1_BSIZE_MASK 0x000007ff
-+#define DMA_RX1_BSIZE_SHIFT 0
-+#define DMA_RX1_CHAINED BIT(24)
-+#define DMA_RX1_RER BIT(25)
-+
-+#define DMA_TX_ERR_UNDER BIT(1) /* underflow error */
-+#define DMA_TX_ERR_DEFER BIT(2) /* excessive deferral */
-+#define DMA_TX_COL_MASK 0x78
-+#define DMA_TX_COL_SHIFT 3
-+#define DMA_TX_ERR_HB BIT(7) /* hearbeat failure */
-+#define DMA_TX_ERR_COL BIT(8) /* excessive collisions */
-+#define DMA_TX_ERR_LATE BIT(9) /* late collision */
-+#define DMA_TX_ERR_LINK BIT(10) /* no carrier */
-+#define DMA_TX_ERR_LOSS BIT(11) /* loss of carrier */
-+#define DMA_TX_ERR_JABBER BIT(14) /* transmit jabber timeout */
-+#define DMA_TX_ERROR BIT(15) /* frame aborted */
-+#define DMA_TX_OWN BIT(31) /* descr owned by DMA controller */
-+
-+#define DMA_TX1_BSIZE_MASK 0x000007ff
-+#define DMA_TX1_BSIZE_SHIFT 0
-+#define DMA_TX1_CHAINED BIT(24) /* chained descriptors */
-+#define DMA_TX1_TER BIT(25) /* transmit end of ring */
-+#define DMA_TX1_FS BIT(29) /* first segment */
-+#define DMA_TX1_LS BIT(30) /* last segment */
-+#define DMA_TX1_IC BIT(31) /* interrupt on completion */
-+
-+#define RCVPKT_LENGTH(X) (X >> 16) /* Received pkt Length */
-+
-+#define MAC_CONTROL_RE BIT(2) /* receive enable */
-+#define MAC_CONTROL_TE BIT(3) /* transmit enable */
-+#define MAC_CONTROL_DC BIT(5) /* Deferral check */
-+#define MAC_CONTROL_ASTP BIT(8) /* Auto pad strip */
-+#define MAC_CONTROL_DRTY BIT(10) /* Disable retry */
-+#define MAC_CONTROL_DBF BIT(11) /* Disable bcast frames */
-+#define MAC_CONTROL_LCC BIT(12) /* late collision ctrl */
-+#define MAC_CONTROL_HP BIT(13) /* Hash Perfect filtering */
-+#define MAC_CONTROL_HASH BIT(14) /* Unicast hash filtering */
-+#define MAC_CONTROL_HO BIT(15) /* Hash only filtering */
-+#define MAC_CONTROL_PB BIT(16) /* Pass Bad frames */
-+#define MAC_CONTROL_IF BIT(17) /* Inverse filtering */
-+#define MAC_CONTROL_PR BIT(18) /* promis mode (valid frames only) */
-+#define MAC_CONTROL_PM BIT(19) /* pass multicast */
-+#define MAC_CONTROL_F BIT(20) /* full-duplex */
-+#define MAC_CONTROL_DRO BIT(23) /* Disable Receive Own */
-+#define MAC_CONTROL_HBD BIT(28) /* heart-beat disabled (MUST BE SET) */
-+#define MAC_CONTROL_BLE BIT(30) /* big endian mode */
-+#define MAC_CONTROL_RA BIT(31) /* rcv all (valid and invalid frames) */
-+
-+#define MII_ADDR_BUSY BIT(0)
-+#define MII_ADDR_WRITE BIT(1)
-+#define MII_ADDR_REG_SHIFT 6
-+#define MII_ADDR_PHY_SHIFT 11
-+#define MII_DATA_SHIFT 0
-+
-+#define FLOW_CONTROL_FCE BIT(1)
-+
-+#define DMA_BUS_MODE_SWR BIT(0) /* software reset */
-+#define DMA_BUS_MODE_BLE BIT(7) /* big endian mode */
-+#define DMA_BUS_MODE_PBL_SHIFT 8 /* programmable burst length 32 */
-+#define DMA_BUS_MODE_DBO BIT(20) /* big-endian descriptors */
-+
-+#define DMA_STATUS_TI BIT(0) /* transmit interrupt */
-+#define DMA_STATUS_TPS BIT(1) /* transmit process stopped */
-+#define DMA_STATUS_TU BIT(2) /* transmit buffer unavailable */
-+#define DMA_STATUS_TJT BIT(3) /* transmit buffer timeout */
-+#define DMA_STATUS_UNF BIT(5) /* transmit underflow */
-+#define DMA_STATUS_RI BIT(6) /* receive interrupt */
-+#define DMA_STATUS_RU BIT(7) /* receive buffer unavailable */
-+#define DMA_STATUS_RPS BIT(8) /* receive process stopped */
-+#define DMA_STATUS_ETI BIT(10) /* early transmit interrupt */
-+#define DMA_STATUS_FBE BIT(13) /* fatal bus interrupt */
-+#define DMA_STATUS_ERI BIT(14) /* early receive interrupt */
-+#define DMA_STATUS_AIS BIT(15) /* abnormal interrupt summary */
-+#define DMA_STATUS_NIS BIT(16) /* normal interrupt summary */
-+#define DMA_STATUS_RS_SHIFT 17 /* receive process state */
-+#define DMA_STATUS_TS_SHIFT 20 /* transmit process state */
-+#define DMA_STATUS_EB_SHIFT 23 /* error bits */
-+
-+#define DMA_CONTROL_SR BIT(1) /* start receive */
-+#define DMA_CONTROL_ST BIT(13) /* start transmit */
-+#define DMA_CONTROL_SF BIT(21) /* store and forward */
-+
-+typedef struct {
-+ volatile unsigned int status; /* OWN, Device control and status. */
-+ volatile unsigned int devcs; /* pkt Control bits + Length */
-+ volatile unsigned int addr; /* Current Address. */
-+ volatile unsigned int descr; /* Next descriptor in chain. */
-+} ar231x_descr_t;
-+
-+/**
-+ * New Combo structure for Both Eth0 AND eth1
-+ *
-+ * Don't directly access MII related regs since phy chip could be actually
-+ * connected to another ethernet block.
-+ */
-+typedef struct {
-+ volatile unsigned int mac_control; /* 0x00 */
-+ volatile unsigned int mac_addr[2]; /* 0x04 - 0x08 */
-+ volatile unsigned int mcast_table[2]; /* 0x0c - 0x10 */
-+ volatile unsigned int __mii_addr; /* 0x14 */
-+ volatile unsigned int __mii_data; /* 0x18 */
-+ volatile unsigned int flow_control; /* 0x1c */
-+ volatile unsigned int vlan_tag; /* 0x20 */
-+ volatile unsigned int pad[7]; /* 0x24 - 0x3c */
-+ volatile unsigned int ucast_table[8]; /* 0x40-0x5c */
-+} ETHERNET_STRUCT;
-+
-+typedef struct {
-+ volatile unsigned int mii_addr;
-+ volatile unsigned int mii_data;
-+} MII;
-+
-+/********************************************************************
-+ * Interrupt controller
-+ ********************************************************************/
-+
-+typedef struct {
-+ volatile unsigned int wdog_control; /* 0x08 */
-+ volatile unsigned int wdog_timer; /* 0x0c */
-+ volatile unsigned int misc_status; /* 0x10 */
-+ volatile unsigned int misc_mask; /* 0x14 */
-+ volatile unsigned int global_status; /* 0x18 */
-+ volatile unsigned int reserved; /* 0x1c */
-+ volatile unsigned int reset_control; /* 0x20 */
-+} INTERRUPT;
-+
-+/********************************************************************
-+ * DMA controller
-+ ********************************************************************/
-+typedef struct {
-+ volatile unsigned int bus_mode; /* 0x00 (CSR0) */
-+ volatile unsigned int xmt_poll; /* 0x04 (CSR1) */
-+ volatile unsigned int rcv_poll; /* 0x08 (CSR2) */
-+ volatile unsigned int rcv_base; /* 0x0c (CSR3) */
-+ volatile unsigned int xmt_base; /* 0x10 (CSR4) */
-+ volatile unsigned int status; /* 0x14 (CSR5) */
-+ volatile unsigned int control; /* 0x18 (CSR6) */
-+ volatile unsigned int intr_ena; /* 0x1c (CSR7) */
-+ volatile unsigned int rcv_missed; /* 0x20 (CSR8) */
-+ volatile unsigned int reserved[11]; /* 0x24-0x4c (CSR9-19) */
-+ volatile unsigned int cur_tx_buf_addr; /* 0x50 (CSR20) */
-+ volatile unsigned int cur_rx_buf_addr; /* 0x50 (CSR21) */
-+} DMA;
-+
-+/**
-+ * Struct private for the Sibyte.
-+ *
-+ * Elements are grouped so variables used by the tx handling goes
-+ * together, and will go into the same cache lines etc. in order to
-+ * avoid cache line contention between the rx and tx handling on SMP.
-+ *
-+ * Frequently accessed variables are put at the beginning of the
-+ * struct to help the compiler generate better/shorter code.
-+ */
-+struct ar231x_private {
-+ struct net_device *dev;
-+ int version;
-+ u32 mb[2];
-+
-+ volatile MII *phy_regs;
-+ volatile ETHERNET_STRUCT *eth_regs;
-+ volatile DMA *dma_regs;
-+ struct ar231x_eth *cfg;
-+
-+ spinlock_t lock; /* Serialise access to device */
-+
-+ /* RX and TX descriptors, must be adjacent */
-+ ar231x_descr_t *rx_ring;
-+ ar231x_descr_t *tx_ring;
-+
-+ struct sk_buff **rx_skb;
-+ struct sk_buff **tx_skb;
-+
-+ /* RX elements */
-+ u32 rx_skbprd;
-+ u32 cur_rx;
-+
-+ /* TX elements */
-+ u32 tx_prd;
-+ u32 tx_csm;
-+
-+ /* Misc elements */
-+ char name[48];
-+ struct {
-+ u32 address;
-+ u32 length;
-+ char *mapping;
-+ } desc;
-+
-+ struct timer_list link_timer;
-+ unsigned short phy; /* merlot phy = 1, samsung phy = 0x1f */
-+ unsigned short mac;
-+ unsigned short link; /* 0 - link down, 1 - link up */
-+ u16 phy_data;
-+
-+ struct tasklet_struct rx_tasklet;
-+ int unloading;
-+
-+ struct phy_device *phy_dev;
-+ struct mii_bus *mii_bus;
-+ int oldduplex;
-+};
-+
-+/* Prototypes */
-+static int ar231x_init(struct net_device *dev);
-+#ifdef TX_TIMEOUT
-+static void ar231x_tx_timeout(struct net_device *dev);
-+#endif
-+static int ar231x_restart(struct net_device *dev);
-+static void ar231x_load_rx_ring(struct net_device *dev, int bufs);
-+static irqreturn_t ar231x_interrupt(int irq, void *dev_id);
-+static int ar231x_open(struct net_device *dev);
-+static int ar231x_start_xmit(struct sk_buff *skb, struct net_device *dev);
-+static int ar231x_close(struct net_device *dev);
-+static int ar231x_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
-+static void ar231x_init_cleanup(struct net_device *dev);
-+static int ar231x_setup_timer(struct net_device *dev);
-+static void ar231x_link_timer_fn(unsigned long data);
-+static void ar231x_check_link(struct net_device *dev);
-+
-+#endif /* _AR2313_H_ */
---- a/arch/mips/ath25/ar2315_regs.h
-+++ b/arch/mips/ath25/ar2315_regs.h
-@@ -57,6 +57,9 @@
- #define AR2315_PCI_EXT_BASE 0x80000000 /* PCI external */
- #define AR2315_PCI_EXT_SIZE 0x40000000
-
-+/* MII registers offset inside Ethernet MMR region */
-+#define AR2315_ENET0_MII_BASE (AR2315_ENET0_BASE + 0x14)
-+
- /*
- * Configuration registers
- */
---- a/arch/mips/ath25/ar5312_regs.h
-+++ b/arch/mips/ath25/ar5312_regs.h
-@@ -64,6 +64,10 @@
- #define AR5312_AR5312_REV7 0x0057 /* AR5312 WMAC (AP30-040) */
- #define AR5312_AR2313_REV8 0x0058 /* AR2313 WMAC (AP43-030) */
-
-+/* MII registers offset inside Ethernet MMR region */
-+#define AR5312_ENET0_MII_BASE (AR5312_ENET0_BASE + 0x14)
-+#define AR5312_ENET1_MII_BASE (AR5312_ENET1_BASE + 0x14)
-+
- /* Reset/Timer Block Address Map */
- #define AR5312_TIMER 0x0000 /* countdown timer */
- #define AR5312_RELOAD 0x0004 /* timer reload value */
---- a/arch/mips/ath25/ar2315.c
-+++ b/arch/mips/ath25/ar2315.c
-@@ -136,6 +136,8 @@ static void ar2315_irq_dispatch(void)
-
- if (pending & CAUSEF_IP3)
- do_IRQ(AR2315_IRQ_WLAN0);
-+ else if (pending & CAUSEF_IP4)
-+ do_IRQ(AR2315_IRQ_ENET0);
- #ifdef CONFIG_PCI_AR2315
- else if (pending & CAUSEF_IP5)
- do_IRQ(AR2315_IRQ_LCBUS_PCI);
-@@ -169,6 +171,29 @@ void __init ar2315_arch_init_irq(void)
- ar2315_misc_irq_domain = domain;
- }
-
-+static void ar2315_device_reset_set(u32 mask)
-+{
-+ u32 val;
-+
-+ val = ar2315_rst_reg_read(AR2315_RESET);
-+ ar2315_rst_reg_write(AR2315_RESET, val | mask);
-+}
-+
-+static void ar2315_device_reset_clear(u32 mask)
-+{
-+ u32 val;
-+
-+ val = ar2315_rst_reg_read(AR2315_RESET);
-+ ar2315_rst_reg_write(AR2315_RESET, val & ~mask);
-+}
-+
-+static struct ar231x_eth ar2315_eth_data = {
-+ .reset_set = ar2315_device_reset_set,
-+ .reset_clear = ar2315_device_reset_clear,
-+ .reset_mac = AR2315_RESET_ENET0,
-+ .reset_phy = AR2315_RESET_EPHY0,
-+};
-+
- static struct resource ar2315_gpio_res[] = {
- {
- .name = "ar2315-gpio",
-@@ -205,6 +230,11 @@ void __init ar2315_init_devices(void)
- ar2315_gpio_res[1].end = ar2315_gpio_res[1].start;
- platform_device_register(&ar2315_gpio);
-
-+ ar2315_eth_data.macaddr = ath25_board.config->enet0_mac;
-+ ath25_add_ethernet(0, AR2315_ENET0_BASE, "eth0_mii",
-+ AR2315_ENET0_MII_BASE, AR2315_IRQ_ENET0,
-+ &ar2315_eth_data);
-+
- ath25_add_wmac(0, AR2315_WLAN0_BASE, AR2315_IRQ_WLAN0);
- }
-
---- a/arch/mips/ath25/ar5312.c
-+++ b/arch/mips/ath25/ar5312.c
-@@ -132,6 +132,10 @@ static void ar5312_irq_dispatch(void)
-
- if (pending & CAUSEF_IP2)
- do_IRQ(AR5312_IRQ_WLAN0);
-+ else if (pending & CAUSEF_IP3)
-+ do_IRQ(AR5312_IRQ_ENET0);
-+ else if (pending & CAUSEF_IP4)
-+ do_IRQ(AR5312_IRQ_ENET1);
- else if (pending & CAUSEF_IP5)
- do_IRQ(AR5312_IRQ_WLAN1);
- else if (pending & CAUSEF_IP6)
-@@ -163,6 +167,36 @@ void __init ar5312_arch_init_irq(void)
- ar5312_misc_irq_domain = domain;
- }
-
-+static void ar5312_device_reset_set(u32 mask)
-+{
-+ u32 val;
-+
-+ val = ar5312_rst_reg_read(AR5312_RESET);
-+ ar5312_rst_reg_write(AR5312_RESET, val | mask);
-+}
-+
-+static void ar5312_device_reset_clear(u32 mask)
-+{
-+ u32 val;
-+
-+ val = ar5312_rst_reg_read(AR5312_RESET);
-+ ar5312_rst_reg_write(AR5312_RESET, val & ~mask);
-+}
-+
-+static struct ar231x_eth ar5312_eth0_data = {
-+ .reset_set = ar5312_device_reset_set,
-+ .reset_clear = ar5312_device_reset_clear,
-+ .reset_mac = AR5312_RESET_ENET0,
-+ .reset_phy = AR5312_RESET_EPHY0,
-+};
-+
-+static struct ar231x_eth ar5312_eth1_data = {
-+ .reset_set = ar5312_device_reset_set,
-+ .reset_clear = ar5312_device_reset_clear,
-+ .reset_mac = AR5312_RESET_ENET1,
-+ .reset_phy = AR5312_RESET_EPHY1,
-+};
-+
- static struct physmap_flash_data ar5312_flash_data = {
- .width = 2,
- };
-@@ -243,6 +277,7 @@ static void __init ar5312_flash_init(voi
- void __init ar5312_init_devices(void)
- {
- struct ath25_boarddata *config;
-+ u8 *c;
-
- ar5312_flash_init();
-
-@@ -266,8 +301,30 @@ void __init ar5312_init_devices(void)
-
- platform_device_register(&ar5312_gpio);
-
-+ /* Fix up MAC addresses if necessary */
-+ if (is_broadcast_ether_addr(config->enet0_mac))
-+ ether_addr_copy(config->enet0_mac, config->enet1_mac);
-+
-+ /* If ENET0 and ENET1 have the same mac address,
-+ * increment the one from ENET1 */
-+ if (ether_addr_equal(config->enet0_mac, config->enet1_mac)) {
-+ c = config->enet1_mac + 5;
-+ while ((c >= config->enet1_mac) && !(++(*c)))
-+ c--;
-+ }
-+
- switch (ath25_soc) {
- case ATH25_SOC_AR5312:
-+ ar5312_eth0_data.macaddr = config->enet0_mac;
-+ ath25_add_ethernet(0, AR5312_ENET0_BASE, "eth0_mii",
-+ AR5312_ENET0_MII_BASE, AR5312_IRQ_ENET0,
-+ &ar5312_eth0_data);
-+
-+ ar5312_eth1_data.macaddr = config->enet1_mac;
-+ ath25_add_ethernet(1, AR5312_ENET1_BASE, "eth1_mii",
-+ AR5312_ENET1_MII_BASE, AR5312_IRQ_ENET1,
-+ &ar5312_eth1_data);
-+
- if (!ath25_board.radio)
- return;
-
-@@ -276,8 +333,18 @@ void __init ar5312_init_devices(void)
-
- ath25_add_wmac(0, AR5312_WLAN0_BASE, AR5312_IRQ_WLAN0);
- break;
-+ /*
-+ * AR2312/3 ethernet uses the PHY of ENET0, but the MAC
-+ * of ENET1. Atheros calls it 'twisted' for a reason :)
-+ */
- case ATH25_SOC_AR2312:
- case ATH25_SOC_AR2313:
-+ ar5312_eth1_data.reset_phy = ar5312_eth0_data.reset_phy;
-+ ar5312_eth1_data.macaddr = config->enet0_mac;
-+ ath25_add_ethernet(1, AR5312_ENET1_BASE, "eth0_mii",
-+ AR5312_ENET0_MII_BASE, AR5312_IRQ_ENET1,
-+ &ar5312_eth1_data);
-+
- if (!ath25_board.radio)
- return;
- break;
---- a/arch/mips/ath25/devices.h
-+++ b/arch/mips/ath25/devices.h
-@@ -32,6 +32,8 @@ extern struct ar231x_board_config ath25_
- extern void (*ath25_irq_dispatch)(void);
-
- int ath25_find_config(phys_addr_t offset, unsigned long size);
-+int ath25_add_ethernet(int nr, u32 base, const char *mii_name, u32 mii_base,
-+ int irq, void *pdata);
- void ath25_serial_setup(u32 mapbase, int irq, unsigned int uartclk);
- int ath25_add_wmac(int nr, u32 base, int irq);
-
---- a/arch/mips/ath25/devices.c
-+++ b/arch/mips/ath25/devices.c
-@@ -12,6 +12,51 @@
- struct ar231x_board_config ath25_board;
- enum ath25_soc_type ath25_soc = ATH25_SOC_UNKNOWN;
-
-+static struct resource ath25_eth0_res[] = {
-+ {
-+ .name = "eth0_membase",
-+ .flags = IORESOURCE_MEM,
-+ },
-+ {
-+ .name = "eth0_mii",
-+ .flags = IORESOURCE_MEM,
-+ },
-+ {
-+ .name = "eth0_irq",
-+ .flags = IORESOURCE_IRQ,
-+ }
-+};
-+
-+static struct resource ath25_eth1_res[] = {
-+ {
-+ .name = "eth1_membase",
-+ .flags = IORESOURCE_MEM,
-+ },
-+ {
-+ .name = "eth1_mii",
-+ .flags = IORESOURCE_MEM,
-+ },
-+ {
-+ .name = "eth1_irq",
-+ .flags = IORESOURCE_IRQ,
-+ }
-+};
-+
-+static struct platform_device ath25_eth[] = {
-+ {
-+ .id = 0,
-+ .name = "ar231x-eth",
-+ .resource = ath25_eth0_res,
-+ .num_resources = ARRAY_SIZE(ath25_eth0_res)
-+ },
-+ {
-+ .id = 1,
-+ .name = "ar231x-eth",
-+ .resource = ath25_eth1_res,
-+ .num_resources = ARRAY_SIZE(ath25_eth1_res)
-+ }
-+};
-+
- static struct resource ath25_wmac0_res[] = {
- {
- .name = "wmac0_membase",
-@@ -70,6 +115,25 @@ const char *get_system_type(void)
- return soc_type_strings[ath25_soc];
- }
-
-+int __init ath25_add_ethernet(int nr, u32 base, const char *mii_name,
-+ u32 mii_base, int irq, void *pdata)
-+{
-+ struct resource *res;
-+
-+ ath25_eth[nr].dev.platform_data = pdata;
-+ res = &ath25_eth[nr].resource[0];
-+ res->start = base;
-+ res->end = base + 0x2000 - 1;
-+ res++;
-+ res->name = mii_name;
-+ res->start = mii_base;
-+ res->end = mii_base + 8 - 1;
-+ res++;
-+ res->start = irq;
-+ res->end = irq;
-+ return platform_device_register(&ath25_eth[nr]);
-+}
-+
- void __init ath25_serial_setup(u32 mapbase, int irq, unsigned int uartclk)
- {
- struct uart_port s;
---- a/arch/mips/include/asm/mach-ath25/ath25_platform.h
-+++ b/arch/mips/include/asm/mach-ath25/ath25_platform.h
-@@ -70,4 +70,15 @@ struct ar231x_board_config {
- const char *radio;
- };
-
-+/*
-+ * Platform device information for the Ethernet MAC
-+ */
-+struct ar231x_eth {
-+ void (*reset_set)(u32);
-+ void (*reset_clear)(u32);
-+ u32 reset_mac;
-+ u32 reset_phy;
-+ char *macaddr;
-+};
-+
- #endif /* __ASM_MACH_ATH25_PLATFORM_H */
diff --git a/target/linux/ath25/patches-3.18/120-spiflash.patch b/target/linux/ath25/patches-3.18/120-spiflash.patch
deleted file mode 100644
index 4774c27234..0000000000
--- a/target/linux/ath25/patches-3.18/120-spiflash.patch
+++ /dev/null
@@ -1,634 +0,0 @@
---- a/drivers/mtd/devices/Kconfig
-+++ b/drivers/mtd/devices/Kconfig
-@@ -120,6 +120,10 @@ config MTD_BCM47XXSFLASH
- registered by bcma as platform devices. This enables driver for
- serial flash memories (only read-only mode is implemented).
-
-+config MTD_AR2315
-+ tristate "Atheros AR2315+ SPI Flash support"
-+ depends on SOC_AR2315
-+
- config MTD_SLRAM
- tristate "Uncached system RAM"
- help
---- a/drivers/mtd/devices/Makefile
-+++ b/drivers/mtd/devices/Makefile
-@@ -14,6 +14,7 @@ obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataf
- obj-$(CONFIG_MTD_M25P80) += m25p80.o
- obj-$(CONFIG_MTD_SPEAR_SMI) += spear_smi.o
- obj-$(CONFIG_MTD_SST25L) += sst25l.o
-+obj-$(CONFIG_MTD_AR2315) += ar2315.o
- obj-$(CONFIG_MTD_BCM47XXSFLASH) += bcm47xxsflash.o
- obj-$(CONFIG_MTD_ST_SPI_FSM) += st_spi_fsm.o
-
---- /dev/null
-+++ b/drivers/mtd/devices/ar2315.c
-@@ -0,0 +1,459 @@
-+
-+/*
-+ * MTD driver for the SPI Flash Memory support on Atheros AR2315
-+ *
-+ * Copyright (c) 2005-2006 Atheros Communications Inc.
-+ * Copyright (C) 2006-2007 FON Technology, SL.
-+ * Copyright (C) 2006-2007 Imre Kaloz <kaloz@openwrt.org>
-+ * Copyright (C) 2006-2009 Felix Fietkau <nbd@nbd.name>
-+ * Copyright (C) 2012 Alexandros C. Couloumbis <alex@ozo.com>
-+ *
-+ * This code is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/errno.h>
-+#include <linux/slab.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/platform_device.h>
-+#include <linux/sched.h>
-+#include <linux/delay.h>
-+#include <linux/io.h>
-+#include <linux/mutex.h>
-+
-+#include "ar2315_spiflash.h"
-+
-+#define DRIVER_NAME "ar2315-spiflash"
-+
-+#define busy_wait(_priv, _condition, _wait) do { \
-+ while (_condition) { \
-+ if (_wait > 1) \
-+ msleep(_wait); \
-+ else if ((_wait == 1) && need_resched()) \
-+ schedule(); \
-+ else \
-+ udelay(1); \
-+ } \
-+} while (0)
-+
-+enum {
-+ FLASH_NONE,
-+ FLASH_1MB,
-+ FLASH_2MB,
-+ FLASH_4MB,
-+ FLASH_8MB,
-+ FLASH_16MB,
-+};
-+
-+/* Flash configuration table */
-+struct flashconfig {
-+ u32 byte_cnt;
-+ u32 sector_cnt;
-+ u32 sector_size;
-+};
-+
-+static const struct flashconfig flashconfig_tbl[] = {
-+ [FLASH_NONE] = { 0, 0, 0},
-+ [FLASH_1MB] = { STM_1MB_BYTE_COUNT, STM_1MB_SECTOR_COUNT,
-+ STM_1MB_SECTOR_SIZE},
-+ [FLASH_2MB] = { STM_2MB_BYTE_COUNT, STM_2MB_SECTOR_COUNT,
-+ STM_2MB_SECTOR_SIZE},
-+ [FLASH_4MB] = { STM_4MB_BYTE_COUNT, STM_4MB_SECTOR_COUNT,
-+ STM_4MB_SECTOR_SIZE},
-+ [FLASH_8MB] = { STM_8MB_BYTE_COUNT, STM_8MB_SECTOR_COUNT,
-+ STM_8MB_SECTOR_SIZE},
-+ [FLASH_16MB] = { STM_16MB_BYTE_COUNT, STM_16MB_SECTOR_COUNT,
-+ STM_16MB_SECTOR_SIZE}
-+};
-+
-+/* Mapping of generic opcodes to STM serial flash opcodes */
-+enum {
-+ SPI_WRITE_ENABLE,
-+ SPI_WRITE_DISABLE,
-+ SPI_RD_STATUS,
-+ SPI_WR_STATUS,
-+ SPI_RD_DATA,
-+ SPI_FAST_RD_DATA,
-+ SPI_PAGE_PROGRAM,
-+ SPI_SECTOR_ERASE,
-+ SPI_BULK_ERASE,
-+ SPI_DEEP_PWRDOWN,
-+ SPI_RD_SIG,
-+};
-+
-+struct opcodes {
-+ __u16 code;
-+ __s8 tx_cnt;
-+ __s8 rx_cnt;
-+};
-+
-+static const struct opcodes stm_opcodes[] = {
-+ [SPI_WRITE_ENABLE] = {STM_OP_WR_ENABLE, 1, 0},
-+ [SPI_WRITE_DISABLE] = {STM_OP_WR_DISABLE, 1, 0},
-+ [SPI_RD_STATUS] = {STM_OP_RD_STATUS, 1, 1},
-+ [SPI_WR_STATUS] = {STM_OP_WR_STATUS, 1, 0},
-+ [SPI_RD_DATA] = {STM_OP_RD_DATA, 4, 4},
-+ [SPI_FAST_RD_DATA] = {STM_OP_FAST_RD_DATA, 5, 0},
-+ [SPI_PAGE_PROGRAM] = {STM_OP_PAGE_PGRM, 8, 0},
-+ [SPI_SECTOR_ERASE] = {STM_OP_SECTOR_ERASE, 4, 0},
-+ [SPI_BULK_ERASE] = {STM_OP_BULK_ERASE, 1, 0},
-+ [SPI_DEEP_PWRDOWN] = {STM_OP_DEEP_PWRDOWN, 1, 0},
-+ [SPI_RD_SIG] = {STM_OP_RD_SIG, 4, 1},
-+};
-+
-+/* Driver private data structure */
-+struct spiflash_priv {
-+ struct mtd_info mtd;
-+ void __iomem *readaddr; /* memory mapped data for read */
-+ void __iomem *mmraddr; /* memory mapped register space */
-+ struct mutex lock; /* serialize registers access */
-+};
-+
-+#define to_spiflash(_mtd) container_of(_mtd, struct spiflash_priv, mtd)
-+
-+enum {
-+ FL_READY,
-+ FL_READING,
-+ FL_ERASING,
-+ FL_WRITING
-+};
-+
-+/*****************************************************************************/
-+
-+static u32
-+spiflash_read_reg(struct spiflash_priv *priv, int reg)
-+{
-+ return ioread32(priv->mmraddr + reg);
-+}
-+
-+static void
-+spiflash_write_reg(struct spiflash_priv *priv, int reg, u32 data)
-+{
-+ iowrite32(data, priv->mmraddr + reg);
-+}
-+
-+static u32
-+spiflash_wait_busy(struct spiflash_priv *priv)
-+{
-+ u32 reg;
-+
-+ busy_wait(priv, (reg = spiflash_read_reg(priv, SPI_FLASH_CTL)) &
-+ SPI_CTL_BUSY, 0);
-+ return reg;
-+}
-+
-+static u32
-+spiflash_sendcmd(struct spiflash_priv *priv, int opcode, u32 addr)
-+{
-+ const struct opcodes *op;
-+ u32 reg, mask;
-+
-+ op = &stm_opcodes[opcode];
-+ reg = spiflash_wait_busy(priv);
-+ spiflash_write_reg(priv, SPI_FLASH_OPCODE,
-+ ((u32)op->code) | (addr << 8));
-+
-+ reg &= ~SPI_CTL_TX_RX_CNT_MASK;
-+ reg |= SPI_CTL_START | op->tx_cnt | (op->rx_cnt << 4);
-+
-+ spiflash_write_reg(priv, SPI_FLASH_CTL, reg);
-+ spiflash_wait_busy(priv);
-+
-+ if (!op->rx_cnt)
-+ return 0;
-+
-+ reg = spiflash_read_reg(priv, SPI_FLASH_DATA);
-+
-+ switch (op->rx_cnt) {
-+ case 1:
-+ mask = 0x000000ff;
-+ break;
-+ case 2:
-+ mask = 0x0000ffff;
-+ break;
-+ case 3:
-+ mask = 0x00ffffff;
-+ break;
-+ default:
-+ mask = 0xffffffff;
-+ break;
-+ }
-+ reg &= mask;
-+
-+ return reg;
-+}
-+
-+/*
-+ * Probe SPI flash device
-+ * Function returns 0 for failure.
-+ * and flashconfig_tbl array index for success.
-+ */
-+static int
-+spiflash_probe_chip(struct platform_device *pdev, struct spiflash_priv *priv)
-+{
-+ u32 sig = spiflash_sendcmd(priv, SPI_RD_SIG, 0);
-+ int flash_size;
-+
-+ switch (sig) {
-+ case STM_8MBIT_SIGNATURE:
-+ flash_size = FLASH_1MB;
-+ break;
-+ case STM_16MBIT_SIGNATURE:
-+ flash_size = FLASH_2MB;
-+ break;
-+ case STM_32MBIT_SIGNATURE:
-+ flash_size = FLASH_4MB;
-+ break;
-+ case STM_64MBIT_SIGNATURE:
-+ flash_size = FLASH_8MB;
-+ break;
-+ case STM_128MBIT_SIGNATURE:
-+ flash_size = FLASH_16MB;
-+ break;
-+ default:
-+ dev_warn(&pdev->dev, "read of flash device signature failed!\n");
-+ return 0;
-+ }
-+
-+ return flash_size;
-+}
-+
-+static void
-+spiflash_wait_complete(struct spiflash_priv *priv, unsigned int timeout)
-+{
-+ busy_wait(priv, spiflash_sendcmd(priv, SPI_RD_STATUS, 0) &
-+ SPI_STATUS_WIP, timeout);
-+}
-+
-+static int
-+spiflash_erase(struct mtd_info *mtd, struct erase_info *instr)
-+{
-+ struct spiflash_priv *priv = to_spiflash(mtd);
-+ const struct opcodes *op;
-+ u32 temp, reg;
-+
-+ if (instr->addr + instr->len > mtd->size)
-+ return -EINVAL;
-+
-+ mutex_lock(&priv->lock);
-+
-+ spiflash_sendcmd(priv, SPI_WRITE_ENABLE, 0);
-+ reg = spiflash_wait_busy(priv);
-+
-+ op = &stm_opcodes[SPI_SECTOR_ERASE];
-+ temp = ((u32)instr->addr << 8) | (u32)(op->code);
-+ spiflash_write_reg(priv, SPI_FLASH_OPCODE, temp);
-+
-+ reg &= ~SPI_CTL_TX_RX_CNT_MASK;
-+ reg |= op->tx_cnt | SPI_CTL_START;
-+ spiflash_write_reg(priv, SPI_FLASH_CTL, reg);
-+
-+ spiflash_wait_complete(priv, 20);
-+
-+ mutex_unlock(&priv->lock);
-+
-+ instr->state = MTD_ERASE_DONE;
-+ mtd_erase_callback(instr);
-+
-+ return 0;
-+}
-+
-+static int
-+spiflash_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
-+ u_char *buf)
-+{
-+ struct spiflash_priv *priv = to_spiflash(mtd);
-+
-+ if (!len)
-+ return 0;
-+
-+ if (from + len > mtd->size)
-+ return -EINVAL;
-+
-+ *retlen = len;
-+
-+ mutex_lock(&priv->lock);
-+
-+ memcpy_fromio(buf, priv->readaddr + from, len);
-+
-+ mutex_unlock(&priv->lock);
-+
-+ return 0;
-+}
-+
-+static int
-+spiflash_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
-+ const u8 *buf)
-+{
-+ struct spiflash_priv *priv = to_spiflash(mtd);
-+ u32 opcode, bytes_left;
-+
-+ *retlen = 0;
-+
-+ if (!len)
-+ return 0;
-+
-+ if (to + len > mtd->size)
-+ return -EINVAL;
-+
-+ bytes_left = len;
-+
-+ do {
-+ u32 read_len, reg, page_offset, spi_data = 0;
-+
-+ read_len = min(bytes_left, sizeof(u32));
-+
-+ /* 32-bit writes cannot span across a page boundary
-+ * (256 bytes). This types of writes require two page
-+ * program operations to handle it correctly. The STM part
-+ * will write the overflow data to the beginning of the
-+ * current page as opposed to the subsequent page.
-+ */
-+ page_offset = (to & (STM_PAGE_SIZE - 1)) + read_len;
-+
-+ if (page_offset > STM_PAGE_SIZE)
-+ read_len -= (page_offset - STM_PAGE_SIZE);
-+
-+ mutex_lock(&priv->lock);
-+
-+ spiflash_sendcmd(priv, SPI_WRITE_ENABLE, 0);
-+ spi_data = 0;
-+ switch (read_len) {
-+ case 4:
-+ spi_data |= buf[3] << 24;
-+ /* fall through */
-+ case 3:
-+ spi_data |= buf[2] << 16;
-+ /* fall through */
-+ case 2:
-+ spi_data |= buf[1] << 8;
-+ /* fall through */
-+ case 1:
-+ spi_data |= buf[0] & 0xff;
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ spiflash_write_reg(priv, SPI_FLASH_DATA, spi_data);
-+ opcode = stm_opcodes[SPI_PAGE_PROGRAM].code |
-+ (to & 0x00ffffff) << 8;
-+ spiflash_write_reg(priv, SPI_FLASH_OPCODE, opcode);
-+
-+ reg = spiflash_read_reg(priv, SPI_FLASH_CTL);
-+ reg &= ~SPI_CTL_TX_RX_CNT_MASK;
-+ reg |= (read_len + 4) | SPI_CTL_START;
-+ spiflash_write_reg(priv, SPI_FLASH_CTL, reg);
-+
-+ spiflash_wait_complete(priv, 1);
-+
-+ mutex_unlock(&priv->lock);
-+
-+ bytes_left -= read_len;
-+ to += read_len;
-+ buf += read_len;
-+
-+ *retlen += read_len;
-+ } while (bytes_left != 0);
-+
-+ return 0;
-+}
-+
-+#if defined CONFIG_MTD_REDBOOT_PARTS || CONFIG_MTD_MYLOADER_PARTS
-+static const char * const part_probe_types[] = {
-+ "cmdlinepart", "RedBoot", "MyLoader", NULL
-+};
-+#endif
-+
-+static int
-+spiflash_probe(struct platform_device *pdev)
-+{
-+ struct spiflash_priv *priv;
-+ struct mtd_info *mtd;
-+ struct resource *res;
-+ int index;
-+ int result = 0;
-+
-+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
-+ if (!priv)
-+ return -ENOMEM;
-+
-+ mutex_init(&priv->lock);
-+ mtd = &priv->mtd;
-+
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-+ priv->mmraddr = devm_ioremap_resource(&pdev->dev, res);
-+ if (IS_ERR(priv->mmraddr)) {
-+ dev_warn(&pdev->dev, "failed to map flash MMR\n");
-+ return PTR_ERR(priv->mmraddr);
-+ }
-+
-+ index = spiflash_probe_chip(pdev, priv);
-+ if (!index) {
-+ dev_warn(&pdev->dev, "found no flash device\n");
-+ return -ENODEV;
-+ }
-+
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ priv->readaddr = devm_ioremap_resource(&pdev->dev, res);
-+ if (IS_ERR(priv->readaddr)) {
-+ dev_warn(&pdev->dev, "failed to map flash read mem\n");
-+ return PTR_ERR(priv->readaddr);
-+ }
-+
-+ platform_set_drvdata(pdev, priv);
-+ mtd->name = "spiflash";
-+ mtd->type = MTD_NORFLASH;
-+ mtd->flags = (MTD_CAP_NORFLASH|MTD_WRITEABLE);
-+ mtd->size = flashconfig_tbl[index].byte_cnt;
-+ mtd->erasesize = flashconfig_tbl[index].sector_size;
-+ mtd->writesize = 1;
-+ mtd->numeraseregions = 0;
-+ mtd->eraseregions = NULL;
-+ mtd->_erase = spiflash_erase;
-+ mtd->_read = spiflash_read;
-+ mtd->_write = spiflash_write;
-+ mtd->owner = THIS_MODULE;
-+
-+ dev_info(&pdev->dev, "%lld Kbytes flash detected\n", mtd->size >> 10);
-+
-+#if defined CONFIG_MTD_REDBOOT_PARTS || CONFIG_MTD_MYLOADER_PARTS
-+ /* parse redboot partitions */
-+
-+ result = mtd_device_parse_register(mtd, part_probe_types,
-+ NULL, NULL, 0);
-+#endif
-+
-+ return result;
-+}
-+
-+static int
-+spiflash_remove(struct platform_device *pdev)
-+{
-+ struct spiflash_priv *priv = platform_get_drvdata(pdev);
-+
-+ mtd_device_unregister(&priv->mtd);
-+
-+ return 0;
-+}
-+
-+static struct platform_driver spiflash_driver = {
-+ .driver.name = DRIVER_NAME,
-+ .probe = spiflash_probe,
-+ .remove = spiflash_remove,
-+};
-+
-+module_platform_driver(spiflash_driver);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("OpenWrt.org");
-+MODULE_AUTHOR("Atheros Communications Inc");
-+MODULE_DESCRIPTION("MTD driver for SPI Flash on Atheros AR2315+ SOC");
-+MODULE_ALIAS("platform:" DRIVER_NAME);
-+
---- /dev/null
-+++ b/drivers/mtd/devices/ar2315_spiflash.h
-@@ -0,0 +1,106 @@
-+/*
-+ * Atheros AR2315 SPI Flash Memory support header file.
-+ *
-+ * Copyright (c) 2005, Atheros Communications Inc.
-+ * Copyright (C) 2006 FON Technology, SL.
-+ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
-+ * Copyright (C) 2006-2009 Felix Fietkau <nbd@nbd.name>
-+ *
-+ * This code is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ */
-+#ifndef __AR2315_SPIFLASH_H
-+#define __AR2315_SPIFLASH_H
-+
-+#define STM_PAGE_SIZE 256
-+
-+#define SFI_WRITE_BUFFER_SIZE 4
-+#define SFI_FLASH_ADDR_MASK 0x00ffffff
-+
-+#define STM_8MBIT_SIGNATURE 0x13
-+#define STM_M25P80_BYTE_COUNT 1048576
-+#define STM_M25P80_SECTOR_COUNT 16
-+#define STM_M25P80_SECTOR_SIZE 0x10000
-+
-+#define STM_16MBIT_SIGNATURE 0x14
-+#define STM_M25P16_BYTE_COUNT 2097152
-+#define STM_M25P16_SECTOR_COUNT 32
-+#define STM_M25P16_SECTOR_SIZE 0x10000
-+
-+#define STM_32MBIT_SIGNATURE 0x15
-+#define STM_M25P32_BYTE_COUNT 4194304
-+#define STM_M25P32_SECTOR_COUNT 64
-+#define STM_M25P32_SECTOR_SIZE 0x10000
-+
-+#define STM_64MBIT_SIGNATURE 0x16
-+#define STM_M25P64_BYTE_COUNT 8388608
-+#define STM_M25P64_SECTOR_COUNT 128
-+#define STM_M25P64_SECTOR_SIZE 0x10000
-+
-+#define STM_128MBIT_SIGNATURE 0x17
-+#define STM_M25P128_BYTE_COUNT 16777216
-+#define STM_M25P128_SECTOR_COUNT 256
-+#define STM_M25P128_SECTOR_SIZE 0x10000
-+
-+#define STM_1MB_BYTE_COUNT STM_M25P80_BYTE_COUNT
-+#define STM_1MB_SECTOR_COUNT STM_M25P80_SECTOR_COUNT
-+#define STM_1MB_SECTOR_SIZE STM_M25P80_SECTOR_SIZE
-+#define STM_2MB_BYTE_COUNT STM_M25P16_BYTE_COUNT
-+#define STM_2MB_SECTOR_COUNT STM_M25P16_SECTOR_COUNT
-+#define STM_2MB_SECTOR_SIZE STM_M25P16_SECTOR_SIZE
-+#define STM_4MB_BYTE_COUNT STM_M25P32_BYTE_COUNT
-+#define STM_4MB_SECTOR_COUNT STM_M25P32_SECTOR_COUNT
-+#define STM_4MB_SECTOR_SIZE STM_M25P32_SECTOR_SIZE
-+#define STM_8MB_BYTE_COUNT STM_M25P64_BYTE_COUNT
-+#define STM_8MB_SECTOR_COUNT STM_M25P64_SECTOR_COUNT
-+#define STM_8MB_SECTOR_SIZE STM_M25P64_SECTOR_SIZE
-+#define STM_16MB_BYTE_COUNT STM_M25P128_BYTE_COUNT
-+#define STM_16MB_SECTOR_COUNT STM_M25P128_SECTOR_COUNT
-+#define STM_16MB_SECTOR_SIZE STM_M25P128_SECTOR_SIZE
-+
-+/*
-+ * ST Microelectronics Opcodes for Serial Flash
-+ */
-+
-+#define STM_OP_WR_ENABLE 0x06 /* Write Enable */
-+#define STM_OP_WR_DISABLE 0x04 /* Write Disable */
-+#define STM_OP_RD_STATUS 0x05 /* Read Status */
-+#define STM_OP_WR_STATUS 0x01 /* Write Status */
-+#define STM_OP_RD_DATA 0x03 /* Read Data */
-+#define STM_OP_FAST_RD_DATA 0x0b /* Fast Read Data */
-+#define STM_OP_PAGE_PGRM 0x02 /* Page Program */
-+#define STM_OP_SECTOR_ERASE 0xd8 /* Sector Erase */
-+#define STM_OP_BULK_ERASE 0xc7 /* Bulk Erase */
-+#define STM_OP_DEEP_PWRDOWN 0xb9 /* Deep Power-Down Mode */
-+#define STM_OP_RD_SIG 0xab /* Read Electronic Signature */
-+
-+#define STM_STATUS_WIP 0x01 /* Write-In-Progress */
-+#define STM_STATUS_WEL 0x02 /* Write Enable Latch */
-+#define STM_STATUS_BP0 0x04 /* Block Protect 0 */
-+#define STM_STATUS_BP1 0x08 /* Block Protect 1 */
-+#define STM_STATUS_BP2 0x10 /* Block Protect 2 */
-+#define STM_STATUS_SRWD 0x80 /* Status Register Write Disable */
-+
-+/*
-+ * SPI Flash Interface Registers
-+ */
-+
-+#define SPI_FLASH_CTL 0x00
-+#define SPI_FLASH_OPCODE 0x04
-+#define SPI_FLASH_DATA 0x08
-+
-+#define SPI_CTL_START 0x00000100
-+#define SPI_CTL_BUSY 0x00010000
-+#define SPI_CTL_TXCNT_MASK 0x0000000f
-+#define SPI_CTL_RXCNT_MASK 0x000000f0
-+#define SPI_CTL_TX_RX_CNT_MASK 0x000000ff
-+#define SPI_CTL_SIZE_MASK 0x00060000
-+
-+#define SPI_CTL_CLK_SEL_MASK 0x03000000
-+#define SPI_OPCODE_MASK 0x000000ff
-+
-+#define SPI_STATUS_WIP STM_STATUS_WIP
-+
-+#endif
---- a/arch/mips/ath25/ar2315.c
-+++ b/arch/mips/ath25/ar2315.c
-@@ -220,6 +220,28 @@ static struct platform_device ar2315_gpi
- .num_resources = ARRAY_SIZE(ar2315_gpio_res)
- };
-
-+static struct resource ar2315_spiflash_res[] = {
-+ {
-+ .name = "spiflash_read",
-+ .flags = IORESOURCE_MEM,
-+ .start = AR2315_SPI_READ_BASE,
-+ .end = AR2315_SPI_READ_BASE + AR2315_SPI_READ_SIZE - 1,
-+ },
-+ {
-+ .name = "spiflash_mmr",
-+ .flags = IORESOURCE_MEM,
-+ .start = AR2315_SPI_MMR_BASE,
-+ .end = AR2315_SPI_MMR_BASE + AR2315_SPI_MMR_SIZE - 1,
-+ },
-+};
-+
-+static struct platform_device ar2315_spiflash = {
-+ .id = 0,
-+ .name = "ar2315-spiflash",
-+ .resource = ar2315_spiflash_res,
-+ .num_resources = ARRAY_SIZE(ar2315_spiflash_res)
-+};
-+
- void __init ar2315_init_devices(void)
- {
- /* Find board configuration */
-@@ -230,6 +252,8 @@ void __init ar2315_init_devices(void)
- ar2315_gpio_res[1].end = ar2315_gpio_res[1].start;
- platform_device_register(&ar2315_gpio);
-
-+ platform_device_register(&ar2315_spiflash);
-+
- ar2315_eth_data.macaddr = ath25_board.config->enet0_mac;
- ath25_add_ethernet(0, AR2315_ENET0_BASE, "eth0_mii",
- AR2315_ENET0_MII_BASE, AR2315_IRQ_ENET0,
diff --git a/target/linux/ath25/patches-3.18/130-watchdog.patch b/target/linux/ath25/patches-3.18/130-watchdog.patch
deleted file mode 100644
index 255064a8f2..0000000000
--- a/target/linux/ath25/patches-3.18/130-watchdog.patch
+++ /dev/null
@@ -1,277 +0,0 @@
---- /dev/null
-+++ b/drivers/watchdog/ar2315-wtd.c
-@@ -0,0 +1,209 @@
-+/*
-+ * 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, see <http://www.gnu.org/licenses/>.
-+ *
-+ * Copyright (C) 2008 John Crispin <blogic@openwrt.org>
-+ * Based on EP93xx and ifxmips wdt driver
-+ */
-+
-+#include <linux/interrupt.h>
-+#include <linux/module.h>
-+#include <linux/moduleparam.h>
-+#include <linux/types.h>
-+#include <linux/miscdevice.h>
-+#include <linux/watchdog.h>
-+#include <linux/fs.h>
-+#include <linux/ioport.h>
-+#include <linux/notifier.h>
-+#include <linux/reboot.h>
-+#include <linux/init.h>
-+#include <linux/platform_device.h>
-+#include <linux/io.h>
-+#include <linux/uaccess.h>
-+
-+#define DRIVER_NAME "ar2315-wdt"
-+
-+#define CLOCK_RATE 40000000
-+#define HEARTBEAT(x) (x < 1 || x > 90 ? 20 : x)
-+
-+#define WDT_REG_TIMER 0x00
-+#define WDT_REG_CTRL 0x04
-+
-+#define WDT_CTRL_ACT_NONE 0x00000000 /* No action */
-+#define WDT_CTRL_ACT_NMI 0x00000001 /* NMI on watchdog */
-+#define WDT_CTRL_ACT_RESET 0x00000002 /* reset on watchdog */
-+
-+static int wdt_timeout = 20;
-+static int started;
-+static int in_use;
-+static void __iomem *wdt_base;
-+
-+static inline void ar2315_wdt_wr(unsigned reg, u32 val)
-+{
-+ iowrite32(val, wdt_base + reg);
-+}
-+
-+static void
-+ar2315_wdt_enable(void)
-+{
-+ ar2315_wdt_wr(WDT_REG_TIMER, wdt_timeout * CLOCK_RATE);
-+}
-+
-+static ssize_t
-+ar2315_wdt_write(struct file *file, const char __user *data, size_t len,
-+ loff_t *ppos)
-+{
-+ if (len)
-+ ar2315_wdt_enable();
-+ return len;
-+}
-+
-+static int
-+ar2315_wdt_open(struct inode *inode, struct file *file)
-+{
-+ if (in_use)
-+ return -EBUSY;
-+ ar2315_wdt_enable();
-+ in_use = 1;
-+ started = 1;
-+ return nonseekable_open(inode, file);
-+}
-+
-+static int
-+ar2315_wdt_release(struct inode *inode, struct file *file)
-+{
-+ in_use = 0;
-+ return 0;
-+}
-+
-+static irqreturn_t
-+ar2315_wdt_interrupt(int irq, void *dev)
-+{
-+ struct platform_device *pdev = (struct platform_device *)dev;
-+
-+ if (started) {
-+ dev_crit(&pdev->dev, "watchdog expired, rebooting system\n");
-+ emergency_restart();
-+ } else {
-+ ar2315_wdt_wr(WDT_REG_CTRL, 0);
-+ ar2315_wdt_wr(WDT_REG_TIMER, 0);
-+ }
-+ return IRQ_HANDLED;
-+}
-+
-+static struct watchdog_info ident = {
-+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
-+ .identity = "ar2315 Watchdog",
-+};
-+
-+static long
-+ar2315_wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-+{
-+ int new_wdt_timeout;
-+ int ret = -ENOIOCTLCMD;
-+
-+ switch (cmd) {
-+ case WDIOC_GETSUPPORT:
-+ ret = copy_to_user((void __user *)arg, &ident, sizeof(ident)) ?
-+ -EFAULT : 0;
-+ break;
-+ case WDIOC_KEEPALIVE:
-+ ar2315_wdt_enable();
-+ ret = 0;
-+ break;
-+ case WDIOC_SETTIMEOUT:
-+ ret = get_user(new_wdt_timeout, (int __user *)arg);
-+ if (ret)
-+ break;
-+ wdt_timeout = HEARTBEAT(new_wdt_timeout);
-+ ar2315_wdt_enable();
-+ break;
-+ case WDIOC_GETTIMEOUT:
-+ ret = put_user(wdt_timeout, (int __user *)arg);
-+ break;
-+ }
-+ return ret;
-+}
-+
-+static const struct file_operations ar2315_wdt_fops = {
-+ .owner = THIS_MODULE,
-+ .llseek = no_llseek,
-+ .write = ar2315_wdt_write,
-+ .unlocked_ioctl = ar2315_wdt_ioctl,
-+ .open = ar2315_wdt_open,
-+ .release = ar2315_wdt_release,
-+};
-+
-+static struct miscdevice ar2315_wdt_miscdev = {
-+ .minor = WATCHDOG_MINOR,
-+ .name = "watchdog",
-+ .fops = &ar2315_wdt_fops,
-+};
-+
-+static int
-+ar2315_wdt_probe(struct platform_device *dev)
-+{
-+ struct resource *mem_res, *irq_res;
-+ int ret = 0;
-+
-+ if (wdt_base)
-+ return -EBUSY;
-+
-+ irq_res = platform_get_resource(dev, IORESOURCE_IRQ, 0);
-+ if (!irq_res) {
-+ dev_err(&dev->dev, "no IRQ resource\n");
-+ return -ENOENT;
-+ }
-+
-+ mem_res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-+ wdt_base = devm_ioremap_resource(&dev->dev, mem_res);
-+ if (IS_ERR(wdt_base))
-+ return PTR_ERR(wdt_base);
-+
-+ ret = devm_request_irq(&dev->dev, irq_res->start, ar2315_wdt_interrupt,
-+ IRQF_DISABLED, DRIVER_NAME, dev);
-+ if (ret) {
-+ dev_err(&dev->dev, "failed to register inetrrupt\n");
-+ goto out;
-+ }
-+
-+ ret = misc_register(&ar2315_wdt_miscdev);
-+ if (ret)
-+ dev_err(&dev->dev, "failed to register miscdev\n");
-+
-+out:
-+ return ret;
-+}
-+
-+static int
-+ar2315_wdt_remove(struct platform_device *dev)
-+{
-+ misc_deregister(&ar2315_wdt_miscdev);
-+ return 0;
-+}
-+
-+static struct platform_driver ar2315_wdt_driver = {
-+ .probe = ar2315_wdt_probe,
-+ .remove = ar2315_wdt_remove,
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+module_platform_driver(ar2315_wdt_driver);
-+
-+MODULE_DESCRIPTION("Atheros AR2315 hardware watchdog driver");
-+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
-+MODULE_LICENSE("GPL");
-+MODULE_ALIAS("platform:" DRIVER_NAME);
---- a/drivers/watchdog/Kconfig
-+++ b/drivers/watchdog/Kconfig
-@@ -1257,6 +1257,13 @@ config RALINK_WDT
- help
- Hardware driver for the Ralink SoC Watchdog Timer.
-
-+config AR2315_WDT
-+ tristate "Atheros AR2315+ WiSoCs Watchdog Timer"
-+ depends on ATH25
-+ help
-+ Hardware driver for the built-in watchdog timer on the Atheros
-+ AR2315/AR2316 WiSoCs.
-+
- # PARISC Architecture
-
- # POWERPC Architecture
---- a/drivers/watchdog/Makefile
-+++ b/drivers/watchdog/Makefile
-@@ -138,6 +138,7 @@ obj-$(CONFIG_GPIO_WDT) += old_gpio_wdt.o
- obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o
- obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o
- obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
-+obj-$(CONFIG_AR2315_WDT) += ar2315-wtd.o
- obj-$(CONFIG_TXX9_WDT) += txx9wdt.o
- obj-$(CONFIG_OCTEON_WDT) += octeon-wdt.o
- octeon-wdt-y := octeon-wdt-main.o octeon-wdt-nmi.o
---- a/arch/mips/ath25/ar2315.c
-+++ b/arch/mips/ath25/ar2315.c
-@@ -220,6 +220,24 @@ static struct platform_device ar2315_gpi
- .num_resources = ARRAY_SIZE(ar2315_gpio_res)
- };
-
-+static struct resource ar2315_wdt_res[] = {
-+ {
-+ .flags = IORESOURCE_MEM,
-+ .start = AR2315_RST_BASE + AR2315_WDT_TIMER,
-+ .end = AR2315_RST_BASE + AR2315_WDT_TIMER + 8 - 1,
-+ },
-+ {
-+ .flags = IORESOURCE_IRQ,
-+ }
-+};
-+
-+static struct platform_device ar2315_wdt = {
-+ .id = 0,
-+ .name = "ar2315-wdt",
-+ .resource = ar2315_wdt_res,
-+ .num_resources = ARRAY_SIZE(ar2315_wdt_res)
-+};
-+
- static struct resource ar2315_spiflash_res[] = {
- {
- .name = "spiflash_read",
-@@ -252,6 +270,11 @@ void __init ar2315_init_devices(void)
- ar2315_gpio_res[1].end = ar2315_gpio_res[1].start;
- platform_device_register(&ar2315_gpio);
-
-+ ar2315_wdt_res[1].start = irq_create_mapping(ar2315_misc_irq_domain,
-+ AR2315_MISC_IRQ_WATCHDOG);
-+ ar2315_wdt_res[1].end = ar2315_wdt_res[1].start;
-+ platform_device_register(&ar2315_wdt);
-+
- platform_device_register(&ar2315_spiflash);
-
- ar2315_eth_data.macaddr = ath25_board.config->enet0_mac;
diff --git a/target/linux/ath25/patches-3.18/210-reset_button.patch b/target/linux/ath25/patches-3.18/210-reset_button.patch
deleted file mode 100644
index 89853c84bc..0000000000
--- a/target/linux/ath25/patches-3.18/210-reset_button.patch
+++ /dev/null
@@ -1,71 +0,0 @@
---- a/arch/mips/ath25/Makefile
-+++ b/arch/mips/ath25/Makefile
-@@ -8,7 +8,7 @@
- # Copyright (C) 2006-2009 Felix Fietkau <nbd@nbd.name>
- #
-
--obj-y += board.o prom.o devices.o
-+obj-y += board.o prom.o devices.o reset.o
-
- obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
-
---- /dev/null
-+++ b/arch/mips/ath25/reset.c
-@@ -0,0 +1,57 @@
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/platform_device.h>
-+#include <linux/gpio_keys.h>
-+#include <linux/input.h>
-+#include <ath25_platform.h>
-+#include "devices.h"
-+
-+static int __init
-+ar231x_init_reset(void)
-+{
-+ struct platform_device *pdev;
-+ struct gpio_keys_platform_data pdata;
-+ struct gpio_keys_button *p;
-+ int err;
-+
-+ if (ath25_board.config->reset_config_gpio == 0xffff)
-+ return -ENODEV;
-+
-+ p = kzalloc(sizeof(*p), GFP_KERNEL);
-+ if (!p)
-+ goto err;
-+
-+ p->desc = "reset";
-+ p->type = EV_KEY;
-+ p->code = KEY_RESTART;
-+ p->debounce_interval = 60;
-+ p->gpio = ath25_board.config->reset_config_gpio;
-+
-+ memset(&pdata, 0, sizeof(pdata));
-+ pdata.poll_interval = 20;
-+ pdata.buttons = p;
-+ pdata.nbuttons = 1;
-+
-+ pdev = platform_device_alloc("gpio-keys-polled", 0);
-+ if (!pdev)
-+ goto err_free;
-+
-+ err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
-+ if (err)
-+ goto err_put_pdev;
-+
-+ err = platform_device_add(pdev);
-+ if (err)
-+ goto err_put_pdev;
-+
-+ return 0;
-+
-+err_put_pdev:
-+ platform_device_put(pdev);
-+err_free:
-+ kfree(p);
-+err:
-+ return -ENOMEM;
-+}
-+
-+module_init(ar231x_init_reset);
diff --git a/target/linux/ath25/patches-4.4/107-ar5312_gpio.patch b/target/linux/ath25/patches-4.4/107-ar5312_gpio.patch
new file mode 100644
index 0000000000..13a4393aee
--- /dev/null
+++ b/target/linux/ath25/patches-4.4/107-ar5312_gpio.patch
@@ -0,0 +1,212 @@
+--- a/arch/mips/ath25/Kconfig
++++ b/arch/mips/ath25/Kconfig
+@@ -1,6 +1,7 @@
+ config SOC_AR5312
+ bool "Atheros AR5312/AR2312+ SoC support"
+ depends on ATH25
++ select GPIO_AR5312
+ default y
+
+ config SOC_AR2315
+--- a/arch/mips/ath25/ar5312.c
++++ b/arch/mips/ath25/ar5312.c
+@@ -22,6 +22,7 @@
+ #include <linux/platform_device.h>
+ #include <linux/mtd/physmap.h>
+ #include <linux/reboot.h>
++#include <linux/gpio.h>
+ #include <asm/bootinfo.h>
+ #include <asm/reboot.h>
+ #include <asm/time.h>
+@@ -180,6 +181,22 @@ static struct platform_device ar5312_phy
+ .num_resources = 1,
+ };
+
++static struct resource ar5312_gpio_res[] = {
++ {
++ .name = "ar5312-gpio",
++ .flags = IORESOURCE_MEM,
++ .start = AR5312_GPIO_BASE,
++ .end = AR5312_GPIO_BASE + AR5312_GPIO_SIZE - 1,
++ },
++};
++
++static struct platform_device ar5312_gpio = {
++ .name = "ar5312-gpio",
++ .id = -1,
++ .resource = ar5312_gpio_res,
++ .num_resources = ARRAY_SIZE(ar5312_gpio_res),
++};
++
+ static void __init ar5312_flash_init(void)
+ {
+ void __iomem *flashctl_base;
+@@ -247,6 +264,8 @@ void __init ar5312_init_devices(void)
+
+ platform_device_register(&ar5312_physmap_flash);
+
++ platform_device_register(&ar5312_gpio);
++
+ switch (ath25_soc) {
+ case ATH25_SOC_AR5312:
+ if (!ath25_board.radio)
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -141,6 +141,13 @@ config GPIO_BRCMSTB
+ help
+ Say yes here to enable GPIO support for Broadcom STB (BCM7XXX) SoCs.
+
++config GPIO_AR5312
++ bool "AR5312 SoC GPIO support"
++ default y if SOC_AR5312
++ depends on SOC_AR5312
++ help
++ Say yes here to enable GPIO support for Atheros AR5312/AR2312+ SoCs.
++
+ config GPIO_CLPS711X
+ tristate "CLPS711X GPIO support"
+ depends on ARCH_CLPS711X || COMPILE_TEST
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -21,6 +21,7 @@ obj-$(CONFIG_GPIO_ADP5588) += gpio-adp55
+ obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o
+ obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o
+ obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o
++obj-$(CONFIG_GPIO_AR5312) += gpio-ar5312.o
+ obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
+ obj-$(CONFIG_ATH79) += gpio-ath79.o
+ obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
+--- /dev/null
++++ b/drivers/gpio/gpio-ar5312.c
+@@ -0,0 +1,121 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright (C) 2003 Atheros Communications, Inc., All Rights Reserved.
++ * Copyright (C) 2006 FON Technology, SL.
++ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
++ * Copyright (C) 2006-2009 Felix Fietkau <nbd@nbd.name>
++ * Copyright (C) 2012 Alexandros C. Couloumbis <alex@ozo.com>
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/gpio.h>
++
++#define DRIVER_NAME "ar5312-gpio"
++
++#define AR5312_GPIO_DO 0x00 /* output register */
++#define AR5312_GPIO_DI 0x04 /* intput register */
++#define AR5312_GPIO_CR 0x08 /* control register */
++
++#define AR5312_GPIO_CR_M(x) (1 << (x)) /* mask for i/o */
++#define AR5312_GPIO_CR_O(x) (0 << (x)) /* mask for output */
++#define AR5312_GPIO_CR_I(x) (1 << (x)) /* mask for input */
++#define AR5312_GPIO_CR_INT(x) (1 << ((x)+8)) /* mask for interrupt */
++#define AR5312_GPIO_CR_UART(x) (1 << ((x)+16)) /* uart multiplex */
++
++#define AR5312_GPIO_NUM 8
++
++static void __iomem *ar5312_mem;
++
++static inline u32 ar5312_gpio_reg_read(unsigned reg)
++{
++ return __raw_readl(ar5312_mem + reg);
++}
++
++static inline void ar5312_gpio_reg_write(unsigned reg, u32 val)
++{
++ __raw_writel(val, ar5312_mem + reg);
++}
++
++static inline void ar5312_gpio_reg_mask(unsigned reg, u32 mask, u32 val)
++{
++ ar5312_gpio_reg_write(reg, (ar5312_gpio_reg_read(reg) & ~mask) | val);
++}
++
++static int ar5312_gpio_get_val(struct gpio_chip *chip, unsigned gpio)
++{
++ return (ar5312_gpio_reg_read(AR5312_GPIO_DI) >> gpio) & 1;
++}
++
++static void ar5312_gpio_set_val(struct gpio_chip *chip, unsigned gpio, int val)
++{
++ u32 reg = ar5312_gpio_reg_read(AR5312_GPIO_DO);
++
++ reg = val ? reg | (1 << gpio) : reg & ~(1 << gpio);
++ ar5312_gpio_reg_write(AR5312_GPIO_DO, reg);
++}
++
++static int ar5312_gpio_dir_in(struct gpio_chip *chip, unsigned gpio)
++{
++ ar5312_gpio_reg_mask(AR5312_GPIO_CR, 0, 1 << gpio);
++ return 0;
++}
++
++static int ar5312_gpio_dir_out(struct gpio_chip *chip, unsigned gpio, int val)
++{
++ ar5312_gpio_reg_mask(AR5312_GPIO_CR, 1 << gpio, 0);
++ ar5312_gpio_set_val(chip, gpio, val);
++ return 0;
++}
++
++static struct gpio_chip ar5312_gpio_chip = {
++ .label = DRIVER_NAME,
++ .direction_input = ar5312_gpio_dir_in,
++ .direction_output = ar5312_gpio_dir_out,
++ .set = ar5312_gpio_set_val,
++ .get = ar5312_gpio_get_val,
++ .base = 0,
++ .ngpio = AR5312_GPIO_NUM,
++};
++
++static int ar5312_gpio_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct resource *res;
++ int ret;
++
++ if (ar5312_mem)
++ return -EBUSY;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ ar5312_mem = devm_ioremap_resource(dev, res);
++ if (IS_ERR(ar5312_mem))
++ return PTR_ERR(ar5312_mem);
++
++ ar5312_gpio_chip.dev = dev;
++ ret = gpiochip_add(&ar5312_gpio_chip);
++ if (ret) {
++ dev_err(dev, "failed to add gpiochip\n");
++ return ret;
++ }
++
++ return 0;
++}
++
++static struct platform_driver ar5312_gpio_driver = {
++ .probe = ar5312_gpio_probe,
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ }
++};
++
++static int __init ar5312_gpio_init(void)
++{
++ return platform_driver_register(&ar5312_gpio_driver);
++}
++subsys_initcall(ar5312_gpio_init);
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -117,6 +117,7 @@ config ATH25
+ select SYS_SUPPORTS_BIG_ENDIAN
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_HAS_EARLY_PRINTK
++ select ARCH_REQUIRE_GPIOLIB
+ help
+ Support for Atheros AR231x and Atheros AR531x based boards
+
diff --git a/target/linux/ath25/patches-4.4/108-ar2315_gpio.patch b/target/linux/ath25/patches-4.4/108-ar2315_gpio.patch
new file mode 100644
index 0000000000..ba9c3f77da
--- /dev/null
+++ b/target/linux/ath25/patches-4.4/108-ar2315_gpio.patch
@@ -0,0 +1,363 @@
+--- a/arch/mips/ath25/Kconfig
++++ b/arch/mips/ath25/Kconfig
+@@ -7,6 +7,7 @@ config SOC_AR5312
+ config SOC_AR2315
+ bool "Atheros AR2315+ SoC support"
+ depends on ATH25
++ select GPIO_AR2315
+ default y
+
+ config PCI_AR2315
+--- a/arch/mips/ath25/ar2315.c
++++ b/arch/mips/ath25/ar2315.c
+@@ -21,6 +21,8 @@
+ #include <linux/interrupt.h>
+ #include <linux/platform_device.h>
+ #include <linux/reboot.h>
++#include <linux/delay.h>
++#include <linux/gpio.h>
+ #include <asm/bootinfo.h>
+ #include <asm/reboot.h>
+ #include <asm/time.h>
+@@ -167,11 +169,42 @@ void __init ar2315_arch_init_irq(void)
+ ar2315_misc_irq_domain = domain;
+ }
+
++static struct resource ar2315_gpio_res[] = {
++ {
++ .name = "ar2315-gpio",
++ .flags = IORESOURCE_MEM,
++ .start = AR2315_RST_BASE + AR2315_GPIO,
++ .end = AR2315_RST_BASE + AR2315_GPIO + 0x10 - 1,
++ },
++ {
++ .name = "ar2315-gpio",
++ .flags = IORESOURCE_IRQ,
++ },
++ {
++ .name = "ar2315-gpio-irq-base",
++ .flags = IORESOURCE_IRQ,
++ .start = AR231X_GPIO_IRQ_BASE,
++ .end = AR231X_GPIO_IRQ_BASE,
++ }
++};
++
++static struct platform_device ar2315_gpio = {
++ .id = -1,
++ .name = "ar2315-gpio",
++ .resource = ar2315_gpio_res,
++ .num_resources = ARRAY_SIZE(ar2315_gpio_res)
++};
++
+ void __init ar2315_init_devices(void)
+ {
+ /* Find board configuration */
+ ath25_find_config(AR2315_SPI_READ_BASE, AR2315_SPI_READ_SIZE);
+
++ ar2315_gpio_res[1].start = irq_create_mapping(ar2315_misc_irq_domain,
++ AR2315_MISC_IRQ_GPIO);
++ ar2315_gpio_res[1].end = ar2315_gpio_res[1].start;
++ platform_device_register(&ar2315_gpio);
++
+ ath25_add_wmac(0, AR2315_WLAN0_BASE, AR2315_IRQ_WLAN0);
+ }
+
+@@ -187,8 +220,8 @@ static void ar2315_restart(char *command
+ /* Cold reset does not work on the AR2315/6, use the GPIO reset bits
+ * a workaround. Give it some time to attempt a gpio based hardware
+ * reset (atheros reference design workaround) */
+-
+- /* TODO: implement the GPIO reset workaround */
++ gpio_request_one(AR2315_RESET_GPIO, GPIOF_OUT_INIT_LOW, "Reset");
++ mdelay(100);
+
+ /* Some boards (e.g. Senao EOC-2610) don't implement the reset logic
+ * workaround. Attempt to jump to the mips reset location -
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -141,6 +141,13 @@ config GPIO_BRCMSTB
+ help
+ Say yes here to enable GPIO support for Broadcom STB (BCM7XXX) SoCs.
+
++config GPIO_AR2315
++ bool "AR2315 SoC GPIO support"
++ default y if SOC_AR2315
++ depends on SOC_AR2315
++ help
++ Say yes here to enable GPIO support for Atheros AR2315+ SoCs.
++
+ config GPIO_AR5312
+ bool "AR5312 SoC GPIO support"
+ default y if SOC_AR5312
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -21,6 +21,7 @@ obj-$(CONFIG_GPIO_ADP5588) += gpio-adp55
+ obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o
+ obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o
+ obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o
++obj-$(CONFIG_GPIO_AR2315) += gpio-ar2315.o
+ obj-$(CONFIG_GPIO_AR5312) += gpio-ar5312.o
+ obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
+ obj-$(CONFIG_ATH79) += gpio-ath79.o
+--- /dev/null
++++ b/drivers/gpio/gpio-ar2315.c
+@@ -0,0 +1,233 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright (C) 2003 Atheros Communications, Inc., All Rights Reserved.
++ * Copyright (C) 2006 FON Technology, SL.
++ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
++ * Copyright (C) 2006 Felix Fietkau <nbd@nbd.name>
++ * Copyright (C) 2012 Alexandros C. Couloumbis <alex@ozo.com>
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/gpio.h>
++#include <linux/irq.h>
++
++#define DRIVER_NAME "ar2315-gpio"
++
++#define AR2315_GPIO_DI 0x0000
++#define AR2315_GPIO_DO 0x0008
++#define AR2315_GPIO_DIR 0x0010
++#define AR2315_GPIO_INT 0x0018
++
++#define AR2315_GPIO_DIR_M(x) (1 << (x)) /* mask for i/o */
++#define AR2315_GPIO_DIR_O(x) (1 << (x)) /* output */
++#define AR2315_GPIO_DIR_I(x) (0) /* input */
++
++#define AR2315_GPIO_INT_NUM_M 0x3F /* mask for GPIO num */
++#define AR2315_GPIO_INT_TRIG(x) ((x) << 6) /* interrupt trigger */
++#define AR2315_GPIO_INT_TRIG_M (0x3 << 6) /* mask for int trig */
++
++#define AR2315_GPIO_INT_TRIG_OFF 0 /* Triggerring off */
++#define AR2315_GPIO_INT_TRIG_LOW 1 /* Low Level Triggered */
++#define AR2315_GPIO_INT_TRIG_HIGH 2 /* High Level Triggered */
++#define AR2315_GPIO_INT_TRIG_EDGE 3 /* Edge Triggered */
++
++#define AR2315_GPIO_NUM 22
++
++static u32 ar2315_gpio_intmask;
++static u32 ar2315_gpio_intval;
++static unsigned ar2315_gpio_irq_base;
++static void __iomem *ar2315_mem;
++
++static inline u32 ar2315_gpio_reg_read(unsigned reg)
++{
++ return __raw_readl(ar2315_mem + reg);
++}
++
++static inline void ar2315_gpio_reg_write(unsigned reg, u32 val)
++{
++ __raw_writel(val, ar2315_mem + reg);
++}
++
++static inline void ar2315_gpio_reg_mask(unsigned reg, u32 mask, u32 val)
++{
++ ar2315_gpio_reg_write(reg, (ar2315_gpio_reg_read(reg) & ~mask) | val);
++}
++
++static void ar2315_gpio_irq_handler(struct irq_desc *desc)
++{
++ u32 pend;
++ int bit = -1;
++
++ /* only do one gpio interrupt at a time */
++ pend = ar2315_gpio_reg_read(AR2315_GPIO_DI);
++ pend ^= ar2315_gpio_intval;
++ pend &= ar2315_gpio_intmask;
++
++ if (pend) {
++ bit = fls(pend) - 1;
++ pend &= ~(1 << bit);
++ ar2315_gpio_intval ^= (1 << bit);
++ }
++
++ /* Enable interrupt with edge detection */
++ if ((ar2315_gpio_reg_read(AR2315_GPIO_DIR) & AR2315_GPIO_DIR_M(bit)) !=
++ AR2315_GPIO_DIR_I(bit))
++ return;
++
++ if (bit >= 0)
++ generic_handle_irq(ar2315_gpio_irq_base + bit);
++}
++
++static void ar2315_gpio_int_setup(unsigned gpio, int trig)
++{
++ u32 reg = ar2315_gpio_reg_read(AR2315_GPIO_INT);
++
++ reg &= ~(AR2315_GPIO_INT_NUM_M | AR2315_GPIO_INT_TRIG_M);
++ reg |= gpio | AR2315_GPIO_INT_TRIG(trig);
++ ar2315_gpio_reg_write(AR2315_GPIO_INT, reg);
++}
++
++static void ar2315_gpio_irq_unmask(struct irq_data *d)
++{
++ unsigned gpio = d->irq - ar2315_gpio_irq_base;
++ u32 dir = ar2315_gpio_reg_read(AR2315_GPIO_DIR);
++
++ /* Enable interrupt with edge detection */
++ if ((dir & AR2315_GPIO_DIR_M(gpio)) != AR2315_GPIO_DIR_I(gpio))
++ return;
++
++ ar2315_gpio_intmask |= (1 << gpio);
++ ar2315_gpio_int_setup(gpio, AR2315_GPIO_INT_TRIG_EDGE);
++}
++
++static void ar2315_gpio_irq_mask(struct irq_data *d)
++{
++ unsigned gpio = d->irq - ar2315_gpio_irq_base;
++
++ /* Disable interrupt */
++ ar2315_gpio_intmask &= ~(1 << gpio);
++ ar2315_gpio_int_setup(gpio, AR2315_GPIO_INT_TRIG_OFF);
++}
++
++static struct irq_chip ar2315_gpio_irq_chip = {
++ .name = DRIVER_NAME,
++ .irq_unmask = ar2315_gpio_irq_unmask,
++ .irq_mask = ar2315_gpio_irq_mask,
++};
++
++static void ar2315_gpio_irq_init(unsigned irq)
++{
++ unsigned i;
++
++ ar2315_gpio_intval = ar2315_gpio_reg_read(AR2315_GPIO_DI);
++ for (i = 0; i < AR2315_GPIO_NUM; i++) {
++ unsigned _irq = ar2315_gpio_irq_base + i;
++
++ irq_set_chip_and_handler(_irq, &ar2315_gpio_irq_chip,
++ handle_level_irq);
++ }
++ irq_set_chained_handler(irq, ar2315_gpio_irq_handler);
++}
++
++static int ar2315_gpio_get_val(struct gpio_chip *chip, unsigned gpio)
++{
++ return (ar2315_gpio_reg_read(AR2315_GPIO_DI) >> gpio) & 1;
++}
++
++static void ar2315_gpio_set_val(struct gpio_chip *chip, unsigned gpio, int val)
++{
++ u32 reg = ar2315_gpio_reg_read(AR2315_GPIO_DO);
++
++ reg = val ? reg | (1 << gpio) : reg & ~(1 << gpio);
++ ar2315_gpio_reg_write(AR2315_GPIO_DO, reg);
++}
++
++static int ar2315_gpio_dir_in(struct gpio_chip *chip, unsigned gpio)
++{
++ ar2315_gpio_reg_mask(AR2315_GPIO_DIR, 1 << gpio, 0);
++ return 0;
++}
++
++static int ar2315_gpio_dir_out(struct gpio_chip *chip, unsigned gpio, int val)
++{
++ ar2315_gpio_reg_mask(AR2315_GPIO_DIR, 0, 1 << gpio);
++ ar2315_gpio_set_val(chip, gpio, val);
++ return 0;
++}
++
++static int ar2315_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
++{
++ return ar2315_gpio_irq_base + gpio;
++}
++
++static struct gpio_chip ar2315_gpio_chip = {
++ .label = DRIVER_NAME,
++ .direction_input = ar2315_gpio_dir_in,
++ .direction_output = ar2315_gpio_dir_out,
++ .set = ar2315_gpio_set_val,
++ .get = ar2315_gpio_get_val,
++ .to_irq = ar2315_gpio_to_irq,
++ .base = 0,
++ .ngpio = AR2315_GPIO_NUM,
++};
++
++static int ar2315_gpio_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct resource *res;
++ unsigned irq;
++ int ret;
++
++ if (ar2315_mem)
++ return -EBUSY;
++
++ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
++ "ar2315-gpio-irq-base");
++ if (!res) {
++ dev_err(dev, "not found GPIO IRQ base\n");
++ return -ENXIO;
++ }
++ ar2315_gpio_irq_base = res->start;
++
++ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, DRIVER_NAME);
++ if (!res) {
++ dev_err(dev, "not found IRQ number\n");
++ return -ENXIO;
++ }
++ irq = res->start;
++
++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, DRIVER_NAME);
++ ar2315_mem = devm_ioremap_resource(dev, res);
++ if (IS_ERR(ar2315_mem))
++ return PTR_ERR(ar2315_mem);
++
++ ar2315_gpio_chip.dev = dev;
++ ret = gpiochip_add(&ar2315_gpio_chip);
++ if (ret) {
++ dev_err(dev, "failed to add gpiochip\n");
++ return ret;
++ }
++
++ ar2315_gpio_irq_init(irq);
++
++ return 0;
++}
++
++static struct platform_driver ar2315_gpio_driver = {
++ .probe = ar2315_gpio_probe,
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ }
++};
++
++static int __init ar2315_gpio_init(void)
++{
++ return platform_driver_register(&ar2315_gpio_driver);
++}
++subsys_initcall(ar2315_gpio_init);
+--- a/arch/mips/ath25/devices.h
++++ b/arch/mips/ath25/devices.h
+@@ -3,6 +3,11 @@
+
+ #include <linux/cpu.h>
+
++#define AR231X_GPIO_IRQ_BASE 0x30
++
++/* GPIO number for AR2315/16 reset issue workaround */
++#define AR2315_RESET_GPIO 5
++
+ #define ATH25_REG_MS(_val, _field) (((_val) & _field##_M) >> _field##_S)
+
+ #define ATH25_IRQ_CPU_CLOCK (MIPS_CPU_IRQ_BASE + 7) /* C0_CAUSE: 0x8000 */
+--- a/arch/mips/ath25/ar2315_regs.h
++++ b/arch/mips/ath25/ar2315_regs.h
+@@ -315,6 +315,9 @@
+ #define AR2315_MEM_CFG_BANKADDR_BITS_M 0x00000018
+ #define AR2315_MEM_CFG_BANKADDR_BITS_S 3
+
++/* GPIO MMR base address */
++#define AR2315_GPIO 0x0088
++
+ /*
+ * Local Bus Interface Registers
+ */
diff --git a/target/linux/ath25/patches-4.4/110-ar2313_ethernet.patch b/target/linux/ath25/patches-4.4/110-ar2313_ethernet.patch
new file mode 100644
index 0000000000..9b1286c075
--- /dev/null
+++ b/target/linux/ath25/patches-4.4/110-ar2313_ethernet.patch
@@ -0,0 +1,1828 @@
+--- a/drivers/net/ethernet/atheros/Makefile
++++ b/drivers/net/ethernet/atheros/Makefile
+@@ -7,3 +7,4 @@ obj-$(CONFIG_ATL2) += atlx/
+ obj-$(CONFIG_ATL1E) += atl1e/
+ obj-$(CONFIG_ATL1C) += atl1c/
+ obj-$(CONFIG_ALX) += alx/
++obj-$(CONFIG_NET_AR231X) += ar231x/
+--- a/drivers/net/ethernet/atheros/Kconfig
++++ b/drivers/net/ethernet/atheros/Kconfig
+@@ -5,7 +5,7 @@
+ config NET_VENDOR_ATHEROS
+ bool "Atheros devices"
+ default y
+- depends on PCI
++ depends on (PCI || ATH25)
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y.
+
+@@ -78,4 +78,10 @@ config ALX
+ To compile this driver as a module, choose M here. The module
+ will be called alx.
+
++config NET_AR231X
++ tristate "Atheros AR231X built-in Ethernet support"
++ depends on ATH25
++ help
++ Support for the AR231x/531x ethernet controller
++
+ endif # NET_VENDOR_ATHEROS
+--- /dev/null
++++ b/drivers/net/ethernet/atheros/ar231x/Makefile
+@@ -0,0 +1 @@
++obj-$(CONFIG_NET_AR231X) += ar231x.o
+--- /dev/null
++++ b/drivers/net/ethernet/atheros/ar231x/ar231x.c
+@@ -0,0 +1,1206 @@
++/*
++ * ar231x.c: Linux driver for the Atheros AR231x Ethernet device.
++ *
++ * Copyright (C) 2004 by Sameer Dekate <sdekate@arubanetworks.com>
++ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
++ * Copyright (C) 2006-2009 Felix Fietkau <nbd@nbd.name>
++ *
++ * Thanks to Atheros for providing hardware and documentation
++ * enabling me to write this driver.
++ *
++ * 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.
++ *
++ * Additional credits:
++ * This code is taken from John Taylor's Sibyte driver and then
++ * modified for the AR2313.
++ */
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/ioport.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/interrupt.h>
++#include <linux/skbuff.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/mm.h>
++#include <linux/mii.h>
++#include <linux/phy.h>
++#include <linux/platform_device.h>
++#include <linux/io.h>
++
++#define AR2313_MTU 1692
++#define AR2313_PRIOS 1
++#define AR2313_QUEUES (2*AR2313_PRIOS)
++#define AR2313_DESCR_ENTRIES 64
++
++#ifndef min
++#define min(a, b) (((a) < (b)) ? (a) : (b))
++#endif
++
++#ifndef SMP_CACHE_BYTES
++#define SMP_CACHE_BYTES L1_CACHE_BYTES
++#endif
++
++#define AR2313_MBOX_SET_BIT 0x8
++
++#include "ar231x.h"
++
++/**
++ * New interrupt handler strategy:
++ *
++ * An old interrupt handler worked using the traditional method of
++ * replacing an skbuff with a new one when a packet arrives. However
++ * the rx rings do not need to contain a static number of buffer
++ * descriptors, thus it makes sense to move the memory allocation out
++ * of the main interrupt handler and do it in a bottom half handler
++ * and only allocate new buffers when the number of buffers in the
++ * ring is below a certain threshold. In order to avoid starving the
++ * NIC under heavy load it is however necessary to force allocation
++ * when hitting a minimum threshold. The strategy for alloction is as
++ * follows:
++ *
++ * RX_LOW_BUF_THRES - allocate buffers in the bottom half
++ * RX_PANIC_LOW_THRES - we are very low on buffers, allocate
++ * the buffers in the interrupt handler
++ * RX_RING_THRES - maximum number of buffers in the rx ring
++ *
++ * One advantagous side effect of this allocation approach is that the
++ * entire rx processing can be done without holding any spin lock
++ * since the rx rings and registers are totally independent of the tx
++ * ring and its registers. This of course includes the kmalloc's of
++ * new skb's. Thus start_xmit can run in parallel with rx processing
++ * and the memory allocation on SMP systems.
++ *
++ * Note that running the skb reallocation in a bottom half opens up
++ * another can of races which needs to be handled properly. In
++ * particular it can happen that the interrupt handler tries to run
++ * the reallocation while the bottom half is either running on another
++ * CPU or was interrupted on the same CPU. To get around this the
++ * driver uses bitops to prevent the reallocation routines from being
++ * reentered.
++ *
++ * TX handling can also be done without holding any spin lock, wheee
++ * this is fun! since tx_csm is only written to by the interrupt
++ * handler.
++ */
++
++/**
++ * Threshold values for RX buffer allocation - the low water marks for
++ * when to start refilling the rings are set to 75% of the ring
++ * sizes. It seems to make sense to refill the rings entirely from the
++ * intrrupt handler once it gets below the panic threshold, that way
++ * we don't risk that the refilling is moved to another CPU when the
++ * one running the interrupt handler just got the slab code hot in its
++ * cache.
++ */
++#define RX_RING_SIZE AR2313_DESCR_ENTRIES
++#define RX_PANIC_THRES (RX_RING_SIZE/4)
++#define RX_LOW_THRES ((3*RX_RING_SIZE)/4)
++#define CRC_LEN 4
++#define RX_OFFSET 2
++
++#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
++#define VLAN_HDR 4
++#else
++#define VLAN_HDR 0
++#endif
++
++#define AR2313_BUFSIZE (AR2313_MTU + VLAN_HDR + ETH_HLEN + CRC_LEN + \
++ RX_OFFSET)
++
++#ifdef MODULE
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Sameer Dekate <sdekate@arubanetworks.com>, Imre Kaloz <kaloz@openwrt.org>, Felix Fietkau <nbd@nbd.name>");
++MODULE_DESCRIPTION("AR231x Ethernet driver");
++#endif
++
++#define virt_to_phys(x) ((u32)(x) & 0x1fffffff)
++
++/* prototypes */
++static void ar231x_halt(struct net_device *dev);
++static void rx_tasklet_func(unsigned long data);
++static void rx_tasklet_cleanup(struct net_device *dev);
++static void ar231x_multicast_list(struct net_device *dev);
++static void ar231x_tx_timeout(struct net_device *dev);
++
++static int ar231x_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum);
++static int ar231x_mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum,
++ u16 value);
++static int ar231x_mdiobus_reset(struct mii_bus *bus);
++static int ar231x_mdiobus_probe(struct net_device *dev);
++static void ar231x_adjust_link(struct net_device *dev);
++
++#ifndef ERR
++#define ERR(fmt, args...) printk("%s: " fmt, __func__, ##args)
++#endif
++
++#ifdef CONFIG_NET_POLL_CONTROLLER
++static void
++ar231x_netpoll(struct net_device *dev)
++{
++ unsigned long flags;
++
++ local_irq_save(flags);
++ ar231x_interrupt(dev->irq, dev);
++ local_irq_restore(flags);
++}
++#endif
++
++static const struct net_device_ops ar231x_ops = {
++ .ndo_open = ar231x_open,
++ .ndo_stop = ar231x_close,
++ .ndo_start_xmit = ar231x_start_xmit,
++ .ndo_set_rx_mode = ar231x_multicast_list,
++ .ndo_do_ioctl = ar231x_ioctl,
++ .ndo_change_mtu = eth_change_mtu,
++ .ndo_validate_addr = eth_validate_addr,
++ .ndo_set_mac_address = eth_mac_addr,
++ .ndo_tx_timeout = ar231x_tx_timeout,
++#ifdef CONFIG_NET_POLL_CONTROLLER
++ .ndo_poll_controller = ar231x_netpoll,
++#endif
++};
++
++static int ar231x_probe(struct platform_device *pdev)
++{
++ struct net_device *dev;
++ struct ar231x_private *sp;
++ struct resource *res;
++ unsigned long ar_eth_base;
++ char buf[64];
++
++ dev = alloc_etherdev(sizeof(struct ar231x_private));
++
++ if (dev == NULL) {
++ printk(KERN_ERR
++ "ar231x: Unable to allocate net_device structure!\n");
++ return -ENOMEM;
++ }
++
++ platform_set_drvdata(pdev, dev);
++
++ sp = netdev_priv(dev);
++ sp->dev = dev;
++ sp->cfg = pdev->dev.platform_data;
++
++ sprintf(buf, "eth%d_membase", pdev->id);
++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, buf);
++ if (!res)
++ return -ENODEV;
++
++ sp->link = 0;
++ ar_eth_base = res->start;
++
++ sprintf(buf, "eth%d_irq", pdev->id);
++ dev->irq = platform_get_irq_byname(pdev, buf);
++
++ spin_lock_init(&sp->lock);
++
++ dev->features |= NETIF_F_HIGHDMA;
++ dev->netdev_ops = &ar231x_ops;
++
++ tasklet_init(&sp->rx_tasklet, rx_tasklet_func, (unsigned long)dev);
++ tasklet_disable(&sp->rx_tasklet);
++
++ sp->eth_regs = ioremap_nocache(ar_eth_base, sizeof(*sp->eth_regs));
++ if (!sp->eth_regs) {
++ printk("Can't remap eth registers\n");
++ return -ENXIO;
++ }
++
++ /**
++ * When there's only one MAC, PHY regs are typically on ENET0,
++ * even though the MAC might be on ENET1.
++ * So remap PHY regs separately.
++ */
++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eth0_mii");
++ if (!res) {
++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
++ "eth1_mii");
++ if (!res)
++ return -ENODEV;
++ }
++ sp->phy_regs = ioremap_nocache(res->start, resource_size(res));
++ if (!sp->phy_regs) {
++ printk("Can't remap phy registers\n");
++ return -ENXIO;
++ }
++
++ sp->dma_regs = ioremap_nocache(ar_eth_base + 0x1000,
++ sizeof(*sp->dma_regs));
++ if (!sp->dma_regs) {
++ printk("Can't remap DMA registers\n");
++ return -ENXIO;
++ }
++ dev->base_addr = ar_eth_base + 0x1000;
++
++ strncpy(sp->name, "Atheros AR231x", sizeof(sp->name) - 1);
++ sp->name[sizeof(sp->name) - 1] = '\0';
++ memcpy(dev->dev_addr, sp->cfg->macaddr, 6);
++
++ if (ar231x_init(dev)) {
++ /* ar231x_init() calls ar231x_init_cleanup() on error */
++ kfree(dev);
++ return -ENODEV;
++ }
++
++ if (register_netdev(dev)) {
++ printk("%s: register_netdev failed\n", __func__);
++ return -1;
++ }
++
++ printk("%s: %s: %pM, irq %d\n", dev->name, sp->name, dev->dev_addr,
++ dev->irq);
++
++ sp->mii_bus = mdiobus_alloc();
++ if (sp->mii_bus == NULL)
++ return -1;
++
++ sp->mii_bus->priv = dev;
++ sp->mii_bus->read = ar231x_mdiobus_read;
++ sp->mii_bus->write = ar231x_mdiobus_write;
++ sp->mii_bus->reset = ar231x_mdiobus_reset;
++ sp->mii_bus->name = "ar231x_eth_mii";
++ snprintf(sp->mii_bus->id, MII_BUS_ID_SIZE, "%d", pdev->id);
++ sp->mii_bus->irq = kmalloc(sizeof(int), GFP_KERNEL);
++ *sp->mii_bus->irq = PHY_POLL;
++
++ mdiobus_register(sp->mii_bus);
++
++ if (ar231x_mdiobus_probe(dev) != 0) {
++ printk(KERN_ERR "%s: mdiobus_probe failed\n", dev->name);
++ rx_tasklet_cleanup(dev);
++ ar231x_init_cleanup(dev);
++ unregister_netdev(dev);
++ kfree(dev);
++ return -ENODEV;
++ }
++
++ /* start link poll timer */
++ ar231x_setup_timer(dev);
++
++ return 0;
++}
++
++static void ar231x_multicast_list(struct net_device *dev)
++{
++ struct ar231x_private *sp = netdev_priv(dev);
++ unsigned int filter;
++
++ filter = sp->eth_regs->mac_control;
++
++ if (dev->flags & IFF_PROMISC)
++ filter |= MAC_CONTROL_PR;
++ else
++ filter &= ~MAC_CONTROL_PR;
++ if ((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 0))
++ filter |= MAC_CONTROL_PM;
++ else
++ filter &= ~MAC_CONTROL_PM;
++
++ sp->eth_regs->mac_control = filter;
++}
++
++static void rx_tasklet_cleanup(struct net_device *dev)
++{
++ struct ar231x_private *sp = netdev_priv(dev);
++
++ /**
++ * Tasklet may be scheduled. Need to get it removed from the list
++ * since we're about to free the struct.
++ */
++
++ sp->unloading = 1;
++ tasklet_enable(&sp->rx_tasklet);
++ tasklet_kill(&sp->rx_tasklet);
++}
++
++static int ar231x_remove(struct platform_device *pdev)
++{
++ struct net_device *dev = platform_get_drvdata(pdev);
++ struct ar231x_private *sp = netdev_priv(dev);
++
++ rx_tasklet_cleanup(dev);
++ ar231x_init_cleanup(dev);
++ unregister_netdev(dev);
++ mdiobus_unregister(sp->mii_bus);
++ mdiobus_free(sp->mii_bus);
++ kfree(dev);
++ return 0;
++}
++
++/**
++ * Restart the AR2313 ethernet controller.
++ */
++static int ar231x_restart(struct net_device *dev)
++{
++ /* disable interrupts */
++ disable_irq(dev->irq);
++
++ /* stop mac */
++ ar231x_halt(dev);
++
++ /* initialize */
++ ar231x_init(dev);
++
++ /* enable interrupts */
++ enable_irq(dev->irq);
++
++ return 0;
++}
++
++static struct platform_driver ar231x_driver = {
++ .driver.name = "ar231x-eth",
++ .probe = ar231x_probe,
++ .remove = ar231x_remove,
++};
++
++module_platform_driver(ar231x_driver);
++
++static void ar231x_free_descriptors(struct net_device *dev)
++{
++ struct ar231x_private *sp = netdev_priv(dev);
++
++ if (sp->rx_ring != NULL) {
++ kfree((void *)KSEG0ADDR(sp->rx_ring));
++ sp->rx_ring = NULL;
++ sp->tx_ring = NULL;
++ }
++}
++
++static int ar231x_allocate_descriptors(struct net_device *dev)
++{
++ struct ar231x_private *sp = netdev_priv(dev);
++ int size;
++ int j;
++ ar231x_descr_t *space;
++
++ if (sp->rx_ring != NULL) {
++ printk("%s: already done.\n", __func__);
++ return 0;
++ }
++
++ size = sizeof(ar231x_descr_t) * (AR2313_DESCR_ENTRIES * AR2313_QUEUES);
++ space = kmalloc(size, GFP_KERNEL);
++ if (space == NULL)
++ return 1;
++
++ /* invalidate caches */
++ dma_cache_inv((unsigned int)space, size);
++
++ /* now convert pointer to KSEG1 */
++ space = (ar231x_descr_t *)KSEG1ADDR(space);
++
++ memset((void *)space, 0, size);
++
++ sp->rx_ring = space;
++ space += AR2313_DESCR_ENTRIES;
++
++ sp->tx_ring = space;
++ space += AR2313_DESCR_ENTRIES;
++
++ /* Initialize the transmit Descriptors */
++ for (j = 0; j < AR2313_DESCR_ENTRIES; j++) {
++ ar231x_descr_t *td = &sp->tx_ring[j];
++
++ td->status = 0;
++ td->devcs = DMA_TX1_CHAINED;
++ td->addr = 0;
++ td->descr = virt_to_phys(&sp->tx_ring[DSC_NEXT(j)]);
++ }
++
++ return 0;
++}
++
++/**
++ * Generic cleanup handling data allocated during init. Used when the
++ * module is unloaded or if an error occurs during initialization
++ */
++static void ar231x_init_cleanup(struct net_device *dev)
++{
++ struct ar231x_private *sp = netdev_priv(dev);
++ struct sk_buff *skb;
++ int j;
++
++ ar231x_free_descriptors(dev);
++
++ if (sp->eth_regs)
++ iounmap((void *)sp->eth_regs);
++ if (sp->dma_regs)
++ iounmap((void *)sp->dma_regs);
++ if (sp->phy_regs)
++ iounmap((void *)sp->phy_regs);
++
++ if (sp->rx_skb) {
++ for (j = 0; j < AR2313_DESCR_ENTRIES; j++) {
++ skb = sp->rx_skb[j];
++ if (skb) {
++ sp->rx_skb[j] = NULL;
++ dev_kfree_skb(skb);
++ }
++ }
++ kfree(sp->rx_skb);
++ sp->rx_skb = NULL;
++ }
++
++ if (sp->tx_skb) {
++ for (j = 0; j < AR2313_DESCR_ENTRIES; j++) {
++ skb = sp->tx_skb[j];
++ if (skb) {
++ sp->tx_skb[j] = NULL;
++ dev_kfree_skb(skb);
++ }
++ }
++ kfree(sp->tx_skb);
++ sp->tx_skb = NULL;
++ }
++}
++
++static int ar231x_setup_timer(struct net_device *dev)
++{
++ struct ar231x_private *sp = netdev_priv(dev);
++
++ init_timer(&sp->link_timer);
++
++ sp->link_timer.function = ar231x_link_timer_fn;
++ sp->link_timer.data = (int)dev;
++ sp->link_timer.expires = jiffies + HZ;
++
++ add_timer(&sp->link_timer);
++ return 0;
++}
++
++static void ar231x_link_timer_fn(unsigned long data)
++{
++ struct net_device *dev = (struct net_device *)data;
++ struct ar231x_private *sp = netdev_priv(dev);
++
++ /**
++ * See if the link status changed.
++ * This was needed to make sure we set the PHY to the
++ * autonegotiated value of half or full duplex.
++ */
++ ar231x_check_link(dev);
++
++ /**
++ * Loop faster when we don't have link.
++ * This was needed to speed up the AP bootstrap time.
++ */
++ if (sp->link == 0)
++ mod_timer(&sp->link_timer, jiffies + HZ / 2);
++ else
++ mod_timer(&sp->link_timer, jiffies + LINK_TIMER);
++}
++
++static void ar231x_check_link(struct net_device *dev)
++{
++ struct ar231x_private *sp = netdev_priv(dev);
++ u16 phy_data;
++
++ phy_data = ar231x_mdiobus_read(sp->mii_bus, sp->phy, MII_BMSR);
++ if (sp->phy_data != phy_data) {
++ if (phy_data & BMSR_LSTATUS) {
++ /**
++ * Link is present, ready link partner ability to
++ * deterine duplexity.
++ */
++ int duplex = 0;
++ u16 reg;
++
++ sp->link = 1;
++ reg = ar231x_mdiobus_read(sp->mii_bus, sp->phy,
++ MII_BMCR);
++ if (reg & BMCR_ANENABLE) {
++ /* auto neg enabled */
++ reg = ar231x_mdiobus_read(sp->mii_bus, sp->phy,
++ MII_LPA);
++ duplex = reg & (LPA_100FULL | LPA_10FULL) ?
++ 1 : 0;
++ } else {
++ /* no auto neg, just read duplex config */
++ duplex = (reg & BMCR_FULLDPLX) ? 1 : 0;
++ }
++
++ printk(KERN_INFO "%s: Configuring MAC for %s duplex\n",
++ dev->name, (duplex) ? "full" : "half");
++
++ if (duplex) {
++ /* full duplex */
++ sp->eth_regs->mac_control =
++ (sp->eth_regs->mac_control |
++ MAC_CONTROL_F) & ~MAC_CONTROL_DRO;
++ } else {
++ /* half duplex */
++ sp->eth_regs->mac_control =
++ (sp->eth_regs->mac_control |
++ MAC_CONTROL_DRO) & ~MAC_CONTROL_F;
++ }
++ } else {
++ /* no link */
++ sp->link = 0;
++ }
++ sp->phy_data = phy_data;
++ }
++}
++
++static int ar231x_reset_reg(struct net_device *dev)
++{
++ struct ar231x_private *sp = netdev_priv(dev);
++ unsigned int ethsal, ethsah;
++ unsigned int flags;
++
++ sp->cfg->reset_set(sp->cfg->reset_mac);
++ mdelay(10);
++ sp->cfg->reset_clear(sp->cfg->reset_mac);
++ mdelay(10);
++ sp->cfg->reset_set(sp->cfg->reset_phy);
++ mdelay(10);
++ sp->cfg->reset_clear(sp->cfg->reset_phy);
++ mdelay(10);
++
++ sp->dma_regs->bus_mode = (DMA_BUS_MODE_SWR);
++ mdelay(10);
++ sp->dma_regs->bus_mode =
++ ((32 << DMA_BUS_MODE_PBL_SHIFT) | DMA_BUS_MODE_BLE);
++
++ /* enable interrupts */
++ sp->dma_regs->intr_ena = DMA_STATUS_AIS | DMA_STATUS_NIS |
++ DMA_STATUS_RI | DMA_STATUS_TI |
++ DMA_STATUS_FBE;
++ sp->dma_regs->xmt_base = virt_to_phys(sp->tx_ring);
++ sp->dma_regs->rcv_base = virt_to_phys(sp->rx_ring);
++ sp->dma_regs->control =
++ (DMA_CONTROL_SR | DMA_CONTROL_ST | DMA_CONTROL_SF);
++
++ sp->eth_regs->flow_control = (FLOW_CONTROL_FCE);
++ sp->eth_regs->vlan_tag = (0x8100);
++
++ /* Enable Ethernet Interface */
++ flags = (MAC_CONTROL_TE | /* transmit enable */
++ MAC_CONTROL_PM | /* pass mcast */
++ MAC_CONTROL_F | /* full duplex */
++ MAC_CONTROL_HBD); /* heart beat disabled */
++
++ if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */
++ flags |= MAC_CONTROL_PR;
++ }
++ sp->eth_regs->mac_control = flags;
++
++ /* Set all Ethernet station address registers to their initial values */
++ ethsah = (((u_int) (dev->dev_addr[5]) << 8) & (u_int) 0x0000FF00) |
++ (((u_int) (dev->dev_addr[4]) << 0) & (u_int) 0x000000FF);
++
++ ethsal = (((u_int) (dev->dev_addr[3]) << 24) & (u_int) 0xFF000000) |
++ (((u_int) (dev->dev_addr[2]) << 16) & (u_int) 0x00FF0000) |
++ (((u_int) (dev->dev_addr[1]) << 8) & (u_int) 0x0000FF00) |
++ (((u_int) (dev->dev_addr[0]) << 0) & (u_int) 0x000000FF);
++
++ sp->eth_regs->mac_addr[0] = ethsah;
++ sp->eth_regs->mac_addr[1] = ethsal;
++
++ mdelay(10);
++
++ return 0;
++}
++
++static int ar231x_init(struct net_device *dev)
++{
++ struct ar231x_private *sp = netdev_priv(dev);
++ int ecode = 0;
++
++ /* Allocate descriptors */
++ if (ar231x_allocate_descriptors(dev)) {
++ printk("%s: %s: ar231x_allocate_descriptors failed\n",
++ dev->name, __func__);
++ ecode = -EAGAIN;
++ goto init_error;
++ }
++
++ /* Get the memory for the skb rings */
++ if (sp->rx_skb == NULL) {
++ sp->rx_skb =
++ kmalloc(sizeof(struct sk_buff *) * AR2313_DESCR_ENTRIES,
++ GFP_KERNEL);
++ if (!(sp->rx_skb)) {
++ printk("%s: %s: rx_skb kmalloc failed\n",
++ dev->name, __func__);
++ ecode = -EAGAIN;
++ goto init_error;
++ }
++ }
++ memset(sp->rx_skb, 0, sizeof(struct sk_buff *) * AR2313_DESCR_ENTRIES);
++
++ if (sp->tx_skb == NULL) {
++ sp->tx_skb =
++ kmalloc(sizeof(struct sk_buff *) * AR2313_DESCR_ENTRIES,
++ GFP_KERNEL);
++ if (!(sp->tx_skb)) {
++ printk("%s: %s: tx_skb kmalloc failed\n",
++ dev->name, __func__);
++ ecode = -EAGAIN;
++ goto init_error;
++ }
++ }
++ memset(sp->tx_skb, 0, sizeof(struct sk_buff *) * AR2313_DESCR_ENTRIES);
++
++ /**
++ * Set tx_csm before we start receiving interrupts, otherwise
++ * the interrupt handler might think it is supposed to process
++ * tx ints before we are up and running, which may cause a null
++ * pointer access in the int handler.
++ */
++ sp->rx_skbprd = 0;
++ sp->cur_rx = 0;
++ sp->tx_prd = 0;
++ sp->tx_csm = 0;
++
++ /* Zero the stats before starting the interface */
++ memset(&dev->stats, 0, sizeof(dev->stats));
++
++ /**
++ * We load the ring here as there seem to be no way to tell the
++ * firmware to wipe the ring without re-initializing it.
++ */
++ ar231x_load_rx_ring(dev, RX_RING_SIZE);
++
++ /* Init hardware */
++ ar231x_reset_reg(dev);
++
++ /* Get the IRQ */
++ ecode = request_irq(dev->irq, &ar231x_interrupt, 0,
++ dev->name, dev);
++ if (ecode) {
++ printk(KERN_WARNING "%s: %s: Requested IRQ %d is busy\n",
++ dev->name, __func__, dev->irq);
++ goto init_error;
++ }
++
++ tasklet_enable(&sp->rx_tasklet);
++
++ return 0;
++
++init_error:
++ ar231x_init_cleanup(dev);
++ return ecode;
++}
++
++/**
++ * Load the rx ring.
++ *
++ * Loading rings is safe without holding the spin lock since this is
++ * done only before the device is enabled, thus no interrupts are
++ * generated and by the interrupt handler/tasklet handler.
++ */
++static void ar231x_load_rx_ring(struct net_device *dev, int nr_bufs)
++{
++ struct ar231x_private *sp = netdev_priv(dev);
++ short i, idx;
++
++ idx = sp->rx_skbprd;
++
++ for (i = 0; i < nr_bufs; i++) {
++ struct sk_buff *skb;
++ ar231x_descr_t *rd;
++
++ if (sp->rx_skb[idx])
++ break;
++
++ skb = netdev_alloc_skb_ip_align(dev, AR2313_BUFSIZE);
++ if (!skb) {
++ printk("\n\n\n\n %s: No memory in system\n\n\n\n",
++ __func__);
++ break;
++ }
++
++ /* Make sure IP header starts on a fresh cache line */
++ skb->dev = dev;
++ sp->rx_skb[idx] = skb;
++
++ rd = (ar231x_descr_t *)&sp->rx_ring[idx];
++
++ /* initialize dma descriptor */
++ rd->devcs = ((AR2313_BUFSIZE << DMA_RX1_BSIZE_SHIFT) |
++ DMA_RX1_CHAINED);
++ rd->addr = virt_to_phys(skb->data);
++ rd->descr = virt_to_phys(&sp->rx_ring[DSC_NEXT(idx)]);
++ rd->status = DMA_RX_OWN;
++
++ idx = DSC_NEXT(idx);
++ }
++
++ if (i)
++ sp->rx_skbprd = idx;
++}
++
++#define AR2313_MAX_PKTS_PER_CALL 64
++
++static int ar231x_rx_int(struct net_device *dev)
++{
++ struct ar231x_private *sp = netdev_priv(dev);
++ struct sk_buff *skb, *skb_new;
++ ar231x_descr_t *rxdesc;
++ unsigned int status;
++ u32 idx;
++ int pkts = 0;
++ int rval;
++
++ idx = sp->cur_rx;
++
++ /* process at most the entire ring and then wait for another int */
++ while (1) {
++ rxdesc = &sp->rx_ring[idx];
++ status = rxdesc->status;
++
++ if (status & DMA_RX_OWN) {
++ /* SiByte owns descriptor or descr not yet filled in */
++ rval = 0;
++ break;
++ }
++
++ if (++pkts > AR2313_MAX_PKTS_PER_CALL) {
++ rval = 1;
++ break;
++ }
++
++ if ((status & DMA_RX_ERROR) && !(status & DMA_RX_LONG)) {
++ dev->stats.rx_errors++;
++ dev->stats.rx_dropped++;
++
++ /* add statistics counters */
++ if (status & DMA_RX_ERR_CRC)
++ dev->stats.rx_crc_errors++;
++ if (status & DMA_RX_ERR_COL)
++ dev->stats.rx_over_errors++;
++ if (status & DMA_RX_ERR_LENGTH)
++ dev->stats.rx_length_errors++;
++ if (status & DMA_RX_ERR_RUNT)
++ dev->stats.rx_over_errors++;
++ if (status & DMA_RX_ERR_DESC)
++ dev->stats.rx_over_errors++;
++
++ } else {
++ /* alloc new buffer. */
++ skb_new = netdev_alloc_skb_ip_align(dev,
++ AR2313_BUFSIZE);
++ if (skb_new != NULL) {
++ skb = sp->rx_skb[idx];
++ /* set skb */
++ skb_put(skb, ((status >> DMA_RX_LEN_SHIFT) &
++ 0x3fff) - CRC_LEN);
++
++ dev->stats.rx_bytes += skb->len;
++ skb->protocol = eth_type_trans(skb, dev);
++ /* pass the packet to upper layers */
++ netif_rx(skb);
++
++ skb_new->dev = dev;
++ /* reset descriptor's curr_addr */
++ rxdesc->addr = virt_to_phys(skb_new->data);
++
++ dev->stats.rx_packets++;
++ sp->rx_skb[idx] = skb_new;
++ } else {
++ dev->stats.rx_dropped++;
++ }
++ }
++
++ rxdesc->devcs = ((AR2313_BUFSIZE << DMA_RX1_BSIZE_SHIFT) |
++ DMA_RX1_CHAINED);
++ rxdesc->status = DMA_RX_OWN;
++
++ idx = DSC_NEXT(idx);
++ }
++
++ sp->cur_rx = idx;
++
++ return rval;
++}
++
++static void ar231x_tx_int(struct net_device *dev)
++{
++ struct ar231x_private *sp = netdev_priv(dev);
++ u32 idx;
++ struct sk_buff *skb;
++ ar231x_descr_t *txdesc;
++ unsigned int status = 0;
++
++ idx = sp->tx_csm;
++
++ while (idx != sp->tx_prd) {
++ txdesc = &sp->tx_ring[idx];
++ status = txdesc->status;
++
++ if (status & DMA_TX_OWN) {
++ /* ar231x dma still owns descr */
++ break;
++ }
++ /* done with this descriptor */
++ dma_unmap_single(NULL, txdesc->addr,
++ txdesc->devcs & DMA_TX1_BSIZE_MASK,
++ DMA_TO_DEVICE);
++ txdesc->status = 0;
++
++ if (status & DMA_TX_ERROR) {
++ dev->stats.tx_errors++;
++ dev->stats.tx_dropped++;
++ if (status & DMA_TX_ERR_UNDER)
++ dev->stats.tx_fifo_errors++;
++ if (status & DMA_TX_ERR_HB)
++ dev->stats.tx_heartbeat_errors++;
++ if (status & (DMA_TX_ERR_LOSS | DMA_TX_ERR_LINK))
++ dev->stats.tx_carrier_errors++;
++ if (status & (DMA_TX_ERR_LATE | DMA_TX_ERR_COL |
++ DMA_TX_ERR_JABBER | DMA_TX_ERR_DEFER))
++ dev->stats.tx_aborted_errors++;
++ } else {
++ /* transmit OK */
++ dev->stats.tx_packets++;
++ }
++
++ skb = sp->tx_skb[idx];
++ sp->tx_skb[idx] = NULL;
++ idx = DSC_NEXT(idx);
++ dev->stats.tx_bytes += skb->len;
++ dev_kfree_skb_irq(skb);
++ }
++
++ sp->tx_csm = idx;
++}
++
++static void rx_tasklet_func(unsigned long data)
++{
++ struct net_device *dev = (struct net_device *)data;
++ struct ar231x_private *sp = netdev_priv(dev);
++
++ if (sp->unloading)
++ return;
++
++ if (ar231x_rx_int(dev)) {
++ tasklet_hi_schedule(&sp->rx_tasklet);
++ } else {
++ unsigned long flags;
++
++ spin_lock_irqsave(&sp->lock, flags);
++ sp->dma_regs->intr_ena |= DMA_STATUS_RI;
++ spin_unlock_irqrestore(&sp->lock, flags);
++ }
++}
++
++static void rx_schedule(struct net_device *dev)
++{
++ struct ar231x_private *sp = netdev_priv(dev);
++
++ sp->dma_regs->intr_ena &= ~DMA_STATUS_RI;
++
++ tasklet_hi_schedule(&sp->rx_tasklet);
++}
++
++static irqreturn_t ar231x_interrupt(int irq, void *dev_id)
++{
++ struct net_device *dev = (struct net_device *)dev_id;
++ struct ar231x_private *sp = netdev_priv(dev);
++ unsigned int status, enabled;
++
++ /* clear interrupt */
++ /* Don't clear RI bit if currently disabled */
++ status = sp->dma_regs->status;
++ enabled = sp->dma_regs->intr_ena;
++ sp->dma_regs->status = status & enabled;
++
++ if (status & DMA_STATUS_NIS) {
++ /* normal status */
++ /**
++ * Don't schedule rx processing if interrupt
++ * is already disabled.
++ */
++ if (status & enabled & DMA_STATUS_RI) {
++ /* receive interrupt */
++ rx_schedule(dev);
++ }
++ if (status & DMA_STATUS_TI) {
++ /* transmit interrupt */
++ ar231x_tx_int(dev);
++ }
++ }
++
++ /* abnormal status */
++ if (status & (DMA_STATUS_FBE | DMA_STATUS_TPS))
++ ar231x_restart(dev);
++
++ return IRQ_HANDLED;
++}
++
++static int ar231x_open(struct net_device *dev)
++{
++ struct ar231x_private *sp = netdev_priv(dev);
++ unsigned int ethsal, ethsah;
++
++ /* reset the hardware, in case the MAC address changed */
++ ethsah = (((u_int) (dev->dev_addr[5]) << 8) & (u_int) 0x0000FF00) |
++ (((u_int) (dev->dev_addr[4]) << 0) & (u_int) 0x000000FF);
++
++ ethsal = (((u_int) (dev->dev_addr[3]) << 24) & (u_int) 0xFF000000) |
++ (((u_int) (dev->dev_addr[2]) << 16) & (u_int) 0x00FF0000) |
++ (((u_int) (dev->dev_addr[1]) << 8) & (u_int) 0x0000FF00) |
++ (((u_int) (dev->dev_addr[0]) << 0) & (u_int) 0x000000FF);
++
++ sp->eth_regs->mac_addr[0] = ethsah;
++ sp->eth_regs->mac_addr[1] = ethsal;
++
++ mdelay(10);
++
++ dev->mtu = 1500;
++ netif_start_queue(dev);
++
++ sp->eth_regs->mac_control |= MAC_CONTROL_RE;
++
++ return 0;
++}
++
++static void ar231x_tx_timeout(struct net_device *dev)
++{
++ struct ar231x_private *sp = netdev_priv(dev);
++ unsigned long flags;
++
++ spin_lock_irqsave(&sp->lock, flags);
++ ar231x_restart(dev);
++ spin_unlock_irqrestore(&sp->lock, flags);
++}
++
++static void ar231x_halt(struct net_device *dev)
++{
++ struct ar231x_private *sp = netdev_priv(dev);
++ int j;
++
++ tasklet_disable(&sp->rx_tasklet);
++
++ /* kill the MAC */
++ sp->eth_regs->mac_control &= ~(MAC_CONTROL_RE | /* disable Receives */
++ MAC_CONTROL_TE); /* disable Transmits */
++ /* stop dma */
++ sp->dma_regs->control = 0;
++ sp->dma_regs->bus_mode = DMA_BUS_MODE_SWR;
++
++ /* place phy and MAC in reset */
++ sp->cfg->reset_set(sp->cfg->reset_mac);
++ sp->cfg->reset_set(sp->cfg->reset_phy);
++
++ /* free buffers on tx ring */
++ for (j = 0; j < AR2313_DESCR_ENTRIES; j++) {
++ struct sk_buff *skb;
++ ar231x_descr_t *txdesc;
++
++ txdesc = &sp->tx_ring[j];
++ txdesc->descr = 0;
++
++ skb = sp->tx_skb[j];
++ if (skb) {
++ dev_kfree_skb(skb);
++ sp->tx_skb[j] = NULL;
++ }
++ }
++}
++
++/**
++ * close should do nothing. Here's why. It's called when
++ * 'ifconfig bond0 down' is run. If it calls free_irq then
++ * the irq is gone forever ! When bond0 is made 'up' again,
++ * the ar231x_open () does not call request_irq (). Worse,
++ * the call to ar231x_halt() generates a WDOG reset due to
++ * the write to reset register and the box reboots.
++ * Commenting this out is good since it allows the
++ * system to resume when bond0 is made up again.
++ */
++static int ar231x_close(struct net_device *dev)
++{
++#if 0
++ /* Disable interrupts */
++ disable_irq(dev->irq);
++
++ /**
++ * Without (or before) releasing irq and stopping hardware, this
++ * is an absolute non-sense, by the way. It will be reset instantly
++ * by the first irq.
++ */
++ netif_stop_queue(dev);
++
++ /* stop the MAC and DMA engines */
++ ar231x_halt(dev);
++
++ /* release the interrupt */
++ free_irq(dev->irq, dev);
++
++#endif
++ return 0;
++}
++
++static int ar231x_start_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++ struct ar231x_private *sp = netdev_priv(dev);
++ ar231x_descr_t *td;
++ u32 idx;
++
++ idx = sp->tx_prd;
++ td = &sp->tx_ring[idx];
++
++ if (td->status & DMA_TX_OWN) {
++ /* free skbuf and lie to the caller that we sent it out */
++ dev->stats.tx_dropped++;
++ dev_kfree_skb(skb);
++
++ /* restart transmitter in case locked */
++ sp->dma_regs->xmt_poll = 0;
++ return 0;
++ }
++
++ /* Setup the transmit descriptor. */
++ td->devcs = ((skb->len << DMA_TX1_BSIZE_SHIFT) |
++ (DMA_TX1_LS | DMA_TX1_IC | DMA_TX1_CHAINED));
++ td->addr = dma_map_single(NULL, skb->data, skb->len, DMA_TO_DEVICE);
++ td->status = DMA_TX_OWN;
++
++ /* kick transmitter last */
++ sp->dma_regs->xmt_poll = 0;
++
++ sp->tx_skb[idx] = skb;
++ idx = DSC_NEXT(idx);
++ sp->tx_prd = idx;
++
++ return 0;
++}
++
++static int ar231x_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
++{
++ struct ar231x_private *sp = netdev_priv(dev);
++
++ switch (cmd) {
++ case SIOCGMIIPHY:
++ case SIOCGMIIREG:
++ case SIOCSMIIREG:
++ return phy_mii_ioctl(sp->phy_dev, ifr, cmd);
++
++ default:
++ break;
++ }
++
++ return -EOPNOTSUPP;
++}
++
++static void ar231x_adjust_link(struct net_device *dev)
++{
++ struct ar231x_private *sp = netdev_priv(dev);
++ unsigned int mc;
++
++ if (!sp->phy_dev->link)
++ return;
++
++ if (sp->phy_dev->duplex != sp->oldduplex) {
++ mc = readl(&sp->eth_regs->mac_control);
++ mc &= ~(MAC_CONTROL_F | MAC_CONTROL_DRO);
++ if (sp->phy_dev->duplex)
++ mc |= MAC_CONTROL_F;
++ else
++ mc |= MAC_CONTROL_DRO;
++ writel(mc, &sp->eth_regs->mac_control);
++ sp->oldduplex = sp->phy_dev->duplex;
++ }
++}
++
++#define MII_ADDR(phy, reg) \
++ ((reg << MII_ADDR_REG_SHIFT) | (phy << MII_ADDR_PHY_SHIFT))
++
++static int
++ar231x_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
++{
++ struct net_device *const dev = bus->priv;
++ struct ar231x_private *sp = netdev_priv(dev);
++ volatile MII *ethernet = sp->phy_regs;
++
++ ethernet->mii_addr = MII_ADDR(phy_addr, regnum);
++ while (ethernet->mii_addr & MII_ADDR_BUSY)
++ ;
++ return ethernet->mii_data >> MII_DATA_SHIFT;
++}
++
++static int
++ar231x_mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum, u16 value)
++{
++ struct net_device *const dev = bus->priv;
++ struct ar231x_private *sp = netdev_priv(dev);
++ volatile MII *ethernet = sp->phy_regs;
++
++ while (ethernet->mii_addr & MII_ADDR_BUSY)
++ ;
++ ethernet->mii_data = value << MII_DATA_SHIFT;
++ ethernet->mii_addr = MII_ADDR(phy_addr, regnum) | MII_ADDR_WRITE;
++
++ return 0;
++}
++
++static int ar231x_mdiobus_reset(struct mii_bus *bus)
++{
++ struct net_device *const dev = bus->priv;
++
++ ar231x_reset_reg(dev);
++
++ return 0;
++}
++
++static int ar231x_mdiobus_probe(struct net_device *dev)
++{
++ struct ar231x_private *const sp = netdev_priv(dev);
++ struct phy_device *phydev = NULL;
++ int phy_addr;
++
++ /* find the first (lowest address) PHY on the current MAC's MII bus */
++ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++)
++ if (sp->mii_bus->phy_map[phy_addr]) {
++ phydev = sp->mii_bus->phy_map[phy_addr];
++ sp->phy = phy_addr;
++ break; /* break out with first one found */
++ }
++
++ if (!phydev) {
++ printk(KERN_ERR "ar231x: %s: no PHY found\n", dev->name);
++ return -1;
++ }
++
++ /* now we are supposed to have a proper phydev, to attach to... */
++ BUG_ON(!phydev);
++ BUG_ON(phydev->attached_dev);
++
++ phydev = phy_connect(dev, dev_name(&phydev->dev), &ar231x_adjust_link,
++ PHY_INTERFACE_MODE_MII);
++
++ if (IS_ERR(phydev)) {
++ printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
++ return PTR_ERR(phydev);
++ }
++
++ /* mask with MAC supported features */
++ phydev->supported &= (SUPPORTED_10baseT_Half
++ | SUPPORTED_10baseT_Full
++ | SUPPORTED_100baseT_Half
++ | SUPPORTED_100baseT_Full
++ | SUPPORTED_Autoneg
++ /* | SUPPORTED_Pause | SUPPORTED_Asym_Pause */
++ | SUPPORTED_MII
++ | SUPPORTED_TP);
++
++ phydev->advertising = phydev->supported;
++
++ sp->oldduplex = -1;
++ sp->phy_dev = phydev;
++
++ printk(KERN_INFO "%s: attached PHY driver [%s] (mii_bus:phy_addr=%s)\n",
++ dev->name, phydev->drv->name, dev_name(&phydev->dev));
++
++ return 0;
++}
++
+--- /dev/null
++++ b/drivers/net/ethernet/atheros/ar231x/ar231x.h
+@@ -0,0 +1,288 @@
++/*
++ * ar231x.h: Linux driver for the Atheros AR231x Ethernet device.
++ *
++ * Copyright (C) 2004 by Sameer Dekate <sdekate@arubanetworks.com>
++ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
++ * Copyright (C) 2006-2009 Felix Fietkau <nbd@nbd.name>
++ *
++ * Thanks to Atheros for providing hardware and documentation
++ * enabling me to write this driver.
++ *
++ * 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.
++ */
++
++#ifndef _AR2313_H_
++#define _AR2313_H_
++
++#include <linux/interrupt.h>
++#include <generated/autoconf.h>
++#include <linux/bitops.h>
++#include <ath25_platform.h>
++
++/* probe link timer - 5 secs */
++#define LINK_TIMER (5*HZ)
++
++#define IS_DMA_TX_INT(X) (((X) & (DMA_STATUS_TI)) != 0)
++#define IS_DMA_RX_INT(X) (((X) & (DMA_STATUS_RI)) != 0)
++#define IS_DRIVER_OWNED(X) (((X) & (DMA_TX_OWN)) == 0)
++
++#define AR2313_TX_TIMEOUT (HZ/4)
++
++/* Rings */
++#define DSC_RING_ENTRIES_SIZE (AR2313_DESCR_ENTRIES * sizeof(struct desc))
++#define DSC_NEXT(idx) ((idx + 1) & (AR2313_DESCR_ENTRIES - 1))
++
++#define AR2313_MBGET 2
++#define AR2313_MBSET 3
++#define AR2313_PCI_RECONFIG 4
++#define AR2313_PCI_DUMP 5
++#define AR2313_TEST_PANIC 6
++#define AR2313_TEST_NULLPTR 7
++#define AR2313_READ_DATA 8
++#define AR2313_WRITE_DATA 9
++#define AR2313_GET_VERSION 10
++#define AR2313_TEST_HANG 11
++#define AR2313_SYNC 12
++
++#define DMA_RX_ERR_CRC BIT(1)
++#define DMA_RX_ERR_DRIB BIT(2)
++#define DMA_RX_ERR_MII BIT(3)
++#define DMA_RX_EV2 BIT(5)
++#define DMA_RX_ERR_COL BIT(6)
++#define DMA_RX_LONG BIT(7)
++#define DMA_RX_LS BIT(8) /* last descriptor */
++#define DMA_RX_FS BIT(9) /* first descriptor */
++#define DMA_RX_MF BIT(10) /* multicast frame */
++#define DMA_RX_ERR_RUNT BIT(11) /* runt frame */
++#define DMA_RX_ERR_LENGTH BIT(12) /* length error */
++#define DMA_RX_ERR_DESC BIT(14) /* descriptor error */
++#define DMA_RX_ERROR BIT(15) /* error summary */
++#define DMA_RX_LEN_MASK 0x3fff0000
++#define DMA_RX_LEN_SHIFT 16
++#define DMA_RX_FILT BIT(30)
++#define DMA_RX_OWN BIT(31) /* desc owned by DMA controller */
++
++#define DMA_RX1_BSIZE_MASK 0x000007ff
++#define DMA_RX1_BSIZE_SHIFT 0
++#define DMA_RX1_CHAINED BIT(24)
++#define DMA_RX1_RER BIT(25)
++
++#define DMA_TX_ERR_UNDER BIT(1) /* underflow error */
++#define DMA_TX_ERR_DEFER BIT(2) /* excessive deferral */
++#define DMA_TX_COL_MASK 0x78
++#define DMA_TX_COL_SHIFT 3
++#define DMA_TX_ERR_HB BIT(7) /* hearbeat failure */
++#define DMA_TX_ERR_COL BIT(8) /* excessive collisions */
++#define DMA_TX_ERR_LATE BIT(9) /* late collision */
++#define DMA_TX_ERR_LINK BIT(10) /* no carrier */
++#define DMA_TX_ERR_LOSS BIT(11) /* loss of carrier */
++#define DMA_TX_ERR_JABBER BIT(14) /* transmit jabber timeout */
++#define DMA_TX_ERROR BIT(15) /* frame aborted */
++#define DMA_TX_OWN BIT(31) /* descr owned by DMA controller */
++
++#define DMA_TX1_BSIZE_MASK 0x000007ff
++#define DMA_TX1_BSIZE_SHIFT 0
++#define DMA_TX1_CHAINED BIT(24) /* chained descriptors */
++#define DMA_TX1_TER BIT(25) /* transmit end of ring */
++#define DMA_TX1_FS BIT(29) /* first segment */
++#define DMA_TX1_LS BIT(30) /* last segment */
++#define DMA_TX1_IC BIT(31) /* interrupt on completion */
++
++#define RCVPKT_LENGTH(X) (X >> 16) /* Received pkt Length */
++
++#define MAC_CONTROL_RE BIT(2) /* receive enable */
++#define MAC_CONTROL_TE BIT(3) /* transmit enable */
++#define MAC_CONTROL_DC BIT(5) /* Deferral check */
++#define MAC_CONTROL_ASTP BIT(8) /* Auto pad strip */
++#define MAC_CONTROL_DRTY BIT(10) /* Disable retry */
++#define MAC_CONTROL_DBF BIT(11) /* Disable bcast frames */
++#define MAC_CONTROL_LCC BIT(12) /* late collision ctrl */
++#define MAC_CONTROL_HP BIT(13) /* Hash Perfect filtering */
++#define MAC_CONTROL_HASH BIT(14) /* Unicast hash filtering */
++#define MAC_CONTROL_HO BIT(15) /* Hash only filtering */
++#define MAC_CONTROL_PB BIT(16) /* Pass Bad frames */
++#define MAC_CONTROL_IF BIT(17) /* Inverse filtering */
++#define MAC_CONTROL_PR BIT(18) /* promis mode (valid frames only) */
++#define MAC_CONTROL_PM BIT(19) /* pass multicast */
++#define MAC_CONTROL_F BIT(20) /* full-duplex */
++#define MAC_CONTROL_DRO BIT(23) /* Disable Receive Own */
++#define MAC_CONTROL_HBD BIT(28) /* heart-beat disabled (MUST BE SET) */
++#define MAC_CONTROL_BLE BIT(30) /* big endian mode */
++#define MAC_CONTROL_RA BIT(31) /* rcv all (valid and invalid frames) */
++
++#define MII_ADDR_BUSY BIT(0)
++#define MII_ADDR_WRITE BIT(1)
++#define MII_ADDR_REG_SHIFT 6
++#define MII_ADDR_PHY_SHIFT 11
++#define MII_DATA_SHIFT 0
++
++#define FLOW_CONTROL_FCE BIT(1)
++
++#define DMA_BUS_MODE_SWR BIT(0) /* software reset */
++#define DMA_BUS_MODE_BLE BIT(7) /* big endian mode */
++#define DMA_BUS_MODE_PBL_SHIFT 8 /* programmable burst length 32 */
++#define DMA_BUS_MODE_DBO BIT(20) /* big-endian descriptors */
++
++#define DMA_STATUS_TI BIT(0) /* transmit interrupt */
++#define DMA_STATUS_TPS BIT(1) /* transmit process stopped */
++#define DMA_STATUS_TU BIT(2) /* transmit buffer unavailable */
++#define DMA_STATUS_TJT BIT(3) /* transmit buffer timeout */
++#define DMA_STATUS_UNF BIT(5) /* transmit underflow */
++#define DMA_STATUS_RI BIT(6) /* receive interrupt */
++#define DMA_STATUS_RU BIT(7) /* receive buffer unavailable */
++#define DMA_STATUS_RPS BIT(8) /* receive process stopped */
++#define DMA_STATUS_ETI BIT(10) /* early transmit interrupt */
++#define DMA_STATUS_FBE BIT(13) /* fatal bus interrupt */
++#define DMA_STATUS_ERI BIT(14) /* early receive interrupt */
++#define DMA_STATUS_AIS BIT(15) /* abnormal interrupt summary */
++#define DMA_STATUS_NIS BIT(16) /* normal interrupt summary */
++#define DMA_STATUS_RS_SHIFT 17 /* receive process state */
++#define DMA_STATUS_TS_SHIFT 20 /* transmit process state */
++#define DMA_STATUS_EB_SHIFT 23 /* error bits */
++
++#define DMA_CONTROL_SR BIT(1) /* start receive */
++#define DMA_CONTROL_ST BIT(13) /* start transmit */
++#define DMA_CONTROL_SF BIT(21) /* store and forward */
++
++typedef struct {
++ volatile unsigned int status; /* OWN, Device control and status. */
++ volatile unsigned int devcs; /* pkt Control bits + Length */
++ volatile unsigned int addr; /* Current Address. */
++ volatile unsigned int descr; /* Next descriptor in chain. */
++} ar231x_descr_t;
++
++/**
++ * New Combo structure for Both Eth0 AND eth1
++ *
++ * Don't directly access MII related regs since phy chip could be actually
++ * connected to another ethernet block.
++ */
++typedef struct {
++ volatile unsigned int mac_control; /* 0x00 */
++ volatile unsigned int mac_addr[2]; /* 0x04 - 0x08 */
++ volatile unsigned int mcast_table[2]; /* 0x0c - 0x10 */
++ volatile unsigned int __mii_addr; /* 0x14 */
++ volatile unsigned int __mii_data; /* 0x18 */
++ volatile unsigned int flow_control; /* 0x1c */
++ volatile unsigned int vlan_tag; /* 0x20 */
++ volatile unsigned int pad[7]; /* 0x24 - 0x3c */
++ volatile unsigned int ucast_table[8]; /* 0x40-0x5c */
++} ETHERNET_STRUCT;
++
++typedef struct {
++ volatile unsigned int mii_addr;
++ volatile unsigned int mii_data;
++} MII;
++
++/********************************************************************
++ * Interrupt controller
++ ********************************************************************/
++
++typedef struct {
++ volatile unsigned int wdog_control; /* 0x08 */
++ volatile unsigned int wdog_timer; /* 0x0c */
++ volatile unsigned int misc_status; /* 0x10 */
++ volatile unsigned int misc_mask; /* 0x14 */
++ volatile unsigned int global_status; /* 0x18 */
++ volatile unsigned int reserved; /* 0x1c */
++ volatile unsigned int reset_control; /* 0x20 */
++} INTERRUPT;
++
++/********************************************************************
++ * DMA controller
++ ********************************************************************/
++typedef struct {
++ volatile unsigned int bus_mode; /* 0x00 (CSR0) */
++ volatile unsigned int xmt_poll; /* 0x04 (CSR1) */
++ volatile unsigned int rcv_poll; /* 0x08 (CSR2) */
++ volatile unsigned int rcv_base; /* 0x0c (CSR3) */
++ volatile unsigned int xmt_base; /* 0x10 (CSR4) */
++ volatile unsigned int status; /* 0x14 (CSR5) */
++ volatile unsigned int control; /* 0x18 (CSR6) */
++ volatile unsigned int intr_ena; /* 0x1c (CSR7) */
++ volatile unsigned int rcv_missed; /* 0x20 (CSR8) */
++ volatile unsigned int reserved[11]; /* 0x24-0x4c (CSR9-19) */
++ volatile unsigned int cur_tx_buf_addr; /* 0x50 (CSR20) */
++ volatile unsigned int cur_rx_buf_addr; /* 0x50 (CSR21) */
++} DMA;
++
++/**
++ * Struct private for the Sibyte.
++ *
++ * Elements are grouped so variables used by the tx handling goes
++ * together, and will go into the same cache lines etc. in order to
++ * avoid cache line contention between the rx and tx handling on SMP.
++ *
++ * Frequently accessed variables are put at the beginning of the
++ * struct to help the compiler generate better/shorter code.
++ */
++struct ar231x_private {
++ struct net_device *dev;
++ int version;
++ u32 mb[2];
++
++ volatile MII *phy_regs;
++ volatile ETHERNET_STRUCT *eth_regs;
++ volatile DMA *dma_regs;
++ struct ar231x_eth *cfg;
++
++ spinlock_t lock; /* Serialise access to device */
++
++ /* RX and TX descriptors, must be adjacent */
++ ar231x_descr_t *rx_ring;
++ ar231x_descr_t *tx_ring;
++
++ struct sk_buff **rx_skb;
++ struct sk_buff **tx_skb;
++
++ /* RX elements */
++ u32 rx_skbprd;
++ u32 cur_rx;
++
++ /* TX elements */
++ u32 tx_prd;
++ u32 tx_csm;
++
++ /* Misc elements */
++ char name[48];
++ struct {
++ u32 address;
++ u32 length;
++ char *mapping;
++ } desc;
++
++ struct timer_list link_timer;
++ unsigned short phy; /* merlot phy = 1, samsung phy = 0x1f */
++ unsigned short mac;
++ unsigned short link; /* 0 - link down, 1 - link up */
++ u16 phy_data;
++
++ struct tasklet_struct rx_tasklet;
++ int unloading;
++
++ struct phy_device *phy_dev;
++ struct mii_bus *mii_bus;
++ int oldduplex;
++};
++
++/* Prototypes */
++static int ar231x_init(struct net_device *dev);
++#ifdef TX_TIMEOUT
++static void ar231x_tx_timeout(struct net_device *dev);
++#endif
++static int ar231x_restart(struct net_device *dev);
++static void ar231x_load_rx_ring(struct net_device *dev, int bufs);
++static irqreturn_t ar231x_interrupt(int irq, void *dev_id);
++static int ar231x_open(struct net_device *dev);
++static int ar231x_start_xmit(struct sk_buff *skb, struct net_device *dev);
++static int ar231x_close(struct net_device *dev);
++static int ar231x_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
++static void ar231x_init_cleanup(struct net_device *dev);
++static int ar231x_setup_timer(struct net_device *dev);
++static void ar231x_link_timer_fn(unsigned long data);
++static void ar231x_check_link(struct net_device *dev);
++
++#endif /* _AR2313_H_ */
+--- a/arch/mips/ath25/ar2315_regs.h
++++ b/arch/mips/ath25/ar2315_regs.h
+@@ -57,6 +57,9 @@
+ #define AR2315_PCI_EXT_BASE 0x80000000 /* PCI external */
+ #define AR2315_PCI_EXT_SIZE 0x40000000
+
++/* MII registers offset inside Ethernet MMR region */
++#define AR2315_ENET0_MII_BASE (AR2315_ENET0_BASE + 0x14)
++
+ /*
+ * Configuration registers
+ */
+--- a/arch/mips/ath25/ar5312_regs.h
++++ b/arch/mips/ath25/ar5312_regs.h
+@@ -64,6 +64,10 @@
+ #define AR5312_AR5312_REV7 0x0057 /* AR5312 WMAC (AP30-040) */
+ #define AR5312_AR2313_REV8 0x0058 /* AR2313 WMAC (AP43-030) */
+
++/* MII registers offset inside Ethernet MMR region */
++#define AR5312_ENET0_MII_BASE (AR5312_ENET0_BASE + 0x14)
++#define AR5312_ENET1_MII_BASE (AR5312_ENET1_BASE + 0x14)
++
+ /* Reset/Timer Block Address Map */
+ #define AR5312_TIMER 0x0000 /* countdown timer */
+ #define AR5312_RELOAD 0x0004 /* timer reload value */
+--- a/arch/mips/ath25/ar2315.c
++++ b/arch/mips/ath25/ar2315.c
+@@ -136,6 +136,8 @@ static void ar2315_irq_dispatch(void)
+
+ if (pending & CAUSEF_IP3)
+ do_IRQ(AR2315_IRQ_WLAN0);
++ else if (pending & CAUSEF_IP4)
++ do_IRQ(AR2315_IRQ_ENET0);
+ #ifdef CONFIG_PCI_AR2315
+ else if (pending & CAUSEF_IP5)
+ do_IRQ(AR2315_IRQ_LCBUS_PCI);
+@@ -169,6 +171,29 @@ void __init ar2315_arch_init_irq(void)
+ ar2315_misc_irq_domain = domain;
+ }
+
++static void ar2315_device_reset_set(u32 mask)
++{
++ u32 val;
++
++ val = ar2315_rst_reg_read(AR2315_RESET);
++ ar2315_rst_reg_write(AR2315_RESET, val | mask);
++}
++
++static void ar2315_device_reset_clear(u32 mask)
++{
++ u32 val;
++
++ val = ar2315_rst_reg_read(AR2315_RESET);
++ ar2315_rst_reg_write(AR2315_RESET, val & ~mask);
++}
++
++static struct ar231x_eth ar2315_eth_data = {
++ .reset_set = ar2315_device_reset_set,
++ .reset_clear = ar2315_device_reset_clear,
++ .reset_mac = AR2315_RESET_ENET0,
++ .reset_phy = AR2315_RESET_EPHY0,
++};
++
+ static struct resource ar2315_gpio_res[] = {
+ {
+ .name = "ar2315-gpio",
+@@ -205,6 +230,11 @@ void __init ar2315_init_devices(void)
+ ar2315_gpio_res[1].end = ar2315_gpio_res[1].start;
+ platform_device_register(&ar2315_gpio);
+
++ ar2315_eth_data.macaddr = ath25_board.config->enet0_mac;
++ ath25_add_ethernet(0, AR2315_ENET0_BASE, "eth0_mii",
++ AR2315_ENET0_MII_BASE, AR2315_IRQ_ENET0,
++ &ar2315_eth_data);
++
+ ath25_add_wmac(0, AR2315_WLAN0_BASE, AR2315_IRQ_WLAN0);
+ }
+
+--- a/arch/mips/ath25/ar5312.c
++++ b/arch/mips/ath25/ar5312.c
+@@ -132,6 +132,10 @@ static void ar5312_irq_dispatch(void)
+
+ if (pending & CAUSEF_IP2)
+ do_IRQ(AR5312_IRQ_WLAN0);
++ else if (pending & CAUSEF_IP3)
++ do_IRQ(AR5312_IRQ_ENET0);
++ else if (pending & CAUSEF_IP4)
++ do_IRQ(AR5312_IRQ_ENET1);
+ else if (pending & CAUSEF_IP5)
+ do_IRQ(AR5312_IRQ_WLAN1);
+ else if (pending & CAUSEF_IP6)
+@@ -163,6 +167,36 @@ void __init ar5312_arch_init_irq(void)
+ ar5312_misc_irq_domain = domain;
+ }
+
++static void ar5312_device_reset_set(u32 mask)
++{
++ u32 val;
++
++ val = ar5312_rst_reg_read(AR5312_RESET);
++ ar5312_rst_reg_write(AR5312_RESET, val | mask);
++}
++
++static void ar5312_device_reset_clear(u32 mask)
++{
++ u32 val;
++
++ val = ar5312_rst_reg_read(AR5312_RESET);
++ ar5312_rst_reg_write(AR5312_RESET, val & ~mask);
++}
++
++static struct ar231x_eth ar5312_eth0_data = {
++ .reset_set = ar5312_device_reset_set,
++ .reset_clear = ar5312_device_reset_clear,
++ .reset_mac = AR5312_RESET_ENET0,
++ .reset_phy = AR5312_RESET_EPHY0,
++};
++
++static struct ar231x_eth ar5312_eth1_data = {
++ .reset_set = ar5312_device_reset_set,
++ .reset_clear = ar5312_device_reset_clear,
++ .reset_mac = AR5312_RESET_ENET1,
++ .reset_phy = AR5312_RESET_EPHY1,
++};
++
+ static struct physmap_flash_data ar5312_flash_data = {
+ .width = 2,
+ };
+@@ -243,6 +277,7 @@ static void __init ar5312_flash_init(voi
+ void __init ar5312_init_devices(void)
+ {
+ struct ath25_boarddata *config;
++ u8 *c;
+
+ ar5312_flash_init();
+
+@@ -266,8 +301,30 @@ void __init ar5312_init_devices(void)
+
+ platform_device_register(&ar5312_gpio);
+
++ /* Fix up MAC addresses if necessary */
++ if (is_broadcast_ether_addr(config->enet0_mac))
++ ether_addr_copy(config->enet0_mac, config->enet1_mac);
++
++ /* If ENET0 and ENET1 have the same mac address,
++ * increment the one from ENET1 */
++ if (ether_addr_equal(config->enet0_mac, config->enet1_mac)) {
++ c = config->enet1_mac + 5;
++ while ((c >= config->enet1_mac) && !(++(*c)))
++ c--;
++ }
++
+ switch (ath25_soc) {
+ case ATH25_SOC_AR5312:
++ ar5312_eth0_data.macaddr = config->enet0_mac;
++ ath25_add_ethernet(0, AR5312_ENET0_BASE, "eth0_mii",
++ AR5312_ENET0_MII_BASE, AR5312_IRQ_ENET0,
++ &ar5312_eth0_data);
++
++ ar5312_eth1_data.macaddr = config->enet1_mac;
++ ath25_add_ethernet(1, AR5312_ENET1_BASE, "eth1_mii",
++ AR5312_ENET1_MII_BASE, AR5312_IRQ_ENET1,
++ &ar5312_eth1_data);
++
+ if (!ath25_board.radio)
+ return;
+
+@@ -276,8 +333,18 @@ void __init ar5312_init_devices(void)
+
+ ath25_add_wmac(0, AR5312_WLAN0_BASE, AR5312_IRQ_WLAN0);
+ break;
++ /*
++ * AR2312/3 ethernet uses the PHY of ENET0, but the MAC
++ * of ENET1. Atheros calls it 'twisted' for a reason :)
++ */
+ case ATH25_SOC_AR2312:
+ case ATH25_SOC_AR2313:
++ ar5312_eth1_data.reset_phy = ar5312_eth0_data.reset_phy;
++ ar5312_eth1_data.macaddr = config->enet0_mac;
++ ath25_add_ethernet(1, AR5312_ENET1_BASE, "eth0_mii",
++ AR5312_ENET0_MII_BASE, AR5312_IRQ_ENET1,
++ &ar5312_eth1_data);
++
+ if (!ath25_board.radio)
+ return;
+ break;
+--- a/arch/mips/ath25/devices.h
++++ b/arch/mips/ath25/devices.h
+@@ -32,6 +32,8 @@ extern struct ar231x_board_config ath25_
+ extern void (*ath25_irq_dispatch)(void);
+
+ int ath25_find_config(phys_addr_t offset, unsigned long size);
++int ath25_add_ethernet(int nr, u32 base, const char *mii_name, u32 mii_base,
++ int irq, void *pdata);
+ void ath25_serial_setup(u32 mapbase, int irq, unsigned int uartclk);
+ int ath25_add_wmac(int nr, u32 base, int irq);
+
+--- a/arch/mips/ath25/devices.c
++++ b/arch/mips/ath25/devices.c
+@@ -12,6 +12,51 @@
+ struct ar231x_board_config ath25_board;
+ enum ath25_soc_type ath25_soc = ATH25_SOC_UNKNOWN;
+
++static struct resource ath25_eth0_res[] = {
++ {
++ .name = "eth0_membase",
++ .flags = IORESOURCE_MEM,
++ },
++ {
++ .name = "eth0_mii",
++ .flags = IORESOURCE_MEM,
++ },
++ {
++ .name = "eth0_irq",
++ .flags = IORESOURCE_IRQ,
++ }
++};
++
++static struct resource ath25_eth1_res[] = {
++ {
++ .name = "eth1_membase",
++ .flags = IORESOURCE_MEM,
++ },
++ {
++ .name = "eth1_mii",
++ .flags = IORESOURCE_MEM,
++ },
++ {
++ .name = "eth1_irq",
++ .flags = IORESOURCE_IRQ,
++ }
++};
++
++static struct platform_device ath25_eth[] = {
++ {
++ .id = 0,
++ .name = "ar231x-eth",
++ .resource = ath25_eth0_res,
++ .num_resources = ARRAY_SIZE(ath25_eth0_res)
++ },
++ {
++ .id = 1,
++ .name = "ar231x-eth",
++ .resource = ath25_eth1_res,
++ .num_resources = ARRAY_SIZE(ath25_eth1_res)
++ }
++};
++
+ static struct resource ath25_wmac0_res[] = {
+ {
+ .name = "wmac0_membase",
+@@ -70,6 +115,25 @@ const char *get_system_type(void)
+ return soc_type_strings[ath25_soc];
+ }
+
++int __init ath25_add_ethernet(int nr, u32 base, const char *mii_name,
++ u32 mii_base, int irq, void *pdata)
++{
++ struct resource *res;
++
++ ath25_eth[nr].dev.platform_data = pdata;
++ res = &ath25_eth[nr].resource[0];
++ res->start = base;
++ res->end = base + 0x2000 - 1;
++ res++;
++ res->name = mii_name;
++ res->start = mii_base;
++ res->end = mii_base + 8 - 1;
++ res++;
++ res->start = irq;
++ res->end = irq;
++ return platform_device_register(&ath25_eth[nr]);
++}
++
+ void __init ath25_serial_setup(u32 mapbase, int irq, unsigned int uartclk)
+ {
+ struct uart_port s;
+--- a/arch/mips/include/asm/mach-ath25/ath25_platform.h
++++ b/arch/mips/include/asm/mach-ath25/ath25_platform.h
+@@ -70,4 +70,15 @@ struct ar231x_board_config {
+ const char *radio;
+ };
+
++/*
++ * Platform device information for the Ethernet MAC
++ */
++struct ar231x_eth {
++ void (*reset_set)(u32);
++ void (*reset_clear)(u32);
++ u32 reset_mac;
++ u32 reset_phy;
++ char *macaddr;
++};
++
+ #endif /* __ASM_MACH_ATH25_PLATFORM_H */
diff --git a/target/linux/ath25/patches-4.4/120-spiflash.patch b/target/linux/ath25/patches-4.4/120-spiflash.patch
new file mode 100644
index 0000000000..91cb8bee74
--- /dev/null
+++ b/target/linux/ath25/patches-4.4/120-spiflash.patch
@@ -0,0 +1,634 @@
+--- a/drivers/mtd/devices/Kconfig
++++ b/drivers/mtd/devices/Kconfig
+@@ -120,6 +120,10 @@ config MTD_BCM47XXSFLASH
+ registered by bcma as platform devices. This enables driver for
+ serial flash memories (only read-only mode is implemented).
+
++config MTD_AR2315
++ tristate "Atheros AR2315+ SPI Flash support"
++ depends on SOC_AR2315
++
+ config MTD_SLRAM
+ tristate "Uncached system RAM"
+ help
+--- a/drivers/mtd/devices/Makefile
++++ b/drivers/mtd/devices/Makefile
+@@ -14,6 +14,7 @@ obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataf
+ obj-$(CONFIG_MTD_M25P80) += m25p80.o
+ obj-$(CONFIG_MTD_SPEAR_SMI) += spear_smi.o
+ obj-$(CONFIG_MTD_SST25L) += sst25l.o
++obj-$(CONFIG_MTD_AR2315) += ar2315.o
+ obj-$(CONFIG_MTD_BCM47XXSFLASH) += bcm47xxsflash.o
+ obj-$(CONFIG_MTD_ST_SPI_FSM) += st_spi_fsm.o
+ obj-$(CONFIG_MTD_POWERNV_FLASH) += powernv_flash.o
+--- /dev/null
++++ b/drivers/mtd/devices/ar2315.c
+@@ -0,0 +1,459 @@
++
++/*
++ * MTD driver for the SPI Flash Memory support on Atheros AR2315
++ *
++ * Copyright (c) 2005-2006 Atheros Communications Inc.
++ * Copyright (C) 2006-2007 FON Technology, SL.
++ * Copyright (C) 2006-2007 Imre Kaloz <kaloz@openwrt.org>
++ * Copyright (C) 2006-2009 Felix Fietkau <nbd@nbd.name>
++ * Copyright (C) 2012 Alexandros C. Couloumbis <alex@ozo.com>
++ *
++ * This code is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/platform_device.h>
++#include <linux/sched.h>
++#include <linux/delay.h>
++#include <linux/io.h>
++#include <linux/mutex.h>
++
++#include "ar2315_spiflash.h"
++
++#define DRIVER_NAME "ar2315-spiflash"
++
++#define busy_wait(_priv, _condition, _wait) do { \
++ while (_condition) { \
++ if (_wait > 1) \
++ msleep(_wait); \
++ else if ((_wait == 1) && need_resched()) \
++ schedule(); \
++ else \
++ udelay(1); \
++ } \
++} while (0)
++
++enum {
++ FLASH_NONE,
++ FLASH_1MB,
++ FLASH_2MB,
++ FLASH_4MB,
++ FLASH_8MB,
++ FLASH_16MB,
++};
++
++/* Flash configuration table */
++struct flashconfig {
++ u32 byte_cnt;
++ u32 sector_cnt;
++ u32 sector_size;
++};
++
++static const struct flashconfig flashconfig_tbl[] = {
++ [FLASH_NONE] = { 0, 0, 0},
++ [FLASH_1MB] = { STM_1MB_BYTE_COUNT, STM_1MB_SECTOR_COUNT,
++ STM_1MB_SECTOR_SIZE},
++ [FLASH_2MB] = { STM_2MB_BYTE_COUNT, STM_2MB_SECTOR_COUNT,
++ STM_2MB_SECTOR_SIZE},
++ [FLASH_4MB] = { STM_4MB_BYTE_COUNT, STM_4MB_SECTOR_COUNT,
++ STM_4MB_SECTOR_SIZE},
++ [FLASH_8MB] = { STM_8MB_BYTE_COUNT, STM_8MB_SECTOR_COUNT,
++ STM_8MB_SECTOR_SIZE},
++ [FLASH_16MB] = { STM_16MB_BYTE_COUNT, STM_16MB_SECTOR_COUNT,
++ STM_16MB_SECTOR_SIZE}
++};
++
++/* Mapping of generic opcodes to STM serial flash opcodes */
++enum {
++ SPI_WRITE_ENABLE,
++ SPI_WRITE_DISABLE,
++ SPI_RD_STATUS,
++ SPI_WR_STATUS,
++ SPI_RD_DATA,
++ SPI_FAST_RD_DATA,
++ SPI_PAGE_PROGRAM,
++ SPI_SECTOR_ERASE,
++ SPI_BULK_ERASE,
++ SPI_DEEP_PWRDOWN,
++ SPI_RD_SIG,
++};
++
++struct opcodes {
++ __u16 code;
++ __s8 tx_cnt;
++ __s8 rx_cnt;
++};
++
++static const struct opcodes stm_opcodes[] = {
++ [SPI_WRITE_ENABLE] = {STM_OP_WR_ENABLE, 1, 0},
++ [SPI_WRITE_DISABLE] = {STM_OP_WR_DISABLE, 1, 0},
++ [SPI_RD_STATUS] = {STM_OP_RD_STATUS, 1, 1},
++ [SPI_WR_STATUS] = {STM_OP_WR_STATUS, 1, 0},
++ [SPI_RD_DATA] = {STM_OP_RD_DATA, 4, 4},
++ [SPI_FAST_RD_DATA] = {STM_OP_FAST_RD_DATA, 5, 0},
++ [SPI_PAGE_PROGRAM] = {STM_OP_PAGE_PGRM, 8, 0},
++ [SPI_SECTOR_ERASE] = {STM_OP_SECTOR_ERASE, 4, 0},
++ [SPI_BULK_ERASE] = {STM_OP_BULK_ERASE, 1, 0},
++ [SPI_DEEP_PWRDOWN] = {STM_OP_DEEP_PWRDOWN, 1, 0},
++ [SPI_RD_SIG] = {STM_OP_RD_SIG, 4, 1},
++};
++
++/* Driver private data structure */
++struct spiflash_priv {
++ struct mtd_info mtd;
++ void __iomem *readaddr; /* memory mapped data for read */
++ void __iomem *mmraddr; /* memory mapped register space */
++ struct mutex lock; /* serialize registers access */
++};
++
++#define to_spiflash(_mtd) container_of(_mtd, struct spiflash_priv, mtd)
++
++enum {
++ FL_READY,
++ FL_READING,
++ FL_ERASING,
++ FL_WRITING
++};
++
++/*****************************************************************************/
++
++static u32
++spiflash_read_reg(struct spiflash_priv *priv, int reg)
++{
++ return ioread32(priv->mmraddr + reg);
++}
++
++static void
++spiflash_write_reg(struct spiflash_priv *priv, int reg, u32 data)
++{
++ iowrite32(data, priv->mmraddr + reg);
++}
++
++static u32
++spiflash_wait_busy(struct spiflash_priv *priv)
++{
++ u32 reg;
++
++ busy_wait(priv, (reg = spiflash_read_reg(priv, SPI_FLASH_CTL)) &
++ SPI_CTL_BUSY, 0);
++ return reg;
++}
++
++static u32
++spiflash_sendcmd(struct spiflash_priv *priv, int opcode, u32 addr)
++{
++ const struct opcodes *op;
++ u32 reg, mask;
++
++ op = &stm_opcodes[opcode];
++ reg = spiflash_wait_busy(priv);
++ spiflash_write_reg(priv, SPI_FLASH_OPCODE,
++ ((u32)op->code) | (addr << 8));
++
++ reg &= ~SPI_CTL_TX_RX_CNT_MASK;
++ reg |= SPI_CTL_START | op->tx_cnt | (op->rx_cnt << 4);
++
++ spiflash_write_reg(priv, SPI_FLASH_CTL, reg);
++ spiflash_wait_busy(priv);
++
++ if (!op->rx_cnt)
++ return 0;
++
++ reg = spiflash_read_reg(priv, SPI_FLASH_DATA);
++
++ switch (op->rx_cnt) {
++ case 1:
++ mask = 0x000000ff;
++ break;
++ case 2:
++ mask = 0x0000ffff;
++ break;
++ case 3:
++ mask = 0x00ffffff;
++ break;
++ default:
++ mask = 0xffffffff;
++ break;
++ }
++ reg &= mask;
++
++ return reg;
++}
++
++/*
++ * Probe SPI flash device
++ * Function returns 0 for failure.
++ * and flashconfig_tbl array index for success.
++ */
++static int
++spiflash_probe_chip(struct platform_device *pdev, struct spiflash_priv *priv)
++{
++ u32 sig = spiflash_sendcmd(priv, SPI_RD_SIG, 0);
++ int flash_size;
++
++ switch (sig) {
++ case STM_8MBIT_SIGNATURE:
++ flash_size = FLASH_1MB;
++ break;
++ case STM_16MBIT_SIGNATURE:
++ flash_size = FLASH_2MB;
++ break;
++ case STM_32MBIT_SIGNATURE:
++ flash_size = FLASH_4MB;
++ break;
++ case STM_64MBIT_SIGNATURE:
++ flash_size = FLASH_8MB;
++ break;
++ case STM_128MBIT_SIGNATURE:
++ flash_size = FLASH_16MB;
++ break;
++ default:
++ dev_warn(&pdev->dev, "read of flash device signature failed!\n");
++ return 0;
++ }
++
++ return flash_size;
++}
++
++static void
++spiflash_wait_complete(struct spiflash_priv *priv, unsigned int timeout)
++{
++ busy_wait(priv, spiflash_sendcmd(priv, SPI_RD_STATUS, 0) &
++ SPI_STATUS_WIP, timeout);
++}
++
++static int
++spiflash_erase(struct mtd_info *mtd, struct erase_info *instr)
++{
++ struct spiflash_priv *priv = to_spiflash(mtd);
++ const struct opcodes *op;
++ u32 temp, reg;
++
++ if (instr->addr + instr->len > mtd->size)
++ return -EINVAL;
++
++ mutex_lock(&priv->lock);
++
++ spiflash_sendcmd(priv, SPI_WRITE_ENABLE, 0);
++ reg = spiflash_wait_busy(priv);
++
++ op = &stm_opcodes[SPI_SECTOR_ERASE];
++ temp = ((u32)instr->addr << 8) | (u32)(op->code);
++ spiflash_write_reg(priv, SPI_FLASH_OPCODE, temp);
++
++ reg &= ~SPI_CTL_TX_RX_CNT_MASK;
++ reg |= op->tx_cnt | SPI_CTL_START;
++ spiflash_write_reg(priv, SPI_FLASH_CTL, reg);
++
++ spiflash_wait_complete(priv, 20);
++
++ mutex_unlock(&priv->lock);
++
++ instr->state = MTD_ERASE_DONE;
++ mtd_erase_callback(instr);
++
++ return 0;
++}
++
++static int
++spiflash_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
++ u_char *buf)
++{
++ struct spiflash_priv *priv = to_spiflash(mtd);
++
++ if (!len)
++ return 0;
++
++ if (from + len > mtd->size)
++ return -EINVAL;
++
++ *retlen = len;
++
++ mutex_lock(&priv->lock);
++
++ memcpy_fromio(buf, priv->readaddr + from, len);
++
++ mutex_unlock(&priv->lock);
++
++ return 0;
++}
++
++static int
++spiflash_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
++ const u8 *buf)
++{
++ struct spiflash_priv *priv = to_spiflash(mtd);
++ u32 opcode, bytes_left;
++
++ *retlen = 0;
++
++ if (!len)
++ return 0;
++
++ if (to + len > mtd->size)
++ return -EINVAL;
++
++ bytes_left = len;
++
++ do {
++ u32 read_len, reg, page_offset, spi_data = 0;
++
++ read_len = min(bytes_left, sizeof(u32));
++
++ /* 32-bit writes cannot span across a page boundary
++ * (256 bytes). This types of writes require two page
++ * program operations to handle it correctly. The STM part
++ * will write the overflow data to the beginning of the
++ * current page as opposed to the subsequent page.
++ */
++ page_offset = (to & (STM_PAGE_SIZE - 1)) + read_len;
++
++ if (page_offset > STM_PAGE_SIZE)
++ read_len -= (page_offset - STM_PAGE_SIZE);
++
++ mutex_lock(&priv->lock);
++
++ spiflash_sendcmd(priv, SPI_WRITE_ENABLE, 0);
++ spi_data = 0;
++ switch (read_len) {
++ case 4:
++ spi_data |= buf[3] << 24;
++ /* fall through */
++ case 3:
++ spi_data |= buf[2] << 16;
++ /* fall through */
++ case 2:
++ spi_data |= buf[1] << 8;
++ /* fall through */
++ case 1:
++ spi_data |= buf[0] & 0xff;
++ break;
++ default:
++ break;
++ }
++
++ spiflash_write_reg(priv, SPI_FLASH_DATA, spi_data);
++ opcode = stm_opcodes[SPI_PAGE_PROGRAM].code |
++ (to & 0x00ffffff) << 8;
++ spiflash_write_reg(priv, SPI_FLASH_OPCODE, opcode);
++
++ reg = spiflash_read_reg(priv, SPI_FLASH_CTL);
++ reg &= ~SPI_CTL_TX_RX_CNT_MASK;
++ reg |= (read_len + 4) | SPI_CTL_START;
++ spiflash_write_reg(priv, SPI_FLASH_CTL, reg);
++
++ spiflash_wait_complete(priv, 1);
++
++ mutex_unlock(&priv->lock);
++
++ bytes_left -= read_len;
++ to += read_len;
++ buf += read_len;
++
++ *retlen += read_len;
++ } while (bytes_left != 0);
++
++ return 0;
++}
++
++#if defined CONFIG_MTD_REDBOOT_PARTS || CONFIG_MTD_MYLOADER_PARTS
++static const char * const part_probe_types[] = {
++ "cmdlinepart", "RedBoot", "MyLoader", NULL
++};
++#endif
++
++static int
++spiflash_probe(struct platform_device *pdev)
++{
++ struct spiflash_priv *priv;
++ struct mtd_info *mtd;
++ struct resource *res;
++ int index;
++ int result = 0;
++
++ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ mutex_init(&priv->lock);
++ mtd = &priv->mtd;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++ priv->mmraddr = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(priv->mmraddr)) {
++ dev_warn(&pdev->dev, "failed to map flash MMR\n");
++ return PTR_ERR(priv->mmraddr);
++ }
++
++ index = spiflash_probe_chip(pdev, priv);
++ if (!index) {
++ dev_warn(&pdev->dev, "found no flash device\n");
++ return -ENODEV;
++ }
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ priv->readaddr = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(priv->readaddr)) {
++ dev_warn(&pdev->dev, "failed to map flash read mem\n");
++ return PTR_ERR(priv->readaddr);
++ }
++
++ platform_set_drvdata(pdev, priv);
++ mtd->name = "spiflash";
++ mtd->type = MTD_NORFLASH;
++ mtd->flags = (MTD_CAP_NORFLASH|MTD_WRITEABLE);
++ mtd->size = flashconfig_tbl[index].byte_cnt;
++ mtd->erasesize = flashconfig_tbl[index].sector_size;
++ mtd->writesize = 1;
++ mtd->numeraseregions = 0;
++ mtd->eraseregions = NULL;
++ mtd->_erase = spiflash_erase;
++ mtd->_read = spiflash_read;
++ mtd->_write = spiflash_write;
++ mtd->owner = THIS_MODULE;
++
++ dev_info(&pdev->dev, "%lld Kbytes flash detected\n", mtd->size >> 10);
++
++#if defined CONFIG_MTD_REDBOOT_PARTS || CONFIG_MTD_MYLOADER_PARTS
++ /* parse redboot partitions */
++
++ result = mtd_device_parse_register(mtd, part_probe_types,
++ NULL, NULL, 0);
++#endif
++
++ return result;
++}
++
++static int
++spiflash_remove(struct platform_device *pdev)
++{
++ struct spiflash_priv *priv = platform_get_drvdata(pdev);
++
++ mtd_device_unregister(&priv->mtd);
++
++ return 0;
++}
++
++static struct platform_driver spiflash_driver = {
++ .driver.name = DRIVER_NAME,
++ .probe = spiflash_probe,
++ .remove = spiflash_remove,
++};
++
++module_platform_driver(spiflash_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("OpenWrt.org");
++MODULE_AUTHOR("Atheros Communications Inc");
++MODULE_DESCRIPTION("MTD driver for SPI Flash on Atheros AR2315+ SOC");
++MODULE_ALIAS("platform:" DRIVER_NAME);
++
+--- /dev/null
++++ b/drivers/mtd/devices/ar2315_spiflash.h
+@@ -0,0 +1,106 @@
++/*
++ * Atheros AR2315 SPI Flash Memory support header file.
++ *
++ * Copyright (c) 2005, Atheros Communications Inc.
++ * Copyright (C) 2006 FON Technology, SL.
++ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
++ * Copyright (C) 2006-2009 Felix Fietkau <nbd@nbd.name>
++ *
++ * This code is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++#ifndef __AR2315_SPIFLASH_H
++#define __AR2315_SPIFLASH_H
++
++#define STM_PAGE_SIZE 256
++
++#define SFI_WRITE_BUFFER_SIZE 4
++#define SFI_FLASH_ADDR_MASK 0x00ffffff
++
++#define STM_8MBIT_SIGNATURE 0x13
++#define STM_M25P80_BYTE_COUNT 1048576
++#define STM_M25P80_SECTOR_COUNT 16
++#define STM_M25P80_SECTOR_SIZE 0x10000
++
++#define STM_16MBIT_SIGNATURE 0x14
++#define STM_M25P16_BYTE_COUNT 2097152
++#define STM_M25P16_SECTOR_COUNT 32
++#define STM_M25P16_SECTOR_SIZE 0x10000
++
++#define STM_32MBIT_SIGNATURE 0x15
++#define STM_M25P32_BYTE_COUNT 4194304
++#define STM_M25P32_SECTOR_COUNT 64
++#define STM_M25P32_SECTOR_SIZE 0x10000
++
++#define STM_64MBIT_SIGNATURE 0x16
++#define STM_M25P64_BYTE_COUNT 8388608
++#define STM_M25P64_SECTOR_COUNT 128
++#define STM_M25P64_SECTOR_SIZE 0x10000
++
++#define STM_128MBIT_SIGNATURE 0x17
++#define STM_M25P128_BYTE_COUNT 16777216
++#define STM_M25P128_SECTOR_COUNT 256
++#define STM_M25P128_SECTOR_SIZE 0x10000
++
++#define STM_1MB_BYTE_COUNT STM_M25P80_BYTE_COUNT
++#define STM_1MB_SECTOR_COUNT STM_M25P80_SECTOR_COUNT
++#define STM_1MB_SECTOR_SIZE STM_M25P80_SECTOR_SIZE
++#define STM_2MB_BYTE_COUNT STM_M25P16_BYTE_COUNT
++#define STM_2MB_SECTOR_COUNT STM_M25P16_SECTOR_COUNT
++#define STM_2MB_SECTOR_SIZE STM_M25P16_SECTOR_SIZE
++#define STM_4MB_BYTE_COUNT STM_M25P32_BYTE_COUNT
++#define STM_4MB_SECTOR_COUNT STM_M25P32_SECTOR_COUNT
++#define STM_4MB_SECTOR_SIZE STM_M25P32_SECTOR_SIZE
++#define STM_8MB_BYTE_COUNT STM_M25P64_BYTE_COUNT
++#define STM_8MB_SECTOR_COUNT STM_M25P64_SECTOR_COUNT
++#define STM_8MB_SECTOR_SIZE STM_M25P64_SECTOR_SIZE
++#define STM_16MB_BYTE_COUNT STM_M25P128_BYTE_COUNT
++#define STM_16MB_SECTOR_COUNT STM_M25P128_SECTOR_COUNT
++#define STM_16MB_SECTOR_SIZE STM_M25P128_SECTOR_SIZE
++
++/*
++ * ST Microelectronics Opcodes for Serial Flash
++ */
++
++#define STM_OP_WR_ENABLE 0x06 /* Write Enable */
++#define STM_OP_WR_DISABLE 0x04 /* Write Disable */
++#define STM_OP_RD_STATUS 0x05 /* Read Status */
++#define STM_OP_WR_STATUS 0x01 /* Write Status */
++#define STM_OP_RD_DATA 0x03 /* Read Data */
++#define STM_OP_FAST_RD_DATA 0x0b /* Fast Read Data */
++#define STM_OP_PAGE_PGRM 0x02 /* Page Program */
++#define STM_OP_SECTOR_ERASE 0xd8 /* Sector Erase */
++#define STM_OP_BULK_ERASE 0xc7 /* Bulk Erase */
++#define STM_OP_DEEP_PWRDOWN 0xb9 /* Deep Power-Down Mode */
++#define STM_OP_RD_SIG 0xab /* Read Electronic Signature */
++
++#define STM_STATUS_WIP 0x01 /* Write-In-Progress */
++#define STM_STATUS_WEL 0x02 /* Write Enable Latch */
++#define STM_STATUS_BP0 0x04 /* Block Protect 0 */
++#define STM_STATUS_BP1 0x08 /* Block Protect 1 */
++#define STM_STATUS_BP2 0x10 /* Block Protect 2 */
++#define STM_STATUS_SRWD 0x80 /* Status Register Write Disable */
++
++/*
++ * SPI Flash Interface Registers
++ */
++
++#define SPI_FLASH_CTL 0x00
++#define SPI_FLASH_OPCODE 0x04
++#define SPI_FLASH_DATA 0x08
++
++#define SPI_CTL_START 0x00000100
++#define SPI_CTL_BUSY 0x00010000
++#define SPI_CTL_TXCNT_MASK 0x0000000f
++#define SPI_CTL_RXCNT_MASK 0x000000f0
++#define SPI_CTL_TX_RX_CNT_MASK 0x000000ff
++#define SPI_CTL_SIZE_MASK 0x00060000
++
++#define SPI_CTL_CLK_SEL_MASK 0x03000000
++#define SPI_OPCODE_MASK 0x000000ff
++
++#define SPI_STATUS_WIP STM_STATUS_WIP
++
++#endif
+--- a/arch/mips/ath25/ar2315.c
++++ b/arch/mips/ath25/ar2315.c
+@@ -220,6 +220,28 @@ static struct platform_device ar2315_gpi
+ .num_resources = ARRAY_SIZE(ar2315_gpio_res)
+ };
+
++static struct resource ar2315_spiflash_res[] = {
++ {
++ .name = "spiflash_read",
++ .flags = IORESOURCE_MEM,
++ .start = AR2315_SPI_READ_BASE,
++ .end = AR2315_SPI_READ_BASE + AR2315_SPI_READ_SIZE - 1,
++ },
++ {
++ .name = "spiflash_mmr",
++ .flags = IORESOURCE_MEM,
++ .start = AR2315_SPI_MMR_BASE,
++ .end = AR2315_SPI_MMR_BASE + AR2315_SPI_MMR_SIZE - 1,
++ },
++};
++
++static struct platform_device ar2315_spiflash = {
++ .id = 0,
++ .name = "ar2315-spiflash",
++ .resource = ar2315_spiflash_res,
++ .num_resources = ARRAY_SIZE(ar2315_spiflash_res)
++};
++
+ void __init ar2315_init_devices(void)
+ {
+ /* Find board configuration */
+@@ -230,6 +252,8 @@ void __init ar2315_init_devices(void)
+ ar2315_gpio_res[1].end = ar2315_gpio_res[1].start;
+ platform_device_register(&ar2315_gpio);
+
++ platform_device_register(&ar2315_spiflash);
++
+ ar2315_eth_data.macaddr = ath25_board.config->enet0_mac;
+ ath25_add_ethernet(0, AR2315_ENET0_BASE, "eth0_mii",
+ AR2315_ENET0_MII_BASE, AR2315_IRQ_ENET0,
diff --git a/target/linux/ath25/patches-4.4/130-watchdog.patch b/target/linux/ath25/patches-4.4/130-watchdog.patch
new file mode 100644
index 0000000000..251768f735
--- /dev/null
+++ b/target/linux/ath25/patches-4.4/130-watchdog.patch
@@ -0,0 +1,277 @@
+--- /dev/null
++++ b/drivers/watchdog/ar2315-wtd.c
+@@ -0,0 +1,209 @@
++/*
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ * Copyright (C) 2008 John Crispin <blogic@openwrt.org>
++ * Based on EP93xx and ifxmips wdt driver
++ */
++
++#include <linux/interrupt.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/types.h>
++#include <linux/miscdevice.h>
++#include <linux/watchdog.h>
++#include <linux/fs.h>
++#include <linux/ioport.h>
++#include <linux/notifier.h>
++#include <linux/reboot.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/io.h>
++#include <linux/uaccess.h>
++
++#define DRIVER_NAME "ar2315-wdt"
++
++#define CLOCK_RATE 40000000
++#define HEARTBEAT(x) (x < 1 || x > 90 ? 20 : x)
++
++#define WDT_REG_TIMER 0x00
++#define WDT_REG_CTRL 0x04
++
++#define WDT_CTRL_ACT_NONE 0x00000000 /* No action */
++#define WDT_CTRL_ACT_NMI 0x00000001 /* NMI on watchdog */
++#define WDT_CTRL_ACT_RESET 0x00000002 /* reset on watchdog */
++
++static int wdt_timeout = 20;
++static int started;
++static int in_use;
++static void __iomem *wdt_base;
++
++static inline void ar2315_wdt_wr(unsigned reg, u32 val)
++{
++ iowrite32(val, wdt_base + reg);
++}
++
++static void
++ar2315_wdt_enable(void)
++{
++ ar2315_wdt_wr(WDT_REG_TIMER, wdt_timeout * CLOCK_RATE);
++}
++
++static ssize_t
++ar2315_wdt_write(struct file *file, const char __user *data, size_t len,
++ loff_t *ppos)
++{
++ if (len)
++ ar2315_wdt_enable();
++ return len;
++}
++
++static int
++ar2315_wdt_open(struct inode *inode, struct file *file)
++{
++ if (in_use)
++ return -EBUSY;
++ ar2315_wdt_enable();
++ in_use = 1;
++ started = 1;
++ return nonseekable_open(inode, file);
++}
++
++static int
++ar2315_wdt_release(struct inode *inode, struct file *file)
++{
++ in_use = 0;
++ return 0;
++}
++
++static irqreturn_t
++ar2315_wdt_interrupt(int irq, void *dev)
++{
++ struct platform_device *pdev = (struct platform_device *)dev;
++
++ if (started) {
++ dev_crit(&pdev->dev, "watchdog expired, rebooting system\n");
++ emergency_restart();
++ } else {
++ ar2315_wdt_wr(WDT_REG_CTRL, 0);
++ ar2315_wdt_wr(WDT_REG_TIMER, 0);
++ }
++ return IRQ_HANDLED;
++}
++
++static struct watchdog_info ident = {
++ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
++ .identity = "ar2315 Watchdog",
++};
++
++static long
++ar2315_wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
++{
++ int new_wdt_timeout;
++ int ret = -ENOIOCTLCMD;
++
++ switch (cmd) {
++ case WDIOC_GETSUPPORT:
++ ret = copy_to_user((void __user *)arg, &ident, sizeof(ident)) ?
++ -EFAULT : 0;
++ break;
++ case WDIOC_KEEPALIVE:
++ ar2315_wdt_enable();
++ ret = 0;
++ break;
++ case WDIOC_SETTIMEOUT:
++ ret = get_user(new_wdt_timeout, (int __user *)arg);
++ if (ret)
++ break;
++ wdt_timeout = HEARTBEAT(new_wdt_timeout);
++ ar2315_wdt_enable();
++ break;
++ case WDIOC_GETTIMEOUT:
++ ret = put_user(wdt_timeout, (int __user *)arg);
++ break;
++ }
++ return ret;
++}
++
++static const struct file_operations ar2315_wdt_fops = {
++ .owner = THIS_MODULE,
++ .llseek = no_llseek,
++ .write = ar2315_wdt_write,
++ .unlocked_ioctl = ar2315_wdt_ioctl,
++ .open = ar2315_wdt_open,
++ .release = ar2315_wdt_release,
++};
++
++static struct miscdevice ar2315_wdt_miscdev = {
++ .minor = WATCHDOG_MINOR,
++ .name = "watchdog",
++ .fops = &ar2315_wdt_fops,
++};
++
++static int
++ar2315_wdt_probe(struct platform_device *dev)
++{
++ struct resource *mem_res, *irq_res;
++ int ret = 0;
++
++ if (wdt_base)
++ return -EBUSY;
++
++ irq_res = platform_get_resource(dev, IORESOURCE_IRQ, 0);
++ if (!irq_res) {
++ dev_err(&dev->dev, "no IRQ resource\n");
++ return -ENOENT;
++ }
++
++ mem_res = platform_get_resource(dev, IORESOURCE_MEM, 0);
++ wdt_base = devm_ioremap_resource(&dev->dev, mem_res);
++ if (IS_ERR(wdt_base))
++ return PTR_ERR(wdt_base);
++
++ ret = devm_request_irq(&dev->dev, irq_res->start, ar2315_wdt_interrupt,
++ 0, DRIVER_NAME, dev);
++ if (ret) {
++ dev_err(&dev->dev, "failed to register inetrrupt\n");
++ goto out;
++ }
++
++ ret = misc_register(&ar2315_wdt_miscdev);
++ if (ret)
++ dev_err(&dev->dev, "failed to register miscdev\n");
++
++out:
++ return ret;
++}
++
++static int
++ar2315_wdt_remove(struct platform_device *dev)
++{
++ misc_deregister(&ar2315_wdt_miscdev);
++ return 0;
++}
++
++static struct platform_driver ar2315_wdt_driver = {
++ .probe = ar2315_wdt_probe,
++ .remove = ar2315_wdt_remove,
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ },
++};
++
++module_platform_driver(ar2315_wdt_driver);
++
++MODULE_DESCRIPTION("Atheros AR2315 hardware watchdog driver");
++MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:" DRIVER_NAME);
+--- a/drivers/watchdog/Kconfig
++++ b/drivers/watchdog/Kconfig
+@@ -1345,6 +1345,13 @@ config RALINK_WDT
+ help
+ Hardware driver for the Ralink SoC Watchdog Timer.
+
++config AR2315_WDT
++ tristate "Atheros AR2315+ WiSoCs Watchdog Timer"
++ depends on ATH25
++ help
++ Hardware driver for the built-in watchdog timer on the Atheros
++ AR2315/AR2316 WiSoCs.
++
+ # PARISC Architecture
+
+ # POWERPC Architecture
+--- a/drivers/watchdog/Makefile
++++ b/drivers/watchdog/Makefile
+@@ -143,6 +143,7 @@ obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
+ obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o
+ obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o
+ obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
++obj-$(CONFIG_AR2315_WDT) += ar2315-wtd.o
+ obj-$(CONFIG_TXX9_WDT) += txx9wdt.o
+ obj-$(CONFIG_OCTEON_WDT) += octeon-wdt.o
+ octeon-wdt-y := octeon-wdt-main.o octeon-wdt-nmi.o
+--- a/arch/mips/ath25/ar2315.c
++++ b/arch/mips/ath25/ar2315.c
+@@ -220,6 +220,24 @@ static struct platform_device ar2315_gpi
+ .num_resources = ARRAY_SIZE(ar2315_gpio_res)
+ };
+
++static struct resource ar2315_wdt_res[] = {
++ {
++ .flags = IORESOURCE_MEM,
++ .start = AR2315_RST_BASE + AR2315_WDT_TIMER,
++ .end = AR2315_RST_BASE + AR2315_WDT_TIMER + 8 - 1,
++ },
++ {
++ .flags = IORESOURCE_IRQ,
++ }
++};
++
++static struct platform_device ar2315_wdt = {
++ .id = 0,
++ .name = "ar2315-wdt",
++ .resource = ar2315_wdt_res,
++ .num_resources = ARRAY_SIZE(ar2315_wdt_res)
++};
++
+ static struct resource ar2315_spiflash_res[] = {
+ {
+ .name = "spiflash_read",
+@@ -252,6 +270,11 @@ void __init ar2315_init_devices(void)
+ ar2315_gpio_res[1].end = ar2315_gpio_res[1].start;
+ platform_device_register(&ar2315_gpio);
+
++ ar2315_wdt_res[1].start = irq_create_mapping(ar2315_misc_irq_domain,
++ AR2315_MISC_IRQ_WATCHDOG);
++ ar2315_wdt_res[1].end = ar2315_wdt_res[1].start;
++ platform_device_register(&ar2315_wdt);
++
+ platform_device_register(&ar2315_spiflash);
+
+ ar2315_eth_data.macaddr = ath25_board.config->enet0_mac;
diff --git a/target/linux/ath25/patches-3.18/140-redboot_boardconfig.patch b/target/linux/ath25/patches-4.4/140-redboot_boardconfig.patch
index 98dbf52611..98dbf52611 100644
--- a/target/linux/ath25/patches-3.18/140-redboot_boardconfig.patch
+++ b/target/linux/ath25/patches-4.4/140-redboot_boardconfig.patch
diff --git a/target/linux/ath25/patches-3.18/141-redboot_partition_scan.patch b/target/linux/ath25/patches-4.4/141-redboot_partition_scan.patch
index d1d281eaf4..d1d281eaf4 100644
--- a/target/linux/ath25/patches-3.18/141-redboot_partition_scan.patch
+++ b/target/linux/ath25/patches-4.4/141-redboot_partition_scan.patch
diff --git a/target/linux/ath25/patches-3.18/142-redboot_various_erase_size_fix.patch b/target/linux/ath25/patches-4.4/142-redboot_various_erase_size_fix.patch
index e1b0a89905..e1b0a89905 100644
--- a/target/linux/ath25/patches-3.18/142-redboot_various_erase_size_fix.patch
+++ b/target/linux/ath25/patches-4.4/142-redboot_various_erase_size_fix.patch
diff --git a/target/linux/ath25/patches-4.4/210-reset_button.patch b/target/linux/ath25/patches-4.4/210-reset_button.patch
new file mode 100644
index 0000000000..34ef46bc52
--- /dev/null
+++ b/target/linux/ath25/patches-4.4/210-reset_button.patch
@@ -0,0 +1,71 @@
+--- a/arch/mips/ath25/Makefile
++++ b/arch/mips/ath25/Makefile
+@@ -8,7 +8,7 @@
+ # Copyright (C) 2006-2009 Felix Fietkau <nbd@openwrt.org>
+ #
+
+-obj-y += board.o prom.o devices.o
++obj-y += board.o prom.o devices.o reset.o
+
+ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+
+--- /dev/null
++++ b/arch/mips/ath25/reset.c
+@@ -0,0 +1,57 @@
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/platform_device.h>
++#include <linux/gpio_keys.h>
++#include <linux/input.h>
++#include <ath25_platform.h>
++#include "devices.h"
++
++static int __init
++ar231x_init_reset(void)
++{
++ struct platform_device *pdev;
++ struct gpio_keys_platform_data pdata;
++ struct gpio_keys_button *p;
++ int err;
++
++ if (ath25_board.config->reset_config_gpio == 0xffff)
++ return -ENODEV;
++
++ p = kzalloc(sizeof(*p), GFP_KERNEL);
++ if (!p)
++ goto err;
++
++ p->desc = "reset";
++ p->type = EV_KEY;
++ p->code = KEY_RESTART;
++ p->debounce_interval = 60;
++ p->gpio = ath25_board.config->reset_config_gpio;
++
++ memset(&pdata, 0, sizeof(pdata));
++ pdata.poll_interval = 20;
++ pdata.buttons = p;
++ pdata.nbuttons = 1;
++
++ pdev = platform_device_alloc("gpio-keys-polled", 0);
++ if (!pdev)
++ goto err_free;
++
++ err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
++ if (err)
++ goto err_put_pdev;
++
++ err = platform_device_add(pdev);
++ if (err)
++ goto err_put_pdev;
++
++ return 0;
++
++err_put_pdev:
++ platform_device_put(pdev);
++err_free:
++ kfree(p);
++err:
++ return -ENOMEM;
++}
++
++module_init(ar231x_init_reset);
diff --git a/target/linux/ath25/patches-3.18/220-enet_micrel_workaround.patch b/target/linux/ath25/patches-4.4/220-enet_micrel_workaround.patch
index 398495a80c..398495a80c 100644
--- a/target/linux/ath25/patches-3.18/220-enet_micrel_workaround.patch
+++ b/target/linux/ath25/patches-4.4/220-enet_micrel_workaround.patch
diff --git a/target/linux/ath25/patches-3.18/330-board_leds.patch b/target/linux/ath25/patches-4.4/330-board_leds.patch
index e357fc6a64..e357fc6a64 100644
--- a/target/linux/ath25/patches-3.18/330-board_leds.patch
+++ b/target/linux/ath25/patches-4.4/330-board_leds.patch
diff --git a/target/linux/ath25/profiles/00-default.mk b/target/linux/ath25/profiles/00-default.mk
new file mode 100644
index 0000000000..b40eb1b0ce
--- /dev/null
+++ b/target/linux/ath25/profiles/00-default.mk
@@ -0,0 +1,16 @@
+#
+# Copyright (C) 2011 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/Default
+ NAME:=Default Profile
+ PRIORITY:=1
+endef
+
+define Profile/Default/Description
+ Default package set compatible with most boards.
+endef
+$(eval $(call Profile,Default))
diff --git a/target/linux/bcm53xx/patches-4.4/140-mtd-brcmnand-set-initial-ECC-params-based-on-info-fr.patch b/target/linux/bcm53xx/patches-4.4/140-mtd-brcmnand-set-initial-ECC-params-based-on-info-fr.patch
index 0a3620f693..ea59938aa1 100644
--- a/target/linux/bcm53xx/patches-4.4/140-mtd-brcmnand-set-initial-ECC-params-based-on-info-fr.patch
+++ b/target/linux/bcm53xx/patches-4.4/140-mtd-brcmnand-set-initial-ECC-params-based-on-info-fr.patch
@@ -23,7 +23,7 @@ This should be very helpful for ppl adding new devices support.
--- a/drivers/mtd/nand/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/brcmnand/brcmnand.c
-@@ -613,6 +613,17 @@ static inline u32 brcmnand_ecc_level_mas
+@@ -645,6 +645,17 @@ static inline u32 brcmnand_ecc_level_mas
return mask << NAND_ACC_CONTROL_ECC_SHIFT;
}
@@ -41,7 +41,7 @@ This should be very helpful for ppl adding new devices support.
static void brcmnand_set_ecc_enabled(struct brcmnand_host *host, int en)
{
struct brcmnand_controller *ctrl = host->ctrl;
-@@ -1965,6 +1976,9 @@ static int brcmnand_init_cs(struct brcmn
+@@ -1997,6 +2008,9 @@ static int brcmnand_init_cs(struct brcmn
nand_writereg(ctrl, cfg_offs,
nand_readreg(ctrl, cfg_offs) & ~CFG_BUS_WIDTH);
diff --git a/target/linux/bcm53xx/patches-4.4/191-usb-xhci-add-Broadcom-specific-fake-doorbell.patch b/target/linux/bcm53xx/patches-4.4/191-usb-xhci-add-Broadcom-specific-fake-doorbell.patch
index c54cecb133..61c2a98a8e 100644
--- a/target/linux/bcm53xx/patches-4.4/191-usb-xhci-add-Broadcom-specific-fake-doorbell.patch
+++ b/target/linux/bcm53xx/patches-4.4/191-usb-xhci-add-Broadcom-specific-fake-doorbell.patch
@@ -74,7 +74,7 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
/*
* Set the run bit and wait for the host to be running.
*/
-@@ -567,10 +600,25 @@ int xhci_init(struct usb_hcd *hcd)
+@@ -568,10 +601,25 @@ int xhci_init(struct usb_hcd *hcd)
static int xhci_run_finished(struct xhci_hcd *xhci)
{
@@ -103,7 +103,7 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
xhci->shared_hcd->state = HC_STATE_RUNNING;
xhci->cmd_ring_state = CMD_RING_STATE_RUNNING;
-@@ -580,6 +628,9 @@ static int xhci_run_finished(struct xhci
+@@ -581,6 +629,9 @@ static int xhci_run_finished(struct xhci
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"Finished xhci_run for USB3 roothub");
return 0;
@@ -115,7 +115,7 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
/*
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
-@@ -1630,6 +1630,7 @@ struct xhci_hcd {
+@@ -1631,6 +1631,7 @@ struct xhci_hcd {
/* For controllers with a broken beyond repair streams implementation */
#define XHCI_BROKEN_STREAMS (1 << 19)
#define XHCI_PME_STUCK_QUIRK (1 << 20)
diff --git a/target/linux/bcm53xx/patches-4.4/351-ARM-BCM5301X-Enable-ChipCommon-UART-on-untested-devi.patch b/target/linux/bcm53xx/patches-4.4/351-ARM-BCM5301X-Enable-ChipCommon-UART-on-untested-devi.patch
index b5e92c18fc..19b24849cc 100644
--- a/target/linux/bcm53xx/patches-4.4/351-ARM-BCM5301X-Enable-ChipCommon-UART-on-untested-devi.patch
+++ b/target/linux/bcm53xx/patches-4.4/351-ARM-BCM5301X-Enable-ChipCommon-UART-on-untested-devi.patch
@@ -40,9 +40,9 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+};
--- a/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts
+++ b/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts
-@@ -83,3 +83,7 @@
- };
- };
+@@ -87,3 +87,7 @@
+ &spi_nor {
+ status = "okay";
};
+
+&uart0 {
diff --git a/target/linux/bcm53xx/patches-4.4/400-mtd-brcmnand-stop-special-treating-ECC-strength-1-as.patch b/target/linux/bcm53xx/patches-4.4/400-mtd-brcmnand-stop-special-treating-ECC-strength-1-as.patch
index f7509d3636..4d855c7fb3 100644
--- a/target/linux/bcm53xx/patches-4.4/400-mtd-brcmnand-stop-special-treating-ECC-strength-1-as.patch
+++ b/target/linux/bcm53xx/patches-4.4/400-mtd-brcmnand-stop-special-treating-ECC-strength-1-as.patch
@@ -14,7 +14,7 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
--- a/drivers/mtd/nand/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/brcmnand/brcmnand.c
-@@ -1854,7 +1854,8 @@ static int brcmnand_setup_dev(struct brc
+@@ -1886,7 +1886,8 @@ static int brcmnand_setup_dev(struct brc
switch (chip->ecc.size) {
case 512:
diff --git a/target/linux/bcm53xx/patches-4.4/405-mtd-spi-nor-detect-JEDEC-incompatible-w25q128-using-.patch b/target/linux/bcm53xx/patches-4.4/405-mtd-spi-nor-detect-JEDEC-incompatible-w25q128-using-.patch
index 2b3773f0a2..ca930e75f0 100644
--- a/target/linux/bcm53xx/patches-4.4/405-mtd-spi-nor-detect-JEDEC-incompatible-w25q128-using-.patch
+++ b/target/linux/bcm53xx/patches-4.4/405-mtd-spi-nor-detect-JEDEC-incompatible-w25q128-using-.patch
@@ -13,7 +13,7 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
-@@ -869,6 +869,18 @@ static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
+@@ -870,6 +870,18 @@ static const struct flash_info *spi_nor_
}
dev_err(nor->dev, "unrecognized JEDEC id bytes: %02x, %2x, %2x\n",
id[0], id[1], id[2]);
diff --git a/target/linux/bcm53xx/patches-4.4/406-mtd-m25p80-use-single-SPI-message-for-writing-data.patch b/target/linux/bcm53xx/patches-4.4/406-mtd-m25p80-use-single-SPI-message-for-writing-data.patch
index 0e0cce219c..1a3fc31f66 100644
--- a/target/linux/bcm53xx/patches-4.4/406-mtd-m25p80-use-single-SPI-message-for-writing-data.patch
+++ b/target/linux/bcm53xx/patches-4.4/406-mtd-m25p80-use-single-SPI-message-for-writing-data.patch
@@ -21,7 +21,7 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
-@@ -78,29 +78,30 @@ static void m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
+@@ -78,29 +78,30 @@ static void m25p80_write(struct spi_nor
{
struct m25p *flash = nor->priv;
struct spi_device *spi = flash->spi;
diff --git a/target/linux/bcm53xx/patches-4.4/500-UBI-Detect-EOF-mark-and-erase-all-remaining-blocks.patch b/target/linux/bcm53xx/patches-4.4/500-UBI-Detect-EOF-mark-and-erase-all-remaining-blocks.patch
index 11bd956163..636e63eb29 100644
--- a/target/linux/bcm53xx/patches-4.4/500-UBI-Detect-EOF-mark-and-erase-all-remaining-blocks.patch
+++ b/target/linux/bcm53xx/patches-4.4/500-UBI-Detect-EOF-mark-and-erase-all-remaining-blocks.patch
@@ -49,7 +49,7 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
return UBI_IO_BAD_HDR_EBADMSG;
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
-@@ -781,6 +781,7 @@ extern struct mutex ubi_devices_mutex;
+@@ -783,6 +783,7 @@ extern struct mutex ubi_devices_mutex;
extern struct blocking_notifier_head ubi_notifiers;
/* attach.c */
diff --git a/target/linux/bcm53xx/patches-4.4/820-spi-bcm53xx-let-DT-specify-SPI-device-s-instead-hard.patch b/target/linux/bcm53xx/patches-4.4/820-spi-bcm53xx-let-DT-specify-SPI-device-s-instead-hard.patch
index 0519c1bbcc..c60eb1954a 100644
--- a/target/linux/bcm53xx/patches-4.4/820-spi-bcm53xx-let-DT-specify-SPI-device-s-instead-hard.patch
+++ b/target/linux/bcm53xx/patches-4.4/820-spi-bcm53xx-let-DT-specify-SPI-device-s-instead-hard.patch
@@ -10,7 +10,7 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
--- a/drivers/spi/spi-bcm53xx.c
+++ b/drivers/spi/spi-bcm53xx.c
-@@ -275,10 +275,6 @@ static int bcm53xxspi_flash_read(struct spi_device *spi,
+@@ -275,10 +275,6 @@ static int bcm53xxspi_flash_read(struct
* BCMA
**************************************************/
@@ -21,7 +21,7 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
static const struct bcma_device_id bcm53xxspi_bcma_tbl[] = {
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_QSPI, BCMA_ANY_REV, BCMA_ANY_CLASS),
{},
-@@ -300,6 +296,7 @@ static int bcm53xxspi_bcma_probe(struct bcma_device *core)
+@@ -300,6 +296,7 @@ static int bcm53xxspi_bcma_probe(struct
master = spi_alloc_master(dev, sizeof(*b53spi));
if (!master)
return -ENOMEM;
@@ -29,7 +29,7 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
b53spi = spi_master_get_devdata(master);
b53spi->master = master;
-@@ -324,9 +321,6 @@ static int bcm53xxspi_bcma_probe(struct bcma_device *core)
+@@ -324,9 +321,6 @@ static int bcm53xxspi_bcma_probe(struct
return err;
}
diff --git a/target/linux/brcm2708/base-files/etc/diag.sh b/target/linux/brcm2708/base-files/etc/diag.sh
index de21bcd8aa..2a866e4339 100644
--- a/target/linux/brcm2708/base-files/etc/diag.sh
+++ b/target/linux/brcm2708/base-files/etc/diag.sh
@@ -7,7 +7,8 @@
set_state() {
case "$(brcm2708_board_name)" in
rpi-b |\
- rpi-cm)
+ rpi-cm |\
+ rpi-zero)
status_led="led0"
;;
rpi-b-plus |\
diff --git a/target/linux/brcm2708/base-files/lib/brcm2708.sh b/target/linux/brcm2708/base-files/lib/brcm2708.sh
index 5a59a2826d..ab7a23da96 100644
--- a/target/linux/brcm2708/base-files/lib/brcm2708.sh
+++ b/target/linux/brcm2708/base-files/lib/brcm2708.sh
@@ -18,6 +18,9 @@ brcm2708_detect() {
"Raspberry Pi Compute Module Rev"*)
board_name="rpi-cm"
;;
+ "Raspberry Pi Zero Rev"*)
+ board_name="rpi-zero"
+ ;;
"Raspberry Pi 2 Model B Rev"*)
board_name="rpi-2-b"
;;
diff --git a/target/linux/brcm2708/bcm2708/config-4.4 b/target/linux/brcm2708/bcm2708/config-4.4
index 1209f5e48a..4303f39a22 100644
--- a/target/linux/brcm2708/bcm2708/config-4.4
+++ b/target/linux/brcm2708/bcm2708/config-4.4
@@ -266,6 +266,7 @@ CONFIG_NO_HZ_IDLE=y
CONFIG_OABI_COMPAT=y
CONFIG_OF=y
CONFIG_OF_ADDRESS=y
+CONFIG_OF_CONFIGFS=y
CONFIG_OF_EARLY_FLATTREE=y
CONFIG_OF_FLATTREE=y
CONFIG_OF_GPIO=y
@@ -286,6 +287,9 @@ CONFIG_PINCTRL_BCM2835=y
CONFIG_PM=y
CONFIG_PM_CLK=y
# CONFIG_PM_DEBUG is not set
+CONFIG_PM_GENERIC_DOMAINS=y
+CONFIG_PM_GENERIC_DOMAINS_OF=y
+CONFIG_PM_GENERIC_DOMAINS_SLEEP=y
CONFIG_PM_SLEEP=y
CONFIG_POWER_SUPPLY=y
CONFIG_PRINTK_TIME=y
@@ -294,6 +298,7 @@ CONFIG_PWM=y
CONFIG_PWM_BCM2835=y
CONFIG_PWM_SYSFS=y
CONFIG_RASPBERRYPI_FIRMWARE=y
+CONFIG_RASPBERRYPI_POWER=y
CONFIG_RATIONAL=y
CONFIG_RAW_DRIVER=y
# CONFIG_RCU_STALL_COMMON is not set
diff --git a/target/linux/brcm2708/bcm2708/profiles/RaspberryPi.mk b/target/linux/brcm2708/bcm2708/profiles/RaspberryPi.mk
deleted file mode 100644
index 9f698a711d..0000000000
--- a/target/linux/brcm2708/bcm2708/profiles/RaspberryPi.mk
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-# Copyright (C) 2015 OpenWrt.org
-#
-# This is free software, licensed under the GNU General Public License v2.
-# See /LICENSE for more information.
-#
-
-define Profile/RaspberryPi
- NAME:=Raspberry Pi Models B/B+/CM
-endef
-define Profile/RaspberryPi/Description
- Raspberry Pi Models B/B+/CM
-endef
-$(eval $(call Profile,RaspberryPi))
diff --git a/target/linux/brcm2708/bcm2709/config-4.4 b/target/linux/brcm2708/bcm2709/config-4.4
index 87ca365f6a..132cbef4d2 100644
--- a/target/linux/brcm2708/bcm2709/config-4.4
+++ b/target/linux/brcm2708/bcm2709/config-4.4
@@ -283,6 +283,7 @@ CONFIG_NR_CPUS=4
CONFIG_OABI_COMPAT=y
CONFIG_OF=y
CONFIG_OF_ADDRESS=y
+CONFIG_OF_CONFIGFS=y
CONFIG_OF_EARLY_FLATTREE=y
CONFIG_OF_FLATTREE=y
CONFIG_OF_GPIO=y
@@ -303,6 +304,9 @@ CONFIG_PINCTRL_BCM2835=y
CONFIG_PM=y
CONFIG_PM_CLK=y
# CONFIG_PM_DEBUG is not set
+CONFIG_PM_GENERIC_DOMAINS=y
+CONFIG_PM_GENERIC_DOMAINS_OF=y
+CONFIG_PM_GENERIC_DOMAINS_SLEEP=y
CONFIG_PM_SLEEP=y
CONFIG_PM_SLEEP_SMP=y
CONFIG_POWER_SUPPLY=y
@@ -312,6 +316,7 @@ CONFIG_PWM=y
CONFIG_PWM_BCM2835=y
CONFIG_PWM_SYSFS=y
CONFIG_RASPBERRYPI_FIRMWARE=y
+CONFIG_RASPBERRYPI_POWER=y
CONFIG_RATIONAL=y
CONFIG_RAW_DRIVER=y
CONFIG_RCU_STALL_COMMON=y
diff --git a/target/linux/brcm2708/bcm2709/profiles/RaspberryPi2.mk b/target/linux/brcm2708/bcm2709/profiles/RaspberryPi2.mk
deleted file mode 100644
index ef7483d841..0000000000
--- a/target/linux/brcm2708/bcm2709/profiles/RaspberryPi2.mk
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-# Copyright (C) 2015 OpenWrt.org
-#
-# This is free software, licensed under the GNU General Public License v2.
-# See /LICENSE for more information.
-#
-
-define Profile/RaspberryPi_2
- NAME:=Raspberry Pi 2 Model B
-endef
-define Profile/RaspberryPi_2/Description
- Raspberry Pi 2 Model B
-endef
-$(eval $(call Profile,RaspberryPi_2))
diff --git a/target/linux/brcm2708/bcm2710/config-4.4 b/target/linux/brcm2708/bcm2710/config-4.4
index 8614c8f828..da9f668c15 100644
--- a/target/linux/brcm2708/bcm2710/config-4.4
+++ b/target/linux/brcm2708/bcm2710/config-4.4
@@ -283,6 +283,7 @@ CONFIG_NR_CPUS=4
CONFIG_OABI_COMPAT=y
CONFIG_OF=y
CONFIG_OF_ADDRESS=y
+CONFIG_OF_CONFIGFS=y
CONFIG_OF_EARLY_FLATTREE=y
CONFIG_OF_FLATTREE=y
CONFIG_OF_GPIO=y
@@ -303,6 +304,9 @@ CONFIG_PINCTRL_BCM2835=y
CONFIG_PM=y
CONFIG_PM_CLK=y
# CONFIG_PM_DEBUG is not set
+CONFIG_PM_GENERIC_DOMAINS=y
+CONFIG_PM_GENERIC_DOMAINS_OF=y
+CONFIG_PM_GENERIC_DOMAINS_SLEEP=y
CONFIG_PM_SLEEP=y
CONFIG_PM_SLEEP_SMP=y
CONFIG_POWER_SUPPLY=y
@@ -312,6 +316,7 @@ CONFIG_PWM=y
CONFIG_PWM_BCM2835=y
CONFIG_PWM_SYSFS=y
CONFIG_RASPBERRYPI_FIRMWARE=y
+CONFIG_RASPBERRYPI_POWER=y
CONFIG_RATIONAL=y
CONFIG_RAW_DRIVER=y
CONFIG_RCU_STALL_COMMON=y
diff --git a/target/linux/brcm2708/bcm2710/profiles/RaspberryPi3.mk b/target/linux/brcm2708/bcm2710/profiles/RaspberryPi3.mk
deleted file mode 100644
index c39cf5257b..0000000000
--- a/target/linux/brcm2708/bcm2710/profiles/RaspberryPi3.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-#
-# Copyright (C) 2016 OpenWrt.org
-#
-# This is free software, licensed under the GNU General Public License v2.
-# See /LICENSE for more information.
-#
-
-define Profile/RaspberryPi_3
- NAME:=Raspberry Pi 3 Model B
- PACKAGES:=brcmfmac43430-firmware-sdio kmod-brcmfmac wpad-mini
-endef
-define Profile/RaspberryPi_3/Description
- Raspberry Pi 3 Model B
-endef
-$(eval $(call Profile,RaspberryPi_3))
diff --git a/target/linux/brcm2708/image/Makefile b/target/linux/brcm2708/image/Makefile
index 8cf83a4563..f594c5b056 100644
--- a/target/linux/brcm2708/image/Makefile
+++ b/target/linux/brcm2708/image/Makefile
@@ -20,8 +20,8 @@ endef
define Build/boot-img
rm -f $@.boot
mkfs.fat -C $@.boot $(FAT32_BLOCKS)
+ mcopy -i $@.boot $(LINUX_DIR)/COPYING ::COPYING.linux
mcopy -i $@.boot $(KDIR)/bootcode.bin ::
- mcopy -i $@.boot $(KDIR)/COPYING.linux ::
mcopy -i $@.boot $(KDIR)/LICENCE.broadcom ::
mcopy -i $@.boot $(KDIR)/start.elf ::
mcopy -i $@.boot $(KDIR)/start_cd.elf ::
@@ -32,7 +32,7 @@ define Build/boot-img
mcopy -i $@.boot $(word 1,$^) ::kernel.img
$(foreach dts,$(shell echo $(DEVICE_DTS)),mcopy -i $@.boot $(DTS_DIR)/$(dts).dtb ::;)
mmd -i $@.boot ::/overlays
- mcopy -i $@.boot $(DTS_DIR)/overlays/*.dtb ::/overlays/
+ mcopy -i $@.boot $(DTS_DIR)/overlays/*.dtbo ::/overlays/
mcopy -i $@.boot $(DTS_DIR)/overlays/README ::/overlays/
endef
@@ -42,45 +42,39 @@ define Build/sdcard-img
$(if $(CONFIG_TARGET_IMAGES_GZIP),gzip -9n -c $@ > $(BIN_DIR)/$(notdir $@).gz)
endef
-### Device macros ###
+### Devices ###
define Device/Default
FILESYSTEMS := ext4
- PROFILES = Default $$(DEVICE_PROFILE)
KERNEL := kernel-bin | kernel-img
IMAGES := sdcard.img
IMAGE/sdcard.img := boot-img | sdcard-img
- DEVICE_PROFILE :=
DEVICE_DTS :=
endef
-DEVICE_VARS += DEVICE_PROFILE DEVICE_DTS
+DEVICE_VARS += DEVICE_DTS
-# $(1) = profile
-# $(2) = image name
-# $(3) = dts
-define bcm27xx
- define Device/$(2)
- DEVICE_PROFILE := $(1)
- DEVICE_DTS := $(3)
- endef
- TARGET_DEVICES += $(2)
+define Device/rpi
+ DEVICE_TITLE := Raspberry Pi B/B+/CM/Zero
+ DEVICE_DTS := bcm2708-rpi-b bcm2708-rpi-b-plus bcm2708-rpi-cm
endef
-
-### BCM2708/BCM2835 ###
ifeq ($(SUBTARGET),bcm2708)
- # Raspberry Pi Models B/B+/CM
- $(eval $(call bcm27xx,RaspberryPi,rpi,bcm2708-rpi-b bcm2708-rpi-b-plus bcm2708-rpi-cm))
+ TARGET_DEVICES += rpi
endif
-### BCM2709/BCM2836 ###
-ifeq ($(SUBTARGET),bcm2709)
- # Raspberry Pi 2 Model B
- $(eval $(call bcm27xx,RaspberryPi_2,rpi-2,bcm2709-rpi-2-b))
+define Device/rpi-2
+ DEVICE_TITLE := Raspberry Pi 2 B
+ DEVICE_DTS := bcm2709-rpi-2-b
+endef
+ifeq ($(SUBTARGET),bcm2708)
+ TARGET_DEVICES += rpi-2
endif
-### BCM2710/BCM2837 ###
-ifeq ($(SUBTARGET),bcm2710)
- # Raspberry Pi 3 Model B
- $(eval $(call bcm27xx,RaspberryPi_3,rpi-3,bcm2710-rpi-3-b))
+define Device/rpi-3
+ DEVICE_TITLE := Raspberry Pi 3 B
+ DEVICE_DTS := bcm2710-rpi-3-b
+ DEVICE_PACKAGES := brcmfmac43430-firmware-sdio kmod-brcmfmac wpad-mini
+endef
+ifeq ($(SUBTARGET),bcm2708)
+ TARGET_DEVICES += rpi-3
endif
$(eval $(call BuildImage))
diff --git a/target/linux/brcm2708/image/config.txt b/target/linux/brcm2708/image/config.txt
index 75b1cab7af..e80d9801cc 100644
--- a/target/linux/brcm2708/image/config.txt
+++ b/target/linux/brcm2708/image/config.txt
@@ -476,7 +476,14 @@
## Stop start.elf from filling in ATAGS (memory from 0x100) before
## launching kernel
##
-disable_commandline_tags=2
+#disable_commandline_tags=2
+
+## enable_uart
+## Enables or disables uart pin multiplexing
+## Raspberry Pi 1/2: if unset, uart is enabled by default
+## Raspberry Pi 3: if unset uart is disabled by default
+##
+enable_uart=1
## cmdline (string)
## Command line parameters. Can be used instead of cmdline.txt file
@@ -491,7 +498,7 @@ disable_commandline_tags=2
## kernel_address
## Address to load kernel.img file at
##
-kernel_address=0x8000
+#kernel_address=0x8000
## ramfsfile (string)
## ramfs file to load
@@ -515,21 +522,21 @@ kernel_address=0x8000
## device_tree_address
## Address to load device_tree at
##
-device_tree_address=0x100
+#device_tree_address=0x100
## init_uart_baud
## Initial uart baud rate.
##
## Default 115200
##
-init_uart_baud=115200
+#init_uart_baud=115200
## init_uart_clock
## Initial uart clock.
##
## Default 3000000 (3MHz)
##
-init_uart_clock=3000000
+#init_uart_clock=3000000
## init_emmc_clock
## Initial emmc clock, increasing this can speedup your SD-card.
@@ -928,11 +935,17 @@ init_uart_clock=3000000
dtparam=random=on,watchdog=on,audio=on,i2c0=on,i2c1=on,spi=on
-#dtoverlay=hifiberry-amp-overlay
-#dtoverlay=hifiberry-dac-overlay
-#dtoverlay=hifiberry-dacplus-overlay
-#dtoverlay=hifiberry-digi-overlay
-#dtoverlay=iqaudio-dac-overlay
-#dtoverlay=iqaudio-dacplus-overlay
-#dtoverlay=raspidac3-overlay
-#dtoverlay=rpi-proto-overlay
+#dtoverlay=adau1977-adc
+#dtoverlay=audioinjector-wm8731-audio
+#dtoverlay=hifiberry-amp
+#dtoverlay=hifiberry-dac
+#dtoverlay=hifiberry-dacplus
+#dtoverlay=hifiberry-digi
+#dtoverlay=iqaudio-dac
+#dtoverlay=iqaudio-dacplus
+#dtoverlay=justboom-dac
+#dtoverlay=justboom-digi
+#dtoverlay=raspidac3
+#dtoverlay=rpi-dac
+#dtoverlay=rpi-proto
+#dtoverlay=rra-digidac1-wm8741-audio
diff --git a/target/linux/brcm2708/modules.mk b/target/linux/brcm2708/modules.mk
index 04e6aa9233..bfe3e44014 100644
--- a/target/linux/brcm2708/modules.mk
+++ b/target/linux/brcm2708/modules.mk
@@ -44,6 +44,79 @@ endef
$(eval $(call KernelPackage,sound-soc-bcm2835-i2s))
+define KernelPackage/sound-soc-adau1977-adc
+ TITLE:=Support for ADAU1977 ADC
+ KCONFIG:= \
+ CONFIG_SND_BCM2708_SOC_ADAU1977_ADC \
+ CONFIG_SND_SOC_ADAU1977 \
+ CONFIG_SND_SOC_ADAU1977_I2C
+ FILES:= \
+ $(LINUX_DIR)/sound/soc/bcm/snd-soc-adau1977-adc.ko \
+ $(LINUX_DIR)/sound/soc/codecs/snd-soc-adau1977.ko \
+ $(LINUX_DIR)/sound/soc/codecs/snd-soc-adau1977-i2c.ko
+ AUTOLOAD:=$(call AutoLoad,68,snd-soc-adau1977 snd-soc-adau1977-i2c \
+ snd-soc-adau1977-adc)
+ DEPENDS:= \
+ kmod-sound-soc-bcm2835-i2s \
+ +kmod-i2c-bcm2708
+ $(call AddDepends/sound)
+endef
+
+define KernelPackage/sound-soc-adau1977-adc/description
+ This package contains support for ADAU1977 ADC
+endef
+
+$(eval $(call KernelPackage,sound-soc-adau1977-adc))
+
+define KernelPackage/sound-soc-audioinjector-pi-soundcard
+ TITLE:=Support for AudioInjector Pi soundcard
+ KCONFIG:= \
+ CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD \
+ CONFIG_SND_SOC_WM8731
+ FILES:= \
+ $(LINUX_DIR)/sound/soc/bcm/snd-soc-audioinjector-pi-soundcard.ko \
+ $(LINUX_DIR)/sound/soc/codecs/snd-soc-wm8731.ko
+ AUTOLOAD:=$(call AutoLoad,68,snd-soc-wm8731 \
+ snd-soc-audioinjector-pi-soundcard)
+ DEPENDS:= \
+ kmod-sound-soc-bcm2835-i2s \
+ +kmod-i2c-bcm2708
+ $(call AddDepends/sound)
+endef
+
+define KernelPackage/sound-soc-audioinjector-pi-soundcard/description
+ This package contains support for AudioInjector Pi soundcard
+endef
+
+$(eval $(call KernelPackage,sound-soc-audioinjector-pi-soundcard))
+
+define KernelPackage/sound-soc-digidac1-soundcard
+ TITLE:=Support for RRA DigiDAC1
+ KCONFIG:= \
+ CONFIG_SND_DIGIDAC1_SOUNDCARD \
+ CONFIG_SND_SOC_WM8741 \
+ CONFIG_SND_SOC_WM8804 \
+ CONFIG_SND_SOC_WM8804_I2C
+ FILES:= \
+ $(LINUX_DIR)/sound/soc/bcm/snd-soc-digidac1-soundcard.ko \
+ $(LINUX_DIR)/sound/soc/codecs/snd-soc-wm8741.ko \
+ $(LINUX_DIR)/sound/soc/codecs/snd-soc-wm8804.ko \
+ $(LINUX_DIR)/sound/soc/codecs/snd-soc-wm8804-i2c.ko
+ AUTOLOAD:=$(call AutoLoad,68,snd-soc-snd-soc-wm8741 \
+ snd-soc-snd-soc-wm8804 snd-soc-snd-soc-wm8804-i2c \
+ snd-soc-digidac1-soundcard)
+ DEPENDS:= \
+ kmod-sound-soc-bcm2835-i2s \
+ +kmod-i2c-bcm2708
+ $(call AddDepends/sound)
+endef
+
+define KernelPackage/sound-soc-digidac1-soundcard/description
+ This package contains support for RRA DigiDAC1
+endef
+
+$(eval $(call KernelPackage,sound-soc-digidac1-soundcard))
+
define KernelPackage/sound-soc-hifiberry-dac
TITLE:=Support for HifiBerry DAC
KCONFIG:= \
@@ -74,7 +147,8 @@ define KernelPackage/sound-soc-hifiberry-dacplus
$(LINUX_DIR)/drivers/clk/clk-hifiberry-dacpro.ko \
$(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)
+ AUTOLOAD:=$(call AutoLoad,68,clk-hifiberry-dacpro snd-soc-pcm512x \
+ snd-soc-hifiberry-dacplus)
DEPENDS:= \
kmod-sound-soc-bcm2835-i2s \
+kmod-i2c-bcm2708
@@ -129,70 +203,71 @@ endef
$(eval $(call KernelPackage,sound-soc-hifiberry-amp))
-define KernelPackage/sound-soc-rpi-dac
- TITLE:=Support for RPi-DAC
+define KernelPackage/sound-soc-iqaudio-dac
+ TITLE:=Support for IQaudIO-DAC
KCONFIG:= \
- CONFIG_SND_BCM2708_SOC_RPI_DAC \
- CONFIG_SND_SOC_PCM1794A
+ CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC \
+ CONFIG_SND_SOC_PCM512x \
+ CONFIG_SND_SOC_PCM512x_I2C
FILES:= \
- $(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)
+ $(LINUX_DIR)/sound/soc/bcm/snd-soc-iqaudio-dac.ko \
+ $(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-bcm2835-i2s \
+kmod-i2c-bcm2708
$(call AddDepends/sound)
endef
-define KernelPackage/sound-soc-rpi-dac/description
- This package contains support for RPi-DAC
+define KernelPackage/sound-soc-iqaudio-dac/description
+ This package contains support for IQaudIO-DAC
endef
-$(eval $(call KernelPackage,sound-soc-rpi-dac))
+$(eval $(call KernelPackage,sound-soc-iqaudio-dac))
-define KernelPackage/sound-soc-rpi-proto
- TITLE:=Support for RPi-PROTO
+define KernelPackage/sound-soc-justboom-dac
+ TITLE:=Support for JustBoom DAC
KCONFIG:= \
- CONFIG_SND_BCM2708_SOC_RPI_PROTO \
- CONFIG_SND_SOC_WM8731
+ CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC \
+ CONFIG_SND_SOC_PCM512x
FILES:= \
- $(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)
+ $(LINUX_DIR)/sound/soc/bcm/snd-soc-justboom-dac.ko \
+ $(LINUX_DIR)/sound/soc/codecs/snd-soc-pcm512x.ko
+ AUTOLOAD:=$(call AutoLoad,68,snd-soc-pcm512x snd-soc-justboom-dac)
DEPENDS:= \
kmod-sound-soc-bcm2835-i2s \
+kmod-i2c-bcm2708
$(call AddDepends/sound)
endef
-define KernelPackage/sound-soc-rpi-proto/description
- This package contains support for RPi-PROTO
+define KernelPackage/sound-soc-justboom-dac/description
+ This package contains support for JustBoom DAC
endef
-$(eval $(call KernelPackage,sound-soc-rpi-proto))
+$(eval $(call KernelPackage,sound-soc-justboom-dac))
-define KernelPackage/sound-soc-iqaudio-dac
- TITLE:=Support for IQaudIO-DAC
+define KernelPackage/sound-soc-justboom-digi
+ TITLE:=Support for JustBoom Digi
KCONFIG:= \
- CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC \
- CONFIG_SND_SOC_PCM512x \
- CONFIG_SND_SOC_PCM512x_I2C
+ CONFIG_SND_BCM2708_SOC_JUSTBOOM_DIGI \
+ CONFIG_SND_SOC_WM8804
FILES:= \
- $(LINUX_DIR)/sound/soc/bcm/snd-soc-iqaudio-dac.ko \
- $(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)
+ $(LINUX_DIR)/sound/soc/bcm/snd-soc-justboom-digi.ko \
+ $(LINUX_DIR)/sound/soc/codecs/snd-soc-wm8804.ko
+ AUTOLOAD:=$(call AutoLoad,68,snd-soc-wm8804 snd-soc-justboom-digi)
DEPENDS:= \
kmod-sound-soc-bcm2835-i2s \
+kmod-i2c-bcm2708
$(call AddDepends/sound)
endef
-define KernelPackage/sound-soc-iqaudio-dac/description
- This package contains support for IQaudIO-DAC
+define KernelPackage/sound-soc-justboom-digi/description
+ This package contains support for JustBoom Digi
endef
-$(eval $(call KernelPackage,sound-soc-iqaudio-dac))
+$(eval $(call KernelPackage,sound-soc-justboom-digi))
define KernelPackage/sound-soc-raspidac3
TITLE:=Support for RaspiDAC Rev.3x
@@ -206,7 +281,8 @@ define KernelPackage/sound-soc-raspidac3
$(LINUX_DIR)/sound/soc/codecs/snd-soc-pcm512x.ko \
$(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)
+ AUTOLOAD:=$(call AutoLoad,68,snd-soc-pcm512x snd-soc-pcm512x-i2c \
+ snd-soc-tpa6130a2 snd-soc-raspidac3)
DEPENDS:= \
kmod-sound-soc-bcm2835-i2s \
+kmod-i2c-bcm2708
@@ -219,6 +295,48 @@ endef
$(eval $(call KernelPackage,sound-soc-raspidac3))
+define KernelPackage/sound-soc-rpi-dac
+ TITLE:=Support for RPi-DAC
+ KCONFIG:= \
+ CONFIG_SND_BCM2708_SOC_RPI_DAC \
+ CONFIG_SND_SOC_PCM1794A
+ FILES:= \
+ $(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-bcm2835-i2s \
+ +kmod-i2c-bcm2708
+ $(call AddDepends/sound)
+endef
+
+define KernelPackage/sound-soc-rpi-dac/description
+ This package contains support for RPi-DAC
+endef
+
+$(eval $(call KernelPackage,sound-soc-rpi-dac))
+
+define KernelPackage/sound-soc-rpi-proto
+ TITLE:=Support for RPi-PROTO
+ KCONFIG:= \
+ CONFIG_SND_BCM2708_SOC_RPI_PROTO \
+ CONFIG_SND_SOC_WM8731
+ FILES:= \
+ $(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-bcm2835-i2s \
+ +kmod-i2c-bcm2708
+ $(call AddDepends/sound)
+endef
+
+define KernelPackage/sound-soc-rpi-proto/description
+ This package contains support for RPi-PROTO
+endef
+
+$(eval $(call KernelPackage,sound-soc-rpi-proto))
+
define KernelPackage/random-bcm2835
SUBMENU:=$(OTHER_MENU)
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
index 960b448932..f657679693 100644
--- 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
@@ -1,7 +1,7 @@
-From b6cc28abbbf710379772d3da9227ce66926c46a3 Mon Sep 17 00:00:00 2001
+From 436932c454197f4f1e8707fc3d99d2908e6b842c 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/170] smsx95xx: fix crimes against truesize
+Subject: [PATCH 001/381] 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.
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
index 8ed786b538..3284eea00a 100644
--- 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
@@ -1,7 +1,7 @@
-From 37e24d2f0af32632a17692076dddcf176d1af1f7 Mon Sep 17 00:00:00 2001
+From 012687428d83585c5d55a08b3779ea278fcc35f6 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Fri, 17 Apr 2015 16:58:45 +0100
-Subject: [PATCH 002/170] smsc95xx: Disable turbo mode by default
+Subject: [PATCH 002/381] smsc95xx: Disable turbo mode by default
---
drivers/net/usb/smsc95xx.c | 2 +-
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
index 63d51ba506..7b19ae7894 100644
--- 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
@@ -1,7 +1,7 @@
-From d5cb475205138f9df1fdbb74d8810ab1928696ea Mon Sep 17 00:00:00 2001
+From f5f66abf7c99c7786991f7bdd1b91195e8b48913 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 18 Jun 2014 13:42:01 +0100
-Subject: [PATCH 003/170] vmstat: Workaround for issue where dirty page count
+Subject: [PATCH 003/381] vmstat: Workaround for issue where dirty page count
goes negative
See:
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
index 0d348cabcd..1ae2cd4979 100644
--- 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
@@ -1,7 +1,7 @@
-From 249a499b1d4b6f8a57b3377d4f505841e99f60c8 Mon Sep 17 00:00:00 2001
+From 47658fca0d3c3476d19d78a985aa105022c96d91 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/170] BCM2835_DT: Fix I2S register map
+Subject: [PATCH 004/381] BCM2835_DT: Fix I2S register map
---
Documentation/devicetree/bindings/dma/brcm,bcm2835-dma.txt | 4 ++--
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
index a2e71925cd..a585d9c3d8 100644
--- 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
@@ -1,7 +1,7 @@
-From c24657505a2aac71d0409b0ef703fc21ecab4b2e Mon Sep 17 00:00:00 2001
+From 3031c97bab942c5bc206ea1eef5be76f147026f9 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/170] irq-bcm2836: Prevent spurious interrupts, and trap
+Subject: [PATCH 005/381] irq-bcm2836: Prevent spurious interrupts, and trap
them early
The old arch-specific IRQ macros included a dsb to ensure the
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
index 16d431e4cb..1ac60f4f0e 100644
--- 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
@@ -1,7 +1,7 @@
-From 229bcf2e73ce37e8a18d68773471024c848d84bd Mon Sep 17 00:00:00 2001
+From 3e40206244596cbf6a8056c5e1f1c5aecd446452 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/170] irqchip: bcm2835: Add FIQ support
+Subject: [PATCH 006/381] irqchip: bcm2835: Add FIQ support
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
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
index 6025b7a9b1..46f8c77d6a 100644
--- 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
@@ -1,7 +1,7 @@
-From 6780f0a5c6af19f2b9850e961a0f81fbfdfa48fe Mon Sep 17 00:00:00 2001
+From ead6c040137ae0efb3936f186740b600aff48c6e 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/170] irqchip: irq-bcm2835: Add 2836 FIQ support
+Subject: [PATCH 007/381] irqchip: irq-bcm2835: Add 2836 FIQ support
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
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
index 5c624a8db0..e414910619 100644
--- 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
@@ -1,7 +1,7 @@
-From 4b9529b98c01569dff06f4e67ba28a47318e5ea5 Mon Sep 17 00:00:00 2001
+From 781c45f28a16084b550f2f096b89193d59b9b3e9 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/170] serial: 8250: Don't crash when nr_uarts is 0
+Subject: [PATCH 008/381] serial: 8250: Don't crash when nr_uarts is 0
---
drivers/tty/serial/8250/8250_core.c | 2 ++
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
index fca587747c..edf6ccf096 100644
--- 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
@@ -1,7 +1,7 @@
-From 5fd6ab82b1027504faa66cf4fc8b999fafaacd12 Mon Sep 17 00:00:00 2001
+From f318a741dc08f59c828e06097374aef494ecaac4 Mon Sep 17 00:00:00 2001
From: notro <notro@tronnes.org>
Date: Thu, 10 Jul 2014 13:59:47 +0200
-Subject: [PATCH 009/170] pinctrl-bcm2835: Set base to 0 give expected gpio
+Subject: [PATCH 009/381] pinctrl-bcm2835: Set base to 0 give expected gpio
numbering
Signed-off-by: Noralf Tronnes <notro@tronnes.org>
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
index da3406b413..91e589861f 100644
--- 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
@@ -1,7 +1,7 @@
-From 4254ef2647e89061427836443eac60351b3306a7 Mon Sep 17 00:00:00 2001
+From ba96a12bf302436ffee953c51902a76d22775873 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/170] pinctrl-bcm2835: Fix interrupt handling for GPIOs
+Subject: [PATCH 010/381] pinctrl-bcm2835: Fix interrupt handling for GPIOs
28-31 and 46-53
Contrary to the documentation, the BCM2835 GPIO controller actually has
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
index 02656d9060..a55e420bc6 100644
--- 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
@@ -1,7 +1,7 @@
-From 93b12e64d0e2a8a65189dedd667e00b0a0fab60a Mon Sep 17 00:00:00 2001
+From bd6aa494e149070c03c9eab94f7e473cdca1cf97 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/170] pinctrl-bcm2835: Only request the interrupts listed
+Subject: [PATCH 011/381] pinctrl-bcm2835: Only request the interrupts listed
in the DTB
Although the GPIO controller can generate three interrupts (four counting
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
index 46c37ec973..100cb382b9 100644
--- 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
@@ -1,7 +1,7 @@
-From bb8ff388ad26721eebb7249afb6f6f57bc196de4 Mon Sep 17 00:00:00 2001
+From b20f3df1e261b9a3b9d0051d32a966c251cb3020 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/170] spi-bcm2835: Support pin groups other than 7-11
+Subject: [PATCH 012/381] 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
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
index a0860d1dbf..f8d2f1184d 100644
--- 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
@@ -1,7 +1,7 @@
-From bfcfed788d152e828747ea889a88f8b179217ddb Mon Sep 17 00:00:00 2001
+From 1c2be61a1a6e2eb7cc8b337d732563609f5d8299 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/170] ARM: bcm2835: Set Serial number and Revision
+Subject: [PATCH 013/381] ARM: bcm2835: Set Serial number and Revision
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
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
index 0e4726d458..9e236b2bbb 100644
--- 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
@@ -1,7 +1,7 @@
-From fb968a02c00e2722df2dcfec6f54b7524ff5a155 Mon Sep 17 00:00:00 2001
+From 208e73d0e230d021c7b1d778451cbaa6074e6969 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/170] bcm2835-i2s: get base address for DMA from devicetree
+Subject: [PATCH 014/381] bcm2835-i2s: get base address for DMA from devicetree
Code copied from spi-bcm2835. Get physical address from devicetree
instead of using hardcoded constant.
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
index 79fe1b43a9..b33ccfff79 100644
--- 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
@@ -1,7 +1,7 @@
-From abbe565abfe075b76e01b9671c6fc4cf42cc0328 Mon Sep 17 00:00:00 2001
+From 6dc3da3194a366075cd7187a1119bb9d3834eea6 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/170] bcm2835-i2s: add 24bit support, update bclk_ratio to
+Subject: [PATCH 015/381] bcm2835-i2s: add 24bit support, update bclk_ratio to
more correct values
Code ported from bcm2708-i2s driver in Raspberry Pi tree.
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
index 810f83fb8e..a769152ada 100644
--- 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
@@ -1,7 +1,7 @@
-From b2cc62cd13099d6d2f21b9927df248aa3bdd8d5b Mon Sep 17 00:00:00 2001
+From e1eb1da5932b40e8a201b6b47d7ca2f72119e6e0 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/170] bcm2835-i2s: setup clock only if CPU is clock master
+Subject: [PATCH 016/381] bcm2835-i2s: setup clock only if CPU is clock master
Code ported from bcm2708-i2s driver in Raspberry Pi tree.
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
index 93c83fd682..241ca93e4f 100644
--- 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
@@ -1,7 +1,7 @@
-From 71b2c93cd332be280b9ca7f293e463f30d5fb108 Mon Sep 17 00:00:00 2001
+From b963ad6ff4edc8996000399529e0019a1e8b4dde 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/170] bcm2835-i2s: Eliminate debugfs directory error
+Subject: [PATCH 017/381] bcm2835-i2s: Eliminate debugfs directory error
Code ported from bcm2708-i2s driver in Raspberry Pi tree.
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
index 1b547fd6b9..b9c45aab01 100644
--- 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
@@ -1,7 +1,7 @@
-From fae43fcaa20df1d39c09c98372100bb1dedd6090 Mon Sep 17 00:00:00 2001
+From ea1121d3d44b53da76648d498bb1e02185f24198 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/170] bcm2835-i2s: Register PCM device
+Subject: [PATCH 018/381] bcm2835-i2s: Register PCM device
Code ported from bcm2708-i2s driver in Raspberry Pi tree.
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
index e68391ccce..3fcf32ce15 100644
--- 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
@@ -1,7 +1,7 @@
-From c9e2eeee4889f965a29744718bbff2de409ac649 Mon Sep 17 00:00:00 2001
+From d4e3e25ba7157e76f248ad9ec5a0ea87d47a06f8 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/170] bcm2835-i2s: Enable MMAP support via a DT property
+Subject: [PATCH 019/381] bcm2835-i2s: Enable MMAP support via a DT property
Code ported from bcm2708-i2s driver in Raspberry Pi tree.
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
index 97d6af0490..311e73281d 100644
--- 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
@@ -1,7 +1,7 @@
-From dc5b926436bccc4efbb1695ec3696b5db6746d3b Mon Sep 17 00:00:00 2001
+From a38557498a7aab4543c991a4f9f5638fe2d611d8 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/170] dmaengine: bcm2835: Add slave dma support
+Subject: [PATCH 020/381] dmaengine: bcm2835: Add slave dma support
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
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
index 14d217d3b6..b2f9231e7c 100644
--- 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
@@ -1,7 +1,7 @@
-From 9c6955f3fbfbb46242c63b4640886b9a0d87910a Mon Sep 17 00:00:00 2001
+From 7419ab49d75bc956578201a19008ba3390916d73 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/170] dmaengine: bcm2835: set residue_granularity field
+Subject: [PATCH 021/381] dmaengine: bcm2835: set residue_granularity field
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
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
index bc4e2028de..1f5a1d1f92 100644
--- 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
@@ -1,7 +1,7 @@
-From 8da7ee8d9b714dbbac842fb5ae0471b52e0393ec Mon Sep 17 00:00:00 2001
+From c64813bbb6d293b06994bd8ca2de6075953d8879 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/170] dmaengine: bcm2835: Load driver early and support
+Subject: [PATCH 022/381] dmaengine: bcm2835: Load driver early and support
legacy API
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
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
index 2f512e2aaa..c22d4b959a 100644
--- 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
@@ -1,7 +1,7 @@
-From 0f3a30eb7ad7e709fdc6447c70bc3f1d5704eb63 Mon Sep 17 00:00:00 2001
+From 15614a5ccb77b1a068e53cb4c85e4a65daf6a38f 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/170] bcm2835-dma: Fix dreq not set for slave transfers
+Subject: [PATCH 023/381] bcm2835-dma: Fix dreq not set for slave transfers
Set dreq to slave_id if it is not set like in bcm2708-dmaengine.
---
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
index 01217c9784..13d947ddb1 100644
--- 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
@@ -1,7 +1,7 @@
-From 305370f7caaecafbabb77b630380dbc0c436bb4c Mon Sep 17 00:00:00 2001
+From 4b94adab9a7d920d584ad95a633c30a244f6149b 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/170] bcm2835-dma: Limit cyclic transfers on lite channels
+Subject: [PATCH 024/381] bcm2835-dma: Limit cyclic transfers on lite channels
to 32k
Transfers larger than 32k cause repeated clicking with I2S soundcards.
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
index 6a5d2cb14a..53ec4307e1 100644
--- 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
@@ -1,7 +1,7 @@
-From d801c33b7e2fb0d02ac11b95ea92b7d692286ffc Mon Sep 17 00:00:00 2001
+From 0b7e0b20da67546344f9fc8e57699adfe61b8953 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/170] bcm2835: Add support for uart1
+Subject: [PATCH 025/381] bcm2835: Add support for uart1
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
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
index bde8c0a6c3..4e3dfc97a6 100644
--- 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
@@ -1,7 +1,7 @@
-From 5e90e32b539720ad8c6c8d7ec462378685924f22 Mon Sep 17 00:00:00 2001
+From d1f1043ffe1ff3059a2a545a39b129d47006c131 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/170] firmware: bcm2835: Add missing property tags
+Subject: [PATCH 026/381] firmware: bcm2835: Add missing property tags
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
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
index 7a0f569c2e..249716c2b6 100644
--- 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
@@ -1,7 +1,7 @@
-From 894f124497e95c9af506af2ed7335857f2e71358 Mon Sep 17 00:00:00 2001
+From 4f6a7b0ff6afd26d069c4f6b8d3c4fb4b0cc186b Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sun, 12 May 2013 12:24:19 +0100
-Subject: [PATCH 027/170] Main bcm2708/bcm2709 linux port
+Subject: [PATCH 027/381] Main bcm2708/bcm2709 linux port
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
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
index c35eb6fbb2..9bcc9fcb99 100644
--- 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
@@ -1,7 +1,7 @@
-From 74b2c26348d94949561979a9a3ad61adcac74398 Mon Sep 17 00:00:00 2001
+From 06d95a4dd349c4d5f6b52e657ffd1a27e4df3faf Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 11 Nov 2015 21:01:15 +0000
-Subject: [PATCH 028/170] squash: include ARCH_BCM2708 / ARCH_BCM2709
+Subject: [PATCH 028/381] squash: include ARCH_BCM2708 / ARCH_BCM2709
---
drivers/char/hw_random/Kconfig | 2 +-
@@ -117,7 +117,7 @@ Subject: [PATCH 028/170] squash: include ARCH_BCM2708 / ARCH_BCM2709
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
+@@ -1282,7 +1282,7 @@ config BCM63XX_WDT
config BCM2835_WDT
tristate "Broadcom BCM2835 hardware watchdog"
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
index b1e5a49be0..6a116d07b3 100644
--- 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
@@ -1,7 +1,7 @@
-From a03df8d0f93365689c718f3d1fb62695e9fffe31 Mon Sep 17 00:00:00 2001
+From afd337386d8e58d2590d8f6c6ac85cfc1ba244a5 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 1 May 2013 19:46:17 +0100
-Subject: [PATCH 029/170] Add dwc_otg driver
+Subject: [PATCH 029/381] Add dwc_otg driver
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
diff --git a/target/linux/brcm2708/patches-4.4/0030-bcm2708-framebuffer-driver.patch b/target/linux/brcm2708/patches-4.4/0030-bcm2708-framebuffer-driver.patch
index 4dccb5e759..93141a2630 100644
--- a/target/linux/brcm2708/patches-4.4/0030-bcm2708-framebuffer-driver.patch
+++ b/target/linux/brcm2708/patches-4.4/0030-bcm2708-framebuffer-driver.patch
@@ -1,7 +1,7 @@
-From 845f985818d3d9ba162ab1102da78b0e39eaedba Mon Sep 17 00:00:00 2001
+From f370b4458afa944f9e960e95af476c15c8370c56 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 17 Jun 2015 17:06:34 +0100
-Subject: [PATCH 030/170] bcm2708 framebuffer driver
+Subject: [PATCH 030/381] bcm2708 framebuffer driver
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
diff --git a/target/linux/brcm2708/patches-4.4/0031-dmaengine-Add-support-for-BCM2708.patch b/target/linux/brcm2708/patches-4.4/0031-dmaengine-Add-support-for-BCM2708.patch
index 9796cb5f49..e1107d6b9c 100644
--- a/target/linux/brcm2708/patches-4.4/0031-dmaengine-Add-support-for-BCM2708.patch
+++ b/target/linux/brcm2708/patches-4.4/0031-dmaengine-Add-support-for-BCM2708.patch
@@ -1,7 +1,7 @@
-From a35139d316b78606bfdeb0f10656ba6f1729c83f Mon Sep 17 00:00:00 2001
+From 2ea9159435f6fdc6190126e7c413cb8c37259036 Mon Sep 17 00:00:00 2001
From: Florian Meier <florian.meier@koalo.de>
Date: Fri, 22 Nov 2013 14:22:53 +0100
-Subject: [PATCH 031/170] dmaengine: Add support for BCM2708
+Subject: [PATCH 031/381] dmaengine: Add support for BCM2708
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
diff --git a/target/linux/brcm2708/patches-4.4/0032-Add-blk_pos-parameter-to-mmc-multi_io_quirk-callback.patch b/target/linux/brcm2708/patches-4.4/0032-Add-blk_pos-parameter-to-mmc-multi_io_quirk-callback.patch
deleted file mode 100644
index 46835f15f3..0000000000
--- a/target/linux/brcm2708/patches-4.4/0032-Add-blk_pos-parameter-to-mmc-multi_io_quirk-callback.patch
+++ /dev/null
@@ -1,75 +0,0 @@
-From 462591cf98f15614620667e93b7f8bc0da6e86da Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Fri, 17 Apr 2015 19:30:22 +0100
-Subject: [PATCH 032/170] Add blk_pos parameter to mmc multi_io_quirk callback
-
----
- drivers/mmc/card/block.c | 1 +
- drivers/mmc/host/omap_hsmmc.c | 4 +++-
- drivers/mmc/host/sh_mobile_sdhi.c | 4 +++-
- drivers/mmc/host/tmio_mmc_pio.c | 4 +++-
- include/linux/mmc/host.h | 4 +++-
- 5 files changed, 13 insertions(+), 4 deletions(-)
-
---- a/drivers/mmc/card/block.c
-+++ b/drivers/mmc/card/block.c
-@@ -1518,6 +1518,7 @@ static void mmc_blk_rw_rq_prep(struct mm
- brq->data.blocks = card->host->ops->multi_io_quirk(card,
- (rq_data_dir(req) == READ) ?
- MMC_DATA_READ : MMC_DATA_WRITE,
-+ blk_rq_pos(req),
- brq->data.blocks);
- }
-
---- a/drivers/mmc/host/omap_hsmmc.c
-+++ b/drivers/mmc/host/omap_hsmmc.c
-@@ -1832,7 +1832,9 @@ static void omap_hsmmc_conf_bus_power(st
- }
-
- static int omap_hsmmc_multi_io_quirk(struct mmc_card *card,
-- unsigned int direction, int blk_size)
-+ unsigned int direction,
-+ u32 blk_pos,
-+ int blk_size)
- {
- /* This controller can't do multiblock reads due to hw bugs */
- if (direction == MMC_DATA_READ)
---- a/drivers/mmc/host/sh_mobile_sdhi.c
-+++ b/drivers/mmc/host/sh_mobile_sdhi.c
-@@ -170,7 +170,9 @@ static int sh_mobile_sdhi_write16_hook(s
- }
-
- static int sh_mobile_sdhi_multi_io_quirk(struct mmc_card *card,
-- unsigned int direction, int blk_size)
-+ unsigned int direction,
-+ u32 blk_pos,
-+ int blk_size)
- {
- /*
- * In Renesas controllers, when performing a
---- a/drivers/mmc/host/tmio_mmc_pio.c
-+++ b/drivers/mmc/host/tmio_mmc_pio.c
-@@ -1003,7 +1003,9 @@ static int tmio_mmc_get_ro(struct mmc_ho
- }
-
- static int tmio_multi_io_quirk(struct mmc_card *card,
-- unsigned int direction, int blk_size)
-+ unsigned int direction,
-+ u32 blk_pos,
-+ int blk_size)
- {
- struct tmio_mmc_host *host = mmc_priv(card->host);
-
---- a/include/linux/mmc/host.h
-+++ b/include/linux/mmc/host.h
-@@ -143,7 +143,9 @@ struct mmc_host_ops {
- * I/O. Returns the number of supported blocks for the request.
- */
- int (*multi_io_quirk)(struct mmc_card *card,
-- unsigned int direction, int blk_size);
-+ unsigned int direction,
-+ u32 blk_pos,
-+ int blk_size);
- };
-
- struct mmc_card;
diff --git a/target/linux/brcm2708/patches-4.4/0032-MMC-added-alternative-MMC-driver.patch b/target/linux/brcm2708/patches-4.4/0032-MMC-added-alternative-MMC-driver.patch
new file mode 100644
index 0000000000..6187a65c66
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0032-MMC-added-alternative-MMC-driver.patch
@@ -0,0 +1,1691 @@
+From ded251905fe3ebb582fd87fecf3454834333afa1 Mon Sep 17 00:00:00 2001
+From: gellert <gellert@raspberrypi.org>
+Date: Fri, 15 Aug 2014 16:35:06 +0100
+Subject: [PATCH 032/381] MMC: added alternative MMC driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+mmc: Disable CMD23 transfers on all cards
+
+Pending wire-level investigation of these types of transfers
+and associated errors on bcm2835-mmc, disable for now. Fallback of
+CMD18/CMD25 transfers will be used automatically by the MMC layer.
+
+Reported/Tested-by: Gellert Weisz <gellert@raspberrypi.org>
+
+mmc: bcm2835-mmc: enable DT support for all architectures
+
+Both ARCH_BCM2835 and ARCH_BCM270x are built with OF now.
+Enable Device Tree support for all architectures.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+
+mmc: bcm2835-mmc: fix probe error handling
+
+Probe error handling is broken in several places.
+Simplify error handling by using device managed functions.
+Replace pr_{err,info} with dev_{err,info}.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+
+bcm2835-mmc: Add locks when accessing sdhost registers
+
+bcm2835-mmc: Add range of debug options for slowing things down
+
+bcm2835-mmc: Add option to disable some delays
+
+bcm2835-mmc: Add option to disable MMC_QUIRK_BLK_NO_CMD23
+
+bcm2835-mmc: Default to disabling MMC_QUIRK_BLK_NO_CMD23
+
+bcm2835-mmc: Adding overclocking option
+
+Allow a different clock speed to be substitued for a requested 50MHz.
+This option is exposed using the "overclock_50" DT parameter.
+Note that the mmc interface is restricted to EVEN integer divisions of
+250MHz, and the highest sensible option is 63 (250/4 = 62.5), the
+next being 125 (250/2) which is much too high.
+
+Use at your own risk.
+
+bcm2835-mmc: Round up the overclock, so 62 works for 62.5Mhz
+
+Also only warn once for each overclock setting.
+
+mmc: bcm2835-mmc: Make available on ARCH_BCM2835
+
+Make the bcm2835-mmc driver available for use on ARCH_BCM2835.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+
+BCM270x_DT: add bcm2835-mmc entry
+
+Add Device Tree entry for bcm2835-mmc.
+In non-DT mode, don't add the device in the board file.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+
+bcm2835-mmc: Don't overwrite MMC capabilities from DT
+---
+ drivers/mmc/core/quirks.c | 6 +
+ drivers/mmc/host/Kconfig | 29 +
+ drivers/mmc/host/Makefile | 1 +
+ drivers/mmc/host/bcm2835-mmc.c | 1542 ++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 1578 insertions(+)
+ create mode 100644 drivers/mmc/host/bcm2835-mmc.c
+
+--- a/drivers/mmc/core/quirks.c
++++ b/drivers/mmc/core/quirks.c
+@@ -53,6 +53,7 @@ static const struct mmc_fixup mmc_fixup_
+
+ void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table)
+ {
++ extern unsigned mmc_debug;
+ const struct mmc_fixup *f;
+ u64 rev = cid_rev_card(card);
+
+@@ -77,5 +78,10 @@ void mmc_fixup_device(struct mmc_card *c
+ f->vendor_fixup(card, f->data);
+ }
+ }
++ /* SDHCI on BCM2708 - bug causes a certain sequence of CMD23 operations to fail.
++ * Disable this flag for all cards (fall-back to CMD25/CMD18 multi-block transfers).
++ */
++ if (mmc_debug & (1<<13))
++ card->quirks |= MMC_QUIRK_BLK_NO_CMD23;
+ }
+ EXPORT_SYMBOL(mmc_fixup_device);
+--- a/drivers/mmc/host/Kconfig
++++ b/drivers/mmc/host/Kconfig
+@@ -4,6 +4,35 @@
+
+ comment "MMC/SD/SDIO Host Controller Drivers"
+
++config MMC_BCM2835
++ tristate "MMC support on BCM2835"
++ depends on MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835
++ help
++ This selects the MMC Interface on BCM2835.
++
++ If you have a controller with this interface, say Y or M here.
++
++ If unsure, say N.
++
++config MMC_BCM2835_DMA
++ bool "DMA support on BCM2835 Arasan controller"
++ depends on MMC_BCM2835
++ help
++ Enable DMA support on the Arasan SDHCI controller in Broadcom 2708
++ based chips.
++
++ If unsure, say N.
++
++config MMC_BCM2835_PIO_DMA_BARRIER
++ int "Block count limit for PIO transfers"
++ depends on MMC_BCM2835 && MMC_BCM2835_DMA
++ range 0 256
++ default 2
++ help
++ The inclusive limit in bytes under which PIO will be used instead of DMA
++
++ If unsure, say 2 here.
++
+ config MMC_ARMMMCI
+ tristate "ARM AMBA Multimedia Card Interface support"
+ depends on ARM_AMBA
+--- a/drivers/mmc/host/Makefile
++++ b/drivers/mmc/host/Makefile
+@@ -18,6 +18,7 @@ obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c
+ obj-$(CONFIG_MMC_SDHCI_SIRF) += sdhci-sirf.o
+ obj-$(CONFIG_MMC_SDHCI_F_SDH30) += sdhci_f_sdh30.o
+ obj-$(CONFIG_MMC_SDHCI_SPEAR) += sdhci-spear.o
++obj-$(CONFIG_MMC_BCM2835) += bcm2835-mmc.o
+ obj-$(CONFIG_MMC_WBSD) += wbsd.o
+ obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
+ obj-$(CONFIG_MMC_MTK) += mtk-sd.o
+--- /dev/null
++++ b/drivers/mmc/host/bcm2835-mmc.c
+@@ -0,0 +1,1542 @@
++/*
++ * BCM2835 MMC host driver.
++ *
++ * Author: Gellert Weisz <gellert@raspberrypi.org>
++ * Copyright 2014
++ *
++ * Based on
++ * sdhci-bcm2708.c by Broadcom
++ * sdhci-bcm2835.c by Stephen Warren and Oleksandr Tymoshenko
++ * sdhci.c and sdhci-pci.c by Pierre Ossman
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/delay.h>
++#include <linux/module.h>
++#include <linux/io.h>
++#include <linux/mmc/mmc.h>
++#include <linux/mmc/host.h>
++#include <linux/mmc/sd.h>
++#include <linux/scatterlist.h>
++#include <linux/of_address.h>
++#include <linux/of_irq.h>
++#include <linux/clk.h>
++#include <linux/platform_device.h>
++#include <linux/err.h>
++#include <linux/blkdev.h>
++#include <linux/dmaengine.h>
++#include <linux/dma-mapping.h>
++#include <linux/of_dma.h>
++
++#include "sdhci.h"
++
++
++#define DRIVER_NAME "mmc-bcm2835"
++
++#define DBG(f, x...) \
++pr_debug(DRIVER_NAME " [%s()]: " f, __func__, ## x)
++
++#ifndef CONFIG_MMC_BCM2835_DMA
++ #define FORCE_PIO
++#endif
++
++
++/* the inclusive limit in bytes under which PIO will be used instead of DMA */
++#ifdef CONFIG_MMC_BCM2835_PIO_DMA_BARRIER
++#define PIO_DMA_BARRIER CONFIG_MMC_BCM2835_PIO_DMA_BARRIER
++#else
++#define PIO_DMA_BARRIER 00
++#endif
++
++#define MIN_FREQ 400000
++#define TIMEOUT_VAL 0xE
++#define BCM2835_SDHCI_WRITE_DELAY(f) (((2 * 1000000) / f) + 1)
++
++
++unsigned mmc_debug;
++unsigned mmc_debug2;
++
++struct bcm2835_host {
++ spinlock_t lock;
++
++ void __iomem *ioaddr;
++ u32 bus_addr;
++
++ struct mmc_host *mmc;
++
++ u32 timeout;
++
++ int clock; /* Current clock speed */
++ u8 pwr; /* Current voltage */
++
++ unsigned int max_clk; /* Max possible freq */
++ unsigned int timeout_clk; /* Timeout freq (KHz) */
++ unsigned int clk_mul; /* Clock Muliplier value */
++
++ struct tasklet_struct finish_tasklet; /* Tasklet structures */
++
++ struct timer_list timer; /* Timer for timeouts */
++
++ struct sg_mapping_iter sg_miter; /* SG state for PIO */
++ unsigned int blocks; /* remaining PIO blocks */
++
++ int irq; /* Device IRQ */
++
++
++ u32 ier; /* cached registers */
++
++ struct mmc_request *mrq; /* Current request */
++ struct mmc_command *cmd; /* Current command */
++ struct mmc_data *data; /* Current data request */
++ unsigned int data_early:1; /* Data finished before cmd */
++
++ wait_queue_head_t buf_ready_int; /* Waitqueue for Buffer Read Ready interrupt */
++
++ u32 thread_isr;
++
++ u32 shadow;
++
++ /*DMA part*/
++ struct dma_chan *dma_chan_rx; /* DMA channel for reads */
++ struct dma_chan *dma_chan_tx; /* DMA channel for writes */
++ struct dma_async_tx_descriptor *tx_desc; /* descriptor */
++
++ bool have_dma;
++ bool use_dma;
++ /*end of DMA part*/
++
++ int max_delay; /* maximum length of time spent waiting */
++
++ int flags; /* Host attributes */
++#define SDHCI_REQ_USE_DMA (1<<2) /* Use DMA for this req. */
++#define SDHCI_DEVICE_DEAD (1<<3) /* Device unresponsive */
++#define SDHCI_AUTO_CMD12 (1<<6) /* Auto CMD12 support */
++#define SDHCI_AUTO_CMD23 (1<<7) /* Auto CMD23 support */
++#define SDHCI_SDIO_IRQ_ENABLED (1<<9) /* SDIO irq enabled */
++
++ u32 overclock_50; /* frequency to use when 50MHz is requested (in MHz) */
++ u32 max_overclock; /* Highest reported */
++};
++
++
++static inline void bcm2835_mmc_writel(struct bcm2835_host *host, u32 val, int reg, int from)
++{
++ unsigned delay;
++ lockdep_assert_held_once(&host->lock);
++ writel(val, host->ioaddr + reg);
++ udelay(BCM2835_SDHCI_WRITE_DELAY(max(host->clock, MIN_FREQ)));
++
++ delay = ((mmc_debug >> 16) & 0xf) << ((mmc_debug >> 20) & 0xf);
++ if (delay && !((1<<from) & mmc_debug2))
++ udelay(delay);
++}
++
++static inline void mmc_raw_writel(struct bcm2835_host *host, u32 val, int reg)
++{
++ unsigned delay;
++ lockdep_assert_held_once(&host->lock);
++ writel(val, host->ioaddr + reg);
++
++ delay = ((mmc_debug >> 24) & 0xf) << ((mmc_debug >> 28) & 0xf);
++ if (delay)
++ udelay(delay);
++}
++
++static inline u32 bcm2835_mmc_readl(struct bcm2835_host *host, int reg)
++{
++ lockdep_assert_held_once(&host->lock);
++ return readl(host->ioaddr + reg);
++}
++
++static inline void bcm2835_mmc_writew(struct bcm2835_host *host, u16 val, int reg)
++{
++ u32 oldval = (reg == SDHCI_COMMAND) ? host->shadow :
++ bcm2835_mmc_readl(host, reg & ~3);
++ u32 word_num = (reg >> 1) & 1;
++ u32 word_shift = word_num * 16;
++ u32 mask = 0xffff << word_shift;
++ u32 newval = (oldval & ~mask) | (val << word_shift);
++
++ if (reg == SDHCI_TRANSFER_MODE)
++ host->shadow = newval;
++ else
++ bcm2835_mmc_writel(host, newval, reg & ~3, 0);
++
++}
++
++static inline void bcm2835_mmc_writeb(struct bcm2835_host *host, u8 val, int reg)
++{
++ u32 oldval = bcm2835_mmc_readl(host, reg & ~3);
++ u32 byte_num = reg & 3;
++ u32 byte_shift = byte_num * 8;
++ u32 mask = 0xff << byte_shift;
++ u32 newval = (oldval & ~mask) | (val << byte_shift);
++
++ bcm2835_mmc_writel(host, newval, reg & ~3, 1);
++}
++
++
++static inline u16 bcm2835_mmc_readw(struct bcm2835_host *host, int reg)
++{
++ u32 val = bcm2835_mmc_readl(host, (reg & ~3));
++ u32 word_num = (reg >> 1) & 1;
++ u32 word_shift = word_num * 16;
++ u32 word = (val >> word_shift) & 0xffff;
++
++ return word;
++}
++
++static inline u8 bcm2835_mmc_readb(struct bcm2835_host *host, int reg)
++{
++ u32 val = bcm2835_mmc_readl(host, (reg & ~3));
++ u32 byte_num = reg & 3;
++ u32 byte_shift = byte_num * 8;
++ u32 byte = (val >> byte_shift) & 0xff;
++
++ return byte;
++}
++
++static void bcm2835_mmc_unsignal_irqs(struct bcm2835_host *host, u32 clear)
++{
++ u32 ier;
++
++ ier = bcm2835_mmc_readl(host, SDHCI_SIGNAL_ENABLE);
++ ier &= ~clear;
++ /* change which requests generate IRQs - makes no difference to
++ the content of SDHCI_INT_STATUS, or the need to acknowledge IRQs */
++ bcm2835_mmc_writel(host, ier, SDHCI_SIGNAL_ENABLE, 2);
++}
++
++
++static void bcm2835_mmc_dumpregs(struct bcm2835_host *host)
++{
++ pr_debug(DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n",
++ mmc_hostname(host->mmc));
++
++ pr_debug(DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n",
++ bcm2835_mmc_readl(host, SDHCI_DMA_ADDRESS),
++ bcm2835_mmc_readw(host, SDHCI_HOST_VERSION));
++ pr_debug(DRIVER_NAME ": Blk size: 0x%08x | Blk cnt: 0x%08x\n",
++ bcm2835_mmc_readw(host, SDHCI_BLOCK_SIZE),
++ bcm2835_mmc_readw(host, SDHCI_BLOCK_COUNT));
++ pr_debug(DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n",
++ bcm2835_mmc_readl(host, SDHCI_ARGUMENT),
++ bcm2835_mmc_readw(host, SDHCI_TRANSFER_MODE));
++ pr_debug(DRIVER_NAME ": Present: 0x%08x | Host ctl: 0x%08x\n",
++ bcm2835_mmc_readl(host, SDHCI_PRESENT_STATE),
++ bcm2835_mmc_readb(host, SDHCI_HOST_CONTROL));
++ pr_debug(DRIVER_NAME ": Power: 0x%08x | Blk gap: 0x%08x\n",
++ bcm2835_mmc_readb(host, SDHCI_POWER_CONTROL),
++ bcm2835_mmc_readb(host, SDHCI_BLOCK_GAP_CONTROL));
++ pr_debug(DRIVER_NAME ": Wake-up: 0x%08x | Clock: 0x%08x\n",
++ bcm2835_mmc_readb(host, SDHCI_WAKE_UP_CONTROL),
++ bcm2835_mmc_readw(host, SDHCI_CLOCK_CONTROL));
++ pr_debug(DRIVER_NAME ": Timeout: 0x%08x | Int stat: 0x%08x\n",
++ bcm2835_mmc_readb(host, SDHCI_TIMEOUT_CONTROL),
++ bcm2835_mmc_readl(host, SDHCI_INT_STATUS));
++ pr_debug(DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n",
++ bcm2835_mmc_readl(host, SDHCI_INT_ENABLE),
++ bcm2835_mmc_readl(host, SDHCI_SIGNAL_ENABLE));
++ pr_debug(DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n",
++ bcm2835_mmc_readw(host, SDHCI_ACMD12_ERR),
++ bcm2835_mmc_readw(host, SDHCI_SLOT_INT_STATUS));
++ pr_debug(DRIVER_NAME ": Caps: 0x%08x | Caps_1: 0x%08x\n",
++ bcm2835_mmc_readl(host, SDHCI_CAPABILITIES),
++ bcm2835_mmc_readl(host, SDHCI_CAPABILITIES_1));
++ pr_debug(DRIVER_NAME ": Cmd: 0x%08x | Max curr: 0x%08x\n",
++ bcm2835_mmc_readw(host, SDHCI_COMMAND),
++ bcm2835_mmc_readl(host, SDHCI_MAX_CURRENT));
++ pr_debug(DRIVER_NAME ": Host ctl2: 0x%08x\n",
++ bcm2835_mmc_readw(host, SDHCI_HOST_CONTROL2));
++
++ pr_debug(DRIVER_NAME ": ===========================================\n");
++}
++
++
++static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask)
++{
++ unsigned long timeout;
++ unsigned long flags;
++
++ spin_lock_irqsave(&host->lock, flags);
++ bcm2835_mmc_writeb(host, mask, SDHCI_SOFTWARE_RESET);
++
++ if (mask & SDHCI_RESET_ALL)
++ host->clock = 0;
++
++ /* Wait max 100 ms */
++ timeout = 100;
++
++ /* hw clears the bit when it's done */
++ while (bcm2835_mmc_readb(host, SDHCI_SOFTWARE_RESET) & mask) {
++ if (timeout == 0) {
++ pr_err("%s: Reset 0x%x never completed.\n",
++ mmc_hostname(host->mmc), (int)mask);
++ bcm2835_mmc_dumpregs(host);
++ return;
++ }
++ timeout--;
++ spin_unlock_irqrestore(&host->lock, flags);
++ mdelay(1);
++ spin_lock_irqsave(&host->lock, flags);
++ }
++
++ if (100-timeout > 10 && 100-timeout > host->max_delay) {
++ host->max_delay = 100-timeout;
++ pr_warning("Warning: MMC controller hung for %d ms\n", host->max_delay);
++ }
++ spin_unlock_irqrestore(&host->lock, flags);
++}
++
++static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
++
++static void bcm2835_mmc_init(struct bcm2835_host *host, int soft)
++{
++ unsigned long flags;
++ if (soft)
++ bcm2835_mmc_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA);
++ else
++ bcm2835_mmc_reset(host, SDHCI_RESET_ALL);
++
++ host->ier = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
++ SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT |
++ SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC |
++ SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END |
++ SDHCI_INT_RESPONSE;
++
++ spin_lock_irqsave(&host->lock, flags);
++ bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 3);
++ bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 3);
++ spin_unlock_irqrestore(&host->lock, flags);
++
++ if (soft) {
++ /* force clock reconfiguration */
++ host->clock = 0;
++ bcm2835_mmc_set_ios(host->mmc, &host->mmc->ios);
++ }
++}
++
++
++
++static void bcm2835_mmc_finish_data(struct bcm2835_host *host);
++
++static void bcm2835_mmc_dma_complete(void *param)
++{
++ struct bcm2835_host *host = param;
++ struct dma_chan *dma_chan;
++ unsigned long flags;
++ u32 dir_data;
++
++ spin_lock_irqsave(&host->lock, flags);
++
++ if (host->data && !(host->data->flags & MMC_DATA_WRITE)) {
++ /* otherwise handled in SDHCI IRQ */
++ dma_chan = host->dma_chan_rx;
++ dir_data = DMA_FROM_DEVICE;
++
++ dma_unmap_sg(dma_chan->device->dev,
++ host->data->sg, host->data->sg_len,
++ dir_data);
++
++ bcm2835_mmc_finish_data(host);
++ }
++
++ spin_unlock_irqrestore(&host->lock, flags);
++}
++
++static void bcm2835_bcm2835_mmc_read_block_pio(struct bcm2835_host *host)
++{
++ unsigned long flags;
++ size_t blksize, len, chunk;
++
++ u32 uninitialized_var(scratch);
++ u8 *buf;
++
++ blksize = host->data->blksz;
++ chunk = 0;
++
++ local_irq_save(flags);
++
++ while (blksize) {
++ if (!sg_miter_next(&host->sg_miter))
++ BUG();
++
++ len = min(host->sg_miter.length, blksize);
++
++ blksize -= len;
++ host->sg_miter.consumed = len;
++
++ buf = host->sg_miter.addr;
++
++ while (len) {
++ if (chunk == 0) {
++ scratch = bcm2835_mmc_readl(host, SDHCI_BUFFER);
++ chunk = 4;
++ }
++
++ *buf = scratch & 0xFF;
++
++ buf++;
++ scratch >>= 8;
++ chunk--;
++ len--;
++ }
++ }
++
++ sg_miter_stop(&host->sg_miter);
++
++ local_irq_restore(flags);
++}
++
++static void bcm2835_bcm2835_mmc_write_block_pio(struct bcm2835_host *host)
++{
++ unsigned long flags;
++ size_t blksize, len, chunk;
++ u32 scratch;
++ u8 *buf;
++
++ blksize = host->data->blksz;
++ chunk = 0;
++ chunk = 0;
++ scratch = 0;
++
++ local_irq_save(flags);
++
++ while (blksize) {
++ if (!sg_miter_next(&host->sg_miter))
++ BUG();
++
++ len = min(host->sg_miter.length, blksize);
++
++ blksize -= len;
++ host->sg_miter.consumed = len;
++
++ buf = host->sg_miter.addr;
++
++ while (len) {
++ scratch |= (u32)*buf << (chunk * 8);
++
++ buf++;
++ chunk++;
++ len--;
++
++ if ((chunk == 4) || ((len == 0) && (blksize == 0))) {
++ mmc_raw_writel(host, scratch, SDHCI_BUFFER);
++ chunk = 0;
++ scratch = 0;
++ }
++ }
++ }
++
++ sg_miter_stop(&host->sg_miter);
++
++ local_irq_restore(flags);
++}
++
++
++static void bcm2835_mmc_transfer_pio(struct bcm2835_host *host)
++{
++ u32 mask;
++
++ BUG_ON(!host->data);
++
++ if (host->blocks == 0)
++ return;
++
++ if (host->data->flags & MMC_DATA_READ)
++ mask = SDHCI_DATA_AVAILABLE;
++ else
++ mask = SDHCI_SPACE_AVAILABLE;
++
++ while (bcm2835_mmc_readl(host, SDHCI_PRESENT_STATE) & mask) {
++
++ if (host->data->flags & MMC_DATA_READ)
++ bcm2835_bcm2835_mmc_read_block_pio(host);
++ else
++ bcm2835_bcm2835_mmc_write_block_pio(host);
++
++ host->blocks--;
++
++ /* QUIRK used in sdhci.c removes the 'if' */
++ /* but it seems this is unnecessary */
++ if (host->blocks == 0)
++ break;
++
++
++ }
++}
++
++
++static void bcm2835_mmc_transfer_dma(struct bcm2835_host *host)
++{
++ u32 len, dir_data, dir_slave;
++ struct dma_async_tx_descriptor *desc = NULL;
++ struct dma_chan *dma_chan;
++
++
++ WARN_ON(!host->data);
++
++ if (!host->data)
++ return;
++
++ if (host->blocks == 0)
++ return;
++
++ if (host->data->flags & MMC_DATA_READ) {
++ dma_chan = host->dma_chan_rx;
++ dir_data = DMA_FROM_DEVICE;
++ dir_slave = DMA_DEV_TO_MEM;
++ } else {
++ dma_chan = host->dma_chan_tx;
++ dir_data = DMA_TO_DEVICE;
++ dir_slave = DMA_MEM_TO_DEV;
++ }
++
++ BUG_ON(!dma_chan->device);
++ BUG_ON(!dma_chan->device->dev);
++ BUG_ON(!host->data->sg);
++
++ len = dma_map_sg(dma_chan->device->dev, host->data->sg,
++ host->data->sg_len, dir_data);
++ if (len > 0) {
++ desc = dmaengine_prep_slave_sg(dma_chan, host->data->sg,
++ len, dir_slave,
++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++ } else {
++ dev_err(mmc_dev(host->mmc), "dma_map_sg returned zero length\n");
++ }
++ if (desc) {
++ unsigned long flags;
++ spin_lock_irqsave(&host->lock, flags);
++ bcm2835_mmc_unsignal_irqs(host, SDHCI_INT_DATA_AVAIL |
++ SDHCI_INT_SPACE_AVAIL);
++ host->tx_desc = desc;
++ desc->callback = bcm2835_mmc_dma_complete;
++ desc->callback_param = host;
++ spin_unlock_irqrestore(&host->lock, flags);
++ dmaengine_submit(desc);
++ dma_async_issue_pending(dma_chan);
++ }
++
++}
++
++
++
++static void bcm2835_mmc_set_transfer_irqs(struct bcm2835_host *host)
++{
++ u32 pio_irqs = SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL;
++ u32 dma_irqs = SDHCI_INT_DMA_END | SDHCI_INT_ADMA_ERROR;
++
++ if (host->use_dma)
++ host->ier = (host->ier & ~pio_irqs) | dma_irqs;
++ else
++ host->ier = (host->ier & ~dma_irqs) | pio_irqs;
++
++ bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 4);
++ bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 4);
++}
++
++
++static void bcm2835_mmc_prepare_data(struct bcm2835_host *host, struct mmc_command *cmd)
++{
++ u8 count;
++ struct mmc_data *data = cmd->data;
++
++ WARN_ON(host->data);
++
++ if (data || (cmd->flags & MMC_RSP_BUSY)) {
++ count = TIMEOUT_VAL;
++ bcm2835_mmc_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
++ }
++
++ if (!data)
++ return;
++
++ /* Sanity checks */
++ BUG_ON(data->blksz * data->blocks > 524288);
++ BUG_ON(data->blksz > host->mmc->max_blk_size);
++ BUG_ON(data->blocks > 65535);
++
++ host->data = data;
++ host->data_early = 0;
++ host->data->bytes_xfered = 0;
++
++
++ if (!(host->flags & SDHCI_REQ_USE_DMA)) {
++ int flags;
++
++ flags = SG_MITER_ATOMIC;
++ if (host->data->flags & MMC_DATA_READ)
++ flags |= SG_MITER_TO_SG;
++ else
++ flags |= SG_MITER_FROM_SG;
++ sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
++ host->blocks = data->blocks;
++ }
++
++ host->use_dma = host->have_dma && data->blocks > PIO_DMA_BARRIER;
++
++ bcm2835_mmc_set_transfer_irqs(host);
++
++ /* Set the DMA boundary value and block size */
++ bcm2835_mmc_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG,
++ data->blksz), SDHCI_BLOCK_SIZE);
++ bcm2835_mmc_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
++
++ BUG_ON(!host->data);
++}
++
++static void bcm2835_mmc_set_transfer_mode(struct bcm2835_host *host,
++ struct mmc_command *cmd)
++{
++ u16 mode;
++ struct mmc_data *data = cmd->data;
++
++ if (data == NULL) {
++ /* clear Auto CMD settings for no data CMDs */
++ mode = bcm2835_mmc_readw(host, SDHCI_TRANSFER_MODE);
++ bcm2835_mmc_writew(host, mode & ~(SDHCI_TRNS_AUTO_CMD12 |
++ SDHCI_TRNS_AUTO_CMD23), SDHCI_TRANSFER_MODE);
++ return;
++ }
++
++ WARN_ON(!host->data);
++
++ mode = SDHCI_TRNS_BLK_CNT_EN;
++
++ if ((mmc_op_multi(cmd->opcode) || data->blocks > 1)) {
++ mode |= SDHCI_TRNS_MULTI;
++
++ /*
++ * If we are sending CMD23, CMD12 never gets sent
++ * on successful completion (so no Auto-CMD12).
++ */
++ if (!host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD12))
++ mode |= SDHCI_TRNS_AUTO_CMD12;
++ else if (host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) {
++ mode |= SDHCI_TRNS_AUTO_CMD23;
++ bcm2835_mmc_writel(host, host->mrq->sbc->arg, SDHCI_ARGUMENT2, 5);
++ }
++ }
++
++ if (data->flags & MMC_DATA_READ)
++ mode |= SDHCI_TRNS_READ;
++ if (host->flags & SDHCI_REQ_USE_DMA)
++ mode |= SDHCI_TRNS_DMA;
++
++ bcm2835_mmc_writew(host, mode, SDHCI_TRANSFER_MODE);
++}
++
++void bcm2835_mmc_send_command(struct bcm2835_host *host, struct mmc_command *cmd)
++{
++ int flags;
++ u32 mask;
++ unsigned long timeout;
++
++ WARN_ON(host->cmd);
++
++ /* Wait max 10 ms */
++ timeout = 1000;
++
++ mask = SDHCI_CMD_INHIBIT;
++ if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY))
++ mask |= SDHCI_DATA_INHIBIT;
++
++ /* We shouldn't wait for data inihibit for stop commands, even
++ though they might use busy signaling */
++ if (host->mrq->data && (cmd == host->mrq->data->stop))
++ mask &= ~SDHCI_DATA_INHIBIT;
++
++ while (bcm2835_mmc_readl(host, SDHCI_PRESENT_STATE) & mask) {
++ if (timeout == 0) {
++ pr_err("%s: Controller never released inhibit bit(s).\n",
++ mmc_hostname(host->mmc));
++ bcm2835_mmc_dumpregs(host);
++ cmd->error = -EIO;
++ tasklet_schedule(&host->finish_tasklet);
++ return;
++ }
++ timeout--;
++ udelay(10);
++ }
++
++ if ((1000-timeout)/100 > 1 && (1000-timeout)/100 > host->max_delay) {
++ host->max_delay = (1000-timeout)/100;
++ pr_warning("Warning: MMC controller hung for %d ms\n", host->max_delay);
++ }
++
++ timeout = jiffies;
++ if (!cmd->data && cmd->busy_timeout > 9000)
++ timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
++ else
++ timeout += 10 * HZ;
++ mod_timer(&host->timer, timeout);
++
++ host->cmd = cmd;
++
++ bcm2835_mmc_prepare_data(host, cmd);
++
++ bcm2835_mmc_writel(host, cmd->arg, SDHCI_ARGUMENT, 6);
++
++ bcm2835_mmc_set_transfer_mode(host, cmd);
++
++ if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
++ pr_err("%s: Unsupported response type!\n",
++ mmc_hostname(host->mmc));
++ cmd->error = -EINVAL;
++ tasklet_schedule(&host->finish_tasklet);
++ return;
++ }
++
++ if (!(cmd->flags & MMC_RSP_PRESENT))
++ flags = SDHCI_CMD_RESP_NONE;
++ else if (cmd->flags & MMC_RSP_136)
++ flags = SDHCI_CMD_RESP_LONG;
++ else if (cmd->flags & MMC_RSP_BUSY)
++ flags = SDHCI_CMD_RESP_SHORT_BUSY;
++ else
++ flags = SDHCI_CMD_RESP_SHORT;
++
++ if (cmd->flags & MMC_RSP_CRC)
++ flags |= SDHCI_CMD_CRC;
++ if (cmd->flags & MMC_RSP_OPCODE)
++ flags |= SDHCI_CMD_INDEX;
++
++ if (cmd->data)
++ flags |= SDHCI_CMD_DATA;
++
++ bcm2835_mmc_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
++}
++
++
++static void bcm2835_mmc_finish_data(struct bcm2835_host *host)
++{
++ struct mmc_data *data;
++
++ BUG_ON(!host->data);
++
++ data = host->data;
++ host->data = NULL;
++
++ if (data->error)
++ data->bytes_xfered = 0;
++ else
++ data->bytes_xfered = data->blksz * data->blocks;
++
++ /*
++ * Need to send CMD12 if -
++ * a) open-ended multiblock transfer (no CMD23)
++ * b) error in multiblock transfer
++ */
++ if (data->stop &&
++ (data->error ||
++ !host->mrq->sbc)) {
++
++ /*
++ * The controller needs a reset of internal state machines
++ * upon error conditions.
++ */
++ if (data->error) {
++ bcm2835_mmc_reset(host, SDHCI_RESET_CMD);
++ bcm2835_mmc_reset(host, SDHCI_RESET_DATA);
++ }
++
++ bcm2835_mmc_send_command(host, data->stop);
++ } else
++ tasklet_schedule(&host->finish_tasklet);
++}
++
++static void bcm2835_mmc_finish_command(struct bcm2835_host *host)
++{
++ int i;
++
++ BUG_ON(host->cmd == NULL);
++
++ if (host->cmd->flags & MMC_RSP_PRESENT) {
++ if (host->cmd->flags & MMC_RSP_136) {
++ /* CRC is stripped so we need to do some shifting. */
++ for (i = 0; i < 4; i++) {
++ host->cmd->resp[i] = bcm2835_mmc_readl(host,
++ SDHCI_RESPONSE + (3-i)*4) << 8;
++ if (i != 3)
++ host->cmd->resp[i] |=
++ bcm2835_mmc_readb(host,
++ SDHCI_RESPONSE + (3-i)*4-1);
++ }
++ } else {
++ host->cmd->resp[0] = bcm2835_mmc_readl(host, SDHCI_RESPONSE);
++ }
++ }
++
++ host->cmd->error = 0;
++
++ /* Finished CMD23, now send actual command. */
++ if (host->cmd == host->mrq->sbc) {
++ host->cmd = NULL;
++ bcm2835_mmc_send_command(host, host->mrq->cmd);
++
++ if (host->mrq->cmd->data && host->use_dma) {
++ /* DMA transfer starts now, PIO starts after interrupt */
++ bcm2835_mmc_transfer_dma(host);
++ }
++ } else {
++
++ /* Processed actual command. */
++ if (host->data && host->data_early)
++ bcm2835_mmc_finish_data(host);
++
++ if (!host->cmd->data)
++ tasklet_schedule(&host->finish_tasklet);
++
++ host->cmd = NULL;
++ }
++}
++
++
++static void bcm2835_mmc_timeout_timer(unsigned long data)
++{
++ struct bcm2835_host *host;
++ unsigned long flags;
++
++ host = (struct bcm2835_host *)data;
++
++ spin_lock_irqsave(&host->lock, flags);
++
++ if (host->mrq) {
++ pr_err("%s: Timeout waiting for hardware interrupt.\n",
++ mmc_hostname(host->mmc));
++ bcm2835_mmc_dumpregs(host);
++
++ if (host->data) {
++ host->data->error = -ETIMEDOUT;
++ bcm2835_mmc_finish_data(host);
++ } else {
++ if (host->cmd)
++ host->cmd->error = -ETIMEDOUT;
++ else
++ host->mrq->cmd->error = -ETIMEDOUT;
++
++ tasklet_schedule(&host->finish_tasklet);
++ }
++ }
++
++ mmiowb();
++ spin_unlock_irqrestore(&host->lock, flags);
++}
++
++
++static void bcm2835_mmc_enable_sdio_irq_nolock(struct bcm2835_host *host, int enable)
++{
++ if (!(host->flags & SDHCI_DEVICE_DEAD)) {
++ if (enable)
++ host->ier |= SDHCI_INT_CARD_INT;
++ else
++ host->ier &= ~SDHCI_INT_CARD_INT;
++
++ bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 7);
++ bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 7);
++ mmiowb();
++ }
++}
++
++static void bcm2835_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
++{
++ struct bcm2835_host *host = mmc_priv(mmc);
++ unsigned long flags;
++
++ spin_lock_irqsave(&host->lock, flags);
++ if (enable)
++ host->flags |= SDHCI_SDIO_IRQ_ENABLED;
++ else
++ host->flags &= ~SDHCI_SDIO_IRQ_ENABLED;
++
++ bcm2835_mmc_enable_sdio_irq_nolock(host, enable);
++ spin_unlock_irqrestore(&host->lock, flags);
++}
++
++static void bcm2835_mmc_cmd_irq(struct bcm2835_host *host, u32 intmask)
++{
++
++ BUG_ON(intmask == 0);
++
++ if (!host->cmd) {
++ pr_err("%s: Got command interrupt 0x%08x even "
++ "though no command operation was in progress.\n",
++ mmc_hostname(host->mmc), (unsigned)intmask);
++ bcm2835_mmc_dumpregs(host);
++ return;
++ }
++
++ if (intmask & SDHCI_INT_TIMEOUT)
++ host->cmd->error = -ETIMEDOUT;
++ else if (intmask & (SDHCI_INT_CRC | SDHCI_INT_END_BIT |
++ SDHCI_INT_INDEX)) {
++ host->cmd->error = -EILSEQ;
++ }
++
++ if (host->cmd->error) {
++ tasklet_schedule(&host->finish_tasklet);
++ return;
++ }
++
++ if (intmask & SDHCI_INT_RESPONSE)
++ bcm2835_mmc_finish_command(host);
++
++}
++
++static void bcm2835_mmc_data_irq(struct bcm2835_host *host, u32 intmask)
++{
++ struct dma_chan *dma_chan;
++ u32 dir_data;
++
++ BUG_ON(intmask == 0);
++
++ if (!host->data) {
++ /*
++ * The "data complete" interrupt is also used to
++ * indicate that a busy state has ended. See comment
++ * above in sdhci_cmd_irq().
++ */
++ if (host->cmd && (host->cmd->flags & MMC_RSP_BUSY)) {
++ if (intmask & SDHCI_INT_DATA_END) {
++ bcm2835_mmc_finish_command(host);
++ return;
++ }
++ }
++
++ pr_debug("%s: Got data interrupt 0x%08x even "
++ "though no data operation was in progress.\n",
++ mmc_hostname(host->mmc), (unsigned)intmask);
++ bcm2835_mmc_dumpregs(host);
++
++ return;
++ }
++
++ if (intmask & SDHCI_INT_DATA_TIMEOUT)
++ host->data->error = -ETIMEDOUT;
++ else if (intmask & SDHCI_INT_DATA_END_BIT)
++ host->data->error = -EILSEQ;
++ else if ((intmask & SDHCI_INT_DATA_CRC) &&
++ SDHCI_GET_CMD(bcm2835_mmc_readw(host, SDHCI_COMMAND))
++ != MMC_BUS_TEST_R)
++ host->data->error = -EILSEQ;
++
++ if (host->use_dma) {
++ if (host->data->flags & MMC_DATA_WRITE) {
++ /* IRQ handled here */
++
++ dma_chan = host->dma_chan_tx;
++ dir_data = DMA_TO_DEVICE;
++ dma_unmap_sg(dma_chan->device->dev,
++ host->data->sg, host->data->sg_len,
++ dir_data);
++
++ bcm2835_mmc_finish_data(host);
++ }
++
++ } else {
++ if (host->data->error)
++ bcm2835_mmc_finish_data(host);
++ else {
++ if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL))
++ bcm2835_mmc_transfer_pio(host);
++
++ if (intmask & SDHCI_INT_DATA_END) {
++ if (host->cmd) {
++ /*
++ * Data managed to finish before the
++ * command completed. Make sure we do
++ * things in the proper order.
++ */
++ host->data_early = 1;
++ } else {
++ bcm2835_mmc_finish_data(host);
++ }
++ }
++ }
++ }
++}
++
++
++static irqreturn_t bcm2835_mmc_irq(int irq, void *dev_id)
++{
++ irqreturn_t result = IRQ_NONE;
++ struct bcm2835_host *host = dev_id;
++ u32 intmask, mask, unexpected = 0;
++ int max_loops = 16;
++
++ spin_lock(&host->lock);
++
++ intmask = bcm2835_mmc_readl(host, SDHCI_INT_STATUS);
++
++ if (!intmask || intmask == 0xffffffff) {
++ result = IRQ_NONE;
++ goto out;
++ }
++
++ do {
++ /* Clear selected interrupts. */
++ mask = intmask & (SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK |
++ SDHCI_INT_BUS_POWER);
++ bcm2835_mmc_writel(host, mask, SDHCI_INT_STATUS, 8);
++
++
++ if (intmask & SDHCI_INT_CMD_MASK)
++ bcm2835_mmc_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
++
++ if (intmask & SDHCI_INT_DATA_MASK)
++ bcm2835_mmc_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
++
++ if (intmask & SDHCI_INT_BUS_POWER)
++ pr_err("%s: Card is consuming too much power!\n",
++ mmc_hostname(host->mmc));
++
++ if (intmask & SDHCI_INT_CARD_INT) {
++ bcm2835_mmc_enable_sdio_irq_nolock(host, false);
++ host->thread_isr |= SDHCI_INT_CARD_INT;
++ result = IRQ_WAKE_THREAD;
++ }
++
++ intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE |
++ SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK |
++ SDHCI_INT_ERROR | SDHCI_INT_BUS_POWER |
++ SDHCI_INT_CARD_INT);
++
++ if (intmask) {
++ unexpected |= intmask;
++ bcm2835_mmc_writel(host, intmask, SDHCI_INT_STATUS, 9);
++ }
++
++ if (result == IRQ_NONE)
++ result = IRQ_HANDLED;
++
++ intmask = bcm2835_mmc_readl(host, SDHCI_INT_STATUS);
++ } while (intmask && --max_loops);
++out:
++ spin_unlock(&host->lock);
++
++ if (unexpected) {
++ pr_err("%s: Unexpected interrupt 0x%08x.\n",
++ mmc_hostname(host->mmc), unexpected);
++ bcm2835_mmc_dumpregs(host);
++ }
++
++ return result;
++}
++
++static irqreturn_t bcm2835_mmc_thread_irq(int irq, void *dev_id)
++{
++ struct bcm2835_host *host = dev_id;
++ unsigned long flags;
++ u32 isr;
++
++ spin_lock_irqsave(&host->lock, flags);
++ isr = host->thread_isr;
++ host->thread_isr = 0;
++ spin_unlock_irqrestore(&host->lock, flags);
++
++ if (isr & SDHCI_INT_CARD_INT) {
++ sdio_run_irqs(host->mmc);
++
++ spin_lock_irqsave(&host->lock, flags);
++ if (host->flags & SDHCI_SDIO_IRQ_ENABLED)
++ bcm2835_mmc_enable_sdio_irq_nolock(host, true);
++ spin_unlock_irqrestore(&host->lock, flags);
++ }
++
++ return isr ? IRQ_HANDLED : IRQ_NONE;
++}
++
++
++
++void bcm2835_mmc_set_clock(struct bcm2835_host *host, unsigned int clock)
++{
++ int div = 0; /* Initialized for compiler warning */
++ int real_div = div, clk_mul = 1;
++ u16 clk = 0;
++ unsigned long timeout;
++ unsigned int input_clock = clock;
++
++ if (host->overclock_50 && (clock == 50000000))
++ clock = host->overclock_50 * 1000000 + 999999;
++
++ host->mmc->actual_clock = 0;
++
++ bcm2835_mmc_writew(host, 0, SDHCI_CLOCK_CONTROL);
++
++ if (clock == 0)
++ return;
++
++ /* Version 3.00 divisors must be a multiple of 2. */
++ if (host->max_clk <= clock)
++ div = 1;
++ else {
++ for (div = 2; div < SDHCI_MAX_DIV_SPEC_300;
++ div += 2) {
++ if ((host->max_clk / div) <= clock)
++ break;
++ }
++ }
++
++ real_div = div;
++ div >>= 1;
++
++ if (real_div)
++ clock = (host->max_clk * clk_mul) / real_div;
++ host->mmc->actual_clock = clock;
++
++ if ((clock > input_clock) && (clock > host->max_overclock)) {
++ pr_warn("%s: Overclocking to %dHz\n",
++ mmc_hostname(host->mmc), clock);
++ host->max_overclock = clock;
++ }
++
++ clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
++ clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
++ << SDHCI_DIVIDER_HI_SHIFT;
++ clk |= SDHCI_CLOCK_INT_EN;
++ bcm2835_mmc_writew(host, clk, SDHCI_CLOCK_CONTROL);
++
++ /* Wait max 20 ms */
++ timeout = 20;
++ while (!((clk = bcm2835_mmc_readw(host, SDHCI_CLOCK_CONTROL))
++ & SDHCI_CLOCK_INT_STABLE)) {
++ if (timeout == 0) {
++ pr_err("%s: Internal clock never "
++ "stabilised.\n", mmc_hostname(host->mmc));
++ bcm2835_mmc_dumpregs(host);
++ return;
++ }
++ timeout--;
++ mdelay(1);
++ }
++
++ if (20-timeout > 10 && 20-timeout > host->max_delay) {
++ host->max_delay = 20-timeout;
++ pr_warning("Warning: MMC controller hung for %d ms\n", host->max_delay);
++ }
++
++ clk |= SDHCI_CLOCK_CARD_EN;
++ bcm2835_mmc_writew(host, clk, SDHCI_CLOCK_CONTROL);
++}
++
++static void bcm2835_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
++{
++ struct bcm2835_host *host;
++ unsigned long flags;
++
++ host = mmc_priv(mmc);
++
++ spin_lock_irqsave(&host->lock, flags);
++
++ WARN_ON(host->mrq != NULL);
++
++ host->mrq = mrq;
++
++ if (mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23))
++ bcm2835_mmc_send_command(host, mrq->sbc);
++ else
++ bcm2835_mmc_send_command(host, mrq->cmd);
++
++ mmiowb();
++ spin_unlock_irqrestore(&host->lock, flags);
++
++ if (!(mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23)) && mrq->cmd->data && host->use_dma) {
++ /* DMA transfer starts now, PIO starts after interrupt */
++ bcm2835_mmc_transfer_dma(host);
++ }
++}
++
++
++static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
++{
++
++ struct bcm2835_host *host = mmc_priv(mmc);
++ unsigned long flags;
++ u8 ctrl;
++ u16 clk, ctrl_2;
++
++ pr_debug("bcm2835_mmc_set_ios: clock %d, pwr %d, bus_width %d, timing %d, vdd %d, drv_type %d\n",
++ ios->clock, ios->power_mode, ios->bus_width,
++ ios->timing, ios->signal_voltage, ios->drv_type);
++
++ spin_lock_irqsave(&host->lock, flags);
++
++ if (!ios->clock || ios->clock != host->clock) {
++ bcm2835_mmc_set_clock(host, ios->clock);
++ host->clock = ios->clock;
++ }
++
++ if (host->pwr != SDHCI_POWER_330) {
++ host->pwr = SDHCI_POWER_330;
++ bcm2835_mmc_writeb(host, SDHCI_POWER_330 | SDHCI_POWER_ON, SDHCI_POWER_CONTROL);
++ }
++
++ ctrl = bcm2835_mmc_readb(host, SDHCI_HOST_CONTROL);
++
++ /* set bus width */
++ ctrl &= ~SDHCI_CTRL_8BITBUS;
++ if (ios->bus_width == MMC_BUS_WIDTH_4)
++ ctrl |= SDHCI_CTRL_4BITBUS;
++ else
++ ctrl &= ~SDHCI_CTRL_4BITBUS;
++
++ ctrl &= ~SDHCI_CTRL_HISPD; /* NO_HISPD_BIT */
++
++
++ bcm2835_mmc_writeb(host, ctrl, SDHCI_HOST_CONTROL);
++ /*
++ * We only need to set Driver Strength if the
++ * preset value enable is not set.
++ */
++ ctrl_2 = bcm2835_mmc_readw(host, SDHCI_HOST_CONTROL2);
++ ctrl_2 &= ~SDHCI_CTRL_DRV_TYPE_MASK;
++ if (ios->drv_type == MMC_SET_DRIVER_TYPE_A)
++ ctrl_2 |= SDHCI_CTRL_DRV_TYPE_A;
++ else if (ios->drv_type == MMC_SET_DRIVER_TYPE_C)
++ ctrl_2 |= SDHCI_CTRL_DRV_TYPE_C;
++
++ bcm2835_mmc_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
++
++ /* Reset SD Clock Enable */
++ clk = bcm2835_mmc_readw(host, SDHCI_CLOCK_CONTROL);
++ clk &= ~SDHCI_CLOCK_CARD_EN;
++ bcm2835_mmc_writew(host, clk, SDHCI_CLOCK_CONTROL);
++
++ /* Re-enable SD Clock */
++ bcm2835_mmc_set_clock(host, host->clock);
++ bcm2835_mmc_writeb(host, ctrl, SDHCI_HOST_CONTROL);
++
++ mmiowb();
++
++ spin_unlock_irqrestore(&host->lock, flags);
++}
++
++
++static struct mmc_host_ops bcm2835_ops = {
++ .request = bcm2835_mmc_request,
++ .set_ios = bcm2835_mmc_set_ios,
++ .enable_sdio_irq = bcm2835_mmc_enable_sdio_irq,
++};
++
++
++static void bcm2835_mmc_tasklet_finish(unsigned long param)
++{
++ struct bcm2835_host *host;
++ unsigned long flags;
++ struct mmc_request *mrq;
++
++ host = (struct bcm2835_host *)param;
++
++ spin_lock_irqsave(&host->lock, flags);
++
++ /*
++ * If this tasklet gets rescheduled while running, it will
++ * be run again afterwards but without any active request.
++ */
++ if (!host->mrq) {
++ spin_unlock_irqrestore(&host->lock, flags);
++ return;
++ }
++
++ del_timer(&host->timer);
++
++ mrq = host->mrq;
++
++ /*
++ * The controller needs a reset of internal state machines
++ * upon error conditions.
++ */
++ if (!(host->flags & SDHCI_DEVICE_DEAD) &&
++ ((mrq->cmd && mrq->cmd->error) ||
++ (mrq->data && (mrq->data->error ||
++ (mrq->data->stop && mrq->data->stop->error))))) {
++
++ spin_unlock_irqrestore(&host->lock, flags);
++ bcm2835_mmc_reset(host, SDHCI_RESET_CMD);
++ bcm2835_mmc_reset(host, SDHCI_RESET_DATA);
++ spin_lock_irqsave(&host->lock, flags);
++ }
++
++ host->mrq = NULL;
++ host->cmd = NULL;
++ host->data = NULL;
++
++ mmiowb();
++
++ spin_unlock_irqrestore(&host->lock, flags);
++ mmc_request_done(host->mmc, mrq);
++}
++
++
++
++static int bcm2835_mmc_add_host(struct bcm2835_host *host)
++{
++ struct mmc_host *mmc = host->mmc;
++ struct device *dev = mmc->parent;
++#ifndef FORCE_PIO
++ struct dma_slave_config cfg;
++#endif
++ int ret;
++
++ bcm2835_mmc_reset(host, SDHCI_RESET_ALL);
++
++ host->clk_mul = 0;
++
++ mmc->f_max = host->max_clk;
++ mmc->f_max = host->max_clk;
++ mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300;
++
++ /* SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK */
++ host->timeout_clk = mmc->f_max / 1000;
++ mmc->max_busy_timeout = (1 << 27) / host->timeout_clk;
++
++ /* host controller capabilities */
++ mmc->caps |= MMC_CAP_CMD23 | MMC_CAP_ERASE | MMC_CAP_NEEDS_POLL |
++ MMC_CAP_SDIO_IRQ | MMC_CAP_SD_HIGHSPEED |
++ MMC_CAP_MMC_HIGHSPEED | MMC_CAP_4_BIT_DATA;
++
++ mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
++
++ host->flags = SDHCI_AUTO_CMD23;
++
++ dev_info(dev, "mmc_debug:%x mmc_debug2:%x\n", mmc_debug, mmc_debug2);
++#ifdef FORCE_PIO
++ dev_info(dev, "Forcing PIO mode\n");
++ host->have_dma = false;
++#else
++ if (IS_ERR_OR_NULL(host->dma_chan_tx) ||
++ IS_ERR_OR_NULL(host->dma_chan_rx)) {
++ dev_err(dev, "%s: Unable to initialise DMA channels. Falling back to PIO\n",
++ DRIVER_NAME);
++ host->have_dma = false;
++ } else {
++ dev_info(dev, "DMA channels allocated");
++ host->have_dma = true;
++
++ cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++ cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++ cfg.slave_id = 11; /* DREQ channel */
++
++ cfg.direction = DMA_MEM_TO_DEV;
++ cfg.src_addr = 0;
++ cfg.dst_addr = host->bus_addr + SDHCI_BUFFER;
++ ret = dmaengine_slave_config(host->dma_chan_tx, &cfg);
++
++ cfg.direction = DMA_DEV_TO_MEM;
++ cfg.src_addr = host->bus_addr + SDHCI_BUFFER;
++ cfg.dst_addr = 0;
++ ret = dmaengine_slave_config(host->dma_chan_rx, &cfg);
++ }
++#endif
++ mmc->max_segs = 128;
++ mmc->max_req_size = 524288;
++ mmc->max_seg_size = mmc->max_req_size;
++ mmc->max_blk_size = 512;
++ mmc->max_blk_count = 65535;
++
++ /* report supported voltage ranges */
++ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
++
++ tasklet_init(&host->finish_tasklet,
++ bcm2835_mmc_tasklet_finish, (unsigned long)host);
++
++ setup_timer(&host->timer, bcm2835_mmc_timeout_timer, (unsigned long)host);
++ init_waitqueue_head(&host->buf_ready_int);
++
++ bcm2835_mmc_init(host, 0);
++ ret = devm_request_threaded_irq(dev, host->irq, bcm2835_mmc_irq,
++ bcm2835_mmc_thread_irq, IRQF_SHARED,
++ mmc_hostname(mmc), host);
++ if (ret) {
++ dev_err(dev, "Failed to request IRQ %d: %d\n", host->irq, ret);
++ goto untasklet;
++ }
++
++ mmiowb();
++ mmc_add_host(mmc);
++
++ return 0;
++
++untasklet:
++ tasklet_kill(&host->finish_tasklet);
++
++ return ret;
++}
++
++static int bcm2835_mmc_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct device_node *node = dev->of_node;
++ struct clk *clk;
++ struct resource *iomem;
++ struct bcm2835_host *host;
++ struct mmc_host *mmc;
++ const __be32 *addr;
++ int ret;
++
++ mmc = mmc_alloc_host(sizeof(*host), dev);
++ if (!mmc)
++ return -ENOMEM;
++
++ mmc->ops = &bcm2835_ops;
++ host = mmc_priv(mmc);
++ host->mmc = mmc;
++ host->timeout = msecs_to_jiffies(1000);
++ spin_lock_init(&host->lock);
++
++ iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ host->ioaddr = devm_ioremap_resource(dev, iomem);
++ if (IS_ERR(host->ioaddr)) {
++ ret = PTR_ERR(host->ioaddr);
++ goto err;
++ }
++
++ addr = of_get_address(node, 0, NULL, NULL);
++ if (!addr) {
++ dev_err(dev, "could not get DMA-register address\n");
++ return -ENODEV;
++ }
++ host->bus_addr = be32_to_cpup(addr);
++ pr_debug(" - ioaddr %lx, iomem->start %lx, bus_addr %lx\n",
++ (unsigned long)host->ioaddr,
++ (unsigned long)iomem->start,
++ (unsigned long)host->bus_addr);
++
++#ifndef FORCE_PIO
++ if (node) {
++ host->dma_chan_tx = dma_request_slave_channel(dev, "tx");
++ host->dma_chan_rx = dma_request_slave_channel(dev, "rx");
++ } else {
++ dma_cap_mask_t mask;
++
++ dma_cap_zero(mask);
++ /* we don't care about the channel, any would work */
++ dma_cap_set(DMA_SLAVE, mask);
++ host->dma_chan_tx = dma_request_channel(mask, NULL, NULL);
++ host->dma_chan_rx = dma_request_channel(mask, NULL, NULL);
++ }
++#endif
++ clk = devm_clk_get(dev, NULL);
++ if (IS_ERR(clk)) {
++ dev_err(dev, "could not get clk\n");
++ ret = PTR_ERR(clk);
++ goto err;
++ }
++
++ host->max_clk = clk_get_rate(clk);
++
++ host->irq = platform_get_irq(pdev, 0);
++ if (host->irq <= 0) {
++ dev_err(dev, "get IRQ failed\n");
++ ret = -EINVAL;
++ goto err;
++ }
++
++ if (node) {
++ mmc_of_parse(mmc);
++
++ /* Read any custom properties */
++ of_property_read_u32(node,
++ "brcm,overclock-50",
++ &host->overclock_50);
++ } else {
++ mmc->caps |= MMC_CAP_4_BIT_DATA;
++ }
++
++ ret = bcm2835_mmc_add_host(host);
++ if (ret)
++ goto err;
++
++ platform_set_drvdata(pdev, host);
++
++ return 0;
++err:
++ mmc_free_host(mmc);
++
++ return ret;
++}
++
++static int bcm2835_mmc_remove(struct platform_device *pdev)
++{
++ struct bcm2835_host *host = platform_get_drvdata(pdev);
++ unsigned long flags;
++ int dead;
++ u32 scratch;
++
++ dead = 0;
++ scratch = bcm2835_mmc_readl(host, SDHCI_INT_STATUS);
++ if (scratch == (u32)-1)
++ dead = 1;
++
++
++ if (dead) {
++ spin_lock_irqsave(&host->lock, flags);
++
++ host->flags |= SDHCI_DEVICE_DEAD;
++
++ if (host->mrq) {
++ pr_err("%s: Controller removed during "
++ " transfer!\n", mmc_hostname(host->mmc));
++
++ host->mrq->cmd->error = -ENOMEDIUM;
++ tasklet_schedule(&host->finish_tasklet);
++ }
++
++ spin_unlock_irqrestore(&host->lock, flags);
++ }
++
++ mmc_remove_host(host->mmc);
++
++ if (!dead)
++ bcm2835_mmc_reset(host, SDHCI_RESET_ALL);
++
++ free_irq(host->irq, host);
++
++ del_timer_sync(&host->timer);
++
++ tasklet_kill(&host->finish_tasklet);
++
++ mmc_free_host(host->mmc);
++ platform_set_drvdata(pdev, NULL);
++
++ return 0;
++}
++
++
++static const struct of_device_id bcm2835_mmc_match[] = {
++ { .compatible = "brcm,bcm2835-mmc" },
++ { }
++};
++MODULE_DEVICE_TABLE(of, bcm2835_mmc_match);
++
++
++
++static struct platform_driver bcm2835_mmc_driver = {
++ .probe = bcm2835_mmc_probe,
++ .remove = bcm2835_mmc_remove,
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ .of_match_table = bcm2835_mmc_match,
++ },
++};
++module_platform_driver(bcm2835_mmc_driver);
++
++module_param(mmc_debug, uint, 0644);
++module_param(mmc_debug2, uint, 0644);
++MODULE_ALIAS("platform:mmc-bcm2835");
++MODULE_DESCRIPTION("BCM2835 SDHCI driver");
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Gellert Weisz");
diff --git a/target/linux/brcm2708/patches-4.4/0033-Adding-bcm2835-sdhost-driver-and-an-overlay-to-enabl.patch b/target/linux/brcm2708/patches-4.4/0033-Adding-bcm2835-sdhost-driver-and-an-overlay-to-enabl.patch
new file mode 100644
index 0000000000..d49e57b2c1
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0033-Adding-bcm2835-sdhost-driver-and-an-overlay-to-enabl.patch
@@ -0,0 +1,2022 @@
+From 8c767f6b8d65c2c59995ed51512faeaf56fbb2c3 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Wed, 25 Mar 2015 17:49:47 +0000
+Subject: [PATCH 033/381] Adding bcm2835-sdhost driver, and an overlay to
+ enable it
+
+BCM2835 has two SD card interfaces. This driver uses the other one.
+
+bcm2835-sdhost: Error handling fix, and code clarification
+
+bcm2835-sdhost: Adding overclocking option
+
+Allow a different clock speed to be substitued for a requested 50MHz.
+This option is exposed using the "overclock_50" DT parameter.
+Note that the sdhost interface is restricted to integer divisions of
+core_freq, and the highest sensible option for a core_freq of 250MHz
+is 84 (250/3 = 83.3MHz), the next being 125 (250/2) which is much too
+high.
+
+Use at your own risk.
+
+bcm2835-sdhost: Round up the overclock, so 62 works for 62.5Mhz
+
+Also only warn once for each overclock setting.
+
+bcm2835-sdhost: Improve error handling and recovery
+
+1) Expose the hw_reset method to the MMC framework, removing many
+ internal calls by the driver.
+
+2) Reduce overclock setting on error.
+
+3) Increase timeout to cope with high capacity cards.
+
+4) Add properties and parameters to control pio_limit and debug.
+
+5) Reduce messages at probe time.
+
+bcm2835-sdhost: Further improve overclock back-off
+
+bcm2835-sdhost: Clear HBLC for PIO mode
+
+Also update pio_limit default in overlay README.
+
+bcm2835-sdhost: Add the ERASE capability
+
+See: https://github.com/raspberrypi/linux/issues/1076
+
+bcm2835-sdhost: Ignore CRC7 for MMC CMD1
+
+It seems that the sdhost interface returns CRC7 errors for CMD1,
+which is the MMC-specific SEND_OP_COND. Returning these errors to
+the MMC layer causes a downward spiral, but ignoring them seems
+to be harmless.
+
+bcm2835-mmc/sdhost: Remove ARCH_BCM2835 differences
+
+The bcm2835-mmc driver (and -sdhost driver that copied from it)
+contains code to handle SDIO interrupts in a threaded interrupt
+handler rather than waking the MMC framework thread. The change
+follows a patch from Russell King that adds the facility as the
+preferred way of working.
+
+However, the new code path is only present in ARCH_BCM2835
+builds, which I have taken to be a way of testing the waters
+rather than making the change across the board; I can't see
+any technical reason why it wouldn't be enabled for MACH_BCM270X
+builds. So this patch standardises on the ARCH_BCM2835 code,
+removing the old code paths.
+
+bcm2835-sdhost: Don't log timeout errors unless debug=1
+
+The MMC card-discovery process generates timeouts. This is
+expected behaviour, so reporting it to the user serves no purpose.
+Suppress the reporting of timeout errors unless the debug flag
+is on.
+---
+ drivers/mmc/host/Kconfig | 10 +
+ drivers/mmc/host/Makefile | 1 +
+ drivers/mmc/host/bcm2835-sdhost.c | 1907 +++++++++++++++++++++++++++++++++++++
+ 3 files changed, 1918 insertions(+)
+ create mode 100644 drivers/mmc/host/bcm2835-sdhost.c
+
+--- a/drivers/mmc/host/Kconfig
++++ b/drivers/mmc/host/Kconfig
+@@ -33,6 +33,16 @@ config MMC_BCM2835_PIO_DMA_BARRIER
+
+ If unsure, say 2 here.
+
++config MMC_BCM2835_SDHOST
++ tristate "Support for the SDHost controller on BCM2708/9"
++ depends on MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835
++ help
++ This selects the SDHost controller on BCM2835/6.
++
++ If you have a controller with this interface, say Y or M here.
++
++ If unsure, say N.
++
+ config MMC_ARMMMCI
+ tristate "ARM AMBA Multimedia Card Interface support"
+ depends on ARM_AMBA
+--- a/drivers/mmc/host/Makefile
++++ b/drivers/mmc/host/Makefile
+@@ -18,6 +18,7 @@ obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c
+ obj-$(CONFIG_MMC_SDHCI_SIRF) += sdhci-sirf.o
+ obj-$(CONFIG_MMC_SDHCI_F_SDH30) += sdhci_f_sdh30.o
+ obj-$(CONFIG_MMC_SDHCI_SPEAR) += sdhci-spear.o
++obj-$(CONFIG_MMC_BCM2835_SDHOST) += bcm2835-sdhost.o
+ obj-$(CONFIG_MMC_BCM2835) += bcm2835-mmc.o
+ obj-$(CONFIG_MMC_WBSD) += wbsd.o
+ obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
+--- /dev/null
++++ b/drivers/mmc/host/bcm2835-sdhost.c
+@@ -0,0 +1,1907 @@
++/*
++ * BCM2835 SD host driver.
++ *
++ * Author: Phil Elwell <phil@raspberrypi.org>
++ * Copyright 2015
++ *
++ * Based on
++ * mmc-bcm2835.c by Gellert Weisz
++ * which is, in turn, based on
++ * sdhci-bcm2708.c by Broadcom
++ * sdhci-bcm2835.c by Stephen Warren and Oleksandr Tymoshenko
++ * sdhci.c and sdhci-pci.c by Pierre Ossman
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#define SAFE_READ_THRESHOLD 4
++#define SAFE_WRITE_THRESHOLD 4
++#define ALLOW_DMA 1
++#define ALLOW_CMD23 0
++#define ALLOW_FAST 1
++#define USE_BLOCK_IRQ 1
++
++#include <linux/delay.h>
++#include <linux/module.h>
++#include <linux/io.h>
++#include <linux/mmc/mmc.h>
++#include <linux/mmc/host.h>
++#include <linux/mmc/sd.h>
++#include <linux/scatterlist.h>
++#include <linux/of_address.h>
++#include <linux/of_irq.h>
++#include <linux/clk.h>
++#include <linux/platform_device.h>
++#include <linux/err.h>
++#include <linux/blkdev.h>
++#include <linux/dmaengine.h>
++#include <linux/dma-mapping.h>
++#include <linux/of_dma.h>
++#include <linux/time.h>
++
++#define DRIVER_NAME "sdhost-bcm2835"
++
++#define SDCMD 0x00 /* Command to SD card - 16 R/W */
++#define SDARG 0x04 /* Argument to SD card - 32 R/W */
++#define SDTOUT 0x08 /* Start value for timeout counter - 32 R/W */
++#define SDCDIV 0x0c /* Start value for clock divider - 11 R/W */
++#define SDRSP0 0x10 /* SD card response (31:0) - 32 R */
++#define SDRSP1 0x14 /* SD card response (63:32) - 32 R */
++#define SDRSP2 0x18 /* SD card response (95:64) - 32 R */
++#define SDRSP3 0x1c /* SD card response (127:96) - 32 R */
++#define SDHSTS 0x20 /* SD host status - 11 R */
++#define SDVDD 0x30 /* SD card power control - 1 R/W */
++#define SDEDM 0x34 /* Emergency Debug Mode - 13 R/W */
++#define SDHCFG 0x38 /* Host configuration - 2 R/W */
++#define SDHBCT 0x3c /* Host byte count (debug) - 32 R/W */
++#define SDDATA 0x40 /* Data to/from SD card - 32 R/W */
++#define SDHBLC 0x50 /* Host block count (SDIO/SDHC) - 9 R/W */
++
++#define SDCMD_NEW_FLAG 0x8000
++#define SDCMD_FAIL_FLAG 0x4000
++#define SDCMD_BUSYWAIT 0x800
++#define SDCMD_NO_RESPONSE 0x400
++#define SDCMD_LONG_RESPONSE 0x200
++#define SDCMD_WRITE_CMD 0x80
++#define SDCMD_READ_CMD 0x40
++#define SDCMD_CMD_MASK 0x3f
++
++#define SDCDIV_MAX_CDIV 0x7ff
++
++#define SDHSTS_BUSY_IRPT 0x400
++#define SDHSTS_BLOCK_IRPT 0x200
++#define SDHSTS_SDIO_IRPT 0x100
++#define SDHSTS_REW_TIME_OUT 0x80
++#define SDHSTS_CMD_TIME_OUT 0x40
++#define SDHSTS_CRC16_ERROR 0x20
++#define SDHSTS_CRC7_ERROR 0x10
++#define SDHSTS_FIFO_ERROR 0x08
++/* Reserved */
++/* Reserved */
++#define SDHSTS_DATA_FLAG 0x01
++
++#define SDHSTS_TRANSFER_ERROR_MASK (SDHSTS_CRC7_ERROR|SDHSTS_CRC16_ERROR|SDHSTS_REW_TIME_OUT|SDHSTS_FIFO_ERROR)
++#define SDHSTS_ERROR_MASK (SDHSTS_CMD_TIME_OUT|SDHSTS_TRANSFER_ERROR_MASK)
++
++#define SDHCFG_BUSY_IRPT_EN (1<<10)
++#define SDHCFG_BLOCK_IRPT_EN (1<<8)
++#define SDHCFG_SDIO_IRPT_EN (1<<5)
++#define SDHCFG_DATA_IRPT_EN (1<<4)
++#define SDHCFG_SLOW_CARD (1<<3)
++#define SDHCFG_WIDE_EXT_BUS (1<<2)
++#define SDHCFG_WIDE_INT_BUS (1<<1)
++#define SDHCFG_REL_CMD_LINE (1<<0)
++
++#define SDEDM_FORCE_DATA_MODE (1<<19)
++#define SDEDM_CLOCK_PULSE (1<<20)
++#define SDEDM_BYPASS (1<<21)
++
++#define SDEDM_WRITE_THRESHOLD_SHIFT 9
++#define SDEDM_READ_THRESHOLD_SHIFT 14
++#define SDEDM_THRESHOLD_MASK 0x1f
++
++#define MHZ 1000000
++
++
++struct bcm2835_host {
++ spinlock_t lock;
++
++ void __iomem *ioaddr;
++ u32 bus_addr;
++
++ struct mmc_host *mmc;
++
++ u32 pio_timeout; /* In jiffies */
++
++ int clock; /* Current clock speed */
++
++ bool slow_card; /* Force 11-bit divisor */
++
++ unsigned int max_clk; /* Max possible freq */
++
++ struct tasklet_struct finish_tasklet; /* Tasklet structures */
++
++ struct timer_list timer; /* Timer for timeouts */
++
++ struct timer_list pio_timer; /* PIO error detection timer */
++
++ struct sg_mapping_iter sg_miter; /* SG state for PIO */
++ unsigned int blocks; /* remaining PIO blocks */
++
++ int irq; /* Device IRQ */
++
++
++ /* cached registers */
++ u32 hcfg;
++ u32 cdiv;
++
++ struct mmc_request *mrq; /* Current request */
++ struct mmc_command *cmd; /* Current command */
++ struct mmc_data *data; /* Current data request */
++ unsigned int data_complete:1; /* Data finished before cmd */
++
++ unsigned int flush_fifo:1; /* Drain the fifo when finishing */
++
++ unsigned int use_busy:1; /* Wait for busy interrupt */
++
++ unsigned int debug:1; /* Enable debug output */
++
++ u32 thread_isr;
++
++ /*DMA part*/
++ struct dma_chan *dma_chan_rx; /* DMA channel for reads */
++ struct dma_chan *dma_chan_tx; /* DMA channel for writes */
++
++ bool allow_dma;
++ bool have_dma;
++ bool use_dma;
++ /*end of DMA part*/
++
++ int max_delay; /* maximum length of time spent waiting */
++ struct timeval stop_time; /* when the last stop was issued */
++ u32 delay_after_stop; /* minimum time between stop and subsequent data transfer */
++ u32 overclock_50; /* frequency to use when 50MHz is requested (in MHz) */
++ u32 overclock; /* Current frequency if overclocked, else zero */
++ u32 pio_limit; /* Maximum block count for PIO (0 = always DMA) */
++};
++
++
++static inline void bcm2835_sdhost_write(struct bcm2835_host *host, u32 val, int reg)
++{
++ writel(val, host->ioaddr + reg);
++}
++
++static inline u32 bcm2835_sdhost_read(struct bcm2835_host *host, int reg)
++{
++ return readl(host->ioaddr + reg);
++}
++
++static inline u32 bcm2835_sdhost_read_relaxed(struct bcm2835_host *host, int reg)
++{
++ return readl_relaxed(host->ioaddr + reg);
++}
++
++static void bcm2835_sdhost_dumpcmd(struct bcm2835_host *host,
++ struct mmc_command *cmd,
++ const char *label)
++{
++ if (cmd)
++ pr_info("%s:%c%s op %d arg 0x%x flags 0x%x - resp %08x %08x %08x %08x, err %d\n",
++ mmc_hostname(host->mmc),
++ (cmd == host->cmd) ? '>' : ' ',
++ label, cmd->opcode, cmd->arg, cmd->flags,
++ cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3],
++ cmd->error);
++}
++
++static void bcm2835_sdhost_dumpregs(struct bcm2835_host *host)
++{
++ bcm2835_sdhost_dumpcmd(host, host->mrq->sbc, "sbc");
++ bcm2835_sdhost_dumpcmd(host, host->mrq->cmd, "cmd");
++ if (host->mrq->data)
++ pr_err("%s: data blocks %x blksz %x - err %d\n",
++ mmc_hostname(host->mmc),
++ host->mrq->data->blocks,
++ host->mrq->data->blksz,
++ host->mrq->data->error);
++ bcm2835_sdhost_dumpcmd(host, host->mrq->stop, "stop");
++
++ pr_info("%s: =========== REGISTER DUMP ===========\n",
++ mmc_hostname(host->mmc));
++
++ pr_info("%s: SDCMD 0x%08x\n",
++ mmc_hostname(host->mmc),
++ bcm2835_sdhost_read(host, SDCMD));
++ pr_info("%s: SDARG 0x%08x\n",
++ mmc_hostname(host->mmc),
++ bcm2835_sdhost_read(host, SDARG));
++ pr_info("%s: SDTOUT 0x%08x\n",
++ mmc_hostname(host->mmc),
++ bcm2835_sdhost_read(host, SDTOUT));
++ pr_info("%s: SDCDIV 0x%08x\n",
++ mmc_hostname(host->mmc),
++ bcm2835_sdhost_read(host, SDCDIV));
++ pr_info("%s: SDRSP0 0x%08x\n",
++ mmc_hostname(host->mmc),
++ bcm2835_sdhost_read(host, SDRSP0));
++ pr_info("%s: SDRSP1 0x%08x\n",
++ mmc_hostname(host->mmc),
++ bcm2835_sdhost_read(host, SDRSP1));
++ pr_info("%s: SDRSP2 0x%08x\n",
++ mmc_hostname(host->mmc),
++ bcm2835_sdhost_read(host, SDRSP2));
++ pr_info("%s: SDRSP3 0x%08x\n",
++ mmc_hostname(host->mmc),
++ bcm2835_sdhost_read(host, SDRSP3));
++ pr_info("%s: SDHSTS 0x%08x\n",
++ mmc_hostname(host->mmc),
++ bcm2835_sdhost_read(host, SDHSTS));
++ pr_info("%s: SDVDD 0x%08x\n",
++ mmc_hostname(host->mmc),
++ bcm2835_sdhost_read(host, SDVDD));
++ pr_info("%s: SDEDM 0x%08x\n",
++ mmc_hostname(host->mmc),
++ bcm2835_sdhost_read(host, SDEDM));
++ pr_info("%s: SDHCFG 0x%08x\n",
++ mmc_hostname(host->mmc),
++ bcm2835_sdhost_read(host, SDHCFG));
++ pr_info("%s: SDHBCT 0x%08x\n",
++ mmc_hostname(host->mmc),
++ bcm2835_sdhost_read(host, SDHBCT));
++ pr_info("%s: SDHBLC 0x%08x\n",
++ mmc_hostname(host->mmc),
++ bcm2835_sdhost_read(host, SDHBLC));
++
++ pr_info("%s: ===========================================\n",
++ mmc_hostname(host->mmc));
++}
++
++
++static void bcm2835_sdhost_set_power(struct bcm2835_host *host, bool on)
++{
++ bcm2835_sdhost_write(host, on ? 1 : 0, SDVDD);
++}
++
++
++static void bcm2835_sdhost_reset_internal(struct bcm2835_host *host)
++{
++ u32 temp;
++
++ bcm2835_sdhost_set_power(host, false);
++
++ bcm2835_sdhost_write(host, 0, SDCMD);
++ bcm2835_sdhost_write(host, 0, SDARG);
++ bcm2835_sdhost_write(host, 0xf00000, SDTOUT);
++ bcm2835_sdhost_write(host, 0, SDCDIV);
++ bcm2835_sdhost_write(host, 0x7f8, SDHSTS); /* Write 1s to clear */
++ bcm2835_sdhost_write(host, 0, SDHCFG);
++ bcm2835_sdhost_write(host, 0, SDHBCT);
++ bcm2835_sdhost_write(host, 0, SDHBLC);
++
++ /* Limit fifo usage due to silicon bug */
++ temp = bcm2835_sdhost_read(host, SDEDM);
++ temp &= ~((SDEDM_THRESHOLD_MASK<<SDEDM_READ_THRESHOLD_SHIFT) |
++ (SDEDM_THRESHOLD_MASK<<SDEDM_WRITE_THRESHOLD_SHIFT));
++ temp |= (SAFE_READ_THRESHOLD << SDEDM_READ_THRESHOLD_SHIFT) |
++ (SAFE_WRITE_THRESHOLD << SDEDM_WRITE_THRESHOLD_SHIFT);
++ bcm2835_sdhost_write(host, temp, SDEDM);
++ mdelay(10);
++ bcm2835_sdhost_set_power(host, true);
++ mdelay(10);
++ host->clock = 0;
++ bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
++ bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
++ mmiowb();
++}
++
++
++static void bcm2835_sdhost_reset(struct mmc_host *mmc)
++{
++ struct bcm2835_host *host = mmc_priv(mmc);
++ unsigned long flags;
++ if (host->debug)
++ pr_info("%s: reset\n", mmc_hostname(mmc));
++ spin_lock_irqsave(&host->lock, flags);
++
++ bcm2835_sdhost_reset_internal(host);
++
++ spin_unlock_irqrestore(&host->lock, flags);
++}
++
++static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
++
++static void bcm2835_sdhost_init(struct bcm2835_host *host, int soft)
++{
++ pr_debug("bcm2835_sdhost_init(%d)\n", soft);
++
++ /* Set interrupt enables */
++ host->hcfg = SDHCFG_BUSY_IRPT_EN;
++
++ bcm2835_sdhost_reset_internal(host);
++
++ if (soft) {
++ /* force clock reconfiguration */
++ host->clock = 0;
++ bcm2835_sdhost_set_ios(host->mmc, &host->mmc->ios);
++ }
++}
++
++static bool bcm2835_sdhost_is_write_complete(struct bcm2835_host *host)
++{
++ bool write_complete = ((bcm2835_sdhost_read(host, SDEDM) & 0xf) == 1);
++
++ if (!write_complete) {
++ /* Request an IRQ for the last block */
++ host->hcfg |= SDHCFG_BLOCK_IRPT_EN;
++ bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
++ if ((bcm2835_sdhost_read(host, SDEDM) & 0xf) == 1) {
++ /* The write has now completed. Disable the interrupt
++ and clear the status flag */
++ host->hcfg &= ~SDHCFG_BLOCK_IRPT_EN;
++ bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
++ bcm2835_sdhost_write(host, SDHSTS_BLOCK_IRPT, SDHSTS);
++ write_complete = true;
++ }
++ }
++
++ return write_complete;
++}
++
++static void bcm2835_sdhost_wait_write_complete(struct bcm2835_host *host)
++{
++ int timediff;
++#ifdef DEBUG
++ static struct timeval start_time;
++ static int max_stall_time = 0;
++ static int total_stall_time = 0;
++ struct timeval before, after;
++
++ do_gettimeofday(&before);
++ if (max_stall_time == 0)
++ start_time = before;
++#endif
++
++ timediff = 0;
++
++ while (1) {
++ u32 edm = bcm2835_sdhost_read(host, SDEDM);
++ if ((edm & 0xf) == 1)
++ break;
++ timediff++;
++ if (timediff > 5000000) {
++#ifdef DEBUG
++ do_gettimeofday(&after);
++ timediff = (after.tv_sec - before.tv_sec)*1000000 +
++ (after.tv_usec - before.tv_usec);
++
++ pr_err(" wait_write_complete - still waiting after %dus\n",
++ timediff);
++#else
++ pr_err(" wait_write_complete - still waiting after %d retries\n",
++ timediff);
++#endif
++ bcm2835_sdhost_dumpregs(host);
++ host->data->error = -ETIMEDOUT;
++ return;
++ }
++ }
++
++#ifdef DEBUG
++ do_gettimeofday(&after);
++ timediff = (after.tv_sec - before.tv_sec)*1000000 + (after.tv_usec - before.tv_usec);
++
++ total_stall_time += timediff;
++ if (timediff > max_stall_time)
++ max_stall_time = timediff;
++
++ if ((after.tv_sec - start_time.tv_sec) > 10) {
++ pr_debug(" wait_write_complete - max wait %dus, total %dus\n",
++ max_stall_time, total_stall_time);
++ start_time = after;
++ max_stall_time = 0;
++ total_stall_time = 0;
++ }
++#endif
++}
++
++static void bcm2835_sdhost_finish_data(struct bcm2835_host *host);
++
++static void bcm2835_sdhost_dma_complete(void *param)
++{
++ struct bcm2835_host *host = param;
++ struct dma_chan *dma_chan;
++ unsigned long flags;
++ u32 dir_data;
++
++ spin_lock_irqsave(&host->lock, flags);
++
++ if (host->data) {
++ bool write_complete;
++ if (USE_BLOCK_IRQ)
++ write_complete = bcm2835_sdhost_is_write_complete(host);
++ else {
++ bcm2835_sdhost_wait_write_complete(host);
++ write_complete = true;
++ }
++ pr_debug("dma_complete() - write_complete=%d\n",
++ write_complete);
++
++ if (write_complete || (host->data->flags & MMC_DATA_READ))
++ {
++ if (write_complete) {
++ dma_chan = host->dma_chan_tx;
++ dir_data = DMA_TO_DEVICE;
++ } else {
++ dma_chan = host->dma_chan_rx;
++ dir_data = DMA_FROM_DEVICE;
++ }
++
++ dma_unmap_sg(dma_chan->device->dev,
++ host->data->sg, host->data->sg_len,
++ dir_data);
++
++ bcm2835_sdhost_finish_data(host);
++ }
++ }
++
++ spin_unlock_irqrestore(&host->lock, flags);
++}
++
++static bool data_transfer_wait(struct bcm2835_host *host)
++{
++ unsigned long timeout = 1000000;
++ while (timeout)
++ {
++ u32 sdhsts = bcm2835_sdhost_read(host, SDHSTS);
++ if (sdhsts & SDHSTS_DATA_FLAG) {
++ bcm2835_sdhost_write(host, SDHSTS_DATA_FLAG, SDHSTS);
++ break;
++ }
++ timeout--;
++ }
++ if (timeout == 0) {
++ pr_err("%s: Data %s timeout\n",
++ mmc_hostname(host->mmc),
++ (host->data->flags & MMC_DATA_READ) ? "read" : "write");
++ bcm2835_sdhost_dumpregs(host);
++ host->data->error = -ETIMEDOUT;
++ return false;
++ }
++ return true;
++}
++
++static void bcm2835_sdhost_read_block_pio(struct bcm2835_host *host)
++{
++ unsigned long flags;
++ size_t blksize, len;
++ u32 *buf;
++
++ blksize = host->data->blksz;
++
++ local_irq_save(flags);
++
++ while (blksize) {
++ if (!sg_miter_next(&host->sg_miter))
++ BUG();
++
++ len = min(host->sg_miter.length, blksize);
++ BUG_ON(len % 4);
++
++ blksize -= len;
++ host->sg_miter.consumed = len;
++
++ buf = (u32 *)host->sg_miter.addr;
++
++ while (len) {
++ if (!data_transfer_wait(host))
++ break;
++
++ *(buf++) = bcm2835_sdhost_read(host, SDDATA);
++ len -= 4;
++ }
++
++ if (host->data->error)
++ break;
++ }
++
++ sg_miter_stop(&host->sg_miter);
++
++ local_irq_restore(flags);
++}
++
++static void bcm2835_sdhost_write_block_pio(struct bcm2835_host *host)
++{
++ unsigned long flags;
++ size_t blksize, len;
++ u32 *buf;
++
++ blksize = host->data->blksz;
++
++ local_irq_save(flags);
++
++ while (blksize) {
++ if (!sg_miter_next(&host->sg_miter))
++ BUG();
++
++ len = min(host->sg_miter.length, blksize);
++ BUG_ON(len % 4);
++
++ blksize -= len;
++ host->sg_miter.consumed = len;
++
++ buf = host->sg_miter.addr;
++
++ while (len) {
++ if (!data_transfer_wait(host))
++ break;
++
++ bcm2835_sdhost_write(host, *(buf++), SDDATA);
++ len -= 4;
++ }
++
++ if (host->data->error)
++ break;
++ }
++
++ sg_miter_stop(&host->sg_miter);
++
++ local_irq_restore(flags);
++}
++
++
++static void bcm2835_sdhost_transfer_pio(struct bcm2835_host *host)
++{
++ u32 sdhsts;
++ bool is_read;
++ BUG_ON(!host->data);
++
++ is_read = (host->data->flags & MMC_DATA_READ) != 0;
++ if (is_read)
++ bcm2835_sdhost_read_block_pio(host);
++ else
++ bcm2835_sdhost_write_block_pio(host);
++
++ sdhsts = bcm2835_sdhost_read(host, SDHSTS);
++ if (sdhsts & (SDHSTS_CRC16_ERROR |
++ SDHSTS_CRC7_ERROR |
++ SDHSTS_FIFO_ERROR)) {
++ pr_err("%s: %s transfer error - HSTS %x\n",
++ mmc_hostname(host->mmc),
++ is_read ? "read" : "write",
++ sdhsts);
++ host->data->error = -EILSEQ;
++ } else if ((sdhsts & (SDHSTS_CMD_TIME_OUT |
++ SDHSTS_REW_TIME_OUT))) {
++ pr_err("%s: %s timeout error - HSTS %x\n",
++ mmc_hostname(host->mmc),
++ is_read ? "read" : "write",
++ sdhsts);
++ host->data->error = -ETIMEDOUT;
++ } else if (!is_read && !host->data->error) {
++ /* Start a timer in case a transfer error occurs because
++ there is no error interrupt */
++ mod_timer(&host->pio_timer, jiffies + host->pio_timeout);
++ }
++}
++
++
++static void bcm2835_sdhost_transfer_dma(struct bcm2835_host *host)
++{
++ u32 len, dir_data, dir_slave;
++ struct dma_async_tx_descriptor *desc = NULL;
++ struct dma_chan *dma_chan;
++
++ pr_debug("bcm2835_sdhost_transfer_dma()\n");
++
++ WARN_ON(!host->data);
++
++ if (!host->data)
++ return;
++
++ if (host->data->flags & MMC_DATA_READ) {
++ dma_chan = host->dma_chan_rx;
++ dir_data = DMA_FROM_DEVICE;
++ dir_slave = DMA_DEV_TO_MEM;
++ } else {
++ dma_chan = host->dma_chan_tx;
++ dir_data = DMA_TO_DEVICE;
++ dir_slave = DMA_MEM_TO_DEV;
++ }
++
++ BUG_ON(!dma_chan->device);
++ BUG_ON(!dma_chan->device->dev);
++ BUG_ON(!host->data->sg);
++
++ len = dma_map_sg(dma_chan->device->dev, host->data->sg,
++ host->data->sg_len, dir_data);
++ if (len > 0) {
++ desc = dmaengine_prep_slave_sg(dma_chan, host->data->sg,
++ len, dir_slave,
++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++ } else {
++ dev_err(mmc_dev(host->mmc), "dma_map_sg returned zero length\n");
++ }
++ if (desc) {
++ desc->callback = bcm2835_sdhost_dma_complete;
++ desc->callback_param = host;
++ dmaengine_submit(desc);
++ dma_async_issue_pending(dma_chan);
++ }
++
++}
++
++
++static void bcm2835_sdhost_set_transfer_irqs(struct bcm2835_host *host)
++{
++ u32 all_irqs = SDHCFG_DATA_IRPT_EN | SDHCFG_BLOCK_IRPT_EN |
++ SDHCFG_BUSY_IRPT_EN;
++ if (host->use_dma)
++ host->hcfg = (host->hcfg & ~all_irqs) |
++ SDHCFG_BUSY_IRPT_EN;
++ else
++ host->hcfg = (host->hcfg & ~all_irqs) |
++ SDHCFG_DATA_IRPT_EN |
++ SDHCFG_BUSY_IRPT_EN;
++
++ bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
++}
++
++
++static void bcm2835_sdhost_prepare_data(struct bcm2835_host *host, struct mmc_command *cmd)
++{
++ struct mmc_data *data = cmd->data;
++
++ WARN_ON(host->data);
++
++ if (!data)
++ return;
++
++ /* Sanity checks */
++ BUG_ON(data->blksz * data->blocks > 524288);
++ BUG_ON(data->blksz > host->mmc->max_blk_size);
++ BUG_ON(data->blocks > 65535);
++
++ host->data = data;
++ host->data_complete = 0;
++ host->flush_fifo = 0;
++ host->data->bytes_xfered = 0;
++
++ host->use_dma = host->have_dma && (data->blocks > host->pio_limit);
++ if (!host->use_dma) {
++ int flags;
++
++ flags = SG_MITER_ATOMIC;
++ if (data->flags & MMC_DATA_READ)
++ flags |= SG_MITER_TO_SG;
++ else
++ flags |= SG_MITER_FROM_SG;
++ sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
++ host->blocks = data->blocks;
++ }
++
++ bcm2835_sdhost_set_transfer_irqs(host);
++
++ bcm2835_sdhost_write(host, data->blksz, SDHBCT);
++ bcm2835_sdhost_write(host, host->use_dma ? data->blocks : 0, SDHBLC);
++
++ BUG_ON(!host->data);
++}
++
++
++void bcm2835_sdhost_send_command(struct bcm2835_host *host, struct mmc_command *cmd)
++{
++ u32 sdcmd, sdhsts;
++ unsigned long timeout;
++ int delay;
++
++ WARN_ON(host->cmd);
++
++ if (cmd->data)
++ pr_debug("%s: send_command %d 0x%x "
++ "(flags 0x%x) - %s %d*%d\n",
++ mmc_hostname(host->mmc),
++ cmd->opcode, cmd->arg, cmd->flags,
++ (cmd->data->flags & MMC_DATA_READ) ?
++ "read" : "write", cmd->data->blocks,
++ cmd->data->blksz);
++ else
++ pr_debug("%s: send_command %d 0x%x (flags 0x%x)\n",
++ mmc_hostname(host->mmc),
++ cmd->opcode, cmd->arg, cmd->flags);
++
++ /* Wait max 100 ms */
++ timeout = 10000;
++
++ while (bcm2835_sdhost_read(host, SDCMD) & SDCMD_NEW_FLAG) {
++ if (timeout == 0) {
++ pr_err("%s: previous command never completed.\n",
++ mmc_hostname(host->mmc));
++ bcm2835_sdhost_dumpregs(host);
++ cmd->error = -EIO;
++ tasklet_schedule(&host->finish_tasklet);
++ return;
++ }
++ timeout--;
++ udelay(10);
++ }
++
++ delay = (10000 - timeout)/100;
++ if (delay > host->max_delay) {
++ host->max_delay = delay;
++ pr_warning("%s: controller hung for %d ms\n",
++ mmc_hostname(host->mmc),
++ host->max_delay);
++ }
++
++ timeout = jiffies;
++ if (!cmd->data && cmd->busy_timeout > 9000)
++ timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
++ else
++ timeout += 10 * HZ;
++ mod_timer(&host->timer, timeout);
++
++ host->cmd = cmd;
++
++ /* Clear any error flags */
++ sdhsts = bcm2835_sdhost_read(host, SDHSTS);
++ if (sdhsts & SDHSTS_ERROR_MASK)
++ bcm2835_sdhost_write(host, sdhsts, SDHSTS);
++
++ bcm2835_sdhost_prepare_data(host, cmd);
++
++ bcm2835_sdhost_write(host, cmd->arg, SDARG);
++
++ if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
++ pr_err("%s: unsupported response type!\n",
++ mmc_hostname(host->mmc));
++ cmd->error = -EINVAL;
++ tasklet_schedule(&host->finish_tasklet);
++ return;
++ }
++
++ sdcmd = cmd->opcode & SDCMD_CMD_MASK;
++
++ if (!(cmd->flags & MMC_RSP_PRESENT))
++ sdcmd |= SDCMD_NO_RESPONSE;
++ else {
++ if (cmd->flags & MMC_RSP_136)
++ sdcmd |= SDCMD_LONG_RESPONSE;
++ if (cmd->flags & MMC_RSP_BUSY) {
++ sdcmd |= SDCMD_BUSYWAIT;
++ host->use_busy = 1;
++ }
++ }
++
++ if (cmd->data) {
++ if (host->delay_after_stop) {
++ struct timeval now;
++ int time_since_stop;
++ do_gettimeofday(&now);
++ time_since_stop = (now.tv_sec - host->stop_time.tv_sec);
++ if (time_since_stop < 2) {
++ /* Possibly less than one second */
++ time_since_stop = time_since_stop * 1000000 +
++ (now.tv_usec - host->stop_time.tv_usec);
++ if (time_since_stop < host->delay_after_stop)
++ udelay(host->delay_after_stop -
++ time_since_stop);
++ }
++ }
++
++ if (cmd->data->flags & MMC_DATA_WRITE)
++ sdcmd |= SDCMD_WRITE_CMD;
++ if (cmd->data->flags & MMC_DATA_READ)
++ sdcmd |= SDCMD_READ_CMD;
++ }
++
++ bcm2835_sdhost_write(host, sdcmd | SDCMD_NEW_FLAG, SDCMD);
++}
++
++
++static void bcm2835_sdhost_finish_command(struct bcm2835_host *host);
++static void bcm2835_sdhost_transfer_complete(struct bcm2835_host *host);
++
++static void bcm2835_sdhost_finish_data(struct bcm2835_host *host)
++{
++ struct mmc_data *data;
++
++ data = host->data;
++ BUG_ON(!data);
++
++ pr_debug("finish_data(error %d, stop %d, sbc %d)\n",
++ data->error, data->stop ? 1 : 0,
++ host->mrq->sbc ? 1 : 0);
++
++ host->hcfg &= ~(SDHCFG_DATA_IRPT_EN | SDHCFG_BLOCK_IRPT_EN);
++ bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
++
++ if (data->error) {
++ data->bytes_xfered = 0;
++ } else
++ data->bytes_xfered = data->blksz * data->blocks;
++
++ host->data_complete = 1;
++
++ if (host->cmd) {
++ /*
++ * Data managed to finish before the
++ * command completed. Make sure we do
++ * things in the proper order.
++ */
++ pr_debug("Finished early - HSTS %x\n",
++ bcm2835_sdhost_read(host, SDHSTS));
++ }
++ else
++ bcm2835_sdhost_transfer_complete(host);
++}
++
++
++static void bcm2835_sdhost_transfer_complete(struct bcm2835_host *host)
++{
++ struct mmc_data *data;
++
++ BUG_ON(host->cmd);
++ BUG_ON(!host->data);
++ BUG_ON(!host->data_complete);
++
++ data = host->data;
++ host->data = NULL;
++
++ pr_debug("transfer_complete(error %d, stop %d)\n",
++ data->error, data->stop ? 1 : 0);
++
++ /*
++ * Need to send CMD12 if -
++ * a) open-ended multiblock transfer (no CMD23)
++ * b) error in multiblock transfer
++ */
++ if (data->stop &&
++ (data->error ||
++ !host->mrq->sbc)) {
++ host->flush_fifo = 1;
++ bcm2835_sdhost_send_command(host, data->stop);
++ if (host->delay_after_stop)
++ do_gettimeofday(&host->stop_time);
++ if (!host->use_busy)
++ bcm2835_sdhost_finish_command(host);
++ } else {
++ tasklet_schedule(&host->finish_tasklet);
++ }
++}
++
++static void bcm2835_sdhost_finish_command(struct bcm2835_host *host)
++{
++ u32 sdcmd;
++ unsigned long timeout;
++#ifdef DEBUG
++ struct timeval before, after;
++ int timediff = 0;
++#endif
++
++ pr_debug("finish_command(%x)\n", bcm2835_sdhost_read(host, SDCMD));
++
++ BUG_ON(!host->cmd || !host->mrq);
++
++#ifdef DEBUG
++ do_gettimeofday(&before);
++#endif
++ /* Wait max 100 ms */
++ timeout = 10000;
++ for (sdcmd = bcm2835_sdhost_read(host, SDCMD);
++ (sdcmd & SDCMD_NEW_FLAG) && timeout;
++ timeout--) {
++ if (host->flush_fifo) {
++ while (bcm2835_sdhost_read(host, SDHSTS) &
++ SDHSTS_DATA_FLAG)
++ (void)bcm2835_sdhost_read(host, SDDATA);
++ }
++ udelay(10);
++ sdcmd = bcm2835_sdhost_read(host, SDCMD);
++ }
++#ifdef DEBUG
++ do_gettimeofday(&after);
++ timediff = (after.tv_sec - before.tv_sec)*1000000 +
++ (after.tv_usec - before.tv_usec);
++
++ pr_debug(" finish_command - waited %dus\n", timediff);
++#endif
++
++ if (timeout == 0) {
++ pr_err("%s: command never completed.\n",
++ mmc_hostname(host->mmc));
++ bcm2835_sdhost_dumpregs(host);
++ host->cmd->error = -EIO;
++ tasklet_schedule(&host->finish_tasklet);
++ return;
++ }
++
++ if (host->flush_fifo) {
++ for (timeout = 100;
++ (bcm2835_sdhost_read(host, SDHSTS) & SDHSTS_DATA_FLAG) && timeout;
++ timeout--) {
++ (void)bcm2835_sdhost_read(host, SDDATA);
++ }
++ host->flush_fifo = 0;
++ if (timeout == 0) {
++ pr_err("%s: FIFO never drained.\n",
++ mmc_hostname(host->mmc));
++ bcm2835_sdhost_dumpregs(host);
++ host->cmd->error = -EIO;
++ tasklet_schedule(&host->finish_tasklet);
++ return;
++ }
++ }
++
++ /* Check for errors */
++ if (sdcmd & SDCMD_FAIL_FLAG)
++ {
++ u32 sdhsts = bcm2835_sdhost_read(host, SDHSTS);
++
++ if (host->debug)
++ pr_info("%s: error detected - CMD %x, HSTS %03x, EDM %x\n",
++ mmc_hostname(host->mmc), sdcmd, sdhsts,
++ bcm2835_sdhost_read(host, SDEDM));
++
++ if ((sdhsts & SDHSTS_CRC7_ERROR) &&
++ (host->cmd->opcode == 1)) {
++ if (host->debug)
++ pr_info("%s: ignoring CRC7 error for CMD1\n",
++ mmc_hostname(host->mmc));
++ } else {
++ if (sdhsts & SDHSTS_CMD_TIME_OUT) {
++ if (host->debug)
++ pr_err("%s: command %d timeout\n",
++ mmc_hostname(host->mmc),
++ host->cmd->opcode);
++ host->cmd->error = -ETIMEDOUT;
++ } else {
++ pr_err("%s: unexpected command %d error\n",
++ mmc_hostname(host->mmc),
++ host->cmd->opcode);
++ bcm2835_sdhost_dumpregs(host);
++ host->cmd->error = -EIO;
++ }
++ tasklet_schedule(&host->finish_tasklet);
++ return;
++ }
++ }
++
++ if (host->cmd->flags & MMC_RSP_PRESENT) {
++ if (host->cmd->flags & MMC_RSP_136) {
++ int i;
++ for (i = 0; i < 4; i++)
++ host->cmd->resp[3 - i] = bcm2835_sdhost_read(host, SDRSP0 + i*4);
++ pr_debug("%s: finish_command %08x %08x %08x %08x\n",
++ mmc_hostname(host->mmc),
++ host->cmd->resp[0], host->cmd->resp[1], host->cmd->resp[2], host->cmd->resp[3]);
++ } else {
++ host->cmd->resp[0] = bcm2835_sdhost_read(host, SDRSP0);
++ pr_debug("%s: finish_command %08x\n",
++ mmc_hostname(host->mmc),
++ host->cmd->resp[0]);
++ }
++ }
++
++ host->cmd->error = 0;
++
++ if (host->cmd == host->mrq->sbc) {
++ /* Finished CMD23, now send actual command. */
++ host->cmd = NULL;
++ bcm2835_sdhost_send_command(host, host->mrq->cmd);
++
++ if (host->cmd->data && host->use_dma)
++ /* DMA transfer starts now, PIO starts after irq */
++ bcm2835_sdhost_transfer_dma(host);
++
++ if (!host->use_busy)
++ bcm2835_sdhost_finish_command(host);
++ } else if (host->cmd == host->mrq->stop)
++ /* Finished CMD12 */
++ tasklet_schedule(&host->finish_tasklet);
++ else {
++ /* Processed actual command. */
++ host->cmd = NULL;
++ if (!host->data)
++ tasklet_schedule(&host->finish_tasklet);
++ else if (host->data_complete)
++ bcm2835_sdhost_transfer_complete(host);
++ }
++}
++
++static void bcm2835_sdhost_timeout(unsigned long data)
++{
++ struct bcm2835_host *host;
++ unsigned long flags;
++
++ host = (struct bcm2835_host *)data;
++
++ spin_lock_irqsave(&host->lock, flags);
++
++ if (host->mrq) {
++ pr_err("%s: timeout waiting for hardware interrupt.\n",
++ mmc_hostname(host->mmc));
++ bcm2835_sdhost_dumpregs(host);
++
++ if (host->data) {
++ host->data->error = -ETIMEDOUT;
++ bcm2835_sdhost_finish_data(host);
++ } else {
++ if (host->cmd)
++ host->cmd->error = -ETIMEDOUT;
++ else
++ host->mrq->cmd->error = -ETIMEDOUT;
++
++ pr_debug("timeout_timer tasklet_schedule\n");
++ tasklet_schedule(&host->finish_tasklet);
++ }
++ }
++
++ mmiowb();
++ spin_unlock_irqrestore(&host->lock, flags);
++}
++
++static void bcm2835_sdhost_pio_timeout(unsigned long data)
++{
++ struct bcm2835_host *host;
++ unsigned long flags;
++
++ host = (struct bcm2835_host *)data;
++
++ spin_lock_irqsave(&host->lock, flags);
++
++ if (host->data) {
++ u32 sdhsts = bcm2835_sdhost_read(host, SDHSTS);
++
++ if (sdhsts & SDHSTS_REW_TIME_OUT) {
++ pr_err("%s: transfer timeout\n",
++ mmc_hostname(host->mmc));
++ if (host->debug)
++ bcm2835_sdhost_dumpregs(host);
++ } else {
++ pr_err("%s: unexpected transfer timeout\n",
++ mmc_hostname(host->mmc));
++ bcm2835_sdhost_dumpregs(host);
++ }
++
++ bcm2835_sdhost_write(host, SDHSTS_TRANSFER_ERROR_MASK,
++ SDHSTS);
++
++ host->data->error = -ETIMEDOUT;
++
++ bcm2835_sdhost_finish_data(host);
++ }
++
++ mmiowb();
++ spin_unlock_irqrestore(&host->lock, flags);
++}
++
++static void bcm2835_sdhost_enable_sdio_irq_nolock(struct bcm2835_host *host, int enable)
++{
++ if (enable)
++ host->hcfg |= SDHCFG_SDIO_IRPT_EN;
++ else
++ host->hcfg &= ~SDHCFG_SDIO_IRPT_EN;
++ bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
++ mmiowb();
++}
++
++static void bcm2835_sdhost_enable_sdio_irq(struct mmc_host *mmc, int enable)
++{
++ struct bcm2835_host *host = mmc_priv(mmc);
++ unsigned long flags;
++
++ pr_debug("%s: enable_sdio_irq(%d)\n", mmc_hostname(mmc), enable);
++ spin_lock_irqsave(&host->lock, flags);
++ bcm2835_sdhost_enable_sdio_irq_nolock(host, enable);
++ spin_unlock_irqrestore(&host->lock, flags);
++}
++
++static u32 bcm2835_sdhost_busy_irq(struct bcm2835_host *host, u32 intmask)
++{
++ const u32 handled = (SDHSTS_REW_TIME_OUT | SDHSTS_CMD_TIME_OUT |
++ SDHSTS_CRC16_ERROR | SDHSTS_CRC7_ERROR |
++ SDHSTS_FIFO_ERROR);
++
++ if (!host->cmd) {
++ pr_err("%s: got command busy interrupt 0x%08x even "
++ "though no command operation was in progress.\n",
++ mmc_hostname(host->mmc), (unsigned)intmask);
++ bcm2835_sdhost_dumpregs(host);
++ return 0;
++ }
++
++ if (!host->use_busy) {
++ pr_err("%s: got command busy interrupt 0x%08x even "
++ "though not expecting one.\n",
++ mmc_hostname(host->mmc), (unsigned)intmask);
++ bcm2835_sdhost_dumpregs(host);
++ return 0;
++ }
++ host->use_busy = 0;
++
++ if (intmask & SDHSTS_ERROR_MASK)
++ {
++ pr_err("sdhost_busy_irq: intmask %x, data %p\n", intmask, host->mrq->data);
++ if (intmask & SDHSTS_CRC7_ERROR)
++ host->cmd->error = -EILSEQ;
++ else if (intmask & (SDHSTS_CRC16_ERROR |
++ SDHSTS_FIFO_ERROR)) {
++ if (host->mrq->data)
++ host->mrq->data->error = -EILSEQ;
++ else
++ host->cmd->error = -EILSEQ;
++ } else if (intmask & SDHSTS_REW_TIME_OUT) {
++ if (host->mrq->data)
++ host->mrq->data->error = -ETIMEDOUT;
++ else
++ host->cmd->error = -ETIMEDOUT;
++ } else if (intmask & SDHSTS_CMD_TIME_OUT)
++ host->cmd->error = -ETIMEDOUT;
++
++ bcm2835_sdhost_dumpregs(host);
++ tasklet_schedule(&host->finish_tasklet);
++ }
++ else
++ bcm2835_sdhost_finish_command(host);
++
++ return handled;
++}
++
++static u32 bcm2835_sdhost_data_irq(struct bcm2835_host *host, u32 intmask)
++{
++ const u32 handled = (SDHSTS_REW_TIME_OUT |
++ SDHSTS_CRC16_ERROR |
++ SDHSTS_FIFO_ERROR);
++
++ /* There are no dedicated data/space available interrupt
++ status bits, so it is necessary to use the single shared
++ data/space available FIFO status bits. It is therefore not
++ an error to get here when there is no data transfer in
++ progress. */
++ if (!host->data)
++ return 0;
++
++ if (intmask & (SDHSTS_CRC16_ERROR |
++ SDHSTS_FIFO_ERROR |
++ SDHSTS_REW_TIME_OUT)) {
++ if (intmask & (SDHSTS_CRC16_ERROR |
++ SDHSTS_FIFO_ERROR))
++ host->data->error = -EILSEQ;
++ else
++ host->data->error = -ETIMEDOUT;
++
++ bcm2835_sdhost_dumpregs(host);
++ tasklet_schedule(&host->finish_tasklet);
++ return handled;
++ }
++
++ /* Use the block interrupt for writes after the first block */
++ if (host->data->flags & MMC_DATA_WRITE) {
++ host->hcfg &= ~(SDHCFG_DATA_IRPT_EN);
++ host->hcfg |= SDHCFG_BLOCK_IRPT_EN;
++ bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
++ if (host->data->error)
++ bcm2835_sdhost_finish_data(host);
++ else
++ bcm2835_sdhost_transfer_pio(host);
++ } else {
++ if (!host->data->error) {
++ bcm2835_sdhost_transfer_pio(host);
++ host->blocks--;
++ }
++ if ((host->blocks == 0) || host->data->error)
++ bcm2835_sdhost_finish_data(host);
++ }
++
++ return handled;
++}
++
++static u32 bcm2835_sdhost_block_irq(struct bcm2835_host *host, u32 intmask)
++{
++ struct dma_chan *dma_chan;
++ u32 dir_data;
++ const u32 handled = (SDHSTS_REW_TIME_OUT |
++ SDHSTS_CRC16_ERROR |
++ SDHSTS_FIFO_ERROR);
++
++ if (!host->data) {
++ pr_err("%s: got block interrupt 0x%08x even "
++ "though no data operation was in progress.\n",
++ mmc_hostname(host->mmc), (unsigned)intmask);
++ bcm2835_sdhost_dumpregs(host);
++ return handled;
++ }
++
++ if (intmask & (SDHSTS_CRC16_ERROR |
++ SDHSTS_FIFO_ERROR |
++ SDHSTS_REW_TIME_OUT)) {
++ if (intmask & (SDHSTS_CRC16_ERROR |
++ SDHSTS_FIFO_ERROR))
++ host->data->error = -EILSEQ;
++ else
++ host->data->error = -ETIMEDOUT;
++
++ if (host->debug)
++ bcm2835_sdhost_dumpregs(host);
++ tasklet_schedule(&host->finish_tasklet);
++ return handled;
++ }
++
++ if (!host->use_dma) {
++ BUG_ON(!host->blocks);
++ host->blocks--;
++ if ((host->blocks == 0) || host->data->error) {
++ /* Cancel the timer */
++ del_timer(&host->pio_timer);
++
++ bcm2835_sdhost_finish_data(host);
++ } else {
++ bcm2835_sdhost_transfer_pio(host);
++
++ /* Reset the timer */
++ mod_timer(&host->pio_timer,
++ jiffies + host->pio_timeout);
++ }
++ } else if (host->data->flags & MMC_DATA_WRITE) {
++ dma_chan = host->dma_chan_tx;
++ dir_data = DMA_TO_DEVICE;
++ dma_unmap_sg(dma_chan->device->dev,
++ host->data->sg, host->data->sg_len,
++ dir_data);
++
++ bcm2835_sdhost_finish_data(host);
++ }
++
++ return handled;
++}
++
++
++static irqreturn_t bcm2835_sdhost_irq(int irq, void *dev_id)
++{
++ irqreturn_t result = IRQ_NONE;
++ struct bcm2835_host *host = dev_id;
++ u32 unexpected = 0, early = 0;
++ int loops = 0;
++
++ spin_lock(&host->lock);
++
++ for (loops = 0; loops < 1; loops++) {
++ u32 intmask, handled;
++
++ intmask = bcm2835_sdhost_read(host, SDHSTS);
++ handled = intmask & (SDHSTS_BUSY_IRPT |
++ SDHSTS_BLOCK_IRPT |
++ SDHSTS_SDIO_IRPT |
++ SDHSTS_DATA_FLAG);
++ if ((handled == SDHSTS_DATA_FLAG) &&
++ (loops == 0) && !host->data) {
++ pr_err("%s: sdhost_irq data interrupt 0x%08x even "
++ "though no data operation was in progress.\n",
++ mmc_hostname(host->mmc),
++ (unsigned)intmask);
++
++ bcm2835_sdhost_dumpregs(host);
++ }
++
++ if (!handled)
++ break;
++
++ if (loops)
++ early |= handled;
++
++ result = IRQ_HANDLED;
++
++ /* Clear all interrupts and notifications */
++ bcm2835_sdhost_write(host, intmask, SDHSTS);
++
++ if (intmask & SDHSTS_BUSY_IRPT)
++ handled |= bcm2835_sdhost_busy_irq(host, intmask);
++
++ /* There is no true data interrupt status bit, so it is
++ necessary to qualify the data flag with the interrupt
++ enable bit */
++ if ((intmask & SDHSTS_DATA_FLAG) &&
++ (host->hcfg & SDHCFG_DATA_IRPT_EN))
++ handled |= bcm2835_sdhost_data_irq(host, intmask);
++
++ if (intmask & SDHSTS_BLOCK_IRPT)
++ handled |= bcm2835_sdhost_block_irq(host, intmask);
++
++ if (intmask & SDHSTS_SDIO_IRPT) {
++ bcm2835_sdhost_enable_sdio_irq_nolock(host, false);
++ host->thread_isr |= SDHSTS_SDIO_IRPT;
++ result = IRQ_WAKE_THREAD;
++ }
++
++ unexpected |= (intmask & ~handled);
++ }
++
++ mmiowb();
++
++ spin_unlock(&host->lock);
++
++ if (early)
++ pr_debug("%s: early %x (loops %d)\n",
++ mmc_hostname(host->mmc), early, loops);
++
++ if (unexpected) {
++ pr_err("%s: unexpected interrupt 0x%08x.\n",
++ mmc_hostname(host->mmc), unexpected);
++ bcm2835_sdhost_dumpregs(host);
++ }
++
++ return result;
++}
++
++static irqreturn_t bcm2835_sdhost_thread_irq(int irq, void *dev_id)
++{
++ struct bcm2835_host *host = dev_id;
++ unsigned long flags;
++ u32 isr;
++
++ spin_lock_irqsave(&host->lock, flags);
++ isr = host->thread_isr;
++ host->thread_isr = 0;
++ spin_unlock_irqrestore(&host->lock, flags);
++
++ if (isr & SDHSTS_SDIO_IRPT) {
++ sdio_run_irqs(host->mmc);
++
++/* Is this necessary? Why re-enable an interrupt which is enabled?
++ spin_lock_irqsave(&host->lock, flags);
++ if (host->flags & SDHSTS_SDIO_IRPT_ENABLED)
++ bcm2835_sdhost_enable_sdio_irq_nolock(host, true);
++ spin_unlock_irqrestore(&host->lock, flags);
++*/
++ }
++
++ return isr ? IRQ_HANDLED : IRQ_NONE;
++}
++
++
++
++void bcm2835_sdhost_set_clock(struct bcm2835_host *host, unsigned int clock)
++{
++ int div = 0; /* Initialized for compiler warning */
++ unsigned int input_clock = clock;
++
++ if (host->debug)
++ pr_info("%s: set_clock(%d)\n", mmc_hostname(host->mmc), clock);
++
++ if ((host->overclock_50 > 50) &&
++ (clock == 50*MHZ)) {
++ clock = host->overclock_50 * MHZ + (MHZ - 1);
++ }
++
++ /* The SDCDIV register has 11 bits, and holds (div - 2).
++ But in data mode the max is 50MHz wihout a minimum, and only the
++ bottom 3 bits are used. Since the switch over is automatic (unless
++ we have marked the card as slow...), chosen values have to make
++ sense in both modes.
++ Ident mode must be 100-400KHz, so can range check the requested
++ clock. CMD15 must be used to return to data mode, so this can be
++ monitored.
++
++ clock 250MHz -> 0->125MHz, 1->83.3MHz, 2->62.5MHz, 3->50.0MHz
++ 4->41.7MHz, 5->35.7MHz, 6->31.3MHz, 7->27.8MHz
++
++ 623->400KHz/27.8MHz
++ reset value (507)->491159/50MHz
++
++ BUT, the 3-bit clock divisor in data mode is too small if the
++ core clock is higher than 250MHz, so instead use the SLOW_CARD
++ configuration bit to force the use of the ident clock divisor
++ at all times.
++ */
++
++ host->mmc->actual_clock = 0;
++
++ if (clock < 100000) {
++ /* Can't stop the clock, but make it as slow as possible
++ * to show willing
++ */
++ host->cdiv = SDCDIV_MAX_CDIV;
++ bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
++ return;
++ }
++
++ div = host->max_clk / clock;
++ if (div < 2)
++ div = 2;
++ if ((host->max_clk / div) > clock)
++ div++;
++ div -= 2;
++
++ if (div > SDCDIV_MAX_CDIV)
++ div = SDCDIV_MAX_CDIV;
++
++ clock = host->max_clk / (div + 2);
++ host->mmc->actual_clock = clock;
++
++ if (clock > input_clock) {
++ /* Save the closest value, to make it easier
++ to reduce in the event of error */
++ host->overclock_50 = (clock/MHZ);
++
++ if (clock != host->overclock) {
++ pr_warn("%s: overclocking to %dHz\n",
++ mmc_hostname(host->mmc), clock);
++ host->overclock = clock;
++ }
++ }
++ else if (host->overclock)
++ {
++ host->overclock = 0;
++ if (clock == 50 * MHZ)
++ pr_warn("%s: cancelling overclock\n",
++ mmc_hostname(host->mmc));
++ }
++
++ host->cdiv = div;
++ bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
++
++ /* Set the timeout to 500ms */
++ bcm2835_sdhost_write(host, host->mmc->actual_clock/2, SDTOUT);
++
++ if (host->debug)
++ pr_info("%s: clock=%d -> max_clk=%d, cdiv=%x (actual clock %d)\n",
++ mmc_hostname(host->mmc), input_clock,
++ host->max_clk, host->cdiv, host->mmc->actual_clock);
++}
++
++static void bcm2835_sdhost_request(struct mmc_host *mmc, struct mmc_request *mrq)
++{
++ struct bcm2835_host *host;
++ unsigned long flags;
++
++ host = mmc_priv(mmc);
++
++ if (host->debug) {
++ struct mmc_command *cmd = mrq->cmd;
++ BUG_ON(!cmd);
++ if (cmd->data)
++ pr_info("%s: cmd %d 0x%x (flags 0x%x) - %s %d*%d\n",
++ mmc_hostname(mmc),
++ cmd->opcode, cmd->arg, cmd->flags,
++ (cmd->data->flags & MMC_DATA_READ) ?
++ "read" : "write", cmd->data->blocks,
++ cmd->data->blksz);
++ else
++ pr_info("%s: cmd %d 0x%x (flags 0x%x)\n",
++ mmc_hostname(mmc),
++ cmd->opcode, cmd->arg, cmd->flags);
++ }
++
++ /* Reset the error statuses in case this is a retry */
++ if (mrq->cmd)
++ mrq->cmd->error = 0;
++ if (mrq->data)
++ mrq->data->error = 0;
++ if (mrq->stop)
++ mrq->stop->error = 0;
++
++ if (mrq->data && !is_power_of_2(mrq->data->blksz)) {
++ pr_err("%s: unsupported block size (%d bytes)\n",
++ mmc_hostname(mmc), mrq->data->blksz);
++ mrq->cmd->error = -EINVAL;
++ mmc_request_done(mmc, mrq);
++ return;
++ }
++
++ spin_lock_irqsave(&host->lock, flags);
++
++ WARN_ON(host->mrq != NULL);
++
++ host->mrq = mrq;
++
++ if (mrq->sbc)
++ bcm2835_sdhost_send_command(host, mrq->sbc);
++ else
++ bcm2835_sdhost_send_command(host, mrq->cmd);
++
++ mmiowb();
++ spin_unlock_irqrestore(&host->lock, flags);
++
++ if (!mrq->sbc && mrq->cmd->data && host->use_dma)
++ /* DMA transfer starts now, PIO starts after irq */
++ bcm2835_sdhost_transfer_dma(host);
++
++ if (!host->use_busy)
++ bcm2835_sdhost_finish_command(host);
++}
++
++
++static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
++{
++
++ struct bcm2835_host *host = mmc_priv(mmc);
++ unsigned long flags;
++
++ if (host->debug)
++ pr_info("%s: ios clock %d, pwr %d, bus_width %d, "
++ "timing %d, vdd %d, drv_type %d\n",
++ mmc_hostname(mmc),
++ ios->clock, ios->power_mode, ios->bus_width,
++ ios->timing, ios->signal_voltage, ios->drv_type);
++
++ spin_lock_irqsave(&host->lock, flags);
++
++ if (!ios->clock || ios->clock != host->clock) {
++ bcm2835_sdhost_set_clock(host, ios->clock);
++ host->clock = ios->clock;
++ }
++
++ /* set bus width */
++ host->hcfg &= ~SDHCFG_WIDE_EXT_BUS;
++ if (ios->bus_width == MMC_BUS_WIDTH_4)
++ host->hcfg |= SDHCFG_WIDE_EXT_BUS;
++
++ host->hcfg |= SDHCFG_WIDE_INT_BUS;
++
++ /* Disable clever clock switching, to cope with fast core clocks */
++ host->hcfg |= SDHCFG_SLOW_CARD;
++
++ bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
++
++ mmiowb();
++
++ spin_unlock_irqrestore(&host->lock, flags);
++}
++
++static int bcm2835_sdhost_multi_io_quirk(struct mmc_card *card,
++ unsigned int direction,
++ u32 blk_pos, int blk_size)
++{
++ /* There is a bug in the host controller hardware that makes
++ reading the final sector of the card as part of a multiple read
++ problematic. Detect that case and shorten the read accordingly.
++ */
++ /* csd.capacity is in weird units - convert to sectors */
++ u32 card_sectors = (card->csd.capacity << (card->csd.read_blkbits - 9));
++
++ if ((direction == MMC_DATA_READ) &&
++ ((blk_pos + blk_size) == card_sectors))
++ blk_size--;
++
++ return blk_size;
++}
++
++
++static struct mmc_host_ops bcm2835_sdhost_ops = {
++ .request = bcm2835_sdhost_request,
++ .set_ios = bcm2835_sdhost_set_ios,
++ .enable_sdio_irq = bcm2835_sdhost_enable_sdio_irq,
++ .hw_reset = bcm2835_sdhost_reset,
++ .multi_io_quirk = bcm2835_sdhost_multi_io_quirk,
++};
++
++
++static void bcm2835_sdhost_tasklet_finish(unsigned long param)
++{
++ struct bcm2835_host *host;
++ unsigned long flags;
++ struct mmc_request *mrq;
++
++ host = (struct bcm2835_host *)param;
++
++ spin_lock_irqsave(&host->lock, flags);
++
++ /*
++ * If this tasklet gets rescheduled while running, it will
++ * be run again afterwards but without any active request.
++ */
++ if (!host->mrq) {
++ spin_unlock_irqrestore(&host->lock, flags);
++ return;
++ }
++
++ del_timer(&host->timer);
++
++ mrq = host->mrq;
++
++ /* Drop the overclock after any data corruption, or after any
++ error overclocked */
++ if (host->overclock) {
++ if ((mrq->cmd && mrq->cmd->error) ||
++ (mrq->data && mrq->data->error) ||
++ (mrq->stop && mrq->stop->error)) {
++ host->overclock_50--;
++ pr_warn("%s: reducing overclock due to errors\n",
++ mmc_hostname(host->mmc));
++ bcm2835_sdhost_set_clock(host,50*MHZ);
++ mrq->cmd->error = -EILSEQ;
++ mrq->cmd->retries = 1;
++ }
++ }
++
++ host->mrq = NULL;
++ host->cmd = NULL;
++ host->data = NULL;
++
++ mmiowb();
++
++ spin_unlock_irqrestore(&host->lock, flags);
++ mmc_request_done(host->mmc, mrq);
++}
++
++
++
++int bcm2835_sdhost_add_host(struct bcm2835_host *host)
++{
++ struct mmc_host *mmc;
++ struct dma_slave_config cfg;
++ char pio_limit_string[20];
++ int ret;
++
++ mmc = host->mmc;
++
++ bcm2835_sdhost_reset_internal(host);
++
++ mmc->f_max = host->max_clk;
++ mmc->f_min = host->max_clk / SDCDIV_MAX_CDIV;
++
++ mmc->max_busy_timeout = (~(unsigned int)0)/(mmc->f_max/1000);
++
++ pr_debug("f_max %d, f_min %d, max_busy_timeout %d\n",
++ mmc->f_max, mmc->f_min, mmc->max_busy_timeout);
++
++ /* host controller capabilities */
++ mmc->caps |= /* MMC_CAP_SDIO_IRQ |*/ MMC_CAP_4_BIT_DATA |
++ MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED |
++ MMC_CAP_NEEDS_POLL | MMC_CAP_HW_RESET | MMC_CAP_ERASE |
++ (ALLOW_CMD23 * MMC_CAP_CMD23);
++
++ spin_lock_init(&host->lock);
++
++ if (host->allow_dma) {
++ if (IS_ERR_OR_NULL(host->dma_chan_tx) ||
++ IS_ERR_OR_NULL(host->dma_chan_rx)) {
++ pr_err("%s: unable to initialise DMA channels. "
++ "Falling back to PIO\n",
++ mmc_hostname(mmc));
++ host->have_dma = false;
++ } else {
++ host->have_dma = true;
++
++ cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++ cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++ cfg.slave_id = 13; /* DREQ channel */
++
++ cfg.direction = DMA_MEM_TO_DEV;
++ cfg.src_addr = 0;
++ cfg.dst_addr = host->bus_addr + SDDATA;
++ ret = dmaengine_slave_config(host->dma_chan_tx, &cfg);
++
++ cfg.direction = DMA_DEV_TO_MEM;
++ cfg.src_addr = host->bus_addr + SDDATA;
++ cfg.dst_addr = 0;
++ ret = dmaengine_slave_config(host->dma_chan_rx, &cfg);
++ }
++ } else {
++ host->have_dma = false;
++ }
++
++ mmc->max_segs = 128;
++ mmc->max_req_size = 524288;
++ mmc->max_seg_size = mmc->max_req_size;
++ mmc->max_blk_size = 512;
++ mmc->max_blk_count = 65535;
++
++ /* report supported voltage ranges */
++ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
++
++ tasklet_init(&host->finish_tasklet,
++ bcm2835_sdhost_tasklet_finish, (unsigned long)host);
++
++ setup_timer(&host->timer, bcm2835_sdhost_timeout,
++ (unsigned long)host);
++
++ setup_timer(&host->pio_timer, bcm2835_sdhost_pio_timeout,
++ (unsigned long)host);
++
++ bcm2835_sdhost_init(host, 0);
++ ret = request_threaded_irq(host->irq, bcm2835_sdhost_irq,
++ bcm2835_sdhost_thread_irq,
++ IRQF_SHARED, mmc_hostname(mmc), host);
++ if (ret) {
++ pr_err("%s: failed to request IRQ %d: %d\n",
++ mmc_hostname(mmc), host->irq, ret);
++ goto untasklet;
++ }
++
++ mmiowb();
++ mmc_add_host(mmc);
++
++ pio_limit_string[0] = '\0';
++ if (host->have_dma && (host->pio_limit > 0))
++ sprintf(pio_limit_string, " (>%d)", host->pio_limit);
++ pr_info("%s: %s loaded - DMA %s%s\n",
++ mmc_hostname(mmc), DRIVER_NAME,
++ host->have_dma ? "enabled" : "disabled",
++ pio_limit_string);
++
++ return 0;
++
++untasklet:
++ tasklet_kill(&host->finish_tasklet);
++
++ return ret;
++}
++
++static int bcm2835_sdhost_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct device_node *node = dev->of_node;
++ struct clk *clk;
++ struct resource *iomem;
++ struct bcm2835_host *host;
++ struct mmc_host *mmc;
++ const __be32 *addr;
++ int ret;
++
++ pr_debug("bcm2835_sdhost_probe\n");
++ mmc = mmc_alloc_host(sizeof(*host), dev);
++ if (!mmc)
++ return -ENOMEM;
++
++ mmc->ops = &bcm2835_sdhost_ops;
++ host = mmc_priv(mmc);
++ host->mmc = mmc;
++ host->pio_timeout = msecs_to_jiffies(500);
++ host->max_delay = 1; /* Warn if over 1ms */
++ spin_lock_init(&host->lock);
++
++ iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ host->ioaddr = devm_ioremap_resource(dev, iomem);
++ if (IS_ERR(host->ioaddr)) {
++ ret = PTR_ERR(host->ioaddr);
++ goto err;
++ }
++
++ addr = of_get_address(node, 0, NULL, NULL);
++ if (!addr) {
++ dev_err(dev, "could not get DMA-register address\n");
++ return -ENODEV;
++ }
++ host->bus_addr = be32_to_cpup(addr);
++ pr_debug(" - ioaddr %lx, iomem->start %lx, bus_addr %lx\n",
++ (unsigned long)host->ioaddr,
++ (unsigned long)iomem->start,
++ (unsigned long)host->bus_addr);
++
++ host->allow_dma = ALLOW_DMA;
++
++ if (node) {
++ /* Read any custom properties */
++ of_property_read_u32(node,
++ "brcm,delay-after-stop",
++ &host->delay_after_stop);
++ of_property_read_u32(node,
++ "brcm,overclock-50",
++ &host->overclock_50);
++ of_property_read_u32(node,
++ "brcm,pio-limit",
++ &host->pio_limit);
++ host->allow_dma = ALLOW_DMA &&
++ !of_property_read_bool(node, "brcm,force-pio");
++ host->debug = of_property_read_bool(node, "brcm,debug");
++ }
++
++ if (host->allow_dma) {
++ if (node) {
++ host->dma_chan_tx =
++ dma_request_slave_channel(dev, "tx");
++ host->dma_chan_rx =
++ dma_request_slave_channel(dev, "rx");
++ } else {
++ dma_cap_mask_t mask;
++
++ dma_cap_zero(mask);
++ /* we don't care about the channel, any would work */
++ dma_cap_set(DMA_SLAVE, mask);
++ host->dma_chan_tx =
++ dma_request_channel(mask, NULL, NULL);
++ host->dma_chan_rx =
++ dma_request_channel(mask, NULL, NULL);
++ }
++ }
++
++ clk = devm_clk_get(dev, NULL);
++ if (IS_ERR(clk)) {
++ dev_err(dev, "could not get clk\n");
++ ret = PTR_ERR(clk);
++ goto err;
++ }
++
++ host->max_clk = clk_get_rate(clk);
++
++ host->irq = platform_get_irq(pdev, 0);
++ if (host->irq <= 0) {
++ dev_err(dev, "get IRQ failed\n");
++ ret = -EINVAL;
++ goto err;
++ }
++
++ pr_debug(" - max_clk %lx, irq %d\n",
++ (unsigned long)host->max_clk,
++ (int)host->irq);
++
++ if (node)
++ mmc_of_parse(mmc);
++ else
++ mmc->caps |= MMC_CAP_4_BIT_DATA;
++
++ ret = bcm2835_sdhost_add_host(host);
++ if (ret)
++ goto err;
++
++ platform_set_drvdata(pdev, host);
++
++ pr_debug("bcm2835_sdhost_probe -> OK\n");
++
++ return 0;
++
++err:
++ pr_debug("bcm2835_sdhost_probe -> err %d\n", ret);
++ mmc_free_host(mmc);
++
++ return ret;
++}
++
++static int bcm2835_sdhost_remove(struct platform_device *pdev)
++{
++ struct bcm2835_host *host = platform_get_drvdata(pdev);
++
++ pr_debug("bcm2835_sdhost_remove\n");
++
++ mmc_remove_host(host->mmc);
++
++ bcm2835_sdhost_set_power(host, false);
++
++ free_irq(host->irq, host);
++
++ del_timer_sync(&host->timer);
++
++ tasklet_kill(&host->finish_tasklet);
++
++ mmc_free_host(host->mmc);
++ platform_set_drvdata(pdev, NULL);
++
++ pr_debug("bcm2835_sdhost_remove - OK\n");
++ return 0;
++}
++
++
++static const struct of_device_id bcm2835_sdhost_match[] = {
++ { .compatible = "brcm,bcm2835-sdhost" },
++ { }
++};
++MODULE_DEVICE_TABLE(of, bcm2835_sdhost_match);
++
++
++
++static struct platform_driver bcm2835_sdhost_driver = {
++ .probe = bcm2835_sdhost_probe,
++ .remove = bcm2835_sdhost_remove,
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ .of_match_table = bcm2835_sdhost_match,
++ },
++};
++module_platform_driver(bcm2835_sdhost_driver);
++
++MODULE_ALIAS("platform:sdhost-bcm2835");
++MODULE_DESCRIPTION("BCM2835 SDHost driver");
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Phil Elwell");
diff --git a/target/linux/brcm2708/patches-4.4/0033-MMC-added-alternative-MMC-driver.patch b/target/linux/brcm2708/patches-4.4/0033-MMC-added-alternative-MMC-driver.patch
deleted file mode 100644
index f5996286c8..0000000000
--- a/target/linux/brcm2708/patches-4.4/0033-MMC-added-alternative-MMC-driver.patch
+++ /dev/null
@@ -1,1691 +0,0 @@
-From 3d0ca77d187abbbde572f4a73b1f864ffb8b5d8a Mon Sep 17 00:00:00 2001
-From: gellert <gellert@raspberrypi.org>
-Date: Fri, 15 Aug 2014 16:35:06 +0100
-Subject: [PATCH 033/170] MMC: added alternative MMC driver
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-mmc: Disable CMD23 transfers on all cards
-
-Pending wire-level investigation of these types of transfers
-and associated errors on bcm2835-mmc, disable for now. Fallback of
-CMD18/CMD25 transfers will be used automatically by the MMC layer.
-
-Reported/Tested-by: Gellert Weisz <gellert@raspberrypi.org>
-
-mmc: bcm2835-mmc: enable DT support for all architectures
-
-Both ARCH_BCM2835 and ARCH_BCM270x are built with OF now.
-Enable Device Tree support for all architectures.
-
-Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
-
-mmc: bcm2835-mmc: fix probe error handling
-
-Probe error handling is broken in several places.
-Simplify error handling by using device managed functions.
-Replace pr_{err,info} with dev_{err,info}.
-
-Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
-
-bcm2835-mmc: Add locks when accessing sdhost registers
-
-bcm2835-mmc: Add range of debug options for slowing things down
-
-bcm2835-mmc: Add option to disable some delays
-
-bcm2835-mmc: Add option to disable MMC_QUIRK_BLK_NO_CMD23
-
-bcm2835-mmc: Default to disabling MMC_QUIRK_BLK_NO_CMD23
-
-bcm2835-mmc: Adding overclocking option
-
-Allow a different clock speed to be substitued for a requested 50MHz.
-This option is exposed using the "overclock_50" DT parameter.
-Note that the mmc interface is restricted to EVEN integer divisions of
-250MHz, and the highest sensible option is 63 (250/4 = 62.5), the
-next being 125 (250/2) which is much too high.
-
-Use at your own risk.
-
-bcm2835-mmc: Round up the overclock, so 62 works for 62.5Mhz
-
-Also only warn once for each overclock setting.
-
-mmc: bcm2835-mmc: Make available on ARCH_BCM2835
-
-Make the bcm2835-mmc driver available for use on ARCH_BCM2835.
-
-Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
-
-BCM270x_DT: add bcm2835-mmc entry
-
-Add Device Tree entry for bcm2835-mmc.
-In non-DT mode, don't add the device in the board file.
-
-Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
-
-bcm2835-mmc: Don't overwrite MMC capabilities from DT
----
- drivers/mmc/core/quirks.c | 6 +
- drivers/mmc/host/Kconfig | 29 +
- drivers/mmc/host/Makefile | 1 +
- drivers/mmc/host/bcm2835-mmc.c | 1542 ++++++++++++++++++++++++++++++++++++++++
- 4 files changed, 1578 insertions(+)
- create mode 100644 drivers/mmc/host/bcm2835-mmc.c
-
---- a/drivers/mmc/core/quirks.c
-+++ b/drivers/mmc/core/quirks.c
-@@ -53,6 +53,7 @@ static const struct mmc_fixup mmc_fixup_
-
- void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table)
- {
-+ extern unsigned mmc_debug;
- const struct mmc_fixup *f;
- u64 rev = cid_rev_card(card);
-
-@@ -77,5 +78,10 @@ void mmc_fixup_device(struct mmc_card *c
- f->vendor_fixup(card, f->data);
- }
- }
-+ /* SDHCI on BCM2708 - bug causes a certain sequence of CMD23 operations to fail.
-+ * Disable this flag for all cards (fall-back to CMD25/CMD18 multi-block transfers).
-+ */
-+ if (mmc_debug & (1<<13))
-+ card->quirks |= MMC_QUIRK_BLK_NO_CMD23;
- }
- EXPORT_SYMBOL(mmc_fixup_device);
---- a/drivers/mmc/host/Kconfig
-+++ b/drivers/mmc/host/Kconfig
-@@ -4,6 +4,35 @@
-
- comment "MMC/SD/SDIO Host Controller Drivers"
-
-+config MMC_BCM2835
-+ tristate "MMC support on BCM2835"
-+ depends on MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835
-+ help
-+ This selects the MMC Interface on BCM2835.
-+
-+ If you have a controller with this interface, say Y or M here.
-+
-+ If unsure, say N.
-+
-+config MMC_BCM2835_DMA
-+ bool "DMA support on BCM2835 Arasan controller"
-+ depends on MMC_BCM2835
-+ help
-+ Enable DMA support on the Arasan SDHCI controller in Broadcom 2708
-+ based chips.
-+
-+ If unsure, say N.
-+
-+config MMC_BCM2835_PIO_DMA_BARRIER
-+ int "Block count limit for PIO transfers"
-+ depends on MMC_BCM2835 && MMC_BCM2835_DMA
-+ range 0 256
-+ default 2
-+ help
-+ The inclusive limit in bytes under which PIO will be used instead of DMA
-+
-+ If unsure, say 2 here.
-+
- config MMC_ARMMMCI
- tristate "ARM AMBA Multimedia Card Interface support"
- depends on ARM_AMBA
---- a/drivers/mmc/host/Makefile
-+++ b/drivers/mmc/host/Makefile
-@@ -18,6 +18,7 @@ obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c
- obj-$(CONFIG_MMC_SDHCI_SIRF) += sdhci-sirf.o
- obj-$(CONFIG_MMC_SDHCI_F_SDH30) += sdhci_f_sdh30.o
- obj-$(CONFIG_MMC_SDHCI_SPEAR) += sdhci-spear.o
-+obj-$(CONFIG_MMC_BCM2835) += bcm2835-mmc.o
- obj-$(CONFIG_MMC_WBSD) += wbsd.o
- obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
- obj-$(CONFIG_MMC_MTK) += mtk-sd.o
---- /dev/null
-+++ b/drivers/mmc/host/bcm2835-mmc.c
-@@ -0,0 +1,1542 @@
-+/*
-+ * BCM2835 MMC host driver.
-+ *
-+ * Author: Gellert Weisz <gellert@raspberrypi.org>
-+ * Copyright 2014
-+ *
-+ * Based on
-+ * sdhci-bcm2708.c by Broadcom
-+ * sdhci-bcm2835.c by Stephen Warren and Oleksandr Tymoshenko
-+ * sdhci.c and sdhci-pci.c by Pierre Ossman
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms and conditions of the GNU General Public License,
-+ * version 2, as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope it will be useful, but WITHOUT
-+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
-+ * more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#include <linux/delay.h>
-+#include <linux/module.h>
-+#include <linux/io.h>
-+#include <linux/mmc/mmc.h>
-+#include <linux/mmc/host.h>
-+#include <linux/mmc/sd.h>
-+#include <linux/scatterlist.h>
-+#include <linux/of_address.h>
-+#include <linux/of_irq.h>
-+#include <linux/clk.h>
-+#include <linux/platform_device.h>
-+#include <linux/err.h>
-+#include <linux/blkdev.h>
-+#include <linux/dmaengine.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/of_dma.h>
-+
-+#include "sdhci.h"
-+
-+
-+#define DRIVER_NAME "mmc-bcm2835"
-+
-+#define DBG(f, x...) \
-+pr_debug(DRIVER_NAME " [%s()]: " f, __func__, ## x)
-+
-+#ifndef CONFIG_MMC_BCM2835_DMA
-+ #define FORCE_PIO
-+#endif
-+
-+
-+/* the inclusive limit in bytes under which PIO will be used instead of DMA */
-+#ifdef CONFIG_MMC_BCM2835_PIO_DMA_BARRIER
-+#define PIO_DMA_BARRIER CONFIG_MMC_BCM2835_PIO_DMA_BARRIER
-+#else
-+#define PIO_DMA_BARRIER 00
-+#endif
-+
-+#define MIN_FREQ 400000
-+#define TIMEOUT_VAL 0xE
-+#define BCM2835_SDHCI_WRITE_DELAY(f) (((2 * 1000000) / f) + 1)
-+
-+
-+unsigned mmc_debug;
-+unsigned mmc_debug2;
-+
-+struct bcm2835_host {
-+ spinlock_t lock;
-+
-+ void __iomem *ioaddr;
-+ u32 bus_addr;
-+
-+ struct mmc_host *mmc;
-+
-+ u32 timeout;
-+
-+ int clock; /* Current clock speed */
-+ u8 pwr; /* Current voltage */
-+
-+ unsigned int max_clk; /* Max possible freq */
-+ unsigned int timeout_clk; /* Timeout freq (KHz) */
-+ unsigned int clk_mul; /* Clock Muliplier value */
-+
-+ struct tasklet_struct finish_tasklet; /* Tasklet structures */
-+
-+ struct timer_list timer; /* Timer for timeouts */
-+
-+ struct sg_mapping_iter sg_miter; /* SG state for PIO */
-+ unsigned int blocks; /* remaining PIO blocks */
-+
-+ int irq; /* Device IRQ */
-+
-+
-+ u32 ier; /* cached registers */
-+
-+ struct mmc_request *mrq; /* Current request */
-+ struct mmc_command *cmd; /* Current command */
-+ struct mmc_data *data; /* Current data request */
-+ unsigned int data_early:1; /* Data finished before cmd */
-+
-+ wait_queue_head_t buf_ready_int; /* Waitqueue for Buffer Read Ready interrupt */
-+
-+ u32 thread_isr;
-+
-+ u32 shadow;
-+
-+ /*DMA part*/
-+ struct dma_chan *dma_chan_rx; /* DMA channel for reads */
-+ struct dma_chan *dma_chan_tx; /* DMA channel for writes */
-+ struct dma_async_tx_descriptor *tx_desc; /* descriptor */
-+
-+ bool have_dma;
-+ bool use_dma;
-+ /*end of DMA part*/
-+
-+ int max_delay; /* maximum length of time spent waiting */
-+
-+ int flags; /* Host attributes */
-+#define SDHCI_REQ_USE_DMA (1<<2) /* Use DMA for this req. */
-+#define SDHCI_DEVICE_DEAD (1<<3) /* Device unresponsive */
-+#define SDHCI_AUTO_CMD12 (1<<6) /* Auto CMD12 support */
-+#define SDHCI_AUTO_CMD23 (1<<7) /* Auto CMD23 support */
-+#define SDHCI_SDIO_IRQ_ENABLED (1<<9) /* SDIO irq enabled */
-+
-+ u32 overclock_50; /* frequency to use when 50MHz is requested (in MHz) */
-+ u32 max_overclock; /* Highest reported */
-+};
-+
-+
-+static inline void bcm2835_mmc_writel(struct bcm2835_host *host, u32 val, int reg, int from)
-+{
-+ unsigned delay;
-+ lockdep_assert_held_once(&host->lock);
-+ writel(val, host->ioaddr + reg);
-+ udelay(BCM2835_SDHCI_WRITE_DELAY(max(host->clock, MIN_FREQ)));
-+
-+ delay = ((mmc_debug >> 16) & 0xf) << ((mmc_debug >> 20) & 0xf);
-+ if (delay && !((1<<from) & mmc_debug2))
-+ udelay(delay);
-+}
-+
-+static inline void mmc_raw_writel(struct bcm2835_host *host, u32 val, int reg)
-+{
-+ unsigned delay;
-+ lockdep_assert_held_once(&host->lock);
-+ writel(val, host->ioaddr + reg);
-+
-+ delay = ((mmc_debug >> 24) & 0xf) << ((mmc_debug >> 28) & 0xf);
-+ if (delay)
-+ udelay(delay);
-+}
-+
-+static inline u32 bcm2835_mmc_readl(struct bcm2835_host *host, int reg)
-+{
-+ lockdep_assert_held_once(&host->lock);
-+ return readl(host->ioaddr + reg);
-+}
-+
-+static inline void bcm2835_mmc_writew(struct bcm2835_host *host, u16 val, int reg)
-+{
-+ u32 oldval = (reg == SDHCI_COMMAND) ? host->shadow :
-+ bcm2835_mmc_readl(host, reg & ~3);
-+ u32 word_num = (reg >> 1) & 1;
-+ u32 word_shift = word_num * 16;
-+ u32 mask = 0xffff << word_shift;
-+ u32 newval = (oldval & ~mask) | (val << word_shift);
-+
-+ if (reg == SDHCI_TRANSFER_MODE)
-+ host->shadow = newval;
-+ else
-+ bcm2835_mmc_writel(host, newval, reg & ~3, 0);
-+
-+}
-+
-+static inline void bcm2835_mmc_writeb(struct bcm2835_host *host, u8 val, int reg)
-+{
-+ u32 oldval = bcm2835_mmc_readl(host, reg & ~3);
-+ u32 byte_num = reg & 3;
-+ u32 byte_shift = byte_num * 8;
-+ u32 mask = 0xff << byte_shift;
-+ u32 newval = (oldval & ~mask) | (val << byte_shift);
-+
-+ bcm2835_mmc_writel(host, newval, reg & ~3, 1);
-+}
-+
-+
-+static inline u16 bcm2835_mmc_readw(struct bcm2835_host *host, int reg)
-+{
-+ u32 val = bcm2835_mmc_readl(host, (reg & ~3));
-+ u32 word_num = (reg >> 1) & 1;
-+ u32 word_shift = word_num * 16;
-+ u32 word = (val >> word_shift) & 0xffff;
-+
-+ return word;
-+}
-+
-+static inline u8 bcm2835_mmc_readb(struct bcm2835_host *host, int reg)
-+{
-+ u32 val = bcm2835_mmc_readl(host, (reg & ~3));
-+ u32 byte_num = reg & 3;
-+ u32 byte_shift = byte_num * 8;
-+ u32 byte = (val >> byte_shift) & 0xff;
-+
-+ return byte;
-+}
-+
-+static void bcm2835_mmc_unsignal_irqs(struct bcm2835_host *host, u32 clear)
-+{
-+ u32 ier;
-+
-+ ier = bcm2835_mmc_readl(host, SDHCI_SIGNAL_ENABLE);
-+ ier &= ~clear;
-+ /* change which requests generate IRQs - makes no difference to
-+ the content of SDHCI_INT_STATUS, or the need to acknowledge IRQs */
-+ bcm2835_mmc_writel(host, ier, SDHCI_SIGNAL_ENABLE, 2);
-+}
-+
-+
-+static void bcm2835_mmc_dumpregs(struct bcm2835_host *host)
-+{
-+ pr_debug(DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n",
-+ mmc_hostname(host->mmc));
-+
-+ pr_debug(DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n",
-+ bcm2835_mmc_readl(host, SDHCI_DMA_ADDRESS),
-+ bcm2835_mmc_readw(host, SDHCI_HOST_VERSION));
-+ pr_debug(DRIVER_NAME ": Blk size: 0x%08x | Blk cnt: 0x%08x\n",
-+ bcm2835_mmc_readw(host, SDHCI_BLOCK_SIZE),
-+ bcm2835_mmc_readw(host, SDHCI_BLOCK_COUNT));
-+ pr_debug(DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n",
-+ bcm2835_mmc_readl(host, SDHCI_ARGUMENT),
-+ bcm2835_mmc_readw(host, SDHCI_TRANSFER_MODE));
-+ pr_debug(DRIVER_NAME ": Present: 0x%08x | Host ctl: 0x%08x\n",
-+ bcm2835_mmc_readl(host, SDHCI_PRESENT_STATE),
-+ bcm2835_mmc_readb(host, SDHCI_HOST_CONTROL));
-+ pr_debug(DRIVER_NAME ": Power: 0x%08x | Blk gap: 0x%08x\n",
-+ bcm2835_mmc_readb(host, SDHCI_POWER_CONTROL),
-+ bcm2835_mmc_readb(host, SDHCI_BLOCK_GAP_CONTROL));
-+ pr_debug(DRIVER_NAME ": Wake-up: 0x%08x | Clock: 0x%08x\n",
-+ bcm2835_mmc_readb(host, SDHCI_WAKE_UP_CONTROL),
-+ bcm2835_mmc_readw(host, SDHCI_CLOCK_CONTROL));
-+ pr_debug(DRIVER_NAME ": Timeout: 0x%08x | Int stat: 0x%08x\n",
-+ bcm2835_mmc_readb(host, SDHCI_TIMEOUT_CONTROL),
-+ bcm2835_mmc_readl(host, SDHCI_INT_STATUS));
-+ pr_debug(DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n",
-+ bcm2835_mmc_readl(host, SDHCI_INT_ENABLE),
-+ bcm2835_mmc_readl(host, SDHCI_SIGNAL_ENABLE));
-+ pr_debug(DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n",
-+ bcm2835_mmc_readw(host, SDHCI_ACMD12_ERR),
-+ bcm2835_mmc_readw(host, SDHCI_SLOT_INT_STATUS));
-+ pr_debug(DRIVER_NAME ": Caps: 0x%08x | Caps_1: 0x%08x\n",
-+ bcm2835_mmc_readl(host, SDHCI_CAPABILITIES),
-+ bcm2835_mmc_readl(host, SDHCI_CAPABILITIES_1));
-+ pr_debug(DRIVER_NAME ": Cmd: 0x%08x | Max curr: 0x%08x\n",
-+ bcm2835_mmc_readw(host, SDHCI_COMMAND),
-+ bcm2835_mmc_readl(host, SDHCI_MAX_CURRENT));
-+ pr_debug(DRIVER_NAME ": Host ctl2: 0x%08x\n",
-+ bcm2835_mmc_readw(host, SDHCI_HOST_CONTROL2));
-+
-+ pr_debug(DRIVER_NAME ": ===========================================\n");
-+}
-+
-+
-+static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask)
-+{
-+ unsigned long timeout;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&host->lock, flags);
-+ bcm2835_mmc_writeb(host, mask, SDHCI_SOFTWARE_RESET);
-+
-+ if (mask & SDHCI_RESET_ALL)
-+ host->clock = 0;
-+
-+ /* Wait max 100 ms */
-+ timeout = 100;
-+
-+ /* hw clears the bit when it's done */
-+ while (bcm2835_mmc_readb(host, SDHCI_SOFTWARE_RESET) & mask) {
-+ if (timeout == 0) {
-+ pr_err("%s: Reset 0x%x never completed.\n",
-+ mmc_hostname(host->mmc), (int)mask);
-+ bcm2835_mmc_dumpregs(host);
-+ return;
-+ }
-+ timeout--;
-+ spin_unlock_irqrestore(&host->lock, flags);
-+ mdelay(1);
-+ spin_lock_irqsave(&host->lock, flags);
-+ }
-+
-+ if (100-timeout > 10 && 100-timeout > host->max_delay) {
-+ host->max_delay = 100-timeout;
-+ pr_warning("Warning: MMC controller hung for %d ms\n", host->max_delay);
-+ }
-+ spin_unlock_irqrestore(&host->lock, flags);
-+}
-+
-+static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
-+
-+static void bcm2835_mmc_init(struct bcm2835_host *host, int soft)
-+{
-+ unsigned long flags;
-+ if (soft)
-+ bcm2835_mmc_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA);
-+ else
-+ bcm2835_mmc_reset(host, SDHCI_RESET_ALL);
-+
-+ host->ier = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
-+ SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT |
-+ SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC |
-+ SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END |
-+ SDHCI_INT_RESPONSE;
-+
-+ spin_lock_irqsave(&host->lock, flags);
-+ bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 3);
-+ bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 3);
-+ spin_unlock_irqrestore(&host->lock, flags);
-+
-+ if (soft) {
-+ /* force clock reconfiguration */
-+ host->clock = 0;
-+ bcm2835_mmc_set_ios(host->mmc, &host->mmc->ios);
-+ }
-+}
-+
-+
-+
-+static void bcm2835_mmc_finish_data(struct bcm2835_host *host);
-+
-+static void bcm2835_mmc_dma_complete(void *param)
-+{
-+ struct bcm2835_host *host = param;
-+ struct dma_chan *dma_chan;
-+ unsigned long flags;
-+ u32 dir_data;
-+
-+ spin_lock_irqsave(&host->lock, flags);
-+
-+ if (host->data && !(host->data->flags & MMC_DATA_WRITE)) {
-+ /* otherwise handled in SDHCI IRQ */
-+ dma_chan = host->dma_chan_rx;
-+ dir_data = DMA_FROM_DEVICE;
-+
-+ dma_unmap_sg(dma_chan->device->dev,
-+ host->data->sg, host->data->sg_len,
-+ dir_data);
-+
-+ bcm2835_mmc_finish_data(host);
-+ }
-+
-+ spin_unlock_irqrestore(&host->lock, flags);
-+}
-+
-+static void bcm2835_bcm2835_mmc_read_block_pio(struct bcm2835_host *host)
-+{
-+ unsigned long flags;
-+ size_t blksize, len, chunk;
-+
-+ u32 uninitialized_var(scratch);
-+ u8 *buf;
-+
-+ blksize = host->data->blksz;
-+ chunk = 0;
-+
-+ local_irq_save(flags);
-+
-+ while (blksize) {
-+ if (!sg_miter_next(&host->sg_miter))
-+ BUG();
-+
-+ len = min(host->sg_miter.length, blksize);
-+
-+ blksize -= len;
-+ host->sg_miter.consumed = len;
-+
-+ buf = host->sg_miter.addr;
-+
-+ while (len) {
-+ if (chunk == 0) {
-+ scratch = bcm2835_mmc_readl(host, SDHCI_BUFFER);
-+ chunk = 4;
-+ }
-+
-+ *buf = scratch & 0xFF;
-+
-+ buf++;
-+ scratch >>= 8;
-+ chunk--;
-+ len--;
-+ }
-+ }
-+
-+ sg_miter_stop(&host->sg_miter);
-+
-+ local_irq_restore(flags);
-+}
-+
-+static void bcm2835_bcm2835_mmc_write_block_pio(struct bcm2835_host *host)
-+{
-+ unsigned long flags;
-+ size_t blksize, len, chunk;
-+ u32 scratch;
-+ u8 *buf;
-+
-+ blksize = host->data->blksz;
-+ chunk = 0;
-+ chunk = 0;
-+ scratch = 0;
-+
-+ local_irq_save(flags);
-+
-+ while (blksize) {
-+ if (!sg_miter_next(&host->sg_miter))
-+ BUG();
-+
-+ len = min(host->sg_miter.length, blksize);
-+
-+ blksize -= len;
-+ host->sg_miter.consumed = len;
-+
-+ buf = host->sg_miter.addr;
-+
-+ while (len) {
-+ scratch |= (u32)*buf << (chunk * 8);
-+
-+ buf++;
-+ chunk++;
-+ len--;
-+
-+ if ((chunk == 4) || ((len == 0) && (blksize == 0))) {
-+ mmc_raw_writel(host, scratch, SDHCI_BUFFER);
-+ chunk = 0;
-+ scratch = 0;
-+ }
-+ }
-+ }
-+
-+ sg_miter_stop(&host->sg_miter);
-+
-+ local_irq_restore(flags);
-+}
-+
-+
-+static void bcm2835_mmc_transfer_pio(struct bcm2835_host *host)
-+{
-+ u32 mask;
-+
-+ BUG_ON(!host->data);
-+
-+ if (host->blocks == 0)
-+ return;
-+
-+ if (host->data->flags & MMC_DATA_READ)
-+ mask = SDHCI_DATA_AVAILABLE;
-+ else
-+ mask = SDHCI_SPACE_AVAILABLE;
-+
-+ while (bcm2835_mmc_readl(host, SDHCI_PRESENT_STATE) & mask) {
-+
-+ if (host->data->flags & MMC_DATA_READ)
-+ bcm2835_bcm2835_mmc_read_block_pio(host);
-+ else
-+ bcm2835_bcm2835_mmc_write_block_pio(host);
-+
-+ host->blocks--;
-+
-+ /* QUIRK used in sdhci.c removes the 'if' */
-+ /* but it seems this is unnecessary */
-+ if (host->blocks == 0)
-+ break;
-+
-+
-+ }
-+}
-+
-+
-+static void bcm2835_mmc_transfer_dma(struct bcm2835_host *host)
-+{
-+ u32 len, dir_data, dir_slave;
-+ struct dma_async_tx_descriptor *desc = NULL;
-+ struct dma_chan *dma_chan;
-+
-+
-+ WARN_ON(!host->data);
-+
-+ if (!host->data)
-+ return;
-+
-+ if (host->blocks == 0)
-+ return;
-+
-+ if (host->data->flags & MMC_DATA_READ) {
-+ dma_chan = host->dma_chan_rx;
-+ dir_data = DMA_FROM_DEVICE;
-+ dir_slave = DMA_DEV_TO_MEM;
-+ } else {
-+ dma_chan = host->dma_chan_tx;
-+ dir_data = DMA_TO_DEVICE;
-+ dir_slave = DMA_MEM_TO_DEV;
-+ }
-+
-+ BUG_ON(!dma_chan->device);
-+ BUG_ON(!dma_chan->device->dev);
-+ BUG_ON(!host->data->sg);
-+
-+ len = dma_map_sg(dma_chan->device->dev, host->data->sg,
-+ host->data->sg_len, dir_data);
-+ if (len > 0) {
-+ desc = dmaengine_prep_slave_sg(dma_chan, host->data->sg,
-+ len, dir_slave,
-+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-+ } else {
-+ dev_err(mmc_dev(host->mmc), "dma_map_sg returned zero length\n");
-+ }
-+ if (desc) {
-+ unsigned long flags;
-+ spin_lock_irqsave(&host->lock, flags);
-+ bcm2835_mmc_unsignal_irqs(host, SDHCI_INT_DATA_AVAIL |
-+ SDHCI_INT_SPACE_AVAIL);
-+ host->tx_desc = desc;
-+ desc->callback = bcm2835_mmc_dma_complete;
-+ desc->callback_param = host;
-+ spin_unlock_irqrestore(&host->lock, flags);
-+ dmaengine_submit(desc);
-+ dma_async_issue_pending(dma_chan);
-+ }
-+
-+}
-+
-+
-+
-+static void bcm2835_mmc_set_transfer_irqs(struct bcm2835_host *host)
-+{
-+ u32 pio_irqs = SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL;
-+ u32 dma_irqs = SDHCI_INT_DMA_END | SDHCI_INT_ADMA_ERROR;
-+
-+ if (host->use_dma)
-+ host->ier = (host->ier & ~pio_irqs) | dma_irqs;
-+ else
-+ host->ier = (host->ier & ~dma_irqs) | pio_irqs;
-+
-+ bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 4);
-+ bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 4);
-+}
-+
-+
-+static void bcm2835_mmc_prepare_data(struct bcm2835_host *host, struct mmc_command *cmd)
-+{
-+ u8 count;
-+ struct mmc_data *data = cmd->data;
-+
-+ WARN_ON(host->data);
-+
-+ if (data || (cmd->flags & MMC_RSP_BUSY)) {
-+ count = TIMEOUT_VAL;
-+ bcm2835_mmc_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
-+ }
-+
-+ if (!data)
-+ return;
-+
-+ /* Sanity checks */
-+ BUG_ON(data->blksz * data->blocks > 524288);
-+ BUG_ON(data->blksz > host->mmc->max_blk_size);
-+ BUG_ON(data->blocks > 65535);
-+
-+ host->data = data;
-+ host->data_early = 0;
-+ host->data->bytes_xfered = 0;
-+
-+
-+ if (!(host->flags & SDHCI_REQ_USE_DMA)) {
-+ int flags;
-+
-+ flags = SG_MITER_ATOMIC;
-+ if (host->data->flags & MMC_DATA_READ)
-+ flags |= SG_MITER_TO_SG;
-+ else
-+ flags |= SG_MITER_FROM_SG;
-+ sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
-+ host->blocks = data->blocks;
-+ }
-+
-+ host->use_dma = host->have_dma && data->blocks > PIO_DMA_BARRIER;
-+
-+ bcm2835_mmc_set_transfer_irqs(host);
-+
-+ /* Set the DMA boundary value and block size */
-+ bcm2835_mmc_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG,
-+ data->blksz), SDHCI_BLOCK_SIZE);
-+ bcm2835_mmc_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
-+
-+ BUG_ON(!host->data);
-+}
-+
-+static void bcm2835_mmc_set_transfer_mode(struct bcm2835_host *host,
-+ struct mmc_command *cmd)
-+{
-+ u16 mode;
-+ struct mmc_data *data = cmd->data;
-+
-+ if (data == NULL) {
-+ /* clear Auto CMD settings for no data CMDs */
-+ mode = bcm2835_mmc_readw(host, SDHCI_TRANSFER_MODE);
-+ bcm2835_mmc_writew(host, mode & ~(SDHCI_TRNS_AUTO_CMD12 |
-+ SDHCI_TRNS_AUTO_CMD23), SDHCI_TRANSFER_MODE);
-+ return;
-+ }
-+
-+ WARN_ON(!host->data);
-+
-+ mode = SDHCI_TRNS_BLK_CNT_EN;
-+
-+ if ((mmc_op_multi(cmd->opcode) || data->blocks > 1)) {
-+ mode |= SDHCI_TRNS_MULTI;
-+
-+ /*
-+ * If we are sending CMD23, CMD12 never gets sent
-+ * on successful completion (so no Auto-CMD12).
-+ */
-+ if (!host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD12))
-+ mode |= SDHCI_TRNS_AUTO_CMD12;
-+ else if (host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) {
-+ mode |= SDHCI_TRNS_AUTO_CMD23;
-+ bcm2835_mmc_writel(host, host->mrq->sbc->arg, SDHCI_ARGUMENT2, 5);
-+ }
-+ }
-+
-+ if (data->flags & MMC_DATA_READ)
-+ mode |= SDHCI_TRNS_READ;
-+ if (host->flags & SDHCI_REQ_USE_DMA)
-+ mode |= SDHCI_TRNS_DMA;
-+
-+ bcm2835_mmc_writew(host, mode, SDHCI_TRANSFER_MODE);
-+}
-+
-+void bcm2835_mmc_send_command(struct bcm2835_host *host, struct mmc_command *cmd)
-+{
-+ int flags;
-+ u32 mask;
-+ unsigned long timeout;
-+
-+ WARN_ON(host->cmd);
-+
-+ /* Wait max 10 ms */
-+ timeout = 1000;
-+
-+ mask = SDHCI_CMD_INHIBIT;
-+ if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY))
-+ mask |= SDHCI_DATA_INHIBIT;
-+
-+ /* We shouldn't wait for data inihibit for stop commands, even
-+ though they might use busy signaling */
-+ if (host->mrq->data && (cmd == host->mrq->data->stop))
-+ mask &= ~SDHCI_DATA_INHIBIT;
-+
-+ while (bcm2835_mmc_readl(host, SDHCI_PRESENT_STATE) & mask) {
-+ if (timeout == 0) {
-+ pr_err("%s: Controller never released inhibit bit(s).\n",
-+ mmc_hostname(host->mmc));
-+ bcm2835_mmc_dumpregs(host);
-+ cmd->error = -EIO;
-+ tasklet_schedule(&host->finish_tasklet);
-+ return;
-+ }
-+ timeout--;
-+ udelay(10);
-+ }
-+
-+ if ((1000-timeout)/100 > 1 && (1000-timeout)/100 > host->max_delay) {
-+ host->max_delay = (1000-timeout)/100;
-+ pr_warning("Warning: MMC controller hung for %d ms\n", host->max_delay);
-+ }
-+
-+ timeout = jiffies;
-+ if (!cmd->data && cmd->busy_timeout > 9000)
-+ timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
-+ else
-+ timeout += 10 * HZ;
-+ mod_timer(&host->timer, timeout);
-+
-+ host->cmd = cmd;
-+
-+ bcm2835_mmc_prepare_data(host, cmd);
-+
-+ bcm2835_mmc_writel(host, cmd->arg, SDHCI_ARGUMENT, 6);
-+
-+ bcm2835_mmc_set_transfer_mode(host, cmd);
-+
-+ if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
-+ pr_err("%s: Unsupported response type!\n",
-+ mmc_hostname(host->mmc));
-+ cmd->error = -EINVAL;
-+ tasklet_schedule(&host->finish_tasklet);
-+ return;
-+ }
-+
-+ if (!(cmd->flags & MMC_RSP_PRESENT))
-+ flags = SDHCI_CMD_RESP_NONE;
-+ else if (cmd->flags & MMC_RSP_136)
-+ flags = SDHCI_CMD_RESP_LONG;
-+ else if (cmd->flags & MMC_RSP_BUSY)
-+ flags = SDHCI_CMD_RESP_SHORT_BUSY;
-+ else
-+ flags = SDHCI_CMD_RESP_SHORT;
-+
-+ if (cmd->flags & MMC_RSP_CRC)
-+ flags |= SDHCI_CMD_CRC;
-+ if (cmd->flags & MMC_RSP_OPCODE)
-+ flags |= SDHCI_CMD_INDEX;
-+
-+ if (cmd->data)
-+ flags |= SDHCI_CMD_DATA;
-+
-+ bcm2835_mmc_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
-+}
-+
-+
-+static void bcm2835_mmc_finish_data(struct bcm2835_host *host)
-+{
-+ struct mmc_data *data;
-+
-+ BUG_ON(!host->data);
-+
-+ data = host->data;
-+ host->data = NULL;
-+
-+ if (data->error)
-+ data->bytes_xfered = 0;
-+ else
-+ data->bytes_xfered = data->blksz * data->blocks;
-+
-+ /*
-+ * Need to send CMD12 if -
-+ * a) open-ended multiblock transfer (no CMD23)
-+ * b) error in multiblock transfer
-+ */
-+ if (data->stop &&
-+ (data->error ||
-+ !host->mrq->sbc)) {
-+
-+ /*
-+ * The controller needs a reset of internal state machines
-+ * upon error conditions.
-+ */
-+ if (data->error) {
-+ bcm2835_mmc_reset(host, SDHCI_RESET_CMD);
-+ bcm2835_mmc_reset(host, SDHCI_RESET_DATA);
-+ }
-+
-+ bcm2835_mmc_send_command(host, data->stop);
-+ } else
-+ tasklet_schedule(&host->finish_tasklet);
-+}
-+
-+static void bcm2835_mmc_finish_command(struct bcm2835_host *host)
-+{
-+ int i;
-+
-+ BUG_ON(host->cmd == NULL);
-+
-+ if (host->cmd->flags & MMC_RSP_PRESENT) {
-+ if (host->cmd->flags & MMC_RSP_136) {
-+ /* CRC is stripped so we need to do some shifting. */
-+ for (i = 0; i < 4; i++) {
-+ host->cmd->resp[i] = bcm2835_mmc_readl(host,
-+ SDHCI_RESPONSE + (3-i)*4) << 8;
-+ if (i != 3)
-+ host->cmd->resp[i] |=
-+ bcm2835_mmc_readb(host,
-+ SDHCI_RESPONSE + (3-i)*4-1);
-+ }
-+ } else {
-+ host->cmd->resp[0] = bcm2835_mmc_readl(host, SDHCI_RESPONSE);
-+ }
-+ }
-+
-+ host->cmd->error = 0;
-+
-+ /* Finished CMD23, now send actual command. */
-+ if (host->cmd == host->mrq->sbc) {
-+ host->cmd = NULL;
-+ bcm2835_mmc_send_command(host, host->mrq->cmd);
-+
-+ if (host->mrq->cmd->data && host->use_dma) {
-+ /* DMA transfer starts now, PIO starts after interrupt */
-+ bcm2835_mmc_transfer_dma(host);
-+ }
-+ } else {
-+
-+ /* Processed actual command. */
-+ if (host->data && host->data_early)
-+ bcm2835_mmc_finish_data(host);
-+
-+ if (!host->cmd->data)
-+ tasklet_schedule(&host->finish_tasklet);
-+
-+ host->cmd = NULL;
-+ }
-+}
-+
-+
-+static void bcm2835_mmc_timeout_timer(unsigned long data)
-+{
-+ struct bcm2835_host *host;
-+ unsigned long flags;
-+
-+ host = (struct bcm2835_host *)data;
-+
-+ spin_lock_irqsave(&host->lock, flags);
-+
-+ if (host->mrq) {
-+ pr_err("%s: Timeout waiting for hardware interrupt.\n",
-+ mmc_hostname(host->mmc));
-+ bcm2835_mmc_dumpregs(host);
-+
-+ if (host->data) {
-+ host->data->error = -ETIMEDOUT;
-+ bcm2835_mmc_finish_data(host);
-+ } else {
-+ if (host->cmd)
-+ host->cmd->error = -ETIMEDOUT;
-+ else
-+ host->mrq->cmd->error = -ETIMEDOUT;
-+
-+ tasklet_schedule(&host->finish_tasklet);
-+ }
-+ }
-+
-+ mmiowb();
-+ spin_unlock_irqrestore(&host->lock, flags);
-+}
-+
-+
-+static void bcm2835_mmc_enable_sdio_irq_nolock(struct bcm2835_host *host, int enable)
-+{
-+ if (!(host->flags & SDHCI_DEVICE_DEAD)) {
-+ if (enable)
-+ host->ier |= SDHCI_INT_CARD_INT;
-+ else
-+ host->ier &= ~SDHCI_INT_CARD_INT;
-+
-+ bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 7);
-+ bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 7);
-+ mmiowb();
-+ }
-+}
-+
-+static void bcm2835_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
-+{
-+ struct bcm2835_host *host = mmc_priv(mmc);
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&host->lock, flags);
-+ if (enable)
-+ host->flags |= SDHCI_SDIO_IRQ_ENABLED;
-+ else
-+ host->flags &= ~SDHCI_SDIO_IRQ_ENABLED;
-+
-+ bcm2835_mmc_enable_sdio_irq_nolock(host, enable);
-+ spin_unlock_irqrestore(&host->lock, flags);
-+}
-+
-+static void bcm2835_mmc_cmd_irq(struct bcm2835_host *host, u32 intmask)
-+{
-+
-+ BUG_ON(intmask == 0);
-+
-+ if (!host->cmd) {
-+ pr_err("%s: Got command interrupt 0x%08x even "
-+ "though no command operation was in progress.\n",
-+ mmc_hostname(host->mmc), (unsigned)intmask);
-+ bcm2835_mmc_dumpregs(host);
-+ return;
-+ }
-+
-+ if (intmask & SDHCI_INT_TIMEOUT)
-+ host->cmd->error = -ETIMEDOUT;
-+ else if (intmask & (SDHCI_INT_CRC | SDHCI_INT_END_BIT |
-+ SDHCI_INT_INDEX)) {
-+ host->cmd->error = -EILSEQ;
-+ }
-+
-+ if (host->cmd->error) {
-+ tasklet_schedule(&host->finish_tasklet);
-+ return;
-+ }
-+
-+ if (intmask & SDHCI_INT_RESPONSE)
-+ bcm2835_mmc_finish_command(host);
-+
-+}
-+
-+static void bcm2835_mmc_data_irq(struct bcm2835_host *host, u32 intmask)
-+{
-+ struct dma_chan *dma_chan;
-+ u32 dir_data;
-+
-+ BUG_ON(intmask == 0);
-+
-+ if (!host->data) {
-+ /*
-+ * The "data complete" interrupt is also used to
-+ * indicate that a busy state has ended. See comment
-+ * above in sdhci_cmd_irq().
-+ */
-+ if (host->cmd && (host->cmd->flags & MMC_RSP_BUSY)) {
-+ if (intmask & SDHCI_INT_DATA_END) {
-+ bcm2835_mmc_finish_command(host);
-+ return;
-+ }
-+ }
-+
-+ pr_debug("%s: Got data interrupt 0x%08x even "
-+ "though no data operation was in progress.\n",
-+ mmc_hostname(host->mmc), (unsigned)intmask);
-+ bcm2835_mmc_dumpregs(host);
-+
-+ return;
-+ }
-+
-+ if (intmask & SDHCI_INT_DATA_TIMEOUT)
-+ host->data->error = -ETIMEDOUT;
-+ else if (intmask & SDHCI_INT_DATA_END_BIT)
-+ host->data->error = -EILSEQ;
-+ else if ((intmask & SDHCI_INT_DATA_CRC) &&
-+ SDHCI_GET_CMD(bcm2835_mmc_readw(host, SDHCI_COMMAND))
-+ != MMC_BUS_TEST_R)
-+ host->data->error = -EILSEQ;
-+
-+ if (host->use_dma) {
-+ if (host->data->flags & MMC_DATA_WRITE) {
-+ /* IRQ handled here */
-+
-+ dma_chan = host->dma_chan_tx;
-+ dir_data = DMA_TO_DEVICE;
-+ dma_unmap_sg(dma_chan->device->dev,
-+ host->data->sg, host->data->sg_len,
-+ dir_data);
-+
-+ bcm2835_mmc_finish_data(host);
-+ }
-+
-+ } else {
-+ if (host->data->error)
-+ bcm2835_mmc_finish_data(host);
-+ else {
-+ if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL))
-+ bcm2835_mmc_transfer_pio(host);
-+
-+ if (intmask & SDHCI_INT_DATA_END) {
-+ if (host->cmd) {
-+ /*
-+ * Data managed to finish before the
-+ * command completed. Make sure we do
-+ * things in the proper order.
-+ */
-+ host->data_early = 1;
-+ } else {
-+ bcm2835_mmc_finish_data(host);
-+ }
-+ }
-+ }
-+ }
-+}
-+
-+
-+static irqreturn_t bcm2835_mmc_irq(int irq, void *dev_id)
-+{
-+ irqreturn_t result = IRQ_NONE;
-+ struct bcm2835_host *host = dev_id;
-+ u32 intmask, mask, unexpected = 0;
-+ int max_loops = 16;
-+
-+ spin_lock(&host->lock);
-+
-+ intmask = bcm2835_mmc_readl(host, SDHCI_INT_STATUS);
-+
-+ if (!intmask || intmask == 0xffffffff) {
-+ result = IRQ_NONE;
-+ goto out;
-+ }
-+
-+ do {
-+ /* Clear selected interrupts. */
-+ mask = intmask & (SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK |
-+ SDHCI_INT_BUS_POWER);
-+ bcm2835_mmc_writel(host, mask, SDHCI_INT_STATUS, 8);
-+
-+
-+ if (intmask & SDHCI_INT_CMD_MASK)
-+ bcm2835_mmc_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
-+
-+ if (intmask & SDHCI_INT_DATA_MASK)
-+ bcm2835_mmc_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
-+
-+ if (intmask & SDHCI_INT_BUS_POWER)
-+ pr_err("%s: Card is consuming too much power!\n",
-+ mmc_hostname(host->mmc));
-+
-+ if (intmask & SDHCI_INT_CARD_INT) {
-+ bcm2835_mmc_enable_sdio_irq_nolock(host, false);
-+ host->thread_isr |= SDHCI_INT_CARD_INT;
-+ result = IRQ_WAKE_THREAD;
-+ }
-+
-+ intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE |
-+ SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK |
-+ SDHCI_INT_ERROR | SDHCI_INT_BUS_POWER |
-+ SDHCI_INT_CARD_INT);
-+
-+ if (intmask) {
-+ unexpected |= intmask;
-+ bcm2835_mmc_writel(host, intmask, SDHCI_INT_STATUS, 9);
-+ }
-+
-+ if (result == IRQ_NONE)
-+ result = IRQ_HANDLED;
-+
-+ intmask = bcm2835_mmc_readl(host, SDHCI_INT_STATUS);
-+ } while (intmask && --max_loops);
-+out:
-+ spin_unlock(&host->lock);
-+
-+ if (unexpected) {
-+ pr_err("%s: Unexpected interrupt 0x%08x.\n",
-+ mmc_hostname(host->mmc), unexpected);
-+ bcm2835_mmc_dumpregs(host);
-+ }
-+
-+ return result;
-+}
-+
-+static irqreturn_t bcm2835_mmc_thread_irq(int irq, void *dev_id)
-+{
-+ struct bcm2835_host *host = dev_id;
-+ unsigned long flags;
-+ u32 isr;
-+
-+ spin_lock_irqsave(&host->lock, flags);
-+ isr = host->thread_isr;
-+ host->thread_isr = 0;
-+ spin_unlock_irqrestore(&host->lock, flags);
-+
-+ if (isr & SDHCI_INT_CARD_INT) {
-+ sdio_run_irqs(host->mmc);
-+
-+ spin_lock_irqsave(&host->lock, flags);
-+ if (host->flags & SDHCI_SDIO_IRQ_ENABLED)
-+ bcm2835_mmc_enable_sdio_irq_nolock(host, true);
-+ spin_unlock_irqrestore(&host->lock, flags);
-+ }
-+
-+ return isr ? IRQ_HANDLED : IRQ_NONE;
-+}
-+
-+
-+
-+void bcm2835_mmc_set_clock(struct bcm2835_host *host, unsigned int clock)
-+{
-+ int div = 0; /* Initialized for compiler warning */
-+ int real_div = div, clk_mul = 1;
-+ u16 clk = 0;
-+ unsigned long timeout;
-+ unsigned int input_clock = clock;
-+
-+ if (host->overclock_50 && (clock == 50000000))
-+ clock = host->overclock_50 * 1000000 + 999999;
-+
-+ host->mmc->actual_clock = 0;
-+
-+ bcm2835_mmc_writew(host, 0, SDHCI_CLOCK_CONTROL);
-+
-+ if (clock == 0)
-+ return;
-+
-+ /* Version 3.00 divisors must be a multiple of 2. */
-+ if (host->max_clk <= clock)
-+ div = 1;
-+ else {
-+ for (div = 2; div < SDHCI_MAX_DIV_SPEC_300;
-+ div += 2) {
-+ if ((host->max_clk / div) <= clock)
-+ break;
-+ }
-+ }
-+
-+ real_div = div;
-+ div >>= 1;
-+
-+ if (real_div)
-+ clock = (host->max_clk * clk_mul) / real_div;
-+ host->mmc->actual_clock = clock;
-+
-+ if ((clock > input_clock) && (clock > host->max_overclock)) {
-+ pr_warn("%s: Overclocking to %dHz\n",
-+ mmc_hostname(host->mmc), clock);
-+ host->max_overclock = clock;
-+ }
-+
-+ clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
-+ clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
-+ << SDHCI_DIVIDER_HI_SHIFT;
-+ clk |= SDHCI_CLOCK_INT_EN;
-+ bcm2835_mmc_writew(host, clk, SDHCI_CLOCK_CONTROL);
-+
-+ /* Wait max 20 ms */
-+ timeout = 20;
-+ while (!((clk = bcm2835_mmc_readw(host, SDHCI_CLOCK_CONTROL))
-+ & SDHCI_CLOCK_INT_STABLE)) {
-+ if (timeout == 0) {
-+ pr_err("%s: Internal clock never "
-+ "stabilised.\n", mmc_hostname(host->mmc));
-+ bcm2835_mmc_dumpregs(host);
-+ return;
-+ }
-+ timeout--;
-+ mdelay(1);
-+ }
-+
-+ if (20-timeout > 10 && 20-timeout > host->max_delay) {
-+ host->max_delay = 20-timeout;
-+ pr_warning("Warning: MMC controller hung for %d ms\n", host->max_delay);
-+ }
-+
-+ clk |= SDHCI_CLOCK_CARD_EN;
-+ bcm2835_mmc_writew(host, clk, SDHCI_CLOCK_CONTROL);
-+}
-+
-+static void bcm2835_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
-+{
-+ struct bcm2835_host *host;
-+ unsigned long flags;
-+
-+ host = mmc_priv(mmc);
-+
-+ spin_lock_irqsave(&host->lock, flags);
-+
-+ WARN_ON(host->mrq != NULL);
-+
-+ host->mrq = mrq;
-+
-+ if (mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23))
-+ bcm2835_mmc_send_command(host, mrq->sbc);
-+ else
-+ bcm2835_mmc_send_command(host, mrq->cmd);
-+
-+ mmiowb();
-+ spin_unlock_irqrestore(&host->lock, flags);
-+
-+ if (!(mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23)) && mrq->cmd->data && host->use_dma) {
-+ /* DMA transfer starts now, PIO starts after interrupt */
-+ bcm2835_mmc_transfer_dma(host);
-+ }
-+}
-+
-+
-+static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-+{
-+
-+ struct bcm2835_host *host = mmc_priv(mmc);
-+ unsigned long flags;
-+ u8 ctrl;
-+ u16 clk, ctrl_2;
-+
-+ pr_debug("bcm2835_mmc_set_ios: clock %d, pwr %d, bus_width %d, timing %d, vdd %d, drv_type %d\n",
-+ ios->clock, ios->power_mode, ios->bus_width,
-+ ios->timing, ios->signal_voltage, ios->drv_type);
-+
-+ spin_lock_irqsave(&host->lock, flags);
-+
-+ if (!ios->clock || ios->clock != host->clock) {
-+ bcm2835_mmc_set_clock(host, ios->clock);
-+ host->clock = ios->clock;
-+ }
-+
-+ if (host->pwr != SDHCI_POWER_330) {
-+ host->pwr = SDHCI_POWER_330;
-+ bcm2835_mmc_writeb(host, SDHCI_POWER_330 | SDHCI_POWER_ON, SDHCI_POWER_CONTROL);
-+ }
-+
-+ ctrl = bcm2835_mmc_readb(host, SDHCI_HOST_CONTROL);
-+
-+ /* set bus width */
-+ ctrl &= ~SDHCI_CTRL_8BITBUS;
-+ if (ios->bus_width == MMC_BUS_WIDTH_4)
-+ ctrl |= SDHCI_CTRL_4BITBUS;
-+ else
-+ ctrl &= ~SDHCI_CTRL_4BITBUS;
-+
-+ ctrl &= ~SDHCI_CTRL_HISPD; /* NO_HISPD_BIT */
-+
-+
-+ bcm2835_mmc_writeb(host, ctrl, SDHCI_HOST_CONTROL);
-+ /*
-+ * We only need to set Driver Strength if the
-+ * preset value enable is not set.
-+ */
-+ ctrl_2 = bcm2835_mmc_readw(host, SDHCI_HOST_CONTROL2);
-+ ctrl_2 &= ~SDHCI_CTRL_DRV_TYPE_MASK;
-+ if (ios->drv_type == MMC_SET_DRIVER_TYPE_A)
-+ ctrl_2 |= SDHCI_CTRL_DRV_TYPE_A;
-+ else if (ios->drv_type == MMC_SET_DRIVER_TYPE_C)
-+ ctrl_2 |= SDHCI_CTRL_DRV_TYPE_C;
-+
-+ bcm2835_mmc_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
-+
-+ /* Reset SD Clock Enable */
-+ clk = bcm2835_mmc_readw(host, SDHCI_CLOCK_CONTROL);
-+ clk &= ~SDHCI_CLOCK_CARD_EN;
-+ bcm2835_mmc_writew(host, clk, SDHCI_CLOCK_CONTROL);
-+
-+ /* Re-enable SD Clock */
-+ bcm2835_mmc_set_clock(host, host->clock);
-+ bcm2835_mmc_writeb(host, ctrl, SDHCI_HOST_CONTROL);
-+
-+ mmiowb();
-+
-+ spin_unlock_irqrestore(&host->lock, flags);
-+}
-+
-+
-+static struct mmc_host_ops bcm2835_ops = {
-+ .request = bcm2835_mmc_request,
-+ .set_ios = bcm2835_mmc_set_ios,
-+ .enable_sdio_irq = bcm2835_mmc_enable_sdio_irq,
-+};
-+
-+
-+static void bcm2835_mmc_tasklet_finish(unsigned long param)
-+{
-+ struct bcm2835_host *host;
-+ unsigned long flags;
-+ struct mmc_request *mrq;
-+
-+ host = (struct bcm2835_host *)param;
-+
-+ spin_lock_irqsave(&host->lock, flags);
-+
-+ /*
-+ * If this tasklet gets rescheduled while running, it will
-+ * be run again afterwards but without any active request.
-+ */
-+ if (!host->mrq) {
-+ spin_unlock_irqrestore(&host->lock, flags);
-+ return;
-+ }
-+
-+ del_timer(&host->timer);
-+
-+ mrq = host->mrq;
-+
-+ /*
-+ * The controller needs a reset of internal state machines
-+ * upon error conditions.
-+ */
-+ if (!(host->flags & SDHCI_DEVICE_DEAD) &&
-+ ((mrq->cmd && mrq->cmd->error) ||
-+ (mrq->data && (mrq->data->error ||
-+ (mrq->data->stop && mrq->data->stop->error))))) {
-+
-+ spin_unlock_irqrestore(&host->lock, flags);
-+ bcm2835_mmc_reset(host, SDHCI_RESET_CMD);
-+ bcm2835_mmc_reset(host, SDHCI_RESET_DATA);
-+ spin_lock_irqsave(&host->lock, flags);
-+ }
-+
-+ host->mrq = NULL;
-+ host->cmd = NULL;
-+ host->data = NULL;
-+
-+ mmiowb();
-+
-+ spin_unlock_irqrestore(&host->lock, flags);
-+ mmc_request_done(host->mmc, mrq);
-+}
-+
-+
-+
-+static int bcm2835_mmc_add_host(struct bcm2835_host *host)
-+{
-+ struct mmc_host *mmc = host->mmc;
-+ struct device *dev = mmc->parent;
-+#ifndef FORCE_PIO
-+ struct dma_slave_config cfg;
-+#endif
-+ int ret;
-+
-+ bcm2835_mmc_reset(host, SDHCI_RESET_ALL);
-+
-+ host->clk_mul = 0;
-+
-+ mmc->f_max = host->max_clk;
-+ mmc->f_max = host->max_clk;
-+ mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300;
-+
-+ /* SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK */
-+ host->timeout_clk = mmc->f_max / 1000;
-+ mmc->max_busy_timeout = (1 << 27) / host->timeout_clk;
-+
-+ /* host controller capabilities */
-+ mmc->caps |= MMC_CAP_CMD23 | MMC_CAP_ERASE | MMC_CAP_NEEDS_POLL |
-+ MMC_CAP_SDIO_IRQ | MMC_CAP_SD_HIGHSPEED |
-+ MMC_CAP_MMC_HIGHSPEED | MMC_CAP_4_BIT_DATA;
-+
-+ mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
-+
-+ host->flags = SDHCI_AUTO_CMD23;
-+
-+ dev_info(dev, "mmc_debug:%x mmc_debug2:%x\n", mmc_debug, mmc_debug2);
-+#ifdef FORCE_PIO
-+ dev_info(dev, "Forcing PIO mode\n");
-+ host->have_dma = false;
-+#else
-+ if (IS_ERR_OR_NULL(host->dma_chan_tx) ||
-+ IS_ERR_OR_NULL(host->dma_chan_rx)) {
-+ dev_err(dev, "%s: Unable to initialise DMA channels. Falling back to PIO\n",
-+ DRIVER_NAME);
-+ host->have_dma = false;
-+ } else {
-+ dev_info(dev, "DMA channels allocated");
-+ host->have_dma = true;
-+
-+ cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-+ cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-+ cfg.slave_id = 11; /* DREQ channel */
-+
-+ cfg.direction = DMA_MEM_TO_DEV;
-+ cfg.src_addr = 0;
-+ cfg.dst_addr = host->bus_addr + SDHCI_BUFFER;
-+ ret = dmaengine_slave_config(host->dma_chan_tx, &cfg);
-+
-+ cfg.direction = DMA_DEV_TO_MEM;
-+ cfg.src_addr = host->bus_addr + SDHCI_BUFFER;
-+ cfg.dst_addr = 0;
-+ ret = dmaengine_slave_config(host->dma_chan_rx, &cfg);
-+ }
-+#endif
-+ mmc->max_segs = 128;
-+ mmc->max_req_size = 524288;
-+ mmc->max_seg_size = mmc->max_req_size;
-+ mmc->max_blk_size = 512;
-+ mmc->max_blk_count = 65535;
-+
-+ /* report supported voltage ranges */
-+ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
-+
-+ tasklet_init(&host->finish_tasklet,
-+ bcm2835_mmc_tasklet_finish, (unsigned long)host);
-+
-+ setup_timer(&host->timer, bcm2835_mmc_timeout_timer, (unsigned long)host);
-+ init_waitqueue_head(&host->buf_ready_int);
-+
-+ bcm2835_mmc_init(host, 0);
-+ ret = devm_request_threaded_irq(dev, host->irq, bcm2835_mmc_irq,
-+ bcm2835_mmc_thread_irq, IRQF_SHARED,
-+ mmc_hostname(mmc), host);
-+ if (ret) {
-+ dev_err(dev, "Failed to request IRQ %d: %d\n", host->irq, ret);
-+ goto untasklet;
-+ }
-+
-+ mmiowb();
-+ mmc_add_host(mmc);
-+
-+ return 0;
-+
-+untasklet:
-+ tasklet_kill(&host->finish_tasklet);
-+
-+ return ret;
-+}
-+
-+static int bcm2835_mmc_probe(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ struct device_node *node = dev->of_node;
-+ struct clk *clk;
-+ struct resource *iomem;
-+ struct bcm2835_host *host;
-+ struct mmc_host *mmc;
-+ const __be32 *addr;
-+ int ret;
-+
-+ mmc = mmc_alloc_host(sizeof(*host), dev);
-+ if (!mmc)
-+ return -ENOMEM;
-+
-+ mmc->ops = &bcm2835_ops;
-+ host = mmc_priv(mmc);
-+ host->mmc = mmc;
-+ host->timeout = msecs_to_jiffies(1000);
-+ spin_lock_init(&host->lock);
-+
-+ iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ host->ioaddr = devm_ioremap_resource(dev, iomem);
-+ if (IS_ERR(host->ioaddr)) {
-+ ret = PTR_ERR(host->ioaddr);
-+ goto err;
-+ }
-+
-+ addr = of_get_address(node, 0, NULL, NULL);
-+ if (!addr) {
-+ dev_err(dev, "could not get DMA-register address\n");
-+ return -ENODEV;
-+ }
-+ host->bus_addr = be32_to_cpup(addr);
-+ pr_debug(" - ioaddr %lx, iomem->start %lx, bus_addr %lx\n",
-+ (unsigned long)host->ioaddr,
-+ (unsigned long)iomem->start,
-+ (unsigned long)host->bus_addr);
-+
-+#ifndef FORCE_PIO
-+ if (node) {
-+ host->dma_chan_tx = dma_request_slave_channel(dev, "tx");
-+ host->dma_chan_rx = dma_request_slave_channel(dev, "rx");
-+ } else {
-+ dma_cap_mask_t mask;
-+
-+ dma_cap_zero(mask);
-+ /* we don't care about the channel, any would work */
-+ dma_cap_set(DMA_SLAVE, mask);
-+ host->dma_chan_tx = dma_request_channel(mask, NULL, NULL);
-+ host->dma_chan_rx = dma_request_channel(mask, NULL, NULL);
-+ }
-+#endif
-+ clk = devm_clk_get(dev, NULL);
-+ if (IS_ERR(clk)) {
-+ dev_err(dev, "could not get clk\n");
-+ ret = PTR_ERR(clk);
-+ goto err;
-+ }
-+
-+ host->max_clk = clk_get_rate(clk);
-+
-+ host->irq = platform_get_irq(pdev, 0);
-+ if (host->irq <= 0) {
-+ dev_err(dev, "get IRQ failed\n");
-+ ret = -EINVAL;
-+ goto err;
-+ }
-+
-+ if (node) {
-+ mmc_of_parse(mmc);
-+
-+ /* Read any custom properties */
-+ of_property_read_u32(node,
-+ "brcm,overclock-50",
-+ &host->overclock_50);
-+ } else {
-+ mmc->caps |= MMC_CAP_4_BIT_DATA;
-+ }
-+
-+ ret = bcm2835_mmc_add_host(host);
-+ if (ret)
-+ goto err;
-+
-+ platform_set_drvdata(pdev, host);
-+
-+ return 0;
-+err:
-+ mmc_free_host(mmc);
-+
-+ return ret;
-+}
-+
-+static int bcm2835_mmc_remove(struct platform_device *pdev)
-+{
-+ struct bcm2835_host *host = platform_get_drvdata(pdev);
-+ unsigned long flags;
-+ int dead;
-+ u32 scratch;
-+
-+ dead = 0;
-+ scratch = bcm2835_mmc_readl(host, SDHCI_INT_STATUS);
-+ if (scratch == (u32)-1)
-+ dead = 1;
-+
-+
-+ if (dead) {
-+ spin_lock_irqsave(&host->lock, flags);
-+
-+ host->flags |= SDHCI_DEVICE_DEAD;
-+
-+ if (host->mrq) {
-+ pr_err("%s: Controller removed during "
-+ " transfer!\n", mmc_hostname(host->mmc));
-+
-+ host->mrq->cmd->error = -ENOMEDIUM;
-+ tasklet_schedule(&host->finish_tasklet);
-+ }
-+
-+ spin_unlock_irqrestore(&host->lock, flags);
-+ }
-+
-+ mmc_remove_host(host->mmc);
-+
-+ if (!dead)
-+ bcm2835_mmc_reset(host, SDHCI_RESET_ALL);
-+
-+ free_irq(host->irq, host);
-+
-+ del_timer_sync(&host->timer);
-+
-+ tasklet_kill(&host->finish_tasklet);
-+
-+ mmc_free_host(host->mmc);
-+ platform_set_drvdata(pdev, NULL);
-+
-+ return 0;
-+}
-+
-+
-+static const struct of_device_id bcm2835_mmc_match[] = {
-+ { .compatible = "brcm,bcm2835-mmc" },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(of, bcm2835_mmc_match);
-+
-+
-+
-+static struct platform_driver bcm2835_mmc_driver = {
-+ .probe = bcm2835_mmc_probe,
-+ .remove = bcm2835_mmc_remove,
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ .of_match_table = bcm2835_mmc_match,
-+ },
-+};
-+module_platform_driver(bcm2835_mmc_driver);
-+
-+module_param(mmc_debug, uint, 0644);
-+module_param(mmc_debug2, uint, 0644);
-+MODULE_ALIAS("platform:mmc-bcm2835");
-+MODULE_DESCRIPTION("BCM2835 SDHCI driver");
-+MODULE_LICENSE("GPL v2");
-+MODULE_AUTHOR("Gellert Weisz");
diff --git a/target/linux/brcm2708/patches-4.4/0034-Adding-bcm2835-sdhost-driver-and-an-overlay-to-enabl.patch b/target/linux/brcm2708/patches-4.4/0034-Adding-bcm2835-sdhost-driver-and-an-overlay-to-enabl.patch
deleted file mode 100644
index c6631e8b4e..0000000000
--- a/target/linux/brcm2708/patches-4.4/0034-Adding-bcm2835-sdhost-driver-and-an-overlay-to-enabl.patch
+++ /dev/null
@@ -1,2022 +0,0 @@
-From 756bf8b8f081be45e16d4d58d3fbe2ca073df298 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Wed, 25 Mar 2015 17:49:47 +0000
-Subject: [PATCH 034/170] Adding bcm2835-sdhost driver, and an overlay to
- enable it
-
-BCM2835 has two SD card interfaces. This driver uses the other one.
-
-bcm2835-sdhost: Error handling fix, and code clarification
-
-bcm2835-sdhost: Adding overclocking option
-
-Allow a different clock speed to be substitued for a requested 50MHz.
-This option is exposed using the "overclock_50" DT parameter.
-Note that the sdhost interface is restricted to integer divisions of
-core_freq, and the highest sensible option for a core_freq of 250MHz
-is 84 (250/3 = 83.3MHz), the next being 125 (250/2) which is much too
-high.
-
-Use at your own risk.
-
-bcm2835-sdhost: Round up the overclock, so 62 works for 62.5Mhz
-
-Also only warn once for each overclock setting.
-
-bcm2835-sdhost: Improve error handling and recovery
-
-1) Expose the hw_reset method to the MMC framework, removing many
- internal calls by the driver.
-
-2) Reduce overclock setting on error.
-
-3) Increase timeout to cope with high capacity cards.
-
-4) Add properties and parameters to control pio_limit and debug.
-
-5) Reduce messages at probe time.
-
-bcm2835-sdhost: Further improve overclock back-off
-
-bcm2835-sdhost: Clear HBLC for PIO mode
-
-Also update pio_limit default in overlay README.
-
-bcm2835-sdhost: Add the ERASE capability
-
-See: https://github.com/raspberrypi/linux/issues/1076
-
-bcm2835-sdhost: Ignore CRC7 for MMC CMD1
-
-It seems that the sdhost interface returns CRC7 errors for CMD1,
-which is the MMC-specific SEND_OP_COND. Returning these errors to
-the MMC layer causes a downward spiral, but ignoring them seems
-to be harmless.
-
-bcm2835-mmc/sdhost: Remove ARCH_BCM2835 differences
-
-The bcm2835-mmc driver (and -sdhost driver that copied from it)
-contains code to handle SDIO interrupts in a threaded interrupt
-handler rather than waking the MMC framework thread. The change
-follows a patch from Russell King that adds the facility as the
-preferred way of working.
-
-However, the new code path is only present in ARCH_BCM2835
-builds, which I have taken to be a way of testing the waters
-rather than making the change across the board; I can't see
-any technical reason why it wouldn't be enabled for MACH_BCM270X
-builds. So this patch standardises on the ARCH_BCM2835 code,
-removing the old code paths.
-
-bcm2835-sdhost: Don't log timeout errors unless debug=1
-
-The MMC card-discovery process generates timeouts. This is
-expected behaviour, so reporting it to the user serves no purpose.
-Suppress the reporting of timeout errors unless the debug flag
-is on.
----
- drivers/mmc/host/Kconfig | 10 +
- drivers/mmc/host/Makefile | 1 +
- drivers/mmc/host/bcm2835-sdhost.c | 1907 +++++++++++++++++++++++++++++++++++++
- 3 files changed, 1918 insertions(+)
- create mode 100644 drivers/mmc/host/bcm2835-sdhost.c
-
---- a/drivers/mmc/host/Kconfig
-+++ b/drivers/mmc/host/Kconfig
-@@ -33,6 +33,16 @@ config MMC_BCM2835_PIO_DMA_BARRIER
-
- If unsure, say 2 here.
-
-+config MMC_BCM2835_SDHOST
-+ tristate "Support for the SDHost controller on BCM2708/9"
-+ depends on MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835
-+ help
-+ This selects the SDHost controller on BCM2835/6.
-+
-+ If you have a controller with this interface, say Y or M here.
-+
-+ If unsure, say N.
-+
- config MMC_ARMMMCI
- tristate "ARM AMBA Multimedia Card Interface support"
- depends on ARM_AMBA
---- a/drivers/mmc/host/Makefile
-+++ b/drivers/mmc/host/Makefile
-@@ -18,6 +18,7 @@ obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c
- obj-$(CONFIG_MMC_SDHCI_SIRF) += sdhci-sirf.o
- obj-$(CONFIG_MMC_SDHCI_F_SDH30) += sdhci_f_sdh30.o
- obj-$(CONFIG_MMC_SDHCI_SPEAR) += sdhci-spear.o
-+obj-$(CONFIG_MMC_BCM2835_SDHOST) += bcm2835-sdhost.o
- obj-$(CONFIG_MMC_BCM2835) += bcm2835-mmc.o
- obj-$(CONFIG_MMC_WBSD) += wbsd.o
- obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
---- /dev/null
-+++ b/drivers/mmc/host/bcm2835-sdhost.c
-@@ -0,0 +1,1907 @@
-+/*
-+ * BCM2835 SD host driver.
-+ *
-+ * Author: Phil Elwell <phil@raspberrypi.org>
-+ * Copyright 2015
-+ *
-+ * Based on
-+ * mmc-bcm2835.c by Gellert Weisz
-+ * which is, in turn, based on
-+ * sdhci-bcm2708.c by Broadcom
-+ * sdhci-bcm2835.c by Stephen Warren and Oleksandr Tymoshenko
-+ * sdhci.c and sdhci-pci.c by Pierre Ossman
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms and conditions of the GNU General Public License,
-+ * version 2, as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope it will be useful, but WITHOUT
-+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
-+ * more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#define SAFE_READ_THRESHOLD 4
-+#define SAFE_WRITE_THRESHOLD 4
-+#define ALLOW_DMA 1
-+#define ALLOW_CMD23 0
-+#define ALLOW_FAST 1
-+#define USE_BLOCK_IRQ 1
-+
-+#include <linux/delay.h>
-+#include <linux/module.h>
-+#include <linux/io.h>
-+#include <linux/mmc/mmc.h>
-+#include <linux/mmc/host.h>
-+#include <linux/mmc/sd.h>
-+#include <linux/scatterlist.h>
-+#include <linux/of_address.h>
-+#include <linux/of_irq.h>
-+#include <linux/clk.h>
-+#include <linux/platform_device.h>
-+#include <linux/err.h>
-+#include <linux/blkdev.h>
-+#include <linux/dmaengine.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/of_dma.h>
-+#include <linux/time.h>
-+
-+#define DRIVER_NAME "sdhost-bcm2835"
-+
-+#define SDCMD 0x00 /* Command to SD card - 16 R/W */
-+#define SDARG 0x04 /* Argument to SD card - 32 R/W */
-+#define SDTOUT 0x08 /* Start value for timeout counter - 32 R/W */
-+#define SDCDIV 0x0c /* Start value for clock divider - 11 R/W */
-+#define SDRSP0 0x10 /* SD card response (31:0) - 32 R */
-+#define SDRSP1 0x14 /* SD card response (63:32) - 32 R */
-+#define SDRSP2 0x18 /* SD card response (95:64) - 32 R */
-+#define SDRSP3 0x1c /* SD card response (127:96) - 32 R */
-+#define SDHSTS 0x20 /* SD host status - 11 R */
-+#define SDVDD 0x30 /* SD card power control - 1 R/W */
-+#define SDEDM 0x34 /* Emergency Debug Mode - 13 R/W */
-+#define SDHCFG 0x38 /* Host configuration - 2 R/W */
-+#define SDHBCT 0x3c /* Host byte count (debug) - 32 R/W */
-+#define SDDATA 0x40 /* Data to/from SD card - 32 R/W */
-+#define SDHBLC 0x50 /* Host block count (SDIO/SDHC) - 9 R/W */
-+
-+#define SDCMD_NEW_FLAG 0x8000
-+#define SDCMD_FAIL_FLAG 0x4000
-+#define SDCMD_BUSYWAIT 0x800
-+#define SDCMD_NO_RESPONSE 0x400
-+#define SDCMD_LONG_RESPONSE 0x200
-+#define SDCMD_WRITE_CMD 0x80
-+#define SDCMD_READ_CMD 0x40
-+#define SDCMD_CMD_MASK 0x3f
-+
-+#define SDCDIV_MAX_CDIV 0x7ff
-+
-+#define SDHSTS_BUSY_IRPT 0x400
-+#define SDHSTS_BLOCK_IRPT 0x200
-+#define SDHSTS_SDIO_IRPT 0x100
-+#define SDHSTS_REW_TIME_OUT 0x80
-+#define SDHSTS_CMD_TIME_OUT 0x40
-+#define SDHSTS_CRC16_ERROR 0x20
-+#define SDHSTS_CRC7_ERROR 0x10
-+#define SDHSTS_FIFO_ERROR 0x08
-+/* Reserved */
-+/* Reserved */
-+#define SDHSTS_DATA_FLAG 0x01
-+
-+#define SDHSTS_TRANSFER_ERROR_MASK (SDHSTS_CRC7_ERROR|SDHSTS_CRC16_ERROR|SDHSTS_REW_TIME_OUT|SDHSTS_FIFO_ERROR)
-+#define SDHSTS_ERROR_MASK (SDHSTS_CMD_TIME_OUT|SDHSTS_TRANSFER_ERROR_MASK)
-+
-+#define SDHCFG_BUSY_IRPT_EN (1<<10)
-+#define SDHCFG_BLOCK_IRPT_EN (1<<8)
-+#define SDHCFG_SDIO_IRPT_EN (1<<5)
-+#define SDHCFG_DATA_IRPT_EN (1<<4)
-+#define SDHCFG_SLOW_CARD (1<<3)
-+#define SDHCFG_WIDE_EXT_BUS (1<<2)
-+#define SDHCFG_WIDE_INT_BUS (1<<1)
-+#define SDHCFG_REL_CMD_LINE (1<<0)
-+
-+#define SDEDM_FORCE_DATA_MODE (1<<19)
-+#define SDEDM_CLOCK_PULSE (1<<20)
-+#define SDEDM_BYPASS (1<<21)
-+
-+#define SDEDM_WRITE_THRESHOLD_SHIFT 9
-+#define SDEDM_READ_THRESHOLD_SHIFT 14
-+#define SDEDM_THRESHOLD_MASK 0x1f
-+
-+#define MHZ 1000000
-+
-+
-+struct bcm2835_host {
-+ spinlock_t lock;
-+
-+ void __iomem *ioaddr;
-+ u32 bus_addr;
-+
-+ struct mmc_host *mmc;
-+
-+ u32 pio_timeout; /* In jiffies */
-+
-+ int clock; /* Current clock speed */
-+
-+ bool slow_card; /* Force 11-bit divisor */
-+
-+ unsigned int max_clk; /* Max possible freq */
-+
-+ struct tasklet_struct finish_tasklet; /* Tasklet structures */
-+
-+ struct timer_list timer; /* Timer for timeouts */
-+
-+ struct timer_list pio_timer; /* PIO error detection timer */
-+
-+ struct sg_mapping_iter sg_miter; /* SG state for PIO */
-+ unsigned int blocks; /* remaining PIO blocks */
-+
-+ int irq; /* Device IRQ */
-+
-+
-+ /* cached registers */
-+ u32 hcfg;
-+ u32 cdiv;
-+
-+ struct mmc_request *mrq; /* Current request */
-+ struct mmc_command *cmd; /* Current command */
-+ struct mmc_data *data; /* Current data request */
-+ unsigned int data_complete:1; /* Data finished before cmd */
-+
-+ unsigned int flush_fifo:1; /* Drain the fifo when finishing */
-+
-+ unsigned int use_busy:1; /* Wait for busy interrupt */
-+
-+ unsigned int debug:1; /* Enable debug output */
-+
-+ u32 thread_isr;
-+
-+ /*DMA part*/
-+ struct dma_chan *dma_chan_rx; /* DMA channel for reads */
-+ struct dma_chan *dma_chan_tx; /* DMA channel for writes */
-+
-+ bool allow_dma;
-+ bool have_dma;
-+ bool use_dma;
-+ /*end of DMA part*/
-+
-+ int max_delay; /* maximum length of time spent waiting */
-+ struct timeval stop_time; /* when the last stop was issued */
-+ u32 delay_after_stop; /* minimum time between stop and subsequent data transfer */
-+ u32 overclock_50; /* frequency to use when 50MHz is requested (in MHz) */
-+ u32 overclock; /* Current frequency if overclocked, else zero */
-+ u32 pio_limit; /* Maximum block count for PIO (0 = always DMA) */
-+};
-+
-+
-+static inline void bcm2835_sdhost_write(struct bcm2835_host *host, u32 val, int reg)
-+{
-+ writel(val, host->ioaddr + reg);
-+}
-+
-+static inline u32 bcm2835_sdhost_read(struct bcm2835_host *host, int reg)
-+{
-+ return readl(host->ioaddr + reg);
-+}
-+
-+static inline u32 bcm2835_sdhost_read_relaxed(struct bcm2835_host *host, int reg)
-+{
-+ return readl_relaxed(host->ioaddr + reg);
-+}
-+
-+static void bcm2835_sdhost_dumpcmd(struct bcm2835_host *host,
-+ struct mmc_command *cmd,
-+ const char *label)
-+{
-+ if (cmd)
-+ pr_info("%s:%c%s op %d arg 0x%x flags 0x%x - resp %08x %08x %08x %08x, err %d\n",
-+ mmc_hostname(host->mmc),
-+ (cmd == host->cmd) ? '>' : ' ',
-+ label, cmd->opcode, cmd->arg, cmd->flags,
-+ cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3],
-+ cmd->error);
-+}
-+
-+static void bcm2835_sdhost_dumpregs(struct bcm2835_host *host)
-+{
-+ bcm2835_sdhost_dumpcmd(host, host->mrq->sbc, "sbc");
-+ bcm2835_sdhost_dumpcmd(host, host->mrq->cmd, "cmd");
-+ if (host->mrq->data)
-+ pr_err("%s: data blocks %x blksz %x - err %d\n",
-+ mmc_hostname(host->mmc),
-+ host->mrq->data->blocks,
-+ host->mrq->data->blksz,
-+ host->mrq->data->error);
-+ bcm2835_sdhost_dumpcmd(host, host->mrq->stop, "stop");
-+
-+ pr_info("%s: =========== REGISTER DUMP ===========\n",
-+ mmc_hostname(host->mmc));
-+
-+ pr_info("%s: SDCMD 0x%08x\n",
-+ mmc_hostname(host->mmc),
-+ bcm2835_sdhost_read(host, SDCMD));
-+ pr_info("%s: SDARG 0x%08x\n",
-+ mmc_hostname(host->mmc),
-+ bcm2835_sdhost_read(host, SDARG));
-+ pr_info("%s: SDTOUT 0x%08x\n",
-+ mmc_hostname(host->mmc),
-+ bcm2835_sdhost_read(host, SDTOUT));
-+ pr_info("%s: SDCDIV 0x%08x\n",
-+ mmc_hostname(host->mmc),
-+ bcm2835_sdhost_read(host, SDCDIV));
-+ pr_info("%s: SDRSP0 0x%08x\n",
-+ mmc_hostname(host->mmc),
-+ bcm2835_sdhost_read(host, SDRSP0));
-+ pr_info("%s: SDRSP1 0x%08x\n",
-+ mmc_hostname(host->mmc),
-+ bcm2835_sdhost_read(host, SDRSP1));
-+ pr_info("%s: SDRSP2 0x%08x\n",
-+ mmc_hostname(host->mmc),
-+ bcm2835_sdhost_read(host, SDRSP2));
-+ pr_info("%s: SDRSP3 0x%08x\n",
-+ mmc_hostname(host->mmc),
-+ bcm2835_sdhost_read(host, SDRSP3));
-+ pr_info("%s: SDHSTS 0x%08x\n",
-+ mmc_hostname(host->mmc),
-+ bcm2835_sdhost_read(host, SDHSTS));
-+ pr_info("%s: SDVDD 0x%08x\n",
-+ mmc_hostname(host->mmc),
-+ bcm2835_sdhost_read(host, SDVDD));
-+ pr_info("%s: SDEDM 0x%08x\n",
-+ mmc_hostname(host->mmc),
-+ bcm2835_sdhost_read(host, SDEDM));
-+ pr_info("%s: SDHCFG 0x%08x\n",
-+ mmc_hostname(host->mmc),
-+ bcm2835_sdhost_read(host, SDHCFG));
-+ pr_info("%s: SDHBCT 0x%08x\n",
-+ mmc_hostname(host->mmc),
-+ bcm2835_sdhost_read(host, SDHBCT));
-+ pr_info("%s: SDHBLC 0x%08x\n",
-+ mmc_hostname(host->mmc),
-+ bcm2835_sdhost_read(host, SDHBLC));
-+
-+ pr_info("%s: ===========================================\n",
-+ mmc_hostname(host->mmc));
-+}
-+
-+
-+static void bcm2835_sdhost_set_power(struct bcm2835_host *host, bool on)
-+{
-+ bcm2835_sdhost_write(host, on ? 1 : 0, SDVDD);
-+}
-+
-+
-+static void bcm2835_sdhost_reset_internal(struct bcm2835_host *host)
-+{
-+ u32 temp;
-+
-+ bcm2835_sdhost_set_power(host, false);
-+
-+ bcm2835_sdhost_write(host, 0, SDCMD);
-+ bcm2835_sdhost_write(host, 0, SDARG);
-+ bcm2835_sdhost_write(host, 0xf00000, SDTOUT);
-+ bcm2835_sdhost_write(host, 0, SDCDIV);
-+ bcm2835_sdhost_write(host, 0x7f8, SDHSTS); /* Write 1s to clear */
-+ bcm2835_sdhost_write(host, 0, SDHCFG);
-+ bcm2835_sdhost_write(host, 0, SDHBCT);
-+ bcm2835_sdhost_write(host, 0, SDHBLC);
-+
-+ /* Limit fifo usage due to silicon bug */
-+ temp = bcm2835_sdhost_read(host, SDEDM);
-+ temp &= ~((SDEDM_THRESHOLD_MASK<<SDEDM_READ_THRESHOLD_SHIFT) |
-+ (SDEDM_THRESHOLD_MASK<<SDEDM_WRITE_THRESHOLD_SHIFT));
-+ temp |= (SAFE_READ_THRESHOLD << SDEDM_READ_THRESHOLD_SHIFT) |
-+ (SAFE_WRITE_THRESHOLD << SDEDM_WRITE_THRESHOLD_SHIFT);
-+ bcm2835_sdhost_write(host, temp, SDEDM);
-+ mdelay(10);
-+ bcm2835_sdhost_set_power(host, true);
-+ mdelay(10);
-+ host->clock = 0;
-+ bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
-+ bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
-+ mmiowb();
-+}
-+
-+
-+static void bcm2835_sdhost_reset(struct mmc_host *mmc)
-+{
-+ struct bcm2835_host *host = mmc_priv(mmc);
-+ unsigned long flags;
-+ if (host->debug)
-+ pr_info("%s: reset\n", mmc_hostname(mmc));
-+ spin_lock_irqsave(&host->lock, flags);
-+
-+ bcm2835_sdhost_reset_internal(host);
-+
-+ spin_unlock_irqrestore(&host->lock, flags);
-+}
-+
-+static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
-+
-+static void bcm2835_sdhost_init(struct bcm2835_host *host, int soft)
-+{
-+ pr_debug("bcm2835_sdhost_init(%d)\n", soft);
-+
-+ /* Set interrupt enables */
-+ host->hcfg = SDHCFG_BUSY_IRPT_EN;
-+
-+ bcm2835_sdhost_reset_internal(host);
-+
-+ if (soft) {
-+ /* force clock reconfiguration */
-+ host->clock = 0;
-+ bcm2835_sdhost_set_ios(host->mmc, &host->mmc->ios);
-+ }
-+}
-+
-+static bool bcm2835_sdhost_is_write_complete(struct bcm2835_host *host)
-+{
-+ bool write_complete = ((bcm2835_sdhost_read(host, SDEDM) & 0xf) == 1);
-+
-+ if (!write_complete) {
-+ /* Request an IRQ for the last block */
-+ host->hcfg |= SDHCFG_BLOCK_IRPT_EN;
-+ bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
-+ if ((bcm2835_sdhost_read(host, SDEDM) & 0xf) == 1) {
-+ /* The write has now completed. Disable the interrupt
-+ and clear the status flag */
-+ host->hcfg &= ~SDHCFG_BLOCK_IRPT_EN;
-+ bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
-+ bcm2835_sdhost_write(host, SDHSTS_BLOCK_IRPT, SDHSTS);
-+ write_complete = true;
-+ }
-+ }
-+
-+ return write_complete;
-+}
-+
-+static void bcm2835_sdhost_wait_write_complete(struct bcm2835_host *host)
-+{
-+ int timediff;
-+#ifdef DEBUG
-+ static struct timeval start_time;
-+ static int max_stall_time = 0;
-+ static int total_stall_time = 0;
-+ struct timeval before, after;
-+
-+ do_gettimeofday(&before);
-+ if (max_stall_time == 0)
-+ start_time = before;
-+#endif
-+
-+ timediff = 0;
-+
-+ while (1) {
-+ u32 edm = bcm2835_sdhost_read(host, SDEDM);
-+ if ((edm & 0xf) == 1)
-+ break;
-+ timediff++;
-+ if (timediff > 5000000) {
-+#ifdef DEBUG
-+ do_gettimeofday(&after);
-+ timediff = (after.tv_sec - before.tv_sec)*1000000 +
-+ (after.tv_usec - before.tv_usec);
-+
-+ pr_err(" wait_write_complete - still waiting after %dus\n",
-+ timediff);
-+#else
-+ pr_err(" wait_write_complete - still waiting after %d retries\n",
-+ timediff);
-+#endif
-+ bcm2835_sdhost_dumpregs(host);
-+ host->data->error = -ETIMEDOUT;
-+ return;
-+ }
-+ }
-+
-+#ifdef DEBUG
-+ do_gettimeofday(&after);
-+ timediff = (after.tv_sec - before.tv_sec)*1000000 + (after.tv_usec - before.tv_usec);
-+
-+ total_stall_time += timediff;
-+ if (timediff > max_stall_time)
-+ max_stall_time = timediff;
-+
-+ if ((after.tv_sec - start_time.tv_sec) > 10) {
-+ pr_debug(" wait_write_complete - max wait %dus, total %dus\n",
-+ max_stall_time, total_stall_time);
-+ start_time = after;
-+ max_stall_time = 0;
-+ total_stall_time = 0;
-+ }
-+#endif
-+}
-+
-+static void bcm2835_sdhost_finish_data(struct bcm2835_host *host);
-+
-+static void bcm2835_sdhost_dma_complete(void *param)
-+{
-+ struct bcm2835_host *host = param;
-+ struct dma_chan *dma_chan;
-+ unsigned long flags;
-+ u32 dir_data;
-+
-+ spin_lock_irqsave(&host->lock, flags);
-+
-+ if (host->data) {
-+ bool write_complete;
-+ if (USE_BLOCK_IRQ)
-+ write_complete = bcm2835_sdhost_is_write_complete(host);
-+ else {
-+ bcm2835_sdhost_wait_write_complete(host);
-+ write_complete = true;
-+ }
-+ pr_debug("dma_complete() - write_complete=%d\n",
-+ write_complete);
-+
-+ if (write_complete || (host->data->flags & MMC_DATA_READ))
-+ {
-+ if (write_complete) {
-+ dma_chan = host->dma_chan_tx;
-+ dir_data = DMA_TO_DEVICE;
-+ } else {
-+ dma_chan = host->dma_chan_rx;
-+ dir_data = DMA_FROM_DEVICE;
-+ }
-+
-+ dma_unmap_sg(dma_chan->device->dev,
-+ host->data->sg, host->data->sg_len,
-+ dir_data);
-+
-+ bcm2835_sdhost_finish_data(host);
-+ }
-+ }
-+
-+ spin_unlock_irqrestore(&host->lock, flags);
-+}
-+
-+static bool data_transfer_wait(struct bcm2835_host *host)
-+{
-+ unsigned long timeout = 1000000;
-+ while (timeout)
-+ {
-+ u32 sdhsts = bcm2835_sdhost_read(host, SDHSTS);
-+ if (sdhsts & SDHSTS_DATA_FLAG) {
-+ bcm2835_sdhost_write(host, SDHSTS_DATA_FLAG, SDHSTS);
-+ break;
-+ }
-+ timeout--;
-+ }
-+ if (timeout == 0) {
-+ pr_err("%s: Data %s timeout\n",
-+ mmc_hostname(host->mmc),
-+ (host->data->flags & MMC_DATA_READ) ? "read" : "write");
-+ bcm2835_sdhost_dumpregs(host);
-+ host->data->error = -ETIMEDOUT;
-+ return false;
-+ }
-+ return true;
-+}
-+
-+static void bcm2835_sdhost_read_block_pio(struct bcm2835_host *host)
-+{
-+ unsigned long flags;
-+ size_t blksize, len;
-+ u32 *buf;
-+
-+ blksize = host->data->blksz;
-+
-+ local_irq_save(flags);
-+
-+ while (blksize) {
-+ if (!sg_miter_next(&host->sg_miter))
-+ BUG();
-+
-+ len = min(host->sg_miter.length, blksize);
-+ BUG_ON(len % 4);
-+
-+ blksize -= len;
-+ host->sg_miter.consumed = len;
-+
-+ buf = (u32 *)host->sg_miter.addr;
-+
-+ while (len) {
-+ if (!data_transfer_wait(host))
-+ break;
-+
-+ *(buf++) = bcm2835_sdhost_read(host, SDDATA);
-+ len -= 4;
-+ }
-+
-+ if (host->data->error)
-+ break;
-+ }
-+
-+ sg_miter_stop(&host->sg_miter);
-+
-+ local_irq_restore(flags);
-+}
-+
-+static void bcm2835_sdhost_write_block_pio(struct bcm2835_host *host)
-+{
-+ unsigned long flags;
-+ size_t blksize, len;
-+ u32 *buf;
-+
-+ blksize = host->data->blksz;
-+
-+ local_irq_save(flags);
-+
-+ while (blksize) {
-+ if (!sg_miter_next(&host->sg_miter))
-+ BUG();
-+
-+ len = min(host->sg_miter.length, blksize);
-+ BUG_ON(len % 4);
-+
-+ blksize -= len;
-+ host->sg_miter.consumed = len;
-+
-+ buf = host->sg_miter.addr;
-+
-+ while (len) {
-+ if (!data_transfer_wait(host))
-+ break;
-+
-+ bcm2835_sdhost_write(host, *(buf++), SDDATA);
-+ len -= 4;
-+ }
-+
-+ if (host->data->error)
-+ break;
-+ }
-+
-+ sg_miter_stop(&host->sg_miter);
-+
-+ local_irq_restore(flags);
-+}
-+
-+
-+static void bcm2835_sdhost_transfer_pio(struct bcm2835_host *host)
-+{
-+ u32 sdhsts;
-+ bool is_read;
-+ BUG_ON(!host->data);
-+
-+ is_read = (host->data->flags & MMC_DATA_READ) != 0;
-+ if (is_read)
-+ bcm2835_sdhost_read_block_pio(host);
-+ else
-+ bcm2835_sdhost_write_block_pio(host);
-+
-+ sdhsts = bcm2835_sdhost_read(host, SDHSTS);
-+ if (sdhsts & (SDHSTS_CRC16_ERROR |
-+ SDHSTS_CRC7_ERROR |
-+ SDHSTS_FIFO_ERROR)) {
-+ pr_err("%s: %s transfer error - HSTS %x\n",
-+ mmc_hostname(host->mmc),
-+ is_read ? "read" : "write",
-+ sdhsts);
-+ host->data->error = -EILSEQ;
-+ } else if ((sdhsts & (SDHSTS_CMD_TIME_OUT |
-+ SDHSTS_REW_TIME_OUT))) {
-+ pr_err("%s: %s timeout error - HSTS %x\n",
-+ mmc_hostname(host->mmc),
-+ is_read ? "read" : "write",
-+ sdhsts);
-+ host->data->error = -ETIMEDOUT;
-+ } else if (!is_read && !host->data->error) {
-+ /* Start a timer in case a transfer error occurs because
-+ there is no error interrupt */
-+ mod_timer(&host->pio_timer, jiffies + host->pio_timeout);
-+ }
-+}
-+
-+
-+static void bcm2835_sdhost_transfer_dma(struct bcm2835_host *host)
-+{
-+ u32 len, dir_data, dir_slave;
-+ struct dma_async_tx_descriptor *desc = NULL;
-+ struct dma_chan *dma_chan;
-+
-+ pr_debug("bcm2835_sdhost_transfer_dma()\n");
-+
-+ WARN_ON(!host->data);
-+
-+ if (!host->data)
-+ return;
-+
-+ if (host->data->flags & MMC_DATA_READ) {
-+ dma_chan = host->dma_chan_rx;
-+ dir_data = DMA_FROM_DEVICE;
-+ dir_slave = DMA_DEV_TO_MEM;
-+ } else {
-+ dma_chan = host->dma_chan_tx;
-+ dir_data = DMA_TO_DEVICE;
-+ dir_slave = DMA_MEM_TO_DEV;
-+ }
-+
-+ BUG_ON(!dma_chan->device);
-+ BUG_ON(!dma_chan->device->dev);
-+ BUG_ON(!host->data->sg);
-+
-+ len = dma_map_sg(dma_chan->device->dev, host->data->sg,
-+ host->data->sg_len, dir_data);
-+ if (len > 0) {
-+ desc = dmaengine_prep_slave_sg(dma_chan, host->data->sg,
-+ len, dir_slave,
-+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-+ } else {
-+ dev_err(mmc_dev(host->mmc), "dma_map_sg returned zero length\n");
-+ }
-+ if (desc) {
-+ desc->callback = bcm2835_sdhost_dma_complete;
-+ desc->callback_param = host;
-+ dmaengine_submit(desc);
-+ dma_async_issue_pending(dma_chan);
-+ }
-+
-+}
-+
-+
-+static void bcm2835_sdhost_set_transfer_irqs(struct bcm2835_host *host)
-+{
-+ u32 all_irqs = SDHCFG_DATA_IRPT_EN | SDHCFG_BLOCK_IRPT_EN |
-+ SDHCFG_BUSY_IRPT_EN;
-+ if (host->use_dma)
-+ host->hcfg = (host->hcfg & ~all_irqs) |
-+ SDHCFG_BUSY_IRPT_EN;
-+ else
-+ host->hcfg = (host->hcfg & ~all_irqs) |
-+ SDHCFG_DATA_IRPT_EN |
-+ SDHCFG_BUSY_IRPT_EN;
-+
-+ bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
-+}
-+
-+
-+static void bcm2835_sdhost_prepare_data(struct bcm2835_host *host, struct mmc_command *cmd)
-+{
-+ struct mmc_data *data = cmd->data;
-+
-+ WARN_ON(host->data);
-+
-+ if (!data)
-+ return;
-+
-+ /* Sanity checks */
-+ BUG_ON(data->blksz * data->blocks > 524288);
-+ BUG_ON(data->blksz > host->mmc->max_blk_size);
-+ BUG_ON(data->blocks > 65535);
-+
-+ host->data = data;
-+ host->data_complete = 0;
-+ host->flush_fifo = 0;
-+ host->data->bytes_xfered = 0;
-+
-+ host->use_dma = host->have_dma && (data->blocks > host->pio_limit);
-+ if (!host->use_dma) {
-+ int flags;
-+
-+ flags = SG_MITER_ATOMIC;
-+ if (data->flags & MMC_DATA_READ)
-+ flags |= SG_MITER_TO_SG;
-+ else
-+ flags |= SG_MITER_FROM_SG;
-+ sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
-+ host->blocks = data->blocks;
-+ }
-+
-+ bcm2835_sdhost_set_transfer_irqs(host);
-+
-+ bcm2835_sdhost_write(host, data->blksz, SDHBCT);
-+ bcm2835_sdhost_write(host, host->use_dma ? data->blocks : 0, SDHBLC);
-+
-+ BUG_ON(!host->data);
-+}
-+
-+
-+void bcm2835_sdhost_send_command(struct bcm2835_host *host, struct mmc_command *cmd)
-+{
-+ u32 sdcmd, sdhsts;
-+ unsigned long timeout;
-+ int delay;
-+
-+ WARN_ON(host->cmd);
-+
-+ if (cmd->data)
-+ pr_debug("%s: send_command %d 0x%x "
-+ "(flags 0x%x) - %s %d*%d\n",
-+ mmc_hostname(host->mmc),
-+ cmd->opcode, cmd->arg, cmd->flags,
-+ (cmd->data->flags & MMC_DATA_READ) ?
-+ "read" : "write", cmd->data->blocks,
-+ cmd->data->blksz);
-+ else
-+ pr_debug("%s: send_command %d 0x%x (flags 0x%x)\n",
-+ mmc_hostname(host->mmc),
-+ cmd->opcode, cmd->arg, cmd->flags);
-+
-+ /* Wait max 100 ms */
-+ timeout = 10000;
-+
-+ while (bcm2835_sdhost_read(host, SDCMD) & SDCMD_NEW_FLAG) {
-+ if (timeout == 0) {
-+ pr_err("%s: previous command never completed.\n",
-+ mmc_hostname(host->mmc));
-+ bcm2835_sdhost_dumpregs(host);
-+ cmd->error = -EIO;
-+ tasklet_schedule(&host->finish_tasklet);
-+ return;
-+ }
-+ timeout--;
-+ udelay(10);
-+ }
-+
-+ delay = (10000 - timeout)/100;
-+ if (delay > host->max_delay) {
-+ host->max_delay = delay;
-+ pr_warning("%s: controller hung for %d ms\n",
-+ mmc_hostname(host->mmc),
-+ host->max_delay);
-+ }
-+
-+ timeout = jiffies;
-+ if (!cmd->data && cmd->busy_timeout > 9000)
-+ timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
-+ else
-+ timeout += 10 * HZ;
-+ mod_timer(&host->timer, timeout);
-+
-+ host->cmd = cmd;
-+
-+ /* Clear any error flags */
-+ sdhsts = bcm2835_sdhost_read(host, SDHSTS);
-+ if (sdhsts & SDHSTS_ERROR_MASK)
-+ bcm2835_sdhost_write(host, sdhsts, SDHSTS);
-+
-+ bcm2835_sdhost_prepare_data(host, cmd);
-+
-+ bcm2835_sdhost_write(host, cmd->arg, SDARG);
-+
-+ if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
-+ pr_err("%s: unsupported response type!\n",
-+ mmc_hostname(host->mmc));
-+ cmd->error = -EINVAL;
-+ tasklet_schedule(&host->finish_tasklet);
-+ return;
-+ }
-+
-+ sdcmd = cmd->opcode & SDCMD_CMD_MASK;
-+
-+ if (!(cmd->flags & MMC_RSP_PRESENT))
-+ sdcmd |= SDCMD_NO_RESPONSE;
-+ else {
-+ if (cmd->flags & MMC_RSP_136)
-+ sdcmd |= SDCMD_LONG_RESPONSE;
-+ if (cmd->flags & MMC_RSP_BUSY) {
-+ sdcmd |= SDCMD_BUSYWAIT;
-+ host->use_busy = 1;
-+ }
-+ }
-+
-+ if (cmd->data) {
-+ if (host->delay_after_stop) {
-+ struct timeval now;
-+ int time_since_stop;
-+ do_gettimeofday(&now);
-+ time_since_stop = (now.tv_sec - host->stop_time.tv_sec);
-+ if (time_since_stop < 2) {
-+ /* Possibly less than one second */
-+ time_since_stop = time_since_stop * 1000000 +
-+ (now.tv_usec - host->stop_time.tv_usec);
-+ if (time_since_stop < host->delay_after_stop)
-+ udelay(host->delay_after_stop -
-+ time_since_stop);
-+ }
-+ }
-+
-+ if (cmd->data->flags & MMC_DATA_WRITE)
-+ sdcmd |= SDCMD_WRITE_CMD;
-+ if (cmd->data->flags & MMC_DATA_READ)
-+ sdcmd |= SDCMD_READ_CMD;
-+ }
-+
-+ bcm2835_sdhost_write(host, sdcmd | SDCMD_NEW_FLAG, SDCMD);
-+}
-+
-+
-+static void bcm2835_sdhost_finish_command(struct bcm2835_host *host);
-+static void bcm2835_sdhost_transfer_complete(struct bcm2835_host *host);
-+
-+static void bcm2835_sdhost_finish_data(struct bcm2835_host *host)
-+{
-+ struct mmc_data *data;
-+
-+ data = host->data;
-+ BUG_ON(!data);
-+
-+ pr_debug("finish_data(error %d, stop %d, sbc %d)\n",
-+ data->error, data->stop ? 1 : 0,
-+ host->mrq->sbc ? 1 : 0);
-+
-+ host->hcfg &= ~(SDHCFG_DATA_IRPT_EN | SDHCFG_BLOCK_IRPT_EN);
-+ bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
-+
-+ if (data->error) {
-+ data->bytes_xfered = 0;
-+ } else
-+ data->bytes_xfered = data->blksz * data->blocks;
-+
-+ host->data_complete = 1;
-+
-+ if (host->cmd) {
-+ /*
-+ * Data managed to finish before the
-+ * command completed. Make sure we do
-+ * things in the proper order.
-+ */
-+ pr_debug("Finished early - HSTS %x\n",
-+ bcm2835_sdhost_read(host, SDHSTS));
-+ }
-+ else
-+ bcm2835_sdhost_transfer_complete(host);
-+}
-+
-+
-+static void bcm2835_sdhost_transfer_complete(struct bcm2835_host *host)
-+{
-+ struct mmc_data *data;
-+
-+ BUG_ON(host->cmd);
-+ BUG_ON(!host->data);
-+ BUG_ON(!host->data_complete);
-+
-+ data = host->data;
-+ host->data = NULL;
-+
-+ pr_debug("transfer_complete(error %d, stop %d)\n",
-+ data->error, data->stop ? 1 : 0);
-+
-+ /*
-+ * Need to send CMD12 if -
-+ * a) open-ended multiblock transfer (no CMD23)
-+ * b) error in multiblock transfer
-+ */
-+ if (data->stop &&
-+ (data->error ||
-+ !host->mrq->sbc)) {
-+ host->flush_fifo = 1;
-+ bcm2835_sdhost_send_command(host, data->stop);
-+ if (host->delay_after_stop)
-+ do_gettimeofday(&host->stop_time);
-+ if (!host->use_busy)
-+ bcm2835_sdhost_finish_command(host);
-+ } else {
-+ tasklet_schedule(&host->finish_tasklet);
-+ }
-+}
-+
-+static void bcm2835_sdhost_finish_command(struct bcm2835_host *host)
-+{
-+ u32 sdcmd;
-+ unsigned long timeout;
-+#ifdef DEBUG
-+ struct timeval before, after;
-+ int timediff = 0;
-+#endif
-+
-+ pr_debug("finish_command(%x)\n", bcm2835_sdhost_read(host, SDCMD));
-+
-+ BUG_ON(!host->cmd || !host->mrq);
-+
-+#ifdef DEBUG
-+ do_gettimeofday(&before);
-+#endif
-+ /* Wait max 100 ms */
-+ timeout = 10000;
-+ for (sdcmd = bcm2835_sdhost_read(host, SDCMD);
-+ (sdcmd & SDCMD_NEW_FLAG) && timeout;
-+ timeout--) {
-+ if (host->flush_fifo) {
-+ while (bcm2835_sdhost_read(host, SDHSTS) &
-+ SDHSTS_DATA_FLAG)
-+ (void)bcm2835_sdhost_read(host, SDDATA);
-+ }
-+ udelay(10);
-+ sdcmd = bcm2835_sdhost_read(host, SDCMD);
-+ }
-+#ifdef DEBUG
-+ do_gettimeofday(&after);
-+ timediff = (after.tv_sec - before.tv_sec)*1000000 +
-+ (after.tv_usec - before.tv_usec);
-+
-+ pr_debug(" finish_command - waited %dus\n", timediff);
-+#endif
-+
-+ if (timeout == 0) {
-+ pr_err("%s: command never completed.\n",
-+ mmc_hostname(host->mmc));
-+ bcm2835_sdhost_dumpregs(host);
-+ host->cmd->error = -EIO;
-+ tasklet_schedule(&host->finish_tasklet);
-+ return;
-+ }
-+
-+ if (host->flush_fifo) {
-+ for (timeout = 100;
-+ (bcm2835_sdhost_read(host, SDHSTS) & SDHSTS_DATA_FLAG) && timeout;
-+ timeout--) {
-+ (void)bcm2835_sdhost_read(host, SDDATA);
-+ }
-+ host->flush_fifo = 0;
-+ if (timeout == 0) {
-+ pr_err("%s: FIFO never drained.\n",
-+ mmc_hostname(host->mmc));
-+ bcm2835_sdhost_dumpregs(host);
-+ host->cmd->error = -EIO;
-+ tasklet_schedule(&host->finish_tasklet);
-+ return;
-+ }
-+ }
-+
-+ /* Check for errors */
-+ if (sdcmd & SDCMD_FAIL_FLAG)
-+ {
-+ u32 sdhsts = bcm2835_sdhost_read(host, SDHSTS);
-+
-+ if (host->debug)
-+ pr_info("%s: error detected - CMD %x, HSTS %03x, EDM %x\n",
-+ mmc_hostname(host->mmc), sdcmd, sdhsts,
-+ bcm2835_sdhost_read(host, SDEDM));
-+
-+ if ((sdhsts & SDHSTS_CRC7_ERROR) &&
-+ (host->cmd->opcode == 1)) {
-+ if (host->debug)
-+ pr_info("%s: ignoring CRC7 error for CMD1\n",
-+ mmc_hostname(host->mmc));
-+ } else {
-+ if (sdhsts & SDHSTS_CMD_TIME_OUT) {
-+ if (host->debug)
-+ pr_err("%s: command %d timeout\n",
-+ mmc_hostname(host->mmc),
-+ host->cmd->opcode);
-+ host->cmd->error = -ETIMEDOUT;
-+ } else {
-+ pr_err("%s: unexpected command %d error\n",
-+ mmc_hostname(host->mmc),
-+ host->cmd->opcode);
-+ bcm2835_sdhost_dumpregs(host);
-+ host->cmd->error = -EIO;
-+ }
-+ tasklet_schedule(&host->finish_tasklet);
-+ return;
-+ }
-+ }
-+
-+ if (host->cmd->flags & MMC_RSP_PRESENT) {
-+ if (host->cmd->flags & MMC_RSP_136) {
-+ int i;
-+ for (i = 0; i < 4; i++)
-+ host->cmd->resp[3 - i] = bcm2835_sdhost_read(host, SDRSP0 + i*4);
-+ pr_debug("%s: finish_command %08x %08x %08x %08x\n",
-+ mmc_hostname(host->mmc),
-+ host->cmd->resp[0], host->cmd->resp[1], host->cmd->resp[2], host->cmd->resp[3]);
-+ } else {
-+ host->cmd->resp[0] = bcm2835_sdhost_read(host, SDRSP0);
-+ pr_debug("%s: finish_command %08x\n",
-+ mmc_hostname(host->mmc),
-+ host->cmd->resp[0]);
-+ }
-+ }
-+
-+ host->cmd->error = 0;
-+
-+ if (host->cmd == host->mrq->sbc) {
-+ /* Finished CMD23, now send actual command. */
-+ host->cmd = NULL;
-+ bcm2835_sdhost_send_command(host, host->mrq->cmd);
-+
-+ if (host->cmd->data && host->use_dma)
-+ /* DMA transfer starts now, PIO starts after irq */
-+ bcm2835_sdhost_transfer_dma(host);
-+
-+ if (!host->use_busy)
-+ bcm2835_sdhost_finish_command(host);
-+ } else if (host->cmd == host->mrq->stop)
-+ /* Finished CMD12 */
-+ tasklet_schedule(&host->finish_tasklet);
-+ else {
-+ /* Processed actual command. */
-+ host->cmd = NULL;
-+ if (!host->data)
-+ tasklet_schedule(&host->finish_tasklet);
-+ else if (host->data_complete)
-+ bcm2835_sdhost_transfer_complete(host);
-+ }
-+}
-+
-+static void bcm2835_sdhost_timeout(unsigned long data)
-+{
-+ struct bcm2835_host *host;
-+ unsigned long flags;
-+
-+ host = (struct bcm2835_host *)data;
-+
-+ spin_lock_irqsave(&host->lock, flags);
-+
-+ if (host->mrq) {
-+ pr_err("%s: timeout waiting for hardware interrupt.\n",
-+ mmc_hostname(host->mmc));
-+ bcm2835_sdhost_dumpregs(host);
-+
-+ if (host->data) {
-+ host->data->error = -ETIMEDOUT;
-+ bcm2835_sdhost_finish_data(host);
-+ } else {
-+ if (host->cmd)
-+ host->cmd->error = -ETIMEDOUT;
-+ else
-+ host->mrq->cmd->error = -ETIMEDOUT;
-+
-+ pr_debug("timeout_timer tasklet_schedule\n");
-+ tasklet_schedule(&host->finish_tasklet);
-+ }
-+ }
-+
-+ mmiowb();
-+ spin_unlock_irqrestore(&host->lock, flags);
-+}
-+
-+static void bcm2835_sdhost_pio_timeout(unsigned long data)
-+{
-+ struct bcm2835_host *host;
-+ unsigned long flags;
-+
-+ host = (struct bcm2835_host *)data;
-+
-+ spin_lock_irqsave(&host->lock, flags);
-+
-+ if (host->data) {
-+ u32 sdhsts = bcm2835_sdhost_read(host, SDHSTS);
-+
-+ if (sdhsts & SDHSTS_REW_TIME_OUT) {
-+ pr_err("%s: transfer timeout\n",
-+ mmc_hostname(host->mmc));
-+ if (host->debug)
-+ bcm2835_sdhost_dumpregs(host);
-+ } else {
-+ pr_err("%s: unexpected transfer timeout\n",
-+ mmc_hostname(host->mmc));
-+ bcm2835_sdhost_dumpregs(host);
-+ }
-+
-+ bcm2835_sdhost_write(host, SDHSTS_TRANSFER_ERROR_MASK,
-+ SDHSTS);
-+
-+ host->data->error = -ETIMEDOUT;
-+
-+ bcm2835_sdhost_finish_data(host);
-+ }
-+
-+ mmiowb();
-+ spin_unlock_irqrestore(&host->lock, flags);
-+}
-+
-+static void bcm2835_sdhost_enable_sdio_irq_nolock(struct bcm2835_host *host, int enable)
-+{
-+ if (enable)
-+ host->hcfg |= SDHCFG_SDIO_IRPT_EN;
-+ else
-+ host->hcfg &= ~SDHCFG_SDIO_IRPT_EN;
-+ bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
-+ mmiowb();
-+}
-+
-+static void bcm2835_sdhost_enable_sdio_irq(struct mmc_host *mmc, int enable)
-+{
-+ struct bcm2835_host *host = mmc_priv(mmc);
-+ unsigned long flags;
-+
-+ pr_debug("%s: enable_sdio_irq(%d)\n", mmc_hostname(mmc), enable);
-+ spin_lock_irqsave(&host->lock, flags);
-+ bcm2835_sdhost_enable_sdio_irq_nolock(host, enable);
-+ spin_unlock_irqrestore(&host->lock, flags);
-+}
-+
-+static u32 bcm2835_sdhost_busy_irq(struct bcm2835_host *host, u32 intmask)
-+{
-+ const u32 handled = (SDHSTS_REW_TIME_OUT | SDHSTS_CMD_TIME_OUT |
-+ SDHSTS_CRC16_ERROR | SDHSTS_CRC7_ERROR |
-+ SDHSTS_FIFO_ERROR);
-+
-+ if (!host->cmd) {
-+ pr_err("%s: got command busy interrupt 0x%08x even "
-+ "though no command operation was in progress.\n",
-+ mmc_hostname(host->mmc), (unsigned)intmask);
-+ bcm2835_sdhost_dumpregs(host);
-+ return 0;
-+ }
-+
-+ if (!host->use_busy) {
-+ pr_err("%s: got command busy interrupt 0x%08x even "
-+ "though not expecting one.\n",
-+ mmc_hostname(host->mmc), (unsigned)intmask);
-+ bcm2835_sdhost_dumpregs(host);
-+ return 0;
-+ }
-+ host->use_busy = 0;
-+
-+ if (intmask & SDHSTS_ERROR_MASK)
-+ {
-+ pr_err("sdhost_busy_irq: intmask %x, data %p\n", intmask, host->mrq->data);
-+ if (intmask & SDHSTS_CRC7_ERROR)
-+ host->cmd->error = -EILSEQ;
-+ else if (intmask & (SDHSTS_CRC16_ERROR |
-+ SDHSTS_FIFO_ERROR)) {
-+ if (host->mrq->data)
-+ host->mrq->data->error = -EILSEQ;
-+ else
-+ host->cmd->error = -EILSEQ;
-+ } else if (intmask & SDHSTS_REW_TIME_OUT) {
-+ if (host->mrq->data)
-+ host->mrq->data->error = -ETIMEDOUT;
-+ else
-+ host->cmd->error = -ETIMEDOUT;
-+ } else if (intmask & SDHSTS_CMD_TIME_OUT)
-+ host->cmd->error = -ETIMEDOUT;
-+
-+ bcm2835_sdhost_dumpregs(host);
-+ tasklet_schedule(&host->finish_tasklet);
-+ }
-+ else
-+ bcm2835_sdhost_finish_command(host);
-+
-+ return handled;
-+}
-+
-+static u32 bcm2835_sdhost_data_irq(struct bcm2835_host *host, u32 intmask)
-+{
-+ const u32 handled = (SDHSTS_REW_TIME_OUT |
-+ SDHSTS_CRC16_ERROR |
-+ SDHSTS_FIFO_ERROR);
-+
-+ /* There are no dedicated data/space available interrupt
-+ status bits, so it is necessary to use the single shared
-+ data/space available FIFO status bits. It is therefore not
-+ an error to get here when there is no data transfer in
-+ progress. */
-+ if (!host->data)
-+ return 0;
-+
-+ if (intmask & (SDHSTS_CRC16_ERROR |
-+ SDHSTS_FIFO_ERROR |
-+ SDHSTS_REW_TIME_OUT)) {
-+ if (intmask & (SDHSTS_CRC16_ERROR |
-+ SDHSTS_FIFO_ERROR))
-+ host->data->error = -EILSEQ;
-+ else
-+ host->data->error = -ETIMEDOUT;
-+
-+ bcm2835_sdhost_dumpregs(host);
-+ tasklet_schedule(&host->finish_tasklet);
-+ return handled;
-+ }
-+
-+ /* Use the block interrupt for writes after the first block */
-+ if (host->data->flags & MMC_DATA_WRITE) {
-+ host->hcfg &= ~(SDHCFG_DATA_IRPT_EN);
-+ host->hcfg |= SDHCFG_BLOCK_IRPT_EN;
-+ bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
-+ if (host->data->error)
-+ bcm2835_sdhost_finish_data(host);
-+ else
-+ bcm2835_sdhost_transfer_pio(host);
-+ } else {
-+ if (!host->data->error) {
-+ bcm2835_sdhost_transfer_pio(host);
-+ host->blocks--;
-+ }
-+ if ((host->blocks == 0) || host->data->error)
-+ bcm2835_sdhost_finish_data(host);
-+ }
-+
-+ return handled;
-+}
-+
-+static u32 bcm2835_sdhost_block_irq(struct bcm2835_host *host, u32 intmask)
-+{
-+ struct dma_chan *dma_chan;
-+ u32 dir_data;
-+ const u32 handled = (SDHSTS_REW_TIME_OUT |
-+ SDHSTS_CRC16_ERROR |
-+ SDHSTS_FIFO_ERROR);
-+
-+ if (!host->data) {
-+ pr_err("%s: got block interrupt 0x%08x even "
-+ "though no data operation was in progress.\n",
-+ mmc_hostname(host->mmc), (unsigned)intmask);
-+ bcm2835_sdhost_dumpregs(host);
-+ return handled;
-+ }
-+
-+ if (intmask & (SDHSTS_CRC16_ERROR |
-+ SDHSTS_FIFO_ERROR |
-+ SDHSTS_REW_TIME_OUT)) {
-+ if (intmask & (SDHSTS_CRC16_ERROR |
-+ SDHSTS_FIFO_ERROR))
-+ host->data->error = -EILSEQ;
-+ else
-+ host->data->error = -ETIMEDOUT;
-+
-+ if (host->debug)
-+ bcm2835_sdhost_dumpregs(host);
-+ tasklet_schedule(&host->finish_tasklet);
-+ return handled;
-+ }
-+
-+ if (!host->use_dma) {
-+ BUG_ON(!host->blocks);
-+ host->blocks--;
-+ if ((host->blocks == 0) || host->data->error) {
-+ /* Cancel the timer */
-+ del_timer(&host->pio_timer);
-+
-+ bcm2835_sdhost_finish_data(host);
-+ } else {
-+ bcm2835_sdhost_transfer_pio(host);
-+
-+ /* Reset the timer */
-+ mod_timer(&host->pio_timer,
-+ jiffies + host->pio_timeout);
-+ }
-+ } else if (host->data->flags & MMC_DATA_WRITE) {
-+ dma_chan = host->dma_chan_tx;
-+ dir_data = DMA_TO_DEVICE;
-+ dma_unmap_sg(dma_chan->device->dev,
-+ host->data->sg, host->data->sg_len,
-+ dir_data);
-+
-+ bcm2835_sdhost_finish_data(host);
-+ }
-+
-+ return handled;
-+}
-+
-+
-+static irqreturn_t bcm2835_sdhost_irq(int irq, void *dev_id)
-+{
-+ irqreturn_t result = IRQ_NONE;
-+ struct bcm2835_host *host = dev_id;
-+ u32 unexpected = 0, early = 0;
-+ int loops = 0;
-+
-+ spin_lock(&host->lock);
-+
-+ for (loops = 0; loops < 1; loops++) {
-+ u32 intmask, handled;
-+
-+ intmask = bcm2835_sdhost_read(host, SDHSTS);
-+ handled = intmask & (SDHSTS_BUSY_IRPT |
-+ SDHSTS_BLOCK_IRPT |
-+ SDHSTS_SDIO_IRPT |
-+ SDHSTS_DATA_FLAG);
-+ if ((handled == SDHSTS_DATA_FLAG) &&
-+ (loops == 0) && !host->data) {
-+ pr_err("%s: sdhost_irq data interrupt 0x%08x even "
-+ "though no data operation was in progress.\n",
-+ mmc_hostname(host->mmc),
-+ (unsigned)intmask);
-+
-+ bcm2835_sdhost_dumpregs(host);
-+ }
-+
-+ if (!handled)
-+ break;
-+
-+ if (loops)
-+ early |= handled;
-+
-+ result = IRQ_HANDLED;
-+
-+ /* Clear all interrupts and notifications */
-+ bcm2835_sdhost_write(host, intmask, SDHSTS);
-+
-+ if (intmask & SDHSTS_BUSY_IRPT)
-+ handled |= bcm2835_sdhost_busy_irq(host, intmask);
-+
-+ /* There is no true data interrupt status bit, so it is
-+ necessary to qualify the data flag with the interrupt
-+ enable bit */
-+ if ((intmask & SDHSTS_DATA_FLAG) &&
-+ (host->hcfg & SDHCFG_DATA_IRPT_EN))
-+ handled |= bcm2835_sdhost_data_irq(host, intmask);
-+
-+ if (intmask & SDHSTS_BLOCK_IRPT)
-+ handled |= bcm2835_sdhost_block_irq(host, intmask);
-+
-+ if (intmask & SDHSTS_SDIO_IRPT) {
-+ bcm2835_sdhost_enable_sdio_irq_nolock(host, false);
-+ host->thread_isr |= SDHSTS_SDIO_IRPT;
-+ result = IRQ_WAKE_THREAD;
-+ }
-+
-+ unexpected |= (intmask & ~handled);
-+ }
-+
-+ mmiowb();
-+
-+ spin_unlock(&host->lock);
-+
-+ if (early)
-+ pr_debug("%s: early %x (loops %d)\n",
-+ mmc_hostname(host->mmc), early, loops);
-+
-+ if (unexpected) {
-+ pr_err("%s: unexpected interrupt 0x%08x.\n",
-+ mmc_hostname(host->mmc), unexpected);
-+ bcm2835_sdhost_dumpregs(host);
-+ }
-+
-+ return result;
-+}
-+
-+static irqreturn_t bcm2835_sdhost_thread_irq(int irq, void *dev_id)
-+{
-+ struct bcm2835_host *host = dev_id;
-+ unsigned long flags;
-+ u32 isr;
-+
-+ spin_lock_irqsave(&host->lock, flags);
-+ isr = host->thread_isr;
-+ host->thread_isr = 0;
-+ spin_unlock_irqrestore(&host->lock, flags);
-+
-+ if (isr & SDHSTS_SDIO_IRPT) {
-+ sdio_run_irqs(host->mmc);
-+
-+/* Is this necessary? Why re-enable an interrupt which is enabled?
-+ spin_lock_irqsave(&host->lock, flags);
-+ if (host->flags & SDHSTS_SDIO_IRPT_ENABLED)
-+ bcm2835_sdhost_enable_sdio_irq_nolock(host, true);
-+ spin_unlock_irqrestore(&host->lock, flags);
-+*/
-+ }
-+
-+ return isr ? IRQ_HANDLED : IRQ_NONE;
-+}
-+
-+
-+
-+void bcm2835_sdhost_set_clock(struct bcm2835_host *host, unsigned int clock)
-+{
-+ int div = 0; /* Initialized for compiler warning */
-+ unsigned int input_clock = clock;
-+
-+ if (host->debug)
-+ pr_info("%s: set_clock(%d)\n", mmc_hostname(host->mmc), clock);
-+
-+ if ((host->overclock_50 > 50) &&
-+ (clock == 50*MHZ)) {
-+ clock = host->overclock_50 * MHZ + (MHZ - 1);
-+ }
-+
-+ /* The SDCDIV register has 11 bits, and holds (div - 2).
-+ But in data mode the max is 50MHz wihout a minimum, and only the
-+ bottom 3 bits are used. Since the switch over is automatic (unless
-+ we have marked the card as slow...), chosen values have to make
-+ sense in both modes.
-+ Ident mode must be 100-400KHz, so can range check the requested
-+ clock. CMD15 must be used to return to data mode, so this can be
-+ monitored.
-+
-+ clock 250MHz -> 0->125MHz, 1->83.3MHz, 2->62.5MHz, 3->50.0MHz
-+ 4->41.7MHz, 5->35.7MHz, 6->31.3MHz, 7->27.8MHz
-+
-+ 623->400KHz/27.8MHz
-+ reset value (507)->491159/50MHz
-+
-+ BUT, the 3-bit clock divisor in data mode is too small if the
-+ core clock is higher than 250MHz, so instead use the SLOW_CARD
-+ configuration bit to force the use of the ident clock divisor
-+ at all times.
-+ */
-+
-+ host->mmc->actual_clock = 0;
-+
-+ if (clock < 100000) {
-+ /* Can't stop the clock, but make it as slow as possible
-+ * to show willing
-+ */
-+ host->cdiv = SDCDIV_MAX_CDIV;
-+ bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
-+ return;
-+ }
-+
-+ div = host->max_clk / clock;
-+ if (div < 2)
-+ div = 2;
-+ if ((host->max_clk / div) > clock)
-+ div++;
-+ div -= 2;
-+
-+ if (div > SDCDIV_MAX_CDIV)
-+ div = SDCDIV_MAX_CDIV;
-+
-+ clock = host->max_clk / (div + 2);
-+ host->mmc->actual_clock = clock;
-+
-+ if (clock > input_clock) {
-+ /* Save the closest value, to make it easier
-+ to reduce in the event of error */
-+ host->overclock_50 = (clock/MHZ);
-+
-+ if (clock != host->overclock) {
-+ pr_warn("%s: overclocking to %dHz\n",
-+ mmc_hostname(host->mmc), clock);
-+ host->overclock = clock;
-+ }
-+ }
-+ else if (host->overclock)
-+ {
-+ host->overclock = 0;
-+ if (clock == 50 * MHZ)
-+ pr_warn("%s: cancelling overclock\n",
-+ mmc_hostname(host->mmc));
-+ }
-+
-+ host->cdiv = div;
-+ bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
-+
-+ /* Set the timeout to 500ms */
-+ bcm2835_sdhost_write(host, host->mmc->actual_clock/2, SDTOUT);
-+
-+ if (host->debug)
-+ pr_info("%s: clock=%d -> max_clk=%d, cdiv=%x (actual clock %d)\n",
-+ mmc_hostname(host->mmc), input_clock,
-+ host->max_clk, host->cdiv, host->mmc->actual_clock);
-+}
-+
-+static void bcm2835_sdhost_request(struct mmc_host *mmc, struct mmc_request *mrq)
-+{
-+ struct bcm2835_host *host;
-+ unsigned long flags;
-+
-+ host = mmc_priv(mmc);
-+
-+ if (host->debug) {
-+ struct mmc_command *cmd = mrq->cmd;
-+ BUG_ON(!cmd);
-+ if (cmd->data)
-+ pr_info("%s: cmd %d 0x%x (flags 0x%x) - %s %d*%d\n",
-+ mmc_hostname(mmc),
-+ cmd->opcode, cmd->arg, cmd->flags,
-+ (cmd->data->flags & MMC_DATA_READ) ?
-+ "read" : "write", cmd->data->blocks,
-+ cmd->data->blksz);
-+ else
-+ pr_info("%s: cmd %d 0x%x (flags 0x%x)\n",
-+ mmc_hostname(mmc),
-+ cmd->opcode, cmd->arg, cmd->flags);
-+ }
-+
-+ /* Reset the error statuses in case this is a retry */
-+ if (mrq->cmd)
-+ mrq->cmd->error = 0;
-+ if (mrq->data)
-+ mrq->data->error = 0;
-+ if (mrq->stop)
-+ mrq->stop->error = 0;
-+
-+ if (mrq->data && !is_power_of_2(mrq->data->blksz)) {
-+ pr_err("%s: unsupported block size (%d bytes)\n",
-+ mmc_hostname(mmc), mrq->data->blksz);
-+ mrq->cmd->error = -EINVAL;
-+ mmc_request_done(mmc, mrq);
-+ return;
-+ }
-+
-+ spin_lock_irqsave(&host->lock, flags);
-+
-+ WARN_ON(host->mrq != NULL);
-+
-+ host->mrq = mrq;
-+
-+ if (mrq->sbc)
-+ bcm2835_sdhost_send_command(host, mrq->sbc);
-+ else
-+ bcm2835_sdhost_send_command(host, mrq->cmd);
-+
-+ mmiowb();
-+ spin_unlock_irqrestore(&host->lock, flags);
-+
-+ if (!mrq->sbc && mrq->cmd->data && host->use_dma)
-+ /* DMA transfer starts now, PIO starts after irq */
-+ bcm2835_sdhost_transfer_dma(host);
-+
-+ if (!host->use_busy)
-+ bcm2835_sdhost_finish_command(host);
-+}
-+
-+
-+static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-+{
-+
-+ struct bcm2835_host *host = mmc_priv(mmc);
-+ unsigned long flags;
-+
-+ if (host->debug)
-+ pr_info("%s: ios clock %d, pwr %d, bus_width %d, "
-+ "timing %d, vdd %d, drv_type %d\n",
-+ mmc_hostname(mmc),
-+ ios->clock, ios->power_mode, ios->bus_width,
-+ ios->timing, ios->signal_voltage, ios->drv_type);
-+
-+ spin_lock_irqsave(&host->lock, flags);
-+
-+ if (!ios->clock || ios->clock != host->clock) {
-+ bcm2835_sdhost_set_clock(host, ios->clock);
-+ host->clock = ios->clock;
-+ }
-+
-+ /* set bus width */
-+ host->hcfg &= ~SDHCFG_WIDE_EXT_BUS;
-+ if (ios->bus_width == MMC_BUS_WIDTH_4)
-+ host->hcfg |= SDHCFG_WIDE_EXT_BUS;
-+
-+ host->hcfg |= SDHCFG_WIDE_INT_BUS;
-+
-+ /* Disable clever clock switching, to cope with fast core clocks */
-+ host->hcfg |= SDHCFG_SLOW_CARD;
-+
-+ bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
-+
-+ mmiowb();
-+
-+ spin_unlock_irqrestore(&host->lock, flags);
-+}
-+
-+static int bcm2835_sdhost_multi_io_quirk(struct mmc_card *card,
-+ unsigned int direction,
-+ u32 blk_pos, int blk_size)
-+{
-+ /* There is a bug in the host controller hardware that makes
-+ reading the final sector of the card as part of a multiple read
-+ problematic. Detect that case and shorten the read accordingly.
-+ */
-+ /* csd.capacity is in weird units - convert to sectors */
-+ u32 card_sectors = (card->csd.capacity << (card->csd.read_blkbits - 9));
-+
-+ if ((direction == MMC_DATA_READ) &&
-+ ((blk_pos + blk_size) == card_sectors))
-+ blk_size--;
-+
-+ return blk_size;
-+}
-+
-+
-+static struct mmc_host_ops bcm2835_sdhost_ops = {
-+ .request = bcm2835_sdhost_request,
-+ .set_ios = bcm2835_sdhost_set_ios,
-+ .enable_sdio_irq = bcm2835_sdhost_enable_sdio_irq,
-+ .hw_reset = bcm2835_sdhost_reset,
-+ .multi_io_quirk = bcm2835_sdhost_multi_io_quirk,
-+};
-+
-+
-+static void bcm2835_sdhost_tasklet_finish(unsigned long param)
-+{
-+ struct bcm2835_host *host;
-+ unsigned long flags;
-+ struct mmc_request *mrq;
-+
-+ host = (struct bcm2835_host *)param;
-+
-+ spin_lock_irqsave(&host->lock, flags);
-+
-+ /*
-+ * If this tasklet gets rescheduled while running, it will
-+ * be run again afterwards but without any active request.
-+ */
-+ if (!host->mrq) {
-+ spin_unlock_irqrestore(&host->lock, flags);
-+ return;
-+ }
-+
-+ del_timer(&host->timer);
-+
-+ mrq = host->mrq;
-+
-+ /* Drop the overclock after any data corruption, or after any
-+ error overclocked */
-+ if (host->overclock) {
-+ if ((mrq->cmd && mrq->cmd->error) ||
-+ (mrq->data && mrq->data->error) ||
-+ (mrq->stop && mrq->stop->error)) {
-+ host->overclock_50--;
-+ pr_warn("%s: reducing overclock due to errors\n",
-+ mmc_hostname(host->mmc));
-+ bcm2835_sdhost_set_clock(host,50*MHZ);
-+ mrq->cmd->error = -EILSEQ;
-+ mrq->cmd->retries = 1;
-+ }
-+ }
-+
-+ host->mrq = NULL;
-+ host->cmd = NULL;
-+ host->data = NULL;
-+
-+ mmiowb();
-+
-+ spin_unlock_irqrestore(&host->lock, flags);
-+ mmc_request_done(host->mmc, mrq);
-+}
-+
-+
-+
-+int bcm2835_sdhost_add_host(struct bcm2835_host *host)
-+{
-+ struct mmc_host *mmc;
-+ struct dma_slave_config cfg;
-+ char pio_limit_string[20];
-+ int ret;
-+
-+ mmc = host->mmc;
-+
-+ bcm2835_sdhost_reset_internal(host);
-+
-+ mmc->f_max = host->max_clk;
-+ mmc->f_min = host->max_clk / SDCDIV_MAX_CDIV;
-+
-+ mmc->max_busy_timeout = (~(unsigned int)0)/(mmc->f_max/1000);
-+
-+ pr_debug("f_max %d, f_min %d, max_busy_timeout %d\n",
-+ mmc->f_max, mmc->f_min, mmc->max_busy_timeout);
-+
-+ /* host controller capabilities */
-+ mmc->caps |= /* MMC_CAP_SDIO_IRQ |*/ MMC_CAP_4_BIT_DATA |
-+ MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED |
-+ MMC_CAP_NEEDS_POLL | MMC_CAP_HW_RESET | MMC_CAP_ERASE |
-+ (ALLOW_CMD23 * MMC_CAP_CMD23);
-+
-+ spin_lock_init(&host->lock);
-+
-+ if (host->allow_dma) {
-+ if (IS_ERR_OR_NULL(host->dma_chan_tx) ||
-+ IS_ERR_OR_NULL(host->dma_chan_rx)) {
-+ pr_err("%s: unable to initialise DMA channels. "
-+ "Falling back to PIO\n",
-+ mmc_hostname(mmc));
-+ host->have_dma = false;
-+ } else {
-+ host->have_dma = true;
-+
-+ cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-+ cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-+ cfg.slave_id = 13; /* DREQ channel */
-+
-+ cfg.direction = DMA_MEM_TO_DEV;
-+ cfg.src_addr = 0;
-+ cfg.dst_addr = host->bus_addr + SDDATA;
-+ ret = dmaengine_slave_config(host->dma_chan_tx, &cfg);
-+
-+ cfg.direction = DMA_DEV_TO_MEM;
-+ cfg.src_addr = host->bus_addr + SDDATA;
-+ cfg.dst_addr = 0;
-+ ret = dmaengine_slave_config(host->dma_chan_rx, &cfg);
-+ }
-+ } else {
-+ host->have_dma = false;
-+ }
-+
-+ mmc->max_segs = 128;
-+ mmc->max_req_size = 524288;
-+ mmc->max_seg_size = mmc->max_req_size;
-+ mmc->max_blk_size = 512;
-+ mmc->max_blk_count = 65535;
-+
-+ /* report supported voltage ranges */
-+ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
-+
-+ tasklet_init(&host->finish_tasklet,
-+ bcm2835_sdhost_tasklet_finish, (unsigned long)host);
-+
-+ setup_timer(&host->timer, bcm2835_sdhost_timeout,
-+ (unsigned long)host);
-+
-+ setup_timer(&host->pio_timer, bcm2835_sdhost_pio_timeout,
-+ (unsigned long)host);
-+
-+ bcm2835_sdhost_init(host, 0);
-+ ret = request_threaded_irq(host->irq, bcm2835_sdhost_irq,
-+ bcm2835_sdhost_thread_irq,
-+ IRQF_SHARED, mmc_hostname(mmc), host);
-+ if (ret) {
-+ pr_err("%s: failed to request IRQ %d: %d\n",
-+ mmc_hostname(mmc), host->irq, ret);
-+ goto untasklet;
-+ }
-+
-+ mmiowb();
-+ mmc_add_host(mmc);
-+
-+ pio_limit_string[0] = '\0';
-+ if (host->have_dma && (host->pio_limit > 0))
-+ sprintf(pio_limit_string, " (>%d)", host->pio_limit);
-+ pr_info("%s: %s loaded - DMA %s%s\n",
-+ mmc_hostname(mmc), DRIVER_NAME,
-+ host->have_dma ? "enabled" : "disabled",
-+ pio_limit_string);
-+
-+ return 0;
-+
-+untasklet:
-+ tasklet_kill(&host->finish_tasklet);
-+
-+ return ret;
-+}
-+
-+static int bcm2835_sdhost_probe(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ struct device_node *node = dev->of_node;
-+ struct clk *clk;
-+ struct resource *iomem;
-+ struct bcm2835_host *host;
-+ struct mmc_host *mmc;
-+ const __be32 *addr;
-+ int ret;
-+
-+ pr_debug("bcm2835_sdhost_probe\n");
-+ mmc = mmc_alloc_host(sizeof(*host), dev);
-+ if (!mmc)
-+ return -ENOMEM;
-+
-+ mmc->ops = &bcm2835_sdhost_ops;
-+ host = mmc_priv(mmc);
-+ host->mmc = mmc;
-+ host->pio_timeout = msecs_to_jiffies(500);
-+ host->max_delay = 1; /* Warn if over 1ms */
-+ spin_lock_init(&host->lock);
-+
-+ iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ host->ioaddr = devm_ioremap_resource(dev, iomem);
-+ if (IS_ERR(host->ioaddr)) {
-+ ret = PTR_ERR(host->ioaddr);
-+ goto err;
-+ }
-+
-+ addr = of_get_address(node, 0, NULL, NULL);
-+ if (!addr) {
-+ dev_err(dev, "could not get DMA-register address\n");
-+ return -ENODEV;
-+ }
-+ host->bus_addr = be32_to_cpup(addr);
-+ pr_debug(" - ioaddr %lx, iomem->start %lx, bus_addr %lx\n",
-+ (unsigned long)host->ioaddr,
-+ (unsigned long)iomem->start,
-+ (unsigned long)host->bus_addr);
-+
-+ host->allow_dma = ALLOW_DMA;
-+
-+ if (node) {
-+ /* Read any custom properties */
-+ of_property_read_u32(node,
-+ "brcm,delay-after-stop",
-+ &host->delay_after_stop);
-+ of_property_read_u32(node,
-+ "brcm,overclock-50",
-+ &host->overclock_50);
-+ of_property_read_u32(node,
-+ "brcm,pio-limit",
-+ &host->pio_limit);
-+ host->allow_dma = ALLOW_DMA &&
-+ !of_property_read_bool(node, "brcm,force-pio");
-+ host->debug = of_property_read_bool(node, "brcm,debug");
-+ }
-+
-+ if (host->allow_dma) {
-+ if (node) {
-+ host->dma_chan_tx =
-+ dma_request_slave_channel(dev, "tx");
-+ host->dma_chan_rx =
-+ dma_request_slave_channel(dev, "rx");
-+ } else {
-+ dma_cap_mask_t mask;
-+
-+ dma_cap_zero(mask);
-+ /* we don't care about the channel, any would work */
-+ dma_cap_set(DMA_SLAVE, mask);
-+ host->dma_chan_tx =
-+ dma_request_channel(mask, NULL, NULL);
-+ host->dma_chan_rx =
-+ dma_request_channel(mask, NULL, NULL);
-+ }
-+ }
-+
-+ clk = devm_clk_get(dev, NULL);
-+ if (IS_ERR(clk)) {
-+ dev_err(dev, "could not get clk\n");
-+ ret = PTR_ERR(clk);
-+ goto err;
-+ }
-+
-+ host->max_clk = clk_get_rate(clk);
-+
-+ host->irq = platform_get_irq(pdev, 0);
-+ if (host->irq <= 0) {
-+ dev_err(dev, "get IRQ failed\n");
-+ ret = -EINVAL;
-+ goto err;
-+ }
-+
-+ pr_debug(" - max_clk %lx, irq %d\n",
-+ (unsigned long)host->max_clk,
-+ (int)host->irq);
-+
-+ if (node)
-+ mmc_of_parse(mmc);
-+ else
-+ mmc->caps |= MMC_CAP_4_BIT_DATA;
-+
-+ ret = bcm2835_sdhost_add_host(host);
-+ if (ret)
-+ goto err;
-+
-+ platform_set_drvdata(pdev, host);
-+
-+ pr_debug("bcm2835_sdhost_probe -> OK\n");
-+
-+ return 0;
-+
-+err:
-+ pr_debug("bcm2835_sdhost_probe -> err %d\n", ret);
-+ mmc_free_host(mmc);
-+
-+ return ret;
-+}
-+
-+static int bcm2835_sdhost_remove(struct platform_device *pdev)
-+{
-+ struct bcm2835_host *host = platform_get_drvdata(pdev);
-+
-+ pr_debug("bcm2835_sdhost_remove\n");
-+
-+ mmc_remove_host(host->mmc);
-+
-+ bcm2835_sdhost_set_power(host, false);
-+
-+ free_irq(host->irq, host);
-+
-+ del_timer_sync(&host->timer);
-+
-+ tasklet_kill(&host->finish_tasklet);
-+
-+ mmc_free_host(host->mmc);
-+ platform_set_drvdata(pdev, NULL);
-+
-+ pr_debug("bcm2835_sdhost_remove - OK\n");
-+ return 0;
-+}
-+
-+
-+static const struct of_device_id bcm2835_sdhost_match[] = {
-+ { .compatible = "brcm,bcm2835-sdhost" },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(of, bcm2835_sdhost_match);
-+
-+
-+
-+static struct platform_driver bcm2835_sdhost_driver = {
-+ .probe = bcm2835_sdhost_probe,
-+ .remove = bcm2835_sdhost_remove,
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ .of_match_table = bcm2835_sdhost_match,
-+ },
-+};
-+module_platform_driver(bcm2835_sdhost_driver);
-+
-+MODULE_ALIAS("platform:sdhost-bcm2835");
-+MODULE_DESCRIPTION("BCM2835 SDHost driver");
-+MODULE_LICENSE("GPL v2");
-+MODULE_AUTHOR("Phil Elwell");
diff --git a/target/linux/brcm2708/patches-4.4/0034-cma-Add-vc_cma-driver-to-enable-use-of-CMA.patch b/target/linux/brcm2708/patches-4.4/0034-cma-Add-vc_cma-driver-to-enable-use-of-CMA.patch
new file mode 100644
index 0000000000..e245f020d6
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0034-cma-Add-vc_cma-driver-to-enable-use-of-CMA.patch
@@ -0,0 +1,1326 @@
+From 663e08c7b0f8cefd880dfe1eb3641830dafa8b5a Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Wed, 3 Jul 2013 00:31:47 +0100
+Subject: [PATCH 034/381] cma: Add vc_cma driver to enable use of CMA
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: popcornmix <popcornmix@gmail.com>
+
+vc_cma: Make the vc_cma area the default contiguous DMA area
+
+vc_cma: Provide empty functions when module is not built
+
+Providing empty functions saves the users from guarding the
+function call with an #if clause.
+Move __init markings from prototypes to functions.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+---
+ drivers/char/Kconfig | 2 +
+ drivers/char/Makefile | 1 +
+ drivers/char/broadcom/Kconfig | 15 +
+ drivers/char/broadcom/Makefile | 1 +
+ drivers/char/broadcom/vc_cma/Makefile | 14 +
+ drivers/char/broadcom/vc_cma/vc_cma.c | 1193 +++++++++++++++++++++++++++++++++
+ include/linux/broadcom/vc_cma.h | 36 +
+ 7 files changed, 1262 insertions(+)
+ create mode 100644 drivers/char/broadcom/Kconfig
+ create mode 100644 drivers/char/broadcom/Makefile
+ create mode 100644 drivers/char/broadcom/vc_cma/Makefile
+ create mode 100644 drivers/char/broadcom/vc_cma/vc_cma.c
+ create mode 100644 include/linux/broadcom/vc_cma.h
+
+--- a/drivers/char/Kconfig
++++ b/drivers/char/Kconfig
+@@ -4,6 +4,8 @@
+
+ menu "Character devices"
+
++source "drivers/char/broadcom/Kconfig"
++
+ source "drivers/tty/Kconfig"
+
+ config DEVMEM
+--- a/drivers/char/Makefile
++++ b/drivers/char/Makefile
+@@ -60,3 +60,4 @@ js-rtc-y = rtc.o
+
+ obj-$(CONFIG_TILE_SROM) += tile-srom.o
+ obj-$(CONFIG_XILLYBUS) += xillybus/
++obj-$(CONFIG_BRCM_CHAR_DRIVERS) += broadcom/
+--- /dev/null
++++ b/drivers/char/broadcom/Kconfig
+@@ -0,0 +1,15 @@
++#
++# Broadcom char driver config
++#
++
++menuconfig BRCM_CHAR_DRIVERS
++ bool "Broadcom Char Drivers"
++ help
++ Broadcom's char drivers
++
++config BCM_VC_CMA
++ bool "Videocore CMA"
++ depends on CMA && BRCM_CHAR_DRIVERS && BCM2708_VCHIQ
++ default n
++ help
++ Helper for videocore CMA access.
+--- /dev/null
++++ b/drivers/char/broadcom/Makefile
+@@ -0,0 +1 @@
++obj-$(CONFIG_BCM_VC_CMA) += vc_cma/
+--- /dev/null
++++ b/drivers/char/broadcom/vc_cma/Makefile
+@@ -0,0 +1,14 @@
++ccflags-y += -Wall -Wstrict-prototypes -Wno-trigraphs
++ccflags-y += -Werror
++ccflags-y += -Iinclude/linux/broadcom
++ccflags-y += -Idrivers/misc/vc04_services
++ccflags-y += -Idrivers/misc/vc04_services/interface/vchi
++ccflags-y += -Idrivers/misc/vc04_services/interface/vchiq_arm
++
++ccflags-y += -D__KERNEL__
++ccflags-y += -D__linux__
++ccflags-y += -Werror
++
++obj-$(CONFIG_BCM_VC_CMA) += vc-cma.o
++
++vc-cma-objs := vc_cma.o
+--- /dev/null
++++ b/drivers/char/broadcom/vc_cma/vc_cma.c
+@@ -0,0 +1,1193 @@
++/**
++ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/kthread.h>
++#include <linux/fs.h>
++#include <linux/device.h>
++#include <linux/cdev.h>
++#include <linux/mm.h>
++#include <linux/proc_fs.h>
++#include <linux/seq_file.h>
++#include <linux/dma-mapping.h>
++#include <linux/dma-contiguous.h>
++#include <linux/platform_device.h>
++#include <linux/uaccess.h>
++#include <asm/cacheflush.h>
++
++#include "vc_cma.h"
++
++#include "vchiq_util.h"
++#include "vchiq_connected.h"
++//#include "debug_sym.h"
++//#include "vc_mem.h"
++
++#define DRIVER_NAME "vc-cma"
++
++#define LOG_DBG(fmt, ...) \
++ if (vc_cma_debug) \
++ printk(KERN_INFO fmt "\n", ##__VA_ARGS__)
++#define LOG_INFO(fmt, ...) \
++ printk(KERN_INFO fmt "\n", ##__VA_ARGS__)
++#define LOG_ERR(fmt, ...) \
++ printk(KERN_ERR fmt "\n", ##__VA_ARGS__)
++
++#define VC_CMA_FOURCC VCHIQ_MAKE_FOURCC('C', 'M', 'A', ' ')
++#define VC_CMA_VERSION 2
++
++#define VC_CMA_CHUNK_ORDER 6 /* 256K */
++#define VC_CMA_CHUNK_SIZE (4096 << VC_CMA_CHUNK_ORDER)
++#define VC_CMA_MAX_PARAMS_PER_MSG \
++ ((VCHIQ_MAX_MSG_SIZE - sizeof(unsigned short))/sizeof(unsigned short))
++#define VC_CMA_RESERVE_COUNT_MAX 16
++
++#define PAGES_PER_CHUNK (VC_CMA_CHUNK_SIZE / PAGE_SIZE)
++
++#define VCADDR_TO_PHYSADDR(vcaddr) (mm_vc_mem_phys_addr + vcaddr)
++
++#define loud_error(...) \
++ LOG_ERR("===== " __VA_ARGS__)
++
++enum {
++ VC_CMA_MSG_QUIT,
++ VC_CMA_MSG_OPEN,
++ VC_CMA_MSG_TICK,
++ VC_CMA_MSG_ALLOC, /* chunk count */
++ VC_CMA_MSG_FREE, /* chunk, chunk, ... */
++ VC_CMA_MSG_ALLOCATED, /* chunk, chunk, ... */
++ VC_CMA_MSG_REQUEST_ALLOC, /* chunk count */
++ VC_CMA_MSG_REQUEST_FREE, /* chunk count */
++ VC_CMA_MSG_RESERVE, /* bytes lo, bytes hi */
++ VC_CMA_MSG_UPDATE_RESERVE,
++ VC_CMA_MSG_MAX
++};
++
++struct cma_msg {
++ unsigned short type;
++ unsigned short params[VC_CMA_MAX_PARAMS_PER_MSG];
++};
++
++struct vc_cma_reserve_user {
++ unsigned int pid;
++ unsigned int reserve;
++};
++
++/* Device (/dev) related variables */
++static dev_t vc_cma_devnum;
++static struct class *vc_cma_class;
++static struct cdev vc_cma_cdev;
++static int vc_cma_inited;
++static int vc_cma_debug;
++
++/* Proc entry */
++static struct proc_dir_entry *vc_cma_proc_entry;
++
++phys_addr_t vc_cma_base;
++struct page *vc_cma_base_page;
++unsigned int vc_cma_size;
++EXPORT_SYMBOL(vc_cma_size);
++unsigned int vc_cma_initial;
++unsigned int vc_cma_chunks;
++unsigned int vc_cma_chunks_used;
++unsigned int vc_cma_chunks_reserved;
++
++
++void *vc_cma_dma_alloc;
++unsigned int vc_cma_dma_size;
++
++static int in_loud_error;
++
++unsigned int vc_cma_reserve_total;
++unsigned int vc_cma_reserve_count;
++struct vc_cma_reserve_user vc_cma_reserve_users[VC_CMA_RESERVE_COUNT_MAX];
++static DEFINE_SEMAPHORE(vc_cma_reserve_mutex);
++static DEFINE_SEMAPHORE(vc_cma_worker_queue_push_mutex);
++
++static u64 vc_cma_dma_mask = DMA_BIT_MASK(32);
++static struct platform_device vc_cma_device = {
++ .name = "vc-cma",
++ .id = 0,
++ .dev = {
++ .dma_mask = &vc_cma_dma_mask,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ },
++};
++
++static VCHIQ_INSTANCE_T cma_instance;
++static VCHIQ_SERVICE_HANDLE_T cma_service;
++static VCHIU_QUEUE_T cma_msg_queue;
++static struct task_struct *cma_worker;
++
++static int vc_cma_set_reserve(unsigned int reserve, unsigned int pid);
++static int vc_cma_alloc_chunks(int num_chunks, struct cma_msg *reply);
++static VCHIQ_STATUS_T cma_service_callback(VCHIQ_REASON_T reason,
++ VCHIQ_HEADER_T * header,
++ VCHIQ_SERVICE_HANDLE_T service,
++ void *bulk_userdata);
++static void send_vc_msg(unsigned short type,
++ unsigned short param1, unsigned short param2);
++static bool send_worker_msg(VCHIQ_HEADER_T * msg);
++
++static int early_vc_cma_mem(char *p)
++{
++ unsigned int new_size;
++ printk(KERN_NOTICE "early_vc_cma_mem(%s)", p);
++ vc_cma_size = memparse(p, &p);
++ vc_cma_initial = vc_cma_size;
++ if (*p == '/')
++ vc_cma_size = memparse(p + 1, &p);
++ if (*p == '@')
++ vc_cma_base = memparse(p + 1, &p);
++
++ new_size = (vc_cma_size - ((-vc_cma_base) & (VC_CMA_CHUNK_SIZE - 1)))
++ & ~(VC_CMA_CHUNK_SIZE - 1);
++ if (new_size > vc_cma_size)
++ vc_cma_size = 0;
++ vc_cma_initial = (vc_cma_initial + VC_CMA_CHUNK_SIZE - 1)
++ & ~(VC_CMA_CHUNK_SIZE - 1);
++ if (vc_cma_initial > vc_cma_size)
++ vc_cma_initial = vc_cma_size;
++ vc_cma_base = (vc_cma_base + VC_CMA_CHUNK_SIZE - 1)
++ & ~(VC_CMA_CHUNK_SIZE - 1);
++
++ printk(KERN_NOTICE " -> initial %x, size %x, base %x", vc_cma_initial,
++ vc_cma_size, (unsigned int)vc_cma_base);
++
++ return 0;
++}
++
++early_param("vc-cma-mem", early_vc_cma_mem);
++
++void __init vc_cma_early_init(void)
++{
++ LOG_DBG("vc_cma_early_init - vc_cma_chunks = %d", vc_cma_chunks);
++ if (vc_cma_size) {
++ int rc = platform_device_register(&vc_cma_device);
++ LOG_DBG("platform_device_register -> %d", rc);
++ }
++}
++
++void __init vc_cma_reserve(void)
++{
++ /* if vc_cma_size is set, then declare vc CMA area of the same
++ * size from the end of memory
++ */
++ if (vc_cma_size) {
++ if (dma_declare_contiguous(&vc_cma_device.dev, vc_cma_size,
++ vc_cma_base, 0) == 0) {
++ if (!dev_get_cma_area(NULL)) {
++ /* There is no default CMA area - make this
++ the default */
++ struct cma *vc_cma_area = dev_get_cma_area(
++ &vc_cma_device.dev);
++ dma_contiguous_set_default(vc_cma_area);
++ LOG_INFO("vc_cma_reserve - using vc_cma as "
++ "the default contiguous DMA area");
++ }
++ } else {
++ LOG_ERR("vc_cma: dma_declare_contiguous(%x,%x) failed",
++ vc_cma_size, (unsigned int)vc_cma_base);
++ vc_cma_size = 0;
++ }
++ }
++ vc_cma_chunks = vc_cma_size / VC_CMA_CHUNK_SIZE;
++}
++
++/****************************************************************************
++*
++* vc_cma_open
++*
++***************************************************************************/
++
++static int vc_cma_open(struct inode *inode, struct file *file)
++{
++ (void)inode;
++ (void)file;
++
++ return 0;
++}
++
++/****************************************************************************
++*
++* vc_cma_release
++*
++***************************************************************************/
++
++static int vc_cma_release(struct inode *inode, struct file *file)
++{
++ (void)inode;
++ (void)file;
++
++ vc_cma_set_reserve(0, current->tgid);
++
++ return 0;
++}
++
++/****************************************************************************
++*
++* vc_cma_ioctl
++*
++***************************************************************************/
++
++static long vc_cma_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
++{
++ int rc = 0;
++
++ (void)cmd;
++ (void)arg;
++
++ switch (cmd) {
++ case VC_CMA_IOC_RESERVE:
++ rc = vc_cma_set_reserve((unsigned int)arg, current->tgid);
++ if (rc >= 0)
++ rc = 0;
++ break;
++ default:
++ LOG_ERR("vc-cma: Unknown ioctl %x", cmd);
++ return -ENOTTY;
++ }
++
++ return rc;
++}
++
++/****************************************************************************
++*
++* File Operations for the driver.
++*
++***************************************************************************/
++
++static const struct file_operations vc_cma_fops = {
++ .owner = THIS_MODULE,
++ .open = vc_cma_open,
++ .release = vc_cma_release,
++ .unlocked_ioctl = vc_cma_ioctl,
++};
++
++/****************************************************************************
++*
++* vc_cma_proc_open
++*
++***************************************************************************/
++
++static int vc_cma_show_info(struct seq_file *m, void *v)
++{
++ int i;
++
++ seq_printf(m, "Videocore CMA:\n");
++ seq_printf(m, " Base : %08x\n", (unsigned int)vc_cma_base);
++ seq_printf(m, " Length : %08x\n", vc_cma_size);
++ seq_printf(m, " Initial : %08x\n", vc_cma_initial);
++ seq_printf(m, " Chunk size : %08x\n", VC_CMA_CHUNK_SIZE);
++ seq_printf(m, " Chunks : %4d (%d bytes)\n",
++ (int)vc_cma_chunks,
++ (int)(vc_cma_chunks * VC_CMA_CHUNK_SIZE));
++ seq_printf(m, " Used : %4d (%d bytes)\n",
++ (int)vc_cma_chunks_used,
++ (int)(vc_cma_chunks_used * VC_CMA_CHUNK_SIZE));
++ seq_printf(m, " Reserved : %4d (%d bytes)\n",
++ (unsigned int)vc_cma_chunks_reserved,
++ (int)(vc_cma_chunks_reserved * VC_CMA_CHUNK_SIZE));
++
++ for (i = 0; i < vc_cma_reserve_count; i++) {
++ struct vc_cma_reserve_user *user = &vc_cma_reserve_users[i];
++ seq_printf(m, " PID %5d: %d bytes\n", user->pid,
++ user->reserve);
++ }
++ seq_printf(m, " dma_alloc : %p (%d pages)\n",
++ vc_cma_dma_alloc ? page_address(vc_cma_dma_alloc) : 0,
++ vc_cma_dma_size);
++
++ seq_printf(m, "\n");
++
++ return 0;
++}
++
++static int vc_cma_proc_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, vc_cma_show_info, NULL);
++}
++
++/****************************************************************************
++*
++* vc_cma_proc_write
++*
++***************************************************************************/
++
++static int vc_cma_proc_write(struct file *file,
++ const char __user *buffer,
++ size_t size, loff_t *ppos)
++{
++ int rc = -EFAULT;
++ char input_str[20];
++
++ memset(input_str, 0, sizeof(input_str));
++
++ if (size > sizeof(input_str)) {
++ LOG_ERR("%s: input string length too long", __func__);
++ goto out;
++ }
++
++ if (copy_from_user(input_str, buffer, size - 1)) {
++ LOG_ERR("%s: failed to get input string", __func__);
++ goto out;
++ }
++#define ALLOC_STR "alloc"
++#define FREE_STR "free"
++#define DEBUG_STR "debug"
++#define RESERVE_STR "reserve"
++#define DMA_ALLOC_STR "dma_alloc"
++#define DMA_FREE_STR "dma_free"
++ if (strncmp(input_str, ALLOC_STR, strlen(ALLOC_STR)) == 0) {
++ int alloc_size;
++ char *p = input_str + strlen(ALLOC_STR);
++
++ while (*p == ' ')
++ p++;
++ alloc_size = memparse(p, NULL);
++ LOG_INFO("/proc/vc-cma: alloc %d", alloc_size);
++ if (alloc_size)
++ send_vc_msg(VC_CMA_MSG_REQUEST_FREE,
++ alloc_size / VC_CMA_CHUNK_SIZE, 0);
++ else
++ LOG_ERR("invalid size '%s'", p);
++ rc = size;
++ } else if (strncmp(input_str, FREE_STR, strlen(FREE_STR)) == 0) {
++ int alloc_size;
++ char *p = input_str + strlen(FREE_STR);
++
++ while (*p == ' ')
++ p++;
++ alloc_size = memparse(p, NULL);
++ LOG_INFO("/proc/vc-cma: free %d", alloc_size);
++ if (alloc_size)
++ send_vc_msg(VC_CMA_MSG_REQUEST_ALLOC,
++ alloc_size / VC_CMA_CHUNK_SIZE, 0);
++ else
++ LOG_ERR("invalid size '%s'", p);
++ rc = size;
++ } else if (strncmp(input_str, DEBUG_STR, strlen(DEBUG_STR)) == 0) {
++ char *p = input_str + strlen(DEBUG_STR);
++ while (*p == ' ')
++ p++;
++ if ((strcmp(p, "on") == 0) || (strcmp(p, "1") == 0))
++ vc_cma_debug = 1;
++ else if ((strcmp(p, "off") == 0) || (strcmp(p, "0") == 0))
++ vc_cma_debug = 0;
++ LOG_INFO("/proc/vc-cma: debug %s", vc_cma_debug ? "on" : "off");
++ rc = size;
++ } else if (strncmp(input_str, RESERVE_STR, strlen(RESERVE_STR)) == 0) {
++ int alloc_size;
++ int reserved;
++ char *p = input_str + strlen(RESERVE_STR);
++ while (*p == ' ')
++ p++;
++ alloc_size = memparse(p, NULL);
++
++ reserved = vc_cma_set_reserve(alloc_size, current->tgid);
++ rc = (reserved >= 0) ? size : reserved;
++ } else if (strncmp(input_str, DMA_ALLOC_STR, strlen(DMA_ALLOC_STR)) == 0) {
++ int alloc_size;
++ char *p = input_str + strlen(DMA_ALLOC_STR);
++ while (*p == ' ')
++ p++;
++ alloc_size = memparse(p, NULL);
++
++ if (vc_cma_dma_alloc) {
++ dma_release_from_contiguous(NULL, vc_cma_dma_alloc,
++ vc_cma_dma_size);
++ vc_cma_dma_alloc = NULL;
++ vc_cma_dma_size = 0;
++ }
++ vc_cma_dma_alloc = dma_alloc_from_contiguous(NULL, alloc_size, 0);
++ vc_cma_dma_size = (vc_cma_dma_alloc ? alloc_size : 0);
++ if (vc_cma_dma_alloc)
++ LOG_INFO("dma_alloc(%d pages) -> %p", alloc_size, page_address(vc_cma_dma_alloc));
++ else
++ LOG_ERR("dma_alloc(%d pages) failed", alloc_size);
++ rc = size;
++ } else if (strncmp(input_str, DMA_FREE_STR, strlen(DMA_FREE_STR)) == 0) {
++ if (vc_cma_dma_alloc) {
++ dma_release_from_contiguous(NULL, vc_cma_dma_alloc,
++ vc_cma_dma_size);
++ vc_cma_dma_alloc = NULL;
++ vc_cma_dma_size = 0;
++ }
++ rc = size;
++ }
++
++out:
++ return rc;
++}
++
++/****************************************************************************
++*
++* File Operations for /proc interface.
++*
++***************************************************************************/
++
++static const struct file_operations vc_cma_proc_fops = {
++ .open = vc_cma_proc_open,
++ .read = seq_read,
++ .write = vc_cma_proc_write,
++ .llseek = seq_lseek,
++ .release = single_release
++};
++
++static int vc_cma_set_reserve(unsigned int reserve, unsigned int pid)
++{
++ struct vc_cma_reserve_user *user = NULL;
++ int delta = 0;
++ int i;
++
++ if (down_interruptible(&vc_cma_reserve_mutex))
++ return -ERESTARTSYS;
++
++ for (i = 0; i < vc_cma_reserve_count; i++) {
++ if (pid == vc_cma_reserve_users[i].pid) {
++ user = &vc_cma_reserve_users[i];
++ delta = reserve - user->reserve;
++ if (reserve)
++ user->reserve = reserve;
++ else {
++ /* Remove this entry by copying downwards */
++ while ((i + 1) < vc_cma_reserve_count) {
++ user[0].pid = user[1].pid;
++ user[0].reserve = user[1].reserve;
++ user++;
++ i++;
++ }
++ vc_cma_reserve_count--;
++ user = NULL;
++ }
++ break;
++ }
++ }
++
++ if (reserve && !user) {
++ if (vc_cma_reserve_count == VC_CMA_RESERVE_COUNT_MAX) {
++ LOG_ERR("vc-cma: Too many reservations - "
++ "increase CMA_RESERVE_COUNT_MAX");
++ up(&vc_cma_reserve_mutex);
++ return -EBUSY;
++ }
++ user = &vc_cma_reserve_users[vc_cma_reserve_count];
++ user->pid = pid;
++ user->reserve = reserve;
++ delta = reserve;
++ vc_cma_reserve_count++;
++ }
++
++ vc_cma_reserve_total += delta;
++
++ send_vc_msg(VC_CMA_MSG_RESERVE,
++ vc_cma_reserve_total & 0xffff, vc_cma_reserve_total >> 16);
++
++ send_worker_msg((VCHIQ_HEADER_T *) VC_CMA_MSG_UPDATE_RESERVE);
++
++ LOG_DBG("/proc/vc-cma: reserve %d (PID %d) - total %u",
++ reserve, pid, vc_cma_reserve_total);
++
++ up(&vc_cma_reserve_mutex);
++
++ return vc_cma_reserve_total;
++}
++
++static VCHIQ_STATUS_T cma_service_callback(VCHIQ_REASON_T reason,
++ VCHIQ_HEADER_T * header,
++ VCHIQ_SERVICE_HANDLE_T service,
++ void *bulk_userdata)
++{
++ switch (reason) {
++ case VCHIQ_MESSAGE_AVAILABLE:
++ if (!send_worker_msg(header))
++ return VCHIQ_RETRY;
++ break;
++ case VCHIQ_SERVICE_CLOSED:
++ LOG_DBG("CMA service closed");
++ break;
++ default:
++ LOG_ERR("Unexpected CMA callback reason %d", reason);
++ break;
++ }
++ return VCHIQ_SUCCESS;
++}
++
++static void send_vc_msg(unsigned short type,
++ unsigned short param1, unsigned short param2)
++{
++ unsigned short msg[] = { type, param1, param2 };
++ VCHIQ_ELEMENT_T elem = { &msg, sizeof(msg) };
++ VCHIQ_STATUS_T ret;
++ vchiq_use_service(cma_service);
++ ret = vchiq_queue_message(cma_service, &elem, 1);
++ vchiq_release_service(cma_service);
++ if (ret != VCHIQ_SUCCESS)
++ LOG_ERR("vchiq_queue_message returned %x", ret);
++}
++
++static bool send_worker_msg(VCHIQ_HEADER_T * msg)
++{
++ if (down_interruptible(&vc_cma_worker_queue_push_mutex))
++ return false;
++ vchiu_queue_push(&cma_msg_queue, msg);
++ up(&vc_cma_worker_queue_push_mutex);
++ return true;
++}
++
++static int vc_cma_alloc_chunks(int num_chunks, struct cma_msg *reply)
++{
++ int i;
++ for (i = 0; i < num_chunks; i++) {
++ struct page *chunk;
++ unsigned int chunk_num;
++ uint8_t *chunk_addr;
++ size_t chunk_size = PAGES_PER_CHUNK << PAGE_SHIFT;
++
++ chunk = dma_alloc_from_contiguous(&vc_cma_device.dev,
++ PAGES_PER_CHUNK,
++ VC_CMA_CHUNK_ORDER);
++ if (!chunk)
++ break;
++
++ chunk_addr = page_address(chunk);
++ dmac_flush_range(chunk_addr, chunk_addr + chunk_size);
++ outer_inv_range(__pa(chunk_addr), __pa(chunk_addr) +
++ chunk_size);
++
++ chunk_num =
++ (page_to_phys(chunk) - vc_cma_base) / VC_CMA_CHUNK_SIZE;
++ BUG_ON(((page_to_phys(chunk) - vc_cma_base) %
++ VC_CMA_CHUNK_SIZE) != 0);
++ if (chunk_num >= vc_cma_chunks) {
++ phys_addr_t _pa = vc_cma_base + vc_cma_size - 1;
++ LOG_ERR("%s: ===============================",
++ __func__);
++ LOG_ERR("%s: chunk phys %x, vc_cma %pa-%pa - "
++ "bad SPARSEMEM configuration?",
++ __func__, (unsigned int)page_to_phys(chunk),
++ &vc_cma_base, &_pa);
++ LOG_ERR("%s: dev->cma_area = %p", __func__,
++ (void*)0/*vc_cma_device.dev.cma_area*/);
++ LOG_ERR("%s: ===============================",
++ __func__);
++ break;
++ }
++ reply->params[i] = chunk_num;
++ vc_cma_chunks_used++;
++ }
++
++ if (i < num_chunks) {
++ LOG_ERR("%s: dma_alloc_from_contiguous failed "
++ "for %x bytes (alloc %d of %d, %d free)",
++ __func__, VC_CMA_CHUNK_SIZE, i,
++ num_chunks, vc_cma_chunks - vc_cma_chunks_used);
++ num_chunks = i;
++ }
++
++ LOG_DBG("CMA allocated %d chunks -> %d used",
++ num_chunks, vc_cma_chunks_used);
++ reply->type = VC_CMA_MSG_ALLOCATED;
++
++ {
++ VCHIQ_ELEMENT_T elem = {
++ reply,
++ offsetof(struct cma_msg, params[0]) +
++ num_chunks * sizeof(reply->params[0])
++ };
++ VCHIQ_STATUS_T ret;
++ vchiq_use_service(cma_service);
++ ret = vchiq_queue_message(cma_service, &elem, 1);
++ vchiq_release_service(cma_service);
++ if (ret != VCHIQ_SUCCESS)
++ LOG_ERR("vchiq_queue_message return " "%x", ret);
++ }
++
++ return num_chunks;
++}
++
++static int cma_worker_proc(void *param)
++{
++ static struct cma_msg reply;
++ (void)param;
++
++ while (1) {
++ VCHIQ_HEADER_T *msg;
++ static struct cma_msg msg_copy;
++ struct cma_msg *cma_msg = &msg_copy;
++ int type, msg_size;
++
++ msg = vchiu_queue_pop(&cma_msg_queue);
++ if ((unsigned int)msg >= VC_CMA_MSG_MAX) {
++ msg_size = msg->size;
++ memcpy(&msg_copy, msg->data, msg_size);
++ type = cma_msg->type;
++ vchiq_release_message(cma_service, msg);
++ } else {
++ msg_size = 0;
++ type = (int)msg;
++ if (type == VC_CMA_MSG_QUIT)
++ break;
++ else if (type == VC_CMA_MSG_UPDATE_RESERVE) {
++ msg = NULL;
++ cma_msg = NULL;
++ } else {
++ BUG();
++ continue;
++ }
++ }
++
++ switch (type) {
++ case VC_CMA_MSG_ALLOC:{
++ int num_chunks, free_chunks;
++ num_chunks = cma_msg->params[0];
++ free_chunks =
++ vc_cma_chunks - vc_cma_chunks_used;
++ LOG_DBG("CMA_MSG_ALLOC(%d chunks)", num_chunks);
++ if (num_chunks > VC_CMA_MAX_PARAMS_PER_MSG) {
++ LOG_ERR
++ ("CMA_MSG_ALLOC - chunk count (%d) "
++ "exceeds VC_CMA_MAX_PARAMS_PER_MSG (%d)",
++ num_chunks,
++ VC_CMA_MAX_PARAMS_PER_MSG);
++ num_chunks = VC_CMA_MAX_PARAMS_PER_MSG;
++ }
++
++ if (num_chunks > free_chunks) {
++ LOG_ERR
++ ("CMA_MSG_ALLOC - chunk count (%d) "
++ "exceeds free chunks (%d)",
++ num_chunks, free_chunks);
++ num_chunks = free_chunks;
++ }
++
++ vc_cma_alloc_chunks(num_chunks, &reply);
++ }
++ break;
++
++ case VC_CMA_MSG_FREE:{
++ int chunk_count =
++ (msg_size -
++ offsetof(struct cma_msg,
++ params)) /
++ sizeof(cma_msg->params[0]);
++ int i;
++ BUG_ON(chunk_count <= 0);
++
++ LOG_DBG("CMA_MSG_FREE(%d chunks - %x, ...)",
++ chunk_count, cma_msg->params[0]);
++ for (i = 0; i < chunk_count; i++) {
++ int chunk_num = cma_msg->params[i];
++ struct page *page = vc_cma_base_page +
++ chunk_num * PAGES_PER_CHUNK;
++ if (chunk_num >= vc_cma_chunks) {
++ LOG_ERR
++ ("CMA_MSG_FREE - chunk %d of %d"
++ " (value %x) exceeds maximum "
++ "(%x)", i, chunk_count,
++ chunk_num,
++ vc_cma_chunks - 1);
++ break;
++ }
++
++ if (!dma_release_from_contiguous
++ (&vc_cma_device.dev, page,
++ PAGES_PER_CHUNK)) {
++ phys_addr_t _pa = page_to_phys(page);
++ LOG_ERR
++ ("CMA_MSG_FREE - failed to "
++ "release chunk %d (phys %pa, "
++ "page %x)", chunk_num,
++ &_pa,
++ (unsigned int)page);
++ }
++ vc_cma_chunks_used--;
++ }
++ LOG_DBG("CMA released %d chunks -> %d used",
++ i, vc_cma_chunks_used);
++ }
++ break;
++
++ case VC_CMA_MSG_UPDATE_RESERVE:{
++ int chunks_needed =
++ ((vc_cma_reserve_total + VC_CMA_CHUNK_SIZE -
++ 1)
++ / VC_CMA_CHUNK_SIZE) -
++ vc_cma_chunks_reserved;
++
++ LOG_DBG
++ ("CMA_MSG_UPDATE_RESERVE(%d chunks needed)",
++ chunks_needed);
++
++ /* Cap the reservations to what is available */
++ if (chunks_needed > 0) {
++ if (chunks_needed >
++ (vc_cma_chunks -
++ vc_cma_chunks_used))
++ chunks_needed =
++ (vc_cma_chunks -
++ vc_cma_chunks_used);
++
++ chunks_needed =
++ vc_cma_alloc_chunks(chunks_needed,
++ &reply);
++ }
++
++ LOG_DBG
++ ("CMA_MSG_UPDATE_RESERVE(%d chunks allocated)",
++ chunks_needed);
++ vc_cma_chunks_reserved += chunks_needed;
++ }
++ break;
++
++ default:
++ LOG_ERR("unexpected msg type %d", type);
++ break;
++ }
++ }
++
++ LOG_DBG("quitting...");
++ return 0;
++}
++
++/****************************************************************************
++*
++* vc_cma_connected_init
++*
++* This function is called once the videocore has been connected.
++*
++***************************************************************************/
++
++static void vc_cma_connected_init(void)
++{
++ VCHIQ_SERVICE_PARAMS_T service_params;
++
++ LOG_DBG("vc_cma_connected_init");
++
++ if (!vchiu_queue_init(&cma_msg_queue, 16)) {
++ LOG_ERR("could not create CMA msg queue");
++ goto fail_queue;
++ }
++
++ if (vchiq_initialise(&cma_instance) != VCHIQ_SUCCESS)
++ goto fail_vchiq_init;
++
++ vchiq_connect(cma_instance);
++
++ service_params.fourcc = VC_CMA_FOURCC;
++ service_params.callback = cma_service_callback;
++ service_params.userdata = NULL;
++ service_params.version = VC_CMA_VERSION;
++ service_params.version_min = VC_CMA_VERSION;
++
++ if (vchiq_open_service(cma_instance, &service_params,
++ &cma_service) != VCHIQ_SUCCESS) {
++ LOG_ERR("failed to open service - already in use?");
++ goto fail_vchiq_open;
++ }
++
++ vchiq_release_service(cma_service);
++
++ cma_worker = kthread_create(cma_worker_proc, NULL, "cma_worker");
++ if (!cma_worker) {
++ LOG_ERR("could not create CMA worker thread");
++ goto fail_worker;
++ }
++ set_user_nice(cma_worker, -20);
++ wake_up_process(cma_worker);
++
++ return;
++
++fail_worker:
++ vchiq_close_service(cma_service);
++fail_vchiq_open:
++ vchiq_shutdown(cma_instance);
++fail_vchiq_init:
++ vchiu_queue_delete(&cma_msg_queue);
++fail_queue:
++ return;
++}
++
++void
++loud_error_header(void)
++{
++ if (in_loud_error)
++ return;
++
++ LOG_ERR("============================================================"
++ "================");
++ LOG_ERR("============================================================"
++ "================");
++ LOG_ERR("=====");
++
++ in_loud_error = 1;
++}
++
++void
++loud_error_footer(void)
++{
++ if (!in_loud_error)
++ return;
++
++ LOG_ERR("=====");
++ LOG_ERR("============================================================"
++ "================");
++ LOG_ERR("============================================================"
++ "================");
++
++ in_loud_error = 0;
++}
++
++#if 1
++static int check_cma_config(void) { return 1; }
++#else
++static int
++read_vc_debug_var(VC_MEM_ACCESS_HANDLE_T handle,
++ const char *symbol,
++ void *buf, size_t bufsize)
++{
++ VC_MEM_ADDR_T vcMemAddr;
++ size_t vcMemSize;
++ uint8_t *mapAddr;
++ off_t vcMapAddr;
++
++ if (!LookupVideoCoreSymbol(handle, symbol,
++ &vcMemAddr,
++ &vcMemSize)) {
++ loud_error_header();
++ loud_error(
++ "failed to find VC symbol \"%s\".",
++ symbol);
++ loud_error_footer();
++ return 0;
++ }
++
++ if (vcMemSize != bufsize) {
++ loud_error_header();
++ loud_error(
++ "VC symbol \"%s\" is the wrong size.",
++ symbol);
++ loud_error_footer();
++ return 0;
++ }
++
++ vcMapAddr = (off_t)vcMemAddr & VC_MEM_TO_ARM_ADDR_MASK;
++ vcMapAddr += mm_vc_mem_phys_addr;
++ mapAddr = ioremap_nocache(vcMapAddr, vcMemSize);
++ if (mapAddr == 0) {
++ loud_error_header();
++ loud_error(
++ "failed to ioremap \"%s\" @ 0x%x "
++ "(phys: 0x%x, size: %u).",
++ symbol,
++ (unsigned int)vcMapAddr,
++ (unsigned int)vcMemAddr,
++ (unsigned int)vcMemSize);
++ loud_error_footer();
++ return 0;
++ }
++
++ memcpy(buf, mapAddr, bufsize);
++ iounmap(mapAddr);
++
++ return 1;
++}
++
++
++static int
++check_cma_config(void)
++{
++ VC_MEM_ACCESS_HANDLE_T mem_hndl;
++ VC_MEM_ADDR_T mempool_start;
++ VC_MEM_ADDR_T mempool_end;
++ VC_MEM_ADDR_T mempool_offline_start;
++ VC_MEM_ADDR_T mempool_offline_end;
++ VC_MEM_ADDR_T cam_alloc_base;
++ VC_MEM_ADDR_T cam_alloc_size;
++ VC_MEM_ADDR_T cam_alloc_end;
++ int success = 0;
++
++ if (OpenVideoCoreMemory(&mem_hndl) != 0)
++ goto out;
++
++ /* Read the relevant VideoCore variables */
++ if (!read_vc_debug_var(mem_hndl, "__MEMPOOL_START",
++ &mempool_start,
++ sizeof(mempool_start)))
++ goto close;
++
++ if (!read_vc_debug_var(mem_hndl, "__MEMPOOL_END",
++ &mempool_end,
++ sizeof(mempool_end)))
++ goto close;
++
++ if (!read_vc_debug_var(mem_hndl, "__MEMPOOL_OFFLINE_START",
++ &mempool_offline_start,
++ sizeof(mempool_offline_start)))
++ goto close;
++
++ if (!read_vc_debug_var(mem_hndl, "__MEMPOOL_OFFLINE_END",
++ &mempool_offline_end,
++ sizeof(mempool_offline_end)))
++ goto close;
++
++ if (!read_vc_debug_var(mem_hndl, "cam_alloc_base",
++ &cam_alloc_base,
++ sizeof(cam_alloc_base)))
++ goto close;
++
++ if (!read_vc_debug_var(mem_hndl, "cam_alloc_size",
++ &cam_alloc_size,
++ sizeof(cam_alloc_size)))
++ goto close;
++
++ cam_alloc_end = cam_alloc_base + cam_alloc_size;
++
++ success = 1;
++
++ /* Now the sanity checks */
++ if (!mempool_offline_start)
++ mempool_offline_start = mempool_start;
++ if (!mempool_offline_end)
++ mempool_offline_end = mempool_end;
++
++ if (VCADDR_TO_PHYSADDR(mempool_offline_start) != vc_cma_base) {
++ loud_error_header();
++ loud_error(
++ "__MEMPOOL_OFFLINE_START(%x -> %lx) doesn't match "
++ "vc_cma_base(%x)",
++ mempool_offline_start,
++ VCADDR_TO_PHYSADDR(mempool_offline_start),
++ vc_cma_base);
++ success = 0;
++ }
++
++ if (VCADDR_TO_PHYSADDR(mempool_offline_end) !=
++ (vc_cma_base + vc_cma_size)) {
++ loud_error_header();
++ loud_error(
++ "__MEMPOOL_OFFLINE_END(%x -> %lx) doesn't match "
++ "vc_cma_base(%x) + vc_cma_size(%x) = %x",
++ mempool_offline_start,
++ VCADDR_TO_PHYSADDR(mempool_offline_end),
++ vc_cma_base, vc_cma_size, vc_cma_base + vc_cma_size);
++ success = 0;
++ }
++
++ if (mempool_end < mempool_start) {
++ loud_error_header();
++ loud_error(
++ "__MEMPOOL_END(%x) must not be before "
++ "__MEMPOOL_START(%x)",
++ mempool_end,
++ mempool_start);
++ success = 0;
++ }
++
++ if (mempool_offline_end < mempool_offline_start) {
++ loud_error_header();
++ loud_error(
++ "__MEMPOOL_OFFLINE_END(%x) must not be before "
++ "__MEMPOOL_OFFLINE_START(%x)",
++ mempool_offline_end,
++ mempool_offline_start);
++ success = 0;
++ }
++
++ if (mempool_offline_start < mempool_start) {
++ loud_error_header();
++ loud_error(
++ "__MEMPOOL_OFFLINE_START(%x) must not be before "
++ "__MEMPOOL_START(%x)",
++ mempool_offline_start,
++ mempool_start);
++ success = 0;
++ }
++
++ if (mempool_offline_end > mempool_end) {
++ loud_error_header();
++ loud_error(
++ "__MEMPOOL_OFFLINE_END(%x) must not be after "
++ "__MEMPOOL_END(%x)",
++ mempool_offline_end,
++ mempool_end);
++ success = 0;
++ }
++
++ if ((cam_alloc_base < mempool_end) &&
++ (cam_alloc_end > mempool_start)) {
++ loud_error_header();
++ loud_error(
++ "cam_alloc pool(%x-%x) overlaps "
++ "mempool(%x-%x)",
++ cam_alloc_base, cam_alloc_end,
++ mempool_start, mempool_end);
++ success = 0;
++ }
++
++ loud_error_footer();
++
++close:
++ CloseVideoCoreMemory(mem_hndl);
++
++out:
++ return success;
++}
++#endif
++
++static int vc_cma_init(void)
++{
++ int rc = -EFAULT;
++ struct device *dev;
++
++ if (!check_cma_config())
++ goto out_release;
++
++ LOG_INFO("vc-cma: Videocore CMA driver");
++ LOG_INFO("vc-cma: vc_cma_base = %pa", &vc_cma_base);
++ LOG_INFO("vc-cma: vc_cma_size = 0x%08x (%u MiB)",
++ vc_cma_size, vc_cma_size / (1024 * 1024));
++ LOG_INFO("vc-cma: vc_cma_initial = 0x%08x (%u MiB)",
++ vc_cma_initial, vc_cma_initial / (1024 * 1024));
++
++ vc_cma_base_page = phys_to_page(vc_cma_base);
++
++ if (vc_cma_chunks) {
++ int chunks_needed = vc_cma_initial / VC_CMA_CHUNK_SIZE;
++
++ for (vc_cma_chunks_used = 0;
++ vc_cma_chunks_used < chunks_needed; vc_cma_chunks_used++) {
++ struct page *chunk;
++ chunk = dma_alloc_from_contiguous(&vc_cma_device.dev,
++ PAGES_PER_CHUNK,
++ VC_CMA_CHUNK_ORDER);
++ if (!chunk)
++ break;
++ BUG_ON(((page_to_phys(chunk) - vc_cma_base) %
++ VC_CMA_CHUNK_SIZE) != 0);
++ }
++ if (vc_cma_chunks_used != chunks_needed) {
++ LOG_ERR("%s: dma_alloc_from_contiguous failed (%d "
++ "bytes, allocation %d of %d)",
++ __func__, VC_CMA_CHUNK_SIZE,
++ vc_cma_chunks_used, chunks_needed);
++ goto out_release;
++ }
++
++ vchiq_add_connected_callback(vc_cma_connected_init);
++ }
++
++ rc = alloc_chrdev_region(&vc_cma_devnum, 0, 1, DRIVER_NAME);
++ if (rc < 0) {
++ LOG_ERR("%s: alloc_chrdev_region failed (rc=%d)", __func__, rc);
++ goto out_release;
++ }
++
++ cdev_init(&vc_cma_cdev, &vc_cma_fops);
++ rc = cdev_add(&vc_cma_cdev, vc_cma_devnum, 1);
++ if (rc != 0) {
++ LOG_ERR("%s: cdev_add failed (rc=%d)", __func__, rc);
++ goto out_unregister;
++ }
++
++ vc_cma_class = class_create(THIS_MODULE, DRIVER_NAME);
++ if (IS_ERR(vc_cma_class)) {
++ rc = PTR_ERR(vc_cma_class);
++ LOG_ERR("%s: class_create failed (rc=%d)", __func__, rc);
++ goto out_cdev_del;
++ }
++
++ dev = device_create(vc_cma_class, NULL, vc_cma_devnum, NULL,
++ DRIVER_NAME);
++ if (IS_ERR(dev)) {
++ rc = PTR_ERR(dev);
++ LOG_ERR("%s: device_create failed (rc=%d)", __func__, rc);
++ goto out_class_destroy;
++ }
++
++ vc_cma_proc_entry = proc_create(DRIVER_NAME, 0444, NULL, &vc_cma_proc_fops);
++ if (vc_cma_proc_entry == NULL) {
++ rc = -EFAULT;
++ LOG_ERR("%s: proc_create failed", __func__);
++ goto out_device_destroy;
++ }
++
++ vc_cma_inited = 1;
++ return 0;
++
++out_device_destroy:
++ device_destroy(vc_cma_class, vc_cma_devnum);
++
++out_class_destroy:
++ class_destroy(vc_cma_class);
++ vc_cma_class = NULL;
++
++out_cdev_del:
++ cdev_del(&vc_cma_cdev);
++
++out_unregister:
++ unregister_chrdev_region(vc_cma_devnum, 1);
++
++out_release:
++ /* It is tempting to try to clean up by calling
++ dma_release_from_contiguous for all allocated chunks, but it isn't
++ a very safe thing to do. If vc_cma_initial is non-zero it is because
++ VideoCore is already using that memory, so giving it back to Linux
++ is likely to be fatal.
++ */
++ return -1;
++}
++
++/****************************************************************************
++*
++* vc_cma_exit
++*
++***************************************************************************/
++
++static void __exit vc_cma_exit(void)
++{
++ LOG_DBG("%s: called", __func__);
++
++ if (vc_cma_inited) {
++ remove_proc_entry(DRIVER_NAME, NULL);
++ device_destroy(vc_cma_class, vc_cma_devnum);
++ class_destroy(vc_cma_class);
++ cdev_del(&vc_cma_cdev);
++ unregister_chrdev_region(vc_cma_devnum, 1);
++ }
++}
++
++module_init(vc_cma_init);
++module_exit(vc_cma_exit);
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Broadcom Corporation");
+--- /dev/null
++++ b/include/linux/broadcom/vc_cma.h
+@@ -0,0 +1,36 @@
++/*****************************************************************************
++* Copyright 2012 Broadcom Corporation. All rights reserved.
++*
++* Unless you and Broadcom execute a separate written software license
++* agreement governing use of this software, this software is licensed to you
++* under the terms of the GNU General Public License version 2, available at
++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
++*
++* Notwithstanding the above, under no circumstances may you combine this
++* software in any way with any other Broadcom software provided under a
++* license other than the GPL, without Broadcom's express prior written
++* consent.
++*****************************************************************************/
++
++#if !defined( VC_CMA_H )
++#define VC_CMA_H
++
++#include <linux/ioctl.h>
++
++#define VC_CMA_IOC_MAGIC 0xc5
++
++#define VC_CMA_IOC_RESERVE _IO(VC_CMA_IOC_MAGIC, 0)
++
++#ifdef __KERNEL__
++
++#ifdef CONFIG_BCM_VC_CMA
++void vc_cma_early_init(void);
++void vc_cma_reserve(void);
++#else
++static inline void vc_cma_early_init(void) { }
++static inline void vc_cma_reserve(void) { }
++#endif
++
++#endif
++
++#endif /* VC_CMA_H */
diff --git a/target/linux/brcm2708/patches-4.4/0035-bcm2708-alsa-sound-driver.patch b/target/linux/brcm2708/patches-4.4/0035-bcm2708-alsa-sound-driver.patch
new file mode 100644
index 0000000000..30659cf76b
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0035-bcm2708-alsa-sound-driver.patch
@@ -0,0 +1,2678 @@
+From b7b8ef3806db931be95bddf47946e27facc6d5dd Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Mon, 26 Mar 2012 22:15:50 +0100
+Subject: [PATCH 035/381] bcm2708: alsa sound driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: popcornmix <popcornmix@gmail.com>
+
+alsa: add mmap support and some cleanups to bcm2835 ALSA driver
+
+snd-bcm2835: Add support for spdif/hdmi passthrough
+
+This adds a dedicated subdevice which can be used for passthrough of non-audio
+formats (ie encoded a52) through the hdmi audio link. In addition to this
+driver extension an appropriate card config is required to make alsa-lib
+support the AES parameters for this device.
+
+snd-bcm2708: Add mutex, improve logging
+
+Fix for ALSA driver crash
+
+Avoids an issue when closing and opening vchiq where a message can arrive before service handle has been written
+
+alsa: reduce severity of expected warning message
+
+snd-bcm2708: Fix dmesg spam for non-error case
+
+alsa: Ensure mutexes are released through error paths
+
+alsa: Make interrupted close paths quieter
+
+BCM270x: Add onboard sound device to Device Tree
+
+Add Device Tree support to alsa driver.
+Add device to Device Tree.
+Don't add platform devices when booting in DT mode.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+---
+ sound/arm/Kconfig | 8 +
+ sound/arm/Makefile | 5 +
+ sound/arm/bcm2835-ctl.c | 323 +++++++++++++
+ sound/arm/bcm2835-pcm.c | 557 +++++++++++++++++++++++
+ sound/arm/bcm2835-vchiq.c | 902 +++++++++++++++++++++++++++++++++++++
+ sound/arm/bcm2835.c | 511 +++++++++++++++++++++
+ sound/arm/bcm2835.h | 167 +++++++
+ sound/arm/vc_vchi_audioserv_defs.h | 116 +++++
+ 8 files changed, 2589 insertions(+)
+ create mode 100755 sound/arm/bcm2835-ctl.c
+ create mode 100755 sound/arm/bcm2835-pcm.c
+ create mode 100755 sound/arm/bcm2835-vchiq.c
+ create mode 100644 sound/arm/bcm2835.c
+ create mode 100755 sound/arm/bcm2835.h
+ create mode 100644 sound/arm/vc_vchi_audioserv_defs.h
+
+--- a/sound/arm/Kconfig
++++ b/sound/arm/Kconfig
+@@ -40,5 +40,13 @@ config SND_PXA2XX_AC97
+ Say Y or M if you want to support any AC97 codec attached to
+ the PXA2xx AC97 interface.
+
++config SND_BCM2835
++ tristate "BCM2835 ALSA driver"
++ depends on (ARCH_BCM2708 || ARCH_BCM2709 || ARCH_BCM2835) \
++ && BCM2708_VCHIQ && SND
++ select SND_PCM
++ help
++ Say Y or M if you want to support BCM2835 Alsa pcm card driver
++
+ endif # SND_ARM
+
+--- a/sound/arm/Makefile
++++ b/sound/arm/Makefile
+@@ -14,3 +14,8 @@ snd-pxa2xx-lib-$(CONFIG_SND_PXA2XX_LIB_A
+
+ obj-$(CONFIG_SND_PXA2XX_AC97) += snd-pxa2xx-ac97.o
+ snd-pxa2xx-ac97-objs := pxa2xx-ac97.o
++
++obj-$(CONFIG_SND_BCM2835) += snd-bcm2835.o
++snd-bcm2835-objs := bcm2835.o bcm2835-ctl.o bcm2835-pcm.o bcm2835-vchiq.o
++
++ccflags-y += -Idrivers/misc/vc04_services -Idrivers/misc/vc04_services/interface/vcos/linuxkernel -D__VCCOREVER__=0x04000000
+--- /dev/null
++++ b/sound/arm/bcm2835-ctl.c
+@@ -0,0 +1,323 @@
++/*****************************************************************************
++* Copyright 2011 Broadcom Corporation. All rights reserved.
++*
++* Unless you and Broadcom execute a separate written software license
++* agreement governing use of this software, this software is licensed to you
++* under the terms of the GNU General Public License version 2, available at
++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
++*
++* Notwithstanding the above, under no circumstances may you combine this
++* software in any way with any other Broadcom software provided under a
++* license other than the GPL, without Broadcom's express prior written
++* consent.
++*****************************************************************************/
++
++#include <linux/platform_device.h>
++#include <linux/init.h>
++#include <linux/io.h>
++#include <linux/jiffies.h>
++#include <linux/slab.h>
++#include <linux/time.h>
++#include <linux/wait.h>
++#include <linux/delay.h>
++#include <linux/moduleparam.h>
++#include <linux/sched.h>
++
++#include <sound/core.h>
++#include <sound/control.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/rawmidi.h>
++#include <sound/initval.h>
++#include <sound/tlv.h>
++#include <sound/asoundef.h>
++
++#include "bcm2835.h"
++
++/* volume maximum and minimum in terms of 0.01dB */
++#define CTRL_VOL_MAX 400
++#define CTRL_VOL_MIN -10239 /* originally -10240 */
++
++
++static int snd_bcm2835_ctl_info(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_info *uinfo)
++{
++ audio_info(" ... IN\n");
++ if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
++ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
++ uinfo->count = 1;
++ uinfo->value.integer.min = CTRL_VOL_MIN;
++ uinfo->value.integer.max = CTRL_VOL_MAX; /* 2303 */
++ } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
++ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
++ uinfo->count = 1;
++ uinfo->value.integer.min = 0;
++ uinfo->value.integer.max = 1;
++ } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
++ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
++ uinfo->count = 1;
++ uinfo->value.integer.min = 0;
++ uinfo->value.integer.max = AUDIO_DEST_MAX-1;
++ }
++ audio_info(" ... OUT\n");
++ return 0;
++}
++
++/* toggles mute on or off depending on the value of nmute, and returns
++ * 1 if the mute value was changed, otherwise 0
++ */
++static int toggle_mute(struct bcm2835_chip *chip, int nmute)
++{
++ /* if settings are ok, just return 0 */
++ if(chip->mute == nmute)
++ return 0;
++
++ /* if the sound is muted then we need to unmute */
++ if(chip->mute == CTRL_VOL_MUTE)
++ {
++ chip->volume = chip->old_volume; /* copy the old volume back */
++ audio_info("Unmuting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
++ }
++ else /* otherwise we mute */
++ {
++ chip->old_volume = chip->volume;
++ chip->volume = 26214; /* set volume to minimum level AKA mute */
++ audio_info("Muting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
++ }
++
++ chip->mute = nmute;
++ return 1;
++}
++
++static int snd_bcm2835_ctl_get(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
++
++ BUG_ON(!chip && !(chip->avail_substreams & AVAIL_SUBSTREAMS_MASK));
++
++ if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
++ ucontrol->value.integer.value[0] = chip2alsa(chip->volume);
++ else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
++ ucontrol->value.integer.value[0] = chip->mute;
++ else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
++ ucontrol->value.integer.value[0] = chip->dest;
++
++ return 0;
++}
++
++static int snd_bcm2835_ctl_put(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
++ int changed = 0;
++
++ if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
++ audio_info("Volume change attempted.. volume = %d new_volume = %d\n", chip->volume, (int)ucontrol->value.integer.value[0]);
++ if (chip->mute == CTRL_VOL_MUTE) {
++ /* changed = toggle_mute(chip, CTRL_VOL_UNMUTE); */
++ return 1; /* should return 0 to signify no change but the mixer takes this as the opposite sign (no idea why) */
++ }
++ if (changed
++ || (ucontrol->value.integer.value[0] != chip2alsa(chip->volume))) {
++
++ chip->volume = alsa2chip(ucontrol->value.integer.value[0]);
++ changed = 1;
++ }
++
++ } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
++ /* Now implemented */
++ audio_info(" Mute attempted\n");
++ changed = toggle_mute(chip, ucontrol->value.integer.value[0]);
++
++ } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
++ if (ucontrol->value.integer.value[0] != chip->dest) {
++ chip->dest = ucontrol->value.integer.value[0];
++ changed = 1;
++ }
++ }
++
++ if (changed) {
++ if (bcm2835_audio_set_ctls(chip))
++ printk(KERN_ERR "Failed to set ALSA controls..\n");
++ }
++
++ return changed;
++}
++
++static DECLARE_TLV_DB_SCALE(snd_bcm2835_db_scale, CTRL_VOL_MIN, 1, 1);
++
++static struct snd_kcontrol_new snd_bcm2835_ctl[] = {
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "PCM Playback Volume",
++ .index = 0,
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
++ .private_value = PCM_PLAYBACK_VOLUME,
++ .info = snd_bcm2835_ctl_info,
++ .get = snd_bcm2835_ctl_get,
++ .put = snd_bcm2835_ctl_put,
++ .count = 1,
++ .tlv = {.p = snd_bcm2835_db_scale}
++ },
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "PCM Playback Switch",
++ .index = 0,
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
++ .private_value = PCM_PLAYBACK_MUTE,
++ .info = snd_bcm2835_ctl_info,
++ .get = snd_bcm2835_ctl_get,
++ .put = snd_bcm2835_ctl_put,
++ .count = 1,
++ },
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "PCM Playback Route",
++ .index = 0,
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
++ .private_value = PCM_PLAYBACK_DEVICE,
++ .info = snd_bcm2835_ctl_info,
++ .get = snd_bcm2835_ctl_get,
++ .put = snd_bcm2835_ctl_put,
++ .count = 1,
++ },
++};
++
++static int snd_bcm2835_spdif_default_info(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_info *uinfo)
++{
++ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
++ uinfo->count = 1;
++ return 0;
++}
++
++static int snd_bcm2835_spdif_default_get(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
++ int i;
++
++ for (i = 0; i < 4; i++)
++ ucontrol->value.iec958.status[i] =
++ (chip->spdif_status >> (i * 8)) && 0xff;
++
++ return 0;
++}
++
++static int snd_bcm2835_spdif_default_put(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
++ unsigned int val = 0;
++ int i, change;
++
++ for (i = 0; i < 4; i++)
++ val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
++
++ change = val != chip->spdif_status;
++ chip->spdif_status = val;
++
++ return change;
++}
++
++static int snd_bcm2835_spdif_mask_info(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_info *uinfo)
++{
++ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
++ uinfo->count = 1;
++ return 0;
++}
++
++static int snd_bcm2835_spdif_mask_get(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ /* bcm2835 supports only consumer mode and sets all other format flags
++ * automatically. So the only thing left is signalling non-audio
++ * content */
++ ucontrol->value.iec958.status[0] = IEC958_AES0_NONAUDIO;
++ return 0;
++}
++
++static int snd_bcm2835_spdif_stream_info(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_info *uinfo)
++{
++ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
++ uinfo->count = 1;
++ return 0;
++}
++
++static int snd_bcm2835_spdif_stream_get(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
++ int i;
++
++ for (i = 0; i < 4; i++)
++ ucontrol->value.iec958.status[i] =
++ (chip->spdif_status >> (i * 8)) & 0xff;
++ return 0;
++}
++
++static int snd_bcm2835_spdif_stream_put(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
++ unsigned int val = 0;
++ int i, change;
++
++ for (i = 0; i < 4; i++)
++ val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
++ change = val != chip->spdif_status;
++ chip->spdif_status = val;
++
++ return change;
++}
++
++static struct snd_kcontrol_new snd_bcm2835_spdif[] = {
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
++ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
++ .info = snd_bcm2835_spdif_default_info,
++ .get = snd_bcm2835_spdif_default_get,
++ .put = snd_bcm2835_spdif_default_put
++ },
++ {
++ .access = SNDRV_CTL_ELEM_ACCESS_READ,
++ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
++ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
++ .info = snd_bcm2835_spdif_mask_info,
++ .get = snd_bcm2835_spdif_mask_get,
++ },
++ {
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_INACTIVE,
++ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
++ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM),
++ .info = snd_bcm2835_spdif_stream_info,
++ .get = snd_bcm2835_spdif_stream_get,
++ .put = snd_bcm2835_spdif_stream_put,
++ },
++};
++
++int snd_bcm2835_new_ctl(bcm2835_chip_t * chip)
++{
++ int err;
++ unsigned int idx;
++
++ strcpy(chip->card->mixername, "Broadcom Mixer");
++ for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_ctl); idx++) {
++ err =
++ snd_ctl_add(chip->card,
++ snd_ctl_new1(&snd_bcm2835_ctl[idx], chip));
++ if (err < 0)
++ return err;
++ }
++ for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_spdif); idx++) {
++ err = snd_ctl_add(chip->card,
++ snd_ctl_new1(&snd_bcm2835_spdif[idx], chip));
++ if (err < 0)
++ return err;
++ }
++ return 0;
++}
+--- /dev/null
++++ b/sound/arm/bcm2835-pcm.c
+@@ -0,0 +1,557 @@
++/*****************************************************************************
++* Copyright 2011 Broadcom Corporation. All rights reserved.
++*
++* Unless you and Broadcom execute a separate written software license
++* agreement governing use of this software, this software is licensed to you
++* under the terms of the GNU General Public License version 2, available at
++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
++*
++* Notwithstanding the above, under no circumstances may you combine this
++* software in any way with any other Broadcom software provided under a
++* license other than the GPL, without Broadcom's express prior written
++* consent.
++*****************************************************************************/
++
++#include <linux/interrupt.h>
++#include <linux/slab.h>
++
++#include <sound/asoundef.h>
++
++#include "bcm2835.h"
++
++/* hardware definition */
++static struct snd_pcm_hardware snd_bcm2835_playback_hw = {
++ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
++ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
++ .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
++ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
++ .rate_min = 8000,
++ .rate_max = 48000,
++ .channels_min = 1,
++ .channels_max = 2,
++ .buffer_bytes_max = 128 * 1024,
++ .period_bytes_min = 1 * 1024,
++ .period_bytes_max = 128 * 1024,
++ .periods_min = 1,
++ .periods_max = 128,
++};
++
++static struct snd_pcm_hardware snd_bcm2835_playback_spdif_hw = {
++ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
++ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
++ .formats = SNDRV_PCM_FMTBIT_S16_LE,
++ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_44100 |
++ SNDRV_PCM_RATE_48000,
++ .rate_min = 44100,
++ .rate_max = 48000,
++ .channels_min = 2,
++ .channels_max = 2,
++ .buffer_bytes_max = 128 * 1024,
++ .period_bytes_min = 1 * 1024,
++ .period_bytes_max = 128 * 1024,
++ .periods_min = 1,
++ .periods_max = 128,
++};
++
++static void snd_bcm2835_playback_free(struct snd_pcm_runtime *runtime)
++{
++ audio_info("Freeing up alsa stream here ..\n");
++ if (runtime->private_data)
++ kfree(runtime->private_data);
++ runtime->private_data = NULL;
++}
++
++static irqreturn_t bcm2835_playback_fifo_irq(int irq, void *dev_id)
++{
++ bcm2835_alsa_stream_t *alsa_stream = (bcm2835_alsa_stream_t *) dev_id;
++ uint32_t consumed = 0;
++ int new_period = 0;
++
++ audio_info(" .. IN\n");
++
++ audio_info("alsa_stream=%p substream=%p\n", alsa_stream,
++ alsa_stream ? alsa_stream->substream : 0);
++
++ if (alsa_stream->open)
++ consumed = bcm2835_audio_retrieve_buffers(alsa_stream);
++
++ /* We get called only if playback was triggered, So, the number of buffers we retrieve in
++ * each iteration are the buffers that have been played out already
++ */
++
++ if (alsa_stream->period_size) {
++ if ((alsa_stream->pos / alsa_stream->period_size) !=
++ ((alsa_stream->pos + consumed) / alsa_stream->period_size))
++ new_period = 1;
++ }
++ audio_debug("updating pos cur: %d + %d max:%d period_bytes:%d, hw_ptr: %d new_period:%d\n",
++ alsa_stream->pos,
++ consumed,
++ alsa_stream->buffer_size,
++ (int)(alsa_stream->period_size*alsa_stream->substream->runtime->periods),
++ frames_to_bytes(alsa_stream->substream->runtime, alsa_stream->substream->runtime->status->hw_ptr),
++ new_period);
++ if (alsa_stream->buffer_size) {
++ alsa_stream->pos += consumed &~ (1<<30);
++ alsa_stream->pos %= alsa_stream->buffer_size;
++ }
++
++ if (alsa_stream->substream) {
++ if (new_period)
++ snd_pcm_period_elapsed(alsa_stream->substream);
++ } else {
++ audio_warning(" unexpected NULL substream\n");
++ }
++ audio_info(" .. OUT\n");
++
++ return IRQ_HANDLED;
++}
++
++/* open callback */
++static int snd_bcm2835_playback_open_generic(
++ struct snd_pcm_substream *substream, int spdif)
++{
++ bcm2835_chip_t *chip = snd_pcm_substream_chip(substream);
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ bcm2835_alsa_stream_t *alsa_stream;
++ int idx;
++ int err;
++
++ audio_info(" .. IN (%d)\n", substream->number);
++
++ if(mutex_lock_interruptible(&chip->audio_mutex))
++ {
++ audio_error("Interrupted whilst waiting for lock\n");
++ return -EINTR;
++ }
++ audio_info("Alsa open (%d)\n", substream->number);
++ idx = substream->number;
++
++ if (spdif && chip->opened != 0) {
++ err = -EBUSY;
++ goto out;
++ }
++ else if (!spdif && (chip->opened & (1 << idx))) {
++ err = -EBUSY;
++ goto out;
++ }
++ if (idx > MAX_SUBSTREAMS) {
++ audio_error
++ ("substream(%d) device doesn't exist max(%d) substreams allowed\n",
++ idx, MAX_SUBSTREAMS);
++ err = -ENODEV;
++ goto out;
++ }
++
++ /* Check if we are ready */
++ if (!(chip->avail_substreams & (1 << idx))) {
++ /* We are not ready yet */
++ audio_error("substream(%d) device is not ready yet\n", idx);
++ err = -EAGAIN;
++ goto out;
++ }
++
++ alsa_stream = kzalloc(sizeof(bcm2835_alsa_stream_t), GFP_KERNEL);
++ if (alsa_stream == NULL) {
++ err = -ENOMEM;
++ goto out;
++ }
++
++ /* Initialise alsa_stream */
++ alsa_stream->chip = chip;
++ alsa_stream->substream = substream;
++ alsa_stream->idx = idx;
++
++ sema_init(&alsa_stream->buffers_update_sem, 0);
++ sema_init(&alsa_stream->control_sem, 0);
++ spin_lock_init(&alsa_stream->lock);
++
++ /* Enabled in start trigger, called on each "fifo irq" after that */
++ alsa_stream->enable_fifo_irq = 0;
++ alsa_stream->fifo_irq_handler = bcm2835_playback_fifo_irq;
++
++ err = bcm2835_audio_open(alsa_stream);
++ if (err != 0) {
++ kfree(alsa_stream);
++ goto out;
++ }
++ runtime->private_data = alsa_stream;
++ runtime->private_free = snd_bcm2835_playback_free;
++ if (spdif) {
++ runtime->hw = snd_bcm2835_playback_spdif_hw;
++ } else {
++ /* clear spdif status, as we are not in spdif mode */
++ chip->spdif_status = 0;
++ runtime->hw = snd_bcm2835_playback_hw;
++ }
++ /* minimum 16 bytes alignment (for vchiq bulk transfers) */
++ snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
++ 16);
++
++ chip->alsa_stream[idx] = alsa_stream;
++
++ chip->opened |= (1 << idx);
++ alsa_stream->open = 1;
++ alsa_stream->draining = 1;
++
++out:
++ mutex_unlock(&chip->audio_mutex);
++
++ audio_info(" .. OUT =%d\n", err);
++
++ return err;
++}
++
++static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream)
++{
++ return snd_bcm2835_playback_open_generic(substream, 0);
++}
++
++static int snd_bcm2835_playback_spdif_open(struct snd_pcm_substream *substream)
++{
++ return snd_bcm2835_playback_open_generic(substream, 1);
++}
++
++/* close callback */
++static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream)
++{
++ /* the hardware-specific codes will be here */
++
++ bcm2835_chip_t *chip;
++ struct snd_pcm_runtime *runtime;
++ bcm2835_alsa_stream_t *alsa_stream;
++
++ audio_info(" .. IN\n");
++
++ chip = snd_pcm_substream_chip(substream);
++ if(mutex_lock_interruptible(&chip->audio_mutex))
++ {
++ audio_error("Interrupted whilst waiting for lock\n");
++ return -EINTR;
++ }
++ runtime = substream->runtime;
++ alsa_stream = runtime->private_data;
++
++ audio_info("Alsa close\n");
++
++ /*
++ * Call stop if it's still running. This happens when app
++ * is force killed and we don't get a stop trigger.
++ */
++ if (alsa_stream->running) {
++ int err;
++ err = bcm2835_audio_stop(alsa_stream);
++ alsa_stream->running = 0;
++ if (err != 0)
++ audio_error(" Failed to STOP alsa device\n");
++ }
++
++ alsa_stream->period_size = 0;
++ alsa_stream->buffer_size = 0;
++
++ if (alsa_stream->open) {
++ alsa_stream->open = 0;
++ bcm2835_audio_close(alsa_stream);
++ }
++ if (alsa_stream->chip)
++ alsa_stream->chip->alsa_stream[alsa_stream->idx] = NULL;
++ /*
++ * Do not free up alsa_stream here, it will be freed up by
++ * runtime->private_free callback we registered in *_open above
++ */
++
++ chip->opened &= ~(1 << substream->number);
++
++ mutex_unlock(&chip->audio_mutex);
++ audio_info(" .. OUT\n");
++
++ return 0;
++}
++
++/* hw_params callback */
++static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params)
++{
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
++ int err;
++
++ audio_info(" .. IN\n");
++
++ err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
++ if (err < 0) {
++ audio_error
++ (" pcm_lib_malloc failed to allocated pages for buffers\n");
++ return err;
++ }
++
++ alsa_stream->channels = params_channels(params);
++ alsa_stream->params_rate = params_rate(params);
++ alsa_stream->pcm_format_width = snd_pcm_format_width(params_format (params));
++ audio_info(" .. OUT\n");
++
++ return err;
++}
++
++/* hw_free callback */
++static int snd_bcm2835_pcm_hw_free(struct snd_pcm_substream *substream)
++{
++ audio_info(" .. IN\n");
++ return snd_pcm_lib_free_pages(substream);
++}
++
++/* prepare callback */
++static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
++{
++ bcm2835_chip_t *chip = snd_pcm_substream_chip(substream);
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
++ int channels;
++ int err;
++
++ audio_info(" .. IN\n");
++
++ /* notify the vchiq that it should enter spdif passthrough mode by
++ * setting channels=0 (see
++ * https://github.com/raspberrypi/linux/issues/528) */
++ if (chip->spdif_status & IEC958_AES0_NONAUDIO)
++ channels = 0;
++ else
++ channels = alsa_stream->channels;
++
++ err = bcm2835_audio_set_params(alsa_stream, channels,
++ alsa_stream->params_rate,
++ alsa_stream->pcm_format_width);
++ if (err < 0) {
++ audio_error(" error setting hw params\n");
++ }
++
++ bcm2835_audio_setup(alsa_stream);
++
++ /* in preparation of the stream, set the controls (volume level) of the stream */
++ bcm2835_audio_set_ctls(alsa_stream->chip);
++
++
++ memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
++
++ alsa_stream->pcm_indirect.hw_buffer_size =
++ alsa_stream->pcm_indirect.sw_buffer_size =
++ snd_pcm_lib_buffer_bytes(substream);
++
++ alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
++ alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
++ alsa_stream->pos = 0;
++
++ audio_debug("buffer_size=%d, period_size=%d pos=%d frame_bits=%d\n",
++ alsa_stream->buffer_size, alsa_stream->period_size,
++ alsa_stream->pos, runtime->frame_bits);
++
++ audio_info(" .. OUT\n");
++ return 0;
++}
++
++static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream,
++ struct snd_pcm_indirect *rec, size_t bytes)
++{
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
++ void *src = (void *)(substream->runtime->dma_area + rec->sw_data);
++ int err;
++
++ err = bcm2835_audio_write(alsa_stream, bytes, src);
++ if (err)
++ audio_error(" Failed to transfer to alsa device (%d)\n", err);
++
++}
++
++static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream)
++{
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
++ struct snd_pcm_indirect *pcm_indirect = &alsa_stream->pcm_indirect;
++
++ pcm_indirect->hw_queue_size = runtime->hw.buffer_bytes_max;
++ snd_pcm_indirect_playback_transfer(substream, pcm_indirect,
++ snd_bcm2835_pcm_transfer);
++ return 0;
++}
++
++/* trigger callback */
++static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
++{
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
++ int err = 0;
++
++ audio_info(" .. IN\n");
++
++ switch (cmd) {
++ case SNDRV_PCM_TRIGGER_START:
++ audio_debug("bcm2835_AUDIO_TRIGGER_START running=%d\n",
++ alsa_stream->running);
++ if (!alsa_stream->running) {
++ err = bcm2835_audio_start(alsa_stream);
++ if (err == 0) {
++ alsa_stream->pcm_indirect.hw_io =
++ alsa_stream->pcm_indirect.hw_data =
++ bytes_to_frames(runtime,
++ alsa_stream->pos);
++ substream->ops->ack(substream);
++ alsa_stream->running = 1;
++ alsa_stream->draining = 1;
++ } else {
++ audio_error(" Failed to START alsa device (%d)\n", err);
++ }
++ }
++ break;
++ case SNDRV_PCM_TRIGGER_STOP:
++ audio_debug
++ ("bcm2835_AUDIO_TRIGGER_STOP running=%d draining=%d\n",
++ alsa_stream->running, runtime->status->state == SNDRV_PCM_STATE_DRAINING);
++ if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
++ audio_info("DRAINING\n");
++ alsa_stream->draining = 1;
++ } else {
++ audio_info("DROPPING\n");
++ alsa_stream->draining = 0;
++ }
++ if (alsa_stream->running) {
++ err = bcm2835_audio_stop(alsa_stream);
++ if (err != 0)
++ audio_error(" Failed to STOP alsa device (%d)\n", err);
++ alsa_stream->running = 0;
++ }
++ break;
++ default:
++ err = -EINVAL;
++ }
++
++ audio_info(" .. OUT\n");
++ return err;
++}
++
++/* pointer callback */
++static snd_pcm_uframes_t
++snd_bcm2835_pcm_pointer(struct snd_pcm_substream *substream)
++{
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
++
++ audio_info(" .. IN\n");
++
++ audio_debug("pcm_pointer... (%d) hwptr=%d appl=%d pos=%d\n", 0,
++ frames_to_bytes(runtime, runtime->status->hw_ptr),
++ frames_to_bytes(runtime, runtime->control->appl_ptr),
++ alsa_stream->pos);
++
++ audio_info(" .. OUT\n");
++ return snd_pcm_indirect_playback_pointer(substream,
++ &alsa_stream->pcm_indirect,
++ alsa_stream->pos);
++}
++
++static int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream,
++ unsigned int cmd, void *arg)
++{
++ int ret = snd_pcm_lib_ioctl(substream, cmd, arg);
++ audio_info(" .. substream=%p, cmd=%d, arg=%p (%x) ret=%d\n", substream,
++ cmd, arg, arg ? *(unsigned *)arg : 0, ret);
++ return ret;
++}
++
++/* operators */
++static struct snd_pcm_ops snd_bcm2835_playback_ops = {
++ .open = snd_bcm2835_playback_open,
++ .close = snd_bcm2835_playback_close,
++ .ioctl = snd_bcm2835_pcm_lib_ioctl,
++ .hw_params = snd_bcm2835_pcm_hw_params,
++ .hw_free = snd_bcm2835_pcm_hw_free,
++ .prepare = snd_bcm2835_pcm_prepare,
++ .trigger = snd_bcm2835_pcm_trigger,
++ .pointer = snd_bcm2835_pcm_pointer,
++ .ack = snd_bcm2835_pcm_ack,
++};
++
++static struct snd_pcm_ops snd_bcm2835_playback_spdif_ops = {
++ .open = snd_bcm2835_playback_spdif_open,
++ .close = snd_bcm2835_playback_close,
++ .ioctl = snd_bcm2835_pcm_lib_ioctl,
++ .hw_params = snd_bcm2835_pcm_hw_params,
++ .hw_free = snd_bcm2835_pcm_hw_free,
++ .prepare = snd_bcm2835_pcm_prepare,
++ .trigger = snd_bcm2835_pcm_trigger,
++ .pointer = snd_bcm2835_pcm_pointer,
++ .ack = snd_bcm2835_pcm_ack,
++};
++
++/* create a pcm device */
++int snd_bcm2835_new_pcm(bcm2835_chip_t * chip)
++{
++ struct snd_pcm *pcm;
++ int err;
++
++ audio_info(" .. IN\n");
++ mutex_init(&chip->audio_mutex);
++ if(mutex_lock_interruptible(&chip->audio_mutex))
++ {
++ audio_error("Interrupted whilst waiting for lock\n");
++ return -EINTR;
++ }
++ err =
++ snd_pcm_new(chip->card, "bcm2835 ALSA", 0, MAX_SUBSTREAMS, 0, &pcm);
++ if (err < 0)
++ goto out;
++ pcm->private_data = chip;
++ strcpy(pcm->name, "bcm2835 ALSA");
++ chip->pcm = pcm;
++ chip->dest = AUDIO_DEST_AUTO;
++ chip->volume = alsa2chip(0);
++ chip->mute = CTRL_VOL_UNMUTE; /*disable mute on startup */
++ /* set operators */
++ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
++ &snd_bcm2835_playback_ops);
++
++ /* pre-allocation of buffers */
++ /* NOTE: this may fail */
++ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
++ snd_dma_continuous_data
++ (GFP_KERNEL), 64 * 1024,
++ 64 * 1024);
++
++out:
++ mutex_unlock(&chip->audio_mutex);
++ audio_info(" .. OUT\n");
++
++ return 0;
++}
++
++int snd_bcm2835_new_spdif_pcm(bcm2835_chip_t * chip)
++{
++ struct snd_pcm *pcm;
++ int err;
++
++ audio_info(" .. IN\n");
++ if(mutex_lock_interruptible(&chip->audio_mutex))
++ {
++ audio_error("Interrupted whilst waiting for lock\n");
++ return -EINTR;
++ }
++ err = snd_pcm_new(chip->card, "bcm2835 ALSA", 1, 1, 0, &pcm);
++ if (err < 0)
++ goto out;
++
++ pcm->private_data = chip;
++ strcpy(pcm->name, "bcm2835 IEC958/HDMI");
++ chip->pcm_spdif = pcm;
++ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
++ &snd_bcm2835_playback_spdif_ops);
++
++ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
++ snd_dma_continuous_data (GFP_KERNEL),
++ 64 * 1024, 64 * 1024);
++out:
++ mutex_unlock(&chip->audio_mutex);
++ audio_info(" .. OUT\n");
++
++ return 0;
++}
+--- /dev/null
++++ b/sound/arm/bcm2835-vchiq.c
+@@ -0,0 +1,902 @@
++/*****************************************************************************
++* Copyright 2011 Broadcom Corporation. All rights reserved.
++*
++* Unless you and Broadcom execute a separate written software license
++* agreement governing use of this software, this software is licensed to you
++* under the terms of the GNU General Public License version 2, available at
++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
++*
++* Notwithstanding the above, under no circumstances may you combine this
++* software in any way with any other Broadcom software provided under a
++* license other than the GPL, without Broadcom's express prior written
++* consent.
++*****************************************************************************/
++
++#include <linux/device.h>
++#include <sound/core.h>
++#include <sound/initval.h>
++#include <sound/pcm.h>
++#include <linux/io.h>
++#include <linux/interrupt.h>
++#include <linux/fs.h>
++#include <linux/file.h>
++#include <linux/mm.h>
++#include <linux/syscalls.h>
++#include <asm/uaccess.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <linux/atomic.h>
++#include <linux/module.h>
++#include <linux/completion.h>
++
++#include "bcm2835.h"
++
++/* ---- Include Files -------------------------------------------------------- */
++
++#include "interface/vchi/vchi.h"
++#include "vc_vchi_audioserv_defs.h"
++
++/* ---- Private Constants and Types ------------------------------------------ */
++
++#define BCM2835_AUDIO_STOP 0
++#define BCM2835_AUDIO_START 1
++#define BCM2835_AUDIO_WRITE 2
++
++/* Logging macros (for remapping to other logging mechanisms, i.e., printf) */
++#ifdef AUDIO_DEBUG_ENABLE
++ #define LOG_ERR( fmt, arg... ) pr_err( "%s:%d " fmt, __func__, __LINE__, ##arg)
++ #define LOG_WARN( fmt, arg... ) pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg)
++ #define LOG_INFO( fmt, arg... ) pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg)
++ #define LOG_DBG( fmt, arg... ) pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg)
++#else
++ #define LOG_ERR( fmt, arg... ) pr_err( "%s:%d " fmt, __func__, __LINE__, ##arg)
++ #define LOG_WARN( fmt, arg... )
++ #define LOG_INFO( fmt, arg... )
++ #define LOG_DBG( fmt, arg... )
++#endif
++
++typedef struct opaque_AUDIO_INSTANCE_T {
++ uint32_t num_connections;
++ VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS];
++ struct completion msg_avail_comp;
++ struct mutex vchi_mutex;
++ bcm2835_alsa_stream_t *alsa_stream;
++ int32_t result;
++ short peer_version;
++} AUDIO_INSTANCE_T;
++
++bool force_bulk = false;
++
++/* ---- Private Variables ---------------------------------------------------- */
++
++/* ---- Private Function Prototypes ------------------------------------------ */
++
++/* ---- Private Functions ---------------------------------------------------- */
++
++static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream);
++static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream);
++static int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream,
++ uint32_t count, void *src);
++
++typedef struct {
++ struct work_struct my_work;
++ bcm2835_alsa_stream_t *alsa_stream;
++ int cmd;
++ void *src;
++ uint32_t count;
++} my_work_t;
++
++static void my_wq_function(struct work_struct *work)
++{
++ my_work_t *w = (my_work_t *) work;
++ int ret = -9;
++ LOG_DBG(" .. IN %p:%d\n", w->alsa_stream, w->cmd);
++ switch (w->cmd) {
++ case BCM2835_AUDIO_START:
++ ret = bcm2835_audio_start_worker(w->alsa_stream);
++ break;
++ case BCM2835_AUDIO_STOP:
++ ret = bcm2835_audio_stop_worker(w->alsa_stream);
++ break;
++ case BCM2835_AUDIO_WRITE:
++ ret = bcm2835_audio_write_worker(w->alsa_stream, w->count,
++ w->src);
++ break;
++ default:
++ LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->cmd);
++ break;
++ }
++ kfree((void *)work);
++ LOG_DBG(" .. OUT %d\n", ret);
++}
++
++int bcm2835_audio_start(bcm2835_alsa_stream_t * alsa_stream)
++{
++ int ret = -1;
++ LOG_DBG(" .. IN\n");
++ if (alsa_stream->my_wq) {
++ my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
++ /*--- Queue some work (item 1) ---*/
++ if (work) {
++ INIT_WORK((struct work_struct *)work, my_wq_function);
++ work->alsa_stream = alsa_stream;
++ work->cmd = BCM2835_AUDIO_START;
++ if (queue_work
++ (alsa_stream->my_wq, (struct work_struct *)work))
++ ret = 0;
++ } else
++ LOG_ERR(" .. Error: NULL work kmalloc\n");
++ }
++ LOG_DBG(" .. OUT %d\n", ret);
++ return ret;
++}
++
++int bcm2835_audio_stop(bcm2835_alsa_stream_t * alsa_stream)
++{
++ int ret = -1;
++ LOG_DBG(" .. IN\n");
++ if (alsa_stream->my_wq) {
++ my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
++ /*--- Queue some work (item 1) ---*/
++ if (work) {
++ INIT_WORK((struct work_struct *)work, my_wq_function);
++ work->alsa_stream = alsa_stream;
++ work->cmd = BCM2835_AUDIO_STOP;
++ if (queue_work
++ (alsa_stream->my_wq, (struct work_struct *)work))
++ ret = 0;
++ } else
++ LOG_ERR(" .. Error: NULL work kmalloc\n");
++ }
++ LOG_DBG(" .. OUT %d\n", ret);
++ return ret;
++}
++
++int bcm2835_audio_write(bcm2835_alsa_stream_t *alsa_stream,
++ uint32_t count, void *src)
++{
++ int ret = -1;
++ LOG_DBG(" .. IN\n");
++ if (alsa_stream->my_wq) {
++ my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
++ /*--- Queue some work (item 1) ---*/
++ if (work) {
++ INIT_WORK((struct work_struct *)work, my_wq_function);
++ work->alsa_stream = alsa_stream;
++ work->cmd = BCM2835_AUDIO_WRITE;
++ work->src = src;
++ work->count = count;
++ if (queue_work
++ (alsa_stream->my_wq, (struct work_struct *)work))
++ ret = 0;
++ } else
++ LOG_ERR(" .. Error: NULL work kmalloc\n");
++ }
++ LOG_DBG(" .. OUT %d\n", ret);
++ return ret;
++}
++
++void my_workqueue_init(bcm2835_alsa_stream_t * alsa_stream)
++{
++ alsa_stream->my_wq = alloc_workqueue("my_queue", WQ_HIGHPRI, 1);
++ return;
++}
++
++void my_workqueue_quit(bcm2835_alsa_stream_t * alsa_stream)
++{
++ if (alsa_stream->my_wq) {
++ flush_workqueue(alsa_stream->my_wq);
++ destroy_workqueue(alsa_stream->my_wq);
++ alsa_stream->my_wq = NULL;
++ }
++ return;
++}
++
++static void audio_vchi_callback(void *param,
++ const VCHI_CALLBACK_REASON_T reason,
++ void *msg_handle)
++{
++ AUDIO_INSTANCE_T *instance = (AUDIO_INSTANCE_T *) param;
++ int32_t status;
++ int32_t msg_len;
++ VC_AUDIO_MSG_T m;
++ LOG_DBG(" .. IN instance=%p, handle=%p, alsa=%p, reason=%d, handle=%p\n",
++ instance, instance ? instance->vchi_handle[0] : NULL, instance ? instance->alsa_stream : NULL, reason, msg_handle);
++
++ if (reason != VCHI_CALLBACK_MSG_AVAILABLE) {
++ return;
++ }
++ if (!instance) {
++ LOG_ERR(" .. instance is null\n");
++ BUG();
++ return;
++ }
++ if (!instance->vchi_handle[0]) {
++ LOG_ERR(" .. instance->vchi_handle[0] is null\n");
++ BUG();
++ return;
++ }
++ status = vchi_msg_dequeue(instance->vchi_handle[0],
++ &m, sizeof m, &msg_len, VCHI_FLAGS_NONE);
++ if (m.type == VC_AUDIO_MSG_TYPE_RESULT) {
++ LOG_DBG
++ (" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_RESULT, success=%d\n",
++ instance, m.u.result.success);
++ instance->result = m.u.result.success;
++ complete(&instance->msg_avail_comp);
++ } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
++ bcm2835_alsa_stream_t *alsa_stream = instance->alsa_stream;
++ irq_handler_t callback = (irq_handler_t) m.u.complete.callback;
++ LOG_DBG
++ (" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_COMPLETE, complete=%d\n",
++ instance, m.u.complete.count);
++ if (alsa_stream && callback) {
++ atomic_add(m.u.complete.count, &alsa_stream->retrieved);
++ callback(0, alsa_stream);
++ } else {
++ LOG_ERR(" .. unexpected alsa_stream=%p, callback=%p\n",
++ alsa_stream, callback);
++ }
++ } else {
++ LOG_ERR(" .. unexpected m.type=%d\n", m.type);
++ }
++ LOG_DBG(" .. OUT\n");
++}
++
++static AUDIO_INSTANCE_T *vc_vchi_audio_init(VCHI_INSTANCE_T vchi_instance,
++ VCHI_CONNECTION_T **
++ vchi_connections,
++ uint32_t num_connections)
++{
++ uint32_t i;
++ AUDIO_INSTANCE_T *instance;
++ int status;
++
++ LOG_DBG("%s: start", __func__);
++
++ if (num_connections > VCHI_MAX_NUM_CONNECTIONS) {
++ LOG_ERR("%s: unsupported number of connections %u (max=%u)\n",
++ __func__, num_connections, VCHI_MAX_NUM_CONNECTIONS);
++
++ return NULL;
++ }
++ /* Allocate memory for this instance */
++ instance = kmalloc(sizeof(*instance), GFP_KERNEL);
++ if (!instance)
++ return NULL;
++
++ memset(instance, 0, sizeof(*instance));
++ instance->num_connections = num_connections;
++
++ /* Create a lock for exclusive, serialized VCHI connection access */
++ mutex_init(&instance->vchi_mutex);
++ /* Open the VCHI service connections */
++ for (i = 0; i < num_connections; i++) {
++ SERVICE_CREATION_T params = {
++ VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER),
++ VC_AUDIO_SERVER_NAME, // 4cc service code
++ vchi_connections[i], // passed in fn pointers
++ 0, // rx fifo size (unused)
++ 0, // tx fifo size (unused)
++ audio_vchi_callback, // service callback
++ instance, // service callback parameter
++ 1, //TODO: remove VCOS_FALSE, // unaligned bulk recieves
++ 1, //TODO: remove VCOS_FALSE, // unaligned bulk transmits
++ 0 // want crc check on bulk transfers
++ };
++
++ LOG_DBG("%s: about to open %i\n", __func__, i);
++ status = vchi_service_open(vchi_instance, &params,
++ &instance->vchi_handle[i]);
++ LOG_DBG("%s: opened %i: %p=%d\n", __func__, i, instance->vchi_handle[i], status);
++ if (status) {
++ LOG_ERR
++ ("%s: failed to open VCHI service connection (status=%d)\n",
++ __func__, status);
++
++ goto err_close_services;
++ }
++ /* Finished with the service for now */
++ vchi_service_release(instance->vchi_handle[i]);
++ }
++
++ LOG_DBG("%s: okay\n", __func__);
++ return instance;
++
++err_close_services:
++ for (i = 0; i < instance->num_connections; i++) {
++ LOG_ERR("%s: closing %i: %p\n", __func__, i, instance->vchi_handle[i]);
++ if (instance->vchi_handle[i])
++ vchi_service_close(instance->vchi_handle[i]);
++ }
++
++ kfree(instance);
++ LOG_ERR("%s: error\n", __func__);
++
++ return NULL;
++}
++
++static int32_t vc_vchi_audio_deinit(AUDIO_INSTANCE_T * instance)
++{
++ uint32_t i;
++
++ LOG_DBG(" .. IN\n");
++
++ if (instance == NULL) {
++ LOG_ERR("%s: invalid handle %p\n", __func__, instance);
++
++ return -1;
++ }
++
++ LOG_DBG(" .. about to lock (%d)\n", instance->num_connections);
++ if(mutex_lock_interruptible(&instance->vchi_mutex))
++ {
++ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
++ return -EINTR;
++ }
++
++ /* Close all VCHI service connections */
++ for (i = 0; i < instance->num_connections; i++) {
++ int32_t success;
++ LOG_DBG(" .. %i:closing %p\n", i, instance->vchi_handle[i]);
++ vchi_service_use(instance->vchi_handle[i]);
++
++ success = vchi_service_close(instance->vchi_handle[i]);
++ if (success != 0) {
++ LOG_DBG
++ ("%s: failed to close VCHI service connection (status=%d)\n",
++ __func__, success);
++ }
++ }
++
++ mutex_unlock(&instance->vchi_mutex);
++
++ kfree(instance);
++
++ LOG_DBG(" .. OUT\n");
++
++ return 0;
++}
++
++static int bcm2835_audio_open_connection(bcm2835_alsa_stream_t * alsa_stream)
++{
++ static VCHI_INSTANCE_T vchi_instance;
++ static VCHI_CONNECTION_T *vchi_connection;
++ static int initted;
++ AUDIO_INSTANCE_T *instance = alsa_stream->instance;
++ int ret;
++ LOG_DBG(" .. IN\n");
++
++ LOG_INFO("%s: start\n", __func__);
++ BUG_ON(instance);
++ if (instance) {
++ LOG_ERR("%s: VCHI instance already open (%p)\n",
++ __func__, instance);
++ instance->alsa_stream = alsa_stream;
++ alsa_stream->instance = instance;
++ ret = 0; // xxx todo -1;
++ goto err_free_mem;
++ }
++
++ /* Initialize and create a VCHI connection */
++ if (!initted) {
++ ret = vchi_initialise(&vchi_instance);
++ if (ret != 0) {
++ LOG_ERR("%s: failed to initialise VCHI instance (ret=%d)\n",
++ __func__, ret);
++
++ ret = -EIO;
++ goto err_free_mem;
++ }
++ ret = vchi_connect(NULL, 0, vchi_instance);
++ if (ret != 0) {
++ LOG_ERR("%s: failed to connect VCHI instance (ret=%d)\n",
++ __func__, ret);
++
++ ret = -EIO;
++ goto err_free_mem;
++ }
++ initted = 1;
++ }
++
++ /* Initialize an instance of the audio service */
++ instance = vc_vchi_audio_init(vchi_instance, &vchi_connection, 1);
++
++ if (instance == NULL) {
++ LOG_ERR("%s: failed to initialize audio service\n", __func__);
++
++ ret = -EPERM;
++ goto err_free_mem;
++ }
++
++ instance->alsa_stream = alsa_stream;
++ alsa_stream->instance = instance;
++
++ LOG_DBG(" success !\n");
++err_free_mem:
++ LOG_DBG(" .. OUT\n");
++
++ return ret;
++}
++
++int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream)
++{
++ AUDIO_INSTANCE_T *instance;
++ VC_AUDIO_MSG_T m;
++ int32_t success;
++ int ret;
++ LOG_DBG(" .. IN\n");
++
++ my_workqueue_init(alsa_stream);
++
++ ret = bcm2835_audio_open_connection(alsa_stream);
++ if (ret != 0) {
++ ret = -1;
++ goto exit;
++ }
++ instance = alsa_stream->instance;
++ LOG_DBG(" instance (%p)\n", instance);
++
++ if(mutex_lock_interruptible(&instance->vchi_mutex))
++ {
++ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
++ return -EINTR;
++ }
++ vchi_service_use(instance->vchi_handle[0]);
++
++ m.type = VC_AUDIO_MSG_TYPE_OPEN;
++
++ /* Send the message to the videocore */
++ success = vchi_msg_queue(instance->vchi_handle[0],
++ &m, sizeof m,
++ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
++
++ if (success != 0) {
++ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
++ __func__, success);
++
++ ret = -1;
++ goto unlock;
++ }
++
++ ret = 0;
++
++unlock:
++ vchi_service_release(instance->vchi_handle[0]);
++ mutex_unlock(&instance->vchi_mutex);
++exit:
++ LOG_DBG(" .. OUT\n");
++ return ret;
++}
++
++static int bcm2835_audio_set_ctls_chan(bcm2835_alsa_stream_t * alsa_stream,
++ bcm2835_chip_t * chip)
++{
++ VC_AUDIO_MSG_T m;
++ AUDIO_INSTANCE_T *instance = alsa_stream->instance;
++ int32_t success;
++ int ret;
++ LOG_DBG(" .. IN\n");
++
++ LOG_INFO
++ (" Setting ALSA dest(%d), volume(%d)\n", chip->dest, chip->volume);
++
++ if(mutex_lock_interruptible(&instance->vchi_mutex))
++ {
++ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
++ return -EINTR;
++ }
++ vchi_service_use(instance->vchi_handle[0]);
++
++ instance->result = -1;
++
++ m.type = VC_AUDIO_MSG_TYPE_CONTROL;
++ m.u.control.dest = chip->dest;
++ m.u.control.volume = chip->volume;
++
++ /* Create the message available completion */
++ init_completion(&instance->msg_avail_comp);
++
++ /* Send the message to the videocore */
++ success = vchi_msg_queue(instance->vchi_handle[0],
++ &m, sizeof m,
++ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
++
++ if (success != 0) {
++ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
++ __func__, success);
++
++ ret = -1;
++ goto unlock;
++ }
++
++ /* We are expecting a reply from the videocore */
++ ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
++ if (ret) {
++ LOG_DBG("%s: failed on waiting for event (status=%d)\n",
++ __func__, success);
++ goto unlock;
++ }
++
++ if (instance->result != 0) {
++ LOG_ERR("%s: result=%d\n", __func__, instance->result);
++
++ ret = -1;
++ goto unlock;
++ }
++
++ ret = 0;
++
++unlock:
++ vchi_service_release(instance->vchi_handle[0]);
++ mutex_unlock(&instance->vchi_mutex);
++
++ LOG_DBG(" .. OUT\n");
++ return ret;
++}
++
++int bcm2835_audio_set_ctls(bcm2835_chip_t * chip)
++{
++ int i;
++ int ret = 0;
++ LOG_DBG(" .. IN\n");
++ LOG_DBG(" Setting ALSA dest(%d), volume(%d)\n", chip->dest, chip->volume);
++
++ /* change ctls for all substreams */
++ for (i = 0; i < MAX_SUBSTREAMS; i++) {
++ if (chip->avail_substreams & (1 << i)) {
++ if (!chip->alsa_stream[i])
++ {
++ LOG_DBG(" No ALSA stream available?! %i:%p (%x)\n", i, chip->alsa_stream[i], chip->avail_substreams);
++ ret = 0;
++ }
++ else if (bcm2835_audio_set_ctls_chan /* returns 0 on success */
++ (chip->alsa_stream[i], chip) != 0)
++ {
++ LOG_ERR("Couldn't set the controls for stream %d\n", i);
++ ret = -1;
++ }
++ else LOG_DBG(" Controls set for stream %d\n", i);
++ }
++ }
++ LOG_DBG(" .. OUT ret=%d\n", ret);
++ return ret;
++}
++
++int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
++ uint32_t channels, uint32_t samplerate,
++ uint32_t bps)
++{
++ VC_AUDIO_MSG_T m;
++ AUDIO_INSTANCE_T *instance = alsa_stream->instance;
++ int32_t success;
++ int ret;
++ LOG_DBG(" .. IN\n");
++
++ LOG_INFO
++ (" Setting ALSA channels(%d), samplerate(%d), bits-per-sample(%d)\n",
++ channels, samplerate, bps);
++
++ /* resend ctls - alsa_stream may not have been open when first send */
++ ret = bcm2835_audio_set_ctls_chan(alsa_stream, alsa_stream->chip);
++ if (ret != 0) {
++ LOG_ERR(" Alsa controls not supported\n");
++ return -EINVAL;
++ }
++
++ if(mutex_lock_interruptible(&instance->vchi_mutex))
++ {
++ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
++ return -EINTR;
++ }
++ vchi_service_use(instance->vchi_handle[0]);
++
++ instance->result = -1;
++
++ m.type = VC_AUDIO_MSG_TYPE_CONFIG;
++ m.u.config.channels = channels;
++ m.u.config.samplerate = samplerate;
++ m.u.config.bps = bps;
++
++ /* Create the message available completion */
++ init_completion(&instance->msg_avail_comp);
++
++ /* Send the message to the videocore */
++ success = vchi_msg_queue(instance->vchi_handle[0],
++ &m, sizeof m,
++ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
++
++ if (success != 0) {
++ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
++ __func__, success);
++
++ ret = -1;
++ goto unlock;
++ }
++
++ /* We are expecting a reply from the videocore */
++ ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
++ if (ret) {
++ LOG_DBG("%s: failed on waiting for event (status=%d)\n",
++ __func__, success);
++ goto unlock;
++ }
++
++ if (instance->result != 0) {
++ LOG_ERR("%s: result=%d", __func__, instance->result);
++
++ ret = -1;
++ goto unlock;
++ }
++
++ ret = 0;
++
++unlock:
++ vchi_service_release(instance->vchi_handle[0]);
++ mutex_unlock(&instance->vchi_mutex);
++
++ LOG_DBG(" .. OUT\n");
++ return ret;
++}
++
++int bcm2835_audio_setup(bcm2835_alsa_stream_t * alsa_stream)
++{
++ LOG_DBG(" .. IN\n");
++
++ LOG_DBG(" .. OUT\n");
++
++ return 0;
++}
++
++static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream)
++{
++ VC_AUDIO_MSG_T m;
++ AUDIO_INSTANCE_T *instance = alsa_stream->instance;
++ int32_t success;
++ int ret;
++ LOG_DBG(" .. IN\n");
++
++ if(mutex_lock_interruptible(&instance->vchi_mutex))
++ {
++ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
++ return -EINTR;
++ }
++ vchi_service_use(instance->vchi_handle[0]);
++
++ m.type = VC_AUDIO_MSG_TYPE_START;
++
++ /* Send the message to the videocore */
++ success = vchi_msg_queue(instance->vchi_handle[0],
++ &m, sizeof m,
++ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
++
++ if (success != 0) {
++ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
++ __func__, success);
++
++ ret = -1;
++ goto unlock;
++ }
++
++ ret = 0;
++
++unlock:
++ vchi_service_release(instance->vchi_handle[0]);
++ mutex_unlock(&instance->vchi_mutex);
++ LOG_DBG(" .. OUT\n");
++ return ret;
++}
++
++static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream)
++{
++ VC_AUDIO_MSG_T m;
++ AUDIO_INSTANCE_T *instance = alsa_stream->instance;
++ int32_t success;
++ int ret;
++ LOG_DBG(" .. IN\n");
++
++ if(mutex_lock_interruptible(&instance->vchi_mutex))
++ {
++ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
++ return -EINTR;
++ }
++ vchi_service_use(instance->vchi_handle[0]);
++
++ m.type = VC_AUDIO_MSG_TYPE_STOP;
++ m.u.stop.draining = alsa_stream->draining;
++
++ /* Send the message to the videocore */
++ success = vchi_msg_queue(instance->vchi_handle[0],
++ &m, sizeof m,
++ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
++
++ if (success != 0) {
++ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
++ __func__, success);
++
++ ret = -1;
++ goto unlock;
++ }
++
++ ret = 0;
++
++unlock:
++ vchi_service_release(instance->vchi_handle[0]);
++ mutex_unlock(&instance->vchi_mutex);
++ LOG_DBG(" .. OUT\n");
++ return ret;
++}
++
++int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream)
++{
++ VC_AUDIO_MSG_T m;
++ AUDIO_INSTANCE_T *instance = alsa_stream->instance;
++ int32_t success;
++ int ret;
++ LOG_DBG(" .. IN\n");
++
++ my_workqueue_quit(alsa_stream);
++
++ if(mutex_lock_interruptible(&instance->vchi_mutex))
++ {
++ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
++ return -EINTR;
++ }
++ vchi_service_use(instance->vchi_handle[0]);
++
++ m.type = VC_AUDIO_MSG_TYPE_CLOSE;
++
++ /* Create the message available completion */
++ init_completion(&instance->msg_avail_comp);
++
++ /* Send the message to the videocore */
++ success = vchi_msg_queue(instance->vchi_handle[0],
++ &m, sizeof m,
++ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
++
++ if (success != 0) {
++ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
++ __func__, success);
++ ret = -1;
++ goto unlock;
++ }
++
++ ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
++ if (ret) {
++ LOG_DBG("%s: failed on waiting for event (status=%d)\n",
++ __func__, success);
++ goto unlock;
++ }
++ if (instance->result != 0) {
++ LOG_ERR("%s: failed result (status=%d)\n",
++ __func__, instance->result);
++
++ ret = -1;
++ goto unlock;
++ }
++
++ ret = 0;
++
++unlock:
++ vchi_service_release(instance->vchi_handle[0]);
++ mutex_unlock(&instance->vchi_mutex);
++
++ /* Stop the audio service */
++ if (instance) {
++ vc_vchi_audio_deinit(instance);
++ alsa_stream->instance = NULL;
++ }
++ LOG_DBG(" .. OUT\n");
++ return ret;
++}
++
++int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream,
++ uint32_t count, void *src)
++{
++ VC_AUDIO_MSG_T m;
++ AUDIO_INSTANCE_T *instance = alsa_stream->instance;
++ int32_t success;
++ int ret;
++
++ LOG_DBG(" .. IN\n");
++
++ LOG_INFO(" Writing %d bytes from %p\n", count, src);
++
++ if(mutex_lock_interruptible(&instance->vchi_mutex))
++ {
++ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
++ return -EINTR;
++ }
++ vchi_service_use(instance->vchi_handle[0]);
++
++ if ( instance->peer_version==0 && vchi_get_peer_version(instance->vchi_handle[0], &instance->peer_version) == 0 ) {
++ LOG_DBG("%s: client version %d connected\n", __func__, instance->peer_version);
++ }
++ m.type = VC_AUDIO_MSG_TYPE_WRITE;
++ m.u.write.count = count;
++ // old version uses bulk, new version uses control
++ m.u.write.max_packet = instance->peer_version < 2 || force_bulk ? 0:4000;
++ m.u.write.callback = alsa_stream->fifo_irq_handler;
++ m.u.write.cookie = alsa_stream;
++ m.u.write.silence = src == NULL;
++
++ /* Send the message to the videocore */
++ success = vchi_msg_queue(instance->vchi_handle[0],
++ &m, sizeof m,
++ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
++
++ if (success != 0) {
++ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
++ __func__, success);
++
++ ret = -1;
++ goto unlock;
++ }
++ if (!m.u.write.silence) {
++ if (m.u.write.max_packet == 0) {
++ /* Send the message to the videocore */
++ success = vchi_bulk_queue_transmit(instance->vchi_handle[0],
++ src, count,
++ 0 *
++ VCHI_FLAGS_BLOCK_UNTIL_QUEUED
++ +
++ 1 *
++ VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
++ NULL);
++ } else {
++ while (count > 0) {
++ int bytes = min((int)m.u.write.max_packet, (int)count);
++ success = vchi_msg_queue(instance->vchi_handle[0],
++ src, bytes,
++ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
++ src = (char *)src + bytes;
++ count -= bytes;
++ }
++ }
++ if (success != 0) {
++ LOG_ERR
++ ("%s: failed on vchi_bulk_queue_transmit (status=%d)\n",
++ __func__, success);
++
++ ret = -1;
++ goto unlock;
++ }
++ }
++ ret = 0;
++
++unlock:
++ vchi_service_release(instance->vchi_handle[0]);
++ mutex_unlock(&instance->vchi_mutex);
++ LOG_DBG(" .. OUT\n");
++ return ret;
++}
++
++/**
++ * Returns all buffers from arm->vc
++ */
++void bcm2835_audio_flush_buffers(bcm2835_alsa_stream_t * alsa_stream)
++{
++ LOG_DBG(" .. IN\n");
++ LOG_DBG(" .. OUT\n");
++ return;
++}
++
++/**
++ * Forces VC to flush(drop) its filled playback buffers and
++ * return them the us. (VC->ARM)
++ */
++void bcm2835_audio_flush_playback_buffers(bcm2835_alsa_stream_t * alsa_stream)
++{
++ LOG_DBG(" .. IN\n");
++ LOG_DBG(" .. OUT\n");
++}
++
++uint32_t bcm2835_audio_retrieve_buffers(bcm2835_alsa_stream_t * alsa_stream)
++{
++ uint32_t count = atomic_read(&alsa_stream->retrieved);
++ atomic_sub(count, &alsa_stream->retrieved);
++ return count;
++}
++
++module_param(force_bulk, bool, 0444);
++MODULE_PARM_DESC(force_bulk, "Force use of vchiq bulk for audio");
+--- /dev/null
++++ b/sound/arm/bcm2835.c
+@@ -0,0 +1,511 @@
++/*****************************************************************************
++* Copyright 2011 Broadcom Corporation. All rights reserved.
++*
++* Unless you and Broadcom execute a separate written software license
++* agreement governing use of this software, this software is licensed to you
++* under the terms of the GNU General Public License version 2, available at
++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
++*
++* Notwithstanding the above, under no circumstances may you combine this
++* software in any way with any other Broadcom software provided under a
++* license other than the GPL, without Broadcom's express prior written
++* consent.
++*****************************************************************************/
++
++#include <linux/platform_device.h>
++
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/of.h>
++
++#include "bcm2835.h"
++
++/* module parameters (see "Module Parameters") */
++/* SNDRV_CARDS: maximum number of cards supported by this module */
++static int index[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = -1 };
++static char *id[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = NULL };
++static int enable[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = 1 };
++
++/* HACKY global pointers needed for successive probes to work : ssp
++ * But compared against the changes we will have to do in VC audio_ipc code
++ * to export 8 audio_ipc devices as a single IPC device and then monitor all
++ * four devices in a thread, this gets things done quickly and should be easier
++ * to debug if we run into issues
++ */
++
++static struct snd_card *g_card = NULL;
++static bcm2835_chip_t *g_chip = NULL;
++
++static int snd_bcm2835_free(bcm2835_chip_t * chip)
++{
++ kfree(chip);
++ return 0;
++}
++
++/* component-destructor
++ * (see "Management of Cards and Components")
++ */
++static int snd_bcm2835_dev_free(struct snd_device *device)
++{
++ return snd_bcm2835_free(device->device_data);
++}
++
++/* chip-specific constructor
++ * (see "Management of Cards and Components")
++ */
++static int snd_bcm2835_create(struct snd_card *card,
++ struct platform_device *pdev,
++ bcm2835_chip_t ** rchip)
++{
++ bcm2835_chip_t *chip;
++ int err;
++ static struct snd_device_ops ops = {
++ .dev_free = snd_bcm2835_dev_free,
++ };
++
++ *rchip = NULL;
++
++ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
++ if (chip == NULL)
++ return -ENOMEM;
++
++ chip->card = card;
++
++ err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
++ if (err < 0) {
++ snd_bcm2835_free(chip);
++ return err;
++ }
++
++ *rchip = chip;
++ return 0;
++}
++
++static int snd_bcm2835_alsa_probe_dt(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ bcm2835_chip_t *chip;
++ struct snd_card *card;
++ u32 numchans;
++ int err, i;
++
++ err = of_property_read_u32(dev->of_node, "brcm,pwm-channels",
++ &numchans);
++ if (err) {
++ dev_err(dev, "Failed to get DT property 'brcm,pwm-channels'");
++ return err;
++ }
++
++ if (numchans == 0 || numchans > MAX_SUBSTREAMS) {
++ numchans = MAX_SUBSTREAMS;
++ dev_warn(dev, "Illegal 'brcm,pwm-channels' value, will use %u\n",
++ numchans);
++ }
++
++ err = snd_card_new(NULL, -1, NULL, THIS_MODULE, 0, &card);
++ if (err) {
++ dev_err(dev, "Failed to create soundcard structure\n");
++ return err;
++ }
++
++ snd_card_set_dev(card, dev);
++ strcpy(card->driver, "bcm2835");
++ strcpy(card->shortname, "bcm2835 ALSA");
++ sprintf(card->longname, "%s", card->shortname);
++
++ err = snd_bcm2835_create(card, pdev, &chip);
++ if (err < 0) {
++ dev_err(dev, "Failed to create bcm2835 chip\n");
++ goto err_free;
++ }
++
++ err = snd_bcm2835_new_pcm(chip);
++ if (err < 0) {
++ dev_err(dev, "Failed to create new bcm2835 pcm device\n");
++ goto err_free;
++ }
++
++ err = snd_bcm2835_new_spdif_pcm(chip);
++ if (err < 0) {
++ dev_err(dev, "Failed to create new bcm2835 spdif pcm device\n");
++ goto err_free;
++ }
++
++ err = snd_bcm2835_new_ctl(chip);
++ if (err < 0) {
++ dev_err(dev, "Failed to create new bcm2835 ctl\n");
++ goto err_free;
++ }
++
++ for (i = 0; i < numchans; i++) {
++ chip->avail_substreams |= (1 << i);
++ chip->pdev[i] = pdev;
++ }
++
++ err = snd_card_register(card);
++ if (err) {
++ dev_err(dev, "Failed to register bcm2835 ALSA card \n");
++ goto err_free;
++ }
++
++ g_card = card;
++ g_chip = chip;
++ platform_set_drvdata(pdev, card);
++ audio_info("bcm2835 ALSA card created with %u channels\n", numchans);
++
++ return 0;
++
++err_free:
++ snd_card_free(card);
++
++ return err;
++}
++
++static int snd_bcm2835_alsa_probe(struct platform_device *pdev)
++{
++ static int dev;
++ bcm2835_chip_t *chip;
++ struct snd_card *card;
++ int err;
++
++ if (pdev->dev.of_node)
++ return snd_bcm2835_alsa_probe_dt(pdev);
++
++ if (dev >= MAX_SUBSTREAMS)
++ return -ENODEV;
++
++ if (!enable[dev]) {
++ dev++;
++ return -ENOENT;
++ }
++
++ if (dev > 0)
++ goto add_register_map;
++
++ err = snd_card_new(NULL, index[dev], id[dev], THIS_MODULE, 0, &g_card);
++ if (err < 0)
++ goto out;
++
++ snd_card_set_dev(g_card, &pdev->dev);
++ strcpy(g_card->driver, "bcm2835");
++ strcpy(g_card->shortname, "bcm2835 ALSA");
++ sprintf(g_card->longname, "%s", g_card->shortname);
++
++ err = snd_bcm2835_create(g_card, pdev, &chip);
++ if (err < 0) {
++ dev_err(&pdev->dev, "Failed to create bcm2835 chip\n");
++ goto out_bcm2835_create;
++ }
++
++ g_chip = chip;
++ err = snd_bcm2835_new_pcm(chip);
++ if (err < 0) {
++ dev_err(&pdev->dev, "Failed to create new BCM2835 pcm device\n");
++ goto out_bcm2835_new_pcm;
++ }
++
++ err = snd_bcm2835_new_spdif_pcm(chip);
++ if (err < 0) {
++ dev_err(&pdev->dev, "Failed to create new BCM2835 spdif pcm device\n");
++ goto out_bcm2835_new_spdif;
++ }
++
++ err = snd_bcm2835_new_ctl(chip);
++ if (err < 0) {
++ dev_err(&pdev->dev, "Failed to create new BCM2835 ctl\n");
++ goto out_bcm2835_new_ctl;
++ }
++
++add_register_map:
++ card = g_card;
++ chip = g_chip;
++
++ BUG_ON(!(card && chip));
++
++ chip->avail_substreams |= (1 << dev);
++ chip->pdev[dev] = pdev;
++
++ if (dev == 0) {
++ err = snd_card_register(card);
++ if (err < 0) {
++ dev_err(&pdev->dev,
++ "Failed to register bcm2835 ALSA card \n");
++ goto out_card_register;
++ }
++ platform_set_drvdata(pdev, card);
++ audio_info("bcm2835 ALSA card created!\n");
++ } else {
++ audio_info("bcm2835 ALSA chip created!\n");
++ platform_set_drvdata(pdev, (void *)dev);
++ }
++
++ dev++;
++
++ return 0;
++
++out_card_register:
++out_bcm2835_new_ctl:
++out_bcm2835_new_spdif:
++out_bcm2835_new_pcm:
++out_bcm2835_create:
++ BUG_ON(!g_card);
++ if (snd_card_free(g_card))
++ dev_err(&pdev->dev, "Failed to free Registered alsa card\n");
++ g_card = NULL;
++out:
++ dev = SNDRV_CARDS; /* stop more avail_substreams from being probed */
++ dev_err(&pdev->dev, "BCM2835 ALSA Probe failed !!\n");
++ return err;
++}
++
++static int snd_bcm2835_alsa_remove(struct platform_device *pdev)
++{
++ uint32_t idx;
++ void *drv_data;
++
++ drv_data = platform_get_drvdata(pdev);
++
++ if (drv_data == (void *)g_card) {
++ /* This is the card device */
++ snd_card_free((struct snd_card *)drv_data);
++ g_card = NULL;
++ g_chip = NULL;
++ } else {
++ idx = (uint32_t) drv_data;
++ if (g_card != NULL) {
++ BUG_ON(!g_chip);
++ /* We pass chip device numbers in audio ipc devices
++ * other than the one we registered our card with
++ */
++ idx = (uint32_t) drv_data;
++ BUG_ON(!idx || idx > MAX_SUBSTREAMS);
++ g_chip->avail_substreams &= ~(1 << idx);
++ /* There should be atleast one substream registered
++ * after we are done here, as it wil be removed when
++ * the *remove* is called for the card device
++ */
++ BUG_ON(!g_chip->avail_substreams);
++ }
++ }
++
++ platform_set_drvdata(pdev, NULL);
++
++ return 0;
++}
++
++#ifdef CONFIG_PM
++static int snd_bcm2835_alsa_suspend(struct platform_device *pdev,
++ pm_message_t state)
++{
++ return 0;
++}
++
++static int snd_bcm2835_alsa_resume(struct platform_device *pdev)
++{
++ return 0;
++}
++
++#endif
++
++static const struct of_device_id snd_bcm2835_of_match_table[] = {
++ { .compatible = "brcm,bcm2835-audio", },
++ {},
++};
++MODULE_DEVICE_TABLE(of, snd_bcm2835_of_match_table);
++
++static struct platform_driver bcm2835_alsa0_driver = {
++ .probe = snd_bcm2835_alsa_probe,
++ .remove = snd_bcm2835_alsa_remove,
++#ifdef CONFIG_PM
++ .suspend = snd_bcm2835_alsa_suspend,
++ .resume = snd_bcm2835_alsa_resume,
++#endif
++ .driver = {
++ .name = "bcm2835_AUD0",
++ .owner = THIS_MODULE,
++ .of_match_table = snd_bcm2835_of_match_table,
++ },
++};
++
++static struct platform_driver bcm2835_alsa1_driver = {
++ .probe = snd_bcm2835_alsa_probe,
++ .remove = snd_bcm2835_alsa_remove,
++#ifdef CONFIG_PM
++ .suspend = snd_bcm2835_alsa_suspend,
++ .resume = snd_bcm2835_alsa_resume,
++#endif
++ .driver = {
++ .name = "bcm2835_AUD1",
++ .owner = THIS_MODULE,
++ },
++};
++
++static struct platform_driver bcm2835_alsa2_driver = {
++ .probe = snd_bcm2835_alsa_probe,
++ .remove = snd_bcm2835_alsa_remove,
++#ifdef CONFIG_PM
++ .suspend = snd_bcm2835_alsa_suspend,
++ .resume = snd_bcm2835_alsa_resume,
++#endif
++ .driver = {
++ .name = "bcm2835_AUD2",
++ .owner = THIS_MODULE,
++ },
++};
++
++static struct platform_driver bcm2835_alsa3_driver = {
++ .probe = snd_bcm2835_alsa_probe,
++ .remove = snd_bcm2835_alsa_remove,
++#ifdef CONFIG_PM
++ .suspend = snd_bcm2835_alsa_suspend,
++ .resume = snd_bcm2835_alsa_resume,
++#endif
++ .driver = {
++ .name = "bcm2835_AUD3",
++ .owner = THIS_MODULE,
++ },
++};
++
++static struct platform_driver bcm2835_alsa4_driver = {
++ .probe = snd_bcm2835_alsa_probe,
++ .remove = snd_bcm2835_alsa_remove,
++#ifdef CONFIG_PM
++ .suspend = snd_bcm2835_alsa_suspend,
++ .resume = snd_bcm2835_alsa_resume,
++#endif
++ .driver = {
++ .name = "bcm2835_AUD4",
++ .owner = THIS_MODULE,
++ },
++};
++
++static struct platform_driver bcm2835_alsa5_driver = {
++ .probe = snd_bcm2835_alsa_probe,
++ .remove = snd_bcm2835_alsa_remove,
++#ifdef CONFIG_PM
++ .suspend = snd_bcm2835_alsa_suspend,
++ .resume = snd_bcm2835_alsa_resume,
++#endif
++ .driver = {
++ .name = "bcm2835_AUD5",
++ .owner = THIS_MODULE,
++ },
++};
++
++static struct platform_driver bcm2835_alsa6_driver = {
++ .probe = snd_bcm2835_alsa_probe,
++ .remove = snd_bcm2835_alsa_remove,
++#ifdef CONFIG_PM
++ .suspend = snd_bcm2835_alsa_suspend,
++ .resume = snd_bcm2835_alsa_resume,
++#endif
++ .driver = {
++ .name = "bcm2835_AUD6",
++ .owner = THIS_MODULE,
++ },
++};
++
++static struct platform_driver bcm2835_alsa7_driver = {
++ .probe = snd_bcm2835_alsa_probe,
++ .remove = snd_bcm2835_alsa_remove,
++#ifdef CONFIG_PM
++ .suspend = snd_bcm2835_alsa_suspend,
++ .resume = snd_bcm2835_alsa_resume,
++#endif
++ .driver = {
++ .name = "bcm2835_AUD7",
++ .owner = THIS_MODULE,
++ },
++};
++
++static int bcm2835_alsa_device_init(void)
++{
++ int err;
++ err = platform_driver_register(&bcm2835_alsa0_driver);
++ if (err) {
++ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
++ goto out;
++ }
++
++ err = platform_driver_register(&bcm2835_alsa1_driver);
++ if (err) {
++ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
++ goto unregister_0;
++ }
++
++ err = platform_driver_register(&bcm2835_alsa2_driver);
++ if (err) {
++ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
++ goto unregister_1;
++ }
++
++ err = platform_driver_register(&bcm2835_alsa3_driver);
++ if (err) {
++ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
++ goto unregister_2;
++ }
++
++ err = platform_driver_register(&bcm2835_alsa4_driver);
++ if (err) {
++ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
++ goto unregister_3;
++ }
++
++ err = platform_driver_register(&bcm2835_alsa5_driver);
++ if (err) {
++ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
++ goto unregister_4;
++ }
++
++ err = platform_driver_register(&bcm2835_alsa6_driver);
++ if (err) {
++ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
++ goto unregister_5;
++ }
++
++ err = platform_driver_register(&bcm2835_alsa7_driver);
++ if (err) {
++ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
++ goto unregister_6;
++ }
++
++ return 0;
++
++unregister_6:
++ platform_driver_unregister(&bcm2835_alsa6_driver);
++unregister_5:
++ platform_driver_unregister(&bcm2835_alsa5_driver);
++unregister_4:
++ platform_driver_unregister(&bcm2835_alsa4_driver);
++unregister_3:
++ platform_driver_unregister(&bcm2835_alsa3_driver);
++unregister_2:
++ platform_driver_unregister(&bcm2835_alsa2_driver);
++unregister_1:
++ platform_driver_unregister(&bcm2835_alsa1_driver);
++unregister_0:
++ platform_driver_unregister(&bcm2835_alsa0_driver);
++out:
++ return err;
++}
++
++static void bcm2835_alsa_device_exit(void)
++{
++ platform_driver_unregister(&bcm2835_alsa0_driver);
++ platform_driver_unregister(&bcm2835_alsa1_driver);
++ platform_driver_unregister(&bcm2835_alsa2_driver);
++ platform_driver_unregister(&bcm2835_alsa3_driver);
++ platform_driver_unregister(&bcm2835_alsa4_driver);
++ platform_driver_unregister(&bcm2835_alsa5_driver);
++ platform_driver_unregister(&bcm2835_alsa6_driver);
++ platform_driver_unregister(&bcm2835_alsa7_driver);
++}
++
++late_initcall(bcm2835_alsa_device_init);
++module_exit(bcm2835_alsa_device_exit);
++
++MODULE_AUTHOR("Dom Cobley");
++MODULE_DESCRIPTION("Alsa driver for BCM2835 chip");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:bcm2835_alsa");
+--- /dev/null
++++ b/sound/arm/bcm2835.h
+@@ -0,0 +1,167 @@
++/*****************************************************************************
++* Copyright 2011 Broadcom Corporation. All rights reserved.
++*
++* Unless you and Broadcom execute a separate written software license
++* agreement governing use of this software, this software is licensed to you
++* under the terms of the GNU General Public License version 2, available at
++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
++*
++* Notwithstanding the above, under no circumstances may you combine this
++* software in any way with any other Broadcom software provided under a
++* license other than the GPL, without Broadcom's express prior written
++* consent.
++*****************************************************************************/
++
++#ifndef __SOUND_ARM_BCM2835_H
++#define __SOUND_ARM_BCM2835_H
++
++#include <linux/device.h>
++#include <linux/list.h>
++#include <linux/interrupt.h>
++#include <linux/wait.h>
++#include <sound/core.h>
++#include <sound/initval.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/pcm-indirect.h>
++#include <linux/workqueue.h>
++
++/*
++#define AUDIO_DEBUG_ENABLE
++#define AUDIO_VERBOSE_DEBUG_ENABLE
++*/
++
++/* Debug macros */
++
++#ifdef AUDIO_DEBUG_ENABLE
++#ifdef AUDIO_VERBOSE_DEBUG_ENABLE
++
++#define audio_debug(fmt, arg...) \
++ printk(KERN_INFO"%s:%d " fmt, __func__, __LINE__, ##arg)
++
++#define audio_info(fmt, arg...) \
++ printk(KERN_INFO"%s:%d " fmt, __func__, __LINE__, ##arg)
++
++#else
++
++#define audio_debug(fmt, arg...)
++
++#define audio_info(fmt, arg...)
++
++#endif /* AUDIO_VERBOSE_DEBUG_ENABLE */
++
++#else
++
++#define audio_debug(fmt, arg...)
++
++#define audio_info(fmt, arg...)
++
++#endif /* AUDIO_DEBUG_ENABLE */
++
++#define audio_error(fmt, arg...) \
++ printk(KERN_ERR"%s:%d " fmt, __func__, __LINE__, ##arg)
++
++#define audio_warning(fmt, arg...) \
++ printk(KERN_WARNING"%s:%d " fmt, __func__, __LINE__, ##arg)
++
++#define audio_alert(fmt, arg...) \
++ printk(KERN_ALERT"%s:%d " fmt, __func__, __LINE__, ##arg)
++
++#define MAX_SUBSTREAMS (8)
++#define AVAIL_SUBSTREAMS_MASK (0xff)
++enum {
++ CTRL_VOL_MUTE,
++ CTRL_VOL_UNMUTE
++};
++
++/* macros for alsa2chip and chip2alsa, instead of functions */
++
++#define alsa2chip(vol) (uint)(-((vol << 8) / 100)) /* convert alsa to chip volume (defined as macro rather than function call) */
++#define chip2alsa(vol) -((vol * 100) >> 8) /* convert chip to alsa volume */
++
++/* Some constants for values .. */
++typedef enum {
++ AUDIO_DEST_AUTO = 0,
++ AUDIO_DEST_HEADPHONES = 1,
++ AUDIO_DEST_HDMI = 2,
++ AUDIO_DEST_MAX,
++} SND_BCM2835_ROUTE_T;
++
++typedef enum {
++ PCM_PLAYBACK_VOLUME,
++ PCM_PLAYBACK_MUTE,
++ PCM_PLAYBACK_DEVICE,
++} SND_BCM2835_CTRL_T;
++
++/* definition of the chip-specific record */
++typedef struct bcm2835_chip {
++ struct snd_card *card;
++ struct snd_pcm *pcm;
++ struct snd_pcm *pcm_spdif;
++ /* Bitmat for valid reg_base and irq numbers */
++ uint32_t avail_substreams;
++ struct platform_device *pdev[MAX_SUBSTREAMS];
++ struct bcm2835_alsa_stream *alsa_stream[MAX_SUBSTREAMS];
++
++ int volume;
++ int old_volume; /* stores the volume value whist muted */
++ int dest;
++ int mute;
++
++ unsigned int opened;
++ unsigned int spdif_status;
++ struct mutex audio_mutex;
++} bcm2835_chip_t;
++
++typedef struct bcm2835_alsa_stream {
++ bcm2835_chip_t *chip;
++ struct snd_pcm_substream *substream;
++ struct snd_pcm_indirect pcm_indirect;
++
++ struct semaphore buffers_update_sem;
++ struct semaphore control_sem;
++ spinlock_t lock;
++ volatile uint32_t control;
++ volatile uint32_t status;
++
++ int open;
++ int running;
++ int draining;
++
++ int channels;
++ int params_rate;
++ int pcm_format_width;
++
++ unsigned int pos;
++ unsigned int buffer_size;
++ unsigned int period_size;
++
++ uint32_t enable_fifo_irq;
++ irq_handler_t fifo_irq_handler;
++
++ atomic_t retrieved;
++ struct opaque_AUDIO_INSTANCE_T *instance;
++ struct workqueue_struct *my_wq;
++ int idx;
++} bcm2835_alsa_stream_t;
++
++int snd_bcm2835_new_ctl(bcm2835_chip_t * chip);
++int snd_bcm2835_new_pcm(bcm2835_chip_t * chip);
++int snd_bcm2835_new_spdif_pcm(bcm2835_chip_t * chip);
++
++int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream);
++int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream);
++int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
++ uint32_t channels, uint32_t samplerate,
++ uint32_t bps);
++int bcm2835_audio_setup(bcm2835_alsa_stream_t * alsa_stream);
++int bcm2835_audio_start(bcm2835_alsa_stream_t * alsa_stream);
++int bcm2835_audio_stop(bcm2835_alsa_stream_t * alsa_stream);
++int bcm2835_audio_set_ctls(bcm2835_chip_t * chip);
++int bcm2835_audio_write(bcm2835_alsa_stream_t * alsa_stream, uint32_t count,
++ void *src);
++uint32_t bcm2835_audio_retrieve_buffers(bcm2835_alsa_stream_t * alsa_stream);
++void bcm2835_audio_flush_buffers(bcm2835_alsa_stream_t * alsa_stream);
++void bcm2835_audio_flush_playback_buffers(bcm2835_alsa_stream_t * alsa_stream);
++
++#endif /* __SOUND_ARM_BCM2835_H */
+--- /dev/null
++++ b/sound/arm/vc_vchi_audioserv_defs.h
+@@ -0,0 +1,116 @@
++/*****************************************************************************
++* Copyright 2011 Broadcom Corporation. All rights reserved.
++*
++* Unless you and Broadcom execute a separate written software license
++* agreement governing use of this software, this software is licensed to you
++* under the terms of the GNU General Public License version 2, available at
++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
++*
++* Notwithstanding the above, under no circumstances may you combine this
++* software in any way with any other Broadcom software provided under a
++* license other than the GPL, without Broadcom's express prior written
++* consent.
++*****************************************************************************/
++
++#ifndef _VC_AUDIO_DEFS_H_
++#define _VC_AUDIO_DEFS_H_
++
++#define VC_AUDIOSERV_MIN_VER 1
++#define VC_AUDIOSERV_VER 2
++
++// FourCC code used for VCHI connection
++#define VC_AUDIO_SERVER_NAME MAKE_FOURCC("AUDS")
++
++// Maximum message length
++#define VC_AUDIO_MAX_MSG_LEN (sizeof( VC_AUDIO_MSG_T ))
++
++// List of screens that are currently supported
++// All message types supported for HOST->VC direction
++typedef enum {
++ VC_AUDIO_MSG_TYPE_RESULT, // Generic result
++ VC_AUDIO_MSG_TYPE_COMPLETE, // Generic result
++ VC_AUDIO_MSG_TYPE_CONFIG, // Configure audio
++ VC_AUDIO_MSG_TYPE_CONTROL, // Configure audio
++ VC_AUDIO_MSG_TYPE_OPEN, // Configure audio
++ VC_AUDIO_MSG_TYPE_CLOSE, // Configure audio
++ VC_AUDIO_MSG_TYPE_START, // Configure audio
++ VC_AUDIO_MSG_TYPE_STOP, // Configure audio
++ VC_AUDIO_MSG_TYPE_WRITE, // Configure audio
++ VC_AUDIO_MSG_TYPE_MAX
++} VC_AUDIO_MSG_TYPE;
++
++// configure the audio
++typedef struct {
++ uint32_t channels;
++ uint32_t samplerate;
++ uint32_t bps;
++
++} VC_AUDIO_CONFIG_T;
++
++typedef struct {
++ uint32_t volume;
++ uint32_t dest;
++
++} VC_AUDIO_CONTROL_T;
++
++// audio
++typedef struct {
++ uint32_t dummy;
++
++} VC_AUDIO_OPEN_T;
++
++// audio
++typedef struct {
++ uint32_t dummy;
++
++} VC_AUDIO_CLOSE_T;
++// audio
++typedef struct {
++ uint32_t dummy;
++
++} VC_AUDIO_START_T;
++// audio
++typedef struct {
++ uint32_t draining;
++
++} VC_AUDIO_STOP_T;
++
++// configure the write audio samples
++typedef struct {
++ uint32_t count; // in bytes
++ void *callback;
++ void *cookie;
++ uint16_t silence;
++ uint16_t max_packet;
++} VC_AUDIO_WRITE_T;
++
++// Generic result for a request (VC->HOST)
++typedef struct {
++ int32_t success; // Success value
++
++} VC_AUDIO_RESULT_T;
++
++// Generic result for a request (VC->HOST)
++typedef struct {
++ int32_t count; // Success value
++ void *callback;
++ void *cookie;
++} VC_AUDIO_COMPLETE_T;
++
++// Message header for all messages in HOST->VC direction
++typedef struct {
++ int32_t type; // Message type (VC_AUDIO_MSG_TYPE)
++ union {
++ VC_AUDIO_CONFIG_T config;
++ VC_AUDIO_CONTROL_T control;
++ VC_AUDIO_OPEN_T open;
++ VC_AUDIO_CLOSE_T close;
++ VC_AUDIO_START_T start;
++ VC_AUDIO_STOP_T stop;
++ VC_AUDIO_WRITE_T write;
++ VC_AUDIO_RESULT_T result;
++ VC_AUDIO_COMPLETE_T complete;
++ } u;
++} VC_AUDIO_MSG_T;
++
++#endif // _VC_AUDIO_DEFS_H_
diff --git a/target/linux/brcm2708/patches-4.4/0035-cma-Add-vc_cma-driver-to-enable-use-of-CMA.patch b/target/linux/brcm2708/patches-4.4/0035-cma-Add-vc_cma-driver-to-enable-use-of-CMA.patch
deleted file mode 100644
index 781068f496..0000000000
--- a/target/linux/brcm2708/patches-4.4/0035-cma-Add-vc_cma-driver-to-enable-use-of-CMA.patch
+++ /dev/null
@@ -1,1326 +0,0 @@
-From 8dbb0430386b772f636f474ed45496076d135428 Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Wed, 3 Jul 2013 00:31:47 +0100
-Subject: [PATCH 035/170] cma: Add vc_cma driver to enable use of CMA
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: popcornmix <popcornmix@gmail.com>
-
-vc_cma: Make the vc_cma area the default contiguous DMA area
-
-vc_cma: Provide empty functions when module is not built
-
-Providing empty functions saves the users from guarding the
-function call with an #if clause.
-Move __init markings from prototypes to functions.
-
-Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
----
- drivers/char/Kconfig | 2 +
- drivers/char/Makefile | 1 +
- drivers/char/broadcom/Kconfig | 15 +
- drivers/char/broadcom/Makefile | 1 +
- drivers/char/broadcom/vc_cma/Makefile | 14 +
- drivers/char/broadcom/vc_cma/vc_cma.c | 1193 +++++++++++++++++++++++++++++++++
- include/linux/broadcom/vc_cma.h | 36 +
- 7 files changed, 1262 insertions(+)
- create mode 100644 drivers/char/broadcom/Kconfig
- create mode 100644 drivers/char/broadcom/Makefile
- create mode 100644 drivers/char/broadcom/vc_cma/Makefile
- create mode 100644 drivers/char/broadcom/vc_cma/vc_cma.c
- create mode 100644 include/linux/broadcom/vc_cma.h
-
---- a/drivers/char/Kconfig
-+++ b/drivers/char/Kconfig
-@@ -4,6 +4,8 @@
-
- menu "Character devices"
-
-+source "drivers/char/broadcom/Kconfig"
-+
- source "drivers/tty/Kconfig"
-
- config DEVMEM
---- a/drivers/char/Makefile
-+++ b/drivers/char/Makefile
-@@ -60,3 +60,4 @@ js-rtc-y = rtc.o
-
- obj-$(CONFIG_TILE_SROM) += tile-srom.o
- obj-$(CONFIG_XILLYBUS) += xillybus/
-+obj-$(CONFIG_BRCM_CHAR_DRIVERS) += broadcom/
---- /dev/null
-+++ b/drivers/char/broadcom/Kconfig
-@@ -0,0 +1,15 @@
-+#
-+# Broadcom char driver config
-+#
-+
-+menuconfig BRCM_CHAR_DRIVERS
-+ bool "Broadcom Char Drivers"
-+ help
-+ Broadcom's char drivers
-+
-+config BCM_VC_CMA
-+ bool "Videocore CMA"
-+ depends on CMA && BRCM_CHAR_DRIVERS && BCM2708_VCHIQ
-+ default n
-+ help
-+ Helper for videocore CMA access.
---- /dev/null
-+++ b/drivers/char/broadcom/Makefile
-@@ -0,0 +1 @@
-+obj-$(CONFIG_BCM_VC_CMA) += vc_cma/
---- /dev/null
-+++ b/drivers/char/broadcom/vc_cma/Makefile
-@@ -0,0 +1,14 @@
-+ccflags-y += -Wall -Wstrict-prototypes -Wno-trigraphs
-+ccflags-y += -Werror
-+ccflags-y += -Iinclude/linux/broadcom
-+ccflags-y += -Idrivers/misc/vc04_services
-+ccflags-y += -Idrivers/misc/vc04_services/interface/vchi
-+ccflags-y += -Idrivers/misc/vc04_services/interface/vchiq_arm
-+
-+ccflags-y += -D__KERNEL__
-+ccflags-y += -D__linux__
-+ccflags-y += -Werror
-+
-+obj-$(CONFIG_BCM_VC_CMA) += vc-cma.o
-+
-+vc-cma-objs := vc_cma.o
---- /dev/null
-+++ b/drivers/char/broadcom/vc_cma/vc_cma.c
-@@ -0,0 +1,1193 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/kthread.h>
-+#include <linux/fs.h>
-+#include <linux/device.h>
-+#include <linux/cdev.h>
-+#include <linux/mm.h>
-+#include <linux/proc_fs.h>
-+#include <linux/seq_file.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/dma-contiguous.h>
-+#include <linux/platform_device.h>
-+#include <linux/uaccess.h>
-+#include <asm/cacheflush.h>
-+
-+#include "vc_cma.h"
-+
-+#include "vchiq_util.h"
-+#include "vchiq_connected.h"
-+//#include "debug_sym.h"
-+//#include "vc_mem.h"
-+
-+#define DRIVER_NAME "vc-cma"
-+
-+#define LOG_DBG(fmt, ...) \
-+ if (vc_cma_debug) \
-+ printk(KERN_INFO fmt "\n", ##__VA_ARGS__)
-+#define LOG_INFO(fmt, ...) \
-+ printk(KERN_INFO fmt "\n", ##__VA_ARGS__)
-+#define LOG_ERR(fmt, ...) \
-+ printk(KERN_ERR fmt "\n", ##__VA_ARGS__)
-+
-+#define VC_CMA_FOURCC VCHIQ_MAKE_FOURCC('C', 'M', 'A', ' ')
-+#define VC_CMA_VERSION 2
-+
-+#define VC_CMA_CHUNK_ORDER 6 /* 256K */
-+#define VC_CMA_CHUNK_SIZE (4096 << VC_CMA_CHUNK_ORDER)
-+#define VC_CMA_MAX_PARAMS_PER_MSG \
-+ ((VCHIQ_MAX_MSG_SIZE - sizeof(unsigned short))/sizeof(unsigned short))
-+#define VC_CMA_RESERVE_COUNT_MAX 16
-+
-+#define PAGES_PER_CHUNK (VC_CMA_CHUNK_SIZE / PAGE_SIZE)
-+
-+#define VCADDR_TO_PHYSADDR(vcaddr) (mm_vc_mem_phys_addr + vcaddr)
-+
-+#define loud_error(...) \
-+ LOG_ERR("===== " __VA_ARGS__)
-+
-+enum {
-+ VC_CMA_MSG_QUIT,
-+ VC_CMA_MSG_OPEN,
-+ VC_CMA_MSG_TICK,
-+ VC_CMA_MSG_ALLOC, /* chunk count */
-+ VC_CMA_MSG_FREE, /* chunk, chunk, ... */
-+ VC_CMA_MSG_ALLOCATED, /* chunk, chunk, ... */
-+ VC_CMA_MSG_REQUEST_ALLOC, /* chunk count */
-+ VC_CMA_MSG_REQUEST_FREE, /* chunk count */
-+ VC_CMA_MSG_RESERVE, /* bytes lo, bytes hi */
-+ VC_CMA_MSG_UPDATE_RESERVE,
-+ VC_CMA_MSG_MAX
-+};
-+
-+struct cma_msg {
-+ unsigned short type;
-+ unsigned short params[VC_CMA_MAX_PARAMS_PER_MSG];
-+};
-+
-+struct vc_cma_reserve_user {
-+ unsigned int pid;
-+ unsigned int reserve;
-+};
-+
-+/* Device (/dev) related variables */
-+static dev_t vc_cma_devnum;
-+static struct class *vc_cma_class;
-+static struct cdev vc_cma_cdev;
-+static int vc_cma_inited;
-+static int vc_cma_debug;
-+
-+/* Proc entry */
-+static struct proc_dir_entry *vc_cma_proc_entry;
-+
-+phys_addr_t vc_cma_base;
-+struct page *vc_cma_base_page;
-+unsigned int vc_cma_size;
-+EXPORT_SYMBOL(vc_cma_size);
-+unsigned int vc_cma_initial;
-+unsigned int vc_cma_chunks;
-+unsigned int vc_cma_chunks_used;
-+unsigned int vc_cma_chunks_reserved;
-+
-+
-+void *vc_cma_dma_alloc;
-+unsigned int vc_cma_dma_size;
-+
-+static int in_loud_error;
-+
-+unsigned int vc_cma_reserve_total;
-+unsigned int vc_cma_reserve_count;
-+struct vc_cma_reserve_user vc_cma_reserve_users[VC_CMA_RESERVE_COUNT_MAX];
-+static DEFINE_SEMAPHORE(vc_cma_reserve_mutex);
-+static DEFINE_SEMAPHORE(vc_cma_worker_queue_push_mutex);
-+
-+static u64 vc_cma_dma_mask = DMA_BIT_MASK(32);
-+static struct platform_device vc_cma_device = {
-+ .name = "vc-cma",
-+ .id = 0,
-+ .dev = {
-+ .dma_mask = &vc_cma_dma_mask,
-+ .coherent_dma_mask = DMA_BIT_MASK(32),
-+ },
-+};
-+
-+static VCHIQ_INSTANCE_T cma_instance;
-+static VCHIQ_SERVICE_HANDLE_T cma_service;
-+static VCHIU_QUEUE_T cma_msg_queue;
-+static struct task_struct *cma_worker;
-+
-+static int vc_cma_set_reserve(unsigned int reserve, unsigned int pid);
-+static int vc_cma_alloc_chunks(int num_chunks, struct cma_msg *reply);
-+static VCHIQ_STATUS_T cma_service_callback(VCHIQ_REASON_T reason,
-+ VCHIQ_HEADER_T * header,
-+ VCHIQ_SERVICE_HANDLE_T service,
-+ void *bulk_userdata);
-+static void send_vc_msg(unsigned short type,
-+ unsigned short param1, unsigned short param2);
-+static bool send_worker_msg(VCHIQ_HEADER_T * msg);
-+
-+static int early_vc_cma_mem(char *p)
-+{
-+ unsigned int new_size;
-+ printk(KERN_NOTICE "early_vc_cma_mem(%s)", p);
-+ vc_cma_size = memparse(p, &p);
-+ vc_cma_initial = vc_cma_size;
-+ if (*p == '/')
-+ vc_cma_size = memparse(p + 1, &p);
-+ if (*p == '@')
-+ vc_cma_base = memparse(p + 1, &p);
-+
-+ new_size = (vc_cma_size - ((-vc_cma_base) & (VC_CMA_CHUNK_SIZE - 1)))
-+ & ~(VC_CMA_CHUNK_SIZE - 1);
-+ if (new_size > vc_cma_size)
-+ vc_cma_size = 0;
-+ vc_cma_initial = (vc_cma_initial + VC_CMA_CHUNK_SIZE - 1)
-+ & ~(VC_CMA_CHUNK_SIZE - 1);
-+ if (vc_cma_initial > vc_cma_size)
-+ vc_cma_initial = vc_cma_size;
-+ vc_cma_base = (vc_cma_base + VC_CMA_CHUNK_SIZE - 1)
-+ & ~(VC_CMA_CHUNK_SIZE - 1);
-+
-+ printk(KERN_NOTICE " -> initial %x, size %x, base %x", vc_cma_initial,
-+ vc_cma_size, (unsigned int)vc_cma_base);
-+
-+ return 0;
-+}
-+
-+early_param("vc-cma-mem", early_vc_cma_mem);
-+
-+void __init vc_cma_early_init(void)
-+{
-+ LOG_DBG("vc_cma_early_init - vc_cma_chunks = %d", vc_cma_chunks);
-+ if (vc_cma_size) {
-+ int rc = platform_device_register(&vc_cma_device);
-+ LOG_DBG("platform_device_register -> %d", rc);
-+ }
-+}
-+
-+void __init vc_cma_reserve(void)
-+{
-+ /* if vc_cma_size is set, then declare vc CMA area of the same
-+ * size from the end of memory
-+ */
-+ if (vc_cma_size) {
-+ if (dma_declare_contiguous(&vc_cma_device.dev, vc_cma_size,
-+ vc_cma_base, 0) == 0) {
-+ if (!dev_get_cma_area(NULL)) {
-+ /* There is no default CMA area - make this
-+ the default */
-+ struct cma *vc_cma_area = dev_get_cma_area(
-+ &vc_cma_device.dev);
-+ dma_contiguous_set_default(vc_cma_area);
-+ LOG_INFO("vc_cma_reserve - using vc_cma as "
-+ "the default contiguous DMA area");
-+ }
-+ } else {
-+ LOG_ERR("vc_cma: dma_declare_contiguous(%x,%x) failed",
-+ vc_cma_size, (unsigned int)vc_cma_base);
-+ vc_cma_size = 0;
-+ }
-+ }
-+ vc_cma_chunks = vc_cma_size / VC_CMA_CHUNK_SIZE;
-+}
-+
-+/****************************************************************************
-+*
-+* vc_cma_open
-+*
-+***************************************************************************/
-+
-+static int vc_cma_open(struct inode *inode, struct file *file)
-+{
-+ (void)inode;
-+ (void)file;
-+
-+ return 0;
-+}
-+
-+/****************************************************************************
-+*
-+* vc_cma_release
-+*
-+***************************************************************************/
-+
-+static int vc_cma_release(struct inode *inode, struct file *file)
-+{
-+ (void)inode;
-+ (void)file;
-+
-+ vc_cma_set_reserve(0, current->tgid);
-+
-+ return 0;
-+}
-+
-+/****************************************************************************
-+*
-+* vc_cma_ioctl
-+*
-+***************************************************************************/
-+
-+static long vc_cma_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-+{
-+ int rc = 0;
-+
-+ (void)cmd;
-+ (void)arg;
-+
-+ switch (cmd) {
-+ case VC_CMA_IOC_RESERVE:
-+ rc = vc_cma_set_reserve((unsigned int)arg, current->tgid);
-+ if (rc >= 0)
-+ rc = 0;
-+ break;
-+ default:
-+ LOG_ERR("vc-cma: Unknown ioctl %x", cmd);
-+ return -ENOTTY;
-+ }
-+
-+ return rc;
-+}
-+
-+/****************************************************************************
-+*
-+* File Operations for the driver.
-+*
-+***************************************************************************/
-+
-+static const struct file_operations vc_cma_fops = {
-+ .owner = THIS_MODULE,
-+ .open = vc_cma_open,
-+ .release = vc_cma_release,
-+ .unlocked_ioctl = vc_cma_ioctl,
-+};
-+
-+/****************************************************************************
-+*
-+* vc_cma_proc_open
-+*
-+***************************************************************************/
-+
-+static int vc_cma_show_info(struct seq_file *m, void *v)
-+{
-+ int i;
-+
-+ seq_printf(m, "Videocore CMA:\n");
-+ seq_printf(m, " Base : %08x\n", (unsigned int)vc_cma_base);
-+ seq_printf(m, " Length : %08x\n", vc_cma_size);
-+ seq_printf(m, " Initial : %08x\n", vc_cma_initial);
-+ seq_printf(m, " Chunk size : %08x\n", VC_CMA_CHUNK_SIZE);
-+ seq_printf(m, " Chunks : %4d (%d bytes)\n",
-+ (int)vc_cma_chunks,
-+ (int)(vc_cma_chunks * VC_CMA_CHUNK_SIZE));
-+ seq_printf(m, " Used : %4d (%d bytes)\n",
-+ (int)vc_cma_chunks_used,
-+ (int)(vc_cma_chunks_used * VC_CMA_CHUNK_SIZE));
-+ seq_printf(m, " Reserved : %4d (%d bytes)\n",
-+ (unsigned int)vc_cma_chunks_reserved,
-+ (int)(vc_cma_chunks_reserved * VC_CMA_CHUNK_SIZE));
-+
-+ for (i = 0; i < vc_cma_reserve_count; i++) {
-+ struct vc_cma_reserve_user *user = &vc_cma_reserve_users[i];
-+ seq_printf(m, " PID %5d: %d bytes\n", user->pid,
-+ user->reserve);
-+ }
-+ seq_printf(m, " dma_alloc : %p (%d pages)\n",
-+ vc_cma_dma_alloc ? page_address(vc_cma_dma_alloc) : 0,
-+ vc_cma_dma_size);
-+
-+ seq_printf(m, "\n");
-+
-+ return 0;
-+}
-+
-+static int vc_cma_proc_open(struct inode *inode, struct file *file)
-+{
-+ return single_open(file, vc_cma_show_info, NULL);
-+}
-+
-+/****************************************************************************
-+*
-+* vc_cma_proc_write
-+*
-+***************************************************************************/
-+
-+static int vc_cma_proc_write(struct file *file,
-+ const char __user *buffer,
-+ size_t size, loff_t *ppos)
-+{
-+ int rc = -EFAULT;
-+ char input_str[20];
-+
-+ memset(input_str, 0, sizeof(input_str));
-+
-+ if (size > sizeof(input_str)) {
-+ LOG_ERR("%s: input string length too long", __func__);
-+ goto out;
-+ }
-+
-+ if (copy_from_user(input_str, buffer, size - 1)) {
-+ LOG_ERR("%s: failed to get input string", __func__);
-+ goto out;
-+ }
-+#define ALLOC_STR "alloc"
-+#define FREE_STR "free"
-+#define DEBUG_STR "debug"
-+#define RESERVE_STR "reserve"
-+#define DMA_ALLOC_STR "dma_alloc"
-+#define DMA_FREE_STR "dma_free"
-+ if (strncmp(input_str, ALLOC_STR, strlen(ALLOC_STR)) == 0) {
-+ int alloc_size;
-+ char *p = input_str + strlen(ALLOC_STR);
-+
-+ while (*p == ' ')
-+ p++;
-+ alloc_size = memparse(p, NULL);
-+ LOG_INFO("/proc/vc-cma: alloc %d", alloc_size);
-+ if (alloc_size)
-+ send_vc_msg(VC_CMA_MSG_REQUEST_FREE,
-+ alloc_size / VC_CMA_CHUNK_SIZE, 0);
-+ else
-+ LOG_ERR("invalid size '%s'", p);
-+ rc = size;
-+ } else if (strncmp(input_str, FREE_STR, strlen(FREE_STR)) == 0) {
-+ int alloc_size;
-+ char *p = input_str + strlen(FREE_STR);
-+
-+ while (*p == ' ')
-+ p++;
-+ alloc_size = memparse(p, NULL);
-+ LOG_INFO("/proc/vc-cma: free %d", alloc_size);
-+ if (alloc_size)
-+ send_vc_msg(VC_CMA_MSG_REQUEST_ALLOC,
-+ alloc_size / VC_CMA_CHUNK_SIZE, 0);
-+ else
-+ LOG_ERR("invalid size '%s'", p);
-+ rc = size;
-+ } else if (strncmp(input_str, DEBUG_STR, strlen(DEBUG_STR)) == 0) {
-+ char *p = input_str + strlen(DEBUG_STR);
-+ while (*p == ' ')
-+ p++;
-+ if ((strcmp(p, "on") == 0) || (strcmp(p, "1") == 0))
-+ vc_cma_debug = 1;
-+ else if ((strcmp(p, "off") == 0) || (strcmp(p, "0") == 0))
-+ vc_cma_debug = 0;
-+ LOG_INFO("/proc/vc-cma: debug %s", vc_cma_debug ? "on" : "off");
-+ rc = size;
-+ } else if (strncmp(input_str, RESERVE_STR, strlen(RESERVE_STR)) == 0) {
-+ int alloc_size;
-+ int reserved;
-+ char *p = input_str + strlen(RESERVE_STR);
-+ while (*p == ' ')
-+ p++;
-+ alloc_size = memparse(p, NULL);
-+
-+ reserved = vc_cma_set_reserve(alloc_size, current->tgid);
-+ rc = (reserved >= 0) ? size : reserved;
-+ } else if (strncmp(input_str, DMA_ALLOC_STR, strlen(DMA_ALLOC_STR)) == 0) {
-+ int alloc_size;
-+ char *p = input_str + strlen(DMA_ALLOC_STR);
-+ while (*p == ' ')
-+ p++;
-+ alloc_size = memparse(p, NULL);
-+
-+ if (vc_cma_dma_alloc) {
-+ dma_release_from_contiguous(NULL, vc_cma_dma_alloc,
-+ vc_cma_dma_size);
-+ vc_cma_dma_alloc = NULL;
-+ vc_cma_dma_size = 0;
-+ }
-+ vc_cma_dma_alloc = dma_alloc_from_contiguous(NULL, alloc_size, 0);
-+ vc_cma_dma_size = (vc_cma_dma_alloc ? alloc_size : 0);
-+ if (vc_cma_dma_alloc)
-+ LOG_INFO("dma_alloc(%d pages) -> %p", alloc_size, page_address(vc_cma_dma_alloc));
-+ else
-+ LOG_ERR("dma_alloc(%d pages) failed", alloc_size);
-+ rc = size;
-+ } else if (strncmp(input_str, DMA_FREE_STR, strlen(DMA_FREE_STR)) == 0) {
-+ if (vc_cma_dma_alloc) {
-+ dma_release_from_contiguous(NULL, vc_cma_dma_alloc,
-+ vc_cma_dma_size);
-+ vc_cma_dma_alloc = NULL;
-+ vc_cma_dma_size = 0;
-+ }
-+ rc = size;
-+ }
-+
-+out:
-+ return rc;
-+}
-+
-+/****************************************************************************
-+*
-+* File Operations for /proc interface.
-+*
-+***************************************************************************/
-+
-+static const struct file_operations vc_cma_proc_fops = {
-+ .open = vc_cma_proc_open,
-+ .read = seq_read,
-+ .write = vc_cma_proc_write,
-+ .llseek = seq_lseek,
-+ .release = single_release
-+};
-+
-+static int vc_cma_set_reserve(unsigned int reserve, unsigned int pid)
-+{
-+ struct vc_cma_reserve_user *user = NULL;
-+ int delta = 0;
-+ int i;
-+
-+ if (down_interruptible(&vc_cma_reserve_mutex))
-+ return -ERESTARTSYS;
-+
-+ for (i = 0; i < vc_cma_reserve_count; i++) {
-+ if (pid == vc_cma_reserve_users[i].pid) {
-+ user = &vc_cma_reserve_users[i];
-+ delta = reserve - user->reserve;
-+ if (reserve)
-+ user->reserve = reserve;
-+ else {
-+ /* Remove this entry by copying downwards */
-+ while ((i + 1) < vc_cma_reserve_count) {
-+ user[0].pid = user[1].pid;
-+ user[0].reserve = user[1].reserve;
-+ user++;
-+ i++;
-+ }
-+ vc_cma_reserve_count--;
-+ user = NULL;
-+ }
-+ break;
-+ }
-+ }
-+
-+ if (reserve && !user) {
-+ if (vc_cma_reserve_count == VC_CMA_RESERVE_COUNT_MAX) {
-+ LOG_ERR("vc-cma: Too many reservations - "
-+ "increase CMA_RESERVE_COUNT_MAX");
-+ up(&vc_cma_reserve_mutex);
-+ return -EBUSY;
-+ }
-+ user = &vc_cma_reserve_users[vc_cma_reserve_count];
-+ user->pid = pid;
-+ user->reserve = reserve;
-+ delta = reserve;
-+ vc_cma_reserve_count++;
-+ }
-+
-+ vc_cma_reserve_total += delta;
-+
-+ send_vc_msg(VC_CMA_MSG_RESERVE,
-+ vc_cma_reserve_total & 0xffff, vc_cma_reserve_total >> 16);
-+
-+ send_worker_msg((VCHIQ_HEADER_T *) VC_CMA_MSG_UPDATE_RESERVE);
-+
-+ LOG_DBG("/proc/vc-cma: reserve %d (PID %d) - total %u",
-+ reserve, pid, vc_cma_reserve_total);
-+
-+ up(&vc_cma_reserve_mutex);
-+
-+ return vc_cma_reserve_total;
-+}
-+
-+static VCHIQ_STATUS_T cma_service_callback(VCHIQ_REASON_T reason,
-+ VCHIQ_HEADER_T * header,
-+ VCHIQ_SERVICE_HANDLE_T service,
-+ void *bulk_userdata)
-+{
-+ switch (reason) {
-+ case VCHIQ_MESSAGE_AVAILABLE:
-+ if (!send_worker_msg(header))
-+ return VCHIQ_RETRY;
-+ break;
-+ case VCHIQ_SERVICE_CLOSED:
-+ LOG_DBG("CMA service closed");
-+ break;
-+ default:
-+ LOG_ERR("Unexpected CMA callback reason %d", reason);
-+ break;
-+ }
-+ return VCHIQ_SUCCESS;
-+}
-+
-+static void send_vc_msg(unsigned short type,
-+ unsigned short param1, unsigned short param2)
-+{
-+ unsigned short msg[] = { type, param1, param2 };
-+ VCHIQ_ELEMENT_T elem = { &msg, sizeof(msg) };
-+ VCHIQ_STATUS_T ret;
-+ vchiq_use_service(cma_service);
-+ ret = vchiq_queue_message(cma_service, &elem, 1);
-+ vchiq_release_service(cma_service);
-+ if (ret != VCHIQ_SUCCESS)
-+ LOG_ERR("vchiq_queue_message returned %x", ret);
-+}
-+
-+static bool send_worker_msg(VCHIQ_HEADER_T * msg)
-+{
-+ if (down_interruptible(&vc_cma_worker_queue_push_mutex))
-+ return false;
-+ vchiu_queue_push(&cma_msg_queue, msg);
-+ up(&vc_cma_worker_queue_push_mutex);
-+ return true;
-+}
-+
-+static int vc_cma_alloc_chunks(int num_chunks, struct cma_msg *reply)
-+{
-+ int i;
-+ for (i = 0; i < num_chunks; i++) {
-+ struct page *chunk;
-+ unsigned int chunk_num;
-+ uint8_t *chunk_addr;
-+ size_t chunk_size = PAGES_PER_CHUNK << PAGE_SHIFT;
-+
-+ chunk = dma_alloc_from_contiguous(&vc_cma_device.dev,
-+ PAGES_PER_CHUNK,
-+ VC_CMA_CHUNK_ORDER);
-+ if (!chunk)
-+ break;
-+
-+ chunk_addr = page_address(chunk);
-+ dmac_flush_range(chunk_addr, chunk_addr + chunk_size);
-+ outer_inv_range(__pa(chunk_addr), __pa(chunk_addr) +
-+ chunk_size);
-+
-+ chunk_num =
-+ (page_to_phys(chunk) - vc_cma_base) / VC_CMA_CHUNK_SIZE;
-+ BUG_ON(((page_to_phys(chunk) - vc_cma_base) %
-+ VC_CMA_CHUNK_SIZE) != 0);
-+ if (chunk_num >= vc_cma_chunks) {
-+ phys_addr_t _pa = vc_cma_base + vc_cma_size - 1;
-+ LOG_ERR("%s: ===============================",
-+ __func__);
-+ LOG_ERR("%s: chunk phys %x, vc_cma %pa-%pa - "
-+ "bad SPARSEMEM configuration?",
-+ __func__, (unsigned int)page_to_phys(chunk),
-+ &vc_cma_base, &_pa);
-+ LOG_ERR("%s: dev->cma_area = %p", __func__,
-+ (void*)0/*vc_cma_device.dev.cma_area*/);
-+ LOG_ERR("%s: ===============================",
-+ __func__);
-+ break;
-+ }
-+ reply->params[i] = chunk_num;
-+ vc_cma_chunks_used++;
-+ }
-+
-+ if (i < num_chunks) {
-+ LOG_ERR("%s: dma_alloc_from_contiguous failed "
-+ "for %x bytes (alloc %d of %d, %d free)",
-+ __func__, VC_CMA_CHUNK_SIZE, i,
-+ num_chunks, vc_cma_chunks - vc_cma_chunks_used);
-+ num_chunks = i;
-+ }
-+
-+ LOG_DBG("CMA allocated %d chunks -> %d used",
-+ num_chunks, vc_cma_chunks_used);
-+ reply->type = VC_CMA_MSG_ALLOCATED;
-+
-+ {
-+ VCHIQ_ELEMENT_T elem = {
-+ reply,
-+ offsetof(struct cma_msg, params[0]) +
-+ num_chunks * sizeof(reply->params[0])
-+ };
-+ VCHIQ_STATUS_T ret;
-+ vchiq_use_service(cma_service);
-+ ret = vchiq_queue_message(cma_service, &elem, 1);
-+ vchiq_release_service(cma_service);
-+ if (ret != VCHIQ_SUCCESS)
-+ LOG_ERR("vchiq_queue_message return " "%x", ret);
-+ }
-+
-+ return num_chunks;
-+}
-+
-+static int cma_worker_proc(void *param)
-+{
-+ static struct cma_msg reply;
-+ (void)param;
-+
-+ while (1) {
-+ VCHIQ_HEADER_T *msg;
-+ static struct cma_msg msg_copy;
-+ struct cma_msg *cma_msg = &msg_copy;
-+ int type, msg_size;
-+
-+ msg = vchiu_queue_pop(&cma_msg_queue);
-+ if ((unsigned int)msg >= VC_CMA_MSG_MAX) {
-+ msg_size = msg->size;
-+ memcpy(&msg_copy, msg->data, msg_size);
-+ type = cma_msg->type;
-+ vchiq_release_message(cma_service, msg);
-+ } else {
-+ msg_size = 0;
-+ type = (int)msg;
-+ if (type == VC_CMA_MSG_QUIT)
-+ break;
-+ else if (type == VC_CMA_MSG_UPDATE_RESERVE) {
-+ msg = NULL;
-+ cma_msg = NULL;
-+ } else {
-+ BUG();
-+ continue;
-+ }
-+ }
-+
-+ switch (type) {
-+ case VC_CMA_MSG_ALLOC:{
-+ int num_chunks, free_chunks;
-+ num_chunks = cma_msg->params[0];
-+ free_chunks =
-+ vc_cma_chunks - vc_cma_chunks_used;
-+ LOG_DBG("CMA_MSG_ALLOC(%d chunks)", num_chunks);
-+ if (num_chunks > VC_CMA_MAX_PARAMS_PER_MSG) {
-+ LOG_ERR
-+ ("CMA_MSG_ALLOC - chunk count (%d) "
-+ "exceeds VC_CMA_MAX_PARAMS_PER_MSG (%d)",
-+ num_chunks,
-+ VC_CMA_MAX_PARAMS_PER_MSG);
-+ num_chunks = VC_CMA_MAX_PARAMS_PER_MSG;
-+ }
-+
-+ if (num_chunks > free_chunks) {
-+ LOG_ERR
-+ ("CMA_MSG_ALLOC - chunk count (%d) "
-+ "exceeds free chunks (%d)",
-+ num_chunks, free_chunks);
-+ num_chunks = free_chunks;
-+ }
-+
-+ vc_cma_alloc_chunks(num_chunks, &reply);
-+ }
-+ break;
-+
-+ case VC_CMA_MSG_FREE:{
-+ int chunk_count =
-+ (msg_size -
-+ offsetof(struct cma_msg,
-+ params)) /
-+ sizeof(cma_msg->params[0]);
-+ int i;
-+ BUG_ON(chunk_count <= 0);
-+
-+ LOG_DBG("CMA_MSG_FREE(%d chunks - %x, ...)",
-+ chunk_count, cma_msg->params[0]);
-+ for (i = 0; i < chunk_count; i++) {
-+ int chunk_num = cma_msg->params[i];
-+ struct page *page = vc_cma_base_page +
-+ chunk_num * PAGES_PER_CHUNK;
-+ if (chunk_num >= vc_cma_chunks) {
-+ LOG_ERR
-+ ("CMA_MSG_FREE - chunk %d of %d"
-+ " (value %x) exceeds maximum "
-+ "(%x)", i, chunk_count,
-+ chunk_num,
-+ vc_cma_chunks - 1);
-+ break;
-+ }
-+
-+ if (!dma_release_from_contiguous
-+ (&vc_cma_device.dev, page,
-+ PAGES_PER_CHUNK)) {
-+ phys_addr_t _pa = page_to_phys(page);
-+ LOG_ERR
-+ ("CMA_MSG_FREE - failed to "
-+ "release chunk %d (phys %pa, "
-+ "page %x)", chunk_num,
-+ &_pa,
-+ (unsigned int)page);
-+ }
-+ vc_cma_chunks_used--;
-+ }
-+ LOG_DBG("CMA released %d chunks -> %d used",
-+ i, vc_cma_chunks_used);
-+ }
-+ break;
-+
-+ case VC_CMA_MSG_UPDATE_RESERVE:{
-+ int chunks_needed =
-+ ((vc_cma_reserve_total + VC_CMA_CHUNK_SIZE -
-+ 1)
-+ / VC_CMA_CHUNK_SIZE) -
-+ vc_cma_chunks_reserved;
-+
-+ LOG_DBG
-+ ("CMA_MSG_UPDATE_RESERVE(%d chunks needed)",
-+ chunks_needed);
-+
-+ /* Cap the reservations to what is available */
-+ if (chunks_needed > 0) {
-+ if (chunks_needed >
-+ (vc_cma_chunks -
-+ vc_cma_chunks_used))
-+ chunks_needed =
-+ (vc_cma_chunks -
-+ vc_cma_chunks_used);
-+
-+ chunks_needed =
-+ vc_cma_alloc_chunks(chunks_needed,
-+ &reply);
-+ }
-+
-+ LOG_DBG
-+ ("CMA_MSG_UPDATE_RESERVE(%d chunks allocated)",
-+ chunks_needed);
-+ vc_cma_chunks_reserved += chunks_needed;
-+ }
-+ break;
-+
-+ default:
-+ LOG_ERR("unexpected msg type %d", type);
-+ break;
-+ }
-+ }
-+
-+ LOG_DBG("quitting...");
-+ return 0;
-+}
-+
-+/****************************************************************************
-+*
-+* vc_cma_connected_init
-+*
-+* This function is called once the videocore has been connected.
-+*
-+***************************************************************************/
-+
-+static void vc_cma_connected_init(void)
-+{
-+ VCHIQ_SERVICE_PARAMS_T service_params;
-+
-+ LOG_DBG("vc_cma_connected_init");
-+
-+ if (!vchiu_queue_init(&cma_msg_queue, 16)) {
-+ LOG_ERR("could not create CMA msg queue");
-+ goto fail_queue;
-+ }
-+
-+ if (vchiq_initialise(&cma_instance) != VCHIQ_SUCCESS)
-+ goto fail_vchiq_init;
-+
-+ vchiq_connect(cma_instance);
-+
-+ service_params.fourcc = VC_CMA_FOURCC;
-+ service_params.callback = cma_service_callback;
-+ service_params.userdata = NULL;
-+ service_params.version = VC_CMA_VERSION;
-+ service_params.version_min = VC_CMA_VERSION;
-+
-+ if (vchiq_open_service(cma_instance, &service_params,
-+ &cma_service) != VCHIQ_SUCCESS) {
-+ LOG_ERR("failed to open service - already in use?");
-+ goto fail_vchiq_open;
-+ }
-+
-+ vchiq_release_service(cma_service);
-+
-+ cma_worker = kthread_create(cma_worker_proc, NULL, "cma_worker");
-+ if (!cma_worker) {
-+ LOG_ERR("could not create CMA worker thread");
-+ goto fail_worker;
-+ }
-+ set_user_nice(cma_worker, -20);
-+ wake_up_process(cma_worker);
-+
-+ return;
-+
-+fail_worker:
-+ vchiq_close_service(cma_service);
-+fail_vchiq_open:
-+ vchiq_shutdown(cma_instance);
-+fail_vchiq_init:
-+ vchiu_queue_delete(&cma_msg_queue);
-+fail_queue:
-+ return;
-+}
-+
-+void
-+loud_error_header(void)
-+{
-+ if (in_loud_error)
-+ return;
-+
-+ LOG_ERR("============================================================"
-+ "================");
-+ LOG_ERR("============================================================"
-+ "================");
-+ LOG_ERR("=====");
-+
-+ in_loud_error = 1;
-+}
-+
-+void
-+loud_error_footer(void)
-+{
-+ if (!in_loud_error)
-+ return;
-+
-+ LOG_ERR("=====");
-+ LOG_ERR("============================================================"
-+ "================");
-+ LOG_ERR("============================================================"
-+ "================");
-+
-+ in_loud_error = 0;
-+}
-+
-+#if 1
-+static int check_cma_config(void) { return 1; }
-+#else
-+static int
-+read_vc_debug_var(VC_MEM_ACCESS_HANDLE_T handle,
-+ const char *symbol,
-+ void *buf, size_t bufsize)
-+{
-+ VC_MEM_ADDR_T vcMemAddr;
-+ size_t vcMemSize;
-+ uint8_t *mapAddr;
-+ off_t vcMapAddr;
-+
-+ if (!LookupVideoCoreSymbol(handle, symbol,
-+ &vcMemAddr,
-+ &vcMemSize)) {
-+ loud_error_header();
-+ loud_error(
-+ "failed to find VC symbol \"%s\".",
-+ symbol);
-+ loud_error_footer();
-+ return 0;
-+ }
-+
-+ if (vcMemSize != bufsize) {
-+ loud_error_header();
-+ loud_error(
-+ "VC symbol \"%s\" is the wrong size.",
-+ symbol);
-+ loud_error_footer();
-+ return 0;
-+ }
-+
-+ vcMapAddr = (off_t)vcMemAddr & VC_MEM_TO_ARM_ADDR_MASK;
-+ vcMapAddr += mm_vc_mem_phys_addr;
-+ mapAddr = ioremap_nocache(vcMapAddr, vcMemSize);
-+ if (mapAddr == 0) {
-+ loud_error_header();
-+ loud_error(
-+ "failed to ioremap \"%s\" @ 0x%x "
-+ "(phys: 0x%x, size: %u).",
-+ symbol,
-+ (unsigned int)vcMapAddr,
-+ (unsigned int)vcMemAddr,
-+ (unsigned int)vcMemSize);
-+ loud_error_footer();
-+ return 0;
-+ }
-+
-+ memcpy(buf, mapAddr, bufsize);
-+ iounmap(mapAddr);
-+
-+ return 1;
-+}
-+
-+
-+static int
-+check_cma_config(void)
-+{
-+ VC_MEM_ACCESS_HANDLE_T mem_hndl;
-+ VC_MEM_ADDR_T mempool_start;
-+ VC_MEM_ADDR_T mempool_end;
-+ VC_MEM_ADDR_T mempool_offline_start;
-+ VC_MEM_ADDR_T mempool_offline_end;
-+ VC_MEM_ADDR_T cam_alloc_base;
-+ VC_MEM_ADDR_T cam_alloc_size;
-+ VC_MEM_ADDR_T cam_alloc_end;
-+ int success = 0;
-+
-+ if (OpenVideoCoreMemory(&mem_hndl) != 0)
-+ goto out;
-+
-+ /* Read the relevant VideoCore variables */
-+ if (!read_vc_debug_var(mem_hndl, "__MEMPOOL_START",
-+ &mempool_start,
-+ sizeof(mempool_start)))
-+ goto close;
-+
-+ if (!read_vc_debug_var(mem_hndl, "__MEMPOOL_END",
-+ &mempool_end,
-+ sizeof(mempool_end)))
-+ goto close;
-+
-+ if (!read_vc_debug_var(mem_hndl, "__MEMPOOL_OFFLINE_START",
-+ &mempool_offline_start,
-+ sizeof(mempool_offline_start)))
-+ goto close;
-+
-+ if (!read_vc_debug_var(mem_hndl, "__MEMPOOL_OFFLINE_END",
-+ &mempool_offline_end,
-+ sizeof(mempool_offline_end)))
-+ goto close;
-+
-+ if (!read_vc_debug_var(mem_hndl, "cam_alloc_base",
-+ &cam_alloc_base,
-+ sizeof(cam_alloc_base)))
-+ goto close;
-+
-+ if (!read_vc_debug_var(mem_hndl, "cam_alloc_size",
-+ &cam_alloc_size,
-+ sizeof(cam_alloc_size)))
-+ goto close;
-+
-+ cam_alloc_end = cam_alloc_base + cam_alloc_size;
-+
-+ success = 1;
-+
-+ /* Now the sanity checks */
-+ if (!mempool_offline_start)
-+ mempool_offline_start = mempool_start;
-+ if (!mempool_offline_end)
-+ mempool_offline_end = mempool_end;
-+
-+ if (VCADDR_TO_PHYSADDR(mempool_offline_start) != vc_cma_base) {
-+ loud_error_header();
-+ loud_error(
-+ "__MEMPOOL_OFFLINE_START(%x -> %lx) doesn't match "
-+ "vc_cma_base(%x)",
-+ mempool_offline_start,
-+ VCADDR_TO_PHYSADDR(mempool_offline_start),
-+ vc_cma_base);
-+ success = 0;
-+ }
-+
-+ if (VCADDR_TO_PHYSADDR(mempool_offline_end) !=
-+ (vc_cma_base + vc_cma_size)) {
-+ loud_error_header();
-+ loud_error(
-+ "__MEMPOOL_OFFLINE_END(%x -> %lx) doesn't match "
-+ "vc_cma_base(%x) + vc_cma_size(%x) = %x",
-+ mempool_offline_start,
-+ VCADDR_TO_PHYSADDR(mempool_offline_end),
-+ vc_cma_base, vc_cma_size, vc_cma_base + vc_cma_size);
-+ success = 0;
-+ }
-+
-+ if (mempool_end < mempool_start) {
-+ loud_error_header();
-+ loud_error(
-+ "__MEMPOOL_END(%x) must not be before "
-+ "__MEMPOOL_START(%x)",
-+ mempool_end,
-+ mempool_start);
-+ success = 0;
-+ }
-+
-+ if (mempool_offline_end < mempool_offline_start) {
-+ loud_error_header();
-+ loud_error(
-+ "__MEMPOOL_OFFLINE_END(%x) must not be before "
-+ "__MEMPOOL_OFFLINE_START(%x)",
-+ mempool_offline_end,
-+ mempool_offline_start);
-+ success = 0;
-+ }
-+
-+ if (mempool_offline_start < mempool_start) {
-+ loud_error_header();
-+ loud_error(
-+ "__MEMPOOL_OFFLINE_START(%x) must not be before "
-+ "__MEMPOOL_START(%x)",
-+ mempool_offline_start,
-+ mempool_start);
-+ success = 0;
-+ }
-+
-+ if (mempool_offline_end > mempool_end) {
-+ loud_error_header();
-+ loud_error(
-+ "__MEMPOOL_OFFLINE_END(%x) must not be after "
-+ "__MEMPOOL_END(%x)",
-+ mempool_offline_end,
-+ mempool_end);
-+ success = 0;
-+ }
-+
-+ if ((cam_alloc_base < mempool_end) &&
-+ (cam_alloc_end > mempool_start)) {
-+ loud_error_header();
-+ loud_error(
-+ "cam_alloc pool(%x-%x) overlaps "
-+ "mempool(%x-%x)",
-+ cam_alloc_base, cam_alloc_end,
-+ mempool_start, mempool_end);
-+ success = 0;
-+ }
-+
-+ loud_error_footer();
-+
-+close:
-+ CloseVideoCoreMemory(mem_hndl);
-+
-+out:
-+ return success;
-+}
-+#endif
-+
-+static int vc_cma_init(void)
-+{
-+ int rc = -EFAULT;
-+ struct device *dev;
-+
-+ if (!check_cma_config())
-+ goto out_release;
-+
-+ LOG_INFO("vc-cma: Videocore CMA driver");
-+ LOG_INFO("vc-cma: vc_cma_base = %pa", &vc_cma_base);
-+ LOG_INFO("vc-cma: vc_cma_size = 0x%08x (%u MiB)",
-+ vc_cma_size, vc_cma_size / (1024 * 1024));
-+ LOG_INFO("vc-cma: vc_cma_initial = 0x%08x (%u MiB)",
-+ vc_cma_initial, vc_cma_initial / (1024 * 1024));
-+
-+ vc_cma_base_page = phys_to_page(vc_cma_base);
-+
-+ if (vc_cma_chunks) {
-+ int chunks_needed = vc_cma_initial / VC_CMA_CHUNK_SIZE;
-+
-+ for (vc_cma_chunks_used = 0;
-+ vc_cma_chunks_used < chunks_needed; vc_cma_chunks_used++) {
-+ struct page *chunk;
-+ chunk = dma_alloc_from_contiguous(&vc_cma_device.dev,
-+ PAGES_PER_CHUNK,
-+ VC_CMA_CHUNK_ORDER);
-+ if (!chunk)
-+ break;
-+ BUG_ON(((page_to_phys(chunk) - vc_cma_base) %
-+ VC_CMA_CHUNK_SIZE) != 0);
-+ }
-+ if (vc_cma_chunks_used != chunks_needed) {
-+ LOG_ERR("%s: dma_alloc_from_contiguous failed (%d "
-+ "bytes, allocation %d of %d)",
-+ __func__, VC_CMA_CHUNK_SIZE,
-+ vc_cma_chunks_used, chunks_needed);
-+ goto out_release;
-+ }
-+
-+ vchiq_add_connected_callback(vc_cma_connected_init);
-+ }
-+
-+ rc = alloc_chrdev_region(&vc_cma_devnum, 0, 1, DRIVER_NAME);
-+ if (rc < 0) {
-+ LOG_ERR("%s: alloc_chrdev_region failed (rc=%d)", __func__, rc);
-+ goto out_release;
-+ }
-+
-+ cdev_init(&vc_cma_cdev, &vc_cma_fops);
-+ rc = cdev_add(&vc_cma_cdev, vc_cma_devnum, 1);
-+ if (rc != 0) {
-+ LOG_ERR("%s: cdev_add failed (rc=%d)", __func__, rc);
-+ goto out_unregister;
-+ }
-+
-+ vc_cma_class = class_create(THIS_MODULE, DRIVER_NAME);
-+ if (IS_ERR(vc_cma_class)) {
-+ rc = PTR_ERR(vc_cma_class);
-+ LOG_ERR("%s: class_create failed (rc=%d)", __func__, rc);
-+ goto out_cdev_del;
-+ }
-+
-+ dev = device_create(vc_cma_class, NULL, vc_cma_devnum, NULL,
-+ DRIVER_NAME);
-+ if (IS_ERR(dev)) {
-+ rc = PTR_ERR(dev);
-+ LOG_ERR("%s: device_create failed (rc=%d)", __func__, rc);
-+ goto out_class_destroy;
-+ }
-+
-+ vc_cma_proc_entry = proc_create(DRIVER_NAME, 0444, NULL, &vc_cma_proc_fops);
-+ if (vc_cma_proc_entry == NULL) {
-+ rc = -EFAULT;
-+ LOG_ERR("%s: proc_create failed", __func__);
-+ goto out_device_destroy;
-+ }
-+
-+ vc_cma_inited = 1;
-+ return 0;
-+
-+out_device_destroy:
-+ device_destroy(vc_cma_class, vc_cma_devnum);
-+
-+out_class_destroy:
-+ class_destroy(vc_cma_class);
-+ vc_cma_class = NULL;
-+
-+out_cdev_del:
-+ cdev_del(&vc_cma_cdev);
-+
-+out_unregister:
-+ unregister_chrdev_region(vc_cma_devnum, 1);
-+
-+out_release:
-+ /* It is tempting to try to clean up by calling
-+ dma_release_from_contiguous for all allocated chunks, but it isn't
-+ a very safe thing to do. If vc_cma_initial is non-zero it is because
-+ VideoCore is already using that memory, so giving it back to Linux
-+ is likely to be fatal.
-+ */
-+ return -1;
-+}
-+
-+/****************************************************************************
-+*
-+* vc_cma_exit
-+*
-+***************************************************************************/
-+
-+static void __exit vc_cma_exit(void)
-+{
-+ LOG_DBG("%s: called", __func__);
-+
-+ if (vc_cma_inited) {
-+ remove_proc_entry(DRIVER_NAME, NULL);
-+ device_destroy(vc_cma_class, vc_cma_devnum);
-+ class_destroy(vc_cma_class);
-+ cdev_del(&vc_cma_cdev);
-+ unregister_chrdev_region(vc_cma_devnum, 1);
-+ }
-+}
-+
-+module_init(vc_cma_init);
-+module_exit(vc_cma_exit);
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Broadcom Corporation");
---- /dev/null
-+++ b/include/linux/broadcom/vc_cma.h
-@@ -0,0 +1,36 @@
-+/*****************************************************************************
-+* Copyright 2012 Broadcom Corporation. All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*****************************************************************************/
-+
-+#if !defined( VC_CMA_H )
-+#define VC_CMA_H
-+
-+#include <linux/ioctl.h>
-+
-+#define VC_CMA_IOC_MAGIC 0xc5
-+
-+#define VC_CMA_IOC_RESERVE _IO(VC_CMA_IOC_MAGIC, 0)
-+
-+#ifdef __KERNEL__
-+
-+#ifdef CONFIG_BCM_VC_CMA
-+void vc_cma_early_init(void);
-+void vc_cma_reserve(void);
-+#else
-+static inline void vc_cma_early_init(void) { }
-+static inline void vc_cma_reserve(void) { }
-+#endif
-+
-+#endif
-+
-+#endif /* VC_CMA_H */
diff --git a/target/linux/brcm2708/patches-4.4/0036-bcm2708-alsa-sound-driver.patch b/target/linux/brcm2708/patches-4.4/0036-bcm2708-alsa-sound-driver.patch
deleted file mode 100644
index 936c929e24..0000000000
--- a/target/linux/brcm2708/patches-4.4/0036-bcm2708-alsa-sound-driver.patch
+++ /dev/null
@@ -1,2678 +0,0 @@
-From 1e8eb30b259278ea7ab9d14c66d2fab5f580f73c Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Mon, 26 Mar 2012 22:15:50 +0100
-Subject: [PATCH 036/170] bcm2708: alsa sound driver
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: popcornmix <popcornmix@gmail.com>
-
-alsa: add mmap support and some cleanups to bcm2835 ALSA driver
-
-snd-bcm2835: Add support for spdif/hdmi passthrough
-
-This adds a dedicated subdevice which can be used for passthrough of non-audio
-formats (ie encoded a52) through the hdmi audio link. In addition to this
-driver extension an appropriate card config is required to make alsa-lib
-support the AES parameters for this device.
-
-snd-bcm2708: Add mutex, improve logging
-
-Fix for ALSA driver crash
-
-Avoids an issue when closing and opening vchiq where a message can arrive before service handle has been written
-
-alsa: reduce severity of expected warning message
-
-snd-bcm2708: Fix dmesg spam for non-error case
-
-alsa: Ensure mutexes are released through error paths
-
-alsa: Make interrupted close paths quieter
-
-BCM270x: Add onboard sound device to Device Tree
-
-Add Device Tree support to alsa driver.
-Add device to Device Tree.
-Don't add platform devices when booting in DT mode.
-
-Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
----
- sound/arm/Kconfig | 8 +
- sound/arm/Makefile | 5 +
- sound/arm/bcm2835-ctl.c | 323 +++++++++++++
- sound/arm/bcm2835-pcm.c | 557 +++++++++++++++++++++++
- sound/arm/bcm2835-vchiq.c | 902 +++++++++++++++++++++++++++++++++++++
- sound/arm/bcm2835.c | 511 +++++++++++++++++++++
- sound/arm/bcm2835.h | 167 +++++++
- sound/arm/vc_vchi_audioserv_defs.h | 116 +++++
- 8 files changed, 2589 insertions(+)
- create mode 100755 sound/arm/bcm2835-ctl.c
- create mode 100755 sound/arm/bcm2835-pcm.c
- create mode 100755 sound/arm/bcm2835-vchiq.c
- create mode 100644 sound/arm/bcm2835.c
- create mode 100755 sound/arm/bcm2835.h
- create mode 100644 sound/arm/vc_vchi_audioserv_defs.h
-
---- a/sound/arm/Kconfig
-+++ b/sound/arm/Kconfig
-@@ -40,5 +40,13 @@ config SND_PXA2XX_AC97
- Say Y or M if you want to support any AC97 codec attached to
- the PXA2xx AC97 interface.
-
-+config SND_BCM2835
-+ tristate "BCM2835 ALSA driver"
-+ depends on (ARCH_BCM2708 || ARCH_BCM2709 || ARCH_BCM2835) \
-+ && BCM2708_VCHIQ && SND
-+ select SND_PCM
-+ help
-+ Say Y or M if you want to support BCM2835 Alsa pcm card driver
-+
- endif # SND_ARM
-
---- a/sound/arm/Makefile
-+++ b/sound/arm/Makefile
-@@ -14,3 +14,8 @@ snd-pxa2xx-lib-$(CONFIG_SND_PXA2XX_LIB_A
-
- obj-$(CONFIG_SND_PXA2XX_AC97) += snd-pxa2xx-ac97.o
- snd-pxa2xx-ac97-objs := pxa2xx-ac97.o
-+
-+obj-$(CONFIG_SND_BCM2835) += snd-bcm2835.o
-+snd-bcm2835-objs := bcm2835.o bcm2835-ctl.o bcm2835-pcm.o bcm2835-vchiq.o
-+
-+ccflags-y += -Idrivers/misc/vc04_services -Idrivers/misc/vc04_services/interface/vcos/linuxkernel -D__VCCOREVER__=0x04000000
---- /dev/null
-+++ b/sound/arm/bcm2835-ctl.c
-@@ -0,0 +1,323 @@
-+/*****************************************************************************
-+* Copyright 2011 Broadcom Corporation. All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*****************************************************************************/
-+
-+#include <linux/platform_device.h>
-+#include <linux/init.h>
-+#include <linux/io.h>
-+#include <linux/jiffies.h>
-+#include <linux/slab.h>
-+#include <linux/time.h>
-+#include <linux/wait.h>
-+#include <linux/delay.h>
-+#include <linux/moduleparam.h>
-+#include <linux/sched.h>
-+
-+#include <sound/core.h>
-+#include <sound/control.h>
-+#include <sound/pcm.h>
-+#include <sound/pcm_params.h>
-+#include <sound/rawmidi.h>
-+#include <sound/initval.h>
-+#include <sound/tlv.h>
-+#include <sound/asoundef.h>
-+
-+#include "bcm2835.h"
-+
-+/* volume maximum and minimum in terms of 0.01dB */
-+#define CTRL_VOL_MAX 400
-+#define CTRL_VOL_MIN -10239 /* originally -10240 */
-+
-+
-+static int snd_bcm2835_ctl_info(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_info *uinfo)
-+{
-+ audio_info(" ... IN\n");
-+ if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
-+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-+ uinfo->count = 1;
-+ uinfo->value.integer.min = CTRL_VOL_MIN;
-+ uinfo->value.integer.max = CTRL_VOL_MAX; /* 2303 */
-+ } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
-+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-+ uinfo->count = 1;
-+ uinfo->value.integer.min = 0;
-+ uinfo->value.integer.max = 1;
-+ } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
-+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-+ uinfo->count = 1;
-+ uinfo->value.integer.min = 0;
-+ uinfo->value.integer.max = AUDIO_DEST_MAX-1;
-+ }
-+ audio_info(" ... OUT\n");
-+ return 0;
-+}
-+
-+/* toggles mute on or off depending on the value of nmute, and returns
-+ * 1 if the mute value was changed, otherwise 0
-+ */
-+static int toggle_mute(struct bcm2835_chip *chip, int nmute)
-+{
-+ /* if settings are ok, just return 0 */
-+ if(chip->mute == nmute)
-+ return 0;
-+
-+ /* if the sound is muted then we need to unmute */
-+ if(chip->mute == CTRL_VOL_MUTE)
-+ {
-+ chip->volume = chip->old_volume; /* copy the old volume back */
-+ audio_info("Unmuting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
-+ }
-+ else /* otherwise we mute */
-+ {
-+ chip->old_volume = chip->volume;
-+ chip->volume = 26214; /* set volume to minimum level AKA mute */
-+ audio_info("Muting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
-+ }
-+
-+ chip->mute = nmute;
-+ return 1;
-+}
-+
-+static int snd_bcm2835_ctl_get(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_value *ucontrol)
-+{
-+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
-+
-+ BUG_ON(!chip && !(chip->avail_substreams & AVAIL_SUBSTREAMS_MASK));
-+
-+ if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
-+ ucontrol->value.integer.value[0] = chip2alsa(chip->volume);
-+ else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
-+ ucontrol->value.integer.value[0] = chip->mute;
-+ else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
-+ ucontrol->value.integer.value[0] = chip->dest;
-+
-+ return 0;
-+}
-+
-+static int snd_bcm2835_ctl_put(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_value *ucontrol)
-+{
-+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
-+ int changed = 0;
-+
-+ if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
-+ audio_info("Volume change attempted.. volume = %d new_volume = %d\n", chip->volume, (int)ucontrol->value.integer.value[0]);
-+ if (chip->mute == CTRL_VOL_MUTE) {
-+ /* changed = toggle_mute(chip, CTRL_VOL_UNMUTE); */
-+ return 1; /* should return 0 to signify no change but the mixer takes this as the opposite sign (no idea why) */
-+ }
-+ if (changed
-+ || (ucontrol->value.integer.value[0] != chip2alsa(chip->volume))) {
-+
-+ chip->volume = alsa2chip(ucontrol->value.integer.value[0]);
-+ changed = 1;
-+ }
-+
-+ } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
-+ /* Now implemented */
-+ audio_info(" Mute attempted\n");
-+ changed = toggle_mute(chip, ucontrol->value.integer.value[0]);
-+
-+ } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
-+ if (ucontrol->value.integer.value[0] != chip->dest) {
-+ chip->dest = ucontrol->value.integer.value[0];
-+ changed = 1;
-+ }
-+ }
-+
-+ if (changed) {
-+ if (bcm2835_audio_set_ctls(chip))
-+ printk(KERN_ERR "Failed to set ALSA controls..\n");
-+ }
-+
-+ return changed;
-+}
-+
-+static DECLARE_TLV_DB_SCALE(snd_bcm2835_db_scale, CTRL_VOL_MIN, 1, 1);
-+
-+static struct snd_kcontrol_new snd_bcm2835_ctl[] = {
-+ {
-+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-+ .name = "PCM Playback Volume",
-+ .index = 0,
-+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
-+ .private_value = PCM_PLAYBACK_VOLUME,
-+ .info = snd_bcm2835_ctl_info,
-+ .get = snd_bcm2835_ctl_get,
-+ .put = snd_bcm2835_ctl_put,
-+ .count = 1,
-+ .tlv = {.p = snd_bcm2835_db_scale}
-+ },
-+ {
-+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-+ .name = "PCM Playback Switch",
-+ .index = 0,
-+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
-+ .private_value = PCM_PLAYBACK_MUTE,
-+ .info = snd_bcm2835_ctl_info,
-+ .get = snd_bcm2835_ctl_get,
-+ .put = snd_bcm2835_ctl_put,
-+ .count = 1,
-+ },
-+ {
-+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-+ .name = "PCM Playback Route",
-+ .index = 0,
-+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
-+ .private_value = PCM_PLAYBACK_DEVICE,
-+ .info = snd_bcm2835_ctl_info,
-+ .get = snd_bcm2835_ctl_get,
-+ .put = snd_bcm2835_ctl_put,
-+ .count = 1,
-+ },
-+};
-+
-+static int snd_bcm2835_spdif_default_info(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_info *uinfo)
-+{
-+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
-+ uinfo->count = 1;
-+ return 0;
-+}
-+
-+static int snd_bcm2835_spdif_default_get(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_value *ucontrol)
-+{
-+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
-+ int i;
-+
-+ for (i = 0; i < 4; i++)
-+ ucontrol->value.iec958.status[i] =
-+ (chip->spdif_status >> (i * 8)) && 0xff;
-+
-+ return 0;
-+}
-+
-+static int snd_bcm2835_spdif_default_put(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_value *ucontrol)
-+{
-+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
-+ unsigned int val = 0;
-+ int i, change;
-+
-+ for (i = 0; i < 4; i++)
-+ val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
-+
-+ change = val != chip->spdif_status;
-+ chip->spdif_status = val;
-+
-+ return change;
-+}
-+
-+static int snd_bcm2835_spdif_mask_info(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_info *uinfo)
-+{
-+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
-+ uinfo->count = 1;
-+ return 0;
-+}
-+
-+static int snd_bcm2835_spdif_mask_get(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_value *ucontrol)
-+{
-+ /* bcm2835 supports only consumer mode and sets all other format flags
-+ * automatically. So the only thing left is signalling non-audio
-+ * content */
-+ ucontrol->value.iec958.status[0] = IEC958_AES0_NONAUDIO;
-+ return 0;
-+}
-+
-+static int snd_bcm2835_spdif_stream_info(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_info *uinfo)
-+{
-+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
-+ uinfo->count = 1;
-+ return 0;
-+}
-+
-+static int snd_bcm2835_spdif_stream_get(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_value *ucontrol)
-+{
-+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
-+ int i;
-+
-+ for (i = 0; i < 4; i++)
-+ ucontrol->value.iec958.status[i] =
-+ (chip->spdif_status >> (i * 8)) & 0xff;
-+ return 0;
-+}
-+
-+static int snd_bcm2835_spdif_stream_put(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_value *ucontrol)
-+{
-+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
-+ unsigned int val = 0;
-+ int i, change;
-+
-+ for (i = 0; i < 4; i++)
-+ val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
-+ change = val != chip->spdif_status;
-+ chip->spdif_status = val;
-+
-+ return change;
-+}
-+
-+static struct snd_kcontrol_new snd_bcm2835_spdif[] = {
-+ {
-+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
-+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
-+ .info = snd_bcm2835_spdif_default_info,
-+ .get = snd_bcm2835_spdif_default_get,
-+ .put = snd_bcm2835_spdif_default_put
-+ },
-+ {
-+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
-+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
-+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
-+ .info = snd_bcm2835_spdif_mask_info,
-+ .get = snd_bcm2835_spdif_mask_get,
-+ },
-+ {
-+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
-+ SNDRV_CTL_ELEM_ACCESS_INACTIVE,
-+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
-+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM),
-+ .info = snd_bcm2835_spdif_stream_info,
-+ .get = snd_bcm2835_spdif_stream_get,
-+ .put = snd_bcm2835_spdif_stream_put,
-+ },
-+};
-+
-+int snd_bcm2835_new_ctl(bcm2835_chip_t * chip)
-+{
-+ int err;
-+ unsigned int idx;
-+
-+ strcpy(chip->card->mixername, "Broadcom Mixer");
-+ for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_ctl); idx++) {
-+ err =
-+ snd_ctl_add(chip->card,
-+ snd_ctl_new1(&snd_bcm2835_ctl[idx], chip));
-+ if (err < 0)
-+ return err;
-+ }
-+ for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_spdif); idx++) {
-+ err = snd_ctl_add(chip->card,
-+ snd_ctl_new1(&snd_bcm2835_spdif[idx], chip));
-+ if (err < 0)
-+ return err;
-+ }
-+ return 0;
-+}
---- /dev/null
-+++ b/sound/arm/bcm2835-pcm.c
-@@ -0,0 +1,557 @@
-+/*****************************************************************************
-+* Copyright 2011 Broadcom Corporation. All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*****************************************************************************/
-+
-+#include <linux/interrupt.h>
-+#include <linux/slab.h>
-+
-+#include <sound/asoundef.h>
-+
-+#include "bcm2835.h"
-+
-+/* hardware definition */
-+static struct snd_pcm_hardware snd_bcm2835_playback_hw = {
-+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
-+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
-+ .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
-+ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
-+ .rate_min = 8000,
-+ .rate_max = 48000,
-+ .channels_min = 1,
-+ .channels_max = 2,
-+ .buffer_bytes_max = 128 * 1024,
-+ .period_bytes_min = 1 * 1024,
-+ .period_bytes_max = 128 * 1024,
-+ .periods_min = 1,
-+ .periods_max = 128,
-+};
-+
-+static struct snd_pcm_hardware snd_bcm2835_playback_spdif_hw = {
-+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
-+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
-+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
-+ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_44100 |
-+ SNDRV_PCM_RATE_48000,
-+ .rate_min = 44100,
-+ .rate_max = 48000,
-+ .channels_min = 2,
-+ .channels_max = 2,
-+ .buffer_bytes_max = 128 * 1024,
-+ .period_bytes_min = 1 * 1024,
-+ .period_bytes_max = 128 * 1024,
-+ .periods_min = 1,
-+ .periods_max = 128,
-+};
-+
-+static void snd_bcm2835_playback_free(struct snd_pcm_runtime *runtime)
-+{
-+ audio_info("Freeing up alsa stream here ..\n");
-+ if (runtime->private_data)
-+ kfree(runtime->private_data);
-+ runtime->private_data = NULL;
-+}
-+
-+static irqreturn_t bcm2835_playback_fifo_irq(int irq, void *dev_id)
-+{
-+ bcm2835_alsa_stream_t *alsa_stream = (bcm2835_alsa_stream_t *) dev_id;
-+ uint32_t consumed = 0;
-+ int new_period = 0;
-+
-+ audio_info(" .. IN\n");
-+
-+ audio_info("alsa_stream=%p substream=%p\n", alsa_stream,
-+ alsa_stream ? alsa_stream->substream : 0);
-+
-+ if (alsa_stream->open)
-+ consumed = bcm2835_audio_retrieve_buffers(alsa_stream);
-+
-+ /* We get called only if playback was triggered, So, the number of buffers we retrieve in
-+ * each iteration are the buffers that have been played out already
-+ */
-+
-+ if (alsa_stream->period_size) {
-+ if ((alsa_stream->pos / alsa_stream->period_size) !=
-+ ((alsa_stream->pos + consumed) / alsa_stream->period_size))
-+ new_period = 1;
-+ }
-+ audio_debug("updating pos cur: %d + %d max:%d period_bytes:%d, hw_ptr: %d new_period:%d\n",
-+ alsa_stream->pos,
-+ consumed,
-+ alsa_stream->buffer_size,
-+ (int)(alsa_stream->period_size*alsa_stream->substream->runtime->periods),
-+ frames_to_bytes(alsa_stream->substream->runtime, alsa_stream->substream->runtime->status->hw_ptr),
-+ new_period);
-+ if (alsa_stream->buffer_size) {
-+ alsa_stream->pos += consumed &~ (1<<30);
-+ alsa_stream->pos %= alsa_stream->buffer_size;
-+ }
-+
-+ if (alsa_stream->substream) {
-+ if (new_period)
-+ snd_pcm_period_elapsed(alsa_stream->substream);
-+ } else {
-+ audio_warning(" unexpected NULL substream\n");
-+ }
-+ audio_info(" .. OUT\n");
-+
-+ return IRQ_HANDLED;
-+}
-+
-+/* open callback */
-+static int snd_bcm2835_playback_open_generic(
-+ struct snd_pcm_substream *substream, int spdif)
-+{
-+ bcm2835_chip_t *chip = snd_pcm_substream_chip(substream);
-+ struct snd_pcm_runtime *runtime = substream->runtime;
-+ bcm2835_alsa_stream_t *alsa_stream;
-+ int idx;
-+ int err;
-+
-+ audio_info(" .. IN (%d)\n", substream->number);
-+
-+ if(mutex_lock_interruptible(&chip->audio_mutex))
-+ {
-+ audio_error("Interrupted whilst waiting for lock\n");
-+ return -EINTR;
-+ }
-+ audio_info("Alsa open (%d)\n", substream->number);
-+ idx = substream->number;
-+
-+ if (spdif && chip->opened != 0) {
-+ err = -EBUSY;
-+ goto out;
-+ }
-+ else if (!spdif && (chip->opened & (1 << idx))) {
-+ err = -EBUSY;
-+ goto out;
-+ }
-+ if (idx > MAX_SUBSTREAMS) {
-+ audio_error
-+ ("substream(%d) device doesn't exist max(%d) substreams allowed\n",
-+ idx, MAX_SUBSTREAMS);
-+ err = -ENODEV;
-+ goto out;
-+ }
-+
-+ /* Check if we are ready */
-+ if (!(chip->avail_substreams & (1 << idx))) {
-+ /* We are not ready yet */
-+ audio_error("substream(%d) device is not ready yet\n", idx);
-+ err = -EAGAIN;
-+ goto out;
-+ }
-+
-+ alsa_stream = kzalloc(sizeof(bcm2835_alsa_stream_t), GFP_KERNEL);
-+ if (alsa_stream == NULL) {
-+ err = -ENOMEM;
-+ goto out;
-+ }
-+
-+ /* Initialise alsa_stream */
-+ alsa_stream->chip = chip;
-+ alsa_stream->substream = substream;
-+ alsa_stream->idx = idx;
-+
-+ sema_init(&alsa_stream->buffers_update_sem, 0);
-+ sema_init(&alsa_stream->control_sem, 0);
-+ spin_lock_init(&alsa_stream->lock);
-+
-+ /* Enabled in start trigger, called on each "fifo irq" after that */
-+ alsa_stream->enable_fifo_irq = 0;
-+ alsa_stream->fifo_irq_handler = bcm2835_playback_fifo_irq;
-+
-+ err = bcm2835_audio_open(alsa_stream);
-+ if (err != 0) {
-+ kfree(alsa_stream);
-+ goto out;
-+ }
-+ runtime->private_data = alsa_stream;
-+ runtime->private_free = snd_bcm2835_playback_free;
-+ if (spdif) {
-+ runtime->hw = snd_bcm2835_playback_spdif_hw;
-+ } else {
-+ /* clear spdif status, as we are not in spdif mode */
-+ chip->spdif_status = 0;
-+ runtime->hw = snd_bcm2835_playback_hw;
-+ }
-+ /* minimum 16 bytes alignment (for vchiq bulk transfers) */
-+ snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
-+ 16);
-+
-+ chip->alsa_stream[idx] = alsa_stream;
-+
-+ chip->opened |= (1 << idx);
-+ alsa_stream->open = 1;
-+ alsa_stream->draining = 1;
-+
-+out:
-+ mutex_unlock(&chip->audio_mutex);
-+
-+ audio_info(" .. OUT =%d\n", err);
-+
-+ return err;
-+}
-+
-+static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream)
-+{
-+ return snd_bcm2835_playback_open_generic(substream, 0);
-+}
-+
-+static int snd_bcm2835_playback_spdif_open(struct snd_pcm_substream *substream)
-+{
-+ return snd_bcm2835_playback_open_generic(substream, 1);
-+}
-+
-+/* close callback */
-+static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream)
-+{
-+ /* the hardware-specific codes will be here */
-+
-+ bcm2835_chip_t *chip;
-+ struct snd_pcm_runtime *runtime;
-+ bcm2835_alsa_stream_t *alsa_stream;
-+
-+ audio_info(" .. IN\n");
-+
-+ chip = snd_pcm_substream_chip(substream);
-+ if(mutex_lock_interruptible(&chip->audio_mutex))
-+ {
-+ audio_error("Interrupted whilst waiting for lock\n");
-+ return -EINTR;
-+ }
-+ runtime = substream->runtime;
-+ alsa_stream = runtime->private_data;
-+
-+ audio_info("Alsa close\n");
-+
-+ /*
-+ * Call stop if it's still running. This happens when app
-+ * is force killed and we don't get a stop trigger.
-+ */
-+ if (alsa_stream->running) {
-+ int err;
-+ err = bcm2835_audio_stop(alsa_stream);
-+ alsa_stream->running = 0;
-+ if (err != 0)
-+ audio_error(" Failed to STOP alsa device\n");
-+ }
-+
-+ alsa_stream->period_size = 0;
-+ alsa_stream->buffer_size = 0;
-+
-+ if (alsa_stream->open) {
-+ alsa_stream->open = 0;
-+ bcm2835_audio_close(alsa_stream);
-+ }
-+ if (alsa_stream->chip)
-+ alsa_stream->chip->alsa_stream[alsa_stream->idx] = NULL;
-+ /*
-+ * Do not free up alsa_stream here, it will be freed up by
-+ * runtime->private_free callback we registered in *_open above
-+ */
-+
-+ chip->opened &= ~(1 << substream->number);
-+
-+ mutex_unlock(&chip->audio_mutex);
-+ audio_info(" .. OUT\n");
-+
-+ return 0;
-+}
-+
-+/* hw_params callback */
-+static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream,
-+ struct snd_pcm_hw_params *params)
-+{
-+ struct snd_pcm_runtime *runtime = substream->runtime;
-+ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
-+ int err;
-+
-+ audio_info(" .. IN\n");
-+
-+ err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
-+ if (err < 0) {
-+ audio_error
-+ (" pcm_lib_malloc failed to allocated pages for buffers\n");
-+ return err;
-+ }
-+
-+ alsa_stream->channels = params_channels(params);
-+ alsa_stream->params_rate = params_rate(params);
-+ alsa_stream->pcm_format_width = snd_pcm_format_width(params_format (params));
-+ audio_info(" .. OUT\n");
-+
-+ return err;
-+}
-+
-+/* hw_free callback */
-+static int snd_bcm2835_pcm_hw_free(struct snd_pcm_substream *substream)
-+{
-+ audio_info(" .. IN\n");
-+ return snd_pcm_lib_free_pages(substream);
-+}
-+
-+/* prepare callback */
-+static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
-+{
-+ bcm2835_chip_t *chip = snd_pcm_substream_chip(substream);
-+ struct snd_pcm_runtime *runtime = substream->runtime;
-+ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
-+ int channels;
-+ int err;
-+
-+ audio_info(" .. IN\n");
-+
-+ /* notify the vchiq that it should enter spdif passthrough mode by
-+ * setting channels=0 (see
-+ * https://github.com/raspberrypi/linux/issues/528) */
-+ if (chip->spdif_status & IEC958_AES0_NONAUDIO)
-+ channels = 0;
-+ else
-+ channels = alsa_stream->channels;
-+
-+ err = bcm2835_audio_set_params(alsa_stream, channels,
-+ alsa_stream->params_rate,
-+ alsa_stream->pcm_format_width);
-+ if (err < 0) {
-+ audio_error(" error setting hw params\n");
-+ }
-+
-+ bcm2835_audio_setup(alsa_stream);
-+
-+ /* in preparation of the stream, set the controls (volume level) of the stream */
-+ bcm2835_audio_set_ctls(alsa_stream->chip);
-+
-+
-+ memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
-+
-+ alsa_stream->pcm_indirect.hw_buffer_size =
-+ alsa_stream->pcm_indirect.sw_buffer_size =
-+ snd_pcm_lib_buffer_bytes(substream);
-+
-+ alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
-+ alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
-+ alsa_stream->pos = 0;
-+
-+ audio_debug("buffer_size=%d, period_size=%d pos=%d frame_bits=%d\n",
-+ alsa_stream->buffer_size, alsa_stream->period_size,
-+ alsa_stream->pos, runtime->frame_bits);
-+
-+ audio_info(" .. OUT\n");
-+ return 0;
-+}
-+
-+static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream,
-+ struct snd_pcm_indirect *rec, size_t bytes)
-+{
-+ struct snd_pcm_runtime *runtime = substream->runtime;
-+ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
-+ void *src = (void *)(substream->runtime->dma_area + rec->sw_data);
-+ int err;
-+
-+ err = bcm2835_audio_write(alsa_stream, bytes, src);
-+ if (err)
-+ audio_error(" Failed to transfer to alsa device (%d)\n", err);
-+
-+}
-+
-+static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream)
-+{
-+ struct snd_pcm_runtime *runtime = substream->runtime;
-+ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
-+ struct snd_pcm_indirect *pcm_indirect = &alsa_stream->pcm_indirect;
-+
-+ pcm_indirect->hw_queue_size = runtime->hw.buffer_bytes_max;
-+ snd_pcm_indirect_playback_transfer(substream, pcm_indirect,
-+ snd_bcm2835_pcm_transfer);
-+ return 0;
-+}
-+
-+/* trigger callback */
-+static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-+{
-+ struct snd_pcm_runtime *runtime = substream->runtime;
-+ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
-+ int err = 0;
-+
-+ audio_info(" .. IN\n");
-+
-+ switch (cmd) {
-+ case SNDRV_PCM_TRIGGER_START:
-+ audio_debug("bcm2835_AUDIO_TRIGGER_START running=%d\n",
-+ alsa_stream->running);
-+ if (!alsa_stream->running) {
-+ err = bcm2835_audio_start(alsa_stream);
-+ if (err == 0) {
-+ alsa_stream->pcm_indirect.hw_io =
-+ alsa_stream->pcm_indirect.hw_data =
-+ bytes_to_frames(runtime,
-+ alsa_stream->pos);
-+ substream->ops->ack(substream);
-+ alsa_stream->running = 1;
-+ alsa_stream->draining = 1;
-+ } else {
-+ audio_error(" Failed to START alsa device (%d)\n", err);
-+ }
-+ }
-+ break;
-+ case SNDRV_PCM_TRIGGER_STOP:
-+ audio_debug
-+ ("bcm2835_AUDIO_TRIGGER_STOP running=%d draining=%d\n",
-+ alsa_stream->running, runtime->status->state == SNDRV_PCM_STATE_DRAINING);
-+ if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
-+ audio_info("DRAINING\n");
-+ alsa_stream->draining = 1;
-+ } else {
-+ audio_info("DROPPING\n");
-+ alsa_stream->draining = 0;
-+ }
-+ if (alsa_stream->running) {
-+ err = bcm2835_audio_stop(alsa_stream);
-+ if (err != 0)
-+ audio_error(" Failed to STOP alsa device (%d)\n", err);
-+ alsa_stream->running = 0;
-+ }
-+ break;
-+ default:
-+ err = -EINVAL;
-+ }
-+
-+ audio_info(" .. OUT\n");
-+ return err;
-+}
-+
-+/* pointer callback */
-+static snd_pcm_uframes_t
-+snd_bcm2835_pcm_pointer(struct snd_pcm_substream *substream)
-+{
-+ struct snd_pcm_runtime *runtime = substream->runtime;
-+ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
-+
-+ audio_info(" .. IN\n");
-+
-+ audio_debug("pcm_pointer... (%d) hwptr=%d appl=%d pos=%d\n", 0,
-+ frames_to_bytes(runtime, runtime->status->hw_ptr),
-+ frames_to_bytes(runtime, runtime->control->appl_ptr),
-+ alsa_stream->pos);
-+
-+ audio_info(" .. OUT\n");
-+ return snd_pcm_indirect_playback_pointer(substream,
-+ &alsa_stream->pcm_indirect,
-+ alsa_stream->pos);
-+}
-+
-+static int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream,
-+ unsigned int cmd, void *arg)
-+{
-+ int ret = snd_pcm_lib_ioctl(substream, cmd, arg);
-+ audio_info(" .. substream=%p, cmd=%d, arg=%p (%x) ret=%d\n", substream,
-+ cmd, arg, arg ? *(unsigned *)arg : 0, ret);
-+ return ret;
-+}
-+
-+/* operators */
-+static struct snd_pcm_ops snd_bcm2835_playback_ops = {
-+ .open = snd_bcm2835_playback_open,
-+ .close = snd_bcm2835_playback_close,
-+ .ioctl = snd_bcm2835_pcm_lib_ioctl,
-+ .hw_params = snd_bcm2835_pcm_hw_params,
-+ .hw_free = snd_bcm2835_pcm_hw_free,
-+ .prepare = snd_bcm2835_pcm_prepare,
-+ .trigger = snd_bcm2835_pcm_trigger,
-+ .pointer = snd_bcm2835_pcm_pointer,
-+ .ack = snd_bcm2835_pcm_ack,
-+};
-+
-+static struct snd_pcm_ops snd_bcm2835_playback_spdif_ops = {
-+ .open = snd_bcm2835_playback_spdif_open,
-+ .close = snd_bcm2835_playback_close,
-+ .ioctl = snd_bcm2835_pcm_lib_ioctl,
-+ .hw_params = snd_bcm2835_pcm_hw_params,
-+ .hw_free = snd_bcm2835_pcm_hw_free,
-+ .prepare = snd_bcm2835_pcm_prepare,
-+ .trigger = snd_bcm2835_pcm_trigger,
-+ .pointer = snd_bcm2835_pcm_pointer,
-+ .ack = snd_bcm2835_pcm_ack,
-+};
-+
-+/* create a pcm device */
-+int snd_bcm2835_new_pcm(bcm2835_chip_t * chip)
-+{
-+ struct snd_pcm *pcm;
-+ int err;
-+
-+ audio_info(" .. IN\n");
-+ mutex_init(&chip->audio_mutex);
-+ if(mutex_lock_interruptible(&chip->audio_mutex))
-+ {
-+ audio_error("Interrupted whilst waiting for lock\n");
-+ return -EINTR;
-+ }
-+ err =
-+ snd_pcm_new(chip->card, "bcm2835 ALSA", 0, MAX_SUBSTREAMS, 0, &pcm);
-+ if (err < 0)
-+ goto out;
-+ pcm->private_data = chip;
-+ strcpy(pcm->name, "bcm2835 ALSA");
-+ chip->pcm = pcm;
-+ chip->dest = AUDIO_DEST_AUTO;
-+ chip->volume = alsa2chip(0);
-+ chip->mute = CTRL_VOL_UNMUTE; /*disable mute on startup */
-+ /* set operators */
-+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
-+ &snd_bcm2835_playback_ops);
-+
-+ /* pre-allocation of buffers */
-+ /* NOTE: this may fail */
-+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
-+ snd_dma_continuous_data
-+ (GFP_KERNEL), 64 * 1024,
-+ 64 * 1024);
-+
-+out:
-+ mutex_unlock(&chip->audio_mutex);
-+ audio_info(" .. OUT\n");
-+
-+ return 0;
-+}
-+
-+int snd_bcm2835_new_spdif_pcm(bcm2835_chip_t * chip)
-+{
-+ struct snd_pcm *pcm;
-+ int err;
-+
-+ audio_info(" .. IN\n");
-+ if(mutex_lock_interruptible(&chip->audio_mutex))
-+ {
-+ audio_error("Interrupted whilst waiting for lock\n");
-+ return -EINTR;
-+ }
-+ err = snd_pcm_new(chip->card, "bcm2835 ALSA", 1, 1, 0, &pcm);
-+ if (err < 0)
-+ goto out;
-+
-+ pcm->private_data = chip;
-+ strcpy(pcm->name, "bcm2835 IEC958/HDMI");
-+ chip->pcm_spdif = pcm;
-+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
-+ &snd_bcm2835_playback_spdif_ops);
-+
-+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
-+ snd_dma_continuous_data (GFP_KERNEL),
-+ 64 * 1024, 64 * 1024);
-+out:
-+ mutex_unlock(&chip->audio_mutex);
-+ audio_info(" .. OUT\n");
-+
-+ return 0;
-+}
---- /dev/null
-+++ b/sound/arm/bcm2835-vchiq.c
-@@ -0,0 +1,902 @@
-+/*****************************************************************************
-+* Copyright 2011 Broadcom Corporation. All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*****************************************************************************/
-+
-+#include <linux/device.h>
-+#include <sound/core.h>
-+#include <sound/initval.h>
-+#include <sound/pcm.h>
-+#include <linux/io.h>
-+#include <linux/interrupt.h>
-+#include <linux/fs.h>
-+#include <linux/file.h>
-+#include <linux/mm.h>
-+#include <linux/syscalls.h>
-+#include <asm/uaccess.h>
-+#include <linux/slab.h>
-+#include <linux/delay.h>
-+#include <linux/atomic.h>
-+#include <linux/module.h>
-+#include <linux/completion.h>
-+
-+#include "bcm2835.h"
-+
-+/* ---- Include Files -------------------------------------------------------- */
-+
-+#include "interface/vchi/vchi.h"
-+#include "vc_vchi_audioserv_defs.h"
-+
-+/* ---- Private Constants and Types ------------------------------------------ */
-+
-+#define BCM2835_AUDIO_STOP 0
-+#define BCM2835_AUDIO_START 1
-+#define BCM2835_AUDIO_WRITE 2
-+
-+/* Logging macros (for remapping to other logging mechanisms, i.e., printf) */
-+#ifdef AUDIO_DEBUG_ENABLE
-+ #define LOG_ERR( fmt, arg... ) pr_err( "%s:%d " fmt, __func__, __LINE__, ##arg)
-+ #define LOG_WARN( fmt, arg... ) pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg)
-+ #define LOG_INFO( fmt, arg... ) pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg)
-+ #define LOG_DBG( fmt, arg... ) pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg)
-+#else
-+ #define LOG_ERR( fmt, arg... ) pr_err( "%s:%d " fmt, __func__, __LINE__, ##arg)
-+ #define LOG_WARN( fmt, arg... )
-+ #define LOG_INFO( fmt, arg... )
-+ #define LOG_DBG( fmt, arg... )
-+#endif
-+
-+typedef struct opaque_AUDIO_INSTANCE_T {
-+ uint32_t num_connections;
-+ VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS];
-+ struct completion msg_avail_comp;
-+ struct mutex vchi_mutex;
-+ bcm2835_alsa_stream_t *alsa_stream;
-+ int32_t result;
-+ short peer_version;
-+} AUDIO_INSTANCE_T;
-+
-+bool force_bulk = false;
-+
-+/* ---- Private Variables ---------------------------------------------------- */
-+
-+/* ---- Private Function Prototypes ------------------------------------------ */
-+
-+/* ---- Private Functions ---------------------------------------------------- */
-+
-+static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream);
-+static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream);
-+static int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream,
-+ uint32_t count, void *src);
-+
-+typedef struct {
-+ struct work_struct my_work;
-+ bcm2835_alsa_stream_t *alsa_stream;
-+ int cmd;
-+ void *src;
-+ uint32_t count;
-+} my_work_t;
-+
-+static void my_wq_function(struct work_struct *work)
-+{
-+ my_work_t *w = (my_work_t *) work;
-+ int ret = -9;
-+ LOG_DBG(" .. IN %p:%d\n", w->alsa_stream, w->cmd);
-+ switch (w->cmd) {
-+ case BCM2835_AUDIO_START:
-+ ret = bcm2835_audio_start_worker(w->alsa_stream);
-+ break;
-+ case BCM2835_AUDIO_STOP:
-+ ret = bcm2835_audio_stop_worker(w->alsa_stream);
-+ break;
-+ case BCM2835_AUDIO_WRITE:
-+ ret = bcm2835_audio_write_worker(w->alsa_stream, w->count,
-+ w->src);
-+ break;
-+ default:
-+ LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->cmd);
-+ break;
-+ }
-+ kfree((void *)work);
-+ LOG_DBG(" .. OUT %d\n", ret);
-+}
-+
-+int bcm2835_audio_start(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+ int ret = -1;
-+ LOG_DBG(" .. IN\n");
-+ if (alsa_stream->my_wq) {
-+ my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
-+ /*--- Queue some work (item 1) ---*/
-+ if (work) {
-+ INIT_WORK((struct work_struct *)work, my_wq_function);
-+ work->alsa_stream = alsa_stream;
-+ work->cmd = BCM2835_AUDIO_START;
-+ if (queue_work
-+ (alsa_stream->my_wq, (struct work_struct *)work))
-+ ret = 0;
-+ } else
-+ LOG_ERR(" .. Error: NULL work kmalloc\n");
-+ }
-+ LOG_DBG(" .. OUT %d\n", ret);
-+ return ret;
-+}
-+
-+int bcm2835_audio_stop(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+ int ret = -1;
-+ LOG_DBG(" .. IN\n");
-+ if (alsa_stream->my_wq) {
-+ my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
-+ /*--- Queue some work (item 1) ---*/
-+ if (work) {
-+ INIT_WORK((struct work_struct *)work, my_wq_function);
-+ work->alsa_stream = alsa_stream;
-+ work->cmd = BCM2835_AUDIO_STOP;
-+ if (queue_work
-+ (alsa_stream->my_wq, (struct work_struct *)work))
-+ ret = 0;
-+ } else
-+ LOG_ERR(" .. Error: NULL work kmalloc\n");
-+ }
-+ LOG_DBG(" .. OUT %d\n", ret);
-+ return ret;
-+}
-+
-+int bcm2835_audio_write(bcm2835_alsa_stream_t *alsa_stream,
-+ uint32_t count, void *src)
-+{
-+ int ret = -1;
-+ LOG_DBG(" .. IN\n");
-+ if (alsa_stream->my_wq) {
-+ my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
-+ /*--- Queue some work (item 1) ---*/
-+ if (work) {
-+ INIT_WORK((struct work_struct *)work, my_wq_function);
-+ work->alsa_stream = alsa_stream;
-+ work->cmd = BCM2835_AUDIO_WRITE;
-+ work->src = src;
-+ work->count = count;
-+ if (queue_work
-+ (alsa_stream->my_wq, (struct work_struct *)work))
-+ ret = 0;
-+ } else
-+ LOG_ERR(" .. Error: NULL work kmalloc\n");
-+ }
-+ LOG_DBG(" .. OUT %d\n", ret);
-+ return ret;
-+}
-+
-+void my_workqueue_init(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+ alsa_stream->my_wq = alloc_workqueue("my_queue", WQ_HIGHPRI, 1);
-+ return;
-+}
-+
-+void my_workqueue_quit(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+ if (alsa_stream->my_wq) {
-+ flush_workqueue(alsa_stream->my_wq);
-+ destroy_workqueue(alsa_stream->my_wq);
-+ alsa_stream->my_wq = NULL;
-+ }
-+ return;
-+}
-+
-+static void audio_vchi_callback(void *param,
-+ const VCHI_CALLBACK_REASON_T reason,
-+ void *msg_handle)
-+{
-+ AUDIO_INSTANCE_T *instance = (AUDIO_INSTANCE_T *) param;
-+ int32_t status;
-+ int32_t msg_len;
-+ VC_AUDIO_MSG_T m;
-+ LOG_DBG(" .. IN instance=%p, handle=%p, alsa=%p, reason=%d, handle=%p\n",
-+ instance, instance ? instance->vchi_handle[0] : NULL, instance ? instance->alsa_stream : NULL, reason, msg_handle);
-+
-+ if (reason != VCHI_CALLBACK_MSG_AVAILABLE) {
-+ return;
-+ }
-+ if (!instance) {
-+ LOG_ERR(" .. instance is null\n");
-+ BUG();
-+ return;
-+ }
-+ if (!instance->vchi_handle[0]) {
-+ LOG_ERR(" .. instance->vchi_handle[0] is null\n");
-+ BUG();
-+ return;
-+ }
-+ status = vchi_msg_dequeue(instance->vchi_handle[0],
-+ &m, sizeof m, &msg_len, VCHI_FLAGS_NONE);
-+ if (m.type == VC_AUDIO_MSG_TYPE_RESULT) {
-+ LOG_DBG
-+ (" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_RESULT, success=%d\n",
-+ instance, m.u.result.success);
-+ instance->result = m.u.result.success;
-+ complete(&instance->msg_avail_comp);
-+ } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
-+ bcm2835_alsa_stream_t *alsa_stream = instance->alsa_stream;
-+ irq_handler_t callback = (irq_handler_t) m.u.complete.callback;
-+ LOG_DBG
-+ (" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_COMPLETE, complete=%d\n",
-+ instance, m.u.complete.count);
-+ if (alsa_stream && callback) {
-+ atomic_add(m.u.complete.count, &alsa_stream->retrieved);
-+ callback(0, alsa_stream);
-+ } else {
-+ LOG_ERR(" .. unexpected alsa_stream=%p, callback=%p\n",
-+ alsa_stream, callback);
-+ }
-+ } else {
-+ LOG_ERR(" .. unexpected m.type=%d\n", m.type);
-+ }
-+ LOG_DBG(" .. OUT\n");
-+}
-+
-+static AUDIO_INSTANCE_T *vc_vchi_audio_init(VCHI_INSTANCE_T vchi_instance,
-+ VCHI_CONNECTION_T **
-+ vchi_connections,
-+ uint32_t num_connections)
-+{
-+ uint32_t i;
-+ AUDIO_INSTANCE_T *instance;
-+ int status;
-+
-+ LOG_DBG("%s: start", __func__);
-+
-+ if (num_connections > VCHI_MAX_NUM_CONNECTIONS) {
-+ LOG_ERR("%s: unsupported number of connections %u (max=%u)\n",
-+ __func__, num_connections, VCHI_MAX_NUM_CONNECTIONS);
-+
-+ return NULL;
-+ }
-+ /* Allocate memory for this instance */
-+ instance = kmalloc(sizeof(*instance), GFP_KERNEL);
-+ if (!instance)
-+ return NULL;
-+
-+ memset(instance, 0, sizeof(*instance));
-+ instance->num_connections = num_connections;
-+
-+ /* Create a lock for exclusive, serialized VCHI connection access */
-+ mutex_init(&instance->vchi_mutex);
-+ /* Open the VCHI service connections */
-+ for (i = 0; i < num_connections; i++) {
-+ SERVICE_CREATION_T params = {
-+ VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER),
-+ VC_AUDIO_SERVER_NAME, // 4cc service code
-+ vchi_connections[i], // passed in fn pointers
-+ 0, // rx fifo size (unused)
-+ 0, // tx fifo size (unused)
-+ audio_vchi_callback, // service callback
-+ instance, // service callback parameter
-+ 1, //TODO: remove VCOS_FALSE, // unaligned bulk recieves
-+ 1, //TODO: remove VCOS_FALSE, // unaligned bulk transmits
-+ 0 // want crc check on bulk transfers
-+ };
-+
-+ LOG_DBG("%s: about to open %i\n", __func__, i);
-+ status = vchi_service_open(vchi_instance, &params,
-+ &instance->vchi_handle[i]);
-+ LOG_DBG("%s: opened %i: %p=%d\n", __func__, i, instance->vchi_handle[i], status);
-+ if (status) {
-+ LOG_ERR
-+ ("%s: failed to open VCHI service connection (status=%d)\n",
-+ __func__, status);
-+
-+ goto err_close_services;
-+ }
-+ /* Finished with the service for now */
-+ vchi_service_release(instance->vchi_handle[i]);
-+ }
-+
-+ LOG_DBG("%s: okay\n", __func__);
-+ return instance;
-+
-+err_close_services:
-+ for (i = 0; i < instance->num_connections; i++) {
-+ LOG_ERR("%s: closing %i: %p\n", __func__, i, instance->vchi_handle[i]);
-+ if (instance->vchi_handle[i])
-+ vchi_service_close(instance->vchi_handle[i]);
-+ }
-+
-+ kfree(instance);
-+ LOG_ERR("%s: error\n", __func__);
-+
-+ return NULL;
-+}
-+
-+static int32_t vc_vchi_audio_deinit(AUDIO_INSTANCE_T * instance)
-+{
-+ uint32_t i;
-+
-+ LOG_DBG(" .. IN\n");
-+
-+ if (instance == NULL) {
-+ LOG_ERR("%s: invalid handle %p\n", __func__, instance);
-+
-+ return -1;
-+ }
-+
-+ LOG_DBG(" .. about to lock (%d)\n", instance->num_connections);
-+ if(mutex_lock_interruptible(&instance->vchi_mutex))
-+ {
-+ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
-+ return -EINTR;
-+ }
-+
-+ /* Close all VCHI service connections */
-+ for (i = 0; i < instance->num_connections; i++) {
-+ int32_t success;
-+ LOG_DBG(" .. %i:closing %p\n", i, instance->vchi_handle[i]);
-+ vchi_service_use(instance->vchi_handle[i]);
-+
-+ success = vchi_service_close(instance->vchi_handle[i]);
-+ if (success != 0) {
-+ LOG_DBG
-+ ("%s: failed to close VCHI service connection (status=%d)\n",
-+ __func__, success);
-+ }
-+ }
-+
-+ mutex_unlock(&instance->vchi_mutex);
-+
-+ kfree(instance);
-+
-+ LOG_DBG(" .. OUT\n");
-+
-+ return 0;
-+}
-+
-+static int bcm2835_audio_open_connection(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+ static VCHI_INSTANCE_T vchi_instance;
-+ static VCHI_CONNECTION_T *vchi_connection;
-+ static int initted;
-+ AUDIO_INSTANCE_T *instance = alsa_stream->instance;
-+ int ret;
-+ LOG_DBG(" .. IN\n");
-+
-+ LOG_INFO("%s: start\n", __func__);
-+ BUG_ON(instance);
-+ if (instance) {
-+ LOG_ERR("%s: VCHI instance already open (%p)\n",
-+ __func__, instance);
-+ instance->alsa_stream = alsa_stream;
-+ alsa_stream->instance = instance;
-+ ret = 0; // xxx todo -1;
-+ goto err_free_mem;
-+ }
-+
-+ /* Initialize and create a VCHI connection */
-+ if (!initted) {
-+ ret = vchi_initialise(&vchi_instance);
-+ if (ret != 0) {
-+ LOG_ERR("%s: failed to initialise VCHI instance (ret=%d)\n",
-+ __func__, ret);
-+
-+ ret = -EIO;
-+ goto err_free_mem;
-+ }
-+ ret = vchi_connect(NULL, 0, vchi_instance);
-+ if (ret != 0) {
-+ LOG_ERR("%s: failed to connect VCHI instance (ret=%d)\n",
-+ __func__, ret);
-+
-+ ret = -EIO;
-+ goto err_free_mem;
-+ }
-+ initted = 1;
-+ }
-+
-+ /* Initialize an instance of the audio service */
-+ instance = vc_vchi_audio_init(vchi_instance, &vchi_connection, 1);
-+
-+ if (instance == NULL) {
-+ LOG_ERR("%s: failed to initialize audio service\n", __func__);
-+
-+ ret = -EPERM;
-+ goto err_free_mem;
-+ }
-+
-+ instance->alsa_stream = alsa_stream;
-+ alsa_stream->instance = instance;
-+
-+ LOG_DBG(" success !\n");
-+err_free_mem:
-+ LOG_DBG(" .. OUT\n");
-+
-+ return ret;
-+}
-+
-+int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+ AUDIO_INSTANCE_T *instance;
-+ VC_AUDIO_MSG_T m;
-+ int32_t success;
-+ int ret;
-+ LOG_DBG(" .. IN\n");
-+
-+ my_workqueue_init(alsa_stream);
-+
-+ ret = bcm2835_audio_open_connection(alsa_stream);
-+ if (ret != 0) {
-+ ret = -1;
-+ goto exit;
-+ }
-+ instance = alsa_stream->instance;
-+ LOG_DBG(" instance (%p)\n", instance);
-+
-+ if(mutex_lock_interruptible(&instance->vchi_mutex))
-+ {
-+ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
-+ return -EINTR;
-+ }
-+ vchi_service_use(instance->vchi_handle[0]);
-+
-+ m.type = VC_AUDIO_MSG_TYPE_OPEN;
-+
-+ /* Send the message to the videocore */
-+ success = vchi_msg_queue(instance->vchi_handle[0],
-+ &m, sizeof m,
-+ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
-+
-+ if (success != 0) {
-+ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
-+ __func__, success);
-+
-+ ret = -1;
-+ goto unlock;
-+ }
-+
-+ ret = 0;
-+
-+unlock:
-+ vchi_service_release(instance->vchi_handle[0]);
-+ mutex_unlock(&instance->vchi_mutex);
-+exit:
-+ LOG_DBG(" .. OUT\n");
-+ return ret;
-+}
-+
-+static int bcm2835_audio_set_ctls_chan(bcm2835_alsa_stream_t * alsa_stream,
-+ bcm2835_chip_t * chip)
-+{
-+ VC_AUDIO_MSG_T m;
-+ AUDIO_INSTANCE_T *instance = alsa_stream->instance;
-+ int32_t success;
-+ int ret;
-+ LOG_DBG(" .. IN\n");
-+
-+ LOG_INFO
-+ (" Setting ALSA dest(%d), volume(%d)\n", chip->dest, chip->volume);
-+
-+ if(mutex_lock_interruptible(&instance->vchi_mutex))
-+ {
-+ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
-+ return -EINTR;
-+ }
-+ vchi_service_use(instance->vchi_handle[0]);
-+
-+ instance->result = -1;
-+
-+ m.type = VC_AUDIO_MSG_TYPE_CONTROL;
-+ m.u.control.dest = chip->dest;
-+ m.u.control.volume = chip->volume;
-+
-+ /* Create the message available completion */
-+ init_completion(&instance->msg_avail_comp);
-+
-+ /* Send the message to the videocore */
-+ success = vchi_msg_queue(instance->vchi_handle[0],
-+ &m, sizeof m,
-+ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
-+
-+ if (success != 0) {
-+ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
-+ __func__, success);
-+
-+ ret = -1;
-+ goto unlock;
-+ }
-+
-+ /* We are expecting a reply from the videocore */
-+ ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
-+ if (ret) {
-+ LOG_DBG("%s: failed on waiting for event (status=%d)\n",
-+ __func__, success);
-+ goto unlock;
-+ }
-+
-+ if (instance->result != 0) {
-+ LOG_ERR("%s: result=%d\n", __func__, instance->result);
-+
-+ ret = -1;
-+ goto unlock;
-+ }
-+
-+ ret = 0;
-+
-+unlock:
-+ vchi_service_release(instance->vchi_handle[0]);
-+ mutex_unlock(&instance->vchi_mutex);
-+
-+ LOG_DBG(" .. OUT\n");
-+ return ret;
-+}
-+
-+int bcm2835_audio_set_ctls(bcm2835_chip_t * chip)
-+{
-+ int i;
-+ int ret = 0;
-+ LOG_DBG(" .. IN\n");
-+ LOG_DBG(" Setting ALSA dest(%d), volume(%d)\n", chip->dest, chip->volume);
-+
-+ /* change ctls for all substreams */
-+ for (i = 0; i < MAX_SUBSTREAMS; i++) {
-+ if (chip->avail_substreams & (1 << i)) {
-+ if (!chip->alsa_stream[i])
-+ {
-+ LOG_DBG(" No ALSA stream available?! %i:%p (%x)\n", i, chip->alsa_stream[i], chip->avail_substreams);
-+ ret = 0;
-+ }
-+ else if (bcm2835_audio_set_ctls_chan /* returns 0 on success */
-+ (chip->alsa_stream[i], chip) != 0)
-+ {
-+ LOG_ERR("Couldn't set the controls for stream %d\n", i);
-+ ret = -1;
-+ }
-+ else LOG_DBG(" Controls set for stream %d\n", i);
-+ }
-+ }
-+ LOG_DBG(" .. OUT ret=%d\n", ret);
-+ return ret;
-+}
-+
-+int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
-+ uint32_t channels, uint32_t samplerate,
-+ uint32_t bps)
-+{
-+ VC_AUDIO_MSG_T m;
-+ AUDIO_INSTANCE_T *instance = alsa_stream->instance;
-+ int32_t success;
-+ int ret;
-+ LOG_DBG(" .. IN\n");
-+
-+ LOG_INFO
-+ (" Setting ALSA channels(%d), samplerate(%d), bits-per-sample(%d)\n",
-+ channels, samplerate, bps);
-+
-+ /* resend ctls - alsa_stream may not have been open when first send */
-+ ret = bcm2835_audio_set_ctls_chan(alsa_stream, alsa_stream->chip);
-+ if (ret != 0) {
-+ LOG_ERR(" Alsa controls not supported\n");
-+ return -EINVAL;
-+ }
-+
-+ if(mutex_lock_interruptible(&instance->vchi_mutex))
-+ {
-+ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
-+ return -EINTR;
-+ }
-+ vchi_service_use(instance->vchi_handle[0]);
-+
-+ instance->result = -1;
-+
-+ m.type = VC_AUDIO_MSG_TYPE_CONFIG;
-+ m.u.config.channels = channels;
-+ m.u.config.samplerate = samplerate;
-+ m.u.config.bps = bps;
-+
-+ /* Create the message available completion */
-+ init_completion(&instance->msg_avail_comp);
-+
-+ /* Send the message to the videocore */
-+ success = vchi_msg_queue(instance->vchi_handle[0],
-+ &m, sizeof m,
-+ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
-+
-+ if (success != 0) {
-+ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
-+ __func__, success);
-+
-+ ret = -1;
-+ goto unlock;
-+ }
-+
-+ /* We are expecting a reply from the videocore */
-+ ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
-+ if (ret) {
-+ LOG_DBG("%s: failed on waiting for event (status=%d)\n",
-+ __func__, success);
-+ goto unlock;
-+ }
-+
-+ if (instance->result != 0) {
-+ LOG_ERR("%s: result=%d", __func__, instance->result);
-+
-+ ret = -1;
-+ goto unlock;
-+ }
-+
-+ ret = 0;
-+
-+unlock:
-+ vchi_service_release(instance->vchi_handle[0]);
-+ mutex_unlock(&instance->vchi_mutex);
-+
-+ LOG_DBG(" .. OUT\n");
-+ return ret;
-+}
-+
-+int bcm2835_audio_setup(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+ LOG_DBG(" .. IN\n");
-+
-+ LOG_DBG(" .. OUT\n");
-+
-+ return 0;
-+}
-+
-+static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+ VC_AUDIO_MSG_T m;
-+ AUDIO_INSTANCE_T *instance = alsa_stream->instance;
-+ int32_t success;
-+ int ret;
-+ LOG_DBG(" .. IN\n");
-+
-+ if(mutex_lock_interruptible(&instance->vchi_mutex))
-+ {
-+ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
-+ return -EINTR;
-+ }
-+ vchi_service_use(instance->vchi_handle[0]);
-+
-+ m.type = VC_AUDIO_MSG_TYPE_START;
-+
-+ /* Send the message to the videocore */
-+ success = vchi_msg_queue(instance->vchi_handle[0],
-+ &m, sizeof m,
-+ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
-+
-+ if (success != 0) {
-+ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
-+ __func__, success);
-+
-+ ret = -1;
-+ goto unlock;
-+ }
-+
-+ ret = 0;
-+
-+unlock:
-+ vchi_service_release(instance->vchi_handle[0]);
-+ mutex_unlock(&instance->vchi_mutex);
-+ LOG_DBG(" .. OUT\n");
-+ return ret;
-+}
-+
-+static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+ VC_AUDIO_MSG_T m;
-+ AUDIO_INSTANCE_T *instance = alsa_stream->instance;
-+ int32_t success;
-+ int ret;
-+ LOG_DBG(" .. IN\n");
-+
-+ if(mutex_lock_interruptible(&instance->vchi_mutex))
-+ {
-+ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
-+ return -EINTR;
-+ }
-+ vchi_service_use(instance->vchi_handle[0]);
-+
-+ m.type = VC_AUDIO_MSG_TYPE_STOP;
-+ m.u.stop.draining = alsa_stream->draining;
-+
-+ /* Send the message to the videocore */
-+ success = vchi_msg_queue(instance->vchi_handle[0],
-+ &m, sizeof m,
-+ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
-+
-+ if (success != 0) {
-+ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
-+ __func__, success);
-+
-+ ret = -1;
-+ goto unlock;
-+ }
-+
-+ ret = 0;
-+
-+unlock:
-+ vchi_service_release(instance->vchi_handle[0]);
-+ mutex_unlock(&instance->vchi_mutex);
-+ LOG_DBG(" .. OUT\n");
-+ return ret;
-+}
-+
-+int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+ VC_AUDIO_MSG_T m;
-+ AUDIO_INSTANCE_T *instance = alsa_stream->instance;
-+ int32_t success;
-+ int ret;
-+ LOG_DBG(" .. IN\n");
-+
-+ my_workqueue_quit(alsa_stream);
-+
-+ if(mutex_lock_interruptible(&instance->vchi_mutex))
-+ {
-+ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
-+ return -EINTR;
-+ }
-+ vchi_service_use(instance->vchi_handle[0]);
-+
-+ m.type = VC_AUDIO_MSG_TYPE_CLOSE;
-+
-+ /* Create the message available completion */
-+ init_completion(&instance->msg_avail_comp);
-+
-+ /* Send the message to the videocore */
-+ success = vchi_msg_queue(instance->vchi_handle[0],
-+ &m, sizeof m,
-+ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
-+
-+ if (success != 0) {
-+ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
-+ __func__, success);
-+ ret = -1;
-+ goto unlock;
-+ }
-+
-+ ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
-+ if (ret) {
-+ LOG_DBG("%s: failed on waiting for event (status=%d)\n",
-+ __func__, success);
-+ goto unlock;
-+ }
-+ if (instance->result != 0) {
-+ LOG_ERR("%s: failed result (status=%d)\n",
-+ __func__, instance->result);
-+
-+ ret = -1;
-+ goto unlock;
-+ }
-+
-+ ret = 0;
-+
-+unlock:
-+ vchi_service_release(instance->vchi_handle[0]);
-+ mutex_unlock(&instance->vchi_mutex);
-+
-+ /* Stop the audio service */
-+ if (instance) {
-+ vc_vchi_audio_deinit(instance);
-+ alsa_stream->instance = NULL;
-+ }
-+ LOG_DBG(" .. OUT\n");
-+ return ret;
-+}
-+
-+int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream,
-+ uint32_t count, void *src)
-+{
-+ VC_AUDIO_MSG_T m;
-+ AUDIO_INSTANCE_T *instance = alsa_stream->instance;
-+ int32_t success;
-+ int ret;
-+
-+ LOG_DBG(" .. IN\n");
-+
-+ LOG_INFO(" Writing %d bytes from %p\n", count, src);
-+
-+ if(mutex_lock_interruptible(&instance->vchi_mutex))
-+ {
-+ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
-+ return -EINTR;
-+ }
-+ vchi_service_use(instance->vchi_handle[0]);
-+
-+ if ( instance->peer_version==0 && vchi_get_peer_version(instance->vchi_handle[0], &instance->peer_version) == 0 ) {
-+ LOG_DBG("%s: client version %d connected\n", __func__, instance->peer_version);
-+ }
-+ m.type = VC_AUDIO_MSG_TYPE_WRITE;
-+ m.u.write.count = count;
-+ // old version uses bulk, new version uses control
-+ m.u.write.max_packet = instance->peer_version < 2 || force_bulk ? 0:4000;
-+ m.u.write.callback = alsa_stream->fifo_irq_handler;
-+ m.u.write.cookie = alsa_stream;
-+ m.u.write.silence = src == NULL;
-+
-+ /* Send the message to the videocore */
-+ success = vchi_msg_queue(instance->vchi_handle[0],
-+ &m, sizeof m,
-+ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
-+
-+ if (success != 0) {
-+ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
-+ __func__, success);
-+
-+ ret = -1;
-+ goto unlock;
-+ }
-+ if (!m.u.write.silence) {
-+ if (m.u.write.max_packet == 0) {
-+ /* Send the message to the videocore */
-+ success = vchi_bulk_queue_transmit(instance->vchi_handle[0],
-+ src, count,
-+ 0 *
-+ VCHI_FLAGS_BLOCK_UNTIL_QUEUED
-+ +
-+ 1 *
-+ VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
-+ NULL);
-+ } else {
-+ while (count > 0) {
-+ int bytes = min((int)m.u.write.max_packet, (int)count);
-+ success = vchi_msg_queue(instance->vchi_handle[0],
-+ src, bytes,
-+ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
-+ src = (char *)src + bytes;
-+ count -= bytes;
-+ }
-+ }
-+ if (success != 0) {
-+ LOG_ERR
-+ ("%s: failed on vchi_bulk_queue_transmit (status=%d)\n",
-+ __func__, success);
-+
-+ ret = -1;
-+ goto unlock;
-+ }
-+ }
-+ ret = 0;
-+
-+unlock:
-+ vchi_service_release(instance->vchi_handle[0]);
-+ mutex_unlock(&instance->vchi_mutex);
-+ LOG_DBG(" .. OUT\n");
-+ return ret;
-+}
-+
-+/**
-+ * Returns all buffers from arm->vc
-+ */
-+void bcm2835_audio_flush_buffers(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+ LOG_DBG(" .. IN\n");
-+ LOG_DBG(" .. OUT\n");
-+ return;
-+}
-+
-+/**
-+ * Forces VC to flush(drop) its filled playback buffers and
-+ * return them the us. (VC->ARM)
-+ */
-+void bcm2835_audio_flush_playback_buffers(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+ LOG_DBG(" .. IN\n");
-+ LOG_DBG(" .. OUT\n");
-+}
-+
-+uint32_t bcm2835_audio_retrieve_buffers(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+ uint32_t count = atomic_read(&alsa_stream->retrieved);
-+ atomic_sub(count, &alsa_stream->retrieved);
-+ return count;
-+}
-+
-+module_param(force_bulk, bool, 0444);
-+MODULE_PARM_DESC(force_bulk, "Force use of vchiq bulk for audio");
---- /dev/null
-+++ b/sound/arm/bcm2835.c
-@@ -0,0 +1,511 @@
-+/*****************************************************************************
-+* Copyright 2011 Broadcom Corporation. All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*****************************************************************************/
-+
-+#include <linux/platform_device.h>
-+
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+
-+#include "bcm2835.h"
-+
-+/* module parameters (see "Module Parameters") */
-+/* SNDRV_CARDS: maximum number of cards supported by this module */
-+static int index[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = -1 };
-+static char *id[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = NULL };
-+static int enable[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = 1 };
-+
-+/* HACKY global pointers needed for successive probes to work : ssp
-+ * But compared against the changes we will have to do in VC audio_ipc code
-+ * to export 8 audio_ipc devices as a single IPC device and then monitor all
-+ * four devices in a thread, this gets things done quickly and should be easier
-+ * to debug if we run into issues
-+ */
-+
-+static struct snd_card *g_card = NULL;
-+static bcm2835_chip_t *g_chip = NULL;
-+
-+static int snd_bcm2835_free(bcm2835_chip_t * chip)
-+{
-+ kfree(chip);
-+ return 0;
-+}
-+
-+/* component-destructor
-+ * (see "Management of Cards and Components")
-+ */
-+static int snd_bcm2835_dev_free(struct snd_device *device)
-+{
-+ return snd_bcm2835_free(device->device_data);
-+}
-+
-+/* chip-specific constructor
-+ * (see "Management of Cards and Components")
-+ */
-+static int snd_bcm2835_create(struct snd_card *card,
-+ struct platform_device *pdev,
-+ bcm2835_chip_t ** rchip)
-+{
-+ bcm2835_chip_t *chip;
-+ int err;
-+ static struct snd_device_ops ops = {
-+ .dev_free = snd_bcm2835_dev_free,
-+ };
-+
-+ *rchip = NULL;
-+
-+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
-+ if (chip == NULL)
-+ return -ENOMEM;
-+
-+ chip->card = card;
-+
-+ err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
-+ if (err < 0) {
-+ snd_bcm2835_free(chip);
-+ return err;
-+ }
-+
-+ *rchip = chip;
-+ return 0;
-+}
-+
-+static int snd_bcm2835_alsa_probe_dt(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ bcm2835_chip_t *chip;
-+ struct snd_card *card;
-+ u32 numchans;
-+ int err, i;
-+
-+ err = of_property_read_u32(dev->of_node, "brcm,pwm-channels",
-+ &numchans);
-+ if (err) {
-+ dev_err(dev, "Failed to get DT property 'brcm,pwm-channels'");
-+ return err;
-+ }
-+
-+ if (numchans == 0 || numchans > MAX_SUBSTREAMS) {
-+ numchans = MAX_SUBSTREAMS;
-+ dev_warn(dev, "Illegal 'brcm,pwm-channels' value, will use %u\n",
-+ numchans);
-+ }
-+
-+ err = snd_card_new(NULL, -1, NULL, THIS_MODULE, 0, &card);
-+ if (err) {
-+ dev_err(dev, "Failed to create soundcard structure\n");
-+ return err;
-+ }
-+
-+ snd_card_set_dev(card, dev);
-+ strcpy(card->driver, "bcm2835");
-+ strcpy(card->shortname, "bcm2835 ALSA");
-+ sprintf(card->longname, "%s", card->shortname);
-+
-+ err = snd_bcm2835_create(card, pdev, &chip);
-+ if (err < 0) {
-+ dev_err(dev, "Failed to create bcm2835 chip\n");
-+ goto err_free;
-+ }
-+
-+ err = snd_bcm2835_new_pcm(chip);
-+ if (err < 0) {
-+ dev_err(dev, "Failed to create new bcm2835 pcm device\n");
-+ goto err_free;
-+ }
-+
-+ err = snd_bcm2835_new_spdif_pcm(chip);
-+ if (err < 0) {
-+ dev_err(dev, "Failed to create new bcm2835 spdif pcm device\n");
-+ goto err_free;
-+ }
-+
-+ err = snd_bcm2835_new_ctl(chip);
-+ if (err < 0) {
-+ dev_err(dev, "Failed to create new bcm2835 ctl\n");
-+ goto err_free;
-+ }
-+
-+ for (i = 0; i < numchans; i++) {
-+ chip->avail_substreams |= (1 << i);
-+ chip->pdev[i] = pdev;
-+ }
-+
-+ err = snd_card_register(card);
-+ if (err) {
-+ dev_err(dev, "Failed to register bcm2835 ALSA card \n");
-+ goto err_free;
-+ }
-+
-+ g_card = card;
-+ g_chip = chip;
-+ platform_set_drvdata(pdev, card);
-+ audio_info("bcm2835 ALSA card created with %u channels\n", numchans);
-+
-+ return 0;
-+
-+err_free:
-+ snd_card_free(card);
-+
-+ return err;
-+}
-+
-+static int snd_bcm2835_alsa_probe(struct platform_device *pdev)
-+{
-+ static int dev;
-+ bcm2835_chip_t *chip;
-+ struct snd_card *card;
-+ int err;
-+
-+ if (pdev->dev.of_node)
-+ return snd_bcm2835_alsa_probe_dt(pdev);
-+
-+ if (dev >= MAX_SUBSTREAMS)
-+ return -ENODEV;
-+
-+ if (!enable[dev]) {
-+ dev++;
-+ return -ENOENT;
-+ }
-+
-+ if (dev > 0)
-+ goto add_register_map;
-+
-+ err = snd_card_new(NULL, index[dev], id[dev], THIS_MODULE, 0, &g_card);
-+ if (err < 0)
-+ goto out;
-+
-+ snd_card_set_dev(g_card, &pdev->dev);
-+ strcpy(g_card->driver, "bcm2835");
-+ strcpy(g_card->shortname, "bcm2835 ALSA");
-+ sprintf(g_card->longname, "%s", g_card->shortname);
-+
-+ err = snd_bcm2835_create(g_card, pdev, &chip);
-+ if (err < 0) {
-+ dev_err(&pdev->dev, "Failed to create bcm2835 chip\n");
-+ goto out_bcm2835_create;
-+ }
-+
-+ g_chip = chip;
-+ err = snd_bcm2835_new_pcm(chip);
-+ if (err < 0) {
-+ dev_err(&pdev->dev, "Failed to create new BCM2835 pcm device\n");
-+ goto out_bcm2835_new_pcm;
-+ }
-+
-+ err = snd_bcm2835_new_spdif_pcm(chip);
-+ if (err < 0) {
-+ dev_err(&pdev->dev, "Failed to create new BCM2835 spdif pcm device\n");
-+ goto out_bcm2835_new_spdif;
-+ }
-+
-+ err = snd_bcm2835_new_ctl(chip);
-+ if (err < 0) {
-+ dev_err(&pdev->dev, "Failed to create new BCM2835 ctl\n");
-+ goto out_bcm2835_new_ctl;
-+ }
-+
-+add_register_map:
-+ card = g_card;
-+ chip = g_chip;
-+
-+ BUG_ON(!(card && chip));
-+
-+ chip->avail_substreams |= (1 << dev);
-+ chip->pdev[dev] = pdev;
-+
-+ if (dev == 0) {
-+ err = snd_card_register(card);
-+ if (err < 0) {
-+ dev_err(&pdev->dev,
-+ "Failed to register bcm2835 ALSA card \n");
-+ goto out_card_register;
-+ }
-+ platform_set_drvdata(pdev, card);
-+ audio_info("bcm2835 ALSA card created!\n");
-+ } else {
-+ audio_info("bcm2835 ALSA chip created!\n");
-+ platform_set_drvdata(pdev, (void *)dev);
-+ }
-+
-+ dev++;
-+
-+ return 0;
-+
-+out_card_register:
-+out_bcm2835_new_ctl:
-+out_bcm2835_new_spdif:
-+out_bcm2835_new_pcm:
-+out_bcm2835_create:
-+ BUG_ON(!g_card);
-+ if (snd_card_free(g_card))
-+ dev_err(&pdev->dev, "Failed to free Registered alsa card\n");
-+ g_card = NULL;
-+out:
-+ dev = SNDRV_CARDS; /* stop more avail_substreams from being probed */
-+ dev_err(&pdev->dev, "BCM2835 ALSA Probe failed !!\n");
-+ return err;
-+}
-+
-+static int snd_bcm2835_alsa_remove(struct platform_device *pdev)
-+{
-+ uint32_t idx;
-+ void *drv_data;
-+
-+ drv_data = platform_get_drvdata(pdev);
-+
-+ if (drv_data == (void *)g_card) {
-+ /* This is the card device */
-+ snd_card_free((struct snd_card *)drv_data);
-+ g_card = NULL;
-+ g_chip = NULL;
-+ } else {
-+ idx = (uint32_t) drv_data;
-+ if (g_card != NULL) {
-+ BUG_ON(!g_chip);
-+ /* We pass chip device numbers in audio ipc devices
-+ * other than the one we registered our card with
-+ */
-+ idx = (uint32_t) drv_data;
-+ BUG_ON(!idx || idx > MAX_SUBSTREAMS);
-+ g_chip->avail_substreams &= ~(1 << idx);
-+ /* There should be atleast one substream registered
-+ * after we are done here, as it wil be removed when
-+ * the *remove* is called for the card device
-+ */
-+ BUG_ON(!g_chip->avail_substreams);
-+ }
-+ }
-+
-+ platform_set_drvdata(pdev, NULL);
-+
-+ return 0;
-+}
-+
-+#ifdef CONFIG_PM
-+static int snd_bcm2835_alsa_suspend(struct platform_device *pdev,
-+ pm_message_t state)
-+{
-+ return 0;
-+}
-+
-+static int snd_bcm2835_alsa_resume(struct platform_device *pdev)
-+{
-+ return 0;
-+}
-+
-+#endif
-+
-+static const struct of_device_id snd_bcm2835_of_match_table[] = {
-+ { .compatible = "brcm,bcm2835-audio", },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(of, snd_bcm2835_of_match_table);
-+
-+static struct platform_driver bcm2835_alsa0_driver = {
-+ .probe = snd_bcm2835_alsa_probe,
-+ .remove = snd_bcm2835_alsa_remove,
-+#ifdef CONFIG_PM
-+ .suspend = snd_bcm2835_alsa_suspend,
-+ .resume = snd_bcm2835_alsa_resume,
-+#endif
-+ .driver = {
-+ .name = "bcm2835_AUD0",
-+ .owner = THIS_MODULE,
-+ .of_match_table = snd_bcm2835_of_match_table,
-+ },
-+};
-+
-+static struct platform_driver bcm2835_alsa1_driver = {
-+ .probe = snd_bcm2835_alsa_probe,
-+ .remove = snd_bcm2835_alsa_remove,
-+#ifdef CONFIG_PM
-+ .suspend = snd_bcm2835_alsa_suspend,
-+ .resume = snd_bcm2835_alsa_resume,
-+#endif
-+ .driver = {
-+ .name = "bcm2835_AUD1",
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+static struct platform_driver bcm2835_alsa2_driver = {
-+ .probe = snd_bcm2835_alsa_probe,
-+ .remove = snd_bcm2835_alsa_remove,
-+#ifdef CONFIG_PM
-+ .suspend = snd_bcm2835_alsa_suspend,
-+ .resume = snd_bcm2835_alsa_resume,
-+#endif
-+ .driver = {
-+ .name = "bcm2835_AUD2",
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+static struct platform_driver bcm2835_alsa3_driver = {
-+ .probe = snd_bcm2835_alsa_probe,
-+ .remove = snd_bcm2835_alsa_remove,
-+#ifdef CONFIG_PM
-+ .suspend = snd_bcm2835_alsa_suspend,
-+ .resume = snd_bcm2835_alsa_resume,
-+#endif
-+ .driver = {
-+ .name = "bcm2835_AUD3",
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+static struct platform_driver bcm2835_alsa4_driver = {
-+ .probe = snd_bcm2835_alsa_probe,
-+ .remove = snd_bcm2835_alsa_remove,
-+#ifdef CONFIG_PM
-+ .suspend = snd_bcm2835_alsa_suspend,
-+ .resume = snd_bcm2835_alsa_resume,
-+#endif
-+ .driver = {
-+ .name = "bcm2835_AUD4",
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+static struct platform_driver bcm2835_alsa5_driver = {
-+ .probe = snd_bcm2835_alsa_probe,
-+ .remove = snd_bcm2835_alsa_remove,
-+#ifdef CONFIG_PM
-+ .suspend = snd_bcm2835_alsa_suspend,
-+ .resume = snd_bcm2835_alsa_resume,
-+#endif
-+ .driver = {
-+ .name = "bcm2835_AUD5",
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+static struct platform_driver bcm2835_alsa6_driver = {
-+ .probe = snd_bcm2835_alsa_probe,
-+ .remove = snd_bcm2835_alsa_remove,
-+#ifdef CONFIG_PM
-+ .suspend = snd_bcm2835_alsa_suspend,
-+ .resume = snd_bcm2835_alsa_resume,
-+#endif
-+ .driver = {
-+ .name = "bcm2835_AUD6",
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+static struct platform_driver bcm2835_alsa7_driver = {
-+ .probe = snd_bcm2835_alsa_probe,
-+ .remove = snd_bcm2835_alsa_remove,
-+#ifdef CONFIG_PM
-+ .suspend = snd_bcm2835_alsa_suspend,
-+ .resume = snd_bcm2835_alsa_resume,
-+#endif
-+ .driver = {
-+ .name = "bcm2835_AUD7",
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+static int bcm2835_alsa_device_init(void)
-+{
-+ int err;
-+ err = platform_driver_register(&bcm2835_alsa0_driver);
-+ if (err) {
-+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
-+ goto out;
-+ }
-+
-+ err = platform_driver_register(&bcm2835_alsa1_driver);
-+ if (err) {
-+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
-+ goto unregister_0;
-+ }
-+
-+ err = platform_driver_register(&bcm2835_alsa2_driver);
-+ if (err) {
-+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
-+ goto unregister_1;
-+ }
-+
-+ err = platform_driver_register(&bcm2835_alsa3_driver);
-+ if (err) {
-+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
-+ goto unregister_2;
-+ }
-+
-+ err = platform_driver_register(&bcm2835_alsa4_driver);
-+ if (err) {
-+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
-+ goto unregister_3;
-+ }
-+
-+ err = platform_driver_register(&bcm2835_alsa5_driver);
-+ if (err) {
-+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
-+ goto unregister_4;
-+ }
-+
-+ err = platform_driver_register(&bcm2835_alsa6_driver);
-+ if (err) {
-+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
-+ goto unregister_5;
-+ }
-+
-+ err = platform_driver_register(&bcm2835_alsa7_driver);
-+ if (err) {
-+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
-+ goto unregister_6;
-+ }
-+
-+ return 0;
-+
-+unregister_6:
-+ platform_driver_unregister(&bcm2835_alsa6_driver);
-+unregister_5:
-+ platform_driver_unregister(&bcm2835_alsa5_driver);
-+unregister_4:
-+ platform_driver_unregister(&bcm2835_alsa4_driver);
-+unregister_3:
-+ platform_driver_unregister(&bcm2835_alsa3_driver);
-+unregister_2:
-+ platform_driver_unregister(&bcm2835_alsa2_driver);
-+unregister_1:
-+ platform_driver_unregister(&bcm2835_alsa1_driver);
-+unregister_0:
-+ platform_driver_unregister(&bcm2835_alsa0_driver);
-+out:
-+ return err;
-+}
-+
-+static void bcm2835_alsa_device_exit(void)
-+{
-+ platform_driver_unregister(&bcm2835_alsa0_driver);
-+ platform_driver_unregister(&bcm2835_alsa1_driver);
-+ platform_driver_unregister(&bcm2835_alsa2_driver);
-+ platform_driver_unregister(&bcm2835_alsa3_driver);
-+ platform_driver_unregister(&bcm2835_alsa4_driver);
-+ platform_driver_unregister(&bcm2835_alsa5_driver);
-+ platform_driver_unregister(&bcm2835_alsa6_driver);
-+ platform_driver_unregister(&bcm2835_alsa7_driver);
-+}
-+
-+late_initcall(bcm2835_alsa_device_init);
-+module_exit(bcm2835_alsa_device_exit);
-+
-+MODULE_AUTHOR("Dom Cobley");
-+MODULE_DESCRIPTION("Alsa driver for BCM2835 chip");
-+MODULE_LICENSE("GPL");
-+MODULE_ALIAS("platform:bcm2835_alsa");
---- /dev/null
-+++ b/sound/arm/bcm2835.h
-@@ -0,0 +1,167 @@
-+/*****************************************************************************
-+* Copyright 2011 Broadcom Corporation. All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*****************************************************************************/
-+
-+#ifndef __SOUND_ARM_BCM2835_H
-+#define __SOUND_ARM_BCM2835_H
-+
-+#include <linux/device.h>
-+#include <linux/list.h>
-+#include <linux/interrupt.h>
-+#include <linux/wait.h>
-+#include <sound/core.h>
-+#include <sound/initval.h>
-+#include <sound/pcm.h>
-+#include <sound/pcm_params.h>
-+#include <sound/pcm-indirect.h>
-+#include <linux/workqueue.h>
-+
-+/*
-+#define AUDIO_DEBUG_ENABLE
-+#define AUDIO_VERBOSE_DEBUG_ENABLE
-+*/
-+
-+/* Debug macros */
-+
-+#ifdef AUDIO_DEBUG_ENABLE
-+#ifdef AUDIO_VERBOSE_DEBUG_ENABLE
-+
-+#define audio_debug(fmt, arg...) \
-+ printk(KERN_INFO"%s:%d " fmt, __func__, __LINE__, ##arg)
-+
-+#define audio_info(fmt, arg...) \
-+ printk(KERN_INFO"%s:%d " fmt, __func__, __LINE__, ##arg)
-+
-+#else
-+
-+#define audio_debug(fmt, arg...)
-+
-+#define audio_info(fmt, arg...)
-+
-+#endif /* AUDIO_VERBOSE_DEBUG_ENABLE */
-+
-+#else
-+
-+#define audio_debug(fmt, arg...)
-+
-+#define audio_info(fmt, arg...)
-+
-+#endif /* AUDIO_DEBUG_ENABLE */
-+
-+#define audio_error(fmt, arg...) \
-+ printk(KERN_ERR"%s:%d " fmt, __func__, __LINE__, ##arg)
-+
-+#define audio_warning(fmt, arg...) \
-+ printk(KERN_WARNING"%s:%d " fmt, __func__, __LINE__, ##arg)
-+
-+#define audio_alert(fmt, arg...) \
-+ printk(KERN_ALERT"%s:%d " fmt, __func__, __LINE__, ##arg)
-+
-+#define MAX_SUBSTREAMS (8)
-+#define AVAIL_SUBSTREAMS_MASK (0xff)
-+enum {
-+ CTRL_VOL_MUTE,
-+ CTRL_VOL_UNMUTE
-+};
-+
-+/* macros for alsa2chip and chip2alsa, instead of functions */
-+
-+#define alsa2chip(vol) (uint)(-((vol << 8) / 100)) /* convert alsa to chip volume (defined as macro rather than function call) */
-+#define chip2alsa(vol) -((vol * 100) >> 8) /* convert chip to alsa volume */
-+
-+/* Some constants for values .. */
-+typedef enum {
-+ AUDIO_DEST_AUTO = 0,
-+ AUDIO_DEST_HEADPHONES = 1,
-+ AUDIO_DEST_HDMI = 2,
-+ AUDIO_DEST_MAX,
-+} SND_BCM2835_ROUTE_T;
-+
-+typedef enum {
-+ PCM_PLAYBACK_VOLUME,
-+ PCM_PLAYBACK_MUTE,
-+ PCM_PLAYBACK_DEVICE,
-+} SND_BCM2835_CTRL_T;
-+
-+/* definition of the chip-specific record */
-+typedef struct bcm2835_chip {
-+ struct snd_card *card;
-+ struct snd_pcm *pcm;
-+ struct snd_pcm *pcm_spdif;
-+ /* Bitmat for valid reg_base and irq numbers */
-+ uint32_t avail_substreams;
-+ struct platform_device *pdev[MAX_SUBSTREAMS];
-+ struct bcm2835_alsa_stream *alsa_stream[MAX_SUBSTREAMS];
-+
-+ int volume;
-+ int old_volume; /* stores the volume value whist muted */
-+ int dest;
-+ int mute;
-+
-+ unsigned int opened;
-+ unsigned int spdif_status;
-+ struct mutex audio_mutex;
-+} bcm2835_chip_t;
-+
-+typedef struct bcm2835_alsa_stream {
-+ bcm2835_chip_t *chip;
-+ struct snd_pcm_substream *substream;
-+ struct snd_pcm_indirect pcm_indirect;
-+
-+ struct semaphore buffers_update_sem;
-+ struct semaphore control_sem;
-+ spinlock_t lock;
-+ volatile uint32_t control;
-+ volatile uint32_t status;
-+
-+ int open;
-+ int running;
-+ int draining;
-+
-+ int channels;
-+ int params_rate;
-+ int pcm_format_width;
-+
-+ unsigned int pos;
-+ unsigned int buffer_size;
-+ unsigned int period_size;
-+
-+ uint32_t enable_fifo_irq;
-+ irq_handler_t fifo_irq_handler;
-+
-+ atomic_t retrieved;
-+ struct opaque_AUDIO_INSTANCE_T *instance;
-+ struct workqueue_struct *my_wq;
-+ int idx;
-+} bcm2835_alsa_stream_t;
-+
-+int snd_bcm2835_new_ctl(bcm2835_chip_t * chip);
-+int snd_bcm2835_new_pcm(bcm2835_chip_t * chip);
-+int snd_bcm2835_new_spdif_pcm(bcm2835_chip_t * chip);
-+
-+int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream);
-+int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream);
-+int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
-+ uint32_t channels, uint32_t samplerate,
-+ uint32_t bps);
-+int bcm2835_audio_setup(bcm2835_alsa_stream_t * alsa_stream);
-+int bcm2835_audio_start(bcm2835_alsa_stream_t * alsa_stream);
-+int bcm2835_audio_stop(bcm2835_alsa_stream_t * alsa_stream);
-+int bcm2835_audio_set_ctls(bcm2835_chip_t * chip);
-+int bcm2835_audio_write(bcm2835_alsa_stream_t * alsa_stream, uint32_t count,
-+ void *src);
-+uint32_t bcm2835_audio_retrieve_buffers(bcm2835_alsa_stream_t * alsa_stream);
-+void bcm2835_audio_flush_buffers(bcm2835_alsa_stream_t * alsa_stream);
-+void bcm2835_audio_flush_playback_buffers(bcm2835_alsa_stream_t * alsa_stream);
-+
-+#endif /* __SOUND_ARM_BCM2835_H */
---- /dev/null
-+++ b/sound/arm/vc_vchi_audioserv_defs.h
-@@ -0,0 +1,116 @@
-+/*****************************************************************************
-+* Copyright 2011 Broadcom Corporation. All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*****************************************************************************/
-+
-+#ifndef _VC_AUDIO_DEFS_H_
-+#define _VC_AUDIO_DEFS_H_
-+
-+#define VC_AUDIOSERV_MIN_VER 1
-+#define VC_AUDIOSERV_VER 2
-+
-+// FourCC code used for VCHI connection
-+#define VC_AUDIO_SERVER_NAME MAKE_FOURCC("AUDS")
-+
-+// Maximum message length
-+#define VC_AUDIO_MAX_MSG_LEN (sizeof( VC_AUDIO_MSG_T ))
-+
-+// List of screens that are currently supported
-+// All message types supported for HOST->VC direction
-+typedef enum {
-+ VC_AUDIO_MSG_TYPE_RESULT, // Generic result
-+ VC_AUDIO_MSG_TYPE_COMPLETE, // Generic result
-+ VC_AUDIO_MSG_TYPE_CONFIG, // Configure audio
-+ VC_AUDIO_MSG_TYPE_CONTROL, // Configure audio
-+ VC_AUDIO_MSG_TYPE_OPEN, // Configure audio
-+ VC_AUDIO_MSG_TYPE_CLOSE, // Configure audio
-+ VC_AUDIO_MSG_TYPE_START, // Configure audio
-+ VC_AUDIO_MSG_TYPE_STOP, // Configure audio
-+ VC_AUDIO_MSG_TYPE_WRITE, // Configure audio
-+ VC_AUDIO_MSG_TYPE_MAX
-+} VC_AUDIO_MSG_TYPE;
-+
-+// configure the audio
-+typedef struct {
-+ uint32_t channels;
-+ uint32_t samplerate;
-+ uint32_t bps;
-+
-+} VC_AUDIO_CONFIG_T;
-+
-+typedef struct {
-+ uint32_t volume;
-+ uint32_t dest;
-+
-+} VC_AUDIO_CONTROL_T;
-+
-+// audio
-+typedef struct {
-+ uint32_t dummy;
-+
-+} VC_AUDIO_OPEN_T;
-+
-+// audio
-+typedef struct {
-+ uint32_t dummy;
-+
-+} VC_AUDIO_CLOSE_T;
-+// audio
-+typedef struct {
-+ uint32_t dummy;
-+
-+} VC_AUDIO_START_T;
-+// audio
-+typedef struct {
-+ uint32_t draining;
-+
-+} VC_AUDIO_STOP_T;
-+
-+// configure the write audio samples
-+typedef struct {
-+ uint32_t count; // in bytes
-+ void *callback;
-+ void *cookie;
-+ uint16_t silence;
-+ uint16_t max_packet;
-+} VC_AUDIO_WRITE_T;
-+
-+// Generic result for a request (VC->HOST)
-+typedef struct {
-+ int32_t success; // Success value
-+
-+} VC_AUDIO_RESULT_T;
-+
-+// Generic result for a request (VC->HOST)
-+typedef struct {
-+ int32_t count; // Success value
-+ void *callback;
-+ void *cookie;
-+} VC_AUDIO_COMPLETE_T;
-+
-+// Message header for all messages in HOST->VC direction
-+typedef struct {
-+ int32_t type; // Message type (VC_AUDIO_MSG_TYPE)
-+ union {
-+ VC_AUDIO_CONFIG_T config;
-+ VC_AUDIO_CONTROL_T control;
-+ VC_AUDIO_OPEN_T open;
-+ VC_AUDIO_CLOSE_T close;
-+ VC_AUDIO_START_T start;
-+ VC_AUDIO_STOP_T stop;
-+ VC_AUDIO_WRITE_T write;
-+ VC_AUDIO_RESULT_T result;
-+ VC_AUDIO_COMPLETE_T complete;
-+ } u;
-+} VC_AUDIO_MSG_T;
-+
-+#endif // _VC_AUDIO_DEFS_H_
diff --git a/target/linux/brcm2708/patches-4.4/0036-bcm2708-vchiq-driver.patch b/target/linux/brcm2708/patches-4.4/0036-bcm2708-vchiq-driver.patch
new file mode 100644
index 0000000000..3b89f266d8
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0036-bcm2708-vchiq-driver.patch
@@ -0,0 +1,13200 @@
+From 6862270cc99bacc345403c730c38b17615834aef Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Tue, 2 Jul 2013 23:42:01 +0100
+Subject: [PATCH 036/381] bcm2708 vchiq driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: popcornmix <popcornmix@gmail.com>
+
+vchiq: create_pagelist copes with vmalloc memory
+
+Signed-off-by: Daniel Stone <daniels@collabora.com>
+
+vchiq: fix the shim message release
+
+Signed-off-by: Daniel Stone <daniels@collabora.com>
+
+vchiq: export additional symbols
+
+Signed-off-by: Daniel Stone <daniels@collabora.com>
+
+VCHIQ: Make service closure fully synchronous (drv)
+
+This is one half of a two-part patch, the other half of which is to
+the vchiq_lib user library. With these patches, calls to
+vchiq_close_service and vchiq_remove_service won't return until any
+associated callbacks have been delivered to the callback thread.
+
+VCHIQ: Add per-service tracing
+
+The new service option VCHIQ_SERVICE_OPTION_TRACE is a boolean that
+toggles tracing for the specified service.
+
+This commit also introduces vchi_service_set_option and the associated
+option VCHI_SERVICE_OPTION_TRACE.
+
+vchiq: Make the synchronous-CLOSE logic more tolerant
+
+vchiq: Move logging control into debugfs
+
+vchiq: Take care of a corner case tickled by VCSM
+
+Closing a connection that isn't fully open requires care, since one
+side does not know the other side's port number. Code was present to
+handle the case where a CLOSE is sent immediately after an OPEN, i.e.
+before the OPENACK has been received, but this was incorrectly being
+used when an OPEN from a client using port 0 was rejected.
+
+(In the observed failure, the host was attempting to use the VCSM
+service, which isn't present in the 'cutdown' firmware. The failure
+was intermittent because sometimes the keepalive service would
+grab port 0.)
+
+This case can be distinguished because the client's remoteport will
+still be VCHIQ_PORT_FREE, and the srvstate will be OPENING. Either
+condition is sufficient to differentiate it from the special case
+described above.
+
+vchiq: Avoid high load when blocked and unkillable
+
+vchiq: Include SIGSTOP and SIGCONT in list of signals not-masked by vchiq to allow gdb to work
+
+vchiq_arm: Complete support for SYNCHRONOUS mode
+
+vchiq: Remove inline from suspend/resume
+
+vchiq: Allocation does not need to be atomic
+
+vchiq: Fix wrong condition check
+
+The log level is checked from within the log call. Remove the check in the call.
+
+Signed-off-by: Pranith Kumar <bobby.prani@gmail.com>
+
+BCM270x: Add vchiq device to platform file and Device Tree
+
+Prepare to turn the vchiq module into a driver.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+
+bcm2708: vchiq: Add Device Tree support
+
+Turn vchiq into a driver and stop hardcoding resources.
+Use devm_* functions in probe path to simplify cleanup.
+A global variable is used to hold the register address. This is done
+to keep this patch as small as possible.
+Also make available on ARCH_BCM2835.
+Based on work by Lubomir Rintel.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+
+vchiq: Change logging level for inbound data
+
+vchiq_arm: Two cacheing fixes
+
+1) Make fragment size vary with cache line size
+Without this patch, non-cache-line-aligned transfers may corrupt
+(or be corrupted by) adjacent data structures.
+
+Both ARM and VC need to be updated to enable this feature. This is
+ensured by having the loader apply a new DT parameter -
+cache-line-size. The existence of this parameter guarantees that the
+kernel is capable, and the parameter will only be modified from the
+safe default if the loader is capable.
+
+2) Flush/invalidate vmalloc'd memory, and invalidate after reads
+
+vchiq: fix NULL pointer dereference when closing driver
+
+The following code run as root will cause a null pointer dereference oops:
+
+ int fd = open("/dev/vc-cma", O_RDONLY);
+ if (fd < 0)
+ err(1, "open failed");
+ (void)close(fd);
+
+[ 1704.877721] Unable to handle kernel NULL pointer dereference at virtual address 00000000
+[ 1704.877725] pgd = b899c000
+[ 1704.877736] [00000000] *pgd=37fab831, *pte=00000000, *ppte=00000000
+[ 1704.877748] Internal error: Oops: 817 [#1] PREEMPT SMP ARM
+[ 1704.877765] Modules linked in: evdev i2c_bcm2708 uio_pdrv_genirq uio
+[ 1704.877774] CPU: 2 PID: 3656 Comm: stress-ng-fstat Not tainted 3.19.1-12-generic-bcm2709 #12-Ubuntu
+[ 1704.877777] Hardware name: BCM2709
+[ 1704.877783] task: b8ab9b00 ti: b7e68000 task.ti: b7e68000
+[ 1704.877798] PC is at __down_interruptible+0x50/0xec
+[ 1704.877806] LR is at down_interruptible+0x5c/0x68
+[ 1704.877813] pc : [<80630ee8>] lr : [<800704b0>] psr: 60080093
+sp : b7e69e50 ip : b7e69e88 fp : b7e69e84
+[ 1704.877817] r10: b88123c8 r9 : 00000010 r8 : 00000001
+[ 1704.877822] r7 : b8ab9b00 r6 : 7fffffff r5 : 80a1cc34 r4 : 80a1cc34
+[ 1704.877826] r3 : b7e69e50 r2 : 00000000 r1 : 00000000 r0 : 80a1cc34
+[ 1704.877833] Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment user
+[ 1704.877838] Control: 10c5387d Table: 3899c06a DAC: 00000015
+[ 1704.877843] Process do-oops (pid: 3656, stack limit = 0xb7e68238)
+[ 1704.877848] Stack: (0xb7e69e50 to 0xb7e6a000)
+[ 1704.877856] 9e40: 80a1cc3c 00000000 00000010 b88123c8
+[ 1704.877865] 9e60: b7e69e84 80a1cc34 fff9fee9 ffffffff b7e68000 00000009 b7e69ea4 b7e69e88
+[ 1704.877874] 9e80: 800704b0 80630ea4 fff9fee9 60080013 80a1cc28 fff9fee9 b7e69edc b7e69ea8
+[ 1704.877884] 9ea0: 8040f558 80070460 fff9fee9 ffffffff 00000000 00000000 00000009 80a1cb7c
+[ 1704.877893] 9ec0: 00000000 80a1cb7c 00000000 00000010 b7e69ef4 b7e69ee0 803e1ba4 8040f514
+[ 1704.877902] 9ee0: 00000e48 80a1cb7c b7e69f14 b7e69ef8 803e1c9c 803e1b74 b88123c0 b92acb18
+[ 1704.877911] 9f00: b8812790 b8d815d8 b7e69f24 b7e69f18 803e2250 803e1bc8 b7e69f5c b7e69f28
+[ 1704.877921] 9f20: 80167bac 803e222c 00000000 00000000 b7e69f54 b8ab9ffc 00000000 8098c794
+[ 1704.877930] 9f40: b8ab9b00 8000efc4 b7e68000 00000000 b7e69f6c b7e69f60 80167d6c 80167b28
+[ 1704.877939] 9f60: b7e69f8c b7e69f70 80047d38 80167d60 b7e68000 b7e68010 8000efc4 b7e69fb0
+[ 1704.877949] 9f80: b7e69fac b7e69f90 80012820 80047c84 01155490 011549a8 00000001 00000006
+[ 1704.877957] 9fa0: 00000000 b7e69fb0 8000ee5c 80012790 00000000 353d8c0f 7efc4308 00000000
+[ 1704.877966] 9fc0: 01155490 011549a8 00000001 00000006 00000000 00000000 76cf3ba0 00000003
+[ 1704.877975] 9fe0: 00000000 7efc42e4 0002272f 76e2ed66 60080030 00000003 00000000 00000000
+[ 1704.877998] [<80630ee8>] (__down_interruptible) from [<800704b0>] (down_interruptible+0x5c/0x68)
+[ 1704.878015] [<800704b0>] (down_interruptible) from [<8040f558>] (vchiu_queue_push+0x50/0xd8)
+[ 1704.878032] [<8040f558>] (vchiu_queue_push) from [<803e1ba4>] (send_worker_msg+0x3c/0x54)
+[ 1704.878045] [<803e1ba4>] (send_worker_msg) from [<803e1c9c>] (vc_cma_set_reserve+0xe0/0x1c4)
+[ 1704.878057] [<803e1c9c>] (vc_cma_set_reserve) from [<803e2250>] (vc_cma_release+0x30/0x38)
+[ 1704.878069] [<803e2250>] (vc_cma_release) from [<80167bac>] (__fput+0x90/0x1e0)
+[ 1704.878082] [<80167bac>] (__fput) from [<80167d6c>] (____fput+0x18/0x1c)
+[ 1704.878094] [<80167d6c>] (____fput) from [<80047d38>] (task_work_run+0xc0/0xf8)
+[ 1704.878109] [<80047d38>] (task_work_run) from [<80012820>] (do_work_pending+0x9c/0xc4)
+[ 1704.878123] [<80012820>] (do_work_pending) from [<8000ee5c>] (work_pending+0xc/0x20)
+[ 1704.878133] Code: e50b1034 e3a01000 e50b2030 e580300c (e5823000)
+
+..the fix is to ensure that we have actually initialized the queue before we attempt
+to push any items onto it. This occurs if we do an open() followed by a close() without
+any activity in between.
+
+Signed-off-by: Colin Ian King <colin.king@canonical.com>
+
+vchiq_arm: Sort out the vmalloc case
+
+See: https://github.com/raspberrypi/linux/issues/1055
+
+vchiq: hack: Add include depecated dma include file
+---
+ arch/arm/mach-bcm2708/include/mach/platform.h | 2 +
+ arch/arm/mach-bcm2709/include/mach/platform.h | 2 +
+ drivers/misc/Kconfig | 1 +
+ drivers/misc/Makefile | 1 +
+ drivers/misc/vc04_services/Kconfig | 9 +
+ drivers/misc/vc04_services/Makefile | 14 +
+ .../interface/vchi/connections/connection.h | 328 ++
+ .../interface/vchi/message_drivers/message.h | 204 +
+ drivers/misc/vc04_services/interface/vchi/vchi.h | 378 ++
+ .../misc/vc04_services/interface/vchi/vchi_cfg.h | 224 ++
+ .../interface/vchi/vchi_cfg_internal.h | 71 +
+ .../vc04_services/interface/vchi/vchi_common.h | 175 +
+ .../misc/vc04_services/interface/vchi/vchi_mh.h | 42 +
+ .../misc/vc04_services/interface/vchiq_arm/vchiq.h | 40 +
+ .../vc04_services/interface/vchiq_arm/vchiq_2835.h | 42 +
+ .../interface/vchiq_arm/vchiq_2835_arm.c | 586 +++
+ .../vc04_services/interface/vchiq_arm/vchiq_arm.c | 2903 +++++++++++++++
+ .../vc04_services/interface/vchiq_arm/vchiq_arm.h | 220 ++
+ .../interface/vchiq_arm/vchiq_build_info.h | 37 +
+ .../vc04_services/interface/vchiq_arm/vchiq_cfg.h | 69 +
+ .../interface/vchiq_arm/vchiq_connected.c | 120 +
+ .../interface/vchiq_arm/vchiq_connected.h | 50 +
+ .../vc04_services/interface/vchiq_arm/vchiq_core.c | 3934 ++++++++++++++++++++
+ .../vc04_services/interface/vchiq_arm/vchiq_core.h | 712 ++++
+ .../interface/vchiq_arm/vchiq_debugfs.c | 383 ++
+ .../interface/vchiq_arm/vchiq_debugfs.h | 52 +
+ .../interface/vchiq_arm/vchiq_genversion | 87 +
+ .../vc04_services/interface/vchiq_arm/vchiq_if.h | 189 +
+ .../interface/vchiq_arm/vchiq_ioctl.h | 131 +
+ .../interface/vchiq_arm/vchiq_kern_lib.c | 458 +++
+ .../interface/vchiq_arm/vchiq_killable.h | 69 +
+ .../interface/vchiq_arm/vchiq_memdrv.h | 71 +
+ .../interface/vchiq_arm/vchiq_pagelist.h | 58 +
+ .../vc04_services/interface/vchiq_arm/vchiq_shim.c | 860 +++++
+ .../vc04_services/interface/vchiq_arm/vchiq_util.c | 156 +
+ .../vc04_services/interface/vchiq_arm/vchiq_util.h | 82 +
+ .../interface/vchiq_arm/vchiq_version.c | 59 +
+ 37 files changed, 12819 insertions(+)
+ create mode 100644 drivers/misc/vc04_services/Kconfig
+ create mode 100644 drivers/misc/vc04_services/Makefile
+ create mode 100644 drivers/misc/vc04_services/interface/vchi/connections/connection.h
+ create mode 100644 drivers/misc/vc04_services/interface/vchi/message_drivers/message.h
+ create mode 100644 drivers/misc/vc04_services/interface/vchi/vchi.h
+ create mode 100644 drivers/misc/vc04_services/interface/vchi/vchi_cfg.h
+ create mode 100644 drivers/misc/vc04_services/interface/vchi/vchi_cfg_internal.h
+ create mode 100644 drivers/misc/vc04_services/interface/vchi/vchi_common.h
+ create mode 100644 drivers/misc/vc04_services/interface/vchi/vchi_mh.h
+ create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq.h
+ create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835.h
+ create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
+ create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c
+ create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.h
+ create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_build_info.h
+ create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_cfg.h
+ create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.c
+ create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.h
+ create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c
+ create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.h
+ create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
+ create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_debugfs.h
+ create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_genversion
+ create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_if.h
+ create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_ioctl.h
+ create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
+ create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_killable.h
+ create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_memdrv.h
+ create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_pagelist.h
+ create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c
+ create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.c
+ create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.h
+ create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_version.c
+
+--- a/arch/arm/mach-bcm2708/include/mach/platform.h
++++ b/arch/arm/mach-bcm2708/include/mach/platform.h
+@@ -78,6 +78,8 @@
+ #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 */
++#define ARMCTRL_0_BELL_BASE (ARMCTRL_0_SBM_BASE + 0x40) /* User 0 (ARM)'s Doorbell */
++#define ARMCTRL_0_MAIL0_BASE (ARMCTRL_0_SBM_BASE + 0x80) /* User 0 (ARM)'s Mailbox 0 */
+
+ /*
+ * Watchdog
+--- a/arch/arm/mach-bcm2709/include/mach/platform.h
++++ b/arch/arm/mach-bcm2709/include/mach/platform.h
+@@ -78,6 +78,8 @@
+ #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 */
++#define ARMCTRL_0_BELL_BASE (ARMCTRL_0_SBM_BASE + 0x40) /* User 0 (ARM)'s Doorbell */
++#define ARMCTRL_0_MAIL0_BASE (ARMCTRL_0_SBM_BASE + 0x80) /* User 0 (ARM)'s Mailbox 0 */
+
+ /*
+ * Watchdog
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -533,6 +533,7 @@ source "drivers/misc/lis3lv02d/Kconfig"
+ source "drivers/misc/altera-stapl/Kconfig"
+ source "drivers/misc/mei/Kconfig"
+ source "drivers/misc/vmw_vmci/Kconfig"
++source "drivers/misc/vc04_services/Kconfig"
+ source "drivers/misc/mic/Kconfig"
+ source "drivers/misc/genwqe/Kconfig"
+ source "drivers/misc/echo/Kconfig"
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -51,6 +51,7 @@ obj-$(CONFIG_INTEL_MEI) += mei/
+ obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/
+ obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o
+ obj-$(CONFIG_SRAM) += sram.o
++obj-$(CONFIG_BCM2708_VCHIQ) += vc04_services/
+ obj-y += mic/
+ obj-$(CONFIG_GENWQE) += genwqe/
+ obj-$(CONFIG_ECHO) += echo/
+--- /dev/null
++++ b/drivers/misc/vc04_services/Kconfig
+@@ -0,0 +1,9 @@
++config BCM2708_VCHIQ
++ tristate "Videocore VCHIQ"
++ depends on RASPBERRYPI_FIRMWARE
++ default y
++ help
++ Kernel to VideoCore communication interface for the
++ BCM2708 family of products.
++ Defaults to Y when the Broadcom Videocore services
++ are included in the build, N otherwise.
+--- /dev/null
++++ b/drivers/misc/vc04_services/Makefile
+@@ -0,0 +1,14 @@
++obj-$(CONFIG_BCM2708_VCHIQ) += vchiq.o
++
++vchiq-objs := \
++ interface/vchiq_arm/vchiq_core.o \
++ interface/vchiq_arm/vchiq_arm.o \
++ interface/vchiq_arm/vchiq_kern_lib.o \
++ interface/vchiq_arm/vchiq_2835_arm.o \
++ interface/vchiq_arm/vchiq_debugfs.o \
++ interface/vchiq_arm/vchiq_shim.o \
++ interface/vchiq_arm/vchiq_util.o \
++ interface/vchiq_arm/vchiq_connected.o \
++
++ccflags-y += -DVCOS_VERIFY_BKPTS=1 -Idrivers/misc/vc04_services -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000
++
+--- /dev/null
++++ b/drivers/misc/vc04_services/interface/vchi/connections/connection.h
+@@ -0,0 +1,328 @@
++/**
++ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef CONNECTION_H_
++#define CONNECTION_H_
++
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/semaphore.h>
++
++#include "interface/vchi/vchi_cfg_internal.h"
++#include "interface/vchi/vchi_common.h"
++#include "interface/vchi/message_drivers/message.h"
++
++/******************************************************************************
++ Global defs
++ *****************************************************************************/
++
++// Opaque handle for a connection / service pair
++typedef struct opaque_vchi_connection_connected_service_handle_t *VCHI_CONNECTION_SERVICE_HANDLE_T;
++
++// opaque handle to the connection state information
++typedef struct opaque_vchi_connection_info_t VCHI_CONNECTION_STATE_T;
++
++typedef struct vchi_connection_t VCHI_CONNECTION_T;
++
++
++/******************************************************************************
++ API
++ *****************************************************************************/
++
++// Routine to init a connection with a particular low level driver
++typedef VCHI_CONNECTION_STATE_T * (*VCHI_CONNECTION_INIT_T)( struct vchi_connection_t * connection,
++ const VCHI_MESSAGE_DRIVER_T * driver );
++
++// Routine to control CRC enabling at a connection level
++typedef int32_t (*VCHI_CONNECTION_CRC_CONTROL_T)( VCHI_CONNECTION_STATE_T *state_handle,
++ VCHI_CRC_CONTROL_T control );
++
++// Routine to create a service
++typedef int32_t (*VCHI_CONNECTION_SERVICE_CONNECT_T)( VCHI_CONNECTION_STATE_T *state_handle,
++ int32_t service_id,
++ uint32_t rx_fifo_size,
++ uint32_t tx_fifo_size,
++ int server,
++ VCHI_CALLBACK_T callback,
++ void *callback_param,
++ int32_t want_crc,
++ int32_t want_unaligned_bulk_rx,
++ int32_t want_unaligned_bulk_tx,
++ VCHI_CONNECTION_SERVICE_HANDLE_T *service_handle );
++
++// Routine to close a service
++typedef int32_t (*VCHI_CONNECTION_SERVICE_DISCONNECT_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle );
++
++// Routine to queue a message
++typedef int32_t (*VCHI_CONNECTION_SERVICE_QUEUE_MESSAGE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
++ const void *data,
++ uint32_t data_size,
++ VCHI_FLAGS_T flags,
++ void *msg_handle );
++
++// scatter-gather (vector) message queueing
++typedef int32_t (*VCHI_CONNECTION_SERVICE_QUEUE_MESSAGEV_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
++ VCHI_MSG_VECTOR_T *vector,
++ uint32_t count,
++ VCHI_FLAGS_T flags,
++ void *msg_handle );
++
++// Routine to dequeue a message
++typedef int32_t (*VCHI_CONNECTION_SERVICE_DEQUEUE_MESSAGE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
++ void *data,
++ uint32_t max_data_size_to_read,
++ uint32_t *actual_msg_size,
++ VCHI_FLAGS_T flags );
++
++// Routine to peek at a message
++typedef int32_t (*VCHI_CONNECTION_SERVICE_PEEK_MESSAGE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
++ void **data,
++ uint32_t *msg_size,
++ VCHI_FLAGS_T flags );
++
++// Routine to hold a message
++typedef int32_t (*VCHI_CONNECTION_SERVICE_HOLD_MESSAGE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
++ void **data,
++ uint32_t *msg_size,
++ VCHI_FLAGS_T flags,
++ void **message_handle );
++
++// Routine to initialise a received message iterator
++typedef int32_t (*VCHI_CONNECTION_SERVICE_LOOKAHEAD_MESSAGE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
++ VCHI_MSG_ITER_T *iter,
++ VCHI_FLAGS_T flags );
++
++// Routine to release a held message
++typedef int32_t (*VCHI_CONNECTION_HELD_MSG_RELEASE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
++ void *message_handle );
++
++// Routine to get info on a held message
++typedef int32_t (*VCHI_CONNECTION_HELD_MSG_INFO_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
++ void *message_handle,
++ void **data,
++ int32_t *msg_size,
++ uint32_t *tx_timestamp,
++ uint32_t *rx_timestamp );
++
++// Routine to check whether the iterator has a next message
++typedef int32_t (*VCHI_CONNECTION_MSG_ITER_HAS_NEXT_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service,
++ const VCHI_MSG_ITER_T *iter );
++
++// Routine to advance the iterator
++typedef int32_t (*VCHI_CONNECTION_MSG_ITER_NEXT_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service,
++ VCHI_MSG_ITER_T *iter,
++ void **data,
++ uint32_t *msg_size );
++
++// Routine to remove the last message returned by the iterator
++typedef int32_t (*VCHI_CONNECTION_MSG_ITER_REMOVE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service,
++ VCHI_MSG_ITER_T *iter );
++
++// Routine to hold the last message returned by the iterator
++typedef int32_t (*VCHI_CONNECTION_MSG_ITER_HOLD_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service,
++ VCHI_MSG_ITER_T *iter,
++ void **msg_handle );
++
++// Routine to transmit bulk data
++typedef int32_t (*VCHI_CONNECTION_BULK_QUEUE_TRANSMIT_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
++ const void *data_src,
++ uint32_t data_size,
++ VCHI_FLAGS_T flags,
++ void *bulk_handle );
++
++// Routine to receive data
++typedef int32_t (*VCHI_CONNECTION_BULK_QUEUE_RECEIVE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
++ void *data_dst,
++ uint32_t data_size,
++ VCHI_FLAGS_T flags,
++ void *bulk_handle );
++
++// Routine to report if a server is available
++typedef int32_t (*VCHI_CONNECTION_SERVER_PRESENT)( VCHI_CONNECTION_STATE_T *state, int32_t service_id, int32_t peer_flags );
++
++// Routine to report the number of RX slots available
++typedef int (*VCHI_CONNECTION_RX_SLOTS_AVAILABLE)( const VCHI_CONNECTION_STATE_T *state );
++
++// Routine to report the RX slot size
++typedef uint32_t (*VCHI_CONNECTION_RX_SLOT_SIZE)( const VCHI_CONNECTION_STATE_T *state );
++
++// Callback to indicate that the other side has added a buffer to the rx bulk DMA FIFO
++typedef void (*VCHI_CONNECTION_RX_BULK_BUFFER_ADDED)(VCHI_CONNECTION_STATE_T *state,
++ int32_t service,
++ uint32_t length,
++ MESSAGE_TX_CHANNEL_T channel,
++ uint32_t channel_params,
++ uint32_t data_length,
++ uint32_t data_offset);
++
++// Callback to inform a service that a Xon or Xoff message has been received
++typedef void (*VCHI_CONNECTION_FLOW_CONTROL)(VCHI_CONNECTION_STATE_T *state, int32_t service_id, int32_t xoff);
++
++// Callback to inform a service that a server available reply message has been received
++typedef void (*VCHI_CONNECTION_SERVER_AVAILABLE_REPLY)(VCHI_CONNECTION_STATE_T *state, int32_t service_id, uint32_t flags);
++
++// Callback to indicate that bulk auxiliary messages have arrived
++typedef void (*VCHI_CONNECTION_BULK_AUX_RECEIVED)(VCHI_CONNECTION_STATE_T *state);
++
++// Callback to indicate that bulk auxiliary messages have arrived
++typedef void (*VCHI_CONNECTION_BULK_AUX_TRANSMITTED)(VCHI_CONNECTION_STATE_T *state, void *handle);
++
++// Callback with all the connection info you require
++typedef void (*VCHI_CONNECTION_INFO)(VCHI_CONNECTION_STATE_T *state, uint32_t protocol_version, uint32_t slot_size, uint32_t num_slots, uint32_t min_bulk_size);
++
++// Callback to inform of a disconnect
++typedef void (*VCHI_CONNECTION_DISCONNECT)(VCHI_CONNECTION_STATE_T *state, uint32_t flags);
++
++// Callback to inform of a power control request
++typedef void (*VCHI_CONNECTION_POWER_CONTROL)(VCHI_CONNECTION_STATE_T *state, MESSAGE_TX_CHANNEL_T channel, int32_t enable);
++
++// allocate memory suitably aligned for this connection
++typedef void * (*VCHI_BUFFER_ALLOCATE)(VCHI_CONNECTION_SERVICE_HANDLE_T service_handle, uint32_t * length);
++
++// free memory allocated by buffer_allocate
++typedef void (*VCHI_BUFFER_FREE)(VCHI_CONNECTION_SERVICE_HANDLE_T service_handle, void * address);
++
++
++/******************************************************************************
++ System driver struct
++ *****************************************************************************/
++
++struct opaque_vchi_connection_api_t
++{
++ // Routine to init the connection
++ VCHI_CONNECTION_INIT_T init;
++
++ // Connection-level CRC control
++ VCHI_CONNECTION_CRC_CONTROL_T crc_control;
++
++ // Routine to connect to or create service
++ VCHI_CONNECTION_SERVICE_CONNECT_T service_connect;
++
++ // Routine to disconnect from a service
++ VCHI_CONNECTION_SERVICE_DISCONNECT_T service_disconnect;
++
++ // Routine to queue a message
++ VCHI_CONNECTION_SERVICE_QUEUE_MESSAGE_T service_queue_msg;
++
++ // scatter-gather (vector) message queue
++ VCHI_CONNECTION_SERVICE_QUEUE_MESSAGEV_T service_queue_msgv;
++
++ // Routine to dequeue a message
++ VCHI_CONNECTION_SERVICE_DEQUEUE_MESSAGE_T service_dequeue_msg;
++
++ // Routine to peek at a message
++ VCHI_CONNECTION_SERVICE_PEEK_MESSAGE_T service_peek_msg;
++
++ // Routine to hold a message
++ VCHI_CONNECTION_SERVICE_HOLD_MESSAGE_T service_hold_msg;
++
++ // Routine to initialise a received message iterator
++ VCHI_CONNECTION_SERVICE_LOOKAHEAD_MESSAGE_T service_look_ahead_msg;
++
++ // Routine to release a message
++ VCHI_CONNECTION_HELD_MSG_RELEASE_T held_msg_release;
++
++ // Routine to get information on a held message
++ VCHI_CONNECTION_HELD_MSG_INFO_T held_msg_info;
++
++ // Routine to check for next message on iterator
++ VCHI_CONNECTION_MSG_ITER_HAS_NEXT_T msg_iter_has_next;
++
++ // Routine to get next message on iterator
++ VCHI_CONNECTION_MSG_ITER_NEXT_T msg_iter_next;
++
++ // Routine to remove the last message returned by iterator
++ VCHI_CONNECTION_MSG_ITER_REMOVE_T msg_iter_remove;
++
++ // Routine to hold the last message returned by iterator
++ VCHI_CONNECTION_MSG_ITER_HOLD_T msg_iter_hold;
++
++ // Routine to transmit bulk data
++ VCHI_CONNECTION_BULK_QUEUE_TRANSMIT_T bulk_queue_transmit;
++
++ // Routine to receive data
++ VCHI_CONNECTION_BULK_QUEUE_RECEIVE_T bulk_queue_receive;
++
++ // Routine to report the available servers
++ VCHI_CONNECTION_SERVER_PRESENT server_present;
++
++ // Routine to report the number of RX slots available
++ VCHI_CONNECTION_RX_SLOTS_AVAILABLE connection_rx_slots_available;
++
++ // Routine to report the RX slot size
++ VCHI_CONNECTION_RX_SLOT_SIZE connection_rx_slot_size;
++
++ // Callback to indicate that the other side has added a buffer to the rx bulk DMA FIFO
++ VCHI_CONNECTION_RX_BULK_BUFFER_ADDED rx_bulk_buffer_added;
++
++ // Callback to inform a service that a Xon or Xoff message has been received
++ VCHI_CONNECTION_FLOW_CONTROL flow_control;
++
++ // Callback to inform a service that a server available reply message has been received
++ VCHI_CONNECTION_SERVER_AVAILABLE_REPLY server_available_reply;
++
++ // Callback to indicate that bulk auxiliary messages have arrived
++ VCHI_CONNECTION_BULK_AUX_RECEIVED bulk_aux_received;
++
++ // Callback to indicate that a bulk auxiliary message has been transmitted
++ VCHI_CONNECTION_BULK_AUX_TRANSMITTED bulk_aux_transmitted;
++
++ // Callback to provide information about the connection
++ VCHI_CONNECTION_INFO connection_info;
++
++ // Callback to notify that peer has requested disconnect
++ VCHI_CONNECTION_DISCONNECT disconnect;
++
++ // Callback to notify that peer has requested power change
++ VCHI_CONNECTION_POWER_CONTROL power_control;
++
++ // allocate memory suitably aligned for this connection
++ VCHI_BUFFER_ALLOCATE buffer_allocate;
++
++ // free memory allocated by buffer_allocate
++ VCHI_BUFFER_FREE buffer_free;
++
++};
++
++struct vchi_connection_t {
++ const VCHI_CONNECTION_API_T *api;
++ VCHI_CONNECTION_STATE_T *state;
++#ifdef VCHI_COARSE_LOCKING
++ struct semaphore sem;
++#endif
++};
++
++
++#endif /* CONNECTION_H_ */
++
++/****************************** End of file **********************************/
+--- /dev/null
++++ b/drivers/misc/vc04_services/interface/vchi/message_drivers/message.h
+@@ -0,0 +1,204 @@
++/**
++ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _VCHI_MESSAGE_H_
++#define _VCHI_MESSAGE_H_
++
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/semaphore.h>
++
++#include "interface/vchi/vchi_cfg_internal.h"
++#include "interface/vchi/vchi_common.h"
++
++
++typedef enum message_event_type {
++ MESSAGE_EVENT_NONE,
++ MESSAGE_EVENT_NOP,
++ MESSAGE_EVENT_MESSAGE,
++ MESSAGE_EVENT_SLOT_COMPLETE,
++ MESSAGE_EVENT_RX_BULK_PAUSED,
++ MESSAGE_EVENT_RX_BULK_COMPLETE,
++ MESSAGE_EVENT_TX_COMPLETE,
++ MESSAGE_EVENT_MSG_DISCARDED
++} MESSAGE_EVENT_TYPE_T;
++
++typedef enum vchi_msg_flags
++{
++ VCHI_MSG_FLAGS_NONE = 0x0,
++ VCHI_MSG_FLAGS_TERMINATE_DMA = 0x1
++} VCHI_MSG_FLAGS_T;
++
++typedef enum message_tx_channel
++{
++ MESSAGE_TX_CHANNEL_MESSAGE = 0,
++ MESSAGE_TX_CHANNEL_BULK = 1 // drivers may provide multiple bulk channels, from 1 upwards
++} MESSAGE_TX_CHANNEL_T;
++
++// Macros used for cycling through bulk channels
++#define MESSAGE_TX_CHANNEL_BULK_PREV(c) (MESSAGE_TX_CHANNEL_BULK+((c)-MESSAGE_TX_CHANNEL_BULK+VCHI_MAX_BULK_TX_CHANNELS_PER_CONNECTION-1)%VCHI_MAX_BULK_TX_CHANNELS_PER_CONNECTION)
++#define MESSAGE_TX_CHANNEL_BULK_NEXT(c) (MESSAGE_TX_CHANNEL_BULK+((c)-MESSAGE_TX_CHANNEL_BULK+1)%VCHI_MAX_BULK_TX_CHANNELS_PER_CONNECTION)
++
++typedef enum message_rx_channel
++{
++ MESSAGE_RX_CHANNEL_MESSAGE = 0,
++ MESSAGE_RX_CHANNEL_BULK = 1 // drivers may provide multiple bulk channels, from 1 upwards
++} MESSAGE_RX_CHANNEL_T;
++
++// Message receive slot information
++typedef struct rx_msg_slot_info {
++
++ struct rx_msg_slot_info *next;
++ //struct slot_info *prev;
++#if !defined VCHI_COARSE_LOCKING
++ struct semaphore sem;
++#endif
++
++ uint8_t *addr; // base address of slot
++ uint32_t len; // length of slot in bytes
++
++ uint32_t write_ptr; // hardware causes this to advance
++ uint32_t read_ptr; // this module does the reading
++ int active; // is this slot in the hardware dma fifo?
++ uint32_t msgs_parsed; // count how many messages are in this slot
++ uint32_t msgs_released; // how many messages have been released
++ void *state; // connection state information
++ uint8_t ref_count[VCHI_MAX_SERVICES_PER_CONNECTION]; // reference count for slots held by services
++} RX_MSG_SLOTINFO_T;
++
++// The message driver no longer needs to know about the fields of RX_BULK_SLOTINFO_T - sort this out.
++// In particular, it mustn't use addr and len - they're the client buffer, but the message
++// driver will be tasked with sending the aligned core section.
++typedef struct rx_bulk_slotinfo_t {
++ struct rx_bulk_slotinfo_t *next;
++
++ struct semaphore *blocking;
++
++ // needed by DMA
++ void *addr;
++ uint32_t len;
++
++ // needed for the callback
++ void *service;
++ void *handle;
++ VCHI_FLAGS_T flags;
++} RX_BULK_SLOTINFO_T;
++
++
++/* ----------------------------------------------------------------------
++ * each connection driver will have a pool of the following struct.
++ *
++ * the pool will be managed by vchi_qman_*
++ * this means there will be multiple queues (single linked lists)
++ * a given struct message_info will be on exactly one of these queues
++ * at any one time
++ * -------------------------------------------------------------------- */
++typedef struct rx_message_info {
++
++ struct message_info *next;
++ //struct message_info *prev;
++
++ uint8_t *addr;
++ uint32_t len;
++ RX_MSG_SLOTINFO_T *slot; // points to whichever slot contains this message
++ uint32_t tx_timestamp;
++ uint32_t rx_timestamp;
++
++} RX_MESSAGE_INFO_T;
++
++typedef struct {
++ MESSAGE_EVENT_TYPE_T type;
++
++ struct {
++ // for messages
++ void *addr; // address of message
++ uint16_t slot_delta; // whether this message indicated slot delta
++ uint32_t len; // length of message
++ RX_MSG_SLOTINFO_T *slot; // slot this message is in
++ int32_t service; // service id this message is destined for
++ uint32_t tx_timestamp; // timestamp from the header
++ uint32_t rx_timestamp; // timestamp when we parsed it
++ } message;
++
++ // FIXME: cleanup slot reporting...
++ RX_MSG_SLOTINFO_T *rx_msg;
++ RX_BULK_SLOTINFO_T *rx_bulk;
++ void *tx_handle;
++ MESSAGE_TX_CHANNEL_T tx_channel;
++
++} MESSAGE_EVENT_T;
++
++
++// callbacks
++typedef void VCHI_MESSAGE_DRIVER_EVENT_CALLBACK_T( void *state );
++
++typedef struct {
++ VCHI_MESSAGE_DRIVER_EVENT_CALLBACK_T *event_callback;
++} VCHI_MESSAGE_DRIVER_OPEN_T;
++
++
++// handle to this instance of message driver (as returned by ->open)
++typedef struct opaque_mhandle_t *VCHI_MDRIVER_HANDLE_T;
++
++struct opaque_vchi_message_driver_t {
++ VCHI_MDRIVER_HANDLE_T *(*open)( VCHI_MESSAGE_DRIVER_OPEN_T *params, void *state );
++ int32_t (*suspending)( VCHI_MDRIVER_HANDLE_T *handle );
++ int32_t (*resumed)( VCHI_MDRIVER_HANDLE_T *handle );
++ int32_t (*power_control)( VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_TX_CHANNEL_T, int32_t enable );
++ int32_t (*add_msg_rx_slot)( VCHI_MDRIVER_HANDLE_T *handle, RX_MSG_SLOTINFO_T *slot ); // rx message
++ int32_t (*add_bulk_rx)( VCHI_MDRIVER_HANDLE_T *handle, void *data, uint32_t len, RX_BULK_SLOTINFO_T *slot ); // rx data (bulk)
++ int32_t (*send)( VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_TX_CHANNEL_T channel, const void *data, uint32_t len, VCHI_MSG_FLAGS_T flags, void *send_handle ); // tx (message & bulk)
++ void (*next_event)( VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_EVENT_T *event ); // get the next event from message_driver
++ int32_t (*enable)( VCHI_MDRIVER_HANDLE_T *handle );
++ int32_t (*form_message)( VCHI_MDRIVER_HANDLE_T *handle, int32_t service_id, VCHI_MSG_VECTOR_T *vector, uint32_t count, void
++ *address, uint32_t length_avail, uint32_t max_total_length, int32_t pad_to_fill, int32_t allow_partial );
++
++ int32_t (*update_message)( VCHI_MDRIVER_HANDLE_T *handle, void *dest, int16_t *slot_count );
++ int32_t (*buffer_aligned)( VCHI_MDRIVER_HANDLE_T *handle, int tx, int uncached, const void *address, const uint32_t length );
++ void * (*allocate_buffer)( VCHI_MDRIVER_HANDLE_T *handle, uint32_t *length );
++ void (*free_buffer)( VCHI_MDRIVER_HANDLE_T *handle, void *address );
++ int (*rx_slot_size)( VCHI_MDRIVER_HANDLE_T *handle, int msg_size );
++ int (*tx_slot_size)( VCHI_MDRIVER_HANDLE_T *handle, int msg_size );
++
++ int32_t (*tx_supports_terminate)( const VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_TX_CHANNEL_T channel );
++ uint32_t (*tx_bulk_chunk_size)( const VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_TX_CHANNEL_T channel );
++ int (*tx_alignment)( const VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_TX_CHANNEL_T channel );
++ int (*rx_alignment)( const VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_RX_CHANNEL_T channel );
++ void (*form_bulk_aux)( VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_TX_CHANNEL_T channel, const void *data, uint32_t len, uint32_t chunk_size, const void **aux_data, int32_t *aux_len );
++ void (*debug)( VCHI_MDRIVER_HANDLE_T *handle );
++};
++
++
++#endif // _VCHI_MESSAGE_H_
++
++/****************************** End of file ***********************************/
+--- /dev/null
++++ b/drivers/misc/vc04_services/interface/vchi/vchi.h
+@@ -0,0 +1,378 @@
++/**
++ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef VCHI_H_
++#define VCHI_H_
++
++#include "interface/vchi/vchi_cfg.h"
++#include "interface/vchi/vchi_common.h"
++#include "interface/vchi/connections/connection.h"
++#include "vchi_mh.h"
++
++
++/******************************************************************************
++ Global defs
++ *****************************************************************************/
++
++#define VCHI_BULK_ROUND_UP(x) ((((unsigned long)(x))+VCHI_BULK_ALIGN-1) & ~(VCHI_BULK_ALIGN-1))
++#define VCHI_BULK_ROUND_DOWN(x) (((unsigned long)(x)) & ~(VCHI_BULK_ALIGN-1))
++#define VCHI_BULK_ALIGN_NBYTES(x) (VCHI_BULK_ALIGNED(x) ? 0 : (VCHI_BULK_ALIGN - ((unsigned long)(x) & (VCHI_BULK_ALIGN-1))))
++
++#ifdef USE_VCHIQ_ARM
++#define VCHI_BULK_ALIGNED(x) 1
++#else
++#define VCHI_BULK_ALIGNED(x) (((unsigned long)(x) & (VCHI_BULK_ALIGN-1)) == 0)
++#endif
++
++struct vchi_version {
++ uint32_t version;
++ uint32_t version_min;
++};
++#define VCHI_VERSION(v_) { v_, v_ }
++#define VCHI_VERSION_EX(v_, m_) { v_, m_ }
++
++typedef enum
++{
++ VCHI_VEC_POINTER,
++ VCHI_VEC_HANDLE,
++ VCHI_VEC_LIST
++} VCHI_MSG_VECTOR_TYPE_T;
++
++typedef struct vchi_msg_vector_ex {
++
++ VCHI_MSG_VECTOR_TYPE_T type;
++ union
++ {
++ // a memory handle
++ struct
++ {
++ VCHI_MEM_HANDLE_T handle;
++ uint32_t offset;
++ int32_t vec_len;
++ } handle;
++
++ // an ordinary data pointer
++ struct
++ {
++ const void *vec_base;
++ int32_t vec_len;
++ } ptr;
++
++ // a nested vector list
++ struct
++ {
++ struct vchi_msg_vector_ex *vec;
++ uint32_t vec_len;
++ } list;
++ } u;
++} VCHI_MSG_VECTOR_EX_T;
++
++
++// Construct an entry in a msg vector for a pointer (p) of length (l)
++#define VCHI_VEC_POINTER(p,l) VCHI_VEC_POINTER, { { (VCHI_MEM_HANDLE_T)(p), (l) } }
++
++// Construct an entry in a msg vector for a message handle (h), starting at offset (o) of length (l)
++#define VCHI_VEC_HANDLE(h,o,l) VCHI_VEC_HANDLE, { { (h), (o), (l) } }
++
++// Macros to manipulate 'FOURCC' values
++#define MAKE_FOURCC(x) ((int32_t)( (x[0] << 24) | (x[1] << 16) | (x[2] << 8) | x[3] ))
++#define FOURCC_TO_CHAR(x) (x >> 24) & 0xFF,(x >> 16) & 0xFF,(x >> 8) & 0xFF, x & 0xFF
++
++
++// Opaque service information
++struct opaque_vchi_service_t;
++
++// Descriptor for a held message. Allocated by client, initialised by vchi_msg_hold,
++// vchi_msg_iter_hold or vchi_msg_iter_hold_next. Fields are for internal VCHI use only.
++typedef struct
++{
++ struct opaque_vchi_service_t *service;
++ void *message;
++} VCHI_HELD_MSG_T;
++
++
++
++// structure used to provide the information needed to open a server or a client
++typedef struct {
++ struct vchi_version version;
++ int32_t service_id;
++ VCHI_CONNECTION_T *connection;
++ uint32_t rx_fifo_size;
++ uint32_t tx_fifo_size;
++ VCHI_CALLBACK_T callback;
++ void *callback_param;
++ /* client intends to receive bulk transfers of
++ odd lengths or into unaligned buffers */
++ int32_t want_unaligned_bulk_rx;
++ /* client intends to transmit bulk transfers of
++ odd lengths or out of unaligned buffers */
++ int32_t want_unaligned_bulk_tx;
++ /* client wants to check CRCs on (bulk) xfers.
++ Only needs to be set at 1 end - will do both directions. */
++ int32_t want_crc;
++} SERVICE_CREATION_T;
++
++// Opaque handle for a VCHI instance
++typedef struct opaque_vchi_instance_handle_t *VCHI_INSTANCE_T;
++
++// Opaque handle for a server or client
++typedef struct opaque_vchi_service_handle_t *VCHI_SERVICE_HANDLE_T;
++
++// Service registration & startup
++typedef void (*VCHI_SERVICE_INIT)(VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections);
++
++typedef struct service_info_tag {
++ const char * const vll_filename; /* VLL to load to start this service. This is an empty string if VLL is "static" */
++ VCHI_SERVICE_INIT init; /* Service initialisation function */
++ void *vll_handle; /* VLL handle; NULL when unloaded or a "static VLL" in build */
++} SERVICE_INFO_T;
++
++/******************************************************************************
++ Global funcs - implementation is specific to which side you are on (local / remote)
++ *****************************************************************************/
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++extern /*@observer@*/ VCHI_CONNECTION_T * vchi_create_connection( const VCHI_CONNECTION_API_T * function_table,
++ const VCHI_MESSAGE_DRIVER_T * low_level);
++
++
++// Routine used to initialise the vchi on both local + remote connections
++extern int32_t vchi_initialise( VCHI_INSTANCE_T *instance_handle );
++
++extern int32_t vchi_exit( void );
++
++extern int32_t vchi_connect( VCHI_CONNECTION_T **connections,
++ const uint32_t num_connections,
++ VCHI_INSTANCE_T instance_handle );
++
++//When this is called, ensure that all services have no data pending.
++//Bulk transfers can remain 'queued'
++extern int32_t vchi_disconnect( VCHI_INSTANCE_T instance_handle );
++
++// Global control over bulk CRC checking
++extern int32_t vchi_crc_control( VCHI_CONNECTION_T *connection,
++ VCHI_CRC_CONTROL_T control );
++
++// helper functions
++extern void * vchi_allocate_buffer(VCHI_SERVICE_HANDLE_T handle, uint32_t *length);
++extern void vchi_free_buffer(VCHI_SERVICE_HANDLE_T handle, void *address);
++extern uint32_t vchi_current_time(VCHI_INSTANCE_T instance_handle);
++
++
++/******************************************************************************
++ Global service API
++ *****************************************************************************/
++// Routine to create a named service
++extern int32_t vchi_service_create( VCHI_INSTANCE_T instance_handle,
++ SERVICE_CREATION_T *setup,
++ VCHI_SERVICE_HANDLE_T *handle );
++
++// Routine to destory a service
++extern int32_t vchi_service_destroy( const VCHI_SERVICE_HANDLE_T handle );
++
++// Routine to open a named service
++extern int32_t vchi_service_open( VCHI_INSTANCE_T instance_handle,
++ SERVICE_CREATION_T *setup,
++ VCHI_SERVICE_HANDLE_T *handle);
++
++extern int32_t vchi_get_peer_version( const VCHI_SERVICE_HANDLE_T handle,
++ short *peer_version );
++
++// Routine to close a named service
++extern int32_t vchi_service_close( const VCHI_SERVICE_HANDLE_T handle );
++
++// Routine to increment ref count on a named service
++extern int32_t vchi_service_use( const VCHI_SERVICE_HANDLE_T handle );
++
++// Routine to decrement ref count on a named service
++extern int32_t vchi_service_release( const VCHI_SERVICE_HANDLE_T handle );
++
++// Routine to set a control option for a named service
++extern int32_t vchi_service_set_option( const VCHI_SERVICE_HANDLE_T handle,
++ VCHI_SERVICE_OPTION_T option,
++ int value);
++
++// Routine to send a message across a service
++extern int32_t vchi_msg_queue( VCHI_SERVICE_HANDLE_T handle,
++ const void *data,
++ uint32_t data_size,
++ VCHI_FLAGS_T flags,
++ void *msg_handle );
++
++// scatter-gather (vector) and send message
++int32_t vchi_msg_queuev_ex( VCHI_SERVICE_HANDLE_T handle,
++ VCHI_MSG_VECTOR_EX_T *vector,
++ uint32_t count,
++ VCHI_FLAGS_T flags,
++ void *msg_handle );
++
++// legacy scatter-gather (vector) and send message, only handles pointers
++int32_t vchi_msg_queuev( VCHI_SERVICE_HANDLE_T handle,
++ VCHI_MSG_VECTOR_T *vector,
++ uint32_t count,
++ VCHI_FLAGS_T flags,
++ void *msg_handle );
++
++// Routine to receive a msg from a service
++// Dequeue is equivalent to hold, copy into client buffer, release
++extern int32_t vchi_msg_dequeue( VCHI_SERVICE_HANDLE_T handle,
++ void *data,
++ uint32_t max_data_size_to_read,
++ uint32_t *actual_msg_size,
++ VCHI_FLAGS_T flags );
++
++// Routine to look at a message in place.
++// The message is not dequeued, so a subsequent call to peek or dequeue
++// will return the same message.
++extern int32_t vchi_msg_peek( VCHI_SERVICE_HANDLE_T handle,
++ void **data,
++ uint32_t *msg_size,
++ VCHI_FLAGS_T flags );
++
++// Routine to remove a message after it has been read in place with peek
++// The first message on the queue is dequeued.
++extern int32_t vchi_msg_remove( VCHI_SERVICE_HANDLE_T handle );
++
++// Routine to look at a message in place.
++// The message is dequeued, so the caller is left holding it; the descriptor is
++// filled in and must be released when the user has finished with the message.
++extern int32_t vchi_msg_hold( VCHI_SERVICE_HANDLE_T handle,
++ void **data, // } may be NULL, as info can be
++ uint32_t *msg_size, // } obtained from HELD_MSG_T
++ VCHI_FLAGS_T flags,
++ VCHI_HELD_MSG_T *message_descriptor );
++
++// Initialise an iterator to look through messages in place
++extern int32_t vchi_msg_look_ahead( VCHI_SERVICE_HANDLE_T handle,
++ VCHI_MSG_ITER_T *iter,
++ VCHI_FLAGS_T flags );
++
++/******************************************************************************
++ Global service support API - operations on held messages and message iterators
++ *****************************************************************************/
++
++// Routine to get the address of a held message
++extern void *vchi_held_msg_ptr( const VCHI_HELD_MSG_T *message );
++
++// Routine to get the size of a held message
++extern int32_t vchi_held_msg_size( const VCHI_HELD_MSG_T *message );
++
++// Routine to get the transmit timestamp as written into the header by the peer
++extern uint32_t vchi_held_msg_tx_timestamp( const VCHI_HELD_MSG_T *message );
++
++// Routine to get the reception timestamp, written as we parsed the header
++extern uint32_t vchi_held_msg_rx_timestamp( const VCHI_HELD_MSG_T *message );
++
++// Routine to release a held message after it has been processed
++extern int32_t vchi_held_msg_release( VCHI_HELD_MSG_T *message );
++
++// Indicates whether the iterator has a next message.
++extern int32_t vchi_msg_iter_has_next( const VCHI_MSG_ITER_T *iter );
++
++// Return the pointer and length for the next message and advance the iterator.
++extern int32_t vchi_msg_iter_next( VCHI_MSG_ITER_T *iter,
++ void **data,
++ uint32_t *msg_size );
++
++// Remove the last message returned by vchi_msg_iter_next.
++// Can only be called once after each call to vchi_msg_iter_next.
++extern int32_t vchi_msg_iter_remove( VCHI_MSG_ITER_T *iter );
++
++// Hold the last message returned by vchi_msg_iter_next.
++// Can only be called once after each call to vchi_msg_iter_next.
++extern int32_t vchi_msg_iter_hold( VCHI_MSG_ITER_T *iter,
++ VCHI_HELD_MSG_T *message );
++
++// Return information for the next message, and hold it, advancing the iterator.
++extern int32_t vchi_msg_iter_hold_next( VCHI_MSG_ITER_T *iter,
++ void **data, // } may be NULL
++ uint32_t *msg_size, // }
++ VCHI_HELD_MSG_T *message );
++
++
++/******************************************************************************
++ Global bulk API
++ *****************************************************************************/
++
++// Routine to prepare interface for a transfer from the other side
++extern int32_t vchi_bulk_queue_receive( VCHI_SERVICE_HANDLE_T handle,
++ void *data_dst,
++ uint32_t data_size,
++ VCHI_FLAGS_T flags,
++ void *transfer_handle );
++
++
++// Prepare interface for a transfer from the other side into relocatable memory.
++int32_t vchi_bulk_queue_receive_reloc( const VCHI_SERVICE_HANDLE_T handle,
++ VCHI_MEM_HANDLE_T h_dst,
++ uint32_t offset,
++ uint32_t data_size,
++ const VCHI_FLAGS_T flags,
++ void * const bulk_handle );
++
++// Routine to queue up data ready for transfer to the other (once they have signalled they are ready)
++extern int32_t vchi_bulk_queue_transmit( VCHI_SERVICE_HANDLE_T handle,
++ const void *data_src,
++ uint32_t data_size,
++ VCHI_FLAGS_T flags,
++ void *transfer_handle );
++
++
++/******************************************************************************
++ Configuration plumbing
++ *****************************************************************************/
++
++// function prototypes for the different mid layers (the state info gives the different physical connections)
++extern const VCHI_CONNECTION_API_T *single_get_func_table( void );
++//extern const VCHI_CONNECTION_API_T *local_server_get_func_table( void );
++//extern const VCHI_CONNECTION_API_T *local_client_get_func_table( void );
++
++// declare all message drivers here
++const VCHI_MESSAGE_DRIVER_T *vchi_mphi_message_driver_func_table( void );
++
++#ifdef __cplusplus
++}
++#endif
++
++extern int32_t vchi_bulk_queue_transmit_reloc( VCHI_SERVICE_HANDLE_T handle,
++ VCHI_MEM_HANDLE_T h_src,
++ uint32_t offset,
++ uint32_t data_size,
++ VCHI_FLAGS_T flags,
++ void *transfer_handle );
++#endif /* VCHI_H_ */
++
++/****************************** End of file **********************************/
+--- /dev/null
++++ b/drivers/misc/vc04_services/interface/vchi/vchi_cfg.h
+@@ -0,0 +1,224 @@
++/**
++ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef VCHI_CFG_H_
++#define VCHI_CFG_H_
++
++/****************************************************************************************
++ * Defines in this first section are part of the VCHI API and may be examined by VCHI
++ * services.
++ ***************************************************************************************/
++
++/* Required alignment of base addresses for bulk transfer, if unaligned transfers are not enabled */
++/* Really determined by the message driver, and should be available from a run-time call. */
++#ifndef VCHI_BULK_ALIGN
++# if __VCCOREVER__ >= 0x04000000
++# define VCHI_BULK_ALIGN 32 // Allows for the need to do cache cleans
++# else
++# define VCHI_BULK_ALIGN 16
++# endif
++#endif
++
++/* Required length multiple for bulk transfers, if unaligned transfers are not enabled */
++/* May be less than or greater than VCHI_BULK_ALIGN */
++/* Really determined by the message driver, and should be available from a run-time call. */
++#ifndef VCHI_BULK_GRANULARITY
++# if __VCCOREVER__ >= 0x04000000
++# define VCHI_BULK_GRANULARITY 32 // Allows for the need to do cache cleans
++# else
++# define VCHI_BULK_GRANULARITY 16
++# endif
++#endif
++
++/* The largest possible message to be queued with vchi_msg_queue. */
++#ifndef VCHI_MAX_MSG_SIZE
++# if defined VCHI_LOCAL_HOST_PORT
++# define VCHI_MAX_MSG_SIZE 16384 // makes file transfers fast, but should they be using bulk?
++# else
++# define VCHI_MAX_MSG_SIZE 4096 // NOTE: THIS MUST BE LARGER THAN OR EQUAL TO THE SIZE OF THE KHRONOS MERGE BUFFER!!
++# endif
++#endif
++
++/******************************************************************************************
++ * Defines below are system configuration options, and should not be used by VCHI services.
++ *****************************************************************************************/
++
++/* How many connections can we support? A localhost implementation uses 2 connections,
++ * 1 for host-app, 1 for VMCS, and these are hooked together by a loopback MPHI VCFW
++ * driver. */
++#ifndef VCHI_MAX_NUM_CONNECTIONS
++# define VCHI_MAX_NUM_CONNECTIONS 3
++#endif
++
++/* How many services can we open per connection? Extending this doesn't cost processing time, just a small
++ * amount of static memory. */
++#ifndef VCHI_MAX_SERVICES_PER_CONNECTION
++# define VCHI_MAX_SERVICES_PER_CONNECTION 36
++#endif
++
++/* Adjust if using a message driver that supports more logical TX channels */
++#ifndef VCHI_MAX_BULK_TX_CHANNELS_PER_CONNECTION
++# define VCHI_MAX_BULK_TX_CHANNELS_PER_CONNECTION 9 // 1 MPHI + 8 CCP2 logical channels
++#endif
++
++/* Adjust if using a message driver that supports more logical RX channels */
++#ifndef VCHI_MAX_BULK_RX_CHANNELS_PER_CONNECTION
++# define VCHI_MAX_BULK_RX_CHANNELS_PER_CONNECTION 1 // 1 MPHI
++#endif
++
++/* How many receive slots do we use. This times VCHI_MAX_MSG_SIZE gives the effective
++ * receive queue space, less message headers. */
++#ifndef VCHI_NUM_READ_SLOTS
++# if defined(VCHI_LOCAL_HOST_PORT)
++# define VCHI_NUM_READ_SLOTS 4
++# else
++# define VCHI_NUM_READ_SLOTS 48
++# endif
++#endif
++
++/* Do we utilise overrun facility for receive message slots? Can aid peer transmit
++ * performance. Only define on VideoCore end, talking to host.
++ */
++//#define VCHI_MSG_RX_OVERRUN
++
++/* How many transmit slots do we use. Generally don't need many, as the hardware driver
++ * underneath VCHI will usually have its own buffering. */
++#ifndef VCHI_NUM_WRITE_SLOTS
++# define VCHI_NUM_WRITE_SLOTS 4
++#endif
++
++/* If a service has held or queued received messages in VCHI_XOFF_THRESHOLD or more slots,
++ * then it's taking up too much buffer space, and the peer service will be told to stop
++ * transmitting with an XOFF message. For this to be effective, the VCHI_NUM_READ_SLOTS
++ * needs to be considerably bigger than VCHI_NUM_WRITE_SLOTS, or the transmit latency
++ * is too high. */
++#ifndef VCHI_XOFF_THRESHOLD
++# define VCHI_XOFF_THRESHOLD (VCHI_NUM_READ_SLOTS / 2)
++#endif
++
++/* After we've sent an XOFF, the peer will be told to resume transmission once the local
++ * service has dequeued/released enough messages that it's now occupying
++ * VCHI_XON_THRESHOLD slots or fewer. */
++#ifndef VCHI_XON_THRESHOLD
++# define VCHI_XON_THRESHOLD (VCHI_NUM_READ_SLOTS / 4)
++#endif
++
++/* A size below which a bulk transfer omits the handshake completely and always goes
++ * via the message channel, if bulk auxiliary is being sent on that service. (The user
++ * can guarantee this by enabling unaligned transmits).
++ * Not API. */
++#ifndef VCHI_MIN_BULK_SIZE
++# define VCHI_MIN_BULK_SIZE ( VCHI_MAX_MSG_SIZE / 2 < 4096 ? VCHI_MAX_MSG_SIZE / 2 : 4096 )
++#endif
++
++/* Maximum size of bulk transmission chunks, for each interface type. A trade-off between
++ * speed and latency; the smaller the chunk size the better change of messages and other
++ * bulk transmissions getting in when big bulk transfers are happening. Set to 0 to not
++ * break transmissions into chunks.
++ */
++#ifndef VCHI_MAX_BULK_CHUNK_SIZE_MPHI
++# define VCHI_MAX_BULK_CHUNK_SIZE_MPHI (16 * 1024)
++#endif
++
++/* NB Chunked CCP2 transmissions violate the letter of the CCP2 spec by using "JPEG8" mode
++ * with multiple-line frames. Only use if the receiver can cope. */
++#ifndef VCHI_MAX_BULK_CHUNK_SIZE_CCP2
++# define VCHI_MAX_BULK_CHUNK_SIZE_CCP2 0
++#endif
++
++/* How many TX messages can we have pending in our transmit slots. Once exhausted,
++ * vchi_msg_queue will be blocked. */
++#ifndef VCHI_TX_MSG_QUEUE_SIZE
++# define VCHI_TX_MSG_QUEUE_SIZE 256
++#endif
++
++/* How many RX messages can we have parsed in the receive slots. Once exhausted, parsing
++ * will be suspended until older messages are dequeued/released. */
++#ifndef VCHI_RX_MSG_QUEUE_SIZE
++# define VCHI_RX_MSG_QUEUE_SIZE 256
++#endif
++
++/* Really should be able to cope if we run out of received message descriptors, by
++ * suspending parsing as the comment above says, but we don't. This sweeps the issue
++ * under the carpet. */
++#if VCHI_RX_MSG_QUEUE_SIZE < (VCHI_MAX_MSG_SIZE/16 + 1) * VCHI_NUM_READ_SLOTS
++# undef VCHI_RX_MSG_QUEUE_SIZE
++# define VCHI_RX_MSG_QUEUE_SIZE (VCHI_MAX_MSG_SIZE/16 + 1) * VCHI_NUM_READ_SLOTS
++#endif
++
++/* How many bulk transmits can we have pending. Once exhausted, vchi_bulk_queue_transmit
++ * will be blocked. */
++#ifndef VCHI_TX_BULK_QUEUE_SIZE
++# define VCHI_TX_BULK_QUEUE_SIZE 64
++#endif
++
++/* How many bulk receives can we have pending. Once exhausted, vchi_bulk_queue_receive
++ * will be blocked. */
++#ifndef VCHI_RX_BULK_QUEUE_SIZE
++# define VCHI_RX_BULK_QUEUE_SIZE 64
++#endif
++
++/* A limit on how many outstanding bulk requests we expect the peer to give us. If
++ * the peer asks for more than this, VCHI will fail and assert. The number is determined
++ * by the peer's hardware - it's the number of outstanding requests that can be queued
++ * on all bulk channels. VC3's MPHI peripheral allows 16. */
++#ifndef VCHI_MAX_PEER_BULK_REQUESTS
++# define VCHI_MAX_PEER_BULK_REQUESTS 32
++#endif
++
++/* Define VCHI_CCP2TX_MANUAL_POWER if the host tells us when to turn the CCP2
++ * transmitter on and off.
++ */
++/*#define VCHI_CCP2TX_MANUAL_POWER*/
++
++#ifndef VCHI_CCP2TX_MANUAL_POWER
++
++/* Timeout (in milliseconds) for putting the CCP2TX interface into IDLE state. Set
++ * negative for no IDLE.
++ */
++# ifndef VCHI_CCP2TX_IDLE_TIMEOUT
++# define VCHI_CCP2TX_IDLE_TIMEOUT 5
++# endif
++
++/* Timeout (in milliseconds) for putting the CCP2TX interface into OFF state. Set
++ * negative for no OFF.
++ */
++# ifndef VCHI_CCP2TX_OFF_TIMEOUT
++# define VCHI_CCP2TX_OFF_TIMEOUT 1000
++# endif
++
++#endif /* VCHI_CCP2TX_MANUAL_POWER */
++
++#endif /* VCHI_CFG_H_ */
++
++/****************************** End of file **********************************/
+--- /dev/null
++++ b/drivers/misc/vc04_services/interface/vchi/vchi_cfg_internal.h
+@@ -0,0 +1,71 @@
++/**
++ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef VCHI_CFG_INTERNAL_H_
++#define VCHI_CFG_INTERNAL_H_
++
++/****************************************************************************************
++ * Control optimisation attempts.
++ ***************************************************************************************/
++
++// Don't use lots of short-term locks - use great long ones, reducing the overall locks-per-second
++#define VCHI_COARSE_LOCKING
++
++// Avoid lock then unlock on exit from blocking queue operations (msg tx, bulk rx/tx)
++// (only relevant if VCHI_COARSE_LOCKING)
++#define VCHI_ELIDE_BLOCK_EXIT_LOCK
++
++// Avoid lock on non-blocking peek
++// (only relevant if VCHI_COARSE_LOCKING)
++#define VCHI_AVOID_PEEK_LOCK
++
++// Use one slot-handler thread per connection, rather than 1 thread dealing with all connections in rotation.
++#define VCHI_MULTIPLE_HANDLER_THREADS
++
++// Put free descriptors onto the head of the free queue, rather than the tail, so that we don't thrash
++// our way through the pool of descriptors.
++#define VCHI_PUSH_FREE_DESCRIPTORS_ONTO_HEAD
++
++// Don't issue a MSG_AVAILABLE callback for every single message. Possibly only safe if VCHI_COARSE_LOCKING.
++#define VCHI_FEWER_MSG_AVAILABLE_CALLBACKS
++
++// Don't use message descriptors for TX messages that don't need them
++#define VCHI_MINIMISE_TX_MSG_DESCRIPTORS
++
++// Nano-locks for multiqueue
++//#define VCHI_MQUEUE_NANOLOCKS
++
++// Lock-free(er) dequeuing
++//#define VCHI_RX_NANOLOCKS
++
++#endif /*VCHI_CFG_INTERNAL_H_*/
+--- /dev/null
++++ b/drivers/misc/vc04_services/interface/vchi/vchi_common.h
+@@ -0,0 +1,175 @@
++/**
++ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef VCHI_COMMON_H_
++#define VCHI_COMMON_H_
++
++
++//flags used when sending messages (must be bitmapped)
++typedef enum
++{
++ VCHI_FLAGS_NONE = 0x0,
++ VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE = 0x1, // waits for message to be received, or sent (NB. not the same as being seen on other side)
++ VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE = 0x2, // run a callback when message sent
++ VCHI_FLAGS_BLOCK_UNTIL_QUEUED = 0x4, // return once the transfer is in a queue ready to go
++ VCHI_FLAGS_ALLOW_PARTIAL = 0x8,
++ VCHI_FLAGS_BLOCK_UNTIL_DATA_READ = 0x10,
++ VCHI_FLAGS_CALLBACK_WHEN_DATA_READ = 0x20,
++
++ VCHI_FLAGS_ALIGN_SLOT = 0x000080, // internal use only
++ VCHI_FLAGS_BULK_AUX_QUEUED = 0x010000, // internal use only
++ VCHI_FLAGS_BULK_AUX_COMPLETE = 0x020000, // internal use only
++ VCHI_FLAGS_BULK_DATA_QUEUED = 0x040000, // internal use only
++ VCHI_FLAGS_BULK_DATA_COMPLETE = 0x080000, // internal use only
++ VCHI_FLAGS_INTERNAL = 0xFF0000
++} VCHI_FLAGS_T;
++
++// constants for vchi_crc_control()
++typedef enum {
++ VCHI_CRC_NOTHING = -1,
++ VCHI_CRC_PER_SERVICE = 0,
++ VCHI_CRC_EVERYTHING = 1,
++} VCHI_CRC_CONTROL_T;
++
++//callback reasons when an event occurs on a service
++typedef enum
++{
++ VCHI_CALLBACK_REASON_MIN,
++
++ //This indicates that there is data available
++ //handle is the msg id that was transmitted with the data
++ // When a message is received and there was no FULL message available previously, send callback
++ // Tasks get kicked by the callback, reset their event and try and read from the fifo until it fails
++ VCHI_CALLBACK_MSG_AVAILABLE,
++ VCHI_CALLBACK_MSG_SENT,
++ VCHI_CALLBACK_MSG_SPACE_AVAILABLE, // XXX not yet implemented
++
++ // This indicates that a transfer from the other side has completed
++ VCHI_CALLBACK_BULK_RECEIVED,
++ //This indicates that data queued up to be sent has now gone
++ //handle is the msg id that was used when sending the data
++ VCHI_CALLBACK_BULK_SENT,
++ VCHI_CALLBACK_BULK_RX_SPACE_AVAILABLE, // XXX not yet implemented
++ VCHI_CALLBACK_BULK_TX_SPACE_AVAILABLE, // XXX not yet implemented
++
++ VCHI_CALLBACK_SERVICE_CLOSED,
++
++ // this side has sent XOFF to peer due to lack of data consumption by service
++ // (suggests the service may need to take some recovery action if it has
++ // been deliberately holding off consuming data)
++ VCHI_CALLBACK_SENT_XOFF,
++ VCHI_CALLBACK_SENT_XON,
++
++ // indicates that a bulk transfer has finished reading the source buffer
++ VCHI_CALLBACK_BULK_DATA_READ,
++
++ // power notification events (currently host side only)
++ VCHI_CALLBACK_PEER_OFF,
++ VCHI_CALLBACK_PEER_SUSPENDED,
++ VCHI_CALLBACK_PEER_ON,
++ VCHI_CALLBACK_PEER_RESUMED,
++ VCHI_CALLBACK_FORCED_POWER_OFF,
++
++#ifdef USE_VCHIQ_ARM
++ // some extra notifications provided by vchiq_arm
++ VCHI_CALLBACK_SERVICE_OPENED,
++ VCHI_CALLBACK_BULK_RECEIVE_ABORTED,
++ VCHI_CALLBACK_BULK_TRANSMIT_ABORTED,
++#endif
++
++ VCHI_CALLBACK_REASON_MAX
++} VCHI_CALLBACK_REASON_T;
++
++// service control options
++typedef enum
++{
++ VCHI_SERVICE_OPTION_MIN,
++
++ VCHI_SERVICE_OPTION_TRACE,
++ VCHI_SERVICE_OPTION_SYNCHRONOUS,
++
++ VCHI_SERVICE_OPTION_MAX
++} VCHI_SERVICE_OPTION_T;
++
++
++//Callback used by all services / bulk transfers
++typedef void (*VCHI_CALLBACK_T)( void *callback_param, //my service local param
++ VCHI_CALLBACK_REASON_T reason,
++ void *handle ); //for transmitting msg's only
++
++
++
++/*
++ * Define vector struct for scatter-gather (vector) operations
++ * Vectors can be nested - if a vector element has negative length, then
++ * the data pointer is treated as pointing to another vector array, with
++ * '-vec_len' elements. Thus to append a header onto an existing vector,
++ * you can do this:
++ *
++ * void foo(const VCHI_MSG_VECTOR_T *v, int n)
++ * {
++ * VCHI_MSG_VECTOR_T nv[2];
++ * nv[0].vec_base = my_header;
++ * nv[0].vec_len = sizeof my_header;
++ * nv[1].vec_base = v;
++ * nv[1].vec_len = -n;
++ * ...
++ *
++ */
++typedef struct vchi_msg_vector {
++ const void *vec_base;
++ int32_t vec_len;
++} VCHI_MSG_VECTOR_T;
++
++// Opaque type for a connection API
++typedef struct opaque_vchi_connection_api_t VCHI_CONNECTION_API_T;
++
++// Opaque type for a message driver
++typedef struct opaque_vchi_message_driver_t VCHI_MESSAGE_DRIVER_T;
++
++
++// Iterator structure for reading ahead through received message queue. Allocated by client,
++// initialised by vchi_msg_look_ahead. Fields are for internal VCHI use only.
++// Iterates over messages in queue at the instant of the call to vchi_msg_lookahead -
++// will not proceed to messages received since. Behaviour is undefined if an iterator
++// is used again after messages for that service are removed/dequeued by any
++// means other than vchi_msg_iter_... calls on the iterator itself.
++typedef struct {
++ struct opaque_vchi_service_t *service;
++ void *last;
++ void *next;
++ void *remove;
++} VCHI_MSG_ITER_T;
++
++
++#endif // VCHI_COMMON_H_
+--- /dev/null
++++ b/drivers/misc/vc04_services/interface/vchi/vchi_mh.h
+@@ -0,0 +1,42 @@
++/**
++ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef VCHI_MH_H_
++#define VCHI_MH_H_
++
++#include <linux/types.h>
++
++typedef int32_t VCHI_MEM_HANDLE_T;
++#define VCHI_MEM_HANDLE_INVALID 0
++
++#endif
+--- /dev/null
++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq.h
+@@ -0,0 +1,40 @@
++/**
++ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef VCHIQ_VCHIQ_H
++#define VCHIQ_VCHIQ_H
++
++#include "vchiq_if.h"
++#include "vchiq_util.h"
++
++#endif
+--- /dev/null
++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835.h
+@@ -0,0 +1,42 @@
++/**
++ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef VCHIQ_2835_H
++#define VCHIQ_2835_H
++
++#include "vchiq_pagelist.h"
++
++#define VCHIQ_PLATFORM_FRAGMENTS_OFFSET_IDX 0
++#define VCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX 1
++
++#endif /* VCHIQ_2835_H */
+--- /dev/null
++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
+@@ -0,0 +1,586 @@
++/**
++ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/interrupt.h>
++#include <linux/pagemap.h>
++#include <linux/dma-mapping.h>
++#include <linux/version.h>
++#include <linux/io.h>
++#include <linux/platform_device.h>
++#include <linux/uaccess.h>
++#include <linux/of.h>
++#include <asm/pgtable.h>
++#include <soc/bcm2835/raspberrypi-firmware.h>
++
++#define dmac_map_area __glue(_CACHE,_dma_map_area)
++#define dmac_unmap_area __glue(_CACHE,_dma_unmap_area)
++
++extern void dmac_map_area(const void *, size_t, int);
++extern void dmac_unmap_area(const void *, size_t, int);
++
++#define TOTAL_SLOTS (VCHIQ_SLOT_ZERO_SLOTS + 2 * 32)
++
++#define VCHIQ_ARM_ADDRESS(x) ((void *)((char *)x + g_virt_to_bus_offset))
++
++#include "vchiq_arm.h"
++#include "vchiq_2835.h"
++#include "vchiq_connected.h"
++#include "vchiq_killable.h"
++
++#define MAX_FRAGMENTS (VCHIQ_NUM_CURRENT_BULKS * 2)
++
++#define BELL0 0x00
++#define BELL2 0x08
++
++typedef struct vchiq_2835_state_struct {
++ int inited;
++ VCHIQ_ARM_STATE_T arm_state;
++} VCHIQ_2835_ARM_STATE_T;
++
++static void __iomem *g_regs;
++static unsigned int g_cache_line_size = sizeof(CACHE_LINE_SIZE);
++static unsigned int g_fragments_size;
++static char *g_fragments_base;
++static char *g_free_fragments;
++static struct semaphore g_free_fragments_sema;
++static unsigned long g_virt_to_bus_offset;
++
++extern int vchiq_arm_log_level;
++
++static DEFINE_SEMAPHORE(g_free_fragments_mutex);
++
++static irqreturn_t
++vchiq_doorbell_irq(int irq, void *dev_id);
++
++static int
++create_pagelist(char __user *buf, size_t count, unsigned short type,
++ struct task_struct *task, PAGELIST_T ** ppagelist);
++
++static void
++free_pagelist(PAGELIST_T *pagelist, int actual);
++
++int vchiq_platform_init(struct platform_device *pdev, VCHIQ_STATE_T *state)
++{
++ struct device *dev = &pdev->dev;
++ struct rpi_firmware *fw = platform_get_drvdata(pdev);
++ VCHIQ_SLOT_ZERO_T *vchiq_slot_zero;
++ struct resource *res;
++ void *slot_mem;
++ dma_addr_t slot_phys;
++ u32 channelbase;
++ int slot_mem_size, frag_mem_size;
++ int err, irq, i;
++
++ g_virt_to_bus_offset = virt_to_dma(dev, (void *)0);
++
++ (void)of_property_read_u32(dev->of_node, "cache-line-size",
++ &g_cache_line_size);
++ g_fragments_size = 2 * g_cache_line_size;
++
++ /* Allocate space for the channels in coherent memory */
++ slot_mem_size = PAGE_ALIGN(TOTAL_SLOTS * VCHIQ_SLOT_SIZE);
++ frag_mem_size = PAGE_ALIGN(g_fragments_size * MAX_FRAGMENTS);
++
++ slot_mem = dmam_alloc_coherent(dev, slot_mem_size + frag_mem_size,
++ &slot_phys, GFP_KERNEL);
++ if (!slot_mem) {
++ dev_err(dev, "could not allocate DMA memory\n");
++ return -ENOMEM;
++ }
++
++ WARN_ON(((int)slot_mem & (PAGE_SIZE - 1)) != 0);
++
++ vchiq_slot_zero = vchiq_init_slots(slot_mem, slot_mem_size);
++ if (!vchiq_slot_zero)
++ return -EINVAL;
++
++ vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_OFFSET_IDX] =
++ (int)slot_phys + slot_mem_size;
++ vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX] =
++ MAX_FRAGMENTS;
++
++ g_fragments_base = (char *)slot_mem + slot_mem_size;
++ slot_mem_size += frag_mem_size;
++
++ g_free_fragments = g_fragments_base;
++ for (i = 0; i < (MAX_FRAGMENTS - 1); i++) {
++ *(char **)&g_fragments_base[i*g_fragments_size] =
++ &g_fragments_base[(i + 1)*g_fragments_size];
++ }
++ *(char **)&g_fragments_base[i * g_fragments_size] = NULL;
++ sema_init(&g_free_fragments_sema, MAX_FRAGMENTS);
++
++ if (vchiq_init_state(state, vchiq_slot_zero, 0) != VCHIQ_SUCCESS)
++ return -EINVAL;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ g_regs = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(g_regs))
++ return PTR_ERR(g_regs);
++
++ irq = platform_get_irq(pdev, 0);
++ if (irq <= 0) {
++ dev_err(dev, "failed to get IRQ\n");
++ return irq;
++ }
++
++ err = devm_request_irq(dev, irq, vchiq_doorbell_irq, IRQF_IRQPOLL,
++ "VCHIQ doorbell", state);
++ if (err) {
++ dev_err(dev, "failed to register irq=%d\n", irq);
++ return err;
++ }
++
++ /* Send the base address of the slots to VideoCore */
++ channelbase = slot_phys;
++ err = rpi_firmware_property(fw, RPI_FIRMWARE_VCHIQ_INIT,
++ &channelbase, sizeof(channelbase));
++ if (err || channelbase) {
++ dev_err(dev, "failed to set channelbase\n");
++ return err ? : -ENXIO;
++ }
++
++ vchiq_log_info(vchiq_arm_log_level,
++ "vchiq_init - done (slots %x, phys %pad)",
++ (unsigned int)vchiq_slot_zero, &slot_phys);
++
++ vchiq_call_connected_callbacks();
++
++ return 0;
++}
++
++VCHIQ_STATUS_T
++vchiq_platform_init_state(VCHIQ_STATE_T *state)
++{
++ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
++ state->platform_state = kzalloc(sizeof(VCHIQ_2835_ARM_STATE_T), GFP_KERNEL);
++ ((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->inited = 1;
++ status = vchiq_arm_init_state(state, &((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->arm_state);
++ if(status != VCHIQ_SUCCESS)
++ {
++ ((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->inited = 0;
++ }
++ return status;
++}
++
++VCHIQ_ARM_STATE_T*
++vchiq_platform_get_arm_state(VCHIQ_STATE_T *state)
++{
++ if(!((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->inited)
++ {
++ BUG();
++ }
++ return &((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->arm_state;
++}
++
++void
++remote_event_signal(REMOTE_EVENT_T *event)
++{
++ wmb();
++
++ event->fired = 1;
++
++ dsb(); /* data barrier operation */
++
++ if (event->armed)
++ writel(0, g_regs + BELL2); /* trigger vc interrupt */
++}
++
++int
++vchiq_copy_from_user(void *dst, const void *src, int size)
++{
++ if ((uint32_t)src < TASK_SIZE) {
++ return copy_from_user(dst, src, size);
++ } else {
++ memcpy(dst, src, size);
++ return 0;
++ }
++}
++
++VCHIQ_STATUS_T
++vchiq_prepare_bulk_data(VCHIQ_BULK_T *bulk, VCHI_MEM_HANDLE_T memhandle,
++ void *offset, int size, int dir)
++{
++ PAGELIST_T *pagelist;
++ int ret;
++
++ WARN_ON(memhandle != VCHI_MEM_HANDLE_INVALID);
++
++ ret = create_pagelist((char __user *)offset, size,
++ (dir == VCHIQ_BULK_RECEIVE)
++ ? PAGELIST_READ
++ : PAGELIST_WRITE,
++ current,
++ &pagelist);
++ if (ret != 0)
++ return VCHIQ_ERROR;
++
++ bulk->handle = memhandle;
++ bulk->data = VCHIQ_ARM_ADDRESS(pagelist);
++
++ /* Store the pagelist address in remote_data, which isn't used by the
++ slave. */
++ bulk->remote_data = pagelist;
++
++ return VCHIQ_SUCCESS;
++}
++
++void
++vchiq_complete_bulk(VCHIQ_BULK_T *bulk)
++{
++ if (bulk && bulk->remote_data && bulk->actual)
++ free_pagelist((PAGELIST_T *)bulk->remote_data, bulk->actual);
++}
++
++void
++vchiq_transfer_bulk(VCHIQ_BULK_T *bulk)
++{
++ /*
++ * This should only be called on the master (VideoCore) side, but
++ * provide an implementation to avoid the need for ifdefery.
++ */
++ BUG();
++}
++
++void
++vchiq_dump_platform_state(void *dump_context)
++{
++ char buf[80];
++ int len;
++ len = snprintf(buf, sizeof(buf),
++ " Platform: 2835 (VC master)");
++ vchiq_dump(dump_context, buf, len + 1);
++}
++
++VCHIQ_STATUS_T
++vchiq_platform_suspend(VCHIQ_STATE_T *state)
++{
++ return VCHIQ_ERROR;
++}
++
++VCHIQ_STATUS_T
++vchiq_platform_resume(VCHIQ_STATE_T *state)
++{
++ return VCHIQ_SUCCESS;
++}
++
++void
++vchiq_platform_paused(VCHIQ_STATE_T *state)
++{
++}
++
++void
++vchiq_platform_resumed(VCHIQ_STATE_T *state)
++{
++}
++
++int
++vchiq_platform_videocore_wanted(VCHIQ_STATE_T* state)
++{
++ return 1; // autosuspend not supported - videocore always wanted
++}
++
++int
++vchiq_platform_use_suspend_timer(void)
++{
++ return 0;
++}
++void
++vchiq_dump_platform_use_state(VCHIQ_STATE_T *state)
++{
++ vchiq_log_info(vchiq_arm_log_level, "Suspend timer not in use");
++}
++void
++vchiq_platform_handle_timeout(VCHIQ_STATE_T *state)
++{
++ (void)state;
++}
++/*
++ * Local functions
++ */
++
++static irqreturn_t
++vchiq_doorbell_irq(int irq, void *dev_id)
++{
++ VCHIQ_STATE_T *state = dev_id;
++ irqreturn_t ret = IRQ_NONE;
++ unsigned int status;
++
++ /* Read (and clear) the doorbell */
++ status = readl(g_regs + BELL0);
++
++ if (status & 0x4) { /* Was the doorbell rung? */
++ remote_event_pollall(state);
++ ret = IRQ_HANDLED;
++ }
++
++ return ret;
++}
++
++/* There is a potential problem with partial cache lines (pages?)
++** at the ends of the block when reading. If the CPU accessed anything in
++** the same line (page?) then it may have pulled old data into the cache,
++** obscuring the new data underneath. We can solve this by transferring the
++** partial cache lines separately, and allowing the ARM to copy into the
++** cached area.
++
++** N.B. This implementation plays slightly fast and loose with the Linux
++** driver programming rules, e.g. its use of dmac_map_area instead of
++** dma_map_single, but it isn't a multi-platform driver and it benefits
++** from increased speed as a result.
++*/
++
++static int
++create_pagelist(char __user *buf, size_t count, unsigned short type,
++ struct task_struct *task, PAGELIST_T ** ppagelist)
++{
++ PAGELIST_T *pagelist;
++ struct page **pages;
++ unsigned long *addrs;
++ unsigned int num_pages, offset, i;
++ char *addr, *base_addr, *next_addr;
++ int run, addridx, actual_pages;
++ unsigned long *need_release;
++
++ offset = (unsigned int)buf & (PAGE_SIZE - 1);
++ num_pages = (count + offset + PAGE_SIZE - 1) / PAGE_SIZE;
++
++ *ppagelist = NULL;
++
++ /* Allocate enough storage to hold the page pointers and the page
++ ** list
++ */
++ pagelist = kmalloc(sizeof(PAGELIST_T) +
++ (num_pages * sizeof(unsigned long)) +
++ sizeof(unsigned long) +
++ (num_pages * sizeof(pages[0])),
++ GFP_KERNEL);
++
++ vchiq_log_trace(vchiq_arm_log_level,
++ "create_pagelist - %x", (unsigned int)pagelist);
++ if (!pagelist)
++ return -ENOMEM;
++
++ addrs = pagelist->addrs;
++ need_release = (unsigned long *)(addrs + num_pages);
++ pages = (struct page **)(addrs + num_pages + 1);
++
++ if (is_vmalloc_addr(buf)) {
++ int dir = (type == PAGELIST_WRITE) ?
++ DMA_TO_DEVICE : DMA_FROM_DEVICE;
++ unsigned long length = count;
++ unsigned int off = offset;
++
++ for (actual_pages = 0; actual_pages < num_pages;
++ actual_pages++) {
++ struct page *pg = vmalloc_to_page(buf + (actual_pages *
++ PAGE_SIZE));
++ size_t bytes = PAGE_SIZE - off;
++
++ if (bytes > length)
++ bytes = length;
++ pages[actual_pages] = pg;
++ dmac_map_area(page_address(pg) + off, bytes, dir);
++ length -= bytes;
++ off = 0;
++ }
++ *need_release = 0; /* do not try and release vmalloc pages */
++ } else {
++ down_read(&task->mm->mmap_sem);
++ actual_pages = get_user_pages(task, task->mm,
++ (unsigned long)buf & ~(PAGE_SIZE - 1),
++ num_pages,
++ (type == PAGELIST_READ) /*Write */ ,
++ 0 /*Force */ ,
++ pages,
++ NULL /*vmas */);
++ up_read(&task->mm->mmap_sem);
++
++ if (actual_pages != num_pages) {
++ vchiq_log_info(vchiq_arm_log_level,
++ "create_pagelist - only %d/%d pages locked",
++ actual_pages,
++ num_pages);
++
++ /* This is probably due to the process being killed */
++ while (actual_pages > 0)
++ {
++ actual_pages--;
++ page_cache_release(pages[actual_pages]);
++ }
++ kfree(pagelist);
++ if (actual_pages == 0)
++ actual_pages = -ENOMEM;
++ return actual_pages;
++ }
++ *need_release = 1; /* release user pages */
++ }
++
++ pagelist->length = count;
++ pagelist->type = type;
++ pagelist->offset = offset;
++
++ /* Group the pages into runs of contiguous pages */
++
++ base_addr = VCHIQ_ARM_ADDRESS(page_address(pages[0]));
++ next_addr = base_addr + PAGE_SIZE;
++ addridx = 0;
++ run = 0;
++
++ for (i = 1; i < num_pages; i++) {
++ addr = VCHIQ_ARM_ADDRESS(page_address(pages[i]));
++ if ((addr == next_addr) && (run < (PAGE_SIZE - 1))) {
++ next_addr += PAGE_SIZE;
++ run++;
++ } else {
++ addrs[addridx] = (unsigned long)base_addr + run;
++ addridx++;
++ base_addr = addr;
++ next_addr = addr + PAGE_SIZE;
++ run = 0;
++ }
++ }
++
++ addrs[addridx] = (unsigned long)base_addr + run;
++ addridx++;
++
++ /* Partial cache lines (fragments) require special measures */
++ if ((type == PAGELIST_READ) &&
++ ((pagelist->offset & (g_cache_line_size - 1)) ||
++ ((pagelist->offset + pagelist->length) &
++ (g_cache_line_size - 1)))) {
++ char *fragments;
++
++ if (down_interruptible(&g_free_fragments_sema) != 0) {
++ kfree(pagelist);
++ return -EINTR;
++ }
++
++ WARN_ON(g_free_fragments == NULL);
++
++ down(&g_free_fragments_mutex);
++ fragments = g_free_fragments;
++ WARN_ON(fragments == NULL);
++ g_free_fragments = *(char **) g_free_fragments;
++ up(&g_free_fragments_mutex);
++ pagelist->type = PAGELIST_READ_WITH_FRAGMENTS +
++ (fragments - g_fragments_base) / g_fragments_size;
++ }
++
++ dmac_flush_range(pagelist, addrs + num_pages);
++
++ *ppagelist = pagelist;
++
++ return 0;
++}
++
++static void
++free_pagelist(PAGELIST_T *pagelist, int actual)
++{
++ unsigned long *need_release;
++ struct page **pages;
++ unsigned int num_pages, i;
++
++ vchiq_log_trace(vchiq_arm_log_level,
++ "free_pagelist - %x, %d", (unsigned int)pagelist, actual);
++
++ num_pages =
++ (pagelist->length + pagelist->offset + PAGE_SIZE - 1) /
++ PAGE_SIZE;
++
++ need_release = (unsigned long *)(pagelist->addrs + num_pages);
++ pages = (struct page **)(pagelist->addrs + num_pages + 1);
++
++ /* Deal with any partial cache lines (fragments) */
++ if (pagelist->type >= PAGELIST_READ_WITH_FRAGMENTS) {
++ char *fragments = g_fragments_base +
++ (pagelist->type - PAGELIST_READ_WITH_FRAGMENTS) *
++ g_fragments_size;
++ int head_bytes, tail_bytes;
++ head_bytes = (g_cache_line_size - pagelist->offset) &
++ (g_cache_line_size - 1);
++ tail_bytes = (pagelist->offset + actual) &
++ (g_cache_line_size - 1);
++
++ if ((actual >= 0) && (head_bytes != 0)) {
++ if (head_bytes > actual)
++ head_bytes = actual;
++
++ memcpy((char *)page_address(pages[0]) +
++ pagelist->offset,
++ fragments,
++ head_bytes);
++ }
++ if ((actual >= 0) && (head_bytes < actual) &&
++ (tail_bytes != 0)) {
++ memcpy((char *)page_address(pages[num_pages - 1]) +
++ ((pagelist->offset + actual) &
++ (PAGE_SIZE - 1) & ~(g_cache_line_size - 1)),
++ fragments + g_cache_line_size,
++ tail_bytes);
++ }
++
++ down(&g_free_fragments_mutex);
++ *(char **)fragments = g_free_fragments;
++ g_free_fragments = fragments;
++ up(&g_free_fragments_mutex);
++ up(&g_free_fragments_sema);
++ }
++
++ if (*need_release) {
++ unsigned int length = pagelist->length;
++ unsigned int offset = pagelist->offset;
++
++ for (i = 0; i < num_pages; i++) {
++ struct page *pg = pages[i];
++
++ if (pagelist->type != PAGELIST_WRITE) {
++ unsigned int bytes = PAGE_SIZE - offset;
++
++ if (bytes > length)
++ bytes = length;
++ dmac_unmap_area(page_address(pg) + offset,
++ bytes, DMA_FROM_DEVICE);
++ length -= bytes;
++ offset = 0;
++ set_page_dirty(pg);
++ }
++ page_cache_release(pg);
++ }
++ }
++
++ kfree(pagelist);
++}
+--- /dev/null
++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c
+@@ -0,0 +1,2903 @@
++/**
++ * Copyright (c) 2014 Raspberry Pi (Trading) Ltd. All rights reserved.
++ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/cdev.h>
++#include <linux/fs.h>
++#include <linux/device.h>
++#include <linux/mm.h>
++#include <linux/highmem.h>
++#include <linux/pagemap.h>
++#include <linux/bug.h>
++#include <linux/semaphore.h>
++#include <linux/list.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <soc/bcm2835/raspberrypi-firmware.h>
++
++#include "vchiq_core.h"
++#include "vchiq_ioctl.h"
++#include "vchiq_arm.h"
++#include "vchiq_debugfs.h"
++#include "vchiq_killable.h"
++
++#define DEVICE_NAME "vchiq"
++
++/* Override the default prefix, which would be vchiq_arm (from the filename) */
++#undef MODULE_PARAM_PREFIX
++#define MODULE_PARAM_PREFIX DEVICE_NAME "."
++
++#define VCHIQ_MINOR 0
++
++/* Some per-instance constants */
++#define MAX_COMPLETIONS 16
++#define MAX_SERVICES 64
++#define MAX_ELEMENTS 8
++#define MSG_QUEUE_SIZE 64
++
++#define KEEPALIVE_VER 1
++#define KEEPALIVE_VER_MIN KEEPALIVE_VER
++
++/* Run time control of log level, based on KERN_XXX level. */
++int vchiq_arm_log_level = VCHIQ_LOG_DEFAULT;
++int vchiq_susp_log_level = VCHIQ_LOG_ERROR;
++
++#define SUSPEND_TIMER_TIMEOUT_MS 100
++#define SUSPEND_RETRY_TIMER_TIMEOUT_MS 1000
++
++#define VC_SUSPEND_NUM_OFFSET 3 /* number of values before idle which are -ve */
++static const char *const suspend_state_names[] = {
++ "VC_SUSPEND_FORCE_CANCELED",
++ "VC_SUSPEND_REJECTED",
++ "VC_SUSPEND_FAILED",
++ "VC_SUSPEND_IDLE",
++ "VC_SUSPEND_REQUESTED",
++ "VC_SUSPEND_IN_PROGRESS",
++ "VC_SUSPEND_SUSPENDED"
++};
++#define VC_RESUME_NUM_OFFSET 1 /* number of values before idle which are -ve */
++static const char *const resume_state_names[] = {
++ "VC_RESUME_FAILED",
++ "VC_RESUME_IDLE",
++ "VC_RESUME_REQUESTED",
++ "VC_RESUME_IN_PROGRESS",
++ "VC_RESUME_RESUMED"
++};
++/* The number of times we allow force suspend to timeout before actually
++** _forcing_ suspend. This is to cater for SW which fails to release vchiq
++** correctly - we don't want to prevent ARM suspend indefinitely in this case.
++*/
++#define FORCE_SUSPEND_FAIL_MAX 8
++
++/* The time in ms allowed for videocore to go idle when force suspend has been
++ * requested */
++#define FORCE_SUSPEND_TIMEOUT_MS 200
++
++
++static void suspend_timer_callback(unsigned long context);
++
++
++typedef struct user_service_struct {
++ VCHIQ_SERVICE_T *service;
++ void *userdata;
++ VCHIQ_INSTANCE_T instance;
++ char is_vchi;
++ char dequeue_pending;
++ char close_pending;
++ int message_available_pos;
++ int msg_insert;
++ int msg_remove;
++ struct semaphore insert_event;
++ struct semaphore remove_event;
++ struct semaphore close_event;
++ VCHIQ_HEADER_T * msg_queue[MSG_QUEUE_SIZE];
++} USER_SERVICE_T;
++
++struct bulk_waiter_node {
++ struct bulk_waiter bulk_waiter;
++ int pid;
++ struct list_head list;
++};
++
++struct vchiq_instance_struct {
++ VCHIQ_STATE_T *state;
++ VCHIQ_COMPLETION_DATA_T completions[MAX_COMPLETIONS];
++ int completion_insert;
++ int completion_remove;
++ struct semaphore insert_event;
++ struct semaphore remove_event;
++ struct mutex completion_mutex;
++
++ int connected;
++ int closing;
++ int pid;
++ int mark;
++ int use_close_delivered;
++ int trace;
++
++ struct list_head bulk_waiter_list;
++ struct mutex bulk_waiter_list_mutex;
++
++ VCHIQ_DEBUGFS_NODE_T debugfs_node;
++};
++
++typedef struct dump_context_struct {
++ char __user *buf;
++ size_t actual;
++ size_t space;
++ loff_t offset;
++} DUMP_CONTEXT_T;
++
++static struct cdev vchiq_cdev;
++static dev_t vchiq_devid;
++static VCHIQ_STATE_T g_state;
++static struct class *vchiq_class;
++static struct device *vchiq_dev;
++static DEFINE_SPINLOCK(msg_queue_spinlock);
++
++static const char *const ioctl_names[] = {
++ "CONNECT",
++ "SHUTDOWN",
++ "CREATE_SERVICE",
++ "REMOVE_SERVICE",
++ "QUEUE_MESSAGE",
++ "QUEUE_BULK_TRANSMIT",
++ "QUEUE_BULK_RECEIVE",
++ "AWAIT_COMPLETION",
++ "DEQUEUE_MESSAGE",
++ "GET_CLIENT_ID",
++ "GET_CONFIG",
++ "CLOSE_SERVICE",
++ "USE_SERVICE",
++ "RELEASE_SERVICE",
++ "SET_SERVICE_OPTION",
++ "DUMP_PHYS_MEM",
++ "LIB_VERSION",
++ "CLOSE_DELIVERED"
++};
++
++vchiq_static_assert((sizeof(ioctl_names)/sizeof(ioctl_names[0])) ==
++ (VCHIQ_IOC_MAX + 1));
++
++static void
++dump_phys_mem(void *virt_addr, uint32_t num_bytes);
++
++/****************************************************************************
++*
++* add_completion
++*
++***************************************************************************/
++
++static VCHIQ_STATUS_T
++add_completion(VCHIQ_INSTANCE_T instance, VCHIQ_REASON_T reason,
++ VCHIQ_HEADER_T *header, USER_SERVICE_T *user_service,
++ void *bulk_userdata)
++{
++ VCHIQ_COMPLETION_DATA_T *completion;
++ DEBUG_INITIALISE(g_state.local)
++
++ while (instance->completion_insert ==
++ (instance->completion_remove + MAX_COMPLETIONS)) {
++ /* Out of space - wait for the client */
++ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
++ vchiq_log_trace(vchiq_arm_log_level,
++ "add_completion - completion queue full");
++ DEBUG_COUNT(COMPLETION_QUEUE_FULL_COUNT);
++ if (down_interruptible(&instance->remove_event) != 0) {
++ vchiq_log_info(vchiq_arm_log_level,
++ "service_callback interrupted");
++ return VCHIQ_RETRY;
++ } else if (instance->closing) {
++ vchiq_log_info(vchiq_arm_log_level,
++ "service_callback closing");
++ return VCHIQ_ERROR;
++ }
++ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
++ }
++
++ completion =
++ &instance->completions[instance->completion_insert &
++ (MAX_COMPLETIONS - 1)];
++
++ completion->header = header;
++ completion->reason = reason;
++ /* N.B. service_userdata is updated while processing AWAIT_COMPLETION */
++ completion->service_userdata = user_service->service;
++ completion->bulk_userdata = bulk_userdata;
++
++ if (reason == VCHIQ_SERVICE_CLOSED) {
++ /* Take an extra reference, to be held until
++ this CLOSED notification is delivered. */
++ lock_service(user_service->service);
++ if (instance->use_close_delivered)
++ user_service->close_pending = 1;
++ }
++
++ /* A write barrier is needed here to ensure that the entire completion
++ record is written out before the insert point. */
++ wmb();
++
++ if (reason == VCHIQ_MESSAGE_AVAILABLE)
++ user_service->message_available_pos =
++ instance->completion_insert;
++ instance->completion_insert++;
++
++ up(&instance->insert_event);
++
++ return VCHIQ_SUCCESS;
++}
++
++/****************************************************************************
++*
++* service_callback
++*
++***************************************************************************/
++
++static VCHIQ_STATUS_T
++service_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header,
++ VCHIQ_SERVICE_HANDLE_T handle, void *bulk_userdata)
++{
++ /* How do we ensure the callback goes to the right client?
++ ** The service_user data points to a USER_SERVICE_T record containing
++ ** the original callback and the user state structure, which contains a
++ ** circular buffer for completion records.
++ */
++ USER_SERVICE_T *user_service;
++ VCHIQ_SERVICE_T *service;
++ VCHIQ_INSTANCE_T instance;
++ DEBUG_INITIALISE(g_state.local)
++
++ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
++
++ service = handle_to_service(handle);
++ BUG_ON(!service);
++ user_service = (USER_SERVICE_T *)service->base.userdata;
++ instance = user_service->instance;
++
++ if (!instance || instance->closing)
++ return VCHIQ_SUCCESS;
++
++ vchiq_log_trace(vchiq_arm_log_level,
++ "service_callback - service %lx(%d,%p), reason %d, header %lx, "
++ "instance %lx, bulk_userdata %lx",
++ (unsigned long)user_service,
++ service->localport, user_service->userdata,
++ reason, (unsigned long)header,
++ (unsigned long)instance, (unsigned long)bulk_userdata);
++
++ if (header && user_service->is_vchi) {
++ spin_lock(&msg_queue_spinlock);
++ while (user_service->msg_insert ==
++ (user_service->msg_remove + MSG_QUEUE_SIZE)) {
++ spin_unlock(&msg_queue_spinlock);
++ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
++ DEBUG_COUNT(MSG_QUEUE_FULL_COUNT);
++ vchiq_log_trace(vchiq_arm_log_level,
++ "service_callback - msg queue full");
++ /* If there is no MESSAGE_AVAILABLE in the completion
++ ** queue, add one
++ */
++ if ((user_service->message_available_pos -
++ instance->completion_remove) < 0) {
++ VCHIQ_STATUS_T status;
++ vchiq_log_info(vchiq_arm_log_level,
++ "Inserting extra MESSAGE_AVAILABLE");
++ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
++ status = add_completion(instance, reason,
++ NULL, user_service, bulk_userdata);
++ if (status != VCHIQ_SUCCESS) {
++ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
++ return status;
++ }
++ }
++
++ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
++ if (down_interruptible(&user_service->remove_event)
++ != 0) {
++ vchiq_log_info(vchiq_arm_log_level,
++ "service_callback interrupted");
++ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
++ return VCHIQ_RETRY;
++ } else if (instance->closing) {
++ vchiq_log_info(vchiq_arm_log_level,
++ "service_callback closing");
++ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
++ return VCHIQ_ERROR;
++ }
++ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
++ spin_lock(&msg_queue_spinlock);
++ }
++
++ user_service->msg_queue[user_service->msg_insert &
++ (MSG_QUEUE_SIZE - 1)] = header;
++ user_service->msg_insert++;
++ spin_unlock(&msg_queue_spinlock);
++
++ up(&user_service->insert_event);
++
++ /* If there is a thread waiting in DEQUEUE_MESSAGE, or if
++ ** there is a MESSAGE_AVAILABLE in the completion queue then
++ ** bypass the completion queue.
++ */
++ if (((user_service->message_available_pos -
++ instance->completion_remove) >= 0) ||
++ user_service->dequeue_pending) {
++ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
++ user_service->dequeue_pending = 0;
++ return VCHIQ_SUCCESS;
++ }
++
++ header = NULL;
++ }
++ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
++
++ return add_completion(instance, reason, header, user_service,
++ bulk_userdata);
++}
++
++/****************************************************************************
++*
++* user_service_free
++*
++***************************************************************************/
++static void
++user_service_free(void *userdata)
++{
++ kfree(userdata);
++}
++
++/****************************************************************************
++*
++* close_delivered
++*
++***************************************************************************/
++static void close_delivered(USER_SERVICE_T *user_service)
++{
++ vchiq_log_info(vchiq_arm_log_level,
++ "close_delivered(handle=%x)",
++ user_service->service->handle);
++
++ if (user_service->close_pending) {
++ /* Allow the underlying service to be culled */
++ unlock_service(user_service->service);
++
++ /* Wake the user-thread blocked in close_ or remove_service */
++ up(&user_service->close_event);
++
++ user_service->close_pending = 0;
++ }
++}
++
++/****************************************************************************
++*
++* vchiq_ioctl
++*
++***************************************************************************/
++static long
++vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
++{
++ VCHIQ_INSTANCE_T instance = file->private_data;
++ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
++ VCHIQ_SERVICE_T *service = NULL;
++ long ret = 0;
++ int i, rc;
++ DEBUG_INITIALISE(g_state.local)
++
++ vchiq_log_trace(vchiq_arm_log_level,
++ "vchiq_ioctl - instance %x, cmd %s, arg %lx",
++ (unsigned int)instance,
++ ((_IOC_TYPE(cmd) == VCHIQ_IOC_MAGIC) &&
++ (_IOC_NR(cmd) <= VCHIQ_IOC_MAX)) ?
++ ioctl_names[_IOC_NR(cmd)] : "<invalid>", arg);
++
++ switch (cmd) {
++ case VCHIQ_IOC_SHUTDOWN:
++ if (!instance->connected)
++ break;
++
++ /* Remove all services */
++ i = 0;
++ while ((service = next_service_by_instance(instance->state,
++ instance, &i)) != NULL) {
++ status = vchiq_remove_service(service->handle);
++ unlock_service(service);
++ if (status != VCHIQ_SUCCESS)
++ break;
++ }
++ service = NULL;
++
++ if (status == VCHIQ_SUCCESS) {
++ /* Wake the completion thread and ask it to exit */
++ instance->closing = 1;
++ up(&instance->insert_event);
++ }
++
++ break;
++
++ case VCHIQ_IOC_CONNECT:
++ if (instance->connected) {
++ ret = -EINVAL;
++ break;
++ }
++ rc = mutex_lock_interruptible(&instance->state->mutex);
++ if (rc != 0) {
++ vchiq_log_error(vchiq_arm_log_level,
++ "vchiq: connect: could not lock mutex for "
++ "state %d: %d",
++ instance->state->id, rc);
++ ret = -EINTR;
++ break;
++ }
++ status = vchiq_connect_internal(instance->state, instance);
++ mutex_unlock(&instance->state->mutex);
++
++ if (status == VCHIQ_SUCCESS)
++ instance->connected = 1;
++ else
++ vchiq_log_error(vchiq_arm_log_level,
++ "vchiq: could not connect: %d", status);
++ break;
++
++ case VCHIQ_IOC_CREATE_SERVICE: {
++ VCHIQ_CREATE_SERVICE_T args;
++ USER_SERVICE_T *user_service = NULL;
++ void *userdata;
++ int srvstate;
++
++ if (copy_from_user
++ (&args, (const void __user *)arg,
++ sizeof(args)) != 0) {
++ ret = -EFAULT;
++ break;
++ }
++
++ user_service = kmalloc(sizeof(USER_SERVICE_T), GFP_KERNEL);
++ if (!user_service) {
++ ret = -ENOMEM;
++ break;
++ }
++
++ if (args.is_open) {
++ if (!instance->connected) {
++ ret = -ENOTCONN;
++ kfree(user_service);
++ break;
++ }
++ srvstate = VCHIQ_SRVSTATE_OPENING;
++ } else {
++ srvstate =
++ instance->connected ?
++ VCHIQ_SRVSTATE_LISTENING :
++ VCHIQ_SRVSTATE_HIDDEN;
++ }
++
++ userdata = args.params.userdata;
++ args.params.callback = service_callback;
++ args.params.userdata = user_service;
++ service = vchiq_add_service_internal(
++ instance->state,
++ &args.params, srvstate,
++ instance, user_service_free);
++
++ if (service != NULL) {
++ user_service->service = service;
++ user_service->userdata = userdata;
++ user_service->instance = instance;
++ user_service->is_vchi = (args.is_vchi != 0);
++ user_service->dequeue_pending = 0;
++ user_service->close_pending = 0;
++ user_service->message_available_pos =
++ instance->completion_remove - 1;
++ user_service->msg_insert = 0;
++ user_service->msg_remove = 0;
++ sema_init(&user_service->insert_event, 0);
++ sema_init(&user_service->remove_event, 0);
++ sema_init(&user_service->close_event, 0);
++
++ if (args.is_open) {
++ status = vchiq_open_service_internal
++ (service, instance->pid);
++ if (status != VCHIQ_SUCCESS) {
++ vchiq_remove_service(service->handle);
++ service = NULL;
++ ret = (status == VCHIQ_RETRY) ?
++ -EINTR : -EIO;
++ break;
++ }
++ }
++
++ if (copy_to_user((void __user *)
++ &(((VCHIQ_CREATE_SERVICE_T __user *)
++ arg)->handle),
++ (const void *)&service->handle,
++ sizeof(service->handle)) != 0) {
++ ret = -EFAULT;
++ vchiq_remove_service(service->handle);
++ }
++
++ service = NULL;
++ } else {
++ ret = -EEXIST;
++ kfree(user_service);
++ }
++ } break;
++
++ case VCHIQ_IOC_CLOSE_SERVICE: {
++ VCHIQ_SERVICE_HANDLE_T handle = (VCHIQ_SERVICE_HANDLE_T)arg;
++
++ service = find_service_for_instance(instance, handle);
++ if (service != NULL) {
++ USER_SERVICE_T *user_service =
++ (USER_SERVICE_T *)service->base.userdata;
++ /* close_pending is false on first entry, and when the
++ wait in vchiq_close_service has been interrupted. */
++ if (!user_service->close_pending) {
++ status = vchiq_close_service(service->handle);
++ if (status != VCHIQ_SUCCESS)
++ break;
++ }
++
++ /* close_pending is true once the underlying service
++ has been closed until the client library calls the
++ CLOSE_DELIVERED ioctl, signalling close_event. */
++ if (user_service->close_pending &&
++ down_interruptible(&user_service->close_event))
++ status = VCHIQ_RETRY;
++ }
++ else
++ ret = -EINVAL;
++ } break;
++
++ case VCHIQ_IOC_REMOVE_SERVICE: {
++ VCHIQ_SERVICE_HANDLE_T handle = (VCHIQ_SERVICE_HANDLE_T)arg;
++
++ service = find_service_for_instance(instance, handle);
++ if (service != NULL) {
++ USER_SERVICE_T *user_service =
++ (USER_SERVICE_T *)service->base.userdata;
++ /* close_pending is false on first entry, and when the
++ wait in vchiq_close_service has been interrupted. */
++ if (!user_service->close_pending) {
++ status = vchiq_remove_service(service->handle);
++ if (status != VCHIQ_SUCCESS)
++ break;
++ }
++
++ /* close_pending is true once the underlying service
++ has been closed until the client library calls the
++ CLOSE_DELIVERED ioctl, signalling close_event. */
++ if (user_service->close_pending &&
++ down_interruptible(&user_service->close_event))
++ status = VCHIQ_RETRY;
++ }
++ else
++ ret = -EINVAL;
++ } break;
++
++ case VCHIQ_IOC_USE_SERVICE:
++ case VCHIQ_IOC_RELEASE_SERVICE: {
++ VCHIQ_SERVICE_HANDLE_T handle = (VCHIQ_SERVICE_HANDLE_T)arg;
++
++ service = find_service_for_instance(instance, handle);
++ if (service != NULL) {
++ status = (cmd == VCHIQ_IOC_USE_SERVICE) ?
++ vchiq_use_service_internal(service) :
++ vchiq_release_service_internal(service);
++ if (status != VCHIQ_SUCCESS) {
++ vchiq_log_error(vchiq_susp_log_level,
++ "%s: cmd %s returned error %d for "
++ "service %c%c%c%c:%03d",
++ __func__,
++ (cmd == VCHIQ_IOC_USE_SERVICE) ?
++ "VCHIQ_IOC_USE_SERVICE" :
++ "VCHIQ_IOC_RELEASE_SERVICE",
++ status,
++ VCHIQ_FOURCC_AS_4CHARS(
++ service->base.fourcc),
++ service->client_id);
++ ret = -EINVAL;
++ }
++ } else
++ ret = -EINVAL;
++ } break;
++
++ case VCHIQ_IOC_QUEUE_MESSAGE: {
++ VCHIQ_QUEUE_MESSAGE_T args;
++ if (copy_from_user
++ (&args, (const void __user *)arg,
++ sizeof(args)) != 0) {
++ ret = -EFAULT;
++ break;
++ }
++
++ service = find_service_for_instance(instance, args.handle);
++
++ if ((service != NULL) && (args.count <= MAX_ELEMENTS)) {
++ /* Copy elements into kernel space */
++ VCHIQ_ELEMENT_T elements[MAX_ELEMENTS];
++ if (copy_from_user(elements, args.elements,
++ args.count * sizeof(VCHIQ_ELEMENT_T)) == 0)
++ status = vchiq_queue_message
++ (args.handle,
++ elements, args.count);
++ else
++ ret = -EFAULT;
++ } else {
++ ret = -EINVAL;
++ }
++ } break;
++
++ case VCHIQ_IOC_QUEUE_BULK_TRANSMIT:
++ case VCHIQ_IOC_QUEUE_BULK_RECEIVE: {
++ VCHIQ_QUEUE_BULK_TRANSFER_T args;
++ struct bulk_waiter_node *waiter = NULL;
++ VCHIQ_BULK_DIR_T dir =
++ (cmd == VCHIQ_IOC_QUEUE_BULK_TRANSMIT) ?
++ VCHIQ_BULK_TRANSMIT : VCHIQ_BULK_RECEIVE;
++
++ if (copy_from_user
++ (&args, (const void __user *)arg,
++ sizeof(args)) != 0) {
++ ret = -EFAULT;
++ break;
++ }
++
++ service = find_service_for_instance(instance, args.handle);
++ if (!service) {
++ ret = -EINVAL;
++ break;
++ }
++
++ if (args.mode == VCHIQ_BULK_MODE_BLOCKING) {
++ waiter = kzalloc(sizeof(struct bulk_waiter_node),
++ GFP_KERNEL);
++ if (!waiter) {
++ ret = -ENOMEM;
++ break;
++ }
++ args.userdata = &waiter->bulk_waiter;
++ } else if (args.mode == VCHIQ_BULK_MODE_WAITING) {
++ struct list_head *pos;
++ mutex_lock(&instance->bulk_waiter_list_mutex);
++ list_for_each(pos, &instance->bulk_waiter_list) {
++ if (list_entry(pos, struct bulk_waiter_node,
++ list)->pid == current->pid) {
++ waiter = list_entry(pos,
++ struct bulk_waiter_node,
++ list);
++ list_del(pos);
++ break;
++ }
++
++ }
++ mutex_unlock(&instance->bulk_waiter_list_mutex);
++ if (!waiter) {
++ vchiq_log_error(vchiq_arm_log_level,
++ "no bulk_waiter found for pid %d",
++ current->pid);
++ ret = -ESRCH;
++ break;
++ }
++ vchiq_log_info(vchiq_arm_log_level,
++ "found bulk_waiter %x for pid %d",
++ (unsigned int)waiter, current->pid);
++ args.userdata = &waiter->bulk_waiter;
++ }
++ status = vchiq_bulk_transfer
++ (args.handle,
++ VCHI_MEM_HANDLE_INVALID,
++ args.data, args.size,
++ args.userdata, args.mode,
++ dir);
++ if (!waiter)
++ break;
++ if ((status != VCHIQ_RETRY) || fatal_signal_pending(current) ||
++ !waiter->bulk_waiter.bulk) {
++ if (waiter->bulk_waiter.bulk) {
++ /* Cancel the signal when the transfer
++ ** completes. */
++ spin_lock(&bulk_waiter_spinlock);
++ waiter->bulk_waiter.bulk->userdata = NULL;
++ spin_unlock(&bulk_waiter_spinlock);
++ }
++ kfree(waiter);
++ } else {
++ const VCHIQ_BULK_MODE_T mode_waiting =
++ VCHIQ_BULK_MODE_WAITING;
++ waiter->pid = current->pid;
++ mutex_lock(&instance->bulk_waiter_list_mutex);
++ list_add(&waiter->list, &instance->bulk_waiter_list);
++ mutex_unlock(&instance->bulk_waiter_list_mutex);
++ vchiq_log_info(vchiq_arm_log_level,
++ "saved bulk_waiter %x for pid %d",
++ (unsigned int)waiter, current->pid);
++
++ if (copy_to_user((void __user *)
++ &(((VCHIQ_QUEUE_BULK_TRANSFER_T __user *)
++ arg)->mode),
++ (const void *)&mode_waiting,
++ sizeof(mode_waiting)) != 0)
++ ret = -EFAULT;
++ }
++ } break;
++
++ case VCHIQ_IOC_AWAIT_COMPLETION: {
++ VCHIQ_AWAIT_COMPLETION_T args;
++
++ DEBUG_TRACE(AWAIT_COMPLETION_LINE);
++ if (!instance->connected) {
++ ret = -ENOTCONN;
++ break;
++ }
++
++ if (copy_from_user(&args, (const void __user *)arg,
++ sizeof(args)) != 0) {
++ ret = -EFAULT;
++ break;
++ }
++
++ mutex_lock(&instance->completion_mutex);
++
++ DEBUG_TRACE(AWAIT_COMPLETION_LINE);
++ while ((instance->completion_remove ==
++ instance->completion_insert)
++ && !instance->closing) {
++ int rc;
++ DEBUG_TRACE(AWAIT_COMPLETION_LINE);
++ mutex_unlock(&instance->completion_mutex);
++ rc = down_interruptible(&instance->insert_event);
++ mutex_lock(&instance->completion_mutex);
++ if (rc != 0) {
++ DEBUG_TRACE(AWAIT_COMPLETION_LINE);
++ vchiq_log_info(vchiq_arm_log_level,
++ "AWAIT_COMPLETION interrupted");
++ ret = -EINTR;
++ break;
++ }
++ }
++ DEBUG_TRACE(AWAIT_COMPLETION_LINE);
++
++ /* A read memory barrier is needed to stop prefetch of a stale
++ ** completion record
++ */
++ rmb();
++
++ if (ret == 0) {
++ int msgbufcount = args.msgbufcount;
++ for (ret = 0; ret < args.count; ret++) {
++ VCHIQ_COMPLETION_DATA_T *completion;
++ VCHIQ_SERVICE_T *service;
++ USER_SERVICE_T *user_service;
++ VCHIQ_HEADER_T *header;
++ if (instance->completion_remove ==
++ instance->completion_insert)
++ break;
++ completion = &instance->completions[
++ instance->completion_remove &
++ (MAX_COMPLETIONS - 1)];
++
++ service = completion->service_userdata;
++ user_service = service->base.userdata;
++ completion->service_userdata =
++ user_service->userdata;
++
++ header = completion->header;
++ if (header) {
++ void __user *msgbuf;
++ int msglen;
++
++ msglen = header->size +
++ sizeof(VCHIQ_HEADER_T);
++ /* This must be a VCHIQ-style service */
++ if (args.msgbufsize < msglen) {
++ vchiq_log_error(
++ vchiq_arm_log_level,
++ "header %x: msgbufsize"
++ " %x < msglen %x",
++ (unsigned int)header,
++ args.msgbufsize,
++ msglen);
++ WARN(1, "invalid message "
++ "size\n");
++ if (ret == 0)
++ ret = -EMSGSIZE;
++ break;
++ }
++ if (msgbufcount <= 0)
++ /* Stall here for lack of a
++ ** buffer for the message. */
++ break;
++ /* Get the pointer from user space */
++ msgbufcount--;
++ if (copy_from_user(&msgbuf,
++ (const void __user *)
++ &args.msgbufs[msgbufcount],
++ sizeof(msgbuf)) != 0) {
++ if (ret == 0)
++ ret = -EFAULT;
++ break;
++ }
++
++ /* Copy the message to user space */
++ if (copy_to_user(msgbuf, header,
++ msglen) != 0) {
++ if (ret == 0)
++ ret = -EFAULT;
++ break;
++ }
++
++ /* Now it has been copied, the message
++ ** can be released. */
++ vchiq_release_message(service->handle,
++ header);
++
++ /* The completion must point to the
++ ** msgbuf. */
++ completion->header = msgbuf;
++ }
++
++ if ((completion->reason ==
++ VCHIQ_SERVICE_CLOSED) &&
++ !instance->use_close_delivered)
++ unlock_service(service);
++
++ if (copy_to_user((void __user *)(
++ (size_t)args.buf +
++ ret * sizeof(VCHIQ_COMPLETION_DATA_T)),
++ completion,
++ sizeof(VCHIQ_COMPLETION_DATA_T)) != 0) {
++ if (ret == 0)
++ ret = -EFAULT;
++ break;
++ }
++
++ instance->completion_remove++;
++ }
++
++ if (msgbufcount != args.msgbufcount) {
++ if (copy_to_user((void __user *)
++ &((VCHIQ_AWAIT_COMPLETION_T *)arg)->
++ msgbufcount,
++ &msgbufcount,
++ sizeof(msgbufcount)) != 0) {
++ ret = -EFAULT;
++ }
++ }
++ }
++
++ if (ret != 0)
++ up(&instance->remove_event);
++ mutex_unlock(&instance->completion_mutex);
++ DEBUG_TRACE(AWAIT_COMPLETION_LINE);
++ } break;
++
++ case VCHIQ_IOC_DEQUEUE_MESSAGE: {
++ VCHIQ_DEQUEUE_MESSAGE_T args;
++ USER_SERVICE_T *user_service;
++ VCHIQ_HEADER_T *header;
++
++ DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
++ if (copy_from_user
++ (&args, (const void __user *)arg,
++ sizeof(args)) != 0) {
++ ret = -EFAULT;
++ break;
++ }
++ service = find_service_for_instance(instance, args.handle);
++ if (!service) {
++ ret = -EINVAL;
++ break;
++ }
++ user_service = (USER_SERVICE_T *)service->base.userdata;
++ if (user_service->is_vchi == 0) {
++ ret = -EINVAL;
++ break;
++ }
++
++ spin_lock(&msg_queue_spinlock);
++ if (user_service->msg_remove == user_service->msg_insert) {
++ if (!args.blocking) {
++ spin_unlock(&msg_queue_spinlock);
++ DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
++ ret = -EWOULDBLOCK;
++ break;
++ }
++ user_service->dequeue_pending = 1;
++ do {
++ spin_unlock(&msg_queue_spinlock);
++ DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
++ if (down_interruptible(
++ &user_service->insert_event) != 0) {
++ vchiq_log_info(vchiq_arm_log_level,
++ "DEQUEUE_MESSAGE interrupted");
++ ret = -EINTR;
++ break;
++ }
++ spin_lock(&msg_queue_spinlock);
++ } while (user_service->msg_remove ==
++ user_service->msg_insert);
++
++ if (ret)
++ break;
++ }
++
++ BUG_ON((int)(user_service->msg_insert -
++ user_service->msg_remove) < 0);
++
++ header = user_service->msg_queue[user_service->msg_remove &
++ (MSG_QUEUE_SIZE - 1)];
++ user_service->msg_remove++;
++ spin_unlock(&msg_queue_spinlock);
++
++ up(&user_service->remove_event);
++ if (header == NULL)
++ ret = -ENOTCONN;
++ else if (header->size <= args.bufsize) {
++ /* Copy to user space if msgbuf is not NULL */
++ if ((args.buf == NULL) ||
++ (copy_to_user((void __user *)args.buf,
++ header->data,
++ header->size) == 0)) {
++ ret = header->size;
++ vchiq_release_message(
++ service->handle,
++ header);
++ } else
++ ret = -EFAULT;
++ } else {
++ vchiq_log_error(vchiq_arm_log_level,
++ "header %x: bufsize %x < size %x",
++ (unsigned int)header, args.bufsize,
++ header->size);
++ WARN(1, "invalid size\n");
++ ret = -EMSGSIZE;
++ }
++ DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
++ } break;
++
++ case VCHIQ_IOC_GET_CLIENT_ID: {
++ VCHIQ_SERVICE_HANDLE_T handle = (VCHIQ_SERVICE_HANDLE_T)arg;
++
++ ret = vchiq_get_client_id(handle);
++ } break;
++
++ case VCHIQ_IOC_GET_CONFIG: {
++ VCHIQ_GET_CONFIG_T args;
++ VCHIQ_CONFIG_T config;
++
++ if (copy_from_user(&args, (const void __user *)arg,
++ sizeof(args)) != 0) {
++ ret = -EFAULT;
++ break;
++ }
++ if (args.config_size > sizeof(config)) {
++ ret = -EINVAL;
++ break;
++ }
++ status = vchiq_get_config(instance, args.config_size, &config);
++ if (status == VCHIQ_SUCCESS) {
++ if (copy_to_user((void __user *)args.pconfig,
++ &config, args.config_size) != 0) {
++ ret = -EFAULT;
++ break;
++ }
++ }
++ } break;
++
++ case VCHIQ_IOC_SET_SERVICE_OPTION: {
++ VCHIQ_SET_SERVICE_OPTION_T args;
++
++ if (copy_from_user(
++ &args, (const void __user *)arg,
++ sizeof(args)) != 0) {
++ ret = -EFAULT;
++ break;
++ }
++
++ service = find_service_for_instance(instance, args.handle);
++ if (!service) {
++ ret = -EINVAL;
++ break;
++ }
++
++ status = vchiq_set_service_option(
++ args.handle, args.option, args.value);
++ } break;
++
++ case VCHIQ_IOC_DUMP_PHYS_MEM: {
++ VCHIQ_DUMP_MEM_T args;
++
++ if (copy_from_user
++ (&args, (const void __user *)arg,
++ sizeof(args)) != 0) {
++ ret = -EFAULT;
++ break;
++ }
++ dump_phys_mem(args.virt_addr, args.num_bytes);
++ } break;
++
++ case VCHIQ_IOC_LIB_VERSION: {
++ unsigned int lib_version = (unsigned int)arg;
++
++ if (lib_version < VCHIQ_VERSION_MIN)
++ ret = -EINVAL;
++ else if (lib_version >= VCHIQ_VERSION_CLOSE_DELIVERED)
++ instance->use_close_delivered = 1;
++ } break;
++
++ case VCHIQ_IOC_CLOSE_DELIVERED: {
++ VCHIQ_SERVICE_HANDLE_T handle = (VCHIQ_SERVICE_HANDLE_T)arg;
++
++ service = find_closed_service_for_instance(instance, handle);
++ if (service != NULL) {
++ USER_SERVICE_T *user_service =
++ (USER_SERVICE_T *)service->base.userdata;
++ close_delivered(user_service);
++ }
++ else
++ ret = -EINVAL;
++ } break;
++
++ default:
++ ret = -ENOTTY;
++ break;
++ }
++
++ if (service)
++ unlock_service(service);
++
++ if (ret == 0) {
++ if (status == VCHIQ_ERROR)
++ ret = -EIO;
++ else if (status == VCHIQ_RETRY)
++ ret = -EINTR;
++ }
++
++ if ((status == VCHIQ_SUCCESS) && (ret < 0) && (ret != -EINTR) &&
++ (ret != -EWOULDBLOCK))
++ vchiq_log_info(vchiq_arm_log_level,
++ " ioctl instance %lx, cmd %s -> status %d, %ld",
++ (unsigned long)instance,
++ (_IOC_NR(cmd) <= VCHIQ_IOC_MAX) ?
++ ioctl_names[_IOC_NR(cmd)] :
++ "<invalid>",
++ status, ret);
++ else
++ vchiq_log_trace(vchiq_arm_log_level,
++ " ioctl instance %lx, cmd %s -> status %d, %ld",
++ (unsigned long)instance,
++ (_IOC_NR(cmd) <= VCHIQ_IOC_MAX) ?
++ ioctl_names[_IOC_NR(cmd)] :
++ "<invalid>",
++ status, ret);
++
++ return ret;
++}
++
++/****************************************************************************
++*
++* vchiq_open
++*
++***************************************************************************/
++
++static int
++vchiq_open(struct inode *inode, struct file *file)
++{
++ int dev = iminor(inode) & 0x0f;
++ vchiq_log_info(vchiq_arm_log_level, "vchiq_open");
++ switch (dev) {
++ case VCHIQ_MINOR: {
++ int ret;
++ VCHIQ_STATE_T *state = vchiq_get_state();
++ VCHIQ_INSTANCE_T instance;
++
++ if (!state) {
++ vchiq_log_error(vchiq_arm_log_level,
++ "vchiq has no connection to VideoCore");
++ return -ENOTCONN;
++ }
++
++ instance = kzalloc(sizeof(*instance), GFP_KERNEL);
++ if (!instance)
++ return -ENOMEM;
++
++ instance->state = state;
++ instance->pid = current->tgid;
++
++ ret = vchiq_debugfs_add_instance(instance);
++ if (ret != 0) {
++ kfree(instance);
++ return ret;
++ }
++
++ sema_init(&instance->insert_event, 0);
++ sema_init(&instance->remove_event, 0);
++ mutex_init(&instance->completion_mutex);
++ mutex_init(&instance->bulk_waiter_list_mutex);
++ INIT_LIST_HEAD(&instance->bulk_waiter_list);
++
++ file->private_data = instance;
++ } break;
++
++ default:
++ vchiq_log_error(vchiq_arm_log_level,
++ "Unknown minor device: %d", dev);
++ return -ENXIO;
++ }
++
++ return 0;
++}
++
++/****************************************************************************
++*
++* vchiq_release
++*
++***************************************************************************/
++
++static int
++vchiq_release(struct inode *inode, struct file *file)
++{
++ int dev = iminor(inode) & 0x0f;
++ int ret = 0;
++ switch (dev) {
++ case VCHIQ_MINOR: {
++ VCHIQ_INSTANCE_T instance = file->private_data;
++ VCHIQ_STATE_T *state = vchiq_get_state();
++ VCHIQ_SERVICE_T *service;
++ int i;
++
++ vchiq_log_info(vchiq_arm_log_level,
++ "vchiq_release: instance=%lx",
++ (unsigned long)instance);
++
++ if (!state) {
++ ret = -EPERM;
++ goto out;
++ }
++
++ /* Ensure videocore is awake to allow termination. */
++ vchiq_use_internal(instance->state, NULL,
++ USE_TYPE_VCHIQ);
++
++ mutex_lock(&instance->completion_mutex);
++
++ /* Wake the completion thread and ask it to exit */
++ instance->closing = 1;
++ up(&instance->insert_event);
++
++ mutex_unlock(&instance->completion_mutex);
++
++ /* Wake the slot handler if the completion queue is full. */
++ up(&instance->remove_event);
++
++ /* Mark all services for termination... */
++ i = 0;
++ while ((service = next_service_by_instance(state, instance,
++ &i)) != NULL) {
++ USER_SERVICE_T *user_service = service->base.userdata;
++
++ /* Wake the slot handler if the msg queue is full. */
++ up(&user_service->remove_event);
++
++ vchiq_terminate_service_internal(service);
++ unlock_service(service);
++ }
++
++ /* ...and wait for them to die */
++ i = 0;
++ while ((service = next_service_by_instance(state, instance, &i))
++ != NULL) {
++ USER_SERVICE_T *user_service = service->base.userdata;
++
++ down(&service->remove_event);
++
++ BUG_ON(service->srvstate != VCHIQ_SRVSTATE_FREE);
++
++ spin_lock(&msg_queue_spinlock);
++
++ while (user_service->msg_remove !=
++ user_service->msg_insert) {
++ VCHIQ_HEADER_T *header = user_service->
++ msg_queue[user_service->msg_remove &
++ (MSG_QUEUE_SIZE - 1)];
++ user_service->msg_remove++;
++ spin_unlock(&msg_queue_spinlock);
++
++ if (header)
++ vchiq_release_message(
++ service->handle,
++ header);
++ spin_lock(&msg_queue_spinlock);
++ }
++
++ spin_unlock(&msg_queue_spinlock);
++
++ unlock_service(service);
++ }
++
++ /* Release any closed services */
++ while (instance->completion_remove !=
++ instance->completion_insert) {
++ VCHIQ_COMPLETION_DATA_T *completion;
++ VCHIQ_SERVICE_T *service;
++ completion = &instance->completions[
++ instance->completion_remove &
++ (MAX_COMPLETIONS - 1)];
++ service = completion->service_userdata;
++ if (completion->reason == VCHIQ_SERVICE_CLOSED)
++ {
++ USER_SERVICE_T *user_service =
++ service->base.userdata;
++
++ /* Wake any blocked user-thread */
++ if (instance->use_close_delivered)
++ up(&user_service->close_event);
++ unlock_service(service);
++ }
++ instance->completion_remove++;
++ }
++
++ /* Release the PEER service count. */
++ vchiq_release_internal(instance->state, NULL);
++
++ {
++ struct list_head *pos, *next;
++ list_for_each_safe(pos, next,
++ &instance->bulk_waiter_list) {
++ struct bulk_waiter_node *waiter;
++ waiter = list_entry(pos,
++ struct bulk_waiter_node,
++ list);
++ list_del(pos);
++ vchiq_log_info(vchiq_arm_log_level,
++ "bulk_waiter - cleaned up %x "
++ "for pid %d",
++ (unsigned int)waiter, waiter->pid);
++ kfree(waiter);
++ }
++ }
++
++ vchiq_debugfs_remove_instance(instance);
++
++ kfree(instance);
++ file->private_data = NULL;
++ } break;
++
++ default:
++ vchiq_log_error(vchiq_arm_log_level,
++ "Unknown minor device: %d", dev);
++ ret = -ENXIO;
++ }
++
++out:
++ return ret;
++}
++
++/****************************************************************************
++*
++* vchiq_dump
++*
++***************************************************************************/
++
++void
++vchiq_dump(void *dump_context, const char *str, int len)
++{
++ DUMP_CONTEXT_T *context = (DUMP_CONTEXT_T *)dump_context;
++
++ if (context->actual < context->space) {
++ int copy_bytes;
++ if (context->offset > 0) {
++ int skip_bytes = min(len, (int)context->offset);
++ str += skip_bytes;
++ len -= skip_bytes;
++ context->offset -= skip_bytes;
++ if (context->offset > 0)
++ return;
++ }
++ copy_bytes = min(len, (int)(context->space - context->actual));
++ if (copy_bytes == 0)
++ return;
++ if (copy_to_user(context->buf + context->actual, str,
++ copy_bytes))
++ context->actual = -EFAULT;
++ context->actual += copy_bytes;
++ len -= copy_bytes;
++
++ /* If tne terminating NUL is included in the length, then it
++ ** marks the end of a line and should be replaced with a
++ ** carriage return. */
++ if ((len == 0) && (str[copy_bytes - 1] == '\0')) {
++ char cr = '\n';
++ if (copy_to_user(context->buf + context->actual - 1,
++ &cr, 1))
++ context->actual = -EFAULT;
++ }
++ }
++}
++
++/****************************************************************************
++*
++* vchiq_dump_platform_instance_state
++*
++***************************************************************************/
++
++void
++vchiq_dump_platform_instances(void *dump_context)
++{
++ VCHIQ_STATE_T *state = vchiq_get_state();
++ char buf[80];
++ int len;
++ int i;
++
++ /* There is no list of instances, so instead scan all services,
++ marking those that have been dumped. */
++
++ for (i = 0; i < state->unused_service; i++) {
++ VCHIQ_SERVICE_T *service = state->services[i];
++ VCHIQ_INSTANCE_T instance;
++
++ if (service && (service->base.callback == service_callback)) {
++ instance = service->instance;
++ if (instance)
++ instance->mark = 0;
++ }
++ }
++
++ for (i = 0; i < state->unused_service; i++) {
++ VCHIQ_SERVICE_T *service = state->services[i];
++ VCHIQ_INSTANCE_T instance;
++
++ if (service && (service->base.callback == service_callback)) {
++ instance = service->instance;
++ if (instance && !instance->mark) {
++ len = snprintf(buf, sizeof(buf),
++ "Instance %x: pid %d,%s completions "
++ "%d/%d",
++ (unsigned int)instance, instance->pid,
++ instance->connected ? " connected, " :
++ "",
++ instance->completion_insert -
++ instance->completion_remove,
++ MAX_COMPLETIONS);
++
++ vchiq_dump(dump_context, buf, len + 1);
++
++ instance->mark = 1;
++ }
++ }
++ }
++}
++
++/****************************************************************************
++*
++* vchiq_dump_platform_service_state
++*
++***************************************************************************/
++
++void
++vchiq_dump_platform_service_state(void *dump_context, VCHIQ_SERVICE_T *service)
++{
++ USER_SERVICE_T *user_service = (USER_SERVICE_T *)service->base.userdata;
++ char buf[80];
++ int len;
++
++ len = snprintf(buf, sizeof(buf), " instance %x",
++ (unsigned int)service->instance);
++
++ if ((service->base.callback == service_callback) &&
++ user_service->is_vchi) {
++ len += snprintf(buf + len, sizeof(buf) - len,
++ ", %d/%d messages",
++ user_service->msg_insert - user_service->msg_remove,
++ MSG_QUEUE_SIZE);
++
++ if (user_service->dequeue_pending)
++ len += snprintf(buf + len, sizeof(buf) - len,
++ " (dequeue pending)");
++ }
++
++ vchiq_dump(dump_context, buf, len + 1);
++}
++
++/****************************************************************************
++*
++* dump_user_mem
++*
++***************************************************************************/
++
++static void
++dump_phys_mem(void *virt_addr, uint32_t num_bytes)
++{
++ int rc;
++ uint8_t *end_virt_addr = virt_addr + num_bytes;
++ int num_pages;
++ int offset;
++ int end_offset;
++ int page_idx;
++ int prev_idx;
++ struct page *page;
++ struct page **pages;
++ uint8_t *kmapped_virt_ptr;
++
++ /* Align virtAddr and endVirtAddr to 16 byte boundaries. */
++
++ virt_addr = (void *)((unsigned long)virt_addr & ~0x0fuL);
++ end_virt_addr = (void *)(((unsigned long)end_virt_addr + 15uL) &
++ ~0x0fuL);
++
++ offset = (int)(long)virt_addr & (PAGE_SIZE - 1);
++ end_offset = (int)(long)end_virt_addr & (PAGE_SIZE - 1);
++
++ num_pages = (offset + num_bytes + PAGE_SIZE - 1) / PAGE_SIZE;
++
++ pages = kmalloc(sizeof(struct page *) * num_pages, GFP_KERNEL);
++ if (pages == NULL) {
++ vchiq_log_error(vchiq_arm_log_level,
++ "Unable to allocation memory for %d pages\n",
++ num_pages);
++ return;
++ }
++
++ down_read(&current->mm->mmap_sem);
++ rc = get_user_pages(current, /* task */
++ current->mm, /* mm */
++ (unsigned long)virt_addr, /* start */
++ num_pages, /* len */
++ 0, /* write */
++ 0, /* force */
++ pages, /* pages (array of page pointers) */
++ NULL); /* vmas */
++ up_read(&current->mm->mmap_sem);
++
++ prev_idx = -1;
++ page = NULL;
++
++ while (offset < end_offset) {
++
++ int page_offset = offset % PAGE_SIZE;
++ page_idx = offset / PAGE_SIZE;
++
++ if (page_idx != prev_idx) {
++
++ if (page != NULL)
++ kunmap(page);
++ page = pages[page_idx];
++ kmapped_virt_ptr = kmap(page);
++
++ prev_idx = page_idx;
++ }
++
++ if (vchiq_arm_log_level >= VCHIQ_LOG_TRACE)
++ vchiq_log_dump_mem("ph",
++ (uint32_t)(unsigned long)&kmapped_virt_ptr[
++ page_offset],
++ &kmapped_virt_ptr[page_offset], 16);
++
++ offset += 16;
++ }
++ if (page != NULL)
++ kunmap(page);
++
++ for (page_idx = 0; page_idx < num_pages; page_idx++)
++ page_cache_release(pages[page_idx]);
++
++ kfree(pages);
++}
++
++/****************************************************************************
++*
++* vchiq_read
++*
++***************************************************************************/
++
++static ssize_t
++vchiq_read(struct file *file, char __user *buf,
++ size_t count, loff_t *ppos)
++{
++ DUMP_CONTEXT_T context;
++ context.buf = buf;
++ context.actual = 0;
++ context.space = count;
++ context.offset = *ppos;
++
++ vchiq_dump_state(&context, &g_state);
++
++ *ppos += context.actual;
++
++ return context.actual;
++}
++
++VCHIQ_STATE_T *
++vchiq_get_state(void)
++{
++
++ if (g_state.remote == NULL)
++ printk(KERN_ERR "%s: g_state.remote == NULL\n", __func__);
++ else if (g_state.remote->initialised != 1)
++ printk(KERN_NOTICE "%s: g_state.remote->initialised != 1 (%d)\n",
++ __func__, g_state.remote->initialised);
++
++ return ((g_state.remote != NULL) &&
++ (g_state.remote->initialised == 1)) ? &g_state : NULL;
++}
++
++static const struct file_operations
++vchiq_fops = {
++ .owner = THIS_MODULE,
++ .unlocked_ioctl = vchiq_ioctl,
++ .open = vchiq_open,
++ .release = vchiq_release,
++ .read = vchiq_read
++};
++
++/*
++ * Autosuspend related functionality
++ */
++
++int
++vchiq_videocore_wanted(VCHIQ_STATE_T *state)
++{
++ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
++ if (!arm_state)
++ /* autosuspend not supported - always return wanted */
++ return 1;
++ else if (arm_state->blocked_count)
++ return 1;
++ else if (!arm_state->videocore_use_count)
++ /* usage count zero - check for override unless we're forcing */
++ if (arm_state->resume_blocked)
++ return 0;
++ else
++ return vchiq_platform_videocore_wanted(state);
++ else
++ /* non-zero usage count - videocore still required */
++ return 1;
++}
++
++static VCHIQ_STATUS_T
++vchiq_keepalive_vchiq_callback(VCHIQ_REASON_T reason,
++ VCHIQ_HEADER_T *header,
++ VCHIQ_SERVICE_HANDLE_T service_user,
++ void *bulk_user)
++{
++ vchiq_log_error(vchiq_susp_log_level,
++ "%s callback reason %d", __func__, reason);
++ return 0;
++}
++
++static int
++vchiq_keepalive_thread_func(void *v)
++{
++ VCHIQ_STATE_T *state = (VCHIQ_STATE_T *) v;
++ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
++
++ VCHIQ_STATUS_T status;
++ VCHIQ_INSTANCE_T instance;
++ VCHIQ_SERVICE_HANDLE_T ka_handle;
++
++ VCHIQ_SERVICE_PARAMS_T params = {
++ .fourcc = VCHIQ_MAKE_FOURCC('K', 'E', 'E', 'P'),
++ .callback = vchiq_keepalive_vchiq_callback,
++ .version = KEEPALIVE_VER,
++ .version_min = KEEPALIVE_VER_MIN
++ };
++
++ status = vchiq_initialise(&instance);
++ if (status != VCHIQ_SUCCESS) {
++ vchiq_log_error(vchiq_susp_log_level,
++ "%s vchiq_initialise failed %d", __func__, status);
++ goto exit;
++ }
++
++ status = vchiq_connect(instance);
++ if (status != VCHIQ_SUCCESS) {
++ vchiq_log_error(vchiq_susp_log_level,
++ "%s vchiq_connect failed %d", __func__, status);
++ goto shutdown;
++ }
++
++ status = vchiq_add_service(instance, &params, &ka_handle);
++ if (status != VCHIQ_SUCCESS) {
++ vchiq_log_error(vchiq_susp_log_level,
++ "%s vchiq_open_service failed %d", __func__, status);
++ goto shutdown;
++ }
++
++ while (1) {
++ long rc = 0, uc = 0;
++ if (wait_for_completion_interruptible(&arm_state->ka_evt)
++ != 0) {
++ vchiq_log_error(vchiq_susp_log_level,
++ "%s interrupted", __func__);
++ flush_signals(current);
++ continue;
++ }
++
++ /* read and clear counters. Do release_count then use_count to
++ * prevent getting more releases than uses */
++ rc = atomic_xchg(&arm_state->ka_release_count, 0);
++ uc = atomic_xchg(&arm_state->ka_use_count, 0);
++
++ /* Call use/release service the requisite number of times.
++ * Process use before release so use counts don't go negative */
++ while (uc--) {
++ atomic_inc(&arm_state->ka_use_ack_count);
++ status = vchiq_use_service(ka_handle);
++ if (status != VCHIQ_SUCCESS) {
++ vchiq_log_error(vchiq_susp_log_level,
++ "%s vchiq_use_service error %d",
++ __func__, status);
++ }
++ }
++ while (rc--) {
++ status = vchiq_release_service(ka_handle);
++ if (status != VCHIQ_SUCCESS) {
++ vchiq_log_error(vchiq_susp_log_level,
++ "%s vchiq_release_service error %d",
++ __func__, status);
++ }
++ }
++ }
++
++shutdown:
++ vchiq_shutdown(instance);
++exit:
++ return 0;
++}
++
++
++
++VCHIQ_STATUS_T
++vchiq_arm_init_state(VCHIQ_STATE_T *state, VCHIQ_ARM_STATE_T *arm_state)
++{
++ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
++
++ if (arm_state) {
++ rwlock_init(&arm_state->susp_res_lock);
++
++ init_completion(&arm_state->ka_evt);
++ atomic_set(&arm_state->ka_use_count, 0);
++ atomic_set(&arm_state->ka_use_ack_count, 0);
++ atomic_set(&arm_state->ka_release_count, 0);
++
++ init_completion(&arm_state->vc_suspend_complete);
++
++ init_completion(&arm_state->vc_resume_complete);
++ /* Initialise to 'done' state. We only want to block on resume
++ * completion while videocore is suspended. */
++ set_resume_state(arm_state, VC_RESUME_RESUMED);
++
++ init_completion(&arm_state->resume_blocker);
++ /* Initialise to 'done' state. We only want to block on this
++ * completion while resume is blocked */
++ complete_all(&arm_state->resume_blocker);
++
++ init_completion(&arm_state->blocked_blocker);
++ /* Initialise to 'done' state. We only want to block on this
++ * completion while things are waiting on the resume blocker */
++ complete_all(&arm_state->blocked_blocker);
++
++ arm_state->suspend_timer_timeout = SUSPEND_TIMER_TIMEOUT_MS;
++ arm_state->suspend_timer_running = 0;
++ init_timer(&arm_state->suspend_timer);
++ arm_state->suspend_timer.data = (unsigned long)(state);
++ arm_state->suspend_timer.function = suspend_timer_callback;
++
++ arm_state->first_connect = 0;
++
++ }
++ return status;
++}
++
++/*
++** Functions to modify the state variables;
++** set_suspend_state
++** set_resume_state
++**
++** There are more state variables than we might like, so ensure they remain in
++** step. Suspend and resume state are maintained separately, since most of
++** these state machines can operate independently. However, there are a few
++** states where state transitions in one state machine cause a reset to the
++** other state machine. In addition, there are some completion events which
++** need to occur on state machine reset and end-state(s), so these are also
++** dealt with in these functions.
++**
++** In all states we set the state variable according to the input, but in some
++** cases we perform additional steps outlined below;
++**
++** VC_SUSPEND_IDLE - Initialise the suspend completion at the same time.
++** The suspend completion is completed after any suspend
++** attempt. When we reset the state machine we also reset
++** the completion. This reset occurs when videocore is
++** resumed, and also if we initiate suspend after a suspend
++** failure.
++**
++** VC_SUSPEND_IN_PROGRESS - This state is considered the point of no return for
++** suspend - ie from this point on we must try to suspend
++** before resuming can occur. We therefore also reset the
++** resume state machine to VC_RESUME_IDLE in this state.
++**
++** VC_SUSPEND_SUSPENDED - Suspend has completed successfully. Also call
++** complete_all on the suspend completion to notify
++** anything waiting for suspend to happen.
++**
++** VC_SUSPEND_REJECTED - Videocore rejected suspend. Videocore will also
++** initiate resume, so no need to alter resume state.
++** We call complete_all on the suspend completion to notify
++** of suspend rejection.
++**
++** VC_SUSPEND_FAILED - We failed to initiate videocore suspend. We notify the
++** suspend completion and reset the resume state machine.
++**
++** VC_RESUME_IDLE - Initialise the resume completion at the same time. The
++** resume completion is in it's 'done' state whenever
++** videcore is running. Therfore, the VC_RESUME_IDLE state
++** implies that videocore is suspended.
++** Hence, any thread which needs to wait until videocore is
++** running can wait on this completion - it will only block
++** if videocore is suspended.
++**
++** VC_RESUME_RESUMED - Resume has completed successfully. Videocore is running.
++** Call complete_all on the resume completion to unblock
++** any threads waiting for resume. Also reset the suspend
++** state machine to it's idle state.
++**
++** VC_RESUME_FAILED - Currently unused - no mechanism to fail resume exists.
++*/
++
++void
++set_suspend_state(VCHIQ_ARM_STATE_T *arm_state,
++ enum vc_suspend_status new_state)
++{
++ /* set the state in all cases */
++ arm_state->vc_suspend_state = new_state;
++
++ /* state specific additional actions */
++ switch (new_state) {
++ case VC_SUSPEND_FORCE_CANCELED:
++ complete_all(&arm_state->vc_suspend_complete);
++ break;
++ case VC_SUSPEND_REJECTED:
++ complete_all(&arm_state->vc_suspend_complete);
++ break;
++ case VC_SUSPEND_FAILED:
++ complete_all(&arm_state->vc_suspend_complete);
++ arm_state->vc_resume_state = VC_RESUME_RESUMED;
++ complete_all(&arm_state->vc_resume_complete);
++ break;
++ case VC_SUSPEND_IDLE:
++ reinit_completion(&arm_state->vc_suspend_complete);
++ break;
++ case VC_SUSPEND_REQUESTED:
++ break;
++ case VC_SUSPEND_IN_PROGRESS:
++ set_resume_state(arm_state, VC_RESUME_IDLE);
++ break;
++ case VC_SUSPEND_SUSPENDED:
++ complete_all(&arm_state->vc_suspend_complete);
++ break;
++ default:
++ BUG();
++ break;
++ }
++}
++
++void
++set_resume_state(VCHIQ_ARM_STATE_T *arm_state,
++ enum vc_resume_status new_state)
++{
++ /* set the state in all cases */
++ arm_state->vc_resume_state = new_state;
++
++ /* state specific additional actions */
++ switch (new_state) {
++ case VC_RESUME_FAILED:
++ break;
++ case VC_RESUME_IDLE:
++ reinit_completion(&arm_state->vc_resume_complete);
++ break;
++ case VC_RESUME_REQUESTED:
++ break;
++ case VC_RESUME_IN_PROGRESS:
++ break;
++ case VC_RESUME_RESUMED:
++ complete_all(&arm_state->vc_resume_complete);
++ set_suspend_state(arm_state, VC_SUSPEND_IDLE);
++ break;
++ default:
++ BUG();
++ break;
++ }
++}
++
++
++/* should be called with the write lock held */
++inline void
++start_suspend_timer(VCHIQ_ARM_STATE_T *arm_state)
++{
++ del_timer(&arm_state->suspend_timer);
++ arm_state->suspend_timer.expires = jiffies +
++ msecs_to_jiffies(arm_state->
++ suspend_timer_timeout);
++ add_timer(&arm_state->suspend_timer);
++ arm_state->suspend_timer_running = 1;
++}
++
++/* should be called with the write lock held */
++static inline void
++stop_suspend_timer(VCHIQ_ARM_STATE_T *arm_state)
++{
++ if (arm_state->suspend_timer_running) {
++ del_timer(&arm_state->suspend_timer);
++ arm_state->suspend_timer_running = 0;
++ }
++}
++
++static inline int
++need_resume(VCHIQ_STATE_T *state)
++{
++ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
++ return (arm_state->vc_suspend_state > VC_SUSPEND_IDLE) &&
++ (arm_state->vc_resume_state < VC_RESUME_REQUESTED) &&
++ vchiq_videocore_wanted(state);
++}
++
++static int
++block_resume(VCHIQ_ARM_STATE_T *arm_state)
++{
++ int status = VCHIQ_SUCCESS;
++ const unsigned long timeout_val =
++ msecs_to_jiffies(FORCE_SUSPEND_TIMEOUT_MS);
++ int resume_count = 0;
++
++ /* Allow any threads which were blocked by the last force suspend to
++ * complete if they haven't already. Only give this one shot; if
++ * blocked_count is incremented after blocked_blocker is completed
++ * (which only happens when blocked_count hits 0) then those threads
++ * will have to wait until next time around */
++ if (arm_state->blocked_count) {
++ reinit_completion(&arm_state->blocked_blocker);
++ write_unlock_bh(&arm_state->susp_res_lock);
++ vchiq_log_info(vchiq_susp_log_level, "%s wait for previously "
++ "blocked clients", __func__);
++ if (wait_for_completion_interruptible_timeout(
++ &arm_state->blocked_blocker, timeout_val)
++ <= 0) {
++ vchiq_log_error(vchiq_susp_log_level, "%s wait for "
++ "previously blocked clients failed" , __func__);
++ status = VCHIQ_ERROR;
++ write_lock_bh(&arm_state->susp_res_lock);
++ goto out;
++ }
++ vchiq_log_info(vchiq_susp_log_level, "%s previously blocked "
++ "clients resumed", __func__);
++ write_lock_bh(&arm_state->susp_res_lock);
++ }
++
++ /* We need to wait for resume to complete if it's in process */
++ while (arm_state->vc_resume_state != VC_RESUME_RESUMED &&
++ arm_state->vc_resume_state > VC_RESUME_IDLE) {
++ if (resume_count > 1) {
++ status = VCHIQ_ERROR;
++ vchiq_log_error(vchiq_susp_log_level, "%s waited too "
++ "many times for resume" , __func__);
++ goto out;
++ }
++ write_unlock_bh(&arm_state->susp_res_lock);
++ vchiq_log_info(vchiq_susp_log_level, "%s wait for resume",
++ __func__);
++ if (wait_for_completion_interruptible_timeout(
++ &arm_state->vc_resume_complete, timeout_val)
++ <= 0) {
++ vchiq_log_error(vchiq_susp_log_level, "%s wait for "
++ "resume failed (%s)", __func__,
++ resume_state_names[arm_state->vc_resume_state +
++ VC_RESUME_NUM_OFFSET]);
++ status = VCHIQ_ERROR;
++ write_lock_bh(&arm_state->susp_res_lock);
++ goto out;
++ }
++ vchiq_log_info(vchiq_susp_log_level, "%s resumed", __func__);
++ write_lock_bh(&arm_state->susp_res_lock);
++ resume_count++;
++ }
++ reinit_completion(&arm_state->resume_blocker);
++ arm_state->resume_blocked = 1;
++
++out:
++ return status;
++}
++
++static inline void
++unblock_resume(VCHIQ_ARM_STATE_T *arm_state)
++{
++ complete_all(&arm_state->resume_blocker);
++ arm_state->resume_blocked = 0;
++}
++
++/* Initiate suspend via slot handler. Should be called with the write lock
++ * held */
++VCHIQ_STATUS_T
++vchiq_arm_vcsuspend(VCHIQ_STATE_T *state)
++{
++ VCHIQ_STATUS_T status = VCHIQ_ERROR;
++ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
++
++ if (!arm_state)
++ goto out;
++
++ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
++ status = VCHIQ_SUCCESS;
++
++
++ switch (arm_state->vc_suspend_state) {
++ case VC_SUSPEND_REQUESTED:
++ vchiq_log_info(vchiq_susp_log_level, "%s: suspend already "
++ "requested", __func__);
++ break;
++ case VC_SUSPEND_IN_PROGRESS:
++ vchiq_log_info(vchiq_susp_log_level, "%s: suspend already in "
++ "progress", __func__);
++ break;
++
++ default:
++ /* We don't expect to be in other states, so log but continue
++ * anyway */
++ vchiq_log_error(vchiq_susp_log_level,
++ "%s unexpected suspend state %s", __func__,
++ suspend_state_names[arm_state->vc_suspend_state +
++ VC_SUSPEND_NUM_OFFSET]);
++ /* fall through */
++ case VC_SUSPEND_REJECTED:
++ case VC_SUSPEND_FAILED:
++ /* Ensure any idle state actions have been run */
++ set_suspend_state(arm_state, VC_SUSPEND_IDLE);
++ /* fall through */
++ case VC_SUSPEND_IDLE:
++ vchiq_log_info(vchiq_susp_log_level,
++ "%s: suspending", __func__);
++ set_suspend_state(arm_state, VC_SUSPEND_REQUESTED);
++ /* kick the slot handler thread to initiate suspend */
++ request_poll(state, NULL, 0);
++ break;
++ }
++
++out:
++ vchiq_log_trace(vchiq_susp_log_level, "%s exit %d", __func__, status);
++ return status;
++}
++
++void
++vchiq_platform_check_suspend(VCHIQ_STATE_T *state)
++{
++ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
++ int susp = 0;
++
++ if (!arm_state)
++ goto out;
++
++ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
++
++ write_lock_bh(&arm_state->susp_res_lock);
++ if (arm_state->vc_suspend_state == VC_SUSPEND_REQUESTED &&
++ arm_state->vc_resume_state == VC_RESUME_RESUMED) {
++ set_suspend_state(arm_state, VC_SUSPEND_IN_PROGRESS);
++ susp = 1;
++ }
++ write_unlock_bh(&arm_state->susp_res_lock);
++
++ if (susp)
++ vchiq_platform_suspend(state);
++
++out:
++ vchiq_log_trace(vchiq_susp_log_level, "%s exit", __func__);
++ return;
++}
++
++
++static void
++output_timeout_error(VCHIQ_STATE_T *state)
++{
++ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
++ char service_err[50] = "";
++ int vc_use_count = arm_state->videocore_use_count;
++ int active_services = state->unused_service;
++ int i;
++
++ if (!arm_state->videocore_use_count) {
++ snprintf(service_err, 50, " Videocore usecount is 0");
++ goto output_msg;
++ }
++ for (i = 0; i < active_services; i++) {
++ VCHIQ_SERVICE_T *service_ptr = state->services[i];
++ if (service_ptr && service_ptr->service_use_count &&
++ (service_ptr->srvstate != VCHIQ_SRVSTATE_FREE)) {
++ snprintf(service_err, 50, " %c%c%c%c(%d) service has "
++ "use count %d%s", VCHIQ_FOURCC_AS_4CHARS(
++ service_ptr->base.fourcc),
++ service_ptr->client_id,
++ service_ptr->service_use_count,
++ service_ptr->service_use_count ==
++ vc_use_count ? "" : " (+ more)");
++ break;
++ }
++ }
++
++output_msg:
++ vchiq_log_error(vchiq_susp_log_level,
++ "timed out waiting for vc suspend (%d).%s",
++ arm_state->autosuspend_override, service_err);
++
++}
++
++/* Try to get videocore into suspended state, regardless of autosuspend state.
++** We don't actually force suspend, since videocore may get into a bad state
++** if we force suspend at a bad time. Instead, we wait for autosuspend to
++** determine a good point to suspend. If this doesn't happen within 100ms we
++** report failure.
++**
++** Returns VCHIQ_SUCCESS if videocore suspended successfully, VCHIQ_RETRY if
++** videocore failed to suspend in time or VCHIQ_ERROR if interrupted.
++*/
++VCHIQ_STATUS_T
++vchiq_arm_force_suspend(VCHIQ_STATE_T *state)
++{
++ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
++ VCHIQ_STATUS_T status = VCHIQ_ERROR;
++ long rc = 0;
++ int repeat = -1;
++
++ if (!arm_state)
++ goto out;
++
++ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
++
++ write_lock_bh(&arm_state->susp_res_lock);
++
++ status = block_resume(arm_state);
++ if (status != VCHIQ_SUCCESS)
++ goto unlock;
++ if (arm_state->vc_suspend_state == VC_SUSPEND_SUSPENDED) {
++ /* Already suspended - just block resume and exit */
++ vchiq_log_info(vchiq_susp_log_level, "%s already suspended",
++ __func__);
++ status = VCHIQ_SUCCESS;
++ goto unlock;
++ } else if (arm_state->vc_suspend_state <= VC_SUSPEND_IDLE) {
++ /* initiate suspend immediately in the case that we're waiting
++ * for the timeout */
++ stop_suspend_timer(arm_state);
++ if (!vchiq_videocore_wanted(state)) {
++ vchiq_log_info(vchiq_susp_log_level, "%s videocore "
++ "idle, initiating suspend", __func__);
++ status = vchiq_arm_vcsuspend(state);
++ } else if (arm_state->autosuspend_override <
++ FORCE_SUSPEND_FAIL_MAX) {
++ vchiq_log_info(vchiq_susp_log_level, "%s letting "
++ "videocore go idle", __func__);
++ status = VCHIQ_SUCCESS;
++ } else {
++ vchiq_log_warning(vchiq_susp_log_level, "%s failed too "
++ "many times - attempting suspend", __func__);
++ status = vchiq_arm_vcsuspend(state);
++ }
++ } else {
++ vchiq_log_info(vchiq_susp_log_level, "%s videocore suspend "
++ "in progress - wait for completion", __func__);
++ status = VCHIQ_SUCCESS;
++ }
++
++ /* Wait for suspend to happen due to system idle (not forced..) */
++ if (status != VCHIQ_SUCCESS)
++ goto unblock_resume;
++
++ do {
++ write_unlock_bh(&arm_state->susp_res_lock);
++
++ rc = wait_for_completion_interruptible_timeout(
++ &arm_state->vc_suspend_complete,
++ msecs_to_jiffies(FORCE_SUSPEND_TIMEOUT_MS));
++
++ write_lock_bh(&arm_state->susp_res_lock);
++ if (rc < 0) {
++ vchiq_log_warning(vchiq_susp_log_level, "%s "
++ "interrupted waiting for suspend", __func__);
++ status = VCHIQ_ERROR;
++ goto unblock_resume;
++ } else if (rc == 0) {
++ if (arm_state->vc_suspend_state > VC_SUSPEND_IDLE) {
++ /* Repeat timeout once if in progress */
++ if (repeat < 0) {
++ repeat = 1;
++ continue;
++ }
++ }
++ arm_state->autosuspend_override++;
++ output_timeout_error(state);
++
++ status = VCHIQ_RETRY;
++ goto unblock_resume;
++ }
++ } while (0 < (repeat--));
++
++ /* Check and report state in case we need to abort ARM suspend */
++ if (arm_state->vc_suspend_state != VC_SUSPEND_SUSPENDED) {
++ status = VCHIQ_RETRY;
++ vchiq_log_error(vchiq_susp_log_level,
++ "%s videocore suspend failed (state %s)", __func__,
++ suspend_state_names[arm_state->vc_suspend_state +
++ VC_SUSPEND_NUM_OFFSET]);
++ /* Reset the state only if it's still in an error state.
++ * Something could have already initiated another suspend. */
++ if (arm_state->vc_suspend_state < VC_SUSPEND_IDLE)
++ set_suspend_state(arm_state, VC_SUSPEND_IDLE);
++
++ goto unblock_resume;
++ }
++
++ /* successfully suspended - unlock and exit */
++ goto unlock;
++
++unblock_resume:
++ /* all error states need to unblock resume before exit */
++ unblock_resume(arm_state);
++
++unlock:
++ write_unlock_bh(&arm_state->susp_res_lock);
++
++out:
++ vchiq_log_trace(vchiq_susp_log_level, "%s exit %d", __func__, status);
++ return status;
++}
++
++void
++vchiq_check_suspend(VCHIQ_STATE_T *state)
++{
++ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
++
++ if (!arm_state)
++ goto out;
++
++ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
++
++ write_lock_bh(&arm_state->susp_res_lock);
++ if (arm_state->vc_suspend_state != VC_SUSPEND_SUSPENDED &&
++ arm_state->first_connect &&
++ !vchiq_videocore_wanted(state)) {
++ vchiq_arm_vcsuspend(state);
++ }
++ write_unlock_bh(&arm_state->susp_res_lock);
++
++out:
++ vchiq_log_trace(vchiq_susp_log_level, "%s exit", __func__);
++ return;
++}
++
++
++int
++vchiq_arm_allow_resume(VCHIQ_STATE_T *state)
++{
++ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
++ int resume = 0;
++ int ret = -1;
++
++ if (!arm_state)
++ goto out;
++
++ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
++
++ write_lock_bh(&arm_state->susp_res_lock);
++ unblock_resume(arm_state);
++ resume = vchiq_check_resume(state);
++ write_unlock_bh(&arm_state->susp_res_lock);
++
++ if (resume) {
++ if (wait_for_completion_interruptible(
++ &arm_state->vc_resume_complete) < 0) {
++ vchiq_log_error(vchiq_susp_log_level,
++ "%s interrupted", __func__);
++ /* failed, cannot accurately derive suspend
++ * state, so exit early. */
++ goto out;
++ }
++ }
++
++ read_lock_bh(&arm_state->susp_res_lock);
++ if (arm_state->vc_suspend_state == VC_SUSPEND_SUSPENDED) {
++ vchiq_log_info(vchiq_susp_log_level,
++ "%s: Videocore remains suspended", __func__);
++ } else {
++ vchiq_log_info(vchiq_susp_log_level,
++ "%s: Videocore resumed", __func__);
++ ret = 0;
++ }
++ read_unlock_bh(&arm_state->susp_res_lock);
++out:
++ vchiq_log_trace(vchiq_susp_log_level, "%s exit %d", __func__, ret);
++ return ret;
++}
++
++/* This function should be called with the write lock held */
++int
++vchiq_check_resume(VCHIQ_STATE_T *state)
++{
++ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
++ int resume = 0;
++
++ if (!arm_state)
++ goto out;
++
++ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
++
++ if (need_resume(state)) {
++ set_resume_state(arm_state, VC_RESUME_REQUESTED);
++ request_poll(state, NULL, 0);
++ resume = 1;
++ }
++
++out:
++ vchiq_log_trace(vchiq_susp_log_level, "%s exit", __func__);
++ return resume;
++}
++
++void
++vchiq_platform_check_resume(VCHIQ_STATE_T *state)
++{
++ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
++ int res = 0;
++
++ if (!arm_state)
++ goto out;
++
++ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
++
++ write_lock_bh(&arm_state->susp_res_lock);
++ if (arm_state->wake_address == 0) {
++ vchiq_log_info(vchiq_susp_log_level,
++ "%s: already awake", __func__);
++ goto unlock;
++ }
++ if (arm_state->vc_resume_state == VC_RESUME_IN_PROGRESS) {
++ vchiq_log_info(vchiq_susp_log_level,
++ "%s: already resuming", __func__);
++ goto unlock;
++ }
++
++ if (arm_state->vc_resume_state == VC_RESUME_REQUESTED) {
++ set_resume_state(arm_state, VC_RESUME_IN_PROGRESS);
++ res = 1;
++ } else
++ vchiq_log_trace(vchiq_susp_log_level,
++ "%s: not resuming (resume state %s)", __func__,
++ resume_state_names[arm_state->vc_resume_state +
++ VC_RESUME_NUM_OFFSET]);
++
++unlock:
++ write_unlock_bh(&arm_state->susp_res_lock);
++
++ if (res)
++ vchiq_platform_resume(state);
++
++out:
++ vchiq_log_trace(vchiq_susp_log_level, "%s exit", __func__);
++ return;
++
++}
++
++
++
++VCHIQ_STATUS_T
++vchiq_use_internal(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service,
++ enum USE_TYPE_E use_type)
++{
++ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
++ VCHIQ_STATUS_T ret = VCHIQ_SUCCESS;
++ char entity[16];
++ int *entity_uc;
++ int local_uc, local_entity_uc;
++
++ if (!arm_state)
++ goto out;
++
++ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
++
++ if (use_type == USE_TYPE_VCHIQ) {
++ sprintf(entity, "VCHIQ: ");
++ entity_uc = &arm_state->peer_use_count;
++ } else if (service) {
++ sprintf(entity, "%c%c%c%c:%03d",
++ VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc),
++ service->client_id);
++ entity_uc = &service->service_use_count;
++ } else {
++ vchiq_log_error(vchiq_susp_log_level, "%s null service "
++ "ptr", __func__);
++ ret = VCHIQ_ERROR;
++ goto out;
++ }
++
++ write_lock_bh(&arm_state->susp_res_lock);
++ while (arm_state->resume_blocked) {
++ /* If we call 'use' while force suspend is waiting for suspend,
++ * then we're about to block the thread which the force is
++ * waiting to complete, so we're bound to just time out. In this
++ * case, set the suspend state such that the wait will be
++ * canceled, so we can complete as quickly as possible. */
++ if (arm_state->resume_blocked && arm_state->vc_suspend_state ==
++ VC_SUSPEND_IDLE) {
++ set_suspend_state(arm_state, VC_SUSPEND_FORCE_CANCELED);
++ break;
++ }
++ /* If suspend is already in progress then we need to block */
++ if (!try_wait_for_completion(&arm_state->resume_blocker)) {
++ /* Indicate that there are threads waiting on the resume
++ * blocker. These need to be allowed to complete before
++ * a _second_ call to force suspend can complete,
++ * otherwise low priority threads might never actually
++ * continue */
++ arm_state->blocked_count++;
++ write_unlock_bh(&arm_state->susp_res_lock);
++ vchiq_log_info(vchiq_susp_log_level, "%s %s resume "
++ "blocked - waiting...", __func__, entity);
++ if (wait_for_completion_killable(
++ &arm_state->resume_blocker) != 0) {
++ vchiq_log_error(vchiq_susp_log_level, "%s %s "
++ "wait for resume blocker interrupted",
++ __func__, entity);
++ ret = VCHIQ_ERROR;
++ write_lock_bh(&arm_state->susp_res_lock);
++ arm_state->blocked_count--;
++ write_unlock_bh(&arm_state->susp_res_lock);
++ goto out;
++ }
++ vchiq_log_info(vchiq_susp_log_level, "%s %s resume "
++ "unblocked", __func__, entity);
++ write_lock_bh(&arm_state->susp_res_lock);
++ if (--arm_state->blocked_count == 0)
++ complete_all(&arm_state->blocked_blocker);
++ }
++ }
++
++ stop_suspend_timer(arm_state);
++
++ local_uc = ++arm_state->videocore_use_count;
++ local_entity_uc = ++(*entity_uc);
++
++ /* If there's a pending request which hasn't yet been serviced then
++ * just clear it. If we're past VC_SUSPEND_REQUESTED state then
++ * vc_resume_complete will block until we either resume or fail to
++ * suspend */
++ if (arm_state->vc_suspend_state <= VC_SUSPEND_REQUESTED)
++ set_suspend_state(arm_state, VC_SUSPEND_IDLE);
++
++ if ((use_type != USE_TYPE_SERVICE_NO_RESUME) && need_resume(state)) {
++ set_resume_state(arm_state, VC_RESUME_REQUESTED);
++ vchiq_log_info(vchiq_susp_log_level,
++ "%s %s count %d, state count %d",
++ __func__, entity, local_entity_uc, local_uc);
++ request_poll(state, NULL, 0);
++ } else
++ vchiq_log_trace(vchiq_susp_log_level,
++ "%s %s count %d, state count %d",
++ __func__, entity, *entity_uc, local_uc);
++
++
++ write_unlock_bh(&arm_state->susp_res_lock);
++
++ /* Completion is in a done state when we're not suspended, so this won't
++ * block for the non-suspended case. */
++ if (!try_wait_for_completion(&arm_state->vc_resume_complete)) {
++ vchiq_log_info(vchiq_susp_log_level, "%s %s wait for resume",
++ __func__, entity);
++ if (wait_for_completion_killable(
++ &arm_state->vc_resume_complete) != 0) {
++ vchiq_log_error(vchiq_susp_log_level, "%s %s wait for "
++ "resume interrupted", __func__, entity);
++ ret = VCHIQ_ERROR;
++ goto out;
++ }
++ vchiq_log_info(vchiq_susp_log_level, "%s %s resumed", __func__,
++ entity);
++ }
++
++ if (ret == VCHIQ_SUCCESS) {
++ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
++ long ack_cnt = atomic_xchg(&arm_state->ka_use_ack_count, 0);
++ while (ack_cnt && (status == VCHIQ_SUCCESS)) {
++ /* Send the use notify to videocore */
++ status = vchiq_send_remote_use_active(state);
++ if (status == VCHIQ_SUCCESS)
++ ack_cnt--;
++ else
++ atomic_add(ack_cnt,
++ &arm_state->ka_use_ack_count);
++ }
++ }
++
++out:
++ vchiq_log_trace(vchiq_susp_log_level, "%s exit %d", __func__, ret);
++ return ret;
++}
++
++VCHIQ_STATUS_T
++vchiq_release_internal(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service)
++{
++ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
++ VCHIQ_STATUS_T ret = VCHIQ_SUCCESS;
++ char entity[16];
++ int *entity_uc;
++ int local_uc, local_entity_uc;
++
++ if (!arm_state)
++ goto out;
++
++ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
++
++ if (service) {
++ sprintf(entity, "%c%c%c%c:%03d",
++ VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc),
++ service->client_id);
++ entity_uc = &service->service_use_count;
++ } else {
++ sprintf(entity, "PEER: ");
++ entity_uc = &arm_state->peer_use_count;
++ }
++
++ write_lock_bh(&arm_state->susp_res_lock);
++ if (!arm_state->videocore_use_count || !(*entity_uc)) {
++ /* Don't use BUG_ON - don't allow user thread to crash kernel */
++ WARN_ON(!arm_state->videocore_use_count);
++ WARN_ON(!(*entity_uc));
++ ret = VCHIQ_ERROR;
++ goto unlock;
++ }
++ local_uc = --arm_state->videocore_use_count;
++ local_entity_uc = --(*entity_uc);
++
++ if (!vchiq_videocore_wanted(state)) {
++ if (vchiq_platform_use_suspend_timer() &&
++ !arm_state->resume_blocked) {
++ /* Only use the timer if we're not trying to force
++ * suspend (=> resume_blocked) */
++ start_suspend_timer(arm_state);
++ } else {
++ vchiq_log_info(vchiq_susp_log_level,
++ "%s %s count %d, state count %d - suspending",
++ __func__, entity, *entity_uc,
++ arm_state->videocore_use_count);
++ vchiq_arm_vcsuspend(state);
++ }
++ } else
++ vchiq_log_trace(vchiq_susp_log_level,
++ "%s %s count %d, state count %d",
++ __func__, entity, *entity_uc,
++ arm_state->videocore_use_count);
++
++unlock:
++ write_unlock_bh(&arm_state->susp_res_lock);
++
++out:
++ vchiq_log_trace(vchiq_susp_log_level, "%s exit %d", __func__, ret);
++ return ret;
++}
++
++void
++vchiq_on_remote_use(VCHIQ_STATE_T *state)
++{
++ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
++ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
++ atomic_inc(&arm_state->ka_use_count);
++ complete(&arm_state->ka_evt);
++}
++
++void
++vchiq_on_remote_release(VCHIQ_STATE_T *state)
++{
++ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
++ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
++ atomic_inc(&arm_state->ka_release_count);
++ complete(&arm_state->ka_evt);
++}
++
++VCHIQ_STATUS_T
++vchiq_use_service_internal(VCHIQ_SERVICE_T *service)
++{
++ return vchiq_use_internal(service->state, service, USE_TYPE_SERVICE);
++}
++
++VCHIQ_STATUS_T
++vchiq_release_service_internal(VCHIQ_SERVICE_T *service)
++{
++ return vchiq_release_internal(service->state, service);
++}
++
++VCHIQ_DEBUGFS_NODE_T *
++vchiq_instance_get_debugfs_node(VCHIQ_INSTANCE_T instance)
++{
++ return &instance->debugfs_node;
++}
++
++int
++vchiq_instance_get_use_count(VCHIQ_INSTANCE_T instance)
++{
++ VCHIQ_SERVICE_T *service;
++ int use_count = 0, i;
++ i = 0;
++ while ((service = next_service_by_instance(instance->state,
++ instance, &i)) != NULL) {
++ use_count += service->service_use_count;
++ unlock_service(service);
++ }
++ return use_count;
++}
++
++int
++vchiq_instance_get_pid(VCHIQ_INSTANCE_T instance)
++{
++ return instance->pid;
++}
++
++int
++vchiq_instance_get_trace(VCHIQ_INSTANCE_T instance)
++{
++ return instance->trace;
++}
++
++void
++vchiq_instance_set_trace(VCHIQ_INSTANCE_T instance, int trace)
++{
++ VCHIQ_SERVICE_T *service;
++ int i;
++ i = 0;
++ while ((service = next_service_by_instance(instance->state,
++ instance, &i)) != NULL) {
++ service->trace = trace;
++ unlock_service(service);
++ }
++ instance->trace = (trace != 0);
++}
++
++static void suspend_timer_callback(unsigned long context)
++{
++ VCHIQ_STATE_T *state = (VCHIQ_STATE_T *)context;
++ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
++ if (!arm_state)
++ goto out;
++ vchiq_log_info(vchiq_susp_log_level,
++ "%s - suspend timer expired - check suspend", __func__);
++ vchiq_check_suspend(state);
++out:
++ return;
++}
++
++VCHIQ_STATUS_T
++vchiq_use_service_no_resume(VCHIQ_SERVICE_HANDLE_T handle)
++{
++ VCHIQ_STATUS_T ret = VCHIQ_ERROR;
++ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
++ if (service) {
++ ret = vchiq_use_internal(service->state, service,
++ USE_TYPE_SERVICE_NO_RESUME);
++ unlock_service(service);
++ }
++ return ret;
++}
++
++VCHIQ_STATUS_T
++vchiq_use_service(VCHIQ_SERVICE_HANDLE_T handle)
++{
++ VCHIQ_STATUS_T ret = VCHIQ_ERROR;
++ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
++ if (service) {
++ ret = vchiq_use_internal(service->state, service,
++ USE_TYPE_SERVICE);
++ unlock_service(service);
++ }
++ return ret;
++}
++
++VCHIQ_STATUS_T
++vchiq_release_service(VCHIQ_SERVICE_HANDLE_T handle)
++{
++ VCHIQ_STATUS_T ret = VCHIQ_ERROR;
++ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
++ if (service) {
++ ret = vchiq_release_internal(service->state, service);
++ unlock_service(service);
++ }
++ return ret;
++}
++
++void
++vchiq_dump_service_use_state(VCHIQ_STATE_T *state)
++{
++ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
++ int i, j = 0;
++ /* Only dump 64 services */
++ static const int local_max_services = 64;
++ /* If there's more than 64 services, only dump ones with
++ * non-zero counts */
++ int only_nonzero = 0;
++ static const char *nz = "<-- preventing suspend";
++
++ enum vc_suspend_status vc_suspend_state;
++ enum vc_resume_status vc_resume_state;
++ int peer_count;
++ int vc_use_count;
++ int active_services;
++ struct service_data_struct {
++ int fourcc;
++ int clientid;
++ int use_count;
++ } service_data[local_max_services];
++
++ if (!arm_state)
++ return;
++
++ read_lock_bh(&arm_state->susp_res_lock);
++ vc_suspend_state = arm_state->vc_suspend_state;
++ vc_resume_state = arm_state->vc_resume_state;
++ peer_count = arm_state->peer_use_count;
++ vc_use_count = arm_state->videocore_use_count;
++ active_services = state->unused_service;
++ if (active_services > local_max_services)
++ only_nonzero = 1;
++
++ for (i = 0; (i < active_services) && (j < local_max_services); i++) {
++ VCHIQ_SERVICE_T *service_ptr = state->services[i];
++ if (!service_ptr)
++ continue;
++
++ if (only_nonzero && !service_ptr->service_use_count)
++ continue;
++
++ if (service_ptr->srvstate != VCHIQ_SRVSTATE_FREE) {
++ service_data[j].fourcc = service_ptr->base.fourcc;
++ service_data[j].clientid = service_ptr->client_id;
++ service_data[j++].use_count = service_ptr->
++ service_use_count;
++ }
++ }
++
++ read_unlock_bh(&arm_state->susp_res_lock);
++
++ vchiq_log_warning(vchiq_susp_log_level,
++ "-- Videcore suspend state: %s --",
++ suspend_state_names[vc_suspend_state + VC_SUSPEND_NUM_OFFSET]);
++ vchiq_log_warning(vchiq_susp_log_level,
++ "-- Videcore resume state: %s --",
++ resume_state_names[vc_resume_state + VC_RESUME_NUM_OFFSET]);
++
++ if (only_nonzero)
++ vchiq_log_warning(vchiq_susp_log_level, "Too many active "
++ "services (%d). Only dumping up to first %d services "
++ "with non-zero use-count", active_services,
++ local_max_services);
++
++ for (i = 0; i < j; i++) {
++ vchiq_log_warning(vchiq_susp_log_level,
++ "----- %c%c%c%c:%d service count %d %s",
++ VCHIQ_FOURCC_AS_4CHARS(service_data[i].fourcc),
++ service_data[i].clientid,
++ service_data[i].use_count,
++ service_data[i].use_count ? nz : "");
++ }
++ vchiq_log_warning(vchiq_susp_log_level,
++ "----- VCHIQ use count count %d", peer_count);
++ vchiq_log_warning(vchiq_susp_log_level,
++ "--- Overall vchiq instance use count %d", vc_use_count);
++
++ vchiq_dump_platform_use_state(state);
++}
++
++VCHIQ_STATUS_T
++vchiq_check_service(VCHIQ_SERVICE_T *service)
++{
++ VCHIQ_ARM_STATE_T *arm_state;
++ VCHIQ_STATUS_T ret = VCHIQ_ERROR;
++
++ if (!service || !service->state)
++ goto out;
++
++ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
++
++ arm_state = vchiq_platform_get_arm_state(service->state);
++
++ read_lock_bh(&arm_state->susp_res_lock);
++ if (service->service_use_count)
++ ret = VCHIQ_SUCCESS;
++ read_unlock_bh(&arm_state->susp_res_lock);
++
++ if (ret == VCHIQ_ERROR) {
++ vchiq_log_error(vchiq_susp_log_level,
++ "%s ERROR - %c%c%c%c:%d service count %d, "
++ "state count %d, videocore suspend state %s", __func__,
++ VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc),
++ service->client_id, service->service_use_count,
++ arm_state->videocore_use_count,
++ suspend_state_names[arm_state->vc_suspend_state +
++ VC_SUSPEND_NUM_OFFSET]);
++ vchiq_dump_service_use_state(service->state);
++ }
++out:
++ return ret;
++}
++
++/* stub functions */
++void vchiq_on_remote_use_active(VCHIQ_STATE_T *state)
++{
++ (void)state;
++}
++
++void vchiq_platform_conn_state_changed(VCHIQ_STATE_T *state,
++ VCHIQ_CONNSTATE_T oldstate, VCHIQ_CONNSTATE_T newstate)
++{
++ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
++ vchiq_log_info(vchiq_susp_log_level, "%d: %s->%s", state->id,
++ get_conn_state_name(oldstate), get_conn_state_name(newstate));
++ if (state->conn_state == VCHIQ_CONNSTATE_CONNECTED) {
++ write_lock_bh(&arm_state->susp_res_lock);
++ if (!arm_state->first_connect) {
++ char threadname[10];
++ arm_state->first_connect = 1;
++ write_unlock_bh(&arm_state->susp_res_lock);
++ snprintf(threadname, sizeof(threadname), "VCHIQka-%d",
++ state->id);
++ arm_state->ka_thread = kthread_create(
++ &vchiq_keepalive_thread_func,
++ (void *)state,
++ threadname);
++ if (arm_state->ka_thread == NULL) {
++ vchiq_log_error(vchiq_susp_log_level,
++ "vchiq: FATAL: couldn't create thread %s",
++ threadname);
++ } else {
++ wake_up_process(arm_state->ka_thread);
++ }
++ } else
++ write_unlock_bh(&arm_state->susp_res_lock);
++ }
++}
++
++static int vchiq_probe(struct platform_device *pdev)
++{
++ struct device_node *fw_node;
++ struct rpi_firmware *fw;
++ int err;
++ void *ptr_err;
++
++ fw_node = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
++/* Remove comment when booting without Device Tree is no longer supported
++ if (!fw_node) {
++ dev_err(&pdev->dev, "Missing firmware node\n");
++ return -ENOENT;
++ }
++*/
++ fw = rpi_firmware_get(fw_node);
++ if (!fw)
++ return -EPROBE_DEFER;
++
++ platform_set_drvdata(pdev, fw);
++
++ /* create debugfs entries */
++ err = vchiq_debugfs_init();
++ if (err != 0)
++ goto failed_debugfs_init;
++
++ err = alloc_chrdev_region(&vchiq_devid, VCHIQ_MINOR, 1, DEVICE_NAME);
++ if (err != 0) {
++ vchiq_log_error(vchiq_arm_log_level,
++ "Unable to allocate device number");
++ goto failed_alloc_chrdev;
++ }
++ cdev_init(&vchiq_cdev, &vchiq_fops);
++ vchiq_cdev.owner = THIS_MODULE;
++ err = cdev_add(&vchiq_cdev, vchiq_devid, 1);
++ if (err != 0) {
++ vchiq_log_error(vchiq_arm_log_level,
++ "Unable to register device");
++ goto failed_cdev_add;
++ }
++
++ /* create sysfs entries */
++ vchiq_class = class_create(THIS_MODULE, DEVICE_NAME);
++ ptr_err = vchiq_class;
++ if (IS_ERR(ptr_err))
++ goto failed_class_create;
++
++ vchiq_dev = device_create(vchiq_class, NULL,
++ vchiq_devid, NULL, "vchiq");
++ ptr_err = vchiq_dev;
++ if (IS_ERR(ptr_err))
++ goto failed_device_create;
++
++ err = vchiq_platform_init(pdev, &g_state);
++ if (err != 0)
++ goto failed_platform_init;
++
++ vchiq_log_info(vchiq_arm_log_level,
++ "vchiq: initialised - version %d (min %d), device %d.%d",
++ VCHIQ_VERSION, VCHIQ_VERSION_MIN,
++ MAJOR(vchiq_devid), MINOR(vchiq_devid));
++
++ return 0;
++
++failed_platform_init:
++ device_destroy(vchiq_class, vchiq_devid);
++failed_device_create:
++ class_destroy(vchiq_class);
++failed_class_create:
++ cdev_del(&vchiq_cdev);
++ err = PTR_ERR(ptr_err);
++failed_cdev_add:
++ unregister_chrdev_region(vchiq_devid, 1);
++failed_alloc_chrdev:
++ vchiq_debugfs_deinit();
++failed_debugfs_init:
++ vchiq_log_warning(vchiq_arm_log_level, "could not load vchiq");
++ return err;
++}
++
++static int vchiq_remove(struct platform_device *pdev)
++{
++ device_destroy(vchiq_class, vchiq_devid);
++ class_destroy(vchiq_class);
++ cdev_del(&vchiq_cdev);
++ unregister_chrdev_region(vchiq_devid, 1);
++
++ return 0;
++}
++
++static const struct of_device_id vchiq_of_match[] = {
++ { .compatible = "brcm,bcm2835-vchiq", },
++ {},
++};
++MODULE_DEVICE_TABLE(of, vchiq_of_match);
++
++static struct platform_driver vchiq_driver = {
++ .driver = {
++ .name = "bcm2835_vchiq",
++ .owner = THIS_MODULE,
++ .of_match_table = vchiq_of_match,
++ },
++ .probe = vchiq_probe,
++ .remove = vchiq_remove,
++};
++module_platform_driver(vchiq_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Broadcom Corporation");
+--- /dev/null
++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.h
+@@ -0,0 +1,220 @@
++/**
++ * Copyright (c) 2014 Raspberry Pi (Trading) Ltd. All rights reserved.
++ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef VCHIQ_ARM_H
++#define VCHIQ_ARM_H
++
++#include <linux/mutex.h>
++#include <linux/platform_device.h>
++#include <linux/semaphore.h>
++#include <linux/atomic.h>
++#include "vchiq_core.h"
++#include "vchiq_debugfs.h"
++
++
++enum vc_suspend_status {
++ VC_SUSPEND_FORCE_CANCELED = -3, /* Force suspend canceled, too busy */
++ VC_SUSPEND_REJECTED = -2, /* Videocore rejected suspend request */
++ VC_SUSPEND_FAILED = -1, /* Videocore suspend failed */
++ VC_SUSPEND_IDLE = 0, /* VC active, no suspend actions */
++ VC_SUSPEND_REQUESTED, /* User has requested suspend */
++ VC_SUSPEND_IN_PROGRESS, /* Slot handler has recvd suspend request */
++ VC_SUSPEND_SUSPENDED /* Videocore suspend succeeded */
++};
++
++enum vc_resume_status {
++ VC_RESUME_FAILED = -1, /* Videocore resume failed */
++ VC_RESUME_IDLE = 0, /* VC suspended, no resume actions */
++ VC_RESUME_REQUESTED, /* User has requested resume */
++ VC_RESUME_IN_PROGRESS, /* Slot handler has received resume request */
++ VC_RESUME_RESUMED /* Videocore resumed successfully (active) */
++};
++
++
++enum USE_TYPE_E {
++ USE_TYPE_SERVICE,
++ USE_TYPE_SERVICE_NO_RESUME,
++ USE_TYPE_VCHIQ
++};
++
++
++
++typedef struct vchiq_arm_state_struct {
++ /* Keepalive-related data */
++ struct task_struct *ka_thread;
++ struct completion ka_evt;
++ atomic_t ka_use_count;
++ atomic_t ka_use_ack_count;
++ atomic_t ka_release_count;
++
++ struct completion vc_suspend_complete;
++ struct completion vc_resume_complete;
++
++ rwlock_t susp_res_lock;
++ enum vc_suspend_status vc_suspend_state;
++ enum vc_resume_status vc_resume_state;
++
++ unsigned int wake_address;
++
++ struct timer_list suspend_timer;
++ int suspend_timer_timeout;
++ int suspend_timer_running;
++
++ /* Global use count for videocore.
++ ** This is equal to the sum of the use counts for all services. When
++ ** this hits zero the videocore suspend procedure will be initiated.
++ */
++ int videocore_use_count;
++
++ /* Use count to track requests from videocore peer.
++ ** This use count is not associated with a service, so needs to be
++ ** tracked separately with the state.
++ */
++ int peer_use_count;
++
++ /* Flag to indicate whether resume is blocked. This happens when the
++ ** ARM is suspending
++ */
++ struct completion resume_blocker;
++ int resume_blocked;
++ struct completion blocked_blocker;
++ int blocked_count;
++
++ int autosuspend_override;
++
++ /* Flag to indicate that the first vchiq connect has made it through.
++ ** This means that both sides should be fully ready, and we should
++ ** be able to suspend after this point.
++ */
++ int first_connect;
++
++ unsigned long long suspend_start_time;
++ unsigned long long sleep_start_time;
++ unsigned long long resume_start_time;
++ unsigned long long last_wake_time;
++
++} VCHIQ_ARM_STATE_T;
++
++extern int vchiq_arm_log_level;
++extern int vchiq_susp_log_level;
++
++int vchiq_platform_init(struct platform_device *pdev, VCHIQ_STATE_T *state);
++
++extern VCHIQ_STATE_T *
++vchiq_get_state(void);
++
++extern VCHIQ_STATUS_T
++vchiq_arm_vcsuspend(VCHIQ_STATE_T *state);
++
++extern VCHIQ_STATUS_T
++vchiq_arm_force_suspend(VCHIQ_STATE_T *state);
++
++extern int
++vchiq_arm_allow_resume(VCHIQ_STATE_T *state);
++
++extern VCHIQ_STATUS_T
++vchiq_arm_vcresume(VCHIQ_STATE_T *state);
++
++extern VCHIQ_STATUS_T
++vchiq_arm_init_state(VCHIQ_STATE_T *state, VCHIQ_ARM_STATE_T *arm_state);
++
++extern int
++vchiq_check_resume(VCHIQ_STATE_T *state);
++
++extern void
++vchiq_check_suspend(VCHIQ_STATE_T *state);
++ VCHIQ_STATUS_T
++vchiq_use_service(VCHIQ_SERVICE_HANDLE_T handle);
++
++extern VCHIQ_STATUS_T
++vchiq_release_service(VCHIQ_SERVICE_HANDLE_T handle);
++
++extern VCHIQ_STATUS_T
++vchiq_check_service(VCHIQ_SERVICE_T *service);
++
++extern VCHIQ_STATUS_T
++vchiq_platform_suspend(VCHIQ_STATE_T *state);
++
++extern int
++vchiq_platform_videocore_wanted(VCHIQ_STATE_T *state);
++
++extern int
++vchiq_platform_use_suspend_timer(void);
++
++extern void
++vchiq_dump_platform_use_state(VCHIQ_STATE_T *state);
++
++extern void
++vchiq_dump_service_use_state(VCHIQ_STATE_T *state);
++
++extern VCHIQ_ARM_STATE_T*
++vchiq_platform_get_arm_state(VCHIQ_STATE_T *state);
++
++extern int
++vchiq_videocore_wanted(VCHIQ_STATE_T *state);
++
++extern VCHIQ_STATUS_T
++vchiq_use_internal(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service,
++ enum USE_TYPE_E use_type);
++extern VCHIQ_STATUS_T
++vchiq_release_internal(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service);
++
++extern VCHIQ_DEBUGFS_NODE_T *
++vchiq_instance_get_debugfs_node(VCHIQ_INSTANCE_T instance);
++
++extern int
++vchiq_instance_get_use_count(VCHIQ_INSTANCE_T instance);
++
++extern int
++vchiq_instance_get_pid(VCHIQ_INSTANCE_T instance);
++
++extern int
++vchiq_instance_get_trace(VCHIQ_INSTANCE_T instance);
++
++extern void
++vchiq_instance_set_trace(VCHIQ_INSTANCE_T instance, int trace);
++
++extern void
++set_suspend_state(VCHIQ_ARM_STATE_T *arm_state,
++ enum vc_suspend_status new_state);
++
++extern void
++set_resume_state(VCHIQ_ARM_STATE_T *arm_state,
++ enum vc_resume_status new_state);
++
++extern void
++start_suspend_timer(VCHIQ_ARM_STATE_T *arm_state);
++
++
++#endif /* VCHIQ_ARM_H */
+--- /dev/null
++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_build_info.h
+@@ -0,0 +1,37 @@
++/**
++ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++const char *vchiq_get_build_hostname(void);
++const char *vchiq_get_build_version(void);
++const char *vchiq_get_build_time(void);
++const char *vchiq_get_build_date(void);
+--- /dev/null
++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_cfg.h
+@@ -0,0 +1,69 @@
++/**
++ * Copyright (c) 2010-2014 Broadcom. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef VCHIQ_CFG_H
++#define VCHIQ_CFG_H
++
++#define VCHIQ_MAGIC VCHIQ_MAKE_FOURCC('V', 'C', 'H', 'I')
++/* The version of VCHIQ - change with any non-trivial change */
++#define VCHIQ_VERSION 8
++/* The minimum compatible version - update to match VCHIQ_VERSION with any
++** incompatible change */
++#define VCHIQ_VERSION_MIN 3
++
++/* The version that introduced the VCHIQ_IOC_LIB_VERSION ioctl */
++#define VCHIQ_VERSION_LIB_VERSION 7
++
++/* The version that introduced the VCHIQ_IOC_CLOSE_DELIVERED ioctl */
++#define VCHIQ_VERSION_CLOSE_DELIVERED 7
++
++/* The version that made it safe to use SYNCHRONOUS mode */
++#define VCHIQ_VERSION_SYNCHRONOUS_MODE 8
++
++#define VCHIQ_MAX_STATES 1
++#define VCHIQ_MAX_SERVICES 4096
++#define VCHIQ_MAX_SLOTS 128
++#define VCHIQ_MAX_SLOTS_PER_SIDE 64
++
++#define VCHIQ_NUM_CURRENT_BULKS 32
++#define VCHIQ_NUM_SERVICE_BULKS 4
++
++#ifndef VCHIQ_ENABLE_DEBUG
++#define VCHIQ_ENABLE_DEBUG 1
++#endif
++
++#ifndef VCHIQ_ENABLE_STATS
++#define VCHIQ_ENABLE_STATS 1
++#endif
++
++#endif /* VCHIQ_CFG_H */
+--- /dev/null
++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.c
+@@ -0,0 +1,120 @@
++/**
++ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "vchiq_connected.h"
++#include "vchiq_core.h"
++#include "vchiq_killable.h"
++#include <linux/module.h>
++#include <linux/mutex.h>
++
++#define MAX_CALLBACKS 10
++
++static int g_connected;
++static int g_num_deferred_callbacks;
++static VCHIQ_CONNECTED_CALLBACK_T g_deferred_callback[MAX_CALLBACKS];
++static int g_once_init;
++static struct mutex g_connected_mutex;
++
++/****************************************************************************
++*
++* Function to initialize our lock.
++*
++***************************************************************************/
++
++static void connected_init(void)
++{
++ if (!g_once_init) {
++ mutex_init(&g_connected_mutex);
++ g_once_init = 1;
++ }
++}
++
++/****************************************************************************
++*
++* This function is used to defer initialization until the vchiq stack is
++* initialized. If the stack is already initialized, then the callback will
++* be made immediately, otherwise it will be deferred until
++* vchiq_call_connected_callbacks is called.
++*
++***************************************************************************/
++
++void vchiq_add_connected_callback(VCHIQ_CONNECTED_CALLBACK_T callback)
++{
++ connected_init();
++
++ if (mutex_lock_interruptible(&g_connected_mutex) != 0)
++ return;
++
++ if (g_connected)
++ /* We're already connected. Call the callback immediately. */
++
++ callback();
++ else {
++ if (g_num_deferred_callbacks >= MAX_CALLBACKS)
++ vchiq_log_error(vchiq_core_log_level,
++ "There already %d callback registered - "
++ "please increase MAX_CALLBACKS",
++ g_num_deferred_callbacks);
++ else {
++ g_deferred_callback[g_num_deferred_callbacks] =
++ callback;
++ g_num_deferred_callbacks++;
++ }
++ }
++ mutex_unlock(&g_connected_mutex);
++}
++
++/****************************************************************************
++*
++* This function is called by the vchiq stack once it has been connected to
++* the videocore and clients can start to use the stack.
++*
++***************************************************************************/
++
++void vchiq_call_connected_callbacks(void)
++{
++ int i;
++
++ connected_init();
++
++ if (mutex_lock_interruptible(&g_connected_mutex) != 0)
++ return;
++
++ for (i = 0; i < g_num_deferred_callbacks; i++)
++ g_deferred_callback[i]();
++
++ g_num_deferred_callbacks = 0;
++ g_connected = 1;
++ mutex_unlock(&g_connected_mutex);
++}
++EXPORT_SYMBOL(vchiq_add_connected_callback);
+--- /dev/null
++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.h
+@@ -0,0 +1,50 @@
++/**
++ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef VCHIQ_CONNECTED_H
++#define VCHIQ_CONNECTED_H
++
++/* ---- Include Files ----------------------------------------------------- */
++
++/* ---- Constants and Types ---------------------------------------------- */
++
++typedef void (*VCHIQ_CONNECTED_CALLBACK_T)(void);
++
++/* ---- Variable Externs ------------------------------------------------- */
++
++/* ---- Function Prototypes ---------------------------------------------- */
++
++void vchiq_add_connected_callback(VCHIQ_CONNECTED_CALLBACK_T callback);
++void vchiq_call_connected_callbacks(void);
++
++#endif /* VCHIQ_CONNECTED_H */
+--- /dev/null
++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c
+@@ -0,0 +1,3934 @@
++/**
++ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "vchiq_core.h"
++#include "vchiq_killable.h"
++
++#define VCHIQ_SLOT_HANDLER_STACK 8192
++
++#define HANDLE_STATE_SHIFT 12
++
++#define SLOT_INFO_FROM_INDEX(state, index) (state->slot_info + (index))
++#define SLOT_DATA_FROM_INDEX(state, index) (state->slot_data + (index))
++#define SLOT_INDEX_FROM_DATA(state, data) \
++ (((unsigned int)((char *)data - (char *)state->slot_data)) / \
++ VCHIQ_SLOT_SIZE)
++#define SLOT_INDEX_FROM_INFO(state, info) \
++ ((unsigned int)(info - state->slot_info))
++#define SLOT_QUEUE_INDEX_FROM_POS(pos) \
++ ((int)((unsigned int)(pos) / VCHIQ_SLOT_SIZE))
++
++#define BULK_INDEX(x) (x & (VCHIQ_NUM_SERVICE_BULKS - 1))
++
++#define SRVTRACE_LEVEL(srv) \
++ (((srv) && (srv)->trace) ? VCHIQ_LOG_TRACE : vchiq_core_msg_log_level)
++#define SRVTRACE_ENABLED(srv, lev) \
++ (((srv) && (srv)->trace) || (vchiq_core_msg_log_level >= (lev)))
++
++struct vchiq_open_payload {
++ int fourcc;
++ int client_id;
++ short version;
++ short version_min;
++};
++
++struct vchiq_openack_payload {
++ short version;
++};
++
++enum
++{
++ QMFLAGS_IS_BLOCKING = (1 << 0),
++ QMFLAGS_NO_MUTEX_LOCK = (1 << 1),
++ QMFLAGS_NO_MUTEX_UNLOCK = (1 << 2)
++};
++
++/* we require this for consistency between endpoints */
++vchiq_static_assert(sizeof(VCHIQ_HEADER_T) == 8);
++vchiq_static_assert(IS_POW2(sizeof(VCHIQ_HEADER_T)));
++vchiq_static_assert(IS_POW2(VCHIQ_NUM_CURRENT_BULKS));
++vchiq_static_assert(IS_POW2(VCHIQ_NUM_SERVICE_BULKS));
++vchiq_static_assert(IS_POW2(VCHIQ_MAX_SERVICES));
++vchiq_static_assert(VCHIQ_VERSION >= VCHIQ_VERSION_MIN);
++
++/* Run time control of log level, based on KERN_XXX level. */
++int vchiq_core_log_level = VCHIQ_LOG_DEFAULT;
++int vchiq_core_msg_log_level = VCHIQ_LOG_DEFAULT;
++int vchiq_sync_log_level = VCHIQ_LOG_DEFAULT;
++
++static atomic_t pause_bulks_count = ATOMIC_INIT(0);
++
++static DEFINE_SPINLOCK(service_spinlock);
++DEFINE_SPINLOCK(bulk_waiter_spinlock);
++DEFINE_SPINLOCK(quota_spinlock);
++
++VCHIQ_STATE_T *vchiq_states[VCHIQ_MAX_STATES];
++static unsigned int handle_seq;
++
++static const char *const srvstate_names[] = {
++ "FREE",
++ "HIDDEN",
++ "LISTENING",
++ "OPENING",
++ "OPEN",
++ "OPENSYNC",
++ "CLOSESENT",
++ "CLOSERECVD",
++ "CLOSEWAIT",
++ "CLOSED"
++};
++
++static const char *const reason_names[] = {
++ "SERVICE_OPENED",
++ "SERVICE_CLOSED",
++ "MESSAGE_AVAILABLE",
++ "BULK_TRANSMIT_DONE",
++ "BULK_RECEIVE_DONE",
++ "BULK_TRANSMIT_ABORTED",
++ "BULK_RECEIVE_ABORTED"
++};
++
++static const char *const conn_state_names[] = {
++ "DISCONNECTED",
++ "CONNECTING",
++ "CONNECTED",
++ "PAUSING",
++ "PAUSE_SENT",
++ "PAUSED",
++ "RESUMING",
++ "PAUSE_TIMEOUT",
++ "RESUME_TIMEOUT"
++};
++
++
++static void
++release_message_sync(VCHIQ_STATE_T *state, VCHIQ_HEADER_T *header);
++
++static const char *msg_type_str(unsigned int msg_type)
++{
++ switch (msg_type) {
++ case VCHIQ_MSG_PADDING: return "PADDING";
++ case VCHIQ_MSG_CONNECT: return "CONNECT";
++ case VCHIQ_MSG_OPEN: return "OPEN";
++ case VCHIQ_MSG_OPENACK: return "OPENACK";
++ case VCHIQ_MSG_CLOSE: return "CLOSE";
++ case VCHIQ_MSG_DATA: return "DATA";
++ case VCHIQ_MSG_BULK_RX: return "BULK_RX";
++ case VCHIQ_MSG_BULK_TX: return "BULK_TX";
++ case VCHIQ_MSG_BULK_RX_DONE: return "BULK_RX_DONE";
++ case VCHIQ_MSG_BULK_TX_DONE: return "BULK_TX_DONE";
++ case VCHIQ_MSG_PAUSE: return "PAUSE";
++ case VCHIQ_MSG_RESUME: return "RESUME";
++ case VCHIQ_MSG_REMOTE_USE: return "REMOTE_USE";
++ case VCHIQ_MSG_REMOTE_RELEASE: return "REMOTE_RELEASE";
++ case VCHIQ_MSG_REMOTE_USE_ACTIVE: return "REMOTE_USE_ACTIVE";
++ }
++ return "???";
++}
++
++static inline void
++vchiq_set_service_state(VCHIQ_SERVICE_T *service, int newstate)
++{
++ vchiq_log_info(vchiq_core_log_level, "%d: srv:%d %s->%s",
++ service->state->id, service->localport,
++ srvstate_names[service->srvstate],
++ srvstate_names[newstate]);
++ service->srvstate = newstate;
++}
++
++VCHIQ_SERVICE_T *
++find_service_by_handle(VCHIQ_SERVICE_HANDLE_T handle)
++{
++ VCHIQ_SERVICE_T *service;
++
++ spin_lock(&service_spinlock);
++ service = handle_to_service(handle);
++ if (service && (service->srvstate != VCHIQ_SRVSTATE_FREE) &&
++ (service->handle == handle)) {
++ BUG_ON(service->ref_count == 0);
++ service->ref_count++;
++ } else
++ service = NULL;
++ spin_unlock(&service_spinlock);
++
++ if (!service)
++ vchiq_log_info(vchiq_core_log_level,
++ "Invalid service handle 0x%x", handle);
++
++ return service;
++}
++
++VCHIQ_SERVICE_T *
++find_service_by_port(VCHIQ_STATE_T *state, int localport)
++{
++ VCHIQ_SERVICE_T *service = NULL;
++ if ((unsigned int)localport <= VCHIQ_PORT_MAX) {
++ spin_lock(&service_spinlock);
++ service = state->services[localport];
++ if (service && (service->srvstate != VCHIQ_SRVSTATE_FREE)) {
++ BUG_ON(service->ref_count == 0);
++ service->ref_count++;
++ } else
++ service = NULL;
++ spin_unlock(&service_spinlock);
++ }
++
++ if (!service)
++ vchiq_log_info(vchiq_core_log_level,
++ "Invalid port %d", localport);
++
++ return service;
++}
++
++VCHIQ_SERVICE_T *
++find_service_for_instance(VCHIQ_INSTANCE_T instance,
++ VCHIQ_SERVICE_HANDLE_T handle) {
++ VCHIQ_SERVICE_T *service;
++
++ spin_lock(&service_spinlock);
++ service = handle_to_service(handle);
++ if (service && (service->srvstate != VCHIQ_SRVSTATE_FREE) &&
++ (service->handle == handle) &&
++ (service->instance == instance)) {
++ BUG_ON(service->ref_count == 0);
++ service->ref_count++;
++ } else
++ service = NULL;
++ spin_unlock(&service_spinlock);
++
++ if (!service)
++ vchiq_log_info(vchiq_core_log_level,
++ "Invalid service handle 0x%x", handle);
++
++ return service;
++}
++
++VCHIQ_SERVICE_T *
++find_closed_service_for_instance(VCHIQ_INSTANCE_T instance,
++ VCHIQ_SERVICE_HANDLE_T handle) {
++ VCHIQ_SERVICE_T *service;
++
++ spin_lock(&service_spinlock);
++ service = handle_to_service(handle);
++ if (service &&
++ ((service->srvstate == VCHIQ_SRVSTATE_FREE) ||
++ (service->srvstate == VCHIQ_SRVSTATE_CLOSED)) &&
++ (service->handle == handle) &&
++ (service->instance == instance)) {
++ BUG_ON(service->ref_count == 0);
++ service->ref_count++;
++ } else
++ service = NULL;
++ spin_unlock(&service_spinlock);
++
++ if (!service)
++ vchiq_log_info(vchiq_core_log_level,
++ "Invalid service handle 0x%x", handle);
++
++ return service;
++}
++
++VCHIQ_SERVICE_T *
++next_service_by_instance(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance,
++ int *pidx)
++{
++ VCHIQ_SERVICE_T *service = NULL;
++ int idx = *pidx;
++
++ spin_lock(&service_spinlock);
++ while (idx < state->unused_service) {
++ VCHIQ_SERVICE_T *srv = state->services[idx++];
++ if (srv && (srv->srvstate != VCHIQ_SRVSTATE_FREE) &&
++ (srv->instance == instance)) {
++ service = srv;
++ BUG_ON(service->ref_count == 0);
++ service->ref_count++;
++ break;
++ }
++ }
++ spin_unlock(&service_spinlock);
++
++ *pidx = idx;
++
++ return service;
++}
++
++void
++lock_service(VCHIQ_SERVICE_T *service)
++{
++ spin_lock(&service_spinlock);
++ BUG_ON(!service || (service->ref_count == 0));
++ if (service)
++ service->ref_count++;
++ spin_unlock(&service_spinlock);
++}
++
++void
++unlock_service(VCHIQ_SERVICE_T *service)
++{
++ VCHIQ_STATE_T *state = service->state;
++ spin_lock(&service_spinlock);
++ BUG_ON(!service || (service->ref_count == 0));
++ if (service && service->ref_count) {
++ service->ref_count--;
++ if (!service->ref_count) {
++ BUG_ON(service->srvstate != VCHIQ_SRVSTATE_FREE);
++ state->services[service->localport] = NULL;
++ } else
++ service = NULL;
++ }
++ spin_unlock(&service_spinlock);
++
++ if (service && service->userdata_term)
++ service->userdata_term(service->base.userdata);
++
++ kfree(service);
++}
++
++int
++vchiq_get_client_id(VCHIQ_SERVICE_HANDLE_T handle)
++{
++ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
++ int id;
++
++ id = service ? service->client_id : 0;
++ if (service)
++ unlock_service(service);
++
++ return id;
++}
++
++void *
++vchiq_get_service_userdata(VCHIQ_SERVICE_HANDLE_T handle)
++{
++ VCHIQ_SERVICE_T *service = handle_to_service(handle);
++
++ return service ? service->base.userdata : NULL;
++}
++
++int
++vchiq_get_service_fourcc(VCHIQ_SERVICE_HANDLE_T handle)
++{
++ VCHIQ_SERVICE_T *service = handle_to_service(handle);
++
++ return service ? service->base.fourcc : 0;
++}
++
++static void
++mark_service_closing_internal(VCHIQ_SERVICE_T *service, int sh_thread)
++{
++ VCHIQ_STATE_T *state = service->state;
++ VCHIQ_SERVICE_QUOTA_T *service_quota;
++
++ service->closing = 1;
++
++ /* Synchronise with other threads. */
++ mutex_lock(&state->recycle_mutex);
++ mutex_unlock(&state->recycle_mutex);
++ if (!sh_thread || (state->conn_state != VCHIQ_CONNSTATE_PAUSE_SENT)) {
++ /* If we're pausing then the slot_mutex is held until resume
++ * by the slot handler. Therefore don't try to acquire this
++ * mutex if we're the slot handler and in the pause sent state.
++ * We don't need to in this case anyway. */
++ mutex_lock(&state->slot_mutex);
++ mutex_unlock(&state->slot_mutex);
++ }
++
++ /* Unblock any sending thread. */
++ service_quota = &state->service_quotas[service->localport];
++ up(&service_quota->quota_event);
++}
++
++static void
++mark_service_closing(VCHIQ_SERVICE_T *service)
++{
++ mark_service_closing_internal(service, 0);
++}
++
++static inline VCHIQ_STATUS_T
++make_service_callback(VCHIQ_SERVICE_T *service, VCHIQ_REASON_T reason,
++ VCHIQ_HEADER_T *header, void *bulk_userdata)
++{
++ VCHIQ_STATUS_T status;
++ vchiq_log_trace(vchiq_core_log_level, "%d: callback:%d (%s, %x, %x)",
++ service->state->id, service->localport, reason_names[reason],
++ (unsigned int)header, (unsigned int)bulk_userdata);
++ status = service->base.callback(reason, header, service->handle,
++ bulk_userdata);
++ if (status == VCHIQ_ERROR) {
++ vchiq_log_warning(vchiq_core_log_level,
++ "%d: ignoring ERROR from callback to service %x",
++ service->state->id, service->handle);
++ status = VCHIQ_SUCCESS;
++ }
++ return status;
++}
++
++inline void
++vchiq_set_conn_state(VCHIQ_STATE_T *state, VCHIQ_CONNSTATE_T newstate)
++{
++ VCHIQ_CONNSTATE_T oldstate = state->conn_state;
++ vchiq_log_info(vchiq_core_log_level, "%d: %s->%s", state->id,
++ conn_state_names[oldstate],
++ conn_state_names[newstate]);
++ state->conn_state = newstate;
++ vchiq_platform_conn_state_changed(state, oldstate, newstate);
++}
++
++static inline void
++remote_event_create(REMOTE_EVENT_T *event)
++{
++ event->armed = 0;
++ /* Don't clear the 'fired' flag because it may already have been set
++ ** by the other side. */
++ sema_init(event->event, 0);
++}
++
++static inline void
++remote_event_destroy(REMOTE_EVENT_T *event)
++{
++ (void)event;
++}
++
++static inline int
++remote_event_wait(REMOTE_EVENT_T *event)
++{
++ if (!event->fired) {
++ event->armed = 1;
++ dsb();
++ if (!event->fired) {
++ if (down_interruptible(event->event) != 0) {
++ event->armed = 0;
++ return 0;
++ }
++ }
++ event->armed = 0;
++ wmb();
++ }
++
++ event->fired = 0;
++ return 1;
++}
++
++static inline void
++remote_event_signal_local(REMOTE_EVENT_T *event)
++{
++ event->armed = 0;
++ up(event->event);
++}
++
++static inline void
++remote_event_poll(REMOTE_EVENT_T *event)
++{
++ if (event->fired && event->armed)
++ remote_event_signal_local(event);
++}
++
++void
++remote_event_pollall(VCHIQ_STATE_T *state)
++{
++ remote_event_poll(&state->local->sync_trigger);
++ remote_event_poll(&state->local->sync_release);
++ remote_event_poll(&state->local->trigger);
++ remote_event_poll(&state->local->recycle);
++}
++
++/* Round up message sizes so that any space at the end of a slot is always big
++** enough for a header. This relies on header size being a power of two, which
++** has been verified earlier by a static assertion. */
++
++static inline unsigned int
++calc_stride(unsigned int size)
++{
++ /* Allow room for the header */
++ size += sizeof(VCHIQ_HEADER_T);
++
++ /* Round up */
++ return (size + sizeof(VCHIQ_HEADER_T) - 1) & ~(sizeof(VCHIQ_HEADER_T)
++ - 1);
++}
++
++/* Called by the slot handler thread */
++static VCHIQ_SERVICE_T *
++get_listening_service(VCHIQ_STATE_T *state, int fourcc)
++{
++ int i;
++
++ WARN_ON(fourcc == VCHIQ_FOURCC_INVALID);
++
++ for (i = 0; i < state->unused_service; i++) {
++ VCHIQ_SERVICE_T *service = state->services[i];
++ if (service &&
++ (service->public_fourcc == fourcc) &&
++ ((service->srvstate == VCHIQ_SRVSTATE_LISTENING) ||
++ ((service->srvstate == VCHIQ_SRVSTATE_OPEN) &&
++ (service->remoteport == VCHIQ_PORT_FREE)))) {
++ lock_service(service);
++ return service;
++ }
++ }
++
++ return NULL;
++}
++
++/* Called by the slot handler thread */
++static VCHIQ_SERVICE_T *
++get_connected_service(VCHIQ_STATE_T *state, unsigned int port)
++{
++ int i;
++ for (i = 0; i < state->unused_service; i++) {
++ VCHIQ_SERVICE_T *service = state->services[i];
++ if (service && (service->srvstate == VCHIQ_SRVSTATE_OPEN)
++ && (service->remoteport == port)) {
++ lock_service(service);
++ return service;
++ }
++ }
++ return NULL;
++}
++
++inline void
++request_poll(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, int poll_type)
++{
++ uint32_t value;
++
++ if (service) {
++ do {
++ value = atomic_read(&service->poll_flags);
++ } while (atomic_cmpxchg(&service->poll_flags, value,
++ value | (1 << poll_type)) != value);
++
++ do {
++ value = atomic_read(&state->poll_services[
++ service->localport>>5]);
++ } while (atomic_cmpxchg(
++ &state->poll_services[service->localport>>5],
++ value, value | (1 << (service->localport & 0x1f)))
++ != value);
++ }
++
++ state->poll_needed = 1;
++ wmb();
++
++ /* ... and ensure the slot handler runs. */
++ remote_event_signal_local(&state->local->trigger);
++}
++
++/* Called from queue_message, by the slot handler and application threads,
++** with slot_mutex held */
++static VCHIQ_HEADER_T *
++reserve_space(VCHIQ_STATE_T *state, int space, int is_blocking)
++{
++ VCHIQ_SHARED_STATE_T *local = state->local;
++ int tx_pos = state->local_tx_pos;
++ int slot_space = VCHIQ_SLOT_SIZE - (tx_pos & VCHIQ_SLOT_MASK);
++
++ if (space > slot_space) {
++ VCHIQ_HEADER_T *header;
++ /* Fill the remaining space with padding */
++ WARN_ON(state->tx_data == NULL);
++ header = (VCHIQ_HEADER_T *)
++ (state->tx_data + (tx_pos & VCHIQ_SLOT_MASK));
++ header->msgid = VCHIQ_MSGID_PADDING;
++ header->size = slot_space - sizeof(VCHIQ_HEADER_T);
++
++ tx_pos += slot_space;
++ }
++
++ /* If necessary, get the next slot. */
++ if ((tx_pos & VCHIQ_SLOT_MASK) == 0) {
++ int slot_index;
++
++ /* If there is no free slot... */
++
++ if (down_trylock(&state->slot_available_event) != 0) {
++ /* ...wait for one. */
++
++ VCHIQ_STATS_INC(state, slot_stalls);
++
++ /* But first, flush through the last slot. */
++ state->local_tx_pos = tx_pos;
++ local->tx_pos = tx_pos;
++ remote_event_signal(&state->remote->trigger);
++
++ if (!is_blocking ||
++ (down_interruptible(
++ &state->slot_available_event) != 0))
++ return NULL; /* No space available */
++ }
++
++ BUG_ON(tx_pos ==
++ (state->slot_queue_available * VCHIQ_SLOT_SIZE));
++
++ slot_index = local->slot_queue[
++ SLOT_QUEUE_INDEX_FROM_POS(tx_pos) &
++ VCHIQ_SLOT_QUEUE_MASK];
++ state->tx_data =
++ (char *)SLOT_DATA_FROM_INDEX(state, slot_index);
++ }
++
++ state->local_tx_pos = tx_pos + space;
++
++ return (VCHIQ_HEADER_T *)(state->tx_data + (tx_pos & VCHIQ_SLOT_MASK));
++}
++
++/* Called by the recycle thread. */
++static void
++process_free_queue(VCHIQ_STATE_T *state)
++{
++ VCHIQ_SHARED_STATE_T *local = state->local;
++ BITSET_T service_found[BITSET_SIZE(VCHIQ_MAX_SERVICES)];
++ int slot_queue_available;
++
++ /* Use a read memory barrier to ensure that any state that may have
++ ** been modified by another thread is not masked by stale prefetched
++ ** values. */
++ rmb();
++
++ /* Find slots which have been freed by the other side, and return them
++ ** to the available queue. */
++ slot_queue_available = state->slot_queue_available;
++
++ while (slot_queue_available != local->slot_queue_recycle) {
++ unsigned int pos;
++ int slot_index = local->slot_queue[slot_queue_available++ &
++ VCHIQ_SLOT_QUEUE_MASK];
++ char *data = (char *)SLOT_DATA_FROM_INDEX(state, slot_index);
++ int data_found = 0;
++
++ vchiq_log_trace(vchiq_core_log_level, "%d: pfq %d=%x %x %x",
++ state->id, slot_index, (unsigned int)data,
++ local->slot_queue_recycle, slot_queue_available);
++
++ /* Initialise the bitmask for services which have used this
++ ** slot */
++ BITSET_ZERO(service_found);
++
++ pos = 0;
++
++ while (pos < VCHIQ_SLOT_SIZE) {
++ VCHIQ_HEADER_T *header =
++ (VCHIQ_HEADER_T *)(data + pos);
++ int msgid = header->msgid;
++ if (VCHIQ_MSG_TYPE(msgid) == VCHIQ_MSG_DATA) {
++ int port = VCHIQ_MSG_SRCPORT(msgid);
++ VCHIQ_SERVICE_QUOTA_T *service_quota =
++ &state->service_quotas[port];
++ int count;
++ spin_lock(&quota_spinlock);
++ count = service_quota->message_use_count;
++ if (count > 0)
++ service_quota->message_use_count =
++ count - 1;
++ spin_unlock(&quota_spinlock);
++
++ if (count == service_quota->message_quota)
++ /* Signal the service that it
++ ** has dropped below its quota
++ */
++ up(&service_quota->quota_event);
++ else if (count == 0) {
++ vchiq_log_error(vchiq_core_log_level,
++ "service %d "
++ "message_use_count=%d "
++ "(header %x, msgid %x, "
++ "header->msgid %x, "
++ "header->size %x)",
++ port,
++ service_quota->
++ message_use_count,
++ (unsigned int)header, msgid,
++ header->msgid,
++ header->size);
++ WARN(1, "invalid message use count\n");
++ }
++ if (!BITSET_IS_SET(service_found, port)) {
++ /* Set the found bit for this service */
++ BITSET_SET(service_found, port);
++
++ spin_lock(&quota_spinlock);
++ count = service_quota->slot_use_count;
++ if (count > 0)
++ service_quota->slot_use_count =
++ count - 1;
++ spin_unlock(&quota_spinlock);
++
++ if (count > 0) {
++ /* Signal the service in case
++ ** it has dropped below its
++ ** quota */
++ up(&service_quota->quota_event);
++ vchiq_log_trace(
++ vchiq_core_log_level,
++ "%d: pfq:%d %x@%x - "
++ "slot_use->%d",
++ state->id, port,
++ header->size,
++ (unsigned int)header,
++ count - 1);
++ } else {
++ vchiq_log_error(
++ vchiq_core_log_level,
++ "service %d "
++ "slot_use_count"
++ "=%d (header %x"
++ ", msgid %x, "
++ "header->msgid"
++ " %x, header->"
++ "size %x)",
++ port, count,
++ (unsigned int)header,
++ msgid,
++ header->msgid,
++ header->size);
++ WARN(1, "bad slot use count\n");
++ }
++ }
++
++ data_found = 1;
++ }
++
++ pos += calc_stride(header->size);
++ if (pos > VCHIQ_SLOT_SIZE) {
++ vchiq_log_error(vchiq_core_log_level,
++ "pfq - pos %x: header %x, msgid %x, "
++ "header->msgid %x, header->size %x",
++ pos, (unsigned int)header, msgid,
++ header->msgid, header->size);
++ WARN(1, "invalid slot position\n");
++ }
++ }
++
++ if (data_found) {
++ int count;
++ spin_lock(&quota_spinlock);
++ count = state->data_use_count;
++ if (count > 0)
++ state->data_use_count =
++ count - 1;
++ spin_unlock(&quota_spinlock);
++ if (count == state->data_quota)
++ up(&state->data_quota_event);
++ }
++
++ state->slot_queue_available = slot_queue_available;
++ up(&state->slot_available_event);
++ }
++}
++
++/* Called by the slot handler and application threads */
++static VCHIQ_STATUS_T
++queue_message(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service,
++ int msgid, const VCHIQ_ELEMENT_T *elements,
++ int count, int size, int flags)
++{
++ VCHIQ_SHARED_STATE_T *local;
++ VCHIQ_SERVICE_QUOTA_T *service_quota = NULL;
++ VCHIQ_HEADER_T *header;
++ int type = VCHIQ_MSG_TYPE(msgid);
++
++ unsigned int stride;
++
++ local = state->local;
++
++ stride = calc_stride(size);
++
++ WARN_ON(!(stride <= VCHIQ_SLOT_SIZE));
++
++ if (!(flags & QMFLAGS_NO_MUTEX_LOCK) &&
++ (mutex_lock_interruptible(&state->slot_mutex) != 0))
++ return VCHIQ_RETRY;
++
++ if (type == VCHIQ_MSG_DATA) {
++ int tx_end_index;
++
++ BUG_ON(!service);
++ BUG_ON((flags & (QMFLAGS_NO_MUTEX_LOCK |
++ QMFLAGS_NO_MUTEX_UNLOCK)) != 0);
++
++ if (service->closing) {
++ /* The service has been closed */
++ mutex_unlock(&state->slot_mutex);
++ return VCHIQ_ERROR;
++ }
++
++ service_quota = &state->service_quotas[service->localport];
++
++ spin_lock(&quota_spinlock);
++
++ /* Ensure this service doesn't use more than its quota of
++ ** messages or slots */
++ tx_end_index = SLOT_QUEUE_INDEX_FROM_POS(
++ state->local_tx_pos + stride - 1);
++
++ /* Ensure data messages don't use more than their quota of
++ ** slots */
++ while ((tx_end_index != state->previous_data_index) &&
++ (state->data_use_count == state->data_quota)) {
++ VCHIQ_STATS_INC(state, data_stalls);
++ spin_unlock(&quota_spinlock);
++ mutex_unlock(&state->slot_mutex);
++
++ if (down_interruptible(&state->data_quota_event)
++ != 0)
++ return VCHIQ_RETRY;
++
++ mutex_lock(&state->slot_mutex);
++ spin_lock(&quota_spinlock);
++ tx_end_index = SLOT_QUEUE_INDEX_FROM_POS(
++ state->local_tx_pos + stride - 1);
++ if ((tx_end_index == state->previous_data_index) ||
++ (state->data_use_count < state->data_quota)) {
++ /* Pass the signal on to other waiters */
++ up(&state->data_quota_event);
++ break;
++ }
++ }
++
++ while ((service_quota->message_use_count ==
++ service_quota->message_quota) ||
++ ((tx_end_index != service_quota->previous_tx_index) &&
++ (service_quota->slot_use_count ==
++ service_quota->slot_quota))) {
++ spin_unlock(&quota_spinlock);
++ vchiq_log_trace(vchiq_core_log_level,
++ "%d: qm:%d %s,%x - quota stall "
++ "(msg %d, slot %d)",
++ state->id, service->localport,
++ msg_type_str(type), size,
++ service_quota->message_use_count,
++ service_quota->slot_use_count);
++ VCHIQ_SERVICE_STATS_INC(service, quota_stalls);
++ mutex_unlock(&state->slot_mutex);
++ if (down_interruptible(&service_quota->quota_event)
++ != 0)
++ return VCHIQ_RETRY;
++ if (service->closing)
++ return VCHIQ_ERROR;
++ if (mutex_lock_interruptible(&state->slot_mutex) != 0)
++ return VCHIQ_RETRY;
++ if (service->srvstate != VCHIQ_SRVSTATE_OPEN) {
++ /* The service has been closed */
++ mutex_unlock(&state->slot_mutex);
++ return VCHIQ_ERROR;
++ }
++ spin_lock(&quota_spinlock);
++ tx_end_index = SLOT_QUEUE_INDEX_FROM_POS(
++ state->local_tx_pos + stride - 1);
++ }
++
++ spin_unlock(&quota_spinlock);
++ }
++
++ header = reserve_space(state, stride, flags & QMFLAGS_IS_BLOCKING);
++
++ if (!header) {
++ if (service)
++ VCHIQ_SERVICE_STATS_INC(service, slot_stalls);
++ /* In the event of a failure, return the mutex to the
++ state it was in */
++ if (!(flags & QMFLAGS_NO_MUTEX_LOCK))
++ mutex_unlock(&state->slot_mutex);
++ return VCHIQ_RETRY;
++ }
++
++ if (type == VCHIQ_MSG_DATA) {
++ int i, pos;
++ int tx_end_index;
++ int slot_use_count;
++
++ vchiq_log_info(vchiq_core_log_level,
++ "%d: qm %s@%x,%x (%d->%d)",
++ state->id,
++ msg_type_str(VCHIQ_MSG_TYPE(msgid)),
++ (unsigned int)header, size,
++ VCHIQ_MSG_SRCPORT(msgid),
++ VCHIQ_MSG_DSTPORT(msgid));
++
++ BUG_ON(!service);
++ BUG_ON((flags & (QMFLAGS_NO_MUTEX_LOCK |
++ QMFLAGS_NO_MUTEX_UNLOCK)) != 0);
++
++ for (i = 0, pos = 0; i < (unsigned int)count;
++ pos += elements[i++].size)
++ if (elements[i].size) {
++ if (vchiq_copy_from_user
++ (header->data + pos, elements[i].data,
++ (size_t) elements[i].size) !=
++ VCHIQ_SUCCESS) {
++ mutex_unlock(&state->slot_mutex);
++ VCHIQ_SERVICE_STATS_INC(service,
++ error_count);
++ return VCHIQ_ERROR;
++ }
++ if (i == 0) {
++ if (SRVTRACE_ENABLED(service,
++ VCHIQ_LOG_INFO))
++ vchiq_log_dump_mem("Sent", 0,
++ header->data + pos,
++ min(64u,
++ elements[0].size));
++ }
++ }
++
++ spin_lock(&quota_spinlock);
++ service_quota->message_use_count++;
++
++ tx_end_index =
++ SLOT_QUEUE_INDEX_FROM_POS(state->local_tx_pos - 1);
++
++ /* If this transmission can't fit in the last slot used by any
++ ** service, the data_use_count must be increased. */
++ if (tx_end_index != state->previous_data_index) {
++ state->previous_data_index = tx_end_index;
++ state->data_use_count++;
++ }
++
++ /* If this isn't the same slot last used by this service,
++ ** the service's slot_use_count must be increased. */
++ if (tx_end_index != service_quota->previous_tx_index) {
++ service_quota->previous_tx_index = tx_end_index;
++ slot_use_count = ++service_quota->slot_use_count;
++ } else {
++ slot_use_count = 0;
++ }
++
++ spin_unlock(&quota_spinlock);
++
++ if (slot_use_count)
++ vchiq_log_trace(vchiq_core_log_level,
++ "%d: qm:%d %s,%x - slot_use->%d (hdr %p)",
++ state->id, service->localport,
++ msg_type_str(VCHIQ_MSG_TYPE(msgid)), size,
++ slot_use_count, header);
++
++ VCHIQ_SERVICE_STATS_INC(service, ctrl_tx_count);
++ VCHIQ_SERVICE_STATS_ADD(service, ctrl_tx_bytes, size);
++ } else {
++ vchiq_log_info(vchiq_core_log_level,
++ "%d: qm %s@%x,%x (%d->%d)", state->id,
++ msg_type_str(VCHIQ_MSG_TYPE(msgid)),
++ (unsigned int)header, size,
++ VCHIQ_MSG_SRCPORT(msgid),
++ VCHIQ_MSG_DSTPORT(msgid));
++ if (size != 0) {
++ WARN_ON(!((count == 1) && (size == elements[0].size)));
++ memcpy(header->data, elements[0].data,
++ elements[0].size);
++ }
++ VCHIQ_STATS_INC(state, ctrl_tx_count);
++ }
++
++ header->msgid = msgid;
++ header->size = size;
++
++ {
++ int svc_fourcc;
++
++ svc_fourcc = service
++ ? service->base.fourcc
++ : VCHIQ_MAKE_FOURCC('?', '?', '?', '?');
++
++ vchiq_log_info(SRVTRACE_LEVEL(service),
++ "Sent Msg %s(%u) to %c%c%c%c s:%u d:%d len:%d",
++ msg_type_str(VCHIQ_MSG_TYPE(msgid)),
++ VCHIQ_MSG_TYPE(msgid),
++ VCHIQ_FOURCC_AS_4CHARS(svc_fourcc),
++ VCHIQ_MSG_SRCPORT(msgid),
++ VCHIQ_MSG_DSTPORT(msgid),
++ size);
++ }
++
++ /* Make sure the new header is visible to the peer. */
++ wmb();
++
++ /* Make the new tx_pos visible to the peer. */
++ local->tx_pos = state->local_tx_pos;
++ wmb();
++
++ if (service && (type == VCHIQ_MSG_CLOSE))
++ vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSESENT);
++
++ if (!(flags & QMFLAGS_NO_MUTEX_UNLOCK))
++ mutex_unlock(&state->slot_mutex);
++
++ remote_event_signal(&state->remote->trigger);
++
++ return VCHIQ_SUCCESS;
++}
++
++/* Called by the slot handler and application threads */
++static VCHIQ_STATUS_T
++queue_message_sync(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service,
++ int msgid, const VCHIQ_ELEMENT_T *elements,
++ int count, int size, int is_blocking)
++{
++ VCHIQ_SHARED_STATE_T *local;
++ VCHIQ_HEADER_T *header;
++
++ local = state->local;
++
++ if ((VCHIQ_MSG_TYPE(msgid) != VCHIQ_MSG_RESUME) &&
++ (mutex_lock_interruptible(&state->sync_mutex) != 0))
++ return VCHIQ_RETRY;
++
++ remote_event_wait(&local->sync_release);
++
++ rmb();
++
++ header = (VCHIQ_HEADER_T *)SLOT_DATA_FROM_INDEX(state,
++ local->slot_sync);
++
++ {
++ int oldmsgid = header->msgid;
++ if (oldmsgid != VCHIQ_MSGID_PADDING)
++ vchiq_log_error(vchiq_core_log_level,
++ "%d: qms - msgid %x, not PADDING",
++ state->id, oldmsgid);
++ }
++
++ if (service) {
++ int i, pos;
++
++ vchiq_log_info(vchiq_sync_log_level,
++ "%d: qms %s@%x,%x (%d->%d)", state->id,
++ msg_type_str(VCHIQ_MSG_TYPE(msgid)),
++ (unsigned int)header, size,
++ VCHIQ_MSG_SRCPORT(msgid),
++ VCHIQ_MSG_DSTPORT(msgid));
++
++ for (i = 0, pos = 0; i < (unsigned int)count;
++ pos += elements[i++].size)
++ if (elements[i].size) {
++ if (vchiq_copy_from_user
++ (header->data + pos, elements[i].data,
++ (size_t) elements[i].size) !=
++ VCHIQ_SUCCESS) {
++ mutex_unlock(&state->sync_mutex);
++ VCHIQ_SERVICE_STATS_INC(service,
++ error_count);
++ return VCHIQ_ERROR;
++ }
++ if (i == 0) {
++ if (vchiq_sync_log_level >=
++ VCHIQ_LOG_TRACE)
++ vchiq_log_dump_mem("Sent Sync",
++ 0, header->data + pos,
++ min(64u,
++ elements[0].size));
++ }
++ }
++
++ VCHIQ_SERVICE_STATS_INC(service, ctrl_tx_count);
++ VCHIQ_SERVICE_STATS_ADD(service, ctrl_tx_bytes, size);
++ } else {
++ vchiq_log_info(vchiq_sync_log_level,
++ "%d: qms %s@%x,%x (%d->%d)", state->id,
++ msg_type_str(VCHIQ_MSG_TYPE(msgid)),
++ (unsigned int)header, size,
++ VCHIQ_MSG_SRCPORT(msgid),
++ VCHIQ_MSG_DSTPORT(msgid));
++ if (size != 0) {
++ WARN_ON(!((count == 1) && (size == elements[0].size)));
++ memcpy(header->data, elements[0].data,
++ elements[0].size);
++ }
++ VCHIQ_STATS_INC(state, ctrl_tx_count);
++ }
++
++ header->size = size;
++ header->msgid = msgid;
++
++ if (vchiq_sync_log_level >= VCHIQ_LOG_TRACE) {
++ int svc_fourcc;
++
++ svc_fourcc = service
++ ? service->base.fourcc
++ : VCHIQ_MAKE_FOURCC('?', '?', '?', '?');
++
++ vchiq_log_trace(vchiq_sync_log_level,
++ "Sent Sync Msg %s(%u) to %c%c%c%c s:%u d:%d len:%d",
++ msg_type_str(VCHIQ_MSG_TYPE(msgid)),
++ VCHIQ_MSG_TYPE(msgid),
++ VCHIQ_FOURCC_AS_4CHARS(svc_fourcc),
++ VCHIQ_MSG_SRCPORT(msgid),
++ VCHIQ_MSG_DSTPORT(msgid),
++ size);
++ }
++
++ /* Make sure the new header is visible to the peer. */
++ wmb();
++
++ remote_event_signal(&state->remote->sync_trigger);
++
++ if (VCHIQ_MSG_TYPE(msgid) != VCHIQ_MSG_PAUSE)
++ mutex_unlock(&state->sync_mutex);
++
++ return VCHIQ_SUCCESS;
++}
++
++static inline void
++claim_slot(VCHIQ_SLOT_INFO_T *slot)
++{
++ slot->use_count++;
++}
++
++static void
++release_slot(VCHIQ_STATE_T *state, VCHIQ_SLOT_INFO_T *slot_info,
++ VCHIQ_HEADER_T *header, VCHIQ_SERVICE_T *service)
++{
++ int release_count;
++
++ mutex_lock(&state->recycle_mutex);
++
++ if (header) {
++ int msgid = header->msgid;
++ if (((msgid & VCHIQ_MSGID_CLAIMED) == 0) ||
++ (service && service->closing)) {
++ mutex_unlock(&state->recycle_mutex);
++ return;
++ }
++
++ /* Rewrite the message header to prevent a double
++ ** release */
++ header->msgid = msgid & ~VCHIQ_MSGID_CLAIMED;
++ }
++
++ release_count = slot_info->release_count;
++ slot_info->release_count = ++release_count;
++
++ if (release_count == slot_info->use_count) {
++ int slot_queue_recycle;
++ /* Add to the freed queue */
++
++ /* A read barrier is necessary here to prevent speculative
++ ** fetches of remote->slot_queue_recycle from overtaking the
++ ** mutex. */
++ rmb();
++
++ slot_queue_recycle = state->remote->slot_queue_recycle;
++ state->remote->slot_queue[slot_queue_recycle &
++ VCHIQ_SLOT_QUEUE_MASK] =
++ SLOT_INDEX_FROM_INFO(state, slot_info);
++ state->remote->slot_queue_recycle = slot_queue_recycle + 1;
++ vchiq_log_info(vchiq_core_log_level,
++ "%d: release_slot %d - recycle->%x",
++ state->id, SLOT_INDEX_FROM_INFO(state, slot_info),
++ state->remote->slot_queue_recycle);
++
++ /* A write barrier is necessary, but remote_event_signal
++ ** contains one. */
++ remote_event_signal(&state->remote->recycle);
++ }
++
++ mutex_unlock(&state->recycle_mutex);
++}
++
++/* Called by the slot handler - don't hold the bulk mutex */
++static VCHIQ_STATUS_T
++notify_bulks(VCHIQ_SERVICE_T *service, VCHIQ_BULK_QUEUE_T *queue,
++ int retry_poll)
++{
++ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
++
++ vchiq_log_trace(vchiq_core_log_level,
++ "%d: nb:%d %cx - p=%x rn=%x r=%x",
++ service->state->id, service->localport,
++ (queue == &service->bulk_tx) ? 't' : 'r',
++ queue->process, queue->remote_notify, queue->remove);
++
++ if (service->state->is_master) {
++ while (queue->remote_notify != queue->process) {
++ VCHIQ_BULK_T *bulk =
++ &queue->bulks[BULK_INDEX(queue->remote_notify)];
++ int msgtype = (bulk->dir == VCHIQ_BULK_TRANSMIT) ?
++ VCHIQ_MSG_BULK_RX_DONE : VCHIQ_MSG_BULK_TX_DONE;
++ int msgid = VCHIQ_MAKE_MSG(msgtype, service->localport,
++ service->remoteport);
++ VCHIQ_ELEMENT_T element = { &bulk->actual, 4 };
++ /* Only reply to non-dummy bulk requests */
++ if (bulk->remote_data) {
++ status = queue_message(service->state, NULL,
++ msgid, &element, 1, 4, 0);
++ if (status != VCHIQ_SUCCESS)
++ break;
++ }
++ queue->remote_notify++;
++ }
++ } else {
++ queue->remote_notify = queue->process;
++ }
++
++ if (status == VCHIQ_SUCCESS) {
++ while (queue->remove != queue->remote_notify) {
++ VCHIQ_BULK_T *bulk =
++ &queue->bulks[BULK_INDEX(queue->remove)];
++
++ /* Only generate callbacks for non-dummy bulk
++ ** requests, and non-terminated services */
++ if (bulk->data && service->instance) {
++ if (bulk->actual != VCHIQ_BULK_ACTUAL_ABORTED) {
++ if (bulk->dir == VCHIQ_BULK_TRANSMIT) {
++ VCHIQ_SERVICE_STATS_INC(service,
++ bulk_tx_count);
++ VCHIQ_SERVICE_STATS_ADD(service,
++ bulk_tx_bytes,
++ bulk->actual);
++ } else {
++ VCHIQ_SERVICE_STATS_INC(service,
++ bulk_rx_count);
++ VCHIQ_SERVICE_STATS_ADD(service,
++ bulk_rx_bytes,
++ bulk->actual);
++ }
++ } else {
++ VCHIQ_SERVICE_STATS_INC(service,
++ bulk_aborted_count);
++ }
++ if (bulk->mode == VCHIQ_BULK_MODE_BLOCKING) {
++ struct bulk_waiter *waiter;
++ spin_lock(&bulk_waiter_spinlock);
++ waiter = bulk->userdata;
++ if (waiter) {
++ waiter->actual = bulk->actual;
++ up(&waiter->event);
++ }
++ spin_unlock(&bulk_waiter_spinlock);
++ } else if (bulk->mode ==
++ VCHIQ_BULK_MODE_CALLBACK) {
++ VCHIQ_REASON_T reason = (bulk->dir ==
++ VCHIQ_BULK_TRANSMIT) ?
++ ((bulk->actual ==
++ VCHIQ_BULK_ACTUAL_ABORTED) ?
++ VCHIQ_BULK_TRANSMIT_ABORTED :
++ VCHIQ_BULK_TRANSMIT_DONE) :
++ ((bulk->actual ==
++ VCHIQ_BULK_ACTUAL_ABORTED) ?
++ VCHIQ_BULK_RECEIVE_ABORTED :
++ VCHIQ_BULK_RECEIVE_DONE);
++ status = make_service_callback(service,
++ reason, NULL, bulk->userdata);
++ if (status == VCHIQ_RETRY)
++ break;
++ }
++ }
++
++ queue->remove++;
++ up(&service->bulk_remove_event);
++ }
++ if (!retry_poll)
++ status = VCHIQ_SUCCESS;
++ }
++
++ if (status == VCHIQ_RETRY)
++ request_poll(service->state, service,
++ (queue == &service->bulk_tx) ?
++ VCHIQ_POLL_TXNOTIFY : VCHIQ_POLL_RXNOTIFY);
++
++ return status;
++}
++
++/* Called by the slot handler thread */
++static void
++poll_services(VCHIQ_STATE_T *state)
++{
++ int group, i;
++
++ for (group = 0; group < BITSET_SIZE(state->unused_service); group++) {
++ uint32_t flags;
++ flags = atomic_xchg(&state->poll_services[group], 0);
++ for (i = 0; flags; i++) {
++ if (flags & (1 << i)) {
++ VCHIQ_SERVICE_T *service =
++ find_service_by_port(state,
++ (group<<5) + i);
++ uint32_t service_flags;
++ flags &= ~(1 << i);
++ if (!service)
++ continue;
++ service_flags =
++ atomic_xchg(&service->poll_flags, 0);
++ if (service_flags &
++ (1 << VCHIQ_POLL_REMOVE)) {
++ vchiq_log_info(vchiq_core_log_level,
++ "%d: ps - remove %d<->%d",
++ state->id, service->localport,
++ service->remoteport);
++
++ /* Make it look like a client, because
++ it must be removed and not left in
++ the LISTENING state. */
++ service->public_fourcc =
++ VCHIQ_FOURCC_INVALID;
++
++ if (vchiq_close_service_internal(
++ service, 0/*!close_recvd*/) !=
++ VCHIQ_SUCCESS)
++ request_poll(state, service,
++ VCHIQ_POLL_REMOVE);
++ } else if (service_flags &
++ (1 << VCHIQ_POLL_TERMINATE)) {
++ vchiq_log_info(vchiq_core_log_level,
++ "%d: ps - terminate %d<->%d",
++ state->id, service->localport,
++ service->remoteport);
++ if (vchiq_close_service_internal(
++ service, 0/*!close_recvd*/) !=
++ VCHIQ_SUCCESS)
++ request_poll(state, service,
++ VCHIQ_POLL_TERMINATE);
++ }
++ if (service_flags & (1 << VCHIQ_POLL_TXNOTIFY))
++ notify_bulks(service,
++ &service->bulk_tx,
++ 1/*retry_poll*/);
++ if (service_flags & (1 << VCHIQ_POLL_RXNOTIFY))
++ notify_bulks(service,
++ &service->bulk_rx,
++ 1/*retry_poll*/);
++ unlock_service(service);
++ }
++ }
++ }
++}
++
++/* Called by the slot handler or application threads, holding the bulk mutex. */
++static int
++resolve_bulks(VCHIQ_SERVICE_T *service, VCHIQ_BULK_QUEUE_T *queue)
++{
++ VCHIQ_STATE_T *state = service->state;
++ int resolved = 0;
++ int rc;
++
++ while ((queue->process != queue->local_insert) &&
++ (queue->process != queue->remote_insert)) {
++ VCHIQ_BULK_T *bulk = &queue->bulks[BULK_INDEX(queue->process)];
++
++ vchiq_log_trace(vchiq_core_log_level,
++ "%d: rb:%d %cx - li=%x ri=%x p=%x",
++ state->id, service->localport,
++ (queue == &service->bulk_tx) ? 't' : 'r',
++ queue->local_insert, queue->remote_insert,
++ queue->process);
++
++ WARN_ON(!((int)(queue->local_insert - queue->process) > 0));
++ WARN_ON(!((int)(queue->remote_insert - queue->process) > 0));
++
++ rc = mutex_lock_interruptible(&state->bulk_transfer_mutex);
++ if (rc != 0)
++ break;
++
++ vchiq_transfer_bulk(bulk);
++ mutex_unlock(&state->bulk_transfer_mutex);
++
++ if (SRVTRACE_ENABLED(service, VCHIQ_LOG_INFO)) {
++ const char *header = (queue == &service->bulk_tx) ?
++ "Send Bulk to" : "Recv Bulk from";
++ if (bulk->actual != VCHIQ_BULK_ACTUAL_ABORTED)
++ vchiq_log_info(SRVTRACE_LEVEL(service),
++ "%s %c%c%c%c d:%d len:%d %x<->%x",
++ header,
++ VCHIQ_FOURCC_AS_4CHARS(
++ service->base.fourcc),
++ service->remoteport,
++ bulk->size,
++ (unsigned int)bulk->data,
++ (unsigned int)bulk->remote_data);
++ else
++ vchiq_log_info(SRVTRACE_LEVEL(service),
++ "%s %c%c%c%c d:%d ABORTED - tx len:%d,"
++ " rx len:%d %x<->%x",
++ header,
++ VCHIQ_FOURCC_AS_4CHARS(
++ service->base.fourcc),
++ service->remoteport,
++ bulk->size,
++ bulk->remote_size,
++ (unsigned int)bulk->data,
++ (unsigned int)bulk->remote_data);
++ }
++
++ vchiq_complete_bulk(bulk);
++ queue->process++;
++ resolved++;
++ }
++ return resolved;
++}
++
++/* Called with the bulk_mutex held */
++static void
++abort_outstanding_bulks(VCHIQ_SERVICE_T *service, VCHIQ_BULK_QUEUE_T *queue)
++{
++ int is_tx = (queue == &service->bulk_tx);
++ vchiq_log_trace(vchiq_core_log_level,
++ "%d: aob:%d %cx - li=%x ri=%x p=%x",
++ service->state->id, service->localport, is_tx ? 't' : 'r',
++ queue->local_insert, queue->remote_insert, queue->process);
++
++ WARN_ON(!((int)(queue->local_insert - queue->process) >= 0));
++ WARN_ON(!((int)(queue->remote_insert - queue->process) >= 0));
++
++ while ((queue->process != queue->local_insert) ||
++ (queue->process != queue->remote_insert)) {
++ VCHIQ_BULK_T *bulk = &queue->bulks[BULK_INDEX(queue->process)];
++
++ if (queue->process == queue->remote_insert) {
++ /* fabricate a matching dummy bulk */
++ bulk->remote_data = NULL;
++ bulk->remote_size = 0;
++ queue->remote_insert++;
++ }
++
++ if (queue->process != queue->local_insert) {
++ vchiq_complete_bulk(bulk);
++
++ vchiq_log_info(SRVTRACE_LEVEL(service),
++ "%s %c%c%c%c d:%d ABORTED - tx len:%d, "
++ "rx len:%d",
++ is_tx ? "Send Bulk to" : "Recv Bulk from",
++ VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc),
++ service->remoteport,
++ bulk->size,
++ bulk->remote_size);
++ } else {
++ /* fabricate a matching dummy bulk */
++ bulk->data = NULL;
++ bulk->size = 0;
++ bulk->actual = VCHIQ_BULK_ACTUAL_ABORTED;
++ bulk->dir = is_tx ? VCHIQ_BULK_TRANSMIT :
++ VCHIQ_BULK_RECEIVE;
++ queue->local_insert++;
++ }
++
++ queue->process++;
++ }
++}
++
++/* Called from the slot handler thread */
++static void
++pause_bulks(VCHIQ_STATE_T *state)
++{
++ if (unlikely(atomic_inc_return(&pause_bulks_count) != 1)) {
++ WARN_ON_ONCE(1);
++ atomic_set(&pause_bulks_count, 1);
++ return;
++ }
++
++ /* Block bulk transfers from all services */
++ mutex_lock(&state->bulk_transfer_mutex);
++}
++
++/* Called from the slot handler thread */
++static void
++resume_bulks(VCHIQ_STATE_T *state)
++{
++ int i;
++ if (unlikely(atomic_dec_return(&pause_bulks_count) != 0)) {
++ WARN_ON_ONCE(1);
++ atomic_set(&pause_bulks_count, 0);
++ return;
++ }
++
++ /* Allow bulk transfers from all services */
++ mutex_unlock(&state->bulk_transfer_mutex);
++
++ if (state->deferred_bulks == 0)
++ return;
++
++ /* Deal with any bulks which had to be deferred due to being in
++ * paused state. Don't try to match up to number of deferred bulks
++ * in case we've had something come and close the service in the
++ * interim - just process all bulk queues for all services */
++ vchiq_log_info(vchiq_core_log_level, "%s: processing %d deferred bulks",
++ __func__, state->deferred_bulks);
++
++ for (i = 0; i < state->unused_service; i++) {
++ VCHIQ_SERVICE_T *service = state->services[i];
++ int resolved_rx = 0;
++ int resolved_tx = 0;
++ if (!service || (service->srvstate != VCHIQ_SRVSTATE_OPEN))
++ continue;
++
++ mutex_lock(&service->bulk_mutex);
++ resolved_rx = resolve_bulks(service, &service->bulk_rx);
++ resolved_tx = resolve_bulks(service, &service->bulk_tx);
++ mutex_unlock(&service->bulk_mutex);
++ if (resolved_rx)
++ notify_bulks(service, &service->bulk_rx, 1);
++ if (resolved_tx)
++ notify_bulks(service, &service->bulk_tx, 1);
++ }
++ state->deferred_bulks = 0;
++}
++
++static int
++parse_open(VCHIQ_STATE_T *state, VCHIQ_HEADER_T *header)
++{
++ VCHIQ_SERVICE_T *service = NULL;
++ int msgid, size;
++ int type;
++ unsigned int localport, remoteport;
++
++ msgid = header->msgid;
++ size = header->size;
++ type = VCHIQ_MSG_TYPE(msgid);
++ localport = VCHIQ_MSG_DSTPORT(msgid);
++ remoteport = VCHIQ_MSG_SRCPORT(msgid);
++ if (size >= sizeof(struct vchiq_open_payload)) {
++ const struct vchiq_open_payload *payload =
++ (struct vchiq_open_payload *)header->data;
++ unsigned int fourcc;
++
++ fourcc = payload->fourcc;
++ vchiq_log_info(vchiq_core_log_level,
++ "%d: prs OPEN@%x (%d->'%c%c%c%c')",
++ state->id, (unsigned int)header,
++ localport,
++ VCHIQ_FOURCC_AS_4CHARS(fourcc));
++
++ service = get_listening_service(state, fourcc);
++
++ if (service) {
++ /* A matching service exists */
++ short version = payload->version;
++ short version_min = payload->version_min;
++ if ((service->version < version_min) ||
++ (version < service->version_min)) {
++ /* Version mismatch */
++ vchiq_loud_error_header();
++ vchiq_loud_error("%d: service %d (%c%c%c%c) "
++ "version mismatch - local (%d, min %d)"
++ " vs. remote (%d, min %d)",
++ state->id, service->localport,
++ VCHIQ_FOURCC_AS_4CHARS(fourcc),
++ service->version, service->version_min,
++ version, version_min);
++ vchiq_loud_error_footer();
++ unlock_service(service);
++ service = NULL;
++ goto fail_open;
++ }
++ service->peer_version = version;
++
++ if (service->srvstate == VCHIQ_SRVSTATE_LISTENING) {
++ struct vchiq_openack_payload ack_payload = {
++ service->version
++ };
++ VCHIQ_ELEMENT_T body = {
++ &ack_payload,
++ sizeof(ack_payload)
++ };
++
++ if (state->version_common <
++ VCHIQ_VERSION_SYNCHRONOUS_MODE)
++ service->sync = 0;
++
++ /* Acknowledge the OPEN */
++ if (service->sync &&
++ (state->version_common >=
++ VCHIQ_VERSION_SYNCHRONOUS_MODE)) {
++ if (queue_message_sync(state, NULL,
++ VCHIQ_MAKE_MSG(
++ VCHIQ_MSG_OPENACK,
++ service->localport,
++ remoteport),
++ &body, 1, sizeof(ack_payload),
++ 0) == VCHIQ_RETRY)
++ goto bail_not_ready;
++ } else {
++ if (queue_message(state, NULL,
++ VCHIQ_MAKE_MSG(
++ VCHIQ_MSG_OPENACK,
++ service->localport,
++ remoteport),
++ &body, 1, sizeof(ack_payload),
++ 0) == VCHIQ_RETRY)
++ goto bail_not_ready;
++ }
++
++ /* The service is now open */
++ vchiq_set_service_state(service,
++ service->sync ? VCHIQ_SRVSTATE_OPENSYNC
++ : VCHIQ_SRVSTATE_OPEN);
++ }
++
++ service->remoteport = remoteport;
++ service->client_id = ((int *)header->data)[1];
++ if (make_service_callback(service, VCHIQ_SERVICE_OPENED,
++ NULL, NULL) == VCHIQ_RETRY) {
++ /* Bail out if not ready */
++ service->remoteport = VCHIQ_PORT_FREE;
++ goto bail_not_ready;
++ }
++
++ /* Success - the message has been dealt with */
++ unlock_service(service);
++ return 1;
++ }
++ }
++
++fail_open:
++ /* No available service, or an invalid request - send a CLOSE */
++ if (queue_message(state, NULL,
++ VCHIQ_MAKE_MSG(VCHIQ_MSG_CLOSE, 0, VCHIQ_MSG_SRCPORT(msgid)),
++ NULL, 0, 0, 0) == VCHIQ_RETRY)
++ goto bail_not_ready;
++
++ return 1;
++
++bail_not_ready:
++ if (service)
++ unlock_service(service);
++
++ return 0;
++}
++
++/* Called by the slot handler thread */
++static void
++parse_rx_slots(VCHIQ_STATE_T *state)
++{
++ VCHIQ_SHARED_STATE_T *remote = state->remote;
++ VCHIQ_SERVICE_T *service = NULL;
++ int tx_pos;
++ DEBUG_INITIALISE(state->local)
++
++ tx_pos = remote->tx_pos;
++
++ while (state->rx_pos != tx_pos) {
++ VCHIQ_HEADER_T *header;
++ int msgid, size;
++ int type;
++ unsigned int localport, remoteport;
++
++ DEBUG_TRACE(PARSE_LINE);
++ if (!state->rx_data) {
++ int rx_index;
++ WARN_ON(!((state->rx_pos & VCHIQ_SLOT_MASK) == 0));
++ rx_index = remote->slot_queue[
++ SLOT_QUEUE_INDEX_FROM_POS(state->rx_pos) &
++ VCHIQ_SLOT_QUEUE_MASK];
++ state->rx_data = (char *)SLOT_DATA_FROM_INDEX(state,
++ rx_index);
++ state->rx_info = SLOT_INFO_FROM_INDEX(state, rx_index);
++
++ /* Initialise use_count to one, and increment
++ ** release_count at the end of the slot to avoid
++ ** releasing the slot prematurely. */
++ state->rx_info->use_count = 1;
++ state->rx_info->release_count = 0;
++ }
++
++ header = (VCHIQ_HEADER_T *)(state->rx_data +
++ (state->rx_pos & VCHIQ_SLOT_MASK));
++ DEBUG_VALUE(PARSE_HEADER, (int)header);
++ msgid = header->msgid;
++ DEBUG_VALUE(PARSE_MSGID, msgid);
++ size = header->size;
++ type = VCHIQ_MSG_TYPE(msgid);
++ localport = VCHIQ_MSG_DSTPORT(msgid);
++ remoteport = VCHIQ_MSG_SRCPORT(msgid);
++
++ if (type != VCHIQ_MSG_DATA)
++ VCHIQ_STATS_INC(state, ctrl_rx_count);
++
++ switch (type) {
++ case VCHIQ_MSG_OPENACK:
++ case VCHIQ_MSG_CLOSE:
++ case VCHIQ_MSG_DATA:
++ case VCHIQ_MSG_BULK_RX:
++ case VCHIQ_MSG_BULK_TX:
++ case VCHIQ_MSG_BULK_RX_DONE:
++ case VCHIQ_MSG_BULK_TX_DONE:
++ service = find_service_by_port(state, localport);
++ if ((!service ||
++ ((service->remoteport != remoteport) &&
++ (service->remoteport != VCHIQ_PORT_FREE))) &&
++ (localport == 0) &&
++ (type == VCHIQ_MSG_CLOSE)) {
++ /* This could be a CLOSE from a client which
++ hadn't yet received the OPENACK - look for
++ the connected service */
++ if (service)
++ unlock_service(service);
++ service = get_connected_service(state,
++ remoteport);
++ if (service)
++ vchiq_log_warning(vchiq_core_log_level,
++ "%d: prs %s@%x (%d->%d) - "
++ "found connected service %d",
++ state->id, msg_type_str(type),
++ (unsigned int)header,
++ remoteport, localport,
++ service->localport);
++ }
++
++ if (!service) {
++ vchiq_log_error(vchiq_core_log_level,
++ "%d: prs %s@%x (%d->%d) - "
++ "invalid/closed service %d",
++ state->id, msg_type_str(type),
++ (unsigned int)header,
++ remoteport, localport, localport);
++ goto skip_message;
++ }
++ break;
++ default:
++ break;
++ }
++
++ if (SRVTRACE_ENABLED(service, VCHIQ_LOG_INFO)) {
++ int svc_fourcc;
++
++ svc_fourcc = service
++ ? service->base.fourcc
++ : VCHIQ_MAKE_FOURCC('?', '?', '?', '?');
++ vchiq_log_info(SRVTRACE_LEVEL(service),
++ "Rcvd Msg %s(%u) from %c%c%c%c s:%d d:%d "
++ "len:%d",
++ msg_type_str(type), type,
++ VCHIQ_FOURCC_AS_4CHARS(svc_fourcc),
++ remoteport, localport, size);
++ if (size > 0)
++ vchiq_log_dump_mem("Rcvd", 0, header->data,
++ min(64, size));
++ }
++
++ if (((unsigned int)header & VCHIQ_SLOT_MASK) + calc_stride(size)
++ > VCHIQ_SLOT_SIZE) {
++ vchiq_log_error(vchiq_core_log_level,
++ "header %x (msgid %x) - size %x too big for "
++ "slot",
++ (unsigned int)header, (unsigned int)msgid,
++ (unsigned int)size);
++ WARN(1, "oversized for slot\n");
++ }
++
++ switch (type) {
++ case VCHIQ_MSG_OPEN:
++ WARN_ON(!(VCHIQ_MSG_DSTPORT(msgid) == 0));
++ if (!parse_open(state, header))
++ goto bail_not_ready;
++ break;
++ case VCHIQ_MSG_OPENACK:
++ if (size >= sizeof(struct vchiq_openack_payload)) {
++ const struct vchiq_openack_payload *payload =
++ (struct vchiq_openack_payload *)
++ header->data;
++ service->peer_version = payload->version;
++ }
++ vchiq_log_info(vchiq_core_log_level,
++ "%d: prs OPENACK@%x,%x (%d->%d) v:%d",
++ state->id, (unsigned int)header, size,
++ remoteport, localport, service->peer_version);
++ if (service->srvstate ==
++ VCHIQ_SRVSTATE_OPENING) {
++ service->remoteport = remoteport;
++ vchiq_set_service_state(service,
++ VCHIQ_SRVSTATE_OPEN);
++ up(&service->remove_event);
++ } else
++ vchiq_log_error(vchiq_core_log_level,
++ "OPENACK received in state %s",
++ srvstate_names[service->srvstate]);
++ break;
++ case VCHIQ_MSG_CLOSE:
++ WARN_ON(size != 0); /* There should be no data */
++
++ vchiq_log_info(vchiq_core_log_level,
++ "%d: prs CLOSE@%x (%d->%d)",
++ state->id, (unsigned int)header,
++ remoteport, localport);
++
++ mark_service_closing_internal(service, 1);
++
++ if (vchiq_close_service_internal(service,
++ 1/*close_recvd*/) == VCHIQ_RETRY)
++ goto bail_not_ready;
++
++ vchiq_log_info(vchiq_core_log_level,
++ "Close Service %c%c%c%c s:%u d:%d",
++ VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc),
++ service->localport,
++ service->remoteport);
++ break;
++ case VCHIQ_MSG_DATA:
++ vchiq_log_info(vchiq_core_log_level,
++ "%d: prs DATA@%x,%x (%d->%d)",
++ state->id, (unsigned int)header, size,
++ remoteport, localport);
++
++ if ((service->remoteport == remoteport)
++ && (service->srvstate ==
++ VCHIQ_SRVSTATE_OPEN)) {
++ header->msgid = msgid | VCHIQ_MSGID_CLAIMED;
++ claim_slot(state->rx_info);
++ DEBUG_TRACE(PARSE_LINE);
++ if (make_service_callback(service,
++ VCHIQ_MESSAGE_AVAILABLE, header,
++ NULL) == VCHIQ_RETRY) {
++ DEBUG_TRACE(PARSE_LINE);
++ goto bail_not_ready;
++ }
++ VCHIQ_SERVICE_STATS_INC(service, ctrl_rx_count);
++ VCHIQ_SERVICE_STATS_ADD(service, ctrl_rx_bytes,
++ size);
++ } else {
++ VCHIQ_STATS_INC(state, error_count);
++ }
++ break;
++ case VCHIQ_MSG_CONNECT:
++ vchiq_log_info(vchiq_core_log_level,
++ "%d: prs CONNECT@%x",
++ state->id, (unsigned int)header);
++ state->version_common = ((VCHIQ_SLOT_ZERO_T *)
++ state->slot_data)->version;
++ up(&state->connect);
++ break;
++ case VCHIQ_MSG_BULK_RX:
++ case VCHIQ_MSG_BULK_TX: {
++ VCHIQ_BULK_QUEUE_T *queue;
++ WARN_ON(!state->is_master);
++ queue = (type == VCHIQ_MSG_BULK_RX) ?
++ &service->bulk_tx : &service->bulk_rx;
++ if ((service->remoteport == remoteport)
++ && (service->srvstate ==
++ VCHIQ_SRVSTATE_OPEN)) {
++ VCHIQ_BULK_T *bulk;
++ int resolved = 0;
++
++ DEBUG_TRACE(PARSE_LINE);
++ if (mutex_lock_interruptible(
++ &service->bulk_mutex) != 0) {
++ DEBUG_TRACE(PARSE_LINE);
++ goto bail_not_ready;
++ }
++
++ WARN_ON(!(queue->remote_insert < queue->remove +
++ VCHIQ_NUM_SERVICE_BULKS));
++ bulk = &queue->bulks[
++ BULK_INDEX(queue->remote_insert)];
++ bulk->remote_data =
++ (void *)((int *)header->data)[0];
++ bulk->remote_size = ((int *)header->data)[1];
++ wmb();
++
++ vchiq_log_info(vchiq_core_log_level,
++ "%d: prs %s@%x (%d->%d) %x@%x",
++ state->id, msg_type_str(type),
++ (unsigned int)header,
++ remoteport, localport,
++ bulk->remote_size,
++ (unsigned int)bulk->remote_data);
++
++ queue->remote_insert++;
++
++ if (atomic_read(&pause_bulks_count)) {
++ state->deferred_bulks++;
++ vchiq_log_info(vchiq_core_log_level,
++ "%s: deferring bulk (%d)",
++ __func__,
++ state->deferred_bulks);
++ if (state->conn_state !=
++ VCHIQ_CONNSTATE_PAUSE_SENT)
++ vchiq_log_error(
++ vchiq_core_log_level,
++ "%s: bulks paused in "
++ "unexpected state %s",
++ __func__,
++ conn_state_names[
++ state->conn_state]);
++ } else if (state->conn_state ==
++ VCHIQ_CONNSTATE_CONNECTED) {
++ DEBUG_TRACE(PARSE_LINE);
++ resolved = resolve_bulks(service,
++ queue);
++ }
++
++ mutex_unlock(&service->bulk_mutex);
++ if (resolved)
++ notify_bulks(service, queue,
++ 1/*retry_poll*/);
++ }
++ } break;
++ case VCHIQ_MSG_BULK_RX_DONE:
++ case VCHIQ_MSG_BULK_TX_DONE:
++ WARN_ON(state->is_master);
++ if ((service->remoteport == remoteport)
++ && (service->srvstate !=
++ VCHIQ_SRVSTATE_FREE)) {
++ VCHIQ_BULK_QUEUE_T *queue;
++ VCHIQ_BULK_T *bulk;
++
++ queue = (type == VCHIQ_MSG_BULK_RX_DONE) ?
++ &service->bulk_rx : &service->bulk_tx;
++
++ DEBUG_TRACE(PARSE_LINE);
++ if (mutex_lock_interruptible(
++ &service->bulk_mutex) != 0) {
++ DEBUG_TRACE(PARSE_LINE);
++ goto bail_not_ready;
++ }
++ if ((int)(queue->remote_insert -
++ queue->local_insert) >= 0) {
++ vchiq_log_error(vchiq_core_log_level,
++ "%d: prs %s@%x (%d->%d) "
++ "unexpected (ri=%d,li=%d)",
++ state->id, msg_type_str(type),
++ (unsigned int)header,
++ remoteport, localport,
++ queue->remote_insert,
++ queue->local_insert);
++ mutex_unlock(&service->bulk_mutex);
++ break;
++ }
++
++ BUG_ON(queue->process == queue->local_insert);
++ BUG_ON(queue->process != queue->remote_insert);
++
++ bulk = &queue->bulks[
++ BULK_INDEX(queue->remote_insert)];
++ bulk->actual = *(int *)header->data;
++ queue->remote_insert++;
++
++ vchiq_log_info(vchiq_core_log_level,
++ "%d: prs %s@%x (%d->%d) %x@%x",
++ state->id, msg_type_str(type),
++ (unsigned int)header,
++ remoteport, localport,
++ bulk->actual, (unsigned int)bulk->data);
++
++ vchiq_log_trace(vchiq_core_log_level,
++ "%d: prs:%d %cx li=%x ri=%x p=%x",
++ state->id, localport,
++ (type == VCHIQ_MSG_BULK_RX_DONE) ?
++ 'r' : 't',
++ queue->local_insert,
++ queue->remote_insert, queue->process);
++
++ DEBUG_TRACE(PARSE_LINE);
++ WARN_ON(queue->process == queue->local_insert);
++ vchiq_complete_bulk(bulk);
++ queue->process++;
++ mutex_unlock(&service->bulk_mutex);
++ DEBUG_TRACE(PARSE_LINE);
++ notify_bulks(service, queue, 1/*retry_poll*/);
++ DEBUG_TRACE(PARSE_LINE);
++ }
++ break;
++ case VCHIQ_MSG_PADDING:
++ vchiq_log_trace(vchiq_core_log_level,
++ "%d: prs PADDING@%x,%x",
++ state->id, (unsigned int)header, size);
++ break;
++ case VCHIQ_MSG_PAUSE:
++ /* If initiated, signal the application thread */
++ vchiq_log_trace(vchiq_core_log_level,
++ "%d: prs PAUSE@%x,%x",
++ state->id, (unsigned int)header, size);
++ if (state->conn_state == VCHIQ_CONNSTATE_PAUSED) {
++ vchiq_log_error(vchiq_core_log_level,
++ "%d: PAUSE received in state PAUSED",
++ state->id);
++ break;
++ }
++ if (state->conn_state != VCHIQ_CONNSTATE_PAUSE_SENT) {
++ /* Send a PAUSE in response */
++ if (queue_message(state, NULL,
++ VCHIQ_MAKE_MSG(VCHIQ_MSG_PAUSE, 0, 0),
++ NULL, 0, 0, QMFLAGS_NO_MUTEX_UNLOCK)
++ == VCHIQ_RETRY)
++ goto bail_not_ready;
++ if (state->is_master)
++ pause_bulks(state);
++ }
++ /* At this point slot_mutex is held */
++ vchiq_set_conn_state(state, VCHIQ_CONNSTATE_PAUSED);
++ vchiq_platform_paused(state);
++ break;
++ case VCHIQ_MSG_RESUME:
++ vchiq_log_trace(vchiq_core_log_level,
++ "%d: prs RESUME@%x,%x",
++ state->id, (unsigned int)header, size);
++ /* Release the slot mutex */
++ mutex_unlock(&state->slot_mutex);
++ if (state->is_master)
++ resume_bulks(state);
++ vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTED);
++ vchiq_platform_resumed(state);
++ break;
++
++ case VCHIQ_MSG_REMOTE_USE:
++ vchiq_on_remote_use(state);
++ break;
++ case VCHIQ_MSG_REMOTE_RELEASE:
++ vchiq_on_remote_release(state);
++ break;
++ case VCHIQ_MSG_REMOTE_USE_ACTIVE:
++ vchiq_on_remote_use_active(state);
++ break;
++
++ default:
++ vchiq_log_error(vchiq_core_log_level,
++ "%d: prs invalid msgid %x@%x,%x",
++ state->id, msgid, (unsigned int)header, size);
++ WARN(1, "invalid message\n");
++ break;
++ }
++
++skip_message:
++ if (service) {
++ unlock_service(service);
++ service = NULL;
++ }
++
++ state->rx_pos += calc_stride(size);
++
++ DEBUG_TRACE(PARSE_LINE);
++ /* Perform some housekeeping when the end of the slot is
++ ** reached. */
++ if ((state->rx_pos & VCHIQ_SLOT_MASK) == 0) {
++ /* Remove the extra reference count. */
++ release_slot(state, state->rx_info, NULL, NULL);
++ state->rx_data = NULL;
++ }
++ }
++
++bail_not_ready:
++ if (service)
++ unlock_service(service);
++}
++
++/* Called by the slot handler thread */
++static int
++slot_handler_func(void *v)
++{
++ VCHIQ_STATE_T *state = (VCHIQ_STATE_T *) v;
++ VCHIQ_SHARED_STATE_T *local = state->local;
++ DEBUG_INITIALISE(local)
++
++ while (1) {
++ DEBUG_COUNT(SLOT_HANDLER_COUNT);
++ DEBUG_TRACE(SLOT_HANDLER_LINE);
++ remote_event_wait(&local->trigger);
++
++ rmb();
++
++ DEBUG_TRACE(SLOT_HANDLER_LINE);
++ if (state->poll_needed) {
++ /* Check if we need to suspend - may change our
++ * conn_state */
++ vchiq_platform_check_suspend(state);
++
++ state->poll_needed = 0;
++
++ /* Handle service polling and other rare conditions here
++ ** out of the mainline code */
++ switch (state->conn_state) {
++ case VCHIQ_CONNSTATE_CONNECTED:
++ /* Poll the services as requested */
++ poll_services(state);
++ break;
++
++ case VCHIQ_CONNSTATE_PAUSING:
++ if (state->is_master)
++ pause_bulks(state);
++ if (queue_message(state, NULL,
++ VCHIQ_MAKE_MSG(VCHIQ_MSG_PAUSE, 0, 0),
++ NULL, 0, 0,
++ QMFLAGS_NO_MUTEX_UNLOCK)
++ != VCHIQ_RETRY) {
++ vchiq_set_conn_state(state,
++ VCHIQ_CONNSTATE_PAUSE_SENT);
++ } else {
++ if (state->is_master)
++ resume_bulks(state);
++ /* Retry later */
++ state->poll_needed = 1;
++ }
++ break;
++
++ case VCHIQ_CONNSTATE_PAUSED:
++ vchiq_platform_resume(state);
++ break;
++
++ case VCHIQ_CONNSTATE_RESUMING:
++ if (queue_message(state, NULL,
++ VCHIQ_MAKE_MSG(VCHIQ_MSG_RESUME, 0, 0),
++ NULL, 0, 0, QMFLAGS_NO_MUTEX_LOCK)
++ != VCHIQ_RETRY) {
++ if (state->is_master)
++ resume_bulks(state);
++ vchiq_set_conn_state(state,
++ VCHIQ_CONNSTATE_CONNECTED);
++ vchiq_platform_resumed(state);
++ } else {
++ /* This should really be impossible,
++ ** since the PAUSE should have flushed
++ ** through outstanding messages. */
++ vchiq_log_error(vchiq_core_log_level,
++ "Failed to send RESUME "
++ "message");
++ BUG();
++ }
++ break;
++
++ case VCHIQ_CONNSTATE_PAUSE_TIMEOUT:
++ case VCHIQ_CONNSTATE_RESUME_TIMEOUT:
++ vchiq_platform_handle_timeout(state);
++ break;
++ default:
++ break;
++ }
++
++
++ }
++
++ DEBUG_TRACE(SLOT_HANDLER_LINE);
++ parse_rx_slots(state);
++ }
++ return 0;
++}
++
++
++/* Called by the recycle thread */
++static int
++recycle_func(void *v)
++{
++ VCHIQ_STATE_T *state = (VCHIQ_STATE_T *) v;
++ VCHIQ_SHARED_STATE_T *local = state->local;
++
++ while (1) {
++ remote_event_wait(&local->recycle);
++
++ process_free_queue(state);
++ }
++ return 0;
++}
++
++
++/* Called by the sync thread */
++static int
++sync_func(void *v)
++{
++ VCHIQ_STATE_T *state = (VCHIQ_STATE_T *) v;
++ VCHIQ_SHARED_STATE_T *local = state->local;
++ VCHIQ_HEADER_T *header = (VCHIQ_HEADER_T *)SLOT_DATA_FROM_INDEX(state,
++ state->remote->slot_sync);
++
++ while (1) {
++ VCHIQ_SERVICE_T *service;
++ int msgid, size;
++ int type;
++ unsigned int localport, remoteport;
++
++ remote_event_wait(&local->sync_trigger);
++
++ rmb();
++
++ msgid = header->msgid;
++ size = header->size;
++ type = VCHIQ_MSG_TYPE(msgid);
++ localport = VCHIQ_MSG_DSTPORT(msgid);
++ remoteport = VCHIQ_MSG_SRCPORT(msgid);
++
++ service = find_service_by_port(state, localport);
++
++ if (!service) {
++ vchiq_log_error(vchiq_sync_log_level,
++ "%d: sf %s@%x (%d->%d) - "
++ "invalid/closed service %d",
++ state->id, msg_type_str(type),
++ (unsigned int)header,
++ remoteport, localport, localport);
++ release_message_sync(state, header);
++ continue;
++ }
++
++ if (vchiq_sync_log_level >= VCHIQ_LOG_TRACE) {
++ int svc_fourcc;
++
++ svc_fourcc = service
++ ? service->base.fourcc
++ : VCHIQ_MAKE_FOURCC('?', '?', '?', '?');
++ vchiq_log_trace(vchiq_sync_log_level,
++ "Rcvd Msg %s from %c%c%c%c s:%d d:%d len:%d",
++ msg_type_str(type),
++ VCHIQ_FOURCC_AS_4CHARS(svc_fourcc),
++ remoteport, localport, size);
++ if (size > 0)
++ vchiq_log_dump_mem("Rcvd", 0, header->data,
++ min(64, size));
++ }
++
++ switch (type) {
++ case VCHIQ_MSG_OPENACK:
++ if (size >= sizeof(struct vchiq_openack_payload)) {
++ const struct vchiq_openack_payload *payload =
++ (struct vchiq_openack_payload *)
++ header->data;
++ service->peer_version = payload->version;
++ }
++ vchiq_log_info(vchiq_sync_log_level,
++ "%d: sf OPENACK@%x,%x (%d->%d) v:%d",
++ state->id, (unsigned int)header, size,
++ remoteport, localport, service->peer_version);
++ if (service->srvstate == VCHIQ_SRVSTATE_OPENING) {
++ service->remoteport = remoteport;
++ vchiq_set_service_state(service,
++ VCHIQ_SRVSTATE_OPENSYNC);
++ service->sync = 1;
++ up(&service->remove_event);
++ }
++ release_message_sync(state, header);
++ break;
++
++ case VCHIQ_MSG_DATA:
++ vchiq_log_trace(vchiq_sync_log_level,
++ "%d: sf DATA@%x,%x (%d->%d)",
++ state->id, (unsigned int)header, size,
++ remoteport, localport);
++
++ if ((service->remoteport == remoteport) &&
++ (service->srvstate ==
++ VCHIQ_SRVSTATE_OPENSYNC)) {
++ if (make_service_callback(service,
++ VCHIQ_MESSAGE_AVAILABLE, header,
++ NULL) == VCHIQ_RETRY)
++ vchiq_log_error(vchiq_sync_log_level,
++ "synchronous callback to "
++ "service %d returns "
++ "VCHIQ_RETRY",
++ localport);
++ }
++ break;
++
++ default:
++ vchiq_log_error(vchiq_sync_log_level,
++ "%d: sf unexpected msgid %x@%x,%x",
++ state->id, msgid, (unsigned int)header, size);
++ release_message_sync(state, header);
++ break;
++ }
++
++ unlock_service(service);
++ }
++
++ return 0;
++}
++
++
++static void
++init_bulk_queue(VCHIQ_BULK_QUEUE_T *queue)
++{
++ queue->local_insert = 0;
++ queue->remote_insert = 0;
++ queue->process = 0;
++ queue->remote_notify = 0;
++ queue->remove = 0;
++}
++
++
++inline const char *
++get_conn_state_name(VCHIQ_CONNSTATE_T conn_state)
++{
++ return conn_state_names[conn_state];
++}
++
++
++VCHIQ_SLOT_ZERO_T *
++vchiq_init_slots(void *mem_base, int mem_size)
++{
++ int mem_align = (VCHIQ_SLOT_SIZE - (int)mem_base) & VCHIQ_SLOT_MASK;
++ VCHIQ_SLOT_ZERO_T *slot_zero =
++ (VCHIQ_SLOT_ZERO_T *)((char *)mem_base + mem_align);
++ int num_slots = (mem_size - mem_align)/VCHIQ_SLOT_SIZE;
++ int first_data_slot = VCHIQ_SLOT_ZERO_SLOTS;
++
++ /* Ensure there is enough memory to run an absolutely minimum system */
++ num_slots -= first_data_slot;
++
++ if (num_slots < 4) {
++ vchiq_log_error(vchiq_core_log_level,
++ "vchiq_init_slots - insufficient memory %x bytes",
++ mem_size);
++ return NULL;
++ }
++
++ memset(slot_zero, 0, sizeof(VCHIQ_SLOT_ZERO_T));
++
++ slot_zero->magic = VCHIQ_MAGIC;
++ slot_zero->version = VCHIQ_VERSION;
++ slot_zero->version_min = VCHIQ_VERSION_MIN;
++ slot_zero->slot_zero_size = sizeof(VCHIQ_SLOT_ZERO_T);
++ slot_zero->slot_size = VCHIQ_SLOT_SIZE;
++ slot_zero->max_slots = VCHIQ_MAX_SLOTS;
++ slot_zero->max_slots_per_side = VCHIQ_MAX_SLOTS_PER_SIDE;
++
++ slot_zero->master.slot_sync = first_data_slot;
++ slot_zero->master.slot_first = first_data_slot + 1;
++ slot_zero->master.slot_last = first_data_slot + (num_slots/2) - 1;
++ slot_zero->slave.slot_sync = first_data_slot + (num_slots/2);
++ slot_zero->slave.slot_first = first_data_slot + (num_slots/2) + 1;
++ slot_zero->slave.slot_last = first_data_slot + num_slots - 1;
++
++ return slot_zero;
++}
++
++VCHIQ_STATUS_T
++vchiq_init_state(VCHIQ_STATE_T *state, VCHIQ_SLOT_ZERO_T *slot_zero,
++ int is_master)
++{
++ VCHIQ_SHARED_STATE_T *local;
++ VCHIQ_SHARED_STATE_T *remote;
++ VCHIQ_STATUS_T status;
++ char threadname[10];
++ static int id;
++ int i;
++
++ vchiq_log_warning(vchiq_core_log_level,
++ "%s: slot_zero = 0x%08lx, is_master = %d",
++ __func__, (unsigned long)slot_zero, is_master);
++
++ /* Check the input configuration */
++
++ if (slot_zero->magic != VCHIQ_MAGIC) {
++ vchiq_loud_error_header();
++ vchiq_loud_error("Invalid VCHIQ magic value found.");
++ vchiq_loud_error("slot_zero=%x: magic=%x (expected %x)",
++ (unsigned int)slot_zero, slot_zero->magic, VCHIQ_MAGIC);
++ vchiq_loud_error_footer();
++ return VCHIQ_ERROR;
++ }
++
++ if (slot_zero->version < VCHIQ_VERSION_MIN) {
++ vchiq_loud_error_header();
++ vchiq_loud_error("Incompatible VCHIQ versions found.");
++ vchiq_loud_error("slot_zero=%x: VideoCore version=%d "
++ "(minimum %d)",
++ (unsigned int)slot_zero, slot_zero->version,
++ VCHIQ_VERSION_MIN);
++ vchiq_loud_error("Restart with a newer VideoCore image.");
++ vchiq_loud_error_footer();
++ return VCHIQ_ERROR;
++ }
++
++ if (VCHIQ_VERSION < slot_zero->version_min) {
++ vchiq_loud_error_header();
++ vchiq_loud_error("Incompatible VCHIQ versions found.");
++ vchiq_loud_error("slot_zero=%x: version=%d (VideoCore "
++ "minimum %d)",
++ (unsigned int)slot_zero, VCHIQ_VERSION,
++ slot_zero->version_min);
++ vchiq_loud_error("Restart with a newer kernel.");
++ vchiq_loud_error_footer();
++ return VCHIQ_ERROR;
++ }
++
++ if ((slot_zero->slot_zero_size != sizeof(VCHIQ_SLOT_ZERO_T)) ||
++ (slot_zero->slot_size != VCHIQ_SLOT_SIZE) ||
++ (slot_zero->max_slots != VCHIQ_MAX_SLOTS) ||
++ (slot_zero->max_slots_per_side != VCHIQ_MAX_SLOTS_PER_SIDE)) {
++ vchiq_loud_error_header();
++ if (slot_zero->slot_zero_size != sizeof(VCHIQ_SLOT_ZERO_T))
++ vchiq_loud_error("slot_zero=%x: slot_zero_size=%x "
++ "(expected %x)",
++ (unsigned int)slot_zero,
++ slot_zero->slot_zero_size,
++ sizeof(VCHIQ_SLOT_ZERO_T));
++ if (slot_zero->slot_size != VCHIQ_SLOT_SIZE)
++ vchiq_loud_error("slot_zero=%x: slot_size=%d "
++ "(expected %d",
++ (unsigned int)slot_zero, slot_zero->slot_size,
++ VCHIQ_SLOT_SIZE);
++ if (slot_zero->max_slots != VCHIQ_MAX_SLOTS)
++ vchiq_loud_error("slot_zero=%x: max_slots=%d "
++ "(expected %d)",
++ (unsigned int)slot_zero, slot_zero->max_slots,
++ VCHIQ_MAX_SLOTS);
++ if (slot_zero->max_slots_per_side != VCHIQ_MAX_SLOTS_PER_SIDE)
++ vchiq_loud_error("slot_zero=%x: max_slots_per_side=%d "
++ "(expected %d)",
++ (unsigned int)slot_zero,
++ slot_zero->max_slots_per_side,
++ VCHIQ_MAX_SLOTS_PER_SIDE);
++ vchiq_loud_error_footer();
++ return VCHIQ_ERROR;
++ }
++
++ if (VCHIQ_VERSION < slot_zero->version)
++ slot_zero->version = VCHIQ_VERSION;
++
++ if (is_master) {
++ local = &slot_zero->master;
++ remote = &slot_zero->slave;
++ } else {
++ local = &slot_zero->slave;
++ remote = &slot_zero->master;
++ }
++
++ if (local->initialised) {
++ vchiq_loud_error_header();
++ if (remote->initialised)
++ vchiq_loud_error("local state has already been "
++ "initialised");
++ else
++ vchiq_loud_error("master/slave mismatch - two %ss",
++ is_master ? "master" : "slave");
++ vchiq_loud_error_footer();
++ return VCHIQ_ERROR;
++ }
++
++ memset(state, 0, sizeof(VCHIQ_STATE_T));
++
++ state->id = id++;
++ state->is_master = is_master;
++
++ /*
++ initialize shared state pointers
++ */
++
++ state->local = local;
++ state->remote = remote;
++ state->slot_data = (VCHIQ_SLOT_T *)slot_zero;
++
++ /*
++ initialize events and mutexes
++ */
++
++ sema_init(&state->connect, 0);
++ mutex_init(&state->mutex);
++ sema_init(&state->trigger_event, 0);
++ sema_init(&state->recycle_event, 0);
++ sema_init(&state->sync_trigger_event, 0);
++ sema_init(&state->sync_release_event, 0);
++
++ mutex_init(&state->slot_mutex);
++ mutex_init(&state->recycle_mutex);
++ mutex_init(&state->sync_mutex);
++ mutex_init(&state->bulk_transfer_mutex);
++
++ sema_init(&state->slot_available_event, 0);
++ sema_init(&state->slot_remove_event, 0);
++ sema_init(&state->data_quota_event, 0);
++
++ state->slot_queue_available = 0;
++
++ for (i = 0; i < VCHIQ_MAX_SERVICES; i++) {
++ VCHIQ_SERVICE_QUOTA_T *service_quota =
++ &state->service_quotas[i];
++ sema_init(&service_quota->quota_event, 0);
++ }
++
++ for (i = local->slot_first; i <= local->slot_last; i++) {
++ local->slot_queue[state->slot_queue_available++] = i;
++ up(&state->slot_available_event);
++ }
++
++ state->default_slot_quota = state->slot_queue_available/2;
++ state->default_message_quota =
++ min((unsigned short)(state->default_slot_quota * 256),
++ (unsigned short)~0);
++
++ state->previous_data_index = -1;
++ state->data_use_count = 0;
++ state->data_quota = state->slot_queue_available - 1;
++
++ local->trigger.event = &state->trigger_event;
++ remote_event_create(&local->trigger);
++ local->tx_pos = 0;
++
++ local->recycle.event = &state->recycle_event;
++ remote_event_create(&local->recycle);
++ local->slot_queue_recycle = state->slot_queue_available;
++
++ local->sync_trigger.event = &state->sync_trigger_event;
++ remote_event_create(&local->sync_trigger);
++
++ local->sync_release.event = &state->sync_release_event;
++ remote_event_create(&local->sync_release);
++
++ /* At start-of-day, the slot is empty and available */
++ ((VCHIQ_HEADER_T *)SLOT_DATA_FROM_INDEX(state, local->slot_sync))->msgid
++ = VCHIQ_MSGID_PADDING;
++ remote_event_signal_local(&local->sync_release);
++
++ local->debug[DEBUG_ENTRIES] = DEBUG_MAX;
++
++ status = vchiq_platform_init_state(state);
++
++ /*
++ bring up slot handler thread
++ */
++ snprintf(threadname, sizeof(threadname), "VCHIQ-%d", state->id);
++ state->slot_handler_thread = kthread_create(&slot_handler_func,
++ (void *)state,
++ threadname);
++
++ if (state->slot_handler_thread == NULL) {
++ vchiq_loud_error_header();
++ vchiq_loud_error("couldn't create thread %s", threadname);
++ vchiq_loud_error_footer();
++ return VCHIQ_ERROR;
++ }
++ set_user_nice(state->slot_handler_thread, -19);
++ wake_up_process(state->slot_handler_thread);
++
++ snprintf(threadname, sizeof(threadname), "VCHIQr-%d", state->id);
++ state->recycle_thread = kthread_create(&recycle_func,
++ (void *)state,
++ threadname);
++ if (state->recycle_thread == NULL) {
++ vchiq_loud_error_header();
++ vchiq_loud_error("couldn't create thread %s", threadname);
++ vchiq_loud_error_footer();
++ return VCHIQ_ERROR;
++ }
++ set_user_nice(state->recycle_thread, -19);
++ wake_up_process(state->recycle_thread);
++
++ snprintf(threadname, sizeof(threadname), "VCHIQs-%d", state->id);
++ state->sync_thread = kthread_create(&sync_func,
++ (void *)state,
++ threadname);
++ if (state->sync_thread == NULL) {
++ vchiq_loud_error_header();
++ vchiq_loud_error("couldn't create thread %s", threadname);
++ vchiq_loud_error_footer();
++ return VCHIQ_ERROR;
++ }
++ set_user_nice(state->sync_thread, -20);
++ wake_up_process(state->sync_thread);
++
++ BUG_ON(state->id >= VCHIQ_MAX_STATES);
++ vchiq_states[state->id] = state;
++
++ /* Indicate readiness to the other side */
++ local->initialised = 1;
++
++ return status;
++}
++
++/* Called from application thread when a client or server service is created. */
++VCHIQ_SERVICE_T *
++vchiq_add_service_internal(VCHIQ_STATE_T *state,
++ const VCHIQ_SERVICE_PARAMS_T *params, int srvstate,
++ VCHIQ_INSTANCE_T instance, VCHIQ_USERDATA_TERM_T userdata_term)
++{
++ VCHIQ_SERVICE_T *service;
++
++ service = kmalloc(sizeof(VCHIQ_SERVICE_T), GFP_KERNEL);
++ if (service) {
++ service->base.fourcc = params->fourcc;
++ service->base.callback = params->callback;
++ service->base.userdata = params->userdata;
++ service->handle = VCHIQ_SERVICE_HANDLE_INVALID;
++ service->ref_count = 1;
++ service->srvstate = VCHIQ_SRVSTATE_FREE;
++ service->userdata_term = userdata_term;
++ service->localport = VCHIQ_PORT_FREE;
++ service->remoteport = VCHIQ_PORT_FREE;
++
++ service->public_fourcc = (srvstate == VCHIQ_SRVSTATE_OPENING) ?
++ VCHIQ_FOURCC_INVALID : params->fourcc;
++ service->client_id = 0;
++ service->auto_close = 1;
++ service->sync = 0;
++ service->closing = 0;
++ service->trace = 0;
++ atomic_set(&service->poll_flags, 0);
++ service->version = params->version;
++ service->version_min = params->version_min;
++ service->state = state;
++ service->instance = instance;
++ service->service_use_count = 0;
++ init_bulk_queue(&service->bulk_tx);
++ init_bulk_queue(&service->bulk_rx);
++ sema_init(&service->remove_event, 0);
++ sema_init(&service->bulk_remove_event, 0);
++ mutex_init(&service->bulk_mutex);
++ memset(&service->stats, 0, sizeof(service->stats));
++ } else {
++ vchiq_log_error(vchiq_core_log_level,
++ "Out of memory");
++ }
++
++ if (service) {
++ VCHIQ_SERVICE_T **pservice = NULL;
++ int i;
++
++ /* Although it is perfectly possible to use service_spinlock
++ ** to protect the creation of services, it is overkill as it
++ ** disables interrupts while the array is searched.
++ ** The only danger is of another thread trying to create a
++ ** service - service deletion is safe.
++ ** Therefore it is preferable to use state->mutex which,
++ ** although slower to claim, doesn't block interrupts while
++ ** it is held.
++ */
++
++ mutex_lock(&state->mutex);
++
++ /* Prepare to use a previously unused service */
++ if (state->unused_service < VCHIQ_MAX_SERVICES)
++ pservice = &state->services[state->unused_service];
++
++ if (srvstate == VCHIQ_SRVSTATE_OPENING) {
++ for (i = 0; i < state->unused_service; i++) {
++ VCHIQ_SERVICE_T *srv = state->services[i];
++ if (!srv) {
++ pservice = &state->services[i];
++ break;
++ }
++ }
++ } else {
++ for (i = (state->unused_service - 1); i >= 0; i--) {
++ VCHIQ_SERVICE_T *srv = state->services[i];
++ if (!srv)
++ pservice = &state->services[i];
++ else if ((srv->public_fourcc == params->fourcc)
++ && ((srv->instance != instance) ||
++ (srv->base.callback !=
++ params->callback))) {
++ /* There is another server using this
++ ** fourcc which doesn't match. */
++ pservice = NULL;
++ break;
++ }
++ }
++ }
++
++ if (pservice) {
++ service->localport = (pservice - state->services);
++ if (!handle_seq)
++ handle_seq = VCHIQ_MAX_STATES *
++ VCHIQ_MAX_SERVICES;
++ service->handle = handle_seq |
++ (state->id * VCHIQ_MAX_SERVICES) |
++ service->localport;
++ handle_seq += VCHIQ_MAX_STATES * VCHIQ_MAX_SERVICES;
++ *pservice = service;
++ if (pservice == &state->services[state->unused_service])
++ state->unused_service++;
++ }
++
++ mutex_unlock(&state->mutex);
++
++ if (!pservice) {
++ kfree(service);
++ service = NULL;
++ }
++ }
++
++ if (service) {
++ VCHIQ_SERVICE_QUOTA_T *service_quota =
++ &state->service_quotas[service->localport];
++ service_quota->slot_quota = state->default_slot_quota;
++ service_quota->message_quota = state->default_message_quota;
++ if (service_quota->slot_use_count == 0)
++ service_quota->previous_tx_index =
++ SLOT_QUEUE_INDEX_FROM_POS(state->local_tx_pos)
++ - 1;
++
++ /* Bring this service online */
++ vchiq_set_service_state(service, srvstate);
++
++ vchiq_log_info(vchiq_core_msg_log_level,
++ "%s Service %c%c%c%c SrcPort:%d",
++ (srvstate == VCHIQ_SRVSTATE_OPENING)
++ ? "Open" : "Add",
++ VCHIQ_FOURCC_AS_4CHARS(params->fourcc),
++ service->localport);
++ }
++
++ /* Don't unlock the service - leave it with a ref_count of 1. */
++
++ return service;
++}
++
++VCHIQ_STATUS_T
++vchiq_open_service_internal(VCHIQ_SERVICE_T *service, int client_id)
++{
++ struct vchiq_open_payload payload = {
++ service->base.fourcc,
++ client_id,
++ service->version,
++ service->version_min
++ };
++ VCHIQ_ELEMENT_T body = { &payload, sizeof(payload) };
++ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
++
++ service->client_id = client_id;
++ vchiq_use_service_internal(service);
++ status = queue_message(service->state, NULL,
++ VCHIQ_MAKE_MSG(VCHIQ_MSG_OPEN, service->localport, 0),
++ &body, 1, sizeof(payload), QMFLAGS_IS_BLOCKING);
++ if (status == VCHIQ_SUCCESS) {
++ /* Wait for the ACK/NAK */
++ if (down_interruptible(&service->remove_event) != 0) {
++ status = VCHIQ_RETRY;
++ vchiq_release_service_internal(service);
++ } else if ((service->srvstate != VCHIQ_SRVSTATE_OPEN) &&
++ (service->srvstate != VCHIQ_SRVSTATE_OPENSYNC)) {
++ if (service->srvstate != VCHIQ_SRVSTATE_CLOSEWAIT)
++ vchiq_log_error(vchiq_core_log_level,
++ "%d: osi - srvstate = %s (ref %d)",
++ service->state->id,
++ srvstate_names[service->srvstate],
++ service->ref_count);
++ status = VCHIQ_ERROR;
++ VCHIQ_SERVICE_STATS_INC(service, error_count);
++ vchiq_release_service_internal(service);
++ }
++ }
++ return status;
++}
++
++static void
++release_service_messages(VCHIQ_SERVICE_T *service)
++{
++ VCHIQ_STATE_T *state = service->state;
++ int slot_last = state->remote->slot_last;
++ int i;
++
++ /* Release any claimed messages aimed at this service */
++
++ if (service->sync) {
++ VCHIQ_HEADER_T *header =
++ (VCHIQ_HEADER_T *)SLOT_DATA_FROM_INDEX(state,
++ state->remote->slot_sync);
++ if (VCHIQ_MSG_DSTPORT(header->msgid) == service->localport)
++ release_message_sync(state, header);
++
++ return;
++ }
++
++ for (i = state->remote->slot_first; i <= slot_last; i++) {
++ VCHIQ_SLOT_INFO_T *slot_info =
++ SLOT_INFO_FROM_INDEX(state, i);
++ if (slot_info->release_count != slot_info->use_count) {
++ char *data =
++ (char *)SLOT_DATA_FROM_INDEX(state, i);
++ unsigned int pos, end;
++
++ end = VCHIQ_SLOT_SIZE;
++ if (data == state->rx_data)
++ /* This buffer is still being read from - stop
++ ** at the current read position */
++ end = state->rx_pos & VCHIQ_SLOT_MASK;
++
++ pos = 0;
++
++ while (pos < end) {
++ VCHIQ_HEADER_T *header =
++ (VCHIQ_HEADER_T *)(data + pos);
++ int msgid = header->msgid;
++ int port = VCHIQ_MSG_DSTPORT(msgid);
++ if ((port == service->localport) &&
++ (msgid & VCHIQ_MSGID_CLAIMED)) {
++ vchiq_log_info(vchiq_core_log_level,
++ " fsi - hdr %x",
++ (unsigned int)header);
++ release_slot(state, slot_info, header,
++ NULL);
++ }
++ pos += calc_stride(header->size);
++ if (pos > VCHIQ_SLOT_SIZE) {
++ vchiq_log_error(vchiq_core_log_level,
++ "fsi - pos %x: header %x, "
++ "msgid %x, header->msgid %x, "
++ "header->size %x",
++ pos, (unsigned int)header,
++ msgid, header->msgid,
++ header->size);
++ WARN(1, "invalid slot position\n");
++ }
++ }
++ }
++ }
++}
++
++static int
++do_abort_bulks(VCHIQ_SERVICE_T *service)
++{
++ VCHIQ_STATUS_T status;
++
++ /* Abort any outstanding bulk transfers */
++ if (mutex_lock_interruptible(&service->bulk_mutex) != 0)
++ return 0;
++ abort_outstanding_bulks(service, &service->bulk_tx);
++ abort_outstanding_bulks(service, &service->bulk_rx);
++ mutex_unlock(&service->bulk_mutex);
++
++ status = notify_bulks(service, &service->bulk_tx, 0/*!retry_poll*/);
++ if (status == VCHIQ_SUCCESS)
++ status = notify_bulks(service, &service->bulk_rx,
++ 0/*!retry_poll*/);
++ return (status == VCHIQ_SUCCESS);
++}
++
++static VCHIQ_STATUS_T
++close_service_complete(VCHIQ_SERVICE_T *service, int failstate)
++{
++ VCHIQ_STATUS_T status;
++ int is_server = (service->public_fourcc != VCHIQ_FOURCC_INVALID);
++ int newstate;
++
++ switch (service->srvstate) {
++ case VCHIQ_SRVSTATE_OPEN:
++ case VCHIQ_SRVSTATE_CLOSESENT:
++ case VCHIQ_SRVSTATE_CLOSERECVD:
++ if (is_server) {
++ if (service->auto_close) {
++ service->client_id = 0;
++ service->remoteport = VCHIQ_PORT_FREE;
++ newstate = VCHIQ_SRVSTATE_LISTENING;
++ } else
++ newstate = VCHIQ_SRVSTATE_CLOSEWAIT;
++ } else
++ newstate = VCHIQ_SRVSTATE_CLOSED;
++ vchiq_set_service_state(service, newstate);
++ break;
++ case VCHIQ_SRVSTATE_LISTENING:
++ break;
++ default:
++ vchiq_log_error(vchiq_core_log_level,
++ "close_service_complete(%x) called in state %s",
++ service->handle, srvstate_names[service->srvstate]);
++ WARN(1, "close_service_complete in unexpected state\n");
++ return VCHIQ_ERROR;
++ }
++
++ status = make_service_callback(service,
++ VCHIQ_SERVICE_CLOSED, NULL, NULL);
++
++ if (status != VCHIQ_RETRY) {
++ int uc = service->service_use_count;
++ int i;
++ /* Complete the close process */
++ for (i = 0; i < uc; i++)
++ /* cater for cases where close is forced and the
++ ** client may not close all it's handles */
++ vchiq_release_service_internal(service);
++
++ service->client_id = 0;
++ service->remoteport = VCHIQ_PORT_FREE;
++
++ if (service->srvstate == VCHIQ_SRVSTATE_CLOSED)
++ vchiq_free_service_internal(service);
++ else if (service->srvstate != VCHIQ_SRVSTATE_CLOSEWAIT) {
++ if (is_server)
++ service->closing = 0;
++
++ up(&service->remove_event);
++ }
++ } else
++ vchiq_set_service_state(service, failstate);
++
++ return status;
++}
++
++/* Called by the slot handler */
++VCHIQ_STATUS_T
++vchiq_close_service_internal(VCHIQ_SERVICE_T *service, int close_recvd)
++{
++ VCHIQ_STATE_T *state = service->state;
++ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
++ int is_server = (service->public_fourcc != VCHIQ_FOURCC_INVALID);
++
++ vchiq_log_info(vchiq_core_log_level, "%d: csi:%d,%d (%s)",
++ service->state->id, service->localport, close_recvd,
++ srvstate_names[service->srvstate]);
++
++ switch (service->srvstate) {
++ case VCHIQ_SRVSTATE_CLOSED:
++ case VCHIQ_SRVSTATE_HIDDEN:
++ case VCHIQ_SRVSTATE_LISTENING:
++ case VCHIQ_SRVSTATE_CLOSEWAIT:
++ if (close_recvd)
++ vchiq_log_error(vchiq_core_log_level,
++ "vchiq_close_service_internal(1) called "
++ "in state %s",
++ srvstate_names[service->srvstate]);
++ else if (is_server) {
++ if (service->srvstate == VCHIQ_SRVSTATE_LISTENING) {
++ status = VCHIQ_ERROR;
++ } else {
++ service->client_id = 0;
++ service->remoteport = VCHIQ_PORT_FREE;
++ if (service->srvstate ==
++ VCHIQ_SRVSTATE_CLOSEWAIT)
++ vchiq_set_service_state(service,
++ VCHIQ_SRVSTATE_LISTENING);
++ }
++ up(&service->remove_event);
++ } else
++ vchiq_free_service_internal(service);
++ break;
++ case VCHIQ_SRVSTATE_OPENING:
++ if (close_recvd) {
++ /* The open was rejected - tell the user */
++ vchiq_set_service_state(service,
++ VCHIQ_SRVSTATE_CLOSEWAIT);
++ up(&service->remove_event);
++ } else {
++ /* Shutdown mid-open - let the other side know */
++ status = queue_message(state, service,
++ VCHIQ_MAKE_MSG
++ (VCHIQ_MSG_CLOSE,
++ service->localport,
++ VCHIQ_MSG_DSTPORT(service->remoteport)),
++ NULL, 0, 0, 0);
++ }
++ break;
++
++ case VCHIQ_SRVSTATE_OPENSYNC:
++ mutex_lock(&state->sync_mutex);
++ /* Drop through */
++
++ case VCHIQ_SRVSTATE_OPEN:
++ if (state->is_master || close_recvd) {
++ if (!do_abort_bulks(service))
++ status = VCHIQ_RETRY;
++ }
++
++ release_service_messages(service);
++
++ if (status == VCHIQ_SUCCESS)
++ status = queue_message(state, service,
++ VCHIQ_MAKE_MSG
++ (VCHIQ_MSG_CLOSE,
++ service->localport,
++ VCHIQ_MSG_DSTPORT(service->remoteport)),
++ NULL, 0, 0, QMFLAGS_NO_MUTEX_UNLOCK);
++
++ if (status == VCHIQ_SUCCESS) {
++ if (!close_recvd) {
++ /* Change the state while the mutex is
++ still held */
++ vchiq_set_service_state(service,
++ VCHIQ_SRVSTATE_CLOSESENT);
++ mutex_unlock(&state->slot_mutex);
++ if (service->sync)
++ mutex_unlock(&state->sync_mutex);
++ break;
++ }
++ } else if (service->srvstate == VCHIQ_SRVSTATE_OPENSYNC) {
++ mutex_unlock(&state->sync_mutex);
++ break;
++ } else
++ break;
++
++ /* Change the state while the mutex is still held */
++ vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSERECVD);
++ mutex_unlock(&state->slot_mutex);
++ if (service->sync)
++ mutex_unlock(&state->sync_mutex);
++
++ status = close_service_complete(service,
++ VCHIQ_SRVSTATE_CLOSERECVD);
++ break;
++
++ case VCHIQ_SRVSTATE_CLOSESENT:
++ if (!close_recvd)
++ /* This happens when a process is killed mid-close */
++ break;
++
++ if (!state->is_master) {
++ if (!do_abort_bulks(service)) {
++ status = VCHIQ_RETRY;
++ break;
++ }
++ }
++
++ if (status == VCHIQ_SUCCESS)
++ status = close_service_complete(service,
++ VCHIQ_SRVSTATE_CLOSERECVD);
++ break;
++
++ case VCHIQ_SRVSTATE_CLOSERECVD:
++ if (!close_recvd && is_server)
++ /* Force into LISTENING mode */
++ vchiq_set_service_state(service,
++ VCHIQ_SRVSTATE_LISTENING);
++ status = close_service_complete(service,
++ VCHIQ_SRVSTATE_CLOSERECVD);
++ break;
++
++ default:
++ vchiq_log_error(vchiq_core_log_level,
++ "vchiq_close_service_internal(%d) called in state %s",
++ close_recvd, srvstate_names[service->srvstate]);
++ break;
++ }
++
++ return status;
++}
++
++/* Called from the application process upon process death */
++void
++vchiq_terminate_service_internal(VCHIQ_SERVICE_T *service)
++{
++ VCHIQ_STATE_T *state = service->state;
++
++ vchiq_log_info(vchiq_core_log_level, "%d: tsi - (%d<->%d)",
++ state->id, service->localport, service->remoteport);
++
++ mark_service_closing(service);
++
++ /* Mark the service for removal by the slot handler */
++ request_poll(state, service, VCHIQ_POLL_REMOVE);
++}
++
++/* Called from the slot handler */
++void
++vchiq_free_service_internal(VCHIQ_SERVICE_T *service)
++{
++ VCHIQ_STATE_T *state = service->state;
++
++ vchiq_log_info(vchiq_core_log_level, "%d: fsi - (%d)",
++ state->id, service->localport);
++
++ switch (service->srvstate) {
++ case VCHIQ_SRVSTATE_OPENING:
++ case VCHIQ_SRVSTATE_CLOSED:
++ case VCHIQ_SRVSTATE_HIDDEN:
++ case VCHIQ_SRVSTATE_LISTENING:
++ case VCHIQ_SRVSTATE_CLOSEWAIT:
++ break;
++ default:
++ vchiq_log_error(vchiq_core_log_level,
++ "%d: fsi - (%d) in state %s",
++ state->id, service->localport,
++ srvstate_names[service->srvstate]);
++ return;
++ }
++
++ vchiq_set_service_state(service, VCHIQ_SRVSTATE_FREE);
++
++ up(&service->remove_event);
++
++ /* Release the initial lock */
++ unlock_service(service);
++}
++
++VCHIQ_STATUS_T
++vchiq_connect_internal(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance)
++{
++ VCHIQ_SERVICE_T *service;
++ int i;
++
++ /* Find all services registered to this client and enable them. */
++ i = 0;
++ while ((service = next_service_by_instance(state, instance,
++ &i)) != NULL) {
++ if (service->srvstate == VCHIQ_SRVSTATE_HIDDEN)
++ vchiq_set_service_state(service,
++ VCHIQ_SRVSTATE_LISTENING);
++ unlock_service(service);
++ }
++
++ if (state->conn_state == VCHIQ_CONNSTATE_DISCONNECTED) {
++ if (queue_message(state, NULL,
++ VCHIQ_MAKE_MSG(VCHIQ_MSG_CONNECT, 0, 0), NULL, 0,
++ 0, QMFLAGS_IS_BLOCKING) == VCHIQ_RETRY)
++ return VCHIQ_RETRY;
++
++ vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTING);
++ }
++
++ if (state->conn_state == VCHIQ_CONNSTATE_CONNECTING) {
++ if (down_interruptible(&state->connect) != 0)
++ return VCHIQ_RETRY;
++
++ vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTED);
++ up(&state->connect);
++ }
++
++ return VCHIQ_SUCCESS;
++}
++
++VCHIQ_STATUS_T
++vchiq_shutdown_internal(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance)
++{
++ VCHIQ_SERVICE_T *service;
++ int i;
++
++ /* Find all services registered to this client and enable them. */
++ i = 0;
++ while ((service = next_service_by_instance(state, instance,
++ &i)) != NULL) {
++ (void)vchiq_remove_service(service->handle);
++ unlock_service(service);
++ }
++
++ return VCHIQ_SUCCESS;
++}
++
++VCHIQ_STATUS_T
++vchiq_pause_internal(VCHIQ_STATE_T *state)
++{
++ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
++
++ switch (state->conn_state) {
++ case VCHIQ_CONNSTATE_CONNECTED:
++ /* Request a pause */
++ vchiq_set_conn_state(state, VCHIQ_CONNSTATE_PAUSING);
++ request_poll(state, NULL, 0);
++ break;
++ default:
++ vchiq_log_error(vchiq_core_log_level,
++ "vchiq_pause_internal in state %s\n",
++ conn_state_names[state->conn_state]);
++ status = VCHIQ_ERROR;
++ VCHIQ_STATS_INC(state, error_count);
++ break;
++ }
++
++ return status;
++}
++
++VCHIQ_STATUS_T
++vchiq_resume_internal(VCHIQ_STATE_T *state)
++{
++ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
++
++ if (state->conn_state == VCHIQ_CONNSTATE_PAUSED) {
++ vchiq_set_conn_state(state, VCHIQ_CONNSTATE_RESUMING);
++ request_poll(state, NULL, 0);
++ } else {
++ status = VCHIQ_ERROR;
++ VCHIQ_STATS_INC(state, error_count);
++ }
++
++ return status;
++}
++
++VCHIQ_STATUS_T
++vchiq_close_service(VCHIQ_SERVICE_HANDLE_T handle)
++{
++ /* Unregister the service */
++ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
++ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
++
++ if (!service)
++ return VCHIQ_ERROR;
++
++ vchiq_log_info(vchiq_core_log_level,
++ "%d: close_service:%d",
++ service->state->id, service->localport);
++
++ if ((service->srvstate == VCHIQ_SRVSTATE_FREE) ||
++ (service->srvstate == VCHIQ_SRVSTATE_LISTENING) ||
++ (service->srvstate == VCHIQ_SRVSTATE_HIDDEN)) {
++ unlock_service(service);
++ return VCHIQ_ERROR;
++ }
++
++ mark_service_closing(service);
++
++ if (current == service->state->slot_handler_thread) {
++ status = vchiq_close_service_internal(service,
++ 0/*!close_recvd*/);
++ BUG_ON(status == VCHIQ_RETRY);
++ } else {
++ /* Mark the service for termination by the slot handler */
++ request_poll(service->state, service, VCHIQ_POLL_TERMINATE);
++ }
++
++ while (1) {
++ if (down_interruptible(&service->remove_event) != 0) {
++ status = VCHIQ_RETRY;
++ break;
++ }
++
++ if ((service->srvstate == VCHIQ_SRVSTATE_FREE) ||
++ (service->srvstate == VCHIQ_SRVSTATE_LISTENING) ||
++ (service->srvstate == VCHIQ_SRVSTATE_OPEN))
++ break;
++
++ vchiq_log_warning(vchiq_core_log_level,
++ "%d: close_service:%d - waiting in state %s",
++ service->state->id, service->localport,
++ srvstate_names[service->srvstate]);
++ }
++
++ if ((status == VCHIQ_SUCCESS) &&
++ (service->srvstate != VCHIQ_SRVSTATE_FREE) &&
++ (service->srvstate != VCHIQ_SRVSTATE_LISTENING))
++ status = VCHIQ_ERROR;
++
++ unlock_service(service);
++
++ return status;
++}
++
++VCHIQ_STATUS_T
++vchiq_remove_service(VCHIQ_SERVICE_HANDLE_T handle)
++{
++ /* Unregister the service */
++ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
++ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
++
++ if (!service)
++ return VCHIQ_ERROR;
++
++ vchiq_log_info(vchiq_core_log_level,
++ "%d: remove_service:%d",
++ service->state->id, service->localport);
++
++ if (service->srvstate == VCHIQ_SRVSTATE_FREE) {
++ unlock_service(service);
++ return VCHIQ_ERROR;
++ }
++
++ mark_service_closing(service);
++
++ if ((service->srvstate == VCHIQ_SRVSTATE_HIDDEN) ||
++ (current == service->state->slot_handler_thread)) {
++ /* Make it look like a client, because it must be removed and
++ not left in the LISTENING state. */
++ service->public_fourcc = VCHIQ_FOURCC_INVALID;
++
++ status = vchiq_close_service_internal(service,
++ 0/*!close_recvd*/);
++ BUG_ON(status == VCHIQ_RETRY);
++ } else {
++ /* Mark the service for removal by the slot handler */
++ request_poll(service->state, service, VCHIQ_POLL_REMOVE);
++ }
++ while (1) {
++ if (down_interruptible(&service->remove_event) != 0) {
++ status = VCHIQ_RETRY;
++ break;
++ }
++
++ if ((service->srvstate == VCHIQ_SRVSTATE_FREE) ||
++ (service->srvstate == VCHIQ_SRVSTATE_OPEN))
++ break;
++
++ vchiq_log_warning(vchiq_core_log_level,
++ "%d: remove_service:%d - waiting in state %s",
++ service->state->id, service->localport,
++ srvstate_names[service->srvstate]);
++ }
++
++ if ((status == VCHIQ_SUCCESS) &&
++ (service->srvstate != VCHIQ_SRVSTATE_FREE))
++ status = VCHIQ_ERROR;
++
++ unlock_service(service);
++
++ return status;
++}
++
++
++/* This function may be called by kernel threads or user threads.
++ * User threads may receive VCHIQ_RETRY to indicate that a signal has been
++ * received and the call should be retried after being returned to user
++ * context.
++ * When called in blocking mode, the userdata field points to a bulk_waiter
++ * structure.
++ */
++VCHIQ_STATUS_T
++vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle,
++ VCHI_MEM_HANDLE_T memhandle, void *offset, int size, void *userdata,
++ VCHIQ_BULK_MODE_T mode, VCHIQ_BULK_DIR_T dir)
++{
++ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
++ VCHIQ_BULK_QUEUE_T *queue;
++ VCHIQ_BULK_T *bulk;
++ VCHIQ_STATE_T *state;
++ struct bulk_waiter *bulk_waiter = NULL;
++ const char dir_char = (dir == VCHIQ_BULK_TRANSMIT) ? 't' : 'r';
++ const int dir_msgtype = (dir == VCHIQ_BULK_TRANSMIT) ?
++ VCHIQ_MSG_BULK_TX : VCHIQ_MSG_BULK_RX;
++ VCHIQ_STATUS_T status = VCHIQ_ERROR;
++
++ if (!service ||
++ (service->srvstate != VCHIQ_SRVSTATE_OPEN) ||
++ ((memhandle == VCHI_MEM_HANDLE_INVALID) && (offset == NULL)) ||
++ (vchiq_check_service(service) != VCHIQ_SUCCESS))
++ goto error_exit;
++
++ switch (mode) {
++ case VCHIQ_BULK_MODE_NOCALLBACK:
++ case VCHIQ_BULK_MODE_CALLBACK:
++ break;
++ case VCHIQ_BULK_MODE_BLOCKING:
++ bulk_waiter = (struct bulk_waiter *)userdata;
++ sema_init(&bulk_waiter->event, 0);
++ bulk_waiter->actual = 0;
++ bulk_waiter->bulk = NULL;
++ break;
++ case VCHIQ_BULK_MODE_WAITING:
++ bulk_waiter = (struct bulk_waiter *)userdata;
++ bulk = bulk_waiter->bulk;
++ goto waiting;
++ default:
++ goto error_exit;
++ }
++
++ state = service->state;
++
++ queue = (dir == VCHIQ_BULK_TRANSMIT) ?
++ &service->bulk_tx : &service->bulk_rx;
++
++ if (mutex_lock_interruptible(&service->bulk_mutex) != 0) {
++ status = VCHIQ_RETRY;
++ goto error_exit;
++ }
++
++ if (queue->local_insert == queue->remove + VCHIQ_NUM_SERVICE_BULKS) {
++ VCHIQ_SERVICE_STATS_INC(service, bulk_stalls);
++ do {
++ mutex_unlock(&service->bulk_mutex);
++ if (down_interruptible(&service->bulk_remove_event)
++ != 0) {
++ status = VCHIQ_RETRY;
++ goto error_exit;
++ }
++ if (mutex_lock_interruptible(&service->bulk_mutex)
++ != 0) {
++ status = VCHIQ_RETRY;
++ goto error_exit;
++ }
++ } while (queue->local_insert == queue->remove +
++ VCHIQ_NUM_SERVICE_BULKS);
++ }
++
++ bulk = &queue->bulks[BULK_INDEX(queue->local_insert)];
++
++ bulk->mode = mode;
++ bulk->dir = dir;
++ bulk->userdata = userdata;
++ bulk->size = size;
++ bulk->actual = VCHIQ_BULK_ACTUAL_ABORTED;
++
++ if (vchiq_prepare_bulk_data(bulk, memhandle, offset, size, dir) !=
++ VCHIQ_SUCCESS)
++ goto unlock_error_exit;
++
++ wmb();
++
++ vchiq_log_info(vchiq_core_log_level,
++ "%d: bt (%d->%d) %cx %x@%x %x",
++ state->id,
++ service->localport, service->remoteport, dir_char,
++ size, (unsigned int)bulk->data, (unsigned int)userdata);
++
++ /* The slot mutex must be held when the service is being closed, so
++ claim it here to ensure that isn't happening */
++ if (mutex_lock_interruptible(&state->slot_mutex) != 0) {
++ status = VCHIQ_RETRY;
++ goto cancel_bulk_error_exit;
++ }
++
++ if (service->srvstate != VCHIQ_SRVSTATE_OPEN)
++ goto unlock_both_error_exit;
++
++ if (state->is_master) {
++ queue->local_insert++;
++ if (resolve_bulks(service, queue))
++ request_poll(state, service,
++ (dir == VCHIQ_BULK_TRANSMIT) ?
++ VCHIQ_POLL_TXNOTIFY : VCHIQ_POLL_RXNOTIFY);
++ } else {
++ int payload[2] = { (int)bulk->data, bulk->size };
++ VCHIQ_ELEMENT_T element = { payload, sizeof(payload) };
++
++ status = queue_message(state, NULL,
++ VCHIQ_MAKE_MSG(dir_msgtype,
++ service->localport, service->remoteport),
++ &element, 1, sizeof(payload),
++ QMFLAGS_IS_BLOCKING |
++ QMFLAGS_NO_MUTEX_LOCK |
++ QMFLAGS_NO_MUTEX_UNLOCK);
++ if (status != VCHIQ_SUCCESS) {
++ goto unlock_both_error_exit;
++ }
++ queue->local_insert++;
++ }
++
++ mutex_unlock(&state->slot_mutex);
++ mutex_unlock(&service->bulk_mutex);
++
++ vchiq_log_trace(vchiq_core_log_level,
++ "%d: bt:%d %cx li=%x ri=%x p=%x",
++ state->id,
++ service->localport, dir_char,
++ queue->local_insert, queue->remote_insert, queue->process);
++
++waiting:
++ unlock_service(service);
++
++ status = VCHIQ_SUCCESS;
++
++ if (bulk_waiter) {
++ bulk_waiter->bulk = bulk;
++ if (down_interruptible(&bulk_waiter->event) != 0)
++ status = VCHIQ_RETRY;
++ else if (bulk_waiter->actual == VCHIQ_BULK_ACTUAL_ABORTED)
++ status = VCHIQ_ERROR;
++ }
++
++ return status;
++
++unlock_both_error_exit:
++ mutex_unlock(&state->slot_mutex);
++cancel_bulk_error_exit:
++ vchiq_complete_bulk(bulk);
++unlock_error_exit:
++ mutex_unlock(&service->bulk_mutex);
++
++error_exit:
++ if (service)
++ unlock_service(service);
++ return status;
++}
++
++VCHIQ_STATUS_T
++vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T handle,
++ const VCHIQ_ELEMENT_T *elements, unsigned int count)
++{
++ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
++ VCHIQ_STATUS_T status = VCHIQ_ERROR;
++
++ unsigned int size = 0;
++ unsigned int i;
++
++ if (!service ||
++ (vchiq_check_service(service) != VCHIQ_SUCCESS))
++ goto error_exit;
++
++ for (i = 0; i < (unsigned int)count; i++) {
++ if (elements[i].size) {
++ if (elements[i].data == NULL) {
++ VCHIQ_SERVICE_STATS_INC(service, error_count);
++ goto error_exit;
++ }
++ size += elements[i].size;
++ }
++ }
++
++ if (size > VCHIQ_MAX_MSG_SIZE) {
++ VCHIQ_SERVICE_STATS_INC(service, error_count);
++ goto error_exit;
++ }
++
++ switch (service->srvstate) {
++ case VCHIQ_SRVSTATE_OPEN:
++ status = queue_message(service->state, service,
++ VCHIQ_MAKE_MSG(VCHIQ_MSG_DATA,
++ service->localport,
++ service->remoteport),
++ elements, count, size, 1);
++ break;
++ case VCHIQ_SRVSTATE_OPENSYNC:
++ status = queue_message_sync(service->state, service,
++ VCHIQ_MAKE_MSG(VCHIQ_MSG_DATA,
++ service->localport,
++ service->remoteport),
++ elements, count, size, 1);
++ break;
++ default:
++ status = VCHIQ_ERROR;
++ break;
++ }
++
++error_exit:
++ if (service)
++ unlock_service(service);
++
++ return status;
++}
++
++void
++vchiq_release_message(VCHIQ_SERVICE_HANDLE_T handle, VCHIQ_HEADER_T *header)
++{
++ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
++ VCHIQ_SHARED_STATE_T *remote;
++ VCHIQ_STATE_T *state;
++ int slot_index;
++
++ if (!service)
++ return;
++
++ state = service->state;
++ remote = state->remote;
++
++ slot_index = SLOT_INDEX_FROM_DATA(state, (void *)header);
++
++ if ((slot_index >= remote->slot_first) &&
++ (slot_index <= remote->slot_last)) {
++ int msgid = header->msgid;
++ if (msgid & VCHIQ_MSGID_CLAIMED) {
++ VCHIQ_SLOT_INFO_T *slot_info =
++ SLOT_INFO_FROM_INDEX(state, slot_index);
++
++ release_slot(state, slot_info, header, service);
++ }
++ } else if (slot_index == remote->slot_sync)
++ release_message_sync(state, header);
++
++ unlock_service(service);
++}
++
++static void
++release_message_sync(VCHIQ_STATE_T *state, VCHIQ_HEADER_T *header)
++{
++ header->msgid = VCHIQ_MSGID_PADDING;
++ wmb();
++ remote_event_signal(&state->remote->sync_release);
++}
++
++VCHIQ_STATUS_T
++vchiq_get_peer_version(VCHIQ_SERVICE_HANDLE_T handle, short *peer_version)
++{
++ VCHIQ_STATUS_T status = VCHIQ_ERROR;
++ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
++
++ if (!service ||
++ (vchiq_check_service(service) != VCHIQ_SUCCESS) ||
++ !peer_version)
++ goto exit;
++ *peer_version = service->peer_version;
++ status = VCHIQ_SUCCESS;
++
++exit:
++ if (service)
++ unlock_service(service);
++ return status;
++}
++
++VCHIQ_STATUS_T
++vchiq_get_config(VCHIQ_INSTANCE_T instance,
++ int config_size, VCHIQ_CONFIG_T *pconfig)
++{
++ VCHIQ_CONFIG_T config;
++
++ (void)instance;
++
++ config.max_msg_size = VCHIQ_MAX_MSG_SIZE;
++ config.bulk_threshold = VCHIQ_MAX_MSG_SIZE;
++ config.max_outstanding_bulks = VCHIQ_NUM_SERVICE_BULKS;
++ config.max_services = VCHIQ_MAX_SERVICES;
++ config.version = VCHIQ_VERSION;
++ config.version_min = VCHIQ_VERSION_MIN;
++
++ if (config_size > sizeof(VCHIQ_CONFIG_T))
++ return VCHIQ_ERROR;
++
++ memcpy(pconfig, &config,
++ min(config_size, (int)(sizeof(VCHIQ_CONFIG_T))));
++
++ return VCHIQ_SUCCESS;
++}
++
++VCHIQ_STATUS_T
++vchiq_set_service_option(VCHIQ_SERVICE_HANDLE_T handle,
++ VCHIQ_SERVICE_OPTION_T option, int value)
++{
++ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
++ VCHIQ_STATUS_T status = VCHIQ_ERROR;
++
++ if (service) {
++ switch (option) {
++ case VCHIQ_SERVICE_OPTION_AUTOCLOSE:
++ service->auto_close = value;
++ status = VCHIQ_SUCCESS;
++ break;
++
++ case VCHIQ_SERVICE_OPTION_SLOT_QUOTA: {
++ VCHIQ_SERVICE_QUOTA_T *service_quota =
++ &service->state->service_quotas[
++ service->localport];
++ if (value == 0)
++ value = service->state->default_slot_quota;
++ if ((value >= service_quota->slot_use_count) &&
++ (value < (unsigned short)~0)) {
++ service_quota->slot_quota = value;
++ if ((value >= service_quota->slot_use_count) &&
++ (service_quota->message_quota >=
++ service_quota->message_use_count)) {
++ /* Signal the service that it may have
++ ** dropped below its quota */
++ up(&service_quota->quota_event);
++ }
++ status = VCHIQ_SUCCESS;
++ }
++ } break;
++
++ case VCHIQ_SERVICE_OPTION_MESSAGE_QUOTA: {
++ VCHIQ_SERVICE_QUOTA_T *service_quota =
++ &service->state->service_quotas[
++ service->localport];
++ if (value == 0)
++ value = service->state->default_message_quota;
++ if ((value >= service_quota->message_use_count) &&
++ (value < (unsigned short)~0)) {
++ service_quota->message_quota = value;
++ if ((value >=
++ service_quota->message_use_count) &&
++ (service_quota->slot_quota >=
++ service_quota->slot_use_count))
++ /* Signal the service that it may have
++ ** dropped below its quota */
++ up(&service_quota->quota_event);
++ status = VCHIQ_SUCCESS;
++ }
++ } break;
++
++ case VCHIQ_SERVICE_OPTION_SYNCHRONOUS:
++ if ((service->srvstate == VCHIQ_SRVSTATE_HIDDEN) ||
++ (service->srvstate ==
++ VCHIQ_SRVSTATE_LISTENING)) {
++ service->sync = value;
++ status = VCHIQ_SUCCESS;
++ }
++ break;
++
++ case VCHIQ_SERVICE_OPTION_TRACE:
++ service->trace = value;
++ status = VCHIQ_SUCCESS;
++ break;
++
++ default:
++ break;
++ }
++ unlock_service(service);
++ }
++
++ return status;
++}
++
++void
++vchiq_dump_shared_state(void *dump_context, VCHIQ_STATE_T *state,
++ VCHIQ_SHARED_STATE_T *shared, const char *label)
++{
++ static const char *const debug_names[] = {
++ "<entries>",
++ "SLOT_HANDLER_COUNT",
++ "SLOT_HANDLER_LINE",
++ "PARSE_LINE",
++ "PARSE_HEADER",
++ "PARSE_MSGID",
++ "AWAIT_COMPLETION_LINE",
++ "DEQUEUE_MESSAGE_LINE",
++ "SERVICE_CALLBACK_LINE",
++ "MSG_QUEUE_FULL_COUNT",
++ "COMPLETION_QUEUE_FULL_COUNT"
++ };
++ int i;
++
++ char buf[80];
++ int len;
++ len = snprintf(buf, sizeof(buf),
++ " %s: slots %d-%d tx_pos=%x recycle=%x",
++ label, shared->slot_first, shared->slot_last,
++ shared->tx_pos, shared->slot_queue_recycle);
++ vchiq_dump(dump_context, buf, len + 1);
++
++ len = snprintf(buf, sizeof(buf),
++ " Slots claimed:");
++ vchiq_dump(dump_context, buf, len + 1);
++
++ for (i = shared->slot_first; i <= shared->slot_last; i++) {
++ VCHIQ_SLOT_INFO_T slot_info = *SLOT_INFO_FROM_INDEX(state, i);
++ if (slot_info.use_count != slot_info.release_count) {
++ len = snprintf(buf, sizeof(buf),
++ " %d: %d/%d", i, slot_info.use_count,
++ slot_info.release_count);
++ vchiq_dump(dump_context, buf, len + 1);
++ }
++ }
++
++ for (i = 1; i < shared->debug[DEBUG_ENTRIES]; i++) {
++ len = snprintf(buf, sizeof(buf), " DEBUG: %s = %d(%x)",
++ debug_names[i], shared->debug[i], shared->debug[i]);
++ vchiq_dump(dump_context, buf, len + 1);
++ }
++}
++
++void
++vchiq_dump_state(void *dump_context, VCHIQ_STATE_T *state)
++{
++ char buf[80];
++ int len;
++ int i;
++
++ len = snprintf(buf, sizeof(buf), "State %d: %s", state->id,
++ conn_state_names[state->conn_state]);
++ vchiq_dump(dump_context, buf, len + 1);
++
++ len = snprintf(buf, sizeof(buf),
++ " tx_pos=%x(@%x), rx_pos=%x(@%x)",
++ state->local->tx_pos,
++ (uint32_t)state->tx_data +
++ (state->local_tx_pos & VCHIQ_SLOT_MASK),
++ state->rx_pos,
++ (uint32_t)state->rx_data +
++ (state->rx_pos & VCHIQ_SLOT_MASK));
++ vchiq_dump(dump_context, buf, len + 1);
++
++ len = snprintf(buf, sizeof(buf),
++ " Version: %d (min %d)",
++ VCHIQ_VERSION, VCHIQ_VERSION_MIN);
++ vchiq_dump(dump_context, buf, len + 1);
++
++ if (VCHIQ_ENABLE_STATS) {
++ len = snprintf(buf, sizeof(buf),
++ " Stats: ctrl_tx_count=%d, ctrl_rx_count=%d, "
++ "error_count=%d",
++ state->stats.ctrl_tx_count, state->stats.ctrl_rx_count,
++ state->stats.error_count);
++ vchiq_dump(dump_context, buf, len + 1);
++ }
++
++ len = snprintf(buf, sizeof(buf),
++ " Slots: %d available (%d data), %d recyclable, %d stalls "
++ "(%d data)",
++ ((state->slot_queue_available * VCHIQ_SLOT_SIZE) -
++ state->local_tx_pos) / VCHIQ_SLOT_SIZE,
++ state->data_quota - state->data_use_count,
++ state->local->slot_queue_recycle - state->slot_queue_available,
++ state->stats.slot_stalls, state->stats.data_stalls);
++ vchiq_dump(dump_context, buf, len + 1);
++
++ vchiq_dump_platform_state(dump_context);
++
++ vchiq_dump_shared_state(dump_context, state, state->local, "Local");
++ vchiq_dump_shared_state(dump_context, state, state->remote, "Remote");
++
++ vchiq_dump_platform_instances(dump_context);
++
++ for (i = 0; i < state->unused_service; i++) {
++ VCHIQ_SERVICE_T *service = find_service_by_port(state, i);
++
++ if (service) {
++ vchiq_dump_service_state(dump_context, service);
++ unlock_service(service);
++ }
++ }
++}
++
++void
++vchiq_dump_service_state(void *dump_context, VCHIQ_SERVICE_T *service)
++{
++ char buf[80];
++ int len;
++
++ len = snprintf(buf, sizeof(buf), "Service %d: %s (ref %u)",
++ service->localport, srvstate_names[service->srvstate],
++ service->ref_count - 1); /*Don't include the lock just taken*/
++
++ if (service->srvstate != VCHIQ_SRVSTATE_FREE) {
++ char remoteport[30];
++ VCHIQ_SERVICE_QUOTA_T *service_quota =
++ &service->state->service_quotas[service->localport];
++ int fourcc = service->base.fourcc;
++ int tx_pending, rx_pending;
++ if (service->remoteport != VCHIQ_PORT_FREE) {
++ int len2 = snprintf(remoteport, sizeof(remoteport),
++ "%d", service->remoteport);
++ if (service->public_fourcc != VCHIQ_FOURCC_INVALID)
++ snprintf(remoteport + len2,
++ sizeof(remoteport) - len2,
++ " (client %x)", service->client_id);
++ } else
++ strcpy(remoteport, "n/a");
++
++ len += snprintf(buf + len, sizeof(buf) - len,
++ " '%c%c%c%c' remote %s (msg use %d/%d, slot use %d/%d)",
++ VCHIQ_FOURCC_AS_4CHARS(fourcc),
++ remoteport,
++ service_quota->message_use_count,
++ service_quota->message_quota,
++ service_quota->slot_use_count,
++ service_quota->slot_quota);
++
++ vchiq_dump(dump_context, buf, len + 1);
++
++ tx_pending = service->bulk_tx.local_insert -
++ service->bulk_tx.remote_insert;
++
++ rx_pending = service->bulk_rx.local_insert -
++ service->bulk_rx.remote_insert;
++
++ len = snprintf(buf, sizeof(buf),
++ " Bulk: tx_pending=%d (size %d),"
++ " rx_pending=%d (size %d)",
++ tx_pending,
++ tx_pending ? service->bulk_tx.bulks[
++ BULK_INDEX(service->bulk_tx.remove)].size : 0,
++ rx_pending,
++ rx_pending ? service->bulk_rx.bulks[
++ BULK_INDEX(service->bulk_rx.remove)].size : 0);
++
++ if (VCHIQ_ENABLE_STATS) {
++ vchiq_dump(dump_context, buf, len + 1);
++
++ len = snprintf(buf, sizeof(buf),
++ " Ctrl: tx_count=%d, tx_bytes=%llu, "
++ "rx_count=%d, rx_bytes=%llu",
++ service->stats.ctrl_tx_count,
++ service->stats.ctrl_tx_bytes,
++ service->stats.ctrl_rx_count,
++ service->stats.ctrl_rx_bytes);
++ vchiq_dump(dump_context, buf, len + 1);
++
++ len = snprintf(buf, sizeof(buf),
++ " Bulk: tx_count=%d, tx_bytes=%llu, "
++ "rx_count=%d, rx_bytes=%llu",
++ service->stats.bulk_tx_count,
++ service->stats.bulk_tx_bytes,
++ service->stats.bulk_rx_count,
++ service->stats.bulk_rx_bytes);
++ vchiq_dump(dump_context, buf, len + 1);
++
++ len = snprintf(buf, sizeof(buf),
++ " %d quota stalls, %d slot stalls, "
++ "%d bulk stalls, %d aborted, %d errors",
++ service->stats.quota_stalls,
++ service->stats.slot_stalls,
++ service->stats.bulk_stalls,
++ service->stats.bulk_aborted_count,
++ service->stats.error_count);
++ }
++ }
++
++ vchiq_dump(dump_context, buf, len + 1);
++
++ if (service->srvstate != VCHIQ_SRVSTATE_FREE)
++ vchiq_dump_platform_service_state(dump_context, service);
++}
++
++
++void
++vchiq_loud_error_header(void)
++{
++ vchiq_log_error(vchiq_core_log_level,
++ "============================================================"
++ "================");
++ vchiq_log_error(vchiq_core_log_level,
++ "============================================================"
++ "================");
++ vchiq_log_error(vchiq_core_log_level, "=====");
++}
++
++void
++vchiq_loud_error_footer(void)
++{
++ vchiq_log_error(vchiq_core_log_level, "=====");
++ vchiq_log_error(vchiq_core_log_level,
++ "============================================================"
++ "================");
++ vchiq_log_error(vchiq_core_log_level,
++ "============================================================"
++ "================");
++}
++
++
++VCHIQ_STATUS_T vchiq_send_remote_use(VCHIQ_STATE_T *state)
++{
++ VCHIQ_STATUS_T status = VCHIQ_RETRY;
++ if (state->conn_state != VCHIQ_CONNSTATE_DISCONNECTED)
++ status = queue_message(state, NULL,
++ VCHIQ_MAKE_MSG(VCHIQ_MSG_REMOTE_USE, 0, 0),
++ NULL, 0, 0, 0);
++ return status;
++}
++
++VCHIQ_STATUS_T vchiq_send_remote_release(VCHIQ_STATE_T *state)
++{
++ VCHIQ_STATUS_T status = VCHIQ_RETRY;
++ if (state->conn_state != VCHIQ_CONNSTATE_DISCONNECTED)
++ status = queue_message(state, NULL,
++ VCHIQ_MAKE_MSG(VCHIQ_MSG_REMOTE_RELEASE, 0, 0),
++ NULL, 0, 0, 0);
++ return status;
++}
++
++VCHIQ_STATUS_T vchiq_send_remote_use_active(VCHIQ_STATE_T *state)
++{
++ VCHIQ_STATUS_T status = VCHIQ_RETRY;
++ if (state->conn_state != VCHIQ_CONNSTATE_DISCONNECTED)
++ status = queue_message(state, NULL,
++ VCHIQ_MAKE_MSG(VCHIQ_MSG_REMOTE_USE_ACTIVE, 0, 0),
++ NULL, 0, 0, 0);
++ return status;
++}
++
++void vchiq_log_dump_mem(const char *label, uint32_t addr, const void *voidMem,
++ size_t numBytes)
++{
++ const uint8_t *mem = (const uint8_t *)voidMem;
++ size_t offset;
++ char lineBuf[100];
++ char *s;
++
++ while (numBytes > 0) {
++ s = lineBuf;
++
++ for (offset = 0; offset < 16; offset++) {
++ if (offset < numBytes)
++ s += snprintf(s, 4, "%02x ", mem[offset]);
++ else
++ s += snprintf(s, 4, " ");
++ }
++
++ for (offset = 0; offset < 16; offset++) {
++ if (offset < numBytes) {
++ uint8_t ch = mem[offset];
++
++ if ((ch < ' ') || (ch > '~'))
++ ch = '.';
++ *s++ = (char)ch;
++ }
++ }
++ *s++ = '\0';
++
++ if ((label != NULL) && (*label != '\0'))
++ vchiq_log_trace(VCHIQ_LOG_TRACE,
++ "%s: %08x: %s", label, addr, lineBuf);
++ else
++ vchiq_log_trace(VCHIQ_LOG_TRACE,
++ "%08x: %s", addr, lineBuf);
++
++ addr += 16;
++ mem += 16;
++ if (numBytes > 16)
++ numBytes -= 16;
++ else
++ numBytes = 0;
++ }
++}
+--- /dev/null
++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.h
+@@ -0,0 +1,712 @@
++/**
++ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef VCHIQ_CORE_H
++#define VCHIQ_CORE_H
++
++#include <linux/mutex.h>
++#include <linux/semaphore.h>
++#include <linux/kthread.h>
++
++#include "vchiq_cfg.h"
++
++#include "vchiq.h"
++
++/* Run time control of log level, based on KERN_XXX level. */
++#define VCHIQ_LOG_DEFAULT 4
++#define VCHIQ_LOG_ERROR 3
++#define VCHIQ_LOG_WARNING 4
++#define VCHIQ_LOG_INFO 6
++#define VCHIQ_LOG_TRACE 7
++
++#define VCHIQ_LOG_PREFIX KERN_INFO "vchiq: "
++
++#ifndef vchiq_log_error
++#define vchiq_log_error(cat, fmt, ...) \
++ do { if (cat >= VCHIQ_LOG_ERROR) \
++ printk(VCHIQ_LOG_PREFIX fmt "\n", ##__VA_ARGS__); } while (0)
++#endif
++#ifndef vchiq_log_warning
++#define vchiq_log_warning(cat, fmt, ...) \
++ do { if (cat >= VCHIQ_LOG_WARNING) \
++ printk(VCHIQ_LOG_PREFIX fmt "\n", ##__VA_ARGS__); } while (0)
++#endif
++#ifndef vchiq_log_info
++#define vchiq_log_info(cat, fmt, ...) \
++ do { if (cat >= VCHIQ_LOG_INFO) \
++ printk(VCHIQ_LOG_PREFIX fmt "\n", ##__VA_ARGS__); } while (0)
++#endif
++#ifndef vchiq_log_trace
++#define vchiq_log_trace(cat, fmt, ...) \
++ do { if (cat >= VCHIQ_LOG_TRACE) \
++ printk(VCHIQ_LOG_PREFIX fmt "\n", ##__VA_ARGS__); } while (0)
++#endif
++
++#define vchiq_loud_error(...) \
++ vchiq_log_error(vchiq_core_log_level, "===== " __VA_ARGS__)
++
++#ifndef vchiq_static_assert
++#define vchiq_static_assert(cond) __attribute__((unused)) \
++ extern int vchiq_static_assert[(cond) ? 1 : -1]
++#endif
++
++#define IS_POW2(x) (x && ((x & (x - 1)) == 0))
++
++/* Ensure that the slot size and maximum number of slots are powers of 2 */
++vchiq_static_assert(IS_POW2(VCHIQ_SLOT_SIZE));
++vchiq_static_assert(IS_POW2(VCHIQ_MAX_SLOTS));
++vchiq_static_assert(IS_POW2(VCHIQ_MAX_SLOTS_PER_SIDE));
++
++#define VCHIQ_SLOT_MASK (VCHIQ_SLOT_SIZE - 1)
++#define VCHIQ_SLOT_QUEUE_MASK (VCHIQ_MAX_SLOTS_PER_SIDE - 1)
++#define VCHIQ_SLOT_ZERO_SLOTS ((sizeof(VCHIQ_SLOT_ZERO_T) + \
++ VCHIQ_SLOT_SIZE - 1) / VCHIQ_SLOT_SIZE)
++
++#define VCHIQ_MSG_PADDING 0 /* - */
++#define VCHIQ_MSG_CONNECT 1 /* - */
++#define VCHIQ_MSG_OPEN 2 /* + (srcport, -), fourcc, client_id */
++#define VCHIQ_MSG_OPENACK 3 /* + (srcport, dstport) */
++#define VCHIQ_MSG_CLOSE 4 /* + (srcport, dstport) */
++#define VCHIQ_MSG_DATA 5 /* + (srcport, dstport) */
++#define VCHIQ_MSG_BULK_RX 6 /* + (srcport, dstport), data, size */
++#define VCHIQ_MSG_BULK_TX 7 /* + (srcport, dstport), data, size */
++#define VCHIQ_MSG_BULK_RX_DONE 8 /* + (srcport, dstport), actual */
++#define VCHIQ_MSG_BULK_TX_DONE 9 /* + (srcport, dstport), actual */
++#define VCHIQ_MSG_PAUSE 10 /* - */
++#define VCHIQ_MSG_RESUME 11 /* - */
++#define VCHIQ_MSG_REMOTE_USE 12 /* - */
++#define VCHIQ_MSG_REMOTE_RELEASE 13 /* - */
++#define VCHIQ_MSG_REMOTE_USE_ACTIVE 14 /* - */
++
++#define VCHIQ_PORT_MAX (VCHIQ_MAX_SERVICES - 1)
++#define VCHIQ_PORT_FREE 0x1000
++#define VCHIQ_PORT_IS_VALID(port) (port < VCHIQ_PORT_FREE)
++#define VCHIQ_MAKE_MSG(type, srcport, dstport) \
++ ((type<<24) | (srcport<<12) | (dstport<<0))
++#define VCHIQ_MSG_TYPE(msgid) ((unsigned int)msgid >> 24)
++#define VCHIQ_MSG_SRCPORT(msgid) \
++ (unsigned short)(((unsigned int)msgid >> 12) & 0xfff)
++#define VCHIQ_MSG_DSTPORT(msgid) \
++ ((unsigned short)msgid & 0xfff)
++
++#define VCHIQ_FOURCC_AS_4CHARS(fourcc) \
++ ((fourcc) >> 24) & 0xff, \
++ ((fourcc) >> 16) & 0xff, \
++ ((fourcc) >> 8) & 0xff, \
++ (fourcc) & 0xff
++
++/* Ensure the fields are wide enough */
++vchiq_static_assert(VCHIQ_MSG_SRCPORT(VCHIQ_MAKE_MSG(0, 0, VCHIQ_PORT_MAX))
++ == 0);
++vchiq_static_assert(VCHIQ_MSG_TYPE(VCHIQ_MAKE_MSG(0, VCHIQ_PORT_MAX, 0)) == 0);
++vchiq_static_assert((unsigned int)VCHIQ_PORT_MAX <
++ (unsigned int)VCHIQ_PORT_FREE);
++
++#define VCHIQ_MSGID_PADDING VCHIQ_MAKE_MSG(VCHIQ_MSG_PADDING, 0, 0)
++#define VCHIQ_MSGID_CLAIMED 0x40000000
++
++#define VCHIQ_FOURCC_INVALID 0x00000000
++#define VCHIQ_FOURCC_IS_LEGAL(fourcc) (fourcc != VCHIQ_FOURCC_INVALID)
++
++#define VCHIQ_BULK_ACTUAL_ABORTED -1
++
++typedef uint32_t BITSET_T;
++
++vchiq_static_assert((sizeof(BITSET_T) * 8) == 32);
++
++#define BITSET_SIZE(b) ((b + 31) >> 5)
++#define BITSET_WORD(b) (b >> 5)
++#define BITSET_BIT(b) (1 << (b & 31))
++#define BITSET_ZERO(bs) memset(bs, 0, sizeof(bs))
++#define BITSET_IS_SET(bs, b) (bs[BITSET_WORD(b)] & BITSET_BIT(b))
++#define BITSET_SET(bs, b) (bs[BITSET_WORD(b)] |= BITSET_BIT(b))
++#define BITSET_CLR(bs, b) (bs[BITSET_WORD(b)] &= ~BITSET_BIT(b))
++
++#if VCHIQ_ENABLE_STATS
++#define VCHIQ_STATS_INC(state, stat) (state->stats. stat++)
++#define VCHIQ_SERVICE_STATS_INC(service, stat) (service->stats. stat++)
++#define VCHIQ_SERVICE_STATS_ADD(service, stat, addend) \
++ (service->stats. stat += addend)
++#else
++#define VCHIQ_STATS_INC(state, stat) ((void)0)
++#define VCHIQ_SERVICE_STATS_INC(service, stat) ((void)0)
++#define VCHIQ_SERVICE_STATS_ADD(service, stat, addend) ((void)0)
++#endif
++
++enum {
++ DEBUG_ENTRIES,
++#if VCHIQ_ENABLE_DEBUG
++ DEBUG_SLOT_HANDLER_COUNT,
++ DEBUG_SLOT_HANDLER_LINE,
++ DEBUG_PARSE_LINE,
++ DEBUG_PARSE_HEADER,
++ DEBUG_PARSE_MSGID,
++ DEBUG_AWAIT_COMPLETION_LINE,
++ DEBUG_DEQUEUE_MESSAGE_LINE,
++ DEBUG_SERVICE_CALLBACK_LINE,
++ DEBUG_MSG_QUEUE_FULL_COUNT,
++ DEBUG_COMPLETION_QUEUE_FULL_COUNT,
++#endif
++ DEBUG_MAX
++};
++
++#if VCHIQ_ENABLE_DEBUG
++
++#define DEBUG_INITIALISE(local) int *debug_ptr = (local)->debug;
++#define DEBUG_TRACE(d) \
++ do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(); } while (0)
++#define DEBUG_VALUE(d, v) \
++ do { debug_ptr[DEBUG_ ## d] = (v); dsb(); } while (0)
++#define DEBUG_COUNT(d) \
++ do { debug_ptr[DEBUG_ ## d]++; dsb(); } while (0)
++
++#else /* VCHIQ_ENABLE_DEBUG */
++
++#define DEBUG_INITIALISE(local)
++#define DEBUG_TRACE(d)
++#define DEBUG_VALUE(d, v)
++#define DEBUG_COUNT(d)
++
++#endif /* VCHIQ_ENABLE_DEBUG */
++
++typedef enum {
++ VCHIQ_CONNSTATE_DISCONNECTED,
++ VCHIQ_CONNSTATE_CONNECTING,
++ VCHIQ_CONNSTATE_CONNECTED,
++ VCHIQ_CONNSTATE_PAUSING,
++ VCHIQ_CONNSTATE_PAUSE_SENT,
++ VCHIQ_CONNSTATE_PAUSED,
++ VCHIQ_CONNSTATE_RESUMING,
++ VCHIQ_CONNSTATE_PAUSE_TIMEOUT,
++ VCHIQ_CONNSTATE_RESUME_TIMEOUT
++} VCHIQ_CONNSTATE_T;
++
++enum {
++ VCHIQ_SRVSTATE_FREE,
++ VCHIQ_SRVSTATE_HIDDEN,
++ VCHIQ_SRVSTATE_LISTENING,
++ VCHIQ_SRVSTATE_OPENING,
++ VCHIQ_SRVSTATE_OPEN,
++ VCHIQ_SRVSTATE_OPENSYNC,
++ VCHIQ_SRVSTATE_CLOSESENT,
++ VCHIQ_SRVSTATE_CLOSERECVD,
++ VCHIQ_SRVSTATE_CLOSEWAIT,
++ VCHIQ_SRVSTATE_CLOSED
++};
++
++enum {
++ VCHIQ_POLL_TERMINATE,
++ VCHIQ_POLL_REMOVE,
++ VCHIQ_POLL_TXNOTIFY,
++ VCHIQ_POLL_RXNOTIFY,
++ VCHIQ_POLL_COUNT
++};
++
++typedef enum {
++ VCHIQ_BULK_TRANSMIT,
++ VCHIQ_BULK_RECEIVE
++} VCHIQ_BULK_DIR_T;
++
++typedef void (*VCHIQ_USERDATA_TERM_T)(void *userdata);
++
++typedef struct vchiq_bulk_struct {
++ short mode;
++ short dir;
++ void *userdata;
++ VCHI_MEM_HANDLE_T handle;
++ void *data;
++ int size;
++ void *remote_data;
++ int remote_size;
++ int actual;
++} VCHIQ_BULK_T;
++
++typedef struct vchiq_bulk_queue_struct {
++ int local_insert; /* Where to insert the next local bulk */
++ int remote_insert; /* Where to insert the next remote bulk (master) */
++ int process; /* Bulk to transfer next */
++ int remote_notify; /* Bulk to notify the remote client of next (mstr) */
++ int remove; /* Bulk to notify the local client of, and remove,
++ ** next */
++ VCHIQ_BULK_T bulks[VCHIQ_NUM_SERVICE_BULKS];
++} VCHIQ_BULK_QUEUE_T;
++
++typedef struct remote_event_struct {
++ int armed;
++ int fired;
++ struct semaphore *event;
++} REMOTE_EVENT_T;
++
++typedef struct opaque_platform_state_t *VCHIQ_PLATFORM_STATE_T;
++
++typedef struct vchiq_state_struct VCHIQ_STATE_T;
++
++typedef struct vchiq_slot_struct {
++ char data[VCHIQ_SLOT_SIZE];
++} VCHIQ_SLOT_T;
++
++typedef struct vchiq_slot_info_struct {
++ /* Use two counters rather than one to avoid the need for a mutex. */
++ short use_count;
++ short release_count;
++} VCHIQ_SLOT_INFO_T;
++
++typedef struct vchiq_service_struct {
++ VCHIQ_SERVICE_BASE_T base;
++ VCHIQ_SERVICE_HANDLE_T handle;
++ unsigned int ref_count;
++ int srvstate;
++ VCHIQ_USERDATA_TERM_T userdata_term;
++ unsigned int localport;
++ unsigned int remoteport;
++ int public_fourcc;
++ int client_id;
++ char auto_close;
++ char sync;
++ char closing;
++ char trace;
++ atomic_t poll_flags;
++ short version;
++ short version_min;
++ short peer_version;
++
++ VCHIQ_STATE_T *state;
++ VCHIQ_INSTANCE_T instance;
++
++ int service_use_count;
++
++ VCHIQ_BULK_QUEUE_T bulk_tx;
++ VCHIQ_BULK_QUEUE_T bulk_rx;
++
++ struct semaphore remove_event;
++ struct semaphore bulk_remove_event;
++ struct mutex bulk_mutex;
++
++ struct service_stats_struct {
++ int quota_stalls;
++ int slot_stalls;
++ int bulk_stalls;
++ int error_count;
++ int ctrl_tx_count;
++ int ctrl_rx_count;
++ int bulk_tx_count;
++ int bulk_rx_count;
++ int bulk_aborted_count;
++ uint64_t ctrl_tx_bytes;
++ uint64_t ctrl_rx_bytes;
++ uint64_t bulk_tx_bytes;
++ uint64_t bulk_rx_bytes;
++ } stats;
++} VCHIQ_SERVICE_T;
++
++/* The quota information is outside VCHIQ_SERVICE_T so that it can be
++ statically allocated, since for accounting reasons a service's slot
++ usage is carried over between users of the same port number.
++ */
++typedef struct vchiq_service_quota_struct {
++ unsigned short slot_quota;
++ unsigned short slot_use_count;
++ unsigned short message_quota;
++ unsigned short message_use_count;
++ struct semaphore quota_event;
++ int previous_tx_index;
++} VCHIQ_SERVICE_QUOTA_T;
++
++typedef struct vchiq_shared_state_struct {
++
++ /* A non-zero value here indicates that the content is valid. */
++ int initialised;
++
++ /* The first and last (inclusive) slots allocated to the owner. */
++ int slot_first;
++ int slot_last;
++
++ /* The slot allocated to synchronous messages from the owner. */
++ int slot_sync;
++
++ /* Signalling this event indicates that owner's slot handler thread
++ ** should run. */
++ REMOTE_EVENT_T trigger;
++
++ /* Indicates the byte position within the stream where the next message
++ ** will be written. The least significant bits are an index into the
++ ** slot. The next bits are the index of the slot in slot_queue. */
++ int tx_pos;
++
++ /* This event should be signalled when a slot is recycled. */
++ REMOTE_EVENT_T recycle;
++
++ /* The slot_queue index where the next recycled slot will be written. */
++ int slot_queue_recycle;
++
++ /* This event should be signalled when a synchronous message is sent. */
++ REMOTE_EVENT_T sync_trigger;
++
++ /* This event should be signalled when a synchronous message has been
++ ** released. */
++ REMOTE_EVENT_T sync_release;
++
++ /* A circular buffer of slot indexes. */
++ int slot_queue[VCHIQ_MAX_SLOTS_PER_SIDE];
++
++ /* Debugging state */
++ int debug[DEBUG_MAX];
++} VCHIQ_SHARED_STATE_T;
++
++typedef struct vchiq_slot_zero_struct {
++ int magic;
++ short version;
++ short version_min;
++ int slot_zero_size;
++ int slot_size;
++ int max_slots;
++ int max_slots_per_side;
++ int platform_data[2];
++ VCHIQ_SHARED_STATE_T master;
++ VCHIQ_SHARED_STATE_T slave;
++ VCHIQ_SLOT_INFO_T slots[VCHIQ_MAX_SLOTS];
++} VCHIQ_SLOT_ZERO_T;
++
++struct vchiq_state_struct {
++ int id;
++ int initialised;
++ VCHIQ_CONNSTATE_T conn_state;
++ int is_master;
++ short version_common;
++
++ VCHIQ_SHARED_STATE_T *local;
++ VCHIQ_SHARED_STATE_T *remote;
++ VCHIQ_SLOT_T *slot_data;
++
++ unsigned short default_slot_quota;
++ unsigned short default_message_quota;
++
++ /* Event indicating connect message received */
++ struct semaphore connect;
++
++ /* Mutex protecting services */
++ struct mutex mutex;
++ VCHIQ_INSTANCE_T *instance;
++
++ /* Processes incoming messages */
++ struct task_struct *slot_handler_thread;
++
++ /* Processes recycled slots */
++ struct task_struct *recycle_thread;
++
++ /* Processes synchronous messages */
++ struct task_struct *sync_thread;
++
++ /* Local implementation of the trigger remote event */
++ struct semaphore trigger_event;
++
++ /* Local implementation of the recycle remote event */
++ struct semaphore recycle_event;
++
++ /* Local implementation of the sync trigger remote event */
++ struct semaphore sync_trigger_event;
++
++ /* Local implementation of the sync release remote event */
++ struct semaphore sync_release_event;
++
++ char *tx_data;
++ char *rx_data;
++ VCHIQ_SLOT_INFO_T *rx_info;
++
++ struct mutex slot_mutex;
++
++ struct mutex recycle_mutex;
++
++ struct mutex sync_mutex;
++
++ struct mutex bulk_transfer_mutex;
++
++ /* Indicates the byte position within the stream from where the next
++ ** message will be read. The least significant bits are an index into
++ ** the slot.The next bits are the index of the slot in
++ ** remote->slot_queue. */
++ int rx_pos;
++
++ /* A cached copy of local->tx_pos. Only write to local->tx_pos, and read
++ from remote->tx_pos. */
++ int local_tx_pos;
++
++ /* The slot_queue index of the slot to become available next. */
++ int slot_queue_available;
++
++ /* A flag to indicate if any poll has been requested */
++ int poll_needed;
++
++ /* Ths index of the previous slot used for data messages. */
++ int previous_data_index;
++
++ /* The number of slots occupied by data messages. */
++ unsigned short data_use_count;
++
++ /* The maximum number of slots to be occupied by data messages. */
++ unsigned short data_quota;
++
++ /* An array of bit sets indicating which services must be polled. */
++ atomic_t poll_services[BITSET_SIZE(VCHIQ_MAX_SERVICES)];
++
++ /* The number of the first unused service */
++ int unused_service;
++
++ /* Signalled when a free slot becomes available. */
++ struct semaphore slot_available_event;
++
++ struct semaphore slot_remove_event;
++
++ /* Signalled when a free data slot becomes available. */
++ struct semaphore data_quota_event;
++
++ /* Incremented when there are bulk transfers which cannot be processed
++ * whilst paused and must be processed on resume */
++ int deferred_bulks;
++
++ struct state_stats_struct {
++ int slot_stalls;
++ int data_stalls;
++ int ctrl_tx_count;
++ int ctrl_rx_count;
++ int error_count;
++ } stats;
++
++ VCHIQ_SERVICE_T * services[VCHIQ_MAX_SERVICES];
++ VCHIQ_SERVICE_QUOTA_T service_quotas[VCHIQ_MAX_SERVICES];
++ VCHIQ_SLOT_INFO_T slot_info[VCHIQ_MAX_SLOTS];
++
++ VCHIQ_PLATFORM_STATE_T platform_state;
++};
++
++struct bulk_waiter {
++ VCHIQ_BULK_T *bulk;
++ struct semaphore event;
++ int actual;
++};
++
++extern spinlock_t bulk_waiter_spinlock;
++
++extern int vchiq_core_log_level;
++extern int vchiq_core_msg_log_level;
++extern int vchiq_sync_log_level;
++
++extern VCHIQ_STATE_T *vchiq_states[VCHIQ_MAX_STATES];
++
++extern const char *
++get_conn_state_name(VCHIQ_CONNSTATE_T conn_state);
++
++extern VCHIQ_SLOT_ZERO_T *
++vchiq_init_slots(void *mem_base, int mem_size);
++
++extern VCHIQ_STATUS_T
++vchiq_init_state(VCHIQ_STATE_T *state, VCHIQ_SLOT_ZERO_T *slot_zero,
++ int is_master);
++
++extern VCHIQ_STATUS_T
++vchiq_connect_internal(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance);
++
++extern VCHIQ_SERVICE_T *
++vchiq_add_service_internal(VCHIQ_STATE_T *state,
++ const VCHIQ_SERVICE_PARAMS_T *params, int srvstate,
++ VCHIQ_INSTANCE_T instance, VCHIQ_USERDATA_TERM_T userdata_term);
++
++extern VCHIQ_STATUS_T
++vchiq_open_service_internal(VCHIQ_SERVICE_T *service, int client_id);
++
++extern VCHIQ_STATUS_T
++vchiq_close_service_internal(VCHIQ_SERVICE_T *service, int close_recvd);
++
++extern void
++vchiq_terminate_service_internal(VCHIQ_SERVICE_T *service);
++
++extern void
++vchiq_free_service_internal(VCHIQ_SERVICE_T *service);
++
++extern VCHIQ_STATUS_T
++vchiq_shutdown_internal(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance);
++
++extern VCHIQ_STATUS_T
++vchiq_pause_internal(VCHIQ_STATE_T *state);
++
++extern VCHIQ_STATUS_T
++vchiq_resume_internal(VCHIQ_STATE_T *state);
++
++extern void
++remote_event_pollall(VCHIQ_STATE_T *state);
++
++extern VCHIQ_STATUS_T
++vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle,
++ VCHI_MEM_HANDLE_T memhandle, void *offset, int size, void *userdata,
++ VCHIQ_BULK_MODE_T mode, VCHIQ_BULK_DIR_T dir);
++
++extern void
++vchiq_dump_state(void *dump_context, VCHIQ_STATE_T *state);
++
++extern void
++vchiq_dump_service_state(void *dump_context, VCHIQ_SERVICE_T *service);
++
++extern void
++vchiq_loud_error_header(void);
++
++extern void
++vchiq_loud_error_footer(void);
++
++extern void
++request_poll(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, int poll_type);
++
++static inline VCHIQ_SERVICE_T *
++handle_to_service(VCHIQ_SERVICE_HANDLE_T handle)
++{
++ VCHIQ_STATE_T *state = vchiq_states[(handle / VCHIQ_MAX_SERVICES) &
++ (VCHIQ_MAX_STATES - 1)];
++ if (!state)
++ return NULL;
++
++ return state->services[handle & (VCHIQ_MAX_SERVICES - 1)];
++}
++
++extern VCHIQ_SERVICE_T *
++find_service_by_handle(VCHIQ_SERVICE_HANDLE_T handle);
++
++extern VCHIQ_SERVICE_T *
++find_service_by_port(VCHIQ_STATE_T *state, int localport);
++
++extern VCHIQ_SERVICE_T *
++find_service_for_instance(VCHIQ_INSTANCE_T instance,
++ VCHIQ_SERVICE_HANDLE_T handle);
++
++extern VCHIQ_SERVICE_T *
++find_closed_service_for_instance(VCHIQ_INSTANCE_T instance,
++ VCHIQ_SERVICE_HANDLE_T handle);
++
++extern VCHIQ_SERVICE_T *
++next_service_by_instance(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance,
++ int *pidx);
++
++extern void
++lock_service(VCHIQ_SERVICE_T *service);
++
++extern void
++unlock_service(VCHIQ_SERVICE_T *service);
++
++/* The following functions are called from vchiq_core, and external
++** implementations must be provided. */
++
++extern VCHIQ_STATUS_T
++vchiq_prepare_bulk_data(VCHIQ_BULK_T *bulk,
++ VCHI_MEM_HANDLE_T memhandle, void *offset, int size, int dir);
++
++extern void
++vchiq_transfer_bulk(VCHIQ_BULK_T *bulk);
++
++extern void
++vchiq_complete_bulk(VCHIQ_BULK_T *bulk);
++
++extern VCHIQ_STATUS_T
++vchiq_copy_from_user(void *dst, const void *src, int size);
++
++extern void
++remote_event_signal(REMOTE_EVENT_T *event);
++
++void
++vchiq_platform_check_suspend(VCHIQ_STATE_T *state);
++
++extern void
++vchiq_platform_paused(VCHIQ_STATE_T *state);
++
++extern VCHIQ_STATUS_T
++vchiq_platform_resume(VCHIQ_STATE_T *state);
++
++extern void
++vchiq_platform_resumed(VCHIQ_STATE_T *state);
++
++extern void
++vchiq_dump(void *dump_context, const char *str, int len);
++
++extern void
++vchiq_dump_platform_state(void *dump_context);
++
++extern void
++vchiq_dump_platform_instances(void *dump_context);
++
++extern void
++vchiq_dump_platform_service_state(void *dump_context,
++ VCHIQ_SERVICE_T *service);
++
++extern VCHIQ_STATUS_T
++vchiq_use_service_internal(VCHIQ_SERVICE_T *service);
++
++extern VCHIQ_STATUS_T
++vchiq_release_service_internal(VCHIQ_SERVICE_T *service);
++
++extern void
++vchiq_on_remote_use(VCHIQ_STATE_T *state);
++
++extern void
++vchiq_on_remote_release(VCHIQ_STATE_T *state);
++
++extern VCHIQ_STATUS_T
++vchiq_platform_init_state(VCHIQ_STATE_T *state);
++
++extern VCHIQ_STATUS_T
++vchiq_check_service(VCHIQ_SERVICE_T *service);
++
++extern void
++vchiq_on_remote_use_active(VCHIQ_STATE_T *state);
++
++extern VCHIQ_STATUS_T
++vchiq_send_remote_use(VCHIQ_STATE_T *state);
++
++extern VCHIQ_STATUS_T
++vchiq_send_remote_release(VCHIQ_STATE_T *state);
++
++extern VCHIQ_STATUS_T
++vchiq_send_remote_use_active(VCHIQ_STATE_T *state);
++
++extern void
++vchiq_platform_conn_state_changed(VCHIQ_STATE_T *state,
++ VCHIQ_CONNSTATE_T oldstate, VCHIQ_CONNSTATE_T newstate);
++
++extern void
++vchiq_platform_handle_timeout(VCHIQ_STATE_T *state);
++
++extern void
++vchiq_set_conn_state(VCHIQ_STATE_T *state, VCHIQ_CONNSTATE_T newstate);
++
++
++extern void
++vchiq_log_dump_mem(const char *label, uint32_t addr, const void *voidMem,
++ size_t numBytes);
++
++#endif
+--- /dev/null
++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
+@@ -0,0 +1,383 @@
++/**
++ * Copyright (c) 2014 Raspberry Pi (Trading) Ltd. All rights reserved.
++ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++#include <linux/debugfs.h>
++#include "vchiq_core.h"
++#include "vchiq_arm.h"
++#include "vchiq_debugfs.h"
++
++#ifdef CONFIG_DEBUG_FS
++
++/****************************************************************************
++*
++* log category entries
++*
++***************************************************************************/
++#define DEBUGFS_WRITE_BUF_SIZE 256
++
++#define VCHIQ_LOG_ERROR_STR "error"
++#define VCHIQ_LOG_WARNING_STR "warning"
++#define VCHIQ_LOG_INFO_STR "info"
++#define VCHIQ_LOG_TRACE_STR "trace"
++
++
++/* Top-level debug info */
++struct vchiq_debugfs_info {
++ /* Global 'vchiq' debugfs entry used by all instances */
++ struct dentry *vchiq_cfg_dir;
++
++ /* one entry per client process */
++ struct dentry *clients;
++
++ /* log categories */
++ struct dentry *log_categories;
++};
++
++static struct vchiq_debugfs_info debugfs_info;
++
++/* Log category debugfs entries */
++struct vchiq_debugfs_log_entry {
++ const char *name;
++ int *plevel;
++ struct dentry *dir;
++};
++
++static struct vchiq_debugfs_log_entry vchiq_debugfs_log_entries[] = {
++ { "core", &vchiq_core_log_level },
++ { "msg", &vchiq_core_msg_log_level },
++ { "sync", &vchiq_sync_log_level },
++ { "susp", &vchiq_susp_log_level },
++ { "arm", &vchiq_arm_log_level },
++};
++static int n_log_entries =
++ sizeof(vchiq_debugfs_log_entries)/sizeof(vchiq_debugfs_log_entries[0]);
++
++
++static struct dentry *vchiq_clients_top(void);
++static struct dentry *vchiq_debugfs_top(void);
++
++static int debugfs_log_show(struct seq_file *f, void *offset)
++{
++ int *levp = f->private;
++ char *log_value = NULL;
++
++ switch (*levp) {
++ case VCHIQ_LOG_ERROR:
++ log_value = VCHIQ_LOG_ERROR_STR;
++ break;
++ case VCHIQ_LOG_WARNING:
++ log_value = VCHIQ_LOG_WARNING_STR;
++ break;
++ case VCHIQ_LOG_INFO:
++ log_value = VCHIQ_LOG_INFO_STR;
++ break;
++ case VCHIQ_LOG_TRACE:
++ log_value = VCHIQ_LOG_TRACE_STR;
++ break;
++ default:
++ break;
++ }
++
++ seq_printf(f, "%s\n", log_value ? log_value : "(null)");
++
++ return 0;
++}
++
++static int debugfs_log_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, debugfs_log_show, inode->i_private);
++}
++
++static int debugfs_log_write(struct file *file,
++ const char __user *buffer,
++ size_t count, loff_t *ppos)
++{
++ struct seq_file *f = (struct seq_file *)file->private_data;
++ int *levp = f->private;
++ char kbuf[DEBUGFS_WRITE_BUF_SIZE + 1];
++
++ memset(kbuf, 0, DEBUGFS_WRITE_BUF_SIZE + 1);
++ if (count >= DEBUGFS_WRITE_BUF_SIZE)
++ count = DEBUGFS_WRITE_BUF_SIZE;
++
++ if (copy_from_user(kbuf, buffer, count) != 0)
++ return -EFAULT;
++ kbuf[count - 1] = 0;
++
++ if (strncmp("error", kbuf, strlen("error")) == 0)
++ *levp = VCHIQ_LOG_ERROR;
++ else if (strncmp("warning", kbuf, strlen("warning")) == 0)
++ *levp = VCHIQ_LOG_WARNING;
++ else if (strncmp("info", kbuf, strlen("info")) == 0)
++ *levp = VCHIQ_LOG_INFO;
++ else if (strncmp("trace", kbuf, strlen("trace")) == 0)
++ *levp = VCHIQ_LOG_TRACE;
++ else
++ *levp = VCHIQ_LOG_DEFAULT;
++
++ *ppos += count;
++
++ return count;
++}
++
++static const struct file_operations debugfs_log_fops = {
++ .owner = THIS_MODULE,
++ .open = debugfs_log_open,
++ .write = debugfs_log_write,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++
++/* create an entry under <debugfs>/vchiq/log for each log category */
++static int vchiq_debugfs_create_log_entries(struct dentry *top)
++{
++ struct dentry *dir;
++ size_t i;
++ int ret = 0;
++ dir = debugfs_create_dir("log", vchiq_debugfs_top());
++ if (!dir)
++ return -ENOMEM;
++ debugfs_info.log_categories = dir;
++
++ for (i = 0; i < n_log_entries; i++) {
++ void *levp = (void *)vchiq_debugfs_log_entries[i].plevel;
++ dir = debugfs_create_file(vchiq_debugfs_log_entries[i].name,
++ 0644,
++ debugfs_info.log_categories,
++ levp,
++ &debugfs_log_fops);
++ if (!dir) {
++ ret = -ENOMEM;
++ break;
++ }
++
++ vchiq_debugfs_log_entries[i].dir = dir;
++ }
++ return ret;
++}
++
++static int debugfs_usecount_show(struct seq_file *f, void *offset)
++{
++ VCHIQ_INSTANCE_T instance = f->private;
++ int use_count;
++
++ use_count = vchiq_instance_get_use_count(instance);
++ seq_printf(f, "%d\n", use_count);
++
++ return 0;
++}
++
++static int debugfs_usecount_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, debugfs_usecount_show, inode->i_private);
++}
++
++static const struct file_operations debugfs_usecount_fops = {
++ .owner = THIS_MODULE,
++ .open = debugfs_usecount_open,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++
++static int debugfs_trace_show(struct seq_file *f, void *offset)
++{
++ VCHIQ_INSTANCE_T instance = f->private;
++ int trace;
++
++ trace = vchiq_instance_get_trace(instance);
++ seq_printf(f, "%s\n", trace ? "Y" : "N");
++
++ return 0;
++}
++
++static int debugfs_trace_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, debugfs_trace_show, inode->i_private);
++}
++
++static int debugfs_trace_write(struct file *file,
++ const char __user *buffer,
++ size_t count, loff_t *ppos)
++{
++ struct seq_file *f = (struct seq_file *)file->private_data;
++ VCHIQ_INSTANCE_T instance = f->private;
++ char firstchar;
++
++ if (copy_from_user(&firstchar, buffer, 1) != 0)
++ return -EFAULT;
++
++ switch (firstchar) {
++ case 'Y':
++ case 'y':
++ case '1':
++ vchiq_instance_set_trace(instance, 1);
++ break;
++ case 'N':
++ case 'n':
++ case '0':
++ vchiq_instance_set_trace(instance, 0);
++ break;
++ default:
++ break;
++ }
++
++ *ppos += count;
++
++ return count;
++}
++
++static const struct file_operations debugfs_trace_fops = {
++ .owner = THIS_MODULE,
++ .open = debugfs_trace_open,
++ .write = debugfs_trace_write,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++
++/* add an instance (process) to the debugfs entries */
++int vchiq_debugfs_add_instance(VCHIQ_INSTANCE_T instance)
++{
++ char pidstr[16];
++ struct dentry *top, *use_count, *trace;
++ struct dentry *clients = vchiq_clients_top();
++
++ snprintf(pidstr, sizeof(pidstr), "%d",
++ vchiq_instance_get_pid(instance));
++
++ top = debugfs_create_dir(pidstr, clients);
++ if (!top)
++ goto fail_top;
++
++ use_count = debugfs_create_file("use_count",
++ 0444, top,
++ instance,
++ &debugfs_usecount_fops);
++ if (!use_count)
++ goto fail_use_count;
++
++ trace = debugfs_create_file("trace",
++ 0644, top,
++ instance,
++ &debugfs_trace_fops);
++ if (!trace)
++ goto fail_trace;
++
++ vchiq_instance_get_debugfs_node(instance)->dentry = top;
++
++ return 0;
++
++fail_trace:
++ debugfs_remove(use_count);
++fail_use_count:
++ debugfs_remove(top);
++fail_top:
++ return -ENOMEM;
++}
++
++void vchiq_debugfs_remove_instance(VCHIQ_INSTANCE_T instance)
++{
++ VCHIQ_DEBUGFS_NODE_T *node = vchiq_instance_get_debugfs_node(instance);
++ debugfs_remove_recursive(node->dentry);
++}
++
++
++int vchiq_debugfs_init(void)
++{
++ BUG_ON(debugfs_info.vchiq_cfg_dir != NULL);
++
++ debugfs_info.vchiq_cfg_dir = debugfs_create_dir("vchiq", NULL);
++ if (debugfs_info.vchiq_cfg_dir == NULL)
++ goto fail;
++
++ debugfs_info.clients = debugfs_create_dir("clients",
++ vchiq_debugfs_top());
++ if (!debugfs_info.clients)
++ goto fail;
++
++ if (vchiq_debugfs_create_log_entries(vchiq_debugfs_top()) != 0)
++ goto fail;
++
++ return 0;
++
++fail:
++ vchiq_debugfs_deinit();
++ vchiq_log_error(vchiq_arm_log_level,
++ "%s: failed to create debugfs directory",
++ __func__);
++
++ return -ENOMEM;
++}
++
++/* remove all the debugfs entries */
++void vchiq_debugfs_deinit(void)
++{
++ debugfs_remove_recursive(vchiq_debugfs_top());
++}
++
++static struct dentry *vchiq_clients_top(void)
++{
++ return debugfs_info.clients;
++}
++
++static struct dentry *vchiq_debugfs_top(void)
++{
++ BUG_ON(debugfs_info.vchiq_cfg_dir == NULL);
++ return debugfs_info.vchiq_cfg_dir;
++}
++
++#else /* CONFIG_DEBUG_FS */
++
++int vchiq_debugfs_init(void)
++{
++ return 0;
++}
++
++void vchiq_debugfs_deinit(void)
++{
++}
++
++int vchiq_debugfs_add_instance(VCHIQ_INSTANCE_T instance)
++{
++ return 0;
++}
++
++void vchiq_debugfs_remove_instance(VCHIQ_INSTANCE_T instance)
++{
++}
++
++#endif /* CONFIG_DEBUG_FS */
+--- /dev/null
++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_debugfs.h
+@@ -0,0 +1,52 @@
++/**
++ * Copyright (c) 2014 Raspberry Pi (Trading) Ltd. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef VCHIQ_DEBUGFS_H
++#define VCHIQ_DEBUGFS_H
++
++#include "vchiq_core.h"
++
++typedef struct vchiq_debugfs_node_struct
++{
++ struct dentry *dentry;
++} VCHIQ_DEBUGFS_NODE_T;
++
++int vchiq_debugfs_init(void);
++
++void vchiq_debugfs_deinit(void);
++
++int vchiq_debugfs_add_instance(VCHIQ_INSTANCE_T instance);
++
++void vchiq_debugfs_remove_instance(VCHIQ_INSTANCE_T instance);
++
++#endif /* VCHIQ_DEBUGFS_H */
+--- /dev/null
++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_genversion
+@@ -0,0 +1,87 @@
++#!/usr/bin/perl -w
++
++use strict;
++
++#
++# Generate a version from available information
++#
++
++my $prefix = shift @ARGV;
++my $root = shift @ARGV;
++
++
++if ( not defined $root ) {
++ die "usage: $0 prefix root-dir\n";
++}
++
++if ( ! -d $root ) {
++ die "root directory $root not found\n";
++}
++
++my $version = "unknown";
++my $tainted = "";
++
++if ( -d "$root/.git" ) {
++ # attempt to work out git version. only do so
++ # on a linux build host, as cygwin builds are
++ # already slow enough
++
++ if ( -f "/usr/bin/git" || -f "/usr/local/bin/git" ) {
++ if (not open(F, "git --git-dir $root/.git rev-parse --verify HEAD|")) {
++ $version = "no git version";
++ }
++ else {
++ $version = <F>;
++ $version =~ s/[ \r\n]*$//; # chomp may not be enough (cygwin).
++ $version =~ s/^[ \r\n]*//; # chomp may not be enough (cygwin).
++ }
++
++ if (open(G, "git --git-dir $root/.git status --porcelain|")) {
++ $tainted = <G>;
++ $tainted =~ s/[ \r\n]*$//; # chomp may not be enough (cygwin).
++ $tainted =~ s/^[ \r\n]*//; # chomp may not be enough (cygwin).
++ if (length $tainted) {
++ $version = join ' ', $version, "(tainted)";
++ }
++ else {
++ $version = join ' ', $version, "(clean)";
++ }
++ }
++ }
++}
++
++my $hostname = `hostname`;
++$hostname =~ s/[ \r\n]*$//; # chomp may not be enough (cygwin).
++$hostname =~ s/^[ \r\n]*//; # chomp may not be enough (cygwin).
++
++
++print STDERR "Version $version\n";
++print <<EOF;
++#include "${prefix}_build_info.h"
++#include <linux/broadcom/vc_debug_sym.h>
++
++VC_DEBUG_DECLARE_STRING_VAR( ${prefix}_build_hostname, "$hostname" );
++VC_DEBUG_DECLARE_STRING_VAR( ${prefix}_build_version, "$version" );
++VC_DEBUG_DECLARE_STRING_VAR( ${prefix}_build_time, __TIME__ );
++VC_DEBUG_DECLARE_STRING_VAR( ${prefix}_build_date, __DATE__ );
++
++const char *vchiq_get_build_hostname( void )
++{
++ return vchiq_build_hostname;
++}
++
++const char *vchiq_get_build_version( void )
++{
++ return vchiq_build_version;
++}
++
++const char *vchiq_get_build_date( void )
++{
++ return vchiq_build_date;
++}
++
++const char *vchiq_get_build_time( void )
++{
++ return vchiq_build_time;
++}
++EOF
+--- /dev/null
++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_if.h
+@@ -0,0 +1,189 @@
++/**
++ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef VCHIQ_IF_H
++#define VCHIQ_IF_H
++
++#include "interface/vchi/vchi_mh.h"
++
++#define VCHIQ_SERVICE_HANDLE_INVALID 0
++
++#define VCHIQ_SLOT_SIZE 4096
++#define VCHIQ_MAX_MSG_SIZE (VCHIQ_SLOT_SIZE - sizeof(VCHIQ_HEADER_T))
++#define VCHIQ_CHANNEL_SIZE VCHIQ_MAX_MSG_SIZE /* For backwards compatibility */
++
++#define VCHIQ_MAKE_FOURCC(x0, x1, x2, x3) \
++ (((x0) << 24) | ((x1) << 16) | ((x2) << 8) | (x3))
++#define VCHIQ_GET_SERVICE_USERDATA(service) vchiq_get_service_userdata(service)
++#define VCHIQ_GET_SERVICE_FOURCC(service) vchiq_get_service_fourcc(service)
++
++typedef enum {
++ VCHIQ_SERVICE_OPENED, /* service, -, - */
++ VCHIQ_SERVICE_CLOSED, /* service, -, - */
++ VCHIQ_MESSAGE_AVAILABLE, /* service, header, - */
++ VCHIQ_BULK_TRANSMIT_DONE, /* service, -, bulk_userdata */
++ VCHIQ_BULK_RECEIVE_DONE, /* service, -, bulk_userdata */
++ VCHIQ_BULK_TRANSMIT_ABORTED, /* service, -, bulk_userdata */
++ VCHIQ_BULK_RECEIVE_ABORTED /* service, -, bulk_userdata */
++} VCHIQ_REASON_T;
++
++typedef enum {
++ VCHIQ_ERROR = -1,
++ VCHIQ_SUCCESS = 0,
++ VCHIQ_RETRY = 1
++} VCHIQ_STATUS_T;
++
++typedef enum {
++ VCHIQ_BULK_MODE_CALLBACK,
++ VCHIQ_BULK_MODE_BLOCKING,
++ VCHIQ_BULK_MODE_NOCALLBACK,
++ VCHIQ_BULK_MODE_WAITING /* Reserved for internal use */
++} VCHIQ_BULK_MODE_T;
++
++typedef enum {
++ VCHIQ_SERVICE_OPTION_AUTOCLOSE,
++ VCHIQ_SERVICE_OPTION_SLOT_QUOTA,
++ VCHIQ_SERVICE_OPTION_MESSAGE_QUOTA,
++ VCHIQ_SERVICE_OPTION_SYNCHRONOUS,
++ VCHIQ_SERVICE_OPTION_TRACE
++} VCHIQ_SERVICE_OPTION_T;
++
++typedef struct vchiq_header_struct {
++ /* The message identifier - opaque to applications. */
++ int msgid;
++
++ /* Size of message data. */
++ unsigned int size;
++
++ char data[0]; /* message */
++} VCHIQ_HEADER_T;
++
++typedef struct {
++ const void *data;
++ unsigned int size;
++} VCHIQ_ELEMENT_T;
++
++typedef unsigned int VCHIQ_SERVICE_HANDLE_T;
++
++typedef VCHIQ_STATUS_T (*VCHIQ_CALLBACK_T)(VCHIQ_REASON_T, VCHIQ_HEADER_T *,
++ VCHIQ_SERVICE_HANDLE_T, void *);
++
++typedef struct vchiq_service_base_struct {
++ int fourcc;
++ VCHIQ_CALLBACK_T callback;
++ void *userdata;
++} VCHIQ_SERVICE_BASE_T;
++
++typedef struct vchiq_service_params_struct {
++ int fourcc;
++ VCHIQ_CALLBACK_T callback;
++ void *userdata;
++ short version; /* Increment for non-trivial changes */
++ short version_min; /* Update for incompatible changes */
++} VCHIQ_SERVICE_PARAMS_T;
++
++typedef struct vchiq_config_struct {
++ unsigned int max_msg_size;
++ unsigned int bulk_threshold; /* The message size above which it
++ is better to use a bulk transfer
++ (<= max_msg_size) */
++ unsigned int max_outstanding_bulks;
++ unsigned int max_services;
++ short version; /* The version of VCHIQ */
++ short version_min; /* The minimum compatible version of VCHIQ */
++} VCHIQ_CONFIG_T;
++
++typedef struct vchiq_instance_struct *VCHIQ_INSTANCE_T;
++typedef void (*VCHIQ_REMOTE_USE_CALLBACK_T)(void *cb_arg);
++
++extern VCHIQ_STATUS_T vchiq_initialise(VCHIQ_INSTANCE_T *pinstance);
++extern VCHIQ_STATUS_T vchiq_shutdown(VCHIQ_INSTANCE_T instance);
++extern VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance);
++extern VCHIQ_STATUS_T vchiq_add_service(VCHIQ_INSTANCE_T instance,
++ const VCHIQ_SERVICE_PARAMS_T *params,
++ VCHIQ_SERVICE_HANDLE_T *pservice);
++extern VCHIQ_STATUS_T vchiq_open_service(VCHIQ_INSTANCE_T instance,
++ const VCHIQ_SERVICE_PARAMS_T *params,
++ VCHIQ_SERVICE_HANDLE_T *pservice);
++extern VCHIQ_STATUS_T vchiq_close_service(VCHIQ_SERVICE_HANDLE_T service);
++extern VCHIQ_STATUS_T vchiq_remove_service(VCHIQ_SERVICE_HANDLE_T service);
++extern VCHIQ_STATUS_T vchiq_use_service(VCHIQ_SERVICE_HANDLE_T service);
++extern VCHIQ_STATUS_T vchiq_use_service_no_resume(
++ VCHIQ_SERVICE_HANDLE_T service);
++extern VCHIQ_STATUS_T vchiq_release_service(VCHIQ_SERVICE_HANDLE_T service);
++
++extern VCHIQ_STATUS_T vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T service,
++ const VCHIQ_ELEMENT_T *elements, unsigned int count);
++extern void vchiq_release_message(VCHIQ_SERVICE_HANDLE_T service,
++ VCHIQ_HEADER_T *header);
++extern VCHIQ_STATUS_T vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T service,
++ const void *data, unsigned int size, void *userdata);
++extern VCHIQ_STATUS_T vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T service,
++ void *data, unsigned int size, void *userdata);
++extern VCHIQ_STATUS_T vchiq_queue_bulk_transmit_handle(
++ VCHIQ_SERVICE_HANDLE_T service, VCHI_MEM_HANDLE_T handle,
++ const void *offset, unsigned int size, void *userdata);
++extern VCHIQ_STATUS_T vchiq_queue_bulk_receive_handle(
++ VCHIQ_SERVICE_HANDLE_T service, VCHI_MEM_HANDLE_T handle,
++ void *offset, unsigned int size, void *userdata);
++extern VCHIQ_STATUS_T vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T service,
++ const void *data, unsigned int size, void *userdata,
++ VCHIQ_BULK_MODE_T mode);
++extern VCHIQ_STATUS_T vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T service,
++ void *data, unsigned int size, void *userdata,
++ VCHIQ_BULK_MODE_T mode);
++extern VCHIQ_STATUS_T vchiq_bulk_transmit_handle(VCHIQ_SERVICE_HANDLE_T service,
++ VCHI_MEM_HANDLE_T handle, const void *offset, unsigned int size,
++ void *userdata, VCHIQ_BULK_MODE_T mode);
++extern VCHIQ_STATUS_T vchiq_bulk_receive_handle(VCHIQ_SERVICE_HANDLE_T service,
++ VCHI_MEM_HANDLE_T handle, void *offset, unsigned int size,
++ void *userdata, VCHIQ_BULK_MODE_T mode);
++extern int vchiq_get_client_id(VCHIQ_SERVICE_HANDLE_T service);
++extern void *vchiq_get_service_userdata(VCHIQ_SERVICE_HANDLE_T service);
++extern int vchiq_get_service_fourcc(VCHIQ_SERVICE_HANDLE_T service);
++extern VCHIQ_STATUS_T vchiq_get_config(VCHIQ_INSTANCE_T instance,
++ int config_size, VCHIQ_CONFIG_T *pconfig);
++extern VCHIQ_STATUS_T vchiq_set_service_option(VCHIQ_SERVICE_HANDLE_T service,
++ VCHIQ_SERVICE_OPTION_T option, int value);
++
++extern VCHIQ_STATUS_T vchiq_remote_use(VCHIQ_INSTANCE_T instance,
++ VCHIQ_REMOTE_USE_CALLBACK_T callback, void *cb_arg);
++extern VCHIQ_STATUS_T vchiq_remote_release(VCHIQ_INSTANCE_T instance);
++
++extern VCHIQ_STATUS_T vchiq_dump_phys_mem(VCHIQ_SERVICE_HANDLE_T service,
++ void *ptr, size_t num_bytes);
++
++extern VCHIQ_STATUS_T vchiq_get_peer_version(VCHIQ_SERVICE_HANDLE_T handle,
++ short *peer_version);
++
++#endif /* VCHIQ_IF_H */
+--- /dev/null
++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_ioctl.h
+@@ -0,0 +1,131 @@
++/**
++ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef VCHIQ_IOCTLS_H
++#define VCHIQ_IOCTLS_H
++
++#include <linux/ioctl.h>
++#include "vchiq_if.h"
++
++#define VCHIQ_IOC_MAGIC 0xc4
++#define VCHIQ_INVALID_HANDLE (~0)
++
++typedef struct {
++ VCHIQ_SERVICE_PARAMS_T params;
++ int is_open;
++ int is_vchi;
++ unsigned int handle; /* OUT */
++} VCHIQ_CREATE_SERVICE_T;
++
++typedef struct {
++ unsigned int handle;
++ unsigned int count;
++ const VCHIQ_ELEMENT_T *elements;
++} VCHIQ_QUEUE_MESSAGE_T;
++
++typedef struct {
++ unsigned int handle;
++ void *data;
++ unsigned int size;
++ void *userdata;
++ VCHIQ_BULK_MODE_T mode;
++} VCHIQ_QUEUE_BULK_TRANSFER_T;
++
++typedef struct {
++ VCHIQ_REASON_T reason;
++ VCHIQ_HEADER_T *header;
++ void *service_userdata;
++ void *bulk_userdata;
++} VCHIQ_COMPLETION_DATA_T;
++
++typedef struct {
++ unsigned int count;
++ VCHIQ_COMPLETION_DATA_T *buf;
++ unsigned int msgbufsize;
++ unsigned int msgbufcount; /* IN/OUT */
++ void **msgbufs;
++} VCHIQ_AWAIT_COMPLETION_T;
++
++typedef struct {
++ unsigned int handle;
++ int blocking;
++ unsigned int bufsize;
++ void *buf;
++} VCHIQ_DEQUEUE_MESSAGE_T;
++
++typedef struct {
++ unsigned int config_size;
++ VCHIQ_CONFIG_T *pconfig;
++} VCHIQ_GET_CONFIG_T;
++
++typedef struct {
++ unsigned int handle;
++ VCHIQ_SERVICE_OPTION_T option;
++ int value;
++} VCHIQ_SET_SERVICE_OPTION_T;
++
++typedef struct {
++ void *virt_addr;
++ size_t num_bytes;
++} VCHIQ_DUMP_MEM_T;
++
++#define VCHIQ_IOC_CONNECT _IO(VCHIQ_IOC_MAGIC, 0)
++#define VCHIQ_IOC_SHUTDOWN _IO(VCHIQ_IOC_MAGIC, 1)
++#define VCHIQ_IOC_CREATE_SERVICE \
++ _IOWR(VCHIQ_IOC_MAGIC, 2, VCHIQ_CREATE_SERVICE_T)
++#define VCHIQ_IOC_REMOVE_SERVICE _IO(VCHIQ_IOC_MAGIC, 3)
++#define VCHIQ_IOC_QUEUE_MESSAGE \
++ _IOW(VCHIQ_IOC_MAGIC, 4, VCHIQ_QUEUE_MESSAGE_T)
++#define VCHIQ_IOC_QUEUE_BULK_TRANSMIT \
++ _IOWR(VCHIQ_IOC_MAGIC, 5, VCHIQ_QUEUE_BULK_TRANSFER_T)
++#define VCHIQ_IOC_QUEUE_BULK_RECEIVE \
++ _IOWR(VCHIQ_IOC_MAGIC, 6, VCHIQ_QUEUE_BULK_TRANSFER_T)
++#define VCHIQ_IOC_AWAIT_COMPLETION \
++ _IOWR(VCHIQ_IOC_MAGIC, 7, VCHIQ_AWAIT_COMPLETION_T)
++#define VCHIQ_IOC_DEQUEUE_MESSAGE \
++ _IOWR(VCHIQ_IOC_MAGIC, 8, VCHIQ_DEQUEUE_MESSAGE_T)
++#define VCHIQ_IOC_GET_CLIENT_ID _IO(VCHIQ_IOC_MAGIC, 9)
++#define VCHIQ_IOC_GET_CONFIG \
++ _IOWR(VCHIQ_IOC_MAGIC, 10, VCHIQ_GET_CONFIG_T)
++#define VCHIQ_IOC_CLOSE_SERVICE _IO(VCHIQ_IOC_MAGIC, 11)
++#define VCHIQ_IOC_USE_SERVICE _IO(VCHIQ_IOC_MAGIC, 12)
++#define VCHIQ_IOC_RELEASE_SERVICE _IO(VCHIQ_IOC_MAGIC, 13)
++#define VCHIQ_IOC_SET_SERVICE_OPTION \
++ _IOW(VCHIQ_IOC_MAGIC, 14, VCHIQ_SET_SERVICE_OPTION_T)
++#define VCHIQ_IOC_DUMP_PHYS_MEM \
++ _IOW(VCHIQ_IOC_MAGIC, 15, VCHIQ_DUMP_MEM_T)
++#define VCHIQ_IOC_LIB_VERSION _IO(VCHIQ_IOC_MAGIC, 16)
++#define VCHIQ_IOC_CLOSE_DELIVERED _IO(VCHIQ_IOC_MAGIC, 17)
++#define VCHIQ_IOC_MAX 17
++
++#endif
+--- /dev/null
++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
+@@ -0,0 +1,458 @@
++/**
++ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/* ---- Include Files ---------------------------------------------------- */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++
++#include "vchiq_core.h"
++#include "vchiq_arm.h"
++#include "vchiq_killable.h"
++
++/* ---- Public Variables ------------------------------------------------- */
++
++/* ---- Private Constants and Types -------------------------------------- */
++
++struct bulk_waiter_node {
++ struct bulk_waiter bulk_waiter;
++ int pid;
++ struct list_head list;
++};
++
++struct vchiq_instance_struct {
++ VCHIQ_STATE_T *state;
++
++ int connected;
++
++ struct list_head bulk_waiter_list;
++ struct mutex bulk_waiter_list_mutex;
++};
++
++static VCHIQ_STATUS_T
++vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data,
++ unsigned int size, VCHIQ_BULK_DIR_T dir);
++
++/****************************************************************************
++*
++* vchiq_initialise
++*
++***************************************************************************/
++#define VCHIQ_INIT_RETRIES 10
++VCHIQ_STATUS_T vchiq_initialise(VCHIQ_INSTANCE_T *instanceOut)
++{
++ VCHIQ_STATUS_T status = VCHIQ_ERROR;
++ VCHIQ_STATE_T *state;
++ VCHIQ_INSTANCE_T instance = NULL;
++ int i;
++
++ vchiq_log_trace(vchiq_core_log_level, "%s called", __func__);
++
++ /* VideoCore may not be ready due to boot up timing.
++ It may never be ready if kernel and firmware are mismatched, so don't block forever. */
++ for (i=0; i<VCHIQ_INIT_RETRIES; i++) {
++ state = vchiq_get_state();
++ if (state)
++ break;
++ udelay(500);
++ }
++ if (i==VCHIQ_INIT_RETRIES) {
++ vchiq_log_error(vchiq_core_log_level,
++ "%s: videocore not initialized\n", __func__);
++ goto failed;
++ } else if (i>0) {
++ vchiq_log_warning(vchiq_core_log_level,
++ "%s: videocore initialized after %d retries\n", __func__, i);
++ }
++
++ instance = kzalloc(sizeof(*instance), GFP_KERNEL);
++ if (!instance) {
++ vchiq_log_error(vchiq_core_log_level,
++ "%s: error allocating vchiq instance\n", __func__);
++ goto failed;
++ }
++
++ instance->connected = 0;
++ instance->state = state;
++ mutex_init(&instance->bulk_waiter_list_mutex);
++ INIT_LIST_HEAD(&instance->bulk_waiter_list);
++
++ *instanceOut = instance;
++
++ status = VCHIQ_SUCCESS;
++
++failed:
++ vchiq_log_trace(vchiq_core_log_level,
++ "%s(%p): returning %d", __func__, instance, status);
++
++ return status;
++}
++EXPORT_SYMBOL(vchiq_initialise);
++
++/****************************************************************************
++*
++* vchiq_shutdown
++*
++***************************************************************************/
++
++VCHIQ_STATUS_T vchiq_shutdown(VCHIQ_INSTANCE_T instance)
++{
++ VCHIQ_STATUS_T status;
++ VCHIQ_STATE_T *state = instance->state;
++
++ vchiq_log_trace(vchiq_core_log_level,
++ "%s(%p) called", __func__, instance);
++
++ if (mutex_lock_interruptible(&state->mutex) != 0)
++ return VCHIQ_RETRY;
++
++ /* Remove all services */
++ status = vchiq_shutdown_internal(state, instance);
++
++ mutex_unlock(&state->mutex);
++
++ vchiq_log_trace(vchiq_core_log_level,
++ "%s(%p): returning %d", __func__, instance, status);
++
++ if (status == VCHIQ_SUCCESS) {
++ struct list_head *pos, *next;
++ list_for_each_safe(pos, next,
++ &instance->bulk_waiter_list) {
++ struct bulk_waiter_node *waiter;
++ waiter = list_entry(pos,
++ struct bulk_waiter_node,
++ list);
++ list_del(pos);
++ vchiq_log_info(vchiq_arm_log_level,
++ "bulk_waiter - cleaned up %x "
++ "for pid %d",
++ (unsigned int)waiter, waiter->pid);
++ kfree(waiter);
++ }
++ kfree(instance);
++ }
++
++ return status;
++}
++EXPORT_SYMBOL(vchiq_shutdown);
++
++/****************************************************************************
++*
++* vchiq_is_connected
++*
++***************************************************************************/
++
++int vchiq_is_connected(VCHIQ_INSTANCE_T instance)
++{
++ return instance->connected;
++}
++
++/****************************************************************************
++*
++* vchiq_connect
++*
++***************************************************************************/
++
++VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance)
++{
++ VCHIQ_STATUS_T status;
++ VCHIQ_STATE_T *state = instance->state;
++
++ vchiq_log_trace(vchiq_core_log_level,
++ "%s(%p) called", __func__, instance);
++
++ if (mutex_lock_interruptible(&state->mutex) != 0) {
++ vchiq_log_trace(vchiq_core_log_level,
++ "%s: call to mutex_lock failed", __func__);
++ status = VCHIQ_RETRY;
++ goto failed;
++ }
++ status = vchiq_connect_internal(state, instance);
++
++ if (status == VCHIQ_SUCCESS)
++ instance->connected = 1;
++
++ mutex_unlock(&state->mutex);
++
++failed:
++ vchiq_log_trace(vchiq_core_log_level,
++ "%s(%p): returning %d", __func__, instance, status);
++
++ return status;
++}
++EXPORT_SYMBOL(vchiq_connect);
++
++/****************************************************************************
++*
++* vchiq_add_service
++*
++***************************************************************************/
++
++VCHIQ_STATUS_T vchiq_add_service(
++ VCHIQ_INSTANCE_T instance,
++ const VCHIQ_SERVICE_PARAMS_T *params,
++ VCHIQ_SERVICE_HANDLE_T *phandle)
++{
++ VCHIQ_STATUS_T status;
++ VCHIQ_STATE_T *state = instance->state;
++ VCHIQ_SERVICE_T *service = NULL;
++ int srvstate;
++
++ vchiq_log_trace(vchiq_core_log_level,
++ "%s(%p) called", __func__, instance);
++
++ *phandle = VCHIQ_SERVICE_HANDLE_INVALID;
++
++ srvstate = vchiq_is_connected(instance)
++ ? VCHIQ_SRVSTATE_LISTENING
++ : VCHIQ_SRVSTATE_HIDDEN;
++
++ service = vchiq_add_service_internal(
++ state,
++ params,
++ srvstate,
++ instance,
++ NULL);
++
++ if (service) {
++ *phandle = service->handle;
++ status = VCHIQ_SUCCESS;
++ } else
++ status = VCHIQ_ERROR;
++
++ vchiq_log_trace(vchiq_core_log_level,
++ "%s(%p): returning %d", __func__, instance, status);
++
++ return status;
++}
++EXPORT_SYMBOL(vchiq_add_service);
++
++/****************************************************************************
++*
++* vchiq_open_service
++*
++***************************************************************************/
++
++VCHIQ_STATUS_T vchiq_open_service(
++ VCHIQ_INSTANCE_T instance,
++ const VCHIQ_SERVICE_PARAMS_T *params,
++ VCHIQ_SERVICE_HANDLE_T *phandle)
++{
++ VCHIQ_STATUS_T status = VCHIQ_ERROR;
++ VCHIQ_STATE_T *state = instance->state;
++ VCHIQ_SERVICE_T *service = NULL;
++
++ vchiq_log_trace(vchiq_core_log_level,
++ "%s(%p) called", __func__, instance);
++
++ *phandle = VCHIQ_SERVICE_HANDLE_INVALID;
++
++ if (!vchiq_is_connected(instance))
++ goto failed;
++
++ service = vchiq_add_service_internal(state,
++ params,
++ VCHIQ_SRVSTATE_OPENING,
++ instance,
++ NULL);
++
++ if (service) {
++ *phandle = service->handle;
++ status = vchiq_open_service_internal(service, current->pid);
++ if (status != VCHIQ_SUCCESS) {
++ vchiq_remove_service(service->handle);
++ *phandle = VCHIQ_SERVICE_HANDLE_INVALID;
++ }
++ }
++
++failed:
++ vchiq_log_trace(vchiq_core_log_level,
++ "%s(%p): returning %d", __func__, instance, status);
++
++ return status;
++}
++EXPORT_SYMBOL(vchiq_open_service);
++
++VCHIQ_STATUS_T
++vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle,
++ const void *data, unsigned int size, void *userdata)
++{
++ return vchiq_bulk_transfer(handle,
++ VCHI_MEM_HANDLE_INVALID, (void *)data, size, userdata,
++ VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_TRANSMIT);
++}
++EXPORT_SYMBOL(vchiq_queue_bulk_transmit);
++
++VCHIQ_STATUS_T
++vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data,
++ unsigned int size, void *userdata)
++{
++ return vchiq_bulk_transfer(handle,
++ VCHI_MEM_HANDLE_INVALID, data, size, userdata,
++ VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_RECEIVE);
++}
++EXPORT_SYMBOL(vchiq_queue_bulk_receive);
++
++VCHIQ_STATUS_T
++vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle, const void *data,
++ unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode)
++{
++ VCHIQ_STATUS_T status;
++
++ switch (mode) {
++ case VCHIQ_BULK_MODE_NOCALLBACK:
++ case VCHIQ_BULK_MODE_CALLBACK:
++ status = vchiq_bulk_transfer(handle,
++ VCHI_MEM_HANDLE_INVALID, (void *)data, size, userdata,
++ mode, VCHIQ_BULK_TRANSMIT);
++ break;
++ case VCHIQ_BULK_MODE_BLOCKING:
++ status = vchiq_blocking_bulk_transfer(handle,
++ (void *)data, size, VCHIQ_BULK_TRANSMIT);
++ break;
++ default:
++ return VCHIQ_ERROR;
++ }
++
++ return status;
++}
++EXPORT_SYMBOL(vchiq_bulk_transmit);
++
++VCHIQ_STATUS_T
++vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data,
++ unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode)
++{
++ VCHIQ_STATUS_T status;
++
++ switch (mode) {
++ case VCHIQ_BULK_MODE_NOCALLBACK:
++ case VCHIQ_BULK_MODE_CALLBACK:
++ status = vchiq_bulk_transfer(handle,
++ VCHI_MEM_HANDLE_INVALID, data, size, userdata,
++ mode, VCHIQ_BULK_RECEIVE);
++ break;
++ case VCHIQ_BULK_MODE_BLOCKING:
++ status = vchiq_blocking_bulk_transfer(handle,
++ (void *)data, size, VCHIQ_BULK_RECEIVE);
++ break;
++ default:
++ return VCHIQ_ERROR;
++ }
++
++ return status;
++}
++EXPORT_SYMBOL(vchiq_bulk_receive);
++
++static VCHIQ_STATUS_T
++vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data,
++ unsigned int size, VCHIQ_BULK_DIR_T dir)
++{
++ VCHIQ_INSTANCE_T instance;
++ VCHIQ_SERVICE_T *service;
++ VCHIQ_STATUS_T status;
++ struct bulk_waiter_node *waiter = NULL;
++ struct list_head *pos;
++
++ service = find_service_by_handle(handle);
++ if (!service)
++ return VCHIQ_ERROR;
++
++ instance = service->instance;
++
++ unlock_service(service);
++
++ mutex_lock(&instance->bulk_waiter_list_mutex);
++ list_for_each(pos, &instance->bulk_waiter_list) {
++ if (list_entry(pos, struct bulk_waiter_node,
++ list)->pid == current->pid) {
++ waiter = list_entry(pos,
++ struct bulk_waiter_node,
++ list);
++ list_del(pos);
++ break;
++ }
++ }
++ mutex_unlock(&instance->bulk_waiter_list_mutex);
++
++ if (waiter) {
++ VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk;
++ if (bulk) {
++ /* This thread has an outstanding bulk transfer. */
++ if ((bulk->data != data) ||
++ (bulk->size != size)) {
++ /* This is not a retry of the previous one.
++ ** Cancel the signal when the transfer
++ ** completes. */
++ spin_lock(&bulk_waiter_spinlock);
++ bulk->userdata = NULL;
++ spin_unlock(&bulk_waiter_spinlock);
++ }
++ }
++ }
++
++ if (!waiter) {
++ waiter = kzalloc(sizeof(struct bulk_waiter_node), GFP_KERNEL);
++ if (!waiter) {
++ vchiq_log_error(vchiq_core_log_level,
++ "%s - out of memory", __func__);
++ return VCHIQ_ERROR;
++ }
++ }
++
++ status = vchiq_bulk_transfer(handle, VCHI_MEM_HANDLE_INVALID,
++ data, size, &waiter->bulk_waiter, VCHIQ_BULK_MODE_BLOCKING,
++ dir);
++ if ((status != VCHIQ_RETRY) || fatal_signal_pending(current) ||
++ !waiter->bulk_waiter.bulk) {
++ VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk;
++ if (bulk) {
++ /* Cancel the signal when the transfer
++ ** completes. */
++ spin_lock(&bulk_waiter_spinlock);
++ bulk->userdata = NULL;
++ spin_unlock(&bulk_waiter_spinlock);
++ }
++ kfree(waiter);
++ } else {
++ waiter->pid = current->pid;
++ mutex_lock(&instance->bulk_waiter_list_mutex);
++ list_add(&waiter->list, &instance->bulk_waiter_list);
++ mutex_unlock(&instance->bulk_waiter_list_mutex);
++ vchiq_log_info(vchiq_arm_log_level,
++ "saved bulk_waiter %x for pid %d",
++ (unsigned int)waiter, current->pid);
++ }
++
++ return status;
++}
+--- /dev/null
++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_killable.h
+@@ -0,0 +1,69 @@
++/**
++ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef VCHIQ_KILLABLE_H
++#define VCHIQ_KILLABLE_H
++
++#include <linux/mutex.h>
++#include <linux/semaphore.h>
++
++#define SHUTDOWN_SIGS (sigmask(SIGKILL) | sigmask(SIGINT) | sigmask(SIGQUIT) | sigmask(SIGTRAP) | sigmask(SIGSTOP) | sigmask(SIGCONT))
++
++static inline int __must_check down_interruptible_killable(struct semaphore *sem)
++{
++ /* Allow interception of killable signals only. We don't want to be interrupted by harmless signals like SIGALRM */
++ int ret;
++ sigset_t blocked, oldset;
++ siginitsetinv(&blocked, SHUTDOWN_SIGS);
++ sigprocmask(SIG_SETMASK, &blocked, &oldset);
++ ret = down_interruptible(sem);
++ sigprocmask(SIG_SETMASK, &oldset, NULL);
++ return ret;
++}
++#define down_interruptible down_interruptible_killable
++
++
++static inline int __must_check mutex_lock_interruptible_killable(struct mutex *lock)
++{
++ /* Allow interception of killable signals only. We don't want to be interrupted by harmless signals like SIGALRM */
++ int ret;
++ sigset_t blocked, oldset;
++ siginitsetinv(&blocked, SHUTDOWN_SIGS);
++ sigprocmask(SIG_SETMASK, &blocked, &oldset);
++ ret = mutex_lock_interruptible(lock);
++ sigprocmask(SIG_SETMASK, &oldset, NULL);
++ return ret;
++}
++#define mutex_lock_interruptible mutex_lock_interruptible_killable
++
++#endif
+--- /dev/null
++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_memdrv.h
+@@ -0,0 +1,71 @@
++/**
++ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef VCHIQ_MEMDRV_H
++#define VCHIQ_MEMDRV_H
++
++/* ---- Include Files ----------------------------------------------------- */
++
++#include <linux/kernel.h>
++#include "vchiq_if.h"
++
++/* ---- Constants and Types ---------------------------------------------- */
++
++typedef struct {
++ void *armSharedMemVirt;
++ dma_addr_t armSharedMemPhys;
++ size_t armSharedMemSize;
++
++ void *vcSharedMemVirt;
++ dma_addr_t vcSharedMemPhys;
++ size_t vcSharedMemSize;
++} VCHIQ_SHARED_MEM_INFO_T;
++
++/* ---- Variable Externs ------------------------------------------------- */
++
++/* ---- Function Prototypes ---------------------------------------------- */
++
++void vchiq_get_shared_mem_info(VCHIQ_SHARED_MEM_INFO_T *info);
++
++VCHIQ_STATUS_T vchiq_memdrv_initialise(void);
++
++VCHIQ_STATUS_T vchiq_userdrv_create_instance(
++ const VCHIQ_PLATFORM_DATA_T * platform_data);
++
++VCHIQ_STATUS_T vchiq_userdrv_suspend(
++ const VCHIQ_PLATFORM_DATA_T * platform_data);
++
++VCHIQ_STATUS_T vchiq_userdrv_resume(
++ const VCHIQ_PLATFORM_DATA_T * platform_data);
++
++#endif
+--- /dev/null
++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_pagelist.h
+@@ -0,0 +1,58 @@
++/**
++ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef VCHIQ_PAGELIST_H
++#define VCHIQ_PAGELIST_H
++
++#ifndef PAGE_SIZE
++#define PAGE_SIZE 4096
++#endif
++#define CACHE_LINE_SIZE 32
++#define PAGELIST_WRITE 0
++#define PAGELIST_READ 1
++#define PAGELIST_READ_WITH_FRAGMENTS 2
++
++typedef struct pagelist_struct {
++ unsigned long length;
++ unsigned short type;
++ unsigned short offset;
++ unsigned long addrs[1]; /* N.B. 12 LSBs hold the number of following
++ pages at consecutive addresses. */
++} PAGELIST_T;
++
++typedef struct fragments_struct {
++ char headbuf[CACHE_LINE_SIZE];
++ char tailbuf[CACHE_LINE_SIZE];
++} FRAGMENTS_T;
++
++#endif /* VCHIQ_PAGELIST_H */
+--- /dev/null
++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c
+@@ -0,0 +1,860 @@
++/**
++ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++#include <linux/module.h>
++#include <linux/types.h>
++
++#include "interface/vchi/vchi.h"
++#include "vchiq.h"
++#include "vchiq_core.h"
++
++#include "vchiq_util.h"
++
++#include <stddef.h>
++
++#define vchiq_status_to_vchi(status) ((int32_t)status)
++
++typedef struct {
++ VCHIQ_SERVICE_HANDLE_T handle;
++
++ VCHIU_QUEUE_T queue;
++
++ VCHI_CALLBACK_T callback;
++ void *callback_param;
++} SHIM_SERVICE_T;
++
++/* ----------------------------------------------------------------------
++ * return pointer to the mphi message driver function table
++ * -------------------------------------------------------------------- */
++const VCHI_MESSAGE_DRIVER_T *
++vchi_mphi_message_driver_func_table(void)
++{
++ return NULL;
++}
++
++/* ----------------------------------------------------------------------
++ * return a pointer to the 'single' connection driver fops
++ * -------------------------------------------------------------------- */
++const VCHI_CONNECTION_API_T *
++single_get_func_table(void)
++{
++ return NULL;
++}
++
++VCHI_CONNECTION_T *vchi_create_connection(
++ const VCHI_CONNECTION_API_T *function_table,
++ const VCHI_MESSAGE_DRIVER_T *low_level)
++{
++ (void)function_table;
++ (void)low_level;
++ return NULL;
++}
++
++/***********************************************************
++ * Name: vchi_msg_peek
++ *
++ * Arguments: const VCHI_SERVICE_HANDLE_T handle,
++ * void **data,
++ * uint32_t *msg_size,
++
++
++ * VCHI_FLAGS_T flags
++ *
++ * Description: Routine to return a pointer to the current message (to allow in
++ * place processing). The message can be removed using
++ * vchi_msg_remove when you're finished
++ *
++ * Returns: int32_t - success == 0
++ *
++ ***********************************************************/
++int32_t vchi_msg_peek(VCHI_SERVICE_HANDLE_T handle,
++ void **data,
++ uint32_t *msg_size,
++ VCHI_FLAGS_T flags)
++{
++ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
++ VCHIQ_HEADER_T *header;
++
++ WARN_ON((flags != VCHI_FLAGS_NONE) &&
++ (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
++
++ if (flags == VCHI_FLAGS_NONE)
++ if (vchiu_queue_is_empty(&service->queue))
++ return -1;
++
++ header = vchiu_queue_peek(&service->queue);
++
++ *data = header->data;
++ *msg_size = header->size;
++
++ return 0;
++}
++EXPORT_SYMBOL(vchi_msg_peek);
++
++/***********************************************************
++ * Name: vchi_msg_remove
++ *
++ * Arguments: const VCHI_SERVICE_HANDLE_T handle,
++ *
++ * Description: Routine to remove a message (after it has been read with
++ * vchi_msg_peek)
++ *
++ * Returns: int32_t - success == 0
++ *
++ ***********************************************************/
++int32_t vchi_msg_remove(VCHI_SERVICE_HANDLE_T handle)
++{
++ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
++ VCHIQ_HEADER_T *header;
++
++ header = vchiu_queue_pop(&service->queue);
++
++ vchiq_release_message(service->handle, header);
++
++ return 0;
++}
++EXPORT_SYMBOL(vchi_msg_remove);
++
++/***********************************************************
++ * Name: vchi_msg_queue
++ *
++ * Arguments: VCHI_SERVICE_HANDLE_T handle,
++ * const void *data,
++ * uint32_t data_size,
++ * VCHI_FLAGS_T flags,
++ * void *msg_handle,
++ *
++ * Description: Thin wrapper to queue a message onto a connection
++ *
++ * Returns: int32_t - success == 0
++ *
++ ***********************************************************/
++int32_t vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
++ const void *data,
++ uint32_t data_size,
++ VCHI_FLAGS_T flags,
++ void *msg_handle)
++{
++ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
++ VCHIQ_ELEMENT_T element = {data, data_size};
++ VCHIQ_STATUS_T status;
++
++ (void)msg_handle;
++
++ WARN_ON(flags != VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
++
++ status = vchiq_queue_message(service->handle, &element, 1);
++
++ /* vchiq_queue_message() may return VCHIQ_RETRY, so we need to
++ ** implement a retry mechanism since this function is supposed
++ ** to block until queued
++ */
++ while (status == VCHIQ_RETRY) {
++ msleep(1);
++ status = vchiq_queue_message(service->handle, &element, 1);
++ }
++
++ return vchiq_status_to_vchi(status);
++}
++EXPORT_SYMBOL(vchi_msg_queue);
++
++/***********************************************************
++ * Name: vchi_bulk_queue_receive
++ *
++ * Arguments: VCHI_BULK_HANDLE_T handle,
++ * void *data_dst,
++ * const uint32_t data_size,
++ * VCHI_FLAGS_T flags
++ * void *bulk_handle
++ *
++ * Description: Routine to setup a rcv buffer
++ *
++ * Returns: int32_t - success == 0
++ *
++ ***********************************************************/
++int32_t vchi_bulk_queue_receive(VCHI_SERVICE_HANDLE_T handle,
++ void *data_dst,
++ uint32_t data_size,
++ VCHI_FLAGS_T flags,
++ void *bulk_handle)
++{
++ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
++ VCHIQ_BULK_MODE_T mode;
++ VCHIQ_STATUS_T status;
++
++ switch ((int)flags) {
++ case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE
++ | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
++ WARN_ON(!service->callback);
++ mode = VCHIQ_BULK_MODE_CALLBACK;
++ break;
++ case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
++ mode = VCHIQ_BULK_MODE_BLOCKING;
++ break;
++ case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
++ case VCHI_FLAGS_NONE:
++ mode = VCHIQ_BULK_MODE_NOCALLBACK;
++ break;
++ default:
++ WARN(1, "unsupported message\n");
++ return vchiq_status_to_vchi(VCHIQ_ERROR);
++ }
++
++ status = vchiq_bulk_receive(service->handle, data_dst, data_size,
++ bulk_handle, mode);
++
++ /* vchiq_bulk_receive() may return VCHIQ_RETRY, so we need to
++ ** implement a retry mechanism since this function is supposed
++ ** to block until queued
++ */
++ while (status == VCHIQ_RETRY) {
++ msleep(1);
++ status = vchiq_bulk_receive(service->handle, data_dst,
++ data_size, bulk_handle, mode);
++ }
++
++ return vchiq_status_to_vchi(status);
++}
++EXPORT_SYMBOL(vchi_bulk_queue_receive);
++
++/***********************************************************
++ * Name: vchi_bulk_queue_transmit
++ *
++ * Arguments: VCHI_BULK_HANDLE_T handle,
++ * const void *data_src,
++ * uint32_t data_size,
++ * VCHI_FLAGS_T flags,
++ * void *bulk_handle
++ *
++ * Description: Routine to transmit some data
++ *
++ * Returns: int32_t - success == 0
++ *
++ ***********************************************************/
++int32_t vchi_bulk_queue_transmit(VCHI_SERVICE_HANDLE_T handle,
++ const void *data_src,
++ uint32_t data_size,
++ VCHI_FLAGS_T flags,
++ void *bulk_handle)
++{
++ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
++ VCHIQ_BULK_MODE_T mode;
++ VCHIQ_STATUS_T status;
++
++ switch ((int)flags) {
++ case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE
++ | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
++ WARN_ON(!service->callback);
++ mode = VCHIQ_BULK_MODE_CALLBACK;
++ break;
++ case VCHI_FLAGS_BLOCK_UNTIL_DATA_READ:
++ case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
++ mode = VCHIQ_BULK_MODE_BLOCKING;
++ break;
++ case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
++ case VCHI_FLAGS_NONE:
++ mode = VCHIQ_BULK_MODE_NOCALLBACK;
++ break;
++ default:
++ WARN(1, "unsupported message\n");
++ return vchiq_status_to_vchi(VCHIQ_ERROR);
++ }
++
++ status = vchiq_bulk_transmit(service->handle, data_src, data_size,
++ bulk_handle, mode);
++
++ /* vchiq_bulk_transmit() may return VCHIQ_RETRY, so we need to
++ ** implement a retry mechanism since this function is supposed
++ ** to block until queued
++ */
++ while (status == VCHIQ_RETRY) {
++ msleep(1);
++ status = vchiq_bulk_transmit(service->handle, data_src,
++ data_size, bulk_handle, mode);
++ }
++
++ return vchiq_status_to_vchi(status);
++}
++EXPORT_SYMBOL(vchi_bulk_queue_transmit);
++
++/***********************************************************
++ * Name: vchi_msg_dequeue
++ *
++ * Arguments: VCHI_SERVICE_HANDLE_T handle,
++ * void *data,
++ * uint32_t max_data_size_to_read,
++ * uint32_t *actual_msg_size
++ * VCHI_FLAGS_T flags
++ *
++ * Description: Routine to dequeue a message into the supplied buffer
++ *
++ * Returns: int32_t - success == 0
++ *
++ ***********************************************************/
++int32_t vchi_msg_dequeue(VCHI_SERVICE_HANDLE_T handle,
++ void *data,
++ uint32_t max_data_size_to_read,
++ uint32_t *actual_msg_size,
++ VCHI_FLAGS_T flags)
++{
++ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
++ VCHIQ_HEADER_T *header;
++
++ WARN_ON((flags != VCHI_FLAGS_NONE) &&
++ (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
++
++ if (flags == VCHI_FLAGS_NONE)
++ if (vchiu_queue_is_empty(&service->queue))
++ return -1;
++
++ header = vchiu_queue_pop(&service->queue);
++
++ memcpy(data, header->data, header->size < max_data_size_to_read ?
++ header->size : max_data_size_to_read);
++
++ *actual_msg_size = header->size;
++
++ vchiq_release_message(service->handle, header);
++
++ return 0;
++}
++EXPORT_SYMBOL(vchi_msg_dequeue);
++
++/***********************************************************
++ * Name: vchi_msg_queuev
++ *
++ * Arguments: VCHI_SERVICE_HANDLE_T handle,
++ * VCHI_MSG_VECTOR_T *vector,
++ * uint32_t count,
++ * VCHI_FLAGS_T flags,
++ * void *msg_handle
++ *
++ * Description: Thin wrapper to queue a message onto a connection
++ *
++ * Returns: int32_t - success == 0
++ *
++ ***********************************************************/
++
++vchiq_static_assert(sizeof(VCHI_MSG_VECTOR_T) == sizeof(VCHIQ_ELEMENT_T));
++vchiq_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_base) ==
++ offsetof(VCHIQ_ELEMENT_T, data));
++vchiq_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_len) ==
++ offsetof(VCHIQ_ELEMENT_T, size));
++
++int32_t vchi_msg_queuev(VCHI_SERVICE_HANDLE_T handle,
++ VCHI_MSG_VECTOR_T *vector,
++ uint32_t count,
++ VCHI_FLAGS_T flags,
++ void *msg_handle)
++{
++ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
++
++ (void)msg_handle;
++
++ WARN_ON(flags != VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
++
++ return vchiq_status_to_vchi(vchiq_queue_message(service->handle,
++ (const VCHIQ_ELEMENT_T *)vector, count));
++}
++EXPORT_SYMBOL(vchi_msg_queuev);
++
++/***********************************************************
++ * Name: vchi_held_msg_release
++ *
++ * Arguments: VCHI_HELD_MSG_T *message
++ *
++ * Description: Routine to release a held message (after it has been read with
++ * vchi_msg_hold)
++ *
++ * Returns: int32_t - success == 0
++ *
++ ***********************************************************/
++int32_t vchi_held_msg_release(VCHI_HELD_MSG_T *message)
++{
++ vchiq_release_message((VCHIQ_SERVICE_HANDLE_T)message->service,
++ (VCHIQ_HEADER_T *)message->message);
++
++ return 0;
++}
++EXPORT_SYMBOL(vchi_held_msg_release);
++
++/***********************************************************
++ * Name: vchi_msg_hold
++ *
++ * Arguments: VCHI_SERVICE_HANDLE_T handle,
++ * void **data,
++ * uint32_t *msg_size,
++ * VCHI_FLAGS_T flags,
++ * VCHI_HELD_MSG_T *message_handle
++ *
++ * Description: Routine to return a pointer to the current message (to allow
++ * in place processing). The message is dequeued - don't forget
++ * to release the message using vchi_held_msg_release when you're
++ * finished.
++ *
++ * Returns: int32_t - success == 0
++ *
++ ***********************************************************/
++int32_t vchi_msg_hold(VCHI_SERVICE_HANDLE_T handle,
++ void **data,
++ uint32_t *msg_size,
++ VCHI_FLAGS_T flags,
++ VCHI_HELD_MSG_T *message_handle)
++{
++ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
++ VCHIQ_HEADER_T *header;
++
++ WARN_ON((flags != VCHI_FLAGS_NONE) &&
++ (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
++
++ if (flags == VCHI_FLAGS_NONE)
++ if (vchiu_queue_is_empty(&service->queue))
++ return -1;
++
++ header = vchiu_queue_pop(&service->queue);
++
++ *data = header->data;
++ *msg_size = header->size;
++
++ message_handle->service =
++ (struct opaque_vchi_service_t *)service->handle;
++ message_handle->message = header;
++
++ return 0;
++}
++EXPORT_SYMBOL(vchi_msg_hold);
++
++/***********************************************************
++ * Name: vchi_initialise
++ *
++ * Arguments: VCHI_INSTANCE_T *instance_handle
++ *
++ * Description: Initialises the hardware but does not transmit anything
++ * When run as a Host App this will be called twice hence the need
++ * to malloc the state information
++ *
++ * Returns: 0 if successful, failure otherwise
++ *
++ ***********************************************************/
++
++int32_t vchi_initialise(VCHI_INSTANCE_T *instance_handle)
++{
++ VCHIQ_INSTANCE_T instance;
++ VCHIQ_STATUS_T status;
++
++ status = vchiq_initialise(&instance);
++
++ *instance_handle = (VCHI_INSTANCE_T)instance;
++
++ return vchiq_status_to_vchi(status);
++}
++EXPORT_SYMBOL(vchi_initialise);
++
++/***********************************************************
++ * Name: vchi_connect
++ *
++ * Arguments: VCHI_CONNECTION_T **connections
++ * const uint32_t num_connections
++ * VCHI_INSTANCE_T instance_handle)
++ *
++ * Description: Starts the command service on each connection,
++ * causing INIT messages to be pinged back and forth
++ *
++ * Returns: 0 if successful, failure otherwise
++ *
++ ***********************************************************/
++int32_t vchi_connect(VCHI_CONNECTION_T **connections,
++ const uint32_t num_connections,
++ VCHI_INSTANCE_T instance_handle)
++{
++ VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
++
++ (void)connections;
++ (void)num_connections;
++
++ return vchiq_connect(instance);
++}
++EXPORT_SYMBOL(vchi_connect);
++
++
++/***********************************************************
++ * Name: vchi_disconnect
++ *
++ * Arguments: VCHI_INSTANCE_T instance_handle
++ *
++ * Description: Stops the command service on each connection,
++ * causing DE-INIT messages to be pinged back and forth
++ *
++ * Returns: 0 if successful, failure otherwise
++ *
++ ***********************************************************/
++int32_t vchi_disconnect(VCHI_INSTANCE_T instance_handle)
++{
++ VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
++ return vchiq_status_to_vchi(vchiq_shutdown(instance));
++}
++EXPORT_SYMBOL(vchi_disconnect);
++
++
++/***********************************************************
++ * Name: vchi_service_open
++ * Name: vchi_service_create
++ *
++ * Arguments: VCHI_INSTANCE_T *instance_handle
++ * SERVICE_CREATION_T *setup,
++ * VCHI_SERVICE_HANDLE_T *handle
++ *
++ * Description: Routine to open a service
++ *
++ * Returns: int32_t - success == 0
++ *
++ ***********************************************************/
++
++static VCHIQ_STATUS_T shim_callback(VCHIQ_REASON_T reason,
++ VCHIQ_HEADER_T *header, VCHIQ_SERVICE_HANDLE_T handle, void *bulk_user)
++{
++ SHIM_SERVICE_T *service =
++ (SHIM_SERVICE_T *)VCHIQ_GET_SERVICE_USERDATA(handle);
++
++ if (!service->callback)
++ goto release;
++
++ switch (reason) {
++ case VCHIQ_MESSAGE_AVAILABLE:
++ vchiu_queue_push(&service->queue, header);
++
++ service->callback(service->callback_param,
++ VCHI_CALLBACK_MSG_AVAILABLE, NULL);
++
++ goto done;
++ break;
++
++ case VCHIQ_BULK_TRANSMIT_DONE:
++ service->callback(service->callback_param,
++ VCHI_CALLBACK_BULK_SENT, bulk_user);
++ break;
++
++ case VCHIQ_BULK_RECEIVE_DONE:
++ service->callback(service->callback_param,
++ VCHI_CALLBACK_BULK_RECEIVED, bulk_user);
++ break;
++
++ case VCHIQ_SERVICE_CLOSED:
++ service->callback(service->callback_param,
++ VCHI_CALLBACK_SERVICE_CLOSED, NULL);
++ break;
++
++ case VCHIQ_SERVICE_OPENED:
++ /* No equivalent VCHI reason */
++ break;
++
++ case VCHIQ_BULK_TRANSMIT_ABORTED:
++ service->callback(service->callback_param,
++ VCHI_CALLBACK_BULK_TRANSMIT_ABORTED,
++ bulk_user);
++ break;
++
++ case VCHIQ_BULK_RECEIVE_ABORTED:
++ service->callback(service->callback_param,
++ VCHI_CALLBACK_BULK_RECEIVE_ABORTED,
++ bulk_user);
++ break;
++
++ default:
++ WARN(1, "not supported\n");
++ break;
++ }
++
++release:
++ vchiq_release_message(service->handle, header);
++done:
++ return VCHIQ_SUCCESS;
++}
++
++static SHIM_SERVICE_T *service_alloc(VCHIQ_INSTANCE_T instance,
++ SERVICE_CREATION_T *setup)
++{
++ SHIM_SERVICE_T *service = kzalloc(sizeof(SHIM_SERVICE_T), GFP_KERNEL);
++
++ (void)instance;
++
++ if (service) {
++ if (vchiu_queue_init(&service->queue, 64)) {
++ service->callback = setup->callback;
++ service->callback_param = setup->callback_param;
++ } else {
++ kfree(service);
++ service = NULL;
++ }
++ }
++
++ return service;
++}
++
++static void service_free(SHIM_SERVICE_T *service)
++{
++ if (service) {
++ vchiu_queue_delete(&service->queue);
++ kfree(service);
++ }
++}
++
++int32_t vchi_service_open(VCHI_INSTANCE_T instance_handle,
++ SERVICE_CREATION_T *setup,
++ VCHI_SERVICE_HANDLE_T *handle)
++{
++ VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
++ SHIM_SERVICE_T *service = service_alloc(instance, setup);
++
++ *handle = (VCHI_SERVICE_HANDLE_T)service;
++
++ if (service) {
++ VCHIQ_SERVICE_PARAMS_T params;
++ VCHIQ_STATUS_T status;
++
++ memset(&params, 0, sizeof(params));
++ params.fourcc = setup->service_id;
++ params.callback = shim_callback;
++ params.userdata = service;
++ params.version = setup->version.version;
++ params.version_min = setup->version.version_min;
++
++ status = vchiq_open_service(instance, &params,
++ &service->handle);
++ if (status != VCHIQ_SUCCESS) {
++ service_free(service);
++ service = NULL;
++ *handle = NULL;
++ }
++ }
++
++ return (service != NULL) ? 0 : -1;
++}
++EXPORT_SYMBOL(vchi_service_open);
++
++int32_t vchi_service_create(VCHI_INSTANCE_T instance_handle,
++ SERVICE_CREATION_T *setup,
++ VCHI_SERVICE_HANDLE_T *handle)
++{
++ VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
++ SHIM_SERVICE_T *service = service_alloc(instance, setup);
++
++ *handle = (VCHI_SERVICE_HANDLE_T)service;
++
++ if (service) {
++ VCHIQ_SERVICE_PARAMS_T params;
++ VCHIQ_STATUS_T status;
++
++ memset(&params, 0, sizeof(params));
++ params.fourcc = setup->service_id;
++ params.callback = shim_callback;
++ params.userdata = service;
++ params.version = setup->version.version;
++ params.version_min = setup->version.version_min;
++ status = vchiq_add_service(instance, &params, &service->handle);
++
++ if (status != VCHIQ_SUCCESS) {
++ service_free(service);
++ service = NULL;
++ *handle = NULL;
++ }
++ }
++
++ return (service != NULL) ? 0 : -1;
++}
++EXPORT_SYMBOL(vchi_service_create);
++
++int32_t vchi_service_close(const VCHI_SERVICE_HANDLE_T handle)
++{
++ int32_t ret = -1;
++ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
++ if (service) {
++ VCHIQ_STATUS_T status = vchiq_close_service(service->handle);
++ if (status == VCHIQ_SUCCESS) {
++ service_free(service);
++ service = NULL;
++ }
++
++ ret = vchiq_status_to_vchi(status);
++ }
++ return ret;
++}
++EXPORT_SYMBOL(vchi_service_close);
++
++int32_t vchi_service_destroy(const VCHI_SERVICE_HANDLE_T handle)
++{
++ int32_t ret = -1;
++ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
++ if (service) {
++ VCHIQ_STATUS_T status = vchiq_remove_service(service->handle);
++ if (status == VCHIQ_SUCCESS) {
++ service_free(service);
++ service = NULL;
++ }
++
++ ret = vchiq_status_to_vchi(status);
++ }
++ return ret;
++}
++EXPORT_SYMBOL(vchi_service_destroy);
++
++int32_t vchi_service_set_option(const VCHI_SERVICE_HANDLE_T handle,
++ VCHI_SERVICE_OPTION_T option,
++ int value)
++{
++ int32_t ret = -1;
++ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
++ VCHIQ_SERVICE_OPTION_T vchiq_option;
++ switch (option) {
++ case VCHI_SERVICE_OPTION_TRACE:
++ vchiq_option = VCHIQ_SERVICE_OPTION_TRACE;
++ break;
++ case VCHI_SERVICE_OPTION_SYNCHRONOUS:
++ vchiq_option = VCHIQ_SERVICE_OPTION_SYNCHRONOUS;
++ break;
++ default:
++ service = NULL;
++ break;
++ }
++ if (service) {
++ VCHIQ_STATUS_T status =
++ vchiq_set_service_option(service->handle,
++ vchiq_option,
++ value);
++
++ ret = vchiq_status_to_vchi(status);
++ }
++ return ret;
++}
++EXPORT_SYMBOL(vchi_service_set_option);
++
++int32_t vchi_get_peer_version( const VCHI_SERVICE_HANDLE_T handle, short *peer_version )
++{
++ int32_t ret = -1;
++ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
++ if(service)
++ {
++ VCHIQ_STATUS_T status = vchiq_get_peer_version(service->handle, peer_version);
++ ret = vchiq_status_to_vchi( status );
++ }
++ return ret;
++}
++EXPORT_SYMBOL(vchi_get_peer_version);
++
++/* ----------------------------------------------------------------------
++ * read a uint32_t from buffer.
++ * network format is defined to be little endian
++ * -------------------------------------------------------------------- */
++uint32_t
++vchi_readbuf_uint32(const void *_ptr)
++{
++ const unsigned char *ptr = _ptr;
++ return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
++}
++
++/* ----------------------------------------------------------------------
++ * write a uint32_t to buffer.
++ * network format is defined to be little endian
++ * -------------------------------------------------------------------- */
++void
++vchi_writebuf_uint32(void *_ptr, uint32_t value)
++{
++ unsigned char *ptr = _ptr;
++ ptr[0] = (unsigned char)((value >> 0) & 0xFF);
++ ptr[1] = (unsigned char)((value >> 8) & 0xFF);
++ ptr[2] = (unsigned char)((value >> 16) & 0xFF);
++ ptr[3] = (unsigned char)((value >> 24) & 0xFF);
++}
++
++/* ----------------------------------------------------------------------
++ * read a uint16_t from buffer.
++ * network format is defined to be little endian
++ * -------------------------------------------------------------------- */
++uint16_t
++vchi_readbuf_uint16(const void *_ptr)
++{
++ const unsigned char *ptr = _ptr;
++ return ptr[0] | (ptr[1] << 8);
++}
++
++/* ----------------------------------------------------------------------
++ * write a uint16_t into the buffer.
++ * network format is defined to be little endian
++ * -------------------------------------------------------------------- */
++void
++vchi_writebuf_uint16(void *_ptr, uint16_t value)
++{
++ unsigned char *ptr = _ptr;
++ ptr[0] = (value >> 0) & 0xFF;
++ ptr[1] = (value >> 8) & 0xFF;
++}
++
++/***********************************************************
++ * Name: vchi_service_use
++ *
++ * Arguments: const VCHI_SERVICE_HANDLE_T handle
++ *
++ * Description: Routine to increment refcount on a service
++ *
++ * Returns: void
++ *
++ ***********************************************************/
++int32_t vchi_service_use(const VCHI_SERVICE_HANDLE_T handle)
++{
++ int32_t ret = -1;
++ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
++ if (service)
++ ret = vchiq_status_to_vchi(vchiq_use_service(service->handle));
++ return ret;
++}
++EXPORT_SYMBOL(vchi_service_use);
++
++/***********************************************************
++ * Name: vchi_service_release
++ *
++ * Arguments: const VCHI_SERVICE_HANDLE_T handle
++ *
++ * Description: Routine to decrement refcount on a service
++ *
++ * Returns: void
++ *
++ ***********************************************************/
++int32_t vchi_service_release(const VCHI_SERVICE_HANDLE_T handle)
++{
++ int32_t ret = -1;
++ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
++ if (service)
++ ret = vchiq_status_to_vchi(
++ vchiq_release_service(service->handle));
++ return ret;
++}
++EXPORT_SYMBOL(vchi_service_release);
+--- /dev/null
++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.c
+@@ -0,0 +1,156 @@
++/**
++ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "vchiq_util.h"
++#include "vchiq_killable.h"
++
++static inline int is_pow2(int i)
++{
++ return i && !(i & (i - 1));
++}
++
++int vchiu_queue_init(VCHIU_QUEUE_T *queue, int size)
++{
++ WARN_ON(!is_pow2(size));
++
++ queue->size = size;
++ queue->read = 0;
++ queue->write = 0;
++ queue->initialized = 1;
++
++ sema_init(&queue->pop, 0);
++ sema_init(&queue->push, 0);
++
++ queue->storage = kzalloc(size * sizeof(VCHIQ_HEADER_T *), GFP_KERNEL);
++ if (queue->storage == NULL) {
++ vchiu_queue_delete(queue);
++ return 0;
++ }
++ return 1;
++}
++
++void vchiu_queue_delete(VCHIU_QUEUE_T *queue)
++{
++ if (queue->storage != NULL)
++ kfree(queue->storage);
++}
++
++int vchiu_queue_is_empty(VCHIU_QUEUE_T *queue)
++{
++ return queue->read == queue->write;
++}
++
++int vchiu_queue_is_full(VCHIU_QUEUE_T *queue)
++{
++ return queue->write == queue->read + queue->size;
++}
++
++void vchiu_queue_push(VCHIU_QUEUE_T *queue, VCHIQ_HEADER_T *header)
++{
++ if (!queue->initialized)
++ return;
++
++ while (queue->write == queue->read + queue->size) {
++ if (down_interruptible(&queue->pop) != 0) {
++ flush_signals(current);
++ }
++ }
++
++ /*
++ * Write to queue->storage must be visible after read from
++ * queue->read
++ */
++ smp_mb();
++
++ queue->storage[queue->write & (queue->size - 1)] = header;
++
++ /*
++ * Write to queue->storage must be visible before write to
++ * queue->write
++ */
++ smp_wmb();
++
++ queue->write++;
++
++ up(&queue->push);
++}
++
++VCHIQ_HEADER_T *vchiu_queue_peek(VCHIU_QUEUE_T *queue)
++{
++ while (queue->write == queue->read) {
++ if (down_interruptible(&queue->push) != 0) {
++ flush_signals(current);
++ }
++ }
++
++ up(&queue->push); // We haven't removed anything from the queue.
++
++ /*
++ * Read from queue->storage must be visible after read from
++ * queue->write
++ */
++ smp_rmb();
++
++ return queue->storage[queue->read & (queue->size - 1)];
++}
++
++VCHIQ_HEADER_T *vchiu_queue_pop(VCHIU_QUEUE_T *queue)
++{
++ VCHIQ_HEADER_T *header;
++
++ while (queue->write == queue->read) {
++ if (down_interruptible(&queue->push) != 0) {
++ flush_signals(current);
++ }
++ }
++
++ /*
++ * Read from queue->storage must be visible after read from
++ * queue->write
++ */
++ smp_rmb();
++
++ header = queue->storage[queue->read & (queue->size - 1)];
++
++ /*
++ * Read from queue->storage must be visible before write to
++ * queue->read
++ */
++ smp_mb();
++
++ queue->read++;
++
++ up(&queue->pop);
++
++ return header;
++}
+--- /dev/null
++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.h
+@@ -0,0 +1,82 @@
++/**
++ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef VCHIQ_UTIL_H
++#define VCHIQ_UTIL_H
++
++#include <linux/types.h>
++#include <linux/semaphore.h>
++#include <linux/mutex.h>
++#include <linux/bitops.h>
++#include <linux/kthread.h>
++#include <linux/wait.h>
++#include <linux/vmalloc.h>
++#include <linux/jiffies.h>
++#include <linux/delay.h>
++#include <linux/string.h>
++#include <linux/types.h>
++#include <linux/interrupt.h>
++#include <linux/random.h>
++#include <linux/sched.h>
++#include <linux/ctype.h>
++#include <linux/uaccess.h>
++#include <linux/time.h> /* for time_t */
++#include <linux/slab.h>
++#include <linux/vmalloc.h>
++
++#include "vchiq_if.h"
++
++typedef struct {
++ int size;
++ int read;
++ int write;
++ int initialized;
++
++ struct semaphore pop;
++ struct semaphore push;
++
++ VCHIQ_HEADER_T **storage;
++} VCHIU_QUEUE_T;
++
++extern int vchiu_queue_init(VCHIU_QUEUE_T *queue, int size);
++extern void vchiu_queue_delete(VCHIU_QUEUE_T *queue);
++
++extern int vchiu_queue_is_empty(VCHIU_QUEUE_T *queue);
++extern int vchiu_queue_is_full(VCHIU_QUEUE_T *queue);
++
++extern void vchiu_queue_push(VCHIU_QUEUE_T *queue, VCHIQ_HEADER_T *header);
++
++extern VCHIQ_HEADER_T *vchiu_queue_peek(VCHIU_QUEUE_T *queue);
++extern VCHIQ_HEADER_T *vchiu_queue_pop(VCHIU_QUEUE_T *queue);
++
++#endif
+--- /dev/null
++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_version.c
+@@ -0,0 +1,59 @@
++/**
++ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++#include "vchiq_build_info.h"
++#include <linux/broadcom/vc_debug_sym.h>
++
++VC_DEBUG_DECLARE_STRING_VAR( vchiq_build_hostname, "dc4-arm-01" );
++VC_DEBUG_DECLARE_STRING_VAR( vchiq_build_version, "9245b4c35b99b3870e1f7dc598c5692b3c66a6f0 (tainted)" );
++VC_DEBUG_DECLARE_STRING_VAR( vchiq_build_time, __TIME__ );
++VC_DEBUG_DECLARE_STRING_VAR( vchiq_build_date, __DATE__ );
++
++const char *vchiq_get_build_hostname( void )
++{
++ return vchiq_build_hostname;
++}
++
++const char *vchiq_get_build_version( void )
++{
++ return vchiq_build_version;
++}
++
++const char *vchiq_get_build_date( void )
++{
++ return vchiq_build_date;
++}
++
++const char *vchiq_get_build_time( void )
++{
++ return vchiq_build_time;
++}
diff --git a/target/linux/brcm2708/patches-4.4/0037-bcm2708-vchiq-driver.patch b/target/linux/brcm2708/patches-4.4/0037-bcm2708-vchiq-driver.patch
deleted file mode 100644
index 61e99d4bc9..0000000000
--- a/target/linux/brcm2708/patches-4.4/0037-bcm2708-vchiq-driver.patch
+++ /dev/null
@@ -1,13200 +0,0 @@
-From 20c0f57db9cca65943519bd404b3e346958f4544 Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Tue, 2 Jul 2013 23:42:01 +0100
-Subject: [PATCH 037/170] bcm2708 vchiq driver
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: popcornmix <popcornmix@gmail.com>
-
-vchiq: create_pagelist copes with vmalloc memory
-
-Signed-off-by: Daniel Stone <daniels@collabora.com>
-
-vchiq: fix the shim message release
-
-Signed-off-by: Daniel Stone <daniels@collabora.com>
-
-vchiq: export additional symbols
-
-Signed-off-by: Daniel Stone <daniels@collabora.com>
-
-VCHIQ: Make service closure fully synchronous (drv)
-
-This is one half of a two-part patch, the other half of which is to
-the vchiq_lib user library. With these patches, calls to
-vchiq_close_service and vchiq_remove_service won't return until any
-associated callbacks have been delivered to the callback thread.
-
-VCHIQ: Add per-service tracing
-
-The new service option VCHIQ_SERVICE_OPTION_TRACE is a boolean that
-toggles tracing for the specified service.
-
-This commit also introduces vchi_service_set_option and the associated
-option VCHI_SERVICE_OPTION_TRACE.
-
-vchiq: Make the synchronous-CLOSE logic more tolerant
-
-vchiq: Move logging control into debugfs
-
-vchiq: Take care of a corner case tickled by VCSM
-
-Closing a connection that isn't fully open requires care, since one
-side does not know the other side's port number. Code was present to
-handle the case where a CLOSE is sent immediately after an OPEN, i.e.
-before the OPENACK has been received, but this was incorrectly being
-used when an OPEN from a client using port 0 was rejected.
-
-(In the observed failure, the host was attempting to use the VCSM
-service, which isn't present in the 'cutdown' firmware. The failure
-was intermittent because sometimes the keepalive service would
-grab port 0.)
-
-This case can be distinguished because the client's remoteport will
-still be VCHIQ_PORT_FREE, and the srvstate will be OPENING. Either
-condition is sufficient to differentiate it from the special case
-described above.
-
-vchiq: Avoid high load when blocked and unkillable
-
-vchiq: Include SIGSTOP and SIGCONT in list of signals not-masked by vchiq to allow gdb to work
-
-vchiq_arm: Complete support for SYNCHRONOUS mode
-
-vchiq: Remove inline from suspend/resume
-
-vchiq: Allocation does not need to be atomic
-
-vchiq: Fix wrong condition check
-
-The log level is checked from within the log call. Remove the check in the call.
-
-Signed-off-by: Pranith Kumar <bobby.prani@gmail.com>
-
-BCM270x: Add vchiq device to platform file and Device Tree
-
-Prepare to turn the vchiq module into a driver.
-
-Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
-
-bcm2708: vchiq: Add Device Tree support
-
-Turn vchiq into a driver and stop hardcoding resources.
-Use devm_* functions in probe path to simplify cleanup.
-A global variable is used to hold the register address. This is done
-to keep this patch as small as possible.
-Also make available on ARCH_BCM2835.
-Based on work by Lubomir Rintel.
-
-Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
-
-vchiq: Change logging level for inbound data
-
-vchiq_arm: Two cacheing fixes
-
-1) Make fragment size vary with cache line size
-Without this patch, non-cache-line-aligned transfers may corrupt
-(or be corrupted by) adjacent data structures.
-
-Both ARM and VC need to be updated to enable this feature. This is
-ensured by having the loader apply a new DT parameter -
-cache-line-size. The existence of this parameter guarantees that the
-kernel is capable, and the parameter will only be modified from the
-safe default if the loader is capable.
-
-2) Flush/invalidate vmalloc'd memory, and invalidate after reads
-
-vchiq: fix NULL pointer dereference when closing driver
-
-The following code run as root will cause a null pointer dereference oops:
-
- int fd = open("/dev/vc-cma", O_RDONLY);
- if (fd < 0)
- err(1, "open failed");
- (void)close(fd);
-
-[ 1704.877721] Unable to handle kernel NULL pointer dereference at virtual address 00000000
-[ 1704.877725] pgd = b899c000
-[ 1704.877736] [00000000] *pgd=37fab831, *pte=00000000, *ppte=00000000
-[ 1704.877748] Internal error: Oops: 817 [#1] PREEMPT SMP ARM
-[ 1704.877765] Modules linked in: evdev i2c_bcm2708 uio_pdrv_genirq uio
-[ 1704.877774] CPU: 2 PID: 3656 Comm: stress-ng-fstat Not tainted 3.19.1-12-generic-bcm2709 #12-Ubuntu
-[ 1704.877777] Hardware name: BCM2709
-[ 1704.877783] task: b8ab9b00 ti: b7e68000 task.ti: b7e68000
-[ 1704.877798] PC is at __down_interruptible+0x50/0xec
-[ 1704.877806] LR is at down_interruptible+0x5c/0x68
-[ 1704.877813] pc : [<80630ee8>] lr : [<800704b0>] psr: 60080093
-sp : b7e69e50 ip : b7e69e88 fp : b7e69e84
-[ 1704.877817] r10: b88123c8 r9 : 00000010 r8 : 00000001
-[ 1704.877822] r7 : b8ab9b00 r6 : 7fffffff r5 : 80a1cc34 r4 : 80a1cc34
-[ 1704.877826] r3 : b7e69e50 r2 : 00000000 r1 : 00000000 r0 : 80a1cc34
-[ 1704.877833] Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment user
-[ 1704.877838] Control: 10c5387d Table: 3899c06a DAC: 00000015
-[ 1704.877843] Process do-oops (pid: 3656, stack limit = 0xb7e68238)
-[ 1704.877848] Stack: (0xb7e69e50 to 0xb7e6a000)
-[ 1704.877856] 9e40: 80a1cc3c 00000000 00000010 b88123c8
-[ 1704.877865] 9e60: b7e69e84 80a1cc34 fff9fee9 ffffffff b7e68000 00000009 b7e69ea4 b7e69e88
-[ 1704.877874] 9e80: 800704b0 80630ea4 fff9fee9 60080013 80a1cc28 fff9fee9 b7e69edc b7e69ea8
-[ 1704.877884] 9ea0: 8040f558 80070460 fff9fee9 ffffffff 00000000 00000000 00000009 80a1cb7c
-[ 1704.877893] 9ec0: 00000000 80a1cb7c 00000000 00000010 b7e69ef4 b7e69ee0 803e1ba4 8040f514
-[ 1704.877902] 9ee0: 00000e48 80a1cb7c b7e69f14 b7e69ef8 803e1c9c 803e1b74 b88123c0 b92acb18
-[ 1704.877911] 9f00: b8812790 b8d815d8 b7e69f24 b7e69f18 803e2250 803e1bc8 b7e69f5c b7e69f28
-[ 1704.877921] 9f20: 80167bac 803e222c 00000000 00000000 b7e69f54 b8ab9ffc 00000000 8098c794
-[ 1704.877930] 9f40: b8ab9b00 8000efc4 b7e68000 00000000 b7e69f6c b7e69f60 80167d6c 80167b28
-[ 1704.877939] 9f60: b7e69f8c b7e69f70 80047d38 80167d60 b7e68000 b7e68010 8000efc4 b7e69fb0
-[ 1704.877949] 9f80: b7e69fac b7e69f90 80012820 80047c84 01155490 011549a8 00000001 00000006
-[ 1704.877957] 9fa0: 00000000 b7e69fb0 8000ee5c 80012790 00000000 353d8c0f 7efc4308 00000000
-[ 1704.877966] 9fc0: 01155490 011549a8 00000001 00000006 00000000 00000000 76cf3ba0 00000003
-[ 1704.877975] 9fe0: 00000000 7efc42e4 0002272f 76e2ed66 60080030 00000003 00000000 00000000
-[ 1704.877998] [<80630ee8>] (__down_interruptible) from [<800704b0>] (down_interruptible+0x5c/0x68)
-[ 1704.878015] [<800704b0>] (down_interruptible) from [<8040f558>] (vchiu_queue_push+0x50/0xd8)
-[ 1704.878032] [<8040f558>] (vchiu_queue_push) from [<803e1ba4>] (send_worker_msg+0x3c/0x54)
-[ 1704.878045] [<803e1ba4>] (send_worker_msg) from [<803e1c9c>] (vc_cma_set_reserve+0xe0/0x1c4)
-[ 1704.878057] [<803e1c9c>] (vc_cma_set_reserve) from [<803e2250>] (vc_cma_release+0x30/0x38)
-[ 1704.878069] [<803e2250>] (vc_cma_release) from [<80167bac>] (__fput+0x90/0x1e0)
-[ 1704.878082] [<80167bac>] (__fput) from [<80167d6c>] (____fput+0x18/0x1c)
-[ 1704.878094] [<80167d6c>] (____fput) from [<80047d38>] (task_work_run+0xc0/0xf8)
-[ 1704.878109] [<80047d38>] (task_work_run) from [<80012820>] (do_work_pending+0x9c/0xc4)
-[ 1704.878123] [<80012820>] (do_work_pending) from [<8000ee5c>] (work_pending+0xc/0x20)
-[ 1704.878133] Code: e50b1034 e3a01000 e50b2030 e580300c (e5823000)
-
-..the fix is to ensure that we have actually initialized the queue before we attempt
-to push any items onto it. This occurs if we do an open() followed by a close() without
-any activity in between.
-
-Signed-off-by: Colin Ian King <colin.king@canonical.com>
-
-vchiq_arm: Sort out the vmalloc case
-
-See: https://github.com/raspberrypi/linux/issues/1055
-
-vchiq: hack: Add include depecated dma include file
----
- arch/arm/mach-bcm2708/include/mach/platform.h | 2 +
- arch/arm/mach-bcm2709/include/mach/platform.h | 2 +
- drivers/misc/Kconfig | 1 +
- drivers/misc/Makefile | 1 +
- drivers/misc/vc04_services/Kconfig | 9 +
- drivers/misc/vc04_services/Makefile | 14 +
- .../interface/vchi/connections/connection.h | 328 ++
- .../interface/vchi/message_drivers/message.h | 204 +
- drivers/misc/vc04_services/interface/vchi/vchi.h | 378 ++
- .../misc/vc04_services/interface/vchi/vchi_cfg.h | 224 ++
- .../interface/vchi/vchi_cfg_internal.h | 71 +
- .../vc04_services/interface/vchi/vchi_common.h | 175 +
- .../misc/vc04_services/interface/vchi/vchi_mh.h | 42 +
- .../misc/vc04_services/interface/vchiq_arm/vchiq.h | 40 +
- .../vc04_services/interface/vchiq_arm/vchiq_2835.h | 42 +
- .../interface/vchiq_arm/vchiq_2835_arm.c | 586 +++
- .../vc04_services/interface/vchiq_arm/vchiq_arm.c | 2903 +++++++++++++++
- .../vc04_services/interface/vchiq_arm/vchiq_arm.h | 220 ++
- .../interface/vchiq_arm/vchiq_build_info.h | 37 +
- .../vc04_services/interface/vchiq_arm/vchiq_cfg.h | 69 +
- .../interface/vchiq_arm/vchiq_connected.c | 120 +
- .../interface/vchiq_arm/vchiq_connected.h | 50 +
- .../vc04_services/interface/vchiq_arm/vchiq_core.c | 3934 ++++++++++++++++++++
- .../vc04_services/interface/vchiq_arm/vchiq_core.h | 712 ++++
- .../interface/vchiq_arm/vchiq_debugfs.c | 383 ++
- .../interface/vchiq_arm/vchiq_debugfs.h | 52 +
- .../interface/vchiq_arm/vchiq_genversion | 87 +
- .../vc04_services/interface/vchiq_arm/vchiq_if.h | 189 +
- .../interface/vchiq_arm/vchiq_ioctl.h | 131 +
- .../interface/vchiq_arm/vchiq_kern_lib.c | 458 +++
- .../interface/vchiq_arm/vchiq_killable.h | 69 +
- .../interface/vchiq_arm/vchiq_memdrv.h | 71 +
- .../interface/vchiq_arm/vchiq_pagelist.h | 58 +
- .../vc04_services/interface/vchiq_arm/vchiq_shim.c | 860 +++++
- .../vc04_services/interface/vchiq_arm/vchiq_util.c | 156 +
- .../vc04_services/interface/vchiq_arm/vchiq_util.h | 82 +
- .../interface/vchiq_arm/vchiq_version.c | 59 +
- 37 files changed, 12819 insertions(+)
- create mode 100644 drivers/misc/vc04_services/Kconfig
- create mode 100644 drivers/misc/vc04_services/Makefile
- create mode 100644 drivers/misc/vc04_services/interface/vchi/connections/connection.h
- create mode 100644 drivers/misc/vc04_services/interface/vchi/message_drivers/message.h
- create mode 100644 drivers/misc/vc04_services/interface/vchi/vchi.h
- create mode 100644 drivers/misc/vc04_services/interface/vchi/vchi_cfg.h
- create mode 100644 drivers/misc/vc04_services/interface/vchi/vchi_cfg_internal.h
- create mode 100644 drivers/misc/vc04_services/interface/vchi/vchi_common.h
- create mode 100644 drivers/misc/vc04_services/interface/vchi/vchi_mh.h
- create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq.h
- create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835.h
- create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
- create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c
- create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.h
- create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_build_info.h
- create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_cfg.h
- create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.c
- create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.h
- create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c
- create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.h
- create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
- create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_debugfs.h
- create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_genversion
- create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_if.h
- create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_ioctl.h
- create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
- create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_killable.h
- create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_memdrv.h
- create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_pagelist.h
- create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c
- create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.c
- create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.h
- create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_version.c
-
---- a/arch/arm/mach-bcm2708/include/mach/platform.h
-+++ b/arch/arm/mach-bcm2708/include/mach/platform.h
-@@ -78,6 +78,8 @@
- #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 */
-+#define ARMCTRL_0_BELL_BASE (ARMCTRL_0_SBM_BASE + 0x40) /* User 0 (ARM)'s Doorbell */
-+#define ARMCTRL_0_MAIL0_BASE (ARMCTRL_0_SBM_BASE + 0x80) /* User 0 (ARM)'s Mailbox 0 */
-
- /*
- * Watchdog
---- a/arch/arm/mach-bcm2709/include/mach/platform.h
-+++ b/arch/arm/mach-bcm2709/include/mach/platform.h
-@@ -78,6 +78,8 @@
- #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 */
-+#define ARMCTRL_0_BELL_BASE (ARMCTRL_0_SBM_BASE + 0x40) /* User 0 (ARM)'s Doorbell */
-+#define ARMCTRL_0_MAIL0_BASE (ARMCTRL_0_SBM_BASE + 0x80) /* User 0 (ARM)'s Mailbox 0 */
-
- /*
- * Watchdog
---- a/drivers/misc/Kconfig
-+++ b/drivers/misc/Kconfig
-@@ -533,6 +533,7 @@ source "drivers/misc/lis3lv02d/Kconfig"
- source "drivers/misc/altera-stapl/Kconfig"
- source "drivers/misc/mei/Kconfig"
- source "drivers/misc/vmw_vmci/Kconfig"
-+source "drivers/misc/vc04_services/Kconfig"
- source "drivers/misc/mic/Kconfig"
- source "drivers/misc/genwqe/Kconfig"
- source "drivers/misc/echo/Kconfig"
---- a/drivers/misc/Makefile
-+++ b/drivers/misc/Makefile
-@@ -51,6 +51,7 @@ obj-$(CONFIG_INTEL_MEI) += mei/
- obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/
- obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o
- obj-$(CONFIG_SRAM) += sram.o
-+obj-$(CONFIG_BCM2708_VCHIQ) += vc04_services/
- obj-y += mic/
- obj-$(CONFIG_GENWQE) += genwqe/
- obj-$(CONFIG_ECHO) += echo/
---- /dev/null
-+++ b/drivers/misc/vc04_services/Kconfig
-@@ -0,0 +1,9 @@
-+config BCM2708_VCHIQ
-+ tristate "Videocore VCHIQ"
-+ depends on RASPBERRYPI_FIRMWARE
-+ default y
-+ help
-+ Kernel to VideoCore communication interface for the
-+ BCM2708 family of products.
-+ Defaults to Y when the Broadcom Videocore services
-+ are included in the build, N otherwise.
---- /dev/null
-+++ b/drivers/misc/vc04_services/Makefile
-@@ -0,0 +1,14 @@
-+obj-$(CONFIG_BCM2708_VCHIQ) += vchiq.o
-+
-+vchiq-objs := \
-+ interface/vchiq_arm/vchiq_core.o \
-+ interface/vchiq_arm/vchiq_arm.o \
-+ interface/vchiq_arm/vchiq_kern_lib.o \
-+ interface/vchiq_arm/vchiq_2835_arm.o \
-+ interface/vchiq_arm/vchiq_debugfs.o \
-+ interface/vchiq_arm/vchiq_shim.o \
-+ interface/vchiq_arm/vchiq_util.o \
-+ interface/vchiq_arm/vchiq_connected.o \
-+
-+ccflags-y += -DVCOS_VERIFY_BKPTS=1 -Idrivers/misc/vc04_services -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000
-+
---- /dev/null
-+++ b/drivers/misc/vc04_services/interface/vchi/connections/connection.h
-@@ -0,0 +1,328 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef CONNECTION_H_
-+#define CONNECTION_H_
-+
-+#include <linux/kernel.h>
-+#include <linux/types.h>
-+#include <linux/semaphore.h>
-+
-+#include "interface/vchi/vchi_cfg_internal.h"
-+#include "interface/vchi/vchi_common.h"
-+#include "interface/vchi/message_drivers/message.h"
-+
-+/******************************************************************************
-+ Global defs
-+ *****************************************************************************/
-+
-+// Opaque handle for a connection / service pair
-+typedef struct opaque_vchi_connection_connected_service_handle_t *VCHI_CONNECTION_SERVICE_HANDLE_T;
-+
-+// opaque handle to the connection state information
-+typedef struct opaque_vchi_connection_info_t VCHI_CONNECTION_STATE_T;
-+
-+typedef struct vchi_connection_t VCHI_CONNECTION_T;
-+
-+
-+/******************************************************************************
-+ API
-+ *****************************************************************************/
-+
-+// Routine to init a connection with a particular low level driver
-+typedef VCHI_CONNECTION_STATE_T * (*VCHI_CONNECTION_INIT_T)( struct vchi_connection_t * connection,
-+ const VCHI_MESSAGE_DRIVER_T * driver );
-+
-+// Routine to control CRC enabling at a connection level
-+typedef int32_t (*VCHI_CONNECTION_CRC_CONTROL_T)( VCHI_CONNECTION_STATE_T *state_handle,
-+ VCHI_CRC_CONTROL_T control );
-+
-+// Routine to create a service
-+typedef int32_t (*VCHI_CONNECTION_SERVICE_CONNECT_T)( VCHI_CONNECTION_STATE_T *state_handle,
-+ int32_t service_id,
-+ uint32_t rx_fifo_size,
-+ uint32_t tx_fifo_size,
-+ int server,
-+ VCHI_CALLBACK_T callback,
-+ void *callback_param,
-+ int32_t want_crc,
-+ int32_t want_unaligned_bulk_rx,
-+ int32_t want_unaligned_bulk_tx,
-+ VCHI_CONNECTION_SERVICE_HANDLE_T *service_handle );
-+
-+// Routine to close a service
-+typedef int32_t (*VCHI_CONNECTION_SERVICE_DISCONNECT_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle );
-+
-+// Routine to queue a message
-+typedef int32_t (*VCHI_CONNECTION_SERVICE_QUEUE_MESSAGE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
-+ const void *data,
-+ uint32_t data_size,
-+ VCHI_FLAGS_T flags,
-+ void *msg_handle );
-+
-+// scatter-gather (vector) message queueing
-+typedef int32_t (*VCHI_CONNECTION_SERVICE_QUEUE_MESSAGEV_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
-+ VCHI_MSG_VECTOR_T *vector,
-+ uint32_t count,
-+ VCHI_FLAGS_T flags,
-+ void *msg_handle );
-+
-+// Routine to dequeue a message
-+typedef int32_t (*VCHI_CONNECTION_SERVICE_DEQUEUE_MESSAGE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
-+ void *data,
-+ uint32_t max_data_size_to_read,
-+ uint32_t *actual_msg_size,
-+ VCHI_FLAGS_T flags );
-+
-+// Routine to peek at a message
-+typedef int32_t (*VCHI_CONNECTION_SERVICE_PEEK_MESSAGE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
-+ void **data,
-+ uint32_t *msg_size,
-+ VCHI_FLAGS_T flags );
-+
-+// Routine to hold a message
-+typedef int32_t (*VCHI_CONNECTION_SERVICE_HOLD_MESSAGE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
-+ void **data,
-+ uint32_t *msg_size,
-+ VCHI_FLAGS_T flags,
-+ void **message_handle );
-+
-+// Routine to initialise a received message iterator
-+typedef int32_t (*VCHI_CONNECTION_SERVICE_LOOKAHEAD_MESSAGE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
-+ VCHI_MSG_ITER_T *iter,
-+ VCHI_FLAGS_T flags );
-+
-+// Routine to release a held message
-+typedef int32_t (*VCHI_CONNECTION_HELD_MSG_RELEASE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
-+ void *message_handle );
-+
-+// Routine to get info on a held message
-+typedef int32_t (*VCHI_CONNECTION_HELD_MSG_INFO_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
-+ void *message_handle,
-+ void **data,
-+ int32_t *msg_size,
-+ uint32_t *tx_timestamp,
-+ uint32_t *rx_timestamp );
-+
-+// Routine to check whether the iterator has a next message
-+typedef int32_t (*VCHI_CONNECTION_MSG_ITER_HAS_NEXT_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service,
-+ const VCHI_MSG_ITER_T *iter );
-+
-+// Routine to advance the iterator
-+typedef int32_t (*VCHI_CONNECTION_MSG_ITER_NEXT_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service,
-+ VCHI_MSG_ITER_T *iter,
-+ void **data,
-+ uint32_t *msg_size );
-+
-+// Routine to remove the last message returned by the iterator
-+typedef int32_t (*VCHI_CONNECTION_MSG_ITER_REMOVE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service,
-+ VCHI_MSG_ITER_T *iter );
-+
-+// Routine to hold the last message returned by the iterator
-+typedef int32_t (*VCHI_CONNECTION_MSG_ITER_HOLD_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service,
-+ VCHI_MSG_ITER_T *iter,
-+ void **msg_handle );
-+
-+// Routine to transmit bulk data
-+typedef int32_t (*VCHI_CONNECTION_BULK_QUEUE_TRANSMIT_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
-+ const void *data_src,
-+ uint32_t data_size,
-+ VCHI_FLAGS_T flags,
-+ void *bulk_handle );
-+
-+// Routine to receive data
-+typedef int32_t (*VCHI_CONNECTION_BULK_QUEUE_RECEIVE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
-+ void *data_dst,
-+ uint32_t data_size,
-+ VCHI_FLAGS_T flags,
-+ void *bulk_handle );
-+
-+// Routine to report if a server is available
-+typedef int32_t (*VCHI_CONNECTION_SERVER_PRESENT)( VCHI_CONNECTION_STATE_T *state, int32_t service_id, int32_t peer_flags );
-+
-+// Routine to report the number of RX slots available
-+typedef int (*VCHI_CONNECTION_RX_SLOTS_AVAILABLE)( const VCHI_CONNECTION_STATE_T *state );
-+
-+// Routine to report the RX slot size
-+typedef uint32_t (*VCHI_CONNECTION_RX_SLOT_SIZE)( const VCHI_CONNECTION_STATE_T *state );
-+
-+// Callback to indicate that the other side has added a buffer to the rx bulk DMA FIFO
-+typedef void (*VCHI_CONNECTION_RX_BULK_BUFFER_ADDED)(VCHI_CONNECTION_STATE_T *state,
-+ int32_t service,
-+ uint32_t length,
-+ MESSAGE_TX_CHANNEL_T channel,
-+ uint32_t channel_params,
-+ uint32_t data_length,
-+ uint32_t data_offset);
-+
-+// Callback to inform a service that a Xon or Xoff message has been received
-+typedef void (*VCHI_CONNECTION_FLOW_CONTROL)(VCHI_CONNECTION_STATE_T *state, int32_t service_id, int32_t xoff);
-+
-+// Callback to inform a service that a server available reply message has been received
-+typedef void (*VCHI_CONNECTION_SERVER_AVAILABLE_REPLY)(VCHI_CONNECTION_STATE_T *state, int32_t service_id, uint32_t flags);
-+
-+// Callback to indicate that bulk auxiliary messages have arrived
-+typedef void (*VCHI_CONNECTION_BULK_AUX_RECEIVED)(VCHI_CONNECTION_STATE_T *state);
-+
-+// Callback to indicate that bulk auxiliary messages have arrived
-+typedef void (*VCHI_CONNECTION_BULK_AUX_TRANSMITTED)(VCHI_CONNECTION_STATE_T *state, void *handle);
-+
-+// Callback with all the connection info you require
-+typedef void (*VCHI_CONNECTION_INFO)(VCHI_CONNECTION_STATE_T *state, uint32_t protocol_version, uint32_t slot_size, uint32_t num_slots, uint32_t min_bulk_size);
-+
-+// Callback to inform of a disconnect
-+typedef void (*VCHI_CONNECTION_DISCONNECT)(VCHI_CONNECTION_STATE_T *state, uint32_t flags);
-+
-+// Callback to inform of a power control request
-+typedef void (*VCHI_CONNECTION_POWER_CONTROL)(VCHI_CONNECTION_STATE_T *state, MESSAGE_TX_CHANNEL_T channel, int32_t enable);
-+
-+// allocate memory suitably aligned for this connection
-+typedef void * (*VCHI_BUFFER_ALLOCATE)(VCHI_CONNECTION_SERVICE_HANDLE_T service_handle, uint32_t * length);
-+
-+// free memory allocated by buffer_allocate
-+typedef void (*VCHI_BUFFER_FREE)(VCHI_CONNECTION_SERVICE_HANDLE_T service_handle, void * address);
-+
-+
-+/******************************************************************************
-+ System driver struct
-+ *****************************************************************************/
-+
-+struct opaque_vchi_connection_api_t
-+{
-+ // Routine to init the connection
-+ VCHI_CONNECTION_INIT_T init;
-+
-+ // Connection-level CRC control
-+ VCHI_CONNECTION_CRC_CONTROL_T crc_control;
-+
-+ // Routine to connect to or create service
-+ VCHI_CONNECTION_SERVICE_CONNECT_T service_connect;
-+
-+ // Routine to disconnect from a service
-+ VCHI_CONNECTION_SERVICE_DISCONNECT_T service_disconnect;
-+
-+ // Routine to queue a message
-+ VCHI_CONNECTION_SERVICE_QUEUE_MESSAGE_T service_queue_msg;
-+
-+ // scatter-gather (vector) message queue
-+ VCHI_CONNECTION_SERVICE_QUEUE_MESSAGEV_T service_queue_msgv;
-+
-+ // Routine to dequeue a message
-+ VCHI_CONNECTION_SERVICE_DEQUEUE_MESSAGE_T service_dequeue_msg;
-+
-+ // Routine to peek at a message
-+ VCHI_CONNECTION_SERVICE_PEEK_MESSAGE_T service_peek_msg;
-+
-+ // Routine to hold a message
-+ VCHI_CONNECTION_SERVICE_HOLD_MESSAGE_T service_hold_msg;
-+
-+ // Routine to initialise a received message iterator
-+ VCHI_CONNECTION_SERVICE_LOOKAHEAD_MESSAGE_T service_look_ahead_msg;
-+
-+ // Routine to release a message
-+ VCHI_CONNECTION_HELD_MSG_RELEASE_T held_msg_release;
-+
-+ // Routine to get information on a held message
-+ VCHI_CONNECTION_HELD_MSG_INFO_T held_msg_info;
-+
-+ // Routine to check for next message on iterator
-+ VCHI_CONNECTION_MSG_ITER_HAS_NEXT_T msg_iter_has_next;
-+
-+ // Routine to get next message on iterator
-+ VCHI_CONNECTION_MSG_ITER_NEXT_T msg_iter_next;
-+
-+ // Routine to remove the last message returned by iterator
-+ VCHI_CONNECTION_MSG_ITER_REMOVE_T msg_iter_remove;
-+
-+ // Routine to hold the last message returned by iterator
-+ VCHI_CONNECTION_MSG_ITER_HOLD_T msg_iter_hold;
-+
-+ // Routine to transmit bulk data
-+ VCHI_CONNECTION_BULK_QUEUE_TRANSMIT_T bulk_queue_transmit;
-+
-+ // Routine to receive data
-+ VCHI_CONNECTION_BULK_QUEUE_RECEIVE_T bulk_queue_receive;
-+
-+ // Routine to report the available servers
-+ VCHI_CONNECTION_SERVER_PRESENT server_present;
-+
-+ // Routine to report the number of RX slots available
-+ VCHI_CONNECTION_RX_SLOTS_AVAILABLE connection_rx_slots_available;
-+
-+ // Routine to report the RX slot size
-+ VCHI_CONNECTION_RX_SLOT_SIZE connection_rx_slot_size;
-+
-+ // Callback to indicate that the other side has added a buffer to the rx bulk DMA FIFO
-+ VCHI_CONNECTION_RX_BULK_BUFFER_ADDED rx_bulk_buffer_added;
-+
-+ // Callback to inform a service that a Xon or Xoff message has been received
-+ VCHI_CONNECTION_FLOW_CONTROL flow_control;
-+
-+ // Callback to inform a service that a server available reply message has been received
-+ VCHI_CONNECTION_SERVER_AVAILABLE_REPLY server_available_reply;
-+
-+ // Callback to indicate that bulk auxiliary messages have arrived
-+ VCHI_CONNECTION_BULK_AUX_RECEIVED bulk_aux_received;
-+
-+ // Callback to indicate that a bulk auxiliary message has been transmitted
-+ VCHI_CONNECTION_BULK_AUX_TRANSMITTED bulk_aux_transmitted;
-+
-+ // Callback to provide information about the connection
-+ VCHI_CONNECTION_INFO connection_info;
-+
-+ // Callback to notify that peer has requested disconnect
-+ VCHI_CONNECTION_DISCONNECT disconnect;
-+
-+ // Callback to notify that peer has requested power change
-+ VCHI_CONNECTION_POWER_CONTROL power_control;
-+
-+ // allocate memory suitably aligned for this connection
-+ VCHI_BUFFER_ALLOCATE buffer_allocate;
-+
-+ // free memory allocated by buffer_allocate
-+ VCHI_BUFFER_FREE buffer_free;
-+
-+};
-+
-+struct vchi_connection_t {
-+ const VCHI_CONNECTION_API_T *api;
-+ VCHI_CONNECTION_STATE_T *state;
-+#ifdef VCHI_COARSE_LOCKING
-+ struct semaphore sem;
-+#endif
-+};
-+
-+
-+#endif /* CONNECTION_H_ */
-+
-+/****************************** End of file **********************************/
---- /dev/null
-+++ b/drivers/misc/vc04_services/interface/vchi/message_drivers/message.h
-@@ -0,0 +1,204 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef _VCHI_MESSAGE_H_
-+#define _VCHI_MESSAGE_H_
-+
-+#include <linux/kernel.h>
-+#include <linux/types.h>
-+#include <linux/semaphore.h>
-+
-+#include "interface/vchi/vchi_cfg_internal.h"
-+#include "interface/vchi/vchi_common.h"
-+
-+
-+typedef enum message_event_type {
-+ MESSAGE_EVENT_NONE,
-+ MESSAGE_EVENT_NOP,
-+ MESSAGE_EVENT_MESSAGE,
-+ MESSAGE_EVENT_SLOT_COMPLETE,
-+ MESSAGE_EVENT_RX_BULK_PAUSED,
-+ MESSAGE_EVENT_RX_BULK_COMPLETE,
-+ MESSAGE_EVENT_TX_COMPLETE,
-+ MESSAGE_EVENT_MSG_DISCARDED
-+} MESSAGE_EVENT_TYPE_T;
-+
-+typedef enum vchi_msg_flags
-+{
-+ VCHI_MSG_FLAGS_NONE = 0x0,
-+ VCHI_MSG_FLAGS_TERMINATE_DMA = 0x1
-+} VCHI_MSG_FLAGS_T;
-+
-+typedef enum message_tx_channel
-+{
-+ MESSAGE_TX_CHANNEL_MESSAGE = 0,
-+ MESSAGE_TX_CHANNEL_BULK = 1 // drivers may provide multiple bulk channels, from 1 upwards
-+} MESSAGE_TX_CHANNEL_T;
-+
-+// Macros used for cycling through bulk channels
-+#define MESSAGE_TX_CHANNEL_BULK_PREV(c) (MESSAGE_TX_CHANNEL_BULK+((c)-MESSAGE_TX_CHANNEL_BULK+VCHI_MAX_BULK_TX_CHANNELS_PER_CONNECTION-1)%VCHI_MAX_BULK_TX_CHANNELS_PER_CONNECTION)
-+#define MESSAGE_TX_CHANNEL_BULK_NEXT(c) (MESSAGE_TX_CHANNEL_BULK+((c)-MESSAGE_TX_CHANNEL_BULK+1)%VCHI_MAX_BULK_TX_CHANNELS_PER_CONNECTION)
-+
-+typedef enum message_rx_channel
-+{
-+ MESSAGE_RX_CHANNEL_MESSAGE = 0,
-+ MESSAGE_RX_CHANNEL_BULK = 1 // drivers may provide multiple bulk channels, from 1 upwards
-+} MESSAGE_RX_CHANNEL_T;
-+
-+// Message receive slot information
-+typedef struct rx_msg_slot_info {
-+
-+ struct rx_msg_slot_info *next;
-+ //struct slot_info *prev;
-+#if !defined VCHI_COARSE_LOCKING
-+ struct semaphore sem;
-+#endif
-+
-+ uint8_t *addr; // base address of slot
-+ uint32_t len; // length of slot in bytes
-+
-+ uint32_t write_ptr; // hardware causes this to advance
-+ uint32_t read_ptr; // this module does the reading
-+ int active; // is this slot in the hardware dma fifo?
-+ uint32_t msgs_parsed; // count how many messages are in this slot
-+ uint32_t msgs_released; // how many messages have been released
-+ void *state; // connection state information
-+ uint8_t ref_count[VCHI_MAX_SERVICES_PER_CONNECTION]; // reference count for slots held by services
-+} RX_MSG_SLOTINFO_T;
-+
-+// The message driver no longer needs to know about the fields of RX_BULK_SLOTINFO_T - sort this out.
-+// In particular, it mustn't use addr and len - they're the client buffer, but the message
-+// driver will be tasked with sending the aligned core section.
-+typedef struct rx_bulk_slotinfo_t {
-+ struct rx_bulk_slotinfo_t *next;
-+
-+ struct semaphore *blocking;
-+
-+ // needed by DMA
-+ void *addr;
-+ uint32_t len;
-+
-+ // needed for the callback
-+ void *service;
-+ void *handle;
-+ VCHI_FLAGS_T flags;
-+} RX_BULK_SLOTINFO_T;
-+
-+
-+/* ----------------------------------------------------------------------
-+ * each connection driver will have a pool of the following struct.
-+ *
-+ * the pool will be managed by vchi_qman_*
-+ * this means there will be multiple queues (single linked lists)
-+ * a given struct message_info will be on exactly one of these queues
-+ * at any one time
-+ * -------------------------------------------------------------------- */
-+typedef struct rx_message_info {
-+
-+ struct message_info *next;
-+ //struct message_info *prev;
-+
-+ uint8_t *addr;
-+ uint32_t len;
-+ RX_MSG_SLOTINFO_T *slot; // points to whichever slot contains this message
-+ uint32_t tx_timestamp;
-+ uint32_t rx_timestamp;
-+
-+} RX_MESSAGE_INFO_T;
-+
-+typedef struct {
-+ MESSAGE_EVENT_TYPE_T type;
-+
-+ struct {
-+ // for messages
-+ void *addr; // address of message
-+ uint16_t slot_delta; // whether this message indicated slot delta
-+ uint32_t len; // length of message
-+ RX_MSG_SLOTINFO_T *slot; // slot this message is in
-+ int32_t service; // service id this message is destined for
-+ uint32_t tx_timestamp; // timestamp from the header
-+ uint32_t rx_timestamp; // timestamp when we parsed it
-+ } message;
-+
-+ // FIXME: cleanup slot reporting...
-+ RX_MSG_SLOTINFO_T *rx_msg;
-+ RX_BULK_SLOTINFO_T *rx_bulk;
-+ void *tx_handle;
-+ MESSAGE_TX_CHANNEL_T tx_channel;
-+
-+} MESSAGE_EVENT_T;
-+
-+
-+// callbacks
-+typedef void VCHI_MESSAGE_DRIVER_EVENT_CALLBACK_T( void *state );
-+
-+typedef struct {
-+ VCHI_MESSAGE_DRIVER_EVENT_CALLBACK_T *event_callback;
-+} VCHI_MESSAGE_DRIVER_OPEN_T;
-+
-+
-+// handle to this instance of message driver (as returned by ->open)
-+typedef struct opaque_mhandle_t *VCHI_MDRIVER_HANDLE_T;
-+
-+struct opaque_vchi_message_driver_t {
-+ VCHI_MDRIVER_HANDLE_T *(*open)( VCHI_MESSAGE_DRIVER_OPEN_T *params, void *state );
-+ int32_t (*suspending)( VCHI_MDRIVER_HANDLE_T *handle );
-+ int32_t (*resumed)( VCHI_MDRIVER_HANDLE_T *handle );
-+ int32_t (*power_control)( VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_TX_CHANNEL_T, int32_t enable );
-+ int32_t (*add_msg_rx_slot)( VCHI_MDRIVER_HANDLE_T *handle, RX_MSG_SLOTINFO_T *slot ); // rx message
-+ int32_t (*add_bulk_rx)( VCHI_MDRIVER_HANDLE_T *handle, void *data, uint32_t len, RX_BULK_SLOTINFO_T *slot ); // rx data (bulk)
-+ int32_t (*send)( VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_TX_CHANNEL_T channel, const void *data, uint32_t len, VCHI_MSG_FLAGS_T flags, void *send_handle ); // tx (message & bulk)
-+ void (*next_event)( VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_EVENT_T *event ); // get the next event from message_driver
-+ int32_t (*enable)( VCHI_MDRIVER_HANDLE_T *handle );
-+ int32_t (*form_message)( VCHI_MDRIVER_HANDLE_T *handle, int32_t service_id, VCHI_MSG_VECTOR_T *vector, uint32_t count, void
-+ *address, uint32_t length_avail, uint32_t max_total_length, int32_t pad_to_fill, int32_t allow_partial );
-+
-+ int32_t (*update_message)( VCHI_MDRIVER_HANDLE_T *handle, void *dest, int16_t *slot_count );
-+ int32_t (*buffer_aligned)( VCHI_MDRIVER_HANDLE_T *handle, int tx, int uncached, const void *address, const uint32_t length );
-+ void * (*allocate_buffer)( VCHI_MDRIVER_HANDLE_T *handle, uint32_t *length );
-+ void (*free_buffer)( VCHI_MDRIVER_HANDLE_T *handle, void *address );
-+ int (*rx_slot_size)( VCHI_MDRIVER_HANDLE_T *handle, int msg_size );
-+ int (*tx_slot_size)( VCHI_MDRIVER_HANDLE_T *handle, int msg_size );
-+
-+ int32_t (*tx_supports_terminate)( const VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_TX_CHANNEL_T channel );
-+ uint32_t (*tx_bulk_chunk_size)( const VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_TX_CHANNEL_T channel );
-+ int (*tx_alignment)( const VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_TX_CHANNEL_T channel );
-+ int (*rx_alignment)( const VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_RX_CHANNEL_T channel );
-+ void (*form_bulk_aux)( VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_TX_CHANNEL_T channel, const void *data, uint32_t len, uint32_t chunk_size, const void **aux_data, int32_t *aux_len );
-+ void (*debug)( VCHI_MDRIVER_HANDLE_T *handle );
-+};
-+
-+
-+#endif // _VCHI_MESSAGE_H_
-+
-+/****************************** End of file ***********************************/
---- /dev/null
-+++ b/drivers/misc/vc04_services/interface/vchi/vchi.h
-@@ -0,0 +1,378 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHI_H_
-+#define VCHI_H_
-+
-+#include "interface/vchi/vchi_cfg.h"
-+#include "interface/vchi/vchi_common.h"
-+#include "interface/vchi/connections/connection.h"
-+#include "vchi_mh.h"
-+
-+
-+/******************************************************************************
-+ Global defs
-+ *****************************************************************************/
-+
-+#define VCHI_BULK_ROUND_UP(x) ((((unsigned long)(x))+VCHI_BULK_ALIGN-1) & ~(VCHI_BULK_ALIGN-1))
-+#define VCHI_BULK_ROUND_DOWN(x) (((unsigned long)(x)) & ~(VCHI_BULK_ALIGN-1))
-+#define VCHI_BULK_ALIGN_NBYTES(x) (VCHI_BULK_ALIGNED(x) ? 0 : (VCHI_BULK_ALIGN - ((unsigned long)(x) & (VCHI_BULK_ALIGN-1))))
-+
-+#ifdef USE_VCHIQ_ARM
-+#define VCHI_BULK_ALIGNED(x) 1
-+#else
-+#define VCHI_BULK_ALIGNED(x) (((unsigned long)(x) & (VCHI_BULK_ALIGN-1)) == 0)
-+#endif
-+
-+struct vchi_version {
-+ uint32_t version;
-+ uint32_t version_min;
-+};
-+#define VCHI_VERSION(v_) { v_, v_ }
-+#define VCHI_VERSION_EX(v_, m_) { v_, m_ }
-+
-+typedef enum
-+{
-+ VCHI_VEC_POINTER,
-+ VCHI_VEC_HANDLE,
-+ VCHI_VEC_LIST
-+} VCHI_MSG_VECTOR_TYPE_T;
-+
-+typedef struct vchi_msg_vector_ex {
-+
-+ VCHI_MSG_VECTOR_TYPE_T type;
-+ union
-+ {
-+ // a memory handle
-+ struct
-+ {
-+ VCHI_MEM_HANDLE_T handle;
-+ uint32_t offset;
-+ int32_t vec_len;
-+ } handle;
-+
-+ // an ordinary data pointer
-+ struct
-+ {
-+ const void *vec_base;
-+ int32_t vec_len;
-+ } ptr;
-+
-+ // a nested vector list
-+ struct
-+ {
-+ struct vchi_msg_vector_ex *vec;
-+ uint32_t vec_len;
-+ } list;
-+ } u;
-+} VCHI_MSG_VECTOR_EX_T;
-+
-+
-+// Construct an entry in a msg vector for a pointer (p) of length (l)
-+#define VCHI_VEC_POINTER(p,l) VCHI_VEC_POINTER, { { (VCHI_MEM_HANDLE_T)(p), (l) } }
-+
-+// Construct an entry in a msg vector for a message handle (h), starting at offset (o) of length (l)
-+#define VCHI_VEC_HANDLE(h,o,l) VCHI_VEC_HANDLE, { { (h), (o), (l) } }
-+
-+// Macros to manipulate 'FOURCC' values
-+#define MAKE_FOURCC(x) ((int32_t)( (x[0] << 24) | (x[1] << 16) | (x[2] << 8) | x[3] ))
-+#define FOURCC_TO_CHAR(x) (x >> 24) & 0xFF,(x >> 16) & 0xFF,(x >> 8) & 0xFF, x & 0xFF
-+
-+
-+// Opaque service information
-+struct opaque_vchi_service_t;
-+
-+// Descriptor for a held message. Allocated by client, initialised by vchi_msg_hold,
-+// vchi_msg_iter_hold or vchi_msg_iter_hold_next. Fields are for internal VCHI use only.
-+typedef struct
-+{
-+ struct opaque_vchi_service_t *service;
-+ void *message;
-+} VCHI_HELD_MSG_T;
-+
-+
-+
-+// structure used to provide the information needed to open a server or a client
-+typedef struct {
-+ struct vchi_version version;
-+ int32_t service_id;
-+ VCHI_CONNECTION_T *connection;
-+ uint32_t rx_fifo_size;
-+ uint32_t tx_fifo_size;
-+ VCHI_CALLBACK_T callback;
-+ void *callback_param;
-+ /* client intends to receive bulk transfers of
-+ odd lengths or into unaligned buffers */
-+ int32_t want_unaligned_bulk_rx;
-+ /* client intends to transmit bulk transfers of
-+ odd lengths or out of unaligned buffers */
-+ int32_t want_unaligned_bulk_tx;
-+ /* client wants to check CRCs on (bulk) xfers.
-+ Only needs to be set at 1 end - will do both directions. */
-+ int32_t want_crc;
-+} SERVICE_CREATION_T;
-+
-+// Opaque handle for a VCHI instance
-+typedef struct opaque_vchi_instance_handle_t *VCHI_INSTANCE_T;
-+
-+// Opaque handle for a server or client
-+typedef struct opaque_vchi_service_handle_t *VCHI_SERVICE_HANDLE_T;
-+
-+// Service registration & startup
-+typedef void (*VCHI_SERVICE_INIT)(VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections);
-+
-+typedef struct service_info_tag {
-+ const char * const vll_filename; /* VLL to load to start this service. This is an empty string if VLL is "static" */
-+ VCHI_SERVICE_INIT init; /* Service initialisation function */
-+ void *vll_handle; /* VLL handle; NULL when unloaded or a "static VLL" in build */
-+} SERVICE_INFO_T;
-+
-+/******************************************************************************
-+ Global funcs - implementation is specific to which side you are on (local / remote)
-+ *****************************************************************************/
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+extern /*@observer@*/ VCHI_CONNECTION_T * vchi_create_connection( const VCHI_CONNECTION_API_T * function_table,
-+ const VCHI_MESSAGE_DRIVER_T * low_level);
-+
-+
-+// Routine used to initialise the vchi on both local + remote connections
-+extern int32_t vchi_initialise( VCHI_INSTANCE_T *instance_handle );
-+
-+extern int32_t vchi_exit( void );
-+
-+extern int32_t vchi_connect( VCHI_CONNECTION_T **connections,
-+ const uint32_t num_connections,
-+ VCHI_INSTANCE_T instance_handle );
-+
-+//When this is called, ensure that all services have no data pending.
-+//Bulk transfers can remain 'queued'
-+extern int32_t vchi_disconnect( VCHI_INSTANCE_T instance_handle );
-+
-+// Global control over bulk CRC checking
-+extern int32_t vchi_crc_control( VCHI_CONNECTION_T *connection,
-+ VCHI_CRC_CONTROL_T control );
-+
-+// helper functions
-+extern void * vchi_allocate_buffer(VCHI_SERVICE_HANDLE_T handle, uint32_t *length);
-+extern void vchi_free_buffer(VCHI_SERVICE_HANDLE_T handle, void *address);
-+extern uint32_t vchi_current_time(VCHI_INSTANCE_T instance_handle);
-+
-+
-+/******************************************************************************
-+ Global service API
-+ *****************************************************************************/
-+// Routine to create a named service
-+extern int32_t vchi_service_create( VCHI_INSTANCE_T instance_handle,
-+ SERVICE_CREATION_T *setup,
-+ VCHI_SERVICE_HANDLE_T *handle );
-+
-+// Routine to destory a service
-+extern int32_t vchi_service_destroy( const VCHI_SERVICE_HANDLE_T handle );
-+
-+// Routine to open a named service
-+extern int32_t vchi_service_open( VCHI_INSTANCE_T instance_handle,
-+ SERVICE_CREATION_T *setup,
-+ VCHI_SERVICE_HANDLE_T *handle);
-+
-+extern int32_t vchi_get_peer_version( const VCHI_SERVICE_HANDLE_T handle,
-+ short *peer_version );
-+
-+// Routine to close a named service
-+extern int32_t vchi_service_close( const VCHI_SERVICE_HANDLE_T handle );
-+
-+// Routine to increment ref count on a named service
-+extern int32_t vchi_service_use( const VCHI_SERVICE_HANDLE_T handle );
-+
-+// Routine to decrement ref count on a named service
-+extern int32_t vchi_service_release( const VCHI_SERVICE_HANDLE_T handle );
-+
-+// Routine to set a control option for a named service
-+extern int32_t vchi_service_set_option( const VCHI_SERVICE_HANDLE_T handle,
-+ VCHI_SERVICE_OPTION_T option,
-+ int value);
-+
-+// Routine to send a message across a service
-+extern int32_t vchi_msg_queue( VCHI_SERVICE_HANDLE_T handle,
-+ const void *data,
-+ uint32_t data_size,
-+ VCHI_FLAGS_T flags,
-+ void *msg_handle );
-+
-+// scatter-gather (vector) and send message
-+int32_t vchi_msg_queuev_ex( VCHI_SERVICE_HANDLE_T handle,
-+ VCHI_MSG_VECTOR_EX_T *vector,
-+ uint32_t count,
-+ VCHI_FLAGS_T flags,
-+ void *msg_handle );
-+
-+// legacy scatter-gather (vector) and send message, only handles pointers
-+int32_t vchi_msg_queuev( VCHI_SERVICE_HANDLE_T handle,
-+ VCHI_MSG_VECTOR_T *vector,
-+ uint32_t count,
-+ VCHI_FLAGS_T flags,
-+ void *msg_handle );
-+
-+// Routine to receive a msg from a service
-+// Dequeue is equivalent to hold, copy into client buffer, release
-+extern int32_t vchi_msg_dequeue( VCHI_SERVICE_HANDLE_T handle,
-+ void *data,
-+ uint32_t max_data_size_to_read,
-+ uint32_t *actual_msg_size,
-+ VCHI_FLAGS_T flags );
-+
-+// Routine to look at a message in place.
-+// The message is not dequeued, so a subsequent call to peek or dequeue
-+// will return the same message.
-+extern int32_t vchi_msg_peek( VCHI_SERVICE_HANDLE_T handle,
-+ void **data,
-+ uint32_t *msg_size,
-+ VCHI_FLAGS_T flags );
-+
-+// Routine to remove a message after it has been read in place with peek
-+// The first message on the queue is dequeued.
-+extern int32_t vchi_msg_remove( VCHI_SERVICE_HANDLE_T handle );
-+
-+// Routine to look at a message in place.
-+// The message is dequeued, so the caller is left holding it; the descriptor is
-+// filled in and must be released when the user has finished with the message.
-+extern int32_t vchi_msg_hold( VCHI_SERVICE_HANDLE_T handle,
-+ void **data, // } may be NULL, as info can be
-+ uint32_t *msg_size, // } obtained from HELD_MSG_T
-+ VCHI_FLAGS_T flags,
-+ VCHI_HELD_MSG_T *message_descriptor );
-+
-+// Initialise an iterator to look through messages in place
-+extern int32_t vchi_msg_look_ahead( VCHI_SERVICE_HANDLE_T handle,
-+ VCHI_MSG_ITER_T *iter,
-+ VCHI_FLAGS_T flags );
-+
-+/******************************************************************************
-+ Global service support API - operations on held messages and message iterators
-+ *****************************************************************************/
-+
-+// Routine to get the address of a held message
-+extern void *vchi_held_msg_ptr( const VCHI_HELD_MSG_T *message );
-+
-+// Routine to get the size of a held message
-+extern int32_t vchi_held_msg_size( const VCHI_HELD_MSG_T *message );
-+
-+// Routine to get the transmit timestamp as written into the header by the peer
-+extern uint32_t vchi_held_msg_tx_timestamp( const VCHI_HELD_MSG_T *message );
-+
-+// Routine to get the reception timestamp, written as we parsed the header
-+extern uint32_t vchi_held_msg_rx_timestamp( const VCHI_HELD_MSG_T *message );
-+
-+// Routine to release a held message after it has been processed
-+extern int32_t vchi_held_msg_release( VCHI_HELD_MSG_T *message );
-+
-+// Indicates whether the iterator has a next message.
-+extern int32_t vchi_msg_iter_has_next( const VCHI_MSG_ITER_T *iter );
-+
-+// Return the pointer and length for the next message and advance the iterator.
-+extern int32_t vchi_msg_iter_next( VCHI_MSG_ITER_T *iter,
-+ void **data,
-+ uint32_t *msg_size );
-+
-+// Remove the last message returned by vchi_msg_iter_next.
-+// Can only be called once after each call to vchi_msg_iter_next.
-+extern int32_t vchi_msg_iter_remove( VCHI_MSG_ITER_T *iter );
-+
-+// Hold the last message returned by vchi_msg_iter_next.
-+// Can only be called once after each call to vchi_msg_iter_next.
-+extern int32_t vchi_msg_iter_hold( VCHI_MSG_ITER_T *iter,
-+ VCHI_HELD_MSG_T *message );
-+
-+// Return information for the next message, and hold it, advancing the iterator.
-+extern int32_t vchi_msg_iter_hold_next( VCHI_MSG_ITER_T *iter,
-+ void **data, // } may be NULL
-+ uint32_t *msg_size, // }
-+ VCHI_HELD_MSG_T *message );
-+
-+
-+/******************************************************************************
-+ Global bulk API
-+ *****************************************************************************/
-+
-+// Routine to prepare interface for a transfer from the other side
-+extern int32_t vchi_bulk_queue_receive( VCHI_SERVICE_HANDLE_T handle,
-+ void *data_dst,
-+ uint32_t data_size,
-+ VCHI_FLAGS_T flags,
-+ void *transfer_handle );
-+
-+
-+// Prepare interface for a transfer from the other side into relocatable memory.
-+int32_t vchi_bulk_queue_receive_reloc( const VCHI_SERVICE_HANDLE_T handle,
-+ VCHI_MEM_HANDLE_T h_dst,
-+ uint32_t offset,
-+ uint32_t data_size,
-+ const VCHI_FLAGS_T flags,
-+ void * const bulk_handle );
-+
-+// Routine to queue up data ready for transfer to the other (once they have signalled they are ready)
-+extern int32_t vchi_bulk_queue_transmit( VCHI_SERVICE_HANDLE_T handle,
-+ const void *data_src,
-+ uint32_t data_size,
-+ VCHI_FLAGS_T flags,
-+ void *transfer_handle );
-+
-+
-+/******************************************************************************
-+ Configuration plumbing
-+ *****************************************************************************/
-+
-+// function prototypes for the different mid layers (the state info gives the different physical connections)
-+extern const VCHI_CONNECTION_API_T *single_get_func_table( void );
-+//extern const VCHI_CONNECTION_API_T *local_server_get_func_table( void );
-+//extern const VCHI_CONNECTION_API_T *local_client_get_func_table( void );
-+
-+// declare all message drivers here
-+const VCHI_MESSAGE_DRIVER_T *vchi_mphi_message_driver_func_table( void );
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+extern int32_t vchi_bulk_queue_transmit_reloc( VCHI_SERVICE_HANDLE_T handle,
-+ VCHI_MEM_HANDLE_T h_src,
-+ uint32_t offset,
-+ uint32_t data_size,
-+ VCHI_FLAGS_T flags,
-+ void *transfer_handle );
-+#endif /* VCHI_H_ */
-+
-+/****************************** End of file **********************************/
---- /dev/null
-+++ b/drivers/misc/vc04_services/interface/vchi/vchi_cfg.h
-@@ -0,0 +1,224 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHI_CFG_H_
-+#define VCHI_CFG_H_
-+
-+/****************************************************************************************
-+ * Defines in this first section are part of the VCHI API and may be examined by VCHI
-+ * services.
-+ ***************************************************************************************/
-+
-+/* Required alignment of base addresses for bulk transfer, if unaligned transfers are not enabled */
-+/* Really determined by the message driver, and should be available from a run-time call. */
-+#ifndef VCHI_BULK_ALIGN
-+# if __VCCOREVER__ >= 0x04000000
-+# define VCHI_BULK_ALIGN 32 // Allows for the need to do cache cleans
-+# else
-+# define VCHI_BULK_ALIGN 16
-+# endif
-+#endif
-+
-+/* Required length multiple for bulk transfers, if unaligned transfers are not enabled */
-+/* May be less than or greater than VCHI_BULK_ALIGN */
-+/* Really determined by the message driver, and should be available from a run-time call. */
-+#ifndef VCHI_BULK_GRANULARITY
-+# if __VCCOREVER__ >= 0x04000000
-+# define VCHI_BULK_GRANULARITY 32 // Allows for the need to do cache cleans
-+# else
-+# define VCHI_BULK_GRANULARITY 16
-+# endif
-+#endif
-+
-+/* The largest possible message to be queued with vchi_msg_queue. */
-+#ifndef VCHI_MAX_MSG_SIZE
-+# if defined VCHI_LOCAL_HOST_PORT
-+# define VCHI_MAX_MSG_SIZE 16384 // makes file transfers fast, but should they be using bulk?
-+# else
-+# define VCHI_MAX_MSG_SIZE 4096 // NOTE: THIS MUST BE LARGER THAN OR EQUAL TO THE SIZE OF THE KHRONOS MERGE BUFFER!!
-+# endif
-+#endif
-+
-+/******************************************************************************************
-+ * Defines below are system configuration options, and should not be used by VCHI services.
-+ *****************************************************************************************/
-+
-+/* How many connections can we support? A localhost implementation uses 2 connections,
-+ * 1 for host-app, 1 for VMCS, and these are hooked together by a loopback MPHI VCFW
-+ * driver. */
-+#ifndef VCHI_MAX_NUM_CONNECTIONS
-+# define VCHI_MAX_NUM_CONNECTIONS 3
-+#endif
-+
-+/* How many services can we open per connection? Extending this doesn't cost processing time, just a small
-+ * amount of static memory. */
-+#ifndef VCHI_MAX_SERVICES_PER_CONNECTION
-+# define VCHI_MAX_SERVICES_PER_CONNECTION 36
-+#endif
-+
-+/* Adjust if using a message driver that supports more logical TX channels */
-+#ifndef VCHI_MAX_BULK_TX_CHANNELS_PER_CONNECTION
-+# define VCHI_MAX_BULK_TX_CHANNELS_PER_CONNECTION 9 // 1 MPHI + 8 CCP2 logical channels
-+#endif
-+
-+/* Adjust if using a message driver that supports more logical RX channels */
-+#ifndef VCHI_MAX_BULK_RX_CHANNELS_PER_CONNECTION
-+# define VCHI_MAX_BULK_RX_CHANNELS_PER_CONNECTION 1 // 1 MPHI
-+#endif
-+
-+/* How many receive slots do we use. This times VCHI_MAX_MSG_SIZE gives the effective
-+ * receive queue space, less message headers. */
-+#ifndef VCHI_NUM_READ_SLOTS
-+# if defined(VCHI_LOCAL_HOST_PORT)
-+# define VCHI_NUM_READ_SLOTS 4
-+# else
-+# define VCHI_NUM_READ_SLOTS 48
-+# endif
-+#endif
-+
-+/* Do we utilise overrun facility for receive message slots? Can aid peer transmit
-+ * performance. Only define on VideoCore end, talking to host.
-+ */
-+//#define VCHI_MSG_RX_OVERRUN
-+
-+/* How many transmit slots do we use. Generally don't need many, as the hardware driver
-+ * underneath VCHI will usually have its own buffering. */
-+#ifndef VCHI_NUM_WRITE_SLOTS
-+# define VCHI_NUM_WRITE_SLOTS 4
-+#endif
-+
-+/* If a service has held or queued received messages in VCHI_XOFF_THRESHOLD or more slots,
-+ * then it's taking up too much buffer space, and the peer service will be told to stop
-+ * transmitting with an XOFF message. For this to be effective, the VCHI_NUM_READ_SLOTS
-+ * needs to be considerably bigger than VCHI_NUM_WRITE_SLOTS, or the transmit latency
-+ * is too high. */
-+#ifndef VCHI_XOFF_THRESHOLD
-+# define VCHI_XOFF_THRESHOLD (VCHI_NUM_READ_SLOTS / 2)
-+#endif
-+
-+/* After we've sent an XOFF, the peer will be told to resume transmission once the local
-+ * service has dequeued/released enough messages that it's now occupying
-+ * VCHI_XON_THRESHOLD slots or fewer. */
-+#ifndef VCHI_XON_THRESHOLD
-+# define VCHI_XON_THRESHOLD (VCHI_NUM_READ_SLOTS / 4)
-+#endif
-+
-+/* A size below which a bulk transfer omits the handshake completely and always goes
-+ * via the message channel, if bulk auxiliary is being sent on that service. (The user
-+ * can guarantee this by enabling unaligned transmits).
-+ * Not API. */
-+#ifndef VCHI_MIN_BULK_SIZE
-+# define VCHI_MIN_BULK_SIZE ( VCHI_MAX_MSG_SIZE / 2 < 4096 ? VCHI_MAX_MSG_SIZE / 2 : 4096 )
-+#endif
-+
-+/* Maximum size of bulk transmission chunks, for each interface type. A trade-off between
-+ * speed and latency; the smaller the chunk size the better change of messages and other
-+ * bulk transmissions getting in when big bulk transfers are happening. Set to 0 to not
-+ * break transmissions into chunks.
-+ */
-+#ifndef VCHI_MAX_BULK_CHUNK_SIZE_MPHI
-+# define VCHI_MAX_BULK_CHUNK_SIZE_MPHI (16 * 1024)
-+#endif
-+
-+/* NB Chunked CCP2 transmissions violate the letter of the CCP2 spec by using "JPEG8" mode
-+ * with multiple-line frames. Only use if the receiver can cope. */
-+#ifndef VCHI_MAX_BULK_CHUNK_SIZE_CCP2
-+# define VCHI_MAX_BULK_CHUNK_SIZE_CCP2 0
-+#endif
-+
-+/* How many TX messages can we have pending in our transmit slots. Once exhausted,
-+ * vchi_msg_queue will be blocked. */
-+#ifndef VCHI_TX_MSG_QUEUE_SIZE
-+# define VCHI_TX_MSG_QUEUE_SIZE 256
-+#endif
-+
-+/* How many RX messages can we have parsed in the receive slots. Once exhausted, parsing
-+ * will be suspended until older messages are dequeued/released. */
-+#ifndef VCHI_RX_MSG_QUEUE_SIZE
-+# define VCHI_RX_MSG_QUEUE_SIZE 256
-+#endif
-+
-+/* Really should be able to cope if we run out of received message descriptors, by
-+ * suspending parsing as the comment above says, but we don't. This sweeps the issue
-+ * under the carpet. */
-+#if VCHI_RX_MSG_QUEUE_SIZE < (VCHI_MAX_MSG_SIZE/16 + 1) * VCHI_NUM_READ_SLOTS
-+# undef VCHI_RX_MSG_QUEUE_SIZE
-+# define VCHI_RX_MSG_QUEUE_SIZE (VCHI_MAX_MSG_SIZE/16 + 1) * VCHI_NUM_READ_SLOTS
-+#endif
-+
-+/* How many bulk transmits can we have pending. Once exhausted, vchi_bulk_queue_transmit
-+ * will be blocked. */
-+#ifndef VCHI_TX_BULK_QUEUE_SIZE
-+# define VCHI_TX_BULK_QUEUE_SIZE 64
-+#endif
-+
-+/* How many bulk receives can we have pending. Once exhausted, vchi_bulk_queue_receive
-+ * will be blocked. */
-+#ifndef VCHI_RX_BULK_QUEUE_SIZE
-+# define VCHI_RX_BULK_QUEUE_SIZE 64
-+#endif
-+
-+/* A limit on how many outstanding bulk requests we expect the peer to give us. If
-+ * the peer asks for more than this, VCHI will fail and assert. The number is determined
-+ * by the peer's hardware - it's the number of outstanding requests that can be queued
-+ * on all bulk channels. VC3's MPHI peripheral allows 16. */
-+#ifndef VCHI_MAX_PEER_BULK_REQUESTS
-+# define VCHI_MAX_PEER_BULK_REQUESTS 32
-+#endif
-+
-+/* Define VCHI_CCP2TX_MANUAL_POWER if the host tells us when to turn the CCP2
-+ * transmitter on and off.
-+ */
-+/*#define VCHI_CCP2TX_MANUAL_POWER*/
-+
-+#ifndef VCHI_CCP2TX_MANUAL_POWER
-+
-+/* Timeout (in milliseconds) for putting the CCP2TX interface into IDLE state. Set
-+ * negative for no IDLE.
-+ */
-+# ifndef VCHI_CCP2TX_IDLE_TIMEOUT
-+# define VCHI_CCP2TX_IDLE_TIMEOUT 5
-+# endif
-+
-+/* Timeout (in milliseconds) for putting the CCP2TX interface into OFF state. Set
-+ * negative for no OFF.
-+ */
-+# ifndef VCHI_CCP2TX_OFF_TIMEOUT
-+# define VCHI_CCP2TX_OFF_TIMEOUT 1000
-+# endif
-+
-+#endif /* VCHI_CCP2TX_MANUAL_POWER */
-+
-+#endif /* VCHI_CFG_H_ */
-+
-+/****************************** End of file **********************************/
---- /dev/null
-+++ b/drivers/misc/vc04_services/interface/vchi/vchi_cfg_internal.h
-@@ -0,0 +1,71 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHI_CFG_INTERNAL_H_
-+#define VCHI_CFG_INTERNAL_H_
-+
-+/****************************************************************************************
-+ * Control optimisation attempts.
-+ ***************************************************************************************/
-+
-+// Don't use lots of short-term locks - use great long ones, reducing the overall locks-per-second
-+#define VCHI_COARSE_LOCKING
-+
-+// Avoid lock then unlock on exit from blocking queue operations (msg tx, bulk rx/tx)
-+// (only relevant if VCHI_COARSE_LOCKING)
-+#define VCHI_ELIDE_BLOCK_EXIT_LOCK
-+
-+// Avoid lock on non-blocking peek
-+// (only relevant if VCHI_COARSE_LOCKING)
-+#define VCHI_AVOID_PEEK_LOCK
-+
-+// Use one slot-handler thread per connection, rather than 1 thread dealing with all connections in rotation.
-+#define VCHI_MULTIPLE_HANDLER_THREADS
-+
-+// Put free descriptors onto the head of the free queue, rather than the tail, so that we don't thrash
-+// our way through the pool of descriptors.
-+#define VCHI_PUSH_FREE_DESCRIPTORS_ONTO_HEAD
-+
-+// Don't issue a MSG_AVAILABLE callback for every single message. Possibly only safe if VCHI_COARSE_LOCKING.
-+#define VCHI_FEWER_MSG_AVAILABLE_CALLBACKS
-+
-+// Don't use message descriptors for TX messages that don't need them
-+#define VCHI_MINIMISE_TX_MSG_DESCRIPTORS
-+
-+// Nano-locks for multiqueue
-+//#define VCHI_MQUEUE_NANOLOCKS
-+
-+// Lock-free(er) dequeuing
-+//#define VCHI_RX_NANOLOCKS
-+
-+#endif /*VCHI_CFG_INTERNAL_H_*/
---- /dev/null
-+++ b/drivers/misc/vc04_services/interface/vchi/vchi_common.h
-@@ -0,0 +1,175 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHI_COMMON_H_
-+#define VCHI_COMMON_H_
-+
-+
-+//flags used when sending messages (must be bitmapped)
-+typedef enum
-+{
-+ VCHI_FLAGS_NONE = 0x0,
-+ VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE = 0x1, // waits for message to be received, or sent (NB. not the same as being seen on other side)
-+ VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE = 0x2, // run a callback when message sent
-+ VCHI_FLAGS_BLOCK_UNTIL_QUEUED = 0x4, // return once the transfer is in a queue ready to go
-+ VCHI_FLAGS_ALLOW_PARTIAL = 0x8,
-+ VCHI_FLAGS_BLOCK_UNTIL_DATA_READ = 0x10,
-+ VCHI_FLAGS_CALLBACK_WHEN_DATA_READ = 0x20,
-+
-+ VCHI_FLAGS_ALIGN_SLOT = 0x000080, // internal use only
-+ VCHI_FLAGS_BULK_AUX_QUEUED = 0x010000, // internal use only
-+ VCHI_FLAGS_BULK_AUX_COMPLETE = 0x020000, // internal use only
-+ VCHI_FLAGS_BULK_DATA_QUEUED = 0x040000, // internal use only
-+ VCHI_FLAGS_BULK_DATA_COMPLETE = 0x080000, // internal use only
-+ VCHI_FLAGS_INTERNAL = 0xFF0000
-+} VCHI_FLAGS_T;
-+
-+// constants for vchi_crc_control()
-+typedef enum {
-+ VCHI_CRC_NOTHING = -1,
-+ VCHI_CRC_PER_SERVICE = 0,
-+ VCHI_CRC_EVERYTHING = 1,
-+} VCHI_CRC_CONTROL_T;
-+
-+//callback reasons when an event occurs on a service
-+typedef enum
-+{
-+ VCHI_CALLBACK_REASON_MIN,
-+
-+ //This indicates that there is data available
-+ //handle is the msg id that was transmitted with the data
-+ // When a message is received and there was no FULL message available previously, send callback
-+ // Tasks get kicked by the callback, reset their event and try and read from the fifo until it fails
-+ VCHI_CALLBACK_MSG_AVAILABLE,
-+ VCHI_CALLBACK_MSG_SENT,
-+ VCHI_CALLBACK_MSG_SPACE_AVAILABLE, // XXX not yet implemented
-+
-+ // This indicates that a transfer from the other side has completed
-+ VCHI_CALLBACK_BULK_RECEIVED,
-+ //This indicates that data queued up to be sent has now gone
-+ //handle is the msg id that was used when sending the data
-+ VCHI_CALLBACK_BULK_SENT,
-+ VCHI_CALLBACK_BULK_RX_SPACE_AVAILABLE, // XXX not yet implemented
-+ VCHI_CALLBACK_BULK_TX_SPACE_AVAILABLE, // XXX not yet implemented
-+
-+ VCHI_CALLBACK_SERVICE_CLOSED,
-+
-+ // this side has sent XOFF to peer due to lack of data consumption by service
-+ // (suggests the service may need to take some recovery action if it has
-+ // been deliberately holding off consuming data)
-+ VCHI_CALLBACK_SENT_XOFF,
-+ VCHI_CALLBACK_SENT_XON,
-+
-+ // indicates that a bulk transfer has finished reading the source buffer
-+ VCHI_CALLBACK_BULK_DATA_READ,
-+
-+ // power notification events (currently host side only)
-+ VCHI_CALLBACK_PEER_OFF,
-+ VCHI_CALLBACK_PEER_SUSPENDED,
-+ VCHI_CALLBACK_PEER_ON,
-+ VCHI_CALLBACK_PEER_RESUMED,
-+ VCHI_CALLBACK_FORCED_POWER_OFF,
-+
-+#ifdef USE_VCHIQ_ARM
-+ // some extra notifications provided by vchiq_arm
-+ VCHI_CALLBACK_SERVICE_OPENED,
-+ VCHI_CALLBACK_BULK_RECEIVE_ABORTED,
-+ VCHI_CALLBACK_BULK_TRANSMIT_ABORTED,
-+#endif
-+
-+ VCHI_CALLBACK_REASON_MAX
-+} VCHI_CALLBACK_REASON_T;
-+
-+// service control options
-+typedef enum
-+{
-+ VCHI_SERVICE_OPTION_MIN,
-+
-+ VCHI_SERVICE_OPTION_TRACE,
-+ VCHI_SERVICE_OPTION_SYNCHRONOUS,
-+
-+ VCHI_SERVICE_OPTION_MAX
-+} VCHI_SERVICE_OPTION_T;
-+
-+
-+//Callback used by all services / bulk transfers
-+typedef void (*VCHI_CALLBACK_T)( void *callback_param, //my service local param
-+ VCHI_CALLBACK_REASON_T reason,
-+ void *handle ); //for transmitting msg's only
-+
-+
-+
-+/*
-+ * Define vector struct for scatter-gather (vector) operations
-+ * Vectors can be nested - if a vector element has negative length, then
-+ * the data pointer is treated as pointing to another vector array, with
-+ * '-vec_len' elements. Thus to append a header onto an existing vector,
-+ * you can do this:
-+ *
-+ * void foo(const VCHI_MSG_VECTOR_T *v, int n)
-+ * {
-+ * VCHI_MSG_VECTOR_T nv[2];
-+ * nv[0].vec_base = my_header;
-+ * nv[0].vec_len = sizeof my_header;
-+ * nv[1].vec_base = v;
-+ * nv[1].vec_len = -n;
-+ * ...
-+ *
-+ */
-+typedef struct vchi_msg_vector {
-+ const void *vec_base;
-+ int32_t vec_len;
-+} VCHI_MSG_VECTOR_T;
-+
-+// Opaque type for a connection API
-+typedef struct opaque_vchi_connection_api_t VCHI_CONNECTION_API_T;
-+
-+// Opaque type for a message driver
-+typedef struct opaque_vchi_message_driver_t VCHI_MESSAGE_DRIVER_T;
-+
-+
-+// Iterator structure for reading ahead through received message queue. Allocated by client,
-+// initialised by vchi_msg_look_ahead. Fields are for internal VCHI use only.
-+// Iterates over messages in queue at the instant of the call to vchi_msg_lookahead -
-+// will not proceed to messages received since. Behaviour is undefined if an iterator
-+// is used again after messages for that service are removed/dequeued by any
-+// means other than vchi_msg_iter_... calls on the iterator itself.
-+typedef struct {
-+ struct opaque_vchi_service_t *service;
-+ void *last;
-+ void *next;
-+ void *remove;
-+} VCHI_MSG_ITER_T;
-+
-+
-+#endif // VCHI_COMMON_H_
---- /dev/null
-+++ b/drivers/misc/vc04_services/interface/vchi/vchi_mh.h
-@@ -0,0 +1,42 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHI_MH_H_
-+#define VCHI_MH_H_
-+
-+#include <linux/types.h>
-+
-+typedef int32_t VCHI_MEM_HANDLE_T;
-+#define VCHI_MEM_HANDLE_INVALID 0
-+
-+#endif
---- /dev/null
-+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq.h
-@@ -0,0 +1,40 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHIQ_VCHIQ_H
-+#define VCHIQ_VCHIQ_H
-+
-+#include "vchiq_if.h"
-+#include "vchiq_util.h"
-+
-+#endif
---- /dev/null
-+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835.h
-@@ -0,0 +1,42 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHIQ_2835_H
-+#define VCHIQ_2835_H
-+
-+#include "vchiq_pagelist.h"
-+
-+#define VCHIQ_PLATFORM_FRAGMENTS_OFFSET_IDX 0
-+#define VCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX 1
-+
-+#endif /* VCHIQ_2835_H */
---- /dev/null
-+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
-@@ -0,0 +1,586 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/types.h>
-+#include <linux/errno.h>
-+#include <linux/interrupt.h>
-+#include <linux/pagemap.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/version.h>
-+#include <linux/io.h>
-+#include <linux/platform_device.h>
-+#include <linux/uaccess.h>
-+#include <linux/of.h>
-+#include <asm/pgtable.h>
-+#include <soc/bcm2835/raspberrypi-firmware.h>
-+
-+#define dmac_map_area __glue(_CACHE,_dma_map_area)
-+#define dmac_unmap_area __glue(_CACHE,_dma_unmap_area)
-+
-+extern void dmac_map_area(const void *, size_t, int);
-+extern void dmac_unmap_area(const void *, size_t, int);
-+
-+#define TOTAL_SLOTS (VCHIQ_SLOT_ZERO_SLOTS + 2 * 32)
-+
-+#define VCHIQ_ARM_ADDRESS(x) ((void *)((char *)x + g_virt_to_bus_offset))
-+
-+#include "vchiq_arm.h"
-+#include "vchiq_2835.h"
-+#include "vchiq_connected.h"
-+#include "vchiq_killable.h"
-+
-+#define MAX_FRAGMENTS (VCHIQ_NUM_CURRENT_BULKS * 2)
-+
-+#define BELL0 0x00
-+#define BELL2 0x08
-+
-+typedef struct vchiq_2835_state_struct {
-+ int inited;
-+ VCHIQ_ARM_STATE_T arm_state;
-+} VCHIQ_2835_ARM_STATE_T;
-+
-+static void __iomem *g_regs;
-+static unsigned int g_cache_line_size = sizeof(CACHE_LINE_SIZE);
-+static unsigned int g_fragments_size;
-+static char *g_fragments_base;
-+static char *g_free_fragments;
-+static struct semaphore g_free_fragments_sema;
-+static unsigned long g_virt_to_bus_offset;
-+
-+extern int vchiq_arm_log_level;
-+
-+static DEFINE_SEMAPHORE(g_free_fragments_mutex);
-+
-+static irqreturn_t
-+vchiq_doorbell_irq(int irq, void *dev_id);
-+
-+static int
-+create_pagelist(char __user *buf, size_t count, unsigned short type,
-+ struct task_struct *task, PAGELIST_T ** ppagelist);
-+
-+static void
-+free_pagelist(PAGELIST_T *pagelist, int actual);
-+
-+int vchiq_platform_init(struct platform_device *pdev, VCHIQ_STATE_T *state)
-+{
-+ struct device *dev = &pdev->dev;
-+ struct rpi_firmware *fw = platform_get_drvdata(pdev);
-+ VCHIQ_SLOT_ZERO_T *vchiq_slot_zero;
-+ struct resource *res;
-+ void *slot_mem;
-+ dma_addr_t slot_phys;
-+ u32 channelbase;
-+ int slot_mem_size, frag_mem_size;
-+ int err, irq, i;
-+
-+ g_virt_to_bus_offset = virt_to_dma(dev, (void *)0);
-+
-+ (void)of_property_read_u32(dev->of_node, "cache-line-size",
-+ &g_cache_line_size);
-+ g_fragments_size = 2 * g_cache_line_size;
-+
-+ /* Allocate space for the channels in coherent memory */
-+ slot_mem_size = PAGE_ALIGN(TOTAL_SLOTS * VCHIQ_SLOT_SIZE);
-+ frag_mem_size = PAGE_ALIGN(g_fragments_size * MAX_FRAGMENTS);
-+
-+ slot_mem = dmam_alloc_coherent(dev, slot_mem_size + frag_mem_size,
-+ &slot_phys, GFP_KERNEL);
-+ if (!slot_mem) {
-+ dev_err(dev, "could not allocate DMA memory\n");
-+ return -ENOMEM;
-+ }
-+
-+ WARN_ON(((int)slot_mem & (PAGE_SIZE - 1)) != 0);
-+
-+ vchiq_slot_zero = vchiq_init_slots(slot_mem, slot_mem_size);
-+ if (!vchiq_slot_zero)
-+ return -EINVAL;
-+
-+ vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_OFFSET_IDX] =
-+ (int)slot_phys + slot_mem_size;
-+ vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX] =
-+ MAX_FRAGMENTS;
-+
-+ g_fragments_base = (char *)slot_mem + slot_mem_size;
-+ slot_mem_size += frag_mem_size;
-+
-+ g_free_fragments = g_fragments_base;
-+ for (i = 0; i < (MAX_FRAGMENTS - 1); i++) {
-+ *(char **)&g_fragments_base[i*g_fragments_size] =
-+ &g_fragments_base[(i + 1)*g_fragments_size];
-+ }
-+ *(char **)&g_fragments_base[i * g_fragments_size] = NULL;
-+ sema_init(&g_free_fragments_sema, MAX_FRAGMENTS);
-+
-+ if (vchiq_init_state(state, vchiq_slot_zero, 0) != VCHIQ_SUCCESS)
-+ return -EINVAL;
-+
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ g_regs = devm_ioremap_resource(&pdev->dev, res);
-+ if (IS_ERR(g_regs))
-+ return PTR_ERR(g_regs);
-+
-+ irq = platform_get_irq(pdev, 0);
-+ if (irq <= 0) {
-+ dev_err(dev, "failed to get IRQ\n");
-+ return irq;
-+ }
-+
-+ err = devm_request_irq(dev, irq, vchiq_doorbell_irq, IRQF_IRQPOLL,
-+ "VCHIQ doorbell", state);
-+ if (err) {
-+ dev_err(dev, "failed to register irq=%d\n", irq);
-+ return err;
-+ }
-+
-+ /* Send the base address of the slots to VideoCore */
-+ channelbase = slot_phys;
-+ err = rpi_firmware_property(fw, RPI_FIRMWARE_VCHIQ_INIT,
-+ &channelbase, sizeof(channelbase));
-+ if (err || channelbase) {
-+ dev_err(dev, "failed to set channelbase\n");
-+ return err ? : -ENXIO;
-+ }
-+
-+ vchiq_log_info(vchiq_arm_log_level,
-+ "vchiq_init - done (slots %x, phys %pad)",
-+ (unsigned int)vchiq_slot_zero, &slot_phys);
-+
-+ vchiq_call_connected_callbacks();
-+
-+ return 0;
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_platform_init_state(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
-+ state->platform_state = kzalloc(sizeof(VCHIQ_2835_ARM_STATE_T), GFP_KERNEL);
-+ ((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->inited = 1;
-+ status = vchiq_arm_init_state(state, &((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->arm_state);
-+ if(status != VCHIQ_SUCCESS)
-+ {
-+ ((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->inited = 0;
-+ }
-+ return status;
-+}
-+
-+VCHIQ_ARM_STATE_T*
-+vchiq_platform_get_arm_state(VCHIQ_STATE_T *state)
-+{
-+ if(!((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->inited)
-+ {
-+ BUG();
-+ }
-+ return &((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->arm_state;
-+}
-+
-+void
-+remote_event_signal(REMOTE_EVENT_T *event)
-+{
-+ wmb();
-+
-+ event->fired = 1;
-+
-+ dsb(); /* data barrier operation */
-+
-+ if (event->armed)
-+ writel(0, g_regs + BELL2); /* trigger vc interrupt */
-+}
-+
-+int
-+vchiq_copy_from_user(void *dst, const void *src, int size)
-+{
-+ if ((uint32_t)src < TASK_SIZE) {
-+ return copy_from_user(dst, src, size);
-+ } else {
-+ memcpy(dst, src, size);
-+ return 0;
-+ }
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_prepare_bulk_data(VCHIQ_BULK_T *bulk, VCHI_MEM_HANDLE_T memhandle,
-+ void *offset, int size, int dir)
-+{
-+ PAGELIST_T *pagelist;
-+ int ret;
-+
-+ WARN_ON(memhandle != VCHI_MEM_HANDLE_INVALID);
-+
-+ ret = create_pagelist((char __user *)offset, size,
-+ (dir == VCHIQ_BULK_RECEIVE)
-+ ? PAGELIST_READ
-+ : PAGELIST_WRITE,
-+ current,
-+ &pagelist);
-+ if (ret != 0)
-+ return VCHIQ_ERROR;
-+
-+ bulk->handle = memhandle;
-+ bulk->data = VCHIQ_ARM_ADDRESS(pagelist);
-+
-+ /* Store the pagelist address in remote_data, which isn't used by the
-+ slave. */
-+ bulk->remote_data = pagelist;
-+
-+ return VCHIQ_SUCCESS;
-+}
-+
-+void
-+vchiq_complete_bulk(VCHIQ_BULK_T *bulk)
-+{
-+ if (bulk && bulk->remote_data && bulk->actual)
-+ free_pagelist((PAGELIST_T *)bulk->remote_data, bulk->actual);
-+}
-+
-+void
-+vchiq_transfer_bulk(VCHIQ_BULK_T *bulk)
-+{
-+ /*
-+ * This should only be called on the master (VideoCore) side, but
-+ * provide an implementation to avoid the need for ifdefery.
-+ */
-+ BUG();
-+}
-+
-+void
-+vchiq_dump_platform_state(void *dump_context)
-+{
-+ char buf[80];
-+ int len;
-+ len = snprintf(buf, sizeof(buf),
-+ " Platform: 2835 (VC master)");
-+ vchiq_dump(dump_context, buf, len + 1);
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_platform_suspend(VCHIQ_STATE_T *state)
-+{
-+ return VCHIQ_ERROR;
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_platform_resume(VCHIQ_STATE_T *state)
-+{
-+ return VCHIQ_SUCCESS;
-+}
-+
-+void
-+vchiq_platform_paused(VCHIQ_STATE_T *state)
-+{
-+}
-+
-+void
-+vchiq_platform_resumed(VCHIQ_STATE_T *state)
-+{
-+}
-+
-+int
-+vchiq_platform_videocore_wanted(VCHIQ_STATE_T* state)
-+{
-+ return 1; // autosuspend not supported - videocore always wanted
-+}
-+
-+int
-+vchiq_platform_use_suspend_timer(void)
-+{
-+ return 0;
-+}
-+void
-+vchiq_dump_platform_use_state(VCHIQ_STATE_T *state)
-+{
-+ vchiq_log_info(vchiq_arm_log_level, "Suspend timer not in use");
-+}
-+void
-+vchiq_platform_handle_timeout(VCHIQ_STATE_T *state)
-+{
-+ (void)state;
-+}
-+/*
-+ * Local functions
-+ */
-+
-+static irqreturn_t
-+vchiq_doorbell_irq(int irq, void *dev_id)
-+{
-+ VCHIQ_STATE_T *state = dev_id;
-+ irqreturn_t ret = IRQ_NONE;
-+ unsigned int status;
-+
-+ /* Read (and clear) the doorbell */
-+ status = readl(g_regs + BELL0);
-+
-+ if (status & 0x4) { /* Was the doorbell rung? */
-+ remote_event_pollall(state);
-+ ret = IRQ_HANDLED;
-+ }
-+
-+ return ret;
-+}
-+
-+/* There is a potential problem with partial cache lines (pages?)
-+** at the ends of the block when reading. If the CPU accessed anything in
-+** the same line (page?) then it may have pulled old data into the cache,
-+** obscuring the new data underneath. We can solve this by transferring the
-+** partial cache lines separately, and allowing the ARM to copy into the
-+** cached area.
-+
-+** N.B. This implementation plays slightly fast and loose with the Linux
-+** driver programming rules, e.g. its use of dmac_map_area instead of
-+** dma_map_single, but it isn't a multi-platform driver and it benefits
-+** from increased speed as a result.
-+*/
-+
-+static int
-+create_pagelist(char __user *buf, size_t count, unsigned short type,
-+ struct task_struct *task, PAGELIST_T ** ppagelist)
-+{
-+ PAGELIST_T *pagelist;
-+ struct page **pages;
-+ unsigned long *addrs;
-+ unsigned int num_pages, offset, i;
-+ char *addr, *base_addr, *next_addr;
-+ int run, addridx, actual_pages;
-+ unsigned long *need_release;
-+
-+ offset = (unsigned int)buf & (PAGE_SIZE - 1);
-+ num_pages = (count + offset + PAGE_SIZE - 1) / PAGE_SIZE;
-+
-+ *ppagelist = NULL;
-+
-+ /* Allocate enough storage to hold the page pointers and the page
-+ ** list
-+ */
-+ pagelist = kmalloc(sizeof(PAGELIST_T) +
-+ (num_pages * sizeof(unsigned long)) +
-+ sizeof(unsigned long) +
-+ (num_pages * sizeof(pages[0])),
-+ GFP_KERNEL);
-+
-+ vchiq_log_trace(vchiq_arm_log_level,
-+ "create_pagelist - %x", (unsigned int)pagelist);
-+ if (!pagelist)
-+ return -ENOMEM;
-+
-+ addrs = pagelist->addrs;
-+ need_release = (unsigned long *)(addrs + num_pages);
-+ pages = (struct page **)(addrs + num_pages + 1);
-+
-+ if (is_vmalloc_addr(buf)) {
-+ int dir = (type == PAGELIST_WRITE) ?
-+ DMA_TO_DEVICE : DMA_FROM_DEVICE;
-+ unsigned long length = count;
-+ unsigned int off = offset;
-+
-+ for (actual_pages = 0; actual_pages < num_pages;
-+ actual_pages++) {
-+ struct page *pg = vmalloc_to_page(buf + (actual_pages *
-+ PAGE_SIZE));
-+ size_t bytes = PAGE_SIZE - off;
-+
-+ if (bytes > length)
-+ bytes = length;
-+ pages[actual_pages] = pg;
-+ dmac_map_area(page_address(pg) + off, bytes, dir);
-+ length -= bytes;
-+ off = 0;
-+ }
-+ *need_release = 0; /* do not try and release vmalloc pages */
-+ } else {
-+ down_read(&task->mm->mmap_sem);
-+ actual_pages = get_user_pages(task, task->mm,
-+ (unsigned long)buf & ~(PAGE_SIZE - 1),
-+ num_pages,
-+ (type == PAGELIST_READ) /*Write */ ,
-+ 0 /*Force */ ,
-+ pages,
-+ NULL /*vmas */);
-+ up_read(&task->mm->mmap_sem);
-+
-+ if (actual_pages != num_pages) {
-+ vchiq_log_info(vchiq_arm_log_level,
-+ "create_pagelist - only %d/%d pages locked",
-+ actual_pages,
-+ num_pages);
-+
-+ /* This is probably due to the process being killed */
-+ while (actual_pages > 0)
-+ {
-+ actual_pages--;
-+ page_cache_release(pages[actual_pages]);
-+ }
-+ kfree(pagelist);
-+ if (actual_pages == 0)
-+ actual_pages = -ENOMEM;
-+ return actual_pages;
-+ }
-+ *need_release = 1; /* release user pages */
-+ }
-+
-+ pagelist->length = count;
-+ pagelist->type = type;
-+ pagelist->offset = offset;
-+
-+ /* Group the pages into runs of contiguous pages */
-+
-+ base_addr = VCHIQ_ARM_ADDRESS(page_address(pages[0]));
-+ next_addr = base_addr + PAGE_SIZE;
-+ addridx = 0;
-+ run = 0;
-+
-+ for (i = 1; i < num_pages; i++) {
-+ addr = VCHIQ_ARM_ADDRESS(page_address(pages[i]));
-+ if ((addr == next_addr) && (run < (PAGE_SIZE - 1))) {
-+ next_addr += PAGE_SIZE;
-+ run++;
-+ } else {
-+ addrs[addridx] = (unsigned long)base_addr + run;
-+ addridx++;
-+ base_addr = addr;
-+ next_addr = addr + PAGE_SIZE;
-+ run = 0;
-+ }
-+ }
-+
-+ addrs[addridx] = (unsigned long)base_addr + run;
-+ addridx++;
-+
-+ /* Partial cache lines (fragments) require special measures */
-+ if ((type == PAGELIST_READ) &&
-+ ((pagelist->offset & (g_cache_line_size - 1)) ||
-+ ((pagelist->offset + pagelist->length) &
-+ (g_cache_line_size - 1)))) {
-+ char *fragments;
-+
-+ if (down_interruptible(&g_free_fragments_sema) != 0) {
-+ kfree(pagelist);
-+ return -EINTR;
-+ }
-+
-+ WARN_ON(g_free_fragments == NULL);
-+
-+ down(&g_free_fragments_mutex);
-+ fragments = g_free_fragments;
-+ WARN_ON(fragments == NULL);
-+ g_free_fragments = *(char **) g_free_fragments;
-+ up(&g_free_fragments_mutex);
-+ pagelist->type = PAGELIST_READ_WITH_FRAGMENTS +
-+ (fragments - g_fragments_base) / g_fragments_size;
-+ }
-+
-+ dmac_flush_range(pagelist, addrs + num_pages);
-+
-+ *ppagelist = pagelist;
-+
-+ return 0;
-+}
-+
-+static void
-+free_pagelist(PAGELIST_T *pagelist, int actual)
-+{
-+ unsigned long *need_release;
-+ struct page **pages;
-+ unsigned int num_pages, i;
-+
-+ vchiq_log_trace(vchiq_arm_log_level,
-+ "free_pagelist - %x, %d", (unsigned int)pagelist, actual);
-+
-+ num_pages =
-+ (pagelist->length + pagelist->offset + PAGE_SIZE - 1) /
-+ PAGE_SIZE;
-+
-+ need_release = (unsigned long *)(pagelist->addrs + num_pages);
-+ pages = (struct page **)(pagelist->addrs + num_pages + 1);
-+
-+ /* Deal with any partial cache lines (fragments) */
-+ if (pagelist->type >= PAGELIST_READ_WITH_FRAGMENTS) {
-+ char *fragments = g_fragments_base +
-+ (pagelist->type - PAGELIST_READ_WITH_FRAGMENTS) *
-+ g_fragments_size;
-+ int head_bytes, tail_bytes;
-+ head_bytes = (g_cache_line_size - pagelist->offset) &
-+ (g_cache_line_size - 1);
-+ tail_bytes = (pagelist->offset + actual) &
-+ (g_cache_line_size - 1);
-+
-+ if ((actual >= 0) && (head_bytes != 0)) {
-+ if (head_bytes > actual)
-+ head_bytes = actual;
-+
-+ memcpy((char *)page_address(pages[0]) +
-+ pagelist->offset,
-+ fragments,
-+ head_bytes);
-+ }
-+ if ((actual >= 0) && (head_bytes < actual) &&
-+ (tail_bytes != 0)) {
-+ memcpy((char *)page_address(pages[num_pages - 1]) +
-+ ((pagelist->offset + actual) &
-+ (PAGE_SIZE - 1) & ~(g_cache_line_size - 1)),
-+ fragments + g_cache_line_size,
-+ tail_bytes);
-+ }
-+
-+ down(&g_free_fragments_mutex);
-+ *(char **)fragments = g_free_fragments;
-+ g_free_fragments = fragments;
-+ up(&g_free_fragments_mutex);
-+ up(&g_free_fragments_sema);
-+ }
-+
-+ if (*need_release) {
-+ unsigned int length = pagelist->length;
-+ unsigned int offset = pagelist->offset;
-+
-+ for (i = 0; i < num_pages; i++) {
-+ struct page *pg = pages[i];
-+
-+ if (pagelist->type != PAGELIST_WRITE) {
-+ unsigned int bytes = PAGE_SIZE - offset;
-+
-+ if (bytes > length)
-+ bytes = length;
-+ dmac_unmap_area(page_address(pg) + offset,
-+ bytes, DMA_FROM_DEVICE);
-+ length -= bytes;
-+ offset = 0;
-+ set_page_dirty(pg);
-+ }
-+ page_cache_release(pg);
-+ }
-+ }
-+
-+ kfree(pagelist);
-+}
---- /dev/null
-+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c
-@@ -0,0 +1,2903 @@
-+/**
-+ * Copyright (c) 2014 Raspberry Pi (Trading) Ltd. All rights reserved.
-+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/errno.h>
-+#include <linux/cdev.h>
-+#include <linux/fs.h>
-+#include <linux/device.h>
-+#include <linux/mm.h>
-+#include <linux/highmem.h>
-+#include <linux/pagemap.h>
-+#include <linux/bug.h>
-+#include <linux/semaphore.h>
-+#include <linux/list.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <soc/bcm2835/raspberrypi-firmware.h>
-+
-+#include "vchiq_core.h"
-+#include "vchiq_ioctl.h"
-+#include "vchiq_arm.h"
-+#include "vchiq_debugfs.h"
-+#include "vchiq_killable.h"
-+
-+#define DEVICE_NAME "vchiq"
-+
-+/* Override the default prefix, which would be vchiq_arm (from the filename) */
-+#undef MODULE_PARAM_PREFIX
-+#define MODULE_PARAM_PREFIX DEVICE_NAME "."
-+
-+#define VCHIQ_MINOR 0
-+
-+/* Some per-instance constants */
-+#define MAX_COMPLETIONS 16
-+#define MAX_SERVICES 64
-+#define MAX_ELEMENTS 8
-+#define MSG_QUEUE_SIZE 64
-+
-+#define KEEPALIVE_VER 1
-+#define KEEPALIVE_VER_MIN KEEPALIVE_VER
-+
-+/* Run time control of log level, based on KERN_XXX level. */
-+int vchiq_arm_log_level = VCHIQ_LOG_DEFAULT;
-+int vchiq_susp_log_level = VCHIQ_LOG_ERROR;
-+
-+#define SUSPEND_TIMER_TIMEOUT_MS 100
-+#define SUSPEND_RETRY_TIMER_TIMEOUT_MS 1000
-+
-+#define VC_SUSPEND_NUM_OFFSET 3 /* number of values before idle which are -ve */
-+static const char *const suspend_state_names[] = {
-+ "VC_SUSPEND_FORCE_CANCELED",
-+ "VC_SUSPEND_REJECTED",
-+ "VC_SUSPEND_FAILED",
-+ "VC_SUSPEND_IDLE",
-+ "VC_SUSPEND_REQUESTED",
-+ "VC_SUSPEND_IN_PROGRESS",
-+ "VC_SUSPEND_SUSPENDED"
-+};
-+#define VC_RESUME_NUM_OFFSET 1 /* number of values before idle which are -ve */
-+static const char *const resume_state_names[] = {
-+ "VC_RESUME_FAILED",
-+ "VC_RESUME_IDLE",
-+ "VC_RESUME_REQUESTED",
-+ "VC_RESUME_IN_PROGRESS",
-+ "VC_RESUME_RESUMED"
-+};
-+/* The number of times we allow force suspend to timeout before actually
-+** _forcing_ suspend. This is to cater for SW which fails to release vchiq
-+** correctly - we don't want to prevent ARM suspend indefinitely in this case.
-+*/
-+#define FORCE_SUSPEND_FAIL_MAX 8
-+
-+/* The time in ms allowed for videocore to go idle when force suspend has been
-+ * requested */
-+#define FORCE_SUSPEND_TIMEOUT_MS 200
-+
-+
-+static void suspend_timer_callback(unsigned long context);
-+
-+
-+typedef struct user_service_struct {
-+ VCHIQ_SERVICE_T *service;
-+ void *userdata;
-+ VCHIQ_INSTANCE_T instance;
-+ char is_vchi;
-+ char dequeue_pending;
-+ char close_pending;
-+ int message_available_pos;
-+ int msg_insert;
-+ int msg_remove;
-+ struct semaphore insert_event;
-+ struct semaphore remove_event;
-+ struct semaphore close_event;
-+ VCHIQ_HEADER_T * msg_queue[MSG_QUEUE_SIZE];
-+} USER_SERVICE_T;
-+
-+struct bulk_waiter_node {
-+ struct bulk_waiter bulk_waiter;
-+ int pid;
-+ struct list_head list;
-+};
-+
-+struct vchiq_instance_struct {
-+ VCHIQ_STATE_T *state;
-+ VCHIQ_COMPLETION_DATA_T completions[MAX_COMPLETIONS];
-+ int completion_insert;
-+ int completion_remove;
-+ struct semaphore insert_event;
-+ struct semaphore remove_event;
-+ struct mutex completion_mutex;
-+
-+ int connected;
-+ int closing;
-+ int pid;
-+ int mark;
-+ int use_close_delivered;
-+ int trace;
-+
-+ struct list_head bulk_waiter_list;
-+ struct mutex bulk_waiter_list_mutex;
-+
-+ VCHIQ_DEBUGFS_NODE_T debugfs_node;
-+};
-+
-+typedef struct dump_context_struct {
-+ char __user *buf;
-+ size_t actual;
-+ size_t space;
-+ loff_t offset;
-+} DUMP_CONTEXT_T;
-+
-+static struct cdev vchiq_cdev;
-+static dev_t vchiq_devid;
-+static VCHIQ_STATE_T g_state;
-+static struct class *vchiq_class;
-+static struct device *vchiq_dev;
-+static DEFINE_SPINLOCK(msg_queue_spinlock);
-+
-+static const char *const ioctl_names[] = {
-+ "CONNECT",
-+ "SHUTDOWN",
-+ "CREATE_SERVICE",
-+ "REMOVE_SERVICE",
-+ "QUEUE_MESSAGE",
-+ "QUEUE_BULK_TRANSMIT",
-+ "QUEUE_BULK_RECEIVE",
-+ "AWAIT_COMPLETION",
-+ "DEQUEUE_MESSAGE",
-+ "GET_CLIENT_ID",
-+ "GET_CONFIG",
-+ "CLOSE_SERVICE",
-+ "USE_SERVICE",
-+ "RELEASE_SERVICE",
-+ "SET_SERVICE_OPTION",
-+ "DUMP_PHYS_MEM",
-+ "LIB_VERSION",
-+ "CLOSE_DELIVERED"
-+};
-+
-+vchiq_static_assert((sizeof(ioctl_names)/sizeof(ioctl_names[0])) ==
-+ (VCHIQ_IOC_MAX + 1));
-+
-+static void
-+dump_phys_mem(void *virt_addr, uint32_t num_bytes);
-+
-+/****************************************************************************
-+*
-+* add_completion
-+*
-+***************************************************************************/
-+
-+static VCHIQ_STATUS_T
-+add_completion(VCHIQ_INSTANCE_T instance, VCHIQ_REASON_T reason,
-+ VCHIQ_HEADER_T *header, USER_SERVICE_T *user_service,
-+ void *bulk_userdata)
-+{
-+ VCHIQ_COMPLETION_DATA_T *completion;
-+ DEBUG_INITIALISE(g_state.local)
-+
-+ while (instance->completion_insert ==
-+ (instance->completion_remove + MAX_COMPLETIONS)) {
-+ /* Out of space - wait for the client */
-+ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
-+ vchiq_log_trace(vchiq_arm_log_level,
-+ "add_completion - completion queue full");
-+ DEBUG_COUNT(COMPLETION_QUEUE_FULL_COUNT);
-+ if (down_interruptible(&instance->remove_event) != 0) {
-+ vchiq_log_info(vchiq_arm_log_level,
-+ "service_callback interrupted");
-+ return VCHIQ_RETRY;
-+ } else if (instance->closing) {
-+ vchiq_log_info(vchiq_arm_log_level,
-+ "service_callback closing");
-+ return VCHIQ_ERROR;
-+ }
-+ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
-+ }
-+
-+ completion =
-+ &instance->completions[instance->completion_insert &
-+ (MAX_COMPLETIONS - 1)];
-+
-+ completion->header = header;
-+ completion->reason = reason;
-+ /* N.B. service_userdata is updated while processing AWAIT_COMPLETION */
-+ completion->service_userdata = user_service->service;
-+ completion->bulk_userdata = bulk_userdata;
-+
-+ if (reason == VCHIQ_SERVICE_CLOSED) {
-+ /* Take an extra reference, to be held until
-+ this CLOSED notification is delivered. */
-+ lock_service(user_service->service);
-+ if (instance->use_close_delivered)
-+ user_service->close_pending = 1;
-+ }
-+
-+ /* A write barrier is needed here to ensure that the entire completion
-+ record is written out before the insert point. */
-+ wmb();
-+
-+ if (reason == VCHIQ_MESSAGE_AVAILABLE)
-+ user_service->message_available_pos =
-+ instance->completion_insert;
-+ instance->completion_insert++;
-+
-+ up(&instance->insert_event);
-+
-+ return VCHIQ_SUCCESS;
-+}
-+
-+/****************************************************************************
-+*
-+* service_callback
-+*
-+***************************************************************************/
-+
-+static VCHIQ_STATUS_T
-+service_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header,
-+ VCHIQ_SERVICE_HANDLE_T handle, void *bulk_userdata)
-+{
-+ /* How do we ensure the callback goes to the right client?
-+ ** The service_user data points to a USER_SERVICE_T record containing
-+ ** the original callback and the user state structure, which contains a
-+ ** circular buffer for completion records.
-+ */
-+ USER_SERVICE_T *user_service;
-+ VCHIQ_SERVICE_T *service;
-+ VCHIQ_INSTANCE_T instance;
-+ DEBUG_INITIALISE(g_state.local)
-+
-+ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
-+
-+ service = handle_to_service(handle);
-+ BUG_ON(!service);
-+ user_service = (USER_SERVICE_T *)service->base.userdata;
-+ instance = user_service->instance;
-+
-+ if (!instance || instance->closing)
-+ return VCHIQ_SUCCESS;
-+
-+ vchiq_log_trace(vchiq_arm_log_level,
-+ "service_callback - service %lx(%d,%p), reason %d, header %lx, "
-+ "instance %lx, bulk_userdata %lx",
-+ (unsigned long)user_service,
-+ service->localport, user_service->userdata,
-+ reason, (unsigned long)header,
-+ (unsigned long)instance, (unsigned long)bulk_userdata);
-+
-+ if (header && user_service->is_vchi) {
-+ spin_lock(&msg_queue_spinlock);
-+ while (user_service->msg_insert ==
-+ (user_service->msg_remove + MSG_QUEUE_SIZE)) {
-+ spin_unlock(&msg_queue_spinlock);
-+ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
-+ DEBUG_COUNT(MSG_QUEUE_FULL_COUNT);
-+ vchiq_log_trace(vchiq_arm_log_level,
-+ "service_callback - msg queue full");
-+ /* If there is no MESSAGE_AVAILABLE in the completion
-+ ** queue, add one
-+ */
-+ if ((user_service->message_available_pos -
-+ instance->completion_remove) < 0) {
-+ VCHIQ_STATUS_T status;
-+ vchiq_log_info(vchiq_arm_log_level,
-+ "Inserting extra MESSAGE_AVAILABLE");
-+ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
-+ status = add_completion(instance, reason,
-+ NULL, user_service, bulk_userdata);
-+ if (status != VCHIQ_SUCCESS) {
-+ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
-+ return status;
-+ }
-+ }
-+
-+ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
-+ if (down_interruptible(&user_service->remove_event)
-+ != 0) {
-+ vchiq_log_info(vchiq_arm_log_level,
-+ "service_callback interrupted");
-+ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
-+ return VCHIQ_RETRY;
-+ } else if (instance->closing) {
-+ vchiq_log_info(vchiq_arm_log_level,
-+ "service_callback closing");
-+ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
-+ return VCHIQ_ERROR;
-+ }
-+ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
-+ spin_lock(&msg_queue_spinlock);
-+ }
-+
-+ user_service->msg_queue[user_service->msg_insert &
-+ (MSG_QUEUE_SIZE - 1)] = header;
-+ user_service->msg_insert++;
-+ spin_unlock(&msg_queue_spinlock);
-+
-+ up(&user_service->insert_event);
-+
-+ /* If there is a thread waiting in DEQUEUE_MESSAGE, or if
-+ ** there is a MESSAGE_AVAILABLE in the completion queue then
-+ ** bypass the completion queue.
-+ */
-+ if (((user_service->message_available_pos -
-+ instance->completion_remove) >= 0) ||
-+ user_service->dequeue_pending) {
-+ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
-+ user_service->dequeue_pending = 0;
-+ return VCHIQ_SUCCESS;
-+ }
-+
-+ header = NULL;
-+ }
-+ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
-+
-+ return add_completion(instance, reason, header, user_service,
-+ bulk_userdata);
-+}
-+
-+/****************************************************************************
-+*
-+* user_service_free
-+*
-+***************************************************************************/
-+static void
-+user_service_free(void *userdata)
-+{
-+ kfree(userdata);
-+}
-+
-+/****************************************************************************
-+*
-+* close_delivered
-+*
-+***************************************************************************/
-+static void close_delivered(USER_SERVICE_T *user_service)
-+{
-+ vchiq_log_info(vchiq_arm_log_level,
-+ "close_delivered(handle=%x)",
-+ user_service->service->handle);
-+
-+ if (user_service->close_pending) {
-+ /* Allow the underlying service to be culled */
-+ unlock_service(user_service->service);
-+
-+ /* Wake the user-thread blocked in close_ or remove_service */
-+ up(&user_service->close_event);
-+
-+ user_service->close_pending = 0;
-+ }
-+}
-+
-+/****************************************************************************
-+*
-+* vchiq_ioctl
-+*
-+***************************************************************************/
-+static long
-+vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-+{
-+ VCHIQ_INSTANCE_T instance = file->private_data;
-+ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
-+ VCHIQ_SERVICE_T *service = NULL;
-+ long ret = 0;
-+ int i, rc;
-+ DEBUG_INITIALISE(g_state.local)
-+
-+ vchiq_log_trace(vchiq_arm_log_level,
-+ "vchiq_ioctl - instance %x, cmd %s, arg %lx",
-+ (unsigned int)instance,
-+ ((_IOC_TYPE(cmd) == VCHIQ_IOC_MAGIC) &&
-+ (_IOC_NR(cmd) <= VCHIQ_IOC_MAX)) ?
-+ ioctl_names[_IOC_NR(cmd)] : "<invalid>", arg);
-+
-+ switch (cmd) {
-+ case VCHIQ_IOC_SHUTDOWN:
-+ if (!instance->connected)
-+ break;
-+
-+ /* Remove all services */
-+ i = 0;
-+ while ((service = next_service_by_instance(instance->state,
-+ instance, &i)) != NULL) {
-+ status = vchiq_remove_service(service->handle);
-+ unlock_service(service);
-+ if (status != VCHIQ_SUCCESS)
-+ break;
-+ }
-+ service = NULL;
-+
-+ if (status == VCHIQ_SUCCESS) {
-+ /* Wake the completion thread and ask it to exit */
-+ instance->closing = 1;
-+ up(&instance->insert_event);
-+ }
-+
-+ break;
-+
-+ case VCHIQ_IOC_CONNECT:
-+ if (instance->connected) {
-+ ret = -EINVAL;
-+ break;
-+ }
-+ rc = mutex_lock_interruptible(&instance->state->mutex);
-+ if (rc != 0) {
-+ vchiq_log_error(vchiq_arm_log_level,
-+ "vchiq: connect: could not lock mutex for "
-+ "state %d: %d",
-+ instance->state->id, rc);
-+ ret = -EINTR;
-+ break;
-+ }
-+ status = vchiq_connect_internal(instance->state, instance);
-+ mutex_unlock(&instance->state->mutex);
-+
-+ if (status == VCHIQ_SUCCESS)
-+ instance->connected = 1;
-+ else
-+ vchiq_log_error(vchiq_arm_log_level,
-+ "vchiq: could not connect: %d", status);
-+ break;
-+
-+ case VCHIQ_IOC_CREATE_SERVICE: {
-+ VCHIQ_CREATE_SERVICE_T args;
-+ USER_SERVICE_T *user_service = NULL;
-+ void *userdata;
-+ int srvstate;
-+
-+ if (copy_from_user
-+ (&args, (const void __user *)arg,
-+ sizeof(args)) != 0) {
-+ ret = -EFAULT;
-+ break;
-+ }
-+
-+ user_service = kmalloc(sizeof(USER_SERVICE_T), GFP_KERNEL);
-+ if (!user_service) {
-+ ret = -ENOMEM;
-+ break;
-+ }
-+
-+ if (args.is_open) {
-+ if (!instance->connected) {
-+ ret = -ENOTCONN;
-+ kfree(user_service);
-+ break;
-+ }
-+ srvstate = VCHIQ_SRVSTATE_OPENING;
-+ } else {
-+ srvstate =
-+ instance->connected ?
-+ VCHIQ_SRVSTATE_LISTENING :
-+ VCHIQ_SRVSTATE_HIDDEN;
-+ }
-+
-+ userdata = args.params.userdata;
-+ args.params.callback = service_callback;
-+ args.params.userdata = user_service;
-+ service = vchiq_add_service_internal(
-+ instance->state,
-+ &args.params, srvstate,
-+ instance, user_service_free);
-+
-+ if (service != NULL) {
-+ user_service->service = service;
-+ user_service->userdata = userdata;
-+ user_service->instance = instance;
-+ user_service->is_vchi = (args.is_vchi != 0);
-+ user_service->dequeue_pending = 0;
-+ user_service->close_pending = 0;
-+ user_service->message_available_pos =
-+ instance->completion_remove - 1;
-+ user_service->msg_insert = 0;
-+ user_service->msg_remove = 0;
-+ sema_init(&user_service->insert_event, 0);
-+ sema_init(&user_service->remove_event, 0);
-+ sema_init(&user_service->close_event, 0);
-+
-+ if (args.is_open) {
-+ status = vchiq_open_service_internal
-+ (service, instance->pid);
-+ if (status != VCHIQ_SUCCESS) {
-+ vchiq_remove_service(service->handle);
-+ service = NULL;
-+ ret = (status == VCHIQ_RETRY) ?
-+ -EINTR : -EIO;
-+ break;
-+ }
-+ }
-+
-+ if (copy_to_user((void __user *)
-+ &(((VCHIQ_CREATE_SERVICE_T __user *)
-+ arg)->handle),
-+ (const void *)&service->handle,
-+ sizeof(service->handle)) != 0) {
-+ ret = -EFAULT;
-+ vchiq_remove_service(service->handle);
-+ }
-+
-+ service = NULL;
-+ } else {
-+ ret = -EEXIST;
-+ kfree(user_service);
-+ }
-+ } break;
-+
-+ case VCHIQ_IOC_CLOSE_SERVICE: {
-+ VCHIQ_SERVICE_HANDLE_T handle = (VCHIQ_SERVICE_HANDLE_T)arg;
-+
-+ service = find_service_for_instance(instance, handle);
-+ if (service != NULL) {
-+ USER_SERVICE_T *user_service =
-+ (USER_SERVICE_T *)service->base.userdata;
-+ /* close_pending is false on first entry, and when the
-+ wait in vchiq_close_service has been interrupted. */
-+ if (!user_service->close_pending) {
-+ status = vchiq_close_service(service->handle);
-+ if (status != VCHIQ_SUCCESS)
-+ break;
-+ }
-+
-+ /* close_pending is true once the underlying service
-+ has been closed until the client library calls the
-+ CLOSE_DELIVERED ioctl, signalling close_event. */
-+ if (user_service->close_pending &&
-+ down_interruptible(&user_service->close_event))
-+ status = VCHIQ_RETRY;
-+ }
-+ else
-+ ret = -EINVAL;
-+ } break;
-+
-+ case VCHIQ_IOC_REMOVE_SERVICE: {
-+ VCHIQ_SERVICE_HANDLE_T handle = (VCHIQ_SERVICE_HANDLE_T)arg;
-+
-+ service = find_service_for_instance(instance, handle);
-+ if (service != NULL) {
-+ USER_SERVICE_T *user_service =
-+ (USER_SERVICE_T *)service->base.userdata;
-+ /* close_pending is false on first entry, and when the
-+ wait in vchiq_close_service has been interrupted. */
-+ if (!user_service->close_pending) {
-+ status = vchiq_remove_service(service->handle);
-+ if (status != VCHIQ_SUCCESS)
-+ break;
-+ }
-+
-+ /* close_pending is true once the underlying service
-+ has been closed until the client library calls the
-+ CLOSE_DELIVERED ioctl, signalling close_event. */
-+ if (user_service->close_pending &&
-+ down_interruptible(&user_service->close_event))
-+ status = VCHIQ_RETRY;
-+ }
-+ else
-+ ret = -EINVAL;
-+ } break;
-+
-+ case VCHIQ_IOC_USE_SERVICE:
-+ case VCHIQ_IOC_RELEASE_SERVICE: {
-+ VCHIQ_SERVICE_HANDLE_T handle = (VCHIQ_SERVICE_HANDLE_T)arg;
-+
-+ service = find_service_for_instance(instance, handle);
-+ if (service != NULL) {
-+ status = (cmd == VCHIQ_IOC_USE_SERVICE) ?
-+ vchiq_use_service_internal(service) :
-+ vchiq_release_service_internal(service);
-+ if (status != VCHIQ_SUCCESS) {
-+ vchiq_log_error(vchiq_susp_log_level,
-+ "%s: cmd %s returned error %d for "
-+ "service %c%c%c%c:%03d",
-+ __func__,
-+ (cmd == VCHIQ_IOC_USE_SERVICE) ?
-+ "VCHIQ_IOC_USE_SERVICE" :
-+ "VCHIQ_IOC_RELEASE_SERVICE",
-+ status,
-+ VCHIQ_FOURCC_AS_4CHARS(
-+ service->base.fourcc),
-+ service->client_id);
-+ ret = -EINVAL;
-+ }
-+ } else
-+ ret = -EINVAL;
-+ } break;
-+
-+ case VCHIQ_IOC_QUEUE_MESSAGE: {
-+ VCHIQ_QUEUE_MESSAGE_T args;
-+ if (copy_from_user
-+ (&args, (const void __user *)arg,
-+ sizeof(args)) != 0) {
-+ ret = -EFAULT;
-+ break;
-+ }
-+
-+ service = find_service_for_instance(instance, args.handle);
-+
-+ if ((service != NULL) && (args.count <= MAX_ELEMENTS)) {
-+ /* Copy elements into kernel space */
-+ VCHIQ_ELEMENT_T elements[MAX_ELEMENTS];
-+ if (copy_from_user(elements, args.elements,
-+ args.count * sizeof(VCHIQ_ELEMENT_T)) == 0)
-+ status = vchiq_queue_message
-+ (args.handle,
-+ elements, args.count);
-+ else
-+ ret = -EFAULT;
-+ } else {
-+ ret = -EINVAL;
-+ }
-+ } break;
-+
-+ case VCHIQ_IOC_QUEUE_BULK_TRANSMIT:
-+ case VCHIQ_IOC_QUEUE_BULK_RECEIVE: {
-+ VCHIQ_QUEUE_BULK_TRANSFER_T args;
-+ struct bulk_waiter_node *waiter = NULL;
-+ VCHIQ_BULK_DIR_T dir =
-+ (cmd == VCHIQ_IOC_QUEUE_BULK_TRANSMIT) ?
-+ VCHIQ_BULK_TRANSMIT : VCHIQ_BULK_RECEIVE;
-+
-+ if (copy_from_user
-+ (&args, (const void __user *)arg,
-+ sizeof(args)) != 0) {
-+ ret = -EFAULT;
-+ break;
-+ }
-+
-+ service = find_service_for_instance(instance, args.handle);
-+ if (!service) {
-+ ret = -EINVAL;
-+ break;
-+ }
-+
-+ if (args.mode == VCHIQ_BULK_MODE_BLOCKING) {
-+ waiter = kzalloc(sizeof(struct bulk_waiter_node),
-+ GFP_KERNEL);
-+ if (!waiter) {
-+ ret = -ENOMEM;
-+ break;
-+ }
-+ args.userdata = &waiter->bulk_waiter;
-+ } else if (args.mode == VCHIQ_BULK_MODE_WAITING) {
-+ struct list_head *pos;
-+ mutex_lock(&instance->bulk_waiter_list_mutex);
-+ list_for_each(pos, &instance->bulk_waiter_list) {
-+ if (list_entry(pos, struct bulk_waiter_node,
-+ list)->pid == current->pid) {
-+ waiter = list_entry(pos,
-+ struct bulk_waiter_node,
-+ list);
-+ list_del(pos);
-+ break;
-+ }
-+
-+ }
-+ mutex_unlock(&instance->bulk_waiter_list_mutex);
-+ if (!waiter) {
-+ vchiq_log_error(vchiq_arm_log_level,
-+ "no bulk_waiter found for pid %d",
-+ current->pid);
-+ ret = -ESRCH;
-+ break;
-+ }
-+ vchiq_log_info(vchiq_arm_log_level,
-+ "found bulk_waiter %x for pid %d",
-+ (unsigned int)waiter, current->pid);
-+ args.userdata = &waiter->bulk_waiter;
-+ }
-+ status = vchiq_bulk_transfer
-+ (args.handle,
-+ VCHI_MEM_HANDLE_INVALID,
-+ args.data, args.size,
-+ args.userdata, args.mode,
-+ dir);
-+ if (!waiter)
-+ break;
-+ if ((status != VCHIQ_RETRY) || fatal_signal_pending(current) ||
-+ !waiter->bulk_waiter.bulk) {
-+ if (waiter->bulk_waiter.bulk) {
-+ /* Cancel the signal when the transfer
-+ ** completes. */
-+ spin_lock(&bulk_waiter_spinlock);
-+ waiter->bulk_waiter.bulk->userdata = NULL;
-+ spin_unlock(&bulk_waiter_spinlock);
-+ }
-+ kfree(waiter);
-+ } else {
-+ const VCHIQ_BULK_MODE_T mode_waiting =
-+ VCHIQ_BULK_MODE_WAITING;
-+ waiter->pid = current->pid;
-+ mutex_lock(&instance->bulk_waiter_list_mutex);
-+ list_add(&waiter->list, &instance->bulk_waiter_list);
-+ mutex_unlock(&instance->bulk_waiter_list_mutex);
-+ vchiq_log_info(vchiq_arm_log_level,
-+ "saved bulk_waiter %x for pid %d",
-+ (unsigned int)waiter, current->pid);
-+
-+ if (copy_to_user((void __user *)
-+ &(((VCHIQ_QUEUE_BULK_TRANSFER_T __user *)
-+ arg)->mode),
-+ (const void *)&mode_waiting,
-+ sizeof(mode_waiting)) != 0)
-+ ret = -EFAULT;
-+ }
-+ } break;
-+
-+ case VCHIQ_IOC_AWAIT_COMPLETION: {
-+ VCHIQ_AWAIT_COMPLETION_T args;
-+
-+ DEBUG_TRACE(AWAIT_COMPLETION_LINE);
-+ if (!instance->connected) {
-+ ret = -ENOTCONN;
-+ break;
-+ }
-+
-+ if (copy_from_user(&args, (const void __user *)arg,
-+ sizeof(args)) != 0) {
-+ ret = -EFAULT;
-+ break;
-+ }
-+
-+ mutex_lock(&instance->completion_mutex);
-+
-+ DEBUG_TRACE(AWAIT_COMPLETION_LINE);
-+ while ((instance->completion_remove ==
-+ instance->completion_insert)
-+ && !instance->closing) {
-+ int rc;
-+ DEBUG_TRACE(AWAIT_COMPLETION_LINE);
-+ mutex_unlock(&instance->completion_mutex);
-+ rc = down_interruptible(&instance->insert_event);
-+ mutex_lock(&instance->completion_mutex);
-+ if (rc != 0) {
-+ DEBUG_TRACE(AWAIT_COMPLETION_LINE);
-+ vchiq_log_info(vchiq_arm_log_level,
-+ "AWAIT_COMPLETION interrupted");
-+ ret = -EINTR;
-+ break;
-+ }
-+ }
-+ DEBUG_TRACE(AWAIT_COMPLETION_LINE);
-+
-+ /* A read memory barrier is needed to stop prefetch of a stale
-+ ** completion record
-+ */
-+ rmb();
-+
-+ if (ret == 0) {
-+ int msgbufcount = args.msgbufcount;
-+ for (ret = 0; ret < args.count; ret++) {
-+ VCHIQ_COMPLETION_DATA_T *completion;
-+ VCHIQ_SERVICE_T *service;
-+ USER_SERVICE_T *user_service;
-+ VCHIQ_HEADER_T *header;
-+ if (instance->completion_remove ==
-+ instance->completion_insert)
-+ break;
-+ completion = &instance->completions[
-+ instance->completion_remove &
-+ (MAX_COMPLETIONS - 1)];
-+
-+ service = completion->service_userdata;
-+ user_service = service->base.userdata;
-+ completion->service_userdata =
-+ user_service->userdata;
-+
-+ header = completion->header;
-+ if (header) {
-+ void __user *msgbuf;
-+ int msglen;
-+
-+ msglen = header->size +
-+ sizeof(VCHIQ_HEADER_T);
-+ /* This must be a VCHIQ-style service */
-+ if (args.msgbufsize < msglen) {
-+ vchiq_log_error(
-+ vchiq_arm_log_level,
-+ "header %x: msgbufsize"
-+ " %x < msglen %x",
-+ (unsigned int)header,
-+ args.msgbufsize,
-+ msglen);
-+ WARN(1, "invalid message "
-+ "size\n");
-+ if (ret == 0)
-+ ret = -EMSGSIZE;
-+ break;
-+ }
-+ if (msgbufcount <= 0)
-+ /* Stall here for lack of a
-+ ** buffer for the message. */
-+ break;
-+ /* Get the pointer from user space */
-+ msgbufcount--;
-+ if (copy_from_user(&msgbuf,
-+ (const void __user *)
-+ &args.msgbufs[msgbufcount],
-+ sizeof(msgbuf)) != 0) {
-+ if (ret == 0)
-+ ret = -EFAULT;
-+ break;
-+ }
-+
-+ /* Copy the message to user space */
-+ if (copy_to_user(msgbuf, header,
-+ msglen) != 0) {
-+ if (ret == 0)
-+ ret = -EFAULT;
-+ break;
-+ }
-+
-+ /* Now it has been copied, the message
-+ ** can be released. */
-+ vchiq_release_message(service->handle,
-+ header);
-+
-+ /* The completion must point to the
-+ ** msgbuf. */
-+ completion->header = msgbuf;
-+ }
-+
-+ if ((completion->reason ==
-+ VCHIQ_SERVICE_CLOSED) &&
-+ !instance->use_close_delivered)
-+ unlock_service(service);
-+
-+ if (copy_to_user((void __user *)(
-+ (size_t)args.buf +
-+ ret * sizeof(VCHIQ_COMPLETION_DATA_T)),
-+ completion,
-+ sizeof(VCHIQ_COMPLETION_DATA_T)) != 0) {
-+ if (ret == 0)
-+ ret = -EFAULT;
-+ break;
-+ }
-+
-+ instance->completion_remove++;
-+ }
-+
-+ if (msgbufcount != args.msgbufcount) {
-+ if (copy_to_user((void __user *)
-+ &((VCHIQ_AWAIT_COMPLETION_T *)arg)->
-+ msgbufcount,
-+ &msgbufcount,
-+ sizeof(msgbufcount)) != 0) {
-+ ret = -EFAULT;
-+ }
-+ }
-+ }
-+
-+ if (ret != 0)
-+ up(&instance->remove_event);
-+ mutex_unlock(&instance->completion_mutex);
-+ DEBUG_TRACE(AWAIT_COMPLETION_LINE);
-+ } break;
-+
-+ case VCHIQ_IOC_DEQUEUE_MESSAGE: {
-+ VCHIQ_DEQUEUE_MESSAGE_T args;
-+ USER_SERVICE_T *user_service;
-+ VCHIQ_HEADER_T *header;
-+
-+ DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
-+ if (copy_from_user
-+ (&args, (const void __user *)arg,
-+ sizeof(args)) != 0) {
-+ ret = -EFAULT;
-+ break;
-+ }
-+ service = find_service_for_instance(instance, args.handle);
-+ if (!service) {
-+ ret = -EINVAL;
-+ break;
-+ }
-+ user_service = (USER_SERVICE_T *)service->base.userdata;
-+ if (user_service->is_vchi == 0) {
-+ ret = -EINVAL;
-+ break;
-+ }
-+
-+ spin_lock(&msg_queue_spinlock);
-+ if (user_service->msg_remove == user_service->msg_insert) {
-+ if (!args.blocking) {
-+ spin_unlock(&msg_queue_spinlock);
-+ DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
-+ ret = -EWOULDBLOCK;
-+ break;
-+ }
-+ user_service->dequeue_pending = 1;
-+ do {
-+ spin_unlock(&msg_queue_spinlock);
-+ DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
-+ if (down_interruptible(
-+ &user_service->insert_event) != 0) {
-+ vchiq_log_info(vchiq_arm_log_level,
-+ "DEQUEUE_MESSAGE interrupted");
-+ ret = -EINTR;
-+ break;
-+ }
-+ spin_lock(&msg_queue_spinlock);
-+ } while (user_service->msg_remove ==
-+ user_service->msg_insert);
-+
-+ if (ret)
-+ break;
-+ }
-+
-+ BUG_ON((int)(user_service->msg_insert -
-+ user_service->msg_remove) < 0);
-+
-+ header = user_service->msg_queue[user_service->msg_remove &
-+ (MSG_QUEUE_SIZE - 1)];
-+ user_service->msg_remove++;
-+ spin_unlock(&msg_queue_spinlock);
-+
-+ up(&user_service->remove_event);
-+ if (header == NULL)
-+ ret = -ENOTCONN;
-+ else if (header->size <= args.bufsize) {
-+ /* Copy to user space if msgbuf is not NULL */
-+ if ((args.buf == NULL) ||
-+ (copy_to_user((void __user *)args.buf,
-+ header->data,
-+ header->size) == 0)) {
-+ ret = header->size;
-+ vchiq_release_message(
-+ service->handle,
-+ header);
-+ } else
-+ ret = -EFAULT;
-+ } else {
-+ vchiq_log_error(vchiq_arm_log_level,
-+ "header %x: bufsize %x < size %x",
-+ (unsigned int)header, args.bufsize,
-+ header->size);
-+ WARN(1, "invalid size\n");
-+ ret = -EMSGSIZE;
-+ }
-+ DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
-+ } break;
-+
-+ case VCHIQ_IOC_GET_CLIENT_ID: {
-+ VCHIQ_SERVICE_HANDLE_T handle = (VCHIQ_SERVICE_HANDLE_T)arg;
-+
-+ ret = vchiq_get_client_id(handle);
-+ } break;
-+
-+ case VCHIQ_IOC_GET_CONFIG: {
-+ VCHIQ_GET_CONFIG_T args;
-+ VCHIQ_CONFIG_T config;
-+
-+ if (copy_from_user(&args, (const void __user *)arg,
-+ sizeof(args)) != 0) {
-+ ret = -EFAULT;
-+ break;
-+ }
-+ if (args.config_size > sizeof(config)) {
-+ ret = -EINVAL;
-+ break;
-+ }
-+ status = vchiq_get_config(instance, args.config_size, &config);
-+ if (status == VCHIQ_SUCCESS) {
-+ if (copy_to_user((void __user *)args.pconfig,
-+ &config, args.config_size) != 0) {
-+ ret = -EFAULT;
-+ break;
-+ }
-+ }
-+ } break;
-+
-+ case VCHIQ_IOC_SET_SERVICE_OPTION: {
-+ VCHIQ_SET_SERVICE_OPTION_T args;
-+
-+ if (copy_from_user(
-+ &args, (const void __user *)arg,
-+ sizeof(args)) != 0) {
-+ ret = -EFAULT;
-+ break;
-+ }
-+
-+ service = find_service_for_instance(instance, args.handle);
-+ if (!service) {
-+ ret = -EINVAL;
-+ break;
-+ }
-+
-+ status = vchiq_set_service_option(
-+ args.handle, args.option, args.value);
-+ } break;
-+
-+ case VCHIQ_IOC_DUMP_PHYS_MEM: {
-+ VCHIQ_DUMP_MEM_T args;
-+
-+ if (copy_from_user
-+ (&args, (const void __user *)arg,
-+ sizeof(args)) != 0) {
-+ ret = -EFAULT;
-+ break;
-+ }
-+ dump_phys_mem(args.virt_addr, args.num_bytes);
-+ } break;
-+
-+ case VCHIQ_IOC_LIB_VERSION: {
-+ unsigned int lib_version = (unsigned int)arg;
-+
-+ if (lib_version < VCHIQ_VERSION_MIN)
-+ ret = -EINVAL;
-+ else if (lib_version >= VCHIQ_VERSION_CLOSE_DELIVERED)
-+ instance->use_close_delivered = 1;
-+ } break;
-+
-+ case VCHIQ_IOC_CLOSE_DELIVERED: {
-+ VCHIQ_SERVICE_HANDLE_T handle = (VCHIQ_SERVICE_HANDLE_T)arg;
-+
-+ service = find_closed_service_for_instance(instance, handle);
-+ if (service != NULL) {
-+ USER_SERVICE_T *user_service =
-+ (USER_SERVICE_T *)service->base.userdata;
-+ close_delivered(user_service);
-+ }
-+ else
-+ ret = -EINVAL;
-+ } break;
-+
-+ default:
-+ ret = -ENOTTY;
-+ break;
-+ }
-+
-+ if (service)
-+ unlock_service(service);
-+
-+ if (ret == 0) {
-+ if (status == VCHIQ_ERROR)
-+ ret = -EIO;
-+ else if (status == VCHIQ_RETRY)
-+ ret = -EINTR;
-+ }
-+
-+ if ((status == VCHIQ_SUCCESS) && (ret < 0) && (ret != -EINTR) &&
-+ (ret != -EWOULDBLOCK))
-+ vchiq_log_info(vchiq_arm_log_level,
-+ " ioctl instance %lx, cmd %s -> status %d, %ld",
-+ (unsigned long)instance,
-+ (_IOC_NR(cmd) <= VCHIQ_IOC_MAX) ?
-+ ioctl_names[_IOC_NR(cmd)] :
-+ "<invalid>",
-+ status, ret);
-+ else
-+ vchiq_log_trace(vchiq_arm_log_level,
-+ " ioctl instance %lx, cmd %s -> status %d, %ld",
-+ (unsigned long)instance,
-+ (_IOC_NR(cmd) <= VCHIQ_IOC_MAX) ?
-+ ioctl_names[_IOC_NR(cmd)] :
-+ "<invalid>",
-+ status, ret);
-+
-+ return ret;
-+}
-+
-+/****************************************************************************
-+*
-+* vchiq_open
-+*
-+***************************************************************************/
-+
-+static int
-+vchiq_open(struct inode *inode, struct file *file)
-+{
-+ int dev = iminor(inode) & 0x0f;
-+ vchiq_log_info(vchiq_arm_log_level, "vchiq_open");
-+ switch (dev) {
-+ case VCHIQ_MINOR: {
-+ int ret;
-+ VCHIQ_STATE_T *state = vchiq_get_state();
-+ VCHIQ_INSTANCE_T instance;
-+
-+ if (!state) {
-+ vchiq_log_error(vchiq_arm_log_level,
-+ "vchiq has no connection to VideoCore");
-+ return -ENOTCONN;
-+ }
-+
-+ instance = kzalloc(sizeof(*instance), GFP_KERNEL);
-+ if (!instance)
-+ return -ENOMEM;
-+
-+ instance->state = state;
-+ instance->pid = current->tgid;
-+
-+ ret = vchiq_debugfs_add_instance(instance);
-+ if (ret != 0) {
-+ kfree(instance);
-+ return ret;
-+ }
-+
-+ sema_init(&instance->insert_event, 0);
-+ sema_init(&instance->remove_event, 0);
-+ mutex_init(&instance->completion_mutex);
-+ mutex_init(&instance->bulk_waiter_list_mutex);
-+ INIT_LIST_HEAD(&instance->bulk_waiter_list);
-+
-+ file->private_data = instance;
-+ } break;
-+
-+ default:
-+ vchiq_log_error(vchiq_arm_log_level,
-+ "Unknown minor device: %d", dev);
-+ return -ENXIO;
-+ }
-+
-+ return 0;
-+}
-+
-+/****************************************************************************
-+*
-+* vchiq_release
-+*
-+***************************************************************************/
-+
-+static int
-+vchiq_release(struct inode *inode, struct file *file)
-+{
-+ int dev = iminor(inode) & 0x0f;
-+ int ret = 0;
-+ switch (dev) {
-+ case VCHIQ_MINOR: {
-+ VCHIQ_INSTANCE_T instance = file->private_data;
-+ VCHIQ_STATE_T *state = vchiq_get_state();
-+ VCHIQ_SERVICE_T *service;
-+ int i;
-+
-+ vchiq_log_info(vchiq_arm_log_level,
-+ "vchiq_release: instance=%lx",
-+ (unsigned long)instance);
-+
-+ if (!state) {
-+ ret = -EPERM;
-+ goto out;
-+ }
-+
-+ /* Ensure videocore is awake to allow termination. */
-+ vchiq_use_internal(instance->state, NULL,
-+ USE_TYPE_VCHIQ);
-+
-+ mutex_lock(&instance->completion_mutex);
-+
-+ /* Wake the completion thread and ask it to exit */
-+ instance->closing = 1;
-+ up(&instance->insert_event);
-+
-+ mutex_unlock(&instance->completion_mutex);
-+
-+ /* Wake the slot handler if the completion queue is full. */
-+ up(&instance->remove_event);
-+
-+ /* Mark all services for termination... */
-+ i = 0;
-+ while ((service = next_service_by_instance(state, instance,
-+ &i)) != NULL) {
-+ USER_SERVICE_T *user_service = service->base.userdata;
-+
-+ /* Wake the slot handler if the msg queue is full. */
-+ up(&user_service->remove_event);
-+
-+ vchiq_terminate_service_internal(service);
-+ unlock_service(service);
-+ }
-+
-+ /* ...and wait for them to die */
-+ i = 0;
-+ while ((service = next_service_by_instance(state, instance, &i))
-+ != NULL) {
-+ USER_SERVICE_T *user_service = service->base.userdata;
-+
-+ down(&service->remove_event);
-+
-+ BUG_ON(service->srvstate != VCHIQ_SRVSTATE_FREE);
-+
-+ spin_lock(&msg_queue_spinlock);
-+
-+ while (user_service->msg_remove !=
-+ user_service->msg_insert) {
-+ VCHIQ_HEADER_T *header = user_service->
-+ msg_queue[user_service->msg_remove &
-+ (MSG_QUEUE_SIZE - 1)];
-+ user_service->msg_remove++;
-+ spin_unlock(&msg_queue_spinlock);
-+
-+ if (header)
-+ vchiq_release_message(
-+ service->handle,
-+ header);
-+ spin_lock(&msg_queue_spinlock);
-+ }
-+
-+ spin_unlock(&msg_queue_spinlock);
-+
-+ unlock_service(service);
-+ }
-+
-+ /* Release any closed services */
-+ while (instance->completion_remove !=
-+ instance->completion_insert) {
-+ VCHIQ_COMPLETION_DATA_T *completion;
-+ VCHIQ_SERVICE_T *service;
-+ completion = &instance->completions[
-+ instance->completion_remove &
-+ (MAX_COMPLETIONS - 1)];
-+ service = completion->service_userdata;
-+ if (completion->reason == VCHIQ_SERVICE_CLOSED)
-+ {
-+ USER_SERVICE_T *user_service =
-+ service->base.userdata;
-+
-+ /* Wake any blocked user-thread */
-+ if (instance->use_close_delivered)
-+ up(&user_service->close_event);
-+ unlock_service(service);
-+ }
-+ instance->completion_remove++;
-+ }
-+
-+ /* Release the PEER service count. */
-+ vchiq_release_internal(instance->state, NULL);
-+
-+ {
-+ struct list_head *pos, *next;
-+ list_for_each_safe(pos, next,
-+ &instance->bulk_waiter_list) {
-+ struct bulk_waiter_node *waiter;
-+ waiter = list_entry(pos,
-+ struct bulk_waiter_node,
-+ list);
-+ list_del(pos);
-+ vchiq_log_info(vchiq_arm_log_level,
-+ "bulk_waiter - cleaned up %x "
-+ "for pid %d",
-+ (unsigned int)waiter, waiter->pid);
-+ kfree(waiter);
-+ }
-+ }
-+
-+ vchiq_debugfs_remove_instance(instance);
-+
-+ kfree(instance);
-+ file->private_data = NULL;
-+ } break;
-+
-+ default:
-+ vchiq_log_error(vchiq_arm_log_level,
-+ "Unknown minor device: %d", dev);
-+ ret = -ENXIO;
-+ }
-+
-+out:
-+ return ret;
-+}
-+
-+/****************************************************************************
-+*
-+* vchiq_dump
-+*
-+***************************************************************************/
-+
-+void
-+vchiq_dump(void *dump_context, const char *str, int len)
-+{
-+ DUMP_CONTEXT_T *context = (DUMP_CONTEXT_T *)dump_context;
-+
-+ if (context->actual < context->space) {
-+ int copy_bytes;
-+ if (context->offset > 0) {
-+ int skip_bytes = min(len, (int)context->offset);
-+ str += skip_bytes;
-+ len -= skip_bytes;
-+ context->offset -= skip_bytes;
-+ if (context->offset > 0)
-+ return;
-+ }
-+ copy_bytes = min(len, (int)(context->space - context->actual));
-+ if (copy_bytes == 0)
-+ return;
-+ if (copy_to_user(context->buf + context->actual, str,
-+ copy_bytes))
-+ context->actual = -EFAULT;
-+ context->actual += copy_bytes;
-+ len -= copy_bytes;
-+
-+ /* If tne terminating NUL is included in the length, then it
-+ ** marks the end of a line and should be replaced with a
-+ ** carriage return. */
-+ if ((len == 0) && (str[copy_bytes - 1] == '\0')) {
-+ char cr = '\n';
-+ if (copy_to_user(context->buf + context->actual - 1,
-+ &cr, 1))
-+ context->actual = -EFAULT;
-+ }
-+ }
-+}
-+
-+/****************************************************************************
-+*
-+* vchiq_dump_platform_instance_state
-+*
-+***************************************************************************/
-+
-+void
-+vchiq_dump_platform_instances(void *dump_context)
-+{
-+ VCHIQ_STATE_T *state = vchiq_get_state();
-+ char buf[80];
-+ int len;
-+ int i;
-+
-+ /* There is no list of instances, so instead scan all services,
-+ marking those that have been dumped. */
-+
-+ for (i = 0; i < state->unused_service; i++) {
-+ VCHIQ_SERVICE_T *service = state->services[i];
-+ VCHIQ_INSTANCE_T instance;
-+
-+ if (service && (service->base.callback == service_callback)) {
-+ instance = service->instance;
-+ if (instance)
-+ instance->mark = 0;
-+ }
-+ }
-+
-+ for (i = 0; i < state->unused_service; i++) {
-+ VCHIQ_SERVICE_T *service = state->services[i];
-+ VCHIQ_INSTANCE_T instance;
-+
-+ if (service && (service->base.callback == service_callback)) {
-+ instance = service->instance;
-+ if (instance && !instance->mark) {
-+ len = snprintf(buf, sizeof(buf),
-+ "Instance %x: pid %d,%s completions "
-+ "%d/%d",
-+ (unsigned int)instance, instance->pid,
-+ instance->connected ? " connected, " :
-+ "",
-+ instance->completion_insert -
-+ instance->completion_remove,
-+ MAX_COMPLETIONS);
-+
-+ vchiq_dump(dump_context, buf, len + 1);
-+
-+ instance->mark = 1;
-+ }
-+ }
-+ }
-+}
-+
-+/****************************************************************************
-+*
-+* vchiq_dump_platform_service_state
-+*
-+***************************************************************************/
-+
-+void
-+vchiq_dump_platform_service_state(void *dump_context, VCHIQ_SERVICE_T *service)
-+{
-+ USER_SERVICE_T *user_service = (USER_SERVICE_T *)service->base.userdata;
-+ char buf[80];
-+ int len;
-+
-+ len = snprintf(buf, sizeof(buf), " instance %x",
-+ (unsigned int)service->instance);
-+
-+ if ((service->base.callback == service_callback) &&
-+ user_service->is_vchi) {
-+ len += snprintf(buf + len, sizeof(buf) - len,
-+ ", %d/%d messages",
-+ user_service->msg_insert - user_service->msg_remove,
-+ MSG_QUEUE_SIZE);
-+
-+ if (user_service->dequeue_pending)
-+ len += snprintf(buf + len, sizeof(buf) - len,
-+ " (dequeue pending)");
-+ }
-+
-+ vchiq_dump(dump_context, buf, len + 1);
-+}
-+
-+/****************************************************************************
-+*
-+* dump_user_mem
-+*
-+***************************************************************************/
-+
-+static void
-+dump_phys_mem(void *virt_addr, uint32_t num_bytes)
-+{
-+ int rc;
-+ uint8_t *end_virt_addr = virt_addr + num_bytes;
-+ int num_pages;
-+ int offset;
-+ int end_offset;
-+ int page_idx;
-+ int prev_idx;
-+ struct page *page;
-+ struct page **pages;
-+ uint8_t *kmapped_virt_ptr;
-+
-+ /* Align virtAddr and endVirtAddr to 16 byte boundaries. */
-+
-+ virt_addr = (void *)((unsigned long)virt_addr & ~0x0fuL);
-+ end_virt_addr = (void *)(((unsigned long)end_virt_addr + 15uL) &
-+ ~0x0fuL);
-+
-+ offset = (int)(long)virt_addr & (PAGE_SIZE - 1);
-+ end_offset = (int)(long)end_virt_addr & (PAGE_SIZE - 1);
-+
-+ num_pages = (offset + num_bytes + PAGE_SIZE - 1) / PAGE_SIZE;
-+
-+ pages = kmalloc(sizeof(struct page *) * num_pages, GFP_KERNEL);
-+ if (pages == NULL) {
-+ vchiq_log_error(vchiq_arm_log_level,
-+ "Unable to allocation memory for %d pages\n",
-+ num_pages);
-+ return;
-+ }
-+
-+ down_read(&current->mm->mmap_sem);
-+ rc = get_user_pages(current, /* task */
-+ current->mm, /* mm */
-+ (unsigned long)virt_addr, /* start */
-+ num_pages, /* len */
-+ 0, /* write */
-+ 0, /* force */
-+ pages, /* pages (array of page pointers) */
-+ NULL); /* vmas */
-+ up_read(&current->mm->mmap_sem);
-+
-+ prev_idx = -1;
-+ page = NULL;
-+
-+ while (offset < end_offset) {
-+
-+ int page_offset = offset % PAGE_SIZE;
-+ page_idx = offset / PAGE_SIZE;
-+
-+ if (page_idx != prev_idx) {
-+
-+ if (page != NULL)
-+ kunmap(page);
-+ page = pages[page_idx];
-+ kmapped_virt_ptr = kmap(page);
-+
-+ prev_idx = page_idx;
-+ }
-+
-+ if (vchiq_arm_log_level >= VCHIQ_LOG_TRACE)
-+ vchiq_log_dump_mem("ph",
-+ (uint32_t)(unsigned long)&kmapped_virt_ptr[
-+ page_offset],
-+ &kmapped_virt_ptr[page_offset], 16);
-+
-+ offset += 16;
-+ }
-+ if (page != NULL)
-+ kunmap(page);
-+
-+ for (page_idx = 0; page_idx < num_pages; page_idx++)
-+ page_cache_release(pages[page_idx]);
-+
-+ kfree(pages);
-+}
-+
-+/****************************************************************************
-+*
-+* vchiq_read
-+*
-+***************************************************************************/
-+
-+static ssize_t
-+vchiq_read(struct file *file, char __user *buf,
-+ size_t count, loff_t *ppos)
-+{
-+ DUMP_CONTEXT_T context;
-+ context.buf = buf;
-+ context.actual = 0;
-+ context.space = count;
-+ context.offset = *ppos;
-+
-+ vchiq_dump_state(&context, &g_state);
-+
-+ *ppos += context.actual;
-+
-+ return context.actual;
-+}
-+
-+VCHIQ_STATE_T *
-+vchiq_get_state(void)
-+{
-+
-+ if (g_state.remote == NULL)
-+ printk(KERN_ERR "%s: g_state.remote == NULL\n", __func__);
-+ else if (g_state.remote->initialised != 1)
-+ printk(KERN_NOTICE "%s: g_state.remote->initialised != 1 (%d)\n",
-+ __func__, g_state.remote->initialised);
-+
-+ return ((g_state.remote != NULL) &&
-+ (g_state.remote->initialised == 1)) ? &g_state : NULL;
-+}
-+
-+static const struct file_operations
-+vchiq_fops = {
-+ .owner = THIS_MODULE,
-+ .unlocked_ioctl = vchiq_ioctl,
-+ .open = vchiq_open,
-+ .release = vchiq_release,
-+ .read = vchiq_read
-+};
-+
-+/*
-+ * Autosuspend related functionality
-+ */
-+
-+int
-+vchiq_videocore_wanted(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+ if (!arm_state)
-+ /* autosuspend not supported - always return wanted */
-+ return 1;
-+ else if (arm_state->blocked_count)
-+ return 1;
-+ else if (!arm_state->videocore_use_count)
-+ /* usage count zero - check for override unless we're forcing */
-+ if (arm_state->resume_blocked)
-+ return 0;
-+ else
-+ return vchiq_platform_videocore_wanted(state);
-+ else
-+ /* non-zero usage count - videocore still required */
-+ return 1;
-+}
-+
-+static VCHIQ_STATUS_T
-+vchiq_keepalive_vchiq_callback(VCHIQ_REASON_T reason,
-+ VCHIQ_HEADER_T *header,
-+ VCHIQ_SERVICE_HANDLE_T service_user,
-+ void *bulk_user)
-+{
-+ vchiq_log_error(vchiq_susp_log_level,
-+ "%s callback reason %d", __func__, reason);
-+ return 0;
-+}
-+
-+static int
-+vchiq_keepalive_thread_func(void *v)
-+{
-+ VCHIQ_STATE_T *state = (VCHIQ_STATE_T *) v;
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+
-+ VCHIQ_STATUS_T status;
-+ VCHIQ_INSTANCE_T instance;
-+ VCHIQ_SERVICE_HANDLE_T ka_handle;
-+
-+ VCHIQ_SERVICE_PARAMS_T params = {
-+ .fourcc = VCHIQ_MAKE_FOURCC('K', 'E', 'E', 'P'),
-+ .callback = vchiq_keepalive_vchiq_callback,
-+ .version = KEEPALIVE_VER,
-+ .version_min = KEEPALIVE_VER_MIN
-+ };
-+
-+ status = vchiq_initialise(&instance);
-+ if (status != VCHIQ_SUCCESS) {
-+ vchiq_log_error(vchiq_susp_log_level,
-+ "%s vchiq_initialise failed %d", __func__, status);
-+ goto exit;
-+ }
-+
-+ status = vchiq_connect(instance);
-+ if (status != VCHIQ_SUCCESS) {
-+ vchiq_log_error(vchiq_susp_log_level,
-+ "%s vchiq_connect failed %d", __func__, status);
-+ goto shutdown;
-+ }
-+
-+ status = vchiq_add_service(instance, &params, &ka_handle);
-+ if (status != VCHIQ_SUCCESS) {
-+ vchiq_log_error(vchiq_susp_log_level,
-+ "%s vchiq_open_service failed %d", __func__, status);
-+ goto shutdown;
-+ }
-+
-+ while (1) {
-+ long rc = 0, uc = 0;
-+ if (wait_for_completion_interruptible(&arm_state->ka_evt)
-+ != 0) {
-+ vchiq_log_error(vchiq_susp_log_level,
-+ "%s interrupted", __func__);
-+ flush_signals(current);
-+ continue;
-+ }
-+
-+ /* read and clear counters. Do release_count then use_count to
-+ * prevent getting more releases than uses */
-+ rc = atomic_xchg(&arm_state->ka_release_count, 0);
-+ uc = atomic_xchg(&arm_state->ka_use_count, 0);
-+
-+ /* Call use/release service the requisite number of times.
-+ * Process use before release so use counts don't go negative */
-+ while (uc--) {
-+ atomic_inc(&arm_state->ka_use_ack_count);
-+ status = vchiq_use_service(ka_handle);
-+ if (status != VCHIQ_SUCCESS) {
-+ vchiq_log_error(vchiq_susp_log_level,
-+ "%s vchiq_use_service error %d",
-+ __func__, status);
-+ }
-+ }
-+ while (rc--) {
-+ status = vchiq_release_service(ka_handle);
-+ if (status != VCHIQ_SUCCESS) {
-+ vchiq_log_error(vchiq_susp_log_level,
-+ "%s vchiq_release_service error %d",
-+ __func__, status);
-+ }
-+ }
-+ }
-+
-+shutdown:
-+ vchiq_shutdown(instance);
-+exit:
-+ return 0;
-+}
-+
-+
-+
-+VCHIQ_STATUS_T
-+vchiq_arm_init_state(VCHIQ_STATE_T *state, VCHIQ_ARM_STATE_T *arm_state)
-+{
-+ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
-+
-+ if (arm_state) {
-+ rwlock_init(&arm_state->susp_res_lock);
-+
-+ init_completion(&arm_state->ka_evt);
-+ atomic_set(&arm_state->ka_use_count, 0);
-+ atomic_set(&arm_state->ka_use_ack_count, 0);
-+ atomic_set(&arm_state->ka_release_count, 0);
-+
-+ init_completion(&arm_state->vc_suspend_complete);
-+
-+ init_completion(&arm_state->vc_resume_complete);
-+ /* Initialise to 'done' state. We only want to block on resume
-+ * completion while videocore is suspended. */
-+ set_resume_state(arm_state, VC_RESUME_RESUMED);
-+
-+ init_completion(&arm_state->resume_blocker);
-+ /* Initialise to 'done' state. We only want to block on this
-+ * completion while resume is blocked */
-+ complete_all(&arm_state->resume_blocker);
-+
-+ init_completion(&arm_state->blocked_blocker);
-+ /* Initialise to 'done' state. We only want to block on this
-+ * completion while things are waiting on the resume blocker */
-+ complete_all(&arm_state->blocked_blocker);
-+
-+ arm_state->suspend_timer_timeout = SUSPEND_TIMER_TIMEOUT_MS;
-+ arm_state->suspend_timer_running = 0;
-+ init_timer(&arm_state->suspend_timer);
-+ arm_state->suspend_timer.data = (unsigned long)(state);
-+ arm_state->suspend_timer.function = suspend_timer_callback;
-+
-+ arm_state->first_connect = 0;
-+
-+ }
-+ return status;
-+}
-+
-+/*
-+** Functions to modify the state variables;
-+** set_suspend_state
-+** set_resume_state
-+**
-+** There are more state variables than we might like, so ensure they remain in
-+** step. Suspend and resume state are maintained separately, since most of
-+** these state machines can operate independently. However, there are a few
-+** states where state transitions in one state machine cause a reset to the
-+** other state machine. In addition, there are some completion events which
-+** need to occur on state machine reset and end-state(s), so these are also
-+** dealt with in these functions.
-+**
-+** In all states we set the state variable according to the input, but in some
-+** cases we perform additional steps outlined below;
-+**
-+** VC_SUSPEND_IDLE - Initialise the suspend completion at the same time.
-+** The suspend completion is completed after any suspend
-+** attempt. When we reset the state machine we also reset
-+** the completion. This reset occurs when videocore is
-+** resumed, and also if we initiate suspend after a suspend
-+** failure.
-+**
-+** VC_SUSPEND_IN_PROGRESS - This state is considered the point of no return for
-+** suspend - ie from this point on we must try to suspend
-+** before resuming can occur. We therefore also reset the
-+** resume state machine to VC_RESUME_IDLE in this state.
-+**
-+** VC_SUSPEND_SUSPENDED - Suspend has completed successfully. Also call
-+** complete_all on the suspend completion to notify
-+** anything waiting for suspend to happen.
-+**
-+** VC_SUSPEND_REJECTED - Videocore rejected suspend. Videocore will also
-+** initiate resume, so no need to alter resume state.
-+** We call complete_all on the suspend completion to notify
-+** of suspend rejection.
-+**
-+** VC_SUSPEND_FAILED - We failed to initiate videocore suspend. We notify the
-+** suspend completion and reset the resume state machine.
-+**
-+** VC_RESUME_IDLE - Initialise the resume completion at the same time. The
-+** resume completion is in it's 'done' state whenever
-+** videcore is running. Therfore, the VC_RESUME_IDLE state
-+** implies that videocore is suspended.
-+** Hence, any thread which needs to wait until videocore is
-+** running can wait on this completion - it will only block
-+** if videocore is suspended.
-+**
-+** VC_RESUME_RESUMED - Resume has completed successfully. Videocore is running.
-+** Call complete_all on the resume completion to unblock
-+** any threads waiting for resume. Also reset the suspend
-+** state machine to it's idle state.
-+**
-+** VC_RESUME_FAILED - Currently unused - no mechanism to fail resume exists.
-+*/
-+
-+void
-+set_suspend_state(VCHIQ_ARM_STATE_T *arm_state,
-+ enum vc_suspend_status new_state)
-+{
-+ /* set the state in all cases */
-+ arm_state->vc_suspend_state = new_state;
-+
-+ /* state specific additional actions */
-+ switch (new_state) {
-+ case VC_SUSPEND_FORCE_CANCELED:
-+ complete_all(&arm_state->vc_suspend_complete);
-+ break;
-+ case VC_SUSPEND_REJECTED:
-+ complete_all(&arm_state->vc_suspend_complete);
-+ break;
-+ case VC_SUSPEND_FAILED:
-+ complete_all(&arm_state->vc_suspend_complete);
-+ arm_state->vc_resume_state = VC_RESUME_RESUMED;
-+ complete_all(&arm_state->vc_resume_complete);
-+ break;
-+ case VC_SUSPEND_IDLE:
-+ reinit_completion(&arm_state->vc_suspend_complete);
-+ break;
-+ case VC_SUSPEND_REQUESTED:
-+ break;
-+ case VC_SUSPEND_IN_PROGRESS:
-+ set_resume_state(arm_state, VC_RESUME_IDLE);
-+ break;
-+ case VC_SUSPEND_SUSPENDED:
-+ complete_all(&arm_state->vc_suspend_complete);
-+ break;
-+ default:
-+ BUG();
-+ break;
-+ }
-+}
-+
-+void
-+set_resume_state(VCHIQ_ARM_STATE_T *arm_state,
-+ enum vc_resume_status new_state)
-+{
-+ /* set the state in all cases */
-+ arm_state->vc_resume_state = new_state;
-+
-+ /* state specific additional actions */
-+ switch (new_state) {
-+ case VC_RESUME_FAILED:
-+ break;
-+ case VC_RESUME_IDLE:
-+ reinit_completion(&arm_state->vc_resume_complete);
-+ break;
-+ case VC_RESUME_REQUESTED:
-+ break;
-+ case VC_RESUME_IN_PROGRESS:
-+ break;
-+ case VC_RESUME_RESUMED:
-+ complete_all(&arm_state->vc_resume_complete);
-+ set_suspend_state(arm_state, VC_SUSPEND_IDLE);
-+ break;
-+ default:
-+ BUG();
-+ break;
-+ }
-+}
-+
-+
-+/* should be called with the write lock held */
-+inline void
-+start_suspend_timer(VCHIQ_ARM_STATE_T *arm_state)
-+{
-+ del_timer(&arm_state->suspend_timer);
-+ arm_state->suspend_timer.expires = jiffies +
-+ msecs_to_jiffies(arm_state->
-+ suspend_timer_timeout);
-+ add_timer(&arm_state->suspend_timer);
-+ arm_state->suspend_timer_running = 1;
-+}
-+
-+/* should be called with the write lock held */
-+static inline void
-+stop_suspend_timer(VCHIQ_ARM_STATE_T *arm_state)
-+{
-+ if (arm_state->suspend_timer_running) {
-+ del_timer(&arm_state->suspend_timer);
-+ arm_state->suspend_timer_running = 0;
-+ }
-+}
-+
-+static inline int
-+need_resume(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+ return (arm_state->vc_suspend_state > VC_SUSPEND_IDLE) &&
-+ (arm_state->vc_resume_state < VC_RESUME_REQUESTED) &&
-+ vchiq_videocore_wanted(state);
-+}
-+
-+static int
-+block_resume(VCHIQ_ARM_STATE_T *arm_state)
-+{
-+ int status = VCHIQ_SUCCESS;
-+ const unsigned long timeout_val =
-+ msecs_to_jiffies(FORCE_SUSPEND_TIMEOUT_MS);
-+ int resume_count = 0;
-+
-+ /* Allow any threads which were blocked by the last force suspend to
-+ * complete if they haven't already. Only give this one shot; if
-+ * blocked_count is incremented after blocked_blocker is completed
-+ * (which only happens when blocked_count hits 0) then those threads
-+ * will have to wait until next time around */
-+ if (arm_state->blocked_count) {
-+ reinit_completion(&arm_state->blocked_blocker);
-+ write_unlock_bh(&arm_state->susp_res_lock);
-+ vchiq_log_info(vchiq_susp_log_level, "%s wait for previously "
-+ "blocked clients", __func__);
-+ if (wait_for_completion_interruptible_timeout(
-+ &arm_state->blocked_blocker, timeout_val)
-+ <= 0) {
-+ vchiq_log_error(vchiq_susp_log_level, "%s wait for "
-+ "previously blocked clients failed" , __func__);
-+ status = VCHIQ_ERROR;
-+ write_lock_bh(&arm_state->susp_res_lock);
-+ goto out;
-+ }
-+ vchiq_log_info(vchiq_susp_log_level, "%s previously blocked "
-+ "clients resumed", __func__);
-+ write_lock_bh(&arm_state->susp_res_lock);
-+ }
-+
-+ /* We need to wait for resume to complete if it's in process */
-+ while (arm_state->vc_resume_state != VC_RESUME_RESUMED &&
-+ arm_state->vc_resume_state > VC_RESUME_IDLE) {
-+ if (resume_count > 1) {
-+ status = VCHIQ_ERROR;
-+ vchiq_log_error(vchiq_susp_log_level, "%s waited too "
-+ "many times for resume" , __func__);
-+ goto out;
-+ }
-+ write_unlock_bh(&arm_state->susp_res_lock);
-+ vchiq_log_info(vchiq_susp_log_level, "%s wait for resume",
-+ __func__);
-+ if (wait_for_completion_interruptible_timeout(
-+ &arm_state->vc_resume_complete, timeout_val)
-+ <= 0) {
-+ vchiq_log_error(vchiq_susp_log_level, "%s wait for "
-+ "resume failed (%s)", __func__,
-+ resume_state_names[arm_state->vc_resume_state +
-+ VC_RESUME_NUM_OFFSET]);
-+ status = VCHIQ_ERROR;
-+ write_lock_bh(&arm_state->susp_res_lock);
-+ goto out;
-+ }
-+ vchiq_log_info(vchiq_susp_log_level, "%s resumed", __func__);
-+ write_lock_bh(&arm_state->susp_res_lock);
-+ resume_count++;
-+ }
-+ reinit_completion(&arm_state->resume_blocker);
-+ arm_state->resume_blocked = 1;
-+
-+out:
-+ return status;
-+}
-+
-+static inline void
-+unblock_resume(VCHIQ_ARM_STATE_T *arm_state)
-+{
-+ complete_all(&arm_state->resume_blocker);
-+ arm_state->resume_blocked = 0;
-+}
-+
-+/* Initiate suspend via slot handler. Should be called with the write lock
-+ * held */
-+VCHIQ_STATUS_T
-+vchiq_arm_vcsuspend(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_STATUS_T status = VCHIQ_ERROR;
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+
-+ if (!arm_state)
-+ goto out;
-+
-+ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-+ status = VCHIQ_SUCCESS;
-+
-+
-+ switch (arm_state->vc_suspend_state) {
-+ case VC_SUSPEND_REQUESTED:
-+ vchiq_log_info(vchiq_susp_log_level, "%s: suspend already "
-+ "requested", __func__);
-+ break;
-+ case VC_SUSPEND_IN_PROGRESS:
-+ vchiq_log_info(vchiq_susp_log_level, "%s: suspend already in "
-+ "progress", __func__);
-+ break;
-+
-+ default:
-+ /* We don't expect to be in other states, so log but continue
-+ * anyway */
-+ vchiq_log_error(vchiq_susp_log_level,
-+ "%s unexpected suspend state %s", __func__,
-+ suspend_state_names[arm_state->vc_suspend_state +
-+ VC_SUSPEND_NUM_OFFSET]);
-+ /* fall through */
-+ case VC_SUSPEND_REJECTED:
-+ case VC_SUSPEND_FAILED:
-+ /* Ensure any idle state actions have been run */
-+ set_suspend_state(arm_state, VC_SUSPEND_IDLE);
-+ /* fall through */
-+ case VC_SUSPEND_IDLE:
-+ vchiq_log_info(vchiq_susp_log_level,
-+ "%s: suspending", __func__);
-+ set_suspend_state(arm_state, VC_SUSPEND_REQUESTED);
-+ /* kick the slot handler thread to initiate suspend */
-+ request_poll(state, NULL, 0);
-+ break;
-+ }
-+
-+out:
-+ vchiq_log_trace(vchiq_susp_log_level, "%s exit %d", __func__, status);
-+ return status;
-+}
-+
-+void
-+vchiq_platform_check_suspend(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+ int susp = 0;
-+
-+ if (!arm_state)
-+ goto out;
-+
-+ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-+
-+ write_lock_bh(&arm_state->susp_res_lock);
-+ if (arm_state->vc_suspend_state == VC_SUSPEND_REQUESTED &&
-+ arm_state->vc_resume_state == VC_RESUME_RESUMED) {
-+ set_suspend_state(arm_state, VC_SUSPEND_IN_PROGRESS);
-+ susp = 1;
-+ }
-+ write_unlock_bh(&arm_state->susp_res_lock);
-+
-+ if (susp)
-+ vchiq_platform_suspend(state);
-+
-+out:
-+ vchiq_log_trace(vchiq_susp_log_level, "%s exit", __func__);
-+ return;
-+}
-+
-+
-+static void
-+output_timeout_error(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+ char service_err[50] = "";
-+ int vc_use_count = arm_state->videocore_use_count;
-+ int active_services = state->unused_service;
-+ int i;
-+
-+ if (!arm_state->videocore_use_count) {
-+ snprintf(service_err, 50, " Videocore usecount is 0");
-+ goto output_msg;
-+ }
-+ for (i = 0; i < active_services; i++) {
-+ VCHIQ_SERVICE_T *service_ptr = state->services[i];
-+ if (service_ptr && service_ptr->service_use_count &&
-+ (service_ptr->srvstate != VCHIQ_SRVSTATE_FREE)) {
-+ snprintf(service_err, 50, " %c%c%c%c(%d) service has "
-+ "use count %d%s", VCHIQ_FOURCC_AS_4CHARS(
-+ service_ptr->base.fourcc),
-+ service_ptr->client_id,
-+ service_ptr->service_use_count,
-+ service_ptr->service_use_count ==
-+ vc_use_count ? "" : " (+ more)");
-+ break;
-+ }
-+ }
-+
-+output_msg:
-+ vchiq_log_error(vchiq_susp_log_level,
-+ "timed out waiting for vc suspend (%d).%s",
-+ arm_state->autosuspend_override, service_err);
-+
-+}
-+
-+/* Try to get videocore into suspended state, regardless of autosuspend state.
-+** We don't actually force suspend, since videocore may get into a bad state
-+** if we force suspend at a bad time. Instead, we wait for autosuspend to
-+** determine a good point to suspend. If this doesn't happen within 100ms we
-+** report failure.
-+**
-+** Returns VCHIQ_SUCCESS if videocore suspended successfully, VCHIQ_RETRY if
-+** videocore failed to suspend in time or VCHIQ_ERROR if interrupted.
-+*/
-+VCHIQ_STATUS_T
-+vchiq_arm_force_suspend(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+ VCHIQ_STATUS_T status = VCHIQ_ERROR;
-+ long rc = 0;
-+ int repeat = -1;
-+
-+ if (!arm_state)
-+ goto out;
-+
-+ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-+
-+ write_lock_bh(&arm_state->susp_res_lock);
-+
-+ status = block_resume(arm_state);
-+ if (status != VCHIQ_SUCCESS)
-+ goto unlock;
-+ if (arm_state->vc_suspend_state == VC_SUSPEND_SUSPENDED) {
-+ /* Already suspended - just block resume and exit */
-+ vchiq_log_info(vchiq_susp_log_level, "%s already suspended",
-+ __func__);
-+ status = VCHIQ_SUCCESS;
-+ goto unlock;
-+ } else if (arm_state->vc_suspend_state <= VC_SUSPEND_IDLE) {
-+ /* initiate suspend immediately in the case that we're waiting
-+ * for the timeout */
-+ stop_suspend_timer(arm_state);
-+ if (!vchiq_videocore_wanted(state)) {
-+ vchiq_log_info(vchiq_susp_log_level, "%s videocore "
-+ "idle, initiating suspend", __func__);
-+ status = vchiq_arm_vcsuspend(state);
-+ } else if (arm_state->autosuspend_override <
-+ FORCE_SUSPEND_FAIL_MAX) {
-+ vchiq_log_info(vchiq_susp_log_level, "%s letting "
-+ "videocore go idle", __func__);
-+ status = VCHIQ_SUCCESS;
-+ } else {
-+ vchiq_log_warning(vchiq_susp_log_level, "%s failed too "
-+ "many times - attempting suspend", __func__);
-+ status = vchiq_arm_vcsuspend(state);
-+ }
-+ } else {
-+ vchiq_log_info(vchiq_susp_log_level, "%s videocore suspend "
-+ "in progress - wait for completion", __func__);
-+ status = VCHIQ_SUCCESS;
-+ }
-+
-+ /* Wait for suspend to happen due to system idle (not forced..) */
-+ if (status != VCHIQ_SUCCESS)
-+ goto unblock_resume;
-+
-+ do {
-+ write_unlock_bh(&arm_state->susp_res_lock);
-+
-+ rc = wait_for_completion_interruptible_timeout(
-+ &arm_state->vc_suspend_complete,
-+ msecs_to_jiffies(FORCE_SUSPEND_TIMEOUT_MS));
-+
-+ write_lock_bh(&arm_state->susp_res_lock);
-+ if (rc < 0) {
-+ vchiq_log_warning(vchiq_susp_log_level, "%s "
-+ "interrupted waiting for suspend", __func__);
-+ status = VCHIQ_ERROR;
-+ goto unblock_resume;
-+ } else if (rc == 0) {
-+ if (arm_state->vc_suspend_state > VC_SUSPEND_IDLE) {
-+ /* Repeat timeout once if in progress */
-+ if (repeat < 0) {
-+ repeat = 1;
-+ continue;
-+ }
-+ }
-+ arm_state->autosuspend_override++;
-+ output_timeout_error(state);
-+
-+ status = VCHIQ_RETRY;
-+ goto unblock_resume;
-+ }
-+ } while (0 < (repeat--));
-+
-+ /* Check and report state in case we need to abort ARM suspend */
-+ if (arm_state->vc_suspend_state != VC_SUSPEND_SUSPENDED) {
-+ status = VCHIQ_RETRY;
-+ vchiq_log_error(vchiq_susp_log_level,
-+ "%s videocore suspend failed (state %s)", __func__,
-+ suspend_state_names[arm_state->vc_suspend_state +
-+ VC_SUSPEND_NUM_OFFSET]);
-+ /* Reset the state only if it's still in an error state.
-+ * Something could have already initiated another suspend. */
-+ if (arm_state->vc_suspend_state < VC_SUSPEND_IDLE)
-+ set_suspend_state(arm_state, VC_SUSPEND_IDLE);
-+
-+ goto unblock_resume;
-+ }
-+
-+ /* successfully suspended - unlock and exit */
-+ goto unlock;
-+
-+unblock_resume:
-+ /* all error states need to unblock resume before exit */
-+ unblock_resume(arm_state);
-+
-+unlock:
-+ write_unlock_bh(&arm_state->susp_res_lock);
-+
-+out:
-+ vchiq_log_trace(vchiq_susp_log_level, "%s exit %d", __func__, status);
-+ return status;
-+}
-+
-+void
-+vchiq_check_suspend(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+
-+ if (!arm_state)
-+ goto out;
-+
-+ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-+
-+ write_lock_bh(&arm_state->susp_res_lock);
-+ if (arm_state->vc_suspend_state != VC_SUSPEND_SUSPENDED &&
-+ arm_state->first_connect &&
-+ !vchiq_videocore_wanted(state)) {
-+ vchiq_arm_vcsuspend(state);
-+ }
-+ write_unlock_bh(&arm_state->susp_res_lock);
-+
-+out:
-+ vchiq_log_trace(vchiq_susp_log_level, "%s exit", __func__);
-+ return;
-+}
-+
-+
-+int
-+vchiq_arm_allow_resume(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+ int resume = 0;
-+ int ret = -1;
-+
-+ if (!arm_state)
-+ goto out;
-+
-+ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-+
-+ write_lock_bh(&arm_state->susp_res_lock);
-+ unblock_resume(arm_state);
-+ resume = vchiq_check_resume(state);
-+ write_unlock_bh(&arm_state->susp_res_lock);
-+
-+ if (resume) {
-+ if (wait_for_completion_interruptible(
-+ &arm_state->vc_resume_complete) < 0) {
-+ vchiq_log_error(vchiq_susp_log_level,
-+ "%s interrupted", __func__);
-+ /* failed, cannot accurately derive suspend
-+ * state, so exit early. */
-+ goto out;
-+ }
-+ }
-+
-+ read_lock_bh(&arm_state->susp_res_lock);
-+ if (arm_state->vc_suspend_state == VC_SUSPEND_SUSPENDED) {
-+ vchiq_log_info(vchiq_susp_log_level,
-+ "%s: Videocore remains suspended", __func__);
-+ } else {
-+ vchiq_log_info(vchiq_susp_log_level,
-+ "%s: Videocore resumed", __func__);
-+ ret = 0;
-+ }
-+ read_unlock_bh(&arm_state->susp_res_lock);
-+out:
-+ vchiq_log_trace(vchiq_susp_log_level, "%s exit %d", __func__, ret);
-+ return ret;
-+}
-+
-+/* This function should be called with the write lock held */
-+int
-+vchiq_check_resume(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+ int resume = 0;
-+
-+ if (!arm_state)
-+ goto out;
-+
-+ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-+
-+ if (need_resume(state)) {
-+ set_resume_state(arm_state, VC_RESUME_REQUESTED);
-+ request_poll(state, NULL, 0);
-+ resume = 1;
-+ }
-+
-+out:
-+ vchiq_log_trace(vchiq_susp_log_level, "%s exit", __func__);
-+ return resume;
-+}
-+
-+void
-+vchiq_platform_check_resume(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+ int res = 0;
-+
-+ if (!arm_state)
-+ goto out;
-+
-+ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-+
-+ write_lock_bh(&arm_state->susp_res_lock);
-+ if (arm_state->wake_address == 0) {
-+ vchiq_log_info(vchiq_susp_log_level,
-+ "%s: already awake", __func__);
-+ goto unlock;
-+ }
-+ if (arm_state->vc_resume_state == VC_RESUME_IN_PROGRESS) {
-+ vchiq_log_info(vchiq_susp_log_level,
-+ "%s: already resuming", __func__);
-+ goto unlock;
-+ }
-+
-+ if (arm_state->vc_resume_state == VC_RESUME_REQUESTED) {
-+ set_resume_state(arm_state, VC_RESUME_IN_PROGRESS);
-+ res = 1;
-+ } else
-+ vchiq_log_trace(vchiq_susp_log_level,
-+ "%s: not resuming (resume state %s)", __func__,
-+ resume_state_names[arm_state->vc_resume_state +
-+ VC_RESUME_NUM_OFFSET]);
-+
-+unlock:
-+ write_unlock_bh(&arm_state->susp_res_lock);
-+
-+ if (res)
-+ vchiq_platform_resume(state);
-+
-+out:
-+ vchiq_log_trace(vchiq_susp_log_level, "%s exit", __func__);
-+ return;
-+
-+}
-+
-+
-+
-+VCHIQ_STATUS_T
-+vchiq_use_internal(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service,
-+ enum USE_TYPE_E use_type)
-+{
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+ VCHIQ_STATUS_T ret = VCHIQ_SUCCESS;
-+ char entity[16];
-+ int *entity_uc;
-+ int local_uc, local_entity_uc;
-+
-+ if (!arm_state)
-+ goto out;
-+
-+ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-+
-+ if (use_type == USE_TYPE_VCHIQ) {
-+ sprintf(entity, "VCHIQ: ");
-+ entity_uc = &arm_state->peer_use_count;
-+ } else if (service) {
-+ sprintf(entity, "%c%c%c%c:%03d",
-+ VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc),
-+ service->client_id);
-+ entity_uc = &service->service_use_count;
-+ } else {
-+ vchiq_log_error(vchiq_susp_log_level, "%s null service "
-+ "ptr", __func__);
-+ ret = VCHIQ_ERROR;
-+ goto out;
-+ }
-+
-+ write_lock_bh(&arm_state->susp_res_lock);
-+ while (arm_state->resume_blocked) {
-+ /* If we call 'use' while force suspend is waiting for suspend,
-+ * then we're about to block the thread which the force is
-+ * waiting to complete, so we're bound to just time out. In this
-+ * case, set the suspend state such that the wait will be
-+ * canceled, so we can complete as quickly as possible. */
-+ if (arm_state->resume_blocked && arm_state->vc_suspend_state ==
-+ VC_SUSPEND_IDLE) {
-+ set_suspend_state(arm_state, VC_SUSPEND_FORCE_CANCELED);
-+ break;
-+ }
-+ /* If suspend is already in progress then we need to block */
-+ if (!try_wait_for_completion(&arm_state->resume_blocker)) {
-+ /* Indicate that there are threads waiting on the resume
-+ * blocker. These need to be allowed to complete before
-+ * a _second_ call to force suspend can complete,
-+ * otherwise low priority threads might never actually
-+ * continue */
-+ arm_state->blocked_count++;
-+ write_unlock_bh(&arm_state->susp_res_lock);
-+ vchiq_log_info(vchiq_susp_log_level, "%s %s resume "
-+ "blocked - waiting...", __func__, entity);
-+ if (wait_for_completion_killable(
-+ &arm_state->resume_blocker) != 0) {
-+ vchiq_log_error(vchiq_susp_log_level, "%s %s "
-+ "wait for resume blocker interrupted",
-+ __func__, entity);
-+ ret = VCHIQ_ERROR;
-+ write_lock_bh(&arm_state->susp_res_lock);
-+ arm_state->blocked_count--;
-+ write_unlock_bh(&arm_state->susp_res_lock);
-+ goto out;
-+ }
-+ vchiq_log_info(vchiq_susp_log_level, "%s %s resume "
-+ "unblocked", __func__, entity);
-+ write_lock_bh(&arm_state->susp_res_lock);
-+ if (--arm_state->blocked_count == 0)
-+ complete_all(&arm_state->blocked_blocker);
-+ }
-+ }
-+
-+ stop_suspend_timer(arm_state);
-+
-+ local_uc = ++arm_state->videocore_use_count;
-+ local_entity_uc = ++(*entity_uc);
-+
-+ /* If there's a pending request which hasn't yet been serviced then
-+ * just clear it. If we're past VC_SUSPEND_REQUESTED state then
-+ * vc_resume_complete will block until we either resume or fail to
-+ * suspend */
-+ if (arm_state->vc_suspend_state <= VC_SUSPEND_REQUESTED)
-+ set_suspend_state(arm_state, VC_SUSPEND_IDLE);
-+
-+ if ((use_type != USE_TYPE_SERVICE_NO_RESUME) && need_resume(state)) {
-+ set_resume_state(arm_state, VC_RESUME_REQUESTED);
-+ vchiq_log_info(vchiq_susp_log_level,
-+ "%s %s count %d, state count %d",
-+ __func__, entity, local_entity_uc, local_uc);
-+ request_poll(state, NULL, 0);
-+ } else
-+ vchiq_log_trace(vchiq_susp_log_level,
-+ "%s %s count %d, state count %d",
-+ __func__, entity, *entity_uc, local_uc);
-+
-+
-+ write_unlock_bh(&arm_state->susp_res_lock);
-+
-+ /* Completion is in a done state when we're not suspended, so this won't
-+ * block for the non-suspended case. */
-+ if (!try_wait_for_completion(&arm_state->vc_resume_complete)) {
-+ vchiq_log_info(vchiq_susp_log_level, "%s %s wait for resume",
-+ __func__, entity);
-+ if (wait_for_completion_killable(
-+ &arm_state->vc_resume_complete) != 0) {
-+ vchiq_log_error(vchiq_susp_log_level, "%s %s wait for "
-+ "resume interrupted", __func__, entity);
-+ ret = VCHIQ_ERROR;
-+ goto out;
-+ }
-+ vchiq_log_info(vchiq_susp_log_level, "%s %s resumed", __func__,
-+ entity);
-+ }
-+
-+ if (ret == VCHIQ_SUCCESS) {
-+ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
-+ long ack_cnt = atomic_xchg(&arm_state->ka_use_ack_count, 0);
-+ while (ack_cnt && (status == VCHIQ_SUCCESS)) {
-+ /* Send the use notify to videocore */
-+ status = vchiq_send_remote_use_active(state);
-+ if (status == VCHIQ_SUCCESS)
-+ ack_cnt--;
-+ else
-+ atomic_add(ack_cnt,
-+ &arm_state->ka_use_ack_count);
-+ }
-+ }
-+
-+out:
-+ vchiq_log_trace(vchiq_susp_log_level, "%s exit %d", __func__, ret);
-+ return ret;
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_release_internal(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service)
-+{
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+ VCHIQ_STATUS_T ret = VCHIQ_SUCCESS;
-+ char entity[16];
-+ int *entity_uc;
-+ int local_uc, local_entity_uc;
-+
-+ if (!arm_state)
-+ goto out;
-+
-+ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-+
-+ if (service) {
-+ sprintf(entity, "%c%c%c%c:%03d",
-+ VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc),
-+ service->client_id);
-+ entity_uc = &service->service_use_count;
-+ } else {
-+ sprintf(entity, "PEER: ");
-+ entity_uc = &arm_state->peer_use_count;
-+ }
-+
-+ write_lock_bh(&arm_state->susp_res_lock);
-+ if (!arm_state->videocore_use_count || !(*entity_uc)) {
-+ /* Don't use BUG_ON - don't allow user thread to crash kernel */
-+ WARN_ON(!arm_state->videocore_use_count);
-+ WARN_ON(!(*entity_uc));
-+ ret = VCHIQ_ERROR;
-+ goto unlock;
-+ }
-+ local_uc = --arm_state->videocore_use_count;
-+ local_entity_uc = --(*entity_uc);
-+
-+ if (!vchiq_videocore_wanted(state)) {
-+ if (vchiq_platform_use_suspend_timer() &&
-+ !arm_state->resume_blocked) {
-+ /* Only use the timer if we're not trying to force
-+ * suspend (=> resume_blocked) */
-+ start_suspend_timer(arm_state);
-+ } else {
-+ vchiq_log_info(vchiq_susp_log_level,
-+ "%s %s count %d, state count %d - suspending",
-+ __func__, entity, *entity_uc,
-+ arm_state->videocore_use_count);
-+ vchiq_arm_vcsuspend(state);
-+ }
-+ } else
-+ vchiq_log_trace(vchiq_susp_log_level,
-+ "%s %s count %d, state count %d",
-+ __func__, entity, *entity_uc,
-+ arm_state->videocore_use_count);
-+
-+unlock:
-+ write_unlock_bh(&arm_state->susp_res_lock);
-+
-+out:
-+ vchiq_log_trace(vchiq_susp_log_level, "%s exit %d", __func__, ret);
-+ return ret;
-+}
-+
-+void
-+vchiq_on_remote_use(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-+ atomic_inc(&arm_state->ka_use_count);
-+ complete(&arm_state->ka_evt);
-+}
-+
-+void
-+vchiq_on_remote_release(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-+ atomic_inc(&arm_state->ka_release_count);
-+ complete(&arm_state->ka_evt);
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_use_service_internal(VCHIQ_SERVICE_T *service)
-+{
-+ return vchiq_use_internal(service->state, service, USE_TYPE_SERVICE);
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_release_service_internal(VCHIQ_SERVICE_T *service)
-+{
-+ return vchiq_release_internal(service->state, service);
-+}
-+
-+VCHIQ_DEBUGFS_NODE_T *
-+vchiq_instance_get_debugfs_node(VCHIQ_INSTANCE_T instance)
-+{
-+ return &instance->debugfs_node;
-+}
-+
-+int
-+vchiq_instance_get_use_count(VCHIQ_INSTANCE_T instance)
-+{
-+ VCHIQ_SERVICE_T *service;
-+ int use_count = 0, i;
-+ i = 0;
-+ while ((service = next_service_by_instance(instance->state,
-+ instance, &i)) != NULL) {
-+ use_count += service->service_use_count;
-+ unlock_service(service);
-+ }
-+ return use_count;
-+}
-+
-+int
-+vchiq_instance_get_pid(VCHIQ_INSTANCE_T instance)
-+{
-+ return instance->pid;
-+}
-+
-+int
-+vchiq_instance_get_trace(VCHIQ_INSTANCE_T instance)
-+{
-+ return instance->trace;
-+}
-+
-+void
-+vchiq_instance_set_trace(VCHIQ_INSTANCE_T instance, int trace)
-+{
-+ VCHIQ_SERVICE_T *service;
-+ int i;
-+ i = 0;
-+ while ((service = next_service_by_instance(instance->state,
-+ instance, &i)) != NULL) {
-+ service->trace = trace;
-+ unlock_service(service);
-+ }
-+ instance->trace = (trace != 0);
-+}
-+
-+static void suspend_timer_callback(unsigned long context)
-+{
-+ VCHIQ_STATE_T *state = (VCHIQ_STATE_T *)context;
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+ if (!arm_state)
-+ goto out;
-+ vchiq_log_info(vchiq_susp_log_level,
-+ "%s - suspend timer expired - check suspend", __func__);
-+ vchiq_check_suspend(state);
-+out:
-+ return;
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_use_service_no_resume(VCHIQ_SERVICE_HANDLE_T handle)
-+{
-+ VCHIQ_STATUS_T ret = VCHIQ_ERROR;
-+ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
-+ if (service) {
-+ ret = vchiq_use_internal(service->state, service,
-+ USE_TYPE_SERVICE_NO_RESUME);
-+ unlock_service(service);
-+ }
-+ return ret;
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_use_service(VCHIQ_SERVICE_HANDLE_T handle)
-+{
-+ VCHIQ_STATUS_T ret = VCHIQ_ERROR;
-+ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
-+ if (service) {
-+ ret = vchiq_use_internal(service->state, service,
-+ USE_TYPE_SERVICE);
-+ unlock_service(service);
-+ }
-+ return ret;
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_release_service(VCHIQ_SERVICE_HANDLE_T handle)
-+{
-+ VCHIQ_STATUS_T ret = VCHIQ_ERROR;
-+ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
-+ if (service) {
-+ ret = vchiq_release_internal(service->state, service);
-+ unlock_service(service);
-+ }
-+ return ret;
-+}
-+
-+void
-+vchiq_dump_service_use_state(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+ int i, j = 0;
-+ /* Only dump 64 services */
-+ static const int local_max_services = 64;
-+ /* If there's more than 64 services, only dump ones with
-+ * non-zero counts */
-+ int only_nonzero = 0;
-+ static const char *nz = "<-- preventing suspend";
-+
-+ enum vc_suspend_status vc_suspend_state;
-+ enum vc_resume_status vc_resume_state;
-+ int peer_count;
-+ int vc_use_count;
-+ int active_services;
-+ struct service_data_struct {
-+ int fourcc;
-+ int clientid;
-+ int use_count;
-+ } service_data[local_max_services];
-+
-+ if (!arm_state)
-+ return;
-+
-+ read_lock_bh(&arm_state->susp_res_lock);
-+ vc_suspend_state = arm_state->vc_suspend_state;
-+ vc_resume_state = arm_state->vc_resume_state;
-+ peer_count = arm_state->peer_use_count;
-+ vc_use_count = arm_state->videocore_use_count;
-+ active_services = state->unused_service;
-+ if (active_services > local_max_services)
-+ only_nonzero = 1;
-+
-+ for (i = 0; (i < active_services) && (j < local_max_services); i++) {
-+ VCHIQ_SERVICE_T *service_ptr = state->services[i];
-+ if (!service_ptr)
-+ continue;
-+
-+ if (only_nonzero && !service_ptr->service_use_count)
-+ continue;
-+
-+ if (service_ptr->srvstate != VCHIQ_SRVSTATE_FREE) {
-+ service_data[j].fourcc = service_ptr->base.fourcc;
-+ service_data[j].clientid = service_ptr->client_id;
-+ service_data[j++].use_count = service_ptr->
-+ service_use_count;
-+ }
-+ }
-+
-+ read_unlock_bh(&arm_state->susp_res_lock);
-+
-+ vchiq_log_warning(vchiq_susp_log_level,
-+ "-- Videcore suspend state: %s --",
-+ suspend_state_names[vc_suspend_state + VC_SUSPEND_NUM_OFFSET]);
-+ vchiq_log_warning(vchiq_susp_log_level,
-+ "-- Videcore resume state: %s --",
-+ resume_state_names[vc_resume_state + VC_RESUME_NUM_OFFSET]);
-+
-+ if (only_nonzero)
-+ vchiq_log_warning(vchiq_susp_log_level, "Too many active "
-+ "services (%d). Only dumping up to first %d services "
-+ "with non-zero use-count", active_services,
-+ local_max_services);
-+
-+ for (i = 0; i < j; i++) {
-+ vchiq_log_warning(vchiq_susp_log_level,
-+ "----- %c%c%c%c:%d service count %d %s",
-+ VCHIQ_FOURCC_AS_4CHARS(service_data[i].fourcc),
-+ service_data[i].clientid,
-+ service_data[i].use_count,
-+ service_data[i].use_count ? nz : "");
-+ }
-+ vchiq_log_warning(vchiq_susp_log_level,
-+ "----- VCHIQ use count count %d", peer_count);
-+ vchiq_log_warning(vchiq_susp_log_level,
-+ "--- Overall vchiq instance use count %d", vc_use_count);
-+
-+ vchiq_dump_platform_use_state(state);
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_check_service(VCHIQ_SERVICE_T *service)
-+{
-+ VCHIQ_ARM_STATE_T *arm_state;
-+ VCHIQ_STATUS_T ret = VCHIQ_ERROR;
-+
-+ if (!service || !service->state)
-+ goto out;
-+
-+ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-+
-+ arm_state = vchiq_platform_get_arm_state(service->state);
-+
-+ read_lock_bh(&arm_state->susp_res_lock);
-+ if (service->service_use_count)
-+ ret = VCHIQ_SUCCESS;
-+ read_unlock_bh(&arm_state->susp_res_lock);
-+
-+ if (ret == VCHIQ_ERROR) {
-+ vchiq_log_error(vchiq_susp_log_level,
-+ "%s ERROR - %c%c%c%c:%d service count %d, "
-+ "state count %d, videocore suspend state %s", __func__,
-+ VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc),
-+ service->client_id, service->service_use_count,
-+ arm_state->videocore_use_count,
-+ suspend_state_names[arm_state->vc_suspend_state +
-+ VC_SUSPEND_NUM_OFFSET]);
-+ vchiq_dump_service_use_state(service->state);
-+ }
-+out:
-+ return ret;
-+}
-+
-+/* stub functions */
-+void vchiq_on_remote_use_active(VCHIQ_STATE_T *state)
-+{
-+ (void)state;
-+}
-+
-+void vchiq_platform_conn_state_changed(VCHIQ_STATE_T *state,
-+ VCHIQ_CONNSTATE_T oldstate, VCHIQ_CONNSTATE_T newstate)
-+{
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+ vchiq_log_info(vchiq_susp_log_level, "%d: %s->%s", state->id,
-+ get_conn_state_name(oldstate), get_conn_state_name(newstate));
-+ if (state->conn_state == VCHIQ_CONNSTATE_CONNECTED) {
-+ write_lock_bh(&arm_state->susp_res_lock);
-+ if (!arm_state->first_connect) {
-+ char threadname[10];
-+ arm_state->first_connect = 1;
-+ write_unlock_bh(&arm_state->susp_res_lock);
-+ snprintf(threadname, sizeof(threadname), "VCHIQka-%d",
-+ state->id);
-+ arm_state->ka_thread = kthread_create(
-+ &vchiq_keepalive_thread_func,
-+ (void *)state,
-+ threadname);
-+ if (arm_state->ka_thread == NULL) {
-+ vchiq_log_error(vchiq_susp_log_level,
-+ "vchiq: FATAL: couldn't create thread %s",
-+ threadname);
-+ } else {
-+ wake_up_process(arm_state->ka_thread);
-+ }
-+ } else
-+ write_unlock_bh(&arm_state->susp_res_lock);
-+ }
-+}
-+
-+static int vchiq_probe(struct platform_device *pdev)
-+{
-+ struct device_node *fw_node;
-+ struct rpi_firmware *fw;
-+ int err;
-+ void *ptr_err;
-+
-+ fw_node = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
-+/* Remove comment when booting without Device Tree is no longer supported
-+ if (!fw_node) {
-+ dev_err(&pdev->dev, "Missing firmware node\n");
-+ return -ENOENT;
-+ }
-+*/
-+ fw = rpi_firmware_get(fw_node);
-+ if (!fw)
-+ return -EPROBE_DEFER;
-+
-+ platform_set_drvdata(pdev, fw);
-+
-+ /* create debugfs entries */
-+ err = vchiq_debugfs_init();
-+ if (err != 0)
-+ goto failed_debugfs_init;
-+
-+ err = alloc_chrdev_region(&vchiq_devid, VCHIQ_MINOR, 1, DEVICE_NAME);
-+ if (err != 0) {
-+ vchiq_log_error(vchiq_arm_log_level,
-+ "Unable to allocate device number");
-+ goto failed_alloc_chrdev;
-+ }
-+ cdev_init(&vchiq_cdev, &vchiq_fops);
-+ vchiq_cdev.owner = THIS_MODULE;
-+ err = cdev_add(&vchiq_cdev, vchiq_devid, 1);
-+ if (err != 0) {
-+ vchiq_log_error(vchiq_arm_log_level,
-+ "Unable to register device");
-+ goto failed_cdev_add;
-+ }
-+
-+ /* create sysfs entries */
-+ vchiq_class = class_create(THIS_MODULE, DEVICE_NAME);
-+ ptr_err = vchiq_class;
-+ if (IS_ERR(ptr_err))
-+ goto failed_class_create;
-+
-+ vchiq_dev = device_create(vchiq_class, NULL,
-+ vchiq_devid, NULL, "vchiq");
-+ ptr_err = vchiq_dev;
-+ if (IS_ERR(ptr_err))
-+ goto failed_device_create;
-+
-+ err = vchiq_platform_init(pdev, &g_state);
-+ if (err != 0)
-+ goto failed_platform_init;
-+
-+ vchiq_log_info(vchiq_arm_log_level,
-+ "vchiq: initialised - version %d (min %d), device %d.%d",
-+ VCHIQ_VERSION, VCHIQ_VERSION_MIN,
-+ MAJOR(vchiq_devid), MINOR(vchiq_devid));
-+
-+ return 0;
-+
-+failed_platform_init:
-+ device_destroy(vchiq_class, vchiq_devid);
-+failed_device_create:
-+ class_destroy(vchiq_class);
-+failed_class_create:
-+ cdev_del(&vchiq_cdev);
-+ err = PTR_ERR(ptr_err);
-+failed_cdev_add:
-+ unregister_chrdev_region(vchiq_devid, 1);
-+failed_alloc_chrdev:
-+ vchiq_debugfs_deinit();
-+failed_debugfs_init:
-+ vchiq_log_warning(vchiq_arm_log_level, "could not load vchiq");
-+ return err;
-+}
-+
-+static int vchiq_remove(struct platform_device *pdev)
-+{
-+ device_destroy(vchiq_class, vchiq_devid);
-+ class_destroy(vchiq_class);
-+ cdev_del(&vchiq_cdev);
-+ unregister_chrdev_region(vchiq_devid, 1);
-+
-+ return 0;
-+}
-+
-+static const struct of_device_id vchiq_of_match[] = {
-+ { .compatible = "brcm,bcm2835-vchiq", },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(of, vchiq_of_match);
-+
-+static struct platform_driver vchiq_driver = {
-+ .driver = {
-+ .name = "bcm2835_vchiq",
-+ .owner = THIS_MODULE,
-+ .of_match_table = vchiq_of_match,
-+ },
-+ .probe = vchiq_probe,
-+ .remove = vchiq_remove,
-+};
-+module_platform_driver(vchiq_driver);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Broadcom Corporation");
---- /dev/null
-+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.h
-@@ -0,0 +1,220 @@
-+/**
-+ * Copyright (c) 2014 Raspberry Pi (Trading) Ltd. All rights reserved.
-+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHIQ_ARM_H
-+#define VCHIQ_ARM_H
-+
-+#include <linux/mutex.h>
-+#include <linux/platform_device.h>
-+#include <linux/semaphore.h>
-+#include <linux/atomic.h>
-+#include "vchiq_core.h"
-+#include "vchiq_debugfs.h"
-+
-+
-+enum vc_suspend_status {
-+ VC_SUSPEND_FORCE_CANCELED = -3, /* Force suspend canceled, too busy */
-+ VC_SUSPEND_REJECTED = -2, /* Videocore rejected suspend request */
-+ VC_SUSPEND_FAILED = -1, /* Videocore suspend failed */
-+ VC_SUSPEND_IDLE = 0, /* VC active, no suspend actions */
-+ VC_SUSPEND_REQUESTED, /* User has requested suspend */
-+ VC_SUSPEND_IN_PROGRESS, /* Slot handler has recvd suspend request */
-+ VC_SUSPEND_SUSPENDED /* Videocore suspend succeeded */
-+};
-+
-+enum vc_resume_status {
-+ VC_RESUME_FAILED = -1, /* Videocore resume failed */
-+ VC_RESUME_IDLE = 0, /* VC suspended, no resume actions */
-+ VC_RESUME_REQUESTED, /* User has requested resume */
-+ VC_RESUME_IN_PROGRESS, /* Slot handler has received resume request */
-+ VC_RESUME_RESUMED /* Videocore resumed successfully (active) */
-+};
-+
-+
-+enum USE_TYPE_E {
-+ USE_TYPE_SERVICE,
-+ USE_TYPE_SERVICE_NO_RESUME,
-+ USE_TYPE_VCHIQ
-+};
-+
-+
-+
-+typedef struct vchiq_arm_state_struct {
-+ /* Keepalive-related data */
-+ struct task_struct *ka_thread;
-+ struct completion ka_evt;
-+ atomic_t ka_use_count;
-+ atomic_t ka_use_ack_count;
-+ atomic_t ka_release_count;
-+
-+ struct completion vc_suspend_complete;
-+ struct completion vc_resume_complete;
-+
-+ rwlock_t susp_res_lock;
-+ enum vc_suspend_status vc_suspend_state;
-+ enum vc_resume_status vc_resume_state;
-+
-+ unsigned int wake_address;
-+
-+ struct timer_list suspend_timer;
-+ int suspend_timer_timeout;
-+ int suspend_timer_running;
-+
-+ /* Global use count for videocore.
-+ ** This is equal to the sum of the use counts for all services. When
-+ ** this hits zero the videocore suspend procedure will be initiated.
-+ */
-+ int videocore_use_count;
-+
-+ /* Use count to track requests from videocore peer.
-+ ** This use count is not associated with a service, so needs to be
-+ ** tracked separately with the state.
-+ */
-+ int peer_use_count;
-+
-+ /* Flag to indicate whether resume is blocked. This happens when the
-+ ** ARM is suspending
-+ */
-+ struct completion resume_blocker;
-+ int resume_blocked;
-+ struct completion blocked_blocker;
-+ int blocked_count;
-+
-+ int autosuspend_override;
-+
-+ /* Flag to indicate that the first vchiq connect has made it through.
-+ ** This means that both sides should be fully ready, and we should
-+ ** be able to suspend after this point.
-+ */
-+ int first_connect;
-+
-+ unsigned long long suspend_start_time;
-+ unsigned long long sleep_start_time;
-+ unsigned long long resume_start_time;
-+ unsigned long long last_wake_time;
-+
-+} VCHIQ_ARM_STATE_T;
-+
-+extern int vchiq_arm_log_level;
-+extern int vchiq_susp_log_level;
-+
-+int vchiq_platform_init(struct platform_device *pdev, VCHIQ_STATE_T *state);
-+
-+extern VCHIQ_STATE_T *
-+vchiq_get_state(void);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_arm_vcsuspend(VCHIQ_STATE_T *state);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_arm_force_suspend(VCHIQ_STATE_T *state);
-+
-+extern int
-+vchiq_arm_allow_resume(VCHIQ_STATE_T *state);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_arm_vcresume(VCHIQ_STATE_T *state);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_arm_init_state(VCHIQ_STATE_T *state, VCHIQ_ARM_STATE_T *arm_state);
-+
-+extern int
-+vchiq_check_resume(VCHIQ_STATE_T *state);
-+
-+extern void
-+vchiq_check_suspend(VCHIQ_STATE_T *state);
-+ VCHIQ_STATUS_T
-+vchiq_use_service(VCHIQ_SERVICE_HANDLE_T handle);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_release_service(VCHIQ_SERVICE_HANDLE_T handle);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_check_service(VCHIQ_SERVICE_T *service);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_platform_suspend(VCHIQ_STATE_T *state);
-+
-+extern int
-+vchiq_platform_videocore_wanted(VCHIQ_STATE_T *state);
-+
-+extern int
-+vchiq_platform_use_suspend_timer(void);
-+
-+extern void
-+vchiq_dump_platform_use_state(VCHIQ_STATE_T *state);
-+
-+extern void
-+vchiq_dump_service_use_state(VCHIQ_STATE_T *state);
-+
-+extern VCHIQ_ARM_STATE_T*
-+vchiq_platform_get_arm_state(VCHIQ_STATE_T *state);
-+
-+extern int
-+vchiq_videocore_wanted(VCHIQ_STATE_T *state);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_use_internal(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service,
-+ enum USE_TYPE_E use_type);
-+extern VCHIQ_STATUS_T
-+vchiq_release_internal(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service);
-+
-+extern VCHIQ_DEBUGFS_NODE_T *
-+vchiq_instance_get_debugfs_node(VCHIQ_INSTANCE_T instance);
-+
-+extern int
-+vchiq_instance_get_use_count(VCHIQ_INSTANCE_T instance);
-+
-+extern int
-+vchiq_instance_get_pid(VCHIQ_INSTANCE_T instance);
-+
-+extern int
-+vchiq_instance_get_trace(VCHIQ_INSTANCE_T instance);
-+
-+extern void
-+vchiq_instance_set_trace(VCHIQ_INSTANCE_T instance, int trace);
-+
-+extern void
-+set_suspend_state(VCHIQ_ARM_STATE_T *arm_state,
-+ enum vc_suspend_status new_state);
-+
-+extern void
-+set_resume_state(VCHIQ_ARM_STATE_T *arm_state,
-+ enum vc_resume_status new_state);
-+
-+extern void
-+start_suspend_timer(VCHIQ_ARM_STATE_T *arm_state);
-+
-+
-+#endif /* VCHIQ_ARM_H */
---- /dev/null
-+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_build_info.h
-@@ -0,0 +1,37 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+const char *vchiq_get_build_hostname(void);
-+const char *vchiq_get_build_version(void);
-+const char *vchiq_get_build_time(void);
-+const char *vchiq_get_build_date(void);
---- /dev/null
-+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_cfg.h
-@@ -0,0 +1,69 @@
-+/**
-+ * Copyright (c) 2010-2014 Broadcom. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHIQ_CFG_H
-+#define VCHIQ_CFG_H
-+
-+#define VCHIQ_MAGIC VCHIQ_MAKE_FOURCC('V', 'C', 'H', 'I')
-+/* The version of VCHIQ - change with any non-trivial change */
-+#define VCHIQ_VERSION 8
-+/* The minimum compatible version - update to match VCHIQ_VERSION with any
-+** incompatible change */
-+#define VCHIQ_VERSION_MIN 3
-+
-+/* The version that introduced the VCHIQ_IOC_LIB_VERSION ioctl */
-+#define VCHIQ_VERSION_LIB_VERSION 7
-+
-+/* The version that introduced the VCHIQ_IOC_CLOSE_DELIVERED ioctl */
-+#define VCHIQ_VERSION_CLOSE_DELIVERED 7
-+
-+/* The version that made it safe to use SYNCHRONOUS mode */
-+#define VCHIQ_VERSION_SYNCHRONOUS_MODE 8
-+
-+#define VCHIQ_MAX_STATES 1
-+#define VCHIQ_MAX_SERVICES 4096
-+#define VCHIQ_MAX_SLOTS 128
-+#define VCHIQ_MAX_SLOTS_PER_SIDE 64
-+
-+#define VCHIQ_NUM_CURRENT_BULKS 32
-+#define VCHIQ_NUM_SERVICE_BULKS 4
-+
-+#ifndef VCHIQ_ENABLE_DEBUG
-+#define VCHIQ_ENABLE_DEBUG 1
-+#endif
-+
-+#ifndef VCHIQ_ENABLE_STATS
-+#define VCHIQ_ENABLE_STATS 1
-+#endif
-+
-+#endif /* VCHIQ_CFG_H */
---- /dev/null
-+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.c
-@@ -0,0 +1,120 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#include "vchiq_connected.h"
-+#include "vchiq_core.h"
-+#include "vchiq_killable.h"
-+#include <linux/module.h>
-+#include <linux/mutex.h>
-+
-+#define MAX_CALLBACKS 10
-+
-+static int g_connected;
-+static int g_num_deferred_callbacks;
-+static VCHIQ_CONNECTED_CALLBACK_T g_deferred_callback[MAX_CALLBACKS];
-+static int g_once_init;
-+static struct mutex g_connected_mutex;
-+
-+/****************************************************************************
-+*
-+* Function to initialize our lock.
-+*
-+***************************************************************************/
-+
-+static void connected_init(void)
-+{
-+ if (!g_once_init) {
-+ mutex_init(&g_connected_mutex);
-+ g_once_init = 1;
-+ }
-+}
-+
-+/****************************************************************************
-+*
-+* This function is used to defer initialization until the vchiq stack is
-+* initialized. If the stack is already initialized, then the callback will
-+* be made immediately, otherwise it will be deferred until
-+* vchiq_call_connected_callbacks is called.
-+*
-+***************************************************************************/
-+
-+void vchiq_add_connected_callback(VCHIQ_CONNECTED_CALLBACK_T callback)
-+{
-+ connected_init();
-+
-+ if (mutex_lock_interruptible(&g_connected_mutex) != 0)
-+ return;
-+
-+ if (g_connected)
-+ /* We're already connected. Call the callback immediately. */
-+
-+ callback();
-+ else {
-+ if (g_num_deferred_callbacks >= MAX_CALLBACKS)
-+ vchiq_log_error(vchiq_core_log_level,
-+ "There already %d callback registered - "
-+ "please increase MAX_CALLBACKS",
-+ g_num_deferred_callbacks);
-+ else {
-+ g_deferred_callback[g_num_deferred_callbacks] =
-+ callback;
-+ g_num_deferred_callbacks++;
-+ }
-+ }
-+ mutex_unlock(&g_connected_mutex);
-+}
-+
-+/****************************************************************************
-+*
-+* This function is called by the vchiq stack once it has been connected to
-+* the videocore and clients can start to use the stack.
-+*
-+***************************************************************************/
-+
-+void vchiq_call_connected_callbacks(void)
-+{
-+ int i;
-+
-+ connected_init();
-+
-+ if (mutex_lock_interruptible(&g_connected_mutex) != 0)
-+ return;
-+
-+ for (i = 0; i < g_num_deferred_callbacks; i++)
-+ g_deferred_callback[i]();
-+
-+ g_num_deferred_callbacks = 0;
-+ g_connected = 1;
-+ mutex_unlock(&g_connected_mutex);
-+}
-+EXPORT_SYMBOL(vchiq_add_connected_callback);
---- /dev/null
-+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.h
-@@ -0,0 +1,50 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHIQ_CONNECTED_H
-+#define VCHIQ_CONNECTED_H
-+
-+/* ---- Include Files ----------------------------------------------------- */
-+
-+/* ---- Constants and Types ---------------------------------------------- */
-+
-+typedef void (*VCHIQ_CONNECTED_CALLBACK_T)(void);
-+
-+/* ---- Variable Externs ------------------------------------------------- */
-+
-+/* ---- Function Prototypes ---------------------------------------------- */
-+
-+void vchiq_add_connected_callback(VCHIQ_CONNECTED_CALLBACK_T callback);
-+void vchiq_call_connected_callbacks(void);
-+
-+#endif /* VCHIQ_CONNECTED_H */
---- /dev/null
-+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c
-@@ -0,0 +1,3934 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#include "vchiq_core.h"
-+#include "vchiq_killable.h"
-+
-+#define VCHIQ_SLOT_HANDLER_STACK 8192
-+
-+#define HANDLE_STATE_SHIFT 12
-+
-+#define SLOT_INFO_FROM_INDEX(state, index) (state->slot_info + (index))
-+#define SLOT_DATA_FROM_INDEX(state, index) (state->slot_data + (index))
-+#define SLOT_INDEX_FROM_DATA(state, data) \
-+ (((unsigned int)((char *)data - (char *)state->slot_data)) / \
-+ VCHIQ_SLOT_SIZE)
-+#define SLOT_INDEX_FROM_INFO(state, info) \
-+ ((unsigned int)(info - state->slot_info))
-+#define SLOT_QUEUE_INDEX_FROM_POS(pos) \
-+ ((int)((unsigned int)(pos) / VCHIQ_SLOT_SIZE))
-+
-+#define BULK_INDEX(x) (x & (VCHIQ_NUM_SERVICE_BULKS - 1))
-+
-+#define SRVTRACE_LEVEL(srv) \
-+ (((srv) && (srv)->trace) ? VCHIQ_LOG_TRACE : vchiq_core_msg_log_level)
-+#define SRVTRACE_ENABLED(srv, lev) \
-+ (((srv) && (srv)->trace) || (vchiq_core_msg_log_level >= (lev)))
-+
-+struct vchiq_open_payload {
-+ int fourcc;
-+ int client_id;
-+ short version;
-+ short version_min;
-+};
-+
-+struct vchiq_openack_payload {
-+ short version;
-+};
-+
-+enum
-+{
-+ QMFLAGS_IS_BLOCKING = (1 << 0),
-+ QMFLAGS_NO_MUTEX_LOCK = (1 << 1),
-+ QMFLAGS_NO_MUTEX_UNLOCK = (1 << 2)
-+};
-+
-+/* we require this for consistency between endpoints */
-+vchiq_static_assert(sizeof(VCHIQ_HEADER_T) == 8);
-+vchiq_static_assert(IS_POW2(sizeof(VCHIQ_HEADER_T)));
-+vchiq_static_assert(IS_POW2(VCHIQ_NUM_CURRENT_BULKS));
-+vchiq_static_assert(IS_POW2(VCHIQ_NUM_SERVICE_BULKS));
-+vchiq_static_assert(IS_POW2(VCHIQ_MAX_SERVICES));
-+vchiq_static_assert(VCHIQ_VERSION >= VCHIQ_VERSION_MIN);
-+
-+/* Run time control of log level, based on KERN_XXX level. */
-+int vchiq_core_log_level = VCHIQ_LOG_DEFAULT;
-+int vchiq_core_msg_log_level = VCHIQ_LOG_DEFAULT;
-+int vchiq_sync_log_level = VCHIQ_LOG_DEFAULT;
-+
-+static atomic_t pause_bulks_count = ATOMIC_INIT(0);
-+
-+static DEFINE_SPINLOCK(service_spinlock);
-+DEFINE_SPINLOCK(bulk_waiter_spinlock);
-+DEFINE_SPINLOCK(quota_spinlock);
-+
-+VCHIQ_STATE_T *vchiq_states[VCHIQ_MAX_STATES];
-+static unsigned int handle_seq;
-+
-+static const char *const srvstate_names[] = {
-+ "FREE",
-+ "HIDDEN",
-+ "LISTENING",
-+ "OPENING",
-+ "OPEN",
-+ "OPENSYNC",
-+ "CLOSESENT",
-+ "CLOSERECVD",
-+ "CLOSEWAIT",
-+ "CLOSED"
-+};
-+
-+static const char *const reason_names[] = {
-+ "SERVICE_OPENED",
-+ "SERVICE_CLOSED",
-+ "MESSAGE_AVAILABLE",
-+ "BULK_TRANSMIT_DONE",
-+ "BULK_RECEIVE_DONE",
-+ "BULK_TRANSMIT_ABORTED",
-+ "BULK_RECEIVE_ABORTED"
-+};
-+
-+static const char *const conn_state_names[] = {
-+ "DISCONNECTED",
-+ "CONNECTING",
-+ "CONNECTED",
-+ "PAUSING",
-+ "PAUSE_SENT",
-+ "PAUSED",
-+ "RESUMING",
-+ "PAUSE_TIMEOUT",
-+ "RESUME_TIMEOUT"
-+};
-+
-+
-+static void
-+release_message_sync(VCHIQ_STATE_T *state, VCHIQ_HEADER_T *header);
-+
-+static const char *msg_type_str(unsigned int msg_type)
-+{
-+ switch (msg_type) {
-+ case VCHIQ_MSG_PADDING: return "PADDING";
-+ case VCHIQ_MSG_CONNECT: return "CONNECT";
-+ case VCHIQ_MSG_OPEN: return "OPEN";
-+ case VCHIQ_MSG_OPENACK: return "OPENACK";
-+ case VCHIQ_MSG_CLOSE: return "CLOSE";
-+ case VCHIQ_MSG_DATA: return "DATA";
-+ case VCHIQ_MSG_BULK_RX: return "BULK_RX";
-+ case VCHIQ_MSG_BULK_TX: return "BULK_TX";
-+ case VCHIQ_MSG_BULK_RX_DONE: return "BULK_RX_DONE";
-+ case VCHIQ_MSG_BULK_TX_DONE: return "BULK_TX_DONE";
-+ case VCHIQ_MSG_PAUSE: return "PAUSE";
-+ case VCHIQ_MSG_RESUME: return "RESUME";
-+ case VCHIQ_MSG_REMOTE_USE: return "REMOTE_USE";
-+ case VCHIQ_MSG_REMOTE_RELEASE: return "REMOTE_RELEASE";
-+ case VCHIQ_MSG_REMOTE_USE_ACTIVE: return "REMOTE_USE_ACTIVE";
-+ }
-+ return "???";
-+}
-+
-+static inline void
-+vchiq_set_service_state(VCHIQ_SERVICE_T *service, int newstate)
-+{
-+ vchiq_log_info(vchiq_core_log_level, "%d: srv:%d %s->%s",
-+ service->state->id, service->localport,
-+ srvstate_names[service->srvstate],
-+ srvstate_names[newstate]);
-+ service->srvstate = newstate;
-+}
-+
-+VCHIQ_SERVICE_T *
-+find_service_by_handle(VCHIQ_SERVICE_HANDLE_T handle)
-+{
-+ VCHIQ_SERVICE_T *service;
-+
-+ spin_lock(&service_spinlock);
-+ service = handle_to_service(handle);
-+ if (service && (service->srvstate != VCHIQ_SRVSTATE_FREE) &&
-+ (service->handle == handle)) {
-+ BUG_ON(service->ref_count == 0);
-+ service->ref_count++;
-+ } else
-+ service = NULL;
-+ spin_unlock(&service_spinlock);
-+
-+ if (!service)
-+ vchiq_log_info(vchiq_core_log_level,
-+ "Invalid service handle 0x%x", handle);
-+
-+ return service;
-+}
-+
-+VCHIQ_SERVICE_T *
-+find_service_by_port(VCHIQ_STATE_T *state, int localport)
-+{
-+ VCHIQ_SERVICE_T *service = NULL;
-+ if ((unsigned int)localport <= VCHIQ_PORT_MAX) {
-+ spin_lock(&service_spinlock);
-+ service = state->services[localport];
-+ if (service && (service->srvstate != VCHIQ_SRVSTATE_FREE)) {
-+ BUG_ON(service->ref_count == 0);
-+ service->ref_count++;
-+ } else
-+ service = NULL;
-+ spin_unlock(&service_spinlock);
-+ }
-+
-+ if (!service)
-+ vchiq_log_info(vchiq_core_log_level,
-+ "Invalid port %d", localport);
-+
-+ return service;
-+}
-+
-+VCHIQ_SERVICE_T *
-+find_service_for_instance(VCHIQ_INSTANCE_T instance,
-+ VCHIQ_SERVICE_HANDLE_T handle) {
-+ VCHIQ_SERVICE_T *service;
-+
-+ spin_lock(&service_spinlock);
-+ service = handle_to_service(handle);
-+ if (service && (service->srvstate != VCHIQ_SRVSTATE_FREE) &&
-+ (service->handle == handle) &&
-+ (service->instance == instance)) {
-+ BUG_ON(service->ref_count == 0);
-+ service->ref_count++;
-+ } else
-+ service = NULL;
-+ spin_unlock(&service_spinlock);
-+
-+ if (!service)
-+ vchiq_log_info(vchiq_core_log_level,
-+ "Invalid service handle 0x%x", handle);
-+
-+ return service;
-+}
-+
-+VCHIQ_SERVICE_T *
-+find_closed_service_for_instance(VCHIQ_INSTANCE_T instance,
-+ VCHIQ_SERVICE_HANDLE_T handle) {
-+ VCHIQ_SERVICE_T *service;
-+
-+ spin_lock(&service_spinlock);
-+ service = handle_to_service(handle);
-+ if (service &&
-+ ((service->srvstate == VCHIQ_SRVSTATE_FREE) ||
-+ (service->srvstate == VCHIQ_SRVSTATE_CLOSED)) &&
-+ (service->handle == handle) &&
-+ (service->instance == instance)) {
-+ BUG_ON(service->ref_count == 0);
-+ service->ref_count++;
-+ } else
-+ service = NULL;
-+ spin_unlock(&service_spinlock);
-+
-+ if (!service)
-+ vchiq_log_info(vchiq_core_log_level,
-+ "Invalid service handle 0x%x", handle);
-+
-+ return service;
-+}
-+
-+VCHIQ_SERVICE_T *
-+next_service_by_instance(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance,
-+ int *pidx)
-+{
-+ VCHIQ_SERVICE_T *service = NULL;
-+ int idx = *pidx;
-+
-+ spin_lock(&service_spinlock);
-+ while (idx < state->unused_service) {
-+ VCHIQ_SERVICE_T *srv = state->services[idx++];
-+ if (srv && (srv->srvstate != VCHIQ_SRVSTATE_FREE) &&
-+ (srv->instance == instance)) {
-+ service = srv;
-+ BUG_ON(service->ref_count == 0);
-+ service->ref_count++;
-+ break;
-+ }
-+ }
-+ spin_unlock(&service_spinlock);
-+
-+ *pidx = idx;
-+
-+ return service;
-+}
-+
-+void
-+lock_service(VCHIQ_SERVICE_T *service)
-+{
-+ spin_lock(&service_spinlock);
-+ BUG_ON(!service || (service->ref_count == 0));
-+ if (service)
-+ service->ref_count++;
-+ spin_unlock(&service_spinlock);
-+}
-+
-+void
-+unlock_service(VCHIQ_SERVICE_T *service)
-+{
-+ VCHIQ_STATE_T *state = service->state;
-+ spin_lock(&service_spinlock);
-+ BUG_ON(!service || (service->ref_count == 0));
-+ if (service && service->ref_count) {
-+ service->ref_count--;
-+ if (!service->ref_count) {
-+ BUG_ON(service->srvstate != VCHIQ_SRVSTATE_FREE);
-+ state->services[service->localport] = NULL;
-+ } else
-+ service = NULL;
-+ }
-+ spin_unlock(&service_spinlock);
-+
-+ if (service && service->userdata_term)
-+ service->userdata_term(service->base.userdata);
-+
-+ kfree(service);
-+}
-+
-+int
-+vchiq_get_client_id(VCHIQ_SERVICE_HANDLE_T handle)
-+{
-+ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
-+ int id;
-+
-+ id = service ? service->client_id : 0;
-+ if (service)
-+ unlock_service(service);
-+
-+ return id;
-+}
-+
-+void *
-+vchiq_get_service_userdata(VCHIQ_SERVICE_HANDLE_T handle)
-+{
-+ VCHIQ_SERVICE_T *service = handle_to_service(handle);
-+
-+ return service ? service->base.userdata : NULL;
-+}
-+
-+int
-+vchiq_get_service_fourcc(VCHIQ_SERVICE_HANDLE_T handle)
-+{
-+ VCHIQ_SERVICE_T *service = handle_to_service(handle);
-+
-+ return service ? service->base.fourcc : 0;
-+}
-+
-+static void
-+mark_service_closing_internal(VCHIQ_SERVICE_T *service, int sh_thread)
-+{
-+ VCHIQ_STATE_T *state = service->state;
-+ VCHIQ_SERVICE_QUOTA_T *service_quota;
-+
-+ service->closing = 1;
-+
-+ /* Synchronise with other threads. */
-+ mutex_lock(&state->recycle_mutex);
-+ mutex_unlock(&state->recycle_mutex);
-+ if (!sh_thread || (state->conn_state != VCHIQ_CONNSTATE_PAUSE_SENT)) {
-+ /* If we're pausing then the slot_mutex is held until resume
-+ * by the slot handler. Therefore don't try to acquire this
-+ * mutex if we're the slot handler and in the pause sent state.
-+ * We don't need to in this case anyway. */
-+ mutex_lock(&state->slot_mutex);
-+ mutex_unlock(&state->slot_mutex);
-+ }
-+
-+ /* Unblock any sending thread. */
-+ service_quota = &state->service_quotas[service->localport];
-+ up(&service_quota->quota_event);
-+}
-+
-+static void
-+mark_service_closing(VCHIQ_SERVICE_T *service)
-+{
-+ mark_service_closing_internal(service, 0);
-+}
-+
-+static inline VCHIQ_STATUS_T
-+make_service_callback(VCHIQ_SERVICE_T *service, VCHIQ_REASON_T reason,
-+ VCHIQ_HEADER_T *header, void *bulk_userdata)
-+{
-+ VCHIQ_STATUS_T status;
-+ vchiq_log_trace(vchiq_core_log_level, "%d: callback:%d (%s, %x, %x)",
-+ service->state->id, service->localport, reason_names[reason],
-+ (unsigned int)header, (unsigned int)bulk_userdata);
-+ status = service->base.callback(reason, header, service->handle,
-+ bulk_userdata);
-+ if (status == VCHIQ_ERROR) {
-+ vchiq_log_warning(vchiq_core_log_level,
-+ "%d: ignoring ERROR from callback to service %x",
-+ service->state->id, service->handle);
-+ status = VCHIQ_SUCCESS;
-+ }
-+ return status;
-+}
-+
-+inline void
-+vchiq_set_conn_state(VCHIQ_STATE_T *state, VCHIQ_CONNSTATE_T newstate)
-+{
-+ VCHIQ_CONNSTATE_T oldstate = state->conn_state;
-+ vchiq_log_info(vchiq_core_log_level, "%d: %s->%s", state->id,
-+ conn_state_names[oldstate],
-+ conn_state_names[newstate]);
-+ state->conn_state = newstate;
-+ vchiq_platform_conn_state_changed(state, oldstate, newstate);
-+}
-+
-+static inline void
-+remote_event_create(REMOTE_EVENT_T *event)
-+{
-+ event->armed = 0;
-+ /* Don't clear the 'fired' flag because it may already have been set
-+ ** by the other side. */
-+ sema_init(event->event, 0);
-+}
-+
-+static inline void
-+remote_event_destroy(REMOTE_EVENT_T *event)
-+{
-+ (void)event;
-+}
-+
-+static inline int
-+remote_event_wait(REMOTE_EVENT_T *event)
-+{
-+ if (!event->fired) {
-+ event->armed = 1;
-+ dsb();
-+ if (!event->fired) {
-+ if (down_interruptible(event->event) != 0) {
-+ event->armed = 0;
-+ return 0;
-+ }
-+ }
-+ event->armed = 0;
-+ wmb();
-+ }
-+
-+ event->fired = 0;
-+ return 1;
-+}
-+
-+static inline void
-+remote_event_signal_local(REMOTE_EVENT_T *event)
-+{
-+ event->armed = 0;
-+ up(event->event);
-+}
-+
-+static inline void
-+remote_event_poll(REMOTE_EVENT_T *event)
-+{
-+ if (event->fired && event->armed)
-+ remote_event_signal_local(event);
-+}
-+
-+void
-+remote_event_pollall(VCHIQ_STATE_T *state)
-+{
-+ remote_event_poll(&state->local->sync_trigger);
-+ remote_event_poll(&state->local->sync_release);
-+ remote_event_poll(&state->local->trigger);
-+ remote_event_poll(&state->local->recycle);
-+}
-+
-+/* Round up message sizes so that any space at the end of a slot is always big
-+** enough for a header. This relies on header size being a power of two, which
-+** has been verified earlier by a static assertion. */
-+
-+static inline unsigned int
-+calc_stride(unsigned int size)
-+{
-+ /* Allow room for the header */
-+ size += sizeof(VCHIQ_HEADER_T);
-+
-+ /* Round up */
-+ return (size + sizeof(VCHIQ_HEADER_T) - 1) & ~(sizeof(VCHIQ_HEADER_T)
-+ - 1);
-+}
-+
-+/* Called by the slot handler thread */
-+static VCHIQ_SERVICE_T *
-+get_listening_service(VCHIQ_STATE_T *state, int fourcc)
-+{
-+ int i;
-+
-+ WARN_ON(fourcc == VCHIQ_FOURCC_INVALID);
-+
-+ for (i = 0; i < state->unused_service; i++) {
-+ VCHIQ_SERVICE_T *service = state->services[i];
-+ if (service &&
-+ (service->public_fourcc == fourcc) &&
-+ ((service->srvstate == VCHIQ_SRVSTATE_LISTENING) ||
-+ ((service->srvstate == VCHIQ_SRVSTATE_OPEN) &&
-+ (service->remoteport == VCHIQ_PORT_FREE)))) {
-+ lock_service(service);
-+ return service;
-+ }
-+ }
-+
-+ return NULL;
-+}
-+
-+/* Called by the slot handler thread */
-+static VCHIQ_SERVICE_T *
-+get_connected_service(VCHIQ_STATE_T *state, unsigned int port)
-+{
-+ int i;
-+ for (i = 0; i < state->unused_service; i++) {
-+ VCHIQ_SERVICE_T *service = state->services[i];
-+ if (service && (service->srvstate == VCHIQ_SRVSTATE_OPEN)
-+ && (service->remoteport == port)) {
-+ lock_service(service);
-+ return service;
-+ }
-+ }
-+ return NULL;
-+}
-+
-+inline void
-+request_poll(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, int poll_type)
-+{
-+ uint32_t value;
-+
-+ if (service) {
-+ do {
-+ value = atomic_read(&service->poll_flags);
-+ } while (atomic_cmpxchg(&service->poll_flags, value,
-+ value | (1 << poll_type)) != value);
-+
-+ do {
-+ value = atomic_read(&state->poll_services[
-+ service->localport>>5]);
-+ } while (atomic_cmpxchg(
-+ &state->poll_services[service->localport>>5],
-+ value, value | (1 << (service->localport & 0x1f)))
-+ != value);
-+ }
-+
-+ state->poll_needed = 1;
-+ wmb();
-+
-+ /* ... and ensure the slot handler runs. */
-+ remote_event_signal_local(&state->local->trigger);
-+}
-+
-+/* Called from queue_message, by the slot handler and application threads,
-+** with slot_mutex held */
-+static VCHIQ_HEADER_T *
-+reserve_space(VCHIQ_STATE_T *state, int space, int is_blocking)
-+{
-+ VCHIQ_SHARED_STATE_T *local = state->local;
-+ int tx_pos = state->local_tx_pos;
-+ int slot_space = VCHIQ_SLOT_SIZE - (tx_pos & VCHIQ_SLOT_MASK);
-+
-+ if (space > slot_space) {
-+ VCHIQ_HEADER_T *header;
-+ /* Fill the remaining space with padding */
-+ WARN_ON(state->tx_data == NULL);
-+ header = (VCHIQ_HEADER_T *)
-+ (state->tx_data + (tx_pos & VCHIQ_SLOT_MASK));
-+ header->msgid = VCHIQ_MSGID_PADDING;
-+ header->size = slot_space - sizeof(VCHIQ_HEADER_T);
-+
-+ tx_pos += slot_space;
-+ }
-+
-+ /* If necessary, get the next slot. */
-+ if ((tx_pos & VCHIQ_SLOT_MASK) == 0) {
-+ int slot_index;
-+
-+ /* If there is no free slot... */
-+
-+ if (down_trylock(&state->slot_available_event) != 0) {
-+ /* ...wait for one. */
-+
-+ VCHIQ_STATS_INC(state, slot_stalls);
-+
-+ /* But first, flush through the last slot. */
-+ state->local_tx_pos = tx_pos;
-+ local->tx_pos = tx_pos;
-+ remote_event_signal(&state->remote->trigger);
-+
-+ if (!is_blocking ||
-+ (down_interruptible(
-+ &state->slot_available_event) != 0))
-+ return NULL; /* No space available */
-+ }
-+
-+ BUG_ON(tx_pos ==
-+ (state->slot_queue_available * VCHIQ_SLOT_SIZE));
-+
-+ slot_index = local->slot_queue[
-+ SLOT_QUEUE_INDEX_FROM_POS(tx_pos) &
-+ VCHIQ_SLOT_QUEUE_MASK];
-+ state->tx_data =
-+ (char *)SLOT_DATA_FROM_INDEX(state, slot_index);
-+ }
-+
-+ state->local_tx_pos = tx_pos + space;
-+
-+ return (VCHIQ_HEADER_T *)(state->tx_data + (tx_pos & VCHIQ_SLOT_MASK));
-+}
-+
-+/* Called by the recycle thread. */
-+static void
-+process_free_queue(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_SHARED_STATE_T *local = state->local;
-+ BITSET_T service_found[BITSET_SIZE(VCHIQ_MAX_SERVICES)];
-+ int slot_queue_available;
-+
-+ /* Use a read memory barrier to ensure that any state that may have
-+ ** been modified by another thread is not masked by stale prefetched
-+ ** values. */
-+ rmb();
-+
-+ /* Find slots which have been freed by the other side, and return them
-+ ** to the available queue. */
-+ slot_queue_available = state->slot_queue_available;
-+
-+ while (slot_queue_available != local->slot_queue_recycle) {
-+ unsigned int pos;
-+ int slot_index = local->slot_queue[slot_queue_available++ &
-+ VCHIQ_SLOT_QUEUE_MASK];
-+ char *data = (char *)SLOT_DATA_FROM_INDEX(state, slot_index);
-+ int data_found = 0;
-+
-+ vchiq_log_trace(vchiq_core_log_level, "%d: pfq %d=%x %x %x",
-+ state->id, slot_index, (unsigned int)data,
-+ local->slot_queue_recycle, slot_queue_available);
-+
-+ /* Initialise the bitmask for services which have used this
-+ ** slot */
-+ BITSET_ZERO(service_found);
-+
-+ pos = 0;
-+
-+ while (pos < VCHIQ_SLOT_SIZE) {
-+ VCHIQ_HEADER_T *header =
-+ (VCHIQ_HEADER_T *)(data + pos);
-+ int msgid = header->msgid;
-+ if (VCHIQ_MSG_TYPE(msgid) == VCHIQ_MSG_DATA) {
-+ int port = VCHIQ_MSG_SRCPORT(msgid);
-+ VCHIQ_SERVICE_QUOTA_T *service_quota =
-+ &state->service_quotas[port];
-+ int count;
-+ spin_lock(&quota_spinlock);
-+ count = service_quota->message_use_count;
-+ if (count > 0)
-+ service_quota->message_use_count =
-+ count - 1;
-+ spin_unlock(&quota_spinlock);
-+
-+ if (count == service_quota->message_quota)
-+ /* Signal the service that it
-+ ** has dropped below its quota
-+ */
-+ up(&service_quota->quota_event);
-+ else if (count == 0) {
-+ vchiq_log_error(vchiq_core_log_level,
-+ "service %d "
-+ "message_use_count=%d "
-+ "(header %x, msgid %x, "
-+ "header->msgid %x, "
-+ "header->size %x)",
-+ port,
-+ service_quota->
-+ message_use_count,
-+ (unsigned int)header, msgid,
-+ header->msgid,
-+ header->size);
-+ WARN(1, "invalid message use count\n");
-+ }
-+ if (!BITSET_IS_SET(service_found, port)) {
-+ /* Set the found bit for this service */
-+ BITSET_SET(service_found, port);
-+
-+ spin_lock(&quota_spinlock);
-+ count = service_quota->slot_use_count;
-+ if (count > 0)
-+ service_quota->slot_use_count =
-+ count - 1;
-+ spin_unlock(&quota_spinlock);
-+
-+ if (count > 0) {
-+ /* Signal the service in case
-+ ** it has dropped below its
-+ ** quota */
-+ up(&service_quota->quota_event);
-+ vchiq_log_trace(
-+ vchiq_core_log_level,
-+ "%d: pfq:%d %x@%x - "
-+ "slot_use->%d",
-+ state->id, port,
-+ header->size,
-+ (unsigned int)header,
-+ count - 1);
-+ } else {
-+ vchiq_log_error(
-+ vchiq_core_log_level,
-+ "service %d "
-+ "slot_use_count"
-+ "=%d (header %x"
-+ ", msgid %x, "
-+ "header->msgid"
-+ " %x, header->"
-+ "size %x)",
-+ port, count,
-+ (unsigned int)header,
-+ msgid,
-+ header->msgid,
-+ header->size);
-+ WARN(1, "bad slot use count\n");
-+ }
-+ }
-+
-+ data_found = 1;
-+ }
-+
-+ pos += calc_stride(header->size);
-+ if (pos > VCHIQ_SLOT_SIZE) {
-+ vchiq_log_error(vchiq_core_log_level,
-+ "pfq - pos %x: header %x, msgid %x, "
-+ "header->msgid %x, header->size %x",
-+ pos, (unsigned int)header, msgid,
-+ header->msgid, header->size);
-+ WARN(1, "invalid slot position\n");
-+ }
-+ }
-+
-+ if (data_found) {
-+ int count;
-+ spin_lock(&quota_spinlock);
-+ count = state->data_use_count;
-+ if (count > 0)
-+ state->data_use_count =
-+ count - 1;
-+ spin_unlock(&quota_spinlock);
-+ if (count == state->data_quota)
-+ up(&state->data_quota_event);
-+ }
-+
-+ state->slot_queue_available = slot_queue_available;
-+ up(&state->slot_available_event);
-+ }
-+}
-+
-+/* Called by the slot handler and application threads */
-+static VCHIQ_STATUS_T
-+queue_message(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service,
-+ int msgid, const VCHIQ_ELEMENT_T *elements,
-+ int count, int size, int flags)
-+{
-+ VCHIQ_SHARED_STATE_T *local;
-+ VCHIQ_SERVICE_QUOTA_T *service_quota = NULL;
-+ VCHIQ_HEADER_T *header;
-+ int type = VCHIQ_MSG_TYPE(msgid);
-+
-+ unsigned int stride;
-+
-+ local = state->local;
-+
-+ stride = calc_stride(size);
-+
-+ WARN_ON(!(stride <= VCHIQ_SLOT_SIZE));
-+
-+ if (!(flags & QMFLAGS_NO_MUTEX_LOCK) &&
-+ (mutex_lock_interruptible(&state->slot_mutex) != 0))
-+ return VCHIQ_RETRY;
-+
-+ if (type == VCHIQ_MSG_DATA) {
-+ int tx_end_index;
-+
-+ BUG_ON(!service);
-+ BUG_ON((flags & (QMFLAGS_NO_MUTEX_LOCK |
-+ QMFLAGS_NO_MUTEX_UNLOCK)) != 0);
-+
-+ if (service->closing) {
-+ /* The service has been closed */
-+ mutex_unlock(&state->slot_mutex);
-+ return VCHIQ_ERROR;
-+ }
-+
-+ service_quota = &state->service_quotas[service->localport];
-+
-+ spin_lock(&quota_spinlock);
-+
-+ /* Ensure this service doesn't use more than its quota of
-+ ** messages or slots */
-+ tx_end_index = SLOT_QUEUE_INDEX_FROM_POS(
-+ state->local_tx_pos + stride - 1);
-+
-+ /* Ensure data messages don't use more than their quota of
-+ ** slots */
-+ while ((tx_end_index != state->previous_data_index) &&
-+ (state->data_use_count == state->data_quota)) {
-+ VCHIQ_STATS_INC(state, data_stalls);
-+ spin_unlock(&quota_spinlock);
-+ mutex_unlock(&state->slot_mutex);
-+
-+ if (down_interruptible(&state->data_quota_event)
-+ != 0)
-+ return VCHIQ_RETRY;
-+
-+ mutex_lock(&state->slot_mutex);
-+ spin_lock(&quota_spinlock);
-+ tx_end_index = SLOT_QUEUE_INDEX_FROM_POS(
-+ state->local_tx_pos + stride - 1);
-+ if ((tx_end_index == state->previous_data_index) ||
-+ (state->data_use_count < state->data_quota)) {
-+ /* Pass the signal on to other waiters */
-+ up(&state->data_quota_event);
-+ break;
-+ }
-+ }
-+
-+ while ((service_quota->message_use_count ==
-+ service_quota->message_quota) ||
-+ ((tx_end_index != service_quota->previous_tx_index) &&
-+ (service_quota->slot_use_count ==
-+ service_quota->slot_quota))) {
-+ spin_unlock(&quota_spinlock);
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%d: qm:%d %s,%x - quota stall "
-+ "(msg %d, slot %d)",
-+ state->id, service->localport,
-+ msg_type_str(type), size,
-+ service_quota->message_use_count,
-+ service_quota->slot_use_count);
-+ VCHIQ_SERVICE_STATS_INC(service, quota_stalls);
-+ mutex_unlock(&state->slot_mutex);
-+ if (down_interruptible(&service_quota->quota_event)
-+ != 0)
-+ return VCHIQ_RETRY;
-+ if (service->closing)
-+ return VCHIQ_ERROR;
-+ if (mutex_lock_interruptible(&state->slot_mutex) != 0)
-+ return VCHIQ_RETRY;
-+ if (service->srvstate != VCHIQ_SRVSTATE_OPEN) {
-+ /* The service has been closed */
-+ mutex_unlock(&state->slot_mutex);
-+ return VCHIQ_ERROR;
-+ }
-+ spin_lock(&quota_spinlock);
-+ tx_end_index = SLOT_QUEUE_INDEX_FROM_POS(
-+ state->local_tx_pos + stride - 1);
-+ }
-+
-+ spin_unlock(&quota_spinlock);
-+ }
-+
-+ header = reserve_space(state, stride, flags & QMFLAGS_IS_BLOCKING);
-+
-+ if (!header) {
-+ if (service)
-+ VCHIQ_SERVICE_STATS_INC(service, slot_stalls);
-+ /* In the event of a failure, return the mutex to the
-+ state it was in */
-+ if (!(flags & QMFLAGS_NO_MUTEX_LOCK))
-+ mutex_unlock(&state->slot_mutex);
-+ return VCHIQ_RETRY;
-+ }
-+
-+ if (type == VCHIQ_MSG_DATA) {
-+ int i, pos;
-+ int tx_end_index;
-+ int slot_use_count;
-+
-+ vchiq_log_info(vchiq_core_log_level,
-+ "%d: qm %s@%x,%x (%d->%d)",
-+ state->id,
-+ msg_type_str(VCHIQ_MSG_TYPE(msgid)),
-+ (unsigned int)header, size,
-+ VCHIQ_MSG_SRCPORT(msgid),
-+ VCHIQ_MSG_DSTPORT(msgid));
-+
-+ BUG_ON(!service);
-+ BUG_ON((flags & (QMFLAGS_NO_MUTEX_LOCK |
-+ QMFLAGS_NO_MUTEX_UNLOCK)) != 0);
-+
-+ for (i = 0, pos = 0; i < (unsigned int)count;
-+ pos += elements[i++].size)
-+ if (elements[i].size) {
-+ if (vchiq_copy_from_user
-+ (header->data + pos, elements[i].data,
-+ (size_t) elements[i].size) !=
-+ VCHIQ_SUCCESS) {
-+ mutex_unlock(&state->slot_mutex);
-+ VCHIQ_SERVICE_STATS_INC(service,
-+ error_count);
-+ return VCHIQ_ERROR;
-+ }
-+ if (i == 0) {
-+ if (SRVTRACE_ENABLED(service,
-+ VCHIQ_LOG_INFO))
-+ vchiq_log_dump_mem("Sent", 0,
-+ header->data + pos,
-+ min(64u,
-+ elements[0].size));
-+ }
-+ }
-+
-+ spin_lock(&quota_spinlock);
-+ service_quota->message_use_count++;
-+
-+ tx_end_index =
-+ SLOT_QUEUE_INDEX_FROM_POS(state->local_tx_pos - 1);
-+
-+ /* If this transmission can't fit in the last slot used by any
-+ ** service, the data_use_count must be increased. */
-+ if (tx_end_index != state->previous_data_index) {
-+ state->previous_data_index = tx_end_index;
-+ state->data_use_count++;
-+ }
-+
-+ /* If this isn't the same slot last used by this service,
-+ ** the service's slot_use_count must be increased. */
-+ if (tx_end_index != service_quota->previous_tx_index) {
-+ service_quota->previous_tx_index = tx_end_index;
-+ slot_use_count = ++service_quota->slot_use_count;
-+ } else {
-+ slot_use_count = 0;
-+ }
-+
-+ spin_unlock(&quota_spinlock);
-+
-+ if (slot_use_count)
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%d: qm:%d %s,%x - slot_use->%d (hdr %p)",
-+ state->id, service->localport,
-+ msg_type_str(VCHIQ_MSG_TYPE(msgid)), size,
-+ slot_use_count, header);
-+
-+ VCHIQ_SERVICE_STATS_INC(service, ctrl_tx_count);
-+ VCHIQ_SERVICE_STATS_ADD(service, ctrl_tx_bytes, size);
-+ } else {
-+ vchiq_log_info(vchiq_core_log_level,
-+ "%d: qm %s@%x,%x (%d->%d)", state->id,
-+ msg_type_str(VCHIQ_MSG_TYPE(msgid)),
-+ (unsigned int)header, size,
-+ VCHIQ_MSG_SRCPORT(msgid),
-+ VCHIQ_MSG_DSTPORT(msgid));
-+ if (size != 0) {
-+ WARN_ON(!((count == 1) && (size == elements[0].size)));
-+ memcpy(header->data, elements[0].data,
-+ elements[0].size);
-+ }
-+ VCHIQ_STATS_INC(state, ctrl_tx_count);
-+ }
-+
-+ header->msgid = msgid;
-+ header->size = size;
-+
-+ {
-+ int svc_fourcc;
-+
-+ svc_fourcc = service
-+ ? service->base.fourcc
-+ : VCHIQ_MAKE_FOURCC('?', '?', '?', '?');
-+
-+ vchiq_log_info(SRVTRACE_LEVEL(service),
-+ "Sent Msg %s(%u) to %c%c%c%c s:%u d:%d len:%d",
-+ msg_type_str(VCHIQ_MSG_TYPE(msgid)),
-+ VCHIQ_MSG_TYPE(msgid),
-+ VCHIQ_FOURCC_AS_4CHARS(svc_fourcc),
-+ VCHIQ_MSG_SRCPORT(msgid),
-+ VCHIQ_MSG_DSTPORT(msgid),
-+ size);
-+ }
-+
-+ /* Make sure the new header is visible to the peer. */
-+ wmb();
-+
-+ /* Make the new tx_pos visible to the peer. */
-+ local->tx_pos = state->local_tx_pos;
-+ wmb();
-+
-+ if (service && (type == VCHIQ_MSG_CLOSE))
-+ vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSESENT);
-+
-+ if (!(flags & QMFLAGS_NO_MUTEX_UNLOCK))
-+ mutex_unlock(&state->slot_mutex);
-+
-+ remote_event_signal(&state->remote->trigger);
-+
-+ return VCHIQ_SUCCESS;
-+}
-+
-+/* Called by the slot handler and application threads */
-+static VCHIQ_STATUS_T
-+queue_message_sync(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service,
-+ int msgid, const VCHIQ_ELEMENT_T *elements,
-+ int count, int size, int is_blocking)
-+{
-+ VCHIQ_SHARED_STATE_T *local;
-+ VCHIQ_HEADER_T *header;
-+
-+ local = state->local;
-+
-+ if ((VCHIQ_MSG_TYPE(msgid) != VCHIQ_MSG_RESUME) &&
-+ (mutex_lock_interruptible(&state->sync_mutex) != 0))
-+ return VCHIQ_RETRY;
-+
-+ remote_event_wait(&local->sync_release);
-+
-+ rmb();
-+
-+ header = (VCHIQ_HEADER_T *)SLOT_DATA_FROM_INDEX(state,
-+ local->slot_sync);
-+
-+ {
-+ int oldmsgid = header->msgid;
-+ if (oldmsgid != VCHIQ_MSGID_PADDING)
-+ vchiq_log_error(vchiq_core_log_level,
-+ "%d: qms - msgid %x, not PADDING",
-+ state->id, oldmsgid);
-+ }
-+
-+ if (service) {
-+ int i, pos;
-+
-+ vchiq_log_info(vchiq_sync_log_level,
-+ "%d: qms %s@%x,%x (%d->%d)", state->id,
-+ msg_type_str(VCHIQ_MSG_TYPE(msgid)),
-+ (unsigned int)header, size,
-+ VCHIQ_MSG_SRCPORT(msgid),
-+ VCHIQ_MSG_DSTPORT(msgid));
-+
-+ for (i = 0, pos = 0; i < (unsigned int)count;
-+ pos += elements[i++].size)
-+ if (elements[i].size) {
-+ if (vchiq_copy_from_user
-+ (header->data + pos, elements[i].data,
-+ (size_t) elements[i].size) !=
-+ VCHIQ_SUCCESS) {
-+ mutex_unlock(&state->sync_mutex);
-+ VCHIQ_SERVICE_STATS_INC(service,
-+ error_count);
-+ return VCHIQ_ERROR;
-+ }
-+ if (i == 0) {
-+ if (vchiq_sync_log_level >=
-+ VCHIQ_LOG_TRACE)
-+ vchiq_log_dump_mem("Sent Sync",
-+ 0, header->data + pos,
-+ min(64u,
-+ elements[0].size));
-+ }
-+ }
-+
-+ VCHIQ_SERVICE_STATS_INC(service, ctrl_tx_count);
-+ VCHIQ_SERVICE_STATS_ADD(service, ctrl_tx_bytes, size);
-+ } else {
-+ vchiq_log_info(vchiq_sync_log_level,
-+ "%d: qms %s@%x,%x (%d->%d)", state->id,
-+ msg_type_str(VCHIQ_MSG_TYPE(msgid)),
-+ (unsigned int)header, size,
-+ VCHIQ_MSG_SRCPORT(msgid),
-+ VCHIQ_MSG_DSTPORT(msgid));
-+ if (size != 0) {
-+ WARN_ON(!((count == 1) && (size == elements[0].size)));
-+ memcpy(header->data, elements[0].data,
-+ elements[0].size);
-+ }
-+ VCHIQ_STATS_INC(state, ctrl_tx_count);
-+ }
-+
-+ header->size = size;
-+ header->msgid = msgid;
-+
-+ if (vchiq_sync_log_level >= VCHIQ_LOG_TRACE) {
-+ int svc_fourcc;
-+
-+ svc_fourcc = service
-+ ? service->base.fourcc
-+ : VCHIQ_MAKE_FOURCC('?', '?', '?', '?');
-+
-+ vchiq_log_trace(vchiq_sync_log_level,
-+ "Sent Sync Msg %s(%u) to %c%c%c%c s:%u d:%d len:%d",
-+ msg_type_str(VCHIQ_MSG_TYPE(msgid)),
-+ VCHIQ_MSG_TYPE(msgid),
-+ VCHIQ_FOURCC_AS_4CHARS(svc_fourcc),
-+ VCHIQ_MSG_SRCPORT(msgid),
-+ VCHIQ_MSG_DSTPORT(msgid),
-+ size);
-+ }
-+
-+ /* Make sure the new header is visible to the peer. */
-+ wmb();
-+
-+ remote_event_signal(&state->remote->sync_trigger);
-+
-+ if (VCHIQ_MSG_TYPE(msgid) != VCHIQ_MSG_PAUSE)
-+ mutex_unlock(&state->sync_mutex);
-+
-+ return VCHIQ_SUCCESS;
-+}
-+
-+static inline void
-+claim_slot(VCHIQ_SLOT_INFO_T *slot)
-+{
-+ slot->use_count++;
-+}
-+
-+static void
-+release_slot(VCHIQ_STATE_T *state, VCHIQ_SLOT_INFO_T *slot_info,
-+ VCHIQ_HEADER_T *header, VCHIQ_SERVICE_T *service)
-+{
-+ int release_count;
-+
-+ mutex_lock(&state->recycle_mutex);
-+
-+ if (header) {
-+ int msgid = header->msgid;
-+ if (((msgid & VCHIQ_MSGID_CLAIMED) == 0) ||
-+ (service && service->closing)) {
-+ mutex_unlock(&state->recycle_mutex);
-+ return;
-+ }
-+
-+ /* Rewrite the message header to prevent a double
-+ ** release */
-+ header->msgid = msgid & ~VCHIQ_MSGID_CLAIMED;
-+ }
-+
-+ release_count = slot_info->release_count;
-+ slot_info->release_count = ++release_count;
-+
-+ if (release_count == slot_info->use_count) {
-+ int slot_queue_recycle;
-+ /* Add to the freed queue */
-+
-+ /* A read barrier is necessary here to prevent speculative
-+ ** fetches of remote->slot_queue_recycle from overtaking the
-+ ** mutex. */
-+ rmb();
-+
-+ slot_queue_recycle = state->remote->slot_queue_recycle;
-+ state->remote->slot_queue[slot_queue_recycle &
-+ VCHIQ_SLOT_QUEUE_MASK] =
-+ SLOT_INDEX_FROM_INFO(state, slot_info);
-+ state->remote->slot_queue_recycle = slot_queue_recycle + 1;
-+ vchiq_log_info(vchiq_core_log_level,
-+ "%d: release_slot %d - recycle->%x",
-+ state->id, SLOT_INDEX_FROM_INFO(state, slot_info),
-+ state->remote->slot_queue_recycle);
-+
-+ /* A write barrier is necessary, but remote_event_signal
-+ ** contains one. */
-+ remote_event_signal(&state->remote->recycle);
-+ }
-+
-+ mutex_unlock(&state->recycle_mutex);
-+}
-+
-+/* Called by the slot handler - don't hold the bulk mutex */
-+static VCHIQ_STATUS_T
-+notify_bulks(VCHIQ_SERVICE_T *service, VCHIQ_BULK_QUEUE_T *queue,
-+ int retry_poll)
-+{
-+ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
-+
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%d: nb:%d %cx - p=%x rn=%x r=%x",
-+ service->state->id, service->localport,
-+ (queue == &service->bulk_tx) ? 't' : 'r',
-+ queue->process, queue->remote_notify, queue->remove);
-+
-+ if (service->state->is_master) {
-+ while (queue->remote_notify != queue->process) {
-+ VCHIQ_BULK_T *bulk =
-+ &queue->bulks[BULK_INDEX(queue->remote_notify)];
-+ int msgtype = (bulk->dir == VCHIQ_BULK_TRANSMIT) ?
-+ VCHIQ_MSG_BULK_RX_DONE : VCHIQ_MSG_BULK_TX_DONE;
-+ int msgid = VCHIQ_MAKE_MSG(msgtype, service->localport,
-+ service->remoteport);
-+ VCHIQ_ELEMENT_T element = { &bulk->actual, 4 };
-+ /* Only reply to non-dummy bulk requests */
-+ if (bulk->remote_data) {
-+ status = queue_message(service->state, NULL,
-+ msgid, &element, 1, 4, 0);
-+ if (status != VCHIQ_SUCCESS)
-+ break;
-+ }
-+ queue->remote_notify++;
-+ }
-+ } else {
-+ queue->remote_notify = queue->process;
-+ }
-+
-+ if (status == VCHIQ_SUCCESS) {
-+ while (queue->remove != queue->remote_notify) {
-+ VCHIQ_BULK_T *bulk =
-+ &queue->bulks[BULK_INDEX(queue->remove)];
-+
-+ /* Only generate callbacks for non-dummy bulk
-+ ** requests, and non-terminated services */
-+ if (bulk->data && service->instance) {
-+ if (bulk->actual != VCHIQ_BULK_ACTUAL_ABORTED) {
-+ if (bulk->dir == VCHIQ_BULK_TRANSMIT) {
-+ VCHIQ_SERVICE_STATS_INC(service,
-+ bulk_tx_count);
-+ VCHIQ_SERVICE_STATS_ADD(service,
-+ bulk_tx_bytes,
-+ bulk->actual);
-+ } else {
-+ VCHIQ_SERVICE_STATS_INC(service,
-+ bulk_rx_count);
-+ VCHIQ_SERVICE_STATS_ADD(service,
-+ bulk_rx_bytes,
-+ bulk->actual);
-+ }
-+ } else {
-+ VCHIQ_SERVICE_STATS_INC(service,
-+ bulk_aborted_count);
-+ }
-+ if (bulk->mode == VCHIQ_BULK_MODE_BLOCKING) {
-+ struct bulk_waiter *waiter;
-+ spin_lock(&bulk_waiter_spinlock);
-+ waiter = bulk->userdata;
-+ if (waiter) {
-+ waiter->actual = bulk->actual;
-+ up(&waiter->event);
-+ }
-+ spin_unlock(&bulk_waiter_spinlock);
-+ } else if (bulk->mode ==
-+ VCHIQ_BULK_MODE_CALLBACK) {
-+ VCHIQ_REASON_T reason = (bulk->dir ==
-+ VCHIQ_BULK_TRANSMIT) ?
-+ ((bulk->actual ==
-+ VCHIQ_BULK_ACTUAL_ABORTED) ?
-+ VCHIQ_BULK_TRANSMIT_ABORTED :
-+ VCHIQ_BULK_TRANSMIT_DONE) :
-+ ((bulk->actual ==
-+ VCHIQ_BULK_ACTUAL_ABORTED) ?
-+ VCHIQ_BULK_RECEIVE_ABORTED :
-+ VCHIQ_BULK_RECEIVE_DONE);
-+ status = make_service_callback(service,
-+ reason, NULL, bulk->userdata);
-+ if (status == VCHIQ_RETRY)
-+ break;
-+ }
-+ }
-+
-+ queue->remove++;
-+ up(&service->bulk_remove_event);
-+ }
-+ if (!retry_poll)
-+ status = VCHIQ_SUCCESS;
-+ }
-+
-+ if (status == VCHIQ_RETRY)
-+ request_poll(service->state, service,
-+ (queue == &service->bulk_tx) ?
-+ VCHIQ_POLL_TXNOTIFY : VCHIQ_POLL_RXNOTIFY);
-+
-+ return status;
-+}
-+
-+/* Called by the slot handler thread */
-+static void
-+poll_services(VCHIQ_STATE_T *state)
-+{
-+ int group, i;
-+
-+ for (group = 0; group < BITSET_SIZE(state->unused_service); group++) {
-+ uint32_t flags;
-+ flags = atomic_xchg(&state->poll_services[group], 0);
-+ for (i = 0; flags; i++) {
-+ if (flags & (1 << i)) {
-+ VCHIQ_SERVICE_T *service =
-+ find_service_by_port(state,
-+ (group<<5) + i);
-+ uint32_t service_flags;
-+ flags &= ~(1 << i);
-+ if (!service)
-+ continue;
-+ service_flags =
-+ atomic_xchg(&service->poll_flags, 0);
-+ if (service_flags &
-+ (1 << VCHIQ_POLL_REMOVE)) {
-+ vchiq_log_info(vchiq_core_log_level,
-+ "%d: ps - remove %d<->%d",
-+ state->id, service->localport,
-+ service->remoteport);
-+
-+ /* Make it look like a client, because
-+ it must be removed and not left in
-+ the LISTENING state. */
-+ service->public_fourcc =
-+ VCHIQ_FOURCC_INVALID;
-+
-+ if (vchiq_close_service_internal(
-+ service, 0/*!close_recvd*/) !=
-+ VCHIQ_SUCCESS)
-+ request_poll(state, service,
-+ VCHIQ_POLL_REMOVE);
-+ } else if (service_flags &
-+ (1 << VCHIQ_POLL_TERMINATE)) {
-+ vchiq_log_info(vchiq_core_log_level,
-+ "%d: ps - terminate %d<->%d",
-+ state->id, service->localport,
-+ service->remoteport);
-+ if (vchiq_close_service_internal(
-+ service, 0/*!close_recvd*/) !=
-+ VCHIQ_SUCCESS)
-+ request_poll(state, service,
-+ VCHIQ_POLL_TERMINATE);
-+ }
-+ if (service_flags & (1 << VCHIQ_POLL_TXNOTIFY))
-+ notify_bulks(service,
-+ &service->bulk_tx,
-+ 1/*retry_poll*/);
-+ if (service_flags & (1 << VCHIQ_POLL_RXNOTIFY))
-+ notify_bulks(service,
-+ &service->bulk_rx,
-+ 1/*retry_poll*/);
-+ unlock_service(service);
-+ }
-+ }
-+ }
-+}
-+
-+/* Called by the slot handler or application threads, holding the bulk mutex. */
-+static int
-+resolve_bulks(VCHIQ_SERVICE_T *service, VCHIQ_BULK_QUEUE_T *queue)
-+{
-+ VCHIQ_STATE_T *state = service->state;
-+ int resolved = 0;
-+ int rc;
-+
-+ while ((queue->process != queue->local_insert) &&
-+ (queue->process != queue->remote_insert)) {
-+ VCHIQ_BULK_T *bulk = &queue->bulks[BULK_INDEX(queue->process)];
-+
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%d: rb:%d %cx - li=%x ri=%x p=%x",
-+ state->id, service->localport,
-+ (queue == &service->bulk_tx) ? 't' : 'r',
-+ queue->local_insert, queue->remote_insert,
-+ queue->process);
-+
-+ WARN_ON(!((int)(queue->local_insert - queue->process) > 0));
-+ WARN_ON(!((int)(queue->remote_insert - queue->process) > 0));
-+
-+ rc = mutex_lock_interruptible(&state->bulk_transfer_mutex);
-+ if (rc != 0)
-+ break;
-+
-+ vchiq_transfer_bulk(bulk);
-+ mutex_unlock(&state->bulk_transfer_mutex);
-+
-+ if (SRVTRACE_ENABLED(service, VCHIQ_LOG_INFO)) {
-+ const char *header = (queue == &service->bulk_tx) ?
-+ "Send Bulk to" : "Recv Bulk from";
-+ if (bulk->actual != VCHIQ_BULK_ACTUAL_ABORTED)
-+ vchiq_log_info(SRVTRACE_LEVEL(service),
-+ "%s %c%c%c%c d:%d len:%d %x<->%x",
-+ header,
-+ VCHIQ_FOURCC_AS_4CHARS(
-+ service->base.fourcc),
-+ service->remoteport,
-+ bulk->size,
-+ (unsigned int)bulk->data,
-+ (unsigned int)bulk->remote_data);
-+ else
-+ vchiq_log_info(SRVTRACE_LEVEL(service),
-+ "%s %c%c%c%c d:%d ABORTED - tx len:%d,"
-+ " rx len:%d %x<->%x",
-+ header,
-+ VCHIQ_FOURCC_AS_4CHARS(
-+ service->base.fourcc),
-+ service->remoteport,
-+ bulk->size,
-+ bulk->remote_size,
-+ (unsigned int)bulk->data,
-+ (unsigned int)bulk->remote_data);
-+ }
-+
-+ vchiq_complete_bulk(bulk);
-+ queue->process++;
-+ resolved++;
-+ }
-+ return resolved;
-+}
-+
-+/* Called with the bulk_mutex held */
-+static void
-+abort_outstanding_bulks(VCHIQ_SERVICE_T *service, VCHIQ_BULK_QUEUE_T *queue)
-+{
-+ int is_tx = (queue == &service->bulk_tx);
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%d: aob:%d %cx - li=%x ri=%x p=%x",
-+ service->state->id, service->localport, is_tx ? 't' : 'r',
-+ queue->local_insert, queue->remote_insert, queue->process);
-+
-+ WARN_ON(!((int)(queue->local_insert - queue->process) >= 0));
-+ WARN_ON(!((int)(queue->remote_insert - queue->process) >= 0));
-+
-+ while ((queue->process != queue->local_insert) ||
-+ (queue->process != queue->remote_insert)) {
-+ VCHIQ_BULK_T *bulk = &queue->bulks[BULK_INDEX(queue->process)];
-+
-+ if (queue->process == queue->remote_insert) {
-+ /* fabricate a matching dummy bulk */
-+ bulk->remote_data = NULL;
-+ bulk->remote_size = 0;
-+ queue->remote_insert++;
-+ }
-+
-+ if (queue->process != queue->local_insert) {
-+ vchiq_complete_bulk(bulk);
-+
-+ vchiq_log_info(SRVTRACE_LEVEL(service),
-+ "%s %c%c%c%c d:%d ABORTED - tx len:%d, "
-+ "rx len:%d",
-+ is_tx ? "Send Bulk to" : "Recv Bulk from",
-+ VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc),
-+ service->remoteport,
-+ bulk->size,
-+ bulk->remote_size);
-+ } else {
-+ /* fabricate a matching dummy bulk */
-+ bulk->data = NULL;
-+ bulk->size = 0;
-+ bulk->actual = VCHIQ_BULK_ACTUAL_ABORTED;
-+ bulk->dir = is_tx ? VCHIQ_BULK_TRANSMIT :
-+ VCHIQ_BULK_RECEIVE;
-+ queue->local_insert++;
-+ }
-+
-+ queue->process++;
-+ }
-+}
-+
-+/* Called from the slot handler thread */
-+static void
-+pause_bulks(VCHIQ_STATE_T *state)
-+{
-+ if (unlikely(atomic_inc_return(&pause_bulks_count) != 1)) {
-+ WARN_ON_ONCE(1);
-+ atomic_set(&pause_bulks_count, 1);
-+ return;
-+ }
-+
-+ /* Block bulk transfers from all services */
-+ mutex_lock(&state->bulk_transfer_mutex);
-+}
-+
-+/* Called from the slot handler thread */
-+static void
-+resume_bulks(VCHIQ_STATE_T *state)
-+{
-+ int i;
-+ if (unlikely(atomic_dec_return(&pause_bulks_count) != 0)) {
-+ WARN_ON_ONCE(1);
-+ atomic_set(&pause_bulks_count, 0);
-+ return;
-+ }
-+
-+ /* Allow bulk transfers from all services */
-+ mutex_unlock(&state->bulk_transfer_mutex);
-+
-+ if (state->deferred_bulks == 0)
-+ return;
-+
-+ /* Deal with any bulks which had to be deferred due to being in
-+ * paused state. Don't try to match up to number of deferred bulks
-+ * in case we've had something come and close the service in the
-+ * interim - just process all bulk queues for all services */
-+ vchiq_log_info(vchiq_core_log_level, "%s: processing %d deferred bulks",
-+ __func__, state->deferred_bulks);
-+
-+ for (i = 0; i < state->unused_service; i++) {
-+ VCHIQ_SERVICE_T *service = state->services[i];
-+ int resolved_rx = 0;
-+ int resolved_tx = 0;
-+ if (!service || (service->srvstate != VCHIQ_SRVSTATE_OPEN))
-+ continue;
-+
-+ mutex_lock(&service->bulk_mutex);
-+ resolved_rx = resolve_bulks(service, &service->bulk_rx);
-+ resolved_tx = resolve_bulks(service, &service->bulk_tx);
-+ mutex_unlock(&service->bulk_mutex);
-+ if (resolved_rx)
-+ notify_bulks(service, &service->bulk_rx, 1);
-+ if (resolved_tx)
-+ notify_bulks(service, &service->bulk_tx, 1);
-+ }
-+ state->deferred_bulks = 0;
-+}
-+
-+static int
-+parse_open(VCHIQ_STATE_T *state, VCHIQ_HEADER_T *header)
-+{
-+ VCHIQ_SERVICE_T *service = NULL;
-+ int msgid, size;
-+ int type;
-+ unsigned int localport, remoteport;
-+
-+ msgid = header->msgid;
-+ size = header->size;
-+ type = VCHIQ_MSG_TYPE(msgid);
-+ localport = VCHIQ_MSG_DSTPORT(msgid);
-+ remoteport = VCHIQ_MSG_SRCPORT(msgid);
-+ if (size >= sizeof(struct vchiq_open_payload)) {
-+ const struct vchiq_open_payload *payload =
-+ (struct vchiq_open_payload *)header->data;
-+ unsigned int fourcc;
-+
-+ fourcc = payload->fourcc;
-+ vchiq_log_info(vchiq_core_log_level,
-+ "%d: prs OPEN@%x (%d->'%c%c%c%c')",
-+ state->id, (unsigned int)header,
-+ localport,
-+ VCHIQ_FOURCC_AS_4CHARS(fourcc));
-+
-+ service = get_listening_service(state, fourcc);
-+
-+ if (service) {
-+ /* A matching service exists */
-+ short version = payload->version;
-+ short version_min = payload->version_min;
-+ if ((service->version < version_min) ||
-+ (version < service->version_min)) {
-+ /* Version mismatch */
-+ vchiq_loud_error_header();
-+ vchiq_loud_error("%d: service %d (%c%c%c%c) "
-+ "version mismatch - local (%d, min %d)"
-+ " vs. remote (%d, min %d)",
-+ state->id, service->localport,
-+ VCHIQ_FOURCC_AS_4CHARS(fourcc),
-+ service->version, service->version_min,
-+ version, version_min);
-+ vchiq_loud_error_footer();
-+ unlock_service(service);
-+ service = NULL;
-+ goto fail_open;
-+ }
-+ service->peer_version = version;
-+
-+ if (service->srvstate == VCHIQ_SRVSTATE_LISTENING) {
-+ struct vchiq_openack_payload ack_payload = {
-+ service->version
-+ };
-+ VCHIQ_ELEMENT_T body = {
-+ &ack_payload,
-+ sizeof(ack_payload)
-+ };
-+
-+ if (state->version_common <
-+ VCHIQ_VERSION_SYNCHRONOUS_MODE)
-+ service->sync = 0;
-+
-+ /* Acknowledge the OPEN */
-+ if (service->sync &&
-+ (state->version_common >=
-+ VCHIQ_VERSION_SYNCHRONOUS_MODE)) {
-+ if (queue_message_sync(state, NULL,
-+ VCHIQ_MAKE_MSG(
-+ VCHIQ_MSG_OPENACK,
-+ service->localport,
-+ remoteport),
-+ &body, 1, sizeof(ack_payload),
-+ 0) == VCHIQ_RETRY)
-+ goto bail_not_ready;
-+ } else {
-+ if (queue_message(state, NULL,
-+ VCHIQ_MAKE_MSG(
-+ VCHIQ_MSG_OPENACK,
-+ service->localport,
-+ remoteport),
-+ &body, 1, sizeof(ack_payload),
-+ 0) == VCHIQ_RETRY)
-+ goto bail_not_ready;
-+ }
-+
-+ /* The service is now open */
-+ vchiq_set_service_state(service,
-+ service->sync ? VCHIQ_SRVSTATE_OPENSYNC
-+ : VCHIQ_SRVSTATE_OPEN);
-+ }
-+
-+ service->remoteport = remoteport;
-+ service->client_id = ((int *)header->data)[1];
-+ if (make_service_callback(service, VCHIQ_SERVICE_OPENED,
-+ NULL, NULL) == VCHIQ_RETRY) {
-+ /* Bail out if not ready */
-+ service->remoteport = VCHIQ_PORT_FREE;
-+ goto bail_not_ready;
-+ }
-+
-+ /* Success - the message has been dealt with */
-+ unlock_service(service);
-+ return 1;
-+ }
-+ }
-+
-+fail_open:
-+ /* No available service, or an invalid request - send a CLOSE */
-+ if (queue_message(state, NULL,
-+ VCHIQ_MAKE_MSG(VCHIQ_MSG_CLOSE, 0, VCHIQ_MSG_SRCPORT(msgid)),
-+ NULL, 0, 0, 0) == VCHIQ_RETRY)
-+ goto bail_not_ready;
-+
-+ return 1;
-+
-+bail_not_ready:
-+ if (service)
-+ unlock_service(service);
-+
-+ return 0;
-+}
-+
-+/* Called by the slot handler thread */
-+static void
-+parse_rx_slots(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_SHARED_STATE_T *remote = state->remote;
-+ VCHIQ_SERVICE_T *service = NULL;
-+ int tx_pos;
-+ DEBUG_INITIALISE(state->local)
-+
-+ tx_pos = remote->tx_pos;
-+
-+ while (state->rx_pos != tx_pos) {
-+ VCHIQ_HEADER_T *header;
-+ int msgid, size;
-+ int type;
-+ unsigned int localport, remoteport;
-+
-+ DEBUG_TRACE(PARSE_LINE);
-+ if (!state->rx_data) {
-+ int rx_index;
-+ WARN_ON(!((state->rx_pos & VCHIQ_SLOT_MASK) == 0));
-+ rx_index = remote->slot_queue[
-+ SLOT_QUEUE_INDEX_FROM_POS(state->rx_pos) &
-+ VCHIQ_SLOT_QUEUE_MASK];
-+ state->rx_data = (char *)SLOT_DATA_FROM_INDEX(state,
-+ rx_index);
-+ state->rx_info = SLOT_INFO_FROM_INDEX(state, rx_index);
-+
-+ /* Initialise use_count to one, and increment
-+ ** release_count at the end of the slot to avoid
-+ ** releasing the slot prematurely. */
-+ state->rx_info->use_count = 1;
-+ state->rx_info->release_count = 0;
-+ }
-+
-+ header = (VCHIQ_HEADER_T *)(state->rx_data +
-+ (state->rx_pos & VCHIQ_SLOT_MASK));
-+ DEBUG_VALUE(PARSE_HEADER, (int)header);
-+ msgid = header->msgid;
-+ DEBUG_VALUE(PARSE_MSGID, msgid);
-+ size = header->size;
-+ type = VCHIQ_MSG_TYPE(msgid);
-+ localport = VCHIQ_MSG_DSTPORT(msgid);
-+ remoteport = VCHIQ_MSG_SRCPORT(msgid);
-+
-+ if (type != VCHIQ_MSG_DATA)
-+ VCHIQ_STATS_INC(state, ctrl_rx_count);
-+
-+ switch (type) {
-+ case VCHIQ_MSG_OPENACK:
-+ case VCHIQ_MSG_CLOSE:
-+ case VCHIQ_MSG_DATA:
-+ case VCHIQ_MSG_BULK_RX:
-+ case VCHIQ_MSG_BULK_TX:
-+ case VCHIQ_MSG_BULK_RX_DONE:
-+ case VCHIQ_MSG_BULK_TX_DONE:
-+ service = find_service_by_port(state, localport);
-+ if ((!service ||
-+ ((service->remoteport != remoteport) &&
-+ (service->remoteport != VCHIQ_PORT_FREE))) &&
-+ (localport == 0) &&
-+ (type == VCHIQ_MSG_CLOSE)) {
-+ /* This could be a CLOSE from a client which
-+ hadn't yet received the OPENACK - look for
-+ the connected service */
-+ if (service)
-+ unlock_service(service);
-+ service = get_connected_service(state,
-+ remoteport);
-+ if (service)
-+ vchiq_log_warning(vchiq_core_log_level,
-+ "%d: prs %s@%x (%d->%d) - "
-+ "found connected service %d",
-+ state->id, msg_type_str(type),
-+ (unsigned int)header,
-+ remoteport, localport,
-+ service->localport);
-+ }
-+
-+ if (!service) {
-+ vchiq_log_error(vchiq_core_log_level,
-+ "%d: prs %s@%x (%d->%d) - "
-+ "invalid/closed service %d",
-+ state->id, msg_type_str(type),
-+ (unsigned int)header,
-+ remoteport, localport, localport);
-+ goto skip_message;
-+ }
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ if (SRVTRACE_ENABLED(service, VCHIQ_LOG_INFO)) {
-+ int svc_fourcc;
-+
-+ svc_fourcc = service
-+ ? service->base.fourcc
-+ : VCHIQ_MAKE_FOURCC('?', '?', '?', '?');
-+ vchiq_log_info(SRVTRACE_LEVEL(service),
-+ "Rcvd Msg %s(%u) from %c%c%c%c s:%d d:%d "
-+ "len:%d",
-+ msg_type_str(type), type,
-+ VCHIQ_FOURCC_AS_4CHARS(svc_fourcc),
-+ remoteport, localport, size);
-+ if (size > 0)
-+ vchiq_log_dump_mem("Rcvd", 0, header->data,
-+ min(64, size));
-+ }
-+
-+ if (((unsigned int)header & VCHIQ_SLOT_MASK) + calc_stride(size)
-+ > VCHIQ_SLOT_SIZE) {
-+ vchiq_log_error(vchiq_core_log_level,
-+ "header %x (msgid %x) - size %x too big for "
-+ "slot",
-+ (unsigned int)header, (unsigned int)msgid,
-+ (unsigned int)size);
-+ WARN(1, "oversized for slot\n");
-+ }
-+
-+ switch (type) {
-+ case VCHIQ_MSG_OPEN:
-+ WARN_ON(!(VCHIQ_MSG_DSTPORT(msgid) == 0));
-+ if (!parse_open(state, header))
-+ goto bail_not_ready;
-+ break;
-+ case VCHIQ_MSG_OPENACK:
-+ if (size >= sizeof(struct vchiq_openack_payload)) {
-+ const struct vchiq_openack_payload *payload =
-+ (struct vchiq_openack_payload *)
-+ header->data;
-+ service->peer_version = payload->version;
-+ }
-+ vchiq_log_info(vchiq_core_log_level,
-+ "%d: prs OPENACK@%x,%x (%d->%d) v:%d",
-+ state->id, (unsigned int)header, size,
-+ remoteport, localport, service->peer_version);
-+ if (service->srvstate ==
-+ VCHIQ_SRVSTATE_OPENING) {
-+ service->remoteport = remoteport;
-+ vchiq_set_service_state(service,
-+ VCHIQ_SRVSTATE_OPEN);
-+ up(&service->remove_event);
-+ } else
-+ vchiq_log_error(vchiq_core_log_level,
-+ "OPENACK received in state %s",
-+ srvstate_names[service->srvstate]);
-+ break;
-+ case VCHIQ_MSG_CLOSE:
-+ WARN_ON(size != 0); /* There should be no data */
-+
-+ vchiq_log_info(vchiq_core_log_level,
-+ "%d: prs CLOSE@%x (%d->%d)",
-+ state->id, (unsigned int)header,
-+ remoteport, localport);
-+
-+ mark_service_closing_internal(service, 1);
-+
-+ if (vchiq_close_service_internal(service,
-+ 1/*close_recvd*/) == VCHIQ_RETRY)
-+ goto bail_not_ready;
-+
-+ vchiq_log_info(vchiq_core_log_level,
-+ "Close Service %c%c%c%c s:%u d:%d",
-+ VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc),
-+ service->localport,
-+ service->remoteport);
-+ break;
-+ case VCHIQ_MSG_DATA:
-+ vchiq_log_info(vchiq_core_log_level,
-+ "%d: prs DATA@%x,%x (%d->%d)",
-+ state->id, (unsigned int)header, size,
-+ remoteport, localport);
-+
-+ if ((service->remoteport == remoteport)
-+ && (service->srvstate ==
-+ VCHIQ_SRVSTATE_OPEN)) {
-+ header->msgid = msgid | VCHIQ_MSGID_CLAIMED;
-+ claim_slot(state->rx_info);
-+ DEBUG_TRACE(PARSE_LINE);
-+ if (make_service_callback(service,
-+ VCHIQ_MESSAGE_AVAILABLE, header,
-+ NULL) == VCHIQ_RETRY) {
-+ DEBUG_TRACE(PARSE_LINE);
-+ goto bail_not_ready;
-+ }
-+ VCHIQ_SERVICE_STATS_INC(service, ctrl_rx_count);
-+ VCHIQ_SERVICE_STATS_ADD(service, ctrl_rx_bytes,
-+ size);
-+ } else {
-+ VCHIQ_STATS_INC(state, error_count);
-+ }
-+ break;
-+ case VCHIQ_MSG_CONNECT:
-+ vchiq_log_info(vchiq_core_log_level,
-+ "%d: prs CONNECT@%x",
-+ state->id, (unsigned int)header);
-+ state->version_common = ((VCHIQ_SLOT_ZERO_T *)
-+ state->slot_data)->version;
-+ up(&state->connect);
-+ break;
-+ case VCHIQ_MSG_BULK_RX:
-+ case VCHIQ_MSG_BULK_TX: {
-+ VCHIQ_BULK_QUEUE_T *queue;
-+ WARN_ON(!state->is_master);
-+ queue = (type == VCHIQ_MSG_BULK_RX) ?
-+ &service->bulk_tx : &service->bulk_rx;
-+ if ((service->remoteport == remoteport)
-+ && (service->srvstate ==
-+ VCHIQ_SRVSTATE_OPEN)) {
-+ VCHIQ_BULK_T *bulk;
-+ int resolved = 0;
-+
-+ DEBUG_TRACE(PARSE_LINE);
-+ if (mutex_lock_interruptible(
-+ &service->bulk_mutex) != 0) {
-+ DEBUG_TRACE(PARSE_LINE);
-+ goto bail_not_ready;
-+ }
-+
-+ WARN_ON(!(queue->remote_insert < queue->remove +
-+ VCHIQ_NUM_SERVICE_BULKS));
-+ bulk = &queue->bulks[
-+ BULK_INDEX(queue->remote_insert)];
-+ bulk->remote_data =
-+ (void *)((int *)header->data)[0];
-+ bulk->remote_size = ((int *)header->data)[1];
-+ wmb();
-+
-+ vchiq_log_info(vchiq_core_log_level,
-+ "%d: prs %s@%x (%d->%d) %x@%x",
-+ state->id, msg_type_str(type),
-+ (unsigned int)header,
-+ remoteport, localport,
-+ bulk->remote_size,
-+ (unsigned int)bulk->remote_data);
-+
-+ queue->remote_insert++;
-+
-+ if (atomic_read(&pause_bulks_count)) {
-+ state->deferred_bulks++;
-+ vchiq_log_info(vchiq_core_log_level,
-+ "%s: deferring bulk (%d)",
-+ __func__,
-+ state->deferred_bulks);
-+ if (state->conn_state !=
-+ VCHIQ_CONNSTATE_PAUSE_SENT)
-+ vchiq_log_error(
-+ vchiq_core_log_level,
-+ "%s: bulks paused in "
-+ "unexpected state %s",
-+ __func__,
-+ conn_state_names[
-+ state->conn_state]);
-+ } else if (state->conn_state ==
-+ VCHIQ_CONNSTATE_CONNECTED) {
-+ DEBUG_TRACE(PARSE_LINE);
-+ resolved = resolve_bulks(service,
-+ queue);
-+ }
-+
-+ mutex_unlock(&service->bulk_mutex);
-+ if (resolved)
-+ notify_bulks(service, queue,
-+ 1/*retry_poll*/);
-+ }
-+ } break;
-+ case VCHIQ_MSG_BULK_RX_DONE:
-+ case VCHIQ_MSG_BULK_TX_DONE:
-+ WARN_ON(state->is_master);
-+ if ((service->remoteport == remoteport)
-+ && (service->srvstate !=
-+ VCHIQ_SRVSTATE_FREE)) {
-+ VCHIQ_BULK_QUEUE_T *queue;
-+ VCHIQ_BULK_T *bulk;
-+
-+ queue = (type == VCHIQ_MSG_BULK_RX_DONE) ?
-+ &service->bulk_rx : &service->bulk_tx;
-+
-+ DEBUG_TRACE(PARSE_LINE);
-+ if (mutex_lock_interruptible(
-+ &service->bulk_mutex) != 0) {
-+ DEBUG_TRACE(PARSE_LINE);
-+ goto bail_not_ready;
-+ }
-+ if ((int)(queue->remote_insert -
-+ queue->local_insert) >= 0) {
-+ vchiq_log_error(vchiq_core_log_level,
-+ "%d: prs %s@%x (%d->%d) "
-+ "unexpected (ri=%d,li=%d)",
-+ state->id, msg_type_str(type),
-+ (unsigned int)header,
-+ remoteport, localport,
-+ queue->remote_insert,
-+ queue->local_insert);
-+ mutex_unlock(&service->bulk_mutex);
-+ break;
-+ }
-+
-+ BUG_ON(queue->process == queue->local_insert);
-+ BUG_ON(queue->process != queue->remote_insert);
-+
-+ bulk = &queue->bulks[
-+ BULK_INDEX(queue->remote_insert)];
-+ bulk->actual = *(int *)header->data;
-+ queue->remote_insert++;
-+
-+ vchiq_log_info(vchiq_core_log_level,
-+ "%d: prs %s@%x (%d->%d) %x@%x",
-+ state->id, msg_type_str(type),
-+ (unsigned int)header,
-+ remoteport, localport,
-+ bulk->actual, (unsigned int)bulk->data);
-+
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%d: prs:%d %cx li=%x ri=%x p=%x",
-+ state->id, localport,
-+ (type == VCHIQ_MSG_BULK_RX_DONE) ?
-+ 'r' : 't',
-+ queue->local_insert,
-+ queue->remote_insert, queue->process);
-+
-+ DEBUG_TRACE(PARSE_LINE);
-+ WARN_ON(queue->process == queue->local_insert);
-+ vchiq_complete_bulk(bulk);
-+ queue->process++;
-+ mutex_unlock(&service->bulk_mutex);
-+ DEBUG_TRACE(PARSE_LINE);
-+ notify_bulks(service, queue, 1/*retry_poll*/);
-+ DEBUG_TRACE(PARSE_LINE);
-+ }
-+ break;
-+ case VCHIQ_MSG_PADDING:
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%d: prs PADDING@%x,%x",
-+ state->id, (unsigned int)header, size);
-+ break;
-+ case VCHIQ_MSG_PAUSE:
-+ /* If initiated, signal the application thread */
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%d: prs PAUSE@%x,%x",
-+ state->id, (unsigned int)header, size);
-+ if (state->conn_state == VCHIQ_CONNSTATE_PAUSED) {
-+ vchiq_log_error(vchiq_core_log_level,
-+ "%d: PAUSE received in state PAUSED",
-+ state->id);
-+ break;
-+ }
-+ if (state->conn_state != VCHIQ_CONNSTATE_PAUSE_SENT) {
-+ /* Send a PAUSE in response */
-+ if (queue_message(state, NULL,
-+ VCHIQ_MAKE_MSG(VCHIQ_MSG_PAUSE, 0, 0),
-+ NULL, 0, 0, QMFLAGS_NO_MUTEX_UNLOCK)
-+ == VCHIQ_RETRY)
-+ goto bail_not_ready;
-+ if (state->is_master)
-+ pause_bulks(state);
-+ }
-+ /* At this point slot_mutex is held */
-+ vchiq_set_conn_state(state, VCHIQ_CONNSTATE_PAUSED);
-+ vchiq_platform_paused(state);
-+ break;
-+ case VCHIQ_MSG_RESUME:
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%d: prs RESUME@%x,%x",
-+ state->id, (unsigned int)header, size);
-+ /* Release the slot mutex */
-+ mutex_unlock(&state->slot_mutex);
-+ if (state->is_master)
-+ resume_bulks(state);
-+ vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTED);
-+ vchiq_platform_resumed(state);
-+ break;
-+
-+ case VCHIQ_MSG_REMOTE_USE:
-+ vchiq_on_remote_use(state);
-+ break;
-+ case VCHIQ_MSG_REMOTE_RELEASE:
-+ vchiq_on_remote_release(state);
-+ break;
-+ case VCHIQ_MSG_REMOTE_USE_ACTIVE:
-+ vchiq_on_remote_use_active(state);
-+ break;
-+
-+ default:
-+ vchiq_log_error(vchiq_core_log_level,
-+ "%d: prs invalid msgid %x@%x,%x",
-+ state->id, msgid, (unsigned int)header, size);
-+ WARN(1, "invalid message\n");
-+ break;
-+ }
-+
-+skip_message:
-+ if (service) {
-+ unlock_service(service);
-+ service = NULL;
-+ }
-+
-+ state->rx_pos += calc_stride(size);
-+
-+ DEBUG_TRACE(PARSE_LINE);
-+ /* Perform some housekeeping when the end of the slot is
-+ ** reached. */
-+ if ((state->rx_pos & VCHIQ_SLOT_MASK) == 0) {
-+ /* Remove the extra reference count. */
-+ release_slot(state, state->rx_info, NULL, NULL);
-+ state->rx_data = NULL;
-+ }
-+ }
-+
-+bail_not_ready:
-+ if (service)
-+ unlock_service(service);
-+}
-+
-+/* Called by the slot handler thread */
-+static int
-+slot_handler_func(void *v)
-+{
-+ VCHIQ_STATE_T *state = (VCHIQ_STATE_T *) v;
-+ VCHIQ_SHARED_STATE_T *local = state->local;
-+ DEBUG_INITIALISE(local)
-+
-+ while (1) {
-+ DEBUG_COUNT(SLOT_HANDLER_COUNT);
-+ DEBUG_TRACE(SLOT_HANDLER_LINE);
-+ remote_event_wait(&local->trigger);
-+
-+ rmb();
-+
-+ DEBUG_TRACE(SLOT_HANDLER_LINE);
-+ if (state->poll_needed) {
-+ /* Check if we need to suspend - may change our
-+ * conn_state */
-+ vchiq_platform_check_suspend(state);
-+
-+ state->poll_needed = 0;
-+
-+ /* Handle service polling and other rare conditions here
-+ ** out of the mainline code */
-+ switch (state->conn_state) {
-+ case VCHIQ_CONNSTATE_CONNECTED:
-+ /* Poll the services as requested */
-+ poll_services(state);
-+ break;
-+
-+ case VCHIQ_CONNSTATE_PAUSING:
-+ if (state->is_master)
-+ pause_bulks(state);
-+ if (queue_message(state, NULL,
-+ VCHIQ_MAKE_MSG(VCHIQ_MSG_PAUSE, 0, 0),
-+ NULL, 0, 0,
-+ QMFLAGS_NO_MUTEX_UNLOCK)
-+ != VCHIQ_RETRY) {
-+ vchiq_set_conn_state(state,
-+ VCHIQ_CONNSTATE_PAUSE_SENT);
-+ } else {
-+ if (state->is_master)
-+ resume_bulks(state);
-+ /* Retry later */
-+ state->poll_needed = 1;
-+ }
-+ break;
-+
-+ case VCHIQ_CONNSTATE_PAUSED:
-+ vchiq_platform_resume(state);
-+ break;
-+
-+ case VCHIQ_CONNSTATE_RESUMING:
-+ if (queue_message(state, NULL,
-+ VCHIQ_MAKE_MSG(VCHIQ_MSG_RESUME, 0, 0),
-+ NULL, 0, 0, QMFLAGS_NO_MUTEX_LOCK)
-+ != VCHIQ_RETRY) {
-+ if (state->is_master)
-+ resume_bulks(state);
-+ vchiq_set_conn_state(state,
-+ VCHIQ_CONNSTATE_CONNECTED);
-+ vchiq_platform_resumed(state);
-+ } else {
-+ /* This should really be impossible,
-+ ** since the PAUSE should have flushed
-+ ** through outstanding messages. */
-+ vchiq_log_error(vchiq_core_log_level,
-+ "Failed to send RESUME "
-+ "message");
-+ BUG();
-+ }
-+ break;
-+
-+ case VCHIQ_CONNSTATE_PAUSE_TIMEOUT:
-+ case VCHIQ_CONNSTATE_RESUME_TIMEOUT:
-+ vchiq_platform_handle_timeout(state);
-+ break;
-+ default:
-+ break;
-+ }
-+
-+
-+ }
-+
-+ DEBUG_TRACE(SLOT_HANDLER_LINE);
-+ parse_rx_slots(state);
-+ }
-+ return 0;
-+}
-+
-+
-+/* Called by the recycle thread */
-+static int
-+recycle_func(void *v)
-+{
-+ VCHIQ_STATE_T *state = (VCHIQ_STATE_T *) v;
-+ VCHIQ_SHARED_STATE_T *local = state->local;
-+
-+ while (1) {
-+ remote_event_wait(&local->recycle);
-+
-+ process_free_queue(state);
-+ }
-+ return 0;
-+}
-+
-+
-+/* Called by the sync thread */
-+static int
-+sync_func(void *v)
-+{
-+ VCHIQ_STATE_T *state = (VCHIQ_STATE_T *) v;
-+ VCHIQ_SHARED_STATE_T *local = state->local;
-+ VCHIQ_HEADER_T *header = (VCHIQ_HEADER_T *)SLOT_DATA_FROM_INDEX(state,
-+ state->remote->slot_sync);
-+
-+ while (1) {
-+ VCHIQ_SERVICE_T *service;
-+ int msgid, size;
-+ int type;
-+ unsigned int localport, remoteport;
-+
-+ remote_event_wait(&local->sync_trigger);
-+
-+ rmb();
-+
-+ msgid = header->msgid;
-+ size = header->size;
-+ type = VCHIQ_MSG_TYPE(msgid);
-+ localport = VCHIQ_MSG_DSTPORT(msgid);
-+ remoteport = VCHIQ_MSG_SRCPORT(msgid);
-+
-+ service = find_service_by_port(state, localport);
-+
-+ if (!service) {
-+ vchiq_log_error(vchiq_sync_log_level,
-+ "%d: sf %s@%x (%d->%d) - "
-+ "invalid/closed service %d",
-+ state->id, msg_type_str(type),
-+ (unsigned int)header,
-+ remoteport, localport, localport);
-+ release_message_sync(state, header);
-+ continue;
-+ }
-+
-+ if (vchiq_sync_log_level >= VCHIQ_LOG_TRACE) {
-+ int svc_fourcc;
-+
-+ svc_fourcc = service
-+ ? service->base.fourcc
-+ : VCHIQ_MAKE_FOURCC('?', '?', '?', '?');
-+ vchiq_log_trace(vchiq_sync_log_level,
-+ "Rcvd Msg %s from %c%c%c%c s:%d d:%d len:%d",
-+ msg_type_str(type),
-+ VCHIQ_FOURCC_AS_4CHARS(svc_fourcc),
-+ remoteport, localport, size);
-+ if (size > 0)
-+ vchiq_log_dump_mem("Rcvd", 0, header->data,
-+ min(64, size));
-+ }
-+
-+ switch (type) {
-+ case VCHIQ_MSG_OPENACK:
-+ if (size >= sizeof(struct vchiq_openack_payload)) {
-+ const struct vchiq_openack_payload *payload =
-+ (struct vchiq_openack_payload *)
-+ header->data;
-+ service->peer_version = payload->version;
-+ }
-+ vchiq_log_info(vchiq_sync_log_level,
-+ "%d: sf OPENACK@%x,%x (%d->%d) v:%d",
-+ state->id, (unsigned int)header, size,
-+ remoteport, localport, service->peer_version);
-+ if (service->srvstate == VCHIQ_SRVSTATE_OPENING) {
-+ service->remoteport = remoteport;
-+ vchiq_set_service_state(service,
-+ VCHIQ_SRVSTATE_OPENSYNC);
-+ service->sync = 1;
-+ up(&service->remove_event);
-+ }
-+ release_message_sync(state, header);
-+ break;
-+
-+ case VCHIQ_MSG_DATA:
-+ vchiq_log_trace(vchiq_sync_log_level,
-+ "%d: sf DATA@%x,%x (%d->%d)",
-+ state->id, (unsigned int)header, size,
-+ remoteport, localport);
-+
-+ if ((service->remoteport == remoteport) &&
-+ (service->srvstate ==
-+ VCHIQ_SRVSTATE_OPENSYNC)) {
-+ if (make_service_callback(service,
-+ VCHIQ_MESSAGE_AVAILABLE, header,
-+ NULL) == VCHIQ_RETRY)
-+ vchiq_log_error(vchiq_sync_log_level,
-+ "synchronous callback to "
-+ "service %d returns "
-+ "VCHIQ_RETRY",
-+ localport);
-+ }
-+ break;
-+
-+ default:
-+ vchiq_log_error(vchiq_sync_log_level,
-+ "%d: sf unexpected msgid %x@%x,%x",
-+ state->id, msgid, (unsigned int)header, size);
-+ release_message_sync(state, header);
-+ break;
-+ }
-+
-+ unlock_service(service);
-+ }
-+
-+ return 0;
-+}
-+
-+
-+static void
-+init_bulk_queue(VCHIQ_BULK_QUEUE_T *queue)
-+{
-+ queue->local_insert = 0;
-+ queue->remote_insert = 0;
-+ queue->process = 0;
-+ queue->remote_notify = 0;
-+ queue->remove = 0;
-+}
-+
-+
-+inline const char *
-+get_conn_state_name(VCHIQ_CONNSTATE_T conn_state)
-+{
-+ return conn_state_names[conn_state];
-+}
-+
-+
-+VCHIQ_SLOT_ZERO_T *
-+vchiq_init_slots(void *mem_base, int mem_size)
-+{
-+ int mem_align = (VCHIQ_SLOT_SIZE - (int)mem_base) & VCHIQ_SLOT_MASK;
-+ VCHIQ_SLOT_ZERO_T *slot_zero =
-+ (VCHIQ_SLOT_ZERO_T *)((char *)mem_base + mem_align);
-+ int num_slots = (mem_size - mem_align)/VCHIQ_SLOT_SIZE;
-+ int first_data_slot = VCHIQ_SLOT_ZERO_SLOTS;
-+
-+ /* Ensure there is enough memory to run an absolutely minimum system */
-+ num_slots -= first_data_slot;
-+
-+ if (num_slots < 4) {
-+ vchiq_log_error(vchiq_core_log_level,
-+ "vchiq_init_slots - insufficient memory %x bytes",
-+ mem_size);
-+ return NULL;
-+ }
-+
-+ memset(slot_zero, 0, sizeof(VCHIQ_SLOT_ZERO_T));
-+
-+ slot_zero->magic = VCHIQ_MAGIC;
-+ slot_zero->version = VCHIQ_VERSION;
-+ slot_zero->version_min = VCHIQ_VERSION_MIN;
-+ slot_zero->slot_zero_size = sizeof(VCHIQ_SLOT_ZERO_T);
-+ slot_zero->slot_size = VCHIQ_SLOT_SIZE;
-+ slot_zero->max_slots = VCHIQ_MAX_SLOTS;
-+ slot_zero->max_slots_per_side = VCHIQ_MAX_SLOTS_PER_SIDE;
-+
-+ slot_zero->master.slot_sync = first_data_slot;
-+ slot_zero->master.slot_first = first_data_slot + 1;
-+ slot_zero->master.slot_last = first_data_slot + (num_slots/2) - 1;
-+ slot_zero->slave.slot_sync = first_data_slot + (num_slots/2);
-+ slot_zero->slave.slot_first = first_data_slot + (num_slots/2) + 1;
-+ slot_zero->slave.slot_last = first_data_slot + num_slots - 1;
-+
-+ return slot_zero;
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_init_state(VCHIQ_STATE_T *state, VCHIQ_SLOT_ZERO_T *slot_zero,
-+ int is_master)
-+{
-+ VCHIQ_SHARED_STATE_T *local;
-+ VCHIQ_SHARED_STATE_T *remote;
-+ VCHIQ_STATUS_T status;
-+ char threadname[10];
-+ static int id;
-+ int i;
-+
-+ vchiq_log_warning(vchiq_core_log_level,
-+ "%s: slot_zero = 0x%08lx, is_master = %d",
-+ __func__, (unsigned long)slot_zero, is_master);
-+
-+ /* Check the input configuration */
-+
-+ if (slot_zero->magic != VCHIQ_MAGIC) {
-+ vchiq_loud_error_header();
-+ vchiq_loud_error("Invalid VCHIQ magic value found.");
-+ vchiq_loud_error("slot_zero=%x: magic=%x (expected %x)",
-+ (unsigned int)slot_zero, slot_zero->magic, VCHIQ_MAGIC);
-+ vchiq_loud_error_footer();
-+ return VCHIQ_ERROR;
-+ }
-+
-+ if (slot_zero->version < VCHIQ_VERSION_MIN) {
-+ vchiq_loud_error_header();
-+ vchiq_loud_error("Incompatible VCHIQ versions found.");
-+ vchiq_loud_error("slot_zero=%x: VideoCore version=%d "
-+ "(minimum %d)",
-+ (unsigned int)slot_zero, slot_zero->version,
-+ VCHIQ_VERSION_MIN);
-+ vchiq_loud_error("Restart with a newer VideoCore image.");
-+ vchiq_loud_error_footer();
-+ return VCHIQ_ERROR;
-+ }
-+
-+ if (VCHIQ_VERSION < slot_zero->version_min) {
-+ vchiq_loud_error_header();
-+ vchiq_loud_error("Incompatible VCHIQ versions found.");
-+ vchiq_loud_error("slot_zero=%x: version=%d (VideoCore "
-+ "minimum %d)",
-+ (unsigned int)slot_zero, VCHIQ_VERSION,
-+ slot_zero->version_min);
-+ vchiq_loud_error("Restart with a newer kernel.");
-+ vchiq_loud_error_footer();
-+ return VCHIQ_ERROR;
-+ }
-+
-+ if ((slot_zero->slot_zero_size != sizeof(VCHIQ_SLOT_ZERO_T)) ||
-+ (slot_zero->slot_size != VCHIQ_SLOT_SIZE) ||
-+ (slot_zero->max_slots != VCHIQ_MAX_SLOTS) ||
-+ (slot_zero->max_slots_per_side != VCHIQ_MAX_SLOTS_PER_SIDE)) {
-+ vchiq_loud_error_header();
-+ if (slot_zero->slot_zero_size != sizeof(VCHIQ_SLOT_ZERO_T))
-+ vchiq_loud_error("slot_zero=%x: slot_zero_size=%x "
-+ "(expected %x)",
-+ (unsigned int)slot_zero,
-+ slot_zero->slot_zero_size,
-+ sizeof(VCHIQ_SLOT_ZERO_T));
-+ if (slot_zero->slot_size != VCHIQ_SLOT_SIZE)
-+ vchiq_loud_error("slot_zero=%x: slot_size=%d "
-+ "(expected %d",
-+ (unsigned int)slot_zero, slot_zero->slot_size,
-+ VCHIQ_SLOT_SIZE);
-+ if (slot_zero->max_slots != VCHIQ_MAX_SLOTS)
-+ vchiq_loud_error("slot_zero=%x: max_slots=%d "
-+ "(expected %d)",
-+ (unsigned int)slot_zero, slot_zero->max_slots,
-+ VCHIQ_MAX_SLOTS);
-+ if (slot_zero->max_slots_per_side != VCHIQ_MAX_SLOTS_PER_SIDE)
-+ vchiq_loud_error("slot_zero=%x: max_slots_per_side=%d "
-+ "(expected %d)",
-+ (unsigned int)slot_zero,
-+ slot_zero->max_slots_per_side,
-+ VCHIQ_MAX_SLOTS_PER_SIDE);
-+ vchiq_loud_error_footer();
-+ return VCHIQ_ERROR;
-+ }
-+
-+ if (VCHIQ_VERSION < slot_zero->version)
-+ slot_zero->version = VCHIQ_VERSION;
-+
-+ if (is_master) {
-+ local = &slot_zero->master;
-+ remote = &slot_zero->slave;
-+ } else {
-+ local = &slot_zero->slave;
-+ remote = &slot_zero->master;
-+ }
-+
-+ if (local->initialised) {
-+ vchiq_loud_error_header();
-+ if (remote->initialised)
-+ vchiq_loud_error("local state has already been "
-+ "initialised");
-+ else
-+ vchiq_loud_error("master/slave mismatch - two %ss",
-+ is_master ? "master" : "slave");
-+ vchiq_loud_error_footer();
-+ return VCHIQ_ERROR;
-+ }
-+
-+ memset(state, 0, sizeof(VCHIQ_STATE_T));
-+
-+ state->id = id++;
-+ state->is_master = is_master;
-+
-+ /*
-+ initialize shared state pointers
-+ */
-+
-+ state->local = local;
-+ state->remote = remote;
-+ state->slot_data = (VCHIQ_SLOT_T *)slot_zero;
-+
-+ /*
-+ initialize events and mutexes
-+ */
-+
-+ sema_init(&state->connect, 0);
-+ mutex_init(&state->mutex);
-+ sema_init(&state->trigger_event, 0);
-+ sema_init(&state->recycle_event, 0);
-+ sema_init(&state->sync_trigger_event, 0);
-+ sema_init(&state->sync_release_event, 0);
-+
-+ mutex_init(&state->slot_mutex);
-+ mutex_init(&state->recycle_mutex);
-+ mutex_init(&state->sync_mutex);
-+ mutex_init(&state->bulk_transfer_mutex);
-+
-+ sema_init(&state->slot_available_event, 0);
-+ sema_init(&state->slot_remove_event, 0);
-+ sema_init(&state->data_quota_event, 0);
-+
-+ state->slot_queue_available = 0;
-+
-+ for (i = 0; i < VCHIQ_MAX_SERVICES; i++) {
-+ VCHIQ_SERVICE_QUOTA_T *service_quota =
-+ &state->service_quotas[i];
-+ sema_init(&service_quota->quota_event, 0);
-+ }
-+
-+ for (i = local->slot_first; i <= local->slot_last; i++) {
-+ local->slot_queue[state->slot_queue_available++] = i;
-+ up(&state->slot_available_event);
-+ }
-+
-+ state->default_slot_quota = state->slot_queue_available/2;
-+ state->default_message_quota =
-+ min((unsigned short)(state->default_slot_quota * 256),
-+ (unsigned short)~0);
-+
-+ state->previous_data_index = -1;
-+ state->data_use_count = 0;
-+ state->data_quota = state->slot_queue_available - 1;
-+
-+ local->trigger.event = &state->trigger_event;
-+ remote_event_create(&local->trigger);
-+ local->tx_pos = 0;
-+
-+ local->recycle.event = &state->recycle_event;
-+ remote_event_create(&local->recycle);
-+ local->slot_queue_recycle = state->slot_queue_available;
-+
-+ local->sync_trigger.event = &state->sync_trigger_event;
-+ remote_event_create(&local->sync_trigger);
-+
-+ local->sync_release.event = &state->sync_release_event;
-+ remote_event_create(&local->sync_release);
-+
-+ /* At start-of-day, the slot is empty and available */
-+ ((VCHIQ_HEADER_T *)SLOT_DATA_FROM_INDEX(state, local->slot_sync))->msgid
-+ = VCHIQ_MSGID_PADDING;
-+ remote_event_signal_local(&local->sync_release);
-+
-+ local->debug[DEBUG_ENTRIES] = DEBUG_MAX;
-+
-+ status = vchiq_platform_init_state(state);
-+
-+ /*
-+ bring up slot handler thread
-+ */
-+ snprintf(threadname, sizeof(threadname), "VCHIQ-%d", state->id);
-+ state->slot_handler_thread = kthread_create(&slot_handler_func,
-+ (void *)state,
-+ threadname);
-+
-+ if (state->slot_handler_thread == NULL) {
-+ vchiq_loud_error_header();
-+ vchiq_loud_error("couldn't create thread %s", threadname);
-+ vchiq_loud_error_footer();
-+ return VCHIQ_ERROR;
-+ }
-+ set_user_nice(state->slot_handler_thread, -19);
-+ wake_up_process(state->slot_handler_thread);
-+
-+ snprintf(threadname, sizeof(threadname), "VCHIQr-%d", state->id);
-+ state->recycle_thread = kthread_create(&recycle_func,
-+ (void *)state,
-+ threadname);
-+ if (state->recycle_thread == NULL) {
-+ vchiq_loud_error_header();
-+ vchiq_loud_error("couldn't create thread %s", threadname);
-+ vchiq_loud_error_footer();
-+ return VCHIQ_ERROR;
-+ }
-+ set_user_nice(state->recycle_thread, -19);
-+ wake_up_process(state->recycle_thread);
-+
-+ snprintf(threadname, sizeof(threadname), "VCHIQs-%d", state->id);
-+ state->sync_thread = kthread_create(&sync_func,
-+ (void *)state,
-+ threadname);
-+ if (state->sync_thread == NULL) {
-+ vchiq_loud_error_header();
-+ vchiq_loud_error("couldn't create thread %s", threadname);
-+ vchiq_loud_error_footer();
-+ return VCHIQ_ERROR;
-+ }
-+ set_user_nice(state->sync_thread, -20);
-+ wake_up_process(state->sync_thread);
-+
-+ BUG_ON(state->id >= VCHIQ_MAX_STATES);
-+ vchiq_states[state->id] = state;
-+
-+ /* Indicate readiness to the other side */
-+ local->initialised = 1;
-+
-+ return status;
-+}
-+
-+/* Called from application thread when a client or server service is created. */
-+VCHIQ_SERVICE_T *
-+vchiq_add_service_internal(VCHIQ_STATE_T *state,
-+ const VCHIQ_SERVICE_PARAMS_T *params, int srvstate,
-+ VCHIQ_INSTANCE_T instance, VCHIQ_USERDATA_TERM_T userdata_term)
-+{
-+ VCHIQ_SERVICE_T *service;
-+
-+ service = kmalloc(sizeof(VCHIQ_SERVICE_T), GFP_KERNEL);
-+ if (service) {
-+ service->base.fourcc = params->fourcc;
-+ service->base.callback = params->callback;
-+ service->base.userdata = params->userdata;
-+ service->handle = VCHIQ_SERVICE_HANDLE_INVALID;
-+ service->ref_count = 1;
-+ service->srvstate = VCHIQ_SRVSTATE_FREE;
-+ service->userdata_term = userdata_term;
-+ service->localport = VCHIQ_PORT_FREE;
-+ service->remoteport = VCHIQ_PORT_FREE;
-+
-+ service->public_fourcc = (srvstate == VCHIQ_SRVSTATE_OPENING) ?
-+ VCHIQ_FOURCC_INVALID : params->fourcc;
-+ service->client_id = 0;
-+ service->auto_close = 1;
-+ service->sync = 0;
-+ service->closing = 0;
-+ service->trace = 0;
-+ atomic_set(&service->poll_flags, 0);
-+ service->version = params->version;
-+ service->version_min = params->version_min;
-+ service->state = state;
-+ service->instance = instance;
-+ service->service_use_count = 0;
-+ init_bulk_queue(&service->bulk_tx);
-+ init_bulk_queue(&service->bulk_rx);
-+ sema_init(&service->remove_event, 0);
-+ sema_init(&service->bulk_remove_event, 0);
-+ mutex_init(&service->bulk_mutex);
-+ memset(&service->stats, 0, sizeof(service->stats));
-+ } else {
-+ vchiq_log_error(vchiq_core_log_level,
-+ "Out of memory");
-+ }
-+
-+ if (service) {
-+ VCHIQ_SERVICE_T **pservice = NULL;
-+ int i;
-+
-+ /* Although it is perfectly possible to use service_spinlock
-+ ** to protect the creation of services, it is overkill as it
-+ ** disables interrupts while the array is searched.
-+ ** The only danger is of another thread trying to create a
-+ ** service - service deletion is safe.
-+ ** Therefore it is preferable to use state->mutex which,
-+ ** although slower to claim, doesn't block interrupts while
-+ ** it is held.
-+ */
-+
-+ mutex_lock(&state->mutex);
-+
-+ /* Prepare to use a previously unused service */
-+ if (state->unused_service < VCHIQ_MAX_SERVICES)
-+ pservice = &state->services[state->unused_service];
-+
-+ if (srvstate == VCHIQ_SRVSTATE_OPENING) {
-+ for (i = 0; i < state->unused_service; i++) {
-+ VCHIQ_SERVICE_T *srv = state->services[i];
-+ if (!srv) {
-+ pservice = &state->services[i];
-+ break;
-+ }
-+ }
-+ } else {
-+ for (i = (state->unused_service - 1); i >= 0; i--) {
-+ VCHIQ_SERVICE_T *srv = state->services[i];
-+ if (!srv)
-+ pservice = &state->services[i];
-+ else if ((srv->public_fourcc == params->fourcc)
-+ && ((srv->instance != instance) ||
-+ (srv->base.callback !=
-+ params->callback))) {
-+ /* There is another server using this
-+ ** fourcc which doesn't match. */
-+ pservice = NULL;
-+ break;
-+ }
-+ }
-+ }
-+
-+ if (pservice) {
-+ service->localport = (pservice - state->services);
-+ if (!handle_seq)
-+ handle_seq = VCHIQ_MAX_STATES *
-+ VCHIQ_MAX_SERVICES;
-+ service->handle = handle_seq |
-+ (state->id * VCHIQ_MAX_SERVICES) |
-+ service->localport;
-+ handle_seq += VCHIQ_MAX_STATES * VCHIQ_MAX_SERVICES;
-+ *pservice = service;
-+ if (pservice == &state->services[state->unused_service])
-+ state->unused_service++;
-+ }
-+
-+ mutex_unlock(&state->mutex);
-+
-+ if (!pservice) {
-+ kfree(service);
-+ service = NULL;
-+ }
-+ }
-+
-+ if (service) {
-+ VCHIQ_SERVICE_QUOTA_T *service_quota =
-+ &state->service_quotas[service->localport];
-+ service_quota->slot_quota = state->default_slot_quota;
-+ service_quota->message_quota = state->default_message_quota;
-+ if (service_quota->slot_use_count == 0)
-+ service_quota->previous_tx_index =
-+ SLOT_QUEUE_INDEX_FROM_POS(state->local_tx_pos)
-+ - 1;
-+
-+ /* Bring this service online */
-+ vchiq_set_service_state(service, srvstate);
-+
-+ vchiq_log_info(vchiq_core_msg_log_level,
-+ "%s Service %c%c%c%c SrcPort:%d",
-+ (srvstate == VCHIQ_SRVSTATE_OPENING)
-+ ? "Open" : "Add",
-+ VCHIQ_FOURCC_AS_4CHARS(params->fourcc),
-+ service->localport);
-+ }
-+
-+ /* Don't unlock the service - leave it with a ref_count of 1. */
-+
-+ return service;
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_open_service_internal(VCHIQ_SERVICE_T *service, int client_id)
-+{
-+ struct vchiq_open_payload payload = {
-+ service->base.fourcc,
-+ client_id,
-+ service->version,
-+ service->version_min
-+ };
-+ VCHIQ_ELEMENT_T body = { &payload, sizeof(payload) };
-+ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
-+
-+ service->client_id = client_id;
-+ vchiq_use_service_internal(service);
-+ status = queue_message(service->state, NULL,
-+ VCHIQ_MAKE_MSG(VCHIQ_MSG_OPEN, service->localport, 0),
-+ &body, 1, sizeof(payload), QMFLAGS_IS_BLOCKING);
-+ if (status == VCHIQ_SUCCESS) {
-+ /* Wait for the ACK/NAK */
-+ if (down_interruptible(&service->remove_event) != 0) {
-+ status = VCHIQ_RETRY;
-+ vchiq_release_service_internal(service);
-+ } else if ((service->srvstate != VCHIQ_SRVSTATE_OPEN) &&
-+ (service->srvstate != VCHIQ_SRVSTATE_OPENSYNC)) {
-+ if (service->srvstate != VCHIQ_SRVSTATE_CLOSEWAIT)
-+ vchiq_log_error(vchiq_core_log_level,
-+ "%d: osi - srvstate = %s (ref %d)",
-+ service->state->id,
-+ srvstate_names[service->srvstate],
-+ service->ref_count);
-+ status = VCHIQ_ERROR;
-+ VCHIQ_SERVICE_STATS_INC(service, error_count);
-+ vchiq_release_service_internal(service);
-+ }
-+ }
-+ return status;
-+}
-+
-+static void
-+release_service_messages(VCHIQ_SERVICE_T *service)
-+{
-+ VCHIQ_STATE_T *state = service->state;
-+ int slot_last = state->remote->slot_last;
-+ int i;
-+
-+ /* Release any claimed messages aimed at this service */
-+
-+ if (service->sync) {
-+ VCHIQ_HEADER_T *header =
-+ (VCHIQ_HEADER_T *)SLOT_DATA_FROM_INDEX(state,
-+ state->remote->slot_sync);
-+ if (VCHIQ_MSG_DSTPORT(header->msgid) == service->localport)
-+ release_message_sync(state, header);
-+
-+ return;
-+ }
-+
-+ for (i = state->remote->slot_first; i <= slot_last; i++) {
-+ VCHIQ_SLOT_INFO_T *slot_info =
-+ SLOT_INFO_FROM_INDEX(state, i);
-+ if (slot_info->release_count != slot_info->use_count) {
-+ char *data =
-+ (char *)SLOT_DATA_FROM_INDEX(state, i);
-+ unsigned int pos, end;
-+
-+ end = VCHIQ_SLOT_SIZE;
-+ if (data == state->rx_data)
-+ /* This buffer is still being read from - stop
-+ ** at the current read position */
-+ end = state->rx_pos & VCHIQ_SLOT_MASK;
-+
-+ pos = 0;
-+
-+ while (pos < end) {
-+ VCHIQ_HEADER_T *header =
-+ (VCHIQ_HEADER_T *)(data + pos);
-+ int msgid = header->msgid;
-+ int port = VCHIQ_MSG_DSTPORT(msgid);
-+ if ((port == service->localport) &&
-+ (msgid & VCHIQ_MSGID_CLAIMED)) {
-+ vchiq_log_info(vchiq_core_log_level,
-+ " fsi - hdr %x",
-+ (unsigned int)header);
-+ release_slot(state, slot_info, header,
-+ NULL);
-+ }
-+ pos += calc_stride(header->size);
-+ if (pos > VCHIQ_SLOT_SIZE) {
-+ vchiq_log_error(vchiq_core_log_level,
-+ "fsi - pos %x: header %x, "
-+ "msgid %x, header->msgid %x, "
-+ "header->size %x",
-+ pos, (unsigned int)header,
-+ msgid, header->msgid,
-+ header->size);
-+ WARN(1, "invalid slot position\n");
-+ }
-+ }
-+ }
-+ }
-+}
-+
-+static int
-+do_abort_bulks(VCHIQ_SERVICE_T *service)
-+{
-+ VCHIQ_STATUS_T status;
-+
-+ /* Abort any outstanding bulk transfers */
-+ if (mutex_lock_interruptible(&service->bulk_mutex) != 0)
-+ return 0;
-+ abort_outstanding_bulks(service, &service->bulk_tx);
-+ abort_outstanding_bulks(service, &service->bulk_rx);
-+ mutex_unlock(&service->bulk_mutex);
-+
-+ status = notify_bulks(service, &service->bulk_tx, 0/*!retry_poll*/);
-+ if (status == VCHIQ_SUCCESS)
-+ status = notify_bulks(service, &service->bulk_rx,
-+ 0/*!retry_poll*/);
-+ return (status == VCHIQ_SUCCESS);
-+}
-+
-+static VCHIQ_STATUS_T
-+close_service_complete(VCHIQ_SERVICE_T *service, int failstate)
-+{
-+ VCHIQ_STATUS_T status;
-+ int is_server = (service->public_fourcc != VCHIQ_FOURCC_INVALID);
-+ int newstate;
-+
-+ switch (service->srvstate) {
-+ case VCHIQ_SRVSTATE_OPEN:
-+ case VCHIQ_SRVSTATE_CLOSESENT:
-+ case VCHIQ_SRVSTATE_CLOSERECVD:
-+ if (is_server) {
-+ if (service->auto_close) {
-+ service->client_id = 0;
-+ service->remoteport = VCHIQ_PORT_FREE;
-+ newstate = VCHIQ_SRVSTATE_LISTENING;
-+ } else
-+ newstate = VCHIQ_SRVSTATE_CLOSEWAIT;
-+ } else
-+ newstate = VCHIQ_SRVSTATE_CLOSED;
-+ vchiq_set_service_state(service, newstate);
-+ break;
-+ case VCHIQ_SRVSTATE_LISTENING:
-+ break;
-+ default:
-+ vchiq_log_error(vchiq_core_log_level,
-+ "close_service_complete(%x) called in state %s",
-+ service->handle, srvstate_names[service->srvstate]);
-+ WARN(1, "close_service_complete in unexpected state\n");
-+ return VCHIQ_ERROR;
-+ }
-+
-+ status = make_service_callback(service,
-+ VCHIQ_SERVICE_CLOSED, NULL, NULL);
-+
-+ if (status != VCHIQ_RETRY) {
-+ int uc = service->service_use_count;
-+ int i;
-+ /* Complete the close process */
-+ for (i = 0; i < uc; i++)
-+ /* cater for cases where close is forced and the
-+ ** client may not close all it's handles */
-+ vchiq_release_service_internal(service);
-+
-+ service->client_id = 0;
-+ service->remoteport = VCHIQ_PORT_FREE;
-+
-+ if (service->srvstate == VCHIQ_SRVSTATE_CLOSED)
-+ vchiq_free_service_internal(service);
-+ else if (service->srvstate != VCHIQ_SRVSTATE_CLOSEWAIT) {
-+ if (is_server)
-+ service->closing = 0;
-+
-+ up(&service->remove_event);
-+ }
-+ } else
-+ vchiq_set_service_state(service, failstate);
-+
-+ return status;
-+}
-+
-+/* Called by the slot handler */
-+VCHIQ_STATUS_T
-+vchiq_close_service_internal(VCHIQ_SERVICE_T *service, int close_recvd)
-+{
-+ VCHIQ_STATE_T *state = service->state;
-+ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
-+ int is_server = (service->public_fourcc != VCHIQ_FOURCC_INVALID);
-+
-+ vchiq_log_info(vchiq_core_log_level, "%d: csi:%d,%d (%s)",
-+ service->state->id, service->localport, close_recvd,
-+ srvstate_names[service->srvstate]);
-+
-+ switch (service->srvstate) {
-+ case VCHIQ_SRVSTATE_CLOSED:
-+ case VCHIQ_SRVSTATE_HIDDEN:
-+ case VCHIQ_SRVSTATE_LISTENING:
-+ case VCHIQ_SRVSTATE_CLOSEWAIT:
-+ if (close_recvd)
-+ vchiq_log_error(vchiq_core_log_level,
-+ "vchiq_close_service_internal(1) called "
-+ "in state %s",
-+ srvstate_names[service->srvstate]);
-+ else if (is_server) {
-+ if (service->srvstate == VCHIQ_SRVSTATE_LISTENING) {
-+ status = VCHIQ_ERROR;
-+ } else {
-+ service->client_id = 0;
-+ service->remoteport = VCHIQ_PORT_FREE;
-+ if (service->srvstate ==
-+ VCHIQ_SRVSTATE_CLOSEWAIT)
-+ vchiq_set_service_state(service,
-+ VCHIQ_SRVSTATE_LISTENING);
-+ }
-+ up(&service->remove_event);
-+ } else
-+ vchiq_free_service_internal(service);
-+ break;
-+ case VCHIQ_SRVSTATE_OPENING:
-+ if (close_recvd) {
-+ /* The open was rejected - tell the user */
-+ vchiq_set_service_state(service,
-+ VCHIQ_SRVSTATE_CLOSEWAIT);
-+ up(&service->remove_event);
-+ } else {
-+ /* Shutdown mid-open - let the other side know */
-+ status = queue_message(state, service,
-+ VCHIQ_MAKE_MSG
-+ (VCHIQ_MSG_CLOSE,
-+ service->localport,
-+ VCHIQ_MSG_DSTPORT(service->remoteport)),
-+ NULL, 0, 0, 0);
-+ }
-+ break;
-+
-+ case VCHIQ_SRVSTATE_OPENSYNC:
-+ mutex_lock(&state->sync_mutex);
-+ /* Drop through */
-+
-+ case VCHIQ_SRVSTATE_OPEN:
-+ if (state->is_master || close_recvd) {
-+ if (!do_abort_bulks(service))
-+ status = VCHIQ_RETRY;
-+ }
-+
-+ release_service_messages(service);
-+
-+ if (status == VCHIQ_SUCCESS)
-+ status = queue_message(state, service,
-+ VCHIQ_MAKE_MSG
-+ (VCHIQ_MSG_CLOSE,
-+ service->localport,
-+ VCHIQ_MSG_DSTPORT(service->remoteport)),
-+ NULL, 0, 0, QMFLAGS_NO_MUTEX_UNLOCK);
-+
-+ if (status == VCHIQ_SUCCESS) {
-+ if (!close_recvd) {
-+ /* Change the state while the mutex is
-+ still held */
-+ vchiq_set_service_state(service,
-+ VCHIQ_SRVSTATE_CLOSESENT);
-+ mutex_unlock(&state->slot_mutex);
-+ if (service->sync)
-+ mutex_unlock(&state->sync_mutex);
-+ break;
-+ }
-+ } else if (service->srvstate == VCHIQ_SRVSTATE_OPENSYNC) {
-+ mutex_unlock(&state->sync_mutex);
-+ break;
-+ } else
-+ break;
-+
-+ /* Change the state while the mutex is still held */
-+ vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSERECVD);
-+ mutex_unlock(&state->slot_mutex);
-+ if (service->sync)
-+ mutex_unlock(&state->sync_mutex);
-+
-+ status = close_service_complete(service,
-+ VCHIQ_SRVSTATE_CLOSERECVD);
-+ break;
-+
-+ case VCHIQ_SRVSTATE_CLOSESENT:
-+ if (!close_recvd)
-+ /* This happens when a process is killed mid-close */
-+ break;
-+
-+ if (!state->is_master) {
-+ if (!do_abort_bulks(service)) {
-+ status = VCHIQ_RETRY;
-+ break;
-+ }
-+ }
-+
-+ if (status == VCHIQ_SUCCESS)
-+ status = close_service_complete(service,
-+ VCHIQ_SRVSTATE_CLOSERECVD);
-+ break;
-+
-+ case VCHIQ_SRVSTATE_CLOSERECVD:
-+ if (!close_recvd && is_server)
-+ /* Force into LISTENING mode */
-+ vchiq_set_service_state(service,
-+ VCHIQ_SRVSTATE_LISTENING);
-+ status = close_service_complete(service,
-+ VCHIQ_SRVSTATE_CLOSERECVD);
-+ break;
-+
-+ default:
-+ vchiq_log_error(vchiq_core_log_level,
-+ "vchiq_close_service_internal(%d) called in state %s",
-+ close_recvd, srvstate_names[service->srvstate]);
-+ break;
-+ }
-+
-+ return status;
-+}
-+
-+/* Called from the application process upon process death */
-+void
-+vchiq_terminate_service_internal(VCHIQ_SERVICE_T *service)
-+{
-+ VCHIQ_STATE_T *state = service->state;
-+
-+ vchiq_log_info(vchiq_core_log_level, "%d: tsi - (%d<->%d)",
-+ state->id, service->localport, service->remoteport);
-+
-+ mark_service_closing(service);
-+
-+ /* Mark the service for removal by the slot handler */
-+ request_poll(state, service, VCHIQ_POLL_REMOVE);
-+}
-+
-+/* Called from the slot handler */
-+void
-+vchiq_free_service_internal(VCHIQ_SERVICE_T *service)
-+{
-+ VCHIQ_STATE_T *state = service->state;
-+
-+ vchiq_log_info(vchiq_core_log_level, "%d: fsi - (%d)",
-+ state->id, service->localport);
-+
-+ switch (service->srvstate) {
-+ case VCHIQ_SRVSTATE_OPENING:
-+ case VCHIQ_SRVSTATE_CLOSED:
-+ case VCHIQ_SRVSTATE_HIDDEN:
-+ case VCHIQ_SRVSTATE_LISTENING:
-+ case VCHIQ_SRVSTATE_CLOSEWAIT:
-+ break;
-+ default:
-+ vchiq_log_error(vchiq_core_log_level,
-+ "%d: fsi - (%d) in state %s",
-+ state->id, service->localport,
-+ srvstate_names[service->srvstate]);
-+ return;
-+ }
-+
-+ vchiq_set_service_state(service, VCHIQ_SRVSTATE_FREE);
-+
-+ up(&service->remove_event);
-+
-+ /* Release the initial lock */
-+ unlock_service(service);
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_connect_internal(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance)
-+{
-+ VCHIQ_SERVICE_T *service;
-+ int i;
-+
-+ /* Find all services registered to this client and enable them. */
-+ i = 0;
-+ while ((service = next_service_by_instance(state, instance,
-+ &i)) != NULL) {
-+ if (service->srvstate == VCHIQ_SRVSTATE_HIDDEN)
-+ vchiq_set_service_state(service,
-+ VCHIQ_SRVSTATE_LISTENING);
-+ unlock_service(service);
-+ }
-+
-+ if (state->conn_state == VCHIQ_CONNSTATE_DISCONNECTED) {
-+ if (queue_message(state, NULL,
-+ VCHIQ_MAKE_MSG(VCHIQ_MSG_CONNECT, 0, 0), NULL, 0,
-+ 0, QMFLAGS_IS_BLOCKING) == VCHIQ_RETRY)
-+ return VCHIQ_RETRY;
-+
-+ vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTING);
-+ }
-+
-+ if (state->conn_state == VCHIQ_CONNSTATE_CONNECTING) {
-+ if (down_interruptible(&state->connect) != 0)
-+ return VCHIQ_RETRY;
-+
-+ vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTED);
-+ up(&state->connect);
-+ }
-+
-+ return VCHIQ_SUCCESS;
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_shutdown_internal(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance)
-+{
-+ VCHIQ_SERVICE_T *service;
-+ int i;
-+
-+ /* Find all services registered to this client and enable them. */
-+ i = 0;
-+ while ((service = next_service_by_instance(state, instance,
-+ &i)) != NULL) {
-+ (void)vchiq_remove_service(service->handle);
-+ unlock_service(service);
-+ }
-+
-+ return VCHIQ_SUCCESS;
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_pause_internal(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
-+
-+ switch (state->conn_state) {
-+ case VCHIQ_CONNSTATE_CONNECTED:
-+ /* Request a pause */
-+ vchiq_set_conn_state(state, VCHIQ_CONNSTATE_PAUSING);
-+ request_poll(state, NULL, 0);
-+ break;
-+ default:
-+ vchiq_log_error(vchiq_core_log_level,
-+ "vchiq_pause_internal in state %s\n",
-+ conn_state_names[state->conn_state]);
-+ status = VCHIQ_ERROR;
-+ VCHIQ_STATS_INC(state, error_count);
-+ break;
-+ }
-+
-+ return status;
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_resume_internal(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
-+
-+ if (state->conn_state == VCHIQ_CONNSTATE_PAUSED) {
-+ vchiq_set_conn_state(state, VCHIQ_CONNSTATE_RESUMING);
-+ request_poll(state, NULL, 0);
-+ } else {
-+ status = VCHIQ_ERROR;
-+ VCHIQ_STATS_INC(state, error_count);
-+ }
-+
-+ return status;
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_close_service(VCHIQ_SERVICE_HANDLE_T handle)
-+{
-+ /* Unregister the service */
-+ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
-+ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
-+
-+ if (!service)
-+ return VCHIQ_ERROR;
-+
-+ vchiq_log_info(vchiq_core_log_level,
-+ "%d: close_service:%d",
-+ service->state->id, service->localport);
-+
-+ if ((service->srvstate == VCHIQ_SRVSTATE_FREE) ||
-+ (service->srvstate == VCHIQ_SRVSTATE_LISTENING) ||
-+ (service->srvstate == VCHIQ_SRVSTATE_HIDDEN)) {
-+ unlock_service(service);
-+ return VCHIQ_ERROR;
-+ }
-+
-+ mark_service_closing(service);
-+
-+ if (current == service->state->slot_handler_thread) {
-+ status = vchiq_close_service_internal(service,
-+ 0/*!close_recvd*/);
-+ BUG_ON(status == VCHIQ_RETRY);
-+ } else {
-+ /* Mark the service for termination by the slot handler */
-+ request_poll(service->state, service, VCHIQ_POLL_TERMINATE);
-+ }
-+
-+ while (1) {
-+ if (down_interruptible(&service->remove_event) != 0) {
-+ status = VCHIQ_RETRY;
-+ break;
-+ }
-+
-+ if ((service->srvstate == VCHIQ_SRVSTATE_FREE) ||
-+ (service->srvstate == VCHIQ_SRVSTATE_LISTENING) ||
-+ (service->srvstate == VCHIQ_SRVSTATE_OPEN))
-+ break;
-+
-+ vchiq_log_warning(vchiq_core_log_level,
-+ "%d: close_service:%d - waiting in state %s",
-+ service->state->id, service->localport,
-+ srvstate_names[service->srvstate]);
-+ }
-+
-+ if ((status == VCHIQ_SUCCESS) &&
-+ (service->srvstate != VCHIQ_SRVSTATE_FREE) &&
-+ (service->srvstate != VCHIQ_SRVSTATE_LISTENING))
-+ status = VCHIQ_ERROR;
-+
-+ unlock_service(service);
-+
-+ return status;
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_remove_service(VCHIQ_SERVICE_HANDLE_T handle)
-+{
-+ /* Unregister the service */
-+ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
-+ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
-+
-+ if (!service)
-+ return VCHIQ_ERROR;
-+
-+ vchiq_log_info(vchiq_core_log_level,
-+ "%d: remove_service:%d",
-+ service->state->id, service->localport);
-+
-+ if (service->srvstate == VCHIQ_SRVSTATE_FREE) {
-+ unlock_service(service);
-+ return VCHIQ_ERROR;
-+ }
-+
-+ mark_service_closing(service);
-+
-+ if ((service->srvstate == VCHIQ_SRVSTATE_HIDDEN) ||
-+ (current == service->state->slot_handler_thread)) {
-+ /* Make it look like a client, because it must be removed and
-+ not left in the LISTENING state. */
-+ service->public_fourcc = VCHIQ_FOURCC_INVALID;
-+
-+ status = vchiq_close_service_internal(service,
-+ 0/*!close_recvd*/);
-+ BUG_ON(status == VCHIQ_RETRY);
-+ } else {
-+ /* Mark the service for removal by the slot handler */
-+ request_poll(service->state, service, VCHIQ_POLL_REMOVE);
-+ }
-+ while (1) {
-+ if (down_interruptible(&service->remove_event) != 0) {
-+ status = VCHIQ_RETRY;
-+ break;
-+ }
-+
-+ if ((service->srvstate == VCHIQ_SRVSTATE_FREE) ||
-+ (service->srvstate == VCHIQ_SRVSTATE_OPEN))
-+ break;
-+
-+ vchiq_log_warning(vchiq_core_log_level,
-+ "%d: remove_service:%d - waiting in state %s",
-+ service->state->id, service->localport,
-+ srvstate_names[service->srvstate]);
-+ }
-+
-+ if ((status == VCHIQ_SUCCESS) &&
-+ (service->srvstate != VCHIQ_SRVSTATE_FREE))
-+ status = VCHIQ_ERROR;
-+
-+ unlock_service(service);
-+
-+ return status;
-+}
-+
-+
-+/* This function may be called by kernel threads or user threads.
-+ * User threads may receive VCHIQ_RETRY to indicate that a signal has been
-+ * received and the call should be retried after being returned to user
-+ * context.
-+ * When called in blocking mode, the userdata field points to a bulk_waiter
-+ * structure.
-+ */
-+VCHIQ_STATUS_T
-+vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle,
-+ VCHI_MEM_HANDLE_T memhandle, void *offset, int size, void *userdata,
-+ VCHIQ_BULK_MODE_T mode, VCHIQ_BULK_DIR_T dir)
-+{
-+ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
-+ VCHIQ_BULK_QUEUE_T *queue;
-+ VCHIQ_BULK_T *bulk;
-+ VCHIQ_STATE_T *state;
-+ struct bulk_waiter *bulk_waiter = NULL;
-+ const char dir_char = (dir == VCHIQ_BULK_TRANSMIT) ? 't' : 'r';
-+ const int dir_msgtype = (dir == VCHIQ_BULK_TRANSMIT) ?
-+ VCHIQ_MSG_BULK_TX : VCHIQ_MSG_BULK_RX;
-+ VCHIQ_STATUS_T status = VCHIQ_ERROR;
-+
-+ if (!service ||
-+ (service->srvstate != VCHIQ_SRVSTATE_OPEN) ||
-+ ((memhandle == VCHI_MEM_HANDLE_INVALID) && (offset == NULL)) ||
-+ (vchiq_check_service(service) != VCHIQ_SUCCESS))
-+ goto error_exit;
-+
-+ switch (mode) {
-+ case VCHIQ_BULK_MODE_NOCALLBACK:
-+ case VCHIQ_BULK_MODE_CALLBACK:
-+ break;
-+ case VCHIQ_BULK_MODE_BLOCKING:
-+ bulk_waiter = (struct bulk_waiter *)userdata;
-+ sema_init(&bulk_waiter->event, 0);
-+ bulk_waiter->actual = 0;
-+ bulk_waiter->bulk = NULL;
-+ break;
-+ case VCHIQ_BULK_MODE_WAITING:
-+ bulk_waiter = (struct bulk_waiter *)userdata;
-+ bulk = bulk_waiter->bulk;
-+ goto waiting;
-+ default:
-+ goto error_exit;
-+ }
-+
-+ state = service->state;
-+
-+ queue = (dir == VCHIQ_BULK_TRANSMIT) ?
-+ &service->bulk_tx : &service->bulk_rx;
-+
-+ if (mutex_lock_interruptible(&service->bulk_mutex) != 0) {
-+ status = VCHIQ_RETRY;
-+ goto error_exit;
-+ }
-+
-+ if (queue->local_insert == queue->remove + VCHIQ_NUM_SERVICE_BULKS) {
-+ VCHIQ_SERVICE_STATS_INC(service, bulk_stalls);
-+ do {
-+ mutex_unlock(&service->bulk_mutex);
-+ if (down_interruptible(&service->bulk_remove_event)
-+ != 0) {
-+ status = VCHIQ_RETRY;
-+ goto error_exit;
-+ }
-+ if (mutex_lock_interruptible(&service->bulk_mutex)
-+ != 0) {
-+ status = VCHIQ_RETRY;
-+ goto error_exit;
-+ }
-+ } while (queue->local_insert == queue->remove +
-+ VCHIQ_NUM_SERVICE_BULKS);
-+ }
-+
-+ bulk = &queue->bulks[BULK_INDEX(queue->local_insert)];
-+
-+ bulk->mode = mode;
-+ bulk->dir = dir;
-+ bulk->userdata = userdata;
-+ bulk->size = size;
-+ bulk->actual = VCHIQ_BULK_ACTUAL_ABORTED;
-+
-+ if (vchiq_prepare_bulk_data(bulk, memhandle, offset, size, dir) !=
-+ VCHIQ_SUCCESS)
-+ goto unlock_error_exit;
-+
-+ wmb();
-+
-+ vchiq_log_info(vchiq_core_log_level,
-+ "%d: bt (%d->%d) %cx %x@%x %x",
-+ state->id,
-+ service->localport, service->remoteport, dir_char,
-+ size, (unsigned int)bulk->data, (unsigned int)userdata);
-+
-+ /* The slot mutex must be held when the service is being closed, so
-+ claim it here to ensure that isn't happening */
-+ if (mutex_lock_interruptible(&state->slot_mutex) != 0) {
-+ status = VCHIQ_RETRY;
-+ goto cancel_bulk_error_exit;
-+ }
-+
-+ if (service->srvstate != VCHIQ_SRVSTATE_OPEN)
-+ goto unlock_both_error_exit;
-+
-+ if (state->is_master) {
-+ queue->local_insert++;
-+ if (resolve_bulks(service, queue))
-+ request_poll(state, service,
-+ (dir == VCHIQ_BULK_TRANSMIT) ?
-+ VCHIQ_POLL_TXNOTIFY : VCHIQ_POLL_RXNOTIFY);
-+ } else {
-+ int payload[2] = { (int)bulk->data, bulk->size };
-+ VCHIQ_ELEMENT_T element = { payload, sizeof(payload) };
-+
-+ status = queue_message(state, NULL,
-+ VCHIQ_MAKE_MSG(dir_msgtype,
-+ service->localport, service->remoteport),
-+ &element, 1, sizeof(payload),
-+ QMFLAGS_IS_BLOCKING |
-+ QMFLAGS_NO_MUTEX_LOCK |
-+ QMFLAGS_NO_MUTEX_UNLOCK);
-+ if (status != VCHIQ_SUCCESS) {
-+ goto unlock_both_error_exit;
-+ }
-+ queue->local_insert++;
-+ }
-+
-+ mutex_unlock(&state->slot_mutex);
-+ mutex_unlock(&service->bulk_mutex);
-+
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%d: bt:%d %cx li=%x ri=%x p=%x",
-+ state->id,
-+ service->localport, dir_char,
-+ queue->local_insert, queue->remote_insert, queue->process);
-+
-+waiting:
-+ unlock_service(service);
-+
-+ status = VCHIQ_SUCCESS;
-+
-+ if (bulk_waiter) {
-+ bulk_waiter->bulk = bulk;
-+ if (down_interruptible(&bulk_waiter->event) != 0)
-+ status = VCHIQ_RETRY;
-+ else if (bulk_waiter->actual == VCHIQ_BULK_ACTUAL_ABORTED)
-+ status = VCHIQ_ERROR;
-+ }
-+
-+ return status;
-+
-+unlock_both_error_exit:
-+ mutex_unlock(&state->slot_mutex);
-+cancel_bulk_error_exit:
-+ vchiq_complete_bulk(bulk);
-+unlock_error_exit:
-+ mutex_unlock(&service->bulk_mutex);
-+
-+error_exit:
-+ if (service)
-+ unlock_service(service);
-+ return status;
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T handle,
-+ const VCHIQ_ELEMENT_T *elements, unsigned int count)
-+{
-+ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
-+ VCHIQ_STATUS_T status = VCHIQ_ERROR;
-+
-+ unsigned int size = 0;
-+ unsigned int i;
-+
-+ if (!service ||
-+ (vchiq_check_service(service) != VCHIQ_SUCCESS))
-+ goto error_exit;
-+
-+ for (i = 0; i < (unsigned int)count; i++) {
-+ if (elements[i].size) {
-+ if (elements[i].data == NULL) {
-+ VCHIQ_SERVICE_STATS_INC(service, error_count);
-+ goto error_exit;
-+ }
-+ size += elements[i].size;
-+ }
-+ }
-+
-+ if (size > VCHIQ_MAX_MSG_SIZE) {
-+ VCHIQ_SERVICE_STATS_INC(service, error_count);
-+ goto error_exit;
-+ }
-+
-+ switch (service->srvstate) {
-+ case VCHIQ_SRVSTATE_OPEN:
-+ status = queue_message(service->state, service,
-+ VCHIQ_MAKE_MSG(VCHIQ_MSG_DATA,
-+ service->localport,
-+ service->remoteport),
-+ elements, count, size, 1);
-+ break;
-+ case VCHIQ_SRVSTATE_OPENSYNC:
-+ status = queue_message_sync(service->state, service,
-+ VCHIQ_MAKE_MSG(VCHIQ_MSG_DATA,
-+ service->localport,
-+ service->remoteport),
-+ elements, count, size, 1);
-+ break;
-+ default:
-+ status = VCHIQ_ERROR;
-+ break;
-+ }
-+
-+error_exit:
-+ if (service)
-+ unlock_service(service);
-+
-+ return status;
-+}
-+
-+void
-+vchiq_release_message(VCHIQ_SERVICE_HANDLE_T handle, VCHIQ_HEADER_T *header)
-+{
-+ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
-+ VCHIQ_SHARED_STATE_T *remote;
-+ VCHIQ_STATE_T *state;
-+ int slot_index;
-+
-+ if (!service)
-+ return;
-+
-+ state = service->state;
-+ remote = state->remote;
-+
-+ slot_index = SLOT_INDEX_FROM_DATA(state, (void *)header);
-+
-+ if ((slot_index >= remote->slot_first) &&
-+ (slot_index <= remote->slot_last)) {
-+ int msgid = header->msgid;
-+ if (msgid & VCHIQ_MSGID_CLAIMED) {
-+ VCHIQ_SLOT_INFO_T *slot_info =
-+ SLOT_INFO_FROM_INDEX(state, slot_index);
-+
-+ release_slot(state, slot_info, header, service);
-+ }
-+ } else if (slot_index == remote->slot_sync)
-+ release_message_sync(state, header);
-+
-+ unlock_service(service);
-+}
-+
-+static void
-+release_message_sync(VCHIQ_STATE_T *state, VCHIQ_HEADER_T *header)
-+{
-+ header->msgid = VCHIQ_MSGID_PADDING;
-+ wmb();
-+ remote_event_signal(&state->remote->sync_release);
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_get_peer_version(VCHIQ_SERVICE_HANDLE_T handle, short *peer_version)
-+{
-+ VCHIQ_STATUS_T status = VCHIQ_ERROR;
-+ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
-+
-+ if (!service ||
-+ (vchiq_check_service(service) != VCHIQ_SUCCESS) ||
-+ !peer_version)
-+ goto exit;
-+ *peer_version = service->peer_version;
-+ status = VCHIQ_SUCCESS;
-+
-+exit:
-+ if (service)
-+ unlock_service(service);
-+ return status;
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_get_config(VCHIQ_INSTANCE_T instance,
-+ int config_size, VCHIQ_CONFIG_T *pconfig)
-+{
-+ VCHIQ_CONFIG_T config;
-+
-+ (void)instance;
-+
-+ config.max_msg_size = VCHIQ_MAX_MSG_SIZE;
-+ config.bulk_threshold = VCHIQ_MAX_MSG_SIZE;
-+ config.max_outstanding_bulks = VCHIQ_NUM_SERVICE_BULKS;
-+ config.max_services = VCHIQ_MAX_SERVICES;
-+ config.version = VCHIQ_VERSION;
-+ config.version_min = VCHIQ_VERSION_MIN;
-+
-+ if (config_size > sizeof(VCHIQ_CONFIG_T))
-+ return VCHIQ_ERROR;
-+
-+ memcpy(pconfig, &config,
-+ min(config_size, (int)(sizeof(VCHIQ_CONFIG_T))));
-+
-+ return VCHIQ_SUCCESS;
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_set_service_option(VCHIQ_SERVICE_HANDLE_T handle,
-+ VCHIQ_SERVICE_OPTION_T option, int value)
-+{
-+ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
-+ VCHIQ_STATUS_T status = VCHIQ_ERROR;
-+
-+ if (service) {
-+ switch (option) {
-+ case VCHIQ_SERVICE_OPTION_AUTOCLOSE:
-+ service->auto_close = value;
-+ status = VCHIQ_SUCCESS;
-+ break;
-+
-+ case VCHIQ_SERVICE_OPTION_SLOT_QUOTA: {
-+ VCHIQ_SERVICE_QUOTA_T *service_quota =
-+ &service->state->service_quotas[
-+ service->localport];
-+ if (value == 0)
-+ value = service->state->default_slot_quota;
-+ if ((value >= service_quota->slot_use_count) &&
-+ (value < (unsigned short)~0)) {
-+ service_quota->slot_quota = value;
-+ if ((value >= service_quota->slot_use_count) &&
-+ (service_quota->message_quota >=
-+ service_quota->message_use_count)) {
-+ /* Signal the service that it may have
-+ ** dropped below its quota */
-+ up(&service_quota->quota_event);
-+ }
-+ status = VCHIQ_SUCCESS;
-+ }
-+ } break;
-+
-+ case VCHIQ_SERVICE_OPTION_MESSAGE_QUOTA: {
-+ VCHIQ_SERVICE_QUOTA_T *service_quota =
-+ &service->state->service_quotas[
-+ service->localport];
-+ if (value == 0)
-+ value = service->state->default_message_quota;
-+ if ((value >= service_quota->message_use_count) &&
-+ (value < (unsigned short)~0)) {
-+ service_quota->message_quota = value;
-+ if ((value >=
-+ service_quota->message_use_count) &&
-+ (service_quota->slot_quota >=
-+ service_quota->slot_use_count))
-+ /* Signal the service that it may have
-+ ** dropped below its quota */
-+ up(&service_quota->quota_event);
-+ status = VCHIQ_SUCCESS;
-+ }
-+ } break;
-+
-+ case VCHIQ_SERVICE_OPTION_SYNCHRONOUS:
-+ if ((service->srvstate == VCHIQ_SRVSTATE_HIDDEN) ||
-+ (service->srvstate ==
-+ VCHIQ_SRVSTATE_LISTENING)) {
-+ service->sync = value;
-+ status = VCHIQ_SUCCESS;
-+ }
-+ break;
-+
-+ case VCHIQ_SERVICE_OPTION_TRACE:
-+ service->trace = value;
-+ status = VCHIQ_SUCCESS;
-+ break;
-+
-+ default:
-+ break;
-+ }
-+ unlock_service(service);
-+ }
-+
-+ return status;
-+}
-+
-+void
-+vchiq_dump_shared_state(void *dump_context, VCHIQ_STATE_T *state,
-+ VCHIQ_SHARED_STATE_T *shared, const char *label)
-+{
-+ static const char *const debug_names[] = {
-+ "<entries>",
-+ "SLOT_HANDLER_COUNT",
-+ "SLOT_HANDLER_LINE",
-+ "PARSE_LINE",
-+ "PARSE_HEADER",
-+ "PARSE_MSGID",
-+ "AWAIT_COMPLETION_LINE",
-+ "DEQUEUE_MESSAGE_LINE",
-+ "SERVICE_CALLBACK_LINE",
-+ "MSG_QUEUE_FULL_COUNT",
-+ "COMPLETION_QUEUE_FULL_COUNT"
-+ };
-+ int i;
-+
-+ char buf[80];
-+ int len;
-+ len = snprintf(buf, sizeof(buf),
-+ " %s: slots %d-%d tx_pos=%x recycle=%x",
-+ label, shared->slot_first, shared->slot_last,
-+ shared->tx_pos, shared->slot_queue_recycle);
-+ vchiq_dump(dump_context, buf, len + 1);
-+
-+ len = snprintf(buf, sizeof(buf),
-+ " Slots claimed:");
-+ vchiq_dump(dump_context, buf, len + 1);
-+
-+ for (i = shared->slot_first; i <= shared->slot_last; i++) {
-+ VCHIQ_SLOT_INFO_T slot_info = *SLOT_INFO_FROM_INDEX(state, i);
-+ if (slot_info.use_count != slot_info.release_count) {
-+ len = snprintf(buf, sizeof(buf),
-+ " %d: %d/%d", i, slot_info.use_count,
-+ slot_info.release_count);
-+ vchiq_dump(dump_context, buf, len + 1);
-+ }
-+ }
-+
-+ for (i = 1; i < shared->debug[DEBUG_ENTRIES]; i++) {
-+ len = snprintf(buf, sizeof(buf), " DEBUG: %s = %d(%x)",
-+ debug_names[i], shared->debug[i], shared->debug[i]);
-+ vchiq_dump(dump_context, buf, len + 1);
-+ }
-+}
-+
-+void
-+vchiq_dump_state(void *dump_context, VCHIQ_STATE_T *state)
-+{
-+ char buf[80];
-+ int len;
-+ int i;
-+
-+ len = snprintf(buf, sizeof(buf), "State %d: %s", state->id,
-+ conn_state_names[state->conn_state]);
-+ vchiq_dump(dump_context, buf, len + 1);
-+
-+ len = snprintf(buf, sizeof(buf),
-+ " tx_pos=%x(@%x), rx_pos=%x(@%x)",
-+ state->local->tx_pos,
-+ (uint32_t)state->tx_data +
-+ (state->local_tx_pos & VCHIQ_SLOT_MASK),
-+ state->rx_pos,
-+ (uint32_t)state->rx_data +
-+ (state->rx_pos & VCHIQ_SLOT_MASK));
-+ vchiq_dump(dump_context, buf, len + 1);
-+
-+ len = snprintf(buf, sizeof(buf),
-+ " Version: %d (min %d)",
-+ VCHIQ_VERSION, VCHIQ_VERSION_MIN);
-+ vchiq_dump(dump_context, buf, len + 1);
-+
-+ if (VCHIQ_ENABLE_STATS) {
-+ len = snprintf(buf, sizeof(buf),
-+ " Stats: ctrl_tx_count=%d, ctrl_rx_count=%d, "
-+ "error_count=%d",
-+ state->stats.ctrl_tx_count, state->stats.ctrl_rx_count,
-+ state->stats.error_count);
-+ vchiq_dump(dump_context, buf, len + 1);
-+ }
-+
-+ len = snprintf(buf, sizeof(buf),
-+ " Slots: %d available (%d data), %d recyclable, %d stalls "
-+ "(%d data)",
-+ ((state->slot_queue_available * VCHIQ_SLOT_SIZE) -
-+ state->local_tx_pos) / VCHIQ_SLOT_SIZE,
-+ state->data_quota - state->data_use_count,
-+ state->local->slot_queue_recycle - state->slot_queue_available,
-+ state->stats.slot_stalls, state->stats.data_stalls);
-+ vchiq_dump(dump_context, buf, len + 1);
-+
-+ vchiq_dump_platform_state(dump_context);
-+
-+ vchiq_dump_shared_state(dump_context, state, state->local, "Local");
-+ vchiq_dump_shared_state(dump_context, state, state->remote, "Remote");
-+
-+ vchiq_dump_platform_instances(dump_context);
-+
-+ for (i = 0; i < state->unused_service; i++) {
-+ VCHIQ_SERVICE_T *service = find_service_by_port(state, i);
-+
-+ if (service) {
-+ vchiq_dump_service_state(dump_context, service);
-+ unlock_service(service);
-+ }
-+ }
-+}
-+
-+void
-+vchiq_dump_service_state(void *dump_context, VCHIQ_SERVICE_T *service)
-+{
-+ char buf[80];
-+ int len;
-+
-+ len = snprintf(buf, sizeof(buf), "Service %d: %s (ref %u)",
-+ service->localport, srvstate_names[service->srvstate],
-+ service->ref_count - 1); /*Don't include the lock just taken*/
-+
-+ if (service->srvstate != VCHIQ_SRVSTATE_FREE) {
-+ char remoteport[30];
-+ VCHIQ_SERVICE_QUOTA_T *service_quota =
-+ &service->state->service_quotas[service->localport];
-+ int fourcc = service->base.fourcc;
-+ int tx_pending, rx_pending;
-+ if (service->remoteport != VCHIQ_PORT_FREE) {
-+ int len2 = snprintf(remoteport, sizeof(remoteport),
-+ "%d", service->remoteport);
-+ if (service->public_fourcc != VCHIQ_FOURCC_INVALID)
-+ snprintf(remoteport + len2,
-+ sizeof(remoteport) - len2,
-+ " (client %x)", service->client_id);
-+ } else
-+ strcpy(remoteport, "n/a");
-+
-+ len += snprintf(buf + len, sizeof(buf) - len,
-+ " '%c%c%c%c' remote %s (msg use %d/%d, slot use %d/%d)",
-+ VCHIQ_FOURCC_AS_4CHARS(fourcc),
-+ remoteport,
-+ service_quota->message_use_count,
-+ service_quota->message_quota,
-+ service_quota->slot_use_count,
-+ service_quota->slot_quota);
-+
-+ vchiq_dump(dump_context, buf, len + 1);
-+
-+ tx_pending = service->bulk_tx.local_insert -
-+ service->bulk_tx.remote_insert;
-+
-+ rx_pending = service->bulk_rx.local_insert -
-+ service->bulk_rx.remote_insert;
-+
-+ len = snprintf(buf, sizeof(buf),
-+ " Bulk: tx_pending=%d (size %d),"
-+ " rx_pending=%d (size %d)",
-+ tx_pending,
-+ tx_pending ? service->bulk_tx.bulks[
-+ BULK_INDEX(service->bulk_tx.remove)].size : 0,
-+ rx_pending,
-+ rx_pending ? service->bulk_rx.bulks[
-+ BULK_INDEX(service->bulk_rx.remove)].size : 0);
-+
-+ if (VCHIQ_ENABLE_STATS) {
-+ vchiq_dump(dump_context, buf, len + 1);
-+
-+ len = snprintf(buf, sizeof(buf),
-+ " Ctrl: tx_count=%d, tx_bytes=%llu, "
-+ "rx_count=%d, rx_bytes=%llu",
-+ service->stats.ctrl_tx_count,
-+ service->stats.ctrl_tx_bytes,
-+ service->stats.ctrl_rx_count,
-+ service->stats.ctrl_rx_bytes);
-+ vchiq_dump(dump_context, buf, len + 1);
-+
-+ len = snprintf(buf, sizeof(buf),
-+ " Bulk: tx_count=%d, tx_bytes=%llu, "
-+ "rx_count=%d, rx_bytes=%llu",
-+ service->stats.bulk_tx_count,
-+ service->stats.bulk_tx_bytes,
-+ service->stats.bulk_rx_count,
-+ service->stats.bulk_rx_bytes);
-+ vchiq_dump(dump_context, buf, len + 1);
-+
-+ len = snprintf(buf, sizeof(buf),
-+ " %d quota stalls, %d slot stalls, "
-+ "%d bulk stalls, %d aborted, %d errors",
-+ service->stats.quota_stalls,
-+ service->stats.slot_stalls,
-+ service->stats.bulk_stalls,
-+ service->stats.bulk_aborted_count,
-+ service->stats.error_count);
-+ }
-+ }
-+
-+ vchiq_dump(dump_context, buf, len + 1);
-+
-+ if (service->srvstate != VCHIQ_SRVSTATE_FREE)
-+ vchiq_dump_platform_service_state(dump_context, service);
-+}
-+
-+
-+void
-+vchiq_loud_error_header(void)
-+{
-+ vchiq_log_error(vchiq_core_log_level,
-+ "============================================================"
-+ "================");
-+ vchiq_log_error(vchiq_core_log_level,
-+ "============================================================"
-+ "================");
-+ vchiq_log_error(vchiq_core_log_level, "=====");
-+}
-+
-+void
-+vchiq_loud_error_footer(void)
-+{
-+ vchiq_log_error(vchiq_core_log_level, "=====");
-+ vchiq_log_error(vchiq_core_log_level,
-+ "============================================================"
-+ "================");
-+ vchiq_log_error(vchiq_core_log_level,
-+ "============================================================"
-+ "================");
-+}
-+
-+
-+VCHIQ_STATUS_T vchiq_send_remote_use(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_STATUS_T status = VCHIQ_RETRY;
-+ if (state->conn_state != VCHIQ_CONNSTATE_DISCONNECTED)
-+ status = queue_message(state, NULL,
-+ VCHIQ_MAKE_MSG(VCHIQ_MSG_REMOTE_USE, 0, 0),
-+ NULL, 0, 0, 0);
-+ return status;
-+}
-+
-+VCHIQ_STATUS_T vchiq_send_remote_release(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_STATUS_T status = VCHIQ_RETRY;
-+ if (state->conn_state != VCHIQ_CONNSTATE_DISCONNECTED)
-+ status = queue_message(state, NULL,
-+ VCHIQ_MAKE_MSG(VCHIQ_MSG_REMOTE_RELEASE, 0, 0),
-+ NULL, 0, 0, 0);
-+ return status;
-+}
-+
-+VCHIQ_STATUS_T vchiq_send_remote_use_active(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_STATUS_T status = VCHIQ_RETRY;
-+ if (state->conn_state != VCHIQ_CONNSTATE_DISCONNECTED)
-+ status = queue_message(state, NULL,
-+ VCHIQ_MAKE_MSG(VCHIQ_MSG_REMOTE_USE_ACTIVE, 0, 0),
-+ NULL, 0, 0, 0);
-+ return status;
-+}
-+
-+void vchiq_log_dump_mem(const char *label, uint32_t addr, const void *voidMem,
-+ size_t numBytes)
-+{
-+ const uint8_t *mem = (const uint8_t *)voidMem;
-+ size_t offset;
-+ char lineBuf[100];
-+ char *s;
-+
-+ while (numBytes > 0) {
-+ s = lineBuf;
-+
-+ for (offset = 0; offset < 16; offset++) {
-+ if (offset < numBytes)
-+ s += snprintf(s, 4, "%02x ", mem[offset]);
-+ else
-+ s += snprintf(s, 4, " ");
-+ }
-+
-+ for (offset = 0; offset < 16; offset++) {
-+ if (offset < numBytes) {
-+ uint8_t ch = mem[offset];
-+
-+ if ((ch < ' ') || (ch > '~'))
-+ ch = '.';
-+ *s++ = (char)ch;
-+ }
-+ }
-+ *s++ = '\0';
-+
-+ if ((label != NULL) && (*label != '\0'))
-+ vchiq_log_trace(VCHIQ_LOG_TRACE,
-+ "%s: %08x: %s", label, addr, lineBuf);
-+ else
-+ vchiq_log_trace(VCHIQ_LOG_TRACE,
-+ "%08x: %s", addr, lineBuf);
-+
-+ addr += 16;
-+ mem += 16;
-+ if (numBytes > 16)
-+ numBytes -= 16;
-+ else
-+ numBytes = 0;
-+ }
-+}
---- /dev/null
-+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.h
-@@ -0,0 +1,712 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHIQ_CORE_H
-+#define VCHIQ_CORE_H
-+
-+#include <linux/mutex.h>
-+#include <linux/semaphore.h>
-+#include <linux/kthread.h>
-+
-+#include "vchiq_cfg.h"
-+
-+#include "vchiq.h"
-+
-+/* Run time control of log level, based on KERN_XXX level. */
-+#define VCHIQ_LOG_DEFAULT 4
-+#define VCHIQ_LOG_ERROR 3
-+#define VCHIQ_LOG_WARNING 4
-+#define VCHIQ_LOG_INFO 6
-+#define VCHIQ_LOG_TRACE 7
-+
-+#define VCHIQ_LOG_PREFIX KERN_INFO "vchiq: "
-+
-+#ifndef vchiq_log_error
-+#define vchiq_log_error(cat, fmt, ...) \
-+ do { if (cat >= VCHIQ_LOG_ERROR) \
-+ printk(VCHIQ_LOG_PREFIX fmt "\n", ##__VA_ARGS__); } while (0)
-+#endif
-+#ifndef vchiq_log_warning
-+#define vchiq_log_warning(cat, fmt, ...) \
-+ do { if (cat >= VCHIQ_LOG_WARNING) \
-+ printk(VCHIQ_LOG_PREFIX fmt "\n", ##__VA_ARGS__); } while (0)
-+#endif
-+#ifndef vchiq_log_info
-+#define vchiq_log_info(cat, fmt, ...) \
-+ do { if (cat >= VCHIQ_LOG_INFO) \
-+ printk(VCHIQ_LOG_PREFIX fmt "\n", ##__VA_ARGS__); } while (0)
-+#endif
-+#ifndef vchiq_log_trace
-+#define vchiq_log_trace(cat, fmt, ...) \
-+ do { if (cat >= VCHIQ_LOG_TRACE) \
-+ printk(VCHIQ_LOG_PREFIX fmt "\n", ##__VA_ARGS__); } while (0)
-+#endif
-+
-+#define vchiq_loud_error(...) \
-+ vchiq_log_error(vchiq_core_log_level, "===== " __VA_ARGS__)
-+
-+#ifndef vchiq_static_assert
-+#define vchiq_static_assert(cond) __attribute__((unused)) \
-+ extern int vchiq_static_assert[(cond) ? 1 : -1]
-+#endif
-+
-+#define IS_POW2(x) (x && ((x & (x - 1)) == 0))
-+
-+/* Ensure that the slot size and maximum number of slots are powers of 2 */
-+vchiq_static_assert(IS_POW2(VCHIQ_SLOT_SIZE));
-+vchiq_static_assert(IS_POW2(VCHIQ_MAX_SLOTS));
-+vchiq_static_assert(IS_POW2(VCHIQ_MAX_SLOTS_PER_SIDE));
-+
-+#define VCHIQ_SLOT_MASK (VCHIQ_SLOT_SIZE - 1)
-+#define VCHIQ_SLOT_QUEUE_MASK (VCHIQ_MAX_SLOTS_PER_SIDE - 1)
-+#define VCHIQ_SLOT_ZERO_SLOTS ((sizeof(VCHIQ_SLOT_ZERO_T) + \
-+ VCHIQ_SLOT_SIZE - 1) / VCHIQ_SLOT_SIZE)
-+
-+#define VCHIQ_MSG_PADDING 0 /* - */
-+#define VCHIQ_MSG_CONNECT 1 /* - */
-+#define VCHIQ_MSG_OPEN 2 /* + (srcport, -), fourcc, client_id */
-+#define VCHIQ_MSG_OPENACK 3 /* + (srcport, dstport) */
-+#define VCHIQ_MSG_CLOSE 4 /* + (srcport, dstport) */
-+#define VCHIQ_MSG_DATA 5 /* + (srcport, dstport) */
-+#define VCHIQ_MSG_BULK_RX 6 /* + (srcport, dstport), data, size */
-+#define VCHIQ_MSG_BULK_TX 7 /* + (srcport, dstport), data, size */
-+#define VCHIQ_MSG_BULK_RX_DONE 8 /* + (srcport, dstport), actual */
-+#define VCHIQ_MSG_BULK_TX_DONE 9 /* + (srcport, dstport), actual */
-+#define VCHIQ_MSG_PAUSE 10 /* - */
-+#define VCHIQ_MSG_RESUME 11 /* - */
-+#define VCHIQ_MSG_REMOTE_USE 12 /* - */
-+#define VCHIQ_MSG_REMOTE_RELEASE 13 /* - */
-+#define VCHIQ_MSG_REMOTE_USE_ACTIVE 14 /* - */
-+
-+#define VCHIQ_PORT_MAX (VCHIQ_MAX_SERVICES - 1)
-+#define VCHIQ_PORT_FREE 0x1000
-+#define VCHIQ_PORT_IS_VALID(port) (port < VCHIQ_PORT_FREE)
-+#define VCHIQ_MAKE_MSG(type, srcport, dstport) \
-+ ((type<<24) | (srcport<<12) | (dstport<<0))
-+#define VCHIQ_MSG_TYPE(msgid) ((unsigned int)msgid >> 24)
-+#define VCHIQ_MSG_SRCPORT(msgid) \
-+ (unsigned short)(((unsigned int)msgid >> 12) & 0xfff)
-+#define VCHIQ_MSG_DSTPORT(msgid) \
-+ ((unsigned short)msgid & 0xfff)
-+
-+#define VCHIQ_FOURCC_AS_4CHARS(fourcc) \
-+ ((fourcc) >> 24) & 0xff, \
-+ ((fourcc) >> 16) & 0xff, \
-+ ((fourcc) >> 8) & 0xff, \
-+ (fourcc) & 0xff
-+
-+/* Ensure the fields are wide enough */
-+vchiq_static_assert(VCHIQ_MSG_SRCPORT(VCHIQ_MAKE_MSG(0, 0, VCHIQ_PORT_MAX))
-+ == 0);
-+vchiq_static_assert(VCHIQ_MSG_TYPE(VCHIQ_MAKE_MSG(0, VCHIQ_PORT_MAX, 0)) == 0);
-+vchiq_static_assert((unsigned int)VCHIQ_PORT_MAX <
-+ (unsigned int)VCHIQ_PORT_FREE);
-+
-+#define VCHIQ_MSGID_PADDING VCHIQ_MAKE_MSG(VCHIQ_MSG_PADDING, 0, 0)
-+#define VCHIQ_MSGID_CLAIMED 0x40000000
-+
-+#define VCHIQ_FOURCC_INVALID 0x00000000
-+#define VCHIQ_FOURCC_IS_LEGAL(fourcc) (fourcc != VCHIQ_FOURCC_INVALID)
-+
-+#define VCHIQ_BULK_ACTUAL_ABORTED -1
-+
-+typedef uint32_t BITSET_T;
-+
-+vchiq_static_assert((sizeof(BITSET_T) * 8) == 32);
-+
-+#define BITSET_SIZE(b) ((b + 31) >> 5)
-+#define BITSET_WORD(b) (b >> 5)
-+#define BITSET_BIT(b) (1 << (b & 31))
-+#define BITSET_ZERO(bs) memset(bs, 0, sizeof(bs))
-+#define BITSET_IS_SET(bs, b) (bs[BITSET_WORD(b)] & BITSET_BIT(b))
-+#define BITSET_SET(bs, b) (bs[BITSET_WORD(b)] |= BITSET_BIT(b))
-+#define BITSET_CLR(bs, b) (bs[BITSET_WORD(b)] &= ~BITSET_BIT(b))
-+
-+#if VCHIQ_ENABLE_STATS
-+#define VCHIQ_STATS_INC(state, stat) (state->stats. stat++)
-+#define VCHIQ_SERVICE_STATS_INC(service, stat) (service->stats. stat++)
-+#define VCHIQ_SERVICE_STATS_ADD(service, stat, addend) \
-+ (service->stats. stat += addend)
-+#else
-+#define VCHIQ_STATS_INC(state, stat) ((void)0)
-+#define VCHIQ_SERVICE_STATS_INC(service, stat) ((void)0)
-+#define VCHIQ_SERVICE_STATS_ADD(service, stat, addend) ((void)0)
-+#endif
-+
-+enum {
-+ DEBUG_ENTRIES,
-+#if VCHIQ_ENABLE_DEBUG
-+ DEBUG_SLOT_HANDLER_COUNT,
-+ DEBUG_SLOT_HANDLER_LINE,
-+ DEBUG_PARSE_LINE,
-+ DEBUG_PARSE_HEADER,
-+ DEBUG_PARSE_MSGID,
-+ DEBUG_AWAIT_COMPLETION_LINE,
-+ DEBUG_DEQUEUE_MESSAGE_LINE,
-+ DEBUG_SERVICE_CALLBACK_LINE,
-+ DEBUG_MSG_QUEUE_FULL_COUNT,
-+ DEBUG_COMPLETION_QUEUE_FULL_COUNT,
-+#endif
-+ DEBUG_MAX
-+};
-+
-+#if VCHIQ_ENABLE_DEBUG
-+
-+#define DEBUG_INITIALISE(local) int *debug_ptr = (local)->debug;
-+#define DEBUG_TRACE(d) \
-+ do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(); } while (0)
-+#define DEBUG_VALUE(d, v) \
-+ do { debug_ptr[DEBUG_ ## d] = (v); dsb(); } while (0)
-+#define DEBUG_COUNT(d) \
-+ do { debug_ptr[DEBUG_ ## d]++; dsb(); } while (0)
-+
-+#else /* VCHIQ_ENABLE_DEBUG */
-+
-+#define DEBUG_INITIALISE(local)
-+#define DEBUG_TRACE(d)
-+#define DEBUG_VALUE(d, v)
-+#define DEBUG_COUNT(d)
-+
-+#endif /* VCHIQ_ENABLE_DEBUG */
-+
-+typedef enum {
-+ VCHIQ_CONNSTATE_DISCONNECTED,
-+ VCHIQ_CONNSTATE_CONNECTING,
-+ VCHIQ_CONNSTATE_CONNECTED,
-+ VCHIQ_CONNSTATE_PAUSING,
-+ VCHIQ_CONNSTATE_PAUSE_SENT,
-+ VCHIQ_CONNSTATE_PAUSED,
-+ VCHIQ_CONNSTATE_RESUMING,
-+ VCHIQ_CONNSTATE_PAUSE_TIMEOUT,
-+ VCHIQ_CONNSTATE_RESUME_TIMEOUT
-+} VCHIQ_CONNSTATE_T;
-+
-+enum {
-+ VCHIQ_SRVSTATE_FREE,
-+ VCHIQ_SRVSTATE_HIDDEN,
-+ VCHIQ_SRVSTATE_LISTENING,
-+ VCHIQ_SRVSTATE_OPENING,
-+ VCHIQ_SRVSTATE_OPEN,
-+ VCHIQ_SRVSTATE_OPENSYNC,
-+ VCHIQ_SRVSTATE_CLOSESENT,
-+ VCHIQ_SRVSTATE_CLOSERECVD,
-+ VCHIQ_SRVSTATE_CLOSEWAIT,
-+ VCHIQ_SRVSTATE_CLOSED
-+};
-+
-+enum {
-+ VCHIQ_POLL_TERMINATE,
-+ VCHIQ_POLL_REMOVE,
-+ VCHIQ_POLL_TXNOTIFY,
-+ VCHIQ_POLL_RXNOTIFY,
-+ VCHIQ_POLL_COUNT
-+};
-+
-+typedef enum {
-+ VCHIQ_BULK_TRANSMIT,
-+ VCHIQ_BULK_RECEIVE
-+} VCHIQ_BULK_DIR_T;
-+
-+typedef void (*VCHIQ_USERDATA_TERM_T)(void *userdata);
-+
-+typedef struct vchiq_bulk_struct {
-+ short mode;
-+ short dir;
-+ void *userdata;
-+ VCHI_MEM_HANDLE_T handle;
-+ void *data;
-+ int size;
-+ void *remote_data;
-+ int remote_size;
-+ int actual;
-+} VCHIQ_BULK_T;
-+
-+typedef struct vchiq_bulk_queue_struct {
-+ int local_insert; /* Where to insert the next local bulk */
-+ int remote_insert; /* Where to insert the next remote bulk (master) */
-+ int process; /* Bulk to transfer next */
-+ int remote_notify; /* Bulk to notify the remote client of next (mstr) */
-+ int remove; /* Bulk to notify the local client of, and remove,
-+ ** next */
-+ VCHIQ_BULK_T bulks[VCHIQ_NUM_SERVICE_BULKS];
-+} VCHIQ_BULK_QUEUE_T;
-+
-+typedef struct remote_event_struct {
-+ int armed;
-+ int fired;
-+ struct semaphore *event;
-+} REMOTE_EVENT_T;
-+
-+typedef struct opaque_platform_state_t *VCHIQ_PLATFORM_STATE_T;
-+
-+typedef struct vchiq_state_struct VCHIQ_STATE_T;
-+
-+typedef struct vchiq_slot_struct {
-+ char data[VCHIQ_SLOT_SIZE];
-+} VCHIQ_SLOT_T;
-+
-+typedef struct vchiq_slot_info_struct {
-+ /* Use two counters rather than one to avoid the need for a mutex. */
-+ short use_count;
-+ short release_count;
-+} VCHIQ_SLOT_INFO_T;
-+
-+typedef struct vchiq_service_struct {
-+ VCHIQ_SERVICE_BASE_T base;
-+ VCHIQ_SERVICE_HANDLE_T handle;
-+ unsigned int ref_count;
-+ int srvstate;
-+ VCHIQ_USERDATA_TERM_T userdata_term;
-+ unsigned int localport;
-+ unsigned int remoteport;
-+ int public_fourcc;
-+ int client_id;
-+ char auto_close;
-+ char sync;
-+ char closing;
-+ char trace;
-+ atomic_t poll_flags;
-+ short version;
-+ short version_min;
-+ short peer_version;
-+
-+ VCHIQ_STATE_T *state;
-+ VCHIQ_INSTANCE_T instance;
-+
-+ int service_use_count;
-+
-+ VCHIQ_BULK_QUEUE_T bulk_tx;
-+ VCHIQ_BULK_QUEUE_T bulk_rx;
-+
-+ struct semaphore remove_event;
-+ struct semaphore bulk_remove_event;
-+ struct mutex bulk_mutex;
-+
-+ struct service_stats_struct {
-+ int quota_stalls;
-+ int slot_stalls;
-+ int bulk_stalls;
-+ int error_count;
-+ int ctrl_tx_count;
-+ int ctrl_rx_count;
-+ int bulk_tx_count;
-+ int bulk_rx_count;
-+ int bulk_aborted_count;
-+ uint64_t ctrl_tx_bytes;
-+ uint64_t ctrl_rx_bytes;
-+ uint64_t bulk_tx_bytes;
-+ uint64_t bulk_rx_bytes;
-+ } stats;
-+} VCHIQ_SERVICE_T;
-+
-+/* The quota information is outside VCHIQ_SERVICE_T so that it can be
-+ statically allocated, since for accounting reasons a service's slot
-+ usage is carried over between users of the same port number.
-+ */
-+typedef struct vchiq_service_quota_struct {
-+ unsigned short slot_quota;
-+ unsigned short slot_use_count;
-+ unsigned short message_quota;
-+ unsigned short message_use_count;
-+ struct semaphore quota_event;
-+ int previous_tx_index;
-+} VCHIQ_SERVICE_QUOTA_T;
-+
-+typedef struct vchiq_shared_state_struct {
-+
-+ /* A non-zero value here indicates that the content is valid. */
-+ int initialised;
-+
-+ /* The first and last (inclusive) slots allocated to the owner. */
-+ int slot_first;
-+ int slot_last;
-+
-+ /* The slot allocated to synchronous messages from the owner. */
-+ int slot_sync;
-+
-+ /* Signalling this event indicates that owner's slot handler thread
-+ ** should run. */
-+ REMOTE_EVENT_T trigger;
-+
-+ /* Indicates the byte position within the stream where the next message
-+ ** will be written. The least significant bits are an index into the
-+ ** slot. The next bits are the index of the slot in slot_queue. */
-+ int tx_pos;
-+
-+ /* This event should be signalled when a slot is recycled. */
-+ REMOTE_EVENT_T recycle;
-+
-+ /* The slot_queue index where the next recycled slot will be written. */
-+ int slot_queue_recycle;
-+
-+ /* This event should be signalled when a synchronous message is sent. */
-+ REMOTE_EVENT_T sync_trigger;
-+
-+ /* This event should be signalled when a synchronous message has been
-+ ** released. */
-+ REMOTE_EVENT_T sync_release;
-+
-+ /* A circular buffer of slot indexes. */
-+ int slot_queue[VCHIQ_MAX_SLOTS_PER_SIDE];
-+
-+ /* Debugging state */
-+ int debug[DEBUG_MAX];
-+} VCHIQ_SHARED_STATE_T;
-+
-+typedef struct vchiq_slot_zero_struct {
-+ int magic;
-+ short version;
-+ short version_min;
-+ int slot_zero_size;
-+ int slot_size;
-+ int max_slots;
-+ int max_slots_per_side;
-+ int platform_data[2];
-+ VCHIQ_SHARED_STATE_T master;
-+ VCHIQ_SHARED_STATE_T slave;
-+ VCHIQ_SLOT_INFO_T slots[VCHIQ_MAX_SLOTS];
-+} VCHIQ_SLOT_ZERO_T;
-+
-+struct vchiq_state_struct {
-+ int id;
-+ int initialised;
-+ VCHIQ_CONNSTATE_T conn_state;
-+ int is_master;
-+ short version_common;
-+
-+ VCHIQ_SHARED_STATE_T *local;
-+ VCHIQ_SHARED_STATE_T *remote;
-+ VCHIQ_SLOT_T *slot_data;
-+
-+ unsigned short default_slot_quota;
-+ unsigned short default_message_quota;
-+
-+ /* Event indicating connect message received */
-+ struct semaphore connect;
-+
-+ /* Mutex protecting services */
-+ struct mutex mutex;
-+ VCHIQ_INSTANCE_T *instance;
-+
-+ /* Processes incoming messages */
-+ struct task_struct *slot_handler_thread;
-+
-+ /* Processes recycled slots */
-+ struct task_struct *recycle_thread;
-+
-+ /* Processes synchronous messages */
-+ struct task_struct *sync_thread;
-+
-+ /* Local implementation of the trigger remote event */
-+ struct semaphore trigger_event;
-+
-+ /* Local implementation of the recycle remote event */
-+ struct semaphore recycle_event;
-+
-+ /* Local implementation of the sync trigger remote event */
-+ struct semaphore sync_trigger_event;
-+
-+ /* Local implementation of the sync release remote event */
-+ struct semaphore sync_release_event;
-+
-+ char *tx_data;
-+ char *rx_data;
-+ VCHIQ_SLOT_INFO_T *rx_info;
-+
-+ struct mutex slot_mutex;
-+
-+ struct mutex recycle_mutex;
-+
-+ struct mutex sync_mutex;
-+
-+ struct mutex bulk_transfer_mutex;
-+
-+ /* Indicates the byte position within the stream from where the next
-+ ** message will be read. The least significant bits are an index into
-+ ** the slot.The next bits are the index of the slot in
-+ ** remote->slot_queue. */
-+ int rx_pos;
-+
-+ /* A cached copy of local->tx_pos. Only write to local->tx_pos, and read
-+ from remote->tx_pos. */
-+ int local_tx_pos;
-+
-+ /* The slot_queue index of the slot to become available next. */
-+ int slot_queue_available;
-+
-+ /* A flag to indicate if any poll has been requested */
-+ int poll_needed;
-+
-+ /* Ths index of the previous slot used for data messages. */
-+ int previous_data_index;
-+
-+ /* The number of slots occupied by data messages. */
-+ unsigned short data_use_count;
-+
-+ /* The maximum number of slots to be occupied by data messages. */
-+ unsigned short data_quota;
-+
-+ /* An array of bit sets indicating which services must be polled. */
-+ atomic_t poll_services[BITSET_SIZE(VCHIQ_MAX_SERVICES)];
-+
-+ /* The number of the first unused service */
-+ int unused_service;
-+
-+ /* Signalled when a free slot becomes available. */
-+ struct semaphore slot_available_event;
-+
-+ struct semaphore slot_remove_event;
-+
-+ /* Signalled when a free data slot becomes available. */
-+ struct semaphore data_quota_event;
-+
-+ /* Incremented when there are bulk transfers which cannot be processed
-+ * whilst paused and must be processed on resume */
-+ int deferred_bulks;
-+
-+ struct state_stats_struct {
-+ int slot_stalls;
-+ int data_stalls;
-+ int ctrl_tx_count;
-+ int ctrl_rx_count;
-+ int error_count;
-+ } stats;
-+
-+ VCHIQ_SERVICE_T * services[VCHIQ_MAX_SERVICES];
-+ VCHIQ_SERVICE_QUOTA_T service_quotas[VCHIQ_MAX_SERVICES];
-+ VCHIQ_SLOT_INFO_T slot_info[VCHIQ_MAX_SLOTS];
-+
-+ VCHIQ_PLATFORM_STATE_T platform_state;
-+};
-+
-+struct bulk_waiter {
-+ VCHIQ_BULK_T *bulk;
-+ struct semaphore event;
-+ int actual;
-+};
-+
-+extern spinlock_t bulk_waiter_spinlock;
-+
-+extern int vchiq_core_log_level;
-+extern int vchiq_core_msg_log_level;
-+extern int vchiq_sync_log_level;
-+
-+extern VCHIQ_STATE_T *vchiq_states[VCHIQ_MAX_STATES];
-+
-+extern const char *
-+get_conn_state_name(VCHIQ_CONNSTATE_T conn_state);
-+
-+extern VCHIQ_SLOT_ZERO_T *
-+vchiq_init_slots(void *mem_base, int mem_size);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_init_state(VCHIQ_STATE_T *state, VCHIQ_SLOT_ZERO_T *slot_zero,
-+ int is_master);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_connect_internal(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance);
-+
-+extern VCHIQ_SERVICE_T *
-+vchiq_add_service_internal(VCHIQ_STATE_T *state,
-+ const VCHIQ_SERVICE_PARAMS_T *params, int srvstate,
-+ VCHIQ_INSTANCE_T instance, VCHIQ_USERDATA_TERM_T userdata_term);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_open_service_internal(VCHIQ_SERVICE_T *service, int client_id);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_close_service_internal(VCHIQ_SERVICE_T *service, int close_recvd);
-+
-+extern void
-+vchiq_terminate_service_internal(VCHIQ_SERVICE_T *service);
-+
-+extern void
-+vchiq_free_service_internal(VCHIQ_SERVICE_T *service);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_shutdown_internal(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_pause_internal(VCHIQ_STATE_T *state);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_resume_internal(VCHIQ_STATE_T *state);
-+
-+extern void
-+remote_event_pollall(VCHIQ_STATE_T *state);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle,
-+ VCHI_MEM_HANDLE_T memhandle, void *offset, int size, void *userdata,
-+ VCHIQ_BULK_MODE_T mode, VCHIQ_BULK_DIR_T dir);
-+
-+extern void
-+vchiq_dump_state(void *dump_context, VCHIQ_STATE_T *state);
-+
-+extern void
-+vchiq_dump_service_state(void *dump_context, VCHIQ_SERVICE_T *service);
-+
-+extern void
-+vchiq_loud_error_header(void);
-+
-+extern void
-+vchiq_loud_error_footer(void);
-+
-+extern void
-+request_poll(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, int poll_type);
-+
-+static inline VCHIQ_SERVICE_T *
-+handle_to_service(VCHIQ_SERVICE_HANDLE_T handle)
-+{
-+ VCHIQ_STATE_T *state = vchiq_states[(handle / VCHIQ_MAX_SERVICES) &
-+ (VCHIQ_MAX_STATES - 1)];
-+ if (!state)
-+ return NULL;
-+
-+ return state->services[handle & (VCHIQ_MAX_SERVICES - 1)];
-+}
-+
-+extern VCHIQ_SERVICE_T *
-+find_service_by_handle(VCHIQ_SERVICE_HANDLE_T handle);
-+
-+extern VCHIQ_SERVICE_T *
-+find_service_by_port(VCHIQ_STATE_T *state, int localport);
-+
-+extern VCHIQ_SERVICE_T *
-+find_service_for_instance(VCHIQ_INSTANCE_T instance,
-+ VCHIQ_SERVICE_HANDLE_T handle);
-+
-+extern VCHIQ_SERVICE_T *
-+find_closed_service_for_instance(VCHIQ_INSTANCE_T instance,
-+ VCHIQ_SERVICE_HANDLE_T handle);
-+
-+extern VCHIQ_SERVICE_T *
-+next_service_by_instance(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance,
-+ int *pidx);
-+
-+extern void
-+lock_service(VCHIQ_SERVICE_T *service);
-+
-+extern void
-+unlock_service(VCHIQ_SERVICE_T *service);
-+
-+/* The following functions are called from vchiq_core, and external
-+** implementations must be provided. */
-+
-+extern VCHIQ_STATUS_T
-+vchiq_prepare_bulk_data(VCHIQ_BULK_T *bulk,
-+ VCHI_MEM_HANDLE_T memhandle, void *offset, int size, int dir);
-+
-+extern void
-+vchiq_transfer_bulk(VCHIQ_BULK_T *bulk);
-+
-+extern void
-+vchiq_complete_bulk(VCHIQ_BULK_T *bulk);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_copy_from_user(void *dst, const void *src, int size);
-+
-+extern void
-+remote_event_signal(REMOTE_EVENT_T *event);
-+
-+void
-+vchiq_platform_check_suspend(VCHIQ_STATE_T *state);
-+
-+extern void
-+vchiq_platform_paused(VCHIQ_STATE_T *state);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_platform_resume(VCHIQ_STATE_T *state);
-+
-+extern void
-+vchiq_platform_resumed(VCHIQ_STATE_T *state);
-+
-+extern void
-+vchiq_dump(void *dump_context, const char *str, int len);
-+
-+extern void
-+vchiq_dump_platform_state(void *dump_context);
-+
-+extern void
-+vchiq_dump_platform_instances(void *dump_context);
-+
-+extern void
-+vchiq_dump_platform_service_state(void *dump_context,
-+ VCHIQ_SERVICE_T *service);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_use_service_internal(VCHIQ_SERVICE_T *service);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_release_service_internal(VCHIQ_SERVICE_T *service);
-+
-+extern void
-+vchiq_on_remote_use(VCHIQ_STATE_T *state);
-+
-+extern void
-+vchiq_on_remote_release(VCHIQ_STATE_T *state);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_platform_init_state(VCHIQ_STATE_T *state);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_check_service(VCHIQ_SERVICE_T *service);
-+
-+extern void
-+vchiq_on_remote_use_active(VCHIQ_STATE_T *state);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_send_remote_use(VCHIQ_STATE_T *state);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_send_remote_release(VCHIQ_STATE_T *state);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_send_remote_use_active(VCHIQ_STATE_T *state);
-+
-+extern void
-+vchiq_platform_conn_state_changed(VCHIQ_STATE_T *state,
-+ VCHIQ_CONNSTATE_T oldstate, VCHIQ_CONNSTATE_T newstate);
-+
-+extern void
-+vchiq_platform_handle_timeout(VCHIQ_STATE_T *state);
-+
-+extern void
-+vchiq_set_conn_state(VCHIQ_STATE_T *state, VCHIQ_CONNSTATE_T newstate);
-+
-+
-+extern void
-+vchiq_log_dump_mem(const char *label, uint32_t addr, const void *voidMem,
-+ size_t numBytes);
-+
-+#endif
---- /dev/null
-+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
-@@ -0,0 +1,383 @@
-+/**
-+ * Copyright (c) 2014 Raspberry Pi (Trading) Ltd. All rights reserved.
-+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+
-+#include <linux/debugfs.h>
-+#include "vchiq_core.h"
-+#include "vchiq_arm.h"
-+#include "vchiq_debugfs.h"
-+
-+#ifdef CONFIG_DEBUG_FS
-+
-+/****************************************************************************
-+*
-+* log category entries
-+*
-+***************************************************************************/
-+#define DEBUGFS_WRITE_BUF_SIZE 256
-+
-+#define VCHIQ_LOG_ERROR_STR "error"
-+#define VCHIQ_LOG_WARNING_STR "warning"
-+#define VCHIQ_LOG_INFO_STR "info"
-+#define VCHIQ_LOG_TRACE_STR "trace"
-+
-+
-+/* Top-level debug info */
-+struct vchiq_debugfs_info {
-+ /* Global 'vchiq' debugfs entry used by all instances */
-+ struct dentry *vchiq_cfg_dir;
-+
-+ /* one entry per client process */
-+ struct dentry *clients;
-+
-+ /* log categories */
-+ struct dentry *log_categories;
-+};
-+
-+static struct vchiq_debugfs_info debugfs_info;
-+
-+/* Log category debugfs entries */
-+struct vchiq_debugfs_log_entry {
-+ const char *name;
-+ int *plevel;
-+ struct dentry *dir;
-+};
-+
-+static struct vchiq_debugfs_log_entry vchiq_debugfs_log_entries[] = {
-+ { "core", &vchiq_core_log_level },
-+ { "msg", &vchiq_core_msg_log_level },
-+ { "sync", &vchiq_sync_log_level },
-+ { "susp", &vchiq_susp_log_level },
-+ { "arm", &vchiq_arm_log_level },
-+};
-+static int n_log_entries =
-+ sizeof(vchiq_debugfs_log_entries)/sizeof(vchiq_debugfs_log_entries[0]);
-+
-+
-+static struct dentry *vchiq_clients_top(void);
-+static struct dentry *vchiq_debugfs_top(void);
-+
-+static int debugfs_log_show(struct seq_file *f, void *offset)
-+{
-+ int *levp = f->private;
-+ char *log_value = NULL;
-+
-+ switch (*levp) {
-+ case VCHIQ_LOG_ERROR:
-+ log_value = VCHIQ_LOG_ERROR_STR;
-+ break;
-+ case VCHIQ_LOG_WARNING:
-+ log_value = VCHIQ_LOG_WARNING_STR;
-+ break;
-+ case VCHIQ_LOG_INFO:
-+ log_value = VCHIQ_LOG_INFO_STR;
-+ break;
-+ case VCHIQ_LOG_TRACE:
-+ log_value = VCHIQ_LOG_TRACE_STR;
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ seq_printf(f, "%s\n", log_value ? log_value : "(null)");
-+
-+ return 0;
-+}
-+
-+static int debugfs_log_open(struct inode *inode, struct file *file)
-+{
-+ return single_open(file, debugfs_log_show, inode->i_private);
-+}
-+
-+static int debugfs_log_write(struct file *file,
-+ const char __user *buffer,
-+ size_t count, loff_t *ppos)
-+{
-+ struct seq_file *f = (struct seq_file *)file->private_data;
-+ int *levp = f->private;
-+ char kbuf[DEBUGFS_WRITE_BUF_SIZE + 1];
-+
-+ memset(kbuf, 0, DEBUGFS_WRITE_BUF_SIZE + 1);
-+ if (count >= DEBUGFS_WRITE_BUF_SIZE)
-+ count = DEBUGFS_WRITE_BUF_SIZE;
-+
-+ if (copy_from_user(kbuf, buffer, count) != 0)
-+ return -EFAULT;
-+ kbuf[count - 1] = 0;
-+
-+ if (strncmp("error", kbuf, strlen("error")) == 0)
-+ *levp = VCHIQ_LOG_ERROR;
-+ else if (strncmp("warning", kbuf, strlen("warning")) == 0)
-+ *levp = VCHIQ_LOG_WARNING;
-+ else if (strncmp("info", kbuf, strlen("info")) == 0)
-+ *levp = VCHIQ_LOG_INFO;
-+ else if (strncmp("trace", kbuf, strlen("trace")) == 0)
-+ *levp = VCHIQ_LOG_TRACE;
-+ else
-+ *levp = VCHIQ_LOG_DEFAULT;
-+
-+ *ppos += count;
-+
-+ return count;
-+}
-+
-+static const struct file_operations debugfs_log_fops = {
-+ .owner = THIS_MODULE,
-+ .open = debugfs_log_open,
-+ .write = debugfs_log_write,
-+ .read = seq_read,
-+ .llseek = seq_lseek,
-+ .release = single_release,
-+};
-+
-+/* create an entry under <debugfs>/vchiq/log for each log category */
-+static int vchiq_debugfs_create_log_entries(struct dentry *top)
-+{
-+ struct dentry *dir;
-+ size_t i;
-+ int ret = 0;
-+ dir = debugfs_create_dir("log", vchiq_debugfs_top());
-+ if (!dir)
-+ return -ENOMEM;
-+ debugfs_info.log_categories = dir;
-+
-+ for (i = 0; i < n_log_entries; i++) {
-+ void *levp = (void *)vchiq_debugfs_log_entries[i].plevel;
-+ dir = debugfs_create_file(vchiq_debugfs_log_entries[i].name,
-+ 0644,
-+ debugfs_info.log_categories,
-+ levp,
-+ &debugfs_log_fops);
-+ if (!dir) {
-+ ret = -ENOMEM;
-+ break;
-+ }
-+
-+ vchiq_debugfs_log_entries[i].dir = dir;
-+ }
-+ return ret;
-+}
-+
-+static int debugfs_usecount_show(struct seq_file *f, void *offset)
-+{
-+ VCHIQ_INSTANCE_T instance = f->private;
-+ int use_count;
-+
-+ use_count = vchiq_instance_get_use_count(instance);
-+ seq_printf(f, "%d\n", use_count);
-+
-+ return 0;
-+}
-+
-+static int debugfs_usecount_open(struct inode *inode, struct file *file)
-+{
-+ return single_open(file, debugfs_usecount_show, inode->i_private);
-+}
-+
-+static const struct file_operations debugfs_usecount_fops = {
-+ .owner = THIS_MODULE,
-+ .open = debugfs_usecount_open,
-+ .read = seq_read,
-+ .llseek = seq_lseek,
-+ .release = single_release,
-+};
-+
-+static int debugfs_trace_show(struct seq_file *f, void *offset)
-+{
-+ VCHIQ_INSTANCE_T instance = f->private;
-+ int trace;
-+
-+ trace = vchiq_instance_get_trace(instance);
-+ seq_printf(f, "%s\n", trace ? "Y" : "N");
-+
-+ return 0;
-+}
-+
-+static int debugfs_trace_open(struct inode *inode, struct file *file)
-+{
-+ return single_open(file, debugfs_trace_show, inode->i_private);
-+}
-+
-+static int debugfs_trace_write(struct file *file,
-+ const char __user *buffer,
-+ size_t count, loff_t *ppos)
-+{
-+ struct seq_file *f = (struct seq_file *)file->private_data;
-+ VCHIQ_INSTANCE_T instance = f->private;
-+ char firstchar;
-+
-+ if (copy_from_user(&firstchar, buffer, 1) != 0)
-+ return -EFAULT;
-+
-+ switch (firstchar) {
-+ case 'Y':
-+ case 'y':
-+ case '1':
-+ vchiq_instance_set_trace(instance, 1);
-+ break;
-+ case 'N':
-+ case 'n':
-+ case '0':
-+ vchiq_instance_set_trace(instance, 0);
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ *ppos += count;
-+
-+ return count;
-+}
-+
-+static const struct file_operations debugfs_trace_fops = {
-+ .owner = THIS_MODULE,
-+ .open = debugfs_trace_open,
-+ .write = debugfs_trace_write,
-+ .read = seq_read,
-+ .llseek = seq_lseek,
-+ .release = single_release,
-+};
-+
-+/* add an instance (process) to the debugfs entries */
-+int vchiq_debugfs_add_instance(VCHIQ_INSTANCE_T instance)
-+{
-+ char pidstr[16];
-+ struct dentry *top, *use_count, *trace;
-+ struct dentry *clients = vchiq_clients_top();
-+
-+ snprintf(pidstr, sizeof(pidstr), "%d",
-+ vchiq_instance_get_pid(instance));
-+
-+ top = debugfs_create_dir(pidstr, clients);
-+ if (!top)
-+ goto fail_top;
-+
-+ use_count = debugfs_create_file("use_count",
-+ 0444, top,
-+ instance,
-+ &debugfs_usecount_fops);
-+ if (!use_count)
-+ goto fail_use_count;
-+
-+ trace = debugfs_create_file("trace",
-+ 0644, top,
-+ instance,
-+ &debugfs_trace_fops);
-+ if (!trace)
-+ goto fail_trace;
-+
-+ vchiq_instance_get_debugfs_node(instance)->dentry = top;
-+
-+ return 0;
-+
-+fail_trace:
-+ debugfs_remove(use_count);
-+fail_use_count:
-+ debugfs_remove(top);
-+fail_top:
-+ return -ENOMEM;
-+}
-+
-+void vchiq_debugfs_remove_instance(VCHIQ_INSTANCE_T instance)
-+{
-+ VCHIQ_DEBUGFS_NODE_T *node = vchiq_instance_get_debugfs_node(instance);
-+ debugfs_remove_recursive(node->dentry);
-+}
-+
-+
-+int vchiq_debugfs_init(void)
-+{
-+ BUG_ON(debugfs_info.vchiq_cfg_dir != NULL);
-+
-+ debugfs_info.vchiq_cfg_dir = debugfs_create_dir("vchiq", NULL);
-+ if (debugfs_info.vchiq_cfg_dir == NULL)
-+ goto fail;
-+
-+ debugfs_info.clients = debugfs_create_dir("clients",
-+ vchiq_debugfs_top());
-+ if (!debugfs_info.clients)
-+ goto fail;
-+
-+ if (vchiq_debugfs_create_log_entries(vchiq_debugfs_top()) != 0)
-+ goto fail;
-+
-+ return 0;
-+
-+fail:
-+ vchiq_debugfs_deinit();
-+ vchiq_log_error(vchiq_arm_log_level,
-+ "%s: failed to create debugfs directory",
-+ __func__);
-+
-+ return -ENOMEM;
-+}
-+
-+/* remove all the debugfs entries */
-+void vchiq_debugfs_deinit(void)
-+{
-+ debugfs_remove_recursive(vchiq_debugfs_top());
-+}
-+
-+static struct dentry *vchiq_clients_top(void)
-+{
-+ return debugfs_info.clients;
-+}
-+
-+static struct dentry *vchiq_debugfs_top(void)
-+{
-+ BUG_ON(debugfs_info.vchiq_cfg_dir == NULL);
-+ return debugfs_info.vchiq_cfg_dir;
-+}
-+
-+#else /* CONFIG_DEBUG_FS */
-+
-+int vchiq_debugfs_init(void)
-+{
-+ return 0;
-+}
-+
-+void vchiq_debugfs_deinit(void)
-+{
-+}
-+
-+int vchiq_debugfs_add_instance(VCHIQ_INSTANCE_T instance)
-+{
-+ return 0;
-+}
-+
-+void vchiq_debugfs_remove_instance(VCHIQ_INSTANCE_T instance)
-+{
-+}
-+
-+#endif /* CONFIG_DEBUG_FS */
---- /dev/null
-+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_debugfs.h
-@@ -0,0 +1,52 @@
-+/**
-+ * Copyright (c) 2014 Raspberry Pi (Trading) Ltd. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHIQ_DEBUGFS_H
-+#define VCHIQ_DEBUGFS_H
-+
-+#include "vchiq_core.h"
-+
-+typedef struct vchiq_debugfs_node_struct
-+{
-+ struct dentry *dentry;
-+} VCHIQ_DEBUGFS_NODE_T;
-+
-+int vchiq_debugfs_init(void);
-+
-+void vchiq_debugfs_deinit(void);
-+
-+int vchiq_debugfs_add_instance(VCHIQ_INSTANCE_T instance);
-+
-+void vchiq_debugfs_remove_instance(VCHIQ_INSTANCE_T instance);
-+
-+#endif /* VCHIQ_DEBUGFS_H */
---- /dev/null
-+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_genversion
-@@ -0,0 +1,87 @@
-+#!/usr/bin/perl -w
-+
-+use strict;
-+
-+#
-+# Generate a version from available information
-+#
-+
-+my $prefix = shift @ARGV;
-+my $root = shift @ARGV;
-+
-+
-+if ( not defined $root ) {
-+ die "usage: $0 prefix root-dir\n";
-+}
-+
-+if ( ! -d $root ) {
-+ die "root directory $root not found\n";
-+}
-+
-+my $version = "unknown";
-+my $tainted = "";
-+
-+if ( -d "$root/.git" ) {
-+ # attempt to work out git version. only do so
-+ # on a linux build host, as cygwin builds are
-+ # already slow enough
-+
-+ if ( -f "/usr/bin/git" || -f "/usr/local/bin/git" ) {
-+ if (not open(F, "git --git-dir $root/.git rev-parse --verify HEAD|")) {
-+ $version = "no git version";
-+ }
-+ else {
-+ $version = <F>;
-+ $version =~ s/[ \r\n]*$//; # chomp may not be enough (cygwin).
-+ $version =~ s/^[ \r\n]*//; # chomp may not be enough (cygwin).
-+ }
-+
-+ if (open(G, "git --git-dir $root/.git status --porcelain|")) {
-+ $tainted = <G>;
-+ $tainted =~ s/[ \r\n]*$//; # chomp may not be enough (cygwin).
-+ $tainted =~ s/^[ \r\n]*//; # chomp may not be enough (cygwin).
-+ if (length $tainted) {
-+ $version = join ' ', $version, "(tainted)";
-+ }
-+ else {
-+ $version = join ' ', $version, "(clean)";
-+ }
-+ }
-+ }
-+}
-+
-+my $hostname = `hostname`;
-+$hostname =~ s/[ \r\n]*$//; # chomp may not be enough (cygwin).
-+$hostname =~ s/^[ \r\n]*//; # chomp may not be enough (cygwin).
-+
-+
-+print STDERR "Version $version\n";
-+print <<EOF;
-+#include "${prefix}_build_info.h"
-+#include <linux/broadcom/vc_debug_sym.h>
-+
-+VC_DEBUG_DECLARE_STRING_VAR( ${prefix}_build_hostname, "$hostname" );
-+VC_DEBUG_DECLARE_STRING_VAR( ${prefix}_build_version, "$version" );
-+VC_DEBUG_DECLARE_STRING_VAR( ${prefix}_build_time, __TIME__ );
-+VC_DEBUG_DECLARE_STRING_VAR( ${prefix}_build_date, __DATE__ );
-+
-+const char *vchiq_get_build_hostname( void )
-+{
-+ return vchiq_build_hostname;
-+}
-+
-+const char *vchiq_get_build_version( void )
-+{
-+ return vchiq_build_version;
-+}
-+
-+const char *vchiq_get_build_date( void )
-+{
-+ return vchiq_build_date;
-+}
-+
-+const char *vchiq_get_build_time( void )
-+{
-+ return vchiq_build_time;
-+}
-+EOF
---- /dev/null
-+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_if.h
-@@ -0,0 +1,189 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHIQ_IF_H
-+#define VCHIQ_IF_H
-+
-+#include "interface/vchi/vchi_mh.h"
-+
-+#define VCHIQ_SERVICE_HANDLE_INVALID 0
-+
-+#define VCHIQ_SLOT_SIZE 4096
-+#define VCHIQ_MAX_MSG_SIZE (VCHIQ_SLOT_SIZE - sizeof(VCHIQ_HEADER_T))
-+#define VCHIQ_CHANNEL_SIZE VCHIQ_MAX_MSG_SIZE /* For backwards compatibility */
-+
-+#define VCHIQ_MAKE_FOURCC(x0, x1, x2, x3) \
-+ (((x0) << 24) | ((x1) << 16) | ((x2) << 8) | (x3))
-+#define VCHIQ_GET_SERVICE_USERDATA(service) vchiq_get_service_userdata(service)
-+#define VCHIQ_GET_SERVICE_FOURCC(service) vchiq_get_service_fourcc(service)
-+
-+typedef enum {
-+ VCHIQ_SERVICE_OPENED, /* service, -, - */
-+ VCHIQ_SERVICE_CLOSED, /* service, -, - */
-+ VCHIQ_MESSAGE_AVAILABLE, /* service, header, - */
-+ VCHIQ_BULK_TRANSMIT_DONE, /* service, -, bulk_userdata */
-+ VCHIQ_BULK_RECEIVE_DONE, /* service, -, bulk_userdata */
-+ VCHIQ_BULK_TRANSMIT_ABORTED, /* service, -, bulk_userdata */
-+ VCHIQ_BULK_RECEIVE_ABORTED /* service, -, bulk_userdata */
-+} VCHIQ_REASON_T;
-+
-+typedef enum {
-+ VCHIQ_ERROR = -1,
-+ VCHIQ_SUCCESS = 0,
-+ VCHIQ_RETRY = 1
-+} VCHIQ_STATUS_T;
-+
-+typedef enum {
-+ VCHIQ_BULK_MODE_CALLBACK,
-+ VCHIQ_BULK_MODE_BLOCKING,
-+ VCHIQ_BULK_MODE_NOCALLBACK,
-+ VCHIQ_BULK_MODE_WAITING /* Reserved for internal use */
-+} VCHIQ_BULK_MODE_T;
-+
-+typedef enum {
-+ VCHIQ_SERVICE_OPTION_AUTOCLOSE,
-+ VCHIQ_SERVICE_OPTION_SLOT_QUOTA,
-+ VCHIQ_SERVICE_OPTION_MESSAGE_QUOTA,
-+ VCHIQ_SERVICE_OPTION_SYNCHRONOUS,
-+ VCHIQ_SERVICE_OPTION_TRACE
-+} VCHIQ_SERVICE_OPTION_T;
-+
-+typedef struct vchiq_header_struct {
-+ /* The message identifier - opaque to applications. */
-+ int msgid;
-+
-+ /* Size of message data. */
-+ unsigned int size;
-+
-+ char data[0]; /* message */
-+} VCHIQ_HEADER_T;
-+
-+typedef struct {
-+ const void *data;
-+ unsigned int size;
-+} VCHIQ_ELEMENT_T;
-+
-+typedef unsigned int VCHIQ_SERVICE_HANDLE_T;
-+
-+typedef VCHIQ_STATUS_T (*VCHIQ_CALLBACK_T)(VCHIQ_REASON_T, VCHIQ_HEADER_T *,
-+ VCHIQ_SERVICE_HANDLE_T, void *);
-+
-+typedef struct vchiq_service_base_struct {
-+ int fourcc;
-+ VCHIQ_CALLBACK_T callback;
-+ void *userdata;
-+} VCHIQ_SERVICE_BASE_T;
-+
-+typedef struct vchiq_service_params_struct {
-+ int fourcc;
-+ VCHIQ_CALLBACK_T callback;
-+ void *userdata;
-+ short version; /* Increment for non-trivial changes */
-+ short version_min; /* Update for incompatible changes */
-+} VCHIQ_SERVICE_PARAMS_T;
-+
-+typedef struct vchiq_config_struct {
-+ unsigned int max_msg_size;
-+ unsigned int bulk_threshold; /* The message size above which it
-+ is better to use a bulk transfer
-+ (<= max_msg_size) */
-+ unsigned int max_outstanding_bulks;
-+ unsigned int max_services;
-+ short version; /* The version of VCHIQ */
-+ short version_min; /* The minimum compatible version of VCHIQ */
-+} VCHIQ_CONFIG_T;
-+
-+typedef struct vchiq_instance_struct *VCHIQ_INSTANCE_T;
-+typedef void (*VCHIQ_REMOTE_USE_CALLBACK_T)(void *cb_arg);
-+
-+extern VCHIQ_STATUS_T vchiq_initialise(VCHIQ_INSTANCE_T *pinstance);
-+extern VCHIQ_STATUS_T vchiq_shutdown(VCHIQ_INSTANCE_T instance);
-+extern VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance);
-+extern VCHIQ_STATUS_T vchiq_add_service(VCHIQ_INSTANCE_T instance,
-+ const VCHIQ_SERVICE_PARAMS_T *params,
-+ VCHIQ_SERVICE_HANDLE_T *pservice);
-+extern VCHIQ_STATUS_T vchiq_open_service(VCHIQ_INSTANCE_T instance,
-+ const VCHIQ_SERVICE_PARAMS_T *params,
-+ VCHIQ_SERVICE_HANDLE_T *pservice);
-+extern VCHIQ_STATUS_T vchiq_close_service(VCHIQ_SERVICE_HANDLE_T service);
-+extern VCHIQ_STATUS_T vchiq_remove_service(VCHIQ_SERVICE_HANDLE_T service);
-+extern VCHIQ_STATUS_T vchiq_use_service(VCHIQ_SERVICE_HANDLE_T service);
-+extern VCHIQ_STATUS_T vchiq_use_service_no_resume(
-+ VCHIQ_SERVICE_HANDLE_T service);
-+extern VCHIQ_STATUS_T vchiq_release_service(VCHIQ_SERVICE_HANDLE_T service);
-+
-+extern VCHIQ_STATUS_T vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T service,
-+ const VCHIQ_ELEMENT_T *elements, unsigned int count);
-+extern void vchiq_release_message(VCHIQ_SERVICE_HANDLE_T service,
-+ VCHIQ_HEADER_T *header);
-+extern VCHIQ_STATUS_T vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T service,
-+ const void *data, unsigned int size, void *userdata);
-+extern VCHIQ_STATUS_T vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T service,
-+ void *data, unsigned int size, void *userdata);
-+extern VCHIQ_STATUS_T vchiq_queue_bulk_transmit_handle(
-+ VCHIQ_SERVICE_HANDLE_T service, VCHI_MEM_HANDLE_T handle,
-+ const void *offset, unsigned int size, void *userdata);
-+extern VCHIQ_STATUS_T vchiq_queue_bulk_receive_handle(
-+ VCHIQ_SERVICE_HANDLE_T service, VCHI_MEM_HANDLE_T handle,
-+ void *offset, unsigned int size, void *userdata);
-+extern VCHIQ_STATUS_T vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T service,
-+ const void *data, unsigned int size, void *userdata,
-+ VCHIQ_BULK_MODE_T mode);
-+extern VCHIQ_STATUS_T vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T service,
-+ void *data, unsigned int size, void *userdata,
-+ VCHIQ_BULK_MODE_T mode);
-+extern VCHIQ_STATUS_T vchiq_bulk_transmit_handle(VCHIQ_SERVICE_HANDLE_T service,
-+ VCHI_MEM_HANDLE_T handle, const void *offset, unsigned int size,
-+ void *userdata, VCHIQ_BULK_MODE_T mode);
-+extern VCHIQ_STATUS_T vchiq_bulk_receive_handle(VCHIQ_SERVICE_HANDLE_T service,
-+ VCHI_MEM_HANDLE_T handle, void *offset, unsigned int size,
-+ void *userdata, VCHIQ_BULK_MODE_T mode);
-+extern int vchiq_get_client_id(VCHIQ_SERVICE_HANDLE_T service);
-+extern void *vchiq_get_service_userdata(VCHIQ_SERVICE_HANDLE_T service);
-+extern int vchiq_get_service_fourcc(VCHIQ_SERVICE_HANDLE_T service);
-+extern VCHIQ_STATUS_T vchiq_get_config(VCHIQ_INSTANCE_T instance,
-+ int config_size, VCHIQ_CONFIG_T *pconfig);
-+extern VCHIQ_STATUS_T vchiq_set_service_option(VCHIQ_SERVICE_HANDLE_T service,
-+ VCHIQ_SERVICE_OPTION_T option, int value);
-+
-+extern VCHIQ_STATUS_T vchiq_remote_use(VCHIQ_INSTANCE_T instance,
-+ VCHIQ_REMOTE_USE_CALLBACK_T callback, void *cb_arg);
-+extern VCHIQ_STATUS_T vchiq_remote_release(VCHIQ_INSTANCE_T instance);
-+
-+extern VCHIQ_STATUS_T vchiq_dump_phys_mem(VCHIQ_SERVICE_HANDLE_T service,
-+ void *ptr, size_t num_bytes);
-+
-+extern VCHIQ_STATUS_T vchiq_get_peer_version(VCHIQ_SERVICE_HANDLE_T handle,
-+ short *peer_version);
-+
-+#endif /* VCHIQ_IF_H */
---- /dev/null
-+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_ioctl.h
-@@ -0,0 +1,131 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHIQ_IOCTLS_H
-+#define VCHIQ_IOCTLS_H
-+
-+#include <linux/ioctl.h>
-+#include "vchiq_if.h"
-+
-+#define VCHIQ_IOC_MAGIC 0xc4
-+#define VCHIQ_INVALID_HANDLE (~0)
-+
-+typedef struct {
-+ VCHIQ_SERVICE_PARAMS_T params;
-+ int is_open;
-+ int is_vchi;
-+ unsigned int handle; /* OUT */
-+} VCHIQ_CREATE_SERVICE_T;
-+
-+typedef struct {
-+ unsigned int handle;
-+ unsigned int count;
-+ const VCHIQ_ELEMENT_T *elements;
-+} VCHIQ_QUEUE_MESSAGE_T;
-+
-+typedef struct {
-+ unsigned int handle;
-+ void *data;
-+ unsigned int size;
-+ void *userdata;
-+ VCHIQ_BULK_MODE_T mode;
-+} VCHIQ_QUEUE_BULK_TRANSFER_T;
-+
-+typedef struct {
-+ VCHIQ_REASON_T reason;
-+ VCHIQ_HEADER_T *header;
-+ void *service_userdata;
-+ void *bulk_userdata;
-+} VCHIQ_COMPLETION_DATA_T;
-+
-+typedef struct {
-+ unsigned int count;
-+ VCHIQ_COMPLETION_DATA_T *buf;
-+ unsigned int msgbufsize;
-+ unsigned int msgbufcount; /* IN/OUT */
-+ void **msgbufs;
-+} VCHIQ_AWAIT_COMPLETION_T;
-+
-+typedef struct {
-+ unsigned int handle;
-+ int blocking;
-+ unsigned int bufsize;
-+ void *buf;
-+} VCHIQ_DEQUEUE_MESSAGE_T;
-+
-+typedef struct {
-+ unsigned int config_size;
-+ VCHIQ_CONFIG_T *pconfig;
-+} VCHIQ_GET_CONFIG_T;
-+
-+typedef struct {
-+ unsigned int handle;
-+ VCHIQ_SERVICE_OPTION_T option;
-+ int value;
-+} VCHIQ_SET_SERVICE_OPTION_T;
-+
-+typedef struct {
-+ void *virt_addr;
-+ size_t num_bytes;
-+} VCHIQ_DUMP_MEM_T;
-+
-+#define VCHIQ_IOC_CONNECT _IO(VCHIQ_IOC_MAGIC, 0)
-+#define VCHIQ_IOC_SHUTDOWN _IO(VCHIQ_IOC_MAGIC, 1)
-+#define VCHIQ_IOC_CREATE_SERVICE \
-+ _IOWR(VCHIQ_IOC_MAGIC, 2, VCHIQ_CREATE_SERVICE_T)
-+#define VCHIQ_IOC_REMOVE_SERVICE _IO(VCHIQ_IOC_MAGIC, 3)
-+#define VCHIQ_IOC_QUEUE_MESSAGE \
-+ _IOW(VCHIQ_IOC_MAGIC, 4, VCHIQ_QUEUE_MESSAGE_T)
-+#define VCHIQ_IOC_QUEUE_BULK_TRANSMIT \
-+ _IOWR(VCHIQ_IOC_MAGIC, 5, VCHIQ_QUEUE_BULK_TRANSFER_T)
-+#define VCHIQ_IOC_QUEUE_BULK_RECEIVE \
-+ _IOWR(VCHIQ_IOC_MAGIC, 6, VCHIQ_QUEUE_BULK_TRANSFER_T)
-+#define VCHIQ_IOC_AWAIT_COMPLETION \
-+ _IOWR(VCHIQ_IOC_MAGIC, 7, VCHIQ_AWAIT_COMPLETION_T)
-+#define VCHIQ_IOC_DEQUEUE_MESSAGE \
-+ _IOWR(VCHIQ_IOC_MAGIC, 8, VCHIQ_DEQUEUE_MESSAGE_T)
-+#define VCHIQ_IOC_GET_CLIENT_ID _IO(VCHIQ_IOC_MAGIC, 9)
-+#define VCHIQ_IOC_GET_CONFIG \
-+ _IOWR(VCHIQ_IOC_MAGIC, 10, VCHIQ_GET_CONFIG_T)
-+#define VCHIQ_IOC_CLOSE_SERVICE _IO(VCHIQ_IOC_MAGIC, 11)
-+#define VCHIQ_IOC_USE_SERVICE _IO(VCHIQ_IOC_MAGIC, 12)
-+#define VCHIQ_IOC_RELEASE_SERVICE _IO(VCHIQ_IOC_MAGIC, 13)
-+#define VCHIQ_IOC_SET_SERVICE_OPTION \
-+ _IOW(VCHIQ_IOC_MAGIC, 14, VCHIQ_SET_SERVICE_OPTION_T)
-+#define VCHIQ_IOC_DUMP_PHYS_MEM \
-+ _IOW(VCHIQ_IOC_MAGIC, 15, VCHIQ_DUMP_MEM_T)
-+#define VCHIQ_IOC_LIB_VERSION _IO(VCHIQ_IOC_MAGIC, 16)
-+#define VCHIQ_IOC_CLOSE_DELIVERED _IO(VCHIQ_IOC_MAGIC, 17)
-+#define VCHIQ_IOC_MAX 17
-+
-+#endif
---- /dev/null
-+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
-@@ -0,0 +1,458 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+/* ---- Include Files ---------------------------------------------------- */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/mutex.h>
-+
-+#include "vchiq_core.h"
-+#include "vchiq_arm.h"
-+#include "vchiq_killable.h"
-+
-+/* ---- Public Variables ------------------------------------------------- */
-+
-+/* ---- Private Constants and Types -------------------------------------- */
-+
-+struct bulk_waiter_node {
-+ struct bulk_waiter bulk_waiter;
-+ int pid;
-+ struct list_head list;
-+};
-+
-+struct vchiq_instance_struct {
-+ VCHIQ_STATE_T *state;
-+
-+ int connected;
-+
-+ struct list_head bulk_waiter_list;
-+ struct mutex bulk_waiter_list_mutex;
-+};
-+
-+static VCHIQ_STATUS_T
-+vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data,
-+ unsigned int size, VCHIQ_BULK_DIR_T dir);
-+
-+/****************************************************************************
-+*
-+* vchiq_initialise
-+*
-+***************************************************************************/
-+#define VCHIQ_INIT_RETRIES 10
-+VCHIQ_STATUS_T vchiq_initialise(VCHIQ_INSTANCE_T *instanceOut)
-+{
-+ VCHIQ_STATUS_T status = VCHIQ_ERROR;
-+ VCHIQ_STATE_T *state;
-+ VCHIQ_INSTANCE_T instance = NULL;
-+ int i;
-+
-+ vchiq_log_trace(vchiq_core_log_level, "%s called", __func__);
-+
-+ /* VideoCore may not be ready due to boot up timing.
-+ It may never be ready if kernel and firmware are mismatched, so don't block forever. */
-+ for (i=0; i<VCHIQ_INIT_RETRIES; i++) {
-+ state = vchiq_get_state();
-+ if (state)
-+ break;
-+ udelay(500);
-+ }
-+ if (i==VCHIQ_INIT_RETRIES) {
-+ vchiq_log_error(vchiq_core_log_level,
-+ "%s: videocore not initialized\n", __func__);
-+ goto failed;
-+ } else if (i>0) {
-+ vchiq_log_warning(vchiq_core_log_level,
-+ "%s: videocore initialized after %d retries\n", __func__, i);
-+ }
-+
-+ instance = kzalloc(sizeof(*instance), GFP_KERNEL);
-+ if (!instance) {
-+ vchiq_log_error(vchiq_core_log_level,
-+ "%s: error allocating vchiq instance\n", __func__);
-+ goto failed;
-+ }
-+
-+ instance->connected = 0;
-+ instance->state = state;
-+ mutex_init(&instance->bulk_waiter_list_mutex);
-+ INIT_LIST_HEAD(&instance->bulk_waiter_list);
-+
-+ *instanceOut = instance;
-+
-+ status = VCHIQ_SUCCESS;
-+
-+failed:
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%s(%p): returning %d", __func__, instance, status);
-+
-+ return status;
-+}
-+EXPORT_SYMBOL(vchiq_initialise);
-+
-+/****************************************************************************
-+*
-+* vchiq_shutdown
-+*
-+***************************************************************************/
-+
-+VCHIQ_STATUS_T vchiq_shutdown(VCHIQ_INSTANCE_T instance)
-+{
-+ VCHIQ_STATUS_T status;
-+ VCHIQ_STATE_T *state = instance->state;
-+
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%s(%p) called", __func__, instance);
-+
-+ if (mutex_lock_interruptible(&state->mutex) != 0)
-+ return VCHIQ_RETRY;
-+
-+ /* Remove all services */
-+ status = vchiq_shutdown_internal(state, instance);
-+
-+ mutex_unlock(&state->mutex);
-+
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%s(%p): returning %d", __func__, instance, status);
-+
-+ if (status == VCHIQ_SUCCESS) {
-+ struct list_head *pos, *next;
-+ list_for_each_safe(pos, next,
-+ &instance->bulk_waiter_list) {
-+ struct bulk_waiter_node *waiter;
-+ waiter = list_entry(pos,
-+ struct bulk_waiter_node,
-+ list);
-+ list_del(pos);
-+ vchiq_log_info(vchiq_arm_log_level,
-+ "bulk_waiter - cleaned up %x "
-+ "for pid %d",
-+ (unsigned int)waiter, waiter->pid);
-+ kfree(waiter);
-+ }
-+ kfree(instance);
-+ }
-+
-+ return status;
-+}
-+EXPORT_SYMBOL(vchiq_shutdown);
-+
-+/****************************************************************************
-+*
-+* vchiq_is_connected
-+*
-+***************************************************************************/
-+
-+int vchiq_is_connected(VCHIQ_INSTANCE_T instance)
-+{
-+ return instance->connected;
-+}
-+
-+/****************************************************************************
-+*
-+* vchiq_connect
-+*
-+***************************************************************************/
-+
-+VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance)
-+{
-+ VCHIQ_STATUS_T status;
-+ VCHIQ_STATE_T *state = instance->state;
-+
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%s(%p) called", __func__, instance);
-+
-+ if (mutex_lock_interruptible(&state->mutex) != 0) {
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%s: call to mutex_lock failed", __func__);
-+ status = VCHIQ_RETRY;
-+ goto failed;
-+ }
-+ status = vchiq_connect_internal(state, instance);
-+
-+ if (status == VCHIQ_SUCCESS)
-+ instance->connected = 1;
-+
-+ mutex_unlock(&state->mutex);
-+
-+failed:
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%s(%p): returning %d", __func__, instance, status);
-+
-+ return status;
-+}
-+EXPORT_SYMBOL(vchiq_connect);
-+
-+/****************************************************************************
-+*
-+* vchiq_add_service
-+*
-+***************************************************************************/
-+
-+VCHIQ_STATUS_T vchiq_add_service(
-+ VCHIQ_INSTANCE_T instance,
-+ const VCHIQ_SERVICE_PARAMS_T *params,
-+ VCHIQ_SERVICE_HANDLE_T *phandle)
-+{
-+ VCHIQ_STATUS_T status;
-+ VCHIQ_STATE_T *state = instance->state;
-+ VCHIQ_SERVICE_T *service = NULL;
-+ int srvstate;
-+
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%s(%p) called", __func__, instance);
-+
-+ *phandle = VCHIQ_SERVICE_HANDLE_INVALID;
-+
-+ srvstate = vchiq_is_connected(instance)
-+ ? VCHIQ_SRVSTATE_LISTENING
-+ : VCHIQ_SRVSTATE_HIDDEN;
-+
-+ service = vchiq_add_service_internal(
-+ state,
-+ params,
-+ srvstate,
-+ instance,
-+ NULL);
-+
-+ if (service) {
-+ *phandle = service->handle;
-+ status = VCHIQ_SUCCESS;
-+ } else
-+ status = VCHIQ_ERROR;
-+
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%s(%p): returning %d", __func__, instance, status);
-+
-+ return status;
-+}
-+EXPORT_SYMBOL(vchiq_add_service);
-+
-+/****************************************************************************
-+*
-+* vchiq_open_service
-+*
-+***************************************************************************/
-+
-+VCHIQ_STATUS_T vchiq_open_service(
-+ VCHIQ_INSTANCE_T instance,
-+ const VCHIQ_SERVICE_PARAMS_T *params,
-+ VCHIQ_SERVICE_HANDLE_T *phandle)
-+{
-+ VCHIQ_STATUS_T status = VCHIQ_ERROR;
-+ VCHIQ_STATE_T *state = instance->state;
-+ VCHIQ_SERVICE_T *service = NULL;
-+
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%s(%p) called", __func__, instance);
-+
-+ *phandle = VCHIQ_SERVICE_HANDLE_INVALID;
-+
-+ if (!vchiq_is_connected(instance))
-+ goto failed;
-+
-+ service = vchiq_add_service_internal(state,
-+ params,
-+ VCHIQ_SRVSTATE_OPENING,
-+ instance,
-+ NULL);
-+
-+ if (service) {
-+ *phandle = service->handle;
-+ status = vchiq_open_service_internal(service, current->pid);
-+ if (status != VCHIQ_SUCCESS) {
-+ vchiq_remove_service(service->handle);
-+ *phandle = VCHIQ_SERVICE_HANDLE_INVALID;
-+ }
-+ }
-+
-+failed:
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%s(%p): returning %d", __func__, instance, status);
-+
-+ return status;
-+}
-+EXPORT_SYMBOL(vchiq_open_service);
-+
-+VCHIQ_STATUS_T
-+vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle,
-+ const void *data, unsigned int size, void *userdata)
-+{
-+ return vchiq_bulk_transfer(handle,
-+ VCHI_MEM_HANDLE_INVALID, (void *)data, size, userdata,
-+ VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_TRANSMIT);
-+}
-+EXPORT_SYMBOL(vchiq_queue_bulk_transmit);
-+
-+VCHIQ_STATUS_T
-+vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data,
-+ unsigned int size, void *userdata)
-+{
-+ return vchiq_bulk_transfer(handle,
-+ VCHI_MEM_HANDLE_INVALID, data, size, userdata,
-+ VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_RECEIVE);
-+}
-+EXPORT_SYMBOL(vchiq_queue_bulk_receive);
-+
-+VCHIQ_STATUS_T
-+vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle, const void *data,
-+ unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode)
-+{
-+ VCHIQ_STATUS_T status;
-+
-+ switch (mode) {
-+ case VCHIQ_BULK_MODE_NOCALLBACK:
-+ case VCHIQ_BULK_MODE_CALLBACK:
-+ status = vchiq_bulk_transfer(handle,
-+ VCHI_MEM_HANDLE_INVALID, (void *)data, size, userdata,
-+ mode, VCHIQ_BULK_TRANSMIT);
-+ break;
-+ case VCHIQ_BULK_MODE_BLOCKING:
-+ status = vchiq_blocking_bulk_transfer(handle,
-+ (void *)data, size, VCHIQ_BULK_TRANSMIT);
-+ break;
-+ default:
-+ return VCHIQ_ERROR;
-+ }
-+
-+ return status;
-+}
-+EXPORT_SYMBOL(vchiq_bulk_transmit);
-+
-+VCHIQ_STATUS_T
-+vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data,
-+ unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode)
-+{
-+ VCHIQ_STATUS_T status;
-+
-+ switch (mode) {
-+ case VCHIQ_BULK_MODE_NOCALLBACK:
-+ case VCHIQ_BULK_MODE_CALLBACK:
-+ status = vchiq_bulk_transfer(handle,
-+ VCHI_MEM_HANDLE_INVALID, data, size, userdata,
-+ mode, VCHIQ_BULK_RECEIVE);
-+ break;
-+ case VCHIQ_BULK_MODE_BLOCKING:
-+ status = vchiq_blocking_bulk_transfer(handle,
-+ (void *)data, size, VCHIQ_BULK_RECEIVE);
-+ break;
-+ default:
-+ return VCHIQ_ERROR;
-+ }
-+
-+ return status;
-+}
-+EXPORT_SYMBOL(vchiq_bulk_receive);
-+
-+static VCHIQ_STATUS_T
-+vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data,
-+ unsigned int size, VCHIQ_BULK_DIR_T dir)
-+{
-+ VCHIQ_INSTANCE_T instance;
-+ VCHIQ_SERVICE_T *service;
-+ VCHIQ_STATUS_T status;
-+ struct bulk_waiter_node *waiter = NULL;
-+ struct list_head *pos;
-+
-+ service = find_service_by_handle(handle);
-+ if (!service)
-+ return VCHIQ_ERROR;
-+
-+ instance = service->instance;
-+
-+ unlock_service(service);
-+
-+ mutex_lock(&instance->bulk_waiter_list_mutex);
-+ list_for_each(pos, &instance->bulk_waiter_list) {
-+ if (list_entry(pos, struct bulk_waiter_node,
-+ list)->pid == current->pid) {
-+ waiter = list_entry(pos,
-+ struct bulk_waiter_node,
-+ list);
-+ list_del(pos);
-+ break;
-+ }
-+ }
-+ mutex_unlock(&instance->bulk_waiter_list_mutex);
-+
-+ if (waiter) {
-+ VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk;
-+ if (bulk) {
-+ /* This thread has an outstanding bulk transfer. */
-+ if ((bulk->data != data) ||
-+ (bulk->size != size)) {
-+ /* This is not a retry of the previous one.
-+ ** Cancel the signal when the transfer
-+ ** completes. */
-+ spin_lock(&bulk_waiter_spinlock);
-+ bulk->userdata = NULL;
-+ spin_unlock(&bulk_waiter_spinlock);
-+ }
-+ }
-+ }
-+
-+ if (!waiter) {
-+ waiter = kzalloc(sizeof(struct bulk_waiter_node), GFP_KERNEL);
-+ if (!waiter) {
-+ vchiq_log_error(vchiq_core_log_level,
-+ "%s - out of memory", __func__);
-+ return VCHIQ_ERROR;
-+ }
-+ }
-+
-+ status = vchiq_bulk_transfer(handle, VCHI_MEM_HANDLE_INVALID,
-+ data, size, &waiter->bulk_waiter, VCHIQ_BULK_MODE_BLOCKING,
-+ dir);
-+ if ((status != VCHIQ_RETRY) || fatal_signal_pending(current) ||
-+ !waiter->bulk_waiter.bulk) {
-+ VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk;
-+ if (bulk) {
-+ /* Cancel the signal when the transfer
-+ ** completes. */
-+ spin_lock(&bulk_waiter_spinlock);
-+ bulk->userdata = NULL;
-+ spin_unlock(&bulk_waiter_spinlock);
-+ }
-+ kfree(waiter);
-+ } else {
-+ waiter->pid = current->pid;
-+ mutex_lock(&instance->bulk_waiter_list_mutex);
-+ list_add(&waiter->list, &instance->bulk_waiter_list);
-+ mutex_unlock(&instance->bulk_waiter_list_mutex);
-+ vchiq_log_info(vchiq_arm_log_level,
-+ "saved bulk_waiter %x for pid %d",
-+ (unsigned int)waiter, current->pid);
-+ }
-+
-+ return status;
-+}
---- /dev/null
-+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_killable.h
-@@ -0,0 +1,69 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHIQ_KILLABLE_H
-+#define VCHIQ_KILLABLE_H
-+
-+#include <linux/mutex.h>
-+#include <linux/semaphore.h>
-+
-+#define SHUTDOWN_SIGS (sigmask(SIGKILL) | sigmask(SIGINT) | sigmask(SIGQUIT) | sigmask(SIGTRAP) | sigmask(SIGSTOP) | sigmask(SIGCONT))
-+
-+static inline int __must_check down_interruptible_killable(struct semaphore *sem)
-+{
-+ /* Allow interception of killable signals only. We don't want to be interrupted by harmless signals like SIGALRM */
-+ int ret;
-+ sigset_t blocked, oldset;
-+ siginitsetinv(&blocked, SHUTDOWN_SIGS);
-+ sigprocmask(SIG_SETMASK, &blocked, &oldset);
-+ ret = down_interruptible(sem);
-+ sigprocmask(SIG_SETMASK, &oldset, NULL);
-+ return ret;
-+}
-+#define down_interruptible down_interruptible_killable
-+
-+
-+static inline int __must_check mutex_lock_interruptible_killable(struct mutex *lock)
-+{
-+ /* Allow interception of killable signals only. We don't want to be interrupted by harmless signals like SIGALRM */
-+ int ret;
-+ sigset_t blocked, oldset;
-+ siginitsetinv(&blocked, SHUTDOWN_SIGS);
-+ sigprocmask(SIG_SETMASK, &blocked, &oldset);
-+ ret = mutex_lock_interruptible(lock);
-+ sigprocmask(SIG_SETMASK, &oldset, NULL);
-+ return ret;
-+}
-+#define mutex_lock_interruptible mutex_lock_interruptible_killable
-+
-+#endif
---- /dev/null
-+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_memdrv.h
-@@ -0,0 +1,71 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHIQ_MEMDRV_H
-+#define VCHIQ_MEMDRV_H
-+
-+/* ---- Include Files ----------------------------------------------------- */
-+
-+#include <linux/kernel.h>
-+#include "vchiq_if.h"
-+
-+/* ---- Constants and Types ---------------------------------------------- */
-+
-+typedef struct {
-+ void *armSharedMemVirt;
-+ dma_addr_t armSharedMemPhys;
-+ size_t armSharedMemSize;
-+
-+ void *vcSharedMemVirt;
-+ dma_addr_t vcSharedMemPhys;
-+ size_t vcSharedMemSize;
-+} VCHIQ_SHARED_MEM_INFO_T;
-+
-+/* ---- Variable Externs ------------------------------------------------- */
-+
-+/* ---- Function Prototypes ---------------------------------------------- */
-+
-+void vchiq_get_shared_mem_info(VCHIQ_SHARED_MEM_INFO_T *info);
-+
-+VCHIQ_STATUS_T vchiq_memdrv_initialise(void);
-+
-+VCHIQ_STATUS_T vchiq_userdrv_create_instance(
-+ const VCHIQ_PLATFORM_DATA_T * platform_data);
-+
-+VCHIQ_STATUS_T vchiq_userdrv_suspend(
-+ const VCHIQ_PLATFORM_DATA_T * platform_data);
-+
-+VCHIQ_STATUS_T vchiq_userdrv_resume(
-+ const VCHIQ_PLATFORM_DATA_T * platform_data);
-+
-+#endif
---- /dev/null
-+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_pagelist.h
-@@ -0,0 +1,58 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHIQ_PAGELIST_H
-+#define VCHIQ_PAGELIST_H
-+
-+#ifndef PAGE_SIZE
-+#define PAGE_SIZE 4096
-+#endif
-+#define CACHE_LINE_SIZE 32
-+#define PAGELIST_WRITE 0
-+#define PAGELIST_READ 1
-+#define PAGELIST_READ_WITH_FRAGMENTS 2
-+
-+typedef struct pagelist_struct {
-+ unsigned long length;
-+ unsigned short type;
-+ unsigned short offset;
-+ unsigned long addrs[1]; /* N.B. 12 LSBs hold the number of following
-+ pages at consecutive addresses. */
-+} PAGELIST_T;
-+
-+typedef struct fragments_struct {
-+ char headbuf[CACHE_LINE_SIZE];
-+ char tailbuf[CACHE_LINE_SIZE];
-+} FRAGMENTS_T;
-+
-+#endif /* VCHIQ_PAGELIST_H */
---- /dev/null
-+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c
-@@ -0,0 +1,860 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+#include <linux/module.h>
-+#include <linux/types.h>
-+
-+#include "interface/vchi/vchi.h"
-+#include "vchiq.h"
-+#include "vchiq_core.h"
-+
-+#include "vchiq_util.h"
-+
-+#include <stddef.h>
-+
-+#define vchiq_status_to_vchi(status) ((int32_t)status)
-+
-+typedef struct {
-+ VCHIQ_SERVICE_HANDLE_T handle;
-+
-+ VCHIU_QUEUE_T queue;
-+
-+ VCHI_CALLBACK_T callback;
-+ void *callback_param;
-+} SHIM_SERVICE_T;
-+
-+/* ----------------------------------------------------------------------
-+ * return pointer to the mphi message driver function table
-+ * -------------------------------------------------------------------- */
-+const VCHI_MESSAGE_DRIVER_T *
-+vchi_mphi_message_driver_func_table(void)
-+{
-+ return NULL;
-+}
-+
-+/* ----------------------------------------------------------------------
-+ * return a pointer to the 'single' connection driver fops
-+ * -------------------------------------------------------------------- */
-+const VCHI_CONNECTION_API_T *
-+single_get_func_table(void)
-+{
-+ return NULL;
-+}
-+
-+VCHI_CONNECTION_T *vchi_create_connection(
-+ const VCHI_CONNECTION_API_T *function_table,
-+ const VCHI_MESSAGE_DRIVER_T *low_level)
-+{
-+ (void)function_table;
-+ (void)low_level;
-+ return NULL;
-+}
-+
-+/***********************************************************
-+ * Name: vchi_msg_peek
-+ *
-+ * Arguments: const VCHI_SERVICE_HANDLE_T handle,
-+ * void **data,
-+ * uint32_t *msg_size,
-+
-+
-+ * VCHI_FLAGS_T flags
-+ *
-+ * Description: Routine to return a pointer to the current message (to allow in
-+ * place processing). The message can be removed using
-+ * vchi_msg_remove when you're finished
-+ *
-+ * Returns: int32_t - success == 0
-+ *
-+ ***********************************************************/
-+int32_t vchi_msg_peek(VCHI_SERVICE_HANDLE_T handle,
-+ void **data,
-+ uint32_t *msg_size,
-+ VCHI_FLAGS_T flags)
-+{
-+ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
-+ VCHIQ_HEADER_T *header;
-+
-+ WARN_ON((flags != VCHI_FLAGS_NONE) &&
-+ (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
-+
-+ if (flags == VCHI_FLAGS_NONE)
-+ if (vchiu_queue_is_empty(&service->queue))
-+ return -1;
-+
-+ header = vchiu_queue_peek(&service->queue);
-+
-+ *data = header->data;
-+ *msg_size = header->size;
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL(vchi_msg_peek);
-+
-+/***********************************************************
-+ * Name: vchi_msg_remove
-+ *
-+ * Arguments: const VCHI_SERVICE_HANDLE_T handle,
-+ *
-+ * Description: Routine to remove a message (after it has been read with
-+ * vchi_msg_peek)
-+ *
-+ * Returns: int32_t - success == 0
-+ *
-+ ***********************************************************/
-+int32_t vchi_msg_remove(VCHI_SERVICE_HANDLE_T handle)
-+{
-+ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
-+ VCHIQ_HEADER_T *header;
-+
-+ header = vchiu_queue_pop(&service->queue);
-+
-+ vchiq_release_message(service->handle, header);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL(vchi_msg_remove);
-+
-+/***********************************************************
-+ * Name: vchi_msg_queue
-+ *
-+ * Arguments: VCHI_SERVICE_HANDLE_T handle,
-+ * const void *data,
-+ * uint32_t data_size,
-+ * VCHI_FLAGS_T flags,
-+ * void *msg_handle,
-+ *
-+ * Description: Thin wrapper to queue a message onto a connection
-+ *
-+ * Returns: int32_t - success == 0
-+ *
-+ ***********************************************************/
-+int32_t vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
-+ const void *data,
-+ uint32_t data_size,
-+ VCHI_FLAGS_T flags,
-+ void *msg_handle)
-+{
-+ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
-+ VCHIQ_ELEMENT_T element = {data, data_size};
-+ VCHIQ_STATUS_T status;
-+
-+ (void)msg_handle;
-+
-+ WARN_ON(flags != VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
-+
-+ status = vchiq_queue_message(service->handle, &element, 1);
-+
-+ /* vchiq_queue_message() may return VCHIQ_RETRY, so we need to
-+ ** implement a retry mechanism since this function is supposed
-+ ** to block until queued
-+ */
-+ while (status == VCHIQ_RETRY) {
-+ msleep(1);
-+ status = vchiq_queue_message(service->handle, &element, 1);
-+ }
-+
-+ return vchiq_status_to_vchi(status);
-+}
-+EXPORT_SYMBOL(vchi_msg_queue);
-+
-+/***********************************************************
-+ * Name: vchi_bulk_queue_receive
-+ *
-+ * Arguments: VCHI_BULK_HANDLE_T handle,
-+ * void *data_dst,
-+ * const uint32_t data_size,
-+ * VCHI_FLAGS_T flags
-+ * void *bulk_handle
-+ *
-+ * Description: Routine to setup a rcv buffer
-+ *
-+ * Returns: int32_t - success == 0
-+ *
-+ ***********************************************************/
-+int32_t vchi_bulk_queue_receive(VCHI_SERVICE_HANDLE_T handle,
-+ void *data_dst,
-+ uint32_t data_size,
-+ VCHI_FLAGS_T flags,
-+ void *bulk_handle)
-+{
-+ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
-+ VCHIQ_BULK_MODE_T mode;
-+ VCHIQ_STATUS_T status;
-+
-+ switch ((int)flags) {
-+ case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE
-+ | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
-+ WARN_ON(!service->callback);
-+ mode = VCHIQ_BULK_MODE_CALLBACK;
-+ break;
-+ case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
-+ mode = VCHIQ_BULK_MODE_BLOCKING;
-+ break;
-+ case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
-+ case VCHI_FLAGS_NONE:
-+ mode = VCHIQ_BULK_MODE_NOCALLBACK;
-+ break;
-+ default:
-+ WARN(1, "unsupported message\n");
-+ return vchiq_status_to_vchi(VCHIQ_ERROR);
-+ }
-+
-+ status = vchiq_bulk_receive(service->handle, data_dst, data_size,
-+ bulk_handle, mode);
-+
-+ /* vchiq_bulk_receive() may return VCHIQ_RETRY, so we need to
-+ ** implement a retry mechanism since this function is supposed
-+ ** to block until queued
-+ */
-+ while (status == VCHIQ_RETRY) {
-+ msleep(1);
-+ status = vchiq_bulk_receive(service->handle, data_dst,
-+ data_size, bulk_handle, mode);
-+ }
-+
-+ return vchiq_status_to_vchi(status);
-+}
-+EXPORT_SYMBOL(vchi_bulk_queue_receive);
-+
-+/***********************************************************
-+ * Name: vchi_bulk_queue_transmit
-+ *
-+ * Arguments: VCHI_BULK_HANDLE_T handle,
-+ * const void *data_src,
-+ * uint32_t data_size,
-+ * VCHI_FLAGS_T flags,
-+ * void *bulk_handle
-+ *
-+ * Description: Routine to transmit some data
-+ *
-+ * Returns: int32_t - success == 0
-+ *
-+ ***********************************************************/
-+int32_t vchi_bulk_queue_transmit(VCHI_SERVICE_HANDLE_T handle,
-+ const void *data_src,
-+ uint32_t data_size,
-+ VCHI_FLAGS_T flags,
-+ void *bulk_handle)
-+{
-+ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
-+ VCHIQ_BULK_MODE_T mode;
-+ VCHIQ_STATUS_T status;
-+
-+ switch ((int)flags) {
-+ case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE
-+ | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
-+ WARN_ON(!service->callback);
-+ mode = VCHIQ_BULK_MODE_CALLBACK;
-+ break;
-+ case VCHI_FLAGS_BLOCK_UNTIL_DATA_READ:
-+ case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
-+ mode = VCHIQ_BULK_MODE_BLOCKING;
-+ break;
-+ case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
-+ case VCHI_FLAGS_NONE:
-+ mode = VCHIQ_BULK_MODE_NOCALLBACK;
-+ break;
-+ default:
-+ WARN(1, "unsupported message\n");
-+ return vchiq_status_to_vchi(VCHIQ_ERROR);
-+ }
-+
-+ status = vchiq_bulk_transmit(service->handle, data_src, data_size,
-+ bulk_handle, mode);
-+
-+ /* vchiq_bulk_transmit() may return VCHIQ_RETRY, so we need to
-+ ** implement a retry mechanism since this function is supposed
-+ ** to block until queued
-+ */
-+ while (status == VCHIQ_RETRY) {
-+ msleep(1);
-+ status = vchiq_bulk_transmit(service->handle, data_src,
-+ data_size, bulk_handle, mode);
-+ }
-+
-+ return vchiq_status_to_vchi(status);
-+}
-+EXPORT_SYMBOL(vchi_bulk_queue_transmit);
-+
-+/***********************************************************
-+ * Name: vchi_msg_dequeue
-+ *
-+ * Arguments: VCHI_SERVICE_HANDLE_T handle,
-+ * void *data,
-+ * uint32_t max_data_size_to_read,
-+ * uint32_t *actual_msg_size
-+ * VCHI_FLAGS_T flags
-+ *
-+ * Description: Routine to dequeue a message into the supplied buffer
-+ *
-+ * Returns: int32_t - success == 0
-+ *
-+ ***********************************************************/
-+int32_t vchi_msg_dequeue(VCHI_SERVICE_HANDLE_T handle,
-+ void *data,
-+ uint32_t max_data_size_to_read,
-+ uint32_t *actual_msg_size,
-+ VCHI_FLAGS_T flags)
-+{
-+ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
-+ VCHIQ_HEADER_T *header;
-+
-+ WARN_ON((flags != VCHI_FLAGS_NONE) &&
-+ (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
-+
-+ if (flags == VCHI_FLAGS_NONE)
-+ if (vchiu_queue_is_empty(&service->queue))
-+ return -1;
-+
-+ header = vchiu_queue_pop(&service->queue);
-+
-+ memcpy(data, header->data, header->size < max_data_size_to_read ?
-+ header->size : max_data_size_to_read);
-+
-+ *actual_msg_size = header->size;
-+
-+ vchiq_release_message(service->handle, header);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL(vchi_msg_dequeue);
-+
-+/***********************************************************
-+ * Name: vchi_msg_queuev
-+ *
-+ * Arguments: VCHI_SERVICE_HANDLE_T handle,
-+ * VCHI_MSG_VECTOR_T *vector,
-+ * uint32_t count,
-+ * VCHI_FLAGS_T flags,
-+ * void *msg_handle
-+ *
-+ * Description: Thin wrapper to queue a message onto a connection
-+ *
-+ * Returns: int32_t - success == 0
-+ *
-+ ***********************************************************/
-+
-+vchiq_static_assert(sizeof(VCHI_MSG_VECTOR_T) == sizeof(VCHIQ_ELEMENT_T));
-+vchiq_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_base) ==
-+ offsetof(VCHIQ_ELEMENT_T, data));
-+vchiq_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_len) ==
-+ offsetof(VCHIQ_ELEMENT_T, size));
-+
-+int32_t vchi_msg_queuev(VCHI_SERVICE_HANDLE_T handle,
-+ VCHI_MSG_VECTOR_T *vector,
-+ uint32_t count,
-+ VCHI_FLAGS_T flags,
-+ void *msg_handle)
-+{
-+ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
-+
-+ (void)msg_handle;
-+
-+ WARN_ON(flags != VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
-+
-+ return vchiq_status_to_vchi(vchiq_queue_message(service->handle,
-+ (const VCHIQ_ELEMENT_T *)vector, count));
-+}
-+EXPORT_SYMBOL(vchi_msg_queuev);
-+
-+/***********************************************************
-+ * Name: vchi_held_msg_release
-+ *
-+ * Arguments: VCHI_HELD_MSG_T *message
-+ *
-+ * Description: Routine to release a held message (after it has been read with
-+ * vchi_msg_hold)
-+ *
-+ * Returns: int32_t - success == 0
-+ *
-+ ***********************************************************/
-+int32_t vchi_held_msg_release(VCHI_HELD_MSG_T *message)
-+{
-+ vchiq_release_message((VCHIQ_SERVICE_HANDLE_T)message->service,
-+ (VCHIQ_HEADER_T *)message->message);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL(vchi_held_msg_release);
-+
-+/***********************************************************
-+ * Name: vchi_msg_hold
-+ *
-+ * Arguments: VCHI_SERVICE_HANDLE_T handle,
-+ * void **data,
-+ * uint32_t *msg_size,
-+ * VCHI_FLAGS_T flags,
-+ * VCHI_HELD_MSG_T *message_handle
-+ *
-+ * Description: Routine to return a pointer to the current message (to allow
-+ * in place processing). The message is dequeued - don't forget
-+ * to release the message using vchi_held_msg_release when you're
-+ * finished.
-+ *
-+ * Returns: int32_t - success == 0
-+ *
-+ ***********************************************************/
-+int32_t vchi_msg_hold(VCHI_SERVICE_HANDLE_T handle,
-+ void **data,
-+ uint32_t *msg_size,
-+ VCHI_FLAGS_T flags,
-+ VCHI_HELD_MSG_T *message_handle)
-+{
-+ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
-+ VCHIQ_HEADER_T *header;
-+
-+ WARN_ON((flags != VCHI_FLAGS_NONE) &&
-+ (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
-+
-+ if (flags == VCHI_FLAGS_NONE)
-+ if (vchiu_queue_is_empty(&service->queue))
-+ return -1;
-+
-+ header = vchiu_queue_pop(&service->queue);
-+
-+ *data = header->data;
-+ *msg_size = header->size;
-+
-+ message_handle->service =
-+ (struct opaque_vchi_service_t *)service->handle;
-+ message_handle->message = header;
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL(vchi_msg_hold);
-+
-+/***********************************************************
-+ * Name: vchi_initialise
-+ *
-+ * Arguments: VCHI_INSTANCE_T *instance_handle
-+ *
-+ * Description: Initialises the hardware but does not transmit anything
-+ * When run as a Host App this will be called twice hence the need
-+ * to malloc the state information
-+ *
-+ * Returns: 0 if successful, failure otherwise
-+ *
-+ ***********************************************************/
-+
-+int32_t vchi_initialise(VCHI_INSTANCE_T *instance_handle)
-+{
-+ VCHIQ_INSTANCE_T instance;
-+ VCHIQ_STATUS_T status;
-+
-+ status = vchiq_initialise(&instance);
-+
-+ *instance_handle = (VCHI_INSTANCE_T)instance;
-+
-+ return vchiq_status_to_vchi(status);
-+}
-+EXPORT_SYMBOL(vchi_initialise);
-+
-+/***********************************************************
-+ * Name: vchi_connect
-+ *
-+ * Arguments: VCHI_CONNECTION_T **connections
-+ * const uint32_t num_connections
-+ * VCHI_INSTANCE_T instance_handle)
-+ *
-+ * Description: Starts the command service on each connection,
-+ * causing INIT messages to be pinged back and forth
-+ *
-+ * Returns: 0 if successful, failure otherwise
-+ *
-+ ***********************************************************/
-+int32_t vchi_connect(VCHI_CONNECTION_T **connections,
-+ const uint32_t num_connections,
-+ VCHI_INSTANCE_T instance_handle)
-+{
-+ VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
-+
-+ (void)connections;
-+ (void)num_connections;
-+
-+ return vchiq_connect(instance);
-+}
-+EXPORT_SYMBOL(vchi_connect);
-+
-+
-+/***********************************************************
-+ * Name: vchi_disconnect
-+ *
-+ * Arguments: VCHI_INSTANCE_T instance_handle
-+ *
-+ * Description: Stops the command service on each connection,
-+ * causing DE-INIT messages to be pinged back and forth
-+ *
-+ * Returns: 0 if successful, failure otherwise
-+ *
-+ ***********************************************************/
-+int32_t vchi_disconnect(VCHI_INSTANCE_T instance_handle)
-+{
-+ VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
-+ return vchiq_status_to_vchi(vchiq_shutdown(instance));
-+}
-+EXPORT_SYMBOL(vchi_disconnect);
-+
-+
-+/***********************************************************
-+ * Name: vchi_service_open
-+ * Name: vchi_service_create
-+ *
-+ * Arguments: VCHI_INSTANCE_T *instance_handle
-+ * SERVICE_CREATION_T *setup,
-+ * VCHI_SERVICE_HANDLE_T *handle
-+ *
-+ * Description: Routine to open a service
-+ *
-+ * Returns: int32_t - success == 0
-+ *
-+ ***********************************************************/
-+
-+static VCHIQ_STATUS_T shim_callback(VCHIQ_REASON_T reason,
-+ VCHIQ_HEADER_T *header, VCHIQ_SERVICE_HANDLE_T handle, void *bulk_user)
-+{
-+ SHIM_SERVICE_T *service =
-+ (SHIM_SERVICE_T *)VCHIQ_GET_SERVICE_USERDATA(handle);
-+
-+ if (!service->callback)
-+ goto release;
-+
-+ switch (reason) {
-+ case VCHIQ_MESSAGE_AVAILABLE:
-+ vchiu_queue_push(&service->queue, header);
-+
-+ service->callback(service->callback_param,
-+ VCHI_CALLBACK_MSG_AVAILABLE, NULL);
-+
-+ goto done;
-+ break;
-+
-+ case VCHIQ_BULK_TRANSMIT_DONE:
-+ service->callback(service->callback_param,
-+ VCHI_CALLBACK_BULK_SENT, bulk_user);
-+ break;
-+
-+ case VCHIQ_BULK_RECEIVE_DONE:
-+ service->callback(service->callback_param,
-+ VCHI_CALLBACK_BULK_RECEIVED, bulk_user);
-+ break;
-+
-+ case VCHIQ_SERVICE_CLOSED:
-+ service->callback(service->callback_param,
-+ VCHI_CALLBACK_SERVICE_CLOSED, NULL);
-+ break;
-+
-+ case VCHIQ_SERVICE_OPENED:
-+ /* No equivalent VCHI reason */
-+ break;
-+
-+ case VCHIQ_BULK_TRANSMIT_ABORTED:
-+ service->callback(service->callback_param,
-+ VCHI_CALLBACK_BULK_TRANSMIT_ABORTED,
-+ bulk_user);
-+ break;
-+
-+ case VCHIQ_BULK_RECEIVE_ABORTED:
-+ service->callback(service->callback_param,
-+ VCHI_CALLBACK_BULK_RECEIVE_ABORTED,
-+ bulk_user);
-+ break;
-+
-+ default:
-+ WARN(1, "not supported\n");
-+ break;
-+ }
-+
-+release:
-+ vchiq_release_message(service->handle, header);
-+done:
-+ return VCHIQ_SUCCESS;
-+}
-+
-+static SHIM_SERVICE_T *service_alloc(VCHIQ_INSTANCE_T instance,
-+ SERVICE_CREATION_T *setup)
-+{
-+ SHIM_SERVICE_T *service = kzalloc(sizeof(SHIM_SERVICE_T), GFP_KERNEL);
-+
-+ (void)instance;
-+
-+ if (service) {
-+ if (vchiu_queue_init(&service->queue, 64)) {
-+ service->callback = setup->callback;
-+ service->callback_param = setup->callback_param;
-+ } else {
-+ kfree(service);
-+ service = NULL;
-+ }
-+ }
-+
-+ return service;
-+}
-+
-+static void service_free(SHIM_SERVICE_T *service)
-+{
-+ if (service) {
-+ vchiu_queue_delete(&service->queue);
-+ kfree(service);
-+ }
-+}
-+
-+int32_t vchi_service_open(VCHI_INSTANCE_T instance_handle,
-+ SERVICE_CREATION_T *setup,
-+ VCHI_SERVICE_HANDLE_T *handle)
-+{
-+ VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
-+ SHIM_SERVICE_T *service = service_alloc(instance, setup);
-+
-+ *handle = (VCHI_SERVICE_HANDLE_T)service;
-+
-+ if (service) {
-+ VCHIQ_SERVICE_PARAMS_T params;
-+ VCHIQ_STATUS_T status;
-+
-+ memset(&params, 0, sizeof(params));
-+ params.fourcc = setup->service_id;
-+ params.callback = shim_callback;
-+ params.userdata = service;
-+ params.version = setup->version.version;
-+ params.version_min = setup->version.version_min;
-+
-+ status = vchiq_open_service(instance, &params,
-+ &service->handle);
-+ if (status != VCHIQ_SUCCESS) {
-+ service_free(service);
-+ service = NULL;
-+ *handle = NULL;
-+ }
-+ }
-+
-+ return (service != NULL) ? 0 : -1;
-+}
-+EXPORT_SYMBOL(vchi_service_open);
-+
-+int32_t vchi_service_create(VCHI_INSTANCE_T instance_handle,
-+ SERVICE_CREATION_T *setup,
-+ VCHI_SERVICE_HANDLE_T *handle)
-+{
-+ VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
-+ SHIM_SERVICE_T *service = service_alloc(instance, setup);
-+
-+ *handle = (VCHI_SERVICE_HANDLE_T)service;
-+
-+ if (service) {
-+ VCHIQ_SERVICE_PARAMS_T params;
-+ VCHIQ_STATUS_T status;
-+
-+ memset(&params, 0, sizeof(params));
-+ params.fourcc = setup->service_id;
-+ params.callback = shim_callback;
-+ params.userdata = service;
-+ params.version = setup->version.version;
-+ params.version_min = setup->version.version_min;
-+ status = vchiq_add_service(instance, &params, &service->handle);
-+
-+ if (status != VCHIQ_SUCCESS) {
-+ service_free(service);
-+ service = NULL;
-+ *handle = NULL;
-+ }
-+ }
-+
-+ return (service != NULL) ? 0 : -1;
-+}
-+EXPORT_SYMBOL(vchi_service_create);
-+
-+int32_t vchi_service_close(const VCHI_SERVICE_HANDLE_T handle)
-+{
-+ int32_t ret = -1;
-+ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
-+ if (service) {
-+ VCHIQ_STATUS_T status = vchiq_close_service(service->handle);
-+ if (status == VCHIQ_SUCCESS) {
-+ service_free(service);
-+ service = NULL;
-+ }
-+
-+ ret = vchiq_status_to_vchi(status);
-+ }
-+ return ret;
-+}
-+EXPORT_SYMBOL(vchi_service_close);
-+
-+int32_t vchi_service_destroy(const VCHI_SERVICE_HANDLE_T handle)
-+{
-+ int32_t ret = -1;
-+ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
-+ if (service) {
-+ VCHIQ_STATUS_T status = vchiq_remove_service(service->handle);
-+ if (status == VCHIQ_SUCCESS) {
-+ service_free(service);
-+ service = NULL;
-+ }
-+
-+ ret = vchiq_status_to_vchi(status);
-+ }
-+ return ret;
-+}
-+EXPORT_SYMBOL(vchi_service_destroy);
-+
-+int32_t vchi_service_set_option(const VCHI_SERVICE_HANDLE_T handle,
-+ VCHI_SERVICE_OPTION_T option,
-+ int value)
-+{
-+ int32_t ret = -1;
-+ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
-+ VCHIQ_SERVICE_OPTION_T vchiq_option;
-+ switch (option) {
-+ case VCHI_SERVICE_OPTION_TRACE:
-+ vchiq_option = VCHIQ_SERVICE_OPTION_TRACE;
-+ break;
-+ case VCHI_SERVICE_OPTION_SYNCHRONOUS:
-+ vchiq_option = VCHIQ_SERVICE_OPTION_SYNCHRONOUS;
-+ break;
-+ default:
-+ service = NULL;
-+ break;
-+ }
-+ if (service) {
-+ VCHIQ_STATUS_T status =
-+ vchiq_set_service_option(service->handle,
-+ vchiq_option,
-+ value);
-+
-+ ret = vchiq_status_to_vchi(status);
-+ }
-+ return ret;
-+}
-+EXPORT_SYMBOL(vchi_service_set_option);
-+
-+int32_t vchi_get_peer_version( const VCHI_SERVICE_HANDLE_T handle, short *peer_version )
-+{
-+ int32_t ret = -1;
-+ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
-+ if(service)
-+ {
-+ VCHIQ_STATUS_T status = vchiq_get_peer_version(service->handle, peer_version);
-+ ret = vchiq_status_to_vchi( status );
-+ }
-+ return ret;
-+}
-+EXPORT_SYMBOL(vchi_get_peer_version);
-+
-+/* ----------------------------------------------------------------------
-+ * read a uint32_t from buffer.
-+ * network format is defined to be little endian
-+ * -------------------------------------------------------------------- */
-+uint32_t
-+vchi_readbuf_uint32(const void *_ptr)
-+{
-+ const unsigned char *ptr = _ptr;
-+ return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
-+}
-+
-+/* ----------------------------------------------------------------------
-+ * write a uint32_t to buffer.
-+ * network format is defined to be little endian
-+ * -------------------------------------------------------------------- */
-+void
-+vchi_writebuf_uint32(void *_ptr, uint32_t value)
-+{
-+ unsigned char *ptr = _ptr;
-+ ptr[0] = (unsigned char)((value >> 0) & 0xFF);
-+ ptr[1] = (unsigned char)((value >> 8) & 0xFF);
-+ ptr[2] = (unsigned char)((value >> 16) & 0xFF);
-+ ptr[3] = (unsigned char)((value >> 24) & 0xFF);
-+}
-+
-+/* ----------------------------------------------------------------------
-+ * read a uint16_t from buffer.
-+ * network format is defined to be little endian
-+ * -------------------------------------------------------------------- */
-+uint16_t
-+vchi_readbuf_uint16(const void *_ptr)
-+{
-+ const unsigned char *ptr = _ptr;
-+ return ptr[0] | (ptr[1] << 8);
-+}
-+
-+/* ----------------------------------------------------------------------
-+ * write a uint16_t into the buffer.
-+ * network format is defined to be little endian
-+ * -------------------------------------------------------------------- */
-+void
-+vchi_writebuf_uint16(void *_ptr, uint16_t value)
-+{
-+ unsigned char *ptr = _ptr;
-+ ptr[0] = (value >> 0) & 0xFF;
-+ ptr[1] = (value >> 8) & 0xFF;
-+}
-+
-+/***********************************************************
-+ * Name: vchi_service_use
-+ *
-+ * Arguments: const VCHI_SERVICE_HANDLE_T handle
-+ *
-+ * Description: Routine to increment refcount on a service
-+ *
-+ * Returns: void
-+ *
-+ ***********************************************************/
-+int32_t vchi_service_use(const VCHI_SERVICE_HANDLE_T handle)
-+{
-+ int32_t ret = -1;
-+ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
-+ if (service)
-+ ret = vchiq_status_to_vchi(vchiq_use_service(service->handle));
-+ return ret;
-+}
-+EXPORT_SYMBOL(vchi_service_use);
-+
-+/***********************************************************
-+ * Name: vchi_service_release
-+ *
-+ * Arguments: const VCHI_SERVICE_HANDLE_T handle
-+ *
-+ * Description: Routine to decrement refcount on a service
-+ *
-+ * Returns: void
-+ *
-+ ***********************************************************/
-+int32_t vchi_service_release(const VCHI_SERVICE_HANDLE_T handle)
-+{
-+ int32_t ret = -1;
-+ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
-+ if (service)
-+ ret = vchiq_status_to_vchi(
-+ vchiq_release_service(service->handle));
-+ return ret;
-+}
-+EXPORT_SYMBOL(vchi_service_release);
---- /dev/null
-+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.c
-@@ -0,0 +1,156 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#include "vchiq_util.h"
-+#include "vchiq_killable.h"
-+
-+static inline int is_pow2(int i)
-+{
-+ return i && !(i & (i - 1));
-+}
-+
-+int vchiu_queue_init(VCHIU_QUEUE_T *queue, int size)
-+{
-+ WARN_ON(!is_pow2(size));
-+
-+ queue->size = size;
-+ queue->read = 0;
-+ queue->write = 0;
-+ queue->initialized = 1;
-+
-+ sema_init(&queue->pop, 0);
-+ sema_init(&queue->push, 0);
-+
-+ queue->storage = kzalloc(size * sizeof(VCHIQ_HEADER_T *), GFP_KERNEL);
-+ if (queue->storage == NULL) {
-+ vchiu_queue_delete(queue);
-+ return 0;
-+ }
-+ return 1;
-+}
-+
-+void vchiu_queue_delete(VCHIU_QUEUE_T *queue)
-+{
-+ if (queue->storage != NULL)
-+ kfree(queue->storage);
-+}
-+
-+int vchiu_queue_is_empty(VCHIU_QUEUE_T *queue)
-+{
-+ return queue->read == queue->write;
-+}
-+
-+int vchiu_queue_is_full(VCHIU_QUEUE_T *queue)
-+{
-+ return queue->write == queue->read + queue->size;
-+}
-+
-+void vchiu_queue_push(VCHIU_QUEUE_T *queue, VCHIQ_HEADER_T *header)
-+{
-+ if (!queue->initialized)
-+ return;
-+
-+ while (queue->write == queue->read + queue->size) {
-+ if (down_interruptible(&queue->pop) != 0) {
-+ flush_signals(current);
-+ }
-+ }
-+
-+ /*
-+ * Write to queue->storage must be visible after read from
-+ * queue->read
-+ */
-+ smp_mb();
-+
-+ queue->storage[queue->write & (queue->size - 1)] = header;
-+
-+ /*
-+ * Write to queue->storage must be visible before write to
-+ * queue->write
-+ */
-+ smp_wmb();
-+
-+ queue->write++;
-+
-+ up(&queue->push);
-+}
-+
-+VCHIQ_HEADER_T *vchiu_queue_peek(VCHIU_QUEUE_T *queue)
-+{
-+ while (queue->write == queue->read) {
-+ if (down_interruptible(&queue->push) != 0) {
-+ flush_signals(current);
-+ }
-+ }
-+
-+ up(&queue->push); // We haven't removed anything from the queue.
-+
-+ /*
-+ * Read from queue->storage must be visible after read from
-+ * queue->write
-+ */
-+ smp_rmb();
-+
-+ return queue->storage[queue->read & (queue->size - 1)];
-+}
-+
-+VCHIQ_HEADER_T *vchiu_queue_pop(VCHIU_QUEUE_T *queue)
-+{
-+ VCHIQ_HEADER_T *header;
-+
-+ while (queue->write == queue->read) {
-+ if (down_interruptible(&queue->push) != 0) {
-+ flush_signals(current);
-+ }
-+ }
-+
-+ /*
-+ * Read from queue->storage must be visible after read from
-+ * queue->write
-+ */
-+ smp_rmb();
-+
-+ header = queue->storage[queue->read & (queue->size - 1)];
-+
-+ /*
-+ * Read from queue->storage must be visible before write to
-+ * queue->read
-+ */
-+ smp_mb();
-+
-+ queue->read++;
-+
-+ up(&queue->pop);
-+
-+ return header;
-+}
---- /dev/null
-+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.h
-@@ -0,0 +1,82 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHIQ_UTIL_H
-+#define VCHIQ_UTIL_H
-+
-+#include <linux/types.h>
-+#include <linux/semaphore.h>
-+#include <linux/mutex.h>
-+#include <linux/bitops.h>
-+#include <linux/kthread.h>
-+#include <linux/wait.h>
-+#include <linux/vmalloc.h>
-+#include <linux/jiffies.h>
-+#include <linux/delay.h>
-+#include <linux/string.h>
-+#include <linux/types.h>
-+#include <linux/interrupt.h>
-+#include <linux/random.h>
-+#include <linux/sched.h>
-+#include <linux/ctype.h>
-+#include <linux/uaccess.h>
-+#include <linux/time.h> /* for time_t */
-+#include <linux/slab.h>
-+#include <linux/vmalloc.h>
-+
-+#include "vchiq_if.h"
-+
-+typedef struct {
-+ int size;
-+ int read;
-+ int write;
-+ int initialized;
-+
-+ struct semaphore pop;
-+ struct semaphore push;
-+
-+ VCHIQ_HEADER_T **storage;
-+} VCHIU_QUEUE_T;
-+
-+extern int vchiu_queue_init(VCHIU_QUEUE_T *queue, int size);
-+extern void vchiu_queue_delete(VCHIU_QUEUE_T *queue);
-+
-+extern int vchiu_queue_is_empty(VCHIU_QUEUE_T *queue);
-+extern int vchiu_queue_is_full(VCHIU_QUEUE_T *queue);
-+
-+extern void vchiu_queue_push(VCHIU_QUEUE_T *queue, VCHIQ_HEADER_T *header);
-+
-+extern VCHIQ_HEADER_T *vchiu_queue_peek(VCHIU_QUEUE_T *queue);
-+extern VCHIQ_HEADER_T *vchiu_queue_pop(VCHIU_QUEUE_T *queue);
-+
-+#endif
---- /dev/null
-+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_version.c
-@@ -0,0 +1,59 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+#include "vchiq_build_info.h"
-+#include <linux/broadcom/vc_debug_sym.h>
-+
-+VC_DEBUG_DECLARE_STRING_VAR( vchiq_build_hostname, "dc4-arm-01" );
-+VC_DEBUG_DECLARE_STRING_VAR( vchiq_build_version, "9245b4c35b99b3870e1f7dc598c5692b3c66a6f0 (tainted)" );
-+VC_DEBUG_DECLARE_STRING_VAR( vchiq_build_time, __TIME__ );
-+VC_DEBUG_DECLARE_STRING_VAR( vchiq_build_date, __DATE__ );
-+
-+const char *vchiq_get_build_hostname( void )
-+{
-+ return vchiq_build_hostname;
-+}
-+
-+const char *vchiq_get_build_version( void )
-+{
-+ return vchiq_build_version;
-+}
-+
-+const char *vchiq_get_build_date( void )
-+{
-+ return vchiq_build_date;
-+}
-+
-+const char *vchiq_get_build_time( void )
-+{
-+ return vchiq_build_time;
-+}
diff --git a/target/linux/brcm2708/patches-4.4/0037-vc_mem-Add-vc_mem-driver.patch b/target/linux/brcm2708/patches-4.4/0037-vc_mem-Add-vc_mem-driver.patch
new file mode 100644
index 0000000000..5559db506d
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0037-vc_mem-Add-vc_mem-driver.patch
@@ -0,0 +1,991 @@
+From f5cce853dbe19f479d61c2d91a009edbea5735fc Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Wed, 17 Jun 2015 16:07:06 +0100
+Subject: [PATCH 037/381] vc_mem: Add vc_mem driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: popcornmix <popcornmix@gmail.com>
+
+BCM270x: Move vc_mem
+
+Make the vc_mem module available for ARCH_BCM2835 by moving it.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+---
+ arch/arm/mach-bcm2709/include/mach/vc_mem.h | 35 ---
+ arch/arm/mach-bcm2709/vc_mem.c | 431 ----------------------------
+ drivers/char/broadcom/Kconfig | 12 +-
+ drivers/char/broadcom/Makefile | 1 +
+ drivers/char/broadcom/vc_mem.c | 422 +++++++++++++++++++++++++++
+ include/linux/broadcom/vc_mem.h | 35 +++
+ 6 files changed, 469 insertions(+), 467 deletions(-)
+ delete mode 100644 arch/arm/mach-bcm2709/include/mach/vc_mem.h
+ delete mode 100644 arch/arm/mach-bcm2709/vc_mem.c
+ create mode 100644 drivers/char/broadcom/vc_mem.c
+ create mode 100644 include/linux/broadcom/vc_mem.h
+
+--- a/arch/arm/mach-bcm2709/include/mach/vc_mem.h
++++ /dev/null
+@@ -1,35 +0,0 @@
+-/*****************************************************************************
+-* 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 */
+--- a/arch/arm/mach-bcm2709/vc_mem.c
++++ /dev/null
+@@ -1,431 +0,0 @@
+-/*****************************************************************************
+-* 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/drivers/char/broadcom/Kconfig
++++ b/drivers/char/broadcom/Kconfig
+@@ -7,9 +7,19 @@ menuconfig BRCM_CHAR_DRIVERS
+ help
+ Broadcom's char drivers
+
++if BRCM_CHAR_DRIVERS
++
+ config BCM_VC_CMA
+ bool "Videocore CMA"
+- depends on CMA && BRCM_CHAR_DRIVERS && BCM2708_VCHIQ
++ depends on CMA && BCM2708_VCHIQ
+ default n
+ help
+ Helper for videocore CMA access.
++
++config BCM2708_VCMEM
++ bool "Videocore Memory"
++ default y
++ help
++ Helper for videocore memory access and total size allocation.
++
++endif
+--- a/drivers/char/broadcom/Makefile
++++ b/drivers/char/broadcom/Makefile
+@@ -1 +1,2 @@
+ obj-$(CONFIG_BCM_VC_CMA) += vc_cma/
++obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o
+--- /dev/null
++++ b/drivers/char/broadcom/vc_mem.c
+@@ -0,0 +1,422 @@
++/*****************************************************************************
++* 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/broadcom/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);
+--- /dev/null
++++ b/include/linux/broadcom/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.
++*****************************************************************************/
++
++#ifndef _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 */
diff --git a/target/linux/brcm2708/patches-4.4/0038-vc_mem-Add-vc_mem-driver.patch b/target/linux/brcm2708/patches-4.4/0038-vc_mem-Add-vc_mem-driver.patch
deleted file mode 100644
index c8778b5adb..0000000000
--- a/target/linux/brcm2708/patches-4.4/0038-vc_mem-Add-vc_mem-driver.patch
+++ /dev/null
@@ -1,991 +0,0 @@
-From 2cabfc660c80dd79f24a8323b3913b5060ebf750 Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Wed, 17 Jun 2015 16:07:06 +0100
-Subject: [PATCH 038/170] vc_mem: Add vc_mem driver
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: popcornmix <popcornmix@gmail.com>
-
-BCM270x: Move vc_mem
-
-Make the vc_mem module available for ARCH_BCM2835 by moving it.
-
-Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
----
- arch/arm/mach-bcm2709/include/mach/vc_mem.h | 35 ---
- arch/arm/mach-bcm2709/vc_mem.c | 431 ----------------------------
- drivers/char/broadcom/Kconfig | 12 +-
- drivers/char/broadcom/Makefile | 1 +
- drivers/char/broadcom/vc_mem.c | 422 +++++++++++++++++++++++++++
- include/linux/broadcom/vc_mem.h | 35 +++
- 6 files changed, 469 insertions(+), 467 deletions(-)
- delete mode 100644 arch/arm/mach-bcm2709/include/mach/vc_mem.h
- delete mode 100644 arch/arm/mach-bcm2709/vc_mem.c
- create mode 100644 drivers/char/broadcom/vc_mem.c
- create mode 100644 include/linux/broadcom/vc_mem.h
-
---- a/arch/arm/mach-bcm2709/include/mach/vc_mem.h
-+++ /dev/null
-@@ -1,35 +0,0 @@
--/*****************************************************************************
--* 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 */
---- a/arch/arm/mach-bcm2709/vc_mem.c
-+++ /dev/null
-@@ -1,431 +0,0 @@
--/*****************************************************************************
--* 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/drivers/char/broadcom/Kconfig
-+++ b/drivers/char/broadcom/Kconfig
-@@ -7,9 +7,19 @@ menuconfig BRCM_CHAR_DRIVERS
- help
- Broadcom's char drivers
-
-+if BRCM_CHAR_DRIVERS
-+
- config BCM_VC_CMA
- bool "Videocore CMA"
-- depends on CMA && BRCM_CHAR_DRIVERS && BCM2708_VCHIQ
-+ depends on CMA && BCM2708_VCHIQ
- default n
- help
- Helper for videocore CMA access.
-+
-+config BCM2708_VCMEM
-+ bool "Videocore Memory"
-+ default y
-+ help
-+ Helper for videocore memory access and total size allocation.
-+
-+endif
---- a/drivers/char/broadcom/Makefile
-+++ b/drivers/char/broadcom/Makefile
-@@ -1 +1,2 @@
- obj-$(CONFIG_BCM_VC_CMA) += vc_cma/
-+obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o
---- /dev/null
-+++ b/drivers/char/broadcom/vc_mem.c
-@@ -0,0 +1,422 @@
-+/*****************************************************************************
-+* 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/broadcom/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);
---- /dev/null
-+++ b/include/linux/broadcom/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.
-+*****************************************************************************/
-+
-+#ifndef _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 */
diff --git a/target/linux/brcm2708/patches-4.4/0038-vcsm-VideoCore-shared-memory-service-for-BCM2835.patch b/target/linux/brcm2708/patches-4.4/0038-vcsm-VideoCore-shared-memory-service-for-BCM2835.patch
new file mode 100644
index 0000000000..4c3bd69251
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0038-vcsm-VideoCore-shared-memory-service-for-BCM2835.patch
@@ -0,0 +1,4393 @@
+From f5a5cd2721763f3759fc49d08f1b1ca0b039fcf2 Mon Sep 17 00:00:00 2001
+From: Tim Gover <tgover@broadcom.com>
+Date: Tue, 22 Jul 2014 15:41:04 +0100
+Subject: [PATCH 038/381] vcsm: VideoCore shared memory service for BCM2835
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add experimental support for the VideoCore shared memory service.
+This allows user processes to allocate memory from VideoCore's
+GPU relocatable heap and mmap the buffers. Additionally, the memory
+handles can passed to other VideoCore services such as MMAL, OpenMax
+and DispmanX
+
+TODO
+* This driver was originally released for BCM28155 which has a different
+ cache architecture to BCM2835. Consequently, in this release only
+ uncached mappings are supported. However, there's no fundamental
+ reason which cached mappings cannot be support or BCM2835
+* More refactoring is required to remove the typedefs.
+* Re-enable the some of the commented out debug-fs statistics which were
+ disabled when migrating code from proc-fs.
+* There's a lot of code to support sharing of VCSM in order to support
+ Android. This could probably done more cleanly or perhaps just
+ removed.
+
+Signed-off-by: Tim Gover <timgover@gmail.com>
+
+config: Disable VC_SM for now to fix hang with cutdown kernel
+
+vcsm: Use boolean as it cannot be built as module
+
+On building the bcm_vc_sm as a module we get the following error:
+
+v7_dma_flush_range and do_munmap are undefined in vc-sm.ko.
+
+Fix by making it not an option to build as module
+
+vcsm: Add ioctl for custom cache flushing
+
+vc-sm: Move headers out of arch directory
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+---
+ drivers/char/broadcom/Kconfig | 9 +
+ drivers/char/broadcom/Makefile | 1 +
+ drivers/char/broadcom/vc_sm/Makefile | 20 +
+ drivers/char/broadcom/vc_sm/vc_sm_defs.h | 181 ++
+ drivers/char/broadcom/vc_sm/vc_sm_knl.h | 55 +
+ drivers/char/broadcom/vc_sm/vc_vchi_sm.c | 492 +++++
+ drivers/char/broadcom/vc_sm/vc_vchi_sm.h | 82 +
+ drivers/char/broadcom/vc_sm/vmcs_sm.c | 3211 ++++++++++++++++++++++++++++++
+ include/linux/broadcom/vmcs_sm_ioctl.h | 248 +++
+ 9 files changed, 4299 insertions(+)
+ create mode 100644 drivers/char/broadcom/vc_sm/Makefile
+ create mode 100644 drivers/char/broadcom/vc_sm/vc_sm_defs.h
+ create mode 100644 drivers/char/broadcom/vc_sm/vc_sm_knl.h
+ create mode 100644 drivers/char/broadcom/vc_sm/vc_vchi_sm.c
+ create mode 100644 drivers/char/broadcom/vc_sm/vc_vchi_sm.h
+ create mode 100644 drivers/char/broadcom/vc_sm/vmcs_sm.c
+ create mode 100644 include/linux/broadcom/vmcs_sm_ioctl.h
+
+--- a/drivers/char/broadcom/Kconfig
++++ b/drivers/char/broadcom/Kconfig
+@@ -23,3 +23,12 @@ config BCM2708_VCMEM
+ Helper for videocore memory access and total size allocation.
+
+ endif
++
++config BCM_VC_SM
++ bool "VMCS Shared Memory"
++ depends on BCM2708_VCHIQ
++ select BCM2708_VCMEM
++ default n
++ help
++ Support for the VC shared memory on the Broadcom reference
++ design. Uses the VCHIQ stack.
+--- a/drivers/char/broadcom/Makefile
++++ b/drivers/char/broadcom/Makefile
+@@ -1,2 +1,3 @@
+ obj-$(CONFIG_BCM_VC_CMA) += vc_cma/
+ obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o
++obj-$(CONFIG_BCM_VC_SM) += vc_sm/
+--- /dev/null
++++ b/drivers/char/broadcom/vc_sm/Makefile
+@@ -0,0 +1,20 @@
++EXTRA_CFLAGS += -Wall -Wstrict-prototypes -Wno-trigraphs -O2
++
++EXTRA_CFLAGS += -I"drivers/misc/vc04_services"
++EXTRA_CFLAGS += -I"drivers/misc/vc04_services/interface/vchi"
++EXTRA_CFLAGS += -I"drivers/misc/vc04_services/interface/vchiq_arm"
++EXTRA_CFLAGS += -I"$(srctree)/fs/"
++
++EXTRA_CFLAGS += -DOS_ASSERT_FAILURE
++EXTRA_CFLAGS += -D__STDC_VERSION=199901L
++EXTRA_CFLAGS += -D__STDC_VERSION__=199901L
++EXTRA_CFLAGS += -D__VCCOREVER__=0
++EXTRA_CFLAGS += -D__KERNEL__
++EXTRA_CFLAGS += -D__linux__
++EXTRA_CFLAGS += -Werror
++
++obj-$(CONFIG_BCM_VC_SM) := vc-sm.o
++
++vc-sm-objs := \
++ vmcs_sm.o \
++ vc_vchi_sm.o
+--- /dev/null
++++ b/drivers/char/broadcom/vc_sm/vc_sm_defs.h
+@@ -0,0 +1,181 @@
++/*****************************************************************************
++* Copyright 2011 Broadcom Corporation. All rights reserved.
++*
++* Unless you and Broadcom execute a separate written software license
++* agreement governing use of this software, this software is licensed to you
++* under the terms of the GNU General Public License version 2, available at
++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
++*
++* Notwithstanding the above, under no circumstances may you combine this
++* software in any way with any other Broadcom software provided under a
++* license other than the GPL, without Broadcom's express prior written
++* consent.
++*****************************************************************************/
++
++#ifndef __VC_SM_DEFS_H__INCLUDED__
++#define __VC_SM_DEFS_H__INCLUDED__
++
++/* FourCC code used for VCHI connection */
++#define VC_SM_SERVER_NAME MAKE_FOURCC("SMEM")
++
++/* Maximum message length */
++#define VC_SM_MAX_MSG_LEN (sizeof(VC_SM_MSG_UNION_T) + \
++ sizeof(VC_SM_MSG_HDR_T))
++#define VC_SM_MAX_RSP_LEN (sizeof(VC_SM_MSG_UNION_T))
++
++/* Resource name maximum size */
++#define VC_SM_RESOURCE_NAME 32
++
++/* All message types supported for HOST->VC direction */
++typedef enum {
++ /* Allocate shared memory block */
++ VC_SM_MSG_TYPE_ALLOC,
++ /* Lock allocated shared memory block */
++ VC_SM_MSG_TYPE_LOCK,
++ /* Unlock allocated shared memory block */
++ VC_SM_MSG_TYPE_UNLOCK,
++ /* Unlock allocated shared memory block, do not answer command */
++ VC_SM_MSG_TYPE_UNLOCK_NOANS,
++ /* Free shared memory block */
++ VC_SM_MSG_TYPE_FREE,
++ /* Resize a shared memory block */
++ VC_SM_MSG_TYPE_RESIZE,
++ /* Walk the allocated shared memory block(s) */
++ VC_SM_MSG_TYPE_WALK_ALLOC,
++
++ /* A previously applied action will need to be reverted */
++ VC_SM_MSG_TYPE_ACTION_CLEAN,
++ VC_SM_MSG_TYPE_MAX
++} VC_SM_MSG_TYPE;
++
++/* Type of memory to be allocated */
++typedef enum {
++ VC_SM_ALLOC_CACHED,
++ VC_SM_ALLOC_NON_CACHED,
++
++} VC_SM_ALLOC_TYPE_T;
++
++/* Message header for all messages in HOST->VC direction */
++typedef struct {
++ int32_t type;
++ uint32_t trans_id;
++ uint8_t body[0];
++
++} VC_SM_MSG_HDR_T;
++
++/* Request to allocate memory (HOST->VC) */
++typedef struct {
++ /* type of memory to allocate */
++ VC_SM_ALLOC_TYPE_T type;
++ /* byte amount of data to allocate per unit */
++ uint32_t base_unit;
++ /* number of unit to allocate */
++ uint32_t num_unit;
++ /* alignement to be applied on allocation */
++ uint32_t alignement;
++ /* identity of who allocated this block */
++ uint32_t allocator;
++ /* resource name (for easier tracking on vc side) */
++ char name[VC_SM_RESOURCE_NAME];
++
++} VC_SM_ALLOC_T;
++
++/* Result of a requested memory allocation (VC->HOST) */
++typedef struct {
++ /* Transaction identifier */
++ uint32_t trans_id;
++
++ /* Resource handle */
++ uint32_t res_handle;
++ /* Pointer to resource buffer */
++ void *res_mem;
++ /* Resource base size (bytes) */
++ uint32_t res_base_size;
++ /* Resource number */
++ uint32_t res_num;
++
++} VC_SM_ALLOC_RESULT_T;
++
++/* Request to free a previously allocated memory (HOST->VC) */
++typedef struct {
++ /* Resource handle (returned from alloc) */
++ uint32_t res_handle;
++ /* Resource buffer (returned from alloc) */
++ void *res_mem;
++
++} VC_SM_FREE_T;
++
++/* Request to lock a previously allocated memory (HOST->VC) */
++typedef struct {
++ /* Resource handle (returned from alloc) */
++ uint32_t res_handle;
++ /* Resource buffer (returned from alloc) */
++ void *res_mem;
++
++} VC_SM_LOCK_UNLOCK_T;
++
++/* Request to resize a previously allocated memory (HOST->VC) */
++typedef struct {
++ /* Resource handle (returned from alloc) */
++ uint32_t res_handle;
++ /* Resource buffer (returned from alloc) */
++ void *res_mem;
++ /* Resource *new* size requested (bytes) */
++ uint32_t res_new_size;
++
++} VC_SM_RESIZE_T;
++
++/* Result of a requested memory lock (VC->HOST) */
++typedef struct {
++ /* Transaction identifier */
++ uint32_t trans_id;
++
++ /* Resource handle */
++ uint32_t res_handle;
++ /* Pointer to resource buffer */
++ void *res_mem;
++ /* Pointer to former resource buffer if the memory
++ * was reallocated */
++ void *res_old_mem;
++
++} VC_SM_LOCK_RESULT_T;
++
++/* Generic result for a request (VC->HOST) */
++typedef struct {
++ /* Transaction identifier */
++ uint32_t trans_id;
++
++ int32_t success;
++
++} VC_SM_RESULT_T;
++
++/* Request to revert a previously applied action (HOST->VC) */
++typedef struct {
++ /* Action of interest */
++ VC_SM_MSG_TYPE res_action;
++ /* Transaction identifier for the action of interest */
++ uint32_t action_trans_id;
++
++} VC_SM_ACTION_CLEAN_T;
++
++/* Request to remove all data associated with a given allocator (HOST->VC) */
++typedef struct {
++ /* Allocator identifier */
++ uint32_t allocator;
++
++} VC_SM_FREE_ALL_T;
++
++/* Union of ALL messages */
++typedef union {
++ VC_SM_ALLOC_T alloc;
++ VC_SM_ALLOC_RESULT_T alloc_result;
++ VC_SM_FREE_T free;
++ VC_SM_ACTION_CLEAN_T action_clean;
++ VC_SM_RESIZE_T resize;
++ VC_SM_LOCK_RESULT_T lock_result;
++ VC_SM_RESULT_T result;
++ VC_SM_FREE_ALL_T free_all;
++
++} VC_SM_MSG_UNION_T;
++
++#endif /* __VC_SM_DEFS_H__INCLUDED__ */
+--- /dev/null
++++ b/drivers/char/broadcom/vc_sm/vc_sm_knl.h
+@@ -0,0 +1,55 @@
++/*****************************************************************************
++* Copyright 2011 Broadcom Corporation. All rights reserved.
++*
++* Unless you and Broadcom execute a separate written software license
++* agreement governing use of this software, this software is licensed to you
++* under the terms of the GNU General Public License version 2, available at
++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
++*
++* Notwithstanding the above, under no circumstances may you combine this
++* software in any way with any other Broadcom software provided under a
++* license other than the GPL, without Broadcom's express prior written
++* consent.
++*****************************************************************************/
++
++#ifndef __VC_SM_KNL_H__INCLUDED__
++#define __VC_SM_KNL_H__INCLUDED__
++
++#if !defined(__KERNEL__)
++#error "This interface is for kernel use only..."
++#endif
++
++/* Type of memory to be locked (ie mapped) */
++typedef enum {
++ VC_SM_LOCK_CACHED,
++ VC_SM_LOCK_NON_CACHED,
++
++} VC_SM_LOCK_CACHE_MODE_T;
++
++/* Allocate a shared memory handle and block.
++*/
++int vc_sm_alloc(VC_SM_ALLOC_T *alloc, int *handle);
++
++/* Free a previously allocated shared memory handle and block.
++*/
++int vc_sm_free(int handle);
++
++/* Lock a memory handle for use by kernel.
++*/
++int vc_sm_lock(int handle, VC_SM_LOCK_CACHE_MODE_T mode,
++ long unsigned int *data);
++
++/* Unlock a memory handle in use by kernel.
++*/
++int vc_sm_unlock(int handle, int flush, int no_vc_unlock);
++
++/* Get an internal resource handle mapped from the external one.
++*/
++int vc_sm_int_handle(int handle);
++
++/* Map a shared memory region for use by kernel.
++*/
++int vc_sm_map(int handle, unsigned int sm_addr, VC_SM_LOCK_CACHE_MODE_T mode,
++ long unsigned int *data);
++
++#endif /* __VC_SM_KNL_H__INCLUDED__ */
+--- /dev/null
++++ b/drivers/char/broadcom/vc_sm/vc_vchi_sm.c
+@@ -0,0 +1,492 @@
++/*****************************************************************************
++* Copyright 2011-2012 Broadcom Corporation. All rights reserved.
++*
++* Unless you and Broadcom execute a separate written software license
++* agreement governing use of this software, this software is licensed to you
++* under the terms of the GNU General Public License version 2, available at
++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
++*
++* Notwithstanding the above, under no circumstances may you combine this
++* software in any way with any other Broadcom software provided under a
++* license other than the GPL, without Broadcom's express prior written
++* consent.
++*****************************************************************************/
++
++/* ---- Include Files ----------------------------------------------------- */
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/semaphore.h>
++#include <linux/mutex.h>
++#include <linux/slab.h>
++#include <linux/kthread.h>
++
++#include "vc_vchi_sm.h"
++
++#define VC_SM_VER 1
++#define VC_SM_MIN_VER 0
++
++/* ---- Private Constants and Types -------------------------------------- */
++
++/* Command blocks come from a pool */
++#define SM_MAX_NUM_CMD_RSP_BLKS 32
++
++struct sm_cmd_rsp_blk {
++ struct list_head head; /* To create lists */
++ struct semaphore sema; /* To be signaled when the response is there */
++
++ uint16_t id;
++ uint16_t length;
++
++ uint8_t msg[VC_SM_MAX_MSG_LEN];
++
++ uint32_t wait:1;
++ uint32_t sent:1;
++ uint32_t alloc:1;
++
++};
++
++struct sm_instance {
++ uint32_t num_connections;
++ VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS];
++ struct task_struct *io_thread;
++ struct semaphore io_sema;
++
++ uint32_t trans_id;
++
++ struct mutex lock;
++ struct list_head cmd_list;
++ struct list_head rsp_list;
++ struct list_head dead_list;
++
++ struct sm_cmd_rsp_blk free_blk[SM_MAX_NUM_CMD_RSP_BLKS];
++ struct list_head free_list;
++ struct mutex free_lock;
++ struct semaphore free_sema;
++
++};
++
++/* ---- Private Variables ------------------------------------------------ */
++
++/* ---- Private Function Prototypes -------------------------------------- */
++
++/* ---- Private Functions ------------------------------------------------ */
++static struct
++sm_cmd_rsp_blk *vc_vchi_cmd_create(struct sm_instance *instance,
++ VC_SM_MSG_TYPE id, void *msg,
++ uint32_t size, int wait)
++{
++ struct sm_cmd_rsp_blk *blk;
++ VC_SM_MSG_HDR_T *hdr;
++
++ if (down_interruptible(&instance->free_sema)) {
++ blk = kmalloc(sizeof(*blk), GFP_KERNEL);
++ if (!blk)
++ return NULL;
++
++ blk->alloc = 1;
++ sema_init(&blk->sema, 0);
++ } else {
++ mutex_lock(&instance->free_lock);
++ blk =
++ list_first_entry(&instance->free_list,
++ struct sm_cmd_rsp_blk, head);
++ list_del(&blk->head);
++ mutex_unlock(&instance->free_lock);
++ }
++
++ blk->sent = 0;
++ blk->wait = wait;
++ blk->length = sizeof(*hdr) + size;
++
++ hdr = (VC_SM_MSG_HDR_T *) blk->msg;
++ hdr->type = id;
++ mutex_lock(&instance->lock);
++ hdr->trans_id = blk->id = ++instance->trans_id;
++ mutex_unlock(&instance->lock);
++
++ if (size)
++ memcpy(hdr->body, msg, size);
++
++ return blk;
++}
++
++static void
++vc_vchi_cmd_delete(struct sm_instance *instance, struct sm_cmd_rsp_blk *blk)
++{
++ if (blk->alloc) {
++ kfree(blk);
++ return;
++ }
++
++ mutex_lock(&instance->free_lock);
++ list_add(&blk->head, &instance->free_list);
++ mutex_unlock(&instance->free_lock);
++ up(&instance->free_sema);
++}
++
++static int vc_vchi_sm_videocore_io(void *arg)
++{
++ struct sm_instance *instance = arg;
++ struct sm_cmd_rsp_blk *cmd = NULL, *cmd_tmp;
++ VC_SM_RESULT_T *reply;
++ uint32_t reply_len;
++ int32_t status;
++ int svc_use = 1;
++
++ while (1) {
++ if (svc_use)
++ vchi_service_release(instance->vchi_handle[0]);
++ svc_use = 0;
++ if (!down_interruptible(&instance->io_sema)) {
++ vchi_service_use(instance->vchi_handle[0]);
++ svc_use = 1;
++
++ do {
++ unsigned int flags;
++ /*
++ * Get new command and move it to response list
++ */
++ mutex_lock(&instance->lock);
++ if (list_empty(&instance->cmd_list)) {
++ /* no more commands to process */
++ mutex_unlock(&instance->lock);
++ break;
++ }
++ cmd =
++ list_first_entry(&instance->cmd_list,
++ struct sm_cmd_rsp_blk,
++ head);
++ list_move(&cmd->head, &instance->rsp_list);
++ cmd->sent = 1;
++ mutex_unlock(&instance->lock);
++
++ /* Send the command */
++ flags = VCHI_FLAGS_BLOCK_UNTIL_QUEUED;
++ status = vchi_msg_queue(
++ instance->vchi_handle[0],
++ cmd->msg, cmd->length,
++ flags, NULL);
++ if (status) {
++ pr_err("%s: failed to queue message (%d)",
++ __func__, status);
++ }
++
++ /* If no reply is needed then we're done */
++ if (!cmd->wait) {
++ mutex_lock(&instance->lock);
++ list_del(&cmd->head);
++ mutex_unlock(&instance->lock);
++ vc_vchi_cmd_delete(instance, cmd);
++ continue;
++ }
++
++ if (status) {
++ up(&cmd->sema);
++ continue;
++ }
++
++ } while (1);
++
++ while (!vchi_msg_peek
++ (instance->vchi_handle[0], (void **)&reply,
++ &reply_len, VCHI_FLAGS_NONE)) {
++ mutex_lock(&instance->lock);
++ list_for_each_entry(cmd, &instance->rsp_list,
++ head) {
++ if (cmd->id == reply->trans_id)
++ break;
++ }
++ mutex_unlock(&instance->lock);
++
++ if (&cmd->head == &instance->rsp_list) {
++ pr_debug("%s: received response %u, throw away...",
++ __func__, reply->trans_id);
++ } else if (reply_len > sizeof(cmd->msg)) {
++ pr_err("%s: reply too big (%u) %u, throw away...",
++ __func__, reply_len,
++ reply->trans_id);
++ } else {
++ memcpy(cmd->msg, reply, reply_len);
++ up(&cmd->sema);
++ }
++
++ vchi_msg_remove(instance->vchi_handle[0]);
++ }
++
++ /* Go through the dead list and free them */
++ mutex_lock(&instance->lock);
++ list_for_each_entry_safe(cmd, cmd_tmp,
++ &instance->dead_list, head) {
++ list_del(&cmd->head);
++ vc_vchi_cmd_delete(instance, cmd);
++ }
++ mutex_unlock(&instance->lock);
++ }
++ }
++
++ return 0;
++}
++
++static void vc_sm_vchi_callback(void *param,
++ const VCHI_CALLBACK_REASON_T reason,
++ void *msg_handle)
++{
++ struct sm_instance *instance = param;
++
++ (void)msg_handle;
++
++ switch (reason) {
++ case VCHI_CALLBACK_MSG_AVAILABLE:
++ up(&instance->io_sema);
++ break;
++
++ case VCHI_CALLBACK_SERVICE_CLOSED:
++ pr_info("%s: service CLOSED!!", __func__);
++ default:
++ break;
++ }
++}
++
++VC_VCHI_SM_HANDLE_T vc_vchi_sm_init(VCHI_INSTANCE_T vchi_instance,
++ VCHI_CONNECTION_T **vchi_connections,
++ uint32_t num_connections)
++{
++ uint32_t i;
++ struct sm_instance *instance;
++ int status;
++
++ pr_debug("%s: start", __func__);
++
++ if (num_connections > VCHI_MAX_NUM_CONNECTIONS) {
++ pr_err("%s: unsupported number of connections %u (max=%u)",
++ __func__, num_connections, VCHI_MAX_NUM_CONNECTIONS);
++
++ goto err_null;
++ }
++ /* Allocate memory for this instance */
++ instance = kzalloc(sizeof(*instance), GFP_KERNEL);
++
++ /* Misc initialisations */
++ mutex_init(&instance->lock);
++ sema_init(&instance->io_sema, 0);
++ INIT_LIST_HEAD(&instance->cmd_list);
++ INIT_LIST_HEAD(&instance->rsp_list);
++ INIT_LIST_HEAD(&instance->dead_list);
++ INIT_LIST_HEAD(&instance->free_list);
++ sema_init(&instance->free_sema, SM_MAX_NUM_CMD_RSP_BLKS);
++ mutex_init(&instance->free_lock);
++ for (i = 0; i < SM_MAX_NUM_CMD_RSP_BLKS; i++) {
++ sema_init(&instance->free_blk[i].sema, 0);
++ list_add(&instance->free_blk[i].head, &instance->free_list);
++ }
++
++ /* Open the VCHI service connections */
++ instance->num_connections = num_connections;
++ for (i = 0; i < num_connections; i++) {
++ SERVICE_CREATION_T params = {
++ VCHI_VERSION_EX(VC_SM_VER, VC_SM_MIN_VER),
++ VC_SM_SERVER_NAME,
++ vchi_connections[i],
++ 0,
++ 0,
++ vc_sm_vchi_callback,
++ instance,
++ 0,
++ 0,
++ 0,
++ };
++
++ status = vchi_service_open(vchi_instance,
++ &params, &instance->vchi_handle[i]);
++ if (status) {
++ pr_err("%s: failed to open VCHI service (%d)",
++ __func__, status);
++
++ goto err_close_services;
++ }
++ }
++
++ /* Create the thread which takes care of all io to/from videoocore. */
++ instance->io_thread = kthread_create(&vc_vchi_sm_videocore_io,
++ (void *)instance, "SMIO");
++ if (instance->io_thread == NULL) {
++ pr_err("%s: failed to create SMIO thread", __func__);
++
++ goto err_close_services;
++ }
++ set_user_nice(instance->io_thread, -10);
++ wake_up_process(instance->io_thread);
++
++ pr_debug("%s: success - instance 0x%x", __func__, (unsigned)instance);
++ return instance;
++
++err_close_services:
++ for (i = 0; i < instance->num_connections; i++) {
++ if (instance->vchi_handle[i] != NULL)
++ vchi_service_close(instance->vchi_handle[i]);
++ }
++ kfree(instance);
++err_null:
++ pr_debug("%s: FAILED", __func__);
++ return NULL;
++}
++
++int vc_vchi_sm_stop(VC_VCHI_SM_HANDLE_T *handle)
++{
++ struct sm_instance *instance;
++ uint32_t i;
++
++ if (handle == NULL) {
++ pr_err("%s: invalid pointer to handle %p", __func__, handle);
++ goto lock;
++ }
++
++ if (*handle == NULL) {
++ pr_err("%s: invalid handle %p", __func__, *handle);
++ goto lock;
++ }
++
++ instance = *handle;
++
++ /* Close all VCHI service connections */
++ for (i = 0; i < instance->num_connections; i++) {
++ int32_t success;
++ vchi_service_use(instance->vchi_handle[i]);
++
++ success = vchi_service_close(instance->vchi_handle[i]);
++ }
++
++ kfree(instance);
++
++ *handle = NULL;
++ return 0;
++
++lock:
++ return -EINVAL;
++}
++
++int vc_vchi_sm_send_msg(VC_VCHI_SM_HANDLE_T handle,
++ VC_SM_MSG_TYPE msg_id,
++ void *msg, uint32_t msg_size,
++ void *result, uint32_t result_size,
++ uint32_t *cur_trans_id, uint8_t wait_reply)
++{
++ int status = 0;
++ struct sm_instance *instance = handle;
++ struct sm_cmd_rsp_blk *cmd_blk;
++
++ if (handle == NULL) {
++ pr_err("%s: invalid handle", __func__);
++ return -EINVAL;
++ }
++ if (msg == NULL) {
++ pr_err("%s: invalid msg pointer", __func__);
++ return -EINVAL;
++ }
++
++ cmd_blk =
++ vc_vchi_cmd_create(instance, msg_id, msg, msg_size, wait_reply);
++ if (cmd_blk == NULL) {
++ pr_err("[%s]: failed to allocate global tracking resource",
++ __func__);
++ return -ENOMEM;
++ }
++
++ if (cur_trans_id != NULL)
++ *cur_trans_id = cmd_blk->id;
++
++ mutex_lock(&instance->lock);
++ list_add_tail(&cmd_blk->head, &instance->cmd_list);
++ mutex_unlock(&instance->lock);
++ up(&instance->io_sema);
++
++ if (!wait_reply)
++ /* We're done */
++ return 0;
++
++ /* Wait for the response */
++ if (down_interruptible(&cmd_blk->sema)) {
++ mutex_lock(&instance->lock);
++ if (!cmd_blk->sent) {
++ list_del(&cmd_blk->head);
++ mutex_unlock(&instance->lock);
++ vc_vchi_cmd_delete(instance, cmd_blk);
++ return -ENXIO;
++ }
++ mutex_unlock(&instance->lock);
++
++ mutex_lock(&instance->lock);
++ list_move(&cmd_blk->head, &instance->dead_list);
++ mutex_unlock(&instance->lock);
++ up(&instance->io_sema);
++ return -EINTR; /* We're done */
++ }
++
++ if (result && result_size) {
++ memcpy(result, cmd_blk->msg, result_size);
++ } else {
++ VC_SM_RESULT_T *res = (VC_SM_RESULT_T *) cmd_blk->msg;
++ status = (res->success == 0) ? 0 : -ENXIO;
++ }
++
++ mutex_lock(&instance->lock);
++ list_del(&cmd_blk->head);
++ mutex_unlock(&instance->lock);
++ vc_vchi_cmd_delete(instance, cmd_blk);
++ return status;
++}
++
++int vc_vchi_sm_alloc(VC_VCHI_SM_HANDLE_T handle, VC_SM_ALLOC_T *msg,
++ VC_SM_ALLOC_RESULT_T *result, uint32_t *cur_trans_id)
++{
++ return vc_vchi_sm_send_msg(handle, VC_SM_MSG_TYPE_ALLOC,
++ msg, sizeof(*msg), result, sizeof(*result),
++ cur_trans_id, 1);
++}
++
++int vc_vchi_sm_free(VC_VCHI_SM_HANDLE_T handle,
++ VC_SM_FREE_T *msg, uint32_t *cur_trans_id)
++{
++ return vc_vchi_sm_send_msg(handle, VC_SM_MSG_TYPE_FREE,
++ msg, sizeof(*msg), 0, 0, cur_trans_id, 0);
++}
++
++int vc_vchi_sm_lock(VC_VCHI_SM_HANDLE_T handle,
++ VC_SM_LOCK_UNLOCK_T *msg,
++ VC_SM_LOCK_RESULT_T *result, uint32_t *cur_trans_id)
++{
++ return vc_vchi_sm_send_msg(handle, VC_SM_MSG_TYPE_LOCK,
++ msg, sizeof(*msg), result, sizeof(*result),
++ cur_trans_id, 1);
++}
++
++int vc_vchi_sm_unlock(VC_VCHI_SM_HANDLE_T handle,
++ VC_SM_LOCK_UNLOCK_T *msg,
++ uint32_t *cur_trans_id, uint8_t wait_reply)
++{
++ return vc_vchi_sm_send_msg(handle, wait_reply ?
++ VC_SM_MSG_TYPE_UNLOCK :
++ VC_SM_MSG_TYPE_UNLOCK_NOANS, msg,
++ sizeof(*msg), 0, 0, cur_trans_id,
++ wait_reply);
++}
++
++int vc_vchi_sm_resize(VC_VCHI_SM_HANDLE_T handle, VC_SM_RESIZE_T *msg,
++ uint32_t *cur_trans_id)
++{
++ return vc_vchi_sm_send_msg(handle, VC_SM_MSG_TYPE_RESIZE,
++ msg, sizeof(*msg), 0, 0, cur_trans_id, 1);
++}
++
++int vc_vchi_sm_walk_alloc(VC_VCHI_SM_HANDLE_T handle)
++{
++ return vc_vchi_sm_send_msg(handle, VC_SM_MSG_TYPE_WALK_ALLOC,
++ 0, 0, 0, 0, 0, 0);
++}
++
++int vc_vchi_sm_clean_up(VC_VCHI_SM_HANDLE_T handle, VC_SM_ACTION_CLEAN_T *msg)
++{
++ return vc_vchi_sm_send_msg(handle, VC_SM_MSG_TYPE_ACTION_CLEAN,
++ msg, sizeof(*msg), 0, 0, 0, 0);
++}
+--- /dev/null
++++ b/drivers/char/broadcom/vc_sm/vc_vchi_sm.h
+@@ -0,0 +1,82 @@
++/*****************************************************************************
++* Copyright 2011 Broadcom Corporation. All rights reserved.
++*
++* Unless you and Broadcom execute a separate written software license
++* agreement governing use of this software, this software is licensed to you
++* under the terms of the GNU General Public License version 2, available at
++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
++*
++* Notwithstanding the above, under no circumstances may you combine this
++* software in any way with any other Broadcom software provided under a
++* license other than the GPL, without Broadcom's express prior written
++* consent.
++*****************************************************************************/
++
++#ifndef __VC_VCHI_SM_H__INCLUDED__
++#define __VC_VCHI_SM_H__INCLUDED__
++
++#include "interface/vchi/vchi.h"
++
++#include "vc_sm_defs.h"
++
++/* Forward declare.
++*/
++typedef struct sm_instance *VC_VCHI_SM_HANDLE_T;
++
++/* Initialize the shared memory service, opens up vchi connection to talk to it.
++*/
++VC_VCHI_SM_HANDLE_T vc_vchi_sm_init(VCHI_INSTANCE_T vchi_instance,
++ VCHI_CONNECTION_T **vchi_connections,
++ uint32_t num_connections);
++
++/* Terminates the shared memory service.
++*/
++int vc_vchi_sm_stop(VC_VCHI_SM_HANDLE_T *handle);
++
++/* Ask the shared memory service to allocate some memory on videocre and
++** return the result of this allocation (which upon success will be a pointer
++** to some memory in videocore space).
++*/
++int vc_vchi_sm_alloc(VC_VCHI_SM_HANDLE_T handle,
++ VC_SM_ALLOC_T *alloc,
++ VC_SM_ALLOC_RESULT_T *alloc_result, uint32_t *trans_id);
++
++/* Ask the shared memory service to free up some memory that was previously
++** allocated by the vc_vchi_sm_alloc function call.
++*/
++int vc_vchi_sm_free(VC_VCHI_SM_HANDLE_T handle,
++ VC_SM_FREE_T *free, uint32_t *trans_id);
++
++/* Ask the shared memory service to lock up some memory that was previously
++** allocated by the vc_vchi_sm_alloc function call.
++*/
++int vc_vchi_sm_lock(VC_VCHI_SM_HANDLE_T handle,
++ VC_SM_LOCK_UNLOCK_T *lock_unlock,
++ VC_SM_LOCK_RESULT_T *lock_result, uint32_t *trans_id);
++
++/* Ask the shared memory service to unlock some memory that was previously
++** allocated by the vc_vchi_sm_alloc function call.
++*/
++int vc_vchi_sm_unlock(VC_VCHI_SM_HANDLE_T handle,
++ VC_SM_LOCK_UNLOCK_T *lock_unlock,
++ uint32_t *trans_id, uint8_t wait_reply);
++
++/* Ask the shared memory service to resize some memory that was previously
++** allocated by the vc_vchi_sm_alloc function call.
++*/
++int vc_vchi_sm_resize(VC_VCHI_SM_HANDLE_T handle,
++ VC_SM_RESIZE_T *resize, uint32_t *trans_id);
++
++/* Walk the allocated resources on the videocore side, the allocation will
++** show up in the log. This is purely for debug/information and takes no
++** specific actions.
++*/
++int vc_vchi_sm_walk_alloc(VC_VCHI_SM_HANDLE_T handle);
++
++/* Clean up following a previously interrupted action which left the system
++** in a bad state of some sort.
++*/
++int vc_vchi_sm_clean_up(VC_VCHI_SM_HANDLE_T handle,
++ VC_SM_ACTION_CLEAN_T *action_clean);
++
++#endif /* __VC_VCHI_SM_H__INCLUDED__ */
+--- /dev/null
++++ b/drivers/char/broadcom/vc_sm/vmcs_sm.c
+@@ -0,0 +1,3211 @@
++/*****************************************************************************
++* Copyright 2011-2012 Broadcom Corporation. All rights reserved.
++*
++* Unless you and Broadcom execute a separate written software license
++* agreement governing use of this software, this software is licensed to you
++* under the terms of the GNU General Public License version 2, available at
++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
++*
++* Notwithstanding the above, under no circumstances may you combine this
++* software in any way with any other Broadcom software provided under a
++* license other than the GPL, without Broadcom's express prior written
++* consent.
++*****************************************************************************/
++
++/* ---- Include Files ----------------------------------------------------- */
++
++#include <linux/cdev.h>
++#include <linux/broadcom/vc_mem.h>
++#include <linux/device.h>
++#include <linux/debugfs.h>
++#include <linux/dma-mapping.h>
++#include <linux/errno.h>
++#include <linux/fs.h>
++#include <linux/hugetlb.h>
++#include <linux/ioctl.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/module.h>
++#include <linux/mm.h>
++#include <linux/pfn.h>
++#include <linux/proc_fs.h>
++#include <linux/pagemap.h>
++#include <linux/semaphore.h>
++#include <linux/slab.h>
++#include <linux/seq_file.h>
++#include <linux/types.h>
++#include <asm/cacheflush.h>
++
++#include "vchiq_connected.h"
++#include "vc_vchi_sm.h"
++
++#include <linux/broadcom/vmcs_sm_ioctl.h>
++#include "vc_sm_knl.h"
++
++/* ---- Private Constants and Types --------------------------------------- */
++
++#define DEVICE_NAME "vcsm"
++#define DEVICE_MINOR 0
++
++#define VC_SM_DIR_ROOT_NAME "vc-smem"
++#define VC_SM_DIR_ALLOC_NAME "alloc"
++#define VC_SM_STATE "state"
++#define VC_SM_STATS "statistics"
++#define VC_SM_RESOURCES "resources"
++#define VC_SM_DEBUG "debug"
++#define VC_SM_WRITE_BUF_SIZE 128
++
++/* Statistics tracked per resource and globally.
++*/
++enum SM_STATS_T {
++ /* Attempt. */
++ ALLOC,
++ FREE,
++ LOCK,
++ UNLOCK,
++ MAP,
++ FLUSH,
++ INVALID,
++
++ END_ATTEMPT,
++
++ /* Failure. */
++ ALLOC_FAIL,
++ FREE_FAIL,
++ LOCK_FAIL,
++ UNLOCK_FAIL,
++ MAP_FAIL,
++ FLUSH_FAIL,
++ INVALID_FAIL,
++
++ END_ALL,
++
++};
++
++static const char *const sm_stats_human_read[] = {
++ "Alloc",
++ "Free",
++ "Lock",
++ "Unlock",
++ "Map",
++ "Cache Flush",
++ "Cache Invalidate",
++};
++
++typedef int (*VC_SM_SHOW) (struct seq_file *s, void *v);
++struct SM_PDE_T {
++ VC_SM_SHOW show; /* Debug fs function hookup. */
++ struct dentry *dir_entry; /* Debug fs directory entry. */
++ void *priv_data; /* Private data */
++
++};
++
++/* Single resource allocation tracked for all devices.
++*/
++struct sm_mmap {
++ struct list_head map_list; /* Linked list of maps. */
++
++ struct SM_RESOURCE_T *resource; /* Pointer to the resource. */
++
++ pid_t res_pid; /* PID owning that resource. */
++ unsigned int res_vc_hdl; /* Resource handle (videocore). */
++ unsigned int res_usr_hdl; /* Resource handle (user). */
++
++ long unsigned int res_addr; /* Mapped virtual address. */
++ struct vm_area_struct *vma; /* VM area for this mapping. */
++ unsigned int ref_count; /* Reference count to this vma. */
++
++ /* Used to link maps associated with a resource. */
++ struct list_head resource_map_list;
++};
++
++/* Single resource allocation tracked for each opened device.
++*/
++struct SM_RESOURCE_T {
++ struct list_head resource_list; /* List of resources. */
++ struct list_head global_resource_list; /* Global list of resources. */
++
++ pid_t pid; /* PID owning that resource. */
++ uint32_t res_guid; /* Unique identifier. */
++ uint32_t lock_count; /* Lock count for this resource. */
++ uint32_t ref_count; /* Ref count for this resource. */
++
++ uint32_t res_handle; /* Resource allocation handle. */
++ void *res_base_mem; /* Resource base memory address. */
++ uint32_t res_size; /* Resource size allocated. */
++ enum vmcs_sm_cache_e res_cached; /* Resource cache type. */
++ struct SM_RESOURCE_T *res_shared; /* Shared resource */
++
++ enum SM_STATS_T res_stats[END_ALL]; /* Resource statistics. */
++
++ uint8_t map_count; /* Counter of mappings for this resource. */
++ struct list_head map_list; /* Maps associated with a resource. */
++
++ struct SM_PRIV_DATA_T *private;
++};
++
++/* Private file data associated with each opened device.
++*/
++struct SM_PRIV_DATA_T {
++ struct list_head resource_list; /* List of resources. */
++
++ pid_t pid; /* PID of creator. */
++
++ struct dentry *dir_pid; /* Debug fs entries root. */
++ struct SM_PDE_T dir_stats; /* Debug fs entries statistics sub-tree. */
++ struct SM_PDE_T dir_res; /* Debug fs resource sub-tree. */
++
++ int restart_sys; /* Tracks restart on interrupt. */
++ VC_SM_MSG_TYPE int_action; /* Interrupted action. */
++ uint32_t int_trans_id; /* Interrupted transaction. */
++
++};
++
++/* Global state information.
++*/
++struct SM_STATE_T {
++ VC_VCHI_SM_HANDLE_T sm_handle; /* Handle for videocore service. */
++ struct dentry *dir_root; /* Debug fs entries root. */
++ struct dentry *dir_alloc; /* Debug fs entries allocations. */
++ struct SM_PDE_T dir_stats; /* Debug fs entries statistics sub-tree. */
++ struct SM_PDE_T dir_state; /* Debug fs entries state sub-tree. */
++ struct dentry *debug; /* Debug fs entries debug. */
++
++ struct mutex map_lock; /* Global map lock. */
++ struct list_head map_list; /* List of maps. */
++ struct list_head resource_list; /* List of resources. */
++
++ enum SM_STATS_T deceased[END_ALL]; /* Natural termination stats. */
++ enum SM_STATS_T terminated[END_ALL]; /* Forced termination stats. */
++ uint32_t res_deceased_cnt; /* Natural termination counter. */
++ uint32_t res_terminated_cnt; /* Forced termination counter. */
++
++ struct cdev sm_cdev; /* Device. */
++ dev_t sm_devid; /* Device identifier. */
++ struct class *sm_class; /* Class. */
++ struct device *sm_dev; /* Device. */
++
++ struct SM_PRIV_DATA_T *data_knl; /* Kernel internal data tracking. */
++
++ struct mutex lock; /* Global lock. */
++ uint32_t guid; /* GUID (next) tracker. */
++
++};
++
++/* ---- Private Variables ----------------------------------------------- */
++
++static struct SM_STATE_T *sm_state;
++static int sm_inited;
++
++static const char *const sm_cache_map_vector[] = {
++ "(null)",
++ "host",
++ "videocore",
++ "host+videocore",
++};
++
++/* ---- Private Function Prototypes -------------------------------------- */
++
++/* ---- Private Functions ------------------------------------------------ */
++
++static inline unsigned vcaddr_to_pfn(unsigned long vc_addr)
++{
++ unsigned long pfn = vc_addr & 0x3FFFFFFF;
++ pfn += mm_vc_mem_phys_addr;
++ pfn >>= PAGE_SHIFT;
++ return pfn;
++}
++
++/* Carries over to the state statistics the statistics once owned by a deceased
++** resource.
++*/
++static void vc_sm_resource_deceased(struct SM_RESOURCE_T *p_res, int terminated)
++{
++ if (sm_state != NULL) {
++ if (p_res != NULL) {
++ int ix;
++
++ if (terminated)
++ sm_state->res_terminated_cnt++;
++ else
++ sm_state->res_deceased_cnt++;
++
++ for (ix = 0; ix < END_ALL; ix++) {
++ if (terminated)
++ sm_state->terminated[ix] +=
++ p_res->res_stats[ix];
++ else
++ sm_state->deceased[ix] +=
++ p_res->res_stats[ix];
++ }
++ }
++ }
++}
++
++/* Fetch a videocore handle corresponding to a mapping of the pid+address
++** returns 0 (ie NULL) if no such handle exists in the global map.
++*/
++static unsigned int vmcs_sm_vc_handle_from_pid_and_address(unsigned int pid,
++ unsigned int addr)
++{
++ struct sm_mmap *map = NULL;
++ unsigned int handle = 0;
++
++ if (!sm_state || addr == 0)
++ goto out;
++
++ mutex_lock(&(sm_state->map_lock));
++
++ /* Lookup the resource.
++ */
++ if (!list_empty(&sm_state->map_list)) {
++ list_for_each_entry(map, &sm_state->map_list, map_list) {
++ if (map->res_pid != pid || map->res_addr != addr)
++ continue;
++
++ pr_debug("[%s]: global map %p (pid %u, addr %lx) -> vc-hdl %x (usr-hdl %x)\n",
++ __func__, map, map->res_pid, map->res_addr,
++ map->res_vc_hdl, map->res_usr_hdl);
++
++ handle = map->res_vc_hdl;
++ break;
++ }
++ }
++
++ mutex_unlock(&(sm_state->map_lock));
++
++out:
++ /* Use a debug log here as it may be a valid situation that we query
++ ** for something that is not mapped, we do not want a kernel log each
++ ** time around.
++ **
++ ** There are other error log that would pop up accordingly if someone
++ ** subsequently tries to use something invalid after being told not to
++ ** use it...
++ */
++ if (handle == 0) {
++ pr_debug("[%s]: not a valid map (pid %u, addr %x)\n",
++ __func__, pid, addr);
++ }
++
++ return handle;
++}
++
++/* Fetch a user handle corresponding to a mapping of the pid+address
++** returns 0 (ie NULL) if no such handle exists in the global map.
++*/
++static unsigned int vmcs_sm_usr_handle_from_pid_and_address(unsigned int pid,
++ unsigned int addr)
++{
++ struct sm_mmap *map = NULL;
++ unsigned int handle = 0;
++
++ if (!sm_state || addr == 0)
++ goto out;
++
++ mutex_lock(&(sm_state->map_lock));
++
++ /* Lookup the resource.
++ */
++ if (!list_empty(&sm_state->map_list)) {
++ list_for_each_entry(map, &sm_state->map_list, map_list) {
++ if (map->res_pid != pid || map->res_addr != addr)
++ continue;
++
++ pr_debug("[%s]: global map %p (pid %u, addr %lx) -> usr-hdl %x (vc-hdl %x)\n",
++ __func__, map, map->res_pid, map->res_addr,
++ map->res_usr_hdl, map->res_vc_hdl);
++
++ handle = map->res_usr_hdl;
++ break;
++ }
++ }
++
++ mutex_unlock(&(sm_state->map_lock));
++
++out:
++ /* Use a debug log here as it may be a valid situation that we query
++ * for something that is not mapped yet.
++ *
++ * There are other error log that would pop up accordingly if someone
++ * subsequently tries to use something invalid after being told not to
++ * use it...
++ */
++ if (handle == 0)
++ pr_debug("[%s]: not a valid map (pid %u, addr %x)\n",
++ __func__, pid, addr);
++
++ return handle;
++}
++
++#if defined(DO_NOT_USE)
++/* Fetch an address corresponding to a mapping of the pid+handle
++** returns 0 (ie NULL) if no such address exists in the global map.
++*/
++static unsigned int vmcs_sm_usr_address_from_pid_and_vc_handle(unsigned int pid,
++ unsigned int hdl)
++{
++ struct sm_mmap *map = NULL;
++ unsigned int addr = 0;
++
++ if (sm_state == NULL || hdl == 0)
++ goto out;
++
++ mutex_lock(&(sm_state->map_lock));
++
++ /* Lookup the resource.
++ */
++ if (!list_empty(&sm_state->map_list)) {
++ list_for_each_entry(map, &sm_state->map_list, map_list) {
++ if (map->res_pid != pid || map->res_vc_hdl != hdl)
++ continue;
++
++ pr_debug("[%s]: global map %p (pid %u, vc-hdl %x, usr-hdl %x) -> addr %lx\n",
++ __func__, map, map->res_pid, map->res_vc_hdl,
++ map->res_usr_hdl, map->res_addr);
++
++ addr = map->res_addr;
++ break;
++ }
++ }
++
++ mutex_unlock(&(sm_state->map_lock));
++
++out:
++ /* Use a debug log here as it may be a valid situation that we query
++ ** for something that is not mapped, we do not want a kernel log each
++ ** time around.
++ **
++ ** There are other error log that would pop up accordingly if someone
++ ** subsequently tries to use something invalid after being told not to
++ ** use it...
++ */
++ if (addr == 0)
++ pr_debug("[%s]: not a valid map (pid %u, hdl %x)\n",
++ __func__, pid, hdl);
++
++ return addr;
++}
++#endif
++
++/* Fetch an address corresponding to a mapping of the pid+handle
++** returns 0 (ie NULL) if no such address exists in the global map.
++*/
++static unsigned int vmcs_sm_usr_address_from_pid_and_usr_handle(unsigned int
++ pid,
++ unsigned int
++ hdl)
++{
++ struct sm_mmap *map = NULL;
++ unsigned int addr = 0;
++
++ if (sm_state == NULL || hdl == 0)
++ goto out;
++
++ mutex_lock(&(sm_state->map_lock));
++
++ /* Lookup the resource.
++ */
++ if (!list_empty(&sm_state->map_list)) {
++ list_for_each_entry(map, &sm_state->map_list, map_list) {
++ if (map->res_pid != pid || map->res_usr_hdl != hdl)
++ continue;
++
++ pr_debug("[%s]: global map %p (pid %u, vc-hdl %x, usr-hdl %x) -> addr %lx\n",
++ __func__, map, map->res_pid, map->res_vc_hdl,
++ map->res_usr_hdl, map->res_addr);
++
++ addr = map->res_addr;
++ break;
++ }
++ }
++
++ mutex_unlock(&(sm_state->map_lock));
++
++out:
++ /* Use a debug log here as it may be a valid situation that we query
++ * for something that is not mapped, we do not want a kernel log each
++ * time around.
++ *
++ * There are other error log that would pop up accordingly if someone
++ * subsequently tries to use something invalid after being told not to
++ * use it...
++ */
++ if (addr == 0)
++ pr_debug("[%s]: not a valid map (pid %u, hdl %x)\n", __func__,
++ pid, hdl);
++
++ return addr;
++}
++
++/* Adds a resource mapping to the global data list.
++*/
++static void vmcs_sm_add_map(struct SM_STATE_T *state,
++ struct SM_RESOURCE_T *resource, struct sm_mmap *map)
++{
++ mutex_lock(&(state->map_lock));
++
++ /* Add to the global list of mappings
++ */
++ list_add(&map->map_list, &state->map_list);
++
++ /* Add to the list of mappings for this resource
++ */
++ list_add(&map->resource_map_list, &resource->map_list);
++ resource->map_count++;
++
++ mutex_unlock(&(state->map_lock));
++
++ pr_debug("[%s]: added map %p (pid %u, vc-hdl %x, usr-hdl %x, addr %lx)\n",
++ __func__, map, map->res_pid, map->res_vc_hdl,
++ map->res_usr_hdl, map->res_addr);
++}
++
++/* Removes a resource mapping from the global data list.
++*/
++static void vmcs_sm_remove_map(struct SM_STATE_T *state,
++ struct SM_RESOURCE_T *resource,
++ struct sm_mmap *map)
++{
++ mutex_lock(&(state->map_lock));
++
++ /* Remove from the global list of mappings
++ */
++ list_del(&map->map_list);
++
++ /* Remove from the list of mapping for this resource
++ */
++ list_del(&map->resource_map_list);
++ if (resource->map_count > 0)
++ resource->map_count--;
++
++ mutex_unlock(&(state->map_lock));
++
++ pr_debug("[%s]: removed map %p (pid %d, vc-hdl %x, usr-hdl %x, addr %lx)\n",
++ __func__, map, map->res_pid, map->res_vc_hdl, map->res_usr_hdl,
++ map->res_addr);
++
++ kfree(map);
++}
++
++/* Read callback for the global state proc entry.
++*/
++static int vc_sm_global_state_show(struct seq_file *s, void *v)
++{
++ struct sm_mmap *map = NULL;
++ int map_count = 0;
++
++ if (sm_state == NULL)
++ return 0;
++
++ seq_printf(s, "\nVC-ServiceHandle 0x%x\n",
++ (unsigned int)sm_state->sm_handle);
++
++ /* Log all applicable mapping(s).
++ */
++
++ mutex_lock(&(sm_state->map_lock));
++
++ if (!list_empty(&sm_state->map_list)) {
++ list_for_each_entry(map, &sm_state->map_list, map_list) {
++ map_count++;
++
++ seq_printf(s, "\nMapping 0x%x\n",
++ (unsigned int)map);
++ seq_printf(s, " TGID %u\n",
++ map->res_pid);
++ seq_printf(s, " VC-HDL 0x%x\n",
++ map->res_vc_hdl);
++ seq_printf(s, " USR-HDL 0x%x\n",
++ map->res_usr_hdl);
++ seq_printf(s, " USR-ADDR 0x%lx\n",
++ map->res_addr);
++ }
++ }
++
++ mutex_unlock(&(sm_state->map_lock));
++ seq_printf(s, "\n\nTotal map count: %d\n\n", map_count);
++
++ return 0;
++}
++
++static int vc_sm_global_statistics_show(struct seq_file *s, void *v)
++{
++ int ix;
++
++ /* Global state tracked statistics.
++ */
++ if (sm_state != NULL) {
++ seq_puts(s, "\nDeceased Resources Statistics\n");
++
++ seq_printf(s, "\nNatural Cause (%u occurences)\n",
++ sm_state->res_deceased_cnt);
++ for (ix = 0; ix < END_ATTEMPT; ix++) {
++ if (sm_state->deceased[ix] > 0) {
++ seq_printf(s, " %u\t%s\n",
++ sm_state->deceased[ix],
++ sm_stats_human_read[ix]);
++ }
++ }
++ seq_puts(s, "\n");
++ for (ix = 0; ix < END_ATTEMPT; ix++) {
++ if (sm_state->deceased[ix + END_ATTEMPT] > 0) {
++ seq_printf(s, " %u\tFAILED %s\n",
++ sm_state->deceased[ix + END_ATTEMPT],
++ sm_stats_human_read[ix]);
++ }
++ }
++
++ seq_printf(s, "\nForcefull (%u occurences)\n",
++ sm_state->res_terminated_cnt);
++ for (ix = 0; ix < END_ATTEMPT; ix++) {
++ if (sm_state->terminated[ix] > 0) {
++ seq_printf(s, " %u\t%s\n",
++ sm_state->terminated[ix],
++ sm_stats_human_read[ix]);
++ }
++ }
++ seq_puts(s, "\n");
++ for (ix = 0; ix < END_ATTEMPT; ix++) {
++ if (sm_state->terminated[ix + END_ATTEMPT] > 0) {
++ seq_printf(s, " %u\tFAILED %s\n",
++ sm_state->terminated[ix +
++ END_ATTEMPT],
++ sm_stats_human_read[ix]);
++ }
++ }
++ }
++
++ return 0;
++}
++
++#if 0
++/* Read callback for the statistics proc entry.
++*/
++static int vc_sm_statistics_show(struct seq_file *s, void *v)
++{
++ int ix;
++ struct SM_PRIV_DATA_T *file_data;
++ struct SM_RESOURCE_T *resource;
++ int res_count = 0;
++ struct SM_PDE_T *p_pde;
++
++ p_pde = (struct SM_PDE_T *)(s->private);
++ file_data = (struct SM_PRIV_DATA_T *)(p_pde->priv_data);
++
++ if (file_data == NULL)
++ return 0;
++
++ /* Per process statistics.
++ */
++
++ seq_printf(s, "\nStatistics for TGID %d\n", file_data->pid);
++
++ mutex_lock(&(sm_state->map_lock));
++
++ if (!list_empty(&file_data->resource_list)) {
++ list_for_each_entry(resource, &file_data->resource_list,
++ resource_list) {
++ res_count++;
++
++ seq_printf(s, "\nGUID: 0x%x\n\n",
++ resource->res_guid);
++ for (ix = 0; ix < END_ATTEMPT; ix++) {
++ if (resource->res_stats[ix] > 0) {
++ seq_printf(s,
++ " %u\t%s\n",
++ resource->res_stats[ix],
++ sm_stats_human_read[ix]);
++ }
++ }
++ seq_puts(s, "\n");
++ for (ix = 0; ix < END_ATTEMPT; ix++) {
++ if (resource->res_stats[ix + END_ATTEMPT] > 0) {
++ seq_printf(s,
++ " %u\tFAILED %s\n",
++ resource->res_stats[
++ ix + END_ATTEMPT],
++ sm_stats_human_read[ix]);
++ }
++ }
++ }
++ }
++
++ mutex_unlock(&(sm_state->map_lock));
++
++ seq_printf(s, "\nResources Count %d\n", res_count);
++
++ return 0;
++}
++#endif
++
++#if 0
++/* Read callback for the allocation proc entry. */
++static int vc_sm_alloc_show(struct seq_file *s, void *v)
++{
++ struct SM_PRIV_DATA_T *file_data;
++ struct SM_RESOURCE_T *resource;
++ int alloc_count = 0;
++ struct SM_PDE_T *p_pde;
++
++ p_pde = (struct SM_PDE_T *)(s->private);
++ file_data = (struct SM_PRIV_DATA_T *)(p_pde->priv_data);
++
++ if (!file_data)
++ return 0;
++
++ /* Per process statistics. */
++ seq_printf(s, "\nAllocation for TGID %d\n", file_data->pid);
++
++ mutex_lock(&(sm_state->map_lock));
++
++ if (!list_empty(&file_data->resource_list)) {
++ list_for_each_entry(resource, &file_data->resource_list,
++ resource_list) {
++ alloc_count++;
++
++ seq_printf(s, "\nGUID: 0x%x\n",
++ resource->res_guid);
++ seq_printf(s, "Lock Count: %u\n",
++ resource->lock_count);
++ seq_printf(s, "Mapped: %s\n",
++ (resource->map_count ? "yes" : "no"));
++ seq_printf(s, "VC-handle: 0x%x\n",
++ resource->res_handle);
++ seq_printf(s, "VC-address: 0x%p\n",
++ resource->res_base_mem);
++ seq_printf(s, "VC-size (bytes): %u\n",
++ resource->res_size);
++ seq_printf(s, "Cache: %s\n",
++ sm_cache_map_vector[resource->res_cached]);
++ }
++ }
++
++ mutex_unlock(&(sm_state->map_lock));
++
++ seq_printf(s, "\n\nTotal allocation count: %d\n\n", alloc_count);
++
++ return 0;
++}
++#endif
++
++static int vc_sm_seq_file_show(struct seq_file *s, void *v)
++{
++ struct SM_PDE_T *sm_pde;
++
++ sm_pde = (struct SM_PDE_T *)(s->private);
++
++ if (sm_pde && sm_pde->show)
++ sm_pde->show(s, v);
++
++ return 0;
++}
++
++static int vc_sm_single_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, vc_sm_seq_file_show, inode->i_private);
++}
++
++static const struct file_operations vc_sm_debug_fs_fops = {
++ .open = vc_sm_single_open,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++
++/* Adds a resource to the private data list which tracks all the allocated
++** data.
++*/
++static void vmcs_sm_add_resource(struct SM_PRIV_DATA_T *privdata,
++ struct SM_RESOURCE_T *resource)
++{
++ mutex_lock(&(sm_state->map_lock));
++ list_add(&resource->resource_list, &privdata->resource_list);
++ list_add(&resource->global_resource_list, &sm_state->resource_list);
++ mutex_unlock(&(sm_state->map_lock));
++
++ pr_debug("[%s]: added resource %p (base addr %p, hdl %x, size %u, cache %u)\n",
++ __func__, resource, resource->res_base_mem,
++ resource->res_handle, resource->res_size, resource->res_cached);
++}
++
++/* Locates a resource and acquire a reference on it.
++** The resource won't be deleted while there is a reference on it.
++*/
++static struct SM_RESOURCE_T *vmcs_sm_acquire_resource(struct SM_PRIV_DATA_T
++ *private,
++ unsigned int res_guid)
++{
++ struct SM_RESOURCE_T *resource, *ret = NULL;
++
++ mutex_lock(&(sm_state->map_lock));
++
++ list_for_each_entry(resource, &private->resource_list, resource_list) {
++ if (resource->res_guid != res_guid)
++ continue;
++
++ pr_debug("[%s]: located resource %p (guid: %x, base addr %p, hdl %x, size %u, cache %u)\n",
++ __func__, resource, resource->res_guid,
++ resource->res_base_mem, resource->res_handle,
++ resource->res_size, resource->res_cached);
++ resource->ref_count++;
++ ret = resource;
++ break;
++ }
++
++ mutex_unlock(&(sm_state->map_lock));
++
++ return ret;
++}
++
++/* Locates a resource and acquire a reference on it.
++** The resource won't be deleted while there is a reference on it.
++*/
++static struct SM_RESOURCE_T *vmcs_sm_acquire_first_resource(
++ struct SM_PRIV_DATA_T *private)
++{
++ struct SM_RESOURCE_T *resource, *ret = NULL;
++
++ mutex_lock(&(sm_state->map_lock));
++
++ list_for_each_entry(resource, &private->resource_list, resource_list) {
++ pr_debug("[%s]: located resource %p (guid: %x, base addr %p, hdl %x, size %u, cache %u)\n",
++ __func__, resource, resource->res_guid,
++ resource->res_base_mem, resource->res_handle,
++ resource->res_size, resource->res_cached);
++ resource->ref_count++;
++ ret = resource;
++ break;
++ }
++
++ mutex_unlock(&(sm_state->map_lock));
++
++ return ret;
++}
++
++/* Locates a resource and acquire a reference on it.
++** The resource won't be deleted while there is a reference on it.
++*/
++static struct SM_RESOURCE_T *vmcs_sm_acquire_global_resource(unsigned int
++ res_guid)
++{
++ struct SM_RESOURCE_T *resource, *ret = NULL;
++
++ mutex_lock(&(sm_state->map_lock));
++
++ list_for_each_entry(resource, &sm_state->resource_list,
++ global_resource_list) {
++ if (resource->res_guid != res_guid)
++ continue;
++
++ pr_debug("[%s]: located resource %p (guid: %x, base addr %p, hdl %x, size %u, cache %u)\n",
++ __func__, resource, resource->res_guid,
++ resource->res_base_mem, resource->res_handle,
++ resource->res_size, resource->res_cached);
++ resource->ref_count++;
++ ret = resource;
++ break;
++ }
++
++ mutex_unlock(&(sm_state->map_lock));
++
++ return ret;
++}
++
++/* Release a previously acquired resource.
++** The resource will be deleted when its refcount reaches 0.
++*/
++static void vmcs_sm_release_resource(struct SM_RESOURCE_T *resource, int force)
++{
++ struct SM_PRIV_DATA_T *private = resource->private;
++ struct sm_mmap *map, *map_tmp;
++ struct SM_RESOURCE_T *res_tmp;
++ int ret;
++
++ mutex_lock(&(sm_state->map_lock));
++
++ if (--resource->ref_count) {
++ if (force)
++ pr_err("[%s]: resource %p in use\n", __func__, resource);
++
++ mutex_unlock(&(sm_state->map_lock));
++ return;
++ }
++
++ /* Time to free the resource. Start by removing it from the list */
++ list_del(&resource->resource_list);
++ list_del(&resource->global_resource_list);
++
++ /* Walk the global resource list, find out if the resource is used
++ * somewhere else. In which case we don't want to delete it.
++ */
++ list_for_each_entry(res_tmp, &sm_state->resource_list,
++ global_resource_list) {
++ if (res_tmp->res_handle == resource->res_handle) {
++ resource->res_handle = 0;
++ break;
++ }
++ }
++
++ mutex_unlock(&(sm_state->map_lock));
++
++ pr_debug("[%s]: freeing data - guid %x, hdl %x, base address %p\n",
++ __func__, resource->res_guid, resource->res_handle,
++ resource->res_base_mem);
++ resource->res_stats[FREE]++;
++
++ /* Make sure the resource we're removing is unmapped first */
++ if (resource->map_count && !list_empty(&resource->map_list)) {
++ down_write(&current->mm->mmap_sem);
++ list_for_each_entry_safe(map, map_tmp, &resource->map_list,
++ resource_map_list) {
++ ret =
++ do_munmap(current->mm, map->res_addr,
++ resource->res_size);
++ if (ret) {
++ pr_err("[%s]: could not unmap resource %p\n",
++ __func__, resource);
++ }
++ }
++ up_write(&current->mm->mmap_sem);
++ }
++
++ /* Free up the videocore allocated resource.
++ */
++ if (resource->res_handle) {
++ VC_SM_FREE_T free = {
++ resource->res_handle, resource->res_base_mem
++ };
++ int status = vc_vchi_sm_free(sm_state->sm_handle, &free,
++ &private->int_trans_id);
++ if (status != 0 && status != -EINTR) {
++ pr_err("[%s]: failed to free memory on videocore (status: %u, trans_id: %u)\n",
++ __func__, status, private->int_trans_id);
++ resource->res_stats[FREE_FAIL]++;
++ ret = -EPERM;
++ }
++ }
++
++ /* Free up the shared resource.
++ */
++ if (resource->res_shared)
++ vmcs_sm_release_resource(resource->res_shared, 0);
++
++ /* Free up the local resource tracking this allocation.
++ */
++ vc_sm_resource_deceased(resource, force);
++ kfree(resource);
++}
++
++/* Dump the map table for the driver. If process is -1, dumps the whole table,
++** if process is a valid pid (non -1) dump only the entries associated with the
++** pid of interest.
++*/
++static void vmcs_sm_host_walk_map_per_pid(int pid)
++{
++ struct sm_mmap *map = NULL;
++
++ /* Make sure the device was started properly.
++ */
++ if (sm_state == NULL) {
++ pr_err("[%s]: invalid device\n", __func__);
++ return;
++ }
++
++ mutex_lock(&(sm_state->map_lock));
++
++ /* Log all applicable mapping(s).
++ */
++ if (!list_empty(&sm_state->map_list)) {
++ list_for_each_entry(map, &sm_state->map_list, map_list) {
++ if (pid == -1 || map->res_pid == pid) {
++ pr_info("[%s]: tgid: %u - vc-hdl: %x, usr-hdl: %x, usr-addr: %lx\n",
++ __func__, map->res_pid, map->res_vc_hdl,
++ map->res_usr_hdl, map->res_addr);
++ }
++ }
++ }
++
++ mutex_unlock(&(sm_state->map_lock));
++
++ return;
++}
++
++/* Dump the allocation table from host side point of view. This only dumps the
++** data allocated for this process/device referenced by the file_data.
++*/
++static void vmcs_sm_host_walk_alloc(struct SM_PRIV_DATA_T *file_data)
++{
++ struct SM_RESOURCE_T *resource = NULL;
++
++ /* Make sure the device was started properly.
++ */
++ if ((sm_state == NULL) || (file_data == NULL)) {
++ pr_err("[%s]: invalid device\n", __func__);
++ return;
++ }
++
++ mutex_lock(&(sm_state->map_lock));
++
++ if (!list_empty(&file_data->resource_list)) {
++ list_for_each_entry(resource, &file_data->resource_list,
++ resource_list) {
++ pr_info("[%s]: guid: %x - hdl: %x, vc-mem: %p, size: %u, cache: %u\n",
++ __func__, resource->res_guid, resource->res_handle,
++ resource->res_base_mem, resource->res_size,
++ resource->res_cached);
++ }
++ }
++
++ mutex_unlock(&(sm_state->map_lock));
++
++ return;
++}
++
++/* Create support for private data tracking.
++*/
++static struct SM_PRIV_DATA_T *vc_sm_create_priv_data(pid_t id)
++{
++ char alloc_name[32];
++ struct SM_PRIV_DATA_T *file_data = NULL;
++
++ /* Allocate private structure. */
++ file_data = kzalloc(sizeof(*file_data), GFP_KERNEL);
++
++ if (!file_data) {
++ pr_err("[%s]: cannot allocate file data\n", __func__);
++ goto out;
++ }
++
++ snprintf(alloc_name, sizeof(alloc_name), "%d", id);
++
++ INIT_LIST_HEAD(&file_data->resource_list);
++ file_data->pid = id;
++ file_data->dir_pid = debugfs_create_dir(alloc_name,
++ sm_state->dir_alloc);
++#if 0
++ /* TODO: fix this to support querying statistics per pid */
++
++ if (IS_ERR_OR_NULL(file_data->dir_pid)) {
++ file_data->dir_pid = NULL;
++ } else {
++ struct dentry *dir_entry;
++
++ dir_entry = debugfs_create_file(VC_SM_RESOURCES, S_IRUGO,
++ file_data->dir_pid, file_data,
++ vc_sm_debug_fs_fops);
++
++ file_data->dir_res.dir_entry = dir_entry;
++ file_data->dir_res.priv_data = file_data;
++ file_data->dir_res.show = &vc_sm_alloc_show;
++
++ dir_entry = debugfs_create_file(VC_SM_STATS, S_IRUGO,
++ file_data->dir_pid, file_data,
++ vc_sm_debug_fs_fops);
++
++ file_data->dir_res.dir_entry = dir_entry;
++ file_data->dir_res.priv_data = file_data;
++ file_data->dir_res.show = &vc_sm_statistics_show;
++ }
++ pr_debug("[%s]: private data allocated %p\n", __func__, file_data);
++
++#endif
++out:
++ return file_data;
++}
++
++/* Open the device. Creates a private state to help track all allocation
++** associated with this device.
++*/
++static int vc_sm_open(struct inode *inode, struct file *file)
++{
++ int ret = 0;
++
++ /* Make sure the device was started properly.
++ */
++ if (!sm_state) {
++ pr_err("[%s]: invalid device\n", __func__);
++ ret = -EPERM;
++ goto out;
++ }
++
++ file->private_data = vc_sm_create_priv_data(current->tgid);
++ if (file->private_data == NULL) {
++ pr_err("[%s]: failed to create data tracker\n", __func__);
++
++ ret = -ENOMEM;
++ goto out;
++ }
++
++out:
++ return ret;
++}
++
++/* Close the device. Free up all resources still associated with this device
++** at the time.
++*/
++static int vc_sm_release(struct inode *inode, struct file *file)
++{
++ struct SM_PRIV_DATA_T *file_data =
++ (struct SM_PRIV_DATA_T *)file->private_data;
++ struct SM_RESOURCE_T *resource;
++ int ret = 0;
++
++ /* Make sure the device was started properly.
++ */
++ if (sm_state == NULL || file_data == NULL) {
++ pr_err("[%s]: invalid device\n", __func__);
++ ret = -EPERM;
++ goto out;
++ }
++
++ pr_debug("[%s]: using private data %p\n", __func__, file_data);
++
++ if (file_data->restart_sys == -EINTR) {
++ VC_SM_ACTION_CLEAN_T action_clean;
++
++ pr_debug("[%s]: releasing following EINTR on %u (trans_id: %u) (likely due to signal)...\n",
++ __func__, file_data->int_action,
++ file_data->int_trans_id);
++
++ action_clean.res_action = file_data->int_action;
++ action_clean.action_trans_id = file_data->int_trans_id;
++
++ vc_vchi_sm_clean_up(sm_state->sm_handle, &action_clean);
++ }
++
++ while ((resource = vmcs_sm_acquire_first_resource(file_data)) != NULL) {
++ vmcs_sm_release_resource(resource, 0);
++ vmcs_sm_release_resource(resource, 1);
++ }
++
++ /* Remove the corresponding proc entry. */
++ debugfs_remove_recursive(file_data->dir_pid);
++
++ /* Terminate the private data.
++ */
++ kfree(file_data);
++
++out:
++ return ret;
++}
++
++static void vcsm_vma_open(struct vm_area_struct *vma)
++{
++ struct sm_mmap *map = (struct sm_mmap *)vma->vm_private_data;
++
++ pr_debug("[%s]: virt %lx-%lx, pid %i, pfn %i\n",
++ __func__, vma->vm_start, vma->vm_end, (int)current->tgid,
++ (int)vma->vm_pgoff);
++
++ map->ref_count++;
++}
++
++static void vcsm_vma_close(struct vm_area_struct *vma)
++{
++ struct sm_mmap *map = (struct sm_mmap *)vma->vm_private_data;
++
++ pr_debug("[%s]: virt %lx-%lx, pid %i, pfn %i\n",
++ __func__, vma->vm_start, vma->vm_end, (int)current->tgid,
++ (int)vma->vm_pgoff);
++
++ map->ref_count--;
++
++ /* Remove from the map table.
++ */
++ if (map->ref_count == 0)
++ vmcs_sm_remove_map(sm_state, map->resource, map);
++}
++
++static int vcsm_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
++{
++ struct sm_mmap *map = (struct sm_mmap *)vma->vm_private_data;
++ struct SM_RESOURCE_T *resource = map->resource;
++ pgoff_t page_offset;
++ unsigned long pfn;
++ int ret = 0;
++
++ /* Lock the resource if necessary.
++ */
++ if (!resource->lock_count) {
++ VC_SM_LOCK_UNLOCK_T lock_unlock;
++ VC_SM_LOCK_RESULT_T lock_result;
++ int status;
++
++ lock_unlock.res_handle = resource->res_handle;
++ lock_unlock.res_mem = resource->res_base_mem;
++
++ pr_debug("[%s]: attempt to lock data - hdl %x, base address %p\n",
++ __func__, lock_unlock.res_handle, lock_unlock.res_mem);
++
++ /* Lock the videocore allocated resource.
++ */
++ status = vc_vchi_sm_lock(sm_state->sm_handle,
++ &lock_unlock, &lock_result, 0);
++ if ((status != 0) ||
++ ((status == 0) && (lock_result.res_mem == NULL))) {
++ pr_err("[%s]: failed to lock memory on videocore (status: %u)\n",
++ __func__, status);
++ resource->res_stats[LOCK_FAIL]++;
++ return VM_FAULT_SIGBUS;
++ }
++
++ pfn = vcaddr_to_pfn((unsigned long)resource->res_base_mem);
++ outer_inv_range(__pfn_to_phys(pfn),
++ __pfn_to_phys(pfn) + resource->res_size);
++
++ resource->res_stats[LOCK]++;
++ resource->lock_count++;
++
++ /* Keep track of the new base memory.
++ */
++ if ((lock_result.res_mem != NULL) &&
++ (lock_result.res_old_mem != NULL) &&
++ (lock_result.res_mem != lock_result.res_old_mem)) {
++ resource->res_base_mem = lock_result.res_mem;
++ }
++ }
++
++ /* We don't use vmf->pgoff since that has the fake offset */
++ page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start);
++ pfn = (uint32_t)resource->res_base_mem & 0x3FFFFFFF;
++ pfn += mm_vc_mem_phys_addr;
++ pfn += page_offset;
++ pfn >>= PAGE_SHIFT;
++
++ /* Finally, remap it */
++ ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn);
++
++ switch (ret) {
++ case 0:
++ case -ERESTARTSYS:
++ return VM_FAULT_NOPAGE;
++ case -ENOMEM:
++ case -EAGAIN:
++ return VM_FAULT_OOM;
++ default:
++ return VM_FAULT_SIGBUS;
++ }
++}
++
++static struct vm_operations_struct vcsm_vm_ops = {
++ .open = vcsm_vma_open,
++ .close = vcsm_vma_close,
++ .fault = vcsm_vma_fault,
++};
++
++/* Walks a VMA and clean each valid page from the cache */
++static void vcsm_vma_cache_clean_page_range(unsigned long addr,
++ unsigned long end)
++{
++ pgd_t *pgd;
++ pud_t *pud;
++ pmd_t *pmd;
++ pte_t *pte;
++ unsigned long pgd_next, pud_next, pmd_next;
++
++ if (addr >= end)
++ return;
++
++ /* Walk PGD */
++ pgd = pgd_offset(current->mm, addr);
++ do {
++ pgd_next = pgd_addr_end(addr, end);
++
++ if (pgd_none(*pgd) || pgd_bad(*pgd))
++ continue;
++
++ /* Walk PUD */
++ pud = pud_offset(pgd, addr);
++ do {
++ pud_next = pud_addr_end(addr, pgd_next);
++ if (pud_none(*pud) || pud_bad(*pud))
++ continue;
++
++ /* Walk PMD */
++ pmd = pmd_offset(pud, addr);
++ do {
++ pmd_next = pmd_addr_end(addr, pud_next);
++ if (pmd_none(*pmd) || pmd_bad(*pmd))
++ continue;
++
++ /* Walk PTE */
++ pte = pte_offset_map(pmd, addr);
++ do {
++ if (pte_none(*pte)
++ || !pte_present(*pte))
++ continue;
++
++ /* Clean + invalidate */
++ dmac_flush_range((const void *) addr,
++ (const void *)
++ (addr + PAGE_SIZE));
++
++ } while (pte++, addr +=
++ PAGE_SIZE, addr != pmd_next);
++ pte_unmap(pte);
++
++ } while (pmd++, addr = pmd_next, addr != pud_next);
++
++ } while (pud++, addr = pud_next, addr != pgd_next);
++ } while (pgd++, addr = pgd_next, addr != end);
++}
++
++/* Map an allocated data into something that the user space.
++*/
++static int vc_sm_mmap(struct file *file, struct vm_area_struct *vma)
++{
++ int ret = 0;
++ struct SM_PRIV_DATA_T *file_data =
++ (struct SM_PRIV_DATA_T *)file->private_data;
++ struct SM_RESOURCE_T *resource = NULL;
++ struct sm_mmap *map = NULL;
++
++ /* Make sure the device was started properly.
++ */
++ if ((sm_state == NULL) || (file_data == NULL)) {
++ pr_err("[%s]: invalid device\n", __func__);
++ return -EPERM;
++ }
++
++ pr_debug("[%s]: private data %p, guid %x\n", __func__, file_data,
++ ((unsigned int)vma->vm_pgoff << PAGE_SHIFT));
++
++ /* We lookup to make sure that the data we are being asked to mmap is
++ ** something that we allocated.
++ **
++ ** We use the offset information as the key to tell us which resource
++ ** we are mapping.
++ */
++ resource = vmcs_sm_acquire_resource(file_data,
++ ((unsigned int)vma->vm_pgoff <<
++ PAGE_SHIFT));
++ if (resource == NULL) {
++ pr_err("[%s]: failed to locate resource for guid %x\n", __func__,
++ ((unsigned int)vma->vm_pgoff << PAGE_SHIFT));
++ return -ENOMEM;
++ }
++
++ pr_debug("[%s]: guid %x, tgid %u, %u, %u\n",
++ __func__, resource->res_guid, current->tgid, resource->pid,
++ file_data->pid);
++
++ /* Check permissions.
++ */
++ if (resource->pid && (resource->pid != current->tgid)) {
++ pr_err("[%s]: current tgid %u != %u owner\n",
++ __func__, current->tgid, resource->pid);
++ ret = -EPERM;
++ goto error;
++ }
++
++ /* Verify that what we are asked to mmap is proper.
++ */
++ if (resource->res_size != (unsigned int)(vma->vm_end - vma->vm_start)) {
++ pr_err("[%s]: size inconsistency (resource: %u - mmap: %u)\n",
++ __func__,
++ resource->res_size,
++ (unsigned int)(vma->vm_end - vma->vm_start));
++
++ ret = -EINVAL;
++ goto error;
++ }
++
++ /* Keep track of the tuple in the global resource list such that one
++ * can do a mapping lookup for address/memory handle.
++ */
++ map = kzalloc(sizeof(*map), GFP_KERNEL);
++ if (map == NULL) {
++ pr_err("[%s]: failed to allocate global tracking resource\n",
++ __func__);
++ ret = -ENOMEM;
++ goto error;
++ }
++
++ map->res_pid = current->tgid;
++ map->res_vc_hdl = resource->res_handle;
++ map->res_usr_hdl = resource->res_guid;
++ map->res_addr = (long unsigned int)vma->vm_start;
++ map->resource = resource;
++ map->vma = vma;
++ vmcs_sm_add_map(sm_state, resource, map);
++
++ /* We are not actually mapping the pages, we just provide a fault
++ ** handler to allow pages to be mapped when accessed
++ */
++ vma->vm_flags |=
++ VM_IO | VM_PFNMAP | VM_DONTCOPY | VM_DONTEXPAND;
++ vma->vm_ops = &vcsm_vm_ops;
++ vma->vm_private_data = map;
++
++ /* vm_pgoff is the first PFN of the mapped memory */
++ vma->vm_pgoff = (unsigned long)resource->res_base_mem & 0x3FFFFFFF;
++ vma->vm_pgoff += mm_vc_mem_phys_addr;
++ vma->vm_pgoff >>= PAGE_SHIFT;
++
++ if ((resource->res_cached == VMCS_SM_CACHE_NONE) ||
++ (resource->res_cached == VMCS_SM_CACHE_VC)) {
++ /* Allocated non host cached memory, honour it.
++ */
++ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
++ }
++
++ pr_debug("[%s]: resource %p (guid %x) - cnt %u, base address %p, handle %x, size %u (%u), cache %u\n",
++ __func__,
++ resource, resource->res_guid, resource->lock_count,
++ resource->res_base_mem, resource->res_handle,
++ resource->res_size, (unsigned int)(vma->vm_end - vma->vm_start),
++ resource->res_cached);
++
++ pr_debug("[%s]: resource %p (base address %p, handle %x) - map-count %d, usr-addr %x\n",
++ __func__, resource, resource->res_base_mem,
++ resource->res_handle, resource->map_count,
++ (unsigned int)vma->vm_start);
++
++ vcsm_vma_open(vma);
++ resource->res_stats[MAP]++;
++ vmcs_sm_release_resource(resource, 0);
++ return 0;
++
++error:
++ resource->res_stats[MAP_FAIL]++;
++ vmcs_sm_release_resource(resource, 0);
++ return ret;
++}
++
++/* Allocate a shared memory handle and block.
++*/
++int vc_sm_ioctl_alloc(struct SM_PRIV_DATA_T *private,
++ struct vmcs_sm_ioctl_alloc *ioparam)
++{
++ int ret = 0;
++ int status;
++ struct SM_RESOURCE_T *resource;
++ VC_SM_ALLOC_T alloc = { 0 };
++ VC_SM_ALLOC_RESULT_T result = { 0 };
++
++ /* Setup our allocation parameters */
++ alloc.type = ((ioparam->cached == VMCS_SM_CACHE_VC)
++ || (ioparam->cached ==
++ VMCS_SM_CACHE_BOTH)) ? VC_SM_ALLOC_CACHED :
++ VC_SM_ALLOC_NON_CACHED;
++ alloc.base_unit = ioparam->size;
++ alloc.num_unit = ioparam->num;
++ alloc.allocator = current->tgid;
++ /* Align to kernel page size */
++ alloc.alignement = 4096;
++ /* Align the size to the kernel page size */
++ alloc.base_unit =
++ (alloc.base_unit + alloc.alignement - 1) & ~(alloc.alignement - 1);
++ if (*ioparam->name) {
++ memcpy(alloc.name, ioparam->name, sizeof(alloc.name) - 1);
++ } else {
++ memcpy(alloc.name, VMCS_SM_RESOURCE_NAME_DEFAULT,
++ sizeof(VMCS_SM_RESOURCE_NAME_DEFAULT));
++ }
++
++ pr_debug("[%s]: attempt to allocate \"%s\" data - type %u, base %u (%u), num %u, alignement %u\n",
++ __func__, alloc.name, alloc.type, ioparam->size,
++ alloc.base_unit, alloc.num_unit, alloc.alignement);
++
++ /* Allocate local resource to track this allocation.
++ */
++ resource = kzalloc(sizeof(*resource), GFP_KERNEL);
++ if (!resource) {
++ ret = -ENOMEM;
++ goto error;
++ }
++ INIT_LIST_HEAD(&resource->map_list);
++ resource->ref_count++;
++ resource->pid = current->tgid;
++
++ /* Allocate the videocore resource.
++ */
++ status = vc_vchi_sm_alloc(sm_state->sm_handle, &alloc, &result,
++ &private->int_trans_id);
++ if (status == -EINTR) {
++ pr_debug("[%s]: requesting allocate memory action restart (trans_id: %u)\n",
++ __func__, private->int_trans_id);
++ ret = -ERESTARTSYS;
++ private->restart_sys = -EINTR;
++ private->int_action = VC_SM_MSG_TYPE_ALLOC;
++ goto error;
++ } else if (status != 0 || (status == 0 && result.res_mem == NULL)) {
++ pr_err("[%s]: failed to allocate memory on videocore (status: %u, trans_id: %u)\n",
++ __func__, status, private->int_trans_id);
++ ret = -ENOMEM;
++ resource->res_stats[ALLOC_FAIL]++;
++ goto error;
++ }
++
++ /* Keep track of the resource we created.
++ */
++ resource->private = private;
++ resource->res_handle = result.res_handle;
++ resource->res_base_mem = result.res_mem;
++ resource->res_size = alloc.base_unit * alloc.num_unit;
++ resource->res_cached = ioparam->cached;
++
++ /* Kernel/user GUID. This global identifier is used for mmap'ing the
++ * allocated region from user space, it is passed as the mmap'ing
++ * offset, we use it to 'hide' the videocore handle/address.
++ */
++ mutex_lock(&sm_state->lock);
++ resource->res_guid = ++sm_state->guid;
++ mutex_unlock(&sm_state->lock);
++ resource->res_guid <<= PAGE_SHIFT;
++
++ vmcs_sm_add_resource(private, resource);
++
++ pr_debug("[%s]: allocated data - guid %x, hdl %x, base address %p, size %d, cache %d\n",
++ __func__, resource->res_guid, resource->res_handle,
++ resource->res_base_mem, resource->res_size,
++ resource->res_cached);
++
++ /* We're done */
++ resource->res_stats[ALLOC]++;
++ ioparam->handle = resource->res_guid;
++ return 0;
++
++error:
++ pr_err("[%s]: failed to allocate \"%s\" data (%i) - type %u, base %u (%u), num %u, alignment %u\n",
++ __func__, alloc.name, ret, alloc.type, ioparam->size,
++ alloc.base_unit, alloc.num_unit, alloc.alignement);
++ if (resource != NULL) {
++ vc_sm_resource_deceased(resource, 1);
++ kfree(resource);
++ }
++ return ret;
++}
++
++/* Share an allocate memory handle and block.
++*/
++int vc_sm_ioctl_alloc_share(struct SM_PRIV_DATA_T *private,
++ struct vmcs_sm_ioctl_alloc_share *ioparam)
++{
++ struct SM_RESOURCE_T *resource, *shared_resource;
++ int ret = 0;
++
++ pr_debug("[%s]: attempt to share resource %u\n", __func__,
++ ioparam->handle);
++
++ shared_resource = vmcs_sm_acquire_global_resource(ioparam->handle);
++ if (shared_resource == NULL) {
++ ret = -ENOMEM;
++ goto error;
++ }
++
++ /* Allocate local resource to track this allocation.
++ */
++ resource = kzalloc(sizeof(*resource), GFP_KERNEL);
++ if (resource == NULL) {
++ pr_err("[%s]: failed to allocate local tracking resource\n",
++ __func__);
++ ret = -ENOMEM;
++ goto error;
++ }
++ INIT_LIST_HEAD(&resource->map_list);
++ resource->ref_count++;
++ resource->pid = current->tgid;
++
++ /* Keep track of the resource we created.
++ */
++ resource->private = private;
++ resource->res_handle = shared_resource->res_handle;
++ resource->res_base_mem = shared_resource->res_base_mem;
++ resource->res_size = shared_resource->res_size;
++ resource->res_cached = shared_resource->res_cached;
++ resource->res_shared = shared_resource;
++
++ mutex_lock(&sm_state->lock);
++ resource->res_guid = ++sm_state->guid;
++ mutex_unlock(&sm_state->lock);
++ resource->res_guid <<= PAGE_SHIFT;
++
++ vmcs_sm_add_resource(private, resource);
++
++ pr_debug("[%s]: allocated data - guid %x, hdl %x, base address %p, size %d, cache %d\n",
++ __func__, resource->res_guid, resource->res_handle,
++ resource->res_base_mem, resource->res_size,
++ resource->res_cached);
++
++ /* We're done */
++ resource->res_stats[ALLOC]++;
++ ioparam->handle = resource->res_guid;
++ ioparam->size = resource->res_size;
++ return 0;
++
++error:
++ pr_err("[%s]: failed to share %u\n", __func__, ioparam->handle);
++ if (shared_resource != NULL)
++ vmcs_sm_release_resource(shared_resource, 0);
++
++ return ret;
++}
++
++/* Free a previously allocated shared memory handle and block.
++*/
++static int vc_sm_ioctl_free(struct SM_PRIV_DATA_T *private,
++ struct vmcs_sm_ioctl_free *ioparam)
++{
++ struct SM_RESOURCE_T *resource =
++ vmcs_sm_acquire_resource(private, ioparam->handle);
++
++ if (resource == NULL) {
++ pr_err("[%s]: resource for guid %u does not exist\n", __func__,
++ ioparam->handle);
++ return -EINVAL;
++ }
++
++ /* Check permissions.
++ */
++ if (resource->pid && (resource->pid != current->tgid)) {
++ pr_err("[%s]: current tgid %u != %u owner\n",
++ __func__, current->tgid, resource->pid);
++ vmcs_sm_release_resource(resource, 0);
++ return -EPERM;
++ }
++
++ vmcs_sm_release_resource(resource, 0);
++ vmcs_sm_release_resource(resource, 0);
++ return 0;
++}
++
++/* Resize a previously allocated shared memory handle and block.
++*/
++static int vc_sm_ioctl_resize(struct SM_PRIV_DATA_T *private,
++ struct vmcs_sm_ioctl_resize *ioparam)
++{
++ int ret = 0;
++ int status;
++ VC_SM_RESIZE_T resize;
++ struct SM_RESOURCE_T *resource;
++
++ /* Locate resource from GUID.
++ */
++ resource = vmcs_sm_acquire_resource(private, ioparam->handle);
++ if (!resource) {
++ pr_err("[%s]: failed resource - guid %x\n",
++ __func__, ioparam->handle);
++ ret = -EFAULT;
++ goto error;
++ }
++
++ /* If the resource is locked, its reference count will be not NULL,
++ ** in which case we will not be allowed to resize it anyways, so
++ ** reject the attempt here.
++ */
++ if (resource->lock_count != 0) {
++ pr_err("[%s]: cannot resize - guid %x, ref-cnt %d\n",
++ __func__, ioparam->handle, resource->lock_count);
++ ret = -EFAULT;
++ goto error;
++ }
++
++ /* Check permissions.
++ */
++ if (resource->pid && (resource->pid != current->tgid)) {
++ pr_err("[%s]: current tgid %u != %u owner\n", __func__,
++ current->tgid, resource->pid);
++ ret = -EPERM;
++ goto error;
++ }
++
++ if (resource->map_count != 0) {
++ pr_err("[%s]: cannot resize - guid %x, ref-cnt %d\n",
++ __func__, ioparam->handle, resource->map_count);
++ ret = -EFAULT;
++ goto error;
++ }
++
++ resize.res_handle = resource->res_handle;
++ resize.res_mem = resource->res_base_mem;
++ resize.res_new_size = ioparam->new_size;
++
++ pr_debug("[%s]: attempt to resize data - guid %x, hdl %x, base address %p\n",
++ __func__, ioparam->handle, resize.res_handle, resize.res_mem);
++
++ /* Resize the videocore allocated resource.
++ */
++ status = vc_vchi_sm_resize(sm_state->sm_handle, &resize,
++ &private->int_trans_id);
++ if (status == -EINTR) {
++ pr_debug("[%s]: requesting resize memory action restart (trans_id: %u)\n",
++ __func__, private->int_trans_id);
++ ret = -ERESTARTSYS;
++ private->restart_sys = -EINTR;
++ private->int_action = VC_SM_MSG_TYPE_RESIZE;
++ goto error;
++ } else if (status != 0) {
++ pr_err("[%s]: failed to resize memory on videocore (status: %u, trans_id: %u)\n",
++ __func__, status, private->int_trans_id);
++ ret = -EPERM;
++ goto error;
++ }
++
++ pr_debug("[%s]: success to resize data - hdl %x, size %d -> %d\n",
++ __func__, resize.res_handle, resource->res_size,
++ resize.res_new_size);
++
++ /* Successfully resized, save the information and inform the user.
++ */
++ ioparam->old_size = resource->res_size;
++ resource->res_size = resize.res_new_size;
++
++error:
++ if (resource)
++ vmcs_sm_release_resource(resource, 0);
++
++ return ret;
++}
++
++/* Lock a previously allocated shared memory handle and block.
++*/
++static int vc_sm_ioctl_lock(struct SM_PRIV_DATA_T *private,
++ struct vmcs_sm_ioctl_lock_unlock *ioparam,
++ int change_cache, enum vmcs_sm_cache_e cache_type,
++ unsigned int vc_addr)
++{
++ int status;
++ VC_SM_LOCK_UNLOCK_T lock;
++ VC_SM_LOCK_RESULT_T result;
++ struct SM_RESOURCE_T *resource;
++ int ret = 0;
++ struct sm_mmap *map, *map_tmp;
++ long unsigned int phys_addr;
++
++ map = NULL;
++
++ /* Locate resource from GUID.
++ */
++ resource = vmcs_sm_acquire_resource(private, ioparam->handle);
++ if (resource == NULL) {
++ ret = -EINVAL;
++ goto error;
++ }
++
++ /* Check permissions.
++ */
++ if (resource->pid && (resource->pid != current->tgid)) {
++ pr_err("[%s]: current tgid %u != %u owner\n", __func__,
++ current->tgid, resource->pid);
++ ret = -EPERM;
++ goto error;
++ }
++
++ lock.res_handle = resource->res_handle;
++ lock.res_mem = resource->res_base_mem;
++
++ /* Take the lock and get the address to be mapped.
++ */
++ if (vc_addr == 0) {
++ pr_debug("[%s]: attempt to lock data - guid %x, hdl %x, base address %p\n",
++ __func__, ioparam->handle, lock.res_handle,
++ lock.res_mem);
++
++ /* Lock the videocore allocated resource.
++ */
++ status = vc_vchi_sm_lock(sm_state->sm_handle, &lock, &result,
++ &private->int_trans_id);
++ if (status == -EINTR) {
++ pr_debug("[%s]: requesting lock memory action restart (trans_id: %u)\n",
++ __func__, private->int_trans_id);
++ ret = -ERESTARTSYS;
++ private->restart_sys = -EINTR;
++ private->int_action = VC_SM_MSG_TYPE_LOCK;
++ goto error;
++ } else if (status != 0 ||
++ (status == 0 && result.res_mem == NULL)) {
++ pr_err("[%s]: failed to lock memory on videocore (status: %u, trans_id: %u)\n",
++ __func__, status, private->int_trans_id);
++ ret = -EPERM;
++ resource->res_stats[LOCK_FAIL]++;
++ goto error;
++ }
++
++ pr_debug("[%s]: succeed to lock data - hdl %x, base address %p (%p), ref-cnt %d\n",
++ __func__, lock.res_handle, result.res_mem,
++ lock.res_mem, resource->lock_count);
++ }
++ /* Lock assumed taken already, address to be mapped is known.
++ */
++ else
++ resource->res_base_mem = (void *)vc_addr;
++
++ resource->res_stats[LOCK]++;
++ resource->lock_count++;
++
++ /* Keep track of the new base memory allocation if it has changed.
++ */
++ if ((vc_addr == 0) &&
++ (result.res_mem != NULL) &&
++ (result.res_old_mem != NULL) &&
++ (result.res_mem != result.res_old_mem)) {
++ resource->res_base_mem = result.res_mem;
++
++ /* Kernel allocated resources.
++ */
++ if (resource->pid == 0) {
++ if (!list_empty(&resource->map_list)) {
++ list_for_each_entry_safe(map, map_tmp,
++ &resource->map_list,
++ resource_map_list) {
++ if (map->res_addr) {
++ iounmap((void *)map->res_addr);
++ map->res_addr = 0;
++
++ vmcs_sm_remove_map(sm_state,
++ map->resource,
++ map);
++ break;
++ }
++ }
++ }
++ }
++ }
++
++ if (change_cache)
++ resource->res_cached = cache_type;
++
++ if (resource->map_count) {
++ ioparam->addr =
++ vmcs_sm_usr_address_from_pid_and_usr_handle(
++ current->tgid, ioparam->handle);
++
++ pr_debug("[%s] map_count %d private->pid %d current->tgid %d hnd %x addr %u\n",
++ __func__, resource->map_count, private->pid,
++ current->tgid, ioparam->handle, ioparam->addr);
++ } else {
++ /* Kernel allocated resources.
++ */
++ if (resource->pid == 0) {
++ pr_debug("[%s]: attempt mapping kernel resource - guid %x, hdl %x\n",
++ __func__, ioparam->handle, lock.res_handle);
++
++ ioparam->addr = 0;
++
++ map = kzalloc(sizeof(*map), GFP_KERNEL);
++ if (map == NULL) {
++ pr_err("[%s]: failed allocating tracker\n",
++ __func__);
++ ret = -ENOMEM;
++ goto error;
++ } else {
++ phys_addr = (uint32_t)resource->res_base_mem &
++ 0x3FFFFFFF;
++ phys_addr += mm_vc_mem_phys_addr;
++ if (resource->res_cached
++ == VMCS_SM_CACHE_HOST) {
++ ioparam->addr = (long unsigned int)
++ /* TODO - make cached work */
++ ioremap_nocache(phys_addr,
++ resource->res_size);
++
++ pr_debug("[%s]: mapping kernel - guid %x, hdl %x - cached mapping %u\n",
++ __func__, ioparam->handle,
++ lock.res_handle, ioparam->addr);
++ } else {
++ ioparam->addr = (long unsigned int)
++ ioremap_nocache(phys_addr,
++ resource->res_size);
++
++ pr_debug("[%s]: mapping kernel- guid %x, hdl %x - non cached mapping %u\n",
++ __func__, ioparam->handle,
++ lock.res_handle, ioparam->addr);
++ }
++
++ map->res_pid = 0;
++ map->res_vc_hdl = resource->res_handle;
++ map->res_usr_hdl = resource->res_guid;
++ map->res_addr = ioparam->addr;
++ map->resource = resource;
++ map->vma = NULL;
++
++ vmcs_sm_add_map(sm_state, resource, map);
++ }
++ } else
++ ioparam->addr = 0;
++ }
++
++error:
++ if (resource)
++ vmcs_sm_release_resource(resource, 0);
++
++ return ret;
++}
++
++/* Unlock a previously allocated shared memory handle and block.
++*/
++static int vc_sm_ioctl_unlock(struct SM_PRIV_DATA_T *private,
++ struct vmcs_sm_ioctl_lock_unlock *ioparam,
++ int flush, int wait_reply, int no_vc_unlock)
++{
++ int status;
++ VC_SM_LOCK_UNLOCK_T unlock;
++ struct sm_mmap *map, *map_tmp;
++ struct SM_RESOURCE_T *resource;
++ int ret = 0;
++
++ map = NULL;
++
++ /* Locate resource from GUID.
++ */
++ resource = vmcs_sm_acquire_resource(private, ioparam->handle);
++ if (resource == NULL) {
++ ret = -EINVAL;
++ goto error;
++ }
++
++ /* Check permissions.
++ */
++ if (resource->pid && (resource->pid != current->tgid)) {
++ pr_err("[%s]: current tgid %u != %u owner\n",
++ __func__, current->tgid, resource->pid);
++ ret = -EPERM;
++ goto error;
++ }
++
++ unlock.res_handle = resource->res_handle;
++ unlock.res_mem = resource->res_base_mem;
++
++ pr_debug("[%s]: attempt to unlock data - guid %x, hdl %x, base address %p\n",
++ __func__, ioparam->handle, unlock.res_handle, unlock.res_mem);
++
++ /* User space allocated resources.
++ */
++ if (resource->pid) {
++ /* Flush if requested */
++ if (resource->res_cached && flush) {
++ dma_addr_t phys_addr = 0;
++ resource->res_stats[FLUSH]++;
++
++ phys_addr =
++ (dma_addr_t)((uint32_t)resource->res_base_mem &
++ 0x3FFFFFFF);
++ phys_addr += (dma_addr_t)mm_vc_mem_phys_addr;
++
++ /* L1 cache flush */
++ down_read(&current->mm->mmap_sem);
++ list_for_each_entry(map, &resource->map_list,
++ resource_map_list) {
++ if (map->vma) {
++ unsigned long start;
++ unsigned long end;
++ start = map->vma->vm_start;
++ end = map->vma->vm_end;
++
++ vcsm_vma_cache_clean_page_range(
++ start, end);
++ }
++ }
++ up_read(&current->mm->mmap_sem);
++
++ /* L2 cache flush */
++ outer_clean_range(phys_addr,
++ phys_addr +
++ (size_t) resource->res_size);
++ }
++
++ /* We need to zap all the vmas associated with this resource */
++ if (resource->lock_count == 1) {
++ down_read(&current->mm->mmap_sem);
++ list_for_each_entry(map, &resource->map_list,
++ resource_map_list) {
++ if (map->vma) {
++ zap_vma_ptes(map->vma,
++ map->vma->vm_start,
++ map->vma->vm_end -
++ map->vma->vm_start);
++ }
++ }
++ up_read(&current->mm->mmap_sem);
++ }
++ }
++ /* Kernel allocated resources. */
++ else {
++ /* Global + Taken in this context */
++ if (resource->ref_count == 2) {
++ if (!list_empty(&resource->map_list)) {
++ list_for_each_entry_safe(map, map_tmp,
++ &resource->map_list,
++ resource_map_list) {
++ if (map->res_addr) {
++ if (flush &&
++ (resource->res_cached ==
++ VMCS_SM_CACHE_HOST)) {
++ long unsigned int
++ phys_addr;
++ phys_addr = (uint32_t)
++ resource->res_base_mem & 0x3FFFFFFF;
++ phys_addr +=
++ mm_vc_mem_phys_addr;
++
++ /* L1 cache flush */
++ dmac_flush_range((const
++ void
++ *)
++ map->res_addr, (const void *)
++ (map->res_addr + resource->res_size));
++
++ /* L2 cache flush */
++ outer_clean_range
++ (phys_addr,
++ phys_addr +
++ (size_t)
++ resource->res_size);
++ }
++
++ iounmap((void *)map->res_addr);
++ map->res_addr = 0;
++
++ vmcs_sm_remove_map(sm_state,
++ map->resource,
++ map);
++ break;
++ }
++ }
++ }
++ }
++ }
++
++ if (resource->lock_count) {
++ /* Bypass the videocore unlock.
++ */
++ if (no_vc_unlock)
++ status = 0;
++ /* Unlock the videocore allocated resource.
++ */
++ else {
++ status =
++ vc_vchi_sm_unlock(sm_state->sm_handle, &unlock,
++ &private->int_trans_id,
++ wait_reply);
++ if (status == -EINTR) {
++ pr_debug("[%s]: requesting unlock memory action restart (trans_id: %u)\n",
++ __func__, private->int_trans_id);
++
++ ret = -ERESTARTSYS;
++ resource->res_stats[UNLOCK]--;
++ private->restart_sys = -EINTR;
++ private->int_action = VC_SM_MSG_TYPE_UNLOCK;
++ goto error;
++ } else if (status != 0) {
++ pr_err("[%s]: failed to unlock vc mem (status: %u, trans_id: %u)\n",
++ __func__, status, private->int_trans_id);
++
++ ret = -EPERM;
++ resource->res_stats[UNLOCK_FAIL]++;
++ goto error;
++ }
++ }
++
++ resource->res_stats[UNLOCK]++;
++ resource->lock_count--;
++ }
++
++ pr_debug("[%s]: success to unlock data - hdl %x, base address %p, ref-cnt %d\n",
++ __func__, unlock.res_handle, unlock.res_mem,
++ resource->lock_count);
++
++error:
++ if (resource)
++ vmcs_sm_release_resource(resource, 0);
++
++ return ret;
++}
++
++/* Handle control from host. */
++static long vc_sm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
++{
++ int ret = 0;
++ unsigned int cmdnr = _IOC_NR(cmd);
++ struct SM_PRIV_DATA_T *file_data =
++ (struct SM_PRIV_DATA_T *)file->private_data;
++ struct SM_RESOURCE_T *resource = NULL;
++
++ /* Validate we can work with this device. */
++ if ((sm_state == NULL) || (file_data == NULL)) {
++ pr_err("[%s]: invalid device\n", __func__);
++ ret = -EPERM;
++ goto out;
++ }
++
++ pr_debug("[%s]: cmd %x tgid %u, owner %u\n", __func__, cmdnr,
++ current->tgid, file_data->pid);
++
++ /* Action is a re-post of a previously interrupted action? */
++ if (file_data->restart_sys == -EINTR) {
++ VC_SM_ACTION_CLEAN_T action_clean;
++
++ pr_debug("[%s]: clean up of action %u (trans_id: %u) following EINTR\n",
++ __func__, file_data->int_action,
++ file_data->int_trans_id);
++
++ action_clean.res_action = file_data->int_action;
++ action_clean.action_trans_id = file_data->int_trans_id;
++
++ vc_vchi_sm_clean_up(sm_state->sm_handle, &action_clean);
++
++ file_data->restart_sys = 0;
++ }
++
++ /* Now process the command.
++ */
++ switch (cmdnr) {
++ /* New memory allocation.
++ */
++ case VMCS_SM_CMD_ALLOC:
++ {
++ struct vmcs_sm_ioctl_alloc ioparam;
++
++ /* Get the parameter data.
++ */
++ if (copy_from_user
++ (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
++ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
++ __func__, cmdnr);
++ ret = -EFAULT;
++ goto out;
++ }
++
++ ret = vc_sm_ioctl_alloc(file_data, &ioparam);
++ if (!ret &&
++ (copy_to_user((void *)arg,
++ &ioparam, sizeof(ioparam)) != 0)) {
++ struct vmcs_sm_ioctl_free freeparam = {
++ ioparam.handle
++ };
++ pr_err("[%s]: failed to copy-to-user for cmd %x\n",
++ __func__, cmdnr);
++ vc_sm_ioctl_free(file_data, &freeparam);
++ ret = -EFAULT;
++ }
++
++ /* Done.
++ */
++ goto out;
++ }
++ break;
++
++ /* Share existing memory allocation.
++ */
++ case VMCS_SM_CMD_ALLOC_SHARE:
++ {
++ struct vmcs_sm_ioctl_alloc_share ioparam;
++
++ /* Get the parameter data.
++ */
++ if (copy_from_user
++ (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
++ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
++ __func__, cmdnr);
++ ret = -EFAULT;
++ goto out;
++ }
++
++ ret = vc_sm_ioctl_alloc_share(file_data, &ioparam);
++
++ /* Copy result back to user.
++ */
++ if (!ret
++ && copy_to_user((void *)arg, &ioparam,
++ sizeof(ioparam)) != 0) {
++ struct vmcs_sm_ioctl_free freeparam = {
++ ioparam.handle
++ };
++ pr_err("[%s]: failed to copy-to-user for cmd %x\n",
++ __func__, cmdnr);
++ vc_sm_ioctl_free(file_data, &freeparam);
++ ret = -EFAULT;
++ }
++
++ /* Done.
++ */
++ goto out;
++ }
++ break;
++
++ /* Lock (attempt to) *and* register a cache behavior change.
++ */
++ case VMCS_SM_CMD_LOCK_CACHE:
++ {
++ struct vmcs_sm_ioctl_lock_cache ioparam;
++ struct vmcs_sm_ioctl_lock_unlock lock;
++
++ /* Get parameter data.
++ */
++ if (copy_from_user
++ (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
++ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
++ __func__, cmdnr);
++ ret = -EFAULT;
++ goto out;
++ }
++
++ lock.handle = ioparam.handle;
++ ret =
++ vc_sm_ioctl_lock(file_data, &lock, 1,
++ ioparam.cached, 0);
++
++ /* Done.
++ */
++ goto out;
++ }
++ break;
++
++ /* Lock (attempt to) existing memory allocation.
++ */
++ case VMCS_SM_CMD_LOCK:
++ {
++ struct vmcs_sm_ioctl_lock_unlock ioparam;
++
++ /* Get parameter data.
++ */
++ if (copy_from_user
++ (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
++ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
++ __func__, cmdnr);
++ ret = -EFAULT;
++ goto out;
++ }
++
++ ret = vc_sm_ioctl_lock(file_data, &ioparam, 0, 0, 0);
++
++ /* Copy result back to user.
++ */
++ if (copy_to_user((void *)arg, &ioparam, sizeof(ioparam))
++ != 0) {
++ pr_err("[%s]: failed to copy-to-user for cmd %x\n",
++ __func__, cmdnr);
++ ret = -EFAULT;
++ }
++
++ /* Done.
++ */
++ goto out;
++ }
++ break;
++
++ /* Unlock (attempt to) existing memory allocation.
++ */
++ case VMCS_SM_CMD_UNLOCK:
++ {
++ struct vmcs_sm_ioctl_lock_unlock ioparam;
++
++ /* Get parameter data.
++ */
++ if (copy_from_user
++ (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
++ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
++ __func__, cmdnr);
++ ret = -EFAULT;
++ goto out;
++ }
++
++ ret = vc_sm_ioctl_unlock(file_data, &ioparam, 0, 1, 0);
++
++ /* Done.
++ */
++ goto out;
++ }
++ break;
++
++ /* Resize (attempt to) existing memory allocation.
++ */
++ case VMCS_SM_CMD_RESIZE:
++ {
++ struct vmcs_sm_ioctl_resize ioparam;
++
++ /* Get parameter data.
++ */
++ if (copy_from_user
++ (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
++ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
++ __func__, cmdnr);
++ ret = -EFAULT;
++ goto out;
++ }
++
++ ret = vc_sm_ioctl_resize(file_data, &ioparam);
++
++ /* Copy result back to user.
++ */
++ if (copy_to_user((void *)arg, &ioparam, sizeof(ioparam))
++ != 0) {
++ pr_err("[%s]: failed to copy-to-user for cmd %x\n",
++ __func__, cmdnr);
++ ret = -EFAULT;
++ }
++
++ /* Done.
++ */
++ goto out;
++ }
++ break;
++
++ /* Terminate existing memory allocation.
++ */
++ case VMCS_SM_CMD_FREE:
++ {
++ struct vmcs_sm_ioctl_free ioparam;
++
++ /* Get parameter data.
++ */
++ if (copy_from_user
++ (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
++ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
++ __func__, cmdnr);
++ ret = -EFAULT;
++ goto out;
++ }
++
++ ret = vc_sm_ioctl_free(file_data, &ioparam);
++
++ /* Done.
++ */
++ goto out;
++ }
++ break;
++
++ /* Walk allocation on videocore, information shows up in the
++ ** videocore log.
++ */
++ case VMCS_SM_CMD_VC_WALK_ALLOC:
++ {
++ pr_debug("[%s]: invoking walk alloc\n", __func__);
++
++ if (vc_vchi_sm_walk_alloc(sm_state->sm_handle) != 0)
++ pr_err("[%s]: failed to walk-alloc on videocore\n",
++ __func__);
++
++ /* Done.
++ */
++ goto out;
++ }
++ break;
++/* Walk mapping table on host, information shows up in the
++ ** kernel log.
++ */
++ case VMCS_SM_CMD_HOST_WALK_MAP:
++ {
++ /* Use pid of -1 to tell to walk the whole map. */
++ vmcs_sm_host_walk_map_per_pid(-1);
++
++ /* Done. */
++ goto out;
++ }
++ break;
++
++ /* Walk mapping table per process on host. */
++ case VMCS_SM_CMD_HOST_WALK_PID_ALLOC:
++ {
++ struct vmcs_sm_ioctl_walk ioparam;
++
++ /* Get parameter data. */
++ if (copy_from_user(&ioparam,
++ (void *)arg, sizeof(ioparam)) != 0) {
++ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
++ __func__, cmdnr);
++ ret = -EFAULT;
++ goto out;
++ }
++
++ vmcs_sm_host_walk_alloc(file_data);
++
++ /* Done. */
++ goto out;
++ }
++ break;
++
++ /* Walk allocation per process on host. */
++ case VMCS_SM_CMD_HOST_WALK_PID_MAP:
++ {
++ struct vmcs_sm_ioctl_walk ioparam;
++
++ /* Get parameter data. */
++ if (copy_from_user(&ioparam,
++ (void *)arg, sizeof(ioparam)) != 0) {
++ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
++ __func__, cmdnr);
++ ret = -EFAULT;
++ goto out;
++ }
++
++ vmcs_sm_host_walk_map_per_pid(ioparam.pid);
++
++ /* Done. */
++ goto out;
++ }
++ break;
++
++ /* Gets the size of the memory associated with a user handle. */
++ case VMCS_SM_CMD_SIZE_USR_HANDLE:
++ {
++ struct vmcs_sm_ioctl_size ioparam;
++
++ /* Get parameter data. */
++ if (copy_from_user(&ioparam,
++ (void *)arg, sizeof(ioparam)) != 0) {
++ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
++ __func__, cmdnr);
++ ret = -EFAULT;
++ goto out;
++ }
++
++ /* Locate resource from GUID. */
++ resource =
++ vmcs_sm_acquire_resource(file_data, ioparam.handle);
++ if (resource != NULL) {
++ ioparam.size = resource->res_size;
++ vmcs_sm_release_resource(resource, 0);
++ } else {
++ ioparam.size = 0;
++ }
++
++ if (copy_to_user((void *)arg,
++ &ioparam, sizeof(ioparam)) != 0) {
++ pr_err("[%s]: failed to copy-to-user for cmd %x\n",
++ __func__, cmdnr);
++ ret = -EFAULT;
++ }
++
++ /* Done. */
++ goto out;
++ }
++ break;
++
++ /* Verify we are dealing with a valid resource. */
++ case VMCS_SM_CMD_CHK_USR_HANDLE:
++ {
++ struct vmcs_sm_ioctl_chk ioparam;
++
++ /* Get parameter data.
++ */
++ if (copy_from_user(&ioparam,
++ (void *)arg, sizeof(ioparam)) != 0) {
++ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
++ __func__, cmdnr);
++
++ ret = -EFAULT;
++ goto out;
++ }
++
++ /* Locate resource from GUID. */
++ resource =
++ vmcs_sm_acquire_resource(file_data, ioparam.handle);
++ if (resource == NULL)
++ ret = -EINVAL;
++ /* If the resource is cacheable, return additional
++ * information that may be needed to flush the cache.
++ */
++ else if ((resource->res_cached == VMCS_SM_CACHE_HOST) ||
++ (resource->res_cached == VMCS_SM_CACHE_BOTH)) {
++ ioparam.addr =
++ vmcs_sm_usr_address_from_pid_and_usr_handle
++ (current->tgid, ioparam.handle);
++ ioparam.size = resource->res_size;
++ ioparam.cache = resource->res_cached;
++ } else {
++ ioparam.addr = 0;
++ ioparam.size = 0;
++ ioparam.cache = resource->res_cached;
++ }
++
++ if (resource)
++ vmcs_sm_release_resource(resource, 0);
++
++ if (copy_to_user((void *)arg,
++ &ioparam, sizeof(ioparam)) != 0) {
++ pr_err("[%s]: failed to copy-to-user for cmd %x\n",
++ __func__, cmdnr);
++ ret = -EFAULT;
++ }
++
++ /* Done.
++ */
++ goto out;
++ }
++ break;
++
++ /*
++ * Maps a user handle given the process and the virtual address.
++ */
++ case VMCS_SM_CMD_MAPPED_USR_HANDLE:
++ {
++ struct vmcs_sm_ioctl_map ioparam;
++
++ /* Get parameter data. */
++ if (copy_from_user(&ioparam,
++ (void *)arg, sizeof(ioparam)) != 0) {
++ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
++ __func__, cmdnr);
++
++ ret = -EFAULT;
++ goto out;
++ }
++
++ ioparam.handle =
++ vmcs_sm_usr_handle_from_pid_and_address(
++ ioparam.pid, ioparam.addr);
++
++ resource =
++ vmcs_sm_acquire_resource(file_data, ioparam.handle);
++ if ((resource != NULL)
++ && ((resource->res_cached == VMCS_SM_CACHE_HOST)
++ || (resource->res_cached ==
++ VMCS_SM_CACHE_BOTH))) {
++ ioparam.size = resource->res_size;
++ } else {
++ ioparam.size = 0;
++ }
++
++ if (resource)
++ vmcs_sm_release_resource(resource, 0);
++
++ if (copy_to_user((void *)arg,
++ &ioparam, sizeof(ioparam)) != 0) {
++ pr_err("[%s]: failed to copy-to-user for cmd %x\n",
++ __func__, cmdnr);
++ ret = -EFAULT;
++ }
++
++ /* Done. */
++ goto out;
++ }
++ break;
++
++ /*
++ * Maps a videocore handle given process and virtual address.
++ */
++ case VMCS_SM_CMD_MAPPED_VC_HDL_FROM_ADDR:
++ {
++ struct vmcs_sm_ioctl_map ioparam;
++
++ /* Get parameter data. */
++ if (copy_from_user(&ioparam,
++ (void *)arg, sizeof(ioparam)) != 0) {
++ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
++ __func__, cmdnr);
++ ret = -EFAULT;
++ goto out;
++ }
++
++ ioparam.handle = vmcs_sm_vc_handle_from_pid_and_address(
++ ioparam.pid, ioparam.addr);
++
++ if (copy_to_user((void *)arg,
++ &ioparam, sizeof(ioparam)) != 0) {
++ pr_err("[%s]: failed to copy-to-user for cmd %x\n",
++ __func__, cmdnr);
++
++ ret = -EFAULT;
++ }
++
++ /* Done.
++ */
++ goto out;
++ }
++ break;
++
++ /* Maps a videocore handle given process and user handle. */
++ case VMCS_SM_CMD_MAPPED_VC_HDL_FROM_HDL:
++ {
++ struct vmcs_sm_ioctl_map ioparam;
++
++ /* Get parameter data. */
++ if (copy_from_user(&ioparam,
++ (void *)arg, sizeof(ioparam)) != 0) {
++ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
++ __func__, cmdnr);
++ ret = -EFAULT;
++ goto out;
++ }
++
++ /* Locate resource from GUID. */
++ resource =
++ vmcs_sm_acquire_resource(file_data, ioparam.handle);
++ if (resource != NULL) {
++ ioparam.handle = resource->res_handle;
++ vmcs_sm_release_resource(resource, 0);
++ } else {
++ ioparam.handle = 0;
++ }
++
++ if (copy_to_user((void *)arg,
++ &ioparam, sizeof(ioparam)) != 0) {
++ pr_err("[%s]: failed to copy-to-user for cmd %x\n",
++ __func__, cmdnr);
++
++ ret = -EFAULT;
++ }
++
++ /* Done. */
++ goto out;
++ }
++ break;
++
++ /*
++ * Maps a videocore address given process and videocore handle.
++ */
++ case VMCS_SM_CMD_MAPPED_VC_ADDR_FROM_HDL:
++ {
++ struct vmcs_sm_ioctl_map ioparam;
++
++ /* Get parameter data. */
++ if (copy_from_user(&ioparam,
++ (void *)arg, sizeof(ioparam)) != 0) {
++ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
++ __func__, cmdnr);
++
++ ret = -EFAULT;
++ goto out;
++ }
++
++ /* Locate resource from GUID. */
++ resource =
++ vmcs_sm_acquire_resource(file_data, ioparam.handle);
++ if (resource != NULL) {
++ ioparam.addr =
++ (unsigned int)resource->res_base_mem;
++ vmcs_sm_release_resource(resource, 0);
++ } else {
++ ioparam.addr = 0;
++ }
++
++ if (copy_to_user((void *)arg,
++ &ioparam, sizeof(ioparam)) != 0) {
++ pr_err("[%s]: failed to copy-to-user for cmd %x\n",
++ __func__, cmdnr);
++ ret = -EFAULT;
++ }
++
++ /* Done. */
++ goto out;
++ }
++ break;
++
++ /* Maps a user address given process and vc handle.
++ */
++ case VMCS_SM_CMD_MAPPED_USR_ADDRESS:
++ {
++ struct vmcs_sm_ioctl_map ioparam;
++
++ /* Get parameter data. */
++ if (copy_from_user(&ioparam,
++ (void *)arg, sizeof(ioparam)) != 0) {
++ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
++ __func__, cmdnr);
++ ret = -EFAULT;
++ goto out;
++ }
++
++ /*
++ * Return the address information from the mapping,
++ * 0 (ie NULL) if it cannot locate the actual mapping.
++ */
++ ioparam.addr =
++ vmcs_sm_usr_address_from_pid_and_usr_handle
++ (ioparam.pid, ioparam.handle);
++
++ if (copy_to_user((void *)arg,
++ &ioparam, sizeof(ioparam)) != 0) {
++ pr_err("[%s]: failed to copy-to-user for cmd %x\n",
++ __func__, cmdnr);
++ ret = -EFAULT;
++ }
++
++ /* Done. */
++ goto out;
++ }
++ break;
++
++ /* Flush the cache for a given mapping. */
++ case VMCS_SM_CMD_FLUSH:
++ {
++ struct vmcs_sm_ioctl_cache ioparam;
++
++ /* Get parameter data. */
++ if (copy_from_user(&ioparam,
++ (void *)arg, sizeof(ioparam)) != 0) {
++ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
++ __func__, cmdnr);
++ ret = -EFAULT;
++ goto out;
++ }
++
++ /* Locate resource from GUID. */
++ resource =
++ vmcs_sm_acquire_resource(file_data, ioparam.handle);
++
++ if ((resource != NULL) && resource->res_cached) {
++ dma_addr_t phys_addr = 0;
++
++ resource->res_stats[FLUSH]++;
++
++ phys_addr =
++ (dma_addr_t)((uint32_t)
++ resource->res_base_mem &
++ 0x3FFFFFFF);
++ phys_addr += (dma_addr_t)mm_vc_mem_phys_addr;
++
++ /* L1 cache flush */
++ down_read(&current->mm->mmap_sem);
++ vcsm_vma_cache_clean_page_range((unsigned long)
++ ioparam.addr,
++ (unsigned long)
++ ioparam.addr +
++ ioparam.size);
++ up_read(&current->mm->mmap_sem);
++
++ /* L2 cache flush */
++ outer_clean_range(phys_addr,
++ phys_addr +
++ (size_t) ioparam.size);
++ } else if (resource == NULL) {
++ ret = -EINVAL;
++ goto out;
++ }
++
++ if (resource)
++ vmcs_sm_release_resource(resource, 0);
++
++ /* Done. */
++ goto out;
++ }
++ break;
++
++ /* Invalidate the cache for a given mapping. */
++ case VMCS_SM_CMD_INVALID:
++ {
++ struct vmcs_sm_ioctl_cache ioparam;
++
++ /* Get parameter data. */
++ if (copy_from_user(&ioparam,
++ (void *)arg, sizeof(ioparam)) != 0) {
++ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
++ __func__, cmdnr);
++ ret = -EFAULT;
++ goto out;
++ }
++
++ /* Locate resource from GUID.
++ */
++ resource =
++ vmcs_sm_acquire_resource(file_data, ioparam.handle);
++
++ if ((resource != NULL) && resource->res_cached) {
++ dma_addr_t phys_addr = 0;
++
++ resource->res_stats[INVALID]++;
++
++ phys_addr =
++ (dma_addr_t)((uint32_t)
++ resource->res_base_mem &
++ 0x3FFFFFFF);
++ phys_addr += (dma_addr_t)mm_vc_mem_phys_addr;
++
++ /* L2 cache invalidate */
++ outer_inv_range(phys_addr,
++ phys_addr +
++ (size_t) ioparam.size);
++
++ /* L1 cache invalidate */
++ down_read(&current->mm->mmap_sem);
++ vcsm_vma_cache_clean_page_range((unsigned long)
++ ioparam.addr,
++ (unsigned long)
++ ioparam.addr +
++ ioparam.size);
++ up_read(&current->mm->mmap_sem);
++ } else if (resource == NULL) {
++ ret = -EINVAL;
++ goto out;
++ }
++
++ if (resource)
++ vmcs_sm_release_resource(resource, 0);
++
++ /* Done.
++ */
++ goto out;
++ }
++ break;
++
++ /* Flush/Invalidate the cache for a given mapping. */
++ case VMCS_SM_CMD_CLEAN_INVALID:
++ {
++ int i;
++ struct vmcs_sm_ioctl_clean_invalid ioparam;
++
++ /* Get parameter data. */
++ if (copy_from_user(&ioparam,
++ (void *)arg, sizeof(ioparam)) != 0) {
++ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
++ __func__, cmdnr);
++ ret = -EFAULT;
++ goto out;
++ }
++ for (i=0; i<sizeof ioparam.s/sizeof *ioparam.s; i++) {
++ switch (ioparam.s[i].cmd) {
++ default: case 0: break; /* NOOP */
++ case 1: /* L1/L2 invalidate virtual range */
++ case 2: /* L1/L2 clean physical range */
++ case 3: /* L1/L2 clean+invalidate all */
++ {
++ /* Locate resource from GUID.
++ */
++ resource =
++ vmcs_sm_acquire_resource(file_data, ioparam.s[i].handle);
++
++ if ((resource != NULL) && resource->res_cached) {
++ unsigned long base = ioparam.s[i].addr & ~(PAGE_SIZE-1);
++ unsigned long end = (ioparam.s[i].addr + ioparam.s[i].size + PAGE_SIZE-1) & ~(PAGE_SIZE-1);
++ resource->res_stats[ioparam.s[i].cmd == 1 ? INVALID:FLUSH]++;
++
++ /* L1/L2 cache flush */
++ down_read(&current->mm->mmap_sem);
++ vcsm_vma_cache_clean_page_range(base, end);
++ up_read(&current->mm->mmap_sem);
++ } else if (resource == NULL) {
++ ret = -EINVAL;
++ goto out;
++ }
++
++ if (resource)
++ vmcs_sm_release_resource(resource, 0);
++ }
++ break;
++ }
++ }
++ }
++ break;
++
++ default:
++ {
++ ret = -EINVAL;
++ goto out;
++ }
++ break;
++ }
++
++out:
++ return ret;
++}
++
++/* Device operations that we managed in this driver.
++*/
++static const struct file_operations vmcs_sm_ops = {
++ .owner = THIS_MODULE,
++ .unlocked_ioctl = vc_sm_ioctl,
++ .open = vc_sm_open,
++ .release = vc_sm_release,
++ .mmap = vc_sm_mmap,
++};
++
++/* Creation of device.
++*/
++static int vc_sm_create_sharedmemory(void)
++{
++ int ret;
++
++ if (sm_state == NULL) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ /* Create a device class for creating dev nodes.
++ */
++ sm_state->sm_class = class_create(THIS_MODULE, "vc-sm");
++ if (IS_ERR(sm_state->sm_class)) {
++ pr_err("[%s]: unable to create device class\n", __func__);
++ ret = PTR_ERR(sm_state->sm_class);
++ goto out;
++ }
++
++ /* Create a character driver.
++ */
++ ret = alloc_chrdev_region(&sm_state->sm_devid,
++ DEVICE_MINOR, 1, DEVICE_NAME);
++ if (ret != 0) {
++ pr_err("[%s]: unable to allocate device number\n", __func__);
++ goto out_dev_class_destroy;
++ }
++
++ cdev_init(&sm_state->sm_cdev, &vmcs_sm_ops);
++ ret = cdev_add(&sm_state->sm_cdev, sm_state->sm_devid, 1);
++ if (ret != 0) {
++ pr_err("[%s]: unable to register device\n", __func__);
++ goto out_chrdev_unreg;
++ }
++
++ /* Create a device node.
++ */
++ sm_state->sm_dev = device_create(sm_state->sm_class,
++ NULL,
++ MKDEV(MAJOR(sm_state->sm_devid),
++ DEVICE_MINOR), NULL,
++ DEVICE_NAME);
++ if (IS_ERR(sm_state->sm_dev)) {
++ pr_err("[%s]: unable to create device node\n", __func__);
++ ret = PTR_ERR(sm_state->sm_dev);
++ goto out_chrdev_del;
++ }
++
++ goto out;
++
++out_chrdev_del:
++ cdev_del(&sm_state->sm_cdev);
++out_chrdev_unreg:
++ unregister_chrdev_region(sm_state->sm_devid, 1);
++out_dev_class_destroy:
++ class_destroy(sm_state->sm_class);
++ sm_state->sm_class = NULL;
++out:
++ return ret;
++}
++
++/* Termination of the device.
++*/
++static int vc_sm_remove_sharedmemory(void)
++{
++ int ret;
++
++ if (sm_state == NULL) {
++ /* Nothing to do.
++ */
++ ret = 0;
++ goto out;
++ }
++
++ /* Remove the sharedmemory character driver.
++ */
++ cdev_del(&sm_state->sm_cdev);
++
++ /* Unregister region.
++ */
++ unregister_chrdev_region(sm_state->sm_devid, 1);
++
++ ret = 0;
++ goto out;
++
++out:
++ return ret;
++}
++
++/* Videocore connected. */
++static void vc_sm_connected_init(void)
++{
++ int ret;
++ VCHI_INSTANCE_T vchi_instance;
++ VCHI_CONNECTION_T *vchi_connection = NULL;
++
++ pr_info("[%s]: start\n", __func__);
++
++ /* Allocate memory for the state structure.
++ */
++ sm_state = kzalloc(sizeof(struct SM_STATE_T), GFP_KERNEL);
++ if (sm_state == NULL) {
++ pr_err("[%s]: failed to allocate memory\n", __func__);
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ mutex_init(&sm_state->lock);
++ mutex_init(&sm_state->map_lock);
++
++ /* Initialize and create a VCHI connection for the shared memory service
++ ** running on videocore.
++ */
++ ret = vchi_initialise(&vchi_instance);
++ if (ret != 0) {
++ pr_err("[%s]: failed to initialise VCHI instance (ret=%d)\n",
++ __func__, ret);
++
++ ret = -EIO;
++ goto err_free_mem;
++ }
++
++ ret = vchi_connect(NULL, 0, vchi_instance);
++ if (ret != 0) {
++ pr_err("[%s]: failed to connect VCHI instance (ret=%d)\n",
++ __func__, ret);
++
++ ret = -EIO;
++ goto err_free_mem;
++ }
++
++ /* Initialize an instance of the shared memory service. */
++ sm_state->sm_handle =
++ vc_vchi_sm_init(vchi_instance, &vchi_connection, 1);
++ if (sm_state->sm_handle == NULL) {
++ pr_err("[%s]: failed to initialize shared memory service\n",
++ __func__);
++
++ ret = -EPERM;
++ goto err_free_mem;
++ }
++
++ /* Create a debug fs directory entry (root). */
++ sm_state->dir_root = debugfs_create_dir(VC_SM_DIR_ROOT_NAME, NULL);
++ if (!sm_state->dir_root) {
++ pr_err("[%s]: failed to create \'%s\' directory entry\n",
++ __func__, VC_SM_DIR_ROOT_NAME);
++
++ ret = -EPERM;
++ goto err_stop_sm_service;
++ }
++
++ sm_state->dir_state.show = &vc_sm_global_state_show;
++ sm_state->dir_state.dir_entry = debugfs_create_file(VC_SM_STATE,
++ S_IRUGO, sm_state->dir_root, &sm_state->dir_state,
++ &vc_sm_debug_fs_fops);
++
++ sm_state->dir_stats.show = &vc_sm_global_statistics_show;
++ sm_state->dir_stats.dir_entry = debugfs_create_file(VC_SM_STATS,
++ S_IRUGO, sm_state->dir_root, &sm_state->dir_stats,
++ &vc_sm_debug_fs_fops);
++
++ /* Create the proc entry children. */
++ sm_state->dir_alloc = debugfs_create_dir(VC_SM_DIR_ALLOC_NAME,
++ sm_state->dir_root);
++
++ /* Create a shared memory device. */
++ ret = vc_sm_create_sharedmemory();
++ if (ret != 0) {
++ pr_err("[%s]: failed to create shared memory device\n",
++ __func__);
++ goto err_remove_debugfs;
++ }
++
++ INIT_LIST_HEAD(&sm_state->map_list);
++ INIT_LIST_HEAD(&sm_state->resource_list);
++
++ sm_state->data_knl = vc_sm_create_priv_data(0);
++ if (sm_state->data_knl == NULL) {
++ pr_err("[%s]: failed to create kernel private data tracker\n",
++ __func__);
++ goto err_remove_shared_memory;
++ }
++
++ /* Done!
++ */
++ sm_inited = 1;
++ goto out;
++
++err_remove_shared_memory:
++ vc_sm_remove_sharedmemory();
++err_remove_debugfs:
++ debugfs_remove_recursive(sm_state->dir_root);
++err_stop_sm_service:
++ vc_vchi_sm_stop(&sm_state->sm_handle);
++err_free_mem:
++ kfree(sm_state);
++out:
++ pr_info("[%s]: end - returning %d\n", __func__, ret);
++}
++
++/* Driver loading. */
++static int __init vc_sm_init(void)
++{
++ pr_info("vc-sm: Videocore shared memory driver\n");
++ vchiq_add_connected_callback(vc_sm_connected_init);
++ return 0;
++}
++
++/* Driver unloading. */
++static void __exit vc_sm_exit(void)
++{
++ pr_debug("[%s]: start\n", __func__);
++ if (sm_inited) {
++ /* Remove shared memory device.
++ */
++ vc_sm_remove_sharedmemory();
++
++ /* Remove all proc entries.
++ */
++ debugfs_remove_recursive(sm_state->dir_root);
++
++ /* Stop the videocore shared memory service.
++ */
++ vc_vchi_sm_stop(&sm_state->sm_handle);
++
++ /* Free the memory for the state structure.
++ */
++ mutex_destroy(&(sm_state->map_lock));
++ kfree(sm_state);
++ }
++
++ pr_debug("[%s]: end\n", __func__);
++}
++
++#if defined(__KERNEL__)
++/* Allocate a shared memory handle and block. */
++int vc_sm_alloc(VC_SM_ALLOC_T *alloc, int *handle)
++{
++ struct vmcs_sm_ioctl_alloc ioparam = { 0 };
++ int ret;
++ struct SM_RESOURCE_T *resource;
++
++ /* Validate we can work with this device.
++ */
++ if (sm_state == NULL || alloc == NULL || handle == NULL) {
++ pr_err("[%s]: invalid input\n", __func__);
++ return -EPERM;
++ }
++
++ ioparam.size = alloc->base_unit;
++ ioparam.num = alloc->num_unit;
++ ioparam.cached =
++ alloc->type == VC_SM_ALLOC_CACHED ? VMCS_SM_CACHE_VC : 0;
++
++ ret = vc_sm_ioctl_alloc(sm_state->data_knl, &ioparam);
++
++ if (ret == 0) {
++ resource =
++ vmcs_sm_acquire_resource(sm_state->data_knl,
++ ioparam.handle);
++ if (resource) {
++ resource->pid = 0;
++ vmcs_sm_release_resource(resource, 0);
++
++ /* Assign valid handle at this time.
++ */
++ *handle = ioparam.handle;
++ } else {
++ ret = -ENOMEM;
++ }
++ }
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(vc_sm_alloc);
++
++/* Get an internal resource handle mapped from the external one.
++*/
++int vc_sm_int_handle(int handle)
++{
++ struct SM_RESOURCE_T *resource;
++ int ret = 0;
++
++ /* Validate we can work with this device.
++ */
++ if (sm_state == NULL || handle == 0) {
++ pr_err("[%s]: invalid input\n", __func__);
++ return 0;
++ }
++
++ /* Locate resource from GUID.
++ */
++ resource = vmcs_sm_acquire_resource(sm_state->data_knl, handle);
++ if (resource) {
++ ret = resource->res_handle;
++ vmcs_sm_release_resource(resource, 0);
++ }
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(vc_sm_int_handle);
++
++/* Free a previously allocated shared memory handle and block.
++*/
++int vc_sm_free(int handle)
++{
++ struct vmcs_sm_ioctl_free ioparam = { handle };
++
++ /* Validate we can work with this device.
++ */
++ if (sm_state == NULL || handle == 0) {
++ pr_err("[%s]: invalid input\n", __func__);
++ return -EPERM;
++ }
++
++ return vc_sm_ioctl_free(sm_state->data_knl, &ioparam);
++}
++EXPORT_SYMBOL_GPL(vc_sm_free);
++
++/* Lock a memory handle for use by kernel.
++*/
++int vc_sm_lock(int handle, VC_SM_LOCK_CACHE_MODE_T mode,
++ long unsigned int *data)
++{
++ struct vmcs_sm_ioctl_lock_unlock ioparam;
++ int ret;
++
++ /* Validate we can work with this device.
++ */
++ if (sm_state == NULL || handle == 0 || data == NULL) {
++ pr_err("[%s]: invalid input\n", __func__);
++ return -EPERM;
++ }
++
++ *data = 0;
++
++ ioparam.handle = handle;
++ ret = vc_sm_ioctl_lock(sm_state->data_knl,
++ &ioparam,
++ 1,
++ ((mode ==
++ VC_SM_LOCK_CACHED) ? VMCS_SM_CACHE_HOST :
++ VMCS_SM_CACHE_NONE), 0);
++
++ *data = ioparam.addr;
++ return ret;
++}
++EXPORT_SYMBOL_GPL(vc_sm_lock);
++
++/* Unlock a memory handle in use by kernel.
++*/
++int vc_sm_unlock(int handle, int flush, int no_vc_unlock)
++{
++ struct vmcs_sm_ioctl_lock_unlock ioparam;
++
++ /* Validate we can work with this device.
++ */
++ if (sm_state == NULL || handle == 0) {
++ pr_err("[%s]: invalid input\n", __func__);
++ return -EPERM;
++ }
++
++ ioparam.handle = handle;
++ return vc_sm_ioctl_unlock(sm_state->data_knl,
++ &ioparam, flush, 0, no_vc_unlock);
++}
++EXPORT_SYMBOL_GPL(vc_sm_unlock);
++
++/* Map a shared memory region for use by kernel.
++*/
++int vc_sm_map(int handle, unsigned int sm_addr, VC_SM_LOCK_CACHE_MODE_T mode,
++ long unsigned int *data)
++{
++ struct vmcs_sm_ioctl_lock_unlock ioparam;
++ int ret;
++
++ /* Validate we can work with this device.
++ */
++ if (sm_state == NULL || handle == 0 || data == NULL || sm_addr == 0) {
++ pr_err("[%s]: invalid input\n", __func__);
++ return -EPERM;
++ }
++
++ *data = 0;
++
++ ioparam.handle = handle;
++ ret = vc_sm_ioctl_lock(sm_state->data_knl,
++ &ioparam,
++ 1,
++ ((mode ==
++ VC_SM_LOCK_CACHED) ? VMCS_SM_CACHE_HOST :
++ VMCS_SM_CACHE_NONE), sm_addr);
++
++ *data = ioparam.addr;
++ return ret;
++}
++EXPORT_SYMBOL_GPL(vc_sm_map);
++#endif
++
++late_initcall(vc_sm_init);
++module_exit(vc_sm_exit);
++
++MODULE_AUTHOR("Broadcom");
++MODULE_DESCRIPTION("VideoCore SharedMemory Driver");
++MODULE_LICENSE("GPL v2");
+--- /dev/null
++++ b/include/linux/broadcom/vmcs_sm_ioctl.h
+@@ -0,0 +1,248 @@
++/*****************************************************************************
++* Copyright 2011 Broadcom Corporation. All rights reserved.
++*
++* Unless you and Broadcom execute a separate written software license
++* agreement governing use of this software, this software is licensed to you
++* under the terms of the GNU General Public License version 2, available at
++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
++*
++* Notwithstanding the above, under no circumstances may you combine this
++* software in any way with any other Broadcom software provided under a
++* license other than the GPL, without Broadcom's express prior written
++* consent.
++*
++*****************************************************************************/
++
++#if !defined(__VMCS_SM_IOCTL_H__INCLUDED__)
++#define __VMCS_SM_IOCTL_H__INCLUDED__
++
++/* ---- Include Files ---------------------------------------------------- */
++
++#if defined(__KERNEL__)
++#include <linux/types.h> /* Needed for standard types */
++#else
++#include <stdint.h>
++#endif
++
++#include <linux/ioctl.h>
++
++/* ---- Constants and Types ---------------------------------------------- */
++
++#define VMCS_SM_RESOURCE_NAME 32
++#define VMCS_SM_RESOURCE_NAME_DEFAULT "sm-host-resource"
++
++/* Type define used to create unique IOCTL number */
++#define VMCS_SM_MAGIC_TYPE 'I'
++
++/* IOCTL commands */
++enum vmcs_sm_cmd_e {
++ VMCS_SM_CMD_ALLOC = 0x5A, /* Start at 0x5A arbitrarily */
++ VMCS_SM_CMD_ALLOC_SHARE,
++ VMCS_SM_CMD_LOCK,
++ VMCS_SM_CMD_LOCK_CACHE,
++ VMCS_SM_CMD_UNLOCK,
++ VMCS_SM_CMD_RESIZE,
++ VMCS_SM_CMD_UNMAP,
++ VMCS_SM_CMD_FREE,
++ VMCS_SM_CMD_FLUSH,
++ VMCS_SM_CMD_INVALID,
++
++ VMCS_SM_CMD_SIZE_USR_HANDLE,
++ VMCS_SM_CMD_CHK_USR_HANDLE,
++
++ VMCS_SM_CMD_MAPPED_USR_HANDLE,
++ VMCS_SM_CMD_MAPPED_USR_ADDRESS,
++ VMCS_SM_CMD_MAPPED_VC_HDL_FROM_ADDR,
++ VMCS_SM_CMD_MAPPED_VC_HDL_FROM_HDL,
++ VMCS_SM_CMD_MAPPED_VC_ADDR_FROM_HDL,
++
++ VMCS_SM_CMD_VC_WALK_ALLOC,
++ VMCS_SM_CMD_HOST_WALK_MAP,
++ VMCS_SM_CMD_HOST_WALK_PID_ALLOC,
++ VMCS_SM_CMD_HOST_WALK_PID_MAP,
++
++ VMCS_SM_CMD_CLEAN_INVALID,
++
++ VMCS_SM_CMD_LAST /* Do no delete */
++};
++
++/* Cache type supported, conveniently matches the user space definition in
++** user-vcsm.h.
++*/
++enum vmcs_sm_cache_e {
++ VMCS_SM_CACHE_NONE,
++ VMCS_SM_CACHE_HOST,
++ VMCS_SM_CACHE_VC,
++ VMCS_SM_CACHE_BOTH,
++};
++
++/* IOCTL Data structures */
++struct vmcs_sm_ioctl_alloc {
++ /* user -> kernel */
++ unsigned int size;
++ unsigned int num;
++ enum vmcs_sm_cache_e cached;
++ char name[VMCS_SM_RESOURCE_NAME];
++
++ /* kernel -> user */
++ unsigned int handle;
++ /* unsigned int base_addr; */
++};
++
++struct vmcs_sm_ioctl_alloc_share {
++ /* user -> kernel */
++ unsigned int handle;
++ unsigned int size;
++};
++
++struct vmcs_sm_ioctl_free {
++ /* user -> kernel */
++ unsigned int handle;
++ /* unsigned int base_addr; */
++};
++
++struct vmcs_sm_ioctl_lock_unlock {
++ /* user -> kernel */
++ unsigned int handle;
++
++ /* kernel -> user */
++ unsigned int addr;
++};
++
++struct vmcs_sm_ioctl_lock_cache {
++ /* user -> kernel */
++ unsigned int handle;
++ enum vmcs_sm_cache_e cached;
++};
++
++struct vmcs_sm_ioctl_resize {
++ /* user -> kernel */
++ unsigned int handle;
++ unsigned int new_size;
++
++ /* kernel -> user */
++ unsigned int old_size;
++};
++
++struct vmcs_sm_ioctl_map {
++ /* user -> kernel */
++ /* and kernel -> user */
++ unsigned int pid;
++ unsigned int handle;
++ unsigned int addr;
++
++ /* kernel -> user */
++ unsigned int size;
++};
++
++struct vmcs_sm_ioctl_walk {
++ /* user -> kernel */
++ unsigned int pid;
++};
++
++struct vmcs_sm_ioctl_chk {
++ /* user -> kernel */
++ unsigned int handle;
++
++ /* kernel -> user */
++ unsigned int addr;
++ unsigned int size;
++ enum vmcs_sm_cache_e cache;
++};
++
++struct vmcs_sm_ioctl_size {
++ /* user -> kernel */
++ unsigned int handle;
++
++ /* kernel -> user */
++ unsigned int size;
++};
++
++struct vmcs_sm_ioctl_cache {
++ /* user -> kernel */
++ unsigned int handle;
++ unsigned int addr;
++ unsigned int size;
++};
++
++struct vmcs_sm_ioctl_clean_invalid {
++ /* user -> kernel */
++ struct {
++ unsigned int cmd;
++ unsigned int handle;
++ unsigned int addr;
++ unsigned int size;
++ } s[8];
++};
++
++/* IOCTL numbers */
++#define VMCS_SM_IOCTL_MEM_ALLOC\
++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_ALLOC,\
++ struct vmcs_sm_ioctl_alloc)
++#define VMCS_SM_IOCTL_MEM_ALLOC_SHARE\
++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_ALLOC_SHARE,\
++ struct vmcs_sm_ioctl_alloc_share)
++#define VMCS_SM_IOCTL_MEM_LOCK\
++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_LOCK,\
++ struct vmcs_sm_ioctl_lock_unlock)
++#define VMCS_SM_IOCTL_MEM_LOCK_CACHE\
++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_LOCK_CACHE,\
++ struct vmcs_sm_ioctl_lock_cache)
++#define VMCS_SM_IOCTL_MEM_UNLOCK\
++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_UNLOCK,\
++ struct vmcs_sm_ioctl_lock_unlock)
++#define VMCS_SM_IOCTL_MEM_RESIZE\
++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_RESIZE,\
++ struct vmcs_sm_ioctl_resize)
++#define VMCS_SM_IOCTL_MEM_FREE\
++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_FREE,\
++ struct vmcs_sm_ioctl_free)
++#define VMCS_SM_IOCTL_MEM_FLUSH\
++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_FLUSH,\
++ struct vmcs_sm_ioctl_cache)
++#define VMCS_SM_IOCTL_MEM_INVALID\
++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_INVALID,\
++ struct vmcs_sm_ioctl_cache)
++#define VMCS_SM_IOCTL_MEM_CLEAN_INVALID\
++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_CLEAN_INVALID,\
++ struct vmcs_sm_ioctl_clean_invalid)
++
++#define VMCS_SM_IOCTL_SIZE_USR_HDL\
++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_SIZE_USR_HANDLE,\
++ struct vmcs_sm_ioctl_size)
++#define VMCS_SM_IOCTL_CHK_USR_HDL\
++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_CHK_USR_HANDLE,\
++ struct vmcs_sm_ioctl_chk)
++
++#define VMCS_SM_IOCTL_MAP_USR_HDL\
++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_MAPPED_USR_HANDLE,\
++ struct vmcs_sm_ioctl_map)
++#define VMCS_SM_IOCTL_MAP_USR_ADDRESS\
++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_MAPPED_USR_ADDRESS,\
++ struct vmcs_sm_ioctl_map)
++#define VMCS_SM_IOCTL_MAP_VC_HDL_FR_ADDR\
++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_MAPPED_VC_HDL_FROM_ADDR,\
++ struct vmcs_sm_ioctl_map)
++#define VMCS_SM_IOCTL_MAP_VC_HDL_FR_HDL\
++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_MAPPED_VC_HDL_FROM_HDL,\
++ struct vmcs_sm_ioctl_map)
++#define VMCS_SM_IOCTL_MAP_VC_ADDR_FR_HDL\
++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_MAPPED_VC_ADDR_FROM_HDL,\
++ struct vmcs_sm_ioctl_map)
++
++#define VMCS_SM_IOCTL_VC_WALK_ALLOC\
++ _IO(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_VC_WALK_ALLOC)
++#define VMCS_SM_IOCTL_HOST_WALK_MAP\
++ _IO(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_HOST_WALK_MAP)
++#define VMCS_SM_IOCTL_HOST_WALK_PID_ALLOC\
++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_HOST_WALK_PID_ALLOC,\
++ struct vmcs_sm_ioctl_walk)
++#define VMCS_SM_IOCTL_HOST_WALK_PID_MAP\
++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_HOST_WALK_PID_MAP,\
++ struct vmcs_sm_ioctl_walk)
++
++/* ---- Variable Externs ------------------------------------------------- */
++
++/* ---- Function Prototypes ---------------------------------------------- */
++
++#endif /* __VMCS_SM_IOCTL_H__INCLUDED__ */
diff --git a/target/linux/brcm2708/patches-4.4/0039-Add-dev-gpiomem-device-for-rootless-user-GPIO-access.patch b/target/linux/brcm2708/patches-4.4/0039-Add-dev-gpiomem-device-for-rootless-user-GPIO-access.patch
new file mode 100644
index 0000000000..1d75def84a
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0039-Add-dev-gpiomem-device-for-rootless-user-GPIO-access.patch
@@ -0,0 +1,306 @@
+From 60d7c4ca1dd8ff0ab4d84f0b3d1d3aaeecede4d7 Mon Sep 17 00:00:00 2001
+From: Luke Wren <luke@raspberrypi.org>
+Date: Fri, 21 Aug 2015 23:14:48 +0100
+Subject: [PATCH 039/381] Add /dev/gpiomem device for rootless user GPIO access
+
+Signed-off-by: Luke Wren <luke@raspberrypi.org>
+
+bcm2835-gpiomem: Fix for ARCH_BCM2835 builds
+
+Build on ARCH_BCM2835, and fail to probe if no IO resource.
+
+See: https://github.com/raspberrypi/linux/issues/1154
+---
+ drivers/char/broadcom/Kconfig | 9 ++
+ drivers/char/broadcom/Makefile | 3 +
+ drivers/char/broadcom/bcm2835-gpiomem.c | 260 ++++++++++++++++++++++++++++++++
+ 3 files changed, 272 insertions(+)
+ create mode 100644 drivers/char/broadcom/bcm2835-gpiomem.c
+
+--- a/drivers/char/broadcom/Kconfig
++++ b/drivers/char/broadcom/Kconfig
+@@ -32,3 +32,12 @@ config BCM_VC_SM
+ help
+ Support for the VC shared memory on the Broadcom reference
+ design. Uses the VCHIQ stack.
++
++config BCM2835_DEVGPIOMEM
++ tristate "/dev/gpiomem rootless GPIO access via mmap() on the BCM2835"
++ default m
++ help
++ Provides users with root-free access to the GPIO registers
++ on the 2835. Calling mmap(/dev/gpiomem) will map the GPIO
++ register page to the user's pointer.
++
+--- a/drivers/char/broadcom/Makefile
++++ b/drivers/char/broadcom/Makefile
+@@ -1,3 +1,6 @@
+ obj-$(CONFIG_BCM_VC_CMA) += vc_cma/
+ obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o
+ obj-$(CONFIG_BCM_VC_SM) += vc_sm/
++
++obj-$(CONFIG_BCM2835_DEVGPIOMEM)+= bcm2835-gpiomem.o
++
+--- /dev/null
++++ b/drivers/char/broadcom/bcm2835-gpiomem.c
+@@ -0,0 +1,260 @@
++/**
++ * GPIO memory device driver
++ *
++ * Creates a chardev /dev/gpiomem which will provide user access to
++ * the BCM2835's GPIO registers when it is mmap()'d.
++ * No longer need root for user GPIO access, but without relaxing permissions
++ * on /dev/mem.
++ *
++ * Written by Luke Wren <luke@raspberrypi.org>
++ * Copyright (c) 2015, Raspberry Pi (Trading) Ltd.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/cdev.h>
++#include <linux/pagemap.h>
++#include <linux/io.h>
++
++#define DEVICE_NAME "bcm2835-gpiomem"
++#define DRIVER_NAME "gpiomem-bcm2835"
++#define DEVICE_MINOR 0
++
++struct bcm2835_gpiomem_instance {
++ unsigned long gpio_regs_phys;
++ struct device *dev;
++};
++
++static struct cdev bcm2835_gpiomem_cdev;
++static dev_t bcm2835_gpiomem_devid;
++static struct class *bcm2835_gpiomem_class;
++static struct device *bcm2835_gpiomem_dev;
++static struct bcm2835_gpiomem_instance *inst;
++
++
++/****************************************************************************
++*
++* GPIO mem chardev file ops
++*
++***************************************************************************/
++
++static int bcm2835_gpiomem_open(struct inode *inode, struct file *file)
++{
++ int dev = iminor(inode);
++ int ret = 0;
++
++ dev_info(inst->dev, "gpiomem device opened.");
++
++ if (dev != DEVICE_MINOR) {
++ dev_err(inst->dev, "Unknown minor device: %d", dev);
++ ret = -ENXIO;
++ }
++ return ret;
++}
++
++static int bcm2835_gpiomem_release(struct inode *inode, struct file *file)
++{
++ int dev = iminor(inode);
++ int ret = 0;
++
++ if (dev != DEVICE_MINOR) {
++ dev_err(inst->dev, "Unknown minor device %d", dev);
++ ret = -ENXIO;
++ }
++ return ret;
++}
++
++static const struct vm_operations_struct bcm2835_gpiomem_vm_ops = {
++#ifdef CONFIG_HAVE_IOREMAP_PROT
++ .access = generic_access_phys
++#endif
++};
++
++static int bcm2835_gpiomem_mmap(struct file *file, struct vm_area_struct *vma)
++{
++ /* Ignore what the user says - they're getting the GPIO regs
++ whether they like it or not! */
++ unsigned long gpio_page = inst->gpio_regs_phys >> PAGE_SHIFT;
++
++ vma->vm_page_prot = phys_mem_access_prot(file, gpio_page,
++ PAGE_SIZE,
++ vma->vm_page_prot);
++ vma->vm_ops = &bcm2835_gpiomem_vm_ops;
++ if (remap_pfn_range(vma, vma->vm_start,
++ gpio_page,
++ PAGE_SIZE,
++ vma->vm_page_prot)) {
++ return -EAGAIN;
++ }
++ return 0;
++}
++
++static const struct file_operations
++bcm2835_gpiomem_fops = {
++ .owner = THIS_MODULE,
++ .open = bcm2835_gpiomem_open,
++ .release = bcm2835_gpiomem_release,
++ .mmap = bcm2835_gpiomem_mmap,
++};
++
++
++ /****************************************************************************
++*
++* Probe and remove functions
++*
++***************************************************************************/
++
++
++static int bcm2835_gpiomem_probe(struct platform_device *pdev)
++{
++ int err;
++ void *ptr_err;
++ struct device *dev = &pdev->dev;
++ struct resource *ioresource;
++
++ /* Allocate buffers and instance data */
++
++ inst = kzalloc(sizeof(struct bcm2835_gpiomem_instance), GFP_KERNEL);
++
++ if (!inst) {
++ err = -ENOMEM;
++ goto failed_inst_alloc;
++ }
++
++ inst->dev = dev;
++
++ ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (ioresource) {
++ inst->gpio_regs_phys = ioresource->start;
++ } else {
++ dev_err(inst->dev, "failed to get IO resource");
++ err = -ENOENT;
++ goto failed_get_resource;
++ }
++
++ /* Create character device entries */
++
++ err = alloc_chrdev_region(&bcm2835_gpiomem_devid,
++ DEVICE_MINOR, 1, DEVICE_NAME);
++ if (err != 0) {
++ dev_err(inst->dev, "unable to allocate device number");
++ goto failed_alloc_chrdev;
++ }
++ cdev_init(&bcm2835_gpiomem_cdev, &bcm2835_gpiomem_fops);
++ bcm2835_gpiomem_cdev.owner = THIS_MODULE;
++ err = cdev_add(&bcm2835_gpiomem_cdev, bcm2835_gpiomem_devid, 1);
++ if (err != 0) {
++ dev_err(inst->dev, "unable to register device");
++ goto failed_cdev_add;
++ }
++
++ /* Create sysfs entries */
++
++ bcm2835_gpiomem_class = class_create(THIS_MODULE, DEVICE_NAME);
++ ptr_err = bcm2835_gpiomem_class;
++ if (IS_ERR(ptr_err))
++ goto failed_class_create;
++
++ bcm2835_gpiomem_dev = device_create(bcm2835_gpiomem_class, NULL,
++ bcm2835_gpiomem_devid, NULL,
++ "gpiomem");
++ ptr_err = bcm2835_gpiomem_dev;
++ if (IS_ERR(ptr_err))
++ goto failed_device_create;
++
++ dev_info(inst->dev, "Initialised: Registers at 0x%08lx",
++ inst->gpio_regs_phys);
++
++ return 0;
++
++failed_device_create:
++ class_destroy(bcm2835_gpiomem_class);
++failed_class_create:
++ cdev_del(&bcm2835_gpiomem_cdev);
++ err = PTR_ERR(ptr_err);
++failed_cdev_add:
++ unregister_chrdev_region(bcm2835_gpiomem_devid, 1);
++failed_alloc_chrdev:
++failed_get_resource:
++ kfree(inst);
++failed_inst_alloc:
++ dev_err(inst->dev, "could not load bcm2835_gpiomem");
++ return err;
++}
++
++static int bcm2835_gpiomem_remove(struct platform_device *pdev)
++{
++ struct device *dev = inst->dev;
++
++ kfree(inst);
++ device_destroy(bcm2835_gpiomem_class, bcm2835_gpiomem_devid);
++ class_destroy(bcm2835_gpiomem_class);
++ cdev_del(&bcm2835_gpiomem_cdev);
++ unregister_chrdev_region(bcm2835_gpiomem_devid, 1);
++
++ dev_info(dev, "GPIO mem driver removed - OK");
++ return 0;
++}
++
++ /****************************************************************************
++*
++* Register the driver with device tree
++*
++***************************************************************************/
++
++static const struct of_device_id bcm2835_gpiomem_of_match[] = {
++ {.compatible = "brcm,bcm2835-gpiomem",},
++ { /* sentinel */ },
++};
++
++MODULE_DEVICE_TABLE(of, bcm2835_gpiomem_of_match);
++
++static struct platform_driver bcm2835_gpiomem_driver = {
++ .probe = bcm2835_gpiomem_probe,
++ .remove = bcm2835_gpiomem_remove,
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ .of_match_table = bcm2835_gpiomem_of_match,
++ },
++};
++
++module_platform_driver(bcm2835_gpiomem_driver);
++
++MODULE_ALIAS("platform:gpiomem-bcm2835");
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("gpiomem driver for accessing GPIO from userspace");
++MODULE_AUTHOR("Luke Wren <luke@raspberrypi.org>");
diff --git a/target/linux/brcm2708/patches-4.4/0039-vcsm-VideoCore-shared-memory-service-for-BCM2835.patch b/target/linux/brcm2708/patches-4.4/0039-vcsm-VideoCore-shared-memory-service-for-BCM2835.patch
deleted file mode 100644
index 8940443a0b..0000000000
--- a/target/linux/brcm2708/patches-4.4/0039-vcsm-VideoCore-shared-memory-service-for-BCM2835.patch
+++ /dev/null
@@ -1,4393 +0,0 @@
-From 01574b9e0f1086399e7f796cc1dc8fcadabf4a46 Mon Sep 17 00:00:00 2001
-From: Tim Gover <tgover@broadcom.com>
-Date: Tue, 22 Jul 2014 15:41:04 +0100
-Subject: [PATCH 039/170] vcsm: VideoCore shared memory service for BCM2835
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Add experimental support for the VideoCore shared memory service.
-This allows user processes to allocate memory from VideoCore's
-GPU relocatable heap and mmap the buffers. Additionally, the memory
-handles can passed to other VideoCore services such as MMAL, OpenMax
-and DispmanX
-
-TODO
-* This driver was originally released for BCM28155 which has a different
- cache architecture to BCM2835. Consequently, in this release only
- uncached mappings are supported. However, there's no fundamental
- reason which cached mappings cannot be support or BCM2835
-* More refactoring is required to remove the typedefs.
-* Re-enable the some of the commented out debug-fs statistics which were
- disabled when migrating code from proc-fs.
-* There's a lot of code to support sharing of VCSM in order to support
- Android. This could probably done more cleanly or perhaps just
- removed.
-
-Signed-off-by: Tim Gover <timgover@gmail.com>
-
-config: Disable VC_SM for now to fix hang with cutdown kernel
-
-vcsm: Use boolean as it cannot be built as module
-
-On building the bcm_vc_sm as a module we get the following error:
-
-v7_dma_flush_range and do_munmap are undefined in vc-sm.ko.
-
-Fix by making it not an option to build as module
-
-vcsm: Add ioctl for custom cache flushing
-
-vc-sm: Move headers out of arch directory
-
-Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
----
- drivers/char/broadcom/Kconfig | 9 +
- drivers/char/broadcom/Makefile | 1 +
- drivers/char/broadcom/vc_sm/Makefile | 20 +
- drivers/char/broadcom/vc_sm/vc_sm_defs.h | 181 ++
- drivers/char/broadcom/vc_sm/vc_sm_knl.h | 55 +
- drivers/char/broadcom/vc_sm/vc_vchi_sm.c | 492 +++++
- drivers/char/broadcom/vc_sm/vc_vchi_sm.h | 82 +
- drivers/char/broadcom/vc_sm/vmcs_sm.c | 3211 ++++++++++++++++++++++++++++++
- include/linux/broadcom/vmcs_sm_ioctl.h | 248 +++
- 9 files changed, 4299 insertions(+)
- create mode 100644 drivers/char/broadcom/vc_sm/Makefile
- create mode 100644 drivers/char/broadcom/vc_sm/vc_sm_defs.h
- create mode 100644 drivers/char/broadcom/vc_sm/vc_sm_knl.h
- create mode 100644 drivers/char/broadcom/vc_sm/vc_vchi_sm.c
- create mode 100644 drivers/char/broadcom/vc_sm/vc_vchi_sm.h
- create mode 100644 drivers/char/broadcom/vc_sm/vmcs_sm.c
- create mode 100644 include/linux/broadcom/vmcs_sm_ioctl.h
-
---- a/drivers/char/broadcom/Kconfig
-+++ b/drivers/char/broadcom/Kconfig
-@@ -23,3 +23,12 @@ config BCM2708_VCMEM
- Helper for videocore memory access and total size allocation.
-
- endif
-+
-+config BCM_VC_SM
-+ bool "VMCS Shared Memory"
-+ depends on BCM2708_VCHIQ
-+ select BCM2708_VCMEM
-+ default n
-+ help
-+ Support for the VC shared memory on the Broadcom reference
-+ design. Uses the VCHIQ stack.
---- a/drivers/char/broadcom/Makefile
-+++ b/drivers/char/broadcom/Makefile
-@@ -1,2 +1,3 @@
- obj-$(CONFIG_BCM_VC_CMA) += vc_cma/
- obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o
-+obj-$(CONFIG_BCM_VC_SM) += vc_sm/
---- /dev/null
-+++ b/drivers/char/broadcom/vc_sm/Makefile
-@@ -0,0 +1,20 @@
-+EXTRA_CFLAGS += -Wall -Wstrict-prototypes -Wno-trigraphs -O2
-+
-+EXTRA_CFLAGS += -I"drivers/misc/vc04_services"
-+EXTRA_CFLAGS += -I"drivers/misc/vc04_services/interface/vchi"
-+EXTRA_CFLAGS += -I"drivers/misc/vc04_services/interface/vchiq_arm"
-+EXTRA_CFLAGS += -I"$(srctree)/fs/"
-+
-+EXTRA_CFLAGS += -DOS_ASSERT_FAILURE
-+EXTRA_CFLAGS += -D__STDC_VERSION=199901L
-+EXTRA_CFLAGS += -D__STDC_VERSION__=199901L
-+EXTRA_CFLAGS += -D__VCCOREVER__=0
-+EXTRA_CFLAGS += -D__KERNEL__
-+EXTRA_CFLAGS += -D__linux__
-+EXTRA_CFLAGS += -Werror
-+
-+obj-$(CONFIG_BCM_VC_SM) := vc-sm.o
-+
-+vc-sm-objs := \
-+ vmcs_sm.o \
-+ vc_vchi_sm.o
---- /dev/null
-+++ b/drivers/char/broadcom/vc_sm/vc_sm_defs.h
-@@ -0,0 +1,181 @@
-+/*****************************************************************************
-+* Copyright 2011 Broadcom Corporation. All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*****************************************************************************/
-+
-+#ifndef __VC_SM_DEFS_H__INCLUDED__
-+#define __VC_SM_DEFS_H__INCLUDED__
-+
-+/* FourCC code used for VCHI connection */
-+#define VC_SM_SERVER_NAME MAKE_FOURCC("SMEM")
-+
-+/* Maximum message length */
-+#define VC_SM_MAX_MSG_LEN (sizeof(VC_SM_MSG_UNION_T) + \
-+ sizeof(VC_SM_MSG_HDR_T))
-+#define VC_SM_MAX_RSP_LEN (sizeof(VC_SM_MSG_UNION_T))
-+
-+/* Resource name maximum size */
-+#define VC_SM_RESOURCE_NAME 32
-+
-+/* All message types supported for HOST->VC direction */
-+typedef enum {
-+ /* Allocate shared memory block */
-+ VC_SM_MSG_TYPE_ALLOC,
-+ /* Lock allocated shared memory block */
-+ VC_SM_MSG_TYPE_LOCK,
-+ /* Unlock allocated shared memory block */
-+ VC_SM_MSG_TYPE_UNLOCK,
-+ /* Unlock allocated shared memory block, do not answer command */
-+ VC_SM_MSG_TYPE_UNLOCK_NOANS,
-+ /* Free shared memory block */
-+ VC_SM_MSG_TYPE_FREE,
-+ /* Resize a shared memory block */
-+ VC_SM_MSG_TYPE_RESIZE,
-+ /* Walk the allocated shared memory block(s) */
-+ VC_SM_MSG_TYPE_WALK_ALLOC,
-+
-+ /* A previously applied action will need to be reverted */
-+ VC_SM_MSG_TYPE_ACTION_CLEAN,
-+ VC_SM_MSG_TYPE_MAX
-+} VC_SM_MSG_TYPE;
-+
-+/* Type of memory to be allocated */
-+typedef enum {
-+ VC_SM_ALLOC_CACHED,
-+ VC_SM_ALLOC_NON_CACHED,
-+
-+} VC_SM_ALLOC_TYPE_T;
-+
-+/* Message header for all messages in HOST->VC direction */
-+typedef struct {
-+ int32_t type;
-+ uint32_t trans_id;
-+ uint8_t body[0];
-+
-+} VC_SM_MSG_HDR_T;
-+
-+/* Request to allocate memory (HOST->VC) */
-+typedef struct {
-+ /* type of memory to allocate */
-+ VC_SM_ALLOC_TYPE_T type;
-+ /* byte amount of data to allocate per unit */
-+ uint32_t base_unit;
-+ /* number of unit to allocate */
-+ uint32_t num_unit;
-+ /* alignement to be applied on allocation */
-+ uint32_t alignement;
-+ /* identity of who allocated this block */
-+ uint32_t allocator;
-+ /* resource name (for easier tracking on vc side) */
-+ char name[VC_SM_RESOURCE_NAME];
-+
-+} VC_SM_ALLOC_T;
-+
-+/* Result of a requested memory allocation (VC->HOST) */
-+typedef struct {
-+ /* Transaction identifier */
-+ uint32_t trans_id;
-+
-+ /* Resource handle */
-+ uint32_t res_handle;
-+ /* Pointer to resource buffer */
-+ void *res_mem;
-+ /* Resource base size (bytes) */
-+ uint32_t res_base_size;
-+ /* Resource number */
-+ uint32_t res_num;
-+
-+} VC_SM_ALLOC_RESULT_T;
-+
-+/* Request to free a previously allocated memory (HOST->VC) */
-+typedef struct {
-+ /* Resource handle (returned from alloc) */
-+ uint32_t res_handle;
-+ /* Resource buffer (returned from alloc) */
-+ void *res_mem;
-+
-+} VC_SM_FREE_T;
-+
-+/* Request to lock a previously allocated memory (HOST->VC) */
-+typedef struct {
-+ /* Resource handle (returned from alloc) */
-+ uint32_t res_handle;
-+ /* Resource buffer (returned from alloc) */
-+ void *res_mem;
-+
-+} VC_SM_LOCK_UNLOCK_T;
-+
-+/* Request to resize a previously allocated memory (HOST->VC) */
-+typedef struct {
-+ /* Resource handle (returned from alloc) */
-+ uint32_t res_handle;
-+ /* Resource buffer (returned from alloc) */
-+ void *res_mem;
-+ /* Resource *new* size requested (bytes) */
-+ uint32_t res_new_size;
-+
-+} VC_SM_RESIZE_T;
-+
-+/* Result of a requested memory lock (VC->HOST) */
-+typedef struct {
-+ /* Transaction identifier */
-+ uint32_t trans_id;
-+
-+ /* Resource handle */
-+ uint32_t res_handle;
-+ /* Pointer to resource buffer */
-+ void *res_mem;
-+ /* Pointer to former resource buffer if the memory
-+ * was reallocated */
-+ void *res_old_mem;
-+
-+} VC_SM_LOCK_RESULT_T;
-+
-+/* Generic result for a request (VC->HOST) */
-+typedef struct {
-+ /* Transaction identifier */
-+ uint32_t trans_id;
-+
-+ int32_t success;
-+
-+} VC_SM_RESULT_T;
-+
-+/* Request to revert a previously applied action (HOST->VC) */
-+typedef struct {
-+ /* Action of interest */
-+ VC_SM_MSG_TYPE res_action;
-+ /* Transaction identifier for the action of interest */
-+ uint32_t action_trans_id;
-+
-+} VC_SM_ACTION_CLEAN_T;
-+
-+/* Request to remove all data associated with a given allocator (HOST->VC) */
-+typedef struct {
-+ /* Allocator identifier */
-+ uint32_t allocator;
-+
-+} VC_SM_FREE_ALL_T;
-+
-+/* Union of ALL messages */
-+typedef union {
-+ VC_SM_ALLOC_T alloc;
-+ VC_SM_ALLOC_RESULT_T alloc_result;
-+ VC_SM_FREE_T free;
-+ VC_SM_ACTION_CLEAN_T action_clean;
-+ VC_SM_RESIZE_T resize;
-+ VC_SM_LOCK_RESULT_T lock_result;
-+ VC_SM_RESULT_T result;
-+ VC_SM_FREE_ALL_T free_all;
-+
-+} VC_SM_MSG_UNION_T;
-+
-+#endif /* __VC_SM_DEFS_H__INCLUDED__ */
---- /dev/null
-+++ b/drivers/char/broadcom/vc_sm/vc_sm_knl.h
-@@ -0,0 +1,55 @@
-+/*****************************************************************************
-+* Copyright 2011 Broadcom Corporation. All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*****************************************************************************/
-+
-+#ifndef __VC_SM_KNL_H__INCLUDED__
-+#define __VC_SM_KNL_H__INCLUDED__
-+
-+#if !defined(__KERNEL__)
-+#error "This interface is for kernel use only..."
-+#endif
-+
-+/* Type of memory to be locked (ie mapped) */
-+typedef enum {
-+ VC_SM_LOCK_CACHED,
-+ VC_SM_LOCK_NON_CACHED,
-+
-+} VC_SM_LOCK_CACHE_MODE_T;
-+
-+/* Allocate a shared memory handle and block.
-+*/
-+int vc_sm_alloc(VC_SM_ALLOC_T *alloc, int *handle);
-+
-+/* Free a previously allocated shared memory handle and block.
-+*/
-+int vc_sm_free(int handle);
-+
-+/* Lock a memory handle for use by kernel.
-+*/
-+int vc_sm_lock(int handle, VC_SM_LOCK_CACHE_MODE_T mode,
-+ long unsigned int *data);
-+
-+/* Unlock a memory handle in use by kernel.
-+*/
-+int vc_sm_unlock(int handle, int flush, int no_vc_unlock);
-+
-+/* Get an internal resource handle mapped from the external one.
-+*/
-+int vc_sm_int_handle(int handle);
-+
-+/* Map a shared memory region for use by kernel.
-+*/
-+int vc_sm_map(int handle, unsigned int sm_addr, VC_SM_LOCK_CACHE_MODE_T mode,
-+ long unsigned int *data);
-+
-+#endif /* __VC_SM_KNL_H__INCLUDED__ */
---- /dev/null
-+++ b/drivers/char/broadcom/vc_sm/vc_vchi_sm.c
-@@ -0,0 +1,492 @@
-+/*****************************************************************************
-+* Copyright 2011-2012 Broadcom Corporation. All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*****************************************************************************/
-+
-+/* ---- Include Files ----------------------------------------------------- */
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/list.h>
-+#include <linux/semaphore.h>
-+#include <linux/mutex.h>
-+#include <linux/slab.h>
-+#include <linux/kthread.h>
-+
-+#include "vc_vchi_sm.h"
-+
-+#define VC_SM_VER 1
-+#define VC_SM_MIN_VER 0
-+
-+/* ---- Private Constants and Types -------------------------------------- */
-+
-+/* Command blocks come from a pool */
-+#define SM_MAX_NUM_CMD_RSP_BLKS 32
-+
-+struct sm_cmd_rsp_blk {
-+ struct list_head head; /* To create lists */
-+ struct semaphore sema; /* To be signaled when the response is there */
-+
-+ uint16_t id;
-+ uint16_t length;
-+
-+ uint8_t msg[VC_SM_MAX_MSG_LEN];
-+
-+ uint32_t wait:1;
-+ uint32_t sent:1;
-+ uint32_t alloc:1;
-+
-+};
-+
-+struct sm_instance {
-+ uint32_t num_connections;
-+ VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS];
-+ struct task_struct *io_thread;
-+ struct semaphore io_sema;
-+
-+ uint32_t trans_id;
-+
-+ struct mutex lock;
-+ struct list_head cmd_list;
-+ struct list_head rsp_list;
-+ struct list_head dead_list;
-+
-+ struct sm_cmd_rsp_blk free_blk[SM_MAX_NUM_CMD_RSP_BLKS];
-+ struct list_head free_list;
-+ struct mutex free_lock;
-+ struct semaphore free_sema;
-+
-+};
-+
-+/* ---- Private Variables ------------------------------------------------ */
-+
-+/* ---- Private Function Prototypes -------------------------------------- */
-+
-+/* ---- Private Functions ------------------------------------------------ */
-+static struct
-+sm_cmd_rsp_blk *vc_vchi_cmd_create(struct sm_instance *instance,
-+ VC_SM_MSG_TYPE id, void *msg,
-+ uint32_t size, int wait)
-+{
-+ struct sm_cmd_rsp_blk *blk;
-+ VC_SM_MSG_HDR_T *hdr;
-+
-+ if (down_interruptible(&instance->free_sema)) {
-+ blk = kmalloc(sizeof(*blk), GFP_KERNEL);
-+ if (!blk)
-+ return NULL;
-+
-+ blk->alloc = 1;
-+ sema_init(&blk->sema, 0);
-+ } else {
-+ mutex_lock(&instance->free_lock);
-+ blk =
-+ list_first_entry(&instance->free_list,
-+ struct sm_cmd_rsp_blk, head);
-+ list_del(&blk->head);
-+ mutex_unlock(&instance->free_lock);
-+ }
-+
-+ blk->sent = 0;
-+ blk->wait = wait;
-+ blk->length = sizeof(*hdr) + size;
-+
-+ hdr = (VC_SM_MSG_HDR_T *) blk->msg;
-+ hdr->type = id;
-+ mutex_lock(&instance->lock);
-+ hdr->trans_id = blk->id = ++instance->trans_id;
-+ mutex_unlock(&instance->lock);
-+
-+ if (size)
-+ memcpy(hdr->body, msg, size);
-+
-+ return blk;
-+}
-+
-+static void
-+vc_vchi_cmd_delete(struct sm_instance *instance, struct sm_cmd_rsp_blk *blk)
-+{
-+ if (blk->alloc) {
-+ kfree(blk);
-+ return;
-+ }
-+
-+ mutex_lock(&instance->free_lock);
-+ list_add(&blk->head, &instance->free_list);
-+ mutex_unlock(&instance->free_lock);
-+ up(&instance->free_sema);
-+}
-+
-+static int vc_vchi_sm_videocore_io(void *arg)
-+{
-+ struct sm_instance *instance = arg;
-+ struct sm_cmd_rsp_blk *cmd = NULL, *cmd_tmp;
-+ VC_SM_RESULT_T *reply;
-+ uint32_t reply_len;
-+ int32_t status;
-+ int svc_use = 1;
-+
-+ while (1) {
-+ if (svc_use)
-+ vchi_service_release(instance->vchi_handle[0]);
-+ svc_use = 0;
-+ if (!down_interruptible(&instance->io_sema)) {
-+ vchi_service_use(instance->vchi_handle[0]);
-+ svc_use = 1;
-+
-+ do {
-+ unsigned int flags;
-+ /*
-+ * Get new command and move it to response list
-+ */
-+ mutex_lock(&instance->lock);
-+ if (list_empty(&instance->cmd_list)) {
-+ /* no more commands to process */
-+ mutex_unlock(&instance->lock);
-+ break;
-+ }
-+ cmd =
-+ list_first_entry(&instance->cmd_list,
-+ struct sm_cmd_rsp_blk,
-+ head);
-+ list_move(&cmd->head, &instance->rsp_list);
-+ cmd->sent = 1;
-+ mutex_unlock(&instance->lock);
-+
-+ /* Send the command */
-+ flags = VCHI_FLAGS_BLOCK_UNTIL_QUEUED;
-+ status = vchi_msg_queue(
-+ instance->vchi_handle[0],
-+ cmd->msg, cmd->length,
-+ flags, NULL);
-+ if (status) {
-+ pr_err("%s: failed to queue message (%d)",
-+ __func__, status);
-+ }
-+
-+ /* If no reply is needed then we're done */
-+ if (!cmd->wait) {
-+ mutex_lock(&instance->lock);
-+ list_del(&cmd->head);
-+ mutex_unlock(&instance->lock);
-+ vc_vchi_cmd_delete(instance, cmd);
-+ continue;
-+ }
-+
-+ if (status) {
-+ up(&cmd->sema);
-+ continue;
-+ }
-+
-+ } while (1);
-+
-+ while (!vchi_msg_peek
-+ (instance->vchi_handle[0], (void **)&reply,
-+ &reply_len, VCHI_FLAGS_NONE)) {
-+ mutex_lock(&instance->lock);
-+ list_for_each_entry(cmd, &instance->rsp_list,
-+ head) {
-+ if (cmd->id == reply->trans_id)
-+ break;
-+ }
-+ mutex_unlock(&instance->lock);
-+
-+ if (&cmd->head == &instance->rsp_list) {
-+ pr_debug("%s: received response %u, throw away...",
-+ __func__, reply->trans_id);
-+ } else if (reply_len > sizeof(cmd->msg)) {
-+ pr_err("%s: reply too big (%u) %u, throw away...",
-+ __func__, reply_len,
-+ reply->trans_id);
-+ } else {
-+ memcpy(cmd->msg, reply, reply_len);
-+ up(&cmd->sema);
-+ }
-+
-+ vchi_msg_remove(instance->vchi_handle[0]);
-+ }
-+
-+ /* Go through the dead list and free them */
-+ mutex_lock(&instance->lock);
-+ list_for_each_entry_safe(cmd, cmd_tmp,
-+ &instance->dead_list, head) {
-+ list_del(&cmd->head);
-+ vc_vchi_cmd_delete(instance, cmd);
-+ }
-+ mutex_unlock(&instance->lock);
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static void vc_sm_vchi_callback(void *param,
-+ const VCHI_CALLBACK_REASON_T reason,
-+ void *msg_handle)
-+{
-+ struct sm_instance *instance = param;
-+
-+ (void)msg_handle;
-+
-+ switch (reason) {
-+ case VCHI_CALLBACK_MSG_AVAILABLE:
-+ up(&instance->io_sema);
-+ break;
-+
-+ case VCHI_CALLBACK_SERVICE_CLOSED:
-+ pr_info("%s: service CLOSED!!", __func__);
-+ default:
-+ break;
-+ }
-+}
-+
-+VC_VCHI_SM_HANDLE_T vc_vchi_sm_init(VCHI_INSTANCE_T vchi_instance,
-+ VCHI_CONNECTION_T **vchi_connections,
-+ uint32_t num_connections)
-+{
-+ uint32_t i;
-+ struct sm_instance *instance;
-+ int status;
-+
-+ pr_debug("%s: start", __func__);
-+
-+ if (num_connections > VCHI_MAX_NUM_CONNECTIONS) {
-+ pr_err("%s: unsupported number of connections %u (max=%u)",
-+ __func__, num_connections, VCHI_MAX_NUM_CONNECTIONS);
-+
-+ goto err_null;
-+ }
-+ /* Allocate memory for this instance */
-+ instance = kzalloc(sizeof(*instance), GFP_KERNEL);
-+
-+ /* Misc initialisations */
-+ mutex_init(&instance->lock);
-+ sema_init(&instance->io_sema, 0);
-+ INIT_LIST_HEAD(&instance->cmd_list);
-+ INIT_LIST_HEAD(&instance->rsp_list);
-+ INIT_LIST_HEAD(&instance->dead_list);
-+ INIT_LIST_HEAD(&instance->free_list);
-+ sema_init(&instance->free_sema, SM_MAX_NUM_CMD_RSP_BLKS);
-+ mutex_init(&instance->free_lock);
-+ for (i = 0; i < SM_MAX_NUM_CMD_RSP_BLKS; i++) {
-+ sema_init(&instance->free_blk[i].sema, 0);
-+ list_add(&instance->free_blk[i].head, &instance->free_list);
-+ }
-+
-+ /* Open the VCHI service connections */
-+ instance->num_connections = num_connections;
-+ for (i = 0; i < num_connections; i++) {
-+ SERVICE_CREATION_T params = {
-+ VCHI_VERSION_EX(VC_SM_VER, VC_SM_MIN_VER),
-+ VC_SM_SERVER_NAME,
-+ vchi_connections[i],
-+ 0,
-+ 0,
-+ vc_sm_vchi_callback,
-+ instance,
-+ 0,
-+ 0,
-+ 0,
-+ };
-+
-+ status = vchi_service_open(vchi_instance,
-+ &params, &instance->vchi_handle[i]);
-+ if (status) {
-+ pr_err("%s: failed to open VCHI service (%d)",
-+ __func__, status);
-+
-+ goto err_close_services;
-+ }
-+ }
-+
-+ /* Create the thread which takes care of all io to/from videoocore. */
-+ instance->io_thread = kthread_create(&vc_vchi_sm_videocore_io,
-+ (void *)instance, "SMIO");
-+ if (instance->io_thread == NULL) {
-+ pr_err("%s: failed to create SMIO thread", __func__);
-+
-+ goto err_close_services;
-+ }
-+ set_user_nice(instance->io_thread, -10);
-+ wake_up_process(instance->io_thread);
-+
-+ pr_debug("%s: success - instance 0x%x", __func__, (unsigned)instance);
-+ return instance;
-+
-+err_close_services:
-+ for (i = 0; i < instance->num_connections; i++) {
-+ if (instance->vchi_handle[i] != NULL)
-+ vchi_service_close(instance->vchi_handle[i]);
-+ }
-+ kfree(instance);
-+err_null:
-+ pr_debug("%s: FAILED", __func__);
-+ return NULL;
-+}
-+
-+int vc_vchi_sm_stop(VC_VCHI_SM_HANDLE_T *handle)
-+{
-+ struct sm_instance *instance;
-+ uint32_t i;
-+
-+ if (handle == NULL) {
-+ pr_err("%s: invalid pointer to handle %p", __func__, handle);
-+ goto lock;
-+ }
-+
-+ if (*handle == NULL) {
-+ pr_err("%s: invalid handle %p", __func__, *handle);
-+ goto lock;
-+ }
-+
-+ instance = *handle;
-+
-+ /* Close all VCHI service connections */
-+ for (i = 0; i < instance->num_connections; i++) {
-+ int32_t success;
-+ vchi_service_use(instance->vchi_handle[i]);
-+
-+ success = vchi_service_close(instance->vchi_handle[i]);
-+ }
-+
-+ kfree(instance);
-+
-+ *handle = NULL;
-+ return 0;
-+
-+lock:
-+ return -EINVAL;
-+}
-+
-+int vc_vchi_sm_send_msg(VC_VCHI_SM_HANDLE_T handle,
-+ VC_SM_MSG_TYPE msg_id,
-+ void *msg, uint32_t msg_size,
-+ void *result, uint32_t result_size,
-+ uint32_t *cur_trans_id, uint8_t wait_reply)
-+{
-+ int status = 0;
-+ struct sm_instance *instance = handle;
-+ struct sm_cmd_rsp_blk *cmd_blk;
-+
-+ if (handle == NULL) {
-+ pr_err("%s: invalid handle", __func__);
-+ return -EINVAL;
-+ }
-+ if (msg == NULL) {
-+ pr_err("%s: invalid msg pointer", __func__);
-+ return -EINVAL;
-+ }
-+
-+ cmd_blk =
-+ vc_vchi_cmd_create(instance, msg_id, msg, msg_size, wait_reply);
-+ if (cmd_blk == NULL) {
-+ pr_err("[%s]: failed to allocate global tracking resource",
-+ __func__);
-+ return -ENOMEM;
-+ }
-+
-+ if (cur_trans_id != NULL)
-+ *cur_trans_id = cmd_blk->id;
-+
-+ mutex_lock(&instance->lock);
-+ list_add_tail(&cmd_blk->head, &instance->cmd_list);
-+ mutex_unlock(&instance->lock);
-+ up(&instance->io_sema);
-+
-+ if (!wait_reply)
-+ /* We're done */
-+ return 0;
-+
-+ /* Wait for the response */
-+ if (down_interruptible(&cmd_blk->sema)) {
-+ mutex_lock(&instance->lock);
-+ if (!cmd_blk->sent) {
-+ list_del(&cmd_blk->head);
-+ mutex_unlock(&instance->lock);
-+ vc_vchi_cmd_delete(instance, cmd_blk);
-+ return -ENXIO;
-+ }
-+ mutex_unlock(&instance->lock);
-+
-+ mutex_lock(&instance->lock);
-+ list_move(&cmd_blk->head, &instance->dead_list);
-+ mutex_unlock(&instance->lock);
-+ up(&instance->io_sema);
-+ return -EINTR; /* We're done */
-+ }
-+
-+ if (result && result_size) {
-+ memcpy(result, cmd_blk->msg, result_size);
-+ } else {
-+ VC_SM_RESULT_T *res = (VC_SM_RESULT_T *) cmd_blk->msg;
-+ status = (res->success == 0) ? 0 : -ENXIO;
-+ }
-+
-+ mutex_lock(&instance->lock);
-+ list_del(&cmd_blk->head);
-+ mutex_unlock(&instance->lock);
-+ vc_vchi_cmd_delete(instance, cmd_blk);
-+ return status;
-+}
-+
-+int vc_vchi_sm_alloc(VC_VCHI_SM_HANDLE_T handle, VC_SM_ALLOC_T *msg,
-+ VC_SM_ALLOC_RESULT_T *result, uint32_t *cur_trans_id)
-+{
-+ return vc_vchi_sm_send_msg(handle, VC_SM_MSG_TYPE_ALLOC,
-+ msg, sizeof(*msg), result, sizeof(*result),
-+ cur_trans_id, 1);
-+}
-+
-+int vc_vchi_sm_free(VC_VCHI_SM_HANDLE_T handle,
-+ VC_SM_FREE_T *msg, uint32_t *cur_trans_id)
-+{
-+ return vc_vchi_sm_send_msg(handle, VC_SM_MSG_TYPE_FREE,
-+ msg, sizeof(*msg), 0, 0, cur_trans_id, 0);
-+}
-+
-+int vc_vchi_sm_lock(VC_VCHI_SM_HANDLE_T handle,
-+ VC_SM_LOCK_UNLOCK_T *msg,
-+ VC_SM_LOCK_RESULT_T *result, uint32_t *cur_trans_id)
-+{
-+ return vc_vchi_sm_send_msg(handle, VC_SM_MSG_TYPE_LOCK,
-+ msg, sizeof(*msg), result, sizeof(*result),
-+ cur_trans_id, 1);
-+}
-+
-+int vc_vchi_sm_unlock(VC_VCHI_SM_HANDLE_T handle,
-+ VC_SM_LOCK_UNLOCK_T *msg,
-+ uint32_t *cur_trans_id, uint8_t wait_reply)
-+{
-+ return vc_vchi_sm_send_msg(handle, wait_reply ?
-+ VC_SM_MSG_TYPE_UNLOCK :
-+ VC_SM_MSG_TYPE_UNLOCK_NOANS, msg,
-+ sizeof(*msg), 0, 0, cur_trans_id,
-+ wait_reply);
-+}
-+
-+int vc_vchi_sm_resize(VC_VCHI_SM_HANDLE_T handle, VC_SM_RESIZE_T *msg,
-+ uint32_t *cur_trans_id)
-+{
-+ return vc_vchi_sm_send_msg(handle, VC_SM_MSG_TYPE_RESIZE,
-+ msg, sizeof(*msg), 0, 0, cur_trans_id, 1);
-+}
-+
-+int vc_vchi_sm_walk_alloc(VC_VCHI_SM_HANDLE_T handle)
-+{
-+ return vc_vchi_sm_send_msg(handle, VC_SM_MSG_TYPE_WALK_ALLOC,
-+ 0, 0, 0, 0, 0, 0);
-+}
-+
-+int vc_vchi_sm_clean_up(VC_VCHI_SM_HANDLE_T handle, VC_SM_ACTION_CLEAN_T *msg)
-+{
-+ return vc_vchi_sm_send_msg(handle, VC_SM_MSG_TYPE_ACTION_CLEAN,
-+ msg, sizeof(*msg), 0, 0, 0, 0);
-+}
---- /dev/null
-+++ b/drivers/char/broadcom/vc_sm/vc_vchi_sm.h
-@@ -0,0 +1,82 @@
-+/*****************************************************************************
-+* Copyright 2011 Broadcom Corporation. All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*****************************************************************************/
-+
-+#ifndef __VC_VCHI_SM_H__INCLUDED__
-+#define __VC_VCHI_SM_H__INCLUDED__
-+
-+#include "interface/vchi/vchi.h"
-+
-+#include "vc_sm_defs.h"
-+
-+/* Forward declare.
-+*/
-+typedef struct sm_instance *VC_VCHI_SM_HANDLE_T;
-+
-+/* Initialize the shared memory service, opens up vchi connection to talk to it.
-+*/
-+VC_VCHI_SM_HANDLE_T vc_vchi_sm_init(VCHI_INSTANCE_T vchi_instance,
-+ VCHI_CONNECTION_T **vchi_connections,
-+ uint32_t num_connections);
-+
-+/* Terminates the shared memory service.
-+*/
-+int vc_vchi_sm_stop(VC_VCHI_SM_HANDLE_T *handle);
-+
-+/* Ask the shared memory service to allocate some memory on videocre and
-+** return the result of this allocation (which upon success will be a pointer
-+** to some memory in videocore space).
-+*/
-+int vc_vchi_sm_alloc(VC_VCHI_SM_HANDLE_T handle,
-+ VC_SM_ALLOC_T *alloc,
-+ VC_SM_ALLOC_RESULT_T *alloc_result, uint32_t *trans_id);
-+
-+/* Ask the shared memory service to free up some memory that was previously
-+** allocated by the vc_vchi_sm_alloc function call.
-+*/
-+int vc_vchi_sm_free(VC_VCHI_SM_HANDLE_T handle,
-+ VC_SM_FREE_T *free, uint32_t *trans_id);
-+
-+/* Ask the shared memory service to lock up some memory that was previously
-+** allocated by the vc_vchi_sm_alloc function call.
-+*/
-+int vc_vchi_sm_lock(VC_VCHI_SM_HANDLE_T handle,
-+ VC_SM_LOCK_UNLOCK_T *lock_unlock,
-+ VC_SM_LOCK_RESULT_T *lock_result, uint32_t *trans_id);
-+
-+/* Ask the shared memory service to unlock some memory that was previously
-+** allocated by the vc_vchi_sm_alloc function call.
-+*/
-+int vc_vchi_sm_unlock(VC_VCHI_SM_HANDLE_T handle,
-+ VC_SM_LOCK_UNLOCK_T *lock_unlock,
-+ uint32_t *trans_id, uint8_t wait_reply);
-+
-+/* Ask the shared memory service to resize some memory that was previously
-+** allocated by the vc_vchi_sm_alloc function call.
-+*/
-+int vc_vchi_sm_resize(VC_VCHI_SM_HANDLE_T handle,
-+ VC_SM_RESIZE_T *resize, uint32_t *trans_id);
-+
-+/* Walk the allocated resources on the videocore side, the allocation will
-+** show up in the log. This is purely for debug/information and takes no
-+** specific actions.
-+*/
-+int vc_vchi_sm_walk_alloc(VC_VCHI_SM_HANDLE_T handle);
-+
-+/* Clean up following a previously interrupted action which left the system
-+** in a bad state of some sort.
-+*/
-+int vc_vchi_sm_clean_up(VC_VCHI_SM_HANDLE_T handle,
-+ VC_SM_ACTION_CLEAN_T *action_clean);
-+
-+#endif /* __VC_VCHI_SM_H__INCLUDED__ */
---- /dev/null
-+++ b/drivers/char/broadcom/vc_sm/vmcs_sm.c
-@@ -0,0 +1,3211 @@
-+/*****************************************************************************
-+* Copyright 2011-2012 Broadcom Corporation. All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*****************************************************************************/
-+
-+/* ---- Include Files ----------------------------------------------------- */
-+
-+#include <linux/cdev.h>
-+#include <linux/broadcom/vc_mem.h>
-+#include <linux/device.h>
-+#include <linux/debugfs.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/errno.h>
-+#include <linux/fs.h>
-+#include <linux/hugetlb.h>
-+#include <linux/ioctl.h>
-+#include <linux/kernel.h>
-+#include <linux/list.h>
-+#include <linux/module.h>
-+#include <linux/mm.h>
-+#include <linux/pfn.h>
-+#include <linux/proc_fs.h>
-+#include <linux/pagemap.h>
-+#include <linux/semaphore.h>
-+#include <linux/slab.h>
-+#include <linux/seq_file.h>
-+#include <linux/types.h>
-+#include <asm/cacheflush.h>
-+
-+#include "vchiq_connected.h"
-+#include "vc_vchi_sm.h"
-+
-+#include <linux/broadcom/vmcs_sm_ioctl.h>
-+#include "vc_sm_knl.h"
-+
-+/* ---- Private Constants and Types --------------------------------------- */
-+
-+#define DEVICE_NAME "vcsm"
-+#define DEVICE_MINOR 0
-+
-+#define VC_SM_DIR_ROOT_NAME "vc-smem"
-+#define VC_SM_DIR_ALLOC_NAME "alloc"
-+#define VC_SM_STATE "state"
-+#define VC_SM_STATS "statistics"
-+#define VC_SM_RESOURCES "resources"
-+#define VC_SM_DEBUG "debug"
-+#define VC_SM_WRITE_BUF_SIZE 128
-+
-+/* Statistics tracked per resource and globally.
-+*/
-+enum SM_STATS_T {
-+ /* Attempt. */
-+ ALLOC,
-+ FREE,
-+ LOCK,
-+ UNLOCK,
-+ MAP,
-+ FLUSH,
-+ INVALID,
-+
-+ END_ATTEMPT,
-+
-+ /* Failure. */
-+ ALLOC_FAIL,
-+ FREE_FAIL,
-+ LOCK_FAIL,
-+ UNLOCK_FAIL,
-+ MAP_FAIL,
-+ FLUSH_FAIL,
-+ INVALID_FAIL,
-+
-+ END_ALL,
-+
-+};
-+
-+static const char *const sm_stats_human_read[] = {
-+ "Alloc",
-+ "Free",
-+ "Lock",
-+ "Unlock",
-+ "Map",
-+ "Cache Flush",
-+ "Cache Invalidate",
-+};
-+
-+typedef int (*VC_SM_SHOW) (struct seq_file *s, void *v);
-+struct SM_PDE_T {
-+ VC_SM_SHOW show; /* Debug fs function hookup. */
-+ struct dentry *dir_entry; /* Debug fs directory entry. */
-+ void *priv_data; /* Private data */
-+
-+};
-+
-+/* Single resource allocation tracked for all devices.
-+*/
-+struct sm_mmap {
-+ struct list_head map_list; /* Linked list of maps. */
-+
-+ struct SM_RESOURCE_T *resource; /* Pointer to the resource. */
-+
-+ pid_t res_pid; /* PID owning that resource. */
-+ unsigned int res_vc_hdl; /* Resource handle (videocore). */
-+ unsigned int res_usr_hdl; /* Resource handle (user). */
-+
-+ long unsigned int res_addr; /* Mapped virtual address. */
-+ struct vm_area_struct *vma; /* VM area for this mapping. */
-+ unsigned int ref_count; /* Reference count to this vma. */
-+
-+ /* Used to link maps associated with a resource. */
-+ struct list_head resource_map_list;
-+};
-+
-+/* Single resource allocation tracked for each opened device.
-+*/
-+struct SM_RESOURCE_T {
-+ struct list_head resource_list; /* List of resources. */
-+ struct list_head global_resource_list; /* Global list of resources. */
-+
-+ pid_t pid; /* PID owning that resource. */
-+ uint32_t res_guid; /* Unique identifier. */
-+ uint32_t lock_count; /* Lock count for this resource. */
-+ uint32_t ref_count; /* Ref count for this resource. */
-+
-+ uint32_t res_handle; /* Resource allocation handle. */
-+ void *res_base_mem; /* Resource base memory address. */
-+ uint32_t res_size; /* Resource size allocated. */
-+ enum vmcs_sm_cache_e res_cached; /* Resource cache type. */
-+ struct SM_RESOURCE_T *res_shared; /* Shared resource */
-+
-+ enum SM_STATS_T res_stats[END_ALL]; /* Resource statistics. */
-+
-+ uint8_t map_count; /* Counter of mappings for this resource. */
-+ struct list_head map_list; /* Maps associated with a resource. */
-+
-+ struct SM_PRIV_DATA_T *private;
-+};
-+
-+/* Private file data associated with each opened device.
-+*/
-+struct SM_PRIV_DATA_T {
-+ struct list_head resource_list; /* List of resources. */
-+
-+ pid_t pid; /* PID of creator. */
-+
-+ struct dentry *dir_pid; /* Debug fs entries root. */
-+ struct SM_PDE_T dir_stats; /* Debug fs entries statistics sub-tree. */
-+ struct SM_PDE_T dir_res; /* Debug fs resource sub-tree. */
-+
-+ int restart_sys; /* Tracks restart on interrupt. */
-+ VC_SM_MSG_TYPE int_action; /* Interrupted action. */
-+ uint32_t int_trans_id; /* Interrupted transaction. */
-+
-+};
-+
-+/* Global state information.
-+*/
-+struct SM_STATE_T {
-+ VC_VCHI_SM_HANDLE_T sm_handle; /* Handle for videocore service. */
-+ struct dentry *dir_root; /* Debug fs entries root. */
-+ struct dentry *dir_alloc; /* Debug fs entries allocations. */
-+ struct SM_PDE_T dir_stats; /* Debug fs entries statistics sub-tree. */
-+ struct SM_PDE_T dir_state; /* Debug fs entries state sub-tree. */
-+ struct dentry *debug; /* Debug fs entries debug. */
-+
-+ struct mutex map_lock; /* Global map lock. */
-+ struct list_head map_list; /* List of maps. */
-+ struct list_head resource_list; /* List of resources. */
-+
-+ enum SM_STATS_T deceased[END_ALL]; /* Natural termination stats. */
-+ enum SM_STATS_T terminated[END_ALL]; /* Forced termination stats. */
-+ uint32_t res_deceased_cnt; /* Natural termination counter. */
-+ uint32_t res_terminated_cnt; /* Forced termination counter. */
-+
-+ struct cdev sm_cdev; /* Device. */
-+ dev_t sm_devid; /* Device identifier. */
-+ struct class *sm_class; /* Class. */
-+ struct device *sm_dev; /* Device. */
-+
-+ struct SM_PRIV_DATA_T *data_knl; /* Kernel internal data tracking. */
-+
-+ struct mutex lock; /* Global lock. */
-+ uint32_t guid; /* GUID (next) tracker. */
-+
-+};
-+
-+/* ---- Private Variables ----------------------------------------------- */
-+
-+static struct SM_STATE_T *sm_state;
-+static int sm_inited;
-+
-+static const char *const sm_cache_map_vector[] = {
-+ "(null)",
-+ "host",
-+ "videocore",
-+ "host+videocore",
-+};
-+
-+/* ---- Private Function Prototypes -------------------------------------- */
-+
-+/* ---- Private Functions ------------------------------------------------ */
-+
-+static inline unsigned vcaddr_to_pfn(unsigned long vc_addr)
-+{
-+ unsigned long pfn = vc_addr & 0x3FFFFFFF;
-+ pfn += mm_vc_mem_phys_addr;
-+ pfn >>= PAGE_SHIFT;
-+ return pfn;
-+}
-+
-+/* Carries over to the state statistics the statistics once owned by a deceased
-+** resource.
-+*/
-+static void vc_sm_resource_deceased(struct SM_RESOURCE_T *p_res, int terminated)
-+{
-+ if (sm_state != NULL) {
-+ if (p_res != NULL) {
-+ int ix;
-+
-+ if (terminated)
-+ sm_state->res_terminated_cnt++;
-+ else
-+ sm_state->res_deceased_cnt++;
-+
-+ for (ix = 0; ix < END_ALL; ix++) {
-+ if (terminated)
-+ sm_state->terminated[ix] +=
-+ p_res->res_stats[ix];
-+ else
-+ sm_state->deceased[ix] +=
-+ p_res->res_stats[ix];
-+ }
-+ }
-+ }
-+}
-+
-+/* Fetch a videocore handle corresponding to a mapping of the pid+address
-+** returns 0 (ie NULL) if no such handle exists in the global map.
-+*/
-+static unsigned int vmcs_sm_vc_handle_from_pid_and_address(unsigned int pid,
-+ unsigned int addr)
-+{
-+ struct sm_mmap *map = NULL;
-+ unsigned int handle = 0;
-+
-+ if (!sm_state || addr == 0)
-+ goto out;
-+
-+ mutex_lock(&(sm_state->map_lock));
-+
-+ /* Lookup the resource.
-+ */
-+ if (!list_empty(&sm_state->map_list)) {
-+ list_for_each_entry(map, &sm_state->map_list, map_list) {
-+ if (map->res_pid != pid || map->res_addr != addr)
-+ continue;
-+
-+ pr_debug("[%s]: global map %p (pid %u, addr %lx) -> vc-hdl %x (usr-hdl %x)\n",
-+ __func__, map, map->res_pid, map->res_addr,
-+ map->res_vc_hdl, map->res_usr_hdl);
-+
-+ handle = map->res_vc_hdl;
-+ break;
-+ }
-+ }
-+
-+ mutex_unlock(&(sm_state->map_lock));
-+
-+out:
-+ /* Use a debug log here as it may be a valid situation that we query
-+ ** for something that is not mapped, we do not want a kernel log each
-+ ** time around.
-+ **
-+ ** There are other error log that would pop up accordingly if someone
-+ ** subsequently tries to use something invalid after being told not to
-+ ** use it...
-+ */
-+ if (handle == 0) {
-+ pr_debug("[%s]: not a valid map (pid %u, addr %x)\n",
-+ __func__, pid, addr);
-+ }
-+
-+ return handle;
-+}
-+
-+/* Fetch a user handle corresponding to a mapping of the pid+address
-+** returns 0 (ie NULL) if no such handle exists in the global map.
-+*/
-+static unsigned int vmcs_sm_usr_handle_from_pid_and_address(unsigned int pid,
-+ unsigned int addr)
-+{
-+ struct sm_mmap *map = NULL;
-+ unsigned int handle = 0;
-+
-+ if (!sm_state || addr == 0)
-+ goto out;
-+
-+ mutex_lock(&(sm_state->map_lock));
-+
-+ /* Lookup the resource.
-+ */
-+ if (!list_empty(&sm_state->map_list)) {
-+ list_for_each_entry(map, &sm_state->map_list, map_list) {
-+ if (map->res_pid != pid || map->res_addr != addr)
-+ continue;
-+
-+ pr_debug("[%s]: global map %p (pid %u, addr %lx) -> usr-hdl %x (vc-hdl %x)\n",
-+ __func__, map, map->res_pid, map->res_addr,
-+ map->res_usr_hdl, map->res_vc_hdl);
-+
-+ handle = map->res_usr_hdl;
-+ break;
-+ }
-+ }
-+
-+ mutex_unlock(&(sm_state->map_lock));
-+
-+out:
-+ /* Use a debug log here as it may be a valid situation that we query
-+ * for something that is not mapped yet.
-+ *
-+ * There are other error log that would pop up accordingly if someone
-+ * subsequently tries to use something invalid after being told not to
-+ * use it...
-+ */
-+ if (handle == 0)
-+ pr_debug("[%s]: not a valid map (pid %u, addr %x)\n",
-+ __func__, pid, addr);
-+
-+ return handle;
-+}
-+
-+#if defined(DO_NOT_USE)
-+/* Fetch an address corresponding to a mapping of the pid+handle
-+** returns 0 (ie NULL) if no such address exists in the global map.
-+*/
-+static unsigned int vmcs_sm_usr_address_from_pid_and_vc_handle(unsigned int pid,
-+ unsigned int hdl)
-+{
-+ struct sm_mmap *map = NULL;
-+ unsigned int addr = 0;
-+
-+ if (sm_state == NULL || hdl == 0)
-+ goto out;
-+
-+ mutex_lock(&(sm_state->map_lock));
-+
-+ /* Lookup the resource.
-+ */
-+ if (!list_empty(&sm_state->map_list)) {
-+ list_for_each_entry(map, &sm_state->map_list, map_list) {
-+ if (map->res_pid != pid || map->res_vc_hdl != hdl)
-+ continue;
-+
-+ pr_debug("[%s]: global map %p (pid %u, vc-hdl %x, usr-hdl %x) -> addr %lx\n",
-+ __func__, map, map->res_pid, map->res_vc_hdl,
-+ map->res_usr_hdl, map->res_addr);
-+
-+ addr = map->res_addr;
-+ break;
-+ }
-+ }
-+
-+ mutex_unlock(&(sm_state->map_lock));
-+
-+out:
-+ /* Use a debug log here as it may be a valid situation that we query
-+ ** for something that is not mapped, we do not want a kernel log each
-+ ** time around.
-+ **
-+ ** There are other error log that would pop up accordingly if someone
-+ ** subsequently tries to use something invalid after being told not to
-+ ** use it...
-+ */
-+ if (addr == 0)
-+ pr_debug("[%s]: not a valid map (pid %u, hdl %x)\n",
-+ __func__, pid, hdl);
-+
-+ return addr;
-+}
-+#endif
-+
-+/* Fetch an address corresponding to a mapping of the pid+handle
-+** returns 0 (ie NULL) if no such address exists in the global map.
-+*/
-+static unsigned int vmcs_sm_usr_address_from_pid_and_usr_handle(unsigned int
-+ pid,
-+ unsigned int
-+ hdl)
-+{
-+ struct sm_mmap *map = NULL;
-+ unsigned int addr = 0;
-+
-+ if (sm_state == NULL || hdl == 0)
-+ goto out;
-+
-+ mutex_lock(&(sm_state->map_lock));
-+
-+ /* Lookup the resource.
-+ */
-+ if (!list_empty(&sm_state->map_list)) {
-+ list_for_each_entry(map, &sm_state->map_list, map_list) {
-+ if (map->res_pid != pid || map->res_usr_hdl != hdl)
-+ continue;
-+
-+ pr_debug("[%s]: global map %p (pid %u, vc-hdl %x, usr-hdl %x) -> addr %lx\n",
-+ __func__, map, map->res_pid, map->res_vc_hdl,
-+ map->res_usr_hdl, map->res_addr);
-+
-+ addr = map->res_addr;
-+ break;
-+ }
-+ }
-+
-+ mutex_unlock(&(sm_state->map_lock));
-+
-+out:
-+ /* Use a debug log here as it may be a valid situation that we query
-+ * for something that is not mapped, we do not want a kernel log each
-+ * time around.
-+ *
-+ * There are other error log that would pop up accordingly if someone
-+ * subsequently tries to use something invalid after being told not to
-+ * use it...
-+ */
-+ if (addr == 0)
-+ pr_debug("[%s]: not a valid map (pid %u, hdl %x)\n", __func__,
-+ pid, hdl);
-+
-+ return addr;
-+}
-+
-+/* Adds a resource mapping to the global data list.
-+*/
-+static void vmcs_sm_add_map(struct SM_STATE_T *state,
-+ struct SM_RESOURCE_T *resource, struct sm_mmap *map)
-+{
-+ mutex_lock(&(state->map_lock));
-+
-+ /* Add to the global list of mappings
-+ */
-+ list_add(&map->map_list, &state->map_list);
-+
-+ /* Add to the list of mappings for this resource
-+ */
-+ list_add(&map->resource_map_list, &resource->map_list);
-+ resource->map_count++;
-+
-+ mutex_unlock(&(state->map_lock));
-+
-+ pr_debug("[%s]: added map %p (pid %u, vc-hdl %x, usr-hdl %x, addr %lx)\n",
-+ __func__, map, map->res_pid, map->res_vc_hdl,
-+ map->res_usr_hdl, map->res_addr);
-+}
-+
-+/* Removes a resource mapping from the global data list.
-+*/
-+static void vmcs_sm_remove_map(struct SM_STATE_T *state,
-+ struct SM_RESOURCE_T *resource,
-+ struct sm_mmap *map)
-+{
-+ mutex_lock(&(state->map_lock));
-+
-+ /* Remove from the global list of mappings
-+ */
-+ list_del(&map->map_list);
-+
-+ /* Remove from the list of mapping for this resource
-+ */
-+ list_del(&map->resource_map_list);
-+ if (resource->map_count > 0)
-+ resource->map_count--;
-+
-+ mutex_unlock(&(state->map_lock));
-+
-+ pr_debug("[%s]: removed map %p (pid %d, vc-hdl %x, usr-hdl %x, addr %lx)\n",
-+ __func__, map, map->res_pid, map->res_vc_hdl, map->res_usr_hdl,
-+ map->res_addr);
-+
-+ kfree(map);
-+}
-+
-+/* Read callback for the global state proc entry.
-+*/
-+static int vc_sm_global_state_show(struct seq_file *s, void *v)
-+{
-+ struct sm_mmap *map = NULL;
-+ int map_count = 0;
-+
-+ if (sm_state == NULL)
-+ return 0;
-+
-+ seq_printf(s, "\nVC-ServiceHandle 0x%x\n",
-+ (unsigned int)sm_state->sm_handle);
-+
-+ /* Log all applicable mapping(s).
-+ */
-+
-+ mutex_lock(&(sm_state->map_lock));
-+
-+ if (!list_empty(&sm_state->map_list)) {
-+ list_for_each_entry(map, &sm_state->map_list, map_list) {
-+ map_count++;
-+
-+ seq_printf(s, "\nMapping 0x%x\n",
-+ (unsigned int)map);
-+ seq_printf(s, " TGID %u\n",
-+ map->res_pid);
-+ seq_printf(s, " VC-HDL 0x%x\n",
-+ map->res_vc_hdl);
-+ seq_printf(s, " USR-HDL 0x%x\n",
-+ map->res_usr_hdl);
-+ seq_printf(s, " USR-ADDR 0x%lx\n",
-+ map->res_addr);
-+ }
-+ }
-+
-+ mutex_unlock(&(sm_state->map_lock));
-+ seq_printf(s, "\n\nTotal map count: %d\n\n", map_count);
-+
-+ return 0;
-+}
-+
-+static int vc_sm_global_statistics_show(struct seq_file *s, void *v)
-+{
-+ int ix;
-+
-+ /* Global state tracked statistics.
-+ */
-+ if (sm_state != NULL) {
-+ seq_puts(s, "\nDeceased Resources Statistics\n");
-+
-+ seq_printf(s, "\nNatural Cause (%u occurences)\n",
-+ sm_state->res_deceased_cnt);
-+ for (ix = 0; ix < END_ATTEMPT; ix++) {
-+ if (sm_state->deceased[ix] > 0) {
-+ seq_printf(s, " %u\t%s\n",
-+ sm_state->deceased[ix],
-+ sm_stats_human_read[ix]);
-+ }
-+ }
-+ seq_puts(s, "\n");
-+ for (ix = 0; ix < END_ATTEMPT; ix++) {
-+ if (sm_state->deceased[ix + END_ATTEMPT] > 0) {
-+ seq_printf(s, " %u\tFAILED %s\n",
-+ sm_state->deceased[ix + END_ATTEMPT],
-+ sm_stats_human_read[ix]);
-+ }
-+ }
-+
-+ seq_printf(s, "\nForcefull (%u occurences)\n",
-+ sm_state->res_terminated_cnt);
-+ for (ix = 0; ix < END_ATTEMPT; ix++) {
-+ if (sm_state->terminated[ix] > 0) {
-+ seq_printf(s, " %u\t%s\n",
-+ sm_state->terminated[ix],
-+ sm_stats_human_read[ix]);
-+ }
-+ }
-+ seq_puts(s, "\n");
-+ for (ix = 0; ix < END_ATTEMPT; ix++) {
-+ if (sm_state->terminated[ix + END_ATTEMPT] > 0) {
-+ seq_printf(s, " %u\tFAILED %s\n",
-+ sm_state->terminated[ix +
-+ END_ATTEMPT],
-+ sm_stats_human_read[ix]);
-+ }
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+#if 0
-+/* Read callback for the statistics proc entry.
-+*/
-+static int vc_sm_statistics_show(struct seq_file *s, void *v)
-+{
-+ int ix;
-+ struct SM_PRIV_DATA_T *file_data;
-+ struct SM_RESOURCE_T *resource;
-+ int res_count = 0;
-+ struct SM_PDE_T *p_pde;
-+
-+ p_pde = (struct SM_PDE_T *)(s->private);
-+ file_data = (struct SM_PRIV_DATA_T *)(p_pde->priv_data);
-+
-+ if (file_data == NULL)
-+ return 0;
-+
-+ /* Per process statistics.
-+ */
-+
-+ seq_printf(s, "\nStatistics for TGID %d\n", file_data->pid);
-+
-+ mutex_lock(&(sm_state->map_lock));
-+
-+ if (!list_empty(&file_data->resource_list)) {
-+ list_for_each_entry(resource, &file_data->resource_list,
-+ resource_list) {
-+ res_count++;
-+
-+ seq_printf(s, "\nGUID: 0x%x\n\n",
-+ resource->res_guid);
-+ for (ix = 0; ix < END_ATTEMPT; ix++) {
-+ if (resource->res_stats[ix] > 0) {
-+ seq_printf(s,
-+ " %u\t%s\n",
-+ resource->res_stats[ix],
-+ sm_stats_human_read[ix]);
-+ }
-+ }
-+ seq_puts(s, "\n");
-+ for (ix = 0; ix < END_ATTEMPT; ix++) {
-+ if (resource->res_stats[ix + END_ATTEMPT] > 0) {
-+ seq_printf(s,
-+ " %u\tFAILED %s\n",
-+ resource->res_stats[
-+ ix + END_ATTEMPT],
-+ sm_stats_human_read[ix]);
-+ }
-+ }
-+ }
-+ }
-+
-+ mutex_unlock(&(sm_state->map_lock));
-+
-+ seq_printf(s, "\nResources Count %d\n", res_count);
-+
-+ return 0;
-+}
-+#endif
-+
-+#if 0
-+/* Read callback for the allocation proc entry. */
-+static int vc_sm_alloc_show(struct seq_file *s, void *v)
-+{
-+ struct SM_PRIV_DATA_T *file_data;
-+ struct SM_RESOURCE_T *resource;
-+ int alloc_count = 0;
-+ struct SM_PDE_T *p_pde;
-+
-+ p_pde = (struct SM_PDE_T *)(s->private);
-+ file_data = (struct SM_PRIV_DATA_T *)(p_pde->priv_data);
-+
-+ if (!file_data)
-+ return 0;
-+
-+ /* Per process statistics. */
-+ seq_printf(s, "\nAllocation for TGID %d\n", file_data->pid);
-+
-+ mutex_lock(&(sm_state->map_lock));
-+
-+ if (!list_empty(&file_data->resource_list)) {
-+ list_for_each_entry(resource, &file_data->resource_list,
-+ resource_list) {
-+ alloc_count++;
-+
-+ seq_printf(s, "\nGUID: 0x%x\n",
-+ resource->res_guid);
-+ seq_printf(s, "Lock Count: %u\n",
-+ resource->lock_count);
-+ seq_printf(s, "Mapped: %s\n",
-+ (resource->map_count ? "yes" : "no"));
-+ seq_printf(s, "VC-handle: 0x%x\n",
-+ resource->res_handle);
-+ seq_printf(s, "VC-address: 0x%p\n",
-+ resource->res_base_mem);
-+ seq_printf(s, "VC-size (bytes): %u\n",
-+ resource->res_size);
-+ seq_printf(s, "Cache: %s\n",
-+ sm_cache_map_vector[resource->res_cached]);
-+ }
-+ }
-+
-+ mutex_unlock(&(sm_state->map_lock));
-+
-+ seq_printf(s, "\n\nTotal allocation count: %d\n\n", alloc_count);
-+
-+ return 0;
-+}
-+#endif
-+
-+static int vc_sm_seq_file_show(struct seq_file *s, void *v)
-+{
-+ struct SM_PDE_T *sm_pde;
-+
-+ sm_pde = (struct SM_PDE_T *)(s->private);
-+
-+ if (sm_pde && sm_pde->show)
-+ sm_pde->show(s, v);
-+
-+ return 0;
-+}
-+
-+static int vc_sm_single_open(struct inode *inode, struct file *file)
-+{
-+ return single_open(file, vc_sm_seq_file_show, inode->i_private);
-+}
-+
-+static const struct file_operations vc_sm_debug_fs_fops = {
-+ .open = vc_sm_single_open,
-+ .read = seq_read,
-+ .llseek = seq_lseek,
-+ .release = single_release,
-+};
-+
-+/* Adds a resource to the private data list which tracks all the allocated
-+** data.
-+*/
-+static void vmcs_sm_add_resource(struct SM_PRIV_DATA_T *privdata,
-+ struct SM_RESOURCE_T *resource)
-+{
-+ mutex_lock(&(sm_state->map_lock));
-+ list_add(&resource->resource_list, &privdata->resource_list);
-+ list_add(&resource->global_resource_list, &sm_state->resource_list);
-+ mutex_unlock(&(sm_state->map_lock));
-+
-+ pr_debug("[%s]: added resource %p (base addr %p, hdl %x, size %u, cache %u)\n",
-+ __func__, resource, resource->res_base_mem,
-+ resource->res_handle, resource->res_size, resource->res_cached);
-+}
-+
-+/* Locates a resource and acquire a reference on it.
-+** The resource won't be deleted while there is a reference on it.
-+*/
-+static struct SM_RESOURCE_T *vmcs_sm_acquire_resource(struct SM_PRIV_DATA_T
-+ *private,
-+ unsigned int res_guid)
-+{
-+ struct SM_RESOURCE_T *resource, *ret = NULL;
-+
-+ mutex_lock(&(sm_state->map_lock));
-+
-+ list_for_each_entry(resource, &private->resource_list, resource_list) {
-+ if (resource->res_guid != res_guid)
-+ continue;
-+
-+ pr_debug("[%s]: located resource %p (guid: %x, base addr %p, hdl %x, size %u, cache %u)\n",
-+ __func__, resource, resource->res_guid,
-+ resource->res_base_mem, resource->res_handle,
-+ resource->res_size, resource->res_cached);
-+ resource->ref_count++;
-+ ret = resource;
-+ break;
-+ }
-+
-+ mutex_unlock(&(sm_state->map_lock));
-+
-+ return ret;
-+}
-+
-+/* Locates a resource and acquire a reference on it.
-+** The resource won't be deleted while there is a reference on it.
-+*/
-+static struct SM_RESOURCE_T *vmcs_sm_acquire_first_resource(
-+ struct SM_PRIV_DATA_T *private)
-+{
-+ struct SM_RESOURCE_T *resource, *ret = NULL;
-+
-+ mutex_lock(&(sm_state->map_lock));
-+
-+ list_for_each_entry(resource, &private->resource_list, resource_list) {
-+ pr_debug("[%s]: located resource %p (guid: %x, base addr %p, hdl %x, size %u, cache %u)\n",
-+ __func__, resource, resource->res_guid,
-+ resource->res_base_mem, resource->res_handle,
-+ resource->res_size, resource->res_cached);
-+ resource->ref_count++;
-+ ret = resource;
-+ break;
-+ }
-+
-+ mutex_unlock(&(sm_state->map_lock));
-+
-+ return ret;
-+}
-+
-+/* Locates a resource and acquire a reference on it.
-+** The resource won't be deleted while there is a reference on it.
-+*/
-+static struct SM_RESOURCE_T *vmcs_sm_acquire_global_resource(unsigned int
-+ res_guid)
-+{
-+ struct SM_RESOURCE_T *resource, *ret = NULL;
-+
-+ mutex_lock(&(sm_state->map_lock));
-+
-+ list_for_each_entry(resource, &sm_state->resource_list,
-+ global_resource_list) {
-+ if (resource->res_guid != res_guid)
-+ continue;
-+
-+ pr_debug("[%s]: located resource %p (guid: %x, base addr %p, hdl %x, size %u, cache %u)\n",
-+ __func__, resource, resource->res_guid,
-+ resource->res_base_mem, resource->res_handle,
-+ resource->res_size, resource->res_cached);
-+ resource->ref_count++;
-+ ret = resource;
-+ break;
-+ }
-+
-+ mutex_unlock(&(sm_state->map_lock));
-+
-+ return ret;
-+}
-+
-+/* Release a previously acquired resource.
-+** The resource will be deleted when its refcount reaches 0.
-+*/
-+static void vmcs_sm_release_resource(struct SM_RESOURCE_T *resource, int force)
-+{
-+ struct SM_PRIV_DATA_T *private = resource->private;
-+ struct sm_mmap *map, *map_tmp;
-+ struct SM_RESOURCE_T *res_tmp;
-+ int ret;
-+
-+ mutex_lock(&(sm_state->map_lock));
-+
-+ if (--resource->ref_count) {
-+ if (force)
-+ pr_err("[%s]: resource %p in use\n", __func__, resource);
-+
-+ mutex_unlock(&(sm_state->map_lock));
-+ return;
-+ }
-+
-+ /* Time to free the resource. Start by removing it from the list */
-+ list_del(&resource->resource_list);
-+ list_del(&resource->global_resource_list);
-+
-+ /* Walk the global resource list, find out if the resource is used
-+ * somewhere else. In which case we don't want to delete it.
-+ */
-+ list_for_each_entry(res_tmp, &sm_state->resource_list,
-+ global_resource_list) {
-+ if (res_tmp->res_handle == resource->res_handle) {
-+ resource->res_handle = 0;
-+ break;
-+ }
-+ }
-+
-+ mutex_unlock(&(sm_state->map_lock));
-+
-+ pr_debug("[%s]: freeing data - guid %x, hdl %x, base address %p\n",
-+ __func__, resource->res_guid, resource->res_handle,
-+ resource->res_base_mem);
-+ resource->res_stats[FREE]++;
-+
-+ /* Make sure the resource we're removing is unmapped first */
-+ if (resource->map_count && !list_empty(&resource->map_list)) {
-+ down_write(&current->mm->mmap_sem);
-+ list_for_each_entry_safe(map, map_tmp, &resource->map_list,
-+ resource_map_list) {
-+ ret =
-+ do_munmap(current->mm, map->res_addr,
-+ resource->res_size);
-+ if (ret) {
-+ pr_err("[%s]: could not unmap resource %p\n",
-+ __func__, resource);
-+ }
-+ }
-+ up_write(&current->mm->mmap_sem);
-+ }
-+
-+ /* Free up the videocore allocated resource.
-+ */
-+ if (resource->res_handle) {
-+ VC_SM_FREE_T free = {
-+ resource->res_handle, resource->res_base_mem
-+ };
-+ int status = vc_vchi_sm_free(sm_state->sm_handle, &free,
-+ &private->int_trans_id);
-+ if (status != 0 && status != -EINTR) {
-+ pr_err("[%s]: failed to free memory on videocore (status: %u, trans_id: %u)\n",
-+ __func__, status, private->int_trans_id);
-+ resource->res_stats[FREE_FAIL]++;
-+ ret = -EPERM;
-+ }
-+ }
-+
-+ /* Free up the shared resource.
-+ */
-+ if (resource->res_shared)
-+ vmcs_sm_release_resource(resource->res_shared, 0);
-+
-+ /* Free up the local resource tracking this allocation.
-+ */
-+ vc_sm_resource_deceased(resource, force);
-+ kfree(resource);
-+}
-+
-+/* Dump the map table for the driver. If process is -1, dumps the whole table,
-+** if process is a valid pid (non -1) dump only the entries associated with the
-+** pid of interest.
-+*/
-+static void vmcs_sm_host_walk_map_per_pid(int pid)
-+{
-+ struct sm_mmap *map = NULL;
-+
-+ /* Make sure the device was started properly.
-+ */
-+ if (sm_state == NULL) {
-+ pr_err("[%s]: invalid device\n", __func__);
-+ return;
-+ }
-+
-+ mutex_lock(&(sm_state->map_lock));
-+
-+ /* Log all applicable mapping(s).
-+ */
-+ if (!list_empty(&sm_state->map_list)) {
-+ list_for_each_entry(map, &sm_state->map_list, map_list) {
-+ if (pid == -1 || map->res_pid == pid) {
-+ pr_info("[%s]: tgid: %u - vc-hdl: %x, usr-hdl: %x, usr-addr: %lx\n",
-+ __func__, map->res_pid, map->res_vc_hdl,
-+ map->res_usr_hdl, map->res_addr);
-+ }
-+ }
-+ }
-+
-+ mutex_unlock(&(sm_state->map_lock));
-+
-+ return;
-+}
-+
-+/* Dump the allocation table from host side point of view. This only dumps the
-+** data allocated for this process/device referenced by the file_data.
-+*/
-+static void vmcs_sm_host_walk_alloc(struct SM_PRIV_DATA_T *file_data)
-+{
-+ struct SM_RESOURCE_T *resource = NULL;
-+
-+ /* Make sure the device was started properly.
-+ */
-+ if ((sm_state == NULL) || (file_data == NULL)) {
-+ pr_err("[%s]: invalid device\n", __func__);
-+ return;
-+ }
-+
-+ mutex_lock(&(sm_state->map_lock));
-+
-+ if (!list_empty(&file_data->resource_list)) {
-+ list_for_each_entry(resource, &file_data->resource_list,
-+ resource_list) {
-+ pr_info("[%s]: guid: %x - hdl: %x, vc-mem: %p, size: %u, cache: %u\n",
-+ __func__, resource->res_guid, resource->res_handle,
-+ resource->res_base_mem, resource->res_size,
-+ resource->res_cached);
-+ }
-+ }
-+
-+ mutex_unlock(&(sm_state->map_lock));
-+
-+ return;
-+}
-+
-+/* Create support for private data tracking.
-+*/
-+static struct SM_PRIV_DATA_T *vc_sm_create_priv_data(pid_t id)
-+{
-+ char alloc_name[32];
-+ struct SM_PRIV_DATA_T *file_data = NULL;
-+
-+ /* Allocate private structure. */
-+ file_data = kzalloc(sizeof(*file_data), GFP_KERNEL);
-+
-+ if (!file_data) {
-+ pr_err("[%s]: cannot allocate file data\n", __func__);
-+ goto out;
-+ }
-+
-+ snprintf(alloc_name, sizeof(alloc_name), "%d", id);
-+
-+ INIT_LIST_HEAD(&file_data->resource_list);
-+ file_data->pid = id;
-+ file_data->dir_pid = debugfs_create_dir(alloc_name,
-+ sm_state->dir_alloc);
-+#if 0
-+ /* TODO: fix this to support querying statistics per pid */
-+
-+ if (IS_ERR_OR_NULL(file_data->dir_pid)) {
-+ file_data->dir_pid = NULL;
-+ } else {
-+ struct dentry *dir_entry;
-+
-+ dir_entry = debugfs_create_file(VC_SM_RESOURCES, S_IRUGO,
-+ file_data->dir_pid, file_data,
-+ vc_sm_debug_fs_fops);
-+
-+ file_data->dir_res.dir_entry = dir_entry;
-+ file_data->dir_res.priv_data = file_data;
-+ file_data->dir_res.show = &vc_sm_alloc_show;
-+
-+ dir_entry = debugfs_create_file(VC_SM_STATS, S_IRUGO,
-+ file_data->dir_pid, file_data,
-+ vc_sm_debug_fs_fops);
-+
-+ file_data->dir_res.dir_entry = dir_entry;
-+ file_data->dir_res.priv_data = file_data;
-+ file_data->dir_res.show = &vc_sm_statistics_show;
-+ }
-+ pr_debug("[%s]: private data allocated %p\n", __func__, file_data);
-+
-+#endif
-+out:
-+ return file_data;
-+}
-+
-+/* Open the device. Creates a private state to help track all allocation
-+** associated with this device.
-+*/
-+static int vc_sm_open(struct inode *inode, struct file *file)
-+{
-+ int ret = 0;
-+
-+ /* Make sure the device was started properly.
-+ */
-+ if (!sm_state) {
-+ pr_err("[%s]: invalid device\n", __func__);
-+ ret = -EPERM;
-+ goto out;
-+ }
-+
-+ file->private_data = vc_sm_create_priv_data(current->tgid);
-+ if (file->private_data == NULL) {
-+ pr_err("[%s]: failed to create data tracker\n", __func__);
-+
-+ ret = -ENOMEM;
-+ goto out;
-+ }
-+
-+out:
-+ return ret;
-+}
-+
-+/* Close the device. Free up all resources still associated with this device
-+** at the time.
-+*/
-+static int vc_sm_release(struct inode *inode, struct file *file)
-+{
-+ struct SM_PRIV_DATA_T *file_data =
-+ (struct SM_PRIV_DATA_T *)file->private_data;
-+ struct SM_RESOURCE_T *resource;
-+ int ret = 0;
-+
-+ /* Make sure the device was started properly.
-+ */
-+ if (sm_state == NULL || file_data == NULL) {
-+ pr_err("[%s]: invalid device\n", __func__);
-+ ret = -EPERM;
-+ goto out;
-+ }
-+
-+ pr_debug("[%s]: using private data %p\n", __func__, file_data);
-+
-+ if (file_data->restart_sys == -EINTR) {
-+ VC_SM_ACTION_CLEAN_T action_clean;
-+
-+ pr_debug("[%s]: releasing following EINTR on %u (trans_id: %u) (likely due to signal)...\n",
-+ __func__, file_data->int_action,
-+ file_data->int_trans_id);
-+
-+ action_clean.res_action = file_data->int_action;
-+ action_clean.action_trans_id = file_data->int_trans_id;
-+
-+ vc_vchi_sm_clean_up(sm_state->sm_handle, &action_clean);
-+ }
-+
-+ while ((resource = vmcs_sm_acquire_first_resource(file_data)) != NULL) {
-+ vmcs_sm_release_resource(resource, 0);
-+ vmcs_sm_release_resource(resource, 1);
-+ }
-+
-+ /* Remove the corresponding proc entry. */
-+ debugfs_remove_recursive(file_data->dir_pid);
-+
-+ /* Terminate the private data.
-+ */
-+ kfree(file_data);
-+
-+out:
-+ return ret;
-+}
-+
-+static void vcsm_vma_open(struct vm_area_struct *vma)
-+{
-+ struct sm_mmap *map = (struct sm_mmap *)vma->vm_private_data;
-+
-+ pr_debug("[%s]: virt %lx-%lx, pid %i, pfn %i\n",
-+ __func__, vma->vm_start, vma->vm_end, (int)current->tgid,
-+ (int)vma->vm_pgoff);
-+
-+ map->ref_count++;
-+}
-+
-+static void vcsm_vma_close(struct vm_area_struct *vma)
-+{
-+ struct sm_mmap *map = (struct sm_mmap *)vma->vm_private_data;
-+
-+ pr_debug("[%s]: virt %lx-%lx, pid %i, pfn %i\n",
-+ __func__, vma->vm_start, vma->vm_end, (int)current->tgid,
-+ (int)vma->vm_pgoff);
-+
-+ map->ref_count--;
-+
-+ /* Remove from the map table.
-+ */
-+ if (map->ref_count == 0)
-+ vmcs_sm_remove_map(sm_state, map->resource, map);
-+}
-+
-+static int vcsm_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
-+{
-+ struct sm_mmap *map = (struct sm_mmap *)vma->vm_private_data;
-+ struct SM_RESOURCE_T *resource = map->resource;
-+ pgoff_t page_offset;
-+ unsigned long pfn;
-+ int ret = 0;
-+
-+ /* Lock the resource if necessary.
-+ */
-+ if (!resource->lock_count) {
-+ VC_SM_LOCK_UNLOCK_T lock_unlock;
-+ VC_SM_LOCK_RESULT_T lock_result;
-+ int status;
-+
-+ lock_unlock.res_handle = resource->res_handle;
-+ lock_unlock.res_mem = resource->res_base_mem;
-+
-+ pr_debug("[%s]: attempt to lock data - hdl %x, base address %p\n",
-+ __func__, lock_unlock.res_handle, lock_unlock.res_mem);
-+
-+ /* Lock the videocore allocated resource.
-+ */
-+ status = vc_vchi_sm_lock(sm_state->sm_handle,
-+ &lock_unlock, &lock_result, 0);
-+ if ((status != 0) ||
-+ ((status == 0) && (lock_result.res_mem == NULL))) {
-+ pr_err("[%s]: failed to lock memory on videocore (status: %u)\n",
-+ __func__, status);
-+ resource->res_stats[LOCK_FAIL]++;
-+ return VM_FAULT_SIGBUS;
-+ }
-+
-+ pfn = vcaddr_to_pfn((unsigned long)resource->res_base_mem);
-+ outer_inv_range(__pfn_to_phys(pfn),
-+ __pfn_to_phys(pfn) + resource->res_size);
-+
-+ resource->res_stats[LOCK]++;
-+ resource->lock_count++;
-+
-+ /* Keep track of the new base memory.
-+ */
-+ if ((lock_result.res_mem != NULL) &&
-+ (lock_result.res_old_mem != NULL) &&
-+ (lock_result.res_mem != lock_result.res_old_mem)) {
-+ resource->res_base_mem = lock_result.res_mem;
-+ }
-+ }
-+
-+ /* We don't use vmf->pgoff since that has the fake offset */
-+ page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start);
-+ pfn = (uint32_t)resource->res_base_mem & 0x3FFFFFFF;
-+ pfn += mm_vc_mem_phys_addr;
-+ pfn += page_offset;
-+ pfn >>= PAGE_SHIFT;
-+
-+ /* Finally, remap it */
-+ ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn);
-+
-+ switch (ret) {
-+ case 0:
-+ case -ERESTARTSYS:
-+ return VM_FAULT_NOPAGE;
-+ case -ENOMEM:
-+ case -EAGAIN:
-+ return VM_FAULT_OOM;
-+ default:
-+ return VM_FAULT_SIGBUS;
-+ }
-+}
-+
-+static struct vm_operations_struct vcsm_vm_ops = {
-+ .open = vcsm_vma_open,
-+ .close = vcsm_vma_close,
-+ .fault = vcsm_vma_fault,
-+};
-+
-+/* Walks a VMA and clean each valid page from the cache */
-+static void vcsm_vma_cache_clean_page_range(unsigned long addr,
-+ unsigned long end)
-+{
-+ pgd_t *pgd;
-+ pud_t *pud;
-+ pmd_t *pmd;
-+ pte_t *pte;
-+ unsigned long pgd_next, pud_next, pmd_next;
-+
-+ if (addr >= end)
-+ return;
-+
-+ /* Walk PGD */
-+ pgd = pgd_offset(current->mm, addr);
-+ do {
-+ pgd_next = pgd_addr_end(addr, end);
-+
-+ if (pgd_none(*pgd) || pgd_bad(*pgd))
-+ continue;
-+
-+ /* Walk PUD */
-+ pud = pud_offset(pgd, addr);
-+ do {
-+ pud_next = pud_addr_end(addr, pgd_next);
-+ if (pud_none(*pud) || pud_bad(*pud))
-+ continue;
-+
-+ /* Walk PMD */
-+ pmd = pmd_offset(pud, addr);
-+ do {
-+ pmd_next = pmd_addr_end(addr, pud_next);
-+ if (pmd_none(*pmd) || pmd_bad(*pmd))
-+ continue;
-+
-+ /* Walk PTE */
-+ pte = pte_offset_map(pmd, addr);
-+ do {
-+ if (pte_none(*pte)
-+ || !pte_present(*pte))
-+ continue;
-+
-+ /* Clean + invalidate */
-+ dmac_flush_range((const void *) addr,
-+ (const void *)
-+ (addr + PAGE_SIZE));
-+
-+ } while (pte++, addr +=
-+ PAGE_SIZE, addr != pmd_next);
-+ pte_unmap(pte);
-+
-+ } while (pmd++, addr = pmd_next, addr != pud_next);
-+
-+ } while (pud++, addr = pud_next, addr != pgd_next);
-+ } while (pgd++, addr = pgd_next, addr != end);
-+}
-+
-+/* Map an allocated data into something that the user space.
-+*/
-+static int vc_sm_mmap(struct file *file, struct vm_area_struct *vma)
-+{
-+ int ret = 0;
-+ struct SM_PRIV_DATA_T *file_data =
-+ (struct SM_PRIV_DATA_T *)file->private_data;
-+ struct SM_RESOURCE_T *resource = NULL;
-+ struct sm_mmap *map = NULL;
-+
-+ /* Make sure the device was started properly.
-+ */
-+ if ((sm_state == NULL) || (file_data == NULL)) {
-+ pr_err("[%s]: invalid device\n", __func__);
-+ return -EPERM;
-+ }
-+
-+ pr_debug("[%s]: private data %p, guid %x\n", __func__, file_data,
-+ ((unsigned int)vma->vm_pgoff << PAGE_SHIFT));
-+
-+ /* We lookup to make sure that the data we are being asked to mmap is
-+ ** something that we allocated.
-+ **
-+ ** We use the offset information as the key to tell us which resource
-+ ** we are mapping.
-+ */
-+ resource = vmcs_sm_acquire_resource(file_data,
-+ ((unsigned int)vma->vm_pgoff <<
-+ PAGE_SHIFT));
-+ if (resource == NULL) {
-+ pr_err("[%s]: failed to locate resource for guid %x\n", __func__,
-+ ((unsigned int)vma->vm_pgoff << PAGE_SHIFT));
-+ return -ENOMEM;
-+ }
-+
-+ pr_debug("[%s]: guid %x, tgid %u, %u, %u\n",
-+ __func__, resource->res_guid, current->tgid, resource->pid,
-+ file_data->pid);
-+
-+ /* Check permissions.
-+ */
-+ if (resource->pid && (resource->pid != current->tgid)) {
-+ pr_err("[%s]: current tgid %u != %u owner\n",
-+ __func__, current->tgid, resource->pid);
-+ ret = -EPERM;
-+ goto error;
-+ }
-+
-+ /* Verify that what we are asked to mmap is proper.
-+ */
-+ if (resource->res_size != (unsigned int)(vma->vm_end - vma->vm_start)) {
-+ pr_err("[%s]: size inconsistency (resource: %u - mmap: %u)\n",
-+ __func__,
-+ resource->res_size,
-+ (unsigned int)(vma->vm_end - vma->vm_start));
-+
-+ ret = -EINVAL;
-+ goto error;
-+ }
-+
-+ /* Keep track of the tuple in the global resource list such that one
-+ * can do a mapping lookup for address/memory handle.
-+ */
-+ map = kzalloc(sizeof(*map), GFP_KERNEL);
-+ if (map == NULL) {
-+ pr_err("[%s]: failed to allocate global tracking resource\n",
-+ __func__);
-+ ret = -ENOMEM;
-+ goto error;
-+ }
-+
-+ map->res_pid = current->tgid;
-+ map->res_vc_hdl = resource->res_handle;
-+ map->res_usr_hdl = resource->res_guid;
-+ map->res_addr = (long unsigned int)vma->vm_start;
-+ map->resource = resource;
-+ map->vma = vma;
-+ vmcs_sm_add_map(sm_state, resource, map);
-+
-+ /* We are not actually mapping the pages, we just provide a fault
-+ ** handler to allow pages to be mapped when accessed
-+ */
-+ vma->vm_flags |=
-+ VM_IO | VM_PFNMAP | VM_DONTCOPY | VM_DONTEXPAND;
-+ vma->vm_ops = &vcsm_vm_ops;
-+ vma->vm_private_data = map;
-+
-+ /* vm_pgoff is the first PFN of the mapped memory */
-+ vma->vm_pgoff = (unsigned long)resource->res_base_mem & 0x3FFFFFFF;
-+ vma->vm_pgoff += mm_vc_mem_phys_addr;
-+ vma->vm_pgoff >>= PAGE_SHIFT;
-+
-+ if ((resource->res_cached == VMCS_SM_CACHE_NONE) ||
-+ (resource->res_cached == VMCS_SM_CACHE_VC)) {
-+ /* Allocated non host cached memory, honour it.
-+ */
-+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-+ }
-+
-+ pr_debug("[%s]: resource %p (guid %x) - cnt %u, base address %p, handle %x, size %u (%u), cache %u\n",
-+ __func__,
-+ resource, resource->res_guid, resource->lock_count,
-+ resource->res_base_mem, resource->res_handle,
-+ resource->res_size, (unsigned int)(vma->vm_end - vma->vm_start),
-+ resource->res_cached);
-+
-+ pr_debug("[%s]: resource %p (base address %p, handle %x) - map-count %d, usr-addr %x\n",
-+ __func__, resource, resource->res_base_mem,
-+ resource->res_handle, resource->map_count,
-+ (unsigned int)vma->vm_start);
-+
-+ vcsm_vma_open(vma);
-+ resource->res_stats[MAP]++;
-+ vmcs_sm_release_resource(resource, 0);
-+ return 0;
-+
-+error:
-+ resource->res_stats[MAP_FAIL]++;
-+ vmcs_sm_release_resource(resource, 0);
-+ return ret;
-+}
-+
-+/* Allocate a shared memory handle and block.
-+*/
-+int vc_sm_ioctl_alloc(struct SM_PRIV_DATA_T *private,
-+ struct vmcs_sm_ioctl_alloc *ioparam)
-+{
-+ int ret = 0;
-+ int status;
-+ struct SM_RESOURCE_T *resource;
-+ VC_SM_ALLOC_T alloc = { 0 };
-+ VC_SM_ALLOC_RESULT_T result = { 0 };
-+
-+ /* Setup our allocation parameters */
-+ alloc.type = ((ioparam->cached == VMCS_SM_CACHE_VC)
-+ || (ioparam->cached ==
-+ VMCS_SM_CACHE_BOTH)) ? VC_SM_ALLOC_CACHED :
-+ VC_SM_ALLOC_NON_CACHED;
-+ alloc.base_unit = ioparam->size;
-+ alloc.num_unit = ioparam->num;
-+ alloc.allocator = current->tgid;
-+ /* Align to kernel page size */
-+ alloc.alignement = 4096;
-+ /* Align the size to the kernel page size */
-+ alloc.base_unit =
-+ (alloc.base_unit + alloc.alignement - 1) & ~(alloc.alignement - 1);
-+ if (*ioparam->name) {
-+ memcpy(alloc.name, ioparam->name, sizeof(alloc.name) - 1);
-+ } else {
-+ memcpy(alloc.name, VMCS_SM_RESOURCE_NAME_DEFAULT,
-+ sizeof(VMCS_SM_RESOURCE_NAME_DEFAULT));
-+ }
-+
-+ pr_debug("[%s]: attempt to allocate \"%s\" data - type %u, base %u (%u), num %u, alignement %u\n",
-+ __func__, alloc.name, alloc.type, ioparam->size,
-+ alloc.base_unit, alloc.num_unit, alloc.alignement);
-+
-+ /* Allocate local resource to track this allocation.
-+ */
-+ resource = kzalloc(sizeof(*resource), GFP_KERNEL);
-+ if (!resource) {
-+ ret = -ENOMEM;
-+ goto error;
-+ }
-+ INIT_LIST_HEAD(&resource->map_list);
-+ resource->ref_count++;
-+ resource->pid = current->tgid;
-+
-+ /* Allocate the videocore resource.
-+ */
-+ status = vc_vchi_sm_alloc(sm_state->sm_handle, &alloc, &result,
-+ &private->int_trans_id);
-+ if (status == -EINTR) {
-+ pr_debug("[%s]: requesting allocate memory action restart (trans_id: %u)\n",
-+ __func__, private->int_trans_id);
-+ ret = -ERESTARTSYS;
-+ private->restart_sys = -EINTR;
-+ private->int_action = VC_SM_MSG_TYPE_ALLOC;
-+ goto error;
-+ } else if (status != 0 || (status == 0 && result.res_mem == NULL)) {
-+ pr_err("[%s]: failed to allocate memory on videocore (status: %u, trans_id: %u)\n",
-+ __func__, status, private->int_trans_id);
-+ ret = -ENOMEM;
-+ resource->res_stats[ALLOC_FAIL]++;
-+ goto error;
-+ }
-+
-+ /* Keep track of the resource we created.
-+ */
-+ resource->private = private;
-+ resource->res_handle = result.res_handle;
-+ resource->res_base_mem = result.res_mem;
-+ resource->res_size = alloc.base_unit * alloc.num_unit;
-+ resource->res_cached = ioparam->cached;
-+
-+ /* Kernel/user GUID. This global identifier is used for mmap'ing the
-+ * allocated region from user space, it is passed as the mmap'ing
-+ * offset, we use it to 'hide' the videocore handle/address.
-+ */
-+ mutex_lock(&sm_state->lock);
-+ resource->res_guid = ++sm_state->guid;
-+ mutex_unlock(&sm_state->lock);
-+ resource->res_guid <<= PAGE_SHIFT;
-+
-+ vmcs_sm_add_resource(private, resource);
-+
-+ pr_debug("[%s]: allocated data - guid %x, hdl %x, base address %p, size %d, cache %d\n",
-+ __func__, resource->res_guid, resource->res_handle,
-+ resource->res_base_mem, resource->res_size,
-+ resource->res_cached);
-+
-+ /* We're done */
-+ resource->res_stats[ALLOC]++;
-+ ioparam->handle = resource->res_guid;
-+ return 0;
-+
-+error:
-+ pr_err("[%s]: failed to allocate \"%s\" data (%i) - type %u, base %u (%u), num %u, alignment %u\n",
-+ __func__, alloc.name, ret, alloc.type, ioparam->size,
-+ alloc.base_unit, alloc.num_unit, alloc.alignement);
-+ if (resource != NULL) {
-+ vc_sm_resource_deceased(resource, 1);
-+ kfree(resource);
-+ }
-+ return ret;
-+}
-+
-+/* Share an allocate memory handle and block.
-+*/
-+int vc_sm_ioctl_alloc_share(struct SM_PRIV_DATA_T *private,
-+ struct vmcs_sm_ioctl_alloc_share *ioparam)
-+{
-+ struct SM_RESOURCE_T *resource, *shared_resource;
-+ int ret = 0;
-+
-+ pr_debug("[%s]: attempt to share resource %u\n", __func__,
-+ ioparam->handle);
-+
-+ shared_resource = vmcs_sm_acquire_global_resource(ioparam->handle);
-+ if (shared_resource == NULL) {
-+ ret = -ENOMEM;
-+ goto error;
-+ }
-+
-+ /* Allocate local resource to track this allocation.
-+ */
-+ resource = kzalloc(sizeof(*resource), GFP_KERNEL);
-+ if (resource == NULL) {
-+ pr_err("[%s]: failed to allocate local tracking resource\n",
-+ __func__);
-+ ret = -ENOMEM;
-+ goto error;
-+ }
-+ INIT_LIST_HEAD(&resource->map_list);
-+ resource->ref_count++;
-+ resource->pid = current->tgid;
-+
-+ /* Keep track of the resource we created.
-+ */
-+ resource->private = private;
-+ resource->res_handle = shared_resource->res_handle;
-+ resource->res_base_mem = shared_resource->res_base_mem;
-+ resource->res_size = shared_resource->res_size;
-+ resource->res_cached = shared_resource->res_cached;
-+ resource->res_shared = shared_resource;
-+
-+ mutex_lock(&sm_state->lock);
-+ resource->res_guid = ++sm_state->guid;
-+ mutex_unlock(&sm_state->lock);
-+ resource->res_guid <<= PAGE_SHIFT;
-+
-+ vmcs_sm_add_resource(private, resource);
-+
-+ pr_debug("[%s]: allocated data - guid %x, hdl %x, base address %p, size %d, cache %d\n",
-+ __func__, resource->res_guid, resource->res_handle,
-+ resource->res_base_mem, resource->res_size,
-+ resource->res_cached);
-+
-+ /* We're done */
-+ resource->res_stats[ALLOC]++;
-+ ioparam->handle = resource->res_guid;
-+ ioparam->size = resource->res_size;
-+ return 0;
-+
-+error:
-+ pr_err("[%s]: failed to share %u\n", __func__, ioparam->handle);
-+ if (shared_resource != NULL)
-+ vmcs_sm_release_resource(shared_resource, 0);
-+
-+ return ret;
-+}
-+
-+/* Free a previously allocated shared memory handle and block.
-+*/
-+static int vc_sm_ioctl_free(struct SM_PRIV_DATA_T *private,
-+ struct vmcs_sm_ioctl_free *ioparam)
-+{
-+ struct SM_RESOURCE_T *resource =
-+ vmcs_sm_acquire_resource(private, ioparam->handle);
-+
-+ if (resource == NULL) {
-+ pr_err("[%s]: resource for guid %u does not exist\n", __func__,
-+ ioparam->handle);
-+ return -EINVAL;
-+ }
-+
-+ /* Check permissions.
-+ */
-+ if (resource->pid && (resource->pid != current->tgid)) {
-+ pr_err("[%s]: current tgid %u != %u owner\n",
-+ __func__, current->tgid, resource->pid);
-+ vmcs_sm_release_resource(resource, 0);
-+ return -EPERM;
-+ }
-+
-+ vmcs_sm_release_resource(resource, 0);
-+ vmcs_sm_release_resource(resource, 0);
-+ return 0;
-+}
-+
-+/* Resize a previously allocated shared memory handle and block.
-+*/
-+static int vc_sm_ioctl_resize(struct SM_PRIV_DATA_T *private,
-+ struct vmcs_sm_ioctl_resize *ioparam)
-+{
-+ int ret = 0;
-+ int status;
-+ VC_SM_RESIZE_T resize;
-+ struct SM_RESOURCE_T *resource;
-+
-+ /* Locate resource from GUID.
-+ */
-+ resource = vmcs_sm_acquire_resource(private, ioparam->handle);
-+ if (!resource) {
-+ pr_err("[%s]: failed resource - guid %x\n",
-+ __func__, ioparam->handle);
-+ ret = -EFAULT;
-+ goto error;
-+ }
-+
-+ /* If the resource is locked, its reference count will be not NULL,
-+ ** in which case we will not be allowed to resize it anyways, so
-+ ** reject the attempt here.
-+ */
-+ if (resource->lock_count != 0) {
-+ pr_err("[%s]: cannot resize - guid %x, ref-cnt %d\n",
-+ __func__, ioparam->handle, resource->lock_count);
-+ ret = -EFAULT;
-+ goto error;
-+ }
-+
-+ /* Check permissions.
-+ */
-+ if (resource->pid && (resource->pid != current->tgid)) {
-+ pr_err("[%s]: current tgid %u != %u owner\n", __func__,
-+ current->tgid, resource->pid);
-+ ret = -EPERM;
-+ goto error;
-+ }
-+
-+ if (resource->map_count != 0) {
-+ pr_err("[%s]: cannot resize - guid %x, ref-cnt %d\n",
-+ __func__, ioparam->handle, resource->map_count);
-+ ret = -EFAULT;
-+ goto error;
-+ }
-+
-+ resize.res_handle = resource->res_handle;
-+ resize.res_mem = resource->res_base_mem;
-+ resize.res_new_size = ioparam->new_size;
-+
-+ pr_debug("[%s]: attempt to resize data - guid %x, hdl %x, base address %p\n",
-+ __func__, ioparam->handle, resize.res_handle, resize.res_mem);
-+
-+ /* Resize the videocore allocated resource.
-+ */
-+ status = vc_vchi_sm_resize(sm_state->sm_handle, &resize,
-+ &private->int_trans_id);
-+ if (status == -EINTR) {
-+ pr_debug("[%s]: requesting resize memory action restart (trans_id: %u)\n",
-+ __func__, private->int_trans_id);
-+ ret = -ERESTARTSYS;
-+ private->restart_sys = -EINTR;
-+ private->int_action = VC_SM_MSG_TYPE_RESIZE;
-+ goto error;
-+ } else if (status != 0) {
-+ pr_err("[%s]: failed to resize memory on videocore (status: %u, trans_id: %u)\n",
-+ __func__, status, private->int_trans_id);
-+ ret = -EPERM;
-+ goto error;
-+ }
-+
-+ pr_debug("[%s]: success to resize data - hdl %x, size %d -> %d\n",
-+ __func__, resize.res_handle, resource->res_size,
-+ resize.res_new_size);
-+
-+ /* Successfully resized, save the information and inform the user.
-+ */
-+ ioparam->old_size = resource->res_size;
-+ resource->res_size = resize.res_new_size;
-+
-+error:
-+ if (resource)
-+ vmcs_sm_release_resource(resource, 0);
-+
-+ return ret;
-+}
-+
-+/* Lock a previously allocated shared memory handle and block.
-+*/
-+static int vc_sm_ioctl_lock(struct SM_PRIV_DATA_T *private,
-+ struct vmcs_sm_ioctl_lock_unlock *ioparam,
-+ int change_cache, enum vmcs_sm_cache_e cache_type,
-+ unsigned int vc_addr)
-+{
-+ int status;
-+ VC_SM_LOCK_UNLOCK_T lock;
-+ VC_SM_LOCK_RESULT_T result;
-+ struct SM_RESOURCE_T *resource;
-+ int ret = 0;
-+ struct sm_mmap *map, *map_tmp;
-+ long unsigned int phys_addr;
-+
-+ map = NULL;
-+
-+ /* Locate resource from GUID.
-+ */
-+ resource = vmcs_sm_acquire_resource(private, ioparam->handle);
-+ if (resource == NULL) {
-+ ret = -EINVAL;
-+ goto error;
-+ }
-+
-+ /* Check permissions.
-+ */
-+ if (resource->pid && (resource->pid != current->tgid)) {
-+ pr_err("[%s]: current tgid %u != %u owner\n", __func__,
-+ current->tgid, resource->pid);
-+ ret = -EPERM;
-+ goto error;
-+ }
-+
-+ lock.res_handle = resource->res_handle;
-+ lock.res_mem = resource->res_base_mem;
-+
-+ /* Take the lock and get the address to be mapped.
-+ */
-+ if (vc_addr == 0) {
-+ pr_debug("[%s]: attempt to lock data - guid %x, hdl %x, base address %p\n",
-+ __func__, ioparam->handle, lock.res_handle,
-+ lock.res_mem);
-+
-+ /* Lock the videocore allocated resource.
-+ */
-+ status = vc_vchi_sm_lock(sm_state->sm_handle, &lock, &result,
-+ &private->int_trans_id);
-+ if (status == -EINTR) {
-+ pr_debug("[%s]: requesting lock memory action restart (trans_id: %u)\n",
-+ __func__, private->int_trans_id);
-+ ret = -ERESTARTSYS;
-+ private->restart_sys = -EINTR;
-+ private->int_action = VC_SM_MSG_TYPE_LOCK;
-+ goto error;
-+ } else if (status != 0 ||
-+ (status == 0 && result.res_mem == NULL)) {
-+ pr_err("[%s]: failed to lock memory on videocore (status: %u, trans_id: %u)\n",
-+ __func__, status, private->int_trans_id);
-+ ret = -EPERM;
-+ resource->res_stats[LOCK_FAIL]++;
-+ goto error;
-+ }
-+
-+ pr_debug("[%s]: succeed to lock data - hdl %x, base address %p (%p), ref-cnt %d\n",
-+ __func__, lock.res_handle, result.res_mem,
-+ lock.res_mem, resource->lock_count);
-+ }
-+ /* Lock assumed taken already, address to be mapped is known.
-+ */
-+ else
-+ resource->res_base_mem = (void *)vc_addr;
-+
-+ resource->res_stats[LOCK]++;
-+ resource->lock_count++;
-+
-+ /* Keep track of the new base memory allocation if it has changed.
-+ */
-+ if ((vc_addr == 0) &&
-+ (result.res_mem != NULL) &&
-+ (result.res_old_mem != NULL) &&
-+ (result.res_mem != result.res_old_mem)) {
-+ resource->res_base_mem = result.res_mem;
-+
-+ /* Kernel allocated resources.
-+ */
-+ if (resource->pid == 0) {
-+ if (!list_empty(&resource->map_list)) {
-+ list_for_each_entry_safe(map, map_tmp,
-+ &resource->map_list,
-+ resource_map_list) {
-+ if (map->res_addr) {
-+ iounmap((void *)map->res_addr);
-+ map->res_addr = 0;
-+
-+ vmcs_sm_remove_map(sm_state,
-+ map->resource,
-+ map);
-+ break;
-+ }
-+ }
-+ }
-+ }
-+ }
-+
-+ if (change_cache)
-+ resource->res_cached = cache_type;
-+
-+ if (resource->map_count) {
-+ ioparam->addr =
-+ vmcs_sm_usr_address_from_pid_and_usr_handle(
-+ current->tgid, ioparam->handle);
-+
-+ pr_debug("[%s] map_count %d private->pid %d current->tgid %d hnd %x addr %u\n",
-+ __func__, resource->map_count, private->pid,
-+ current->tgid, ioparam->handle, ioparam->addr);
-+ } else {
-+ /* Kernel allocated resources.
-+ */
-+ if (resource->pid == 0) {
-+ pr_debug("[%s]: attempt mapping kernel resource - guid %x, hdl %x\n",
-+ __func__, ioparam->handle, lock.res_handle);
-+
-+ ioparam->addr = 0;
-+
-+ map = kzalloc(sizeof(*map), GFP_KERNEL);
-+ if (map == NULL) {
-+ pr_err("[%s]: failed allocating tracker\n",
-+ __func__);
-+ ret = -ENOMEM;
-+ goto error;
-+ } else {
-+ phys_addr = (uint32_t)resource->res_base_mem &
-+ 0x3FFFFFFF;
-+ phys_addr += mm_vc_mem_phys_addr;
-+ if (resource->res_cached
-+ == VMCS_SM_CACHE_HOST) {
-+ ioparam->addr = (long unsigned int)
-+ /* TODO - make cached work */
-+ ioremap_nocache(phys_addr,
-+ resource->res_size);
-+
-+ pr_debug("[%s]: mapping kernel - guid %x, hdl %x - cached mapping %u\n",
-+ __func__, ioparam->handle,
-+ lock.res_handle, ioparam->addr);
-+ } else {
-+ ioparam->addr = (long unsigned int)
-+ ioremap_nocache(phys_addr,
-+ resource->res_size);
-+
-+ pr_debug("[%s]: mapping kernel- guid %x, hdl %x - non cached mapping %u\n",
-+ __func__, ioparam->handle,
-+ lock.res_handle, ioparam->addr);
-+ }
-+
-+ map->res_pid = 0;
-+ map->res_vc_hdl = resource->res_handle;
-+ map->res_usr_hdl = resource->res_guid;
-+ map->res_addr = ioparam->addr;
-+ map->resource = resource;
-+ map->vma = NULL;
-+
-+ vmcs_sm_add_map(sm_state, resource, map);
-+ }
-+ } else
-+ ioparam->addr = 0;
-+ }
-+
-+error:
-+ if (resource)
-+ vmcs_sm_release_resource(resource, 0);
-+
-+ return ret;
-+}
-+
-+/* Unlock a previously allocated shared memory handle and block.
-+*/
-+static int vc_sm_ioctl_unlock(struct SM_PRIV_DATA_T *private,
-+ struct vmcs_sm_ioctl_lock_unlock *ioparam,
-+ int flush, int wait_reply, int no_vc_unlock)
-+{
-+ int status;
-+ VC_SM_LOCK_UNLOCK_T unlock;
-+ struct sm_mmap *map, *map_tmp;
-+ struct SM_RESOURCE_T *resource;
-+ int ret = 0;
-+
-+ map = NULL;
-+
-+ /* Locate resource from GUID.
-+ */
-+ resource = vmcs_sm_acquire_resource(private, ioparam->handle);
-+ if (resource == NULL) {
-+ ret = -EINVAL;
-+ goto error;
-+ }
-+
-+ /* Check permissions.
-+ */
-+ if (resource->pid && (resource->pid != current->tgid)) {
-+ pr_err("[%s]: current tgid %u != %u owner\n",
-+ __func__, current->tgid, resource->pid);
-+ ret = -EPERM;
-+ goto error;
-+ }
-+
-+ unlock.res_handle = resource->res_handle;
-+ unlock.res_mem = resource->res_base_mem;
-+
-+ pr_debug("[%s]: attempt to unlock data - guid %x, hdl %x, base address %p\n",
-+ __func__, ioparam->handle, unlock.res_handle, unlock.res_mem);
-+
-+ /* User space allocated resources.
-+ */
-+ if (resource->pid) {
-+ /* Flush if requested */
-+ if (resource->res_cached && flush) {
-+ dma_addr_t phys_addr = 0;
-+ resource->res_stats[FLUSH]++;
-+
-+ phys_addr =
-+ (dma_addr_t)((uint32_t)resource->res_base_mem &
-+ 0x3FFFFFFF);
-+ phys_addr += (dma_addr_t)mm_vc_mem_phys_addr;
-+
-+ /* L1 cache flush */
-+ down_read(&current->mm->mmap_sem);
-+ list_for_each_entry(map, &resource->map_list,
-+ resource_map_list) {
-+ if (map->vma) {
-+ unsigned long start;
-+ unsigned long end;
-+ start = map->vma->vm_start;
-+ end = map->vma->vm_end;
-+
-+ vcsm_vma_cache_clean_page_range(
-+ start, end);
-+ }
-+ }
-+ up_read(&current->mm->mmap_sem);
-+
-+ /* L2 cache flush */
-+ outer_clean_range(phys_addr,
-+ phys_addr +
-+ (size_t) resource->res_size);
-+ }
-+
-+ /* We need to zap all the vmas associated with this resource */
-+ if (resource->lock_count == 1) {
-+ down_read(&current->mm->mmap_sem);
-+ list_for_each_entry(map, &resource->map_list,
-+ resource_map_list) {
-+ if (map->vma) {
-+ zap_vma_ptes(map->vma,
-+ map->vma->vm_start,
-+ map->vma->vm_end -
-+ map->vma->vm_start);
-+ }
-+ }
-+ up_read(&current->mm->mmap_sem);
-+ }
-+ }
-+ /* Kernel allocated resources. */
-+ else {
-+ /* Global + Taken in this context */
-+ if (resource->ref_count == 2) {
-+ if (!list_empty(&resource->map_list)) {
-+ list_for_each_entry_safe(map, map_tmp,
-+ &resource->map_list,
-+ resource_map_list) {
-+ if (map->res_addr) {
-+ if (flush &&
-+ (resource->res_cached ==
-+ VMCS_SM_CACHE_HOST)) {
-+ long unsigned int
-+ phys_addr;
-+ phys_addr = (uint32_t)
-+ resource->res_base_mem & 0x3FFFFFFF;
-+ phys_addr +=
-+ mm_vc_mem_phys_addr;
-+
-+ /* L1 cache flush */
-+ dmac_flush_range((const
-+ void
-+ *)
-+ map->res_addr, (const void *)
-+ (map->res_addr + resource->res_size));
-+
-+ /* L2 cache flush */
-+ outer_clean_range
-+ (phys_addr,
-+ phys_addr +
-+ (size_t)
-+ resource->res_size);
-+ }
-+
-+ iounmap((void *)map->res_addr);
-+ map->res_addr = 0;
-+
-+ vmcs_sm_remove_map(sm_state,
-+ map->resource,
-+ map);
-+ break;
-+ }
-+ }
-+ }
-+ }
-+ }
-+
-+ if (resource->lock_count) {
-+ /* Bypass the videocore unlock.
-+ */
-+ if (no_vc_unlock)
-+ status = 0;
-+ /* Unlock the videocore allocated resource.
-+ */
-+ else {
-+ status =
-+ vc_vchi_sm_unlock(sm_state->sm_handle, &unlock,
-+ &private->int_trans_id,
-+ wait_reply);
-+ if (status == -EINTR) {
-+ pr_debug("[%s]: requesting unlock memory action restart (trans_id: %u)\n",
-+ __func__, private->int_trans_id);
-+
-+ ret = -ERESTARTSYS;
-+ resource->res_stats[UNLOCK]--;
-+ private->restart_sys = -EINTR;
-+ private->int_action = VC_SM_MSG_TYPE_UNLOCK;
-+ goto error;
-+ } else if (status != 0) {
-+ pr_err("[%s]: failed to unlock vc mem (status: %u, trans_id: %u)\n",
-+ __func__, status, private->int_trans_id);
-+
-+ ret = -EPERM;
-+ resource->res_stats[UNLOCK_FAIL]++;
-+ goto error;
-+ }
-+ }
-+
-+ resource->res_stats[UNLOCK]++;
-+ resource->lock_count--;
-+ }
-+
-+ pr_debug("[%s]: success to unlock data - hdl %x, base address %p, ref-cnt %d\n",
-+ __func__, unlock.res_handle, unlock.res_mem,
-+ resource->lock_count);
-+
-+error:
-+ if (resource)
-+ vmcs_sm_release_resource(resource, 0);
-+
-+ return ret;
-+}
-+
-+/* Handle control from host. */
-+static long vc_sm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-+{
-+ int ret = 0;
-+ unsigned int cmdnr = _IOC_NR(cmd);
-+ struct SM_PRIV_DATA_T *file_data =
-+ (struct SM_PRIV_DATA_T *)file->private_data;
-+ struct SM_RESOURCE_T *resource = NULL;
-+
-+ /* Validate we can work with this device. */
-+ if ((sm_state == NULL) || (file_data == NULL)) {
-+ pr_err("[%s]: invalid device\n", __func__);
-+ ret = -EPERM;
-+ goto out;
-+ }
-+
-+ pr_debug("[%s]: cmd %x tgid %u, owner %u\n", __func__, cmdnr,
-+ current->tgid, file_data->pid);
-+
-+ /* Action is a re-post of a previously interrupted action? */
-+ if (file_data->restart_sys == -EINTR) {
-+ VC_SM_ACTION_CLEAN_T action_clean;
-+
-+ pr_debug("[%s]: clean up of action %u (trans_id: %u) following EINTR\n",
-+ __func__, file_data->int_action,
-+ file_data->int_trans_id);
-+
-+ action_clean.res_action = file_data->int_action;
-+ action_clean.action_trans_id = file_data->int_trans_id;
-+
-+ vc_vchi_sm_clean_up(sm_state->sm_handle, &action_clean);
-+
-+ file_data->restart_sys = 0;
-+ }
-+
-+ /* Now process the command.
-+ */
-+ switch (cmdnr) {
-+ /* New memory allocation.
-+ */
-+ case VMCS_SM_CMD_ALLOC:
-+ {
-+ struct vmcs_sm_ioctl_alloc ioparam;
-+
-+ /* Get the parameter data.
-+ */
-+ if (copy_from_user
-+ (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
-+ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
-+ __func__, cmdnr);
-+ ret = -EFAULT;
-+ goto out;
-+ }
-+
-+ ret = vc_sm_ioctl_alloc(file_data, &ioparam);
-+ if (!ret &&
-+ (copy_to_user((void *)arg,
-+ &ioparam, sizeof(ioparam)) != 0)) {
-+ struct vmcs_sm_ioctl_free freeparam = {
-+ ioparam.handle
-+ };
-+ pr_err("[%s]: failed to copy-to-user for cmd %x\n",
-+ __func__, cmdnr);
-+ vc_sm_ioctl_free(file_data, &freeparam);
-+ ret = -EFAULT;
-+ }
-+
-+ /* Done.
-+ */
-+ goto out;
-+ }
-+ break;
-+
-+ /* Share existing memory allocation.
-+ */
-+ case VMCS_SM_CMD_ALLOC_SHARE:
-+ {
-+ struct vmcs_sm_ioctl_alloc_share ioparam;
-+
-+ /* Get the parameter data.
-+ */
-+ if (copy_from_user
-+ (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
-+ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
-+ __func__, cmdnr);
-+ ret = -EFAULT;
-+ goto out;
-+ }
-+
-+ ret = vc_sm_ioctl_alloc_share(file_data, &ioparam);
-+
-+ /* Copy result back to user.
-+ */
-+ if (!ret
-+ && copy_to_user((void *)arg, &ioparam,
-+ sizeof(ioparam)) != 0) {
-+ struct vmcs_sm_ioctl_free freeparam = {
-+ ioparam.handle
-+ };
-+ pr_err("[%s]: failed to copy-to-user for cmd %x\n",
-+ __func__, cmdnr);
-+ vc_sm_ioctl_free(file_data, &freeparam);
-+ ret = -EFAULT;
-+ }
-+
-+ /* Done.
-+ */
-+ goto out;
-+ }
-+ break;
-+
-+ /* Lock (attempt to) *and* register a cache behavior change.
-+ */
-+ case VMCS_SM_CMD_LOCK_CACHE:
-+ {
-+ struct vmcs_sm_ioctl_lock_cache ioparam;
-+ struct vmcs_sm_ioctl_lock_unlock lock;
-+
-+ /* Get parameter data.
-+ */
-+ if (copy_from_user
-+ (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
-+ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
-+ __func__, cmdnr);
-+ ret = -EFAULT;
-+ goto out;
-+ }
-+
-+ lock.handle = ioparam.handle;
-+ ret =
-+ vc_sm_ioctl_lock(file_data, &lock, 1,
-+ ioparam.cached, 0);
-+
-+ /* Done.
-+ */
-+ goto out;
-+ }
-+ break;
-+
-+ /* Lock (attempt to) existing memory allocation.
-+ */
-+ case VMCS_SM_CMD_LOCK:
-+ {
-+ struct vmcs_sm_ioctl_lock_unlock ioparam;
-+
-+ /* Get parameter data.
-+ */
-+ if (copy_from_user
-+ (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
-+ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
-+ __func__, cmdnr);
-+ ret = -EFAULT;
-+ goto out;
-+ }
-+
-+ ret = vc_sm_ioctl_lock(file_data, &ioparam, 0, 0, 0);
-+
-+ /* Copy result back to user.
-+ */
-+ if (copy_to_user((void *)arg, &ioparam, sizeof(ioparam))
-+ != 0) {
-+ pr_err("[%s]: failed to copy-to-user for cmd %x\n",
-+ __func__, cmdnr);
-+ ret = -EFAULT;
-+ }
-+
-+ /* Done.
-+ */
-+ goto out;
-+ }
-+ break;
-+
-+ /* Unlock (attempt to) existing memory allocation.
-+ */
-+ case VMCS_SM_CMD_UNLOCK:
-+ {
-+ struct vmcs_sm_ioctl_lock_unlock ioparam;
-+
-+ /* Get parameter data.
-+ */
-+ if (copy_from_user
-+ (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
-+ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
-+ __func__, cmdnr);
-+ ret = -EFAULT;
-+ goto out;
-+ }
-+
-+ ret = vc_sm_ioctl_unlock(file_data, &ioparam, 0, 1, 0);
-+
-+ /* Done.
-+ */
-+ goto out;
-+ }
-+ break;
-+
-+ /* Resize (attempt to) existing memory allocation.
-+ */
-+ case VMCS_SM_CMD_RESIZE:
-+ {
-+ struct vmcs_sm_ioctl_resize ioparam;
-+
-+ /* Get parameter data.
-+ */
-+ if (copy_from_user
-+ (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
-+ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
-+ __func__, cmdnr);
-+ ret = -EFAULT;
-+ goto out;
-+ }
-+
-+ ret = vc_sm_ioctl_resize(file_data, &ioparam);
-+
-+ /* Copy result back to user.
-+ */
-+ if (copy_to_user((void *)arg, &ioparam, sizeof(ioparam))
-+ != 0) {
-+ pr_err("[%s]: failed to copy-to-user for cmd %x\n",
-+ __func__, cmdnr);
-+ ret = -EFAULT;
-+ }
-+
-+ /* Done.
-+ */
-+ goto out;
-+ }
-+ break;
-+
-+ /* Terminate existing memory allocation.
-+ */
-+ case VMCS_SM_CMD_FREE:
-+ {
-+ struct vmcs_sm_ioctl_free ioparam;
-+
-+ /* Get parameter data.
-+ */
-+ if (copy_from_user
-+ (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
-+ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
-+ __func__, cmdnr);
-+ ret = -EFAULT;
-+ goto out;
-+ }
-+
-+ ret = vc_sm_ioctl_free(file_data, &ioparam);
-+
-+ /* Done.
-+ */
-+ goto out;
-+ }
-+ break;
-+
-+ /* Walk allocation on videocore, information shows up in the
-+ ** videocore log.
-+ */
-+ case VMCS_SM_CMD_VC_WALK_ALLOC:
-+ {
-+ pr_debug("[%s]: invoking walk alloc\n", __func__);
-+
-+ if (vc_vchi_sm_walk_alloc(sm_state->sm_handle) != 0)
-+ pr_err("[%s]: failed to walk-alloc on videocore\n",
-+ __func__);
-+
-+ /* Done.
-+ */
-+ goto out;
-+ }
-+ break;
-+/* Walk mapping table on host, information shows up in the
-+ ** kernel log.
-+ */
-+ case VMCS_SM_CMD_HOST_WALK_MAP:
-+ {
-+ /* Use pid of -1 to tell to walk the whole map. */
-+ vmcs_sm_host_walk_map_per_pid(-1);
-+
-+ /* Done. */
-+ goto out;
-+ }
-+ break;
-+
-+ /* Walk mapping table per process on host. */
-+ case VMCS_SM_CMD_HOST_WALK_PID_ALLOC:
-+ {
-+ struct vmcs_sm_ioctl_walk ioparam;
-+
-+ /* Get parameter data. */
-+ if (copy_from_user(&ioparam,
-+ (void *)arg, sizeof(ioparam)) != 0) {
-+ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
-+ __func__, cmdnr);
-+ ret = -EFAULT;
-+ goto out;
-+ }
-+
-+ vmcs_sm_host_walk_alloc(file_data);
-+
-+ /* Done. */
-+ goto out;
-+ }
-+ break;
-+
-+ /* Walk allocation per process on host. */
-+ case VMCS_SM_CMD_HOST_WALK_PID_MAP:
-+ {
-+ struct vmcs_sm_ioctl_walk ioparam;
-+
-+ /* Get parameter data. */
-+ if (copy_from_user(&ioparam,
-+ (void *)arg, sizeof(ioparam)) != 0) {
-+ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
-+ __func__, cmdnr);
-+ ret = -EFAULT;
-+ goto out;
-+ }
-+
-+ vmcs_sm_host_walk_map_per_pid(ioparam.pid);
-+
-+ /* Done. */
-+ goto out;
-+ }
-+ break;
-+
-+ /* Gets the size of the memory associated with a user handle. */
-+ case VMCS_SM_CMD_SIZE_USR_HANDLE:
-+ {
-+ struct vmcs_sm_ioctl_size ioparam;
-+
-+ /* Get parameter data. */
-+ if (copy_from_user(&ioparam,
-+ (void *)arg, sizeof(ioparam)) != 0) {
-+ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
-+ __func__, cmdnr);
-+ ret = -EFAULT;
-+ goto out;
-+ }
-+
-+ /* Locate resource from GUID. */
-+ resource =
-+ vmcs_sm_acquire_resource(file_data, ioparam.handle);
-+ if (resource != NULL) {
-+ ioparam.size = resource->res_size;
-+ vmcs_sm_release_resource(resource, 0);
-+ } else {
-+ ioparam.size = 0;
-+ }
-+
-+ if (copy_to_user((void *)arg,
-+ &ioparam, sizeof(ioparam)) != 0) {
-+ pr_err("[%s]: failed to copy-to-user for cmd %x\n",
-+ __func__, cmdnr);
-+ ret = -EFAULT;
-+ }
-+
-+ /* Done. */
-+ goto out;
-+ }
-+ break;
-+
-+ /* Verify we are dealing with a valid resource. */
-+ case VMCS_SM_CMD_CHK_USR_HANDLE:
-+ {
-+ struct vmcs_sm_ioctl_chk ioparam;
-+
-+ /* Get parameter data.
-+ */
-+ if (copy_from_user(&ioparam,
-+ (void *)arg, sizeof(ioparam)) != 0) {
-+ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
-+ __func__, cmdnr);
-+
-+ ret = -EFAULT;
-+ goto out;
-+ }
-+
-+ /* Locate resource from GUID. */
-+ resource =
-+ vmcs_sm_acquire_resource(file_data, ioparam.handle);
-+ if (resource == NULL)
-+ ret = -EINVAL;
-+ /* If the resource is cacheable, return additional
-+ * information that may be needed to flush the cache.
-+ */
-+ else if ((resource->res_cached == VMCS_SM_CACHE_HOST) ||
-+ (resource->res_cached == VMCS_SM_CACHE_BOTH)) {
-+ ioparam.addr =
-+ vmcs_sm_usr_address_from_pid_and_usr_handle
-+ (current->tgid, ioparam.handle);
-+ ioparam.size = resource->res_size;
-+ ioparam.cache = resource->res_cached;
-+ } else {
-+ ioparam.addr = 0;
-+ ioparam.size = 0;
-+ ioparam.cache = resource->res_cached;
-+ }
-+
-+ if (resource)
-+ vmcs_sm_release_resource(resource, 0);
-+
-+ if (copy_to_user((void *)arg,
-+ &ioparam, sizeof(ioparam)) != 0) {
-+ pr_err("[%s]: failed to copy-to-user for cmd %x\n",
-+ __func__, cmdnr);
-+ ret = -EFAULT;
-+ }
-+
-+ /* Done.
-+ */
-+ goto out;
-+ }
-+ break;
-+
-+ /*
-+ * Maps a user handle given the process and the virtual address.
-+ */
-+ case VMCS_SM_CMD_MAPPED_USR_HANDLE:
-+ {
-+ struct vmcs_sm_ioctl_map ioparam;
-+
-+ /* Get parameter data. */
-+ if (copy_from_user(&ioparam,
-+ (void *)arg, sizeof(ioparam)) != 0) {
-+ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
-+ __func__, cmdnr);
-+
-+ ret = -EFAULT;
-+ goto out;
-+ }
-+
-+ ioparam.handle =
-+ vmcs_sm_usr_handle_from_pid_and_address(
-+ ioparam.pid, ioparam.addr);
-+
-+ resource =
-+ vmcs_sm_acquire_resource(file_data, ioparam.handle);
-+ if ((resource != NULL)
-+ && ((resource->res_cached == VMCS_SM_CACHE_HOST)
-+ || (resource->res_cached ==
-+ VMCS_SM_CACHE_BOTH))) {
-+ ioparam.size = resource->res_size;
-+ } else {
-+ ioparam.size = 0;
-+ }
-+
-+ if (resource)
-+ vmcs_sm_release_resource(resource, 0);
-+
-+ if (copy_to_user((void *)arg,
-+ &ioparam, sizeof(ioparam)) != 0) {
-+ pr_err("[%s]: failed to copy-to-user for cmd %x\n",
-+ __func__, cmdnr);
-+ ret = -EFAULT;
-+ }
-+
-+ /* Done. */
-+ goto out;
-+ }
-+ break;
-+
-+ /*
-+ * Maps a videocore handle given process and virtual address.
-+ */
-+ case VMCS_SM_CMD_MAPPED_VC_HDL_FROM_ADDR:
-+ {
-+ struct vmcs_sm_ioctl_map ioparam;
-+
-+ /* Get parameter data. */
-+ if (copy_from_user(&ioparam,
-+ (void *)arg, sizeof(ioparam)) != 0) {
-+ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
-+ __func__, cmdnr);
-+ ret = -EFAULT;
-+ goto out;
-+ }
-+
-+ ioparam.handle = vmcs_sm_vc_handle_from_pid_and_address(
-+ ioparam.pid, ioparam.addr);
-+
-+ if (copy_to_user((void *)arg,
-+ &ioparam, sizeof(ioparam)) != 0) {
-+ pr_err("[%s]: failed to copy-to-user for cmd %x\n",
-+ __func__, cmdnr);
-+
-+ ret = -EFAULT;
-+ }
-+
-+ /* Done.
-+ */
-+ goto out;
-+ }
-+ break;
-+
-+ /* Maps a videocore handle given process and user handle. */
-+ case VMCS_SM_CMD_MAPPED_VC_HDL_FROM_HDL:
-+ {
-+ struct vmcs_sm_ioctl_map ioparam;
-+
-+ /* Get parameter data. */
-+ if (copy_from_user(&ioparam,
-+ (void *)arg, sizeof(ioparam)) != 0) {
-+ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
-+ __func__, cmdnr);
-+ ret = -EFAULT;
-+ goto out;
-+ }
-+
-+ /* Locate resource from GUID. */
-+ resource =
-+ vmcs_sm_acquire_resource(file_data, ioparam.handle);
-+ if (resource != NULL) {
-+ ioparam.handle = resource->res_handle;
-+ vmcs_sm_release_resource(resource, 0);
-+ } else {
-+ ioparam.handle = 0;
-+ }
-+
-+ if (copy_to_user((void *)arg,
-+ &ioparam, sizeof(ioparam)) != 0) {
-+ pr_err("[%s]: failed to copy-to-user for cmd %x\n",
-+ __func__, cmdnr);
-+
-+ ret = -EFAULT;
-+ }
-+
-+ /* Done. */
-+ goto out;
-+ }
-+ break;
-+
-+ /*
-+ * Maps a videocore address given process and videocore handle.
-+ */
-+ case VMCS_SM_CMD_MAPPED_VC_ADDR_FROM_HDL:
-+ {
-+ struct vmcs_sm_ioctl_map ioparam;
-+
-+ /* Get parameter data. */
-+ if (copy_from_user(&ioparam,
-+ (void *)arg, sizeof(ioparam)) != 0) {
-+ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
-+ __func__, cmdnr);
-+
-+ ret = -EFAULT;
-+ goto out;
-+ }
-+
-+ /* Locate resource from GUID. */
-+ resource =
-+ vmcs_sm_acquire_resource(file_data, ioparam.handle);
-+ if (resource != NULL) {
-+ ioparam.addr =
-+ (unsigned int)resource->res_base_mem;
-+ vmcs_sm_release_resource(resource, 0);
-+ } else {
-+ ioparam.addr = 0;
-+ }
-+
-+ if (copy_to_user((void *)arg,
-+ &ioparam, sizeof(ioparam)) != 0) {
-+ pr_err("[%s]: failed to copy-to-user for cmd %x\n",
-+ __func__, cmdnr);
-+ ret = -EFAULT;
-+ }
-+
-+ /* Done. */
-+ goto out;
-+ }
-+ break;
-+
-+ /* Maps a user address given process and vc handle.
-+ */
-+ case VMCS_SM_CMD_MAPPED_USR_ADDRESS:
-+ {
-+ struct vmcs_sm_ioctl_map ioparam;
-+
-+ /* Get parameter data. */
-+ if (copy_from_user(&ioparam,
-+ (void *)arg, sizeof(ioparam)) != 0) {
-+ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
-+ __func__, cmdnr);
-+ ret = -EFAULT;
-+ goto out;
-+ }
-+
-+ /*
-+ * Return the address information from the mapping,
-+ * 0 (ie NULL) if it cannot locate the actual mapping.
-+ */
-+ ioparam.addr =
-+ vmcs_sm_usr_address_from_pid_and_usr_handle
-+ (ioparam.pid, ioparam.handle);
-+
-+ if (copy_to_user((void *)arg,
-+ &ioparam, sizeof(ioparam)) != 0) {
-+ pr_err("[%s]: failed to copy-to-user for cmd %x\n",
-+ __func__, cmdnr);
-+ ret = -EFAULT;
-+ }
-+
-+ /* Done. */
-+ goto out;
-+ }
-+ break;
-+
-+ /* Flush the cache for a given mapping. */
-+ case VMCS_SM_CMD_FLUSH:
-+ {
-+ struct vmcs_sm_ioctl_cache ioparam;
-+
-+ /* Get parameter data. */
-+ if (copy_from_user(&ioparam,
-+ (void *)arg, sizeof(ioparam)) != 0) {
-+ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
-+ __func__, cmdnr);
-+ ret = -EFAULT;
-+ goto out;
-+ }
-+
-+ /* Locate resource from GUID. */
-+ resource =
-+ vmcs_sm_acquire_resource(file_data, ioparam.handle);
-+
-+ if ((resource != NULL) && resource->res_cached) {
-+ dma_addr_t phys_addr = 0;
-+
-+ resource->res_stats[FLUSH]++;
-+
-+ phys_addr =
-+ (dma_addr_t)((uint32_t)
-+ resource->res_base_mem &
-+ 0x3FFFFFFF);
-+ phys_addr += (dma_addr_t)mm_vc_mem_phys_addr;
-+
-+ /* L1 cache flush */
-+ down_read(&current->mm->mmap_sem);
-+ vcsm_vma_cache_clean_page_range((unsigned long)
-+ ioparam.addr,
-+ (unsigned long)
-+ ioparam.addr +
-+ ioparam.size);
-+ up_read(&current->mm->mmap_sem);
-+
-+ /* L2 cache flush */
-+ outer_clean_range(phys_addr,
-+ phys_addr +
-+ (size_t) ioparam.size);
-+ } else if (resource == NULL) {
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ if (resource)
-+ vmcs_sm_release_resource(resource, 0);
-+
-+ /* Done. */
-+ goto out;
-+ }
-+ break;
-+
-+ /* Invalidate the cache for a given mapping. */
-+ case VMCS_SM_CMD_INVALID:
-+ {
-+ struct vmcs_sm_ioctl_cache ioparam;
-+
-+ /* Get parameter data. */
-+ if (copy_from_user(&ioparam,
-+ (void *)arg, sizeof(ioparam)) != 0) {
-+ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
-+ __func__, cmdnr);
-+ ret = -EFAULT;
-+ goto out;
-+ }
-+
-+ /* Locate resource from GUID.
-+ */
-+ resource =
-+ vmcs_sm_acquire_resource(file_data, ioparam.handle);
-+
-+ if ((resource != NULL) && resource->res_cached) {
-+ dma_addr_t phys_addr = 0;
-+
-+ resource->res_stats[INVALID]++;
-+
-+ phys_addr =
-+ (dma_addr_t)((uint32_t)
-+ resource->res_base_mem &
-+ 0x3FFFFFFF);
-+ phys_addr += (dma_addr_t)mm_vc_mem_phys_addr;
-+
-+ /* L2 cache invalidate */
-+ outer_inv_range(phys_addr,
-+ phys_addr +
-+ (size_t) ioparam.size);
-+
-+ /* L1 cache invalidate */
-+ down_read(&current->mm->mmap_sem);
-+ vcsm_vma_cache_clean_page_range((unsigned long)
-+ ioparam.addr,
-+ (unsigned long)
-+ ioparam.addr +
-+ ioparam.size);
-+ up_read(&current->mm->mmap_sem);
-+ } else if (resource == NULL) {
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ if (resource)
-+ vmcs_sm_release_resource(resource, 0);
-+
-+ /* Done.
-+ */
-+ goto out;
-+ }
-+ break;
-+
-+ /* Flush/Invalidate the cache for a given mapping. */
-+ case VMCS_SM_CMD_CLEAN_INVALID:
-+ {
-+ int i;
-+ struct vmcs_sm_ioctl_clean_invalid ioparam;
-+
-+ /* Get parameter data. */
-+ if (copy_from_user(&ioparam,
-+ (void *)arg, sizeof(ioparam)) != 0) {
-+ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
-+ __func__, cmdnr);
-+ ret = -EFAULT;
-+ goto out;
-+ }
-+ for (i=0; i<sizeof ioparam.s/sizeof *ioparam.s; i++) {
-+ switch (ioparam.s[i].cmd) {
-+ default: case 0: break; /* NOOP */
-+ case 1: /* L1/L2 invalidate virtual range */
-+ case 2: /* L1/L2 clean physical range */
-+ case 3: /* L1/L2 clean+invalidate all */
-+ {
-+ /* Locate resource from GUID.
-+ */
-+ resource =
-+ vmcs_sm_acquire_resource(file_data, ioparam.s[i].handle);
-+
-+ if ((resource != NULL) && resource->res_cached) {
-+ unsigned long base = ioparam.s[i].addr & ~(PAGE_SIZE-1);
-+ unsigned long end = (ioparam.s[i].addr + ioparam.s[i].size + PAGE_SIZE-1) & ~(PAGE_SIZE-1);
-+ resource->res_stats[ioparam.s[i].cmd == 1 ? INVALID:FLUSH]++;
-+
-+ /* L1/L2 cache flush */
-+ down_read(&current->mm->mmap_sem);
-+ vcsm_vma_cache_clean_page_range(base, end);
-+ up_read(&current->mm->mmap_sem);
-+ } else if (resource == NULL) {
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ if (resource)
-+ vmcs_sm_release_resource(resource, 0);
-+ }
-+ break;
-+ }
-+ }
-+ }
-+ break;
-+
-+ default:
-+ {
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+ break;
-+ }
-+
-+out:
-+ return ret;
-+}
-+
-+/* Device operations that we managed in this driver.
-+*/
-+static const struct file_operations vmcs_sm_ops = {
-+ .owner = THIS_MODULE,
-+ .unlocked_ioctl = vc_sm_ioctl,
-+ .open = vc_sm_open,
-+ .release = vc_sm_release,
-+ .mmap = vc_sm_mmap,
-+};
-+
-+/* Creation of device.
-+*/
-+static int vc_sm_create_sharedmemory(void)
-+{
-+ int ret;
-+
-+ if (sm_state == NULL) {
-+ ret = -ENOMEM;
-+ goto out;
-+ }
-+
-+ /* Create a device class for creating dev nodes.
-+ */
-+ sm_state->sm_class = class_create(THIS_MODULE, "vc-sm");
-+ if (IS_ERR(sm_state->sm_class)) {
-+ pr_err("[%s]: unable to create device class\n", __func__);
-+ ret = PTR_ERR(sm_state->sm_class);
-+ goto out;
-+ }
-+
-+ /* Create a character driver.
-+ */
-+ ret = alloc_chrdev_region(&sm_state->sm_devid,
-+ DEVICE_MINOR, 1, DEVICE_NAME);
-+ if (ret != 0) {
-+ pr_err("[%s]: unable to allocate device number\n", __func__);
-+ goto out_dev_class_destroy;
-+ }
-+
-+ cdev_init(&sm_state->sm_cdev, &vmcs_sm_ops);
-+ ret = cdev_add(&sm_state->sm_cdev, sm_state->sm_devid, 1);
-+ if (ret != 0) {
-+ pr_err("[%s]: unable to register device\n", __func__);
-+ goto out_chrdev_unreg;
-+ }
-+
-+ /* Create a device node.
-+ */
-+ sm_state->sm_dev = device_create(sm_state->sm_class,
-+ NULL,
-+ MKDEV(MAJOR(sm_state->sm_devid),
-+ DEVICE_MINOR), NULL,
-+ DEVICE_NAME);
-+ if (IS_ERR(sm_state->sm_dev)) {
-+ pr_err("[%s]: unable to create device node\n", __func__);
-+ ret = PTR_ERR(sm_state->sm_dev);
-+ goto out_chrdev_del;
-+ }
-+
-+ goto out;
-+
-+out_chrdev_del:
-+ cdev_del(&sm_state->sm_cdev);
-+out_chrdev_unreg:
-+ unregister_chrdev_region(sm_state->sm_devid, 1);
-+out_dev_class_destroy:
-+ class_destroy(sm_state->sm_class);
-+ sm_state->sm_class = NULL;
-+out:
-+ return ret;
-+}
-+
-+/* Termination of the device.
-+*/
-+static int vc_sm_remove_sharedmemory(void)
-+{
-+ int ret;
-+
-+ if (sm_state == NULL) {
-+ /* Nothing to do.
-+ */
-+ ret = 0;
-+ goto out;
-+ }
-+
-+ /* Remove the sharedmemory character driver.
-+ */
-+ cdev_del(&sm_state->sm_cdev);
-+
-+ /* Unregister region.
-+ */
-+ unregister_chrdev_region(sm_state->sm_devid, 1);
-+
-+ ret = 0;
-+ goto out;
-+
-+out:
-+ return ret;
-+}
-+
-+/* Videocore connected. */
-+static void vc_sm_connected_init(void)
-+{
-+ int ret;
-+ VCHI_INSTANCE_T vchi_instance;
-+ VCHI_CONNECTION_T *vchi_connection = NULL;
-+
-+ pr_info("[%s]: start\n", __func__);
-+
-+ /* Allocate memory for the state structure.
-+ */
-+ sm_state = kzalloc(sizeof(struct SM_STATE_T), GFP_KERNEL);
-+ if (sm_state == NULL) {
-+ pr_err("[%s]: failed to allocate memory\n", __func__);
-+ ret = -ENOMEM;
-+ goto out;
-+ }
-+
-+ mutex_init(&sm_state->lock);
-+ mutex_init(&sm_state->map_lock);
-+
-+ /* Initialize and create a VCHI connection for the shared memory service
-+ ** running on videocore.
-+ */
-+ ret = vchi_initialise(&vchi_instance);
-+ if (ret != 0) {
-+ pr_err("[%s]: failed to initialise VCHI instance (ret=%d)\n",
-+ __func__, ret);
-+
-+ ret = -EIO;
-+ goto err_free_mem;
-+ }
-+
-+ ret = vchi_connect(NULL, 0, vchi_instance);
-+ if (ret != 0) {
-+ pr_err("[%s]: failed to connect VCHI instance (ret=%d)\n",
-+ __func__, ret);
-+
-+ ret = -EIO;
-+ goto err_free_mem;
-+ }
-+
-+ /* Initialize an instance of the shared memory service. */
-+ sm_state->sm_handle =
-+ vc_vchi_sm_init(vchi_instance, &vchi_connection, 1);
-+ if (sm_state->sm_handle == NULL) {
-+ pr_err("[%s]: failed to initialize shared memory service\n",
-+ __func__);
-+
-+ ret = -EPERM;
-+ goto err_free_mem;
-+ }
-+
-+ /* Create a debug fs directory entry (root). */
-+ sm_state->dir_root = debugfs_create_dir(VC_SM_DIR_ROOT_NAME, NULL);
-+ if (!sm_state->dir_root) {
-+ pr_err("[%s]: failed to create \'%s\' directory entry\n",
-+ __func__, VC_SM_DIR_ROOT_NAME);
-+
-+ ret = -EPERM;
-+ goto err_stop_sm_service;
-+ }
-+
-+ sm_state->dir_state.show = &vc_sm_global_state_show;
-+ sm_state->dir_state.dir_entry = debugfs_create_file(VC_SM_STATE,
-+ S_IRUGO, sm_state->dir_root, &sm_state->dir_state,
-+ &vc_sm_debug_fs_fops);
-+
-+ sm_state->dir_stats.show = &vc_sm_global_statistics_show;
-+ sm_state->dir_stats.dir_entry = debugfs_create_file(VC_SM_STATS,
-+ S_IRUGO, sm_state->dir_root, &sm_state->dir_stats,
-+ &vc_sm_debug_fs_fops);
-+
-+ /* Create the proc entry children. */
-+ sm_state->dir_alloc = debugfs_create_dir(VC_SM_DIR_ALLOC_NAME,
-+ sm_state->dir_root);
-+
-+ /* Create a shared memory device. */
-+ ret = vc_sm_create_sharedmemory();
-+ if (ret != 0) {
-+ pr_err("[%s]: failed to create shared memory device\n",
-+ __func__);
-+ goto err_remove_debugfs;
-+ }
-+
-+ INIT_LIST_HEAD(&sm_state->map_list);
-+ INIT_LIST_HEAD(&sm_state->resource_list);
-+
-+ sm_state->data_knl = vc_sm_create_priv_data(0);
-+ if (sm_state->data_knl == NULL) {
-+ pr_err("[%s]: failed to create kernel private data tracker\n",
-+ __func__);
-+ goto err_remove_shared_memory;
-+ }
-+
-+ /* Done!
-+ */
-+ sm_inited = 1;
-+ goto out;
-+
-+err_remove_shared_memory:
-+ vc_sm_remove_sharedmemory();
-+err_remove_debugfs:
-+ debugfs_remove_recursive(sm_state->dir_root);
-+err_stop_sm_service:
-+ vc_vchi_sm_stop(&sm_state->sm_handle);
-+err_free_mem:
-+ kfree(sm_state);
-+out:
-+ pr_info("[%s]: end - returning %d\n", __func__, ret);
-+}
-+
-+/* Driver loading. */
-+static int __init vc_sm_init(void)
-+{
-+ pr_info("vc-sm: Videocore shared memory driver\n");
-+ vchiq_add_connected_callback(vc_sm_connected_init);
-+ return 0;
-+}
-+
-+/* Driver unloading. */
-+static void __exit vc_sm_exit(void)
-+{
-+ pr_debug("[%s]: start\n", __func__);
-+ if (sm_inited) {
-+ /* Remove shared memory device.
-+ */
-+ vc_sm_remove_sharedmemory();
-+
-+ /* Remove all proc entries.
-+ */
-+ debugfs_remove_recursive(sm_state->dir_root);
-+
-+ /* Stop the videocore shared memory service.
-+ */
-+ vc_vchi_sm_stop(&sm_state->sm_handle);
-+
-+ /* Free the memory for the state structure.
-+ */
-+ mutex_destroy(&(sm_state->map_lock));
-+ kfree(sm_state);
-+ }
-+
-+ pr_debug("[%s]: end\n", __func__);
-+}
-+
-+#if defined(__KERNEL__)
-+/* Allocate a shared memory handle and block. */
-+int vc_sm_alloc(VC_SM_ALLOC_T *alloc, int *handle)
-+{
-+ struct vmcs_sm_ioctl_alloc ioparam = { 0 };
-+ int ret;
-+ struct SM_RESOURCE_T *resource;
-+
-+ /* Validate we can work with this device.
-+ */
-+ if (sm_state == NULL || alloc == NULL || handle == NULL) {
-+ pr_err("[%s]: invalid input\n", __func__);
-+ return -EPERM;
-+ }
-+
-+ ioparam.size = alloc->base_unit;
-+ ioparam.num = alloc->num_unit;
-+ ioparam.cached =
-+ alloc->type == VC_SM_ALLOC_CACHED ? VMCS_SM_CACHE_VC : 0;
-+
-+ ret = vc_sm_ioctl_alloc(sm_state->data_knl, &ioparam);
-+
-+ if (ret == 0) {
-+ resource =
-+ vmcs_sm_acquire_resource(sm_state->data_knl,
-+ ioparam.handle);
-+ if (resource) {
-+ resource->pid = 0;
-+ vmcs_sm_release_resource(resource, 0);
-+
-+ /* Assign valid handle at this time.
-+ */
-+ *handle = ioparam.handle;
-+ } else {
-+ ret = -ENOMEM;
-+ }
-+ }
-+
-+ return ret;
-+}
-+EXPORT_SYMBOL_GPL(vc_sm_alloc);
-+
-+/* Get an internal resource handle mapped from the external one.
-+*/
-+int vc_sm_int_handle(int handle)
-+{
-+ struct SM_RESOURCE_T *resource;
-+ int ret = 0;
-+
-+ /* Validate we can work with this device.
-+ */
-+ if (sm_state == NULL || handle == 0) {
-+ pr_err("[%s]: invalid input\n", __func__);
-+ return 0;
-+ }
-+
-+ /* Locate resource from GUID.
-+ */
-+ resource = vmcs_sm_acquire_resource(sm_state->data_knl, handle);
-+ if (resource) {
-+ ret = resource->res_handle;
-+ vmcs_sm_release_resource(resource, 0);
-+ }
-+
-+ return ret;
-+}
-+EXPORT_SYMBOL_GPL(vc_sm_int_handle);
-+
-+/* Free a previously allocated shared memory handle and block.
-+*/
-+int vc_sm_free(int handle)
-+{
-+ struct vmcs_sm_ioctl_free ioparam = { handle };
-+
-+ /* Validate we can work with this device.
-+ */
-+ if (sm_state == NULL || handle == 0) {
-+ pr_err("[%s]: invalid input\n", __func__);
-+ return -EPERM;
-+ }
-+
-+ return vc_sm_ioctl_free(sm_state->data_knl, &ioparam);
-+}
-+EXPORT_SYMBOL_GPL(vc_sm_free);
-+
-+/* Lock a memory handle for use by kernel.
-+*/
-+int vc_sm_lock(int handle, VC_SM_LOCK_CACHE_MODE_T mode,
-+ long unsigned int *data)
-+{
-+ struct vmcs_sm_ioctl_lock_unlock ioparam;
-+ int ret;
-+
-+ /* Validate we can work with this device.
-+ */
-+ if (sm_state == NULL || handle == 0 || data == NULL) {
-+ pr_err("[%s]: invalid input\n", __func__);
-+ return -EPERM;
-+ }
-+
-+ *data = 0;
-+
-+ ioparam.handle = handle;
-+ ret = vc_sm_ioctl_lock(sm_state->data_knl,
-+ &ioparam,
-+ 1,
-+ ((mode ==
-+ VC_SM_LOCK_CACHED) ? VMCS_SM_CACHE_HOST :
-+ VMCS_SM_CACHE_NONE), 0);
-+
-+ *data = ioparam.addr;
-+ return ret;
-+}
-+EXPORT_SYMBOL_GPL(vc_sm_lock);
-+
-+/* Unlock a memory handle in use by kernel.
-+*/
-+int vc_sm_unlock(int handle, int flush, int no_vc_unlock)
-+{
-+ struct vmcs_sm_ioctl_lock_unlock ioparam;
-+
-+ /* Validate we can work with this device.
-+ */
-+ if (sm_state == NULL || handle == 0) {
-+ pr_err("[%s]: invalid input\n", __func__);
-+ return -EPERM;
-+ }
-+
-+ ioparam.handle = handle;
-+ return vc_sm_ioctl_unlock(sm_state->data_knl,
-+ &ioparam, flush, 0, no_vc_unlock);
-+}
-+EXPORT_SYMBOL_GPL(vc_sm_unlock);
-+
-+/* Map a shared memory region for use by kernel.
-+*/
-+int vc_sm_map(int handle, unsigned int sm_addr, VC_SM_LOCK_CACHE_MODE_T mode,
-+ long unsigned int *data)
-+{
-+ struct vmcs_sm_ioctl_lock_unlock ioparam;
-+ int ret;
-+
-+ /* Validate we can work with this device.
-+ */
-+ if (sm_state == NULL || handle == 0 || data == NULL || sm_addr == 0) {
-+ pr_err("[%s]: invalid input\n", __func__);
-+ return -EPERM;
-+ }
-+
-+ *data = 0;
-+
-+ ioparam.handle = handle;
-+ ret = vc_sm_ioctl_lock(sm_state->data_knl,
-+ &ioparam,
-+ 1,
-+ ((mode ==
-+ VC_SM_LOCK_CACHED) ? VMCS_SM_CACHE_HOST :
-+ VMCS_SM_CACHE_NONE), sm_addr);
-+
-+ *data = ioparam.addr;
-+ return ret;
-+}
-+EXPORT_SYMBOL_GPL(vc_sm_map);
-+#endif
-+
-+late_initcall(vc_sm_init);
-+module_exit(vc_sm_exit);
-+
-+MODULE_AUTHOR("Broadcom");
-+MODULE_DESCRIPTION("VideoCore SharedMemory Driver");
-+MODULE_LICENSE("GPL v2");
---- /dev/null
-+++ b/include/linux/broadcom/vmcs_sm_ioctl.h
-@@ -0,0 +1,248 @@
-+/*****************************************************************************
-+* Copyright 2011 Broadcom Corporation. All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*
-+*****************************************************************************/
-+
-+#if !defined(__VMCS_SM_IOCTL_H__INCLUDED__)
-+#define __VMCS_SM_IOCTL_H__INCLUDED__
-+
-+/* ---- Include Files ---------------------------------------------------- */
-+
-+#if defined(__KERNEL__)
-+#include <linux/types.h> /* Needed for standard types */
-+#else
-+#include <stdint.h>
-+#endif
-+
-+#include <linux/ioctl.h>
-+
-+/* ---- Constants and Types ---------------------------------------------- */
-+
-+#define VMCS_SM_RESOURCE_NAME 32
-+#define VMCS_SM_RESOURCE_NAME_DEFAULT "sm-host-resource"
-+
-+/* Type define used to create unique IOCTL number */
-+#define VMCS_SM_MAGIC_TYPE 'I'
-+
-+/* IOCTL commands */
-+enum vmcs_sm_cmd_e {
-+ VMCS_SM_CMD_ALLOC = 0x5A, /* Start at 0x5A arbitrarily */
-+ VMCS_SM_CMD_ALLOC_SHARE,
-+ VMCS_SM_CMD_LOCK,
-+ VMCS_SM_CMD_LOCK_CACHE,
-+ VMCS_SM_CMD_UNLOCK,
-+ VMCS_SM_CMD_RESIZE,
-+ VMCS_SM_CMD_UNMAP,
-+ VMCS_SM_CMD_FREE,
-+ VMCS_SM_CMD_FLUSH,
-+ VMCS_SM_CMD_INVALID,
-+
-+ VMCS_SM_CMD_SIZE_USR_HANDLE,
-+ VMCS_SM_CMD_CHK_USR_HANDLE,
-+
-+ VMCS_SM_CMD_MAPPED_USR_HANDLE,
-+ VMCS_SM_CMD_MAPPED_USR_ADDRESS,
-+ VMCS_SM_CMD_MAPPED_VC_HDL_FROM_ADDR,
-+ VMCS_SM_CMD_MAPPED_VC_HDL_FROM_HDL,
-+ VMCS_SM_CMD_MAPPED_VC_ADDR_FROM_HDL,
-+
-+ VMCS_SM_CMD_VC_WALK_ALLOC,
-+ VMCS_SM_CMD_HOST_WALK_MAP,
-+ VMCS_SM_CMD_HOST_WALK_PID_ALLOC,
-+ VMCS_SM_CMD_HOST_WALK_PID_MAP,
-+
-+ VMCS_SM_CMD_CLEAN_INVALID,
-+
-+ VMCS_SM_CMD_LAST /* Do no delete */
-+};
-+
-+/* Cache type supported, conveniently matches the user space definition in
-+** user-vcsm.h.
-+*/
-+enum vmcs_sm_cache_e {
-+ VMCS_SM_CACHE_NONE,
-+ VMCS_SM_CACHE_HOST,
-+ VMCS_SM_CACHE_VC,
-+ VMCS_SM_CACHE_BOTH,
-+};
-+
-+/* IOCTL Data structures */
-+struct vmcs_sm_ioctl_alloc {
-+ /* user -> kernel */
-+ unsigned int size;
-+ unsigned int num;
-+ enum vmcs_sm_cache_e cached;
-+ char name[VMCS_SM_RESOURCE_NAME];
-+
-+ /* kernel -> user */
-+ unsigned int handle;
-+ /* unsigned int base_addr; */
-+};
-+
-+struct vmcs_sm_ioctl_alloc_share {
-+ /* user -> kernel */
-+ unsigned int handle;
-+ unsigned int size;
-+};
-+
-+struct vmcs_sm_ioctl_free {
-+ /* user -> kernel */
-+ unsigned int handle;
-+ /* unsigned int base_addr; */
-+};
-+
-+struct vmcs_sm_ioctl_lock_unlock {
-+ /* user -> kernel */
-+ unsigned int handle;
-+
-+ /* kernel -> user */
-+ unsigned int addr;
-+};
-+
-+struct vmcs_sm_ioctl_lock_cache {
-+ /* user -> kernel */
-+ unsigned int handle;
-+ enum vmcs_sm_cache_e cached;
-+};
-+
-+struct vmcs_sm_ioctl_resize {
-+ /* user -> kernel */
-+ unsigned int handle;
-+ unsigned int new_size;
-+
-+ /* kernel -> user */
-+ unsigned int old_size;
-+};
-+
-+struct vmcs_sm_ioctl_map {
-+ /* user -> kernel */
-+ /* and kernel -> user */
-+ unsigned int pid;
-+ unsigned int handle;
-+ unsigned int addr;
-+
-+ /* kernel -> user */
-+ unsigned int size;
-+};
-+
-+struct vmcs_sm_ioctl_walk {
-+ /* user -> kernel */
-+ unsigned int pid;
-+};
-+
-+struct vmcs_sm_ioctl_chk {
-+ /* user -> kernel */
-+ unsigned int handle;
-+
-+ /* kernel -> user */
-+ unsigned int addr;
-+ unsigned int size;
-+ enum vmcs_sm_cache_e cache;
-+};
-+
-+struct vmcs_sm_ioctl_size {
-+ /* user -> kernel */
-+ unsigned int handle;
-+
-+ /* kernel -> user */
-+ unsigned int size;
-+};
-+
-+struct vmcs_sm_ioctl_cache {
-+ /* user -> kernel */
-+ unsigned int handle;
-+ unsigned int addr;
-+ unsigned int size;
-+};
-+
-+struct vmcs_sm_ioctl_clean_invalid {
-+ /* user -> kernel */
-+ struct {
-+ unsigned int cmd;
-+ unsigned int handle;
-+ unsigned int addr;
-+ unsigned int size;
-+ } s[8];
-+};
-+
-+/* IOCTL numbers */
-+#define VMCS_SM_IOCTL_MEM_ALLOC\
-+ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_ALLOC,\
-+ struct vmcs_sm_ioctl_alloc)
-+#define VMCS_SM_IOCTL_MEM_ALLOC_SHARE\
-+ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_ALLOC_SHARE,\
-+ struct vmcs_sm_ioctl_alloc_share)
-+#define VMCS_SM_IOCTL_MEM_LOCK\
-+ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_LOCK,\
-+ struct vmcs_sm_ioctl_lock_unlock)
-+#define VMCS_SM_IOCTL_MEM_LOCK_CACHE\
-+ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_LOCK_CACHE,\
-+ struct vmcs_sm_ioctl_lock_cache)
-+#define VMCS_SM_IOCTL_MEM_UNLOCK\
-+ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_UNLOCK,\
-+ struct vmcs_sm_ioctl_lock_unlock)
-+#define VMCS_SM_IOCTL_MEM_RESIZE\
-+ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_RESIZE,\
-+ struct vmcs_sm_ioctl_resize)
-+#define VMCS_SM_IOCTL_MEM_FREE\
-+ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_FREE,\
-+ struct vmcs_sm_ioctl_free)
-+#define VMCS_SM_IOCTL_MEM_FLUSH\
-+ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_FLUSH,\
-+ struct vmcs_sm_ioctl_cache)
-+#define VMCS_SM_IOCTL_MEM_INVALID\
-+ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_INVALID,\
-+ struct vmcs_sm_ioctl_cache)
-+#define VMCS_SM_IOCTL_MEM_CLEAN_INVALID\
-+ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_CLEAN_INVALID,\
-+ struct vmcs_sm_ioctl_clean_invalid)
-+
-+#define VMCS_SM_IOCTL_SIZE_USR_HDL\
-+ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_SIZE_USR_HANDLE,\
-+ struct vmcs_sm_ioctl_size)
-+#define VMCS_SM_IOCTL_CHK_USR_HDL\
-+ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_CHK_USR_HANDLE,\
-+ struct vmcs_sm_ioctl_chk)
-+
-+#define VMCS_SM_IOCTL_MAP_USR_HDL\
-+ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_MAPPED_USR_HANDLE,\
-+ struct vmcs_sm_ioctl_map)
-+#define VMCS_SM_IOCTL_MAP_USR_ADDRESS\
-+ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_MAPPED_USR_ADDRESS,\
-+ struct vmcs_sm_ioctl_map)
-+#define VMCS_SM_IOCTL_MAP_VC_HDL_FR_ADDR\
-+ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_MAPPED_VC_HDL_FROM_ADDR,\
-+ struct vmcs_sm_ioctl_map)
-+#define VMCS_SM_IOCTL_MAP_VC_HDL_FR_HDL\
-+ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_MAPPED_VC_HDL_FROM_HDL,\
-+ struct vmcs_sm_ioctl_map)
-+#define VMCS_SM_IOCTL_MAP_VC_ADDR_FR_HDL\
-+ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_MAPPED_VC_ADDR_FROM_HDL,\
-+ struct vmcs_sm_ioctl_map)
-+
-+#define VMCS_SM_IOCTL_VC_WALK_ALLOC\
-+ _IO(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_VC_WALK_ALLOC)
-+#define VMCS_SM_IOCTL_HOST_WALK_MAP\
-+ _IO(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_HOST_WALK_MAP)
-+#define VMCS_SM_IOCTL_HOST_WALK_PID_ALLOC\
-+ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_HOST_WALK_PID_ALLOC,\
-+ struct vmcs_sm_ioctl_walk)
-+#define VMCS_SM_IOCTL_HOST_WALK_PID_MAP\
-+ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_HOST_WALK_PID_MAP,\
-+ struct vmcs_sm_ioctl_walk)
-+
-+/* ---- Variable Externs ------------------------------------------------- */
-+
-+/* ---- Function Prototypes ---------------------------------------------- */
-+
-+#endif /* __VMCS_SM_IOCTL_H__INCLUDED__ */
diff --git a/target/linux/brcm2708/patches-4.4/0040-Add-SMI-driver.patch b/target/linux/brcm2708/patches-4.4/0040-Add-SMI-driver.patch
new file mode 100644
index 0000000000..61a942b97b
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0040-Add-SMI-driver.patch
@@ -0,0 +1,1930 @@
+From c5c6cdc2f3dc823bf7ac7e31709f192a783f7d56 Mon Sep 17 00:00:00 2001
+From: Luke Wren <wren6991@gmail.com>
+Date: Sat, 5 Sep 2015 01:14:45 +0100
+Subject: [PATCH 040/381] Add SMI driver
+
+Signed-off-by: Luke Wren <wren6991@gmail.com>
+---
+ .../bindings/misc/brcm,bcm2835-smi-dev.txt | 17 +
+ .../devicetree/bindings/misc/brcm,bcm2835-smi.txt | 48 +
+ drivers/char/broadcom/Kconfig | 8 +
+ drivers/char/broadcom/Makefile | 2 +-
+ drivers/char/broadcom/bcm2835_smi_dev.c | 402 +++++++++
+ drivers/misc/Kconfig | 8 +
+ drivers/misc/Makefile | 1 +
+ drivers/misc/bcm2835_smi.c | 985 +++++++++++++++++++++
+ include/linux/broadcom/bcm2835_smi.h | 391 ++++++++
+ 9 files changed, 1861 insertions(+), 1 deletion(-)
+ create mode 100644 Documentation/devicetree/bindings/misc/brcm,bcm2835-smi-dev.txt
+ create mode 100644 Documentation/devicetree/bindings/misc/brcm,bcm2835-smi.txt
+ create mode 100644 drivers/char/broadcom/bcm2835_smi_dev.c
+ create mode 100644 drivers/misc/bcm2835_smi.c
+ create mode 100644 include/linux/broadcom/bcm2835_smi.h
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/misc/brcm,bcm2835-smi-dev.txt
+@@ -0,0 +1,17 @@
++* Broadcom BCM2835 SMI character device driver.
++
++SMI or secondary memory interface is a peripheral specific to certain Broadcom
++SOCs, and is helpful for talking to things like parallel-interface displays
++and NAND flashes (in fact, most things with a parallel register interface).
++
++This driver adds a character device which provides a user-space interface to
++an instance of the SMI driver.
++
++Required properties:
++- compatible: "brcm,bcm2835-smi-dev"
++- smi_handle: a phandle to the smi node.
++
++Optional properties:
++- None.
++
++
+--- /dev/null
++++ b/Documentation/devicetree/bindings/misc/brcm,bcm2835-smi.txt
+@@ -0,0 +1,48 @@
++* Broadcom BCM2835 SMI driver.
++
++SMI or secondary memory interface is a peripheral specific to certain Broadcom
++SOCs, and is helpful for talking to things like parallel-interface displays
++and NAND flashes (in fact, most things with a parallel register interface).
++
++Required properties:
++- compatible: "brcm,bcm2835-smi"
++- reg: Should contain location and length of SMI registers and SMI clkman regs
++- interrupts: *the* SMI interrupt.
++- pinctrl-names: should be "default".
++- pinctrl-0: the phandle of the gpio pin node.
++- brcm,smi-clock-source: the clock source for clkman
++- brcm,smi-clock-divisor: the integer clock divisor for clkman
++- dmas: the dma controller phandle and the DREQ number (4 on a 2835)
++- dma-names: the name used by the driver to request its channel.
++ Should be "rx-tx".
++
++Optional properties:
++- None.
++
++Examples:
++
++8 data pin configuration:
++
++smi: smi@7e600000 {
++ compatible = "brcm,bcm2835-smi";
++ reg = <0x7e600000 0x44>, <0x7e1010b0 0x8>;
++ interrupts = <2 16>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&smi_pins>;
++ brcm,smi-clock-source = <6>;
++ brcm,smi-clock-divisor = <4>;
++ dmas = <&dma 4>;
++ dma-names = "rx-tx";
++
++ status = "okay";
++};
++
++smi_pins: smi_pins {
++ brcm,pins = <2 3 4 5 6 7 8 9 10 11 12 13 14 15>;
++ /* Alt 1: SMI */
++ brcm,function = <5 5 5 5 5 5 5 5 5 5 5 5 5 5>;
++ /* /CS, /WE and /OE are pulled high, as they are
++ generally active low signals */
++ brcm,pull = <2 2 2 2 2 2 0 0 0 0 0 0 0 0>;
++};
++
+--- a/drivers/char/broadcom/Kconfig
++++ b/drivers/char/broadcom/Kconfig
+@@ -41,3 +41,11 @@ config BCM2835_DEVGPIOMEM
+ on the 2835. Calling mmap(/dev/gpiomem) will map the GPIO
+ register page to the user's pointer.
+
++config BCM2835_SMI_DEV
++ tristate "Character device driver for BCM2835 Secondary Memory Interface"
++ depends on (MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835) && BCM2835_SMI
++ default m
++ help
++ This driver provides a character device interface (ioctl + read/write) to
++ Broadcom's Secondary Memory interface. The low-level functionality is provided
++ by the SMI driver itself.
+--- a/drivers/char/broadcom/Makefile
++++ b/drivers/char/broadcom/Makefile
+@@ -3,4 +3,4 @@ obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o
+ obj-$(CONFIG_BCM_VC_SM) += vc_sm/
+
+ obj-$(CONFIG_BCM2835_DEVGPIOMEM)+= bcm2835-gpiomem.o
+-
++obj-$(CONFIG_BCM2835_SMI_DEV) += bcm2835_smi_dev.o
+--- /dev/null
++++ b/drivers/char/broadcom/bcm2835_smi_dev.c
+@@ -0,0 +1,402 @@
++/**
++ * Character device driver for Broadcom Secondary Memory Interface
++ *
++ * Written by Luke Wren <luke@raspberrypi.org>
++ * Copyright (c) 2015, Raspberry Pi (Trading) Ltd.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/mm.h>
++#include <linux/pagemap.h>
++#include <linux/fs.h>
++#include <linux/cdev.h>
++#include <linux/fs.h>
++
++#include <linux/broadcom/bcm2835_smi.h>
++
++#define DEVICE_NAME "bcm2835-smi-dev"
++#define DRIVER_NAME "smi-dev-bcm2835"
++#define DEVICE_MINOR 0
++
++static struct cdev bcm2835_smi_cdev;
++static dev_t bcm2835_smi_devid;
++static struct class *bcm2835_smi_class;
++static struct device *bcm2835_smi_dev;
++
++struct bcm2835_smi_dev_instance {
++ struct device *dev;
++};
++
++static struct bcm2835_smi_instance *smi_inst;
++static struct bcm2835_smi_dev_instance *inst;
++
++static const char *const ioctl_names[] = {
++ "READ_SETTINGS",
++ "WRITE_SETTINGS",
++ "ADDRESS"
++};
++
++/****************************************************************************
++*
++* SMI chardev file ops
++*
++***************************************************************************/
++static long
++bcm2835_smi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
++{
++ long ret = 0;
++
++ dev_info(inst->dev, "serving ioctl...");
++
++ switch (cmd) {
++ case BCM2835_SMI_IOC_GET_SETTINGS:{
++ struct smi_settings *settings;
++
++ dev_info(inst->dev, "Reading SMI settings to user.");
++ settings = bcm2835_smi_get_settings_from_regs(smi_inst);
++ if (copy_to_user((void *)arg, settings,
++ sizeof(struct smi_settings)))
++ dev_err(inst->dev, "settings copy failed.");
++ break;
++ }
++ case BCM2835_SMI_IOC_WRITE_SETTINGS:{
++ struct smi_settings *settings;
++
++ dev_info(inst->dev, "Setting user's SMI settings.");
++ settings = bcm2835_smi_get_settings_from_regs(smi_inst);
++ if (copy_from_user(settings, (void *)arg,
++ sizeof(struct smi_settings)))
++ dev_err(inst->dev, "settings copy failed.");
++ else
++ bcm2835_smi_set_regs_from_settings(smi_inst);
++ break;
++ }
++ case BCM2835_SMI_IOC_ADDRESS:
++ dev_info(inst->dev, "SMI address set: 0x%02x", (int)arg);
++ bcm2835_smi_set_address(smi_inst, arg);
++ break;
++ default:
++ dev_err(inst->dev, "invalid ioctl cmd: %d", cmd);
++ ret = -ENOTTY;
++ break;
++ }
++
++ return ret;
++}
++
++static int bcm2835_smi_open(struct inode *inode, struct file *file)
++{
++ int dev = iminor(inode);
++
++ dev_dbg(inst->dev, "SMI device opened.");
++
++ if (dev != DEVICE_MINOR) {
++ dev_err(inst->dev,
++ "bcm2835_smi_release: Unknown minor device: %d",
++ dev);
++ return -ENXIO;
++ }
++
++ return 0;
++}
++
++static int bcm2835_smi_release(struct inode *inode, struct file *file)
++{
++ int dev = iminor(inode);
++
++ if (dev != DEVICE_MINOR) {
++ dev_err(inst->dev,
++ "bcm2835_smi_release: Unknown minor device %d", dev);
++ return -ENXIO;
++ }
++
++ return 0;
++}
++
++static ssize_t dma_bounce_user(
++ enum dma_transfer_direction dma_dir,
++ char __user *user_ptr,
++ size_t count,
++ struct bcm2835_smi_bounce_info *bounce)
++{
++ int chunk_size;
++ int chunk_no = 0;
++ int count_left = count;
++
++ while (count_left) {
++ int rv;
++ void *buf;
++
++ /* Wait for current chunk to complete: */
++ if (down_timeout(&bounce->callback_sem,
++ msecs_to_jiffies(1000))) {
++ dev_err(inst->dev, "DMA bounce timed out");
++ count -= (count_left);
++ break;
++ }
++
++ if (bounce->callback_sem.count >= DMA_BOUNCE_BUFFER_COUNT - 1)
++ dev_err(inst->dev, "WARNING: Ring buffer overflow");
++ chunk_size = count_left > DMA_BOUNCE_BUFFER_SIZE ?
++ DMA_BOUNCE_BUFFER_SIZE : count_left;
++ buf = bounce->buffer[chunk_no % DMA_BOUNCE_BUFFER_COUNT];
++ if (dma_dir == DMA_DEV_TO_MEM)
++ rv = copy_to_user(user_ptr, buf, chunk_size);
++ else
++ rv = copy_from_user(buf, user_ptr, chunk_size);
++ if (rv)
++ dev_err(inst->dev, "copy_*_user() failed!: %d", rv);
++ user_ptr += chunk_size;
++ count_left -= chunk_size;
++ chunk_no++;
++ }
++ return count;
++}
++
++static ssize_t
++bcm2835_read_file(struct file *f, char __user *user_ptr,
++ size_t count, loff_t *offs)
++{
++ int odd_bytes;
++
++ dev_dbg(inst->dev, "User reading %d bytes from SMI.", count);
++ /* We don't want to DMA a number of bytes % 4 != 0 (32 bit FIFO) */
++ if (count > DMA_THRESHOLD_BYTES)
++ odd_bytes = count & 0x3;
++ else
++ odd_bytes = count;
++ count -= odd_bytes;
++ if (count) {
++ struct bcm2835_smi_bounce_info *bounce;
++
++ count = bcm2835_smi_user_dma(smi_inst,
++ DMA_DEV_TO_MEM, user_ptr, count,
++ &bounce);
++ if (count)
++ count = dma_bounce_user(DMA_DEV_TO_MEM, user_ptr,
++ count, bounce);
++ }
++ if (odd_bytes) {
++ /* Read from FIFO directly if not using DMA */
++ uint8_t buf[DMA_THRESHOLD_BYTES];
++
++ bcm2835_smi_read_buf(smi_inst, buf, odd_bytes);
++ if (copy_to_user(user_ptr, buf, odd_bytes))
++ dev_err(inst->dev, "copy_to_user() failed.");
++ count += odd_bytes;
++
++ }
++ return count;
++}
++
++static ssize_t
++bcm2835_write_file(struct file *f, const char __user *user_ptr,
++ size_t count, loff_t *offs)
++{
++ int odd_bytes;
++
++ dev_dbg(inst->dev, "User writing %d bytes to SMI.", count);
++ if (count > DMA_THRESHOLD_BYTES)
++ odd_bytes = count & 0x3;
++ else
++ odd_bytes = count;
++ count -= odd_bytes;
++ if (count) {
++ struct bcm2835_smi_bounce_info *bounce;
++
++ count = bcm2835_smi_user_dma(smi_inst,
++ DMA_MEM_TO_DEV, (char __user *)user_ptr, count,
++ &bounce);
++ if (count)
++ count = dma_bounce_user(DMA_MEM_TO_DEV,
++ (char __user *)user_ptr,
++ count, bounce);
++ }
++ if (odd_bytes) {
++ uint8_t buf[DMA_THRESHOLD_BYTES];
++
++ if (copy_from_user(buf, user_ptr, odd_bytes))
++ dev_err(inst->dev, "copy_from_user() failed.");
++ else
++ bcm2835_smi_write_buf(smi_inst, buf, odd_bytes);
++ count += odd_bytes;
++ }
++ return count;
++}
++
++static const struct file_operations
++bcm2835_smi_fops = {
++ .owner = THIS_MODULE,
++ .unlocked_ioctl = bcm2835_smi_ioctl,
++ .open = bcm2835_smi_open,
++ .release = bcm2835_smi_release,
++ .read = bcm2835_read_file,
++ .write = bcm2835_write_file,
++};
++
++
++/****************************************************************************
++*
++* bcm2835_smi_probe - called when the driver is loaded.
++*
++***************************************************************************/
++
++static int bcm2835_smi_dev_probe(struct platform_device *pdev)
++{
++ int err;
++ void *ptr_err;
++ struct device *dev = &pdev->dev;
++ struct device_node *node = dev->of_node, *smi_node;
++
++ if (!node) {
++ dev_err(dev, "No device tree node supplied!");
++ return -EINVAL;
++ }
++
++ smi_node = of_parse_phandle(node, "smi_handle", 0);
++
++ if (!smi_node) {
++ dev_err(dev, "No such property: smi_handle");
++ return -ENXIO;
++ }
++
++ smi_inst = bcm2835_smi_get(smi_node);
++
++ if (!smi_inst)
++ return -EPROBE_DEFER;
++
++ /* Allocate buffers and instance data */
++
++ inst = devm_kzalloc(dev, sizeof(*inst), GFP_KERNEL);
++
++ if (!inst)
++ return -ENOMEM;
++
++ inst->dev = dev;
++
++ /* Create character device entries */
++
++ err = alloc_chrdev_region(&bcm2835_smi_devid,
++ DEVICE_MINOR, 1, DEVICE_NAME);
++ if (err != 0) {
++ dev_err(inst->dev, "unable to allocate device number");
++ return -ENOMEM;
++ }
++ cdev_init(&bcm2835_smi_cdev, &bcm2835_smi_fops);
++ bcm2835_smi_cdev.owner = THIS_MODULE;
++ err = cdev_add(&bcm2835_smi_cdev, bcm2835_smi_devid, 1);
++ if (err != 0) {
++ dev_err(inst->dev, "unable to register device");
++ err = -ENOMEM;
++ goto failed_cdev_add;
++ }
++
++ /* Create sysfs entries */
++
++ bcm2835_smi_class = class_create(THIS_MODULE, DEVICE_NAME);
++ ptr_err = bcm2835_smi_class;
++ if (IS_ERR(ptr_err))
++ goto failed_class_create;
++
++ bcm2835_smi_dev = device_create(bcm2835_smi_class, NULL,
++ bcm2835_smi_devid, NULL,
++ "smi");
++ ptr_err = bcm2835_smi_dev;
++ if (IS_ERR(ptr_err))
++ goto failed_device_create;
++
++ dev_info(inst->dev, "initialised");
++
++ return 0;
++
++failed_device_create:
++ class_destroy(bcm2835_smi_class);
++failed_class_create:
++ cdev_del(&bcm2835_smi_cdev);
++ err = PTR_ERR(ptr_err);
++failed_cdev_add:
++ unregister_chrdev_region(bcm2835_smi_devid, 1);
++ dev_err(dev, "could not load bcm2835_smi_dev");
++ return err;
++}
++
++/****************************************************************************
++*
++* bcm2835_smi_remove - called when the driver is unloaded.
++*
++***************************************************************************/
++
++static int bcm2835_smi_dev_remove(struct platform_device *pdev)
++{
++ device_destroy(bcm2835_smi_class, bcm2835_smi_devid);
++ class_destroy(bcm2835_smi_class);
++ cdev_del(&bcm2835_smi_cdev);
++ unregister_chrdev_region(bcm2835_smi_devid, 1);
++
++ dev_info(inst->dev, "SMI character dev removed - OK");
++ return 0;
++}
++
++/****************************************************************************
++*
++* Register the driver with device tree
++*
++***************************************************************************/
++
++static const struct of_device_id bcm2835_smi_dev_of_match[] = {
++ {.compatible = "brcm,bcm2835-smi-dev",},
++ { /* sentinel */ },
++};
++
++MODULE_DEVICE_TABLE(of, bcm2835_smi_dev_of_match);
++
++static struct platform_driver bcm2835_smi_dev_driver = {
++ .probe = bcm2835_smi_dev_probe,
++ .remove = bcm2835_smi_dev_remove,
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ .of_match_table = bcm2835_smi_dev_of_match,
++ },
++};
++
++module_platform_driver(bcm2835_smi_dev_driver);
++
++MODULE_ALIAS("platform:smi-dev-bcm2835");
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION(
++ "Character device driver for BCM2835's secondary memory interface");
++MODULE_AUTHOR("Luke Wren <luke@raspberrypi.org>");
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -10,6 +10,14 @@ config SENSORS_LIS3LV02D
+ select INPUT_POLLDEV
+ default n
+
++config BCM2835_SMI
++ tristate "Broadcom 283x Secondary Memory Interface driver"
++ depends on MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835
++ default m
++ help
++ Driver for enabling and using Broadcom's Secondary/Slow Memory Interface.
++ Appears as /dev/bcm2835_smi. For ioctl interface see drivers/misc/bcm2835_smi.h
++
+ config AD525X_DPOT
+ tristate "Analog Devices Digital Potentiometers"
+ depends on (I2C || SPI) && SYSFS
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -9,6 +9,7 @@ obj-$(CONFIG_AD525X_DPOT_SPI) += ad525x_
+ obj-$(CONFIG_INTEL_MID_PTI) += pti.o
+ obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
+ obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o
++obj-$(CONFIG_BCM2835_SMI) += bcm2835_smi.o
+ obj-$(CONFIG_BMP085) += bmp085.o
+ obj-$(CONFIG_BMP085_I2C) += bmp085-i2c.o
+ obj-$(CONFIG_BMP085_SPI) += bmp085-spi.o
+--- /dev/null
++++ b/drivers/misc/bcm2835_smi.c
+@@ -0,0 +1,985 @@
++/**
++ * Broadcom Secondary Memory Interface driver
++ *
++ * Written by Luke Wren <luke@raspberrypi.org>
++ * Copyright (c) 2015, Raspberry Pi (Trading) Ltd.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/of_address.h>
++#include <linux/of_platform.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/pagemap.h>
++#include <linux/dma-mapping.h>
++#include <linux/dmaengine.h>
++#include <linux/semaphore.h>
++#include <linux/spinlock.h>
++#include <linux/io.h>
++
++#define BCM2835_SMI_IMPLEMENTATION
++#include <linux/broadcom/bcm2835_smi.h>
++
++#define DRIVER_NAME "smi-bcm2835"
++
++#define N_PAGES_FROM_BYTES(n) ((n + PAGE_SIZE-1) / PAGE_SIZE)
++
++#define DMA_WRITE_TO_MEM true
++#define DMA_READ_FROM_MEM false
++
++struct bcm2835_smi_instance {
++ struct device *dev;
++ struct smi_settings settings;
++ __iomem void *smi_regs_ptr, *cm_smi_regs_ptr;
++ dma_addr_t smi_regs_busaddr;
++
++ struct dma_chan *dma_chan;
++ struct dma_slave_config dma_config;
++
++ struct bcm2835_smi_bounce_info bounce;
++
++ struct scatterlist buffer_sgl;
++
++ int clock_source;
++ int clock_divisor;
++
++ /* Sometimes we are called into in an atomic context (e.g. by
++ JFFS2 + MTD) so we can't use a mutex */
++ spinlock_t transaction_lock;
++};
++
++/****************************************************************************
++*
++* SMI clock manager setup
++*
++***************************************************************************/
++
++static inline void write_smi_cm_reg(struct bcm2835_smi_instance *inst,
++ u32 val, unsigned reg)
++{
++ writel(CM_PWD | val, inst->cm_smi_regs_ptr + reg);
++}
++
++static inline u32 read_smi_cm_reg(struct bcm2835_smi_instance *inst,
++ unsigned reg)
++{
++ return readl(inst->cm_smi_regs_ptr + reg);
++}
++
++static void smi_setup_clock(struct bcm2835_smi_instance *inst)
++{
++ dev_dbg(inst->dev, "Setting up clock...");
++ /* Disable SMI clock and wait for it to stop. */
++ write_smi_cm_reg(inst, 0, CM_SMI_CTL);
++ while (read_smi_cm_reg(inst, CM_SMI_CTL) & CM_SMI_CTL_BUSY)
++ ;
++
++ write_smi_cm_reg(inst, (inst->clock_divisor << CM_SMI_DIV_DIVI_OFFS),
++ CM_SMI_DIV);
++ write_smi_cm_reg(inst, (inst->clock_source << CM_SMI_CTL_SRC_OFFS),
++ CM_SMI_CTL);
++
++ /* Enable the clock */
++ write_smi_cm_reg(inst, (inst->clock_source << CM_SMI_CTL_SRC_OFFS) |
++ CM_SMI_CTL_ENAB, CM_SMI_CTL);
++}
++
++/****************************************************************************
++*
++* SMI peripheral setup
++*
++***************************************************************************/
++
++static inline void write_smi_reg(struct bcm2835_smi_instance *inst,
++ u32 val, unsigned reg)
++{
++ writel(val, inst->smi_regs_ptr + reg);
++}
++
++static inline u32 read_smi_reg(struct bcm2835_smi_instance *inst, unsigned reg)
++{
++ return readl(inst->smi_regs_ptr + reg);
++}
++
++/* Token-paste macro for e.g SMIDSR_RSTROBE -> value of SMIDSR_RSTROBE_MASK */
++#define _CONCAT(x, y) x##y
++#define CONCAT(x, y) _CONCAT(x, y)
++
++#define SET_BIT_FIELD(dest, field, bits) ((dest) = \
++ ((dest) & ~CONCAT(field, _MASK)) | (((bits) << CONCAT(field, _OFFS))& \
++ CONCAT(field, _MASK)))
++#define GET_BIT_FIELD(src, field) (((src) & \
++ CONCAT(field, _MASK)) >> CONCAT(field, _OFFS))
++
++static void smi_dump_context_labelled(struct bcm2835_smi_instance *inst,
++ const char *label)
++{
++ dev_err(inst->dev, "SMI context dump: %s", label);
++ dev_err(inst->dev, "SMICS: 0x%08x", read_smi_reg(inst, SMICS));
++ dev_err(inst->dev, "SMIL: 0x%08x", read_smi_reg(inst, SMIL));
++ dev_err(inst->dev, "SMIDSR: 0x%08x", read_smi_reg(inst, SMIDSR0));
++ dev_err(inst->dev, "SMIDSW: 0x%08x", read_smi_reg(inst, SMIDSW0));
++ dev_err(inst->dev, "SMIDC: 0x%08x", read_smi_reg(inst, SMIDC));
++ dev_err(inst->dev, "SMIFD: 0x%08x", read_smi_reg(inst, SMIFD));
++ dev_err(inst->dev, " ");
++}
++
++static inline void smi_dump_context(struct bcm2835_smi_instance *inst)
++{
++ smi_dump_context_labelled(inst, "");
++}
++
++static void smi_get_default_settings(struct bcm2835_smi_instance *inst)
++{
++ struct smi_settings *settings = &inst->settings;
++
++ settings->data_width = SMI_WIDTH_16BIT;
++ settings->pack_data = true;
++
++ settings->read_setup_time = 1;
++ settings->read_hold_time = 1;
++ settings->read_pace_time = 1;
++ settings->read_strobe_time = 3;
++
++ settings->write_setup_time = settings->read_setup_time;
++ settings->write_hold_time = settings->read_hold_time;
++ settings->write_pace_time = settings->read_pace_time;
++ settings->write_strobe_time = settings->read_strobe_time;
++
++ settings->dma_enable = true;
++ settings->dma_passthrough_enable = false;
++ settings->dma_read_thresh = 0x01;
++ settings->dma_write_thresh = 0x3f;
++ settings->dma_panic_read_thresh = 0x20;
++ settings->dma_panic_write_thresh = 0x20;
++}
++
++void bcm2835_smi_set_regs_from_settings(struct bcm2835_smi_instance *inst)
++{
++ struct smi_settings *settings = &inst->settings;
++ int smidsr_temp = 0, smidsw_temp = 0, smics_temp,
++ smidcs_temp, smidc_temp = 0;
++
++ spin_lock(&inst->transaction_lock);
++
++ /* temporarily disable the peripheral: */
++ smics_temp = read_smi_reg(inst, SMICS);
++ write_smi_reg(inst, 0, SMICS);
++ smidcs_temp = read_smi_reg(inst, SMIDCS);
++ write_smi_reg(inst, 0, SMIDCS);
++
++ if (settings->pack_data)
++ smics_temp |= SMICS_PXLDAT;
++ else
++ smics_temp &= ~SMICS_PXLDAT;
++
++ SET_BIT_FIELD(smidsr_temp, SMIDSR_RWIDTH, settings->data_width);
++ SET_BIT_FIELD(smidsr_temp, SMIDSR_RSETUP, settings->read_setup_time);
++ SET_BIT_FIELD(smidsr_temp, SMIDSR_RHOLD, settings->read_hold_time);
++ SET_BIT_FIELD(smidsr_temp, SMIDSR_RPACE, settings->read_pace_time);
++ SET_BIT_FIELD(smidsr_temp, SMIDSR_RSTROBE, settings->read_strobe_time);
++ write_smi_reg(inst, smidsr_temp, SMIDSR0);
++
++ SET_BIT_FIELD(smidsw_temp, SMIDSW_WWIDTH, settings->data_width);
++ if (settings->data_width == SMI_WIDTH_8BIT)
++ smidsw_temp |= SMIDSW_WSWAP;
++ else
++ smidsw_temp &= ~SMIDSW_WSWAP;
++ SET_BIT_FIELD(smidsw_temp, SMIDSW_WSETUP, settings->write_setup_time);
++ SET_BIT_FIELD(smidsw_temp, SMIDSW_WHOLD, settings->write_hold_time);
++ SET_BIT_FIELD(smidsw_temp, SMIDSW_WPACE, settings->write_pace_time);
++ SET_BIT_FIELD(smidsw_temp, SMIDSW_WSTROBE,
++ settings->write_strobe_time);
++ write_smi_reg(inst, smidsw_temp, SMIDSW0);
++
++ SET_BIT_FIELD(smidc_temp, SMIDC_REQR, settings->dma_read_thresh);
++ SET_BIT_FIELD(smidc_temp, SMIDC_REQW, settings->dma_write_thresh);
++ SET_BIT_FIELD(smidc_temp, SMIDC_PANICR,
++ settings->dma_panic_read_thresh);
++ SET_BIT_FIELD(smidc_temp, SMIDC_PANICW,
++ settings->dma_panic_write_thresh);
++ if (settings->dma_passthrough_enable) {
++ smidc_temp |= SMIDC_DMAP;
++ smidsr_temp |= SMIDSR_RDREQ;
++ write_smi_reg(inst, smidsr_temp, SMIDSR0);
++ smidsw_temp |= SMIDSW_WDREQ;
++ write_smi_reg(inst, smidsw_temp, SMIDSW0);
++ } else
++ smidc_temp &= ~SMIDC_DMAP;
++ if (settings->dma_enable)
++ smidc_temp |= SMIDC_DMAEN;
++ else
++ smidc_temp &= ~SMIDC_DMAEN;
++
++ write_smi_reg(inst, smidc_temp, SMIDC);
++
++ /* re-enable (if was previously enabled) */
++ write_smi_reg(inst, smics_temp, SMICS);
++ write_smi_reg(inst, smidcs_temp, SMIDCS);
++
++ spin_unlock(&inst->transaction_lock);
++}
++EXPORT_SYMBOL(bcm2835_smi_set_regs_from_settings);
++
++struct smi_settings *bcm2835_smi_get_settings_from_regs
++ (struct bcm2835_smi_instance *inst)
++{
++ struct smi_settings *settings = &inst->settings;
++ int smidsr, smidsw, smidc;
++
++ spin_lock(&inst->transaction_lock);
++
++ smidsr = read_smi_reg(inst, SMIDSR0);
++ smidsw = read_smi_reg(inst, SMIDSW0);
++ smidc = read_smi_reg(inst, SMIDC);
++
++ settings->pack_data = (read_smi_reg(inst, SMICS) & SMICS_PXLDAT) ?
++ true : false;
++
++ settings->data_width = GET_BIT_FIELD(smidsr, SMIDSR_RWIDTH);
++ settings->read_setup_time = GET_BIT_FIELD(smidsr, SMIDSR_RSETUP);
++ settings->read_hold_time = GET_BIT_FIELD(smidsr, SMIDSR_RHOLD);
++ settings->read_pace_time = GET_BIT_FIELD(smidsr, SMIDSR_RPACE);
++ settings->read_strobe_time = GET_BIT_FIELD(smidsr, SMIDSR_RSTROBE);
++
++ settings->write_setup_time = GET_BIT_FIELD(smidsw, SMIDSW_WSETUP);
++ settings->write_hold_time = GET_BIT_FIELD(smidsw, SMIDSW_WHOLD);
++ settings->write_pace_time = GET_BIT_FIELD(smidsw, SMIDSW_WPACE);
++ settings->write_strobe_time = GET_BIT_FIELD(smidsw, SMIDSW_WSTROBE);
++
++ settings->dma_read_thresh = GET_BIT_FIELD(smidc, SMIDC_REQR);
++ settings->dma_write_thresh = GET_BIT_FIELD(smidc, SMIDC_REQW);
++ settings->dma_panic_read_thresh = GET_BIT_FIELD(smidc, SMIDC_PANICR);
++ settings->dma_panic_write_thresh = GET_BIT_FIELD(smidc, SMIDC_PANICW);
++ settings->dma_passthrough_enable = (smidc & SMIDC_DMAP) ? true : false;
++ settings->dma_enable = (smidc & SMIDC_DMAEN) ? true : false;
++
++ spin_unlock(&inst->transaction_lock);
++
++ return settings;
++}
++EXPORT_SYMBOL(bcm2835_smi_get_settings_from_regs);
++
++static inline void smi_set_address(struct bcm2835_smi_instance *inst,
++ unsigned int address)
++{
++ int smia_temp = 0, smida_temp = 0;
++
++ SET_BIT_FIELD(smia_temp, SMIA_ADDR, address);
++ SET_BIT_FIELD(smida_temp, SMIDA_ADDR, address);
++
++ /* Write to both address registers - user doesn't care whether we're
++ doing programmed or direct transfers. */
++ write_smi_reg(inst, smia_temp, SMIA);
++ write_smi_reg(inst, smida_temp, SMIDA);
++}
++
++static void smi_setup_regs(struct bcm2835_smi_instance *inst)
++{
++
++ dev_dbg(inst->dev, "Initialising SMI registers...");
++ /* Disable the peripheral if already enabled */
++ write_smi_reg(inst, 0, SMICS);
++ write_smi_reg(inst, 0, SMIDCS);
++
++ smi_get_default_settings(inst);
++ bcm2835_smi_set_regs_from_settings(inst);
++ smi_set_address(inst, 0);
++
++ write_smi_reg(inst, read_smi_reg(inst, SMICS) | SMICS_ENABLE, SMICS);
++ write_smi_reg(inst, read_smi_reg(inst, SMIDCS) | SMIDCS_ENABLE,
++ SMIDCS);
++}
++
++/****************************************************************************
++*
++* Low-level SMI access functions
++* Other modules should use the exported higher-level functions e.g.
++* bcm2835_smi_write_buf() unless they have a good reason to use these
++*
++***************************************************************************/
++
++static inline uint32_t smi_read_single_word(struct bcm2835_smi_instance *inst)
++{
++ int timeout = 0;
++
++ write_smi_reg(inst, SMIDCS_ENABLE, SMIDCS);
++ write_smi_reg(inst, SMIDCS_ENABLE | SMIDCS_START, SMIDCS);
++ /* Make sure things happen in the right order...*/
++ mb();
++ while (!(read_smi_reg(inst, SMIDCS) & SMIDCS_DONE) &&
++ ++timeout < 10000)
++ ;
++ if (timeout < 10000)
++ return read_smi_reg(inst, SMIDD);
++
++ dev_err(inst->dev,
++ "SMI direct read timed out (is the clock set up correctly?)");
++ return 0;
++}
++
++static inline void smi_write_single_word(struct bcm2835_smi_instance *inst,
++ uint32_t data)
++{
++ int timeout = 0;
++
++ write_smi_reg(inst, SMIDCS_ENABLE | SMIDCS_WRITE, SMIDCS);
++ write_smi_reg(inst, data, SMIDD);
++ write_smi_reg(inst, SMIDCS_ENABLE | SMIDCS_WRITE | SMIDCS_START,
++ SMIDCS);
++
++ while (!(read_smi_reg(inst, SMIDCS) & SMIDCS_DONE) &&
++ ++timeout < 10000)
++ ;
++ if (timeout >= 10000)
++ dev_err(inst->dev,
++ "SMI direct write timed out (is the clock set up correctly?)");
++}
++
++/* Initiates a programmed read into the read FIFO. It is up to the caller to
++ * read data from the FIFO - either via paced DMA transfer,
++ * or polling SMICS_RXD to check whether data is available.
++ * SMICS_ACTIVE will go low upon completion. */
++static void smi_init_programmed_read(struct bcm2835_smi_instance *inst,
++ int num_transfers)
++{
++ int smics_temp;
++
++ /* Disable the peripheral: */
++ smics_temp = read_smi_reg(inst, SMICS) & ~(SMICS_ENABLE | SMICS_WRITE);
++ write_smi_reg(inst, smics_temp, SMICS);
++ while (read_smi_reg(inst, SMICS) & SMICS_ENABLE)
++ ;
++
++ /* Program the transfer count: */
++ write_smi_reg(inst, num_transfers, SMIL);
++
++ /* re-enable and start: */
++ smics_temp |= SMICS_ENABLE;
++ write_smi_reg(inst, smics_temp, SMICS);
++ smics_temp |= SMICS_CLEAR;
++ /* Just to be certain: */
++ mb();
++ while (read_smi_reg(inst, SMICS) & SMICS_ACTIVE)
++ ;
++ write_smi_reg(inst, smics_temp, SMICS);
++ smics_temp |= SMICS_START;
++ write_smi_reg(inst, smics_temp, SMICS);
++}
++
++/* Initiates a programmed write sequence, using data from the write FIFO.
++ * It is up to the caller to initiate a DMA transfer before calling,
++ * or use another method to keep the write FIFO topped up.
++ * SMICS_ACTIVE will go low upon completion.
++ */
++static void smi_init_programmed_write(struct bcm2835_smi_instance *inst,
++ int num_transfers)
++{
++ int smics_temp;
++
++ /* Disable the peripheral: */
++ smics_temp = read_smi_reg(inst, SMICS) & ~SMICS_ENABLE;
++ write_smi_reg(inst, smics_temp, SMICS);
++ while (read_smi_reg(inst, SMICS) & SMICS_ENABLE)
++ ;
++
++ /* Program the transfer count: */
++ write_smi_reg(inst, num_transfers, SMIL);
++
++ /* setup, re-enable and start: */
++ smics_temp |= SMICS_WRITE | SMICS_ENABLE;
++ write_smi_reg(inst, smics_temp, SMICS);
++ smics_temp |= SMICS_START;
++ write_smi_reg(inst, smics_temp, SMICS);
++}
++
++/* Initiate a read and then poll FIFO for data, reading out as it appears. */
++static void smi_read_fifo(struct bcm2835_smi_instance *inst,
++ uint32_t *dest, int n_bytes)
++{
++ if (read_smi_reg(inst, SMICS) & SMICS_RXD) {
++ smi_dump_context_labelled(inst,
++ "WARNING: read FIFO not empty at start of read call.");
++ while (read_smi_reg(inst, SMICS))
++ ;
++ }
++
++ /* Dispatch the read: */
++ if (inst->settings.data_width == SMI_WIDTH_8BIT)
++ smi_init_programmed_read(inst, n_bytes);
++ else if (inst->settings.data_width == SMI_WIDTH_16BIT)
++ smi_init_programmed_read(inst, n_bytes / 2);
++ else {
++ dev_err(inst->dev, "Unsupported data width for read.");
++ return;
++ }
++
++ /* Poll FIFO to keep it empty */
++ while (!(read_smi_reg(inst, SMICS) & SMICS_DONE))
++ if (read_smi_reg(inst, SMICS) & SMICS_RXD)
++ *dest++ = read_smi_reg(inst, SMID);
++
++ /* Ensure that the FIFO is emptied */
++ if (read_smi_reg(inst, SMICS) & SMICS_RXD) {
++ int fifo_count;
++
++ fifo_count = GET_BIT_FIELD(read_smi_reg(inst, SMIFD),
++ SMIFD_FCNT);
++ while (fifo_count--)
++ *dest++ = read_smi_reg(inst, SMID);
++ }
++
++ if (!(read_smi_reg(inst, SMICS) & SMICS_DONE))
++ smi_dump_context_labelled(inst,
++ "WARNING: transaction finished but done bit not set.");
++
++ if (read_smi_reg(inst, SMICS) & SMICS_RXD)
++ smi_dump_context_labelled(inst,
++ "WARNING: read FIFO not empty at end of read call.");
++
++}
++
++/* Initiate a write, and then keep the FIFO topped up. */
++static void smi_write_fifo(struct bcm2835_smi_instance *inst,
++ uint32_t *src, int n_bytes)
++{
++ int i, timeout = 0;
++
++ /* Empty FIFOs if not already so */
++ if (!(read_smi_reg(inst, SMICS) & SMICS_TXE)) {
++ smi_dump_context_labelled(inst,
++ "WARNING: write fifo not empty at start of write call.");
++ write_smi_reg(inst, read_smi_reg(inst, SMICS) | SMICS_CLEAR,
++ SMICS);
++ }
++
++ /* Initiate the transfer */
++ if (inst->settings.data_width == SMI_WIDTH_8BIT)
++ smi_init_programmed_write(inst, n_bytes);
++ else if (inst->settings.data_width == SMI_WIDTH_16BIT)
++ smi_init_programmed_write(inst, n_bytes / 2);
++ else {
++ dev_err(inst->dev, "Unsupported data width for write.");
++ return;
++ }
++ /* Fill the FIFO: */
++ for (i = 0; i < (n_bytes - 1) / 4 + 1; ++i) {
++ while (!(read_smi_reg(inst, SMICS) & SMICS_TXD))
++ ;
++ write_smi_reg(inst, *src++, SMID);
++ }
++ /* Busy wait... */
++ while (!(read_smi_reg(inst, SMICS) & SMICS_DONE) && ++timeout <
++ 1000000)
++ ;
++ if (timeout >= 1000000)
++ smi_dump_context_labelled(inst,
++ "Timed out on write operation!");
++ if (!(read_smi_reg(inst, SMICS) & SMICS_TXE))
++ smi_dump_context_labelled(inst,
++ "WARNING: FIFO not empty at end of write operation.");
++}
++
++/****************************************************************************
++*
++* SMI DMA operations
++*
++***************************************************************************/
++
++/* Disable SMI and put it into the correct direction before doing DMA setup.
++ Stops spurious DREQs during setup. Peripheral is re-enabled by init_*() */
++static void smi_disable(struct bcm2835_smi_instance *inst,
++ enum dma_transfer_direction direction)
++{
++ int smics_temp = read_smi_reg(inst, SMICS) & ~SMICS_ENABLE;
++
++ if (direction == DMA_DEV_TO_MEM)
++ smics_temp &= ~SMICS_WRITE;
++ else
++ smics_temp |= SMICS_WRITE;
++ write_smi_reg(inst, smics_temp, SMICS);
++ while (read_smi_reg(inst, SMICS) & SMICS_ACTIVE)
++ ;
++}
++
++static struct scatterlist *smi_scatterlist_from_buffer(
++ struct bcm2835_smi_instance *inst,
++ dma_addr_t buf,
++ size_t len,
++ struct scatterlist *sg)
++{
++ sg_init_table(sg, 1);
++ sg_dma_address(sg) = buf;
++ sg_dma_len(sg) = len;
++ return sg;
++}
++
++static void smi_dma_callback_user_copy(void *param)
++{
++ /* Notify the bottom half that a chunk is ready for user copy */
++ struct bcm2835_smi_instance *inst =
++ (struct bcm2835_smi_instance *)param;
++
++ up(&inst->bounce.callback_sem);
++}
++
++/* Creates a descriptor, assigns the given callback, and submits the
++ descriptor to dmaengine. Does not block - can queue up multiple
++ descriptors and then wait for them all to complete.
++ sg_len is the number of control blocks, NOT the number of bytes.
++ dir can be DMA_MEM_TO_DEV or DMA_DEV_TO_MEM.
++ callback can be NULL - in this case it is not called. */
++static inline struct dma_async_tx_descriptor *smi_dma_submit_sgl(
++ struct bcm2835_smi_instance *inst,
++ struct scatterlist *sgl,
++ size_t sg_len,
++ enum dma_transfer_direction dir,
++ dma_async_tx_callback callback)
++{
++ struct dma_async_tx_descriptor *desc;
++
++ desc = dmaengine_prep_slave_sg(inst->dma_chan,
++ sgl,
++ sg_len,
++ dir,
++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK |
++ DMA_PREP_FENCE);
++ if (!desc) {
++ dev_err(inst->dev, "read_sgl: dma slave preparation failed!");
++ write_smi_reg(inst, read_smi_reg(inst, SMICS) & ~SMICS_ACTIVE,
++ SMICS);
++ while (read_smi_reg(inst, SMICS) & SMICS_ACTIVE)
++ cpu_relax();
++ write_smi_reg(inst, read_smi_reg(inst, SMICS) | SMICS_ACTIVE,
++ SMICS);
++ return NULL;
++ }
++ desc->callback = callback;
++ desc->callback_param = inst;
++ if (dmaengine_submit(desc) < 0)
++ return NULL;
++ return desc;
++}
++
++/* NB this function blocks until the transfer is complete */
++static void
++smi_dma_read_sgl(struct bcm2835_smi_instance *inst,
++ struct scatterlist *sgl, size_t sg_len, size_t n_bytes)
++{
++ struct dma_async_tx_descriptor *desc;
++
++ /* Disable SMI and set to read before dispatching DMA - if SMI is in
++ * write mode and TX fifo is empty, it will generate a DREQ which may
++ * cause the read DMA to complete before the SMI read command is even
++ * dispatched! We want to dispatch DMA before SMI read so that reading
++ * is gapless, for logic analyser.
++ */
++
++ smi_disable(inst, DMA_DEV_TO_MEM);
++
++ desc = smi_dma_submit_sgl(inst, sgl, sg_len, DMA_DEV_TO_MEM, NULL);
++ dma_async_issue_pending(inst->dma_chan);
++
++ if (inst->settings.data_width == SMI_WIDTH_8BIT)
++ smi_init_programmed_read(inst, n_bytes);
++ else
++ smi_init_programmed_read(inst, n_bytes / 2);
++
++ if (dma_wait_for_async_tx(desc) == DMA_ERROR)
++ smi_dump_context_labelled(inst, "DMA timeout!");
++}
++
++static void
++smi_dma_write_sgl(struct bcm2835_smi_instance *inst,
++ struct scatterlist *sgl, size_t sg_len, size_t n_bytes)
++{
++ struct dma_async_tx_descriptor *desc;
++
++ if (inst->settings.data_width == SMI_WIDTH_8BIT)
++ smi_init_programmed_write(inst, n_bytes);
++ else
++ smi_init_programmed_write(inst, n_bytes / 2);
++
++ desc = smi_dma_submit_sgl(inst, sgl, sg_len, DMA_MEM_TO_DEV, NULL);
++ dma_async_issue_pending(inst->dma_chan);
++
++ if (dma_wait_for_async_tx(desc) == DMA_ERROR)
++ smi_dump_context_labelled(inst, "DMA timeout!");
++ else
++ /* Wait for SMI to finish our writes */
++ while (!(read_smi_reg(inst, SMICS) & SMICS_DONE))
++ cpu_relax();
++}
++
++ssize_t bcm2835_smi_user_dma(
++ struct bcm2835_smi_instance *inst,
++ enum dma_transfer_direction dma_dir,
++ char __user *user_ptr, size_t count,
++ struct bcm2835_smi_bounce_info **bounce)
++{
++ int chunk_no = 0, chunk_size, count_left = count;
++ struct scatterlist *sgl;
++ void (*init_trans_func)(struct bcm2835_smi_instance *, int);
++
++ spin_lock(&inst->transaction_lock);
++
++ if (dma_dir == DMA_DEV_TO_MEM)
++ init_trans_func = smi_init_programmed_read;
++ else
++ init_trans_func = smi_init_programmed_write;
++
++ smi_disable(inst, dma_dir);
++
++ sema_init(&inst->bounce.callback_sem, 0);
++ if (bounce)
++ *bounce = &inst->bounce;
++ while (count_left) {
++ chunk_size = count_left > DMA_BOUNCE_BUFFER_SIZE ?
++ DMA_BOUNCE_BUFFER_SIZE : count_left;
++ if (chunk_size == DMA_BOUNCE_BUFFER_SIZE) {
++ sgl =
++ &inst->bounce.sgl[chunk_no % DMA_BOUNCE_BUFFER_COUNT];
++ } else {
++ sgl = smi_scatterlist_from_buffer(
++ inst,
++ inst->bounce.phys[
++ chunk_no % DMA_BOUNCE_BUFFER_COUNT],
++ chunk_size,
++ &inst->buffer_sgl);
++ }
++
++ if (!smi_dma_submit_sgl(inst, sgl, 1, dma_dir,
++ smi_dma_callback_user_copy
++ )) {
++ dev_err(inst->dev, "sgl submit failed");
++ count = 0;
++ goto out;
++ }
++ count_left -= chunk_size;
++ chunk_no++;
++ }
++ dma_async_issue_pending(inst->dma_chan);
++
++ if (inst->settings.data_width == SMI_WIDTH_8BIT)
++ init_trans_func(inst, count);
++ else if (inst->settings.data_width == SMI_WIDTH_16BIT)
++ init_trans_func(inst, count / 2);
++out:
++ spin_unlock(&inst->transaction_lock);
++ return count;
++}
++EXPORT_SYMBOL(bcm2835_smi_user_dma);
++
++
++/****************************************************************************
++*
++* High level buffer transfer functions - for use by other drivers
++*
++***************************************************************************/
++
++/* Buffer must be physically contiguous - i.e. kmalloc, not vmalloc! */
++void bcm2835_smi_write_buf(
++ struct bcm2835_smi_instance *inst,
++ const void *buf, size_t n_bytes)
++{
++ int odd_bytes = n_bytes & 0x3;
++
++ n_bytes -= odd_bytes;
++
++ spin_lock(&inst->transaction_lock);
++
++ if (n_bytes > DMA_THRESHOLD_BYTES) {
++ dma_addr_t phy_addr = dma_map_single(
++ inst->dev,
++ (void *)buf,
++ n_bytes,
++ DMA_MEM_TO_DEV);
++ struct scatterlist *sgl =
++ smi_scatterlist_from_buffer(inst, phy_addr, n_bytes,
++ &inst->buffer_sgl);
++
++ if (!sgl) {
++ smi_dump_context_labelled(inst,
++ "Error: could not create scatterlist for write!");
++ goto out;
++ }
++ smi_dma_write_sgl(inst, sgl, 1, n_bytes);
++
++ dma_unmap_single
++ (inst->dev, phy_addr, n_bytes, DMA_MEM_TO_DEV);
++ } else if (n_bytes) {
++ smi_write_fifo(inst, (uint32_t *) buf, n_bytes);
++ }
++ buf += n_bytes;
++
++ if (inst->settings.data_width == SMI_WIDTH_8BIT) {
++ while (odd_bytes--)
++ smi_write_single_word(inst, *(uint8_t *) (buf++));
++ } else {
++ while (odd_bytes >= 2) {
++ smi_write_single_word(inst, *(uint16_t *)buf);
++ buf += 2;
++ odd_bytes -= 2;
++ }
++ if (odd_bytes) {
++ /* Reading an odd number of bytes on a 16 bit bus is
++ a user bug. It's kinder to fail early and tell them
++ than to e.g. transparently give them the bottom byte
++ of a 16 bit transfer. */
++ dev_err(inst->dev,
++ "WARNING: odd number of bytes specified for wide transfer.");
++ dev_err(inst->dev,
++ "At least one byte dropped as a result.");
++ dump_stack();
++ }
++ }
++out:
++ spin_unlock(&inst->transaction_lock);
++}
++EXPORT_SYMBOL(bcm2835_smi_write_buf);
++
++void bcm2835_smi_read_buf(struct bcm2835_smi_instance *inst,
++ void *buf, size_t n_bytes)
++{
++
++ /* SMI is inherently 32-bit, which causes surprising amounts of mess
++ for bytes % 4 != 0. Easiest to avoid this mess altogether
++ by handling remainder separately. */
++ int odd_bytes = n_bytes & 0x3;
++
++ spin_lock(&inst->transaction_lock);
++ n_bytes -= odd_bytes;
++ if (n_bytes > DMA_THRESHOLD_BYTES) {
++ dma_addr_t phy_addr = dma_map_single(inst->dev,
++ buf, n_bytes,
++ DMA_DEV_TO_MEM);
++ struct scatterlist *sgl = smi_scatterlist_from_buffer(
++ inst, phy_addr, n_bytes,
++ &inst->buffer_sgl);
++ if (!sgl) {
++ smi_dump_context_labelled(inst,
++ "Error: could not create scatterlist for read!");
++ goto out;
++ }
++ smi_dma_read_sgl(inst, sgl, 1, n_bytes);
++ dma_unmap_single(inst->dev, phy_addr, n_bytes, DMA_DEV_TO_MEM);
++ } else if (n_bytes) {
++ smi_read_fifo(inst, (uint32_t *)buf, n_bytes);
++ }
++ buf += n_bytes;
++
++ if (inst->settings.data_width == SMI_WIDTH_8BIT) {
++ while (odd_bytes--)
++ *((uint8_t *) (buf++)) = smi_read_single_word(inst);
++ } else {
++ while (odd_bytes >= 2) {
++ *(uint16_t *) buf = smi_read_single_word(inst);
++ buf += 2;
++ odd_bytes -= 2;
++ }
++ if (odd_bytes) {
++ dev_err(inst->dev,
++ "WARNING: odd number of bytes specified for wide transfer.");
++ dev_err(inst->dev,
++ "At least one byte dropped as a result.");
++ dump_stack();
++ }
++ }
++out:
++ spin_unlock(&inst->transaction_lock);
++}
++EXPORT_SYMBOL(bcm2835_smi_read_buf);
++
++void bcm2835_smi_set_address(struct bcm2835_smi_instance *inst,
++ unsigned int address)
++{
++ spin_lock(&inst->transaction_lock);
++ smi_set_address(inst, address);
++ spin_unlock(&inst->transaction_lock);
++}
++EXPORT_SYMBOL(bcm2835_smi_set_address);
++
++struct bcm2835_smi_instance *bcm2835_smi_get(struct device_node *node)
++{
++ struct platform_device *pdev;
++
++ if (!node)
++ return NULL;
++
++ pdev = of_find_device_by_node(node);
++ if (!pdev)
++ return NULL;
++
++ return platform_get_drvdata(pdev);
++}
++EXPORT_SYMBOL(bcm2835_smi_get);
++
++/****************************************************************************
++*
++* bcm2835_smi_probe - called when the driver is loaded.
++*
++***************************************************************************/
++
++static int bcm2835_smi_dma_setup(struct bcm2835_smi_instance *inst)
++{
++ int i, rv = 0;
++
++ inst->dma_chan = dma_request_slave_channel(inst->dev, "rx-tx");
++
++ inst->dma_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++ inst->dma_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++ inst->dma_config.src_addr = inst->smi_regs_busaddr + SMID;
++ inst->dma_config.dst_addr = inst->dma_config.src_addr;
++ /* Direction unimportant - always overridden by prep_slave_sg */
++ inst->dma_config.direction = DMA_DEV_TO_MEM;
++ dmaengine_slave_config(inst->dma_chan, &inst->dma_config);
++ /* Alloc and map bounce buffers */
++ for (i = 0; i < DMA_BOUNCE_BUFFER_COUNT; ++i) {
++ inst->bounce.buffer[i] =
++ dmam_alloc_coherent(inst->dev, DMA_BOUNCE_BUFFER_SIZE,
++ &inst->bounce.phys[i],
++ GFP_KERNEL);
++ if (!inst->bounce.buffer[i]) {
++ dev_err(inst->dev, "Could not allocate buffer!");
++ rv = -ENOMEM;
++ break;
++ }
++ smi_scatterlist_from_buffer(
++ inst,
++ inst->bounce.phys[i],
++ DMA_BOUNCE_BUFFER_SIZE,
++ &inst->bounce.sgl[i]
++ );
++ }
++
++ return rv;
++}
++
++static int bcm2835_smi_probe(struct platform_device *pdev)
++{
++ int err;
++ struct device *dev = &pdev->dev;
++ struct device_node *node = dev->of_node;
++ struct resource *ioresource;
++ struct bcm2835_smi_instance *inst;
++
++ /* Allocate buffers and instance data */
++
++ inst = devm_kzalloc(dev, sizeof(struct bcm2835_smi_instance),
++ GFP_KERNEL);
++
++ if (!inst)
++ return -ENOMEM;
++
++ inst->dev = dev;
++ spin_lock_init(&inst->transaction_lock);
++
++ /* We require device tree support */
++ if (!node)
++ return -EINVAL;
++
++ ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ inst->smi_regs_ptr = devm_ioremap_resource(dev, ioresource);
++ ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++ inst->cm_smi_regs_ptr = devm_ioremap_resource(dev, ioresource);
++ inst->smi_regs_busaddr = be32_to_cpu(
++ *of_get_address(node, 0, NULL, NULL));
++ of_property_read_u32(node,
++ "brcm,smi-clock-source",
++ &inst->clock_source);
++ of_property_read_u32(node,
++ "brcm,smi-clock-divisor",
++ &inst->clock_divisor);
++
++ err = bcm2835_smi_dma_setup(inst);
++ if (err)
++ return err;
++
++ /* Finally, do peripheral setup */
++
++ smi_setup_clock(inst);
++ smi_setup_regs(inst);
++
++ platform_set_drvdata(pdev, inst);
++
++ dev_info(inst->dev, "initialised");
++
++ return 0;
++}
++
++/****************************************************************************
++*
++* bcm2835_smi_remove - called when the driver is unloaded.
++*
++***************************************************************************/
++
++static int bcm2835_smi_remove(struct platform_device *pdev)
++{
++ struct bcm2835_smi_instance *inst = platform_get_drvdata(pdev);
++ struct device *dev = inst->dev;
++
++ dev_info(dev, "SMI device removed - OK");
++ return 0;
++}
++
++/****************************************************************************
++*
++* Register the driver with device tree
++*
++***************************************************************************/
++
++static const struct of_device_id bcm2835_smi_of_match[] = {
++ {.compatible = "brcm,bcm2835-smi",},
++ { /* sentinel */ },
++};
++
++MODULE_DEVICE_TABLE(of, bcm2835_smi_of_match);
++
++static struct platform_driver bcm2835_smi_driver = {
++ .probe = bcm2835_smi_probe,
++ .remove = bcm2835_smi_remove,
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ .of_match_table = bcm2835_smi_of_match,
++ },
++};
++
++module_platform_driver(bcm2835_smi_driver);
++
++MODULE_ALIAS("platform:smi-bcm2835");
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Device driver for BCM2835's secondary memory interface");
++MODULE_AUTHOR("Luke Wren <luke@raspberrypi.org>");
+--- /dev/null
++++ b/include/linux/broadcom/bcm2835_smi.h
+@@ -0,0 +1,391 @@
++/**
++ * Declarations and definitions for Broadcom's Secondary Memory Interface
++ *
++ * Written by Luke Wren <luke@raspberrypi.org>
++ * Copyright (c) 2015, Raspberry Pi (Trading) Ltd.
++ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef BCM2835_SMI_H
++#define BCM2835_SMI_H
++
++#include <linux/ioctl.h>
++
++#ifndef __KERNEL__
++#include <stdint.h>
++#include <stdbool.h>
++#endif
++
++#define BCM2835_SMI_IOC_MAGIC 0x1
++#define BCM2835_SMI_INVALID_HANDLE (~0)
++
++/* IOCTLs 0x100...0x1ff are not device-specific - we can use them */
++#define BCM2835_SMI_IOC_GET_SETTINGS _IO(BCM2835_SMI_IOC_MAGIC, 0)
++#define BCM2835_SMI_IOC_WRITE_SETTINGS _IO(BCM2835_SMI_IOC_MAGIC, 1)
++#define BCM2835_SMI_IOC_ADDRESS _IO(BCM2835_SMI_IOC_MAGIC, 2)
++#define BCM2835_SMI_IOC_MAX 2
++
++#define SMI_WIDTH_8BIT 0
++#define SMI_WIDTH_16BIT 1
++#define SMI_WIDTH_9BIT 2
++#define SMI_WIDTH_18BIT 3
++
++/* max number of bytes where DMA will not be used */
++#define DMA_THRESHOLD_BYTES 128
++#define DMA_BOUNCE_BUFFER_SIZE (1024 * 1024 / 2)
++#define DMA_BOUNCE_BUFFER_COUNT 3
++
++
++struct smi_settings {
++ int data_width;
++ /* Whether or not to pack multiple SMI transfers into a
++ single 32 bit FIFO word */
++ bool pack_data;
++
++ /* Timing for reads (writes the same but for WE)
++ *
++ * OE ----------+ +--------------------
++ * | |
++ * +----------+
++ * SD -<==============================>-----------
++ * SA -<=========================================>-
++ * <-setup-> <-strobe -> <-hold -> <- pace ->
++ */
++
++ int read_setup_time;
++ int read_hold_time;
++ int read_pace_time;
++ int read_strobe_time;
++
++ int write_setup_time;
++ int write_hold_time;
++ int write_pace_time;
++ int write_strobe_time;
++
++ bool dma_enable; /* DREQs */
++ bool dma_passthrough_enable; /* External DREQs */
++ int dma_read_thresh;
++ int dma_write_thresh;
++ int dma_panic_read_thresh;
++ int dma_panic_write_thresh;
++};
++
++/****************************************************************************
++*
++* Declare exported SMI functions
++*
++***************************************************************************/
++
++#ifdef __KERNEL__
++
++#include <linux/dmaengine.h> /* for enum dma_transfer_direction */
++#include <linux/of.h>
++#include <linux/semaphore.h>
++
++struct bcm2835_smi_instance;
++
++struct bcm2835_smi_bounce_info {
++ struct semaphore callback_sem;
++ void *buffer[DMA_BOUNCE_BUFFER_COUNT];
++ dma_addr_t phys[DMA_BOUNCE_BUFFER_COUNT];
++ struct scatterlist sgl[DMA_BOUNCE_BUFFER_COUNT];
++};
++
++
++void bcm2835_smi_set_regs_from_settings(struct bcm2835_smi_instance *);
++
++struct smi_settings *bcm2835_smi_get_settings_from_regs(
++ struct bcm2835_smi_instance *inst);
++
++void bcm2835_smi_write_buf(
++ struct bcm2835_smi_instance *inst,
++ const void *buf,
++ size_t n_bytes);
++
++void bcm2835_smi_read_buf(
++ struct bcm2835_smi_instance *inst,
++ void *buf,
++ size_t n_bytes);
++
++void bcm2835_smi_set_address(struct bcm2835_smi_instance *inst,
++ unsigned int address);
++
++ssize_t bcm2835_smi_user_dma(
++ struct bcm2835_smi_instance *inst,
++ enum dma_transfer_direction dma_dir,
++ char __user *user_ptr,
++ size_t count,
++ struct bcm2835_smi_bounce_info **bounce);
++
++struct bcm2835_smi_instance *bcm2835_smi_get(struct device_node *node);
++
++#endif /* __KERNEL__ */
++
++/****************************************************************
++*
++* Implementation-only declarations
++*
++****************************************************************/
++
++#ifdef BCM2835_SMI_IMPLEMENTATION
++
++/* Clock manager registers for SMI clock: */
++#define CM_SMI_BASE_ADDRESS ((BCM2708_PERI_BASE) + 0x1010b0)
++/* Clock manager "password" to protect registers from spurious writes */
++#define CM_PWD (0x5a << 24)
++
++#define CM_SMI_CTL 0x00
++#define CM_SMI_DIV 0x04
++
++#define CM_SMI_CTL_FLIP (1 << 8)
++#define CM_SMI_CTL_BUSY (1 << 7)
++#define CM_SMI_CTL_KILL (1 << 5)
++#define CM_SMI_CTL_ENAB (1 << 4)
++#define CM_SMI_CTL_SRC_MASK (0xf)
++#define CM_SMI_CTL_SRC_OFFS (0)
++
++#define CM_SMI_DIV_DIVI_MASK (0xf << 12)
++#define CM_SMI_DIV_DIVI_OFFS (12)
++#define CM_SMI_DIV_DIVF_MASK (0xff << 4)
++#define CM_SMI_DIV_DIVF_OFFS (4)
++
++/* SMI register mapping:*/
++#define SMI_BASE_ADDRESS ((BCM2708_PERI_BASE) + 0x600000)
++
++#define SMICS 0x00 /* control + status register */
++#define SMIL 0x04 /* length/count (n external txfers) */
++#define SMIA 0x08 /* address register */
++#define SMID 0x0c /* data register */
++#define SMIDSR0 0x10 /* device 0 read settings */
++#define SMIDSW0 0x14 /* device 0 write settings */
++#define SMIDSR1 0x18 /* device 1 read settings */
++#define SMIDSW1 0x1c /* device 1 write settings */
++#define SMIDSR2 0x20 /* device 2 read settings */
++#define SMIDSW2 0x24 /* device 2 write settings */
++#define SMIDSR3 0x28 /* device 3 read settings */
++#define SMIDSW3 0x2c /* device 3 write settings */
++#define SMIDC 0x30 /* DMA control registers */
++#define SMIDCS 0x34 /* direct control/status register */
++#define SMIDA 0x38 /* direct address register */
++#define SMIDD 0x3c /* direct data registers */
++#define SMIFD 0x40 /* FIFO debug register */
++
++
++
++/* Control and Status register bits:
++ * SMICS_RXF : RX fifo full: 1 when RX fifo is full
++ * SMICS_TXE : TX fifo empty: 1 when empty.
++ * SMICS_RXD : RX fifo contains data: 1 when there is data.
++ * SMICS_TXD : TX fifo can accept data: 1 when true.
++ * SMICS_RXR : RX fifo needs reading: 1 when fifo more than 3/4 full, or
++ * when "DONE" and fifo not emptied.
++ * SMICS_TXW : TX fifo needs writing: 1 when less than 1/4 full.
++ * SMICS_AFERR : AXI FIFO error: 1 when fifo read when empty or written
++ * when full. Write 1 to clear.
++ * SMICS_EDREQ : 1 when external DREQ received.
++ * SMICS_PXLDAT : Pixel data: write 1 to enable pixel transfer modes.
++ * SMICS_SETERR : 1 if there was an error writing to setup regs (e.g.
++ * tx was in progress). Write 1 to clear.
++ * SMICS_PVMODE : Set to 1 to enable pixel valve mode.
++ * SMICS_INTR : Set to 1 to enable interrupt on RX.
++ * SMICS_INTT : Set to 1 to enable interrupt on TX.
++ * SMICS_INTD : Set to 1 to enable interrupt on DONE condition.
++ * SMICS_TEEN : Tear effect mode enabled: Programmed transfers will wait
++ * for a TE trigger before writing.
++ * SMICS_PAD1 : Padding settings for external transfers. For writes: the
++ * number of bytes initially written to the TX fifo that
++ * SMICS_PAD0 : should be ignored. For reads: the number of bytes that will
++ * be read before the data, and should be dropped.
++ * SMICS_WRITE : Transfer direction: 1 = write to external device, 0 = read
++ * SMICS_CLEAR : Write 1 to clear the FIFOs.
++ * SMICS_START : Write 1 to start the programmed transfer.
++ * SMICS_ACTIVE : Reads as 1 when a programmed transfer is underway.
++ * SMICS_DONE : Reads as 1 when transfer finished. For RX, not set until
++ * FIFO emptied.
++ * SMICS_ENABLE : Set to 1 to enable the SMI peripheral, 0 to disable.
++ */
++
++#define SMICS_RXF (1 << 31)
++#define SMICS_TXE (1 << 30)
++#define SMICS_RXD (1 << 29)
++#define SMICS_TXD (1 << 28)
++#define SMICS_RXR (1 << 27)
++#define SMICS_TXW (1 << 26)
++#define SMICS_AFERR (1 << 25)
++#define SMICS_EDREQ (1 << 15)
++#define SMICS_PXLDAT (1 << 14)
++#define SMICS_SETERR (1 << 13)
++#define SMICS_PVMODE (1 << 12)
++#define SMICS_INTR (1 << 11)
++#define SMICS_INTT (1 << 10)
++#define SMICS_INTD (1 << 9)
++#define SMICS_TEEN (1 << 8)
++#define SMICS_PAD1 (1 << 7)
++#define SMICS_PAD0 (1 << 6)
++#define SMICS_WRITE (1 << 5)
++#define SMICS_CLEAR (1 << 4)
++#define SMICS_START (1 << 3)
++#define SMICS_ACTIVE (1 << 2)
++#define SMICS_DONE (1 << 1)
++#define SMICS_ENABLE (1 << 0)
++
++/* Address register bits: */
++
++#define SMIA_DEVICE_MASK ((1 << 9) | (1 << 8))
++#define SMIA_DEVICE_OFFS (8)
++#define SMIA_ADDR_MASK (0x3f) /* bits 5 -> 0 */
++#define SMIA_ADDR_OFFS (0)
++
++/* DMA control register bits:
++ * SMIDC_DMAEN : DMA enable: set 1: DMA requests will be issued.
++ * SMIDC_DMAP : DMA passthrough: when set to 0, top two data pins are used by
++ * SMI as usual. When set to 1, the top two pins are used for
++ * external DREQs: pin 16 read request, 17 write.
++ * SMIDC_PANIC* : Threshold at which DMA will panic during read/write.
++ * SMIDC_REQ* : Threshold at which DMA will generate a DREQ.
++ */
++
++#define SMIDC_DMAEN (1 << 28)
++#define SMIDC_DMAP (1 << 24)
++#define SMIDC_PANICR_MASK (0x3f << 18)
++#define SMIDC_PANICR_OFFS (18)
++#define SMIDC_PANICW_MASK (0x3f << 12)
++#define SMIDC_PANICW_OFFS (12)
++#define SMIDC_REQR_MASK (0x3f << 6)
++#define SMIDC_REQR_OFFS (6)
++#define SMIDC_REQW_MASK (0x3f)
++#define SMIDC_REQW_OFFS (0)
++
++/* Device settings register bits: same for all 4 (or 3?) device register sets.
++ * Device read settings:
++ * SMIDSR_RWIDTH : Read transfer width. 00 = 8bit, 01 = 16bit,
++ * 10 = 18bit, 11 = 9bit.
++ * SMIDSR_RSETUP : Read setup time: number of core cycles between chip
++ * select/address and read strobe. Min 1, max 64.
++ * SMIDSR_MODE68 : 1 for System 68 mode (i.e. enable + direction pins,
++ * rather than OE + WE pin)
++ * SMIDSR_FSETUP : If set to 1, setup time only applies to first
++ * transfer after address change.
++ * SMIDSR_RHOLD : Number of core cycles between read strobe going
++ * inactive and CS/address going inactive. Min 1, max 64
++ * SMIDSR_RPACEALL : When set to 1, this device's RPACE value will always
++ * be used for the next transaction, even if it is not
++ * to this device.
++ * SMIDSR_RPACE : Number of core cycles spent waiting between CS
++ * deassert and start of next transfer. Min 1, max 128
++ * SMIDSR_RDREQ : 1 = use external DMA request on SD16 to pace reads
++ * from device. Must also set DMAP in SMICS.
++ * SMIDSR_RSTROBE : Number of cycles to assert the read strobe.
++ * min 1, max 128.
++ */
++#define SMIDSR_RWIDTH_MASK ((1<<31)|(1<<30))
++#define SMIDSR_RWIDTH_OFFS (30)
++#define SMIDSR_RSETUP_MASK (0x3f << 24)
++#define SMIDSR_RSETUP_OFFS (24)
++#define SMIDSR_MODE68 (1 << 23)
++#define SMIDSR_FSETUP (1 << 22)
++#define SMIDSR_RHOLD_MASK (0x3f << 16)
++#define SMIDSR_RHOLD_OFFS (16)
++#define SMIDSR_RPACEALL (1 << 15)
++#define SMIDSR_RPACE_MASK (0x7f << 8)
++#define SMIDSR_RPACE_OFFS (8)
++#define SMIDSR_RDREQ (1 << 7)
++#define SMIDSR_RSTROBE_MASK (0x7f)
++#define SMIDSR_RSTROBE_OFFS (0)
++
++/* Device write settings:
++ * SMIDSW_WWIDTH : Write transfer width. 00 = 8bit, 01 = 16bit,
++ * 10= 18bit, 11 = 9bit.
++ * SMIDSW_WSETUP : Number of cycles between CS assert and write strobe.
++ * Min 1, max 64.
++ * SMIDSW_WFORMAT : Pixel format of input. 0 = 16bit RGB 565,
++ * 1 = 32bit RGBA 8888
++ * SMIDSW_WSWAP : 1 = swap pixel data bits. (Use with SMICS_PXLDAT)
++ * SMIDSW_WHOLD : Time between WE deassert and CS deassert. 1 to 64
++ * SMIDSW_WPACEALL : 1: this device's WPACE will be used for the next
++ * transfer, regardless of that transfer's device.
++ * SMIDSW_WPACE : Cycles between CS deassert and next CS assert.
++ * Min 1, max 128
++ * SMIDSW_WDREQ : Use external DREQ on pin 17 to pace writes. DMAP must
++ * be set in SMICS.
++ * SMIDSW_WSTROBE : Number of cycles to assert the write strobe.
++ * Min 1, max 128
++ */
++#define SMIDSW_WWIDTH_MASK ((1<<31)|(1<<30))
++#define SMIDSW_WWIDTH_OFFS (30)
++#define SMIDSW_WSETUP_MASK (0x3f << 24)
++#define SMIDSW_WSETUP_OFFS (24)
++#define SMIDSW_WFORMAT (1 << 23)
++#define SMIDSW_WSWAP (1 << 22)
++#define SMIDSW_WHOLD_MASK (0x3f << 16)
++#define SMIDSW_WHOLD_OFFS (16)
++#define SMIDSW_WPACEALL (1 << 15)
++#define SMIDSW_WPACE_MASK (0x7f << 8)
++#define SMIDSW_WPACE_OFFS (8)
++#define SMIDSW_WDREQ (1 << 7)
++#define SMIDSW_WSTROBE_MASK (0x7f)
++#define SMIDSW_WSTROBE_OFFS (0)
++
++/* Direct transfer control + status register
++ * SMIDCS_WRITE : Direction of transfer: 1 -> write, 0 -> read
++ * SMIDCS_DONE : 1 when a transfer has finished. Write 1 to clear.
++ * SMIDCS_START : Write 1 to start a transfer, if one is not already underway.
++ * SMIDCE_ENABLE: Write 1 to enable SMI in direct mode.
++ */
++
++#define SMIDCS_WRITE (1 << 3)
++#define SMIDCS_DONE (1 << 2)
++#define SMIDCS_START (1 << 1)
++#define SMIDCS_ENABLE (1 << 0)
++
++/* Direct transfer address register
++ * SMIDA_DEVICE : Indicates which of the device settings banks should be used.
++ * SMIDA_ADDR : The value to be asserted on the address pins.
++ */
++
++#define SMIDA_DEVICE_MASK ((1<<9)|(1<<8))
++#define SMIDA_DEVICE_OFFS (8)
++#define SMIDA_ADDR_MASK (0x3f)
++#define SMIDA_ADDR_OFFS (0)
++
++/* FIFO debug register
++ * SMIFD_FLVL : The high-tide mark of FIFO count during the most recent txfer
++ * SMIFD_FCNT : The current FIFO count.
++ */
++#define SMIFD_FLVL_MASK (0x3f << 8)
++#define SMIFD_FLVL_OFFS (8)
++#define SMIFD_FCNT_MASK (0x3f)
++#define SMIFD_FCNT_OFFS (0)
++
++#endif /* BCM2835_SMI_IMPLEMENTATION */
++
++#endif /* BCM2835_SMI_H */
diff --git a/target/linux/brcm2708/patches-4.4/0040-Add-dev-gpiomem-device-for-rootless-user-GPIO-access.patch b/target/linux/brcm2708/patches-4.4/0040-Add-dev-gpiomem-device-for-rootless-user-GPIO-access.patch
deleted file mode 100644
index 34806e682b..0000000000
--- a/target/linux/brcm2708/patches-4.4/0040-Add-dev-gpiomem-device-for-rootless-user-GPIO-access.patch
+++ /dev/null
@@ -1,306 +0,0 @@
-From 832077a0f61e44a9259b153f60eb233fa723c2a9 Mon Sep 17 00:00:00 2001
-From: Luke Wren <luke@raspberrypi.org>
-Date: Fri, 21 Aug 2015 23:14:48 +0100
-Subject: [PATCH 040/170] Add /dev/gpiomem device for rootless user GPIO access
-
-Signed-off-by: Luke Wren <luke@raspberrypi.org>
-
-bcm2835-gpiomem: Fix for ARCH_BCM2835 builds
-
-Build on ARCH_BCM2835, and fail to probe if no IO resource.
-
-See: https://github.com/raspberrypi/linux/issues/1154
----
- drivers/char/broadcom/Kconfig | 9 ++
- drivers/char/broadcom/Makefile | 3 +
- drivers/char/broadcom/bcm2835-gpiomem.c | 260 ++++++++++++++++++++++++++++++++
- 3 files changed, 272 insertions(+)
- create mode 100644 drivers/char/broadcom/bcm2835-gpiomem.c
-
---- a/drivers/char/broadcom/Kconfig
-+++ b/drivers/char/broadcom/Kconfig
-@@ -32,3 +32,12 @@ config BCM_VC_SM
- help
- Support for the VC shared memory on the Broadcom reference
- design. Uses the VCHIQ stack.
-+
-+config BCM2835_DEVGPIOMEM
-+ tristate "/dev/gpiomem rootless GPIO access via mmap() on the BCM2835"
-+ default m
-+ help
-+ Provides users with root-free access to the GPIO registers
-+ on the 2835. Calling mmap(/dev/gpiomem) will map the GPIO
-+ register page to the user's pointer.
-+
---- a/drivers/char/broadcom/Makefile
-+++ b/drivers/char/broadcom/Makefile
-@@ -1,3 +1,6 @@
- obj-$(CONFIG_BCM_VC_CMA) += vc_cma/
- obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o
- obj-$(CONFIG_BCM_VC_SM) += vc_sm/
-+
-+obj-$(CONFIG_BCM2835_DEVGPIOMEM)+= bcm2835-gpiomem.o
-+
---- /dev/null
-+++ b/drivers/char/broadcom/bcm2835-gpiomem.c
-@@ -0,0 +1,260 @@
-+/**
-+ * GPIO memory device driver
-+ *
-+ * Creates a chardev /dev/gpiomem which will provide user access to
-+ * the BCM2835's GPIO registers when it is mmap()'d.
-+ * No longer need root for user GPIO access, but without relaxing permissions
-+ * on /dev/mem.
-+ *
-+ * Written by Luke Wren <luke@raspberrypi.org>
-+ * Copyright (c) 2015, Raspberry Pi (Trading) Ltd.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <linux/mm.h>
-+#include <linux/slab.h>
-+#include <linux/cdev.h>
-+#include <linux/pagemap.h>
-+#include <linux/io.h>
-+
-+#define DEVICE_NAME "bcm2835-gpiomem"
-+#define DRIVER_NAME "gpiomem-bcm2835"
-+#define DEVICE_MINOR 0
-+
-+struct bcm2835_gpiomem_instance {
-+ unsigned long gpio_regs_phys;
-+ struct device *dev;
-+};
-+
-+static struct cdev bcm2835_gpiomem_cdev;
-+static dev_t bcm2835_gpiomem_devid;
-+static struct class *bcm2835_gpiomem_class;
-+static struct device *bcm2835_gpiomem_dev;
-+static struct bcm2835_gpiomem_instance *inst;
-+
-+
-+/****************************************************************************
-+*
-+* GPIO mem chardev file ops
-+*
-+***************************************************************************/
-+
-+static int bcm2835_gpiomem_open(struct inode *inode, struct file *file)
-+{
-+ int dev = iminor(inode);
-+ int ret = 0;
-+
-+ dev_info(inst->dev, "gpiomem device opened.");
-+
-+ if (dev != DEVICE_MINOR) {
-+ dev_err(inst->dev, "Unknown minor device: %d", dev);
-+ ret = -ENXIO;
-+ }
-+ return ret;
-+}
-+
-+static int bcm2835_gpiomem_release(struct inode *inode, struct file *file)
-+{
-+ int dev = iminor(inode);
-+ int ret = 0;
-+
-+ if (dev != DEVICE_MINOR) {
-+ dev_err(inst->dev, "Unknown minor device %d", dev);
-+ ret = -ENXIO;
-+ }
-+ return ret;
-+}
-+
-+static const struct vm_operations_struct bcm2835_gpiomem_vm_ops = {
-+#ifdef CONFIG_HAVE_IOREMAP_PROT
-+ .access = generic_access_phys
-+#endif
-+};
-+
-+static int bcm2835_gpiomem_mmap(struct file *file, struct vm_area_struct *vma)
-+{
-+ /* Ignore what the user says - they're getting the GPIO regs
-+ whether they like it or not! */
-+ unsigned long gpio_page = inst->gpio_regs_phys >> PAGE_SHIFT;
-+
-+ vma->vm_page_prot = phys_mem_access_prot(file, gpio_page,
-+ PAGE_SIZE,
-+ vma->vm_page_prot);
-+ vma->vm_ops = &bcm2835_gpiomem_vm_ops;
-+ if (remap_pfn_range(vma, vma->vm_start,
-+ gpio_page,
-+ PAGE_SIZE,
-+ vma->vm_page_prot)) {
-+ return -EAGAIN;
-+ }
-+ return 0;
-+}
-+
-+static const struct file_operations
-+bcm2835_gpiomem_fops = {
-+ .owner = THIS_MODULE,
-+ .open = bcm2835_gpiomem_open,
-+ .release = bcm2835_gpiomem_release,
-+ .mmap = bcm2835_gpiomem_mmap,
-+};
-+
-+
-+ /****************************************************************************
-+*
-+* Probe and remove functions
-+*
-+***************************************************************************/
-+
-+
-+static int bcm2835_gpiomem_probe(struct platform_device *pdev)
-+{
-+ int err;
-+ void *ptr_err;
-+ struct device *dev = &pdev->dev;
-+ struct resource *ioresource;
-+
-+ /* Allocate buffers and instance data */
-+
-+ inst = kzalloc(sizeof(struct bcm2835_gpiomem_instance), GFP_KERNEL);
-+
-+ if (!inst) {
-+ err = -ENOMEM;
-+ goto failed_inst_alloc;
-+ }
-+
-+ inst->dev = dev;
-+
-+ ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ if (ioresource) {
-+ inst->gpio_regs_phys = ioresource->start;
-+ } else {
-+ dev_err(inst->dev, "failed to get IO resource");
-+ err = -ENOENT;
-+ goto failed_get_resource;
-+ }
-+
-+ /* Create character device entries */
-+
-+ err = alloc_chrdev_region(&bcm2835_gpiomem_devid,
-+ DEVICE_MINOR, 1, DEVICE_NAME);
-+ if (err != 0) {
-+ dev_err(inst->dev, "unable to allocate device number");
-+ goto failed_alloc_chrdev;
-+ }
-+ cdev_init(&bcm2835_gpiomem_cdev, &bcm2835_gpiomem_fops);
-+ bcm2835_gpiomem_cdev.owner = THIS_MODULE;
-+ err = cdev_add(&bcm2835_gpiomem_cdev, bcm2835_gpiomem_devid, 1);
-+ if (err != 0) {
-+ dev_err(inst->dev, "unable to register device");
-+ goto failed_cdev_add;
-+ }
-+
-+ /* Create sysfs entries */
-+
-+ bcm2835_gpiomem_class = class_create(THIS_MODULE, DEVICE_NAME);
-+ ptr_err = bcm2835_gpiomem_class;
-+ if (IS_ERR(ptr_err))
-+ goto failed_class_create;
-+
-+ bcm2835_gpiomem_dev = device_create(bcm2835_gpiomem_class, NULL,
-+ bcm2835_gpiomem_devid, NULL,
-+ "gpiomem");
-+ ptr_err = bcm2835_gpiomem_dev;
-+ if (IS_ERR(ptr_err))
-+ goto failed_device_create;
-+
-+ dev_info(inst->dev, "Initialised: Registers at 0x%08lx",
-+ inst->gpio_regs_phys);
-+
-+ return 0;
-+
-+failed_device_create:
-+ class_destroy(bcm2835_gpiomem_class);
-+failed_class_create:
-+ cdev_del(&bcm2835_gpiomem_cdev);
-+ err = PTR_ERR(ptr_err);
-+failed_cdev_add:
-+ unregister_chrdev_region(bcm2835_gpiomem_devid, 1);
-+failed_alloc_chrdev:
-+failed_get_resource:
-+ kfree(inst);
-+failed_inst_alloc:
-+ dev_err(inst->dev, "could not load bcm2835_gpiomem");
-+ return err;
-+}
-+
-+static int bcm2835_gpiomem_remove(struct platform_device *pdev)
-+{
-+ struct device *dev = inst->dev;
-+
-+ kfree(inst);
-+ device_destroy(bcm2835_gpiomem_class, bcm2835_gpiomem_devid);
-+ class_destroy(bcm2835_gpiomem_class);
-+ cdev_del(&bcm2835_gpiomem_cdev);
-+ unregister_chrdev_region(bcm2835_gpiomem_devid, 1);
-+
-+ dev_info(dev, "GPIO mem driver removed - OK");
-+ return 0;
-+}
-+
-+ /****************************************************************************
-+*
-+* Register the driver with device tree
-+*
-+***************************************************************************/
-+
-+static const struct of_device_id bcm2835_gpiomem_of_match[] = {
-+ {.compatible = "brcm,bcm2835-gpiomem",},
-+ { /* sentinel */ },
-+};
-+
-+MODULE_DEVICE_TABLE(of, bcm2835_gpiomem_of_match);
-+
-+static struct platform_driver bcm2835_gpiomem_driver = {
-+ .probe = bcm2835_gpiomem_probe,
-+ .remove = bcm2835_gpiomem_remove,
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ .of_match_table = bcm2835_gpiomem_of_match,
-+ },
-+};
-+
-+module_platform_driver(bcm2835_gpiomem_driver);
-+
-+MODULE_ALIAS("platform:gpiomem-bcm2835");
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("gpiomem driver for accessing GPIO from userspace");
-+MODULE_AUTHOR("Luke Wren <luke@raspberrypi.org>");
diff --git a/target/linux/brcm2708/patches-4.4/0041-Add-SMI-NAND-driver.patch b/target/linux/brcm2708/patches-4.4/0041-Add-SMI-NAND-driver.patch
new file mode 100644
index 0000000000..0cefde75c1
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0041-Add-SMI-NAND-driver.patch
@@ -0,0 +1,358 @@
+From 6470951ad62727bb57bde4c1a7584baacac7c558 Mon Sep 17 00:00:00 2001
+From: Luke Wren <wren6991@gmail.com>
+Date: Sat, 5 Sep 2015 01:16:10 +0100
+Subject: [PATCH 041/381] Add SMI NAND driver
+
+Signed-off-by: Luke Wren <wren6991@gmail.com>
+---
+ .../bindings/mtd/brcm,bcm2835-smi-nand.txt | 42 ++++
+ drivers/mtd/nand/Kconfig | 7 +
+ drivers/mtd/nand/Makefile | 1 +
+ drivers/mtd/nand/bcm2835_smi_nand.c | 268 +++++++++++++++++++++
+ 4 files changed, 318 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/mtd/brcm,bcm2835-smi-nand.txt
+ create mode 100644 drivers/mtd/nand/bcm2835_smi_nand.c
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/mtd/brcm,bcm2835-smi-nand.txt
+@@ -0,0 +1,42 @@
++* BCM2835 SMI NAND flash
++
++This driver is a shim between the BCM2835 SMI driver (SMI is a peripheral for
++talking to parallel register interfaces) and Linux's MTD layer.
++
++Required properties:
++- compatible: "brcm,bcm2835-smi-nand"
++- status: "okay"
++
++Optional properties:
++- partition@n, where n is an integer from a consecutive sequence starting at 0
++ - Difficult to store partition table on NAND device - normally put it
++ in the source code, kernel bootparams, or device tree (the best way!)
++ - Sub-properties:
++ - label: the partition name, as shown by mtdinfo /dev/mtd*
++ - reg: the size and offset of this partition.
++ - (optional) read-only: an empty property flagging as read only
++
++Example:
++
++nand: flash@0 {
++ compatible = "brcm,bcm2835-smi-nand";
++ status = "okay";
++
++ partition@0 {
++ label = "stage2";
++ // 128k
++ reg = <0 0x20000>;
++ read-only;
++ };
++ partition@1 {
++ label = "firmware";
++ // 16M
++ reg = <0x20000 0x1000000>;
++ read-only;
++ };
++ partition@2 {
++ label = "root";
++ // 2G
++ reg = <0x1020000 0x80000000>;
++ };
++};
+\ No newline at end of file
+--- a/drivers/mtd/nand/Kconfig
++++ b/drivers/mtd/nand/Kconfig
+@@ -41,6 +41,13 @@ config MTD_SM_COMMON
+ tristate
+ default n
+
++config MTD_NAND_BCM2835_SMI
++ tristate "Use Broadcom's Secondary Memory Interface as a NAND controller (BCM283x)"
++ depends on (MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835) && BCM2835_SMI && MTD_NAND
++ default m
++ help
++ Uses the BCM2835's SMI peripheral as a NAND controller.
++
+ config MTD_NAND_DENALI
+ tristate
+
+--- a/drivers/mtd/nand/Makefile
++++ b/drivers/mtd/nand/Makefile
+@@ -14,6 +14,7 @@ obj-$(CONFIG_MTD_NAND_DENALI) += denali
+ obj-$(CONFIG_MTD_NAND_DENALI_PCI) += denali_pci.o
+ obj-$(CONFIG_MTD_NAND_DENALI_DT) += denali_dt.o
+ obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o
++obj-$(CONFIG_MTD_NAND_BCM2835_SMI) += bcm2835_smi_nand.o
+ obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o
+ obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o
+ obj-$(CONFIG_MTD_NAND_DAVINCI) += davinci_nand.o
+--- /dev/null
++++ b/drivers/mtd/nand/bcm2835_smi_nand.c
+@@ -0,0 +1,268 @@
++/**
++ * NAND flash driver for Broadcom Secondary Memory Interface
++ *
++ * Written by Luke Wren <luke@raspberrypi.org>
++ * Copyright (c) 2015, Raspberry Pi (Trading) Ltd.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/partitions.h>
++
++#include <linux/broadcom/bcm2835_smi.h>
++
++#define DEVICE_NAME "bcm2835-smi-nand"
++#define DRIVER_NAME "smi-nand-bcm2835"
++
++struct bcm2835_smi_nand_host {
++ struct bcm2835_smi_instance *smi_inst;
++ struct nand_chip nand_chip;
++ struct mtd_info mtd;
++ struct device *dev;
++};
++
++/****************************************************************************
++*
++* NAND functionality implementation
++*
++****************************************************************************/
++
++#define SMI_NAND_CLE_PIN 0x01
++#define SMI_NAND_ALE_PIN 0x02
++
++static inline void bcm2835_smi_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
++ unsigned int ctrl)
++{
++ uint32_t cmd32 = cmd;
++ uint32_t addr = ~(SMI_NAND_CLE_PIN | SMI_NAND_ALE_PIN);
++ struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
++ struct bcm2835_smi_instance *inst = host->smi_inst;
++
++ if (ctrl & NAND_CLE)
++ addr |= SMI_NAND_CLE_PIN;
++ if (ctrl & NAND_ALE)
++ addr |= SMI_NAND_ALE_PIN;
++ /* Lower ALL the CS pins! */
++ if (ctrl & NAND_NCE)
++ addr &= (SMI_NAND_CLE_PIN | SMI_NAND_ALE_PIN);
++
++ bcm2835_smi_set_address(inst, addr);
++
++ if (cmd != NAND_CMD_NONE)
++ bcm2835_smi_write_buf(inst, &cmd32, 1);
++}
++
++static inline uint8_t bcm2835_smi_nand_read_byte(struct mtd_info *mtd)
++{
++ uint8_t byte;
++ struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
++ struct bcm2835_smi_instance *inst = host->smi_inst;
++
++ bcm2835_smi_read_buf(inst, &byte, 1);
++ return byte;
++}
++
++static inline void bcm2835_smi_nand_write_byte(struct mtd_info *mtd,
++ uint8_t byte)
++{
++ struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
++ struct bcm2835_smi_instance *inst = host->smi_inst;
++
++ bcm2835_smi_write_buf(inst, &byte, 1);
++}
++
++static inline void bcm2835_smi_nand_write_buf(struct mtd_info *mtd,
++ const uint8_t *buf, int len)
++{
++ struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
++ struct bcm2835_smi_instance *inst = host->smi_inst;
++
++ bcm2835_smi_write_buf(inst, buf, len);
++}
++
++static inline void bcm2835_smi_nand_read_buf(struct mtd_info *mtd,
++ uint8_t *buf, int len)
++{
++ struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
++ struct bcm2835_smi_instance *inst = host->smi_inst;
++
++ bcm2835_smi_read_buf(inst, buf, len);
++}
++
++/****************************************************************************
++*
++* Probe and remove functions
++*
++***************************************************************************/
++
++static int bcm2835_smi_nand_probe(struct platform_device *pdev)
++{
++ struct bcm2835_smi_nand_host *host;
++ struct nand_chip *this;
++ struct mtd_info *mtd;
++ struct device *dev = &pdev->dev;
++ struct device_node *node = dev->of_node, *smi_node;
++ struct mtd_part_parser_data ppdata;
++ struct smi_settings *smi_settings;
++ struct bcm2835_smi_instance *smi_inst;
++ int ret = -ENXIO;
++
++ if (!node) {
++ dev_err(dev, "No device tree node supplied!");
++ return -EINVAL;
++ }
++
++ smi_node = of_parse_phandle(node, "smi_handle", 0);
++
++ /* Request use of SMI peripheral: */
++ smi_inst = bcm2835_smi_get(smi_node);
++
++ if (!smi_inst) {
++ dev_err(dev, "Could not register with SMI.");
++ return -EPROBE_DEFER;
++ }
++
++ /* Set SMI timing and bus width */
++
++ smi_settings = bcm2835_smi_get_settings_from_regs(smi_inst);
++
++ smi_settings->data_width = SMI_WIDTH_8BIT;
++ smi_settings->read_setup_time = 2;
++ smi_settings->read_hold_time = 1;
++ smi_settings->read_pace_time = 1;
++ smi_settings->read_strobe_time = 3;
++
++ smi_settings->write_setup_time = 2;
++ smi_settings->write_hold_time = 1;
++ smi_settings->write_pace_time = 1;
++ smi_settings->write_strobe_time = 3;
++
++ bcm2835_smi_set_regs_from_settings(smi_inst);
++
++ host = devm_kzalloc(dev, sizeof(struct bcm2835_smi_nand_host),
++ GFP_KERNEL);
++ if (!host)
++ return -ENOMEM;
++
++ host->dev = dev;
++ host->smi_inst = smi_inst;
++
++ platform_set_drvdata(pdev, host);
++
++ /* Link the structures together */
++
++ this = &host->nand_chip;
++ mtd = &host->mtd;
++ mtd->priv = this;
++ mtd->owner = THIS_MODULE;
++ mtd->dev.parent = dev;
++ mtd->name = DRIVER_NAME;
++ ppdata.of_node = node;
++
++ /* 20 us command delay time... */
++ this->chip_delay = 20;
++
++ this->priv = host;
++ this->cmd_ctrl = bcm2835_smi_nand_cmd_ctrl;
++ this->read_byte = bcm2835_smi_nand_read_byte;
++ this->write_byte = bcm2835_smi_nand_write_byte;
++ this->write_buf = bcm2835_smi_nand_write_buf;
++ this->read_buf = bcm2835_smi_nand_read_buf;
++
++ this->ecc.mode = NAND_ECC_SOFT;
++
++ /* Should never be accessed directly: */
++
++ this->IO_ADDR_R = (void *)0xdeadbeef;
++ this->IO_ADDR_W = (void *)0xdeadbeef;
++
++ /* First scan to find the device and get the page size */
++
++ if (nand_scan_ident(mtd, 1, NULL))
++ return -ENXIO;
++
++ /* Second phase scan */
++
++ if (nand_scan_tail(mtd))
++ return -ENXIO;
++
++ ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
++ if (!ret)
++ return 0;
++
++ nand_release(mtd);
++ return -EINVAL;
++}
++
++static int bcm2835_smi_nand_remove(struct platform_device *pdev)
++{
++ struct bcm2835_smi_nand_host *host = platform_get_drvdata(pdev);
++
++ nand_release(&host->mtd);
++
++ return 0;
++}
++
++/****************************************************************************
++*
++* Register the driver with device tree
++*
++***************************************************************************/
++
++static const struct of_device_id bcm2835_smi_nand_of_match[] = {
++ {.compatible = "brcm,bcm2835-smi-nand",},
++ { /* sentinel */ }
++};
++
++MODULE_DEVICE_TABLE(of, bcm2835_smi_nand_of_match);
++
++static struct platform_driver bcm2835_smi_nand_driver = {
++ .probe = bcm2835_smi_nand_probe,
++ .remove = bcm2835_smi_nand_remove,
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ .of_match_table = bcm2835_smi_nand_of_match,
++ },
++};
++
++module_platform_driver(bcm2835_smi_nand_driver);
++
++MODULE_ALIAS("platform:smi-nand-bcm2835");
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION
++ ("Driver for NAND chips using Broadcom Secondary Memory Interface");
++MODULE_AUTHOR("Luke Wren <luke@raspberrypi.org>");
diff --git a/target/linux/brcm2708/patches-4.4/0041-Add-SMI-driver.patch b/target/linux/brcm2708/patches-4.4/0041-Add-SMI-driver.patch
deleted file mode 100644
index b2a2b008f0..0000000000
--- a/target/linux/brcm2708/patches-4.4/0041-Add-SMI-driver.patch
+++ /dev/null
@@ -1,1930 +0,0 @@
-From 6609b15c34f26f34b4b49e7726693a1de321078c Mon Sep 17 00:00:00 2001
-From: Luke Wren <wren6991@gmail.com>
-Date: Sat, 5 Sep 2015 01:14:45 +0100
-Subject: [PATCH 041/170] Add SMI driver
-
-Signed-off-by: Luke Wren <wren6991@gmail.com>
----
- .../bindings/misc/brcm,bcm2835-smi-dev.txt | 17 +
- .../devicetree/bindings/misc/brcm,bcm2835-smi.txt | 48 +
- drivers/char/broadcom/Kconfig | 8 +
- drivers/char/broadcom/Makefile | 2 +-
- drivers/char/broadcom/bcm2835_smi_dev.c | 402 +++++++++
- drivers/misc/Kconfig | 8 +
- drivers/misc/Makefile | 1 +
- drivers/misc/bcm2835_smi.c | 985 +++++++++++++++++++++
- include/linux/broadcom/bcm2835_smi.h | 391 ++++++++
- 9 files changed, 1861 insertions(+), 1 deletion(-)
- create mode 100644 Documentation/devicetree/bindings/misc/brcm,bcm2835-smi-dev.txt
- create mode 100644 Documentation/devicetree/bindings/misc/brcm,bcm2835-smi.txt
- create mode 100644 drivers/char/broadcom/bcm2835_smi_dev.c
- create mode 100644 drivers/misc/bcm2835_smi.c
- create mode 100644 include/linux/broadcom/bcm2835_smi.h
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/misc/brcm,bcm2835-smi-dev.txt
-@@ -0,0 +1,17 @@
-+* Broadcom BCM2835 SMI character device driver.
-+
-+SMI or secondary memory interface is a peripheral specific to certain Broadcom
-+SOCs, and is helpful for talking to things like parallel-interface displays
-+and NAND flashes (in fact, most things with a parallel register interface).
-+
-+This driver adds a character device which provides a user-space interface to
-+an instance of the SMI driver.
-+
-+Required properties:
-+- compatible: "brcm,bcm2835-smi-dev"
-+- smi_handle: a phandle to the smi node.
-+
-+Optional properties:
-+- None.
-+
-+
---- /dev/null
-+++ b/Documentation/devicetree/bindings/misc/brcm,bcm2835-smi.txt
-@@ -0,0 +1,48 @@
-+* Broadcom BCM2835 SMI driver.
-+
-+SMI or secondary memory interface is a peripheral specific to certain Broadcom
-+SOCs, and is helpful for talking to things like parallel-interface displays
-+and NAND flashes (in fact, most things with a parallel register interface).
-+
-+Required properties:
-+- compatible: "brcm,bcm2835-smi"
-+- reg: Should contain location and length of SMI registers and SMI clkman regs
-+- interrupts: *the* SMI interrupt.
-+- pinctrl-names: should be "default".
-+- pinctrl-0: the phandle of the gpio pin node.
-+- brcm,smi-clock-source: the clock source for clkman
-+- brcm,smi-clock-divisor: the integer clock divisor for clkman
-+- dmas: the dma controller phandle and the DREQ number (4 on a 2835)
-+- dma-names: the name used by the driver to request its channel.
-+ Should be "rx-tx".
-+
-+Optional properties:
-+- None.
-+
-+Examples:
-+
-+8 data pin configuration:
-+
-+smi: smi@7e600000 {
-+ compatible = "brcm,bcm2835-smi";
-+ reg = <0x7e600000 0x44>, <0x7e1010b0 0x8>;
-+ interrupts = <2 16>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&smi_pins>;
-+ brcm,smi-clock-source = <6>;
-+ brcm,smi-clock-divisor = <4>;
-+ dmas = <&dma 4>;
-+ dma-names = "rx-tx";
-+
-+ status = "okay";
-+};
-+
-+smi_pins: smi_pins {
-+ brcm,pins = <2 3 4 5 6 7 8 9 10 11 12 13 14 15>;
-+ /* Alt 1: SMI */
-+ brcm,function = <5 5 5 5 5 5 5 5 5 5 5 5 5 5>;
-+ /* /CS, /WE and /OE are pulled high, as they are
-+ generally active low signals */
-+ brcm,pull = <2 2 2 2 2 2 0 0 0 0 0 0 0 0>;
-+};
-+
---- a/drivers/char/broadcom/Kconfig
-+++ b/drivers/char/broadcom/Kconfig
-@@ -41,3 +41,11 @@ config BCM2835_DEVGPIOMEM
- on the 2835. Calling mmap(/dev/gpiomem) will map the GPIO
- register page to the user's pointer.
-
-+config BCM2835_SMI_DEV
-+ tristate "Character device driver for BCM2835 Secondary Memory Interface"
-+ depends on (MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835) && BCM2835_SMI
-+ default m
-+ help
-+ This driver provides a character device interface (ioctl + read/write) to
-+ Broadcom's Secondary Memory interface. The low-level functionality is provided
-+ by the SMI driver itself.
---- a/drivers/char/broadcom/Makefile
-+++ b/drivers/char/broadcom/Makefile
-@@ -3,4 +3,4 @@ obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o
- obj-$(CONFIG_BCM_VC_SM) += vc_sm/
-
- obj-$(CONFIG_BCM2835_DEVGPIOMEM)+= bcm2835-gpiomem.o
--
-+obj-$(CONFIG_BCM2835_SMI_DEV) += bcm2835_smi_dev.o
---- /dev/null
-+++ b/drivers/char/broadcom/bcm2835_smi_dev.c
-@@ -0,0 +1,402 @@
-+/**
-+ * Character device driver for Broadcom Secondary Memory Interface
-+ *
-+ * Written by Luke Wren <luke@raspberrypi.org>
-+ * Copyright (c) 2015, Raspberry Pi (Trading) Ltd.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <linux/slab.h>
-+#include <linux/mm.h>
-+#include <linux/pagemap.h>
-+#include <linux/fs.h>
-+#include <linux/cdev.h>
-+#include <linux/fs.h>
-+
-+#include <linux/broadcom/bcm2835_smi.h>
-+
-+#define DEVICE_NAME "bcm2835-smi-dev"
-+#define DRIVER_NAME "smi-dev-bcm2835"
-+#define DEVICE_MINOR 0
-+
-+static struct cdev bcm2835_smi_cdev;
-+static dev_t bcm2835_smi_devid;
-+static struct class *bcm2835_smi_class;
-+static struct device *bcm2835_smi_dev;
-+
-+struct bcm2835_smi_dev_instance {
-+ struct device *dev;
-+};
-+
-+static struct bcm2835_smi_instance *smi_inst;
-+static struct bcm2835_smi_dev_instance *inst;
-+
-+static const char *const ioctl_names[] = {
-+ "READ_SETTINGS",
-+ "WRITE_SETTINGS",
-+ "ADDRESS"
-+};
-+
-+/****************************************************************************
-+*
-+* SMI chardev file ops
-+*
-+***************************************************************************/
-+static long
-+bcm2835_smi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-+{
-+ long ret = 0;
-+
-+ dev_info(inst->dev, "serving ioctl...");
-+
-+ switch (cmd) {
-+ case BCM2835_SMI_IOC_GET_SETTINGS:{
-+ struct smi_settings *settings;
-+
-+ dev_info(inst->dev, "Reading SMI settings to user.");
-+ settings = bcm2835_smi_get_settings_from_regs(smi_inst);
-+ if (copy_to_user((void *)arg, settings,
-+ sizeof(struct smi_settings)))
-+ dev_err(inst->dev, "settings copy failed.");
-+ break;
-+ }
-+ case BCM2835_SMI_IOC_WRITE_SETTINGS:{
-+ struct smi_settings *settings;
-+
-+ dev_info(inst->dev, "Setting user's SMI settings.");
-+ settings = bcm2835_smi_get_settings_from_regs(smi_inst);
-+ if (copy_from_user(settings, (void *)arg,
-+ sizeof(struct smi_settings)))
-+ dev_err(inst->dev, "settings copy failed.");
-+ else
-+ bcm2835_smi_set_regs_from_settings(smi_inst);
-+ break;
-+ }
-+ case BCM2835_SMI_IOC_ADDRESS:
-+ dev_info(inst->dev, "SMI address set: 0x%02x", (int)arg);
-+ bcm2835_smi_set_address(smi_inst, arg);
-+ break;
-+ default:
-+ dev_err(inst->dev, "invalid ioctl cmd: %d", cmd);
-+ ret = -ENOTTY;
-+ break;
-+ }
-+
-+ return ret;
-+}
-+
-+static int bcm2835_smi_open(struct inode *inode, struct file *file)
-+{
-+ int dev = iminor(inode);
-+
-+ dev_dbg(inst->dev, "SMI device opened.");
-+
-+ if (dev != DEVICE_MINOR) {
-+ dev_err(inst->dev,
-+ "bcm2835_smi_release: Unknown minor device: %d",
-+ dev);
-+ return -ENXIO;
-+ }
-+
-+ return 0;
-+}
-+
-+static int bcm2835_smi_release(struct inode *inode, struct file *file)
-+{
-+ int dev = iminor(inode);
-+
-+ if (dev != DEVICE_MINOR) {
-+ dev_err(inst->dev,
-+ "bcm2835_smi_release: Unknown minor device %d", dev);
-+ return -ENXIO;
-+ }
-+
-+ return 0;
-+}
-+
-+static ssize_t dma_bounce_user(
-+ enum dma_transfer_direction dma_dir,
-+ char __user *user_ptr,
-+ size_t count,
-+ struct bcm2835_smi_bounce_info *bounce)
-+{
-+ int chunk_size;
-+ int chunk_no = 0;
-+ int count_left = count;
-+
-+ while (count_left) {
-+ int rv;
-+ void *buf;
-+
-+ /* Wait for current chunk to complete: */
-+ if (down_timeout(&bounce->callback_sem,
-+ msecs_to_jiffies(1000))) {
-+ dev_err(inst->dev, "DMA bounce timed out");
-+ count -= (count_left);
-+ break;
-+ }
-+
-+ if (bounce->callback_sem.count >= DMA_BOUNCE_BUFFER_COUNT - 1)
-+ dev_err(inst->dev, "WARNING: Ring buffer overflow");
-+ chunk_size = count_left > DMA_BOUNCE_BUFFER_SIZE ?
-+ DMA_BOUNCE_BUFFER_SIZE : count_left;
-+ buf = bounce->buffer[chunk_no % DMA_BOUNCE_BUFFER_COUNT];
-+ if (dma_dir == DMA_DEV_TO_MEM)
-+ rv = copy_to_user(user_ptr, buf, chunk_size);
-+ else
-+ rv = copy_from_user(buf, user_ptr, chunk_size);
-+ if (rv)
-+ dev_err(inst->dev, "copy_*_user() failed!: %d", rv);
-+ user_ptr += chunk_size;
-+ count_left -= chunk_size;
-+ chunk_no++;
-+ }
-+ return count;
-+}
-+
-+static ssize_t
-+bcm2835_read_file(struct file *f, char __user *user_ptr,
-+ size_t count, loff_t *offs)
-+{
-+ int odd_bytes;
-+
-+ dev_dbg(inst->dev, "User reading %d bytes from SMI.", count);
-+ /* We don't want to DMA a number of bytes % 4 != 0 (32 bit FIFO) */
-+ if (count > DMA_THRESHOLD_BYTES)
-+ odd_bytes = count & 0x3;
-+ else
-+ odd_bytes = count;
-+ count -= odd_bytes;
-+ if (count) {
-+ struct bcm2835_smi_bounce_info *bounce;
-+
-+ count = bcm2835_smi_user_dma(smi_inst,
-+ DMA_DEV_TO_MEM, user_ptr, count,
-+ &bounce);
-+ if (count)
-+ count = dma_bounce_user(DMA_DEV_TO_MEM, user_ptr,
-+ count, bounce);
-+ }
-+ if (odd_bytes) {
-+ /* Read from FIFO directly if not using DMA */
-+ uint8_t buf[DMA_THRESHOLD_BYTES];
-+
-+ bcm2835_smi_read_buf(smi_inst, buf, odd_bytes);
-+ if (copy_to_user(user_ptr, buf, odd_bytes))
-+ dev_err(inst->dev, "copy_to_user() failed.");
-+ count += odd_bytes;
-+
-+ }
-+ return count;
-+}
-+
-+static ssize_t
-+bcm2835_write_file(struct file *f, const char __user *user_ptr,
-+ size_t count, loff_t *offs)
-+{
-+ int odd_bytes;
-+
-+ dev_dbg(inst->dev, "User writing %d bytes to SMI.", count);
-+ if (count > DMA_THRESHOLD_BYTES)
-+ odd_bytes = count & 0x3;
-+ else
-+ odd_bytes = count;
-+ count -= odd_bytes;
-+ if (count) {
-+ struct bcm2835_smi_bounce_info *bounce;
-+
-+ count = bcm2835_smi_user_dma(smi_inst,
-+ DMA_MEM_TO_DEV, (char __user *)user_ptr, count,
-+ &bounce);
-+ if (count)
-+ count = dma_bounce_user(DMA_MEM_TO_DEV,
-+ (char __user *)user_ptr,
-+ count, bounce);
-+ }
-+ if (odd_bytes) {
-+ uint8_t buf[DMA_THRESHOLD_BYTES];
-+
-+ if (copy_from_user(buf, user_ptr, odd_bytes))
-+ dev_err(inst->dev, "copy_from_user() failed.");
-+ else
-+ bcm2835_smi_write_buf(smi_inst, buf, odd_bytes);
-+ count += odd_bytes;
-+ }
-+ return count;
-+}
-+
-+static const struct file_operations
-+bcm2835_smi_fops = {
-+ .owner = THIS_MODULE,
-+ .unlocked_ioctl = bcm2835_smi_ioctl,
-+ .open = bcm2835_smi_open,
-+ .release = bcm2835_smi_release,
-+ .read = bcm2835_read_file,
-+ .write = bcm2835_write_file,
-+};
-+
-+
-+/****************************************************************************
-+*
-+* bcm2835_smi_probe - called when the driver is loaded.
-+*
-+***************************************************************************/
-+
-+static int bcm2835_smi_dev_probe(struct platform_device *pdev)
-+{
-+ int err;
-+ void *ptr_err;
-+ struct device *dev = &pdev->dev;
-+ struct device_node *node = dev->of_node, *smi_node;
-+
-+ if (!node) {
-+ dev_err(dev, "No device tree node supplied!");
-+ return -EINVAL;
-+ }
-+
-+ smi_node = of_parse_phandle(node, "smi_handle", 0);
-+
-+ if (!smi_node) {
-+ dev_err(dev, "No such property: smi_handle");
-+ return -ENXIO;
-+ }
-+
-+ smi_inst = bcm2835_smi_get(smi_node);
-+
-+ if (!smi_inst)
-+ return -EPROBE_DEFER;
-+
-+ /* Allocate buffers and instance data */
-+
-+ inst = devm_kzalloc(dev, sizeof(*inst), GFP_KERNEL);
-+
-+ if (!inst)
-+ return -ENOMEM;
-+
-+ inst->dev = dev;
-+
-+ /* Create character device entries */
-+
-+ err = alloc_chrdev_region(&bcm2835_smi_devid,
-+ DEVICE_MINOR, 1, DEVICE_NAME);
-+ if (err != 0) {
-+ dev_err(inst->dev, "unable to allocate device number");
-+ return -ENOMEM;
-+ }
-+ cdev_init(&bcm2835_smi_cdev, &bcm2835_smi_fops);
-+ bcm2835_smi_cdev.owner = THIS_MODULE;
-+ err = cdev_add(&bcm2835_smi_cdev, bcm2835_smi_devid, 1);
-+ if (err != 0) {
-+ dev_err(inst->dev, "unable to register device");
-+ err = -ENOMEM;
-+ goto failed_cdev_add;
-+ }
-+
-+ /* Create sysfs entries */
-+
-+ bcm2835_smi_class = class_create(THIS_MODULE, DEVICE_NAME);
-+ ptr_err = bcm2835_smi_class;
-+ if (IS_ERR(ptr_err))
-+ goto failed_class_create;
-+
-+ bcm2835_smi_dev = device_create(bcm2835_smi_class, NULL,
-+ bcm2835_smi_devid, NULL,
-+ "smi");
-+ ptr_err = bcm2835_smi_dev;
-+ if (IS_ERR(ptr_err))
-+ goto failed_device_create;
-+
-+ dev_info(inst->dev, "initialised");
-+
-+ return 0;
-+
-+failed_device_create:
-+ class_destroy(bcm2835_smi_class);
-+failed_class_create:
-+ cdev_del(&bcm2835_smi_cdev);
-+ err = PTR_ERR(ptr_err);
-+failed_cdev_add:
-+ unregister_chrdev_region(bcm2835_smi_devid, 1);
-+ dev_err(dev, "could not load bcm2835_smi_dev");
-+ return err;
-+}
-+
-+/****************************************************************************
-+*
-+* bcm2835_smi_remove - called when the driver is unloaded.
-+*
-+***************************************************************************/
-+
-+static int bcm2835_smi_dev_remove(struct platform_device *pdev)
-+{
-+ device_destroy(bcm2835_smi_class, bcm2835_smi_devid);
-+ class_destroy(bcm2835_smi_class);
-+ cdev_del(&bcm2835_smi_cdev);
-+ unregister_chrdev_region(bcm2835_smi_devid, 1);
-+
-+ dev_info(inst->dev, "SMI character dev removed - OK");
-+ return 0;
-+}
-+
-+/****************************************************************************
-+*
-+* Register the driver with device tree
-+*
-+***************************************************************************/
-+
-+static const struct of_device_id bcm2835_smi_dev_of_match[] = {
-+ {.compatible = "brcm,bcm2835-smi-dev",},
-+ { /* sentinel */ },
-+};
-+
-+MODULE_DEVICE_TABLE(of, bcm2835_smi_dev_of_match);
-+
-+static struct platform_driver bcm2835_smi_dev_driver = {
-+ .probe = bcm2835_smi_dev_probe,
-+ .remove = bcm2835_smi_dev_remove,
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ .of_match_table = bcm2835_smi_dev_of_match,
-+ },
-+};
-+
-+module_platform_driver(bcm2835_smi_dev_driver);
-+
-+MODULE_ALIAS("platform:smi-dev-bcm2835");
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION(
-+ "Character device driver for BCM2835's secondary memory interface");
-+MODULE_AUTHOR("Luke Wren <luke@raspberrypi.org>");
---- a/drivers/misc/Kconfig
-+++ b/drivers/misc/Kconfig
-@@ -10,6 +10,14 @@ config SENSORS_LIS3LV02D
- select INPUT_POLLDEV
- default n
-
-+config BCM2835_SMI
-+ tristate "Broadcom 283x Secondary Memory Interface driver"
-+ depends on MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835
-+ default m
-+ help
-+ Driver for enabling and using Broadcom's Secondary/Slow Memory Interface.
-+ Appears as /dev/bcm2835_smi. For ioctl interface see drivers/misc/bcm2835_smi.h
-+
- config AD525X_DPOT
- tristate "Analog Devices Digital Potentiometers"
- depends on (I2C || SPI) && SYSFS
---- a/drivers/misc/Makefile
-+++ b/drivers/misc/Makefile
-@@ -9,6 +9,7 @@ obj-$(CONFIG_AD525X_DPOT_SPI) += ad525x_
- obj-$(CONFIG_INTEL_MID_PTI) += pti.o
- obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
- obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o
-+obj-$(CONFIG_BCM2835_SMI) += bcm2835_smi.o
- obj-$(CONFIG_BMP085) += bmp085.o
- obj-$(CONFIG_BMP085_I2C) += bmp085-i2c.o
- obj-$(CONFIG_BMP085_SPI) += bmp085-spi.o
---- /dev/null
-+++ b/drivers/misc/bcm2835_smi.c
-@@ -0,0 +1,985 @@
-+/**
-+ * Broadcom Secondary Memory Interface driver
-+ *
-+ * Written by Luke Wren <luke@raspberrypi.org>
-+ * Copyright (c) 2015, Raspberry Pi (Trading) Ltd.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <linux/of_address.h>
-+#include <linux/of_platform.h>
-+#include <linux/mm.h>
-+#include <linux/slab.h>
-+#include <linux/pagemap.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/dmaengine.h>
-+#include <linux/semaphore.h>
-+#include <linux/spinlock.h>
-+#include <linux/io.h>
-+
-+#define BCM2835_SMI_IMPLEMENTATION
-+#include <linux/broadcom/bcm2835_smi.h>
-+
-+#define DRIVER_NAME "smi-bcm2835"
-+
-+#define N_PAGES_FROM_BYTES(n) ((n + PAGE_SIZE-1) / PAGE_SIZE)
-+
-+#define DMA_WRITE_TO_MEM true
-+#define DMA_READ_FROM_MEM false
-+
-+struct bcm2835_smi_instance {
-+ struct device *dev;
-+ struct smi_settings settings;
-+ __iomem void *smi_regs_ptr, *cm_smi_regs_ptr;
-+ dma_addr_t smi_regs_busaddr;
-+
-+ struct dma_chan *dma_chan;
-+ struct dma_slave_config dma_config;
-+
-+ struct bcm2835_smi_bounce_info bounce;
-+
-+ struct scatterlist buffer_sgl;
-+
-+ int clock_source;
-+ int clock_divisor;
-+
-+ /* Sometimes we are called into in an atomic context (e.g. by
-+ JFFS2 + MTD) so we can't use a mutex */
-+ spinlock_t transaction_lock;
-+};
-+
-+/****************************************************************************
-+*
-+* SMI clock manager setup
-+*
-+***************************************************************************/
-+
-+static inline void write_smi_cm_reg(struct bcm2835_smi_instance *inst,
-+ u32 val, unsigned reg)
-+{
-+ writel(CM_PWD | val, inst->cm_smi_regs_ptr + reg);
-+}
-+
-+static inline u32 read_smi_cm_reg(struct bcm2835_smi_instance *inst,
-+ unsigned reg)
-+{
-+ return readl(inst->cm_smi_regs_ptr + reg);
-+}
-+
-+static void smi_setup_clock(struct bcm2835_smi_instance *inst)
-+{
-+ dev_dbg(inst->dev, "Setting up clock...");
-+ /* Disable SMI clock and wait for it to stop. */
-+ write_smi_cm_reg(inst, 0, CM_SMI_CTL);
-+ while (read_smi_cm_reg(inst, CM_SMI_CTL) & CM_SMI_CTL_BUSY)
-+ ;
-+
-+ write_smi_cm_reg(inst, (inst->clock_divisor << CM_SMI_DIV_DIVI_OFFS),
-+ CM_SMI_DIV);
-+ write_smi_cm_reg(inst, (inst->clock_source << CM_SMI_CTL_SRC_OFFS),
-+ CM_SMI_CTL);
-+
-+ /* Enable the clock */
-+ write_smi_cm_reg(inst, (inst->clock_source << CM_SMI_CTL_SRC_OFFS) |
-+ CM_SMI_CTL_ENAB, CM_SMI_CTL);
-+}
-+
-+/****************************************************************************
-+*
-+* SMI peripheral setup
-+*
-+***************************************************************************/
-+
-+static inline void write_smi_reg(struct bcm2835_smi_instance *inst,
-+ u32 val, unsigned reg)
-+{
-+ writel(val, inst->smi_regs_ptr + reg);
-+}
-+
-+static inline u32 read_smi_reg(struct bcm2835_smi_instance *inst, unsigned reg)
-+{
-+ return readl(inst->smi_regs_ptr + reg);
-+}
-+
-+/* Token-paste macro for e.g SMIDSR_RSTROBE -> value of SMIDSR_RSTROBE_MASK */
-+#define _CONCAT(x, y) x##y
-+#define CONCAT(x, y) _CONCAT(x, y)
-+
-+#define SET_BIT_FIELD(dest, field, bits) ((dest) = \
-+ ((dest) & ~CONCAT(field, _MASK)) | (((bits) << CONCAT(field, _OFFS))& \
-+ CONCAT(field, _MASK)))
-+#define GET_BIT_FIELD(src, field) (((src) & \
-+ CONCAT(field, _MASK)) >> CONCAT(field, _OFFS))
-+
-+static void smi_dump_context_labelled(struct bcm2835_smi_instance *inst,
-+ const char *label)
-+{
-+ dev_err(inst->dev, "SMI context dump: %s", label);
-+ dev_err(inst->dev, "SMICS: 0x%08x", read_smi_reg(inst, SMICS));
-+ dev_err(inst->dev, "SMIL: 0x%08x", read_smi_reg(inst, SMIL));
-+ dev_err(inst->dev, "SMIDSR: 0x%08x", read_smi_reg(inst, SMIDSR0));
-+ dev_err(inst->dev, "SMIDSW: 0x%08x", read_smi_reg(inst, SMIDSW0));
-+ dev_err(inst->dev, "SMIDC: 0x%08x", read_smi_reg(inst, SMIDC));
-+ dev_err(inst->dev, "SMIFD: 0x%08x", read_smi_reg(inst, SMIFD));
-+ dev_err(inst->dev, " ");
-+}
-+
-+static inline void smi_dump_context(struct bcm2835_smi_instance *inst)
-+{
-+ smi_dump_context_labelled(inst, "");
-+}
-+
-+static void smi_get_default_settings(struct bcm2835_smi_instance *inst)
-+{
-+ struct smi_settings *settings = &inst->settings;
-+
-+ settings->data_width = SMI_WIDTH_16BIT;
-+ settings->pack_data = true;
-+
-+ settings->read_setup_time = 1;
-+ settings->read_hold_time = 1;
-+ settings->read_pace_time = 1;
-+ settings->read_strobe_time = 3;
-+
-+ settings->write_setup_time = settings->read_setup_time;
-+ settings->write_hold_time = settings->read_hold_time;
-+ settings->write_pace_time = settings->read_pace_time;
-+ settings->write_strobe_time = settings->read_strobe_time;
-+
-+ settings->dma_enable = true;
-+ settings->dma_passthrough_enable = false;
-+ settings->dma_read_thresh = 0x01;
-+ settings->dma_write_thresh = 0x3f;
-+ settings->dma_panic_read_thresh = 0x20;
-+ settings->dma_panic_write_thresh = 0x20;
-+}
-+
-+void bcm2835_smi_set_regs_from_settings(struct bcm2835_smi_instance *inst)
-+{
-+ struct smi_settings *settings = &inst->settings;
-+ int smidsr_temp = 0, smidsw_temp = 0, smics_temp,
-+ smidcs_temp, smidc_temp = 0;
-+
-+ spin_lock(&inst->transaction_lock);
-+
-+ /* temporarily disable the peripheral: */
-+ smics_temp = read_smi_reg(inst, SMICS);
-+ write_smi_reg(inst, 0, SMICS);
-+ smidcs_temp = read_smi_reg(inst, SMIDCS);
-+ write_smi_reg(inst, 0, SMIDCS);
-+
-+ if (settings->pack_data)
-+ smics_temp |= SMICS_PXLDAT;
-+ else
-+ smics_temp &= ~SMICS_PXLDAT;
-+
-+ SET_BIT_FIELD(smidsr_temp, SMIDSR_RWIDTH, settings->data_width);
-+ SET_BIT_FIELD(smidsr_temp, SMIDSR_RSETUP, settings->read_setup_time);
-+ SET_BIT_FIELD(smidsr_temp, SMIDSR_RHOLD, settings->read_hold_time);
-+ SET_BIT_FIELD(smidsr_temp, SMIDSR_RPACE, settings->read_pace_time);
-+ SET_BIT_FIELD(smidsr_temp, SMIDSR_RSTROBE, settings->read_strobe_time);
-+ write_smi_reg(inst, smidsr_temp, SMIDSR0);
-+
-+ SET_BIT_FIELD(smidsw_temp, SMIDSW_WWIDTH, settings->data_width);
-+ if (settings->data_width == SMI_WIDTH_8BIT)
-+ smidsw_temp |= SMIDSW_WSWAP;
-+ else
-+ smidsw_temp &= ~SMIDSW_WSWAP;
-+ SET_BIT_FIELD(smidsw_temp, SMIDSW_WSETUP, settings->write_setup_time);
-+ SET_BIT_FIELD(smidsw_temp, SMIDSW_WHOLD, settings->write_hold_time);
-+ SET_BIT_FIELD(smidsw_temp, SMIDSW_WPACE, settings->write_pace_time);
-+ SET_BIT_FIELD(smidsw_temp, SMIDSW_WSTROBE,
-+ settings->write_strobe_time);
-+ write_smi_reg(inst, smidsw_temp, SMIDSW0);
-+
-+ SET_BIT_FIELD(smidc_temp, SMIDC_REQR, settings->dma_read_thresh);
-+ SET_BIT_FIELD(smidc_temp, SMIDC_REQW, settings->dma_write_thresh);
-+ SET_BIT_FIELD(smidc_temp, SMIDC_PANICR,
-+ settings->dma_panic_read_thresh);
-+ SET_BIT_FIELD(smidc_temp, SMIDC_PANICW,
-+ settings->dma_panic_write_thresh);
-+ if (settings->dma_passthrough_enable) {
-+ smidc_temp |= SMIDC_DMAP;
-+ smidsr_temp |= SMIDSR_RDREQ;
-+ write_smi_reg(inst, smidsr_temp, SMIDSR0);
-+ smidsw_temp |= SMIDSW_WDREQ;
-+ write_smi_reg(inst, smidsw_temp, SMIDSW0);
-+ } else
-+ smidc_temp &= ~SMIDC_DMAP;
-+ if (settings->dma_enable)
-+ smidc_temp |= SMIDC_DMAEN;
-+ else
-+ smidc_temp &= ~SMIDC_DMAEN;
-+
-+ write_smi_reg(inst, smidc_temp, SMIDC);
-+
-+ /* re-enable (if was previously enabled) */
-+ write_smi_reg(inst, smics_temp, SMICS);
-+ write_smi_reg(inst, smidcs_temp, SMIDCS);
-+
-+ spin_unlock(&inst->transaction_lock);
-+}
-+EXPORT_SYMBOL(bcm2835_smi_set_regs_from_settings);
-+
-+struct smi_settings *bcm2835_smi_get_settings_from_regs
-+ (struct bcm2835_smi_instance *inst)
-+{
-+ struct smi_settings *settings = &inst->settings;
-+ int smidsr, smidsw, smidc;
-+
-+ spin_lock(&inst->transaction_lock);
-+
-+ smidsr = read_smi_reg(inst, SMIDSR0);
-+ smidsw = read_smi_reg(inst, SMIDSW0);
-+ smidc = read_smi_reg(inst, SMIDC);
-+
-+ settings->pack_data = (read_smi_reg(inst, SMICS) & SMICS_PXLDAT) ?
-+ true : false;
-+
-+ settings->data_width = GET_BIT_FIELD(smidsr, SMIDSR_RWIDTH);
-+ settings->read_setup_time = GET_BIT_FIELD(smidsr, SMIDSR_RSETUP);
-+ settings->read_hold_time = GET_BIT_FIELD(smidsr, SMIDSR_RHOLD);
-+ settings->read_pace_time = GET_BIT_FIELD(smidsr, SMIDSR_RPACE);
-+ settings->read_strobe_time = GET_BIT_FIELD(smidsr, SMIDSR_RSTROBE);
-+
-+ settings->write_setup_time = GET_BIT_FIELD(smidsw, SMIDSW_WSETUP);
-+ settings->write_hold_time = GET_BIT_FIELD(smidsw, SMIDSW_WHOLD);
-+ settings->write_pace_time = GET_BIT_FIELD(smidsw, SMIDSW_WPACE);
-+ settings->write_strobe_time = GET_BIT_FIELD(smidsw, SMIDSW_WSTROBE);
-+
-+ settings->dma_read_thresh = GET_BIT_FIELD(smidc, SMIDC_REQR);
-+ settings->dma_write_thresh = GET_BIT_FIELD(smidc, SMIDC_REQW);
-+ settings->dma_panic_read_thresh = GET_BIT_FIELD(smidc, SMIDC_PANICR);
-+ settings->dma_panic_write_thresh = GET_BIT_FIELD(smidc, SMIDC_PANICW);
-+ settings->dma_passthrough_enable = (smidc & SMIDC_DMAP) ? true : false;
-+ settings->dma_enable = (smidc & SMIDC_DMAEN) ? true : false;
-+
-+ spin_unlock(&inst->transaction_lock);
-+
-+ return settings;
-+}
-+EXPORT_SYMBOL(bcm2835_smi_get_settings_from_regs);
-+
-+static inline void smi_set_address(struct bcm2835_smi_instance *inst,
-+ unsigned int address)
-+{
-+ int smia_temp = 0, smida_temp = 0;
-+
-+ SET_BIT_FIELD(smia_temp, SMIA_ADDR, address);
-+ SET_BIT_FIELD(smida_temp, SMIDA_ADDR, address);
-+
-+ /* Write to both address registers - user doesn't care whether we're
-+ doing programmed or direct transfers. */
-+ write_smi_reg(inst, smia_temp, SMIA);
-+ write_smi_reg(inst, smida_temp, SMIDA);
-+}
-+
-+static void smi_setup_regs(struct bcm2835_smi_instance *inst)
-+{
-+
-+ dev_dbg(inst->dev, "Initialising SMI registers...");
-+ /* Disable the peripheral if already enabled */
-+ write_smi_reg(inst, 0, SMICS);
-+ write_smi_reg(inst, 0, SMIDCS);
-+
-+ smi_get_default_settings(inst);
-+ bcm2835_smi_set_regs_from_settings(inst);
-+ smi_set_address(inst, 0);
-+
-+ write_smi_reg(inst, read_smi_reg(inst, SMICS) | SMICS_ENABLE, SMICS);
-+ write_smi_reg(inst, read_smi_reg(inst, SMIDCS) | SMIDCS_ENABLE,
-+ SMIDCS);
-+}
-+
-+/****************************************************************************
-+*
-+* Low-level SMI access functions
-+* Other modules should use the exported higher-level functions e.g.
-+* bcm2835_smi_write_buf() unless they have a good reason to use these
-+*
-+***************************************************************************/
-+
-+static inline uint32_t smi_read_single_word(struct bcm2835_smi_instance *inst)
-+{
-+ int timeout = 0;
-+
-+ write_smi_reg(inst, SMIDCS_ENABLE, SMIDCS);
-+ write_smi_reg(inst, SMIDCS_ENABLE | SMIDCS_START, SMIDCS);
-+ /* Make sure things happen in the right order...*/
-+ mb();
-+ while (!(read_smi_reg(inst, SMIDCS) & SMIDCS_DONE) &&
-+ ++timeout < 10000)
-+ ;
-+ if (timeout < 10000)
-+ return read_smi_reg(inst, SMIDD);
-+
-+ dev_err(inst->dev,
-+ "SMI direct read timed out (is the clock set up correctly?)");
-+ return 0;
-+}
-+
-+static inline void smi_write_single_word(struct bcm2835_smi_instance *inst,
-+ uint32_t data)
-+{
-+ int timeout = 0;
-+
-+ write_smi_reg(inst, SMIDCS_ENABLE | SMIDCS_WRITE, SMIDCS);
-+ write_smi_reg(inst, data, SMIDD);
-+ write_smi_reg(inst, SMIDCS_ENABLE | SMIDCS_WRITE | SMIDCS_START,
-+ SMIDCS);
-+
-+ while (!(read_smi_reg(inst, SMIDCS) & SMIDCS_DONE) &&
-+ ++timeout < 10000)
-+ ;
-+ if (timeout >= 10000)
-+ dev_err(inst->dev,
-+ "SMI direct write timed out (is the clock set up correctly?)");
-+}
-+
-+/* Initiates a programmed read into the read FIFO. It is up to the caller to
-+ * read data from the FIFO - either via paced DMA transfer,
-+ * or polling SMICS_RXD to check whether data is available.
-+ * SMICS_ACTIVE will go low upon completion. */
-+static void smi_init_programmed_read(struct bcm2835_smi_instance *inst,
-+ int num_transfers)
-+{
-+ int smics_temp;
-+
-+ /* Disable the peripheral: */
-+ smics_temp = read_smi_reg(inst, SMICS) & ~(SMICS_ENABLE | SMICS_WRITE);
-+ write_smi_reg(inst, smics_temp, SMICS);
-+ while (read_smi_reg(inst, SMICS) & SMICS_ENABLE)
-+ ;
-+
-+ /* Program the transfer count: */
-+ write_smi_reg(inst, num_transfers, SMIL);
-+
-+ /* re-enable and start: */
-+ smics_temp |= SMICS_ENABLE;
-+ write_smi_reg(inst, smics_temp, SMICS);
-+ smics_temp |= SMICS_CLEAR;
-+ /* Just to be certain: */
-+ mb();
-+ while (read_smi_reg(inst, SMICS) & SMICS_ACTIVE)
-+ ;
-+ write_smi_reg(inst, smics_temp, SMICS);
-+ smics_temp |= SMICS_START;
-+ write_smi_reg(inst, smics_temp, SMICS);
-+}
-+
-+/* Initiates a programmed write sequence, using data from the write FIFO.
-+ * It is up to the caller to initiate a DMA transfer before calling,
-+ * or use another method to keep the write FIFO topped up.
-+ * SMICS_ACTIVE will go low upon completion.
-+ */
-+static void smi_init_programmed_write(struct bcm2835_smi_instance *inst,
-+ int num_transfers)
-+{
-+ int smics_temp;
-+
-+ /* Disable the peripheral: */
-+ smics_temp = read_smi_reg(inst, SMICS) & ~SMICS_ENABLE;
-+ write_smi_reg(inst, smics_temp, SMICS);
-+ while (read_smi_reg(inst, SMICS) & SMICS_ENABLE)
-+ ;
-+
-+ /* Program the transfer count: */
-+ write_smi_reg(inst, num_transfers, SMIL);
-+
-+ /* setup, re-enable and start: */
-+ smics_temp |= SMICS_WRITE | SMICS_ENABLE;
-+ write_smi_reg(inst, smics_temp, SMICS);
-+ smics_temp |= SMICS_START;
-+ write_smi_reg(inst, smics_temp, SMICS);
-+}
-+
-+/* Initiate a read and then poll FIFO for data, reading out as it appears. */
-+static void smi_read_fifo(struct bcm2835_smi_instance *inst,
-+ uint32_t *dest, int n_bytes)
-+{
-+ if (read_smi_reg(inst, SMICS) & SMICS_RXD) {
-+ smi_dump_context_labelled(inst,
-+ "WARNING: read FIFO not empty at start of read call.");
-+ while (read_smi_reg(inst, SMICS))
-+ ;
-+ }
-+
-+ /* Dispatch the read: */
-+ if (inst->settings.data_width == SMI_WIDTH_8BIT)
-+ smi_init_programmed_read(inst, n_bytes);
-+ else if (inst->settings.data_width == SMI_WIDTH_16BIT)
-+ smi_init_programmed_read(inst, n_bytes / 2);
-+ else {
-+ dev_err(inst->dev, "Unsupported data width for read.");
-+ return;
-+ }
-+
-+ /* Poll FIFO to keep it empty */
-+ while (!(read_smi_reg(inst, SMICS) & SMICS_DONE))
-+ if (read_smi_reg(inst, SMICS) & SMICS_RXD)
-+ *dest++ = read_smi_reg(inst, SMID);
-+
-+ /* Ensure that the FIFO is emptied */
-+ if (read_smi_reg(inst, SMICS) & SMICS_RXD) {
-+ int fifo_count;
-+
-+ fifo_count = GET_BIT_FIELD(read_smi_reg(inst, SMIFD),
-+ SMIFD_FCNT);
-+ while (fifo_count--)
-+ *dest++ = read_smi_reg(inst, SMID);
-+ }
-+
-+ if (!(read_smi_reg(inst, SMICS) & SMICS_DONE))
-+ smi_dump_context_labelled(inst,
-+ "WARNING: transaction finished but done bit not set.");
-+
-+ if (read_smi_reg(inst, SMICS) & SMICS_RXD)
-+ smi_dump_context_labelled(inst,
-+ "WARNING: read FIFO not empty at end of read call.");
-+
-+}
-+
-+/* Initiate a write, and then keep the FIFO topped up. */
-+static void smi_write_fifo(struct bcm2835_smi_instance *inst,
-+ uint32_t *src, int n_bytes)
-+{
-+ int i, timeout = 0;
-+
-+ /* Empty FIFOs if not already so */
-+ if (!(read_smi_reg(inst, SMICS) & SMICS_TXE)) {
-+ smi_dump_context_labelled(inst,
-+ "WARNING: write fifo not empty at start of write call.");
-+ write_smi_reg(inst, read_smi_reg(inst, SMICS) | SMICS_CLEAR,
-+ SMICS);
-+ }
-+
-+ /* Initiate the transfer */
-+ if (inst->settings.data_width == SMI_WIDTH_8BIT)
-+ smi_init_programmed_write(inst, n_bytes);
-+ else if (inst->settings.data_width == SMI_WIDTH_16BIT)
-+ smi_init_programmed_write(inst, n_bytes / 2);
-+ else {
-+ dev_err(inst->dev, "Unsupported data width for write.");
-+ return;
-+ }
-+ /* Fill the FIFO: */
-+ for (i = 0; i < (n_bytes - 1) / 4 + 1; ++i) {
-+ while (!(read_smi_reg(inst, SMICS) & SMICS_TXD))
-+ ;
-+ write_smi_reg(inst, *src++, SMID);
-+ }
-+ /* Busy wait... */
-+ while (!(read_smi_reg(inst, SMICS) & SMICS_DONE) && ++timeout <
-+ 1000000)
-+ ;
-+ if (timeout >= 1000000)
-+ smi_dump_context_labelled(inst,
-+ "Timed out on write operation!");
-+ if (!(read_smi_reg(inst, SMICS) & SMICS_TXE))
-+ smi_dump_context_labelled(inst,
-+ "WARNING: FIFO not empty at end of write operation.");
-+}
-+
-+/****************************************************************************
-+*
-+* SMI DMA operations
-+*
-+***************************************************************************/
-+
-+/* Disable SMI and put it into the correct direction before doing DMA setup.
-+ Stops spurious DREQs during setup. Peripheral is re-enabled by init_*() */
-+static void smi_disable(struct bcm2835_smi_instance *inst,
-+ enum dma_transfer_direction direction)
-+{
-+ int smics_temp = read_smi_reg(inst, SMICS) & ~SMICS_ENABLE;
-+
-+ if (direction == DMA_DEV_TO_MEM)
-+ smics_temp &= ~SMICS_WRITE;
-+ else
-+ smics_temp |= SMICS_WRITE;
-+ write_smi_reg(inst, smics_temp, SMICS);
-+ while (read_smi_reg(inst, SMICS) & SMICS_ACTIVE)
-+ ;
-+}
-+
-+static struct scatterlist *smi_scatterlist_from_buffer(
-+ struct bcm2835_smi_instance *inst,
-+ dma_addr_t buf,
-+ size_t len,
-+ struct scatterlist *sg)
-+{
-+ sg_init_table(sg, 1);
-+ sg_dma_address(sg) = buf;
-+ sg_dma_len(sg) = len;
-+ return sg;
-+}
-+
-+static void smi_dma_callback_user_copy(void *param)
-+{
-+ /* Notify the bottom half that a chunk is ready for user copy */
-+ struct bcm2835_smi_instance *inst =
-+ (struct bcm2835_smi_instance *)param;
-+
-+ up(&inst->bounce.callback_sem);
-+}
-+
-+/* Creates a descriptor, assigns the given callback, and submits the
-+ descriptor to dmaengine. Does not block - can queue up multiple
-+ descriptors and then wait for them all to complete.
-+ sg_len is the number of control blocks, NOT the number of bytes.
-+ dir can be DMA_MEM_TO_DEV or DMA_DEV_TO_MEM.
-+ callback can be NULL - in this case it is not called. */
-+static inline struct dma_async_tx_descriptor *smi_dma_submit_sgl(
-+ struct bcm2835_smi_instance *inst,
-+ struct scatterlist *sgl,
-+ size_t sg_len,
-+ enum dma_transfer_direction dir,
-+ dma_async_tx_callback callback)
-+{
-+ struct dma_async_tx_descriptor *desc;
-+
-+ desc = dmaengine_prep_slave_sg(inst->dma_chan,
-+ sgl,
-+ sg_len,
-+ dir,
-+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK |
-+ DMA_PREP_FENCE);
-+ if (!desc) {
-+ dev_err(inst->dev, "read_sgl: dma slave preparation failed!");
-+ write_smi_reg(inst, read_smi_reg(inst, SMICS) & ~SMICS_ACTIVE,
-+ SMICS);
-+ while (read_smi_reg(inst, SMICS) & SMICS_ACTIVE)
-+ cpu_relax();
-+ write_smi_reg(inst, read_smi_reg(inst, SMICS) | SMICS_ACTIVE,
-+ SMICS);
-+ return NULL;
-+ }
-+ desc->callback = callback;
-+ desc->callback_param = inst;
-+ if (dmaengine_submit(desc) < 0)
-+ return NULL;
-+ return desc;
-+}
-+
-+/* NB this function blocks until the transfer is complete */
-+static void
-+smi_dma_read_sgl(struct bcm2835_smi_instance *inst,
-+ struct scatterlist *sgl, size_t sg_len, size_t n_bytes)
-+{
-+ struct dma_async_tx_descriptor *desc;
-+
-+ /* Disable SMI and set to read before dispatching DMA - if SMI is in
-+ * write mode and TX fifo is empty, it will generate a DREQ which may
-+ * cause the read DMA to complete before the SMI read command is even
-+ * dispatched! We want to dispatch DMA before SMI read so that reading
-+ * is gapless, for logic analyser.
-+ */
-+
-+ smi_disable(inst, DMA_DEV_TO_MEM);
-+
-+ desc = smi_dma_submit_sgl(inst, sgl, sg_len, DMA_DEV_TO_MEM, NULL);
-+ dma_async_issue_pending(inst->dma_chan);
-+
-+ if (inst->settings.data_width == SMI_WIDTH_8BIT)
-+ smi_init_programmed_read(inst, n_bytes);
-+ else
-+ smi_init_programmed_read(inst, n_bytes / 2);
-+
-+ if (dma_wait_for_async_tx(desc) == DMA_ERROR)
-+ smi_dump_context_labelled(inst, "DMA timeout!");
-+}
-+
-+static void
-+smi_dma_write_sgl(struct bcm2835_smi_instance *inst,
-+ struct scatterlist *sgl, size_t sg_len, size_t n_bytes)
-+{
-+ struct dma_async_tx_descriptor *desc;
-+
-+ if (inst->settings.data_width == SMI_WIDTH_8BIT)
-+ smi_init_programmed_write(inst, n_bytes);
-+ else
-+ smi_init_programmed_write(inst, n_bytes / 2);
-+
-+ desc = smi_dma_submit_sgl(inst, sgl, sg_len, DMA_MEM_TO_DEV, NULL);
-+ dma_async_issue_pending(inst->dma_chan);
-+
-+ if (dma_wait_for_async_tx(desc) == DMA_ERROR)
-+ smi_dump_context_labelled(inst, "DMA timeout!");
-+ else
-+ /* Wait for SMI to finish our writes */
-+ while (!(read_smi_reg(inst, SMICS) & SMICS_DONE))
-+ cpu_relax();
-+}
-+
-+ssize_t bcm2835_smi_user_dma(
-+ struct bcm2835_smi_instance *inst,
-+ enum dma_transfer_direction dma_dir,
-+ char __user *user_ptr, size_t count,
-+ struct bcm2835_smi_bounce_info **bounce)
-+{
-+ int chunk_no = 0, chunk_size, count_left = count;
-+ struct scatterlist *sgl;
-+ void (*init_trans_func)(struct bcm2835_smi_instance *, int);
-+
-+ spin_lock(&inst->transaction_lock);
-+
-+ if (dma_dir == DMA_DEV_TO_MEM)
-+ init_trans_func = smi_init_programmed_read;
-+ else
-+ init_trans_func = smi_init_programmed_write;
-+
-+ smi_disable(inst, dma_dir);
-+
-+ sema_init(&inst->bounce.callback_sem, 0);
-+ if (bounce)
-+ *bounce = &inst->bounce;
-+ while (count_left) {
-+ chunk_size = count_left > DMA_BOUNCE_BUFFER_SIZE ?
-+ DMA_BOUNCE_BUFFER_SIZE : count_left;
-+ if (chunk_size == DMA_BOUNCE_BUFFER_SIZE) {
-+ sgl =
-+ &inst->bounce.sgl[chunk_no % DMA_BOUNCE_BUFFER_COUNT];
-+ } else {
-+ sgl = smi_scatterlist_from_buffer(
-+ inst,
-+ inst->bounce.phys[
-+ chunk_no % DMA_BOUNCE_BUFFER_COUNT],
-+ chunk_size,
-+ &inst->buffer_sgl);
-+ }
-+
-+ if (!smi_dma_submit_sgl(inst, sgl, 1, dma_dir,
-+ smi_dma_callback_user_copy
-+ )) {
-+ dev_err(inst->dev, "sgl submit failed");
-+ count = 0;
-+ goto out;
-+ }
-+ count_left -= chunk_size;
-+ chunk_no++;
-+ }
-+ dma_async_issue_pending(inst->dma_chan);
-+
-+ if (inst->settings.data_width == SMI_WIDTH_8BIT)
-+ init_trans_func(inst, count);
-+ else if (inst->settings.data_width == SMI_WIDTH_16BIT)
-+ init_trans_func(inst, count / 2);
-+out:
-+ spin_unlock(&inst->transaction_lock);
-+ return count;
-+}
-+EXPORT_SYMBOL(bcm2835_smi_user_dma);
-+
-+
-+/****************************************************************************
-+*
-+* High level buffer transfer functions - for use by other drivers
-+*
-+***************************************************************************/
-+
-+/* Buffer must be physically contiguous - i.e. kmalloc, not vmalloc! */
-+void bcm2835_smi_write_buf(
-+ struct bcm2835_smi_instance *inst,
-+ const void *buf, size_t n_bytes)
-+{
-+ int odd_bytes = n_bytes & 0x3;
-+
-+ n_bytes -= odd_bytes;
-+
-+ spin_lock(&inst->transaction_lock);
-+
-+ if (n_bytes > DMA_THRESHOLD_BYTES) {
-+ dma_addr_t phy_addr = dma_map_single(
-+ inst->dev,
-+ (void *)buf,
-+ n_bytes,
-+ DMA_MEM_TO_DEV);
-+ struct scatterlist *sgl =
-+ smi_scatterlist_from_buffer(inst, phy_addr, n_bytes,
-+ &inst->buffer_sgl);
-+
-+ if (!sgl) {
-+ smi_dump_context_labelled(inst,
-+ "Error: could not create scatterlist for write!");
-+ goto out;
-+ }
-+ smi_dma_write_sgl(inst, sgl, 1, n_bytes);
-+
-+ dma_unmap_single
-+ (inst->dev, phy_addr, n_bytes, DMA_MEM_TO_DEV);
-+ } else if (n_bytes) {
-+ smi_write_fifo(inst, (uint32_t *) buf, n_bytes);
-+ }
-+ buf += n_bytes;
-+
-+ if (inst->settings.data_width == SMI_WIDTH_8BIT) {
-+ while (odd_bytes--)
-+ smi_write_single_word(inst, *(uint8_t *) (buf++));
-+ } else {
-+ while (odd_bytes >= 2) {
-+ smi_write_single_word(inst, *(uint16_t *)buf);
-+ buf += 2;
-+ odd_bytes -= 2;
-+ }
-+ if (odd_bytes) {
-+ /* Reading an odd number of bytes on a 16 bit bus is
-+ a user bug. It's kinder to fail early and tell them
-+ than to e.g. transparently give them the bottom byte
-+ of a 16 bit transfer. */
-+ dev_err(inst->dev,
-+ "WARNING: odd number of bytes specified for wide transfer.");
-+ dev_err(inst->dev,
-+ "At least one byte dropped as a result.");
-+ dump_stack();
-+ }
-+ }
-+out:
-+ spin_unlock(&inst->transaction_lock);
-+}
-+EXPORT_SYMBOL(bcm2835_smi_write_buf);
-+
-+void bcm2835_smi_read_buf(struct bcm2835_smi_instance *inst,
-+ void *buf, size_t n_bytes)
-+{
-+
-+ /* SMI is inherently 32-bit, which causes surprising amounts of mess
-+ for bytes % 4 != 0. Easiest to avoid this mess altogether
-+ by handling remainder separately. */
-+ int odd_bytes = n_bytes & 0x3;
-+
-+ spin_lock(&inst->transaction_lock);
-+ n_bytes -= odd_bytes;
-+ if (n_bytes > DMA_THRESHOLD_BYTES) {
-+ dma_addr_t phy_addr = dma_map_single(inst->dev,
-+ buf, n_bytes,
-+ DMA_DEV_TO_MEM);
-+ struct scatterlist *sgl = smi_scatterlist_from_buffer(
-+ inst, phy_addr, n_bytes,
-+ &inst->buffer_sgl);
-+ if (!sgl) {
-+ smi_dump_context_labelled(inst,
-+ "Error: could not create scatterlist for read!");
-+ goto out;
-+ }
-+ smi_dma_read_sgl(inst, sgl, 1, n_bytes);
-+ dma_unmap_single(inst->dev, phy_addr, n_bytes, DMA_DEV_TO_MEM);
-+ } else if (n_bytes) {
-+ smi_read_fifo(inst, (uint32_t *)buf, n_bytes);
-+ }
-+ buf += n_bytes;
-+
-+ if (inst->settings.data_width == SMI_WIDTH_8BIT) {
-+ while (odd_bytes--)
-+ *((uint8_t *) (buf++)) = smi_read_single_word(inst);
-+ } else {
-+ while (odd_bytes >= 2) {
-+ *(uint16_t *) buf = smi_read_single_word(inst);
-+ buf += 2;
-+ odd_bytes -= 2;
-+ }
-+ if (odd_bytes) {
-+ dev_err(inst->dev,
-+ "WARNING: odd number of bytes specified for wide transfer.");
-+ dev_err(inst->dev,
-+ "At least one byte dropped as a result.");
-+ dump_stack();
-+ }
-+ }
-+out:
-+ spin_unlock(&inst->transaction_lock);
-+}
-+EXPORT_SYMBOL(bcm2835_smi_read_buf);
-+
-+void bcm2835_smi_set_address(struct bcm2835_smi_instance *inst,
-+ unsigned int address)
-+{
-+ spin_lock(&inst->transaction_lock);
-+ smi_set_address(inst, address);
-+ spin_unlock(&inst->transaction_lock);
-+}
-+EXPORT_SYMBOL(bcm2835_smi_set_address);
-+
-+struct bcm2835_smi_instance *bcm2835_smi_get(struct device_node *node)
-+{
-+ struct platform_device *pdev;
-+
-+ if (!node)
-+ return NULL;
-+
-+ pdev = of_find_device_by_node(node);
-+ if (!pdev)
-+ return NULL;
-+
-+ return platform_get_drvdata(pdev);
-+}
-+EXPORT_SYMBOL(bcm2835_smi_get);
-+
-+/****************************************************************************
-+*
-+* bcm2835_smi_probe - called when the driver is loaded.
-+*
-+***************************************************************************/
-+
-+static int bcm2835_smi_dma_setup(struct bcm2835_smi_instance *inst)
-+{
-+ int i, rv = 0;
-+
-+ inst->dma_chan = dma_request_slave_channel(inst->dev, "rx-tx");
-+
-+ inst->dma_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-+ inst->dma_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-+ inst->dma_config.src_addr = inst->smi_regs_busaddr + SMID;
-+ inst->dma_config.dst_addr = inst->dma_config.src_addr;
-+ /* Direction unimportant - always overridden by prep_slave_sg */
-+ inst->dma_config.direction = DMA_DEV_TO_MEM;
-+ dmaengine_slave_config(inst->dma_chan, &inst->dma_config);
-+ /* Alloc and map bounce buffers */
-+ for (i = 0; i < DMA_BOUNCE_BUFFER_COUNT; ++i) {
-+ inst->bounce.buffer[i] =
-+ dmam_alloc_coherent(inst->dev, DMA_BOUNCE_BUFFER_SIZE,
-+ &inst->bounce.phys[i],
-+ GFP_KERNEL);
-+ if (!inst->bounce.buffer[i]) {
-+ dev_err(inst->dev, "Could not allocate buffer!");
-+ rv = -ENOMEM;
-+ break;
-+ }
-+ smi_scatterlist_from_buffer(
-+ inst,
-+ inst->bounce.phys[i],
-+ DMA_BOUNCE_BUFFER_SIZE,
-+ &inst->bounce.sgl[i]
-+ );
-+ }
-+
-+ return rv;
-+}
-+
-+static int bcm2835_smi_probe(struct platform_device *pdev)
-+{
-+ int err;
-+ struct device *dev = &pdev->dev;
-+ struct device_node *node = dev->of_node;
-+ struct resource *ioresource;
-+ struct bcm2835_smi_instance *inst;
-+
-+ /* Allocate buffers and instance data */
-+
-+ inst = devm_kzalloc(dev, sizeof(struct bcm2835_smi_instance),
-+ GFP_KERNEL);
-+
-+ if (!inst)
-+ return -ENOMEM;
-+
-+ inst->dev = dev;
-+ spin_lock_init(&inst->transaction_lock);
-+
-+ /* We require device tree support */
-+ if (!node)
-+ return -EINVAL;
-+
-+ ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ inst->smi_regs_ptr = devm_ioremap_resource(dev, ioresource);
-+ ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-+ inst->cm_smi_regs_ptr = devm_ioremap_resource(dev, ioresource);
-+ inst->smi_regs_busaddr = be32_to_cpu(
-+ *of_get_address(node, 0, NULL, NULL));
-+ of_property_read_u32(node,
-+ "brcm,smi-clock-source",
-+ &inst->clock_source);
-+ of_property_read_u32(node,
-+ "brcm,smi-clock-divisor",
-+ &inst->clock_divisor);
-+
-+ err = bcm2835_smi_dma_setup(inst);
-+ if (err)
-+ return err;
-+
-+ /* Finally, do peripheral setup */
-+
-+ smi_setup_clock(inst);
-+ smi_setup_regs(inst);
-+
-+ platform_set_drvdata(pdev, inst);
-+
-+ dev_info(inst->dev, "initialised");
-+
-+ return 0;
-+}
-+
-+/****************************************************************************
-+*
-+* bcm2835_smi_remove - called when the driver is unloaded.
-+*
-+***************************************************************************/
-+
-+static int bcm2835_smi_remove(struct platform_device *pdev)
-+{
-+ struct bcm2835_smi_instance *inst = platform_get_drvdata(pdev);
-+ struct device *dev = inst->dev;
-+
-+ dev_info(dev, "SMI device removed - OK");
-+ return 0;
-+}
-+
-+/****************************************************************************
-+*
-+* Register the driver with device tree
-+*
-+***************************************************************************/
-+
-+static const struct of_device_id bcm2835_smi_of_match[] = {
-+ {.compatible = "brcm,bcm2835-smi",},
-+ { /* sentinel */ },
-+};
-+
-+MODULE_DEVICE_TABLE(of, bcm2835_smi_of_match);
-+
-+static struct platform_driver bcm2835_smi_driver = {
-+ .probe = bcm2835_smi_probe,
-+ .remove = bcm2835_smi_remove,
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ .of_match_table = bcm2835_smi_of_match,
-+ },
-+};
-+
-+module_platform_driver(bcm2835_smi_driver);
-+
-+MODULE_ALIAS("platform:smi-bcm2835");
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("Device driver for BCM2835's secondary memory interface");
-+MODULE_AUTHOR("Luke Wren <luke@raspberrypi.org>");
---- /dev/null
-+++ b/include/linux/broadcom/bcm2835_smi.h
-@@ -0,0 +1,391 @@
-+/**
-+ * Declarations and definitions for Broadcom's Secondary Memory Interface
-+ *
-+ * Written by Luke Wren <luke@raspberrypi.org>
-+ * Copyright (c) 2015, Raspberry Pi (Trading) Ltd.
-+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef BCM2835_SMI_H
-+#define BCM2835_SMI_H
-+
-+#include <linux/ioctl.h>
-+
-+#ifndef __KERNEL__
-+#include <stdint.h>
-+#include <stdbool.h>
-+#endif
-+
-+#define BCM2835_SMI_IOC_MAGIC 0x1
-+#define BCM2835_SMI_INVALID_HANDLE (~0)
-+
-+/* IOCTLs 0x100...0x1ff are not device-specific - we can use them */
-+#define BCM2835_SMI_IOC_GET_SETTINGS _IO(BCM2835_SMI_IOC_MAGIC, 0)
-+#define BCM2835_SMI_IOC_WRITE_SETTINGS _IO(BCM2835_SMI_IOC_MAGIC, 1)
-+#define BCM2835_SMI_IOC_ADDRESS _IO(BCM2835_SMI_IOC_MAGIC, 2)
-+#define BCM2835_SMI_IOC_MAX 2
-+
-+#define SMI_WIDTH_8BIT 0
-+#define SMI_WIDTH_16BIT 1
-+#define SMI_WIDTH_9BIT 2
-+#define SMI_WIDTH_18BIT 3
-+
-+/* max number of bytes where DMA will not be used */
-+#define DMA_THRESHOLD_BYTES 128
-+#define DMA_BOUNCE_BUFFER_SIZE (1024 * 1024 / 2)
-+#define DMA_BOUNCE_BUFFER_COUNT 3
-+
-+
-+struct smi_settings {
-+ int data_width;
-+ /* Whether or not to pack multiple SMI transfers into a
-+ single 32 bit FIFO word */
-+ bool pack_data;
-+
-+ /* Timing for reads (writes the same but for WE)
-+ *
-+ * OE ----------+ +--------------------
-+ * | |
-+ * +----------+
-+ * SD -<==============================>-----------
-+ * SA -<=========================================>-
-+ * <-setup-> <-strobe -> <-hold -> <- pace ->
-+ */
-+
-+ int read_setup_time;
-+ int read_hold_time;
-+ int read_pace_time;
-+ int read_strobe_time;
-+
-+ int write_setup_time;
-+ int write_hold_time;
-+ int write_pace_time;
-+ int write_strobe_time;
-+
-+ bool dma_enable; /* DREQs */
-+ bool dma_passthrough_enable; /* External DREQs */
-+ int dma_read_thresh;
-+ int dma_write_thresh;
-+ int dma_panic_read_thresh;
-+ int dma_panic_write_thresh;
-+};
-+
-+/****************************************************************************
-+*
-+* Declare exported SMI functions
-+*
-+***************************************************************************/
-+
-+#ifdef __KERNEL__
-+
-+#include <linux/dmaengine.h> /* for enum dma_transfer_direction */
-+#include <linux/of.h>
-+#include <linux/semaphore.h>
-+
-+struct bcm2835_smi_instance;
-+
-+struct bcm2835_smi_bounce_info {
-+ struct semaphore callback_sem;
-+ void *buffer[DMA_BOUNCE_BUFFER_COUNT];
-+ dma_addr_t phys[DMA_BOUNCE_BUFFER_COUNT];
-+ struct scatterlist sgl[DMA_BOUNCE_BUFFER_COUNT];
-+};
-+
-+
-+void bcm2835_smi_set_regs_from_settings(struct bcm2835_smi_instance *);
-+
-+struct smi_settings *bcm2835_smi_get_settings_from_regs(
-+ struct bcm2835_smi_instance *inst);
-+
-+void bcm2835_smi_write_buf(
-+ struct bcm2835_smi_instance *inst,
-+ const void *buf,
-+ size_t n_bytes);
-+
-+void bcm2835_smi_read_buf(
-+ struct bcm2835_smi_instance *inst,
-+ void *buf,
-+ size_t n_bytes);
-+
-+void bcm2835_smi_set_address(struct bcm2835_smi_instance *inst,
-+ unsigned int address);
-+
-+ssize_t bcm2835_smi_user_dma(
-+ struct bcm2835_smi_instance *inst,
-+ enum dma_transfer_direction dma_dir,
-+ char __user *user_ptr,
-+ size_t count,
-+ struct bcm2835_smi_bounce_info **bounce);
-+
-+struct bcm2835_smi_instance *bcm2835_smi_get(struct device_node *node);
-+
-+#endif /* __KERNEL__ */
-+
-+/****************************************************************
-+*
-+* Implementation-only declarations
-+*
-+****************************************************************/
-+
-+#ifdef BCM2835_SMI_IMPLEMENTATION
-+
-+/* Clock manager registers for SMI clock: */
-+#define CM_SMI_BASE_ADDRESS ((BCM2708_PERI_BASE) + 0x1010b0)
-+/* Clock manager "password" to protect registers from spurious writes */
-+#define CM_PWD (0x5a << 24)
-+
-+#define CM_SMI_CTL 0x00
-+#define CM_SMI_DIV 0x04
-+
-+#define CM_SMI_CTL_FLIP (1 << 8)
-+#define CM_SMI_CTL_BUSY (1 << 7)
-+#define CM_SMI_CTL_KILL (1 << 5)
-+#define CM_SMI_CTL_ENAB (1 << 4)
-+#define CM_SMI_CTL_SRC_MASK (0xf)
-+#define CM_SMI_CTL_SRC_OFFS (0)
-+
-+#define CM_SMI_DIV_DIVI_MASK (0xf << 12)
-+#define CM_SMI_DIV_DIVI_OFFS (12)
-+#define CM_SMI_DIV_DIVF_MASK (0xff << 4)
-+#define CM_SMI_DIV_DIVF_OFFS (4)
-+
-+/* SMI register mapping:*/
-+#define SMI_BASE_ADDRESS ((BCM2708_PERI_BASE) + 0x600000)
-+
-+#define SMICS 0x00 /* control + status register */
-+#define SMIL 0x04 /* length/count (n external txfers) */
-+#define SMIA 0x08 /* address register */
-+#define SMID 0x0c /* data register */
-+#define SMIDSR0 0x10 /* device 0 read settings */
-+#define SMIDSW0 0x14 /* device 0 write settings */
-+#define SMIDSR1 0x18 /* device 1 read settings */
-+#define SMIDSW1 0x1c /* device 1 write settings */
-+#define SMIDSR2 0x20 /* device 2 read settings */
-+#define SMIDSW2 0x24 /* device 2 write settings */
-+#define SMIDSR3 0x28 /* device 3 read settings */
-+#define SMIDSW3 0x2c /* device 3 write settings */
-+#define SMIDC 0x30 /* DMA control registers */
-+#define SMIDCS 0x34 /* direct control/status register */
-+#define SMIDA 0x38 /* direct address register */
-+#define SMIDD 0x3c /* direct data registers */
-+#define SMIFD 0x40 /* FIFO debug register */
-+
-+
-+
-+/* Control and Status register bits:
-+ * SMICS_RXF : RX fifo full: 1 when RX fifo is full
-+ * SMICS_TXE : TX fifo empty: 1 when empty.
-+ * SMICS_RXD : RX fifo contains data: 1 when there is data.
-+ * SMICS_TXD : TX fifo can accept data: 1 when true.
-+ * SMICS_RXR : RX fifo needs reading: 1 when fifo more than 3/4 full, or
-+ * when "DONE" and fifo not emptied.
-+ * SMICS_TXW : TX fifo needs writing: 1 when less than 1/4 full.
-+ * SMICS_AFERR : AXI FIFO error: 1 when fifo read when empty or written
-+ * when full. Write 1 to clear.
-+ * SMICS_EDREQ : 1 when external DREQ received.
-+ * SMICS_PXLDAT : Pixel data: write 1 to enable pixel transfer modes.
-+ * SMICS_SETERR : 1 if there was an error writing to setup regs (e.g.
-+ * tx was in progress). Write 1 to clear.
-+ * SMICS_PVMODE : Set to 1 to enable pixel valve mode.
-+ * SMICS_INTR : Set to 1 to enable interrupt on RX.
-+ * SMICS_INTT : Set to 1 to enable interrupt on TX.
-+ * SMICS_INTD : Set to 1 to enable interrupt on DONE condition.
-+ * SMICS_TEEN : Tear effect mode enabled: Programmed transfers will wait
-+ * for a TE trigger before writing.
-+ * SMICS_PAD1 : Padding settings for external transfers. For writes: the
-+ * number of bytes initially written to the TX fifo that
-+ * SMICS_PAD0 : should be ignored. For reads: the number of bytes that will
-+ * be read before the data, and should be dropped.
-+ * SMICS_WRITE : Transfer direction: 1 = write to external device, 0 = read
-+ * SMICS_CLEAR : Write 1 to clear the FIFOs.
-+ * SMICS_START : Write 1 to start the programmed transfer.
-+ * SMICS_ACTIVE : Reads as 1 when a programmed transfer is underway.
-+ * SMICS_DONE : Reads as 1 when transfer finished. For RX, not set until
-+ * FIFO emptied.
-+ * SMICS_ENABLE : Set to 1 to enable the SMI peripheral, 0 to disable.
-+ */
-+
-+#define SMICS_RXF (1 << 31)
-+#define SMICS_TXE (1 << 30)
-+#define SMICS_RXD (1 << 29)
-+#define SMICS_TXD (1 << 28)
-+#define SMICS_RXR (1 << 27)
-+#define SMICS_TXW (1 << 26)
-+#define SMICS_AFERR (1 << 25)
-+#define SMICS_EDREQ (1 << 15)
-+#define SMICS_PXLDAT (1 << 14)
-+#define SMICS_SETERR (1 << 13)
-+#define SMICS_PVMODE (1 << 12)
-+#define SMICS_INTR (1 << 11)
-+#define SMICS_INTT (1 << 10)
-+#define SMICS_INTD (1 << 9)
-+#define SMICS_TEEN (1 << 8)
-+#define SMICS_PAD1 (1 << 7)
-+#define SMICS_PAD0 (1 << 6)
-+#define SMICS_WRITE (1 << 5)
-+#define SMICS_CLEAR (1 << 4)
-+#define SMICS_START (1 << 3)
-+#define SMICS_ACTIVE (1 << 2)
-+#define SMICS_DONE (1 << 1)
-+#define SMICS_ENABLE (1 << 0)
-+
-+/* Address register bits: */
-+
-+#define SMIA_DEVICE_MASK ((1 << 9) | (1 << 8))
-+#define SMIA_DEVICE_OFFS (8)
-+#define SMIA_ADDR_MASK (0x3f) /* bits 5 -> 0 */
-+#define SMIA_ADDR_OFFS (0)
-+
-+/* DMA control register bits:
-+ * SMIDC_DMAEN : DMA enable: set 1: DMA requests will be issued.
-+ * SMIDC_DMAP : DMA passthrough: when set to 0, top two data pins are used by
-+ * SMI as usual. When set to 1, the top two pins are used for
-+ * external DREQs: pin 16 read request, 17 write.
-+ * SMIDC_PANIC* : Threshold at which DMA will panic during read/write.
-+ * SMIDC_REQ* : Threshold at which DMA will generate a DREQ.
-+ */
-+
-+#define SMIDC_DMAEN (1 << 28)
-+#define SMIDC_DMAP (1 << 24)
-+#define SMIDC_PANICR_MASK (0x3f << 18)
-+#define SMIDC_PANICR_OFFS (18)
-+#define SMIDC_PANICW_MASK (0x3f << 12)
-+#define SMIDC_PANICW_OFFS (12)
-+#define SMIDC_REQR_MASK (0x3f << 6)
-+#define SMIDC_REQR_OFFS (6)
-+#define SMIDC_REQW_MASK (0x3f)
-+#define SMIDC_REQW_OFFS (0)
-+
-+/* Device settings register bits: same for all 4 (or 3?) device register sets.
-+ * Device read settings:
-+ * SMIDSR_RWIDTH : Read transfer width. 00 = 8bit, 01 = 16bit,
-+ * 10 = 18bit, 11 = 9bit.
-+ * SMIDSR_RSETUP : Read setup time: number of core cycles between chip
-+ * select/address and read strobe. Min 1, max 64.
-+ * SMIDSR_MODE68 : 1 for System 68 mode (i.e. enable + direction pins,
-+ * rather than OE + WE pin)
-+ * SMIDSR_FSETUP : If set to 1, setup time only applies to first
-+ * transfer after address change.
-+ * SMIDSR_RHOLD : Number of core cycles between read strobe going
-+ * inactive and CS/address going inactive. Min 1, max 64
-+ * SMIDSR_RPACEALL : When set to 1, this device's RPACE value will always
-+ * be used for the next transaction, even if it is not
-+ * to this device.
-+ * SMIDSR_RPACE : Number of core cycles spent waiting between CS
-+ * deassert and start of next transfer. Min 1, max 128
-+ * SMIDSR_RDREQ : 1 = use external DMA request on SD16 to pace reads
-+ * from device. Must also set DMAP in SMICS.
-+ * SMIDSR_RSTROBE : Number of cycles to assert the read strobe.
-+ * min 1, max 128.
-+ */
-+#define SMIDSR_RWIDTH_MASK ((1<<31)|(1<<30))
-+#define SMIDSR_RWIDTH_OFFS (30)
-+#define SMIDSR_RSETUP_MASK (0x3f << 24)
-+#define SMIDSR_RSETUP_OFFS (24)
-+#define SMIDSR_MODE68 (1 << 23)
-+#define SMIDSR_FSETUP (1 << 22)
-+#define SMIDSR_RHOLD_MASK (0x3f << 16)
-+#define SMIDSR_RHOLD_OFFS (16)
-+#define SMIDSR_RPACEALL (1 << 15)
-+#define SMIDSR_RPACE_MASK (0x7f << 8)
-+#define SMIDSR_RPACE_OFFS (8)
-+#define SMIDSR_RDREQ (1 << 7)
-+#define SMIDSR_RSTROBE_MASK (0x7f)
-+#define SMIDSR_RSTROBE_OFFS (0)
-+
-+/* Device write settings:
-+ * SMIDSW_WWIDTH : Write transfer width. 00 = 8bit, 01 = 16bit,
-+ * 10= 18bit, 11 = 9bit.
-+ * SMIDSW_WSETUP : Number of cycles between CS assert and write strobe.
-+ * Min 1, max 64.
-+ * SMIDSW_WFORMAT : Pixel format of input. 0 = 16bit RGB 565,
-+ * 1 = 32bit RGBA 8888
-+ * SMIDSW_WSWAP : 1 = swap pixel data bits. (Use with SMICS_PXLDAT)
-+ * SMIDSW_WHOLD : Time between WE deassert and CS deassert. 1 to 64
-+ * SMIDSW_WPACEALL : 1: this device's WPACE will be used for the next
-+ * transfer, regardless of that transfer's device.
-+ * SMIDSW_WPACE : Cycles between CS deassert and next CS assert.
-+ * Min 1, max 128
-+ * SMIDSW_WDREQ : Use external DREQ on pin 17 to pace writes. DMAP must
-+ * be set in SMICS.
-+ * SMIDSW_WSTROBE : Number of cycles to assert the write strobe.
-+ * Min 1, max 128
-+ */
-+#define SMIDSW_WWIDTH_MASK ((1<<31)|(1<<30))
-+#define SMIDSW_WWIDTH_OFFS (30)
-+#define SMIDSW_WSETUP_MASK (0x3f << 24)
-+#define SMIDSW_WSETUP_OFFS (24)
-+#define SMIDSW_WFORMAT (1 << 23)
-+#define SMIDSW_WSWAP (1 << 22)
-+#define SMIDSW_WHOLD_MASK (0x3f << 16)
-+#define SMIDSW_WHOLD_OFFS (16)
-+#define SMIDSW_WPACEALL (1 << 15)
-+#define SMIDSW_WPACE_MASK (0x7f << 8)
-+#define SMIDSW_WPACE_OFFS (8)
-+#define SMIDSW_WDREQ (1 << 7)
-+#define SMIDSW_WSTROBE_MASK (0x7f)
-+#define SMIDSW_WSTROBE_OFFS (0)
-+
-+/* Direct transfer control + status register
-+ * SMIDCS_WRITE : Direction of transfer: 1 -> write, 0 -> read
-+ * SMIDCS_DONE : 1 when a transfer has finished. Write 1 to clear.
-+ * SMIDCS_START : Write 1 to start a transfer, if one is not already underway.
-+ * SMIDCE_ENABLE: Write 1 to enable SMI in direct mode.
-+ */
-+
-+#define SMIDCS_WRITE (1 << 3)
-+#define SMIDCS_DONE (1 << 2)
-+#define SMIDCS_START (1 << 1)
-+#define SMIDCS_ENABLE (1 << 0)
-+
-+/* Direct transfer address register
-+ * SMIDA_DEVICE : Indicates which of the device settings banks should be used.
-+ * SMIDA_ADDR : The value to be asserted on the address pins.
-+ */
-+
-+#define SMIDA_DEVICE_MASK ((1<<9)|(1<<8))
-+#define SMIDA_DEVICE_OFFS (8)
-+#define SMIDA_ADDR_MASK (0x3f)
-+#define SMIDA_ADDR_OFFS (0)
-+
-+/* FIFO debug register
-+ * SMIFD_FLVL : The high-tide mark of FIFO count during the most recent txfer
-+ * SMIFD_FCNT : The current FIFO count.
-+ */
-+#define SMIFD_FLVL_MASK (0x3f << 8)
-+#define SMIFD_FLVL_OFFS (8)
-+#define SMIFD_FCNT_MASK (0x3f)
-+#define SMIFD_FCNT_OFFS (0)
-+
-+#endif /* BCM2835_SMI_IMPLEMENTATION */
-+
-+#endif /* BCM2835_SMI_H */
diff --git a/target/linux/brcm2708/patches-4.4/0042-Add-SMI-NAND-driver.patch b/target/linux/brcm2708/patches-4.4/0042-Add-SMI-NAND-driver.patch
deleted file mode 100644
index edf2c93e05..0000000000
--- a/target/linux/brcm2708/patches-4.4/0042-Add-SMI-NAND-driver.patch
+++ /dev/null
@@ -1,358 +0,0 @@
-From f4d44b2c447c401791645627e88d0ef9830c1239 Mon Sep 17 00:00:00 2001
-From: Luke Wren <wren6991@gmail.com>
-Date: Sat, 5 Sep 2015 01:16:10 +0100
-Subject: [PATCH 042/170] Add SMI NAND driver
-
-Signed-off-by: Luke Wren <wren6991@gmail.com>
----
- .../bindings/mtd/brcm,bcm2835-smi-nand.txt | 42 ++++
- drivers/mtd/nand/Kconfig | 7 +
- drivers/mtd/nand/Makefile | 1 +
- drivers/mtd/nand/bcm2835_smi_nand.c | 268 +++++++++++++++++++++
- 4 files changed, 318 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/mtd/brcm,bcm2835-smi-nand.txt
- create mode 100644 drivers/mtd/nand/bcm2835_smi_nand.c
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/mtd/brcm,bcm2835-smi-nand.txt
-@@ -0,0 +1,42 @@
-+* BCM2835 SMI NAND flash
-+
-+This driver is a shim between the BCM2835 SMI driver (SMI is a peripheral for
-+talking to parallel register interfaces) and Linux's MTD layer.
-+
-+Required properties:
-+- compatible: "brcm,bcm2835-smi-nand"
-+- status: "okay"
-+
-+Optional properties:
-+- partition@n, where n is an integer from a consecutive sequence starting at 0
-+ - Difficult to store partition table on NAND device - normally put it
-+ in the source code, kernel bootparams, or device tree (the best way!)
-+ - Sub-properties:
-+ - label: the partition name, as shown by mtdinfo /dev/mtd*
-+ - reg: the size and offset of this partition.
-+ - (optional) read-only: an empty property flagging as read only
-+
-+Example:
-+
-+nand: flash@0 {
-+ compatible = "brcm,bcm2835-smi-nand";
-+ status = "okay";
-+
-+ partition@0 {
-+ label = "stage2";
-+ // 128k
-+ reg = <0 0x20000>;
-+ read-only;
-+ };
-+ partition@1 {
-+ label = "firmware";
-+ // 16M
-+ reg = <0x20000 0x1000000>;
-+ read-only;
-+ };
-+ partition@2 {
-+ label = "root";
-+ // 2G
-+ reg = <0x1020000 0x80000000>;
-+ };
-+};
-\ No newline at end of file
---- a/drivers/mtd/nand/Kconfig
-+++ b/drivers/mtd/nand/Kconfig
-@@ -41,6 +41,13 @@ config MTD_SM_COMMON
- tristate
- default n
-
-+config MTD_NAND_BCM2835_SMI
-+ tristate "Use Broadcom's Secondary Memory Interface as a NAND controller (BCM283x)"
-+ depends on (MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835) && BCM2835_SMI && MTD_NAND
-+ default m
-+ help
-+ Uses the BCM2835's SMI peripheral as a NAND controller.
-+
- config MTD_NAND_DENALI
- tristate
-
---- a/drivers/mtd/nand/Makefile
-+++ b/drivers/mtd/nand/Makefile
-@@ -14,6 +14,7 @@ obj-$(CONFIG_MTD_NAND_DENALI) += denali
- obj-$(CONFIG_MTD_NAND_DENALI_PCI) += denali_pci.o
- obj-$(CONFIG_MTD_NAND_DENALI_DT) += denali_dt.o
- obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o
-+obj-$(CONFIG_MTD_NAND_BCM2835_SMI) += bcm2835_smi_nand.o
- obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o
- obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o
- obj-$(CONFIG_MTD_NAND_DAVINCI) += davinci_nand.o
---- /dev/null
-+++ b/drivers/mtd/nand/bcm2835_smi_nand.c
-@@ -0,0 +1,268 @@
-+/**
-+ * NAND flash driver for Broadcom Secondary Memory Interface
-+ *
-+ * Written by Luke Wren <luke@raspberrypi.org>
-+ * Copyright (c) 2015, Raspberry Pi (Trading) Ltd.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <linux/slab.h>
-+#include <linux/mtd/nand.h>
-+#include <linux/mtd/partitions.h>
-+
-+#include <linux/broadcom/bcm2835_smi.h>
-+
-+#define DEVICE_NAME "bcm2835-smi-nand"
-+#define DRIVER_NAME "smi-nand-bcm2835"
-+
-+struct bcm2835_smi_nand_host {
-+ struct bcm2835_smi_instance *smi_inst;
-+ struct nand_chip nand_chip;
-+ struct mtd_info mtd;
-+ struct device *dev;
-+};
-+
-+/****************************************************************************
-+*
-+* NAND functionality implementation
-+*
-+****************************************************************************/
-+
-+#define SMI_NAND_CLE_PIN 0x01
-+#define SMI_NAND_ALE_PIN 0x02
-+
-+static inline void bcm2835_smi_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
-+ unsigned int ctrl)
-+{
-+ uint32_t cmd32 = cmd;
-+ uint32_t addr = ~(SMI_NAND_CLE_PIN | SMI_NAND_ALE_PIN);
-+ struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
-+ struct bcm2835_smi_instance *inst = host->smi_inst;
-+
-+ if (ctrl & NAND_CLE)
-+ addr |= SMI_NAND_CLE_PIN;
-+ if (ctrl & NAND_ALE)
-+ addr |= SMI_NAND_ALE_PIN;
-+ /* Lower ALL the CS pins! */
-+ if (ctrl & NAND_NCE)
-+ addr &= (SMI_NAND_CLE_PIN | SMI_NAND_ALE_PIN);
-+
-+ bcm2835_smi_set_address(inst, addr);
-+
-+ if (cmd != NAND_CMD_NONE)
-+ bcm2835_smi_write_buf(inst, &cmd32, 1);
-+}
-+
-+static inline uint8_t bcm2835_smi_nand_read_byte(struct mtd_info *mtd)
-+{
-+ uint8_t byte;
-+ struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
-+ struct bcm2835_smi_instance *inst = host->smi_inst;
-+
-+ bcm2835_smi_read_buf(inst, &byte, 1);
-+ return byte;
-+}
-+
-+static inline void bcm2835_smi_nand_write_byte(struct mtd_info *mtd,
-+ uint8_t byte)
-+{
-+ struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
-+ struct bcm2835_smi_instance *inst = host->smi_inst;
-+
-+ bcm2835_smi_write_buf(inst, &byte, 1);
-+}
-+
-+static inline void bcm2835_smi_nand_write_buf(struct mtd_info *mtd,
-+ const uint8_t *buf, int len)
-+{
-+ struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
-+ struct bcm2835_smi_instance *inst = host->smi_inst;
-+
-+ bcm2835_smi_write_buf(inst, buf, len);
-+}
-+
-+static inline void bcm2835_smi_nand_read_buf(struct mtd_info *mtd,
-+ uint8_t *buf, int len)
-+{
-+ struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
-+ struct bcm2835_smi_instance *inst = host->smi_inst;
-+
-+ bcm2835_smi_read_buf(inst, buf, len);
-+}
-+
-+/****************************************************************************
-+*
-+* Probe and remove functions
-+*
-+***************************************************************************/
-+
-+static int bcm2835_smi_nand_probe(struct platform_device *pdev)
-+{
-+ struct bcm2835_smi_nand_host *host;
-+ struct nand_chip *this;
-+ struct mtd_info *mtd;
-+ struct device *dev = &pdev->dev;
-+ struct device_node *node = dev->of_node, *smi_node;
-+ struct mtd_part_parser_data ppdata;
-+ struct smi_settings *smi_settings;
-+ struct bcm2835_smi_instance *smi_inst;
-+ int ret = -ENXIO;
-+
-+ if (!node) {
-+ dev_err(dev, "No device tree node supplied!");
-+ return -EINVAL;
-+ }
-+
-+ smi_node = of_parse_phandle(node, "smi_handle", 0);
-+
-+ /* Request use of SMI peripheral: */
-+ smi_inst = bcm2835_smi_get(smi_node);
-+
-+ if (!smi_inst) {
-+ dev_err(dev, "Could not register with SMI.");
-+ return -EPROBE_DEFER;
-+ }
-+
-+ /* Set SMI timing and bus width */
-+
-+ smi_settings = bcm2835_smi_get_settings_from_regs(smi_inst);
-+
-+ smi_settings->data_width = SMI_WIDTH_8BIT;
-+ smi_settings->read_setup_time = 2;
-+ smi_settings->read_hold_time = 1;
-+ smi_settings->read_pace_time = 1;
-+ smi_settings->read_strobe_time = 3;
-+
-+ smi_settings->write_setup_time = 2;
-+ smi_settings->write_hold_time = 1;
-+ smi_settings->write_pace_time = 1;
-+ smi_settings->write_strobe_time = 3;
-+
-+ bcm2835_smi_set_regs_from_settings(smi_inst);
-+
-+ host = devm_kzalloc(dev, sizeof(struct bcm2835_smi_nand_host),
-+ GFP_KERNEL);
-+ if (!host)
-+ return -ENOMEM;
-+
-+ host->dev = dev;
-+ host->smi_inst = smi_inst;
-+
-+ platform_set_drvdata(pdev, host);
-+
-+ /* Link the structures together */
-+
-+ this = &host->nand_chip;
-+ mtd = &host->mtd;
-+ mtd->priv = this;
-+ mtd->owner = THIS_MODULE;
-+ mtd->dev.parent = dev;
-+ mtd->name = DRIVER_NAME;
-+ ppdata.of_node = node;
-+
-+ /* 20 us command delay time... */
-+ this->chip_delay = 20;
-+
-+ this->priv = host;
-+ this->cmd_ctrl = bcm2835_smi_nand_cmd_ctrl;
-+ this->read_byte = bcm2835_smi_nand_read_byte;
-+ this->write_byte = bcm2835_smi_nand_write_byte;
-+ this->write_buf = bcm2835_smi_nand_write_buf;
-+ this->read_buf = bcm2835_smi_nand_read_buf;
-+
-+ this->ecc.mode = NAND_ECC_SOFT;
-+
-+ /* Should never be accessed directly: */
-+
-+ this->IO_ADDR_R = (void *)0xdeadbeef;
-+ this->IO_ADDR_W = (void *)0xdeadbeef;
-+
-+ /* First scan to find the device and get the page size */
-+
-+ if (nand_scan_ident(mtd, 1, NULL))
-+ return -ENXIO;
-+
-+ /* Second phase scan */
-+
-+ if (nand_scan_tail(mtd))
-+ return -ENXIO;
-+
-+ ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
-+ if (!ret)
-+ return 0;
-+
-+ nand_release(mtd);
-+ return -EINVAL;
-+}
-+
-+static int bcm2835_smi_nand_remove(struct platform_device *pdev)
-+{
-+ struct bcm2835_smi_nand_host *host = platform_get_drvdata(pdev);
-+
-+ nand_release(&host->mtd);
-+
-+ return 0;
-+}
-+
-+/****************************************************************************
-+*
-+* Register the driver with device tree
-+*
-+***************************************************************************/
-+
-+static const struct of_device_id bcm2835_smi_nand_of_match[] = {
-+ {.compatible = "brcm,bcm2835-smi-nand",},
-+ { /* sentinel */ }
-+};
-+
-+MODULE_DEVICE_TABLE(of, bcm2835_smi_nand_of_match);
-+
-+static struct platform_driver bcm2835_smi_nand_driver = {
-+ .probe = bcm2835_smi_nand_probe,
-+ .remove = bcm2835_smi_nand_remove,
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ .of_match_table = bcm2835_smi_nand_of_match,
-+ },
-+};
-+
-+module_platform_driver(bcm2835_smi_nand_driver);
-+
-+MODULE_ALIAS("platform:smi-nand-bcm2835");
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION
-+ ("Driver for NAND chips using Broadcom Secondary Memory Interface");
-+MODULE_AUTHOR("Luke Wren <luke@raspberrypi.org>");
diff --git a/target/linux/brcm2708/patches-4.4/0042-lirc-added-support-for-RaspberryPi-GPIO.patch b/target/linux/brcm2708/patches-4.4/0042-lirc-added-support-for-RaspberryPi-GPIO.patch
new file mode 100644
index 0000000000..690cc2e4d1
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0042-lirc-added-support-for-RaspberryPi-GPIO.patch
@@ -0,0 +1,841 @@
+From e33b63b907bb2a83b9c40ebbe15eeced175c8567 Mon Sep 17 00:00:00 2001
+From: Aron Szabo <aron@aron.ws>
+Date: Sat, 16 Jun 2012 12:15:55 +0200
+Subject: [PATCH 042/381] lirc: added support for RaspberryPi GPIO
+
+lirc_rpi: Use read_current_timer to determine transmitter delay. Thanks to jjmz and others
+See: https://github.com/raspberrypi/linux/issues/525
+
+lirc: Remove restriction on gpio pins that can be used with lirc
+
+Compute Module, for example could use different pins
+
+lirc_rpi: Add parameter to specify input pin pull
+
+Depending on the connected IR circuitry it might be desirable to change the
+gpios internal pull from it pull-down default behaviour. Add a module
+parameter to allow the user to set it explicitly.
+
+Signed-off-by: Julian Scheel <julian@jusst.de>
+
+lirc-rpi: Use the higher-level irq control functions
+
+This module used to access the irq_chip methods of the
+gpio controller directly, rather than going through the
+standard enable_irq/irq_set_irq_type functions. This
+caused problems on pinctrl-bcm2835 which only implements
+the irq_enable/disable methods and not irq_unmask/mask.
+
+lirc-rpi: Correct the interrupt usage
+
+1) Correct the use of enable_irq (i.e. don't call it so often)
+2) Correct the shutdown sequence.
+3) Avoid a bcm2708_gpio driver quirk by setting the irq flags earlier
+
+lirc-rpi: use getnstimeofday instead of read_current_timer
+
+read_current_timer isn't guaranteed to return values in
+microseconds, and indeed it doesn't on a Pi2.
+
+Issue: linux#827
+
+lirc-rpi: Add device tree support, and a suitable overlay
+
+The overlay supports DT parameters that match the old module
+parameters, except that gpio_in_pull should be set using the
+strings "up", "down" or "off".
+
+lirc-rpi: Also support pinctrl-bcm2835 in non-DT mode
+---
+ drivers/staging/media/lirc/Kconfig | 6 +
+ drivers/staging/media/lirc/Makefile | 1 +
+ drivers/staging/media/lirc/lirc_rpi.c | 730 ++++++++++++++++++++++++++++++++++
+ include/linux/platform_data/bcm2708.h | 23 ++
+ 4 files changed, 760 insertions(+)
+ create mode 100644 drivers/staging/media/lirc/lirc_rpi.c
+ create mode 100644 include/linux/platform_data/bcm2708.h
+
+--- a/drivers/staging/media/lirc/Kconfig
++++ b/drivers/staging/media/lirc/Kconfig
+@@ -32,6 +32,12 @@ config LIRC_PARALLEL
+ help
+ Driver for Homebrew Parallel Port Receivers
+
++config LIRC_RPI
++ tristate "Homebrew GPIO Port Receiver/Transmitter for the RaspberryPi"
++ depends on LIRC
++ help
++ Driver for Homebrew GPIO Port Receiver/Transmitter for the RaspberryPi
++
+ config LIRC_SASEM
+ tristate "Sasem USB IR Remote"
+ depends on LIRC && USB
+--- a/drivers/staging/media/lirc/Makefile
++++ b/drivers/staging/media/lirc/Makefile
+@@ -6,6 +6,7 @@
+ obj-$(CONFIG_LIRC_BT829) += lirc_bt829.o
+ obj-$(CONFIG_LIRC_IMON) += lirc_imon.o
+ obj-$(CONFIG_LIRC_PARALLEL) += lirc_parallel.o
++obj-$(CONFIG_LIRC_RPI) += lirc_rpi.o
+ obj-$(CONFIG_LIRC_SASEM) += lirc_sasem.o
+ obj-$(CONFIG_LIRC_SERIAL) += lirc_serial.o
+ obj-$(CONFIG_LIRC_SIR) += lirc_sir.o
+--- /dev/null
++++ b/drivers/staging/media/lirc/lirc_rpi.c
+@@ -0,0 +1,730 @@
++/*
++ * lirc_rpi.c
++ *
++ * lirc_rpi - Device driver that records pulse- and pause-lengths
++ * (space-lengths) (just like the lirc_serial driver does)
++ * between GPIO interrupt events on the Raspberry Pi.
++ * Lots of code has been taken from the lirc_serial module,
++ * so I would like say thanks to the authors.
++ *
++ * Copyright (C) 2012 Aron Robert Szabo <aron@reon.hu>,
++ * Michael Bishop <cleverca22@gmail.com>
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#include <linux/module.h>
++#include <linux/errno.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++#include <linux/kernel.h>
++#include <linux/time.h>
++#include <linux/timex.h>
++#include <linux/timekeeping.h>
++#include <linux/string.h>
++#include <linux/delay.h>
++#include <linux/platform_device.h>
++#include <linux/irq.h>
++#include <linux/spinlock.h>
++#include <media/lirc.h>
++#include <media/lirc_dev.h>
++#include <linux/gpio.h>
++#include <linux/of_platform.h>
++#include <linux/platform_data/bcm2708.h>
++
++#define LIRC_DRIVER_NAME "lirc_rpi"
++#define RBUF_LEN 256
++#define LIRC_TRANSMITTER_LATENCY 50
++
++#ifndef MAX_UDELAY_MS
++#define MAX_UDELAY_US 5000
++#else
++#define MAX_UDELAY_US (MAX_UDELAY_MS*1000)
++#endif
++
++#define dprintk(fmt, args...) \
++ do { \
++ if (debug) \
++ printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \
++ fmt, ## args); \
++ } while (0)
++
++/* module parameters */
++
++/* set the default GPIO input pin */
++static int gpio_in_pin = 18;
++/* set the default pull behaviour for input pin */
++static int gpio_in_pull = BCM2708_PULL_DOWN;
++/* set the default GPIO output pin */
++static int gpio_out_pin = 17;
++/* enable debugging messages */
++static bool debug;
++/* -1 = auto, 0 = active high, 1 = active low */
++static int sense = -1;
++/* use softcarrier by default */
++static bool softcarrier = 1;
++/* 0 = do not invert output, 1 = invert output */
++static bool invert = 0;
++
++struct gpio_chip *gpiochip;
++static int irq_num;
++
++/* forward declarations */
++static long send_pulse(unsigned long length);
++static void send_space(long length);
++static void lirc_rpi_exit(void);
++
++static struct platform_device *lirc_rpi_dev;
++static struct timeval lasttv = { 0, 0 };
++static struct lirc_buffer rbuf;
++static spinlock_t lock;
++
++/* initialized/set in init_timing_params() */
++static unsigned int freq = 38000;
++static unsigned int duty_cycle = 50;
++static unsigned long period;
++static unsigned long pulse_width;
++static unsigned long space_width;
++
++static void safe_udelay(unsigned long usecs)
++{
++ while (usecs > MAX_UDELAY_US) {
++ udelay(MAX_UDELAY_US);
++ usecs -= MAX_UDELAY_US;
++ }
++ udelay(usecs);
++}
++
++static unsigned long read_current_us(void)
++{
++ struct timespec now;
++ getnstimeofday(&now);
++ return (now.tv_sec * 1000000) + (now.tv_nsec/1000);
++}
++
++static int init_timing_params(unsigned int new_duty_cycle,
++ unsigned int new_freq)
++{
++ if (1000 * 1000000L / new_freq * new_duty_cycle / 100 <=
++ LIRC_TRANSMITTER_LATENCY)
++ return -EINVAL;
++ if (1000 * 1000000L / new_freq * (100 - new_duty_cycle) / 100 <=
++ LIRC_TRANSMITTER_LATENCY)
++ return -EINVAL;
++ duty_cycle = new_duty_cycle;
++ freq = new_freq;
++ period = 1000 * 1000000L / freq;
++ pulse_width = period * duty_cycle / 100;
++ space_width = period - pulse_width;
++ dprintk("in init_timing_params, freq=%d pulse=%ld, "
++ "space=%ld\n", freq, pulse_width, space_width);
++ return 0;
++}
++
++static long send_pulse_softcarrier(unsigned long length)
++{
++ int flag;
++ unsigned long actual, target;
++ unsigned long actual_us, initial_us, target_us;
++
++ length *= 1000;
++
++ actual = 0; target = 0; flag = 0;
++ actual_us = read_current_us();
++
++ while (actual < length) {
++ if (flag) {
++ gpiochip->set(gpiochip, gpio_out_pin, invert);
++ target += space_width;
++ } else {
++ gpiochip->set(gpiochip, gpio_out_pin, !invert);
++ target += pulse_width;
++ }
++ initial_us = actual_us;
++ target_us = actual_us + (target - actual) / 1000;
++ /*
++ * Note - we've checked in ioctl that the pulse/space
++ * widths are big enough so that d is > 0
++ */
++ if ((int)(target_us - actual_us) > 0)
++ udelay(target_us - actual_us);
++ actual_us = read_current_us();
++ actual += (actual_us - initial_us) * 1000;
++ flag = !flag;
++ }
++ return (actual-length) / 1000;
++}
++
++static long send_pulse(unsigned long length)
++{
++ if (length <= 0)
++ return 0;
++
++ if (softcarrier) {
++ return send_pulse_softcarrier(length);
++ } else {
++ gpiochip->set(gpiochip, gpio_out_pin, !invert);
++ safe_udelay(length);
++ return 0;
++ }
++}
++
++static void send_space(long length)
++{
++ gpiochip->set(gpiochip, gpio_out_pin, invert);
++ if (length <= 0)
++ return;
++ safe_udelay(length);
++}
++
++static void rbwrite(int l)
++{
++ if (lirc_buffer_full(&rbuf)) {
++ /* no new signals will be accepted */
++ dprintk("Buffer overrun\n");
++ return;
++ }
++ lirc_buffer_write(&rbuf, (void *)&l);
++}
++
++static void frbwrite(int l)
++{
++ /* simple noise filter */
++ static int pulse, space;
++ static unsigned int ptr;
++
++ if (ptr > 0 && (l & PULSE_BIT)) {
++ pulse += l & PULSE_MASK;
++ if (pulse > 250) {
++ rbwrite(space);
++ rbwrite(pulse | PULSE_BIT);
++ ptr = 0;
++ pulse = 0;
++ }
++ return;
++ }
++ if (!(l & PULSE_BIT)) {
++ if (ptr == 0) {
++ if (l > 20000) {
++ space = l;
++ ptr++;
++ return;
++ }
++ } else {
++ if (l > 20000) {
++ space += pulse;
++ if (space > PULSE_MASK)
++ space = PULSE_MASK;
++ space += l;
++ if (space > PULSE_MASK)
++ space = PULSE_MASK;
++ pulse = 0;
++ return;
++ }
++ rbwrite(space);
++ rbwrite(pulse | PULSE_BIT);
++ ptr = 0;
++ pulse = 0;
++ }
++ }
++ rbwrite(l);
++}
++
++static irqreturn_t irq_handler(int i, void *blah, struct pt_regs *regs)
++{
++ struct timeval tv;
++ long deltv;
++ int data;
++ int signal;
++
++ /* use the GPIO signal level */
++ signal = gpiochip->get(gpiochip, gpio_in_pin);
++
++ if (sense != -1) {
++ /* get current time */
++ do_gettimeofday(&tv);
++
++ /* calc time since last interrupt in microseconds */
++ deltv = tv.tv_sec-lasttv.tv_sec;
++ if (tv.tv_sec < lasttv.tv_sec ||
++ (tv.tv_sec == lasttv.tv_sec &&
++ tv.tv_usec < lasttv.tv_usec)) {
++ printk(KERN_WARNING LIRC_DRIVER_NAME
++ ": AIEEEE: your clock just jumped backwards\n");
++ printk(KERN_WARNING LIRC_DRIVER_NAME
++ ": %d %d %lx %lx %lx %lx\n", signal, sense,
++ tv.tv_sec, lasttv.tv_sec,
++ tv.tv_usec, lasttv.tv_usec);
++ data = PULSE_MASK;
++ } else if (deltv > 15) {
++ data = PULSE_MASK; /* really long time */
++ if (!(signal^sense)) {
++ /* sanity check */
++ printk(KERN_WARNING LIRC_DRIVER_NAME
++ ": AIEEEE: %d %d %lx %lx %lx %lx\n",
++ signal, sense, tv.tv_sec, lasttv.tv_sec,
++ tv.tv_usec, lasttv.tv_usec);
++ /*
++ * detecting pulse while this
++ * MUST be a space!
++ */
++ sense = sense ? 0 : 1;
++ }
++ } else {
++ data = (int) (deltv*1000000 +
++ (tv.tv_usec - lasttv.tv_usec));
++ }
++ frbwrite(signal^sense ? data : (data|PULSE_BIT));
++ lasttv = tv;
++ wake_up_interruptible(&rbuf.wait_poll);
++ }
++
++ return IRQ_HANDLED;
++}
++
++static int is_right_chip(struct gpio_chip *chip, void *data)
++{
++ dprintk("is_right_chip %s %d\n", chip->label, strcmp(data, chip->label));
++
++ if (strcmp(data, chip->label) == 0)
++ return 1;
++ return 0;
++}
++
++static inline int read_bool_property(const struct device_node *np,
++ const char *propname,
++ bool *out_value)
++{
++ u32 value = 0;
++ int err = of_property_read_u32(np, propname, &value);
++ if (err == 0)
++ *out_value = (value != 0);
++ return err;
++}
++
++static void read_pin_settings(struct device_node *node)
++{
++ u32 pin;
++ int index;
++
++ for (index = 0;
++ of_property_read_u32_index(
++ node,
++ "brcm,pins",
++ index,
++ &pin) == 0;
++ index++) {
++ u32 function;
++ int err;
++ err = of_property_read_u32_index(
++ node,
++ "brcm,function",
++ index,
++ &function);
++ if (err == 0) {
++ if (function == 1) /* Output */
++ gpio_out_pin = pin;
++ else if (function == 0) /* Input */
++ gpio_in_pin = pin;
++ }
++ }
++}
++
++static int init_port(void)
++{
++ int i, nlow, nhigh;
++ struct device_node *node;
++
++ node = lirc_rpi_dev->dev.of_node;
++
++ gpiochip = gpiochip_find("bcm2708_gpio", is_right_chip);
++
++ /*
++ * Because of the lack of a setpull function, only support
++ * pinctrl-bcm2835 if using device tree.
++ */
++ if (!gpiochip && node)
++ gpiochip = gpiochip_find("pinctrl-bcm2835", is_right_chip);
++
++ if (!gpiochip) {
++ pr_err(LIRC_DRIVER_NAME ": gpio chip not found!\n");
++ return -ENODEV;
++ }
++
++ if (node) {
++ struct device_node *pins_node;
++
++ pins_node = of_parse_phandle(node, "pinctrl-0", 0);
++ if (!pins_node) {
++ printk(KERN_ERR LIRC_DRIVER_NAME
++ ": pinctrl settings not found!\n");
++ return -EINVAL;
++ }
++
++ read_pin_settings(pins_node);
++
++ of_property_read_u32(node, "rpi,sense", &sense);
++
++ read_bool_property(node, "rpi,softcarrier", &softcarrier);
++
++ read_bool_property(node, "rpi,invert", &invert);
++
++ read_bool_property(node, "rpi,debug", &debug);
++
++ } else {
++ return -EINVAL;
++ }
++
++ gpiochip->set(gpiochip, gpio_out_pin, invert);
++
++ irq_num = gpiochip->to_irq(gpiochip, gpio_in_pin);
++ dprintk("to_irq %d\n", irq_num);
++
++ /* if pin is high, then this must be an active low receiver. */
++ if (sense == -1) {
++ /* wait 1/2 sec for the power supply */
++ msleep(500);
++
++ /*
++ * probe 9 times every 0.04s, collect "votes" for
++ * active high/low
++ */
++ nlow = 0;
++ nhigh = 0;
++ for (i = 0; i < 9; i++) {
++ if (gpiochip->get(gpiochip, gpio_in_pin))
++ nlow++;
++ else
++ nhigh++;
++ msleep(40);
++ }
++ sense = (nlow >= nhigh ? 1 : 0);
++ printk(KERN_INFO LIRC_DRIVER_NAME
++ ": auto-detected active %s receiver on GPIO pin %d\n",
++ sense ? "low" : "high", gpio_in_pin);
++ } else {
++ printk(KERN_INFO LIRC_DRIVER_NAME
++ ": manually using active %s receiver on GPIO pin %d\n",
++ sense ? "low" : "high", gpio_in_pin);
++ }
++
++ return 0;
++}
++
++// called when the character device is opened
++static int set_use_inc(void *data)
++{
++ int result;
++
++ /* initialize timestamp */
++ do_gettimeofday(&lasttv);
++
++ result = request_irq(irq_num,
++ (irq_handler_t) irq_handler,
++ IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING,
++ LIRC_DRIVER_NAME, (void*) 0);
++
++ switch (result) {
++ case -EBUSY:
++ printk(KERN_ERR LIRC_DRIVER_NAME
++ ": IRQ %d is busy\n",
++ irq_num);
++ return -EBUSY;
++ case -EINVAL:
++ printk(KERN_ERR LIRC_DRIVER_NAME
++ ": Bad irq number or handler\n");
++ return -EINVAL;
++ default:
++ dprintk("Interrupt %d obtained\n",
++ irq_num);
++ break;
++ };
++
++ /* initialize pulse/space widths */
++ init_timing_params(duty_cycle, freq);
++
++ return 0;
++}
++
++static void set_use_dec(void *data)
++{
++ /* GPIO Pin Falling/Rising Edge Detect Disable */
++ irq_set_irq_type(irq_num, 0);
++ disable_irq(irq_num);
++
++ free_irq(irq_num, (void *) 0);
++
++ dprintk(KERN_INFO LIRC_DRIVER_NAME
++ ": freed IRQ %d\n", irq_num);
++}
++
++static ssize_t lirc_write(struct file *file, const char *buf,
++ size_t n, loff_t *ppos)
++{
++ int i, count;
++ unsigned long flags;
++ long delta = 0;
++ int *wbuf;
++
++ count = n / sizeof(int);
++ if (n % sizeof(int) || count % 2 == 0)
++ return -EINVAL;
++ wbuf = memdup_user(buf, n);
++ if (IS_ERR(wbuf))
++ return PTR_ERR(wbuf);
++ spin_lock_irqsave(&lock, flags);
++
++ for (i = 0; i < count; i++) {
++ if (i%2)
++ send_space(wbuf[i] - delta);
++ else
++ delta = send_pulse(wbuf[i]);
++ }
++ gpiochip->set(gpiochip, gpio_out_pin, invert);
++
++ spin_unlock_irqrestore(&lock, flags);
++ kfree(wbuf);
++ return n;
++}
++
++static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
++{
++ int result;
++ __u32 value;
++
++ switch (cmd) {
++ case LIRC_GET_SEND_MODE:
++ return -ENOIOCTLCMD;
++ break;
++
++ case LIRC_SET_SEND_MODE:
++ result = get_user(value, (__u32 *) arg);
++ if (result)
++ return result;
++ /* only LIRC_MODE_PULSE supported */
++ if (value != LIRC_MODE_PULSE)
++ return -ENOSYS;
++ break;
++
++ case LIRC_GET_LENGTH:
++ return -ENOSYS;
++ break;
++
++ case LIRC_SET_SEND_DUTY_CYCLE:
++ dprintk("SET_SEND_DUTY_CYCLE\n");
++ result = get_user(value, (__u32 *) arg);
++ if (result)
++ return result;
++ if (value <= 0 || value > 100)
++ return -EINVAL;
++ return init_timing_params(value, freq);
++ break;
++
++ case LIRC_SET_SEND_CARRIER:
++ dprintk("SET_SEND_CARRIER\n");
++ result = get_user(value, (__u32 *) arg);
++ if (result)
++ return result;
++ if (value > 500000 || value < 20000)
++ return -EINVAL;
++ return init_timing_params(duty_cycle, value);
++ break;
++
++ default:
++ return lirc_dev_fop_ioctl(filep, cmd, arg);
++ }
++ return 0;
++}
++
++static const struct file_operations lirc_fops = {
++ .owner = THIS_MODULE,
++ .write = lirc_write,
++ .unlocked_ioctl = lirc_ioctl,
++ .read = lirc_dev_fop_read,
++ .poll = lirc_dev_fop_poll,
++ .open = lirc_dev_fop_open,
++ .release = lirc_dev_fop_close,
++ .llseek = no_llseek,
++};
++
++static struct lirc_driver driver = {
++ .name = LIRC_DRIVER_NAME,
++ .minor = -1,
++ .code_length = 1,
++ .sample_rate = 0,
++ .data = NULL,
++ .add_to_buf = NULL,
++ .rbuf = &rbuf,
++ .set_use_inc = set_use_inc,
++ .set_use_dec = set_use_dec,
++ .fops = &lirc_fops,
++ .dev = NULL,
++ .owner = THIS_MODULE,
++};
++
++static const struct of_device_id lirc_rpi_of_match[] = {
++ { .compatible = "rpi,lirc-rpi", },
++ {},
++};
++MODULE_DEVICE_TABLE(of, lirc_rpi_of_match);
++
++static struct platform_driver lirc_rpi_driver = {
++ .driver = {
++ .name = LIRC_DRIVER_NAME,
++ .owner = THIS_MODULE,
++ .of_match_table = of_match_ptr(lirc_rpi_of_match),
++ },
++};
++
++static int __init lirc_rpi_init(void)
++{
++ struct device_node *node;
++ int result;
++
++ /* Init read buffer. */
++ result = lirc_buffer_init(&rbuf, sizeof(int), RBUF_LEN);
++ if (result < 0)
++ return -ENOMEM;
++
++ result = platform_driver_register(&lirc_rpi_driver);
++ if (result) {
++ printk(KERN_ERR LIRC_DRIVER_NAME
++ ": lirc register returned %d\n", result);
++ goto exit_buffer_free;
++ }
++
++ node = of_find_compatible_node(NULL, NULL,
++ lirc_rpi_of_match[0].compatible);
++
++ if (node) {
++ /* DT-enabled */
++ lirc_rpi_dev = of_find_device_by_node(node);
++ WARN_ON(lirc_rpi_dev->dev.of_node != node);
++ of_node_put(node);
++ }
++ else {
++ lirc_rpi_dev = platform_device_alloc(LIRC_DRIVER_NAME, 0);
++ if (!lirc_rpi_dev) {
++ result = -ENOMEM;
++ goto exit_driver_unregister;
++ }
++
++ result = platform_device_add(lirc_rpi_dev);
++ if (result)
++ goto exit_device_put;
++ }
++
++ return 0;
++
++ exit_device_put:
++ platform_device_put(lirc_rpi_dev);
++
++ exit_driver_unregister:
++ platform_driver_unregister(&lirc_rpi_driver);
++
++ exit_buffer_free:
++ lirc_buffer_free(&rbuf);
++
++ return result;
++}
++
++static void lirc_rpi_exit(void)
++{
++ if (!lirc_rpi_dev->dev.of_node)
++ platform_device_unregister(lirc_rpi_dev);
++ platform_driver_unregister(&lirc_rpi_driver);
++ lirc_buffer_free(&rbuf);
++}
++
++static int __init lirc_rpi_init_module(void)
++{
++ int result;
++
++ result = lirc_rpi_init();
++ if (result)
++ return result;
++
++ result = init_port();
++ if (result < 0)
++ goto exit_rpi;
++
++ driver.features = LIRC_CAN_SET_SEND_DUTY_CYCLE |
++ LIRC_CAN_SET_SEND_CARRIER |
++ LIRC_CAN_SEND_PULSE |
++ LIRC_CAN_REC_MODE2;
++
++ driver.dev = &lirc_rpi_dev->dev;
++ driver.minor = lirc_register_driver(&driver);
++
++ if (driver.minor < 0) {
++ printk(KERN_ERR LIRC_DRIVER_NAME
++ ": device registration failed with %d\n", result);
++ result = -EIO;
++ goto exit_rpi;
++ }
++
++ printk(KERN_INFO LIRC_DRIVER_NAME ": driver registered!\n");
++
++ return 0;
++
++ exit_rpi:
++ lirc_rpi_exit();
++
++ return result;
++}
++
++static void __exit lirc_rpi_exit_module(void)
++{
++ lirc_unregister_driver(driver.minor);
++
++ gpio_free(gpio_out_pin);
++ gpio_free(gpio_in_pin);
++
++ lirc_rpi_exit();
++
++ printk(KERN_INFO LIRC_DRIVER_NAME ": cleaned up module\n");
++}
++
++module_init(lirc_rpi_init_module);
++module_exit(lirc_rpi_exit_module);
++
++MODULE_DESCRIPTION("Infra-red receiver and blaster driver for Raspberry Pi GPIO.");
++MODULE_AUTHOR("Aron Robert Szabo <aron@reon.hu>");
++MODULE_AUTHOR("Michael Bishop <cleverca22@gmail.com>");
++MODULE_LICENSE("GPL");
++
++module_param(gpio_out_pin, int, S_IRUGO);
++MODULE_PARM_DESC(gpio_out_pin, "GPIO output/transmitter pin number of the BCM"
++ " processor. (default 17");
++
++module_param(gpio_in_pin, int, S_IRUGO);
++MODULE_PARM_DESC(gpio_in_pin, "GPIO input pin number of the BCM processor."
++ " (default 18");
++
++module_param(gpio_in_pull, int, S_IRUGO);
++MODULE_PARM_DESC(gpio_in_pull, "GPIO input pin pull configuration."
++ " (0 = off, 1 = up, 2 = down, default down)");
++
++module_param(sense, int, S_IRUGO);
++MODULE_PARM_DESC(sense, "Override autodetection of IR receiver circuit"
++ " (0 = active high, 1 = active low )");
++
++module_param(softcarrier, bool, S_IRUGO);
++MODULE_PARM_DESC(softcarrier, "Software carrier (0 = off, 1 = on, default on)");
++
++module_param(invert, bool, S_IRUGO);
++MODULE_PARM_DESC(invert, "Invert output (0 = off, 1 = on, default off");
++
++module_param(debug, bool, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(debug, "Enable debugging messages");
+--- /dev/null
++++ b/include/linux/platform_data/bcm2708.h
+@@ -0,0 +1,23 @@
++/*
++ * include/linux/platform_data/bcm2708.h
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * (C) 2014 Julian Scheel <julian@jusst.de>
++ *
++ */
++#ifndef __BCM2708_H_
++#define __BCM2708_H_
++
++typedef enum {
++ BCM2708_PULL_OFF,
++ BCM2708_PULL_UP,
++ BCM2708_PULL_DOWN
++} bcm2708_gpio_pull_t;
++
++extern int bcm2708_gpio_setpull(struct gpio_chip *gc, unsigned offset,
++ bcm2708_gpio_pull_t value);
++
++#endif
diff --git a/target/linux/brcm2708/patches-4.4/0043-Add-cpufreq-driver.patch b/target/linux/brcm2708/patches-4.4/0043-Add-cpufreq-driver.patch
new file mode 100644
index 0000000000..dfdb9552e5
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0043-Add-cpufreq-driver.patch
@@ -0,0 +1,257 @@
+From 14b034de59582e2dac59aaf95c98d6593cfc5549 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Wed, 3 Jul 2013 00:49:20 +0100
+Subject: [PATCH 043/381] Add cpufreq driver
+
+Signed-off-by: popcornmix <popcornmix@gmail.com>
+---
+ drivers/cpufreq/Kconfig.arm | 9 ++
+ drivers/cpufreq/Makefile | 1 +
+ drivers/cpufreq/bcm2835-cpufreq.c | 213 ++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 223 insertions(+)
+ create mode 100644 drivers/cpufreq/bcm2835-cpufreq.c
+
+--- a/drivers/cpufreq/Kconfig.arm
++++ b/drivers/cpufreq/Kconfig.arm
+@@ -217,6 +217,15 @@ config ARM_SPEAR_CPUFREQ
+ help
+ This adds the CPUFreq driver support for SPEAr SOCs.
+
++config ARM_BCM2835_CPUFREQ
++ depends on RASPBERRYPI_FIRMWARE
++ bool "BCM2835 Driver"
++ default y
++ help
++ This adds the CPUFreq driver for BCM2835
++
++ If in doubt, say N.
++
+ config ARM_TEGRA20_CPUFREQ
+ bool "Tegra20 CPUFreq support"
+ depends on ARCH_TEGRA
+--- a/drivers/cpufreq/Makefile
++++ b/drivers/cpufreq/Makefile
+@@ -73,6 +73,7 @@ obj-$(CONFIG_ARM_SA1100_CPUFREQ) += sa11
+ obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o
+ obj-$(CONFIG_ARM_SCPI_CPUFREQ) += scpi-cpufreq.o
+ obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o
++obj-$(CONFIG_ARM_BCM2835_CPUFREQ) += bcm2835-cpufreq.o
+ obj-$(CONFIG_ARM_TEGRA20_CPUFREQ) += tegra20-cpufreq.o
+ obj-$(CONFIG_ARM_TEGRA124_CPUFREQ) += tegra124-cpufreq.o
+ obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o
+--- /dev/null
++++ b/drivers/cpufreq/bcm2835-cpufreq.c
+@@ -0,0 +1,213 @@
++/*****************************************************************************
++* Copyright 2011 Broadcom Corporation. All rights reserved.
++*
++* Unless you and Broadcom execute a separate written software license
++* agreement governing use of this software, this software is licensed to you
++* under the terms of the GNU General Public License version 2, available at
++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
++*
++* Notwithstanding the above, under no circumstances may you combine this
++* software in any way with any other Broadcom software provided under a
++* license other than the GPL, without Broadcom's express prior written
++* consent.
++*****************************************************************************/
++
++/*****************************************************************************
++* FILENAME: bcm2835-cpufreq.h
++* DESCRIPTION: This driver dynamically manages the CPU Frequency of the ARM
++* processor. Messages are sent to Videocore either setting or requesting the
++* frequency of the ARM in order to match an appropiate frequency to the current
++* usage of the processor. The policy which selects the frequency to use is
++* defined in the kernel .config file, but can be changed during runtime.
++*****************************************************************************/
++
++/* ---------- INCLUDES ---------- */
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/cpufreq.h>
++#include <soc/bcm2835/raspberrypi-firmware.h>
++
++/* ---------- DEFINES ---------- */
++/*#define CPUFREQ_DEBUG_ENABLE*/ /* enable debugging */
++#define MODULE_NAME "bcm2835-cpufreq"
++
++#define VCMSG_ID_ARM_CLOCK 0x000000003 /* Clock/Voltage ID's */
++
++/* debug printk macros */
++#ifdef CPUFREQ_DEBUG_ENABLE
++#define print_debug(fmt,...) pr_debug("%s:%s:%d: "fmt, MODULE_NAME, __func__, __LINE__, ##__VA_ARGS__)
++#else
++#define print_debug(fmt,...)
++#endif
++#define print_err(fmt,...) pr_err("%s:%s:%d: "fmt, MODULE_NAME, __func__,__LINE__, ##__VA_ARGS__)
++#define print_info(fmt,...) pr_info("%s: "fmt, MODULE_NAME, ##__VA_ARGS__)
++
++/* ---------- GLOBALS ---------- */
++static struct cpufreq_driver bcm2835_cpufreq_driver; /* the cpufreq driver global */
++
++static struct cpufreq_frequency_table bcm2835_freq_table[] = {
++ {0, 0, 0},
++ {0, 0, 0},
++ {0, 0, CPUFREQ_TABLE_END},
++};
++
++/*
++ ===============================================
++ clk_rate either gets or sets the clock rates.
++ ===============================================
++*/
++
++static int bcm2835_cpufreq_clock_property(u32 tag, u32 id, u32 *val)
++{
++ struct rpi_firmware *fw = rpi_firmware_get(NULL);
++ struct {
++ u32 id;
++ u32 val;
++ } packet;
++ int ret;
++
++ packet.id = id;
++ packet.val = *val;
++ ret = rpi_firmware_property(fw, tag, &packet, sizeof(packet));
++ if (ret)
++ return ret;
++
++ *val = packet.val;
++
++ return 0;
++}
++
++static uint32_t bcm2835_cpufreq_set_clock(int cur_rate, int arm_rate)
++{
++ u32 rate = arm_rate * 1000;
++ int ret;
++
++ ret = bcm2835_cpufreq_clock_property(RPI_FIRMWARE_SET_CLOCK_RATE, VCMSG_ID_ARM_CLOCK, &rate);
++ if (ret) {
++ print_err("Failed to set clock: %d (%d)\n", arm_rate, ret);
++ return 0;
++ }
++
++ rate /= 1000;
++ print_debug("Setting new frequency = %d -> %d (actual %d)\n", cur_rate, arm_rate, rate);
++
++ return rate;
++}
++
++static uint32_t bcm2835_cpufreq_get_clock(int tag)
++{
++ u32 rate;
++ int ret;
++
++ ret = bcm2835_cpufreq_clock_property(tag, VCMSG_ID_ARM_CLOCK, &rate);
++ if (ret) {
++ print_err("Failed to get clock (%d)\n", ret);
++ return 0;
++ }
++
++ rate /= 1000;
++ print_debug("%s frequency = %u\n",
++ tag == RPI_FIRMWARE_GET_CLOCK_RATE ? "Current":
++ tag == RPI_FIRMWARE_GET_MIN_CLOCK_RATE ? "Min":
++ tag == RPI_FIRMWARE_GET_MAX_CLOCK_RATE ? "Max":
++ "Unexpected", rate);
++
++ return rate;
++}
++
++/*
++ ====================================================
++ Module Initialisation registers the cpufreq driver
++ ====================================================
++*/
++static int __init bcm2835_cpufreq_module_init(void)
++{
++ print_debug("IN\n");
++ return cpufreq_register_driver(&bcm2835_cpufreq_driver);
++}
++
++/*
++ =============
++ Module exit
++ =============
++*/
++static void __exit bcm2835_cpufreq_module_exit(void)
++{
++ print_debug("IN\n");
++ cpufreq_unregister_driver(&bcm2835_cpufreq_driver);
++ return;
++}
++
++/*
++ ==============================================================
++ Initialisation function sets up the CPU policy for first use
++ ==============================================================
++*/
++static int bcm2835_cpufreq_driver_init(struct cpufreq_policy *policy)
++{
++ /* measured value of how long it takes to change frequency */
++ const unsigned int transition_latency = 355000; /* ns */
++
++ if (!rpi_firmware_get(NULL)) {
++ print_err("Firmware is not available\n");
++ return -ENODEV;
++ }
++
++ /* now find out what the maximum and minimum frequencies are */
++ bcm2835_freq_table[0].frequency = bcm2835_cpufreq_get_clock(RPI_FIRMWARE_GET_MIN_CLOCK_RATE);
++ bcm2835_freq_table[1].frequency = bcm2835_cpufreq_get_clock(RPI_FIRMWARE_GET_MAX_CLOCK_RATE);
++
++ print_info("min=%d max=%d\n", bcm2835_freq_table[0].frequency, bcm2835_freq_table[1].frequency);
++ return cpufreq_generic_init(policy, bcm2835_freq_table, transition_latency);
++}
++
++/*
++ =====================================================================
++ Target index function chooses the requested frequency from the table
++ =====================================================================
++*/
++
++static int bcm2835_cpufreq_driver_target_index(struct cpufreq_policy *policy, unsigned int state)
++{
++ unsigned int target_freq = bcm2835_freq_table[state].frequency;
++ unsigned int cur = bcm2835_cpufreq_set_clock(policy->cur, target_freq);
++
++ if (!cur)
++ {
++ print_err("Error occurred setting a new frequency (%d)\n", target_freq);
++ return -EINVAL;
++ }
++ print_debug("%s: %i: freq %d->%d\n", policy->governor->name, state, policy->cur, cur);
++ return 0;
++}
++
++/*
++ ======================================================
++ Get function returns the current frequency from table
++ ======================================================
++*/
++
++static unsigned int bcm2835_cpufreq_driver_get(unsigned int cpu)
++{
++ unsigned int actual_rate = bcm2835_cpufreq_get_clock(RPI_FIRMWARE_GET_CLOCK_RATE);
++ print_debug("cpu%d: freq=%d\n", cpu, actual_rate);
++ return actual_rate <= bcm2835_freq_table[0].frequency ? bcm2835_freq_table[0].frequency : bcm2835_freq_table[1].frequency;
++}
++
++/* the CPUFreq driver */
++static struct cpufreq_driver bcm2835_cpufreq_driver = {
++ .name = "BCM2835 CPUFreq",
++ .init = bcm2835_cpufreq_driver_init,
++ .verify = cpufreq_generic_frequency_table_verify,
++ .target_index = bcm2835_cpufreq_driver_target_index,
++ .get = bcm2835_cpufreq_driver_get,
++ .attr = cpufreq_generic_attr,
++};
++
++MODULE_AUTHOR("Dorian Peake and Dom Cobley");
++MODULE_DESCRIPTION("CPU frequency driver for BCM2835 chip");
++MODULE_LICENSE("GPL");
++
++module_init(bcm2835_cpufreq_module_init);
++module_exit(bcm2835_cpufreq_module_exit);
diff --git a/target/linux/brcm2708/patches-4.4/0043-lirc-added-support-for-RaspberryPi-GPIO.patch b/target/linux/brcm2708/patches-4.4/0043-lirc-added-support-for-RaspberryPi-GPIO.patch
deleted file mode 100644
index a46d3af154..0000000000
--- a/target/linux/brcm2708/patches-4.4/0043-lirc-added-support-for-RaspberryPi-GPIO.patch
+++ /dev/null
@@ -1,841 +0,0 @@
-From 2faad8f6644fa53418c5a7b80da8d5400b72df3f Mon Sep 17 00:00:00 2001
-From: Aron Szabo <aron@aron.ws>
-Date: Sat, 16 Jun 2012 12:15:55 +0200
-Subject: [PATCH 043/170] lirc: added support for RaspberryPi GPIO
-
-lirc_rpi: Use read_current_timer to determine transmitter delay. Thanks to jjmz and others
-See: https://github.com/raspberrypi/linux/issues/525
-
-lirc: Remove restriction on gpio pins that can be used with lirc
-
-Compute Module, for example could use different pins
-
-lirc_rpi: Add parameter to specify input pin pull
-
-Depending on the connected IR circuitry it might be desirable to change the
-gpios internal pull from it pull-down default behaviour. Add a module
-parameter to allow the user to set it explicitly.
-
-Signed-off-by: Julian Scheel <julian@jusst.de>
-
-lirc-rpi: Use the higher-level irq control functions
-
-This module used to access the irq_chip methods of the
-gpio controller directly, rather than going through the
-standard enable_irq/irq_set_irq_type functions. This
-caused problems on pinctrl-bcm2835 which only implements
-the irq_enable/disable methods and not irq_unmask/mask.
-
-lirc-rpi: Correct the interrupt usage
-
-1) Correct the use of enable_irq (i.e. don't call it so often)
-2) Correct the shutdown sequence.
-3) Avoid a bcm2708_gpio driver quirk by setting the irq flags earlier
-
-lirc-rpi: use getnstimeofday instead of read_current_timer
-
-read_current_timer isn't guaranteed to return values in
-microseconds, and indeed it doesn't on a Pi2.
-
-Issue: linux#827
-
-lirc-rpi: Add device tree support, and a suitable overlay
-
-The overlay supports DT parameters that match the old module
-parameters, except that gpio_in_pull should be set using the
-strings "up", "down" or "off".
-
-lirc-rpi: Also support pinctrl-bcm2835 in non-DT mode
----
- drivers/staging/media/lirc/Kconfig | 6 +
- drivers/staging/media/lirc/Makefile | 1 +
- drivers/staging/media/lirc/lirc_rpi.c | 730 ++++++++++++++++++++++++++++++++++
- include/linux/platform_data/bcm2708.h | 23 ++
- 4 files changed, 760 insertions(+)
- create mode 100644 drivers/staging/media/lirc/lirc_rpi.c
- create mode 100644 include/linux/platform_data/bcm2708.h
-
---- a/drivers/staging/media/lirc/Kconfig
-+++ b/drivers/staging/media/lirc/Kconfig
-@@ -32,6 +32,12 @@ config LIRC_PARALLEL
- help
- Driver for Homebrew Parallel Port Receivers
-
-+config LIRC_RPI
-+ tristate "Homebrew GPIO Port Receiver/Transmitter for the RaspberryPi"
-+ depends on LIRC
-+ help
-+ Driver for Homebrew GPIO Port Receiver/Transmitter for the RaspberryPi
-+
- config LIRC_SASEM
- tristate "Sasem USB IR Remote"
- depends on LIRC && USB
---- a/drivers/staging/media/lirc/Makefile
-+++ b/drivers/staging/media/lirc/Makefile
-@@ -6,6 +6,7 @@
- obj-$(CONFIG_LIRC_BT829) += lirc_bt829.o
- obj-$(CONFIG_LIRC_IMON) += lirc_imon.o
- obj-$(CONFIG_LIRC_PARALLEL) += lirc_parallel.o
-+obj-$(CONFIG_LIRC_RPI) += lirc_rpi.o
- obj-$(CONFIG_LIRC_SASEM) += lirc_sasem.o
- obj-$(CONFIG_LIRC_SERIAL) += lirc_serial.o
- obj-$(CONFIG_LIRC_SIR) += lirc_sir.o
---- /dev/null
-+++ b/drivers/staging/media/lirc/lirc_rpi.c
-@@ -0,0 +1,730 @@
-+/*
-+ * lirc_rpi.c
-+ *
-+ * lirc_rpi - Device driver that records pulse- and pause-lengths
-+ * (space-lengths) (just like the lirc_serial driver does)
-+ * between GPIO interrupt events on the Raspberry Pi.
-+ * Lots of code has been taken from the lirc_serial module,
-+ * so I would like say thanks to the authors.
-+ *
-+ * Copyright (C) 2012 Aron Robert Szabo <aron@reon.hu>,
-+ * Michael Bishop <cleverca22@gmail.com>
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/errno.h>
-+#include <linux/interrupt.h>
-+#include <linux/sched.h>
-+#include <linux/kernel.h>
-+#include <linux/time.h>
-+#include <linux/timex.h>
-+#include <linux/timekeeping.h>
-+#include <linux/string.h>
-+#include <linux/delay.h>
-+#include <linux/platform_device.h>
-+#include <linux/irq.h>
-+#include <linux/spinlock.h>
-+#include <media/lirc.h>
-+#include <media/lirc_dev.h>
-+#include <linux/gpio.h>
-+#include <linux/of_platform.h>
-+#include <linux/platform_data/bcm2708.h>
-+
-+#define LIRC_DRIVER_NAME "lirc_rpi"
-+#define RBUF_LEN 256
-+#define LIRC_TRANSMITTER_LATENCY 50
-+
-+#ifndef MAX_UDELAY_MS
-+#define MAX_UDELAY_US 5000
-+#else
-+#define MAX_UDELAY_US (MAX_UDELAY_MS*1000)
-+#endif
-+
-+#define dprintk(fmt, args...) \
-+ do { \
-+ if (debug) \
-+ printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \
-+ fmt, ## args); \
-+ } while (0)
-+
-+/* module parameters */
-+
-+/* set the default GPIO input pin */
-+static int gpio_in_pin = 18;
-+/* set the default pull behaviour for input pin */
-+static int gpio_in_pull = BCM2708_PULL_DOWN;
-+/* set the default GPIO output pin */
-+static int gpio_out_pin = 17;
-+/* enable debugging messages */
-+static bool debug;
-+/* -1 = auto, 0 = active high, 1 = active low */
-+static int sense = -1;
-+/* use softcarrier by default */
-+static bool softcarrier = 1;
-+/* 0 = do not invert output, 1 = invert output */
-+static bool invert = 0;
-+
-+struct gpio_chip *gpiochip;
-+static int irq_num;
-+
-+/* forward declarations */
-+static long send_pulse(unsigned long length);
-+static void send_space(long length);
-+static void lirc_rpi_exit(void);
-+
-+static struct platform_device *lirc_rpi_dev;
-+static struct timeval lasttv = { 0, 0 };
-+static struct lirc_buffer rbuf;
-+static spinlock_t lock;
-+
-+/* initialized/set in init_timing_params() */
-+static unsigned int freq = 38000;
-+static unsigned int duty_cycle = 50;
-+static unsigned long period;
-+static unsigned long pulse_width;
-+static unsigned long space_width;
-+
-+static void safe_udelay(unsigned long usecs)
-+{
-+ while (usecs > MAX_UDELAY_US) {
-+ udelay(MAX_UDELAY_US);
-+ usecs -= MAX_UDELAY_US;
-+ }
-+ udelay(usecs);
-+}
-+
-+static unsigned long read_current_us(void)
-+{
-+ struct timespec now;
-+ getnstimeofday(&now);
-+ return (now.tv_sec * 1000000) + (now.tv_nsec/1000);
-+}
-+
-+static int init_timing_params(unsigned int new_duty_cycle,
-+ unsigned int new_freq)
-+{
-+ if (1000 * 1000000L / new_freq * new_duty_cycle / 100 <=
-+ LIRC_TRANSMITTER_LATENCY)
-+ return -EINVAL;
-+ if (1000 * 1000000L / new_freq * (100 - new_duty_cycle) / 100 <=
-+ LIRC_TRANSMITTER_LATENCY)
-+ return -EINVAL;
-+ duty_cycle = new_duty_cycle;
-+ freq = new_freq;
-+ period = 1000 * 1000000L / freq;
-+ pulse_width = period * duty_cycle / 100;
-+ space_width = period - pulse_width;
-+ dprintk("in init_timing_params, freq=%d pulse=%ld, "
-+ "space=%ld\n", freq, pulse_width, space_width);
-+ return 0;
-+}
-+
-+static long send_pulse_softcarrier(unsigned long length)
-+{
-+ int flag;
-+ unsigned long actual, target;
-+ unsigned long actual_us, initial_us, target_us;
-+
-+ length *= 1000;
-+
-+ actual = 0; target = 0; flag = 0;
-+ actual_us = read_current_us();
-+
-+ while (actual < length) {
-+ if (flag) {
-+ gpiochip->set(gpiochip, gpio_out_pin, invert);
-+ target += space_width;
-+ } else {
-+ gpiochip->set(gpiochip, gpio_out_pin, !invert);
-+ target += pulse_width;
-+ }
-+ initial_us = actual_us;
-+ target_us = actual_us + (target - actual) / 1000;
-+ /*
-+ * Note - we've checked in ioctl that the pulse/space
-+ * widths are big enough so that d is > 0
-+ */
-+ if ((int)(target_us - actual_us) > 0)
-+ udelay(target_us - actual_us);
-+ actual_us = read_current_us();
-+ actual += (actual_us - initial_us) * 1000;
-+ flag = !flag;
-+ }
-+ return (actual-length) / 1000;
-+}
-+
-+static long send_pulse(unsigned long length)
-+{
-+ if (length <= 0)
-+ return 0;
-+
-+ if (softcarrier) {
-+ return send_pulse_softcarrier(length);
-+ } else {
-+ gpiochip->set(gpiochip, gpio_out_pin, !invert);
-+ safe_udelay(length);
-+ return 0;
-+ }
-+}
-+
-+static void send_space(long length)
-+{
-+ gpiochip->set(gpiochip, gpio_out_pin, invert);
-+ if (length <= 0)
-+ return;
-+ safe_udelay(length);
-+}
-+
-+static void rbwrite(int l)
-+{
-+ if (lirc_buffer_full(&rbuf)) {
-+ /* no new signals will be accepted */
-+ dprintk("Buffer overrun\n");
-+ return;
-+ }
-+ lirc_buffer_write(&rbuf, (void *)&l);
-+}
-+
-+static void frbwrite(int l)
-+{
-+ /* simple noise filter */
-+ static int pulse, space;
-+ static unsigned int ptr;
-+
-+ if (ptr > 0 && (l & PULSE_BIT)) {
-+ pulse += l & PULSE_MASK;
-+ if (pulse > 250) {
-+ rbwrite(space);
-+ rbwrite(pulse | PULSE_BIT);
-+ ptr = 0;
-+ pulse = 0;
-+ }
-+ return;
-+ }
-+ if (!(l & PULSE_BIT)) {
-+ if (ptr == 0) {
-+ if (l > 20000) {
-+ space = l;
-+ ptr++;
-+ return;
-+ }
-+ } else {
-+ if (l > 20000) {
-+ space += pulse;
-+ if (space > PULSE_MASK)
-+ space = PULSE_MASK;
-+ space += l;
-+ if (space > PULSE_MASK)
-+ space = PULSE_MASK;
-+ pulse = 0;
-+ return;
-+ }
-+ rbwrite(space);
-+ rbwrite(pulse | PULSE_BIT);
-+ ptr = 0;
-+ pulse = 0;
-+ }
-+ }
-+ rbwrite(l);
-+}
-+
-+static irqreturn_t irq_handler(int i, void *blah, struct pt_regs *regs)
-+{
-+ struct timeval tv;
-+ long deltv;
-+ int data;
-+ int signal;
-+
-+ /* use the GPIO signal level */
-+ signal = gpiochip->get(gpiochip, gpio_in_pin);
-+
-+ if (sense != -1) {
-+ /* get current time */
-+ do_gettimeofday(&tv);
-+
-+ /* calc time since last interrupt in microseconds */
-+ deltv = tv.tv_sec-lasttv.tv_sec;
-+ if (tv.tv_sec < lasttv.tv_sec ||
-+ (tv.tv_sec == lasttv.tv_sec &&
-+ tv.tv_usec < lasttv.tv_usec)) {
-+ printk(KERN_WARNING LIRC_DRIVER_NAME
-+ ": AIEEEE: your clock just jumped backwards\n");
-+ printk(KERN_WARNING LIRC_DRIVER_NAME
-+ ": %d %d %lx %lx %lx %lx\n", signal, sense,
-+ tv.tv_sec, lasttv.tv_sec,
-+ tv.tv_usec, lasttv.tv_usec);
-+ data = PULSE_MASK;
-+ } else if (deltv > 15) {
-+ data = PULSE_MASK; /* really long time */
-+ if (!(signal^sense)) {
-+ /* sanity check */
-+ printk(KERN_WARNING LIRC_DRIVER_NAME
-+ ": AIEEEE: %d %d %lx %lx %lx %lx\n",
-+ signal, sense, tv.tv_sec, lasttv.tv_sec,
-+ tv.tv_usec, lasttv.tv_usec);
-+ /*
-+ * detecting pulse while this
-+ * MUST be a space!
-+ */
-+ sense = sense ? 0 : 1;
-+ }
-+ } else {
-+ data = (int) (deltv*1000000 +
-+ (tv.tv_usec - lasttv.tv_usec));
-+ }
-+ frbwrite(signal^sense ? data : (data|PULSE_BIT));
-+ lasttv = tv;
-+ wake_up_interruptible(&rbuf.wait_poll);
-+ }
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static int is_right_chip(struct gpio_chip *chip, void *data)
-+{
-+ dprintk("is_right_chip %s %d\n", chip->label, strcmp(data, chip->label));
-+
-+ if (strcmp(data, chip->label) == 0)
-+ return 1;
-+ return 0;
-+}
-+
-+static inline int read_bool_property(const struct device_node *np,
-+ const char *propname,
-+ bool *out_value)
-+{
-+ u32 value = 0;
-+ int err = of_property_read_u32(np, propname, &value);
-+ if (err == 0)
-+ *out_value = (value != 0);
-+ return err;
-+}
-+
-+static void read_pin_settings(struct device_node *node)
-+{
-+ u32 pin;
-+ int index;
-+
-+ for (index = 0;
-+ of_property_read_u32_index(
-+ node,
-+ "brcm,pins",
-+ index,
-+ &pin) == 0;
-+ index++) {
-+ u32 function;
-+ int err;
-+ err = of_property_read_u32_index(
-+ node,
-+ "brcm,function",
-+ index,
-+ &function);
-+ if (err == 0) {
-+ if (function == 1) /* Output */
-+ gpio_out_pin = pin;
-+ else if (function == 0) /* Input */
-+ gpio_in_pin = pin;
-+ }
-+ }
-+}
-+
-+static int init_port(void)
-+{
-+ int i, nlow, nhigh;
-+ struct device_node *node;
-+
-+ node = lirc_rpi_dev->dev.of_node;
-+
-+ gpiochip = gpiochip_find("bcm2708_gpio", is_right_chip);
-+
-+ /*
-+ * Because of the lack of a setpull function, only support
-+ * pinctrl-bcm2835 if using device tree.
-+ */
-+ if (!gpiochip && node)
-+ gpiochip = gpiochip_find("pinctrl-bcm2835", is_right_chip);
-+
-+ if (!gpiochip) {
-+ pr_err(LIRC_DRIVER_NAME ": gpio chip not found!\n");
-+ return -ENODEV;
-+ }
-+
-+ if (node) {
-+ struct device_node *pins_node;
-+
-+ pins_node = of_parse_phandle(node, "pinctrl-0", 0);
-+ if (!pins_node) {
-+ printk(KERN_ERR LIRC_DRIVER_NAME
-+ ": pinctrl settings not found!\n");
-+ return -EINVAL;
-+ }
-+
-+ read_pin_settings(pins_node);
-+
-+ of_property_read_u32(node, "rpi,sense", &sense);
-+
-+ read_bool_property(node, "rpi,softcarrier", &softcarrier);
-+
-+ read_bool_property(node, "rpi,invert", &invert);
-+
-+ read_bool_property(node, "rpi,debug", &debug);
-+
-+ } else {
-+ return -EINVAL;
-+ }
-+
-+ gpiochip->set(gpiochip, gpio_out_pin, invert);
-+
-+ irq_num = gpiochip->to_irq(gpiochip, gpio_in_pin);
-+ dprintk("to_irq %d\n", irq_num);
-+
-+ /* if pin is high, then this must be an active low receiver. */
-+ if (sense == -1) {
-+ /* wait 1/2 sec for the power supply */
-+ msleep(500);
-+
-+ /*
-+ * probe 9 times every 0.04s, collect "votes" for
-+ * active high/low
-+ */
-+ nlow = 0;
-+ nhigh = 0;
-+ for (i = 0; i < 9; i++) {
-+ if (gpiochip->get(gpiochip, gpio_in_pin))
-+ nlow++;
-+ else
-+ nhigh++;
-+ msleep(40);
-+ }
-+ sense = (nlow >= nhigh ? 1 : 0);
-+ printk(KERN_INFO LIRC_DRIVER_NAME
-+ ": auto-detected active %s receiver on GPIO pin %d\n",
-+ sense ? "low" : "high", gpio_in_pin);
-+ } else {
-+ printk(KERN_INFO LIRC_DRIVER_NAME
-+ ": manually using active %s receiver on GPIO pin %d\n",
-+ sense ? "low" : "high", gpio_in_pin);
-+ }
-+
-+ return 0;
-+}
-+
-+// called when the character device is opened
-+static int set_use_inc(void *data)
-+{
-+ int result;
-+
-+ /* initialize timestamp */
-+ do_gettimeofday(&lasttv);
-+
-+ result = request_irq(irq_num,
-+ (irq_handler_t) irq_handler,
-+ IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING,
-+ LIRC_DRIVER_NAME, (void*) 0);
-+
-+ switch (result) {
-+ case -EBUSY:
-+ printk(KERN_ERR LIRC_DRIVER_NAME
-+ ": IRQ %d is busy\n",
-+ irq_num);
-+ return -EBUSY;
-+ case -EINVAL:
-+ printk(KERN_ERR LIRC_DRIVER_NAME
-+ ": Bad irq number or handler\n");
-+ return -EINVAL;
-+ default:
-+ dprintk("Interrupt %d obtained\n",
-+ irq_num);
-+ break;
-+ };
-+
-+ /* initialize pulse/space widths */
-+ init_timing_params(duty_cycle, freq);
-+
-+ return 0;
-+}
-+
-+static void set_use_dec(void *data)
-+{
-+ /* GPIO Pin Falling/Rising Edge Detect Disable */
-+ irq_set_irq_type(irq_num, 0);
-+ disable_irq(irq_num);
-+
-+ free_irq(irq_num, (void *) 0);
-+
-+ dprintk(KERN_INFO LIRC_DRIVER_NAME
-+ ": freed IRQ %d\n", irq_num);
-+}
-+
-+static ssize_t lirc_write(struct file *file, const char *buf,
-+ size_t n, loff_t *ppos)
-+{
-+ int i, count;
-+ unsigned long flags;
-+ long delta = 0;
-+ int *wbuf;
-+
-+ count = n / sizeof(int);
-+ if (n % sizeof(int) || count % 2 == 0)
-+ return -EINVAL;
-+ wbuf = memdup_user(buf, n);
-+ if (IS_ERR(wbuf))
-+ return PTR_ERR(wbuf);
-+ spin_lock_irqsave(&lock, flags);
-+
-+ for (i = 0; i < count; i++) {
-+ if (i%2)
-+ send_space(wbuf[i] - delta);
-+ else
-+ delta = send_pulse(wbuf[i]);
-+ }
-+ gpiochip->set(gpiochip, gpio_out_pin, invert);
-+
-+ spin_unlock_irqrestore(&lock, flags);
-+ kfree(wbuf);
-+ return n;
-+}
-+
-+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
-+{
-+ int result;
-+ __u32 value;
-+
-+ switch (cmd) {
-+ case LIRC_GET_SEND_MODE:
-+ return -ENOIOCTLCMD;
-+ break;
-+
-+ case LIRC_SET_SEND_MODE:
-+ result = get_user(value, (__u32 *) arg);
-+ if (result)
-+ return result;
-+ /* only LIRC_MODE_PULSE supported */
-+ if (value != LIRC_MODE_PULSE)
-+ return -ENOSYS;
-+ break;
-+
-+ case LIRC_GET_LENGTH:
-+ return -ENOSYS;
-+ break;
-+
-+ case LIRC_SET_SEND_DUTY_CYCLE:
-+ dprintk("SET_SEND_DUTY_CYCLE\n");
-+ result = get_user(value, (__u32 *) arg);
-+ if (result)
-+ return result;
-+ if (value <= 0 || value > 100)
-+ return -EINVAL;
-+ return init_timing_params(value, freq);
-+ break;
-+
-+ case LIRC_SET_SEND_CARRIER:
-+ dprintk("SET_SEND_CARRIER\n");
-+ result = get_user(value, (__u32 *) arg);
-+ if (result)
-+ return result;
-+ if (value > 500000 || value < 20000)
-+ return -EINVAL;
-+ return init_timing_params(duty_cycle, value);
-+ break;
-+
-+ default:
-+ return lirc_dev_fop_ioctl(filep, cmd, arg);
-+ }
-+ return 0;
-+}
-+
-+static const struct file_operations lirc_fops = {
-+ .owner = THIS_MODULE,
-+ .write = lirc_write,
-+ .unlocked_ioctl = lirc_ioctl,
-+ .read = lirc_dev_fop_read,
-+ .poll = lirc_dev_fop_poll,
-+ .open = lirc_dev_fop_open,
-+ .release = lirc_dev_fop_close,
-+ .llseek = no_llseek,
-+};
-+
-+static struct lirc_driver driver = {
-+ .name = LIRC_DRIVER_NAME,
-+ .minor = -1,
-+ .code_length = 1,
-+ .sample_rate = 0,
-+ .data = NULL,
-+ .add_to_buf = NULL,
-+ .rbuf = &rbuf,
-+ .set_use_inc = set_use_inc,
-+ .set_use_dec = set_use_dec,
-+ .fops = &lirc_fops,
-+ .dev = NULL,
-+ .owner = THIS_MODULE,
-+};
-+
-+static const struct of_device_id lirc_rpi_of_match[] = {
-+ { .compatible = "rpi,lirc-rpi", },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(of, lirc_rpi_of_match);
-+
-+static struct platform_driver lirc_rpi_driver = {
-+ .driver = {
-+ .name = LIRC_DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ .of_match_table = of_match_ptr(lirc_rpi_of_match),
-+ },
-+};
-+
-+static int __init lirc_rpi_init(void)
-+{
-+ struct device_node *node;
-+ int result;
-+
-+ /* Init read buffer. */
-+ result = lirc_buffer_init(&rbuf, sizeof(int), RBUF_LEN);
-+ if (result < 0)
-+ return -ENOMEM;
-+
-+ result = platform_driver_register(&lirc_rpi_driver);
-+ if (result) {
-+ printk(KERN_ERR LIRC_DRIVER_NAME
-+ ": lirc register returned %d\n", result);
-+ goto exit_buffer_free;
-+ }
-+
-+ node = of_find_compatible_node(NULL, NULL,
-+ lirc_rpi_of_match[0].compatible);
-+
-+ if (node) {
-+ /* DT-enabled */
-+ lirc_rpi_dev = of_find_device_by_node(node);
-+ WARN_ON(lirc_rpi_dev->dev.of_node != node);
-+ of_node_put(node);
-+ }
-+ else {
-+ lirc_rpi_dev = platform_device_alloc(LIRC_DRIVER_NAME, 0);
-+ if (!lirc_rpi_dev) {
-+ result = -ENOMEM;
-+ goto exit_driver_unregister;
-+ }
-+
-+ result = platform_device_add(lirc_rpi_dev);
-+ if (result)
-+ goto exit_device_put;
-+ }
-+
-+ return 0;
-+
-+ exit_device_put:
-+ platform_device_put(lirc_rpi_dev);
-+
-+ exit_driver_unregister:
-+ platform_driver_unregister(&lirc_rpi_driver);
-+
-+ exit_buffer_free:
-+ lirc_buffer_free(&rbuf);
-+
-+ return result;
-+}
-+
-+static void lirc_rpi_exit(void)
-+{
-+ if (!lirc_rpi_dev->dev.of_node)
-+ platform_device_unregister(lirc_rpi_dev);
-+ platform_driver_unregister(&lirc_rpi_driver);
-+ lirc_buffer_free(&rbuf);
-+}
-+
-+static int __init lirc_rpi_init_module(void)
-+{
-+ int result;
-+
-+ result = lirc_rpi_init();
-+ if (result)
-+ return result;
-+
-+ result = init_port();
-+ if (result < 0)
-+ goto exit_rpi;
-+
-+ driver.features = LIRC_CAN_SET_SEND_DUTY_CYCLE |
-+ LIRC_CAN_SET_SEND_CARRIER |
-+ LIRC_CAN_SEND_PULSE |
-+ LIRC_CAN_REC_MODE2;
-+
-+ driver.dev = &lirc_rpi_dev->dev;
-+ driver.minor = lirc_register_driver(&driver);
-+
-+ if (driver.minor < 0) {
-+ printk(KERN_ERR LIRC_DRIVER_NAME
-+ ": device registration failed with %d\n", result);
-+ result = -EIO;
-+ goto exit_rpi;
-+ }
-+
-+ printk(KERN_INFO LIRC_DRIVER_NAME ": driver registered!\n");
-+
-+ return 0;
-+
-+ exit_rpi:
-+ lirc_rpi_exit();
-+
-+ return result;
-+}
-+
-+static void __exit lirc_rpi_exit_module(void)
-+{
-+ lirc_unregister_driver(driver.minor);
-+
-+ gpio_free(gpio_out_pin);
-+ gpio_free(gpio_in_pin);
-+
-+ lirc_rpi_exit();
-+
-+ printk(KERN_INFO LIRC_DRIVER_NAME ": cleaned up module\n");
-+}
-+
-+module_init(lirc_rpi_init_module);
-+module_exit(lirc_rpi_exit_module);
-+
-+MODULE_DESCRIPTION("Infra-red receiver and blaster driver for Raspberry Pi GPIO.");
-+MODULE_AUTHOR("Aron Robert Szabo <aron@reon.hu>");
-+MODULE_AUTHOR("Michael Bishop <cleverca22@gmail.com>");
-+MODULE_LICENSE("GPL");
-+
-+module_param(gpio_out_pin, int, S_IRUGO);
-+MODULE_PARM_DESC(gpio_out_pin, "GPIO output/transmitter pin number of the BCM"
-+ " processor. (default 17");
-+
-+module_param(gpio_in_pin, int, S_IRUGO);
-+MODULE_PARM_DESC(gpio_in_pin, "GPIO input pin number of the BCM processor."
-+ " (default 18");
-+
-+module_param(gpio_in_pull, int, S_IRUGO);
-+MODULE_PARM_DESC(gpio_in_pull, "GPIO input pin pull configuration."
-+ " (0 = off, 1 = up, 2 = down, default down)");
-+
-+module_param(sense, int, S_IRUGO);
-+MODULE_PARM_DESC(sense, "Override autodetection of IR receiver circuit"
-+ " (0 = active high, 1 = active low )");
-+
-+module_param(softcarrier, bool, S_IRUGO);
-+MODULE_PARM_DESC(softcarrier, "Software carrier (0 = off, 1 = on, default on)");
-+
-+module_param(invert, bool, S_IRUGO);
-+MODULE_PARM_DESC(invert, "Invert output (0 = off, 1 = on, default off");
-+
-+module_param(debug, bool, S_IRUGO | S_IWUSR);
-+MODULE_PARM_DESC(debug, "Enable debugging messages");
---- /dev/null
-+++ b/include/linux/platform_data/bcm2708.h
-@@ -0,0 +1,23 @@
-+/*
-+ * include/linux/platform_data/bcm2708.h
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * (C) 2014 Julian Scheel <julian@jusst.de>
-+ *
-+ */
-+#ifndef __BCM2708_H_
-+#define __BCM2708_H_
-+
-+typedef enum {
-+ BCM2708_PULL_OFF,
-+ BCM2708_PULL_UP,
-+ BCM2708_PULL_DOWN
-+} bcm2708_gpio_pull_t;
-+
-+extern int bcm2708_gpio_setpull(struct gpio_chip *gc, unsigned offset,
-+ bcm2708_gpio_pull_t value);
-+
-+#endif
diff --git a/target/linux/brcm2708/patches-4.4/0044-Add-cpufreq-driver.patch b/target/linux/brcm2708/patches-4.4/0044-Add-cpufreq-driver.patch
deleted file mode 100644
index f1ec5da74f..0000000000
--- a/target/linux/brcm2708/patches-4.4/0044-Add-cpufreq-driver.patch
+++ /dev/null
@@ -1,257 +0,0 @@
-From 3c7ea37319a4974cbf6b89a84c109a53f4d6b408 Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Wed, 3 Jul 2013 00:49:20 +0100
-Subject: [PATCH 044/170] Add cpufreq driver
-
-Signed-off-by: popcornmix <popcornmix@gmail.com>
----
- drivers/cpufreq/Kconfig.arm | 9 ++
- drivers/cpufreq/Makefile | 1 +
- drivers/cpufreq/bcm2835-cpufreq.c | 213 ++++++++++++++++++++++++++++++++++++++
- 3 files changed, 223 insertions(+)
- create mode 100644 drivers/cpufreq/bcm2835-cpufreq.c
-
---- a/drivers/cpufreq/Kconfig.arm
-+++ b/drivers/cpufreq/Kconfig.arm
-@@ -217,6 +217,15 @@ config ARM_SPEAR_CPUFREQ
- help
- This adds the CPUFreq driver support for SPEAr SOCs.
-
-+config ARM_BCM2835_CPUFREQ
-+ depends on RASPBERRYPI_FIRMWARE
-+ bool "BCM2835 Driver"
-+ default y
-+ help
-+ This adds the CPUFreq driver for BCM2835
-+
-+ If in doubt, say N.
-+
- config ARM_TEGRA20_CPUFREQ
- bool "Tegra20 CPUFreq support"
- depends on ARCH_TEGRA
---- a/drivers/cpufreq/Makefile
-+++ b/drivers/cpufreq/Makefile
-@@ -73,6 +73,7 @@ obj-$(CONFIG_ARM_SA1100_CPUFREQ) += sa11
- obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o
- obj-$(CONFIG_ARM_SCPI_CPUFREQ) += scpi-cpufreq.o
- obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o
-+obj-$(CONFIG_ARM_BCM2835_CPUFREQ) += bcm2835-cpufreq.o
- obj-$(CONFIG_ARM_TEGRA20_CPUFREQ) += tegra20-cpufreq.o
- obj-$(CONFIG_ARM_TEGRA124_CPUFREQ) += tegra124-cpufreq.o
- obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o
---- /dev/null
-+++ b/drivers/cpufreq/bcm2835-cpufreq.c
-@@ -0,0 +1,213 @@
-+/*****************************************************************************
-+* Copyright 2011 Broadcom Corporation. All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*****************************************************************************/
-+
-+/*****************************************************************************
-+* FILENAME: bcm2835-cpufreq.h
-+* DESCRIPTION: This driver dynamically manages the CPU Frequency of the ARM
-+* processor. Messages are sent to Videocore either setting or requesting the
-+* frequency of the ARM in order to match an appropiate frequency to the current
-+* usage of the processor. The policy which selects the frequency to use is
-+* defined in the kernel .config file, but can be changed during runtime.
-+*****************************************************************************/
-+
-+/* ---------- INCLUDES ---------- */
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/cpufreq.h>
-+#include <soc/bcm2835/raspberrypi-firmware.h>
-+
-+/* ---------- DEFINES ---------- */
-+/*#define CPUFREQ_DEBUG_ENABLE*/ /* enable debugging */
-+#define MODULE_NAME "bcm2835-cpufreq"
-+
-+#define VCMSG_ID_ARM_CLOCK 0x000000003 /* Clock/Voltage ID's */
-+
-+/* debug printk macros */
-+#ifdef CPUFREQ_DEBUG_ENABLE
-+#define print_debug(fmt,...) pr_debug("%s:%s:%d: "fmt, MODULE_NAME, __func__, __LINE__, ##__VA_ARGS__)
-+#else
-+#define print_debug(fmt,...)
-+#endif
-+#define print_err(fmt,...) pr_err("%s:%s:%d: "fmt, MODULE_NAME, __func__,__LINE__, ##__VA_ARGS__)
-+#define print_info(fmt,...) pr_info("%s: "fmt, MODULE_NAME, ##__VA_ARGS__)
-+
-+/* ---------- GLOBALS ---------- */
-+static struct cpufreq_driver bcm2835_cpufreq_driver; /* the cpufreq driver global */
-+
-+static struct cpufreq_frequency_table bcm2835_freq_table[] = {
-+ {0, 0, 0},
-+ {0, 0, 0},
-+ {0, 0, CPUFREQ_TABLE_END},
-+};
-+
-+/*
-+ ===============================================
-+ clk_rate either gets or sets the clock rates.
-+ ===============================================
-+*/
-+
-+static int bcm2835_cpufreq_clock_property(u32 tag, u32 id, u32 *val)
-+{
-+ struct rpi_firmware *fw = rpi_firmware_get(NULL);
-+ struct {
-+ u32 id;
-+ u32 val;
-+ } packet;
-+ int ret;
-+
-+ packet.id = id;
-+ packet.val = *val;
-+ ret = rpi_firmware_property(fw, tag, &packet, sizeof(packet));
-+ if (ret)
-+ return ret;
-+
-+ *val = packet.val;
-+
-+ return 0;
-+}
-+
-+static uint32_t bcm2835_cpufreq_set_clock(int cur_rate, int arm_rate)
-+{
-+ u32 rate = arm_rate * 1000;
-+ int ret;
-+
-+ ret = bcm2835_cpufreq_clock_property(RPI_FIRMWARE_SET_CLOCK_RATE, VCMSG_ID_ARM_CLOCK, &rate);
-+ if (ret) {
-+ print_err("Failed to set clock: %d (%d)\n", arm_rate, ret);
-+ return 0;
-+ }
-+
-+ rate /= 1000;
-+ print_debug("Setting new frequency = %d -> %d (actual %d)\n", cur_rate, arm_rate, rate);
-+
-+ return rate;
-+}
-+
-+static uint32_t bcm2835_cpufreq_get_clock(int tag)
-+{
-+ u32 rate;
-+ int ret;
-+
-+ ret = bcm2835_cpufreq_clock_property(tag, VCMSG_ID_ARM_CLOCK, &rate);
-+ if (ret) {
-+ print_err("Failed to get clock (%d)\n", ret);
-+ return 0;
-+ }
-+
-+ rate /= 1000;
-+ print_debug("%s frequency = %u\n",
-+ tag == RPI_FIRMWARE_GET_CLOCK_RATE ? "Current":
-+ tag == RPI_FIRMWARE_GET_MIN_CLOCK_RATE ? "Min":
-+ tag == RPI_FIRMWARE_GET_MAX_CLOCK_RATE ? "Max":
-+ "Unexpected", rate);
-+
-+ return rate;
-+}
-+
-+/*
-+ ====================================================
-+ Module Initialisation registers the cpufreq driver
-+ ====================================================
-+*/
-+static int __init bcm2835_cpufreq_module_init(void)
-+{
-+ print_debug("IN\n");
-+ return cpufreq_register_driver(&bcm2835_cpufreq_driver);
-+}
-+
-+/*
-+ =============
-+ Module exit
-+ =============
-+*/
-+static void __exit bcm2835_cpufreq_module_exit(void)
-+{
-+ print_debug("IN\n");
-+ cpufreq_unregister_driver(&bcm2835_cpufreq_driver);
-+ return;
-+}
-+
-+/*
-+ ==============================================================
-+ Initialisation function sets up the CPU policy for first use
-+ ==============================================================
-+*/
-+static int bcm2835_cpufreq_driver_init(struct cpufreq_policy *policy)
-+{
-+ /* measured value of how long it takes to change frequency */
-+ const unsigned int transition_latency = 355000; /* ns */
-+
-+ if (!rpi_firmware_get(NULL)) {
-+ print_err("Firmware is not available\n");
-+ return -ENODEV;
-+ }
-+
-+ /* now find out what the maximum and minimum frequencies are */
-+ bcm2835_freq_table[0].frequency = bcm2835_cpufreq_get_clock(RPI_FIRMWARE_GET_MIN_CLOCK_RATE);
-+ bcm2835_freq_table[1].frequency = bcm2835_cpufreq_get_clock(RPI_FIRMWARE_GET_MAX_CLOCK_RATE);
-+
-+ print_info("min=%d max=%d\n", bcm2835_freq_table[0].frequency, bcm2835_freq_table[1].frequency);
-+ return cpufreq_generic_init(policy, bcm2835_freq_table, transition_latency);
-+}
-+
-+/*
-+ =====================================================================
-+ Target index function chooses the requested frequency from the table
-+ =====================================================================
-+*/
-+
-+static int bcm2835_cpufreq_driver_target_index(struct cpufreq_policy *policy, unsigned int state)
-+{
-+ unsigned int target_freq = bcm2835_freq_table[state].frequency;
-+ unsigned int cur = bcm2835_cpufreq_set_clock(policy->cur, target_freq);
-+
-+ if (!cur)
-+ {
-+ print_err("Error occurred setting a new frequency (%d)\n", target_freq);
-+ return -EINVAL;
-+ }
-+ print_debug("%s: %i: freq %d->%d\n", policy->governor->name, state, policy->cur, cur);
-+ return 0;
-+}
-+
-+/*
-+ ======================================================
-+ Get function returns the current frequency from table
-+ ======================================================
-+*/
-+
-+static unsigned int bcm2835_cpufreq_driver_get(unsigned int cpu)
-+{
-+ unsigned int actual_rate = bcm2835_cpufreq_get_clock(RPI_FIRMWARE_GET_CLOCK_RATE);
-+ print_debug("cpu%d: freq=%d\n", cpu, actual_rate);
-+ return actual_rate <= bcm2835_freq_table[0].frequency ? bcm2835_freq_table[0].frequency : bcm2835_freq_table[1].frequency;
-+}
-+
-+/* the CPUFreq driver */
-+static struct cpufreq_driver bcm2835_cpufreq_driver = {
-+ .name = "BCM2835 CPUFreq",
-+ .init = bcm2835_cpufreq_driver_init,
-+ .verify = cpufreq_generic_frequency_table_verify,
-+ .target_index = bcm2835_cpufreq_driver_target_index,
-+ .get = bcm2835_cpufreq_driver_get,
-+ .attr = cpufreq_generic_attr,
-+};
-+
-+MODULE_AUTHOR("Dorian Peake and Dom Cobley");
-+MODULE_DESCRIPTION("CPU frequency driver for BCM2835 chip");
-+MODULE_LICENSE("GPL");
-+
-+module_init(bcm2835_cpufreq_module_init);
-+module_exit(bcm2835_cpufreq_module_exit);
diff --git a/target/linux/brcm2708/patches-4.4/0044-Added-hwmon-thermal-driver-for-reporting-core-temper.patch b/target/linux/brcm2708/patches-4.4/0044-Added-hwmon-thermal-driver-for-reporting-core-temper.patch
new file mode 100644
index 0000000000..7cc88fe23a
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0044-Added-hwmon-thermal-driver-for-reporting-core-temper.patch
@@ -0,0 +1,193 @@
+From 9bccd57257d3156887d5bbeadbf35898505cd7f6 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Tue, 26 Mar 2013 19:24:24 +0000
+Subject: [PATCH 044/381] Added hwmon/thermal driver for reporting core
+ temperature. Thanks Dorian
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+BCM270x: Move thermal sensor to Device Tree
+
+Add Device Tree support to bcm2835-thermal driver.
+Add thermal sensor device to Device Tree.
+Don't add platform device when booting in DT mode.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+---
+ drivers/thermal/Kconfig | 7 ++
+ drivers/thermal/Makefile | 1 +
+ drivers/thermal/bcm2835-thermal.c | 141 ++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 149 insertions(+)
+ create mode 100644 drivers/thermal/bcm2835-thermal.c
+
+--- a/drivers/thermal/Kconfig
++++ b/drivers/thermal/Kconfig
+@@ -285,6 +285,13 @@ config INTEL_POWERCLAMP
+ enforce idle time which results in more package C-state residency. The
+ user interface is exposed via generic thermal framework.
+
++config THERMAL_BCM2835
++ depends on RASPBERRYPI_FIRMWARE
++ tristate "BCM2835 Thermal Driver"
++ help
++ This will enable temperature monitoring for the Broadcom BCM2835
++ chip. If built as a module, it will be called 'bcm2835-thermal'.
++
+ config X86_PKG_TEMP_THERMAL
+ tristate "X86 package temperature thermal driver"
+ depends on X86_THERMAL_VECTOR
+--- a/drivers/thermal/Makefile
++++ b/drivers/thermal/Makefile
+@@ -38,6 +38,7 @@ obj-$(CONFIG_ARMADA_THERMAL) += armada_t
+ obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o
+ obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o
+ obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o
++obj-$(CONFIG_THERMAL_BCM2835) += bcm2835-thermal.o
+ obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o
+ obj-$(CONFIG_INTEL_SOC_DTS_IOSF_CORE) += intel_soc_dts_iosf.o
+ obj-$(CONFIG_INTEL_SOC_DTS_THERMAL) += intel_soc_dts_thermal.o
+--- /dev/null
++++ b/drivers/thermal/bcm2835-thermal.c
+@@ -0,0 +1,141 @@
++/*****************************************************************************
++* Copyright 2011 Broadcom Corporation. All rights reserved.
++*
++* Unless you and Broadcom execute a separate written software license
++* agreement governing use of this software, this software is licensed to you
++* under the terms of the GNU General Public License version 2, available at
++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
++*
++* Notwithstanding the above, under no circumstances may you combine this
++* software in any way with any other Broadcom software provided under a
++* license other than the GPL, without Broadcom's express prior written
++* consent.
++*****************************************************************************/
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/thermal.h>
++#include <soc/bcm2835/raspberrypi-firmware.h>
++
++static int bcm2835_thermal_get_property(struct thermal_zone_device *tz,
++ int *temp, u32 tag)
++{
++ struct rpi_firmware *fw = tz->devdata;
++ struct {
++ u32 id;
++ u32 val;
++ } packet;
++ int ret;
++
++ *temp = 0;
++ packet.id = 0;
++ ret = rpi_firmware_property(fw, tag, &packet, sizeof(packet));
++ if (ret) {
++ dev_err(&tz->device, "Failed to get temperature\n");
++ return ret;
++ }
++
++ *temp = packet.val;
++ dev_dbg(&tz->device, "%stemp=%d\n",
++ tag == RPI_FIRMWARE_GET_MAX_TEMPERATURE ? "max" : "", *temp);
++
++ return 0;
++}
++
++static int bcm2835_thermal_get_temp(struct thermal_zone_device *tz,
++ int *temp)
++{
++ return bcm2835_thermal_get_property(tz, temp,
++ RPI_FIRMWARE_GET_TEMPERATURE);
++}
++
++static int bcm2835_thermal_get_max_temp(struct thermal_zone_device *tz,
++ int trip, int *temp)
++{
++ /*
++ * The maximum safe temperature of the SoC.
++ * Overclock may be disabled above this temperature.
++ */
++ return bcm2835_thermal_get_property(tz, temp,
++ RPI_FIRMWARE_GET_MAX_TEMPERATURE);
++}
++
++static int bcm2835_thermal_get_trip_type(struct thermal_zone_device *tz,
++ int trip, enum thermal_trip_type *type)
++{
++ *type = THERMAL_TRIP_HOT;
++
++ return 0;
++}
++
++static int bcm2835_thermal_get_mode(struct thermal_zone_device *tz,
++ enum thermal_device_mode *mode)
++{
++ *mode = THERMAL_DEVICE_ENABLED;
++
++ return 0;
++}
++
++static struct thermal_zone_device_ops ops = {
++ .get_temp = bcm2835_thermal_get_temp,
++ .get_trip_temp = bcm2835_thermal_get_max_temp,
++ .get_trip_type = bcm2835_thermal_get_trip_type,
++ .get_mode = bcm2835_thermal_get_mode,
++};
++
++static int bcm2835_thermal_probe(struct platform_device *pdev)
++{
++ struct device_node *fw_np;
++ struct rpi_firmware *fw;
++ struct thermal_zone_device *tz;
++
++ fw_np = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
++/* Remove comment when booting without Device Tree is no longer supported
++ if (!fw_np) {
++ dev_err(&pdev->dev, "Missing firmware node\n");
++ return -ENOENT;
++ }
++*/
++ fw = rpi_firmware_get(fw_np);
++ if (!fw)
++ return -EPROBE_DEFER;
++
++ tz = thermal_zone_device_register("bcm2835_thermal", 1, 0, fw, &ops,
++ NULL, 0, 0);
++ if (IS_ERR(tz)) {
++ dev_err(&pdev->dev, "Failed to register the thermal device\n");
++ return PTR_ERR(tz);
++ }
++
++ platform_set_drvdata(pdev, tz);
++
++ return 0;
++}
++
++static int bcm2835_thermal_remove(struct platform_device *pdev)
++{
++ thermal_zone_device_unregister(platform_get_drvdata(pdev));
++
++ return 0;
++}
++
++static const struct of_device_id bcm2835_thermal_of_match_table[] = {
++ { .compatible = "brcm,bcm2835-thermal", },
++ {},
++};
++MODULE_DEVICE_TABLE(of, bcm2835_thermal_of_match_table);
++
++static struct platform_driver bcm2835_thermal_driver = {
++ .probe = bcm2835_thermal_probe,
++ .remove = bcm2835_thermal_remove,
++ .driver = {
++ .name = "bcm2835_thermal",
++ .of_match_table = bcm2835_thermal_of_match_table,
++ },
++};
++module_platform_driver(bcm2835_thermal_driver);
++
++MODULE_AUTHOR("Dorian Peake");
++MODULE_AUTHOR("Noralf Trønnes");
++MODULE_DESCRIPTION("Thermal driver for bcm2835 chip");
++MODULE_LICENSE("GPL");
diff --git a/target/linux/brcm2708/patches-4.4/0045-Add-Chris-Boot-s-i2c-driver.patch b/target/linux/brcm2708/patches-4.4/0045-Add-Chris-Boot-s-i2c-driver.patch
new file mode 100644
index 0000000000..ba3f9980eb
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0045-Add-Chris-Boot-s-i2c-driver.patch
@@ -0,0 +1,635 @@
+From dc4e4461802c9dff395a49212e8420a9f586e247 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Wed, 17 Jun 2015 15:44:08 +0100
+Subject: [PATCH 045/381] Add Chris Boot's i2c driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+i2c-bcm2708: fixed baudrate
+
+Fixed issue where the wrong CDIV value was set for baudrates below 3815 Hz (for 250MHz bus clock).
+In that case the computed CDIV value was more than 0xffff. However the CDIV register width is only 16 bits.
+This resulted in incorrect setting of CDIV and higher baudrate than intended.
+Example: 3500Hz -> CDIV=0x11704 -> CDIV(16bit)=0x1704 -> 42430Hz
+After correction: 3500Hz -> CDIV=0x11704 -> CDIV(16bit)=0xffff -> 3815Hz
+The correct baudrate is shown in the log after the cdiv > 0xffff correction.
+
+Perform I2C combined transactions when possible
+
+Perform I2C combined transactions whenever possible, within the
+restrictions of the Broadcomm Serial Controller.
+
+Disable DONE interrupt during TA poll
+
+Prevent interrupt from being triggered if poll is missed and transfer
+starts and finishes.
+
+i2c: Make combined transactions optional and disabled by default
+
+i2c: bcm2708: add device tree support
+
+Add DT support to driver and add to .dtsi file.
+Setup pins in .dts file.
+i2c is disabled by default.
+
+Signed-off-by: Noralf Tronnes <notro@tronnes.org>
+
+bcm2708: don't register i2c controllers when using DT
+
+The devices for the i2c controllers are in the Device Tree.
+Only register devices when not using DT.
+
+Signed-off-by: Noralf Tronnes <notro@tronnes.org>
+
+I2C: Only register the I2C device for the current board revision
+
+i2c_bcm2708: Fix clock reference counting
+
+Fix grabbing lock from atomic context in i2c driver
+
+2 main changes:
+- check for timeouts in the bcm2708_bsc_setup function as indicated by this comment:
+ /* poll for transfer start bit (should only take 1-20 polls) */
+ This implies that the setup function can now fail so account for this everywhere it's called
+- Removed the clk_get_rate call from inside the setup function as it locks a mutex and that's not ok since we call it from under a spin lock.
+
+i2c-bcm2708: When using DT, leave the GPIO setup to pinctrl
+
+i2c-bcm2708: Increase timeouts to allow larger transfers
+
+Use the timeout value provided by the I2C_TIMEOUT ioctl when waiting
+for completion. The default timeout is 1 second.
+
+See: https://github.com/raspberrypi/linux/issues/260
+
+i2c-bcm2708/BCM270X_DT: Add support for I2C2
+
+The third I2C bus (I2C2) is normally reserved for HDMI use. Careless
+use of this bus can break an attached display - use with caution.
+
+It is recommended to disable accesses by VideoCore by setting
+hdmi_ignore_edid=1 or hdmi_edid_file=1 in config.txt.
+
+The interface is disabled by default - enable using the
+i2c2_iknowwhatimdoing DT parameter.
+
+bcm2708-spi: Don't use static pin configuration with DT
+
+Also remove superfluous error checking - the SPI framework ensures the
+validity of the chip_select value.
+
+i2c-bcm2708: Remove non-DT support
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+---
+ drivers/i2c/busses/Kconfig | 21 +-
+ drivers/i2c/busses/Makefile | 2 +
+ drivers/i2c/busses/i2c-bcm2708.c | 493 +++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 515 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/i2c/busses/i2c-bcm2708.c
+
+--- a/drivers/i2c/busses/Kconfig
++++ b/drivers/i2c/busses/Kconfig
+@@ -8,6 +8,25 @@ menu "I2C Hardware Bus support"
+ comment "PC SMBus host controller drivers"
+ depends on PCI
+
++config I2C_BCM2708
++ tristate "BCM2708 BSC"
++ depends on MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835
++ help
++ Enabling this option will add BSC (Broadcom Serial Controller)
++ support for the BCM2708. BSC is a Broadcom proprietary bus compatible
++ with I2C/TWI/SMBus.
++
++config I2C_BCM2708_BAUDRATE
++ prompt "BCM2708 I2C baudrate"
++ depends on I2C_BCM2708
++ int
++ default 100000
++ help
++ Set the I2C baudrate. This will alter the default value. A
++ different baudrate can be set by using a module parameter as well. If
++ no parameter is provided when loading, this is the value that will be
++ used.
++
+ config I2C_ALI1535
+ tristate "ALI 1535"
+ depends on PCI
+@@ -365,7 +384,7 @@ config I2C_AXXIA
+
+ config I2C_BCM2835
+ tristate "Broadcom BCM2835 I2C controller"
+- depends on ARCH_BCM2835
++ depends on ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709
+ help
+ If you say yes to this option, support will be included for the
+ BCM2835 I2C controller.
+--- a/drivers/i2c/busses/Makefile
++++ b/drivers/i2c/busses/Makefile
+@@ -2,6 +2,8 @@
+ # Makefile for the i2c bus drivers.
+ #
+
++obj-$(CONFIG_I2C_BCM2708) += i2c-bcm2708.o
++
+ # ACPI drivers
+ obj-$(CONFIG_I2C_SCMI) += i2c-scmi.o
+
+--- /dev/null
++++ b/drivers/i2c/busses/i2c-bcm2708.c
+@@ -0,0 +1,493 @@
++/*
++ * Driver for Broadcom BCM2708 BSC Controllers
++ *
++ * Copyright (C) 2012 Chris Boot & Frank Buss
++ *
++ * This driver is inspired by:
++ * i2c-ocores.c, by Peter Korsgaard <jacmet@sunsite.dk>
++ *
++ * 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/kernel.h>
++#include <linux/module.h>
++#include <linux/spinlock.h>
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/io.h>
++#include <linux/slab.h>
++#include <linux/i2c.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++#include <linux/wait.h>
++
++/* BSC register offsets */
++#define BSC_C 0x00
++#define BSC_S 0x04
++#define BSC_DLEN 0x08
++#define BSC_A 0x0c
++#define BSC_FIFO 0x10
++#define BSC_DIV 0x14
++#define BSC_DEL 0x18
++#define BSC_CLKT 0x1c
++
++/* Bitfields in BSC_C */
++#define BSC_C_I2CEN 0x00008000
++#define BSC_C_INTR 0x00000400
++#define BSC_C_INTT 0x00000200
++#define BSC_C_INTD 0x00000100
++#define BSC_C_ST 0x00000080
++#define BSC_C_CLEAR_1 0x00000020
++#define BSC_C_CLEAR_2 0x00000010
++#define BSC_C_READ 0x00000001
++
++/* Bitfields in BSC_S */
++#define BSC_S_CLKT 0x00000200
++#define BSC_S_ERR 0x00000100
++#define BSC_S_RXF 0x00000080
++#define BSC_S_TXE 0x00000040
++#define BSC_S_RXD 0x00000020
++#define BSC_S_TXD 0x00000010
++#define BSC_S_RXR 0x00000008
++#define BSC_S_TXW 0x00000004
++#define BSC_S_DONE 0x00000002
++#define BSC_S_TA 0x00000001
++
++#define I2C_WAIT_LOOP_COUNT 200
++
++#define DRV_NAME "bcm2708_i2c"
++
++static unsigned int baudrate = CONFIG_I2C_BCM2708_BAUDRATE;
++module_param(baudrate, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
++MODULE_PARM_DESC(baudrate, "The I2C baudrate");
++
++static bool combined = false;
++module_param(combined, bool, 0644);
++MODULE_PARM_DESC(combined, "Use combined transactions");
++
++struct bcm2708_i2c {
++ struct i2c_adapter adapter;
++
++ spinlock_t lock;
++ void __iomem *base;
++ int irq;
++ struct clk *clk;
++ u32 cdiv;
++
++ struct completion done;
++
++ struct i2c_msg *msg;
++ int pos;
++ int nmsgs;
++ bool error;
++};
++
++static inline u32 bcm2708_rd(struct bcm2708_i2c *bi, unsigned reg)
++{
++ return readl(bi->base + reg);
++}
++
++static inline void bcm2708_wr(struct bcm2708_i2c *bi, unsigned reg, u32 val)
++{
++ writel(val, bi->base + reg);
++}
++
++static inline void bcm2708_bsc_reset(struct bcm2708_i2c *bi)
++{
++ bcm2708_wr(bi, BSC_C, 0);
++ bcm2708_wr(bi, BSC_S, BSC_S_CLKT | BSC_S_ERR | BSC_S_DONE);
++}
++
++static inline void bcm2708_bsc_fifo_drain(struct bcm2708_i2c *bi)
++{
++ while ((bcm2708_rd(bi, BSC_S) & BSC_S_RXD) && (bi->pos < bi->msg->len))
++ bi->msg->buf[bi->pos++] = bcm2708_rd(bi, BSC_FIFO);
++}
++
++static inline void bcm2708_bsc_fifo_fill(struct bcm2708_i2c *bi)
++{
++ while ((bcm2708_rd(bi, BSC_S) & BSC_S_TXD) && (bi->pos < bi->msg->len))
++ bcm2708_wr(bi, BSC_FIFO, bi->msg->buf[bi->pos++]);
++}
++
++static inline int bcm2708_bsc_setup(struct bcm2708_i2c *bi)
++{
++ u32 cdiv, s;
++ u32 c = BSC_C_I2CEN | BSC_C_INTD | BSC_C_ST | BSC_C_CLEAR_1;
++ int wait_loops = I2C_WAIT_LOOP_COUNT;
++
++ /* Can't call clk_get_rate as it locks a mutex and here we are spinlocked.
++ * Use the value that we cached in the probe.
++ */
++ cdiv = bi->cdiv;
++
++ if (bi->msg->flags & I2C_M_RD)
++ c |= BSC_C_INTR | BSC_C_READ;
++ else
++ c |= BSC_C_INTT;
++
++ bcm2708_wr(bi, BSC_DIV, cdiv);
++ bcm2708_wr(bi, BSC_A, bi->msg->addr);
++ bcm2708_wr(bi, BSC_DLEN, bi->msg->len);
++ if (combined)
++ {
++ /* Do the next two messages meet combined transaction criteria?
++ - Current message is a write, next message is a read
++ - Both messages to same slave address
++ - Write message can fit inside FIFO (16 bytes or less) */
++ if ( (bi->nmsgs > 1) &&
++ !(bi->msg[0].flags & I2C_M_RD) && (bi->msg[1].flags & I2C_M_RD) &&
++ (bi->msg[0].addr == bi->msg[1].addr) && (bi->msg[0].len <= 16)) {
++ /* Fill FIFO with entire write message (16 byte FIFO) */
++ while (bi->pos < bi->msg->len) {
++ bcm2708_wr(bi, BSC_FIFO, bi->msg->buf[bi->pos++]);
++ }
++ /* Start write transfer (no interrupts, don't clear FIFO) */
++ bcm2708_wr(bi, BSC_C, BSC_C_I2CEN | BSC_C_ST);
++
++ /* poll for transfer start bit (should only take 1-20 polls) */
++ do {
++ s = bcm2708_rd(bi, BSC_S);
++ } while (!(s & (BSC_S_TA | BSC_S_ERR | BSC_S_CLKT | BSC_S_DONE)) && --wait_loops >= 0);
++
++ /* did we time out or some error occured? */
++ if (wait_loops < 0 || (s & (BSC_S_ERR | BSC_S_CLKT))) {
++ return -1;
++ }
++
++ /* Send next read message before the write transfer finishes. */
++ bi->nmsgs--;
++ bi->msg++;
++ bi->pos = 0;
++ bcm2708_wr(bi, BSC_DLEN, bi->msg->len);
++ c = BSC_C_I2CEN | BSC_C_INTD | BSC_C_INTR | BSC_C_ST | BSC_C_READ;
++ }
++ }
++ bcm2708_wr(bi, BSC_C, c);
++
++ return 0;
++}
++
++static irqreturn_t bcm2708_i2c_interrupt(int irq, void *dev_id)
++{
++ struct bcm2708_i2c *bi = dev_id;
++ bool handled = true;
++ u32 s;
++ int ret;
++
++ spin_lock(&bi->lock);
++
++ /* we may see camera interrupts on the "other" I2C channel
++ Just return if we've not sent anything */
++ if (!bi->nmsgs || !bi->msg) {
++ goto early_exit;
++ }
++
++ s = bcm2708_rd(bi, BSC_S);
++
++ if (s & (BSC_S_CLKT | BSC_S_ERR)) {
++ bcm2708_bsc_reset(bi);
++ bi->error = true;
++
++ bi->msg = 0; /* to inform the that all work is done */
++ bi->nmsgs = 0;
++ /* wake up our bh */
++ complete(&bi->done);
++ } else if (s & BSC_S_DONE) {
++ bi->nmsgs--;
++
++ if (bi->msg->flags & I2C_M_RD) {
++ bcm2708_bsc_fifo_drain(bi);
++ }
++
++ bcm2708_bsc_reset(bi);
++
++ if (bi->nmsgs) {
++ /* advance to next message */
++ bi->msg++;
++ bi->pos = 0;
++ ret = bcm2708_bsc_setup(bi);
++ if (ret < 0) {
++ bcm2708_bsc_reset(bi);
++ bi->error = true;
++ bi->msg = 0; /* to inform the that all work is done */
++ bi->nmsgs = 0;
++ /* wake up our bh */
++ complete(&bi->done);
++ goto early_exit;
++ }
++ } else {
++ bi->msg = 0; /* to inform the that all work is done */
++ bi->nmsgs = 0;
++ /* wake up our bh */
++ complete(&bi->done);
++ }
++ } else if (s & BSC_S_TXW) {
++ bcm2708_bsc_fifo_fill(bi);
++ } else if (s & BSC_S_RXR) {
++ bcm2708_bsc_fifo_drain(bi);
++ } else {
++ handled = false;
++ }
++
++early_exit:
++ spin_unlock(&bi->lock);
++
++ return handled ? IRQ_HANDLED : IRQ_NONE;
++}
++
++static int bcm2708_i2c_master_xfer(struct i2c_adapter *adap,
++ struct i2c_msg *msgs, int num)
++{
++ struct bcm2708_i2c *bi = adap->algo_data;
++ unsigned long flags;
++ int ret;
++
++ spin_lock_irqsave(&bi->lock, flags);
++
++ reinit_completion(&bi->done);
++ bi->msg = msgs;
++ bi->pos = 0;
++ bi->nmsgs = num;
++ bi->error = false;
++
++ ret = bcm2708_bsc_setup(bi);
++
++ spin_unlock_irqrestore(&bi->lock, flags);
++
++ /* check the result of the setup */
++ if (ret < 0)
++ {
++ dev_err(&adap->dev, "transfer setup timed out\n");
++ goto error_timeout;
++ }
++
++ ret = wait_for_completion_timeout(&bi->done, adap->timeout);
++ if (ret == 0) {
++ dev_err(&adap->dev, "transfer timed out\n");
++ goto error_timeout;
++ }
++
++ ret = bi->error ? -EIO : num;
++ return ret;
++
++error_timeout:
++ spin_lock_irqsave(&bi->lock, flags);
++ bcm2708_bsc_reset(bi);
++ bi->msg = 0; /* to inform the interrupt handler that there's nothing else to be done */
++ bi->nmsgs = 0;
++ spin_unlock_irqrestore(&bi->lock, flags);
++ return -ETIMEDOUT;
++}
++
++static u32 bcm2708_i2c_functionality(struct i2c_adapter *adap)
++{
++ return I2C_FUNC_I2C | /*I2C_FUNC_10BIT_ADDR |*/ I2C_FUNC_SMBUS_EMUL;
++}
++
++static struct i2c_algorithm bcm2708_i2c_algorithm = {
++ .master_xfer = bcm2708_i2c_master_xfer,
++ .functionality = bcm2708_i2c_functionality,
++};
++
++static int bcm2708_i2c_probe(struct platform_device *pdev)
++{
++ struct resource *regs;
++ int irq, err = -ENOMEM;
++ struct clk *clk;
++ struct bcm2708_i2c *bi;
++ struct i2c_adapter *adap;
++ unsigned long bus_hz;
++ u32 cdiv;
++
++ if (pdev->dev.of_node) {
++ u32 bus_clk_rate;
++ pdev->id = of_alias_get_id(pdev->dev.of_node, "i2c");
++ if (pdev->id < 0) {
++ dev_err(&pdev->dev, "alias is missing\n");
++ return -EINVAL;
++ }
++ if (!of_property_read_u32(pdev->dev.of_node,
++ "clock-frequency", &bus_clk_rate))
++ baudrate = bus_clk_rate;
++ else
++ dev_warn(&pdev->dev,
++ "Could not read clock-frequency property\n");
++ }
++
++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!regs) {
++ dev_err(&pdev->dev, "could not get IO memory\n");
++ return -ENXIO;
++ }
++
++ irq = platform_get_irq(pdev, 0);
++ if (irq < 0) {
++ dev_err(&pdev->dev, "could not get IRQ\n");
++ return irq;
++ }
++
++ clk = clk_get(&pdev->dev, NULL);
++ if (IS_ERR(clk)) {
++ dev_err(&pdev->dev, "could not find clk: %ld\n", PTR_ERR(clk));
++ return PTR_ERR(clk);
++ }
++
++ err = clk_prepare_enable(clk);
++ if (err) {
++ dev_err(&pdev->dev, "could not enable clk: %d\n", err);
++ goto out_clk_put;
++ }
++
++ bi = kzalloc(sizeof(*bi), GFP_KERNEL);
++ if (!bi)
++ goto out_clk_disable;
++
++ platform_set_drvdata(pdev, bi);
++
++ adap = &bi->adapter;
++ adap->class = I2C_CLASS_HWMON | I2C_CLASS_DDC;
++ adap->algo = &bcm2708_i2c_algorithm;
++ adap->algo_data = bi;
++ adap->dev.parent = &pdev->dev;
++ adap->nr = pdev->id;
++ strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name));
++ adap->dev.of_node = pdev->dev.of_node;
++
++ switch (pdev->id) {
++ case 0:
++ adap->class = I2C_CLASS_HWMON;
++ break;
++ case 1:
++ adap->class = I2C_CLASS_DDC;
++ break;
++ case 2:
++ adap->class = I2C_CLASS_DDC;
++ break;
++ default:
++ dev_err(&pdev->dev, "can only bind to BSC 0, 1 or 2\n");
++ err = -ENXIO;
++ goto out_free_bi;
++ }
++
++ spin_lock_init(&bi->lock);
++ init_completion(&bi->done);
++
++ bi->base = ioremap(regs->start, resource_size(regs));
++ if (!bi->base) {
++ dev_err(&pdev->dev, "could not remap memory\n");
++ goto out_free_bi;
++ }
++
++ bi->irq = irq;
++ bi->clk = clk;
++
++ err = request_irq(irq, bcm2708_i2c_interrupt, IRQF_SHARED,
++ dev_name(&pdev->dev), bi);
++ if (err) {
++ dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
++ goto out_iounmap;
++ }
++
++ bcm2708_bsc_reset(bi);
++
++ err = i2c_add_numbered_adapter(adap);
++ if (err < 0) {
++ dev_err(&pdev->dev, "could not add I2C adapter: %d\n", err);
++ goto out_free_irq;
++ }
++
++ bus_hz = clk_get_rate(bi->clk);
++ cdiv = bus_hz / baudrate;
++ if (cdiv > 0xffff) {
++ cdiv = 0xffff;
++ baudrate = bus_hz / cdiv;
++ }
++ bi->cdiv = cdiv;
++
++ dev_info(&pdev->dev, "BSC%d Controller at 0x%08lx (irq %d) (baudrate %d)\n",
++ pdev->id, (unsigned long)regs->start, irq, baudrate);
++
++ return 0;
++
++out_free_irq:
++ free_irq(bi->irq, bi);
++out_iounmap:
++ iounmap(bi->base);
++out_free_bi:
++ kfree(bi);
++out_clk_disable:
++ clk_disable_unprepare(clk);
++out_clk_put:
++ clk_put(clk);
++ return err;
++}
++
++static int bcm2708_i2c_remove(struct platform_device *pdev)
++{
++ struct bcm2708_i2c *bi = platform_get_drvdata(pdev);
++
++ platform_set_drvdata(pdev, NULL);
++
++ i2c_del_adapter(&bi->adapter);
++ free_irq(bi->irq, bi);
++ iounmap(bi->base);
++ clk_disable_unprepare(bi->clk);
++ clk_put(bi->clk);
++ kfree(bi);
++
++ return 0;
++}
++
++static const struct of_device_id bcm2708_i2c_of_match[] = {
++ { .compatible = "brcm,bcm2708-i2c" },
++ {},
++};
++MODULE_DEVICE_TABLE(of, bcm2708_i2c_of_match);
++
++static struct platform_driver bcm2708_i2c_driver = {
++ .driver = {
++ .name = DRV_NAME,
++ .owner = THIS_MODULE,
++ .of_match_table = bcm2708_i2c_of_match,
++ },
++ .probe = bcm2708_i2c_probe,
++ .remove = bcm2708_i2c_remove,
++};
++
++// module_platform_driver(bcm2708_i2c_driver);
++
++
++static int __init bcm2708_i2c_init(void)
++{
++ return platform_driver_register(&bcm2708_i2c_driver);
++}
++
++static void __exit bcm2708_i2c_exit(void)
++{
++ platform_driver_unregister(&bcm2708_i2c_driver);
++}
++
++module_init(bcm2708_i2c_init);
++module_exit(bcm2708_i2c_exit);
++
++
++
++MODULE_DESCRIPTION("BSC controller driver for Broadcom BCM2708");
++MODULE_AUTHOR("Chris Boot <bootc@bootc.net>");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/target/linux/brcm2708/patches-4.4/0045-Added-hwmon-thermal-driver-for-reporting-core-temper.patch b/target/linux/brcm2708/patches-4.4/0045-Added-hwmon-thermal-driver-for-reporting-core-temper.patch
deleted file mode 100644
index 06046a69f5..0000000000
--- a/target/linux/brcm2708/patches-4.4/0045-Added-hwmon-thermal-driver-for-reporting-core-temper.patch
+++ /dev/null
@@ -1,193 +0,0 @@
-From 776e87ffc8b137ea465e7b0076e56cd71d9c56d1 Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Tue, 26 Mar 2013 19:24:24 +0000
-Subject: [PATCH 045/170] Added hwmon/thermal driver for reporting core
- temperature. Thanks Dorian
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-BCM270x: Move thermal sensor to Device Tree
-
-Add Device Tree support to bcm2835-thermal driver.
-Add thermal sensor device to Device Tree.
-Don't add platform device when booting in DT mode.
-
-Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
----
- drivers/thermal/Kconfig | 7 ++
- drivers/thermal/Makefile | 1 +
- drivers/thermal/bcm2835-thermal.c | 141 ++++++++++++++++++++++++++++++++++++++
- 3 files changed, 149 insertions(+)
- create mode 100644 drivers/thermal/bcm2835-thermal.c
-
---- a/drivers/thermal/Kconfig
-+++ b/drivers/thermal/Kconfig
-@@ -285,6 +285,13 @@ config INTEL_POWERCLAMP
- enforce idle time which results in more package C-state residency. The
- user interface is exposed via generic thermal framework.
-
-+config THERMAL_BCM2835
-+ depends on RASPBERRYPI_FIRMWARE
-+ tristate "BCM2835 Thermal Driver"
-+ help
-+ This will enable temperature monitoring for the Broadcom BCM2835
-+ chip. If built as a module, it will be called 'bcm2835-thermal'.
-+
- config X86_PKG_TEMP_THERMAL
- tristate "X86 package temperature thermal driver"
- depends on X86_THERMAL_VECTOR
---- a/drivers/thermal/Makefile
-+++ b/drivers/thermal/Makefile
-@@ -38,6 +38,7 @@ obj-$(CONFIG_ARMADA_THERMAL) += armada_t
- obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o
- obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o
- obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o
-+obj-$(CONFIG_THERMAL_BCM2835) += bcm2835-thermal.o
- obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o
- obj-$(CONFIG_INTEL_SOC_DTS_IOSF_CORE) += intel_soc_dts_iosf.o
- obj-$(CONFIG_INTEL_SOC_DTS_THERMAL) += intel_soc_dts_thermal.o
---- /dev/null
-+++ b/drivers/thermal/bcm2835-thermal.c
-@@ -0,0 +1,141 @@
-+/*****************************************************************************
-+* Copyright 2011 Broadcom Corporation. All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*****************************************************************************/
-+
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/thermal.h>
-+#include <soc/bcm2835/raspberrypi-firmware.h>
-+
-+static int bcm2835_thermal_get_property(struct thermal_zone_device *tz,
-+ int *temp, u32 tag)
-+{
-+ struct rpi_firmware *fw = tz->devdata;
-+ struct {
-+ u32 id;
-+ u32 val;
-+ } packet;
-+ int ret;
-+
-+ *temp = 0;
-+ packet.id = 0;
-+ ret = rpi_firmware_property(fw, tag, &packet, sizeof(packet));
-+ if (ret) {
-+ dev_err(&tz->device, "Failed to get temperature\n");
-+ return ret;
-+ }
-+
-+ *temp = packet.val;
-+ dev_dbg(&tz->device, "%stemp=%d\n",
-+ tag == RPI_FIRMWARE_GET_MAX_TEMPERATURE ? "max" : "", *temp);
-+
-+ return 0;
-+}
-+
-+static int bcm2835_thermal_get_temp(struct thermal_zone_device *tz,
-+ int *temp)
-+{
-+ return bcm2835_thermal_get_property(tz, temp,
-+ RPI_FIRMWARE_GET_TEMPERATURE);
-+}
-+
-+static int bcm2835_thermal_get_max_temp(struct thermal_zone_device *tz,
-+ int trip, int *temp)
-+{
-+ /*
-+ * The maximum safe temperature of the SoC.
-+ * Overclock may be disabled above this temperature.
-+ */
-+ return bcm2835_thermal_get_property(tz, temp,
-+ RPI_FIRMWARE_GET_MAX_TEMPERATURE);
-+}
-+
-+static int bcm2835_thermal_get_trip_type(struct thermal_zone_device *tz,
-+ int trip, enum thermal_trip_type *type)
-+{
-+ *type = THERMAL_TRIP_HOT;
-+
-+ return 0;
-+}
-+
-+static int bcm2835_thermal_get_mode(struct thermal_zone_device *tz,
-+ enum thermal_device_mode *mode)
-+{
-+ *mode = THERMAL_DEVICE_ENABLED;
-+
-+ return 0;
-+}
-+
-+static struct thermal_zone_device_ops ops = {
-+ .get_temp = bcm2835_thermal_get_temp,
-+ .get_trip_temp = bcm2835_thermal_get_max_temp,
-+ .get_trip_type = bcm2835_thermal_get_trip_type,
-+ .get_mode = bcm2835_thermal_get_mode,
-+};
-+
-+static int bcm2835_thermal_probe(struct platform_device *pdev)
-+{
-+ struct device_node *fw_np;
-+ struct rpi_firmware *fw;
-+ struct thermal_zone_device *tz;
-+
-+ fw_np = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
-+/* Remove comment when booting without Device Tree is no longer supported
-+ if (!fw_np) {
-+ dev_err(&pdev->dev, "Missing firmware node\n");
-+ return -ENOENT;
-+ }
-+*/
-+ fw = rpi_firmware_get(fw_np);
-+ if (!fw)
-+ return -EPROBE_DEFER;
-+
-+ tz = thermal_zone_device_register("bcm2835_thermal", 1, 0, fw, &ops,
-+ NULL, 0, 0);
-+ if (IS_ERR(tz)) {
-+ dev_err(&pdev->dev, "Failed to register the thermal device\n");
-+ return PTR_ERR(tz);
-+ }
-+
-+ platform_set_drvdata(pdev, tz);
-+
-+ return 0;
-+}
-+
-+static int bcm2835_thermal_remove(struct platform_device *pdev)
-+{
-+ thermal_zone_device_unregister(platform_get_drvdata(pdev));
-+
-+ return 0;
-+}
-+
-+static const struct of_device_id bcm2835_thermal_of_match_table[] = {
-+ { .compatible = "brcm,bcm2835-thermal", },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(of, bcm2835_thermal_of_match_table);
-+
-+static struct platform_driver bcm2835_thermal_driver = {
-+ .probe = bcm2835_thermal_probe,
-+ .remove = bcm2835_thermal_remove,
-+ .driver = {
-+ .name = "bcm2835_thermal",
-+ .of_match_table = bcm2835_thermal_of_match_table,
-+ },
-+};
-+module_platform_driver(bcm2835_thermal_driver);
-+
-+MODULE_AUTHOR("Dorian Peake");
-+MODULE_AUTHOR("Noralf Trønnes");
-+MODULE_DESCRIPTION("Thermal driver for bcm2835 chip");
-+MODULE_LICENSE("GPL");
diff --git a/target/linux/brcm2708/patches-4.4/0046-Add-Chris-Boot-s-i2c-driver.patch b/target/linux/brcm2708/patches-4.4/0046-Add-Chris-Boot-s-i2c-driver.patch
deleted file mode 100644
index 6730ee6fd8..0000000000
--- a/target/linux/brcm2708/patches-4.4/0046-Add-Chris-Boot-s-i2c-driver.patch
+++ /dev/null
@@ -1,635 +0,0 @@
-From 72181304010d3aa74cd2b98db592554a541ce4c2 Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Wed, 17 Jun 2015 15:44:08 +0100
-Subject: [PATCH 046/170] Add Chris Boot's i2c driver
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-i2c-bcm2708: fixed baudrate
-
-Fixed issue where the wrong CDIV value was set for baudrates below 3815 Hz (for 250MHz bus clock).
-In that case the computed CDIV value was more than 0xffff. However the CDIV register width is only 16 bits.
-This resulted in incorrect setting of CDIV and higher baudrate than intended.
-Example: 3500Hz -> CDIV=0x11704 -> CDIV(16bit)=0x1704 -> 42430Hz
-After correction: 3500Hz -> CDIV=0x11704 -> CDIV(16bit)=0xffff -> 3815Hz
-The correct baudrate is shown in the log after the cdiv > 0xffff correction.
-
-Perform I2C combined transactions when possible
-
-Perform I2C combined transactions whenever possible, within the
-restrictions of the Broadcomm Serial Controller.
-
-Disable DONE interrupt during TA poll
-
-Prevent interrupt from being triggered if poll is missed and transfer
-starts and finishes.
-
-i2c: Make combined transactions optional and disabled by default
-
-i2c: bcm2708: add device tree support
-
-Add DT support to driver and add to .dtsi file.
-Setup pins in .dts file.
-i2c is disabled by default.
-
-Signed-off-by: Noralf Tronnes <notro@tronnes.org>
-
-bcm2708: don't register i2c controllers when using DT
-
-The devices for the i2c controllers are in the Device Tree.
-Only register devices when not using DT.
-
-Signed-off-by: Noralf Tronnes <notro@tronnes.org>
-
-I2C: Only register the I2C device for the current board revision
-
-i2c_bcm2708: Fix clock reference counting
-
-Fix grabbing lock from atomic context in i2c driver
-
-2 main changes:
-- check for timeouts in the bcm2708_bsc_setup function as indicated by this comment:
- /* poll for transfer start bit (should only take 1-20 polls) */
- This implies that the setup function can now fail so account for this everywhere it's called
-- Removed the clk_get_rate call from inside the setup function as it locks a mutex and that's not ok since we call it from under a spin lock.
-
-i2c-bcm2708: When using DT, leave the GPIO setup to pinctrl
-
-i2c-bcm2708: Increase timeouts to allow larger transfers
-
-Use the timeout value provided by the I2C_TIMEOUT ioctl when waiting
-for completion. The default timeout is 1 second.
-
-See: https://github.com/raspberrypi/linux/issues/260
-
-i2c-bcm2708/BCM270X_DT: Add support for I2C2
-
-The third I2C bus (I2C2) is normally reserved for HDMI use. Careless
-use of this bus can break an attached display - use with caution.
-
-It is recommended to disable accesses by VideoCore by setting
-hdmi_ignore_edid=1 or hdmi_edid_file=1 in config.txt.
-
-The interface is disabled by default - enable using the
-i2c2_iknowwhatimdoing DT parameter.
-
-bcm2708-spi: Don't use static pin configuration with DT
-
-Also remove superfluous error checking - the SPI framework ensures the
-validity of the chip_select value.
-
-i2c-bcm2708: Remove non-DT support
-
-Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
----
- drivers/i2c/busses/Kconfig | 21 +-
- drivers/i2c/busses/Makefile | 2 +
- drivers/i2c/busses/i2c-bcm2708.c | 493 +++++++++++++++++++++++++++++++++++++++
- 3 files changed, 515 insertions(+), 1 deletion(-)
- create mode 100644 drivers/i2c/busses/i2c-bcm2708.c
-
---- a/drivers/i2c/busses/Kconfig
-+++ b/drivers/i2c/busses/Kconfig
-@@ -8,6 +8,25 @@ menu "I2C Hardware Bus support"
- comment "PC SMBus host controller drivers"
- depends on PCI
-
-+config I2C_BCM2708
-+ tristate "BCM2708 BSC"
-+ depends on MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835
-+ help
-+ Enabling this option will add BSC (Broadcom Serial Controller)
-+ support for the BCM2708. BSC is a Broadcom proprietary bus compatible
-+ with I2C/TWI/SMBus.
-+
-+config I2C_BCM2708_BAUDRATE
-+ prompt "BCM2708 I2C baudrate"
-+ depends on I2C_BCM2708
-+ int
-+ default 100000
-+ help
-+ Set the I2C baudrate. This will alter the default value. A
-+ different baudrate can be set by using a module parameter as well. If
-+ no parameter is provided when loading, this is the value that will be
-+ used.
-+
- config I2C_ALI1535
- tristate "ALI 1535"
- depends on PCI
-@@ -365,7 +384,7 @@ config I2C_AXXIA
-
- config I2C_BCM2835
- tristate "Broadcom BCM2835 I2C controller"
-- depends on ARCH_BCM2835
-+ depends on ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709
- help
- If you say yes to this option, support will be included for the
- BCM2835 I2C controller.
---- a/drivers/i2c/busses/Makefile
-+++ b/drivers/i2c/busses/Makefile
-@@ -2,6 +2,8 @@
- # Makefile for the i2c bus drivers.
- #
-
-+obj-$(CONFIG_I2C_BCM2708) += i2c-bcm2708.o
-+
- # ACPI drivers
- obj-$(CONFIG_I2C_SCMI) += i2c-scmi.o
-
---- /dev/null
-+++ b/drivers/i2c/busses/i2c-bcm2708.c
-@@ -0,0 +1,493 @@
-+/*
-+ * Driver for Broadcom BCM2708 BSC Controllers
-+ *
-+ * Copyright (C) 2012 Chris Boot & Frank Buss
-+ *
-+ * This driver is inspired by:
-+ * i2c-ocores.c, by Peter Korsgaard <jacmet@sunsite.dk>
-+ *
-+ * 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/kernel.h>
-+#include <linux/module.h>
-+#include <linux/spinlock.h>
-+#include <linux/clk.h>
-+#include <linux/err.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <linux/io.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/interrupt.h>
-+#include <linux/sched.h>
-+#include <linux/wait.h>
-+
-+/* BSC register offsets */
-+#define BSC_C 0x00
-+#define BSC_S 0x04
-+#define BSC_DLEN 0x08
-+#define BSC_A 0x0c
-+#define BSC_FIFO 0x10
-+#define BSC_DIV 0x14
-+#define BSC_DEL 0x18
-+#define BSC_CLKT 0x1c
-+
-+/* Bitfields in BSC_C */
-+#define BSC_C_I2CEN 0x00008000
-+#define BSC_C_INTR 0x00000400
-+#define BSC_C_INTT 0x00000200
-+#define BSC_C_INTD 0x00000100
-+#define BSC_C_ST 0x00000080
-+#define BSC_C_CLEAR_1 0x00000020
-+#define BSC_C_CLEAR_2 0x00000010
-+#define BSC_C_READ 0x00000001
-+
-+/* Bitfields in BSC_S */
-+#define BSC_S_CLKT 0x00000200
-+#define BSC_S_ERR 0x00000100
-+#define BSC_S_RXF 0x00000080
-+#define BSC_S_TXE 0x00000040
-+#define BSC_S_RXD 0x00000020
-+#define BSC_S_TXD 0x00000010
-+#define BSC_S_RXR 0x00000008
-+#define BSC_S_TXW 0x00000004
-+#define BSC_S_DONE 0x00000002
-+#define BSC_S_TA 0x00000001
-+
-+#define I2C_WAIT_LOOP_COUNT 200
-+
-+#define DRV_NAME "bcm2708_i2c"
-+
-+static unsigned int baudrate = CONFIG_I2C_BCM2708_BAUDRATE;
-+module_param(baudrate, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
-+MODULE_PARM_DESC(baudrate, "The I2C baudrate");
-+
-+static bool combined = false;
-+module_param(combined, bool, 0644);
-+MODULE_PARM_DESC(combined, "Use combined transactions");
-+
-+struct bcm2708_i2c {
-+ struct i2c_adapter adapter;
-+
-+ spinlock_t lock;
-+ void __iomem *base;
-+ int irq;
-+ struct clk *clk;
-+ u32 cdiv;
-+
-+ struct completion done;
-+
-+ struct i2c_msg *msg;
-+ int pos;
-+ int nmsgs;
-+ bool error;
-+};
-+
-+static inline u32 bcm2708_rd(struct bcm2708_i2c *bi, unsigned reg)
-+{
-+ return readl(bi->base + reg);
-+}
-+
-+static inline void bcm2708_wr(struct bcm2708_i2c *bi, unsigned reg, u32 val)
-+{
-+ writel(val, bi->base + reg);
-+}
-+
-+static inline void bcm2708_bsc_reset(struct bcm2708_i2c *bi)
-+{
-+ bcm2708_wr(bi, BSC_C, 0);
-+ bcm2708_wr(bi, BSC_S, BSC_S_CLKT | BSC_S_ERR | BSC_S_DONE);
-+}
-+
-+static inline void bcm2708_bsc_fifo_drain(struct bcm2708_i2c *bi)
-+{
-+ while ((bcm2708_rd(bi, BSC_S) & BSC_S_RXD) && (bi->pos < bi->msg->len))
-+ bi->msg->buf[bi->pos++] = bcm2708_rd(bi, BSC_FIFO);
-+}
-+
-+static inline void bcm2708_bsc_fifo_fill(struct bcm2708_i2c *bi)
-+{
-+ while ((bcm2708_rd(bi, BSC_S) & BSC_S_TXD) && (bi->pos < bi->msg->len))
-+ bcm2708_wr(bi, BSC_FIFO, bi->msg->buf[bi->pos++]);
-+}
-+
-+static inline int bcm2708_bsc_setup(struct bcm2708_i2c *bi)
-+{
-+ u32 cdiv, s;
-+ u32 c = BSC_C_I2CEN | BSC_C_INTD | BSC_C_ST | BSC_C_CLEAR_1;
-+ int wait_loops = I2C_WAIT_LOOP_COUNT;
-+
-+ /* Can't call clk_get_rate as it locks a mutex and here we are spinlocked.
-+ * Use the value that we cached in the probe.
-+ */
-+ cdiv = bi->cdiv;
-+
-+ if (bi->msg->flags & I2C_M_RD)
-+ c |= BSC_C_INTR | BSC_C_READ;
-+ else
-+ c |= BSC_C_INTT;
-+
-+ bcm2708_wr(bi, BSC_DIV, cdiv);
-+ bcm2708_wr(bi, BSC_A, bi->msg->addr);
-+ bcm2708_wr(bi, BSC_DLEN, bi->msg->len);
-+ if (combined)
-+ {
-+ /* Do the next two messages meet combined transaction criteria?
-+ - Current message is a write, next message is a read
-+ - Both messages to same slave address
-+ - Write message can fit inside FIFO (16 bytes or less) */
-+ if ( (bi->nmsgs > 1) &&
-+ !(bi->msg[0].flags & I2C_M_RD) && (bi->msg[1].flags & I2C_M_RD) &&
-+ (bi->msg[0].addr == bi->msg[1].addr) && (bi->msg[0].len <= 16)) {
-+ /* Fill FIFO with entire write message (16 byte FIFO) */
-+ while (bi->pos < bi->msg->len) {
-+ bcm2708_wr(bi, BSC_FIFO, bi->msg->buf[bi->pos++]);
-+ }
-+ /* Start write transfer (no interrupts, don't clear FIFO) */
-+ bcm2708_wr(bi, BSC_C, BSC_C_I2CEN | BSC_C_ST);
-+
-+ /* poll for transfer start bit (should only take 1-20 polls) */
-+ do {
-+ s = bcm2708_rd(bi, BSC_S);
-+ } while (!(s & (BSC_S_TA | BSC_S_ERR | BSC_S_CLKT | BSC_S_DONE)) && --wait_loops >= 0);
-+
-+ /* did we time out or some error occured? */
-+ if (wait_loops < 0 || (s & (BSC_S_ERR | BSC_S_CLKT))) {
-+ return -1;
-+ }
-+
-+ /* Send next read message before the write transfer finishes. */
-+ bi->nmsgs--;
-+ bi->msg++;
-+ bi->pos = 0;
-+ bcm2708_wr(bi, BSC_DLEN, bi->msg->len);
-+ c = BSC_C_I2CEN | BSC_C_INTD | BSC_C_INTR | BSC_C_ST | BSC_C_READ;
-+ }
-+ }
-+ bcm2708_wr(bi, BSC_C, c);
-+
-+ return 0;
-+}
-+
-+static irqreturn_t bcm2708_i2c_interrupt(int irq, void *dev_id)
-+{
-+ struct bcm2708_i2c *bi = dev_id;
-+ bool handled = true;
-+ u32 s;
-+ int ret;
-+
-+ spin_lock(&bi->lock);
-+
-+ /* we may see camera interrupts on the "other" I2C channel
-+ Just return if we've not sent anything */
-+ if (!bi->nmsgs || !bi->msg) {
-+ goto early_exit;
-+ }
-+
-+ s = bcm2708_rd(bi, BSC_S);
-+
-+ if (s & (BSC_S_CLKT | BSC_S_ERR)) {
-+ bcm2708_bsc_reset(bi);
-+ bi->error = true;
-+
-+ bi->msg = 0; /* to inform the that all work is done */
-+ bi->nmsgs = 0;
-+ /* wake up our bh */
-+ complete(&bi->done);
-+ } else if (s & BSC_S_DONE) {
-+ bi->nmsgs--;
-+
-+ if (bi->msg->flags & I2C_M_RD) {
-+ bcm2708_bsc_fifo_drain(bi);
-+ }
-+
-+ bcm2708_bsc_reset(bi);
-+
-+ if (bi->nmsgs) {
-+ /* advance to next message */
-+ bi->msg++;
-+ bi->pos = 0;
-+ ret = bcm2708_bsc_setup(bi);
-+ if (ret < 0) {
-+ bcm2708_bsc_reset(bi);
-+ bi->error = true;
-+ bi->msg = 0; /* to inform the that all work is done */
-+ bi->nmsgs = 0;
-+ /* wake up our bh */
-+ complete(&bi->done);
-+ goto early_exit;
-+ }
-+ } else {
-+ bi->msg = 0; /* to inform the that all work is done */
-+ bi->nmsgs = 0;
-+ /* wake up our bh */
-+ complete(&bi->done);
-+ }
-+ } else if (s & BSC_S_TXW) {
-+ bcm2708_bsc_fifo_fill(bi);
-+ } else if (s & BSC_S_RXR) {
-+ bcm2708_bsc_fifo_drain(bi);
-+ } else {
-+ handled = false;
-+ }
-+
-+early_exit:
-+ spin_unlock(&bi->lock);
-+
-+ return handled ? IRQ_HANDLED : IRQ_NONE;
-+}
-+
-+static int bcm2708_i2c_master_xfer(struct i2c_adapter *adap,
-+ struct i2c_msg *msgs, int num)
-+{
-+ struct bcm2708_i2c *bi = adap->algo_data;
-+ unsigned long flags;
-+ int ret;
-+
-+ spin_lock_irqsave(&bi->lock, flags);
-+
-+ reinit_completion(&bi->done);
-+ bi->msg = msgs;
-+ bi->pos = 0;
-+ bi->nmsgs = num;
-+ bi->error = false;
-+
-+ ret = bcm2708_bsc_setup(bi);
-+
-+ spin_unlock_irqrestore(&bi->lock, flags);
-+
-+ /* check the result of the setup */
-+ if (ret < 0)
-+ {
-+ dev_err(&adap->dev, "transfer setup timed out\n");
-+ goto error_timeout;
-+ }
-+
-+ ret = wait_for_completion_timeout(&bi->done, adap->timeout);
-+ if (ret == 0) {
-+ dev_err(&adap->dev, "transfer timed out\n");
-+ goto error_timeout;
-+ }
-+
-+ ret = bi->error ? -EIO : num;
-+ return ret;
-+
-+error_timeout:
-+ spin_lock_irqsave(&bi->lock, flags);
-+ bcm2708_bsc_reset(bi);
-+ bi->msg = 0; /* to inform the interrupt handler that there's nothing else to be done */
-+ bi->nmsgs = 0;
-+ spin_unlock_irqrestore(&bi->lock, flags);
-+ return -ETIMEDOUT;
-+}
-+
-+static u32 bcm2708_i2c_functionality(struct i2c_adapter *adap)
-+{
-+ return I2C_FUNC_I2C | /*I2C_FUNC_10BIT_ADDR |*/ I2C_FUNC_SMBUS_EMUL;
-+}
-+
-+static struct i2c_algorithm bcm2708_i2c_algorithm = {
-+ .master_xfer = bcm2708_i2c_master_xfer,
-+ .functionality = bcm2708_i2c_functionality,
-+};
-+
-+static int bcm2708_i2c_probe(struct platform_device *pdev)
-+{
-+ struct resource *regs;
-+ int irq, err = -ENOMEM;
-+ struct clk *clk;
-+ struct bcm2708_i2c *bi;
-+ struct i2c_adapter *adap;
-+ unsigned long bus_hz;
-+ u32 cdiv;
-+
-+ if (pdev->dev.of_node) {
-+ u32 bus_clk_rate;
-+ pdev->id = of_alias_get_id(pdev->dev.of_node, "i2c");
-+ if (pdev->id < 0) {
-+ dev_err(&pdev->dev, "alias is missing\n");
-+ return -EINVAL;
-+ }
-+ if (!of_property_read_u32(pdev->dev.of_node,
-+ "clock-frequency", &bus_clk_rate))
-+ baudrate = bus_clk_rate;
-+ else
-+ dev_warn(&pdev->dev,
-+ "Could not read clock-frequency property\n");
-+ }
-+
-+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ if (!regs) {
-+ dev_err(&pdev->dev, "could not get IO memory\n");
-+ return -ENXIO;
-+ }
-+
-+ irq = platform_get_irq(pdev, 0);
-+ if (irq < 0) {
-+ dev_err(&pdev->dev, "could not get IRQ\n");
-+ return irq;
-+ }
-+
-+ clk = clk_get(&pdev->dev, NULL);
-+ if (IS_ERR(clk)) {
-+ dev_err(&pdev->dev, "could not find clk: %ld\n", PTR_ERR(clk));
-+ return PTR_ERR(clk);
-+ }
-+
-+ err = clk_prepare_enable(clk);
-+ if (err) {
-+ dev_err(&pdev->dev, "could not enable clk: %d\n", err);
-+ goto out_clk_put;
-+ }
-+
-+ bi = kzalloc(sizeof(*bi), GFP_KERNEL);
-+ if (!bi)
-+ goto out_clk_disable;
-+
-+ platform_set_drvdata(pdev, bi);
-+
-+ adap = &bi->adapter;
-+ adap->class = I2C_CLASS_HWMON | I2C_CLASS_DDC;
-+ adap->algo = &bcm2708_i2c_algorithm;
-+ adap->algo_data = bi;
-+ adap->dev.parent = &pdev->dev;
-+ adap->nr = pdev->id;
-+ strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name));
-+ adap->dev.of_node = pdev->dev.of_node;
-+
-+ switch (pdev->id) {
-+ case 0:
-+ adap->class = I2C_CLASS_HWMON;
-+ break;
-+ case 1:
-+ adap->class = I2C_CLASS_DDC;
-+ break;
-+ case 2:
-+ adap->class = I2C_CLASS_DDC;
-+ break;
-+ default:
-+ dev_err(&pdev->dev, "can only bind to BSC 0, 1 or 2\n");
-+ err = -ENXIO;
-+ goto out_free_bi;
-+ }
-+
-+ spin_lock_init(&bi->lock);
-+ init_completion(&bi->done);
-+
-+ bi->base = ioremap(regs->start, resource_size(regs));
-+ if (!bi->base) {
-+ dev_err(&pdev->dev, "could not remap memory\n");
-+ goto out_free_bi;
-+ }
-+
-+ bi->irq = irq;
-+ bi->clk = clk;
-+
-+ err = request_irq(irq, bcm2708_i2c_interrupt, IRQF_SHARED,
-+ dev_name(&pdev->dev), bi);
-+ if (err) {
-+ dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
-+ goto out_iounmap;
-+ }
-+
-+ bcm2708_bsc_reset(bi);
-+
-+ err = i2c_add_numbered_adapter(adap);
-+ if (err < 0) {
-+ dev_err(&pdev->dev, "could not add I2C adapter: %d\n", err);
-+ goto out_free_irq;
-+ }
-+
-+ bus_hz = clk_get_rate(bi->clk);
-+ cdiv = bus_hz / baudrate;
-+ if (cdiv > 0xffff) {
-+ cdiv = 0xffff;
-+ baudrate = bus_hz / cdiv;
-+ }
-+ bi->cdiv = cdiv;
-+
-+ dev_info(&pdev->dev, "BSC%d Controller at 0x%08lx (irq %d) (baudrate %d)\n",
-+ pdev->id, (unsigned long)regs->start, irq, baudrate);
-+
-+ return 0;
-+
-+out_free_irq:
-+ free_irq(bi->irq, bi);
-+out_iounmap:
-+ iounmap(bi->base);
-+out_free_bi:
-+ kfree(bi);
-+out_clk_disable:
-+ clk_disable_unprepare(clk);
-+out_clk_put:
-+ clk_put(clk);
-+ return err;
-+}
-+
-+static int bcm2708_i2c_remove(struct platform_device *pdev)
-+{
-+ struct bcm2708_i2c *bi = platform_get_drvdata(pdev);
-+
-+ platform_set_drvdata(pdev, NULL);
-+
-+ i2c_del_adapter(&bi->adapter);
-+ free_irq(bi->irq, bi);
-+ iounmap(bi->base);
-+ clk_disable_unprepare(bi->clk);
-+ clk_put(bi->clk);
-+ kfree(bi);
-+
-+ return 0;
-+}
-+
-+static const struct of_device_id bcm2708_i2c_of_match[] = {
-+ { .compatible = "brcm,bcm2708-i2c" },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(of, bcm2708_i2c_of_match);
-+
-+static struct platform_driver bcm2708_i2c_driver = {
-+ .driver = {
-+ .name = DRV_NAME,
-+ .owner = THIS_MODULE,
-+ .of_match_table = bcm2708_i2c_of_match,
-+ },
-+ .probe = bcm2708_i2c_probe,
-+ .remove = bcm2708_i2c_remove,
-+};
-+
-+// module_platform_driver(bcm2708_i2c_driver);
-+
-+
-+static int __init bcm2708_i2c_init(void)
-+{
-+ return platform_driver_register(&bcm2708_i2c_driver);
-+}
-+
-+static void __exit bcm2708_i2c_exit(void)
-+{
-+ platform_driver_unregister(&bcm2708_i2c_driver);
-+}
-+
-+module_init(bcm2708_i2c_init);
-+module_exit(bcm2708_i2c_exit);
-+
-+
-+
-+MODULE_DESCRIPTION("BSC controller driver for Broadcom BCM2708");
-+MODULE_AUTHOR("Chris Boot <bootc@bootc.net>");
-+MODULE_LICENSE("GPL v2");
-+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/target/linux/brcm2708/patches-4.4/0046-char-broadcom-Add-vcio-module.patch b/target/linux/brcm2708/patches-4.4/0046-char-broadcom-Add-vcio-module.patch
new file mode 100644
index 0000000000..c0c27528ae
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0046-char-broadcom-Add-vcio-module.patch
@@ -0,0 +1,221 @@
+From 9999c1fcfe8f03afaa2d91c2e9766ce8ae057c65 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
+Date: Fri, 26 Jun 2015 14:27:06 +0200
+Subject: [PATCH 046/381] char: broadcom: Add vcio module
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add module for accessing the mailbox property channel through
+/dev/vcio. Was previously in bcm2708-vcio.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+---
+ drivers/char/broadcom/Kconfig | 6 ++
+ drivers/char/broadcom/Makefile | 1 +
+ drivers/char/broadcom/vcio.c | 175 +++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 182 insertions(+)
+ create mode 100644 drivers/char/broadcom/vcio.c
+
+--- a/drivers/char/broadcom/Kconfig
++++ b/drivers/char/broadcom/Kconfig
+@@ -22,6 +22,12 @@ config BCM2708_VCMEM
+ help
+ Helper for videocore memory access and total size allocation.
+
++config BCM_VCIO
++ tristate "Mailbox userspace access"
++ depends on BCM2835_MBOX
++ help
++ Gives access to the mailbox property channel from userspace.
++
+ endif
+
+ config BCM_VC_SM
+--- a/drivers/char/broadcom/Makefile
++++ b/drivers/char/broadcom/Makefile
+@@ -1,5 +1,6 @@
+ obj-$(CONFIG_BCM_VC_CMA) += vc_cma/
+ obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o
++obj-$(CONFIG_BCM_VCIO) += vcio.o
+ obj-$(CONFIG_BCM_VC_SM) += vc_sm/
+
+ obj-$(CONFIG_BCM2835_DEVGPIOMEM)+= bcm2835-gpiomem.o
+--- /dev/null
++++ b/drivers/char/broadcom/vcio.c
+@@ -0,0 +1,175 @@
++/*
++ * Copyright (C) 2010 Broadcom
++ * Copyright (C) 2015 Noralf Trønnes
++ *
++ * 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.
++ *
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/cdev.h>
++#include <linux/device.h>
++#include <linux/fs.h>
++#include <linux/init.h>
++#include <linux/ioctl.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/uaccess.h>
++#include <soc/bcm2835/raspberrypi-firmware.h>
++
++#define MBOX_CHAN_PROPERTY 8
++
++#define VCIO_IOC_MAGIC 100
++#define IOCTL_MBOX_PROPERTY _IOWR(VCIO_IOC_MAGIC, 0, char *)
++
++static struct {
++ dev_t devt;
++ struct cdev cdev;
++ struct class *class;
++ struct rpi_firmware *fw;
++} vcio;
++
++static int vcio_user_property_list(void *user)
++{
++ u32 *buf, size;
++ int ret;
++
++ /* The first 32-bit is the size of the buffer */
++ if (copy_from_user(&size, user, sizeof(size)))
++ return -EFAULT;
++
++ buf = kmalloc(size, GFP_KERNEL);
++ if (!buf)
++ return -ENOMEM;
++
++ if (copy_from_user(buf, user, size)) {
++ kfree(buf);
++ return -EFAULT;
++ }
++
++ /* Strip off protocol encapsulation */
++ ret = rpi_firmware_property_list(vcio.fw, &buf[2], size - 12);
++ if (ret) {
++ kfree(buf);
++ return ret;
++ }
++
++ buf[1] = RPI_FIRMWARE_STATUS_SUCCESS;
++ if (copy_to_user(user, buf, size))
++ ret = -EFAULT;
++
++ kfree(buf);
++
++ return ret;
++}
++
++static int vcio_device_open(struct inode *inode, struct file *file)
++{
++ try_module_get(THIS_MODULE);
++
++ return 0;
++}
++
++static int vcio_device_release(struct inode *inode, struct file *file)
++{
++ module_put(THIS_MODULE);
++
++ return 0;
++}
++
++static long vcio_device_ioctl(struct file *file, unsigned int ioctl_num,
++ unsigned long ioctl_param)
++{
++ switch (ioctl_num) {
++ case IOCTL_MBOX_PROPERTY:
++ return vcio_user_property_list((void *)ioctl_param);
++ default:
++ pr_err("unknown ioctl: %d\n", ioctl_num);
++ return -EINVAL;
++ }
++}
++
++const struct file_operations vcio_fops = {
++ .unlocked_ioctl = vcio_device_ioctl,
++ .open = vcio_device_open,
++ .release = vcio_device_release,
++};
++
++static int __init vcio_init(void)
++{
++ struct device_node *np;
++ static struct device *dev;
++ int ret;
++
++ np = of_find_compatible_node(NULL, NULL,
++ "raspberrypi,bcm2835-firmware");
++/* Uncomment this when we only boot with Device Tree
++ if (!of_device_is_available(np))
++ return -ENODEV;
++*/
++ vcio.fw = rpi_firmware_get(np);
++ if (!vcio.fw)
++ return -ENODEV;
++
++ ret = alloc_chrdev_region(&vcio.devt, 0, 1, "vcio");
++ if (ret) {
++ pr_err("failed to allocate device number\n");
++ return ret;
++ }
++
++ cdev_init(&vcio.cdev, &vcio_fops);
++ vcio.cdev.owner = THIS_MODULE;
++ ret = cdev_add(&vcio.cdev, vcio.devt, 1);
++ if (ret) {
++ pr_err("failed to register device\n");
++ goto err_unregister_chardev;
++ }
++
++ /*
++ * Create sysfs entries
++ * 'bcm2708_vcio' is used for backwards compatibility so we don't break
++ * userspace. Raspian has a udev rule that changes the permissions.
++ */
++ vcio.class = class_create(THIS_MODULE, "bcm2708_vcio");
++ if (IS_ERR(vcio.class)) {
++ ret = PTR_ERR(vcio.class);
++ pr_err("failed to create class\n");
++ goto err_cdev_del;
++ }
++
++ dev = device_create(vcio.class, NULL, vcio.devt, NULL, "vcio");
++ if (IS_ERR(dev)) {
++ ret = PTR_ERR(dev);
++ pr_err("failed to create device\n");
++ goto err_class_destroy;
++ }
++
++ return 0;
++
++err_class_destroy:
++ class_destroy(vcio.class);
++err_cdev_del:
++ cdev_del(&vcio.cdev);
++err_unregister_chardev:
++ unregister_chrdev_region(vcio.devt, 1);
++
++ return ret;
++}
++module_init(vcio_init);
++
++static void __exit vcio_exit(void)
++{
++ device_destroy(vcio.class, vcio.devt);
++ class_destroy(vcio.class);
++ cdev_del(&vcio.cdev);
++ unregister_chrdev_region(vcio.devt, 1);
++}
++module_exit(vcio_exit);
++
++MODULE_AUTHOR("Gray Girling");
++MODULE_AUTHOR("Noralf Trønnes");
++MODULE_DESCRIPTION("Mailbox userspace access");
++MODULE_LICENSE("GPL");
diff --git a/target/linux/brcm2708/patches-4.4/0047-char-broadcom-Add-vcio-module.patch b/target/linux/brcm2708/patches-4.4/0047-char-broadcom-Add-vcio-module.patch
deleted file mode 100644
index 4ef967b62f..0000000000
--- a/target/linux/brcm2708/patches-4.4/0047-char-broadcom-Add-vcio-module.patch
+++ /dev/null
@@ -1,221 +0,0 @@
-From abcf04d54ccb3d0897b1f7a95ddf9d9ccf63dc76 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
-Date: Fri, 26 Jun 2015 14:27:06 +0200
-Subject: [PATCH 047/170] char: broadcom: Add vcio module
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Add module for accessing the mailbox property channel through
-/dev/vcio. Was previously in bcm2708-vcio.
-
-Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
----
- drivers/char/broadcom/Kconfig | 6 ++
- drivers/char/broadcom/Makefile | 1 +
- drivers/char/broadcom/vcio.c | 175 +++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 182 insertions(+)
- create mode 100644 drivers/char/broadcom/vcio.c
-
---- a/drivers/char/broadcom/Kconfig
-+++ b/drivers/char/broadcom/Kconfig
-@@ -22,6 +22,12 @@ config BCM2708_VCMEM
- help
- Helper for videocore memory access and total size allocation.
-
-+config BCM_VCIO
-+ tristate "Mailbox userspace access"
-+ depends on BCM2835_MBOX
-+ help
-+ Gives access to the mailbox property channel from userspace.
-+
- endif
-
- config BCM_VC_SM
---- a/drivers/char/broadcom/Makefile
-+++ b/drivers/char/broadcom/Makefile
-@@ -1,5 +1,6 @@
- obj-$(CONFIG_BCM_VC_CMA) += vc_cma/
- obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o
-+obj-$(CONFIG_BCM_VCIO) += vcio.o
- obj-$(CONFIG_BCM_VC_SM) += vc_sm/
-
- obj-$(CONFIG_BCM2835_DEVGPIOMEM)+= bcm2835-gpiomem.o
---- /dev/null
-+++ b/drivers/char/broadcom/vcio.c
-@@ -0,0 +1,175 @@
-+/*
-+ * Copyright (C) 2010 Broadcom
-+ * Copyright (C) 2015 Noralf Trønnes
-+ *
-+ * 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.
-+ *
-+ */
-+
-+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-+
-+#include <linux/cdev.h>
-+#include <linux/device.h>
-+#include <linux/fs.h>
-+#include <linux/init.h>
-+#include <linux/ioctl.h>
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/uaccess.h>
-+#include <soc/bcm2835/raspberrypi-firmware.h>
-+
-+#define MBOX_CHAN_PROPERTY 8
-+
-+#define VCIO_IOC_MAGIC 100
-+#define IOCTL_MBOX_PROPERTY _IOWR(VCIO_IOC_MAGIC, 0, char *)
-+
-+static struct {
-+ dev_t devt;
-+ struct cdev cdev;
-+ struct class *class;
-+ struct rpi_firmware *fw;
-+} vcio;
-+
-+static int vcio_user_property_list(void *user)
-+{
-+ u32 *buf, size;
-+ int ret;
-+
-+ /* The first 32-bit is the size of the buffer */
-+ if (copy_from_user(&size, user, sizeof(size)))
-+ return -EFAULT;
-+
-+ buf = kmalloc(size, GFP_KERNEL);
-+ if (!buf)
-+ return -ENOMEM;
-+
-+ if (copy_from_user(buf, user, size)) {
-+ kfree(buf);
-+ return -EFAULT;
-+ }
-+
-+ /* Strip off protocol encapsulation */
-+ ret = rpi_firmware_property_list(vcio.fw, &buf[2], size - 12);
-+ if (ret) {
-+ kfree(buf);
-+ return ret;
-+ }
-+
-+ buf[1] = RPI_FIRMWARE_STATUS_SUCCESS;
-+ if (copy_to_user(user, buf, size))
-+ ret = -EFAULT;
-+
-+ kfree(buf);
-+
-+ return ret;
-+}
-+
-+static int vcio_device_open(struct inode *inode, struct file *file)
-+{
-+ try_module_get(THIS_MODULE);
-+
-+ return 0;
-+}
-+
-+static int vcio_device_release(struct inode *inode, struct file *file)
-+{
-+ module_put(THIS_MODULE);
-+
-+ return 0;
-+}
-+
-+static long vcio_device_ioctl(struct file *file, unsigned int ioctl_num,
-+ unsigned long ioctl_param)
-+{
-+ switch (ioctl_num) {
-+ case IOCTL_MBOX_PROPERTY:
-+ return vcio_user_property_list((void *)ioctl_param);
-+ default:
-+ pr_err("unknown ioctl: %d\n", ioctl_num);
-+ return -EINVAL;
-+ }
-+}
-+
-+const struct file_operations vcio_fops = {
-+ .unlocked_ioctl = vcio_device_ioctl,
-+ .open = vcio_device_open,
-+ .release = vcio_device_release,
-+};
-+
-+static int __init vcio_init(void)
-+{
-+ struct device_node *np;
-+ static struct device *dev;
-+ int ret;
-+
-+ np = of_find_compatible_node(NULL, NULL,
-+ "raspberrypi,bcm2835-firmware");
-+/* Uncomment this when we only boot with Device Tree
-+ if (!of_device_is_available(np))
-+ return -ENODEV;
-+*/
-+ vcio.fw = rpi_firmware_get(np);
-+ if (!vcio.fw)
-+ return -ENODEV;
-+
-+ ret = alloc_chrdev_region(&vcio.devt, 0, 1, "vcio");
-+ if (ret) {
-+ pr_err("failed to allocate device number\n");
-+ return ret;
-+ }
-+
-+ cdev_init(&vcio.cdev, &vcio_fops);
-+ vcio.cdev.owner = THIS_MODULE;
-+ ret = cdev_add(&vcio.cdev, vcio.devt, 1);
-+ if (ret) {
-+ pr_err("failed to register device\n");
-+ goto err_unregister_chardev;
-+ }
-+
-+ /*
-+ * Create sysfs entries
-+ * 'bcm2708_vcio' is used for backwards compatibility so we don't break
-+ * userspace. Raspian has a udev rule that changes the permissions.
-+ */
-+ vcio.class = class_create(THIS_MODULE, "bcm2708_vcio");
-+ if (IS_ERR(vcio.class)) {
-+ ret = PTR_ERR(vcio.class);
-+ pr_err("failed to create class\n");
-+ goto err_cdev_del;
-+ }
-+
-+ dev = device_create(vcio.class, NULL, vcio.devt, NULL, "vcio");
-+ if (IS_ERR(dev)) {
-+ ret = PTR_ERR(dev);
-+ pr_err("failed to create device\n");
-+ goto err_class_destroy;
-+ }
-+
-+ return 0;
-+
-+err_class_destroy:
-+ class_destroy(vcio.class);
-+err_cdev_del:
-+ cdev_del(&vcio.cdev);
-+err_unregister_chardev:
-+ unregister_chrdev_region(vcio.devt, 1);
-+
-+ return ret;
-+}
-+module_init(vcio_init);
-+
-+static void __exit vcio_exit(void)
-+{
-+ device_destroy(vcio.class, vcio.devt);
-+ class_destroy(vcio.class);
-+ cdev_del(&vcio.cdev);
-+ unregister_chrdev_region(vcio.devt, 1);
-+}
-+module_exit(vcio_exit);
-+
-+MODULE_AUTHOR("Gray Girling");
-+MODULE_AUTHOR("Noralf Trønnes");
-+MODULE_DESCRIPTION("Mailbox userspace access");
-+MODULE_LICENSE("GPL");
diff --git a/target/linux/brcm2708/patches-4.4/0047-firmware-bcm2835-Support-ARCH_BCM270x.patch b/target/linux/brcm2708/patches-4.4/0047-firmware-bcm2835-Support-ARCH_BCM270x.patch
new file mode 100644
index 0000000000..8f992b0265
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0047-firmware-bcm2835-Support-ARCH_BCM270x.patch
@@ -0,0 +1,106 @@
+From 3ab001bd58d4578bf2beb293f93a91f81e3ad3b4 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
+Date: Fri, 26 Jun 2015 14:25:01 +0200
+Subject: [PATCH 047/381] firmware: bcm2835: Support ARCH_BCM270x
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Support booting without Device Tree.
+Turn on USB power.
+Load driver early because of lacking support for deferred probing
+in many drivers.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+---
+ drivers/firmware/raspberrypi.c | 41 +++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 39 insertions(+), 2 deletions(-)
+
+--- a/drivers/firmware/raspberrypi.c
++++ b/drivers/firmware/raspberrypi.c
+@@ -28,6 +28,8 @@ struct rpi_firmware {
+ u32 enabled;
+ };
+
++static struct platform_device *g_pdev;
++
+ static DEFINE_MUTEX(transaction_lock);
+
+ static void response_callback(struct mbox_client *cl, void *msg)
+@@ -183,6 +185,25 @@ rpi_firmware_print_firmware_revision(str
+ }
+ }
+
++static int raspberrypi_firmware_set_power(struct rpi_firmware *fw,
++ u32 domain, bool on)
++{
++ struct {
++ u32 domain;
++ u32 on;
++ } packet;
++ int ret;
++
++ packet.domain = domain;
++ packet.on = on;
++ ret = rpi_firmware_property(fw, RPI_FIRMWARE_SET_POWER_STATE,
++ &packet, sizeof(packet));
++ if (!ret && packet.on != on)
++ ret = -EINVAL;
++
++ return ret;
++}
++
+ static int rpi_firmware_probe(struct platform_device *pdev)
+ {
+ struct device *dev = &pdev->dev;
+@@ -207,9 +228,13 @@ static int rpi_firmware_probe(struct pla
+ init_completion(&fw->c);
+
+ platform_set_drvdata(pdev, fw);
++ g_pdev = pdev;
+
+ rpi_firmware_print_firmware_revision(fw);
+
++ if (raspberrypi_firmware_set_power(fw, 3, true))
++ dev_err(dev, "failed to turn on USB power\n");
++
+ return 0;
+ }
+
+@@ -218,6 +243,7 @@ static int rpi_firmware_remove(struct pl
+ struct rpi_firmware *fw = platform_get_drvdata(pdev);
+
+ mbox_free_channel(fw->chan);
++ g_pdev = NULL;
+
+ return 0;
+ }
+@@ -230,7 +256,7 @@ static int rpi_firmware_remove(struct pl
+ */
+ struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node)
+ {
+- struct platform_device *pdev = of_find_device_by_node(firmware_node);
++ struct platform_device *pdev = g_pdev;
+
+ if (!pdev)
+ return NULL;
+@@ -253,7 +279,18 @@ static struct platform_driver rpi_firmwa
+ .probe = rpi_firmware_probe,
+ .remove = rpi_firmware_remove,
+ };
+-module_platform_driver(rpi_firmware_driver);
++
++static int __init rpi_firmware_init(void)
++{
++ return platform_driver_register(&rpi_firmware_driver);
++}
++subsys_initcall(rpi_firmware_init);
++
++static void __init rpi_firmware_exit(void)
++{
++ platform_driver_unregister(&rpi_firmware_driver);
++}
++module_exit(rpi_firmware_exit);
+
+ MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
+ MODULE_DESCRIPTION("Raspberry Pi firmware driver");
diff --git a/target/linux/brcm2708/patches-4.4/0048-bcm2835-add-v4l2-camera-device.patch b/target/linux/brcm2708/patches-4.4/0048-bcm2835-add-v4l2-camera-device.patch
new file mode 100644
index 0000000000..8080b17b58
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0048-bcm2835-add-v4l2-camera-device.patch
@@ -0,0 +1,7338 @@
+From 47ada5db4dbd8a4dd751bbd630d4abbd15131c98 Mon Sep 17 00:00:00 2001
+From: Vincent Sanders <vincent.sanders@collabora.co.uk>
+Date: Wed, 30 Jan 2013 12:45:18 +0000
+Subject: [PATCH 048/381] bcm2835: add v4l2 camera device
+
+- Supports raw YUV capture, preview, JPEG and H264.
+- Uses videobuf2 for data transfer, using dma_buf.
+- Uses 3.6.10 timestamping
+- Camera power based on use
+- Uses immutable input mode on video encoder
+
+Signed-off-by: Daniel Stone <daniels@collabora.com>
+Signed-off-by: Luke Diamand <luked@broadcom.com>
+
+V4L2: Fixes from 6by9
+
+V4L2: Fix EV values. Add manual shutter speed control
+
+V4L2 EV values should be in units of 1/1000. Corrected.
+Add support for V4L2_CID_EXPOSURE_ABSOLUTE which should
+give manual shutter control. Requires manual exposure mode
+to be selected first.
+
+Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
+
+V4L2: Correct JPEG Q-factor range
+
+Should be 1-100, not 0-100
+
+Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
+
+V4L2: Fix issue of driver jamming if STREAMON failed.
+
+Fix issue where the driver was left in a partially enabled
+state if STREAMON failed, and would then reject many IOCTLs
+as it thought it was streaming.
+
+Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
+
+V4L2: Fix ISO controls.
+
+Driver was passing the index to the GPU, and not the desired
+ISO value.
+
+Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
+
+V4L2: Add flicker avoidance controls
+
+Add support for V4L2_CID_POWER_LINE_FREQUENCY to set flicker
+avoidance frequencies.
+
+Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
+
+V4L2: Add support for frame rate control.
+
+Add support for frame rate (or time per frame as V4L2
+inverts it) control via s_parm.
+
+Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
+
+V4L2: Improve G_FBUF handling so we pass conformance
+
+Return some sane numbers for get framebuffer so that
+we pass conformance.
+
+Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
+
+V4L2: Fix information advertised through g_vidfmt
+
+Width and height were being stored based on incorrect
+values.
+
+Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
+
+V4L2: Add support for inline H264 headers
+
+Add support for V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER
+to control H264 inline headers.
+Requires firmware fix to work correctly, otherwise format
+has to be set to H264 before this parameter is set.
+
+Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
+
+V4L2: Fix JPEG timestamp issue
+
+JPEG images were coming through from the GPU with timestamp
+of 0. Detect this and give current system time instead
+of some invalid value.
+
+Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
+
+V4L2: Fix issue when switching down JPEG resolution.
+
+JPEG buffer size calculation is based on input resolution.
+Input resolution was being configured after output port
+format. Caused failures if switching from one JPEG resolution
+to a smaller one.
+
+Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
+
+V4L2: Enable MJPEG encoding
+
+Requires GPU firmware update to support MJPEG encoder.
+
+Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
+
+V4L2: Correct flag settings for compressed formats
+
+Set flags field correctly on enum_fmt_vid_cap for compressed
+image formats.
+
+Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
+
+V4L2: H264 profile & level ctrls, FPS control and auto exp pri
+
+Several control handling updates.
+H264 profile and level controls.
+Timeperframe/FPS reworked to add V4L2_CID_EXPOSURE_AUTO_PRIORITY to
+select whether AE is allowed to override the framerate specified.
+
+Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
+
+V4L2: Correct BGR24 to RGB24 in format table
+
+Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
+
+V4L2: Add additional pixel formats. Correct colourspace
+
+Adds the other flavours of YUYV, and NV12.
+Corrects the overlay advertised colourspace.
+
+Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
+
+V4L2: Drop logging msg from info to debug
+
+Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
+
+V4L2: Initial pass at scene modes.
+
+Only supports exposure mode and metering modes.
+
+Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
+
+V4L2: Add manual white balance control.
+
+Adds support for V4L2_CID_RED_BALANCE and
+V4L2_CID_BLUE_BALANCE. Only has an effect if
+V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE has
+V4L2_WHITE_BALANCE_MANUAL selected.
+
+Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
+
+config: Enable V4L / MMAL driver
+
+V4L2: Increase the MMAL timeout to 3sec
+
+MJPEG codec flush is now taking longer and results
+in a kernel panic if the driver has stopped waiting for
+the result when it finally completes.
+Increase the timeout value from 1 to 3secs.
+
+Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
+
+V4L2: Add support for setting H264_I_PERIOD
+
+Adds support for the parameter V4L2_CID_MPEG_VIDEO_H264_I_PERIOD
+to set the frequency with which I frames are produced.
+
+Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
+
+V4L2: Enable GPU function for removing padding from images.
+
+GPU can now support arbitrary strides, although may require
+additional processing to achieve it. Enable this feature
+so that the images delivered are the size requested.
+
+Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
+
+V4L2: Add support for V4L2_PIX_FMT_BGR32
+
+Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
+
+V4L2: Set the colourspace to avoid odd YUV-RGB conversions
+
+Removes the amiguity from the conversion routines and stops
+them dropping back to the SD vs HD choice of coeffs.
+
+Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
+
+V4L2: Make video/still threshold a run-time param
+
+Move the define for at what resolution the driver
+switches from a video mode capture to a stills mode
+capture to module parameters.
+
+Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
+
+V4L2: Fix incorrect pool sizing
+
+Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
+
+V4L2: Add option to disable enum_framesizes.
+
+Gstreamer's handling of a driver that advertises
+V4L2_FRMSIZE_TYPE_STEPWISE to define the supported
+resolutions is broken. See bug
+https://bugzilla.gnome.org/show_bug.cgi?id=726521
+
+Optional parameter of gst_v4l2src_is_broken added.
+If non-zero, the driver claims not to support that
+ioctl, and gstreamer should be happy again (it
+guesses a set of defaults for itself).
+
+Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
+
+V4L2: Add support for more image formats
+
+Adds YVU420 (YV12), YVU420SP (NV21), and BGR888.
+
+Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
+
+V4L2: Extend range for V4L2_CID_MPEG_VIDEO_H264_I_PERIOD
+
+Request to extend the range from the fairly arbitrary
+1000 frames (33 seconds at 30fps). Extend out to the
+max range supported (int32 value).
+Also allow 0, which is handled by the codec as only
+send an I-frame on the first frame and never again.
+There may be an exception if it detects a significant
+scene change, but there's no easy way around that.
+
+Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
+
+bcm2835-camera: stop_streaming now has a void return
+
+BCM2835-V4L2: Fix compliance test failures
+
+VIDIOC_TRY_FMT and VIDIOC_S_FMT tests were faling due
+to reporting V4L2_COLORSPACE_JPEG when the colour
+format wasn't V4L2_PIX_FMT_JPEG.
+Now reports V4L2_COLORSPACE_SMPTE170M for YUV formats.
+
+bcm2835 camera planar/packed stride length
+
+Added a field to the mmal_fmt struct used to compute the bytes per line
+when using a particular format. This results in the correct stride being
+calculated even when the format is planar.
+
+Signed-off-by: Garrett Wilson <g@floft.net>
+
+bcm2835: camera: check for scene not being found
+
+static analysis by cppcheck detected some potential NULL pointer
+dereference issues:
+
+[drivers/media/platform/bcm2835/controls.c:854]: (error) Possible null
+ pointer dereference: scene
+ (and lines 858, 859 too)
+
+it is possible that scene is not found because of an invalue ctrl->val
+and is therefore NULL and hence causing a null pointer dereference.
+
+Signed-off-by: Colin Ian King <colin.king@canonical.com>
+
+bcm2835: memcpy port data to m rather than rmsg
+
+static analysis by cppcheck detected a memcpy to rmsg which is
+not actually initialized at that point. The memcpy should be copying
+to variable m instead.
+
+Signed-off-by: Colin Ian King <colin.king@canonical.com>
+
+BCM2835-V4L2: Return buffers to videobuf2 on shutdown
+
+https://github.com/raspberrypi/linux/issues/817
+Fixes the kernel warning from videobuf2 as buffers
+are now returned as they are being flushed on
+stop_streaming.
+
+squash: Fixup bcm2835-camera for changes in kernel 4.4 api
+---
+ Documentation/video4linux/bcm2835-v4l2.txt | 60 +
+ drivers/media/platform/Kconfig | 2 +
+ drivers/media/platform/Makefile | 2 +
+ drivers/media/platform/bcm2835/Kconfig | 25 +
+ drivers/media/platform/bcm2835/Makefile | 5 +
+ drivers/media/platform/bcm2835/bcm2835-camera.c | 1844 +++++++++++++++++++++
+ drivers/media/platform/bcm2835/bcm2835-camera.h | 126 ++
+ drivers/media/platform/bcm2835/controls.c | 1324 +++++++++++++++
+ drivers/media/platform/bcm2835/mmal-common.h | 53 +
+ drivers/media/platform/bcm2835/mmal-encodings.h | 127 ++
+ drivers/media/platform/bcm2835/mmal-msg-common.h | 50 +
+ drivers/media/platform/bcm2835/mmal-msg-format.h | 81 +
+ drivers/media/platform/bcm2835/mmal-msg-port.h | 107 ++
+ drivers/media/platform/bcm2835/mmal-msg.h | 404 +++++
+ drivers/media/platform/bcm2835/mmal-parameters.h | 656 ++++++++
+ drivers/media/platform/bcm2835/mmal-vchiq.c | 1916 ++++++++++++++++++++++
+ drivers/media/platform/bcm2835/mmal-vchiq.h | 178 ++
+ 17 files changed, 6960 insertions(+)
+ create mode 100644 Documentation/video4linux/bcm2835-v4l2.txt
+ create mode 100644 drivers/media/platform/bcm2835/Kconfig
+ create mode 100644 drivers/media/platform/bcm2835/Makefile
+ create mode 100644 drivers/media/platform/bcm2835/bcm2835-camera.c
+ create mode 100644 drivers/media/platform/bcm2835/bcm2835-camera.h
+ create mode 100644 drivers/media/platform/bcm2835/controls.c
+ create mode 100644 drivers/media/platform/bcm2835/mmal-common.h
+ create mode 100644 drivers/media/platform/bcm2835/mmal-encodings.h
+ create mode 100644 drivers/media/platform/bcm2835/mmal-msg-common.h
+ create mode 100644 drivers/media/platform/bcm2835/mmal-msg-format.h
+ create mode 100644 drivers/media/platform/bcm2835/mmal-msg-port.h
+ create mode 100644 drivers/media/platform/bcm2835/mmal-msg.h
+ create mode 100644 drivers/media/platform/bcm2835/mmal-parameters.h
+ create mode 100644 drivers/media/platform/bcm2835/mmal-vchiq.c
+ create mode 100644 drivers/media/platform/bcm2835/mmal-vchiq.h
+
+--- /dev/null
++++ b/Documentation/video4linux/bcm2835-v4l2.txt
+@@ -0,0 +1,60 @@
++
++BCM2835 (aka Raspberry Pi) V4L2 driver
++======================================
++
++1. Copyright
++============
++
++Copyright © 2013 Raspberry Pi (Trading) Ltd.
++
++2. License
++==========
++
++This program is free software; you can redistribute it and/or modify
++it under the terms of the GNU General Public License as published by
++the Free Software Foundation; either version 2 of the License, or
++(at your option) any later version.
++
++This program is distributed in the hope that it will be useful,
++but WITHOUT ANY WARRANTY; without even the implied warranty of
++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++GNU General Public License for more details.
++
++You should have received a copy of the GNU General Public License
++along with this program; if not, write to the Free Software
++Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++
++3. Quick Start
++==============
++
++You need a version 1.0 or later of v4l2-ctl, available from:
++ git://git.linuxtv.org/v4l-utils.git
++
++$ sudo modprobe bcm2835-v4l2
++
++Turn on the overlay:
++
++$ v4l2-ctl --overlay=1
++
++Turn off the overlay:
++
++$ v4l2-ctl --overlay=0
++
++Set the capture format for video:
++
++$ v4l2-ctl --set-fmt-video=width=1920,height=1088,pixelformat=4
++
++(Note: 1088 not 1080).
++
++Capture:
++
++$ v4l2-ctl --stream-mmap=3 --stream-count=100 --stream-to=somefile.h264
++
++Stills capture:
++
++$ v4l2-ctl --set-fmt-video=width=2592,height=1944,pixelformat=3
++$ v4l2-ctl --stream-mmap=3 --stream-count=1 --stream-to=somefile.jpg
++
++List of available formats:
++
++$ v4l2-ctl --list-formats
+--- a/drivers/media/platform/Kconfig
++++ b/drivers/media/platform/Kconfig
+@@ -11,6 +11,8 @@ menuconfig V4L_PLATFORM_DRIVERS
+
+ if V4L_PLATFORM_DRIVERS
+
++source "drivers/media/platform/bcm2835/Kconfig"
++
+ source "drivers/media/platform/marvell-ccic/Kconfig"
+
+ config VIDEO_VIA_CAMERA
+--- a/drivers/media/platform/Makefile
++++ b/drivers/media/platform/Makefile
+@@ -2,6 +2,8 @@
+ # Makefile for the video capture/playback device drivers.
+ #
+
++obj-$(CONFIG_VIDEO_BCM2835) += bcm2835/
++
+ obj-$(CONFIG_VIDEO_TIMBERDALE) += timblogiw.o
+ obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
+
+--- /dev/null
++++ b/drivers/media/platform/bcm2835/Kconfig
+@@ -0,0 +1,25 @@
++# Broadcom VideoCore IV v4l2 camera support
++
++config VIDEO_BCM2835
++ bool "Broadcom BCM2835 camera interface driver"
++ depends on VIDEO_V4L2 && (ARCH_BCM2708 || ARCH_BCM2709 || ARCH_BCM2835)
++ ---help---
++ Say Y here to enable camera host interface devices for
++ Broadcom BCM2835 SoC. This operates over the VCHIQ interface
++ to a service running on VideoCore.
++
++
++if VIDEO_BCM2835
++
++config VIDEO_BCM2835_MMAL
++ tristate "Broadcom BM2835 MMAL camera interface driver"
++ depends on BCM2708_VCHIQ
++ select VIDEOBUF2_VMALLOC
++ ---help---
++ This is a V4L2 driver for the Broadcom BCM2835 MMAL camera host interface
++
++ To compile this driver as a module, choose M here: the
++ module will be called bcm2835-v4l2.o
++
++
++endif # VIDEO_BM2835
+--- /dev/null
++++ b/drivers/media/platform/bcm2835/Makefile
+@@ -0,0 +1,5 @@
++bcm2835-v4l2-objs := bcm2835-camera.o controls.o mmal-vchiq.o
++
++obj-$(CONFIG_VIDEO_BCM2835_MMAL) += bcm2835-v4l2.o
++
++ccflags-$(CONFIG_VIDEO_BCM2835) += -Idrivers/misc/vc04_services -Idrivers/misc/vc04_services/interface/vcos/linuxkernel -D__VCCOREVER__=0x04000000
+--- /dev/null
++++ b/drivers/media/platform/bcm2835/bcm2835-camera.c
+@@ -0,0 +1,1844 @@
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file COPYING in the main directory of this archive
++ * for more details.
++ *
++ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
++ * Dave Stevenson <dsteve@broadcom.com>
++ * Simon Mellor <simellor@broadcom.com>
++ * Luke Diamand <luked@broadcom.com>
++ */
++
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <media/videobuf2-vmalloc.h>
++#include <media/videobuf2-dma-contig.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-ioctl.h>
++#include <media/v4l2-ctrls.h>
++#include <media/v4l2-fh.h>
++#include <media/v4l2-event.h>
++#include <media/v4l2-common.h>
++#include <linux/delay.h>
++
++#include "mmal-common.h"
++#include "mmal-encodings.h"
++#include "mmal-vchiq.h"
++#include "mmal-msg.h"
++#include "mmal-parameters.h"
++#include "bcm2835-camera.h"
++
++#define BM2835_MMAL_VERSION "0.0.2"
++#define BM2835_MMAL_MODULE_NAME "bcm2835-v4l2"
++#define MIN_WIDTH 16
++#define MIN_HEIGHT 16
++#define MAX_WIDTH 2592
++#define MAX_HEIGHT 1944
++#define MIN_BUFFER_SIZE (80*1024)
++
++#define MAX_VIDEO_MODE_WIDTH 1280
++#define MAX_VIDEO_MODE_HEIGHT 720
++
++MODULE_DESCRIPTION("Broadcom 2835 MMAL video capture");
++MODULE_AUTHOR("Vincent Sanders");
++MODULE_LICENSE("GPL");
++MODULE_VERSION(BM2835_MMAL_VERSION);
++
++int bcm2835_v4l2_debug;
++module_param_named(debug, bcm2835_v4l2_debug, int, 0644);
++MODULE_PARM_DESC(bcm2835_v4l2_debug, "Debug level 0-2");
++
++int max_video_width = MAX_VIDEO_MODE_WIDTH;
++int max_video_height = MAX_VIDEO_MODE_HEIGHT;
++module_param(max_video_width, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
++MODULE_PARM_DESC(max_video_width, "Threshold for video mode");
++module_param(max_video_height, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
++MODULE_PARM_DESC(max_video_height, "Threshold for video mode");
++
++/* Gstreamer bug https://bugzilla.gnome.org/show_bug.cgi?id=726521
++ * v4l2src does bad (and actually wrong) things when the vidioc_enum_framesizes
++ * function says type V4L2_FRMSIZE_TYPE_STEPWISE, which we do by default.
++ * It's happier if we just don't say anything at all, when it then
++ * sets up a load of defaults that it thinks might work.
++ * If gst_v4l2src_is_broken is non-zero, then we remove the function from
++ * our function table list (actually switch to an alternate set, but same
++ * result).
++ */
++int gst_v4l2src_is_broken = 0;
++module_param(gst_v4l2src_is_broken, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
++MODULE_PARM_DESC(gst_v4l2src_is_broken, "If non-zero, enable workaround for Gstreamer");
++
++static struct bm2835_mmal_dev *gdev; /* global device data */
++
++#define FPS_MIN 1
++#define FPS_MAX 90
++
++/* timeperframe: min/max and default */
++static const struct v4l2_fract
++ tpf_min = {.numerator = 1, .denominator = FPS_MAX},
++ tpf_max = {.numerator = 1, .denominator = FPS_MIN},
++ tpf_default = {.numerator = 1000, .denominator = 30000};
++
++/* video formats */
++static struct mmal_fmt formats[] = {
++ {
++ .name = "4:2:0, planar, YUV",
++ .fourcc = V4L2_PIX_FMT_YUV420,
++ .flags = 0,
++ .mmal = MMAL_ENCODING_I420,
++ .depth = 12,
++ .mmal_component = MMAL_COMPONENT_CAMERA,
++ .ybbp = 1,
++ },
++ {
++ .name = "4:2:2, packed, YUYV",
++ .fourcc = V4L2_PIX_FMT_YUYV,
++ .flags = 0,
++ .mmal = MMAL_ENCODING_YUYV,
++ .depth = 16,
++ .mmal_component = MMAL_COMPONENT_CAMERA,
++ .ybbp = 2,
++ },
++ {
++ .name = "RGB24 (LE)",
++ .fourcc = V4L2_PIX_FMT_RGB24,
++ .flags = 0,
++ .mmal = MMAL_ENCODING_BGR24,
++ .depth = 24,
++ .mmal_component = MMAL_COMPONENT_CAMERA,
++ .ybbp = 3,
++ },
++ {
++ .name = "JPEG",
++ .fourcc = V4L2_PIX_FMT_JPEG,
++ .flags = V4L2_FMT_FLAG_COMPRESSED,
++ .mmal = MMAL_ENCODING_JPEG,
++ .depth = 8,
++ .mmal_component = MMAL_COMPONENT_IMAGE_ENCODE,
++ .ybbp = 0,
++ },
++ {
++ .name = "H264",
++ .fourcc = V4L2_PIX_FMT_H264,
++ .flags = V4L2_FMT_FLAG_COMPRESSED,
++ .mmal = MMAL_ENCODING_H264,
++ .depth = 8,
++ .mmal_component = MMAL_COMPONENT_VIDEO_ENCODE,
++ .ybbp = 0,
++ },
++ {
++ .name = "MJPEG",
++ .fourcc = V4L2_PIX_FMT_MJPEG,
++ .flags = V4L2_FMT_FLAG_COMPRESSED,
++ .mmal = MMAL_ENCODING_MJPEG,
++ .depth = 8,
++ .mmal_component = MMAL_COMPONENT_VIDEO_ENCODE,
++ .ybbp = 0,
++ },
++ {
++ .name = "4:2:2, packed, YVYU",
++ .fourcc = V4L2_PIX_FMT_YVYU,
++ .flags = 0,
++ .mmal = MMAL_ENCODING_YVYU,
++ .depth = 16,
++ .mmal_component = MMAL_COMPONENT_CAMERA,
++ .ybbp = 2,
++ },
++ {
++ .name = "4:2:2, packed, VYUY",
++ .fourcc = V4L2_PIX_FMT_VYUY,
++ .flags = 0,
++ .mmal = MMAL_ENCODING_VYUY,
++ .depth = 16,
++ .mmal_component = MMAL_COMPONENT_CAMERA,
++ .ybbp = 2,
++ },
++ {
++ .name = "4:2:2, packed, UYVY",
++ .fourcc = V4L2_PIX_FMT_UYVY,
++ .flags = 0,
++ .mmal = MMAL_ENCODING_UYVY,
++ .depth = 16,
++ .mmal_component = MMAL_COMPONENT_CAMERA,
++ .ybbp = 2,
++ },
++ {
++ .name = "4:2:0, planar, NV12",
++ .fourcc = V4L2_PIX_FMT_NV12,
++ .flags = 0,
++ .mmal = MMAL_ENCODING_NV12,
++ .depth = 12,
++ .mmal_component = MMAL_COMPONENT_CAMERA,
++ .ybbp = 1,
++ },
++ {
++ .name = "RGB24 (BE)",
++ .fourcc = V4L2_PIX_FMT_BGR24,
++ .flags = 0,
++ .mmal = MMAL_ENCODING_RGB24,
++ .depth = 24,
++ .mmal_component = MMAL_COMPONENT_CAMERA,
++ .ybbp = 3,
++ },
++ {
++ .name = "4:2:0, planar, YVU",
++ .fourcc = V4L2_PIX_FMT_YVU420,
++ .flags = 0,
++ .mmal = MMAL_ENCODING_YV12,
++ .depth = 12,
++ .mmal_component = MMAL_COMPONENT_CAMERA,
++ .ybbp = 1,
++ },
++ {
++ .name = "4:2:0, planar, NV21",
++ .fourcc = V4L2_PIX_FMT_NV21,
++ .flags = 0,
++ .mmal = MMAL_ENCODING_NV21,
++ .depth = 12,
++ .mmal_component = MMAL_COMPONENT_CAMERA,
++ .ybbp = 1,
++ },
++ {
++ .name = "RGB32 (BE)",
++ .fourcc = V4L2_PIX_FMT_BGR32,
++ .flags = 0,
++ .mmal = MMAL_ENCODING_BGRA,
++ .depth = 32,
++ .mmal_component = MMAL_COMPONENT_CAMERA,
++ .ybbp = 4,
++ },
++};
++
++static struct mmal_fmt *get_format(struct v4l2_format *f)
++{
++ struct mmal_fmt *fmt;
++ unsigned int k;
++
++ for (k = 0; k < ARRAY_SIZE(formats); k++) {
++ fmt = &formats[k];
++ if (fmt->fourcc == f->fmt.pix.pixelformat)
++ break;
++ }
++
++ if (k == ARRAY_SIZE(formats))
++ return NULL;
++
++ return &formats[k];
++}
++
++/* ------------------------------------------------------------------
++ Videobuf queue operations
++ ------------------------------------------------------------------*/
++
++static int queue_setup(struct vb2_queue *vq, const void *parg,
++ unsigned int *nbuffers, unsigned int *nplanes,
++ unsigned int sizes[], void *alloc_ctxs[])
++{
++ struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq);
++ unsigned long size;
++
++ /* refuse queue setup if port is not configured */
++ if (dev->capture.port == NULL) {
++ v4l2_err(&dev->v4l2_dev,
++ "%s: capture port not configured\n", __func__);
++ return -EINVAL;
++ }
++
++ size = dev->capture.port->current_buffer.size;
++ if (size == 0) {
++ v4l2_err(&dev->v4l2_dev,
++ "%s: capture port buffer size is zero\n", __func__);
++ return -EINVAL;
++ }
++
++ if (*nbuffers < (dev->capture.port->current_buffer.num + 2))
++ *nbuffers = (dev->capture.port->current_buffer.num + 2);
++
++ *nplanes = 1;
++
++ sizes[0] = size;
++
++ /*
++ * videobuf2-vmalloc allocator is context-less so no need to set
++ * alloc_ctxs array.
++ */
++
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p\n",
++ __func__, dev);
++
++ return 0;
++}
++
++static int buffer_prepare(struct vb2_buffer *vb)
++{
++ struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
++ unsigned long size;
++
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p\n",
++ __func__, dev);
++
++ BUG_ON(dev->capture.port == NULL);
++ BUG_ON(dev->capture.fmt == NULL);
++
++ size = dev->capture.stride * dev->capture.height;
++ if (vb2_plane_size(vb, 0) < size) {
++ v4l2_err(&dev->v4l2_dev,
++ "%s data will not fit into plane (%lu < %lu)\n",
++ __func__, vb2_plane_size(vb, 0), size);
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static inline bool is_capturing(struct bm2835_mmal_dev *dev)
++{
++ return dev->capture.camera_port ==
++ &dev->
++ component[MMAL_COMPONENT_CAMERA]->output[MMAL_CAMERA_PORT_CAPTURE];
++}
++
++static void buffer_cb(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ int status,
++ struct mmal_buffer *buf,
++ unsigned long length, u32 mmal_flags, s64 dts, s64 pts)
++{
++ struct bm2835_mmal_dev *dev = port->cb_ctx;
++
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "%s: status:%d, buf:%p, length:%lu, flags %u, pts %lld\n",
++ __func__, status, buf, length, mmal_flags, pts);
++
++ if (status != 0) {
++ /* error in transfer */
++ if (buf != NULL) {
++ /* there was a buffer with the error so return it */
++ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
++ }
++ return;
++ } else if (length == 0) {
++ /* stream ended */
++ if (buf != NULL) {
++ /* this should only ever happen if the port is
++ * disabled and there are buffers still queued
++ */
++ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
++ pr_debug("Empty buffer");
++ } else if (dev->capture.frame_count) {
++ /* grab another frame */
++ if (is_capturing(dev)) {
++ pr_debug("Grab another frame");
++ vchiq_mmal_port_parameter_set(
++ instance,
++ dev->capture.
++ camera_port,
++ MMAL_PARAMETER_CAPTURE,
++ &dev->capture.
++ frame_count,
++ sizeof(dev->capture.frame_count));
++ }
++ } else {
++ /* signal frame completion */
++ complete(&dev->capture.frame_cmplt);
++ }
++ } else {
++ if (dev->capture.frame_count) {
++ if (dev->capture.vc_start_timestamp != -1 &&
++ pts != 0) {
++ s64 runtime_us = pts -
++ dev->capture.vc_start_timestamp;
++ u32 div = 0;
++ u32 rem = 0;
++
++ div =
++ div_u64_rem(runtime_us, USEC_PER_SEC, &rem);
++ buf->vb.timestamp.tv_sec =
++ dev->capture.kernel_start_ts.tv_sec - 1 +
++ div;
++ buf->vb.timestamp.tv_usec =
++ dev->capture.kernel_start_ts.tv_usec + rem;
++
++ if (buf->vb.timestamp.tv_usec >=
++ USEC_PER_SEC) {
++ buf->vb.timestamp.tv_sec++;
++ buf->vb.timestamp.tv_usec -=
++ USEC_PER_SEC;
++ }
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "Convert start time %d.%06d and %llu "
++ "with offset %llu to %d.%06d\n",
++ (int)dev->capture.kernel_start_ts.
++ tv_sec,
++ (int)dev->capture.kernel_start_ts.
++ tv_usec,
++ dev->capture.vc_start_timestamp, pts,
++ (int)buf->vb.timestamp.tv_sec,
++ (int)buf->vb.timestamp.
++ tv_usec);
++ } else {
++ v4l2_get_timestamp(&buf->vb.timestamp);
++ }
++
++ vb2_set_plane_payload(&buf->vb.vb2_buf, 0, length);
++ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
++
++ if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS &&
++ is_capturing(dev)) {
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "Grab another frame as buffer has EOS");
++ vchiq_mmal_port_parameter_set(
++ instance,
++ dev->capture.
++ camera_port,
++ MMAL_PARAMETER_CAPTURE,
++ &dev->capture.
++ frame_count,
++ sizeof(dev->capture.frame_count));
++ }
++ } else {
++ /* signal frame completion */
++ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
++ complete(&dev->capture.frame_cmplt);
++ }
++ }
++}
++
++static int enable_camera(struct bm2835_mmal_dev *dev)
++{
++ int ret;
++ if (!dev->camera_use_count) {
++ ret = vchiq_mmal_component_enable(
++ dev->instance,
++ dev->component[MMAL_COMPONENT_CAMERA]);
++ if (ret < 0) {
++ v4l2_err(&dev->v4l2_dev,
++ "Failed enabling camera, ret %d\n", ret);
++ return -EINVAL;
++ }
++ }
++ dev->camera_use_count++;
++ v4l2_dbg(1, bcm2835_v4l2_debug,
++ &dev->v4l2_dev, "enabled camera (refcount %d)\n",
++ dev->camera_use_count);
++ return 0;
++}
++
++static int disable_camera(struct bm2835_mmal_dev *dev)
++{
++ int ret;
++ if (!dev->camera_use_count) {
++ v4l2_err(&dev->v4l2_dev,
++ "Disabled the camera when already disabled\n");
++ return -EINVAL;
++ }
++ dev->camera_use_count--;
++ if (!dev->camera_use_count) {
++ unsigned int i = 0xFFFFFFFF;
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "Disabling camera\n");
++ ret =
++ vchiq_mmal_component_disable(
++ dev->instance,
++ dev->component[MMAL_COMPONENT_CAMERA]);
++ if (ret < 0) {
++ v4l2_err(&dev->v4l2_dev,
++ "Failed disabling camera, ret %d\n", ret);
++ return -EINVAL;
++ }
++ vchiq_mmal_port_parameter_set(
++ dev->instance,
++ &dev->component[MMAL_COMPONENT_CAMERA]->control,
++ MMAL_PARAMETER_CAMERA_NUM, &i,
++ sizeof(i));
++ }
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "Camera refcount now %d\n", dev->camera_use_count);
++ return 0;
++}
++
++static void buffer_queue(struct vb2_buffer *vb)
++{
++ struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
++ struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb);
++ struct mmal_buffer *buf = container_of(vb2, struct mmal_buffer, vb);
++ int ret;
++
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "%s: dev:%p buf:%p\n", __func__, dev, buf);
++
++ buf->buffer = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
++ buf->buffer_size = vb2_plane_size(&buf->vb.vb2_buf, 0);
++
++ ret = vchiq_mmal_submit_buffer(dev->instance, dev->capture.port, buf);
++ if (ret < 0)
++ v4l2_err(&dev->v4l2_dev, "%s: error submitting buffer\n",
++ __func__);
++}
++
++static int start_streaming(struct vb2_queue *vq, unsigned int count)
++{
++ struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq);
++ int ret;
++ int parameter_size;
++
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p\n",
++ __func__, dev);
++
++ /* ensure a format has actually been set */
++ if (dev->capture.port == NULL)
++ return -EINVAL;
++
++ if (enable_camera(dev) < 0) {
++ v4l2_err(&dev->v4l2_dev, "Failed to enable camera\n");
++ return -EINVAL;
++ }
++
++ /*init_completion(&dev->capture.frame_cmplt); */
++
++ /* enable frame capture */
++ dev->capture.frame_count = 1;
++
++ /* if the preview is not already running, wait for a few frames for AGC
++ * to settle down.
++ */
++ if (!dev->component[MMAL_COMPONENT_PREVIEW]->enabled)
++ msleep(300);
++
++ /* enable the connection from camera to encoder (if applicable) */
++ if (dev->capture.camera_port != dev->capture.port
++ && dev->capture.camera_port) {
++ ret = vchiq_mmal_port_enable(dev->instance,
++ dev->capture.camera_port, NULL);
++ if (ret) {
++ v4l2_err(&dev->v4l2_dev,
++ "Failed to enable encode tunnel - error %d\n",
++ ret);
++ return -1;
++ }
++ }
++
++ /* Get VC timestamp at this point in time */
++ parameter_size = sizeof(dev->capture.vc_start_timestamp);
++ if (vchiq_mmal_port_parameter_get(dev->instance,
++ dev->capture.camera_port,
++ MMAL_PARAMETER_SYSTEM_TIME,
++ &dev->capture.vc_start_timestamp,
++ &parameter_size)) {
++ v4l2_err(&dev->v4l2_dev,
++ "Failed to get VC start time - update your VC f/w\n");
++
++ /* Flag to indicate just to rely on kernel timestamps */
++ dev->capture.vc_start_timestamp = -1;
++ } else
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "Start time %lld size %d\n",
++ dev->capture.vc_start_timestamp, parameter_size);
++
++ v4l2_get_timestamp(&dev->capture.kernel_start_ts);
++
++ /* enable the camera port */
++ dev->capture.port->cb_ctx = dev;
++ ret =
++ vchiq_mmal_port_enable(dev->instance, dev->capture.port, buffer_cb);
++ if (ret) {
++ v4l2_err(&dev->v4l2_dev,
++ "Failed to enable capture port - error %d. "
++ "Disabling camera port again\n", ret);
++
++ vchiq_mmal_port_disable(dev->instance,
++ dev->capture.camera_port);
++ if (disable_camera(dev) < 0) {
++ v4l2_err(&dev->v4l2_dev, "Failed to disable camera\n");
++ return -EINVAL;
++ }
++ return -1;
++ }
++
++ /* capture the first frame */
++ vchiq_mmal_port_parameter_set(dev->instance,
++ dev->capture.camera_port,
++ MMAL_PARAMETER_CAPTURE,
++ &dev->capture.frame_count,
++ sizeof(dev->capture.frame_count));
++ return 0;
++}
++
++/* abort streaming and wait for last buffer */
++static void stop_streaming(struct vb2_queue *vq)
++{
++ int ret;
++ struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq);
++
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p\n",
++ __func__, dev);
++
++ init_completion(&dev->capture.frame_cmplt);
++ dev->capture.frame_count = 0;
++
++ /* ensure a format has actually been set */
++ if (dev->capture.port == NULL) {
++ v4l2_err(&dev->v4l2_dev,
++ "no capture port - stream not started?\n");
++ return;
++ }
++
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "stopping capturing\n");
++
++ /* stop capturing frames */
++ vchiq_mmal_port_parameter_set(dev->instance,
++ dev->capture.camera_port,
++ MMAL_PARAMETER_CAPTURE,
++ &dev->capture.frame_count,
++ sizeof(dev->capture.frame_count));
++
++ /* wait for last frame to complete */
++ ret = wait_for_completion_timeout(&dev->capture.frame_cmplt, HZ);
++ if (ret <= 0)
++ v4l2_err(&dev->v4l2_dev,
++ "error %d waiting for frame completion\n", ret);
++
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "disabling connection\n");
++
++ /* disable the connection from camera to encoder */
++ ret = vchiq_mmal_port_disable(dev->instance, dev->capture.camera_port);
++ if (!ret && dev->capture.camera_port != dev->capture.port) {
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "disabling port\n");
++ ret = vchiq_mmal_port_disable(dev->instance, dev->capture.port);
++ } else if (dev->capture.camera_port != dev->capture.port) {
++ v4l2_err(&dev->v4l2_dev, "port_disable failed, error %d\n",
++ ret);
++ }
++
++ if (disable_camera(dev) < 0)
++ v4l2_err(&dev->v4l2_dev, "Failed to disable camera\n");
++}
++
++static void bm2835_mmal_lock(struct vb2_queue *vq)
++{
++ struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq);
++ mutex_lock(&dev->mutex);
++}
++
++static void bm2835_mmal_unlock(struct vb2_queue *vq)
++{
++ struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq);
++ mutex_unlock(&dev->mutex);
++}
++
++static struct vb2_ops bm2835_mmal_video_qops = {
++ .queue_setup = queue_setup,
++ .buf_prepare = buffer_prepare,
++ .buf_queue = buffer_queue,
++ .start_streaming = start_streaming,
++ .stop_streaming = stop_streaming,
++ .wait_prepare = bm2835_mmal_unlock,
++ .wait_finish = bm2835_mmal_lock,
++};
++
++/* ------------------------------------------------------------------
++ IOCTL operations
++ ------------------------------------------------------------------*/
++
++/* overlay ioctl */
++static int vidioc_enum_fmt_vid_overlay(struct file *file, void *priv,
++ struct v4l2_fmtdesc *f)
++{
++ struct mmal_fmt *fmt;
++
++ if (f->index >= ARRAY_SIZE(formats))
++ return -EINVAL;
++
++ fmt = &formats[f->index];
++
++ strlcpy(f->description, fmt->name, sizeof(f->description));
++ f->pixelformat = fmt->fourcc;
++ f->flags = fmt->flags;
++
++ return 0;
++}
++
++static int vidioc_g_fmt_vid_overlay(struct file *file, void *priv,
++ struct v4l2_format *f)
++{
++ struct bm2835_mmal_dev *dev = video_drvdata(file);
++
++ f->fmt.win = dev->overlay;
++
++ return 0;
++}
++
++static int vidioc_try_fmt_vid_overlay(struct file *file, void *priv,
++ struct v4l2_format *f)
++{
++ /* Only support one format so get the current one. */
++ vidioc_g_fmt_vid_overlay(file, priv, f);
++
++ /* todo: allow the size and/or offset to be changed. */
++ return 0;
++}
++
++static int vidioc_s_fmt_vid_overlay(struct file *file, void *priv,
++ struct v4l2_format *f)
++{
++ struct bm2835_mmal_dev *dev = video_drvdata(file);
++
++ vidioc_try_fmt_vid_overlay(file, priv, f);
++
++ dev->overlay = f->fmt.win;
++
++ /* todo: program the preview port parameters */
++ return 0;
++}
++
++static int vidioc_overlay(struct file *file, void *f, unsigned int on)
++{
++ int ret;
++ struct bm2835_mmal_dev *dev = video_drvdata(file);
++ struct vchiq_mmal_port *src;
++ struct vchiq_mmal_port *dst;
++ struct mmal_parameter_displayregion prev_config = {
++ .set = MMAL_DISPLAY_SET_LAYER | MMAL_DISPLAY_SET_ALPHA |
++ MMAL_DISPLAY_SET_DEST_RECT | MMAL_DISPLAY_SET_FULLSCREEN,
++ .layer = PREVIEW_LAYER,
++ .alpha = 255,
++ .fullscreen = 0,
++ .dest_rect = {
++ .x = dev->overlay.w.left,
++ .y = dev->overlay.w.top,
++ .width = dev->overlay.w.width,
++ .height = dev->overlay.w.height,
++ },
++ };
++
++ if ((on && dev->component[MMAL_COMPONENT_PREVIEW]->enabled) ||
++ (!on && !dev->component[MMAL_COMPONENT_PREVIEW]->enabled))
++ return 0; /* already in requested state */
++
++ src =
++ &dev->component[MMAL_COMPONENT_CAMERA]->
++ output[MMAL_CAMERA_PORT_PREVIEW];
++
++ if (!on) {
++ /* disconnect preview ports and disable component */
++ ret = vchiq_mmal_port_disable(dev->instance, src);
++ if (!ret)
++ ret =
++ vchiq_mmal_port_connect_tunnel(dev->instance, src,
++ NULL);
++ if (ret >= 0)
++ ret = vchiq_mmal_component_disable(
++ dev->instance,
++ dev->component[MMAL_COMPONENT_PREVIEW]);
++
++ disable_camera(dev);
++ return ret;
++ }
++
++ /* set preview port format and connect it to output */
++ dst = &dev->component[MMAL_COMPONENT_PREVIEW]->input[0];
++
++ ret = vchiq_mmal_port_set_format(dev->instance, src);
++ if (ret < 0)
++ goto error;
++
++ ret = vchiq_mmal_port_parameter_set(dev->instance, dst,
++ MMAL_PARAMETER_DISPLAYREGION,
++ &prev_config, sizeof(prev_config));
++ if (ret < 0)
++ goto error;
++
++ if (enable_camera(dev) < 0)
++ goto error;
++
++ ret = vchiq_mmal_component_enable(
++ dev->instance,
++ dev->component[MMAL_COMPONENT_PREVIEW]);
++ if (ret < 0)
++ goto error;
++
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "connecting %p to %p\n",
++ src, dst);
++ ret = vchiq_mmal_port_connect_tunnel(dev->instance, src, dst);
++ if (!ret)
++ ret = vchiq_mmal_port_enable(dev->instance, src, NULL);
++error:
++ return ret;
++}
++
++static int vidioc_g_fbuf(struct file *file, void *fh,
++ struct v4l2_framebuffer *a)
++{
++ /* The video overlay must stay within the framebuffer and can't be
++ positioned independently. */
++ struct bm2835_mmal_dev *dev = video_drvdata(file);
++ struct vchiq_mmal_port *preview_port =
++ &dev->component[MMAL_COMPONENT_CAMERA]->
++ output[MMAL_CAMERA_PORT_PREVIEW];
++ a->flags = V4L2_FBUF_FLAG_OVERLAY;
++ a->fmt.width = preview_port->es.video.width;
++ a->fmt.height = preview_port->es.video.height;
++ a->fmt.pixelformat = V4L2_PIX_FMT_YUV420;
++ a->fmt.bytesperline = preview_port->es.video.width;
++ a->fmt.sizeimage = (preview_port->es.video.width *
++ preview_port->es.video.height * 3)>>1;
++ a->fmt.colorspace = V4L2_COLORSPACE_SMPTE170M;
++
++ return 0;
++}
++
++/* input ioctls */
++static int vidioc_enum_input(struct file *file, void *priv,
++ struct v4l2_input *inp)
++{
++ /* only a single camera input */
++ if (inp->index != 0)
++ return -EINVAL;
++
++ inp->type = V4L2_INPUT_TYPE_CAMERA;
++ sprintf(inp->name, "Camera %u", inp->index);
++ return 0;
++}
++
++static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
++{
++ *i = 0;
++ return 0;
++}
++
++static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
++{
++ if (i != 0)
++ return -EINVAL;
++
++ return 0;
++}
++
++/* capture ioctls */
++static int vidioc_querycap(struct file *file, void *priv,
++ struct v4l2_capability *cap)
++{
++ struct bm2835_mmal_dev *dev = video_drvdata(file);
++ u32 major;
++ u32 minor;
++
++ vchiq_mmal_version(dev->instance, &major, &minor);
++
++ strcpy(cap->driver, "bm2835 mmal");
++ snprintf(cap->card, sizeof(cap->card), "mmal service %d.%d",
++ major, minor);
++
++ snprintf(cap->bus_info, sizeof(cap->bus_info),
++ "platform:%s", dev->v4l2_dev.name);
++ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY |
++ V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
++ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
++
++ return 0;
++}
++
++static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
++ struct v4l2_fmtdesc *f)
++{
++ struct mmal_fmt *fmt;
++
++ if (f->index >= ARRAY_SIZE(formats))
++ return -EINVAL;
++
++ fmt = &formats[f->index];
++
++ strlcpy(f->description, fmt->name, sizeof(f->description));
++ f->pixelformat = fmt->fourcc;
++ f->flags = fmt->flags;
++
++ return 0;
++}
++
++static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
++ struct v4l2_format *f)
++{
++ struct bm2835_mmal_dev *dev = video_drvdata(file);
++
++ f->fmt.pix.width = dev->capture.width;
++ f->fmt.pix.height = dev->capture.height;
++ f->fmt.pix.field = V4L2_FIELD_NONE;
++ f->fmt.pix.pixelformat = dev->capture.fmt->fourcc;
++ f->fmt.pix.bytesperline = dev->capture.stride;
++ f->fmt.pix.sizeimage = dev->capture.buffersize;
++
++ if (dev->capture.fmt->fourcc == V4L2_PIX_FMT_RGB24)
++ f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
++ else if (dev->capture.fmt->fourcc == V4L2_PIX_FMT_JPEG)
++ f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
++ else
++ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
++ f->fmt.pix.priv = 0;
++
++ v4l2_dump_pix_format(1, bcm2835_v4l2_debug, &dev->v4l2_dev, &f->fmt.pix,
++ __func__);
++ return 0;
++}
++
++static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
++ struct v4l2_format *f)
++{
++ struct bm2835_mmal_dev *dev = video_drvdata(file);
++ struct mmal_fmt *mfmt;
++
++ mfmt = get_format(f);
++ if (!mfmt) {
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "Fourcc format (0x%08x) unknown.\n",
++ f->fmt.pix.pixelformat);
++ f->fmt.pix.pixelformat = formats[0].fourcc;
++ mfmt = get_format(f);
++ }
++
++ f->fmt.pix.field = V4L2_FIELD_NONE;
++
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "Clipping/aligning %dx%d format %08X\n",
++ f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.pixelformat);
++
++ v4l_bound_align_image(&f->fmt.pix.width, MIN_WIDTH, MAX_WIDTH, 1,
++ &f->fmt.pix.height, MIN_HEIGHT, MAX_HEIGHT, 1, 0);
++ f->fmt.pix.bytesperline = f->fmt.pix.width * mfmt->ybbp;
++
++ /* Image buffer has to be padded to allow for alignment, even though
++ * we then remove that padding before delivering the buffer.
++ */
++ f->fmt.pix.sizeimage = ((f->fmt.pix.height+15)&~15) *
++ (((f->fmt.pix.width+31)&~31) * mfmt->depth) >> 3;
++
++ if ((mfmt->flags & V4L2_FMT_FLAG_COMPRESSED) &&
++ f->fmt.pix.sizeimage < MIN_BUFFER_SIZE)
++ f->fmt.pix.sizeimage = MIN_BUFFER_SIZE;
++
++ if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24)
++ f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
++ else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG)
++ f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
++ else
++ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
++ f->fmt.pix.priv = 0;
++
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "Now %dx%d format %08X\n",
++ f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.pixelformat);
++
++ v4l2_dump_pix_format(1, bcm2835_v4l2_debug, &dev->v4l2_dev, &f->fmt.pix,
++ __func__);
++ return 0;
++}
++
++static int mmal_setup_components(struct bm2835_mmal_dev *dev,
++ struct v4l2_format *f)
++{
++ int ret;
++ struct vchiq_mmal_port *port = NULL, *camera_port = NULL;
++ struct vchiq_mmal_component *encode_component = NULL;
++ struct mmal_fmt *mfmt = get_format(f);
++
++ BUG_ON(!mfmt);
++
++ if (dev->capture.encode_component) {
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "vid_cap - disconnect previous tunnel\n");
++
++ /* Disconnect any previous connection */
++ vchiq_mmal_port_connect_tunnel(dev->instance,
++ dev->capture.camera_port, NULL);
++ dev->capture.camera_port = NULL;
++ ret = vchiq_mmal_component_disable(dev->instance,
++ dev->capture.
++ encode_component);
++ if (ret)
++ v4l2_err(&dev->v4l2_dev,
++ "Failed to disable encode component %d\n",
++ ret);
++
++ dev->capture.encode_component = NULL;
++ }
++ /* format dependant port setup */
++ switch (mfmt->mmal_component) {
++ case MMAL_COMPONENT_CAMERA:
++ /* Make a further decision on port based on resolution */
++ if (f->fmt.pix.width <= max_video_width
++ && f->fmt.pix.height <= max_video_height)
++ camera_port = port =
++ &dev->component[MMAL_COMPONENT_CAMERA]->
++ output[MMAL_CAMERA_PORT_VIDEO];
++ else
++ camera_port = port =
++ &dev->component[MMAL_COMPONENT_CAMERA]->
++ output[MMAL_CAMERA_PORT_CAPTURE];
++ break;
++ case MMAL_COMPONENT_IMAGE_ENCODE:
++ encode_component = dev->component[MMAL_COMPONENT_IMAGE_ENCODE];
++ port = &dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->output[0];
++ camera_port =
++ &dev->component[MMAL_COMPONENT_CAMERA]->
++ output[MMAL_CAMERA_PORT_CAPTURE];
++ break;
++ case MMAL_COMPONENT_VIDEO_ENCODE:
++ encode_component = dev->component[MMAL_COMPONENT_VIDEO_ENCODE];
++ port = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
++ camera_port =
++ &dev->component[MMAL_COMPONENT_CAMERA]->
++ output[MMAL_CAMERA_PORT_VIDEO];
++ break;
++ default:
++ break;
++ }
++
++ if (!port)
++ return -EINVAL;
++
++ if (encode_component)
++ camera_port->format.encoding = MMAL_ENCODING_OPAQUE;
++ else
++ camera_port->format.encoding = mfmt->mmal;
++
++ camera_port->format.encoding_variant = 0;
++ camera_port->es.video.width = f->fmt.pix.width;
++ camera_port->es.video.height = f->fmt.pix.height;
++ camera_port->es.video.crop.x = 0;
++ camera_port->es.video.crop.y = 0;
++ camera_port->es.video.crop.width = f->fmt.pix.width;
++ camera_port->es.video.crop.height = f->fmt.pix.height;
++ camera_port->es.video.frame_rate.num = 0;
++ camera_port->es.video.frame_rate.den = 1;
++ camera_port->es.video.color_space = MMAL_COLOR_SPACE_JPEG_JFIF;
++
++ ret = vchiq_mmal_port_set_format(dev->instance, camera_port);
++
++ if (!ret
++ && camera_port ==
++ &dev->component[MMAL_COMPONENT_CAMERA]->
++ output[MMAL_CAMERA_PORT_VIDEO]) {
++ bool overlay_enabled =
++ !!dev->component[MMAL_COMPONENT_PREVIEW]->enabled;
++ struct vchiq_mmal_port *preview_port =
++ &dev->component[MMAL_COMPONENT_CAMERA]->
++ output[MMAL_CAMERA_PORT_PREVIEW];
++ /* Preview and encode ports need to match on resolution */
++ if (overlay_enabled) {
++ /* Need to disable the overlay before we can update
++ * the resolution
++ */
++ ret =
++ vchiq_mmal_port_disable(dev->instance,
++ preview_port);
++ if (!ret)
++ ret =
++ vchiq_mmal_port_connect_tunnel(
++ dev->instance,
++ preview_port,
++ NULL);
++ }
++ preview_port->es.video.width = f->fmt.pix.width;
++ preview_port->es.video.height = f->fmt.pix.height;
++ preview_port->es.video.crop.x = 0;
++ preview_port->es.video.crop.y = 0;
++ preview_port->es.video.crop.width = f->fmt.pix.width;
++ preview_port->es.video.crop.height = f->fmt.pix.height;
++ preview_port->es.video.frame_rate.num =
++ dev->capture.timeperframe.denominator;
++ preview_port->es.video.frame_rate.den =
++ dev->capture.timeperframe.numerator;
++ ret = vchiq_mmal_port_set_format(dev->instance, preview_port);
++ if (overlay_enabled) {
++ ret = vchiq_mmal_port_connect_tunnel(
++ dev->instance,
++ preview_port,
++ &dev->component[MMAL_COMPONENT_PREVIEW]->input[0]);
++ if (!ret)
++ ret = vchiq_mmal_port_enable(dev->instance,
++ preview_port,
++ NULL);
++ }
++ }
++
++ if (ret) {
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "%s failed to set format %dx%d %08X\n", __func__,
++ f->fmt.pix.width, f->fmt.pix.height,
++ f->fmt.pix.pixelformat);
++ /* ensure capture is not going to be tried */
++ dev->capture.port = NULL;
++ } else {
++ if (encode_component) {
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "vid_cap - set up encode comp\n");
++
++ /* configure buffering */
++ camera_port->current_buffer.size =
++ camera_port->recommended_buffer.size;
++ camera_port->current_buffer.num =
++ camera_port->recommended_buffer.num;
++
++ ret =
++ vchiq_mmal_port_connect_tunnel(
++ dev->instance,
++ camera_port,
++ &encode_component->input[0]);
++ if (ret) {
++ v4l2_dbg(1, bcm2835_v4l2_debug,
++ &dev->v4l2_dev,
++ "%s failed to create connection\n",
++ __func__);
++ /* ensure capture is not going to be tried */
++ dev->capture.port = NULL;
++ } else {
++ port->es.video.width = f->fmt.pix.width;
++ port->es.video.height = f->fmt.pix.height;
++ port->es.video.crop.x = 0;
++ port->es.video.crop.y = 0;
++ port->es.video.crop.width = f->fmt.pix.width;
++ port->es.video.crop.height = f->fmt.pix.height;
++ port->es.video.frame_rate.num =
++ dev->capture.timeperframe.denominator;
++ port->es.video.frame_rate.den =
++ dev->capture.timeperframe.numerator;
++
++ port->format.encoding = mfmt->mmal;
++ port->format.encoding_variant = 0;
++ /* Set any encoding specific parameters */
++ switch (mfmt->mmal_component) {
++ case MMAL_COMPONENT_VIDEO_ENCODE:
++ port->format.bitrate =
++ dev->capture.encode_bitrate;
++ break;
++ case MMAL_COMPONENT_IMAGE_ENCODE:
++ /* Could set EXIF parameters here */
++ break;
++ default:
++ break;
++ }
++ ret = vchiq_mmal_port_set_format(dev->instance,
++ port);
++ if (ret)
++ v4l2_dbg(1, bcm2835_v4l2_debug,
++ &dev->v4l2_dev,
++ "%s failed to set format %dx%d fmt %08X\n",
++ __func__,
++ f->fmt.pix.width,
++ f->fmt.pix.height,
++ f->fmt.pix.pixelformat
++ );
++ }
++
++ if (!ret) {
++ ret = vchiq_mmal_component_enable(
++ dev->instance,
++ encode_component);
++ if (ret) {
++ v4l2_dbg(1, bcm2835_v4l2_debug,
++ &dev->v4l2_dev,
++ "%s Failed to enable encode components\n",
++ __func__);
++ }
++ }
++ if (!ret) {
++ /* configure buffering */
++ port->current_buffer.num = 1;
++ port->current_buffer.size =
++ f->fmt.pix.sizeimage;
++ if (port->format.encoding ==
++ MMAL_ENCODING_JPEG) {
++ v4l2_dbg(1, bcm2835_v4l2_debug,
++ &dev->v4l2_dev,
++ "JPG - buf size now %d was %d\n",
++ f->fmt.pix.sizeimage,
++ port->current_buffer.size);
++ port->current_buffer.size =
++ (f->fmt.pix.sizeimage <
++ (100 << 10))
++ ? (100 << 10) : f->fmt.pix.
++ sizeimage;
++ }
++ v4l2_dbg(1, bcm2835_v4l2_debug,
++ &dev->v4l2_dev,
++ "vid_cap - cur_buf.size set to %d\n",
++ f->fmt.pix.sizeimage);
++ port->current_buffer.alignment = 0;
++ }
++ } else {
++ /* configure buffering */
++ camera_port->current_buffer.num = 1;
++ camera_port->current_buffer.size = f->fmt.pix.sizeimage;
++ camera_port->current_buffer.alignment = 0;
++ }
++
++ if (!ret) {
++ dev->capture.fmt = mfmt;
++ dev->capture.stride = f->fmt.pix.bytesperline;
++ dev->capture.width = camera_port->es.video.crop.width;
++ dev->capture.height = camera_port->es.video.crop.height;
++ dev->capture.buffersize = port->current_buffer.size;
++
++ /* select port for capture */
++ dev->capture.port = port;
++ dev->capture.camera_port = camera_port;
++ dev->capture.encode_component = encode_component;
++ v4l2_dbg(1, bcm2835_v4l2_debug,
++ &dev->v4l2_dev,
++ "Set dev->capture.fmt %08X, %dx%d, stride %d, size %d",
++ port->format.encoding,
++ dev->capture.width, dev->capture.height,
++ dev->capture.stride, dev->capture.buffersize);
++ }
++ }
++
++ /* todo: Need to convert the vchiq/mmal error into a v4l2 error. */
++ return ret;
++}
++
++static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
++ struct v4l2_format *f)
++{
++ int ret;
++ struct bm2835_mmal_dev *dev = video_drvdata(file);
++ struct mmal_fmt *mfmt;
++
++ /* try the format to set valid parameters */
++ ret = vidioc_try_fmt_vid_cap(file, priv, f);
++ if (ret) {
++ v4l2_err(&dev->v4l2_dev,
++ "vid_cap - vidioc_try_fmt_vid_cap failed\n");
++ return ret;
++ }
++
++ /* if a capture is running refuse to set format */
++ if (vb2_is_busy(&dev->capture.vb_vidq)) {
++ v4l2_info(&dev->v4l2_dev, "%s device busy\n", __func__);
++ return -EBUSY;
++ }
++
++ /* If the format is unsupported v4l2 says we should switch to
++ * a supported one and not return an error. */
++ mfmt = get_format(f);
++ if (!mfmt) {
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "Fourcc format (0x%08x) unknown.\n",
++ f->fmt.pix.pixelformat);
++ f->fmt.pix.pixelformat = formats[0].fourcc;
++ mfmt = get_format(f);
++ }
++
++ ret = mmal_setup_components(dev, f);
++ if (ret != 0) {
++ v4l2_err(&dev->v4l2_dev,
++ "%s: failed to setup mmal components: %d\n",
++ __func__, ret);
++ ret = -EINVAL;
++ }
++
++ return ret;
++}
++
++int vidioc_enum_framesizes(struct file *file, void *fh,
++ struct v4l2_frmsizeenum *fsize)
++{
++ static const struct v4l2_frmsize_stepwise sizes = {
++ MIN_WIDTH, MAX_WIDTH, 2,
++ MIN_HEIGHT, MAX_HEIGHT, 2
++ };
++ int i;
++
++ if (fsize->index)
++ return -EINVAL;
++ for (i = 0; i < ARRAY_SIZE(formats); i++)
++ if (formats[i].fourcc == fsize->pixel_format)
++ break;
++ if (i == ARRAY_SIZE(formats))
++ return -EINVAL;
++ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
++ fsize->stepwise = sizes;
++ return 0;
++}
++
++/* timeperframe is arbitrary and continous */
++static int vidioc_enum_frameintervals(struct file *file, void *priv,
++ struct v4l2_frmivalenum *fival)
++{
++ int i;
++
++ if (fival->index)
++ return -EINVAL;
++
++ for (i = 0; i < ARRAY_SIZE(formats); i++)
++ if (formats[i].fourcc == fival->pixel_format)
++ break;
++ if (i == ARRAY_SIZE(formats))
++ return -EINVAL;
++
++ /* regarding width & height - we support any within range */
++ if (fival->width < MIN_WIDTH || fival->width > MAX_WIDTH ||
++ fival->height < MIN_HEIGHT || fival->height > MAX_HEIGHT)
++ return -EINVAL;
++
++ fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS;
++
++ /* fill in stepwise (step=1.0 is requred by V4L2 spec) */
++ fival->stepwise.min = tpf_min;
++ fival->stepwise.max = tpf_max;
++ fival->stepwise.step = (struct v4l2_fract) {1, 1};
++
++ return 0;
++}
++
++static int vidioc_g_parm(struct file *file, void *priv,
++ struct v4l2_streamparm *parm)
++{
++ struct bm2835_mmal_dev *dev = video_drvdata(file);
++
++ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EINVAL;
++
++ parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
++ parm->parm.capture.timeperframe = dev->capture.timeperframe;
++ parm->parm.capture.readbuffers = 1;
++ return 0;
++}
++
++#define FRACT_CMP(a, OP, b) \
++ ((u64)(a).numerator * (b).denominator OP \
++ (u64)(b).numerator * (a).denominator)
++
++static int vidioc_s_parm(struct file *file, void *priv,
++ struct v4l2_streamparm *parm)
++{
++ struct bm2835_mmal_dev *dev = video_drvdata(file);
++ struct v4l2_fract tpf;
++ struct mmal_parameter_rational fps_param;
++
++ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EINVAL;
++
++ tpf = parm->parm.capture.timeperframe;
++
++ /* tpf: {*, 0} resets timing; clip to [min, max]*/
++ tpf = tpf.denominator ? tpf : tpf_default;
++ tpf = FRACT_CMP(tpf, <, tpf_min) ? tpf_min : tpf;
++ tpf = FRACT_CMP(tpf, >, tpf_max) ? tpf_max : tpf;
++
++ dev->capture.timeperframe = tpf;
++ parm->parm.capture.timeperframe = tpf;
++ parm->parm.capture.readbuffers = 1;
++
++ fps_param.num = 0; /* Select variable fps, and then use
++ * FPS_RANGE to select the actual limits.
++ */
++ fps_param.den = 1;
++ set_framerate_params(dev);
++
++ return 0;
++}
++
++static const struct v4l2_ioctl_ops camera0_ioctl_ops = {
++ /* overlay */
++ .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_overlay,
++ .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay,
++ .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay,
++ .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay,
++ .vidioc_overlay = vidioc_overlay,
++ .vidioc_g_fbuf = vidioc_g_fbuf,
++
++ /* inputs */
++ .vidioc_enum_input = vidioc_enum_input,
++ .vidioc_g_input = vidioc_g_input,
++ .vidioc_s_input = vidioc_s_input,
++
++ /* capture */
++ .vidioc_querycap = vidioc_querycap,
++ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
++ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
++ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
++ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
++
++ /* buffer management */
++ .vidioc_reqbufs = vb2_ioctl_reqbufs,
++ .vidioc_create_bufs = vb2_ioctl_create_bufs,
++ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
++ .vidioc_querybuf = vb2_ioctl_querybuf,
++ .vidioc_qbuf = vb2_ioctl_qbuf,
++ .vidioc_dqbuf = vb2_ioctl_dqbuf,
++ .vidioc_enum_framesizes = vidioc_enum_framesizes,
++ .vidioc_enum_frameintervals = vidioc_enum_frameintervals,
++ .vidioc_g_parm = vidioc_g_parm,
++ .vidioc_s_parm = vidioc_s_parm,
++ .vidioc_streamon = vb2_ioctl_streamon,
++ .vidioc_streamoff = vb2_ioctl_streamoff,
++
++ .vidioc_log_status = v4l2_ctrl_log_status,
++ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
++ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
++};
++
++static const struct v4l2_ioctl_ops camera0_ioctl_ops_gstreamer = {
++ /* overlay */
++ .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_overlay,
++ .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay,
++ .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay,
++ .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay,
++ .vidioc_overlay = vidioc_overlay,
++ .vidioc_g_fbuf = vidioc_g_fbuf,
++
++ /* inputs */
++ .vidioc_enum_input = vidioc_enum_input,
++ .vidioc_g_input = vidioc_g_input,
++ .vidioc_s_input = vidioc_s_input,
++
++ /* capture */
++ .vidioc_querycap = vidioc_querycap,
++ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
++ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
++ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
++ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
++
++ /* buffer management */
++ .vidioc_reqbufs = vb2_ioctl_reqbufs,
++ .vidioc_create_bufs = vb2_ioctl_create_bufs,
++ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
++ .vidioc_querybuf = vb2_ioctl_querybuf,
++ .vidioc_qbuf = vb2_ioctl_qbuf,
++ .vidioc_dqbuf = vb2_ioctl_dqbuf,
++ /* Remove this function ptr to fix gstreamer bug
++ .vidioc_enum_framesizes = vidioc_enum_framesizes, */
++ .vidioc_enum_frameintervals = vidioc_enum_frameintervals,
++ .vidioc_g_parm = vidioc_g_parm,
++ .vidioc_s_parm = vidioc_s_parm,
++ .vidioc_streamon = vb2_ioctl_streamon,
++ .vidioc_streamoff = vb2_ioctl_streamoff,
++
++ .vidioc_log_status = v4l2_ctrl_log_status,
++ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
++ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
++};
++
++/* ------------------------------------------------------------------
++ Driver init/finalise
++ ------------------------------------------------------------------*/
++
++static const struct v4l2_file_operations camera0_fops = {
++ .owner = THIS_MODULE,
++ .open = v4l2_fh_open,
++ .release = vb2_fop_release,
++ .read = vb2_fop_read,
++ .poll = vb2_fop_poll,
++ .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
++ .mmap = vb2_fop_mmap,
++};
++
++static struct video_device vdev_template = {
++ .name = "camera0",
++ .fops = &camera0_fops,
++ .ioctl_ops = &camera0_ioctl_ops,
++ .release = video_device_release_empty,
++};
++
++static int set_camera_parameters(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_component *camera)
++{
++ int ret;
++ struct mmal_parameter_camera_config cam_config = {
++ .max_stills_w = MAX_WIDTH,
++ .max_stills_h = MAX_HEIGHT,
++ .stills_yuv422 = 1,
++ .one_shot_stills = 1,
++ .max_preview_video_w = (max_video_width > 1920) ?
++ max_video_width : 1920,
++ .max_preview_video_h = (max_video_height > 1088) ?
++ max_video_height : 1088,
++ .num_preview_video_frames = 3,
++ .stills_capture_circular_buffer_height = 0,
++ .fast_preview_resume = 0,
++ .use_stc_timestamp = MMAL_PARAM_TIMESTAMP_MODE_RAW_STC
++ };
++
++ ret = vchiq_mmal_port_parameter_set(instance, &camera->control,
++ MMAL_PARAMETER_CAMERA_CONFIG,
++ &cam_config, sizeof(cam_config));
++ return ret;
++}
++
++/* MMAL instance and component init */
++static int __init mmal_init(struct bm2835_mmal_dev *dev)
++{
++ int ret;
++ struct mmal_es_format *format;
++ u32 bool_true = 1;
++
++ ret = vchiq_mmal_init(&dev->instance);
++ if (ret < 0)
++ return ret;
++
++ /* get the camera component ready */
++ ret = vchiq_mmal_component_init(dev->instance, "ril.camera",
++ &dev->component[MMAL_COMPONENT_CAMERA]);
++ if (ret < 0)
++ goto unreg_mmal;
++
++ if (dev->component[MMAL_COMPONENT_CAMERA]->outputs <
++ MMAL_CAMERA_PORT_COUNT) {
++ ret = -EINVAL;
++ goto unreg_camera;
++ }
++
++ ret = set_camera_parameters(dev->instance,
++ dev->component[MMAL_COMPONENT_CAMERA]);
++ if (ret < 0)
++ goto unreg_camera;
++
++ format =
++ &dev->component[MMAL_COMPONENT_CAMERA]->
++ output[MMAL_CAMERA_PORT_PREVIEW].format;
++
++ format->encoding = MMAL_ENCODING_OPAQUE;
++ format->encoding_variant = MMAL_ENCODING_I420;
++
++ format->es->video.width = 1024;
++ format->es->video.height = 768;
++ format->es->video.crop.x = 0;
++ format->es->video.crop.y = 0;
++ format->es->video.crop.width = 1024;
++ format->es->video.crop.height = 768;
++ format->es->video.frame_rate.num = 0; /* Rely on fps_range */
++ format->es->video.frame_rate.den = 1;
++
++ format =
++ &dev->component[MMAL_COMPONENT_CAMERA]->
++ output[MMAL_CAMERA_PORT_VIDEO].format;
++
++ format->encoding = MMAL_ENCODING_OPAQUE;
++ format->encoding_variant = MMAL_ENCODING_I420;
++
++ format->es->video.width = 1024;
++ format->es->video.height = 768;
++ format->es->video.crop.x = 0;
++ format->es->video.crop.y = 0;
++ format->es->video.crop.width = 1024;
++ format->es->video.crop.height = 768;
++ format->es->video.frame_rate.num = 0; /* Rely on fps_range */
++ format->es->video.frame_rate.den = 1;
++
++ vchiq_mmal_port_parameter_set(dev->instance,
++ &dev->component[MMAL_COMPONENT_CAMERA]->
++ output[MMAL_CAMERA_PORT_VIDEO],
++ MMAL_PARAMETER_NO_IMAGE_PADDING,
++ &bool_true, sizeof(bool_true));
++
++ format =
++ &dev->component[MMAL_COMPONENT_CAMERA]->
++ output[MMAL_CAMERA_PORT_CAPTURE].format;
++
++ format->encoding = MMAL_ENCODING_OPAQUE;
++
++ format->es->video.width = 2592;
++ format->es->video.height = 1944;
++ format->es->video.crop.x = 0;
++ format->es->video.crop.y = 0;
++ format->es->video.crop.width = 2592;
++ format->es->video.crop.height = 1944;
++ format->es->video.frame_rate.num = 0; /* Rely on fps_range */
++ format->es->video.frame_rate.den = 1;
++
++ dev->capture.width = format->es->video.width;
++ dev->capture.height = format->es->video.height;
++ dev->capture.fmt = &formats[0];
++ dev->capture.encode_component = NULL;
++ dev->capture.timeperframe = tpf_default;
++ dev->capture.enc_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH;
++ dev->capture.enc_level = V4L2_MPEG_VIDEO_H264_LEVEL_4_0;
++
++ vchiq_mmal_port_parameter_set(dev->instance,
++ &dev->component[MMAL_COMPONENT_CAMERA]->
++ output[MMAL_CAMERA_PORT_CAPTURE],
++ MMAL_PARAMETER_NO_IMAGE_PADDING,
++ &bool_true, sizeof(bool_true));
++
++ /* get the preview component ready */
++ ret = vchiq_mmal_component_init(
++ dev->instance, "ril.video_render",
++ &dev->component[MMAL_COMPONENT_PREVIEW]);
++ if (ret < 0)
++ goto unreg_camera;
++
++ if (dev->component[MMAL_COMPONENT_PREVIEW]->inputs < 1) {
++ ret = -EINVAL;
++ pr_debug("too few input ports %d needed %d\n",
++ dev->component[MMAL_COMPONENT_PREVIEW]->inputs, 1);
++ goto unreg_preview;
++ }
++
++ /* get the image encoder component ready */
++ ret = vchiq_mmal_component_init(
++ dev->instance, "ril.image_encode",
++ &dev->component[MMAL_COMPONENT_IMAGE_ENCODE]);
++ if (ret < 0)
++ goto unreg_preview;
++
++ if (dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->inputs < 1) {
++ ret = -EINVAL;
++ v4l2_err(&dev->v4l2_dev, "too few input ports %d needed %d\n",
++ dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->inputs,
++ 1);
++ goto unreg_image_encoder;
++ }
++
++ /* get the video encoder component ready */
++ ret = vchiq_mmal_component_init(dev->instance, "ril.video_encode",
++ &dev->
++ component[MMAL_COMPONENT_VIDEO_ENCODE]);
++ if (ret < 0)
++ goto unreg_image_encoder;
++
++ if (dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->inputs < 1) {
++ ret = -EINVAL;
++ v4l2_err(&dev->v4l2_dev, "too few input ports %d needed %d\n",
++ dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->inputs,
++ 1);
++ goto unreg_vid_encoder;
++ }
++
++ {
++ struct vchiq_mmal_port *encoder_port =
++ &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
++ encoder_port->format.encoding = MMAL_ENCODING_H264;
++ ret = vchiq_mmal_port_set_format(dev->instance,
++ encoder_port);
++ }
++
++ {
++ unsigned int enable = 1;
++ vchiq_mmal_port_parameter_set(
++ dev->instance,
++ &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->control,
++ MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT,
++ &enable, sizeof(enable));
++
++ vchiq_mmal_port_parameter_set(dev->instance,
++ &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->control,
++ MMAL_PARAMETER_MINIMISE_FRAGMENTATION,
++ &enable,
++ sizeof(enable));
++ }
++ ret = bm2835_mmal_set_all_camera_controls(dev);
++ if (ret < 0)
++ goto unreg_vid_encoder;
++
++ return 0;
++
++unreg_vid_encoder:
++ pr_err("Cleanup: Destroy video encoder\n");
++ vchiq_mmal_component_finalise(
++ dev->instance,
++ dev->component[MMAL_COMPONENT_VIDEO_ENCODE]);
++
++unreg_image_encoder:
++ pr_err("Cleanup: Destroy image encoder\n");
++ vchiq_mmal_component_finalise(
++ dev->instance,
++ dev->component[MMAL_COMPONENT_IMAGE_ENCODE]);
++
++unreg_preview:
++ pr_err("Cleanup: Destroy video render\n");
++ vchiq_mmal_component_finalise(dev->instance,
++ dev->component[MMAL_COMPONENT_PREVIEW]);
++
++unreg_camera:
++ pr_err("Cleanup: Destroy camera\n");
++ vchiq_mmal_component_finalise(dev->instance,
++ dev->component[MMAL_COMPONENT_CAMERA]);
++
++unreg_mmal:
++ vchiq_mmal_finalise(dev->instance);
++ return ret;
++}
++
++static int __init bm2835_mmal_init_device(struct bm2835_mmal_dev *dev,
++ struct video_device *vfd)
++{
++ int ret;
++
++ *vfd = vdev_template;
++ if (gst_v4l2src_is_broken) {
++ v4l2_info(&dev->v4l2_dev,
++ "Work-around for gstreamer issue is active.\n");
++ vfd->ioctl_ops = &camera0_ioctl_ops_gstreamer;
++ }
++
++ vfd->v4l2_dev = &dev->v4l2_dev;
++
++ vfd->lock = &dev->mutex;
++
++ vfd->queue = &dev->capture.vb_vidq;
++
++ /* video device needs to be able to access instance data */
++ video_set_drvdata(vfd, dev);
++
++ ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
++ if (ret < 0)
++ return ret;
++
++ v4l2_info(vfd->v4l2_dev,
++ "V4L2 device registered as %s - stills mode > %dx%d\n",
++ video_device_node_name(vfd), max_video_width, max_video_height);
++
++ return 0;
++}
++
++static struct v4l2_format default_v4l2_format = {
++ .fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG,
++ .fmt.pix.width = 1024,
++ .fmt.pix.bytesperline = 1024,
++ .fmt.pix.height = 768,
++ .fmt.pix.sizeimage = 1024*768,
++};
++
++static int __init bm2835_mmal_init(void)
++{
++ int ret;
++ struct bm2835_mmal_dev *dev;
++ struct vb2_queue *q;
++
++ dev = kzalloc(sizeof(*gdev), GFP_KERNEL);
++ if (!dev)
++ return -ENOMEM;
++
++ /* setup device defaults */
++ dev->overlay.w.left = 150;
++ dev->overlay.w.top = 50;
++ dev->overlay.w.width = 1024;
++ dev->overlay.w.height = 768;
++ dev->overlay.clipcount = 0;
++ dev->overlay.field = V4L2_FIELD_NONE;
++
++ dev->capture.fmt = &formats[3]; /* JPEG */
++
++ /* v4l device registration */
++ snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
++ "%s", BM2835_MMAL_MODULE_NAME);
++ ret = v4l2_device_register(NULL, &dev->v4l2_dev);
++ if (ret)
++ goto free_dev;
++
++ /* setup v4l controls */
++ ret = bm2835_mmal_init_controls(dev, &dev->ctrl_handler);
++ if (ret < 0)
++ goto unreg_dev;
++ dev->v4l2_dev.ctrl_handler = &dev->ctrl_handler;
++
++ /* mmal init */
++ ret = mmal_init(dev);
++ if (ret < 0)
++ goto unreg_dev;
++
++ /* initialize queue */
++ q = &dev->capture.vb_vidq;
++ memset(q, 0, sizeof(*q));
++ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
++ q->drv_priv = dev;
++ q->buf_struct_size = sizeof(struct mmal_buffer);
++ q->ops = &bm2835_mmal_video_qops;
++ q->mem_ops = &vb2_vmalloc_memops;
++ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
++ ret = vb2_queue_init(q);
++ if (ret < 0)
++ goto unreg_dev;
++
++ /* v4l2 core mutex used to protect all fops and v4l2 ioctls. */
++ mutex_init(&dev->mutex);
++
++ /* initialise video devices */
++ ret = bm2835_mmal_init_device(dev, &dev->vdev);
++ if (ret < 0)
++ goto unreg_dev;
++
++ /* Really want to call vidioc_s_fmt_vid_cap with the default
++ * format, but currently the APIs don't join up.
++ */
++ ret = mmal_setup_components(dev, &default_v4l2_format);
++ if (ret < 0) {
++ v4l2_err(&dev->v4l2_dev,
++ "%s: could not setup components\n", __func__);
++ goto unreg_dev;
++ }
++
++ v4l2_info(&dev->v4l2_dev,
++ "Broadcom 2835 MMAL video capture ver %s loaded.\n",
++ BM2835_MMAL_VERSION);
++
++ gdev = dev;
++ return 0;
++
++unreg_dev:
++ v4l2_ctrl_handler_free(&dev->ctrl_handler);
++ v4l2_device_unregister(&dev->v4l2_dev);
++
++free_dev:
++ kfree(dev);
++
++ v4l2_err(&dev->v4l2_dev,
++ "%s: error %d while loading driver\n",
++ BM2835_MMAL_MODULE_NAME, ret);
++
++ return ret;
++}
++
++static void __exit bm2835_mmal_exit(void)
++{
++ if (!gdev)
++ return;
++
++ v4l2_info(&gdev->v4l2_dev, "unregistering %s\n",
++ video_device_node_name(&gdev->vdev));
++
++ video_unregister_device(&gdev->vdev);
++
++ if (gdev->capture.encode_component) {
++ v4l2_dbg(1, bcm2835_v4l2_debug, &gdev->v4l2_dev,
++ "mmal_exit - disconnect tunnel\n");
++ vchiq_mmal_port_connect_tunnel(gdev->instance,
++ gdev->capture.camera_port, NULL);
++ vchiq_mmal_component_disable(gdev->instance,
++ gdev->capture.encode_component);
++ }
++ vchiq_mmal_component_disable(gdev->instance,
++ gdev->component[MMAL_COMPONENT_CAMERA]);
++
++ vchiq_mmal_component_finalise(gdev->instance,
++ gdev->
++ component[MMAL_COMPONENT_VIDEO_ENCODE]);
++
++ vchiq_mmal_component_finalise(gdev->instance,
++ gdev->
++ component[MMAL_COMPONENT_IMAGE_ENCODE]);
++
++ vchiq_mmal_component_finalise(gdev->instance,
++ gdev->component[MMAL_COMPONENT_PREVIEW]);
++
++ vchiq_mmal_component_finalise(gdev->instance,
++ gdev->component[MMAL_COMPONENT_CAMERA]);
++
++ vchiq_mmal_finalise(gdev->instance);
++
++ v4l2_ctrl_handler_free(&gdev->ctrl_handler);
++
++ v4l2_device_unregister(&gdev->v4l2_dev);
++
++ kfree(gdev);
++}
++
++module_init(bm2835_mmal_init);
++module_exit(bm2835_mmal_exit);
+--- /dev/null
++++ b/drivers/media/platform/bcm2835/bcm2835-camera.h
+@@ -0,0 +1,126 @@
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file COPYING in the main directory of this archive
++ * for more details.
++ *
++ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
++ * Dave Stevenson <dsteve@broadcom.com>
++ * Simon Mellor <simellor@broadcom.com>
++ * Luke Diamand <luked@broadcom.com>
++ *
++ * core driver device
++ */
++
++#define V4L2_CTRL_COUNT 28 /* number of v4l controls */
++
++enum {
++ MMAL_COMPONENT_CAMERA = 0,
++ MMAL_COMPONENT_PREVIEW,
++ MMAL_COMPONENT_IMAGE_ENCODE,
++ MMAL_COMPONENT_VIDEO_ENCODE,
++ MMAL_COMPONENT_COUNT
++};
++
++enum {
++ MMAL_CAMERA_PORT_PREVIEW = 0,
++ MMAL_CAMERA_PORT_VIDEO,
++ MMAL_CAMERA_PORT_CAPTURE,
++ MMAL_CAMERA_PORT_COUNT
++};
++
++#define PREVIEW_LAYER 2
++
++extern int bcm2835_v4l2_debug;
++
++struct bm2835_mmal_dev {
++ /* v4l2 devices */
++ struct v4l2_device v4l2_dev;
++ struct video_device vdev;
++ struct mutex mutex;
++
++ /* controls */
++ struct v4l2_ctrl_handler ctrl_handler;
++ struct v4l2_ctrl *ctrls[V4L2_CTRL_COUNT];
++ enum v4l2_scene_mode scene_mode;
++ struct mmal_colourfx colourfx;
++ int hflip;
++ int vflip;
++ int red_gain;
++ int blue_gain;
++ enum mmal_parameter_exposuremode exposure_mode_user;
++ enum v4l2_exposure_auto_type exposure_mode_v4l2_user;
++ /* active exposure mode may differ if selected via a scene mode */
++ enum mmal_parameter_exposuremode exposure_mode_active;
++ enum mmal_parameter_exposuremeteringmode metering_mode;
++ unsigned int manual_shutter_speed;
++ bool exp_auto_priority;
++
++ /* allocated mmal instance and components */
++ struct vchiq_mmal_instance *instance;
++ struct vchiq_mmal_component *component[MMAL_COMPONENT_COUNT];
++ int camera_use_count;
++
++ struct v4l2_window overlay;
++
++ struct {
++ unsigned int width; /* width */
++ unsigned int height; /* height */
++ unsigned int stride; /* stride */
++ unsigned int buffersize; /* buffer size with padding */
++ struct mmal_fmt *fmt;
++ struct v4l2_fract timeperframe;
++
++ /* H264 encode bitrate */
++ int encode_bitrate;
++ /* H264 bitrate mode. CBR/VBR */
++ int encode_bitrate_mode;
++ /* H264 profile */
++ enum v4l2_mpeg_video_h264_profile enc_profile;
++ /* H264 level */
++ enum v4l2_mpeg_video_h264_level enc_level;
++ /* JPEG Q-factor */
++ int q_factor;
++
++ struct vb2_queue vb_vidq;
++
++ /* VC start timestamp for streaming */
++ s64 vc_start_timestamp;
++ /* Kernel start timestamp for streaming */
++ struct timeval kernel_start_ts;
++
++ struct vchiq_mmal_port *port; /* port being used for capture */
++ /* camera port being used for capture */
++ struct vchiq_mmal_port *camera_port;
++ /* component being used for encode */
++ struct vchiq_mmal_component *encode_component;
++ /* number of frames remaining which driver should capture */
++ unsigned int frame_count;
++ /* last frame completion */
++ struct completion frame_cmplt;
++
++ } capture;
++
++};
++
++int bm2835_mmal_init_controls(
++ struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl_handler *hdl);
++
++int bm2835_mmal_set_all_camera_controls(struct bm2835_mmal_dev *dev);
++int set_framerate_params(struct bm2835_mmal_dev *dev);
++
++/* Debug helpers */
++
++#define v4l2_dump_pix_format(level, debug, dev, pix_fmt, desc) \
++{ \
++ v4l2_dbg(level, debug, dev, \
++"%s: w %u h %u field %u pfmt 0x%x bpl %u sz_img %u colorspace 0x%x priv %u\n", \
++ desc == NULL ? "" : desc, \
++ (pix_fmt)->width, (pix_fmt)->height, (pix_fmt)->field, \
++ (pix_fmt)->pixelformat, (pix_fmt)->bytesperline, \
++ (pix_fmt)->sizeimage, (pix_fmt)->colorspace, (pix_fmt)->priv); \
++}
+--- /dev/null
++++ b/drivers/media/platform/bcm2835/controls.c
+@@ -0,0 +1,1324 @@
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file COPYING in the main directory of this archive
++ * for more details.
++ *
++ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
++ * Dave Stevenson <dsteve@broadcom.com>
++ * Simon Mellor <simellor@broadcom.com>
++ * Luke Diamand <luked@broadcom.com>
++ */
++
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <media/videobuf2-vmalloc.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-ioctl.h>
++#include <media/v4l2-ctrls.h>
++#include <media/v4l2-fh.h>
++#include <media/v4l2-event.h>
++#include <media/v4l2-common.h>
++
++#include "mmal-common.h"
++#include "mmal-vchiq.h"
++#include "mmal-parameters.h"
++#include "bcm2835-camera.h"
++
++/* The supported V4L2_CID_AUTO_EXPOSURE_BIAS values are from -4.0 to +4.0.
++ * MMAL values are in 1/6th increments so the MMAL range is -24 to +24.
++ * V4L2 docs say value "is expressed in terms of EV, drivers should interpret
++ * the values as 0.001 EV units, where the value 1000 stands for +1 EV."
++ * V4L2 is limited to a max of 32 values in a menu, so count in 1/3rds from
++ * -4 to +4
++ */
++static const s64 ev_bias_qmenu[] = {
++ -4000, -3667, -3333,
++ -3000, -2667, -2333,
++ -2000, -1667, -1333,
++ -1000, -667, -333,
++ 0, 333, 667,
++ 1000, 1333, 1667,
++ 2000, 2333, 2667,
++ 3000, 3333, 3667,
++ 4000
++};
++
++/* Supported ISO values
++ * ISOO = auto ISO
++ */
++static const s64 iso_qmenu[] = {
++ 0, 100, 200, 400, 800,
++};
++
++static const s64 mains_freq_qmenu[] = {
++ V4L2_CID_POWER_LINE_FREQUENCY_DISABLED,
++ V4L2_CID_POWER_LINE_FREQUENCY_50HZ,
++ V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
++ V4L2_CID_POWER_LINE_FREQUENCY_AUTO
++};
++
++/* Supported video encode modes */
++static const s64 bitrate_mode_qmenu[] = {
++ (s64)V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
++ (s64)V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
++};
++
++enum bm2835_mmal_ctrl_type {
++ MMAL_CONTROL_TYPE_STD,
++ MMAL_CONTROL_TYPE_STD_MENU,
++ MMAL_CONTROL_TYPE_INT_MENU,
++ MMAL_CONTROL_TYPE_CLUSTER, /* special cluster entry */
++};
++
++struct bm2835_mmal_v4l2_ctrl;
++
++typedef int(bm2835_mmal_v4l2_ctrl_cb)(
++ struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl);
++
++struct bm2835_mmal_v4l2_ctrl {
++ u32 id; /* v4l2 control identifier */
++ enum bm2835_mmal_ctrl_type type;
++ /* control minimum value or
++ * mask for MMAL_CONTROL_TYPE_STD_MENU */
++ s32 min;
++ s32 max; /* maximum value of control */
++ s32 def; /* default value of control */
++ s32 step; /* step size of the control */
++ const s64 *imenu; /* integer menu array */
++ u32 mmal_id; /* mmal parameter id */
++ bm2835_mmal_v4l2_ctrl_cb *setter;
++ bool ignore_errors;
++};
++
++struct v4l2_to_mmal_effects_setting {
++ u32 v4l2_effect;
++ u32 mmal_effect;
++ s32 col_fx_enable;
++ s32 col_fx_fixed_cbcr;
++ u32 u;
++ u32 v;
++ u32 num_effect_params;
++ u32 effect_params[MMAL_MAX_IMAGEFX_PARAMETERS];
++};
++
++static const struct v4l2_to_mmal_effects_setting
++ v4l2_to_mmal_effects_values[] = {
++ { V4L2_COLORFX_NONE, MMAL_PARAM_IMAGEFX_NONE,
++ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
++ { V4L2_COLORFX_BW, MMAL_PARAM_IMAGEFX_NONE,
++ 1, 0, 128, 128, 0, {0, 0, 0, 0, 0} },
++ { V4L2_COLORFX_SEPIA, MMAL_PARAM_IMAGEFX_NONE,
++ 1, 0, 87, 151, 0, {0, 0, 0, 0, 0} },
++ { V4L2_COLORFX_NEGATIVE, MMAL_PARAM_IMAGEFX_NEGATIVE,
++ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
++ { V4L2_COLORFX_EMBOSS, MMAL_PARAM_IMAGEFX_EMBOSS,
++ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
++ { V4L2_COLORFX_SKETCH, MMAL_PARAM_IMAGEFX_SKETCH,
++ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
++ { V4L2_COLORFX_SKY_BLUE, MMAL_PARAM_IMAGEFX_PASTEL,
++ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
++ { V4L2_COLORFX_GRASS_GREEN, MMAL_PARAM_IMAGEFX_WATERCOLOUR,
++ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
++ { V4L2_COLORFX_SKIN_WHITEN, MMAL_PARAM_IMAGEFX_WASHEDOUT,
++ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
++ { V4L2_COLORFX_VIVID, MMAL_PARAM_IMAGEFX_SATURATION,
++ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
++ { V4L2_COLORFX_AQUA, MMAL_PARAM_IMAGEFX_NONE,
++ 1, 0, 171, 121, 0, {0, 0, 0, 0, 0} },
++ { V4L2_COLORFX_ART_FREEZE, MMAL_PARAM_IMAGEFX_HATCH,
++ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
++ { V4L2_COLORFX_SILHOUETTE, MMAL_PARAM_IMAGEFX_FILM,
++ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
++ { V4L2_COLORFX_SOLARIZATION, MMAL_PARAM_IMAGEFX_SOLARIZE,
++ 0, 0, 0, 0, 5, {1, 128, 160, 160, 48} },
++ { V4L2_COLORFX_ANTIQUE, MMAL_PARAM_IMAGEFX_COLOURBALANCE,
++ 0, 0, 0, 0, 3, {108, 274, 238, 0, 0} },
++ { V4L2_COLORFX_SET_CBCR, MMAL_PARAM_IMAGEFX_NONE,
++ 1, 1, 0, 0, 0, {0, 0, 0, 0, 0} }
++};
++
++struct v4l2_mmal_scene_config {
++ enum v4l2_scene_mode v4l2_scene;
++ enum mmal_parameter_exposuremode exposure_mode;
++ enum mmal_parameter_exposuremeteringmode metering_mode;
++};
++
++static const struct v4l2_mmal_scene_config scene_configs[] = {
++ /* V4L2_SCENE_MODE_NONE automatically added */
++ {
++ V4L2_SCENE_MODE_NIGHT,
++ MMAL_PARAM_EXPOSUREMODE_NIGHT,
++ MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE
++ },
++ {
++ V4L2_SCENE_MODE_SPORTS,
++ MMAL_PARAM_EXPOSUREMODE_SPORTS,
++ MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE
++ },
++};
++
++/* control handlers*/
++
++static int ctrl_set_rational(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
++{
++ struct mmal_parameter_rational rational_value;
++ struct vchiq_mmal_port *control;
++
++ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
++
++ rational_value.num = ctrl->val;
++ rational_value.den = 100;
++
++ return vchiq_mmal_port_parameter_set(dev->instance, control,
++ mmal_ctrl->mmal_id,
++ &rational_value,
++ sizeof(rational_value));
++}
++
++static int ctrl_set_value(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
++{
++ u32 u32_value;
++ struct vchiq_mmal_port *control;
++
++ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
++
++ u32_value = ctrl->val;
++
++ return vchiq_mmal_port_parameter_set(dev->instance, control,
++ mmal_ctrl->mmal_id,
++ &u32_value, sizeof(u32_value));
++}
++
++static int ctrl_set_value_menu(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
++{
++ u32 u32_value;
++ struct vchiq_mmal_port *control;
++
++ if (ctrl->val > mmal_ctrl->max || ctrl->val < mmal_ctrl->min)
++ return 1;
++
++ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
++
++ u32_value = mmal_ctrl->imenu[ctrl->val];
++
++ return vchiq_mmal_port_parameter_set(dev->instance, control,
++ mmal_ctrl->mmal_id,
++ &u32_value, sizeof(u32_value));
++}
++
++static int ctrl_set_value_ev(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
++{
++ s32 s32_value;
++ struct vchiq_mmal_port *control;
++
++ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
++
++ s32_value = (ctrl->val-12)*2; /* Convert from index to 1/6ths */
++
++ return vchiq_mmal_port_parameter_set(dev->instance, control,
++ mmal_ctrl->mmal_id,
++ &s32_value, sizeof(s32_value));
++}
++
++static int ctrl_set_rotate(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
++{
++ int ret;
++ u32 u32_value;
++ struct vchiq_mmal_component *camera;
++
++ camera = dev->component[MMAL_COMPONENT_CAMERA];
++
++ u32_value = ((ctrl->val % 360) / 90) * 90;
++
++ ret = vchiq_mmal_port_parameter_set(dev->instance, &camera->output[0],
++ mmal_ctrl->mmal_id,
++ &u32_value, sizeof(u32_value));
++ if (ret < 0)
++ return ret;
++
++ ret = vchiq_mmal_port_parameter_set(dev->instance, &camera->output[1],
++ mmal_ctrl->mmal_id,
++ &u32_value, sizeof(u32_value));
++ if (ret < 0)
++ return ret;
++
++ ret = vchiq_mmal_port_parameter_set(dev->instance, &camera->output[2],
++ mmal_ctrl->mmal_id,
++ &u32_value, sizeof(u32_value));
++
++ return ret;
++}
++
++static int ctrl_set_flip(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
++{
++ int ret;
++ u32 u32_value;
++ struct vchiq_mmal_component *camera;
++
++ if (ctrl->id == V4L2_CID_HFLIP)
++ dev->hflip = ctrl->val;
++ else
++ dev->vflip = ctrl->val;
++
++ camera = dev->component[MMAL_COMPONENT_CAMERA];
++
++ if (dev->hflip && dev->vflip)
++ u32_value = MMAL_PARAM_MIRROR_BOTH;
++ else if (dev->hflip)
++ u32_value = MMAL_PARAM_MIRROR_HORIZONTAL;
++ else if (dev->vflip)
++ u32_value = MMAL_PARAM_MIRROR_VERTICAL;
++ else
++ u32_value = MMAL_PARAM_MIRROR_NONE;
++
++ ret = vchiq_mmal_port_parameter_set(dev->instance, &camera->output[0],
++ mmal_ctrl->mmal_id,
++ &u32_value, sizeof(u32_value));
++ if (ret < 0)
++ return ret;
++
++ ret = vchiq_mmal_port_parameter_set(dev->instance, &camera->output[1],
++ mmal_ctrl->mmal_id,
++ &u32_value, sizeof(u32_value));
++ if (ret < 0)
++ return ret;
++
++ ret = vchiq_mmal_port_parameter_set(dev->instance, &camera->output[2],
++ mmal_ctrl->mmal_id,
++ &u32_value, sizeof(u32_value));
++
++ return ret;
++
++}
++
++static int ctrl_set_exposure(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
++{
++ enum mmal_parameter_exposuremode exp_mode = dev->exposure_mode_user;
++ u32 shutter_speed = 0;
++ struct vchiq_mmal_port *control;
++ int ret = 0;
++
++ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
++
++ if (mmal_ctrl->mmal_id == MMAL_PARAMETER_SHUTTER_SPEED) {
++ /* V4L2 is in 100usec increments.
++ * MMAL is 1usec.
++ */
++ dev->manual_shutter_speed = ctrl->val * 100;
++ } else if (mmal_ctrl->mmal_id == MMAL_PARAMETER_EXPOSURE_MODE) {
++ switch (ctrl->val) {
++ case V4L2_EXPOSURE_AUTO:
++ exp_mode = MMAL_PARAM_EXPOSUREMODE_AUTO;
++ break;
++
++ case V4L2_EXPOSURE_MANUAL:
++ exp_mode = MMAL_PARAM_EXPOSUREMODE_OFF;
++ break;
++ }
++ dev->exposure_mode_user = exp_mode;
++ dev->exposure_mode_v4l2_user = ctrl->val;
++ } else if (mmal_ctrl->id == V4L2_CID_EXPOSURE_AUTO_PRIORITY) {
++ dev->exp_auto_priority = ctrl->val;
++ }
++
++ if (dev->scene_mode == V4L2_SCENE_MODE_NONE) {
++ if (exp_mode == MMAL_PARAM_EXPOSUREMODE_OFF)
++ shutter_speed = dev->manual_shutter_speed;
++
++ ret = vchiq_mmal_port_parameter_set(dev->instance,
++ control,
++ MMAL_PARAMETER_SHUTTER_SPEED,
++ &shutter_speed,
++ sizeof(shutter_speed));
++ ret += vchiq_mmal_port_parameter_set(dev->instance,
++ control,
++ MMAL_PARAMETER_EXPOSURE_MODE,
++ &exp_mode,
++ sizeof(u32));
++ dev->exposure_mode_active = exp_mode;
++ }
++ /* exposure_dynamic_framerate (V4L2_CID_EXPOSURE_AUTO_PRIORITY) should
++ * always apply irrespective of scene mode.
++ */
++ ret += set_framerate_params(dev);
++
++ return ret;
++}
++
++static int ctrl_set_metering_mode(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
++{
++ switch (ctrl->val) {
++ case V4L2_EXPOSURE_METERING_AVERAGE:
++ dev->metering_mode = MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE;
++ break;
++
++ case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED:
++ dev->metering_mode = MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT;
++ break;
++
++ case V4L2_EXPOSURE_METERING_SPOT:
++ dev->metering_mode = MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT;
++ break;
++
++ /* todo matrix weighting not added to Linux API till 3.9
++ case V4L2_EXPOSURE_METERING_MATRIX:
++ dev->metering_mode = MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX;
++ break;
++ */
++
++ }
++
++ if (dev->scene_mode == V4L2_SCENE_MODE_NONE) {
++ struct vchiq_mmal_port *control;
++ u32 u32_value = dev->metering_mode;
++
++ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
++
++ return vchiq_mmal_port_parameter_set(dev->instance, control,
++ mmal_ctrl->mmal_id,
++ &u32_value, sizeof(u32_value));
++ } else
++ return 0;
++}
++
++static int ctrl_set_flicker_avoidance(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
++{
++ u32 u32_value;
++ struct vchiq_mmal_port *control;
++
++ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
++
++ switch (ctrl->val) {
++ case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED:
++ u32_value = MMAL_PARAM_FLICKERAVOID_OFF;
++ break;
++ case V4L2_CID_POWER_LINE_FREQUENCY_50HZ:
++ u32_value = MMAL_PARAM_FLICKERAVOID_50HZ;
++ break;
++ case V4L2_CID_POWER_LINE_FREQUENCY_60HZ:
++ u32_value = MMAL_PARAM_FLICKERAVOID_60HZ;
++ break;
++ case V4L2_CID_POWER_LINE_FREQUENCY_AUTO:
++ u32_value = MMAL_PARAM_FLICKERAVOID_AUTO;
++ break;
++ }
++
++ return vchiq_mmal_port_parameter_set(dev->instance, control,
++ mmal_ctrl->mmal_id,
++ &u32_value, sizeof(u32_value));
++}
++
++static int ctrl_set_awb_mode(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
++{
++ u32 u32_value;
++ struct vchiq_mmal_port *control;
++
++ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
++
++ switch (ctrl->val) {
++ case V4L2_WHITE_BALANCE_MANUAL:
++ u32_value = MMAL_PARAM_AWBMODE_OFF;
++ break;
++
++ case V4L2_WHITE_BALANCE_AUTO:
++ u32_value = MMAL_PARAM_AWBMODE_AUTO;
++ break;
++
++ case V4L2_WHITE_BALANCE_INCANDESCENT:
++ u32_value = MMAL_PARAM_AWBMODE_INCANDESCENT;
++ break;
++
++ case V4L2_WHITE_BALANCE_FLUORESCENT:
++ u32_value = MMAL_PARAM_AWBMODE_FLUORESCENT;
++ break;
++
++ case V4L2_WHITE_BALANCE_FLUORESCENT_H:
++ u32_value = MMAL_PARAM_AWBMODE_TUNGSTEN;
++ break;
++
++ case V4L2_WHITE_BALANCE_HORIZON:
++ u32_value = MMAL_PARAM_AWBMODE_HORIZON;
++ break;
++
++ case V4L2_WHITE_BALANCE_DAYLIGHT:
++ u32_value = MMAL_PARAM_AWBMODE_SUNLIGHT;
++ break;
++
++ case V4L2_WHITE_BALANCE_FLASH:
++ u32_value = MMAL_PARAM_AWBMODE_FLASH;
++ break;
++
++ case V4L2_WHITE_BALANCE_CLOUDY:
++ u32_value = MMAL_PARAM_AWBMODE_CLOUDY;
++ break;
++
++ case V4L2_WHITE_BALANCE_SHADE:
++ u32_value = MMAL_PARAM_AWBMODE_SHADE;
++ break;
++
++ }
++
++ return vchiq_mmal_port_parameter_set(dev->instance, control,
++ mmal_ctrl->mmal_id,
++ &u32_value, sizeof(u32_value));
++}
++
++static int ctrl_set_awb_gains(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
++{
++ struct vchiq_mmal_port *control;
++ struct mmal_parameter_awbgains gains;
++
++ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
++
++ if (ctrl->id == V4L2_CID_RED_BALANCE)
++ dev->red_gain = ctrl->val;
++ else if (ctrl->id == V4L2_CID_BLUE_BALANCE)
++ dev->blue_gain = ctrl->val;
++
++ gains.r_gain.num = dev->red_gain;
++ gains.b_gain.num = dev->blue_gain;
++ gains.r_gain.den = gains.b_gain.den = 1000;
++
++ return vchiq_mmal_port_parameter_set(dev->instance, control,
++ mmal_ctrl->mmal_id,
++ &gains, sizeof(gains));
++}
++
++static int ctrl_set_image_effect(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
++{
++ int ret = -EINVAL;
++ int i, j;
++ struct vchiq_mmal_port *control;
++ struct mmal_parameter_imagefx_parameters imagefx;
++
++ for (i = 0; i < ARRAY_SIZE(v4l2_to_mmal_effects_values); i++) {
++ if (ctrl->val == v4l2_to_mmal_effects_values[i].v4l2_effect) {
++
++ imagefx.effect =
++ v4l2_to_mmal_effects_values[i].mmal_effect;
++ imagefx.num_effect_params =
++ v4l2_to_mmal_effects_values[i].num_effect_params;
++
++ if (imagefx.num_effect_params > MMAL_MAX_IMAGEFX_PARAMETERS)
++ imagefx.num_effect_params = MMAL_MAX_IMAGEFX_PARAMETERS;
++
++ for (j = 0; j < imagefx.num_effect_params; j++)
++ imagefx.effect_parameter[j] =
++ v4l2_to_mmal_effects_values[i].effect_params[j];
++
++ dev->colourfx.enable =
++ v4l2_to_mmal_effects_values[i].col_fx_enable;
++ if (!v4l2_to_mmal_effects_values[i].col_fx_fixed_cbcr) {
++ dev->colourfx.u =
++ v4l2_to_mmal_effects_values[i].u;
++ dev->colourfx.v =
++ v4l2_to_mmal_effects_values[i].v;
++ }
++
++ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
++
++ ret = vchiq_mmal_port_parameter_set(
++ dev->instance, control,
++ MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS,
++ &imagefx, sizeof(imagefx));
++ if (ret)
++ goto exit;
++
++ ret = vchiq_mmal_port_parameter_set(
++ dev->instance, control,
++ MMAL_PARAMETER_COLOUR_EFFECT,
++ &dev->colourfx, sizeof(dev->colourfx));
++ }
++ }
++
++exit:
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "mmal_ctrl:%p ctrl id:0x%x ctrl val:%d imagefx:0x%x color_effect:%s u:%d v:%d ret %d(%d)\n",
++ mmal_ctrl, ctrl->id, ctrl->val, imagefx.effect,
++ dev->colourfx.enable ? "true" : "false",
++ dev->colourfx.u, dev->colourfx.v,
++ ret, (ret == 0 ? 0 : -EINVAL));
++ return (ret == 0 ? 0 : EINVAL);
++}
++
++static int ctrl_set_colfx(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
++{
++ int ret = -EINVAL;
++ struct vchiq_mmal_port *control;
++
++ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
++
++ dev->colourfx.enable = (ctrl->val & 0xff00) >> 8;
++ dev->colourfx.enable = ctrl->val & 0xff;
++
++ ret = vchiq_mmal_port_parameter_set(dev->instance, control,
++ MMAL_PARAMETER_COLOUR_EFFECT,
++ &dev->colourfx, sizeof(dev->colourfx));
++
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "%s: After: mmal_ctrl:%p ctrl id:0x%x ctrl val:%d ret %d(%d)\n",
++ __func__, mmal_ctrl, ctrl->id, ctrl->val, ret,
++ (ret == 0 ? 0 : -EINVAL));
++ return (ret == 0 ? 0 : EINVAL);
++}
++
++static int ctrl_set_bitrate(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
++{
++ int ret;
++ struct vchiq_mmal_port *encoder_out;
++
++ dev->capture.encode_bitrate = ctrl->val;
++
++ encoder_out = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
++
++ ret = vchiq_mmal_port_parameter_set(dev->instance, encoder_out,
++ mmal_ctrl->mmal_id,
++ &ctrl->val, sizeof(ctrl->val));
++ ret = 0;
++ return ret;
++}
++
++static int ctrl_set_bitrate_mode(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
++{
++ u32 bitrate_mode;
++ struct vchiq_mmal_port *encoder_out;
++
++ encoder_out = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
++
++ dev->capture.encode_bitrate_mode = ctrl->val;
++ switch (ctrl->val) {
++ default:
++ case V4L2_MPEG_VIDEO_BITRATE_MODE_VBR:
++ bitrate_mode = MMAL_VIDEO_RATECONTROL_VARIABLE;
++ break;
++ case V4L2_MPEG_VIDEO_BITRATE_MODE_CBR:
++ bitrate_mode = MMAL_VIDEO_RATECONTROL_CONSTANT;
++ break;
++ }
++
++ vchiq_mmal_port_parameter_set(dev->instance, encoder_out,
++ mmal_ctrl->mmal_id,
++ &bitrate_mode,
++ sizeof(bitrate_mode));
++ return 0;
++}
++
++static int ctrl_set_image_encode_output(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
++{
++ u32 u32_value;
++ struct vchiq_mmal_port *jpeg_out;
++
++ jpeg_out = &dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->output[0];
++
++ u32_value = ctrl->val;
++
++ return vchiq_mmal_port_parameter_set(dev->instance, jpeg_out,
++ mmal_ctrl->mmal_id,
++ &u32_value, sizeof(u32_value));
++}
++
++static int ctrl_set_video_encode_param_output(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
++{
++ u32 u32_value;
++ struct vchiq_mmal_port *vid_enc_ctl;
++
++ vid_enc_ctl = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
++
++ u32_value = ctrl->val;
++
++ return vchiq_mmal_port_parameter_set(dev->instance, vid_enc_ctl,
++ mmal_ctrl->mmal_id,
++ &u32_value, sizeof(u32_value));
++}
++
++static int ctrl_set_video_encode_profile_level(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
++{
++ struct mmal_parameter_video_profile param;
++ int ret = 0;
++
++ if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_PROFILE) {
++ switch (ctrl->val) {
++ case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
++ case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
++ case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
++ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
++ dev->capture.enc_profile = ctrl->val;
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
++ } else if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_LEVEL) {
++ switch (ctrl->val) {
++ case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
++ case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
++ case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
++ case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
++ case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
++ case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
++ case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
++ case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
++ case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
++ case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
++ case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
++ case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
++ dev->capture.enc_level = ctrl->val;
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
++ }
++
++ if (!ret) {
++ switch (dev->capture.enc_profile) {
++ case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
++ param.profile = MMAL_VIDEO_PROFILE_H264_BASELINE;
++ break;
++ case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
++ param.profile =
++ MMAL_VIDEO_PROFILE_H264_CONSTRAINED_BASELINE;
++ break;
++ case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
++ param.profile = MMAL_VIDEO_PROFILE_H264_MAIN;
++ break;
++ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
++ param.profile = MMAL_VIDEO_PROFILE_H264_HIGH;
++ break;
++ default:
++ /* Should never get here */
++ break;
++ }
++
++ switch (dev->capture.enc_level) {
++ case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
++ param.level = MMAL_VIDEO_LEVEL_H264_1;
++ break;
++ case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
++ param.level = MMAL_VIDEO_LEVEL_H264_1b;
++ break;
++ case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
++ param.level = MMAL_VIDEO_LEVEL_H264_11;
++ break;
++ case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
++ param.level = MMAL_VIDEO_LEVEL_H264_12;
++ break;
++ case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
++ param.level = MMAL_VIDEO_LEVEL_H264_13;
++ break;
++ case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
++ param.level = MMAL_VIDEO_LEVEL_H264_2;
++ break;
++ case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
++ param.level = MMAL_VIDEO_LEVEL_H264_21;
++ break;
++ case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
++ param.level = MMAL_VIDEO_LEVEL_H264_22;
++ break;
++ case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
++ param.level = MMAL_VIDEO_LEVEL_H264_3;
++ break;
++ case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
++ param.level = MMAL_VIDEO_LEVEL_H264_31;
++ break;
++ case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
++ param.level = MMAL_VIDEO_LEVEL_H264_32;
++ break;
++ case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
++ param.level = MMAL_VIDEO_LEVEL_H264_4;
++ break;
++ default:
++ /* Should never get here */
++ break;
++ }
++
++ ret = vchiq_mmal_port_parameter_set(dev->instance,
++ &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0],
++ mmal_ctrl->mmal_id,
++ &param, sizeof(param));
++ }
++ return ret;
++}
++
++static int ctrl_set_scene_mode(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl *ctrl,
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
++{
++ int ret = 0;
++ int shutter_speed;
++ struct vchiq_mmal_port *control;
++
++ v4l2_dbg(0, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "scene mode selected %d, was %d\n", ctrl->val,
++ dev->scene_mode);
++ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
++
++ if (ctrl->val == dev->scene_mode)
++ return 0;
++
++ if (ctrl->val == V4L2_SCENE_MODE_NONE) {
++ /* Restore all user selections */
++ dev->scene_mode = V4L2_SCENE_MODE_NONE;
++
++ if (dev->exposure_mode_user == MMAL_PARAM_EXPOSUREMODE_OFF)
++ shutter_speed = dev->manual_shutter_speed;
++ else
++ shutter_speed = 0;
++
++ v4l2_dbg(0, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "%s: scene mode none: shut_speed %d, exp_mode %d, metering %d\n",
++ __func__, shutter_speed, dev->exposure_mode_user,
++ dev->metering_mode);
++ ret = vchiq_mmal_port_parameter_set(dev->instance,
++ control,
++ MMAL_PARAMETER_SHUTTER_SPEED,
++ &shutter_speed,
++ sizeof(shutter_speed));
++ ret += vchiq_mmal_port_parameter_set(dev->instance,
++ control,
++ MMAL_PARAMETER_EXPOSURE_MODE,
++ &dev->exposure_mode_user,
++ sizeof(u32));
++ dev->exposure_mode_active = dev->exposure_mode_user;
++ ret += vchiq_mmal_port_parameter_set(dev->instance,
++ control,
++ MMAL_PARAMETER_EXP_METERING_MODE,
++ &dev->metering_mode,
++ sizeof(u32));
++ ret += set_framerate_params(dev);
++ } else {
++ /* Set up scene mode */
++ int i;
++ const struct v4l2_mmal_scene_config *scene = NULL;
++ int shutter_speed;
++ enum mmal_parameter_exposuremode exposure_mode;
++ enum mmal_parameter_exposuremeteringmode metering_mode;
++
++ for (i = 0; i < ARRAY_SIZE(scene_configs); i++) {
++ if (scene_configs[i].v4l2_scene ==
++ ctrl->val) {
++ scene = &scene_configs[i];
++ break;
++ }
++ }
++ if (!scene)
++ return -EINVAL;
++ if (i >= ARRAY_SIZE(scene_configs))
++ return -EINVAL;
++
++ /* Set all the values */
++ dev->scene_mode = ctrl->val;
++
++ if (scene->exposure_mode == MMAL_PARAM_EXPOSUREMODE_OFF)
++ shutter_speed = dev->manual_shutter_speed;
++ else
++ shutter_speed = 0;
++ exposure_mode = scene->exposure_mode;
++ metering_mode = scene->metering_mode;
++
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "%s: scene mode none: shut_speed %d, exp_mode %d, metering %d\n",
++ __func__, shutter_speed, exposure_mode, metering_mode);
++
++ ret = vchiq_mmal_port_parameter_set(dev->instance, control,
++ MMAL_PARAMETER_SHUTTER_SPEED,
++ &shutter_speed,
++ sizeof(shutter_speed));
++ ret += vchiq_mmal_port_parameter_set(dev->instance,
++ control,
++ MMAL_PARAMETER_EXPOSURE_MODE,
++ &exposure_mode,
++ sizeof(u32));
++ dev->exposure_mode_active = exposure_mode;
++ ret += vchiq_mmal_port_parameter_set(dev->instance, control,
++ MMAL_PARAMETER_EXPOSURE_MODE,
++ &exposure_mode,
++ sizeof(u32));
++ ret += vchiq_mmal_port_parameter_set(dev->instance, control,
++ MMAL_PARAMETER_EXP_METERING_MODE,
++ &metering_mode,
++ sizeof(u32));
++ ret += set_framerate_params(dev);
++ }
++ if (ret) {
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "%s: Setting scene to %d, ret=%d\n",
++ __func__, ctrl->val, ret);
++ ret = -EINVAL;
++ }
++ return 0;
++}
++
++static int bm2835_mmal_s_ctrl(struct v4l2_ctrl *ctrl)
++{
++ struct bm2835_mmal_dev *dev =
++ container_of(ctrl->handler, struct bm2835_mmal_dev,
++ ctrl_handler);
++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl = ctrl->priv;
++ int ret;
++
++ if ((mmal_ctrl == NULL) ||
++ (mmal_ctrl->id != ctrl->id) ||
++ (mmal_ctrl->setter == NULL)) {
++ pr_warn("mmal_ctrl:%p ctrl id:%d\n", mmal_ctrl, ctrl->id);
++ return -EINVAL;
++ }
++
++ ret = mmal_ctrl->setter(dev, ctrl, mmal_ctrl);
++ if (ret)
++ pr_warn("ctrl id:%d/MMAL param %08X- returned ret %d\n",
++ ctrl->id, mmal_ctrl->mmal_id, ret);
++ if (mmal_ctrl->ignore_errors)
++ ret = 0;
++ return ret;
++}
++
++static const struct v4l2_ctrl_ops bm2835_mmal_ctrl_ops = {
++ .s_ctrl = bm2835_mmal_s_ctrl,
++};
++
++
++
++static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = {
++ {
++ V4L2_CID_SATURATION, MMAL_CONTROL_TYPE_STD,
++ -100, 100, 0, 1, NULL,
++ MMAL_PARAMETER_SATURATION,
++ &ctrl_set_rational,
++ false
++ },
++ {
++ V4L2_CID_SHARPNESS, MMAL_CONTROL_TYPE_STD,
++ -100, 100, 0, 1, NULL,
++ MMAL_PARAMETER_SHARPNESS,
++ &ctrl_set_rational,
++ false
++ },
++ {
++ V4L2_CID_CONTRAST, MMAL_CONTROL_TYPE_STD,
++ -100, 100, 0, 1, NULL,
++ MMAL_PARAMETER_CONTRAST,
++ &ctrl_set_rational,
++ false
++ },
++ {
++ V4L2_CID_BRIGHTNESS, MMAL_CONTROL_TYPE_STD,
++ 0, 100, 50, 1, NULL,
++ MMAL_PARAMETER_BRIGHTNESS,
++ &ctrl_set_rational,
++ false
++ },
++ {
++ V4L2_CID_ISO_SENSITIVITY, MMAL_CONTROL_TYPE_INT_MENU,
++ 0, ARRAY_SIZE(iso_qmenu) - 1, 0, 1, iso_qmenu,
++ MMAL_PARAMETER_ISO,
++ &ctrl_set_value_menu,
++ false
++ },
++ {
++ V4L2_CID_IMAGE_STABILIZATION, MMAL_CONTROL_TYPE_STD,
++ 0, 1, 0, 1, NULL,
++ MMAL_PARAMETER_VIDEO_STABILISATION,
++ &ctrl_set_value,
++ false
++ },
++/* {
++ 0, MMAL_CONTROL_TYPE_CLUSTER, 3, 1, 0, NULL, 0, NULL
++ }, */
++ {
++ V4L2_CID_EXPOSURE_AUTO, MMAL_CONTROL_TYPE_STD_MENU,
++ ~0x03, 3, V4L2_EXPOSURE_AUTO, 0, NULL,
++ MMAL_PARAMETER_EXPOSURE_MODE,
++ &ctrl_set_exposure,
++ false
++ },
++/* todo this needs mixing in with set exposure
++ {
++ V4L2_CID_SCENE_MODE, MMAL_CONTROL_TYPE_STD_MENU,
++ },
++ */
++ {
++ V4L2_CID_EXPOSURE_ABSOLUTE, MMAL_CONTROL_TYPE_STD,
++ /* Units of 100usecs */
++ 1, 1*1000*10, 100*10, 1, NULL,
++ MMAL_PARAMETER_SHUTTER_SPEED,
++ &ctrl_set_exposure,
++ false
++ },
++ {
++ V4L2_CID_AUTO_EXPOSURE_BIAS, MMAL_CONTROL_TYPE_INT_MENU,
++ 0, ARRAY_SIZE(ev_bias_qmenu) - 1,
++ (ARRAY_SIZE(ev_bias_qmenu)+1)/2 - 1, 0, ev_bias_qmenu,
++ MMAL_PARAMETER_EXPOSURE_COMP,
++ &ctrl_set_value_ev,
++ false
++ },
++ {
++ V4L2_CID_EXPOSURE_AUTO_PRIORITY, MMAL_CONTROL_TYPE_STD,
++ 0, 1,
++ 0, 1, NULL,
++ 0, /* Dummy MMAL ID as it gets mapped into FPS range*/
++ &ctrl_set_exposure,
++ false
++ },
++ {
++ V4L2_CID_EXPOSURE_METERING,
++ MMAL_CONTROL_TYPE_STD_MENU,
++ ~0x7, 2, V4L2_EXPOSURE_METERING_AVERAGE, 0, NULL,
++ MMAL_PARAMETER_EXP_METERING_MODE,
++ &ctrl_set_metering_mode,
++ false
++ },
++ {
++ V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
++ MMAL_CONTROL_TYPE_STD_MENU,
++ ~0x3ff, 9, V4L2_WHITE_BALANCE_AUTO, 0, NULL,
++ MMAL_PARAMETER_AWB_MODE,
++ &ctrl_set_awb_mode,
++ false
++ },
++ {
++ V4L2_CID_RED_BALANCE, MMAL_CONTROL_TYPE_STD,
++ 1, 7999, 1000, 1, NULL,
++ MMAL_PARAMETER_CUSTOM_AWB_GAINS,
++ &ctrl_set_awb_gains,
++ false
++ },
++ {
++ V4L2_CID_BLUE_BALANCE, MMAL_CONTROL_TYPE_STD,
++ 1, 7999, 1000, 1, NULL,
++ MMAL_PARAMETER_CUSTOM_AWB_GAINS,
++ &ctrl_set_awb_gains,
++ false
++ },
++ {
++ V4L2_CID_COLORFX, MMAL_CONTROL_TYPE_STD_MENU,
++ 0, 15, V4L2_COLORFX_NONE, 0, NULL,
++ MMAL_PARAMETER_IMAGE_EFFECT,
++ &ctrl_set_image_effect,
++ false
++ },
++ {
++ V4L2_CID_COLORFX_CBCR, MMAL_CONTROL_TYPE_STD,
++ 0, 0xffff, 0x8080, 1, NULL,
++ MMAL_PARAMETER_COLOUR_EFFECT,
++ &ctrl_set_colfx,
++ false
++ },
++ {
++ V4L2_CID_ROTATE, MMAL_CONTROL_TYPE_STD,
++ 0, 360, 0, 90, NULL,
++ MMAL_PARAMETER_ROTATION,
++ &ctrl_set_rotate,
++ false
++ },
++ {
++ V4L2_CID_HFLIP, MMAL_CONTROL_TYPE_STD,
++ 0, 1, 0, 1, NULL,
++ MMAL_PARAMETER_MIRROR,
++ &ctrl_set_flip,
++ false
++ },
++ {
++ V4L2_CID_VFLIP, MMAL_CONTROL_TYPE_STD,
++ 0, 1, 0, 1, NULL,
++ MMAL_PARAMETER_MIRROR,
++ &ctrl_set_flip,
++ false
++ },
++ {
++ V4L2_CID_MPEG_VIDEO_BITRATE_MODE, MMAL_CONTROL_TYPE_STD_MENU,
++ 0, ARRAY_SIZE(bitrate_mode_qmenu) - 1,
++ 0, 0, bitrate_mode_qmenu,
++ MMAL_PARAMETER_RATECONTROL,
++ &ctrl_set_bitrate_mode,
++ false
++ },
++ {
++ V4L2_CID_MPEG_VIDEO_BITRATE, MMAL_CONTROL_TYPE_STD,
++ 25*1000, 25*1000*1000, 10*1000*1000, 25*1000, NULL,
++ MMAL_PARAMETER_VIDEO_BIT_RATE,
++ &ctrl_set_bitrate,
++ false
++ },
++ {
++ V4L2_CID_JPEG_COMPRESSION_QUALITY, MMAL_CONTROL_TYPE_STD,
++ 1, 100,
++ 30, 1, NULL,
++ MMAL_PARAMETER_JPEG_Q_FACTOR,
++ &ctrl_set_image_encode_output,
++ false
++ },
++ {
++ V4L2_CID_POWER_LINE_FREQUENCY, MMAL_CONTROL_TYPE_STD_MENU,
++ 0, ARRAY_SIZE(mains_freq_qmenu) - 1,
++ 1, 1, NULL,
++ MMAL_PARAMETER_FLICKER_AVOID,
++ &ctrl_set_flicker_avoidance,
++ false
++ },
++ {
++ V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER, MMAL_CONTROL_TYPE_STD,
++ 0, 1,
++ 0, 1, NULL,
++ MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER,
++ &ctrl_set_video_encode_param_output,
++ true /* Errors ignored as requires latest firmware to work */
++ },
++ {
++ V4L2_CID_MPEG_VIDEO_H264_PROFILE,
++ MMAL_CONTROL_TYPE_STD_MENU,
++ ~((1<<V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
++ (1<<V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) |
++ (1<<V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
++ (1<<V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)),
++ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
++ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, 1, NULL,
++ MMAL_PARAMETER_PROFILE,
++ &ctrl_set_video_encode_profile_level,
++ false
++ },
++ {
++ V4L2_CID_MPEG_VIDEO_H264_LEVEL, MMAL_CONTROL_TYPE_STD_MENU,
++ ~((1<<V4L2_MPEG_VIDEO_H264_LEVEL_1_0) |
++ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_1B) |
++ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_1_1) |
++ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_1_2) |
++ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_1_3) |
++ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
++ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_2_1) |
++ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_2_2) |
++ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_3_0) |
++ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_3_1) |
++ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
++ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_4_0)),
++ V4L2_MPEG_VIDEO_H264_LEVEL_4_0,
++ V4L2_MPEG_VIDEO_H264_LEVEL_4_0, 1, NULL,
++ MMAL_PARAMETER_PROFILE,
++ &ctrl_set_video_encode_profile_level,
++ false
++ },
++ {
++ V4L2_CID_SCENE_MODE, MMAL_CONTROL_TYPE_STD_MENU,
++ -1, /* Min is computed at runtime */
++ V4L2_SCENE_MODE_TEXT,
++ V4L2_SCENE_MODE_NONE, 1, NULL,
++ MMAL_PARAMETER_PROFILE,
++ &ctrl_set_scene_mode,
++ false
++ },
++ {
++ V4L2_CID_MPEG_VIDEO_H264_I_PERIOD, MMAL_CONTROL_TYPE_STD,
++ 0, 0x7FFFFFFF, 60, 1, NULL,
++ MMAL_PARAMETER_INTRAPERIOD,
++ &ctrl_set_video_encode_param_output,
++ false
++ },
++};
++
++int bm2835_mmal_set_all_camera_controls(struct bm2835_mmal_dev *dev)
++{
++ int c;
++ int ret = 0;
++
++ for (c = 0; c < V4L2_CTRL_COUNT; c++) {
++ if ((dev->ctrls[c]) && (v4l2_ctrls[c].setter)) {
++ ret = v4l2_ctrls[c].setter(dev, dev->ctrls[c],
++ &v4l2_ctrls[c]);
++ if (!v4l2_ctrls[c].ignore_errors && ret) {
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "Failed when setting default values for ctrl %d\n",
++ c);
++ break;
++ }
++ }
++ }
++ return ret;
++}
++
++int set_framerate_params(struct bm2835_mmal_dev *dev)
++{
++ struct mmal_parameter_fps_range fps_range;
++ int ret;
++
++ if ((dev->exposure_mode_active != MMAL_PARAM_EXPOSUREMODE_OFF) &&
++ (dev->exp_auto_priority)) {
++ /* Variable FPS. Define min FPS as 1fps.
++ * Max as max defined FPS.
++ */
++ fps_range.fps_low.num = 1;
++ fps_range.fps_low.den = 1;
++ fps_range.fps_high.num = dev->capture.timeperframe.denominator;
++ fps_range.fps_high.den = dev->capture.timeperframe.numerator;
++ } else {
++ /* Fixed FPS - set min and max to be the same */
++ fps_range.fps_low.num = fps_range.fps_high.num =
++ dev->capture.timeperframe.denominator;
++ fps_range.fps_low.den = fps_range.fps_high.den =
++ dev->capture.timeperframe.numerator;
++ }
++
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "Set fps range to %d/%d to %d/%d\n",
++ fps_range.fps_low.num,
++ fps_range.fps_low.den,
++ fps_range.fps_high.num,
++ fps_range.fps_high.den
++ );
++
++ ret = vchiq_mmal_port_parameter_set(dev->instance,
++ &dev->component[MMAL_COMPONENT_CAMERA]->
++ output[MMAL_CAMERA_PORT_PREVIEW],
++ MMAL_PARAMETER_FPS_RANGE,
++ &fps_range, sizeof(fps_range));
++ ret += vchiq_mmal_port_parameter_set(dev->instance,
++ &dev->component[MMAL_COMPONENT_CAMERA]->
++ output[MMAL_CAMERA_PORT_VIDEO],
++ MMAL_PARAMETER_FPS_RANGE,
++ &fps_range, sizeof(fps_range));
++ ret += vchiq_mmal_port_parameter_set(dev->instance,
++ &dev->component[MMAL_COMPONENT_CAMERA]->
++ output[MMAL_CAMERA_PORT_CAPTURE],
++ MMAL_PARAMETER_FPS_RANGE,
++ &fps_range, sizeof(fps_range));
++ if (ret)
++ v4l2_dbg(0, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "Failed to set fps ret %d\n",
++ ret);
++
++ return ret;
++
++}
++
++int bm2835_mmal_init_controls(struct bm2835_mmal_dev *dev,
++ struct v4l2_ctrl_handler *hdl)
++{
++ int c;
++ const struct bm2835_mmal_v4l2_ctrl *ctrl;
++
++ v4l2_ctrl_handler_init(hdl, V4L2_CTRL_COUNT);
++
++ for (c = 0; c < V4L2_CTRL_COUNT; c++) {
++ ctrl = &v4l2_ctrls[c];
++
++ switch (ctrl->type) {
++ case MMAL_CONTROL_TYPE_STD:
++ dev->ctrls[c] = v4l2_ctrl_new_std(hdl,
++ &bm2835_mmal_ctrl_ops, ctrl->id,
++ ctrl->min, ctrl->max, ctrl->step, ctrl->def);
++ break;
++
++ case MMAL_CONTROL_TYPE_STD_MENU:
++ {
++ int mask = ctrl->min;
++
++ if (ctrl->id == V4L2_CID_SCENE_MODE) {
++ /* Special handling to work out the mask
++ * value based on the scene_configs array
++ * at runtime. Reduces the chance of
++ * mismatches.
++ */
++ int i;
++ mask = 1<<V4L2_SCENE_MODE_NONE;
++ for (i = 0;
++ i < ARRAY_SIZE(scene_configs);
++ i++) {
++ mask |= 1<<scene_configs[i].v4l2_scene;
++ }
++ mask = ~mask;
++ }
++
++ dev->ctrls[c] = v4l2_ctrl_new_std_menu(hdl,
++ &bm2835_mmal_ctrl_ops, ctrl->id,
++ ctrl->max, mask, ctrl->def);
++ break;
++ }
++
++ case MMAL_CONTROL_TYPE_INT_MENU:
++ dev->ctrls[c] = v4l2_ctrl_new_int_menu(hdl,
++ &bm2835_mmal_ctrl_ops, ctrl->id,
++ ctrl->max, ctrl->def, ctrl->imenu);
++ break;
++
++ case MMAL_CONTROL_TYPE_CLUSTER:
++ /* skip this entry when constructing controls */
++ continue;
++ }
++
++ if (hdl->error)
++ break;
++
++ dev->ctrls[c]->priv = (void *)ctrl;
++ }
++
++ if (hdl->error) {
++ pr_err("error adding control %d/%d id 0x%x\n", c,
++ V4L2_CTRL_COUNT, ctrl->id);
++ return hdl->error;
++ }
++
++ for (c = 0; c < V4L2_CTRL_COUNT; c++) {
++ ctrl = &v4l2_ctrls[c];
++
++ switch (ctrl->type) {
++ case MMAL_CONTROL_TYPE_CLUSTER:
++ v4l2_ctrl_auto_cluster(ctrl->min,
++ &dev->ctrls[c+1],
++ ctrl->max,
++ ctrl->def);
++ break;
++
++ case MMAL_CONTROL_TYPE_STD:
++ case MMAL_CONTROL_TYPE_STD_MENU:
++ case MMAL_CONTROL_TYPE_INT_MENU:
++ break;
++ }
++
++ }
++
++ return 0;
++}
+--- /dev/null
++++ b/drivers/media/platform/bcm2835/mmal-common.h
+@@ -0,0 +1,53 @@
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file COPYING in the main directory of this archive
++ * for more details.
++ *
++ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
++ * Dave Stevenson <dsteve@broadcom.com>
++ * Simon Mellor <simellor@broadcom.com>
++ * Luke Diamand <luked@broadcom.com>
++ *
++ * MMAL structures
++ *
++ */
++
++#define MMAL_FOURCC(a, b, c, d) ((a) | (b << 8) | (c << 16) | (d << 24))
++#define MMAL_MAGIC MMAL_FOURCC('m', 'm', 'a', 'l')
++
++/** Special value signalling that time is not known */
++#define MMAL_TIME_UNKNOWN (1LL<<63)
++
++/* mapping between v4l and mmal video modes */
++struct mmal_fmt {
++ char *name;
++ u32 fourcc; /* v4l2 format id */
++ int flags; /* v4l2 flags field */
++ u32 mmal;
++ int depth;
++ u32 mmal_component; /* MMAL component index to be used to encode */
++ u32 ybbp; /* depth of first Y plane for planar formats */
++};
++
++/* buffer for one video frame */
++struct mmal_buffer {
++ /* v4l buffer data -- must be first */
++ struct vb2_v4l2_buffer vb;
++
++ /* list of buffers available */
++ struct list_head list;
++
++ void *buffer; /* buffer pointer */
++ unsigned long buffer_size; /* size of allocated buffer */
++};
++
++/* */
++struct mmal_colourfx {
++ s32 enable;
++ u32 u;
++ u32 v;
++};
+--- /dev/null
++++ b/drivers/media/platform/bcm2835/mmal-encodings.h
+@@ -0,0 +1,127 @@
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file COPYING in the main directory of this archive
++ * for more details.
++ *
++ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
++ * Dave Stevenson <dsteve@broadcom.com>
++ * Simon Mellor <simellor@broadcom.com>
++ * Luke Diamand <luked@broadcom.com>
++ */
++#ifndef MMAL_ENCODINGS_H
++#define MMAL_ENCODINGS_H
++
++#define MMAL_ENCODING_H264 MMAL_FOURCC('H', '2', '6', '4')
++#define MMAL_ENCODING_H263 MMAL_FOURCC('H', '2', '6', '3')
++#define MMAL_ENCODING_MP4V MMAL_FOURCC('M', 'P', '4', 'V')
++#define MMAL_ENCODING_MP2V MMAL_FOURCC('M', 'P', '2', 'V')
++#define MMAL_ENCODING_MP1V MMAL_FOURCC('M', 'P', '1', 'V')
++#define MMAL_ENCODING_WMV3 MMAL_FOURCC('W', 'M', 'V', '3')
++#define MMAL_ENCODING_WMV2 MMAL_FOURCC('W', 'M', 'V', '2')
++#define MMAL_ENCODING_WMV1 MMAL_FOURCC('W', 'M', 'V', '1')
++#define MMAL_ENCODING_WVC1 MMAL_FOURCC('W', 'V', 'C', '1')
++#define MMAL_ENCODING_VP8 MMAL_FOURCC('V', 'P', '8', ' ')
++#define MMAL_ENCODING_VP7 MMAL_FOURCC('V', 'P', '7', ' ')
++#define MMAL_ENCODING_VP6 MMAL_FOURCC('V', 'P', '6', ' ')
++#define MMAL_ENCODING_THEORA MMAL_FOURCC('T', 'H', 'E', 'O')
++#define MMAL_ENCODING_SPARK MMAL_FOURCC('S', 'P', 'R', 'K')
++#define MMAL_ENCODING_MJPEG MMAL_FOURCC('M', 'J', 'P', 'G')
++
++#define MMAL_ENCODING_JPEG MMAL_FOURCC('J', 'P', 'E', 'G')
++#define MMAL_ENCODING_GIF MMAL_FOURCC('G', 'I', 'F', ' ')
++#define MMAL_ENCODING_PNG MMAL_FOURCC('P', 'N', 'G', ' ')
++#define MMAL_ENCODING_PPM MMAL_FOURCC('P', 'P', 'M', ' ')
++#define MMAL_ENCODING_TGA MMAL_FOURCC('T', 'G', 'A', ' ')
++#define MMAL_ENCODING_BMP MMAL_FOURCC('B', 'M', 'P', ' ')
++
++#define MMAL_ENCODING_I420 MMAL_FOURCC('I', '4', '2', '0')
++#define MMAL_ENCODING_I420_SLICE MMAL_FOURCC('S', '4', '2', '0')
++#define MMAL_ENCODING_YV12 MMAL_FOURCC('Y', 'V', '1', '2')
++#define MMAL_ENCODING_I422 MMAL_FOURCC('I', '4', '2', '2')
++#define MMAL_ENCODING_I422_SLICE MMAL_FOURCC('S', '4', '2', '2')
++#define MMAL_ENCODING_YUYV MMAL_FOURCC('Y', 'U', 'Y', 'V')
++#define MMAL_ENCODING_YVYU MMAL_FOURCC('Y', 'V', 'Y', 'U')
++#define MMAL_ENCODING_UYVY MMAL_FOURCC('U', 'Y', 'V', 'Y')
++#define MMAL_ENCODING_VYUY MMAL_FOURCC('V', 'Y', 'U', 'Y')
++#define MMAL_ENCODING_NV12 MMAL_FOURCC('N', 'V', '1', '2')
++#define MMAL_ENCODING_NV21 MMAL_FOURCC('N', 'V', '2', '1')
++#define MMAL_ENCODING_ARGB MMAL_FOURCC('A', 'R', 'G', 'B')
++#define MMAL_ENCODING_RGBA MMAL_FOURCC('R', 'G', 'B', 'A')
++#define MMAL_ENCODING_ABGR MMAL_FOURCC('A', 'B', 'G', 'R')
++#define MMAL_ENCODING_BGRA MMAL_FOURCC('B', 'G', 'R', 'A')
++#define MMAL_ENCODING_RGB16 MMAL_FOURCC('R', 'G', 'B', '2')
++#define MMAL_ENCODING_RGB24 MMAL_FOURCC('R', 'G', 'B', '3')
++#define MMAL_ENCODING_RGB32 MMAL_FOURCC('R', 'G', 'B', '4')
++#define MMAL_ENCODING_BGR16 MMAL_FOURCC('B', 'G', 'R', '2')
++#define MMAL_ENCODING_BGR24 MMAL_FOURCC('B', 'G', 'R', '3')
++#define MMAL_ENCODING_BGR32 MMAL_FOURCC('B', 'G', 'R', '4')
++
++/** SAND Video (YUVUV128) format, native format understood by VideoCore.
++ * This format is *not* opaque - if requested you will receive full frames
++ * of YUV_UV video.
++ */
++#define MMAL_ENCODING_YUVUV128 MMAL_FOURCC('S', 'A', 'N', 'D')
++
++/** VideoCore opaque image format, image handles are returned to
++ * the host but not the actual image data.
++ */
++#define MMAL_ENCODING_OPAQUE MMAL_FOURCC('O', 'P', 'Q', 'V')
++
++/** An EGL image handle
++ */
++#define MMAL_ENCODING_EGL_IMAGE MMAL_FOURCC('E', 'G', 'L', 'I')
++
++/* }@ */
++
++/** \name Pre-defined audio encodings */
++/* @{ */
++#define MMAL_ENCODING_PCM_UNSIGNED_BE MMAL_FOURCC('P', 'C', 'M', 'U')
++#define MMAL_ENCODING_PCM_UNSIGNED_LE MMAL_FOURCC('p', 'c', 'm', 'u')
++#define MMAL_ENCODING_PCM_SIGNED_BE MMAL_FOURCC('P', 'C', 'M', 'S')
++#define MMAL_ENCODING_PCM_SIGNED_LE MMAL_FOURCC('p', 'c', 'm', 's')
++#define MMAL_ENCODING_PCM_FLOAT_BE MMAL_FOURCC('P', 'C', 'M', 'F')
++#define MMAL_ENCODING_PCM_FLOAT_LE MMAL_FOURCC('p', 'c', 'm', 'f')
++
++/* Pre-defined H264 encoding variants */
++
++/** ISO 14496-10 Annex B byte stream format */
++#define MMAL_ENCODING_VARIANT_H264_DEFAULT 0
++/** ISO 14496-15 AVC stream format */
++#define MMAL_ENCODING_VARIANT_H264_AVC1 MMAL_FOURCC('A', 'V', 'C', '1')
++/** Implicitly delineated NAL units without emulation prevention */
++#define MMAL_ENCODING_VARIANT_H264_RAW MMAL_FOURCC('R', 'A', 'W', ' ')
++
++
++/** \defgroup MmalColorSpace List of pre-defined video color spaces
++ * This defines a list of common color spaces. This list isn't exhaustive and
++ * is only provided as a convenience to avoid clients having to use FourCC
++ * codes directly. However components are allowed to define and use their own
++ * FourCC codes.
++ */
++/* @{ */
++
++/** Unknown color space */
++#define MMAL_COLOR_SPACE_UNKNOWN 0
++/** ITU-R BT.601-5 [SDTV] */
++#define MMAL_COLOR_SPACE_ITUR_BT601 MMAL_FOURCC('Y', '6', '0', '1')
++/** ITU-R BT.709-3 [HDTV] */
++#define MMAL_COLOR_SPACE_ITUR_BT709 MMAL_FOURCC('Y', '7', '0', '9')
++/** JPEG JFIF */
++#define MMAL_COLOR_SPACE_JPEG_JFIF MMAL_FOURCC('Y', 'J', 'F', 'I')
++/** Title 47 Code of Federal Regulations (2003) 73.682 (a) (20) */
++#define MMAL_COLOR_SPACE_FCC MMAL_FOURCC('Y', 'F', 'C', 'C')
++/** Society of Motion Picture and Television Engineers 240M (1999) */
++#define MMAL_COLOR_SPACE_SMPTE240M MMAL_FOURCC('Y', '2', '4', '0')
++/** ITU-R BT.470-2 System M */
++#define MMAL_COLOR_SPACE_BT470_2_M MMAL_FOURCC('Y', '_', '_', 'M')
++/** ITU-R BT.470-2 System BG */
++#define MMAL_COLOR_SPACE_BT470_2_BG MMAL_FOURCC('Y', '_', 'B', 'G')
++/** JPEG JFIF, but with 16..255 luma */
++#define MMAL_COLOR_SPACE_JFIF_Y16_255 MMAL_FOURCC('Y', 'Y', '1', '6')
++/* @} MmalColorSpace List */
++
++#endif /* MMAL_ENCODINGS_H */
+--- /dev/null
++++ b/drivers/media/platform/bcm2835/mmal-msg-common.h
+@@ -0,0 +1,50 @@
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file COPYING in the main directory of this archive
++ * for more details.
++ *
++ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
++ * Dave Stevenson <dsteve@broadcom.com>
++ * Simon Mellor <simellor@broadcom.com>
++ * Luke Diamand <luked@broadcom.com>
++ */
++
++#ifndef MMAL_MSG_COMMON_H
++#define MMAL_MSG_COMMON_H
++
++enum mmal_msg_status {
++ MMAL_MSG_STATUS_SUCCESS = 0, /**< Success */
++ MMAL_MSG_STATUS_ENOMEM, /**< Out of memory */
++ MMAL_MSG_STATUS_ENOSPC, /**< Out of resources other than memory */
++ MMAL_MSG_STATUS_EINVAL, /**< Argument is invalid */
++ MMAL_MSG_STATUS_ENOSYS, /**< Function not implemented */
++ MMAL_MSG_STATUS_ENOENT, /**< No such file or directory */
++ MMAL_MSG_STATUS_ENXIO, /**< No such device or address */
++ MMAL_MSG_STATUS_EIO, /**< I/O error */
++ MMAL_MSG_STATUS_ESPIPE, /**< Illegal seek */
++ MMAL_MSG_STATUS_ECORRUPT, /**< Data is corrupt \attention */
++ MMAL_MSG_STATUS_ENOTREADY, /**< Component is not ready */
++ MMAL_MSG_STATUS_ECONFIG, /**< Component is not configured */
++ MMAL_MSG_STATUS_EISCONN, /**< Port is already connected */
++ MMAL_MSG_STATUS_ENOTCONN, /**< Port is disconnected */
++ MMAL_MSG_STATUS_EAGAIN, /**< Resource temporarily unavailable. */
++ MMAL_MSG_STATUS_EFAULT, /**< Bad address */
++};
++
++struct mmal_rect {
++ s32 x; /**< x coordinate (from left) */
++ s32 y; /**< y coordinate (from top) */
++ s32 width; /**< width */
++ s32 height; /**< height */
++};
++
++struct mmal_rational {
++ s32 num; /**< Numerator */
++ s32 den; /**< Denominator */
++};
++
++#endif /* MMAL_MSG_COMMON_H */
+--- /dev/null
++++ b/drivers/media/platform/bcm2835/mmal-msg-format.h
+@@ -0,0 +1,81 @@
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file COPYING in the main directory of this archive
++ * for more details.
++ *
++ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
++ * Dave Stevenson <dsteve@broadcom.com>
++ * Simon Mellor <simellor@broadcom.com>
++ * Luke Diamand <luked@broadcom.com>
++ */
++
++#ifndef MMAL_MSG_FORMAT_H
++#define MMAL_MSG_FORMAT_H
++
++#include "mmal-msg-common.h"
++
++/* MMAL_ES_FORMAT_T */
++
++
++struct mmal_audio_format {
++ u32 channels; /**< Number of audio channels */
++ u32 sample_rate; /**< Sample rate */
++
++ u32 bits_per_sample; /**< Bits per sample */
++ u32 block_align; /**< Size of a block of data */
++};
++
++struct mmal_video_format {
++ u32 width; /**< Width of frame in pixels */
++ u32 height; /**< Height of frame in rows of pixels */
++ struct mmal_rect crop; /**< Visible region of the frame */
++ struct mmal_rational frame_rate; /**< Frame rate */
++ struct mmal_rational par; /**< Pixel aspect ratio */
++
++ /* FourCC specifying the color space of the video stream. See the
++ * \ref MmalColorSpace "pre-defined color spaces" for some examples.
++ */
++ u32 color_space;
++};
++
++struct mmal_subpicture_format {
++ u32 x_offset;
++ u32 y_offset;
++};
++
++union mmal_es_specific_format {
++ struct mmal_audio_format audio;
++ struct mmal_video_format video;
++ struct mmal_subpicture_format subpicture;
++};
++
++/** Definition of an elementary stream format (MMAL_ES_FORMAT_T) */
++struct mmal_es_format {
++ u32 type; /* enum mmal_es_type */
++
++ u32 encoding; /* FourCC specifying encoding of the elementary stream.*/
++ u32 encoding_variant; /* FourCC specifying the specific
++ * encoding variant of the elementary
++ * stream.
++ */
++
++ union mmal_es_specific_format *es; /* TODO: pointers in
++ * message serialisation?!?
++ */
++ /* Type specific
++ * information for the
++ * elementary stream
++ */
++
++ u32 bitrate; /**< Bitrate in bits per second */
++ u32 flags; /**< Flags describing properties of the elementary stream. */
++
++ u32 extradata_size; /**< Size of the codec specific data */
++ u8 *extradata; /**< Codec specific data */
++};
++
++#endif /* MMAL_MSG_FORMAT_H */
+--- /dev/null
++++ b/drivers/media/platform/bcm2835/mmal-msg-port.h
+@@ -0,0 +1,107 @@
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file COPYING in the main directory of this archive
++ * for more details.
++ *
++ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
++ * Dave Stevenson <dsteve@broadcom.com>
++ * Simon Mellor <simellor@broadcom.com>
++ * Luke Diamand <luked@broadcom.com>
++ */
++
++/* MMAL_PORT_TYPE_T */
++enum mmal_port_type {
++ MMAL_PORT_TYPE_UNKNOWN = 0, /**< Unknown port type */
++ MMAL_PORT_TYPE_CONTROL, /**< Control port */
++ MMAL_PORT_TYPE_INPUT, /**< Input port */
++ MMAL_PORT_TYPE_OUTPUT, /**< Output port */
++ MMAL_PORT_TYPE_CLOCK, /**< Clock port */
++};
++
++/** The port is pass-through and doesn't need buffer headers allocated */
++#define MMAL_PORT_CAPABILITY_PASSTHROUGH 0x01
++/** The port wants to allocate the buffer payloads.
++ * This signals a preference that payload allocation should be done
++ * on this port for efficiency reasons. */
++#define MMAL_PORT_CAPABILITY_ALLOCATION 0x02
++/** The port supports format change events.
++ * This applies to input ports and is used to let the client know
++ * whether the port supports being reconfigured via a format
++ * change event (i.e. without having to disable the port). */
++#define MMAL_PORT_CAPABILITY_SUPPORTS_EVENT_FORMAT_CHANGE 0x04
++
++/* mmal port structure (MMAL_PORT_T)
++ *
++ * most elements are informational only, the pointer values for
++ * interogation messages are generally provided as additional
++ * strucures within the message. When used to set values only teh
++ * buffer_num, buffer_size and userdata parameters are writable.
++ */
++struct mmal_port {
++ void *priv; /* Private member used by the framework */
++ const char *name; /* Port name. Used for debugging purposes (RO) */
++
++ u32 type; /* Type of the port (RO) enum mmal_port_type */
++ u16 index; /* Index of the port in its type list (RO) */
++ u16 index_all; /* Index of the port in the list of all ports (RO) */
++
++ u32 is_enabled; /* Indicates whether the port is enabled or not (RO) */
++ struct mmal_es_format *format; /* Format of the elementary stream */
++
++ u32 buffer_num_min; /* Minimum number of buffers the port
++ * requires (RO). This is set by the
++ * component.
++ */
++
++ u32 buffer_size_min; /* Minimum size of buffers the port
++ * requires (RO). This is set by the
++ * component.
++ */
++
++ u32 buffer_alignment_min; /* Minimum alignment requirement for
++ * the buffers (RO). A value of
++ * zero means no special alignment
++ * requirements. This is set by the
++ * component.
++ */
++
++ u32 buffer_num_recommended; /* Number of buffers the port
++ * recommends for optimal
++ * performance (RO). A value of
++ * zero means no special
++ * recommendation. This is set
++ * by the component.
++ */
++
++ u32 buffer_size_recommended; /* Size of buffers the port
++ * recommends for optimal
++ * performance (RO). A value of
++ * zero means no special
++ * recommendation. This is set
++ * by the component.
++ */
++
++ u32 buffer_num; /* Actual number of buffers the port will use.
++ * This is set by the client.
++ */
++
++ u32 buffer_size; /* Actual maximum size of the buffers that
++ * will be sent to the port. This is set by
++ * the client.
++ */
++
++ void *component; /* Component this port belongs to (Read Only) */
++
++ void *userdata; /* Field reserved for use by the client */
++
++ u32 capabilities; /* Flags describing the capabilities of a
++ * port (RO). Bitwise combination of \ref
++ * portcapabilities "Port capabilities"
++ * values.
++ */
++
++};
+--- /dev/null
++++ b/drivers/media/platform/bcm2835/mmal-msg.h
+@@ -0,0 +1,404 @@
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file COPYING in the main directory of this archive
++ * for more details.
++ *
++ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
++ * Dave Stevenson <dsteve@broadcom.com>
++ * Simon Mellor <simellor@broadcom.com>
++ * Luke Diamand <luked@broadcom.com>
++ */
++
++/* all the data structures which serialise the MMAL protocol. note
++ * these are directly mapped onto the recived message data.
++ *
++ * BEWARE: They seem to *assume* pointers are u32 and that there is no
++ * structure padding!
++ *
++ * NOTE: this implementation uses kernel types to ensure sizes. Rather
++ * than assigning values to enums to force their size the
++ * implementation uses fixed size types and not the enums (though the
++ * comments have the actual enum type
++ */
++
++#define VC_MMAL_VER 15
++#define VC_MMAL_MIN_VER 10
++#define VC_MMAL_SERVER_NAME MAKE_FOURCC("mmal")
++
++/* max total message size is 512 bytes */
++#define MMAL_MSG_MAX_SIZE 512
++/* with six 32bit header elements max payload is therefore 488 bytes */
++#define MMAL_MSG_MAX_PAYLOAD 488
++
++#include "mmal-msg-common.h"
++#include "mmal-msg-format.h"
++#include "mmal-msg-port.h"
++
++enum mmal_msg_type {
++ MMAL_MSG_TYPE_QUIT = 1,
++ MMAL_MSG_TYPE_SERVICE_CLOSED,
++ MMAL_MSG_TYPE_GET_VERSION,
++ MMAL_MSG_TYPE_COMPONENT_CREATE,
++ MMAL_MSG_TYPE_COMPONENT_DESTROY, /* 5 */
++ MMAL_MSG_TYPE_COMPONENT_ENABLE,
++ MMAL_MSG_TYPE_COMPONENT_DISABLE,
++ MMAL_MSG_TYPE_PORT_INFO_GET,
++ MMAL_MSG_TYPE_PORT_INFO_SET,
++ MMAL_MSG_TYPE_PORT_ACTION, /* 10 */
++ MMAL_MSG_TYPE_BUFFER_FROM_HOST,
++ MMAL_MSG_TYPE_BUFFER_TO_HOST,
++ MMAL_MSG_TYPE_GET_STATS,
++ MMAL_MSG_TYPE_PORT_PARAMETER_SET,
++ MMAL_MSG_TYPE_PORT_PARAMETER_GET, /* 15 */
++ MMAL_MSG_TYPE_EVENT_TO_HOST,
++ MMAL_MSG_TYPE_GET_CORE_STATS_FOR_PORT,
++ MMAL_MSG_TYPE_OPAQUE_ALLOCATOR,
++ MMAL_MSG_TYPE_CONSUME_MEM,
++ MMAL_MSG_TYPE_LMK, /* 20 */
++ MMAL_MSG_TYPE_OPAQUE_ALLOCATOR_DESC,
++ MMAL_MSG_TYPE_DRM_GET_LHS32,
++ MMAL_MSG_TYPE_DRM_GET_TIME,
++ MMAL_MSG_TYPE_BUFFER_FROM_HOST_ZEROLEN,
++ MMAL_MSG_TYPE_PORT_FLUSH, /* 25 */
++ MMAL_MSG_TYPE_HOST_LOG,
++ MMAL_MSG_TYPE_MSG_LAST
++};
++
++/* port action request messages differ depending on the action type */
++enum mmal_msg_port_action_type {
++ MMAL_MSG_PORT_ACTION_TYPE_UNKNOWN = 0, /* Unkown action */
++ MMAL_MSG_PORT_ACTION_TYPE_ENABLE, /* Enable a port */
++ MMAL_MSG_PORT_ACTION_TYPE_DISABLE, /* Disable a port */
++ MMAL_MSG_PORT_ACTION_TYPE_FLUSH, /* Flush a port */
++ MMAL_MSG_PORT_ACTION_TYPE_CONNECT, /* Connect ports */
++ MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT, /* Disconnect ports */
++ MMAL_MSG_PORT_ACTION_TYPE_SET_REQUIREMENTS, /* Set buffer requirements*/
++};
++
++struct mmal_msg_header {
++ u32 magic;
++ u32 type; /** enum mmal_msg_type */
++
++ /* Opaque handle to the control service */
++ struct mmal_control_service *control_service;
++
++ struct mmal_msg_context *context; /** a u32 per message context */
++ u32 status; /** The status of the vchiq operation */
++ u32 padding;
++};
++
++/* Send from VC to host to report version */
++struct mmal_msg_version {
++ u32 flags;
++ u32 major;
++ u32 minor;
++ u32 minimum;
++};
++
++/* request to VC to create component */
++struct mmal_msg_component_create {
++ void *client_component; /* component context */
++ char name[128];
++ u32 pid; /* For debug */
++};
++
++/* reply from VC to component creation request */
++struct mmal_msg_component_create_reply {
++ u32 status; /** enum mmal_msg_status - how does this differ to
++ * the one in the header?
++ */
++ u32 component_handle; /* VideoCore handle for component */
++ u32 input_num; /* Number of input ports */
++ u32 output_num; /* Number of output ports */
++ u32 clock_num; /* Number of clock ports */
++};
++
++/* request to VC to destroy a component */
++struct mmal_msg_component_destroy {
++ u32 component_handle;
++};
++
++struct mmal_msg_component_destroy_reply {
++ u32 status; /** The component destruction status */
++};
++
++
++/* request and reply to VC to enable a component */
++struct mmal_msg_component_enable {
++ u32 component_handle;
++};
++
++struct mmal_msg_component_enable_reply {
++ u32 status; /** The component enable status */
++};
++
++
++/* request and reply to VC to disable a component */
++struct mmal_msg_component_disable {
++ u32 component_handle;
++};
++
++struct mmal_msg_component_disable_reply {
++ u32 status; /** The component disable status */
++};
++
++/* request to VC to get port information */
++struct mmal_msg_port_info_get {
++ u32 component_handle; /* component handle port is associated with */
++ u32 port_type; /* enum mmal_msg_port_type */
++ u32 index; /* port index to query */
++};
++
++/* reply from VC to get port info request */
++struct mmal_msg_port_info_get_reply {
++ u32 status; /** enum mmal_msg_status */
++ u32 component_handle; /* component handle port is associated with */
++ u32 port_type; /* enum mmal_msg_port_type */
++ u32 port_index; /* port indexed in query */
++ s32 found; /* unused */
++ u32 port_handle; /**< Handle to use for this port */
++ struct mmal_port port;
++ struct mmal_es_format format; /* elementry stream format */
++ union mmal_es_specific_format es; /* es type specific data */
++ u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE]; /* es extra data */
++};
++
++/* request to VC to set port information */
++struct mmal_msg_port_info_set {
++ u32 component_handle;
++ u32 port_type; /* enum mmal_msg_port_type */
++ u32 port_index; /* port indexed in query */
++ struct mmal_port port;
++ struct mmal_es_format format;
++ union mmal_es_specific_format es;
++ u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE];
++};
++
++/* reply from VC to port info set request */
++struct mmal_msg_port_info_set_reply {
++ u32 status;
++ u32 component_handle; /* component handle port is associated with */
++ u32 port_type; /* enum mmal_msg_port_type */
++ u32 index; /* port indexed in query */
++ s32 found; /* unused */
++ u32 port_handle; /**< Handle to use for this port */
++ struct mmal_port port;
++ struct mmal_es_format format;
++ union mmal_es_specific_format es;
++ u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE];
++};
++
++
++/* port action requests that take a mmal_port as a parameter */
++struct mmal_msg_port_action_port {
++ u32 component_handle;
++ u32 port_handle;
++ u32 action; /* enum mmal_msg_port_action_type */
++ struct mmal_port port;
++};
++
++/* port action requests that take handles as a parameter */
++struct mmal_msg_port_action_handle {
++ u32 component_handle;
++ u32 port_handle;
++ u32 action; /* enum mmal_msg_port_action_type */
++ u32 connect_component_handle;
++ u32 connect_port_handle;
++};
++
++struct mmal_msg_port_action_reply {
++ u32 status; /** The port action operation status */
++};
++
++
++
++
++/* MMAL buffer transfer */
++
++/** Size of space reserved in a buffer message for short messages. */
++#define MMAL_VC_SHORT_DATA 128
++
++/** Signals that the current payload is the end of the stream of data */
++#define MMAL_BUFFER_HEADER_FLAG_EOS (1<<0)
++/** Signals that the start of the current payload starts a frame */
++#define MMAL_BUFFER_HEADER_FLAG_FRAME_START (1<<1)
++/** Signals that the end of the current payload ends a frame */
++#define MMAL_BUFFER_HEADER_FLAG_FRAME_END (1<<2)
++/** Signals that the current payload contains only complete frames (>1) */
++#define MMAL_BUFFER_HEADER_FLAG_FRAME \
++ (MMAL_BUFFER_HEADER_FLAG_FRAME_START|MMAL_BUFFER_HEADER_FLAG_FRAME_END)
++/** Signals that the current payload is a keyframe (i.e. self decodable) */
++#define MMAL_BUFFER_HEADER_FLAG_KEYFRAME (1<<3)
++/** Signals a discontinuity in the stream of data (e.g. after a seek).
++ * Can be used for instance by a decoder to reset its state */
++#define MMAL_BUFFER_HEADER_FLAG_DISCONTINUITY (1<<4)
++/** Signals a buffer containing some kind of config data for the component
++ * (e.g. codec config data) */
++#define MMAL_BUFFER_HEADER_FLAG_CONFIG (1<<5)
++/** Signals an encrypted payload */
++#define MMAL_BUFFER_HEADER_FLAG_ENCRYPTED (1<<6)
++/** Signals a buffer containing side information */
++#define MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO (1<<7)
++/** Signals a buffer which is the snapshot/postview image from a stills
++ * capture
++ */
++#define MMAL_BUFFER_HEADER_FLAGS_SNAPSHOT (1<<8)
++/** Signals a buffer which contains data known to be corrupted */
++#define MMAL_BUFFER_HEADER_FLAG_CORRUPTED (1<<9)
++/** Signals that a buffer failed to be transmitted */
++#define MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED (1<<10)
++
++struct mmal_driver_buffer {
++ u32 magic;
++ u32 component_handle;
++ u32 port_handle;
++ void *client_context;
++};
++
++/* buffer header */
++struct mmal_buffer_header {
++ struct mmal_buffer_header *next; /* next header */
++ void *priv; /* framework private data */
++ u32 cmd;
++ void *data;
++ u32 alloc_size;
++ u32 length;
++ u32 offset;
++ u32 flags;
++ s64 pts;
++ s64 dts;
++ void *type;
++ void *user_data;
++};
++
++struct mmal_buffer_header_type_specific {
++ union {
++ struct {
++ u32 planes;
++ u32 offset[4];
++ u32 pitch[4];
++ u32 flags;
++ } video;
++ } u;
++};
++
++struct mmal_msg_buffer_from_host {
++ /* The front 32 bytes of the buffer header are copied
++ * back to us in the reply to allow for context. This
++ * area is used to store two mmal_driver_buffer structures to
++ * allow for multiple concurrent service users.
++ */
++ /* control data */
++ struct mmal_driver_buffer drvbuf;
++
++ /* referenced control data for passthrough buffer management */
++ struct mmal_driver_buffer drvbuf_ref;
++ struct mmal_buffer_header buffer_header; /* buffer header itself */
++ struct mmal_buffer_header_type_specific buffer_header_type_specific;
++ s32 is_zero_copy;
++ s32 has_reference;
++
++ /** allows short data to be xfered in control message */
++ u32 payload_in_message;
++ u8 short_data[MMAL_VC_SHORT_DATA];
++};
++
++
++/* port parameter setting */
++
++#define MMAL_WORKER_PORT_PARAMETER_SPACE 96
++
++struct mmal_msg_port_parameter_set {
++ u32 component_handle; /* component */
++ u32 port_handle; /* port */
++ u32 id; /* Parameter ID */
++ u32 size; /* Parameter size */
++ uint32_t value[MMAL_WORKER_PORT_PARAMETER_SPACE];
++};
++
++struct mmal_msg_port_parameter_set_reply {
++ u32 status; /** enum mmal_msg_status todo: how does this
++ * differ to the one in the header?
++ */
++};
++
++/* port parameter getting */
++
++struct mmal_msg_port_parameter_get {
++ u32 component_handle; /* component */
++ u32 port_handle; /* port */
++ u32 id; /* Parameter ID */
++ u32 size; /* Parameter size */
++};
++
++struct mmal_msg_port_parameter_get_reply {
++ u32 status; /* Status of mmal_port_parameter_get call */
++ u32 id; /* Parameter ID */
++ u32 size; /* Parameter size */
++ uint32_t value[MMAL_WORKER_PORT_PARAMETER_SPACE];
++};
++
++/* event messages */
++#define MMAL_WORKER_EVENT_SPACE 256
++
++struct mmal_msg_event_to_host {
++ void *client_component; /* component context */
++
++ u32 port_type;
++ u32 port_num;
++
++ u32 cmd;
++ u32 length;
++ u8 data[MMAL_WORKER_EVENT_SPACE];
++ struct mmal_buffer_header *delayed_buffer;
++};
++
++/* all mmal messages are serialised through this structure */
++struct mmal_msg {
++ /* header */
++ struct mmal_msg_header h;
++ /* payload */
++ union {
++ struct mmal_msg_version version;
++
++ struct mmal_msg_component_create component_create;
++ struct mmal_msg_component_create_reply component_create_reply;
++
++ struct mmal_msg_component_destroy component_destroy;
++ struct mmal_msg_component_destroy_reply component_destroy_reply;
++
++ struct mmal_msg_component_enable component_enable;
++ struct mmal_msg_component_enable_reply component_enable_reply;
++
++ struct mmal_msg_component_disable component_disable;
++ struct mmal_msg_component_disable_reply component_disable_reply;
++
++ struct mmal_msg_port_info_get port_info_get;
++ struct mmal_msg_port_info_get_reply port_info_get_reply;
++
++ struct mmal_msg_port_info_set port_info_set;
++ struct mmal_msg_port_info_set_reply port_info_set_reply;
++
++ struct mmal_msg_port_action_port port_action_port;
++ struct mmal_msg_port_action_handle port_action_handle;
++ struct mmal_msg_port_action_reply port_action_reply;
++
++ struct mmal_msg_buffer_from_host buffer_from_host;
++
++ struct mmal_msg_port_parameter_set port_parameter_set;
++ struct mmal_msg_port_parameter_set_reply
++ port_parameter_set_reply;
++ struct mmal_msg_port_parameter_get
++ port_parameter_get;
++ struct mmal_msg_port_parameter_get_reply
++ port_parameter_get_reply;
++
++ struct mmal_msg_event_to_host event_to_host;
++
++ u8 payload[MMAL_MSG_MAX_PAYLOAD];
++ } u;
++};
+--- /dev/null
++++ b/drivers/media/platform/bcm2835/mmal-parameters.h
+@@ -0,0 +1,656 @@
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file COPYING in the main directory of this archive
++ * for more details.
++ *
++ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
++ * Dave Stevenson <dsteve@broadcom.com>
++ * Simon Mellor <simellor@broadcom.com>
++ * Luke Diamand <luked@broadcom.com>
++ */
++
++/* common parameters */
++
++/** @name Parameter groups
++ * Parameters are divided into groups, and then allocated sequentially within
++ * a group using an enum.
++ * @{
++ */
++
++/** Common parameter ID group, used with many types of component. */
++#define MMAL_PARAMETER_GROUP_COMMON (0<<16)
++/** Camera-specific parameter ID group. */
++#define MMAL_PARAMETER_GROUP_CAMERA (1<<16)
++/** Video-specific parameter ID group. */
++#define MMAL_PARAMETER_GROUP_VIDEO (2<<16)
++/** Audio-specific parameter ID group. */
++#define MMAL_PARAMETER_GROUP_AUDIO (3<<16)
++/** Clock-specific parameter ID group. */
++#define MMAL_PARAMETER_GROUP_CLOCK (4<<16)
++/** Miracast-specific parameter ID group. */
++#define MMAL_PARAMETER_GROUP_MIRACAST (5<<16)
++
++/* Common parameters */
++enum mmal_parameter_common_type {
++ MMAL_PARAMETER_UNUSED /**< Never a valid parameter ID */
++ = MMAL_PARAMETER_GROUP_COMMON,
++ MMAL_PARAMETER_SUPPORTED_ENCODINGS, /**< MMAL_PARAMETER_ENCODING_T */
++ MMAL_PARAMETER_URI, /**< MMAL_PARAMETER_URI_T */
++
++ /** MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T */
++ MMAL_PARAMETER_CHANGE_EVENT_REQUEST,
++
++ /** MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_ZERO_COPY,
++
++ /**< MMAL_PARAMETER_BUFFER_REQUIREMENTS_T */
++ MMAL_PARAMETER_BUFFER_REQUIREMENTS,
++
++ MMAL_PARAMETER_STATISTICS, /**< MMAL_PARAMETER_STATISTICS_T */
++ MMAL_PARAMETER_CORE_STATISTICS, /**< MMAL_PARAMETER_CORE_STATISTICS_T */
++ MMAL_PARAMETER_MEM_USAGE, /**< MMAL_PARAMETER_MEM_USAGE_T */
++ MMAL_PARAMETER_BUFFER_FLAG_FILTER, /**< MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_SEEK, /**< MMAL_PARAMETER_SEEK_T */
++ MMAL_PARAMETER_POWERMON_ENABLE, /**< MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_LOGGING, /**< MMAL_PARAMETER_LOGGING_T */
++ MMAL_PARAMETER_SYSTEM_TIME, /**< MMAL_PARAMETER_UINT64_T */
++ MMAL_PARAMETER_NO_IMAGE_PADDING /**< MMAL_PARAMETER_BOOLEAN_T */
++};
++
++/* camera parameters */
++
++enum mmal_parameter_camera_type {
++ /* 0 */
++ /** @ref MMAL_PARAMETER_THUMBNAIL_CONFIG_T */
++ MMAL_PARAMETER_THUMBNAIL_CONFIGURATION
++ = MMAL_PARAMETER_GROUP_CAMERA,
++ MMAL_PARAMETER_CAPTURE_QUALITY, /**< Unused? */
++ MMAL_PARAMETER_ROTATION, /**< @ref MMAL_PARAMETER_INT32_T */
++ MMAL_PARAMETER_EXIF_DISABLE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_EXIF, /**< @ref MMAL_PARAMETER_EXIF_T */
++ MMAL_PARAMETER_AWB_MODE, /**< @ref MMAL_PARAM_AWBMODE_T */
++ MMAL_PARAMETER_IMAGE_EFFECT, /**< @ref MMAL_PARAMETER_IMAGEFX_T */
++ MMAL_PARAMETER_COLOUR_EFFECT, /**< @ref MMAL_PARAMETER_COLOURFX_T */
++ MMAL_PARAMETER_FLICKER_AVOID, /**< @ref MMAL_PARAMETER_FLICKERAVOID_T */
++ MMAL_PARAMETER_FLASH, /**< @ref MMAL_PARAMETER_FLASH_T */
++ MMAL_PARAMETER_REDEYE, /**< @ref MMAL_PARAMETER_REDEYE_T */
++ MMAL_PARAMETER_FOCUS, /**< @ref MMAL_PARAMETER_FOCUS_T */
++ MMAL_PARAMETER_FOCAL_LENGTHS, /**< Unused? */
++ MMAL_PARAMETER_EXPOSURE_COMP, /**< @ref MMAL_PARAMETER_INT32_T */
++ MMAL_PARAMETER_ZOOM, /**< @ref MMAL_PARAMETER_SCALEFACTOR_T */
++ MMAL_PARAMETER_MIRROR, /**< @ref MMAL_PARAMETER_MIRROR_T */
++
++ /* 0x10 */
++ MMAL_PARAMETER_CAMERA_NUM, /**< @ref MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_CAPTURE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_EXPOSURE_MODE, /**< @ref MMAL_PARAMETER_EXPOSUREMODE_T */
++ MMAL_PARAMETER_EXP_METERING_MODE, /**< @ref MMAL_PARAMETER_EXPOSUREMETERINGMODE_T */
++ MMAL_PARAMETER_FOCUS_STATUS, /**< @ref MMAL_PARAMETER_FOCUS_STATUS_T */
++ MMAL_PARAMETER_CAMERA_CONFIG, /**< @ref MMAL_PARAMETER_CAMERA_CONFIG_T */
++ MMAL_PARAMETER_CAPTURE_STATUS, /**< @ref MMAL_PARAMETER_CAPTURE_STATUS_T */
++ MMAL_PARAMETER_FACE_TRACK, /**< @ref MMAL_PARAMETER_FACE_TRACK_T */
++ MMAL_PARAMETER_DRAW_BOX_FACES_AND_FOCUS, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_JPEG_Q_FACTOR, /**< @ref MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_FRAME_RATE, /**< @ref MMAL_PARAMETER_FRAME_RATE_T */
++ MMAL_PARAMETER_USE_STC, /**< @ref MMAL_PARAMETER_CAMERA_STC_MODE_T */
++ MMAL_PARAMETER_CAMERA_INFO, /**< @ref MMAL_PARAMETER_CAMERA_INFO_T */
++ MMAL_PARAMETER_VIDEO_STABILISATION, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_FACE_TRACK_RESULTS, /**< @ref MMAL_PARAMETER_FACE_TRACK_RESULTS_T */
++ MMAL_PARAMETER_ENABLE_RAW_CAPTURE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++
++ /* 0x20 */
++ MMAL_PARAMETER_DPF_FILE, /**< @ref MMAL_PARAMETER_URI_T */
++ MMAL_PARAMETER_ENABLE_DPF_FILE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_DPF_FAIL_IS_FATAL, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_CAPTURE_MODE, /**< @ref MMAL_PARAMETER_CAPTUREMODE_T */
++ MMAL_PARAMETER_FOCUS_REGIONS, /**< @ref MMAL_PARAMETER_FOCUS_REGIONS_T */
++ MMAL_PARAMETER_INPUT_CROP, /**< @ref MMAL_PARAMETER_INPUT_CROP_T */
++ MMAL_PARAMETER_SENSOR_INFORMATION, /**< @ref MMAL_PARAMETER_SENSOR_INFORMATION_T */
++ MMAL_PARAMETER_FLASH_SELECT, /**< @ref MMAL_PARAMETER_FLASH_SELECT_T */
++ MMAL_PARAMETER_FIELD_OF_VIEW, /**< @ref MMAL_PARAMETER_FIELD_OF_VIEW_T */
++ MMAL_PARAMETER_HIGH_DYNAMIC_RANGE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_DYNAMIC_RANGE_COMPRESSION, /**< @ref MMAL_PARAMETER_DRC_T */
++ MMAL_PARAMETER_ALGORITHM_CONTROL, /**< @ref MMAL_PARAMETER_ALGORITHM_CONTROL_T */
++ MMAL_PARAMETER_SHARPNESS, /**< @ref MMAL_PARAMETER_RATIONAL_T */
++ MMAL_PARAMETER_CONTRAST, /**< @ref MMAL_PARAMETER_RATIONAL_T */
++ MMAL_PARAMETER_BRIGHTNESS, /**< @ref MMAL_PARAMETER_RATIONAL_T */
++ MMAL_PARAMETER_SATURATION, /**< @ref MMAL_PARAMETER_RATIONAL_T */
++
++ /* 0x30 */
++ MMAL_PARAMETER_ISO, /**< @ref MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_ANTISHAKE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++
++ /** @ref MMAL_PARAMETER_IMAGEFX_PARAMETERS_T */
++ MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_CAMERA_BURST_CAPTURE,
++
++ /** @ref MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_CAMERA_MIN_ISO,
++
++ /** @ref MMAL_PARAMETER_CAMERA_USE_CASE_T */
++ MMAL_PARAMETER_CAMERA_USE_CASE,
++
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_CAPTURE_STATS_PASS,
++
++ /** @ref MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_ENABLE_REGISTER_FILE,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_REGISTER_FAIL_IS_FATAL,
++
++ /** @ref MMAL_PARAMETER_CONFIGFILE_T */
++ MMAL_PARAMETER_CONFIGFILE_REGISTERS,
++
++ /** @ref MMAL_PARAMETER_CONFIGFILE_CHUNK_T */
++ MMAL_PARAMETER_CONFIGFILE_CHUNK_REGISTERS,
++ MMAL_PARAMETER_JPEG_ATTACH_LOG, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_ZERO_SHUTTER_LAG, /**< @ref MMAL_PARAMETER_ZEROSHUTTERLAG_T */
++ MMAL_PARAMETER_FPS_RANGE, /**< @ref MMAL_PARAMETER_FPS_RANGE_T */
++ MMAL_PARAMETER_CAPTURE_EXPOSURE_COMP, /**< @ref MMAL_PARAMETER_INT32_T */
++
++ /* 0x40 */
++ MMAL_PARAMETER_SW_SHARPEN_DISABLE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_FLASH_REQUIRED, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_SW_SATURATION_DISABLE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_SHUTTER_SPEED, /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_CUSTOM_AWB_GAINS, /**< Takes a @ref MMAL_PARAMETER_AWB_GAINS_T */
++};
++
++struct mmal_parameter_rational {
++ s32 num; /**< Numerator */
++ s32 den; /**< Denominator */
++};
++
++enum mmal_parameter_camera_config_timestamp_mode {
++ MMAL_PARAM_TIMESTAMP_MODE_ZERO = 0, /* Always timestamp frames as 0 */
++ MMAL_PARAM_TIMESTAMP_MODE_RAW_STC, /* Use the raw STC value
++ * for the frame timestamp
++ */
++ MMAL_PARAM_TIMESTAMP_MODE_RESET_STC, /* Use the STC timestamp
++ * but subtract the
++ * timestamp of the first
++ * frame sent to give a
++ * zero based timestamp.
++ */
++};
++
++struct mmal_parameter_fps_range {
++ /**< Low end of the permitted framerate range */
++ struct mmal_parameter_rational fps_low;
++ /**< High end of the permitted framerate range */
++ struct mmal_parameter_rational fps_high;
++};
++
++
++/* camera configuration parameter */
++struct mmal_parameter_camera_config {
++ /* Parameters for setting up the image pools */
++ u32 max_stills_w; /* Max size of stills capture */
++ u32 max_stills_h;
++ u32 stills_yuv422; /* Allow YUV422 stills capture */
++ u32 one_shot_stills; /* Continuous or one shot stills captures. */
++
++ u32 max_preview_video_w; /* Max size of the preview or video
++ * capture frames
++ */
++ u32 max_preview_video_h;
++ u32 num_preview_video_frames;
++
++ /** Sets the height of the circular buffer for stills capture. */
++ u32 stills_capture_circular_buffer_height;
++
++ /** Allows preview/encode to resume as fast as possible after the stills
++ * input frame has been received, and then processes the still frame in
++ * the background whilst preview/encode has resumed.
++ * Actual mode is controlled by MMAL_PARAMETER_CAPTURE_MODE.
++ */
++ u32 fast_preview_resume;
++
++ /** Selects algorithm for timestamping frames if
++ * there is no clock component connected.
++ * enum mmal_parameter_camera_config_timestamp_mode
++ */
++ s32 use_stc_timestamp;
++};
++
++
++enum mmal_parameter_exposuremode {
++ MMAL_PARAM_EXPOSUREMODE_OFF,
++ MMAL_PARAM_EXPOSUREMODE_AUTO,
++ MMAL_PARAM_EXPOSUREMODE_NIGHT,
++ MMAL_PARAM_EXPOSUREMODE_NIGHTPREVIEW,
++ MMAL_PARAM_EXPOSUREMODE_BACKLIGHT,
++ MMAL_PARAM_EXPOSUREMODE_SPOTLIGHT,
++ MMAL_PARAM_EXPOSUREMODE_SPORTS,
++ MMAL_PARAM_EXPOSUREMODE_SNOW,
++ MMAL_PARAM_EXPOSUREMODE_BEACH,
++ MMAL_PARAM_EXPOSUREMODE_VERYLONG,
++ MMAL_PARAM_EXPOSUREMODE_FIXEDFPS,
++ MMAL_PARAM_EXPOSUREMODE_ANTISHAKE,
++ MMAL_PARAM_EXPOSUREMODE_FIREWORKS,
++};
++
++enum mmal_parameter_exposuremeteringmode {
++ MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE,
++ MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT,
++ MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT,
++ MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX,
++};
++
++enum mmal_parameter_awbmode {
++ MMAL_PARAM_AWBMODE_OFF,
++ MMAL_PARAM_AWBMODE_AUTO,
++ MMAL_PARAM_AWBMODE_SUNLIGHT,
++ MMAL_PARAM_AWBMODE_CLOUDY,
++ MMAL_PARAM_AWBMODE_SHADE,
++ MMAL_PARAM_AWBMODE_TUNGSTEN,
++ MMAL_PARAM_AWBMODE_FLUORESCENT,
++ MMAL_PARAM_AWBMODE_INCANDESCENT,
++ MMAL_PARAM_AWBMODE_FLASH,
++ MMAL_PARAM_AWBMODE_HORIZON,
++};
++
++enum mmal_parameter_imagefx {
++ MMAL_PARAM_IMAGEFX_NONE,
++ MMAL_PARAM_IMAGEFX_NEGATIVE,
++ MMAL_PARAM_IMAGEFX_SOLARIZE,
++ MMAL_PARAM_IMAGEFX_POSTERIZE,
++ MMAL_PARAM_IMAGEFX_WHITEBOARD,
++ MMAL_PARAM_IMAGEFX_BLACKBOARD,
++ MMAL_PARAM_IMAGEFX_SKETCH,
++ MMAL_PARAM_IMAGEFX_DENOISE,
++ MMAL_PARAM_IMAGEFX_EMBOSS,
++ MMAL_PARAM_IMAGEFX_OILPAINT,
++ MMAL_PARAM_IMAGEFX_HATCH,
++ MMAL_PARAM_IMAGEFX_GPEN,
++ MMAL_PARAM_IMAGEFX_PASTEL,
++ MMAL_PARAM_IMAGEFX_WATERCOLOUR,
++ MMAL_PARAM_IMAGEFX_FILM,
++ MMAL_PARAM_IMAGEFX_BLUR,
++ MMAL_PARAM_IMAGEFX_SATURATION,
++ MMAL_PARAM_IMAGEFX_COLOURSWAP,
++ MMAL_PARAM_IMAGEFX_WASHEDOUT,
++ MMAL_PARAM_IMAGEFX_POSTERISE,
++ MMAL_PARAM_IMAGEFX_COLOURPOINT,
++ MMAL_PARAM_IMAGEFX_COLOURBALANCE,
++ MMAL_PARAM_IMAGEFX_CARTOON,
++};
++
++enum MMAL_PARAM_FLICKERAVOID_T {
++ MMAL_PARAM_FLICKERAVOID_OFF,
++ MMAL_PARAM_FLICKERAVOID_AUTO,
++ MMAL_PARAM_FLICKERAVOID_50HZ,
++ MMAL_PARAM_FLICKERAVOID_60HZ,
++ MMAL_PARAM_FLICKERAVOID_MAX = 0x7FFFFFFF
++};
++
++struct mmal_parameter_awbgains {
++ struct mmal_parameter_rational r_gain; /**< Red gain */
++ struct mmal_parameter_rational b_gain; /**< Blue gain */
++};
++
++/** Manner of video rate control */
++enum mmal_parameter_rate_control_mode {
++ MMAL_VIDEO_RATECONTROL_DEFAULT,
++ MMAL_VIDEO_RATECONTROL_VARIABLE,
++ MMAL_VIDEO_RATECONTROL_CONSTANT,
++ MMAL_VIDEO_RATECONTROL_VARIABLE_SKIP_FRAMES,
++ MMAL_VIDEO_RATECONTROL_CONSTANT_SKIP_FRAMES
++};
++
++enum mmal_video_profile {
++ MMAL_VIDEO_PROFILE_H263_BASELINE,
++ MMAL_VIDEO_PROFILE_H263_H320CODING,
++ MMAL_VIDEO_PROFILE_H263_BACKWARDCOMPATIBLE,
++ MMAL_VIDEO_PROFILE_H263_ISWV2,
++ MMAL_VIDEO_PROFILE_H263_ISWV3,
++ MMAL_VIDEO_PROFILE_H263_HIGHCOMPRESSION,
++ MMAL_VIDEO_PROFILE_H263_INTERNET,
++ MMAL_VIDEO_PROFILE_H263_INTERLACE,
++ MMAL_VIDEO_PROFILE_H263_HIGHLATENCY,
++ MMAL_VIDEO_PROFILE_MP4V_SIMPLE,
++ MMAL_VIDEO_PROFILE_MP4V_SIMPLESCALABLE,
++ MMAL_VIDEO_PROFILE_MP4V_CORE,
++ MMAL_VIDEO_PROFILE_MP4V_MAIN,
++ MMAL_VIDEO_PROFILE_MP4V_NBIT,
++ MMAL_VIDEO_PROFILE_MP4V_SCALABLETEXTURE,
++ MMAL_VIDEO_PROFILE_MP4V_SIMPLEFACE,
++ MMAL_VIDEO_PROFILE_MP4V_SIMPLEFBA,
++ MMAL_VIDEO_PROFILE_MP4V_BASICANIMATED,
++ MMAL_VIDEO_PROFILE_MP4V_HYBRID,
++ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDREALTIME,
++ MMAL_VIDEO_PROFILE_MP4V_CORESCALABLE,
++ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDCODING,
++ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDCORE,
++ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDSCALABLE,
++ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDSIMPLE,
++ MMAL_VIDEO_PROFILE_H264_BASELINE,
++ MMAL_VIDEO_PROFILE_H264_MAIN,
++ MMAL_VIDEO_PROFILE_H264_EXTENDED,
++ MMAL_VIDEO_PROFILE_H264_HIGH,
++ MMAL_VIDEO_PROFILE_H264_HIGH10,
++ MMAL_VIDEO_PROFILE_H264_HIGH422,
++ MMAL_VIDEO_PROFILE_H264_HIGH444,
++ MMAL_VIDEO_PROFILE_H264_CONSTRAINED_BASELINE,
++ MMAL_VIDEO_PROFILE_DUMMY = 0x7FFFFFFF
++};
++
++enum mmal_video_level {
++ MMAL_VIDEO_LEVEL_H263_10,
++ MMAL_VIDEO_LEVEL_H263_20,
++ MMAL_VIDEO_LEVEL_H263_30,
++ MMAL_VIDEO_LEVEL_H263_40,
++ MMAL_VIDEO_LEVEL_H263_45,
++ MMAL_VIDEO_LEVEL_H263_50,
++ MMAL_VIDEO_LEVEL_H263_60,
++ MMAL_VIDEO_LEVEL_H263_70,
++ MMAL_VIDEO_LEVEL_MP4V_0,
++ MMAL_VIDEO_LEVEL_MP4V_0b,
++ MMAL_VIDEO_LEVEL_MP4V_1,
++ MMAL_VIDEO_LEVEL_MP4V_2,
++ MMAL_VIDEO_LEVEL_MP4V_3,
++ MMAL_VIDEO_LEVEL_MP4V_4,
++ MMAL_VIDEO_LEVEL_MP4V_4a,
++ MMAL_VIDEO_LEVEL_MP4V_5,
++ MMAL_VIDEO_LEVEL_MP4V_6,
++ MMAL_VIDEO_LEVEL_H264_1,
++ MMAL_VIDEO_LEVEL_H264_1b,
++ MMAL_VIDEO_LEVEL_H264_11,
++ MMAL_VIDEO_LEVEL_H264_12,
++ MMAL_VIDEO_LEVEL_H264_13,
++ MMAL_VIDEO_LEVEL_H264_2,
++ MMAL_VIDEO_LEVEL_H264_21,
++ MMAL_VIDEO_LEVEL_H264_22,
++ MMAL_VIDEO_LEVEL_H264_3,
++ MMAL_VIDEO_LEVEL_H264_31,
++ MMAL_VIDEO_LEVEL_H264_32,
++ MMAL_VIDEO_LEVEL_H264_4,
++ MMAL_VIDEO_LEVEL_H264_41,
++ MMAL_VIDEO_LEVEL_H264_42,
++ MMAL_VIDEO_LEVEL_H264_5,
++ MMAL_VIDEO_LEVEL_H264_51,
++ MMAL_VIDEO_LEVEL_DUMMY = 0x7FFFFFFF
++};
++
++struct mmal_parameter_video_profile {
++ enum mmal_video_profile profile;
++ enum mmal_video_level level;
++};
++
++/* video parameters */
++
++enum mmal_parameter_video_type {
++ /** @ref MMAL_DISPLAYREGION_T */
++ MMAL_PARAMETER_DISPLAYREGION = MMAL_PARAMETER_GROUP_VIDEO,
++
++ /** @ref MMAL_PARAMETER_VIDEO_PROFILE_T */
++ MMAL_PARAMETER_SUPPORTED_PROFILES,
++
++ /** @ref MMAL_PARAMETER_VIDEO_PROFILE_T */
++ MMAL_PARAMETER_PROFILE,
++
++ /** @ref MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_INTRAPERIOD,
++
++ /** @ref MMAL_PARAMETER_VIDEO_RATECONTROL_T */
++ MMAL_PARAMETER_RATECONTROL,
++
++ /** @ref MMAL_PARAMETER_VIDEO_NALUNITFORMAT_T */
++ MMAL_PARAMETER_NALUNITFORMAT,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_MINIMISE_FRAGMENTATION,
++
++ /** @ref MMAL_PARAMETER_UINT32_T.
++ * Setting the value to zero resets to the default (one slice per frame).
++ */
++ MMAL_PARAMETER_MB_ROWS_PER_SLICE,
++
++ /** @ref MMAL_PARAMETER_VIDEO_LEVEL_EXTENSION_T */
++ MMAL_PARAMETER_VIDEO_LEVEL_EXTENSION,
++
++ /** @ref MMAL_PARAMETER_VIDEO_EEDE_ENABLE_T */
++ MMAL_PARAMETER_VIDEO_EEDE_ENABLE,
++
++ /** @ref MMAL_PARAMETER_VIDEO_EEDE_LOSSRATE_T */
++ MMAL_PARAMETER_VIDEO_EEDE_LOSSRATE,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T. Request an I-frame. */
++ MMAL_PARAMETER_VIDEO_REQUEST_I_FRAME,
++ /** @ref MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T */
++ MMAL_PARAMETER_VIDEO_INTRA_REFRESH,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T. */
++ MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT,
++
++ /** @ref MMAL_PARAMETER_UINT32_T. Run-time bit rate control */
++ MMAL_PARAMETER_VIDEO_BIT_RATE,
++
++ /** @ref MMAL_PARAMETER_FRAME_RATE_T */
++ MMAL_PARAMETER_VIDEO_FRAME_RATE,
++
++ /** @ref MMAL_PARAMETER_UINT32_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_MIN_QUANT,
++
++ /** @ref MMAL_PARAMETER_UINT32_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_MAX_QUANT,
++
++ /** @ref MMAL_PARAMETER_VIDEO_ENCODE_RC_MODEL_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_RC_MODEL,
++
++ MMAL_PARAMETER_EXTRA_BUFFERS, /**< @ref MMAL_PARAMETER_UINT32_T. */
++ /** @ref MMAL_PARAMETER_UINT32_T.
++ * Changing this parameter from the default can reduce frame rate
++ * because image buffers need to be re-pitched.
++ */
++ MMAL_PARAMETER_VIDEO_ALIGN_HORIZ,
++
++ /** @ref MMAL_PARAMETER_UINT32_T.
++ * Changing this parameter from the default can reduce frame rate
++ * because image buffers need to be re-pitched.
++ */
++ MMAL_PARAMETER_VIDEO_ALIGN_VERT,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T. */
++ MMAL_PARAMETER_VIDEO_DROPPABLE_PFRAMES,
++
++ /** @ref MMAL_PARAMETER_UINT32_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_INITIAL_QUANT,
++
++ /**< @ref MMAL_PARAMETER_UINT32_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_QP_P,
++
++ /**< @ref MMAL_PARAMETER_UINT32_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_RC_SLICE_DQUANT,
++
++ /** @ref MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_VIDEO_ENCODE_FRAME_LIMIT_BITS,
++
++ /** @ref MMAL_PARAMETER_UINT32_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_PEAK_RATE,
++
++ /* H264 specific parameters */
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_H264_DISABLE_CABAC,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_LATENCY,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_H264_AU_DELIMITERS,
++
++ /** @ref MMAL_PARAMETER_UINT32_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_H264_DEBLOCK_IDC,
++
++ /** @ref MMAL_PARAMETER_VIDEO_ENCODER_H264_MB_INTRA_MODES_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_H264_MB_INTRA_MODE,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_VIDEO_ENCODE_HEADER_ON_OPEN,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_VIDEO_ENCODE_PRECODE_FOR_QP,
++
++ /** @ref MMAL_PARAMETER_VIDEO_DRM_INIT_INFO_T. */
++ MMAL_PARAMETER_VIDEO_DRM_INIT_INFO,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_VIDEO_TIMESTAMP_FIFO,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_VIDEO_DECODE_ERROR_CONCEALMENT,
++
++ /** @ref MMAL_PARAMETER_VIDEO_DRM_PROTECT_BUFFER_T. */
++ MMAL_PARAMETER_VIDEO_DRM_PROTECT_BUFFER,
++
++ /** @ref MMAL_PARAMETER_BYTES_T */
++ MMAL_PARAMETER_VIDEO_DECODE_CONFIG_VD3,
++
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_VIDEO_ENCODE_H264_VCL_HRD_PARAMETERS,
++
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_DELAY_HRD_FLAG,
++
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER
++};
++
++/** Valid mirror modes */
++enum mmal_parameter_mirror {
++ MMAL_PARAM_MIRROR_NONE,
++ MMAL_PARAM_MIRROR_VERTICAL,
++ MMAL_PARAM_MIRROR_HORIZONTAL,
++ MMAL_PARAM_MIRROR_BOTH,
++};
++
++enum mmal_parameter_displaytransform {
++ MMAL_DISPLAY_ROT0 = 0,
++ MMAL_DISPLAY_MIRROR_ROT0 = 1,
++ MMAL_DISPLAY_MIRROR_ROT180 = 2,
++ MMAL_DISPLAY_ROT180 = 3,
++ MMAL_DISPLAY_MIRROR_ROT90 = 4,
++ MMAL_DISPLAY_ROT270 = 5,
++ MMAL_DISPLAY_ROT90 = 6,
++ MMAL_DISPLAY_MIRROR_ROT270 = 7,
++};
++
++enum mmal_parameter_displaymode {
++ MMAL_DISPLAY_MODE_FILL = 0,
++ MMAL_DISPLAY_MODE_LETTERBOX = 1,
++};
++
++enum mmal_parameter_displayset {
++ MMAL_DISPLAY_SET_NONE = 0,
++ MMAL_DISPLAY_SET_NUM = 1,
++ MMAL_DISPLAY_SET_FULLSCREEN = 2,
++ MMAL_DISPLAY_SET_TRANSFORM = 4,
++ MMAL_DISPLAY_SET_DEST_RECT = 8,
++ MMAL_DISPLAY_SET_SRC_RECT = 0x10,
++ MMAL_DISPLAY_SET_MODE = 0x20,
++ MMAL_DISPLAY_SET_PIXEL = 0x40,
++ MMAL_DISPLAY_SET_NOASPECT = 0x80,
++ MMAL_DISPLAY_SET_LAYER = 0x100,
++ MMAL_DISPLAY_SET_COPYPROTECT = 0x200,
++ MMAL_DISPLAY_SET_ALPHA = 0x400,
++};
++
++struct mmal_parameter_displayregion {
++ /** Bitfield that indicates which fields are set and should be
++ * used. All other fields will maintain their current value.
++ * \ref MMAL_DISPLAYSET_T defines the bits that can be
++ * combined.
++ */
++ u32 set;
++
++ /** Describes the display output device, with 0 typically
++ * being a directly connected LCD display. The actual values
++ * will depend on the hardware. Code using hard-wired numbers
++ * (e.g. 2) is certain to fail.
++ */
++
++ u32 display_num;
++ /** Indicates that we are using the full device screen area,
++ * rather than a window of the display. If zero, then
++ * dest_rect is used to specify a region of the display to
++ * use.
++ */
++
++ s32 fullscreen;
++ /** Indicates any rotation or flipping used to map frames onto
++ * the natural display orientation.
++ */
++ u32 transform; /* enum mmal_parameter_displaytransform */
++
++ /** Where to display the frame within the screen, if
++ * fullscreen is zero.
++ */
++ struct vchiq_mmal_rect dest_rect;
++
++ /** Indicates which area of the frame to display. If all
++ * values are zero, the whole frame will be used.
++ */
++ struct vchiq_mmal_rect src_rect;
++
++ /** If set to non-zero, indicates that any display scaling
++ * should disregard the aspect ratio of the frame region being
++ * displayed.
++ */
++ s32 noaspect;
++
++ /** Indicates how the image should be scaled to fit the
++ * display. \code MMAL_DISPLAY_MODE_FILL \endcode indicates
++ * that the image should fill the screen by potentially
++ * cropping the frames. Setting \code mode \endcode to \code
++ * MMAL_DISPLAY_MODE_LETTERBOX \endcode indicates that all the
++ * source region should be displayed and black bars added if
++ * necessary.
++ */
++ u32 mode; /* enum mmal_parameter_displaymode */
++
++ /** If non-zero, defines the width of a source pixel relative
++ * to \code pixel_y \endcode. If zero, then pixels default to
++ * being square.
++ */
++ u32 pixel_x;
++
++ /** If non-zero, defines the height of a source pixel relative
++ * to \code pixel_x \endcode. If zero, then pixels default to
++ * being square.
++ */
++ u32 pixel_y;
++
++ /** Sets the relative depth of the images, with greater values
++ * being in front of smaller values.
++ */
++ u32 layer;
++
++ /** Set to non-zero to ensure copy protection is used on
++ * output.
++ */
++ s32 copyprotect_required;
++
++ /** Level of opacity of the layer, where zero is fully
++ * transparent and 255 is fully opaque.
++ */
++ u32 alpha;
++};
++
++#define MMAL_MAX_IMAGEFX_PARAMETERS 5
++
++struct mmal_parameter_imagefx_parameters {
++ enum mmal_parameter_imagefx effect;
++ u32 num_effect_params;
++ u32 effect_parameter[MMAL_MAX_IMAGEFX_PARAMETERS];
++};
+--- /dev/null
++++ b/drivers/media/platform/bcm2835/mmal-vchiq.c
+@@ -0,0 +1,1916 @@
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file COPYING in the main directory of this archive
++ * for more details.
++ *
++ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
++ * Dave Stevenson <dsteve@broadcom.com>
++ * Simon Mellor <simellor@broadcom.com>
++ * Luke Diamand <luked@broadcom.com>
++ *
++ * V4L2 driver MMAL vchiq interface code
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/mutex.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/completion.h>
++#include <linux/vmalloc.h>
++#include <asm/cacheflush.h>
++#include <media/videobuf2-vmalloc.h>
++
++#include "mmal-common.h"
++#include "mmal-vchiq.h"
++#include "mmal-msg.h"
++
++#define USE_VCHIQ_ARM
++#include "interface/vchi/vchi.h"
++
++/* maximum number of components supported */
++#define VCHIQ_MMAL_MAX_COMPONENTS 4
++
++/*#define FULL_MSG_DUMP 1*/
++
++#ifdef DEBUG
++static const char *const msg_type_names[] = {
++ "UNKNOWN",
++ "QUIT",
++ "SERVICE_CLOSED",
++ "GET_VERSION",
++ "COMPONENT_CREATE",
++ "COMPONENT_DESTROY",
++ "COMPONENT_ENABLE",
++ "COMPONENT_DISABLE",
++ "PORT_INFO_GET",
++ "PORT_INFO_SET",
++ "PORT_ACTION",
++ "BUFFER_FROM_HOST",
++ "BUFFER_TO_HOST",
++ "GET_STATS",
++ "PORT_PARAMETER_SET",
++ "PORT_PARAMETER_GET",
++ "EVENT_TO_HOST",
++ "GET_CORE_STATS_FOR_PORT",
++ "OPAQUE_ALLOCATOR",
++ "CONSUME_MEM",
++ "LMK",
++ "OPAQUE_ALLOCATOR_DESC",
++ "DRM_GET_LHS32",
++ "DRM_GET_TIME",
++ "BUFFER_FROM_HOST_ZEROLEN",
++ "PORT_FLUSH",
++ "HOST_LOG",
++};
++#endif
++
++static const char *const port_action_type_names[] = {
++ "UNKNOWN",
++ "ENABLE",
++ "DISABLE",
++ "FLUSH",
++ "CONNECT",
++ "DISCONNECT",
++ "SET_REQUIREMENTS",
++};
++
++#if defined(DEBUG)
++#if defined(FULL_MSG_DUMP)
++#define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE) \
++ do { \
++ pr_debug(TITLE" type:%s(%d) length:%d\n", \
++ msg_type_names[(MSG)->h.type], \
++ (MSG)->h.type, (MSG_LEN)); \
++ print_hex_dump(KERN_DEBUG, "<<h: ", DUMP_PREFIX_OFFSET, \
++ 16, 4, (MSG), \
++ sizeof(struct mmal_msg_header), 1); \
++ print_hex_dump(KERN_DEBUG, "<<p: ", DUMP_PREFIX_OFFSET, \
++ 16, 4, \
++ ((u8 *)(MSG)) + sizeof(struct mmal_msg_header),\
++ (MSG_LEN) - sizeof(struct mmal_msg_header), 1); \
++ } while (0)
++#else
++#define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE) \
++ { \
++ pr_debug(TITLE" type:%s(%d) length:%d\n", \
++ msg_type_names[(MSG)->h.type], \
++ (MSG)->h.type, (MSG_LEN)); \
++ }
++#endif
++#else
++#define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE)
++#endif
++
++/* normal message context */
++struct mmal_msg_context {
++ union {
++ struct {
++ /* work struct for defered callback - must come first */
++ struct work_struct work;
++ /* mmal instance */
++ struct vchiq_mmal_instance *instance;
++ /* mmal port */
++ struct vchiq_mmal_port *port;
++ /* actual buffer used to store bulk reply */
++ struct mmal_buffer *buffer;
++ /* amount of buffer used */
++ unsigned long buffer_used;
++ /* MMAL buffer flags */
++ u32 mmal_flags;
++ /* Presentation and Decode timestamps */
++ s64 pts;
++ s64 dts;
++
++ int status; /* context status */
++
++ } bulk; /* bulk data */
++
++ struct {
++ /* message handle to release */
++ VCHI_HELD_MSG_T msg_handle;
++ /* pointer to received message */
++ struct mmal_msg *msg;
++ /* received message length */
++ u32 msg_len;
++ /* completion upon reply */
++ struct completion cmplt;
++ } sync; /* synchronous response */
++ } u;
++
++};
++
++struct vchiq_mmal_instance {
++ VCHI_SERVICE_HANDLE_T handle;
++
++ /* ensure serialised access to service */
++ struct mutex vchiq_mutex;
++
++ /* ensure serialised access to bulk operations */
++ struct mutex bulk_mutex;
++
++ /* vmalloc page to receive scratch bulk xfers into */
++ void *bulk_scratch;
++
++ /* component to use next */
++ int component_idx;
++ struct vchiq_mmal_component component[VCHIQ_MMAL_MAX_COMPONENTS];
++};
++
++static struct mmal_msg_context *get_msg_context(struct vchiq_mmal_instance
++ *instance)
++{
++ struct mmal_msg_context *msg_context;
++
++ /* todo: should this be allocated from a pool to avoid kmalloc */
++ msg_context = kmalloc(sizeof(*msg_context), GFP_KERNEL);
++ memset(msg_context, 0, sizeof(*msg_context));
++
++ return msg_context;
++}
++
++static void release_msg_context(struct mmal_msg_context *msg_context)
++{
++ kfree(msg_context);
++}
++
++/* deals with receipt of event to host message */
++static void event_to_host_cb(struct vchiq_mmal_instance *instance,
++ struct mmal_msg *msg, u32 msg_len)
++{
++ pr_debug("unhandled event\n");
++ pr_debug("component:%p port type:%d num:%d cmd:0x%x length:%d\n",
++ msg->u.event_to_host.client_component,
++ msg->u.event_to_host.port_type,
++ msg->u.event_to_host.port_num,
++ msg->u.event_to_host.cmd, msg->u.event_to_host.length);
++}
++
++/* workqueue scheduled callback
++ *
++ * we do this because it is important we do not call any other vchiq
++ * sync calls from witin the message delivery thread
++ */
++static void buffer_work_cb(struct work_struct *work)
++{
++ struct mmal_msg_context *msg_context = (struct mmal_msg_context *)work;
++
++ msg_context->u.bulk.port->buffer_cb(msg_context->u.bulk.instance,
++ msg_context->u.bulk.port,
++ msg_context->u.bulk.status,
++ msg_context->u.bulk.buffer,
++ msg_context->u.bulk.buffer_used,
++ msg_context->u.bulk.mmal_flags,
++ msg_context->u.bulk.dts,
++ msg_context->u.bulk.pts);
++
++ /* release message context */
++ release_msg_context(msg_context);
++}
++
++/* enqueue a bulk receive for a given message context */
++static int bulk_receive(struct vchiq_mmal_instance *instance,
++ struct mmal_msg *msg,
++ struct mmal_msg_context *msg_context)
++{
++ unsigned long rd_len;
++ unsigned long flags = 0;
++ int ret;
++
++ /* bulk mutex stops other bulk operations while we have a
++ * receive in progress - released in callback
++ */
++ ret = mutex_lock_interruptible(&instance->bulk_mutex);
++ if (ret != 0)
++ return ret;
++
++ rd_len = msg->u.buffer_from_host.buffer_header.length;
++
++ /* take buffer from queue */
++ spin_lock_irqsave(&msg_context->u.bulk.port->slock, flags);
++ if (list_empty(&msg_context->u.bulk.port->buffers)) {
++ spin_unlock_irqrestore(&msg_context->u.bulk.port->slock, flags);
++ pr_err("buffer list empty trying to submit bulk receive\n");
++
++ /* todo: this is a serious error, we should never have
++ * commited a buffer_to_host operation to the mmal
++ * port without the buffer to back it up (underflow
++ * handling) and there is no obvious way to deal with
++ * this - how is the mmal servie going to react when
++ * we fail to do the xfer and reschedule a buffer when
++ * it arrives? perhaps a starved flag to indicate a
++ * waiting bulk receive?
++ */
++
++ mutex_unlock(&instance->bulk_mutex);
++
++ return -EINVAL;
++ }
++
++ msg_context->u.bulk.buffer =
++ list_entry(msg_context->u.bulk.port->buffers.next,
++ struct mmal_buffer, list);
++ list_del(&msg_context->u.bulk.buffer->list);
++
++ spin_unlock_irqrestore(&msg_context->u.bulk.port->slock, flags);
++
++ /* ensure we do not overrun the available buffer */
++ if (rd_len > msg_context->u.bulk.buffer->buffer_size) {
++ rd_len = msg_context->u.bulk.buffer->buffer_size;
++ pr_warn("short read as not enough receive buffer space\n");
++ /* todo: is this the correct response, what happens to
++ * the rest of the message data?
++ */
++ }
++
++ /* store length */
++ msg_context->u.bulk.buffer_used = rd_len;
++ msg_context->u.bulk.mmal_flags =
++ msg->u.buffer_from_host.buffer_header.flags;
++ msg_context->u.bulk.dts = msg->u.buffer_from_host.buffer_header.dts;
++ msg_context->u.bulk.pts = msg->u.buffer_from_host.buffer_header.pts;
++
++ // only need to flush L1 cache here, as VCHIQ takes care of the L2
++ // cache.
++ __cpuc_flush_dcache_area(msg_context->u.bulk.buffer->buffer, rd_len);
++
++ /* queue the bulk submission */
++ vchi_service_use(instance->handle);
++ ret = vchi_bulk_queue_receive(instance->handle,
++ msg_context->u.bulk.buffer->buffer,
++ /* Actual receive needs to be a multiple
++ * of 4 bytes
++ */
++ (rd_len + 3) & ~3,
++ VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE |
++ VCHI_FLAGS_BLOCK_UNTIL_QUEUED,
++ msg_context);
++
++ vchi_service_release(instance->handle);
++
++ if (ret != 0) {
++ /* callback will not be clearing the mutex */
++ mutex_unlock(&instance->bulk_mutex);
++ }
++
++ return ret;
++}
++
++/* enque a dummy bulk receive for a given message context */
++static int dummy_bulk_receive(struct vchiq_mmal_instance *instance,
++ struct mmal_msg_context *msg_context)
++{
++ int ret;
++
++ /* bulk mutex stops other bulk operations while we have a
++ * receive in progress - released in callback
++ */
++ ret = mutex_lock_interruptible(&instance->bulk_mutex);
++ if (ret != 0)
++ return ret;
++
++ /* zero length indicates this was a dummy transfer */
++ msg_context->u.bulk.buffer_used = 0;
++
++ /* queue the bulk submission */
++ vchi_service_use(instance->handle);
++
++ ret = vchi_bulk_queue_receive(instance->handle,
++ instance->bulk_scratch,
++ 8,
++ VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE |
++ VCHI_FLAGS_BLOCK_UNTIL_QUEUED,
++ msg_context);
++
++ vchi_service_release(instance->handle);
++
++ if (ret != 0) {
++ /* callback will not be clearing the mutex */
++ mutex_unlock(&instance->bulk_mutex);
++ }
++
++ return ret;
++}
++
++/* data in message, memcpy from packet into output buffer */
++static int inline_receive(struct vchiq_mmal_instance *instance,
++ struct mmal_msg *msg,
++ struct mmal_msg_context *msg_context)
++{
++ unsigned long flags = 0;
++
++ /* take buffer from queue */
++ spin_lock_irqsave(&msg_context->u.bulk.port->slock, flags);
++ if (list_empty(&msg_context->u.bulk.port->buffers)) {
++ spin_unlock_irqrestore(&msg_context->u.bulk.port->slock, flags);
++ pr_err("buffer list empty trying to receive inline\n");
++
++ /* todo: this is a serious error, we should never have
++ * commited a buffer_to_host operation to the mmal
++ * port without the buffer to back it up (with
++ * underflow handling) and there is no obvious way to
++ * deal with this. Less bad than the bulk case as we
++ * can just drop this on the floor but...unhelpful
++ */
++ return -EINVAL;
++ }
++
++ msg_context->u.bulk.buffer =
++ list_entry(msg_context->u.bulk.port->buffers.next,
++ struct mmal_buffer, list);
++ list_del(&msg_context->u.bulk.buffer->list);
++
++ spin_unlock_irqrestore(&msg_context->u.bulk.port->slock, flags);
++
++ memcpy(msg_context->u.bulk.buffer->buffer,
++ msg->u.buffer_from_host.short_data,
++ msg->u.buffer_from_host.payload_in_message);
++
++ msg_context->u.bulk.buffer_used =
++ msg->u.buffer_from_host.payload_in_message;
++
++ return 0;
++}
++
++/* queue the buffer availability with MMAL_MSG_TYPE_BUFFER_FROM_HOST */
++static int
++buffer_from_host(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port, struct mmal_buffer *buf)
++{
++ struct mmal_msg_context *msg_context;
++ struct mmal_msg m;
++ int ret;
++
++ pr_debug("instance:%p buffer:%p\n", instance->handle, buf);
++
++ /* bulk mutex stops other bulk operations while we
++ * have a receive in progress
++ */
++ if (mutex_lock_interruptible(&instance->bulk_mutex))
++ return -EINTR;
++
++ /* get context */
++ msg_context = get_msg_context(instance);
++ if (msg_context == NULL)
++ return -ENOMEM;
++
++ /* store bulk message context for when data arrives */
++ msg_context->u.bulk.instance = instance;
++ msg_context->u.bulk.port = port;
++ msg_context->u.bulk.buffer = NULL; /* not valid until bulk xfer */
++ msg_context->u.bulk.buffer_used = 0;
++
++ /* initialise work structure ready to schedule callback */
++ INIT_WORK(&msg_context->u.bulk.work, buffer_work_cb);
++
++ /* prep the buffer from host message */
++ memset(&m, 0xbc, sizeof(m)); /* just to make debug clearer */
++
++ m.h.type = MMAL_MSG_TYPE_BUFFER_FROM_HOST;
++ m.h.magic = MMAL_MAGIC;
++ m.h.context = msg_context;
++ m.h.status = 0;
++
++ /* drvbuf is our private data passed back */
++ m.u.buffer_from_host.drvbuf.magic = MMAL_MAGIC;
++ m.u.buffer_from_host.drvbuf.component_handle = port->component->handle;
++ m.u.buffer_from_host.drvbuf.port_handle = port->handle;
++ m.u.buffer_from_host.drvbuf.client_context = msg_context;
++
++ /* buffer header */
++ m.u.buffer_from_host.buffer_header.cmd = 0;
++ m.u.buffer_from_host.buffer_header.data = buf->buffer;
++ m.u.buffer_from_host.buffer_header.alloc_size = buf->buffer_size;
++ m.u.buffer_from_host.buffer_header.length = 0; /* nothing used yet */
++ m.u.buffer_from_host.buffer_header.offset = 0; /* no offset */
++ m.u.buffer_from_host.buffer_header.flags = 0; /* no flags */
++ m.u.buffer_from_host.buffer_header.pts = MMAL_TIME_UNKNOWN;
++ m.u.buffer_from_host.buffer_header.dts = MMAL_TIME_UNKNOWN;
++
++ /* clear buffer type sepecific data */
++ memset(&m.u.buffer_from_host.buffer_header_type_specific, 0,
++ sizeof(m.u.buffer_from_host.buffer_header_type_specific));
++
++ /* no payload in message */
++ m.u.buffer_from_host.payload_in_message = 0;
++
++ vchi_service_use(instance->handle);
++
++ ret = vchi_msg_queue(instance->handle, &m,
++ sizeof(struct mmal_msg_header) +
++ sizeof(m.u.buffer_from_host),
++ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
++
++ if (ret != 0) {
++ release_msg_context(msg_context);
++ /* todo: is this correct error value? */
++ }
++
++ vchi_service_release(instance->handle);
++
++ mutex_unlock(&instance->bulk_mutex);
++
++ return ret;
++}
++
++/* submit a buffer to the mmal sevice
++ *
++ * the buffer_from_host uses size data from the ports next available
++ * mmal_buffer and deals with there being no buffer available by
++ * incrementing the underflow for later
++ */
++static int port_buffer_from_host(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port)
++{
++ int ret;
++ struct mmal_buffer *buf;
++ unsigned long flags = 0;
++
++ if (!port->enabled)
++ return -EINVAL;
++
++ /* peek buffer from queue */
++ spin_lock_irqsave(&port->slock, flags);
++ if (list_empty(&port->buffers)) {
++ port->buffer_underflow++;
++ spin_unlock_irqrestore(&port->slock, flags);
++ return -ENOSPC;
++ }
++
++ buf = list_entry(port->buffers.next, struct mmal_buffer, list);
++
++ spin_unlock_irqrestore(&port->slock, flags);
++
++ /* issue buffer to mmal service */
++ ret = buffer_from_host(instance, port, buf);
++ if (ret) {
++ pr_err("adding buffer header failed\n");
++ /* todo: how should this be dealt with */
++ }
++
++ return ret;
++}
++
++/* deals with receipt of buffer to host message */
++static void buffer_to_host_cb(struct vchiq_mmal_instance *instance,
++ struct mmal_msg *msg, u32 msg_len)
++{
++ struct mmal_msg_context *msg_context;
++
++ pr_debug("buffer_to_host_cb: instance:%p msg:%p msg_len:%d\n",
++ instance, msg, msg_len);
++
++ if (msg->u.buffer_from_host.drvbuf.magic == MMAL_MAGIC) {
++ msg_context = msg->u.buffer_from_host.drvbuf.client_context;
++ } else {
++ pr_err("MMAL_MSG_TYPE_BUFFER_TO_HOST with bad magic\n");
++ return;
++ }
++
++ if (msg->h.status != MMAL_MSG_STATUS_SUCCESS) {
++ /* message reception had an error */
++ pr_warn("error %d in reply\n", msg->h.status);
++
++ msg_context->u.bulk.status = msg->h.status;
++
++ } else if (msg->u.buffer_from_host.buffer_header.length == 0) {
++ /* empty buffer */
++ if (msg->u.buffer_from_host.buffer_header.flags &
++ MMAL_BUFFER_HEADER_FLAG_EOS) {
++ msg_context->u.bulk.status =
++ dummy_bulk_receive(instance, msg_context);
++ if (msg_context->u.bulk.status == 0)
++ return; /* successful bulk submission, bulk
++ * completion will trigger callback
++ */
++ } else {
++ /* do callback with empty buffer - not EOS though */
++ msg_context->u.bulk.status = 0;
++ msg_context->u.bulk.buffer_used = 0;
++ }
++ } else if (msg->u.buffer_from_host.payload_in_message == 0) {
++ /* data is not in message, queue a bulk receive */
++ msg_context->u.bulk.status =
++ bulk_receive(instance, msg, msg_context);
++ if (msg_context->u.bulk.status == 0)
++ return; /* successful bulk submission, bulk
++ * completion will trigger callback
++ */
++
++ /* failed to submit buffer, this will end badly */
++ pr_err("error %d on bulk submission\n",
++ msg_context->u.bulk.status);
++
++ } else if (msg->u.buffer_from_host.payload_in_message <=
++ MMAL_VC_SHORT_DATA) {
++ /* data payload within message */
++ msg_context->u.bulk.status = inline_receive(instance, msg,
++ msg_context);
++ } else {
++ pr_err("message with invalid short payload\n");
++
++ /* signal error */
++ msg_context->u.bulk.status = -EINVAL;
++ msg_context->u.bulk.buffer_used =
++ msg->u.buffer_from_host.payload_in_message;
++ }
++
++ /* replace the buffer header */
++ port_buffer_from_host(instance, msg_context->u.bulk.port);
++
++ /* schedule the port callback */
++ schedule_work(&msg_context->u.bulk.work);
++}
++
++static void bulk_receive_cb(struct vchiq_mmal_instance *instance,
++ struct mmal_msg_context *msg_context)
++{
++ /* bulk receive operation complete */
++ mutex_unlock(&msg_context->u.bulk.instance->bulk_mutex);
++
++ /* replace the buffer header */
++ port_buffer_from_host(msg_context->u.bulk.instance,
++ msg_context->u.bulk.port);
++
++ msg_context->u.bulk.status = 0;
++
++ /* schedule the port callback */
++ schedule_work(&msg_context->u.bulk.work);
++}
++
++static void bulk_abort_cb(struct vchiq_mmal_instance *instance,
++ struct mmal_msg_context *msg_context)
++{
++ pr_err("%s: bulk ABORTED msg_context:%p\n", __func__, msg_context);
++
++ /* bulk receive operation complete */
++ mutex_unlock(&msg_context->u.bulk.instance->bulk_mutex);
++
++ /* replace the buffer header */
++ port_buffer_from_host(msg_context->u.bulk.instance,
++ msg_context->u.bulk.port);
++
++ msg_context->u.bulk.status = -EINTR;
++
++ schedule_work(&msg_context->u.bulk.work);
++}
++
++/* incoming event service callback */
++static void service_callback(void *param,
++ const VCHI_CALLBACK_REASON_T reason,
++ void *bulk_ctx)
++{
++ struct vchiq_mmal_instance *instance = param;
++ int status;
++ u32 msg_len;
++ struct mmal_msg *msg;
++ VCHI_HELD_MSG_T msg_handle;
++
++ if (!instance) {
++ pr_err("Message callback passed NULL instance\n");
++ return;
++ }
++
++ switch (reason) {
++ case VCHI_CALLBACK_MSG_AVAILABLE:
++ status = vchi_msg_hold(instance->handle, (void **)&msg,
++ &msg_len, VCHI_FLAGS_NONE, &msg_handle);
++ if (status) {
++ pr_err("Unable to dequeue a message (%d)\n", status);
++ break;
++ }
++
++ DBG_DUMP_MSG(msg, msg_len, "<<< reply message");
++
++ /* handling is different for buffer messages */
++ switch (msg->h.type) {
++
++ case MMAL_MSG_TYPE_BUFFER_FROM_HOST:
++ vchi_held_msg_release(&msg_handle);
++ break;
++
++ case MMAL_MSG_TYPE_EVENT_TO_HOST:
++ event_to_host_cb(instance, msg, msg_len);
++ vchi_held_msg_release(&msg_handle);
++
++ break;
++
++ case MMAL_MSG_TYPE_BUFFER_TO_HOST:
++ buffer_to_host_cb(instance, msg, msg_len);
++ vchi_held_msg_release(&msg_handle);
++ break;
++
++ default:
++ /* messages dependant on header context to complete */
++
++ /* todo: the msg.context really ought to be sanity
++ * checked before we just use it, afaict it comes back
++ * and is used raw from the videocore. Perhaps it
++ * should be verified the address lies in the kernel
++ * address space.
++ */
++ if (msg->h.context == NULL) {
++ pr_err("received message context was null!\n");
++ vchi_held_msg_release(&msg_handle);
++ break;
++ }
++
++ /* fill in context values */
++ msg->h.context->u.sync.msg_handle = msg_handle;
++ msg->h.context->u.sync.msg = msg;
++ msg->h.context->u.sync.msg_len = msg_len;
++
++ /* todo: should this check (completion_done()
++ * == 1) for no one waiting? or do we need a
++ * flag to tell us the completion has been
++ * interrupted so we can free the message and
++ * its context. This probably also solves the
++ * message arriving after interruption todo
++ * below
++ */
++
++ /* complete message so caller knows it happened */
++ complete(&msg->h.context->u.sync.cmplt);
++ break;
++ }
++
++ break;
++
++ case VCHI_CALLBACK_BULK_RECEIVED:
++ bulk_receive_cb(instance, bulk_ctx);
++ break;
++
++ case VCHI_CALLBACK_BULK_RECEIVE_ABORTED:
++ bulk_abort_cb(instance, bulk_ctx);
++ break;
++
++ case VCHI_CALLBACK_SERVICE_CLOSED:
++ /* TODO: consider if this requires action if received when
++ * driver is not explicitly closing the service
++ */
++ break;
++
++ default:
++ pr_err("Received unhandled message reason %d\n", reason);
++ break;
++ }
++}
++
++static int send_synchronous_mmal_msg(struct vchiq_mmal_instance *instance,
++ struct mmal_msg *msg,
++ unsigned int payload_len,
++ struct mmal_msg **msg_out,
++ VCHI_HELD_MSG_T *msg_handle_out)
++{
++ struct mmal_msg_context msg_context;
++ int ret;
++
++ /* payload size must not cause message to exceed max size */
++ if (payload_len >
++ (MMAL_MSG_MAX_SIZE - sizeof(struct mmal_msg_header))) {
++ pr_err("payload length %d exceeds max:%d\n", payload_len,
++ (MMAL_MSG_MAX_SIZE - sizeof(struct mmal_msg_header)));
++ return -EINVAL;
++ }
++
++ init_completion(&msg_context.u.sync.cmplt);
++
++ msg->h.magic = MMAL_MAGIC;
++ msg->h.context = &msg_context;
++ msg->h.status = 0;
++
++ DBG_DUMP_MSG(msg, (sizeof(struct mmal_msg_header) + payload_len),
++ ">>> sync message");
++
++ vchi_service_use(instance->handle);
++
++ ret = vchi_msg_queue(instance->handle,
++ msg,
++ sizeof(struct mmal_msg_header) + payload_len,
++ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
++
++ vchi_service_release(instance->handle);
++
++ if (ret) {
++ pr_err("error %d queuing message\n", ret);
++ return ret;
++ }
++
++ ret = wait_for_completion_timeout(&msg_context.u.sync.cmplt, 3*HZ);
++ if (ret <= 0) {
++ pr_err("error %d waiting for sync completion\n", ret);
++ if (ret == 0)
++ ret = -ETIME;
++ /* todo: what happens if the message arrives after aborting */
++ return ret;
++ }
++
++ *msg_out = msg_context.u.sync.msg;
++ *msg_handle_out = msg_context.u.sync.msg_handle;
++
++ return 0;
++}
++
++static void dump_port_info(struct vchiq_mmal_port *port)
++{
++ pr_debug("port handle:0x%x enabled:%d\n", port->handle, port->enabled);
++
++ pr_debug("buffer minimum num:%d size:%d align:%d\n",
++ port->minimum_buffer.num,
++ port->minimum_buffer.size, port->minimum_buffer.alignment);
++
++ pr_debug("buffer recommended num:%d size:%d align:%d\n",
++ port->recommended_buffer.num,
++ port->recommended_buffer.size,
++ port->recommended_buffer.alignment);
++
++ pr_debug("buffer current values num:%d size:%d align:%d\n",
++ port->current_buffer.num,
++ port->current_buffer.size, port->current_buffer.alignment);
++
++ pr_debug("elementry stream: type:%d encoding:0x%x varient:0x%x\n",
++ port->format.type,
++ port->format.encoding, port->format.encoding_variant);
++
++ pr_debug(" bitrate:%d flags:0x%x\n",
++ port->format.bitrate, port->format.flags);
++
++ if (port->format.type == MMAL_ES_TYPE_VIDEO) {
++ pr_debug
++ ("es video format: width:%d height:%d colourspace:0x%x\n",
++ port->es.video.width, port->es.video.height,
++ port->es.video.color_space);
++
++ pr_debug(" : crop xywh %d,%d,%d,%d\n",
++ port->es.video.crop.x,
++ port->es.video.crop.y,
++ port->es.video.crop.width, port->es.video.crop.height);
++ pr_debug(" : framerate %d/%d aspect %d/%d\n",
++ port->es.video.frame_rate.num,
++ port->es.video.frame_rate.den,
++ port->es.video.par.num, port->es.video.par.den);
++ }
++}
++
++static void port_to_mmal_msg(struct vchiq_mmal_port *port, struct mmal_port *p)
++{
++
++ /* todo do readonly fields need setting at all? */
++ p->type = port->type;
++ p->index = port->index;
++ p->index_all = 0;
++ p->is_enabled = port->enabled;
++ p->buffer_num_min = port->minimum_buffer.num;
++ p->buffer_size_min = port->minimum_buffer.size;
++ p->buffer_alignment_min = port->minimum_buffer.alignment;
++ p->buffer_num_recommended = port->recommended_buffer.num;
++ p->buffer_size_recommended = port->recommended_buffer.size;
++
++ /* only three writable fields in a port */
++ p->buffer_num = port->current_buffer.num;
++ p->buffer_size = port->current_buffer.size;
++ p->userdata = port;
++}
++
++static int port_info_set(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ pr_debug("setting port info port %p\n", port);
++ if (!port)
++ return -1;
++ dump_port_info(port);
++
++ m.h.type = MMAL_MSG_TYPE_PORT_INFO_SET;
++
++ m.u.port_info_set.component_handle = port->component->handle;
++ m.u.port_info_set.port_type = port->type;
++ m.u.port_info_set.port_index = port->index;
++
++ port_to_mmal_msg(port, &m.u.port_info_set.port);
++
++ /* elementry stream format setup */
++ m.u.port_info_set.format.type = port->format.type;
++ m.u.port_info_set.format.encoding = port->format.encoding;
++ m.u.port_info_set.format.encoding_variant =
++ port->format.encoding_variant;
++ m.u.port_info_set.format.bitrate = port->format.bitrate;
++ m.u.port_info_set.format.flags = port->format.flags;
++
++ memcpy(&m.u.port_info_set.es, &port->es,
++ sizeof(union mmal_es_specific_format));
++
++ m.u.port_info_set.format.extradata_size = port->format.extradata_size;
++ memcpy(&m.u.port_info_set.extradata, port->format.extradata,
++ port->format.extradata_size);
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ sizeof(m.u.port_info_set),
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_INFO_SET) {
++ /* got an unexpected message type in reply */
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ /* return operation status */
++ ret = -rmsg->u.port_info_get_reply.status;
++
++ pr_debug("%s:result:%d component:0x%x port:%d\n", __func__, ret,
++ port->component->handle, port->handle);
++
++release_msg:
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++
++}
++
++/* use port info get message to retrive port information */
++static int port_info_get(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ /* port info time */
++ m.h.type = MMAL_MSG_TYPE_PORT_INFO_GET;
++ m.u.port_info_get.component_handle = port->component->handle;
++ m.u.port_info_get.port_type = port->type;
++ m.u.port_info_get.index = port->index;
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ sizeof(m.u.port_info_get),
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_INFO_GET) {
++ /* got an unexpected message type in reply */
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ /* return operation status */
++ ret = -rmsg->u.port_info_get_reply.status;
++ if (ret != MMAL_MSG_STATUS_SUCCESS)
++ goto release_msg;
++
++ if (rmsg->u.port_info_get_reply.port.is_enabled == 0)
++ port->enabled = false;
++ else
++ port->enabled = true;
++
++ /* copy the values out of the message */
++ port->handle = rmsg->u.port_info_get_reply.port_handle;
++
++ /* port type and index cached to use on port info set becuase
++ * it does not use a port handle
++ */
++ port->type = rmsg->u.port_info_get_reply.port_type;
++ port->index = rmsg->u.port_info_get_reply.port_index;
++
++ port->minimum_buffer.num =
++ rmsg->u.port_info_get_reply.port.buffer_num_min;
++ port->minimum_buffer.size =
++ rmsg->u.port_info_get_reply.port.buffer_size_min;
++ port->minimum_buffer.alignment =
++ rmsg->u.port_info_get_reply.port.buffer_alignment_min;
++
++ port->recommended_buffer.alignment =
++ rmsg->u.port_info_get_reply.port.buffer_alignment_min;
++ port->recommended_buffer.num =
++ rmsg->u.port_info_get_reply.port.buffer_num_recommended;
++
++ port->current_buffer.num = rmsg->u.port_info_get_reply.port.buffer_num;
++ port->current_buffer.size =
++ rmsg->u.port_info_get_reply.port.buffer_size;
++
++ /* stream format */
++ port->format.type = rmsg->u.port_info_get_reply.format.type;
++ port->format.encoding = rmsg->u.port_info_get_reply.format.encoding;
++ port->format.encoding_variant =
++ rmsg->u.port_info_get_reply.format.encoding_variant;
++ port->format.bitrate = rmsg->u.port_info_get_reply.format.bitrate;
++ port->format.flags = rmsg->u.port_info_get_reply.format.flags;
++
++ /* elementry stream format */
++ memcpy(&port->es,
++ &rmsg->u.port_info_get_reply.es,
++ sizeof(union mmal_es_specific_format));
++ port->format.es = &port->es;
++
++ port->format.extradata_size =
++ rmsg->u.port_info_get_reply.format.extradata_size;
++ memcpy(port->format.extradata,
++ rmsg->u.port_info_get_reply.extradata,
++ port->format.extradata_size);
++
++ pr_debug("received port info\n");
++ dump_port_info(port);
++
++release_msg:
++
++ pr_debug("%s:result:%d component:0x%x port:%d\n",
++ __func__, ret, port->component->handle, port->handle);
++
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++}
++
++/* create comonent on vc */
++static int create_component(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_component *component,
++ const char *name)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ /* build component create message */
++ m.h.type = MMAL_MSG_TYPE_COMPONENT_CREATE;
++ m.u.component_create.client_component = component;
++ strncpy(m.u.component_create.name, name,
++ sizeof(m.u.component_create.name));
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ sizeof(m.u.component_create),
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != m.h.type) {
++ /* got an unexpected message type in reply */
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ ret = -rmsg->u.component_create_reply.status;
++ if (ret != MMAL_MSG_STATUS_SUCCESS)
++ goto release_msg;
++
++ /* a valid component response received */
++ component->handle = rmsg->u.component_create_reply.component_handle;
++ component->inputs = rmsg->u.component_create_reply.input_num;
++ component->outputs = rmsg->u.component_create_reply.output_num;
++ component->clocks = rmsg->u.component_create_reply.clock_num;
++
++ pr_debug("Component handle:0x%x in:%d out:%d clock:%d\n",
++ component->handle,
++ component->inputs, component->outputs, component->clocks);
++
++release_msg:
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++}
++
++/* destroys a component on vc */
++static int destroy_component(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_component *component)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ m.h.type = MMAL_MSG_TYPE_COMPONENT_DESTROY;
++ m.u.component_destroy.component_handle = component->handle;
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ sizeof(m.u.component_destroy),
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != m.h.type) {
++ /* got an unexpected message type in reply */
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ ret = -rmsg->u.component_destroy_reply.status;
++
++release_msg:
++
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++}
++
++/* enable a component on vc */
++static int enable_component(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_component *component)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ m.h.type = MMAL_MSG_TYPE_COMPONENT_ENABLE;
++ m.u.component_enable.component_handle = component->handle;
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ sizeof(m.u.component_enable),
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != m.h.type) {
++ /* got an unexpected message type in reply */
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ ret = -rmsg->u.component_enable_reply.status;
++
++release_msg:
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++}
++
++/* disable a component on vc */
++static int disable_component(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_component *component)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ m.h.type = MMAL_MSG_TYPE_COMPONENT_DISABLE;
++ m.u.component_disable.component_handle = component->handle;
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ sizeof(m.u.component_disable),
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != m.h.type) {
++ /* got an unexpected message type in reply */
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ ret = -rmsg->u.component_disable_reply.status;
++
++release_msg:
++
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++}
++
++/* get version of mmal implementation */
++static int get_version(struct vchiq_mmal_instance *instance,
++ u32 *major_out, u32 *minor_out)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ m.h.type = MMAL_MSG_TYPE_GET_VERSION;
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ sizeof(m.u.version),
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != m.h.type) {
++ /* got an unexpected message type in reply */
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ *major_out = rmsg->u.version.major;
++ *minor_out = rmsg->u.version.minor;
++
++release_msg:
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++}
++
++/* do a port action with a port as a parameter */
++static int port_action_port(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ enum mmal_msg_port_action_type action_type)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ m.h.type = MMAL_MSG_TYPE_PORT_ACTION;
++ m.u.port_action_port.component_handle = port->component->handle;
++ m.u.port_action_port.port_handle = port->handle;
++ m.u.port_action_port.action = action_type;
++
++ port_to_mmal_msg(port, &m.u.port_action_port.port);
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ sizeof(m.u.port_action_port),
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_ACTION) {
++ /* got an unexpected message type in reply */
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ ret = -rmsg->u.port_action_reply.status;
++
++ pr_debug("%s:result:%d component:0x%x port:%d action:%s(%d)\n",
++ __func__,
++ ret, port->component->handle, port->handle,
++ port_action_type_names[action_type], action_type);
++
++release_msg:
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++}
++
++/* do a port action with handles as parameters */
++static int port_action_handle(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ enum mmal_msg_port_action_type action_type,
++ u32 connect_component_handle,
++ u32 connect_port_handle)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ m.h.type = MMAL_MSG_TYPE_PORT_ACTION;
++
++ m.u.port_action_handle.component_handle = port->component->handle;
++ m.u.port_action_handle.port_handle = port->handle;
++ m.u.port_action_handle.action = action_type;
++
++ m.u.port_action_handle.connect_component_handle =
++ connect_component_handle;
++ m.u.port_action_handle.connect_port_handle = connect_port_handle;
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ sizeof(m.u.port_action_handle),
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_ACTION) {
++ /* got an unexpected message type in reply */
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ ret = -rmsg->u.port_action_reply.status;
++
++ pr_debug("%s:result:%d component:0x%x port:%d action:%s(%d)" \
++ " connect component:0x%x connect port:%d\n",
++ __func__,
++ ret, port->component->handle, port->handle,
++ port_action_type_names[action_type],
++ action_type, connect_component_handle, connect_port_handle);
++
++release_msg:
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++}
++
++static int port_parameter_set(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ u32 parameter_id, void *value, u32 value_size)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ m.h.type = MMAL_MSG_TYPE_PORT_PARAMETER_SET;
++
++ m.u.port_parameter_set.component_handle = port->component->handle;
++ m.u.port_parameter_set.port_handle = port->handle;
++ m.u.port_parameter_set.id = parameter_id;
++ m.u.port_parameter_set.size = (2 * sizeof(u32)) + value_size;
++ memcpy(&m.u.port_parameter_set.value, value, value_size);
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ (4 * sizeof(u32)) + value_size,
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_PARAMETER_SET) {
++ /* got an unexpected message type in reply */
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ ret = -rmsg->u.port_parameter_set_reply.status;
++
++ pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n",
++ __func__,
++ ret, port->component->handle, port->handle, parameter_id);
++
++release_msg:
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++}
++
++static int port_parameter_get(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ u32 parameter_id, void *value, u32 *value_size)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ m.h.type = MMAL_MSG_TYPE_PORT_PARAMETER_GET;
++
++ m.u.port_parameter_get.component_handle = port->component->handle;
++ m.u.port_parameter_get.port_handle = port->handle;
++ m.u.port_parameter_get.id = parameter_id;
++ m.u.port_parameter_get.size = (2 * sizeof(u32)) + *value_size;
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ sizeof(struct
++ mmal_msg_port_parameter_get),
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_PARAMETER_GET) {
++ /* got an unexpected message type in reply */
++ pr_err("Incorrect reply type %d\n", rmsg->h.type);
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ ret = -rmsg->u.port_parameter_get_reply.status;
++ if (ret) {
++ /* Copy only as much as we have space for
++ * but report true size of parameter
++ */
++ memcpy(value, &rmsg->u.port_parameter_get_reply.value,
++ *value_size);
++ *value_size = rmsg->u.port_parameter_get_reply.size;
++ } else
++ memcpy(value, &rmsg->u.port_parameter_get_reply.value,
++ rmsg->u.port_parameter_get_reply.size);
++
++ pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n", __func__,
++ ret, port->component->handle, port->handle, parameter_id);
++
++release_msg:
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++}
++
++/* disables a port and drains buffers from it */
++static int port_disable(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port)
++{
++ int ret;
++ struct list_head *q, *buf_head;
++ unsigned long flags = 0;
++
++ if (!port->enabled)
++ return 0;
++
++ port->enabled = false;
++
++ ret = port_action_port(instance, port,
++ MMAL_MSG_PORT_ACTION_TYPE_DISABLE);
++ if (ret == 0) {
++
++ /* drain all queued buffers on port */
++ spin_lock_irqsave(&port->slock, flags);
++
++ list_for_each_safe(buf_head, q, &port->buffers) {
++ struct mmal_buffer *mmalbuf;
++ mmalbuf = list_entry(buf_head, struct mmal_buffer,
++ list);
++ list_del(buf_head);
++ if (port->buffer_cb)
++ port->buffer_cb(instance,
++ port, 0, mmalbuf, 0, 0,
++ MMAL_TIME_UNKNOWN,
++ MMAL_TIME_UNKNOWN);
++ }
++
++ spin_unlock_irqrestore(&port->slock, flags);
++
++ ret = port_info_get(instance, port);
++ }
++
++ return ret;
++}
++
++/* enable a port */
++static int port_enable(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port)
++{
++ unsigned int hdr_count;
++ struct list_head *buf_head;
++ int ret;
++
++ if (port->enabled)
++ return 0;
++
++ /* ensure there are enough buffers queued to cover the buffer headers */
++ if (port->buffer_cb != NULL) {
++ hdr_count = 0;
++ list_for_each(buf_head, &port->buffers) {
++ hdr_count++;
++ }
++ if (hdr_count < port->current_buffer.num)
++ return -ENOSPC;
++ }
++
++ ret = port_action_port(instance, port,
++ MMAL_MSG_PORT_ACTION_TYPE_ENABLE);
++ if (ret)
++ goto done;
++
++ port->enabled = true;
++
++ if (port->buffer_cb) {
++ /* send buffer headers to videocore */
++ hdr_count = 1;
++ list_for_each(buf_head, &port->buffers) {
++ struct mmal_buffer *mmalbuf;
++ mmalbuf = list_entry(buf_head, struct mmal_buffer,
++ list);
++ ret = buffer_from_host(instance, port, mmalbuf);
++ if (ret)
++ goto done;
++
++ hdr_count++;
++ if (hdr_count > port->current_buffer.num)
++ break;
++ }
++ }
++
++ ret = port_info_get(instance, port);
++
++done:
++ return ret;
++}
++
++/* ------------------------------------------------------------------
++ * Exported API
++ *------------------------------------------------------------------*/
++
++int vchiq_mmal_port_set_format(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port)
++{
++ int ret;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ ret = port_info_set(instance, port);
++ if (ret)
++ goto release_unlock;
++
++ /* read what has actually been set */
++ ret = port_info_get(instance, port);
++
++release_unlock:
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++
++}
++
++int vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ u32 parameter, void *value, u32 value_size)
++{
++ int ret;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ ret = port_parameter_set(instance, port, parameter, value, value_size);
++
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++}
++
++int vchiq_mmal_port_parameter_get(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ u32 parameter, void *value, u32 *value_size)
++{
++ int ret;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ ret = port_parameter_get(instance, port, parameter, value, value_size);
++
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++}
++
++/* enable a port
++ *
++ * enables a port and queues buffers for satisfying callbacks if we
++ * provide a callback handler
++ */
++int vchiq_mmal_port_enable(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ vchiq_mmal_buffer_cb buffer_cb)
++{
++ int ret;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ /* already enabled - noop */
++ if (port->enabled) {
++ ret = 0;
++ goto unlock;
++ }
++
++ port->buffer_cb = buffer_cb;
++
++ ret = port_enable(instance, port);
++
++unlock:
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++}
++
++int vchiq_mmal_port_disable(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port)
++{
++ int ret;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ if (!port->enabled) {
++ mutex_unlock(&instance->vchiq_mutex);
++ return 0;
++ }
++
++ ret = port_disable(instance, port);
++
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++}
++
++/* ports will be connected in a tunneled manner so data buffers
++ * are not handled by client.
++ */
++int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *src,
++ struct vchiq_mmal_port *dst)
++{
++ int ret;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ /* disconnect ports if connected */
++ if (src->connected != NULL) {
++ ret = port_disable(instance, src);
++ if (ret) {
++ pr_err("failed disabling src port(%d)\n", ret);
++ goto release_unlock;
++ }
++
++ /* do not need to disable the destination port as they
++ * are connected and it is done automatically
++ */
++
++ ret = port_action_handle(instance, src,
++ MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT,
++ src->connected->component->handle,
++ src->connected->handle);
++ if (ret < 0) {
++ pr_err("failed disconnecting src port\n");
++ goto release_unlock;
++ }
++ src->connected->enabled = false;
++ src->connected = NULL;
++ }
++
++ if (dst == NULL) {
++ /* do not make new connection */
++ ret = 0;
++ pr_debug("not making new connection\n");
++ goto release_unlock;
++ }
++
++ /* copy src port format to dst */
++ dst->format.encoding = src->format.encoding;
++ dst->es.video.width = src->es.video.width;
++ dst->es.video.height = src->es.video.height;
++ dst->es.video.crop.x = src->es.video.crop.x;
++ dst->es.video.crop.y = src->es.video.crop.y;
++ dst->es.video.crop.width = src->es.video.crop.width;
++ dst->es.video.crop.height = src->es.video.crop.height;
++ dst->es.video.frame_rate.num = src->es.video.frame_rate.num;
++ dst->es.video.frame_rate.den = src->es.video.frame_rate.den;
++
++ /* set new format */
++ ret = port_info_set(instance, dst);
++ if (ret) {
++ pr_debug("setting port info failed\n");
++ goto release_unlock;
++ }
++
++ /* read what has actually been set */
++ ret = port_info_get(instance, dst);
++ if (ret) {
++ pr_debug("read back port info failed\n");
++ goto release_unlock;
++ }
++
++ /* connect two ports together */
++ ret = port_action_handle(instance, src,
++ MMAL_MSG_PORT_ACTION_TYPE_CONNECT,
++ dst->component->handle, dst->handle);
++ if (ret < 0) {
++ pr_debug("connecting port %d:%d to %d:%d failed\n",
++ src->component->handle, src->handle,
++ dst->component->handle, dst->handle);
++ goto release_unlock;
++ }
++ src->connected = dst;
++
++release_unlock:
++
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++}
++
++int vchiq_mmal_submit_buffer(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ struct mmal_buffer *buffer)
++{
++ unsigned long flags = 0;
++
++ spin_lock_irqsave(&port->slock, flags);
++ list_add_tail(&buffer->list, &port->buffers);
++ spin_unlock_irqrestore(&port->slock, flags);
++
++ /* the port previously underflowed because it was missing a
++ * mmal_buffer which has just been added, submit that buffer
++ * to the mmal service.
++ */
++ if (port->buffer_underflow) {
++ port_buffer_from_host(instance, port);
++ port->buffer_underflow--;
++ }
++
++ return 0;
++}
++
++/* Initialise a mmal component and its ports
++ *
++ */
++int vchiq_mmal_component_init(struct vchiq_mmal_instance *instance,
++ const char *name,
++ struct vchiq_mmal_component **component_out)
++{
++ int ret;
++ int idx; /* port index */
++ struct vchiq_mmal_component *component;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ if (instance->component_idx == VCHIQ_MMAL_MAX_COMPONENTS) {
++ ret = -EINVAL; /* todo is this correct error? */
++ goto unlock;
++ }
++
++ component = &instance->component[instance->component_idx];
++
++ ret = create_component(instance, component, name);
++ if (ret < 0)
++ goto unlock;
++
++ /* ports info needs gathering */
++ component->control.type = MMAL_PORT_TYPE_CONTROL;
++ component->control.index = 0;
++ component->control.component = component;
++ spin_lock_init(&component->control.slock);
++ INIT_LIST_HEAD(&component->control.buffers);
++ ret = port_info_get(instance, &component->control);
++ if (ret < 0)
++ goto release_component;
++
++ for (idx = 0; idx < component->inputs; idx++) {
++ component->input[idx].type = MMAL_PORT_TYPE_INPUT;
++ component->input[idx].index = idx;
++ component->input[idx].component = component;
++ spin_lock_init(&component->input[idx].slock);
++ INIT_LIST_HEAD(&component->input[idx].buffers);
++ ret = port_info_get(instance, &component->input[idx]);
++ if (ret < 0)
++ goto release_component;
++ }
++
++ for (idx = 0; idx < component->outputs; idx++) {
++ component->output[idx].type = MMAL_PORT_TYPE_OUTPUT;
++ component->output[idx].index = idx;
++ component->output[idx].component = component;
++ spin_lock_init(&component->output[idx].slock);
++ INIT_LIST_HEAD(&component->output[idx].buffers);
++ ret = port_info_get(instance, &component->output[idx]);
++ if (ret < 0)
++ goto release_component;
++ }
++
++ for (idx = 0; idx < component->clocks; idx++) {
++ component->clock[idx].type = MMAL_PORT_TYPE_CLOCK;
++ component->clock[idx].index = idx;
++ component->clock[idx].component = component;
++ spin_lock_init(&component->clock[idx].slock);
++ INIT_LIST_HEAD(&component->clock[idx].buffers);
++ ret = port_info_get(instance, &component->clock[idx]);
++ if (ret < 0)
++ goto release_component;
++ }
++
++ instance->component_idx++;
++
++ *component_out = component;
++
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return 0;
++
++release_component:
++ destroy_component(instance, component);
++unlock:
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++}
++
++/*
++ * cause a mmal component to be destroyed
++ */
++int vchiq_mmal_component_finalise(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_component *component)
++{
++ int ret;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ if (component->enabled)
++ ret = disable_component(instance, component);
++
++ ret = destroy_component(instance, component);
++
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++}
++
++/*
++ * cause a mmal component to be enabled
++ */
++int vchiq_mmal_component_enable(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_component *component)
++{
++ int ret;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ if (component->enabled) {
++ mutex_unlock(&instance->vchiq_mutex);
++ return 0;
++ }
++
++ ret = enable_component(instance, component);
++ if (ret == 0)
++ component->enabled = true;
++
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++}
++
++/*
++ * cause a mmal component to be enabled
++ */
++int vchiq_mmal_component_disable(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_component *component)
++{
++ int ret;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ if (!component->enabled) {
++ mutex_unlock(&instance->vchiq_mutex);
++ return 0;
++ }
++
++ ret = disable_component(instance, component);
++ if (ret == 0)
++ component->enabled = false;
++
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++}
++
++int vchiq_mmal_version(struct vchiq_mmal_instance *instance,
++ u32 *major_out, u32 *minor_out)
++{
++ int ret;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ ret = get_version(instance, major_out, minor_out);
++
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++}
++
++int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance)
++{
++ int status = 0;
++
++ if (instance == NULL)
++ return -EINVAL;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ vchi_service_use(instance->handle);
++
++ status = vchi_service_close(instance->handle);
++ if (status != 0)
++ pr_err("mmal-vchiq: VCHIQ close failed");
++
++ mutex_unlock(&instance->vchiq_mutex);
++
++ vfree(instance->bulk_scratch);
++
++ kfree(instance);
++
++ return status;
++}
++
++int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance)
++{
++ int status;
++ struct vchiq_mmal_instance *instance;
++ static VCHI_CONNECTION_T *vchi_connection;
++ static VCHI_INSTANCE_T vchi_instance;
++ SERVICE_CREATION_T params = {
++ VCHI_VERSION_EX(VC_MMAL_VER, VC_MMAL_MIN_VER),
++ VC_MMAL_SERVER_NAME,
++ vchi_connection,
++ 0, /* rx fifo size (unused) */
++ 0, /* tx fifo size (unused) */
++ service_callback,
++ NULL, /* service callback parameter */
++ 1, /* unaligned bulk receives */
++ 1, /* unaligned bulk transmits */
++ 0 /* want crc check on bulk transfers */
++ };
++
++ /* compile time checks to ensure structure size as they are
++ * directly (de)serialised from memory.
++ */
++
++ /* ensure the header structure has packed to the correct size */
++ BUILD_BUG_ON(sizeof(struct mmal_msg_header) != 24);
++
++ /* ensure message structure does not exceed maximum length */
++ BUILD_BUG_ON(sizeof(struct mmal_msg) > MMAL_MSG_MAX_SIZE);
++
++ /* mmal port struct is correct size */
++ BUILD_BUG_ON(sizeof(struct mmal_port) != 64);
++
++ /* create a vchi instance */
++ status = vchi_initialise(&vchi_instance);
++ if (status) {
++ pr_err("Failed to initialise VCHI instance (status=%d)\n",
++ status);
++ return -EIO;
++ }
++
++ status = vchi_connect(NULL, 0, vchi_instance);
++ if (status) {
++ pr_err("Failed to connect VCHI instance (status=%d)\n", status);
++ return -EIO;
++ }
++
++ instance = kmalloc(sizeof(*instance), GFP_KERNEL);
++ memset(instance, 0, sizeof(*instance));
++
++ mutex_init(&instance->vchiq_mutex);
++ mutex_init(&instance->bulk_mutex);
++
++ instance->bulk_scratch = vmalloc(PAGE_SIZE);
++
++ params.callback_param = instance;
++
++ status = vchi_service_open(vchi_instance, &params, &instance->handle);
++ if (status) {
++ pr_err("Failed to open VCHI service connection (status=%d)\n",
++ status);
++ goto err_close_services;
++ }
++
++ vchi_service_release(instance->handle);
++
++ *out_instance = instance;
++
++ return 0;
++
++err_close_services:
++
++ vchi_service_close(instance->handle);
++ vfree(instance->bulk_scratch);
++ kfree(instance);
++ return -ENODEV;
++}
+--- /dev/null
++++ b/drivers/media/platform/bcm2835/mmal-vchiq.h
+@@ -0,0 +1,178 @@
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file COPYING in the main directory of this archive
++ * for more details.
++ *
++ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
++ * Dave Stevenson <dsteve@broadcom.com>
++ * Simon Mellor <simellor@broadcom.com>
++ * Luke Diamand <luked@broadcom.com>
++ *
++ * MMAL interface to VCHIQ message passing
++ */
++
++#ifndef MMAL_VCHIQ_H
++#define MMAL_VCHIQ_H
++
++#include "mmal-msg-format.h"
++
++#define MAX_PORT_COUNT 4
++
++/* Maximum size of the format extradata. */
++#define MMAL_FORMAT_EXTRADATA_MAX_SIZE 128
++
++struct vchiq_mmal_instance;
++
++enum vchiq_mmal_es_type {
++ MMAL_ES_TYPE_UNKNOWN, /**< Unknown elementary stream type */
++ MMAL_ES_TYPE_CONTROL, /**< Elementary stream of control commands */
++ MMAL_ES_TYPE_AUDIO, /**< Audio elementary stream */
++ MMAL_ES_TYPE_VIDEO, /**< Video elementary stream */
++ MMAL_ES_TYPE_SUBPICTURE /**< Sub-picture elementary stream */
++};
++
++/* rectangle, used lots so it gets its own struct */
++struct vchiq_mmal_rect {
++ s32 x;
++ s32 y;
++ s32 width;
++ s32 height;
++};
++
++struct vchiq_mmal_port_buffer {
++ unsigned int num; /* number of buffers */
++ u32 size; /* size of buffers */
++ u32 alignment; /* alignment of buffers */
++};
++
++struct vchiq_mmal_port;
++
++typedef void (*vchiq_mmal_buffer_cb)(
++ struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ int status, struct mmal_buffer *buffer,
++ unsigned long length, u32 mmal_flags, s64 dts, s64 pts);
++
++struct vchiq_mmal_port {
++ bool enabled;
++ u32 handle;
++ u32 type; /* port type, cached to use on port info set */
++ u32 index; /* port index, cached to use on port info set */
++
++ /* component port belongs to, allows simple deref */
++ struct vchiq_mmal_component *component;
++
++ struct vchiq_mmal_port *connected; /* port conencted to */
++
++ /* buffer info */
++ struct vchiq_mmal_port_buffer minimum_buffer;
++ struct vchiq_mmal_port_buffer recommended_buffer;
++ struct vchiq_mmal_port_buffer current_buffer;
++
++ /* stream format */
++ struct mmal_es_format format;
++ /* elementry stream format */
++ union mmal_es_specific_format es;
++
++ /* data buffers to fill */
++ struct list_head buffers;
++ /* lock to serialise adding and removing buffers from list */
++ spinlock_t slock;
++ /* count of how many buffer header refils have failed because
++ * there was no buffer to satisfy them
++ */
++ int buffer_underflow;
++ /* callback on buffer completion */
++ vchiq_mmal_buffer_cb buffer_cb;
++ /* callback context */
++ void *cb_ctx;
++};
++
++struct vchiq_mmal_component {
++ bool enabled;
++ u32 handle; /* VideoCore handle for component */
++ u32 inputs; /* Number of input ports */
++ u32 outputs; /* Number of output ports */
++ u32 clocks; /* Number of clock ports */
++ struct vchiq_mmal_port control; /* control port */
++ struct vchiq_mmal_port input[MAX_PORT_COUNT]; /* input ports */
++ struct vchiq_mmal_port output[MAX_PORT_COUNT]; /* output ports */
++ struct vchiq_mmal_port clock[MAX_PORT_COUNT]; /* clock ports */
++};
++
++
++int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance);
++int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance);
++
++/* Initialise a mmal component and its ports
++*
++*/
++int vchiq_mmal_component_init(
++ struct vchiq_mmal_instance *instance,
++ const char *name,
++ struct vchiq_mmal_component **component_out);
++
++int vchiq_mmal_component_finalise(
++ struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_component *component);
++
++int vchiq_mmal_component_enable(
++ struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_component *component);
++
++int vchiq_mmal_component_disable(
++ struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_component *component);
++
++
++
++/* enable a mmal port
++ *
++ * enables a port and if a buffer callback provided enque buffer
++ * headers as apropriate for the port.
++ */
++int vchiq_mmal_port_enable(
++ struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ vchiq_mmal_buffer_cb buffer_cb);
++
++/* disable a port
++ *
++ * disable a port will dequeue any pending buffers
++ */
++int vchiq_mmal_port_disable(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port);
++
++
++int vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ u32 parameter,
++ void *value,
++ u32 value_size);
++
++int vchiq_mmal_port_parameter_get(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ u32 parameter,
++ void *value,
++ u32 *value_size);
++
++int vchiq_mmal_port_set_format(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port);
++
++int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *src,
++ struct vchiq_mmal_port *dst);
++
++int vchiq_mmal_version(struct vchiq_mmal_instance *instance,
++ u32 *major_out,
++ u32 *minor_out);
++
++int vchiq_mmal_submit_buffer(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ struct mmal_buffer *buf);
++
++#endif /* MMAL_VCHIQ_H */
diff --git a/target/linux/brcm2708/patches-4.4/0048-firmware-bcm2835-Support-ARCH_BCM270x.patch b/target/linux/brcm2708/patches-4.4/0048-firmware-bcm2835-Support-ARCH_BCM270x.patch
deleted file mode 100644
index 93c24d893e..0000000000
--- a/target/linux/brcm2708/patches-4.4/0048-firmware-bcm2835-Support-ARCH_BCM270x.patch
+++ /dev/null
@@ -1,106 +0,0 @@
-From a205e934b63b6bf3f5f74bc39974ec6ff09df596 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
-Date: Fri, 26 Jun 2015 14:25:01 +0200
-Subject: [PATCH 048/170] firmware: bcm2835: Support ARCH_BCM270x
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Support booting without Device Tree.
-Turn on USB power.
-Load driver early because of lacking support for deferred probing
-in many drivers.
-
-Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
----
- drivers/firmware/raspberrypi.c | 41 +++++++++++++++++++++++++++++++++++++++--
- 1 file changed, 39 insertions(+), 2 deletions(-)
-
---- a/drivers/firmware/raspberrypi.c
-+++ b/drivers/firmware/raspberrypi.c
-@@ -28,6 +28,8 @@ struct rpi_firmware {
- u32 enabled;
- };
-
-+static struct platform_device *g_pdev;
-+
- static DEFINE_MUTEX(transaction_lock);
-
- static void response_callback(struct mbox_client *cl, void *msg)
-@@ -183,6 +185,25 @@ rpi_firmware_print_firmware_revision(str
- }
- }
-
-+static int raspberrypi_firmware_set_power(struct rpi_firmware *fw,
-+ u32 domain, bool on)
-+{
-+ struct {
-+ u32 domain;
-+ u32 on;
-+ } packet;
-+ int ret;
-+
-+ packet.domain = domain;
-+ packet.on = on;
-+ ret = rpi_firmware_property(fw, RPI_FIRMWARE_SET_POWER_STATE,
-+ &packet, sizeof(packet));
-+ if (!ret && packet.on != on)
-+ ret = -EINVAL;
-+
-+ return ret;
-+}
-+
- static int rpi_firmware_probe(struct platform_device *pdev)
- {
- struct device *dev = &pdev->dev;
-@@ -207,9 +228,13 @@ static int rpi_firmware_probe(struct pla
- init_completion(&fw->c);
-
- platform_set_drvdata(pdev, fw);
-+ g_pdev = pdev;
-
- rpi_firmware_print_firmware_revision(fw);
-
-+ if (raspberrypi_firmware_set_power(fw, 3, true))
-+ dev_err(dev, "failed to turn on USB power\n");
-+
- return 0;
- }
-
-@@ -218,6 +243,7 @@ static int rpi_firmware_remove(struct pl
- struct rpi_firmware *fw = platform_get_drvdata(pdev);
-
- mbox_free_channel(fw->chan);
-+ g_pdev = NULL;
-
- return 0;
- }
-@@ -230,7 +256,7 @@ static int rpi_firmware_remove(struct pl
- */
- struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node)
- {
-- struct platform_device *pdev = of_find_device_by_node(firmware_node);
-+ struct platform_device *pdev = g_pdev;
-
- if (!pdev)
- return NULL;
-@@ -253,7 +279,18 @@ static struct platform_driver rpi_firmwa
- .probe = rpi_firmware_probe,
- .remove = rpi_firmware_remove,
- };
--module_platform_driver(rpi_firmware_driver);
-+
-+static int __init rpi_firmware_init(void)
-+{
-+ return platform_driver_register(&rpi_firmware_driver);
-+}
-+subsys_initcall(rpi_firmware_init);
-+
-+static void __init rpi_firmware_exit(void)
-+{
-+ platform_driver_unregister(&rpi_firmware_driver);
-+}
-+module_exit(rpi_firmware_exit);
-
- MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
- MODULE_DESCRIPTION("Raspberry Pi firmware driver");
diff --git a/target/linux/brcm2708/patches-4.4/0049-bcm2835-add-v4l2-camera-device.patch b/target/linux/brcm2708/patches-4.4/0049-bcm2835-add-v4l2-camera-device.patch
deleted file mode 100644
index a464881a16..0000000000
--- a/target/linux/brcm2708/patches-4.4/0049-bcm2835-add-v4l2-camera-device.patch
+++ /dev/null
@@ -1,7338 +0,0 @@
-From 4d74ee3d433df319ae3fc36bd16fd96b4bbff865 Mon Sep 17 00:00:00 2001
-From: Vincent Sanders <vincent.sanders@collabora.co.uk>
-Date: Wed, 30 Jan 2013 12:45:18 +0000
-Subject: [PATCH 049/170] bcm2835: add v4l2 camera device
-
-- Supports raw YUV capture, preview, JPEG and H264.
-- Uses videobuf2 for data transfer, using dma_buf.
-- Uses 3.6.10 timestamping
-- Camera power based on use
-- Uses immutable input mode on video encoder
-
-Signed-off-by: Daniel Stone <daniels@collabora.com>
-Signed-off-by: Luke Diamand <luked@broadcom.com>
-
-V4L2: Fixes from 6by9
-
-V4L2: Fix EV values. Add manual shutter speed control
-
-V4L2 EV values should be in units of 1/1000. Corrected.
-Add support for V4L2_CID_EXPOSURE_ABSOLUTE which should
-give manual shutter control. Requires manual exposure mode
-to be selected first.
-
-Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
-
-V4L2: Correct JPEG Q-factor range
-
-Should be 1-100, not 0-100
-
-Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
-
-V4L2: Fix issue of driver jamming if STREAMON failed.
-
-Fix issue where the driver was left in a partially enabled
-state if STREAMON failed, and would then reject many IOCTLs
-as it thought it was streaming.
-
-Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
-
-V4L2: Fix ISO controls.
-
-Driver was passing the index to the GPU, and not the desired
-ISO value.
-
-Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
-
-V4L2: Add flicker avoidance controls
-
-Add support for V4L2_CID_POWER_LINE_FREQUENCY to set flicker
-avoidance frequencies.
-
-Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
-
-V4L2: Add support for frame rate control.
-
-Add support for frame rate (or time per frame as V4L2
-inverts it) control via s_parm.
-
-Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
-
-V4L2: Improve G_FBUF handling so we pass conformance
-
-Return some sane numbers for get framebuffer so that
-we pass conformance.
-
-Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
-
-V4L2: Fix information advertised through g_vidfmt
-
-Width and height were being stored based on incorrect
-values.
-
-Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
-
-V4L2: Add support for inline H264 headers
-
-Add support for V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER
-to control H264 inline headers.
-Requires firmware fix to work correctly, otherwise format
-has to be set to H264 before this parameter is set.
-
-Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
-
-V4L2: Fix JPEG timestamp issue
-
-JPEG images were coming through from the GPU with timestamp
-of 0. Detect this and give current system time instead
-of some invalid value.
-
-Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
-
-V4L2: Fix issue when switching down JPEG resolution.
-
-JPEG buffer size calculation is based on input resolution.
-Input resolution was being configured after output port
-format. Caused failures if switching from one JPEG resolution
-to a smaller one.
-
-Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
-
-V4L2: Enable MJPEG encoding
-
-Requires GPU firmware update to support MJPEG encoder.
-
-Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
-
-V4L2: Correct flag settings for compressed formats
-
-Set flags field correctly on enum_fmt_vid_cap for compressed
-image formats.
-
-Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
-
-V4L2: H264 profile & level ctrls, FPS control and auto exp pri
-
-Several control handling updates.
-H264 profile and level controls.
-Timeperframe/FPS reworked to add V4L2_CID_EXPOSURE_AUTO_PRIORITY to
-select whether AE is allowed to override the framerate specified.
-
-Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
-
-V4L2: Correct BGR24 to RGB24 in format table
-
-Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
-
-V4L2: Add additional pixel formats. Correct colourspace
-
-Adds the other flavours of YUYV, and NV12.
-Corrects the overlay advertised colourspace.
-
-Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
-
-V4L2: Drop logging msg from info to debug
-
-Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
-
-V4L2: Initial pass at scene modes.
-
-Only supports exposure mode and metering modes.
-
-Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
-
-V4L2: Add manual white balance control.
-
-Adds support for V4L2_CID_RED_BALANCE and
-V4L2_CID_BLUE_BALANCE. Only has an effect if
-V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE has
-V4L2_WHITE_BALANCE_MANUAL selected.
-
-Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
-
-config: Enable V4L / MMAL driver
-
-V4L2: Increase the MMAL timeout to 3sec
-
-MJPEG codec flush is now taking longer and results
-in a kernel panic if the driver has stopped waiting for
-the result when it finally completes.
-Increase the timeout value from 1 to 3secs.
-
-Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
-
-V4L2: Add support for setting H264_I_PERIOD
-
-Adds support for the parameter V4L2_CID_MPEG_VIDEO_H264_I_PERIOD
-to set the frequency with which I frames are produced.
-
-Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
-
-V4L2: Enable GPU function for removing padding from images.
-
-GPU can now support arbitrary strides, although may require
-additional processing to achieve it. Enable this feature
-so that the images delivered are the size requested.
-
-Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
-
-V4L2: Add support for V4L2_PIX_FMT_BGR32
-
-Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
-
-V4L2: Set the colourspace to avoid odd YUV-RGB conversions
-
-Removes the amiguity from the conversion routines and stops
-them dropping back to the SD vs HD choice of coeffs.
-
-Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
-
-V4L2: Make video/still threshold a run-time param
-
-Move the define for at what resolution the driver
-switches from a video mode capture to a stills mode
-capture to module parameters.
-
-Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
-
-V4L2: Fix incorrect pool sizing
-
-Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
-
-V4L2: Add option to disable enum_framesizes.
-
-Gstreamer's handling of a driver that advertises
-V4L2_FRMSIZE_TYPE_STEPWISE to define the supported
-resolutions is broken. See bug
-https://bugzilla.gnome.org/show_bug.cgi?id=726521
-
-Optional parameter of gst_v4l2src_is_broken added.
-If non-zero, the driver claims not to support that
-ioctl, and gstreamer should be happy again (it
-guesses a set of defaults for itself).
-
-Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
-
-V4L2: Add support for more image formats
-
-Adds YVU420 (YV12), YVU420SP (NV21), and BGR888.
-
-Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
-
-V4L2: Extend range for V4L2_CID_MPEG_VIDEO_H264_I_PERIOD
-
-Request to extend the range from the fairly arbitrary
-1000 frames (33 seconds at 30fps). Extend out to the
-max range supported (int32 value).
-Also allow 0, which is handled by the codec as only
-send an I-frame on the first frame and never again.
-There may be an exception if it detects a significant
-scene change, but there's no easy way around that.
-
-Signed-off-by: Dave Stevenson <dsteve@broadcom.com>
-
-bcm2835-camera: stop_streaming now has a void return
-
-BCM2835-V4L2: Fix compliance test failures
-
-VIDIOC_TRY_FMT and VIDIOC_S_FMT tests were faling due
-to reporting V4L2_COLORSPACE_JPEG when the colour
-format wasn't V4L2_PIX_FMT_JPEG.
-Now reports V4L2_COLORSPACE_SMPTE170M for YUV formats.
-
-bcm2835 camera planar/packed stride length
-
-Added a field to the mmal_fmt struct used to compute the bytes per line
-when using a particular format. This results in the correct stride being
-calculated even when the format is planar.
-
-Signed-off-by: Garrett Wilson <g@floft.net>
-
-bcm2835: camera: check for scene not being found
-
-static analysis by cppcheck detected some potential NULL pointer
-dereference issues:
-
-[drivers/media/platform/bcm2835/controls.c:854]: (error) Possible null
- pointer dereference: scene
- (and lines 858, 859 too)
-
-it is possible that scene is not found because of an invalue ctrl->val
-and is therefore NULL and hence causing a null pointer dereference.
-
-Signed-off-by: Colin Ian King <colin.king@canonical.com>
-
-bcm2835: memcpy port data to m rather than rmsg
-
-static analysis by cppcheck detected a memcpy to rmsg which is
-not actually initialized at that point. The memcpy should be copying
-to variable m instead.
-
-Signed-off-by: Colin Ian King <colin.king@canonical.com>
-
-BCM2835-V4L2: Return buffers to videobuf2 on shutdown
-
-https://github.com/raspberrypi/linux/issues/817
-Fixes the kernel warning from videobuf2 as buffers
-are now returned as they are being flushed on
-stop_streaming.
-
-squash: Fixup bcm2835-camera for changes in kernel 4.4 api
----
- Documentation/video4linux/bcm2835-v4l2.txt | 60 +
- drivers/media/platform/Kconfig | 2 +
- drivers/media/platform/Makefile | 2 +
- drivers/media/platform/bcm2835/Kconfig | 25 +
- drivers/media/platform/bcm2835/Makefile | 5 +
- drivers/media/platform/bcm2835/bcm2835-camera.c | 1844 +++++++++++++++++++++
- drivers/media/platform/bcm2835/bcm2835-camera.h | 126 ++
- drivers/media/platform/bcm2835/controls.c | 1324 +++++++++++++++
- drivers/media/platform/bcm2835/mmal-common.h | 53 +
- drivers/media/platform/bcm2835/mmal-encodings.h | 127 ++
- drivers/media/platform/bcm2835/mmal-msg-common.h | 50 +
- drivers/media/platform/bcm2835/mmal-msg-format.h | 81 +
- drivers/media/platform/bcm2835/mmal-msg-port.h | 107 ++
- drivers/media/platform/bcm2835/mmal-msg.h | 404 +++++
- drivers/media/platform/bcm2835/mmal-parameters.h | 656 ++++++++
- drivers/media/platform/bcm2835/mmal-vchiq.c | 1916 ++++++++++++++++++++++
- drivers/media/platform/bcm2835/mmal-vchiq.h | 178 ++
- 17 files changed, 6960 insertions(+)
- create mode 100644 Documentation/video4linux/bcm2835-v4l2.txt
- create mode 100644 drivers/media/platform/bcm2835/Kconfig
- create mode 100644 drivers/media/platform/bcm2835/Makefile
- create mode 100644 drivers/media/platform/bcm2835/bcm2835-camera.c
- create mode 100644 drivers/media/platform/bcm2835/bcm2835-camera.h
- create mode 100644 drivers/media/platform/bcm2835/controls.c
- create mode 100644 drivers/media/platform/bcm2835/mmal-common.h
- create mode 100644 drivers/media/platform/bcm2835/mmal-encodings.h
- create mode 100644 drivers/media/platform/bcm2835/mmal-msg-common.h
- create mode 100644 drivers/media/platform/bcm2835/mmal-msg-format.h
- create mode 100644 drivers/media/platform/bcm2835/mmal-msg-port.h
- create mode 100644 drivers/media/platform/bcm2835/mmal-msg.h
- create mode 100644 drivers/media/platform/bcm2835/mmal-parameters.h
- create mode 100644 drivers/media/platform/bcm2835/mmal-vchiq.c
- create mode 100644 drivers/media/platform/bcm2835/mmal-vchiq.h
-
---- /dev/null
-+++ b/Documentation/video4linux/bcm2835-v4l2.txt
-@@ -0,0 +1,60 @@
-+
-+BCM2835 (aka Raspberry Pi) V4L2 driver
-+======================================
-+
-+1. Copyright
-+============
-+
-+Copyright © 2013 Raspberry Pi (Trading) Ltd.
-+
-+2. License
-+==========
-+
-+This program is free software; you can redistribute it and/or modify
-+it under the terms of the GNU General Public License as published by
-+the Free Software Foundation; either version 2 of the License, or
-+(at your option) any later version.
-+
-+This program is distributed in the hope that it will be useful,
-+but WITHOUT ANY WARRANTY; without even the implied warranty of
-+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+GNU General Public License for more details.
-+
-+You should have received a copy of the GNU General Public License
-+along with this program; if not, write to the Free Software
-+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-+
-+3. Quick Start
-+==============
-+
-+You need a version 1.0 or later of v4l2-ctl, available from:
-+ git://git.linuxtv.org/v4l-utils.git
-+
-+$ sudo modprobe bcm2835-v4l2
-+
-+Turn on the overlay:
-+
-+$ v4l2-ctl --overlay=1
-+
-+Turn off the overlay:
-+
-+$ v4l2-ctl --overlay=0
-+
-+Set the capture format for video:
-+
-+$ v4l2-ctl --set-fmt-video=width=1920,height=1088,pixelformat=4
-+
-+(Note: 1088 not 1080).
-+
-+Capture:
-+
-+$ v4l2-ctl --stream-mmap=3 --stream-count=100 --stream-to=somefile.h264
-+
-+Stills capture:
-+
-+$ v4l2-ctl --set-fmt-video=width=2592,height=1944,pixelformat=3
-+$ v4l2-ctl --stream-mmap=3 --stream-count=1 --stream-to=somefile.jpg
-+
-+List of available formats:
-+
-+$ v4l2-ctl --list-formats
---- a/drivers/media/platform/Kconfig
-+++ b/drivers/media/platform/Kconfig
-@@ -11,6 +11,8 @@ menuconfig V4L_PLATFORM_DRIVERS
-
- if V4L_PLATFORM_DRIVERS
-
-+source "drivers/media/platform/bcm2835/Kconfig"
-+
- source "drivers/media/platform/marvell-ccic/Kconfig"
-
- config VIDEO_VIA_CAMERA
---- a/drivers/media/platform/Makefile
-+++ b/drivers/media/platform/Makefile
-@@ -2,6 +2,8 @@
- # Makefile for the video capture/playback device drivers.
- #
-
-+obj-$(CONFIG_VIDEO_BCM2835) += bcm2835/
-+
- obj-$(CONFIG_VIDEO_TIMBERDALE) += timblogiw.o
- obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
-
---- /dev/null
-+++ b/drivers/media/platform/bcm2835/Kconfig
-@@ -0,0 +1,25 @@
-+# Broadcom VideoCore IV v4l2 camera support
-+
-+config VIDEO_BCM2835
-+ bool "Broadcom BCM2835 camera interface driver"
-+ depends on VIDEO_V4L2 && (ARCH_BCM2708 || ARCH_BCM2709 || ARCH_BCM2835)
-+ ---help---
-+ Say Y here to enable camera host interface devices for
-+ Broadcom BCM2835 SoC. This operates over the VCHIQ interface
-+ to a service running on VideoCore.
-+
-+
-+if VIDEO_BCM2835
-+
-+config VIDEO_BCM2835_MMAL
-+ tristate "Broadcom BM2835 MMAL camera interface driver"
-+ depends on BCM2708_VCHIQ
-+ select VIDEOBUF2_VMALLOC
-+ ---help---
-+ This is a V4L2 driver for the Broadcom BCM2835 MMAL camera host interface
-+
-+ To compile this driver as a module, choose M here: the
-+ module will be called bcm2835-v4l2.o
-+
-+
-+endif # VIDEO_BM2835
---- /dev/null
-+++ b/drivers/media/platform/bcm2835/Makefile
-@@ -0,0 +1,5 @@
-+bcm2835-v4l2-objs := bcm2835-camera.o controls.o mmal-vchiq.o
-+
-+obj-$(CONFIG_VIDEO_BCM2835_MMAL) += bcm2835-v4l2.o
-+
-+ccflags-$(CONFIG_VIDEO_BCM2835) += -Idrivers/misc/vc04_services -Idrivers/misc/vc04_services/interface/vcos/linuxkernel -D__VCCOREVER__=0x04000000
---- /dev/null
-+++ b/drivers/media/platform/bcm2835/bcm2835-camera.c
-@@ -0,0 +1,1844 @@
-+/*
-+ * Broadcom BM2835 V4L2 driver
-+ *
-+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
-+ *
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file COPYING in the main directory of this archive
-+ * for more details.
-+ *
-+ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
-+ * Dave Stevenson <dsteve@broadcom.com>
-+ * Simon Mellor <simellor@broadcom.com>
-+ * Luke Diamand <luked@broadcom.com>
-+ */
-+
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <media/videobuf2-vmalloc.h>
-+#include <media/videobuf2-dma-contig.h>
-+#include <media/v4l2-device.h>
-+#include <media/v4l2-ioctl.h>
-+#include <media/v4l2-ctrls.h>
-+#include <media/v4l2-fh.h>
-+#include <media/v4l2-event.h>
-+#include <media/v4l2-common.h>
-+#include <linux/delay.h>
-+
-+#include "mmal-common.h"
-+#include "mmal-encodings.h"
-+#include "mmal-vchiq.h"
-+#include "mmal-msg.h"
-+#include "mmal-parameters.h"
-+#include "bcm2835-camera.h"
-+
-+#define BM2835_MMAL_VERSION "0.0.2"
-+#define BM2835_MMAL_MODULE_NAME "bcm2835-v4l2"
-+#define MIN_WIDTH 16
-+#define MIN_HEIGHT 16
-+#define MAX_WIDTH 2592
-+#define MAX_HEIGHT 1944
-+#define MIN_BUFFER_SIZE (80*1024)
-+
-+#define MAX_VIDEO_MODE_WIDTH 1280
-+#define MAX_VIDEO_MODE_HEIGHT 720
-+
-+MODULE_DESCRIPTION("Broadcom 2835 MMAL video capture");
-+MODULE_AUTHOR("Vincent Sanders");
-+MODULE_LICENSE("GPL");
-+MODULE_VERSION(BM2835_MMAL_VERSION);
-+
-+int bcm2835_v4l2_debug;
-+module_param_named(debug, bcm2835_v4l2_debug, int, 0644);
-+MODULE_PARM_DESC(bcm2835_v4l2_debug, "Debug level 0-2");
-+
-+int max_video_width = MAX_VIDEO_MODE_WIDTH;
-+int max_video_height = MAX_VIDEO_MODE_HEIGHT;
-+module_param(max_video_width, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-+MODULE_PARM_DESC(max_video_width, "Threshold for video mode");
-+module_param(max_video_height, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-+MODULE_PARM_DESC(max_video_height, "Threshold for video mode");
-+
-+/* Gstreamer bug https://bugzilla.gnome.org/show_bug.cgi?id=726521
-+ * v4l2src does bad (and actually wrong) things when the vidioc_enum_framesizes
-+ * function says type V4L2_FRMSIZE_TYPE_STEPWISE, which we do by default.
-+ * It's happier if we just don't say anything at all, when it then
-+ * sets up a load of defaults that it thinks might work.
-+ * If gst_v4l2src_is_broken is non-zero, then we remove the function from
-+ * our function table list (actually switch to an alternate set, but same
-+ * result).
-+ */
-+int gst_v4l2src_is_broken = 0;
-+module_param(gst_v4l2src_is_broken, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-+MODULE_PARM_DESC(gst_v4l2src_is_broken, "If non-zero, enable workaround for Gstreamer");
-+
-+static struct bm2835_mmal_dev *gdev; /* global device data */
-+
-+#define FPS_MIN 1
-+#define FPS_MAX 90
-+
-+/* timeperframe: min/max and default */
-+static const struct v4l2_fract
-+ tpf_min = {.numerator = 1, .denominator = FPS_MAX},
-+ tpf_max = {.numerator = 1, .denominator = FPS_MIN},
-+ tpf_default = {.numerator = 1000, .denominator = 30000};
-+
-+/* video formats */
-+static struct mmal_fmt formats[] = {
-+ {
-+ .name = "4:2:0, planar, YUV",
-+ .fourcc = V4L2_PIX_FMT_YUV420,
-+ .flags = 0,
-+ .mmal = MMAL_ENCODING_I420,
-+ .depth = 12,
-+ .mmal_component = MMAL_COMPONENT_CAMERA,
-+ .ybbp = 1,
-+ },
-+ {
-+ .name = "4:2:2, packed, YUYV",
-+ .fourcc = V4L2_PIX_FMT_YUYV,
-+ .flags = 0,
-+ .mmal = MMAL_ENCODING_YUYV,
-+ .depth = 16,
-+ .mmal_component = MMAL_COMPONENT_CAMERA,
-+ .ybbp = 2,
-+ },
-+ {
-+ .name = "RGB24 (LE)",
-+ .fourcc = V4L2_PIX_FMT_RGB24,
-+ .flags = 0,
-+ .mmal = MMAL_ENCODING_BGR24,
-+ .depth = 24,
-+ .mmal_component = MMAL_COMPONENT_CAMERA,
-+ .ybbp = 3,
-+ },
-+ {
-+ .name = "JPEG",
-+ .fourcc = V4L2_PIX_FMT_JPEG,
-+ .flags = V4L2_FMT_FLAG_COMPRESSED,
-+ .mmal = MMAL_ENCODING_JPEG,
-+ .depth = 8,
-+ .mmal_component = MMAL_COMPONENT_IMAGE_ENCODE,
-+ .ybbp = 0,
-+ },
-+ {
-+ .name = "H264",
-+ .fourcc = V4L2_PIX_FMT_H264,
-+ .flags = V4L2_FMT_FLAG_COMPRESSED,
-+ .mmal = MMAL_ENCODING_H264,
-+ .depth = 8,
-+ .mmal_component = MMAL_COMPONENT_VIDEO_ENCODE,
-+ .ybbp = 0,
-+ },
-+ {
-+ .name = "MJPEG",
-+ .fourcc = V4L2_PIX_FMT_MJPEG,
-+ .flags = V4L2_FMT_FLAG_COMPRESSED,
-+ .mmal = MMAL_ENCODING_MJPEG,
-+ .depth = 8,
-+ .mmal_component = MMAL_COMPONENT_VIDEO_ENCODE,
-+ .ybbp = 0,
-+ },
-+ {
-+ .name = "4:2:2, packed, YVYU",
-+ .fourcc = V4L2_PIX_FMT_YVYU,
-+ .flags = 0,
-+ .mmal = MMAL_ENCODING_YVYU,
-+ .depth = 16,
-+ .mmal_component = MMAL_COMPONENT_CAMERA,
-+ .ybbp = 2,
-+ },
-+ {
-+ .name = "4:2:2, packed, VYUY",
-+ .fourcc = V4L2_PIX_FMT_VYUY,
-+ .flags = 0,
-+ .mmal = MMAL_ENCODING_VYUY,
-+ .depth = 16,
-+ .mmal_component = MMAL_COMPONENT_CAMERA,
-+ .ybbp = 2,
-+ },
-+ {
-+ .name = "4:2:2, packed, UYVY",
-+ .fourcc = V4L2_PIX_FMT_UYVY,
-+ .flags = 0,
-+ .mmal = MMAL_ENCODING_UYVY,
-+ .depth = 16,
-+ .mmal_component = MMAL_COMPONENT_CAMERA,
-+ .ybbp = 2,
-+ },
-+ {
-+ .name = "4:2:0, planar, NV12",
-+ .fourcc = V4L2_PIX_FMT_NV12,
-+ .flags = 0,
-+ .mmal = MMAL_ENCODING_NV12,
-+ .depth = 12,
-+ .mmal_component = MMAL_COMPONENT_CAMERA,
-+ .ybbp = 1,
-+ },
-+ {
-+ .name = "RGB24 (BE)",
-+ .fourcc = V4L2_PIX_FMT_BGR24,
-+ .flags = 0,
-+ .mmal = MMAL_ENCODING_RGB24,
-+ .depth = 24,
-+ .mmal_component = MMAL_COMPONENT_CAMERA,
-+ .ybbp = 3,
-+ },
-+ {
-+ .name = "4:2:0, planar, YVU",
-+ .fourcc = V4L2_PIX_FMT_YVU420,
-+ .flags = 0,
-+ .mmal = MMAL_ENCODING_YV12,
-+ .depth = 12,
-+ .mmal_component = MMAL_COMPONENT_CAMERA,
-+ .ybbp = 1,
-+ },
-+ {
-+ .name = "4:2:0, planar, NV21",
-+ .fourcc = V4L2_PIX_FMT_NV21,
-+ .flags = 0,
-+ .mmal = MMAL_ENCODING_NV21,
-+ .depth = 12,
-+ .mmal_component = MMAL_COMPONENT_CAMERA,
-+ .ybbp = 1,
-+ },
-+ {
-+ .name = "RGB32 (BE)",
-+ .fourcc = V4L2_PIX_FMT_BGR32,
-+ .flags = 0,
-+ .mmal = MMAL_ENCODING_BGRA,
-+ .depth = 32,
-+ .mmal_component = MMAL_COMPONENT_CAMERA,
-+ .ybbp = 4,
-+ },
-+};
-+
-+static struct mmal_fmt *get_format(struct v4l2_format *f)
-+{
-+ struct mmal_fmt *fmt;
-+ unsigned int k;
-+
-+ for (k = 0; k < ARRAY_SIZE(formats); k++) {
-+ fmt = &formats[k];
-+ if (fmt->fourcc == f->fmt.pix.pixelformat)
-+ break;
-+ }
-+
-+ if (k == ARRAY_SIZE(formats))
-+ return NULL;
-+
-+ return &formats[k];
-+}
-+
-+/* ------------------------------------------------------------------
-+ Videobuf queue operations
-+ ------------------------------------------------------------------*/
-+
-+static int queue_setup(struct vb2_queue *vq, const void *parg,
-+ unsigned int *nbuffers, unsigned int *nplanes,
-+ unsigned int sizes[], void *alloc_ctxs[])
-+{
-+ struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq);
-+ unsigned long size;
-+
-+ /* refuse queue setup if port is not configured */
-+ if (dev->capture.port == NULL) {
-+ v4l2_err(&dev->v4l2_dev,
-+ "%s: capture port not configured\n", __func__);
-+ return -EINVAL;
-+ }
-+
-+ size = dev->capture.port->current_buffer.size;
-+ if (size == 0) {
-+ v4l2_err(&dev->v4l2_dev,
-+ "%s: capture port buffer size is zero\n", __func__);
-+ return -EINVAL;
-+ }
-+
-+ if (*nbuffers < (dev->capture.port->current_buffer.num + 2))
-+ *nbuffers = (dev->capture.port->current_buffer.num + 2);
-+
-+ *nplanes = 1;
-+
-+ sizes[0] = size;
-+
-+ /*
-+ * videobuf2-vmalloc allocator is context-less so no need to set
-+ * alloc_ctxs array.
-+ */
-+
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p\n",
-+ __func__, dev);
-+
-+ return 0;
-+}
-+
-+static int buffer_prepare(struct vb2_buffer *vb)
-+{
-+ struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
-+ unsigned long size;
-+
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p\n",
-+ __func__, dev);
-+
-+ BUG_ON(dev->capture.port == NULL);
-+ BUG_ON(dev->capture.fmt == NULL);
-+
-+ size = dev->capture.stride * dev->capture.height;
-+ if (vb2_plane_size(vb, 0) < size) {
-+ v4l2_err(&dev->v4l2_dev,
-+ "%s data will not fit into plane (%lu < %lu)\n",
-+ __func__, vb2_plane_size(vb, 0), size);
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+static inline bool is_capturing(struct bm2835_mmal_dev *dev)
-+{
-+ return dev->capture.camera_port ==
-+ &dev->
-+ component[MMAL_COMPONENT_CAMERA]->output[MMAL_CAMERA_PORT_CAPTURE];
-+}
-+
-+static void buffer_cb(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port,
-+ int status,
-+ struct mmal_buffer *buf,
-+ unsigned long length, u32 mmal_flags, s64 dts, s64 pts)
-+{
-+ struct bm2835_mmal_dev *dev = port->cb_ctx;
-+
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "%s: status:%d, buf:%p, length:%lu, flags %u, pts %lld\n",
-+ __func__, status, buf, length, mmal_flags, pts);
-+
-+ if (status != 0) {
-+ /* error in transfer */
-+ if (buf != NULL) {
-+ /* there was a buffer with the error so return it */
-+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
-+ }
-+ return;
-+ } else if (length == 0) {
-+ /* stream ended */
-+ if (buf != NULL) {
-+ /* this should only ever happen if the port is
-+ * disabled and there are buffers still queued
-+ */
-+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
-+ pr_debug("Empty buffer");
-+ } else if (dev->capture.frame_count) {
-+ /* grab another frame */
-+ if (is_capturing(dev)) {
-+ pr_debug("Grab another frame");
-+ vchiq_mmal_port_parameter_set(
-+ instance,
-+ dev->capture.
-+ camera_port,
-+ MMAL_PARAMETER_CAPTURE,
-+ &dev->capture.
-+ frame_count,
-+ sizeof(dev->capture.frame_count));
-+ }
-+ } else {
-+ /* signal frame completion */
-+ complete(&dev->capture.frame_cmplt);
-+ }
-+ } else {
-+ if (dev->capture.frame_count) {
-+ if (dev->capture.vc_start_timestamp != -1 &&
-+ pts != 0) {
-+ s64 runtime_us = pts -
-+ dev->capture.vc_start_timestamp;
-+ u32 div = 0;
-+ u32 rem = 0;
-+
-+ div =
-+ div_u64_rem(runtime_us, USEC_PER_SEC, &rem);
-+ buf->vb.timestamp.tv_sec =
-+ dev->capture.kernel_start_ts.tv_sec - 1 +
-+ div;
-+ buf->vb.timestamp.tv_usec =
-+ dev->capture.kernel_start_ts.tv_usec + rem;
-+
-+ if (buf->vb.timestamp.tv_usec >=
-+ USEC_PER_SEC) {
-+ buf->vb.timestamp.tv_sec++;
-+ buf->vb.timestamp.tv_usec -=
-+ USEC_PER_SEC;
-+ }
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "Convert start time %d.%06d and %llu "
-+ "with offset %llu to %d.%06d\n",
-+ (int)dev->capture.kernel_start_ts.
-+ tv_sec,
-+ (int)dev->capture.kernel_start_ts.
-+ tv_usec,
-+ dev->capture.vc_start_timestamp, pts,
-+ (int)buf->vb.timestamp.tv_sec,
-+ (int)buf->vb.timestamp.
-+ tv_usec);
-+ } else {
-+ v4l2_get_timestamp(&buf->vb.timestamp);
-+ }
-+
-+ vb2_set_plane_payload(&buf->vb.vb2_buf, 0, length);
-+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
-+
-+ if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS &&
-+ is_capturing(dev)) {
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "Grab another frame as buffer has EOS");
-+ vchiq_mmal_port_parameter_set(
-+ instance,
-+ dev->capture.
-+ camera_port,
-+ MMAL_PARAMETER_CAPTURE,
-+ &dev->capture.
-+ frame_count,
-+ sizeof(dev->capture.frame_count));
-+ }
-+ } else {
-+ /* signal frame completion */
-+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
-+ complete(&dev->capture.frame_cmplt);
-+ }
-+ }
-+}
-+
-+static int enable_camera(struct bm2835_mmal_dev *dev)
-+{
-+ int ret;
-+ if (!dev->camera_use_count) {
-+ ret = vchiq_mmal_component_enable(
-+ dev->instance,
-+ dev->component[MMAL_COMPONENT_CAMERA]);
-+ if (ret < 0) {
-+ v4l2_err(&dev->v4l2_dev,
-+ "Failed enabling camera, ret %d\n", ret);
-+ return -EINVAL;
-+ }
-+ }
-+ dev->camera_use_count++;
-+ v4l2_dbg(1, bcm2835_v4l2_debug,
-+ &dev->v4l2_dev, "enabled camera (refcount %d)\n",
-+ dev->camera_use_count);
-+ return 0;
-+}
-+
-+static int disable_camera(struct bm2835_mmal_dev *dev)
-+{
-+ int ret;
-+ if (!dev->camera_use_count) {
-+ v4l2_err(&dev->v4l2_dev,
-+ "Disabled the camera when already disabled\n");
-+ return -EINVAL;
-+ }
-+ dev->camera_use_count--;
-+ if (!dev->camera_use_count) {
-+ unsigned int i = 0xFFFFFFFF;
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "Disabling camera\n");
-+ ret =
-+ vchiq_mmal_component_disable(
-+ dev->instance,
-+ dev->component[MMAL_COMPONENT_CAMERA]);
-+ if (ret < 0) {
-+ v4l2_err(&dev->v4l2_dev,
-+ "Failed disabling camera, ret %d\n", ret);
-+ return -EINVAL;
-+ }
-+ vchiq_mmal_port_parameter_set(
-+ dev->instance,
-+ &dev->component[MMAL_COMPONENT_CAMERA]->control,
-+ MMAL_PARAMETER_CAMERA_NUM, &i,
-+ sizeof(i));
-+ }
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "Camera refcount now %d\n", dev->camera_use_count);
-+ return 0;
-+}
-+
-+static void buffer_queue(struct vb2_buffer *vb)
-+{
-+ struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
-+ struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb);
-+ struct mmal_buffer *buf = container_of(vb2, struct mmal_buffer, vb);
-+ int ret;
-+
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "%s: dev:%p buf:%p\n", __func__, dev, buf);
-+
-+ buf->buffer = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
-+ buf->buffer_size = vb2_plane_size(&buf->vb.vb2_buf, 0);
-+
-+ ret = vchiq_mmal_submit_buffer(dev->instance, dev->capture.port, buf);
-+ if (ret < 0)
-+ v4l2_err(&dev->v4l2_dev, "%s: error submitting buffer\n",
-+ __func__);
-+}
-+
-+static int start_streaming(struct vb2_queue *vq, unsigned int count)
-+{
-+ struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq);
-+ int ret;
-+ int parameter_size;
-+
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p\n",
-+ __func__, dev);
-+
-+ /* ensure a format has actually been set */
-+ if (dev->capture.port == NULL)
-+ return -EINVAL;
-+
-+ if (enable_camera(dev) < 0) {
-+ v4l2_err(&dev->v4l2_dev, "Failed to enable camera\n");
-+ return -EINVAL;
-+ }
-+
-+ /*init_completion(&dev->capture.frame_cmplt); */
-+
-+ /* enable frame capture */
-+ dev->capture.frame_count = 1;
-+
-+ /* if the preview is not already running, wait for a few frames for AGC
-+ * to settle down.
-+ */
-+ if (!dev->component[MMAL_COMPONENT_PREVIEW]->enabled)
-+ msleep(300);
-+
-+ /* enable the connection from camera to encoder (if applicable) */
-+ if (dev->capture.camera_port != dev->capture.port
-+ && dev->capture.camera_port) {
-+ ret = vchiq_mmal_port_enable(dev->instance,
-+ dev->capture.camera_port, NULL);
-+ if (ret) {
-+ v4l2_err(&dev->v4l2_dev,
-+ "Failed to enable encode tunnel - error %d\n",
-+ ret);
-+ return -1;
-+ }
-+ }
-+
-+ /* Get VC timestamp at this point in time */
-+ parameter_size = sizeof(dev->capture.vc_start_timestamp);
-+ if (vchiq_mmal_port_parameter_get(dev->instance,
-+ dev->capture.camera_port,
-+ MMAL_PARAMETER_SYSTEM_TIME,
-+ &dev->capture.vc_start_timestamp,
-+ &parameter_size)) {
-+ v4l2_err(&dev->v4l2_dev,
-+ "Failed to get VC start time - update your VC f/w\n");
-+
-+ /* Flag to indicate just to rely on kernel timestamps */
-+ dev->capture.vc_start_timestamp = -1;
-+ } else
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "Start time %lld size %d\n",
-+ dev->capture.vc_start_timestamp, parameter_size);
-+
-+ v4l2_get_timestamp(&dev->capture.kernel_start_ts);
-+
-+ /* enable the camera port */
-+ dev->capture.port->cb_ctx = dev;
-+ ret =
-+ vchiq_mmal_port_enable(dev->instance, dev->capture.port, buffer_cb);
-+ if (ret) {
-+ v4l2_err(&dev->v4l2_dev,
-+ "Failed to enable capture port - error %d. "
-+ "Disabling camera port again\n", ret);
-+
-+ vchiq_mmal_port_disable(dev->instance,
-+ dev->capture.camera_port);
-+ if (disable_camera(dev) < 0) {
-+ v4l2_err(&dev->v4l2_dev, "Failed to disable camera\n");
-+ return -EINVAL;
-+ }
-+ return -1;
-+ }
-+
-+ /* capture the first frame */
-+ vchiq_mmal_port_parameter_set(dev->instance,
-+ dev->capture.camera_port,
-+ MMAL_PARAMETER_CAPTURE,
-+ &dev->capture.frame_count,
-+ sizeof(dev->capture.frame_count));
-+ return 0;
-+}
-+
-+/* abort streaming and wait for last buffer */
-+static void stop_streaming(struct vb2_queue *vq)
-+{
-+ int ret;
-+ struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq);
-+
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p\n",
-+ __func__, dev);
-+
-+ init_completion(&dev->capture.frame_cmplt);
-+ dev->capture.frame_count = 0;
-+
-+ /* ensure a format has actually been set */
-+ if (dev->capture.port == NULL) {
-+ v4l2_err(&dev->v4l2_dev,
-+ "no capture port - stream not started?\n");
-+ return;
-+ }
-+
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "stopping capturing\n");
-+
-+ /* stop capturing frames */
-+ vchiq_mmal_port_parameter_set(dev->instance,
-+ dev->capture.camera_port,
-+ MMAL_PARAMETER_CAPTURE,
-+ &dev->capture.frame_count,
-+ sizeof(dev->capture.frame_count));
-+
-+ /* wait for last frame to complete */
-+ ret = wait_for_completion_timeout(&dev->capture.frame_cmplt, HZ);
-+ if (ret <= 0)
-+ v4l2_err(&dev->v4l2_dev,
-+ "error %d waiting for frame completion\n", ret);
-+
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "disabling connection\n");
-+
-+ /* disable the connection from camera to encoder */
-+ ret = vchiq_mmal_port_disable(dev->instance, dev->capture.camera_port);
-+ if (!ret && dev->capture.camera_port != dev->capture.port) {
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "disabling port\n");
-+ ret = vchiq_mmal_port_disable(dev->instance, dev->capture.port);
-+ } else if (dev->capture.camera_port != dev->capture.port) {
-+ v4l2_err(&dev->v4l2_dev, "port_disable failed, error %d\n",
-+ ret);
-+ }
-+
-+ if (disable_camera(dev) < 0)
-+ v4l2_err(&dev->v4l2_dev, "Failed to disable camera\n");
-+}
-+
-+static void bm2835_mmal_lock(struct vb2_queue *vq)
-+{
-+ struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq);
-+ mutex_lock(&dev->mutex);
-+}
-+
-+static void bm2835_mmal_unlock(struct vb2_queue *vq)
-+{
-+ struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq);
-+ mutex_unlock(&dev->mutex);
-+}
-+
-+static struct vb2_ops bm2835_mmal_video_qops = {
-+ .queue_setup = queue_setup,
-+ .buf_prepare = buffer_prepare,
-+ .buf_queue = buffer_queue,
-+ .start_streaming = start_streaming,
-+ .stop_streaming = stop_streaming,
-+ .wait_prepare = bm2835_mmal_unlock,
-+ .wait_finish = bm2835_mmal_lock,
-+};
-+
-+/* ------------------------------------------------------------------
-+ IOCTL operations
-+ ------------------------------------------------------------------*/
-+
-+/* overlay ioctl */
-+static int vidioc_enum_fmt_vid_overlay(struct file *file, void *priv,
-+ struct v4l2_fmtdesc *f)
-+{
-+ struct mmal_fmt *fmt;
-+
-+ if (f->index >= ARRAY_SIZE(formats))
-+ return -EINVAL;
-+
-+ fmt = &formats[f->index];
-+
-+ strlcpy(f->description, fmt->name, sizeof(f->description));
-+ f->pixelformat = fmt->fourcc;
-+ f->flags = fmt->flags;
-+
-+ return 0;
-+}
-+
-+static int vidioc_g_fmt_vid_overlay(struct file *file, void *priv,
-+ struct v4l2_format *f)
-+{
-+ struct bm2835_mmal_dev *dev = video_drvdata(file);
-+
-+ f->fmt.win = dev->overlay;
-+
-+ return 0;
-+}
-+
-+static int vidioc_try_fmt_vid_overlay(struct file *file, void *priv,
-+ struct v4l2_format *f)
-+{
-+ /* Only support one format so get the current one. */
-+ vidioc_g_fmt_vid_overlay(file, priv, f);
-+
-+ /* todo: allow the size and/or offset to be changed. */
-+ return 0;
-+}
-+
-+static int vidioc_s_fmt_vid_overlay(struct file *file, void *priv,
-+ struct v4l2_format *f)
-+{
-+ struct bm2835_mmal_dev *dev = video_drvdata(file);
-+
-+ vidioc_try_fmt_vid_overlay(file, priv, f);
-+
-+ dev->overlay = f->fmt.win;
-+
-+ /* todo: program the preview port parameters */
-+ return 0;
-+}
-+
-+static int vidioc_overlay(struct file *file, void *f, unsigned int on)
-+{
-+ int ret;
-+ struct bm2835_mmal_dev *dev = video_drvdata(file);
-+ struct vchiq_mmal_port *src;
-+ struct vchiq_mmal_port *dst;
-+ struct mmal_parameter_displayregion prev_config = {
-+ .set = MMAL_DISPLAY_SET_LAYER | MMAL_DISPLAY_SET_ALPHA |
-+ MMAL_DISPLAY_SET_DEST_RECT | MMAL_DISPLAY_SET_FULLSCREEN,
-+ .layer = PREVIEW_LAYER,
-+ .alpha = 255,
-+ .fullscreen = 0,
-+ .dest_rect = {
-+ .x = dev->overlay.w.left,
-+ .y = dev->overlay.w.top,
-+ .width = dev->overlay.w.width,
-+ .height = dev->overlay.w.height,
-+ },
-+ };
-+
-+ if ((on && dev->component[MMAL_COMPONENT_PREVIEW]->enabled) ||
-+ (!on && !dev->component[MMAL_COMPONENT_PREVIEW]->enabled))
-+ return 0; /* already in requested state */
-+
-+ src =
-+ &dev->component[MMAL_COMPONENT_CAMERA]->
-+ output[MMAL_CAMERA_PORT_PREVIEW];
-+
-+ if (!on) {
-+ /* disconnect preview ports and disable component */
-+ ret = vchiq_mmal_port_disable(dev->instance, src);
-+ if (!ret)
-+ ret =
-+ vchiq_mmal_port_connect_tunnel(dev->instance, src,
-+ NULL);
-+ if (ret >= 0)
-+ ret = vchiq_mmal_component_disable(
-+ dev->instance,
-+ dev->component[MMAL_COMPONENT_PREVIEW]);
-+
-+ disable_camera(dev);
-+ return ret;
-+ }
-+
-+ /* set preview port format and connect it to output */
-+ dst = &dev->component[MMAL_COMPONENT_PREVIEW]->input[0];
-+
-+ ret = vchiq_mmal_port_set_format(dev->instance, src);
-+ if (ret < 0)
-+ goto error;
-+
-+ ret = vchiq_mmal_port_parameter_set(dev->instance, dst,
-+ MMAL_PARAMETER_DISPLAYREGION,
-+ &prev_config, sizeof(prev_config));
-+ if (ret < 0)
-+ goto error;
-+
-+ if (enable_camera(dev) < 0)
-+ goto error;
-+
-+ ret = vchiq_mmal_component_enable(
-+ dev->instance,
-+ dev->component[MMAL_COMPONENT_PREVIEW]);
-+ if (ret < 0)
-+ goto error;
-+
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "connecting %p to %p\n",
-+ src, dst);
-+ ret = vchiq_mmal_port_connect_tunnel(dev->instance, src, dst);
-+ if (!ret)
-+ ret = vchiq_mmal_port_enable(dev->instance, src, NULL);
-+error:
-+ return ret;
-+}
-+
-+static int vidioc_g_fbuf(struct file *file, void *fh,
-+ struct v4l2_framebuffer *a)
-+{
-+ /* The video overlay must stay within the framebuffer and can't be
-+ positioned independently. */
-+ struct bm2835_mmal_dev *dev = video_drvdata(file);
-+ struct vchiq_mmal_port *preview_port =
-+ &dev->component[MMAL_COMPONENT_CAMERA]->
-+ output[MMAL_CAMERA_PORT_PREVIEW];
-+ a->flags = V4L2_FBUF_FLAG_OVERLAY;
-+ a->fmt.width = preview_port->es.video.width;
-+ a->fmt.height = preview_port->es.video.height;
-+ a->fmt.pixelformat = V4L2_PIX_FMT_YUV420;
-+ a->fmt.bytesperline = preview_port->es.video.width;
-+ a->fmt.sizeimage = (preview_port->es.video.width *
-+ preview_port->es.video.height * 3)>>1;
-+ a->fmt.colorspace = V4L2_COLORSPACE_SMPTE170M;
-+
-+ return 0;
-+}
-+
-+/* input ioctls */
-+static int vidioc_enum_input(struct file *file, void *priv,
-+ struct v4l2_input *inp)
-+{
-+ /* only a single camera input */
-+ if (inp->index != 0)
-+ return -EINVAL;
-+
-+ inp->type = V4L2_INPUT_TYPE_CAMERA;
-+ sprintf(inp->name, "Camera %u", inp->index);
-+ return 0;
-+}
-+
-+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
-+{
-+ *i = 0;
-+ return 0;
-+}
-+
-+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
-+{
-+ if (i != 0)
-+ return -EINVAL;
-+
-+ return 0;
-+}
-+
-+/* capture ioctls */
-+static int vidioc_querycap(struct file *file, void *priv,
-+ struct v4l2_capability *cap)
-+{
-+ struct bm2835_mmal_dev *dev = video_drvdata(file);
-+ u32 major;
-+ u32 minor;
-+
-+ vchiq_mmal_version(dev->instance, &major, &minor);
-+
-+ strcpy(cap->driver, "bm2835 mmal");
-+ snprintf(cap->card, sizeof(cap->card), "mmal service %d.%d",
-+ major, minor);
-+
-+ snprintf(cap->bus_info, sizeof(cap->bus_info),
-+ "platform:%s", dev->v4l2_dev.name);
-+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY |
-+ V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
-+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
-+
-+ return 0;
-+}
-+
-+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
-+ struct v4l2_fmtdesc *f)
-+{
-+ struct mmal_fmt *fmt;
-+
-+ if (f->index >= ARRAY_SIZE(formats))
-+ return -EINVAL;
-+
-+ fmt = &formats[f->index];
-+
-+ strlcpy(f->description, fmt->name, sizeof(f->description));
-+ f->pixelformat = fmt->fourcc;
-+ f->flags = fmt->flags;
-+
-+ return 0;
-+}
-+
-+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
-+ struct v4l2_format *f)
-+{
-+ struct bm2835_mmal_dev *dev = video_drvdata(file);
-+
-+ f->fmt.pix.width = dev->capture.width;
-+ f->fmt.pix.height = dev->capture.height;
-+ f->fmt.pix.field = V4L2_FIELD_NONE;
-+ f->fmt.pix.pixelformat = dev->capture.fmt->fourcc;
-+ f->fmt.pix.bytesperline = dev->capture.stride;
-+ f->fmt.pix.sizeimage = dev->capture.buffersize;
-+
-+ if (dev->capture.fmt->fourcc == V4L2_PIX_FMT_RGB24)
-+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
-+ else if (dev->capture.fmt->fourcc == V4L2_PIX_FMT_JPEG)
-+ f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
-+ else
-+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-+ f->fmt.pix.priv = 0;
-+
-+ v4l2_dump_pix_format(1, bcm2835_v4l2_debug, &dev->v4l2_dev, &f->fmt.pix,
-+ __func__);
-+ return 0;
-+}
-+
-+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
-+ struct v4l2_format *f)
-+{
-+ struct bm2835_mmal_dev *dev = video_drvdata(file);
-+ struct mmal_fmt *mfmt;
-+
-+ mfmt = get_format(f);
-+ if (!mfmt) {
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "Fourcc format (0x%08x) unknown.\n",
-+ f->fmt.pix.pixelformat);
-+ f->fmt.pix.pixelformat = formats[0].fourcc;
-+ mfmt = get_format(f);
-+ }
-+
-+ f->fmt.pix.field = V4L2_FIELD_NONE;
-+
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "Clipping/aligning %dx%d format %08X\n",
-+ f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.pixelformat);
-+
-+ v4l_bound_align_image(&f->fmt.pix.width, MIN_WIDTH, MAX_WIDTH, 1,
-+ &f->fmt.pix.height, MIN_HEIGHT, MAX_HEIGHT, 1, 0);
-+ f->fmt.pix.bytesperline = f->fmt.pix.width * mfmt->ybbp;
-+
-+ /* Image buffer has to be padded to allow for alignment, even though
-+ * we then remove that padding before delivering the buffer.
-+ */
-+ f->fmt.pix.sizeimage = ((f->fmt.pix.height+15)&~15) *
-+ (((f->fmt.pix.width+31)&~31) * mfmt->depth) >> 3;
-+
-+ if ((mfmt->flags & V4L2_FMT_FLAG_COMPRESSED) &&
-+ f->fmt.pix.sizeimage < MIN_BUFFER_SIZE)
-+ f->fmt.pix.sizeimage = MIN_BUFFER_SIZE;
-+
-+ if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24)
-+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
-+ else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG)
-+ f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
-+ else
-+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-+ f->fmt.pix.priv = 0;
-+
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "Now %dx%d format %08X\n",
-+ f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.pixelformat);
-+
-+ v4l2_dump_pix_format(1, bcm2835_v4l2_debug, &dev->v4l2_dev, &f->fmt.pix,
-+ __func__);
-+ return 0;
-+}
-+
-+static int mmal_setup_components(struct bm2835_mmal_dev *dev,
-+ struct v4l2_format *f)
-+{
-+ int ret;
-+ struct vchiq_mmal_port *port = NULL, *camera_port = NULL;
-+ struct vchiq_mmal_component *encode_component = NULL;
-+ struct mmal_fmt *mfmt = get_format(f);
-+
-+ BUG_ON(!mfmt);
-+
-+ if (dev->capture.encode_component) {
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "vid_cap - disconnect previous tunnel\n");
-+
-+ /* Disconnect any previous connection */
-+ vchiq_mmal_port_connect_tunnel(dev->instance,
-+ dev->capture.camera_port, NULL);
-+ dev->capture.camera_port = NULL;
-+ ret = vchiq_mmal_component_disable(dev->instance,
-+ dev->capture.
-+ encode_component);
-+ if (ret)
-+ v4l2_err(&dev->v4l2_dev,
-+ "Failed to disable encode component %d\n",
-+ ret);
-+
-+ dev->capture.encode_component = NULL;
-+ }
-+ /* format dependant port setup */
-+ switch (mfmt->mmal_component) {
-+ case MMAL_COMPONENT_CAMERA:
-+ /* Make a further decision on port based on resolution */
-+ if (f->fmt.pix.width <= max_video_width
-+ && f->fmt.pix.height <= max_video_height)
-+ camera_port = port =
-+ &dev->component[MMAL_COMPONENT_CAMERA]->
-+ output[MMAL_CAMERA_PORT_VIDEO];
-+ else
-+ camera_port = port =
-+ &dev->component[MMAL_COMPONENT_CAMERA]->
-+ output[MMAL_CAMERA_PORT_CAPTURE];
-+ break;
-+ case MMAL_COMPONENT_IMAGE_ENCODE:
-+ encode_component = dev->component[MMAL_COMPONENT_IMAGE_ENCODE];
-+ port = &dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->output[0];
-+ camera_port =
-+ &dev->component[MMAL_COMPONENT_CAMERA]->
-+ output[MMAL_CAMERA_PORT_CAPTURE];
-+ break;
-+ case MMAL_COMPONENT_VIDEO_ENCODE:
-+ encode_component = dev->component[MMAL_COMPONENT_VIDEO_ENCODE];
-+ port = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
-+ camera_port =
-+ &dev->component[MMAL_COMPONENT_CAMERA]->
-+ output[MMAL_CAMERA_PORT_VIDEO];
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ if (!port)
-+ return -EINVAL;
-+
-+ if (encode_component)
-+ camera_port->format.encoding = MMAL_ENCODING_OPAQUE;
-+ else
-+ camera_port->format.encoding = mfmt->mmal;
-+
-+ camera_port->format.encoding_variant = 0;
-+ camera_port->es.video.width = f->fmt.pix.width;
-+ camera_port->es.video.height = f->fmt.pix.height;
-+ camera_port->es.video.crop.x = 0;
-+ camera_port->es.video.crop.y = 0;
-+ camera_port->es.video.crop.width = f->fmt.pix.width;
-+ camera_port->es.video.crop.height = f->fmt.pix.height;
-+ camera_port->es.video.frame_rate.num = 0;
-+ camera_port->es.video.frame_rate.den = 1;
-+ camera_port->es.video.color_space = MMAL_COLOR_SPACE_JPEG_JFIF;
-+
-+ ret = vchiq_mmal_port_set_format(dev->instance, camera_port);
-+
-+ if (!ret
-+ && camera_port ==
-+ &dev->component[MMAL_COMPONENT_CAMERA]->
-+ output[MMAL_CAMERA_PORT_VIDEO]) {
-+ bool overlay_enabled =
-+ !!dev->component[MMAL_COMPONENT_PREVIEW]->enabled;
-+ struct vchiq_mmal_port *preview_port =
-+ &dev->component[MMAL_COMPONENT_CAMERA]->
-+ output[MMAL_CAMERA_PORT_PREVIEW];
-+ /* Preview and encode ports need to match on resolution */
-+ if (overlay_enabled) {
-+ /* Need to disable the overlay before we can update
-+ * the resolution
-+ */
-+ ret =
-+ vchiq_mmal_port_disable(dev->instance,
-+ preview_port);
-+ if (!ret)
-+ ret =
-+ vchiq_mmal_port_connect_tunnel(
-+ dev->instance,
-+ preview_port,
-+ NULL);
-+ }
-+ preview_port->es.video.width = f->fmt.pix.width;
-+ preview_port->es.video.height = f->fmt.pix.height;
-+ preview_port->es.video.crop.x = 0;
-+ preview_port->es.video.crop.y = 0;
-+ preview_port->es.video.crop.width = f->fmt.pix.width;
-+ preview_port->es.video.crop.height = f->fmt.pix.height;
-+ preview_port->es.video.frame_rate.num =
-+ dev->capture.timeperframe.denominator;
-+ preview_port->es.video.frame_rate.den =
-+ dev->capture.timeperframe.numerator;
-+ ret = vchiq_mmal_port_set_format(dev->instance, preview_port);
-+ if (overlay_enabled) {
-+ ret = vchiq_mmal_port_connect_tunnel(
-+ dev->instance,
-+ preview_port,
-+ &dev->component[MMAL_COMPONENT_PREVIEW]->input[0]);
-+ if (!ret)
-+ ret = vchiq_mmal_port_enable(dev->instance,
-+ preview_port,
-+ NULL);
-+ }
-+ }
-+
-+ if (ret) {
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "%s failed to set format %dx%d %08X\n", __func__,
-+ f->fmt.pix.width, f->fmt.pix.height,
-+ f->fmt.pix.pixelformat);
-+ /* ensure capture is not going to be tried */
-+ dev->capture.port = NULL;
-+ } else {
-+ if (encode_component) {
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "vid_cap - set up encode comp\n");
-+
-+ /* configure buffering */
-+ camera_port->current_buffer.size =
-+ camera_port->recommended_buffer.size;
-+ camera_port->current_buffer.num =
-+ camera_port->recommended_buffer.num;
-+
-+ ret =
-+ vchiq_mmal_port_connect_tunnel(
-+ dev->instance,
-+ camera_port,
-+ &encode_component->input[0]);
-+ if (ret) {
-+ v4l2_dbg(1, bcm2835_v4l2_debug,
-+ &dev->v4l2_dev,
-+ "%s failed to create connection\n",
-+ __func__);
-+ /* ensure capture is not going to be tried */
-+ dev->capture.port = NULL;
-+ } else {
-+ port->es.video.width = f->fmt.pix.width;
-+ port->es.video.height = f->fmt.pix.height;
-+ port->es.video.crop.x = 0;
-+ port->es.video.crop.y = 0;
-+ port->es.video.crop.width = f->fmt.pix.width;
-+ port->es.video.crop.height = f->fmt.pix.height;
-+ port->es.video.frame_rate.num =
-+ dev->capture.timeperframe.denominator;
-+ port->es.video.frame_rate.den =
-+ dev->capture.timeperframe.numerator;
-+
-+ port->format.encoding = mfmt->mmal;
-+ port->format.encoding_variant = 0;
-+ /* Set any encoding specific parameters */
-+ switch (mfmt->mmal_component) {
-+ case MMAL_COMPONENT_VIDEO_ENCODE:
-+ port->format.bitrate =
-+ dev->capture.encode_bitrate;
-+ break;
-+ case MMAL_COMPONENT_IMAGE_ENCODE:
-+ /* Could set EXIF parameters here */
-+ break;
-+ default:
-+ break;
-+ }
-+ ret = vchiq_mmal_port_set_format(dev->instance,
-+ port);
-+ if (ret)
-+ v4l2_dbg(1, bcm2835_v4l2_debug,
-+ &dev->v4l2_dev,
-+ "%s failed to set format %dx%d fmt %08X\n",
-+ __func__,
-+ f->fmt.pix.width,
-+ f->fmt.pix.height,
-+ f->fmt.pix.pixelformat
-+ );
-+ }
-+
-+ if (!ret) {
-+ ret = vchiq_mmal_component_enable(
-+ dev->instance,
-+ encode_component);
-+ if (ret) {
-+ v4l2_dbg(1, bcm2835_v4l2_debug,
-+ &dev->v4l2_dev,
-+ "%s Failed to enable encode components\n",
-+ __func__);
-+ }
-+ }
-+ if (!ret) {
-+ /* configure buffering */
-+ port->current_buffer.num = 1;
-+ port->current_buffer.size =
-+ f->fmt.pix.sizeimage;
-+ if (port->format.encoding ==
-+ MMAL_ENCODING_JPEG) {
-+ v4l2_dbg(1, bcm2835_v4l2_debug,
-+ &dev->v4l2_dev,
-+ "JPG - buf size now %d was %d\n",
-+ f->fmt.pix.sizeimage,
-+ port->current_buffer.size);
-+ port->current_buffer.size =
-+ (f->fmt.pix.sizeimage <
-+ (100 << 10))
-+ ? (100 << 10) : f->fmt.pix.
-+ sizeimage;
-+ }
-+ v4l2_dbg(1, bcm2835_v4l2_debug,
-+ &dev->v4l2_dev,
-+ "vid_cap - cur_buf.size set to %d\n",
-+ f->fmt.pix.sizeimage);
-+ port->current_buffer.alignment = 0;
-+ }
-+ } else {
-+ /* configure buffering */
-+ camera_port->current_buffer.num = 1;
-+ camera_port->current_buffer.size = f->fmt.pix.sizeimage;
-+ camera_port->current_buffer.alignment = 0;
-+ }
-+
-+ if (!ret) {
-+ dev->capture.fmt = mfmt;
-+ dev->capture.stride = f->fmt.pix.bytesperline;
-+ dev->capture.width = camera_port->es.video.crop.width;
-+ dev->capture.height = camera_port->es.video.crop.height;
-+ dev->capture.buffersize = port->current_buffer.size;
-+
-+ /* select port for capture */
-+ dev->capture.port = port;
-+ dev->capture.camera_port = camera_port;
-+ dev->capture.encode_component = encode_component;
-+ v4l2_dbg(1, bcm2835_v4l2_debug,
-+ &dev->v4l2_dev,
-+ "Set dev->capture.fmt %08X, %dx%d, stride %d, size %d",
-+ port->format.encoding,
-+ dev->capture.width, dev->capture.height,
-+ dev->capture.stride, dev->capture.buffersize);
-+ }
-+ }
-+
-+ /* todo: Need to convert the vchiq/mmal error into a v4l2 error. */
-+ return ret;
-+}
-+
-+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-+ struct v4l2_format *f)
-+{
-+ int ret;
-+ struct bm2835_mmal_dev *dev = video_drvdata(file);
-+ struct mmal_fmt *mfmt;
-+
-+ /* try the format to set valid parameters */
-+ ret = vidioc_try_fmt_vid_cap(file, priv, f);
-+ if (ret) {
-+ v4l2_err(&dev->v4l2_dev,
-+ "vid_cap - vidioc_try_fmt_vid_cap failed\n");
-+ return ret;
-+ }
-+
-+ /* if a capture is running refuse to set format */
-+ if (vb2_is_busy(&dev->capture.vb_vidq)) {
-+ v4l2_info(&dev->v4l2_dev, "%s device busy\n", __func__);
-+ return -EBUSY;
-+ }
-+
-+ /* If the format is unsupported v4l2 says we should switch to
-+ * a supported one and not return an error. */
-+ mfmt = get_format(f);
-+ if (!mfmt) {
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "Fourcc format (0x%08x) unknown.\n",
-+ f->fmt.pix.pixelformat);
-+ f->fmt.pix.pixelformat = formats[0].fourcc;
-+ mfmt = get_format(f);
-+ }
-+
-+ ret = mmal_setup_components(dev, f);
-+ if (ret != 0) {
-+ v4l2_err(&dev->v4l2_dev,
-+ "%s: failed to setup mmal components: %d\n",
-+ __func__, ret);
-+ ret = -EINVAL;
-+ }
-+
-+ return ret;
-+}
-+
-+int vidioc_enum_framesizes(struct file *file, void *fh,
-+ struct v4l2_frmsizeenum *fsize)
-+{
-+ static const struct v4l2_frmsize_stepwise sizes = {
-+ MIN_WIDTH, MAX_WIDTH, 2,
-+ MIN_HEIGHT, MAX_HEIGHT, 2
-+ };
-+ int i;
-+
-+ if (fsize->index)
-+ return -EINVAL;
-+ for (i = 0; i < ARRAY_SIZE(formats); i++)
-+ if (formats[i].fourcc == fsize->pixel_format)
-+ break;
-+ if (i == ARRAY_SIZE(formats))
-+ return -EINVAL;
-+ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
-+ fsize->stepwise = sizes;
-+ return 0;
-+}
-+
-+/* timeperframe is arbitrary and continous */
-+static int vidioc_enum_frameintervals(struct file *file, void *priv,
-+ struct v4l2_frmivalenum *fival)
-+{
-+ int i;
-+
-+ if (fival->index)
-+ return -EINVAL;
-+
-+ for (i = 0; i < ARRAY_SIZE(formats); i++)
-+ if (formats[i].fourcc == fival->pixel_format)
-+ break;
-+ if (i == ARRAY_SIZE(formats))
-+ return -EINVAL;
-+
-+ /* regarding width & height - we support any within range */
-+ if (fival->width < MIN_WIDTH || fival->width > MAX_WIDTH ||
-+ fival->height < MIN_HEIGHT || fival->height > MAX_HEIGHT)
-+ return -EINVAL;
-+
-+ fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS;
-+
-+ /* fill in stepwise (step=1.0 is requred by V4L2 spec) */
-+ fival->stepwise.min = tpf_min;
-+ fival->stepwise.max = tpf_max;
-+ fival->stepwise.step = (struct v4l2_fract) {1, 1};
-+
-+ return 0;
-+}
-+
-+static int vidioc_g_parm(struct file *file, void *priv,
-+ struct v4l2_streamparm *parm)
-+{
-+ struct bm2835_mmal_dev *dev = video_drvdata(file);
-+
-+ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-+ return -EINVAL;
-+
-+ parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
-+ parm->parm.capture.timeperframe = dev->capture.timeperframe;
-+ parm->parm.capture.readbuffers = 1;
-+ return 0;
-+}
-+
-+#define FRACT_CMP(a, OP, b) \
-+ ((u64)(a).numerator * (b).denominator OP \
-+ (u64)(b).numerator * (a).denominator)
-+
-+static int vidioc_s_parm(struct file *file, void *priv,
-+ struct v4l2_streamparm *parm)
-+{
-+ struct bm2835_mmal_dev *dev = video_drvdata(file);
-+ struct v4l2_fract tpf;
-+ struct mmal_parameter_rational fps_param;
-+
-+ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-+ return -EINVAL;
-+
-+ tpf = parm->parm.capture.timeperframe;
-+
-+ /* tpf: {*, 0} resets timing; clip to [min, max]*/
-+ tpf = tpf.denominator ? tpf : tpf_default;
-+ tpf = FRACT_CMP(tpf, <, tpf_min) ? tpf_min : tpf;
-+ tpf = FRACT_CMP(tpf, >, tpf_max) ? tpf_max : tpf;
-+
-+ dev->capture.timeperframe = tpf;
-+ parm->parm.capture.timeperframe = tpf;
-+ parm->parm.capture.readbuffers = 1;
-+
-+ fps_param.num = 0; /* Select variable fps, and then use
-+ * FPS_RANGE to select the actual limits.
-+ */
-+ fps_param.den = 1;
-+ set_framerate_params(dev);
-+
-+ return 0;
-+}
-+
-+static const struct v4l2_ioctl_ops camera0_ioctl_ops = {
-+ /* overlay */
-+ .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_overlay,
-+ .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay,
-+ .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay,
-+ .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay,
-+ .vidioc_overlay = vidioc_overlay,
-+ .vidioc_g_fbuf = vidioc_g_fbuf,
-+
-+ /* inputs */
-+ .vidioc_enum_input = vidioc_enum_input,
-+ .vidioc_g_input = vidioc_g_input,
-+ .vidioc_s_input = vidioc_s_input,
-+
-+ /* capture */
-+ .vidioc_querycap = vidioc_querycap,
-+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
-+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
-+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
-+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-+
-+ /* buffer management */
-+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
-+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
-+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
-+ .vidioc_querybuf = vb2_ioctl_querybuf,
-+ .vidioc_qbuf = vb2_ioctl_qbuf,
-+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
-+ .vidioc_enum_framesizes = vidioc_enum_framesizes,
-+ .vidioc_enum_frameintervals = vidioc_enum_frameintervals,
-+ .vidioc_g_parm = vidioc_g_parm,
-+ .vidioc_s_parm = vidioc_s_parm,
-+ .vidioc_streamon = vb2_ioctl_streamon,
-+ .vidioc_streamoff = vb2_ioctl_streamoff,
-+
-+ .vidioc_log_status = v4l2_ctrl_log_status,
-+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
-+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-+};
-+
-+static const struct v4l2_ioctl_ops camera0_ioctl_ops_gstreamer = {
-+ /* overlay */
-+ .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_overlay,
-+ .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay,
-+ .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay,
-+ .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay,
-+ .vidioc_overlay = vidioc_overlay,
-+ .vidioc_g_fbuf = vidioc_g_fbuf,
-+
-+ /* inputs */
-+ .vidioc_enum_input = vidioc_enum_input,
-+ .vidioc_g_input = vidioc_g_input,
-+ .vidioc_s_input = vidioc_s_input,
-+
-+ /* capture */
-+ .vidioc_querycap = vidioc_querycap,
-+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
-+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
-+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
-+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-+
-+ /* buffer management */
-+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
-+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
-+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
-+ .vidioc_querybuf = vb2_ioctl_querybuf,
-+ .vidioc_qbuf = vb2_ioctl_qbuf,
-+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
-+ /* Remove this function ptr to fix gstreamer bug
-+ .vidioc_enum_framesizes = vidioc_enum_framesizes, */
-+ .vidioc_enum_frameintervals = vidioc_enum_frameintervals,
-+ .vidioc_g_parm = vidioc_g_parm,
-+ .vidioc_s_parm = vidioc_s_parm,
-+ .vidioc_streamon = vb2_ioctl_streamon,
-+ .vidioc_streamoff = vb2_ioctl_streamoff,
-+
-+ .vidioc_log_status = v4l2_ctrl_log_status,
-+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
-+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-+};
-+
-+/* ------------------------------------------------------------------
-+ Driver init/finalise
-+ ------------------------------------------------------------------*/
-+
-+static const struct v4l2_file_operations camera0_fops = {
-+ .owner = THIS_MODULE,
-+ .open = v4l2_fh_open,
-+ .release = vb2_fop_release,
-+ .read = vb2_fop_read,
-+ .poll = vb2_fop_poll,
-+ .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
-+ .mmap = vb2_fop_mmap,
-+};
-+
-+static struct video_device vdev_template = {
-+ .name = "camera0",
-+ .fops = &camera0_fops,
-+ .ioctl_ops = &camera0_ioctl_ops,
-+ .release = video_device_release_empty,
-+};
-+
-+static int set_camera_parameters(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_component *camera)
-+{
-+ int ret;
-+ struct mmal_parameter_camera_config cam_config = {
-+ .max_stills_w = MAX_WIDTH,
-+ .max_stills_h = MAX_HEIGHT,
-+ .stills_yuv422 = 1,
-+ .one_shot_stills = 1,
-+ .max_preview_video_w = (max_video_width > 1920) ?
-+ max_video_width : 1920,
-+ .max_preview_video_h = (max_video_height > 1088) ?
-+ max_video_height : 1088,
-+ .num_preview_video_frames = 3,
-+ .stills_capture_circular_buffer_height = 0,
-+ .fast_preview_resume = 0,
-+ .use_stc_timestamp = MMAL_PARAM_TIMESTAMP_MODE_RAW_STC
-+ };
-+
-+ ret = vchiq_mmal_port_parameter_set(instance, &camera->control,
-+ MMAL_PARAMETER_CAMERA_CONFIG,
-+ &cam_config, sizeof(cam_config));
-+ return ret;
-+}
-+
-+/* MMAL instance and component init */
-+static int __init mmal_init(struct bm2835_mmal_dev *dev)
-+{
-+ int ret;
-+ struct mmal_es_format *format;
-+ u32 bool_true = 1;
-+
-+ ret = vchiq_mmal_init(&dev->instance);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* get the camera component ready */
-+ ret = vchiq_mmal_component_init(dev->instance, "ril.camera",
-+ &dev->component[MMAL_COMPONENT_CAMERA]);
-+ if (ret < 0)
-+ goto unreg_mmal;
-+
-+ if (dev->component[MMAL_COMPONENT_CAMERA]->outputs <
-+ MMAL_CAMERA_PORT_COUNT) {
-+ ret = -EINVAL;
-+ goto unreg_camera;
-+ }
-+
-+ ret = set_camera_parameters(dev->instance,
-+ dev->component[MMAL_COMPONENT_CAMERA]);
-+ if (ret < 0)
-+ goto unreg_camera;
-+
-+ format =
-+ &dev->component[MMAL_COMPONENT_CAMERA]->
-+ output[MMAL_CAMERA_PORT_PREVIEW].format;
-+
-+ format->encoding = MMAL_ENCODING_OPAQUE;
-+ format->encoding_variant = MMAL_ENCODING_I420;
-+
-+ format->es->video.width = 1024;
-+ format->es->video.height = 768;
-+ format->es->video.crop.x = 0;
-+ format->es->video.crop.y = 0;
-+ format->es->video.crop.width = 1024;
-+ format->es->video.crop.height = 768;
-+ format->es->video.frame_rate.num = 0; /* Rely on fps_range */
-+ format->es->video.frame_rate.den = 1;
-+
-+ format =
-+ &dev->component[MMAL_COMPONENT_CAMERA]->
-+ output[MMAL_CAMERA_PORT_VIDEO].format;
-+
-+ format->encoding = MMAL_ENCODING_OPAQUE;
-+ format->encoding_variant = MMAL_ENCODING_I420;
-+
-+ format->es->video.width = 1024;
-+ format->es->video.height = 768;
-+ format->es->video.crop.x = 0;
-+ format->es->video.crop.y = 0;
-+ format->es->video.crop.width = 1024;
-+ format->es->video.crop.height = 768;
-+ format->es->video.frame_rate.num = 0; /* Rely on fps_range */
-+ format->es->video.frame_rate.den = 1;
-+
-+ vchiq_mmal_port_parameter_set(dev->instance,
-+ &dev->component[MMAL_COMPONENT_CAMERA]->
-+ output[MMAL_CAMERA_PORT_VIDEO],
-+ MMAL_PARAMETER_NO_IMAGE_PADDING,
-+ &bool_true, sizeof(bool_true));
-+
-+ format =
-+ &dev->component[MMAL_COMPONENT_CAMERA]->
-+ output[MMAL_CAMERA_PORT_CAPTURE].format;
-+
-+ format->encoding = MMAL_ENCODING_OPAQUE;
-+
-+ format->es->video.width = 2592;
-+ format->es->video.height = 1944;
-+ format->es->video.crop.x = 0;
-+ format->es->video.crop.y = 0;
-+ format->es->video.crop.width = 2592;
-+ format->es->video.crop.height = 1944;
-+ format->es->video.frame_rate.num = 0; /* Rely on fps_range */
-+ format->es->video.frame_rate.den = 1;
-+
-+ dev->capture.width = format->es->video.width;
-+ dev->capture.height = format->es->video.height;
-+ dev->capture.fmt = &formats[0];
-+ dev->capture.encode_component = NULL;
-+ dev->capture.timeperframe = tpf_default;
-+ dev->capture.enc_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH;
-+ dev->capture.enc_level = V4L2_MPEG_VIDEO_H264_LEVEL_4_0;
-+
-+ vchiq_mmal_port_parameter_set(dev->instance,
-+ &dev->component[MMAL_COMPONENT_CAMERA]->
-+ output[MMAL_CAMERA_PORT_CAPTURE],
-+ MMAL_PARAMETER_NO_IMAGE_PADDING,
-+ &bool_true, sizeof(bool_true));
-+
-+ /* get the preview component ready */
-+ ret = vchiq_mmal_component_init(
-+ dev->instance, "ril.video_render",
-+ &dev->component[MMAL_COMPONENT_PREVIEW]);
-+ if (ret < 0)
-+ goto unreg_camera;
-+
-+ if (dev->component[MMAL_COMPONENT_PREVIEW]->inputs < 1) {
-+ ret = -EINVAL;
-+ pr_debug("too few input ports %d needed %d\n",
-+ dev->component[MMAL_COMPONENT_PREVIEW]->inputs, 1);
-+ goto unreg_preview;
-+ }
-+
-+ /* get the image encoder component ready */
-+ ret = vchiq_mmal_component_init(
-+ dev->instance, "ril.image_encode",
-+ &dev->component[MMAL_COMPONENT_IMAGE_ENCODE]);
-+ if (ret < 0)
-+ goto unreg_preview;
-+
-+ if (dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->inputs < 1) {
-+ ret = -EINVAL;
-+ v4l2_err(&dev->v4l2_dev, "too few input ports %d needed %d\n",
-+ dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->inputs,
-+ 1);
-+ goto unreg_image_encoder;
-+ }
-+
-+ /* get the video encoder component ready */
-+ ret = vchiq_mmal_component_init(dev->instance, "ril.video_encode",
-+ &dev->
-+ component[MMAL_COMPONENT_VIDEO_ENCODE]);
-+ if (ret < 0)
-+ goto unreg_image_encoder;
-+
-+ if (dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->inputs < 1) {
-+ ret = -EINVAL;
-+ v4l2_err(&dev->v4l2_dev, "too few input ports %d needed %d\n",
-+ dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->inputs,
-+ 1);
-+ goto unreg_vid_encoder;
-+ }
-+
-+ {
-+ struct vchiq_mmal_port *encoder_port =
-+ &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
-+ encoder_port->format.encoding = MMAL_ENCODING_H264;
-+ ret = vchiq_mmal_port_set_format(dev->instance,
-+ encoder_port);
-+ }
-+
-+ {
-+ unsigned int enable = 1;
-+ vchiq_mmal_port_parameter_set(
-+ dev->instance,
-+ &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->control,
-+ MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT,
-+ &enable, sizeof(enable));
-+
-+ vchiq_mmal_port_parameter_set(dev->instance,
-+ &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->control,
-+ MMAL_PARAMETER_MINIMISE_FRAGMENTATION,
-+ &enable,
-+ sizeof(enable));
-+ }
-+ ret = bm2835_mmal_set_all_camera_controls(dev);
-+ if (ret < 0)
-+ goto unreg_vid_encoder;
-+
-+ return 0;
-+
-+unreg_vid_encoder:
-+ pr_err("Cleanup: Destroy video encoder\n");
-+ vchiq_mmal_component_finalise(
-+ dev->instance,
-+ dev->component[MMAL_COMPONENT_VIDEO_ENCODE]);
-+
-+unreg_image_encoder:
-+ pr_err("Cleanup: Destroy image encoder\n");
-+ vchiq_mmal_component_finalise(
-+ dev->instance,
-+ dev->component[MMAL_COMPONENT_IMAGE_ENCODE]);
-+
-+unreg_preview:
-+ pr_err("Cleanup: Destroy video render\n");
-+ vchiq_mmal_component_finalise(dev->instance,
-+ dev->component[MMAL_COMPONENT_PREVIEW]);
-+
-+unreg_camera:
-+ pr_err("Cleanup: Destroy camera\n");
-+ vchiq_mmal_component_finalise(dev->instance,
-+ dev->component[MMAL_COMPONENT_CAMERA]);
-+
-+unreg_mmal:
-+ vchiq_mmal_finalise(dev->instance);
-+ return ret;
-+}
-+
-+static int __init bm2835_mmal_init_device(struct bm2835_mmal_dev *dev,
-+ struct video_device *vfd)
-+{
-+ int ret;
-+
-+ *vfd = vdev_template;
-+ if (gst_v4l2src_is_broken) {
-+ v4l2_info(&dev->v4l2_dev,
-+ "Work-around for gstreamer issue is active.\n");
-+ vfd->ioctl_ops = &camera0_ioctl_ops_gstreamer;
-+ }
-+
-+ vfd->v4l2_dev = &dev->v4l2_dev;
-+
-+ vfd->lock = &dev->mutex;
-+
-+ vfd->queue = &dev->capture.vb_vidq;
-+
-+ /* video device needs to be able to access instance data */
-+ video_set_drvdata(vfd, dev);
-+
-+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
-+ if (ret < 0)
-+ return ret;
-+
-+ v4l2_info(vfd->v4l2_dev,
-+ "V4L2 device registered as %s - stills mode > %dx%d\n",
-+ video_device_node_name(vfd), max_video_width, max_video_height);
-+
-+ return 0;
-+}
-+
-+static struct v4l2_format default_v4l2_format = {
-+ .fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG,
-+ .fmt.pix.width = 1024,
-+ .fmt.pix.bytesperline = 1024,
-+ .fmt.pix.height = 768,
-+ .fmt.pix.sizeimage = 1024*768,
-+};
-+
-+static int __init bm2835_mmal_init(void)
-+{
-+ int ret;
-+ struct bm2835_mmal_dev *dev;
-+ struct vb2_queue *q;
-+
-+ dev = kzalloc(sizeof(*gdev), GFP_KERNEL);
-+ if (!dev)
-+ return -ENOMEM;
-+
-+ /* setup device defaults */
-+ dev->overlay.w.left = 150;
-+ dev->overlay.w.top = 50;
-+ dev->overlay.w.width = 1024;
-+ dev->overlay.w.height = 768;
-+ dev->overlay.clipcount = 0;
-+ dev->overlay.field = V4L2_FIELD_NONE;
-+
-+ dev->capture.fmt = &formats[3]; /* JPEG */
-+
-+ /* v4l device registration */
-+ snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
-+ "%s", BM2835_MMAL_MODULE_NAME);
-+ ret = v4l2_device_register(NULL, &dev->v4l2_dev);
-+ if (ret)
-+ goto free_dev;
-+
-+ /* setup v4l controls */
-+ ret = bm2835_mmal_init_controls(dev, &dev->ctrl_handler);
-+ if (ret < 0)
-+ goto unreg_dev;
-+ dev->v4l2_dev.ctrl_handler = &dev->ctrl_handler;
-+
-+ /* mmal init */
-+ ret = mmal_init(dev);
-+ if (ret < 0)
-+ goto unreg_dev;
-+
-+ /* initialize queue */
-+ q = &dev->capture.vb_vidq;
-+ memset(q, 0, sizeof(*q));
-+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-+ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
-+ q->drv_priv = dev;
-+ q->buf_struct_size = sizeof(struct mmal_buffer);
-+ q->ops = &bm2835_mmal_video_qops;
-+ q->mem_ops = &vb2_vmalloc_memops;
-+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
-+ ret = vb2_queue_init(q);
-+ if (ret < 0)
-+ goto unreg_dev;
-+
-+ /* v4l2 core mutex used to protect all fops and v4l2 ioctls. */
-+ mutex_init(&dev->mutex);
-+
-+ /* initialise video devices */
-+ ret = bm2835_mmal_init_device(dev, &dev->vdev);
-+ if (ret < 0)
-+ goto unreg_dev;
-+
-+ /* Really want to call vidioc_s_fmt_vid_cap with the default
-+ * format, but currently the APIs don't join up.
-+ */
-+ ret = mmal_setup_components(dev, &default_v4l2_format);
-+ if (ret < 0) {
-+ v4l2_err(&dev->v4l2_dev,
-+ "%s: could not setup components\n", __func__);
-+ goto unreg_dev;
-+ }
-+
-+ v4l2_info(&dev->v4l2_dev,
-+ "Broadcom 2835 MMAL video capture ver %s loaded.\n",
-+ BM2835_MMAL_VERSION);
-+
-+ gdev = dev;
-+ return 0;
-+
-+unreg_dev:
-+ v4l2_ctrl_handler_free(&dev->ctrl_handler);
-+ v4l2_device_unregister(&dev->v4l2_dev);
-+
-+free_dev:
-+ kfree(dev);
-+
-+ v4l2_err(&dev->v4l2_dev,
-+ "%s: error %d while loading driver\n",
-+ BM2835_MMAL_MODULE_NAME, ret);
-+
-+ return ret;
-+}
-+
-+static void __exit bm2835_mmal_exit(void)
-+{
-+ if (!gdev)
-+ return;
-+
-+ v4l2_info(&gdev->v4l2_dev, "unregistering %s\n",
-+ video_device_node_name(&gdev->vdev));
-+
-+ video_unregister_device(&gdev->vdev);
-+
-+ if (gdev->capture.encode_component) {
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &gdev->v4l2_dev,
-+ "mmal_exit - disconnect tunnel\n");
-+ vchiq_mmal_port_connect_tunnel(gdev->instance,
-+ gdev->capture.camera_port, NULL);
-+ vchiq_mmal_component_disable(gdev->instance,
-+ gdev->capture.encode_component);
-+ }
-+ vchiq_mmal_component_disable(gdev->instance,
-+ gdev->component[MMAL_COMPONENT_CAMERA]);
-+
-+ vchiq_mmal_component_finalise(gdev->instance,
-+ gdev->
-+ component[MMAL_COMPONENT_VIDEO_ENCODE]);
-+
-+ vchiq_mmal_component_finalise(gdev->instance,
-+ gdev->
-+ component[MMAL_COMPONENT_IMAGE_ENCODE]);
-+
-+ vchiq_mmal_component_finalise(gdev->instance,
-+ gdev->component[MMAL_COMPONENT_PREVIEW]);
-+
-+ vchiq_mmal_component_finalise(gdev->instance,
-+ gdev->component[MMAL_COMPONENT_CAMERA]);
-+
-+ vchiq_mmal_finalise(gdev->instance);
-+
-+ v4l2_ctrl_handler_free(&gdev->ctrl_handler);
-+
-+ v4l2_device_unregister(&gdev->v4l2_dev);
-+
-+ kfree(gdev);
-+}
-+
-+module_init(bm2835_mmal_init);
-+module_exit(bm2835_mmal_exit);
---- /dev/null
-+++ b/drivers/media/platform/bcm2835/bcm2835-camera.h
-@@ -0,0 +1,126 @@
-+/*
-+ * Broadcom BM2835 V4L2 driver
-+ *
-+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
-+ *
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file COPYING in the main directory of this archive
-+ * for more details.
-+ *
-+ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
-+ * Dave Stevenson <dsteve@broadcom.com>
-+ * Simon Mellor <simellor@broadcom.com>
-+ * Luke Diamand <luked@broadcom.com>
-+ *
-+ * core driver device
-+ */
-+
-+#define V4L2_CTRL_COUNT 28 /* number of v4l controls */
-+
-+enum {
-+ MMAL_COMPONENT_CAMERA = 0,
-+ MMAL_COMPONENT_PREVIEW,
-+ MMAL_COMPONENT_IMAGE_ENCODE,
-+ MMAL_COMPONENT_VIDEO_ENCODE,
-+ MMAL_COMPONENT_COUNT
-+};
-+
-+enum {
-+ MMAL_CAMERA_PORT_PREVIEW = 0,
-+ MMAL_CAMERA_PORT_VIDEO,
-+ MMAL_CAMERA_PORT_CAPTURE,
-+ MMAL_CAMERA_PORT_COUNT
-+};
-+
-+#define PREVIEW_LAYER 2
-+
-+extern int bcm2835_v4l2_debug;
-+
-+struct bm2835_mmal_dev {
-+ /* v4l2 devices */
-+ struct v4l2_device v4l2_dev;
-+ struct video_device vdev;
-+ struct mutex mutex;
-+
-+ /* controls */
-+ struct v4l2_ctrl_handler ctrl_handler;
-+ struct v4l2_ctrl *ctrls[V4L2_CTRL_COUNT];
-+ enum v4l2_scene_mode scene_mode;
-+ struct mmal_colourfx colourfx;
-+ int hflip;
-+ int vflip;
-+ int red_gain;
-+ int blue_gain;
-+ enum mmal_parameter_exposuremode exposure_mode_user;
-+ enum v4l2_exposure_auto_type exposure_mode_v4l2_user;
-+ /* active exposure mode may differ if selected via a scene mode */
-+ enum mmal_parameter_exposuremode exposure_mode_active;
-+ enum mmal_parameter_exposuremeteringmode metering_mode;
-+ unsigned int manual_shutter_speed;
-+ bool exp_auto_priority;
-+
-+ /* allocated mmal instance and components */
-+ struct vchiq_mmal_instance *instance;
-+ struct vchiq_mmal_component *component[MMAL_COMPONENT_COUNT];
-+ int camera_use_count;
-+
-+ struct v4l2_window overlay;
-+
-+ struct {
-+ unsigned int width; /* width */
-+ unsigned int height; /* height */
-+ unsigned int stride; /* stride */
-+ unsigned int buffersize; /* buffer size with padding */
-+ struct mmal_fmt *fmt;
-+ struct v4l2_fract timeperframe;
-+
-+ /* H264 encode bitrate */
-+ int encode_bitrate;
-+ /* H264 bitrate mode. CBR/VBR */
-+ int encode_bitrate_mode;
-+ /* H264 profile */
-+ enum v4l2_mpeg_video_h264_profile enc_profile;
-+ /* H264 level */
-+ enum v4l2_mpeg_video_h264_level enc_level;
-+ /* JPEG Q-factor */
-+ int q_factor;
-+
-+ struct vb2_queue vb_vidq;
-+
-+ /* VC start timestamp for streaming */
-+ s64 vc_start_timestamp;
-+ /* Kernel start timestamp for streaming */
-+ struct timeval kernel_start_ts;
-+
-+ struct vchiq_mmal_port *port; /* port being used for capture */
-+ /* camera port being used for capture */
-+ struct vchiq_mmal_port *camera_port;
-+ /* component being used for encode */
-+ struct vchiq_mmal_component *encode_component;
-+ /* number of frames remaining which driver should capture */
-+ unsigned int frame_count;
-+ /* last frame completion */
-+ struct completion frame_cmplt;
-+
-+ } capture;
-+
-+};
-+
-+int bm2835_mmal_init_controls(
-+ struct bm2835_mmal_dev *dev,
-+ struct v4l2_ctrl_handler *hdl);
-+
-+int bm2835_mmal_set_all_camera_controls(struct bm2835_mmal_dev *dev);
-+int set_framerate_params(struct bm2835_mmal_dev *dev);
-+
-+/* Debug helpers */
-+
-+#define v4l2_dump_pix_format(level, debug, dev, pix_fmt, desc) \
-+{ \
-+ v4l2_dbg(level, debug, dev, \
-+"%s: w %u h %u field %u pfmt 0x%x bpl %u sz_img %u colorspace 0x%x priv %u\n", \
-+ desc == NULL ? "" : desc, \
-+ (pix_fmt)->width, (pix_fmt)->height, (pix_fmt)->field, \
-+ (pix_fmt)->pixelformat, (pix_fmt)->bytesperline, \
-+ (pix_fmt)->sizeimage, (pix_fmt)->colorspace, (pix_fmt)->priv); \
-+}
---- /dev/null
-+++ b/drivers/media/platform/bcm2835/controls.c
-@@ -0,0 +1,1324 @@
-+/*
-+ * Broadcom BM2835 V4L2 driver
-+ *
-+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
-+ *
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file COPYING in the main directory of this archive
-+ * for more details.
-+ *
-+ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
-+ * Dave Stevenson <dsteve@broadcom.com>
-+ * Simon Mellor <simellor@broadcom.com>
-+ * Luke Diamand <luked@broadcom.com>
-+ */
-+
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <media/videobuf2-vmalloc.h>
-+#include <media/v4l2-device.h>
-+#include <media/v4l2-ioctl.h>
-+#include <media/v4l2-ctrls.h>
-+#include <media/v4l2-fh.h>
-+#include <media/v4l2-event.h>
-+#include <media/v4l2-common.h>
-+
-+#include "mmal-common.h"
-+#include "mmal-vchiq.h"
-+#include "mmal-parameters.h"
-+#include "bcm2835-camera.h"
-+
-+/* The supported V4L2_CID_AUTO_EXPOSURE_BIAS values are from -4.0 to +4.0.
-+ * MMAL values are in 1/6th increments so the MMAL range is -24 to +24.
-+ * V4L2 docs say value "is expressed in terms of EV, drivers should interpret
-+ * the values as 0.001 EV units, where the value 1000 stands for +1 EV."
-+ * V4L2 is limited to a max of 32 values in a menu, so count in 1/3rds from
-+ * -4 to +4
-+ */
-+static const s64 ev_bias_qmenu[] = {
-+ -4000, -3667, -3333,
-+ -3000, -2667, -2333,
-+ -2000, -1667, -1333,
-+ -1000, -667, -333,
-+ 0, 333, 667,
-+ 1000, 1333, 1667,
-+ 2000, 2333, 2667,
-+ 3000, 3333, 3667,
-+ 4000
-+};
-+
-+/* Supported ISO values
-+ * ISOO = auto ISO
-+ */
-+static const s64 iso_qmenu[] = {
-+ 0, 100, 200, 400, 800,
-+};
-+
-+static const s64 mains_freq_qmenu[] = {
-+ V4L2_CID_POWER_LINE_FREQUENCY_DISABLED,
-+ V4L2_CID_POWER_LINE_FREQUENCY_50HZ,
-+ V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
-+ V4L2_CID_POWER_LINE_FREQUENCY_AUTO
-+};
-+
-+/* Supported video encode modes */
-+static const s64 bitrate_mode_qmenu[] = {
-+ (s64)V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
-+ (s64)V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
-+};
-+
-+enum bm2835_mmal_ctrl_type {
-+ MMAL_CONTROL_TYPE_STD,
-+ MMAL_CONTROL_TYPE_STD_MENU,
-+ MMAL_CONTROL_TYPE_INT_MENU,
-+ MMAL_CONTROL_TYPE_CLUSTER, /* special cluster entry */
-+};
-+
-+struct bm2835_mmal_v4l2_ctrl;
-+
-+typedef int(bm2835_mmal_v4l2_ctrl_cb)(
-+ struct bm2835_mmal_dev *dev,
-+ struct v4l2_ctrl *ctrl,
-+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl);
-+
-+struct bm2835_mmal_v4l2_ctrl {
-+ u32 id; /* v4l2 control identifier */
-+ enum bm2835_mmal_ctrl_type type;
-+ /* control minimum value or
-+ * mask for MMAL_CONTROL_TYPE_STD_MENU */
-+ s32 min;
-+ s32 max; /* maximum value of control */
-+ s32 def; /* default value of control */
-+ s32 step; /* step size of the control */
-+ const s64 *imenu; /* integer menu array */
-+ u32 mmal_id; /* mmal parameter id */
-+ bm2835_mmal_v4l2_ctrl_cb *setter;
-+ bool ignore_errors;
-+};
-+
-+struct v4l2_to_mmal_effects_setting {
-+ u32 v4l2_effect;
-+ u32 mmal_effect;
-+ s32 col_fx_enable;
-+ s32 col_fx_fixed_cbcr;
-+ u32 u;
-+ u32 v;
-+ u32 num_effect_params;
-+ u32 effect_params[MMAL_MAX_IMAGEFX_PARAMETERS];
-+};
-+
-+static const struct v4l2_to_mmal_effects_setting
-+ v4l2_to_mmal_effects_values[] = {
-+ { V4L2_COLORFX_NONE, MMAL_PARAM_IMAGEFX_NONE,
-+ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
-+ { V4L2_COLORFX_BW, MMAL_PARAM_IMAGEFX_NONE,
-+ 1, 0, 128, 128, 0, {0, 0, 0, 0, 0} },
-+ { V4L2_COLORFX_SEPIA, MMAL_PARAM_IMAGEFX_NONE,
-+ 1, 0, 87, 151, 0, {0, 0, 0, 0, 0} },
-+ { V4L2_COLORFX_NEGATIVE, MMAL_PARAM_IMAGEFX_NEGATIVE,
-+ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
-+ { V4L2_COLORFX_EMBOSS, MMAL_PARAM_IMAGEFX_EMBOSS,
-+ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
-+ { V4L2_COLORFX_SKETCH, MMAL_PARAM_IMAGEFX_SKETCH,
-+ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
-+ { V4L2_COLORFX_SKY_BLUE, MMAL_PARAM_IMAGEFX_PASTEL,
-+ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
-+ { V4L2_COLORFX_GRASS_GREEN, MMAL_PARAM_IMAGEFX_WATERCOLOUR,
-+ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
-+ { V4L2_COLORFX_SKIN_WHITEN, MMAL_PARAM_IMAGEFX_WASHEDOUT,
-+ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
-+ { V4L2_COLORFX_VIVID, MMAL_PARAM_IMAGEFX_SATURATION,
-+ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
-+ { V4L2_COLORFX_AQUA, MMAL_PARAM_IMAGEFX_NONE,
-+ 1, 0, 171, 121, 0, {0, 0, 0, 0, 0} },
-+ { V4L2_COLORFX_ART_FREEZE, MMAL_PARAM_IMAGEFX_HATCH,
-+ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
-+ { V4L2_COLORFX_SILHOUETTE, MMAL_PARAM_IMAGEFX_FILM,
-+ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
-+ { V4L2_COLORFX_SOLARIZATION, MMAL_PARAM_IMAGEFX_SOLARIZE,
-+ 0, 0, 0, 0, 5, {1, 128, 160, 160, 48} },
-+ { V4L2_COLORFX_ANTIQUE, MMAL_PARAM_IMAGEFX_COLOURBALANCE,
-+ 0, 0, 0, 0, 3, {108, 274, 238, 0, 0} },
-+ { V4L2_COLORFX_SET_CBCR, MMAL_PARAM_IMAGEFX_NONE,
-+ 1, 1, 0, 0, 0, {0, 0, 0, 0, 0} }
-+};
-+
-+struct v4l2_mmal_scene_config {
-+ enum v4l2_scene_mode v4l2_scene;
-+ enum mmal_parameter_exposuremode exposure_mode;
-+ enum mmal_parameter_exposuremeteringmode metering_mode;
-+};
-+
-+static const struct v4l2_mmal_scene_config scene_configs[] = {
-+ /* V4L2_SCENE_MODE_NONE automatically added */
-+ {
-+ V4L2_SCENE_MODE_NIGHT,
-+ MMAL_PARAM_EXPOSUREMODE_NIGHT,
-+ MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE
-+ },
-+ {
-+ V4L2_SCENE_MODE_SPORTS,
-+ MMAL_PARAM_EXPOSUREMODE_SPORTS,
-+ MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE
-+ },
-+};
-+
-+/* control handlers*/
-+
-+static int ctrl_set_rational(struct bm2835_mmal_dev *dev,
-+ struct v4l2_ctrl *ctrl,
-+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
-+{
-+ struct mmal_parameter_rational rational_value;
-+ struct vchiq_mmal_port *control;
-+
-+ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
-+
-+ rational_value.num = ctrl->val;
-+ rational_value.den = 100;
-+
-+ return vchiq_mmal_port_parameter_set(dev->instance, control,
-+ mmal_ctrl->mmal_id,
-+ &rational_value,
-+ sizeof(rational_value));
-+}
-+
-+static int ctrl_set_value(struct bm2835_mmal_dev *dev,
-+ struct v4l2_ctrl *ctrl,
-+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
-+{
-+ u32 u32_value;
-+ struct vchiq_mmal_port *control;
-+
-+ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
-+
-+ u32_value = ctrl->val;
-+
-+ return vchiq_mmal_port_parameter_set(dev->instance, control,
-+ mmal_ctrl->mmal_id,
-+ &u32_value, sizeof(u32_value));
-+}
-+
-+static int ctrl_set_value_menu(struct bm2835_mmal_dev *dev,
-+ struct v4l2_ctrl *ctrl,
-+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
-+{
-+ u32 u32_value;
-+ struct vchiq_mmal_port *control;
-+
-+ if (ctrl->val > mmal_ctrl->max || ctrl->val < mmal_ctrl->min)
-+ return 1;
-+
-+ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
-+
-+ u32_value = mmal_ctrl->imenu[ctrl->val];
-+
-+ return vchiq_mmal_port_parameter_set(dev->instance, control,
-+ mmal_ctrl->mmal_id,
-+ &u32_value, sizeof(u32_value));
-+}
-+
-+static int ctrl_set_value_ev(struct bm2835_mmal_dev *dev,
-+ struct v4l2_ctrl *ctrl,
-+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
-+{
-+ s32 s32_value;
-+ struct vchiq_mmal_port *control;
-+
-+ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
-+
-+ s32_value = (ctrl->val-12)*2; /* Convert from index to 1/6ths */
-+
-+ return vchiq_mmal_port_parameter_set(dev->instance, control,
-+ mmal_ctrl->mmal_id,
-+ &s32_value, sizeof(s32_value));
-+}
-+
-+static int ctrl_set_rotate(struct bm2835_mmal_dev *dev,
-+ struct v4l2_ctrl *ctrl,
-+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
-+{
-+ int ret;
-+ u32 u32_value;
-+ struct vchiq_mmal_component *camera;
-+
-+ camera = dev->component[MMAL_COMPONENT_CAMERA];
-+
-+ u32_value = ((ctrl->val % 360) / 90) * 90;
-+
-+ ret = vchiq_mmal_port_parameter_set(dev->instance, &camera->output[0],
-+ mmal_ctrl->mmal_id,
-+ &u32_value, sizeof(u32_value));
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = vchiq_mmal_port_parameter_set(dev->instance, &camera->output[1],
-+ mmal_ctrl->mmal_id,
-+ &u32_value, sizeof(u32_value));
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = vchiq_mmal_port_parameter_set(dev->instance, &camera->output[2],
-+ mmal_ctrl->mmal_id,
-+ &u32_value, sizeof(u32_value));
-+
-+ return ret;
-+}
-+
-+static int ctrl_set_flip(struct bm2835_mmal_dev *dev,
-+ struct v4l2_ctrl *ctrl,
-+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
-+{
-+ int ret;
-+ u32 u32_value;
-+ struct vchiq_mmal_component *camera;
-+
-+ if (ctrl->id == V4L2_CID_HFLIP)
-+ dev->hflip = ctrl->val;
-+ else
-+ dev->vflip = ctrl->val;
-+
-+ camera = dev->component[MMAL_COMPONENT_CAMERA];
-+
-+ if (dev->hflip && dev->vflip)
-+ u32_value = MMAL_PARAM_MIRROR_BOTH;
-+ else if (dev->hflip)
-+ u32_value = MMAL_PARAM_MIRROR_HORIZONTAL;
-+ else if (dev->vflip)
-+ u32_value = MMAL_PARAM_MIRROR_VERTICAL;
-+ else
-+ u32_value = MMAL_PARAM_MIRROR_NONE;
-+
-+ ret = vchiq_mmal_port_parameter_set(dev->instance, &camera->output[0],
-+ mmal_ctrl->mmal_id,
-+ &u32_value, sizeof(u32_value));
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = vchiq_mmal_port_parameter_set(dev->instance, &camera->output[1],
-+ mmal_ctrl->mmal_id,
-+ &u32_value, sizeof(u32_value));
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = vchiq_mmal_port_parameter_set(dev->instance, &camera->output[2],
-+ mmal_ctrl->mmal_id,
-+ &u32_value, sizeof(u32_value));
-+
-+ return ret;
-+
-+}
-+
-+static int ctrl_set_exposure(struct bm2835_mmal_dev *dev,
-+ struct v4l2_ctrl *ctrl,
-+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
-+{
-+ enum mmal_parameter_exposuremode exp_mode = dev->exposure_mode_user;
-+ u32 shutter_speed = 0;
-+ struct vchiq_mmal_port *control;
-+ int ret = 0;
-+
-+ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
-+
-+ if (mmal_ctrl->mmal_id == MMAL_PARAMETER_SHUTTER_SPEED) {
-+ /* V4L2 is in 100usec increments.
-+ * MMAL is 1usec.
-+ */
-+ dev->manual_shutter_speed = ctrl->val * 100;
-+ } else if (mmal_ctrl->mmal_id == MMAL_PARAMETER_EXPOSURE_MODE) {
-+ switch (ctrl->val) {
-+ case V4L2_EXPOSURE_AUTO:
-+ exp_mode = MMAL_PARAM_EXPOSUREMODE_AUTO;
-+ break;
-+
-+ case V4L2_EXPOSURE_MANUAL:
-+ exp_mode = MMAL_PARAM_EXPOSUREMODE_OFF;
-+ break;
-+ }
-+ dev->exposure_mode_user = exp_mode;
-+ dev->exposure_mode_v4l2_user = ctrl->val;
-+ } else if (mmal_ctrl->id == V4L2_CID_EXPOSURE_AUTO_PRIORITY) {
-+ dev->exp_auto_priority = ctrl->val;
-+ }
-+
-+ if (dev->scene_mode == V4L2_SCENE_MODE_NONE) {
-+ if (exp_mode == MMAL_PARAM_EXPOSUREMODE_OFF)
-+ shutter_speed = dev->manual_shutter_speed;
-+
-+ ret = vchiq_mmal_port_parameter_set(dev->instance,
-+ control,
-+ MMAL_PARAMETER_SHUTTER_SPEED,
-+ &shutter_speed,
-+ sizeof(shutter_speed));
-+ ret += vchiq_mmal_port_parameter_set(dev->instance,
-+ control,
-+ MMAL_PARAMETER_EXPOSURE_MODE,
-+ &exp_mode,
-+ sizeof(u32));
-+ dev->exposure_mode_active = exp_mode;
-+ }
-+ /* exposure_dynamic_framerate (V4L2_CID_EXPOSURE_AUTO_PRIORITY) should
-+ * always apply irrespective of scene mode.
-+ */
-+ ret += set_framerate_params(dev);
-+
-+ return ret;
-+}
-+
-+static int ctrl_set_metering_mode(struct bm2835_mmal_dev *dev,
-+ struct v4l2_ctrl *ctrl,
-+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
-+{
-+ switch (ctrl->val) {
-+ case V4L2_EXPOSURE_METERING_AVERAGE:
-+ dev->metering_mode = MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE;
-+ break;
-+
-+ case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED:
-+ dev->metering_mode = MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT;
-+ break;
-+
-+ case V4L2_EXPOSURE_METERING_SPOT:
-+ dev->metering_mode = MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT;
-+ break;
-+
-+ /* todo matrix weighting not added to Linux API till 3.9
-+ case V4L2_EXPOSURE_METERING_MATRIX:
-+ dev->metering_mode = MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX;
-+ break;
-+ */
-+
-+ }
-+
-+ if (dev->scene_mode == V4L2_SCENE_MODE_NONE) {
-+ struct vchiq_mmal_port *control;
-+ u32 u32_value = dev->metering_mode;
-+
-+ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
-+
-+ return vchiq_mmal_port_parameter_set(dev->instance, control,
-+ mmal_ctrl->mmal_id,
-+ &u32_value, sizeof(u32_value));
-+ } else
-+ return 0;
-+}
-+
-+static int ctrl_set_flicker_avoidance(struct bm2835_mmal_dev *dev,
-+ struct v4l2_ctrl *ctrl,
-+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
-+{
-+ u32 u32_value;
-+ struct vchiq_mmal_port *control;
-+
-+ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
-+
-+ switch (ctrl->val) {
-+ case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED:
-+ u32_value = MMAL_PARAM_FLICKERAVOID_OFF;
-+ break;
-+ case V4L2_CID_POWER_LINE_FREQUENCY_50HZ:
-+ u32_value = MMAL_PARAM_FLICKERAVOID_50HZ;
-+ break;
-+ case V4L2_CID_POWER_LINE_FREQUENCY_60HZ:
-+ u32_value = MMAL_PARAM_FLICKERAVOID_60HZ;
-+ break;
-+ case V4L2_CID_POWER_LINE_FREQUENCY_AUTO:
-+ u32_value = MMAL_PARAM_FLICKERAVOID_AUTO;
-+ break;
-+ }
-+
-+ return vchiq_mmal_port_parameter_set(dev->instance, control,
-+ mmal_ctrl->mmal_id,
-+ &u32_value, sizeof(u32_value));
-+}
-+
-+static int ctrl_set_awb_mode(struct bm2835_mmal_dev *dev,
-+ struct v4l2_ctrl *ctrl,
-+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
-+{
-+ u32 u32_value;
-+ struct vchiq_mmal_port *control;
-+
-+ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
-+
-+ switch (ctrl->val) {
-+ case V4L2_WHITE_BALANCE_MANUAL:
-+ u32_value = MMAL_PARAM_AWBMODE_OFF;
-+ break;
-+
-+ case V4L2_WHITE_BALANCE_AUTO:
-+ u32_value = MMAL_PARAM_AWBMODE_AUTO;
-+ break;
-+
-+ case V4L2_WHITE_BALANCE_INCANDESCENT:
-+ u32_value = MMAL_PARAM_AWBMODE_INCANDESCENT;
-+ break;
-+
-+ case V4L2_WHITE_BALANCE_FLUORESCENT:
-+ u32_value = MMAL_PARAM_AWBMODE_FLUORESCENT;
-+ break;
-+
-+ case V4L2_WHITE_BALANCE_FLUORESCENT_H:
-+ u32_value = MMAL_PARAM_AWBMODE_TUNGSTEN;
-+ break;
-+
-+ case V4L2_WHITE_BALANCE_HORIZON:
-+ u32_value = MMAL_PARAM_AWBMODE_HORIZON;
-+ break;
-+
-+ case V4L2_WHITE_BALANCE_DAYLIGHT:
-+ u32_value = MMAL_PARAM_AWBMODE_SUNLIGHT;
-+ break;
-+
-+ case V4L2_WHITE_BALANCE_FLASH:
-+ u32_value = MMAL_PARAM_AWBMODE_FLASH;
-+ break;
-+
-+ case V4L2_WHITE_BALANCE_CLOUDY:
-+ u32_value = MMAL_PARAM_AWBMODE_CLOUDY;
-+ break;
-+
-+ case V4L2_WHITE_BALANCE_SHADE:
-+ u32_value = MMAL_PARAM_AWBMODE_SHADE;
-+ break;
-+
-+ }
-+
-+ return vchiq_mmal_port_parameter_set(dev->instance, control,
-+ mmal_ctrl->mmal_id,
-+ &u32_value, sizeof(u32_value));
-+}
-+
-+static int ctrl_set_awb_gains(struct bm2835_mmal_dev *dev,
-+ struct v4l2_ctrl *ctrl,
-+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
-+{
-+ struct vchiq_mmal_port *control;
-+ struct mmal_parameter_awbgains gains;
-+
-+ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
-+
-+ if (ctrl->id == V4L2_CID_RED_BALANCE)
-+ dev->red_gain = ctrl->val;
-+ else if (ctrl->id == V4L2_CID_BLUE_BALANCE)
-+ dev->blue_gain = ctrl->val;
-+
-+ gains.r_gain.num = dev->red_gain;
-+ gains.b_gain.num = dev->blue_gain;
-+ gains.r_gain.den = gains.b_gain.den = 1000;
-+
-+ return vchiq_mmal_port_parameter_set(dev->instance, control,
-+ mmal_ctrl->mmal_id,
-+ &gains, sizeof(gains));
-+}
-+
-+static int ctrl_set_image_effect(struct bm2835_mmal_dev *dev,
-+ struct v4l2_ctrl *ctrl,
-+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
-+{
-+ int ret = -EINVAL;
-+ int i, j;
-+ struct vchiq_mmal_port *control;
-+ struct mmal_parameter_imagefx_parameters imagefx;
-+
-+ for (i = 0; i < ARRAY_SIZE(v4l2_to_mmal_effects_values); i++) {
-+ if (ctrl->val == v4l2_to_mmal_effects_values[i].v4l2_effect) {
-+
-+ imagefx.effect =
-+ v4l2_to_mmal_effects_values[i].mmal_effect;
-+ imagefx.num_effect_params =
-+ v4l2_to_mmal_effects_values[i].num_effect_params;
-+
-+ if (imagefx.num_effect_params > MMAL_MAX_IMAGEFX_PARAMETERS)
-+ imagefx.num_effect_params = MMAL_MAX_IMAGEFX_PARAMETERS;
-+
-+ for (j = 0; j < imagefx.num_effect_params; j++)
-+ imagefx.effect_parameter[j] =
-+ v4l2_to_mmal_effects_values[i].effect_params[j];
-+
-+ dev->colourfx.enable =
-+ v4l2_to_mmal_effects_values[i].col_fx_enable;
-+ if (!v4l2_to_mmal_effects_values[i].col_fx_fixed_cbcr) {
-+ dev->colourfx.u =
-+ v4l2_to_mmal_effects_values[i].u;
-+ dev->colourfx.v =
-+ v4l2_to_mmal_effects_values[i].v;
-+ }
-+
-+ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
-+
-+ ret = vchiq_mmal_port_parameter_set(
-+ dev->instance, control,
-+ MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS,
-+ &imagefx, sizeof(imagefx));
-+ if (ret)
-+ goto exit;
-+
-+ ret = vchiq_mmal_port_parameter_set(
-+ dev->instance, control,
-+ MMAL_PARAMETER_COLOUR_EFFECT,
-+ &dev->colourfx, sizeof(dev->colourfx));
-+ }
-+ }
-+
-+exit:
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "mmal_ctrl:%p ctrl id:0x%x ctrl val:%d imagefx:0x%x color_effect:%s u:%d v:%d ret %d(%d)\n",
-+ mmal_ctrl, ctrl->id, ctrl->val, imagefx.effect,
-+ dev->colourfx.enable ? "true" : "false",
-+ dev->colourfx.u, dev->colourfx.v,
-+ ret, (ret == 0 ? 0 : -EINVAL));
-+ return (ret == 0 ? 0 : EINVAL);
-+}
-+
-+static int ctrl_set_colfx(struct bm2835_mmal_dev *dev,
-+ struct v4l2_ctrl *ctrl,
-+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
-+{
-+ int ret = -EINVAL;
-+ struct vchiq_mmal_port *control;
-+
-+ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
-+
-+ dev->colourfx.enable = (ctrl->val & 0xff00) >> 8;
-+ dev->colourfx.enable = ctrl->val & 0xff;
-+
-+ ret = vchiq_mmal_port_parameter_set(dev->instance, control,
-+ MMAL_PARAMETER_COLOUR_EFFECT,
-+ &dev->colourfx, sizeof(dev->colourfx));
-+
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "%s: After: mmal_ctrl:%p ctrl id:0x%x ctrl val:%d ret %d(%d)\n",
-+ __func__, mmal_ctrl, ctrl->id, ctrl->val, ret,
-+ (ret == 0 ? 0 : -EINVAL));
-+ return (ret == 0 ? 0 : EINVAL);
-+}
-+
-+static int ctrl_set_bitrate(struct bm2835_mmal_dev *dev,
-+ struct v4l2_ctrl *ctrl,
-+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
-+{
-+ int ret;
-+ struct vchiq_mmal_port *encoder_out;
-+
-+ dev->capture.encode_bitrate = ctrl->val;
-+
-+ encoder_out = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
-+
-+ ret = vchiq_mmal_port_parameter_set(dev->instance, encoder_out,
-+ mmal_ctrl->mmal_id,
-+ &ctrl->val, sizeof(ctrl->val));
-+ ret = 0;
-+ return ret;
-+}
-+
-+static int ctrl_set_bitrate_mode(struct bm2835_mmal_dev *dev,
-+ struct v4l2_ctrl *ctrl,
-+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
-+{
-+ u32 bitrate_mode;
-+ struct vchiq_mmal_port *encoder_out;
-+
-+ encoder_out = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
-+
-+ dev->capture.encode_bitrate_mode = ctrl->val;
-+ switch (ctrl->val) {
-+ default:
-+ case V4L2_MPEG_VIDEO_BITRATE_MODE_VBR:
-+ bitrate_mode = MMAL_VIDEO_RATECONTROL_VARIABLE;
-+ break;
-+ case V4L2_MPEG_VIDEO_BITRATE_MODE_CBR:
-+ bitrate_mode = MMAL_VIDEO_RATECONTROL_CONSTANT;
-+ break;
-+ }
-+
-+ vchiq_mmal_port_parameter_set(dev->instance, encoder_out,
-+ mmal_ctrl->mmal_id,
-+ &bitrate_mode,
-+ sizeof(bitrate_mode));
-+ return 0;
-+}
-+
-+static int ctrl_set_image_encode_output(struct bm2835_mmal_dev *dev,
-+ struct v4l2_ctrl *ctrl,
-+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
-+{
-+ u32 u32_value;
-+ struct vchiq_mmal_port *jpeg_out;
-+
-+ jpeg_out = &dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->output[0];
-+
-+ u32_value = ctrl->val;
-+
-+ return vchiq_mmal_port_parameter_set(dev->instance, jpeg_out,
-+ mmal_ctrl->mmal_id,
-+ &u32_value, sizeof(u32_value));
-+}
-+
-+static int ctrl_set_video_encode_param_output(struct bm2835_mmal_dev *dev,
-+ struct v4l2_ctrl *ctrl,
-+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
-+{
-+ u32 u32_value;
-+ struct vchiq_mmal_port *vid_enc_ctl;
-+
-+ vid_enc_ctl = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
-+
-+ u32_value = ctrl->val;
-+
-+ return vchiq_mmal_port_parameter_set(dev->instance, vid_enc_ctl,
-+ mmal_ctrl->mmal_id,
-+ &u32_value, sizeof(u32_value));
-+}
-+
-+static int ctrl_set_video_encode_profile_level(struct bm2835_mmal_dev *dev,
-+ struct v4l2_ctrl *ctrl,
-+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
-+{
-+ struct mmal_parameter_video_profile param;
-+ int ret = 0;
-+
-+ if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_PROFILE) {
-+ switch (ctrl->val) {
-+ case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
-+ case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
-+ case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
-+ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
-+ dev->capture.enc_profile = ctrl->val;
-+ break;
-+ default:
-+ ret = -EINVAL;
-+ break;
-+ }
-+ } else if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_LEVEL) {
-+ switch (ctrl->val) {
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
-+ dev->capture.enc_level = ctrl->val;
-+ break;
-+ default:
-+ ret = -EINVAL;
-+ break;
-+ }
-+ }
-+
-+ if (!ret) {
-+ switch (dev->capture.enc_profile) {
-+ case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
-+ param.profile = MMAL_VIDEO_PROFILE_H264_BASELINE;
-+ break;
-+ case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
-+ param.profile =
-+ MMAL_VIDEO_PROFILE_H264_CONSTRAINED_BASELINE;
-+ break;
-+ case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
-+ param.profile = MMAL_VIDEO_PROFILE_H264_MAIN;
-+ break;
-+ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
-+ param.profile = MMAL_VIDEO_PROFILE_H264_HIGH;
-+ break;
-+ default:
-+ /* Should never get here */
-+ break;
-+ }
-+
-+ switch (dev->capture.enc_level) {
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
-+ param.level = MMAL_VIDEO_LEVEL_H264_1;
-+ break;
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
-+ param.level = MMAL_VIDEO_LEVEL_H264_1b;
-+ break;
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
-+ param.level = MMAL_VIDEO_LEVEL_H264_11;
-+ break;
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
-+ param.level = MMAL_VIDEO_LEVEL_H264_12;
-+ break;
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
-+ param.level = MMAL_VIDEO_LEVEL_H264_13;
-+ break;
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
-+ param.level = MMAL_VIDEO_LEVEL_H264_2;
-+ break;
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
-+ param.level = MMAL_VIDEO_LEVEL_H264_21;
-+ break;
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
-+ param.level = MMAL_VIDEO_LEVEL_H264_22;
-+ break;
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
-+ param.level = MMAL_VIDEO_LEVEL_H264_3;
-+ break;
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
-+ param.level = MMAL_VIDEO_LEVEL_H264_31;
-+ break;
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
-+ param.level = MMAL_VIDEO_LEVEL_H264_32;
-+ break;
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
-+ param.level = MMAL_VIDEO_LEVEL_H264_4;
-+ break;
-+ default:
-+ /* Should never get here */
-+ break;
-+ }
-+
-+ ret = vchiq_mmal_port_parameter_set(dev->instance,
-+ &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0],
-+ mmal_ctrl->mmal_id,
-+ &param, sizeof(param));
-+ }
-+ return ret;
-+}
-+
-+static int ctrl_set_scene_mode(struct bm2835_mmal_dev *dev,
-+ struct v4l2_ctrl *ctrl,
-+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
-+{
-+ int ret = 0;
-+ int shutter_speed;
-+ struct vchiq_mmal_port *control;
-+
-+ v4l2_dbg(0, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "scene mode selected %d, was %d\n", ctrl->val,
-+ dev->scene_mode);
-+ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
-+
-+ if (ctrl->val == dev->scene_mode)
-+ return 0;
-+
-+ if (ctrl->val == V4L2_SCENE_MODE_NONE) {
-+ /* Restore all user selections */
-+ dev->scene_mode = V4L2_SCENE_MODE_NONE;
-+
-+ if (dev->exposure_mode_user == MMAL_PARAM_EXPOSUREMODE_OFF)
-+ shutter_speed = dev->manual_shutter_speed;
-+ else
-+ shutter_speed = 0;
-+
-+ v4l2_dbg(0, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "%s: scene mode none: shut_speed %d, exp_mode %d, metering %d\n",
-+ __func__, shutter_speed, dev->exposure_mode_user,
-+ dev->metering_mode);
-+ ret = vchiq_mmal_port_parameter_set(dev->instance,
-+ control,
-+ MMAL_PARAMETER_SHUTTER_SPEED,
-+ &shutter_speed,
-+ sizeof(shutter_speed));
-+ ret += vchiq_mmal_port_parameter_set(dev->instance,
-+ control,
-+ MMAL_PARAMETER_EXPOSURE_MODE,
-+ &dev->exposure_mode_user,
-+ sizeof(u32));
-+ dev->exposure_mode_active = dev->exposure_mode_user;
-+ ret += vchiq_mmal_port_parameter_set(dev->instance,
-+ control,
-+ MMAL_PARAMETER_EXP_METERING_MODE,
-+ &dev->metering_mode,
-+ sizeof(u32));
-+ ret += set_framerate_params(dev);
-+ } else {
-+ /* Set up scene mode */
-+ int i;
-+ const struct v4l2_mmal_scene_config *scene = NULL;
-+ int shutter_speed;
-+ enum mmal_parameter_exposuremode exposure_mode;
-+ enum mmal_parameter_exposuremeteringmode metering_mode;
-+
-+ for (i = 0; i < ARRAY_SIZE(scene_configs); i++) {
-+ if (scene_configs[i].v4l2_scene ==
-+ ctrl->val) {
-+ scene = &scene_configs[i];
-+ break;
-+ }
-+ }
-+ if (!scene)
-+ return -EINVAL;
-+ if (i >= ARRAY_SIZE(scene_configs))
-+ return -EINVAL;
-+
-+ /* Set all the values */
-+ dev->scene_mode = ctrl->val;
-+
-+ if (scene->exposure_mode == MMAL_PARAM_EXPOSUREMODE_OFF)
-+ shutter_speed = dev->manual_shutter_speed;
-+ else
-+ shutter_speed = 0;
-+ exposure_mode = scene->exposure_mode;
-+ metering_mode = scene->metering_mode;
-+
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "%s: scene mode none: shut_speed %d, exp_mode %d, metering %d\n",
-+ __func__, shutter_speed, exposure_mode, metering_mode);
-+
-+ ret = vchiq_mmal_port_parameter_set(dev->instance, control,
-+ MMAL_PARAMETER_SHUTTER_SPEED,
-+ &shutter_speed,
-+ sizeof(shutter_speed));
-+ ret += vchiq_mmal_port_parameter_set(dev->instance,
-+ control,
-+ MMAL_PARAMETER_EXPOSURE_MODE,
-+ &exposure_mode,
-+ sizeof(u32));
-+ dev->exposure_mode_active = exposure_mode;
-+ ret += vchiq_mmal_port_parameter_set(dev->instance, control,
-+ MMAL_PARAMETER_EXPOSURE_MODE,
-+ &exposure_mode,
-+ sizeof(u32));
-+ ret += vchiq_mmal_port_parameter_set(dev->instance, control,
-+ MMAL_PARAMETER_EXP_METERING_MODE,
-+ &metering_mode,
-+ sizeof(u32));
-+ ret += set_framerate_params(dev);
-+ }
-+ if (ret) {
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "%s: Setting scene to %d, ret=%d\n",
-+ __func__, ctrl->val, ret);
-+ ret = -EINVAL;
-+ }
-+ return 0;
-+}
-+
-+static int bm2835_mmal_s_ctrl(struct v4l2_ctrl *ctrl)
-+{
-+ struct bm2835_mmal_dev *dev =
-+ container_of(ctrl->handler, struct bm2835_mmal_dev,
-+ ctrl_handler);
-+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl = ctrl->priv;
-+ int ret;
-+
-+ if ((mmal_ctrl == NULL) ||
-+ (mmal_ctrl->id != ctrl->id) ||
-+ (mmal_ctrl->setter == NULL)) {
-+ pr_warn("mmal_ctrl:%p ctrl id:%d\n", mmal_ctrl, ctrl->id);
-+ return -EINVAL;
-+ }
-+
-+ ret = mmal_ctrl->setter(dev, ctrl, mmal_ctrl);
-+ if (ret)
-+ pr_warn("ctrl id:%d/MMAL param %08X- returned ret %d\n",
-+ ctrl->id, mmal_ctrl->mmal_id, ret);
-+ if (mmal_ctrl->ignore_errors)
-+ ret = 0;
-+ return ret;
-+}
-+
-+static const struct v4l2_ctrl_ops bm2835_mmal_ctrl_ops = {
-+ .s_ctrl = bm2835_mmal_s_ctrl,
-+};
-+
-+
-+
-+static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = {
-+ {
-+ V4L2_CID_SATURATION, MMAL_CONTROL_TYPE_STD,
-+ -100, 100, 0, 1, NULL,
-+ MMAL_PARAMETER_SATURATION,
-+ &ctrl_set_rational,
-+ false
-+ },
-+ {
-+ V4L2_CID_SHARPNESS, MMAL_CONTROL_TYPE_STD,
-+ -100, 100, 0, 1, NULL,
-+ MMAL_PARAMETER_SHARPNESS,
-+ &ctrl_set_rational,
-+ false
-+ },
-+ {
-+ V4L2_CID_CONTRAST, MMAL_CONTROL_TYPE_STD,
-+ -100, 100, 0, 1, NULL,
-+ MMAL_PARAMETER_CONTRAST,
-+ &ctrl_set_rational,
-+ false
-+ },
-+ {
-+ V4L2_CID_BRIGHTNESS, MMAL_CONTROL_TYPE_STD,
-+ 0, 100, 50, 1, NULL,
-+ MMAL_PARAMETER_BRIGHTNESS,
-+ &ctrl_set_rational,
-+ false
-+ },
-+ {
-+ V4L2_CID_ISO_SENSITIVITY, MMAL_CONTROL_TYPE_INT_MENU,
-+ 0, ARRAY_SIZE(iso_qmenu) - 1, 0, 1, iso_qmenu,
-+ MMAL_PARAMETER_ISO,
-+ &ctrl_set_value_menu,
-+ false
-+ },
-+ {
-+ V4L2_CID_IMAGE_STABILIZATION, MMAL_CONTROL_TYPE_STD,
-+ 0, 1, 0, 1, NULL,
-+ MMAL_PARAMETER_VIDEO_STABILISATION,
-+ &ctrl_set_value,
-+ false
-+ },
-+/* {
-+ 0, MMAL_CONTROL_TYPE_CLUSTER, 3, 1, 0, NULL, 0, NULL
-+ }, */
-+ {
-+ V4L2_CID_EXPOSURE_AUTO, MMAL_CONTROL_TYPE_STD_MENU,
-+ ~0x03, 3, V4L2_EXPOSURE_AUTO, 0, NULL,
-+ MMAL_PARAMETER_EXPOSURE_MODE,
-+ &ctrl_set_exposure,
-+ false
-+ },
-+/* todo this needs mixing in with set exposure
-+ {
-+ V4L2_CID_SCENE_MODE, MMAL_CONTROL_TYPE_STD_MENU,
-+ },
-+ */
-+ {
-+ V4L2_CID_EXPOSURE_ABSOLUTE, MMAL_CONTROL_TYPE_STD,
-+ /* Units of 100usecs */
-+ 1, 1*1000*10, 100*10, 1, NULL,
-+ MMAL_PARAMETER_SHUTTER_SPEED,
-+ &ctrl_set_exposure,
-+ false
-+ },
-+ {
-+ V4L2_CID_AUTO_EXPOSURE_BIAS, MMAL_CONTROL_TYPE_INT_MENU,
-+ 0, ARRAY_SIZE(ev_bias_qmenu) - 1,
-+ (ARRAY_SIZE(ev_bias_qmenu)+1)/2 - 1, 0, ev_bias_qmenu,
-+ MMAL_PARAMETER_EXPOSURE_COMP,
-+ &ctrl_set_value_ev,
-+ false
-+ },
-+ {
-+ V4L2_CID_EXPOSURE_AUTO_PRIORITY, MMAL_CONTROL_TYPE_STD,
-+ 0, 1,
-+ 0, 1, NULL,
-+ 0, /* Dummy MMAL ID as it gets mapped into FPS range*/
-+ &ctrl_set_exposure,
-+ false
-+ },
-+ {
-+ V4L2_CID_EXPOSURE_METERING,
-+ MMAL_CONTROL_TYPE_STD_MENU,
-+ ~0x7, 2, V4L2_EXPOSURE_METERING_AVERAGE, 0, NULL,
-+ MMAL_PARAMETER_EXP_METERING_MODE,
-+ &ctrl_set_metering_mode,
-+ false
-+ },
-+ {
-+ V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
-+ MMAL_CONTROL_TYPE_STD_MENU,
-+ ~0x3ff, 9, V4L2_WHITE_BALANCE_AUTO, 0, NULL,
-+ MMAL_PARAMETER_AWB_MODE,
-+ &ctrl_set_awb_mode,
-+ false
-+ },
-+ {
-+ V4L2_CID_RED_BALANCE, MMAL_CONTROL_TYPE_STD,
-+ 1, 7999, 1000, 1, NULL,
-+ MMAL_PARAMETER_CUSTOM_AWB_GAINS,
-+ &ctrl_set_awb_gains,
-+ false
-+ },
-+ {
-+ V4L2_CID_BLUE_BALANCE, MMAL_CONTROL_TYPE_STD,
-+ 1, 7999, 1000, 1, NULL,
-+ MMAL_PARAMETER_CUSTOM_AWB_GAINS,
-+ &ctrl_set_awb_gains,
-+ false
-+ },
-+ {
-+ V4L2_CID_COLORFX, MMAL_CONTROL_TYPE_STD_MENU,
-+ 0, 15, V4L2_COLORFX_NONE, 0, NULL,
-+ MMAL_PARAMETER_IMAGE_EFFECT,
-+ &ctrl_set_image_effect,
-+ false
-+ },
-+ {
-+ V4L2_CID_COLORFX_CBCR, MMAL_CONTROL_TYPE_STD,
-+ 0, 0xffff, 0x8080, 1, NULL,
-+ MMAL_PARAMETER_COLOUR_EFFECT,
-+ &ctrl_set_colfx,
-+ false
-+ },
-+ {
-+ V4L2_CID_ROTATE, MMAL_CONTROL_TYPE_STD,
-+ 0, 360, 0, 90, NULL,
-+ MMAL_PARAMETER_ROTATION,
-+ &ctrl_set_rotate,
-+ false
-+ },
-+ {
-+ V4L2_CID_HFLIP, MMAL_CONTROL_TYPE_STD,
-+ 0, 1, 0, 1, NULL,
-+ MMAL_PARAMETER_MIRROR,
-+ &ctrl_set_flip,
-+ false
-+ },
-+ {
-+ V4L2_CID_VFLIP, MMAL_CONTROL_TYPE_STD,
-+ 0, 1, 0, 1, NULL,
-+ MMAL_PARAMETER_MIRROR,
-+ &ctrl_set_flip,
-+ false
-+ },
-+ {
-+ V4L2_CID_MPEG_VIDEO_BITRATE_MODE, MMAL_CONTROL_TYPE_STD_MENU,
-+ 0, ARRAY_SIZE(bitrate_mode_qmenu) - 1,
-+ 0, 0, bitrate_mode_qmenu,
-+ MMAL_PARAMETER_RATECONTROL,
-+ &ctrl_set_bitrate_mode,
-+ false
-+ },
-+ {
-+ V4L2_CID_MPEG_VIDEO_BITRATE, MMAL_CONTROL_TYPE_STD,
-+ 25*1000, 25*1000*1000, 10*1000*1000, 25*1000, NULL,
-+ MMAL_PARAMETER_VIDEO_BIT_RATE,
-+ &ctrl_set_bitrate,
-+ false
-+ },
-+ {
-+ V4L2_CID_JPEG_COMPRESSION_QUALITY, MMAL_CONTROL_TYPE_STD,
-+ 1, 100,
-+ 30, 1, NULL,
-+ MMAL_PARAMETER_JPEG_Q_FACTOR,
-+ &ctrl_set_image_encode_output,
-+ false
-+ },
-+ {
-+ V4L2_CID_POWER_LINE_FREQUENCY, MMAL_CONTROL_TYPE_STD_MENU,
-+ 0, ARRAY_SIZE(mains_freq_qmenu) - 1,
-+ 1, 1, NULL,
-+ MMAL_PARAMETER_FLICKER_AVOID,
-+ &ctrl_set_flicker_avoidance,
-+ false
-+ },
-+ {
-+ V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER, MMAL_CONTROL_TYPE_STD,
-+ 0, 1,
-+ 0, 1, NULL,
-+ MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER,
-+ &ctrl_set_video_encode_param_output,
-+ true /* Errors ignored as requires latest firmware to work */
-+ },
-+ {
-+ V4L2_CID_MPEG_VIDEO_H264_PROFILE,
-+ MMAL_CONTROL_TYPE_STD_MENU,
-+ ~((1<<V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
-+ (1<<V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) |
-+ (1<<V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
-+ (1<<V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)),
-+ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
-+ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, 1, NULL,
-+ MMAL_PARAMETER_PROFILE,
-+ &ctrl_set_video_encode_profile_level,
-+ false
-+ },
-+ {
-+ V4L2_CID_MPEG_VIDEO_H264_LEVEL, MMAL_CONTROL_TYPE_STD_MENU,
-+ ~((1<<V4L2_MPEG_VIDEO_H264_LEVEL_1_0) |
-+ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_1B) |
-+ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_1_1) |
-+ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_1_2) |
-+ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_1_3) |
-+ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
-+ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_2_1) |
-+ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_2_2) |
-+ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_3_0) |
-+ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_3_1) |
-+ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
-+ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_4_0)),
-+ V4L2_MPEG_VIDEO_H264_LEVEL_4_0,
-+ V4L2_MPEG_VIDEO_H264_LEVEL_4_0, 1, NULL,
-+ MMAL_PARAMETER_PROFILE,
-+ &ctrl_set_video_encode_profile_level,
-+ false
-+ },
-+ {
-+ V4L2_CID_SCENE_MODE, MMAL_CONTROL_TYPE_STD_MENU,
-+ -1, /* Min is computed at runtime */
-+ V4L2_SCENE_MODE_TEXT,
-+ V4L2_SCENE_MODE_NONE, 1, NULL,
-+ MMAL_PARAMETER_PROFILE,
-+ &ctrl_set_scene_mode,
-+ false
-+ },
-+ {
-+ V4L2_CID_MPEG_VIDEO_H264_I_PERIOD, MMAL_CONTROL_TYPE_STD,
-+ 0, 0x7FFFFFFF, 60, 1, NULL,
-+ MMAL_PARAMETER_INTRAPERIOD,
-+ &ctrl_set_video_encode_param_output,
-+ false
-+ },
-+};
-+
-+int bm2835_mmal_set_all_camera_controls(struct bm2835_mmal_dev *dev)
-+{
-+ int c;
-+ int ret = 0;
-+
-+ for (c = 0; c < V4L2_CTRL_COUNT; c++) {
-+ if ((dev->ctrls[c]) && (v4l2_ctrls[c].setter)) {
-+ ret = v4l2_ctrls[c].setter(dev, dev->ctrls[c],
-+ &v4l2_ctrls[c]);
-+ if (!v4l2_ctrls[c].ignore_errors && ret) {
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "Failed when setting default values for ctrl %d\n",
-+ c);
-+ break;
-+ }
-+ }
-+ }
-+ return ret;
-+}
-+
-+int set_framerate_params(struct bm2835_mmal_dev *dev)
-+{
-+ struct mmal_parameter_fps_range fps_range;
-+ int ret;
-+
-+ if ((dev->exposure_mode_active != MMAL_PARAM_EXPOSUREMODE_OFF) &&
-+ (dev->exp_auto_priority)) {
-+ /* Variable FPS. Define min FPS as 1fps.
-+ * Max as max defined FPS.
-+ */
-+ fps_range.fps_low.num = 1;
-+ fps_range.fps_low.den = 1;
-+ fps_range.fps_high.num = dev->capture.timeperframe.denominator;
-+ fps_range.fps_high.den = dev->capture.timeperframe.numerator;
-+ } else {
-+ /* Fixed FPS - set min and max to be the same */
-+ fps_range.fps_low.num = fps_range.fps_high.num =
-+ dev->capture.timeperframe.denominator;
-+ fps_range.fps_low.den = fps_range.fps_high.den =
-+ dev->capture.timeperframe.numerator;
-+ }
-+
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "Set fps range to %d/%d to %d/%d\n",
-+ fps_range.fps_low.num,
-+ fps_range.fps_low.den,
-+ fps_range.fps_high.num,
-+ fps_range.fps_high.den
-+ );
-+
-+ ret = vchiq_mmal_port_parameter_set(dev->instance,
-+ &dev->component[MMAL_COMPONENT_CAMERA]->
-+ output[MMAL_CAMERA_PORT_PREVIEW],
-+ MMAL_PARAMETER_FPS_RANGE,
-+ &fps_range, sizeof(fps_range));
-+ ret += vchiq_mmal_port_parameter_set(dev->instance,
-+ &dev->component[MMAL_COMPONENT_CAMERA]->
-+ output[MMAL_CAMERA_PORT_VIDEO],
-+ MMAL_PARAMETER_FPS_RANGE,
-+ &fps_range, sizeof(fps_range));
-+ ret += vchiq_mmal_port_parameter_set(dev->instance,
-+ &dev->component[MMAL_COMPONENT_CAMERA]->
-+ output[MMAL_CAMERA_PORT_CAPTURE],
-+ MMAL_PARAMETER_FPS_RANGE,
-+ &fps_range, sizeof(fps_range));
-+ if (ret)
-+ v4l2_dbg(0, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "Failed to set fps ret %d\n",
-+ ret);
-+
-+ return ret;
-+
-+}
-+
-+int bm2835_mmal_init_controls(struct bm2835_mmal_dev *dev,
-+ struct v4l2_ctrl_handler *hdl)
-+{
-+ int c;
-+ const struct bm2835_mmal_v4l2_ctrl *ctrl;
-+
-+ v4l2_ctrl_handler_init(hdl, V4L2_CTRL_COUNT);
-+
-+ for (c = 0; c < V4L2_CTRL_COUNT; c++) {
-+ ctrl = &v4l2_ctrls[c];
-+
-+ switch (ctrl->type) {
-+ case MMAL_CONTROL_TYPE_STD:
-+ dev->ctrls[c] = v4l2_ctrl_new_std(hdl,
-+ &bm2835_mmal_ctrl_ops, ctrl->id,
-+ ctrl->min, ctrl->max, ctrl->step, ctrl->def);
-+ break;
-+
-+ case MMAL_CONTROL_TYPE_STD_MENU:
-+ {
-+ int mask = ctrl->min;
-+
-+ if (ctrl->id == V4L2_CID_SCENE_MODE) {
-+ /* Special handling to work out the mask
-+ * value based on the scene_configs array
-+ * at runtime. Reduces the chance of
-+ * mismatches.
-+ */
-+ int i;
-+ mask = 1<<V4L2_SCENE_MODE_NONE;
-+ for (i = 0;
-+ i < ARRAY_SIZE(scene_configs);
-+ i++) {
-+ mask |= 1<<scene_configs[i].v4l2_scene;
-+ }
-+ mask = ~mask;
-+ }
-+
-+ dev->ctrls[c] = v4l2_ctrl_new_std_menu(hdl,
-+ &bm2835_mmal_ctrl_ops, ctrl->id,
-+ ctrl->max, mask, ctrl->def);
-+ break;
-+ }
-+
-+ case MMAL_CONTROL_TYPE_INT_MENU:
-+ dev->ctrls[c] = v4l2_ctrl_new_int_menu(hdl,
-+ &bm2835_mmal_ctrl_ops, ctrl->id,
-+ ctrl->max, ctrl->def, ctrl->imenu);
-+ break;
-+
-+ case MMAL_CONTROL_TYPE_CLUSTER:
-+ /* skip this entry when constructing controls */
-+ continue;
-+ }
-+
-+ if (hdl->error)
-+ break;
-+
-+ dev->ctrls[c]->priv = (void *)ctrl;
-+ }
-+
-+ if (hdl->error) {
-+ pr_err("error adding control %d/%d id 0x%x\n", c,
-+ V4L2_CTRL_COUNT, ctrl->id);
-+ return hdl->error;
-+ }
-+
-+ for (c = 0; c < V4L2_CTRL_COUNT; c++) {
-+ ctrl = &v4l2_ctrls[c];
-+
-+ switch (ctrl->type) {
-+ case MMAL_CONTROL_TYPE_CLUSTER:
-+ v4l2_ctrl_auto_cluster(ctrl->min,
-+ &dev->ctrls[c+1],
-+ ctrl->max,
-+ ctrl->def);
-+ break;
-+
-+ case MMAL_CONTROL_TYPE_STD:
-+ case MMAL_CONTROL_TYPE_STD_MENU:
-+ case MMAL_CONTROL_TYPE_INT_MENU:
-+ break;
-+ }
-+
-+ }
-+
-+ return 0;
-+}
---- /dev/null
-+++ b/drivers/media/platform/bcm2835/mmal-common.h
-@@ -0,0 +1,53 @@
-+/*
-+ * Broadcom BM2835 V4L2 driver
-+ *
-+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
-+ *
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file COPYING in the main directory of this archive
-+ * for more details.
-+ *
-+ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
-+ * Dave Stevenson <dsteve@broadcom.com>
-+ * Simon Mellor <simellor@broadcom.com>
-+ * Luke Diamand <luked@broadcom.com>
-+ *
-+ * MMAL structures
-+ *
-+ */
-+
-+#define MMAL_FOURCC(a, b, c, d) ((a) | (b << 8) | (c << 16) | (d << 24))
-+#define MMAL_MAGIC MMAL_FOURCC('m', 'm', 'a', 'l')
-+
-+/** Special value signalling that time is not known */
-+#define MMAL_TIME_UNKNOWN (1LL<<63)
-+
-+/* mapping between v4l and mmal video modes */
-+struct mmal_fmt {
-+ char *name;
-+ u32 fourcc; /* v4l2 format id */
-+ int flags; /* v4l2 flags field */
-+ u32 mmal;
-+ int depth;
-+ u32 mmal_component; /* MMAL component index to be used to encode */
-+ u32 ybbp; /* depth of first Y plane for planar formats */
-+};
-+
-+/* buffer for one video frame */
-+struct mmal_buffer {
-+ /* v4l buffer data -- must be first */
-+ struct vb2_v4l2_buffer vb;
-+
-+ /* list of buffers available */
-+ struct list_head list;
-+
-+ void *buffer; /* buffer pointer */
-+ unsigned long buffer_size; /* size of allocated buffer */
-+};
-+
-+/* */
-+struct mmal_colourfx {
-+ s32 enable;
-+ u32 u;
-+ u32 v;
-+};
---- /dev/null
-+++ b/drivers/media/platform/bcm2835/mmal-encodings.h
-@@ -0,0 +1,127 @@
-+/*
-+ * Broadcom BM2835 V4L2 driver
-+ *
-+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
-+ *
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file COPYING in the main directory of this archive
-+ * for more details.
-+ *
-+ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
-+ * Dave Stevenson <dsteve@broadcom.com>
-+ * Simon Mellor <simellor@broadcom.com>
-+ * Luke Diamand <luked@broadcom.com>
-+ */
-+#ifndef MMAL_ENCODINGS_H
-+#define MMAL_ENCODINGS_H
-+
-+#define MMAL_ENCODING_H264 MMAL_FOURCC('H', '2', '6', '4')
-+#define MMAL_ENCODING_H263 MMAL_FOURCC('H', '2', '6', '3')
-+#define MMAL_ENCODING_MP4V MMAL_FOURCC('M', 'P', '4', 'V')
-+#define MMAL_ENCODING_MP2V MMAL_FOURCC('M', 'P', '2', 'V')
-+#define MMAL_ENCODING_MP1V MMAL_FOURCC('M', 'P', '1', 'V')
-+#define MMAL_ENCODING_WMV3 MMAL_FOURCC('W', 'M', 'V', '3')
-+#define MMAL_ENCODING_WMV2 MMAL_FOURCC('W', 'M', 'V', '2')
-+#define MMAL_ENCODING_WMV1 MMAL_FOURCC('W', 'M', 'V', '1')
-+#define MMAL_ENCODING_WVC1 MMAL_FOURCC('W', 'V', 'C', '1')
-+#define MMAL_ENCODING_VP8 MMAL_FOURCC('V', 'P', '8', ' ')
-+#define MMAL_ENCODING_VP7 MMAL_FOURCC('V', 'P', '7', ' ')
-+#define MMAL_ENCODING_VP6 MMAL_FOURCC('V', 'P', '6', ' ')
-+#define MMAL_ENCODING_THEORA MMAL_FOURCC('T', 'H', 'E', 'O')
-+#define MMAL_ENCODING_SPARK MMAL_FOURCC('S', 'P', 'R', 'K')
-+#define MMAL_ENCODING_MJPEG MMAL_FOURCC('M', 'J', 'P', 'G')
-+
-+#define MMAL_ENCODING_JPEG MMAL_FOURCC('J', 'P', 'E', 'G')
-+#define MMAL_ENCODING_GIF MMAL_FOURCC('G', 'I', 'F', ' ')
-+#define MMAL_ENCODING_PNG MMAL_FOURCC('P', 'N', 'G', ' ')
-+#define MMAL_ENCODING_PPM MMAL_FOURCC('P', 'P', 'M', ' ')
-+#define MMAL_ENCODING_TGA MMAL_FOURCC('T', 'G', 'A', ' ')
-+#define MMAL_ENCODING_BMP MMAL_FOURCC('B', 'M', 'P', ' ')
-+
-+#define MMAL_ENCODING_I420 MMAL_FOURCC('I', '4', '2', '0')
-+#define MMAL_ENCODING_I420_SLICE MMAL_FOURCC('S', '4', '2', '0')
-+#define MMAL_ENCODING_YV12 MMAL_FOURCC('Y', 'V', '1', '2')
-+#define MMAL_ENCODING_I422 MMAL_FOURCC('I', '4', '2', '2')
-+#define MMAL_ENCODING_I422_SLICE MMAL_FOURCC('S', '4', '2', '2')
-+#define MMAL_ENCODING_YUYV MMAL_FOURCC('Y', 'U', 'Y', 'V')
-+#define MMAL_ENCODING_YVYU MMAL_FOURCC('Y', 'V', 'Y', 'U')
-+#define MMAL_ENCODING_UYVY MMAL_FOURCC('U', 'Y', 'V', 'Y')
-+#define MMAL_ENCODING_VYUY MMAL_FOURCC('V', 'Y', 'U', 'Y')
-+#define MMAL_ENCODING_NV12 MMAL_FOURCC('N', 'V', '1', '2')
-+#define MMAL_ENCODING_NV21 MMAL_FOURCC('N', 'V', '2', '1')
-+#define MMAL_ENCODING_ARGB MMAL_FOURCC('A', 'R', 'G', 'B')
-+#define MMAL_ENCODING_RGBA MMAL_FOURCC('R', 'G', 'B', 'A')
-+#define MMAL_ENCODING_ABGR MMAL_FOURCC('A', 'B', 'G', 'R')
-+#define MMAL_ENCODING_BGRA MMAL_FOURCC('B', 'G', 'R', 'A')
-+#define MMAL_ENCODING_RGB16 MMAL_FOURCC('R', 'G', 'B', '2')
-+#define MMAL_ENCODING_RGB24 MMAL_FOURCC('R', 'G', 'B', '3')
-+#define MMAL_ENCODING_RGB32 MMAL_FOURCC('R', 'G', 'B', '4')
-+#define MMAL_ENCODING_BGR16 MMAL_FOURCC('B', 'G', 'R', '2')
-+#define MMAL_ENCODING_BGR24 MMAL_FOURCC('B', 'G', 'R', '3')
-+#define MMAL_ENCODING_BGR32 MMAL_FOURCC('B', 'G', 'R', '4')
-+
-+/** SAND Video (YUVUV128) format, native format understood by VideoCore.
-+ * This format is *not* opaque - if requested you will receive full frames
-+ * of YUV_UV video.
-+ */
-+#define MMAL_ENCODING_YUVUV128 MMAL_FOURCC('S', 'A', 'N', 'D')
-+
-+/** VideoCore opaque image format, image handles are returned to
-+ * the host but not the actual image data.
-+ */
-+#define MMAL_ENCODING_OPAQUE MMAL_FOURCC('O', 'P', 'Q', 'V')
-+
-+/** An EGL image handle
-+ */
-+#define MMAL_ENCODING_EGL_IMAGE MMAL_FOURCC('E', 'G', 'L', 'I')
-+
-+/* }@ */
-+
-+/** \name Pre-defined audio encodings */
-+/* @{ */
-+#define MMAL_ENCODING_PCM_UNSIGNED_BE MMAL_FOURCC('P', 'C', 'M', 'U')
-+#define MMAL_ENCODING_PCM_UNSIGNED_LE MMAL_FOURCC('p', 'c', 'm', 'u')
-+#define MMAL_ENCODING_PCM_SIGNED_BE MMAL_FOURCC('P', 'C', 'M', 'S')
-+#define MMAL_ENCODING_PCM_SIGNED_LE MMAL_FOURCC('p', 'c', 'm', 's')
-+#define MMAL_ENCODING_PCM_FLOAT_BE MMAL_FOURCC('P', 'C', 'M', 'F')
-+#define MMAL_ENCODING_PCM_FLOAT_LE MMAL_FOURCC('p', 'c', 'm', 'f')
-+
-+/* Pre-defined H264 encoding variants */
-+
-+/** ISO 14496-10 Annex B byte stream format */
-+#define MMAL_ENCODING_VARIANT_H264_DEFAULT 0
-+/** ISO 14496-15 AVC stream format */
-+#define MMAL_ENCODING_VARIANT_H264_AVC1 MMAL_FOURCC('A', 'V', 'C', '1')
-+/** Implicitly delineated NAL units without emulation prevention */
-+#define MMAL_ENCODING_VARIANT_H264_RAW MMAL_FOURCC('R', 'A', 'W', ' ')
-+
-+
-+/** \defgroup MmalColorSpace List of pre-defined video color spaces
-+ * This defines a list of common color spaces. This list isn't exhaustive and
-+ * is only provided as a convenience to avoid clients having to use FourCC
-+ * codes directly. However components are allowed to define and use their own
-+ * FourCC codes.
-+ */
-+/* @{ */
-+
-+/** Unknown color space */
-+#define MMAL_COLOR_SPACE_UNKNOWN 0
-+/** ITU-R BT.601-5 [SDTV] */
-+#define MMAL_COLOR_SPACE_ITUR_BT601 MMAL_FOURCC('Y', '6', '0', '1')
-+/** ITU-R BT.709-3 [HDTV] */
-+#define MMAL_COLOR_SPACE_ITUR_BT709 MMAL_FOURCC('Y', '7', '0', '9')
-+/** JPEG JFIF */
-+#define MMAL_COLOR_SPACE_JPEG_JFIF MMAL_FOURCC('Y', 'J', 'F', 'I')
-+/** Title 47 Code of Federal Regulations (2003) 73.682 (a) (20) */
-+#define MMAL_COLOR_SPACE_FCC MMAL_FOURCC('Y', 'F', 'C', 'C')
-+/** Society of Motion Picture and Television Engineers 240M (1999) */
-+#define MMAL_COLOR_SPACE_SMPTE240M MMAL_FOURCC('Y', '2', '4', '0')
-+/** ITU-R BT.470-2 System M */
-+#define MMAL_COLOR_SPACE_BT470_2_M MMAL_FOURCC('Y', '_', '_', 'M')
-+/** ITU-R BT.470-2 System BG */
-+#define MMAL_COLOR_SPACE_BT470_2_BG MMAL_FOURCC('Y', '_', 'B', 'G')
-+/** JPEG JFIF, but with 16..255 luma */
-+#define MMAL_COLOR_SPACE_JFIF_Y16_255 MMAL_FOURCC('Y', 'Y', '1', '6')
-+/* @} MmalColorSpace List */
-+
-+#endif /* MMAL_ENCODINGS_H */
---- /dev/null
-+++ b/drivers/media/platform/bcm2835/mmal-msg-common.h
-@@ -0,0 +1,50 @@
-+/*
-+ * Broadcom BM2835 V4L2 driver
-+ *
-+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
-+ *
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file COPYING in the main directory of this archive
-+ * for more details.
-+ *
-+ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
-+ * Dave Stevenson <dsteve@broadcom.com>
-+ * Simon Mellor <simellor@broadcom.com>
-+ * Luke Diamand <luked@broadcom.com>
-+ */
-+
-+#ifndef MMAL_MSG_COMMON_H
-+#define MMAL_MSG_COMMON_H
-+
-+enum mmal_msg_status {
-+ MMAL_MSG_STATUS_SUCCESS = 0, /**< Success */
-+ MMAL_MSG_STATUS_ENOMEM, /**< Out of memory */
-+ MMAL_MSG_STATUS_ENOSPC, /**< Out of resources other than memory */
-+ MMAL_MSG_STATUS_EINVAL, /**< Argument is invalid */
-+ MMAL_MSG_STATUS_ENOSYS, /**< Function not implemented */
-+ MMAL_MSG_STATUS_ENOENT, /**< No such file or directory */
-+ MMAL_MSG_STATUS_ENXIO, /**< No such device or address */
-+ MMAL_MSG_STATUS_EIO, /**< I/O error */
-+ MMAL_MSG_STATUS_ESPIPE, /**< Illegal seek */
-+ MMAL_MSG_STATUS_ECORRUPT, /**< Data is corrupt \attention */
-+ MMAL_MSG_STATUS_ENOTREADY, /**< Component is not ready */
-+ MMAL_MSG_STATUS_ECONFIG, /**< Component is not configured */
-+ MMAL_MSG_STATUS_EISCONN, /**< Port is already connected */
-+ MMAL_MSG_STATUS_ENOTCONN, /**< Port is disconnected */
-+ MMAL_MSG_STATUS_EAGAIN, /**< Resource temporarily unavailable. */
-+ MMAL_MSG_STATUS_EFAULT, /**< Bad address */
-+};
-+
-+struct mmal_rect {
-+ s32 x; /**< x coordinate (from left) */
-+ s32 y; /**< y coordinate (from top) */
-+ s32 width; /**< width */
-+ s32 height; /**< height */
-+};
-+
-+struct mmal_rational {
-+ s32 num; /**< Numerator */
-+ s32 den; /**< Denominator */
-+};
-+
-+#endif /* MMAL_MSG_COMMON_H */
---- /dev/null
-+++ b/drivers/media/platform/bcm2835/mmal-msg-format.h
-@@ -0,0 +1,81 @@
-+/*
-+ * Broadcom BM2835 V4L2 driver
-+ *
-+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
-+ *
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file COPYING in the main directory of this archive
-+ * for more details.
-+ *
-+ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
-+ * Dave Stevenson <dsteve@broadcom.com>
-+ * Simon Mellor <simellor@broadcom.com>
-+ * Luke Diamand <luked@broadcom.com>
-+ */
-+
-+#ifndef MMAL_MSG_FORMAT_H
-+#define MMAL_MSG_FORMAT_H
-+
-+#include "mmal-msg-common.h"
-+
-+/* MMAL_ES_FORMAT_T */
-+
-+
-+struct mmal_audio_format {
-+ u32 channels; /**< Number of audio channels */
-+ u32 sample_rate; /**< Sample rate */
-+
-+ u32 bits_per_sample; /**< Bits per sample */
-+ u32 block_align; /**< Size of a block of data */
-+};
-+
-+struct mmal_video_format {
-+ u32 width; /**< Width of frame in pixels */
-+ u32 height; /**< Height of frame in rows of pixels */
-+ struct mmal_rect crop; /**< Visible region of the frame */
-+ struct mmal_rational frame_rate; /**< Frame rate */
-+ struct mmal_rational par; /**< Pixel aspect ratio */
-+
-+ /* FourCC specifying the color space of the video stream. See the
-+ * \ref MmalColorSpace "pre-defined color spaces" for some examples.
-+ */
-+ u32 color_space;
-+};
-+
-+struct mmal_subpicture_format {
-+ u32 x_offset;
-+ u32 y_offset;
-+};
-+
-+union mmal_es_specific_format {
-+ struct mmal_audio_format audio;
-+ struct mmal_video_format video;
-+ struct mmal_subpicture_format subpicture;
-+};
-+
-+/** Definition of an elementary stream format (MMAL_ES_FORMAT_T) */
-+struct mmal_es_format {
-+ u32 type; /* enum mmal_es_type */
-+
-+ u32 encoding; /* FourCC specifying encoding of the elementary stream.*/
-+ u32 encoding_variant; /* FourCC specifying the specific
-+ * encoding variant of the elementary
-+ * stream.
-+ */
-+
-+ union mmal_es_specific_format *es; /* TODO: pointers in
-+ * message serialisation?!?
-+ */
-+ /* Type specific
-+ * information for the
-+ * elementary stream
-+ */
-+
-+ u32 bitrate; /**< Bitrate in bits per second */
-+ u32 flags; /**< Flags describing properties of the elementary stream. */
-+
-+ u32 extradata_size; /**< Size of the codec specific data */
-+ u8 *extradata; /**< Codec specific data */
-+};
-+
-+#endif /* MMAL_MSG_FORMAT_H */
---- /dev/null
-+++ b/drivers/media/platform/bcm2835/mmal-msg-port.h
-@@ -0,0 +1,107 @@
-+/*
-+ * Broadcom BM2835 V4L2 driver
-+ *
-+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
-+ *
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file COPYING in the main directory of this archive
-+ * for more details.
-+ *
-+ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
-+ * Dave Stevenson <dsteve@broadcom.com>
-+ * Simon Mellor <simellor@broadcom.com>
-+ * Luke Diamand <luked@broadcom.com>
-+ */
-+
-+/* MMAL_PORT_TYPE_T */
-+enum mmal_port_type {
-+ MMAL_PORT_TYPE_UNKNOWN = 0, /**< Unknown port type */
-+ MMAL_PORT_TYPE_CONTROL, /**< Control port */
-+ MMAL_PORT_TYPE_INPUT, /**< Input port */
-+ MMAL_PORT_TYPE_OUTPUT, /**< Output port */
-+ MMAL_PORT_TYPE_CLOCK, /**< Clock port */
-+};
-+
-+/** The port is pass-through and doesn't need buffer headers allocated */
-+#define MMAL_PORT_CAPABILITY_PASSTHROUGH 0x01
-+/** The port wants to allocate the buffer payloads.
-+ * This signals a preference that payload allocation should be done
-+ * on this port for efficiency reasons. */
-+#define MMAL_PORT_CAPABILITY_ALLOCATION 0x02
-+/** The port supports format change events.
-+ * This applies to input ports and is used to let the client know
-+ * whether the port supports being reconfigured via a format
-+ * change event (i.e. without having to disable the port). */
-+#define MMAL_PORT_CAPABILITY_SUPPORTS_EVENT_FORMAT_CHANGE 0x04
-+
-+/* mmal port structure (MMAL_PORT_T)
-+ *
-+ * most elements are informational only, the pointer values for
-+ * interogation messages are generally provided as additional
-+ * strucures within the message. When used to set values only teh
-+ * buffer_num, buffer_size and userdata parameters are writable.
-+ */
-+struct mmal_port {
-+ void *priv; /* Private member used by the framework */
-+ const char *name; /* Port name. Used for debugging purposes (RO) */
-+
-+ u32 type; /* Type of the port (RO) enum mmal_port_type */
-+ u16 index; /* Index of the port in its type list (RO) */
-+ u16 index_all; /* Index of the port in the list of all ports (RO) */
-+
-+ u32 is_enabled; /* Indicates whether the port is enabled or not (RO) */
-+ struct mmal_es_format *format; /* Format of the elementary stream */
-+
-+ u32 buffer_num_min; /* Minimum number of buffers the port
-+ * requires (RO). This is set by the
-+ * component.
-+ */
-+
-+ u32 buffer_size_min; /* Minimum size of buffers the port
-+ * requires (RO). This is set by the
-+ * component.
-+ */
-+
-+ u32 buffer_alignment_min; /* Minimum alignment requirement for
-+ * the buffers (RO). A value of
-+ * zero means no special alignment
-+ * requirements. This is set by the
-+ * component.
-+ */
-+
-+ u32 buffer_num_recommended; /* Number of buffers the port
-+ * recommends for optimal
-+ * performance (RO). A value of
-+ * zero means no special
-+ * recommendation. This is set
-+ * by the component.
-+ */
-+
-+ u32 buffer_size_recommended; /* Size of buffers the port
-+ * recommends for optimal
-+ * performance (RO). A value of
-+ * zero means no special
-+ * recommendation. This is set
-+ * by the component.
-+ */
-+
-+ u32 buffer_num; /* Actual number of buffers the port will use.
-+ * This is set by the client.
-+ */
-+
-+ u32 buffer_size; /* Actual maximum size of the buffers that
-+ * will be sent to the port. This is set by
-+ * the client.
-+ */
-+
-+ void *component; /* Component this port belongs to (Read Only) */
-+
-+ void *userdata; /* Field reserved for use by the client */
-+
-+ u32 capabilities; /* Flags describing the capabilities of a
-+ * port (RO). Bitwise combination of \ref
-+ * portcapabilities "Port capabilities"
-+ * values.
-+ */
-+
-+};
---- /dev/null
-+++ b/drivers/media/platform/bcm2835/mmal-msg.h
-@@ -0,0 +1,404 @@
-+/*
-+ * Broadcom BM2835 V4L2 driver
-+ *
-+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
-+ *
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file COPYING in the main directory of this archive
-+ * for more details.
-+ *
-+ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
-+ * Dave Stevenson <dsteve@broadcom.com>
-+ * Simon Mellor <simellor@broadcom.com>
-+ * Luke Diamand <luked@broadcom.com>
-+ */
-+
-+/* all the data structures which serialise the MMAL protocol. note
-+ * these are directly mapped onto the recived message data.
-+ *
-+ * BEWARE: They seem to *assume* pointers are u32 and that there is no
-+ * structure padding!
-+ *
-+ * NOTE: this implementation uses kernel types to ensure sizes. Rather
-+ * than assigning values to enums to force their size the
-+ * implementation uses fixed size types and not the enums (though the
-+ * comments have the actual enum type
-+ */
-+
-+#define VC_MMAL_VER 15
-+#define VC_MMAL_MIN_VER 10
-+#define VC_MMAL_SERVER_NAME MAKE_FOURCC("mmal")
-+
-+/* max total message size is 512 bytes */
-+#define MMAL_MSG_MAX_SIZE 512
-+/* with six 32bit header elements max payload is therefore 488 bytes */
-+#define MMAL_MSG_MAX_PAYLOAD 488
-+
-+#include "mmal-msg-common.h"
-+#include "mmal-msg-format.h"
-+#include "mmal-msg-port.h"
-+
-+enum mmal_msg_type {
-+ MMAL_MSG_TYPE_QUIT = 1,
-+ MMAL_MSG_TYPE_SERVICE_CLOSED,
-+ MMAL_MSG_TYPE_GET_VERSION,
-+ MMAL_MSG_TYPE_COMPONENT_CREATE,
-+ MMAL_MSG_TYPE_COMPONENT_DESTROY, /* 5 */
-+ MMAL_MSG_TYPE_COMPONENT_ENABLE,
-+ MMAL_MSG_TYPE_COMPONENT_DISABLE,
-+ MMAL_MSG_TYPE_PORT_INFO_GET,
-+ MMAL_MSG_TYPE_PORT_INFO_SET,
-+ MMAL_MSG_TYPE_PORT_ACTION, /* 10 */
-+ MMAL_MSG_TYPE_BUFFER_FROM_HOST,
-+ MMAL_MSG_TYPE_BUFFER_TO_HOST,
-+ MMAL_MSG_TYPE_GET_STATS,
-+ MMAL_MSG_TYPE_PORT_PARAMETER_SET,
-+ MMAL_MSG_TYPE_PORT_PARAMETER_GET, /* 15 */
-+ MMAL_MSG_TYPE_EVENT_TO_HOST,
-+ MMAL_MSG_TYPE_GET_CORE_STATS_FOR_PORT,
-+ MMAL_MSG_TYPE_OPAQUE_ALLOCATOR,
-+ MMAL_MSG_TYPE_CONSUME_MEM,
-+ MMAL_MSG_TYPE_LMK, /* 20 */
-+ MMAL_MSG_TYPE_OPAQUE_ALLOCATOR_DESC,
-+ MMAL_MSG_TYPE_DRM_GET_LHS32,
-+ MMAL_MSG_TYPE_DRM_GET_TIME,
-+ MMAL_MSG_TYPE_BUFFER_FROM_HOST_ZEROLEN,
-+ MMAL_MSG_TYPE_PORT_FLUSH, /* 25 */
-+ MMAL_MSG_TYPE_HOST_LOG,
-+ MMAL_MSG_TYPE_MSG_LAST
-+};
-+
-+/* port action request messages differ depending on the action type */
-+enum mmal_msg_port_action_type {
-+ MMAL_MSG_PORT_ACTION_TYPE_UNKNOWN = 0, /* Unkown action */
-+ MMAL_MSG_PORT_ACTION_TYPE_ENABLE, /* Enable a port */
-+ MMAL_MSG_PORT_ACTION_TYPE_DISABLE, /* Disable a port */
-+ MMAL_MSG_PORT_ACTION_TYPE_FLUSH, /* Flush a port */
-+ MMAL_MSG_PORT_ACTION_TYPE_CONNECT, /* Connect ports */
-+ MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT, /* Disconnect ports */
-+ MMAL_MSG_PORT_ACTION_TYPE_SET_REQUIREMENTS, /* Set buffer requirements*/
-+};
-+
-+struct mmal_msg_header {
-+ u32 magic;
-+ u32 type; /** enum mmal_msg_type */
-+
-+ /* Opaque handle to the control service */
-+ struct mmal_control_service *control_service;
-+
-+ struct mmal_msg_context *context; /** a u32 per message context */
-+ u32 status; /** The status of the vchiq operation */
-+ u32 padding;
-+};
-+
-+/* Send from VC to host to report version */
-+struct mmal_msg_version {
-+ u32 flags;
-+ u32 major;
-+ u32 minor;
-+ u32 minimum;
-+};
-+
-+/* request to VC to create component */
-+struct mmal_msg_component_create {
-+ void *client_component; /* component context */
-+ char name[128];
-+ u32 pid; /* For debug */
-+};
-+
-+/* reply from VC to component creation request */
-+struct mmal_msg_component_create_reply {
-+ u32 status; /** enum mmal_msg_status - how does this differ to
-+ * the one in the header?
-+ */
-+ u32 component_handle; /* VideoCore handle for component */
-+ u32 input_num; /* Number of input ports */
-+ u32 output_num; /* Number of output ports */
-+ u32 clock_num; /* Number of clock ports */
-+};
-+
-+/* request to VC to destroy a component */
-+struct mmal_msg_component_destroy {
-+ u32 component_handle;
-+};
-+
-+struct mmal_msg_component_destroy_reply {
-+ u32 status; /** The component destruction status */
-+};
-+
-+
-+/* request and reply to VC to enable a component */
-+struct mmal_msg_component_enable {
-+ u32 component_handle;
-+};
-+
-+struct mmal_msg_component_enable_reply {
-+ u32 status; /** The component enable status */
-+};
-+
-+
-+/* request and reply to VC to disable a component */
-+struct mmal_msg_component_disable {
-+ u32 component_handle;
-+};
-+
-+struct mmal_msg_component_disable_reply {
-+ u32 status; /** The component disable status */
-+};
-+
-+/* request to VC to get port information */
-+struct mmal_msg_port_info_get {
-+ u32 component_handle; /* component handle port is associated with */
-+ u32 port_type; /* enum mmal_msg_port_type */
-+ u32 index; /* port index to query */
-+};
-+
-+/* reply from VC to get port info request */
-+struct mmal_msg_port_info_get_reply {
-+ u32 status; /** enum mmal_msg_status */
-+ u32 component_handle; /* component handle port is associated with */
-+ u32 port_type; /* enum mmal_msg_port_type */
-+ u32 port_index; /* port indexed in query */
-+ s32 found; /* unused */
-+ u32 port_handle; /**< Handle to use for this port */
-+ struct mmal_port port;
-+ struct mmal_es_format format; /* elementry stream format */
-+ union mmal_es_specific_format es; /* es type specific data */
-+ u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE]; /* es extra data */
-+};
-+
-+/* request to VC to set port information */
-+struct mmal_msg_port_info_set {
-+ u32 component_handle;
-+ u32 port_type; /* enum mmal_msg_port_type */
-+ u32 port_index; /* port indexed in query */
-+ struct mmal_port port;
-+ struct mmal_es_format format;
-+ union mmal_es_specific_format es;
-+ u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE];
-+};
-+
-+/* reply from VC to port info set request */
-+struct mmal_msg_port_info_set_reply {
-+ u32 status;
-+ u32 component_handle; /* component handle port is associated with */
-+ u32 port_type; /* enum mmal_msg_port_type */
-+ u32 index; /* port indexed in query */
-+ s32 found; /* unused */
-+ u32 port_handle; /**< Handle to use for this port */
-+ struct mmal_port port;
-+ struct mmal_es_format format;
-+ union mmal_es_specific_format es;
-+ u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE];
-+};
-+
-+
-+/* port action requests that take a mmal_port as a parameter */
-+struct mmal_msg_port_action_port {
-+ u32 component_handle;
-+ u32 port_handle;
-+ u32 action; /* enum mmal_msg_port_action_type */
-+ struct mmal_port port;
-+};
-+
-+/* port action requests that take handles as a parameter */
-+struct mmal_msg_port_action_handle {
-+ u32 component_handle;
-+ u32 port_handle;
-+ u32 action; /* enum mmal_msg_port_action_type */
-+ u32 connect_component_handle;
-+ u32 connect_port_handle;
-+};
-+
-+struct mmal_msg_port_action_reply {
-+ u32 status; /** The port action operation status */
-+};
-+
-+
-+
-+
-+/* MMAL buffer transfer */
-+
-+/** Size of space reserved in a buffer message for short messages. */
-+#define MMAL_VC_SHORT_DATA 128
-+
-+/** Signals that the current payload is the end of the stream of data */
-+#define MMAL_BUFFER_HEADER_FLAG_EOS (1<<0)
-+/** Signals that the start of the current payload starts a frame */
-+#define MMAL_BUFFER_HEADER_FLAG_FRAME_START (1<<1)
-+/** Signals that the end of the current payload ends a frame */
-+#define MMAL_BUFFER_HEADER_FLAG_FRAME_END (1<<2)
-+/** Signals that the current payload contains only complete frames (>1) */
-+#define MMAL_BUFFER_HEADER_FLAG_FRAME \
-+ (MMAL_BUFFER_HEADER_FLAG_FRAME_START|MMAL_BUFFER_HEADER_FLAG_FRAME_END)
-+/** Signals that the current payload is a keyframe (i.e. self decodable) */
-+#define MMAL_BUFFER_HEADER_FLAG_KEYFRAME (1<<3)
-+/** Signals a discontinuity in the stream of data (e.g. after a seek).
-+ * Can be used for instance by a decoder to reset its state */
-+#define MMAL_BUFFER_HEADER_FLAG_DISCONTINUITY (1<<4)
-+/** Signals a buffer containing some kind of config data for the component
-+ * (e.g. codec config data) */
-+#define MMAL_BUFFER_HEADER_FLAG_CONFIG (1<<5)
-+/** Signals an encrypted payload */
-+#define MMAL_BUFFER_HEADER_FLAG_ENCRYPTED (1<<6)
-+/** Signals a buffer containing side information */
-+#define MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO (1<<7)
-+/** Signals a buffer which is the snapshot/postview image from a stills
-+ * capture
-+ */
-+#define MMAL_BUFFER_HEADER_FLAGS_SNAPSHOT (1<<8)
-+/** Signals a buffer which contains data known to be corrupted */
-+#define MMAL_BUFFER_HEADER_FLAG_CORRUPTED (1<<9)
-+/** Signals that a buffer failed to be transmitted */
-+#define MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED (1<<10)
-+
-+struct mmal_driver_buffer {
-+ u32 magic;
-+ u32 component_handle;
-+ u32 port_handle;
-+ void *client_context;
-+};
-+
-+/* buffer header */
-+struct mmal_buffer_header {
-+ struct mmal_buffer_header *next; /* next header */
-+ void *priv; /* framework private data */
-+ u32 cmd;
-+ void *data;
-+ u32 alloc_size;
-+ u32 length;
-+ u32 offset;
-+ u32 flags;
-+ s64 pts;
-+ s64 dts;
-+ void *type;
-+ void *user_data;
-+};
-+
-+struct mmal_buffer_header_type_specific {
-+ union {
-+ struct {
-+ u32 planes;
-+ u32 offset[4];
-+ u32 pitch[4];
-+ u32 flags;
-+ } video;
-+ } u;
-+};
-+
-+struct mmal_msg_buffer_from_host {
-+ /* The front 32 bytes of the buffer header are copied
-+ * back to us in the reply to allow for context. This
-+ * area is used to store two mmal_driver_buffer structures to
-+ * allow for multiple concurrent service users.
-+ */
-+ /* control data */
-+ struct mmal_driver_buffer drvbuf;
-+
-+ /* referenced control data for passthrough buffer management */
-+ struct mmal_driver_buffer drvbuf_ref;
-+ struct mmal_buffer_header buffer_header; /* buffer header itself */
-+ struct mmal_buffer_header_type_specific buffer_header_type_specific;
-+ s32 is_zero_copy;
-+ s32 has_reference;
-+
-+ /** allows short data to be xfered in control message */
-+ u32 payload_in_message;
-+ u8 short_data[MMAL_VC_SHORT_DATA];
-+};
-+
-+
-+/* port parameter setting */
-+
-+#define MMAL_WORKER_PORT_PARAMETER_SPACE 96
-+
-+struct mmal_msg_port_parameter_set {
-+ u32 component_handle; /* component */
-+ u32 port_handle; /* port */
-+ u32 id; /* Parameter ID */
-+ u32 size; /* Parameter size */
-+ uint32_t value[MMAL_WORKER_PORT_PARAMETER_SPACE];
-+};
-+
-+struct mmal_msg_port_parameter_set_reply {
-+ u32 status; /** enum mmal_msg_status todo: how does this
-+ * differ to the one in the header?
-+ */
-+};
-+
-+/* port parameter getting */
-+
-+struct mmal_msg_port_parameter_get {
-+ u32 component_handle; /* component */
-+ u32 port_handle; /* port */
-+ u32 id; /* Parameter ID */
-+ u32 size; /* Parameter size */
-+};
-+
-+struct mmal_msg_port_parameter_get_reply {
-+ u32 status; /* Status of mmal_port_parameter_get call */
-+ u32 id; /* Parameter ID */
-+ u32 size; /* Parameter size */
-+ uint32_t value[MMAL_WORKER_PORT_PARAMETER_SPACE];
-+};
-+
-+/* event messages */
-+#define MMAL_WORKER_EVENT_SPACE 256
-+
-+struct mmal_msg_event_to_host {
-+ void *client_component; /* component context */
-+
-+ u32 port_type;
-+ u32 port_num;
-+
-+ u32 cmd;
-+ u32 length;
-+ u8 data[MMAL_WORKER_EVENT_SPACE];
-+ struct mmal_buffer_header *delayed_buffer;
-+};
-+
-+/* all mmal messages are serialised through this structure */
-+struct mmal_msg {
-+ /* header */
-+ struct mmal_msg_header h;
-+ /* payload */
-+ union {
-+ struct mmal_msg_version version;
-+
-+ struct mmal_msg_component_create component_create;
-+ struct mmal_msg_component_create_reply component_create_reply;
-+
-+ struct mmal_msg_component_destroy component_destroy;
-+ struct mmal_msg_component_destroy_reply component_destroy_reply;
-+
-+ struct mmal_msg_component_enable component_enable;
-+ struct mmal_msg_component_enable_reply component_enable_reply;
-+
-+ struct mmal_msg_component_disable component_disable;
-+ struct mmal_msg_component_disable_reply component_disable_reply;
-+
-+ struct mmal_msg_port_info_get port_info_get;
-+ struct mmal_msg_port_info_get_reply port_info_get_reply;
-+
-+ struct mmal_msg_port_info_set port_info_set;
-+ struct mmal_msg_port_info_set_reply port_info_set_reply;
-+
-+ struct mmal_msg_port_action_port port_action_port;
-+ struct mmal_msg_port_action_handle port_action_handle;
-+ struct mmal_msg_port_action_reply port_action_reply;
-+
-+ struct mmal_msg_buffer_from_host buffer_from_host;
-+
-+ struct mmal_msg_port_parameter_set port_parameter_set;
-+ struct mmal_msg_port_parameter_set_reply
-+ port_parameter_set_reply;
-+ struct mmal_msg_port_parameter_get
-+ port_parameter_get;
-+ struct mmal_msg_port_parameter_get_reply
-+ port_parameter_get_reply;
-+
-+ struct mmal_msg_event_to_host event_to_host;
-+
-+ u8 payload[MMAL_MSG_MAX_PAYLOAD];
-+ } u;
-+};
---- /dev/null
-+++ b/drivers/media/platform/bcm2835/mmal-parameters.h
-@@ -0,0 +1,656 @@
-+/*
-+ * Broadcom BM2835 V4L2 driver
-+ *
-+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
-+ *
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file COPYING in the main directory of this archive
-+ * for more details.
-+ *
-+ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
-+ * Dave Stevenson <dsteve@broadcom.com>
-+ * Simon Mellor <simellor@broadcom.com>
-+ * Luke Diamand <luked@broadcom.com>
-+ */
-+
-+/* common parameters */
-+
-+/** @name Parameter groups
-+ * Parameters are divided into groups, and then allocated sequentially within
-+ * a group using an enum.
-+ * @{
-+ */
-+
-+/** Common parameter ID group, used with many types of component. */
-+#define MMAL_PARAMETER_GROUP_COMMON (0<<16)
-+/** Camera-specific parameter ID group. */
-+#define MMAL_PARAMETER_GROUP_CAMERA (1<<16)
-+/** Video-specific parameter ID group. */
-+#define MMAL_PARAMETER_GROUP_VIDEO (2<<16)
-+/** Audio-specific parameter ID group. */
-+#define MMAL_PARAMETER_GROUP_AUDIO (3<<16)
-+/** Clock-specific parameter ID group. */
-+#define MMAL_PARAMETER_GROUP_CLOCK (4<<16)
-+/** Miracast-specific parameter ID group. */
-+#define MMAL_PARAMETER_GROUP_MIRACAST (5<<16)
-+
-+/* Common parameters */
-+enum mmal_parameter_common_type {
-+ MMAL_PARAMETER_UNUSED /**< Never a valid parameter ID */
-+ = MMAL_PARAMETER_GROUP_COMMON,
-+ MMAL_PARAMETER_SUPPORTED_ENCODINGS, /**< MMAL_PARAMETER_ENCODING_T */
-+ MMAL_PARAMETER_URI, /**< MMAL_PARAMETER_URI_T */
-+
-+ /** MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T */
-+ MMAL_PARAMETER_CHANGE_EVENT_REQUEST,
-+
-+ /** MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_ZERO_COPY,
-+
-+ /**< MMAL_PARAMETER_BUFFER_REQUIREMENTS_T */
-+ MMAL_PARAMETER_BUFFER_REQUIREMENTS,
-+
-+ MMAL_PARAMETER_STATISTICS, /**< MMAL_PARAMETER_STATISTICS_T */
-+ MMAL_PARAMETER_CORE_STATISTICS, /**< MMAL_PARAMETER_CORE_STATISTICS_T */
-+ MMAL_PARAMETER_MEM_USAGE, /**< MMAL_PARAMETER_MEM_USAGE_T */
-+ MMAL_PARAMETER_BUFFER_FLAG_FILTER, /**< MMAL_PARAMETER_UINT32_T */
-+ MMAL_PARAMETER_SEEK, /**< MMAL_PARAMETER_SEEK_T */
-+ MMAL_PARAMETER_POWERMON_ENABLE, /**< MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_LOGGING, /**< MMAL_PARAMETER_LOGGING_T */
-+ MMAL_PARAMETER_SYSTEM_TIME, /**< MMAL_PARAMETER_UINT64_T */
-+ MMAL_PARAMETER_NO_IMAGE_PADDING /**< MMAL_PARAMETER_BOOLEAN_T */
-+};
-+
-+/* camera parameters */
-+
-+enum mmal_parameter_camera_type {
-+ /* 0 */
-+ /** @ref MMAL_PARAMETER_THUMBNAIL_CONFIG_T */
-+ MMAL_PARAMETER_THUMBNAIL_CONFIGURATION
-+ = MMAL_PARAMETER_GROUP_CAMERA,
-+ MMAL_PARAMETER_CAPTURE_QUALITY, /**< Unused? */
-+ MMAL_PARAMETER_ROTATION, /**< @ref MMAL_PARAMETER_INT32_T */
-+ MMAL_PARAMETER_EXIF_DISABLE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_EXIF, /**< @ref MMAL_PARAMETER_EXIF_T */
-+ MMAL_PARAMETER_AWB_MODE, /**< @ref MMAL_PARAM_AWBMODE_T */
-+ MMAL_PARAMETER_IMAGE_EFFECT, /**< @ref MMAL_PARAMETER_IMAGEFX_T */
-+ MMAL_PARAMETER_COLOUR_EFFECT, /**< @ref MMAL_PARAMETER_COLOURFX_T */
-+ MMAL_PARAMETER_FLICKER_AVOID, /**< @ref MMAL_PARAMETER_FLICKERAVOID_T */
-+ MMAL_PARAMETER_FLASH, /**< @ref MMAL_PARAMETER_FLASH_T */
-+ MMAL_PARAMETER_REDEYE, /**< @ref MMAL_PARAMETER_REDEYE_T */
-+ MMAL_PARAMETER_FOCUS, /**< @ref MMAL_PARAMETER_FOCUS_T */
-+ MMAL_PARAMETER_FOCAL_LENGTHS, /**< Unused? */
-+ MMAL_PARAMETER_EXPOSURE_COMP, /**< @ref MMAL_PARAMETER_INT32_T */
-+ MMAL_PARAMETER_ZOOM, /**< @ref MMAL_PARAMETER_SCALEFACTOR_T */
-+ MMAL_PARAMETER_MIRROR, /**< @ref MMAL_PARAMETER_MIRROR_T */
-+
-+ /* 0x10 */
-+ MMAL_PARAMETER_CAMERA_NUM, /**< @ref MMAL_PARAMETER_UINT32_T */
-+ MMAL_PARAMETER_CAPTURE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_EXPOSURE_MODE, /**< @ref MMAL_PARAMETER_EXPOSUREMODE_T */
-+ MMAL_PARAMETER_EXP_METERING_MODE, /**< @ref MMAL_PARAMETER_EXPOSUREMETERINGMODE_T */
-+ MMAL_PARAMETER_FOCUS_STATUS, /**< @ref MMAL_PARAMETER_FOCUS_STATUS_T */
-+ MMAL_PARAMETER_CAMERA_CONFIG, /**< @ref MMAL_PARAMETER_CAMERA_CONFIG_T */
-+ MMAL_PARAMETER_CAPTURE_STATUS, /**< @ref MMAL_PARAMETER_CAPTURE_STATUS_T */
-+ MMAL_PARAMETER_FACE_TRACK, /**< @ref MMAL_PARAMETER_FACE_TRACK_T */
-+ MMAL_PARAMETER_DRAW_BOX_FACES_AND_FOCUS, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_JPEG_Q_FACTOR, /**< @ref MMAL_PARAMETER_UINT32_T */
-+ MMAL_PARAMETER_FRAME_RATE, /**< @ref MMAL_PARAMETER_FRAME_RATE_T */
-+ MMAL_PARAMETER_USE_STC, /**< @ref MMAL_PARAMETER_CAMERA_STC_MODE_T */
-+ MMAL_PARAMETER_CAMERA_INFO, /**< @ref MMAL_PARAMETER_CAMERA_INFO_T */
-+ MMAL_PARAMETER_VIDEO_STABILISATION, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_FACE_TRACK_RESULTS, /**< @ref MMAL_PARAMETER_FACE_TRACK_RESULTS_T */
-+ MMAL_PARAMETER_ENABLE_RAW_CAPTURE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+
-+ /* 0x20 */
-+ MMAL_PARAMETER_DPF_FILE, /**< @ref MMAL_PARAMETER_URI_T */
-+ MMAL_PARAMETER_ENABLE_DPF_FILE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_DPF_FAIL_IS_FATAL, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_CAPTURE_MODE, /**< @ref MMAL_PARAMETER_CAPTUREMODE_T */
-+ MMAL_PARAMETER_FOCUS_REGIONS, /**< @ref MMAL_PARAMETER_FOCUS_REGIONS_T */
-+ MMAL_PARAMETER_INPUT_CROP, /**< @ref MMAL_PARAMETER_INPUT_CROP_T */
-+ MMAL_PARAMETER_SENSOR_INFORMATION, /**< @ref MMAL_PARAMETER_SENSOR_INFORMATION_T */
-+ MMAL_PARAMETER_FLASH_SELECT, /**< @ref MMAL_PARAMETER_FLASH_SELECT_T */
-+ MMAL_PARAMETER_FIELD_OF_VIEW, /**< @ref MMAL_PARAMETER_FIELD_OF_VIEW_T */
-+ MMAL_PARAMETER_HIGH_DYNAMIC_RANGE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_DYNAMIC_RANGE_COMPRESSION, /**< @ref MMAL_PARAMETER_DRC_T */
-+ MMAL_PARAMETER_ALGORITHM_CONTROL, /**< @ref MMAL_PARAMETER_ALGORITHM_CONTROL_T */
-+ MMAL_PARAMETER_SHARPNESS, /**< @ref MMAL_PARAMETER_RATIONAL_T */
-+ MMAL_PARAMETER_CONTRAST, /**< @ref MMAL_PARAMETER_RATIONAL_T */
-+ MMAL_PARAMETER_BRIGHTNESS, /**< @ref MMAL_PARAMETER_RATIONAL_T */
-+ MMAL_PARAMETER_SATURATION, /**< @ref MMAL_PARAMETER_RATIONAL_T */
-+
-+ /* 0x30 */
-+ MMAL_PARAMETER_ISO, /**< @ref MMAL_PARAMETER_UINT32_T */
-+ MMAL_PARAMETER_ANTISHAKE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+
-+ /** @ref MMAL_PARAMETER_IMAGEFX_PARAMETERS_T */
-+ MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS,
-+
-+ /** @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_CAMERA_BURST_CAPTURE,
-+
-+ /** @ref MMAL_PARAMETER_UINT32_T */
-+ MMAL_PARAMETER_CAMERA_MIN_ISO,
-+
-+ /** @ref MMAL_PARAMETER_CAMERA_USE_CASE_T */
-+ MMAL_PARAMETER_CAMERA_USE_CASE,
-+
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_CAPTURE_STATS_PASS,
-+
-+ /** @ref MMAL_PARAMETER_UINT32_T */
-+ MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG,
-+
-+ /** @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_ENABLE_REGISTER_FILE,
-+
-+ /** @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_REGISTER_FAIL_IS_FATAL,
-+
-+ /** @ref MMAL_PARAMETER_CONFIGFILE_T */
-+ MMAL_PARAMETER_CONFIGFILE_REGISTERS,
-+
-+ /** @ref MMAL_PARAMETER_CONFIGFILE_CHUNK_T */
-+ MMAL_PARAMETER_CONFIGFILE_CHUNK_REGISTERS,
-+ MMAL_PARAMETER_JPEG_ATTACH_LOG, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_ZERO_SHUTTER_LAG, /**< @ref MMAL_PARAMETER_ZEROSHUTTERLAG_T */
-+ MMAL_PARAMETER_FPS_RANGE, /**< @ref MMAL_PARAMETER_FPS_RANGE_T */
-+ MMAL_PARAMETER_CAPTURE_EXPOSURE_COMP, /**< @ref MMAL_PARAMETER_INT32_T */
-+
-+ /* 0x40 */
-+ MMAL_PARAMETER_SW_SHARPEN_DISABLE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_FLASH_REQUIRED, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_SW_SATURATION_DISABLE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_SHUTTER_SPEED, /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
-+ MMAL_PARAMETER_CUSTOM_AWB_GAINS, /**< Takes a @ref MMAL_PARAMETER_AWB_GAINS_T */
-+};
-+
-+struct mmal_parameter_rational {
-+ s32 num; /**< Numerator */
-+ s32 den; /**< Denominator */
-+};
-+
-+enum mmal_parameter_camera_config_timestamp_mode {
-+ MMAL_PARAM_TIMESTAMP_MODE_ZERO = 0, /* Always timestamp frames as 0 */
-+ MMAL_PARAM_TIMESTAMP_MODE_RAW_STC, /* Use the raw STC value
-+ * for the frame timestamp
-+ */
-+ MMAL_PARAM_TIMESTAMP_MODE_RESET_STC, /* Use the STC timestamp
-+ * but subtract the
-+ * timestamp of the first
-+ * frame sent to give a
-+ * zero based timestamp.
-+ */
-+};
-+
-+struct mmal_parameter_fps_range {
-+ /**< Low end of the permitted framerate range */
-+ struct mmal_parameter_rational fps_low;
-+ /**< High end of the permitted framerate range */
-+ struct mmal_parameter_rational fps_high;
-+};
-+
-+
-+/* camera configuration parameter */
-+struct mmal_parameter_camera_config {
-+ /* Parameters for setting up the image pools */
-+ u32 max_stills_w; /* Max size of stills capture */
-+ u32 max_stills_h;
-+ u32 stills_yuv422; /* Allow YUV422 stills capture */
-+ u32 one_shot_stills; /* Continuous or one shot stills captures. */
-+
-+ u32 max_preview_video_w; /* Max size of the preview or video
-+ * capture frames
-+ */
-+ u32 max_preview_video_h;
-+ u32 num_preview_video_frames;
-+
-+ /** Sets the height of the circular buffer for stills capture. */
-+ u32 stills_capture_circular_buffer_height;
-+
-+ /** Allows preview/encode to resume as fast as possible after the stills
-+ * input frame has been received, and then processes the still frame in
-+ * the background whilst preview/encode has resumed.
-+ * Actual mode is controlled by MMAL_PARAMETER_CAPTURE_MODE.
-+ */
-+ u32 fast_preview_resume;
-+
-+ /** Selects algorithm for timestamping frames if
-+ * there is no clock component connected.
-+ * enum mmal_parameter_camera_config_timestamp_mode
-+ */
-+ s32 use_stc_timestamp;
-+};
-+
-+
-+enum mmal_parameter_exposuremode {
-+ MMAL_PARAM_EXPOSUREMODE_OFF,
-+ MMAL_PARAM_EXPOSUREMODE_AUTO,
-+ MMAL_PARAM_EXPOSUREMODE_NIGHT,
-+ MMAL_PARAM_EXPOSUREMODE_NIGHTPREVIEW,
-+ MMAL_PARAM_EXPOSUREMODE_BACKLIGHT,
-+ MMAL_PARAM_EXPOSUREMODE_SPOTLIGHT,
-+ MMAL_PARAM_EXPOSUREMODE_SPORTS,
-+ MMAL_PARAM_EXPOSUREMODE_SNOW,
-+ MMAL_PARAM_EXPOSUREMODE_BEACH,
-+ MMAL_PARAM_EXPOSUREMODE_VERYLONG,
-+ MMAL_PARAM_EXPOSUREMODE_FIXEDFPS,
-+ MMAL_PARAM_EXPOSUREMODE_ANTISHAKE,
-+ MMAL_PARAM_EXPOSUREMODE_FIREWORKS,
-+};
-+
-+enum mmal_parameter_exposuremeteringmode {
-+ MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE,
-+ MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT,
-+ MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT,
-+ MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX,
-+};
-+
-+enum mmal_parameter_awbmode {
-+ MMAL_PARAM_AWBMODE_OFF,
-+ MMAL_PARAM_AWBMODE_AUTO,
-+ MMAL_PARAM_AWBMODE_SUNLIGHT,
-+ MMAL_PARAM_AWBMODE_CLOUDY,
-+ MMAL_PARAM_AWBMODE_SHADE,
-+ MMAL_PARAM_AWBMODE_TUNGSTEN,
-+ MMAL_PARAM_AWBMODE_FLUORESCENT,
-+ MMAL_PARAM_AWBMODE_INCANDESCENT,
-+ MMAL_PARAM_AWBMODE_FLASH,
-+ MMAL_PARAM_AWBMODE_HORIZON,
-+};
-+
-+enum mmal_parameter_imagefx {
-+ MMAL_PARAM_IMAGEFX_NONE,
-+ MMAL_PARAM_IMAGEFX_NEGATIVE,
-+ MMAL_PARAM_IMAGEFX_SOLARIZE,
-+ MMAL_PARAM_IMAGEFX_POSTERIZE,
-+ MMAL_PARAM_IMAGEFX_WHITEBOARD,
-+ MMAL_PARAM_IMAGEFX_BLACKBOARD,
-+ MMAL_PARAM_IMAGEFX_SKETCH,
-+ MMAL_PARAM_IMAGEFX_DENOISE,
-+ MMAL_PARAM_IMAGEFX_EMBOSS,
-+ MMAL_PARAM_IMAGEFX_OILPAINT,
-+ MMAL_PARAM_IMAGEFX_HATCH,
-+ MMAL_PARAM_IMAGEFX_GPEN,
-+ MMAL_PARAM_IMAGEFX_PASTEL,
-+ MMAL_PARAM_IMAGEFX_WATERCOLOUR,
-+ MMAL_PARAM_IMAGEFX_FILM,
-+ MMAL_PARAM_IMAGEFX_BLUR,
-+ MMAL_PARAM_IMAGEFX_SATURATION,
-+ MMAL_PARAM_IMAGEFX_COLOURSWAP,
-+ MMAL_PARAM_IMAGEFX_WASHEDOUT,
-+ MMAL_PARAM_IMAGEFX_POSTERISE,
-+ MMAL_PARAM_IMAGEFX_COLOURPOINT,
-+ MMAL_PARAM_IMAGEFX_COLOURBALANCE,
-+ MMAL_PARAM_IMAGEFX_CARTOON,
-+};
-+
-+enum MMAL_PARAM_FLICKERAVOID_T {
-+ MMAL_PARAM_FLICKERAVOID_OFF,
-+ MMAL_PARAM_FLICKERAVOID_AUTO,
-+ MMAL_PARAM_FLICKERAVOID_50HZ,
-+ MMAL_PARAM_FLICKERAVOID_60HZ,
-+ MMAL_PARAM_FLICKERAVOID_MAX = 0x7FFFFFFF
-+};
-+
-+struct mmal_parameter_awbgains {
-+ struct mmal_parameter_rational r_gain; /**< Red gain */
-+ struct mmal_parameter_rational b_gain; /**< Blue gain */
-+};
-+
-+/** Manner of video rate control */
-+enum mmal_parameter_rate_control_mode {
-+ MMAL_VIDEO_RATECONTROL_DEFAULT,
-+ MMAL_VIDEO_RATECONTROL_VARIABLE,
-+ MMAL_VIDEO_RATECONTROL_CONSTANT,
-+ MMAL_VIDEO_RATECONTROL_VARIABLE_SKIP_FRAMES,
-+ MMAL_VIDEO_RATECONTROL_CONSTANT_SKIP_FRAMES
-+};
-+
-+enum mmal_video_profile {
-+ MMAL_VIDEO_PROFILE_H263_BASELINE,
-+ MMAL_VIDEO_PROFILE_H263_H320CODING,
-+ MMAL_VIDEO_PROFILE_H263_BACKWARDCOMPATIBLE,
-+ MMAL_VIDEO_PROFILE_H263_ISWV2,
-+ MMAL_VIDEO_PROFILE_H263_ISWV3,
-+ MMAL_VIDEO_PROFILE_H263_HIGHCOMPRESSION,
-+ MMAL_VIDEO_PROFILE_H263_INTERNET,
-+ MMAL_VIDEO_PROFILE_H263_INTERLACE,
-+ MMAL_VIDEO_PROFILE_H263_HIGHLATENCY,
-+ MMAL_VIDEO_PROFILE_MP4V_SIMPLE,
-+ MMAL_VIDEO_PROFILE_MP4V_SIMPLESCALABLE,
-+ MMAL_VIDEO_PROFILE_MP4V_CORE,
-+ MMAL_VIDEO_PROFILE_MP4V_MAIN,
-+ MMAL_VIDEO_PROFILE_MP4V_NBIT,
-+ MMAL_VIDEO_PROFILE_MP4V_SCALABLETEXTURE,
-+ MMAL_VIDEO_PROFILE_MP4V_SIMPLEFACE,
-+ MMAL_VIDEO_PROFILE_MP4V_SIMPLEFBA,
-+ MMAL_VIDEO_PROFILE_MP4V_BASICANIMATED,
-+ MMAL_VIDEO_PROFILE_MP4V_HYBRID,
-+ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDREALTIME,
-+ MMAL_VIDEO_PROFILE_MP4V_CORESCALABLE,
-+ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDCODING,
-+ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDCORE,
-+ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDSCALABLE,
-+ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDSIMPLE,
-+ MMAL_VIDEO_PROFILE_H264_BASELINE,
-+ MMAL_VIDEO_PROFILE_H264_MAIN,
-+ MMAL_VIDEO_PROFILE_H264_EXTENDED,
-+ MMAL_VIDEO_PROFILE_H264_HIGH,
-+ MMAL_VIDEO_PROFILE_H264_HIGH10,
-+ MMAL_VIDEO_PROFILE_H264_HIGH422,
-+ MMAL_VIDEO_PROFILE_H264_HIGH444,
-+ MMAL_VIDEO_PROFILE_H264_CONSTRAINED_BASELINE,
-+ MMAL_VIDEO_PROFILE_DUMMY = 0x7FFFFFFF
-+};
-+
-+enum mmal_video_level {
-+ MMAL_VIDEO_LEVEL_H263_10,
-+ MMAL_VIDEO_LEVEL_H263_20,
-+ MMAL_VIDEO_LEVEL_H263_30,
-+ MMAL_VIDEO_LEVEL_H263_40,
-+ MMAL_VIDEO_LEVEL_H263_45,
-+ MMAL_VIDEO_LEVEL_H263_50,
-+ MMAL_VIDEO_LEVEL_H263_60,
-+ MMAL_VIDEO_LEVEL_H263_70,
-+ MMAL_VIDEO_LEVEL_MP4V_0,
-+ MMAL_VIDEO_LEVEL_MP4V_0b,
-+ MMAL_VIDEO_LEVEL_MP4V_1,
-+ MMAL_VIDEO_LEVEL_MP4V_2,
-+ MMAL_VIDEO_LEVEL_MP4V_3,
-+ MMAL_VIDEO_LEVEL_MP4V_4,
-+ MMAL_VIDEO_LEVEL_MP4V_4a,
-+ MMAL_VIDEO_LEVEL_MP4V_5,
-+ MMAL_VIDEO_LEVEL_MP4V_6,
-+ MMAL_VIDEO_LEVEL_H264_1,
-+ MMAL_VIDEO_LEVEL_H264_1b,
-+ MMAL_VIDEO_LEVEL_H264_11,
-+ MMAL_VIDEO_LEVEL_H264_12,
-+ MMAL_VIDEO_LEVEL_H264_13,
-+ MMAL_VIDEO_LEVEL_H264_2,
-+ MMAL_VIDEO_LEVEL_H264_21,
-+ MMAL_VIDEO_LEVEL_H264_22,
-+ MMAL_VIDEO_LEVEL_H264_3,
-+ MMAL_VIDEO_LEVEL_H264_31,
-+ MMAL_VIDEO_LEVEL_H264_32,
-+ MMAL_VIDEO_LEVEL_H264_4,
-+ MMAL_VIDEO_LEVEL_H264_41,
-+ MMAL_VIDEO_LEVEL_H264_42,
-+ MMAL_VIDEO_LEVEL_H264_5,
-+ MMAL_VIDEO_LEVEL_H264_51,
-+ MMAL_VIDEO_LEVEL_DUMMY = 0x7FFFFFFF
-+};
-+
-+struct mmal_parameter_video_profile {
-+ enum mmal_video_profile profile;
-+ enum mmal_video_level level;
-+};
-+
-+/* video parameters */
-+
-+enum mmal_parameter_video_type {
-+ /** @ref MMAL_DISPLAYREGION_T */
-+ MMAL_PARAMETER_DISPLAYREGION = MMAL_PARAMETER_GROUP_VIDEO,
-+
-+ /** @ref MMAL_PARAMETER_VIDEO_PROFILE_T */
-+ MMAL_PARAMETER_SUPPORTED_PROFILES,
-+
-+ /** @ref MMAL_PARAMETER_VIDEO_PROFILE_T */
-+ MMAL_PARAMETER_PROFILE,
-+
-+ /** @ref MMAL_PARAMETER_UINT32_T */
-+ MMAL_PARAMETER_INTRAPERIOD,
-+
-+ /** @ref MMAL_PARAMETER_VIDEO_RATECONTROL_T */
-+ MMAL_PARAMETER_RATECONTROL,
-+
-+ /** @ref MMAL_PARAMETER_VIDEO_NALUNITFORMAT_T */
-+ MMAL_PARAMETER_NALUNITFORMAT,
-+
-+ /** @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_MINIMISE_FRAGMENTATION,
-+
-+ /** @ref MMAL_PARAMETER_UINT32_T.
-+ * Setting the value to zero resets to the default (one slice per frame).
-+ */
-+ MMAL_PARAMETER_MB_ROWS_PER_SLICE,
-+
-+ /** @ref MMAL_PARAMETER_VIDEO_LEVEL_EXTENSION_T */
-+ MMAL_PARAMETER_VIDEO_LEVEL_EXTENSION,
-+
-+ /** @ref MMAL_PARAMETER_VIDEO_EEDE_ENABLE_T */
-+ MMAL_PARAMETER_VIDEO_EEDE_ENABLE,
-+
-+ /** @ref MMAL_PARAMETER_VIDEO_EEDE_LOSSRATE_T */
-+ MMAL_PARAMETER_VIDEO_EEDE_LOSSRATE,
-+
-+ /** @ref MMAL_PARAMETER_BOOLEAN_T. Request an I-frame. */
-+ MMAL_PARAMETER_VIDEO_REQUEST_I_FRAME,
-+ /** @ref MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T */
-+ MMAL_PARAMETER_VIDEO_INTRA_REFRESH,
-+
-+ /** @ref MMAL_PARAMETER_BOOLEAN_T. */
-+ MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT,
-+
-+ /** @ref MMAL_PARAMETER_UINT32_T. Run-time bit rate control */
-+ MMAL_PARAMETER_VIDEO_BIT_RATE,
-+
-+ /** @ref MMAL_PARAMETER_FRAME_RATE_T */
-+ MMAL_PARAMETER_VIDEO_FRAME_RATE,
-+
-+ /** @ref MMAL_PARAMETER_UINT32_T. */
-+ MMAL_PARAMETER_VIDEO_ENCODE_MIN_QUANT,
-+
-+ /** @ref MMAL_PARAMETER_UINT32_T. */
-+ MMAL_PARAMETER_VIDEO_ENCODE_MAX_QUANT,
-+
-+ /** @ref MMAL_PARAMETER_VIDEO_ENCODE_RC_MODEL_T. */
-+ MMAL_PARAMETER_VIDEO_ENCODE_RC_MODEL,
-+
-+ MMAL_PARAMETER_EXTRA_BUFFERS, /**< @ref MMAL_PARAMETER_UINT32_T. */
-+ /** @ref MMAL_PARAMETER_UINT32_T.
-+ * Changing this parameter from the default can reduce frame rate
-+ * because image buffers need to be re-pitched.
-+ */
-+ MMAL_PARAMETER_VIDEO_ALIGN_HORIZ,
-+
-+ /** @ref MMAL_PARAMETER_UINT32_T.
-+ * Changing this parameter from the default can reduce frame rate
-+ * because image buffers need to be re-pitched.
-+ */
-+ MMAL_PARAMETER_VIDEO_ALIGN_VERT,
-+
-+ /** @ref MMAL_PARAMETER_BOOLEAN_T. */
-+ MMAL_PARAMETER_VIDEO_DROPPABLE_PFRAMES,
-+
-+ /** @ref MMAL_PARAMETER_UINT32_T. */
-+ MMAL_PARAMETER_VIDEO_ENCODE_INITIAL_QUANT,
-+
-+ /**< @ref MMAL_PARAMETER_UINT32_T. */
-+ MMAL_PARAMETER_VIDEO_ENCODE_QP_P,
-+
-+ /**< @ref MMAL_PARAMETER_UINT32_T. */
-+ MMAL_PARAMETER_VIDEO_ENCODE_RC_SLICE_DQUANT,
-+
-+ /** @ref MMAL_PARAMETER_UINT32_T */
-+ MMAL_PARAMETER_VIDEO_ENCODE_FRAME_LIMIT_BITS,
-+
-+ /** @ref MMAL_PARAMETER_UINT32_T. */
-+ MMAL_PARAMETER_VIDEO_ENCODE_PEAK_RATE,
-+
-+ /* H264 specific parameters */
-+
-+ /** @ref MMAL_PARAMETER_BOOLEAN_T. */
-+ MMAL_PARAMETER_VIDEO_ENCODE_H264_DISABLE_CABAC,
-+
-+ /** @ref MMAL_PARAMETER_BOOLEAN_T. */
-+ MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_LATENCY,
-+
-+ /** @ref MMAL_PARAMETER_BOOLEAN_T. */
-+ MMAL_PARAMETER_VIDEO_ENCODE_H264_AU_DELIMITERS,
-+
-+ /** @ref MMAL_PARAMETER_UINT32_T. */
-+ MMAL_PARAMETER_VIDEO_ENCODE_H264_DEBLOCK_IDC,
-+
-+ /** @ref MMAL_PARAMETER_VIDEO_ENCODER_H264_MB_INTRA_MODES_T. */
-+ MMAL_PARAMETER_VIDEO_ENCODE_H264_MB_INTRA_MODE,
-+
-+ /** @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_VIDEO_ENCODE_HEADER_ON_OPEN,
-+
-+ /** @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_VIDEO_ENCODE_PRECODE_FOR_QP,
-+
-+ /** @ref MMAL_PARAMETER_VIDEO_DRM_INIT_INFO_T. */
-+ MMAL_PARAMETER_VIDEO_DRM_INIT_INFO,
-+
-+ /** @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_VIDEO_TIMESTAMP_FIFO,
-+
-+ /** @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_VIDEO_DECODE_ERROR_CONCEALMENT,
-+
-+ /** @ref MMAL_PARAMETER_VIDEO_DRM_PROTECT_BUFFER_T. */
-+ MMAL_PARAMETER_VIDEO_DRM_PROTECT_BUFFER,
-+
-+ /** @ref MMAL_PARAMETER_BYTES_T */
-+ MMAL_PARAMETER_VIDEO_DECODE_CONFIG_VD3,
-+
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_VIDEO_ENCODE_H264_VCL_HRD_PARAMETERS,
-+
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_DELAY_HRD_FLAG,
-+
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER
-+};
-+
-+/** Valid mirror modes */
-+enum mmal_parameter_mirror {
-+ MMAL_PARAM_MIRROR_NONE,
-+ MMAL_PARAM_MIRROR_VERTICAL,
-+ MMAL_PARAM_MIRROR_HORIZONTAL,
-+ MMAL_PARAM_MIRROR_BOTH,
-+};
-+
-+enum mmal_parameter_displaytransform {
-+ MMAL_DISPLAY_ROT0 = 0,
-+ MMAL_DISPLAY_MIRROR_ROT0 = 1,
-+ MMAL_DISPLAY_MIRROR_ROT180 = 2,
-+ MMAL_DISPLAY_ROT180 = 3,
-+ MMAL_DISPLAY_MIRROR_ROT90 = 4,
-+ MMAL_DISPLAY_ROT270 = 5,
-+ MMAL_DISPLAY_ROT90 = 6,
-+ MMAL_DISPLAY_MIRROR_ROT270 = 7,
-+};
-+
-+enum mmal_parameter_displaymode {
-+ MMAL_DISPLAY_MODE_FILL = 0,
-+ MMAL_DISPLAY_MODE_LETTERBOX = 1,
-+};
-+
-+enum mmal_parameter_displayset {
-+ MMAL_DISPLAY_SET_NONE = 0,
-+ MMAL_DISPLAY_SET_NUM = 1,
-+ MMAL_DISPLAY_SET_FULLSCREEN = 2,
-+ MMAL_DISPLAY_SET_TRANSFORM = 4,
-+ MMAL_DISPLAY_SET_DEST_RECT = 8,
-+ MMAL_DISPLAY_SET_SRC_RECT = 0x10,
-+ MMAL_DISPLAY_SET_MODE = 0x20,
-+ MMAL_DISPLAY_SET_PIXEL = 0x40,
-+ MMAL_DISPLAY_SET_NOASPECT = 0x80,
-+ MMAL_DISPLAY_SET_LAYER = 0x100,
-+ MMAL_DISPLAY_SET_COPYPROTECT = 0x200,
-+ MMAL_DISPLAY_SET_ALPHA = 0x400,
-+};
-+
-+struct mmal_parameter_displayregion {
-+ /** Bitfield that indicates which fields are set and should be
-+ * used. All other fields will maintain their current value.
-+ * \ref MMAL_DISPLAYSET_T defines the bits that can be
-+ * combined.
-+ */
-+ u32 set;
-+
-+ /** Describes the display output device, with 0 typically
-+ * being a directly connected LCD display. The actual values
-+ * will depend on the hardware. Code using hard-wired numbers
-+ * (e.g. 2) is certain to fail.
-+ */
-+
-+ u32 display_num;
-+ /** Indicates that we are using the full device screen area,
-+ * rather than a window of the display. If zero, then
-+ * dest_rect is used to specify a region of the display to
-+ * use.
-+ */
-+
-+ s32 fullscreen;
-+ /** Indicates any rotation or flipping used to map frames onto
-+ * the natural display orientation.
-+ */
-+ u32 transform; /* enum mmal_parameter_displaytransform */
-+
-+ /** Where to display the frame within the screen, if
-+ * fullscreen is zero.
-+ */
-+ struct vchiq_mmal_rect dest_rect;
-+
-+ /** Indicates which area of the frame to display. If all
-+ * values are zero, the whole frame will be used.
-+ */
-+ struct vchiq_mmal_rect src_rect;
-+
-+ /** If set to non-zero, indicates that any display scaling
-+ * should disregard the aspect ratio of the frame region being
-+ * displayed.
-+ */
-+ s32 noaspect;
-+
-+ /** Indicates how the image should be scaled to fit the
-+ * display. \code MMAL_DISPLAY_MODE_FILL \endcode indicates
-+ * that the image should fill the screen by potentially
-+ * cropping the frames. Setting \code mode \endcode to \code
-+ * MMAL_DISPLAY_MODE_LETTERBOX \endcode indicates that all the
-+ * source region should be displayed and black bars added if
-+ * necessary.
-+ */
-+ u32 mode; /* enum mmal_parameter_displaymode */
-+
-+ /** If non-zero, defines the width of a source pixel relative
-+ * to \code pixel_y \endcode. If zero, then pixels default to
-+ * being square.
-+ */
-+ u32 pixel_x;
-+
-+ /** If non-zero, defines the height of a source pixel relative
-+ * to \code pixel_x \endcode. If zero, then pixels default to
-+ * being square.
-+ */
-+ u32 pixel_y;
-+
-+ /** Sets the relative depth of the images, with greater values
-+ * being in front of smaller values.
-+ */
-+ u32 layer;
-+
-+ /** Set to non-zero to ensure copy protection is used on
-+ * output.
-+ */
-+ s32 copyprotect_required;
-+
-+ /** Level of opacity of the layer, where zero is fully
-+ * transparent and 255 is fully opaque.
-+ */
-+ u32 alpha;
-+};
-+
-+#define MMAL_MAX_IMAGEFX_PARAMETERS 5
-+
-+struct mmal_parameter_imagefx_parameters {
-+ enum mmal_parameter_imagefx effect;
-+ u32 num_effect_params;
-+ u32 effect_parameter[MMAL_MAX_IMAGEFX_PARAMETERS];
-+};
---- /dev/null
-+++ b/drivers/media/platform/bcm2835/mmal-vchiq.c
-@@ -0,0 +1,1916 @@
-+/*
-+ * Broadcom BM2835 V4L2 driver
-+ *
-+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
-+ *
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file COPYING in the main directory of this archive
-+ * for more details.
-+ *
-+ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
-+ * Dave Stevenson <dsteve@broadcom.com>
-+ * Simon Mellor <simellor@broadcom.com>
-+ * Luke Diamand <luked@broadcom.com>
-+ *
-+ * V4L2 driver MMAL vchiq interface code
-+ */
-+
-+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-+
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/mutex.h>
-+#include <linux/mm.h>
-+#include <linux/slab.h>
-+#include <linux/completion.h>
-+#include <linux/vmalloc.h>
-+#include <asm/cacheflush.h>
-+#include <media/videobuf2-vmalloc.h>
-+
-+#include "mmal-common.h"
-+#include "mmal-vchiq.h"
-+#include "mmal-msg.h"
-+
-+#define USE_VCHIQ_ARM
-+#include "interface/vchi/vchi.h"
-+
-+/* maximum number of components supported */
-+#define VCHIQ_MMAL_MAX_COMPONENTS 4
-+
-+/*#define FULL_MSG_DUMP 1*/
-+
-+#ifdef DEBUG
-+static const char *const msg_type_names[] = {
-+ "UNKNOWN",
-+ "QUIT",
-+ "SERVICE_CLOSED",
-+ "GET_VERSION",
-+ "COMPONENT_CREATE",
-+ "COMPONENT_DESTROY",
-+ "COMPONENT_ENABLE",
-+ "COMPONENT_DISABLE",
-+ "PORT_INFO_GET",
-+ "PORT_INFO_SET",
-+ "PORT_ACTION",
-+ "BUFFER_FROM_HOST",
-+ "BUFFER_TO_HOST",
-+ "GET_STATS",
-+ "PORT_PARAMETER_SET",
-+ "PORT_PARAMETER_GET",
-+ "EVENT_TO_HOST",
-+ "GET_CORE_STATS_FOR_PORT",
-+ "OPAQUE_ALLOCATOR",
-+ "CONSUME_MEM",
-+ "LMK",
-+ "OPAQUE_ALLOCATOR_DESC",
-+ "DRM_GET_LHS32",
-+ "DRM_GET_TIME",
-+ "BUFFER_FROM_HOST_ZEROLEN",
-+ "PORT_FLUSH",
-+ "HOST_LOG",
-+};
-+#endif
-+
-+static const char *const port_action_type_names[] = {
-+ "UNKNOWN",
-+ "ENABLE",
-+ "DISABLE",
-+ "FLUSH",
-+ "CONNECT",
-+ "DISCONNECT",
-+ "SET_REQUIREMENTS",
-+};
-+
-+#if defined(DEBUG)
-+#if defined(FULL_MSG_DUMP)
-+#define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE) \
-+ do { \
-+ pr_debug(TITLE" type:%s(%d) length:%d\n", \
-+ msg_type_names[(MSG)->h.type], \
-+ (MSG)->h.type, (MSG_LEN)); \
-+ print_hex_dump(KERN_DEBUG, "<<h: ", DUMP_PREFIX_OFFSET, \
-+ 16, 4, (MSG), \
-+ sizeof(struct mmal_msg_header), 1); \
-+ print_hex_dump(KERN_DEBUG, "<<p: ", DUMP_PREFIX_OFFSET, \
-+ 16, 4, \
-+ ((u8 *)(MSG)) + sizeof(struct mmal_msg_header),\
-+ (MSG_LEN) - sizeof(struct mmal_msg_header), 1); \
-+ } while (0)
-+#else
-+#define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE) \
-+ { \
-+ pr_debug(TITLE" type:%s(%d) length:%d\n", \
-+ msg_type_names[(MSG)->h.type], \
-+ (MSG)->h.type, (MSG_LEN)); \
-+ }
-+#endif
-+#else
-+#define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE)
-+#endif
-+
-+/* normal message context */
-+struct mmal_msg_context {
-+ union {
-+ struct {
-+ /* work struct for defered callback - must come first */
-+ struct work_struct work;
-+ /* mmal instance */
-+ struct vchiq_mmal_instance *instance;
-+ /* mmal port */
-+ struct vchiq_mmal_port *port;
-+ /* actual buffer used to store bulk reply */
-+ struct mmal_buffer *buffer;
-+ /* amount of buffer used */
-+ unsigned long buffer_used;
-+ /* MMAL buffer flags */
-+ u32 mmal_flags;
-+ /* Presentation and Decode timestamps */
-+ s64 pts;
-+ s64 dts;
-+
-+ int status; /* context status */
-+
-+ } bulk; /* bulk data */
-+
-+ struct {
-+ /* message handle to release */
-+ VCHI_HELD_MSG_T msg_handle;
-+ /* pointer to received message */
-+ struct mmal_msg *msg;
-+ /* received message length */
-+ u32 msg_len;
-+ /* completion upon reply */
-+ struct completion cmplt;
-+ } sync; /* synchronous response */
-+ } u;
-+
-+};
-+
-+struct vchiq_mmal_instance {
-+ VCHI_SERVICE_HANDLE_T handle;
-+
-+ /* ensure serialised access to service */
-+ struct mutex vchiq_mutex;
-+
-+ /* ensure serialised access to bulk operations */
-+ struct mutex bulk_mutex;
-+
-+ /* vmalloc page to receive scratch bulk xfers into */
-+ void *bulk_scratch;
-+
-+ /* component to use next */
-+ int component_idx;
-+ struct vchiq_mmal_component component[VCHIQ_MMAL_MAX_COMPONENTS];
-+};
-+
-+static struct mmal_msg_context *get_msg_context(struct vchiq_mmal_instance
-+ *instance)
-+{
-+ struct mmal_msg_context *msg_context;
-+
-+ /* todo: should this be allocated from a pool to avoid kmalloc */
-+ msg_context = kmalloc(sizeof(*msg_context), GFP_KERNEL);
-+ memset(msg_context, 0, sizeof(*msg_context));
-+
-+ return msg_context;
-+}
-+
-+static void release_msg_context(struct mmal_msg_context *msg_context)
-+{
-+ kfree(msg_context);
-+}
-+
-+/* deals with receipt of event to host message */
-+static void event_to_host_cb(struct vchiq_mmal_instance *instance,
-+ struct mmal_msg *msg, u32 msg_len)
-+{
-+ pr_debug("unhandled event\n");
-+ pr_debug("component:%p port type:%d num:%d cmd:0x%x length:%d\n",
-+ msg->u.event_to_host.client_component,
-+ msg->u.event_to_host.port_type,
-+ msg->u.event_to_host.port_num,
-+ msg->u.event_to_host.cmd, msg->u.event_to_host.length);
-+}
-+
-+/* workqueue scheduled callback
-+ *
-+ * we do this because it is important we do not call any other vchiq
-+ * sync calls from witin the message delivery thread
-+ */
-+static void buffer_work_cb(struct work_struct *work)
-+{
-+ struct mmal_msg_context *msg_context = (struct mmal_msg_context *)work;
-+
-+ msg_context->u.bulk.port->buffer_cb(msg_context->u.bulk.instance,
-+ msg_context->u.bulk.port,
-+ msg_context->u.bulk.status,
-+ msg_context->u.bulk.buffer,
-+ msg_context->u.bulk.buffer_used,
-+ msg_context->u.bulk.mmal_flags,
-+ msg_context->u.bulk.dts,
-+ msg_context->u.bulk.pts);
-+
-+ /* release message context */
-+ release_msg_context(msg_context);
-+}
-+
-+/* enqueue a bulk receive for a given message context */
-+static int bulk_receive(struct vchiq_mmal_instance *instance,
-+ struct mmal_msg *msg,
-+ struct mmal_msg_context *msg_context)
-+{
-+ unsigned long rd_len;
-+ unsigned long flags = 0;
-+ int ret;
-+
-+ /* bulk mutex stops other bulk operations while we have a
-+ * receive in progress - released in callback
-+ */
-+ ret = mutex_lock_interruptible(&instance->bulk_mutex);
-+ if (ret != 0)
-+ return ret;
-+
-+ rd_len = msg->u.buffer_from_host.buffer_header.length;
-+
-+ /* take buffer from queue */
-+ spin_lock_irqsave(&msg_context->u.bulk.port->slock, flags);
-+ if (list_empty(&msg_context->u.bulk.port->buffers)) {
-+ spin_unlock_irqrestore(&msg_context->u.bulk.port->slock, flags);
-+ pr_err("buffer list empty trying to submit bulk receive\n");
-+
-+ /* todo: this is a serious error, we should never have
-+ * commited a buffer_to_host operation to the mmal
-+ * port without the buffer to back it up (underflow
-+ * handling) and there is no obvious way to deal with
-+ * this - how is the mmal servie going to react when
-+ * we fail to do the xfer and reschedule a buffer when
-+ * it arrives? perhaps a starved flag to indicate a
-+ * waiting bulk receive?
-+ */
-+
-+ mutex_unlock(&instance->bulk_mutex);
-+
-+ return -EINVAL;
-+ }
-+
-+ msg_context->u.bulk.buffer =
-+ list_entry(msg_context->u.bulk.port->buffers.next,
-+ struct mmal_buffer, list);
-+ list_del(&msg_context->u.bulk.buffer->list);
-+
-+ spin_unlock_irqrestore(&msg_context->u.bulk.port->slock, flags);
-+
-+ /* ensure we do not overrun the available buffer */
-+ if (rd_len > msg_context->u.bulk.buffer->buffer_size) {
-+ rd_len = msg_context->u.bulk.buffer->buffer_size;
-+ pr_warn("short read as not enough receive buffer space\n");
-+ /* todo: is this the correct response, what happens to
-+ * the rest of the message data?
-+ */
-+ }
-+
-+ /* store length */
-+ msg_context->u.bulk.buffer_used = rd_len;
-+ msg_context->u.bulk.mmal_flags =
-+ msg->u.buffer_from_host.buffer_header.flags;
-+ msg_context->u.bulk.dts = msg->u.buffer_from_host.buffer_header.dts;
-+ msg_context->u.bulk.pts = msg->u.buffer_from_host.buffer_header.pts;
-+
-+ // only need to flush L1 cache here, as VCHIQ takes care of the L2
-+ // cache.
-+ __cpuc_flush_dcache_area(msg_context->u.bulk.buffer->buffer, rd_len);
-+
-+ /* queue the bulk submission */
-+ vchi_service_use(instance->handle);
-+ ret = vchi_bulk_queue_receive(instance->handle,
-+ msg_context->u.bulk.buffer->buffer,
-+ /* Actual receive needs to be a multiple
-+ * of 4 bytes
-+ */
-+ (rd_len + 3) & ~3,
-+ VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE |
-+ VCHI_FLAGS_BLOCK_UNTIL_QUEUED,
-+ msg_context);
-+
-+ vchi_service_release(instance->handle);
-+
-+ if (ret != 0) {
-+ /* callback will not be clearing the mutex */
-+ mutex_unlock(&instance->bulk_mutex);
-+ }
-+
-+ return ret;
-+}
-+
-+/* enque a dummy bulk receive for a given message context */
-+static int dummy_bulk_receive(struct vchiq_mmal_instance *instance,
-+ struct mmal_msg_context *msg_context)
-+{
-+ int ret;
-+
-+ /* bulk mutex stops other bulk operations while we have a
-+ * receive in progress - released in callback
-+ */
-+ ret = mutex_lock_interruptible(&instance->bulk_mutex);
-+ if (ret != 0)
-+ return ret;
-+
-+ /* zero length indicates this was a dummy transfer */
-+ msg_context->u.bulk.buffer_used = 0;
-+
-+ /* queue the bulk submission */
-+ vchi_service_use(instance->handle);
-+
-+ ret = vchi_bulk_queue_receive(instance->handle,
-+ instance->bulk_scratch,
-+ 8,
-+ VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE |
-+ VCHI_FLAGS_BLOCK_UNTIL_QUEUED,
-+ msg_context);
-+
-+ vchi_service_release(instance->handle);
-+
-+ if (ret != 0) {
-+ /* callback will not be clearing the mutex */
-+ mutex_unlock(&instance->bulk_mutex);
-+ }
-+
-+ return ret;
-+}
-+
-+/* data in message, memcpy from packet into output buffer */
-+static int inline_receive(struct vchiq_mmal_instance *instance,
-+ struct mmal_msg *msg,
-+ struct mmal_msg_context *msg_context)
-+{
-+ unsigned long flags = 0;
-+
-+ /* take buffer from queue */
-+ spin_lock_irqsave(&msg_context->u.bulk.port->slock, flags);
-+ if (list_empty(&msg_context->u.bulk.port->buffers)) {
-+ spin_unlock_irqrestore(&msg_context->u.bulk.port->slock, flags);
-+ pr_err("buffer list empty trying to receive inline\n");
-+
-+ /* todo: this is a serious error, we should never have
-+ * commited a buffer_to_host operation to the mmal
-+ * port without the buffer to back it up (with
-+ * underflow handling) and there is no obvious way to
-+ * deal with this. Less bad than the bulk case as we
-+ * can just drop this on the floor but...unhelpful
-+ */
-+ return -EINVAL;
-+ }
-+
-+ msg_context->u.bulk.buffer =
-+ list_entry(msg_context->u.bulk.port->buffers.next,
-+ struct mmal_buffer, list);
-+ list_del(&msg_context->u.bulk.buffer->list);
-+
-+ spin_unlock_irqrestore(&msg_context->u.bulk.port->slock, flags);
-+
-+ memcpy(msg_context->u.bulk.buffer->buffer,
-+ msg->u.buffer_from_host.short_data,
-+ msg->u.buffer_from_host.payload_in_message);
-+
-+ msg_context->u.bulk.buffer_used =
-+ msg->u.buffer_from_host.payload_in_message;
-+
-+ return 0;
-+}
-+
-+/* queue the buffer availability with MMAL_MSG_TYPE_BUFFER_FROM_HOST */
-+static int
-+buffer_from_host(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port, struct mmal_buffer *buf)
-+{
-+ struct mmal_msg_context *msg_context;
-+ struct mmal_msg m;
-+ int ret;
-+
-+ pr_debug("instance:%p buffer:%p\n", instance->handle, buf);
-+
-+ /* bulk mutex stops other bulk operations while we
-+ * have a receive in progress
-+ */
-+ if (mutex_lock_interruptible(&instance->bulk_mutex))
-+ return -EINTR;
-+
-+ /* get context */
-+ msg_context = get_msg_context(instance);
-+ if (msg_context == NULL)
-+ return -ENOMEM;
-+
-+ /* store bulk message context for when data arrives */
-+ msg_context->u.bulk.instance = instance;
-+ msg_context->u.bulk.port = port;
-+ msg_context->u.bulk.buffer = NULL; /* not valid until bulk xfer */
-+ msg_context->u.bulk.buffer_used = 0;
-+
-+ /* initialise work structure ready to schedule callback */
-+ INIT_WORK(&msg_context->u.bulk.work, buffer_work_cb);
-+
-+ /* prep the buffer from host message */
-+ memset(&m, 0xbc, sizeof(m)); /* just to make debug clearer */
-+
-+ m.h.type = MMAL_MSG_TYPE_BUFFER_FROM_HOST;
-+ m.h.magic = MMAL_MAGIC;
-+ m.h.context = msg_context;
-+ m.h.status = 0;
-+
-+ /* drvbuf is our private data passed back */
-+ m.u.buffer_from_host.drvbuf.magic = MMAL_MAGIC;
-+ m.u.buffer_from_host.drvbuf.component_handle = port->component->handle;
-+ m.u.buffer_from_host.drvbuf.port_handle = port->handle;
-+ m.u.buffer_from_host.drvbuf.client_context = msg_context;
-+
-+ /* buffer header */
-+ m.u.buffer_from_host.buffer_header.cmd = 0;
-+ m.u.buffer_from_host.buffer_header.data = buf->buffer;
-+ m.u.buffer_from_host.buffer_header.alloc_size = buf->buffer_size;
-+ m.u.buffer_from_host.buffer_header.length = 0; /* nothing used yet */
-+ m.u.buffer_from_host.buffer_header.offset = 0; /* no offset */
-+ m.u.buffer_from_host.buffer_header.flags = 0; /* no flags */
-+ m.u.buffer_from_host.buffer_header.pts = MMAL_TIME_UNKNOWN;
-+ m.u.buffer_from_host.buffer_header.dts = MMAL_TIME_UNKNOWN;
-+
-+ /* clear buffer type sepecific data */
-+ memset(&m.u.buffer_from_host.buffer_header_type_specific, 0,
-+ sizeof(m.u.buffer_from_host.buffer_header_type_specific));
-+
-+ /* no payload in message */
-+ m.u.buffer_from_host.payload_in_message = 0;
-+
-+ vchi_service_use(instance->handle);
-+
-+ ret = vchi_msg_queue(instance->handle, &m,
-+ sizeof(struct mmal_msg_header) +
-+ sizeof(m.u.buffer_from_host),
-+ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
-+
-+ if (ret != 0) {
-+ release_msg_context(msg_context);
-+ /* todo: is this correct error value? */
-+ }
-+
-+ vchi_service_release(instance->handle);
-+
-+ mutex_unlock(&instance->bulk_mutex);
-+
-+ return ret;
-+}
-+
-+/* submit a buffer to the mmal sevice
-+ *
-+ * the buffer_from_host uses size data from the ports next available
-+ * mmal_buffer and deals with there being no buffer available by
-+ * incrementing the underflow for later
-+ */
-+static int port_buffer_from_host(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port)
-+{
-+ int ret;
-+ struct mmal_buffer *buf;
-+ unsigned long flags = 0;
-+
-+ if (!port->enabled)
-+ return -EINVAL;
-+
-+ /* peek buffer from queue */
-+ spin_lock_irqsave(&port->slock, flags);
-+ if (list_empty(&port->buffers)) {
-+ port->buffer_underflow++;
-+ spin_unlock_irqrestore(&port->slock, flags);
-+ return -ENOSPC;
-+ }
-+
-+ buf = list_entry(port->buffers.next, struct mmal_buffer, list);
-+
-+ spin_unlock_irqrestore(&port->slock, flags);
-+
-+ /* issue buffer to mmal service */
-+ ret = buffer_from_host(instance, port, buf);
-+ if (ret) {
-+ pr_err("adding buffer header failed\n");
-+ /* todo: how should this be dealt with */
-+ }
-+
-+ return ret;
-+}
-+
-+/* deals with receipt of buffer to host message */
-+static void buffer_to_host_cb(struct vchiq_mmal_instance *instance,
-+ struct mmal_msg *msg, u32 msg_len)
-+{
-+ struct mmal_msg_context *msg_context;
-+
-+ pr_debug("buffer_to_host_cb: instance:%p msg:%p msg_len:%d\n",
-+ instance, msg, msg_len);
-+
-+ if (msg->u.buffer_from_host.drvbuf.magic == MMAL_MAGIC) {
-+ msg_context = msg->u.buffer_from_host.drvbuf.client_context;
-+ } else {
-+ pr_err("MMAL_MSG_TYPE_BUFFER_TO_HOST with bad magic\n");
-+ return;
-+ }
-+
-+ if (msg->h.status != MMAL_MSG_STATUS_SUCCESS) {
-+ /* message reception had an error */
-+ pr_warn("error %d in reply\n", msg->h.status);
-+
-+ msg_context->u.bulk.status = msg->h.status;
-+
-+ } else if (msg->u.buffer_from_host.buffer_header.length == 0) {
-+ /* empty buffer */
-+ if (msg->u.buffer_from_host.buffer_header.flags &
-+ MMAL_BUFFER_HEADER_FLAG_EOS) {
-+ msg_context->u.bulk.status =
-+ dummy_bulk_receive(instance, msg_context);
-+ if (msg_context->u.bulk.status == 0)
-+ return; /* successful bulk submission, bulk
-+ * completion will trigger callback
-+ */
-+ } else {
-+ /* do callback with empty buffer - not EOS though */
-+ msg_context->u.bulk.status = 0;
-+ msg_context->u.bulk.buffer_used = 0;
-+ }
-+ } else if (msg->u.buffer_from_host.payload_in_message == 0) {
-+ /* data is not in message, queue a bulk receive */
-+ msg_context->u.bulk.status =
-+ bulk_receive(instance, msg, msg_context);
-+ if (msg_context->u.bulk.status == 0)
-+ return; /* successful bulk submission, bulk
-+ * completion will trigger callback
-+ */
-+
-+ /* failed to submit buffer, this will end badly */
-+ pr_err("error %d on bulk submission\n",
-+ msg_context->u.bulk.status);
-+
-+ } else if (msg->u.buffer_from_host.payload_in_message <=
-+ MMAL_VC_SHORT_DATA) {
-+ /* data payload within message */
-+ msg_context->u.bulk.status = inline_receive(instance, msg,
-+ msg_context);
-+ } else {
-+ pr_err("message with invalid short payload\n");
-+
-+ /* signal error */
-+ msg_context->u.bulk.status = -EINVAL;
-+ msg_context->u.bulk.buffer_used =
-+ msg->u.buffer_from_host.payload_in_message;
-+ }
-+
-+ /* replace the buffer header */
-+ port_buffer_from_host(instance, msg_context->u.bulk.port);
-+
-+ /* schedule the port callback */
-+ schedule_work(&msg_context->u.bulk.work);
-+}
-+
-+static void bulk_receive_cb(struct vchiq_mmal_instance *instance,
-+ struct mmal_msg_context *msg_context)
-+{
-+ /* bulk receive operation complete */
-+ mutex_unlock(&msg_context->u.bulk.instance->bulk_mutex);
-+
-+ /* replace the buffer header */
-+ port_buffer_from_host(msg_context->u.bulk.instance,
-+ msg_context->u.bulk.port);
-+
-+ msg_context->u.bulk.status = 0;
-+
-+ /* schedule the port callback */
-+ schedule_work(&msg_context->u.bulk.work);
-+}
-+
-+static void bulk_abort_cb(struct vchiq_mmal_instance *instance,
-+ struct mmal_msg_context *msg_context)
-+{
-+ pr_err("%s: bulk ABORTED msg_context:%p\n", __func__, msg_context);
-+
-+ /* bulk receive operation complete */
-+ mutex_unlock(&msg_context->u.bulk.instance->bulk_mutex);
-+
-+ /* replace the buffer header */
-+ port_buffer_from_host(msg_context->u.bulk.instance,
-+ msg_context->u.bulk.port);
-+
-+ msg_context->u.bulk.status = -EINTR;
-+
-+ schedule_work(&msg_context->u.bulk.work);
-+}
-+
-+/* incoming event service callback */
-+static void service_callback(void *param,
-+ const VCHI_CALLBACK_REASON_T reason,
-+ void *bulk_ctx)
-+{
-+ struct vchiq_mmal_instance *instance = param;
-+ int status;
-+ u32 msg_len;
-+ struct mmal_msg *msg;
-+ VCHI_HELD_MSG_T msg_handle;
-+
-+ if (!instance) {
-+ pr_err("Message callback passed NULL instance\n");
-+ return;
-+ }
-+
-+ switch (reason) {
-+ case VCHI_CALLBACK_MSG_AVAILABLE:
-+ status = vchi_msg_hold(instance->handle, (void **)&msg,
-+ &msg_len, VCHI_FLAGS_NONE, &msg_handle);
-+ if (status) {
-+ pr_err("Unable to dequeue a message (%d)\n", status);
-+ break;
-+ }
-+
-+ DBG_DUMP_MSG(msg, msg_len, "<<< reply message");
-+
-+ /* handling is different for buffer messages */
-+ switch (msg->h.type) {
-+
-+ case MMAL_MSG_TYPE_BUFFER_FROM_HOST:
-+ vchi_held_msg_release(&msg_handle);
-+ break;
-+
-+ case MMAL_MSG_TYPE_EVENT_TO_HOST:
-+ event_to_host_cb(instance, msg, msg_len);
-+ vchi_held_msg_release(&msg_handle);
-+
-+ break;
-+
-+ case MMAL_MSG_TYPE_BUFFER_TO_HOST:
-+ buffer_to_host_cb(instance, msg, msg_len);
-+ vchi_held_msg_release(&msg_handle);
-+ break;
-+
-+ default:
-+ /* messages dependant on header context to complete */
-+
-+ /* todo: the msg.context really ought to be sanity
-+ * checked before we just use it, afaict it comes back
-+ * and is used raw from the videocore. Perhaps it
-+ * should be verified the address lies in the kernel
-+ * address space.
-+ */
-+ if (msg->h.context == NULL) {
-+ pr_err("received message context was null!\n");
-+ vchi_held_msg_release(&msg_handle);
-+ break;
-+ }
-+
-+ /* fill in context values */
-+ msg->h.context->u.sync.msg_handle = msg_handle;
-+ msg->h.context->u.sync.msg = msg;
-+ msg->h.context->u.sync.msg_len = msg_len;
-+
-+ /* todo: should this check (completion_done()
-+ * == 1) for no one waiting? or do we need a
-+ * flag to tell us the completion has been
-+ * interrupted so we can free the message and
-+ * its context. This probably also solves the
-+ * message arriving after interruption todo
-+ * below
-+ */
-+
-+ /* complete message so caller knows it happened */
-+ complete(&msg->h.context->u.sync.cmplt);
-+ break;
-+ }
-+
-+ break;
-+
-+ case VCHI_CALLBACK_BULK_RECEIVED:
-+ bulk_receive_cb(instance, bulk_ctx);
-+ break;
-+
-+ case VCHI_CALLBACK_BULK_RECEIVE_ABORTED:
-+ bulk_abort_cb(instance, bulk_ctx);
-+ break;
-+
-+ case VCHI_CALLBACK_SERVICE_CLOSED:
-+ /* TODO: consider if this requires action if received when
-+ * driver is not explicitly closing the service
-+ */
-+ break;
-+
-+ default:
-+ pr_err("Received unhandled message reason %d\n", reason);
-+ break;
-+ }
-+}
-+
-+static int send_synchronous_mmal_msg(struct vchiq_mmal_instance *instance,
-+ struct mmal_msg *msg,
-+ unsigned int payload_len,
-+ struct mmal_msg **msg_out,
-+ VCHI_HELD_MSG_T *msg_handle_out)
-+{
-+ struct mmal_msg_context msg_context;
-+ int ret;
-+
-+ /* payload size must not cause message to exceed max size */
-+ if (payload_len >
-+ (MMAL_MSG_MAX_SIZE - sizeof(struct mmal_msg_header))) {
-+ pr_err("payload length %d exceeds max:%d\n", payload_len,
-+ (MMAL_MSG_MAX_SIZE - sizeof(struct mmal_msg_header)));
-+ return -EINVAL;
-+ }
-+
-+ init_completion(&msg_context.u.sync.cmplt);
-+
-+ msg->h.magic = MMAL_MAGIC;
-+ msg->h.context = &msg_context;
-+ msg->h.status = 0;
-+
-+ DBG_DUMP_MSG(msg, (sizeof(struct mmal_msg_header) + payload_len),
-+ ">>> sync message");
-+
-+ vchi_service_use(instance->handle);
-+
-+ ret = vchi_msg_queue(instance->handle,
-+ msg,
-+ sizeof(struct mmal_msg_header) + payload_len,
-+ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
-+
-+ vchi_service_release(instance->handle);
-+
-+ if (ret) {
-+ pr_err("error %d queuing message\n", ret);
-+ return ret;
-+ }
-+
-+ ret = wait_for_completion_timeout(&msg_context.u.sync.cmplt, 3*HZ);
-+ if (ret <= 0) {
-+ pr_err("error %d waiting for sync completion\n", ret);
-+ if (ret == 0)
-+ ret = -ETIME;
-+ /* todo: what happens if the message arrives after aborting */
-+ return ret;
-+ }
-+
-+ *msg_out = msg_context.u.sync.msg;
-+ *msg_handle_out = msg_context.u.sync.msg_handle;
-+
-+ return 0;
-+}
-+
-+static void dump_port_info(struct vchiq_mmal_port *port)
-+{
-+ pr_debug("port handle:0x%x enabled:%d\n", port->handle, port->enabled);
-+
-+ pr_debug("buffer minimum num:%d size:%d align:%d\n",
-+ port->minimum_buffer.num,
-+ port->minimum_buffer.size, port->minimum_buffer.alignment);
-+
-+ pr_debug("buffer recommended num:%d size:%d align:%d\n",
-+ port->recommended_buffer.num,
-+ port->recommended_buffer.size,
-+ port->recommended_buffer.alignment);
-+
-+ pr_debug("buffer current values num:%d size:%d align:%d\n",
-+ port->current_buffer.num,
-+ port->current_buffer.size, port->current_buffer.alignment);
-+
-+ pr_debug("elementry stream: type:%d encoding:0x%x varient:0x%x\n",
-+ port->format.type,
-+ port->format.encoding, port->format.encoding_variant);
-+
-+ pr_debug(" bitrate:%d flags:0x%x\n",
-+ port->format.bitrate, port->format.flags);
-+
-+ if (port->format.type == MMAL_ES_TYPE_VIDEO) {
-+ pr_debug
-+ ("es video format: width:%d height:%d colourspace:0x%x\n",
-+ port->es.video.width, port->es.video.height,
-+ port->es.video.color_space);
-+
-+ pr_debug(" : crop xywh %d,%d,%d,%d\n",
-+ port->es.video.crop.x,
-+ port->es.video.crop.y,
-+ port->es.video.crop.width, port->es.video.crop.height);
-+ pr_debug(" : framerate %d/%d aspect %d/%d\n",
-+ port->es.video.frame_rate.num,
-+ port->es.video.frame_rate.den,
-+ port->es.video.par.num, port->es.video.par.den);
-+ }
-+}
-+
-+static void port_to_mmal_msg(struct vchiq_mmal_port *port, struct mmal_port *p)
-+{
-+
-+ /* todo do readonly fields need setting at all? */
-+ p->type = port->type;
-+ p->index = port->index;
-+ p->index_all = 0;
-+ p->is_enabled = port->enabled;
-+ p->buffer_num_min = port->minimum_buffer.num;
-+ p->buffer_size_min = port->minimum_buffer.size;
-+ p->buffer_alignment_min = port->minimum_buffer.alignment;
-+ p->buffer_num_recommended = port->recommended_buffer.num;
-+ p->buffer_size_recommended = port->recommended_buffer.size;
-+
-+ /* only three writable fields in a port */
-+ p->buffer_num = port->current_buffer.num;
-+ p->buffer_size = port->current_buffer.size;
-+ p->userdata = port;
-+}
-+
-+static int port_info_set(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port)
-+{
-+ int ret;
-+ struct mmal_msg m;
-+ struct mmal_msg *rmsg;
-+ VCHI_HELD_MSG_T rmsg_handle;
-+
-+ pr_debug("setting port info port %p\n", port);
-+ if (!port)
-+ return -1;
-+ dump_port_info(port);
-+
-+ m.h.type = MMAL_MSG_TYPE_PORT_INFO_SET;
-+
-+ m.u.port_info_set.component_handle = port->component->handle;
-+ m.u.port_info_set.port_type = port->type;
-+ m.u.port_info_set.port_index = port->index;
-+
-+ port_to_mmal_msg(port, &m.u.port_info_set.port);
-+
-+ /* elementry stream format setup */
-+ m.u.port_info_set.format.type = port->format.type;
-+ m.u.port_info_set.format.encoding = port->format.encoding;
-+ m.u.port_info_set.format.encoding_variant =
-+ port->format.encoding_variant;
-+ m.u.port_info_set.format.bitrate = port->format.bitrate;
-+ m.u.port_info_set.format.flags = port->format.flags;
-+
-+ memcpy(&m.u.port_info_set.es, &port->es,
-+ sizeof(union mmal_es_specific_format));
-+
-+ m.u.port_info_set.format.extradata_size = port->format.extradata_size;
-+ memcpy(&m.u.port_info_set.extradata, port->format.extradata,
-+ port->format.extradata_size);
-+
-+ ret = send_synchronous_mmal_msg(instance, &m,
-+ sizeof(m.u.port_info_set),
-+ &rmsg, &rmsg_handle);
-+ if (ret)
-+ return ret;
-+
-+ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_INFO_SET) {
-+ /* got an unexpected message type in reply */
-+ ret = -EINVAL;
-+ goto release_msg;
-+ }
-+
-+ /* return operation status */
-+ ret = -rmsg->u.port_info_get_reply.status;
-+
-+ pr_debug("%s:result:%d component:0x%x port:%d\n", __func__, ret,
-+ port->component->handle, port->handle);
-+
-+release_msg:
-+ vchi_held_msg_release(&rmsg_handle);
-+
-+ return ret;
-+
-+}
-+
-+/* use port info get message to retrive port information */
-+static int port_info_get(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port)
-+{
-+ int ret;
-+ struct mmal_msg m;
-+ struct mmal_msg *rmsg;
-+ VCHI_HELD_MSG_T rmsg_handle;
-+
-+ /* port info time */
-+ m.h.type = MMAL_MSG_TYPE_PORT_INFO_GET;
-+ m.u.port_info_get.component_handle = port->component->handle;
-+ m.u.port_info_get.port_type = port->type;
-+ m.u.port_info_get.index = port->index;
-+
-+ ret = send_synchronous_mmal_msg(instance, &m,
-+ sizeof(m.u.port_info_get),
-+ &rmsg, &rmsg_handle);
-+ if (ret)
-+ return ret;
-+
-+ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_INFO_GET) {
-+ /* got an unexpected message type in reply */
-+ ret = -EINVAL;
-+ goto release_msg;
-+ }
-+
-+ /* return operation status */
-+ ret = -rmsg->u.port_info_get_reply.status;
-+ if (ret != MMAL_MSG_STATUS_SUCCESS)
-+ goto release_msg;
-+
-+ if (rmsg->u.port_info_get_reply.port.is_enabled == 0)
-+ port->enabled = false;
-+ else
-+ port->enabled = true;
-+
-+ /* copy the values out of the message */
-+ port->handle = rmsg->u.port_info_get_reply.port_handle;
-+
-+ /* port type and index cached to use on port info set becuase
-+ * it does not use a port handle
-+ */
-+ port->type = rmsg->u.port_info_get_reply.port_type;
-+ port->index = rmsg->u.port_info_get_reply.port_index;
-+
-+ port->minimum_buffer.num =
-+ rmsg->u.port_info_get_reply.port.buffer_num_min;
-+ port->minimum_buffer.size =
-+ rmsg->u.port_info_get_reply.port.buffer_size_min;
-+ port->minimum_buffer.alignment =
-+ rmsg->u.port_info_get_reply.port.buffer_alignment_min;
-+
-+ port->recommended_buffer.alignment =
-+ rmsg->u.port_info_get_reply.port.buffer_alignment_min;
-+ port->recommended_buffer.num =
-+ rmsg->u.port_info_get_reply.port.buffer_num_recommended;
-+
-+ port->current_buffer.num = rmsg->u.port_info_get_reply.port.buffer_num;
-+ port->current_buffer.size =
-+ rmsg->u.port_info_get_reply.port.buffer_size;
-+
-+ /* stream format */
-+ port->format.type = rmsg->u.port_info_get_reply.format.type;
-+ port->format.encoding = rmsg->u.port_info_get_reply.format.encoding;
-+ port->format.encoding_variant =
-+ rmsg->u.port_info_get_reply.format.encoding_variant;
-+ port->format.bitrate = rmsg->u.port_info_get_reply.format.bitrate;
-+ port->format.flags = rmsg->u.port_info_get_reply.format.flags;
-+
-+ /* elementry stream format */
-+ memcpy(&port->es,
-+ &rmsg->u.port_info_get_reply.es,
-+ sizeof(union mmal_es_specific_format));
-+ port->format.es = &port->es;
-+
-+ port->format.extradata_size =
-+ rmsg->u.port_info_get_reply.format.extradata_size;
-+ memcpy(port->format.extradata,
-+ rmsg->u.port_info_get_reply.extradata,
-+ port->format.extradata_size);
-+
-+ pr_debug("received port info\n");
-+ dump_port_info(port);
-+
-+release_msg:
-+
-+ pr_debug("%s:result:%d component:0x%x port:%d\n",
-+ __func__, ret, port->component->handle, port->handle);
-+
-+ vchi_held_msg_release(&rmsg_handle);
-+
-+ return ret;
-+}
-+
-+/* create comonent on vc */
-+static int create_component(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_component *component,
-+ const char *name)
-+{
-+ int ret;
-+ struct mmal_msg m;
-+ struct mmal_msg *rmsg;
-+ VCHI_HELD_MSG_T rmsg_handle;
-+
-+ /* build component create message */
-+ m.h.type = MMAL_MSG_TYPE_COMPONENT_CREATE;
-+ m.u.component_create.client_component = component;
-+ strncpy(m.u.component_create.name, name,
-+ sizeof(m.u.component_create.name));
-+
-+ ret = send_synchronous_mmal_msg(instance, &m,
-+ sizeof(m.u.component_create),
-+ &rmsg, &rmsg_handle);
-+ if (ret)
-+ return ret;
-+
-+ if (rmsg->h.type != m.h.type) {
-+ /* got an unexpected message type in reply */
-+ ret = -EINVAL;
-+ goto release_msg;
-+ }
-+
-+ ret = -rmsg->u.component_create_reply.status;
-+ if (ret != MMAL_MSG_STATUS_SUCCESS)
-+ goto release_msg;
-+
-+ /* a valid component response received */
-+ component->handle = rmsg->u.component_create_reply.component_handle;
-+ component->inputs = rmsg->u.component_create_reply.input_num;
-+ component->outputs = rmsg->u.component_create_reply.output_num;
-+ component->clocks = rmsg->u.component_create_reply.clock_num;
-+
-+ pr_debug("Component handle:0x%x in:%d out:%d clock:%d\n",
-+ component->handle,
-+ component->inputs, component->outputs, component->clocks);
-+
-+release_msg:
-+ vchi_held_msg_release(&rmsg_handle);
-+
-+ return ret;
-+}
-+
-+/* destroys a component on vc */
-+static int destroy_component(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_component *component)
-+{
-+ int ret;
-+ struct mmal_msg m;
-+ struct mmal_msg *rmsg;
-+ VCHI_HELD_MSG_T rmsg_handle;
-+
-+ m.h.type = MMAL_MSG_TYPE_COMPONENT_DESTROY;
-+ m.u.component_destroy.component_handle = component->handle;
-+
-+ ret = send_synchronous_mmal_msg(instance, &m,
-+ sizeof(m.u.component_destroy),
-+ &rmsg, &rmsg_handle);
-+ if (ret)
-+ return ret;
-+
-+ if (rmsg->h.type != m.h.type) {
-+ /* got an unexpected message type in reply */
-+ ret = -EINVAL;
-+ goto release_msg;
-+ }
-+
-+ ret = -rmsg->u.component_destroy_reply.status;
-+
-+release_msg:
-+
-+ vchi_held_msg_release(&rmsg_handle);
-+
-+ return ret;
-+}
-+
-+/* enable a component on vc */
-+static int enable_component(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_component *component)
-+{
-+ int ret;
-+ struct mmal_msg m;
-+ struct mmal_msg *rmsg;
-+ VCHI_HELD_MSG_T rmsg_handle;
-+
-+ m.h.type = MMAL_MSG_TYPE_COMPONENT_ENABLE;
-+ m.u.component_enable.component_handle = component->handle;
-+
-+ ret = send_synchronous_mmal_msg(instance, &m,
-+ sizeof(m.u.component_enable),
-+ &rmsg, &rmsg_handle);
-+ if (ret)
-+ return ret;
-+
-+ if (rmsg->h.type != m.h.type) {
-+ /* got an unexpected message type in reply */
-+ ret = -EINVAL;
-+ goto release_msg;
-+ }
-+
-+ ret = -rmsg->u.component_enable_reply.status;
-+
-+release_msg:
-+ vchi_held_msg_release(&rmsg_handle);
-+
-+ return ret;
-+}
-+
-+/* disable a component on vc */
-+static int disable_component(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_component *component)
-+{
-+ int ret;
-+ struct mmal_msg m;
-+ struct mmal_msg *rmsg;
-+ VCHI_HELD_MSG_T rmsg_handle;
-+
-+ m.h.type = MMAL_MSG_TYPE_COMPONENT_DISABLE;
-+ m.u.component_disable.component_handle = component->handle;
-+
-+ ret = send_synchronous_mmal_msg(instance, &m,
-+ sizeof(m.u.component_disable),
-+ &rmsg, &rmsg_handle);
-+ if (ret)
-+ return ret;
-+
-+ if (rmsg->h.type != m.h.type) {
-+ /* got an unexpected message type in reply */
-+ ret = -EINVAL;
-+ goto release_msg;
-+ }
-+
-+ ret = -rmsg->u.component_disable_reply.status;
-+
-+release_msg:
-+
-+ vchi_held_msg_release(&rmsg_handle);
-+
-+ return ret;
-+}
-+
-+/* get version of mmal implementation */
-+static int get_version(struct vchiq_mmal_instance *instance,
-+ u32 *major_out, u32 *minor_out)
-+{
-+ int ret;
-+ struct mmal_msg m;
-+ struct mmal_msg *rmsg;
-+ VCHI_HELD_MSG_T rmsg_handle;
-+
-+ m.h.type = MMAL_MSG_TYPE_GET_VERSION;
-+
-+ ret = send_synchronous_mmal_msg(instance, &m,
-+ sizeof(m.u.version),
-+ &rmsg, &rmsg_handle);
-+ if (ret)
-+ return ret;
-+
-+ if (rmsg->h.type != m.h.type) {
-+ /* got an unexpected message type in reply */
-+ ret = -EINVAL;
-+ goto release_msg;
-+ }
-+
-+ *major_out = rmsg->u.version.major;
-+ *minor_out = rmsg->u.version.minor;
-+
-+release_msg:
-+ vchi_held_msg_release(&rmsg_handle);
-+
-+ return ret;
-+}
-+
-+/* do a port action with a port as a parameter */
-+static int port_action_port(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port,
-+ enum mmal_msg_port_action_type action_type)
-+{
-+ int ret;
-+ struct mmal_msg m;
-+ struct mmal_msg *rmsg;
-+ VCHI_HELD_MSG_T rmsg_handle;
-+
-+ m.h.type = MMAL_MSG_TYPE_PORT_ACTION;
-+ m.u.port_action_port.component_handle = port->component->handle;
-+ m.u.port_action_port.port_handle = port->handle;
-+ m.u.port_action_port.action = action_type;
-+
-+ port_to_mmal_msg(port, &m.u.port_action_port.port);
-+
-+ ret = send_synchronous_mmal_msg(instance, &m,
-+ sizeof(m.u.port_action_port),
-+ &rmsg, &rmsg_handle);
-+ if (ret)
-+ return ret;
-+
-+ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_ACTION) {
-+ /* got an unexpected message type in reply */
-+ ret = -EINVAL;
-+ goto release_msg;
-+ }
-+
-+ ret = -rmsg->u.port_action_reply.status;
-+
-+ pr_debug("%s:result:%d component:0x%x port:%d action:%s(%d)\n",
-+ __func__,
-+ ret, port->component->handle, port->handle,
-+ port_action_type_names[action_type], action_type);
-+
-+release_msg:
-+ vchi_held_msg_release(&rmsg_handle);
-+
-+ return ret;
-+}
-+
-+/* do a port action with handles as parameters */
-+static int port_action_handle(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port,
-+ enum mmal_msg_port_action_type action_type,
-+ u32 connect_component_handle,
-+ u32 connect_port_handle)
-+{
-+ int ret;
-+ struct mmal_msg m;
-+ struct mmal_msg *rmsg;
-+ VCHI_HELD_MSG_T rmsg_handle;
-+
-+ m.h.type = MMAL_MSG_TYPE_PORT_ACTION;
-+
-+ m.u.port_action_handle.component_handle = port->component->handle;
-+ m.u.port_action_handle.port_handle = port->handle;
-+ m.u.port_action_handle.action = action_type;
-+
-+ m.u.port_action_handle.connect_component_handle =
-+ connect_component_handle;
-+ m.u.port_action_handle.connect_port_handle = connect_port_handle;
-+
-+ ret = send_synchronous_mmal_msg(instance, &m,
-+ sizeof(m.u.port_action_handle),
-+ &rmsg, &rmsg_handle);
-+ if (ret)
-+ return ret;
-+
-+ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_ACTION) {
-+ /* got an unexpected message type in reply */
-+ ret = -EINVAL;
-+ goto release_msg;
-+ }
-+
-+ ret = -rmsg->u.port_action_reply.status;
-+
-+ pr_debug("%s:result:%d component:0x%x port:%d action:%s(%d)" \
-+ " connect component:0x%x connect port:%d\n",
-+ __func__,
-+ ret, port->component->handle, port->handle,
-+ port_action_type_names[action_type],
-+ action_type, connect_component_handle, connect_port_handle);
-+
-+release_msg:
-+ vchi_held_msg_release(&rmsg_handle);
-+
-+ return ret;
-+}
-+
-+static int port_parameter_set(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port,
-+ u32 parameter_id, void *value, u32 value_size)
-+{
-+ int ret;
-+ struct mmal_msg m;
-+ struct mmal_msg *rmsg;
-+ VCHI_HELD_MSG_T rmsg_handle;
-+
-+ m.h.type = MMAL_MSG_TYPE_PORT_PARAMETER_SET;
-+
-+ m.u.port_parameter_set.component_handle = port->component->handle;
-+ m.u.port_parameter_set.port_handle = port->handle;
-+ m.u.port_parameter_set.id = parameter_id;
-+ m.u.port_parameter_set.size = (2 * sizeof(u32)) + value_size;
-+ memcpy(&m.u.port_parameter_set.value, value, value_size);
-+
-+ ret = send_synchronous_mmal_msg(instance, &m,
-+ (4 * sizeof(u32)) + value_size,
-+ &rmsg, &rmsg_handle);
-+ if (ret)
-+ return ret;
-+
-+ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_PARAMETER_SET) {
-+ /* got an unexpected message type in reply */
-+ ret = -EINVAL;
-+ goto release_msg;
-+ }
-+
-+ ret = -rmsg->u.port_parameter_set_reply.status;
-+
-+ pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n",
-+ __func__,
-+ ret, port->component->handle, port->handle, parameter_id);
-+
-+release_msg:
-+ vchi_held_msg_release(&rmsg_handle);
-+
-+ return ret;
-+}
-+
-+static int port_parameter_get(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port,
-+ u32 parameter_id, void *value, u32 *value_size)
-+{
-+ int ret;
-+ struct mmal_msg m;
-+ struct mmal_msg *rmsg;
-+ VCHI_HELD_MSG_T rmsg_handle;
-+
-+ m.h.type = MMAL_MSG_TYPE_PORT_PARAMETER_GET;
-+
-+ m.u.port_parameter_get.component_handle = port->component->handle;
-+ m.u.port_parameter_get.port_handle = port->handle;
-+ m.u.port_parameter_get.id = parameter_id;
-+ m.u.port_parameter_get.size = (2 * sizeof(u32)) + *value_size;
-+
-+ ret = send_synchronous_mmal_msg(instance, &m,
-+ sizeof(struct
-+ mmal_msg_port_parameter_get),
-+ &rmsg, &rmsg_handle);
-+ if (ret)
-+ return ret;
-+
-+ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_PARAMETER_GET) {
-+ /* got an unexpected message type in reply */
-+ pr_err("Incorrect reply type %d\n", rmsg->h.type);
-+ ret = -EINVAL;
-+ goto release_msg;
-+ }
-+
-+ ret = -rmsg->u.port_parameter_get_reply.status;
-+ if (ret) {
-+ /* Copy only as much as we have space for
-+ * but report true size of parameter
-+ */
-+ memcpy(value, &rmsg->u.port_parameter_get_reply.value,
-+ *value_size);
-+ *value_size = rmsg->u.port_parameter_get_reply.size;
-+ } else
-+ memcpy(value, &rmsg->u.port_parameter_get_reply.value,
-+ rmsg->u.port_parameter_get_reply.size);
-+
-+ pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n", __func__,
-+ ret, port->component->handle, port->handle, parameter_id);
-+
-+release_msg:
-+ vchi_held_msg_release(&rmsg_handle);
-+
-+ return ret;
-+}
-+
-+/* disables a port and drains buffers from it */
-+static int port_disable(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port)
-+{
-+ int ret;
-+ struct list_head *q, *buf_head;
-+ unsigned long flags = 0;
-+
-+ if (!port->enabled)
-+ return 0;
-+
-+ port->enabled = false;
-+
-+ ret = port_action_port(instance, port,
-+ MMAL_MSG_PORT_ACTION_TYPE_DISABLE);
-+ if (ret == 0) {
-+
-+ /* drain all queued buffers on port */
-+ spin_lock_irqsave(&port->slock, flags);
-+
-+ list_for_each_safe(buf_head, q, &port->buffers) {
-+ struct mmal_buffer *mmalbuf;
-+ mmalbuf = list_entry(buf_head, struct mmal_buffer,
-+ list);
-+ list_del(buf_head);
-+ if (port->buffer_cb)
-+ port->buffer_cb(instance,
-+ port, 0, mmalbuf, 0, 0,
-+ MMAL_TIME_UNKNOWN,
-+ MMAL_TIME_UNKNOWN);
-+ }
-+
-+ spin_unlock_irqrestore(&port->slock, flags);
-+
-+ ret = port_info_get(instance, port);
-+ }
-+
-+ return ret;
-+}
-+
-+/* enable a port */
-+static int port_enable(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port)
-+{
-+ unsigned int hdr_count;
-+ struct list_head *buf_head;
-+ int ret;
-+
-+ if (port->enabled)
-+ return 0;
-+
-+ /* ensure there are enough buffers queued to cover the buffer headers */
-+ if (port->buffer_cb != NULL) {
-+ hdr_count = 0;
-+ list_for_each(buf_head, &port->buffers) {
-+ hdr_count++;
-+ }
-+ if (hdr_count < port->current_buffer.num)
-+ return -ENOSPC;
-+ }
-+
-+ ret = port_action_port(instance, port,
-+ MMAL_MSG_PORT_ACTION_TYPE_ENABLE);
-+ if (ret)
-+ goto done;
-+
-+ port->enabled = true;
-+
-+ if (port->buffer_cb) {
-+ /* send buffer headers to videocore */
-+ hdr_count = 1;
-+ list_for_each(buf_head, &port->buffers) {
-+ struct mmal_buffer *mmalbuf;
-+ mmalbuf = list_entry(buf_head, struct mmal_buffer,
-+ list);
-+ ret = buffer_from_host(instance, port, mmalbuf);
-+ if (ret)
-+ goto done;
-+
-+ hdr_count++;
-+ if (hdr_count > port->current_buffer.num)
-+ break;
-+ }
-+ }
-+
-+ ret = port_info_get(instance, port);
-+
-+done:
-+ return ret;
-+}
-+
-+/* ------------------------------------------------------------------
-+ * Exported API
-+ *------------------------------------------------------------------*/
-+
-+int vchiq_mmal_port_set_format(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port)
-+{
-+ int ret;
-+
-+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
-+ return -EINTR;
-+
-+ ret = port_info_set(instance, port);
-+ if (ret)
-+ goto release_unlock;
-+
-+ /* read what has actually been set */
-+ ret = port_info_get(instance, port);
-+
-+release_unlock:
-+ mutex_unlock(&instance->vchiq_mutex);
-+
-+ return ret;
-+
-+}
-+
-+int vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port,
-+ u32 parameter, void *value, u32 value_size)
-+{
-+ int ret;
-+
-+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
-+ return -EINTR;
-+
-+ ret = port_parameter_set(instance, port, parameter, value, value_size);
-+
-+ mutex_unlock(&instance->vchiq_mutex);
-+
-+ return ret;
-+}
-+
-+int vchiq_mmal_port_parameter_get(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port,
-+ u32 parameter, void *value, u32 *value_size)
-+{
-+ int ret;
-+
-+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
-+ return -EINTR;
-+
-+ ret = port_parameter_get(instance, port, parameter, value, value_size);
-+
-+ mutex_unlock(&instance->vchiq_mutex);
-+
-+ return ret;
-+}
-+
-+/* enable a port
-+ *
-+ * enables a port and queues buffers for satisfying callbacks if we
-+ * provide a callback handler
-+ */
-+int vchiq_mmal_port_enable(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port,
-+ vchiq_mmal_buffer_cb buffer_cb)
-+{
-+ int ret;
-+
-+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
-+ return -EINTR;
-+
-+ /* already enabled - noop */
-+ if (port->enabled) {
-+ ret = 0;
-+ goto unlock;
-+ }
-+
-+ port->buffer_cb = buffer_cb;
-+
-+ ret = port_enable(instance, port);
-+
-+unlock:
-+ mutex_unlock(&instance->vchiq_mutex);
-+
-+ return ret;
-+}
-+
-+int vchiq_mmal_port_disable(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port)
-+{
-+ int ret;
-+
-+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
-+ return -EINTR;
-+
-+ if (!port->enabled) {
-+ mutex_unlock(&instance->vchiq_mutex);
-+ return 0;
-+ }
-+
-+ ret = port_disable(instance, port);
-+
-+ mutex_unlock(&instance->vchiq_mutex);
-+
-+ return ret;
-+}
-+
-+/* ports will be connected in a tunneled manner so data buffers
-+ * are not handled by client.
-+ */
-+int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *src,
-+ struct vchiq_mmal_port *dst)
-+{
-+ int ret;
-+
-+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
-+ return -EINTR;
-+
-+ /* disconnect ports if connected */
-+ if (src->connected != NULL) {
-+ ret = port_disable(instance, src);
-+ if (ret) {
-+ pr_err("failed disabling src port(%d)\n", ret);
-+ goto release_unlock;
-+ }
-+
-+ /* do not need to disable the destination port as they
-+ * are connected and it is done automatically
-+ */
-+
-+ ret = port_action_handle(instance, src,
-+ MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT,
-+ src->connected->component->handle,
-+ src->connected->handle);
-+ if (ret < 0) {
-+ pr_err("failed disconnecting src port\n");
-+ goto release_unlock;
-+ }
-+ src->connected->enabled = false;
-+ src->connected = NULL;
-+ }
-+
-+ if (dst == NULL) {
-+ /* do not make new connection */
-+ ret = 0;
-+ pr_debug("not making new connection\n");
-+ goto release_unlock;
-+ }
-+
-+ /* copy src port format to dst */
-+ dst->format.encoding = src->format.encoding;
-+ dst->es.video.width = src->es.video.width;
-+ dst->es.video.height = src->es.video.height;
-+ dst->es.video.crop.x = src->es.video.crop.x;
-+ dst->es.video.crop.y = src->es.video.crop.y;
-+ dst->es.video.crop.width = src->es.video.crop.width;
-+ dst->es.video.crop.height = src->es.video.crop.height;
-+ dst->es.video.frame_rate.num = src->es.video.frame_rate.num;
-+ dst->es.video.frame_rate.den = src->es.video.frame_rate.den;
-+
-+ /* set new format */
-+ ret = port_info_set(instance, dst);
-+ if (ret) {
-+ pr_debug("setting port info failed\n");
-+ goto release_unlock;
-+ }
-+
-+ /* read what has actually been set */
-+ ret = port_info_get(instance, dst);
-+ if (ret) {
-+ pr_debug("read back port info failed\n");
-+ goto release_unlock;
-+ }
-+
-+ /* connect two ports together */
-+ ret = port_action_handle(instance, src,
-+ MMAL_MSG_PORT_ACTION_TYPE_CONNECT,
-+ dst->component->handle, dst->handle);
-+ if (ret < 0) {
-+ pr_debug("connecting port %d:%d to %d:%d failed\n",
-+ src->component->handle, src->handle,
-+ dst->component->handle, dst->handle);
-+ goto release_unlock;
-+ }
-+ src->connected = dst;
-+
-+release_unlock:
-+
-+ mutex_unlock(&instance->vchiq_mutex);
-+
-+ return ret;
-+}
-+
-+int vchiq_mmal_submit_buffer(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port,
-+ struct mmal_buffer *buffer)
-+{
-+ unsigned long flags = 0;
-+
-+ spin_lock_irqsave(&port->slock, flags);
-+ list_add_tail(&buffer->list, &port->buffers);
-+ spin_unlock_irqrestore(&port->slock, flags);
-+
-+ /* the port previously underflowed because it was missing a
-+ * mmal_buffer which has just been added, submit that buffer
-+ * to the mmal service.
-+ */
-+ if (port->buffer_underflow) {
-+ port_buffer_from_host(instance, port);
-+ port->buffer_underflow--;
-+ }
-+
-+ return 0;
-+}
-+
-+/* Initialise a mmal component and its ports
-+ *
-+ */
-+int vchiq_mmal_component_init(struct vchiq_mmal_instance *instance,
-+ const char *name,
-+ struct vchiq_mmal_component **component_out)
-+{
-+ int ret;
-+ int idx; /* port index */
-+ struct vchiq_mmal_component *component;
-+
-+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
-+ return -EINTR;
-+
-+ if (instance->component_idx == VCHIQ_MMAL_MAX_COMPONENTS) {
-+ ret = -EINVAL; /* todo is this correct error? */
-+ goto unlock;
-+ }
-+
-+ component = &instance->component[instance->component_idx];
-+
-+ ret = create_component(instance, component, name);
-+ if (ret < 0)
-+ goto unlock;
-+
-+ /* ports info needs gathering */
-+ component->control.type = MMAL_PORT_TYPE_CONTROL;
-+ component->control.index = 0;
-+ component->control.component = component;
-+ spin_lock_init(&component->control.slock);
-+ INIT_LIST_HEAD(&component->control.buffers);
-+ ret = port_info_get(instance, &component->control);
-+ if (ret < 0)
-+ goto release_component;
-+
-+ for (idx = 0; idx < component->inputs; idx++) {
-+ component->input[idx].type = MMAL_PORT_TYPE_INPUT;
-+ component->input[idx].index = idx;
-+ component->input[idx].component = component;
-+ spin_lock_init(&component->input[idx].slock);
-+ INIT_LIST_HEAD(&component->input[idx].buffers);
-+ ret = port_info_get(instance, &component->input[idx]);
-+ if (ret < 0)
-+ goto release_component;
-+ }
-+
-+ for (idx = 0; idx < component->outputs; idx++) {
-+ component->output[idx].type = MMAL_PORT_TYPE_OUTPUT;
-+ component->output[idx].index = idx;
-+ component->output[idx].component = component;
-+ spin_lock_init(&component->output[idx].slock);
-+ INIT_LIST_HEAD(&component->output[idx].buffers);
-+ ret = port_info_get(instance, &component->output[idx]);
-+ if (ret < 0)
-+ goto release_component;
-+ }
-+
-+ for (idx = 0; idx < component->clocks; idx++) {
-+ component->clock[idx].type = MMAL_PORT_TYPE_CLOCK;
-+ component->clock[idx].index = idx;
-+ component->clock[idx].component = component;
-+ spin_lock_init(&component->clock[idx].slock);
-+ INIT_LIST_HEAD(&component->clock[idx].buffers);
-+ ret = port_info_get(instance, &component->clock[idx]);
-+ if (ret < 0)
-+ goto release_component;
-+ }
-+
-+ instance->component_idx++;
-+
-+ *component_out = component;
-+
-+ mutex_unlock(&instance->vchiq_mutex);
-+
-+ return 0;
-+
-+release_component:
-+ destroy_component(instance, component);
-+unlock:
-+ mutex_unlock(&instance->vchiq_mutex);
-+
-+ return ret;
-+}
-+
-+/*
-+ * cause a mmal component to be destroyed
-+ */
-+int vchiq_mmal_component_finalise(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_component *component)
-+{
-+ int ret;
-+
-+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
-+ return -EINTR;
-+
-+ if (component->enabled)
-+ ret = disable_component(instance, component);
-+
-+ ret = destroy_component(instance, component);
-+
-+ mutex_unlock(&instance->vchiq_mutex);
-+
-+ return ret;
-+}
-+
-+/*
-+ * cause a mmal component to be enabled
-+ */
-+int vchiq_mmal_component_enable(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_component *component)
-+{
-+ int ret;
-+
-+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
-+ return -EINTR;
-+
-+ if (component->enabled) {
-+ mutex_unlock(&instance->vchiq_mutex);
-+ return 0;
-+ }
-+
-+ ret = enable_component(instance, component);
-+ if (ret == 0)
-+ component->enabled = true;
-+
-+ mutex_unlock(&instance->vchiq_mutex);
-+
-+ return ret;
-+}
-+
-+/*
-+ * cause a mmal component to be enabled
-+ */
-+int vchiq_mmal_component_disable(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_component *component)
-+{
-+ int ret;
-+
-+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
-+ return -EINTR;
-+
-+ if (!component->enabled) {
-+ mutex_unlock(&instance->vchiq_mutex);
-+ return 0;
-+ }
-+
-+ ret = disable_component(instance, component);
-+ if (ret == 0)
-+ component->enabled = false;
-+
-+ mutex_unlock(&instance->vchiq_mutex);
-+
-+ return ret;
-+}
-+
-+int vchiq_mmal_version(struct vchiq_mmal_instance *instance,
-+ u32 *major_out, u32 *minor_out)
-+{
-+ int ret;
-+
-+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
-+ return -EINTR;
-+
-+ ret = get_version(instance, major_out, minor_out);
-+
-+ mutex_unlock(&instance->vchiq_mutex);
-+
-+ return ret;
-+}
-+
-+int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance)
-+{
-+ int status = 0;
-+
-+ if (instance == NULL)
-+ return -EINVAL;
-+
-+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
-+ return -EINTR;
-+
-+ vchi_service_use(instance->handle);
-+
-+ status = vchi_service_close(instance->handle);
-+ if (status != 0)
-+ pr_err("mmal-vchiq: VCHIQ close failed");
-+
-+ mutex_unlock(&instance->vchiq_mutex);
-+
-+ vfree(instance->bulk_scratch);
-+
-+ kfree(instance);
-+
-+ return status;
-+}
-+
-+int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance)
-+{
-+ int status;
-+ struct vchiq_mmal_instance *instance;
-+ static VCHI_CONNECTION_T *vchi_connection;
-+ static VCHI_INSTANCE_T vchi_instance;
-+ SERVICE_CREATION_T params = {
-+ VCHI_VERSION_EX(VC_MMAL_VER, VC_MMAL_MIN_VER),
-+ VC_MMAL_SERVER_NAME,
-+ vchi_connection,
-+ 0, /* rx fifo size (unused) */
-+ 0, /* tx fifo size (unused) */
-+ service_callback,
-+ NULL, /* service callback parameter */
-+ 1, /* unaligned bulk receives */
-+ 1, /* unaligned bulk transmits */
-+ 0 /* want crc check on bulk transfers */
-+ };
-+
-+ /* compile time checks to ensure structure size as they are
-+ * directly (de)serialised from memory.
-+ */
-+
-+ /* ensure the header structure has packed to the correct size */
-+ BUILD_BUG_ON(sizeof(struct mmal_msg_header) != 24);
-+
-+ /* ensure message structure does not exceed maximum length */
-+ BUILD_BUG_ON(sizeof(struct mmal_msg) > MMAL_MSG_MAX_SIZE);
-+
-+ /* mmal port struct is correct size */
-+ BUILD_BUG_ON(sizeof(struct mmal_port) != 64);
-+
-+ /* create a vchi instance */
-+ status = vchi_initialise(&vchi_instance);
-+ if (status) {
-+ pr_err("Failed to initialise VCHI instance (status=%d)\n",
-+ status);
-+ return -EIO;
-+ }
-+
-+ status = vchi_connect(NULL, 0, vchi_instance);
-+ if (status) {
-+ pr_err("Failed to connect VCHI instance (status=%d)\n", status);
-+ return -EIO;
-+ }
-+
-+ instance = kmalloc(sizeof(*instance), GFP_KERNEL);
-+ memset(instance, 0, sizeof(*instance));
-+
-+ mutex_init(&instance->vchiq_mutex);
-+ mutex_init(&instance->bulk_mutex);
-+
-+ instance->bulk_scratch = vmalloc(PAGE_SIZE);
-+
-+ params.callback_param = instance;
-+
-+ status = vchi_service_open(vchi_instance, &params, &instance->handle);
-+ if (status) {
-+ pr_err("Failed to open VCHI service connection (status=%d)\n",
-+ status);
-+ goto err_close_services;
-+ }
-+
-+ vchi_service_release(instance->handle);
-+
-+ *out_instance = instance;
-+
-+ return 0;
-+
-+err_close_services:
-+
-+ vchi_service_close(instance->handle);
-+ vfree(instance->bulk_scratch);
-+ kfree(instance);
-+ return -ENODEV;
-+}
---- /dev/null
-+++ b/drivers/media/platform/bcm2835/mmal-vchiq.h
-@@ -0,0 +1,178 @@
-+/*
-+ * Broadcom BM2835 V4L2 driver
-+ *
-+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
-+ *
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file COPYING in the main directory of this archive
-+ * for more details.
-+ *
-+ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
-+ * Dave Stevenson <dsteve@broadcom.com>
-+ * Simon Mellor <simellor@broadcom.com>
-+ * Luke Diamand <luked@broadcom.com>
-+ *
-+ * MMAL interface to VCHIQ message passing
-+ */
-+
-+#ifndef MMAL_VCHIQ_H
-+#define MMAL_VCHIQ_H
-+
-+#include "mmal-msg-format.h"
-+
-+#define MAX_PORT_COUNT 4
-+
-+/* Maximum size of the format extradata. */
-+#define MMAL_FORMAT_EXTRADATA_MAX_SIZE 128
-+
-+struct vchiq_mmal_instance;
-+
-+enum vchiq_mmal_es_type {
-+ MMAL_ES_TYPE_UNKNOWN, /**< Unknown elementary stream type */
-+ MMAL_ES_TYPE_CONTROL, /**< Elementary stream of control commands */
-+ MMAL_ES_TYPE_AUDIO, /**< Audio elementary stream */
-+ MMAL_ES_TYPE_VIDEO, /**< Video elementary stream */
-+ MMAL_ES_TYPE_SUBPICTURE /**< Sub-picture elementary stream */
-+};
-+
-+/* rectangle, used lots so it gets its own struct */
-+struct vchiq_mmal_rect {
-+ s32 x;
-+ s32 y;
-+ s32 width;
-+ s32 height;
-+};
-+
-+struct vchiq_mmal_port_buffer {
-+ unsigned int num; /* number of buffers */
-+ u32 size; /* size of buffers */
-+ u32 alignment; /* alignment of buffers */
-+};
-+
-+struct vchiq_mmal_port;
-+
-+typedef void (*vchiq_mmal_buffer_cb)(
-+ struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port,
-+ int status, struct mmal_buffer *buffer,
-+ unsigned long length, u32 mmal_flags, s64 dts, s64 pts);
-+
-+struct vchiq_mmal_port {
-+ bool enabled;
-+ u32 handle;
-+ u32 type; /* port type, cached to use on port info set */
-+ u32 index; /* port index, cached to use on port info set */
-+
-+ /* component port belongs to, allows simple deref */
-+ struct vchiq_mmal_component *component;
-+
-+ struct vchiq_mmal_port *connected; /* port conencted to */
-+
-+ /* buffer info */
-+ struct vchiq_mmal_port_buffer minimum_buffer;
-+ struct vchiq_mmal_port_buffer recommended_buffer;
-+ struct vchiq_mmal_port_buffer current_buffer;
-+
-+ /* stream format */
-+ struct mmal_es_format format;
-+ /* elementry stream format */
-+ union mmal_es_specific_format es;
-+
-+ /* data buffers to fill */
-+ struct list_head buffers;
-+ /* lock to serialise adding and removing buffers from list */
-+ spinlock_t slock;
-+ /* count of how many buffer header refils have failed because
-+ * there was no buffer to satisfy them
-+ */
-+ int buffer_underflow;
-+ /* callback on buffer completion */
-+ vchiq_mmal_buffer_cb buffer_cb;
-+ /* callback context */
-+ void *cb_ctx;
-+};
-+
-+struct vchiq_mmal_component {
-+ bool enabled;
-+ u32 handle; /* VideoCore handle for component */
-+ u32 inputs; /* Number of input ports */
-+ u32 outputs; /* Number of output ports */
-+ u32 clocks; /* Number of clock ports */
-+ struct vchiq_mmal_port control; /* control port */
-+ struct vchiq_mmal_port input[MAX_PORT_COUNT]; /* input ports */
-+ struct vchiq_mmal_port output[MAX_PORT_COUNT]; /* output ports */
-+ struct vchiq_mmal_port clock[MAX_PORT_COUNT]; /* clock ports */
-+};
-+
-+
-+int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance);
-+int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance);
-+
-+/* Initialise a mmal component and its ports
-+*
-+*/
-+int vchiq_mmal_component_init(
-+ struct vchiq_mmal_instance *instance,
-+ const char *name,
-+ struct vchiq_mmal_component **component_out);
-+
-+int vchiq_mmal_component_finalise(
-+ struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_component *component);
-+
-+int vchiq_mmal_component_enable(
-+ struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_component *component);
-+
-+int vchiq_mmal_component_disable(
-+ struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_component *component);
-+
-+
-+
-+/* enable a mmal port
-+ *
-+ * enables a port and if a buffer callback provided enque buffer
-+ * headers as apropriate for the port.
-+ */
-+int vchiq_mmal_port_enable(
-+ struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port,
-+ vchiq_mmal_buffer_cb buffer_cb);
-+
-+/* disable a port
-+ *
-+ * disable a port will dequeue any pending buffers
-+ */
-+int vchiq_mmal_port_disable(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port);
-+
-+
-+int vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port,
-+ u32 parameter,
-+ void *value,
-+ u32 value_size);
-+
-+int vchiq_mmal_port_parameter_get(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port,
-+ u32 parameter,
-+ void *value,
-+ u32 *value_size);
-+
-+int vchiq_mmal_port_set_format(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port);
-+
-+int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *src,
-+ struct vchiq_mmal_port *dst);
-+
-+int vchiq_mmal_version(struct vchiq_mmal_instance *instance,
-+ u32 *major_out,
-+ u32 *minor_out);
-+
-+int vchiq_mmal_submit_buffer(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port,
-+ struct mmal_buffer *buf);
-+
-+#endif /* MMAL_VCHIQ_H */
diff --git a/target/linux/brcm2708/patches-4.4/0049-scripts-Add-mkknlimg-and-knlinfo-scripts-from-tools-.patch b/target/linux/brcm2708/patches-4.4/0049-scripts-Add-mkknlimg-and-knlinfo-scripts-from-tools-.patch
new file mode 100644
index 0000000000..9943e07a80
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0049-scripts-Add-mkknlimg-and-knlinfo-scripts-from-tools-.patch
@@ -0,0 +1,461 @@
+From b2f75aacf0bfb9e3069bdec7a6481ed4bf7a2b51 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 11 May 2015 09:00:42 +0100
+Subject: [PATCH 049/381] scripts: Add mkknlimg and knlinfo scripts from tools
+ repo
+
+The Raspberry Pi firmware looks for a trailer on the kernel image to
+determine whether it was compiled with Device Tree support enabled.
+If the firmware finds a kernel without this trailer, or which has a
+trailer indicating that it isn't DT-capable, it disables DT support
+and reverts to using ATAGs.
+
+The mkknlimg utility adds that trailer, having first analysed the
+image to look for signs of DT support and the kernel version string.
+
+knlinfo displays the contents of the trailer in the given kernel image.
+
+scripts/mkknlimg: Add support for ARCH_BCM2835
+
+Add a new trailer field indicating whether this is an ARCH_BCM2835
+build, as opposed to MACH_BCM2708/9. If the loader finds this flag
+is set it changes the default base dtb file name from bcm270x...
+to bcm283y...
+
+Also update knlinfo to show the status of the field.
+
+scripts/mkknlimg: Improve ARCH_BCM2835 detection
+
+The board support code contains sufficient strings to be able to
+distinguish 2708 vs. 2835 builds, so remove the check for
+bcm2835-pm-wdt which could exist in either.
+
+Also, since the canned configuration is no longer built in (it's
+a module), remove the config string checking.
+
+See: https://github.com/raspberrypi/linux/issues/1157
+---
+ scripts/knlinfo | 168 ++++++++++++++++++++++++++++++++++++++
+ scripts/mkknlimg | 244 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 412 insertions(+)
+ create mode 100755 scripts/knlinfo
+ create mode 100755 scripts/mkknlimg
+
+--- /dev/null
++++ b/scripts/knlinfo
+@@ -0,0 +1,168 @@
++#!/usr/bin/env perl
++# ----------------------------------------------------------------------
++# knlinfo by Phil Elwell for Raspberry Pi
++#
++# (c) 2014,2015 Raspberry Pi (Trading) Limited <info@raspberrypi.org>
++#
++# Licensed under the terms of the GNU General Public License.
++# ----------------------------------------------------------------------
++
++use strict;
++use integer;
++
++use Fcntl ":seek";
++
++my $trailer_magic = 'RPTL';
++
++my %atom_formats =
++(
++ 'DTOK' => \&format_bool,
++ 'KVer' => \&format_string,
++ '283x' => \&format_bool,
++);
++
++if (@ARGV != 1)
++{
++ print ("Usage: knlinfo <kernel image>\n");
++ exit(1);
++}
++
++my $kernel_file = $ARGV[0];
++
++
++my ($atoms, $pos) = read_trailer($kernel_file);
++
++exit(1) if (!$atoms);
++
++printf("Kernel trailer found at %d/0x%x:\n", $pos, $pos);
++
++foreach my $atom (@$atoms)
++{
++ printf(" %s: %s\n", $atom->[0], format_atom($atom));
++}
++
++exit(0);
++
++sub read_trailer
++{
++ my ($kernel_file) = @_;
++ my $fh;
++
++ if (!open($fh, '<', $kernel_file))
++ {
++ print ("* Failed to open '$kernel_file'\n");
++ return undef;
++ }
++
++ if (!seek($fh, -12, SEEK_END))
++ {
++ print ("* seek error in '$kernel_file'\n");
++ return undef;
++ }
++
++ my $last_bytes;
++ sysread($fh, $last_bytes, 12);
++
++ my ($trailer_len, $data_len, $magic) = unpack('VVa4', $last_bytes);
++
++ if (($magic ne $trailer_magic) || ($data_len != 4))
++ {
++ print ("* no trailer\n");
++ return undef;
++ }
++ if (!seek($fh, -12, SEEK_END))
++ {
++ print ("* seek error in '$kernel_file'\n");
++ return undef;
++ }
++
++ $trailer_len -= 12;
++
++ while ($trailer_len > 0)
++ {
++ if ($trailer_len < 8)
++ {
++ print ("* truncated atom header in trailer\n");
++ return undef;
++ }
++ if (!seek($fh, -8, SEEK_CUR))
++ {
++ print ("* seek error in '$kernel_file'\n");
++ return undef;
++ }
++ $trailer_len -= 8;
++
++ my $atom_hdr;
++ sysread($fh, $atom_hdr, 8);
++ my ($atom_len, $atom_type) = unpack('Va4', $atom_hdr);
++
++ if ($trailer_len < $atom_len)
++ {
++ print ("* truncated atom data in trailer\n");
++ return undef;
++ }
++
++ my $rounded_len = (($atom_len + 3) & ~3);
++ if (!seek($fh, -(8 + $rounded_len), SEEK_CUR))
++ {
++ print ("* seek error in '$kernel_file'\n");
++ return undef;
++ }
++ $trailer_len -= $rounded_len;
++
++ my $atom_data;
++ sysread($fh, $atom_data, $atom_len);
++
++ if (!seek($fh, -$atom_len, SEEK_CUR))
++ {
++ print ("* seek error in '$kernel_file'\n");
++ return undef;
++ }
++
++ push @$atoms, [ $atom_type, $atom_data ];
++ }
++
++ if (($$atoms[-1][0] eq "\x00\x00\x00\x00") &&
++ ($$atoms[-1][1] eq ""))
++ {
++ pop @$atoms;
++ }
++ else
++ {
++ print ("* end marker missing from trailer\n");
++ }
++
++ return ($atoms, tell($fh));
++}
++
++sub format_atom
++{
++ my ($atom) = @_;
++
++ my $format_func = $atom_formats{$atom->[0]} || \&format_hex;
++ return $format_func->($atom->[1]);
++}
++
++sub format_bool
++{
++ my ($data) = @_;
++ return unpack('V', $data) ? 'true' : 'false';
++}
++
++sub format_int
++{
++ my ($data) = @_;
++ return unpack('V', $data);
++}
++
++sub format_string
++{
++ my ($data) = @_;
++ return '"'.$data.'"';
++}
++
++sub format_hex
++{
++ my ($data) = @_;
++ return unpack('H*', $data);
++}
+--- /dev/null
++++ b/scripts/mkknlimg
+@@ -0,0 +1,244 @@
++#!/usr/bin/env perl
++# ----------------------------------------------------------------------
++# mkknlimg by Phil Elwell for Raspberry Pi
++# based on extract-ikconfig by Dick Streefland
++#
++# (c) 2009,2010 Dick Streefland <dick@streefland.net>
++# (c) 2014,2015 Raspberry Pi (Trading) Limited <info@raspberrypi.org>
++#
++# Licensed under the terms of the GNU General Public License.
++# ----------------------------------------------------------------------
++
++use strict;
++use warnings;
++use integer;
++
++my $trailer_magic = 'RPTL';
++
++my $tmpfile1 = "/tmp/mkknlimg_$$.1";
++my $tmpfile2 = "/tmp/mkknlimg_$$.2";
++
++my $dtok = 0;
++my $is_283x = 0;
++
++while (@ARGV && ($ARGV[0] =~ /^-/))
++{
++ my $arg = shift(@ARGV);
++ if ($arg eq '--dtok')
++ {
++ $dtok = 1;
++ }
++ elsif ($arg eq '--283x')
++ {
++ $is_283x = 1;
++ }
++ else
++ {
++ print ("* Unknown option '$arg'\n");
++ usage();
++ }
++}
++
++usage() if (@ARGV != 2);
++
++my $kernel_file = $ARGV[0];
++my $out_file = $ARGV[1];
++
++if (! -r $kernel_file)
++{
++ print ("* File '$kernel_file' not found\n");
++ usage();
++}
++
++my @wanted_strings =
++(
++ 'bcm2708_fb',
++ 'brcm,bcm2835-mmc',
++ 'brcm,bcm2835-sdhost',
++ 'brcm,bcm2708-pinctrl',
++ 'brcm,bcm2835-gpio',
++ 'brcm,bcm2835',
++ 'brcm,bcm2836'
++);
++
++my $res = try_extract($kernel_file, $tmpfile1);
++$res = try_decompress('\037\213\010', 'xy', 'gunzip', 0,
++ $kernel_file, $tmpfile1, $tmpfile2) if (!$res);
++$res = try_decompress('\3757zXZ\000', 'abcde', 'unxz --single-stream', -1,
++ $kernel_file, $tmpfile1, $tmpfile2) if (!$res);
++$res = try_decompress('BZh', 'xy', 'bunzip2', 0,
++ $kernel_file, $tmpfile1, $tmpfile2) if (!$res);
++$res = try_decompress('\135\0\0\0', 'xxx', 'unlzma', 0,
++ $kernel_file, $tmpfile1, $tmpfile2) if (!$res);
++$res = try_decompress('\211\114\132', 'xy', 'lzop -d', 0,
++ $kernel_file, $tmpfile1, $tmpfile2) if (!$res);
++$res = try_decompress('\002\041\114\030', 'xy', 'lz4 -d', 1,
++ $kernel_file, $tmpfile1, $tmpfile2) if (!$res);
++
++my $append_trailer;
++my $trailer;
++my $kver = '?';
++
++$append_trailer = $dtok;
++
++if ($res)
++{
++ $kver = $res->{''} || '?';
++ print("Version: $kver\n");
++
++ $append_trailer = $dtok;
++ if (!$dtok)
++ {
++ if (config_bool($res, 'bcm2708_fb') ||
++ config_bool($res, 'brcm,bcm2835-mmc') ||
++ config_bool($res, 'brcm,bcm2835-sdhost'))
++ {
++ $dtok ||= config_bool($res, 'brcm,bcm2708-pinctrl');
++ $dtok ||= config_bool($res, 'brcm,bcm2835-gpio');
++ $is_283x ||= config_bool($res, 'brcm,bcm2835');
++ $is_283x ||= config_bool($res, 'brcm,bcm2836');
++ $dtok ||= $is_283x;
++ $append_trailer = 1;
++ }
++ else
++ {
++ print ("* This doesn't look like a Raspberry Pi kernel. In pass-through mode.\n");
++ }
++ }
++}
++elsif (!$dtok)
++{
++ print ("* Is this a valid kernel? In pass-through mode.\n");
++}
++
++if ($append_trailer)
++{
++ printf("DT: %s\n", $dtok ? "y" : "n");
++ printf("283x: %s\n", $is_283x ? "y" : "n");
++
++ my @atoms;
++
++ push @atoms, [ $trailer_magic, pack('V', 0) ];
++ push @atoms, [ 'KVer', $kver ];
++ push @atoms, [ 'DTOK', pack('V', $dtok) ];
++ push @atoms, [ '283x', pack('V', $is_283x) ];
++
++ $trailer = pack_trailer(\@atoms);
++ $atoms[0]->[1] = pack('V', length($trailer));
++
++ $trailer = pack_trailer(\@atoms);
++}
++
++my $ofh;
++my $total_len = 0;
++
++if ($out_file eq $kernel_file)
++{
++ die "* Failed to open '$out_file' for append\n"
++ if (!open($ofh, '>>', $out_file));
++ $total_len = tell($ofh);
++}
++else
++{
++ die "* Failed to open '$kernel_file'\n"
++ if (!open(my $ifh, '<', $kernel_file));
++ die "* Failed to create '$out_file'\n"
++ if (!open($ofh, '>', $out_file));
++
++ my $copybuf;
++ while (1)
++ {
++ my $bytes = sysread($ifh, $copybuf, 64*1024);
++ last if (!$bytes);
++ syswrite($ofh, $copybuf, $bytes);
++ $total_len += $bytes;
++ }
++ close($ifh);
++}
++
++if ($trailer)
++{
++ # Pad to word-alignment
++ syswrite($ofh, "\x000\x000\x000", (-$total_len & 0x3));
++ syswrite($ofh, $trailer);
++}
++
++close($ofh);
++
++exit($trailer ? 0 : 1);
++
++END {
++ unlink($tmpfile1) if ($tmpfile1);
++ unlink($tmpfile2) if ($tmpfile2);
++}
++
++
++sub usage
++{
++ print ("Usage: mkknlimg [--dtok] [--283x] <vmlinux|zImage|bzImage> <outfile>\n");
++ exit(1);
++}
++
++sub try_extract
++{
++ my ($knl, $tmp) = @_;
++
++ my $ver = `strings "$knl" | grep -a -E "^Linux version [1-9]"`;
++
++ return undef if (!$ver);
++
++ chomp($ver);
++
++ my $res = { ''=>$ver };
++ my $string_pattern = '^('.join('|', @wanted_strings).')$';
++
++ my @matches = `strings \"$knl\" | grep -E \"$string_pattern\"`;
++ foreach my $match (@matches)
++ {
++ chomp($match);
++ $res->{$match} = 1;
++ }
++
++ return $res;
++}
++
++
++sub try_decompress
++{
++ my ($magic, $subst, $zcat, $idx, $knl, $tmp1, $tmp2) = @_;
++
++ my $pos = `tr "$magic\n$subst" "\n$subst=" < "$knl" | grep -abo "^$subst"`;
++ if ($pos)
++ {
++ chomp($pos);
++ $pos = (split(/[\r\n]+/, $pos))[$idx];
++ return undef if (!defined($pos));
++ $pos =~ s/:.*[\r\n]*$//s;
++ my $cmd = "tail -c+$pos \"$knl\" | $zcat > $tmp2 2> /dev/null";
++ my $err = (system($cmd) >> 8);
++ return undef if (($err != 0) && ($err != 2));
++
++ return try_extract($tmp2, $tmp1);
++ }
++
++ return undef;
++}
++
++sub pack_trailer
++{
++ my ($atoms) = @_;
++ my $trailer = pack('VV', 0, 0);
++ for (my $i = $#$atoms; $i>=0; $i--)
++ {
++ my $atom = $atoms->[$i];
++ $trailer .= pack('a*x!4Va4', $atom->[1], length($atom->[1]), $atom->[0]);
++ }
++ return $trailer;
++}
++
++sub config_bool
++{
++ my ($configs, $wanted) = @_;
++ my $val = $configs->{$wanted} || 'n';
++ return (($val eq 'y') || ($val eq '1'));
++}
diff --git a/target/linux/brcm2708/patches-4.4/0050-fdt-Add-support-for-the-CONFIG_CMDLINE_EXTEND-option.patch b/target/linux/brcm2708/patches-4.4/0050-fdt-Add-support-for-the-CONFIG_CMDLINE_EXTEND-option.patch
new file mode 100644
index 0000000000..f7e8b29a2c
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0050-fdt-Add-support-for-the-CONFIG_CMDLINE_EXTEND-option.patch
@@ -0,0 +1,55 @@
+From 0f79afb206f238e89f1cb5c40299f6fd6a47dda3 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 5 Dec 2014 17:26:26 +0000
+Subject: [PATCH 050/381] fdt: Add support for the CONFIG_CMDLINE_EXTEND option
+
+---
+ drivers/of/fdt.c | 29 ++++++++++++++++++++++++-----
+ 1 file changed, 24 insertions(+), 5 deletions(-)
+
+--- a/drivers/of/fdt.c
++++ b/drivers/of/fdt.c
+@@ -954,19 +954,38 @@ int __init early_init_dt_scan_chosen(uns
+
+ /* Retrieve command line */
+ p = of_get_flat_dt_prop(node, "bootargs", &l);
+- if (p != NULL && l > 0)
+- strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE));
+
+ /*
+ * CONFIG_CMDLINE is meant to be a default in case nothing else
+ * managed to set the command line, unless CONFIG_CMDLINE_FORCE
+ * is set in which case we override whatever was found earlier.
++ *
++ * However, it can be useful to be able to treat the default as
++ * a starting point to be extended using CONFIG_CMDLINE_EXTEND.
+ */
++ ((char *)data)[0] = '\0';
++
+ #ifdef CONFIG_CMDLINE
+-#ifndef CONFIG_CMDLINE_FORCE
+- if (!((char *)data)[0])
++ strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
++
++ if (p != NULL && l > 0) {
++#if defined(CONFIG_CMDLINE_EXTEND)
++ int len = strlen(data);
++ if (len > 0) {
++ strlcat(data, " ", COMMAND_LINE_SIZE);
++ len++;
++ }
++ strlcpy((char *)data + len, p, min((int)l, COMMAND_LINE_SIZE - len));
++#elif defined(CONFIG_CMDLINE_FORCE)
++ pr_warning("Ignoring bootargs property (using the default kernel command line)\n");
++#else
++ /* Neither extend nor force - just override */
++ strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE));
+ #endif
+- strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
++ }
++#else /* CONFIG_CMDLINE */
++ if (p != NULL && l > 0)
++ strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE));
+ #endif /* CONFIG_CMDLINE */
+
+ pr_debug("Command line is: %s\n", (char*)data);
diff --git a/target/linux/brcm2708/patches-4.4/0050-scripts-Add-mkknlimg-and-knlinfo-scripts-from-tools-.patch b/target/linux/brcm2708/patches-4.4/0050-scripts-Add-mkknlimg-and-knlinfo-scripts-from-tools-.patch
deleted file mode 100644
index 30cdfe9b0f..0000000000
--- a/target/linux/brcm2708/patches-4.4/0050-scripts-Add-mkknlimg-and-knlinfo-scripts-from-tools-.patch
+++ /dev/null
@@ -1,461 +0,0 @@
-From 03435989bbadbd333a810644c8246dd7eb0bad07 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Mon, 11 May 2015 09:00:42 +0100
-Subject: [PATCH 050/170] scripts: Add mkknlimg and knlinfo scripts from tools
- repo
-
-The Raspberry Pi firmware looks for a trailer on the kernel image to
-determine whether it was compiled with Device Tree support enabled.
-If the firmware finds a kernel without this trailer, or which has a
-trailer indicating that it isn't DT-capable, it disables DT support
-and reverts to using ATAGs.
-
-The mkknlimg utility adds that trailer, having first analysed the
-image to look for signs of DT support and the kernel version string.
-
-knlinfo displays the contents of the trailer in the given kernel image.
-
-scripts/mkknlimg: Add support for ARCH_BCM2835
-
-Add a new trailer field indicating whether this is an ARCH_BCM2835
-build, as opposed to MACH_BCM2708/9. If the loader finds this flag
-is set it changes the default base dtb file name from bcm270x...
-to bcm283y...
-
-Also update knlinfo to show the status of the field.
-
-scripts/mkknlimg: Improve ARCH_BCM2835 detection
-
-The board support code contains sufficient strings to be able to
-distinguish 2708 vs. 2835 builds, so remove the check for
-bcm2835-pm-wdt which could exist in either.
-
-Also, since the canned configuration is no longer built in (it's
-a module), remove the config string checking.
-
-See: https://github.com/raspberrypi/linux/issues/1157
----
- scripts/knlinfo | 168 ++++++++++++++++++++++++++++++++++++++
- scripts/mkknlimg | 244 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 2 files changed, 412 insertions(+)
- create mode 100755 scripts/knlinfo
- create mode 100755 scripts/mkknlimg
-
---- /dev/null
-+++ b/scripts/knlinfo
-@@ -0,0 +1,168 @@
-+#!/usr/bin/env perl
-+# ----------------------------------------------------------------------
-+# knlinfo by Phil Elwell for Raspberry Pi
-+#
-+# (c) 2014,2015 Raspberry Pi (Trading) Limited <info@raspberrypi.org>
-+#
-+# Licensed under the terms of the GNU General Public License.
-+# ----------------------------------------------------------------------
-+
-+use strict;
-+use integer;
-+
-+use Fcntl ":seek";
-+
-+my $trailer_magic = 'RPTL';
-+
-+my %atom_formats =
-+(
-+ 'DTOK' => \&format_bool,
-+ 'KVer' => \&format_string,
-+ '283x' => \&format_bool,
-+);
-+
-+if (@ARGV != 1)
-+{
-+ print ("Usage: knlinfo <kernel image>\n");
-+ exit(1);
-+}
-+
-+my $kernel_file = $ARGV[0];
-+
-+
-+my ($atoms, $pos) = read_trailer($kernel_file);
-+
-+exit(1) if (!$atoms);
-+
-+printf("Kernel trailer found at %d/0x%x:\n", $pos, $pos);
-+
-+foreach my $atom (@$atoms)
-+{
-+ printf(" %s: %s\n", $atom->[0], format_atom($atom));
-+}
-+
-+exit(0);
-+
-+sub read_trailer
-+{
-+ my ($kernel_file) = @_;
-+ my $fh;
-+
-+ if (!open($fh, '<', $kernel_file))
-+ {
-+ print ("* Failed to open '$kernel_file'\n");
-+ return undef;
-+ }
-+
-+ if (!seek($fh, -12, SEEK_END))
-+ {
-+ print ("* seek error in '$kernel_file'\n");
-+ return undef;
-+ }
-+
-+ my $last_bytes;
-+ sysread($fh, $last_bytes, 12);
-+
-+ my ($trailer_len, $data_len, $magic) = unpack('VVa4', $last_bytes);
-+
-+ if (($magic ne $trailer_magic) || ($data_len != 4))
-+ {
-+ print ("* no trailer\n");
-+ return undef;
-+ }
-+ if (!seek($fh, -12, SEEK_END))
-+ {
-+ print ("* seek error in '$kernel_file'\n");
-+ return undef;
-+ }
-+
-+ $trailer_len -= 12;
-+
-+ while ($trailer_len > 0)
-+ {
-+ if ($trailer_len < 8)
-+ {
-+ print ("* truncated atom header in trailer\n");
-+ return undef;
-+ }
-+ if (!seek($fh, -8, SEEK_CUR))
-+ {
-+ print ("* seek error in '$kernel_file'\n");
-+ return undef;
-+ }
-+ $trailer_len -= 8;
-+
-+ my $atom_hdr;
-+ sysread($fh, $atom_hdr, 8);
-+ my ($atom_len, $atom_type) = unpack('Va4', $atom_hdr);
-+
-+ if ($trailer_len < $atom_len)
-+ {
-+ print ("* truncated atom data in trailer\n");
-+ return undef;
-+ }
-+
-+ my $rounded_len = (($atom_len + 3) & ~3);
-+ if (!seek($fh, -(8 + $rounded_len), SEEK_CUR))
-+ {
-+ print ("* seek error in '$kernel_file'\n");
-+ return undef;
-+ }
-+ $trailer_len -= $rounded_len;
-+
-+ my $atom_data;
-+ sysread($fh, $atom_data, $atom_len);
-+
-+ if (!seek($fh, -$atom_len, SEEK_CUR))
-+ {
-+ print ("* seek error in '$kernel_file'\n");
-+ return undef;
-+ }
-+
-+ push @$atoms, [ $atom_type, $atom_data ];
-+ }
-+
-+ if (($$atoms[-1][0] eq "\x00\x00\x00\x00") &&
-+ ($$atoms[-1][1] eq ""))
-+ {
-+ pop @$atoms;
-+ }
-+ else
-+ {
-+ print ("* end marker missing from trailer\n");
-+ }
-+
-+ return ($atoms, tell($fh));
-+}
-+
-+sub format_atom
-+{
-+ my ($atom) = @_;
-+
-+ my $format_func = $atom_formats{$atom->[0]} || \&format_hex;
-+ return $format_func->($atom->[1]);
-+}
-+
-+sub format_bool
-+{
-+ my ($data) = @_;
-+ return unpack('V', $data) ? 'true' : 'false';
-+}
-+
-+sub format_int
-+{
-+ my ($data) = @_;
-+ return unpack('V', $data);
-+}
-+
-+sub format_string
-+{
-+ my ($data) = @_;
-+ return '"'.$data.'"';
-+}
-+
-+sub format_hex
-+{
-+ my ($data) = @_;
-+ return unpack('H*', $data);
-+}
---- /dev/null
-+++ b/scripts/mkknlimg
-@@ -0,0 +1,244 @@
-+#!/usr/bin/env perl
-+# ----------------------------------------------------------------------
-+# mkknlimg by Phil Elwell for Raspberry Pi
-+# based on extract-ikconfig by Dick Streefland
-+#
-+# (c) 2009,2010 Dick Streefland <dick@streefland.net>
-+# (c) 2014,2015 Raspberry Pi (Trading) Limited <info@raspberrypi.org>
-+#
-+# Licensed under the terms of the GNU General Public License.
-+# ----------------------------------------------------------------------
-+
-+use strict;
-+use warnings;
-+use integer;
-+
-+my $trailer_magic = 'RPTL';
-+
-+my $tmpfile1 = "/tmp/mkknlimg_$$.1";
-+my $tmpfile2 = "/tmp/mkknlimg_$$.2";
-+
-+my $dtok = 0;
-+my $is_283x = 0;
-+
-+while (@ARGV && ($ARGV[0] =~ /^-/))
-+{
-+ my $arg = shift(@ARGV);
-+ if ($arg eq '--dtok')
-+ {
-+ $dtok = 1;
-+ }
-+ elsif ($arg eq '--283x')
-+ {
-+ $is_283x = 1;
-+ }
-+ else
-+ {
-+ print ("* Unknown option '$arg'\n");
-+ usage();
-+ }
-+}
-+
-+usage() if (@ARGV != 2);
-+
-+my $kernel_file = $ARGV[0];
-+my $out_file = $ARGV[1];
-+
-+if (! -r $kernel_file)
-+{
-+ print ("* File '$kernel_file' not found\n");
-+ usage();
-+}
-+
-+my @wanted_strings =
-+(
-+ 'bcm2708_fb',
-+ 'brcm,bcm2835-mmc',
-+ 'brcm,bcm2835-sdhost',
-+ 'brcm,bcm2708-pinctrl',
-+ 'brcm,bcm2835-gpio',
-+ 'brcm,bcm2835',
-+ 'brcm,bcm2836'
-+);
-+
-+my $res = try_extract($kernel_file, $tmpfile1);
-+$res = try_decompress('\037\213\010', 'xy', 'gunzip', 0,
-+ $kernel_file, $tmpfile1, $tmpfile2) if (!$res);
-+$res = try_decompress('\3757zXZ\000', 'abcde', 'unxz --single-stream', -1,
-+ $kernel_file, $tmpfile1, $tmpfile2) if (!$res);
-+$res = try_decompress('BZh', 'xy', 'bunzip2', 0,
-+ $kernel_file, $tmpfile1, $tmpfile2) if (!$res);
-+$res = try_decompress('\135\0\0\0', 'xxx', 'unlzma', 0,
-+ $kernel_file, $tmpfile1, $tmpfile2) if (!$res);
-+$res = try_decompress('\211\114\132', 'xy', 'lzop -d', 0,
-+ $kernel_file, $tmpfile1, $tmpfile2) if (!$res);
-+$res = try_decompress('\002\041\114\030', 'xy', 'lz4 -d', 1,
-+ $kernel_file, $tmpfile1, $tmpfile2) if (!$res);
-+
-+my $append_trailer;
-+my $trailer;
-+my $kver = '?';
-+
-+$append_trailer = $dtok;
-+
-+if ($res)
-+{
-+ $kver = $res->{''} || '?';
-+ print("Version: $kver\n");
-+
-+ $append_trailer = $dtok;
-+ if (!$dtok)
-+ {
-+ if (config_bool($res, 'bcm2708_fb') ||
-+ config_bool($res, 'brcm,bcm2835-mmc') ||
-+ config_bool($res, 'brcm,bcm2835-sdhost'))
-+ {
-+ $dtok ||= config_bool($res, 'brcm,bcm2708-pinctrl');
-+ $dtok ||= config_bool($res, 'brcm,bcm2835-gpio');
-+ $is_283x ||= config_bool($res, 'brcm,bcm2835');
-+ $is_283x ||= config_bool($res, 'brcm,bcm2836');
-+ $dtok ||= $is_283x;
-+ $append_trailer = 1;
-+ }
-+ else
-+ {
-+ print ("* This doesn't look like a Raspberry Pi kernel. In pass-through mode.\n");
-+ }
-+ }
-+}
-+elsif (!$dtok)
-+{
-+ print ("* Is this a valid kernel? In pass-through mode.\n");
-+}
-+
-+if ($append_trailer)
-+{
-+ printf("DT: %s\n", $dtok ? "y" : "n");
-+ printf("283x: %s\n", $is_283x ? "y" : "n");
-+
-+ my @atoms;
-+
-+ push @atoms, [ $trailer_magic, pack('V', 0) ];
-+ push @atoms, [ 'KVer', $kver ];
-+ push @atoms, [ 'DTOK', pack('V', $dtok) ];
-+ push @atoms, [ '283x', pack('V', $is_283x) ];
-+
-+ $trailer = pack_trailer(\@atoms);
-+ $atoms[0]->[1] = pack('V', length($trailer));
-+
-+ $trailer = pack_trailer(\@atoms);
-+}
-+
-+my $ofh;
-+my $total_len = 0;
-+
-+if ($out_file eq $kernel_file)
-+{
-+ die "* Failed to open '$out_file' for append\n"
-+ if (!open($ofh, '>>', $out_file));
-+ $total_len = tell($ofh);
-+}
-+else
-+{
-+ die "* Failed to open '$kernel_file'\n"
-+ if (!open(my $ifh, '<', $kernel_file));
-+ die "* Failed to create '$out_file'\n"
-+ if (!open($ofh, '>', $out_file));
-+
-+ my $copybuf;
-+ while (1)
-+ {
-+ my $bytes = sysread($ifh, $copybuf, 64*1024);
-+ last if (!$bytes);
-+ syswrite($ofh, $copybuf, $bytes);
-+ $total_len += $bytes;
-+ }
-+ close($ifh);
-+}
-+
-+if ($trailer)
-+{
-+ # Pad to word-alignment
-+ syswrite($ofh, "\x000\x000\x000", (-$total_len & 0x3));
-+ syswrite($ofh, $trailer);
-+}
-+
-+close($ofh);
-+
-+exit($trailer ? 0 : 1);
-+
-+END {
-+ unlink($tmpfile1) if ($tmpfile1);
-+ unlink($tmpfile2) if ($tmpfile2);
-+}
-+
-+
-+sub usage
-+{
-+ print ("Usage: mkknlimg [--dtok] [--283x] <vmlinux|zImage|bzImage> <outfile>\n");
-+ exit(1);
-+}
-+
-+sub try_extract
-+{
-+ my ($knl, $tmp) = @_;
-+
-+ my $ver = `strings "$knl" | grep -a -E "^Linux version [1-9]"`;
-+
-+ return undef if (!$ver);
-+
-+ chomp($ver);
-+
-+ my $res = { ''=>$ver };
-+ my $string_pattern = '^('.join('|', @wanted_strings).')$';
-+
-+ my @matches = `strings \"$knl\" | grep -E \"$string_pattern\"`;
-+ foreach my $match (@matches)
-+ {
-+ chomp($match);
-+ $res->{$match} = 1;
-+ }
-+
-+ return $res;
-+}
-+
-+
-+sub try_decompress
-+{
-+ my ($magic, $subst, $zcat, $idx, $knl, $tmp1, $tmp2) = @_;
-+
-+ my $pos = `tr "$magic\n$subst" "\n$subst=" < "$knl" | grep -abo "^$subst"`;
-+ if ($pos)
-+ {
-+ chomp($pos);
-+ $pos = (split(/[\r\n]+/, $pos))[$idx];
-+ return undef if (!defined($pos));
-+ $pos =~ s/:.*[\r\n]*$//s;
-+ my $cmd = "tail -c+$pos \"$knl\" | $zcat > $tmp2 2> /dev/null";
-+ my $err = (system($cmd) >> 8);
-+ return undef if (($err != 0) && ($err != 2));
-+
-+ return try_extract($tmp2, $tmp1);
-+ }
-+
-+ return undef;
-+}
-+
-+sub pack_trailer
-+{
-+ my ($atoms) = @_;
-+ my $trailer = pack('VV', 0, 0);
-+ for (my $i = $#$atoms; $i>=0; $i--)
-+ {
-+ my $atom = $atoms->[$i];
-+ $trailer .= pack('a*x!4Va4', $atom->[1], length($atom->[1]), $atom->[0]);
-+ }
-+ return $trailer;
-+}
-+
-+sub config_bool
-+{
-+ my ($configs, $wanted) = @_;
-+ my $val = $configs->{$wanted} || 'n';
-+ return (($val eq 'y') || ($val eq '1'));
-+}
diff --git a/target/linux/brcm2708/patches-4.4/0051-BCM2708-Add-core-Device-Tree-support.patch b/target/linux/brcm2708/patches-4.4/0051-BCM2708-Add-core-Device-Tree-support.patch
new file mode 100644
index 0000000000..d2f3e71cb5
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0051-BCM2708-Add-core-Device-Tree-support.patch
@@ -0,0 +1,4564 @@
+From 4dc11d58769fda62ef7cff1ab506d4c68c232270 Mon Sep 17 00:00:00 2001
+From: notro <notro@tronnes.org>
+Date: Wed, 9 Jul 2014 14:46:08 +0200
+Subject: [PATCH 051/381] BCM2708: Add core Device Tree support
+
+Add the bare minimum needed to boot BCM2708 from a Device Tree.
+
+Signed-off-by: Noralf Tronnes <notro@tronnes.org>
+
+BCM2708: DT: change 'axi' nodename to 'soc'
+
+Change DT node named 'axi' to 'soc' so it matches ARCH_BCM2835.
+The VC4 bootloader fills in certain properties in the 'axi' subtree,
+but since this is part of an upstreaming effort, the name is changed.
+
+Signed-off-by: Noralf Tronnes notro@tronnes.org
+
+BCM2708_DT: Correct length of the peripheral space
+
+Use dts-dirs feature for overlays.
+
+The kernel makefiles have a dts-dirs target that is for vendor subdirectories.
+
+Using this fixes the install_dtbs target, which previously did not install the overlays.
+
+BCM270X_DT: configure I2S DMA channels
+
+Signed-off-by: Matthias Reichl <hias@horus.com>
+
+BCM270X_DT: switch to bcm2835-i2s
+
+I2S soundcard drivers with proper devicetree support (i.e. not linking
+to the cpu_dai/platform via name but to cpu/platform via of_node)
+will work out of the box without any modifications.
+
+When the kernel is compiled without devicetree support the platform
+code will instantiate the bcm2708-i2s driver and I2S soundcard drivers
+will link to it via name, as before.
+
+Signed-off-by: Matthias Reichl <hias@horus.com>
+
+SDIO-overlay: add poll_once-boolean parameter
+
+Add paramter to toggle sdio-device-polling
+done every second or once at boot-time.
+
+Signed-off-by: Patrick Boettcher <patrick.boettcher@posteo.de>
+
+BCM270X_DT: Make mmc overlay compatible with current firmware
+
+The original DT overlay logic followed a merge-then-patch procedure,
+i.e. parameters are applied to the loaded overlay before the overlay
+is merged into the base DTB. This sequence has been changed to
+patch-then-merge, in order to support parameterised node names, and
+to protect against bad overlays. As a result, overrides (parameters)
+must only target labels in the overlay, but the overlay can obviously target nodes in the base DTB.
+
+mmc-overlay.dts (that switches back to the original mmc sdcard
+driver) is the only overlay violating that rule, and this patch
+fixes it.
+
+bcm270x_dt: Use the sdhost MMC controller by default
+
+The "mmc" overlay reverts to using the other controller.
+
+squash: Add cprman to dt
+
+BCM270X_DT: Use clk_core for I2C interfaces
+---
+ arch/arm/boot/dts/Makefile | 30 +
+ arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 145 +++++
+ arch/arm/boot/dts/bcm2708-rpi-b.dts | 135 +++++
+ arch/arm/boot/dts/bcm2708-rpi-cm.dts | 102 ++++
+ arch/arm/boot/dts/bcm2708-rpi-cm.dtsi | 40 ++
+ arch/arm/boot/dts/bcm2708.dtsi | 40 ++
+ arch/arm/boot/dts/bcm2708_common.dtsi | 347 +++++++++++
+ arch/arm/boot/dts/bcm2709-rpi-2-b.dts | 145 +++++
+ arch/arm/boot/dts/bcm2709.dtsi | 102 ++++
+ arch/arm/boot/dts/bcm2835-rpi-cm.dts | 93 +++
+ arch/arm/boot/dts/bcm2835-rpi-cm.dtsi | 30 +
+ arch/arm/boot/dts/overlays/Makefile | 69 +++
+ arch/arm/boot/dts/overlays/README | 648 +++++++++++++++++++++
+ arch/arm/boot/dts/overlays/ads7846-overlay.dts | 83 +++
+ .../dts/overlays/bmp085_i2c-sensor-overlay.dts | 23 +
+ arch/arm/boot/dts/overlays/dht11-overlay.dts | 39 ++
+ arch/arm/boot/dts/overlays/enc28j60-overlay.dts | 50 ++
+ .../boot/dts/overlays/gpio-poweroff-overlay.dts | 34 ++
+ .../boot/dts/overlays/hifiberry-amp-overlay.dts | 39 ++
+ .../boot/dts/overlays/hifiberry-dac-overlay.dts | 34 ++
+ .../dts/overlays/hifiberry-dacplus-overlay.dts | 39 ++
+ .../boot/dts/overlays/hifiberry-digi-overlay.dts | 39 ++
+ arch/arm/boot/dts/overlays/hy28a-overlay.dts | 87 +++
+ arch/arm/boot/dts/overlays/hy28b-overlay.dts | 142 +++++
+ arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts | 55 ++
+ arch/arm/boot/dts/overlays/i2s-mmap-overlay.dts | 13 +
+ arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts | 39 ++
+ .../boot/dts/overlays/iqaudio-dacplus-overlay.dts | 39 ++
+ arch/arm/boot/dts/overlays/lirc-rpi-overlay.dts | 57 ++
+ .../arm/boot/dts/overlays/mcp2515-can0-overlay.dts | 69 +++
+ .../arm/boot/dts/overlays/mcp2515-can1-overlay.dts | 69 +++
+ arch/arm/boot/dts/overlays/mmc-overlay.dts | 39 ++
+ arch/arm/boot/dts/overlays/mz61581-overlay.dts | 111 ++++
+ arch/arm/boot/dts/overlays/piscreen-overlay.dts | 96 +++
+ .../dts/overlays/pitft28-resistive-overlay.dts | 115 ++++
+ arch/arm/boot/dts/overlays/pps-gpio-overlay.dts | 34 ++
+ arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts | 46 ++
+ arch/arm/boot/dts/overlays/pwm-overlay.dts | 42 ++
+ arch/arm/boot/dts/overlays/raspidac3-overlay.dts | 45 ++
+ arch/arm/boot/dts/overlays/rpi-dac-overlay.dts | 34 ++
+ arch/arm/boot/dts/overlays/rpi-display-overlay.dts | 82 +++
+ arch/arm/boot/dts/overlays/rpi-ft5406-overlay.dts | 17 +
+ arch/arm/boot/dts/overlays/rpi-proto-overlay.dts | 39 ++
+ arch/arm/boot/dts/overlays/rpi-sense-overlay.dts | 47 ++
+ arch/arm/boot/dts/overlays/sdhost-overlay.dts | 29 +
+ arch/arm/boot/dts/overlays/sdio-overlay.dts | 32 +
+ arch/arm/boot/dts/overlays/smi-dev-overlay.dts | 18 +
+ arch/arm/boot/dts/overlays/smi-nand-overlay.dts | 69 +++
+ arch/arm/boot/dts/overlays/smi-overlay.dts | 37 ++
+ .../boot/dts/overlays/spi-gpio35-39-overlay.dts | 31 +
+ arch/arm/boot/dts/overlays/tinylcd35-overlay.dts | 216 +++++++
+ arch/arm/boot/dts/overlays/uart1-overlay.dts | 38 ++
+ arch/arm/boot/dts/overlays/vga666-overlay.dts | 30 +
+ arch/arm/boot/dts/overlays/w1-gpio-overlay.dts | 39 ++
+ .../boot/dts/overlays/w1-gpio-pullup-overlay.dts | 41 ++
+ 55 files changed, 4203 insertions(+)
+ create mode 100644 arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
+ create mode 100644 arch/arm/boot/dts/bcm2708-rpi-b.dts
+ create mode 100755 arch/arm/boot/dts/bcm2708-rpi-cm.dts
+ create mode 100644 arch/arm/boot/dts/bcm2708-rpi-cm.dtsi
+ create mode 100644 arch/arm/boot/dts/bcm2708.dtsi
+ create mode 100644 arch/arm/boot/dts/bcm2708_common.dtsi
+ create mode 100644 arch/arm/boot/dts/bcm2709-rpi-2-b.dts
+ create mode 100644 arch/arm/boot/dts/bcm2709.dtsi
+ create mode 100644 arch/arm/boot/dts/bcm2835-rpi-cm.dts
+ create mode 100644 arch/arm/boot/dts/bcm2835-rpi-cm.dtsi
+ create mode 100644 arch/arm/boot/dts/overlays/Makefile
+ create mode 100644 arch/arm/boot/dts/overlays/README
+ create mode 100644 arch/arm/boot/dts/overlays/ads7846-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/bmp085_i2c-sensor-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/dht11-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/enc28j60-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/hifiberry-amp-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/hifiberry-dac-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/hifiberry-digi-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/hy28a-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/hy28b-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/i2s-mmap-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/lirc-rpi-overlay.dts
+ create mode 100755 arch/arm/boot/dts/overlays/mcp2515-can0-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/mcp2515-can1-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/mmc-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/mz61581-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/piscreen-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/pitft28-resistive-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/pps-gpio-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/pwm-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/raspidac3-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/rpi-dac-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/rpi-display-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/rpi-ft5406-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/rpi-proto-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/rpi-sense-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/sdhost-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/sdio-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/smi-dev-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/smi-nand-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/smi-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/spi-gpio35-39-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/tinylcd35-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/uart1-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/vga666-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/w1-gpio-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/w1-gpio-pullup-overlay.dts
+
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -1,5 +1,25 @@
+ ifeq ($(CONFIG_OF),y)
+
++dtb-$(CONFIG_ARCH_BCM2708) += bcm2708-rpi-b.dtb
++dtb-$(CONFIG_ARCH_BCM2708) += bcm2708-rpi-b-plus.dtb
++dtb-$(CONFIG_ARCH_BCM2708) += bcm2708-rpi-cm.dtb
++dtb-$(CONFIG_ARCH_BCM2835) += bcm2835-rpi-cm.dtb
++dtb-$(CONFIG_ARCH_BCM2709) += bcm2709-rpi-2-b.dtb
++
++# Raspberry Pi
++ifeq ($(CONFIG_ARCH_BCM2708),y)
++ RPI_DT_OVERLAYS=y
++endif
++ifeq ($(CONFIG_ARCH_BCM2709),y)
++ RPI_DT_OVERLAYS=y
++endif
++ifeq ($(CONFIG_ARCH_BCM2835),y)
++ RPI_DT_OVERLAYS=y
++endif
++ifeq ($(RPI_DT_OVERLAYS),y)
++ dts-dirs += overlays
++endif
++
+ dtb-$(CONFIG_ARCH_ALPINE) += \
+ alpine-db.dtb
+ dtb-$(CONFIG_MACH_ASM9260) += \
+@@ -777,10 +797,20 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \
+ mt8127-moose.dtb \
+ mt8135-evbp1.dtb
+ dtb-$(CONFIG_ARCH_ZX) += zx296702-ad1.dtb
++
++targets += dtbs dtbs_install
++targets += $(dtb-y)
++
+ endif
+
+ dtstree := $(srctree)/$(src)
+ dtb-$(CONFIG_OF_ALL_DTBS) := $(patsubst $(dtstree)/%.dts,%.dtb, $(wildcard $(dtstree)/*.dts))
+
+ always := $(dtb-y)
++subdir-y := $(dts-dirs)
+ clean-files := *.dtb
++
++# Enable fixups to support overlays on BCM2708 platforms
++ifeq ($(RPI_DT_OVERLAYS),y)
++ DTC_FLAGS ?= -@
++endif
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
+@@ -0,0 +1,145 @@
++/dts-v1/;
++
++#include "bcm2708.dtsi"
++
++/ {
++ compatible = "brcm,bcm2708";
++ model = "Raspberry Pi Model B+";
++};
++
++&gpio {
++ sdhost_pins: sdhost_pins {
++ brcm,pins = <48 49 50 51 52 53>;
++ brcm,function = <4>; /* alt0 */
++ };
++
++ spi0_pins: spi0_pins {
++ brcm,pins = <9 10 11>;
++ brcm,function = <4>; /* alt0 */
++ };
++
++ spi0_cs_pins: spi0_cs_pins {
++ brcm,pins = <8 7>;
++ brcm,function = <1>; /* output */
++ };
++
++ i2c0_pins: i2c0 {
++ brcm,pins = <0 1>;
++ brcm,function = <4>;
++ };
++
++ i2c1_pins: i2c1 {
++ brcm,pins = <2 3>;
++ brcm,function = <4>;
++ };
++
++ i2s_pins: i2s {
++ brcm,pins = <18 19 20 21>;
++ brcm,function = <4>; /* alt0 */
++ };
++};
++
++&sdhost {
++ pinctrl-names = "default";
++ pinctrl-0 = <&sdhost_pins>;
++ bus-width = <4>;
++ status = "okay";
++};
++
++&fb {
++ status = "okay";
++};
++
++&uart0 {
++ status = "okay";
++};
++
++&spi0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi0_pins &spi0_cs_pins>;
++ cs-gpios = <&gpio 8 1>, <&gpio 7 1>;
++
++ spidev@0{
++ compatible = "spidev";
++ reg = <0>; /* CE0 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <500000>;
++ };
++
++ spidev@1{
++ compatible = "spidev";
++ reg = <1>; /* CE1 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <500000>;
++ };
++};
++
++&i2c0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c0_pins>;
++ clock-frequency = <100000>;
++};
++
++&i2c1 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c1_pins>;
++ clock-frequency = <100000>;
++};
++
++&i2c2 {
++ clock-frequency = <100000>;
++};
++
++&i2s {
++ #sound-dai-cells = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2s_pins>;
++};
++
++&random {
++ status = "okay";
++};
++
++&leds {
++ act_led: act {
++ label = "led0";
++ linux,default-trigger = "mmc0";
++ gpios = <&gpio 47 0>;
++ };
++
++ pwr_led: pwr {
++ label = "led1";
++ linux,default-trigger = "input";
++ gpios = <&gpio 35 0>;
++ };
++};
++
++/ {
++ __overrides__ {
++ uart0 = <&uart0>,"status";
++ uart0_clkrate = <&clk_uart0>,"clock-frequency:0";
++ i2s = <&i2s>,"status";
++ spi = <&spi0>,"status";
++ i2c0 = <&i2c0>,"status";
++ i2c1 = <&i2c1>,"status";
++ i2c2_iknowwhatimdoing = <&i2c2>,"status";
++ i2c0_baudrate = <&i2c0>,"clock-frequency:0";
++ i2c1_baudrate = <&i2c1>,"clock-frequency:0";
++ i2c2_baudrate = <&i2c2>,"clock-frequency:0";
++ core_freq = <&clk_core>,"clock-frequency:0";
++
++ act_led_gpio = <&act_led>,"gpios:4";
++ act_led_activelow = <&act_led>,"gpios:8";
++ act_led_trigger = <&act_led>,"linux,default-trigger";
++
++ pwr_led_gpio = <&pwr_led>,"gpios:4";
++ pwr_led_activelow = <&pwr_led>,"gpios:8";
++ pwr_led_trigger = <&pwr_led>,"linux,default-trigger";
++
++ audio = <&audio>,"status";
++ watchdog = <&watchdog>,"status";
++ random = <&random>,"status";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2708-rpi-b.dts
+@@ -0,0 +1,135 @@
++/dts-v1/;
++
++#include "bcm2708.dtsi"
++
++/ {
++ compatible = "brcm,bcm2708";
++ model = "Raspberry Pi Model B";
++};
++
++&gpio {
++ sdhost_pins: sdhost_pins {
++ brcm,pins = <48 49 50 51 52 53>;
++ brcm,function = <4>; /* alt0 */
++ };
++
++ spi0_pins: spi0_pins {
++ brcm,pins = <9 10 11>;
++ brcm,function = <4>; /* alt0 */
++ };
++
++ spi0_cs_pins: spi0_cs_pins {
++ brcm,pins = <8 7>;
++ brcm,function = <1>; /* output */
++ };
++
++ i2c0_pins: i2c0 {
++ brcm,pins = <0 1>;
++ brcm,function = <4>;
++ };
++
++ i2c1_pins: i2c1 {
++ brcm,pins = <2 3>;
++ brcm,function = <4>;
++ };
++
++ i2s_pins: i2s {
++ brcm,pins = <28 29 30 31>;
++ brcm,function = <6>; /* alt2 */
++ };
++};
++
++&sdhost {
++ pinctrl-names = "default";
++ pinctrl-0 = <&sdhost_pins>;
++ bus-width = <4>;
++ status = "okay";
++};
++
++&fb {
++ status = "okay";
++};
++
++&uart0 {
++ status = "okay";
++};
++
++&spi0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi0_pins &spi0_cs_pins>;
++ cs-gpios = <&gpio 8 1>, <&gpio 7 1>;
++
++ spidev@0{
++ compatible = "spidev";
++ reg = <0>; /* CE0 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <500000>;
++ };
++
++ spidev@1{
++ compatible = "spidev";
++ reg = <1>; /* CE1 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <500000>;
++ };
++};
++
++&i2c0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c0_pins>;
++ clock-frequency = <100000>;
++};
++
++&i2c1 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c1_pins>;
++ clock-frequency = <100000>;
++};
++
++&i2c2 {
++ clock-frequency = <100000>;
++};
++
++&i2s {
++ #sound-dai-cells = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2s_pins>;
++};
++
++&random {
++ status = "okay";
++};
++
++&leds {
++ act_led: act {
++ label = "led0";
++ linux,default-trigger = "mmc0";
++ gpios = <&gpio 16 1>;
++ };
++};
++
++/ {
++ __overrides__ {
++ uart0 = <&uart0>,"status";
++ uart0_clkrate = <&clk_uart0>,"clock-frequency:0";
++ i2s = <&i2s>,"status";
++ spi = <&spi0>,"status";
++ i2c0 = <&i2c0>,"status";
++ i2c1 = <&i2c1>,"status";
++ i2c2_iknowwhatimdoing = <&i2c2>,"status";
++ i2c0_baudrate = <&i2c0>,"clock-frequency:0";
++ i2c1_baudrate = <&i2c1>,"clock-frequency:0";
++ i2c2_baudrate = <&i2c2>,"clock-frequency:0";
++ core_freq = <&clk_core>,"clock-frequency:0";
++
++ act_led_gpio = <&act_led>,"gpios:4";
++ act_led_activelow = <&act_led>,"gpios:8";
++ act_led_trigger = <&act_led>,"linux,default-trigger";
++
++ audio = <&audio>,"status";
++ watchdog = <&watchdog>,"status";
++ random = <&random>,"status";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dts
+@@ -0,0 +1,102 @@
++/dts-v1/;
++
++#include "bcm2708-rpi-cm.dtsi"
++
++/ {
++ model = "Raspberry Pi Compute Module";
++};
++
++&uart0 {
++ status = "okay";
++};
++
++&gpio {
++ spi0_pins: spi0_pins {
++ brcm,pins = <9 10 11>;
++ brcm,function = <4>; /* alt0 */
++ };
++
++ spi0_cs_pins: spi0_cs_pins {
++ brcm,pins = <8 7>;
++ brcm,function = <1>; /* output */
++ };
++
++ i2c0_pins: i2c0 {
++ brcm,pins = <0 1>;
++ brcm,function = <4>;
++ };
++
++ i2c1_pins: i2c1 {
++ brcm,pins = <2 3>;
++ brcm,function = <4>;
++ };
++
++ i2s_pins: i2s {
++ brcm,pins = <18 19 20 21>;
++ brcm,function = <4>; /* alt0 */
++ };
++};
++
++&spi0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi0_pins &spi0_cs_pins>;
++ cs-gpios = <&gpio 8 1>, <&gpio 7 1>;
++
++ spidev@0{
++ compatible = "spidev";
++ reg = <0>; /* CE0 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <500000>;
++ };
++
++ spidev@1{
++ compatible = "spidev";
++ reg = <1>; /* CE1 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <500000>;
++ };
++};
++
++&i2c0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c0_pins>;
++ clock-frequency = <100000>;
++};
++
++&i2c1 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c1_pins>;
++ clock-frequency = <100000>;
++};
++
++&i2c2 {
++ clock-frequency = <100000>;
++};
++
++&i2s {
++ #sound-dai-cells = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2s_pins>;
++};
++
++&random {
++ status = "okay";
++};
++
++/ {
++ __overrides__ {
++ uart0 = <&uart0>,"status";
++ uart0_clkrate = <&clk_uart0>,"clock-frequency:0";
++ i2s = <&i2s>,"status";
++ spi = <&spi0>,"status";
++ i2c0 = <&i2c0>,"status";
++ i2c1 = <&i2c1>,"status";
++ i2c2_iknowwhatimdoing = <&i2c2>,"status";
++ i2c0_baudrate = <&i2c0>,"clock-frequency:0";
++ i2c1_baudrate = <&i2c1>,"clock-frequency:0";
++ i2c2_baudrate = <&i2c2>,"clock-frequency:0";
++ core_freq = <&clk_core>,"clock-frequency:0";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi
+@@ -0,0 +1,40 @@
++#include "bcm2708.dtsi"
++
++&gpio {
++ sdhost_pins: sdhost_pins {
++ brcm,pins = <48 49 50 51 52 53>;
++ brcm,function = <4>; /* alt0 */
++ };
++};
++
++&leds {
++ act_led: act {
++ label = "led0";
++ linux,default-trigger = "mmc0";
++ gpios = <&gpio 47 0>;
++ };
++};
++
++&sdhost {
++ pinctrl-names = "default";
++ pinctrl-0 = <&sdhost_pins>;
++ bus-width = <4>;
++ non-removable;
++ status = "okay";
++};
++
++&fb {
++ status = "okay";
++};
++
++/ {
++ __overrides__ {
++ act_led_gpio = <&act_led>,"gpios:4";
++ act_led_activelow = <&act_led>,"gpios:8";
++ act_led_trigger = <&act_led>,"linux,default-trigger";
++
++ audio = <&audio>,"status";
++ watchdog = <&watchdog>,"status";
++ random = <&random>,"status";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2708.dtsi
+@@ -0,0 +1,40 @@
++#include "bcm2708_common.dtsi"
++
++/ {
++ compatible = "brcm,bcm2708";
++ model = "BCM2708";
++
++ chosen {
++ /* No padding required - the boot loader can do that. */
++ bootargs = "";
++ };
++
++ soc {
++ ranges = <0x7e000000 0x20000000 0x01000000>;
++
++ timer@7e003000 {
++ compatible = "brcm,bcm2835-system-timer";
++ reg = <0x7e003000 0x1000>;
++ interrupts = <1 0>, <1 1>, <1 2>, <1 3>;
++ clock-frequency = <1000000>;
++ };
++
++ arm-pmu {
++ compatible = "arm,arm1176-pmu";
++ };
++
++ gpiomem {
++ compatible = "brcm,bcm2835-gpiomem";
++ reg = <0x7e200000 0x1000>;
++ status = "okay";
++ };
++ };
++};
++
++&intc {
++ compatible = "brcm,bcm2835-armctrl-ic";
++};
++
++&watchdog {
++ status = "okay";
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2708_common.dtsi
+@@ -0,0 +1,347 @@
++#include "skeleton.dtsi"
++
++/ {
++ interrupt-parent = <&intc>;
++
++ aliases {
++ audio = &audio;
++ sound = &sound;
++ soc = &soc;
++ dma = &dma;
++ intc = &intc;
++ watchdog = &watchdog;
++ random = &random;
++ mailbox = &mailbox;
++ gpio = &gpio;
++ uart0 = &uart0;
++ sdhost = &sdhost;
++ i2s = &i2s;
++ spi0 = &spi0;
++ i2c0 = &i2c0;
++ uart1 = &uart1;
++ mmc = &mmc;
++ i2c1 = &i2c1;
++ i2c2 = &i2c2;
++ usb = &usb;
++ leds = &leds;
++ fb = &fb;
++ vchiq = &vchiq;
++ thermal = &thermal;
++ clocks = &clocks;
++ };
++
++ /* Onboard audio */
++ audio: audio {
++ compatible = "brcm,bcm2835-audio";
++ brcm,pwm-channels = <8>;
++ status = "disabled";
++ };
++
++ /* External sound card */
++ sound: sound {
++ };
++
++ soc: soc {
++ compatible = "simple-bus";
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ dma: dma@7e007000 {
++ compatible = "brcm,bcm2835-dma";
++ reg = <0x7e007000 0xf00>;
++ interrupts = <1 16>,
++ <1 17>,
++ <1 18>,
++ <1 19>,
++ <1 20>,
++ <1 21>,
++ <1 22>,
++ <1 23>,
++ <1 24>,
++ <1 25>,
++ <1 26>,
++ <1 27>;
++
++ #dma-cells = <1>;
++ brcm,dma-channel-mask = <0x0f35>;
++ };
++
++ intc: interrupt-controller@7e00b200 {
++ compatible = "brcm,bcm2708-armctrl-ic";
++ reg = <0x7e00b200 0x200>;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
++
++ mailbox: mailbox@7e00b800 {
++ compatible = "brcm,bcm2835-mbox";
++ reg = <0x7e00b880 0x40>;
++ interrupts = <0 1>;
++ #mbox-cells = <0>;
++ };
++
++ watchdog: watchdog@7e100000 {
++ compatible = "brcm,bcm2835-pm-wdt";
++ reg = <0x7e100000 0x28>;
++ status = "disabled";
++ };
++
++ cprman: cprman@7e101000 {
++ compatible = "brcm,bcm2835-cprman";
++ #clock-cells = <1>;
++ reg = <0x7e101000 0x2000>;
++
++ /* CPRMAN derives everything from the platform's
++ * oscillator.
++ */
++ clocks = <&clk_osc>;
++ status = "disabled";
++ };
++
++ random: rng@7e104000 {
++ compatible = "brcm,bcm2835-rng";
++ reg = <0x7e104000 0x10>;
++ status = "disabled";
++ };
++
++ gpio: gpio@7e200000 {
++ compatible = "brcm,bcm2835-gpio";
++ reg = <0x7e200000 0xb4>;
++ interrupts = <2 17>, <2 18>;
++
++ gpio-controller;
++ #gpio-cells = <2>;
++
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
++
++ uart0: uart@7e201000 {
++ compatible = "arm,pl011", "arm,primecell";
++ reg = <0x7e201000 0x1000>;
++ interrupts = <2 25>;
++ clocks = <&clk_uart0 &clk_apb_p>;
++ clock-names = "uartclk","apb_pclk";
++ arm,primecell-periphid = <0x00241011>; // For an explanation, see
++ // https://github.com/raspberrypi/linux/commit/13731d862cf5219216533a3b0de052cee4cc5038
++ status = "disabled";
++ };
++
++ sdhost: sdhost@7e202000 {
++ compatible = "brcm,bcm2835-sdhost";
++ reg = <0x7e202000 0x100>;
++ interrupts = <2 24>;
++ clocks = <&clk_core>;
++ dmas = <&dma 13>,
++ <&dma 13>;
++ dma-names = "tx", "rx";
++ brcm,pio-limit = <1>;
++ status = "disabled";
++ };
++
++ i2s: i2s@7e203000 {
++ compatible = "brcm,bcm2835-i2s";
++ reg = <0x7e203000 0x24>,
++ <0x7e101098 0x08>;
++
++ dmas = <&dma 2>, <&dma 3>;
++ dma-names = "tx", "rx";
++ status = "disabled";
++ };
++
++ spi0: spi@7e204000 {
++ compatible = "brcm,bcm2835-spi";
++ reg = <0x7e204000 0x1000>;
++ interrupts = <2 22>;
++ clocks = <&clk_core>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ /* the dma channels */
++ dmas = <&dma 6>, <&dma 7>;
++ dma-names = "tx", "rx";
++ /* the chipselects used - <0> means native GPIO
++ * add more gpios if necessary as <&gpio 6 1>
++ * (but do not forget to make them output!)
++ */
++ cs-gpios = <0>, <0>;
++ };
++
++ i2c0: i2c@7e205000 {
++ compatible = "brcm,bcm2708-i2c";
++ reg = <0x7e205000 0x1000>;
++ interrupts = <2 21>;
++ clocks = <&clk_core>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ pwm: pwm@7e20c000 {
++ compatible = "brcm,bcm2835-pwm";
++ reg = <0x7e20c000 0x28>;
++ clocks = <&clk_pwm>;
++ #pwm-cells = <2>;
++ status = "disabled";
++ };
++
++ uart1: uart@7e215040 {
++ compatible = "brcm,bcm2835-aux-uart", "ns16550";
++ reg = <0x7e215040 0x40>;
++ interrupts = <1 29>;
++ clocks = <&clk_uart1>;
++ reg-shift = <2>;
++ no-loopback-test;
++ status = "disabled";
++ };
++
++ mmc: mmc@7e300000 {
++ compatible = "brcm,bcm2835-mmc";
++ reg = <0x7e300000 0x100>;
++ interrupts = <2 30>;
++ clocks = <&clk_mmc>;
++ dmas = <&dma 11>,
++ <&dma 11>;
++ dma-names = "tx", "rx";
++ status = "disabled";
++ };
++
++ i2c1: i2c@7e804000 {
++ compatible = "brcm,bcm2708-i2c";
++ reg = <0x7e804000 0x1000>;
++ interrupts = <2 21>;
++ clocks = <&clk_core>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ i2c2: i2c@7e805000 {
++ // Beware - this is shared with the HDMI module.
++ // Careless use may break (really) your display.
++ // Caveat emptor.
++ compatible = "brcm,bcm2708-i2c";
++ reg = <0x7e805000 0x1000>;
++ interrupts = <2 21>;
++ clocks = <&clk_core>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ smi: smi@7e600000 {
++ compatible = "brcm,bcm2835-smi";
++ reg = <0x7e600000 0x44>, <0x7e1010b0 0x8>;
++ interrupts = <2 16>;
++ brcm,smi-clock-source = <6>;
++ brcm,smi-clock-divisor = <4>;
++ dmas = <&dma 4>;
++ dma-names = "rx-tx";
++ status = "disabled";
++ };
++
++ usb: usb@7e980000 {
++ compatible = "brcm,bcm2708-usb";
++ reg = <0x7e980000 0x10000>,
++ <0x7e006000 0x1000>;
++ interrupts = <2 0>,
++ <1 9>;
++ };
++
++ firmware: firmware {
++ compatible = "raspberrypi,bcm2835-firmware";
++ mboxes = <&mailbox>;
++ };
++
++ leds: leds {
++ compatible = "gpio-leds";
++ };
++
++ fb: fb {
++ compatible = "brcm,bcm2708-fb";
++ firmware = <&firmware>;
++ status = "disabled";
++ };
++
++ vchiq: vchiq {
++ compatible = "brcm,bcm2835-vchiq";
++ reg = <0x7e00b840 0xf>;
++ interrupts = <0 2>;
++ cache-line-size = <32>;
++ firmware = <&firmware>;
++ };
++
++ thermal: thermal {
++ compatible = "brcm,bcm2835-thermal";
++ firmware = <&firmware>;
++ };
++ };
++
++ clocks: clocks {
++ compatible = "simple-bus";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ clk_core: clock@0 {
++ compatible = "fixed-clock";
++ reg = <0>;
++ #clock-cells = <0>;
++ clock-output-names = "core";
++ clock-frequency = <250000000>;
++ };
++
++ clk_mmc: clock@1 {
++ compatible = "fixed-clock";
++ reg = <1>;
++ #clock-cells = <0>;
++ clock-output-names = "mmc";
++ clock-frequency = <250000000>;
++ };
++
++ clk_uart0: clock@2 {
++ compatible = "fixed-clock";
++ reg = <2>;
++ #clock-cells = <0>;
++ clock-output-names = "uart0_pclk";
++ clock-frequency = <3000000>;
++ };
++
++ clk_apb_p: clock@3 {
++ compatible = "fixed-clock";
++ reg = <3>;
++ #clock-cells = <0>;
++ clock-output-names = "apb_pclk";
++ clock-frequency = <126000000>;
++ };
++
++ clk_pwm: clock@4 {
++ compatible = "fixed-clock";
++ reg = <4>;
++ #clock-cells = <0>;
++ clock-output-names = "pwm";
++ clock-frequency = <100000000>;
++ };
++
++ clk_uart1: clock@5 {
++ compatible = "fixed-factor-clock";
++ reg = <5>;
++ clocks = <&clk_core>;
++ #clock-cells = <0>;
++ clock-div = <1>;
++ clock-mult = <2>;
++ };
++
++ /* The oscillator is the root of the clock tree. */
++ clk_osc: clock@6 {
++ compatible = "fixed-clock";
++ reg = <6>;
++ #clock-cells = <0>;
++ clock-output-names = "osc";
++ clock-frequency = <19200000>;
++ };
++ };
++
++ __overrides__ {
++ cache_line_size = <&vchiq>, "cache-line-size:0";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts
+@@ -0,0 +1,145 @@
++/dts-v1/;
++
++#include "bcm2709.dtsi"
++
++/ {
++ compatible = "brcm,bcm2709";
++ model = "Raspberry Pi 2 Model B";
++};
++
++&gpio {
++ sdhost_pins: sdhost_pins {
++ brcm,pins = <48 49 50 51 52 53>;
++ brcm,function = <4>; /* alt0 */
++ };
++
++ spi0_pins: spi0_pins {
++ brcm,pins = <9 10 11>;
++ brcm,function = <4>; /* alt0 */
++ };
++
++ spi0_cs_pins: spi0_cs_pins {
++ brcm,pins = <8 7>;
++ brcm,function = <1>; /* output */
++ };
++
++ i2c0_pins: i2c0 {
++ brcm,pins = <0 1>;
++ brcm,function = <4>;
++ };
++
++ i2c1_pins: i2c1 {
++ brcm,pins = <2 3>;
++ brcm,function = <4>;
++ };
++
++ i2s_pins: i2s {
++ brcm,pins = <18 19 20 21>;
++ brcm,function = <4>; /* alt0 */
++ };
++};
++
++&sdhost {
++ pinctrl-names = "default";
++ pinctrl-0 = <&sdhost_pins>;
++ bus-width = <4>;
++ status = "okay";
++};
++
++&fb {
++ status = "okay";
++};
++
++&uart0 {
++ status = "okay";
++};
++
++&spi0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi0_pins &spi0_cs_pins>;
++ cs-gpios = <&gpio 8 1>, <&gpio 7 1>;
++
++ spidev@0{
++ compatible = "spidev";
++ reg = <0>; /* CE0 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <500000>;
++ };
++
++ spidev@1{
++ compatible = "spidev";
++ reg = <1>; /* CE1 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <500000>;
++ };
++};
++
++&i2c0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c0_pins>;
++ clock-frequency = <100000>;
++};
++
++&i2c1 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c1_pins>;
++ clock-frequency = <100000>;
++};
++
++&i2c2 {
++ clock-frequency = <100000>;
++};
++
++&i2s {
++ #sound-dai-cells = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2s_pins>;
++};
++
++&random {
++ status = "okay";
++};
++
++&leds {
++ act_led: act {
++ label = "led0";
++ linux,default-trigger = "mmc0";
++ gpios = <&gpio 47 0>;
++ };
++
++ pwr_led: pwr {
++ label = "led1";
++ linux,default-trigger = "input";
++ gpios = <&gpio 35 0>;
++ };
++};
++
++/ {
++ __overrides__ {
++ uart0 = <&uart0>,"status";
++ uart0_clkrate = <&clk_uart0>,"clock-frequency:0";
++ i2s = <&i2s>,"status";
++ spi = <&spi0>,"status";
++ i2c0 = <&i2c0>,"status";
++ i2c1 = <&i2c1>,"status";
++ i2c2_iknowwhatimdoing = <&i2c2>,"status";
++ i2c0_baudrate = <&i2c0>,"clock-frequency:0";
++ i2c1_baudrate = <&i2c1>,"clock-frequency:0";
++ i2c2_baudrate = <&i2c2>,"clock-frequency:0";
++ core_freq = <&clk_core>,"clock-frequency:0";
++
++ act_led_gpio = <&act_led>,"gpios:4";
++ act_led_activelow = <&act_led>,"gpios:8";
++ act_led_trigger = <&act_led>,"linux,default-trigger";
++
++ pwr_led_gpio = <&pwr_led>,"gpios:4";
++ pwr_led_activelow = <&pwr_led>,"gpios:8";
++ pwr_led_trigger = <&pwr_led>,"linux,default-trigger";
++
++ audio = <&audio>,"status";
++ watchdog = <&watchdog>,"status";
++ random = <&random>,"status";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2709.dtsi
+@@ -0,0 +1,102 @@
++#include "bcm2708_common.dtsi"
++
++/ {
++ compatible = "brcm,bcm2709";
++ model = "BCM2709";
++
++ chosen {
++ /* No padding required - the boot loader can do that. */
++ bootargs = "";
++ };
++
++ soc {
++ ranges = <0x7e000000 0x3f000000 0x01000000>,
++ <0x40000000 0x40000000 0x00040000>;
++
++ local_intc: local_intc {
++ compatible = "brcm,bcm2836-l1-intc";
++ reg = <0x40000000 0x100>;
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ interrupt-parent = <&local_intc>;
++ };
++
++ arm-pmu {
++ compatible = "arm,cortex-a7-pmu";
++ interrupt-parent = <&local_intc>;
++ interrupts = <9>;
++ };
++
++ gpiomem {
++ compatible = "brcm,bcm2835-gpiomem";
++ reg = <0x7e200000 0x1000>;
++ status = "okay";
++ };
++
++ timer {
++ compatible = "arm,armv7-timer";
++ clock-frequency = <19200000>;
++ interrupt-parent = <&local_intc>;
++ interrupts = <0>, // PHYS_SECURE_PPI
++ <1>, // PHYS_NONSECURE_PPI
++ <3>, // VIRT_PPI
++ <2>; // HYP_PPI
++ always-on;
++ };
++
++ syscon@40000000 {
++ compatible = "brcm,bcm2836-arm-local", "syscon";
++ reg = <0x40000000 0x100>;
++ };
++ };
++
++ cpus: cpus {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ v7_cpu0: cpu@0 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a7";
++ reg = <0xf00>;
++ clock-frequency = <800000000>;
++ };
++
++ v7_cpu1: cpu@1 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a7";
++ reg = <0xf01>;
++ clock-frequency = <800000000>;
++ };
++
++ v7_cpu2: cpu@2 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a7";
++ reg = <0xf02>;
++ clock-frequency = <800000000>;
++ };
++
++ v7_cpu3: cpu@3 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a7";
++ reg = <0xf03>;
++ clock-frequency = <800000000>;
++ };
++ };
++
++ __overrides__ {
++ arm_freq = <&v7_cpu0>, "clock-frequency:0",
++ <&v7_cpu1>, "clock-frequency:0",
++ <&v7_cpu2>, "clock-frequency:0",
++ <&v7_cpu3>, "clock-frequency:0";
++ };
++};
++
++&watchdog {
++ status = "okay";
++};
++
++&intc {
++ compatible = "brcm,bcm2836-armctrl-ic";
++ interrupt-parent = <&local_intc>;
++ interrupts = <8>;
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2835-rpi-cm.dts
+@@ -0,0 +1,93 @@
++/dts-v1/;
++
++#include "bcm2835-rpi-cm.dtsi"
++
++/ {
++ model = "Raspberry Pi Compute Module";
++};
++
++&uart0 {
++ status = "okay";
++};
++
++&gpio {
++ spi0_pins: spi0_pins {
++ brcm,pins = <7 8 9 10 11>;
++ brcm,function = <4>; /* alt0 */
++ };
++
++ i2c0_pins: i2c0 {
++ brcm,pins = <0 1>;
++ brcm,function = <4>;
++ };
++
++ i2c1_pins: i2c1 {
++ brcm,pins = <2 3>;
++ brcm,function = <4>;
++ };
++
++ i2s_pins: i2s {
++ brcm,pins = <18 19 20 21>;
++ brcm,function = <4>; /* alt0 */
++ };
++};
++
++&spi0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi0_pins>;
++
++ spidev@0{
++ compatible = "spidev";
++ reg = <0>; /* CE0 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <500000>;
++ };
++
++ spidev@1{
++ compatible = "spidev";
++ reg = <1>; /* CE1 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <500000>;
++ };
++};
++
++&i2c0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c0_pins>;
++ clock-frequency = <100000>;
++};
++
++&i2c1 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c1_pins>;
++ clock-frequency = <100000>;
++};
++
++&i2c2 {
++ clock-frequency = <100000>;
++};
++
++&i2s {
++ #sound-dai-cells = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2s_pins>;
++};
++
++/ {
++ __overrides__ {
++ uart0 = <&uart0>,"status";
++ uart0_clkrate = <&clk_uart0>,"clock-frequency:0";
++ uart1_clkrate = <&uart1>,"clock-frequency:0";
++ i2s = <&i2s>,"status";
++ spi = <&spi0>,"status";
++ i2c0 = <&i2c0>,"status";
++ i2c1 = <&i2c1>,"status";
++ i2c2_iknowwhatimdoing = <&i2c2>,"status";
++ i2c0_baudrate = <&i2c0>,"clock-frequency:0";
++ i2c1_baudrate = <&i2c1>,"clock-frequency:0";
++ i2c2_baudrate = <&i2c2>,"clock-frequency:0";
++ core_freq = <&clk_core>,"clock-frequency:0";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2835-rpi-cm.dtsi
+@@ -0,0 +1,30 @@
++#include "bcm2835.dtsi"
++
++&leds {
++ act_led: act {
++ label = "led0";
++ linux,default-trigger = "mmc0";
++ gpios = <&gpio 47 0>;
++ };
++};
++
++&mmc {
++ status = "okay";
++ bus-width = <4>;
++};
++
++&fb {
++ status = "okay";
++};
++
++/ {
++ __overrides__ {
++ act_led_gpio = <&act_led>,"gpios:4";
++ act_led_activelow = <&act_led>,"gpios:8";
++ act_led_trigger = <&act_led>,"linux,default-trigger";
++
++ audio = <&audio>,"status";
++ watchdog = <&watchdog>,"status";
++ random = <&random>,"status";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -0,0 +1,69 @@
++ifeq ($(CONFIG_OF),y)
++
++# Overlays for the Raspberry Pi platform
++
++ifeq ($(CONFIG_ARCH_BCM2708),y)
++ RPI_DT_OVERLAYS=y
++endif
++ifeq ($(CONFIG_ARCH_BCM2709),y)
++ RPI_DT_OVERLAYS=y
++endif
++ifeq ($(CONFIG_ARCH_BCM2835),y)
++ RPI_DT_OVERLAYS=y
++endif
++
++dtb-$(RPI_DT_OVERLAYS) += ads7846-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += bmp085_i2c-sensor-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += dht11-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += enc28j60-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += gpio-poweroff-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += hifiberry-amp-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += hifiberry-dac-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += hifiberry-dacplus-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += hifiberry-digi-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += hy28a-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += hy28b-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += i2c-rtc-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += i2s-mmap-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += iqaudio-dac-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += iqaudio-dacplus-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += lirc-rpi-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += mcp2515-can0-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += mcp2515-can1-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += mmc-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += mz61581-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += piscreen-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += pitft28-resistive-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += pps-gpio-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += pwm-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += pwm-2chan-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += raspidac3-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += rpi-dac-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += rpi-display-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += rpi-ft5406-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += rpi-proto-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += rpi-sense-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += sdhost-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += sdio-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += smi-dev-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += smi-nand-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += smi-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += spi-gpio35-39-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += tinylcd35-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += uart1-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += vga666-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += w1-gpio-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += w1-gpio-pullup-overlay.dtb
++
++targets += dtbs dtbs_install
++targets += $(dtb-y)
++
++endif
++
++always := $(dtb-y)
++clean-files := *.dtb
++
++# Enable fixups to support overlays on BCM2708 platforms
++ifeq ($(RPI_DT_OVERLAYS),y)
++ DTC_FLAGS ?= -@
++endif
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/README
+@@ -0,0 +1,648 @@
++Introduction
++============
++
++This directory contains Device Tree overlays. Device Tree makes it possible
++to support many hardware configurations with a single kernel and without the
++need to explicitly load or blacklist kernel modules. Note that this isn't a
++"pure" Device Tree configuration (c.f. MACH_BCM2835) - some on-board devices
++are still configured by the board support code, but the intention is to
++eventually reach that goal.
++
++On Raspberry Pi, Device Tree usage is controlled from /boot/config.txt. By
++default, the Raspberry Pi kernel boots with device tree enabled. You can
++completely disable DT usage (for now) by adding:
++
++ device_tree=
++
++to your config.txt, which should cause your Pi to revert to the old way of
++doing things after a reboot.
++
++In /boot you will find a .dtb for each base platform. This describes the
++hardware that is part of the Raspberry Pi board. The loader (start.elf and its
++siblings) selects the .dtb file appropriate for the platform by name, and reads
++it into memory. At this point, all of the optional interfaces (i2c, i2s, spi)
++are disabled, but they can be enabled using Device Tree parameters:
++
++ dtparam=i2c=on,i2s=on,spi=on
++
++However, this shouldn't be necessary in many use cases because loading an
++overlay that requires one of those interfaces will cause it to be enabled
++automatically, and it is advisable to only enable interfaces if they are
++needed.
++
++Configuring additional, optional hardware is done using Device Tree overlays
++(see below).
++
++raspi-config
++============
++
++The Advanced Options section of the raspi-config utility can enable and disable
++Device Tree use, as well as toggling the I2C and SPI interfaces. Note that it
++is possible to both enable an interface and blacklist the driver, if for some
++reason you should want to defer the loading.
++
++Modules
++=======
++
++As well as describing the hardware, Device Tree also gives enough information
++to allow suitable driver modules to be located and loaded, with the corollary
++that unneeded modules are not loaded. As a result it should be possible to
++remove lines from /etc/modules, and /etc/modprobe.d/raspi-blacklist.conf can
++have its contents deleted (or commented out).
++
++Using Overlays
++==============
++
++Overlays are loaded using the "dtoverlay" directive. As an example, consider the
++popular lirc-rpi module, the Linux Infrared Remote Control driver. In the
++pre-DT world this would be loaded from /etc/modules, with an explicit
++"modprobe lirc-rpi" command, or programmatically by lircd. With DT enabled,
++this becomes a line in config.txt:
++
++ dtoverlay=lirc-rpi
++
++This causes the file /boot/overlays/lirc-rpi-overlay.dtb to be loaded. By
++default it will use GPIOs 17 (out) and 18 (in), but this can be modified using
++DT parameters:
++
++ dtoverlay=lirc-rpi,gpio_out_pin=17,gpio_in_pin=13
++
++Parameters always have default values, although in some cases (e.g. "w1-gpio")
++it is necessary to provided multiple overlays in order to get the desired
++behaviour. See the list of overlays below for a description of the parameters and their defaults.
++
++The Overlay and Parameter Reference
++===================================
++
++N.B. When editing this file, please preserve the indentation levels to make it simple to parse
++programmatically. NO HARD TABS.
++
++
++Name: <The base DTB>
++Info: Configures the base Raspberry Pi hardware
++Load: <loaded automatically>
++Params:
++ audio Set to "on" to enable the onboard ALSA audio
++ interface (default "off")
++
++ i2c_arm Set to "on" to enable the ARM's i2c interface
++ (default "off")
++
++ i2c_vc Set to "on" to enable the i2c interface
++ usually reserved for the VideoCore processor
++ (default "off")
++
++ i2c An alias for i2c_arm
++
++ i2c_arm_baudrate Set the baudrate of the ARM's i2c interface
++ (default "100000")
++
++ i2c_vc_baudrate Set the baudrate of the VideoCore i2c interface
++ (default "100000")
++
++ i2c_baudrate An alias for i2c_arm_baudrate
++
++ i2s Set to "on" to enable the i2s interface
++ (default "off")
++
++ spi Set to "on" to enable the spi interfaces
++ (default "off")
++
++ random Set to "on" to enable the hardware random
++ number generator (default "on")
++
++ uart0 Set to "off" to disable uart0 (default "on")
++
++ watchdog Set to "on" to enable the hardware watchdog
++ (default "off")
++
++ act_led_trigger Choose which activity the LED tracks.
++ Use "heartbeat" for a nice load indicator.
++ (default "mmc")
++
++ act_led_activelow Set to "on" to invert the sense of the LED
++ (default "off")
++
++ act_led_gpio Set which GPIO to use for the activity LED
++ (in case you want to connect it to an external
++ device)
++ (default "16" on a non-Plus board, "47" on a
++ Plus or Pi 2)
++
++ pwr_led_trigger
++ pwr_led_activelow
++ pwr_led_gpio
++ As for act_led_*, but using the PWR LED.
++ Not available on Model A/B boards.
++
++ N.B. It is recommended to only enable those interfaces that are needed.
++ Leaving all interfaces enabled can lead to unwanted behaviour (i2c_vc
++ interfering with Pi Camera, I2S and SPI hogging GPIO pins, etc.)
++ Note also that i2c, i2c_arm and i2c_vc are aliases for the physical
++ interfaces i2c0 and i2c1. Use of the numeric variants is still possible
++ but deprecated because the ARM/VC assignments differ between board
++ revisions. The same board-specific mapping applies to i2c_baudrate,
++ and the other i2c baudrate parameters.
++
++
++Name: ads7846
++Info: ADS7846 Touch controller
++Load: dtoverlay=ads7846,<param>=<val>
++Params: cs SPI bus Chip Select (default 1)
++ speed SPI bus speed (default 2Mhz, max 3.25MHz)
++ penirq GPIO used for PENIRQ. REQUIRED
++ penirq_pull Set GPIO pull (default 0=none, 2=pullup)
++ swapxy Swap x and y axis
++ xmin Minimum value on the X axis (default 0)
++ ymin Minimum value on the Y axis (default 0)
++ xmax Maximum value on the X axis (default 4095)
++ ymax Maximum value on the Y axis (default 4095)
++ pmin Minimum reported pressure value (default 0)
++ pmax Maximum reported pressure value (default 65535)
++ xohms Touchpanel sensitivity (X-plate resistance)
++ (default 400)
++
++ penirq is required and usually xohms (60-100) has to be set as well.
++ Apart from that, pmax (255) and swapxy are also common.
++ The rest of the calibration can be done with xinput-calibrator.
++ See: github.com/notro/fbtft/wiki/FBTFT-on-Raspian
++ Device Tree binding document:
++ www.kernel.org/doc/Documentation/devicetree/bindings/input/ads7846.txt
++
++
++Name: bmp085_i2c-sensor
++Info: Configures the BMP085/BMP180 digital barometric pressure and temperature
++ sensors from Bosch Sensortec
++Load: dtoverlay=bmp085_i2c-sensor
++Params: <None>
++
++
++Name: dht11
++Info: Overlay for the DHT11/DHT21/DHT22 humidity/temperature sensors
++ Also sometimes found with the part number(s) AM230x.
++Load: dtoverlay=dht11,<param>=<val>
++Params: gpiopin GPIO connected to the sensor's DATA output.
++ (default 4)
++
++
++[ The ds1307-rtc overlay has been deleted. See i2c-rtc. ]
++
++
++Name: enc28j60
++Info: Overlay for the Microchip ENC28J60 Ethernet Controller (SPI)
++Load: dtoverlay=enc28j60,<param>=<val>
++Params: int_pin GPIO used for INT (default 25)
++
++ speed SPI bus speed (default 12000000)
++
++
++Name: gpio-poweroff
++Info: Drives a GPIO high or low on reboot
++Load: dtoverlay=gpio-poweroff,<param>=<val>
++Params: gpiopin GPIO for signalling (default 26)
++
++ active_low Set if the power control device requires a
++ high->low transition to trigger a power-down.
++ Note that this will require the support of a
++ custom dt-blob.bin to prevent a power-down
++ during the boot process, and that a reboot
++ will also cause the pin to go low.
++
++
++Name: hifiberry-amp
++Info: Configures the HifiBerry Amp and Amp+ audio cards
++Load: dtoverlay=hifiberry-amp
++Params: <None>
++
++
++Name: hifiberry-dac
++Info: Configures the HifiBerry DAC audio card
++Load: dtoverlay=hifiberry-dac
++Params: <None>
++
++
++Name: hifiberry-dacplus
++Info: Configures the HifiBerry DAC+ audio card
++Load: dtoverlay=hifiberry-dacplus
++Params: <None>
++
++
++Name: hifiberry-digi
++Info: Configures the HifiBerry Digi audio card
++Load: dtoverlay=hifiberry-digi
++Params: <None>
++
++
++Name: hy28a
++Info: HY28A - 2.8" TFT LCD Display Module by HAOYU Electronics
++ Default values match Texy's display shield
++Load: dtoverlay=hy28a,<param>=<val>
++Params: speed Display SPI bus speed
++
++ rotate Display rotation {0,90,180,270}
++
++ fps Delay between frame updates
++
++ debug Debug output level {0-7}
++
++ xohms Touchpanel sensitivity (X-plate resistance)
++
++ resetgpio GPIO used to reset controller
++
++ ledgpio GPIO used to control backlight
++
++
++Name: hy28b
++Info: HY28B - 2.8" TFT LCD Display Module by HAOYU Electronics
++ Default values match Texy's display shield
++Load: dtoverlay=hy28b,<param>=<val>
++Params: speed Display SPI bus speed
++
++ rotate Display rotation {0,90,180,270}
++
++ fps Delay between frame updates
++
++ debug Debug output level {0-7}
++
++ xohms Touchpanel sensitivity (X-plate resistance)
++
++ resetgpio GPIO used to reset controller
++
++ ledgpio GPIO used to control backlight
++
++
++Name: i2c-rtc
++Info: Adds support for a number of I2C Real Time Clock devices
++Load: dtoverlay=i2c-rtc,<param>
++Params: ds1307 Select the DS1307 device
++
++ ds3231 Select the DS3231 device
++
++ mcp7941x Select the MCP7941x device
++
++ pcf2127 Select the PCF2127 device
++
++ pcf8523 Select the PCF8523 device
++
++ pcf8563 Select the PCF8563 device
++
++
++Name: i2s-mmap
++Info: Enables mmap support in the bcm2708-i2s driver
++Load: dtoverlay=i2s-mmap
++Params: <None>
++
++
++Name: iqaudio-dac
++Info: Configures the IQaudio DAC audio card
++Load: dtoverlay=iqaudio-dac
++Params: <None>
++
++
++Name: iqaudio-dacplus
++Info: Configures the IQaudio DAC+ audio card
++Load: dtoverlay=iqaudio-dacplus
++Params: <None>
++
++
++Name: lirc-rpi
++Info: Configures lirc-rpi (Linux Infrared Remote Control for Raspberry Pi)
++ Consult the module documentation for more details.
++Load: dtoverlay=lirc-rpi,<param>=<val>,...
++Params: gpio_out_pin GPIO for output (default "17")
++
++ gpio_in_pin GPIO for input (default "18")
++
++ gpio_in_pull Pull up/down/off on the input pin
++ (default "down")
++
++ sense Override the IR receive auto-detection logic:
++ "0" = force active-high
++ "1" = force active-low
++ "-1" = use auto-detection
++ (default "-1")
++
++ softcarrier Turn the software carrier "on" or "off"
++ (default "on")
++
++ invert "on" = invert the output pin (default "off")
++
++ debug "on" = enable additional debug messages
++ (default "off")
++
++
++Name: mcp2515-can0
++Info: Configures the MCP2515 CAN controller on spi0.0
++Load: dtoverlay=mcp2515-can0,<param>=<val>
++Params: oscillator Clock frequency for the CAN controller (Hz)
++
++ spimaxfrequency Maximum SPI frequence (Hz)
++
++ interrupt GPIO for interrupt signal
++
++
++Name: mcp2515-can1
++Info: Configures the MCP2515 CAN controller on spi0.1
++Load: dtoverlay=mcp2515-can1,<param>=<val>
++Params: oscillator Clock frequency for the CAN controller (Hz)
++
++ spimaxfrequency Maximum SPI frequence (Hz)
++
++ interrupt GPIO for interrupt signal
++
++
++Name: mmc
++Info: Selects the bcm2835-mmc SD/MMC driver, optionally with overclock
++Load: dtoverlay=mmc,<param>=<val>
++Params: overclock_50 Clock (in MHz) to use when the MMC framework
++ requests 50MHz
++ force_pio Disable DMA support
++
++
++Name: mz61581
++Info: MZ61581 display by Tontec
++Load: dtoverlay=mz61581,<param>=<val>
++Params: speed Display SPI bus speed
++
++ rotate Display rotation {0,90,180,270}
++
++ fps Delay between frame updates
++
++ txbuflen Transmit buffer length (default 32768)
++
++ debug Debug output level {0-7}
++
++ xohms Touchpanel sensitivity (X-plate resistance)
++
++
++[ The pcf2127-rtc overlay has been deleted. See i2c-rtc. ]
++
++
++[ The pcf8523-rtc overlay has been deleted. See i2c-rtc. ]
++
++
++[ The pcf8563-rtc overlay has been deleted. See i2c-rtc. ]
++
++
++Name: piscreen
++Info: PiScreen display by OzzMaker.com
++Load: dtoverlay=piscreen,<param>=<val>
++Params: speed Display SPI bus speed
++
++ rotate Display rotation {0,90,180,270}
++
++ fps Delay between frame updates
++
++ debug Debug output level {0-7}
++
++ xohms Touchpanel sensitivity (X-plate resistance)
++
++
++Name: pitft28-resistive
++Info: Adafruit PiTFT 2.8" resistive touch screen
++Load: dtoverlay=pitft28-resistive,<param>=<val>
++Params: speed Display SPI bus speed
++
++ rotate Display rotation {0,90,180,270}
++
++ fps Delay between frame updates
++
++ debug Debug output level {0-7}
++
++
++Name: pps-gpio
++Info: Configures the pps-gpio (pulse-per-second time signal via GPIO).
++Load: dtoverlay=pps-gpio,<param>=<val>
++Params: gpiopin Input GPIO (default "18")
++
++
++Name: pwm
++Info: Configures a single PWM channel
++ Legal pin,function combinations for each channel:
++ PWM0: 12,4(Alt0) 18,2(Alt5) 40,4(Alt0) 52,5(Alt1)
++ PWM1: 13,4(Alt0) 19,2(Alt5) 41,4(Alt0) 45,4(Alt0) 53,5(Alt1)
++ N.B.:
++ 1) Pin 18 is the only one available on all platforms, and
++ it is the one used by the I2S audio interface.
++ Pins 12 and 13 might be better choices on an A+, B+ or Pi2.
++ 2) The onboard analogue audio output uses both PWM channels.
++ 3) So be careful mixing audio and PWM.
++ 4) Currently the clock must have been enabled and configured
++ by other means.
++Load: dtoverlay=pwm,<param>=<val>
++Params: pin Output pin (default 18) - see table
++ func Pin function (default 2 = Alt5) - see above
++ clock PWM clock frequency (informational)
++
++
++Name: pwm-2chan
++Info: Configures both PWM channels
++ Legal pin,function combinations for each channel:
++ PWM0: 12,4(Alt0) 18,2(Alt5) 40,4(Alt0) 52,5(Alt1)
++ PWM1: 13,4(Alt0) 19,2(Alt5) 41,4(Alt0) 45,4(Alt0) 53,5(Alt1)
++ N.B.:
++ 1) Pin 18 is the only one available on all platforms, and
++ it is the one used by the I2S audio interface.
++ Pins 12 and 13 might be better choices on an A+, B+ or Pi2.
++ 2) The onboard analogue audio output uses both PWM channels.
++ 3) So be careful mixing audio and PWM.
++ 4) Currently the clock must have been enabled and configured
++ by other means.
++Load: dtoverlay=pwm-2chan,<param>=<val>
++Params: pin Output pin (default 18) - see table
++ pin2 Output pin for other channel (default 19)
++ func Pin function (default 2 = Alt5) - see above
++ func2 Function for pin2 (default 2 = Alt5)
++ clock PWM clock frequency (informational)
++
++
++Name: raspidac3
++Info: Configures the RaspiDAV Rev.3x audio card
++Load: dtoverlay=raspidac3
++Params: <None>
++
++
++Name: rpi-dac
++Info: Configures the RPi DAC audio card
++Load: dtoverlay=rpi-dac
++Params: <None>
++
++
++Name: rpi-display
++Info: RPi-Display - 2.8" Touch Display by Watterott
++Load: dtoverlay=rpi-display,<param>=<val>
++Params: speed Display SPI bus speed
++
++ rotate Display rotation {0,90,180,270}
++
++ fps Delay between frame updates
++
++ debug Debug output level {0-7}
++
++ xohms Touchpanel sensitivity (X-plate resistance)
++
++
++Name: rpi-ft5406
++Info: Official Raspberry Pi display touchscreen
++Load: dtoverlay=rpi-ft5406
++Params: <None>
++
++
++Name: rpi-proto
++Info: Configures the RPi Proto audio card
++Load: dtoverlay=rpi-proto
++Params: <None>
++
++
++Name: rpi-sense
++Info: Raspberry Pi Sense HAT
++Load: dtoverlay=rpi-sense
++Params: <None>
++
++
++Name: sdhost
++Info: Selects the bcm2835-sdhost SD/MMC driver, optionally with overclock
++Load: dtoverlay=sdhost,<param>=<val>
++Params: overclock_50 Clock (in MHz) to use when the MMC framework
++ requests 50MHz
++
++ force_pio Disable DMA support (default off)
++
++ pio_limit Number of blocks above which to use DMA
++ (default 1)
++
++ debug Enable debug output (default off)
++
++
++Name: sdio
++Info: Selects the bcm2835-sdhost SD/MMC driver, optionally with overclock,
++ and enables SDIO via GPIOs 22-27.
++Load: dtoverlay=sdio,<param>=<val>
++Params: overclock_50 Clock (in MHz) to use when the MMC framework
++ requests 50MHz
++
++ force_pio Disable DMA support (default off)
++
++ pio_limit Number of blocks above which to use DMA
++ (default 1)
++
++ debug Enable debug output (default off)
++
++ poll_once Disable SDIO-device polling every second
++ (default on: polling once at boot-time)
++
++
++Name: smi
++Info: Enables the Secondary Memory Interface peripheral. Uses GPIOs 2-25!
++Load: dtoverlay=smi
++Params: <None>
++
++
++Name: smi-dev
++Info: Enables the userspace interface for the SMI driver
++Load: dtoverlay=smi-dev
++Params: <None>
++
++
++Name: smi-nand
++Info: Enables access to NAND flash via the SMI interface
++Load: dtoverlay=smi-nand
++Params: <None>
++
++
++Name: spi-gpio35-39
++Info: move SPI function block to GPIO 35 to 39
++Load: dtoverlay=spi-gpio35-39
++Params: <None>
++
++
++Name: tinylcd35
++Info: 3.5" Color TFT Display by www.tinylcd.com
++ Options: Touch, RTC, keypad
++Load: dtoverlay=tinylcd35,<param>=<val>
++Params: speed Display SPI bus speed
++
++ rotate Display rotation {0,90,180,270}
++
++ fps Delay between frame updates
++
++ debug Debug output level {0-7}
++
++ touch Enable touch panel
++
++ touchgpio Touch controller IRQ GPIO
++
++ xohms Touchpanel: Resistance of X-plate in ohms
++
++ rtc-pcf PCF8563 Real Time Clock
++
++ rtc-ds DS1307 Real Time Clock
++
++ keypad Enable keypad
++
++ Examples:
++ Display with touchpanel, PCF8563 RTC and keypad:
++ dtoverlay=tinylcd35,touch,rtc-pcf,keypad
++ Old touch display:
++ dtoverlay=tinylcd35,touch,touchgpio=3
++
++
++Name: uart1
++Info: Enable uart1 in place of uart0
++Load: dtoverlay=uart1,<param>=<val>
++Params: txd1_pin GPIO pin for TXD1 (14, 32 or 40 - default 14)
++
++ rxd1_pin GPIO pin for RXD1 (15, 33 or 41 - default 15)
++
++
++Name: vga666
++Info: Overlay for the Fen Logic VGA666 board
++ This uses GPIOs 2-21 (so no I2C), and activates the output 2-3 seconds
++ after the kernel has started.
++Load: dtoverlay=vga666
++Params: <None>
++
++
++Name: w1-gpio
++Info: Configures the w1-gpio Onewire interface module.
++ Use this overlay if you *don't* need a GPIO to drive an external pullup.
++Load: dtoverlay=w1-gpio,<param>=<val>
++Params: gpiopin GPIO for I/O (default "4")
++
++ pullup Non-zero, "on", or "y" to enable the parasitic
++ power (2-wire, power-on-data) feature
++
++
++Name: w1-gpio-pullup
++Info: Configures the w1-gpio Onewire interface module.
++ Use this overlay if you *do* need a GPIO to drive an external pullup.
++Load: dtoverlay=w1-gpio-pullup,<param>=<val>
++Params: gpiopin GPIO for I/O (default "4")
++
++ pullup Non-zero, "on", or "y" to enable the parasitic
++ power (2-wire, power-on-data) feature
++
++ extpullup GPIO for external pullup (default "5")
++
++
++Troubleshooting
++===============
++
++If you are experiencing problems that you think are DT-related, enable DT
++diagnostic output by adding this to /boot/config.txt:
++
++ dtdebug=on
++
++and rebooting. Then run:
++
++ sudo vcdbg log msg
++
++and look for relevant messages.
++
++Further reading
++===============
++
++This is only meant to be a quick introduction to the subject of Device Tree on
++Raspberry Pi. There is a more complete explanation here:
++
++http://www.raspberrypi.org/documentation/configuration/device-tree.md
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/ads7846-overlay.dts
+@@ -0,0 +1,83 @@
++/*
++ * Generic Device Tree overlay for the ADS7846 touch controller
++ *
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++
++ fragment@0 {
++ target = <&spi0>;
++ __overlay__ {
++ status = "okay";
++
++ spidev@0{
++ status = "disabled";
++ };
++
++ spidev@1{
++ status = "disabled";
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ ads7846_pins: ads7846_pins {
++ brcm,pins = <255>; /* illegal default value */
++ brcm,function = <0>; /* in */
++ brcm,pull = <0>; /* none */
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&spi0>;
++ __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ ads7846: ads7846@1 {
++ compatible = "ti,ads7846";
++ reg = <1>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&ads7846_pins>;
++
++ spi-max-frequency = <2000000>;
++ interrupts = <255 2>; /* high-to-low edge triggered */
++ interrupt-parent = <&gpio>;
++ pendown-gpio = <&gpio 255 0>;
++
++ /* driver defaults */
++ ti,x-min = /bits/ 16 <0>;
++ ti,y-min = /bits/ 16 <0>;
++ ti,x-max = /bits/ 16 <0x0FFF>;
++ ti,y-max = /bits/ 16 <0x0FFF>;
++ ti,pressure-min = /bits/ 16 <0>;
++ ti,pressure-max = /bits/ 16 <0xFFFF>;
++ ti,x-plate-ohms = /bits/ 16 <400>;
++ };
++ };
++ };
++ __overrides__ {
++ cs = <&ads7846>,"reg:0";
++ speed = <&ads7846>,"spi-max-frequency:0";
++ penirq = <&ads7846_pins>,"brcm,pins:0", /* REQUIRED */
++ <&ads7846>,"interrupts:0",
++ <&ads7846>,"pendown-gpio:4";
++ penirq_pull = <&ads7846_pins>,"brcm,pull:0";
++ swapxy = <&ads7846>,"ti,swap-xy?";
++ xmin = <&ads7846>,"ti,x-min;0";
++ ymin = <&ads7846>,"ti,y-min;0";
++ xmax = <&ads7846>,"ti,x-max;0";
++ ymax = <&ads7846>,"ti,y-max;0";
++ pmin = <&ads7846>,"ti,pressure-min;0";
++ pmax = <&ads7846>,"ti,pressure-max;0";
++ xohms = <&ads7846>,"ti,x-plate-ohms;0";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/bmp085_i2c-sensor-overlay.dts
+@@ -0,0 +1,23 @@
++// Definitions for BMP085/BMP180 digital barometric pressure and temperature sensors from Bosch Sensortec
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&i2c_arm>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ bmp085@77 {
++ compatible = "bosch,bmp085";
++ reg = <0x77>;
++ default-oversampling = <3>;
++ status = "okay";
++ };
++ };
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/dht11-overlay.dts
+@@ -0,0 +1,39 @@
++/*
++ * Overlay for the DHT11/21/22 humidity/temperature sensor modules.
++ */
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target-path = "/";
++ __overlay__ {
++
++ dht11: dht11@0 {
++ compatible = "dht11";
++ pinctrl-names = "default";
++ pinctrl-0 = <&dht11_pins>;
++ gpios = <&gpio 4 0>;
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ dht11_pins: dht11_pins {
++ brcm,pins = <4>;
++ brcm,function = <0>; // in
++ brcm,pull = <0>; // off
++ };
++ };
++ };
++
++ __overrides__ {
++ gpiopin = <&dht11_pins>,"brcm,pins:0",
++ <&dht11>,"gpios:4";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/enc28j60-overlay.dts
+@@ -0,0 +1,50 @@
++// Overlay for the Microchip ENC28J60 Ethernet Controller
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&spi0>;
++ __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ status = "okay";
++
++ spidev@0{
++ status = "disabled";
++ };
++
++ eth1: enc28j60@0{
++ compatible = "microchip,enc28j60";
++ reg = <0>; /* CE0 */
++ pinctrl-names = "default";
++ pinctrl-0 = <&eth1_pins>;
++ interrupt-parent = <&gpio>;
++ interrupts = <25 0x2>; /* falling edge */
++ spi-max-frequency = <12000000>;
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ eth1_pins: eth1_pins {
++ brcm,pins = <25>;
++ brcm,function = <0>; /* in */
++ brcm,pull = <0>; /* none */
++ };
++ };
++ };
++
++ __overrides__ {
++ int_pin = <&eth1>, "interrupts:0",
++ <&eth1_pins>, "brcm,pins:0";
++ speed = <&eth1>, "spi-max-frequency:0";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts
+@@ -0,0 +1,34 @@
++// Definitions for gpio-poweroff module
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target-path = "/";
++ __overlay__ {
++ power_ctrl: power_ctrl {
++ compatible = "gpio-poweroff";
++ gpios = <&gpio 26 0>;
++ force;
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ power_ctrl_pins: power_ctrl_pins {
++ brcm,pins = <26>;
++ brcm,function = <1>; // out
++ };
++ };
++ };
++
++ __overrides__ {
++ gpiopin = <&power_ctrl>,"gpios:4",
++ <&power_ctrl_pins>,"brcm,pins:0";
++ active_low = <&power_ctrl>,"gpios:8";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/hifiberry-amp-overlay.dts
+@@ -0,0 +1,39 @@
++// Definitions for HiFiBerry Amp/Amp+
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&sound>;
++ __overlay__ {
++ compatible = "hifiberry,hifiberry-amp";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&i2s>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@2 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ tas5713@1b {
++ #sound-dai-cells = <0>;
++ compatible = "ti,tas5713";
++ reg = <0x1b>;
++ status = "okay";
++ };
++ };
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/hifiberry-dac-overlay.dts
+@@ -0,0 +1,34 @@
++// Definitions for HiFiBerry DAC
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&sound>;
++ __overlay__ {
++ compatible = "hifiberry,hifiberry-dac";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&i2s>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@2 {
++ target-path = "/";
++ __overlay__ {
++ pcm5102a-codec {
++ #sound-dai-cells = <0>;
++ compatible = "ti,pcm5102a";
++ status = "okay";
++ };
++ };
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
+@@ -0,0 +1,39 @@
++// Definitions for HiFiBerry DAC+
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&sound>;
++ __overlay__ {
++ compatible = "hifiberry,hifiberry-dacplus";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&i2s>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@2 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ pcm5122@4d {
++ #sound-dai-cells = <0>;
++ compatible = "ti,pcm5122";
++ reg = <0x4d>;
++ status = "okay";
++ };
++ };
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/hifiberry-digi-overlay.dts
+@@ -0,0 +1,39 @@
++// Definitions for HiFiBerry Digi
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&sound>;
++ __overlay__ {
++ compatible = "hifiberry,hifiberry-digi";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&i2s>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@2 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ wm8804@3b {
++ #sound-dai-cells = <0>;
++ compatible = "wlf,wm8804";
++ reg = <0x3b>;
++ status = "okay";
++ };
++ };
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/hy28a-overlay.dts
+@@ -0,0 +1,87 @@
++/*
++ * Device Tree overlay for HY28A display
++ *
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++
++ fragment@0 {
++ target = <&spi0>;
++ __overlay__ {
++ status = "okay";
++
++ spidev@0{
++ status = "disabled";
++ };
++
++ spidev@1{
++ status = "disabled";
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ hy28a_pins: hy28a_pins {
++ brcm,pins = <17 25 18>;
++ brcm,function = <0 1 1>; /* in out out */
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&spi0>;
++ __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ hy28a: hy28a@0{
++ compatible = "ilitek,ili9320";
++ reg = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&hy28a_pins>;
++
++ spi-max-frequency = <32000000>;
++ spi-cpol;
++ spi-cpha;
++ rotate = <270>;
++ bgr;
++ fps = <50>;
++ buswidth = <8>;
++ startbyte = <0x70>;
++ reset-gpios = <&gpio 25 0>;
++ led-gpios = <&gpio 18 1>;
++ debug = <0>;
++ };
++
++ hy28a_ts: hy28a-ts@1 {
++ compatible = "ti,ads7846";
++ reg = <1>;
++
++ spi-max-frequency = <2000000>;
++ interrupts = <17 2>; /* high-to-low edge triggered */
++ interrupt-parent = <&gpio>;
++ pendown-gpio = <&gpio 17 0>;
++ ti,x-plate-ohms = /bits/ 16 <100>;
++ ti,pressure-max = /bits/ 16 <255>;
++ };
++ };
++ };
++ __overrides__ {
++ speed = <&hy28a>,"spi-max-frequency:0";
++ rotate = <&hy28a>,"rotate:0";
++ fps = <&hy28a>,"fps:0";
++ debug = <&hy28a>,"debug:0";
++ xohms = <&hy28a_ts>,"ti,x-plate-ohms;0";
++ resetgpio = <&hy28a>,"reset-gpios:4",
++ <&hy28a_pins>, "brcm,pins:1";
++ ledgpio = <&hy28a>,"led-gpios:4",
++ <&hy28a_pins>, "brcm,pins:2";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/hy28b-overlay.dts
+@@ -0,0 +1,142 @@
++/*
++ * Device Tree overlay for HY28b display shield by Texy
++ *
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++
++ fragment@0 {
++ target = <&spi0>;
++ __overlay__ {
++ status = "okay";
++
++ spidev@0{
++ status = "disabled";
++ };
++
++ spidev@1{
++ status = "disabled";
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ hy28b_pins: hy28b_pins {
++ brcm,pins = <17 25 18>;
++ brcm,function = <0 1 1>; /* in out out */
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&spi0>;
++ __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ hy28b: hy28b@0{
++ compatible = "ilitek,ili9325";
++ reg = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&hy28b_pins>;
++
++ spi-max-frequency = <48000000>;
++ spi-cpol;
++ spi-cpha;
++ rotate = <270>;
++ bgr;
++ fps = <50>;
++ buswidth = <8>;
++ startbyte = <0x70>;
++ reset-gpios = <&gpio 25 0>;
++ led-gpios = <&gpio 18 1>;
++
++ gamma = "04 1F 4 7 7 0 7 7 6 0\n0F 00 1 7 4 0 0 0 6 7";
++
++ init = <0x10000e7 0x0010
++ 0x1000000 0x0001
++ 0x1000001 0x0100
++ 0x1000002 0x0700
++ 0x1000003 0x1030
++ 0x1000004 0x0000
++ 0x1000008 0x0207
++ 0x1000009 0x0000
++ 0x100000a 0x0000
++ 0x100000c 0x0001
++ 0x100000d 0x0000
++ 0x100000f 0x0000
++ 0x1000010 0x0000
++ 0x1000011 0x0007
++ 0x1000012 0x0000
++ 0x1000013 0x0000
++ 0x2000032
++ 0x1000010 0x1590
++ 0x1000011 0x0227
++ 0x2000032
++ 0x1000012 0x009c
++ 0x2000032
++ 0x1000013 0x1900
++ 0x1000029 0x0023
++ 0x100002b 0x000e
++ 0x2000032
++ 0x1000020 0x0000
++ 0x1000021 0x0000
++ 0x2000032
++ 0x1000050 0x0000
++ 0x1000051 0x00ef
++ 0x1000052 0x0000
++ 0x1000053 0x013f
++ 0x1000060 0xa700
++ 0x1000061 0x0001
++ 0x100006a 0x0000
++ 0x1000080 0x0000
++ 0x1000081 0x0000
++ 0x1000082 0x0000
++ 0x1000083 0x0000
++ 0x1000084 0x0000
++ 0x1000085 0x0000
++ 0x1000090 0x0010
++ 0x1000092 0x0000
++ 0x1000093 0x0003
++ 0x1000095 0x0110
++ 0x1000097 0x0000
++ 0x1000098 0x0000
++ 0x1000007 0x0133
++ 0x1000020 0x0000
++ 0x1000021 0x0000
++ 0x2000064>;
++ debug = <0>;
++ };
++
++ hy28b_ts: hy28b-ts@1 {
++ compatible = "ti,ads7846";
++ reg = <1>;
++
++ spi-max-frequency = <2000000>;
++ interrupts = <17 2>; /* high-to-low edge triggered */
++ interrupt-parent = <&gpio>;
++ pendown-gpio = <&gpio 17 0>;
++ ti,x-plate-ohms = /bits/ 16 <100>;
++ ti,pressure-max = /bits/ 16 <255>;
++ };
++ };
++ };
++ __overrides__ {
++ speed = <&hy28b>,"spi-max-frequency:0";
++ rotate = <&hy28b>,"rotate:0";
++ fps = <&hy28b>,"fps:0";
++ debug = <&hy28b>,"debug:0";
++ xohms = <&hy28b_ts>,"ti,x-plate-ohms;0";
++ resetgpio = <&hy28b>,"reset-gpios:4",
++ <&hy28b_pins>, "brcm,pins:1";
++ ledgpio = <&hy28b>,"led-gpios:4",
++ <&hy28b_pins>, "brcm,pins:2";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
+@@ -0,0 +1,55 @@
++// Definitions for several I2C based Real Time Clocks
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&i2c_arm>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ ds1307: ds1307@68 {
++ compatible = "maxim,ds1307";
++ reg = <0x68>;
++ status = "disable";
++ };
++ mcp7941x: mcp7941x@6f {
++ compatible = "microchip,mcp7941x";
++ reg = <0x6f>;
++ status = "disable";
++ };
++ ds3231: ds3231@68 {
++ compatible = "maxim,ds3231";
++ reg = <0x68>;
++ status = "disable";
++ };
++ pcf2127: pcf2127@51 {
++ compatible = "nxp,pcf2127";
++ reg = <0x51>;
++ status = "disable";
++ };
++ pcf8523: pcf8523@68 {
++ compatible = "nxp,pcf8523";
++ reg = <0x68>;
++ status = "disable";
++ };
++ pcf8563: pcf8563@51 {
++ compatible = "nxp,pcf8563";
++ reg = <0x51>;
++ status = "disable";
++ };
++ };
++ };
++ __overrides__ {
++ ds1307 = <&ds1307>,"status";
++ ds3231 = <&ds3231>,"status";
++ mcp7941x = <&mcp7941x>,"status";
++ pcf2127 = <&pcf2127>,"status";
++ pcf8523 = <&pcf8523>,"status";
++ pcf8563 = <&pcf8563>,"status";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/i2s-mmap-overlay.dts
+@@ -0,0 +1,13 @@
++/dts-v1/;
++/plugin/;
++
++/{
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&i2s>;
++ __overlay__ {
++ brcm,enable-mmap;
++ };
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts
+@@ -0,0 +1,39 @@
++// Definitions for IQaudIO DAC
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&sound>;
++ __overlay__ {
++ compatible = "iqaudio,iqaudio-dac";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&i2s>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@2 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ pcm5122@4c {
++ #sound-dai-cells = <0>;
++ compatible = "ti,pcm5122";
++ reg = <0x4c>;
++ status = "okay";
++ };
++ };
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts
+@@ -0,0 +1,39 @@
++// Definitions for IQaudIO DAC+
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&sound>;
++ __overlay__ {
++ compatible = "iqaudio,iqaudio-dac";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&i2s>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@2 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ pcm5122@4c {
++ #sound-dai-cells = <0>;
++ compatible = "ti,pcm5122";
++ reg = <0x4c>;
++ status = "okay";
++ };
++ };
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/lirc-rpi-overlay.dts
+@@ -0,0 +1,57 @@
++// Definitions for lirc-rpi module
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target-path = "/";
++ __overlay__ {
++ lirc_rpi: lirc_rpi {
++ compatible = "rpi,lirc-rpi";
++ pinctrl-names = "default";
++ pinctrl-0 = <&lirc_pins>;
++ status = "okay";
++
++ // Override autodetection of IR receiver circuit
++ // (0 = active high, 1 = active low, -1 = no override )
++ rpi,sense = <0xffffffff>;
++
++ // Software carrier
++ // (0 = off, 1 = on)
++ rpi,softcarrier = <1>;
++
++ // Invert output
++ // (0 = off, 1 = on)
++ rpi,invert = <0>;
++
++ // Enable debugging messages
++ // (0 = off, 1 = on)
++ rpi,debug = <0>;
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ lirc_pins: lirc_pins {
++ brcm,pins = <17 18>;
++ brcm,function = <1 0>; // out in
++ brcm,pull = <0 1>; // off down
++ };
++ };
++ };
++
++ __overrides__ {
++ gpio_out_pin = <&lirc_pins>,"brcm,pins:0";
++ gpio_in_pin = <&lirc_pins>,"brcm,pins:4";
++ gpio_in_pull = <&lirc_pins>,"brcm,pull:4";
++
++ sense = <&lirc_rpi>,"rpi,sense:0";
++ softcarrier = <&lirc_rpi>,"rpi,softcarrier:0";
++ invert = <&lirc_rpi>,"rpi,invert:0";
++ debug = <&lirc_rpi>,"rpi,debug:0";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/mcp2515-can0-overlay.dts
+@@ -0,0 +1,69 @@
++/*
++ * Device tree overlay for mcp251x/can0 on spi0.0
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709";
++ /* disable spi-dev for spi0.0 */
++ fragment@0 {
++ target = <&spi0>;
++ __overlay__ {
++ status = "okay";
++ spidev@0{
++ status = "disabled";
++ };
++ };
++ };
++
++ /* the interrupt pin of the can-controller */
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ can0_pins: can0_pins {
++ brcm,pins = <25>;
++ brcm,function = <0>; /* input */
++ };
++ };
++ };
++
++ /* the clock/oscillator of the can-controller */
++ fragment@2 {
++ target-path = "/clocks";
++ __overlay__ {
++ /* external oscillator of mcp2515 on SPI0.0 */
++ can0_osc: can0_osc {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ clock-frequency = <16000000>;
++ };
++ };
++ };
++
++ /* the spi config of the can-controller itself binding everything together */
++ fragment@3 {
++ target = <&spi0>;
++ __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ can0: mcp2515@0 {
++ reg = <0>;
++ compatible = "microchip,mcp2515";
++ pinctrl-names = "default";
++ pinctrl-0 = <&can0_pins>;
++ spi-max-frequency = <10000000>;
++ interrupt-parent = <&gpio>;
++ interrupts = <25 0x2>;
++ clocks = <&can0_osc>;
++ };
++ };
++ };
++ __overrides__ {
++ oscillator = <&can0_osc>,"clock-frequency:0";
++ spimaxfrequency = <&can0>,"spi-max-frequency:0";
++ interrupt = <&can0_pins>,"brcm,pins:0",<&can0>,"interrupts:0";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/mcp2515-can1-overlay.dts
+@@ -0,0 +1,69 @@
++/*
++ * Device tree overlay for mcp251x/can1 on spi0.1 edited by petit_miner
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709";
++ /* disable spi-dev for spi0.1 */
++ fragment@0 {
++ target = <&spi0>;
++ __overlay__ {
++ status = "okay";
++ spidev@1{
++ status = "disabled";
++ };
++ };
++ };
++
++ /* the interrupt pin of the can-controller */
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ can1_pins: can1_pins {
++ brcm,pins = <25>;
++ brcm,function = <0>; /* input */
++ };
++ };
++ };
++
++ /* the clock/oscillator of the can-controller */
++ fragment@2 {
++ target-path = "/clocks";
++ __overlay__ {
++ /* external oscillator of mcp2515 on spi0.1 */
++ can1_osc: can1_osc {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ clock-frequency = <16000000>;
++ };
++ };
++ };
++
++ /* the spi config of the can-controller itself binding everything together */
++ fragment@3 {
++ target = <&spi0>;
++ __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ can1: mcp2515@1 {
++ reg = <1>;
++ compatible = "microchip,mcp2515";
++ pinctrl-names = "default";
++ pinctrl-0 = <&can1_pins>;
++ spi-max-frequency = <10000000>;
++ interrupt-parent = <&gpio>;
++ interrupts = <25 0x2>;
++ clocks = <&can1_osc>;
++ };
++ };
++ };
++ __overrides__ {
++ oscillator = <&can1_osc>,"clock-frequency:0";
++ spimaxfrequency = <&can1>,"spi-max-frequency:0";
++ interrupt = <&can1_pins>,"brcm,pins:0",<&can1>,"interrupts:0";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/mmc-overlay.dts
+@@ -0,0 +1,39 @@
++/dts-v1/;
++/plugin/;
++
++/{
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&mmc>;
++ frag0: __overlay__ {
++ pinctrl-names = "default";
++ pinctrl-0 = <&mmc_pins>;
++ bus-width = <4>;
++ brcm,overclock-50 = <0>;
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ mmc_pins: mmc_pins {
++ brcm,pins = <48 49 50 51 52 53>;
++ brcm,function = <7>; /* alt3 */
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&sdhost>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
++ __overrides__ {
++ overclock_50 = <&frag0>,"brcm,overclock-50:0";
++ force_pio = <&frag0>,"brcm,force-pio?";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/mz61581-overlay.dts
+@@ -0,0 +1,111 @@
++/*
++ * Device Tree overlay for MZ61581-PI-EXT 2014.12.28 by Tontec
++ *
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++
++ fragment@0 {
++ target = <&spi0>;
++ __overlay__ {
++ status = "okay";
++
++ spidev@0{
++ status = "disabled";
++ };
++
++ spidev@1{
++ status = "disabled";
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ mz61581_pins: mz61581_pins {
++ brcm,pins = <4 15 18 25>;
++ brcm,function = <0 1 1 1>; /* in out out out */
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&spi0>;
++ __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ mz61581: mz61581@0{
++ compatible = "samsung,s6d02a1";
++ reg = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&mz61581_pins>;
++
++ spi-max-frequency = <128000000>;
++ spi-cpol;
++ spi-cpha;
++
++ width = <320>;
++ height = <480>;
++ rotate = <270>;
++ bgr;
++ fps = <30>;
++ buswidth = <8>;
++ txbuflen = <32768>;
++
++ reset-gpios = <&gpio 15 0>;
++ dc-gpios = <&gpio 25 0>;
++ led-gpios = <&gpio 18 0>;
++
++ init = <0x10000b0 00
++ 0x1000011
++ 0x20000ff
++ 0x10000b3 0x02 0x00 0x00 0x00
++ 0x10000c0 0x13 0x3b 0x00 0x02 0x00 0x01 0x00 0x43
++ 0x10000c1 0x08 0x16 0x08 0x08
++ 0x10000c4 0x11 0x07 0x03 0x03
++ 0x10000c6 0x00
++ 0x10000c8 0x03 0x03 0x13 0x5c 0x03 0x07 0x14 0x08 0x00 0x21 0x08 0x14 0x07 0x53 0x0c 0x13 0x03 0x03 0x21 0x00
++ 0x1000035 0x00
++ 0x1000036 0xa0
++ 0x100003a 0x55
++ 0x1000044 0x00 0x01
++ 0x10000d0 0x07 0x07 0x1d 0x03
++ 0x10000d1 0x03 0x30 0x10
++ 0x10000d2 0x03 0x14 0x04
++ 0x1000029
++ 0x100002c>;
++
++ /* This is a workaround to make sure the init sequence slows down and doesn't fail */
++ debug = <3>;
++ };
++
++ mz61581_ts: mz61581_ts@1 {
++ compatible = "ti,ads7846";
++ reg = <1>;
++
++ spi-max-frequency = <2000000>;
++ interrupts = <4 2>; /* high-to-low edge triggered */
++ interrupt-parent = <&gpio>;
++ pendown-gpio = <&gpio 4 0>;
++
++ ti,x-plate-ohms = /bits/ 16 <60>;
++ ti,pressure-max = /bits/ 16 <255>;
++ };
++ };
++ };
++ __overrides__ {
++ speed = <&mz61581>, "spi-max-frequency:0";
++ rotate = <&mz61581>, "rotate:0";
++ fps = <&mz61581>, "fps:0";
++ txbuflen = <&mz61581>, "txbuflen:0";
++ debug = <&mz61581>, "debug:0";
++ xohms = <&mz61581_ts>,"ti,x-plate-ohms;0";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/piscreen-overlay.dts
+@@ -0,0 +1,96 @@
++/*
++ * Device Tree overlay for PiScreen 3.5" display shield by Ozzmaker
++ *
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++
++ fragment@0 {
++ target = <&spi0>;
++ __overlay__ {
++ status = "okay";
++
++ spidev@0{
++ status = "disabled";
++ };
++
++ spidev@1{
++ status = "disabled";
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ piscreen_pins: piscreen_pins {
++ brcm,pins = <17 25 24 22>;
++ brcm,function = <0 1 1 1>; /* in out out out */
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&spi0>;
++ __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ piscreen: piscreen@0{
++ compatible = "ilitek,ili9486";
++ reg = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&piscreen_pins>;
++
++ spi-max-frequency = <24000000>;
++ rotate = <270>;
++ bgr;
++ fps = <30>;
++ buswidth = <8>;
++ regwidth = <16>;
++ reset-gpios = <&gpio 25 0>;
++ dc-gpios = <&gpio 24 0>;
++ led-gpios = <&gpio 22 1>;
++ debug = <0>;
++
++ init = <0x10000b0 0x00
++ 0x1000011
++ 0x20000ff
++ 0x100003a 0x55
++ 0x1000036 0x28
++ 0x10000c2 0x44
++ 0x10000c5 0x00 0x00 0x00 0x00
++ 0x10000e0 0x0f 0x1f 0x1c 0x0c 0x0f 0x08 0x48 0x98 0x37 0x0a 0x13 0x04 0x11 0x0d 0x00
++ 0x10000e1 0x0f 0x32 0x2e 0x0b 0x0d 0x05 0x47 0x75 0x37 0x06 0x10 0x03 0x24 0x20 0x00
++ 0x10000e2 0x0f 0x32 0x2e 0x0b 0x0d 0x05 0x47 0x75 0x37 0x06 0x10 0x03 0x24 0x20 0x00
++ 0x1000011
++ 0x1000029>;
++ };
++
++ piscreen_ts: piscreen-ts@1 {
++ compatible = "ti,ads7846";
++ reg = <1>;
++
++ spi-max-frequency = <2000000>;
++ interrupts = <17 2>; /* high-to-low edge triggered */
++ interrupt-parent = <&gpio>;
++ pendown-gpio = <&gpio 17 0>;
++ ti,swap-xy;
++ ti,x-plate-ohms = /bits/ 16 <100>;
++ ti,pressure-max = /bits/ 16 <255>;
++ };
++ };
++ };
++ __overrides__ {
++ speed = <&piscreen>,"spi-max-frequency:0";
++ rotate = <&piscreen>,"rotate:0";
++ fps = <&piscreen>,"fps:0";
++ debug = <&piscreen>,"debug:0";
++ xohms = <&piscreen_ts>,"ti,x-plate-ohms;0";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/pitft28-resistive-overlay.dts
+@@ -0,0 +1,115 @@
++/*
++ * Device Tree overlay for Adafruit PiTFT 2.8" resistive touch screen
++ *
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++
++ fragment@0 {
++ target = <&spi0>;
++ __overlay__ {
++ status = "okay";
++
++ spidev@0{
++ status = "disabled";
++ };
++
++ spidev@1{
++ status = "disabled";
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ pitft_pins: pitft_pins {
++ brcm,pins = <24 25>;
++ brcm,function = <0 1>; /* in out */
++ brcm,pull = <2 0>; /* pullup none */
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&spi0>;
++ __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ pitft: pitft@0{
++ compatible = "ilitek,ili9340";
++ reg = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pitft_pins>;
++
++ spi-max-frequency = <32000000>;
++ rotate = <90>;
++ fps = <25>;
++ bgr;
++ buswidth = <8>;
++ dc-gpios = <&gpio 25 0>;
++ debug = <0>;
++ };
++
++ pitft_ts@1 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ compatible = "st,stmpe610";
++ reg = <1>;
++
++ spi-max-frequency = <500000>;
++ irq-gpio = <&gpio 24 0x2>; /* IRQF_TRIGGER_FALLING */
++ interrupts = <24 2>; /* high-to-low edge triggered */
++ interrupt-parent = <&gpio>;
++ interrupt-controller;
++
++ stmpe_touchscreen {
++ compatible = "st,stmpe-ts";
++ st,sample-time = <4>;
++ st,mod-12b = <1>;
++ st,ref-sel = <0>;
++ st,adc-freq = <2>;
++ st,ave-ctrl = <3>;
++ st,touch-det-delay = <4>;
++ st,settling = <2>;
++ st,fraction-z = <7>;
++ st,i-drive = <0>;
++ };
++
++ stmpe_gpio: stmpe_gpio {
++ #gpio-cells = <2>;
++ compatible = "st,stmpe-gpio";
++ /*
++ * only GPIO2 is wired/available
++ * and it is wired to the backlight
++ */
++ st,norequest-mask = <0x7b>;
++ };
++ };
++ };
++ };
++
++ fragment@3 {
++ target-path = "/soc";
++ __overlay__ {
++ backlight {
++ compatible = "gpio-backlight";
++ gpios = <&stmpe_gpio 2 0>;
++ default-on;
++ };
++ };
++ };
++
++ __overrides__ {
++ speed = <&pitft>,"spi-max-frequency:0";
++ rotate = <&pitft>,"rotate:0";
++ fps = <&pitft>,"fps:0";
++ debug = <&pitft>,"debug:0";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/pps-gpio-overlay.dts
+@@ -0,0 +1,34 @@
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++ fragment@0 {
++ target-path = "/";
++ __overlay__ {
++ pps: pps {
++ compatible = "pps-gpio";
++ pinctrl-names = "default";
++ pinctrl-0 = <&pps_pins>;
++ gpios = <&gpio 18 0>;
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ pps_pins: pps_pins {
++ brcm,pins = <18>;
++ brcm,function = <0>; // in
++ brcm,pull = <0>; // off
++ };
++ };
++ };
++
++ __overrides__ {
++ gpiopin = <&pps>,"gpios:4",
++ <&pps_pins>,"brcm,pins:0";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts
+@@ -0,0 +1,46 @@
++/dts-v1/;
++/plugin/;
++
++/*
++This is the 2-channel overlay - only use it if you need both channels.
++
++Legal pin,function combinations for each channel:
++ PWM0: 12,4(Alt0) 18,2(Alt5) 40,4(Alt0) 52,5(Alt1)
++ PWM1: 13,4(Alt0) 19,2(Alt5) 41,4(Alt0) 45,4(Alt0) 53,5(Alt1)
++
++N.B.:
++ 1) Pin 18 is the only one available on all platforms, and
++ it is the one used by the I2S audio interface.
++ Pins 12 and 13 might be better choices on an A+, B+ or Pi2.
++ 2) The onboard analogue audio output uses both PWM channels.
++ 3) So be careful mixing audio and PWM.
++*/
++
++/ {
++ fragment@0 {
++ target = <&gpio>;
++ __overlay__ {
++ pwm_pins: pwm_pins {
++ brcm,pins = <18 19>;
++ brcm,function = <2 2>; /* Alt5 */
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&pwm>;
++ __overlay__ {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pwm_pins>;
++ status = "okay";
++ };
++ };
++
++ __overrides__ {
++ pin = <&pwm_pins>,"brcm,pins:0";
++ pin2 = <&pwm_pins>,"brcm,pins:4";
++ func = <&pwm_pins>,"brcm,function:0";
++ func2 = <&pwm_pins>,"brcm,function:4";
++ clock = <&clk_pwm>,"clock-frequency:0";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/pwm-overlay.dts
+@@ -0,0 +1,42 @@
++/dts-v1/;
++/plugin/;
++
++/*
++Legal pin,function combinations for each channel:
++ PWM0: 12,4(Alt0) 18,2(Alt5) 40,4(Alt0) 52,5(Alt1)
++ PWM1: 13,4(Alt0) 19,2(Alt5) 41,4(Alt0) 45,4(Alt0) 53,5(Alt1)
++
++N.B.:
++ 1) Pin 18 is the only one available on all platforms, and
++ it is the one used by the I2S audio interface.
++ Pins 12 and 13 might be better choices on an A+, B+ or Pi2.
++ 2) The onboard analogue audio output uses both PWM channels.
++ 3) So be careful mixing audio and PWM.
++*/
++
++/ {
++ fragment@0 {
++ target = <&gpio>;
++ __overlay__ {
++ pwm_pins: pwm_pins {
++ brcm,pins = <18>;
++ brcm,function = <2>; /* Alt5 */
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&pwm>;
++ __overlay__ {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pwm_pins>;
++ status = "okay";
++ };
++ };
++
++ __overrides__ {
++ pin = <&pwm_pins>,"brcm,pins:0";
++ func = <&pwm_pins>,"brcm,function:0";
++ clock = <&clk_pwm>,"clock-frequency:0";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/raspidac3-overlay.dts
+@@ -0,0 +1,45 @@
++// Definitions for RaspiDACv3
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&sound>;
++ __overlay__ {
++ compatible = "jg,raspidacv3";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&i2s>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@2 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ pcm5122@4c {
++ #sound-dai-cells = <0>;
++ compatible = "ti,pcm5122";
++ reg = <0x4c>;
++ status = "okay";
++ };
++
++ tpa6130a2: tpa6130a2@60 {
++ compatible = "ti,tpa6130a2";
++ reg = <0x60>;
++ status = "okay";
++ };
++ };
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/rpi-dac-overlay.dts
+@@ -0,0 +1,34 @@
++// Definitions for RPi DAC
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&sound>;
++ __overlay__ {
++ compatible = "rpi,rpi-dac";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&i2s>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@2 {
++ target-path = "/";
++ __overlay__ {
++ pcm1794a-codec {
++ #sound-dai-cells = <0>;
++ compatible = "ti,pcm1794a";
++ status = "okay";
++ };
++ };
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/rpi-display-overlay.dts
+@@ -0,0 +1,82 @@
++/*
++ * Device Tree overlay for rpi-display by Watterott
++ *
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++
++ fragment@0 {
++ target = <&spi0>;
++ __overlay__ {
++ status = "okay";
++
++ spidev@0{
++ status = "disabled";
++ };
++
++ spidev@1{
++ status = "disabled";
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ rpi_display_pins: rpi_display_pins {
++ brcm,pins = <18 23 24 25>;
++ brcm,function = <1 1 1 0>; /* out out out in */
++ brcm,pull = <0 0 0 2>; /* - - - up */
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&spi0>;
++ __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ rpidisplay: rpi-display@0{
++ compatible = "ilitek,ili9341";
++ reg = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&rpi_display_pins>;
++
++ spi-max-frequency = <32000000>;
++ rotate = <270>;
++ bgr;
++ fps = <30>;
++ buswidth = <8>;
++ reset-gpios = <&gpio 23 0>;
++ dc-gpios = <&gpio 24 0>;
++ led-gpios = <&gpio 18 1>;
++ debug = <0>;
++ };
++
++ rpidisplay_ts: rpi-display-ts@1 {
++ compatible = "ti,ads7846";
++ reg = <1>;
++
++ spi-max-frequency = <2000000>;
++ interrupts = <25 2>; /* high-to-low edge triggered */
++ interrupt-parent = <&gpio>;
++ pendown-gpio = <&gpio 25 0>;
++ ti,x-plate-ohms = /bits/ 16 <60>;
++ ti,pressure-max = /bits/ 16 <255>;
++ };
++ };
++ };
++ __overrides__ {
++ speed = <&rpidisplay>,"spi-max-frequency:0";
++ rotate = <&rpidisplay>,"rotate:0";
++ fps = <&rpidisplay>,"fps:0";
++ debug = <&rpidisplay>,"debug:0";
++ xohms = <&rpidisplay_ts>,"ti,x-plate-ohms;0";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/rpi-ft5406-overlay.dts
+@@ -0,0 +1,17 @@
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target-path = "/";
++ __overlay__ {
++ rpi_ft5406: rpi_ft5406 {
++ compatible = "rpi,rpi-ft5406";
++ firmware = <&firmware>;
++ status = "okay";
++ };
++ };
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/rpi-proto-overlay.dts
+@@ -0,0 +1,39 @@
++// Definitions for Rpi-Proto
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&sound>;
++ __overlay__ {
++ compatible = "rpi,rpi-proto";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&i2s>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@2 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ wm8731@1a {
++ #sound-dai-cells = <0>;
++ compatible = "wlf,wm8731";
++ reg = <0x1a>;
++ status = "okay";
++ };
++ };
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/rpi-sense-overlay.dts
+@@ -0,0 +1,47 @@
++// rpi-sense HAT
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708", "brcm,bcm2709";
++
++ fragment@0 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ rpi-sense@46 {
++ compatible = "rpi,rpi-sense";
++ reg = <0x46>;
++ keys-int-gpios = <&gpio 23 1>;
++ status = "okay";
++ };
++
++ lsm9ds1-magn@1c {
++ compatible = "st,lsm9ds1-magn";
++ reg = <0x1c>;
++ status = "okay";
++ };
++
++ lsm9ds1-accel6a {
++ compatible = "st,lsm9ds1-accel";
++ reg = <0x6a>;
++ status = "okay";
++ };
++
++ lps25h-press@5c {
++ compatible = "st,lps25h-press";
++ reg = <0x5c>;
++ status = "okay";
++ };
++
++ hts221-humid@5f {
++ compatible = "st,hts221-humid";
++ reg = <0x5f>;
++ status = "okay";
++ };
++ };
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/sdhost-overlay.dts
+@@ -0,0 +1,29 @@
++/dts-v1/;
++/plugin/;
++
++/{
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&mmc>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@1 {
++ target = <&sdhost>;
++ frag1: __overlay__ {
++ brcm,overclock-50 = <0>;
++ brcm,pio-limit = <1>;
++ status = "okay";
++ };
++ };
++
++ __overrides__ {
++ overclock_50 = <&frag1>,"brcm,overclock-50:0";
++ force_pio = <&frag1>,"brcm,force-pio?";
++ pio_limit = <&frag1>,"brcm,pio-limit:0";
++ debug = <&frag1>,"brcm,debug?";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/sdio-overlay.dts
+@@ -0,0 +1,32 @@
++/* Enable SDIO from MMC interface via GPIOs 22-27. Includes sdhost overlay. */
++
++/include/ "sdhost-overlay.dts"
++
++/{
++ compatible = "brcm,bcm2708";
++
++ fragment@3 {
++ target = <&mmc>;
++ sdio_mmc: __overlay__ {
++ pinctrl-names = "default";
++ pinctrl-0 = <&sdio_pins>;
++ non-removable;
++ status = "okay";
++ };
++ };
++
++ fragment@4 {
++ target = <&gpio>;
++ __overlay__ {
++ sdio_pins: sdio_pins {
++ brcm,pins = <22 23 24 25 26 27>;
++ brcm,function = <7 7 7 7 7 7>; /* ALT3 = SD1 */
++ brcm,pull = <0 2 2 2 2 2>;
++ };
++ };
++ };
++
++ __overrides__ {
++ poll_once = <&sdio_mmc>,"non-removable?";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/smi-dev-overlay.dts
+@@ -0,0 +1,18 @@
++// Description: Overlay to enable character device interface for SMI.
++// Author: Luke Wren <luke@raspberrypi.org>
++
++/dts-v1/;
++/plugin/;
++
++/{
++ fragment@0 {
++ target = <&soc>;
++ __overlay__ {
++ smi_dev {
++ compatible = "brcm,bcm2835-smi-dev";
++ smi_handle = <&smi>;
++ status = "okay";
++ };
++ };
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/smi-nand-overlay.dts
+@@ -0,0 +1,69 @@
++// Description: Overlay to enable NAND flash through
++// the secondary memory interface
++// Author: Luke Wren
++
++/dts-v1/;
++/plugin/;
++
++/{
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&smi>;
++ __overlay__ {
++ pinctrl-names = "default";
++ pinctrl-0 = <&smi_pins>;
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&soc>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ nand: flash@0 {
++ compatible = "brcm,bcm2835-smi-nand";
++ smi_handle = <&smi>;
++ #address-cells = <1>;
++ #size-cells = <1>;
++ status = "okay";
++
++ partition@0 {
++ label = "stage2";
++ // 128k
++ reg = <0 0x20000>;
++ read-only;
++ };
++ partition@1 {
++ label = "firmware";
++ // 16M
++ reg = <0x20000 0x1000000>;
++ read-only;
++ };
++ partition@2 {
++ label = "root";
++ // 2G (will need to use 64 bit for >=4G)
++ reg = <0x1020000 0x80000000>;
++ };
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&gpio>;
++ __overlay__ {
++ smi_pins: smi_pins {
++ brcm,pins = <0 1 2 3 4 5 6 7 8 9 10 11
++ 12 13 14 15>;
++ /* Alt 1: SMI */
++ brcm,function = <5 5 5 5 5 5 5 5 5 5 5
++ 5 5 5 5 5>;
++ /* /CS, /WE and /OE are pulled high, as they are
++ generally active low signals */
++ brcm,pull = <2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0>;
++ };
++ };
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/smi-overlay.dts
+@@ -0,0 +1,37 @@
++// Description: Overlay to enable the secondary memory interface peripheral
++// Author: Luke Wren
++
++/dts-v1/;
++/plugin/;
++
++/{
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&smi>;
++ __overlay__ {
++ pinctrl-names = "default";
++ pinctrl-0 = <&smi_pins>;
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ smi_pins: smi_pins {
++ /* Don't configure the top two address bits, as
++ these are already used as ID_SD and ID_SC */
++ brcm,pins = <2 3 4 5 6 7 8 9 10 11 12 13 14 15
++ 16 17 18 19 20 21 22 23 24 25>;
++ /* Alt 0: SMI */
++ brcm,function = <5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
++ 5 5 5 5 5 5 5 5 5>;
++ /* /CS, /WE and /OE are pulled high, as they are
++ generally active low signals */
++ brcm,pull = <2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0>;
++ };
++ };
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/spi-gpio35-39-overlay.dts
+@@ -0,0 +1,31 @@
++/*
++ * Device tree overlay to move spi0 to gpio 35 to 39 on CM
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709";
++
++ fragment@0 {
++ target = <&spi0>;
++ __overlay__ {
++ cs-gpios = <&gpio 36 1>, <&gpio 35 1>;
++ };
++ };
++
++ fragment@1 {
++ target = <&spi0_cs_pins>;
++ __overlay__ {
++ bcrm,pins = <36 35>;
++ };
++ };
++
++ fragment@2 {
++ target = <&spi0_pins>;
++ __overlay__ {
++ bcrm,pins = <37 38 39>;
++ };
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/tinylcd35-overlay.dts
+@@ -0,0 +1,216 @@
++/*
++ * tinylcd35-overlay.dts
++ *
++ * -------------------------------------------------
++ * www.tinlylcd.com
++ * -------------------------------------------------
++ * Device---Driver-----BUS GPIO's
++ * display tinylcd35 spi0.0 25 24 18
++ * touch ads7846 spi0.1 5
++ * rtc ds1307 i2c1-0068
++ * rtc pcf8563 i2c1-0051
++ * keypad gpio-keys --------- 17 22 27 23 28
++ *
++ *
++ * TinyLCD.com 3.5 inch TFT
++ *
++ * Version 001
++ * 5/3/2015 -- Noralf Trønnes Initial Device tree framework
++ * 10/3/2015 -- tinylcd@gmail.com added ds1307 support.
++ *
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++
++ fragment@0 {
++ target = <&spi0>;
++ __overlay__ {
++ status = "okay";
++
++ spidev@0{
++ status = "disabled";
++ };
++
++ spidev@1{
++ status = "disabled";
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ tinylcd35_pins: tinylcd35_pins {
++ brcm,pins = <25 24 18>;
++ brcm,function = <1>; /* out */
++ };
++ tinylcd35_ts_pins: tinylcd35_ts_pins {
++ brcm,pins = <5>;
++ brcm,function = <0>; /* in */
++ };
++ keypad_pins: keypad_pins {
++ brcm,pins = <4 17 22 23 27>;
++ brcm,function = <0>; /* in */
++ brcm,pull = <1>; /* down */
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&spi0>;
++ __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ tinylcd35: tinylcd35@0{
++ compatible = "neosec,tinylcd";
++ reg = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&tinylcd35_pins>,
++ <&tinylcd35_ts_pins>;
++
++ spi-max-frequency = <48000000>;
++ rotate = <270>;
++ fps = <20>;
++ bgr;
++ buswidth = <8>;
++ reset-gpios = <&gpio 25 0>;
++ dc-gpios = <&gpio 24 0>;
++ led-gpios = <&gpio 18 1>;
++ debug = <0>;
++
++ init = <0x10000B0 0x80
++ 0x10000C0 0x0A 0x0A
++ 0x10000C1 0x01 0x01
++ 0x10000C2 0x33
++ 0x10000C5 0x00 0x42 0x80
++ 0x10000B1 0xD0 0x11
++ 0x10000B4 0x02
++ 0x10000B6 0x00 0x22 0x3B
++ 0x10000B7 0x07
++ 0x1000036 0x58
++ 0x10000F0 0x36 0xA5 0xD3
++ 0x10000E5 0x80
++ 0x10000E5 0x01
++ 0x10000B3 0x00
++ 0x10000E5 0x00
++ 0x10000F0 0x36 0xA5 0x53
++ 0x10000E0 0x00 0x35 0x33 0x00 0x00 0x00 0x00 0x35 0x33 0x00 0x00 0x00
++ 0x100003A 0x55
++ 0x1000011
++ 0x2000001
++ 0x1000029>;
++ };
++
++ tinylcd35_ts: tinylcd35_ts@1 {
++ compatible = "ti,ads7846";
++ reg = <1>;
++ status = "disabled";
++
++ spi-max-frequency = <2000000>;
++ interrupts = <5 2>; /* high-to-low edge triggered */
++ interrupt-parent = <&gpio>;
++ pendown-gpio = <&gpio 5 0>;
++ ti,x-plate-ohms = /bits/ 16 <100>;
++ ti,pressure-max = /bits/ 16 <255>;
++ };
++ };
++ };
++
++ /* RTC */
++
++ fragment@3 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ pcf8563: pcf8563@51 {
++ compatible = "nxp,pcf8563";
++ reg = <0x51>;
++ status = "disabled";
++ };
++ };
++ };
++
++ fragment@4 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ ds1307: ds1307@68 {
++ compatible = "maxim,ds1307";
++ reg = <0x68>;
++ status = "disabled";
++ };
++ };
++ };
++
++ /*
++ * Values for input event code is found under the
++ * 'Keys and buttons' heading in include/uapi/linux/input.h
++ */
++ fragment@5 {
++ target-path = "/soc";
++ __overlay__ {
++ keypad: keypad {
++ compatible = "gpio-keys";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&keypad_pins>;
++ status = "disabled";
++ autorepeat;
++
++ button@17 {
++ label = "GPIO KEY_UP";
++ linux,code = <103>;
++ gpios = <&gpio 17 0>;
++ };
++ button@22 {
++ label = "GPIO KEY_DOWN";
++ linux,code = <108>;
++ gpios = <&gpio 22 0>;
++ };
++ button@27 {
++ label = "GPIO KEY_LEFT";
++ linux,code = <105>;
++ gpios = <&gpio 27 0>;
++ };
++ button@23 {
++ label = "GPIO KEY_RIGHT";
++ linux,code = <106>;
++ gpios = <&gpio 23 0>;
++ };
++ button@4 {
++ label = "GPIO KEY_ENTER";
++ linux,code = <28>;
++ gpios = <&gpio 4 0>;
++ };
++ };
++ };
++ };
++
++ __overrides__ {
++ speed = <&tinylcd35>,"spi-max-frequency:0";
++ rotate = <&tinylcd35>,"rotate:0";
++ fps = <&tinylcd35>,"fps:0";
++ debug = <&tinylcd35>,"debug:0";
++ touch = <&tinylcd35_ts>,"status";
++ touchgpio = <&tinylcd35_ts_pins>,"brcm,pins:0",
++ <&tinylcd35_ts>,"interrupts:0",
++ <&tinylcd35_ts>,"pendown-gpio:4";
++ xohms = <&tinylcd35_ts>,"ti,x-plate-ohms;0";
++ rtc-pcf = <&i2c1>,"status",
++ <&pcf8563>,"status";
++ rtc-ds = <&i2c1>,"status",
++ <&ds1307>,"status";
++ keypad = <&keypad>,"status";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/uart1-overlay.dts
+@@ -0,0 +1,38 @@
++/dts-v1/;
++/plugin/;
++
++/{
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&uart1>;
++ __overlay__ {
++ pinctrl-names = "default";
++ pinctrl-0 = <&uart1_pins>;
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ uart1_pins: uart1_pins {
++ brcm,pins = <14 15>;
++ brcm,function = <2>; /* alt5 */
++ brcm,pull = <0 2>;
++ };
++ };
++ };
++
++ fragment@2 {
++ target-path = "/chosen";
++ __overlay__ {
++ bootargs = "8250.nr_uarts=1";
++ };
++ };
++
++ __overrides__ {
++ txd1_pin = <&uart1_pins>,"brcm,pins:0";
++ rxd1_pin = <&uart1_pins>,"brcm,pins:4";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/vga666-overlay.dts
+@@ -0,0 +1,30 @@
++/dts-v1/;
++/plugin/;
++
++/{
++ compatible = "brcm,bcm2708";
++
++ // There is no VGA driver module, but we need a platform device
++ // node (that doesn't already use pinctrl) to hang the pinctrl
++ // reference on - leds will do
++
++ fragment@0 {
++ target = <&leds>;
++ __overlay__ {
++ pinctrl-names = "default";
++ pinctrl-0 = <&vga666_pins>;
++ };
++ };
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ vga666_pins: vga666_pins {
++ brcm,pins = <2 3 4 5 6 7 8 9 10 11 12
++ 13 14 15 16 17 18 19 20 21>;
++ brcm,function = <6>; /* alt2 */
++ brcm,pull = <0>; /* no pull */
++ };
++ };
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/w1-gpio-overlay.dts
+@@ -0,0 +1,39 @@
++// Definitions for w1-gpio module (without external pullup)
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target-path = "/";
++ __overlay__ {
++
++ w1: onewire@0 {
++ compatible = "w1-gpio";
++ pinctrl-names = "default";
++ pinctrl-0 = <&w1_pins>;
++ gpios = <&gpio 4 0>;
++ rpi,parasitic-power = <0>;
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ w1_pins: w1_pins {
++ brcm,pins = <4>;
++ brcm,function = <0>; // in (initially)
++ brcm,pull = <0>; // off
++ };
++ };
++ };
++
++ __overrides__ {
++ gpiopin = <&w1>,"gpios:4",
++ <&w1_pins>,"brcm,pins:0";
++ pullup = <&w1>,"rpi,parasitic-power:0";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/w1-gpio-pullup-overlay.dts
+@@ -0,0 +1,41 @@
++// Definitions for w1-gpio module (with external pullup)
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target-path = "/";
++ __overlay__ {
++
++ w1: onewire@0 {
++ compatible = "w1-gpio";
++ pinctrl-names = "default";
++ pinctrl-0 = <&w1_pins>;
++ gpios = <&gpio 4 0>, <&gpio 5 1>;
++ rpi,parasitic-power = <0>;
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ w1_pins: w1_pins {
++ brcm,pins = <4 5>;
++ brcm,function = <0 1>; // in out
++ brcm,pull = <0 0>; // off off
++ };
++ };
++ };
++
++ __overrides__ {
++ gpiopin = <&w1>,"gpios:4",
++ <&w1_pins>,"brcm,pins:0";
++ extpullup = <&w1>,"gpios:16",
++ <&w1_pins>,"brcm,pins:4";
++ pullup = <&w1>,"rpi,parasitic-power:0";
++ };
++};
diff --git a/target/linux/brcm2708/patches-4.4/0051-fdt-Add-support-for-the-CONFIG_CMDLINE_EXTEND-option.patch b/target/linux/brcm2708/patches-4.4/0051-fdt-Add-support-for-the-CONFIG_CMDLINE_EXTEND-option.patch
deleted file mode 100644
index 6103352b51..0000000000
--- a/target/linux/brcm2708/patches-4.4/0051-fdt-Add-support-for-the-CONFIG_CMDLINE_EXTEND-option.patch
+++ /dev/null
@@ -1,58 +0,0 @@
-From a251bf4a37d8fd468bc3ff853bcebe8ee452a31e Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Fri, 5 Dec 2014 17:26:26 +0000
-Subject: [PATCH 051/170] fdt: Add support for the CONFIG_CMDLINE_EXTEND option
-
----
- drivers/of/fdt.c | 29 ++++++++++++++++++++++++-----
- 1 file changed, 24 insertions(+), 5 deletions(-)
-
---- a/drivers/of/fdt.c
-+++ b/drivers/of/fdt.c
-@@ -954,22 +954,38 @@ int __init early_init_dt_scan_chosen(uns
-
- /* Retrieve command line */
- p = of_get_flat_dt_prop(node, "bootargs", &l);
-- if (p != NULL && l > 0)
-- strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE));
-- p = of_get_flat_dt_prop(node, "bootargs-append", &l);
-- if (p != NULL && l > 0)
-- strlcat(data, p, min_t(int, strlen(data) + (int)l, COMMAND_LINE_SIZE));
-
- /*
- * CONFIG_CMDLINE is meant to be a default in case nothing else
- * managed to set the command line, unless CONFIG_CMDLINE_FORCE
- * is set in which case we override whatever was found earlier.
-+ *
-+ * However, it can be useful to be able to treat the default as
-+ * a starting point to be extended using CONFIG_CMDLINE_EXTEND.
- */
-+ ((char *)data)[0] = '\0';
-+
- #ifdef CONFIG_CMDLINE
--#ifndef CONFIG_CMDLINE_FORCE
-- if (!((char *)data)[0])
-+ strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
-+
-+ if (p != NULL && l > 0) {
-+#if defined(CONFIG_CMDLINE_EXTEND)
-+ int len = strlen(data);
-+ if (len > 0) {
-+ strlcat(data, " ", COMMAND_LINE_SIZE);
-+ len++;
-+ }
-+ strlcpy((char *)data + len, p, min((int)l, COMMAND_LINE_SIZE - len));
-+#elif defined(CONFIG_CMDLINE_FORCE)
-+ pr_warning("Ignoring bootargs property (using the default kernel command line)\n");
-+#else
-+ /* Neither extend nor force - just override */
-+ strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE));
- #endif
-- strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
-+ }
-+#else /* CONFIG_CMDLINE */
-+ if (p != NULL && l > 0)
-+ strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE));
- #endif /* CONFIG_CMDLINE */
-
- pr_debug("Command line is: %s\n", (char*)data);
diff --git a/target/linux/brcm2708/patches-4.4/0052-BCM2708-Add-core-Device-Tree-support.patch b/target/linux/brcm2708/patches-4.4/0052-BCM2708-Add-core-Device-Tree-support.patch
deleted file mode 100644
index 84d2c7ba6f..0000000000
--- a/target/linux/brcm2708/patches-4.4/0052-BCM2708-Add-core-Device-Tree-support.patch
+++ /dev/null
@@ -1,4564 +0,0 @@
-From 0112c4ce9db6cdc53af67dc7634966c3594de7ff Mon Sep 17 00:00:00 2001
-From: notro <notro@tronnes.org>
-Date: Wed, 9 Jul 2014 14:46:08 +0200
-Subject: [PATCH 052/170] BCM2708: Add core Device Tree support
-
-Add the bare minimum needed to boot BCM2708 from a Device Tree.
-
-Signed-off-by: Noralf Tronnes <notro@tronnes.org>
-
-BCM2708: DT: change 'axi' nodename to 'soc'
-
-Change DT node named 'axi' to 'soc' so it matches ARCH_BCM2835.
-The VC4 bootloader fills in certain properties in the 'axi' subtree,
-but since this is part of an upstreaming effort, the name is changed.
-
-Signed-off-by: Noralf Tronnes notro@tronnes.org
-
-BCM2708_DT: Correct length of the peripheral space
-
-Use dts-dirs feature for overlays.
-
-The kernel makefiles have a dts-dirs target that is for vendor subdirectories.
-
-Using this fixes the install_dtbs target, which previously did not install the overlays.
-
-BCM270X_DT: configure I2S DMA channels
-
-Signed-off-by: Matthias Reichl <hias@horus.com>
-
-BCM270X_DT: switch to bcm2835-i2s
-
-I2S soundcard drivers with proper devicetree support (i.e. not linking
-to the cpu_dai/platform via name but to cpu/platform via of_node)
-will work out of the box without any modifications.
-
-When the kernel is compiled without devicetree support the platform
-code will instantiate the bcm2708-i2s driver and I2S soundcard drivers
-will link to it via name, as before.
-
-Signed-off-by: Matthias Reichl <hias@horus.com>
-
-SDIO-overlay: add poll_once-boolean parameter
-
-Add paramter to toggle sdio-device-polling
-done every second or once at boot-time.
-
-Signed-off-by: Patrick Boettcher <patrick.boettcher@posteo.de>
-
-BCM270X_DT: Make mmc overlay compatible with current firmware
-
-The original DT overlay logic followed a merge-then-patch procedure,
-i.e. parameters are applied to the loaded overlay before the overlay
-is merged into the base DTB. This sequence has been changed to
-patch-then-merge, in order to support parameterised node names, and
-to protect against bad overlays. As a result, overrides (parameters)
-must only target labels in the overlay, but the overlay can obviously target nodes in the base DTB.
-
-mmc-overlay.dts (that switches back to the original mmc sdcard
-driver) is the only overlay violating that rule, and this patch
-fixes it.
-
-bcm270x_dt: Use the sdhost MMC controller by default
-
-The "mmc" overlay reverts to using the other controller.
-
-squash: Add cprman to dt
-
-BCM270X_DT: Use clk_core for I2C interfaces
----
- arch/arm/boot/dts/Makefile | 30 +
- arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 145 +++++
- arch/arm/boot/dts/bcm2708-rpi-b.dts | 135 +++++
- arch/arm/boot/dts/bcm2708-rpi-cm.dts | 102 ++++
- arch/arm/boot/dts/bcm2708-rpi-cm.dtsi | 40 ++
- arch/arm/boot/dts/bcm2708.dtsi | 40 ++
- arch/arm/boot/dts/bcm2708_common.dtsi | 347 +++++++++++
- arch/arm/boot/dts/bcm2709-rpi-2-b.dts | 145 +++++
- arch/arm/boot/dts/bcm2709.dtsi | 102 ++++
- arch/arm/boot/dts/bcm2835-rpi-cm.dts | 93 +++
- arch/arm/boot/dts/bcm2835-rpi-cm.dtsi | 30 +
- arch/arm/boot/dts/overlays/Makefile | 69 +++
- arch/arm/boot/dts/overlays/README | 648 +++++++++++++++++++++
- arch/arm/boot/dts/overlays/ads7846-overlay.dts | 83 +++
- .../dts/overlays/bmp085_i2c-sensor-overlay.dts | 23 +
- arch/arm/boot/dts/overlays/dht11-overlay.dts | 39 ++
- arch/arm/boot/dts/overlays/enc28j60-overlay.dts | 50 ++
- .../boot/dts/overlays/gpio-poweroff-overlay.dts | 34 ++
- .../boot/dts/overlays/hifiberry-amp-overlay.dts | 39 ++
- .../boot/dts/overlays/hifiberry-dac-overlay.dts | 34 ++
- .../dts/overlays/hifiberry-dacplus-overlay.dts | 39 ++
- .../boot/dts/overlays/hifiberry-digi-overlay.dts | 39 ++
- arch/arm/boot/dts/overlays/hy28a-overlay.dts | 87 +++
- arch/arm/boot/dts/overlays/hy28b-overlay.dts | 142 +++++
- arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts | 55 ++
- arch/arm/boot/dts/overlays/i2s-mmap-overlay.dts | 13 +
- arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts | 39 ++
- .../boot/dts/overlays/iqaudio-dacplus-overlay.dts | 39 ++
- arch/arm/boot/dts/overlays/lirc-rpi-overlay.dts | 57 ++
- .../arm/boot/dts/overlays/mcp2515-can0-overlay.dts | 69 +++
- .../arm/boot/dts/overlays/mcp2515-can1-overlay.dts | 69 +++
- arch/arm/boot/dts/overlays/mmc-overlay.dts | 39 ++
- arch/arm/boot/dts/overlays/mz61581-overlay.dts | 111 ++++
- arch/arm/boot/dts/overlays/piscreen-overlay.dts | 96 +++
- .../dts/overlays/pitft28-resistive-overlay.dts | 115 ++++
- arch/arm/boot/dts/overlays/pps-gpio-overlay.dts | 34 ++
- arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts | 46 ++
- arch/arm/boot/dts/overlays/pwm-overlay.dts | 42 ++
- arch/arm/boot/dts/overlays/raspidac3-overlay.dts | 45 ++
- arch/arm/boot/dts/overlays/rpi-dac-overlay.dts | 34 ++
- arch/arm/boot/dts/overlays/rpi-display-overlay.dts | 82 +++
- arch/arm/boot/dts/overlays/rpi-ft5406-overlay.dts | 17 +
- arch/arm/boot/dts/overlays/rpi-proto-overlay.dts | 39 ++
- arch/arm/boot/dts/overlays/rpi-sense-overlay.dts | 47 ++
- arch/arm/boot/dts/overlays/sdhost-overlay.dts | 29 +
- arch/arm/boot/dts/overlays/sdio-overlay.dts | 32 +
- arch/arm/boot/dts/overlays/smi-dev-overlay.dts | 18 +
- arch/arm/boot/dts/overlays/smi-nand-overlay.dts | 69 +++
- arch/arm/boot/dts/overlays/smi-overlay.dts | 37 ++
- .../boot/dts/overlays/spi-gpio35-39-overlay.dts | 31 +
- arch/arm/boot/dts/overlays/tinylcd35-overlay.dts | 216 +++++++
- arch/arm/boot/dts/overlays/uart1-overlay.dts | 38 ++
- arch/arm/boot/dts/overlays/vga666-overlay.dts | 30 +
- arch/arm/boot/dts/overlays/w1-gpio-overlay.dts | 39 ++
- .../boot/dts/overlays/w1-gpio-pullup-overlay.dts | 41 ++
- 55 files changed, 4203 insertions(+)
- create mode 100644 arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
- create mode 100644 arch/arm/boot/dts/bcm2708-rpi-b.dts
- create mode 100755 arch/arm/boot/dts/bcm2708-rpi-cm.dts
- create mode 100644 arch/arm/boot/dts/bcm2708-rpi-cm.dtsi
- create mode 100644 arch/arm/boot/dts/bcm2708.dtsi
- create mode 100644 arch/arm/boot/dts/bcm2708_common.dtsi
- create mode 100644 arch/arm/boot/dts/bcm2709-rpi-2-b.dts
- create mode 100644 arch/arm/boot/dts/bcm2709.dtsi
- create mode 100644 arch/arm/boot/dts/bcm2835-rpi-cm.dts
- create mode 100644 arch/arm/boot/dts/bcm2835-rpi-cm.dtsi
- create mode 100644 arch/arm/boot/dts/overlays/Makefile
- create mode 100644 arch/arm/boot/dts/overlays/README
- create mode 100644 arch/arm/boot/dts/overlays/ads7846-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/bmp085_i2c-sensor-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/dht11-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/enc28j60-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/hifiberry-amp-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/hifiberry-dac-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/hifiberry-digi-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/hy28a-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/hy28b-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/i2s-mmap-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/lirc-rpi-overlay.dts
- create mode 100755 arch/arm/boot/dts/overlays/mcp2515-can0-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/mcp2515-can1-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/mmc-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/mz61581-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/piscreen-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/pitft28-resistive-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/pps-gpio-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/pwm-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/raspidac3-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/rpi-dac-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/rpi-display-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/rpi-ft5406-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/rpi-proto-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/rpi-sense-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/sdhost-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/sdio-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/smi-dev-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/smi-nand-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/smi-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/spi-gpio35-39-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/tinylcd35-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/uart1-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/vga666-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/w1-gpio-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/w1-gpio-pullup-overlay.dts
-
---- a/arch/arm/boot/dts/Makefile
-+++ b/arch/arm/boot/dts/Makefile
-@@ -1,5 +1,25 @@
- ifeq ($(CONFIG_OF),y)
-
-+dtb-$(CONFIG_ARCH_BCM2708) += bcm2708-rpi-b.dtb
-+dtb-$(CONFIG_ARCH_BCM2708) += bcm2708-rpi-b-plus.dtb
-+dtb-$(CONFIG_ARCH_BCM2708) += bcm2708-rpi-cm.dtb
-+dtb-$(CONFIG_ARCH_BCM2835) += bcm2835-rpi-cm.dtb
-+dtb-$(CONFIG_ARCH_BCM2709) += bcm2709-rpi-2-b.dtb
-+
-+# Raspberry Pi
-+ifeq ($(CONFIG_ARCH_BCM2708),y)
-+ RPI_DT_OVERLAYS=y
-+endif
-+ifeq ($(CONFIG_ARCH_BCM2709),y)
-+ RPI_DT_OVERLAYS=y
-+endif
-+ifeq ($(CONFIG_ARCH_BCM2835),y)
-+ RPI_DT_OVERLAYS=y
-+endif
-+ifeq ($(RPI_DT_OVERLAYS),y)
-+ dts-dirs += overlays
-+endif
-+
- dtb-$(CONFIG_ARCH_ALPINE) += \
- alpine-db.dtb
- dtb-$(CONFIG_MACH_ASM9260) += \
-@@ -777,10 +797,20 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \
- mt8127-moose.dtb \
- mt8135-evbp1.dtb
- dtb-$(CONFIG_ARCH_ZX) += zx296702-ad1.dtb
-+
-+targets += dtbs dtbs_install
-+targets += $(dtb-y)
-+
- endif
-
- dtstree := $(srctree)/$(src)
- dtb-$(CONFIG_OF_ALL_DTBS) := $(patsubst $(dtstree)/%.dts,%.dtb, $(wildcard $(dtstree)/*.dts))
-
- always := $(dtb-y)
-+subdir-y := $(dts-dirs)
- clean-files := *.dtb
-+
-+# Enable fixups to support overlays on BCM2708 platforms
-+ifeq ($(RPI_DT_OVERLAYS),y)
-+ DTC_FLAGS ?= -@
-+endif
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
-@@ -0,0 +1,145 @@
-+/dts-v1/;
-+
-+#include "bcm2708.dtsi"
-+
-+/ {
-+ compatible = "brcm,bcm2708";
-+ model = "Raspberry Pi Model B+";
-+};
-+
-+&gpio {
-+ sdhost_pins: sdhost_pins {
-+ brcm,pins = <48 49 50 51 52 53>;
-+ brcm,function = <4>; /* alt0 */
-+ };
-+
-+ spi0_pins: spi0_pins {
-+ brcm,pins = <9 10 11>;
-+ brcm,function = <4>; /* alt0 */
-+ };
-+
-+ spi0_cs_pins: spi0_cs_pins {
-+ brcm,pins = <8 7>;
-+ brcm,function = <1>; /* output */
-+ };
-+
-+ i2c0_pins: i2c0 {
-+ brcm,pins = <0 1>;
-+ brcm,function = <4>;
-+ };
-+
-+ i2c1_pins: i2c1 {
-+ brcm,pins = <2 3>;
-+ brcm,function = <4>;
-+ };
-+
-+ i2s_pins: i2s {
-+ brcm,pins = <18 19 20 21>;
-+ brcm,function = <4>; /* alt0 */
-+ };
-+};
-+
-+&sdhost {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&sdhost_pins>;
-+ bus-width = <4>;
-+ status = "okay";
-+};
-+
-+&fb {
-+ status = "okay";
-+};
-+
-+&uart0 {
-+ status = "okay";
-+};
-+
-+&spi0 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&spi0_pins &spi0_cs_pins>;
-+ cs-gpios = <&gpio 8 1>, <&gpio 7 1>;
-+
-+ spidev@0{
-+ compatible = "spidev";
-+ reg = <0>; /* CE0 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <500000>;
-+ };
-+
-+ spidev@1{
-+ compatible = "spidev";
-+ reg = <1>; /* CE1 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <500000>;
-+ };
-+};
-+
-+&i2c0 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c0_pins>;
-+ clock-frequency = <100000>;
-+};
-+
-+&i2c1 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c1_pins>;
-+ clock-frequency = <100000>;
-+};
-+
-+&i2c2 {
-+ clock-frequency = <100000>;
-+};
-+
-+&i2s {
-+ #sound-dai-cells = <0>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2s_pins>;
-+};
-+
-+&random {
-+ status = "okay";
-+};
-+
-+&leds {
-+ act_led: act {
-+ label = "led0";
-+ linux,default-trigger = "mmc0";
-+ gpios = <&gpio 47 0>;
-+ };
-+
-+ pwr_led: pwr {
-+ label = "led1";
-+ linux,default-trigger = "input";
-+ gpios = <&gpio 35 0>;
-+ };
-+};
-+
-+/ {
-+ __overrides__ {
-+ uart0 = <&uart0>,"status";
-+ uart0_clkrate = <&clk_uart0>,"clock-frequency:0";
-+ i2s = <&i2s>,"status";
-+ spi = <&spi0>,"status";
-+ i2c0 = <&i2c0>,"status";
-+ i2c1 = <&i2c1>,"status";
-+ i2c2_iknowwhatimdoing = <&i2c2>,"status";
-+ i2c0_baudrate = <&i2c0>,"clock-frequency:0";
-+ i2c1_baudrate = <&i2c1>,"clock-frequency:0";
-+ i2c2_baudrate = <&i2c2>,"clock-frequency:0";
-+ core_freq = <&clk_core>,"clock-frequency:0";
-+
-+ act_led_gpio = <&act_led>,"gpios:4";
-+ act_led_activelow = <&act_led>,"gpios:8";
-+ act_led_trigger = <&act_led>,"linux,default-trigger";
-+
-+ pwr_led_gpio = <&pwr_led>,"gpios:4";
-+ pwr_led_activelow = <&pwr_led>,"gpios:8";
-+ pwr_led_trigger = <&pwr_led>,"linux,default-trigger";
-+
-+ audio = <&audio>,"status";
-+ watchdog = <&watchdog>,"status";
-+ random = <&random>,"status";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2708-rpi-b.dts
-@@ -0,0 +1,135 @@
-+/dts-v1/;
-+
-+#include "bcm2708.dtsi"
-+
-+/ {
-+ compatible = "brcm,bcm2708";
-+ model = "Raspberry Pi Model B";
-+};
-+
-+&gpio {
-+ sdhost_pins: sdhost_pins {
-+ brcm,pins = <48 49 50 51 52 53>;
-+ brcm,function = <4>; /* alt0 */
-+ };
-+
-+ spi0_pins: spi0_pins {
-+ brcm,pins = <9 10 11>;
-+ brcm,function = <4>; /* alt0 */
-+ };
-+
-+ spi0_cs_pins: spi0_cs_pins {
-+ brcm,pins = <8 7>;
-+ brcm,function = <1>; /* output */
-+ };
-+
-+ i2c0_pins: i2c0 {
-+ brcm,pins = <0 1>;
-+ brcm,function = <4>;
-+ };
-+
-+ i2c1_pins: i2c1 {
-+ brcm,pins = <2 3>;
-+ brcm,function = <4>;
-+ };
-+
-+ i2s_pins: i2s {
-+ brcm,pins = <28 29 30 31>;
-+ brcm,function = <6>; /* alt2 */
-+ };
-+};
-+
-+&sdhost {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&sdhost_pins>;
-+ bus-width = <4>;
-+ status = "okay";
-+};
-+
-+&fb {
-+ status = "okay";
-+};
-+
-+&uart0 {
-+ status = "okay";
-+};
-+
-+&spi0 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&spi0_pins &spi0_cs_pins>;
-+ cs-gpios = <&gpio 8 1>, <&gpio 7 1>;
-+
-+ spidev@0{
-+ compatible = "spidev";
-+ reg = <0>; /* CE0 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <500000>;
-+ };
-+
-+ spidev@1{
-+ compatible = "spidev";
-+ reg = <1>; /* CE1 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <500000>;
-+ };
-+};
-+
-+&i2c0 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c0_pins>;
-+ clock-frequency = <100000>;
-+};
-+
-+&i2c1 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c1_pins>;
-+ clock-frequency = <100000>;
-+};
-+
-+&i2c2 {
-+ clock-frequency = <100000>;
-+};
-+
-+&i2s {
-+ #sound-dai-cells = <0>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2s_pins>;
-+};
-+
-+&random {
-+ status = "okay";
-+};
-+
-+&leds {
-+ act_led: act {
-+ label = "led0";
-+ linux,default-trigger = "mmc0";
-+ gpios = <&gpio 16 1>;
-+ };
-+};
-+
-+/ {
-+ __overrides__ {
-+ uart0 = <&uart0>,"status";
-+ uart0_clkrate = <&clk_uart0>,"clock-frequency:0";
-+ i2s = <&i2s>,"status";
-+ spi = <&spi0>,"status";
-+ i2c0 = <&i2c0>,"status";
-+ i2c1 = <&i2c1>,"status";
-+ i2c2_iknowwhatimdoing = <&i2c2>,"status";
-+ i2c0_baudrate = <&i2c0>,"clock-frequency:0";
-+ i2c1_baudrate = <&i2c1>,"clock-frequency:0";
-+ i2c2_baudrate = <&i2c2>,"clock-frequency:0";
-+ core_freq = <&clk_core>,"clock-frequency:0";
-+
-+ act_led_gpio = <&act_led>,"gpios:4";
-+ act_led_activelow = <&act_led>,"gpios:8";
-+ act_led_trigger = <&act_led>,"linux,default-trigger";
-+
-+ audio = <&audio>,"status";
-+ watchdog = <&watchdog>,"status";
-+ random = <&random>,"status";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dts
-@@ -0,0 +1,102 @@
-+/dts-v1/;
-+
-+#include "bcm2708-rpi-cm.dtsi"
-+
-+/ {
-+ model = "Raspberry Pi Compute Module";
-+};
-+
-+&uart0 {
-+ status = "okay";
-+};
-+
-+&gpio {
-+ spi0_pins: spi0_pins {
-+ brcm,pins = <9 10 11>;
-+ brcm,function = <4>; /* alt0 */
-+ };
-+
-+ spi0_cs_pins: spi0_cs_pins {
-+ brcm,pins = <8 7>;
-+ brcm,function = <1>; /* output */
-+ };
-+
-+ i2c0_pins: i2c0 {
-+ brcm,pins = <0 1>;
-+ brcm,function = <4>;
-+ };
-+
-+ i2c1_pins: i2c1 {
-+ brcm,pins = <2 3>;
-+ brcm,function = <4>;
-+ };
-+
-+ i2s_pins: i2s {
-+ brcm,pins = <18 19 20 21>;
-+ brcm,function = <4>; /* alt0 */
-+ };
-+};
-+
-+&spi0 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&spi0_pins &spi0_cs_pins>;
-+ cs-gpios = <&gpio 8 1>, <&gpio 7 1>;
-+
-+ spidev@0{
-+ compatible = "spidev";
-+ reg = <0>; /* CE0 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <500000>;
-+ };
-+
-+ spidev@1{
-+ compatible = "spidev";
-+ reg = <1>; /* CE1 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <500000>;
-+ };
-+};
-+
-+&i2c0 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c0_pins>;
-+ clock-frequency = <100000>;
-+};
-+
-+&i2c1 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c1_pins>;
-+ clock-frequency = <100000>;
-+};
-+
-+&i2c2 {
-+ clock-frequency = <100000>;
-+};
-+
-+&i2s {
-+ #sound-dai-cells = <0>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2s_pins>;
-+};
-+
-+&random {
-+ status = "okay";
-+};
-+
-+/ {
-+ __overrides__ {
-+ uart0 = <&uart0>,"status";
-+ uart0_clkrate = <&clk_uart0>,"clock-frequency:0";
-+ i2s = <&i2s>,"status";
-+ spi = <&spi0>,"status";
-+ i2c0 = <&i2c0>,"status";
-+ i2c1 = <&i2c1>,"status";
-+ i2c2_iknowwhatimdoing = <&i2c2>,"status";
-+ i2c0_baudrate = <&i2c0>,"clock-frequency:0";
-+ i2c1_baudrate = <&i2c1>,"clock-frequency:0";
-+ i2c2_baudrate = <&i2c2>,"clock-frequency:0";
-+ core_freq = <&clk_core>,"clock-frequency:0";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi
-@@ -0,0 +1,40 @@
-+#include "bcm2708.dtsi"
-+
-+&gpio {
-+ sdhost_pins: sdhost_pins {
-+ brcm,pins = <48 49 50 51 52 53>;
-+ brcm,function = <4>; /* alt0 */
-+ };
-+};
-+
-+&leds {
-+ act_led: act {
-+ label = "led0";
-+ linux,default-trigger = "mmc0";
-+ gpios = <&gpio 47 0>;
-+ };
-+};
-+
-+&sdhost {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&sdhost_pins>;
-+ bus-width = <4>;
-+ non-removable;
-+ status = "okay";
-+};
-+
-+&fb {
-+ status = "okay";
-+};
-+
-+/ {
-+ __overrides__ {
-+ act_led_gpio = <&act_led>,"gpios:4";
-+ act_led_activelow = <&act_led>,"gpios:8";
-+ act_led_trigger = <&act_led>,"linux,default-trigger";
-+
-+ audio = <&audio>,"status";
-+ watchdog = <&watchdog>,"status";
-+ random = <&random>,"status";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2708.dtsi
-@@ -0,0 +1,40 @@
-+#include "bcm2708_common.dtsi"
-+
-+/ {
-+ compatible = "brcm,bcm2708";
-+ model = "BCM2708";
-+
-+ chosen {
-+ /* No padding required - the boot loader can do that. */
-+ bootargs = "";
-+ };
-+
-+ soc {
-+ ranges = <0x7e000000 0x20000000 0x01000000>;
-+
-+ timer@7e003000 {
-+ compatible = "brcm,bcm2835-system-timer";
-+ reg = <0x7e003000 0x1000>;
-+ interrupts = <1 0>, <1 1>, <1 2>, <1 3>;
-+ clock-frequency = <1000000>;
-+ };
-+
-+ arm-pmu {
-+ compatible = "arm,arm1176-pmu";
-+ };
-+
-+ gpiomem {
-+ compatible = "brcm,bcm2835-gpiomem";
-+ reg = <0x7e200000 0x1000>;
-+ status = "okay";
-+ };
-+ };
-+};
-+
-+&intc {
-+ compatible = "brcm,bcm2835-armctrl-ic";
-+};
-+
-+&watchdog {
-+ status = "okay";
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2708_common.dtsi
-@@ -0,0 +1,347 @@
-+#include "skeleton.dtsi"
-+
-+/ {
-+ interrupt-parent = <&intc>;
-+
-+ aliases {
-+ audio = &audio;
-+ sound = &sound;
-+ soc = &soc;
-+ dma = &dma;
-+ intc = &intc;
-+ watchdog = &watchdog;
-+ random = &random;
-+ mailbox = &mailbox;
-+ gpio = &gpio;
-+ uart0 = &uart0;
-+ sdhost = &sdhost;
-+ i2s = &i2s;
-+ spi0 = &spi0;
-+ i2c0 = &i2c0;
-+ uart1 = &uart1;
-+ mmc = &mmc;
-+ i2c1 = &i2c1;
-+ i2c2 = &i2c2;
-+ usb = &usb;
-+ leds = &leds;
-+ fb = &fb;
-+ vchiq = &vchiq;
-+ thermal = &thermal;
-+ clocks = &clocks;
-+ };
-+
-+ /* Onboard audio */
-+ audio: audio {
-+ compatible = "brcm,bcm2835-audio";
-+ brcm,pwm-channels = <8>;
-+ status = "disabled";
-+ };
-+
-+ /* External sound card */
-+ sound: sound {
-+ };
-+
-+ soc: soc {
-+ compatible = "simple-bus";
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+
-+ dma: dma@7e007000 {
-+ compatible = "brcm,bcm2835-dma";
-+ reg = <0x7e007000 0xf00>;
-+ interrupts = <1 16>,
-+ <1 17>,
-+ <1 18>,
-+ <1 19>,
-+ <1 20>,
-+ <1 21>,
-+ <1 22>,
-+ <1 23>,
-+ <1 24>,
-+ <1 25>,
-+ <1 26>,
-+ <1 27>;
-+
-+ #dma-cells = <1>;
-+ brcm,dma-channel-mask = <0x0f35>;
-+ };
-+
-+ intc: interrupt-controller@7e00b200 {
-+ compatible = "brcm,bcm2708-armctrl-ic";
-+ reg = <0x7e00b200 0x200>;
-+ interrupt-controller;
-+ #interrupt-cells = <2>;
-+ };
-+
-+ mailbox: mailbox@7e00b800 {
-+ compatible = "brcm,bcm2835-mbox";
-+ reg = <0x7e00b880 0x40>;
-+ interrupts = <0 1>;
-+ #mbox-cells = <0>;
-+ };
-+
-+ watchdog: watchdog@7e100000 {
-+ compatible = "brcm,bcm2835-pm-wdt";
-+ reg = <0x7e100000 0x28>;
-+ status = "disabled";
-+ };
-+
-+ cprman: cprman@7e101000 {
-+ compatible = "brcm,bcm2835-cprman";
-+ #clock-cells = <1>;
-+ reg = <0x7e101000 0x2000>;
-+
-+ /* CPRMAN derives everything from the platform's
-+ * oscillator.
-+ */
-+ clocks = <&clk_osc>;
-+ status = "disabled";
-+ };
-+
-+ random: rng@7e104000 {
-+ compatible = "brcm,bcm2835-rng";
-+ reg = <0x7e104000 0x10>;
-+ status = "disabled";
-+ };
-+
-+ gpio: gpio@7e200000 {
-+ compatible = "brcm,bcm2835-gpio";
-+ reg = <0x7e200000 0xb4>;
-+ interrupts = <2 17>, <2 18>;
-+
-+ gpio-controller;
-+ #gpio-cells = <2>;
-+
-+ interrupt-controller;
-+ #interrupt-cells = <2>;
-+ };
-+
-+ uart0: uart@7e201000 {
-+ compatible = "arm,pl011", "arm,primecell";
-+ reg = <0x7e201000 0x1000>;
-+ interrupts = <2 25>;
-+ clocks = <&clk_uart0 &clk_apb_p>;
-+ clock-names = "uartclk","apb_pclk";
-+ arm,primecell-periphid = <0x00241011>; // For an explanation, see
-+ // https://github.com/raspberrypi/linux/commit/13731d862cf5219216533a3b0de052cee4cc5038
-+ status = "disabled";
-+ };
-+
-+ sdhost: sdhost@7e202000 {
-+ compatible = "brcm,bcm2835-sdhost";
-+ reg = <0x7e202000 0x100>;
-+ interrupts = <2 24>;
-+ clocks = <&clk_core>;
-+ dmas = <&dma 13>,
-+ <&dma 13>;
-+ dma-names = "tx", "rx";
-+ brcm,pio-limit = <1>;
-+ status = "disabled";
-+ };
-+
-+ i2s: i2s@7e203000 {
-+ compatible = "brcm,bcm2835-i2s";
-+ reg = <0x7e203000 0x24>,
-+ <0x7e101098 0x08>;
-+
-+ dmas = <&dma 2>, <&dma 3>;
-+ dma-names = "tx", "rx";
-+ status = "disabled";
-+ };
-+
-+ spi0: spi@7e204000 {
-+ compatible = "brcm,bcm2835-spi";
-+ reg = <0x7e204000 0x1000>;
-+ interrupts = <2 22>;
-+ clocks = <&clk_core>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ /* the dma channels */
-+ dmas = <&dma 6>, <&dma 7>;
-+ dma-names = "tx", "rx";
-+ /* the chipselects used - <0> means native GPIO
-+ * add more gpios if necessary as <&gpio 6 1>
-+ * (but do not forget to make them output!)
-+ */
-+ cs-gpios = <0>, <0>;
-+ };
-+
-+ i2c0: i2c@7e205000 {
-+ compatible = "brcm,bcm2708-i2c";
-+ reg = <0x7e205000 0x1000>;
-+ interrupts = <2 21>;
-+ clocks = <&clk_core>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ pwm: pwm@7e20c000 {
-+ compatible = "brcm,bcm2835-pwm";
-+ reg = <0x7e20c000 0x28>;
-+ clocks = <&clk_pwm>;
-+ #pwm-cells = <2>;
-+ status = "disabled";
-+ };
-+
-+ uart1: uart@7e215040 {
-+ compatible = "brcm,bcm2835-aux-uart", "ns16550";
-+ reg = <0x7e215040 0x40>;
-+ interrupts = <1 29>;
-+ clocks = <&clk_uart1>;
-+ reg-shift = <2>;
-+ no-loopback-test;
-+ status = "disabled";
-+ };
-+
-+ mmc: mmc@7e300000 {
-+ compatible = "brcm,bcm2835-mmc";
-+ reg = <0x7e300000 0x100>;
-+ interrupts = <2 30>;
-+ clocks = <&clk_mmc>;
-+ dmas = <&dma 11>,
-+ <&dma 11>;
-+ dma-names = "tx", "rx";
-+ status = "disabled";
-+ };
-+
-+ i2c1: i2c@7e804000 {
-+ compatible = "brcm,bcm2708-i2c";
-+ reg = <0x7e804000 0x1000>;
-+ interrupts = <2 21>;
-+ clocks = <&clk_core>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ i2c2: i2c@7e805000 {
-+ // Beware - this is shared with the HDMI module.
-+ // Careless use may break (really) your display.
-+ // Caveat emptor.
-+ compatible = "brcm,bcm2708-i2c";
-+ reg = <0x7e805000 0x1000>;
-+ interrupts = <2 21>;
-+ clocks = <&clk_core>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ smi: smi@7e600000 {
-+ compatible = "brcm,bcm2835-smi";
-+ reg = <0x7e600000 0x44>, <0x7e1010b0 0x8>;
-+ interrupts = <2 16>;
-+ brcm,smi-clock-source = <6>;
-+ brcm,smi-clock-divisor = <4>;
-+ dmas = <&dma 4>;
-+ dma-names = "rx-tx";
-+ status = "disabled";
-+ };
-+
-+ usb: usb@7e980000 {
-+ compatible = "brcm,bcm2708-usb";
-+ reg = <0x7e980000 0x10000>,
-+ <0x7e006000 0x1000>;
-+ interrupts = <2 0>,
-+ <1 9>;
-+ };
-+
-+ firmware: firmware {
-+ compatible = "raspberrypi,bcm2835-firmware";
-+ mboxes = <&mailbox>;
-+ };
-+
-+ leds: leds {
-+ compatible = "gpio-leds";
-+ };
-+
-+ fb: fb {
-+ compatible = "brcm,bcm2708-fb";
-+ firmware = <&firmware>;
-+ status = "disabled";
-+ };
-+
-+ vchiq: vchiq {
-+ compatible = "brcm,bcm2835-vchiq";
-+ reg = <0x7e00b840 0xf>;
-+ interrupts = <0 2>;
-+ cache-line-size = <32>;
-+ firmware = <&firmware>;
-+ };
-+
-+ thermal: thermal {
-+ compatible = "brcm,bcm2835-thermal";
-+ firmware = <&firmware>;
-+ };
-+ };
-+
-+ clocks: clocks {
-+ compatible = "simple-bus";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ clk_core: clock@0 {
-+ compatible = "fixed-clock";
-+ reg = <0>;
-+ #clock-cells = <0>;
-+ clock-output-names = "core";
-+ clock-frequency = <250000000>;
-+ };
-+
-+ clk_mmc: clock@1 {
-+ compatible = "fixed-clock";
-+ reg = <1>;
-+ #clock-cells = <0>;
-+ clock-output-names = "mmc";
-+ clock-frequency = <250000000>;
-+ };
-+
-+ clk_uart0: clock@2 {
-+ compatible = "fixed-clock";
-+ reg = <2>;
-+ #clock-cells = <0>;
-+ clock-output-names = "uart0_pclk";
-+ clock-frequency = <3000000>;
-+ };
-+
-+ clk_apb_p: clock@3 {
-+ compatible = "fixed-clock";
-+ reg = <3>;
-+ #clock-cells = <0>;
-+ clock-output-names = "apb_pclk";
-+ clock-frequency = <126000000>;
-+ };
-+
-+ clk_pwm: clock@4 {
-+ compatible = "fixed-clock";
-+ reg = <4>;
-+ #clock-cells = <0>;
-+ clock-output-names = "pwm";
-+ clock-frequency = <100000000>;
-+ };
-+
-+ clk_uart1: clock@5 {
-+ compatible = "fixed-factor-clock";
-+ reg = <5>;
-+ clocks = <&clk_core>;
-+ #clock-cells = <0>;
-+ clock-div = <1>;
-+ clock-mult = <2>;
-+ };
-+
-+ /* The oscillator is the root of the clock tree. */
-+ clk_osc: clock@6 {
-+ compatible = "fixed-clock";
-+ reg = <6>;
-+ #clock-cells = <0>;
-+ clock-output-names = "osc";
-+ clock-frequency = <19200000>;
-+ };
-+ };
-+
-+ __overrides__ {
-+ cache_line_size = <&vchiq>, "cache-line-size:0";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts
-@@ -0,0 +1,145 @@
-+/dts-v1/;
-+
-+#include "bcm2709.dtsi"
-+
-+/ {
-+ compatible = "brcm,bcm2709";
-+ model = "Raspberry Pi 2 Model B";
-+};
-+
-+&gpio {
-+ sdhost_pins: sdhost_pins {
-+ brcm,pins = <48 49 50 51 52 53>;
-+ brcm,function = <4>; /* alt0 */
-+ };
-+
-+ spi0_pins: spi0_pins {
-+ brcm,pins = <9 10 11>;
-+ brcm,function = <4>; /* alt0 */
-+ };
-+
-+ spi0_cs_pins: spi0_cs_pins {
-+ brcm,pins = <8 7>;
-+ brcm,function = <1>; /* output */
-+ };
-+
-+ i2c0_pins: i2c0 {
-+ brcm,pins = <0 1>;
-+ brcm,function = <4>;
-+ };
-+
-+ i2c1_pins: i2c1 {
-+ brcm,pins = <2 3>;
-+ brcm,function = <4>;
-+ };
-+
-+ i2s_pins: i2s {
-+ brcm,pins = <18 19 20 21>;
-+ brcm,function = <4>; /* alt0 */
-+ };
-+};
-+
-+&sdhost {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&sdhost_pins>;
-+ bus-width = <4>;
-+ status = "okay";
-+};
-+
-+&fb {
-+ status = "okay";
-+};
-+
-+&uart0 {
-+ status = "okay";
-+};
-+
-+&spi0 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&spi0_pins &spi0_cs_pins>;
-+ cs-gpios = <&gpio 8 1>, <&gpio 7 1>;
-+
-+ spidev@0{
-+ compatible = "spidev";
-+ reg = <0>; /* CE0 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <500000>;
-+ };
-+
-+ spidev@1{
-+ compatible = "spidev";
-+ reg = <1>; /* CE1 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <500000>;
-+ };
-+};
-+
-+&i2c0 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c0_pins>;
-+ clock-frequency = <100000>;
-+};
-+
-+&i2c1 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c1_pins>;
-+ clock-frequency = <100000>;
-+};
-+
-+&i2c2 {
-+ clock-frequency = <100000>;
-+};
-+
-+&i2s {
-+ #sound-dai-cells = <0>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2s_pins>;
-+};
-+
-+&random {
-+ status = "okay";
-+};
-+
-+&leds {
-+ act_led: act {
-+ label = "led0";
-+ linux,default-trigger = "mmc0";
-+ gpios = <&gpio 47 0>;
-+ };
-+
-+ pwr_led: pwr {
-+ label = "led1";
-+ linux,default-trigger = "input";
-+ gpios = <&gpio 35 0>;
-+ };
-+};
-+
-+/ {
-+ __overrides__ {
-+ uart0 = <&uart0>,"status";
-+ uart0_clkrate = <&clk_uart0>,"clock-frequency:0";
-+ i2s = <&i2s>,"status";
-+ spi = <&spi0>,"status";
-+ i2c0 = <&i2c0>,"status";
-+ i2c1 = <&i2c1>,"status";
-+ i2c2_iknowwhatimdoing = <&i2c2>,"status";
-+ i2c0_baudrate = <&i2c0>,"clock-frequency:0";
-+ i2c1_baudrate = <&i2c1>,"clock-frequency:0";
-+ i2c2_baudrate = <&i2c2>,"clock-frequency:0";
-+ core_freq = <&clk_core>,"clock-frequency:0";
-+
-+ act_led_gpio = <&act_led>,"gpios:4";
-+ act_led_activelow = <&act_led>,"gpios:8";
-+ act_led_trigger = <&act_led>,"linux,default-trigger";
-+
-+ pwr_led_gpio = <&pwr_led>,"gpios:4";
-+ pwr_led_activelow = <&pwr_led>,"gpios:8";
-+ pwr_led_trigger = <&pwr_led>,"linux,default-trigger";
-+
-+ audio = <&audio>,"status";
-+ watchdog = <&watchdog>,"status";
-+ random = <&random>,"status";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2709.dtsi
-@@ -0,0 +1,102 @@
-+#include "bcm2708_common.dtsi"
-+
-+/ {
-+ compatible = "brcm,bcm2709";
-+ model = "BCM2709";
-+
-+ chosen {
-+ /* No padding required - the boot loader can do that. */
-+ bootargs = "";
-+ };
-+
-+ soc {
-+ ranges = <0x7e000000 0x3f000000 0x01000000>,
-+ <0x40000000 0x40000000 0x00040000>;
-+
-+ local_intc: local_intc {
-+ compatible = "brcm,bcm2836-l1-intc";
-+ reg = <0x40000000 0x100>;
-+ interrupt-controller;
-+ #interrupt-cells = <1>;
-+ interrupt-parent = <&local_intc>;
-+ };
-+
-+ arm-pmu {
-+ compatible = "arm,cortex-a7-pmu";
-+ interrupt-parent = <&local_intc>;
-+ interrupts = <9>;
-+ };
-+
-+ gpiomem {
-+ compatible = "brcm,bcm2835-gpiomem";
-+ reg = <0x7e200000 0x1000>;
-+ status = "okay";
-+ };
-+
-+ timer {
-+ compatible = "arm,armv7-timer";
-+ clock-frequency = <19200000>;
-+ interrupt-parent = <&local_intc>;
-+ interrupts = <0>, // PHYS_SECURE_PPI
-+ <1>, // PHYS_NONSECURE_PPI
-+ <3>, // VIRT_PPI
-+ <2>; // HYP_PPI
-+ always-on;
-+ };
-+
-+ syscon@40000000 {
-+ compatible = "brcm,bcm2836-arm-local", "syscon";
-+ reg = <0x40000000 0x100>;
-+ };
-+ };
-+
-+ cpus: cpus {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ v7_cpu0: cpu@0 {
-+ device_type = "cpu";
-+ compatible = "arm,cortex-a7";
-+ reg = <0xf00>;
-+ clock-frequency = <800000000>;
-+ };
-+
-+ v7_cpu1: cpu@1 {
-+ device_type = "cpu";
-+ compatible = "arm,cortex-a7";
-+ reg = <0xf01>;
-+ clock-frequency = <800000000>;
-+ };
-+
-+ v7_cpu2: cpu@2 {
-+ device_type = "cpu";
-+ compatible = "arm,cortex-a7";
-+ reg = <0xf02>;
-+ clock-frequency = <800000000>;
-+ };
-+
-+ v7_cpu3: cpu@3 {
-+ device_type = "cpu";
-+ compatible = "arm,cortex-a7";
-+ reg = <0xf03>;
-+ clock-frequency = <800000000>;
-+ };
-+ };
-+
-+ __overrides__ {
-+ arm_freq = <&v7_cpu0>, "clock-frequency:0",
-+ <&v7_cpu1>, "clock-frequency:0",
-+ <&v7_cpu2>, "clock-frequency:0",
-+ <&v7_cpu3>, "clock-frequency:0";
-+ };
-+};
-+
-+&watchdog {
-+ status = "okay";
-+};
-+
-+&intc {
-+ compatible = "brcm,bcm2836-armctrl-ic";
-+ interrupt-parent = <&local_intc>;
-+ interrupts = <8>;
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2835-rpi-cm.dts
-@@ -0,0 +1,93 @@
-+/dts-v1/;
-+
-+#include "bcm2835-rpi-cm.dtsi"
-+
-+/ {
-+ model = "Raspberry Pi Compute Module";
-+};
-+
-+&uart0 {
-+ status = "okay";
-+};
-+
-+&gpio {
-+ spi0_pins: spi0_pins {
-+ brcm,pins = <7 8 9 10 11>;
-+ brcm,function = <4>; /* alt0 */
-+ };
-+
-+ i2c0_pins: i2c0 {
-+ brcm,pins = <0 1>;
-+ brcm,function = <4>;
-+ };
-+
-+ i2c1_pins: i2c1 {
-+ brcm,pins = <2 3>;
-+ brcm,function = <4>;
-+ };
-+
-+ i2s_pins: i2s {
-+ brcm,pins = <18 19 20 21>;
-+ brcm,function = <4>; /* alt0 */
-+ };
-+};
-+
-+&spi0 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&spi0_pins>;
-+
-+ spidev@0{
-+ compatible = "spidev";
-+ reg = <0>; /* CE0 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <500000>;
-+ };
-+
-+ spidev@1{
-+ compatible = "spidev";
-+ reg = <1>; /* CE1 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <500000>;
-+ };
-+};
-+
-+&i2c0 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c0_pins>;
-+ clock-frequency = <100000>;
-+};
-+
-+&i2c1 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c1_pins>;
-+ clock-frequency = <100000>;
-+};
-+
-+&i2c2 {
-+ clock-frequency = <100000>;
-+};
-+
-+&i2s {
-+ #sound-dai-cells = <0>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2s_pins>;
-+};
-+
-+/ {
-+ __overrides__ {
-+ uart0 = <&uart0>,"status";
-+ uart0_clkrate = <&clk_uart0>,"clock-frequency:0";
-+ uart1_clkrate = <&uart1>,"clock-frequency:0";
-+ i2s = <&i2s>,"status";
-+ spi = <&spi0>,"status";
-+ i2c0 = <&i2c0>,"status";
-+ i2c1 = <&i2c1>,"status";
-+ i2c2_iknowwhatimdoing = <&i2c2>,"status";
-+ i2c0_baudrate = <&i2c0>,"clock-frequency:0";
-+ i2c1_baudrate = <&i2c1>,"clock-frequency:0";
-+ i2c2_baudrate = <&i2c2>,"clock-frequency:0";
-+ core_freq = <&clk_core>,"clock-frequency:0";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2835-rpi-cm.dtsi
-@@ -0,0 +1,30 @@
-+#include "bcm2835.dtsi"
-+
-+&leds {
-+ act_led: act {
-+ label = "led0";
-+ linux,default-trigger = "mmc0";
-+ gpios = <&gpio 47 0>;
-+ };
-+};
-+
-+&mmc {
-+ status = "okay";
-+ bus-width = <4>;
-+};
-+
-+&fb {
-+ status = "okay";
-+};
-+
-+/ {
-+ __overrides__ {
-+ act_led_gpio = <&act_led>,"gpios:4";
-+ act_led_activelow = <&act_led>,"gpios:8";
-+ act_led_trigger = <&act_led>,"linux,default-trigger";
-+
-+ audio = <&audio>,"status";
-+ watchdog = <&watchdog>,"status";
-+ random = <&random>,"status";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -0,0 +1,69 @@
-+ifeq ($(CONFIG_OF),y)
-+
-+# Overlays for the Raspberry Pi platform
-+
-+ifeq ($(CONFIG_ARCH_BCM2708),y)
-+ RPI_DT_OVERLAYS=y
-+endif
-+ifeq ($(CONFIG_ARCH_BCM2709),y)
-+ RPI_DT_OVERLAYS=y
-+endif
-+ifeq ($(CONFIG_ARCH_BCM2835),y)
-+ RPI_DT_OVERLAYS=y
-+endif
-+
-+dtb-$(RPI_DT_OVERLAYS) += ads7846-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += bmp085_i2c-sensor-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += dht11-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += enc28j60-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += gpio-poweroff-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += hifiberry-amp-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += hifiberry-dac-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += hifiberry-dacplus-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += hifiberry-digi-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += hy28a-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += hy28b-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += i2c-rtc-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += i2s-mmap-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += iqaudio-dac-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += iqaudio-dacplus-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += lirc-rpi-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += mcp2515-can0-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += mcp2515-can1-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += mmc-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += mz61581-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += piscreen-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += pitft28-resistive-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += pps-gpio-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += pwm-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += pwm-2chan-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += raspidac3-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += rpi-dac-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += rpi-display-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += rpi-ft5406-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += rpi-proto-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += rpi-sense-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += sdhost-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += sdio-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += smi-dev-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += smi-nand-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += smi-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += spi-gpio35-39-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += tinylcd35-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += uart1-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += vga666-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += w1-gpio-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += w1-gpio-pullup-overlay.dtb
-+
-+targets += dtbs dtbs_install
-+targets += $(dtb-y)
-+
-+endif
-+
-+always := $(dtb-y)
-+clean-files := *.dtb
-+
-+# Enable fixups to support overlays on BCM2708 platforms
-+ifeq ($(RPI_DT_OVERLAYS),y)
-+ DTC_FLAGS ?= -@
-+endif
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -0,0 +1,648 @@
-+Introduction
-+============
-+
-+This directory contains Device Tree overlays. Device Tree makes it possible
-+to support many hardware configurations with a single kernel and without the
-+need to explicitly load or blacklist kernel modules. Note that this isn't a
-+"pure" Device Tree configuration (c.f. MACH_BCM2835) - some on-board devices
-+are still configured by the board support code, but the intention is to
-+eventually reach that goal.
-+
-+On Raspberry Pi, Device Tree usage is controlled from /boot/config.txt. By
-+default, the Raspberry Pi kernel boots with device tree enabled. You can
-+completely disable DT usage (for now) by adding:
-+
-+ device_tree=
-+
-+to your config.txt, which should cause your Pi to revert to the old way of
-+doing things after a reboot.
-+
-+In /boot you will find a .dtb for each base platform. This describes the
-+hardware that is part of the Raspberry Pi board. The loader (start.elf and its
-+siblings) selects the .dtb file appropriate for the platform by name, and reads
-+it into memory. At this point, all of the optional interfaces (i2c, i2s, spi)
-+are disabled, but they can be enabled using Device Tree parameters:
-+
-+ dtparam=i2c=on,i2s=on,spi=on
-+
-+However, this shouldn't be necessary in many use cases because loading an
-+overlay that requires one of those interfaces will cause it to be enabled
-+automatically, and it is advisable to only enable interfaces if they are
-+needed.
-+
-+Configuring additional, optional hardware is done using Device Tree overlays
-+(see below).
-+
-+raspi-config
-+============
-+
-+The Advanced Options section of the raspi-config utility can enable and disable
-+Device Tree use, as well as toggling the I2C and SPI interfaces. Note that it
-+is possible to both enable an interface and blacklist the driver, if for some
-+reason you should want to defer the loading.
-+
-+Modules
-+=======
-+
-+As well as describing the hardware, Device Tree also gives enough information
-+to allow suitable driver modules to be located and loaded, with the corollary
-+that unneeded modules are not loaded. As a result it should be possible to
-+remove lines from /etc/modules, and /etc/modprobe.d/raspi-blacklist.conf can
-+have its contents deleted (or commented out).
-+
-+Using Overlays
-+==============
-+
-+Overlays are loaded using the "dtoverlay" directive. As an example, consider the
-+popular lirc-rpi module, the Linux Infrared Remote Control driver. In the
-+pre-DT world this would be loaded from /etc/modules, with an explicit
-+"modprobe lirc-rpi" command, or programmatically by lircd. With DT enabled,
-+this becomes a line in config.txt:
-+
-+ dtoverlay=lirc-rpi
-+
-+This causes the file /boot/overlays/lirc-rpi-overlay.dtb to be loaded. By
-+default it will use GPIOs 17 (out) and 18 (in), but this can be modified using
-+DT parameters:
-+
-+ dtoverlay=lirc-rpi,gpio_out_pin=17,gpio_in_pin=13
-+
-+Parameters always have default values, although in some cases (e.g. "w1-gpio")
-+it is necessary to provided multiple overlays in order to get the desired
-+behaviour. See the list of overlays below for a description of the parameters and their defaults.
-+
-+The Overlay and Parameter Reference
-+===================================
-+
-+N.B. When editing this file, please preserve the indentation levels to make it simple to parse
-+programmatically. NO HARD TABS.
-+
-+
-+Name: <The base DTB>
-+Info: Configures the base Raspberry Pi hardware
-+Load: <loaded automatically>
-+Params:
-+ audio Set to "on" to enable the onboard ALSA audio
-+ interface (default "off")
-+
-+ i2c_arm Set to "on" to enable the ARM's i2c interface
-+ (default "off")
-+
-+ i2c_vc Set to "on" to enable the i2c interface
-+ usually reserved for the VideoCore processor
-+ (default "off")
-+
-+ i2c An alias for i2c_arm
-+
-+ i2c_arm_baudrate Set the baudrate of the ARM's i2c interface
-+ (default "100000")
-+
-+ i2c_vc_baudrate Set the baudrate of the VideoCore i2c interface
-+ (default "100000")
-+
-+ i2c_baudrate An alias for i2c_arm_baudrate
-+
-+ i2s Set to "on" to enable the i2s interface
-+ (default "off")
-+
-+ spi Set to "on" to enable the spi interfaces
-+ (default "off")
-+
-+ random Set to "on" to enable the hardware random
-+ number generator (default "off")
-+
-+ uart0 Set to "off" to disable uart0 (default "on")
-+
-+ watchdog Set to "on" to enable the hardware watchdog
-+ (default "off")
-+
-+ act_led_trigger Choose which activity the LED tracks.
-+ Use "heartbeat" for a nice load indicator.
-+ (default "mmc")
-+
-+ act_led_activelow Set to "on" to invert the sense of the LED
-+ (default "off")
-+
-+ act_led_gpio Set which GPIO to use for the activity LED
-+ (in case you want to connect it to an external
-+ device)
-+ (default "16" on a non-Plus board, "47" on a
-+ Plus or Pi 2)
-+
-+ pwr_led_trigger
-+ pwr_led_activelow
-+ pwr_led_gpio
-+ As for act_led_*, but using the PWR LED.
-+ Not available on Model A/B boards.
-+
-+ N.B. It is recommended to only enable those interfaces that are needed.
-+ Leaving all interfaces enabled can lead to unwanted behaviour (i2c_vc
-+ interfering with Pi Camera, I2S and SPI hogging GPIO pins, etc.)
-+ Note also that i2c, i2c_arm and i2c_vc are aliases for the physical
-+ interfaces i2c0 and i2c1. Use of the numeric variants is still possible
-+ but deprecated because the ARM/VC assignments differ between board
-+ revisions. The same board-specific mapping applies to i2c_baudrate,
-+ and the other i2c baudrate parameters.
-+
-+
-+Name: ads7846
-+Info: ADS7846 Touch controller
-+Load: dtoverlay=ads7846,<param>=<val>
-+Params: cs SPI bus Chip Select (default 1)
-+ speed SPI bus speed (default 2Mhz, max 3.25MHz)
-+ penirq GPIO used for PENIRQ. REQUIRED
-+ penirq_pull Set GPIO pull (default 0=none, 2=pullup)
-+ swapxy Swap x and y axis
-+ xmin Minimum value on the X axis (default 0)
-+ ymin Minimum value on the Y axis (default 0)
-+ xmax Maximum value on the X axis (default 4095)
-+ ymax Maximum value on the Y axis (default 4095)
-+ pmin Minimum reported pressure value (default 0)
-+ pmax Maximum reported pressure value (default 65535)
-+ xohms Touchpanel sensitivity (X-plate resistance)
-+ (default 400)
-+
-+ penirq is required and usually xohms (60-100) has to be set as well.
-+ Apart from that, pmax (255) and swapxy are also common.
-+ The rest of the calibration can be done with xinput-calibrator.
-+ See: github.com/notro/fbtft/wiki/FBTFT-on-Raspian
-+ Device Tree binding document:
-+ www.kernel.org/doc/Documentation/devicetree/bindings/input/ads7846.txt
-+
-+
-+Name: bmp085_i2c-sensor
-+Info: Configures the BMP085/BMP180 digital barometric pressure and temperature
-+ sensors from Bosch Sensortec
-+Load: dtoverlay=bmp085_i2c-sensor
-+Params: <None>
-+
-+
-+Name: dht11
-+Info: Overlay for the DHT11/DHT21/DHT22 humidity/temperature sensors
-+ Also sometimes found with the part number(s) AM230x.
-+Load: dtoverlay=dht11,<param>=<val>
-+Params: gpiopin GPIO connected to the sensor's DATA output.
-+ (default 4)
-+
-+
-+[ The ds1307-rtc overlay has been deleted. See i2c-rtc. ]
-+
-+
-+Name: enc28j60
-+Info: Overlay for the Microchip ENC28J60 Ethernet Controller (SPI)
-+Load: dtoverlay=enc28j60,<param>=<val>
-+Params: int_pin GPIO used for INT (default 25)
-+
-+ speed SPI bus speed (default 12000000)
-+
-+
-+Name: gpio-poweroff
-+Info: Drives a GPIO high or low on reboot
-+Load: dtoverlay=gpio-poweroff,<param>=<val>
-+Params: gpiopin GPIO for signalling (default 26)
-+
-+ active_low Set if the power control device requires a
-+ high->low transition to trigger a power-down.
-+ Note that this will require the support of a
-+ custom dt-blob.bin to prevent a power-down
-+ during the boot process, and that a reboot
-+ will also cause the pin to go low.
-+
-+
-+Name: hifiberry-amp
-+Info: Configures the HifiBerry Amp and Amp+ audio cards
-+Load: dtoverlay=hifiberry-amp
-+Params: <None>
-+
-+
-+Name: hifiberry-dac
-+Info: Configures the HifiBerry DAC audio card
-+Load: dtoverlay=hifiberry-dac
-+Params: <None>
-+
-+
-+Name: hifiberry-dacplus
-+Info: Configures the HifiBerry DAC+ audio card
-+Load: dtoverlay=hifiberry-dacplus
-+Params: <None>
-+
-+
-+Name: hifiberry-digi
-+Info: Configures the HifiBerry Digi audio card
-+Load: dtoverlay=hifiberry-digi
-+Params: <None>
-+
-+
-+Name: hy28a
-+Info: HY28A - 2.8" TFT LCD Display Module by HAOYU Electronics
-+ Default values match Texy's display shield
-+Load: dtoverlay=hy28a,<param>=<val>
-+Params: speed Display SPI bus speed
-+
-+ rotate Display rotation {0,90,180,270}
-+
-+ fps Delay between frame updates
-+
-+ debug Debug output level {0-7}
-+
-+ xohms Touchpanel sensitivity (X-plate resistance)
-+
-+ resetgpio GPIO used to reset controller
-+
-+ ledgpio GPIO used to control backlight
-+
-+
-+Name: hy28b
-+Info: HY28B - 2.8" TFT LCD Display Module by HAOYU Electronics
-+ Default values match Texy's display shield
-+Load: dtoverlay=hy28b,<param>=<val>
-+Params: speed Display SPI bus speed
-+
-+ rotate Display rotation {0,90,180,270}
-+
-+ fps Delay between frame updates
-+
-+ debug Debug output level {0-7}
-+
-+ xohms Touchpanel sensitivity (X-plate resistance)
-+
-+ resetgpio GPIO used to reset controller
-+
-+ ledgpio GPIO used to control backlight
-+
-+
-+Name: i2c-rtc
-+Info: Adds support for a number of I2C Real Time Clock devices
-+Load: dtoverlay=i2c-rtc,<param>
-+Params: ds1307 Select the DS1307 device
-+
-+ ds3231 Select the DS3231 device
-+
-+ mcp7941x Select the MCP7941x device
-+
-+ pcf2127 Select the PCF2127 device
-+
-+ pcf8523 Select the PCF8523 device
-+
-+ pcf8563 Select the PCF8563 device
-+
-+
-+Name: i2s-mmap
-+Info: Enables mmap support in the bcm2708-i2s driver
-+Load: dtoverlay=i2s-mmap
-+Params: <None>
-+
-+
-+Name: iqaudio-dac
-+Info: Configures the IQaudio DAC audio card
-+Load: dtoverlay=iqaudio-dac
-+Params: <None>
-+
-+
-+Name: iqaudio-dacplus
-+Info: Configures the IQaudio DAC+ audio card
-+Load: dtoverlay=iqaudio-dacplus
-+Params: <None>
-+
-+
-+Name: lirc-rpi
-+Info: Configures lirc-rpi (Linux Infrared Remote Control for Raspberry Pi)
-+ Consult the module documentation for more details.
-+Load: dtoverlay=lirc-rpi,<param>=<val>,...
-+Params: gpio_out_pin GPIO for output (default "17")
-+
-+ gpio_in_pin GPIO for input (default "18")
-+
-+ gpio_in_pull Pull up/down/off on the input pin
-+ (default "down")
-+
-+ sense Override the IR receive auto-detection logic:
-+ "0" = force active-high
-+ "1" = force active-low
-+ "-1" = use auto-detection
-+ (default "-1")
-+
-+ softcarrier Turn the software carrier "on" or "off"
-+ (default "on")
-+
-+ invert "on" = invert the output pin (default "off")
-+
-+ debug "on" = enable additional debug messages
-+ (default "off")
-+
-+
-+Name: mcp2515-can0
-+Info: Configures the MCP2515 CAN controller on spi0.0
-+Load: dtoverlay=mcp2515-can0,<param>=<val>
-+Params: oscillator Clock frequency for the CAN controller (Hz)
-+
-+ spimaxfrequency Maximum SPI frequence (Hz)
-+
-+ interrupt GPIO for interrupt signal
-+
-+
-+Name: mcp2515-can1
-+Info: Configures the MCP2515 CAN controller on spi0.1
-+Load: dtoverlay=mcp2515-can1,<param>=<val>
-+Params: oscillator Clock frequency for the CAN controller (Hz)
-+
-+ spimaxfrequency Maximum SPI frequence (Hz)
-+
-+ interrupt GPIO for interrupt signal
-+
-+
-+Name: mmc
-+Info: Selects the bcm2835-mmc SD/MMC driver, optionally with overclock
-+Load: dtoverlay=mmc,<param>=<val>
-+Params: overclock_50 Clock (in MHz) to use when the MMC framework
-+ requests 50MHz
-+ force_pio Disable DMA support
-+
-+
-+Name: mz61581
-+Info: MZ61581 display by Tontec
-+Load: dtoverlay=mz61581,<param>=<val>
-+Params: speed Display SPI bus speed
-+
-+ rotate Display rotation {0,90,180,270}
-+
-+ fps Delay between frame updates
-+
-+ txbuflen Transmit buffer length (default 32768)
-+
-+ debug Debug output level {0-7}
-+
-+ xohms Touchpanel sensitivity (X-plate resistance)
-+
-+
-+[ The pcf2127-rtc overlay has been deleted. See i2c-rtc. ]
-+
-+
-+[ The pcf8523-rtc overlay has been deleted. See i2c-rtc. ]
-+
-+
-+[ The pcf8563-rtc overlay has been deleted. See i2c-rtc. ]
-+
-+
-+Name: piscreen
-+Info: PiScreen display by OzzMaker.com
-+Load: dtoverlay=piscreen,<param>=<val>
-+Params: speed Display SPI bus speed
-+
-+ rotate Display rotation {0,90,180,270}
-+
-+ fps Delay between frame updates
-+
-+ debug Debug output level {0-7}
-+
-+ xohms Touchpanel sensitivity (X-plate resistance)
-+
-+
-+Name: pitft28-resistive
-+Info: Adafruit PiTFT 2.8" resistive touch screen
-+Load: dtoverlay=pitft28-resistive,<param>=<val>
-+Params: speed Display SPI bus speed
-+
-+ rotate Display rotation {0,90,180,270}
-+
-+ fps Delay between frame updates
-+
-+ debug Debug output level {0-7}
-+
-+
-+Name: pps-gpio
-+Info: Configures the pps-gpio (pulse-per-second time signal via GPIO).
-+Load: dtoverlay=pps-gpio,<param>=<val>
-+Params: gpiopin Input GPIO (default "18")
-+
-+
-+Name: pwm
-+Info: Configures a single PWM channel
-+ Legal pin,function combinations for each channel:
-+ PWM0: 12,4(Alt0) 18,2(Alt5) 40,4(Alt0) 52,5(Alt1)
-+ PWM1: 13,4(Alt0) 19,2(Alt5) 41,4(Alt0) 45,4(Alt0) 53,5(Alt1)
-+ N.B.:
-+ 1) Pin 18 is the only one available on all platforms, and
-+ it is the one used by the I2S audio interface.
-+ Pins 12 and 13 might be better choices on an A+, B+ or Pi2.
-+ 2) The onboard analogue audio output uses both PWM channels.
-+ 3) So be careful mixing audio and PWM.
-+ 4) Currently the clock must have been enabled and configured
-+ by other means.
-+Load: dtoverlay=pwm,<param>=<val>
-+Params: pin Output pin (default 18) - see table
-+ func Pin function (default 2 = Alt5) - see above
-+ clock PWM clock frequency (informational)
-+
-+
-+Name: pwm-2chan
-+Info: Configures both PWM channels
-+ Legal pin,function combinations for each channel:
-+ PWM0: 12,4(Alt0) 18,2(Alt5) 40,4(Alt0) 52,5(Alt1)
-+ PWM1: 13,4(Alt0) 19,2(Alt5) 41,4(Alt0) 45,4(Alt0) 53,5(Alt1)
-+ N.B.:
-+ 1) Pin 18 is the only one available on all platforms, and
-+ it is the one used by the I2S audio interface.
-+ Pins 12 and 13 might be better choices on an A+, B+ or Pi2.
-+ 2) The onboard analogue audio output uses both PWM channels.
-+ 3) So be careful mixing audio and PWM.
-+ 4) Currently the clock must have been enabled and configured
-+ by other means.
-+Load: dtoverlay=pwm-2chan,<param>=<val>
-+Params: pin Output pin (default 18) - see table
-+ pin2 Output pin for other channel (default 19)
-+ func Pin function (default 2 = Alt5) - see above
-+ func2 Function for pin2 (default 2 = Alt5)
-+ clock PWM clock frequency (informational)
-+
-+
-+Name: raspidac3
-+Info: Configures the RaspiDAV Rev.3x audio card
-+Load: dtoverlay=raspidac3
-+Params: <None>
-+
-+
-+Name: rpi-dac
-+Info: Configures the RPi DAC audio card
-+Load: dtoverlay=rpi-dac
-+Params: <None>
-+
-+
-+Name: rpi-display
-+Info: RPi-Display - 2.8" Touch Display by Watterott
-+Load: dtoverlay=rpi-display,<param>=<val>
-+Params: speed Display SPI bus speed
-+
-+ rotate Display rotation {0,90,180,270}
-+
-+ fps Delay between frame updates
-+
-+ debug Debug output level {0-7}
-+
-+ xohms Touchpanel sensitivity (X-plate resistance)
-+
-+
-+Name: rpi-ft5406
-+Info: Official Raspberry Pi display touchscreen
-+Load: dtoverlay=rpi-ft5406
-+Params: <None>
-+
-+
-+Name: rpi-proto
-+Info: Configures the RPi Proto audio card
-+Load: dtoverlay=rpi-proto
-+Params: <None>
-+
-+
-+Name: rpi-sense
-+Info: Raspberry Pi Sense HAT
-+Load: dtoverlay=rpi-sense
-+Params: <None>
-+
-+
-+Name: sdhost
-+Info: Selects the bcm2835-sdhost SD/MMC driver, optionally with overclock
-+Load: dtoverlay=sdhost,<param>=<val>
-+Params: overclock_50 Clock (in MHz) to use when the MMC framework
-+ requests 50MHz
-+
-+ force_pio Disable DMA support (default off)
-+
-+ pio_limit Number of blocks above which to use DMA
-+ (default 1)
-+
-+ debug Enable debug output (default off)
-+
-+
-+Name: sdio
-+Info: Selects the bcm2835-sdhost SD/MMC driver, optionally with overclock,
-+ and enables SDIO via GPIOs 22-27.
-+Load: dtoverlay=sdio,<param>=<val>
-+Params: overclock_50 Clock (in MHz) to use when the MMC framework
-+ requests 50MHz
-+
-+ force_pio Disable DMA support (default off)
-+
-+ pio_limit Number of blocks above which to use DMA
-+ (default 1)
-+
-+ debug Enable debug output (default off)
-+
-+ poll_once Disable SDIO-device polling every second
-+ (default on: polling once at boot-time)
-+
-+
-+Name: smi
-+Info: Enables the Secondary Memory Interface peripheral. Uses GPIOs 2-25!
-+Load: dtoverlay=smi
-+Params: <None>
-+
-+
-+Name: smi-dev
-+Info: Enables the userspace interface for the SMI driver
-+Load: dtoverlay=smi-dev
-+Params: <None>
-+
-+
-+Name: smi-nand
-+Info: Enables access to NAND flash via the SMI interface
-+Load: dtoverlay=smi-nand
-+Params: <None>
-+
-+
-+Name: spi-gpio35-39
-+Info: move SPI function block to GPIO 35 to 39
-+Load: dtoverlay=spi-gpio35-39
-+Params: <None>
-+
-+
-+Name: tinylcd35
-+Info: 3.5" Color TFT Display by www.tinylcd.com
-+ Options: Touch, RTC, keypad
-+Load: dtoverlay=tinylcd35,<param>=<val>
-+Params: speed Display SPI bus speed
-+
-+ rotate Display rotation {0,90,180,270}
-+
-+ fps Delay between frame updates
-+
-+ debug Debug output level {0-7}
-+
-+ touch Enable touch panel
-+
-+ touchgpio Touch controller IRQ GPIO
-+
-+ xohms Touchpanel: Resistance of X-plate in ohms
-+
-+ rtc-pcf PCF8563 Real Time Clock
-+
-+ rtc-ds DS1307 Real Time Clock
-+
-+ keypad Enable keypad
-+
-+ Examples:
-+ Display with touchpanel, PCF8563 RTC and keypad:
-+ dtoverlay=tinylcd35,touch,rtc-pcf,keypad
-+ Old touch display:
-+ dtoverlay=tinylcd35,touch,touchgpio=3
-+
-+
-+Name: uart1
-+Info: Enable uart1 in place of uart0
-+Load: dtoverlay=uart1,<param>=<val>
-+Params: txd1_pin GPIO pin for TXD1 (14, 32 or 40 - default 14)
-+
-+ rxd1_pin GPIO pin for RXD1 (15, 33 or 41 - default 15)
-+
-+
-+Name: vga666
-+Info: Overlay for the Fen Logic VGA666 board
-+ This uses GPIOs 2-21 (so no I2C), and activates the output 2-3 seconds
-+ after the kernel has started.
-+Load: dtoverlay=vga666
-+Params: <None>
-+
-+
-+Name: w1-gpio
-+Info: Configures the w1-gpio Onewire interface module.
-+ Use this overlay if you *don't* need a GPIO to drive an external pullup.
-+Load: dtoverlay=w1-gpio,<param>=<val>
-+Params: gpiopin GPIO for I/O (default "4")
-+
-+ pullup Non-zero, "on", or "y" to enable the parasitic
-+ power (2-wire, power-on-data) feature
-+
-+
-+Name: w1-gpio-pullup
-+Info: Configures the w1-gpio Onewire interface module.
-+ Use this overlay if you *do* need a GPIO to drive an external pullup.
-+Load: dtoverlay=w1-gpio-pullup,<param>=<val>
-+Params: gpiopin GPIO for I/O (default "4")
-+
-+ pullup Non-zero, "on", or "y" to enable the parasitic
-+ power (2-wire, power-on-data) feature
-+
-+ extpullup GPIO for external pullup (default "5")
-+
-+
-+Troubleshooting
-+===============
-+
-+If you are experiencing problems that you think are DT-related, enable DT
-+diagnostic output by adding this to /boot/config.txt:
-+
-+ dtdebug=on
-+
-+and rebooting. Then run:
-+
-+ sudo vcdbg log msg
-+
-+and look for relevant messages.
-+
-+Further reading
-+===============
-+
-+This is only meant to be a quick introduction to the subject of Device Tree on
-+Raspberry Pi. There is a more complete explanation here:
-+
-+http://www.raspberrypi.org/documentation/configuration/device-tree.md
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/ads7846-overlay.dts
-@@ -0,0 +1,83 @@
-+/*
-+ * Generic Device Tree overlay for the ADS7846 touch controller
-+ *
-+ */
-+
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+
-+ fragment@0 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ status = "okay";
-+
-+ spidev@0{
-+ status = "disabled";
-+ };
-+
-+ spidev@1{
-+ status = "disabled";
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ ads7846_pins: ads7846_pins {
-+ brcm,pins = <255>; /* illegal default value */
-+ brcm,function = <0>; /* in */
-+ brcm,pull = <0>; /* none */
-+ };
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ ads7846: ads7846@1 {
-+ compatible = "ti,ads7846";
-+ reg = <1>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&ads7846_pins>;
-+
-+ spi-max-frequency = <2000000>;
-+ interrupts = <255 2>; /* high-to-low edge triggered */
-+ interrupt-parent = <&gpio>;
-+ pendown-gpio = <&gpio 255 0>;
-+
-+ /* driver defaults */
-+ ti,x-min = /bits/ 16 <0>;
-+ ti,y-min = /bits/ 16 <0>;
-+ ti,x-max = /bits/ 16 <0x0FFF>;
-+ ti,y-max = /bits/ 16 <0x0FFF>;
-+ ti,pressure-min = /bits/ 16 <0>;
-+ ti,pressure-max = /bits/ 16 <0xFFFF>;
-+ ti,x-plate-ohms = /bits/ 16 <400>;
-+ };
-+ };
-+ };
-+ __overrides__ {
-+ cs = <&ads7846>,"reg:0";
-+ speed = <&ads7846>,"spi-max-frequency:0";
-+ penirq = <&ads7846_pins>,"brcm,pins:0", /* REQUIRED */
-+ <&ads7846>,"interrupts:0",
-+ <&ads7846>,"pendown-gpio:4";
-+ penirq_pull = <&ads7846_pins>,"brcm,pull:0";
-+ swapxy = <&ads7846>,"ti,swap-xy?";
-+ xmin = <&ads7846>,"ti,x-min;0";
-+ ymin = <&ads7846>,"ti,y-min;0";
-+ xmax = <&ads7846>,"ti,x-max;0";
-+ ymax = <&ads7846>,"ti,y-max;0";
-+ pmin = <&ads7846>,"ti,pressure-min;0";
-+ pmax = <&ads7846>,"ti,pressure-max;0";
-+ xohms = <&ads7846>,"ti,x-plate-ohms;0";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/bmp085_i2c-sensor-overlay.dts
-@@ -0,0 +1,23 @@
-+// Definitions for BMP085/BMP180 digital barometric pressure and temperature sensors from Bosch Sensortec
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target = <&i2c_arm>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ bmp085@77 {
-+ compatible = "bosch,bmp085";
-+ reg = <0x77>;
-+ default-oversampling = <3>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/dht11-overlay.dts
-@@ -0,0 +1,39 @@
-+/*
-+ * Overlay for the DHT11/21/22 humidity/temperature sensor modules.
-+ */
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target-path = "/";
-+ __overlay__ {
-+
-+ dht11: dht11@0 {
-+ compatible = "dht11";
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&dht11_pins>;
-+ gpios = <&gpio 4 0>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ dht11_pins: dht11_pins {
-+ brcm,pins = <4>;
-+ brcm,function = <0>; // in
-+ brcm,pull = <0>; // off
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ gpiopin = <&dht11_pins>,"brcm,pins:0",
-+ <&dht11>,"gpios:4";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/enc28j60-overlay.dts
-@@ -0,0 +1,50 @@
-+// Overlay for the Microchip ENC28J60 Ethernet Controller
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ status = "okay";
-+
-+ spidev@0{
-+ status = "disabled";
-+ };
-+
-+ eth1: enc28j60@0{
-+ compatible = "microchip,enc28j60";
-+ reg = <0>; /* CE0 */
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&eth1_pins>;
-+ interrupt-parent = <&gpio>;
-+ interrupts = <25 0x2>; /* falling edge */
-+ spi-max-frequency = <12000000>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ eth1_pins: eth1_pins {
-+ brcm,pins = <25>;
-+ brcm,function = <0>; /* in */
-+ brcm,pull = <0>; /* none */
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ int_pin = <&eth1>, "interrupts:0",
-+ <&eth1_pins>, "brcm,pins:0";
-+ speed = <&eth1>, "spi-max-frequency:0";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts
-@@ -0,0 +1,34 @@
-+// Definitions for gpio-poweroff module
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target-path = "/";
-+ __overlay__ {
-+ power_ctrl: power_ctrl {
-+ compatible = "gpio-poweroff";
-+ gpios = <&gpio 26 0>;
-+ force;
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ power_ctrl_pins: power_ctrl_pins {
-+ brcm,pins = <26>;
-+ brcm,function = <1>; // out
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ gpiopin = <&power_ctrl>,"gpios:4",
-+ <&power_ctrl_pins>,"brcm,pins:0";
-+ active_low = <&power_ctrl>,"gpios:8";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/hifiberry-amp-overlay.dts
-@@ -0,0 +1,39 @@
-+// Definitions for HiFiBerry Amp/Amp+
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target = <&sound>;
-+ __overlay__ {
-+ compatible = "hifiberry,hifiberry-amp";
-+ i2s-controller = <&i2s>;
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&i2s>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ tas5713@1b {
-+ #sound-dai-cells = <0>;
-+ compatible = "ti,tas5713";
-+ reg = <0x1b>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/hifiberry-dac-overlay.dts
-@@ -0,0 +1,34 @@
-+// Definitions for HiFiBerry DAC
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target = <&sound>;
-+ __overlay__ {
-+ compatible = "hifiberry,hifiberry-dac";
-+ i2s-controller = <&i2s>;
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&i2s>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@2 {
-+ target-path = "/";
-+ __overlay__ {
-+ pcm5102a-codec {
-+ #sound-dai-cells = <0>;
-+ compatible = "ti,pcm5102a";
-+ status = "okay";
-+ };
-+ };
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
-@@ -0,0 +1,39 @@
-+// Definitions for HiFiBerry DAC+
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target = <&sound>;
-+ __overlay__ {
-+ compatible = "hifiberry,hifiberry-dacplus";
-+ i2s-controller = <&i2s>;
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&i2s>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ pcm5122@4d {
-+ #sound-dai-cells = <0>;
-+ compatible = "ti,pcm5122";
-+ reg = <0x4d>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/hifiberry-digi-overlay.dts
-@@ -0,0 +1,39 @@
-+// Definitions for HiFiBerry Digi
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target = <&sound>;
-+ __overlay__ {
-+ compatible = "hifiberry,hifiberry-digi";
-+ i2s-controller = <&i2s>;
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&i2s>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ wm8804@3b {
-+ #sound-dai-cells = <0>;
-+ compatible = "wlf,wm8804";
-+ reg = <0x3b>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/hy28a-overlay.dts
-@@ -0,0 +1,87 @@
-+/*
-+ * Device Tree overlay for HY28A display
-+ *
-+ */
-+
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+
-+ fragment@0 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ status = "okay";
-+
-+ spidev@0{
-+ status = "disabled";
-+ };
-+
-+ spidev@1{
-+ status = "disabled";
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ hy28a_pins: hy28a_pins {
-+ brcm,pins = <17 25 18>;
-+ brcm,function = <0 1 1>; /* in out out */
-+ };
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ hy28a: hy28a@0{
-+ compatible = "ilitek,ili9320";
-+ reg = <0>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&hy28a_pins>;
-+
-+ spi-max-frequency = <32000000>;
-+ spi-cpol;
-+ spi-cpha;
-+ rotate = <270>;
-+ bgr;
-+ fps = <50>;
-+ buswidth = <8>;
-+ startbyte = <0x70>;
-+ reset-gpios = <&gpio 25 0>;
-+ led-gpios = <&gpio 18 1>;
-+ debug = <0>;
-+ };
-+
-+ hy28a_ts: hy28a-ts@1 {
-+ compatible = "ti,ads7846";
-+ reg = <1>;
-+
-+ spi-max-frequency = <2000000>;
-+ interrupts = <17 2>; /* high-to-low edge triggered */
-+ interrupt-parent = <&gpio>;
-+ pendown-gpio = <&gpio 17 0>;
-+ ti,x-plate-ohms = /bits/ 16 <100>;
-+ ti,pressure-max = /bits/ 16 <255>;
-+ };
-+ };
-+ };
-+ __overrides__ {
-+ speed = <&hy28a>,"spi-max-frequency:0";
-+ rotate = <&hy28a>,"rotate:0";
-+ fps = <&hy28a>,"fps:0";
-+ debug = <&hy28a>,"debug:0";
-+ xohms = <&hy28a_ts>,"ti,x-plate-ohms;0";
-+ resetgpio = <&hy28a>,"reset-gpios:4",
-+ <&hy28a_pins>, "brcm,pins:1";
-+ ledgpio = <&hy28a>,"led-gpios:4",
-+ <&hy28a_pins>, "brcm,pins:2";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/hy28b-overlay.dts
-@@ -0,0 +1,142 @@
-+/*
-+ * Device Tree overlay for HY28b display shield by Texy
-+ *
-+ */
-+
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+
-+ fragment@0 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ status = "okay";
-+
-+ spidev@0{
-+ status = "disabled";
-+ };
-+
-+ spidev@1{
-+ status = "disabled";
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ hy28b_pins: hy28b_pins {
-+ brcm,pins = <17 25 18>;
-+ brcm,function = <0 1 1>; /* in out out */
-+ };
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ hy28b: hy28b@0{
-+ compatible = "ilitek,ili9325";
-+ reg = <0>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&hy28b_pins>;
-+
-+ spi-max-frequency = <48000000>;
-+ spi-cpol;
-+ spi-cpha;
-+ rotate = <270>;
-+ bgr;
-+ fps = <50>;
-+ buswidth = <8>;
-+ startbyte = <0x70>;
-+ reset-gpios = <&gpio 25 0>;
-+ led-gpios = <&gpio 18 1>;
-+
-+ gamma = "04 1F 4 7 7 0 7 7 6 0\n0F 00 1 7 4 0 0 0 6 7";
-+
-+ init = <0x10000e7 0x0010
-+ 0x1000000 0x0001
-+ 0x1000001 0x0100
-+ 0x1000002 0x0700
-+ 0x1000003 0x1030
-+ 0x1000004 0x0000
-+ 0x1000008 0x0207
-+ 0x1000009 0x0000
-+ 0x100000a 0x0000
-+ 0x100000c 0x0001
-+ 0x100000d 0x0000
-+ 0x100000f 0x0000
-+ 0x1000010 0x0000
-+ 0x1000011 0x0007
-+ 0x1000012 0x0000
-+ 0x1000013 0x0000
-+ 0x2000032
-+ 0x1000010 0x1590
-+ 0x1000011 0x0227
-+ 0x2000032
-+ 0x1000012 0x009c
-+ 0x2000032
-+ 0x1000013 0x1900
-+ 0x1000029 0x0023
-+ 0x100002b 0x000e
-+ 0x2000032
-+ 0x1000020 0x0000
-+ 0x1000021 0x0000
-+ 0x2000032
-+ 0x1000050 0x0000
-+ 0x1000051 0x00ef
-+ 0x1000052 0x0000
-+ 0x1000053 0x013f
-+ 0x1000060 0xa700
-+ 0x1000061 0x0001
-+ 0x100006a 0x0000
-+ 0x1000080 0x0000
-+ 0x1000081 0x0000
-+ 0x1000082 0x0000
-+ 0x1000083 0x0000
-+ 0x1000084 0x0000
-+ 0x1000085 0x0000
-+ 0x1000090 0x0010
-+ 0x1000092 0x0000
-+ 0x1000093 0x0003
-+ 0x1000095 0x0110
-+ 0x1000097 0x0000
-+ 0x1000098 0x0000
-+ 0x1000007 0x0133
-+ 0x1000020 0x0000
-+ 0x1000021 0x0000
-+ 0x2000064>;
-+ debug = <0>;
-+ };
-+
-+ hy28b_ts: hy28b-ts@1 {
-+ compatible = "ti,ads7846";
-+ reg = <1>;
-+
-+ spi-max-frequency = <2000000>;
-+ interrupts = <17 2>; /* high-to-low edge triggered */
-+ interrupt-parent = <&gpio>;
-+ pendown-gpio = <&gpio 17 0>;
-+ ti,x-plate-ohms = /bits/ 16 <100>;
-+ ti,pressure-max = /bits/ 16 <255>;
-+ };
-+ };
-+ };
-+ __overrides__ {
-+ speed = <&hy28b>,"spi-max-frequency:0";
-+ rotate = <&hy28b>,"rotate:0";
-+ fps = <&hy28b>,"fps:0";
-+ debug = <&hy28b>,"debug:0";
-+ xohms = <&hy28b_ts>,"ti,x-plate-ohms;0";
-+ resetgpio = <&hy28b>,"reset-gpios:4",
-+ <&hy28b_pins>, "brcm,pins:1";
-+ ledgpio = <&hy28b>,"led-gpios:4",
-+ <&hy28b_pins>, "brcm,pins:2";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
-@@ -0,0 +1,55 @@
-+// Definitions for several I2C based Real Time Clocks
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target = <&i2c_arm>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ ds1307: ds1307@68 {
-+ compatible = "maxim,ds1307";
-+ reg = <0x68>;
-+ status = "disable";
-+ };
-+ mcp7941x: mcp7941x@6f {
-+ compatible = "microchip,mcp7941x";
-+ reg = <0x6f>;
-+ status = "disable";
-+ };
-+ ds3231: ds3231@68 {
-+ compatible = "maxim,ds3231";
-+ reg = <0x68>;
-+ status = "disable";
-+ };
-+ pcf2127: pcf2127@51 {
-+ compatible = "nxp,pcf2127";
-+ reg = <0x51>;
-+ status = "disable";
-+ };
-+ pcf8523: pcf8523@68 {
-+ compatible = "nxp,pcf8523";
-+ reg = <0x68>;
-+ status = "disable";
-+ };
-+ pcf8563: pcf8563@51 {
-+ compatible = "nxp,pcf8563";
-+ reg = <0x51>;
-+ status = "disable";
-+ };
-+ };
-+ };
-+ __overrides__ {
-+ ds1307 = <&ds1307>,"status";
-+ ds3231 = <&ds3231>,"status";
-+ mcp7941x = <&mcp7941x>,"status";
-+ pcf2127 = <&pcf2127>,"status";
-+ pcf8523 = <&pcf8523>,"status";
-+ pcf8563 = <&pcf8563>,"status";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/i2s-mmap-overlay.dts
-@@ -0,0 +1,13 @@
-+/dts-v1/;
-+/plugin/;
-+
-+/{
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target = <&i2s>;
-+ __overlay__ {
-+ brcm,enable-mmap;
-+ };
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts
-@@ -0,0 +1,39 @@
-+// Definitions for IQaudIO DAC
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target = <&sound>;
-+ __overlay__ {
-+ compatible = "iqaudio,iqaudio-dac";
-+ i2s-controller = <&i2s>;
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&i2s>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ pcm5122@4c {
-+ #sound-dai-cells = <0>;
-+ compatible = "ti,pcm5122";
-+ reg = <0x4c>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts
-@@ -0,0 +1,39 @@
-+// Definitions for IQaudIO DAC+
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target = <&sound>;
-+ __overlay__ {
-+ compatible = "iqaudio,iqaudio-dac";
-+ i2s-controller = <&i2s>;
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&i2s>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ pcm5122@4c {
-+ #sound-dai-cells = <0>;
-+ compatible = "ti,pcm5122";
-+ reg = <0x4c>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/lirc-rpi-overlay.dts
-@@ -0,0 +1,57 @@
-+// Definitions for lirc-rpi module
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target-path = "/";
-+ __overlay__ {
-+ lirc_rpi: lirc_rpi {
-+ compatible = "rpi,lirc-rpi";
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&lirc_pins>;
-+ status = "okay";
-+
-+ // Override autodetection of IR receiver circuit
-+ // (0 = active high, 1 = active low, -1 = no override )
-+ rpi,sense = <0xffffffff>;
-+
-+ // Software carrier
-+ // (0 = off, 1 = on)
-+ rpi,softcarrier = <1>;
-+
-+ // Invert output
-+ // (0 = off, 1 = on)
-+ rpi,invert = <0>;
-+
-+ // Enable debugging messages
-+ // (0 = off, 1 = on)
-+ rpi,debug = <0>;
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ lirc_pins: lirc_pins {
-+ brcm,pins = <17 18>;
-+ brcm,function = <1 0>; // out in
-+ brcm,pull = <0 1>; // off down
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ gpio_out_pin = <&lirc_pins>,"brcm,pins:0";
-+ gpio_in_pin = <&lirc_pins>,"brcm,pins:4";
-+ gpio_in_pull = <&lirc_pins>,"brcm,pull:4";
-+
-+ sense = <&lirc_rpi>,"rpi,sense:0";
-+ softcarrier = <&lirc_rpi>,"rpi,softcarrier:0";
-+ invert = <&lirc_rpi>,"rpi,invert:0";
-+ debug = <&lirc_rpi>,"rpi,debug:0";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/mcp2515-can0-overlay.dts
-@@ -0,0 +1,69 @@
-+/*
-+ * Device tree overlay for mcp251x/can0 on spi0.0
-+ */
-+
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709";
-+ /* disable spi-dev for spi0.0 */
-+ fragment@0 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ status = "okay";
-+ spidev@0{
-+ status = "disabled";
-+ };
-+ };
-+ };
-+
-+ /* the interrupt pin of the can-controller */
-+ fragment@1 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ can0_pins: can0_pins {
-+ brcm,pins = <25>;
-+ brcm,function = <0>; /* input */
-+ };
-+ };
-+ };
-+
-+ /* the clock/oscillator of the can-controller */
-+ fragment@2 {
-+ target-path = "/clocks";
-+ __overlay__ {
-+ /* external oscillator of mcp2515 on SPI0.0 */
-+ can0_osc: can0_osc {
-+ compatible = "fixed-clock";
-+ #clock-cells = <0>;
-+ clock-frequency = <16000000>;
-+ };
-+ };
-+ };
-+
-+ /* the spi config of the can-controller itself binding everything together */
-+ fragment@3 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ can0: mcp2515@0 {
-+ reg = <0>;
-+ compatible = "microchip,mcp2515";
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&can0_pins>;
-+ spi-max-frequency = <10000000>;
-+ interrupt-parent = <&gpio>;
-+ interrupts = <25 0x2>;
-+ clocks = <&can0_osc>;
-+ };
-+ };
-+ };
-+ __overrides__ {
-+ oscillator = <&can0_osc>,"clock-frequency:0";
-+ spimaxfrequency = <&can0>,"spi-max-frequency:0";
-+ interrupt = <&can0_pins>,"brcm,pins:0",<&can0>,"interrupts:0";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/mcp2515-can1-overlay.dts
-@@ -0,0 +1,69 @@
-+/*
-+ * Device tree overlay for mcp251x/can1 on spi0.1 edited by petit_miner
-+ */
-+
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709";
-+ /* disable spi-dev for spi0.1 */
-+ fragment@0 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ status = "okay";
-+ spidev@1{
-+ status = "disabled";
-+ };
-+ };
-+ };
-+
-+ /* the interrupt pin of the can-controller */
-+ fragment@1 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ can1_pins: can1_pins {
-+ brcm,pins = <25>;
-+ brcm,function = <0>; /* input */
-+ };
-+ };
-+ };
-+
-+ /* the clock/oscillator of the can-controller */
-+ fragment@2 {
-+ target-path = "/clocks";
-+ __overlay__ {
-+ /* external oscillator of mcp2515 on spi0.1 */
-+ can1_osc: can1_osc {
-+ compatible = "fixed-clock";
-+ #clock-cells = <0>;
-+ clock-frequency = <16000000>;
-+ };
-+ };
-+ };
-+
-+ /* the spi config of the can-controller itself binding everything together */
-+ fragment@3 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ can1: mcp2515@1 {
-+ reg = <1>;
-+ compatible = "microchip,mcp2515";
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&can1_pins>;
-+ spi-max-frequency = <10000000>;
-+ interrupt-parent = <&gpio>;
-+ interrupts = <25 0x2>;
-+ clocks = <&can1_osc>;
-+ };
-+ };
-+ };
-+ __overrides__ {
-+ oscillator = <&can1_osc>,"clock-frequency:0";
-+ spimaxfrequency = <&can1>,"spi-max-frequency:0";
-+ interrupt = <&can1_pins>,"brcm,pins:0",<&can1>,"interrupts:0";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/mmc-overlay.dts
-@@ -0,0 +1,39 @@
-+/dts-v1/;
-+/plugin/;
-+
-+/{
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target = <&mmc>;
-+ frag0: __overlay__ {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&mmc_pins>;
-+ bus-width = <4>;
-+ brcm,overclock-50 = <0>;
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ mmc_pins: mmc_pins {
-+ brcm,pins = <48 49 50 51 52 53>;
-+ brcm,function = <7>; /* alt3 */
-+ };
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&sdhost>;
-+ __overlay__ {
-+ status = "disabled";
-+ };
-+ };
-+
-+ __overrides__ {
-+ overclock_50 = <&frag0>,"brcm,overclock-50:0";
-+ force_pio = <&frag0>,"brcm,force-pio?";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/mz61581-overlay.dts
-@@ -0,0 +1,111 @@
-+/*
-+ * Device Tree overlay for MZ61581-PI-EXT 2014.12.28 by Tontec
-+ *
-+ */
-+
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+
-+ fragment@0 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ status = "okay";
-+
-+ spidev@0{
-+ status = "disabled";
-+ };
-+
-+ spidev@1{
-+ status = "disabled";
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ mz61581_pins: mz61581_pins {
-+ brcm,pins = <4 15 18 25>;
-+ brcm,function = <0 1 1 1>; /* in out out out */
-+ };
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ mz61581: mz61581@0{
-+ compatible = "samsung,s6d02a1";
-+ reg = <0>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&mz61581_pins>;
-+
-+ spi-max-frequency = <128000000>;
-+ spi-cpol;
-+ spi-cpha;
-+
-+ width = <320>;
-+ height = <480>;
-+ rotate = <270>;
-+ bgr;
-+ fps = <30>;
-+ buswidth = <8>;
-+ txbuflen = <32768>;
-+
-+ reset-gpios = <&gpio 15 0>;
-+ dc-gpios = <&gpio 25 0>;
-+ led-gpios = <&gpio 18 0>;
-+
-+ init = <0x10000b0 00
-+ 0x1000011
-+ 0x20000ff
-+ 0x10000b3 0x02 0x00 0x00 0x00
-+ 0x10000c0 0x13 0x3b 0x00 0x02 0x00 0x01 0x00 0x43
-+ 0x10000c1 0x08 0x16 0x08 0x08
-+ 0x10000c4 0x11 0x07 0x03 0x03
-+ 0x10000c6 0x00
-+ 0x10000c8 0x03 0x03 0x13 0x5c 0x03 0x07 0x14 0x08 0x00 0x21 0x08 0x14 0x07 0x53 0x0c 0x13 0x03 0x03 0x21 0x00
-+ 0x1000035 0x00
-+ 0x1000036 0xa0
-+ 0x100003a 0x55
-+ 0x1000044 0x00 0x01
-+ 0x10000d0 0x07 0x07 0x1d 0x03
-+ 0x10000d1 0x03 0x30 0x10
-+ 0x10000d2 0x03 0x14 0x04
-+ 0x1000029
-+ 0x100002c>;
-+
-+ /* This is a workaround to make sure the init sequence slows down and doesn't fail */
-+ debug = <3>;
-+ };
-+
-+ mz61581_ts: mz61581_ts@1 {
-+ compatible = "ti,ads7846";
-+ reg = <1>;
-+
-+ spi-max-frequency = <2000000>;
-+ interrupts = <4 2>; /* high-to-low edge triggered */
-+ interrupt-parent = <&gpio>;
-+ pendown-gpio = <&gpio 4 0>;
-+
-+ ti,x-plate-ohms = /bits/ 16 <60>;
-+ ti,pressure-max = /bits/ 16 <255>;
-+ };
-+ };
-+ };
-+ __overrides__ {
-+ speed = <&mz61581>, "spi-max-frequency:0";
-+ rotate = <&mz61581>, "rotate:0";
-+ fps = <&mz61581>, "fps:0";
-+ txbuflen = <&mz61581>, "txbuflen:0";
-+ debug = <&mz61581>, "debug:0";
-+ xohms = <&mz61581_ts>,"ti,x-plate-ohms;0";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/piscreen-overlay.dts
-@@ -0,0 +1,96 @@
-+/*
-+ * Device Tree overlay for PiScreen 3.5" display shield by Ozzmaker
-+ *
-+ */
-+
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+
-+ fragment@0 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ status = "okay";
-+
-+ spidev@0{
-+ status = "disabled";
-+ };
-+
-+ spidev@1{
-+ status = "disabled";
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ piscreen_pins: piscreen_pins {
-+ brcm,pins = <17 25 24 22>;
-+ brcm,function = <0 1 1 1>; /* in out out out */
-+ };
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ piscreen: piscreen@0{
-+ compatible = "ilitek,ili9486";
-+ reg = <0>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&piscreen_pins>;
-+
-+ spi-max-frequency = <24000000>;
-+ rotate = <270>;
-+ bgr;
-+ fps = <30>;
-+ buswidth = <8>;
-+ regwidth = <16>;
-+ reset-gpios = <&gpio 25 0>;
-+ dc-gpios = <&gpio 24 0>;
-+ led-gpios = <&gpio 22 1>;
-+ debug = <0>;
-+
-+ init = <0x10000b0 0x00
-+ 0x1000011
-+ 0x20000ff
-+ 0x100003a 0x55
-+ 0x1000036 0x28
-+ 0x10000c2 0x44
-+ 0x10000c5 0x00 0x00 0x00 0x00
-+ 0x10000e0 0x0f 0x1f 0x1c 0x0c 0x0f 0x08 0x48 0x98 0x37 0x0a 0x13 0x04 0x11 0x0d 0x00
-+ 0x10000e1 0x0f 0x32 0x2e 0x0b 0x0d 0x05 0x47 0x75 0x37 0x06 0x10 0x03 0x24 0x20 0x00
-+ 0x10000e2 0x0f 0x32 0x2e 0x0b 0x0d 0x05 0x47 0x75 0x37 0x06 0x10 0x03 0x24 0x20 0x00
-+ 0x1000011
-+ 0x1000029>;
-+ };
-+
-+ piscreen_ts: piscreen-ts@1 {
-+ compatible = "ti,ads7846";
-+ reg = <1>;
-+
-+ spi-max-frequency = <2000000>;
-+ interrupts = <17 2>; /* high-to-low edge triggered */
-+ interrupt-parent = <&gpio>;
-+ pendown-gpio = <&gpio 17 0>;
-+ ti,swap-xy;
-+ ti,x-plate-ohms = /bits/ 16 <100>;
-+ ti,pressure-max = /bits/ 16 <255>;
-+ };
-+ };
-+ };
-+ __overrides__ {
-+ speed = <&piscreen>,"spi-max-frequency:0";
-+ rotate = <&piscreen>,"rotate:0";
-+ fps = <&piscreen>,"fps:0";
-+ debug = <&piscreen>,"debug:0";
-+ xohms = <&piscreen_ts>,"ti,x-plate-ohms;0";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/pitft28-resistive-overlay.dts
-@@ -0,0 +1,115 @@
-+/*
-+ * Device Tree overlay for Adafruit PiTFT 2.8" resistive touch screen
-+ *
-+ */
-+
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+
-+ fragment@0 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ status = "okay";
-+
-+ spidev@0{
-+ status = "disabled";
-+ };
-+
-+ spidev@1{
-+ status = "disabled";
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ pitft_pins: pitft_pins {
-+ brcm,pins = <24 25>;
-+ brcm,function = <0 1>; /* in out */
-+ brcm,pull = <2 0>; /* pullup none */
-+ };
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ pitft: pitft@0{
-+ compatible = "ilitek,ili9340";
-+ reg = <0>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&pitft_pins>;
-+
-+ spi-max-frequency = <32000000>;
-+ rotate = <90>;
-+ fps = <25>;
-+ bgr;
-+ buswidth = <8>;
-+ dc-gpios = <&gpio 25 0>;
-+ debug = <0>;
-+ };
-+
-+ pitft_ts@1 {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ compatible = "st,stmpe610";
-+ reg = <1>;
-+
-+ spi-max-frequency = <500000>;
-+ irq-gpio = <&gpio 24 0x2>; /* IRQF_TRIGGER_FALLING */
-+ interrupts = <24 2>; /* high-to-low edge triggered */
-+ interrupt-parent = <&gpio>;
-+ interrupt-controller;
-+
-+ stmpe_touchscreen {
-+ compatible = "st,stmpe-ts";
-+ st,sample-time = <4>;
-+ st,mod-12b = <1>;
-+ st,ref-sel = <0>;
-+ st,adc-freq = <2>;
-+ st,ave-ctrl = <3>;
-+ st,touch-det-delay = <4>;
-+ st,settling = <2>;
-+ st,fraction-z = <7>;
-+ st,i-drive = <0>;
-+ };
-+
-+ stmpe_gpio: stmpe_gpio {
-+ #gpio-cells = <2>;
-+ compatible = "st,stmpe-gpio";
-+ /*
-+ * only GPIO2 is wired/available
-+ * and it is wired to the backlight
-+ */
-+ st,norequest-mask = <0x7b>;
-+ };
-+ };
-+ };
-+ };
-+
-+ fragment@3 {
-+ target-path = "/soc";
-+ __overlay__ {
-+ backlight {
-+ compatible = "gpio-backlight";
-+ gpios = <&stmpe_gpio 2 0>;
-+ default-on;
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ speed = <&pitft>,"spi-max-frequency:0";
-+ rotate = <&pitft>,"rotate:0";
-+ fps = <&pitft>,"fps:0";
-+ debug = <&pitft>,"debug:0";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/pps-gpio-overlay.dts
-@@ -0,0 +1,34 @@
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2708";
-+ fragment@0 {
-+ target-path = "/";
-+ __overlay__ {
-+ pps: pps {
-+ compatible = "pps-gpio";
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&pps_pins>;
-+ gpios = <&gpio 18 0>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ pps_pins: pps_pins {
-+ brcm,pins = <18>;
-+ brcm,function = <0>; // in
-+ brcm,pull = <0>; // off
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ gpiopin = <&pps>,"gpios:4",
-+ <&pps_pins>,"brcm,pins:0";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts
-@@ -0,0 +1,46 @@
-+/dts-v1/;
-+/plugin/;
-+
-+/*
-+This is the 2-channel overlay - only use it if you need both channels.
-+
-+Legal pin,function combinations for each channel:
-+ PWM0: 12,4(Alt0) 18,2(Alt5) 40,4(Alt0) 52,5(Alt1)
-+ PWM1: 13,4(Alt0) 19,2(Alt5) 41,4(Alt0) 45,4(Alt0) 53,5(Alt1)
-+
-+N.B.:
-+ 1) Pin 18 is the only one available on all platforms, and
-+ it is the one used by the I2S audio interface.
-+ Pins 12 and 13 might be better choices on an A+, B+ or Pi2.
-+ 2) The onboard analogue audio output uses both PWM channels.
-+ 3) So be careful mixing audio and PWM.
-+*/
-+
-+/ {
-+ fragment@0 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ pwm_pins: pwm_pins {
-+ brcm,pins = <18 19>;
-+ brcm,function = <2 2>; /* Alt5 */
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&pwm>;
-+ __overlay__ {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&pwm_pins>;
-+ status = "okay";
-+ };
-+ };
-+
-+ __overrides__ {
-+ pin = <&pwm_pins>,"brcm,pins:0";
-+ pin2 = <&pwm_pins>,"brcm,pins:4";
-+ func = <&pwm_pins>,"brcm,function:0";
-+ func2 = <&pwm_pins>,"brcm,function:4";
-+ clock = <&clk_pwm>,"clock-frequency:0";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/pwm-overlay.dts
-@@ -0,0 +1,42 @@
-+/dts-v1/;
-+/plugin/;
-+
-+/*
-+Legal pin,function combinations for each channel:
-+ PWM0: 12,4(Alt0) 18,2(Alt5) 40,4(Alt0) 52,5(Alt1)
-+ PWM1: 13,4(Alt0) 19,2(Alt5) 41,4(Alt0) 45,4(Alt0) 53,5(Alt1)
-+
-+N.B.:
-+ 1) Pin 18 is the only one available on all platforms, and
-+ it is the one used by the I2S audio interface.
-+ Pins 12 and 13 might be better choices on an A+, B+ or Pi2.
-+ 2) The onboard analogue audio output uses both PWM channels.
-+ 3) So be careful mixing audio and PWM.
-+*/
-+
-+/ {
-+ fragment@0 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ pwm_pins: pwm_pins {
-+ brcm,pins = <18>;
-+ brcm,function = <2>; /* Alt5 */
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&pwm>;
-+ __overlay__ {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&pwm_pins>;
-+ status = "okay";
-+ };
-+ };
-+
-+ __overrides__ {
-+ pin = <&pwm_pins>,"brcm,pins:0";
-+ func = <&pwm_pins>,"brcm,function:0";
-+ clock = <&clk_pwm>,"clock-frequency:0";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/raspidac3-overlay.dts
-@@ -0,0 +1,45 @@
-+// Definitions for RaspiDACv3
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target = <&sound>;
-+ __overlay__ {
-+ compatible = "jg,raspidacv3";
-+ i2s-controller = <&i2s>;
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&i2s>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ pcm5122@4c {
-+ #sound-dai-cells = <0>;
-+ compatible = "ti,pcm5122";
-+ reg = <0x4c>;
-+ status = "okay";
-+ };
-+
-+ tpa6130a2: tpa6130a2@60 {
-+ compatible = "ti,tpa6130a2";
-+ reg = <0x60>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/rpi-dac-overlay.dts
-@@ -0,0 +1,34 @@
-+// Definitions for RPi DAC
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target = <&sound>;
-+ __overlay__ {
-+ compatible = "rpi,rpi-dac";
-+ i2s-controller = <&i2s>;
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&i2s>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@2 {
-+ target-path = "/";
-+ __overlay__ {
-+ pcm1794a-codec {
-+ #sound-dai-cells = <0>;
-+ compatible = "ti,pcm1794a";
-+ status = "okay";
-+ };
-+ };
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/rpi-display-overlay.dts
-@@ -0,0 +1,82 @@
-+/*
-+ * Device Tree overlay for rpi-display by Watterott
-+ *
-+ */
-+
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+
-+ fragment@0 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ status = "okay";
-+
-+ spidev@0{
-+ status = "disabled";
-+ };
-+
-+ spidev@1{
-+ status = "disabled";
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ rpi_display_pins: rpi_display_pins {
-+ brcm,pins = <18 23 24 25>;
-+ brcm,function = <1 1 1 0>; /* out out out in */
-+ brcm,pull = <0 0 0 2>; /* - - - up */
-+ };
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ rpidisplay: rpi-display@0{
-+ compatible = "ilitek,ili9341";
-+ reg = <0>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&rpi_display_pins>;
-+
-+ spi-max-frequency = <32000000>;
-+ rotate = <270>;
-+ bgr;
-+ fps = <30>;
-+ buswidth = <8>;
-+ reset-gpios = <&gpio 23 0>;
-+ dc-gpios = <&gpio 24 0>;
-+ led-gpios = <&gpio 18 1>;
-+ debug = <0>;
-+ };
-+
-+ rpidisplay_ts: rpi-display-ts@1 {
-+ compatible = "ti,ads7846";
-+ reg = <1>;
-+
-+ spi-max-frequency = <2000000>;
-+ interrupts = <25 2>; /* high-to-low edge triggered */
-+ interrupt-parent = <&gpio>;
-+ pendown-gpio = <&gpio 25 0>;
-+ ti,x-plate-ohms = /bits/ 16 <60>;
-+ ti,pressure-max = /bits/ 16 <255>;
-+ };
-+ };
-+ };
-+ __overrides__ {
-+ speed = <&rpidisplay>,"spi-max-frequency:0";
-+ rotate = <&rpidisplay>,"rotate:0";
-+ fps = <&rpidisplay>,"fps:0";
-+ debug = <&rpidisplay>,"debug:0";
-+ xohms = <&rpidisplay_ts>,"ti,x-plate-ohms;0";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/rpi-ft5406-overlay.dts
-@@ -0,0 +1,17 @@
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target-path = "/";
-+ __overlay__ {
-+ rpi_ft5406: rpi_ft5406 {
-+ compatible = "rpi,rpi-ft5406";
-+ firmware = <&firmware>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/rpi-proto-overlay.dts
-@@ -0,0 +1,39 @@
-+// Definitions for Rpi-Proto
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target = <&sound>;
-+ __overlay__ {
-+ compatible = "rpi,rpi-proto";
-+ i2s-controller = <&i2s>;
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&i2s>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ wm8731@1a {
-+ #sound-dai-cells = <0>;
-+ compatible = "wlf,wm8731";
-+ reg = <0x1a>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/rpi-sense-overlay.dts
-@@ -0,0 +1,47 @@
-+// rpi-sense HAT
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2708", "brcm,bcm2709";
-+
-+ fragment@0 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ rpi-sense@46 {
-+ compatible = "rpi,rpi-sense";
-+ reg = <0x46>;
-+ keys-int-gpios = <&gpio 23 1>;
-+ status = "okay";
-+ };
-+
-+ lsm9ds1-magn@1c {
-+ compatible = "st,lsm9ds1-magn";
-+ reg = <0x1c>;
-+ status = "okay";
-+ };
-+
-+ lsm9ds1-accel6a {
-+ compatible = "st,lsm9ds1-accel";
-+ reg = <0x6a>;
-+ status = "okay";
-+ };
-+
-+ lps25h-press@5c {
-+ compatible = "st,lps25h-press";
-+ reg = <0x5c>;
-+ status = "okay";
-+ };
-+
-+ hts221-humid@5f {
-+ compatible = "st,hts221-humid";
-+ reg = <0x5f>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/sdhost-overlay.dts
-@@ -0,0 +1,29 @@
-+/dts-v1/;
-+/plugin/;
-+
-+/{
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target = <&mmc>;
-+ __overlay__ {
-+ status = "disabled";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&sdhost>;
-+ frag1: __overlay__ {
-+ brcm,overclock-50 = <0>;
-+ brcm,pio-limit = <1>;
-+ status = "okay";
-+ };
-+ };
-+
-+ __overrides__ {
-+ overclock_50 = <&frag1>,"brcm,overclock-50:0";
-+ force_pio = <&frag1>,"brcm,force-pio?";
-+ pio_limit = <&frag1>,"brcm,pio-limit:0";
-+ debug = <&frag1>,"brcm,debug?";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/sdio-overlay.dts
-@@ -0,0 +1,32 @@
-+/* Enable SDIO from MMC interface via GPIOs 22-27. Includes sdhost overlay. */
-+
-+/include/ "sdhost-overlay.dts"
-+
-+/{
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@3 {
-+ target = <&mmc>;
-+ sdio_mmc: __overlay__ {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&sdio_pins>;
-+ non-removable;
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@4 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ sdio_pins: sdio_pins {
-+ brcm,pins = <22 23 24 25 26 27>;
-+ brcm,function = <7 7 7 7 7 7>; /* ALT3 = SD1 */
-+ brcm,pull = <0 2 2 2 2 2>;
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ poll_once = <&sdio_mmc>,"non-removable?";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/smi-dev-overlay.dts
-@@ -0,0 +1,18 @@
-+// Description: Overlay to enable character device interface for SMI.
-+// Author: Luke Wren <luke@raspberrypi.org>
-+
-+/dts-v1/;
-+/plugin/;
-+
-+/{
-+ fragment@0 {
-+ target = <&soc>;
-+ __overlay__ {
-+ smi_dev {
-+ compatible = "brcm,bcm2835-smi-dev";
-+ smi_handle = <&smi>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/smi-nand-overlay.dts
-@@ -0,0 +1,69 @@
-+// Description: Overlay to enable NAND flash through
-+// the secondary memory interface
-+// Author: Luke Wren
-+
-+/dts-v1/;
-+/plugin/;
-+
-+/{
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target = <&smi>;
-+ __overlay__ {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&smi_pins>;
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&soc>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+
-+ nand: flash@0 {
-+ compatible = "brcm,bcm2835-smi-nand";
-+ smi_handle = <&smi>;
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+ status = "okay";
-+
-+ partition@0 {
-+ label = "stage2";
-+ // 128k
-+ reg = <0 0x20000>;
-+ read-only;
-+ };
-+ partition@1 {
-+ label = "firmware";
-+ // 16M
-+ reg = <0x20000 0x1000000>;
-+ read-only;
-+ };
-+ partition@2 {
-+ label = "root";
-+ // 2G (will need to use 64 bit for >=4G)
-+ reg = <0x1020000 0x80000000>;
-+ };
-+ };
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ smi_pins: smi_pins {
-+ brcm,pins = <0 1 2 3 4 5 6 7 8 9 10 11
-+ 12 13 14 15>;
-+ /* Alt 1: SMI */
-+ brcm,function = <5 5 5 5 5 5 5 5 5 5 5
-+ 5 5 5 5 5>;
-+ /* /CS, /WE and /OE are pulled high, as they are
-+ generally active low signals */
-+ brcm,pull = <2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0>;
-+ };
-+ };
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/smi-overlay.dts
-@@ -0,0 +1,37 @@
-+// Description: Overlay to enable the secondary memory interface peripheral
-+// Author: Luke Wren
-+
-+/dts-v1/;
-+/plugin/;
-+
-+/{
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target = <&smi>;
-+ __overlay__ {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&smi_pins>;
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ smi_pins: smi_pins {
-+ /* Don't configure the top two address bits, as
-+ these are already used as ID_SD and ID_SC */
-+ brcm,pins = <2 3 4 5 6 7 8 9 10 11 12 13 14 15
-+ 16 17 18 19 20 21 22 23 24 25>;
-+ /* Alt 0: SMI */
-+ brcm,function = <5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
-+ 5 5 5 5 5 5 5 5 5>;
-+ /* /CS, /WE and /OE are pulled high, as they are
-+ generally active low signals */
-+ brcm,pull = <2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0
-+ 0 0 0 0 0 0 0>;
-+ };
-+ };
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/spi-gpio35-39-overlay.dts
-@@ -0,0 +1,31 @@
-+/*
-+ * Device tree overlay to move spi0 to gpio 35 to 39 on CM
-+ */
-+
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709";
-+
-+ fragment@0 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ cs-gpios = <&gpio 36 1>, <&gpio 35 1>;
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&spi0_cs_pins>;
-+ __overlay__ {
-+ bcrm,pins = <36 35>;
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&spi0_pins>;
-+ __overlay__ {
-+ bcrm,pins = <37 38 39>;
-+ };
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/tinylcd35-overlay.dts
-@@ -0,0 +1,216 @@
-+/*
-+ * tinylcd35-overlay.dts
-+ *
-+ * -------------------------------------------------
-+ * www.tinlylcd.com
-+ * -------------------------------------------------
-+ * Device---Driver-----BUS GPIO's
-+ * display tinylcd35 spi0.0 25 24 18
-+ * touch ads7846 spi0.1 5
-+ * rtc ds1307 i2c1-0068
-+ * rtc pcf8563 i2c1-0051
-+ * keypad gpio-keys --------- 17 22 27 23 28
-+ *
-+ *
-+ * TinyLCD.com 3.5 inch TFT
-+ *
-+ * Version 001
-+ * 5/3/2015 -- Noralf Trønnes Initial Device tree framework
-+ * 10/3/2015 -- tinylcd@gmail.com added ds1307 support.
-+ *
-+ */
-+
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+
-+ fragment@0 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ status = "okay";
-+
-+ spidev@0{
-+ status = "disabled";
-+ };
-+
-+ spidev@1{
-+ status = "disabled";
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ tinylcd35_pins: tinylcd35_pins {
-+ brcm,pins = <25 24 18>;
-+ brcm,function = <1>; /* out */
-+ };
-+ tinylcd35_ts_pins: tinylcd35_ts_pins {
-+ brcm,pins = <5>;
-+ brcm,function = <0>; /* in */
-+ };
-+ keypad_pins: keypad_pins {
-+ brcm,pins = <4 17 22 23 27>;
-+ brcm,function = <0>; /* in */
-+ brcm,pull = <1>; /* down */
-+ };
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ tinylcd35: tinylcd35@0{
-+ compatible = "neosec,tinylcd";
-+ reg = <0>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&tinylcd35_pins>,
-+ <&tinylcd35_ts_pins>;
-+
-+ spi-max-frequency = <48000000>;
-+ rotate = <270>;
-+ fps = <20>;
-+ bgr;
-+ buswidth = <8>;
-+ reset-gpios = <&gpio 25 0>;
-+ dc-gpios = <&gpio 24 0>;
-+ led-gpios = <&gpio 18 1>;
-+ debug = <0>;
-+
-+ init = <0x10000B0 0x80
-+ 0x10000C0 0x0A 0x0A
-+ 0x10000C1 0x01 0x01
-+ 0x10000C2 0x33
-+ 0x10000C5 0x00 0x42 0x80
-+ 0x10000B1 0xD0 0x11
-+ 0x10000B4 0x02
-+ 0x10000B6 0x00 0x22 0x3B
-+ 0x10000B7 0x07
-+ 0x1000036 0x58
-+ 0x10000F0 0x36 0xA5 0xD3
-+ 0x10000E5 0x80
-+ 0x10000E5 0x01
-+ 0x10000B3 0x00
-+ 0x10000E5 0x00
-+ 0x10000F0 0x36 0xA5 0x53
-+ 0x10000E0 0x00 0x35 0x33 0x00 0x00 0x00 0x00 0x35 0x33 0x00 0x00 0x00
-+ 0x100003A 0x55
-+ 0x1000011
-+ 0x2000001
-+ 0x1000029>;
-+ };
-+
-+ tinylcd35_ts: tinylcd35_ts@1 {
-+ compatible = "ti,ads7846";
-+ reg = <1>;
-+ status = "disabled";
-+
-+ spi-max-frequency = <2000000>;
-+ interrupts = <5 2>; /* high-to-low edge triggered */
-+ interrupt-parent = <&gpio>;
-+ pendown-gpio = <&gpio 5 0>;
-+ ti,x-plate-ohms = /bits/ 16 <100>;
-+ ti,pressure-max = /bits/ 16 <255>;
-+ };
-+ };
-+ };
-+
-+ /* RTC */
-+
-+ fragment@3 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ pcf8563: pcf8563@51 {
-+ compatible = "nxp,pcf8563";
-+ reg = <0x51>;
-+ status = "disabled";
-+ };
-+ };
-+ };
-+
-+ fragment@4 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ ds1307: ds1307@68 {
-+ compatible = "maxim,ds1307";
-+ reg = <0x68>;
-+ status = "disabled";
-+ };
-+ };
-+ };
-+
-+ /*
-+ * Values for input event code is found under the
-+ * 'Keys and buttons' heading in include/uapi/linux/input.h
-+ */
-+ fragment@5 {
-+ target-path = "/soc";
-+ __overlay__ {
-+ keypad: keypad {
-+ compatible = "gpio-keys";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&keypad_pins>;
-+ status = "disabled";
-+ autorepeat;
-+
-+ button@17 {
-+ label = "GPIO KEY_UP";
-+ linux,code = <103>;
-+ gpios = <&gpio 17 0>;
-+ };
-+ button@22 {
-+ label = "GPIO KEY_DOWN";
-+ linux,code = <108>;
-+ gpios = <&gpio 22 0>;
-+ };
-+ button@27 {
-+ label = "GPIO KEY_LEFT";
-+ linux,code = <105>;
-+ gpios = <&gpio 27 0>;
-+ };
-+ button@23 {
-+ label = "GPIO KEY_RIGHT";
-+ linux,code = <106>;
-+ gpios = <&gpio 23 0>;
-+ };
-+ button@4 {
-+ label = "GPIO KEY_ENTER";
-+ linux,code = <28>;
-+ gpios = <&gpio 4 0>;
-+ };
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ speed = <&tinylcd35>,"spi-max-frequency:0";
-+ rotate = <&tinylcd35>,"rotate:0";
-+ fps = <&tinylcd35>,"fps:0";
-+ debug = <&tinylcd35>,"debug:0";
-+ touch = <&tinylcd35_ts>,"status";
-+ touchgpio = <&tinylcd35_ts_pins>,"brcm,pins:0",
-+ <&tinylcd35_ts>,"interrupts:0",
-+ <&tinylcd35_ts>,"pendown-gpio:4";
-+ xohms = <&tinylcd35_ts>,"ti,x-plate-ohms;0";
-+ rtc-pcf = <&i2c1>,"status",
-+ <&pcf8563>,"status";
-+ rtc-ds = <&i2c1>,"status",
-+ <&ds1307>,"status";
-+ keypad = <&keypad>,"status";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/uart1-overlay.dts
-@@ -0,0 +1,38 @@
-+/dts-v1/;
-+/plugin/;
-+
-+/{
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target = <&uart1>;
-+ __overlay__ {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&uart1_pins>;
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ uart1_pins: uart1_pins {
-+ brcm,pins = <14 15>;
-+ brcm,function = <2>; /* alt5 */
-+ brcm,pull = <0 2>;
-+ };
-+ };
-+ };
-+
-+ fragment@2 {
-+ target-path = "/chosen";
-+ __overlay__ {
-+ bootargs = "8250.nr_uarts=1";
-+ };
-+ };
-+
-+ __overrides__ {
-+ txd1_pin = <&uart1_pins>,"brcm,pins:0";
-+ rxd1_pin = <&uart1_pins>,"brcm,pins:4";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/vga666-overlay.dts
-@@ -0,0 +1,30 @@
-+/dts-v1/;
-+/plugin/;
-+
-+/{
-+ compatible = "brcm,bcm2708";
-+
-+ // There is no VGA driver module, but we need a platform device
-+ // node (that doesn't already use pinctrl) to hang the pinctrl
-+ // reference on - leds will do
-+
-+ fragment@0 {
-+ target = <&leds>;
-+ __overlay__ {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&vga666_pins>;
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ vga666_pins: vga666_pins {
-+ brcm,pins = <2 3 4 5 6 7 8 9 10 11 12
-+ 13 14 15 16 17 18 19 20 21>;
-+ brcm,function = <6>; /* alt2 */
-+ brcm,pull = <0>; /* no pull */
-+ };
-+ };
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/w1-gpio-overlay.dts
-@@ -0,0 +1,39 @@
-+// Definitions for w1-gpio module (without external pullup)
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target-path = "/";
-+ __overlay__ {
-+
-+ w1: onewire@0 {
-+ compatible = "w1-gpio";
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&w1_pins>;
-+ gpios = <&gpio 4 0>;
-+ rpi,parasitic-power = <0>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ w1_pins: w1_pins {
-+ brcm,pins = <4>;
-+ brcm,function = <0>; // in (initially)
-+ brcm,pull = <0>; // off
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ gpiopin = <&w1>,"gpios:4",
-+ <&w1_pins>,"brcm,pins:0";
-+ pullup = <&w1>,"rpi,parasitic-power:0";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/w1-gpio-pullup-overlay.dts
-@@ -0,0 +1,41 @@
-+// Definitions for w1-gpio module (with external pullup)
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target-path = "/";
-+ __overlay__ {
-+
-+ w1: onewire@0 {
-+ compatible = "w1-gpio";
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&w1_pins>;
-+ gpios = <&gpio 4 0>, <&gpio 5 1>;
-+ rpi,parasitic-power = <0>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ w1_pins: w1_pins {
-+ brcm,pins = <4 5>;
-+ brcm,function = <0 1>; // in out
-+ brcm,pull = <0 0>; // off off
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ gpiopin = <&w1>,"gpios:4",
-+ <&w1_pins>,"brcm,pins:0";
-+ extpullup = <&w1>,"gpios:16",
-+ <&w1_pins>,"brcm,pins:4";
-+ pullup = <&w1>,"rpi,parasitic-power:0";
-+ };
-+};
diff --git a/target/linux/brcm2708/patches-4.4/0052-bcm2835-Match-with-BCM2708-Device-Trees.patch b/target/linux/brcm2708/patches-4.4/0052-bcm2835-Match-with-BCM2708-Device-Trees.patch
new file mode 100644
index 0000000000..e9d7e9503a
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0052-bcm2835-Match-with-BCM2708-Device-Trees.patch
@@ -0,0 +1,515 @@
+From 5869509197e8b3b6080f212a22e7d10310fc0a9b Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
+Date: Sat, 15 Aug 2015 20:47:07 +0200
+Subject: [PATCH 052/381] bcm2835: Match with BCM2708 Device Trees
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+---
+ arch/arm/boot/dts/bcm2835-rpi-b-plus.dts | 132 ++++++++++++++++++---
+ arch/arm/boot/dts/bcm2835-rpi-b.dts | 115 ++++++++++++++++--
+ arch/arm/boot/dts/bcm2835.dtsi | 195 +++----------------------------
+ 3 files changed, 237 insertions(+), 205 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
+@@ -1,30 +1,128 @@
+ /dts-v1/;
+-#include "bcm2835-rpi.dtsi"
++#include "bcm2835.dtsi"
+
+ / {
+ compatible = "raspberrypi,model-b-plus", "brcm,bcm2835";
+ model = "Raspberry Pi Model B+";
+-
+- leds {
+- act {
+- gpios = <&gpio 47 0>;
+- };
+-
+- pwr {
+- label = "PWR";
+- gpios = <&gpio 35 0>;
+- default-state = "keep";
+- linux,default-trigger = "default-on";
+- };
+- };
+ };
+
+ &gpio {
+- pinctrl-0 = <&gpioout &alt0 &i2s_alt0 &alt3>;
++ spi0_pins: spi0_pins {
++ brcm,pins = <7 8 9 10 11>;
++ brcm,function = <4>; /* alt0 */
++ };
++
++ i2c0_pins: i2c0 {
++ brcm,pins = <0 1>;
++ brcm,function = <4>;
++ };
+
+- /* I2S interface */
+- i2s_alt0: i2s_alt0 {
++ i2c1_pins: i2c1 {
++ brcm,pins = <2 3>;
++ brcm,function = <4>;
++ };
++
++ i2s_pins: i2s {
+ brcm,pins = <18 19 20 21>;
+- brcm,function = <BCM2835_FSEL_ALT0>;
++ brcm,function = <4>; /* alt0 */
++ };
++};
++
++&mmc {
++ status = "okay";
++ bus-width = <4>;
++};
++
++&fb {
++ status = "okay";
++};
++
++&uart0 {
++ status = "okay";
++};
++
++&spi0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi0_pins>;
++
++ spidev@0{
++ compatible = "spidev";
++ reg = <0>; /* CE0 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <500000>;
++ };
++
++ spidev@1{
++ compatible = "spidev";
++ reg = <1>; /* CE1 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <500000>;
++ };
++};
++
++&i2c0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c0_pins>;
++ clock-frequency = <100000>;
++};
++
++&i2c1 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c1_pins>;
++ clock-frequency = <100000>;
++};
++
++&i2c2 {
++ clock-frequency = <100000>;
++};
++
++&i2s {
++ #sound-dai-cells = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2s_pins>;
++};
++
++&leds {
++ act_led: act {
++ label = "led0";
++ linux,default-trigger = "mmc0";
++ gpios = <&gpio 47 0>;
++ };
++
++ pwr_led: pwr {
++ label = "led1";
++ linux,default-trigger = "input";
++ gpios = <&gpio 35 0>;
++ };
++};
++
++/ {
++ __overrides__ {
++ uart0 = <&uart0>,"status";
++ uart0_clkrate = <&clk_uart0>,"clock-frequency:0";
++ uart1_clkrate = <&uart1>,"clock-frequency:0";
++ i2s = <&i2s>,"status";
++ spi = <&spi0>,"status";
++ i2c0 = <&i2c0>,"status";
++ i2c1 = <&i2c1>,"status";
++ i2c2_iknowwhatimdoing = <&i2c2>,"status";
++ i2c0_baudrate = <&i2c0>,"clock-frequency:0";
++ i2c1_baudrate = <&i2c1>,"clock-frequency:0";
++ i2c2_baudrate = <&i2c2>,"clock-frequency:0";
++ core_freq = <&clk_core>,"clock-frequency:0";
++
++ act_led_gpio = <&act_led>,"gpios:4";
++ act_led_activelow = <&act_led>,"gpios:8";
++ act_led_trigger = <&act_led>,"linux,default-trigger";
++
++ pwr_led_gpio = <&pwr_led>,"gpios:4";
++ pwr_led_activelow = <&pwr_led>,"gpios:8";
++ pwr_led_trigger = <&pwr_led>,"linux,default-trigger";
++
++ audio = <&audio>,"status";
++ watchdog = <&watchdog>,"status";
++ random = <&random>,"status";
+ };
+ };
+--- a/arch/arm/boot/dts/bcm2835-rpi-b.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-b.dts
+@@ -1,17 +1,118 @@
+ /dts-v1/;
+-#include "bcm2835-rpi.dtsi"
++#include "bcm2835.dtsi"
+
+ / {
+ compatible = "raspberrypi,model-b", "brcm,bcm2835";
+ model = "Raspberry Pi Model B";
++};
+
+- leds {
+- act {
+- gpios = <&gpio 16 1>;
+- };
++&gpio {
++ spi0_pins: spi0_pins {
++ brcm,pins = <7 8 9 10 11>;
++ brcm,function = <4>; /* alt0 */
++ };
++
++ i2c0_pins: i2c0 {
++ brcm,pins = <0 1>;
++ brcm,function = <4>;
++ };
++
++ i2c1_pins: i2c1 {
++ brcm,pins = <2 3>;
++ brcm,function = <4>;
++ };
++
++ i2s_pins: i2s {
++ brcm,pins = <28 29 30 31>;
++ brcm,function = <6>; /* alt2 */
+ };
+ };
+
+-&gpio {
+- pinctrl-0 = <&gpioout &alt0 &alt3>;
++&mmc {
++ status = "okay";
++ bus-width = <4>;
++};
++
++&fb {
++ status = "okay";
++};
++
++&uart0 {
++ status = "okay";
++};
++
++&spi0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi0_pins>;
++
++ spidev@0{
++ compatible = "spidev";
++ reg = <0>; /* CE0 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <500000>;
++ };
++
++ spidev@1{
++ compatible = "spidev";
++ reg = <1>; /* CE1 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <500000>;
++ };
++};
++
++&i2c0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c0_pins>;
++ clock-frequency = <100000>;
++};
++
++&i2c1 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c1_pins>;
++ clock-frequency = <100000>;
++};
++
++&i2c2 {
++ clock-frequency = <100000>;
++};
++
++&i2s {
++ #sound-dai-cells = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2s_pins>;
++};
++
++&leds {
++ act_led: act {
++ label = "led0";
++ linux,default-trigger = "mmc0";
++ gpios = <&gpio 16 1>;
++ };
++};
++
++/ {
++ __overrides__ {
++ uart0 = <&uart0>,"status";
++ uart0_clkrate = <&clk_uart0>,"clock-frequency:0";
++ uart1_clkrate = <&uart1>,"clock-frequency:0";
++ i2s = <&i2s>,"status";
++ spi = <&spi0>,"status";
++ i2c0 = <&i2c0>,"status";
++ i2c1 = <&i2c1>,"status";
++ i2c2_iknowwhatimdoing = <&i2c2>,"status";
++ i2c0_baudrate = <&i2c0>,"clock-frequency:0";
++ i2c1_baudrate = <&i2c1>,"clock-frequency:0";
++ i2c2_baudrate = <&i2c2>,"clock-frequency:0";
++ core_freq = <&clk_core>,"clock-frequency:0";
++
++ act_led_gpio = <&act_led>,"gpios:4";
++ act_led_activelow = <&act_led>,"gpios:8";
++ act_led_trigger = <&act_led>,"linux,default-trigger";
++
++ audio = <&audio>,"status";
++ watchdog = <&watchdog>,"status";
++ random = <&random>,"status";
++ };
+ };
+--- a/arch/arm/boot/dts/bcm2835.dtsi
++++ b/arch/arm/boot/dts/bcm2835.dtsi
+@@ -1,206 +1,39 @@
+-#include <dt-bindings/pinctrl/bcm2835.h>
+-#include <dt-bindings/clock/bcm2835.h>
+-#include "skeleton.dtsi"
++#include "bcm2708_common.dtsi"
+
+ / {
+ compatible = "brcm,bcm2835";
+ model = "BCM2835";
+- interrupt-parent = <&intc>;
+
+ chosen {
+- bootargs = "earlyprintk console=ttyAMA0";
++ bootargs = "";
+ };
+
+ soc {
+- compatible = "simple-bus";
+- #address-cells = <1>;
+- #size-cells = <1>;
+- ranges = <0x7e000000 0x20000000 0x02000000>;
++ ranges = <0x7e000000 0x20000000 0x01000000>;
+ dma-ranges = <0x40000000 0x00000000 0x20000000>;
+
+ timer@7e003000 {
+ compatible = "brcm,bcm2835-system-timer";
+ reg = <0x7e003000 0x1000>;
+ interrupts = <1 0>, <1 1>, <1 2>, <1 3>;
+- /* This could be a reference to BCM2835_CLOCK_TIMER,
+- * but we don't have the driver using the common clock
+- * support yet.
+- */
+ clock-frequency = <1000000>;
+ };
+
+- dma: dma@7e007000 {
+- compatible = "brcm,bcm2835-dma";
+- reg = <0x7e007000 0xf00>;
+- interrupts = <1 16>,
+- <1 17>,
+- <1 18>,
+- <1 19>,
+- <1 20>,
+- <1 21>,
+- <1 22>,
+- <1 23>,
+- <1 24>,
+- <1 25>,
+- <1 26>,
+- <1 27>,
+- <1 28>;
+-
+- #dma-cells = <1>;
+- brcm,dma-channel-mask = <0x7f35>;
+- };
+-
+- intc: interrupt-controller@7e00b200 {
+- compatible = "brcm,bcm2835-armctrl-ic";
+- reg = <0x7e00b200 0x200>;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
+-
+- watchdog@7e100000 {
+- compatible = "brcm,bcm2835-pm-wdt";
+- reg = <0x7e100000 0x28>;
+- };
+-
+- clocks: cprman@7e101000 {
+- compatible = "brcm,bcm2835-cprman";
+- #clock-cells = <1>;
+- reg = <0x7e101000 0x2000>;
+-
+- /* CPRMAN derives everything from the platform's
+- * oscillator.
+- */
+- clocks = <&clk_osc>;
+- };
+-
+- rng@7e104000 {
+- compatible = "brcm,bcm2835-rng";
+- reg = <0x7e104000 0x10>;
+- };
+-
+- mailbox: mailbox@7e00b800 {
+- compatible = "brcm,bcm2835-mbox";
+- reg = <0x7e00b880 0x40>;
+- interrupts = <0 1>;
+- #mbox-cells = <0>;
+- };
+-
+- gpio: gpio@7e200000 {
+- compatible = "brcm,bcm2835-gpio";
+- reg = <0x7e200000 0xb4>;
+- /*
+- * The GPIO IP block is designed for 3 banks of GPIOs.
+- * Each bank has a GPIO interrupt for itself.
+- * There is an overall "any bank" interrupt.
+- * In order, these are GIC interrupts 17, 18, 19, 20.
+- * Since the BCM2835 only has 2 banks, the 2nd bank
+- * interrupt output appears to be mirrored onto the
+- * 3rd bank's interrupt signal.
+- * So, a bank0 interrupt shows up on 17, 20, and
+- * a bank1 interrupt shows up on 18, 19, 20!
+- */
+- interrupts = <2 17>, <2 18>, <2 19>, <2 20>;
+-
+- gpio-controller;
+- #gpio-cells = <2>;
+-
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
+-
+- uart0: uart@7e201000 {
+- compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
+- reg = <0x7e201000 0x1000>;
+- interrupts = <2 25>;
+- clocks = <&clocks BCM2835_CLOCK_UART>,
+- <&clocks BCM2835_CLOCK_VPU>;
+- clock-names = "uartclk", "apb_pclk";
+- arm,primecell-periphid = <0x00241011>;
+- };
+-
+- i2s: i2s@7e203000 {
+- compatible = "brcm,bcm2835-i2s";
+- reg = <0x7e203000 0x24>,
+- <0x7e101098 0x08>;
+-
+- dmas = <&dma 2>,
+- <&dma 3>;
+- dma-names = "tx", "rx";
+- status = "disabled";
+- };
+-
+- spi: spi@7e204000 {
+- compatible = "brcm,bcm2835-spi";
+- reg = <0x7e204000 0x1000>;
+- interrupts = <2 22>;
+- clocks = <&clocks BCM2835_CLOCK_VPU>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- i2c0: i2c@7e205000 {
+- compatible = "brcm,bcm2835-i2c";
+- reg = <0x7e205000 0x1000>;
+- interrupts = <2 21>;
+- clocks = <&clocks BCM2835_CLOCK_VPU>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- sdhci: sdhci@7e300000 {
+- compatible = "brcm,bcm2835-sdhci";
+- reg = <0x7e300000 0x100>;
+- interrupts = <2 30>;
+- clocks = <&clocks BCM2835_CLOCK_EMMC>;
+- status = "disabled";
+- };
+-
+- i2c1: i2c@7e804000 {
+- compatible = "brcm,bcm2835-i2c";
+- reg = <0x7e804000 0x1000>;
+- interrupts = <2 21>;
+- clocks = <&clocks BCM2835_CLOCK_VPU>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- i2c2: i2c@7e805000 {
+- compatible = "brcm,bcm2835-i2c";
+- reg = <0x7e805000 0x1000>;
+- interrupts = <2 21>;
+- clocks = <&clocks BCM2835_CLOCK_VPU>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- usb@7e980000 {
+- compatible = "brcm,bcm2835-usb";
+- reg = <0x7e980000 0x10000>;
+- interrupts = <1 9>;
+- };
+-
+ arm-pmu {
+ compatible = "arm,arm1176-pmu";
+ };
+- };
+
+- clocks {
+- compatible = "simple-bus";
+- #address-cells = <1>;
+- #size-cells = <0>;
+-
+- /* The oscillator is the root of the clock tree. */
+- clk_osc: clock@3 {
+- compatible = "fixed-clock";
+- reg = <3>;
+- #clock-cells = <0>;
+- clock-output-names = "osc";
+- clock-frequency = <19200000>;
++ aux_enable: aux_enable@0x7e215004 {
++ compatible = "bcrm,bcm2835-aux-enable";
++ reg = <0x7e215004 0x04>;
+ };
+-
+ };
+ };
++
++&intc {
++ compatible = "brcm,bcm2835-armctrl-ic";
++};
++
++&watchdog {
++ status = "okay";
++};
diff --git a/target/linux/brcm2708/patches-4.4/0053-bcm2835-Match-with-BCM2708-Device-Trees.patch b/target/linux/brcm2708/patches-4.4/0053-bcm2835-Match-with-BCM2708-Device-Trees.patch
deleted file mode 100644
index 23654791a8..0000000000
--- a/target/linux/brcm2708/patches-4.4/0053-bcm2835-Match-with-BCM2708-Device-Trees.patch
+++ /dev/null
@@ -1,515 +0,0 @@
-From 23eabf2220f0f748df3e88a35e55a82c53242b4a Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
-Date: Sat, 15 Aug 2015 20:47:07 +0200
-Subject: [PATCH 053/170] bcm2835: Match with BCM2708 Device Trees
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
----
- arch/arm/boot/dts/bcm2835-rpi-b-plus.dts | 132 ++++++++++++++++++---
- arch/arm/boot/dts/bcm2835-rpi-b.dts | 115 ++++++++++++++++--
- arch/arm/boot/dts/bcm2835.dtsi | 195 +++----------------------------
- 3 files changed, 237 insertions(+), 205 deletions(-)
-
---- a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
-+++ b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
-@@ -1,30 +1,128 @@
- /dts-v1/;
--#include "bcm2835-rpi.dtsi"
-+#include "bcm2835.dtsi"
-
- / {
- compatible = "raspberrypi,model-b-plus", "brcm,bcm2835";
- model = "Raspberry Pi Model B+";
--
-- leds {
-- act {
-- gpios = <&gpio 47 0>;
-- };
--
-- pwr {
-- label = "PWR";
-- gpios = <&gpio 35 0>;
-- default-state = "keep";
-- linux,default-trigger = "default-on";
-- };
-- };
- };
-
- &gpio {
-- pinctrl-0 = <&gpioout &alt0 &i2s_alt0 &alt3>;
-+ spi0_pins: spi0_pins {
-+ brcm,pins = <7 8 9 10 11>;
-+ brcm,function = <4>; /* alt0 */
-+ };
-+
-+ i2c0_pins: i2c0 {
-+ brcm,pins = <0 1>;
-+ brcm,function = <4>;
-+ };
-
-- /* I2S interface */
-- i2s_alt0: i2s_alt0 {
-+ i2c1_pins: i2c1 {
-+ brcm,pins = <2 3>;
-+ brcm,function = <4>;
-+ };
-+
-+ i2s_pins: i2s {
- brcm,pins = <18 19 20 21>;
-- brcm,function = <BCM2835_FSEL_ALT0>;
-+ brcm,function = <4>; /* alt0 */
-+ };
-+};
-+
-+&mmc {
-+ status = "okay";
-+ bus-width = <4>;
-+};
-+
-+&fb {
-+ status = "okay";
-+};
-+
-+&uart0 {
-+ status = "okay";
-+};
-+
-+&spi0 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&spi0_pins>;
-+
-+ spidev@0{
-+ compatible = "spidev";
-+ reg = <0>; /* CE0 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <500000>;
-+ };
-+
-+ spidev@1{
-+ compatible = "spidev";
-+ reg = <1>; /* CE1 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <500000>;
-+ };
-+};
-+
-+&i2c0 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c0_pins>;
-+ clock-frequency = <100000>;
-+};
-+
-+&i2c1 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c1_pins>;
-+ clock-frequency = <100000>;
-+};
-+
-+&i2c2 {
-+ clock-frequency = <100000>;
-+};
-+
-+&i2s {
-+ #sound-dai-cells = <0>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2s_pins>;
-+};
-+
-+&leds {
-+ act_led: act {
-+ label = "led0";
-+ linux,default-trigger = "mmc0";
-+ gpios = <&gpio 47 0>;
-+ };
-+
-+ pwr_led: pwr {
-+ label = "led1";
-+ linux,default-trigger = "input";
-+ gpios = <&gpio 35 0>;
-+ };
-+};
-+
-+/ {
-+ __overrides__ {
-+ uart0 = <&uart0>,"status";
-+ uart0_clkrate = <&clk_uart0>,"clock-frequency:0";
-+ uart1_clkrate = <&uart1>,"clock-frequency:0";
-+ i2s = <&i2s>,"status";
-+ spi = <&spi0>,"status";
-+ i2c0 = <&i2c0>,"status";
-+ i2c1 = <&i2c1>,"status";
-+ i2c2_iknowwhatimdoing = <&i2c2>,"status";
-+ i2c0_baudrate = <&i2c0>,"clock-frequency:0";
-+ i2c1_baudrate = <&i2c1>,"clock-frequency:0";
-+ i2c2_baudrate = <&i2c2>,"clock-frequency:0";
-+ core_freq = <&clk_core>,"clock-frequency:0";
-+
-+ act_led_gpio = <&act_led>,"gpios:4";
-+ act_led_activelow = <&act_led>,"gpios:8";
-+ act_led_trigger = <&act_led>,"linux,default-trigger";
-+
-+ pwr_led_gpio = <&pwr_led>,"gpios:4";
-+ pwr_led_activelow = <&pwr_led>,"gpios:8";
-+ pwr_led_trigger = <&pwr_led>,"linux,default-trigger";
-+
-+ audio = <&audio>,"status";
-+ watchdog = <&watchdog>,"status";
-+ random = <&random>,"status";
- };
- };
---- a/arch/arm/boot/dts/bcm2835-rpi-b.dts
-+++ b/arch/arm/boot/dts/bcm2835-rpi-b.dts
-@@ -1,17 +1,118 @@
- /dts-v1/;
--#include "bcm2835-rpi.dtsi"
-+#include "bcm2835.dtsi"
-
- / {
- compatible = "raspberrypi,model-b", "brcm,bcm2835";
- model = "Raspberry Pi Model B";
-+};
-
-- leds {
-- act {
-- gpios = <&gpio 16 1>;
-- };
-+&gpio {
-+ spi0_pins: spi0_pins {
-+ brcm,pins = <7 8 9 10 11>;
-+ brcm,function = <4>; /* alt0 */
-+ };
-+
-+ i2c0_pins: i2c0 {
-+ brcm,pins = <0 1>;
-+ brcm,function = <4>;
-+ };
-+
-+ i2c1_pins: i2c1 {
-+ brcm,pins = <2 3>;
-+ brcm,function = <4>;
-+ };
-+
-+ i2s_pins: i2s {
-+ brcm,pins = <28 29 30 31>;
-+ brcm,function = <6>; /* alt2 */
- };
- };
-
--&gpio {
-- pinctrl-0 = <&gpioout &alt0 &alt3>;
-+&mmc {
-+ status = "okay";
-+ bus-width = <4>;
-+};
-+
-+&fb {
-+ status = "okay";
-+};
-+
-+&uart0 {
-+ status = "okay";
-+};
-+
-+&spi0 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&spi0_pins>;
-+
-+ spidev@0{
-+ compatible = "spidev";
-+ reg = <0>; /* CE0 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <500000>;
-+ };
-+
-+ spidev@1{
-+ compatible = "spidev";
-+ reg = <1>; /* CE1 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <500000>;
-+ };
-+};
-+
-+&i2c0 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c0_pins>;
-+ clock-frequency = <100000>;
-+};
-+
-+&i2c1 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c1_pins>;
-+ clock-frequency = <100000>;
-+};
-+
-+&i2c2 {
-+ clock-frequency = <100000>;
-+};
-+
-+&i2s {
-+ #sound-dai-cells = <0>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2s_pins>;
-+};
-+
-+&leds {
-+ act_led: act {
-+ label = "led0";
-+ linux,default-trigger = "mmc0";
-+ gpios = <&gpio 16 1>;
-+ };
-+};
-+
-+/ {
-+ __overrides__ {
-+ uart0 = <&uart0>,"status";
-+ uart0_clkrate = <&clk_uart0>,"clock-frequency:0";
-+ uart1_clkrate = <&uart1>,"clock-frequency:0";
-+ i2s = <&i2s>,"status";
-+ spi = <&spi0>,"status";
-+ i2c0 = <&i2c0>,"status";
-+ i2c1 = <&i2c1>,"status";
-+ i2c2_iknowwhatimdoing = <&i2c2>,"status";
-+ i2c0_baudrate = <&i2c0>,"clock-frequency:0";
-+ i2c1_baudrate = <&i2c1>,"clock-frequency:0";
-+ i2c2_baudrate = <&i2c2>,"clock-frequency:0";
-+ core_freq = <&clk_core>,"clock-frequency:0";
-+
-+ act_led_gpio = <&act_led>,"gpios:4";
-+ act_led_activelow = <&act_led>,"gpios:8";
-+ act_led_trigger = <&act_led>,"linux,default-trigger";
-+
-+ audio = <&audio>,"status";
-+ watchdog = <&watchdog>,"status";
-+ random = <&random>,"status";
-+ };
- };
---- a/arch/arm/boot/dts/bcm2835.dtsi
-+++ b/arch/arm/boot/dts/bcm2835.dtsi
-@@ -1,206 +1,39 @@
--#include <dt-bindings/pinctrl/bcm2835.h>
--#include <dt-bindings/clock/bcm2835.h>
--#include "skeleton.dtsi"
-+#include "bcm2708_common.dtsi"
-
- / {
- compatible = "brcm,bcm2835";
- model = "BCM2835";
-- interrupt-parent = <&intc>;
-
- chosen {
-- bootargs = "earlyprintk console=ttyAMA0";
-+ bootargs = "";
- };
-
- soc {
-- compatible = "simple-bus";
-- #address-cells = <1>;
-- #size-cells = <1>;
-- ranges = <0x7e000000 0x20000000 0x02000000>;
-+ ranges = <0x7e000000 0x20000000 0x01000000>;
- dma-ranges = <0x40000000 0x00000000 0x20000000>;
-
- timer@7e003000 {
- compatible = "brcm,bcm2835-system-timer";
- reg = <0x7e003000 0x1000>;
- interrupts = <1 0>, <1 1>, <1 2>, <1 3>;
-- /* This could be a reference to BCM2835_CLOCK_TIMER,
-- * but we don't have the driver using the common clock
-- * support yet.
-- */
- clock-frequency = <1000000>;
- };
-
-- dma: dma@7e007000 {
-- compatible = "brcm,bcm2835-dma";
-- reg = <0x7e007000 0xf00>;
-- interrupts = <1 16>,
-- <1 17>,
-- <1 18>,
-- <1 19>,
-- <1 20>,
-- <1 21>,
-- <1 22>,
-- <1 23>,
-- <1 24>,
-- <1 25>,
-- <1 26>,
-- <1 27>,
-- <1 28>;
--
-- #dma-cells = <1>;
-- brcm,dma-channel-mask = <0x7f35>;
-- };
--
-- intc: interrupt-controller@7e00b200 {
-- compatible = "brcm,bcm2835-armctrl-ic";
-- reg = <0x7e00b200 0x200>;
-- interrupt-controller;
-- #interrupt-cells = <2>;
-- };
--
-- watchdog@7e100000 {
-- compatible = "brcm,bcm2835-pm-wdt";
-- reg = <0x7e100000 0x28>;
-- };
--
-- clocks: cprman@7e101000 {
-- compatible = "brcm,bcm2835-cprman";
-- #clock-cells = <1>;
-- reg = <0x7e101000 0x2000>;
--
-- /* CPRMAN derives everything from the platform's
-- * oscillator.
-- */
-- clocks = <&clk_osc>;
-- };
--
-- rng@7e104000 {
-- compatible = "brcm,bcm2835-rng";
-- reg = <0x7e104000 0x10>;
-- };
--
-- mailbox: mailbox@7e00b800 {
-- compatible = "brcm,bcm2835-mbox";
-- reg = <0x7e00b880 0x40>;
-- interrupts = <0 1>;
-- #mbox-cells = <0>;
-- };
--
-- gpio: gpio@7e200000 {
-- compatible = "brcm,bcm2835-gpio";
-- reg = <0x7e200000 0xb4>;
-- /*
-- * The GPIO IP block is designed for 3 banks of GPIOs.
-- * Each bank has a GPIO interrupt for itself.
-- * There is an overall "any bank" interrupt.
-- * In order, these are GIC interrupts 17, 18, 19, 20.
-- * Since the BCM2835 only has 2 banks, the 2nd bank
-- * interrupt output appears to be mirrored onto the
-- * 3rd bank's interrupt signal.
-- * So, a bank0 interrupt shows up on 17, 20, and
-- * a bank1 interrupt shows up on 18, 19, 20!
-- */
-- interrupts = <2 17>, <2 18>, <2 19>, <2 20>;
--
-- gpio-controller;
-- #gpio-cells = <2>;
--
-- interrupt-controller;
-- #interrupt-cells = <2>;
-- };
--
-- uart0: uart@7e201000 {
-- compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
-- reg = <0x7e201000 0x1000>;
-- interrupts = <2 25>;
-- clocks = <&clocks BCM2835_CLOCK_UART>,
-- <&clocks BCM2835_CLOCK_VPU>;
-- clock-names = "uartclk", "apb_pclk";
-- arm,primecell-periphid = <0x00241011>;
-- };
--
-- i2s: i2s@7e203000 {
-- compatible = "brcm,bcm2835-i2s";
-- reg = <0x7e203000 0x24>,
-- <0x7e101098 0x08>;
--
-- dmas = <&dma 2>,
-- <&dma 3>;
-- dma-names = "tx", "rx";
-- status = "disabled";
-- };
--
-- spi: spi@7e204000 {
-- compatible = "brcm,bcm2835-spi";
-- reg = <0x7e204000 0x1000>;
-- interrupts = <2 22>;
-- clocks = <&clocks BCM2835_CLOCK_VPU>;
-- #address-cells = <1>;
-- #size-cells = <0>;
-- status = "disabled";
-- };
--
-- i2c0: i2c@7e205000 {
-- compatible = "brcm,bcm2835-i2c";
-- reg = <0x7e205000 0x1000>;
-- interrupts = <2 21>;
-- clocks = <&clocks BCM2835_CLOCK_VPU>;
-- #address-cells = <1>;
-- #size-cells = <0>;
-- status = "disabled";
-- };
--
-- sdhci: sdhci@7e300000 {
-- compatible = "brcm,bcm2835-sdhci";
-- reg = <0x7e300000 0x100>;
-- interrupts = <2 30>;
-- clocks = <&clocks BCM2835_CLOCK_EMMC>;
-- status = "disabled";
-- };
--
-- i2c1: i2c@7e804000 {
-- compatible = "brcm,bcm2835-i2c";
-- reg = <0x7e804000 0x1000>;
-- interrupts = <2 21>;
-- clocks = <&clocks BCM2835_CLOCK_VPU>;
-- #address-cells = <1>;
-- #size-cells = <0>;
-- status = "disabled";
-- };
--
-- i2c2: i2c@7e805000 {
-- compatible = "brcm,bcm2835-i2c";
-- reg = <0x7e805000 0x1000>;
-- interrupts = <2 21>;
-- clocks = <&clocks BCM2835_CLOCK_VPU>;
-- #address-cells = <1>;
-- #size-cells = <0>;
-- status = "disabled";
-- };
--
-- usb@7e980000 {
-- compatible = "brcm,bcm2835-usb";
-- reg = <0x7e980000 0x10000>;
-- interrupts = <1 9>;
-- };
--
- arm-pmu {
- compatible = "arm,arm1176-pmu";
- };
-- };
-
-- clocks {
-- compatible = "simple-bus";
-- #address-cells = <1>;
-- #size-cells = <0>;
--
-- /* The oscillator is the root of the clock tree. */
-- clk_osc: clock@3 {
-- compatible = "fixed-clock";
-- reg = <3>;
-- #clock-cells = <0>;
-- clock-output-names = "osc";
-- clock-frequency = <19200000>;
-+ aux_enable: aux_enable@0x7e215004 {
-+ compatible = "bcrm,bcm2835-aux-enable";
-+ reg = <0x7e215004 0x04>;
- };
--
- };
- };
-+
-+&intc {
-+ compatible = "brcm,bcm2835-armctrl-ic";
-+};
-+
-+&watchdog {
-+ status = "okay";
-+};
diff --git a/target/linux/brcm2708/patches-4.4/0053-fbdev-add-FBIOCOPYAREA-ioctl.patch b/target/linux/brcm2708/patches-4.4/0053-fbdev-add-FBIOCOPYAREA-ioctl.patch
new file mode 100644
index 0000000000..5cde4b8c95
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0053-fbdev-add-FBIOCOPYAREA-ioctl.patch
@@ -0,0 +1,91 @@
+From 6f58dcfd94cdd56fb1d462f93397a8548d0340c7 Mon Sep 17 00:00:00 2001
+From: Siarhei Siamashka <siarhei.siamashka@gmail.com>
+Date: Mon, 17 Jun 2013 13:32:11 +0300
+Subject: [PATCH 053/381] fbdev: add FBIOCOPYAREA ioctl
+
+Based on the patch authored by Ali Gholami Rudi at
+ https://lkml.org/lkml/2009/7/13/153
+
+Provide an ioctl for userspace applications, but only if this operation
+is hardware accelerated (otherwide it does not make any sense).
+
+Signed-off-by: Siarhei Siamashka <siarhei.siamashka@gmail.com>
+---
+ drivers/video/fbdev/core/fbmem.c | 30 ++++++++++++++++++++++++++++++
+ include/uapi/linux/fb.h | 5 +++++
+ 2 files changed, 35 insertions(+)
+
+--- a/drivers/video/fbdev/core/fbmem.c
++++ b/drivers/video/fbdev/core/fbmem.c
+@@ -1084,6 +1084,25 @@ fb_blank(struct fb_info *info, int blank
+ }
+ EXPORT_SYMBOL(fb_blank);
+
++static int fb_copyarea_user(struct fb_info *info,
++ struct fb_copyarea *copy)
++{
++ int ret = 0;
++ if (!lock_fb_info(info))
++ return -ENODEV;
++ if (copy->dx + copy->width > info->var.xres ||
++ copy->sx + copy->width > info->var.xres ||
++ copy->dy + copy->height > info->var.yres ||
++ copy->sy + copy->height > info->var.yres) {
++ ret = -EINVAL;
++ goto out;
++ }
++ info->fbops->fb_copyarea(info, copy);
++out:
++ unlock_fb_info(info);
++ return ret;
++}
++
+ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
+ {
+@@ -1094,6 +1113,7 @@ static long do_fb_ioctl(struct fb_info *
+ struct fb_cmap cmap_from;
+ struct fb_cmap_user cmap;
+ struct fb_event event;
++ struct fb_copyarea copy;
+ void __user *argp = (void __user *)arg;
+ long ret = 0;
+
+@@ -1211,6 +1231,15 @@ static long do_fb_ioctl(struct fb_info *
+ unlock_fb_info(info);
+ console_unlock();
+ break;
++ case FBIOCOPYAREA:
++ if (info->flags & FBINFO_HWACCEL_COPYAREA) {
++ /* only provide this ioctl if it is accelerated */
++ if (copy_from_user(&copy, argp, sizeof(copy)))
++ return -EFAULT;
++ ret = fb_copyarea_user(info, &copy);
++ break;
++ }
++ /* fall through */
+ default:
+ if (!lock_fb_info(info))
+ return -ENODEV;
+@@ -1365,6 +1394,7 @@ static long fb_compat_ioctl(struct file
+ case FBIOPAN_DISPLAY:
+ case FBIOGET_CON2FBMAP:
+ case FBIOPUT_CON2FBMAP:
++ case FBIOCOPYAREA:
+ arg = (unsigned long) compat_ptr(arg);
+ case FBIOBLANK:
+ ret = do_fb_ioctl(info, cmd, arg);
+--- a/include/uapi/linux/fb.h
++++ b/include/uapi/linux/fb.h
+@@ -34,6 +34,11 @@
+ #define FBIOPUT_MODEINFO 0x4617
+ #define FBIOGET_DISPINFO 0x4618
+ #define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
++/*
++ * HACK: use 'z' in order not to clash with any other ioctl numbers which might
++ * be concurrently added to the mainline kernel
++ */
++#define FBIOCOPYAREA _IOW('z', 0x21, struct fb_copyarea)
+
+ #define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */
+ #define FB_TYPE_PLANES 1 /* Non interleaved planes */
diff --git a/target/linux/brcm2708/patches-4.4/0054-fbdev-add-FBIOCOPYAREA-ioctl.patch b/target/linux/brcm2708/patches-4.4/0054-fbdev-add-FBIOCOPYAREA-ioctl.patch
deleted file mode 100644
index f4808874fb..0000000000
--- a/target/linux/brcm2708/patches-4.4/0054-fbdev-add-FBIOCOPYAREA-ioctl.patch
+++ /dev/null
@@ -1,91 +0,0 @@
-From f978fb3b816681159b6cc97104954dea31488add Mon Sep 17 00:00:00 2001
-From: Siarhei Siamashka <siarhei.siamashka@gmail.com>
-Date: Mon, 17 Jun 2013 13:32:11 +0300
-Subject: [PATCH 054/170] fbdev: add FBIOCOPYAREA ioctl
-
-Based on the patch authored by Ali Gholami Rudi at
- https://lkml.org/lkml/2009/7/13/153
-
-Provide an ioctl for userspace applications, but only if this operation
-is hardware accelerated (otherwide it does not make any sense).
-
-Signed-off-by: Siarhei Siamashka <siarhei.siamashka@gmail.com>
----
- drivers/video/fbdev/core/fbmem.c | 30 ++++++++++++++++++++++++++++++
- include/uapi/linux/fb.h | 5 +++++
- 2 files changed, 35 insertions(+)
-
---- a/drivers/video/fbdev/core/fbmem.c
-+++ b/drivers/video/fbdev/core/fbmem.c
-@@ -1084,6 +1084,25 @@ fb_blank(struct fb_info *info, int blank
- }
- EXPORT_SYMBOL(fb_blank);
-
-+static int fb_copyarea_user(struct fb_info *info,
-+ struct fb_copyarea *copy)
-+{
-+ int ret = 0;
-+ if (!lock_fb_info(info))
-+ return -ENODEV;
-+ if (copy->dx + copy->width > info->var.xres ||
-+ copy->sx + copy->width > info->var.xres ||
-+ copy->dy + copy->height > info->var.yres ||
-+ copy->sy + copy->height > info->var.yres) {
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+ info->fbops->fb_copyarea(info, copy);
-+out:
-+ unlock_fb_info(info);
-+ return ret;
-+}
-+
- static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
- unsigned long arg)
- {
-@@ -1094,6 +1113,7 @@ static long do_fb_ioctl(struct fb_info *
- struct fb_cmap cmap_from;
- struct fb_cmap_user cmap;
- struct fb_event event;
-+ struct fb_copyarea copy;
- void __user *argp = (void __user *)arg;
- long ret = 0;
-
-@@ -1211,6 +1231,15 @@ static long do_fb_ioctl(struct fb_info *
- unlock_fb_info(info);
- console_unlock();
- break;
-+ case FBIOCOPYAREA:
-+ if (info->flags & FBINFO_HWACCEL_COPYAREA) {
-+ /* only provide this ioctl if it is accelerated */
-+ if (copy_from_user(&copy, argp, sizeof(copy)))
-+ return -EFAULT;
-+ ret = fb_copyarea_user(info, &copy);
-+ break;
-+ }
-+ /* fall through */
- default:
- if (!lock_fb_info(info))
- return -ENODEV;
-@@ -1365,6 +1394,7 @@ static long fb_compat_ioctl(struct file
- case FBIOPAN_DISPLAY:
- case FBIOGET_CON2FBMAP:
- case FBIOPUT_CON2FBMAP:
-+ case FBIOCOPYAREA:
- arg = (unsigned long) compat_ptr(arg);
- case FBIOBLANK:
- ret = do_fb_ioctl(info, cmd, arg);
---- a/include/uapi/linux/fb.h
-+++ b/include/uapi/linux/fb.h
-@@ -34,6 +34,11 @@
- #define FBIOPUT_MODEINFO 0x4617
- #define FBIOGET_DISPINFO 0x4618
- #define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
-+/*
-+ * HACK: use 'z' in order not to clash with any other ioctl numbers which might
-+ * be concurrently added to the mainline kernel
-+ */
-+#define FBIOCOPYAREA _IOW('z', 0x21, struct fb_copyarea)
-
- #define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */
- #define FB_TYPE_PLANES 1 /* Non interleaved planes */
diff --git a/target/linux/brcm2708/patches-4.4/0057-Speed-up-console-framebuffer-imageblit-function.patch b/target/linux/brcm2708/patches-4.4/0057-Speed-up-console-framebuffer-imageblit-function.patch
new file mode 100644
index 0000000000..7254cffd0a
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0057-Speed-up-console-framebuffer-imageblit-function.patch
@@ -0,0 +1,209 @@
+From 634d2880e22cb1f77250db07b0c60e3f1280f645 Mon Sep 17 00:00:00 2001
+From: Harm Hanemaaijer <fgenfb@yahoo.com>
+Date: Thu, 20 Jun 2013 20:21:39 +0200
+Subject: [PATCH 057/381] Speed up console framebuffer imageblit function
+
+Especially on platforms with a slower CPU but a relatively high
+framebuffer fill bandwidth, like current ARM devices, the existing
+console monochrome imageblit function used to draw console text is
+suboptimal for common pixel depths such as 16bpp and 32bpp. The existing
+code is quite general and can deal with several pixel depths. By creating
+special case functions for 16bpp and 32bpp, by far the most common pixel
+formats used on modern systems, a significant speed-up is attained
+which can be readily felt on ARM-based devices like the Raspberry Pi
+and the Allwinner platform, but should help any platform using the
+fb layer.
+
+The special case functions allow constant folding, eliminating a number
+of instructions including divide operations, and allow the use of an
+unrolled loop, eliminating instructions with a variable shift size,
+reducing source memory access instructions, and eliminating excessive
+branching. These unrolled loops also allow much better code optimization
+by the C compiler. The code that selects which optimized variant is used
+is also simplified, eliminating integer divide instructions.
+
+The speed-up, measured by timing 'cat file.txt' in the console, varies
+between 40% and 70%, when testing on the Raspberry Pi and Allwinner
+ARM-based platforms, depending on font size and the pixel depth, with
+the greater benefit for 32bpp.
+
+Signed-off-by: Harm Hanemaaijer <fgenfb@yahoo.com>
+---
+ drivers/video/fbdev/core/cfbimgblt.c | 152 +++++++++++++++++++++++++++++++++--
+ 1 file changed, 147 insertions(+), 5 deletions(-)
+
+--- a/drivers/video/fbdev/core/cfbimgblt.c
++++ b/drivers/video/fbdev/core/cfbimgblt.c
+@@ -28,6 +28,11 @@
+ *
+ * Also need to add code to deal with cards endians that are different than
+ * the native cpu endians. I also need to deal with MSB position in the word.
++ * Modified by Harm Hanemaaijer (fgenfb@yahoo.com) 2013:
++ * - Provide optimized versions of fast_imageblit for 16 and 32bpp that are
++ * significantly faster than the previous implementation.
++ * - Simplify the fast/slow_imageblit selection code, avoiding integer
++ * divides.
+ */
+ #include <linux/module.h>
+ #include <linux/string.h>
+@@ -262,6 +267,133 @@ static inline void fast_imageblit(const
+ }
+ }
+
++/*
++ * Optimized fast_imageblit for bpp == 16. ppw = 2, bit_mask = 3 folded
++ * into the code, main loop unrolled.
++ */
++
++static inline void fast_imageblit16(const struct fb_image *image,
++ struct fb_info *p, u8 __iomem * dst1,
++ u32 fgcolor, u32 bgcolor)
++{
++ u32 fgx = fgcolor, bgx = bgcolor;
++ u32 spitch = (image->width + 7) / 8;
++ u32 end_mask, eorx;
++ const char *s = image->data, *src;
++ u32 __iomem *dst;
++ const u32 *tab = NULL;
++ int i, j, k;
++
++ tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le;
++
++ fgx <<= 16;
++ bgx <<= 16;
++ fgx |= fgcolor;
++ bgx |= bgcolor;
++
++ eorx = fgx ^ bgx;
++ k = image->width / 2;
++
++ for (i = image->height; i--;) {
++ dst = (u32 __iomem *) dst1;
++ src = s;
++
++ j = k;
++ while (j >= 4) {
++ u8 bits = *src;
++ end_mask = tab[(bits >> 6) & 3];
++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
++ end_mask = tab[(bits >> 4) & 3];
++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
++ end_mask = tab[(bits >> 2) & 3];
++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
++ end_mask = tab[bits & 3];
++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
++ src++;
++ j -= 4;
++ }
++ if (j != 0) {
++ u8 bits = *src;
++ end_mask = tab[(bits >> 6) & 3];
++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
++ if (j >= 2) {
++ end_mask = tab[(bits >> 4) & 3];
++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
++ if (j == 3) {
++ end_mask = tab[(bits >> 2) & 3];
++ FB_WRITEL((end_mask & eorx) ^ bgx, dst);
++ }
++ }
++ }
++ dst1 += p->fix.line_length;
++ s += spitch;
++ }
++}
++
++/*
++ * Optimized fast_imageblit for bpp == 32. ppw = 1, bit_mask = 1 folded
++ * into the code, main loop unrolled.
++ */
++
++static inline void fast_imageblit32(const struct fb_image *image,
++ struct fb_info *p, u8 __iomem * dst1,
++ u32 fgcolor, u32 bgcolor)
++{
++ u32 fgx = fgcolor, bgx = bgcolor;
++ u32 spitch = (image->width + 7) / 8;
++ u32 end_mask, eorx;
++ const char *s = image->data, *src;
++ u32 __iomem *dst;
++ const u32 *tab = NULL;
++ int i, j, k;
++
++ tab = cfb_tab32;
++
++ eorx = fgx ^ bgx;
++ k = image->width;
++
++ for (i = image->height; i--;) {
++ dst = (u32 __iomem *) dst1;
++ src = s;
++
++ j = k;
++ while (j >= 8) {
++ u8 bits = *src;
++ end_mask = tab[(bits >> 7) & 1];
++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
++ end_mask = tab[(bits >> 6) & 1];
++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
++ end_mask = tab[(bits >> 5) & 1];
++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
++ end_mask = tab[(bits >> 4) & 1];
++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
++ end_mask = tab[(bits >> 3) & 1];
++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
++ end_mask = tab[(bits >> 2) & 1];
++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
++ end_mask = tab[(bits >> 1) & 1];
++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
++ end_mask = tab[bits & 1];
++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
++ src++;
++ j -= 8;
++ }
++ if (j != 0) {
++ u32 bits = (u32) * src;
++ while (j > 1) {
++ end_mask = tab[(bits >> 7) & 1];
++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
++ bits <<= 1;
++ j--;
++ }
++ end_mask = tab[(bits >> 7) & 1];
++ FB_WRITEL((end_mask & eorx) ^ bgx, dst);
++ }
++ dst1 += p->fix.line_length;
++ s += spitch;
++ }
++}
++
+ void cfb_imageblit(struct fb_info *p, const struct fb_image *image)
+ {
+ u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0;
+@@ -294,11 +426,21 @@ void cfb_imageblit(struct fb_info *p, co
+ bgcolor = image->bg_color;
+ }
+
+- if (32 % bpp == 0 && !start_index && !pitch_index &&
+- ((width & (32/bpp-1)) == 0) &&
+- bpp >= 8 && bpp <= 32)
+- fast_imageblit(image, p, dst1, fgcolor, bgcolor);
+- else
++ if (!start_index && !pitch_index) {
++ if (bpp == 32)
++ fast_imageblit32(image, p, dst1, fgcolor,
++ bgcolor);
++ else if (bpp == 16 && (width & 1) == 0)
++ fast_imageblit16(image, p, dst1, fgcolor,
++ bgcolor);
++ else if (bpp == 8 && (width & 3) == 0)
++ fast_imageblit(image, p, dst1, fgcolor,
++ bgcolor);
++ else
++ slow_imageblit(image, p, dst1, fgcolor,
++ bgcolor,
++ start_index, pitch_index);
++ } else
+ slow_imageblit(image, p, dst1, fgcolor, bgcolor,
+ start_index, pitch_index);
+ } else
diff --git a/target/linux/brcm2708/patches-4.4/0058-Allow-mac-address-to-be-set-in-smsc95xx.patch b/target/linux/brcm2708/patches-4.4/0058-Allow-mac-address-to-be-set-in-smsc95xx.patch
new file mode 100644
index 0000000000..b89eafad2b
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0058-Allow-mac-address-to-be-set-in-smsc95xx.patch
@@ -0,0 +1,91 @@
+From 775d5392d5ba612dc856f05fef318b3fd0687f81 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Tue, 26 Mar 2013 17:26:38 +0000
+Subject: [PATCH 058/381] Allow mac address to be set in smsc95xx
+
+Signed-off-by: popcornmix <popcornmix@gmail.com>
+---
+ drivers/net/usb/smsc95xx.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 56 insertions(+)
+
+--- a/drivers/net/usb/smsc95xx.c
++++ b/drivers/net/usb/smsc95xx.c
+@@ -59,6 +59,7 @@
+ #define SUSPEND_SUSPEND3 (0x08)
+ #define SUSPEND_ALLMODES (SUSPEND_SUSPEND0 | SUSPEND_SUSPEND1 | \
+ SUSPEND_SUSPEND2 | SUSPEND_SUSPEND3)
++#define MAC_ADDR_LEN (6)
+
+ struct smsc95xx_priv {
+ u32 mac_cr;
+@@ -74,6 +75,10 @@ static bool turbo_mode = false;
+ module_param(turbo_mode, bool, 0644);
+ MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
+
++static char *macaddr = ":";
++module_param(macaddr, charp, 0);
++MODULE_PARM_DESC(macaddr, "MAC address");
++
+ static int __must_check __smsc95xx_read_reg(struct usbnet *dev, u32 index,
+ u32 *data, int in_pm)
+ {
+@@ -763,8 +768,59 @@ static int smsc95xx_ioctl(struct net_dev
+ return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
+ }
+
++/* Check the macaddr module parameter for a MAC address */
++static int smsc95xx_is_macaddr_param(struct usbnet *dev, u8 *dev_mac)
++{
++ int i, j, got_num, num;
++ u8 mtbl[MAC_ADDR_LEN];
++
++ if (macaddr[0] == ':')
++ return 0;
++
++ i = 0;
++ j = 0;
++ num = 0;
++ got_num = 0;
++ while (j < MAC_ADDR_LEN) {
++ if (macaddr[i] && macaddr[i] != ':') {
++ got_num++;
++ if ('0' <= macaddr[i] && macaddr[i] <= '9')
++ num = num * 16 + macaddr[i] - '0';
++ else if ('A' <= macaddr[i] && macaddr[i] <= 'F')
++ num = num * 16 + 10 + macaddr[i] - 'A';
++ else if ('a' <= macaddr[i] && macaddr[i] <= 'f')
++ num = num * 16 + 10 + macaddr[i] - 'a';
++ else
++ break;
++ i++;
++ } else if (got_num == 2) {
++ mtbl[j++] = (u8) num;
++ num = 0;
++ got_num = 0;
++ i++;
++ } else {
++ break;
++ }
++ }
++
++ if (j == MAC_ADDR_LEN) {
++ netif_dbg(dev, ifup, dev->net, "Overriding MAC address with: "
++ "%02x:%02x:%02x:%02x:%02x:%02x\n", mtbl[0], mtbl[1], mtbl[2],
++ mtbl[3], mtbl[4], mtbl[5]);
++ for (i = 0; i < MAC_ADDR_LEN; i++)
++ dev_mac[i] = mtbl[i];
++ return 1;
++ } else {
++ return 0;
++ }
++}
++
+ static void smsc95xx_init_mac_address(struct usbnet *dev)
+ {
++ /* Check module parameters */
++ if (smsc95xx_is_macaddr_param(dev, dev->net->dev_addr))
++ return;
++
+ /* try reading mac address from EEPROM */
+ if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN,
+ dev->net->dev_addr) == 0) {
diff --git a/target/linux/brcm2708/patches-4.4/0058-Speed-up-console-framebuffer-imageblit-function.patch b/target/linux/brcm2708/patches-4.4/0058-Speed-up-console-framebuffer-imageblit-function.patch
deleted file mode 100644
index 5d5a561a06..0000000000
--- a/target/linux/brcm2708/patches-4.4/0058-Speed-up-console-framebuffer-imageblit-function.patch
+++ /dev/null
@@ -1,209 +0,0 @@
-From 53bcd6e5a43a353508c7aff48abcdcaae1b35ca8 Mon Sep 17 00:00:00 2001
-From: Harm Hanemaaijer <fgenfb@yahoo.com>
-Date: Thu, 20 Jun 2013 20:21:39 +0200
-Subject: [PATCH 058/170] Speed up console framebuffer imageblit function
-
-Especially on platforms with a slower CPU but a relatively high
-framebuffer fill bandwidth, like current ARM devices, the existing
-console monochrome imageblit function used to draw console text is
-suboptimal for common pixel depths such as 16bpp and 32bpp. The existing
-code is quite general and can deal with several pixel depths. By creating
-special case functions for 16bpp and 32bpp, by far the most common pixel
-formats used on modern systems, a significant speed-up is attained
-which can be readily felt on ARM-based devices like the Raspberry Pi
-and the Allwinner platform, but should help any platform using the
-fb layer.
-
-The special case functions allow constant folding, eliminating a number
-of instructions including divide operations, and allow the use of an
-unrolled loop, eliminating instructions with a variable shift size,
-reducing source memory access instructions, and eliminating excessive
-branching. These unrolled loops also allow much better code optimization
-by the C compiler. The code that selects which optimized variant is used
-is also simplified, eliminating integer divide instructions.
-
-The speed-up, measured by timing 'cat file.txt' in the console, varies
-between 40% and 70%, when testing on the Raspberry Pi and Allwinner
-ARM-based platforms, depending on font size and the pixel depth, with
-the greater benefit for 32bpp.
-
-Signed-off-by: Harm Hanemaaijer <fgenfb@yahoo.com>
----
- drivers/video/fbdev/core/cfbimgblt.c | 152 +++++++++++++++++++++++++++++++++--
- 1 file changed, 147 insertions(+), 5 deletions(-)
-
---- a/drivers/video/fbdev/core/cfbimgblt.c
-+++ b/drivers/video/fbdev/core/cfbimgblt.c
-@@ -28,6 +28,11 @@
- *
- * Also need to add code to deal with cards endians that are different than
- * the native cpu endians. I also need to deal with MSB position in the word.
-+ * Modified by Harm Hanemaaijer (fgenfb@yahoo.com) 2013:
-+ * - Provide optimized versions of fast_imageblit for 16 and 32bpp that are
-+ * significantly faster than the previous implementation.
-+ * - Simplify the fast/slow_imageblit selection code, avoiding integer
-+ * divides.
- */
- #include <linux/module.h>
- #include <linux/string.h>
-@@ -262,6 +267,133 @@ static inline void fast_imageblit(const
- }
- }
-
-+/*
-+ * Optimized fast_imageblit for bpp == 16. ppw = 2, bit_mask = 3 folded
-+ * into the code, main loop unrolled.
-+ */
-+
-+static inline void fast_imageblit16(const struct fb_image *image,
-+ struct fb_info *p, u8 __iomem * dst1,
-+ u32 fgcolor, u32 bgcolor)
-+{
-+ u32 fgx = fgcolor, bgx = bgcolor;
-+ u32 spitch = (image->width + 7) / 8;
-+ u32 end_mask, eorx;
-+ const char *s = image->data, *src;
-+ u32 __iomem *dst;
-+ const u32 *tab = NULL;
-+ int i, j, k;
-+
-+ tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le;
-+
-+ fgx <<= 16;
-+ bgx <<= 16;
-+ fgx |= fgcolor;
-+ bgx |= bgcolor;
-+
-+ eorx = fgx ^ bgx;
-+ k = image->width / 2;
-+
-+ for (i = image->height; i--;) {
-+ dst = (u32 __iomem *) dst1;
-+ src = s;
-+
-+ j = k;
-+ while (j >= 4) {
-+ u8 bits = *src;
-+ end_mask = tab[(bits >> 6) & 3];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
-+ end_mask = tab[(bits >> 4) & 3];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
-+ end_mask = tab[(bits >> 2) & 3];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
-+ end_mask = tab[bits & 3];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
-+ src++;
-+ j -= 4;
-+ }
-+ if (j != 0) {
-+ u8 bits = *src;
-+ end_mask = tab[(bits >> 6) & 3];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
-+ if (j >= 2) {
-+ end_mask = tab[(bits >> 4) & 3];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
-+ if (j == 3) {
-+ end_mask = tab[(bits >> 2) & 3];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst);
-+ }
-+ }
-+ }
-+ dst1 += p->fix.line_length;
-+ s += spitch;
-+ }
-+}
-+
-+/*
-+ * Optimized fast_imageblit for bpp == 32. ppw = 1, bit_mask = 1 folded
-+ * into the code, main loop unrolled.
-+ */
-+
-+static inline void fast_imageblit32(const struct fb_image *image,
-+ struct fb_info *p, u8 __iomem * dst1,
-+ u32 fgcolor, u32 bgcolor)
-+{
-+ u32 fgx = fgcolor, bgx = bgcolor;
-+ u32 spitch = (image->width + 7) / 8;
-+ u32 end_mask, eorx;
-+ const char *s = image->data, *src;
-+ u32 __iomem *dst;
-+ const u32 *tab = NULL;
-+ int i, j, k;
-+
-+ tab = cfb_tab32;
-+
-+ eorx = fgx ^ bgx;
-+ k = image->width;
-+
-+ for (i = image->height; i--;) {
-+ dst = (u32 __iomem *) dst1;
-+ src = s;
-+
-+ j = k;
-+ while (j >= 8) {
-+ u8 bits = *src;
-+ end_mask = tab[(bits >> 7) & 1];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
-+ end_mask = tab[(bits >> 6) & 1];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
-+ end_mask = tab[(bits >> 5) & 1];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
-+ end_mask = tab[(bits >> 4) & 1];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
-+ end_mask = tab[(bits >> 3) & 1];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
-+ end_mask = tab[(bits >> 2) & 1];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
-+ end_mask = tab[(bits >> 1) & 1];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
-+ end_mask = tab[bits & 1];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
-+ src++;
-+ j -= 8;
-+ }
-+ if (j != 0) {
-+ u32 bits = (u32) * src;
-+ while (j > 1) {
-+ end_mask = tab[(bits >> 7) & 1];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
-+ bits <<= 1;
-+ j--;
-+ }
-+ end_mask = tab[(bits >> 7) & 1];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst);
-+ }
-+ dst1 += p->fix.line_length;
-+ s += spitch;
-+ }
-+}
-+
- void cfb_imageblit(struct fb_info *p, const struct fb_image *image)
- {
- u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0;
-@@ -294,11 +426,21 @@ void cfb_imageblit(struct fb_info *p, co
- bgcolor = image->bg_color;
- }
-
-- if (32 % bpp == 0 && !start_index && !pitch_index &&
-- ((width & (32/bpp-1)) == 0) &&
-- bpp >= 8 && bpp <= 32)
-- fast_imageblit(image, p, dst1, fgcolor, bgcolor);
-- else
-+ if (!start_index && !pitch_index) {
-+ if (bpp == 32)
-+ fast_imageblit32(image, p, dst1, fgcolor,
-+ bgcolor);
-+ else if (bpp == 16 && (width & 1) == 0)
-+ fast_imageblit16(image, p, dst1, fgcolor,
-+ bgcolor);
-+ else if (bpp == 8 && (width & 3) == 0)
-+ fast_imageblit(image, p, dst1, fgcolor,
-+ bgcolor);
-+ else
-+ slow_imageblit(image, p, dst1, fgcolor,
-+ bgcolor,
-+ start_index, pitch_index);
-+ } else
- slow_imageblit(image, p, dst1, fgcolor, bgcolor,
- start_index, pitch_index);
- } else
diff --git a/target/linux/brcm2708/patches-4.4/0059-Allow-mac-address-to-be-set-in-smsc95xx.patch b/target/linux/brcm2708/patches-4.4/0059-Allow-mac-address-to-be-set-in-smsc95xx.patch
deleted file mode 100644
index 03a972c8f4..0000000000
--- a/target/linux/brcm2708/patches-4.4/0059-Allow-mac-address-to-be-set-in-smsc95xx.patch
+++ /dev/null
@@ -1,91 +0,0 @@
-From 6c0a9150827dc58fac38c8e787c050626325842e Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Tue, 26 Mar 2013 17:26:38 +0000
-Subject: [PATCH 059/170] Allow mac address to be set in smsc95xx
-
-Signed-off-by: popcornmix <popcornmix@gmail.com>
----
- drivers/net/usb/smsc95xx.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 56 insertions(+)
-
---- a/drivers/net/usb/smsc95xx.c
-+++ b/drivers/net/usb/smsc95xx.c
-@@ -59,6 +59,7 @@
- #define SUSPEND_SUSPEND3 (0x08)
- #define SUSPEND_ALLMODES (SUSPEND_SUSPEND0 | SUSPEND_SUSPEND1 | \
- SUSPEND_SUSPEND2 | SUSPEND_SUSPEND3)
-+#define MAC_ADDR_LEN (6)
-
- struct smsc95xx_priv {
- u32 mac_cr;
-@@ -74,6 +75,10 @@ static bool turbo_mode = false;
- module_param(turbo_mode, bool, 0644);
- MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
-
-+static char *macaddr = ":";
-+module_param(macaddr, charp, 0);
-+MODULE_PARM_DESC(macaddr, "MAC address");
-+
- static int __must_check __smsc95xx_read_reg(struct usbnet *dev, u32 index,
- u32 *data, int in_pm)
- {
-@@ -763,8 +768,59 @@ static int smsc95xx_ioctl(struct net_dev
- return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
- }
-
-+/* Check the macaddr module parameter for a MAC address */
-+static int smsc95xx_is_macaddr_param(struct usbnet *dev, u8 *dev_mac)
-+{
-+ int i, j, got_num, num;
-+ u8 mtbl[MAC_ADDR_LEN];
-+
-+ if (macaddr[0] == ':')
-+ return 0;
-+
-+ i = 0;
-+ j = 0;
-+ num = 0;
-+ got_num = 0;
-+ while (j < MAC_ADDR_LEN) {
-+ if (macaddr[i] && macaddr[i] != ':') {
-+ got_num++;
-+ if ('0' <= macaddr[i] && macaddr[i] <= '9')
-+ num = num * 16 + macaddr[i] - '0';
-+ else if ('A' <= macaddr[i] && macaddr[i] <= 'F')
-+ num = num * 16 + 10 + macaddr[i] - 'A';
-+ else if ('a' <= macaddr[i] && macaddr[i] <= 'f')
-+ num = num * 16 + 10 + macaddr[i] - 'a';
-+ else
-+ break;
-+ i++;
-+ } else if (got_num == 2) {
-+ mtbl[j++] = (u8) num;
-+ num = 0;
-+ got_num = 0;
-+ i++;
-+ } else {
-+ break;
-+ }
-+ }
-+
-+ if (j == MAC_ADDR_LEN) {
-+ netif_dbg(dev, ifup, dev->net, "Overriding MAC address with: "
-+ "%02x:%02x:%02x:%02x:%02x:%02x\n", mtbl[0], mtbl[1], mtbl[2],
-+ mtbl[3], mtbl[4], mtbl[5]);
-+ for (i = 0; i < MAC_ADDR_LEN; i++)
-+ dev_mac[i] = mtbl[i];
-+ return 1;
-+ } else {
-+ return 0;
-+ }
-+}
-+
- static void smsc95xx_init_mac_address(struct usbnet *dev)
- {
-+ /* Check module parameters */
-+ if (smsc95xx_is_macaddr_param(dev, dev->net->dev_addr))
-+ return;
-+
- /* try reading mac address from EEPROM */
- if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN,
- dev->net->dev_addr) == 0) {
diff --git a/target/linux/brcm2708/patches-4.4/0059-enabling-the-realtime-clock-1-wire-chip-DS1307-and-1.patch b/target/linux/brcm2708/patches-4.4/0059-enabling-the-realtime-clock-1-wire-chip-DS1307-and-1.patch
new file mode 100644
index 0000000000..bbbd19b637
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0059-enabling-the-realtime-clock-1-wire-chip-DS1307-and-1.patch
@@ -0,0 +1,242 @@
+From 5e030ebb3c7dd9a757e871ac7434e24b22ca7a16 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Wed, 8 May 2013 11:46:50 +0100
+Subject: [PATCH 059/381] enabling the realtime clock 1-wire chip DS1307 and
+ 1-wire on GPIO4 (as a module)
+
+1-wire: Add support for configuring pin for w1-gpio kernel module
+See: https://github.com/raspberrypi/linux/pull/457
+
+Add bitbanging pullups, use them for w1-gpio
+
+Allows parasite power to work, uses module option pullup=1
+
+bcm2708: Ensure 1-wire pullup is disabled by default, and expose as module parameter
+
+Signed-off-by: Alex J Lennon <ajlennon@dynamicdevices.co.uk>
+
+w1-gpio: Add gpiopin module parameter and correctly free up gpio pull-up pin, if set
+
+Signed-off-by: Alex J Lennon <ajlennon@dynamicdevices.co.uk>
+
+w1-gpio: Sort out the pullup/parasitic power tangle
+---
+ drivers/w1/masters/w1-gpio.c | 69 ++++++++++++++++++++++++++++++++++++++++----
+ drivers/w1/w1.h | 6 ++++
+ drivers/w1/w1_int.c | 14 +++++++++
+ drivers/w1/w1_io.c | 18 ++++++++++--
+ include/linux/w1-gpio.h | 1 +
+ 5 files changed, 99 insertions(+), 9 deletions(-)
+
+--- a/drivers/w1/masters/w1-gpio.c
++++ b/drivers/w1/masters/w1-gpio.c
+@@ -23,6 +23,19 @@
+ #include "../w1.h"
+ #include "../w1_int.h"
+
++static int w1_gpio_pullup = 0;
++static int w1_gpio_pullup_orig = 0;
++module_param_named(pullup, w1_gpio_pullup, int, 0);
++MODULE_PARM_DESC(pullup, "Enable parasitic power (power on data) mode");
++static int w1_gpio_pullup_pin = -1;
++static int w1_gpio_pullup_pin_orig = -1;
++module_param_named(extpullup, w1_gpio_pullup_pin, int, 0);
++MODULE_PARM_DESC(extpullup, "GPIO external pullup pin number");
++static int w1_gpio_pin = -1;
++static int w1_gpio_pin_orig = -1;
++module_param_named(gpiopin, w1_gpio_pin, int, 0);
++MODULE_PARM_DESC(gpiopin, "GPIO pin number");
++
+ static u8 w1_gpio_set_pullup(void *data, int delay)
+ {
+ struct w1_gpio_platform_data *pdata = data;
+@@ -67,6 +80,16 @@ static u8 w1_gpio_read_bit(void *data)
+ return gpio_get_value(pdata->pin) ? 1 : 0;
+ }
+
++static void w1_gpio_bitbang_pullup(void *data, u8 on)
++{
++ struct w1_gpio_platform_data *pdata = data;
++
++ if (on)
++ gpio_direction_output(pdata->pin, 1);
++ else
++ gpio_direction_input(pdata->pin);
++}
++
+ #if defined(CONFIG_OF)
+ static const struct of_device_id w1_gpio_dt_ids[] = {
+ { .compatible = "w1-gpio" },
+@@ -80,6 +103,7 @@ static int w1_gpio_probe_dt(struct platf
+ struct w1_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
+ struct device_node *np = pdev->dev.of_node;
+ int gpio;
++ u32 value;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+@@ -88,6 +112,9 @@ static int w1_gpio_probe_dt(struct platf
+ if (of_get_property(np, "linux,open-drain", NULL))
+ pdata->is_open_drain = 1;
+
++ if (of_property_read_u32(np, "rpi,parasitic-power", &value) == 0)
++ pdata->parasitic_power = (value != 0);
++
+ gpio = of_get_gpio(np, 0);
+ if (gpio < 0) {
+ if (gpio != -EPROBE_DEFER)
+@@ -103,7 +130,7 @@ static int w1_gpio_probe_dt(struct platf
+ if (gpio == -EPROBE_DEFER)
+ return gpio;
+ /* ignore other errors as the pullup gpio is optional */
+- pdata->ext_pullup_enable_pin = gpio;
++ pdata->ext_pullup_enable_pin = (gpio >= 0) ? gpio : -1;
+
+ pdev->dev.platform_data = pdata;
+
+@@ -113,13 +140,15 @@ static int w1_gpio_probe_dt(struct platf
+ static int w1_gpio_probe(struct platform_device *pdev)
+ {
+ struct w1_bus_master *master;
+- struct w1_gpio_platform_data *pdata;
++ struct w1_gpio_platform_data *pdata = pdev->dev.platform_data;
+ int err;
+
+- if (of_have_populated_dt()) {
+- err = w1_gpio_probe_dt(pdev);
+- if (err < 0)
+- return err;
++ if(pdata == NULL) {
++ if (of_have_populated_dt()) {
++ err = w1_gpio_probe_dt(pdev);
++ if (err < 0)
++ return err;
++ }
+ }
+
+ pdata = dev_get_platdata(&pdev->dev);
+@@ -136,6 +165,22 @@ static int w1_gpio_probe(struct platform
+ return -ENOMEM;
+ }
+
++ w1_gpio_pin_orig = pdata->pin;
++ w1_gpio_pullup_pin_orig = pdata->ext_pullup_enable_pin;
++ w1_gpio_pullup_orig = pdata->parasitic_power;
++
++ if(gpio_is_valid(w1_gpio_pin)) {
++ pdata->pin = w1_gpio_pin;
++ pdata->ext_pullup_enable_pin = -1;
++ pdata->parasitic_power = -1;
++ }
++ pdata->parasitic_power |= w1_gpio_pullup;
++ if(gpio_is_valid(w1_gpio_pullup_pin)) {
++ pdata->ext_pullup_enable_pin = w1_gpio_pullup_pin;
++ }
++
++ dev_info(&pdev->dev, "gpio pin %d, external pullup pin %d, parasitic power %d\n", pdata->pin, pdata->ext_pullup_enable_pin, pdata->parasitic_power);
++
+ err = devm_gpio_request(&pdev->dev, pdata->pin, "w1");
+ if (err) {
+ dev_err(&pdev->dev, "gpio_request (pin) failed\n");
+@@ -165,6 +210,14 @@ static int w1_gpio_probe(struct platform
+ master->set_pullup = w1_gpio_set_pullup;
+ }
+
++ if (pdata->parasitic_power) {
++ if (pdata->is_open_drain)
++ printk(KERN_ERR "w1-gpio 'pullup'(parasitic power) "
++ "option doesn't work with open drain GPIO\n");
++ else
++ master->bitbang_pullup = w1_gpio_bitbang_pullup;
++ }
++
+ err = w1_add_master_device(master);
+ if (err) {
+ dev_err(&pdev->dev, "w1_add_master device failed\n");
+@@ -195,6 +248,10 @@ static int w1_gpio_remove(struct platfor
+
+ w1_remove_master_device(master);
+
++ pdata->pin = w1_gpio_pin_orig;
++ pdata->ext_pullup_enable_pin = w1_gpio_pullup_pin_orig;
++ pdata->parasitic_power = w1_gpio_pullup_orig;
++
+ return 0;
+ }
+
+--- a/drivers/w1/w1.h
++++ b/drivers/w1/w1.h
+@@ -171,6 +171,12 @@ struct w1_bus_master
+
+ u8 (*set_pullup)(void *, int);
+
++ /**
++ * Turns the pullup on/off in bitbanging mode, takes an on/off argument.
++ * @return -1=Error, 0=completed
++ */
++ void (*bitbang_pullup) (void *, u8);
++
+ void (*search)(void *, struct w1_master *,
+ u8, w1_slave_found_callback);
+ };
+--- a/drivers/w1/w1_int.c
++++ b/drivers/w1/w1_int.c
+@@ -122,6 +122,20 @@ int w1_add_master_device(struct w1_bus_m
+ return(-EINVAL);
+ }
+
++ /* bitbanging hardware uses bitbang_pullup, other hardware uses set_pullup
++ * and takes care of timing itself */
++ if (!master->write_byte && !master->touch_bit && master->set_pullup) {
++ printk(KERN_ERR "w1_add_master_device: set_pullup requires "
++ "write_byte or touch_bit, disabling\n");
++ master->set_pullup = NULL;
++ }
++
++ if (master->set_pullup && master->bitbang_pullup) {
++ printk(KERN_ERR "w1_add_master_device: set_pullup should not "
++ "be set when bitbang_pullup is used, disabling\n");
++ master->set_pullup = NULL;
++ }
++
+ /* Lock until the device is added (or not) to w1_masters. */
+ mutex_lock(&w1_mlock);
+ /* Search for the first available id (starting at 1). */
+--- a/drivers/w1/w1_io.c
++++ b/drivers/w1/w1_io.c
+@@ -134,10 +134,22 @@ static void w1_pre_write(struct w1_maste
+ static void w1_post_write(struct w1_master *dev)
+ {
+ if (dev->pullup_duration) {
+- if (dev->enable_pullup && dev->bus_master->set_pullup)
+- dev->bus_master->set_pullup(dev->bus_master->data, 0);
+- else
++ if (dev->enable_pullup) {
++ if (dev->bus_master->set_pullup) {
++ dev->bus_master->set_pullup(dev->
++ bus_master->data,
++ 0);
++ } else if (dev->bus_master->bitbang_pullup) {
++ dev->bus_master->
++ bitbang_pullup(dev->bus_master->data, 1);
+ msleep(dev->pullup_duration);
++ dev->bus_master->
++ bitbang_pullup(dev->bus_master->data, 0);
++ }
++ } else {
++ msleep(dev->pullup_duration);
++ }
++
+ dev->pullup_duration = 0;
+ }
+ }
+--- a/include/linux/w1-gpio.h
++++ b/include/linux/w1-gpio.h
+@@ -18,6 +18,7 @@
+ struct w1_gpio_platform_data {
+ unsigned int pin;
+ unsigned int is_open_drain:1;
++ unsigned int parasitic_power:1;
+ void (*enable_external_pullup)(int enable);
+ unsigned int ext_pullup_enable_pin;
+ unsigned int pullup_duration;
diff --git a/target/linux/brcm2708/patches-4.4/0060-Added-Device-IDs-for-August-DVB-T-205.patch b/target/linux/brcm2708/patches-4.4/0060-Added-Device-IDs-for-August-DVB-T-205.patch
new file mode 100644
index 0000000000..972cc95af9
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0060-Added-Device-IDs-for-August-DVB-T-205.patch
@@ -0,0 +1,22 @@
+From 151995a5f455ff415d2e2d19ad8528137d53629d Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Wed, 3 Jul 2013 00:54:08 +0100
+Subject: [PATCH 060/381] Added Device IDs for August DVB-T 205
+
+---
+ drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
++++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+@@ -1900,6 +1900,10 @@ static const struct usb_device_id rtl28x
+ &rtl28xxu_props, "Compro VideoMate U650F", NULL) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, 0xd394,
+ &rtl28xxu_props, "MaxMedia HU394-T", NULL) },
++ { DVB_USB_DEVICE(USB_VID_GTEK, 0xb803 /*USB_PID_AUGUST_DVBT205*/,
++ &rtl28xxu_props, "August DVB-T 205", NULL) },
++ { DVB_USB_DEVICE(USB_VID_GTEK, 0xa803 /*USB_PID_AUGUST_DVBT205*/,
++ &rtl28xxu_props, "August DVB-T 205", NULL) },
+ { DVB_USB_DEVICE(USB_VID_LEADTEK, 0x6a03,
+ &rtl28xxu_props, "Leadtek WinFast DTV Dongle mini", NULL) },
+ { DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_CPYTO_REDI_PC50A,
diff --git a/target/linux/brcm2708/patches-4.4/0060-enabling-the-realtime-clock-1-wire-chip-DS1307-and-1.patch b/target/linux/brcm2708/patches-4.4/0060-enabling-the-realtime-clock-1-wire-chip-DS1307-and-1.patch
deleted file mode 100644
index eb44deb85e..0000000000
--- a/target/linux/brcm2708/patches-4.4/0060-enabling-the-realtime-clock-1-wire-chip-DS1307-and-1.patch
+++ /dev/null
@@ -1,242 +0,0 @@
-From e172d31b8402f13aed5679cd7023f0c0935aab05 Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Wed, 8 May 2013 11:46:50 +0100
-Subject: [PATCH 060/170] enabling the realtime clock 1-wire chip DS1307 and
- 1-wire on GPIO4 (as a module)
-
-1-wire: Add support for configuring pin for w1-gpio kernel module
-See: https://github.com/raspberrypi/linux/pull/457
-
-Add bitbanging pullups, use them for w1-gpio
-
-Allows parasite power to work, uses module option pullup=1
-
-bcm2708: Ensure 1-wire pullup is disabled by default, and expose as module parameter
-
-Signed-off-by: Alex J Lennon <ajlennon@dynamicdevices.co.uk>
-
-w1-gpio: Add gpiopin module parameter and correctly free up gpio pull-up pin, if set
-
-Signed-off-by: Alex J Lennon <ajlennon@dynamicdevices.co.uk>
-
-w1-gpio: Sort out the pullup/parasitic power tangle
----
- drivers/w1/masters/w1-gpio.c | 69 ++++++++++++++++++++++++++++++++++++++++----
- drivers/w1/w1.h | 6 ++++
- drivers/w1/w1_int.c | 14 +++++++++
- drivers/w1/w1_io.c | 18 ++++++++++--
- include/linux/w1-gpio.h | 1 +
- 5 files changed, 99 insertions(+), 9 deletions(-)
-
---- a/drivers/w1/masters/w1-gpio.c
-+++ b/drivers/w1/masters/w1-gpio.c
-@@ -23,6 +23,19 @@
- #include "../w1.h"
- #include "../w1_int.h"
-
-+static int w1_gpio_pullup = 0;
-+static int w1_gpio_pullup_orig = 0;
-+module_param_named(pullup, w1_gpio_pullup, int, 0);
-+MODULE_PARM_DESC(pullup, "Enable parasitic power (power on data) mode");
-+static int w1_gpio_pullup_pin = -1;
-+static int w1_gpio_pullup_pin_orig = -1;
-+module_param_named(extpullup, w1_gpio_pullup_pin, int, 0);
-+MODULE_PARM_DESC(extpullup, "GPIO external pullup pin number");
-+static int w1_gpio_pin = -1;
-+static int w1_gpio_pin_orig = -1;
-+module_param_named(gpiopin, w1_gpio_pin, int, 0);
-+MODULE_PARM_DESC(gpiopin, "GPIO pin number");
-+
- static u8 w1_gpio_set_pullup(void *data, int delay)
- {
- struct w1_gpio_platform_data *pdata = data;
-@@ -67,6 +80,16 @@ static u8 w1_gpio_read_bit(void *data)
- return gpio_get_value(pdata->pin) ? 1 : 0;
- }
-
-+static void w1_gpio_bitbang_pullup(void *data, u8 on)
-+{
-+ struct w1_gpio_platform_data *pdata = data;
-+
-+ if (on)
-+ gpio_direction_output(pdata->pin, 1);
-+ else
-+ gpio_direction_input(pdata->pin);
-+}
-+
- #if defined(CONFIG_OF)
- static const struct of_device_id w1_gpio_dt_ids[] = {
- { .compatible = "w1-gpio" },
-@@ -80,6 +103,7 @@ static int w1_gpio_probe_dt(struct platf
- struct w1_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
- struct device_node *np = pdev->dev.of_node;
- int gpio;
-+ u32 value;
-
- pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata)
-@@ -88,6 +112,9 @@ static int w1_gpio_probe_dt(struct platf
- if (of_get_property(np, "linux,open-drain", NULL))
- pdata->is_open_drain = 1;
-
-+ if (of_property_read_u32(np, "rpi,parasitic-power", &value) == 0)
-+ pdata->parasitic_power = (value != 0);
-+
- gpio = of_get_gpio(np, 0);
- if (gpio < 0) {
- if (gpio != -EPROBE_DEFER)
-@@ -103,7 +130,7 @@ static int w1_gpio_probe_dt(struct platf
- if (gpio == -EPROBE_DEFER)
- return gpio;
- /* ignore other errors as the pullup gpio is optional */
-- pdata->ext_pullup_enable_pin = gpio;
-+ pdata->ext_pullup_enable_pin = (gpio >= 0) ? gpio : -1;
-
- pdev->dev.platform_data = pdata;
-
-@@ -113,13 +140,15 @@ static int w1_gpio_probe_dt(struct platf
- static int w1_gpio_probe(struct platform_device *pdev)
- {
- struct w1_bus_master *master;
-- struct w1_gpio_platform_data *pdata;
-+ struct w1_gpio_platform_data *pdata = pdev->dev.platform_data;
- int err;
-
-- if (of_have_populated_dt()) {
-- err = w1_gpio_probe_dt(pdev);
-- if (err < 0)
-- return err;
-+ if(pdata == NULL) {
-+ if (of_have_populated_dt()) {
-+ err = w1_gpio_probe_dt(pdev);
-+ if (err < 0)
-+ return err;
-+ }
- }
-
- pdata = dev_get_platdata(&pdev->dev);
-@@ -136,6 +165,22 @@ static int w1_gpio_probe(struct platform
- return -ENOMEM;
- }
-
-+ w1_gpio_pin_orig = pdata->pin;
-+ w1_gpio_pullup_pin_orig = pdata->ext_pullup_enable_pin;
-+ w1_gpio_pullup_orig = pdata->parasitic_power;
-+
-+ if(gpio_is_valid(w1_gpio_pin)) {
-+ pdata->pin = w1_gpio_pin;
-+ pdata->ext_pullup_enable_pin = -1;
-+ pdata->parasitic_power = -1;
-+ }
-+ pdata->parasitic_power |= w1_gpio_pullup;
-+ if(gpio_is_valid(w1_gpio_pullup_pin)) {
-+ pdata->ext_pullup_enable_pin = w1_gpio_pullup_pin;
-+ }
-+
-+ dev_info(&pdev->dev, "gpio pin %d, external pullup pin %d, parasitic power %d\n", pdata->pin, pdata->ext_pullup_enable_pin, pdata->parasitic_power);
-+
- err = devm_gpio_request(&pdev->dev, pdata->pin, "w1");
- if (err) {
- dev_err(&pdev->dev, "gpio_request (pin) failed\n");
-@@ -165,6 +210,14 @@ static int w1_gpio_probe(struct platform
- master->set_pullup = w1_gpio_set_pullup;
- }
-
-+ if (pdata->parasitic_power) {
-+ if (pdata->is_open_drain)
-+ printk(KERN_ERR "w1-gpio 'pullup'(parasitic power) "
-+ "option doesn't work with open drain GPIO\n");
-+ else
-+ master->bitbang_pullup = w1_gpio_bitbang_pullup;
-+ }
-+
- err = w1_add_master_device(master);
- if (err) {
- dev_err(&pdev->dev, "w1_add_master device failed\n");
-@@ -195,6 +248,10 @@ static int w1_gpio_remove(struct platfor
-
- w1_remove_master_device(master);
-
-+ pdata->pin = w1_gpio_pin_orig;
-+ pdata->ext_pullup_enable_pin = w1_gpio_pullup_pin_orig;
-+ pdata->parasitic_power = w1_gpio_pullup_orig;
-+
- return 0;
- }
-
---- a/drivers/w1/w1.h
-+++ b/drivers/w1/w1.h
-@@ -171,6 +171,12 @@ struct w1_bus_master
-
- u8 (*set_pullup)(void *, int);
-
-+ /**
-+ * Turns the pullup on/off in bitbanging mode, takes an on/off argument.
-+ * @return -1=Error, 0=completed
-+ */
-+ void (*bitbang_pullup) (void *, u8);
-+
- void (*search)(void *, struct w1_master *,
- u8, w1_slave_found_callback);
- };
---- a/drivers/w1/w1_int.c
-+++ b/drivers/w1/w1_int.c
-@@ -122,6 +122,20 @@ int w1_add_master_device(struct w1_bus_m
- return(-EINVAL);
- }
-
-+ /* bitbanging hardware uses bitbang_pullup, other hardware uses set_pullup
-+ * and takes care of timing itself */
-+ if (!master->write_byte && !master->touch_bit && master->set_pullup) {
-+ printk(KERN_ERR "w1_add_master_device: set_pullup requires "
-+ "write_byte or touch_bit, disabling\n");
-+ master->set_pullup = NULL;
-+ }
-+
-+ if (master->set_pullup && master->bitbang_pullup) {
-+ printk(KERN_ERR "w1_add_master_device: set_pullup should not "
-+ "be set when bitbang_pullup is used, disabling\n");
-+ master->set_pullup = NULL;
-+ }
-+
- /* Lock until the device is added (or not) to w1_masters. */
- mutex_lock(&w1_mlock);
- /* Search for the first available id (starting at 1). */
---- a/drivers/w1/w1_io.c
-+++ b/drivers/w1/w1_io.c
-@@ -134,10 +134,22 @@ static void w1_pre_write(struct w1_maste
- static void w1_post_write(struct w1_master *dev)
- {
- if (dev->pullup_duration) {
-- if (dev->enable_pullup && dev->bus_master->set_pullup)
-- dev->bus_master->set_pullup(dev->bus_master->data, 0);
-- else
-+ if (dev->enable_pullup) {
-+ if (dev->bus_master->set_pullup) {
-+ dev->bus_master->set_pullup(dev->
-+ bus_master->data,
-+ 0);
-+ } else if (dev->bus_master->bitbang_pullup) {
-+ dev->bus_master->
-+ bitbang_pullup(dev->bus_master->data, 1);
- msleep(dev->pullup_duration);
-+ dev->bus_master->
-+ bitbang_pullup(dev->bus_master->data, 0);
-+ }
-+ } else {
-+ msleep(dev->pullup_duration);
-+ }
-+
- dev->pullup_duration = 0;
- }
- }
---- a/include/linux/w1-gpio.h
-+++ b/include/linux/w1-gpio.h
-@@ -18,6 +18,7 @@
- struct w1_gpio_platform_data {
- unsigned int pin;
- unsigned int is_open_drain:1;
-+ unsigned int parasitic_power:1;
- void (*enable_external_pullup)(int enable);
- unsigned int ext_pullup_enable_pin;
- unsigned int pullup_duration;
diff --git a/target/linux/brcm2708/patches-4.4/0061-Added-Device-IDs-for-August-DVB-T-205.patch b/target/linux/brcm2708/patches-4.4/0061-Added-Device-IDs-for-August-DVB-T-205.patch
deleted file mode 100644
index 12645bf311..0000000000
--- a/target/linux/brcm2708/patches-4.4/0061-Added-Device-IDs-for-August-DVB-T-205.patch
+++ /dev/null
@@ -1,22 +0,0 @@
-From 78c49b30c0dcc8b73f383f71b89719798fc89b72 Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Wed, 3 Jul 2013 00:54:08 +0100
-Subject: [PATCH 061/170] Added Device IDs for August DVB-T 205
-
----
- drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
-+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
-@@ -1900,6 +1900,10 @@ static const struct usb_device_id rtl28x
- &rtl28xxu_props, "Compro VideoMate U650F", NULL) },
- { DVB_USB_DEVICE(USB_VID_KWORLD_2, 0xd394,
- &rtl28xxu_props, "MaxMedia HU394-T", NULL) },
-+ { DVB_USB_DEVICE(USB_VID_GTEK, 0xb803 /*USB_PID_AUGUST_DVBT205*/,
-+ &rtl28xxu_props, "August DVB-T 205", NULL) },
-+ { DVB_USB_DEVICE(USB_VID_GTEK, 0xa803 /*USB_PID_AUGUST_DVBT205*/,
-+ &rtl28xxu_props, "August DVB-T 205", NULL) },
- { DVB_USB_DEVICE(USB_VID_LEADTEK, 0x6a03,
- &rtl28xxu_props, "Leadtek WinFast DTV Dongle mini", NULL) },
- { DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_CPYTO_REDI_PC50A,
diff --git a/target/linux/brcm2708/patches-4.4/0061-config-Enable-CONFIG_MEMCG-but-leave-it-disabled-due.patch b/target/linux/brcm2708/patches-4.4/0061-config-Enable-CONFIG_MEMCG-but-leave-it-disabled-due.patch
new file mode 100644
index 0000000000..c50c7b1088
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0061-config-Enable-CONFIG_MEMCG-but-leave-it-disabled-due.patch
@@ -0,0 +1,49 @@
+From 27950dc12923e0679a177ae7d17779a77d9500af Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Wed, 18 Dec 2013 22:16:19 +0000
+Subject: [PATCH 061/381] config: Enable CONFIG_MEMCG, but leave it disabled
+ (due to memory cost). Enable with cgroup_enable=memory.
+
+---
+ kernel/cgroup.c | 23 ++++++++++++++++++++++-
+ 1 file changed, 22 insertions(+), 1 deletion(-)
+
+--- a/kernel/cgroup.c
++++ b/kernel/cgroup.c
+@@ -5306,7 +5306,7 @@ int __init cgroup_init_early(void)
+ return 0;
+ }
+
+-static unsigned long cgroup_disable_mask __initdata;
++static unsigned long cgroup_disable_mask __initdata = 1<<0;
+
+ /**
+ * cgroup_init - cgroup initialization
+@@ -5802,6 +5802,27 @@ static int __init cgroup_disable(char *s
+ }
+ __setup("cgroup_disable=", cgroup_disable);
+
++static int __init cgroup_enable(char *str)
++{
++ struct cgroup_subsys *ss;
++ char *token;
++ int i;
++
++ while ((token = strsep(&str, ",")) != NULL) {
++ if (!*token)
++ continue;
++
++ for_each_subsys(ss, i) {
++ if (strcmp(token, ss->name) &&
++ strcmp(token, ss->legacy_name))
++ continue;
++ cgroup_disable_mask &= ~(1 << i);
++ }
++ }
++ return 1;
++}
++__setup("cgroup_enable=", cgroup_enable);
++
+ /**
+ * css_tryget_online_from_dir - get corresponding css from a cgroup dentry
+ * @dentry: directory dentry of interest
diff --git a/target/linux/brcm2708/patches-4.4/0062-ASoC-Add-support-for-PCM5102A-codec.patch b/target/linux/brcm2708/patches-4.4/0062-ASoC-Add-support-for-PCM5102A-codec.patch
new file mode 100644
index 0000000000..ec66823f48
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0062-ASoC-Add-support-for-PCM5102A-codec.patch
@@ -0,0 +1,128 @@
+From 90330d268c0507ca0b41c758feccbab2915e08fc Mon Sep 17 00:00:00 2001
+From: Florian Meier <florian.meier@koalo.de>
+Date: Fri, 22 Nov 2013 14:59:51 +0100
+Subject: [PATCH 062/381] ASoC: Add support for PCM5102A codec
+
+Some definitions to support the PCM5102A codec
+by Texas Instruments.
+
+Signed-off-by: Florian Meier <florian.meier@koalo.de>
+---
+ sound/soc/codecs/Kconfig | 5 ++++
+ sound/soc/codecs/Makefile | 2 ++
+ sound/soc/codecs/pcm5102a.c | 70 +++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 77 insertions(+)
+ create mode 100644 sound/soc/codecs/pcm5102a.c
+
+--- a/sound/soc/codecs/Kconfig
++++ b/sound/soc/codecs/Kconfig
+@@ -89,6 +89,7 @@ config SND_SOC_ALL_CODECS
+ select SND_SOC_PCM512x_SPI if SPI_MASTER
+ select SND_SOC_RT286 if I2C
+ select SND_SOC_RT298 if I2C
++ select SND_SOC_PCM5102A if I2C
+ select SND_SOC_RT5631 if I2C
+ select SND_SOC_RT5640 if I2C
+ select SND_SOC_RT5645 if I2C
+@@ -549,6 +550,10 @@ config SND_SOC_RT298
+ tristate
+ depends on I2C
+
++config SND_SOC_PCM5102A
++ tristate
++ depends on I2C
++
+ config SND_SOC_RT5631
+ tristate "Realtek ALC5631/RT5631 CODEC"
+ depends on I2C
+--- a/sound/soc/codecs/Makefile
++++ b/sound/soc/codecs/Makefile
+@@ -85,6 +85,7 @@ snd-soc-rl6231-objs := rl6231.o
+ snd-soc-rl6347a-objs := rl6347a.o
+ snd-soc-rt286-objs := rt286.o
+ snd-soc-rt298-objs := rt298.o
++snd-soc-pcm5102a-objs := pcm5102a.o
+ snd-soc-rt5631-objs := rt5631.o
+ snd-soc-rt5640-objs := rt5640.o
+ snd-soc-rt5645-objs := rt5645.o
+@@ -280,6 +281,7 @@ obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-
+ obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o
+ obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o
+ obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o
++obj-$(CONFIG_SND_SOC_PCM5102A) += snd-soc-pcm5102a.o
+ obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o
+ obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o
+ obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o
+--- /dev/null
++++ b/sound/soc/codecs/pcm5102a.c
+@@ -0,0 +1,70 @@
++/*
++ * Driver for the PCM5102A codec
++ *
++ * Author: Florian Meier <florian.meier@koalo.de>
++ * Copyright 2013
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#include <sound/soc.h>
++
++static struct snd_soc_dai_driver pcm5102a_dai = {
++ .name = "pcm5102a-hifi",
++ .playback = {
++ .channels_min = 2,
++ .channels_max = 2,
++ .rates = SNDRV_PCM_RATE_8000_192000,
++ .formats = SNDRV_PCM_FMTBIT_S16_LE |
++ SNDRV_PCM_FMTBIT_S24_LE |
++ SNDRV_PCM_FMTBIT_S32_LE
++ },
++};
++
++static struct snd_soc_codec_driver soc_codec_dev_pcm5102a;
++
++static int pcm5102a_probe(struct platform_device *pdev)
++{
++ return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_pcm5102a,
++ &pcm5102a_dai, 1);
++}
++
++static int pcm5102a_remove(struct platform_device *pdev)
++{
++ snd_soc_unregister_codec(&pdev->dev);
++ return 0;
++}
++
++static const struct of_device_id pcm5102a_of_match[] = {
++ { .compatible = "ti,pcm5102a", },
++ { }
++};
++MODULE_DEVICE_TABLE(of, pcm5102a_of_match);
++
++static struct platform_driver pcm5102a_codec_driver = {
++ .probe = pcm5102a_probe,
++ .remove = pcm5102a_remove,
++ .driver = {
++ .name = "pcm5102a-codec",
++ .owner = THIS_MODULE,
++ .of_match_table = pcm5102a_of_match,
++ },
++};
++
++module_platform_driver(pcm5102a_codec_driver);
++
++MODULE_DESCRIPTION("ASoC PCM5102A codec driver");
++MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
++MODULE_LICENSE("GPL v2");
diff --git a/target/linux/brcm2708/patches-4.4/0062-config-Enable-CONFIG_MEMCG-but-leave-it-disabled-due.patch b/target/linux/brcm2708/patches-4.4/0062-config-Enable-CONFIG_MEMCG-but-leave-it-disabled-due.patch
deleted file mode 100644
index 52704d58cb..0000000000
--- a/target/linux/brcm2708/patches-4.4/0062-config-Enable-CONFIG_MEMCG-but-leave-it-disabled-due.patch
+++ /dev/null
@@ -1,49 +0,0 @@
-From d0f48fe7aab3e4036fd55b491a9be94ea24f377d Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Wed, 18 Dec 2013 22:16:19 +0000
-Subject: [PATCH 062/170] config: Enable CONFIG_MEMCG, but leave it disabled
- (due to memory cost). Enable with cgroup_enable=memory.
-
----
- kernel/cgroup.c | 23 ++++++++++++++++++++++-
- 1 file changed, 22 insertions(+), 1 deletion(-)
-
---- a/kernel/cgroup.c
-+++ b/kernel/cgroup.c
-@@ -5302,7 +5302,7 @@ int __init cgroup_init_early(void)
- return 0;
- }
-
--static unsigned long cgroup_disable_mask __initdata;
-+static unsigned long cgroup_disable_mask __initdata = 1<<0;
-
- /**
- * cgroup_init - cgroup initialization
-@@ -5798,6 +5798,27 @@ static int __init cgroup_disable(char *s
- }
- __setup("cgroup_disable=", cgroup_disable);
-
-+static int __init cgroup_enable(char *str)
-+{
-+ struct cgroup_subsys *ss;
-+ char *token;
-+ int i;
-+
-+ while ((token = strsep(&str, ",")) != NULL) {
-+ if (!*token)
-+ continue;
-+
-+ for_each_subsys(ss, i) {
-+ if (strcmp(token, ss->name) &&
-+ strcmp(token, ss->legacy_name))
-+ continue;
-+ cgroup_disable_mask &= ~(1 << i);
-+ }
-+ }
-+ return 1;
-+}
-+__setup("cgroup_enable=", cgroup_enable);
-+
- /**
- * css_tryget_online_from_dir - get corresponding css from a cgroup dentry
- * @dentry: directory dentry of interest
diff --git a/target/linux/brcm2708/patches-4.4/0063-ASoC-Add-support-for-HifiBerry-DAC.patch b/target/linux/brcm2708/patches-4.4/0063-ASoC-Add-support-for-HifiBerry-DAC.patch
new file mode 100644
index 0000000000..4ac9b28e30
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0063-ASoC-Add-support-for-HifiBerry-DAC.patch
@@ -0,0 +1,165 @@
+From 2ea95927e8dc5c1ee099f999a24c5bfa028f18bf Mon Sep 17 00:00:00 2001
+From: Florian Meier <florian.meier@koalo.de>
+Date: Fri, 22 Nov 2013 19:19:08 +0100
+Subject: [PATCH 063/381] ASoC: Add support for HifiBerry DAC
+
+This adds a machine driver for the HifiBerry DAC.
+It is a sound card that can
+be stacked onto the Raspberry Pi.
+
+Signed-off-by: Florian Meier <florian.meier@koalo.de>
+---
+ sound/soc/bcm/Kconfig | 7 +++
+ sound/soc/bcm/Makefile | 4 ++
+ sound/soc/bcm/hifiberry_dac.c | 122 ++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 133 insertions(+)
+ create mode 100644 sound/soc/bcm/hifiberry_dac.c
+
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -7,3 +7,10 @@ config SND_BCM2835_SOC_I2S
+ Say Y or M if you want to add support for codecs attached to
+ the BCM2835 I2S interface. You will also need
+ to select the audio interfaces to support below.
++
++config SND_BCM2708_SOC_HIFIBERRY_DAC
++ tristate "Support for HifiBerry DAC"
++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
++ select SND_SOC_PCM5102A
++ help
++ Say Y or M if you want to add support for HifiBerry DAC.
+--- a/sound/soc/bcm/Makefile
++++ b/sound/soc/bcm/Makefile
+@@ -3,3 +3,7 @@ snd-soc-bcm2835-i2s-objs := bcm2835-i2s.
+
+ obj-$(CONFIG_SND_BCM2835_SOC_I2S) += snd-soc-bcm2835-i2s.o
+
++# BCM2708 Machine Support
++snd-soc-hifiberry-dac-objs := hifiberry_dac.o
++
++obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o
+--- /dev/null
++++ b/sound/soc/bcm/hifiberry_dac.c
+@@ -0,0 +1,122 @@
++/*
++ * ASoC Driver for HifiBerry DAC
++ *
++ * Author: Florian Meier <florian.meier@koalo.de>
++ * Copyright 2013
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/jack.h>
++
++static int snd_rpi_hifiberry_dac_init(struct snd_soc_pcm_runtime *rtd)
++{
++ return 0;
++}
++
++static int snd_rpi_hifiberry_dac_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
++
++ unsigned int sample_bits =
++ snd_pcm_format_physical_width(params_format(params));
++
++ return snd_soc_dai_set_bclk_ratio(cpu_dai, sample_bits * 2);
++}
++
++/* machine stream operations */
++static struct snd_soc_ops snd_rpi_hifiberry_dac_ops = {
++ .hw_params = snd_rpi_hifiberry_dac_hw_params,
++};
++
++static struct snd_soc_dai_link snd_rpi_hifiberry_dac_dai[] = {
++{
++ .name = "HifiBerry DAC",
++ .stream_name = "HifiBerry DAC HiFi",
++ .cpu_dai_name = "bcm2708-i2s.0",
++ .codec_dai_name = "pcm5102a-hifi",
++ .platform_name = "bcm2708-i2s.0",
++ .codec_name = "pcm5102a-codec",
++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBS_CFS,
++ .ops = &snd_rpi_hifiberry_dac_ops,
++ .init = snd_rpi_hifiberry_dac_init,
++},
++};
++
++/* audio machine driver */
++static struct snd_soc_card snd_rpi_hifiberry_dac = {
++ .name = "snd_rpi_hifiberry_dac",
++ .dai_link = snd_rpi_hifiberry_dac_dai,
++ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dac_dai),
++};
++
++static int snd_rpi_hifiberry_dac_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++
++ snd_rpi_hifiberry_dac.dev = &pdev->dev;
++
++ if (pdev->dev.of_node) {
++ struct device_node *i2s_node;
++ struct snd_soc_dai_link *dai = &snd_rpi_hifiberry_dac_dai[0];
++ i2s_node = of_parse_phandle(pdev->dev.of_node,
++ "i2s-controller", 0);
++
++ if (i2s_node) {
++ dai->cpu_dai_name = NULL;
++ dai->cpu_of_node = i2s_node;
++ dai->platform_name = NULL;
++ dai->platform_of_node = i2s_node;
++ }
++ }
++
++ ret = snd_soc_register_card(&snd_rpi_hifiberry_dac);
++ if (ret)
++ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret);
++
++ return ret;
++}
++
++static int snd_rpi_hifiberry_dac_remove(struct platform_device *pdev)
++{
++ return snd_soc_unregister_card(&snd_rpi_hifiberry_dac);
++}
++
++static const struct of_device_id snd_rpi_hifiberry_dac_of_match[] = {
++ { .compatible = "hifiberry,hifiberry-dac", },
++ {},
++};
++MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_dac_of_match);
++
++static struct platform_driver snd_rpi_hifiberry_dac_driver = {
++ .driver = {
++ .name = "snd-hifiberry-dac",
++ .owner = THIS_MODULE,
++ .of_match_table = snd_rpi_hifiberry_dac_of_match,
++ },
++ .probe = snd_rpi_hifiberry_dac_probe,
++ .remove = snd_rpi_hifiberry_dac_remove,
++};
++
++module_platform_driver(snd_rpi_hifiberry_dac_driver);
++
++MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
++MODULE_DESCRIPTION("ASoC Driver for HifiBerry DAC");
++MODULE_LICENSE("GPL v2");
diff --git a/target/linux/brcm2708/patches-4.4/0063-ASoC-Add-support-for-PCM5102A-codec.patch b/target/linux/brcm2708/patches-4.4/0063-ASoC-Add-support-for-PCM5102A-codec.patch
deleted file mode 100644
index 2fcca63e11..0000000000
--- a/target/linux/brcm2708/patches-4.4/0063-ASoC-Add-support-for-PCM5102A-codec.patch
+++ /dev/null
@@ -1,128 +0,0 @@
-From 8d35b3a72d3580ad6f5bc5835bfe13b00cce6086 Mon Sep 17 00:00:00 2001
-From: Florian Meier <florian.meier@koalo.de>
-Date: Fri, 22 Nov 2013 14:59:51 +0100
-Subject: [PATCH 063/170] ASoC: Add support for PCM5102A codec
-
-Some definitions to support the PCM5102A codec
-by Texas Instruments.
-
-Signed-off-by: Florian Meier <florian.meier@koalo.de>
----
- sound/soc/codecs/Kconfig | 5 ++++
- sound/soc/codecs/Makefile | 2 ++
- sound/soc/codecs/pcm5102a.c | 70 +++++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 77 insertions(+)
- create mode 100644 sound/soc/codecs/pcm5102a.c
-
---- a/sound/soc/codecs/Kconfig
-+++ b/sound/soc/codecs/Kconfig
-@@ -89,6 +89,7 @@ config SND_SOC_ALL_CODECS
- select SND_SOC_PCM512x_SPI if SPI_MASTER
- select SND_SOC_RT286 if I2C
- select SND_SOC_RT298 if I2C
-+ select SND_SOC_PCM5102A if I2C
- select SND_SOC_RT5631 if I2C
- select SND_SOC_RT5640 if I2C
- select SND_SOC_RT5645 if I2C
-@@ -549,6 +550,10 @@ config SND_SOC_RT298
- tristate
- depends on I2C
-
-+config SND_SOC_PCM5102A
-+ tristate
-+ depends on I2C
-+
- config SND_SOC_RT5631
- tristate "Realtek ALC5631/RT5631 CODEC"
- depends on I2C
---- a/sound/soc/codecs/Makefile
-+++ b/sound/soc/codecs/Makefile
-@@ -85,6 +85,7 @@ snd-soc-rl6231-objs := rl6231.o
- snd-soc-rl6347a-objs := rl6347a.o
- snd-soc-rt286-objs := rt286.o
- snd-soc-rt298-objs := rt298.o
-+snd-soc-pcm5102a-objs := pcm5102a.o
- snd-soc-rt5631-objs := rt5631.o
- snd-soc-rt5640-objs := rt5640.o
- snd-soc-rt5645-objs := rt5645.o
-@@ -280,6 +281,7 @@ obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-
- obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o
- obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o
- obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o
-+obj-$(CONFIG_SND_SOC_PCM5102A) += snd-soc-pcm5102a.o
- obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o
- obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o
- obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o
---- /dev/null
-+++ b/sound/soc/codecs/pcm5102a.c
-@@ -0,0 +1,70 @@
-+/*
-+ * Driver for the PCM5102A codec
-+ *
-+ * Author: Florian Meier <florian.meier@koalo.de>
-+ * Copyright 2013
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ */
-+
-+
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+
-+#include <sound/soc.h>
-+
-+static struct snd_soc_dai_driver pcm5102a_dai = {
-+ .name = "pcm5102a-hifi",
-+ .playback = {
-+ .channels_min = 2,
-+ .channels_max = 2,
-+ .rates = SNDRV_PCM_RATE_8000_192000,
-+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
-+ SNDRV_PCM_FMTBIT_S24_LE |
-+ SNDRV_PCM_FMTBIT_S32_LE
-+ },
-+};
-+
-+static struct snd_soc_codec_driver soc_codec_dev_pcm5102a;
-+
-+static int pcm5102a_probe(struct platform_device *pdev)
-+{
-+ return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_pcm5102a,
-+ &pcm5102a_dai, 1);
-+}
-+
-+static int pcm5102a_remove(struct platform_device *pdev)
-+{
-+ snd_soc_unregister_codec(&pdev->dev);
-+ return 0;
-+}
-+
-+static const struct of_device_id pcm5102a_of_match[] = {
-+ { .compatible = "ti,pcm5102a", },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(of, pcm5102a_of_match);
-+
-+static struct platform_driver pcm5102a_codec_driver = {
-+ .probe = pcm5102a_probe,
-+ .remove = pcm5102a_remove,
-+ .driver = {
-+ .name = "pcm5102a-codec",
-+ .owner = THIS_MODULE,
-+ .of_match_table = pcm5102a_of_match,
-+ },
-+};
-+
-+module_platform_driver(pcm5102a_codec_driver);
-+
-+MODULE_DESCRIPTION("ASoC PCM5102A codec driver");
-+MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
-+MODULE_LICENSE("GPL v2");
diff --git a/target/linux/brcm2708/patches-4.4/0064-ASoC-Add-support-for-HifiBerry-DAC.patch b/target/linux/brcm2708/patches-4.4/0064-ASoC-Add-support-for-HifiBerry-DAC.patch
deleted file mode 100644
index 51c1fb1da8..0000000000
--- a/target/linux/brcm2708/patches-4.4/0064-ASoC-Add-support-for-HifiBerry-DAC.patch
+++ /dev/null
@@ -1,165 +0,0 @@
-From 9ced0e86593de2214ff8a81f71c802d7e7301b05 Mon Sep 17 00:00:00 2001
-From: Florian Meier <florian.meier@koalo.de>
-Date: Fri, 22 Nov 2013 19:19:08 +0100
-Subject: [PATCH 064/170] ASoC: Add support for HifiBerry DAC
-
-This adds a machine driver for the HifiBerry DAC.
-It is a sound card that can
-be stacked onto the Raspberry Pi.
-
-Signed-off-by: Florian Meier <florian.meier@koalo.de>
----
- sound/soc/bcm/Kconfig | 7 +++
- sound/soc/bcm/Makefile | 4 ++
- sound/soc/bcm/hifiberry_dac.c | 122 ++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 133 insertions(+)
- create mode 100644 sound/soc/bcm/hifiberry_dac.c
-
---- a/sound/soc/bcm/Kconfig
-+++ b/sound/soc/bcm/Kconfig
-@@ -7,3 +7,10 @@ config SND_BCM2835_SOC_I2S
- Say Y or M if you want to add support for codecs attached to
- the BCM2835 I2S interface. You will also need
- to select the audio interfaces to support below.
-+
-+config SND_BCM2708_SOC_HIFIBERRY_DAC
-+ tristate "Support for HifiBerry DAC"
-+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
-+ select SND_SOC_PCM5102A
-+ help
-+ Say Y or M if you want to add support for HifiBerry DAC.
---- a/sound/soc/bcm/Makefile
-+++ b/sound/soc/bcm/Makefile
-@@ -3,3 +3,7 @@ snd-soc-bcm2835-i2s-objs := bcm2835-i2s.
-
- obj-$(CONFIG_SND_BCM2835_SOC_I2S) += snd-soc-bcm2835-i2s.o
-
-+# BCM2708 Machine Support
-+snd-soc-hifiberry-dac-objs := hifiberry_dac.o
-+
-+obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o
---- /dev/null
-+++ b/sound/soc/bcm/hifiberry_dac.c
-@@ -0,0 +1,122 @@
-+/*
-+ * ASoC Driver for HifiBerry DAC
-+ *
-+ * Author: Florian Meier <florian.meier@koalo.de>
-+ * Copyright 2013
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+
-+#include <sound/core.h>
-+#include <sound/pcm.h>
-+#include <sound/pcm_params.h>
-+#include <sound/soc.h>
-+#include <sound/jack.h>
-+
-+static int snd_rpi_hifiberry_dac_init(struct snd_soc_pcm_runtime *rtd)
-+{
-+ return 0;
-+}
-+
-+static int snd_rpi_hifiberry_dac_hw_params(struct snd_pcm_substream *substream,
-+ struct snd_pcm_hw_params *params)
-+{
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-+
-+ unsigned int sample_bits =
-+ snd_pcm_format_physical_width(params_format(params));
-+
-+ return snd_soc_dai_set_bclk_ratio(cpu_dai, sample_bits * 2);
-+}
-+
-+/* machine stream operations */
-+static struct snd_soc_ops snd_rpi_hifiberry_dac_ops = {
-+ .hw_params = snd_rpi_hifiberry_dac_hw_params,
-+};
-+
-+static struct snd_soc_dai_link snd_rpi_hifiberry_dac_dai[] = {
-+{
-+ .name = "HifiBerry DAC",
-+ .stream_name = "HifiBerry DAC HiFi",
-+ .cpu_dai_name = "bcm2708-i2s.0",
-+ .codec_dai_name = "pcm5102a-hifi",
-+ .platform_name = "bcm2708-i2s.0",
-+ .codec_name = "pcm5102a-codec",
-+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-+ SND_SOC_DAIFMT_CBS_CFS,
-+ .ops = &snd_rpi_hifiberry_dac_ops,
-+ .init = snd_rpi_hifiberry_dac_init,
-+},
-+};
-+
-+/* audio machine driver */
-+static struct snd_soc_card snd_rpi_hifiberry_dac = {
-+ .name = "snd_rpi_hifiberry_dac",
-+ .dai_link = snd_rpi_hifiberry_dac_dai,
-+ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dac_dai),
-+};
-+
-+static int snd_rpi_hifiberry_dac_probe(struct platform_device *pdev)
-+{
-+ int ret = 0;
-+
-+ snd_rpi_hifiberry_dac.dev = &pdev->dev;
-+
-+ if (pdev->dev.of_node) {
-+ struct device_node *i2s_node;
-+ struct snd_soc_dai_link *dai = &snd_rpi_hifiberry_dac_dai[0];
-+ i2s_node = of_parse_phandle(pdev->dev.of_node,
-+ "i2s-controller", 0);
-+
-+ if (i2s_node) {
-+ dai->cpu_dai_name = NULL;
-+ dai->cpu_of_node = i2s_node;
-+ dai->platform_name = NULL;
-+ dai->platform_of_node = i2s_node;
-+ }
-+ }
-+
-+ ret = snd_soc_register_card(&snd_rpi_hifiberry_dac);
-+ if (ret)
-+ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret);
-+
-+ return ret;
-+}
-+
-+static int snd_rpi_hifiberry_dac_remove(struct platform_device *pdev)
-+{
-+ return snd_soc_unregister_card(&snd_rpi_hifiberry_dac);
-+}
-+
-+static const struct of_device_id snd_rpi_hifiberry_dac_of_match[] = {
-+ { .compatible = "hifiberry,hifiberry-dac", },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_dac_of_match);
-+
-+static struct platform_driver snd_rpi_hifiberry_dac_driver = {
-+ .driver = {
-+ .name = "snd-hifiberry-dac",
-+ .owner = THIS_MODULE,
-+ .of_match_table = snd_rpi_hifiberry_dac_of_match,
-+ },
-+ .probe = snd_rpi_hifiberry_dac_probe,
-+ .remove = snd_rpi_hifiberry_dac_remove,
-+};
-+
-+module_platform_driver(snd_rpi_hifiberry_dac_driver);
-+
-+MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
-+MODULE_DESCRIPTION("ASoC Driver for HifiBerry DAC");
-+MODULE_LICENSE("GPL v2");
diff --git a/target/linux/brcm2708/patches-4.4/0064-ASoC-Add-support-for-Rpi-DAC.patch b/target/linux/brcm2708/patches-4.4/0064-ASoC-Add-support-for-Rpi-DAC.patch
new file mode 100644
index 0000000000..fd2e78fa91
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0064-ASoC-Add-support-for-Rpi-DAC.patch
@@ -0,0 +1,275 @@
+From 2f681005c89b65de1a2aa1426a41cc7b9e243c74 Mon Sep 17 00:00:00 2001
+From: Florian Meier <florian.meier@koalo.de>
+Date: Fri, 22 Nov 2013 19:21:34 +0100
+Subject: [PATCH 064/381] ASoC: Add support for Rpi-DAC
+
+---
+ sound/soc/bcm/Kconfig | 7 +++
+ sound/soc/bcm/Makefile | 2 +
+ sound/soc/bcm/rpi-dac.c | 118 ++++++++++++++++++++++++++++++++++++++++++++
+ sound/soc/codecs/Kconfig | 9 ++++
+ sound/soc/codecs/Makefile | 2 +
+ sound/soc/codecs/pcm1794a.c | 69 ++++++++++++++++++++++++++
+ 6 files changed, 207 insertions(+)
+ create mode 100644 sound/soc/bcm/rpi-dac.c
+ create mode 100644 sound/soc/codecs/pcm1794a.c
+
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -14,3 +14,10 @@ config SND_BCM2708_SOC_HIFIBERRY_DAC
+ select SND_SOC_PCM5102A
+ help
+ Say Y or M if you want to add support for HifiBerry DAC.
++
++config SND_BCM2708_SOC_RPI_DAC
++ tristate "Support for RPi-DAC"
++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
++ select SND_SOC_PCM1794A
++ help
++ Say Y or M if you want to add support for RPi-DAC.
+--- a/sound/soc/bcm/Makefile
++++ b/sound/soc/bcm/Makefile
+@@ -5,5 +5,7 @@ obj-$(CONFIG_SND_BCM2835_SOC_I2S) += snd
+
+ # BCM2708 Machine Support
+ snd-soc-hifiberry-dac-objs := hifiberry_dac.o
++snd-soc-rpi-dac-objs := rpi-dac.o
+
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o
++obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o
+--- /dev/null
++++ b/sound/soc/bcm/rpi-dac.c
+@@ -0,0 +1,118 @@
++/*
++ * ASoC Driver for RPi-DAC.
++ *
++ * Author: Florian Meier <florian.meier@koalo.de>
++ * Copyright 2013
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/jack.h>
++
++static int snd_rpi_rpi_dac_init(struct snd_soc_pcm_runtime *rtd)
++{
++ return 0;
++}
++
++static int snd_rpi_rpi_dac_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
++
++ return snd_soc_dai_set_bclk_ratio(cpu_dai, 32*2);
++}
++
++/* machine stream operations */
++static struct snd_soc_ops snd_rpi_rpi_dac_ops = {
++ .hw_params = snd_rpi_rpi_dac_hw_params,
++};
++
++static struct snd_soc_dai_link snd_rpi_rpi_dac_dai[] = {
++{
++ .name = "RPi-DAC",
++ .stream_name = "RPi-DAC HiFi",
++ .cpu_dai_name = "bcm2708-i2s.0",
++ .codec_dai_name = "pcm1794a-hifi",
++ .platform_name = "bcm2708-i2s.0",
++ .codec_name = "pcm1794a-codec",
++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBS_CFS,
++ .ops = &snd_rpi_rpi_dac_ops,
++ .init = snd_rpi_rpi_dac_init,
++},
++};
++
++/* audio machine driver */
++static struct snd_soc_card snd_rpi_rpi_dac = {
++ .name = "snd_rpi_rpi_dac",
++ .dai_link = snd_rpi_rpi_dac_dai,
++ .num_links = ARRAY_SIZE(snd_rpi_rpi_dac_dai),
++};
++
++static int snd_rpi_rpi_dac_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++
++ snd_rpi_rpi_dac.dev = &pdev->dev;
++
++ if (pdev->dev.of_node) {
++ struct device_node *i2s_node;
++ struct snd_soc_dai_link *dai = &snd_rpi_rpi_dac_dai[0];
++ i2s_node = of_parse_phandle(pdev->dev.of_node, "i2s-controller", 0);
++
++ if (i2s_node) {
++ dai->cpu_dai_name = NULL;
++ dai->cpu_of_node = i2s_node;
++ dai->platform_name = NULL;
++ dai->platform_of_node = i2s_node;
++ }
++ }
++
++ ret = snd_soc_register_card(&snd_rpi_rpi_dac);
++ if (ret)
++ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret);
++
++ return ret;
++}
++
++static int snd_rpi_rpi_dac_remove(struct platform_device *pdev)
++{
++ return snd_soc_unregister_card(&snd_rpi_rpi_dac);
++}
++
++static const struct of_device_id snd_rpi_rpi_dac_of_match[] = {
++ { .compatible = "rpi,rpi-dac", },
++ {},
++};
++MODULE_DEVICE_TABLE(of, snd_rpi_rpi_dac_of_match);
++
++static struct platform_driver snd_rpi_rpi_dac_driver = {
++ .driver = {
++ .name = "snd-rpi-dac",
++ .owner = THIS_MODULE,
++ .of_match_table = snd_rpi_rpi_dac_of_match,
++ },
++ .probe = snd_rpi_rpi_dac_probe,
++ .remove = snd_rpi_rpi_dac_remove,
++};
++
++module_platform_driver(snd_rpi_rpi_dac_driver);
++
++MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
++MODULE_DESCRIPTION("ASoC Driver for RPi-DAC");
++MODULE_LICENSE("GPL v2");
+--- a/sound/soc/codecs/Kconfig
++++ b/sound/soc/codecs/Kconfig
+@@ -90,6 +90,7 @@ config SND_SOC_ALL_CODECS
+ select SND_SOC_RT286 if I2C
+ select SND_SOC_RT298 if I2C
+ select SND_SOC_PCM5102A if I2C
++ select SND_SOC_PCM1794A if I2C
+ select SND_SOC_RT5631 if I2C
+ select SND_SOC_RT5640 if I2C
+ select SND_SOC_RT5645 if I2C
+@@ -550,6 +551,14 @@ config SND_SOC_RT298
+ tristate
+ depends on I2C
+
++config SND_SOC_RT298
++ tristate
++ depends on I2C
++
++config SND_SOC_PCM1794A
++ tristate
++ depends on I2C
++
+ config SND_SOC_PCM5102A
+ tristate
+ depends on I2C
+--- a/sound/soc/codecs/Makefile
++++ b/sound/soc/codecs/Makefile
+@@ -85,6 +85,7 @@ snd-soc-rl6231-objs := rl6231.o
+ snd-soc-rl6347a-objs := rl6347a.o
+ snd-soc-rt286-objs := rt286.o
+ snd-soc-rt298-objs := rt298.o
++snd-soc-pcm1794a-objs := pcm1794a.o
+ snd-soc-pcm5102a-objs := pcm5102a.o
+ snd-soc-rt5631-objs := rt5631.o
+ snd-soc-rt5640-objs := rt5640.o
+@@ -281,6 +282,7 @@ obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-
+ obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o
+ obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o
+ obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o
++obj-$(CONFIG_SND_SOC_PCM1794A) += snd-soc-pcm1794a.o
+ obj-$(CONFIG_SND_SOC_PCM5102A) += snd-soc-pcm5102a.o
+ obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o
+ obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o
+--- /dev/null
++++ b/sound/soc/codecs/pcm1794a.c
+@@ -0,0 +1,69 @@
++/*
++ * Driver for the PCM1794A codec
++ *
++ * Author: Florian Meier <florian.meier@koalo.de>
++ * Copyright 2013
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#include <sound/soc.h>
++
++static struct snd_soc_dai_driver pcm1794a_dai = {
++ .name = "pcm1794a-hifi",
++ .playback = {
++ .channels_min = 2,
++ .channels_max = 2,
++ .rates = SNDRV_PCM_RATE_8000_192000,
++ .formats = SNDRV_PCM_FMTBIT_S16_LE |
++ SNDRV_PCM_FMTBIT_S24_LE
++ },
++};
++
++static struct snd_soc_codec_driver soc_codec_dev_pcm1794a;
++
++static int pcm1794a_probe(struct platform_device *pdev)
++{
++ return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_pcm1794a,
++ &pcm1794a_dai, 1);
++}
++
++static int pcm1794a_remove(struct platform_device *pdev)
++{
++ snd_soc_unregister_codec(&pdev->dev);
++ return 0;
++}
++
++static const struct of_device_id pcm1794a_of_match[] = {
++ { .compatible = "ti,pcm1794a", },
++ { }
++};
++MODULE_DEVICE_TABLE(of, pcm1794a_of_match);
++
++static struct platform_driver pcm1794a_codec_driver = {
++ .probe = pcm1794a_probe,
++ .remove = pcm1794a_remove,
++ .driver = {
++ .name = "pcm1794a-codec",
++ .owner = THIS_MODULE,
++ .of_match_table = of_match_ptr(pcm1794a_of_match),
++ },
++};
++
++module_platform_driver(pcm1794a_codec_driver);
++
++MODULE_DESCRIPTION("ASoC PCM1794A codec driver");
++MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
++MODULE_LICENSE("GPL v2");
diff --git a/target/linux/brcm2708/patches-4.4/0065-ASoC-Add-support-for-Rpi-DAC.patch b/target/linux/brcm2708/patches-4.4/0065-ASoC-Add-support-for-Rpi-DAC.patch
deleted file mode 100644
index a2d8e5628c..0000000000
--- a/target/linux/brcm2708/patches-4.4/0065-ASoC-Add-support-for-Rpi-DAC.patch
+++ /dev/null
@@ -1,275 +0,0 @@
-From f16a654f57b024d44fe58d62b660e01de6a7811a Mon Sep 17 00:00:00 2001
-From: Florian Meier <florian.meier@koalo.de>
-Date: Fri, 22 Nov 2013 19:21:34 +0100
-Subject: [PATCH 065/170] ASoC: Add support for Rpi-DAC
-
----
- sound/soc/bcm/Kconfig | 7 +++
- sound/soc/bcm/Makefile | 2 +
- sound/soc/bcm/rpi-dac.c | 118 ++++++++++++++++++++++++++++++++++++++++++++
- sound/soc/codecs/Kconfig | 9 ++++
- sound/soc/codecs/Makefile | 2 +
- sound/soc/codecs/pcm1794a.c | 69 ++++++++++++++++++++++++++
- 6 files changed, 207 insertions(+)
- create mode 100644 sound/soc/bcm/rpi-dac.c
- create mode 100644 sound/soc/codecs/pcm1794a.c
-
---- a/sound/soc/bcm/Kconfig
-+++ b/sound/soc/bcm/Kconfig
-@@ -14,3 +14,10 @@ config SND_BCM2708_SOC_HIFIBERRY_DAC
- select SND_SOC_PCM5102A
- help
- Say Y or M if you want to add support for HifiBerry DAC.
-+
-+config SND_BCM2708_SOC_RPI_DAC
-+ tristate "Support for RPi-DAC"
-+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
-+ select SND_SOC_PCM1794A
-+ help
-+ Say Y or M if you want to add support for RPi-DAC.
---- a/sound/soc/bcm/Makefile
-+++ b/sound/soc/bcm/Makefile
-@@ -5,5 +5,7 @@ obj-$(CONFIG_SND_BCM2835_SOC_I2S) += snd
-
- # BCM2708 Machine Support
- snd-soc-hifiberry-dac-objs := hifiberry_dac.o
-+snd-soc-rpi-dac-objs := rpi-dac.o
-
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o
-+obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o
---- /dev/null
-+++ b/sound/soc/bcm/rpi-dac.c
-@@ -0,0 +1,118 @@
-+/*
-+ * ASoC Driver for RPi-DAC.
-+ *
-+ * Author: Florian Meier <florian.meier@koalo.de>
-+ * Copyright 2013
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+
-+#include <sound/core.h>
-+#include <sound/pcm.h>
-+#include <sound/pcm_params.h>
-+#include <sound/soc.h>
-+#include <sound/jack.h>
-+
-+static int snd_rpi_rpi_dac_init(struct snd_soc_pcm_runtime *rtd)
-+{
-+ return 0;
-+}
-+
-+static int snd_rpi_rpi_dac_hw_params(struct snd_pcm_substream *substream,
-+ struct snd_pcm_hw_params *params)
-+{
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-+
-+ return snd_soc_dai_set_bclk_ratio(cpu_dai, 32*2);
-+}
-+
-+/* machine stream operations */
-+static struct snd_soc_ops snd_rpi_rpi_dac_ops = {
-+ .hw_params = snd_rpi_rpi_dac_hw_params,
-+};
-+
-+static struct snd_soc_dai_link snd_rpi_rpi_dac_dai[] = {
-+{
-+ .name = "RPi-DAC",
-+ .stream_name = "RPi-DAC HiFi",
-+ .cpu_dai_name = "bcm2708-i2s.0",
-+ .codec_dai_name = "pcm1794a-hifi",
-+ .platform_name = "bcm2708-i2s.0",
-+ .codec_name = "pcm1794a-codec",
-+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-+ SND_SOC_DAIFMT_CBS_CFS,
-+ .ops = &snd_rpi_rpi_dac_ops,
-+ .init = snd_rpi_rpi_dac_init,
-+},
-+};
-+
-+/* audio machine driver */
-+static struct snd_soc_card snd_rpi_rpi_dac = {
-+ .name = "snd_rpi_rpi_dac",
-+ .dai_link = snd_rpi_rpi_dac_dai,
-+ .num_links = ARRAY_SIZE(snd_rpi_rpi_dac_dai),
-+};
-+
-+static int snd_rpi_rpi_dac_probe(struct platform_device *pdev)
-+{
-+ int ret = 0;
-+
-+ snd_rpi_rpi_dac.dev = &pdev->dev;
-+
-+ if (pdev->dev.of_node) {
-+ struct device_node *i2s_node;
-+ struct snd_soc_dai_link *dai = &snd_rpi_rpi_dac_dai[0];
-+ i2s_node = of_parse_phandle(pdev->dev.of_node, "i2s-controller", 0);
-+
-+ if (i2s_node) {
-+ dai->cpu_dai_name = NULL;
-+ dai->cpu_of_node = i2s_node;
-+ dai->platform_name = NULL;
-+ dai->platform_of_node = i2s_node;
-+ }
-+ }
-+
-+ ret = snd_soc_register_card(&snd_rpi_rpi_dac);
-+ if (ret)
-+ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret);
-+
-+ return ret;
-+}
-+
-+static int snd_rpi_rpi_dac_remove(struct platform_device *pdev)
-+{
-+ return snd_soc_unregister_card(&snd_rpi_rpi_dac);
-+}
-+
-+static const struct of_device_id snd_rpi_rpi_dac_of_match[] = {
-+ { .compatible = "rpi,rpi-dac", },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(of, snd_rpi_rpi_dac_of_match);
-+
-+static struct platform_driver snd_rpi_rpi_dac_driver = {
-+ .driver = {
-+ .name = "snd-rpi-dac",
-+ .owner = THIS_MODULE,
-+ .of_match_table = snd_rpi_rpi_dac_of_match,
-+ },
-+ .probe = snd_rpi_rpi_dac_probe,
-+ .remove = snd_rpi_rpi_dac_remove,
-+};
-+
-+module_platform_driver(snd_rpi_rpi_dac_driver);
-+
-+MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
-+MODULE_DESCRIPTION("ASoC Driver for RPi-DAC");
-+MODULE_LICENSE("GPL v2");
---- a/sound/soc/codecs/Kconfig
-+++ b/sound/soc/codecs/Kconfig
-@@ -90,6 +90,7 @@ config SND_SOC_ALL_CODECS
- select SND_SOC_RT286 if I2C
- select SND_SOC_RT298 if I2C
- select SND_SOC_PCM5102A if I2C
-+ select SND_SOC_PCM1794A if I2C
- select SND_SOC_RT5631 if I2C
- select SND_SOC_RT5640 if I2C
- select SND_SOC_RT5645 if I2C
-@@ -550,6 +551,14 @@ config SND_SOC_RT298
- tristate
- depends on I2C
-
-+config SND_SOC_RT298
-+ tristate
-+ depends on I2C
-+
-+config SND_SOC_PCM1794A
-+ tristate
-+ depends on I2C
-+
- config SND_SOC_PCM5102A
- tristate
- depends on I2C
---- a/sound/soc/codecs/Makefile
-+++ b/sound/soc/codecs/Makefile
-@@ -85,6 +85,7 @@ snd-soc-rl6231-objs := rl6231.o
- snd-soc-rl6347a-objs := rl6347a.o
- snd-soc-rt286-objs := rt286.o
- snd-soc-rt298-objs := rt298.o
-+snd-soc-pcm1794a-objs := pcm1794a.o
- snd-soc-pcm5102a-objs := pcm5102a.o
- snd-soc-rt5631-objs := rt5631.o
- snd-soc-rt5640-objs := rt5640.o
-@@ -281,6 +282,7 @@ obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-
- obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o
- obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o
- obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o
-+obj-$(CONFIG_SND_SOC_PCM1794A) += snd-soc-pcm1794a.o
- obj-$(CONFIG_SND_SOC_PCM5102A) += snd-soc-pcm5102a.o
- obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o
- obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o
---- /dev/null
-+++ b/sound/soc/codecs/pcm1794a.c
-@@ -0,0 +1,69 @@
-+/*
-+ * Driver for the PCM1794A codec
-+ *
-+ * Author: Florian Meier <florian.meier@koalo.de>
-+ * Copyright 2013
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ */
-+
-+
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+
-+#include <sound/soc.h>
-+
-+static struct snd_soc_dai_driver pcm1794a_dai = {
-+ .name = "pcm1794a-hifi",
-+ .playback = {
-+ .channels_min = 2,
-+ .channels_max = 2,
-+ .rates = SNDRV_PCM_RATE_8000_192000,
-+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
-+ SNDRV_PCM_FMTBIT_S24_LE
-+ },
-+};
-+
-+static struct snd_soc_codec_driver soc_codec_dev_pcm1794a;
-+
-+static int pcm1794a_probe(struct platform_device *pdev)
-+{
-+ return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_pcm1794a,
-+ &pcm1794a_dai, 1);
-+}
-+
-+static int pcm1794a_remove(struct platform_device *pdev)
-+{
-+ snd_soc_unregister_codec(&pdev->dev);
-+ return 0;
-+}
-+
-+static const struct of_device_id pcm1794a_of_match[] = {
-+ { .compatible = "ti,pcm1794a", },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(of, pcm1794a_of_match);
-+
-+static struct platform_driver pcm1794a_codec_driver = {
-+ .probe = pcm1794a_probe,
-+ .remove = pcm1794a_remove,
-+ .driver = {
-+ .name = "pcm1794a-codec",
-+ .owner = THIS_MODULE,
-+ .of_match_table = of_match_ptr(pcm1794a_of_match),
-+ },
-+};
-+
-+module_platform_driver(pcm1794a_codec_driver);
-+
-+MODULE_DESCRIPTION("ASoC PCM1794A codec driver");
-+MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
-+MODULE_LICENSE("GPL v2");
diff --git a/target/linux/brcm2708/patches-4.4/0065-ASoC-wm8804-Implement-MCLK-configuration-options-add.patch b/target/linux/brcm2708/patches-4.4/0065-ASoC-wm8804-Implement-MCLK-configuration-options-add.patch
new file mode 100644
index 0000000000..868156fcc7
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0065-ASoC-wm8804-Implement-MCLK-configuration-options-add.patch
@@ -0,0 +1,40 @@
+From e83ad608ca30c502633123ce317f7451491951c0 Mon Sep 17 00:00:00 2001
+From: Daniel Matuschek <info@crazy-audio.com>
+Date: Wed, 15 Jan 2014 21:41:23 +0100
+Subject: [PATCH 065/381] ASoC: wm8804: Implement MCLK configuration options,
+ add 32bit support WM8804 can run with PLL frequencies of 256xfs and 128xfs
+ for most sample rates. At 192kHz only 128xfs is supported. The existing
+ driver selects 128xfs automatically for some lower samples rates. By using an
+ additional mclk_div divider, it is now possible to control the behaviour.
+ This allows using 256xfs PLL frequency on all sample rates up to 96kHz. It
+ should allow lower jitter and better signal quality. The behavior has to be
+ controlled by the sound card driver, because some sample frequency share the
+ same setting. e.g. 192kHz and 96kHz use 24.576MHz master clock. The only
+ difference is the MCLK divider.
+
+This also added support for 32bit data.
+
+Signed-off-by: Daniel Matuschek <daniel@matuschek.net>
+---
+ sound/soc/codecs/wm8804.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/sound/soc/codecs/wm8804.c
++++ b/sound/soc/codecs/wm8804.c
+@@ -304,6 +304,7 @@ static int wm8804_hw_params(struct snd_p
+ blen = 0x1;
+ break;
+ case 24:
++ case 32:
+ blen = 0x2;
+ break;
+ default:
+@@ -515,7 +516,7 @@ static const struct snd_soc_dai_ops wm88
+ };
+
+ #define WM8804_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+- SNDRV_PCM_FMTBIT_S24_LE)
++ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+ #define WM8804_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \
diff --git a/target/linux/brcm2708/patches-4.4/0066-ASoC-BCM-Add-support-for-HiFiBerry-Digi.-Driver-is-b.patch b/target/linux/brcm2708/patches-4.4/0066-ASoC-BCM-Add-support-for-HiFiBerry-Digi.-Driver-is-b.patch
new file mode 100644
index 0000000000..efc387ce22
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0066-ASoC-BCM-Add-support-for-HiFiBerry-Digi.-Driver-is-b.patch
@@ -0,0 +1,282 @@
+From fb61baf20c890884a9e4f55da0f287f27f81a474 Mon Sep 17 00:00:00 2001
+From: Daniel Matuschek <info@crazy-audio.com>
+Date: Wed, 15 Jan 2014 21:42:08 +0100
+Subject: [PATCH 066/381] ASoC: BCM:Add support for HiFiBerry Digi. Driver is
+ based on the patched WM8804 driver.
+
+Signed-off-by: Daniel Matuschek <daniel@matuschek.net>
+
+Add a parameter to turn off SPDIF output if no audio is playing
+
+This patch adds the paramater auto_shutdown_output to the kernel module.
+Default behaviour of the module is the same, but when auto_shutdown_output
+is set to 1, the SPDIF oputput will shutdown if no stream is playing.
+
+bugfix for 32kHz sample rate, was missing
+
+HiFiBerry Digi: set SPDIF status bits for sample rate
+
+The HiFiBerry Digi driver did not signal the sample rate in the SPDIF status bits.
+While this is optional, some DACs and receivers do not accept this signal. This patch
+adds the sample rate bits in the SPDIF status block.
+---
+ sound/soc/bcm/Kconfig | 7 ++
+ sound/soc/bcm/Makefile | 2 +
+ sound/soc/bcm/hifiberry_digi.c | 223 +++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 232 insertions(+)
+ create mode 100644 sound/soc/bcm/hifiberry_digi.c
+
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -15,6 +15,13 @@ config SND_BCM2708_SOC_HIFIBERRY_DAC
+ help
+ Say Y or M if you want to add support for HifiBerry DAC.
+
++config SND_BCM2708_SOC_HIFIBERRY_DIGI
++ tristate "Support for HifiBerry Digi"
++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
++ select SND_SOC_WM8804
++ help
++ Say Y or M if you want to add support for HifiBerry Digi S/PDIF output board.
++
+ config SND_BCM2708_SOC_RPI_DAC
+ tristate "Support for RPi-DAC"
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+--- a/sound/soc/bcm/Makefile
++++ b/sound/soc/bcm/Makefile
+@@ -5,7 +5,9 @@ obj-$(CONFIG_SND_BCM2835_SOC_I2S) += snd
+
+ # BCM2708 Machine Support
+ snd-soc-hifiberry-dac-objs := hifiberry_dac.o
++snd-soc-hifiberry-digi-objs := hifiberry_digi.o
+ snd-soc-rpi-dac-objs := rpi-dac.o
+
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o
++obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o
+ obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o
+--- /dev/null
++++ b/sound/soc/bcm/hifiberry_digi.c
+@@ -0,0 +1,223 @@
++/*
++ * ASoC Driver for HifiBerry Digi
++ *
++ * Author: Daniel Matuschek <info@crazy-audio.com>
++ * based on the HifiBerry DAC driver by Florian Meier <florian.meier@koalo.de>
++ * Copyright 2013
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/jack.h>
++
++#include "../codecs/wm8804.h"
++
++static short int auto_shutdown_output = 0;
++module_param(auto_shutdown_output, short, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
++MODULE_PARM_DESC(auto_shutdown_output, "Shutdown SP/DIF output if playback is stopped");
++
++
++static int samplerate=44100;
++
++static int snd_rpi_hifiberry_digi_init(struct snd_soc_pcm_runtime *rtd)
++{
++ struct snd_soc_codec *codec = rtd->codec;
++
++ /* enable TX output */
++ snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, 0x0);
++
++ return 0;
++}
++
++static int snd_rpi_hifiberry_digi_startup(struct snd_pcm_substream *substream) {
++ /* turn on digital output */
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_codec *codec = rtd->codec;
++ snd_soc_update_bits(codec, WM8804_PWRDN, 0x3c, 0x00);
++ return 0;
++}
++
++static void snd_rpi_hifiberry_digi_shutdown(struct snd_pcm_substream *substream) {
++ /* turn off output */
++ if (auto_shutdown_output) {
++ /* turn off output */
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_codec *codec = rtd->codec;
++ snd_soc_update_bits(codec, WM8804_PWRDN, 0x3c, 0x3c);
++ }
++}
++
++
++static int snd_rpi_hifiberry_digi_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_dai *codec_dai = rtd->codec_dai;
++ struct snd_soc_codec *codec = rtd->codec;
++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
++
++ int sysclk = 27000000; /* This is fixed on this board */
++
++ long mclk_freq=0;
++ int mclk_div=1;
++ int sampling_freq=1;
++
++ int ret;
++
++ samplerate = params_rate(params);
++
++ if (samplerate<=96000) {
++ mclk_freq=samplerate*256;
++ mclk_div=WM8804_MCLKDIV_256FS;
++ } else {
++ mclk_freq=samplerate*128;
++ mclk_div=WM8804_MCLKDIV_128FS;
++ }
++
++ switch (samplerate) {
++ case 32000:
++ sampling_freq=0x03;
++ break;
++ case 44100:
++ sampling_freq=0x00;
++ break;
++ case 48000:
++ sampling_freq=0x02;
++ break;
++ case 88200:
++ sampling_freq=0x08;
++ break;
++ case 96000:
++ sampling_freq=0x0a;
++ break;
++ case 176400:
++ sampling_freq=0x0c;
++ break;
++ case 192000:
++ sampling_freq=0x0e;
++ break;
++ default:
++ dev_err(codec->dev,
++ "Failed to set WM8804 SYSCLK, unsupported samplerate %d\n",
++ samplerate);
++ }
++
++ snd_soc_dai_set_clkdiv(codec_dai, WM8804_MCLK_DIV, mclk_div);
++ snd_soc_dai_set_pll(codec_dai, 0, 0, sysclk, mclk_freq);
++
++ ret = snd_soc_dai_set_sysclk(codec_dai, WM8804_TX_CLKSRC_PLL,
++ sysclk, SND_SOC_CLOCK_OUT);
++ if (ret < 0) {
++ dev_err(codec->dev,
++ "Failed to set WM8804 SYSCLK: %d\n", ret);
++ return ret;
++ }
++
++ /* Enable TX output */
++ snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, 0x0);
++
++ /* Power on */
++ snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0);
++
++ /* set sampling frequency status bits */
++ snd_soc_update_bits(codec, WM8804_SPDTX4, 0x0f, sampling_freq);
++
++ return snd_soc_dai_set_bclk_ratio(cpu_dai,64);
++}
++
++/* machine stream operations */
++static struct snd_soc_ops snd_rpi_hifiberry_digi_ops = {
++ .hw_params = snd_rpi_hifiberry_digi_hw_params,
++ .startup = snd_rpi_hifiberry_digi_startup,
++ .shutdown = snd_rpi_hifiberry_digi_shutdown,
++};
++
++static struct snd_soc_dai_link snd_rpi_hifiberry_digi_dai[] = {
++{
++ .name = "HifiBerry Digi",
++ .stream_name = "HifiBerry Digi HiFi",
++ .cpu_dai_name = "bcm2708-i2s.0",
++ .codec_dai_name = "wm8804-spdif",
++ .platform_name = "bcm2708-i2s.0",
++ .codec_name = "wm8804.1-003b",
++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBM_CFM,
++ .ops = &snd_rpi_hifiberry_digi_ops,
++ .init = snd_rpi_hifiberry_digi_init,
++},
++};
++
++/* audio machine driver */
++static struct snd_soc_card snd_rpi_hifiberry_digi = {
++ .name = "snd_rpi_hifiberry_digi",
++ .dai_link = snd_rpi_hifiberry_digi_dai,
++ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_digi_dai),
++};
++
++static int snd_rpi_hifiberry_digi_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++
++ snd_rpi_hifiberry_digi.dev = &pdev->dev;
++
++ if (pdev->dev.of_node) {
++ struct device_node *i2s_node;
++ struct snd_soc_dai_link *dai = &snd_rpi_hifiberry_digi_dai[0];
++ i2s_node = of_parse_phandle(pdev->dev.of_node,
++ "i2s-controller", 0);
++
++ if (i2s_node) {
++ dai->cpu_dai_name = NULL;
++ dai->cpu_of_node = i2s_node;
++ dai->platform_name = NULL;
++ dai->platform_of_node = i2s_node;
++ }
++ }
++
++ ret = snd_soc_register_card(&snd_rpi_hifiberry_digi);
++ if (ret)
++ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret);
++
++ return ret;
++}
++
++static int snd_rpi_hifiberry_digi_remove(struct platform_device *pdev)
++{
++ return snd_soc_unregister_card(&snd_rpi_hifiberry_digi);
++}
++
++static const struct of_device_id snd_rpi_hifiberry_digi_of_match[] = {
++ { .compatible = "hifiberry,hifiberry-digi", },
++ {},
++};
++MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_digi_of_match);
++
++static struct platform_driver snd_rpi_hifiberry_digi_driver = {
++ .driver = {
++ .name = "snd-hifiberry-digi",
++ .owner = THIS_MODULE,
++ .of_match_table = snd_rpi_hifiberry_digi_of_match,
++ },
++ .probe = snd_rpi_hifiberry_digi_probe,
++ .remove = snd_rpi_hifiberry_digi_remove,
++};
++
++module_platform_driver(snd_rpi_hifiberry_digi_driver);
++
++MODULE_AUTHOR("Daniel Matuschek <info@crazy-audio.com>");
++MODULE_DESCRIPTION("ASoC Driver for HifiBerry Digi");
++MODULE_LICENSE("GPL v2");
diff --git a/target/linux/brcm2708/patches-4.4/0066-ASoC-wm8804-Implement-MCLK-configuration-options-add.patch b/target/linux/brcm2708/patches-4.4/0066-ASoC-wm8804-Implement-MCLK-configuration-options-add.patch
deleted file mode 100644
index 3404a2f08f..0000000000
--- a/target/linux/brcm2708/patches-4.4/0066-ASoC-wm8804-Implement-MCLK-configuration-options-add.patch
+++ /dev/null
@@ -1,40 +0,0 @@
-From dbdeca565b0850da182d3bd0b3ed41f667ca8a45 Mon Sep 17 00:00:00 2001
-From: Daniel Matuschek <info@crazy-audio.com>
-Date: Wed, 15 Jan 2014 21:41:23 +0100
-Subject: [PATCH 066/170] ASoC: wm8804: Implement MCLK configuration options,
- add 32bit support WM8804 can run with PLL frequencies of 256xfs and 128xfs
- for most sample rates. At 192kHz only 128xfs is supported. The existing
- driver selects 128xfs automatically for some lower samples rates. By using an
- additional mclk_div divider, it is now possible to control the behaviour.
- This allows using 256xfs PLL frequency on all sample rates up to 96kHz. It
- should allow lower jitter and better signal quality. The behavior has to be
- controlled by the sound card driver, because some sample frequency share the
- same setting. e.g. 192kHz and 96kHz use 24.576MHz master clock. The only
- difference is the MCLK divider.
-
-This also added support for 32bit data.
-
-Signed-off-by: Daniel Matuschek <daniel@matuschek.net>
----
- sound/soc/codecs/wm8804.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/sound/soc/codecs/wm8804.c
-+++ b/sound/soc/codecs/wm8804.c
-@@ -304,6 +304,7 @@ static int wm8804_hw_params(struct snd_p
- blen = 0x1;
- break;
- case 24:
-+ case 32:
- blen = 0x2;
- break;
- default:
-@@ -515,7 +516,7 @@ static const struct snd_soc_dai_ops wm88
- };
-
- #define WM8804_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
-- SNDRV_PCM_FMTBIT_S24_LE)
-+ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
-
- #define WM8804_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
- SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \
diff --git a/target/linux/brcm2708/patches-4.4/0067-ASoC-BCM-Add-support-for-HiFiBerry-Digi.-Driver-is-b.patch b/target/linux/brcm2708/patches-4.4/0067-ASoC-BCM-Add-support-for-HiFiBerry-Digi.-Driver-is-b.patch
deleted file mode 100644
index 50e1e1957c..0000000000
--- a/target/linux/brcm2708/patches-4.4/0067-ASoC-BCM-Add-support-for-HiFiBerry-Digi.-Driver-is-b.patch
+++ /dev/null
@@ -1,282 +0,0 @@
-From 0c2e64d3eda229c2f52ce6ed9d0b1c1572dd9b19 Mon Sep 17 00:00:00 2001
-From: Daniel Matuschek <info@crazy-audio.com>
-Date: Wed, 15 Jan 2014 21:42:08 +0100
-Subject: [PATCH 067/170] ASoC: BCM:Add support for HiFiBerry Digi. Driver is
- based on the patched WM8804 driver.
-
-Signed-off-by: Daniel Matuschek <daniel@matuschek.net>
-
-Add a parameter to turn off SPDIF output if no audio is playing
-
-This patch adds the paramater auto_shutdown_output to the kernel module.
-Default behaviour of the module is the same, but when auto_shutdown_output
-is set to 1, the SPDIF oputput will shutdown if no stream is playing.
-
-bugfix for 32kHz sample rate, was missing
-
-HiFiBerry Digi: set SPDIF status bits for sample rate
-
-The HiFiBerry Digi driver did not signal the sample rate in the SPDIF status bits.
-While this is optional, some DACs and receivers do not accept this signal. This patch
-adds the sample rate bits in the SPDIF status block.
----
- sound/soc/bcm/Kconfig | 7 ++
- sound/soc/bcm/Makefile | 2 +
- sound/soc/bcm/hifiberry_digi.c | 223 +++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 232 insertions(+)
- create mode 100644 sound/soc/bcm/hifiberry_digi.c
-
---- a/sound/soc/bcm/Kconfig
-+++ b/sound/soc/bcm/Kconfig
-@@ -15,6 +15,13 @@ config SND_BCM2708_SOC_HIFIBERRY_DAC
- help
- Say Y or M if you want to add support for HifiBerry DAC.
-
-+config SND_BCM2708_SOC_HIFIBERRY_DIGI
-+ tristate "Support for HifiBerry Digi"
-+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
-+ select SND_SOC_WM8804
-+ help
-+ Say Y or M if you want to add support for HifiBerry Digi S/PDIF output board.
-+
- config SND_BCM2708_SOC_RPI_DAC
- tristate "Support for RPi-DAC"
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
---- a/sound/soc/bcm/Makefile
-+++ b/sound/soc/bcm/Makefile
-@@ -5,7 +5,9 @@ obj-$(CONFIG_SND_BCM2835_SOC_I2S) += snd
-
- # BCM2708 Machine Support
- snd-soc-hifiberry-dac-objs := hifiberry_dac.o
-+snd-soc-hifiberry-digi-objs := hifiberry_digi.o
- snd-soc-rpi-dac-objs := rpi-dac.o
-
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o
-+obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o
- obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o
---- /dev/null
-+++ b/sound/soc/bcm/hifiberry_digi.c
-@@ -0,0 +1,223 @@
-+/*
-+ * ASoC Driver for HifiBerry Digi
-+ *
-+ * Author: Daniel Matuschek <info@crazy-audio.com>
-+ * based on the HifiBerry DAC driver by Florian Meier <florian.meier@koalo.de>
-+ * Copyright 2013
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+
-+#include <sound/core.h>
-+#include <sound/pcm.h>
-+#include <sound/pcm_params.h>
-+#include <sound/soc.h>
-+#include <sound/jack.h>
-+
-+#include "../codecs/wm8804.h"
-+
-+static short int auto_shutdown_output = 0;
-+module_param(auto_shutdown_output, short, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
-+MODULE_PARM_DESC(auto_shutdown_output, "Shutdown SP/DIF output if playback is stopped");
-+
-+
-+static int samplerate=44100;
-+
-+static int snd_rpi_hifiberry_digi_init(struct snd_soc_pcm_runtime *rtd)
-+{
-+ struct snd_soc_codec *codec = rtd->codec;
-+
-+ /* enable TX output */
-+ snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, 0x0);
-+
-+ return 0;
-+}
-+
-+static int snd_rpi_hifiberry_digi_startup(struct snd_pcm_substream *substream) {
-+ /* turn on digital output */
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ struct snd_soc_codec *codec = rtd->codec;
-+ snd_soc_update_bits(codec, WM8804_PWRDN, 0x3c, 0x00);
-+ return 0;
-+}
-+
-+static void snd_rpi_hifiberry_digi_shutdown(struct snd_pcm_substream *substream) {
-+ /* turn off output */
-+ if (auto_shutdown_output) {
-+ /* turn off output */
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ struct snd_soc_codec *codec = rtd->codec;
-+ snd_soc_update_bits(codec, WM8804_PWRDN, 0x3c, 0x3c);
-+ }
-+}
-+
-+
-+static int snd_rpi_hifiberry_digi_hw_params(struct snd_pcm_substream *substream,
-+ struct snd_pcm_hw_params *params)
-+{
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
-+ struct snd_soc_codec *codec = rtd->codec;
-+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-+
-+ int sysclk = 27000000; /* This is fixed on this board */
-+
-+ long mclk_freq=0;
-+ int mclk_div=1;
-+ int sampling_freq=1;
-+
-+ int ret;
-+
-+ samplerate = params_rate(params);
-+
-+ if (samplerate<=96000) {
-+ mclk_freq=samplerate*256;
-+ mclk_div=WM8804_MCLKDIV_256FS;
-+ } else {
-+ mclk_freq=samplerate*128;
-+ mclk_div=WM8804_MCLKDIV_128FS;
-+ }
-+
-+ switch (samplerate) {
-+ case 32000:
-+ sampling_freq=0x03;
-+ break;
-+ case 44100:
-+ sampling_freq=0x00;
-+ break;
-+ case 48000:
-+ sampling_freq=0x02;
-+ break;
-+ case 88200:
-+ sampling_freq=0x08;
-+ break;
-+ case 96000:
-+ sampling_freq=0x0a;
-+ break;
-+ case 176400:
-+ sampling_freq=0x0c;
-+ break;
-+ case 192000:
-+ sampling_freq=0x0e;
-+ break;
-+ default:
-+ dev_err(codec->dev,
-+ "Failed to set WM8804 SYSCLK, unsupported samplerate %d\n",
-+ samplerate);
-+ }
-+
-+ snd_soc_dai_set_clkdiv(codec_dai, WM8804_MCLK_DIV, mclk_div);
-+ snd_soc_dai_set_pll(codec_dai, 0, 0, sysclk, mclk_freq);
-+
-+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8804_TX_CLKSRC_PLL,
-+ sysclk, SND_SOC_CLOCK_OUT);
-+ if (ret < 0) {
-+ dev_err(codec->dev,
-+ "Failed to set WM8804 SYSCLK: %d\n", ret);
-+ return ret;
-+ }
-+
-+ /* Enable TX output */
-+ snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, 0x0);
-+
-+ /* Power on */
-+ snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0);
-+
-+ /* set sampling frequency status bits */
-+ snd_soc_update_bits(codec, WM8804_SPDTX4, 0x0f, sampling_freq);
-+
-+ return snd_soc_dai_set_bclk_ratio(cpu_dai,64);
-+}
-+
-+/* machine stream operations */
-+static struct snd_soc_ops snd_rpi_hifiberry_digi_ops = {
-+ .hw_params = snd_rpi_hifiberry_digi_hw_params,
-+ .startup = snd_rpi_hifiberry_digi_startup,
-+ .shutdown = snd_rpi_hifiberry_digi_shutdown,
-+};
-+
-+static struct snd_soc_dai_link snd_rpi_hifiberry_digi_dai[] = {
-+{
-+ .name = "HifiBerry Digi",
-+ .stream_name = "HifiBerry Digi HiFi",
-+ .cpu_dai_name = "bcm2708-i2s.0",
-+ .codec_dai_name = "wm8804-spdif",
-+ .platform_name = "bcm2708-i2s.0",
-+ .codec_name = "wm8804.1-003b",
-+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-+ SND_SOC_DAIFMT_CBM_CFM,
-+ .ops = &snd_rpi_hifiberry_digi_ops,
-+ .init = snd_rpi_hifiberry_digi_init,
-+},
-+};
-+
-+/* audio machine driver */
-+static struct snd_soc_card snd_rpi_hifiberry_digi = {
-+ .name = "snd_rpi_hifiberry_digi",
-+ .dai_link = snd_rpi_hifiberry_digi_dai,
-+ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_digi_dai),
-+};
-+
-+static int snd_rpi_hifiberry_digi_probe(struct platform_device *pdev)
-+{
-+ int ret = 0;
-+
-+ snd_rpi_hifiberry_digi.dev = &pdev->dev;
-+
-+ if (pdev->dev.of_node) {
-+ struct device_node *i2s_node;
-+ struct snd_soc_dai_link *dai = &snd_rpi_hifiberry_digi_dai[0];
-+ i2s_node = of_parse_phandle(pdev->dev.of_node,
-+ "i2s-controller", 0);
-+
-+ if (i2s_node) {
-+ dai->cpu_dai_name = NULL;
-+ dai->cpu_of_node = i2s_node;
-+ dai->platform_name = NULL;
-+ dai->platform_of_node = i2s_node;
-+ }
-+ }
-+
-+ ret = snd_soc_register_card(&snd_rpi_hifiberry_digi);
-+ if (ret)
-+ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret);
-+
-+ return ret;
-+}
-+
-+static int snd_rpi_hifiberry_digi_remove(struct platform_device *pdev)
-+{
-+ return snd_soc_unregister_card(&snd_rpi_hifiberry_digi);
-+}
-+
-+static const struct of_device_id snd_rpi_hifiberry_digi_of_match[] = {
-+ { .compatible = "hifiberry,hifiberry-digi", },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_digi_of_match);
-+
-+static struct platform_driver snd_rpi_hifiberry_digi_driver = {
-+ .driver = {
-+ .name = "snd-hifiberry-digi",
-+ .owner = THIS_MODULE,
-+ .of_match_table = snd_rpi_hifiberry_digi_of_match,
-+ },
-+ .probe = snd_rpi_hifiberry_digi_probe,
-+ .remove = snd_rpi_hifiberry_digi_remove,
-+};
-+
-+module_platform_driver(snd_rpi_hifiberry_digi_driver);
-+
-+MODULE_AUTHOR("Daniel Matuschek <info@crazy-audio.com>");
-+MODULE_DESCRIPTION("ASoC Driver for HifiBerry Digi");
-+MODULE_LICENSE("GPL v2");
diff --git a/target/linux/brcm2708/patches-4.4/0067-ASoC-wm8804-Set-idle_bias_off-to-false-Idle-bias-has.patch b/target/linux/brcm2708/patches-4.4/0067-ASoC-wm8804-Set-idle_bias_off-to-false-Idle-bias-has.patch
new file mode 100644
index 0000000000..87dd6d898e
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0067-ASoC-wm8804-Set-idle_bias_off-to-false-Idle-bias-has.patch
@@ -0,0 +1,22 @@
+From cf98984028b036971f95671070806136d865b96e Mon Sep 17 00:00:00 2001
+From: Daniel Matuschek <info@crazy-audio.com>
+Date: Thu, 16 Jan 2014 07:36:35 +0100
+Subject: [PATCH 067/381] ASoC: wm8804: Set idle_bias_off to false Idle bias
+ has been change to remove warning on driver startup
+
+Signed-off-by: Daniel Matuschek <daniel@matuschek.net>
+---
+ sound/soc/codecs/wm8804.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/sound/soc/codecs/wm8804.c
++++ b/sound/soc/codecs/wm8804.c
+@@ -544,7 +544,7 @@ static struct snd_soc_dai_driver wm8804_
+ };
+
+ static const struct snd_soc_codec_driver soc_codec_dev_wm8804 = {
+- .idle_bias_off = true,
++ .idle_bias_off = false,
+
+ .dapm_widgets = wm8804_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(wm8804_dapm_widgets),
diff --git a/target/linux/brcm2708/patches-4.4/0068-ASoC-wm8804-Set-idle_bias_off-to-false-Idle-bias-has.patch b/target/linux/brcm2708/patches-4.4/0068-ASoC-wm8804-Set-idle_bias_off-to-false-Idle-bias-has.patch
deleted file mode 100644
index cc82f7523f..0000000000
--- a/target/linux/brcm2708/patches-4.4/0068-ASoC-wm8804-Set-idle_bias_off-to-false-Idle-bias-has.patch
+++ /dev/null
@@ -1,22 +0,0 @@
-From f2789622ff7c1297e28f38bb198f5fd24b4602ef Mon Sep 17 00:00:00 2001
-From: Daniel Matuschek <info@crazy-audio.com>
-Date: Thu, 16 Jan 2014 07:36:35 +0100
-Subject: [PATCH 068/170] ASoC: wm8804: Set idle_bias_off to false Idle bias
- has been change to remove warning on driver startup
-
-Signed-off-by: Daniel Matuschek <daniel@matuschek.net>
----
- sound/soc/codecs/wm8804.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/sound/soc/codecs/wm8804.c
-+++ b/sound/soc/codecs/wm8804.c
-@@ -544,7 +544,7 @@ static struct snd_soc_dai_driver wm8804_
- };
-
- static const struct snd_soc_codec_driver soc_codec_dev_wm8804 = {
-- .idle_bias_off = true,
-+ .idle_bias_off = false,
-
- .dapm_widgets = wm8804_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(wm8804_dapm_widgets),
diff --git a/target/linux/brcm2708/patches-4.4/0068-Add-IQaudIO-Sound-Card-support-for-Raspberry-Pi.patch b/target/linux/brcm2708/patches-4.4/0068-Add-IQaudIO-Sound-Card-support-for-Raspberry-Pi.patch
new file mode 100644
index 0000000000..2fc38efd0e
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0068-Add-IQaudIO-Sound-Card-support-for-Raspberry-Pi.patch
@@ -0,0 +1,178 @@
+From f0fc1c656af73bbfc2984e0bb6b90b27bac1a532 Mon Sep 17 00:00:00 2001
+From: Gordon Garrity <gordon@iqaudio.com>
+Date: Sat, 8 Mar 2014 16:56:57 +0000
+Subject: [PATCH 068/381] Add IQaudIO Sound Card support for Raspberry Pi
+
+Set a limit of 0dB on Digital Volume Control
+
+The main volume control in the PCM512x DAC has a range up to
++24dB. This is dangerously loud and can potentially cause massive
+clipping in the output stages. Therefore this sets a sensible
+limit of 0dB for this control.
+---
+ sound/soc/bcm/Kconfig | 7 +++
+ sound/soc/bcm/Makefile | 2 +
+ sound/soc/bcm/iqaudio-dac.c | 132 ++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 141 insertions(+)
+ create mode 100644 sound/soc/bcm/iqaudio-dac.c
+
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -28,3 +28,10 @@ config SND_BCM2708_SOC_RPI_DAC
+ select SND_SOC_PCM1794A
+ help
+ Say Y or M if you want to add support for RPi-DAC.
++
++config SND_BCM2708_SOC_IQAUDIO_DAC
++ tristate "Support for IQaudIO-DAC"
++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
++ select SND_SOC_PCM512x_I2C
++ help
++ Say Y or M if you want to add support for IQaudIO-DAC.
+--- a/sound/soc/bcm/Makefile
++++ b/sound/soc/bcm/Makefile
+@@ -7,7 +7,9 @@ obj-$(CONFIG_SND_BCM2835_SOC_I2S) += snd
+ snd-soc-hifiberry-dac-objs := hifiberry_dac.o
+ snd-soc-hifiberry-digi-objs := hifiberry_digi.o
+ snd-soc-rpi-dac-objs := rpi-dac.o
++snd-soc-iqaudio-dac-objs := iqaudio-dac.o
+
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o
+ obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o
++obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
+--- /dev/null
++++ b/sound/soc/bcm/iqaudio-dac.c
+@@ -0,0 +1,132 @@
++/*
++ * ASoC Driver for IQaudIO DAC
++ *
++ * Author: Florian Meier <florian.meier@koalo.de>
++ * Copyright 2013
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/jack.h>
++
++static int snd_rpi_iqaudio_dac_init(struct snd_soc_pcm_runtime *rtd)
++{
++ int ret;
++ struct snd_soc_card *card = rtd->card;
++
++ ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207);
++ if (ret < 0)
++ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
++
++ return 0;
++}
++
++static int snd_rpi_iqaudio_dac_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++// NOT USED struct snd_soc_dai *codec_dai = rtd->codec_dai;
++// NOT USED struct snd_soc_codec *codec = rtd->codec;
++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
++
++ unsigned int sample_bits =
++ snd_pcm_format_physical_width(params_format(params));
++
++ return snd_soc_dai_set_bclk_ratio(cpu_dai, sample_bits * 2);
++}
++
++/* machine stream operations */
++static struct snd_soc_ops snd_rpi_iqaudio_dac_ops = {
++ .hw_params = snd_rpi_iqaudio_dac_hw_params,
++};
++
++static struct snd_soc_dai_link snd_rpi_iqaudio_dac_dai[] = {
++{
++ .name = "IQaudIO DAC",
++ .stream_name = "IQaudIO DAC HiFi",
++ .cpu_dai_name = "bcm2708-i2s.0",
++ .codec_dai_name = "pcm512x-hifi",
++ .platform_name = "bcm2708-i2s.0",
++ .codec_name = "pcm512x.1-004c",
++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBS_CFS,
++ .ops = &snd_rpi_iqaudio_dac_ops,
++ .init = snd_rpi_iqaudio_dac_init,
++},
++};
++
++/* audio machine driver */
++static struct snd_soc_card snd_rpi_iqaudio_dac = {
++ .name = "IQaudIODAC",
++ .dai_link = snd_rpi_iqaudio_dac_dai,
++ .num_links = ARRAY_SIZE(snd_rpi_iqaudio_dac_dai),
++};
++
++static int snd_rpi_iqaudio_dac_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++
++ snd_rpi_iqaudio_dac.dev = &pdev->dev;
++
++ if (pdev->dev.of_node) {
++ struct device_node *i2s_node;
++ struct snd_soc_dai_link *dai = &snd_rpi_iqaudio_dac_dai[0];
++ i2s_node = of_parse_phandle(pdev->dev.of_node,
++ "i2s-controller", 0);
++
++ if (i2s_node) {
++ dai->cpu_dai_name = NULL;
++ dai->cpu_of_node = i2s_node;
++ dai->platform_name = NULL;
++ dai->platform_of_node = i2s_node;
++ }
++ }
++
++ ret = snd_soc_register_card(&snd_rpi_iqaudio_dac);
++ if (ret)
++ dev_err(&pdev->dev,
++ "snd_soc_register_card() failed: %d\n", ret);
++
++ return ret;
++}
++
++static int snd_rpi_iqaudio_dac_remove(struct platform_device *pdev)
++{
++ return snd_soc_unregister_card(&snd_rpi_iqaudio_dac);
++}
++
++static const struct of_device_id iqaudio_of_match[] = {
++ { .compatible = "iqaudio,iqaudio-dac", },
++ {},
++};
++MODULE_DEVICE_TABLE(of, iqaudio_of_match);
++
++static struct platform_driver snd_rpi_iqaudio_dac_driver = {
++ .driver = {
++ .name = "snd-rpi-iqaudio-dac",
++ .owner = THIS_MODULE,
++ .of_match_table = iqaudio_of_match,
++ },
++ .probe = snd_rpi_iqaudio_dac_probe,
++ .remove = snd_rpi_iqaudio_dac_remove,
++};
++
++module_platform_driver(snd_rpi_iqaudio_dac_driver);
++
++MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
++MODULE_DESCRIPTION("ASoC Driver for IQAudio DAC");
++MODULE_LICENSE("GPL v2");
diff --git a/target/linux/brcm2708/patches-4.4/0069-Add-IQaudIO-Sound-Card-support-for-Raspberry-Pi.patch b/target/linux/brcm2708/patches-4.4/0069-Add-IQaudIO-Sound-Card-support-for-Raspberry-Pi.patch
deleted file mode 100644
index 1c2e4e99a5..0000000000
--- a/target/linux/brcm2708/patches-4.4/0069-Add-IQaudIO-Sound-Card-support-for-Raspberry-Pi.patch
+++ /dev/null
@@ -1,178 +0,0 @@
-From 80fa31f923b4967bc86be20c5af780ef284fc972 Mon Sep 17 00:00:00 2001
-From: Gordon Garrity <gordon@iqaudio.com>
-Date: Sat, 8 Mar 2014 16:56:57 +0000
-Subject: [PATCH 069/170] Add IQaudIO Sound Card support for Raspberry Pi
-
-Set a limit of 0dB on Digital Volume Control
-
-The main volume control in the PCM512x DAC has a range up to
-+24dB. This is dangerously loud and can potentially cause massive
-clipping in the output stages. Therefore this sets a sensible
-limit of 0dB for this control.
----
- sound/soc/bcm/Kconfig | 7 +++
- sound/soc/bcm/Makefile | 2 +
- sound/soc/bcm/iqaudio-dac.c | 132 ++++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 141 insertions(+)
- create mode 100644 sound/soc/bcm/iqaudio-dac.c
-
---- a/sound/soc/bcm/Kconfig
-+++ b/sound/soc/bcm/Kconfig
-@@ -28,3 +28,10 @@ config SND_BCM2708_SOC_RPI_DAC
- select SND_SOC_PCM1794A
- help
- Say Y or M if you want to add support for RPi-DAC.
-+
-+config SND_BCM2708_SOC_IQAUDIO_DAC
-+ tristate "Support for IQaudIO-DAC"
-+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
-+ select SND_SOC_PCM512x_I2C
-+ help
-+ Say Y or M if you want to add support for IQaudIO-DAC.
---- a/sound/soc/bcm/Makefile
-+++ b/sound/soc/bcm/Makefile
-@@ -7,7 +7,9 @@ obj-$(CONFIG_SND_BCM2835_SOC_I2S) += snd
- snd-soc-hifiberry-dac-objs := hifiberry_dac.o
- snd-soc-hifiberry-digi-objs := hifiberry_digi.o
- snd-soc-rpi-dac-objs := rpi-dac.o
-+snd-soc-iqaudio-dac-objs := iqaudio-dac.o
-
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o
- obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o
-+obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
---- /dev/null
-+++ b/sound/soc/bcm/iqaudio-dac.c
-@@ -0,0 +1,132 @@
-+/*
-+ * ASoC Driver for IQaudIO DAC
-+ *
-+ * Author: Florian Meier <florian.meier@koalo.de>
-+ * Copyright 2013
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+
-+#include <sound/core.h>
-+#include <sound/pcm.h>
-+#include <sound/pcm_params.h>
-+#include <sound/soc.h>
-+#include <sound/jack.h>
-+
-+static int snd_rpi_iqaudio_dac_init(struct snd_soc_pcm_runtime *rtd)
-+{
-+ int ret;
-+ struct snd_soc_card *card = rtd->card;
-+
-+ ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207);
-+ if (ret < 0)
-+ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
-+
-+ return 0;
-+}
-+
-+static int snd_rpi_iqaudio_dac_hw_params(struct snd_pcm_substream *substream,
-+ struct snd_pcm_hw_params *params)
-+{
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+// NOT USED struct snd_soc_dai *codec_dai = rtd->codec_dai;
-+// NOT USED struct snd_soc_codec *codec = rtd->codec;
-+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-+
-+ unsigned int sample_bits =
-+ snd_pcm_format_physical_width(params_format(params));
-+
-+ return snd_soc_dai_set_bclk_ratio(cpu_dai, sample_bits * 2);
-+}
-+
-+/* machine stream operations */
-+static struct snd_soc_ops snd_rpi_iqaudio_dac_ops = {
-+ .hw_params = snd_rpi_iqaudio_dac_hw_params,
-+};
-+
-+static struct snd_soc_dai_link snd_rpi_iqaudio_dac_dai[] = {
-+{
-+ .name = "IQaudIO DAC",
-+ .stream_name = "IQaudIO DAC HiFi",
-+ .cpu_dai_name = "bcm2708-i2s.0",
-+ .codec_dai_name = "pcm512x-hifi",
-+ .platform_name = "bcm2708-i2s.0",
-+ .codec_name = "pcm512x.1-004c",
-+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-+ SND_SOC_DAIFMT_CBS_CFS,
-+ .ops = &snd_rpi_iqaudio_dac_ops,
-+ .init = snd_rpi_iqaudio_dac_init,
-+},
-+};
-+
-+/* audio machine driver */
-+static struct snd_soc_card snd_rpi_iqaudio_dac = {
-+ .name = "IQaudIODAC",
-+ .dai_link = snd_rpi_iqaudio_dac_dai,
-+ .num_links = ARRAY_SIZE(snd_rpi_iqaudio_dac_dai),
-+};
-+
-+static int snd_rpi_iqaudio_dac_probe(struct platform_device *pdev)
-+{
-+ int ret = 0;
-+
-+ snd_rpi_iqaudio_dac.dev = &pdev->dev;
-+
-+ if (pdev->dev.of_node) {
-+ struct device_node *i2s_node;
-+ struct snd_soc_dai_link *dai = &snd_rpi_iqaudio_dac_dai[0];
-+ i2s_node = of_parse_phandle(pdev->dev.of_node,
-+ "i2s-controller", 0);
-+
-+ if (i2s_node) {
-+ dai->cpu_dai_name = NULL;
-+ dai->cpu_of_node = i2s_node;
-+ dai->platform_name = NULL;
-+ dai->platform_of_node = i2s_node;
-+ }
-+ }
-+
-+ ret = snd_soc_register_card(&snd_rpi_iqaudio_dac);
-+ if (ret)
-+ dev_err(&pdev->dev,
-+ "snd_soc_register_card() failed: %d\n", ret);
-+
-+ return ret;
-+}
-+
-+static int snd_rpi_iqaudio_dac_remove(struct platform_device *pdev)
-+{
-+ return snd_soc_unregister_card(&snd_rpi_iqaudio_dac);
-+}
-+
-+static const struct of_device_id iqaudio_of_match[] = {
-+ { .compatible = "iqaudio,iqaudio-dac", },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(of, iqaudio_of_match);
-+
-+static struct platform_driver snd_rpi_iqaudio_dac_driver = {
-+ .driver = {
-+ .name = "snd-rpi-iqaudio-dac",
-+ .owner = THIS_MODULE,
-+ .of_match_table = iqaudio_of_match,
-+ },
-+ .probe = snd_rpi_iqaudio_dac_probe,
-+ .remove = snd_rpi_iqaudio_dac_remove,
-+};
-+
-+module_platform_driver(snd_rpi_iqaudio_dac_driver);
-+
-+MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
-+MODULE_DESCRIPTION("ASoC Driver for IQAudio DAC");
-+MODULE_LICENSE("GPL v2");
diff --git a/target/linux/brcm2708/patches-4.4/0069-hid-Reduce-default-mouse-polling-interval-to-60Hz.patch b/target/linux/brcm2708/patches-4.4/0069-hid-Reduce-default-mouse-polling-interval-to-60Hz.patch
new file mode 100644
index 0000000000..c3186f518b
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0069-hid-Reduce-default-mouse-polling-interval-to-60Hz.patch
@@ -0,0 +1,36 @@
+From d549bf5e41199399f174701b0f303b385d52beaf Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Mon, 14 Jul 2014 22:02:09 +0100
+Subject: [PATCH 069/381] hid: Reduce default mouse polling interval to 60Hz
+
+Reduces overhead when using X
+---
+ drivers/hid/usbhid/hid-core.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+--- a/drivers/hid/usbhid/hid-core.c
++++ b/drivers/hid/usbhid/hid-core.c
+@@ -49,7 +49,7 @@
+ * Module parameters.
+ */
+
+-static unsigned int hid_mousepoll_interval;
++static unsigned int hid_mousepoll_interval = ~0;
+ module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644);
+ MODULE_PARM_DESC(mousepoll, "Polling interval of mice");
+
+@@ -1083,8 +1083,12 @@ static int usbhid_start(struct hid_devic
+ }
+
+ /* Change the polling interval of mice. */
+- if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0)
+- interval = hid_mousepoll_interval;
++ if (hid->collection->usage == HID_GD_MOUSE) {
++ if (hid_mousepoll_interval == ~0 && interval < 16)
++ interval = 16;
++ else if (hid_mousepoll_interval != ~0 && hid_mousepoll_interval != 0)
++ interval = hid_mousepoll_interval;
++ }
+
+ ret = -ENOMEM;
+ if (usb_endpoint_dir_in(endpoint)) {
diff --git a/target/linux/brcm2708/patches-4.4/0070-Added-support-for-HiFiBerry-DAC.patch b/target/linux/brcm2708/patches-4.4/0070-Added-support-for-HiFiBerry-DAC.patch
new file mode 100644
index 0000000000..894efc40d2
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0070-Added-support-for-HiFiBerry-DAC.patch
@@ -0,0 +1,190 @@
+From 03107b2243e688b6c98042d0fd9416db2bd241f6 Mon Sep 17 00:00:00 2001
+From: Daniel Matuschek <info@crazy-audio.com>
+Date: Mon, 4 Aug 2014 10:06:56 +0200
+Subject: [PATCH 070/381] Added support for HiFiBerry DAC+
+
+The driver is based on the HiFiBerry DAC driver. However HiFiBerry DAC+ uses
+a different codec chip (PCM5122), therefore a new driver is necessary.
+---
+ sound/soc/bcm/Kconfig | 7 ++
+ sound/soc/bcm/Makefile | 2 +
+ sound/soc/bcm/hifiberry_dacplus.c | 141 ++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 150 insertions(+)
+ create mode 100644 sound/soc/bcm/hifiberry_dacplus.c
+
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -15,6 +15,13 @@ config SND_BCM2708_SOC_HIFIBERRY_DAC
+ help
+ Say Y or M if you want to add support for HifiBerry DAC.
+
++config SND_BCM2708_SOC_HIFIBERRY_DACPLUS
++ tristate "Support for HifiBerry DAC+"
++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
++ select SND_SOC_PCM512x
++ help
++ Say Y or M if you want to add support for HifiBerry DAC+.
++
+ config SND_BCM2708_SOC_HIFIBERRY_DIGI
+ tristate "Support for HifiBerry Digi"
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+--- a/sound/soc/bcm/Makefile
++++ b/sound/soc/bcm/Makefile
+@@ -5,11 +5,13 @@ obj-$(CONFIG_SND_BCM2835_SOC_I2S) += snd
+
+ # BCM2708 Machine Support
+ snd-soc-hifiberry-dac-objs := hifiberry_dac.o
++snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
+ snd-soc-hifiberry-digi-objs := hifiberry_digi.o
+ snd-soc-rpi-dac-objs := rpi-dac.o
+ snd-soc-iqaudio-dac-objs := iqaudio-dac.o
+
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o
++obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o
+ obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o
+ obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
+--- /dev/null
++++ b/sound/soc/bcm/hifiberry_dacplus.c
+@@ -0,0 +1,141 @@
++/*
++ * ASoC Driver for HiFiBerry DAC+
++ *
++ * Author: Daniel Matuschek
++ * Copyright 2014
++ * based on code by Florian Meier <florian.meier@koalo.de>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/jack.h>
++
++#include "../codecs/pcm512x.h"
++
++static int snd_rpi_hifiberry_dacplus_init(struct snd_soc_pcm_runtime *rtd)
++{
++ struct snd_soc_codec *codec = rtd->codec;
++ snd_soc_update_bits(codec, PCM512x_GPIO_EN, 0x08, 0x08);
++ snd_soc_update_bits(codec, PCM512x_GPIO_OUTPUT_4, 0xf, 0x02);
++ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08,0x08);
++ return 0;
++}
++
++static int snd_rpi_hifiberry_dacplus_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
++ return snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
++}
++
++static int snd_rpi_hifiberry_dacplus_startup(struct snd_pcm_substream *substream) {
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_codec *codec = rtd->codec;
++ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08,0x08);
++ return 0;
++}
++
++static void snd_rpi_hifiberry_dacplus_shutdown(struct snd_pcm_substream *substream) {
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_codec *codec = rtd->codec;
++ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08,0x00);
++}
++
++/* machine stream operations */
++static struct snd_soc_ops snd_rpi_hifiberry_dacplus_ops = {
++ .hw_params = snd_rpi_hifiberry_dacplus_hw_params,
++ .startup = snd_rpi_hifiberry_dacplus_startup,
++ .shutdown = snd_rpi_hifiberry_dacplus_shutdown,
++};
++
++static struct snd_soc_dai_link snd_rpi_hifiberry_dacplus_dai[] = {
++{
++ .name = "HiFiBerry DAC+",
++ .stream_name = "HiFiBerry DAC+ HiFi",
++ .cpu_dai_name = "bcm2708-i2s.0",
++ .codec_dai_name = "pcm512x-hifi",
++ .platform_name = "bcm2708-i2s.0",
++ .codec_name = "pcm512x.1-004d",
++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBS_CFS,
++ .ops = &snd_rpi_hifiberry_dacplus_ops,
++ .init = snd_rpi_hifiberry_dacplus_init,
++},
++};
++
++/* audio machine driver */
++static struct snd_soc_card snd_rpi_hifiberry_dacplus = {
++ .name = "snd_rpi_hifiberry_dacplus",
++ .dai_link = snd_rpi_hifiberry_dacplus_dai,
++ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dacplus_dai),
++};
++
++static int snd_rpi_hifiberry_dacplus_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++
++ snd_rpi_hifiberry_dacplus.dev = &pdev->dev;
++
++ if (pdev->dev.of_node) {
++ struct device_node *i2s_node;
++ struct snd_soc_dai_link *dai = &snd_rpi_hifiberry_dacplus_dai[0];
++ i2s_node = of_parse_phandle(pdev->dev.of_node,
++ "i2s-controller", 0);
++
++ if (i2s_node) {
++ dai->cpu_dai_name = NULL;
++ dai->cpu_of_node = i2s_node;
++ dai->platform_name = NULL;
++ dai->platform_of_node = i2s_node;
++ }
++ }
++
++ ret = snd_soc_register_card(&snd_rpi_hifiberry_dacplus);
++ if (ret)
++ dev_err(&pdev->dev,
++ "snd_soc_register_card() failed: %d\n", ret);
++
++ return ret;
++}
++
++static int snd_rpi_hifiberry_dacplus_remove(struct platform_device *pdev)
++{
++ return snd_soc_unregister_card(&snd_rpi_hifiberry_dacplus);
++}
++
++static const struct of_device_id snd_rpi_hifiberry_dacplus_of_match[] = {
++ { .compatible = "hifiberry,hifiberry-dacplus", },
++ {},
++};
++MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_dacplus_of_match);
++
++static struct platform_driver snd_rpi_hifiberry_dacplus_driver = {
++ .driver = {
++ .name = "snd-rpi-hifiberry-dacplus",
++ .owner = THIS_MODULE,
++ .of_match_table = snd_rpi_hifiberry_dacplus_of_match,
++ },
++ .probe = snd_rpi_hifiberry_dacplus_probe,
++ .remove = snd_rpi_hifiberry_dacplus_remove,
++};
++
++module_platform_driver(snd_rpi_hifiberry_dacplus_driver);
++
++MODULE_AUTHOR("Daniel Matuschek <daniel@hifiberry.com>");
++MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+");
++MODULE_LICENSE("GPL v2");
diff --git a/target/linux/brcm2708/patches-4.4/0070-hid-Reduce-default-mouse-polling-interval-to-60Hz.patch b/target/linux/brcm2708/patches-4.4/0070-hid-Reduce-default-mouse-polling-interval-to-60Hz.patch
deleted file mode 100644
index 471732ce92..0000000000
--- a/target/linux/brcm2708/patches-4.4/0070-hid-Reduce-default-mouse-polling-interval-to-60Hz.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From b15f112ddaf2cd20a8f999ac823ddb51d7d513b9 Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Mon, 14 Jul 2014 22:02:09 +0100
-Subject: [PATCH 070/170] hid: Reduce default mouse polling interval to 60Hz
-
-Reduces overhead when using X
----
- drivers/hid/usbhid/hid-core.c | 10 +++++++---
- 1 file changed, 7 insertions(+), 3 deletions(-)
-
---- a/drivers/hid/usbhid/hid-core.c
-+++ b/drivers/hid/usbhid/hid-core.c
-@@ -49,7 +49,7 @@
- * Module parameters.
- */
-
--static unsigned int hid_mousepoll_interval;
-+static unsigned int hid_mousepoll_interval = ~0;
- module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644);
- MODULE_PARM_DESC(mousepoll, "Polling interval of mice");
-
-@@ -1091,8 +1091,12 @@ static int usbhid_start(struct hid_devic
- }
-
- /* Change the polling interval of mice. */
-- if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0)
-- interval = hid_mousepoll_interval;
-+ if (hid->collection->usage == HID_GD_MOUSE) {
-+ if (hid_mousepoll_interval == ~0 && interval < 16)
-+ interval = 16;
-+ else if (hid_mousepoll_interval != ~0 && hid_mousepoll_interval != 0)
-+ interval = hid_mousepoll_interval;
-+ }
-
- ret = -ENOMEM;
- if (usb_endpoint_dir_in(endpoint)) {
diff --git a/target/linux/brcm2708/patches-4.4/0071-Added-driver-for-HiFiBerry-Amp-amplifier-add-on-boar.patch b/target/linux/brcm2708/patches-4.4/0071-Added-driver-for-HiFiBerry-Amp-amplifier-add-on-boar.patch
new file mode 100644
index 0000000000..3acdd97c2e
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0071-Added-driver-for-HiFiBerry-Amp-amplifier-add-on-boar.patch
@@ -0,0 +1,816 @@
+From 4076d38775ab7bbdf64875c6e5cec6eb4b27760c Mon Sep 17 00:00:00 2001
+From: Daniel Matuschek <info@crazy-audio.com>
+Date: Mon, 4 Aug 2014 11:09:58 +0200
+Subject: [PATCH 071/381] Added driver for HiFiBerry Amp amplifier add-on board
+
+The driver contains a low-level hardware driver for the TAS5713 and the
+drivers for the Raspberry Pi I2S subsystem.
+
+TAS5713: return error if initialisation fails
+
+Existing TAS5713 driver logs errors during initialisation, but does not return
+an error code. Therefore even if initialisation fails, the driver will still be
+loaded, but won't work. This patch fixes this. I2C communication error will now
+reported correctly by a non-zero return code.
+
+HiFiBerry Amp: fix device-tree problems
+
+Some code to load the driver based on device-tree-overlays was missing. This is added by this patch.
+---
+ sound/soc/bcm/Kconfig | 7 +
+ sound/soc/bcm/Makefile | 2 +
+ sound/soc/bcm/hifiberry_amp.c | 127 +++++++++++++++
+ sound/soc/codecs/Kconfig | 4 +
+ sound/soc/codecs/Makefile | 2 +
+ sound/soc/codecs/tas5713.c | 369 ++++++++++++++++++++++++++++++++++++++++++
+ sound/soc/codecs/tas5713.h | 210 ++++++++++++++++++++++++
+ 7 files changed, 721 insertions(+)
+ create mode 100644 sound/soc/bcm/hifiberry_amp.c
+ create mode 100644 sound/soc/codecs/tas5713.c
+ create mode 100644 sound/soc/codecs/tas5713.h
+
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -29,6 +29,13 @@ config SND_BCM2708_SOC_HIFIBERRY_DIGI
+ help
+ Say Y or M if you want to add support for HifiBerry Digi S/PDIF output board.
+
++config SND_BCM2708_SOC_HIFIBERRY_AMP
++ tristate "Support for the HifiBerry Amp"
++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
++ select SND_SOC_TAS5713
++ help
++ Say Y or M if you want to add support for the HifiBerry Amp amplifier board.
++
+ config SND_BCM2708_SOC_RPI_DAC
+ tristate "Support for RPi-DAC"
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+--- a/sound/soc/bcm/Makefile
++++ b/sound/soc/bcm/Makefile
+@@ -7,11 +7,13 @@ obj-$(CONFIG_SND_BCM2835_SOC_I2S) += snd
+ snd-soc-hifiberry-dac-objs := hifiberry_dac.o
+ snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
+ snd-soc-hifiberry-digi-objs := hifiberry_digi.o
++snd-soc-hifiberry-amp-objs := hifiberry_amp.o
+ snd-soc-rpi-dac-objs := rpi-dac.o
+ snd-soc-iqaudio-dac-objs := iqaudio-dac.o
+
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o
++obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o
+ obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o
+ obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
+--- /dev/null
++++ b/sound/soc/bcm/hifiberry_amp.c
+@@ -0,0 +1,127 @@
++/*
++ * ASoC Driver for HifiBerry AMP
++ *
++ * Author: Sebastian Eickhoff <basti.eickhoff@googlemail.com>
++ * Copyright 2014
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/jack.h>
++
++static int snd_rpi_hifiberry_amp_init(struct snd_soc_pcm_runtime *rtd)
++{
++ // ToDo: init of the dsp-registers.
++ return 0;
++}
++
++static int snd_rpi_hifiberry_amp_hw_params( struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params )
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
++
++ return snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
++}
++
++static struct snd_soc_ops snd_rpi_hifiberry_amp_ops = {
++ .hw_params = snd_rpi_hifiberry_amp_hw_params,
++};
++
++static struct snd_soc_dai_link snd_rpi_hifiberry_amp_dai[] = {
++ {
++ .name = "HifiBerry AMP",
++ .stream_name = "HifiBerry AMP HiFi",
++ .cpu_dai_name = "bcm2708-i2s.0",
++ .codec_dai_name = "tas5713-hifi",
++ .platform_name = "bcm2708-i2s.0",
++ .codec_name = "tas5713.1-001b",
++ .dai_fmt = SND_SOC_DAIFMT_I2S |
++ SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBS_CFS,
++ .ops = &snd_rpi_hifiberry_amp_ops,
++ .init = snd_rpi_hifiberry_amp_init,
++ },
++};
++
++
++static struct snd_soc_card snd_rpi_hifiberry_amp = {
++ .name = "snd_rpi_hifiberry_amp",
++ .dai_link = snd_rpi_hifiberry_amp_dai,
++ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_amp_dai),
++};
++
++static const struct of_device_id snd_rpi_hifiberry_amp_of_match[] = {
++ { .compatible = "hifiberry,hifiberry-amp", },
++ {},
++};
++MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_amp_of_match);
++
++
++static int snd_rpi_hifiberry_amp_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++
++ snd_rpi_hifiberry_amp.dev = &pdev->dev;
++
++ if (pdev->dev.of_node) {
++ struct device_node *i2s_node;
++ struct snd_soc_dai_link *dai = &snd_rpi_hifiberry_amp_dai[0];
++ i2s_node = of_parse_phandle(pdev->dev.of_node,
++ "i2s-controller", 0);
++
++ if (i2s_node) {
++ dai->cpu_dai_name = NULL;
++ dai->cpu_of_node = i2s_node;
++ dai->platform_name = NULL;
++ dai->platform_of_node = i2s_node;
++ }
++ }
++
++ ret = snd_soc_register_card(&snd_rpi_hifiberry_amp);
++
++ if (ret != 0) {
++ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret);
++ }
++
++ return ret;
++}
++
++
++static int snd_rpi_hifiberry_amp_remove(struct platform_device *pdev)
++{
++ return snd_soc_unregister_card(&snd_rpi_hifiberry_amp);
++}
++
++
++static struct platform_driver snd_rpi_hifiberry_amp_driver = {
++ .driver = {
++ .name = "snd-hifiberry-amp",
++ .owner = THIS_MODULE,
++ .of_match_table = snd_rpi_hifiberry_amp_of_match,
++ },
++ .probe = snd_rpi_hifiberry_amp_probe,
++ .remove = snd_rpi_hifiberry_amp_remove,
++};
++
++
++module_platform_driver(snd_rpi_hifiberry_amp_driver);
++
++
++MODULE_AUTHOR("Sebastian Eickhoff <basti.eickhoff@googlemail.com>");
++MODULE_DESCRIPTION("ASoC driver for HiFiBerry-AMP");
++MODULE_LICENSE("GPL v2");
+--- a/sound/soc/codecs/Kconfig
++++ b/sound/soc/codecs/Kconfig
+@@ -117,6 +117,7 @@ config SND_SOC_ALL_CODECS
+ select SND_SOC_TFA9879 if I2C
+ select SND_SOC_TLV320AIC23_I2C if I2C
+ select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
++ select SND_SOC_TAS5713 if I2C
+ select SND_SOC_TLV320AIC26 if SPI_MASTER
+ select SND_SOC_TLV320AIC31XX if I2C
+ select SND_SOC_TLV320AIC32X4 if I2C
+@@ -674,6 +675,9 @@ config SND_SOC_TFA9879
+ tristate "NXP Semiconductors TFA9879 amplifier"
+ depends on I2C
+
++config SND_SOC_TAS5713
++ tristate
++
+ config SND_SOC_TLV320AIC23
+ tristate
+
+--- a/sound/soc/codecs/Makefile
++++ b/sound/soc/codecs/Makefile
+@@ -118,6 +118,7 @@ snd-soc-sti-sas-objs := sti-sas.o
+ snd-soc-tas5086-objs := tas5086.o
+ snd-soc-tas571x-objs := tas571x.o
+ snd-soc-tfa9879-objs := tfa9879.o
++snd-soc-tas5713-objs := tas5713.o
+ snd-soc-tlv320aic23-objs := tlv320aic23.o
+ snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
+ snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o
+@@ -312,6 +313,7 @@ obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc
+ obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o
+ obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o
+ obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o
++obj-$(CONFIG_SND_SOC_TAS5713) += snd-soc-tas5713.o
+ obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o
+ obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o
+ obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI) += snd-soc-tlv320aic23-spi.o
+--- /dev/null
++++ b/sound/soc/codecs/tas5713.c
+@@ -0,0 +1,369 @@
++/*
++ * ASoC Driver for TAS5713
++ *
++ * Author: Sebastian Eickhoff <basti.eickhoff@googlemail.com>
++ * Copyright 2014
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/pm.h>
++#include <linux/i2c.h>
++#include <linux/of_device.h>
++#include <linux/spi/spi.h>
++#include <linux/regmap.h>
++#include <linux/regulator/consumer.h>
++#include <linux/slab.h>
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/initval.h>
++#include <sound/tlv.h>
++
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/fs.h>
++#include <asm/uaccess.h>
++
++#include "tas5713.h"
++
++
++static struct i2c_client *i2c;
++
++struct tas5713_priv {
++ struct regmap *regmap;
++ int mclk_div;
++ struct snd_soc_codec *codec;
++};
++
++static struct tas5713_priv *priv_data;
++
++
++
++
++/*
++ * _ _ ___ _ ___ _ _
++ * /_\ | | / __| /_\ / __|___ _ _| |_ _ _ ___| |___
++ * / _ \| |__\__ \/ _ \ | (__/ _ \ ' \ _| '_/ _ \ (_-<
++ * /_/ \_\____|___/_/ \_\ \___\___/_||_\__|_| \___/_/__/
++ *
++ */
++
++static const DECLARE_TLV_DB_SCALE(tas5713_vol_tlv, -10000, 50, 1);
++
++
++static const struct snd_kcontrol_new tas5713_snd_controls[] = {
++ SOC_SINGLE_TLV ("Master" , TAS5713_VOL_MASTER, 0, 248, 1, tas5713_vol_tlv),
++ SOC_DOUBLE_R_TLV("Channels" , TAS5713_VOL_CH1, TAS5713_VOL_CH2, 0, 248, 1, tas5713_vol_tlv)
++};
++
++
++
++
++/*
++ * __ __ _ _ ___ _
++ * | \/ |__ _ __| |_ (_)_ _ ___ | \ _ _(_)_ _____ _ _
++ * | |\/| / _` / _| ' \| | ' \/ -_) | |) | '_| \ V / -_) '_|
++ * |_| |_\__,_\__|_||_|_|_||_\___| |___/|_| |_|\_/\___|_|
++ *
++ */
++
++static int tas5713_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params,
++ struct snd_soc_dai *dai)
++{
++ u16 blen = 0x00;
++
++ struct snd_soc_codec *codec;
++ codec = dai->codec;
++ priv_data->codec = dai->codec;
++
++ switch (params_format(params)) {
++ case SNDRV_PCM_FORMAT_S16_LE:
++ blen = 0x03;
++ break;
++ case SNDRV_PCM_FORMAT_S20_3LE:
++ blen = 0x1;
++ break;
++ case SNDRV_PCM_FORMAT_S24_LE:
++ blen = 0x04;
++ break;
++ case SNDRV_PCM_FORMAT_S32_LE:
++ blen = 0x05;
++ break;
++ default:
++ dev_err(dai->dev, "Unsupported word length: %u\n",
++ params_format(params));
++ return -EINVAL;
++ }
++
++ // set word length
++ snd_soc_update_bits(codec, TAS5713_SERIAL_DATA_INTERFACE, 0x7, blen);
++
++ return 0;
++}
++
++
++static int tas5713_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
++{
++ unsigned int val = 0;
++
++ struct tas5713_priv *tas5713;
++ struct snd_soc_codec *codec = dai->codec;
++ tas5713 = snd_soc_codec_get_drvdata(codec);
++
++ if (mute) {
++ val = TAS5713_SOFT_MUTE_ALL;
++ }
++
++ return regmap_write(tas5713->regmap, TAS5713_SOFT_MUTE, val);
++}
++
++
++static const struct snd_soc_dai_ops tas5713_dai_ops = {
++ .hw_params = tas5713_hw_params,
++ .mute_stream = tas5713_mute_stream,
++};
++
++
++static struct snd_soc_dai_driver tas5713_dai = {
++ .name = "tas5713-hifi",
++ .playback = {
++ .stream_name = "Playback",
++ .channels_min = 2,
++ .channels_max = 2,
++ .rates = SNDRV_PCM_RATE_8000_48000,
++ .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE ),
++ },
++ .ops = &tas5713_dai_ops,
++};
++
++
++
++
++/*
++ * ___ _ ___ _
++ * / __|___ __| |___ __ | \ _ _(_)_ _____ _ _
++ * | (__/ _ \/ _` / -_) _| | |) | '_| \ V / -_) '_|
++ * \___\___/\__,_\___\__| |___/|_| |_|\_/\___|_|
++ *
++ */
++
++static int tas5713_remove(struct snd_soc_codec *codec)
++{
++ struct tas5713_priv *tas5713;
++
++ tas5713 = snd_soc_codec_get_drvdata(codec);
++
++ return 0;
++}
++
++
++static int tas5713_probe(struct snd_soc_codec *codec)
++{
++ struct tas5713_priv *tas5713;
++ int i, ret;
++
++ i2c = container_of(codec->dev, struct i2c_client, dev);
++
++ tas5713 = snd_soc_codec_get_drvdata(codec);
++
++ // Reset error
++ ret = snd_soc_write(codec, TAS5713_ERROR_STATUS, 0x00);
++ if (ret < 0) return ret;
++
++ // Trim oscillator
++ ret = snd_soc_write(codec, TAS5713_OSC_TRIM, 0x00);
++ if (ret < 0) return ret;
++ msleep(1000);
++
++ // Reset error
++ ret = snd_soc_write(codec, TAS5713_ERROR_STATUS, 0x00);
++ if (ret < 0) return ret;
++
++ // Clock mode: 44/48kHz, MCLK=64xfs
++ ret = snd_soc_write(codec, TAS5713_CLOCK_CTRL, 0x60);
++ if (ret < 0) return ret;
++
++ // I2S 24bit
++ ret = snd_soc_write(codec, TAS5713_SERIAL_DATA_INTERFACE, 0x05);
++ if (ret < 0) return ret;
++
++ // Unmute
++ ret = snd_soc_write(codec, TAS5713_SYSTEM_CTRL2, 0x00);
++ if (ret < 0) return ret;
++ ret = snd_soc_write(codec, TAS5713_SOFT_MUTE, 0x00);
++ if (ret < 0) return ret;
++
++ // Set volume to 0db
++ ret = snd_soc_write(codec, TAS5713_VOL_MASTER, 0x00);
++ if (ret < 0) return ret;
++
++ // Now start programming the default initialization sequence
++ for (i = 0; i < ARRAY_SIZE(tas5713_init_sequence); ++i) {
++ ret = i2c_master_send(i2c,
++ tas5713_init_sequence[i].data,
++ tas5713_init_sequence[i].size);
++ if (ret < 0) {
++ printk(KERN_INFO "TAS5713 CODEC PROBE: InitSeq returns: %d\n", ret);
++ }
++ }
++
++ // Unmute
++ ret = snd_soc_write(codec, TAS5713_SYSTEM_CTRL2, 0x00);
++ if (ret < 0) return ret;
++
++ return 0;
++}
++
++
++static struct snd_soc_codec_driver soc_codec_dev_tas5713 = {
++ .probe = tas5713_probe,
++ .remove = tas5713_remove,
++ .controls = tas5713_snd_controls,
++ .num_controls = ARRAY_SIZE(tas5713_snd_controls),
++};
++
++
++
++
++/*
++ * ___ ___ ___ ___ _
++ * |_ _|_ ) __| | \ _ _(_)_ _____ _ _
++ * | | / / (__ | |) | '_| \ V / -_) '_|
++ * |___/___\___| |___/|_| |_|\_/\___|_|
++ *
++ */
++
++static const struct reg_default tas5713_reg_defaults[] = {
++ { 0x07 ,0x80 }, // R7 - VOL_MASTER - -40dB
++ { 0x08 , 30 }, // R8 - VOL_CH1 - 0dB
++ { 0x09 , 30 }, // R9 - VOL_CH2 - 0dB
++ { 0x0A ,0x80 }, // R10 - VOL_HEADPHONE - -40dB
++};
++
++
++static bool tas5713_reg_volatile(struct device *dev, unsigned int reg)
++{
++ switch (reg) {
++ case TAS5713_DEVICE_ID:
++ case TAS5713_ERROR_STATUS:
++ return true;
++ default:
++ return false;
++ }
++}
++
++
++static const struct of_device_id tas5713_of_match[] = {
++ { .compatible = "ti,tas5713", },
++ { }
++};
++MODULE_DEVICE_TABLE(of, tas5713_of_match);
++
++
++static struct regmap_config tas5713_regmap_config = {
++ .reg_bits = 8,
++ .val_bits = 8,
++
++ .max_register = TAS5713_MAX_REGISTER,
++ .volatile_reg = tas5713_reg_volatile,
++
++ .cache_type = REGCACHE_RBTREE,
++ .reg_defaults = tas5713_reg_defaults,
++ .num_reg_defaults = ARRAY_SIZE(tas5713_reg_defaults),
++};
++
++
++static int tas5713_i2c_probe(struct i2c_client *i2c,
++ const struct i2c_device_id *id)
++{
++ int ret;
++
++ priv_data = devm_kzalloc(&i2c->dev, sizeof *priv_data, GFP_KERNEL);
++ if (!priv_data)
++ return -ENOMEM;
++
++ priv_data->regmap = devm_regmap_init_i2c(i2c, &tas5713_regmap_config);
++ if (IS_ERR(priv_data->regmap)) {
++ ret = PTR_ERR(priv_data->regmap);
++ return ret;
++ }
++
++ i2c_set_clientdata(i2c, priv_data);
++
++ ret = snd_soc_register_codec(&i2c->dev,
++ &soc_codec_dev_tas5713, &tas5713_dai, 1);
++
++ return ret;
++}
++
++
++static int tas5713_i2c_remove(struct i2c_client *i2c)
++{
++ snd_soc_unregister_codec(&i2c->dev);
++ i2c_set_clientdata(i2c, NULL);
++
++ kfree(priv_data);
++
++ return 0;
++}
++
++
++static const struct i2c_device_id tas5713_i2c_id[] = {
++ { "tas5713", 0 },
++ { }
++};
++
++MODULE_DEVICE_TABLE(i2c, tas5713_i2c_id);
++
++
++static struct i2c_driver tas5713_i2c_driver = {
++ .driver = {
++ .name = "tas5713",
++ .owner = THIS_MODULE,
++ .of_match_table = tas5713_of_match,
++ },
++ .probe = tas5713_i2c_probe,
++ .remove = tas5713_i2c_remove,
++ .id_table = tas5713_i2c_id
++};
++
++
++static int __init tas5713_modinit(void)
++{
++ int ret = 0;
++
++ ret = i2c_add_driver(&tas5713_i2c_driver);
++ if (ret) {
++ printk(KERN_ERR "Failed to register tas5713 I2C driver: %d\n",
++ ret);
++ }
++
++ return ret;
++}
++module_init(tas5713_modinit);
++
++
++static void __exit tas5713_exit(void)
++{
++ i2c_del_driver(&tas5713_i2c_driver);
++}
++module_exit(tas5713_exit);
++
++
++MODULE_AUTHOR("Sebastian Eickhoff <basti.eickhoff@googlemail.com>");
++MODULE_DESCRIPTION("ASoC driver for TAS5713");
++MODULE_LICENSE("GPL v2");
+--- /dev/null
++++ b/sound/soc/codecs/tas5713.h
+@@ -0,0 +1,210 @@
++/*
++ * ASoC Driver for TAS5713
++ *
++ * Author: Sebastian Eickhoff <basti.eickhoff@googlemail.com>
++ * Copyright 2014
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++#ifndef _TAS5713_H
++#define _TAS5713_H
++
++
++// TAS5713 I2C-bus register addresses
++
++#define TAS5713_CLOCK_CTRL 0x00
++#define TAS5713_DEVICE_ID 0x01
++#define TAS5713_ERROR_STATUS 0x02
++#define TAS5713_SYSTEM_CTRL1 0x03
++#define TAS5713_SERIAL_DATA_INTERFACE 0x04
++#define TAS5713_SYSTEM_CTRL2 0x05
++#define TAS5713_SOFT_MUTE 0x06
++#define TAS5713_VOL_MASTER 0x07
++#define TAS5713_VOL_CH1 0x08
++#define TAS5713_VOL_CH2 0x09
++#define TAS5713_VOL_HEADPHONE 0x0A
++#define TAS5713_VOL_CONFIG 0x0E
++#define TAS5713_MODULATION_LIMIT 0x10
++#define TAS5713_IC_DLY_CH1 0x11
++#define TAS5713_IC_DLY_CH2 0x12
++#define TAS5713_IC_DLY_CH3 0x13
++#define TAS5713_IC_DLY_CH4 0x14
++
++#define TAS5713_START_STOP_PERIOD 0x1A
++#define TAS5713_OSC_TRIM 0x1B
++#define TAS5713_BKND_ERR 0x1C
++
++#define TAS5713_INPUT_MUX 0x20
++#define TAS5713_SRC_SELECT_CH4 0x21
++#define TAS5713_PWM_MUX 0x25
++
++#define TAS5713_CH1_BQ0 0x29
++#define TAS5713_CH1_BQ1 0x2A
++#define TAS5713_CH1_BQ2 0x2B
++#define TAS5713_CH1_BQ3 0x2C
++#define TAS5713_CH1_BQ4 0x2D
++#define TAS5713_CH1_BQ5 0x2E
++#define TAS5713_CH1_BQ6 0x2F
++#define TAS5713_CH1_BQ7 0x58
++#define TAS5713_CH1_BQ8 0x59
++
++#define TAS5713_CH2_BQ0 0x30
++#define TAS5713_CH2_BQ1 0x31
++#define TAS5713_CH2_BQ2 0x32
++#define TAS5713_CH2_BQ3 0x33
++#define TAS5713_CH2_BQ4 0x34
++#define TAS5713_CH2_BQ5 0x35
++#define TAS5713_CH2_BQ6 0x36
++#define TAS5713_CH2_BQ7 0x5C
++#define TAS5713_CH2_BQ8 0x5D
++
++#define TAS5713_CH4_BQ0 0x5A
++#define TAS5713_CH4_BQ1 0x5B
++#define TAS5713_CH3_BQ0 0x5E
++#define TAS5713_CH3_BQ1 0x5F
++
++#define TAS5713_DRC1_SOFTENING_FILTER_ALPHA_OMEGA 0x3B
++#define TAS5713_DRC1_ATTACK_RELEASE_RATE 0x3C
++#define TAS5713_DRC2_SOFTENING_FILTER_ALPHA_OMEGA 0x3E
++#define TAS5713_DRC2_ATTACK_RELEASE_RATE 0x3F
++#define TAS5713_DRC1_ATTACK_RELEASE_THRES 0x40
++#define TAS5713_DRC2_ATTACK_RELEASE_THRES 0x43
++#define TAS5713_DRC_CTRL 0x46
++
++#define TAS5713_BANK_SW_CTRL 0x50
++#define TAS5713_CH1_OUTPUT_MIXER 0x51
++#define TAS5713_CH2_OUTPUT_MIXER 0x52
++#define TAS5713_CH1_INPUT_MIXER 0x53
++#define TAS5713_CH2_INPUT_MIXER 0x54
++#define TAS5713_OUTPUT_POST_SCALE 0x56
++#define TAS5713_OUTPUT_PRESCALE 0x57
++
++#define TAS5713_IDF_POST_SCALE 0x62
++
++#define TAS5713_CH1_INLINE_MIXER 0x70
++#define TAS5713_CH1_INLINE_DRC_EN_MIXER 0x71
++#define TAS5713_CH1_R_CHANNEL_MIXER 0x72
++#define TAS5713_CH1_L_CHANNEL_MIXER 0x73
++#define TAS5713_CH2_INLINE_MIXER 0x74
++#define TAS5713_CH2_INLINE_DRC_EN_MIXER 0x75
++#define TAS5713_CH2_L_CHANNEL_MIXER 0x76
++#define TAS5713_CH2_R_CHANNEL_MIXER 0x77
++
++#define TAS5713_UPDATE_DEV_ADDR_KEY 0xF8
++#define TAS5713_UPDATE_DEV_ADDR_REG 0xF9
++
++#define TAS5713_REGISTER_COUNT 0x46
++#define TAS5713_MAX_REGISTER 0xF9
++
++
++// Bitmasks for registers
++#define TAS5713_SOFT_MUTE_ALL 0x07
++
++
++
++struct tas5713_init_command {
++ const int size;
++ const char *const data;
++};
++
++static const struct tas5713_init_command tas5713_init_sequence[] = {
++
++ // Trim oscillator
++ { .size = 2, .data = "\x1B\x00" },
++ // System control register 1 (0x03): block DC
++ { .size = 2, .data = "\x03\x80" },
++ // Mute everything
++ { .size = 2, .data = "\x05\x40" },
++ // Modulation limit register (0x10): 97.7%
++ { .size = 2, .data = "\x10\x02" },
++ // Interchannel delay registers
++ // (0x11, 0x12, 0x13, and 0x14): BD mode
++ { .size = 2, .data = "\x11\xB8" },
++ { .size = 2, .data = "\x12\x60" },
++ { .size = 2, .data = "\x13\xA0" },
++ { .size = 2, .data = "\x14\x48" },
++ // PWM shutdown group register (0x19): no shutdown
++ { .size = 2, .data = "\x19\x00" },
++ // Input multiplexer register (0x20): BD mode
++ { .size = 2, .data = "\x20\x00\x89\x77\x72" },
++ // PWM output mux register (0x25)
++ // Channel 1 --> OUTA, channel 1 neg --> OUTB
++ // Channel 2 --> OUTC, channel 2 neg --> OUTD
++ { .size = 5, .data = "\x25\x01\x02\x13\x45" },
++ // DRC control (0x46): DRC off
++ { .size = 5, .data = "\x46\x00\x00\x00\x00" },
++ // BKND_ERR register (0x1C): 299ms reset period
++ { .size = 2, .data = "\x1C\x07" },
++ // Mute channel 3
++ { .size = 2, .data = "\x0A\xFF" },
++ // Volume configuration register (0x0E): volume slew 512 steps
++ { .size = 2, .data = "\x0E\x90" },
++ // Clock control register (0x00): 44/48kHz, MCLK=64xfs
++ { .size = 2, .data = "\x00\x60" },
++ // Bank switch and eq control (0x50): no bank switching
++ { .size = 5, .data = "\x50\x00\x00\x00\x00" },
++ // Volume registers (0x07, 0x08, 0x09, 0x0A)
++ { .size = 2, .data = "\x07\x20" },
++ { .size = 2, .data = "\x08\x30" },
++ { .size = 2, .data = "\x09\x30" },
++ { .size = 2, .data = "\x0A\xFF" },
++ // 0x72, 0x73, 0x76, 0x77 input mixer:
++ // no intermix between channels
++ { .size = 5, .data = "\x72\x00\x00\x00\x00" },
++ { .size = 5, .data = "\x73\x00\x80\x00\x00" },
++ { .size = 5, .data = "\x76\x00\x00\x00\x00" },
++ { .size = 5, .data = "\x77\x00\x80\x00\x00" },
++ // 0x70, 0x71, 0x74, 0x75 inline DRC mixer:
++ // no inline DRC inmix
++ { .size = 5, .data = "\x70\x00\x80\x00\x00" },
++ { .size = 5, .data = "\x71\x00\x00\x00\x00" },
++ { .size = 5, .data = "\x74\x00\x80\x00\x00" },
++ { .size = 5, .data = "\x75\x00\x00\x00\x00" },
++ // 0x56, 0x57 Output scale
++ { .size = 5, .data = "\x56\x00\x80\x00\x00" },
++ { .size = 5, .data = "\x57\x00\x02\x00\x00" },
++ // 0x3B, 0x3c
++ { .size = 9, .data = "\x3B\x00\x08\x00\x00\x00\x78\x00\x00" },
++ { .size = 9, .data = "\x3C\x00\x00\x01\x00\xFF\xFF\xFF\x00" },
++ { .size = 9, .data = "\x3E\x00\x08\x00\x00\x00\x78\x00\x00" },
++ { .size = 9, .data = "\x3F\x00\x00\x01\x00\xFF\xFF\xFF\x00" },
++ { .size = 9, .data = "\x40\x00\x00\x01\x00\xFF\xFF\xFF\x00" },
++ { .size = 9, .data = "\x43\x00\x00\x01\x00\xFF\xFF\xFF\x00" },
++ // 0x51, 0x52: output mixer
++ { .size = 9, .data = "\x51\x00\x80\x00\x00\x00\x00\x00\x00" },
++ { .size = 9, .data = "\x52\x00\x80\x00\x00\x00\x00\x00\x00" },
++ // PEQ defaults
++ { .size = 21, .data = "\x29\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
++ { .size = 21, .data = "\x2A\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
++ { .size = 21, .data = "\x2B\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
++ { .size = 21, .data = "\x2C\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
++ { .size = 21, .data = "\x2D\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
++ { .size = 21, .data = "\x2E\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
++ { .size = 21, .data = "\x2F\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
++ { .size = 21, .data = "\x30\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
++ { .size = 21, .data = "\x31\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
++ { .size = 21, .data = "\x32\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
++ { .size = 21, .data = "\x33\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
++ { .size = 21, .data = "\x34\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
++ { .size = 21, .data = "\x35\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
++ { .size = 21, .data = "\x36\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
++ { .size = 21, .data = "\x58\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
++ { .size = 21, .data = "\x59\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
++ { .size = 21, .data = "\x5C\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
++ { .size = 21, .data = "\x5D\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
++ { .size = 21, .data = "\x5E\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
++ { .size = 21, .data = "\x5F\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
++ { .size = 21, .data = "\x5A\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
++ { .size = 21, .data = "\x5B\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
++};
++
++
++#endif /* _TAS5713_H */
diff --git a/target/linux/brcm2708/patches-4.4/0071-Added-support-for-HiFiBerry-DAC.patch b/target/linux/brcm2708/patches-4.4/0071-Added-support-for-HiFiBerry-DAC.patch
deleted file mode 100644
index c38b623926..0000000000
--- a/target/linux/brcm2708/patches-4.4/0071-Added-support-for-HiFiBerry-DAC.patch
+++ /dev/null
@@ -1,190 +0,0 @@
-From debd3d30b1127328b5a1e444bd1550cb45c50362 Mon Sep 17 00:00:00 2001
-From: Daniel Matuschek <info@crazy-audio.com>
-Date: Mon, 4 Aug 2014 10:06:56 +0200
-Subject: [PATCH 071/170] Added support for HiFiBerry DAC+
-
-The driver is based on the HiFiBerry DAC driver. However HiFiBerry DAC+ uses
-a different codec chip (PCM5122), therefore a new driver is necessary.
----
- sound/soc/bcm/Kconfig | 7 ++
- sound/soc/bcm/Makefile | 2 +
- sound/soc/bcm/hifiberry_dacplus.c | 141 ++++++++++++++++++++++++++++++++++++++
- 3 files changed, 150 insertions(+)
- create mode 100644 sound/soc/bcm/hifiberry_dacplus.c
-
---- a/sound/soc/bcm/Kconfig
-+++ b/sound/soc/bcm/Kconfig
-@@ -15,6 +15,13 @@ config SND_BCM2708_SOC_HIFIBERRY_DAC
- help
- Say Y or M if you want to add support for HifiBerry DAC.
-
-+config SND_BCM2708_SOC_HIFIBERRY_DACPLUS
-+ tristate "Support for HifiBerry DAC+"
-+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
-+ select SND_SOC_PCM512x
-+ help
-+ Say Y or M if you want to add support for HifiBerry DAC+.
-+
- config SND_BCM2708_SOC_HIFIBERRY_DIGI
- tristate "Support for HifiBerry Digi"
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
---- a/sound/soc/bcm/Makefile
-+++ b/sound/soc/bcm/Makefile
-@@ -5,11 +5,13 @@ obj-$(CONFIG_SND_BCM2835_SOC_I2S) += snd
-
- # BCM2708 Machine Support
- snd-soc-hifiberry-dac-objs := hifiberry_dac.o
-+snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
- snd-soc-hifiberry-digi-objs := hifiberry_digi.o
- snd-soc-rpi-dac-objs := rpi-dac.o
- snd-soc-iqaudio-dac-objs := iqaudio-dac.o
-
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o
-+obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o
- obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o
- obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
---- /dev/null
-+++ b/sound/soc/bcm/hifiberry_dacplus.c
-@@ -0,0 +1,141 @@
-+/*
-+ * ASoC Driver for HiFiBerry DAC+
-+ *
-+ * Author: Daniel Matuschek
-+ * Copyright 2014
-+ * based on code by Florian Meier <florian.meier@koalo.de>
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+
-+#include <sound/core.h>
-+#include <sound/pcm.h>
-+#include <sound/pcm_params.h>
-+#include <sound/soc.h>
-+#include <sound/jack.h>
-+
-+#include "../codecs/pcm512x.h"
-+
-+static int snd_rpi_hifiberry_dacplus_init(struct snd_soc_pcm_runtime *rtd)
-+{
-+ struct snd_soc_codec *codec = rtd->codec;
-+ snd_soc_update_bits(codec, PCM512x_GPIO_EN, 0x08, 0x08);
-+ snd_soc_update_bits(codec, PCM512x_GPIO_OUTPUT_4, 0xf, 0x02);
-+ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08,0x08);
-+ return 0;
-+}
-+
-+static int snd_rpi_hifiberry_dacplus_hw_params(struct snd_pcm_substream *substream,
-+ struct snd_pcm_hw_params *params)
-+{
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-+ return snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
-+}
-+
-+static int snd_rpi_hifiberry_dacplus_startup(struct snd_pcm_substream *substream) {
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ struct snd_soc_codec *codec = rtd->codec;
-+ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08,0x08);
-+ return 0;
-+}
-+
-+static void snd_rpi_hifiberry_dacplus_shutdown(struct snd_pcm_substream *substream) {
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ struct snd_soc_codec *codec = rtd->codec;
-+ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08,0x00);
-+}
-+
-+/* machine stream operations */
-+static struct snd_soc_ops snd_rpi_hifiberry_dacplus_ops = {
-+ .hw_params = snd_rpi_hifiberry_dacplus_hw_params,
-+ .startup = snd_rpi_hifiberry_dacplus_startup,
-+ .shutdown = snd_rpi_hifiberry_dacplus_shutdown,
-+};
-+
-+static struct snd_soc_dai_link snd_rpi_hifiberry_dacplus_dai[] = {
-+{
-+ .name = "HiFiBerry DAC+",
-+ .stream_name = "HiFiBerry DAC+ HiFi",
-+ .cpu_dai_name = "bcm2708-i2s.0",
-+ .codec_dai_name = "pcm512x-hifi",
-+ .platform_name = "bcm2708-i2s.0",
-+ .codec_name = "pcm512x.1-004d",
-+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-+ SND_SOC_DAIFMT_CBS_CFS,
-+ .ops = &snd_rpi_hifiberry_dacplus_ops,
-+ .init = snd_rpi_hifiberry_dacplus_init,
-+},
-+};
-+
-+/* audio machine driver */
-+static struct snd_soc_card snd_rpi_hifiberry_dacplus = {
-+ .name = "snd_rpi_hifiberry_dacplus",
-+ .dai_link = snd_rpi_hifiberry_dacplus_dai,
-+ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dacplus_dai),
-+};
-+
-+static int snd_rpi_hifiberry_dacplus_probe(struct platform_device *pdev)
-+{
-+ int ret = 0;
-+
-+ snd_rpi_hifiberry_dacplus.dev = &pdev->dev;
-+
-+ if (pdev->dev.of_node) {
-+ struct device_node *i2s_node;
-+ struct snd_soc_dai_link *dai = &snd_rpi_hifiberry_dacplus_dai[0];
-+ i2s_node = of_parse_phandle(pdev->dev.of_node,
-+ "i2s-controller", 0);
-+
-+ if (i2s_node) {
-+ dai->cpu_dai_name = NULL;
-+ dai->cpu_of_node = i2s_node;
-+ dai->platform_name = NULL;
-+ dai->platform_of_node = i2s_node;
-+ }
-+ }
-+
-+ ret = snd_soc_register_card(&snd_rpi_hifiberry_dacplus);
-+ if (ret)
-+ dev_err(&pdev->dev,
-+ "snd_soc_register_card() failed: %d\n", ret);
-+
-+ return ret;
-+}
-+
-+static int snd_rpi_hifiberry_dacplus_remove(struct platform_device *pdev)
-+{
-+ return snd_soc_unregister_card(&snd_rpi_hifiberry_dacplus);
-+}
-+
-+static const struct of_device_id snd_rpi_hifiberry_dacplus_of_match[] = {
-+ { .compatible = "hifiberry,hifiberry-dacplus", },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_dacplus_of_match);
-+
-+static struct platform_driver snd_rpi_hifiberry_dacplus_driver = {
-+ .driver = {
-+ .name = "snd-rpi-hifiberry-dacplus",
-+ .owner = THIS_MODULE,
-+ .of_match_table = snd_rpi_hifiberry_dacplus_of_match,
-+ },
-+ .probe = snd_rpi_hifiberry_dacplus_probe,
-+ .remove = snd_rpi_hifiberry_dacplus_remove,
-+};
-+
-+module_platform_driver(snd_rpi_hifiberry_dacplus_driver);
-+
-+MODULE_AUTHOR("Daniel Matuschek <daniel@hifiberry.com>");
-+MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+");
-+MODULE_LICENSE("GPL v2");
diff --git a/target/linux/brcm2708/patches-4.4/0072-Added-driver-for-HiFiBerry-Amp-amplifier-add-on-boar.patch b/target/linux/brcm2708/patches-4.4/0072-Added-driver-for-HiFiBerry-Amp-amplifier-add-on-boar.patch
deleted file mode 100644
index b6e6fe9f9b..0000000000
--- a/target/linux/brcm2708/patches-4.4/0072-Added-driver-for-HiFiBerry-Amp-amplifier-add-on-boar.patch
+++ /dev/null
@@ -1,816 +0,0 @@
-From 9c6f0b1812313d39afeefd700b7f9df9a82a47cd Mon Sep 17 00:00:00 2001
-From: Daniel Matuschek <info@crazy-audio.com>
-Date: Mon, 4 Aug 2014 11:09:58 +0200
-Subject: [PATCH 072/170] Added driver for HiFiBerry Amp amplifier add-on board
-
-The driver contains a low-level hardware driver for the TAS5713 and the
-drivers for the Raspberry Pi I2S subsystem.
-
-TAS5713: return error if initialisation fails
-
-Existing TAS5713 driver logs errors during initialisation, but does not return
-an error code. Therefore even if initialisation fails, the driver will still be
-loaded, but won't work. This patch fixes this. I2C communication error will now
-reported correctly by a non-zero return code.
-
-HiFiBerry Amp: fix device-tree problems
-
-Some code to load the driver based on device-tree-overlays was missing. This is added by this patch.
----
- sound/soc/bcm/Kconfig | 7 +
- sound/soc/bcm/Makefile | 2 +
- sound/soc/bcm/hifiberry_amp.c | 127 +++++++++++++++
- sound/soc/codecs/Kconfig | 4 +
- sound/soc/codecs/Makefile | 2 +
- sound/soc/codecs/tas5713.c | 369 ++++++++++++++++++++++++++++++++++++++++++
- sound/soc/codecs/tas5713.h | 210 ++++++++++++++++++++++++
- 7 files changed, 721 insertions(+)
- create mode 100644 sound/soc/bcm/hifiberry_amp.c
- create mode 100644 sound/soc/codecs/tas5713.c
- create mode 100644 sound/soc/codecs/tas5713.h
-
---- a/sound/soc/bcm/Kconfig
-+++ b/sound/soc/bcm/Kconfig
-@@ -29,6 +29,13 @@ config SND_BCM2708_SOC_HIFIBERRY_DIGI
- help
- Say Y or M if you want to add support for HifiBerry Digi S/PDIF output board.
-
-+config SND_BCM2708_SOC_HIFIBERRY_AMP
-+ tristate "Support for the HifiBerry Amp"
-+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
-+ select SND_SOC_TAS5713
-+ help
-+ Say Y or M if you want to add support for the HifiBerry Amp amplifier board.
-+
- config SND_BCM2708_SOC_RPI_DAC
- tristate "Support for RPi-DAC"
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
---- a/sound/soc/bcm/Makefile
-+++ b/sound/soc/bcm/Makefile
-@@ -7,11 +7,13 @@ obj-$(CONFIG_SND_BCM2835_SOC_I2S) += snd
- snd-soc-hifiberry-dac-objs := hifiberry_dac.o
- snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
- snd-soc-hifiberry-digi-objs := hifiberry_digi.o
-+snd-soc-hifiberry-amp-objs := hifiberry_amp.o
- snd-soc-rpi-dac-objs := rpi-dac.o
- snd-soc-iqaudio-dac-objs := iqaudio-dac.o
-
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o
-+obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o
- obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o
- obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
---- /dev/null
-+++ b/sound/soc/bcm/hifiberry_amp.c
-@@ -0,0 +1,127 @@
-+/*
-+ * ASoC Driver for HifiBerry AMP
-+ *
-+ * Author: Sebastian Eickhoff <basti.eickhoff@googlemail.com>
-+ * Copyright 2014
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+
-+#include <sound/core.h>
-+#include <sound/pcm.h>
-+#include <sound/pcm_params.h>
-+#include <sound/soc.h>
-+#include <sound/jack.h>
-+
-+static int snd_rpi_hifiberry_amp_init(struct snd_soc_pcm_runtime *rtd)
-+{
-+ // ToDo: init of the dsp-registers.
-+ return 0;
-+}
-+
-+static int snd_rpi_hifiberry_amp_hw_params( struct snd_pcm_substream *substream,
-+ struct snd_pcm_hw_params *params )
-+{
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-+
-+ return snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
-+}
-+
-+static struct snd_soc_ops snd_rpi_hifiberry_amp_ops = {
-+ .hw_params = snd_rpi_hifiberry_amp_hw_params,
-+};
-+
-+static struct snd_soc_dai_link snd_rpi_hifiberry_amp_dai[] = {
-+ {
-+ .name = "HifiBerry AMP",
-+ .stream_name = "HifiBerry AMP HiFi",
-+ .cpu_dai_name = "bcm2708-i2s.0",
-+ .codec_dai_name = "tas5713-hifi",
-+ .platform_name = "bcm2708-i2s.0",
-+ .codec_name = "tas5713.1-001b",
-+ .dai_fmt = SND_SOC_DAIFMT_I2S |
-+ SND_SOC_DAIFMT_NB_NF |
-+ SND_SOC_DAIFMT_CBS_CFS,
-+ .ops = &snd_rpi_hifiberry_amp_ops,
-+ .init = snd_rpi_hifiberry_amp_init,
-+ },
-+};
-+
-+
-+static struct snd_soc_card snd_rpi_hifiberry_amp = {
-+ .name = "snd_rpi_hifiberry_amp",
-+ .dai_link = snd_rpi_hifiberry_amp_dai,
-+ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_amp_dai),
-+};
-+
-+static const struct of_device_id snd_rpi_hifiberry_amp_of_match[] = {
-+ { .compatible = "hifiberry,hifiberry-amp", },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_amp_of_match);
-+
-+
-+static int snd_rpi_hifiberry_amp_probe(struct platform_device *pdev)
-+{
-+ int ret = 0;
-+
-+ snd_rpi_hifiberry_amp.dev = &pdev->dev;
-+
-+ if (pdev->dev.of_node) {
-+ struct device_node *i2s_node;
-+ struct snd_soc_dai_link *dai = &snd_rpi_hifiberry_amp_dai[0];
-+ i2s_node = of_parse_phandle(pdev->dev.of_node,
-+ "i2s-controller", 0);
-+
-+ if (i2s_node) {
-+ dai->cpu_dai_name = NULL;
-+ dai->cpu_of_node = i2s_node;
-+ dai->platform_name = NULL;
-+ dai->platform_of_node = i2s_node;
-+ }
-+ }
-+
-+ ret = snd_soc_register_card(&snd_rpi_hifiberry_amp);
-+
-+ if (ret != 0) {
-+ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret);
-+ }
-+
-+ return ret;
-+}
-+
-+
-+static int snd_rpi_hifiberry_amp_remove(struct platform_device *pdev)
-+{
-+ return snd_soc_unregister_card(&snd_rpi_hifiberry_amp);
-+}
-+
-+
-+static struct platform_driver snd_rpi_hifiberry_amp_driver = {
-+ .driver = {
-+ .name = "snd-hifiberry-amp",
-+ .owner = THIS_MODULE,
-+ .of_match_table = snd_rpi_hifiberry_amp_of_match,
-+ },
-+ .probe = snd_rpi_hifiberry_amp_probe,
-+ .remove = snd_rpi_hifiberry_amp_remove,
-+};
-+
-+
-+module_platform_driver(snd_rpi_hifiberry_amp_driver);
-+
-+
-+MODULE_AUTHOR("Sebastian Eickhoff <basti.eickhoff@googlemail.com>");
-+MODULE_DESCRIPTION("ASoC driver for HiFiBerry-AMP");
-+MODULE_LICENSE("GPL v2");
---- a/sound/soc/codecs/Kconfig
-+++ b/sound/soc/codecs/Kconfig
-@@ -117,6 +117,7 @@ config SND_SOC_ALL_CODECS
- select SND_SOC_TFA9879 if I2C
- select SND_SOC_TLV320AIC23_I2C if I2C
- select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
-+ select SND_SOC_TAS5713 if I2C
- select SND_SOC_TLV320AIC26 if SPI_MASTER
- select SND_SOC_TLV320AIC31XX if I2C
- select SND_SOC_TLV320AIC32X4 if I2C
-@@ -674,6 +675,9 @@ config SND_SOC_TFA9879
- tristate "NXP Semiconductors TFA9879 amplifier"
- depends on I2C
-
-+config SND_SOC_TAS5713
-+ tristate
-+
- config SND_SOC_TLV320AIC23
- tristate
-
---- a/sound/soc/codecs/Makefile
-+++ b/sound/soc/codecs/Makefile
-@@ -118,6 +118,7 @@ snd-soc-sti-sas-objs := sti-sas.o
- snd-soc-tas5086-objs := tas5086.o
- snd-soc-tas571x-objs := tas571x.o
- snd-soc-tfa9879-objs := tfa9879.o
-+snd-soc-tas5713-objs := tas5713.o
- snd-soc-tlv320aic23-objs := tlv320aic23.o
- snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
- snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o
-@@ -312,6 +313,7 @@ obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc
- obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o
- obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o
- obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o
-+obj-$(CONFIG_SND_SOC_TAS5713) += snd-soc-tas5713.o
- obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o
- obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o
- obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI) += snd-soc-tlv320aic23-spi.o
---- /dev/null
-+++ b/sound/soc/codecs/tas5713.c
-@@ -0,0 +1,369 @@
-+/*
-+ * ASoC Driver for TAS5713
-+ *
-+ * Author: Sebastian Eickhoff <basti.eickhoff@googlemail.com>
-+ * Copyright 2014
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/moduleparam.h>
-+#include <linux/init.h>
-+#include <linux/delay.h>
-+#include <linux/pm.h>
-+#include <linux/i2c.h>
-+#include <linux/of_device.h>
-+#include <linux/spi/spi.h>
-+#include <linux/regmap.h>
-+#include <linux/regulator/consumer.h>
-+#include <linux/slab.h>
-+#include <sound/core.h>
-+#include <sound/pcm.h>
-+#include <sound/pcm_params.h>
-+#include <sound/soc.h>
-+#include <sound/initval.h>
-+#include <sound/tlv.h>
-+
-+#include <linux/kernel.h>
-+#include <linux/string.h>
-+#include <linux/fs.h>
-+#include <asm/uaccess.h>
-+
-+#include "tas5713.h"
-+
-+
-+static struct i2c_client *i2c;
-+
-+struct tas5713_priv {
-+ struct regmap *regmap;
-+ int mclk_div;
-+ struct snd_soc_codec *codec;
-+};
-+
-+static struct tas5713_priv *priv_data;
-+
-+
-+
-+
-+/*
-+ * _ _ ___ _ ___ _ _
-+ * /_\ | | / __| /_\ / __|___ _ _| |_ _ _ ___| |___
-+ * / _ \| |__\__ \/ _ \ | (__/ _ \ ' \ _| '_/ _ \ (_-<
-+ * /_/ \_\____|___/_/ \_\ \___\___/_||_\__|_| \___/_/__/
-+ *
-+ */
-+
-+static const DECLARE_TLV_DB_SCALE(tas5713_vol_tlv, -10000, 50, 1);
-+
-+
-+static const struct snd_kcontrol_new tas5713_snd_controls[] = {
-+ SOC_SINGLE_TLV ("Master" , TAS5713_VOL_MASTER, 0, 248, 1, tas5713_vol_tlv),
-+ SOC_DOUBLE_R_TLV("Channels" , TAS5713_VOL_CH1, TAS5713_VOL_CH2, 0, 248, 1, tas5713_vol_tlv)
-+};
-+
-+
-+
-+
-+/*
-+ * __ __ _ _ ___ _
-+ * | \/ |__ _ __| |_ (_)_ _ ___ | \ _ _(_)_ _____ _ _
-+ * | |\/| / _` / _| ' \| | ' \/ -_) | |) | '_| \ V / -_) '_|
-+ * |_| |_\__,_\__|_||_|_|_||_\___| |___/|_| |_|\_/\___|_|
-+ *
-+ */
-+
-+static int tas5713_hw_params(struct snd_pcm_substream *substream,
-+ struct snd_pcm_hw_params *params,
-+ struct snd_soc_dai *dai)
-+{
-+ u16 blen = 0x00;
-+
-+ struct snd_soc_codec *codec;
-+ codec = dai->codec;
-+ priv_data->codec = dai->codec;
-+
-+ switch (params_format(params)) {
-+ case SNDRV_PCM_FORMAT_S16_LE:
-+ blen = 0x03;
-+ break;
-+ case SNDRV_PCM_FORMAT_S20_3LE:
-+ blen = 0x1;
-+ break;
-+ case SNDRV_PCM_FORMAT_S24_LE:
-+ blen = 0x04;
-+ break;
-+ case SNDRV_PCM_FORMAT_S32_LE:
-+ blen = 0x05;
-+ break;
-+ default:
-+ dev_err(dai->dev, "Unsupported word length: %u\n",
-+ params_format(params));
-+ return -EINVAL;
-+ }
-+
-+ // set word length
-+ snd_soc_update_bits(codec, TAS5713_SERIAL_DATA_INTERFACE, 0x7, blen);
-+
-+ return 0;
-+}
-+
-+
-+static int tas5713_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
-+{
-+ unsigned int val = 0;
-+
-+ struct tas5713_priv *tas5713;
-+ struct snd_soc_codec *codec = dai->codec;
-+ tas5713 = snd_soc_codec_get_drvdata(codec);
-+
-+ if (mute) {
-+ val = TAS5713_SOFT_MUTE_ALL;
-+ }
-+
-+ return regmap_write(tas5713->regmap, TAS5713_SOFT_MUTE, val);
-+}
-+
-+
-+static const struct snd_soc_dai_ops tas5713_dai_ops = {
-+ .hw_params = tas5713_hw_params,
-+ .mute_stream = tas5713_mute_stream,
-+};
-+
-+
-+static struct snd_soc_dai_driver tas5713_dai = {
-+ .name = "tas5713-hifi",
-+ .playback = {
-+ .stream_name = "Playback",
-+ .channels_min = 2,
-+ .channels_max = 2,
-+ .rates = SNDRV_PCM_RATE_8000_48000,
-+ .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE ),
-+ },
-+ .ops = &tas5713_dai_ops,
-+};
-+
-+
-+
-+
-+/*
-+ * ___ _ ___ _
-+ * / __|___ __| |___ __ | \ _ _(_)_ _____ _ _
-+ * | (__/ _ \/ _` / -_) _| | |) | '_| \ V / -_) '_|
-+ * \___\___/\__,_\___\__| |___/|_| |_|\_/\___|_|
-+ *
-+ */
-+
-+static int tas5713_remove(struct snd_soc_codec *codec)
-+{
-+ struct tas5713_priv *tas5713;
-+
-+ tas5713 = snd_soc_codec_get_drvdata(codec);
-+
-+ return 0;
-+}
-+
-+
-+static int tas5713_probe(struct snd_soc_codec *codec)
-+{
-+ struct tas5713_priv *tas5713;
-+ int i, ret;
-+
-+ i2c = container_of(codec->dev, struct i2c_client, dev);
-+
-+ tas5713 = snd_soc_codec_get_drvdata(codec);
-+
-+ // Reset error
-+ ret = snd_soc_write(codec, TAS5713_ERROR_STATUS, 0x00);
-+ if (ret < 0) return ret;
-+
-+ // Trim oscillator
-+ ret = snd_soc_write(codec, TAS5713_OSC_TRIM, 0x00);
-+ if (ret < 0) return ret;
-+ msleep(1000);
-+
-+ // Reset error
-+ ret = snd_soc_write(codec, TAS5713_ERROR_STATUS, 0x00);
-+ if (ret < 0) return ret;
-+
-+ // Clock mode: 44/48kHz, MCLK=64xfs
-+ ret = snd_soc_write(codec, TAS5713_CLOCK_CTRL, 0x60);
-+ if (ret < 0) return ret;
-+
-+ // I2S 24bit
-+ ret = snd_soc_write(codec, TAS5713_SERIAL_DATA_INTERFACE, 0x05);
-+ if (ret < 0) return ret;
-+
-+ // Unmute
-+ ret = snd_soc_write(codec, TAS5713_SYSTEM_CTRL2, 0x00);
-+ if (ret < 0) return ret;
-+ ret = snd_soc_write(codec, TAS5713_SOFT_MUTE, 0x00);
-+ if (ret < 0) return ret;
-+
-+ // Set volume to 0db
-+ ret = snd_soc_write(codec, TAS5713_VOL_MASTER, 0x00);
-+ if (ret < 0) return ret;
-+
-+ // Now start programming the default initialization sequence
-+ for (i = 0; i < ARRAY_SIZE(tas5713_init_sequence); ++i) {
-+ ret = i2c_master_send(i2c,
-+ tas5713_init_sequence[i].data,
-+ tas5713_init_sequence[i].size);
-+ if (ret < 0) {
-+ printk(KERN_INFO "TAS5713 CODEC PROBE: InitSeq returns: %d\n", ret);
-+ }
-+ }
-+
-+ // Unmute
-+ ret = snd_soc_write(codec, TAS5713_SYSTEM_CTRL2, 0x00);
-+ if (ret < 0) return ret;
-+
-+ return 0;
-+}
-+
-+
-+static struct snd_soc_codec_driver soc_codec_dev_tas5713 = {
-+ .probe = tas5713_probe,
-+ .remove = tas5713_remove,
-+ .controls = tas5713_snd_controls,
-+ .num_controls = ARRAY_SIZE(tas5713_snd_controls),
-+};
-+
-+
-+
-+
-+/*
-+ * ___ ___ ___ ___ _
-+ * |_ _|_ ) __| | \ _ _(_)_ _____ _ _
-+ * | | / / (__ | |) | '_| \ V / -_) '_|
-+ * |___/___\___| |___/|_| |_|\_/\___|_|
-+ *
-+ */
-+
-+static const struct reg_default tas5713_reg_defaults[] = {
-+ { 0x07 ,0x80 }, // R7 - VOL_MASTER - -40dB
-+ { 0x08 , 30 }, // R8 - VOL_CH1 - 0dB
-+ { 0x09 , 30 }, // R9 - VOL_CH2 - 0dB
-+ { 0x0A ,0x80 }, // R10 - VOL_HEADPHONE - -40dB
-+};
-+
-+
-+static bool tas5713_reg_volatile(struct device *dev, unsigned int reg)
-+{
-+ switch (reg) {
-+ case TAS5713_DEVICE_ID:
-+ case TAS5713_ERROR_STATUS:
-+ return true;
-+ default:
-+ return false;
-+ }
-+}
-+
-+
-+static const struct of_device_id tas5713_of_match[] = {
-+ { .compatible = "ti,tas5713", },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(of, tas5713_of_match);
-+
-+
-+static struct regmap_config tas5713_regmap_config = {
-+ .reg_bits = 8,
-+ .val_bits = 8,
-+
-+ .max_register = TAS5713_MAX_REGISTER,
-+ .volatile_reg = tas5713_reg_volatile,
-+
-+ .cache_type = REGCACHE_RBTREE,
-+ .reg_defaults = tas5713_reg_defaults,
-+ .num_reg_defaults = ARRAY_SIZE(tas5713_reg_defaults),
-+};
-+
-+
-+static int tas5713_i2c_probe(struct i2c_client *i2c,
-+ const struct i2c_device_id *id)
-+{
-+ int ret;
-+
-+ priv_data = devm_kzalloc(&i2c->dev, sizeof *priv_data, GFP_KERNEL);
-+ if (!priv_data)
-+ return -ENOMEM;
-+
-+ priv_data->regmap = devm_regmap_init_i2c(i2c, &tas5713_regmap_config);
-+ if (IS_ERR(priv_data->regmap)) {
-+ ret = PTR_ERR(priv_data->regmap);
-+ return ret;
-+ }
-+
-+ i2c_set_clientdata(i2c, priv_data);
-+
-+ ret = snd_soc_register_codec(&i2c->dev,
-+ &soc_codec_dev_tas5713, &tas5713_dai, 1);
-+
-+ return ret;
-+}
-+
-+
-+static int tas5713_i2c_remove(struct i2c_client *i2c)
-+{
-+ snd_soc_unregister_codec(&i2c->dev);
-+ i2c_set_clientdata(i2c, NULL);
-+
-+ kfree(priv_data);
-+
-+ return 0;
-+}
-+
-+
-+static const struct i2c_device_id tas5713_i2c_id[] = {
-+ { "tas5713", 0 },
-+ { }
-+};
-+
-+MODULE_DEVICE_TABLE(i2c, tas5713_i2c_id);
-+
-+
-+static struct i2c_driver tas5713_i2c_driver = {
-+ .driver = {
-+ .name = "tas5713",
-+ .owner = THIS_MODULE,
-+ .of_match_table = tas5713_of_match,
-+ },
-+ .probe = tas5713_i2c_probe,
-+ .remove = tas5713_i2c_remove,
-+ .id_table = tas5713_i2c_id
-+};
-+
-+
-+static int __init tas5713_modinit(void)
-+{
-+ int ret = 0;
-+
-+ ret = i2c_add_driver(&tas5713_i2c_driver);
-+ if (ret) {
-+ printk(KERN_ERR "Failed to register tas5713 I2C driver: %d\n",
-+ ret);
-+ }
-+
-+ return ret;
-+}
-+module_init(tas5713_modinit);
-+
-+
-+static void __exit tas5713_exit(void)
-+{
-+ i2c_del_driver(&tas5713_i2c_driver);
-+}
-+module_exit(tas5713_exit);
-+
-+
-+MODULE_AUTHOR("Sebastian Eickhoff <basti.eickhoff@googlemail.com>");
-+MODULE_DESCRIPTION("ASoC driver for TAS5713");
-+MODULE_LICENSE("GPL v2");
---- /dev/null
-+++ b/sound/soc/codecs/tas5713.h
-@@ -0,0 +1,210 @@
-+/*
-+ * ASoC Driver for TAS5713
-+ *
-+ * Author: Sebastian Eickhoff <basti.eickhoff@googlemail.com>
-+ * Copyright 2014
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ */
-+
-+#ifndef _TAS5713_H
-+#define _TAS5713_H
-+
-+
-+// TAS5713 I2C-bus register addresses
-+
-+#define TAS5713_CLOCK_CTRL 0x00
-+#define TAS5713_DEVICE_ID 0x01
-+#define TAS5713_ERROR_STATUS 0x02
-+#define TAS5713_SYSTEM_CTRL1 0x03
-+#define TAS5713_SERIAL_DATA_INTERFACE 0x04
-+#define TAS5713_SYSTEM_CTRL2 0x05
-+#define TAS5713_SOFT_MUTE 0x06
-+#define TAS5713_VOL_MASTER 0x07
-+#define TAS5713_VOL_CH1 0x08
-+#define TAS5713_VOL_CH2 0x09
-+#define TAS5713_VOL_HEADPHONE 0x0A
-+#define TAS5713_VOL_CONFIG 0x0E
-+#define TAS5713_MODULATION_LIMIT 0x10
-+#define TAS5713_IC_DLY_CH1 0x11
-+#define TAS5713_IC_DLY_CH2 0x12
-+#define TAS5713_IC_DLY_CH3 0x13
-+#define TAS5713_IC_DLY_CH4 0x14
-+
-+#define TAS5713_START_STOP_PERIOD 0x1A
-+#define TAS5713_OSC_TRIM 0x1B
-+#define TAS5713_BKND_ERR 0x1C
-+
-+#define TAS5713_INPUT_MUX 0x20
-+#define TAS5713_SRC_SELECT_CH4 0x21
-+#define TAS5713_PWM_MUX 0x25
-+
-+#define TAS5713_CH1_BQ0 0x29
-+#define TAS5713_CH1_BQ1 0x2A
-+#define TAS5713_CH1_BQ2 0x2B
-+#define TAS5713_CH1_BQ3 0x2C
-+#define TAS5713_CH1_BQ4 0x2D
-+#define TAS5713_CH1_BQ5 0x2E
-+#define TAS5713_CH1_BQ6 0x2F
-+#define TAS5713_CH1_BQ7 0x58
-+#define TAS5713_CH1_BQ8 0x59
-+
-+#define TAS5713_CH2_BQ0 0x30
-+#define TAS5713_CH2_BQ1 0x31
-+#define TAS5713_CH2_BQ2 0x32
-+#define TAS5713_CH2_BQ3 0x33
-+#define TAS5713_CH2_BQ4 0x34
-+#define TAS5713_CH2_BQ5 0x35
-+#define TAS5713_CH2_BQ6 0x36
-+#define TAS5713_CH2_BQ7 0x5C
-+#define TAS5713_CH2_BQ8 0x5D
-+
-+#define TAS5713_CH4_BQ0 0x5A
-+#define TAS5713_CH4_BQ1 0x5B
-+#define TAS5713_CH3_BQ0 0x5E
-+#define TAS5713_CH3_BQ1 0x5F
-+
-+#define TAS5713_DRC1_SOFTENING_FILTER_ALPHA_OMEGA 0x3B
-+#define TAS5713_DRC1_ATTACK_RELEASE_RATE 0x3C
-+#define TAS5713_DRC2_SOFTENING_FILTER_ALPHA_OMEGA 0x3E
-+#define TAS5713_DRC2_ATTACK_RELEASE_RATE 0x3F
-+#define TAS5713_DRC1_ATTACK_RELEASE_THRES 0x40
-+#define TAS5713_DRC2_ATTACK_RELEASE_THRES 0x43
-+#define TAS5713_DRC_CTRL 0x46
-+
-+#define TAS5713_BANK_SW_CTRL 0x50
-+#define TAS5713_CH1_OUTPUT_MIXER 0x51
-+#define TAS5713_CH2_OUTPUT_MIXER 0x52
-+#define TAS5713_CH1_INPUT_MIXER 0x53
-+#define TAS5713_CH2_INPUT_MIXER 0x54
-+#define TAS5713_OUTPUT_POST_SCALE 0x56
-+#define TAS5713_OUTPUT_PRESCALE 0x57
-+
-+#define TAS5713_IDF_POST_SCALE 0x62
-+
-+#define TAS5713_CH1_INLINE_MIXER 0x70
-+#define TAS5713_CH1_INLINE_DRC_EN_MIXER 0x71
-+#define TAS5713_CH1_R_CHANNEL_MIXER 0x72
-+#define TAS5713_CH1_L_CHANNEL_MIXER 0x73
-+#define TAS5713_CH2_INLINE_MIXER 0x74
-+#define TAS5713_CH2_INLINE_DRC_EN_MIXER 0x75
-+#define TAS5713_CH2_L_CHANNEL_MIXER 0x76
-+#define TAS5713_CH2_R_CHANNEL_MIXER 0x77
-+
-+#define TAS5713_UPDATE_DEV_ADDR_KEY 0xF8
-+#define TAS5713_UPDATE_DEV_ADDR_REG 0xF9
-+
-+#define TAS5713_REGISTER_COUNT 0x46
-+#define TAS5713_MAX_REGISTER 0xF9
-+
-+
-+// Bitmasks for registers
-+#define TAS5713_SOFT_MUTE_ALL 0x07
-+
-+
-+
-+struct tas5713_init_command {
-+ const int size;
-+ const char *const data;
-+};
-+
-+static const struct tas5713_init_command tas5713_init_sequence[] = {
-+
-+ // Trim oscillator
-+ { .size = 2, .data = "\x1B\x00" },
-+ // System control register 1 (0x03): block DC
-+ { .size = 2, .data = "\x03\x80" },
-+ // Mute everything
-+ { .size = 2, .data = "\x05\x40" },
-+ // Modulation limit register (0x10): 97.7%
-+ { .size = 2, .data = "\x10\x02" },
-+ // Interchannel delay registers
-+ // (0x11, 0x12, 0x13, and 0x14): BD mode
-+ { .size = 2, .data = "\x11\xB8" },
-+ { .size = 2, .data = "\x12\x60" },
-+ { .size = 2, .data = "\x13\xA0" },
-+ { .size = 2, .data = "\x14\x48" },
-+ // PWM shutdown group register (0x19): no shutdown
-+ { .size = 2, .data = "\x19\x00" },
-+ // Input multiplexer register (0x20): BD mode
-+ { .size = 2, .data = "\x20\x00\x89\x77\x72" },
-+ // PWM output mux register (0x25)
-+ // Channel 1 --> OUTA, channel 1 neg --> OUTB
-+ // Channel 2 --> OUTC, channel 2 neg --> OUTD
-+ { .size = 5, .data = "\x25\x01\x02\x13\x45" },
-+ // DRC control (0x46): DRC off
-+ { .size = 5, .data = "\x46\x00\x00\x00\x00" },
-+ // BKND_ERR register (0x1C): 299ms reset period
-+ { .size = 2, .data = "\x1C\x07" },
-+ // Mute channel 3
-+ { .size = 2, .data = "\x0A\xFF" },
-+ // Volume configuration register (0x0E): volume slew 512 steps
-+ { .size = 2, .data = "\x0E\x90" },
-+ // Clock control register (0x00): 44/48kHz, MCLK=64xfs
-+ { .size = 2, .data = "\x00\x60" },
-+ // Bank switch and eq control (0x50): no bank switching
-+ { .size = 5, .data = "\x50\x00\x00\x00\x00" },
-+ // Volume registers (0x07, 0x08, 0x09, 0x0A)
-+ { .size = 2, .data = "\x07\x20" },
-+ { .size = 2, .data = "\x08\x30" },
-+ { .size = 2, .data = "\x09\x30" },
-+ { .size = 2, .data = "\x0A\xFF" },
-+ // 0x72, 0x73, 0x76, 0x77 input mixer:
-+ // no intermix between channels
-+ { .size = 5, .data = "\x72\x00\x00\x00\x00" },
-+ { .size = 5, .data = "\x73\x00\x80\x00\x00" },
-+ { .size = 5, .data = "\x76\x00\x00\x00\x00" },
-+ { .size = 5, .data = "\x77\x00\x80\x00\x00" },
-+ // 0x70, 0x71, 0x74, 0x75 inline DRC mixer:
-+ // no inline DRC inmix
-+ { .size = 5, .data = "\x70\x00\x80\x00\x00" },
-+ { .size = 5, .data = "\x71\x00\x00\x00\x00" },
-+ { .size = 5, .data = "\x74\x00\x80\x00\x00" },
-+ { .size = 5, .data = "\x75\x00\x00\x00\x00" },
-+ // 0x56, 0x57 Output scale
-+ { .size = 5, .data = "\x56\x00\x80\x00\x00" },
-+ { .size = 5, .data = "\x57\x00\x02\x00\x00" },
-+ // 0x3B, 0x3c
-+ { .size = 9, .data = "\x3B\x00\x08\x00\x00\x00\x78\x00\x00" },
-+ { .size = 9, .data = "\x3C\x00\x00\x01\x00\xFF\xFF\xFF\x00" },
-+ { .size = 9, .data = "\x3E\x00\x08\x00\x00\x00\x78\x00\x00" },
-+ { .size = 9, .data = "\x3F\x00\x00\x01\x00\xFF\xFF\xFF\x00" },
-+ { .size = 9, .data = "\x40\x00\x00\x01\x00\xFF\xFF\xFF\x00" },
-+ { .size = 9, .data = "\x43\x00\x00\x01\x00\xFF\xFF\xFF\x00" },
-+ // 0x51, 0x52: output mixer
-+ { .size = 9, .data = "\x51\x00\x80\x00\x00\x00\x00\x00\x00" },
-+ { .size = 9, .data = "\x52\x00\x80\x00\x00\x00\x00\x00\x00" },
-+ // PEQ defaults
-+ { .size = 21, .data = "\x29\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
-+ { .size = 21, .data = "\x2A\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
-+ { .size = 21, .data = "\x2B\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
-+ { .size = 21, .data = "\x2C\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
-+ { .size = 21, .data = "\x2D\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
-+ { .size = 21, .data = "\x2E\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
-+ { .size = 21, .data = "\x2F\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
-+ { .size = 21, .data = "\x30\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
-+ { .size = 21, .data = "\x31\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
-+ { .size = 21, .data = "\x32\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
-+ { .size = 21, .data = "\x33\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
-+ { .size = 21, .data = "\x34\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
-+ { .size = 21, .data = "\x35\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
-+ { .size = 21, .data = "\x36\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
-+ { .size = 21, .data = "\x58\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
-+ { .size = 21, .data = "\x59\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
-+ { .size = 21, .data = "\x5C\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
-+ { .size = 21, .data = "\x5D\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
-+ { .size = 21, .data = "\x5E\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
-+ { .size = 21, .data = "\x5F\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
-+ { .size = 21, .data = "\x5A\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
-+ { .size = 21, .data = "\x5B\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
-+};
-+
-+
-+#endif /* _TAS5713_H */
diff --git a/target/linux/brcm2708/patches-4.4/0072-Update-ds1307-driver-for-device-tree-support.patch b/target/linux/brcm2708/patches-4.4/0072-Update-ds1307-driver-for-device-tree-support.patch
new file mode 100644
index 0000000000..f8fdc78e91
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0072-Update-ds1307-driver-for-device-tree-support.patch
@@ -0,0 +1,27 @@
+From 1e1cdd39b3ed1a3488e796367f6e339dbe2ecaaa Mon Sep 17 00:00:00 2001
+From: Ryan Coe <bluemrp9@gmail.com>
+Date: Sat, 31 Jan 2015 18:25:49 -0700
+Subject: [PATCH 072/381] Update ds1307 driver for device-tree support
+
+Signed-off-by: Ryan Coe <bluemrp9@gmail.com>
+---
+ drivers/rtc/rtc-ds1307.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/drivers/rtc/rtc-ds1307.c
++++ b/drivers/rtc/rtc-ds1307.c
+@@ -1207,6 +1207,14 @@ static int ds1307_remove(struct i2c_clie
+ return 0;
+ }
+
++#ifdef CONFIG_OF
++static const struct of_device_id ds1307_of_match[] = {
++ { .compatible = "maxim,ds1307" },
++ { }
++};
++MODULE_DEVICE_TABLE(of, ds1307_of_match);
++#endif
++
+ static struct i2c_driver ds1307_driver = {
+ .driver = {
+ .name = "rtc-ds1307",
diff --git a/target/linux/brcm2708/patches-4.4/0073-BCM270x_DT-Add-pwr_led-and-the-required-input-trigge.patch b/target/linux/brcm2708/patches-4.4/0073-BCM270x_DT-Add-pwr_led-and-the-required-input-trigge.patch
new file mode 100644
index 0000000000..0990835f8f
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0073-BCM270x_DT-Add-pwr_led-and-the-required-input-trigge.patch
@@ -0,0 +1,170 @@
+From 211b0053ad2b173e646e4db1b5dd2f51a2da4ed7 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 6 Feb 2015 13:50:57 +0000
+Subject: [PATCH 073/381] BCM270x_DT: Add pwr_led, and the required "input"
+ trigger
+
+The "input" trigger makes the associated GPIO an input. This is to support
+the Raspberry Pi PWR LED, which is driven by external hardware in normal use.
+
+N.B. pwr_led is not available on Model A or B boards.
+
+leds-gpio: Implement the brightness_get method
+
+The power LED uses some clever logic that means it is driven
+by a voltage measuring circuit when configured as input, otherwise
+it is driven by the GPIO output value. This patch wires up the
+brightness_get method for leds-gpio so that user-space can monitor
+the LED value via /sys/class/gpio/led1/brightness. Using the input
+trigger this returns an indication of the system power health,
+otherwise it is just whatever value the trigger has written most
+recently.
+
+See: https://github.com/raspberrypi/linux/issues/1064
+---
+ drivers/leds/leds-gpio.c | 18 +++++++++++-
+ drivers/leds/trigger/Kconfig | 7 +++++
+ drivers/leds/trigger/Makefile | 1 +
+ drivers/leds/trigger/ledtrig-input.c | 54 ++++++++++++++++++++++++++++++++++++
+ include/linux/leds.h | 3 ++
+ 5 files changed, 82 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/leds/trigger/ledtrig-input.c
+
+--- a/drivers/leds/leds-gpio.c
++++ b/drivers/leds/leds-gpio.c
+@@ -42,6 +42,13 @@ static void gpio_led_work(struct work_st
+ led_dat->platform_gpio_blink_set(led_dat->gpiod,
+ led_dat->new_level, NULL, NULL);
+ led_dat->blinking = 0;
++ } else if (led_dat->cdev.flags & SET_GPIO_INPUT) {
++ gpiod_direction_input(led_dat->gpiod);
++ led_dat->cdev.flags &= ~SET_GPIO_INPUT;
++ }
++ else if (led_dat->cdev.flags & SET_GPIO_OUTPUT) {
++ gpiod_direction_output(led_dat->gpiod, led_dat->new_level);
++ led_dat->cdev.flags &= ~SET_GPIO_OUTPUT;
+ } else
+ gpiod_set_value_cansleep(led_dat->gpiod, led_dat->new_level);
+ }
+@@ -62,7 +69,8 @@ static void gpio_led_set(struct led_clas
+ * seem to have a reliable way to know if we're already in one; so
+ * let's just assume the worst.
+ */
+- if (led_dat->can_sleep) {
++ if (led_dat->can_sleep ||
++ (led_dat->cdev.flags & (SET_GPIO_INPUT | SET_GPIO_OUTPUT) )) {
+ led_dat->new_level = level;
+ schedule_work(&led_dat->work);
+ } else {
+@@ -75,6 +83,13 @@ static void gpio_led_set(struct led_clas
+ }
+ }
+
++static enum led_brightness gpio_led_get(struct led_classdev *led_cdev)
++{
++ struct gpio_led_data *led_dat =
++ container_of(led_cdev, struct gpio_led_data, cdev);
++ return gpiod_get_value_cansleep(led_dat->gpiod) ? LED_FULL : LED_OFF;
++}
++
+ static int gpio_blink_set(struct led_classdev *led_cdev,
+ unsigned long *delay_on, unsigned long *delay_off)
+ {
+@@ -131,6 +146,7 @@ static int create_gpio_led(const struct
+ led_dat->cdev.blink_set = gpio_blink_set;
+ }
+ led_dat->cdev.brightness_set = gpio_led_set;
++ led_dat->cdev.brightness_get = gpio_led_get;
+ if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP)
+ state = !!gpiod_get_value_cansleep(led_dat->gpiod);
+ else
+--- a/drivers/leds/trigger/Kconfig
++++ b/drivers/leds/trigger/Kconfig
+@@ -126,4 +126,11 @@ config LEDS_TRIGGER_USBDEV
+ This allows LEDs to be controlled by the presence/activity of
+ an USB device. If unsure, say N.
+
++config LEDS_TRIGGER_INPUT
++ tristate "LED Input Trigger"
++ depends on LEDS_TRIGGERS
++ help
++ This allows the GPIOs assigned to be LEDs to be initialised to inputs.
++ If unsure, say Y.
++
+ endif # LEDS_TRIGGERS
+--- a/drivers/leds/trigger/Makefile
++++ b/drivers/leds/trigger/Makefile
+@@ -8,3 +8,4 @@ obj-$(CONFIG_LEDS_TRIGGER_CPU) += ledtr
+ obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o
+ obj-$(CONFIG_LEDS_TRIGGER_TRANSIENT) += ledtrig-transient.o
+ obj-$(CONFIG_LEDS_TRIGGER_CAMERA) += ledtrig-camera.o
++obj-$(CONFIG_LEDS_TRIGGER_INPUT) += ledtrig-input.o
+--- /dev/null
++++ b/drivers/leds/trigger/ledtrig-input.c
+@@ -0,0 +1,54 @@
++/*
++ * Set LED GPIO to Input "Trigger"
++ *
++ * Copyright 2015 Phil Elwell <phil@raspberrypi.org>
++ *
++ * Based on Nick Forbes's ledtrig-default-on.c.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/leds.h>
++#include <linux/gpio.h>
++#include "../leds.h"
++
++static void input_trig_activate(struct led_classdev *led_cdev)
++{
++ led_cdev->flags |= SET_GPIO_INPUT;
++ led_set_brightness_async(led_cdev, 0);
++}
++
++static void input_trig_deactivate(struct led_classdev *led_cdev)
++{
++ led_cdev->flags |= SET_GPIO_OUTPUT;
++ led_set_brightness_async(led_cdev, 0);
++}
++
++static struct led_trigger input_led_trigger = {
++ .name = "input",
++ .activate = input_trig_activate,
++ .deactivate = input_trig_deactivate,
++};
++
++static int __init input_trig_init(void)
++{
++ return led_trigger_register(&input_led_trigger);
++}
++
++static void __exit input_trig_exit(void)
++{
++ led_trigger_unregister(&input_led_trigger);
++}
++
++module_init(input_trig_init);
++module_exit(input_trig_exit);
++
++MODULE_AUTHOR("Phil Elwell <phil@raspberrypi.org>");
++MODULE_DESCRIPTION("Set LED GPIO to Input \"trigger\"");
++MODULE_LICENSE("GPL");
+--- a/include/linux/leds.h
++++ b/include/linux/leds.h
+@@ -48,6 +48,9 @@ struct led_classdev {
+ #define SET_BRIGHTNESS_ASYNC (1 << 21)
+ #define SET_BRIGHTNESS_SYNC (1 << 22)
+ #define LED_DEV_CAP_FLASH (1 << 23)
++ /* Additions for Raspberry Pi PWR LED */
++#define SET_GPIO_INPUT (1 << 30)
++#define SET_GPIO_OUTPUT (1 << 31)
+
+ /* Set LED brightness level */
+ /* Must not sleep, use a workqueue if needed */
diff --git a/target/linux/brcm2708/patches-4.4/0073-Update-ds1307-driver-for-device-tree-support.patch b/target/linux/brcm2708/patches-4.4/0073-Update-ds1307-driver-for-device-tree-support.patch
deleted file mode 100644
index 73afc0975b..0000000000
--- a/target/linux/brcm2708/patches-4.4/0073-Update-ds1307-driver-for-device-tree-support.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-From 21d08f232ffc350b2930f761f3da26f9867b1d4d Mon Sep 17 00:00:00 2001
-From: Ryan Coe <bluemrp9@gmail.com>
-Date: Sat, 31 Jan 2015 18:25:49 -0700
-Subject: [PATCH 073/170] Update ds1307 driver for device-tree support
-
-Signed-off-by: Ryan Coe <bluemrp9@gmail.com>
----
- drivers/rtc/rtc-ds1307.c | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
---- a/drivers/rtc/rtc-ds1307.c
-+++ b/drivers/rtc/rtc-ds1307.c
-@@ -1207,6 +1207,14 @@ static int ds1307_remove(struct i2c_clie
- return 0;
- }
-
-+#ifdef CONFIG_OF
-+static const struct of_device_id ds1307_of_match[] = {
-+ { .compatible = "maxim,ds1307" },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(of, ds1307_of_match);
-+#endif
-+
- static struct i2c_driver ds1307_driver = {
- .driver = {
- .name = "rtc-ds1307",
diff --git a/target/linux/brcm2708/patches-4.4/0074-BCM270x_DT-Add-pwr_led-and-the-required-input-trigge.patch b/target/linux/brcm2708/patches-4.4/0074-BCM270x_DT-Add-pwr_led-and-the-required-input-trigge.patch
deleted file mode 100644
index 2c5fe9907f..0000000000
--- a/target/linux/brcm2708/patches-4.4/0074-BCM270x_DT-Add-pwr_led-and-the-required-input-trigge.patch
+++ /dev/null
@@ -1,170 +0,0 @@
-From a2b52a3af1314e2b691d9518afb3051193758671 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Fri, 6 Feb 2015 13:50:57 +0000
-Subject: [PATCH 074/170] BCM270x_DT: Add pwr_led, and the required "input"
- trigger
-
-The "input" trigger makes the associated GPIO an input. This is to support
-the Raspberry Pi PWR LED, which is driven by external hardware in normal use.
-
-N.B. pwr_led is not available on Model A or B boards.
-
-leds-gpio: Implement the brightness_get method
-
-The power LED uses some clever logic that means it is driven
-by a voltage measuring circuit when configured as input, otherwise
-it is driven by the GPIO output value. This patch wires up the
-brightness_get method for leds-gpio so that user-space can monitor
-the LED value via /sys/class/gpio/led1/brightness. Using the input
-trigger this returns an indication of the system power health,
-otherwise it is just whatever value the trigger has written most
-recently.
-
-See: https://github.com/raspberrypi/linux/issues/1064
----
- drivers/leds/leds-gpio.c | 18 +++++++++++-
- drivers/leds/trigger/Kconfig | 7 +++++
- drivers/leds/trigger/Makefile | 1 +
- drivers/leds/trigger/ledtrig-input.c | 54 ++++++++++++++++++++++++++++++++++++
- include/linux/leds.h | 3 ++
- 5 files changed, 82 insertions(+), 1 deletion(-)
- create mode 100644 drivers/leds/trigger/ledtrig-input.c
-
---- a/drivers/leds/leds-gpio.c
-+++ b/drivers/leds/leds-gpio.c
-@@ -42,6 +42,13 @@ static void gpio_led_work(struct work_st
- led_dat->platform_gpio_blink_set(led_dat->gpiod,
- led_dat->new_level, NULL, NULL);
- led_dat->blinking = 0;
-+ } else if (led_dat->cdev.flags & SET_GPIO_INPUT) {
-+ gpiod_direction_input(led_dat->gpiod);
-+ led_dat->cdev.flags &= ~SET_GPIO_INPUT;
-+ }
-+ else if (led_dat->cdev.flags & SET_GPIO_OUTPUT) {
-+ gpiod_direction_output(led_dat->gpiod, led_dat->new_level);
-+ led_dat->cdev.flags &= ~SET_GPIO_OUTPUT;
- } else
- gpiod_set_value_cansleep(led_dat->gpiod, led_dat->new_level);
- }
-@@ -62,7 +69,8 @@ static void gpio_led_set(struct led_clas
- * seem to have a reliable way to know if we're already in one; so
- * let's just assume the worst.
- */
-- if (led_dat->can_sleep) {
-+ if (led_dat->can_sleep ||
-+ (led_dat->cdev.flags & (SET_GPIO_INPUT | SET_GPIO_OUTPUT) )) {
- led_dat->new_level = level;
- schedule_work(&led_dat->work);
- } else {
-@@ -75,6 +83,13 @@ static void gpio_led_set(struct led_clas
- }
- }
-
-+static enum led_brightness gpio_led_get(struct led_classdev *led_cdev)
-+{
-+ struct gpio_led_data *led_dat =
-+ container_of(led_cdev, struct gpio_led_data, cdev);
-+ return gpiod_get_value_cansleep(led_dat->gpiod) ? LED_FULL : LED_OFF;
-+}
-+
- static int gpio_blink_set(struct led_classdev *led_cdev,
- unsigned long *delay_on, unsigned long *delay_off)
- {
-@@ -131,6 +146,7 @@ static int create_gpio_led(const struct
- led_dat->cdev.blink_set = gpio_blink_set;
- }
- led_dat->cdev.brightness_set = gpio_led_set;
-+ led_dat->cdev.brightness_get = gpio_led_get;
- if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP)
- state = !!gpiod_get_value_cansleep(led_dat->gpiod);
- else
---- a/drivers/leds/trigger/Kconfig
-+++ b/drivers/leds/trigger/Kconfig
-@@ -126,4 +126,11 @@ config LEDS_TRIGGER_USBDEV
- This allows LEDs to be controlled by the presence/activity of
- an USB device. If unsure, say N.
-
-+config LEDS_TRIGGER_INPUT
-+ tristate "LED Input Trigger"
-+ depends on LEDS_TRIGGERS
-+ help
-+ This allows the GPIOs assigned to be LEDs to be initialised to inputs.
-+ If unsure, say Y.
-+
- endif # LEDS_TRIGGERS
---- a/drivers/leds/trigger/Makefile
-+++ b/drivers/leds/trigger/Makefile
-@@ -8,3 +8,4 @@ obj-$(CONFIG_LEDS_TRIGGER_CPU) += ledtr
- obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o
- obj-$(CONFIG_LEDS_TRIGGER_TRANSIENT) += ledtrig-transient.o
- obj-$(CONFIG_LEDS_TRIGGER_CAMERA) += ledtrig-camera.o
-+obj-$(CONFIG_LEDS_TRIGGER_INPUT) += ledtrig-input.o
---- /dev/null
-+++ b/drivers/leds/trigger/ledtrig-input.c
-@@ -0,0 +1,54 @@
-+/*
-+ * Set LED GPIO to Input "Trigger"
-+ *
-+ * Copyright 2015 Phil Elwell <phil@raspberrypi.org>
-+ *
-+ * Based on Nick Forbes's ledtrig-default-on.c.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/leds.h>
-+#include <linux/gpio.h>
-+#include "../leds.h"
-+
-+static void input_trig_activate(struct led_classdev *led_cdev)
-+{
-+ led_cdev->flags |= SET_GPIO_INPUT;
-+ led_set_brightness_async(led_cdev, 0);
-+}
-+
-+static void input_trig_deactivate(struct led_classdev *led_cdev)
-+{
-+ led_cdev->flags |= SET_GPIO_OUTPUT;
-+ led_set_brightness_async(led_cdev, 0);
-+}
-+
-+static struct led_trigger input_led_trigger = {
-+ .name = "input",
-+ .activate = input_trig_activate,
-+ .deactivate = input_trig_deactivate,
-+};
-+
-+static int __init input_trig_init(void)
-+{
-+ return led_trigger_register(&input_led_trigger);
-+}
-+
-+static void __exit input_trig_exit(void)
-+{
-+ led_trigger_unregister(&input_led_trigger);
-+}
-+
-+module_init(input_trig_init);
-+module_exit(input_trig_exit);
-+
-+MODULE_AUTHOR("Phil Elwell <phil@raspberrypi.org>");
-+MODULE_DESCRIPTION("Set LED GPIO to Input \"trigger\"");
-+MODULE_LICENSE("GPL");
---- a/include/linux/leds.h
-+++ b/include/linux/leds.h
-@@ -48,6 +48,9 @@ struct led_classdev {
- #define SET_BRIGHTNESS_ASYNC (1 << 21)
- #define SET_BRIGHTNESS_SYNC (1 << 22)
- #define LED_DEV_CAP_FLASH (1 << 23)
-+ /* Additions for Raspberry Pi PWR LED */
-+#define SET_GPIO_INPUT (1 << 30)
-+#define SET_GPIO_OUTPUT (1 << 31)
-
- /* Set LED brightness level */
- /* Must not sleep, use a workqueue if needed */
diff --git a/target/linux/brcm2708/patches-4.4/0074-enc28j60-Add-device-tree-compatible-string-and-an-ov.patch b/target/linux/brcm2708/patches-4.4/0074-enc28j60-Add-device-tree-compatible-string-and-an-ov.patch
new file mode 100644
index 0000000000..e8287ef83c
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0074-enc28j60-Add-device-tree-compatible-string-and-an-ov.patch
@@ -0,0 +1,29 @@
+From 3a1b6b5d57c7f92e98338172dec58c8cd3f2141f Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 27 Feb 2015 15:10:24 +0000
+Subject: [PATCH 074/381] enc28j60: Add device tree compatible string and an
+ overlay
+
+---
+ drivers/net/ethernet/microchip/enc28j60.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/drivers/net/ethernet/microchip/enc28j60.c
++++ b/drivers/net/ethernet/microchip/enc28j60.c
+@@ -1630,9 +1630,16 @@ static int enc28j60_remove(struct spi_de
+ return 0;
+ }
+
++static const struct of_device_id enc28j60_of_match[] = {
++ { .compatible = "microchip,enc28j60", },
++ { /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, enc28j60_of_match);
++
+ static struct spi_driver enc28j60_driver = {
+ .driver = {
+ .name = DRV_NAME,
++ .of_match_table = enc28j60_of_match,
+ },
+ .probe = enc28j60_probe,
+ .remove = enc28j60_remove,
diff --git a/target/linux/brcm2708/patches-4.4/0075-Add-driver-for-rpi-proto.patch b/target/linux/brcm2708/patches-4.4/0075-Add-driver-for-rpi-proto.patch
new file mode 100644
index 0000000000..390a497cca
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0075-Add-driver-for-rpi-proto.patch
@@ -0,0 +1,210 @@
+From 56a753118a1446feedb1845f37f3e5d3cc4f31a1 Mon Sep 17 00:00:00 2001
+From: Waldemar Brodkorb <wbrodkorb@conet.de>
+Date: Wed, 25 Mar 2015 09:26:17 +0100
+Subject: [PATCH 075/381] Add driver for rpi-proto
+
+Forward port of 3.10.x driver from https://github.com/koalo
+We are using a custom board and would like to use rpi 3.18.x
+kernel. Patch works fine for our embedded system.
+
+URL to the audio chip:
+http://www.mikroe.com/add-on-boards/audio-voice/audio-codec-proto/
+
+Playback tested with devicetree enabled.
+
+Signed-off-by: Waldemar Brodkorb <wbrodkorb@conet.de>
+---
+ sound/soc/bcm/Kconfig | 7 +++
+ sound/soc/bcm/Makefile | 2 +
+ sound/soc/bcm/rpi-proto.c | 153 ++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 162 insertions(+)
+ create mode 100644 sound/soc/bcm/rpi-proto.c
+
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -43,6 +43,13 @@ config SND_BCM2708_SOC_RPI_DAC
+ help
+ Say Y or M if you want to add support for RPi-DAC.
+
++config SND_BCM2708_SOC_RPI_PROTO
++ tristate "Support for Rpi-PROTO"
++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
++ select SND_SOC_WM8731
++ help
++ Say Y or M if you want to add support for Audio Codec Board PROTO (WM8731).
++
+ config SND_BCM2708_SOC_IQAUDIO_DAC
+ tristate "Support for IQaudIO-DAC"
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+--- a/sound/soc/bcm/Makefile
++++ b/sound/soc/bcm/Makefile
+@@ -9,6 +9,7 @@ snd-soc-hifiberry-dacplus-objs := hifibe
+ snd-soc-hifiberry-digi-objs := hifiberry_digi.o
+ snd-soc-hifiberry-amp-objs := hifiberry_amp.o
+ snd-soc-rpi-dac-objs := rpi-dac.o
++snd-soc-rpi-proto-objs := rpi-proto.o
+ snd-soc-iqaudio-dac-objs := iqaudio-dac.o
+
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o
+@@ -16,4 +17,5 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_D
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o
+ obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o
++obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
+ obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
+--- /dev/null
++++ b/sound/soc/bcm/rpi-proto.c
+@@ -0,0 +1,153 @@
++/*
++ * ASoC driver for PROTO AudioCODEC (with a WM8731)
++ * connected to a Raspberry Pi
++ *
++ * Author: Florian Meier, <koalo@koalo.de>
++ * Copyright 2013
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/soc.h>
++#include <sound/jack.h>
++
++#include "../codecs/wm8731.h"
++
++static const unsigned int wm8731_rates_12288000[] = {
++ 8000, 32000, 48000, 96000,
++};
++
++static struct snd_pcm_hw_constraint_list wm8731_constraints_12288000 = {
++ .list = wm8731_rates_12288000,
++ .count = ARRAY_SIZE(wm8731_rates_12288000),
++};
++
++static int snd_rpi_proto_startup(struct snd_pcm_substream *substream)
++{
++ /* Setup constraints, because there is a 12.288 MHz XTAL on the board */
++ snd_pcm_hw_constraint_list(substream->runtime, 0,
++ SNDRV_PCM_HW_PARAM_RATE,
++ &wm8731_constraints_12288000);
++ return 0;
++}
++
++static int snd_rpi_proto_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_codec *codec = rtd->codec;
++ struct snd_soc_dai *codec_dai = rtd->codec_dai;
++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
++ int sysclk = 12288000; /* This is fixed on this board */
++
++ /* Set proto bclk */
++ int ret = snd_soc_dai_set_bclk_ratio(cpu_dai,32*2);
++ if (ret < 0){
++ dev_err(codec->dev,
++ "Failed to set BCLK ratio %d\n", ret);
++ return ret;
++ }
++
++ /* Set proto sysclk */
++ ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
++ sysclk, SND_SOC_CLOCK_IN);
++ if (ret < 0) {
++ dev_err(codec->dev,
++ "Failed to set WM8731 SYSCLK: %d\n", ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++/* machine stream operations */
++static struct snd_soc_ops snd_rpi_proto_ops = {
++ .startup = snd_rpi_proto_startup,
++ .hw_params = snd_rpi_proto_hw_params,
++};
++
++static struct snd_soc_dai_link snd_rpi_proto_dai[] = {
++{
++ .name = "WM8731",
++ .stream_name = "WM8731 HiFi",
++ .cpu_dai_name = "bcm2708-i2s.0",
++ .codec_dai_name = "wm8731-hifi",
++ .platform_name = "bcm2708-i2s.0",
++ .codec_name = "wm8731.1-001a",
++ .dai_fmt = SND_SOC_DAIFMT_I2S
++ | SND_SOC_DAIFMT_NB_NF
++ | SND_SOC_DAIFMT_CBM_CFM,
++ .ops = &snd_rpi_proto_ops,
++},
++};
++
++/* audio machine driver */
++static struct snd_soc_card snd_rpi_proto = {
++ .name = "snd_rpi_proto",
++ .dai_link = snd_rpi_proto_dai,
++ .num_links = ARRAY_SIZE(snd_rpi_proto_dai),
++};
++
++static int snd_rpi_proto_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++
++ snd_rpi_proto.dev = &pdev->dev;
++
++ if (pdev->dev.of_node) {
++ struct device_node *i2s_node;
++ struct snd_soc_dai_link *dai = &snd_rpi_proto_dai[0];
++ i2s_node = of_parse_phandle(pdev->dev.of_node,
++ "i2s-controller", 0);
++
++ if (i2s_node) {
++ dai->cpu_dai_name = NULL;
++ dai->cpu_of_node = i2s_node;
++ dai->platform_name = NULL;
++ dai->platform_of_node = i2s_node;
++ }
++ }
++
++ ret = snd_soc_register_card(&snd_rpi_proto);
++ if (ret) {
++ dev_err(&pdev->dev,
++ "snd_soc_register_card() failed: %d\n", ret);
++ }
++
++ return ret;
++}
++
++
++static int snd_rpi_proto_remove(struct platform_device *pdev)
++{
++ return snd_soc_unregister_card(&snd_rpi_proto);
++}
++
++static const struct of_device_id snd_rpi_proto_of_match[] = {
++ { .compatible = "rpi,rpi-proto", },
++ {},
++};
++MODULE_DEVICE_TABLE(of, snd_rpi_proto_of_match);
++
++static struct platform_driver snd_rpi_proto_driver = {
++ .driver = {
++ .name = "snd-rpi-proto",
++ .owner = THIS_MODULE,
++ .of_match_table = snd_rpi_proto_of_match,
++ },
++ .probe = snd_rpi_proto_probe,
++ .remove = snd_rpi_proto_remove,
++};
++
++module_platform_driver(snd_rpi_proto_driver);
++
++MODULE_AUTHOR("Florian Meier");
++MODULE_DESCRIPTION("ASoC Driver for Raspberry Pi connected to PROTO board (WM8731)");
++MODULE_LICENSE("GPL");
diff --git a/target/linux/brcm2708/patches-4.4/0075-enc28j60-Add-device-tree-compatible-string-and-an-ov.patch b/target/linux/brcm2708/patches-4.4/0075-enc28j60-Add-device-tree-compatible-string-and-an-ov.patch
deleted file mode 100644
index 10ef683cbb..0000000000
--- a/target/linux/brcm2708/patches-4.4/0075-enc28j60-Add-device-tree-compatible-string-and-an-ov.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-From 12ad9b7c670220b1b8b80ebf507651d106cb28c0 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Fri, 27 Feb 2015 15:10:24 +0000
-Subject: [PATCH 075/170] enc28j60: Add device tree compatible string and an
- overlay
-
----
- drivers/net/ethernet/microchip/enc28j60.c | 7 +++++++
- 1 file changed, 7 insertions(+)
-
---- a/drivers/net/ethernet/microchip/enc28j60.c
-+++ b/drivers/net/ethernet/microchip/enc28j60.c
-@@ -1630,9 +1630,16 @@ static int enc28j60_remove(struct spi_de
- return 0;
- }
-
-+static const struct of_device_id enc28j60_of_match[] = {
-+ { .compatible = "microchip,enc28j60", },
-+ { /* sentinel */ }
-+};
-+MODULE_DEVICE_TABLE(of, enc28j60_of_match);
-+
- static struct spi_driver enc28j60_driver = {
- .driver = {
- .name = DRV_NAME,
-+ .of_match_table = enc28j60_of_match,
- },
- .probe = enc28j60_probe,
- .remove = enc28j60_remove,
diff --git a/target/linux/brcm2708/patches-4.4/0076-Add-driver-for-rpi-proto.patch b/target/linux/brcm2708/patches-4.4/0076-Add-driver-for-rpi-proto.patch
deleted file mode 100644
index deef6b6ba7..0000000000
--- a/target/linux/brcm2708/patches-4.4/0076-Add-driver-for-rpi-proto.patch
+++ /dev/null
@@ -1,210 +0,0 @@
-From 660d2fba0483aafc4a1ce678016620c0871bb759 Mon Sep 17 00:00:00 2001
-From: Waldemar Brodkorb <wbrodkorb@conet.de>
-Date: Wed, 25 Mar 2015 09:26:17 +0100
-Subject: [PATCH 076/170] Add driver for rpi-proto
-
-Forward port of 3.10.x driver from https://github.com/koalo
-We are using a custom board and would like to use rpi 3.18.x
-kernel. Patch works fine for our embedded system.
-
-URL to the audio chip:
-http://www.mikroe.com/add-on-boards/audio-voice/audio-codec-proto/
-
-Playback tested with devicetree enabled.
-
-Signed-off-by: Waldemar Brodkorb <wbrodkorb@conet.de>
----
- sound/soc/bcm/Kconfig | 7 +++
- sound/soc/bcm/Makefile | 2 +
- sound/soc/bcm/rpi-proto.c | 153 ++++++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 162 insertions(+)
- create mode 100644 sound/soc/bcm/rpi-proto.c
-
---- a/sound/soc/bcm/Kconfig
-+++ b/sound/soc/bcm/Kconfig
-@@ -43,6 +43,13 @@ config SND_BCM2708_SOC_RPI_DAC
- help
- Say Y or M if you want to add support for RPi-DAC.
-
-+config SND_BCM2708_SOC_RPI_PROTO
-+ tristate "Support for Rpi-PROTO"
-+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
-+ select SND_SOC_WM8731
-+ help
-+ Say Y or M if you want to add support for Audio Codec Board PROTO (WM8731).
-+
- config SND_BCM2708_SOC_IQAUDIO_DAC
- tristate "Support for IQaudIO-DAC"
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
---- a/sound/soc/bcm/Makefile
-+++ b/sound/soc/bcm/Makefile
-@@ -9,6 +9,7 @@ snd-soc-hifiberry-dacplus-objs := hifibe
- snd-soc-hifiberry-digi-objs := hifiberry_digi.o
- snd-soc-hifiberry-amp-objs := hifiberry_amp.o
- snd-soc-rpi-dac-objs := rpi-dac.o
-+snd-soc-rpi-proto-objs := rpi-proto.o
- snd-soc-iqaudio-dac-objs := iqaudio-dac.o
-
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o
-@@ -16,4 +17,5 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_D
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o
- obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o
-+obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
- obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
---- /dev/null
-+++ b/sound/soc/bcm/rpi-proto.c
-@@ -0,0 +1,153 @@
-+/*
-+ * ASoC driver for PROTO AudioCODEC (with a WM8731)
-+ * connected to a Raspberry Pi
-+ *
-+ * Author: Florian Meier, <koalo@koalo.de>
-+ * Copyright 2013
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+
-+#include <sound/core.h>
-+#include <sound/pcm.h>
-+#include <sound/soc.h>
-+#include <sound/jack.h>
-+
-+#include "../codecs/wm8731.h"
-+
-+static const unsigned int wm8731_rates_12288000[] = {
-+ 8000, 32000, 48000, 96000,
-+};
-+
-+static struct snd_pcm_hw_constraint_list wm8731_constraints_12288000 = {
-+ .list = wm8731_rates_12288000,
-+ .count = ARRAY_SIZE(wm8731_rates_12288000),
-+};
-+
-+static int snd_rpi_proto_startup(struct snd_pcm_substream *substream)
-+{
-+ /* Setup constraints, because there is a 12.288 MHz XTAL on the board */
-+ snd_pcm_hw_constraint_list(substream->runtime, 0,
-+ SNDRV_PCM_HW_PARAM_RATE,
-+ &wm8731_constraints_12288000);
-+ return 0;
-+}
-+
-+static int snd_rpi_proto_hw_params(struct snd_pcm_substream *substream,
-+ struct snd_pcm_hw_params *params)
-+{
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ struct snd_soc_codec *codec = rtd->codec;
-+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
-+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-+ int sysclk = 12288000; /* This is fixed on this board */
-+
-+ /* Set proto bclk */
-+ int ret = snd_soc_dai_set_bclk_ratio(cpu_dai,32*2);
-+ if (ret < 0){
-+ dev_err(codec->dev,
-+ "Failed to set BCLK ratio %d\n", ret);
-+ return ret;
-+ }
-+
-+ /* Set proto sysclk */
-+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
-+ sysclk, SND_SOC_CLOCK_IN);
-+ if (ret < 0) {
-+ dev_err(codec->dev,
-+ "Failed to set WM8731 SYSCLK: %d\n", ret);
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+/* machine stream operations */
-+static struct snd_soc_ops snd_rpi_proto_ops = {
-+ .startup = snd_rpi_proto_startup,
-+ .hw_params = snd_rpi_proto_hw_params,
-+};
-+
-+static struct snd_soc_dai_link snd_rpi_proto_dai[] = {
-+{
-+ .name = "WM8731",
-+ .stream_name = "WM8731 HiFi",
-+ .cpu_dai_name = "bcm2708-i2s.0",
-+ .codec_dai_name = "wm8731-hifi",
-+ .platform_name = "bcm2708-i2s.0",
-+ .codec_name = "wm8731.1-001a",
-+ .dai_fmt = SND_SOC_DAIFMT_I2S
-+ | SND_SOC_DAIFMT_NB_NF
-+ | SND_SOC_DAIFMT_CBM_CFM,
-+ .ops = &snd_rpi_proto_ops,
-+},
-+};
-+
-+/* audio machine driver */
-+static struct snd_soc_card snd_rpi_proto = {
-+ .name = "snd_rpi_proto",
-+ .dai_link = snd_rpi_proto_dai,
-+ .num_links = ARRAY_SIZE(snd_rpi_proto_dai),
-+};
-+
-+static int snd_rpi_proto_probe(struct platform_device *pdev)
-+{
-+ int ret = 0;
-+
-+ snd_rpi_proto.dev = &pdev->dev;
-+
-+ if (pdev->dev.of_node) {
-+ struct device_node *i2s_node;
-+ struct snd_soc_dai_link *dai = &snd_rpi_proto_dai[0];
-+ i2s_node = of_parse_phandle(pdev->dev.of_node,
-+ "i2s-controller", 0);
-+
-+ if (i2s_node) {
-+ dai->cpu_dai_name = NULL;
-+ dai->cpu_of_node = i2s_node;
-+ dai->platform_name = NULL;
-+ dai->platform_of_node = i2s_node;
-+ }
-+ }
-+
-+ ret = snd_soc_register_card(&snd_rpi_proto);
-+ if (ret) {
-+ dev_err(&pdev->dev,
-+ "snd_soc_register_card() failed: %d\n", ret);
-+ }
-+
-+ return ret;
-+}
-+
-+
-+static int snd_rpi_proto_remove(struct platform_device *pdev)
-+{
-+ return snd_soc_unregister_card(&snd_rpi_proto);
-+}
-+
-+static const struct of_device_id snd_rpi_proto_of_match[] = {
-+ { .compatible = "rpi,rpi-proto", },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(of, snd_rpi_proto_of_match);
-+
-+static struct platform_driver snd_rpi_proto_driver = {
-+ .driver = {
-+ .name = "snd-rpi-proto",
-+ .owner = THIS_MODULE,
-+ .of_match_table = snd_rpi_proto_of_match,
-+ },
-+ .probe = snd_rpi_proto_probe,
-+ .remove = snd_rpi_proto_remove,
-+};
-+
-+module_platform_driver(snd_rpi_proto_driver);
-+
-+MODULE_AUTHOR("Florian Meier");
-+MODULE_DESCRIPTION("ASoC Driver for Raspberry Pi connected to PROTO board (WM8731)");
-+MODULE_LICENSE("GPL");
diff --git a/target/linux/brcm2708/patches-4.4/0076-config-Add-default-configs.patch b/target/linux/brcm2708/patches-4.4/0076-config-Add-default-configs.patch
new file mode 100644
index 0000000000..f14a40ecc4
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0076-config-Add-default-configs.patch
@@ -0,0 +1,2537 @@
+From c8647aeede51642c863c13cb741866a8ef13c2a7 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Mon, 13 Apr 2015 17:16:29 +0100
+Subject: [PATCH 076/381] config: Add default configs
+
+---
+ arch/arm/configs/bcm2709_defconfig | 1254 +++++++++++++++++++++++++++++++++++
+ arch/arm/configs/bcmrpi_defconfig | 1265 ++++++++++++++++++++++++++++++++++++
+ 2 files changed, 2519 insertions(+)
+ create mode 100644 arch/arm/configs/bcm2709_defconfig
+ create mode 100644 arch/arm/configs/bcmrpi_defconfig
+
+--- /dev/null
++++ b/arch/arm/configs/bcm2709_defconfig
+@@ -0,0 +1,1254 @@
++# CONFIG_ARM_PATCH_PHYS_VIRT is not set
++CONFIG_PHYS_OFFSET=0
++CONFIG_LOCALVERSION="-v7"
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_SYSVIPC=y
++CONFIG_POSIX_MQUEUE=y
++CONFIG_FHANDLE=y
++CONFIG_NO_HZ=y
++CONFIG_HIGH_RES_TIMERS=y
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_BSD_PROCESS_ACCT_V3=y
++CONFIG_TASKSTATS=y
++CONFIG_TASK_DELAY_ACCT=y
++CONFIG_TASK_XACCT=y
++CONFIG_TASK_IO_ACCOUNTING=y
++CONFIG_IKCONFIG=m
++CONFIG_IKCONFIG_PROC=y
++CONFIG_CGROUP_FREEZER=y
++CONFIG_CGROUP_DEVICE=y
++CONFIG_CPUSETS=y
++CONFIG_CGROUP_CPUACCT=y
++CONFIG_MEMCG=y
++CONFIG_BLK_CGROUP=y
++CONFIG_NAMESPACES=y
++CONFIG_SCHED_AUTOGROUP=y
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_EMBEDDED=y
++# CONFIG_COMPAT_BRK is not set
++CONFIG_PROFILING=y
++CONFIG_OPROFILE=m
++CONFIG_KPROBES=y
++CONFIG_JUMP_LABEL=y
++CONFIG_MODULES=y
++CONFIG_MODULE_UNLOAD=y
++CONFIG_MODVERSIONS=y
++CONFIG_MODULE_SRCVERSION_ALL=y
++CONFIG_BLK_DEV_THROTTLING=y
++CONFIG_PARTITION_ADVANCED=y
++CONFIG_MAC_PARTITION=y
++CONFIG_CFQ_GROUP_IOSCHED=y
++CONFIG_ARCH_BCM2709=y
++# CONFIG_CACHE_L2X0 is not set
++CONFIG_SMP=y
++CONFIG_HAVE_ARM_ARCH_TIMER=y
++CONFIG_VMSPLIT_2G=y
++CONFIG_PREEMPT_VOLUNTARY=y
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++# CONFIG_CPU_SW_DOMAIN_PAN is not set
++CONFIG_CLEANCACHE=y
++CONFIG_FRONTSWAP=y
++CONFIG_CMA=y
++CONFIG_ZSMALLOC=m
++CONFIG_PGTABLE_MAPPING=y
++CONFIG_UACCESS_WITH_MEMCPY=y
++CONFIG_SECCOMP=y
++# CONFIG_ATAGS is not set
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait"
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_STAT=m
++CONFIG_CPU_FREQ_STAT_DETAILS=y
++CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE=y
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
++CONFIG_CPU_FREQ_GOV_ONDEMAND=y
++CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
++CONFIG_VFP=y
++CONFIG_NEON=y
++CONFIG_KERNEL_MODE_NEON=y
++CONFIG_BINFMT_MISC=m
++# CONFIG_SUSPEND is not set
++CONFIG_NET=y
++CONFIG_PACKET=y
++CONFIG_UNIX=y
++CONFIG_XFRM_USER=y
++CONFIG_NET_KEY=m
++CONFIG_INET=y
++CONFIG_IP_MULTICAST=y
++CONFIG_IP_ADVANCED_ROUTER=y
++CONFIG_IP_MULTIPLE_TABLES=y
++CONFIG_IP_ROUTE_MULTIPATH=y
++CONFIG_IP_ROUTE_VERBOSE=y
++CONFIG_IP_PNP=y
++CONFIG_IP_PNP_DHCP=y
++CONFIG_IP_PNP_RARP=y
++CONFIG_NET_IPIP=m
++CONFIG_NET_IPGRE_DEMUX=m
++CONFIG_NET_IPGRE=m
++CONFIG_IP_MROUTE=y
++CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
++CONFIG_IP_PIMSM_V1=y
++CONFIG_IP_PIMSM_V2=y
++CONFIG_SYN_COOKIES=y
++CONFIG_INET_AH=m
++CONFIG_INET_ESP=m
++CONFIG_INET_IPCOMP=m
++CONFIG_INET_XFRM_MODE_TRANSPORT=m
++CONFIG_INET_XFRM_MODE_TUNNEL=m
++CONFIG_INET_XFRM_MODE_BEET=m
++CONFIG_INET_LRO=m
++CONFIG_INET_DIAG=m
++CONFIG_INET6_AH=m
++CONFIG_INET6_ESP=m
++CONFIG_INET6_IPCOMP=m
++CONFIG_IPV6_TUNNEL=m
++CONFIG_IPV6_MULTIPLE_TABLES=y
++CONFIG_IPV6_MROUTE=y
++CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
++CONFIG_IPV6_PIMSM_V2=y
++CONFIG_NETFILTER=y
++CONFIG_NF_CONNTRACK=m
++CONFIG_NF_CONNTRACK_ZONES=y
++CONFIG_NF_CONNTRACK_EVENTS=y
++CONFIG_NF_CONNTRACK_TIMESTAMP=y
++CONFIG_NF_CT_PROTO_DCCP=m
++CONFIG_NF_CT_PROTO_UDPLITE=m
++CONFIG_NF_CONNTRACK_AMANDA=m
++CONFIG_NF_CONNTRACK_FTP=m
++CONFIG_NF_CONNTRACK_H323=m
++CONFIG_NF_CONNTRACK_IRC=m
++CONFIG_NF_CONNTRACK_NETBIOS_NS=m
++CONFIG_NF_CONNTRACK_SNMP=m
++CONFIG_NF_CONNTRACK_PPTP=m
++CONFIG_NF_CONNTRACK_SANE=m
++CONFIG_NF_CONNTRACK_SIP=m
++CONFIG_NF_CONNTRACK_TFTP=m
++CONFIG_NF_CT_NETLINK=m
++CONFIG_NETFILTER_XT_SET=m
++CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
++CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
++CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
++CONFIG_NETFILTER_XT_TARGET_DSCP=m
++CONFIG_NETFILTER_XT_TARGET_HMARK=m
++CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
++CONFIG_NETFILTER_XT_TARGET_LED=m
++CONFIG_NETFILTER_XT_TARGET_LOG=m
++CONFIG_NETFILTER_XT_TARGET_MARK=m
++CONFIG_NETFILTER_XT_TARGET_NFLOG=m
++CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
++CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
++CONFIG_NETFILTER_XT_TARGET_TEE=m
++CONFIG_NETFILTER_XT_TARGET_TPROXY=m
++CONFIG_NETFILTER_XT_TARGET_TRACE=m
++CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
++CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
++CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m
++CONFIG_NETFILTER_XT_MATCH_BPF=m
++CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
++CONFIG_NETFILTER_XT_MATCH_COMMENT=m
++CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
++CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m
++CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
++CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
++CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
++CONFIG_NETFILTER_XT_MATCH_CPU=m
++CONFIG_NETFILTER_XT_MATCH_DCCP=m
++CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m
++CONFIG_NETFILTER_XT_MATCH_DSCP=m
++CONFIG_NETFILTER_XT_MATCH_ESP=m
++CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
++CONFIG_NETFILTER_XT_MATCH_HELPER=m
++CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
++CONFIG_NETFILTER_XT_MATCH_IPVS=m
++CONFIG_NETFILTER_XT_MATCH_LENGTH=m
++CONFIG_NETFILTER_XT_MATCH_LIMIT=m
++CONFIG_NETFILTER_XT_MATCH_MAC=m
++CONFIG_NETFILTER_XT_MATCH_MARK=m
++CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
++CONFIG_NETFILTER_XT_MATCH_NFACCT=m
++CONFIG_NETFILTER_XT_MATCH_OSF=m
++CONFIG_NETFILTER_XT_MATCH_OWNER=m
++CONFIG_NETFILTER_XT_MATCH_POLICY=m
++CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
++CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
++CONFIG_NETFILTER_XT_MATCH_QUOTA=m
++CONFIG_NETFILTER_XT_MATCH_RATEEST=m
++CONFIG_NETFILTER_XT_MATCH_REALM=m
++CONFIG_NETFILTER_XT_MATCH_RECENT=m
++CONFIG_NETFILTER_XT_MATCH_SOCKET=m
++CONFIG_NETFILTER_XT_MATCH_STATE=m
++CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
++CONFIG_NETFILTER_XT_MATCH_STRING=m
++CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
++CONFIG_NETFILTER_XT_MATCH_TIME=m
++CONFIG_NETFILTER_XT_MATCH_U32=m
++CONFIG_IP_SET=m
++CONFIG_IP_SET_BITMAP_IP=m
++CONFIG_IP_SET_BITMAP_IPMAC=m
++CONFIG_IP_SET_BITMAP_PORT=m
++CONFIG_IP_SET_HASH_IP=m
++CONFIG_IP_SET_HASH_IPPORT=m
++CONFIG_IP_SET_HASH_IPPORTIP=m
++CONFIG_IP_SET_HASH_IPPORTNET=m
++CONFIG_IP_SET_HASH_NET=m
++CONFIG_IP_SET_HASH_NETPORT=m
++CONFIG_IP_SET_HASH_NETIFACE=m
++CONFIG_IP_SET_LIST_SET=m
++CONFIG_IP_VS=m
++CONFIG_IP_VS_PROTO_TCP=y
++CONFIG_IP_VS_PROTO_UDP=y
++CONFIG_IP_VS_PROTO_ESP=y
++CONFIG_IP_VS_PROTO_AH=y
++CONFIG_IP_VS_PROTO_SCTP=y
++CONFIG_IP_VS_RR=m
++CONFIG_IP_VS_WRR=m
++CONFIG_IP_VS_LC=m
++CONFIG_IP_VS_WLC=m
++CONFIG_IP_VS_LBLC=m
++CONFIG_IP_VS_LBLCR=m
++CONFIG_IP_VS_DH=m
++CONFIG_IP_VS_SH=m
++CONFIG_IP_VS_SED=m
++CONFIG_IP_VS_NQ=m
++CONFIG_IP_VS_FTP=m
++CONFIG_IP_VS_PE_SIP=m
++CONFIG_NF_CONNTRACK_IPV4=m
++CONFIG_IP_NF_IPTABLES=m
++CONFIG_IP_NF_MATCH_AH=m
++CONFIG_IP_NF_MATCH_ECN=m
++CONFIG_IP_NF_MATCH_TTL=m
++CONFIG_IP_NF_FILTER=m
++CONFIG_IP_NF_TARGET_REJECT=m
++CONFIG_IP_NF_NAT=m
++CONFIG_IP_NF_TARGET_MASQUERADE=m
++CONFIG_IP_NF_TARGET_NETMAP=m
++CONFIG_IP_NF_TARGET_REDIRECT=m
++CONFIG_IP_NF_MANGLE=m
++CONFIG_IP_NF_TARGET_CLUSTERIP=m
++CONFIG_IP_NF_TARGET_ECN=m
++CONFIG_IP_NF_TARGET_TTL=m
++CONFIG_IP_NF_RAW=m
++CONFIG_IP_NF_ARPTABLES=m
++CONFIG_IP_NF_ARPFILTER=m
++CONFIG_IP_NF_ARP_MANGLE=m
++CONFIG_NF_CONNTRACK_IPV6=m
++CONFIG_IP6_NF_IPTABLES=m
++CONFIG_IP6_NF_MATCH_AH=m
++CONFIG_IP6_NF_MATCH_EUI64=m
++CONFIG_IP6_NF_MATCH_FRAG=m
++CONFIG_IP6_NF_MATCH_OPTS=m
++CONFIG_IP6_NF_MATCH_HL=m
++CONFIG_IP6_NF_MATCH_IPV6HEADER=m
++CONFIG_IP6_NF_MATCH_MH=m
++CONFIG_IP6_NF_MATCH_RT=m
++CONFIG_IP6_NF_TARGET_HL=m
++CONFIG_IP6_NF_FILTER=m
++CONFIG_IP6_NF_TARGET_REJECT=m
++CONFIG_IP6_NF_MANGLE=m
++CONFIG_IP6_NF_RAW=m
++CONFIG_IP6_NF_NAT=m
++CONFIG_IP6_NF_TARGET_MASQUERADE=m
++CONFIG_IP6_NF_TARGET_NPT=m
++CONFIG_BRIDGE_NF_EBTABLES=m
++CONFIG_BRIDGE_EBT_BROUTE=m
++CONFIG_BRIDGE_EBT_T_FILTER=m
++CONFIG_BRIDGE_EBT_T_NAT=m
++CONFIG_BRIDGE_EBT_802_3=m
++CONFIG_BRIDGE_EBT_AMONG=m
++CONFIG_BRIDGE_EBT_ARP=m
++CONFIG_BRIDGE_EBT_IP=m
++CONFIG_BRIDGE_EBT_IP6=m
++CONFIG_BRIDGE_EBT_LIMIT=m
++CONFIG_BRIDGE_EBT_MARK=m
++CONFIG_BRIDGE_EBT_PKTTYPE=m
++CONFIG_BRIDGE_EBT_STP=m
++CONFIG_BRIDGE_EBT_VLAN=m
++CONFIG_BRIDGE_EBT_ARPREPLY=m
++CONFIG_BRIDGE_EBT_DNAT=m
++CONFIG_BRIDGE_EBT_MARK_T=m
++CONFIG_BRIDGE_EBT_REDIRECT=m
++CONFIG_BRIDGE_EBT_SNAT=m
++CONFIG_BRIDGE_EBT_LOG=m
++CONFIG_BRIDGE_EBT_NFLOG=m
++CONFIG_SCTP_COOKIE_HMAC_SHA1=y
++CONFIG_ATM=m
++CONFIG_L2TP=m
++CONFIG_L2TP_V3=y
++CONFIG_L2TP_IP=m
++CONFIG_L2TP_ETH=m
++CONFIG_BRIDGE=m
++CONFIG_VLAN_8021Q=m
++CONFIG_VLAN_8021Q_GVRP=y
++CONFIG_ATALK=m
++CONFIG_6LOWPAN=m
++CONFIG_IEEE802154=m
++CONFIG_IEEE802154_6LOWPAN=m
++CONFIG_MAC802154=m
++CONFIG_NET_SCHED=y
++CONFIG_NET_SCH_CBQ=m
++CONFIG_NET_SCH_HTB=m
++CONFIG_NET_SCH_HFSC=m
++CONFIG_NET_SCH_PRIO=m
++CONFIG_NET_SCH_MULTIQ=m
++CONFIG_NET_SCH_RED=m
++CONFIG_NET_SCH_SFB=m
++CONFIG_NET_SCH_SFQ=m
++CONFIG_NET_SCH_TEQL=m
++CONFIG_NET_SCH_TBF=m
++CONFIG_NET_SCH_GRED=m
++CONFIG_NET_SCH_DSMARK=m
++CONFIG_NET_SCH_NETEM=m
++CONFIG_NET_SCH_DRR=m
++CONFIG_NET_SCH_MQPRIO=m
++CONFIG_NET_SCH_CHOKE=m
++CONFIG_NET_SCH_QFQ=m
++CONFIG_NET_SCH_CODEL=m
++CONFIG_NET_SCH_FQ_CODEL=m
++CONFIG_NET_SCH_INGRESS=m
++CONFIG_NET_SCH_PLUG=m
++CONFIG_NET_CLS_BASIC=m
++CONFIG_NET_CLS_TCINDEX=m
++CONFIG_NET_CLS_ROUTE4=m
++CONFIG_NET_CLS_FW=m
++CONFIG_NET_CLS_U32=m
++CONFIG_CLS_U32_MARK=y
++CONFIG_NET_CLS_RSVP=m
++CONFIG_NET_CLS_RSVP6=m
++CONFIG_NET_CLS_FLOW=m
++CONFIG_NET_CLS_CGROUP=m
++CONFIG_NET_EMATCH=y
++CONFIG_NET_EMATCH_CMP=m
++CONFIG_NET_EMATCH_NBYTE=m
++CONFIG_NET_EMATCH_U32=m
++CONFIG_NET_EMATCH_META=m
++CONFIG_NET_EMATCH_TEXT=m
++CONFIG_NET_EMATCH_IPSET=m
++CONFIG_NET_CLS_ACT=y
++CONFIG_NET_ACT_POLICE=m
++CONFIG_NET_ACT_GACT=m
++CONFIG_GACT_PROB=y
++CONFIG_NET_ACT_MIRRED=m
++CONFIG_NET_ACT_IPT=m
++CONFIG_NET_ACT_NAT=m
++CONFIG_NET_ACT_PEDIT=m
++CONFIG_NET_ACT_SIMP=m
++CONFIG_NET_ACT_SKBEDIT=m
++CONFIG_NET_ACT_CSUM=m
++CONFIG_BATMAN_ADV=m
++CONFIG_OPENVSWITCH=m
++CONFIG_NET_PKTGEN=m
++CONFIG_HAMRADIO=y
++CONFIG_AX25=m
++CONFIG_NETROM=m
++CONFIG_ROSE=m
++CONFIG_MKISS=m
++CONFIG_6PACK=m
++CONFIG_BPQETHER=m
++CONFIG_BAYCOM_SER_FDX=m
++CONFIG_BAYCOM_SER_HDX=m
++CONFIG_YAM=m
++CONFIG_CAN=m
++CONFIG_CAN_VCAN=m
++CONFIG_CAN_MCP251X=m
++CONFIG_IRDA=m
++CONFIG_IRLAN=m
++CONFIG_IRNET=m
++CONFIG_IRCOMM=m
++CONFIG_IRDA_ULTRA=y
++CONFIG_IRDA_CACHE_LAST_LSAP=y
++CONFIG_IRDA_FAST_RR=y
++CONFIG_IRTTY_SIR=m
++CONFIG_KINGSUN_DONGLE=m
++CONFIG_KSDAZZLE_DONGLE=m
++CONFIG_KS959_DONGLE=m
++CONFIG_USB_IRDA=m
++CONFIG_SIGMATEL_FIR=m
++CONFIG_MCS_FIR=m
++CONFIG_BT=m
++CONFIG_BT_RFCOMM=m
++CONFIG_BT_RFCOMM_TTY=y
++CONFIG_BT_BNEP=m
++CONFIG_BT_BNEP_MC_FILTER=y
++CONFIG_BT_BNEP_PROTO_FILTER=y
++CONFIG_BT_HIDP=m
++CONFIG_BT_6LOWPAN=m
++CONFIG_BT_HCIBTUSB=m
++CONFIG_BT_HCIBCM203X=m
++CONFIG_BT_HCIBPA10X=m
++CONFIG_BT_HCIBFUSB=m
++CONFIG_BT_HCIVHCI=m
++CONFIG_BT_MRVL=m
++CONFIG_BT_MRVL_SDIO=m
++CONFIG_BT_ATH3K=m
++CONFIG_BT_WILINK=m
++CONFIG_MAC80211=m
++CONFIG_MAC80211_MESH=y
++CONFIG_WIMAX=m
++CONFIG_RFKILL=m
++CONFIG_RFKILL_INPUT=y
++CONFIG_NET_9P=m
++CONFIG_NFC=m
++CONFIG_NFC_PN533=m
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_DMA_CMA=y
++CONFIG_CMA_SIZE_MBYTES=5
++CONFIG_MTD=m
++CONFIG_MTD_BLOCK=m
++CONFIG_MTD_NAND=m
++CONFIG_MTD_UBI=m
++CONFIG_ZRAM=m
++CONFIG_ZRAM_LZ4_COMPRESS=y
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_CRYPTOLOOP=m
++CONFIG_BLK_DEV_DRBD=m
++CONFIG_BLK_DEV_NBD=m
++CONFIG_BLK_DEV_RAM=y
++CONFIG_CDROM_PKTCDVD=m
++CONFIG_ATA_OVER_ETH=m
++CONFIG_EEPROM_AT24=m
++CONFIG_TI_ST=m
++CONFIG_SCSI=y
++# CONFIG_SCSI_PROC_FS is not set
++CONFIG_BLK_DEV_SD=y
++CONFIG_CHR_DEV_ST=m
++CONFIG_CHR_DEV_OSST=m
++CONFIG_BLK_DEV_SR=m
++CONFIG_CHR_DEV_SG=m
++CONFIG_SCSI_ISCSI_ATTRS=y
++CONFIG_ISCSI_TCP=m
++CONFIG_ISCSI_BOOT_SYSFS=m
++CONFIG_MD=y
++CONFIG_MD_LINEAR=m
++CONFIG_MD_RAID0=m
++CONFIG_BLK_DEV_DM=m
++CONFIG_DM_CRYPT=m
++CONFIG_DM_SNAPSHOT=m
++CONFIG_DM_THIN_PROVISIONING=m
++CONFIG_DM_MIRROR=m
++CONFIG_DM_LOG_USERSPACE=m
++CONFIG_DM_RAID=m
++CONFIG_DM_ZERO=m
++CONFIG_DM_DELAY=m
++CONFIG_NETDEVICES=y
++CONFIG_BONDING=m
++CONFIG_DUMMY=m
++CONFIG_IFB=m
++CONFIG_MACVLAN=m
++CONFIG_NETCONSOLE=m
++CONFIG_TUN=m
++CONFIG_VETH=m
++CONFIG_ENC28J60=m
++CONFIG_MDIO_BITBANG=m
++CONFIG_PPP=m
++CONFIG_PPP_BSDCOMP=m
++CONFIG_PPP_DEFLATE=m
++CONFIG_PPP_FILTER=y
++CONFIG_PPP_MPPE=m
++CONFIG_PPP_MULTILINK=y
++CONFIG_PPPOATM=m
++CONFIG_PPPOE=m
++CONFIG_PPPOL2TP=m
++CONFIG_PPP_ASYNC=m
++CONFIG_PPP_SYNC_TTY=m
++CONFIG_SLIP=m
++CONFIG_SLIP_COMPRESSED=y
++CONFIG_SLIP_SMART=y
++CONFIG_USB_CATC=m
++CONFIG_USB_KAWETH=m
++CONFIG_USB_PEGASUS=m
++CONFIG_USB_RTL8150=m
++CONFIG_USB_RTL8152=m
++CONFIG_USB_USBNET=y
++CONFIG_USB_NET_AX8817X=m
++CONFIG_USB_NET_AX88179_178A=m
++CONFIG_USB_NET_CDCETHER=m
++CONFIG_USB_NET_CDC_EEM=m
++CONFIG_USB_NET_CDC_NCM=m
++CONFIG_USB_NET_HUAWEI_CDC_NCM=m
++CONFIG_USB_NET_CDC_MBIM=m
++CONFIG_USB_NET_DM9601=m
++CONFIG_USB_NET_SR9700=m
++CONFIG_USB_NET_SR9800=m
++CONFIG_USB_NET_SMSC75XX=m
++CONFIG_USB_NET_SMSC95XX=y
++CONFIG_USB_NET_GL620A=m
++CONFIG_USB_NET_NET1080=m
++CONFIG_USB_NET_PLUSB=m
++CONFIG_USB_NET_MCS7830=m
++CONFIG_USB_NET_CDC_SUBSET=m
++CONFIG_USB_ALI_M5632=y
++CONFIG_USB_AN2720=y
++CONFIG_USB_EPSON2888=y
++CONFIG_USB_KC2190=y
++CONFIG_USB_NET_ZAURUS=m
++CONFIG_USB_NET_CX82310_ETH=m
++CONFIG_USB_NET_KALMIA=m
++CONFIG_USB_NET_QMI_WWAN=m
++CONFIG_USB_HSO=m
++CONFIG_USB_NET_INT51X1=m
++CONFIG_USB_IPHETH=m
++CONFIG_USB_SIERRA_NET=m
++CONFIG_USB_VL600=m
++CONFIG_LIBERTAS_THINFIRM=m
++CONFIG_LIBERTAS_THINFIRM_USB=m
++CONFIG_AT76C50X_USB=m
++CONFIG_USB_ZD1201=m
++CONFIG_USB_NET_RNDIS_WLAN=m
++CONFIG_RTL8187=m
++CONFIG_MAC80211_HWSIM=m
++CONFIG_ATH_CARDS=m
++CONFIG_ATH9K=m
++CONFIG_ATH9K_HTC=m
++CONFIG_CARL9170=m
++CONFIG_ATH6KL=m
++CONFIG_ATH6KL_USB=m
++CONFIG_AR5523=m
++CONFIG_B43=m
++# CONFIG_B43_PHY_N is not set
++CONFIG_B43LEGACY=m
++CONFIG_BRCMFMAC=m
++CONFIG_BRCMFMAC_USB=y
++CONFIG_HOSTAP=m
++CONFIG_LIBERTAS=m
++CONFIG_LIBERTAS_USB=m
++CONFIG_LIBERTAS_SDIO=m
++CONFIG_P54_COMMON=m
++CONFIG_P54_USB=m
++CONFIG_RT2X00=m
++CONFIG_RT2500USB=m
++CONFIG_RT73USB=m
++CONFIG_RT2800USB=m
++CONFIG_RT2800USB_RT3573=y
++CONFIG_RT2800USB_RT53XX=y
++CONFIG_RT2800USB_RT55XX=y
++CONFIG_RT2800USB_UNKNOWN=y
++CONFIG_WL_MEDIATEK=y
++CONFIG_MT7601U=m
++CONFIG_RTL8192CU=m
++CONFIG_ZD1211RW=m
++CONFIG_MWIFIEX=m
++CONFIG_MWIFIEX_SDIO=m
++CONFIG_WIMAX_I2400M_USB=m
++CONFIG_IEEE802154_AT86RF230=m
++CONFIG_IEEE802154_MRF24J40=m
++CONFIG_IEEE802154_CC2520=m
++CONFIG_INPUT_POLLDEV=m
++# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
++CONFIG_INPUT_JOYDEV=m
++CONFIG_INPUT_EVDEV=m
++# CONFIG_KEYBOARD_ATKBD is not set
++CONFIG_KEYBOARD_GPIO=m
++# CONFIG_INPUT_MOUSE is not set
++CONFIG_INPUT_JOYSTICK=y
++CONFIG_JOYSTICK_IFORCE=m
++CONFIG_JOYSTICK_IFORCE_USB=y
++CONFIG_JOYSTICK_XPAD=m
++CONFIG_JOYSTICK_XPAD_FF=y
++CONFIG_JOYSTICK_RPISENSE=m
++CONFIG_INPUT_TOUCHSCREEN=y
++CONFIG_TOUCHSCREEN_ADS7846=m
++CONFIG_TOUCHSCREEN_EGALAX=m
++CONFIG_TOUCHSCREEN_FT6236=m
++CONFIG_TOUCHSCREEN_RPI_FT5406=m
++CONFIG_TOUCHSCREEN_USB_COMPOSITE=m
++CONFIG_TOUCHSCREEN_STMPE=m
++CONFIG_INPUT_MISC=y
++CONFIG_INPUT_AD714X=m
++CONFIG_INPUT_ATI_REMOTE2=m
++CONFIG_INPUT_KEYSPAN_REMOTE=m
++CONFIG_INPUT_POWERMATE=m
++CONFIG_INPUT_YEALINK=m
++CONFIG_INPUT_CM109=m
++CONFIG_INPUT_UINPUT=m
++CONFIG_INPUT_GPIO_ROTARY_ENCODER=m
++CONFIG_INPUT_ADXL34X=m
++CONFIG_INPUT_CMA3000=m
++CONFIG_SERIO=m
++CONFIG_SERIO_RAW=m
++CONFIG_GAMEPORT=m
++CONFIG_GAMEPORT_NS558=m
++CONFIG_GAMEPORT_L4=m
++CONFIG_BRCM_CHAR_DRIVERS=y
++CONFIG_BCM_VC_CMA=y
++CONFIG_BCM_VCIO=y
++CONFIG_BCM_VC_SM=y
++CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_DEVKMEM is not set
++CONFIG_SERIAL_8250=y
++# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
++CONFIG_SERIAL_8250_CONSOLE=y
++# CONFIG_SERIAL_8250_DMA is not set
++CONFIG_SERIAL_8250_NR_UARTS=1
++CONFIG_SERIAL_8250_RUNTIME_UARTS=0
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++CONFIG_SERIAL_OF_PLATFORM=y
++CONFIG_TTY_PRINTK=y
++CONFIG_HW_RANDOM=y
++CONFIG_HW_RANDOM_BCM2835=y
++CONFIG_RAW_DRIVER=y
++CONFIG_I2C=y
++CONFIG_I2C_CHARDEV=m
++CONFIG_I2C_BCM2708=m
++CONFIG_SPI=y
++CONFIG_SPI_BCM2835=m
++CONFIG_SPI_SPIDEV=y
++CONFIG_PPS=m
++CONFIG_PPS_CLIENT_LDISC=m
++CONFIG_PPS_CLIENT_GPIO=m
++CONFIG_GPIO_SYSFS=y
++CONFIG_GPIO_ARIZONA=m
++CONFIG_GPIO_STMPE=y
++CONFIG_W1=m
++CONFIG_W1_MASTER_DS2490=m
++CONFIG_W1_MASTER_DS2482=m
++CONFIG_W1_MASTER_DS1WM=m
++CONFIG_W1_MASTER_GPIO=m
++CONFIG_W1_SLAVE_THERM=m
++CONFIG_W1_SLAVE_SMEM=m
++CONFIG_W1_SLAVE_DS2408=m
++CONFIG_W1_SLAVE_DS2413=m
++CONFIG_W1_SLAVE_DS2406=m
++CONFIG_W1_SLAVE_DS2423=m
++CONFIG_W1_SLAVE_DS2431=m
++CONFIG_W1_SLAVE_DS2433=m
++CONFIG_W1_SLAVE_DS2760=m
++CONFIG_W1_SLAVE_DS2780=m
++CONFIG_W1_SLAVE_DS2781=m
++CONFIG_W1_SLAVE_DS28E04=m
++CONFIG_W1_SLAVE_BQ27000=m
++CONFIG_BATTERY_DS2760=m
++CONFIG_POWER_RESET=y
++CONFIG_POWER_RESET_GPIO=y
++CONFIG_HWMON=m
++CONFIG_SENSORS_SHT21=m
++CONFIG_SENSORS_SHTC1=m
++CONFIG_THERMAL=y
++CONFIG_THERMAL_BCM2835=y
++CONFIG_WATCHDOG=y
++CONFIG_BCM2835_WDT=m
++CONFIG_UCB1400_CORE=m
++CONFIG_MFD_STMPE=y
++CONFIG_STMPE_SPI=y
++CONFIG_MFD_ARIZONA_I2C=m
++CONFIG_MFD_ARIZONA_SPI=m
++CONFIG_MFD_WM5102=y
++CONFIG_MEDIA_SUPPORT=m
++CONFIG_MEDIA_CAMERA_SUPPORT=y
++CONFIG_MEDIA_ANALOG_TV_SUPPORT=y
++CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y
++CONFIG_MEDIA_RADIO_SUPPORT=y
++CONFIG_MEDIA_RC_SUPPORT=y
++CONFIG_MEDIA_CONTROLLER=y
++CONFIG_LIRC=m
++CONFIG_RC_DEVICES=y
++CONFIG_RC_ATI_REMOTE=m
++CONFIG_IR_IMON=m
++CONFIG_IR_MCEUSB=m
++CONFIG_IR_REDRAT3=m
++CONFIG_IR_STREAMZAP=m
++CONFIG_IR_IGUANA=m
++CONFIG_IR_TTUSBIR=m
++CONFIG_RC_LOOPBACK=m
++CONFIG_IR_GPIO_CIR=m
++CONFIG_MEDIA_USB_SUPPORT=y
++CONFIG_USB_VIDEO_CLASS=m
++CONFIG_USB_M5602=m
++CONFIG_USB_STV06XX=m
++CONFIG_USB_GL860=m
++CONFIG_USB_GSPCA_BENQ=m
++CONFIG_USB_GSPCA_CONEX=m
++CONFIG_USB_GSPCA_CPIA1=m
++CONFIG_USB_GSPCA_DTCS033=m
++CONFIG_USB_GSPCA_ETOMS=m
++CONFIG_USB_GSPCA_FINEPIX=m
++CONFIG_USB_GSPCA_JEILINJ=m
++CONFIG_USB_GSPCA_JL2005BCD=m
++CONFIG_USB_GSPCA_KINECT=m
++CONFIG_USB_GSPCA_KONICA=m
++CONFIG_USB_GSPCA_MARS=m
++CONFIG_USB_GSPCA_MR97310A=m
++CONFIG_USB_GSPCA_NW80X=m
++CONFIG_USB_GSPCA_OV519=m
++CONFIG_USB_GSPCA_OV534=m
++CONFIG_USB_GSPCA_OV534_9=m
++CONFIG_USB_GSPCA_PAC207=m
++CONFIG_USB_GSPCA_PAC7302=m
++CONFIG_USB_GSPCA_PAC7311=m
++CONFIG_USB_GSPCA_SE401=m
++CONFIG_USB_GSPCA_SN9C2028=m
++CONFIG_USB_GSPCA_SN9C20X=m
++CONFIG_USB_GSPCA_SONIXB=m
++CONFIG_USB_GSPCA_SONIXJ=m
++CONFIG_USB_GSPCA_SPCA500=m
++CONFIG_USB_GSPCA_SPCA501=m
++CONFIG_USB_GSPCA_SPCA505=m
++CONFIG_USB_GSPCA_SPCA506=m
++CONFIG_USB_GSPCA_SPCA508=m
++CONFIG_USB_GSPCA_SPCA561=m
++CONFIG_USB_GSPCA_SPCA1528=m
++CONFIG_USB_GSPCA_SQ905=m
++CONFIG_USB_GSPCA_SQ905C=m
++CONFIG_USB_GSPCA_SQ930X=m
++CONFIG_USB_GSPCA_STK014=m
++CONFIG_USB_GSPCA_STK1135=m
++CONFIG_USB_GSPCA_STV0680=m
++CONFIG_USB_GSPCA_SUNPLUS=m
++CONFIG_USB_GSPCA_T613=m
++CONFIG_USB_GSPCA_TOPRO=m
++CONFIG_USB_GSPCA_TV8532=m
++CONFIG_USB_GSPCA_VC032X=m
++CONFIG_USB_GSPCA_VICAM=m
++CONFIG_USB_GSPCA_XIRLINK_CIT=m
++CONFIG_USB_GSPCA_ZC3XX=m
++CONFIG_USB_PWC=m
++CONFIG_VIDEO_CPIA2=m
++CONFIG_USB_ZR364XX=m
++CONFIG_USB_STKWEBCAM=m
++CONFIG_USB_S2255=m
++CONFIG_VIDEO_USBTV=m
++CONFIG_VIDEO_PVRUSB2=m
++CONFIG_VIDEO_HDPVR=m
++CONFIG_VIDEO_USBVISION=m
++CONFIG_VIDEO_STK1160_COMMON=m
++CONFIG_VIDEO_STK1160_AC97=y
++CONFIG_VIDEO_GO7007=m
++CONFIG_VIDEO_GO7007_USB=m
++CONFIG_VIDEO_GO7007_USB_S2250_BOARD=m
++CONFIG_VIDEO_AU0828=m
++CONFIG_VIDEO_AU0828_RC=y
++CONFIG_VIDEO_CX231XX=m
++CONFIG_VIDEO_CX231XX_ALSA=m
++CONFIG_VIDEO_CX231XX_DVB=m
++CONFIG_VIDEO_TM6000=m
++CONFIG_VIDEO_TM6000_ALSA=m
++CONFIG_VIDEO_TM6000_DVB=m
++CONFIG_DVB_USB=m
++CONFIG_DVB_USB_A800=m
++CONFIG_DVB_USB_DIBUSB_MB=m
++CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y
++CONFIG_DVB_USB_DIBUSB_MC=m
++CONFIG_DVB_USB_DIB0700=m
++CONFIG_DVB_USB_UMT_010=m
++CONFIG_DVB_USB_CXUSB=m
++CONFIG_DVB_USB_M920X=m
++CONFIG_DVB_USB_DIGITV=m
++CONFIG_DVB_USB_VP7045=m
++CONFIG_DVB_USB_VP702X=m
++CONFIG_DVB_USB_GP8PSK=m
++CONFIG_DVB_USB_NOVA_T_USB2=m
++CONFIG_DVB_USB_TTUSB2=m
++CONFIG_DVB_USB_DTT200U=m
++CONFIG_DVB_USB_OPERA1=m
++CONFIG_DVB_USB_AF9005=m
++CONFIG_DVB_USB_AF9005_REMOTE=m
++CONFIG_DVB_USB_PCTV452E=m
++CONFIG_DVB_USB_DW2102=m
++CONFIG_DVB_USB_CINERGY_T2=m
++CONFIG_DVB_USB_DTV5100=m
++CONFIG_DVB_USB_FRIIO=m
++CONFIG_DVB_USB_AZ6027=m
++CONFIG_DVB_USB_TECHNISAT_USB2=m
++CONFIG_DVB_USB_V2=m
++CONFIG_DVB_USB_AF9015=m
++CONFIG_DVB_USB_AF9035=m
++CONFIG_DVB_USB_ANYSEE=m
++CONFIG_DVB_USB_AU6610=m
++CONFIG_DVB_USB_AZ6007=m
++CONFIG_DVB_USB_CE6230=m
++CONFIG_DVB_USB_EC168=m
++CONFIG_DVB_USB_GL861=m
++CONFIG_DVB_USB_LME2510=m
++CONFIG_DVB_USB_MXL111SF=m
++CONFIG_DVB_USB_RTL28XXU=m
++CONFIG_DVB_USB_DVBSKY=m
++CONFIG_SMS_USB_DRV=m
++CONFIG_DVB_B2C2_FLEXCOP_USB=m
++CONFIG_DVB_AS102=m
++CONFIG_VIDEO_EM28XX=m
++CONFIG_VIDEO_EM28XX_V4L2=m
++CONFIG_VIDEO_EM28XX_ALSA=m
++CONFIG_VIDEO_EM28XX_DVB=m
++CONFIG_V4L_PLATFORM_DRIVERS=y
++CONFIG_VIDEO_BCM2835=y
++CONFIG_VIDEO_BCM2835_MMAL=m
++CONFIG_RADIO_SI470X=y
++CONFIG_USB_SI470X=m
++CONFIG_I2C_SI470X=m
++CONFIG_RADIO_SI4713=m
++CONFIG_I2C_SI4713=m
++CONFIG_USB_MR800=m
++CONFIG_USB_DSBR=m
++CONFIG_RADIO_SHARK=m
++CONFIG_RADIO_SHARK2=m
++CONFIG_USB_KEENE=m
++CONFIG_USB_MA901=m
++CONFIG_RADIO_TEA5764=m
++CONFIG_RADIO_SAA7706H=m
++CONFIG_RADIO_TEF6862=m
++CONFIG_RADIO_WL1273=m
++CONFIG_RADIO_WL128X=m
++# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
++CONFIG_VIDEO_UDA1342=m
++CONFIG_VIDEO_SONY_BTF_MPX=m
++CONFIG_VIDEO_TVP5150=m
++CONFIG_VIDEO_TW2804=m
++CONFIG_VIDEO_TW9903=m
++CONFIG_VIDEO_TW9906=m
++CONFIG_VIDEO_OV7640=m
++CONFIG_VIDEO_MT9V011=m
++CONFIG_FB=y
++CONFIG_FB_BCM2708=y
++CONFIG_FB_UDL=m
++CONFIG_FB_SSD1307=m
++CONFIG_FB_RPISENSE=m
++# CONFIG_BACKLIGHT_GENERIC is not set
++CONFIG_BACKLIGHT_GPIO=m
++CONFIG_FRAMEBUFFER_CONSOLE=y
++CONFIG_LOGO=y
++# CONFIG_LOGO_LINUX_MONO is not set
++# CONFIG_LOGO_LINUX_VGA16 is not set
++CONFIG_SOUND=y
++CONFIG_SND=m
++CONFIG_SND_SEQUENCER=m
++CONFIG_SND_SEQ_DUMMY=m
++CONFIG_SND_MIXER_OSS=m
++CONFIG_SND_PCM_OSS=m
++CONFIG_SND_SEQUENCER_OSS=y
++CONFIG_SND_HRTIMER=m
++CONFIG_SND_DUMMY=m
++CONFIG_SND_ALOOP=m
++CONFIG_SND_VIRMIDI=m
++CONFIG_SND_MTPAV=m
++CONFIG_SND_SERIAL_U16550=m
++CONFIG_SND_MPU401=m
++CONFIG_SND_BCM2835=m
++CONFIG_SND_USB_AUDIO=m
++CONFIG_SND_USB_UA101=m
++CONFIG_SND_USB_CAIAQ=m
++CONFIG_SND_USB_CAIAQ_INPUT=y
++CONFIG_SND_USB_6FIRE=m
++CONFIG_SND_SOC=m
++CONFIG_SND_BCM2835_SOC_I2S=m
++CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC=m
++CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS=m
++CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI=m
++CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP=m
++CONFIG_SND_BCM2708_SOC_RPI_DAC=m
++CONFIG_SND_BCM2708_SOC_RPI_PROTO=m
++CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m
++CONFIG_SND_BCM2708_SOC_RASPIDAC3=m
++CONFIG_SND_SOC_ADAU1701=m
++CONFIG_SND_SOC_WM8804_I2C=m
++CONFIG_SND_SIMPLE_CARD=m
++CONFIG_SOUND_PRIME=m
++CONFIG_HIDRAW=y
++CONFIG_UHID=m
++CONFIG_HID_A4TECH=m
++CONFIG_HID_ACRUX=m
++CONFIG_HID_APPLE=m
++CONFIG_HID_BELKIN=m
++CONFIG_HID_CHERRY=m
++CONFIG_HID_CHICONY=m
++CONFIG_HID_CYPRESS=m
++CONFIG_HID_DRAGONRISE=m
++CONFIG_HID_EMS_FF=m
++CONFIG_HID_ELECOM=m
++CONFIG_HID_ELO=m
++CONFIG_HID_EZKEY=m
++CONFIG_HID_HOLTEK=m
++CONFIG_HID_KEYTOUCH=m
++CONFIG_HID_KYE=m
++CONFIG_HID_UCLOGIC=m
++CONFIG_HID_WALTOP=m
++CONFIG_HID_GYRATION=m
++CONFIG_HID_TWINHAN=m
++CONFIG_HID_KENSINGTON=m
++CONFIG_HID_LCPOWER=m
++CONFIG_HID_LOGITECH=m
++CONFIG_HID_MAGICMOUSE=m
++CONFIG_HID_MICROSOFT=m
++CONFIG_HID_MONTEREY=m
++CONFIG_HID_MULTITOUCH=m
++CONFIG_HID_NTRIG=m
++CONFIG_HID_ORTEK=m
++CONFIG_HID_PANTHERLORD=m
++CONFIG_HID_PETALYNX=m
++CONFIG_HID_PICOLCD=m
++CONFIG_HID_ROCCAT=m
++CONFIG_HID_SAMSUNG=m
++CONFIG_HID_SONY=m
++CONFIG_HID_SPEEDLINK=m
++CONFIG_HID_SUNPLUS=m
++CONFIG_HID_GREENASIA=m
++CONFIG_HID_SMARTJOYPLUS=m
++CONFIG_HID_TOPSEED=m
++CONFIG_HID_THINGM=m
++CONFIG_HID_THRUSTMASTER=m
++CONFIG_HID_WACOM=m
++CONFIG_HID_WIIMOTE=m
++CONFIG_HID_XINMO=m
++CONFIG_HID_ZEROPLUS=m
++CONFIG_HID_ZYDACRON=m
++CONFIG_HID_PID=y
++CONFIG_USB_HIDDEV=y
++CONFIG_USB=y
++CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
++CONFIG_USB_MON=m
++CONFIG_USB_DWCOTG=y
++CONFIG_USB_PRINTER=m
++CONFIG_USB_STORAGE=y
++CONFIG_USB_STORAGE_REALTEK=m
++CONFIG_USB_STORAGE_DATAFAB=m
++CONFIG_USB_STORAGE_FREECOM=m
++CONFIG_USB_STORAGE_ISD200=m
++CONFIG_USB_STORAGE_USBAT=m
++CONFIG_USB_STORAGE_SDDR09=m
++CONFIG_USB_STORAGE_SDDR55=m
++CONFIG_USB_STORAGE_JUMPSHOT=m
++CONFIG_USB_STORAGE_ALAUDA=m
++CONFIG_USB_STORAGE_ONETOUCH=m
++CONFIG_USB_STORAGE_KARMA=m
++CONFIG_USB_STORAGE_CYPRESS_ATACB=m
++CONFIG_USB_STORAGE_ENE_UB6250=m
++CONFIG_USB_MDC800=m
++CONFIG_USB_MICROTEK=m
++CONFIG_USBIP_CORE=m
++CONFIG_USBIP_VHCI_HCD=m
++CONFIG_USBIP_HOST=m
++CONFIG_USB_SERIAL=m
++CONFIG_USB_SERIAL_GENERIC=y
++CONFIG_USB_SERIAL_AIRCABLE=m
++CONFIG_USB_SERIAL_ARK3116=m
++CONFIG_USB_SERIAL_BELKIN=m
++CONFIG_USB_SERIAL_CH341=m
++CONFIG_USB_SERIAL_WHITEHEAT=m
++CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
++CONFIG_USB_SERIAL_CP210X=m
++CONFIG_USB_SERIAL_CYPRESS_M8=m
++CONFIG_USB_SERIAL_EMPEG=m
++CONFIG_USB_SERIAL_FTDI_SIO=m
++CONFIG_USB_SERIAL_VISOR=m
++CONFIG_USB_SERIAL_IPAQ=m
++CONFIG_USB_SERIAL_IR=m
++CONFIG_USB_SERIAL_EDGEPORT=m
++CONFIG_USB_SERIAL_EDGEPORT_TI=m
++CONFIG_USB_SERIAL_F81232=m
++CONFIG_USB_SERIAL_GARMIN=m
++CONFIG_USB_SERIAL_IPW=m
++CONFIG_USB_SERIAL_IUU=m
++CONFIG_USB_SERIAL_KEYSPAN_PDA=m
++CONFIG_USB_SERIAL_KEYSPAN=m
++CONFIG_USB_SERIAL_KLSI=m
++CONFIG_USB_SERIAL_KOBIL_SCT=m
++CONFIG_USB_SERIAL_MCT_U232=m
++CONFIG_USB_SERIAL_METRO=m
++CONFIG_USB_SERIAL_MOS7720=m
++CONFIG_USB_SERIAL_MOS7840=m
++CONFIG_USB_SERIAL_NAVMAN=m
++CONFIG_USB_SERIAL_PL2303=m
++CONFIG_USB_SERIAL_OTI6858=m
++CONFIG_USB_SERIAL_QCAUX=m
++CONFIG_USB_SERIAL_QUALCOMM=m
++CONFIG_USB_SERIAL_SPCP8X5=m
++CONFIG_USB_SERIAL_SAFE=m
++CONFIG_USB_SERIAL_SIERRAWIRELESS=m
++CONFIG_USB_SERIAL_SYMBOL=m
++CONFIG_USB_SERIAL_TI=m
++CONFIG_USB_SERIAL_CYBERJACK=m
++CONFIG_USB_SERIAL_XIRCOM=m
++CONFIG_USB_SERIAL_OPTION=m
++CONFIG_USB_SERIAL_OMNINET=m
++CONFIG_USB_SERIAL_OPTICON=m
++CONFIG_USB_SERIAL_XSENS_MT=m
++CONFIG_USB_SERIAL_WISHBONE=m
++CONFIG_USB_SERIAL_SSU100=m
++CONFIG_USB_SERIAL_QT2=m
++CONFIG_USB_SERIAL_DEBUG=m
++CONFIG_USB_EMI62=m
++CONFIG_USB_EMI26=m
++CONFIG_USB_ADUTUX=m
++CONFIG_USB_SEVSEG=m
++CONFIG_USB_RIO500=m
++CONFIG_USB_LEGOTOWER=m
++CONFIG_USB_LCD=m
++CONFIG_USB_LED=m
++CONFIG_USB_CYPRESS_CY7C63=m
++CONFIG_USB_CYTHERM=m
++CONFIG_USB_IDMOUSE=m
++CONFIG_USB_FTDI_ELAN=m
++CONFIG_USB_APPLEDISPLAY=m
++CONFIG_USB_LD=m
++CONFIG_USB_TRANCEVIBRATOR=m
++CONFIG_USB_IOWARRIOR=m
++CONFIG_USB_TEST=m
++CONFIG_USB_ISIGHTFW=m
++CONFIG_USB_YUREX=m
++CONFIG_USB_ATM=m
++CONFIG_USB_SPEEDTOUCH=m
++CONFIG_USB_CXACRU=m
++CONFIG_USB_UEAGLEATM=m
++CONFIG_USB_XUSBATM=m
++CONFIG_MMC=y
++CONFIG_MMC_BLOCK_MINORS=32
++CONFIG_MMC_BCM2835=y
++CONFIG_MMC_BCM2835_DMA=y
++CONFIG_MMC_BCM2835_SDHOST=y
++CONFIG_MMC_SDHCI=y
++CONFIG_MMC_SDHCI_PLTFM=y
++CONFIG_MMC_SPI=m
++CONFIG_LEDS_CLASS=y
++CONFIG_LEDS_GPIO=y
++CONFIG_LEDS_TRIGGER_TIMER=y
++CONFIG_LEDS_TRIGGER_ONESHOT=y
++CONFIG_LEDS_TRIGGER_HEARTBEAT=y
++CONFIG_LEDS_TRIGGER_BACKLIGHT=y
++CONFIG_LEDS_TRIGGER_CPU=y
++CONFIG_LEDS_TRIGGER_GPIO=y
++CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
++CONFIG_LEDS_TRIGGER_TRANSIENT=m
++CONFIG_LEDS_TRIGGER_CAMERA=m
++CONFIG_LEDS_TRIGGER_INPUT=y
++CONFIG_RTC_CLASS=y
++# CONFIG_RTC_HCTOSYS is not set
++CONFIG_RTC_DRV_DS1307=m
++CONFIG_RTC_DRV_DS1374=m
++CONFIG_RTC_DRV_DS1672=m
++CONFIG_RTC_DRV_DS3232=m
++CONFIG_RTC_DRV_MAX6900=m
++CONFIG_RTC_DRV_RS5C372=m
++CONFIG_RTC_DRV_ISL1208=m
++CONFIG_RTC_DRV_ISL12022=m
++CONFIG_RTC_DRV_ISL12057=m
++CONFIG_RTC_DRV_X1205=m
++CONFIG_RTC_DRV_PCF2127=m
++CONFIG_RTC_DRV_PCF8523=m
++CONFIG_RTC_DRV_PCF8563=m
++CONFIG_RTC_DRV_PCF8583=m
++CONFIG_RTC_DRV_M41T80=m
++CONFIG_RTC_DRV_BQ32K=m
++CONFIG_RTC_DRV_S35390A=m
++CONFIG_RTC_DRV_FM3130=m
++CONFIG_RTC_DRV_RX8581=m
++CONFIG_RTC_DRV_RX8025=m
++CONFIG_RTC_DRV_EM3027=m
++CONFIG_RTC_DRV_RV3029C2=m
++CONFIG_RTC_DRV_M41T93=m
++CONFIG_RTC_DRV_M41T94=m
++CONFIG_RTC_DRV_DS1305=m
++CONFIG_RTC_DRV_DS1390=m
++CONFIG_RTC_DRV_MAX6902=m
++CONFIG_RTC_DRV_R9701=m
++CONFIG_RTC_DRV_RS5C348=m
++CONFIG_RTC_DRV_DS3234=m
++CONFIG_RTC_DRV_PCF2123=m
++CONFIG_RTC_DRV_RX4581=m
++CONFIG_DMADEVICES=y
++CONFIG_DMA_BCM2835=y
++CONFIG_DMA_BCM2708=y
++CONFIG_UIO=m
++CONFIG_UIO_PDRV_GENIRQ=m
++CONFIG_STAGING=y
++CONFIG_PRISM2_USB=m
++CONFIG_R8712U=m
++CONFIG_R8188EU=m
++CONFIG_R8723AU=m
++CONFIG_VT6656=m
++CONFIG_SPEAKUP=m
++CONFIG_SPEAKUP_SYNTH_SOFT=m
++CONFIG_STAGING_MEDIA=y
++CONFIG_LIRC_STAGING=y
++CONFIG_LIRC_IMON=m
++CONFIG_LIRC_RPI=m
++CONFIG_LIRC_SASEM=m
++CONFIG_LIRC_SERIAL=m
++CONFIG_FB_TFT=m
++CONFIG_FB_TFT_AGM1264K_FL=m
++CONFIG_FB_TFT_BD663474=m
++CONFIG_FB_TFT_HX8340BN=m
++CONFIG_FB_TFT_HX8347D=m
++CONFIG_FB_TFT_HX8353D=m
++CONFIG_FB_TFT_ILI9163=m
++CONFIG_FB_TFT_ILI9320=m
++CONFIG_FB_TFT_ILI9325=m
++CONFIG_FB_TFT_ILI9340=m
++CONFIG_FB_TFT_ILI9341=m
++CONFIG_FB_TFT_ILI9481=m
++CONFIG_FB_TFT_ILI9486=m
++CONFIG_FB_TFT_PCD8544=m
++CONFIG_FB_TFT_RA8875=m
++CONFIG_FB_TFT_S6D02A1=m
++CONFIG_FB_TFT_S6D1121=m
++CONFIG_FB_TFT_SSD1289=m
++CONFIG_FB_TFT_SSD1306=m
++CONFIG_FB_TFT_SSD1331=m
++CONFIG_FB_TFT_SSD1351=m
++CONFIG_FB_TFT_ST7735R=m
++CONFIG_FB_TFT_TINYLCD=m
++CONFIG_FB_TFT_TLS8204=m
++CONFIG_FB_TFT_UC1701=m
++CONFIG_FB_TFT_UPD161704=m
++CONFIG_FB_TFT_WATTEROTT=m
++CONFIG_FB_FLEX=m
++CONFIG_FB_TFT_FBTFT_DEVICE=m
++CONFIG_MAILBOX=y
++CONFIG_BCM2835_MBOX=y
++# CONFIG_IOMMU_SUPPORT is not set
++CONFIG_EXTCON=m
++CONFIG_EXTCON_ARIZONA=m
++CONFIG_IIO=m
++CONFIG_IIO_BUFFER=y
++CONFIG_IIO_BUFFER_CB=y
++CONFIG_IIO_KFIFO_BUF=m
++CONFIG_MCP320X=m
++CONFIG_DHT11=m
++CONFIG_PWM_BCM2835=m
++CONFIG_RASPBERRYPI_FIRMWARE=y
++CONFIG_EXT4_FS=y
++CONFIG_EXT4_FS_POSIX_ACL=y
++CONFIG_EXT4_FS_SECURITY=y
++CONFIG_REISERFS_FS=m
++CONFIG_REISERFS_FS_XATTR=y
++CONFIG_REISERFS_FS_POSIX_ACL=y
++CONFIG_REISERFS_FS_SECURITY=y
++CONFIG_JFS_FS=m
++CONFIG_JFS_POSIX_ACL=y
++CONFIG_JFS_SECURITY=y
++CONFIG_JFS_STATISTICS=y
++CONFIG_XFS_FS=m
++CONFIG_XFS_QUOTA=y
++CONFIG_XFS_POSIX_ACL=y
++CONFIG_XFS_RT=y
++CONFIG_GFS2_FS=m
++CONFIG_OCFS2_FS=m
++CONFIG_BTRFS_FS=m
++CONFIG_BTRFS_FS_POSIX_ACL=y
++CONFIG_NILFS2_FS=m
++CONFIG_F2FS_FS=y
++CONFIG_FANOTIFY=y
++CONFIG_QFMT_V1=m
++CONFIG_QFMT_V2=m
++CONFIG_AUTOFS4_FS=y
++CONFIG_FUSE_FS=m
++CONFIG_CUSE=m
++CONFIG_OVERLAY_FS=m
++CONFIG_FSCACHE=y
++CONFIG_FSCACHE_STATS=y
++CONFIG_FSCACHE_HISTOGRAM=y
++CONFIG_CACHEFILES=y
++CONFIG_ISO9660_FS=m
++CONFIG_JOLIET=y
++CONFIG_ZISOFS=y
++CONFIG_UDF_FS=m
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
++CONFIG_NTFS_FS=m
++CONFIG_NTFS_RW=y
++CONFIG_TMPFS=y
++CONFIG_TMPFS_POSIX_ACL=y
++CONFIG_CONFIGFS_FS=y
++CONFIG_ECRYPT_FS=m
++CONFIG_HFS_FS=m
++CONFIG_HFSPLUS_FS=m
++CONFIG_JFFS2_FS=m
++CONFIG_JFFS2_SUMMARY=y
++CONFIG_UBIFS_FS=m
++CONFIG_SQUASHFS=m
++CONFIG_SQUASHFS_XATTR=y
++CONFIG_SQUASHFS_LZO=y
++CONFIG_SQUASHFS_XZ=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3_ACL=y
++CONFIG_NFS_V4=y
++CONFIG_NFS_SWAP=y
++CONFIG_ROOT_NFS=y
++CONFIG_NFS_FSCACHE=y
++CONFIG_NFSD=m
++CONFIG_NFSD_V3_ACL=y
++CONFIG_NFSD_V4=y
++CONFIG_CIFS=m
++CONFIG_CIFS_WEAK_PW_HASH=y
++CONFIG_CIFS_UPCALL=y
++CONFIG_CIFS_XATTR=y
++CONFIG_CIFS_POSIX=y
++CONFIG_CIFS_ACL=y
++CONFIG_CIFS_DFS_UPCALL=y
++CONFIG_CIFS_SMB2=y
++CONFIG_CIFS_FSCACHE=y
++CONFIG_9P_FS=m
++CONFIG_9P_FS_POSIX_ACL=y
++CONFIG_NLS_DEFAULT="utf8"
++CONFIG_NLS_CODEPAGE_437=y
++CONFIG_NLS_CODEPAGE_737=m
++CONFIG_NLS_CODEPAGE_775=m
++CONFIG_NLS_CODEPAGE_850=m
++CONFIG_NLS_CODEPAGE_852=m
++CONFIG_NLS_CODEPAGE_855=m
++CONFIG_NLS_CODEPAGE_857=m
++CONFIG_NLS_CODEPAGE_860=m
++CONFIG_NLS_CODEPAGE_861=m
++CONFIG_NLS_CODEPAGE_862=m
++CONFIG_NLS_CODEPAGE_863=m
++CONFIG_NLS_CODEPAGE_864=m
++CONFIG_NLS_CODEPAGE_865=m
++CONFIG_NLS_CODEPAGE_866=m
++CONFIG_NLS_CODEPAGE_869=m
++CONFIG_NLS_CODEPAGE_936=m
++CONFIG_NLS_CODEPAGE_950=m
++CONFIG_NLS_CODEPAGE_932=m
++CONFIG_NLS_CODEPAGE_949=m
++CONFIG_NLS_CODEPAGE_874=m
++CONFIG_NLS_ISO8859_8=m
++CONFIG_NLS_CODEPAGE_1250=m
++CONFIG_NLS_CODEPAGE_1251=m
++CONFIG_NLS_ASCII=y
++CONFIG_NLS_ISO8859_1=m
++CONFIG_NLS_ISO8859_2=m
++CONFIG_NLS_ISO8859_3=m
++CONFIG_NLS_ISO8859_4=m
++CONFIG_NLS_ISO8859_5=m
++CONFIG_NLS_ISO8859_6=m
++CONFIG_NLS_ISO8859_7=m
++CONFIG_NLS_ISO8859_9=m
++CONFIG_NLS_ISO8859_13=m
++CONFIG_NLS_ISO8859_14=m
++CONFIG_NLS_ISO8859_15=m
++CONFIG_NLS_KOI8_R=m
++CONFIG_NLS_KOI8_U=m
++CONFIG_DLM=m
++CONFIG_PRINTK_TIME=y
++CONFIG_BOOT_PRINTK_DELAY=y
++CONFIG_DEBUG_MEMORY_INIT=y
++CONFIG_DETECT_HUNG_TASK=y
++CONFIG_TIMER_STATS=y
++CONFIG_IRQSOFF_TRACER=y
++CONFIG_SCHED_TRACER=y
++CONFIG_STACK_TRACER=y
++CONFIG_BLK_DEV_IO_TRACE=y
++# CONFIG_KPROBE_EVENT is not set
++CONFIG_FUNCTION_PROFILER=y
++CONFIG_KGDB=y
++CONFIG_KGDB_KDB=y
++CONFIG_KDB_KEYBOARD=y
++CONFIG_CRYPTO_USER=m
++CONFIG_CRYPTO_CBC=y
++CONFIG_CRYPTO_CTS=m
++CONFIG_CRYPTO_XTS=m
++CONFIG_CRYPTO_XCBC=m
++CONFIG_CRYPTO_TGR192=m
++CONFIG_CRYPTO_WP512=m
++CONFIG_CRYPTO_CAST5=m
++CONFIG_CRYPTO_DES=y
++CONFIG_CRYPTO_USER_API_SKCIPHER=m
++# CONFIG_CRYPTO_HW is not set
++CONFIG_ARM_CRYPTO=y
++CONFIG_CRYPTO_SHA1_ARM_NEON=m
++CONFIG_CRYPTO_AES_ARM_BS=m
++CONFIG_CRC_ITU_T=y
++CONFIG_LIBCRC32C=y
+--- /dev/null
++++ b/arch/arm/configs/bcmrpi_defconfig
+@@ -0,0 +1,1265 @@
++# CONFIG_ARM_PATCH_PHYS_VIRT is not set
++CONFIG_PHYS_OFFSET=0
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_SYSVIPC=y
++CONFIG_POSIX_MQUEUE=y
++CONFIG_FHANDLE=y
++CONFIG_NO_HZ=y
++CONFIG_HIGH_RES_TIMERS=y
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_BSD_PROCESS_ACCT_V3=y
++CONFIG_TASKSTATS=y
++CONFIG_TASK_DELAY_ACCT=y
++CONFIG_TASK_XACCT=y
++CONFIG_TASK_IO_ACCOUNTING=y
++CONFIG_IKCONFIG=m
++CONFIG_IKCONFIG_PROC=y
++CONFIG_CGROUP_FREEZER=y
++CONFIG_CGROUP_DEVICE=y
++CONFIG_CPUSETS=y
++CONFIG_CGROUP_CPUACCT=y
++CONFIG_MEMCG=y
++CONFIG_BLK_CGROUP=y
++CONFIG_NAMESPACES=y
++CONFIG_SCHED_AUTOGROUP=y
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_EMBEDDED=y
++# CONFIG_COMPAT_BRK is not set
++CONFIG_PROFILING=y
++CONFIG_OPROFILE=m
++CONFIG_KPROBES=y
++CONFIG_JUMP_LABEL=y
++CONFIG_MODULES=y
++CONFIG_MODULE_UNLOAD=y
++CONFIG_MODVERSIONS=y
++CONFIG_MODULE_SRCVERSION_ALL=y
++CONFIG_BLK_DEV_THROTTLING=y
++CONFIG_PARTITION_ADVANCED=y
++CONFIG_MAC_PARTITION=y
++CONFIG_CFQ_GROUP_IOSCHED=y
++CONFIG_ARCH_BCM2708=y
++CONFIG_PREEMPT_VOLUNTARY=y
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++# CONFIG_CPU_SW_DOMAIN_PAN is not set
++CONFIG_CLEANCACHE=y
++CONFIG_FRONTSWAP=y
++CONFIG_CMA=y
++CONFIG_ZSMALLOC=m
++CONFIG_PGTABLE_MAPPING=y
++CONFIG_UACCESS_WITH_MEMCPY=y
++CONFIG_SECCOMP=y
++# CONFIG_ATAGS is not set
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait"
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_STAT=m
++CONFIG_CPU_FREQ_STAT_DETAILS=y
++CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE=y
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
++CONFIG_CPU_FREQ_GOV_ONDEMAND=y
++CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
++CONFIG_VFP=y
++CONFIG_BINFMT_MISC=m
++# CONFIG_SUSPEND is not set
++CONFIG_NET=y
++CONFIG_PACKET=y
++CONFIG_UNIX=y
++CONFIG_XFRM_USER=y
++CONFIG_NET_KEY=m
++CONFIG_INET=y
++CONFIG_IP_MULTICAST=y
++CONFIG_IP_ADVANCED_ROUTER=y
++CONFIG_IP_MULTIPLE_TABLES=y
++CONFIG_IP_ROUTE_MULTIPATH=y
++CONFIG_IP_ROUTE_VERBOSE=y
++CONFIG_IP_PNP=y
++CONFIG_IP_PNP_DHCP=y
++CONFIG_IP_PNP_RARP=y
++CONFIG_NET_IPIP=m
++CONFIG_NET_IPGRE_DEMUX=m
++CONFIG_NET_IPGRE=m
++CONFIG_IP_MROUTE=y
++CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
++CONFIG_IP_PIMSM_V1=y
++CONFIG_IP_PIMSM_V2=y
++CONFIG_SYN_COOKIES=y
++CONFIG_INET_AH=m
++CONFIG_INET_ESP=m
++CONFIG_INET_IPCOMP=m
++CONFIG_INET_XFRM_MODE_TRANSPORT=m
++CONFIG_INET_XFRM_MODE_TUNNEL=m
++CONFIG_INET_XFRM_MODE_BEET=m
++CONFIG_INET_LRO=m
++CONFIG_INET_DIAG=m
++CONFIG_INET6_AH=m
++CONFIG_INET6_ESP=m
++CONFIG_INET6_IPCOMP=m
++CONFIG_IPV6_TUNNEL=m
++CONFIG_IPV6_MULTIPLE_TABLES=y
++CONFIG_IPV6_MROUTE=y
++CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
++CONFIG_IPV6_PIMSM_V2=y
++CONFIG_NETFILTER=y
++CONFIG_NF_CONNTRACK=m
++CONFIG_NF_CONNTRACK_ZONES=y
++CONFIG_NF_CONNTRACK_EVENTS=y
++CONFIG_NF_CONNTRACK_TIMESTAMP=y
++CONFIG_NF_CT_PROTO_DCCP=m
++CONFIG_NF_CT_PROTO_UDPLITE=m
++CONFIG_NF_CONNTRACK_AMANDA=m
++CONFIG_NF_CONNTRACK_FTP=m
++CONFIG_NF_CONNTRACK_H323=m
++CONFIG_NF_CONNTRACK_IRC=m
++CONFIG_NF_CONNTRACK_NETBIOS_NS=m
++CONFIG_NF_CONNTRACK_SNMP=m
++CONFIG_NF_CONNTRACK_PPTP=m
++CONFIG_NF_CONNTRACK_SANE=m
++CONFIG_NF_CONNTRACK_SIP=m
++CONFIG_NF_CONNTRACK_TFTP=m
++CONFIG_NF_CT_NETLINK=m
++CONFIG_NETFILTER_XT_SET=m
++CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
++CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
++CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
++CONFIG_NETFILTER_XT_TARGET_DSCP=m
++CONFIG_NETFILTER_XT_TARGET_HMARK=m
++CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
++CONFIG_NETFILTER_XT_TARGET_LED=m
++CONFIG_NETFILTER_XT_TARGET_LOG=m
++CONFIG_NETFILTER_XT_TARGET_MARK=m
++CONFIG_NETFILTER_XT_TARGET_NFLOG=m
++CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
++CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
++CONFIG_NETFILTER_XT_TARGET_TEE=m
++CONFIG_NETFILTER_XT_TARGET_TPROXY=m
++CONFIG_NETFILTER_XT_TARGET_TRACE=m
++CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
++CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
++CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m
++CONFIG_NETFILTER_XT_MATCH_BPF=m
++CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
++CONFIG_NETFILTER_XT_MATCH_COMMENT=m
++CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
++CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m
++CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
++CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
++CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
++CONFIG_NETFILTER_XT_MATCH_CPU=m
++CONFIG_NETFILTER_XT_MATCH_DCCP=m
++CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m
++CONFIG_NETFILTER_XT_MATCH_DSCP=m
++CONFIG_NETFILTER_XT_MATCH_ESP=m
++CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
++CONFIG_NETFILTER_XT_MATCH_HELPER=m
++CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
++CONFIG_NETFILTER_XT_MATCH_IPVS=m
++CONFIG_NETFILTER_XT_MATCH_LENGTH=m
++CONFIG_NETFILTER_XT_MATCH_LIMIT=m
++CONFIG_NETFILTER_XT_MATCH_MAC=m
++CONFIG_NETFILTER_XT_MATCH_MARK=m
++CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
++CONFIG_NETFILTER_XT_MATCH_NFACCT=m
++CONFIG_NETFILTER_XT_MATCH_OSF=m
++CONFIG_NETFILTER_XT_MATCH_OWNER=m
++CONFIG_NETFILTER_XT_MATCH_POLICY=m
++CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
++CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
++CONFIG_NETFILTER_XT_MATCH_QUOTA=m
++CONFIG_NETFILTER_XT_MATCH_RATEEST=m
++CONFIG_NETFILTER_XT_MATCH_REALM=m
++CONFIG_NETFILTER_XT_MATCH_RECENT=m
++CONFIG_NETFILTER_XT_MATCH_SOCKET=m
++CONFIG_NETFILTER_XT_MATCH_STATE=m
++CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
++CONFIG_NETFILTER_XT_MATCH_STRING=m
++CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
++CONFIG_NETFILTER_XT_MATCH_TIME=m
++CONFIG_NETFILTER_XT_MATCH_U32=m
++CONFIG_IP_SET=m
++CONFIG_IP_SET_BITMAP_IP=m
++CONFIG_IP_SET_BITMAP_IPMAC=m
++CONFIG_IP_SET_BITMAP_PORT=m
++CONFIG_IP_SET_HASH_IP=m
++CONFIG_IP_SET_HASH_IPPORT=m
++CONFIG_IP_SET_HASH_IPPORTIP=m
++CONFIG_IP_SET_HASH_IPPORTNET=m
++CONFIG_IP_SET_HASH_NET=m
++CONFIG_IP_SET_HASH_NETPORT=m
++CONFIG_IP_SET_HASH_NETIFACE=m
++CONFIG_IP_SET_LIST_SET=m
++CONFIG_IP_VS=m
++CONFIG_IP_VS_PROTO_TCP=y
++CONFIG_IP_VS_PROTO_UDP=y
++CONFIG_IP_VS_PROTO_ESP=y
++CONFIG_IP_VS_PROTO_AH=y
++CONFIG_IP_VS_PROTO_SCTP=y
++CONFIG_IP_VS_RR=m
++CONFIG_IP_VS_WRR=m
++CONFIG_IP_VS_LC=m
++CONFIG_IP_VS_WLC=m
++CONFIG_IP_VS_LBLC=m
++CONFIG_IP_VS_LBLCR=m
++CONFIG_IP_VS_DH=m
++CONFIG_IP_VS_SH=m
++CONFIG_IP_VS_SED=m
++CONFIG_IP_VS_NQ=m
++CONFIG_IP_VS_FTP=m
++CONFIG_IP_VS_PE_SIP=m
++CONFIG_NF_CONNTRACK_IPV4=m
++CONFIG_IP_NF_IPTABLES=m
++CONFIG_IP_NF_MATCH_AH=m
++CONFIG_IP_NF_MATCH_ECN=m
++CONFIG_IP_NF_MATCH_TTL=m
++CONFIG_IP_NF_FILTER=m
++CONFIG_IP_NF_TARGET_REJECT=m
++CONFIG_IP_NF_NAT=m
++CONFIG_IP_NF_TARGET_MASQUERADE=m
++CONFIG_IP_NF_TARGET_NETMAP=m
++CONFIG_IP_NF_TARGET_REDIRECT=m
++CONFIG_IP_NF_MANGLE=m
++CONFIG_IP_NF_TARGET_CLUSTERIP=m
++CONFIG_IP_NF_TARGET_ECN=m
++CONFIG_IP_NF_TARGET_TTL=m
++CONFIG_IP_NF_RAW=m
++CONFIG_IP_NF_ARPTABLES=m
++CONFIG_IP_NF_ARPFILTER=m
++CONFIG_IP_NF_ARP_MANGLE=m
++CONFIG_NF_CONNTRACK_IPV6=m
++CONFIG_IP6_NF_IPTABLES=m
++CONFIG_IP6_NF_MATCH_AH=m
++CONFIG_IP6_NF_MATCH_EUI64=m
++CONFIG_IP6_NF_MATCH_FRAG=m
++CONFIG_IP6_NF_MATCH_OPTS=m
++CONFIG_IP6_NF_MATCH_HL=m
++CONFIG_IP6_NF_MATCH_IPV6HEADER=m
++CONFIG_IP6_NF_MATCH_MH=m
++CONFIG_IP6_NF_MATCH_RT=m
++CONFIG_IP6_NF_TARGET_HL=m
++CONFIG_IP6_NF_FILTER=m
++CONFIG_IP6_NF_TARGET_REJECT=m
++CONFIG_IP6_NF_MANGLE=m
++CONFIG_IP6_NF_RAW=m
++CONFIG_IP6_NF_NAT=m
++CONFIG_IP6_NF_TARGET_MASQUERADE=m
++CONFIG_IP6_NF_TARGET_NPT=m
++CONFIG_BRIDGE_NF_EBTABLES=m
++CONFIG_BRIDGE_EBT_BROUTE=m
++CONFIG_BRIDGE_EBT_T_FILTER=m
++CONFIG_BRIDGE_EBT_T_NAT=m
++CONFIG_BRIDGE_EBT_802_3=m
++CONFIG_BRIDGE_EBT_AMONG=m
++CONFIG_BRIDGE_EBT_ARP=m
++CONFIG_BRIDGE_EBT_IP=m
++CONFIG_BRIDGE_EBT_IP6=m
++CONFIG_BRIDGE_EBT_LIMIT=m
++CONFIG_BRIDGE_EBT_MARK=m
++CONFIG_BRIDGE_EBT_PKTTYPE=m
++CONFIG_BRIDGE_EBT_STP=m
++CONFIG_BRIDGE_EBT_VLAN=m
++CONFIG_BRIDGE_EBT_ARPREPLY=m
++CONFIG_BRIDGE_EBT_DNAT=m
++CONFIG_BRIDGE_EBT_MARK_T=m
++CONFIG_BRIDGE_EBT_REDIRECT=m
++CONFIG_BRIDGE_EBT_SNAT=m
++CONFIG_BRIDGE_EBT_LOG=m
++CONFIG_BRIDGE_EBT_NFLOG=m
++CONFIG_SCTP_COOKIE_HMAC_SHA1=y
++CONFIG_ATM=m
++CONFIG_L2TP=m
++CONFIG_L2TP_V3=y
++CONFIG_L2TP_IP=m
++CONFIG_L2TP_ETH=m
++CONFIG_BRIDGE=m
++CONFIG_VLAN_8021Q=m
++CONFIG_VLAN_8021Q_GVRP=y
++CONFIG_ATALK=m
++CONFIG_6LOWPAN=m
++CONFIG_IEEE802154=m
++CONFIG_IEEE802154_6LOWPAN=m
++CONFIG_MAC802154=m
++CONFIG_NET_SCHED=y
++CONFIG_NET_SCH_CBQ=m
++CONFIG_NET_SCH_HTB=m
++CONFIG_NET_SCH_HFSC=m
++CONFIG_NET_SCH_PRIO=m
++CONFIG_NET_SCH_MULTIQ=m
++CONFIG_NET_SCH_RED=m
++CONFIG_NET_SCH_SFB=m
++CONFIG_NET_SCH_SFQ=m
++CONFIG_NET_SCH_TEQL=m
++CONFIG_NET_SCH_TBF=m
++CONFIG_NET_SCH_GRED=m
++CONFIG_NET_SCH_DSMARK=m
++CONFIG_NET_SCH_NETEM=m
++CONFIG_NET_SCH_DRR=m
++CONFIG_NET_SCH_MQPRIO=m
++CONFIG_NET_SCH_CHOKE=m
++CONFIG_NET_SCH_QFQ=m
++CONFIG_NET_SCH_CODEL=m
++CONFIG_NET_SCH_FQ_CODEL=m
++CONFIG_NET_SCH_INGRESS=m
++CONFIG_NET_SCH_PLUG=m
++CONFIG_NET_CLS_BASIC=m
++CONFIG_NET_CLS_TCINDEX=m
++CONFIG_NET_CLS_ROUTE4=m
++CONFIG_NET_CLS_FW=m
++CONFIG_NET_CLS_U32=m
++CONFIG_CLS_U32_MARK=y
++CONFIG_NET_CLS_RSVP=m
++CONFIG_NET_CLS_RSVP6=m
++CONFIG_NET_CLS_FLOW=m
++CONFIG_NET_CLS_CGROUP=m
++CONFIG_NET_EMATCH=y
++CONFIG_NET_EMATCH_CMP=m
++CONFIG_NET_EMATCH_NBYTE=m
++CONFIG_NET_EMATCH_U32=m
++CONFIG_NET_EMATCH_META=m
++CONFIG_NET_EMATCH_TEXT=m
++CONFIG_NET_EMATCH_IPSET=m
++CONFIG_NET_CLS_ACT=y
++CONFIG_NET_ACT_POLICE=m
++CONFIG_NET_ACT_GACT=m
++CONFIG_GACT_PROB=y
++CONFIG_NET_ACT_MIRRED=m
++CONFIG_NET_ACT_IPT=m
++CONFIG_NET_ACT_NAT=m
++CONFIG_NET_ACT_PEDIT=m
++CONFIG_NET_ACT_SIMP=m
++CONFIG_NET_ACT_SKBEDIT=m
++CONFIG_NET_ACT_CSUM=m
++CONFIG_BATMAN_ADV=m
++CONFIG_OPENVSWITCH=m
++CONFIG_NET_PKTGEN=m
++CONFIG_HAMRADIO=y
++CONFIG_AX25=m
++CONFIG_NETROM=m
++CONFIG_ROSE=m
++CONFIG_MKISS=m
++CONFIG_6PACK=m
++CONFIG_BPQETHER=m
++CONFIG_BAYCOM_SER_FDX=m
++CONFIG_BAYCOM_SER_HDX=m
++CONFIG_YAM=m
++CONFIG_CAN=m
++CONFIG_CAN_VCAN=m
++CONFIG_CAN_MCP251X=m
++CONFIG_IRDA=m
++CONFIG_IRLAN=m
++CONFIG_IRNET=m
++CONFIG_IRCOMM=m
++CONFIG_IRDA_ULTRA=y
++CONFIG_IRDA_CACHE_LAST_LSAP=y
++CONFIG_IRDA_FAST_RR=y
++CONFIG_IRTTY_SIR=m
++CONFIG_KINGSUN_DONGLE=m
++CONFIG_KSDAZZLE_DONGLE=m
++CONFIG_KS959_DONGLE=m
++CONFIG_USB_IRDA=m
++CONFIG_SIGMATEL_FIR=m
++CONFIG_MCS_FIR=m
++CONFIG_BT=m
++CONFIG_BT_RFCOMM=m
++CONFIG_BT_RFCOMM_TTY=y
++CONFIG_BT_BNEP=m
++CONFIG_BT_BNEP_MC_FILTER=y
++CONFIG_BT_BNEP_PROTO_FILTER=y
++CONFIG_BT_HIDP=m
++CONFIG_BT_6LOWPAN=m
++CONFIG_BT_HCIBTUSB=m
++CONFIG_BT_HCIUART=m
++CONFIG_BT_HCIBCM203X=m
++CONFIG_BT_HCIBPA10X=m
++CONFIG_BT_HCIBFUSB=m
++CONFIG_BT_HCIVHCI=m
++CONFIG_BT_MRVL=m
++CONFIG_BT_MRVL_SDIO=m
++CONFIG_BT_ATH3K=m
++CONFIG_BT_WILINK=m
++CONFIG_MAC80211=m
++CONFIG_MAC80211_MESH=y
++CONFIG_WIMAX=m
++CONFIG_RFKILL=m
++CONFIG_RFKILL_INPUT=y
++CONFIG_NET_9P=m
++CONFIG_NFC=m
++CONFIG_NFC_PN533=m
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_DMA_CMA=y
++CONFIG_CMA_SIZE_MBYTES=5
++CONFIG_MTD=m
++CONFIG_MTD_BLOCK=m
++CONFIG_MTD_NAND=m
++CONFIG_MTD_UBI=m
++CONFIG_ZRAM=m
++CONFIG_ZRAM_LZ4_COMPRESS=y
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_CRYPTOLOOP=m
++CONFIG_BLK_DEV_DRBD=m
++CONFIG_BLK_DEV_NBD=m
++CONFIG_BLK_DEV_RAM=y
++CONFIG_CDROM_PKTCDVD=m
++CONFIG_ATA_OVER_ETH=m
++CONFIG_EEPROM_AT24=m
++CONFIG_TI_ST=m
++CONFIG_SCSI=y
++# CONFIG_SCSI_PROC_FS is not set
++CONFIG_BLK_DEV_SD=y
++CONFIG_CHR_DEV_ST=m
++CONFIG_CHR_DEV_OSST=m
++CONFIG_BLK_DEV_SR=m
++CONFIG_CHR_DEV_SG=m
++CONFIG_SCSI_ISCSI_ATTRS=y
++CONFIG_ISCSI_TCP=m
++CONFIG_ISCSI_BOOT_SYSFS=m
++CONFIG_MD=y
++CONFIG_MD_LINEAR=m
++CONFIG_MD_RAID0=m
++CONFIG_BLK_DEV_DM=m
++CONFIG_DM_CRYPT=m
++CONFIG_DM_SNAPSHOT=m
++CONFIG_DM_THIN_PROVISIONING=m
++CONFIG_DM_MIRROR=m
++CONFIG_DM_LOG_USERSPACE=m
++CONFIG_DM_RAID=m
++CONFIG_DM_ZERO=m
++CONFIG_DM_DELAY=m
++CONFIG_NETDEVICES=y
++CONFIG_BONDING=m
++CONFIG_DUMMY=m
++CONFIG_IFB=m
++CONFIG_MACVLAN=m
++CONFIG_NETCONSOLE=m
++CONFIG_TUN=m
++CONFIG_VETH=m
++CONFIG_ENC28J60=m
++CONFIG_MDIO_BITBANG=m
++CONFIG_PPP=m
++CONFIG_PPP_BSDCOMP=m
++CONFIG_PPP_DEFLATE=m
++CONFIG_PPP_FILTER=y
++CONFIG_PPP_MPPE=m
++CONFIG_PPP_MULTILINK=y
++CONFIG_PPPOATM=m
++CONFIG_PPPOE=m
++CONFIG_PPPOL2TP=m
++CONFIG_PPP_ASYNC=m
++CONFIG_PPP_SYNC_TTY=m
++CONFIG_SLIP=m
++CONFIG_SLIP_COMPRESSED=y
++CONFIG_SLIP_SMART=y
++CONFIG_USB_CATC=m
++CONFIG_USB_KAWETH=m
++CONFIG_USB_PEGASUS=m
++CONFIG_USB_RTL8150=m
++CONFIG_USB_RTL8152=m
++CONFIG_USB_USBNET=y
++CONFIG_USB_NET_AX8817X=m
++CONFIG_USB_NET_AX88179_178A=m
++CONFIG_USB_NET_CDCETHER=m
++CONFIG_USB_NET_CDC_EEM=m
++CONFIG_USB_NET_CDC_NCM=m
++CONFIG_USB_NET_HUAWEI_CDC_NCM=m
++CONFIG_USB_NET_CDC_MBIM=m
++CONFIG_USB_NET_DM9601=m
++CONFIG_USB_NET_SR9700=m
++CONFIG_USB_NET_SR9800=m
++CONFIG_USB_NET_SMSC75XX=m
++CONFIG_USB_NET_SMSC95XX=y
++CONFIG_USB_NET_GL620A=m
++CONFIG_USB_NET_NET1080=m
++CONFIG_USB_NET_PLUSB=m
++CONFIG_USB_NET_MCS7830=m
++CONFIG_USB_NET_CDC_SUBSET=m
++CONFIG_USB_ALI_M5632=y
++CONFIG_USB_AN2720=y
++CONFIG_USB_EPSON2888=y
++CONFIG_USB_KC2190=y
++CONFIG_USB_NET_ZAURUS=m
++CONFIG_USB_NET_CX82310_ETH=m
++CONFIG_USB_NET_KALMIA=m
++CONFIG_USB_NET_QMI_WWAN=m
++CONFIG_USB_HSO=m
++CONFIG_USB_NET_INT51X1=m
++CONFIG_USB_IPHETH=m
++CONFIG_USB_SIERRA_NET=m
++CONFIG_USB_VL600=m
++CONFIG_LIBERTAS_THINFIRM=m
++CONFIG_LIBERTAS_THINFIRM_USB=m
++CONFIG_AT76C50X_USB=m
++CONFIG_USB_ZD1201=m
++CONFIG_USB_NET_RNDIS_WLAN=m
++CONFIG_RTL8187=m
++CONFIG_MAC80211_HWSIM=m
++CONFIG_ATH_CARDS=m
++CONFIG_ATH9K=m
++CONFIG_ATH9K_HTC=m
++CONFIG_CARL9170=m
++CONFIG_ATH6KL=m
++CONFIG_ATH6KL_USB=m
++CONFIG_AR5523=m
++CONFIG_B43=m
++# CONFIG_B43_PHY_N is not set
++CONFIG_B43LEGACY=m
++CONFIG_BRCMFMAC=m
++CONFIG_BRCMFMAC_USB=y
++CONFIG_HOSTAP=m
++CONFIG_LIBERTAS=m
++CONFIG_LIBERTAS_USB=m
++CONFIG_LIBERTAS_SDIO=m
++CONFIG_P54_COMMON=m
++CONFIG_P54_USB=m
++CONFIG_RT2X00=m
++CONFIG_RT2500USB=m
++CONFIG_RT73USB=m
++CONFIG_RT2800USB=m
++CONFIG_RT2800USB_RT3573=y
++CONFIG_RT2800USB_RT53XX=y
++CONFIG_RT2800USB_RT55XX=y
++CONFIG_RT2800USB_UNKNOWN=y
++CONFIG_WL_MEDIATEK=y
++CONFIG_MT7601U=m
++CONFIG_RTL8192CU=m
++CONFIG_ZD1211RW=m
++CONFIG_MWIFIEX=m
++CONFIG_MWIFIEX_SDIO=m
++CONFIG_WIMAX_I2400M_USB=m
++CONFIG_IEEE802154_AT86RF230=m
++CONFIG_IEEE802154_MRF24J40=m
++CONFIG_IEEE802154_CC2520=m
++CONFIG_INPUT_POLLDEV=m
++# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
++CONFIG_INPUT_JOYDEV=m
++CONFIG_INPUT_EVDEV=m
++# CONFIG_KEYBOARD_ATKBD is not set
++CONFIG_KEYBOARD_GPIO=m
++# CONFIG_INPUT_MOUSE is not set
++CONFIG_INPUT_JOYSTICK=y
++CONFIG_JOYSTICK_IFORCE=m
++CONFIG_JOYSTICK_IFORCE_USB=y
++CONFIG_JOYSTICK_XPAD=m
++CONFIG_JOYSTICK_XPAD_FF=y
++CONFIG_JOYSTICK_RPISENSE=m
++CONFIG_INPUT_TOUCHSCREEN=y
++CONFIG_TOUCHSCREEN_ADS7846=m
++CONFIG_TOUCHSCREEN_EGALAX=m
++CONFIG_TOUCHSCREEN_FT6236=m
++CONFIG_TOUCHSCREEN_RPI_FT5406=m
++CONFIG_TOUCHSCREEN_USB_COMPOSITE=m
++CONFIG_TOUCHSCREEN_STMPE=m
++CONFIG_INPUT_MISC=y
++CONFIG_INPUT_AD714X=m
++CONFIG_INPUT_ATI_REMOTE2=m
++CONFIG_INPUT_KEYSPAN_REMOTE=m
++CONFIG_INPUT_POWERMATE=m
++CONFIG_INPUT_YEALINK=m
++CONFIG_INPUT_CM109=m
++CONFIG_INPUT_UINPUT=m
++CONFIG_INPUT_GPIO_ROTARY_ENCODER=m
++CONFIG_INPUT_ADXL34X=m
++CONFIG_INPUT_CMA3000=m
++CONFIG_SERIO=m
++CONFIG_SERIO_RAW=m
++CONFIG_GAMEPORT=m
++CONFIG_GAMEPORT_NS558=m
++CONFIG_GAMEPORT_L4=m
++CONFIG_BRCM_CHAR_DRIVERS=y
++CONFIG_BCM_VC_CMA=y
++CONFIG_BCM_VCIO=y
++CONFIG_BCM_VC_SM=y
++CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_DEVKMEM is not set
++CONFIG_SERIAL_8250=y
++# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
++CONFIG_SERIAL_8250_CONSOLE=y
++# CONFIG_SERIAL_8250_DMA is not set
++CONFIG_SERIAL_8250_NR_UARTS=1
++CONFIG_SERIAL_8250_RUNTIME_UARTS=0
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++CONFIG_SERIAL_OF_PLATFORM=y
++CONFIG_TTY_PRINTK=y
++CONFIG_HW_RANDOM=y
++CONFIG_RAW_DRIVER=y
++CONFIG_I2C=y
++CONFIG_I2C_CHARDEV=m
++CONFIG_I2C_BCM2708=m
++CONFIG_SPI=y
++CONFIG_SPI_BCM2835=m
++CONFIG_SPI_SPIDEV=y
++CONFIG_PPS=m
++CONFIG_PPS_CLIENT_LDISC=m
++CONFIG_PPS_CLIENT_GPIO=m
++CONFIG_GPIO_SYSFS=y
++CONFIG_GPIO_ARIZONA=m
++CONFIG_GPIO_STMPE=y
++CONFIG_W1=m
++CONFIG_W1_MASTER_DS2490=m
++CONFIG_W1_MASTER_DS2482=m
++CONFIG_W1_MASTER_DS1WM=m
++CONFIG_W1_MASTER_GPIO=m
++CONFIG_W1_SLAVE_THERM=m
++CONFIG_W1_SLAVE_SMEM=m
++CONFIG_W1_SLAVE_DS2408=m
++CONFIG_W1_SLAVE_DS2413=m
++CONFIG_W1_SLAVE_DS2406=m
++CONFIG_W1_SLAVE_DS2423=m
++CONFIG_W1_SLAVE_DS2431=m
++CONFIG_W1_SLAVE_DS2433=m
++CONFIG_W1_SLAVE_DS2760=m
++CONFIG_W1_SLAVE_DS2780=m
++CONFIG_W1_SLAVE_DS2781=m
++CONFIG_W1_SLAVE_DS28E04=m
++CONFIG_W1_SLAVE_BQ27000=m
++CONFIG_BATTERY_DS2760=m
++CONFIG_POWER_RESET=y
++CONFIG_POWER_RESET_GPIO=y
++CONFIG_HWMON=m
++CONFIG_SENSORS_SHT21=m
++CONFIG_SENSORS_SHTC1=m
++CONFIG_THERMAL=y
++CONFIG_THERMAL_BCM2835=y
++CONFIG_WATCHDOG=y
++CONFIG_BCM2835_WDT=m
++CONFIG_UCB1400_CORE=m
++CONFIG_MFD_STMPE=y
++CONFIG_STMPE_SPI=y
++CONFIG_MFD_ARIZONA_I2C=m
++CONFIG_MFD_ARIZONA_SPI=m
++CONFIG_MFD_WM5102=y
++CONFIG_MEDIA_SUPPORT=m
++CONFIG_MEDIA_CAMERA_SUPPORT=y
++CONFIG_MEDIA_ANALOG_TV_SUPPORT=y
++CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y
++CONFIG_MEDIA_RADIO_SUPPORT=y
++CONFIG_MEDIA_RC_SUPPORT=y
++CONFIG_MEDIA_CONTROLLER=y
++CONFIG_LIRC=m
++CONFIG_RC_DEVICES=y
++CONFIG_RC_ATI_REMOTE=m
++CONFIG_IR_IMON=m
++CONFIG_IR_MCEUSB=m
++CONFIG_IR_REDRAT3=m
++CONFIG_IR_STREAMZAP=m
++CONFIG_IR_IGUANA=m
++CONFIG_IR_TTUSBIR=m
++CONFIG_RC_LOOPBACK=m
++CONFIG_IR_GPIO_CIR=m
++CONFIG_MEDIA_USB_SUPPORT=y
++CONFIG_USB_VIDEO_CLASS=m
++CONFIG_USB_M5602=m
++CONFIG_USB_STV06XX=m
++CONFIG_USB_GL860=m
++CONFIG_USB_GSPCA_BENQ=m
++CONFIG_USB_GSPCA_CONEX=m
++CONFIG_USB_GSPCA_CPIA1=m
++CONFIG_USB_GSPCA_DTCS033=m
++CONFIG_USB_GSPCA_ETOMS=m
++CONFIG_USB_GSPCA_FINEPIX=m
++CONFIG_USB_GSPCA_JEILINJ=m
++CONFIG_USB_GSPCA_JL2005BCD=m
++CONFIG_USB_GSPCA_KINECT=m
++CONFIG_USB_GSPCA_KONICA=m
++CONFIG_USB_GSPCA_MARS=m
++CONFIG_USB_GSPCA_MR97310A=m
++CONFIG_USB_GSPCA_NW80X=m
++CONFIG_USB_GSPCA_OV519=m
++CONFIG_USB_GSPCA_OV534=m
++CONFIG_USB_GSPCA_OV534_9=m
++CONFIG_USB_GSPCA_PAC207=m
++CONFIG_USB_GSPCA_PAC7302=m
++CONFIG_USB_GSPCA_PAC7311=m
++CONFIG_USB_GSPCA_SE401=m
++CONFIG_USB_GSPCA_SN9C2028=m
++CONFIG_USB_GSPCA_SN9C20X=m
++CONFIG_USB_GSPCA_SONIXB=m
++CONFIG_USB_GSPCA_SONIXJ=m
++CONFIG_USB_GSPCA_SPCA500=m
++CONFIG_USB_GSPCA_SPCA501=m
++CONFIG_USB_GSPCA_SPCA505=m
++CONFIG_USB_GSPCA_SPCA506=m
++CONFIG_USB_GSPCA_SPCA508=m
++CONFIG_USB_GSPCA_SPCA561=m
++CONFIG_USB_GSPCA_SPCA1528=m
++CONFIG_USB_GSPCA_SQ905=m
++CONFIG_USB_GSPCA_SQ905C=m
++CONFIG_USB_GSPCA_SQ930X=m
++CONFIG_USB_GSPCA_STK014=m
++CONFIG_USB_GSPCA_STK1135=m
++CONFIG_USB_GSPCA_STV0680=m
++CONFIG_USB_GSPCA_SUNPLUS=m
++CONFIG_USB_GSPCA_T613=m
++CONFIG_USB_GSPCA_TOPRO=m
++CONFIG_USB_GSPCA_TV8532=m
++CONFIG_USB_GSPCA_VC032X=m
++CONFIG_USB_GSPCA_VICAM=m
++CONFIG_USB_GSPCA_XIRLINK_CIT=m
++CONFIG_USB_GSPCA_ZC3XX=m
++CONFIG_USB_PWC=m
++CONFIG_VIDEO_CPIA2=m
++CONFIG_USB_ZR364XX=m
++CONFIG_USB_STKWEBCAM=m
++CONFIG_USB_S2255=m
++CONFIG_VIDEO_USBTV=m
++CONFIG_VIDEO_PVRUSB2=m
++CONFIG_VIDEO_HDPVR=m
++CONFIG_VIDEO_USBVISION=m
++CONFIG_VIDEO_STK1160_COMMON=m
++CONFIG_VIDEO_STK1160_AC97=y
++CONFIG_VIDEO_GO7007=m
++CONFIG_VIDEO_GO7007_USB=m
++CONFIG_VIDEO_GO7007_USB_S2250_BOARD=m
++CONFIG_VIDEO_AU0828=m
++CONFIG_VIDEO_AU0828_RC=y
++CONFIG_VIDEO_CX231XX=m
++CONFIG_VIDEO_CX231XX_ALSA=m
++CONFIG_VIDEO_CX231XX_DVB=m
++CONFIG_VIDEO_TM6000=m
++CONFIG_VIDEO_TM6000_ALSA=m
++CONFIG_VIDEO_TM6000_DVB=m
++CONFIG_DVB_USB=m
++CONFIG_DVB_USB_A800=m
++CONFIG_DVB_USB_DIBUSB_MB=m
++CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y
++CONFIG_DVB_USB_DIBUSB_MC=m
++CONFIG_DVB_USB_DIB0700=m
++CONFIG_DVB_USB_UMT_010=m
++CONFIG_DVB_USB_CXUSB=m
++CONFIG_DVB_USB_M920X=m
++CONFIG_DVB_USB_DIGITV=m
++CONFIG_DVB_USB_VP7045=m
++CONFIG_DVB_USB_VP702X=m
++CONFIG_DVB_USB_GP8PSK=m
++CONFIG_DVB_USB_NOVA_T_USB2=m
++CONFIG_DVB_USB_TTUSB2=m
++CONFIG_DVB_USB_DTT200U=m
++CONFIG_DVB_USB_OPERA1=m
++CONFIG_DVB_USB_AF9005=m
++CONFIG_DVB_USB_AF9005_REMOTE=m
++CONFIG_DVB_USB_PCTV452E=m
++CONFIG_DVB_USB_DW2102=m
++CONFIG_DVB_USB_CINERGY_T2=m
++CONFIG_DVB_USB_DTV5100=m
++CONFIG_DVB_USB_FRIIO=m
++CONFIG_DVB_USB_AZ6027=m
++CONFIG_DVB_USB_TECHNISAT_USB2=m
++CONFIG_DVB_USB_V2=m
++CONFIG_DVB_USB_AF9015=m
++CONFIG_DVB_USB_AF9035=m
++CONFIG_DVB_USB_ANYSEE=m
++CONFIG_DVB_USB_AU6610=m
++CONFIG_DVB_USB_AZ6007=m
++CONFIG_DVB_USB_CE6230=m
++CONFIG_DVB_USB_EC168=m
++CONFIG_DVB_USB_GL861=m
++CONFIG_DVB_USB_LME2510=m
++CONFIG_DVB_USB_MXL111SF=m
++CONFIG_DVB_USB_RTL28XXU=m
++CONFIG_DVB_USB_DVBSKY=m
++CONFIG_SMS_USB_DRV=m
++CONFIG_DVB_B2C2_FLEXCOP_USB=m
++CONFIG_DVB_AS102=m
++CONFIG_VIDEO_EM28XX=m
++CONFIG_VIDEO_EM28XX_V4L2=m
++CONFIG_VIDEO_EM28XX_ALSA=m
++CONFIG_VIDEO_EM28XX_DVB=m
++CONFIG_V4L_PLATFORM_DRIVERS=y
++CONFIG_VIDEO_BCM2835=y
++CONFIG_VIDEO_BCM2835_MMAL=m
++CONFIG_RADIO_SI470X=y
++CONFIG_USB_SI470X=m
++CONFIG_I2C_SI470X=m
++CONFIG_RADIO_SI4713=m
++CONFIG_I2C_SI4713=m
++CONFIG_USB_MR800=m
++CONFIG_USB_DSBR=m
++CONFIG_RADIO_SHARK=m
++CONFIG_RADIO_SHARK2=m
++CONFIG_USB_KEENE=m
++CONFIG_USB_MA901=m
++CONFIG_RADIO_TEA5764=m
++CONFIG_RADIO_SAA7706H=m
++CONFIG_RADIO_TEF6862=m
++CONFIG_RADIO_WL1273=m
++CONFIG_RADIO_WL128X=m
++# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
++CONFIG_VIDEO_UDA1342=m
++CONFIG_VIDEO_SONY_BTF_MPX=m
++CONFIG_VIDEO_TVP5150=m
++CONFIG_VIDEO_TW2804=m
++CONFIG_VIDEO_TW9903=m
++CONFIG_VIDEO_TW9906=m
++CONFIG_VIDEO_OV7640=m
++CONFIG_VIDEO_MT9V011=m
++CONFIG_FB=y
++CONFIG_FB_BCM2708=y
++CONFIG_FB_UDL=m
++CONFIG_FB_SSD1307=m
++CONFIG_FB_RPISENSE=m
++# CONFIG_BACKLIGHT_GENERIC is not set
++CONFIG_BACKLIGHT_GPIO=m
++CONFIG_FRAMEBUFFER_CONSOLE=y
++CONFIG_LOGO=y
++# CONFIG_LOGO_LINUX_MONO is not set
++# CONFIG_LOGO_LINUX_VGA16 is not set
++CONFIG_SOUND=y
++CONFIG_SND=m
++CONFIG_SND_SEQUENCER=m
++CONFIG_SND_SEQ_DUMMY=m
++CONFIG_SND_MIXER_OSS=m
++CONFIG_SND_PCM_OSS=m
++CONFIG_SND_SEQUENCER_OSS=y
++CONFIG_SND_HRTIMER=m
++CONFIG_SND_DUMMY=m
++CONFIG_SND_ALOOP=m
++CONFIG_SND_VIRMIDI=m
++CONFIG_SND_MTPAV=m
++CONFIG_SND_SERIAL_U16550=m
++CONFIG_SND_MPU401=m
++CONFIG_SND_BCM2835=m
++CONFIG_SND_USB_AUDIO=m
++CONFIG_SND_USB_UA101=m
++CONFIG_SND_USB_CAIAQ=m
++CONFIG_SND_USB_CAIAQ_INPUT=y
++CONFIG_SND_USB_6FIRE=m
++CONFIG_SND_SOC=m
++CONFIG_SND_BCM2835_SOC_I2S=m
++CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC=m
++CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS=m
++CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI=m
++CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP=m
++CONFIG_SND_BCM2708_SOC_RPI_DAC=m
++CONFIG_SND_BCM2708_SOC_RPI_PROTO=m
++CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m
++CONFIG_SND_BCM2708_SOC_RASPIDAC3=m
++CONFIG_SND_SOC_ADAU1701=m
++CONFIG_SND_SOC_WM8804_I2C=m
++CONFIG_SND_SIMPLE_CARD=m
++CONFIG_SOUND_PRIME=m
++CONFIG_HIDRAW=y
++CONFIG_UHID=m
++CONFIG_HID_A4TECH=m
++CONFIG_HID_ACRUX=m
++CONFIG_HID_APPLE=m
++CONFIG_HID_BELKIN=m
++CONFIG_HID_CHERRY=m
++CONFIG_HID_CHICONY=m
++CONFIG_HID_CYPRESS=m
++CONFIG_HID_DRAGONRISE=m
++CONFIG_HID_EMS_FF=m
++CONFIG_HID_ELECOM=m
++CONFIG_HID_ELO=m
++CONFIG_HID_EZKEY=m
++CONFIG_HID_HOLTEK=m
++CONFIG_HID_KEYTOUCH=m
++CONFIG_HID_KYE=m
++CONFIG_HID_UCLOGIC=m
++CONFIG_HID_WALTOP=m
++CONFIG_HID_GYRATION=m
++CONFIG_HID_TWINHAN=m
++CONFIG_HID_KENSINGTON=m
++CONFIG_HID_LCPOWER=m
++CONFIG_HID_LOGITECH=m
++CONFIG_HID_MAGICMOUSE=m
++CONFIG_HID_MICROSOFT=m
++CONFIG_HID_MONTEREY=m
++CONFIG_HID_MULTITOUCH=m
++CONFIG_HID_NTRIG=m
++CONFIG_HID_ORTEK=m
++CONFIG_HID_PANTHERLORD=m
++CONFIG_HID_PETALYNX=m
++CONFIG_HID_PICOLCD=m
++CONFIG_HID_ROCCAT=m
++CONFIG_HID_SAMSUNG=m
++CONFIG_HID_SONY=m
++CONFIG_HID_SPEEDLINK=m
++CONFIG_HID_SUNPLUS=m
++CONFIG_HID_GREENASIA=m
++CONFIG_HID_SMARTJOYPLUS=m
++CONFIG_HID_TOPSEED=m
++CONFIG_HID_THINGM=m
++CONFIG_HID_THRUSTMASTER=m
++CONFIG_HID_WACOM=m
++CONFIG_HID_WIIMOTE=m
++CONFIG_HID_XINMO=m
++CONFIG_HID_ZEROPLUS=m
++CONFIG_HID_ZYDACRON=m
++CONFIG_HID_PID=y
++CONFIG_USB_HIDDEV=y
++CONFIG_USB=y
++CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
++CONFIG_USB_MON=m
++CONFIG_USB_DWCOTG=y
++CONFIG_USB_PRINTER=m
++CONFIG_USB_STORAGE=y
++CONFIG_USB_STORAGE_REALTEK=m
++CONFIG_USB_STORAGE_DATAFAB=m
++CONFIG_USB_STORAGE_FREECOM=m
++CONFIG_USB_STORAGE_ISD200=m
++CONFIG_USB_STORAGE_USBAT=m
++CONFIG_USB_STORAGE_SDDR09=m
++CONFIG_USB_STORAGE_SDDR55=m
++CONFIG_USB_STORAGE_JUMPSHOT=m
++CONFIG_USB_STORAGE_ALAUDA=m
++CONFIG_USB_STORAGE_ONETOUCH=m
++CONFIG_USB_STORAGE_KARMA=m
++CONFIG_USB_STORAGE_CYPRESS_ATACB=m
++CONFIG_USB_STORAGE_ENE_UB6250=m
++CONFIG_USB_MDC800=m
++CONFIG_USB_MICROTEK=m
++CONFIG_USBIP_CORE=m
++CONFIG_USBIP_VHCI_HCD=m
++CONFIG_USBIP_HOST=m
++CONFIG_USB_DWC2=m
++CONFIG_USB_SERIAL=m
++CONFIG_USB_SERIAL_GENERIC=y
++CONFIG_USB_SERIAL_AIRCABLE=m
++CONFIG_USB_SERIAL_ARK3116=m
++CONFIG_USB_SERIAL_BELKIN=m
++CONFIG_USB_SERIAL_CH341=m
++CONFIG_USB_SERIAL_WHITEHEAT=m
++CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
++CONFIG_USB_SERIAL_CP210X=m
++CONFIG_USB_SERIAL_CYPRESS_M8=m
++CONFIG_USB_SERIAL_EMPEG=m
++CONFIG_USB_SERIAL_FTDI_SIO=m
++CONFIG_USB_SERIAL_VISOR=m
++CONFIG_USB_SERIAL_IPAQ=m
++CONFIG_USB_SERIAL_IR=m
++CONFIG_USB_SERIAL_EDGEPORT=m
++CONFIG_USB_SERIAL_EDGEPORT_TI=m
++CONFIG_USB_SERIAL_F81232=m
++CONFIG_USB_SERIAL_GARMIN=m
++CONFIG_USB_SERIAL_IPW=m
++CONFIG_USB_SERIAL_IUU=m
++CONFIG_USB_SERIAL_KEYSPAN_PDA=m
++CONFIG_USB_SERIAL_KEYSPAN=m
++CONFIG_USB_SERIAL_KLSI=m
++CONFIG_USB_SERIAL_KOBIL_SCT=m
++CONFIG_USB_SERIAL_MCT_U232=m
++CONFIG_USB_SERIAL_METRO=m
++CONFIG_USB_SERIAL_MOS7720=m
++CONFIG_USB_SERIAL_MOS7840=m
++CONFIG_USB_SERIAL_NAVMAN=m
++CONFIG_USB_SERIAL_PL2303=m
++CONFIG_USB_SERIAL_OTI6858=m
++CONFIG_USB_SERIAL_QCAUX=m
++CONFIG_USB_SERIAL_QUALCOMM=m
++CONFIG_USB_SERIAL_SPCP8X5=m
++CONFIG_USB_SERIAL_SAFE=m
++CONFIG_USB_SERIAL_SIERRAWIRELESS=m
++CONFIG_USB_SERIAL_SYMBOL=m
++CONFIG_USB_SERIAL_TI=m
++CONFIG_USB_SERIAL_CYBERJACK=m
++CONFIG_USB_SERIAL_XIRCOM=m
++CONFIG_USB_SERIAL_OPTION=m
++CONFIG_USB_SERIAL_OMNINET=m
++CONFIG_USB_SERIAL_OPTICON=m
++CONFIG_USB_SERIAL_XSENS_MT=m
++CONFIG_USB_SERIAL_WISHBONE=m
++CONFIG_USB_SERIAL_SSU100=m
++CONFIG_USB_SERIAL_QT2=m
++CONFIG_USB_SERIAL_DEBUG=m
++CONFIG_USB_EMI62=m
++CONFIG_USB_EMI26=m
++CONFIG_USB_ADUTUX=m
++CONFIG_USB_SEVSEG=m
++CONFIG_USB_RIO500=m
++CONFIG_USB_LEGOTOWER=m
++CONFIG_USB_LCD=m
++CONFIG_USB_LED=m
++CONFIG_USB_CYPRESS_CY7C63=m
++CONFIG_USB_CYTHERM=m
++CONFIG_USB_IDMOUSE=m
++CONFIG_USB_FTDI_ELAN=m
++CONFIG_USB_APPLEDISPLAY=m
++CONFIG_USB_LD=m
++CONFIG_USB_TRANCEVIBRATOR=m
++CONFIG_USB_IOWARRIOR=m
++CONFIG_USB_TEST=m
++CONFIG_USB_ISIGHTFW=m
++CONFIG_USB_YUREX=m
++CONFIG_USB_ATM=m
++CONFIG_USB_SPEEDTOUCH=m
++CONFIG_USB_CXACRU=m
++CONFIG_USB_UEAGLEATM=m
++CONFIG_USB_XUSBATM=m
++CONFIG_USB_GADGET=m
++CONFIG_USB_ZERO=m
++CONFIG_USB_AUDIO=m
++CONFIG_USB_ETH=m
++CONFIG_USB_GADGETFS=m
++CONFIG_USB_MASS_STORAGE=m
++CONFIG_USB_G_SERIAL=m
++CONFIG_USB_MIDI_GADGET=m
++CONFIG_USB_G_PRINTER=m
++CONFIG_USB_CDC_COMPOSITE=m
++CONFIG_USB_G_ACM_MS=m
++CONFIG_USB_G_MULTI=m
++CONFIG_USB_G_HID=m
++CONFIG_USB_G_WEBCAM=m
++CONFIG_MMC=y
++CONFIG_MMC_BLOCK_MINORS=32
++CONFIG_MMC_BCM2835=y
++CONFIG_MMC_BCM2835_DMA=y
++CONFIG_MMC_BCM2835_SDHOST=y
++CONFIG_MMC_SDHCI=y
++CONFIG_MMC_SDHCI_PLTFM=y
++CONFIG_MMC_SPI=m
++CONFIG_LEDS_CLASS=y
++CONFIG_LEDS_GPIO=y
++CONFIG_LEDS_TRIGGER_TIMER=y
++CONFIG_LEDS_TRIGGER_ONESHOT=y
++CONFIG_LEDS_TRIGGER_HEARTBEAT=y
++CONFIG_LEDS_TRIGGER_BACKLIGHT=y
++CONFIG_LEDS_TRIGGER_CPU=y
++CONFIG_LEDS_TRIGGER_GPIO=y
++CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
++CONFIG_LEDS_TRIGGER_TRANSIENT=m
++CONFIG_LEDS_TRIGGER_CAMERA=m
++CONFIG_LEDS_TRIGGER_INPUT=y
++CONFIG_RTC_CLASS=y
++# CONFIG_RTC_HCTOSYS is not set
++CONFIG_RTC_DRV_DS1307=m
++CONFIG_RTC_DRV_DS1374=m
++CONFIG_RTC_DRV_DS1672=m
++CONFIG_RTC_DRV_DS3232=m
++CONFIG_RTC_DRV_MAX6900=m
++CONFIG_RTC_DRV_RS5C372=m
++CONFIG_RTC_DRV_ISL1208=m
++CONFIG_RTC_DRV_ISL12022=m
++CONFIG_RTC_DRV_ISL12057=m
++CONFIG_RTC_DRV_X1205=m
++CONFIG_RTC_DRV_PCF2127=m
++CONFIG_RTC_DRV_PCF8523=m
++CONFIG_RTC_DRV_PCF8563=m
++CONFIG_RTC_DRV_PCF8583=m
++CONFIG_RTC_DRV_M41T80=m
++CONFIG_RTC_DRV_BQ32K=m
++CONFIG_RTC_DRV_S35390A=m
++CONFIG_RTC_DRV_FM3130=m
++CONFIG_RTC_DRV_RX8581=m
++CONFIG_RTC_DRV_RX8025=m
++CONFIG_RTC_DRV_EM3027=m
++CONFIG_RTC_DRV_RV3029C2=m
++CONFIG_RTC_DRV_M41T93=m
++CONFIG_RTC_DRV_M41T94=m
++CONFIG_RTC_DRV_DS1305=m
++CONFIG_RTC_DRV_DS1390=m
++CONFIG_RTC_DRV_MAX6902=m
++CONFIG_RTC_DRV_R9701=m
++CONFIG_RTC_DRV_RS5C348=m
++CONFIG_RTC_DRV_DS3234=m
++CONFIG_RTC_DRV_PCF2123=m
++CONFIG_RTC_DRV_RX4581=m
++CONFIG_DMADEVICES=y
++CONFIG_DMA_BCM2835=y
++CONFIG_DMA_BCM2708=y
++CONFIG_UIO=m
++CONFIG_UIO_PDRV_GENIRQ=m
++CONFIG_STAGING=y
++CONFIG_PRISM2_USB=m
++CONFIG_R8712U=m
++CONFIG_R8188EU=m
++CONFIG_R8723AU=m
++CONFIG_VT6656=m
++CONFIG_SPEAKUP=m
++CONFIG_SPEAKUP_SYNTH_SOFT=m
++CONFIG_STAGING_MEDIA=y
++CONFIG_LIRC_STAGING=y
++CONFIG_LIRC_IMON=m
++CONFIG_LIRC_RPI=m
++CONFIG_LIRC_SASEM=m
++CONFIG_LIRC_SERIAL=m
++CONFIG_FB_TFT=m
++CONFIG_FB_TFT_AGM1264K_FL=m
++CONFIG_FB_TFT_BD663474=m
++CONFIG_FB_TFT_HX8340BN=m
++CONFIG_FB_TFT_HX8347D=m
++CONFIG_FB_TFT_HX8353D=m
++CONFIG_FB_TFT_ILI9163=m
++CONFIG_FB_TFT_ILI9320=m
++CONFIG_FB_TFT_ILI9325=m
++CONFIG_FB_TFT_ILI9340=m
++CONFIG_FB_TFT_ILI9341=m
++CONFIG_FB_TFT_ILI9481=m
++CONFIG_FB_TFT_ILI9486=m
++CONFIG_FB_TFT_PCD8544=m
++CONFIG_FB_TFT_RA8875=m
++CONFIG_FB_TFT_S6D02A1=m
++CONFIG_FB_TFT_S6D1121=m
++CONFIG_FB_TFT_SSD1289=m
++CONFIG_FB_TFT_SSD1306=m
++CONFIG_FB_TFT_SSD1331=m
++CONFIG_FB_TFT_SSD1351=m
++CONFIG_FB_TFT_ST7735R=m
++CONFIG_FB_TFT_TINYLCD=m
++CONFIG_FB_TFT_TLS8204=m
++CONFIG_FB_TFT_UC1701=m
++CONFIG_FB_TFT_UPD161704=m
++CONFIG_FB_TFT_WATTEROTT=m
++CONFIG_FB_FLEX=m
++CONFIG_FB_TFT_FBTFT_DEVICE=m
++CONFIG_MAILBOX=y
++CONFIG_BCM2835_MBOX=y
++# CONFIG_IOMMU_SUPPORT is not set
++CONFIG_EXTCON=m
++CONFIG_EXTCON_ARIZONA=m
++CONFIG_IIO=m
++CONFIG_IIO_BUFFER=y
++CONFIG_IIO_BUFFER_CB=m
++CONFIG_IIO_KFIFO_BUF=m
++CONFIG_MCP320X=m
++CONFIG_DHT11=m
++CONFIG_PWM_BCM2835=m
++CONFIG_RASPBERRYPI_FIRMWARE=y
++CONFIG_EXT4_FS=y
++CONFIG_EXT4_FS_POSIX_ACL=y
++CONFIG_EXT4_FS_SECURITY=y
++CONFIG_REISERFS_FS=m
++CONFIG_REISERFS_FS_XATTR=y
++CONFIG_REISERFS_FS_POSIX_ACL=y
++CONFIG_REISERFS_FS_SECURITY=y
++CONFIG_JFS_FS=m
++CONFIG_JFS_POSIX_ACL=y
++CONFIG_JFS_SECURITY=y
++CONFIG_JFS_STATISTICS=y
++CONFIG_XFS_FS=m
++CONFIG_XFS_QUOTA=y
++CONFIG_XFS_POSIX_ACL=y
++CONFIG_XFS_RT=y
++CONFIG_GFS2_FS=m
++CONFIG_OCFS2_FS=m
++CONFIG_BTRFS_FS=m
++CONFIG_BTRFS_FS_POSIX_ACL=y
++CONFIG_NILFS2_FS=m
++CONFIG_F2FS_FS=y
++CONFIG_FANOTIFY=y
++CONFIG_QFMT_V1=m
++CONFIG_QFMT_V2=m
++CONFIG_AUTOFS4_FS=y
++CONFIG_FUSE_FS=m
++CONFIG_CUSE=m
++CONFIG_OVERLAY_FS=m
++CONFIG_FSCACHE=y
++CONFIG_FSCACHE_STATS=y
++CONFIG_FSCACHE_HISTOGRAM=y
++CONFIG_CACHEFILES=y
++CONFIG_ISO9660_FS=m
++CONFIG_JOLIET=y
++CONFIG_ZISOFS=y
++CONFIG_UDF_FS=m
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
++CONFIG_NTFS_FS=m
++CONFIG_NTFS_RW=y
++CONFIG_TMPFS=y
++CONFIG_TMPFS_POSIX_ACL=y
++CONFIG_CONFIGFS_FS=y
++CONFIG_ECRYPT_FS=m
++CONFIG_HFS_FS=m
++CONFIG_HFSPLUS_FS=m
++CONFIG_JFFS2_FS=m
++CONFIG_JFFS2_SUMMARY=y
++CONFIG_UBIFS_FS=m
++CONFIG_SQUASHFS=m
++CONFIG_SQUASHFS_XATTR=y
++CONFIG_SQUASHFS_LZO=y
++CONFIG_SQUASHFS_XZ=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3_ACL=y
++CONFIG_NFS_V4=y
++CONFIG_NFS_SWAP=y
++CONFIG_ROOT_NFS=y
++CONFIG_NFS_FSCACHE=y
++CONFIG_NFSD=m
++CONFIG_NFSD_V3_ACL=y
++CONFIG_NFSD_V4=y
++CONFIG_CIFS=m
++CONFIG_CIFS_WEAK_PW_HASH=y
++CONFIG_CIFS_UPCALL=y
++CONFIG_CIFS_XATTR=y
++CONFIG_CIFS_POSIX=y
++CONFIG_CIFS_ACL=y
++CONFIG_CIFS_DFS_UPCALL=y
++CONFIG_CIFS_SMB2=y
++CONFIG_CIFS_FSCACHE=y
++CONFIG_9P_FS=m
++CONFIG_9P_FS_POSIX_ACL=y
++CONFIG_NLS_DEFAULT="utf8"
++CONFIG_NLS_CODEPAGE_437=y
++CONFIG_NLS_CODEPAGE_737=m
++CONFIG_NLS_CODEPAGE_775=m
++CONFIG_NLS_CODEPAGE_850=m
++CONFIG_NLS_CODEPAGE_852=m
++CONFIG_NLS_CODEPAGE_855=m
++CONFIG_NLS_CODEPAGE_857=m
++CONFIG_NLS_CODEPAGE_860=m
++CONFIG_NLS_CODEPAGE_861=m
++CONFIG_NLS_CODEPAGE_862=m
++CONFIG_NLS_CODEPAGE_863=m
++CONFIG_NLS_CODEPAGE_864=m
++CONFIG_NLS_CODEPAGE_865=m
++CONFIG_NLS_CODEPAGE_866=m
++CONFIG_NLS_CODEPAGE_869=m
++CONFIG_NLS_CODEPAGE_936=m
++CONFIG_NLS_CODEPAGE_950=m
++CONFIG_NLS_CODEPAGE_932=m
++CONFIG_NLS_CODEPAGE_949=m
++CONFIG_NLS_CODEPAGE_874=m
++CONFIG_NLS_ISO8859_8=m
++CONFIG_NLS_CODEPAGE_1250=m
++CONFIG_NLS_CODEPAGE_1251=m
++CONFIG_NLS_ASCII=y
++CONFIG_NLS_ISO8859_1=m
++CONFIG_NLS_ISO8859_2=m
++CONFIG_NLS_ISO8859_3=m
++CONFIG_NLS_ISO8859_4=m
++CONFIG_NLS_ISO8859_5=m
++CONFIG_NLS_ISO8859_6=m
++CONFIG_NLS_ISO8859_7=m
++CONFIG_NLS_ISO8859_9=m
++CONFIG_NLS_ISO8859_13=m
++CONFIG_NLS_ISO8859_14=m
++CONFIG_NLS_ISO8859_15=m
++CONFIG_NLS_KOI8_R=m
++CONFIG_NLS_KOI8_U=m
++CONFIG_DLM=m
++CONFIG_PRINTK_TIME=y
++CONFIG_BOOT_PRINTK_DELAY=y
++CONFIG_DEBUG_MEMORY_INIT=y
++CONFIG_DETECT_HUNG_TASK=y
++CONFIG_TIMER_STATS=y
++CONFIG_LATENCYTOP=y
++CONFIG_IRQSOFF_TRACER=y
++CONFIG_SCHED_TRACER=y
++CONFIG_STACK_TRACER=y
++CONFIG_BLK_DEV_IO_TRACE=y
++# CONFIG_KPROBE_EVENT is not set
++CONFIG_FUNCTION_PROFILER=y
++CONFIG_KGDB=y
++CONFIG_KGDB_KDB=y
++CONFIG_KDB_KEYBOARD=y
++CONFIG_CRYPTO_USER=m
++CONFIG_CRYPTO_CRYPTD=m
++CONFIG_CRYPTO_CBC=y
++CONFIG_CRYPTO_CTS=m
++CONFIG_CRYPTO_XTS=m
++CONFIG_CRYPTO_XCBC=m
++CONFIG_CRYPTO_SHA512=m
++CONFIG_CRYPTO_TGR192=m
++CONFIG_CRYPTO_WP512=m
++CONFIG_CRYPTO_CAST5=m
++CONFIG_CRYPTO_DES=y
++CONFIG_CRYPTO_USER_API_SKCIPHER=m
++# CONFIG_CRYPTO_HW is not set
++CONFIG_ARM_CRYPTO=y
++CONFIG_CRYPTO_SHA1_ARM=m
++CONFIG_CRYPTO_AES_ARM=m
++CONFIG_CRC_ITU_T=y
++CONFIG_LIBCRC32C=y
diff --git a/target/linux/brcm2708/patches-4.4/0077-bcm2835-bcm2835_defconfig.patch b/target/linux/brcm2708/patches-4.4/0077-bcm2835-bcm2835_defconfig.patch
new file mode 100644
index 0000000000..e2c1cc6eee
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0077-bcm2835-bcm2835_defconfig.patch
@@ -0,0 +1,1426 @@
+From d9d77573d48f99b3cc7f760ce4febaf23cfc13e1 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
+Date: Wed, 29 Apr 2015 17:24:02 +0200
+Subject: [PATCH 077/381] bcm2835: bcm2835_defconfig
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Some options in bcm2835_defconfig are now the default and
+some have changed. Update to keep functionality.
+
+No longer available: SCSI_MULTI_LUN and RESOURCE_COUNTERS.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+
+bcm2835: bcm2835_defconfig enable MMC_BCM2835
+
+Enable the downstream bcm2835-mmc driver and DMA support.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+
+bcm2835: bcm2835_defconfig enable BCM2708_MBOX
+
+Enable the mailbox driver.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+
+bcm2835: bcm2835_defconfig use FB_BCM2708
+
+Enable the bcm2708 framebuffer driver.
+Disable the simple framebuffer driver, which matches the
+device handed over by u-boot.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+
+bcm2835: Merge bcm2835_defconfig with bcmrpi_defconfig
+
+These commands where used to make this commit:
+
+./scripts/diffconfig -m arch/arm/configs/bcm2835_defconfig arch/arm/configs/bcmrpi_defconfig > merge.cfg
+
+cat << EOF > filter
+CONFIG_ARCH_BCM2708
+CONFIG_BCM2708_DT
+CONFIG_ARM_PATCH_PHYS_VIRT
+CONFIG_PHYS_OFFSET
+CONFIG_CMDLINE
+CONFIG_BCM2708_WDT
+CONFIG_HW_RANDOM_BCM2708
+CONFIG_I2C_BCM2708
+CONFIG_SPI_BCM2708
+CONFIG_SND_BCM2708_SOC_I2S
+CONFIG_USB_DWCOTG
+CONFIG_LIRC_RPI
+EOF
+
+grep -F -v -f filter merge.cfg > filtered.cfg
+
+cat << EOF > added.cfg
+CONFIG_WATCHDOG=y
+CONFIG_BCM2835_WDT=y
+CONFIG_MISC_FILESYSTEMS=y
+CONFIG_SND_BCM2835_SOC_I2S=m
+EOF
+
+ARCH=arm scripts/kconfig/merge_config.sh arch/arm/configs/bcm2835_defconfig filtered.cfg added.cfg
+ARCH=arm make oldconfig
+
+ARCH=arm make savedefconfig
+cp defconfig arch/arm/configs/bcm2835_defconfig
+
+rm merge.cfg filter filtered.cfg added.cfg defconfig
+
+ARCH=arm make bcm2835_defconfig
+ARCH=arm make oldconfig
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+
+configs: Incorporate v4.1 dependency changes
+
+Commit 78e9b7de78bb53e8bc7f4c4a60ebacb250c0c190 added a
+dependency on TI_ST instead of selecting it, disabling:
+CONFIG_BT_WILINK=m
+CONFIG_RADIO_WL128X=m
+
+Commit 652ccae5cc4e1305fb0a4619947f9ee89d8c7f5a added a
+depency on ARM_CRYPTO, disabling:
+CONFIG_CRYPTO_SHA*_ARM*=m
+CONFIG_CRYPTO_AES_ARM*=m
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+
+Conflicts:
+ arch/arm/configs/bcm2709_defconfig
+
+bcm2835: Sync bcm2835_defconfig with bcmrpi_defconfig
+
+These commands where used to make this commit:
+
+: Get changed and new config values from a merge
+./scripts/diffconfig -m arch/arm/configs/bcm2835_defconfig arch/arm/configs/bcmrpi_defconfig > merge.cfg
+
+: Remove these options
+cat << EOF > filter
+CONFIG_ARCH_BCM2708
+CONFIG_BCM2708_DT
+CONFIG_ARM_PATCH_PHYS_VIRT
+CONFIG_PHYS_OFFSET
+CONFIG_CMDLINE
+CONFIG_BCM2708_WDT
+CONFIG_HW_RANDOM_BCM2708
+CONFIG_SPI_BCM2708
+EOF
+
+: Apply filter
+grep -F -v -f filter merge.cfg > filtered.cfg
+
+: Add these options
+: watchdog contains the restart/poweroff code.
+cat << EOF > added.cfg
+CONFIG_WATCHDOG=y
+CONFIG_BCM2835_WDT=y
+CONFIG_MISC_FILESYSTEMS=y
+CONFIG_I2C_BCM2835=m
+CONFIG_SND_BCM2835_SOC_I2S=m
+EOF
+
+: Create new config
+ARCH=arm scripts/kconfig/merge_config.sh arch/arm/configs/bcm2835_defconfig filtered.cfg added.cfg
+: Verify
+ARCH=arm make oldconfig
+
+: Update bcm2835_defconfig
+ARCH=arm make savedefconfig
+cp defconfig arch/arm/configs/bcm2835_defconfig
+
+: Clean up
+rm merge.cfg filter filtered.cfg added.cfg defconfig
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+---
+ arch/arm/configs/bcm2835_defconfig | 1166 +++++++++++++++++++++++++++++++++++-
+ 1 file changed, 1140 insertions(+), 26 deletions(-)
+
+--- a/arch/arm/configs/bcm2835_defconfig
++++ b/arch/arm/configs/bcm2835_defconfig
+@@ -1,105 +1,1103 @@
+ # CONFIG_LOCALVERSION_AUTO is not set
+ CONFIG_SYSVIPC=y
++CONFIG_POSIX_MQUEUE=y
+ CONFIG_FHANDLE=y
+ CONFIG_NO_HZ=y
+ CONFIG_HIGH_RES_TIMERS=y
+ CONFIG_BSD_PROCESS_ACCT=y
+ CONFIG_BSD_PROCESS_ACCT_V3=y
++CONFIG_TASKSTATS=y
++CONFIG_TASK_DELAY_ACCT=y
++CONFIG_TASK_XACCT=y
++CONFIG_TASK_IO_ACCOUNTING=y
++CONFIG_IKCONFIG=m
++CONFIG_IKCONFIG_PROC=y
+ CONFIG_LOG_BUF_SHIFT=18
+ CONFIG_CGROUP_FREEZER=y
+ CONFIG_CGROUP_DEVICE=y
+ CONFIG_CPUSETS=y
+ CONFIG_CGROUP_CPUACCT=y
+-CONFIG_RESOURCE_COUNTERS=y
++CONFIG_MEMCG=y
+ CONFIG_CGROUP_PERF=y
+ CONFIG_CFS_BANDWIDTH=y
+ CONFIG_RT_GROUP_SCHED=y
++CONFIG_BLK_CGROUP=y
+ CONFIG_NAMESPACES=y
+ CONFIG_SCHED_AUTOGROUP=y
+-CONFIG_RELAY=y
+ CONFIG_BLK_DEV_INITRD=y
+-CONFIG_RD_BZIP2=y
+-CONFIG_RD_LZMA=y
+-CONFIG_RD_XZ=y
+-CONFIG_RD_LZO=y
+ CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+-CONFIG_KALLSYMS_ALL=y
+ CONFIG_EMBEDDED=y
+ # CONFIG_COMPAT_BRK is not set
+ CONFIG_PROFILING=y
+-CONFIG_OPROFILE=y
++CONFIG_OPROFILE=m
++CONFIG_KPROBES=y
+ CONFIG_JUMP_LABEL=y
++CONFIG_CC_STACKPROTECTOR_REGULAR=y
++CONFIG_MODULES=y
++CONFIG_MODULE_UNLOAD=y
++CONFIG_MODVERSIONS=y
++CONFIG_MODULE_SRCVERSION_ALL=y
++CONFIG_BLK_DEV_THROTTLING=y
++CONFIG_PARTITION_ADVANCED=y
++CONFIG_MAC_PARTITION=y
++CONFIG_CFQ_GROUP_IOSCHED=y
+ CONFIG_ARCH_MULTI_V6=y
+ # CONFIG_ARCH_MULTI_V7 is not set
+ CONFIG_ARCH_BCM=y
+ CONFIG_ARCH_BCM2835=y
+-CONFIG_PREEMPT_VOLUNTARY=y
++CONFIG_PREEMPT=y
+ CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
+ CONFIG_KSM=y
+ CONFIG_CLEANCACHE=y
++CONFIG_FRONTSWAP=y
++CONFIG_CMA=y
++CONFIG_ZSMALLOC=m
++CONFIG_PGTABLE_MAPPING=y
++CONFIG_UACCESS_WITH_MEMCPY=y
+ CONFIG_SECCOMP=y
+-CONFIG_CC_STACKPROTECTOR=y
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
+ CONFIG_KEXEC=y
+ CONFIG_CRASH_DUMP=y
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_STAT=m
++CONFIG_CPU_FREQ_STAT_DETAILS=y
++CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE=y
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
++CONFIG_CPU_FREQ_GOV_ONDEMAND=y
++CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+ CONFIG_VFP=y
+ # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_BINFMT_MISC=m
+ # CONFIG_SUSPEND is not set
+ CONFIG_NET=y
+ CONFIG_PACKET=y
+ CONFIG_UNIX=y
++CONFIG_XFRM_USER=y
++CONFIG_NET_KEY=m
+ CONFIG_INET=y
++CONFIG_IP_MULTICAST=y
++CONFIG_IP_ADVANCED_ROUTER=y
++CONFIG_IP_MULTIPLE_TABLES=y
++CONFIG_IP_ROUTE_MULTIPATH=y
++CONFIG_IP_ROUTE_VERBOSE=y
++CONFIG_IP_PNP=y
++CONFIG_IP_PNP_DHCP=y
++CONFIG_IP_PNP_RARP=y
++CONFIG_NET_IPIP=m
++CONFIG_NET_IPGRE_DEMUX=m
++CONFIG_NET_IPGRE=m
++CONFIG_IP_MROUTE=y
++CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
++CONFIG_IP_PIMSM_V1=y
++CONFIG_IP_PIMSM_V2=y
++CONFIG_SYN_COOKIES=y
++CONFIG_INET_AH=m
++CONFIG_INET_ESP=m
++CONFIG_INET_IPCOMP=m
++CONFIG_INET_XFRM_MODE_TRANSPORT=m
++CONFIG_INET_XFRM_MODE_TUNNEL=m
++CONFIG_INET_XFRM_MODE_BEET=m
++CONFIG_INET_LRO=m
++CONFIG_INET_DIAG=m
++CONFIG_INET6_AH=m
++CONFIG_INET6_ESP=m
++CONFIG_INET6_IPCOMP=m
++CONFIG_IPV6_TUNNEL=m
++CONFIG_IPV6_MULTIPLE_TABLES=y
++CONFIG_IPV6_MROUTE=y
++CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
++CONFIG_IPV6_PIMSM_V2=y
+ CONFIG_NETWORK_SECMARK=y
+ CONFIG_NETFILTER=y
+-CONFIG_CFG80211=y
+-CONFIG_MAC80211=y
++CONFIG_NF_CONNTRACK=m
++CONFIG_NF_CONNTRACK_ZONES=y
++CONFIG_NF_CONNTRACK_EVENTS=y
++CONFIG_NF_CONNTRACK_TIMESTAMP=y
++CONFIG_NF_CT_PROTO_DCCP=m
++CONFIG_NF_CT_PROTO_UDPLITE=m
++CONFIG_NF_CONNTRACK_AMANDA=m
++CONFIG_NF_CONNTRACK_FTP=m
++CONFIG_NF_CONNTRACK_H323=m
++CONFIG_NF_CONNTRACK_IRC=m
++CONFIG_NF_CONNTRACK_NETBIOS_NS=m
++CONFIG_NF_CONNTRACK_SNMP=m
++CONFIG_NF_CONNTRACK_PPTP=m
++CONFIG_NF_CONNTRACK_SANE=m
++CONFIG_NF_CONNTRACK_SIP=m
++CONFIG_NF_CONNTRACK_TFTP=m
++CONFIG_NF_CT_NETLINK=m
++CONFIG_NETFILTER_XT_SET=m
++CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
++CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
++CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
++CONFIG_NETFILTER_XT_TARGET_DSCP=m
++CONFIG_NETFILTER_XT_TARGET_HMARK=m
++CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
++CONFIG_NETFILTER_XT_TARGET_LED=m
++CONFIG_NETFILTER_XT_TARGET_LOG=m
++CONFIG_NETFILTER_XT_TARGET_MARK=m
++CONFIG_NETFILTER_XT_TARGET_NFLOG=m
++CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
++CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
++CONFIG_NETFILTER_XT_TARGET_TEE=m
++CONFIG_NETFILTER_XT_TARGET_TPROXY=m
++CONFIG_NETFILTER_XT_TARGET_TRACE=m
++CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
++CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
++CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m
++CONFIG_NETFILTER_XT_MATCH_BPF=m
++CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
++CONFIG_NETFILTER_XT_MATCH_COMMENT=m
++CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
++CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m
++CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
++CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
++CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
++CONFIG_NETFILTER_XT_MATCH_CPU=m
++CONFIG_NETFILTER_XT_MATCH_DCCP=m
++CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m
++CONFIG_NETFILTER_XT_MATCH_DSCP=m
++CONFIG_NETFILTER_XT_MATCH_ESP=m
++CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
++CONFIG_NETFILTER_XT_MATCH_HELPER=m
++CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
++CONFIG_NETFILTER_XT_MATCH_IPVS=m
++CONFIG_NETFILTER_XT_MATCH_LENGTH=m
++CONFIG_NETFILTER_XT_MATCH_LIMIT=m
++CONFIG_NETFILTER_XT_MATCH_MAC=m
++CONFIG_NETFILTER_XT_MATCH_MARK=m
++CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
++CONFIG_NETFILTER_XT_MATCH_NFACCT=m
++CONFIG_NETFILTER_XT_MATCH_OSF=m
++CONFIG_NETFILTER_XT_MATCH_OWNER=m
++CONFIG_NETFILTER_XT_MATCH_POLICY=m
++CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
++CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
++CONFIG_NETFILTER_XT_MATCH_QUOTA=m
++CONFIG_NETFILTER_XT_MATCH_RATEEST=m
++CONFIG_NETFILTER_XT_MATCH_REALM=m
++CONFIG_NETFILTER_XT_MATCH_RECENT=m
++CONFIG_NETFILTER_XT_MATCH_SOCKET=m
++CONFIG_NETFILTER_XT_MATCH_STATE=m
++CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
++CONFIG_NETFILTER_XT_MATCH_STRING=m
++CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
++CONFIG_NETFILTER_XT_MATCH_TIME=m
++CONFIG_NETFILTER_XT_MATCH_U32=m
++CONFIG_IP_SET=m
++CONFIG_IP_SET_BITMAP_IP=m
++CONFIG_IP_SET_BITMAP_IPMAC=m
++CONFIG_IP_SET_BITMAP_PORT=m
++CONFIG_IP_SET_HASH_IP=m
++CONFIG_IP_SET_HASH_IPPORT=m
++CONFIG_IP_SET_HASH_IPPORTIP=m
++CONFIG_IP_SET_HASH_IPPORTNET=m
++CONFIG_IP_SET_HASH_NET=m
++CONFIG_IP_SET_HASH_NETPORT=m
++CONFIG_IP_SET_HASH_NETIFACE=m
++CONFIG_IP_SET_LIST_SET=m
++CONFIG_IP_VS=m
++CONFIG_IP_VS_PROTO_TCP=y
++CONFIG_IP_VS_PROTO_UDP=y
++CONFIG_IP_VS_PROTO_ESP=y
++CONFIG_IP_VS_PROTO_AH=y
++CONFIG_IP_VS_PROTO_SCTP=y
++CONFIG_IP_VS_RR=m
++CONFIG_IP_VS_WRR=m
++CONFIG_IP_VS_LC=m
++CONFIG_IP_VS_WLC=m
++CONFIG_IP_VS_LBLC=m
++CONFIG_IP_VS_LBLCR=m
++CONFIG_IP_VS_DH=m
++CONFIG_IP_VS_SH=m
++CONFIG_IP_VS_SED=m
++CONFIG_IP_VS_NQ=m
++CONFIG_IP_VS_FTP=m
++CONFIG_IP_VS_PE_SIP=m
++CONFIG_NF_CONNTRACK_IPV4=m
++CONFIG_IP_NF_IPTABLES=m
++CONFIG_IP_NF_MATCH_AH=m
++CONFIG_IP_NF_MATCH_ECN=m
++CONFIG_IP_NF_MATCH_TTL=m
++CONFIG_IP_NF_FILTER=m
++CONFIG_IP_NF_TARGET_REJECT=m
++CONFIG_IP_NF_NAT=m
++CONFIG_IP_NF_TARGET_MASQUERADE=m
++CONFIG_IP_NF_TARGET_NETMAP=m
++CONFIG_IP_NF_TARGET_REDIRECT=m
++CONFIG_IP_NF_MANGLE=m
++CONFIG_IP_NF_TARGET_CLUSTERIP=m
++CONFIG_IP_NF_TARGET_ECN=m
++CONFIG_IP_NF_TARGET_TTL=m
++CONFIG_IP_NF_RAW=m
++CONFIG_IP_NF_ARPTABLES=m
++CONFIG_IP_NF_ARPFILTER=m
++CONFIG_IP_NF_ARP_MANGLE=m
++CONFIG_NF_CONNTRACK_IPV6=m
++CONFIG_IP6_NF_IPTABLES=m
++CONFIG_IP6_NF_MATCH_AH=m
++CONFIG_IP6_NF_MATCH_EUI64=m
++CONFIG_IP6_NF_MATCH_FRAG=m
++CONFIG_IP6_NF_MATCH_OPTS=m
++CONFIG_IP6_NF_MATCH_HL=m
++CONFIG_IP6_NF_MATCH_IPV6HEADER=m
++CONFIG_IP6_NF_MATCH_MH=m
++CONFIG_IP6_NF_MATCH_RT=m
++CONFIG_IP6_NF_TARGET_HL=m
++CONFIG_IP6_NF_FILTER=m
++CONFIG_IP6_NF_TARGET_REJECT=m
++CONFIG_IP6_NF_MANGLE=m
++CONFIG_IP6_NF_RAW=m
++CONFIG_IP6_NF_NAT=m
++CONFIG_IP6_NF_TARGET_MASQUERADE=m
++CONFIG_IP6_NF_TARGET_NPT=m
++CONFIG_BRIDGE_NF_EBTABLES=m
++CONFIG_BRIDGE_EBT_BROUTE=m
++CONFIG_BRIDGE_EBT_T_FILTER=m
++CONFIG_BRIDGE_EBT_T_NAT=m
++CONFIG_BRIDGE_EBT_802_3=m
++CONFIG_BRIDGE_EBT_AMONG=m
++CONFIG_BRIDGE_EBT_ARP=m
++CONFIG_BRIDGE_EBT_IP=m
++CONFIG_BRIDGE_EBT_IP6=m
++CONFIG_BRIDGE_EBT_LIMIT=m
++CONFIG_BRIDGE_EBT_MARK=m
++CONFIG_BRIDGE_EBT_PKTTYPE=m
++CONFIG_BRIDGE_EBT_STP=m
++CONFIG_BRIDGE_EBT_VLAN=m
++CONFIG_BRIDGE_EBT_ARPREPLY=m
++CONFIG_BRIDGE_EBT_DNAT=m
++CONFIG_BRIDGE_EBT_MARK_T=m
++CONFIG_BRIDGE_EBT_REDIRECT=m
++CONFIG_BRIDGE_EBT_SNAT=m
++CONFIG_BRIDGE_EBT_LOG=m
++CONFIG_BRIDGE_EBT_NFLOG=m
++CONFIG_SCTP_COOKIE_HMAC_SHA1=y
++CONFIG_ATM=m
++CONFIG_L2TP=m
++CONFIG_L2TP_V3=y
++CONFIG_L2TP_IP=m
++CONFIG_L2TP_ETH=m
++CONFIG_BRIDGE=m
++CONFIG_VLAN_8021Q=m
++CONFIG_VLAN_8021Q_GVRP=y
++CONFIG_ATALK=m
++CONFIG_6LOWPAN=m
++CONFIG_NET_SCHED=y
++CONFIG_NET_SCH_CBQ=m
++CONFIG_NET_SCH_HTB=m
++CONFIG_NET_SCH_HFSC=m
++CONFIG_NET_SCH_PRIO=m
++CONFIG_NET_SCH_MULTIQ=m
++CONFIG_NET_SCH_RED=m
++CONFIG_NET_SCH_SFB=m
++CONFIG_NET_SCH_SFQ=m
++CONFIG_NET_SCH_TEQL=m
++CONFIG_NET_SCH_TBF=m
++CONFIG_NET_SCH_GRED=m
++CONFIG_NET_SCH_DSMARK=m
++CONFIG_NET_SCH_NETEM=m
++CONFIG_NET_SCH_DRR=m
++CONFIG_NET_SCH_MQPRIO=m
++CONFIG_NET_SCH_CHOKE=m
++CONFIG_NET_SCH_QFQ=m
++CONFIG_NET_SCH_CODEL=m
++CONFIG_NET_SCH_FQ_CODEL=m
++CONFIG_NET_SCH_INGRESS=m
++CONFIG_NET_SCH_PLUG=m
++CONFIG_NET_CLS_BASIC=m
++CONFIG_NET_CLS_TCINDEX=m
++CONFIG_NET_CLS_ROUTE4=m
++CONFIG_NET_CLS_FW=m
++CONFIG_NET_CLS_U32=m
++CONFIG_CLS_U32_MARK=y
++CONFIG_NET_CLS_RSVP=m
++CONFIG_NET_CLS_RSVP6=m
++CONFIG_NET_CLS_FLOW=m
++CONFIG_NET_CLS_CGROUP=m
++CONFIG_NET_EMATCH=y
++CONFIG_NET_EMATCH_CMP=m
++CONFIG_NET_EMATCH_NBYTE=m
++CONFIG_NET_EMATCH_U32=m
++CONFIG_NET_EMATCH_META=m
++CONFIG_NET_EMATCH_TEXT=m
++CONFIG_NET_EMATCH_IPSET=m
++CONFIG_NET_CLS_ACT=y
++CONFIG_NET_ACT_POLICE=m
++CONFIG_NET_ACT_GACT=m
++CONFIG_GACT_PROB=y
++CONFIG_NET_ACT_MIRRED=m
++CONFIG_NET_ACT_IPT=m
++CONFIG_NET_ACT_NAT=m
++CONFIG_NET_ACT_PEDIT=m
++CONFIG_NET_ACT_SIMP=m
++CONFIG_NET_ACT_SKBEDIT=m
++CONFIG_NET_ACT_CSUM=m
++CONFIG_BATMAN_ADV=m
++CONFIG_OPENVSWITCH=m
++CONFIG_NET_PKTGEN=m
++CONFIG_HAMRADIO=y
++CONFIG_AX25=m
++CONFIG_NETROM=m
++CONFIG_ROSE=m
++CONFIG_MKISS=m
++CONFIG_6PACK=m
++CONFIG_BPQETHER=m
++CONFIG_BAYCOM_SER_FDX=m
++CONFIG_BAYCOM_SER_HDX=m
++CONFIG_YAM=m
++CONFIG_CAN=m
++CONFIG_CAN_VCAN=m
++CONFIG_CAN_MCP251X=m
++CONFIG_IRDA=m
++CONFIG_IRLAN=m
++CONFIG_IRNET=m
++CONFIG_IRCOMM=m
++CONFIG_IRDA_ULTRA=y
++CONFIG_IRDA_CACHE_LAST_LSAP=y
++CONFIG_IRDA_FAST_RR=y
++CONFIG_IRTTY_SIR=m
++CONFIG_KINGSUN_DONGLE=m
++CONFIG_KSDAZZLE_DONGLE=m
++CONFIG_KS959_DONGLE=m
++CONFIG_USB_IRDA=m
++CONFIG_SIGMATEL_FIR=m
++CONFIG_MCS_FIR=m
++CONFIG_BT=m
++CONFIG_BT_RFCOMM=m
++CONFIG_BT_RFCOMM_TTY=y
++CONFIG_BT_BNEP=m
++CONFIG_BT_BNEP_MC_FILTER=y
++CONFIG_BT_BNEP_PROTO_FILTER=y
++CONFIG_BT_HIDP=m
++CONFIG_BT_6LOWPAN=m
++CONFIG_BT_HCIBTUSB=m
++CONFIG_BT_HCIBCM203X=m
++CONFIG_BT_HCIBPA10X=m
++CONFIG_BT_HCIBFUSB=m
++CONFIG_BT_HCIVHCI=m
++CONFIG_BT_MRVL=m
++CONFIG_BT_MRVL_SDIO=m
++CONFIG_BT_ATH3K=m
++CONFIG_BT_WILINK=m
++CONFIG_MAC80211=m
++CONFIG_MAC80211_MESH=y
++CONFIG_WIMAX=m
++CONFIG_RFKILL=m
++CONFIG_RFKILL_INPUT=y
++CONFIG_NET_9P=m
++CONFIG_NFC=m
++CONFIG_NFC_PN533=m
+ CONFIG_DEVTMPFS=y
+ CONFIG_DEVTMPFS_MOUNT=y
+ # CONFIG_STANDALONE is not set
++CONFIG_DMA_CMA=y
++CONFIG_CMA_SIZE_MBYTES=5
++CONFIG_ZRAM=m
++CONFIG_ZRAM_LZ4_COMPRESS=y
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_CRYPTOLOOP=m
++CONFIG_BLK_DEV_DRBD=m
++CONFIG_BLK_DEV_NBD=m
++CONFIG_BLK_DEV_RAM=y
++CONFIG_CDROM_PKTCDVD=m
++CONFIG_ATA_OVER_ETH=m
++CONFIG_EEPROM_AT24=m
++CONFIG_TI_ST=m
+ CONFIG_SCSI=y
++# CONFIG_SCSI_PROC_FS is not set
+ CONFIG_BLK_DEV_SD=y
+-CONFIG_SCSI_MULTI_LUN=y
++CONFIG_CHR_DEV_ST=m
++CONFIG_CHR_DEV_OSST=m
++CONFIG_BLK_DEV_SR=m
++CONFIG_CHR_DEV_SG=m
+ CONFIG_SCSI_CONSTANTS=y
+ CONFIG_SCSI_SCAN_ASYNC=y
++CONFIG_SCSI_ISCSI_ATTRS=y
++CONFIG_ISCSI_TCP=m
++CONFIG_ISCSI_BOOT_SYSFS=m
++CONFIG_MD=y
++CONFIG_MD_LINEAR=m
++CONFIG_MD_RAID0=m
++CONFIG_BLK_DEV_DM=m
++CONFIG_DM_CRYPT=m
++CONFIG_DM_SNAPSHOT=m
++CONFIG_DM_MIRROR=m
++CONFIG_DM_LOG_USERSPACE=m
++CONFIG_DM_RAID=m
++CONFIG_DM_ZERO=m
++CONFIG_DM_DELAY=m
+ CONFIG_NETDEVICES=y
++CONFIG_BONDING=m
++CONFIG_DUMMY=m
++CONFIG_IFB=m
++CONFIG_MACVLAN=m
++CONFIG_NETCONSOLE=m
++CONFIG_TUN=m
++CONFIG_VETH=m
++CONFIG_ENC28J60=m
++CONFIG_MDIO_BITBANG=m
++CONFIG_PPP=m
++CONFIG_PPP_BSDCOMP=m
++CONFIG_PPP_DEFLATE=m
++CONFIG_PPP_FILTER=y
++CONFIG_PPP_MPPE=m
++CONFIG_PPP_MULTILINK=y
++CONFIG_PPPOATM=m
++CONFIG_PPPOE=m
++CONFIG_PPPOL2TP=m
++CONFIG_PPP_ASYNC=m
++CONFIG_PPP_SYNC_TTY=m
++CONFIG_SLIP=m
++CONFIG_SLIP_COMPRESSED=y
++CONFIG_SLIP_SMART=y
++CONFIG_USB_CATC=m
++CONFIG_USB_KAWETH=m
++CONFIG_USB_PEGASUS=m
++CONFIG_USB_RTL8150=m
++CONFIG_USB_RTL8152=m
+ CONFIG_USB_USBNET=y
++CONFIG_USB_NET_AX8817X=m
++CONFIG_USB_NET_AX88179_178A=m
++CONFIG_USB_NET_CDCETHER=m
++CONFIG_USB_NET_CDC_EEM=m
++CONFIG_USB_NET_CDC_NCM=m
++CONFIG_USB_NET_HUAWEI_CDC_NCM=m
++CONFIG_USB_NET_CDC_MBIM=m
++CONFIG_USB_NET_DM9601=m
++CONFIG_USB_NET_SR9700=m
++CONFIG_USB_NET_SR9800=m
++CONFIG_USB_NET_SMSC75XX=m
+ CONFIG_USB_NET_SMSC95XX=y
+-CONFIG_ZD1211RW=y
+-CONFIG_INPUT_EVDEV=y
++CONFIG_USB_NET_GL620A=m
++CONFIG_USB_NET_NET1080=m
++CONFIG_USB_NET_PLUSB=m
++CONFIG_USB_NET_MCS7830=m
++CONFIG_USB_NET_CDC_SUBSET=m
++CONFIG_USB_ALI_M5632=y
++CONFIG_USB_AN2720=y
++CONFIG_USB_EPSON2888=y
++CONFIG_USB_KC2190=y
++CONFIG_USB_NET_ZAURUS=m
++CONFIG_USB_NET_CX82310_ETH=m
++CONFIG_USB_NET_KALMIA=m
++CONFIG_USB_NET_QMI_WWAN=m
++CONFIG_USB_HSO=m
++CONFIG_USB_NET_INT51X1=m
++CONFIG_USB_IPHETH=m
++CONFIG_USB_SIERRA_NET=m
++CONFIG_USB_VL600=m
++CONFIG_LIBERTAS_THINFIRM=m
++CONFIG_LIBERTAS_THINFIRM_USB=m
++CONFIG_AT76C50X_USB=m
++CONFIG_USB_ZD1201=m
++CONFIG_USB_NET_RNDIS_WLAN=m
++CONFIG_RTL8187=m
++CONFIG_MAC80211_HWSIM=m
++CONFIG_ATH_CARDS=m
++CONFIG_ATH9K=m
++CONFIG_ATH9K_HTC=m
++CONFIG_CARL9170=m
++CONFIG_ATH6KL=m
++CONFIG_ATH6KL_USB=m
++CONFIG_AR5523=m
++CONFIG_B43=m
++# CONFIG_B43_PHY_N is not set
++CONFIG_B43LEGACY=m
++CONFIG_BRCMFMAC=m
++CONFIG_BRCMFMAC_USB=y
++CONFIG_HOSTAP=m
++CONFIG_LIBERTAS=m
++CONFIG_LIBERTAS_USB=m
++CONFIG_LIBERTAS_SDIO=m
++CONFIG_P54_COMMON=m
++CONFIG_P54_USB=m
++CONFIG_RT2X00=m
++CONFIG_RT2500USB=m
++CONFIG_RT73USB=m
++CONFIG_RT2800USB=m
++CONFIG_RT2800USB_RT3573=y
++CONFIG_RT2800USB_RT53XX=y
++CONFIG_RT2800USB_RT55XX=y
++CONFIG_RT2800USB_UNKNOWN=y
++CONFIG_WL_MEDIATEK=y
++CONFIG_MT7601U=m
++CONFIG_RTL8192CU=m
++CONFIG_ZD1211RW=m
++CONFIG_MWIFIEX=m
++CONFIG_MWIFIEX_SDIO=m
++CONFIG_WIMAX_I2400M_USB=m
++CONFIG_INPUT_POLLDEV=m
++# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
++CONFIG_INPUT_JOYDEV=m
++CONFIG_INPUT_EVDEV=m
++# CONFIG_KEYBOARD_ATKBD is not set
++CONFIG_KEYBOARD_GPIO=m
++# CONFIG_INPUT_MOUSE is not set
++CONFIG_INPUT_JOYSTICK=y
++CONFIG_JOYSTICK_IFORCE=m
++CONFIG_JOYSTICK_IFORCE_USB=y
++CONFIG_JOYSTICK_XPAD=m
++CONFIG_JOYSTICK_XPAD_FF=y
++CONFIG_JOYSTICK_RPISENSE=m
++CONFIG_INPUT_TOUCHSCREEN=y
++CONFIG_TOUCHSCREEN_ADS7846=m
++CONFIG_TOUCHSCREEN_EGALAX=m
++CONFIG_TOUCHSCREEN_RPI_FT5406=m
++CONFIG_TOUCHSCREEN_USB_COMPOSITE=m
++CONFIG_TOUCHSCREEN_STMPE=m
++CONFIG_INPUT_MISC=y
++CONFIG_INPUT_AD714X=m
++CONFIG_INPUT_ATI_REMOTE2=m
++CONFIG_INPUT_KEYSPAN_REMOTE=m
++CONFIG_INPUT_POWERMATE=m
++CONFIG_INPUT_YEALINK=m
++CONFIG_INPUT_CM109=m
++CONFIG_INPUT_UINPUT=m
++CONFIG_INPUT_GPIO_ROTARY_ENCODER=m
++CONFIG_INPUT_ADXL34X=m
++CONFIG_INPUT_CMA3000=m
++CONFIG_SERIO=m
++CONFIG_SERIO_RAW=m
++CONFIG_GAMEPORT=m
++CONFIG_GAMEPORT_NS558=m
++CONFIG_GAMEPORT_L4=m
++CONFIG_BRCM_CHAR_DRIVERS=y
++CONFIG_BCM_VC_CMA=y
++CONFIG_BCM_VCIO=y
++CONFIG_BCM_VC_SM=y
++CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
+ # CONFIG_LEGACY_PTYS is not set
+ # CONFIG_DEVKMEM is not set
++CONFIG_SERIAL_8250=y
++# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
++CONFIG_SERIAL_8250_CONSOLE=y
++# CONFIG_SERIAL_8250_DMA is not set
++CONFIG_SERIAL_8250_NR_UARTS=1
++CONFIG_SERIAL_8250_RUNTIME_UARTS=0
+ CONFIG_SERIAL_AMBA_PL011=y
+ CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++CONFIG_SERIAL_OF_PLATFORM=y
+ CONFIG_TTY_PRINTK=y
++CONFIG_HW_RANDOM=y
++CONFIG_HW_RANDOM_BCM2835=m
++CONFIG_RAW_DRIVER=y
+ CONFIG_I2C=y
+-CONFIG_I2C_CHARDEV=y
+-CONFIG_I2C_BCM2835=y
++CONFIG_I2C_CHARDEV=m
++CONFIG_I2C_BCM2708=m
++CONFIG_I2C_BCM2835=m
+ CONFIG_SPI=y
+-CONFIG_SPI_BCM2835=y
++CONFIG_SPI_BCM2835=m
++CONFIG_SPI_SPIDEV=y
++CONFIG_PPS=m
++CONFIG_PPS_CLIENT_LDISC=m
++CONFIG_PPS_CLIENT_GPIO=m
+ CONFIG_GPIO_SYSFS=y
++CONFIG_GPIO_ARIZONA=m
++CONFIG_GPIO_STMPE=y
++CONFIG_W1=m
++CONFIG_W1_MASTER_DS2490=m
++CONFIG_W1_MASTER_DS2482=m
++CONFIG_W1_MASTER_DS1WM=m
++CONFIG_W1_MASTER_GPIO=m
++CONFIG_W1_SLAVE_THERM=m
++CONFIG_W1_SLAVE_SMEM=m
++CONFIG_W1_SLAVE_DS2408=m
++CONFIG_W1_SLAVE_DS2413=m
++CONFIG_W1_SLAVE_DS2406=m
++CONFIG_W1_SLAVE_DS2423=m
++CONFIG_W1_SLAVE_DS2431=m
++CONFIG_W1_SLAVE_DS2433=m
++CONFIG_W1_SLAVE_DS2760=m
++CONFIG_W1_SLAVE_DS2780=m
++CONFIG_W1_SLAVE_DS2781=m
++CONFIG_W1_SLAVE_DS28E04=m
++CONFIG_W1_SLAVE_BQ27000=m
++CONFIG_BATTERY_DS2760=m
++CONFIG_POWER_RESET=y
++CONFIG_POWER_RESET_GPIO=y
+ # CONFIG_HWMON is not set
++CONFIG_THERMAL=y
++CONFIG_THERMAL_BCM2835=y
++CONFIG_WATCHDOG=y
++CONFIG_BCM2835_WDT=y
++CONFIG_UCB1400_CORE=m
++CONFIG_MFD_STMPE=y
++CONFIG_STMPE_SPI=y
++CONFIG_MFD_ARIZONA_I2C=m
++CONFIG_MFD_ARIZONA_SPI=m
++CONFIG_MFD_WM5102=y
++CONFIG_MEDIA_SUPPORT=m
++CONFIG_MEDIA_CAMERA_SUPPORT=y
++CONFIG_MEDIA_ANALOG_TV_SUPPORT=y
++CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y
++CONFIG_MEDIA_RADIO_SUPPORT=y
++CONFIG_MEDIA_RC_SUPPORT=y
++CONFIG_MEDIA_CONTROLLER=y
++CONFIG_LIRC=m
++CONFIG_RC_DEVICES=y
++CONFIG_RC_ATI_REMOTE=m
++CONFIG_IR_IMON=m
++CONFIG_IR_MCEUSB=m
++CONFIG_IR_REDRAT3=m
++CONFIG_IR_STREAMZAP=m
++CONFIG_IR_IGUANA=m
++CONFIG_IR_TTUSBIR=m
++CONFIG_RC_LOOPBACK=m
++CONFIG_IR_GPIO_CIR=m
++CONFIG_MEDIA_USB_SUPPORT=y
++CONFIG_USB_VIDEO_CLASS=m
++CONFIG_USB_M5602=m
++CONFIG_USB_STV06XX=m
++CONFIG_USB_GL860=m
++CONFIG_USB_GSPCA_BENQ=m
++CONFIG_USB_GSPCA_CONEX=m
++CONFIG_USB_GSPCA_CPIA1=m
++CONFIG_USB_GSPCA_DTCS033=m
++CONFIG_USB_GSPCA_ETOMS=m
++CONFIG_USB_GSPCA_FINEPIX=m
++CONFIG_USB_GSPCA_JEILINJ=m
++CONFIG_USB_GSPCA_JL2005BCD=m
++CONFIG_USB_GSPCA_KINECT=m
++CONFIG_USB_GSPCA_KONICA=m
++CONFIG_USB_GSPCA_MARS=m
++CONFIG_USB_GSPCA_MR97310A=m
++CONFIG_USB_GSPCA_NW80X=m
++CONFIG_USB_GSPCA_OV519=m
++CONFIG_USB_GSPCA_OV534=m
++CONFIG_USB_GSPCA_OV534_9=m
++CONFIG_USB_GSPCA_PAC207=m
++CONFIG_USB_GSPCA_PAC7302=m
++CONFIG_USB_GSPCA_PAC7311=m
++CONFIG_USB_GSPCA_SE401=m
++CONFIG_USB_GSPCA_SN9C2028=m
++CONFIG_USB_GSPCA_SN9C20X=m
++CONFIG_USB_GSPCA_SONIXB=m
++CONFIG_USB_GSPCA_SONIXJ=m
++CONFIG_USB_GSPCA_SPCA500=m
++CONFIG_USB_GSPCA_SPCA501=m
++CONFIG_USB_GSPCA_SPCA505=m
++CONFIG_USB_GSPCA_SPCA506=m
++CONFIG_USB_GSPCA_SPCA508=m
++CONFIG_USB_GSPCA_SPCA561=m
++CONFIG_USB_GSPCA_SPCA1528=m
++CONFIG_USB_GSPCA_SQ905=m
++CONFIG_USB_GSPCA_SQ905C=m
++CONFIG_USB_GSPCA_SQ930X=m
++CONFIG_USB_GSPCA_STK014=m
++CONFIG_USB_GSPCA_STK1135=m
++CONFIG_USB_GSPCA_STV0680=m
++CONFIG_USB_GSPCA_SUNPLUS=m
++CONFIG_USB_GSPCA_T613=m
++CONFIG_USB_GSPCA_TOPRO=m
++CONFIG_USB_GSPCA_TV8532=m
++CONFIG_USB_GSPCA_VC032X=m
++CONFIG_USB_GSPCA_VICAM=m
++CONFIG_USB_GSPCA_XIRLINK_CIT=m
++CONFIG_USB_GSPCA_ZC3XX=m
++CONFIG_USB_PWC=m
++CONFIG_VIDEO_CPIA2=m
++CONFIG_USB_ZR364XX=m
++CONFIG_USB_STKWEBCAM=m
++CONFIG_USB_S2255=m
++CONFIG_VIDEO_USBTV=m
++CONFIG_VIDEO_PVRUSB2=m
++CONFIG_VIDEO_HDPVR=m
++CONFIG_VIDEO_USBVISION=m
++CONFIG_VIDEO_STK1160_COMMON=m
++CONFIG_VIDEO_STK1160_AC97=y
++CONFIG_VIDEO_GO7007=m
++CONFIG_VIDEO_GO7007_USB=m
++CONFIG_VIDEO_GO7007_USB_S2250_BOARD=m
++CONFIG_VIDEO_AU0828=m
++CONFIG_VIDEO_AU0828_RC=y
++CONFIG_VIDEO_CX231XX=m
++CONFIG_VIDEO_CX231XX_ALSA=m
++CONFIG_VIDEO_CX231XX_DVB=m
++CONFIG_VIDEO_TM6000=m
++CONFIG_VIDEO_TM6000_ALSA=m
++CONFIG_VIDEO_TM6000_DVB=m
++CONFIG_DVB_USB=m
++CONFIG_DVB_USB_A800=m
++CONFIG_DVB_USB_DIBUSB_MB=m
++CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y
++CONFIG_DVB_USB_DIBUSB_MC=m
++CONFIG_DVB_USB_DIB0700=m
++CONFIG_DVB_USB_UMT_010=m
++CONFIG_DVB_USB_CXUSB=m
++CONFIG_DVB_USB_M920X=m
++CONFIG_DVB_USB_DIGITV=m
++CONFIG_DVB_USB_VP7045=m
++CONFIG_DVB_USB_VP702X=m
++CONFIG_DVB_USB_GP8PSK=m
++CONFIG_DVB_USB_NOVA_T_USB2=m
++CONFIG_DVB_USB_TTUSB2=m
++CONFIG_DVB_USB_DTT200U=m
++CONFIG_DVB_USB_OPERA1=m
++CONFIG_DVB_USB_AF9005=m
++CONFIG_DVB_USB_AF9005_REMOTE=m
++CONFIG_DVB_USB_PCTV452E=m
++CONFIG_DVB_USB_DW2102=m
++CONFIG_DVB_USB_CINERGY_T2=m
++CONFIG_DVB_USB_DTV5100=m
++CONFIG_DVB_USB_FRIIO=m
++CONFIG_DVB_USB_AZ6027=m
++CONFIG_DVB_USB_TECHNISAT_USB2=m
++CONFIG_DVB_USB_V2=m
++CONFIG_DVB_USB_AF9015=m
++CONFIG_DVB_USB_AF9035=m
++CONFIG_DVB_USB_ANYSEE=m
++CONFIG_DVB_USB_AU6610=m
++CONFIG_DVB_USB_AZ6007=m
++CONFIG_DVB_USB_CE6230=m
++CONFIG_DVB_USB_EC168=m
++CONFIG_DVB_USB_GL861=m
++CONFIG_DVB_USB_LME2510=m
++CONFIG_DVB_USB_MXL111SF=m
++CONFIG_DVB_USB_RTL28XXU=m
++CONFIG_DVB_USB_DVBSKY=m
++CONFIG_SMS_USB_DRV=m
++CONFIG_DVB_B2C2_FLEXCOP_USB=m
++CONFIG_DVB_AS102=m
++CONFIG_VIDEO_EM28XX=m
++CONFIG_VIDEO_EM28XX_V4L2=m
++CONFIG_VIDEO_EM28XX_ALSA=m
++CONFIG_VIDEO_EM28XX_DVB=m
++CONFIG_V4L_PLATFORM_DRIVERS=y
++CONFIG_VIDEO_BCM2835=y
++CONFIG_VIDEO_BCM2835_MMAL=m
++CONFIG_RADIO_SI470X=y
++CONFIG_USB_SI470X=m
++CONFIG_I2C_SI470X=m
++CONFIG_RADIO_SI4713=m
++CONFIG_I2C_SI4713=m
++CONFIG_USB_MR800=m
++CONFIG_USB_DSBR=m
++CONFIG_RADIO_SHARK=m
++CONFIG_RADIO_SHARK2=m
++CONFIG_USB_KEENE=m
++CONFIG_USB_MA901=m
++CONFIG_RADIO_TEA5764=m
++CONFIG_RADIO_SAA7706H=m
++CONFIG_RADIO_TEF6862=m
++CONFIG_RADIO_WL1273=m
++CONFIG_RADIO_WL128X=m
++# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
++CONFIG_VIDEO_UDA1342=m
++CONFIG_VIDEO_SONY_BTF_MPX=m
++CONFIG_VIDEO_TVP5150=m
++CONFIG_VIDEO_TW2804=m
++CONFIG_VIDEO_TW9903=m
++CONFIG_VIDEO_TW9906=m
++CONFIG_VIDEO_OV7640=m
++CONFIG_VIDEO_MT9V011=m
+ CONFIG_FB=y
+-CONFIG_FB_SIMPLE=y
++CONFIG_FB_BCM2708=y
++CONFIG_FB_SSD1307=m
++CONFIG_FB_RPISENSE=m
++# CONFIG_BACKLIGHT_GENERIC is not set
++CONFIG_BACKLIGHT_GPIO=m
+ CONFIG_FRAMEBUFFER_CONSOLE=y
+ CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
++CONFIG_LOGO=y
++# CONFIG_LOGO_LINUX_MONO is not set
++# CONFIG_LOGO_LINUX_VGA16 is not set
++CONFIG_SOUND=y
++CONFIG_SND=m
++CONFIG_SND_SEQUENCER=m
++CONFIG_SND_SEQ_DUMMY=m
++CONFIG_SND_MIXER_OSS=m
++CONFIG_SND_PCM_OSS=m
++CONFIG_SND_SEQUENCER_OSS=y
++CONFIG_SND_HRTIMER=m
++CONFIG_SND_DUMMY=m
++CONFIG_SND_ALOOP=m
++CONFIG_SND_VIRMIDI=m
++CONFIG_SND_MTPAV=m
++CONFIG_SND_SERIAL_U16550=m
++CONFIG_SND_MPU401=m
++CONFIG_SND_BCM2835=m
++CONFIG_SND_USB_AUDIO=m
++CONFIG_SND_USB_UA101=m
++CONFIG_SND_USB_CAIAQ=m
++CONFIG_SND_USB_CAIAQ_INPUT=y
++CONFIG_SND_USB_6FIRE=m
++CONFIG_SND_SOC=m
++CONFIG_SND_BCM2835_SOC_I2S=m
++CONFIG_SND_BCM2708_SOC_I2S=m
++CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC=m
++CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS=m
++CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI=m
++CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP=m
++CONFIG_SND_BCM2708_SOC_RPI_DAC=m
++CONFIG_SND_BCM2708_SOC_RPI_PROTO=m
++CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m
++CONFIG_SND_SOC_WM8804_I2C=m
++CONFIG_SND_SIMPLE_CARD=m
++CONFIG_SOUND_PRIME=m
++CONFIG_HIDRAW=y
++CONFIG_HID_A4TECH=m
++CONFIG_HID_ACRUX=m
++CONFIG_HID_APPLE=m
++CONFIG_HID_BELKIN=m
++CONFIG_HID_CHERRY=m
++CONFIG_HID_CHICONY=m
++CONFIG_HID_CYPRESS=m
++CONFIG_HID_DRAGONRISE=m
++CONFIG_HID_EMS_FF=m
++CONFIG_HID_ELECOM=m
++CONFIG_HID_ELO=m
++CONFIG_HID_EZKEY=m
++CONFIG_HID_HOLTEK=m
++CONFIG_HID_KEYTOUCH=m
++CONFIG_HID_KYE=m
++CONFIG_HID_UCLOGIC=m
++CONFIG_HID_WALTOP=m
++CONFIG_HID_GYRATION=m
++CONFIG_HID_TWINHAN=m
++CONFIG_HID_KENSINGTON=m
++CONFIG_HID_LCPOWER=m
++CONFIG_HID_LOGITECH=m
++CONFIG_HID_MAGICMOUSE=m
++CONFIG_HID_MICROSOFT=m
++CONFIG_HID_MONTEREY=m
++CONFIG_HID_MULTITOUCH=m
++CONFIG_HID_NTRIG=m
++CONFIG_HID_ORTEK=m
++CONFIG_HID_PANTHERLORD=m
++CONFIG_HID_PETALYNX=m
++CONFIG_HID_PICOLCD=m
++CONFIG_HID_ROCCAT=m
++CONFIG_HID_SAMSUNG=m
++CONFIG_HID_SONY=m
++CONFIG_HID_SPEEDLINK=m
++CONFIG_HID_SUNPLUS=m
++CONFIG_HID_GREENASIA=m
++CONFIG_HID_SMARTJOYPLUS=m
++CONFIG_HID_TOPSEED=m
++CONFIG_HID_THINGM=m
++CONFIG_HID_THRUSTMASTER=m
++CONFIG_HID_WACOM=m
++CONFIG_HID_WIIMOTE=m
++CONFIG_HID_XINMO=m
++CONFIG_HID_ZEROPLUS=m
++CONFIG_HID_ZYDACRON=m
++CONFIG_HID_PID=y
++CONFIG_USB_HIDDEV=y
+ CONFIG_USB=y
++CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
++CONFIG_USB_MON=m
++CONFIG_USB_DWCOTG=y
++CONFIG_USB_PRINTER=m
+ CONFIG_USB_STORAGE=y
++CONFIG_USB_STORAGE_REALTEK=m
++CONFIG_USB_STORAGE_DATAFAB=m
++CONFIG_USB_STORAGE_FREECOM=m
++CONFIG_USB_STORAGE_ISD200=m
++CONFIG_USB_STORAGE_USBAT=m
++CONFIG_USB_STORAGE_SDDR09=m
++CONFIG_USB_STORAGE_SDDR55=m
++CONFIG_USB_STORAGE_JUMPSHOT=m
++CONFIG_USB_STORAGE_ALAUDA=m
++CONFIG_USB_STORAGE_ONETOUCH=m
++CONFIG_USB_STORAGE_KARMA=m
++CONFIG_USB_STORAGE_CYPRESS_ATACB=m
++CONFIG_USB_STORAGE_ENE_UB6250=m
++CONFIG_USB_MDC800=m
++CONFIG_USB_MICROTEK=m
++CONFIG_USBIP_CORE=m
++CONFIG_USBIP_VHCI_HCD=m
++CONFIG_USBIP_HOST=m
++CONFIG_USB_DWC2=y
++CONFIG_USB_SERIAL=m
++CONFIG_USB_SERIAL_GENERIC=y
++CONFIG_USB_SERIAL_AIRCABLE=m
++CONFIG_USB_SERIAL_ARK3116=m
++CONFIG_USB_SERIAL_BELKIN=m
++CONFIG_USB_SERIAL_CH341=m
++CONFIG_USB_SERIAL_WHITEHEAT=m
++CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
++CONFIG_USB_SERIAL_CP210X=m
++CONFIG_USB_SERIAL_CYPRESS_M8=m
++CONFIG_USB_SERIAL_EMPEG=m
++CONFIG_USB_SERIAL_FTDI_SIO=m
++CONFIG_USB_SERIAL_VISOR=m
++CONFIG_USB_SERIAL_IPAQ=m
++CONFIG_USB_SERIAL_IR=m
++CONFIG_USB_SERIAL_EDGEPORT=m
++CONFIG_USB_SERIAL_EDGEPORT_TI=m
++CONFIG_USB_SERIAL_F81232=m
++CONFIG_USB_SERIAL_GARMIN=m
++CONFIG_USB_SERIAL_IPW=m
++CONFIG_USB_SERIAL_IUU=m
++CONFIG_USB_SERIAL_KEYSPAN_PDA=m
++CONFIG_USB_SERIAL_KEYSPAN=m
++CONFIG_USB_SERIAL_KLSI=m
++CONFIG_USB_SERIAL_KOBIL_SCT=m
++CONFIG_USB_SERIAL_MCT_U232=m
++CONFIG_USB_SERIAL_METRO=m
++CONFIG_USB_SERIAL_MOS7720=m
++CONFIG_USB_SERIAL_MOS7840=m
++CONFIG_USB_SERIAL_NAVMAN=m
++CONFIG_USB_SERIAL_PL2303=m
++CONFIG_USB_SERIAL_OTI6858=m
++CONFIG_USB_SERIAL_QCAUX=m
++CONFIG_USB_SERIAL_QUALCOMM=m
++CONFIG_USB_SERIAL_SPCP8X5=m
++CONFIG_USB_SERIAL_SAFE=m
++CONFIG_USB_SERIAL_SIERRAWIRELESS=m
++CONFIG_USB_SERIAL_SYMBOL=m
++CONFIG_USB_SERIAL_TI=m
++CONFIG_USB_SERIAL_CYBERJACK=m
++CONFIG_USB_SERIAL_XIRCOM=m
++CONFIG_USB_SERIAL_OPTION=m
++CONFIG_USB_SERIAL_OMNINET=m
++CONFIG_USB_SERIAL_OPTICON=m
++CONFIG_USB_SERIAL_XSENS_MT=m
++CONFIG_USB_SERIAL_WISHBONE=m
++CONFIG_USB_SERIAL_SSU100=m
++CONFIG_USB_SERIAL_QT2=m
++CONFIG_USB_SERIAL_DEBUG=m
++CONFIG_USB_EMI62=m
++CONFIG_USB_EMI26=m
++CONFIG_USB_ADUTUX=m
++CONFIG_USB_SEVSEG=m
++CONFIG_USB_RIO500=m
++CONFIG_USB_LEGOTOWER=m
++CONFIG_USB_LCD=m
++CONFIG_USB_LED=m
++CONFIG_USB_CYPRESS_CY7C63=m
++CONFIG_USB_CYTHERM=m
++CONFIG_USB_IDMOUSE=m
++CONFIG_USB_FTDI_ELAN=m
++CONFIG_USB_APPLEDISPLAY=m
++CONFIG_USB_LD=m
++CONFIG_USB_TRANCEVIBRATOR=m
++CONFIG_USB_IOWARRIOR=m
++CONFIG_USB_TEST=m
++CONFIG_USB_ISIGHTFW=m
++CONFIG_USB_YUREX=m
++CONFIG_USB_ATM=m
++CONFIG_USB_SPEEDTOUCH=m
++CONFIG_USB_CXACRU=m
++CONFIG_USB_UEAGLEATM=m
++CONFIG_USB_XUSBATM=m
+ CONFIG_MMC=y
++CONFIG_MMC_BLOCK_MINORS=32
++CONFIG_MMC_BCM2835=y
++CONFIG_MMC_BCM2835_DMA=y
++CONFIG_MMC_BCM2835_SDHOST=y
+ CONFIG_MMC_SDHCI=y
+ CONFIG_MMC_SDHCI_PLTFM=y
+ CONFIG_MMC_SDHCI_BCM2835=y
++CONFIG_MMC_SPI=m
++CONFIG_LEDS_CLASS=y
+ CONFIG_LEDS_GPIO=y
+ CONFIG_LEDS_TRIGGER_TIMER=y
+ CONFIG_LEDS_TRIGGER_ONESHOT=y
+ CONFIG_LEDS_TRIGGER_HEARTBEAT=y
++CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+ CONFIG_LEDS_TRIGGER_CPU=y
+ CONFIG_LEDS_TRIGGER_GPIO=y
+ CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+-CONFIG_LEDS_TRIGGER_TRANSIENT=y
+-CONFIG_LEDS_TRIGGER_CAMERA=y
++CONFIG_LEDS_TRIGGER_TRANSIENT=m
++CONFIG_LEDS_TRIGGER_CAMERA=m
++CONFIG_LEDS_TRIGGER_INPUT=y
++CONFIG_RTC_CLASS=y
++# CONFIG_RTC_HCTOSYS is not set
++CONFIG_RTC_DRV_DS1307=m
++CONFIG_RTC_DRV_DS1374=m
++CONFIG_RTC_DRV_DS1672=m
++CONFIG_RTC_DRV_DS3232=m
++CONFIG_RTC_DRV_MAX6900=m
++CONFIG_RTC_DRV_RS5C372=m
++CONFIG_RTC_DRV_ISL1208=m
++CONFIG_RTC_DRV_ISL12022=m
++CONFIG_RTC_DRV_ISL12057=m
++CONFIG_RTC_DRV_X1205=m
++CONFIG_RTC_DRV_PCF2127=m
++CONFIG_RTC_DRV_PCF8523=m
++CONFIG_RTC_DRV_PCF8563=m
++CONFIG_RTC_DRV_PCF8583=m
++CONFIG_RTC_DRV_M41T80=m
++CONFIG_RTC_DRV_BQ32K=m
++CONFIG_RTC_DRV_S35390A=m
++CONFIG_RTC_DRV_FM3130=m
++CONFIG_RTC_DRV_RX8581=m
++CONFIG_RTC_DRV_RX8025=m
++CONFIG_RTC_DRV_EM3027=m
++CONFIG_RTC_DRV_RV3029C2=m
++CONFIG_RTC_DRV_M41T93=m
++CONFIG_RTC_DRV_M41T94=m
++CONFIG_RTC_DRV_DS1305=m
++CONFIG_RTC_DRV_DS1390=m
++CONFIG_RTC_DRV_MAX6902=m
++CONFIG_RTC_DRV_R9701=m
++CONFIG_RTC_DRV_RS5C348=m
++CONFIG_RTC_DRV_DS3234=m
++CONFIG_RTC_DRV_PCF2123=m
++CONFIG_RTC_DRV_RX4581=m
++CONFIG_DMADEVICES=y
++CONFIG_DMA_BCM2835=y
++CONFIG_DMA_BCM2708=y
++CONFIG_UIO=m
++CONFIG_UIO_PDRV_GENIRQ=m
+ CONFIG_STAGING=y
+-CONFIG_USB_DWC2=y
+-CONFIG_USB_DWC2_HOST=y
++CONFIG_PRISM2_USB=m
++CONFIG_R8712U=m
++CONFIG_R8188EU=m
++CONFIG_R8723AU=m
++CONFIG_VT6656=m
++CONFIG_SPEAKUP=m
++CONFIG_SPEAKUP_SYNTH_SOFT=m
++CONFIG_STAGING_MEDIA=y
++CONFIG_LIRC_STAGING=y
++CONFIG_LIRC_IMON=m
++CONFIG_LIRC_RPI=m
++CONFIG_LIRC_SASEM=m
++CONFIG_LIRC_SERIAL=m
++CONFIG_FB_TFT=m
++CONFIG_FB_TFT_AGM1264K_FL=m
++CONFIG_FB_TFT_BD663474=m
++CONFIG_FB_TFT_HX8340BN=m
++CONFIG_FB_TFT_HX8347D=m
++CONFIG_FB_TFT_HX8353D=m
++CONFIG_FB_TFT_ILI9320=m
++CONFIG_FB_TFT_ILI9325=m
++CONFIG_FB_TFT_ILI9340=m
++CONFIG_FB_TFT_ILI9341=m
++CONFIG_FB_TFT_ILI9481=m
++CONFIG_FB_TFT_ILI9486=m
++CONFIG_FB_TFT_PCD8544=m
++CONFIG_FB_TFT_RA8875=m
++CONFIG_FB_TFT_S6D02A1=m
++CONFIG_FB_TFT_S6D1121=m
++CONFIG_FB_TFT_SSD1289=m
++CONFIG_FB_TFT_SSD1306=m
++CONFIG_FB_TFT_SSD1331=m
++CONFIG_FB_TFT_SSD1351=m
++CONFIG_FB_TFT_ST7735R=m
++CONFIG_FB_TFT_TINYLCD=m
++CONFIG_FB_TFT_TLS8204=m
++CONFIG_FB_TFT_UC1701=m
++CONFIG_FB_TFT_UPD161704=m
++CONFIG_FB_TFT_WATTEROTT=m
++CONFIG_FB_FLEX=m
++CONFIG_FB_TFT_FBTFT_DEVICE=m
++CONFIG_MAILBOX=y
++CONFIG_BCM2835_MBOX=y
+ # CONFIG_IOMMU_SUPPORT is not set
++CONFIG_EXTCON=m
++CONFIG_EXTCON_ARIZONA=m
++CONFIG_IIO=m
++CONFIG_IIO_BUFFER=y
++CONFIG_IIO_BUFFER_CB=y
++CONFIG_IIO_KFIFO_BUF=m
++CONFIG_DHT11=m
++CONFIG_RASPBERRYPI_FIRMWARE=y
+ CONFIG_EXT2_FS=y
+ CONFIG_EXT2_FS_XATTR=y
+ CONFIG_EXT2_FS_POSIX_ACL=y
+@@ -107,18 +1105,110 @@ CONFIG_EXT3_FS=y
+ CONFIG_EXT3_FS_POSIX_ACL=y
+ CONFIG_EXT4_FS=y
+ CONFIG_EXT4_FS_POSIX_ACL=y
++CONFIG_EXT4_FS_SECURITY=y
++CONFIG_REISERFS_FS=m
++CONFIG_REISERFS_FS_XATTR=y
++CONFIG_REISERFS_FS_POSIX_ACL=y
++CONFIG_REISERFS_FS_SECURITY=y
++CONFIG_JFS_FS=m
++CONFIG_JFS_POSIX_ACL=y
++CONFIG_JFS_SECURITY=y
++CONFIG_JFS_STATISTICS=y
++CONFIG_XFS_FS=m
++CONFIG_XFS_QUOTA=y
++CONFIG_XFS_POSIX_ACL=y
++CONFIG_XFS_RT=y
++CONFIG_GFS2_FS=m
++CONFIG_OCFS2_FS=m
++CONFIG_BTRFS_FS=m
++CONFIG_BTRFS_FS_POSIX_ACL=y
++CONFIG_NILFS2_FS=m
++CONFIG_F2FS_FS=y
+ CONFIG_FANOTIFY=y
++CONFIG_QFMT_V1=m
++CONFIG_QFMT_V2=m
++CONFIG_AUTOFS4_FS=y
++CONFIG_FUSE_FS=m
++CONFIG_CUSE=m
++CONFIG_FSCACHE=y
++CONFIG_FSCACHE_STATS=y
++CONFIG_FSCACHE_HISTOGRAM=y
++CONFIG_CACHEFILES=y
++CONFIG_ISO9660_FS=m
++CONFIG_JOLIET=y
++CONFIG_ZISOFS=y
++CONFIG_UDF_FS=m
+ CONFIG_MSDOS_FS=y
+ CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
++CONFIG_NTFS_FS=m
++CONFIG_NTFS_RW=y
+ CONFIG_TMPFS=y
+ CONFIG_TMPFS_POSIX_ACL=y
+-# CONFIG_MISC_FILESYSTEMS is not set
++CONFIG_CONFIGFS_FS=y
++CONFIG_ECRYPT_FS=m
++CONFIG_HFS_FS=m
++CONFIG_HFSPLUS_FS=m
++CONFIG_SQUASHFS=m
++CONFIG_SQUASHFS_XATTR=y
++CONFIG_SQUASHFS_LZO=y
++CONFIG_SQUASHFS_XZ=y
+ CONFIG_NFS_FS=y
+-CONFIG_NFSD=y
++CONFIG_NFS_V3_ACL=y
++CONFIG_NFS_V4=y
++CONFIG_NFS_SWAP=y
++CONFIG_ROOT_NFS=y
++CONFIG_NFS_FSCACHE=y
++CONFIG_NFSD=m
++CONFIG_NFSD_V3_ACL=y
++CONFIG_NFSD_V4=y
++CONFIG_CIFS=m
++CONFIG_CIFS_WEAK_PW_HASH=y
++CONFIG_CIFS_UPCALL=y
++CONFIG_CIFS_XATTR=y
++CONFIG_CIFS_POSIX=y
++CONFIG_9P_FS=m
++CONFIG_9P_FS_POSIX_ACL=y
++CONFIG_NLS_DEFAULT="utf8"
+ CONFIG_NLS_CODEPAGE_437=y
++CONFIG_NLS_CODEPAGE_737=m
++CONFIG_NLS_CODEPAGE_775=m
++CONFIG_NLS_CODEPAGE_850=m
++CONFIG_NLS_CODEPAGE_852=m
++CONFIG_NLS_CODEPAGE_855=m
++CONFIG_NLS_CODEPAGE_857=m
++CONFIG_NLS_CODEPAGE_860=m
++CONFIG_NLS_CODEPAGE_861=m
++CONFIG_NLS_CODEPAGE_862=m
++CONFIG_NLS_CODEPAGE_863=m
++CONFIG_NLS_CODEPAGE_864=m
++CONFIG_NLS_CODEPAGE_865=m
++CONFIG_NLS_CODEPAGE_866=m
++CONFIG_NLS_CODEPAGE_869=m
++CONFIG_NLS_CODEPAGE_936=m
++CONFIG_NLS_CODEPAGE_950=m
++CONFIG_NLS_CODEPAGE_932=m
++CONFIG_NLS_CODEPAGE_949=m
++CONFIG_NLS_CODEPAGE_874=m
++CONFIG_NLS_ISO8859_8=m
++CONFIG_NLS_CODEPAGE_1250=m
++CONFIG_NLS_CODEPAGE_1251=m
+ CONFIG_NLS_ASCII=y
+-CONFIG_NLS_ISO8859_1=y
++CONFIG_NLS_ISO8859_1=m
++CONFIG_NLS_ISO8859_2=m
++CONFIG_NLS_ISO8859_3=m
++CONFIG_NLS_ISO8859_4=m
++CONFIG_NLS_ISO8859_5=m
++CONFIG_NLS_ISO8859_6=m
++CONFIG_NLS_ISO8859_7=m
++CONFIG_NLS_ISO8859_9=m
++CONFIG_NLS_ISO8859_13=m
++CONFIG_NLS_ISO8859_14=m
++CONFIG_NLS_ISO8859_15=m
++CONFIG_NLS_KOI8_R=m
++CONFIG_NLS_KOI8_U=m
+ CONFIG_NLS_UTF8=y
++CONFIG_DLM=m
+ CONFIG_PRINTK_TIME=y
+ CONFIG_BOOT_PRINTK_DELAY=y
+ CONFIG_DYNAMIC_DEBUG=y
+@@ -128,14 +1218,38 @@ CONFIG_DEBUG_INFO=y
+ CONFIG_UNUSED_SYMBOLS=y
+ CONFIG_DEBUG_MEMORY_INIT=y
+ CONFIG_LOCKUP_DETECTOR=y
++CONFIG_TIMER_STATS=y
++# CONFIG_DEBUG_PREEMPT is not set
++CONFIG_LATENCYTOP=y
++CONFIG_IRQSOFF_TRACER=y
+ CONFIG_SCHED_TRACER=y
+ CONFIG_STACK_TRACER=y
++CONFIG_BLK_DEV_IO_TRACE=y
++# CONFIG_KPROBE_EVENT is not set
+ CONFIG_FUNCTION_PROFILER=y
+ CONFIG_TEST_KSTRTOX=y
+ CONFIG_KGDB=y
+ CONFIG_KGDB_KDB=y
++CONFIG_KDB_KEYBOARD=y
+ CONFIG_STRICT_DEVMEM=y
+ CONFIG_DEBUG_LL=y
+ CONFIG_EARLY_PRINTK=y
++CONFIG_CRYPTO_USER=m
++CONFIG_CRYPTO_CRYPTD=m
++CONFIG_CRYPTO_CBC=y
++CONFIG_CRYPTO_CTS=m
++CONFIG_CRYPTO_XTS=m
++CONFIG_CRYPTO_XCBC=m
++CONFIG_CRYPTO_SHA512=m
++CONFIG_CRYPTO_TGR192=m
++CONFIG_CRYPTO_WP512=m
++CONFIG_CRYPTO_CAST5=m
++CONFIG_CRYPTO_DES=y
++# CONFIG_CRYPTO_HW is not set
++CONFIG_ARM_CRYPTO=y
++CONFIG_CRYPTO_SHA1_ARM=m
++CONFIG_CRYPTO_AES_ARM=m
++CONFIG_CRC_ITU_T=y
++CONFIG_LIBCRC32C=y
+ # CONFIG_XZ_DEC_ARM is not set
+ # CONFIG_XZ_DEC_ARMTHUMB is not set
diff --git a/target/linux/brcm2708/patches-4.4/0077-config-Add-default-configs.patch b/target/linux/brcm2708/patches-4.4/0077-config-Add-default-configs.patch
deleted file mode 100644
index ffd1a0bfe4..0000000000
--- a/target/linux/brcm2708/patches-4.4/0077-config-Add-default-configs.patch
+++ /dev/null
@@ -1,2537 +0,0 @@
-From e2af169e60b4ebd710e733996d57ad86264bae27 Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Mon, 13 Apr 2015 17:16:29 +0100
-Subject: [PATCH 077/170] config: Add default configs
-
----
- arch/arm/configs/bcm2709_defconfig | 1254 +++++++++++++++++++++++++++++++++++
- arch/arm/configs/bcmrpi_defconfig | 1265 ++++++++++++++++++++++++++++++++++++
- 2 files changed, 2519 insertions(+)
- create mode 100644 arch/arm/configs/bcm2709_defconfig
- create mode 100644 arch/arm/configs/bcmrpi_defconfig
-
---- /dev/null
-+++ b/arch/arm/configs/bcm2709_defconfig
-@@ -0,0 +1,1254 @@
-+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
-+CONFIG_PHYS_OFFSET=0
-+CONFIG_LOCALVERSION="-v7"
-+# CONFIG_LOCALVERSION_AUTO is not set
-+CONFIG_SYSVIPC=y
-+CONFIG_POSIX_MQUEUE=y
-+CONFIG_FHANDLE=y
-+CONFIG_NO_HZ=y
-+CONFIG_HIGH_RES_TIMERS=y
-+CONFIG_BSD_PROCESS_ACCT=y
-+CONFIG_BSD_PROCESS_ACCT_V3=y
-+CONFIG_TASKSTATS=y
-+CONFIG_TASK_DELAY_ACCT=y
-+CONFIG_TASK_XACCT=y
-+CONFIG_TASK_IO_ACCOUNTING=y
-+CONFIG_IKCONFIG=m
-+CONFIG_IKCONFIG_PROC=y
-+CONFIG_CGROUP_FREEZER=y
-+CONFIG_CGROUP_DEVICE=y
-+CONFIG_CPUSETS=y
-+CONFIG_CGROUP_CPUACCT=y
-+CONFIG_MEMCG=y
-+CONFIG_BLK_CGROUP=y
-+CONFIG_NAMESPACES=y
-+CONFIG_SCHED_AUTOGROUP=y
-+CONFIG_BLK_DEV_INITRD=y
-+CONFIG_EMBEDDED=y
-+# CONFIG_COMPAT_BRK is not set
-+CONFIG_PROFILING=y
-+CONFIG_OPROFILE=m
-+CONFIG_KPROBES=y
-+CONFIG_JUMP_LABEL=y
-+CONFIG_MODULES=y
-+CONFIG_MODULE_UNLOAD=y
-+CONFIG_MODVERSIONS=y
-+CONFIG_MODULE_SRCVERSION_ALL=y
-+CONFIG_BLK_DEV_THROTTLING=y
-+CONFIG_PARTITION_ADVANCED=y
-+CONFIG_MAC_PARTITION=y
-+CONFIG_CFQ_GROUP_IOSCHED=y
-+CONFIG_ARCH_BCM2709=y
-+# CONFIG_CACHE_L2X0 is not set
-+CONFIG_SMP=y
-+CONFIG_HAVE_ARM_ARCH_TIMER=y
-+CONFIG_VMSPLIT_2G=y
-+CONFIG_PREEMPT_VOLUNTARY=y
-+CONFIG_AEABI=y
-+CONFIG_OABI_COMPAT=y
-+# CONFIG_CPU_SW_DOMAIN_PAN is not set
-+CONFIG_CLEANCACHE=y
-+CONFIG_FRONTSWAP=y
-+CONFIG_CMA=y
-+CONFIG_ZSMALLOC=m
-+CONFIG_PGTABLE_MAPPING=y
-+CONFIG_UACCESS_WITH_MEMCPY=y
-+CONFIG_SECCOMP=y
-+# CONFIG_ATAGS is not set
-+CONFIG_ZBOOT_ROM_TEXT=0x0
-+CONFIG_ZBOOT_ROM_BSS=0x0
-+CONFIG_CMDLINE="console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait"
-+CONFIG_CPU_FREQ=y
-+CONFIG_CPU_FREQ_STAT=m
-+CONFIG_CPU_FREQ_STAT_DETAILS=y
-+CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE=y
-+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
-+CONFIG_CPU_FREQ_GOV_USERSPACE=y
-+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
-+CONFIG_VFP=y
-+CONFIG_NEON=y
-+CONFIG_KERNEL_MODE_NEON=y
-+CONFIG_BINFMT_MISC=m
-+# CONFIG_SUSPEND is not set
-+CONFIG_NET=y
-+CONFIG_PACKET=y
-+CONFIG_UNIX=y
-+CONFIG_XFRM_USER=y
-+CONFIG_NET_KEY=m
-+CONFIG_INET=y
-+CONFIG_IP_MULTICAST=y
-+CONFIG_IP_ADVANCED_ROUTER=y
-+CONFIG_IP_MULTIPLE_TABLES=y
-+CONFIG_IP_ROUTE_MULTIPATH=y
-+CONFIG_IP_ROUTE_VERBOSE=y
-+CONFIG_IP_PNP=y
-+CONFIG_IP_PNP_DHCP=y
-+CONFIG_IP_PNP_RARP=y
-+CONFIG_NET_IPIP=m
-+CONFIG_NET_IPGRE_DEMUX=m
-+CONFIG_NET_IPGRE=m
-+CONFIG_IP_MROUTE=y
-+CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
-+CONFIG_IP_PIMSM_V1=y
-+CONFIG_IP_PIMSM_V2=y
-+CONFIG_SYN_COOKIES=y
-+CONFIG_INET_AH=m
-+CONFIG_INET_ESP=m
-+CONFIG_INET_IPCOMP=m
-+CONFIG_INET_XFRM_MODE_TRANSPORT=m
-+CONFIG_INET_XFRM_MODE_TUNNEL=m
-+CONFIG_INET_XFRM_MODE_BEET=m
-+CONFIG_INET_LRO=m
-+CONFIG_INET_DIAG=m
-+CONFIG_INET6_AH=m
-+CONFIG_INET6_ESP=m
-+CONFIG_INET6_IPCOMP=m
-+CONFIG_IPV6_TUNNEL=m
-+CONFIG_IPV6_MULTIPLE_TABLES=y
-+CONFIG_IPV6_MROUTE=y
-+CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
-+CONFIG_IPV6_PIMSM_V2=y
-+CONFIG_NETFILTER=y
-+CONFIG_NF_CONNTRACK=m
-+CONFIG_NF_CONNTRACK_ZONES=y
-+CONFIG_NF_CONNTRACK_EVENTS=y
-+CONFIG_NF_CONNTRACK_TIMESTAMP=y
-+CONFIG_NF_CT_PROTO_DCCP=m
-+CONFIG_NF_CT_PROTO_UDPLITE=m
-+CONFIG_NF_CONNTRACK_AMANDA=m
-+CONFIG_NF_CONNTRACK_FTP=m
-+CONFIG_NF_CONNTRACK_H323=m
-+CONFIG_NF_CONNTRACK_IRC=m
-+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
-+CONFIG_NF_CONNTRACK_SNMP=m
-+CONFIG_NF_CONNTRACK_PPTP=m
-+CONFIG_NF_CONNTRACK_SANE=m
-+CONFIG_NF_CONNTRACK_SIP=m
-+CONFIG_NF_CONNTRACK_TFTP=m
-+CONFIG_NF_CT_NETLINK=m
-+CONFIG_NETFILTER_XT_SET=m
-+CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
-+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
-+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
-+CONFIG_NETFILTER_XT_TARGET_DSCP=m
-+CONFIG_NETFILTER_XT_TARGET_HMARK=m
-+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
-+CONFIG_NETFILTER_XT_TARGET_LED=m
-+CONFIG_NETFILTER_XT_TARGET_LOG=m
-+CONFIG_NETFILTER_XT_TARGET_MARK=m
-+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
-+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
-+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
-+CONFIG_NETFILTER_XT_TARGET_TEE=m
-+CONFIG_NETFILTER_XT_TARGET_TPROXY=m
-+CONFIG_NETFILTER_XT_TARGET_TRACE=m
-+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
-+CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
-+CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m
-+CONFIG_NETFILTER_XT_MATCH_BPF=m
-+CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
-+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
-+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
-+CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m
-+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
-+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
-+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
-+CONFIG_NETFILTER_XT_MATCH_CPU=m
-+CONFIG_NETFILTER_XT_MATCH_DCCP=m
-+CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m
-+CONFIG_NETFILTER_XT_MATCH_DSCP=m
-+CONFIG_NETFILTER_XT_MATCH_ESP=m
-+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
-+CONFIG_NETFILTER_XT_MATCH_HELPER=m
-+CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
-+CONFIG_NETFILTER_XT_MATCH_IPVS=m
-+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
-+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
-+CONFIG_NETFILTER_XT_MATCH_MAC=m
-+CONFIG_NETFILTER_XT_MATCH_MARK=m
-+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
-+CONFIG_NETFILTER_XT_MATCH_NFACCT=m
-+CONFIG_NETFILTER_XT_MATCH_OSF=m
-+CONFIG_NETFILTER_XT_MATCH_OWNER=m
-+CONFIG_NETFILTER_XT_MATCH_POLICY=m
-+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
-+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
-+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
-+CONFIG_NETFILTER_XT_MATCH_RATEEST=m
-+CONFIG_NETFILTER_XT_MATCH_REALM=m
-+CONFIG_NETFILTER_XT_MATCH_RECENT=m
-+CONFIG_NETFILTER_XT_MATCH_SOCKET=m
-+CONFIG_NETFILTER_XT_MATCH_STATE=m
-+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
-+CONFIG_NETFILTER_XT_MATCH_STRING=m
-+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
-+CONFIG_NETFILTER_XT_MATCH_TIME=m
-+CONFIG_NETFILTER_XT_MATCH_U32=m
-+CONFIG_IP_SET=m
-+CONFIG_IP_SET_BITMAP_IP=m
-+CONFIG_IP_SET_BITMAP_IPMAC=m
-+CONFIG_IP_SET_BITMAP_PORT=m
-+CONFIG_IP_SET_HASH_IP=m
-+CONFIG_IP_SET_HASH_IPPORT=m
-+CONFIG_IP_SET_HASH_IPPORTIP=m
-+CONFIG_IP_SET_HASH_IPPORTNET=m
-+CONFIG_IP_SET_HASH_NET=m
-+CONFIG_IP_SET_HASH_NETPORT=m
-+CONFIG_IP_SET_HASH_NETIFACE=m
-+CONFIG_IP_SET_LIST_SET=m
-+CONFIG_IP_VS=m
-+CONFIG_IP_VS_PROTO_TCP=y
-+CONFIG_IP_VS_PROTO_UDP=y
-+CONFIG_IP_VS_PROTO_ESP=y
-+CONFIG_IP_VS_PROTO_AH=y
-+CONFIG_IP_VS_PROTO_SCTP=y
-+CONFIG_IP_VS_RR=m
-+CONFIG_IP_VS_WRR=m
-+CONFIG_IP_VS_LC=m
-+CONFIG_IP_VS_WLC=m
-+CONFIG_IP_VS_LBLC=m
-+CONFIG_IP_VS_LBLCR=m
-+CONFIG_IP_VS_DH=m
-+CONFIG_IP_VS_SH=m
-+CONFIG_IP_VS_SED=m
-+CONFIG_IP_VS_NQ=m
-+CONFIG_IP_VS_FTP=m
-+CONFIG_IP_VS_PE_SIP=m
-+CONFIG_NF_CONNTRACK_IPV4=m
-+CONFIG_IP_NF_IPTABLES=m
-+CONFIG_IP_NF_MATCH_AH=m
-+CONFIG_IP_NF_MATCH_ECN=m
-+CONFIG_IP_NF_MATCH_TTL=m
-+CONFIG_IP_NF_FILTER=m
-+CONFIG_IP_NF_TARGET_REJECT=m
-+CONFIG_IP_NF_NAT=m
-+CONFIG_IP_NF_TARGET_MASQUERADE=m
-+CONFIG_IP_NF_TARGET_NETMAP=m
-+CONFIG_IP_NF_TARGET_REDIRECT=m
-+CONFIG_IP_NF_MANGLE=m
-+CONFIG_IP_NF_TARGET_CLUSTERIP=m
-+CONFIG_IP_NF_TARGET_ECN=m
-+CONFIG_IP_NF_TARGET_TTL=m
-+CONFIG_IP_NF_RAW=m
-+CONFIG_IP_NF_ARPTABLES=m
-+CONFIG_IP_NF_ARPFILTER=m
-+CONFIG_IP_NF_ARP_MANGLE=m
-+CONFIG_NF_CONNTRACK_IPV6=m
-+CONFIG_IP6_NF_IPTABLES=m
-+CONFIG_IP6_NF_MATCH_AH=m
-+CONFIG_IP6_NF_MATCH_EUI64=m
-+CONFIG_IP6_NF_MATCH_FRAG=m
-+CONFIG_IP6_NF_MATCH_OPTS=m
-+CONFIG_IP6_NF_MATCH_HL=m
-+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
-+CONFIG_IP6_NF_MATCH_MH=m
-+CONFIG_IP6_NF_MATCH_RT=m
-+CONFIG_IP6_NF_TARGET_HL=m
-+CONFIG_IP6_NF_FILTER=m
-+CONFIG_IP6_NF_TARGET_REJECT=m
-+CONFIG_IP6_NF_MANGLE=m
-+CONFIG_IP6_NF_RAW=m
-+CONFIG_IP6_NF_NAT=m
-+CONFIG_IP6_NF_TARGET_MASQUERADE=m
-+CONFIG_IP6_NF_TARGET_NPT=m
-+CONFIG_BRIDGE_NF_EBTABLES=m
-+CONFIG_BRIDGE_EBT_BROUTE=m
-+CONFIG_BRIDGE_EBT_T_FILTER=m
-+CONFIG_BRIDGE_EBT_T_NAT=m
-+CONFIG_BRIDGE_EBT_802_3=m
-+CONFIG_BRIDGE_EBT_AMONG=m
-+CONFIG_BRIDGE_EBT_ARP=m
-+CONFIG_BRIDGE_EBT_IP=m
-+CONFIG_BRIDGE_EBT_IP6=m
-+CONFIG_BRIDGE_EBT_LIMIT=m
-+CONFIG_BRIDGE_EBT_MARK=m
-+CONFIG_BRIDGE_EBT_PKTTYPE=m
-+CONFIG_BRIDGE_EBT_STP=m
-+CONFIG_BRIDGE_EBT_VLAN=m
-+CONFIG_BRIDGE_EBT_ARPREPLY=m
-+CONFIG_BRIDGE_EBT_DNAT=m
-+CONFIG_BRIDGE_EBT_MARK_T=m
-+CONFIG_BRIDGE_EBT_REDIRECT=m
-+CONFIG_BRIDGE_EBT_SNAT=m
-+CONFIG_BRIDGE_EBT_LOG=m
-+CONFIG_BRIDGE_EBT_NFLOG=m
-+CONFIG_SCTP_COOKIE_HMAC_SHA1=y
-+CONFIG_ATM=m
-+CONFIG_L2TP=m
-+CONFIG_L2TP_V3=y
-+CONFIG_L2TP_IP=m
-+CONFIG_L2TP_ETH=m
-+CONFIG_BRIDGE=m
-+CONFIG_VLAN_8021Q=m
-+CONFIG_VLAN_8021Q_GVRP=y
-+CONFIG_ATALK=m
-+CONFIG_6LOWPAN=m
-+CONFIG_IEEE802154=m
-+CONFIG_IEEE802154_6LOWPAN=m
-+CONFIG_MAC802154=m
-+CONFIG_NET_SCHED=y
-+CONFIG_NET_SCH_CBQ=m
-+CONFIG_NET_SCH_HTB=m
-+CONFIG_NET_SCH_HFSC=m
-+CONFIG_NET_SCH_PRIO=m
-+CONFIG_NET_SCH_MULTIQ=m
-+CONFIG_NET_SCH_RED=m
-+CONFIG_NET_SCH_SFB=m
-+CONFIG_NET_SCH_SFQ=m
-+CONFIG_NET_SCH_TEQL=m
-+CONFIG_NET_SCH_TBF=m
-+CONFIG_NET_SCH_GRED=m
-+CONFIG_NET_SCH_DSMARK=m
-+CONFIG_NET_SCH_NETEM=m
-+CONFIG_NET_SCH_DRR=m
-+CONFIG_NET_SCH_MQPRIO=m
-+CONFIG_NET_SCH_CHOKE=m
-+CONFIG_NET_SCH_QFQ=m
-+CONFIG_NET_SCH_CODEL=m
-+CONFIG_NET_SCH_FQ_CODEL=m
-+CONFIG_NET_SCH_INGRESS=m
-+CONFIG_NET_SCH_PLUG=m
-+CONFIG_NET_CLS_BASIC=m
-+CONFIG_NET_CLS_TCINDEX=m
-+CONFIG_NET_CLS_ROUTE4=m
-+CONFIG_NET_CLS_FW=m
-+CONFIG_NET_CLS_U32=m
-+CONFIG_CLS_U32_MARK=y
-+CONFIG_NET_CLS_RSVP=m
-+CONFIG_NET_CLS_RSVP6=m
-+CONFIG_NET_CLS_FLOW=m
-+CONFIG_NET_CLS_CGROUP=m
-+CONFIG_NET_EMATCH=y
-+CONFIG_NET_EMATCH_CMP=m
-+CONFIG_NET_EMATCH_NBYTE=m
-+CONFIG_NET_EMATCH_U32=m
-+CONFIG_NET_EMATCH_META=m
-+CONFIG_NET_EMATCH_TEXT=m
-+CONFIG_NET_EMATCH_IPSET=m
-+CONFIG_NET_CLS_ACT=y
-+CONFIG_NET_ACT_POLICE=m
-+CONFIG_NET_ACT_GACT=m
-+CONFIG_GACT_PROB=y
-+CONFIG_NET_ACT_MIRRED=m
-+CONFIG_NET_ACT_IPT=m
-+CONFIG_NET_ACT_NAT=m
-+CONFIG_NET_ACT_PEDIT=m
-+CONFIG_NET_ACT_SIMP=m
-+CONFIG_NET_ACT_SKBEDIT=m
-+CONFIG_NET_ACT_CSUM=m
-+CONFIG_BATMAN_ADV=m
-+CONFIG_OPENVSWITCH=m
-+CONFIG_NET_PKTGEN=m
-+CONFIG_HAMRADIO=y
-+CONFIG_AX25=m
-+CONFIG_NETROM=m
-+CONFIG_ROSE=m
-+CONFIG_MKISS=m
-+CONFIG_6PACK=m
-+CONFIG_BPQETHER=m
-+CONFIG_BAYCOM_SER_FDX=m
-+CONFIG_BAYCOM_SER_HDX=m
-+CONFIG_YAM=m
-+CONFIG_CAN=m
-+CONFIG_CAN_VCAN=m
-+CONFIG_CAN_MCP251X=m
-+CONFIG_IRDA=m
-+CONFIG_IRLAN=m
-+CONFIG_IRNET=m
-+CONFIG_IRCOMM=m
-+CONFIG_IRDA_ULTRA=y
-+CONFIG_IRDA_CACHE_LAST_LSAP=y
-+CONFIG_IRDA_FAST_RR=y
-+CONFIG_IRTTY_SIR=m
-+CONFIG_KINGSUN_DONGLE=m
-+CONFIG_KSDAZZLE_DONGLE=m
-+CONFIG_KS959_DONGLE=m
-+CONFIG_USB_IRDA=m
-+CONFIG_SIGMATEL_FIR=m
-+CONFIG_MCS_FIR=m
-+CONFIG_BT=m
-+CONFIG_BT_RFCOMM=m
-+CONFIG_BT_RFCOMM_TTY=y
-+CONFIG_BT_BNEP=m
-+CONFIG_BT_BNEP_MC_FILTER=y
-+CONFIG_BT_BNEP_PROTO_FILTER=y
-+CONFIG_BT_HIDP=m
-+CONFIG_BT_6LOWPAN=m
-+CONFIG_BT_HCIBTUSB=m
-+CONFIG_BT_HCIBCM203X=m
-+CONFIG_BT_HCIBPA10X=m
-+CONFIG_BT_HCIBFUSB=m
-+CONFIG_BT_HCIVHCI=m
-+CONFIG_BT_MRVL=m
-+CONFIG_BT_MRVL_SDIO=m
-+CONFIG_BT_ATH3K=m
-+CONFIG_BT_WILINK=m
-+CONFIG_MAC80211=m
-+CONFIG_MAC80211_MESH=y
-+CONFIG_WIMAX=m
-+CONFIG_RFKILL=m
-+CONFIG_RFKILL_INPUT=y
-+CONFIG_NET_9P=m
-+CONFIG_NFC=m
-+CONFIG_NFC_PN533=m
-+CONFIG_DEVTMPFS=y
-+CONFIG_DEVTMPFS_MOUNT=y
-+CONFIG_DMA_CMA=y
-+CONFIG_CMA_SIZE_MBYTES=5
-+CONFIG_MTD=m
-+CONFIG_MTD_BLOCK=m
-+CONFIG_MTD_NAND=m
-+CONFIG_MTD_UBI=m
-+CONFIG_ZRAM=m
-+CONFIG_ZRAM_LZ4_COMPRESS=y
-+CONFIG_BLK_DEV_LOOP=y
-+CONFIG_BLK_DEV_CRYPTOLOOP=m
-+CONFIG_BLK_DEV_DRBD=m
-+CONFIG_BLK_DEV_NBD=m
-+CONFIG_BLK_DEV_RAM=y
-+CONFIG_CDROM_PKTCDVD=m
-+CONFIG_ATA_OVER_ETH=m
-+CONFIG_EEPROM_AT24=m
-+CONFIG_TI_ST=m
-+CONFIG_SCSI=y
-+# CONFIG_SCSI_PROC_FS is not set
-+CONFIG_BLK_DEV_SD=y
-+CONFIG_CHR_DEV_ST=m
-+CONFIG_CHR_DEV_OSST=m
-+CONFIG_BLK_DEV_SR=m
-+CONFIG_CHR_DEV_SG=m
-+CONFIG_SCSI_ISCSI_ATTRS=y
-+CONFIG_ISCSI_TCP=m
-+CONFIG_ISCSI_BOOT_SYSFS=m
-+CONFIG_MD=y
-+CONFIG_MD_LINEAR=m
-+CONFIG_MD_RAID0=m
-+CONFIG_BLK_DEV_DM=m
-+CONFIG_DM_CRYPT=m
-+CONFIG_DM_SNAPSHOT=m
-+CONFIG_DM_THIN_PROVISIONING=m
-+CONFIG_DM_MIRROR=m
-+CONFIG_DM_LOG_USERSPACE=m
-+CONFIG_DM_RAID=m
-+CONFIG_DM_ZERO=m
-+CONFIG_DM_DELAY=m
-+CONFIG_NETDEVICES=y
-+CONFIG_BONDING=m
-+CONFIG_DUMMY=m
-+CONFIG_IFB=m
-+CONFIG_MACVLAN=m
-+CONFIG_NETCONSOLE=m
-+CONFIG_TUN=m
-+CONFIG_VETH=m
-+CONFIG_ENC28J60=m
-+CONFIG_MDIO_BITBANG=m
-+CONFIG_PPP=m
-+CONFIG_PPP_BSDCOMP=m
-+CONFIG_PPP_DEFLATE=m
-+CONFIG_PPP_FILTER=y
-+CONFIG_PPP_MPPE=m
-+CONFIG_PPP_MULTILINK=y
-+CONFIG_PPPOATM=m
-+CONFIG_PPPOE=m
-+CONFIG_PPPOL2TP=m
-+CONFIG_PPP_ASYNC=m
-+CONFIG_PPP_SYNC_TTY=m
-+CONFIG_SLIP=m
-+CONFIG_SLIP_COMPRESSED=y
-+CONFIG_SLIP_SMART=y
-+CONFIG_USB_CATC=m
-+CONFIG_USB_KAWETH=m
-+CONFIG_USB_PEGASUS=m
-+CONFIG_USB_RTL8150=m
-+CONFIG_USB_RTL8152=m
-+CONFIG_USB_USBNET=y
-+CONFIG_USB_NET_AX8817X=m
-+CONFIG_USB_NET_AX88179_178A=m
-+CONFIG_USB_NET_CDCETHER=m
-+CONFIG_USB_NET_CDC_EEM=m
-+CONFIG_USB_NET_CDC_NCM=m
-+CONFIG_USB_NET_HUAWEI_CDC_NCM=m
-+CONFIG_USB_NET_CDC_MBIM=m
-+CONFIG_USB_NET_DM9601=m
-+CONFIG_USB_NET_SR9700=m
-+CONFIG_USB_NET_SR9800=m
-+CONFIG_USB_NET_SMSC75XX=m
-+CONFIG_USB_NET_SMSC95XX=y
-+CONFIG_USB_NET_GL620A=m
-+CONFIG_USB_NET_NET1080=m
-+CONFIG_USB_NET_PLUSB=m
-+CONFIG_USB_NET_MCS7830=m
-+CONFIG_USB_NET_CDC_SUBSET=m
-+CONFIG_USB_ALI_M5632=y
-+CONFIG_USB_AN2720=y
-+CONFIG_USB_EPSON2888=y
-+CONFIG_USB_KC2190=y
-+CONFIG_USB_NET_ZAURUS=m
-+CONFIG_USB_NET_CX82310_ETH=m
-+CONFIG_USB_NET_KALMIA=m
-+CONFIG_USB_NET_QMI_WWAN=m
-+CONFIG_USB_HSO=m
-+CONFIG_USB_NET_INT51X1=m
-+CONFIG_USB_IPHETH=m
-+CONFIG_USB_SIERRA_NET=m
-+CONFIG_USB_VL600=m
-+CONFIG_LIBERTAS_THINFIRM=m
-+CONFIG_LIBERTAS_THINFIRM_USB=m
-+CONFIG_AT76C50X_USB=m
-+CONFIG_USB_ZD1201=m
-+CONFIG_USB_NET_RNDIS_WLAN=m
-+CONFIG_RTL8187=m
-+CONFIG_MAC80211_HWSIM=m
-+CONFIG_ATH_CARDS=m
-+CONFIG_ATH9K=m
-+CONFIG_ATH9K_HTC=m
-+CONFIG_CARL9170=m
-+CONFIG_ATH6KL=m
-+CONFIG_ATH6KL_USB=m
-+CONFIG_AR5523=m
-+CONFIG_B43=m
-+# CONFIG_B43_PHY_N is not set
-+CONFIG_B43LEGACY=m
-+CONFIG_BRCMFMAC=m
-+CONFIG_BRCMFMAC_USB=y
-+CONFIG_HOSTAP=m
-+CONFIG_LIBERTAS=m
-+CONFIG_LIBERTAS_USB=m
-+CONFIG_LIBERTAS_SDIO=m
-+CONFIG_P54_COMMON=m
-+CONFIG_P54_USB=m
-+CONFIG_RT2X00=m
-+CONFIG_RT2500USB=m
-+CONFIG_RT73USB=m
-+CONFIG_RT2800USB=m
-+CONFIG_RT2800USB_RT3573=y
-+CONFIG_RT2800USB_RT53XX=y
-+CONFIG_RT2800USB_RT55XX=y
-+CONFIG_RT2800USB_UNKNOWN=y
-+CONFIG_WL_MEDIATEK=y
-+CONFIG_MT7601U=m
-+CONFIG_RTL8192CU=m
-+CONFIG_ZD1211RW=m
-+CONFIG_MWIFIEX=m
-+CONFIG_MWIFIEX_SDIO=m
-+CONFIG_WIMAX_I2400M_USB=m
-+CONFIG_IEEE802154_AT86RF230=m
-+CONFIG_IEEE802154_MRF24J40=m
-+CONFIG_IEEE802154_CC2520=m
-+CONFIG_INPUT_POLLDEV=m
-+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-+CONFIG_INPUT_JOYDEV=m
-+CONFIG_INPUT_EVDEV=m
-+# CONFIG_KEYBOARD_ATKBD is not set
-+CONFIG_KEYBOARD_GPIO=m
-+# CONFIG_INPUT_MOUSE is not set
-+CONFIG_INPUT_JOYSTICK=y
-+CONFIG_JOYSTICK_IFORCE=m
-+CONFIG_JOYSTICK_IFORCE_USB=y
-+CONFIG_JOYSTICK_XPAD=m
-+CONFIG_JOYSTICK_XPAD_FF=y
-+CONFIG_JOYSTICK_RPISENSE=m
-+CONFIG_INPUT_TOUCHSCREEN=y
-+CONFIG_TOUCHSCREEN_ADS7846=m
-+CONFIG_TOUCHSCREEN_EGALAX=m
-+CONFIG_TOUCHSCREEN_FT6236=m
-+CONFIG_TOUCHSCREEN_RPI_FT5406=m
-+CONFIG_TOUCHSCREEN_USB_COMPOSITE=m
-+CONFIG_TOUCHSCREEN_STMPE=m
-+CONFIG_INPUT_MISC=y
-+CONFIG_INPUT_AD714X=m
-+CONFIG_INPUT_ATI_REMOTE2=m
-+CONFIG_INPUT_KEYSPAN_REMOTE=m
-+CONFIG_INPUT_POWERMATE=m
-+CONFIG_INPUT_YEALINK=m
-+CONFIG_INPUT_CM109=m
-+CONFIG_INPUT_UINPUT=m
-+CONFIG_INPUT_GPIO_ROTARY_ENCODER=m
-+CONFIG_INPUT_ADXL34X=m
-+CONFIG_INPUT_CMA3000=m
-+CONFIG_SERIO=m
-+CONFIG_SERIO_RAW=m
-+CONFIG_GAMEPORT=m
-+CONFIG_GAMEPORT_NS558=m
-+CONFIG_GAMEPORT_L4=m
-+CONFIG_BRCM_CHAR_DRIVERS=y
-+CONFIG_BCM_VC_CMA=y
-+CONFIG_BCM_VCIO=y
-+CONFIG_BCM_VC_SM=y
-+CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
-+# CONFIG_LEGACY_PTYS is not set
-+# CONFIG_DEVKMEM is not set
-+CONFIG_SERIAL_8250=y
-+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
-+CONFIG_SERIAL_8250_CONSOLE=y
-+# CONFIG_SERIAL_8250_DMA is not set
-+CONFIG_SERIAL_8250_NR_UARTS=1
-+CONFIG_SERIAL_8250_RUNTIME_UARTS=0
-+CONFIG_SERIAL_AMBA_PL011=y
-+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
-+CONFIG_SERIAL_OF_PLATFORM=y
-+CONFIG_TTY_PRINTK=y
-+CONFIG_HW_RANDOM=y
-+CONFIG_HW_RANDOM_BCM2835=y
-+CONFIG_RAW_DRIVER=y
-+CONFIG_I2C=y
-+CONFIG_I2C_CHARDEV=m
-+CONFIG_I2C_BCM2708=m
-+CONFIG_SPI=y
-+CONFIG_SPI_BCM2835=m
-+CONFIG_SPI_SPIDEV=y
-+CONFIG_PPS=m
-+CONFIG_PPS_CLIENT_LDISC=m
-+CONFIG_PPS_CLIENT_GPIO=m
-+CONFIG_GPIO_SYSFS=y
-+CONFIG_GPIO_ARIZONA=m
-+CONFIG_GPIO_STMPE=y
-+CONFIG_W1=m
-+CONFIG_W1_MASTER_DS2490=m
-+CONFIG_W1_MASTER_DS2482=m
-+CONFIG_W1_MASTER_DS1WM=m
-+CONFIG_W1_MASTER_GPIO=m
-+CONFIG_W1_SLAVE_THERM=m
-+CONFIG_W1_SLAVE_SMEM=m
-+CONFIG_W1_SLAVE_DS2408=m
-+CONFIG_W1_SLAVE_DS2413=m
-+CONFIG_W1_SLAVE_DS2406=m
-+CONFIG_W1_SLAVE_DS2423=m
-+CONFIG_W1_SLAVE_DS2431=m
-+CONFIG_W1_SLAVE_DS2433=m
-+CONFIG_W1_SLAVE_DS2760=m
-+CONFIG_W1_SLAVE_DS2780=m
-+CONFIG_W1_SLAVE_DS2781=m
-+CONFIG_W1_SLAVE_DS28E04=m
-+CONFIG_W1_SLAVE_BQ27000=m
-+CONFIG_BATTERY_DS2760=m
-+CONFIG_POWER_RESET=y
-+CONFIG_POWER_RESET_GPIO=y
-+CONFIG_HWMON=m
-+CONFIG_SENSORS_SHT21=m
-+CONFIG_SENSORS_SHTC1=m
-+CONFIG_THERMAL=y
-+CONFIG_THERMAL_BCM2835=y
-+CONFIG_WATCHDOG=y
-+CONFIG_BCM2835_WDT=m
-+CONFIG_UCB1400_CORE=m
-+CONFIG_MFD_STMPE=y
-+CONFIG_STMPE_SPI=y
-+CONFIG_MFD_ARIZONA_I2C=m
-+CONFIG_MFD_ARIZONA_SPI=m
-+CONFIG_MFD_WM5102=y
-+CONFIG_MEDIA_SUPPORT=m
-+CONFIG_MEDIA_CAMERA_SUPPORT=y
-+CONFIG_MEDIA_ANALOG_TV_SUPPORT=y
-+CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y
-+CONFIG_MEDIA_RADIO_SUPPORT=y
-+CONFIG_MEDIA_RC_SUPPORT=y
-+CONFIG_MEDIA_CONTROLLER=y
-+CONFIG_LIRC=m
-+CONFIG_RC_DEVICES=y
-+CONFIG_RC_ATI_REMOTE=m
-+CONFIG_IR_IMON=m
-+CONFIG_IR_MCEUSB=m
-+CONFIG_IR_REDRAT3=m
-+CONFIG_IR_STREAMZAP=m
-+CONFIG_IR_IGUANA=m
-+CONFIG_IR_TTUSBIR=m
-+CONFIG_RC_LOOPBACK=m
-+CONFIG_IR_GPIO_CIR=m
-+CONFIG_MEDIA_USB_SUPPORT=y
-+CONFIG_USB_VIDEO_CLASS=m
-+CONFIG_USB_M5602=m
-+CONFIG_USB_STV06XX=m
-+CONFIG_USB_GL860=m
-+CONFIG_USB_GSPCA_BENQ=m
-+CONFIG_USB_GSPCA_CONEX=m
-+CONFIG_USB_GSPCA_CPIA1=m
-+CONFIG_USB_GSPCA_DTCS033=m
-+CONFIG_USB_GSPCA_ETOMS=m
-+CONFIG_USB_GSPCA_FINEPIX=m
-+CONFIG_USB_GSPCA_JEILINJ=m
-+CONFIG_USB_GSPCA_JL2005BCD=m
-+CONFIG_USB_GSPCA_KINECT=m
-+CONFIG_USB_GSPCA_KONICA=m
-+CONFIG_USB_GSPCA_MARS=m
-+CONFIG_USB_GSPCA_MR97310A=m
-+CONFIG_USB_GSPCA_NW80X=m
-+CONFIG_USB_GSPCA_OV519=m
-+CONFIG_USB_GSPCA_OV534=m
-+CONFIG_USB_GSPCA_OV534_9=m
-+CONFIG_USB_GSPCA_PAC207=m
-+CONFIG_USB_GSPCA_PAC7302=m
-+CONFIG_USB_GSPCA_PAC7311=m
-+CONFIG_USB_GSPCA_SE401=m
-+CONFIG_USB_GSPCA_SN9C2028=m
-+CONFIG_USB_GSPCA_SN9C20X=m
-+CONFIG_USB_GSPCA_SONIXB=m
-+CONFIG_USB_GSPCA_SONIXJ=m
-+CONFIG_USB_GSPCA_SPCA500=m
-+CONFIG_USB_GSPCA_SPCA501=m
-+CONFIG_USB_GSPCA_SPCA505=m
-+CONFIG_USB_GSPCA_SPCA506=m
-+CONFIG_USB_GSPCA_SPCA508=m
-+CONFIG_USB_GSPCA_SPCA561=m
-+CONFIG_USB_GSPCA_SPCA1528=m
-+CONFIG_USB_GSPCA_SQ905=m
-+CONFIG_USB_GSPCA_SQ905C=m
-+CONFIG_USB_GSPCA_SQ930X=m
-+CONFIG_USB_GSPCA_STK014=m
-+CONFIG_USB_GSPCA_STK1135=m
-+CONFIG_USB_GSPCA_STV0680=m
-+CONFIG_USB_GSPCA_SUNPLUS=m
-+CONFIG_USB_GSPCA_T613=m
-+CONFIG_USB_GSPCA_TOPRO=m
-+CONFIG_USB_GSPCA_TV8532=m
-+CONFIG_USB_GSPCA_VC032X=m
-+CONFIG_USB_GSPCA_VICAM=m
-+CONFIG_USB_GSPCA_XIRLINK_CIT=m
-+CONFIG_USB_GSPCA_ZC3XX=m
-+CONFIG_USB_PWC=m
-+CONFIG_VIDEO_CPIA2=m
-+CONFIG_USB_ZR364XX=m
-+CONFIG_USB_STKWEBCAM=m
-+CONFIG_USB_S2255=m
-+CONFIG_VIDEO_USBTV=m
-+CONFIG_VIDEO_PVRUSB2=m
-+CONFIG_VIDEO_HDPVR=m
-+CONFIG_VIDEO_USBVISION=m
-+CONFIG_VIDEO_STK1160_COMMON=m
-+CONFIG_VIDEO_STK1160_AC97=y
-+CONFIG_VIDEO_GO7007=m
-+CONFIG_VIDEO_GO7007_USB=m
-+CONFIG_VIDEO_GO7007_USB_S2250_BOARD=m
-+CONFIG_VIDEO_AU0828=m
-+CONFIG_VIDEO_AU0828_RC=y
-+CONFIG_VIDEO_CX231XX=m
-+CONFIG_VIDEO_CX231XX_ALSA=m
-+CONFIG_VIDEO_CX231XX_DVB=m
-+CONFIG_VIDEO_TM6000=m
-+CONFIG_VIDEO_TM6000_ALSA=m
-+CONFIG_VIDEO_TM6000_DVB=m
-+CONFIG_DVB_USB=m
-+CONFIG_DVB_USB_A800=m
-+CONFIG_DVB_USB_DIBUSB_MB=m
-+CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y
-+CONFIG_DVB_USB_DIBUSB_MC=m
-+CONFIG_DVB_USB_DIB0700=m
-+CONFIG_DVB_USB_UMT_010=m
-+CONFIG_DVB_USB_CXUSB=m
-+CONFIG_DVB_USB_M920X=m
-+CONFIG_DVB_USB_DIGITV=m
-+CONFIG_DVB_USB_VP7045=m
-+CONFIG_DVB_USB_VP702X=m
-+CONFIG_DVB_USB_GP8PSK=m
-+CONFIG_DVB_USB_NOVA_T_USB2=m
-+CONFIG_DVB_USB_TTUSB2=m
-+CONFIG_DVB_USB_DTT200U=m
-+CONFIG_DVB_USB_OPERA1=m
-+CONFIG_DVB_USB_AF9005=m
-+CONFIG_DVB_USB_AF9005_REMOTE=m
-+CONFIG_DVB_USB_PCTV452E=m
-+CONFIG_DVB_USB_DW2102=m
-+CONFIG_DVB_USB_CINERGY_T2=m
-+CONFIG_DVB_USB_DTV5100=m
-+CONFIG_DVB_USB_FRIIO=m
-+CONFIG_DVB_USB_AZ6027=m
-+CONFIG_DVB_USB_TECHNISAT_USB2=m
-+CONFIG_DVB_USB_V2=m
-+CONFIG_DVB_USB_AF9015=m
-+CONFIG_DVB_USB_AF9035=m
-+CONFIG_DVB_USB_ANYSEE=m
-+CONFIG_DVB_USB_AU6610=m
-+CONFIG_DVB_USB_AZ6007=m
-+CONFIG_DVB_USB_CE6230=m
-+CONFIG_DVB_USB_EC168=m
-+CONFIG_DVB_USB_GL861=m
-+CONFIG_DVB_USB_LME2510=m
-+CONFIG_DVB_USB_MXL111SF=m
-+CONFIG_DVB_USB_RTL28XXU=m
-+CONFIG_DVB_USB_DVBSKY=m
-+CONFIG_SMS_USB_DRV=m
-+CONFIG_DVB_B2C2_FLEXCOP_USB=m
-+CONFIG_DVB_AS102=m
-+CONFIG_VIDEO_EM28XX=m
-+CONFIG_VIDEO_EM28XX_V4L2=m
-+CONFIG_VIDEO_EM28XX_ALSA=m
-+CONFIG_VIDEO_EM28XX_DVB=m
-+CONFIG_V4L_PLATFORM_DRIVERS=y
-+CONFIG_VIDEO_BCM2835=y
-+CONFIG_VIDEO_BCM2835_MMAL=m
-+CONFIG_RADIO_SI470X=y
-+CONFIG_USB_SI470X=m
-+CONFIG_I2C_SI470X=m
-+CONFIG_RADIO_SI4713=m
-+CONFIG_I2C_SI4713=m
-+CONFIG_USB_MR800=m
-+CONFIG_USB_DSBR=m
-+CONFIG_RADIO_SHARK=m
-+CONFIG_RADIO_SHARK2=m
-+CONFIG_USB_KEENE=m
-+CONFIG_USB_MA901=m
-+CONFIG_RADIO_TEA5764=m
-+CONFIG_RADIO_SAA7706H=m
-+CONFIG_RADIO_TEF6862=m
-+CONFIG_RADIO_WL1273=m
-+CONFIG_RADIO_WL128X=m
-+# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
-+CONFIG_VIDEO_UDA1342=m
-+CONFIG_VIDEO_SONY_BTF_MPX=m
-+CONFIG_VIDEO_TVP5150=m
-+CONFIG_VIDEO_TW2804=m
-+CONFIG_VIDEO_TW9903=m
-+CONFIG_VIDEO_TW9906=m
-+CONFIG_VIDEO_OV7640=m
-+CONFIG_VIDEO_MT9V011=m
-+CONFIG_FB=y
-+CONFIG_FB_BCM2708=y
-+CONFIG_FB_UDL=m
-+CONFIG_FB_SSD1307=m
-+CONFIG_FB_RPISENSE=m
-+# CONFIG_BACKLIGHT_GENERIC is not set
-+CONFIG_BACKLIGHT_GPIO=m
-+CONFIG_FRAMEBUFFER_CONSOLE=y
-+CONFIG_LOGO=y
-+# CONFIG_LOGO_LINUX_MONO is not set
-+# CONFIG_LOGO_LINUX_VGA16 is not set
-+CONFIG_SOUND=y
-+CONFIG_SND=m
-+CONFIG_SND_SEQUENCER=m
-+CONFIG_SND_SEQ_DUMMY=m
-+CONFIG_SND_MIXER_OSS=m
-+CONFIG_SND_PCM_OSS=m
-+CONFIG_SND_SEQUENCER_OSS=y
-+CONFIG_SND_HRTIMER=m
-+CONFIG_SND_DUMMY=m
-+CONFIG_SND_ALOOP=m
-+CONFIG_SND_VIRMIDI=m
-+CONFIG_SND_MTPAV=m
-+CONFIG_SND_SERIAL_U16550=m
-+CONFIG_SND_MPU401=m
-+CONFIG_SND_BCM2835=m
-+CONFIG_SND_USB_AUDIO=m
-+CONFIG_SND_USB_UA101=m
-+CONFIG_SND_USB_CAIAQ=m
-+CONFIG_SND_USB_CAIAQ_INPUT=y
-+CONFIG_SND_USB_6FIRE=m
-+CONFIG_SND_SOC=m
-+CONFIG_SND_BCM2835_SOC_I2S=m
-+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC=m
-+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS=m
-+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI=m
-+CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP=m
-+CONFIG_SND_BCM2708_SOC_RPI_DAC=m
-+CONFIG_SND_BCM2708_SOC_RPI_PROTO=m
-+CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m
-+CONFIG_SND_BCM2708_SOC_RASPIDAC3=m
-+CONFIG_SND_SOC_ADAU1701=m
-+CONFIG_SND_SOC_WM8804_I2C=m
-+CONFIG_SND_SIMPLE_CARD=m
-+CONFIG_SOUND_PRIME=m
-+CONFIG_HIDRAW=y
-+CONFIG_UHID=m
-+CONFIG_HID_A4TECH=m
-+CONFIG_HID_ACRUX=m
-+CONFIG_HID_APPLE=m
-+CONFIG_HID_BELKIN=m
-+CONFIG_HID_CHERRY=m
-+CONFIG_HID_CHICONY=m
-+CONFIG_HID_CYPRESS=m
-+CONFIG_HID_DRAGONRISE=m
-+CONFIG_HID_EMS_FF=m
-+CONFIG_HID_ELECOM=m
-+CONFIG_HID_ELO=m
-+CONFIG_HID_EZKEY=m
-+CONFIG_HID_HOLTEK=m
-+CONFIG_HID_KEYTOUCH=m
-+CONFIG_HID_KYE=m
-+CONFIG_HID_UCLOGIC=m
-+CONFIG_HID_WALTOP=m
-+CONFIG_HID_GYRATION=m
-+CONFIG_HID_TWINHAN=m
-+CONFIG_HID_KENSINGTON=m
-+CONFIG_HID_LCPOWER=m
-+CONFIG_HID_LOGITECH=m
-+CONFIG_HID_MAGICMOUSE=m
-+CONFIG_HID_MICROSOFT=m
-+CONFIG_HID_MONTEREY=m
-+CONFIG_HID_MULTITOUCH=m
-+CONFIG_HID_NTRIG=m
-+CONFIG_HID_ORTEK=m
-+CONFIG_HID_PANTHERLORD=m
-+CONFIG_HID_PETALYNX=m
-+CONFIG_HID_PICOLCD=m
-+CONFIG_HID_ROCCAT=m
-+CONFIG_HID_SAMSUNG=m
-+CONFIG_HID_SONY=m
-+CONFIG_HID_SPEEDLINK=m
-+CONFIG_HID_SUNPLUS=m
-+CONFIG_HID_GREENASIA=m
-+CONFIG_HID_SMARTJOYPLUS=m
-+CONFIG_HID_TOPSEED=m
-+CONFIG_HID_THINGM=m
-+CONFIG_HID_THRUSTMASTER=m
-+CONFIG_HID_WACOM=m
-+CONFIG_HID_WIIMOTE=m
-+CONFIG_HID_XINMO=m
-+CONFIG_HID_ZEROPLUS=m
-+CONFIG_HID_ZYDACRON=m
-+CONFIG_HID_PID=y
-+CONFIG_USB_HIDDEV=y
-+CONFIG_USB=y
-+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
-+CONFIG_USB_MON=m
-+CONFIG_USB_DWCOTG=y
-+CONFIG_USB_PRINTER=m
-+CONFIG_USB_STORAGE=y
-+CONFIG_USB_STORAGE_REALTEK=m
-+CONFIG_USB_STORAGE_DATAFAB=m
-+CONFIG_USB_STORAGE_FREECOM=m
-+CONFIG_USB_STORAGE_ISD200=m
-+CONFIG_USB_STORAGE_USBAT=m
-+CONFIG_USB_STORAGE_SDDR09=m
-+CONFIG_USB_STORAGE_SDDR55=m
-+CONFIG_USB_STORAGE_JUMPSHOT=m
-+CONFIG_USB_STORAGE_ALAUDA=m
-+CONFIG_USB_STORAGE_ONETOUCH=m
-+CONFIG_USB_STORAGE_KARMA=m
-+CONFIG_USB_STORAGE_CYPRESS_ATACB=m
-+CONFIG_USB_STORAGE_ENE_UB6250=m
-+CONFIG_USB_MDC800=m
-+CONFIG_USB_MICROTEK=m
-+CONFIG_USBIP_CORE=m
-+CONFIG_USBIP_VHCI_HCD=m
-+CONFIG_USBIP_HOST=m
-+CONFIG_USB_SERIAL=m
-+CONFIG_USB_SERIAL_GENERIC=y
-+CONFIG_USB_SERIAL_AIRCABLE=m
-+CONFIG_USB_SERIAL_ARK3116=m
-+CONFIG_USB_SERIAL_BELKIN=m
-+CONFIG_USB_SERIAL_CH341=m
-+CONFIG_USB_SERIAL_WHITEHEAT=m
-+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
-+CONFIG_USB_SERIAL_CP210X=m
-+CONFIG_USB_SERIAL_CYPRESS_M8=m
-+CONFIG_USB_SERIAL_EMPEG=m
-+CONFIG_USB_SERIAL_FTDI_SIO=m
-+CONFIG_USB_SERIAL_VISOR=m
-+CONFIG_USB_SERIAL_IPAQ=m
-+CONFIG_USB_SERIAL_IR=m
-+CONFIG_USB_SERIAL_EDGEPORT=m
-+CONFIG_USB_SERIAL_EDGEPORT_TI=m
-+CONFIG_USB_SERIAL_F81232=m
-+CONFIG_USB_SERIAL_GARMIN=m
-+CONFIG_USB_SERIAL_IPW=m
-+CONFIG_USB_SERIAL_IUU=m
-+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
-+CONFIG_USB_SERIAL_KEYSPAN=m
-+CONFIG_USB_SERIAL_KLSI=m
-+CONFIG_USB_SERIAL_KOBIL_SCT=m
-+CONFIG_USB_SERIAL_MCT_U232=m
-+CONFIG_USB_SERIAL_METRO=m
-+CONFIG_USB_SERIAL_MOS7720=m
-+CONFIG_USB_SERIAL_MOS7840=m
-+CONFIG_USB_SERIAL_NAVMAN=m
-+CONFIG_USB_SERIAL_PL2303=m
-+CONFIG_USB_SERIAL_OTI6858=m
-+CONFIG_USB_SERIAL_QCAUX=m
-+CONFIG_USB_SERIAL_QUALCOMM=m
-+CONFIG_USB_SERIAL_SPCP8X5=m
-+CONFIG_USB_SERIAL_SAFE=m
-+CONFIG_USB_SERIAL_SIERRAWIRELESS=m
-+CONFIG_USB_SERIAL_SYMBOL=m
-+CONFIG_USB_SERIAL_TI=m
-+CONFIG_USB_SERIAL_CYBERJACK=m
-+CONFIG_USB_SERIAL_XIRCOM=m
-+CONFIG_USB_SERIAL_OPTION=m
-+CONFIG_USB_SERIAL_OMNINET=m
-+CONFIG_USB_SERIAL_OPTICON=m
-+CONFIG_USB_SERIAL_XSENS_MT=m
-+CONFIG_USB_SERIAL_WISHBONE=m
-+CONFIG_USB_SERIAL_SSU100=m
-+CONFIG_USB_SERIAL_QT2=m
-+CONFIG_USB_SERIAL_DEBUG=m
-+CONFIG_USB_EMI62=m
-+CONFIG_USB_EMI26=m
-+CONFIG_USB_ADUTUX=m
-+CONFIG_USB_SEVSEG=m
-+CONFIG_USB_RIO500=m
-+CONFIG_USB_LEGOTOWER=m
-+CONFIG_USB_LCD=m
-+CONFIG_USB_LED=m
-+CONFIG_USB_CYPRESS_CY7C63=m
-+CONFIG_USB_CYTHERM=m
-+CONFIG_USB_IDMOUSE=m
-+CONFIG_USB_FTDI_ELAN=m
-+CONFIG_USB_APPLEDISPLAY=m
-+CONFIG_USB_LD=m
-+CONFIG_USB_TRANCEVIBRATOR=m
-+CONFIG_USB_IOWARRIOR=m
-+CONFIG_USB_TEST=m
-+CONFIG_USB_ISIGHTFW=m
-+CONFIG_USB_YUREX=m
-+CONFIG_USB_ATM=m
-+CONFIG_USB_SPEEDTOUCH=m
-+CONFIG_USB_CXACRU=m
-+CONFIG_USB_UEAGLEATM=m
-+CONFIG_USB_XUSBATM=m
-+CONFIG_MMC=y
-+CONFIG_MMC_BLOCK_MINORS=32
-+CONFIG_MMC_BCM2835=y
-+CONFIG_MMC_BCM2835_DMA=y
-+CONFIG_MMC_BCM2835_SDHOST=y
-+CONFIG_MMC_SDHCI=y
-+CONFIG_MMC_SDHCI_PLTFM=y
-+CONFIG_MMC_SPI=m
-+CONFIG_LEDS_CLASS=y
-+CONFIG_LEDS_GPIO=y
-+CONFIG_LEDS_TRIGGER_TIMER=y
-+CONFIG_LEDS_TRIGGER_ONESHOT=y
-+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
-+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
-+CONFIG_LEDS_TRIGGER_CPU=y
-+CONFIG_LEDS_TRIGGER_GPIO=y
-+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
-+CONFIG_LEDS_TRIGGER_TRANSIENT=m
-+CONFIG_LEDS_TRIGGER_CAMERA=m
-+CONFIG_LEDS_TRIGGER_INPUT=y
-+CONFIG_RTC_CLASS=y
-+# CONFIG_RTC_HCTOSYS is not set
-+CONFIG_RTC_DRV_DS1307=m
-+CONFIG_RTC_DRV_DS1374=m
-+CONFIG_RTC_DRV_DS1672=m
-+CONFIG_RTC_DRV_DS3232=m
-+CONFIG_RTC_DRV_MAX6900=m
-+CONFIG_RTC_DRV_RS5C372=m
-+CONFIG_RTC_DRV_ISL1208=m
-+CONFIG_RTC_DRV_ISL12022=m
-+CONFIG_RTC_DRV_ISL12057=m
-+CONFIG_RTC_DRV_X1205=m
-+CONFIG_RTC_DRV_PCF2127=m
-+CONFIG_RTC_DRV_PCF8523=m
-+CONFIG_RTC_DRV_PCF8563=m
-+CONFIG_RTC_DRV_PCF8583=m
-+CONFIG_RTC_DRV_M41T80=m
-+CONFIG_RTC_DRV_BQ32K=m
-+CONFIG_RTC_DRV_S35390A=m
-+CONFIG_RTC_DRV_FM3130=m
-+CONFIG_RTC_DRV_RX8581=m
-+CONFIG_RTC_DRV_RX8025=m
-+CONFIG_RTC_DRV_EM3027=m
-+CONFIG_RTC_DRV_RV3029C2=m
-+CONFIG_RTC_DRV_M41T93=m
-+CONFIG_RTC_DRV_M41T94=m
-+CONFIG_RTC_DRV_DS1305=m
-+CONFIG_RTC_DRV_DS1390=m
-+CONFIG_RTC_DRV_MAX6902=m
-+CONFIG_RTC_DRV_R9701=m
-+CONFIG_RTC_DRV_RS5C348=m
-+CONFIG_RTC_DRV_DS3234=m
-+CONFIG_RTC_DRV_PCF2123=m
-+CONFIG_RTC_DRV_RX4581=m
-+CONFIG_DMADEVICES=y
-+CONFIG_DMA_BCM2835=y
-+CONFIG_DMA_BCM2708=y
-+CONFIG_UIO=m
-+CONFIG_UIO_PDRV_GENIRQ=m
-+CONFIG_STAGING=y
-+CONFIG_PRISM2_USB=m
-+CONFIG_R8712U=m
-+CONFIG_R8188EU=m
-+CONFIG_R8723AU=m
-+CONFIG_VT6656=m
-+CONFIG_SPEAKUP=m
-+CONFIG_SPEAKUP_SYNTH_SOFT=m
-+CONFIG_STAGING_MEDIA=y
-+CONFIG_LIRC_STAGING=y
-+CONFIG_LIRC_IMON=m
-+CONFIG_LIRC_RPI=m
-+CONFIG_LIRC_SASEM=m
-+CONFIG_LIRC_SERIAL=m
-+CONFIG_FB_TFT=m
-+CONFIG_FB_TFT_AGM1264K_FL=m
-+CONFIG_FB_TFT_BD663474=m
-+CONFIG_FB_TFT_HX8340BN=m
-+CONFIG_FB_TFT_HX8347D=m
-+CONFIG_FB_TFT_HX8353D=m
-+CONFIG_FB_TFT_ILI9163=m
-+CONFIG_FB_TFT_ILI9320=m
-+CONFIG_FB_TFT_ILI9325=m
-+CONFIG_FB_TFT_ILI9340=m
-+CONFIG_FB_TFT_ILI9341=m
-+CONFIG_FB_TFT_ILI9481=m
-+CONFIG_FB_TFT_ILI9486=m
-+CONFIG_FB_TFT_PCD8544=m
-+CONFIG_FB_TFT_RA8875=m
-+CONFIG_FB_TFT_S6D02A1=m
-+CONFIG_FB_TFT_S6D1121=m
-+CONFIG_FB_TFT_SSD1289=m
-+CONFIG_FB_TFT_SSD1306=m
-+CONFIG_FB_TFT_SSD1331=m
-+CONFIG_FB_TFT_SSD1351=m
-+CONFIG_FB_TFT_ST7735R=m
-+CONFIG_FB_TFT_TINYLCD=m
-+CONFIG_FB_TFT_TLS8204=m
-+CONFIG_FB_TFT_UC1701=m
-+CONFIG_FB_TFT_UPD161704=m
-+CONFIG_FB_TFT_WATTEROTT=m
-+CONFIG_FB_FLEX=m
-+CONFIG_FB_TFT_FBTFT_DEVICE=m
-+CONFIG_MAILBOX=y
-+CONFIG_BCM2835_MBOX=y
-+# CONFIG_IOMMU_SUPPORT is not set
-+CONFIG_EXTCON=m
-+CONFIG_EXTCON_ARIZONA=m
-+CONFIG_IIO=m
-+CONFIG_IIO_BUFFER=y
-+CONFIG_IIO_BUFFER_CB=y
-+CONFIG_IIO_KFIFO_BUF=m
-+CONFIG_MCP320X=m
-+CONFIG_DHT11=m
-+CONFIG_PWM_BCM2835=m
-+CONFIG_RASPBERRYPI_FIRMWARE=y
-+CONFIG_EXT4_FS=y
-+CONFIG_EXT4_FS_POSIX_ACL=y
-+CONFIG_EXT4_FS_SECURITY=y
-+CONFIG_REISERFS_FS=m
-+CONFIG_REISERFS_FS_XATTR=y
-+CONFIG_REISERFS_FS_POSIX_ACL=y
-+CONFIG_REISERFS_FS_SECURITY=y
-+CONFIG_JFS_FS=m
-+CONFIG_JFS_POSIX_ACL=y
-+CONFIG_JFS_SECURITY=y
-+CONFIG_JFS_STATISTICS=y
-+CONFIG_XFS_FS=m
-+CONFIG_XFS_QUOTA=y
-+CONFIG_XFS_POSIX_ACL=y
-+CONFIG_XFS_RT=y
-+CONFIG_GFS2_FS=m
-+CONFIG_OCFS2_FS=m
-+CONFIG_BTRFS_FS=m
-+CONFIG_BTRFS_FS_POSIX_ACL=y
-+CONFIG_NILFS2_FS=m
-+CONFIG_F2FS_FS=y
-+CONFIG_FANOTIFY=y
-+CONFIG_QFMT_V1=m
-+CONFIG_QFMT_V2=m
-+CONFIG_AUTOFS4_FS=y
-+CONFIG_FUSE_FS=m
-+CONFIG_CUSE=m
-+CONFIG_OVERLAY_FS=m
-+CONFIG_FSCACHE=y
-+CONFIG_FSCACHE_STATS=y
-+CONFIG_FSCACHE_HISTOGRAM=y
-+CONFIG_CACHEFILES=y
-+CONFIG_ISO9660_FS=m
-+CONFIG_JOLIET=y
-+CONFIG_ZISOFS=y
-+CONFIG_UDF_FS=m
-+CONFIG_MSDOS_FS=y
-+CONFIG_VFAT_FS=y
-+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
-+CONFIG_NTFS_FS=m
-+CONFIG_NTFS_RW=y
-+CONFIG_TMPFS=y
-+CONFIG_TMPFS_POSIX_ACL=y
-+CONFIG_CONFIGFS_FS=y
-+CONFIG_ECRYPT_FS=m
-+CONFIG_HFS_FS=m
-+CONFIG_HFSPLUS_FS=m
-+CONFIG_JFFS2_FS=m
-+CONFIG_JFFS2_SUMMARY=y
-+CONFIG_UBIFS_FS=m
-+CONFIG_SQUASHFS=m
-+CONFIG_SQUASHFS_XATTR=y
-+CONFIG_SQUASHFS_LZO=y
-+CONFIG_SQUASHFS_XZ=y
-+CONFIG_NFS_FS=y
-+CONFIG_NFS_V3_ACL=y
-+CONFIG_NFS_V4=y
-+CONFIG_NFS_SWAP=y
-+CONFIG_ROOT_NFS=y
-+CONFIG_NFS_FSCACHE=y
-+CONFIG_NFSD=m
-+CONFIG_NFSD_V3_ACL=y
-+CONFIG_NFSD_V4=y
-+CONFIG_CIFS=m
-+CONFIG_CIFS_WEAK_PW_HASH=y
-+CONFIG_CIFS_UPCALL=y
-+CONFIG_CIFS_XATTR=y
-+CONFIG_CIFS_POSIX=y
-+CONFIG_CIFS_ACL=y
-+CONFIG_CIFS_DFS_UPCALL=y
-+CONFIG_CIFS_SMB2=y
-+CONFIG_CIFS_FSCACHE=y
-+CONFIG_9P_FS=m
-+CONFIG_9P_FS_POSIX_ACL=y
-+CONFIG_NLS_DEFAULT="utf8"
-+CONFIG_NLS_CODEPAGE_437=y
-+CONFIG_NLS_CODEPAGE_737=m
-+CONFIG_NLS_CODEPAGE_775=m
-+CONFIG_NLS_CODEPAGE_850=m
-+CONFIG_NLS_CODEPAGE_852=m
-+CONFIG_NLS_CODEPAGE_855=m
-+CONFIG_NLS_CODEPAGE_857=m
-+CONFIG_NLS_CODEPAGE_860=m
-+CONFIG_NLS_CODEPAGE_861=m
-+CONFIG_NLS_CODEPAGE_862=m
-+CONFIG_NLS_CODEPAGE_863=m
-+CONFIG_NLS_CODEPAGE_864=m
-+CONFIG_NLS_CODEPAGE_865=m
-+CONFIG_NLS_CODEPAGE_866=m
-+CONFIG_NLS_CODEPAGE_869=m
-+CONFIG_NLS_CODEPAGE_936=m
-+CONFIG_NLS_CODEPAGE_950=m
-+CONFIG_NLS_CODEPAGE_932=m
-+CONFIG_NLS_CODEPAGE_949=m
-+CONFIG_NLS_CODEPAGE_874=m
-+CONFIG_NLS_ISO8859_8=m
-+CONFIG_NLS_CODEPAGE_1250=m
-+CONFIG_NLS_CODEPAGE_1251=m
-+CONFIG_NLS_ASCII=y
-+CONFIG_NLS_ISO8859_1=m
-+CONFIG_NLS_ISO8859_2=m
-+CONFIG_NLS_ISO8859_3=m
-+CONFIG_NLS_ISO8859_4=m
-+CONFIG_NLS_ISO8859_5=m
-+CONFIG_NLS_ISO8859_6=m
-+CONFIG_NLS_ISO8859_7=m
-+CONFIG_NLS_ISO8859_9=m
-+CONFIG_NLS_ISO8859_13=m
-+CONFIG_NLS_ISO8859_14=m
-+CONFIG_NLS_ISO8859_15=m
-+CONFIG_NLS_KOI8_R=m
-+CONFIG_NLS_KOI8_U=m
-+CONFIG_DLM=m
-+CONFIG_PRINTK_TIME=y
-+CONFIG_BOOT_PRINTK_DELAY=y
-+CONFIG_DEBUG_MEMORY_INIT=y
-+CONFIG_DETECT_HUNG_TASK=y
-+CONFIG_TIMER_STATS=y
-+CONFIG_IRQSOFF_TRACER=y
-+CONFIG_SCHED_TRACER=y
-+CONFIG_STACK_TRACER=y
-+CONFIG_BLK_DEV_IO_TRACE=y
-+# CONFIG_KPROBE_EVENT is not set
-+CONFIG_FUNCTION_PROFILER=y
-+CONFIG_KGDB=y
-+CONFIG_KGDB_KDB=y
-+CONFIG_KDB_KEYBOARD=y
-+CONFIG_CRYPTO_USER=m
-+CONFIG_CRYPTO_CBC=y
-+CONFIG_CRYPTO_CTS=m
-+CONFIG_CRYPTO_XTS=m
-+CONFIG_CRYPTO_XCBC=m
-+CONFIG_CRYPTO_TGR192=m
-+CONFIG_CRYPTO_WP512=m
-+CONFIG_CRYPTO_CAST5=m
-+CONFIG_CRYPTO_DES=y
-+CONFIG_CRYPTO_USER_API_SKCIPHER=m
-+# CONFIG_CRYPTO_HW is not set
-+CONFIG_ARM_CRYPTO=y
-+CONFIG_CRYPTO_SHA1_ARM_NEON=m
-+CONFIG_CRYPTO_AES_ARM_BS=m
-+CONFIG_CRC_ITU_T=y
-+CONFIG_LIBCRC32C=y
---- /dev/null
-+++ b/arch/arm/configs/bcmrpi_defconfig
-@@ -0,0 +1,1265 @@
-+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
-+CONFIG_PHYS_OFFSET=0
-+# CONFIG_LOCALVERSION_AUTO is not set
-+CONFIG_SYSVIPC=y
-+CONFIG_POSIX_MQUEUE=y
-+CONFIG_FHANDLE=y
-+CONFIG_NO_HZ=y
-+CONFIG_HIGH_RES_TIMERS=y
-+CONFIG_BSD_PROCESS_ACCT=y
-+CONFIG_BSD_PROCESS_ACCT_V3=y
-+CONFIG_TASKSTATS=y
-+CONFIG_TASK_DELAY_ACCT=y
-+CONFIG_TASK_XACCT=y
-+CONFIG_TASK_IO_ACCOUNTING=y
-+CONFIG_IKCONFIG=m
-+CONFIG_IKCONFIG_PROC=y
-+CONFIG_CGROUP_FREEZER=y
-+CONFIG_CGROUP_DEVICE=y
-+CONFIG_CPUSETS=y
-+CONFIG_CGROUP_CPUACCT=y
-+CONFIG_MEMCG=y
-+CONFIG_BLK_CGROUP=y
-+CONFIG_NAMESPACES=y
-+CONFIG_SCHED_AUTOGROUP=y
-+CONFIG_BLK_DEV_INITRD=y
-+CONFIG_EMBEDDED=y
-+# CONFIG_COMPAT_BRK is not set
-+CONFIG_PROFILING=y
-+CONFIG_OPROFILE=m
-+CONFIG_KPROBES=y
-+CONFIG_JUMP_LABEL=y
-+CONFIG_MODULES=y
-+CONFIG_MODULE_UNLOAD=y
-+CONFIG_MODVERSIONS=y
-+CONFIG_MODULE_SRCVERSION_ALL=y
-+CONFIG_BLK_DEV_THROTTLING=y
-+CONFIG_PARTITION_ADVANCED=y
-+CONFIG_MAC_PARTITION=y
-+CONFIG_CFQ_GROUP_IOSCHED=y
-+CONFIG_ARCH_BCM2708=y
-+CONFIG_PREEMPT_VOLUNTARY=y
-+CONFIG_AEABI=y
-+CONFIG_OABI_COMPAT=y
-+# CONFIG_CPU_SW_DOMAIN_PAN is not set
-+CONFIG_CLEANCACHE=y
-+CONFIG_FRONTSWAP=y
-+CONFIG_CMA=y
-+CONFIG_ZSMALLOC=m
-+CONFIG_PGTABLE_MAPPING=y
-+CONFIG_UACCESS_WITH_MEMCPY=y
-+CONFIG_SECCOMP=y
-+# CONFIG_ATAGS is not set
-+CONFIG_ZBOOT_ROM_TEXT=0x0
-+CONFIG_ZBOOT_ROM_BSS=0x0
-+CONFIG_CMDLINE="console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait"
-+CONFIG_CPU_FREQ=y
-+CONFIG_CPU_FREQ_STAT=m
-+CONFIG_CPU_FREQ_STAT_DETAILS=y
-+CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE=y
-+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
-+CONFIG_CPU_FREQ_GOV_USERSPACE=y
-+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
-+CONFIG_VFP=y
-+CONFIG_BINFMT_MISC=m
-+# CONFIG_SUSPEND is not set
-+CONFIG_NET=y
-+CONFIG_PACKET=y
-+CONFIG_UNIX=y
-+CONFIG_XFRM_USER=y
-+CONFIG_NET_KEY=m
-+CONFIG_INET=y
-+CONFIG_IP_MULTICAST=y
-+CONFIG_IP_ADVANCED_ROUTER=y
-+CONFIG_IP_MULTIPLE_TABLES=y
-+CONFIG_IP_ROUTE_MULTIPATH=y
-+CONFIG_IP_ROUTE_VERBOSE=y
-+CONFIG_IP_PNP=y
-+CONFIG_IP_PNP_DHCP=y
-+CONFIG_IP_PNP_RARP=y
-+CONFIG_NET_IPIP=m
-+CONFIG_NET_IPGRE_DEMUX=m
-+CONFIG_NET_IPGRE=m
-+CONFIG_IP_MROUTE=y
-+CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
-+CONFIG_IP_PIMSM_V1=y
-+CONFIG_IP_PIMSM_V2=y
-+CONFIG_SYN_COOKIES=y
-+CONFIG_INET_AH=m
-+CONFIG_INET_ESP=m
-+CONFIG_INET_IPCOMP=m
-+CONFIG_INET_XFRM_MODE_TRANSPORT=m
-+CONFIG_INET_XFRM_MODE_TUNNEL=m
-+CONFIG_INET_XFRM_MODE_BEET=m
-+CONFIG_INET_LRO=m
-+CONFIG_INET_DIAG=m
-+CONFIG_INET6_AH=m
-+CONFIG_INET6_ESP=m
-+CONFIG_INET6_IPCOMP=m
-+CONFIG_IPV6_TUNNEL=m
-+CONFIG_IPV6_MULTIPLE_TABLES=y
-+CONFIG_IPV6_MROUTE=y
-+CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
-+CONFIG_IPV6_PIMSM_V2=y
-+CONFIG_NETFILTER=y
-+CONFIG_NF_CONNTRACK=m
-+CONFIG_NF_CONNTRACK_ZONES=y
-+CONFIG_NF_CONNTRACK_EVENTS=y
-+CONFIG_NF_CONNTRACK_TIMESTAMP=y
-+CONFIG_NF_CT_PROTO_DCCP=m
-+CONFIG_NF_CT_PROTO_UDPLITE=m
-+CONFIG_NF_CONNTRACK_AMANDA=m
-+CONFIG_NF_CONNTRACK_FTP=m
-+CONFIG_NF_CONNTRACK_H323=m
-+CONFIG_NF_CONNTRACK_IRC=m
-+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
-+CONFIG_NF_CONNTRACK_SNMP=m
-+CONFIG_NF_CONNTRACK_PPTP=m
-+CONFIG_NF_CONNTRACK_SANE=m
-+CONFIG_NF_CONNTRACK_SIP=m
-+CONFIG_NF_CONNTRACK_TFTP=m
-+CONFIG_NF_CT_NETLINK=m
-+CONFIG_NETFILTER_XT_SET=m
-+CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
-+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
-+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
-+CONFIG_NETFILTER_XT_TARGET_DSCP=m
-+CONFIG_NETFILTER_XT_TARGET_HMARK=m
-+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
-+CONFIG_NETFILTER_XT_TARGET_LED=m
-+CONFIG_NETFILTER_XT_TARGET_LOG=m
-+CONFIG_NETFILTER_XT_TARGET_MARK=m
-+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
-+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
-+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
-+CONFIG_NETFILTER_XT_TARGET_TEE=m
-+CONFIG_NETFILTER_XT_TARGET_TPROXY=m
-+CONFIG_NETFILTER_XT_TARGET_TRACE=m
-+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
-+CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
-+CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m
-+CONFIG_NETFILTER_XT_MATCH_BPF=m
-+CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
-+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
-+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
-+CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m
-+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
-+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
-+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
-+CONFIG_NETFILTER_XT_MATCH_CPU=m
-+CONFIG_NETFILTER_XT_MATCH_DCCP=m
-+CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m
-+CONFIG_NETFILTER_XT_MATCH_DSCP=m
-+CONFIG_NETFILTER_XT_MATCH_ESP=m
-+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
-+CONFIG_NETFILTER_XT_MATCH_HELPER=m
-+CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
-+CONFIG_NETFILTER_XT_MATCH_IPVS=m
-+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
-+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
-+CONFIG_NETFILTER_XT_MATCH_MAC=m
-+CONFIG_NETFILTER_XT_MATCH_MARK=m
-+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
-+CONFIG_NETFILTER_XT_MATCH_NFACCT=m
-+CONFIG_NETFILTER_XT_MATCH_OSF=m
-+CONFIG_NETFILTER_XT_MATCH_OWNER=m
-+CONFIG_NETFILTER_XT_MATCH_POLICY=m
-+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
-+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
-+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
-+CONFIG_NETFILTER_XT_MATCH_RATEEST=m
-+CONFIG_NETFILTER_XT_MATCH_REALM=m
-+CONFIG_NETFILTER_XT_MATCH_RECENT=m
-+CONFIG_NETFILTER_XT_MATCH_SOCKET=m
-+CONFIG_NETFILTER_XT_MATCH_STATE=m
-+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
-+CONFIG_NETFILTER_XT_MATCH_STRING=m
-+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
-+CONFIG_NETFILTER_XT_MATCH_TIME=m
-+CONFIG_NETFILTER_XT_MATCH_U32=m
-+CONFIG_IP_SET=m
-+CONFIG_IP_SET_BITMAP_IP=m
-+CONFIG_IP_SET_BITMAP_IPMAC=m
-+CONFIG_IP_SET_BITMAP_PORT=m
-+CONFIG_IP_SET_HASH_IP=m
-+CONFIG_IP_SET_HASH_IPPORT=m
-+CONFIG_IP_SET_HASH_IPPORTIP=m
-+CONFIG_IP_SET_HASH_IPPORTNET=m
-+CONFIG_IP_SET_HASH_NET=m
-+CONFIG_IP_SET_HASH_NETPORT=m
-+CONFIG_IP_SET_HASH_NETIFACE=m
-+CONFIG_IP_SET_LIST_SET=m
-+CONFIG_IP_VS=m
-+CONFIG_IP_VS_PROTO_TCP=y
-+CONFIG_IP_VS_PROTO_UDP=y
-+CONFIG_IP_VS_PROTO_ESP=y
-+CONFIG_IP_VS_PROTO_AH=y
-+CONFIG_IP_VS_PROTO_SCTP=y
-+CONFIG_IP_VS_RR=m
-+CONFIG_IP_VS_WRR=m
-+CONFIG_IP_VS_LC=m
-+CONFIG_IP_VS_WLC=m
-+CONFIG_IP_VS_LBLC=m
-+CONFIG_IP_VS_LBLCR=m
-+CONFIG_IP_VS_DH=m
-+CONFIG_IP_VS_SH=m
-+CONFIG_IP_VS_SED=m
-+CONFIG_IP_VS_NQ=m
-+CONFIG_IP_VS_FTP=m
-+CONFIG_IP_VS_PE_SIP=m
-+CONFIG_NF_CONNTRACK_IPV4=m
-+CONFIG_IP_NF_IPTABLES=m
-+CONFIG_IP_NF_MATCH_AH=m
-+CONFIG_IP_NF_MATCH_ECN=m
-+CONFIG_IP_NF_MATCH_TTL=m
-+CONFIG_IP_NF_FILTER=m
-+CONFIG_IP_NF_TARGET_REJECT=m
-+CONFIG_IP_NF_NAT=m
-+CONFIG_IP_NF_TARGET_MASQUERADE=m
-+CONFIG_IP_NF_TARGET_NETMAP=m
-+CONFIG_IP_NF_TARGET_REDIRECT=m
-+CONFIG_IP_NF_MANGLE=m
-+CONFIG_IP_NF_TARGET_CLUSTERIP=m
-+CONFIG_IP_NF_TARGET_ECN=m
-+CONFIG_IP_NF_TARGET_TTL=m
-+CONFIG_IP_NF_RAW=m
-+CONFIG_IP_NF_ARPTABLES=m
-+CONFIG_IP_NF_ARPFILTER=m
-+CONFIG_IP_NF_ARP_MANGLE=m
-+CONFIG_NF_CONNTRACK_IPV6=m
-+CONFIG_IP6_NF_IPTABLES=m
-+CONFIG_IP6_NF_MATCH_AH=m
-+CONFIG_IP6_NF_MATCH_EUI64=m
-+CONFIG_IP6_NF_MATCH_FRAG=m
-+CONFIG_IP6_NF_MATCH_OPTS=m
-+CONFIG_IP6_NF_MATCH_HL=m
-+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
-+CONFIG_IP6_NF_MATCH_MH=m
-+CONFIG_IP6_NF_MATCH_RT=m
-+CONFIG_IP6_NF_TARGET_HL=m
-+CONFIG_IP6_NF_FILTER=m
-+CONFIG_IP6_NF_TARGET_REJECT=m
-+CONFIG_IP6_NF_MANGLE=m
-+CONFIG_IP6_NF_RAW=m
-+CONFIG_IP6_NF_NAT=m
-+CONFIG_IP6_NF_TARGET_MASQUERADE=m
-+CONFIG_IP6_NF_TARGET_NPT=m
-+CONFIG_BRIDGE_NF_EBTABLES=m
-+CONFIG_BRIDGE_EBT_BROUTE=m
-+CONFIG_BRIDGE_EBT_T_FILTER=m
-+CONFIG_BRIDGE_EBT_T_NAT=m
-+CONFIG_BRIDGE_EBT_802_3=m
-+CONFIG_BRIDGE_EBT_AMONG=m
-+CONFIG_BRIDGE_EBT_ARP=m
-+CONFIG_BRIDGE_EBT_IP=m
-+CONFIG_BRIDGE_EBT_IP6=m
-+CONFIG_BRIDGE_EBT_LIMIT=m
-+CONFIG_BRIDGE_EBT_MARK=m
-+CONFIG_BRIDGE_EBT_PKTTYPE=m
-+CONFIG_BRIDGE_EBT_STP=m
-+CONFIG_BRIDGE_EBT_VLAN=m
-+CONFIG_BRIDGE_EBT_ARPREPLY=m
-+CONFIG_BRIDGE_EBT_DNAT=m
-+CONFIG_BRIDGE_EBT_MARK_T=m
-+CONFIG_BRIDGE_EBT_REDIRECT=m
-+CONFIG_BRIDGE_EBT_SNAT=m
-+CONFIG_BRIDGE_EBT_LOG=m
-+CONFIG_BRIDGE_EBT_NFLOG=m
-+CONFIG_SCTP_COOKIE_HMAC_SHA1=y
-+CONFIG_ATM=m
-+CONFIG_L2TP=m
-+CONFIG_L2TP_V3=y
-+CONFIG_L2TP_IP=m
-+CONFIG_L2TP_ETH=m
-+CONFIG_BRIDGE=m
-+CONFIG_VLAN_8021Q=m
-+CONFIG_VLAN_8021Q_GVRP=y
-+CONFIG_ATALK=m
-+CONFIG_6LOWPAN=m
-+CONFIG_IEEE802154=m
-+CONFIG_IEEE802154_6LOWPAN=m
-+CONFIG_MAC802154=m
-+CONFIG_NET_SCHED=y
-+CONFIG_NET_SCH_CBQ=m
-+CONFIG_NET_SCH_HTB=m
-+CONFIG_NET_SCH_HFSC=m
-+CONFIG_NET_SCH_PRIO=m
-+CONFIG_NET_SCH_MULTIQ=m
-+CONFIG_NET_SCH_RED=m
-+CONFIG_NET_SCH_SFB=m
-+CONFIG_NET_SCH_SFQ=m
-+CONFIG_NET_SCH_TEQL=m
-+CONFIG_NET_SCH_TBF=m
-+CONFIG_NET_SCH_GRED=m
-+CONFIG_NET_SCH_DSMARK=m
-+CONFIG_NET_SCH_NETEM=m
-+CONFIG_NET_SCH_DRR=m
-+CONFIG_NET_SCH_MQPRIO=m
-+CONFIG_NET_SCH_CHOKE=m
-+CONFIG_NET_SCH_QFQ=m
-+CONFIG_NET_SCH_CODEL=m
-+CONFIG_NET_SCH_FQ_CODEL=m
-+CONFIG_NET_SCH_INGRESS=m
-+CONFIG_NET_SCH_PLUG=m
-+CONFIG_NET_CLS_BASIC=m
-+CONFIG_NET_CLS_TCINDEX=m
-+CONFIG_NET_CLS_ROUTE4=m
-+CONFIG_NET_CLS_FW=m
-+CONFIG_NET_CLS_U32=m
-+CONFIG_CLS_U32_MARK=y
-+CONFIG_NET_CLS_RSVP=m
-+CONFIG_NET_CLS_RSVP6=m
-+CONFIG_NET_CLS_FLOW=m
-+CONFIG_NET_CLS_CGROUP=m
-+CONFIG_NET_EMATCH=y
-+CONFIG_NET_EMATCH_CMP=m
-+CONFIG_NET_EMATCH_NBYTE=m
-+CONFIG_NET_EMATCH_U32=m
-+CONFIG_NET_EMATCH_META=m
-+CONFIG_NET_EMATCH_TEXT=m
-+CONFIG_NET_EMATCH_IPSET=m
-+CONFIG_NET_CLS_ACT=y
-+CONFIG_NET_ACT_POLICE=m
-+CONFIG_NET_ACT_GACT=m
-+CONFIG_GACT_PROB=y
-+CONFIG_NET_ACT_MIRRED=m
-+CONFIG_NET_ACT_IPT=m
-+CONFIG_NET_ACT_NAT=m
-+CONFIG_NET_ACT_PEDIT=m
-+CONFIG_NET_ACT_SIMP=m
-+CONFIG_NET_ACT_SKBEDIT=m
-+CONFIG_NET_ACT_CSUM=m
-+CONFIG_BATMAN_ADV=m
-+CONFIG_OPENVSWITCH=m
-+CONFIG_NET_PKTGEN=m
-+CONFIG_HAMRADIO=y
-+CONFIG_AX25=m
-+CONFIG_NETROM=m
-+CONFIG_ROSE=m
-+CONFIG_MKISS=m
-+CONFIG_6PACK=m
-+CONFIG_BPQETHER=m
-+CONFIG_BAYCOM_SER_FDX=m
-+CONFIG_BAYCOM_SER_HDX=m
-+CONFIG_YAM=m
-+CONFIG_CAN=m
-+CONFIG_CAN_VCAN=m
-+CONFIG_CAN_MCP251X=m
-+CONFIG_IRDA=m
-+CONFIG_IRLAN=m
-+CONFIG_IRNET=m
-+CONFIG_IRCOMM=m
-+CONFIG_IRDA_ULTRA=y
-+CONFIG_IRDA_CACHE_LAST_LSAP=y
-+CONFIG_IRDA_FAST_RR=y
-+CONFIG_IRTTY_SIR=m
-+CONFIG_KINGSUN_DONGLE=m
-+CONFIG_KSDAZZLE_DONGLE=m
-+CONFIG_KS959_DONGLE=m
-+CONFIG_USB_IRDA=m
-+CONFIG_SIGMATEL_FIR=m
-+CONFIG_MCS_FIR=m
-+CONFIG_BT=m
-+CONFIG_BT_RFCOMM=m
-+CONFIG_BT_RFCOMM_TTY=y
-+CONFIG_BT_BNEP=m
-+CONFIG_BT_BNEP_MC_FILTER=y
-+CONFIG_BT_BNEP_PROTO_FILTER=y
-+CONFIG_BT_HIDP=m
-+CONFIG_BT_6LOWPAN=m
-+CONFIG_BT_HCIBTUSB=m
-+CONFIG_BT_HCIUART=m
-+CONFIG_BT_HCIBCM203X=m
-+CONFIG_BT_HCIBPA10X=m
-+CONFIG_BT_HCIBFUSB=m
-+CONFIG_BT_HCIVHCI=m
-+CONFIG_BT_MRVL=m
-+CONFIG_BT_MRVL_SDIO=m
-+CONFIG_BT_ATH3K=m
-+CONFIG_BT_WILINK=m
-+CONFIG_MAC80211=m
-+CONFIG_MAC80211_MESH=y
-+CONFIG_WIMAX=m
-+CONFIG_RFKILL=m
-+CONFIG_RFKILL_INPUT=y
-+CONFIG_NET_9P=m
-+CONFIG_NFC=m
-+CONFIG_NFC_PN533=m
-+CONFIG_DEVTMPFS=y
-+CONFIG_DEVTMPFS_MOUNT=y
-+CONFIG_DMA_CMA=y
-+CONFIG_CMA_SIZE_MBYTES=5
-+CONFIG_MTD=m
-+CONFIG_MTD_BLOCK=m
-+CONFIG_MTD_NAND=m
-+CONFIG_MTD_UBI=m
-+CONFIG_ZRAM=m
-+CONFIG_ZRAM_LZ4_COMPRESS=y
-+CONFIG_BLK_DEV_LOOP=y
-+CONFIG_BLK_DEV_CRYPTOLOOP=m
-+CONFIG_BLK_DEV_DRBD=m
-+CONFIG_BLK_DEV_NBD=m
-+CONFIG_BLK_DEV_RAM=y
-+CONFIG_CDROM_PKTCDVD=m
-+CONFIG_ATA_OVER_ETH=m
-+CONFIG_EEPROM_AT24=m
-+CONFIG_TI_ST=m
-+CONFIG_SCSI=y
-+# CONFIG_SCSI_PROC_FS is not set
-+CONFIG_BLK_DEV_SD=y
-+CONFIG_CHR_DEV_ST=m
-+CONFIG_CHR_DEV_OSST=m
-+CONFIG_BLK_DEV_SR=m
-+CONFIG_CHR_DEV_SG=m
-+CONFIG_SCSI_ISCSI_ATTRS=y
-+CONFIG_ISCSI_TCP=m
-+CONFIG_ISCSI_BOOT_SYSFS=m
-+CONFIG_MD=y
-+CONFIG_MD_LINEAR=m
-+CONFIG_MD_RAID0=m
-+CONFIG_BLK_DEV_DM=m
-+CONFIG_DM_CRYPT=m
-+CONFIG_DM_SNAPSHOT=m
-+CONFIG_DM_THIN_PROVISIONING=m
-+CONFIG_DM_MIRROR=m
-+CONFIG_DM_LOG_USERSPACE=m
-+CONFIG_DM_RAID=m
-+CONFIG_DM_ZERO=m
-+CONFIG_DM_DELAY=m
-+CONFIG_NETDEVICES=y
-+CONFIG_BONDING=m
-+CONFIG_DUMMY=m
-+CONFIG_IFB=m
-+CONFIG_MACVLAN=m
-+CONFIG_NETCONSOLE=m
-+CONFIG_TUN=m
-+CONFIG_VETH=m
-+CONFIG_ENC28J60=m
-+CONFIG_MDIO_BITBANG=m
-+CONFIG_PPP=m
-+CONFIG_PPP_BSDCOMP=m
-+CONFIG_PPP_DEFLATE=m
-+CONFIG_PPP_FILTER=y
-+CONFIG_PPP_MPPE=m
-+CONFIG_PPP_MULTILINK=y
-+CONFIG_PPPOATM=m
-+CONFIG_PPPOE=m
-+CONFIG_PPPOL2TP=m
-+CONFIG_PPP_ASYNC=m
-+CONFIG_PPP_SYNC_TTY=m
-+CONFIG_SLIP=m
-+CONFIG_SLIP_COMPRESSED=y
-+CONFIG_SLIP_SMART=y
-+CONFIG_USB_CATC=m
-+CONFIG_USB_KAWETH=m
-+CONFIG_USB_PEGASUS=m
-+CONFIG_USB_RTL8150=m
-+CONFIG_USB_RTL8152=m
-+CONFIG_USB_USBNET=y
-+CONFIG_USB_NET_AX8817X=m
-+CONFIG_USB_NET_AX88179_178A=m
-+CONFIG_USB_NET_CDCETHER=m
-+CONFIG_USB_NET_CDC_EEM=m
-+CONFIG_USB_NET_CDC_NCM=m
-+CONFIG_USB_NET_HUAWEI_CDC_NCM=m
-+CONFIG_USB_NET_CDC_MBIM=m
-+CONFIG_USB_NET_DM9601=m
-+CONFIG_USB_NET_SR9700=m
-+CONFIG_USB_NET_SR9800=m
-+CONFIG_USB_NET_SMSC75XX=m
-+CONFIG_USB_NET_SMSC95XX=y
-+CONFIG_USB_NET_GL620A=m
-+CONFIG_USB_NET_NET1080=m
-+CONFIG_USB_NET_PLUSB=m
-+CONFIG_USB_NET_MCS7830=m
-+CONFIG_USB_NET_CDC_SUBSET=m
-+CONFIG_USB_ALI_M5632=y
-+CONFIG_USB_AN2720=y
-+CONFIG_USB_EPSON2888=y
-+CONFIG_USB_KC2190=y
-+CONFIG_USB_NET_ZAURUS=m
-+CONFIG_USB_NET_CX82310_ETH=m
-+CONFIG_USB_NET_KALMIA=m
-+CONFIG_USB_NET_QMI_WWAN=m
-+CONFIG_USB_HSO=m
-+CONFIG_USB_NET_INT51X1=m
-+CONFIG_USB_IPHETH=m
-+CONFIG_USB_SIERRA_NET=m
-+CONFIG_USB_VL600=m
-+CONFIG_LIBERTAS_THINFIRM=m
-+CONFIG_LIBERTAS_THINFIRM_USB=m
-+CONFIG_AT76C50X_USB=m
-+CONFIG_USB_ZD1201=m
-+CONFIG_USB_NET_RNDIS_WLAN=m
-+CONFIG_RTL8187=m
-+CONFIG_MAC80211_HWSIM=m
-+CONFIG_ATH_CARDS=m
-+CONFIG_ATH9K=m
-+CONFIG_ATH9K_HTC=m
-+CONFIG_CARL9170=m
-+CONFIG_ATH6KL=m
-+CONFIG_ATH6KL_USB=m
-+CONFIG_AR5523=m
-+CONFIG_B43=m
-+# CONFIG_B43_PHY_N is not set
-+CONFIG_B43LEGACY=m
-+CONFIG_BRCMFMAC=m
-+CONFIG_BRCMFMAC_USB=y
-+CONFIG_HOSTAP=m
-+CONFIG_LIBERTAS=m
-+CONFIG_LIBERTAS_USB=m
-+CONFIG_LIBERTAS_SDIO=m
-+CONFIG_P54_COMMON=m
-+CONFIG_P54_USB=m
-+CONFIG_RT2X00=m
-+CONFIG_RT2500USB=m
-+CONFIG_RT73USB=m
-+CONFIG_RT2800USB=m
-+CONFIG_RT2800USB_RT3573=y
-+CONFIG_RT2800USB_RT53XX=y
-+CONFIG_RT2800USB_RT55XX=y
-+CONFIG_RT2800USB_UNKNOWN=y
-+CONFIG_WL_MEDIATEK=y
-+CONFIG_MT7601U=m
-+CONFIG_RTL8192CU=m
-+CONFIG_ZD1211RW=m
-+CONFIG_MWIFIEX=m
-+CONFIG_MWIFIEX_SDIO=m
-+CONFIG_WIMAX_I2400M_USB=m
-+CONFIG_IEEE802154_AT86RF230=m
-+CONFIG_IEEE802154_MRF24J40=m
-+CONFIG_IEEE802154_CC2520=m
-+CONFIG_INPUT_POLLDEV=m
-+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-+CONFIG_INPUT_JOYDEV=m
-+CONFIG_INPUT_EVDEV=m
-+# CONFIG_KEYBOARD_ATKBD is not set
-+CONFIG_KEYBOARD_GPIO=m
-+# CONFIG_INPUT_MOUSE is not set
-+CONFIG_INPUT_JOYSTICK=y
-+CONFIG_JOYSTICK_IFORCE=m
-+CONFIG_JOYSTICK_IFORCE_USB=y
-+CONFIG_JOYSTICK_XPAD=m
-+CONFIG_JOYSTICK_XPAD_FF=y
-+CONFIG_JOYSTICK_RPISENSE=m
-+CONFIG_INPUT_TOUCHSCREEN=y
-+CONFIG_TOUCHSCREEN_ADS7846=m
-+CONFIG_TOUCHSCREEN_EGALAX=m
-+CONFIG_TOUCHSCREEN_FT6236=m
-+CONFIG_TOUCHSCREEN_RPI_FT5406=m
-+CONFIG_TOUCHSCREEN_USB_COMPOSITE=m
-+CONFIG_TOUCHSCREEN_STMPE=m
-+CONFIG_INPUT_MISC=y
-+CONFIG_INPUT_AD714X=m
-+CONFIG_INPUT_ATI_REMOTE2=m
-+CONFIG_INPUT_KEYSPAN_REMOTE=m
-+CONFIG_INPUT_POWERMATE=m
-+CONFIG_INPUT_YEALINK=m
-+CONFIG_INPUT_CM109=m
-+CONFIG_INPUT_UINPUT=m
-+CONFIG_INPUT_GPIO_ROTARY_ENCODER=m
-+CONFIG_INPUT_ADXL34X=m
-+CONFIG_INPUT_CMA3000=m
-+CONFIG_SERIO=m
-+CONFIG_SERIO_RAW=m
-+CONFIG_GAMEPORT=m
-+CONFIG_GAMEPORT_NS558=m
-+CONFIG_GAMEPORT_L4=m
-+CONFIG_BRCM_CHAR_DRIVERS=y
-+CONFIG_BCM_VC_CMA=y
-+CONFIG_BCM_VCIO=y
-+CONFIG_BCM_VC_SM=y
-+CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
-+# CONFIG_LEGACY_PTYS is not set
-+# CONFIG_DEVKMEM is not set
-+CONFIG_SERIAL_8250=y
-+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
-+CONFIG_SERIAL_8250_CONSOLE=y
-+# CONFIG_SERIAL_8250_DMA is not set
-+CONFIG_SERIAL_8250_NR_UARTS=1
-+CONFIG_SERIAL_8250_RUNTIME_UARTS=0
-+CONFIG_SERIAL_AMBA_PL011=y
-+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
-+CONFIG_SERIAL_OF_PLATFORM=y
-+CONFIG_TTY_PRINTK=y
-+CONFIG_HW_RANDOM=y
-+CONFIG_RAW_DRIVER=y
-+CONFIG_I2C=y
-+CONFIG_I2C_CHARDEV=m
-+CONFIG_I2C_BCM2708=m
-+CONFIG_SPI=y
-+CONFIG_SPI_BCM2835=m
-+CONFIG_SPI_SPIDEV=y
-+CONFIG_PPS=m
-+CONFIG_PPS_CLIENT_LDISC=m
-+CONFIG_PPS_CLIENT_GPIO=m
-+CONFIG_GPIO_SYSFS=y
-+CONFIG_GPIO_ARIZONA=m
-+CONFIG_GPIO_STMPE=y
-+CONFIG_W1=m
-+CONFIG_W1_MASTER_DS2490=m
-+CONFIG_W1_MASTER_DS2482=m
-+CONFIG_W1_MASTER_DS1WM=m
-+CONFIG_W1_MASTER_GPIO=m
-+CONFIG_W1_SLAVE_THERM=m
-+CONFIG_W1_SLAVE_SMEM=m
-+CONFIG_W1_SLAVE_DS2408=m
-+CONFIG_W1_SLAVE_DS2413=m
-+CONFIG_W1_SLAVE_DS2406=m
-+CONFIG_W1_SLAVE_DS2423=m
-+CONFIG_W1_SLAVE_DS2431=m
-+CONFIG_W1_SLAVE_DS2433=m
-+CONFIG_W1_SLAVE_DS2760=m
-+CONFIG_W1_SLAVE_DS2780=m
-+CONFIG_W1_SLAVE_DS2781=m
-+CONFIG_W1_SLAVE_DS28E04=m
-+CONFIG_W1_SLAVE_BQ27000=m
-+CONFIG_BATTERY_DS2760=m
-+CONFIG_POWER_RESET=y
-+CONFIG_POWER_RESET_GPIO=y
-+CONFIG_HWMON=m
-+CONFIG_SENSORS_SHT21=m
-+CONFIG_SENSORS_SHTC1=m
-+CONFIG_THERMAL=y
-+CONFIG_THERMAL_BCM2835=y
-+CONFIG_WATCHDOG=y
-+CONFIG_BCM2835_WDT=m
-+CONFIG_UCB1400_CORE=m
-+CONFIG_MFD_STMPE=y
-+CONFIG_STMPE_SPI=y
-+CONFIG_MFD_ARIZONA_I2C=m
-+CONFIG_MFD_ARIZONA_SPI=m
-+CONFIG_MFD_WM5102=y
-+CONFIG_MEDIA_SUPPORT=m
-+CONFIG_MEDIA_CAMERA_SUPPORT=y
-+CONFIG_MEDIA_ANALOG_TV_SUPPORT=y
-+CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y
-+CONFIG_MEDIA_RADIO_SUPPORT=y
-+CONFIG_MEDIA_RC_SUPPORT=y
-+CONFIG_MEDIA_CONTROLLER=y
-+CONFIG_LIRC=m
-+CONFIG_RC_DEVICES=y
-+CONFIG_RC_ATI_REMOTE=m
-+CONFIG_IR_IMON=m
-+CONFIG_IR_MCEUSB=m
-+CONFIG_IR_REDRAT3=m
-+CONFIG_IR_STREAMZAP=m
-+CONFIG_IR_IGUANA=m
-+CONFIG_IR_TTUSBIR=m
-+CONFIG_RC_LOOPBACK=m
-+CONFIG_IR_GPIO_CIR=m
-+CONFIG_MEDIA_USB_SUPPORT=y
-+CONFIG_USB_VIDEO_CLASS=m
-+CONFIG_USB_M5602=m
-+CONFIG_USB_STV06XX=m
-+CONFIG_USB_GL860=m
-+CONFIG_USB_GSPCA_BENQ=m
-+CONFIG_USB_GSPCA_CONEX=m
-+CONFIG_USB_GSPCA_CPIA1=m
-+CONFIG_USB_GSPCA_DTCS033=m
-+CONFIG_USB_GSPCA_ETOMS=m
-+CONFIG_USB_GSPCA_FINEPIX=m
-+CONFIG_USB_GSPCA_JEILINJ=m
-+CONFIG_USB_GSPCA_JL2005BCD=m
-+CONFIG_USB_GSPCA_KINECT=m
-+CONFIG_USB_GSPCA_KONICA=m
-+CONFIG_USB_GSPCA_MARS=m
-+CONFIG_USB_GSPCA_MR97310A=m
-+CONFIG_USB_GSPCA_NW80X=m
-+CONFIG_USB_GSPCA_OV519=m
-+CONFIG_USB_GSPCA_OV534=m
-+CONFIG_USB_GSPCA_OV534_9=m
-+CONFIG_USB_GSPCA_PAC207=m
-+CONFIG_USB_GSPCA_PAC7302=m
-+CONFIG_USB_GSPCA_PAC7311=m
-+CONFIG_USB_GSPCA_SE401=m
-+CONFIG_USB_GSPCA_SN9C2028=m
-+CONFIG_USB_GSPCA_SN9C20X=m
-+CONFIG_USB_GSPCA_SONIXB=m
-+CONFIG_USB_GSPCA_SONIXJ=m
-+CONFIG_USB_GSPCA_SPCA500=m
-+CONFIG_USB_GSPCA_SPCA501=m
-+CONFIG_USB_GSPCA_SPCA505=m
-+CONFIG_USB_GSPCA_SPCA506=m
-+CONFIG_USB_GSPCA_SPCA508=m
-+CONFIG_USB_GSPCA_SPCA561=m
-+CONFIG_USB_GSPCA_SPCA1528=m
-+CONFIG_USB_GSPCA_SQ905=m
-+CONFIG_USB_GSPCA_SQ905C=m
-+CONFIG_USB_GSPCA_SQ930X=m
-+CONFIG_USB_GSPCA_STK014=m
-+CONFIG_USB_GSPCA_STK1135=m
-+CONFIG_USB_GSPCA_STV0680=m
-+CONFIG_USB_GSPCA_SUNPLUS=m
-+CONFIG_USB_GSPCA_T613=m
-+CONFIG_USB_GSPCA_TOPRO=m
-+CONFIG_USB_GSPCA_TV8532=m
-+CONFIG_USB_GSPCA_VC032X=m
-+CONFIG_USB_GSPCA_VICAM=m
-+CONFIG_USB_GSPCA_XIRLINK_CIT=m
-+CONFIG_USB_GSPCA_ZC3XX=m
-+CONFIG_USB_PWC=m
-+CONFIG_VIDEO_CPIA2=m
-+CONFIG_USB_ZR364XX=m
-+CONFIG_USB_STKWEBCAM=m
-+CONFIG_USB_S2255=m
-+CONFIG_VIDEO_USBTV=m
-+CONFIG_VIDEO_PVRUSB2=m
-+CONFIG_VIDEO_HDPVR=m
-+CONFIG_VIDEO_USBVISION=m
-+CONFIG_VIDEO_STK1160_COMMON=m
-+CONFIG_VIDEO_STK1160_AC97=y
-+CONFIG_VIDEO_GO7007=m
-+CONFIG_VIDEO_GO7007_USB=m
-+CONFIG_VIDEO_GO7007_USB_S2250_BOARD=m
-+CONFIG_VIDEO_AU0828=m
-+CONFIG_VIDEO_AU0828_RC=y
-+CONFIG_VIDEO_CX231XX=m
-+CONFIG_VIDEO_CX231XX_ALSA=m
-+CONFIG_VIDEO_CX231XX_DVB=m
-+CONFIG_VIDEO_TM6000=m
-+CONFIG_VIDEO_TM6000_ALSA=m
-+CONFIG_VIDEO_TM6000_DVB=m
-+CONFIG_DVB_USB=m
-+CONFIG_DVB_USB_A800=m
-+CONFIG_DVB_USB_DIBUSB_MB=m
-+CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y
-+CONFIG_DVB_USB_DIBUSB_MC=m
-+CONFIG_DVB_USB_DIB0700=m
-+CONFIG_DVB_USB_UMT_010=m
-+CONFIG_DVB_USB_CXUSB=m
-+CONFIG_DVB_USB_M920X=m
-+CONFIG_DVB_USB_DIGITV=m
-+CONFIG_DVB_USB_VP7045=m
-+CONFIG_DVB_USB_VP702X=m
-+CONFIG_DVB_USB_GP8PSK=m
-+CONFIG_DVB_USB_NOVA_T_USB2=m
-+CONFIG_DVB_USB_TTUSB2=m
-+CONFIG_DVB_USB_DTT200U=m
-+CONFIG_DVB_USB_OPERA1=m
-+CONFIG_DVB_USB_AF9005=m
-+CONFIG_DVB_USB_AF9005_REMOTE=m
-+CONFIG_DVB_USB_PCTV452E=m
-+CONFIG_DVB_USB_DW2102=m
-+CONFIG_DVB_USB_CINERGY_T2=m
-+CONFIG_DVB_USB_DTV5100=m
-+CONFIG_DVB_USB_FRIIO=m
-+CONFIG_DVB_USB_AZ6027=m
-+CONFIG_DVB_USB_TECHNISAT_USB2=m
-+CONFIG_DVB_USB_V2=m
-+CONFIG_DVB_USB_AF9015=m
-+CONFIG_DVB_USB_AF9035=m
-+CONFIG_DVB_USB_ANYSEE=m
-+CONFIG_DVB_USB_AU6610=m
-+CONFIG_DVB_USB_AZ6007=m
-+CONFIG_DVB_USB_CE6230=m
-+CONFIG_DVB_USB_EC168=m
-+CONFIG_DVB_USB_GL861=m
-+CONFIG_DVB_USB_LME2510=m
-+CONFIG_DVB_USB_MXL111SF=m
-+CONFIG_DVB_USB_RTL28XXU=m
-+CONFIG_DVB_USB_DVBSKY=m
-+CONFIG_SMS_USB_DRV=m
-+CONFIG_DVB_B2C2_FLEXCOP_USB=m
-+CONFIG_DVB_AS102=m
-+CONFIG_VIDEO_EM28XX=m
-+CONFIG_VIDEO_EM28XX_V4L2=m
-+CONFIG_VIDEO_EM28XX_ALSA=m
-+CONFIG_VIDEO_EM28XX_DVB=m
-+CONFIG_V4L_PLATFORM_DRIVERS=y
-+CONFIG_VIDEO_BCM2835=y
-+CONFIG_VIDEO_BCM2835_MMAL=m
-+CONFIG_RADIO_SI470X=y
-+CONFIG_USB_SI470X=m
-+CONFIG_I2C_SI470X=m
-+CONFIG_RADIO_SI4713=m
-+CONFIG_I2C_SI4713=m
-+CONFIG_USB_MR800=m
-+CONFIG_USB_DSBR=m
-+CONFIG_RADIO_SHARK=m
-+CONFIG_RADIO_SHARK2=m
-+CONFIG_USB_KEENE=m
-+CONFIG_USB_MA901=m
-+CONFIG_RADIO_TEA5764=m
-+CONFIG_RADIO_SAA7706H=m
-+CONFIG_RADIO_TEF6862=m
-+CONFIG_RADIO_WL1273=m
-+CONFIG_RADIO_WL128X=m
-+# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
-+CONFIG_VIDEO_UDA1342=m
-+CONFIG_VIDEO_SONY_BTF_MPX=m
-+CONFIG_VIDEO_TVP5150=m
-+CONFIG_VIDEO_TW2804=m
-+CONFIG_VIDEO_TW9903=m
-+CONFIG_VIDEO_TW9906=m
-+CONFIG_VIDEO_OV7640=m
-+CONFIG_VIDEO_MT9V011=m
-+CONFIG_FB=y
-+CONFIG_FB_BCM2708=y
-+CONFIG_FB_UDL=m
-+CONFIG_FB_SSD1307=m
-+CONFIG_FB_RPISENSE=m
-+# CONFIG_BACKLIGHT_GENERIC is not set
-+CONFIG_BACKLIGHT_GPIO=m
-+CONFIG_FRAMEBUFFER_CONSOLE=y
-+CONFIG_LOGO=y
-+# CONFIG_LOGO_LINUX_MONO is not set
-+# CONFIG_LOGO_LINUX_VGA16 is not set
-+CONFIG_SOUND=y
-+CONFIG_SND=m
-+CONFIG_SND_SEQUENCER=m
-+CONFIG_SND_SEQ_DUMMY=m
-+CONFIG_SND_MIXER_OSS=m
-+CONFIG_SND_PCM_OSS=m
-+CONFIG_SND_SEQUENCER_OSS=y
-+CONFIG_SND_HRTIMER=m
-+CONFIG_SND_DUMMY=m
-+CONFIG_SND_ALOOP=m
-+CONFIG_SND_VIRMIDI=m
-+CONFIG_SND_MTPAV=m
-+CONFIG_SND_SERIAL_U16550=m
-+CONFIG_SND_MPU401=m
-+CONFIG_SND_BCM2835=m
-+CONFIG_SND_USB_AUDIO=m
-+CONFIG_SND_USB_UA101=m
-+CONFIG_SND_USB_CAIAQ=m
-+CONFIG_SND_USB_CAIAQ_INPUT=y
-+CONFIG_SND_USB_6FIRE=m
-+CONFIG_SND_SOC=m
-+CONFIG_SND_BCM2835_SOC_I2S=m
-+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC=m
-+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS=m
-+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI=m
-+CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP=m
-+CONFIG_SND_BCM2708_SOC_RPI_DAC=m
-+CONFIG_SND_BCM2708_SOC_RPI_PROTO=m
-+CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m
-+CONFIG_SND_BCM2708_SOC_RASPIDAC3=m
-+CONFIG_SND_SOC_ADAU1701=m
-+CONFIG_SND_SOC_WM8804_I2C=m
-+CONFIG_SND_SIMPLE_CARD=m
-+CONFIG_SOUND_PRIME=m
-+CONFIG_HIDRAW=y
-+CONFIG_UHID=m
-+CONFIG_HID_A4TECH=m
-+CONFIG_HID_ACRUX=m
-+CONFIG_HID_APPLE=m
-+CONFIG_HID_BELKIN=m
-+CONFIG_HID_CHERRY=m
-+CONFIG_HID_CHICONY=m
-+CONFIG_HID_CYPRESS=m
-+CONFIG_HID_DRAGONRISE=m
-+CONFIG_HID_EMS_FF=m
-+CONFIG_HID_ELECOM=m
-+CONFIG_HID_ELO=m
-+CONFIG_HID_EZKEY=m
-+CONFIG_HID_HOLTEK=m
-+CONFIG_HID_KEYTOUCH=m
-+CONFIG_HID_KYE=m
-+CONFIG_HID_UCLOGIC=m
-+CONFIG_HID_WALTOP=m
-+CONFIG_HID_GYRATION=m
-+CONFIG_HID_TWINHAN=m
-+CONFIG_HID_KENSINGTON=m
-+CONFIG_HID_LCPOWER=m
-+CONFIG_HID_LOGITECH=m
-+CONFIG_HID_MAGICMOUSE=m
-+CONFIG_HID_MICROSOFT=m
-+CONFIG_HID_MONTEREY=m
-+CONFIG_HID_MULTITOUCH=m
-+CONFIG_HID_NTRIG=m
-+CONFIG_HID_ORTEK=m
-+CONFIG_HID_PANTHERLORD=m
-+CONFIG_HID_PETALYNX=m
-+CONFIG_HID_PICOLCD=m
-+CONFIG_HID_ROCCAT=m
-+CONFIG_HID_SAMSUNG=m
-+CONFIG_HID_SONY=m
-+CONFIG_HID_SPEEDLINK=m
-+CONFIG_HID_SUNPLUS=m
-+CONFIG_HID_GREENASIA=m
-+CONFIG_HID_SMARTJOYPLUS=m
-+CONFIG_HID_TOPSEED=m
-+CONFIG_HID_THINGM=m
-+CONFIG_HID_THRUSTMASTER=m
-+CONFIG_HID_WACOM=m
-+CONFIG_HID_WIIMOTE=m
-+CONFIG_HID_XINMO=m
-+CONFIG_HID_ZEROPLUS=m
-+CONFIG_HID_ZYDACRON=m
-+CONFIG_HID_PID=y
-+CONFIG_USB_HIDDEV=y
-+CONFIG_USB=y
-+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
-+CONFIG_USB_MON=m
-+CONFIG_USB_DWCOTG=y
-+CONFIG_USB_PRINTER=m
-+CONFIG_USB_STORAGE=y
-+CONFIG_USB_STORAGE_REALTEK=m
-+CONFIG_USB_STORAGE_DATAFAB=m
-+CONFIG_USB_STORAGE_FREECOM=m
-+CONFIG_USB_STORAGE_ISD200=m
-+CONFIG_USB_STORAGE_USBAT=m
-+CONFIG_USB_STORAGE_SDDR09=m
-+CONFIG_USB_STORAGE_SDDR55=m
-+CONFIG_USB_STORAGE_JUMPSHOT=m
-+CONFIG_USB_STORAGE_ALAUDA=m
-+CONFIG_USB_STORAGE_ONETOUCH=m
-+CONFIG_USB_STORAGE_KARMA=m
-+CONFIG_USB_STORAGE_CYPRESS_ATACB=m
-+CONFIG_USB_STORAGE_ENE_UB6250=m
-+CONFIG_USB_MDC800=m
-+CONFIG_USB_MICROTEK=m
-+CONFIG_USBIP_CORE=m
-+CONFIG_USBIP_VHCI_HCD=m
-+CONFIG_USBIP_HOST=m
-+CONFIG_USB_DWC2=m
-+CONFIG_USB_SERIAL=m
-+CONFIG_USB_SERIAL_GENERIC=y
-+CONFIG_USB_SERIAL_AIRCABLE=m
-+CONFIG_USB_SERIAL_ARK3116=m
-+CONFIG_USB_SERIAL_BELKIN=m
-+CONFIG_USB_SERIAL_CH341=m
-+CONFIG_USB_SERIAL_WHITEHEAT=m
-+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
-+CONFIG_USB_SERIAL_CP210X=m
-+CONFIG_USB_SERIAL_CYPRESS_M8=m
-+CONFIG_USB_SERIAL_EMPEG=m
-+CONFIG_USB_SERIAL_FTDI_SIO=m
-+CONFIG_USB_SERIAL_VISOR=m
-+CONFIG_USB_SERIAL_IPAQ=m
-+CONFIG_USB_SERIAL_IR=m
-+CONFIG_USB_SERIAL_EDGEPORT=m
-+CONFIG_USB_SERIAL_EDGEPORT_TI=m
-+CONFIG_USB_SERIAL_F81232=m
-+CONFIG_USB_SERIAL_GARMIN=m
-+CONFIG_USB_SERIAL_IPW=m
-+CONFIG_USB_SERIAL_IUU=m
-+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
-+CONFIG_USB_SERIAL_KEYSPAN=m
-+CONFIG_USB_SERIAL_KLSI=m
-+CONFIG_USB_SERIAL_KOBIL_SCT=m
-+CONFIG_USB_SERIAL_MCT_U232=m
-+CONFIG_USB_SERIAL_METRO=m
-+CONFIG_USB_SERIAL_MOS7720=m
-+CONFIG_USB_SERIAL_MOS7840=m
-+CONFIG_USB_SERIAL_NAVMAN=m
-+CONFIG_USB_SERIAL_PL2303=m
-+CONFIG_USB_SERIAL_OTI6858=m
-+CONFIG_USB_SERIAL_QCAUX=m
-+CONFIG_USB_SERIAL_QUALCOMM=m
-+CONFIG_USB_SERIAL_SPCP8X5=m
-+CONFIG_USB_SERIAL_SAFE=m
-+CONFIG_USB_SERIAL_SIERRAWIRELESS=m
-+CONFIG_USB_SERIAL_SYMBOL=m
-+CONFIG_USB_SERIAL_TI=m
-+CONFIG_USB_SERIAL_CYBERJACK=m
-+CONFIG_USB_SERIAL_XIRCOM=m
-+CONFIG_USB_SERIAL_OPTION=m
-+CONFIG_USB_SERIAL_OMNINET=m
-+CONFIG_USB_SERIAL_OPTICON=m
-+CONFIG_USB_SERIAL_XSENS_MT=m
-+CONFIG_USB_SERIAL_WISHBONE=m
-+CONFIG_USB_SERIAL_SSU100=m
-+CONFIG_USB_SERIAL_QT2=m
-+CONFIG_USB_SERIAL_DEBUG=m
-+CONFIG_USB_EMI62=m
-+CONFIG_USB_EMI26=m
-+CONFIG_USB_ADUTUX=m
-+CONFIG_USB_SEVSEG=m
-+CONFIG_USB_RIO500=m
-+CONFIG_USB_LEGOTOWER=m
-+CONFIG_USB_LCD=m
-+CONFIG_USB_LED=m
-+CONFIG_USB_CYPRESS_CY7C63=m
-+CONFIG_USB_CYTHERM=m
-+CONFIG_USB_IDMOUSE=m
-+CONFIG_USB_FTDI_ELAN=m
-+CONFIG_USB_APPLEDISPLAY=m
-+CONFIG_USB_LD=m
-+CONFIG_USB_TRANCEVIBRATOR=m
-+CONFIG_USB_IOWARRIOR=m
-+CONFIG_USB_TEST=m
-+CONFIG_USB_ISIGHTFW=m
-+CONFIG_USB_YUREX=m
-+CONFIG_USB_ATM=m
-+CONFIG_USB_SPEEDTOUCH=m
-+CONFIG_USB_CXACRU=m
-+CONFIG_USB_UEAGLEATM=m
-+CONFIG_USB_XUSBATM=m
-+CONFIG_USB_GADGET=m
-+CONFIG_USB_ZERO=m
-+CONFIG_USB_AUDIO=m
-+CONFIG_USB_ETH=m
-+CONFIG_USB_GADGETFS=m
-+CONFIG_USB_MASS_STORAGE=m
-+CONFIG_USB_G_SERIAL=m
-+CONFIG_USB_MIDI_GADGET=m
-+CONFIG_USB_G_PRINTER=m
-+CONFIG_USB_CDC_COMPOSITE=m
-+CONFIG_USB_G_ACM_MS=m
-+CONFIG_USB_G_MULTI=m
-+CONFIG_USB_G_HID=m
-+CONFIG_USB_G_WEBCAM=m
-+CONFIG_MMC=y
-+CONFIG_MMC_BLOCK_MINORS=32
-+CONFIG_MMC_BCM2835=y
-+CONFIG_MMC_BCM2835_DMA=y
-+CONFIG_MMC_BCM2835_SDHOST=y
-+CONFIG_MMC_SDHCI=y
-+CONFIG_MMC_SDHCI_PLTFM=y
-+CONFIG_MMC_SPI=m
-+CONFIG_LEDS_CLASS=y
-+CONFIG_LEDS_GPIO=y
-+CONFIG_LEDS_TRIGGER_TIMER=y
-+CONFIG_LEDS_TRIGGER_ONESHOT=y
-+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
-+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
-+CONFIG_LEDS_TRIGGER_CPU=y
-+CONFIG_LEDS_TRIGGER_GPIO=y
-+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
-+CONFIG_LEDS_TRIGGER_TRANSIENT=m
-+CONFIG_LEDS_TRIGGER_CAMERA=m
-+CONFIG_LEDS_TRIGGER_INPUT=y
-+CONFIG_RTC_CLASS=y
-+# CONFIG_RTC_HCTOSYS is not set
-+CONFIG_RTC_DRV_DS1307=m
-+CONFIG_RTC_DRV_DS1374=m
-+CONFIG_RTC_DRV_DS1672=m
-+CONFIG_RTC_DRV_DS3232=m
-+CONFIG_RTC_DRV_MAX6900=m
-+CONFIG_RTC_DRV_RS5C372=m
-+CONFIG_RTC_DRV_ISL1208=m
-+CONFIG_RTC_DRV_ISL12022=m
-+CONFIG_RTC_DRV_ISL12057=m
-+CONFIG_RTC_DRV_X1205=m
-+CONFIG_RTC_DRV_PCF2127=m
-+CONFIG_RTC_DRV_PCF8523=m
-+CONFIG_RTC_DRV_PCF8563=m
-+CONFIG_RTC_DRV_PCF8583=m
-+CONFIG_RTC_DRV_M41T80=m
-+CONFIG_RTC_DRV_BQ32K=m
-+CONFIG_RTC_DRV_S35390A=m
-+CONFIG_RTC_DRV_FM3130=m
-+CONFIG_RTC_DRV_RX8581=m
-+CONFIG_RTC_DRV_RX8025=m
-+CONFIG_RTC_DRV_EM3027=m
-+CONFIG_RTC_DRV_RV3029C2=m
-+CONFIG_RTC_DRV_M41T93=m
-+CONFIG_RTC_DRV_M41T94=m
-+CONFIG_RTC_DRV_DS1305=m
-+CONFIG_RTC_DRV_DS1390=m
-+CONFIG_RTC_DRV_MAX6902=m
-+CONFIG_RTC_DRV_R9701=m
-+CONFIG_RTC_DRV_RS5C348=m
-+CONFIG_RTC_DRV_DS3234=m
-+CONFIG_RTC_DRV_PCF2123=m
-+CONFIG_RTC_DRV_RX4581=m
-+CONFIG_DMADEVICES=y
-+CONFIG_DMA_BCM2835=y
-+CONFIG_DMA_BCM2708=y
-+CONFIG_UIO=m
-+CONFIG_UIO_PDRV_GENIRQ=m
-+CONFIG_STAGING=y
-+CONFIG_PRISM2_USB=m
-+CONFIG_R8712U=m
-+CONFIG_R8188EU=m
-+CONFIG_R8723AU=m
-+CONFIG_VT6656=m
-+CONFIG_SPEAKUP=m
-+CONFIG_SPEAKUP_SYNTH_SOFT=m
-+CONFIG_STAGING_MEDIA=y
-+CONFIG_LIRC_STAGING=y
-+CONFIG_LIRC_IMON=m
-+CONFIG_LIRC_RPI=m
-+CONFIG_LIRC_SASEM=m
-+CONFIG_LIRC_SERIAL=m
-+CONFIG_FB_TFT=m
-+CONFIG_FB_TFT_AGM1264K_FL=m
-+CONFIG_FB_TFT_BD663474=m
-+CONFIG_FB_TFT_HX8340BN=m
-+CONFIG_FB_TFT_HX8347D=m
-+CONFIG_FB_TFT_HX8353D=m
-+CONFIG_FB_TFT_ILI9163=m
-+CONFIG_FB_TFT_ILI9320=m
-+CONFIG_FB_TFT_ILI9325=m
-+CONFIG_FB_TFT_ILI9340=m
-+CONFIG_FB_TFT_ILI9341=m
-+CONFIG_FB_TFT_ILI9481=m
-+CONFIG_FB_TFT_ILI9486=m
-+CONFIG_FB_TFT_PCD8544=m
-+CONFIG_FB_TFT_RA8875=m
-+CONFIG_FB_TFT_S6D02A1=m
-+CONFIG_FB_TFT_S6D1121=m
-+CONFIG_FB_TFT_SSD1289=m
-+CONFIG_FB_TFT_SSD1306=m
-+CONFIG_FB_TFT_SSD1331=m
-+CONFIG_FB_TFT_SSD1351=m
-+CONFIG_FB_TFT_ST7735R=m
-+CONFIG_FB_TFT_TINYLCD=m
-+CONFIG_FB_TFT_TLS8204=m
-+CONFIG_FB_TFT_UC1701=m
-+CONFIG_FB_TFT_UPD161704=m
-+CONFIG_FB_TFT_WATTEROTT=m
-+CONFIG_FB_FLEX=m
-+CONFIG_FB_TFT_FBTFT_DEVICE=m
-+CONFIG_MAILBOX=y
-+CONFIG_BCM2835_MBOX=y
-+# CONFIG_IOMMU_SUPPORT is not set
-+CONFIG_EXTCON=m
-+CONFIG_EXTCON_ARIZONA=m
-+CONFIG_IIO=m
-+CONFIG_IIO_BUFFER=y
-+CONFIG_IIO_BUFFER_CB=m
-+CONFIG_IIO_KFIFO_BUF=m
-+CONFIG_MCP320X=m
-+CONFIG_DHT11=m
-+CONFIG_PWM_BCM2835=m
-+CONFIG_RASPBERRYPI_FIRMWARE=y
-+CONFIG_EXT4_FS=y
-+CONFIG_EXT4_FS_POSIX_ACL=y
-+CONFIG_EXT4_FS_SECURITY=y
-+CONFIG_REISERFS_FS=m
-+CONFIG_REISERFS_FS_XATTR=y
-+CONFIG_REISERFS_FS_POSIX_ACL=y
-+CONFIG_REISERFS_FS_SECURITY=y
-+CONFIG_JFS_FS=m
-+CONFIG_JFS_POSIX_ACL=y
-+CONFIG_JFS_SECURITY=y
-+CONFIG_JFS_STATISTICS=y
-+CONFIG_XFS_FS=m
-+CONFIG_XFS_QUOTA=y
-+CONFIG_XFS_POSIX_ACL=y
-+CONFIG_XFS_RT=y
-+CONFIG_GFS2_FS=m
-+CONFIG_OCFS2_FS=m
-+CONFIG_BTRFS_FS=m
-+CONFIG_BTRFS_FS_POSIX_ACL=y
-+CONFIG_NILFS2_FS=m
-+CONFIG_F2FS_FS=y
-+CONFIG_FANOTIFY=y
-+CONFIG_QFMT_V1=m
-+CONFIG_QFMT_V2=m
-+CONFIG_AUTOFS4_FS=y
-+CONFIG_FUSE_FS=m
-+CONFIG_CUSE=m
-+CONFIG_OVERLAY_FS=m
-+CONFIG_FSCACHE=y
-+CONFIG_FSCACHE_STATS=y
-+CONFIG_FSCACHE_HISTOGRAM=y
-+CONFIG_CACHEFILES=y
-+CONFIG_ISO9660_FS=m
-+CONFIG_JOLIET=y
-+CONFIG_ZISOFS=y
-+CONFIG_UDF_FS=m
-+CONFIG_MSDOS_FS=y
-+CONFIG_VFAT_FS=y
-+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
-+CONFIG_NTFS_FS=m
-+CONFIG_NTFS_RW=y
-+CONFIG_TMPFS=y
-+CONFIG_TMPFS_POSIX_ACL=y
-+CONFIG_CONFIGFS_FS=y
-+CONFIG_ECRYPT_FS=m
-+CONFIG_HFS_FS=m
-+CONFIG_HFSPLUS_FS=m
-+CONFIG_JFFS2_FS=m
-+CONFIG_JFFS2_SUMMARY=y
-+CONFIG_UBIFS_FS=m
-+CONFIG_SQUASHFS=m
-+CONFIG_SQUASHFS_XATTR=y
-+CONFIG_SQUASHFS_LZO=y
-+CONFIG_SQUASHFS_XZ=y
-+CONFIG_NFS_FS=y
-+CONFIG_NFS_V3_ACL=y
-+CONFIG_NFS_V4=y
-+CONFIG_NFS_SWAP=y
-+CONFIG_ROOT_NFS=y
-+CONFIG_NFS_FSCACHE=y
-+CONFIG_NFSD=m
-+CONFIG_NFSD_V3_ACL=y
-+CONFIG_NFSD_V4=y
-+CONFIG_CIFS=m
-+CONFIG_CIFS_WEAK_PW_HASH=y
-+CONFIG_CIFS_UPCALL=y
-+CONFIG_CIFS_XATTR=y
-+CONFIG_CIFS_POSIX=y
-+CONFIG_CIFS_ACL=y
-+CONFIG_CIFS_DFS_UPCALL=y
-+CONFIG_CIFS_SMB2=y
-+CONFIG_CIFS_FSCACHE=y
-+CONFIG_9P_FS=m
-+CONFIG_9P_FS_POSIX_ACL=y
-+CONFIG_NLS_DEFAULT="utf8"
-+CONFIG_NLS_CODEPAGE_437=y
-+CONFIG_NLS_CODEPAGE_737=m
-+CONFIG_NLS_CODEPAGE_775=m
-+CONFIG_NLS_CODEPAGE_850=m
-+CONFIG_NLS_CODEPAGE_852=m
-+CONFIG_NLS_CODEPAGE_855=m
-+CONFIG_NLS_CODEPAGE_857=m
-+CONFIG_NLS_CODEPAGE_860=m
-+CONFIG_NLS_CODEPAGE_861=m
-+CONFIG_NLS_CODEPAGE_862=m
-+CONFIG_NLS_CODEPAGE_863=m
-+CONFIG_NLS_CODEPAGE_864=m
-+CONFIG_NLS_CODEPAGE_865=m
-+CONFIG_NLS_CODEPAGE_866=m
-+CONFIG_NLS_CODEPAGE_869=m
-+CONFIG_NLS_CODEPAGE_936=m
-+CONFIG_NLS_CODEPAGE_950=m
-+CONFIG_NLS_CODEPAGE_932=m
-+CONFIG_NLS_CODEPAGE_949=m
-+CONFIG_NLS_CODEPAGE_874=m
-+CONFIG_NLS_ISO8859_8=m
-+CONFIG_NLS_CODEPAGE_1250=m
-+CONFIG_NLS_CODEPAGE_1251=m
-+CONFIG_NLS_ASCII=y
-+CONFIG_NLS_ISO8859_1=m
-+CONFIG_NLS_ISO8859_2=m
-+CONFIG_NLS_ISO8859_3=m
-+CONFIG_NLS_ISO8859_4=m
-+CONFIG_NLS_ISO8859_5=m
-+CONFIG_NLS_ISO8859_6=m
-+CONFIG_NLS_ISO8859_7=m
-+CONFIG_NLS_ISO8859_9=m
-+CONFIG_NLS_ISO8859_13=m
-+CONFIG_NLS_ISO8859_14=m
-+CONFIG_NLS_ISO8859_15=m
-+CONFIG_NLS_KOI8_R=m
-+CONFIG_NLS_KOI8_U=m
-+CONFIG_DLM=m
-+CONFIG_PRINTK_TIME=y
-+CONFIG_BOOT_PRINTK_DELAY=y
-+CONFIG_DEBUG_MEMORY_INIT=y
-+CONFIG_DETECT_HUNG_TASK=y
-+CONFIG_TIMER_STATS=y
-+CONFIG_LATENCYTOP=y
-+CONFIG_IRQSOFF_TRACER=y
-+CONFIG_SCHED_TRACER=y
-+CONFIG_STACK_TRACER=y
-+CONFIG_BLK_DEV_IO_TRACE=y
-+# CONFIG_KPROBE_EVENT is not set
-+CONFIG_FUNCTION_PROFILER=y
-+CONFIG_KGDB=y
-+CONFIG_KGDB_KDB=y
-+CONFIG_KDB_KEYBOARD=y
-+CONFIG_CRYPTO_USER=m
-+CONFIG_CRYPTO_CRYPTD=m
-+CONFIG_CRYPTO_CBC=y
-+CONFIG_CRYPTO_CTS=m
-+CONFIG_CRYPTO_XTS=m
-+CONFIG_CRYPTO_XCBC=m
-+CONFIG_CRYPTO_SHA512=m
-+CONFIG_CRYPTO_TGR192=m
-+CONFIG_CRYPTO_WP512=m
-+CONFIG_CRYPTO_CAST5=m
-+CONFIG_CRYPTO_DES=y
-+CONFIG_CRYPTO_USER_API_SKCIPHER=m
-+# CONFIG_CRYPTO_HW is not set
-+CONFIG_ARM_CRYPTO=y
-+CONFIG_CRYPTO_SHA1_ARM=m
-+CONFIG_CRYPTO_AES_ARM=m
-+CONFIG_CRC_ITU_T=y
-+CONFIG_LIBCRC32C=y
diff --git a/target/linux/brcm2708/patches-4.4/0078-bcm2835-bcm2835_defconfig.patch b/target/linux/brcm2708/patches-4.4/0078-bcm2835-bcm2835_defconfig.patch
deleted file mode 100644
index d4a60cd6ca..0000000000
--- a/target/linux/brcm2708/patches-4.4/0078-bcm2835-bcm2835_defconfig.patch
+++ /dev/null
@@ -1,1426 +0,0 @@
-From e5292198fc83805a9f4751fddeb802f69c0270f0 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
-Date: Wed, 29 Apr 2015 17:24:02 +0200
-Subject: [PATCH 078/170] bcm2835: bcm2835_defconfig
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Some options in bcm2835_defconfig are now the default and
-some have changed. Update to keep functionality.
-
-No longer available: SCSI_MULTI_LUN and RESOURCE_COUNTERS.
-
-Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
-
-bcm2835: bcm2835_defconfig enable MMC_BCM2835
-
-Enable the downstream bcm2835-mmc driver and DMA support.
-
-Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
-
-bcm2835: bcm2835_defconfig enable BCM2708_MBOX
-
-Enable the mailbox driver.
-
-Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
-
-bcm2835: bcm2835_defconfig use FB_BCM2708
-
-Enable the bcm2708 framebuffer driver.
-Disable the simple framebuffer driver, which matches the
-device handed over by u-boot.
-
-Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
-
-bcm2835: Merge bcm2835_defconfig with bcmrpi_defconfig
-
-These commands where used to make this commit:
-
-./scripts/diffconfig -m arch/arm/configs/bcm2835_defconfig arch/arm/configs/bcmrpi_defconfig > merge.cfg
-
-cat << EOF > filter
-CONFIG_ARCH_BCM2708
-CONFIG_BCM2708_DT
-CONFIG_ARM_PATCH_PHYS_VIRT
-CONFIG_PHYS_OFFSET
-CONFIG_CMDLINE
-CONFIG_BCM2708_WDT
-CONFIG_HW_RANDOM_BCM2708
-CONFIG_I2C_BCM2708
-CONFIG_SPI_BCM2708
-CONFIG_SND_BCM2708_SOC_I2S
-CONFIG_USB_DWCOTG
-CONFIG_LIRC_RPI
-EOF
-
-grep -F -v -f filter merge.cfg > filtered.cfg
-
-cat << EOF > added.cfg
-CONFIG_WATCHDOG=y
-CONFIG_BCM2835_WDT=y
-CONFIG_MISC_FILESYSTEMS=y
-CONFIG_SND_BCM2835_SOC_I2S=m
-EOF
-
-ARCH=arm scripts/kconfig/merge_config.sh arch/arm/configs/bcm2835_defconfig filtered.cfg added.cfg
-ARCH=arm make oldconfig
-
-ARCH=arm make savedefconfig
-cp defconfig arch/arm/configs/bcm2835_defconfig
-
-rm merge.cfg filter filtered.cfg added.cfg defconfig
-
-ARCH=arm make bcm2835_defconfig
-ARCH=arm make oldconfig
-
-Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
-
-configs: Incorporate v4.1 dependency changes
-
-Commit 78e9b7de78bb53e8bc7f4c4a60ebacb250c0c190 added a
-dependency on TI_ST instead of selecting it, disabling:
-CONFIG_BT_WILINK=m
-CONFIG_RADIO_WL128X=m
-
-Commit 652ccae5cc4e1305fb0a4619947f9ee89d8c7f5a added a
-depency on ARM_CRYPTO, disabling:
-CONFIG_CRYPTO_SHA*_ARM*=m
-CONFIG_CRYPTO_AES_ARM*=m
-
-Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
-
-Conflicts:
- arch/arm/configs/bcm2709_defconfig
-
-bcm2835: Sync bcm2835_defconfig with bcmrpi_defconfig
-
-These commands where used to make this commit:
-
-: Get changed and new config values from a merge
-./scripts/diffconfig -m arch/arm/configs/bcm2835_defconfig arch/arm/configs/bcmrpi_defconfig > merge.cfg
-
-: Remove these options
-cat << EOF > filter
-CONFIG_ARCH_BCM2708
-CONFIG_BCM2708_DT
-CONFIG_ARM_PATCH_PHYS_VIRT
-CONFIG_PHYS_OFFSET
-CONFIG_CMDLINE
-CONFIG_BCM2708_WDT
-CONFIG_HW_RANDOM_BCM2708
-CONFIG_SPI_BCM2708
-EOF
-
-: Apply filter
-grep -F -v -f filter merge.cfg > filtered.cfg
-
-: Add these options
-: watchdog contains the restart/poweroff code.
-cat << EOF > added.cfg
-CONFIG_WATCHDOG=y
-CONFIG_BCM2835_WDT=y
-CONFIG_MISC_FILESYSTEMS=y
-CONFIG_I2C_BCM2835=m
-CONFIG_SND_BCM2835_SOC_I2S=m
-EOF
-
-: Create new config
-ARCH=arm scripts/kconfig/merge_config.sh arch/arm/configs/bcm2835_defconfig filtered.cfg added.cfg
-: Verify
-ARCH=arm make oldconfig
-
-: Update bcm2835_defconfig
-ARCH=arm make savedefconfig
-cp defconfig arch/arm/configs/bcm2835_defconfig
-
-: Clean up
-rm merge.cfg filter filtered.cfg added.cfg defconfig
-
-Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
----
- arch/arm/configs/bcm2835_defconfig | 1166 +++++++++++++++++++++++++++++++++++-
- 1 file changed, 1140 insertions(+), 26 deletions(-)
-
---- a/arch/arm/configs/bcm2835_defconfig
-+++ b/arch/arm/configs/bcm2835_defconfig
-@@ -1,105 +1,1103 @@
- # CONFIG_LOCALVERSION_AUTO is not set
- CONFIG_SYSVIPC=y
-+CONFIG_POSIX_MQUEUE=y
- CONFIG_FHANDLE=y
- CONFIG_NO_HZ=y
- CONFIG_HIGH_RES_TIMERS=y
- CONFIG_BSD_PROCESS_ACCT=y
- CONFIG_BSD_PROCESS_ACCT_V3=y
-+CONFIG_TASKSTATS=y
-+CONFIG_TASK_DELAY_ACCT=y
-+CONFIG_TASK_XACCT=y
-+CONFIG_TASK_IO_ACCOUNTING=y
-+CONFIG_IKCONFIG=m
-+CONFIG_IKCONFIG_PROC=y
- CONFIG_LOG_BUF_SHIFT=18
- CONFIG_CGROUP_FREEZER=y
- CONFIG_CGROUP_DEVICE=y
- CONFIG_CPUSETS=y
- CONFIG_CGROUP_CPUACCT=y
--CONFIG_RESOURCE_COUNTERS=y
-+CONFIG_MEMCG=y
- CONFIG_CGROUP_PERF=y
- CONFIG_CFS_BANDWIDTH=y
- CONFIG_RT_GROUP_SCHED=y
-+CONFIG_BLK_CGROUP=y
- CONFIG_NAMESPACES=y
- CONFIG_SCHED_AUTOGROUP=y
--CONFIG_RELAY=y
- CONFIG_BLK_DEV_INITRD=y
--CONFIG_RD_BZIP2=y
--CONFIG_RD_LZMA=y
--CONFIG_RD_XZ=y
--CONFIG_RD_LZO=y
- CONFIG_CC_OPTIMIZE_FOR_SIZE=y
--CONFIG_KALLSYMS_ALL=y
- CONFIG_EMBEDDED=y
- # CONFIG_COMPAT_BRK is not set
- CONFIG_PROFILING=y
--CONFIG_OPROFILE=y
-+CONFIG_OPROFILE=m
-+CONFIG_KPROBES=y
- CONFIG_JUMP_LABEL=y
-+CONFIG_CC_STACKPROTECTOR_REGULAR=y
-+CONFIG_MODULES=y
-+CONFIG_MODULE_UNLOAD=y
-+CONFIG_MODVERSIONS=y
-+CONFIG_MODULE_SRCVERSION_ALL=y
-+CONFIG_BLK_DEV_THROTTLING=y
-+CONFIG_PARTITION_ADVANCED=y
-+CONFIG_MAC_PARTITION=y
-+CONFIG_CFQ_GROUP_IOSCHED=y
- CONFIG_ARCH_MULTI_V6=y
- # CONFIG_ARCH_MULTI_V7 is not set
- CONFIG_ARCH_BCM=y
- CONFIG_ARCH_BCM2835=y
--CONFIG_PREEMPT_VOLUNTARY=y
-+CONFIG_PREEMPT=y
- CONFIG_AEABI=y
-+CONFIG_OABI_COMPAT=y
- CONFIG_KSM=y
- CONFIG_CLEANCACHE=y
-+CONFIG_FRONTSWAP=y
-+CONFIG_CMA=y
-+CONFIG_ZSMALLOC=m
-+CONFIG_PGTABLE_MAPPING=y
-+CONFIG_UACCESS_WITH_MEMCPY=y
- CONFIG_SECCOMP=y
--CONFIG_CC_STACKPROTECTOR=y
-+CONFIG_ZBOOT_ROM_TEXT=0x0
-+CONFIG_ZBOOT_ROM_BSS=0x0
- CONFIG_KEXEC=y
- CONFIG_CRASH_DUMP=y
-+CONFIG_CPU_FREQ=y
-+CONFIG_CPU_FREQ_STAT=m
-+CONFIG_CPU_FREQ_STAT_DETAILS=y
-+CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE=y
-+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
-+CONFIG_CPU_FREQ_GOV_USERSPACE=y
-+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
- CONFIG_VFP=y
- # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-+CONFIG_BINFMT_MISC=m
- # CONFIG_SUSPEND is not set
- CONFIG_NET=y
- CONFIG_PACKET=y
- CONFIG_UNIX=y
-+CONFIG_XFRM_USER=y
-+CONFIG_NET_KEY=m
- CONFIG_INET=y
-+CONFIG_IP_MULTICAST=y
-+CONFIG_IP_ADVANCED_ROUTER=y
-+CONFIG_IP_MULTIPLE_TABLES=y
-+CONFIG_IP_ROUTE_MULTIPATH=y
-+CONFIG_IP_ROUTE_VERBOSE=y
-+CONFIG_IP_PNP=y
-+CONFIG_IP_PNP_DHCP=y
-+CONFIG_IP_PNP_RARP=y
-+CONFIG_NET_IPIP=m
-+CONFIG_NET_IPGRE_DEMUX=m
-+CONFIG_NET_IPGRE=m
-+CONFIG_IP_MROUTE=y
-+CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
-+CONFIG_IP_PIMSM_V1=y
-+CONFIG_IP_PIMSM_V2=y
-+CONFIG_SYN_COOKIES=y
-+CONFIG_INET_AH=m
-+CONFIG_INET_ESP=m
-+CONFIG_INET_IPCOMP=m
-+CONFIG_INET_XFRM_MODE_TRANSPORT=m
-+CONFIG_INET_XFRM_MODE_TUNNEL=m
-+CONFIG_INET_XFRM_MODE_BEET=m
-+CONFIG_INET_LRO=m
-+CONFIG_INET_DIAG=m
-+CONFIG_INET6_AH=m
-+CONFIG_INET6_ESP=m
-+CONFIG_INET6_IPCOMP=m
-+CONFIG_IPV6_TUNNEL=m
-+CONFIG_IPV6_MULTIPLE_TABLES=y
-+CONFIG_IPV6_MROUTE=y
-+CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
-+CONFIG_IPV6_PIMSM_V2=y
- CONFIG_NETWORK_SECMARK=y
- CONFIG_NETFILTER=y
--CONFIG_CFG80211=y
--CONFIG_MAC80211=y
-+CONFIG_NF_CONNTRACK=m
-+CONFIG_NF_CONNTRACK_ZONES=y
-+CONFIG_NF_CONNTRACK_EVENTS=y
-+CONFIG_NF_CONNTRACK_TIMESTAMP=y
-+CONFIG_NF_CT_PROTO_DCCP=m
-+CONFIG_NF_CT_PROTO_UDPLITE=m
-+CONFIG_NF_CONNTRACK_AMANDA=m
-+CONFIG_NF_CONNTRACK_FTP=m
-+CONFIG_NF_CONNTRACK_H323=m
-+CONFIG_NF_CONNTRACK_IRC=m
-+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
-+CONFIG_NF_CONNTRACK_SNMP=m
-+CONFIG_NF_CONNTRACK_PPTP=m
-+CONFIG_NF_CONNTRACK_SANE=m
-+CONFIG_NF_CONNTRACK_SIP=m
-+CONFIG_NF_CONNTRACK_TFTP=m
-+CONFIG_NF_CT_NETLINK=m
-+CONFIG_NETFILTER_XT_SET=m
-+CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
-+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
-+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
-+CONFIG_NETFILTER_XT_TARGET_DSCP=m
-+CONFIG_NETFILTER_XT_TARGET_HMARK=m
-+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
-+CONFIG_NETFILTER_XT_TARGET_LED=m
-+CONFIG_NETFILTER_XT_TARGET_LOG=m
-+CONFIG_NETFILTER_XT_TARGET_MARK=m
-+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
-+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
-+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
-+CONFIG_NETFILTER_XT_TARGET_TEE=m
-+CONFIG_NETFILTER_XT_TARGET_TPROXY=m
-+CONFIG_NETFILTER_XT_TARGET_TRACE=m
-+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
-+CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
-+CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m
-+CONFIG_NETFILTER_XT_MATCH_BPF=m
-+CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
-+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
-+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
-+CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m
-+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
-+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
-+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
-+CONFIG_NETFILTER_XT_MATCH_CPU=m
-+CONFIG_NETFILTER_XT_MATCH_DCCP=m
-+CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m
-+CONFIG_NETFILTER_XT_MATCH_DSCP=m
-+CONFIG_NETFILTER_XT_MATCH_ESP=m
-+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
-+CONFIG_NETFILTER_XT_MATCH_HELPER=m
-+CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
-+CONFIG_NETFILTER_XT_MATCH_IPVS=m
-+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
-+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
-+CONFIG_NETFILTER_XT_MATCH_MAC=m
-+CONFIG_NETFILTER_XT_MATCH_MARK=m
-+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
-+CONFIG_NETFILTER_XT_MATCH_NFACCT=m
-+CONFIG_NETFILTER_XT_MATCH_OSF=m
-+CONFIG_NETFILTER_XT_MATCH_OWNER=m
-+CONFIG_NETFILTER_XT_MATCH_POLICY=m
-+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
-+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
-+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
-+CONFIG_NETFILTER_XT_MATCH_RATEEST=m
-+CONFIG_NETFILTER_XT_MATCH_REALM=m
-+CONFIG_NETFILTER_XT_MATCH_RECENT=m
-+CONFIG_NETFILTER_XT_MATCH_SOCKET=m
-+CONFIG_NETFILTER_XT_MATCH_STATE=m
-+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
-+CONFIG_NETFILTER_XT_MATCH_STRING=m
-+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
-+CONFIG_NETFILTER_XT_MATCH_TIME=m
-+CONFIG_NETFILTER_XT_MATCH_U32=m
-+CONFIG_IP_SET=m
-+CONFIG_IP_SET_BITMAP_IP=m
-+CONFIG_IP_SET_BITMAP_IPMAC=m
-+CONFIG_IP_SET_BITMAP_PORT=m
-+CONFIG_IP_SET_HASH_IP=m
-+CONFIG_IP_SET_HASH_IPPORT=m
-+CONFIG_IP_SET_HASH_IPPORTIP=m
-+CONFIG_IP_SET_HASH_IPPORTNET=m
-+CONFIG_IP_SET_HASH_NET=m
-+CONFIG_IP_SET_HASH_NETPORT=m
-+CONFIG_IP_SET_HASH_NETIFACE=m
-+CONFIG_IP_SET_LIST_SET=m
-+CONFIG_IP_VS=m
-+CONFIG_IP_VS_PROTO_TCP=y
-+CONFIG_IP_VS_PROTO_UDP=y
-+CONFIG_IP_VS_PROTO_ESP=y
-+CONFIG_IP_VS_PROTO_AH=y
-+CONFIG_IP_VS_PROTO_SCTP=y
-+CONFIG_IP_VS_RR=m
-+CONFIG_IP_VS_WRR=m
-+CONFIG_IP_VS_LC=m
-+CONFIG_IP_VS_WLC=m
-+CONFIG_IP_VS_LBLC=m
-+CONFIG_IP_VS_LBLCR=m
-+CONFIG_IP_VS_DH=m
-+CONFIG_IP_VS_SH=m
-+CONFIG_IP_VS_SED=m
-+CONFIG_IP_VS_NQ=m
-+CONFIG_IP_VS_FTP=m
-+CONFIG_IP_VS_PE_SIP=m
-+CONFIG_NF_CONNTRACK_IPV4=m
-+CONFIG_IP_NF_IPTABLES=m
-+CONFIG_IP_NF_MATCH_AH=m
-+CONFIG_IP_NF_MATCH_ECN=m
-+CONFIG_IP_NF_MATCH_TTL=m
-+CONFIG_IP_NF_FILTER=m
-+CONFIG_IP_NF_TARGET_REJECT=m
-+CONFIG_IP_NF_NAT=m
-+CONFIG_IP_NF_TARGET_MASQUERADE=m
-+CONFIG_IP_NF_TARGET_NETMAP=m
-+CONFIG_IP_NF_TARGET_REDIRECT=m
-+CONFIG_IP_NF_MANGLE=m
-+CONFIG_IP_NF_TARGET_CLUSTERIP=m
-+CONFIG_IP_NF_TARGET_ECN=m
-+CONFIG_IP_NF_TARGET_TTL=m
-+CONFIG_IP_NF_RAW=m
-+CONFIG_IP_NF_ARPTABLES=m
-+CONFIG_IP_NF_ARPFILTER=m
-+CONFIG_IP_NF_ARP_MANGLE=m
-+CONFIG_NF_CONNTRACK_IPV6=m
-+CONFIG_IP6_NF_IPTABLES=m
-+CONFIG_IP6_NF_MATCH_AH=m
-+CONFIG_IP6_NF_MATCH_EUI64=m
-+CONFIG_IP6_NF_MATCH_FRAG=m
-+CONFIG_IP6_NF_MATCH_OPTS=m
-+CONFIG_IP6_NF_MATCH_HL=m
-+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
-+CONFIG_IP6_NF_MATCH_MH=m
-+CONFIG_IP6_NF_MATCH_RT=m
-+CONFIG_IP6_NF_TARGET_HL=m
-+CONFIG_IP6_NF_FILTER=m
-+CONFIG_IP6_NF_TARGET_REJECT=m
-+CONFIG_IP6_NF_MANGLE=m
-+CONFIG_IP6_NF_RAW=m
-+CONFIG_IP6_NF_NAT=m
-+CONFIG_IP6_NF_TARGET_MASQUERADE=m
-+CONFIG_IP6_NF_TARGET_NPT=m
-+CONFIG_BRIDGE_NF_EBTABLES=m
-+CONFIG_BRIDGE_EBT_BROUTE=m
-+CONFIG_BRIDGE_EBT_T_FILTER=m
-+CONFIG_BRIDGE_EBT_T_NAT=m
-+CONFIG_BRIDGE_EBT_802_3=m
-+CONFIG_BRIDGE_EBT_AMONG=m
-+CONFIG_BRIDGE_EBT_ARP=m
-+CONFIG_BRIDGE_EBT_IP=m
-+CONFIG_BRIDGE_EBT_IP6=m
-+CONFIG_BRIDGE_EBT_LIMIT=m
-+CONFIG_BRIDGE_EBT_MARK=m
-+CONFIG_BRIDGE_EBT_PKTTYPE=m
-+CONFIG_BRIDGE_EBT_STP=m
-+CONFIG_BRIDGE_EBT_VLAN=m
-+CONFIG_BRIDGE_EBT_ARPREPLY=m
-+CONFIG_BRIDGE_EBT_DNAT=m
-+CONFIG_BRIDGE_EBT_MARK_T=m
-+CONFIG_BRIDGE_EBT_REDIRECT=m
-+CONFIG_BRIDGE_EBT_SNAT=m
-+CONFIG_BRIDGE_EBT_LOG=m
-+CONFIG_BRIDGE_EBT_NFLOG=m
-+CONFIG_SCTP_COOKIE_HMAC_SHA1=y
-+CONFIG_ATM=m
-+CONFIG_L2TP=m
-+CONFIG_L2TP_V3=y
-+CONFIG_L2TP_IP=m
-+CONFIG_L2TP_ETH=m
-+CONFIG_BRIDGE=m
-+CONFIG_VLAN_8021Q=m
-+CONFIG_VLAN_8021Q_GVRP=y
-+CONFIG_ATALK=m
-+CONFIG_6LOWPAN=m
-+CONFIG_NET_SCHED=y
-+CONFIG_NET_SCH_CBQ=m
-+CONFIG_NET_SCH_HTB=m
-+CONFIG_NET_SCH_HFSC=m
-+CONFIG_NET_SCH_PRIO=m
-+CONFIG_NET_SCH_MULTIQ=m
-+CONFIG_NET_SCH_RED=m
-+CONFIG_NET_SCH_SFB=m
-+CONFIG_NET_SCH_SFQ=m
-+CONFIG_NET_SCH_TEQL=m
-+CONFIG_NET_SCH_TBF=m
-+CONFIG_NET_SCH_GRED=m
-+CONFIG_NET_SCH_DSMARK=m
-+CONFIG_NET_SCH_NETEM=m
-+CONFIG_NET_SCH_DRR=m
-+CONFIG_NET_SCH_MQPRIO=m
-+CONFIG_NET_SCH_CHOKE=m
-+CONFIG_NET_SCH_QFQ=m
-+CONFIG_NET_SCH_CODEL=m
-+CONFIG_NET_SCH_FQ_CODEL=m
-+CONFIG_NET_SCH_INGRESS=m
-+CONFIG_NET_SCH_PLUG=m
-+CONFIG_NET_CLS_BASIC=m
-+CONFIG_NET_CLS_TCINDEX=m
-+CONFIG_NET_CLS_ROUTE4=m
-+CONFIG_NET_CLS_FW=m
-+CONFIG_NET_CLS_U32=m
-+CONFIG_CLS_U32_MARK=y
-+CONFIG_NET_CLS_RSVP=m
-+CONFIG_NET_CLS_RSVP6=m
-+CONFIG_NET_CLS_FLOW=m
-+CONFIG_NET_CLS_CGROUP=m
-+CONFIG_NET_EMATCH=y
-+CONFIG_NET_EMATCH_CMP=m
-+CONFIG_NET_EMATCH_NBYTE=m
-+CONFIG_NET_EMATCH_U32=m
-+CONFIG_NET_EMATCH_META=m
-+CONFIG_NET_EMATCH_TEXT=m
-+CONFIG_NET_EMATCH_IPSET=m
-+CONFIG_NET_CLS_ACT=y
-+CONFIG_NET_ACT_POLICE=m
-+CONFIG_NET_ACT_GACT=m
-+CONFIG_GACT_PROB=y
-+CONFIG_NET_ACT_MIRRED=m
-+CONFIG_NET_ACT_IPT=m
-+CONFIG_NET_ACT_NAT=m
-+CONFIG_NET_ACT_PEDIT=m
-+CONFIG_NET_ACT_SIMP=m
-+CONFIG_NET_ACT_SKBEDIT=m
-+CONFIG_NET_ACT_CSUM=m
-+CONFIG_BATMAN_ADV=m
-+CONFIG_OPENVSWITCH=m
-+CONFIG_NET_PKTGEN=m
-+CONFIG_HAMRADIO=y
-+CONFIG_AX25=m
-+CONFIG_NETROM=m
-+CONFIG_ROSE=m
-+CONFIG_MKISS=m
-+CONFIG_6PACK=m
-+CONFIG_BPQETHER=m
-+CONFIG_BAYCOM_SER_FDX=m
-+CONFIG_BAYCOM_SER_HDX=m
-+CONFIG_YAM=m
-+CONFIG_CAN=m
-+CONFIG_CAN_VCAN=m
-+CONFIG_CAN_MCP251X=m
-+CONFIG_IRDA=m
-+CONFIG_IRLAN=m
-+CONFIG_IRNET=m
-+CONFIG_IRCOMM=m
-+CONFIG_IRDA_ULTRA=y
-+CONFIG_IRDA_CACHE_LAST_LSAP=y
-+CONFIG_IRDA_FAST_RR=y
-+CONFIG_IRTTY_SIR=m
-+CONFIG_KINGSUN_DONGLE=m
-+CONFIG_KSDAZZLE_DONGLE=m
-+CONFIG_KS959_DONGLE=m
-+CONFIG_USB_IRDA=m
-+CONFIG_SIGMATEL_FIR=m
-+CONFIG_MCS_FIR=m
-+CONFIG_BT=m
-+CONFIG_BT_RFCOMM=m
-+CONFIG_BT_RFCOMM_TTY=y
-+CONFIG_BT_BNEP=m
-+CONFIG_BT_BNEP_MC_FILTER=y
-+CONFIG_BT_BNEP_PROTO_FILTER=y
-+CONFIG_BT_HIDP=m
-+CONFIG_BT_6LOWPAN=m
-+CONFIG_BT_HCIBTUSB=m
-+CONFIG_BT_HCIBCM203X=m
-+CONFIG_BT_HCIBPA10X=m
-+CONFIG_BT_HCIBFUSB=m
-+CONFIG_BT_HCIVHCI=m
-+CONFIG_BT_MRVL=m
-+CONFIG_BT_MRVL_SDIO=m
-+CONFIG_BT_ATH3K=m
-+CONFIG_BT_WILINK=m
-+CONFIG_MAC80211=m
-+CONFIG_MAC80211_MESH=y
-+CONFIG_WIMAX=m
-+CONFIG_RFKILL=m
-+CONFIG_RFKILL_INPUT=y
-+CONFIG_NET_9P=m
-+CONFIG_NFC=m
-+CONFIG_NFC_PN533=m
- CONFIG_DEVTMPFS=y
- CONFIG_DEVTMPFS_MOUNT=y
- # CONFIG_STANDALONE is not set
-+CONFIG_DMA_CMA=y
-+CONFIG_CMA_SIZE_MBYTES=5
-+CONFIG_ZRAM=m
-+CONFIG_ZRAM_LZ4_COMPRESS=y
-+CONFIG_BLK_DEV_LOOP=y
-+CONFIG_BLK_DEV_CRYPTOLOOP=m
-+CONFIG_BLK_DEV_DRBD=m
-+CONFIG_BLK_DEV_NBD=m
-+CONFIG_BLK_DEV_RAM=y
-+CONFIG_CDROM_PKTCDVD=m
-+CONFIG_ATA_OVER_ETH=m
-+CONFIG_EEPROM_AT24=m
-+CONFIG_TI_ST=m
- CONFIG_SCSI=y
-+# CONFIG_SCSI_PROC_FS is not set
- CONFIG_BLK_DEV_SD=y
--CONFIG_SCSI_MULTI_LUN=y
-+CONFIG_CHR_DEV_ST=m
-+CONFIG_CHR_DEV_OSST=m
-+CONFIG_BLK_DEV_SR=m
-+CONFIG_CHR_DEV_SG=m
- CONFIG_SCSI_CONSTANTS=y
- CONFIG_SCSI_SCAN_ASYNC=y
-+CONFIG_SCSI_ISCSI_ATTRS=y
-+CONFIG_ISCSI_TCP=m
-+CONFIG_ISCSI_BOOT_SYSFS=m
-+CONFIG_MD=y
-+CONFIG_MD_LINEAR=m
-+CONFIG_MD_RAID0=m
-+CONFIG_BLK_DEV_DM=m
-+CONFIG_DM_CRYPT=m
-+CONFIG_DM_SNAPSHOT=m
-+CONFIG_DM_MIRROR=m
-+CONFIG_DM_LOG_USERSPACE=m
-+CONFIG_DM_RAID=m
-+CONFIG_DM_ZERO=m
-+CONFIG_DM_DELAY=m
- CONFIG_NETDEVICES=y
-+CONFIG_BONDING=m
-+CONFIG_DUMMY=m
-+CONFIG_IFB=m
-+CONFIG_MACVLAN=m
-+CONFIG_NETCONSOLE=m
-+CONFIG_TUN=m
-+CONFIG_VETH=m
-+CONFIG_ENC28J60=m
-+CONFIG_MDIO_BITBANG=m
-+CONFIG_PPP=m
-+CONFIG_PPP_BSDCOMP=m
-+CONFIG_PPP_DEFLATE=m
-+CONFIG_PPP_FILTER=y
-+CONFIG_PPP_MPPE=m
-+CONFIG_PPP_MULTILINK=y
-+CONFIG_PPPOATM=m
-+CONFIG_PPPOE=m
-+CONFIG_PPPOL2TP=m
-+CONFIG_PPP_ASYNC=m
-+CONFIG_PPP_SYNC_TTY=m
-+CONFIG_SLIP=m
-+CONFIG_SLIP_COMPRESSED=y
-+CONFIG_SLIP_SMART=y
-+CONFIG_USB_CATC=m
-+CONFIG_USB_KAWETH=m
-+CONFIG_USB_PEGASUS=m
-+CONFIG_USB_RTL8150=m
-+CONFIG_USB_RTL8152=m
- CONFIG_USB_USBNET=y
-+CONFIG_USB_NET_AX8817X=m
-+CONFIG_USB_NET_AX88179_178A=m
-+CONFIG_USB_NET_CDCETHER=m
-+CONFIG_USB_NET_CDC_EEM=m
-+CONFIG_USB_NET_CDC_NCM=m
-+CONFIG_USB_NET_HUAWEI_CDC_NCM=m
-+CONFIG_USB_NET_CDC_MBIM=m
-+CONFIG_USB_NET_DM9601=m
-+CONFIG_USB_NET_SR9700=m
-+CONFIG_USB_NET_SR9800=m
-+CONFIG_USB_NET_SMSC75XX=m
- CONFIG_USB_NET_SMSC95XX=y
--CONFIG_ZD1211RW=y
--CONFIG_INPUT_EVDEV=y
-+CONFIG_USB_NET_GL620A=m
-+CONFIG_USB_NET_NET1080=m
-+CONFIG_USB_NET_PLUSB=m
-+CONFIG_USB_NET_MCS7830=m
-+CONFIG_USB_NET_CDC_SUBSET=m
-+CONFIG_USB_ALI_M5632=y
-+CONFIG_USB_AN2720=y
-+CONFIG_USB_EPSON2888=y
-+CONFIG_USB_KC2190=y
-+CONFIG_USB_NET_ZAURUS=m
-+CONFIG_USB_NET_CX82310_ETH=m
-+CONFIG_USB_NET_KALMIA=m
-+CONFIG_USB_NET_QMI_WWAN=m
-+CONFIG_USB_HSO=m
-+CONFIG_USB_NET_INT51X1=m
-+CONFIG_USB_IPHETH=m
-+CONFIG_USB_SIERRA_NET=m
-+CONFIG_USB_VL600=m
-+CONFIG_LIBERTAS_THINFIRM=m
-+CONFIG_LIBERTAS_THINFIRM_USB=m
-+CONFIG_AT76C50X_USB=m
-+CONFIG_USB_ZD1201=m
-+CONFIG_USB_NET_RNDIS_WLAN=m
-+CONFIG_RTL8187=m
-+CONFIG_MAC80211_HWSIM=m
-+CONFIG_ATH_CARDS=m
-+CONFIG_ATH9K=m
-+CONFIG_ATH9K_HTC=m
-+CONFIG_CARL9170=m
-+CONFIG_ATH6KL=m
-+CONFIG_ATH6KL_USB=m
-+CONFIG_AR5523=m
-+CONFIG_B43=m
-+# CONFIG_B43_PHY_N is not set
-+CONFIG_B43LEGACY=m
-+CONFIG_BRCMFMAC=m
-+CONFIG_BRCMFMAC_USB=y
-+CONFIG_HOSTAP=m
-+CONFIG_LIBERTAS=m
-+CONFIG_LIBERTAS_USB=m
-+CONFIG_LIBERTAS_SDIO=m
-+CONFIG_P54_COMMON=m
-+CONFIG_P54_USB=m
-+CONFIG_RT2X00=m
-+CONFIG_RT2500USB=m
-+CONFIG_RT73USB=m
-+CONFIG_RT2800USB=m
-+CONFIG_RT2800USB_RT3573=y
-+CONFIG_RT2800USB_RT53XX=y
-+CONFIG_RT2800USB_RT55XX=y
-+CONFIG_RT2800USB_UNKNOWN=y
-+CONFIG_WL_MEDIATEK=y
-+CONFIG_MT7601U=m
-+CONFIG_RTL8192CU=m
-+CONFIG_ZD1211RW=m
-+CONFIG_MWIFIEX=m
-+CONFIG_MWIFIEX_SDIO=m
-+CONFIG_WIMAX_I2400M_USB=m
-+CONFIG_INPUT_POLLDEV=m
-+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-+CONFIG_INPUT_JOYDEV=m
-+CONFIG_INPUT_EVDEV=m
-+# CONFIG_KEYBOARD_ATKBD is not set
-+CONFIG_KEYBOARD_GPIO=m
-+# CONFIG_INPUT_MOUSE is not set
-+CONFIG_INPUT_JOYSTICK=y
-+CONFIG_JOYSTICK_IFORCE=m
-+CONFIG_JOYSTICK_IFORCE_USB=y
-+CONFIG_JOYSTICK_XPAD=m
-+CONFIG_JOYSTICK_XPAD_FF=y
-+CONFIG_JOYSTICK_RPISENSE=m
-+CONFIG_INPUT_TOUCHSCREEN=y
-+CONFIG_TOUCHSCREEN_ADS7846=m
-+CONFIG_TOUCHSCREEN_EGALAX=m
-+CONFIG_TOUCHSCREEN_RPI_FT5406=m
-+CONFIG_TOUCHSCREEN_USB_COMPOSITE=m
-+CONFIG_TOUCHSCREEN_STMPE=m
-+CONFIG_INPUT_MISC=y
-+CONFIG_INPUT_AD714X=m
-+CONFIG_INPUT_ATI_REMOTE2=m
-+CONFIG_INPUT_KEYSPAN_REMOTE=m
-+CONFIG_INPUT_POWERMATE=m
-+CONFIG_INPUT_YEALINK=m
-+CONFIG_INPUT_CM109=m
-+CONFIG_INPUT_UINPUT=m
-+CONFIG_INPUT_GPIO_ROTARY_ENCODER=m
-+CONFIG_INPUT_ADXL34X=m
-+CONFIG_INPUT_CMA3000=m
-+CONFIG_SERIO=m
-+CONFIG_SERIO_RAW=m
-+CONFIG_GAMEPORT=m
-+CONFIG_GAMEPORT_NS558=m
-+CONFIG_GAMEPORT_L4=m
-+CONFIG_BRCM_CHAR_DRIVERS=y
-+CONFIG_BCM_VC_CMA=y
-+CONFIG_BCM_VCIO=y
-+CONFIG_BCM_VC_SM=y
-+CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
- # CONFIG_LEGACY_PTYS is not set
- # CONFIG_DEVKMEM is not set
-+CONFIG_SERIAL_8250=y
-+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
-+CONFIG_SERIAL_8250_CONSOLE=y
-+# CONFIG_SERIAL_8250_DMA is not set
-+CONFIG_SERIAL_8250_NR_UARTS=1
-+CONFIG_SERIAL_8250_RUNTIME_UARTS=0
- CONFIG_SERIAL_AMBA_PL011=y
- CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
-+CONFIG_SERIAL_OF_PLATFORM=y
- CONFIG_TTY_PRINTK=y
-+CONFIG_HW_RANDOM=y
-+CONFIG_HW_RANDOM_BCM2835=m
-+CONFIG_RAW_DRIVER=y
- CONFIG_I2C=y
--CONFIG_I2C_CHARDEV=y
--CONFIG_I2C_BCM2835=y
-+CONFIG_I2C_CHARDEV=m
-+CONFIG_I2C_BCM2708=m
-+CONFIG_I2C_BCM2835=m
- CONFIG_SPI=y
--CONFIG_SPI_BCM2835=y
-+CONFIG_SPI_BCM2835=m
-+CONFIG_SPI_SPIDEV=y
-+CONFIG_PPS=m
-+CONFIG_PPS_CLIENT_LDISC=m
-+CONFIG_PPS_CLIENT_GPIO=m
- CONFIG_GPIO_SYSFS=y
-+CONFIG_GPIO_ARIZONA=m
-+CONFIG_GPIO_STMPE=y
-+CONFIG_W1=m
-+CONFIG_W1_MASTER_DS2490=m
-+CONFIG_W1_MASTER_DS2482=m
-+CONFIG_W1_MASTER_DS1WM=m
-+CONFIG_W1_MASTER_GPIO=m
-+CONFIG_W1_SLAVE_THERM=m
-+CONFIG_W1_SLAVE_SMEM=m
-+CONFIG_W1_SLAVE_DS2408=m
-+CONFIG_W1_SLAVE_DS2413=m
-+CONFIG_W1_SLAVE_DS2406=m
-+CONFIG_W1_SLAVE_DS2423=m
-+CONFIG_W1_SLAVE_DS2431=m
-+CONFIG_W1_SLAVE_DS2433=m
-+CONFIG_W1_SLAVE_DS2760=m
-+CONFIG_W1_SLAVE_DS2780=m
-+CONFIG_W1_SLAVE_DS2781=m
-+CONFIG_W1_SLAVE_DS28E04=m
-+CONFIG_W1_SLAVE_BQ27000=m
-+CONFIG_BATTERY_DS2760=m
-+CONFIG_POWER_RESET=y
-+CONFIG_POWER_RESET_GPIO=y
- # CONFIG_HWMON is not set
-+CONFIG_THERMAL=y
-+CONFIG_THERMAL_BCM2835=y
-+CONFIG_WATCHDOG=y
-+CONFIG_BCM2835_WDT=y
-+CONFIG_UCB1400_CORE=m
-+CONFIG_MFD_STMPE=y
-+CONFIG_STMPE_SPI=y
-+CONFIG_MFD_ARIZONA_I2C=m
-+CONFIG_MFD_ARIZONA_SPI=m
-+CONFIG_MFD_WM5102=y
-+CONFIG_MEDIA_SUPPORT=m
-+CONFIG_MEDIA_CAMERA_SUPPORT=y
-+CONFIG_MEDIA_ANALOG_TV_SUPPORT=y
-+CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y
-+CONFIG_MEDIA_RADIO_SUPPORT=y
-+CONFIG_MEDIA_RC_SUPPORT=y
-+CONFIG_MEDIA_CONTROLLER=y
-+CONFIG_LIRC=m
-+CONFIG_RC_DEVICES=y
-+CONFIG_RC_ATI_REMOTE=m
-+CONFIG_IR_IMON=m
-+CONFIG_IR_MCEUSB=m
-+CONFIG_IR_REDRAT3=m
-+CONFIG_IR_STREAMZAP=m
-+CONFIG_IR_IGUANA=m
-+CONFIG_IR_TTUSBIR=m
-+CONFIG_RC_LOOPBACK=m
-+CONFIG_IR_GPIO_CIR=m
-+CONFIG_MEDIA_USB_SUPPORT=y
-+CONFIG_USB_VIDEO_CLASS=m
-+CONFIG_USB_M5602=m
-+CONFIG_USB_STV06XX=m
-+CONFIG_USB_GL860=m
-+CONFIG_USB_GSPCA_BENQ=m
-+CONFIG_USB_GSPCA_CONEX=m
-+CONFIG_USB_GSPCA_CPIA1=m
-+CONFIG_USB_GSPCA_DTCS033=m
-+CONFIG_USB_GSPCA_ETOMS=m
-+CONFIG_USB_GSPCA_FINEPIX=m
-+CONFIG_USB_GSPCA_JEILINJ=m
-+CONFIG_USB_GSPCA_JL2005BCD=m
-+CONFIG_USB_GSPCA_KINECT=m
-+CONFIG_USB_GSPCA_KONICA=m
-+CONFIG_USB_GSPCA_MARS=m
-+CONFIG_USB_GSPCA_MR97310A=m
-+CONFIG_USB_GSPCA_NW80X=m
-+CONFIG_USB_GSPCA_OV519=m
-+CONFIG_USB_GSPCA_OV534=m
-+CONFIG_USB_GSPCA_OV534_9=m
-+CONFIG_USB_GSPCA_PAC207=m
-+CONFIG_USB_GSPCA_PAC7302=m
-+CONFIG_USB_GSPCA_PAC7311=m
-+CONFIG_USB_GSPCA_SE401=m
-+CONFIG_USB_GSPCA_SN9C2028=m
-+CONFIG_USB_GSPCA_SN9C20X=m
-+CONFIG_USB_GSPCA_SONIXB=m
-+CONFIG_USB_GSPCA_SONIXJ=m
-+CONFIG_USB_GSPCA_SPCA500=m
-+CONFIG_USB_GSPCA_SPCA501=m
-+CONFIG_USB_GSPCA_SPCA505=m
-+CONFIG_USB_GSPCA_SPCA506=m
-+CONFIG_USB_GSPCA_SPCA508=m
-+CONFIG_USB_GSPCA_SPCA561=m
-+CONFIG_USB_GSPCA_SPCA1528=m
-+CONFIG_USB_GSPCA_SQ905=m
-+CONFIG_USB_GSPCA_SQ905C=m
-+CONFIG_USB_GSPCA_SQ930X=m
-+CONFIG_USB_GSPCA_STK014=m
-+CONFIG_USB_GSPCA_STK1135=m
-+CONFIG_USB_GSPCA_STV0680=m
-+CONFIG_USB_GSPCA_SUNPLUS=m
-+CONFIG_USB_GSPCA_T613=m
-+CONFIG_USB_GSPCA_TOPRO=m
-+CONFIG_USB_GSPCA_TV8532=m
-+CONFIG_USB_GSPCA_VC032X=m
-+CONFIG_USB_GSPCA_VICAM=m
-+CONFIG_USB_GSPCA_XIRLINK_CIT=m
-+CONFIG_USB_GSPCA_ZC3XX=m
-+CONFIG_USB_PWC=m
-+CONFIG_VIDEO_CPIA2=m
-+CONFIG_USB_ZR364XX=m
-+CONFIG_USB_STKWEBCAM=m
-+CONFIG_USB_S2255=m
-+CONFIG_VIDEO_USBTV=m
-+CONFIG_VIDEO_PVRUSB2=m
-+CONFIG_VIDEO_HDPVR=m
-+CONFIG_VIDEO_USBVISION=m
-+CONFIG_VIDEO_STK1160_COMMON=m
-+CONFIG_VIDEO_STK1160_AC97=y
-+CONFIG_VIDEO_GO7007=m
-+CONFIG_VIDEO_GO7007_USB=m
-+CONFIG_VIDEO_GO7007_USB_S2250_BOARD=m
-+CONFIG_VIDEO_AU0828=m
-+CONFIG_VIDEO_AU0828_RC=y
-+CONFIG_VIDEO_CX231XX=m
-+CONFIG_VIDEO_CX231XX_ALSA=m
-+CONFIG_VIDEO_CX231XX_DVB=m
-+CONFIG_VIDEO_TM6000=m
-+CONFIG_VIDEO_TM6000_ALSA=m
-+CONFIG_VIDEO_TM6000_DVB=m
-+CONFIG_DVB_USB=m
-+CONFIG_DVB_USB_A800=m
-+CONFIG_DVB_USB_DIBUSB_MB=m
-+CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y
-+CONFIG_DVB_USB_DIBUSB_MC=m
-+CONFIG_DVB_USB_DIB0700=m
-+CONFIG_DVB_USB_UMT_010=m
-+CONFIG_DVB_USB_CXUSB=m
-+CONFIG_DVB_USB_M920X=m
-+CONFIG_DVB_USB_DIGITV=m
-+CONFIG_DVB_USB_VP7045=m
-+CONFIG_DVB_USB_VP702X=m
-+CONFIG_DVB_USB_GP8PSK=m
-+CONFIG_DVB_USB_NOVA_T_USB2=m
-+CONFIG_DVB_USB_TTUSB2=m
-+CONFIG_DVB_USB_DTT200U=m
-+CONFIG_DVB_USB_OPERA1=m
-+CONFIG_DVB_USB_AF9005=m
-+CONFIG_DVB_USB_AF9005_REMOTE=m
-+CONFIG_DVB_USB_PCTV452E=m
-+CONFIG_DVB_USB_DW2102=m
-+CONFIG_DVB_USB_CINERGY_T2=m
-+CONFIG_DVB_USB_DTV5100=m
-+CONFIG_DVB_USB_FRIIO=m
-+CONFIG_DVB_USB_AZ6027=m
-+CONFIG_DVB_USB_TECHNISAT_USB2=m
-+CONFIG_DVB_USB_V2=m
-+CONFIG_DVB_USB_AF9015=m
-+CONFIG_DVB_USB_AF9035=m
-+CONFIG_DVB_USB_ANYSEE=m
-+CONFIG_DVB_USB_AU6610=m
-+CONFIG_DVB_USB_AZ6007=m
-+CONFIG_DVB_USB_CE6230=m
-+CONFIG_DVB_USB_EC168=m
-+CONFIG_DVB_USB_GL861=m
-+CONFIG_DVB_USB_LME2510=m
-+CONFIG_DVB_USB_MXL111SF=m
-+CONFIG_DVB_USB_RTL28XXU=m
-+CONFIG_DVB_USB_DVBSKY=m
-+CONFIG_SMS_USB_DRV=m
-+CONFIG_DVB_B2C2_FLEXCOP_USB=m
-+CONFIG_DVB_AS102=m
-+CONFIG_VIDEO_EM28XX=m
-+CONFIG_VIDEO_EM28XX_V4L2=m
-+CONFIG_VIDEO_EM28XX_ALSA=m
-+CONFIG_VIDEO_EM28XX_DVB=m
-+CONFIG_V4L_PLATFORM_DRIVERS=y
-+CONFIG_VIDEO_BCM2835=y
-+CONFIG_VIDEO_BCM2835_MMAL=m
-+CONFIG_RADIO_SI470X=y
-+CONFIG_USB_SI470X=m
-+CONFIG_I2C_SI470X=m
-+CONFIG_RADIO_SI4713=m
-+CONFIG_I2C_SI4713=m
-+CONFIG_USB_MR800=m
-+CONFIG_USB_DSBR=m
-+CONFIG_RADIO_SHARK=m
-+CONFIG_RADIO_SHARK2=m
-+CONFIG_USB_KEENE=m
-+CONFIG_USB_MA901=m
-+CONFIG_RADIO_TEA5764=m
-+CONFIG_RADIO_SAA7706H=m
-+CONFIG_RADIO_TEF6862=m
-+CONFIG_RADIO_WL1273=m
-+CONFIG_RADIO_WL128X=m
-+# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
-+CONFIG_VIDEO_UDA1342=m
-+CONFIG_VIDEO_SONY_BTF_MPX=m
-+CONFIG_VIDEO_TVP5150=m
-+CONFIG_VIDEO_TW2804=m
-+CONFIG_VIDEO_TW9903=m
-+CONFIG_VIDEO_TW9906=m
-+CONFIG_VIDEO_OV7640=m
-+CONFIG_VIDEO_MT9V011=m
- CONFIG_FB=y
--CONFIG_FB_SIMPLE=y
-+CONFIG_FB_BCM2708=y
-+CONFIG_FB_SSD1307=m
-+CONFIG_FB_RPISENSE=m
-+# CONFIG_BACKLIGHT_GENERIC is not set
-+CONFIG_BACKLIGHT_GPIO=m
- CONFIG_FRAMEBUFFER_CONSOLE=y
- CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
-+CONFIG_LOGO=y
-+# CONFIG_LOGO_LINUX_MONO is not set
-+# CONFIG_LOGO_LINUX_VGA16 is not set
-+CONFIG_SOUND=y
-+CONFIG_SND=m
-+CONFIG_SND_SEQUENCER=m
-+CONFIG_SND_SEQ_DUMMY=m
-+CONFIG_SND_MIXER_OSS=m
-+CONFIG_SND_PCM_OSS=m
-+CONFIG_SND_SEQUENCER_OSS=y
-+CONFIG_SND_HRTIMER=m
-+CONFIG_SND_DUMMY=m
-+CONFIG_SND_ALOOP=m
-+CONFIG_SND_VIRMIDI=m
-+CONFIG_SND_MTPAV=m
-+CONFIG_SND_SERIAL_U16550=m
-+CONFIG_SND_MPU401=m
-+CONFIG_SND_BCM2835=m
-+CONFIG_SND_USB_AUDIO=m
-+CONFIG_SND_USB_UA101=m
-+CONFIG_SND_USB_CAIAQ=m
-+CONFIG_SND_USB_CAIAQ_INPUT=y
-+CONFIG_SND_USB_6FIRE=m
-+CONFIG_SND_SOC=m
-+CONFIG_SND_BCM2835_SOC_I2S=m
-+CONFIG_SND_BCM2708_SOC_I2S=m
-+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC=m
-+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS=m
-+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI=m
-+CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP=m
-+CONFIG_SND_BCM2708_SOC_RPI_DAC=m
-+CONFIG_SND_BCM2708_SOC_RPI_PROTO=m
-+CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m
-+CONFIG_SND_SOC_WM8804_I2C=m
-+CONFIG_SND_SIMPLE_CARD=m
-+CONFIG_SOUND_PRIME=m
-+CONFIG_HIDRAW=y
-+CONFIG_HID_A4TECH=m
-+CONFIG_HID_ACRUX=m
-+CONFIG_HID_APPLE=m
-+CONFIG_HID_BELKIN=m
-+CONFIG_HID_CHERRY=m
-+CONFIG_HID_CHICONY=m
-+CONFIG_HID_CYPRESS=m
-+CONFIG_HID_DRAGONRISE=m
-+CONFIG_HID_EMS_FF=m
-+CONFIG_HID_ELECOM=m
-+CONFIG_HID_ELO=m
-+CONFIG_HID_EZKEY=m
-+CONFIG_HID_HOLTEK=m
-+CONFIG_HID_KEYTOUCH=m
-+CONFIG_HID_KYE=m
-+CONFIG_HID_UCLOGIC=m
-+CONFIG_HID_WALTOP=m
-+CONFIG_HID_GYRATION=m
-+CONFIG_HID_TWINHAN=m
-+CONFIG_HID_KENSINGTON=m
-+CONFIG_HID_LCPOWER=m
-+CONFIG_HID_LOGITECH=m
-+CONFIG_HID_MAGICMOUSE=m
-+CONFIG_HID_MICROSOFT=m
-+CONFIG_HID_MONTEREY=m
-+CONFIG_HID_MULTITOUCH=m
-+CONFIG_HID_NTRIG=m
-+CONFIG_HID_ORTEK=m
-+CONFIG_HID_PANTHERLORD=m
-+CONFIG_HID_PETALYNX=m
-+CONFIG_HID_PICOLCD=m
-+CONFIG_HID_ROCCAT=m
-+CONFIG_HID_SAMSUNG=m
-+CONFIG_HID_SONY=m
-+CONFIG_HID_SPEEDLINK=m
-+CONFIG_HID_SUNPLUS=m
-+CONFIG_HID_GREENASIA=m
-+CONFIG_HID_SMARTJOYPLUS=m
-+CONFIG_HID_TOPSEED=m
-+CONFIG_HID_THINGM=m
-+CONFIG_HID_THRUSTMASTER=m
-+CONFIG_HID_WACOM=m
-+CONFIG_HID_WIIMOTE=m
-+CONFIG_HID_XINMO=m
-+CONFIG_HID_ZEROPLUS=m
-+CONFIG_HID_ZYDACRON=m
-+CONFIG_HID_PID=y
-+CONFIG_USB_HIDDEV=y
- CONFIG_USB=y
-+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
-+CONFIG_USB_MON=m
-+CONFIG_USB_DWCOTG=y
-+CONFIG_USB_PRINTER=m
- CONFIG_USB_STORAGE=y
-+CONFIG_USB_STORAGE_REALTEK=m
-+CONFIG_USB_STORAGE_DATAFAB=m
-+CONFIG_USB_STORAGE_FREECOM=m
-+CONFIG_USB_STORAGE_ISD200=m
-+CONFIG_USB_STORAGE_USBAT=m
-+CONFIG_USB_STORAGE_SDDR09=m
-+CONFIG_USB_STORAGE_SDDR55=m
-+CONFIG_USB_STORAGE_JUMPSHOT=m
-+CONFIG_USB_STORAGE_ALAUDA=m
-+CONFIG_USB_STORAGE_ONETOUCH=m
-+CONFIG_USB_STORAGE_KARMA=m
-+CONFIG_USB_STORAGE_CYPRESS_ATACB=m
-+CONFIG_USB_STORAGE_ENE_UB6250=m
-+CONFIG_USB_MDC800=m
-+CONFIG_USB_MICROTEK=m
-+CONFIG_USBIP_CORE=m
-+CONFIG_USBIP_VHCI_HCD=m
-+CONFIG_USBIP_HOST=m
-+CONFIG_USB_DWC2=y
-+CONFIG_USB_SERIAL=m
-+CONFIG_USB_SERIAL_GENERIC=y
-+CONFIG_USB_SERIAL_AIRCABLE=m
-+CONFIG_USB_SERIAL_ARK3116=m
-+CONFIG_USB_SERIAL_BELKIN=m
-+CONFIG_USB_SERIAL_CH341=m
-+CONFIG_USB_SERIAL_WHITEHEAT=m
-+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
-+CONFIG_USB_SERIAL_CP210X=m
-+CONFIG_USB_SERIAL_CYPRESS_M8=m
-+CONFIG_USB_SERIAL_EMPEG=m
-+CONFIG_USB_SERIAL_FTDI_SIO=m
-+CONFIG_USB_SERIAL_VISOR=m
-+CONFIG_USB_SERIAL_IPAQ=m
-+CONFIG_USB_SERIAL_IR=m
-+CONFIG_USB_SERIAL_EDGEPORT=m
-+CONFIG_USB_SERIAL_EDGEPORT_TI=m
-+CONFIG_USB_SERIAL_F81232=m
-+CONFIG_USB_SERIAL_GARMIN=m
-+CONFIG_USB_SERIAL_IPW=m
-+CONFIG_USB_SERIAL_IUU=m
-+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
-+CONFIG_USB_SERIAL_KEYSPAN=m
-+CONFIG_USB_SERIAL_KLSI=m
-+CONFIG_USB_SERIAL_KOBIL_SCT=m
-+CONFIG_USB_SERIAL_MCT_U232=m
-+CONFIG_USB_SERIAL_METRO=m
-+CONFIG_USB_SERIAL_MOS7720=m
-+CONFIG_USB_SERIAL_MOS7840=m
-+CONFIG_USB_SERIAL_NAVMAN=m
-+CONFIG_USB_SERIAL_PL2303=m
-+CONFIG_USB_SERIAL_OTI6858=m
-+CONFIG_USB_SERIAL_QCAUX=m
-+CONFIG_USB_SERIAL_QUALCOMM=m
-+CONFIG_USB_SERIAL_SPCP8X5=m
-+CONFIG_USB_SERIAL_SAFE=m
-+CONFIG_USB_SERIAL_SIERRAWIRELESS=m
-+CONFIG_USB_SERIAL_SYMBOL=m
-+CONFIG_USB_SERIAL_TI=m
-+CONFIG_USB_SERIAL_CYBERJACK=m
-+CONFIG_USB_SERIAL_XIRCOM=m
-+CONFIG_USB_SERIAL_OPTION=m
-+CONFIG_USB_SERIAL_OMNINET=m
-+CONFIG_USB_SERIAL_OPTICON=m
-+CONFIG_USB_SERIAL_XSENS_MT=m
-+CONFIG_USB_SERIAL_WISHBONE=m
-+CONFIG_USB_SERIAL_SSU100=m
-+CONFIG_USB_SERIAL_QT2=m
-+CONFIG_USB_SERIAL_DEBUG=m
-+CONFIG_USB_EMI62=m
-+CONFIG_USB_EMI26=m
-+CONFIG_USB_ADUTUX=m
-+CONFIG_USB_SEVSEG=m
-+CONFIG_USB_RIO500=m
-+CONFIG_USB_LEGOTOWER=m
-+CONFIG_USB_LCD=m
-+CONFIG_USB_LED=m
-+CONFIG_USB_CYPRESS_CY7C63=m
-+CONFIG_USB_CYTHERM=m
-+CONFIG_USB_IDMOUSE=m
-+CONFIG_USB_FTDI_ELAN=m
-+CONFIG_USB_APPLEDISPLAY=m
-+CONFIG_USB_LD=m
-+CONFIG_USB_TRANCEVIBRATOR=m
-+CONFIG_USB_IOWARRIOR=m
-+CONFIG_USB_TEST=m
-+CONFIG_USB_ISIGHTFW=m
-+CONFIG_USB_YUREX=m
-+CONFIG_USB_ATM=m
-+CONFIG_USB_SPEEDTOUCH=m
-+CONFIG_USB_CXACRU=m
-+CONFIG_USB_UEAGLEATM=m
-+CONFIG_USB_XUSBATM=m
- CONFIG_MMC=y
-+CONFIG_MMC_BLOCK_MINORS=32
-+CONFIG_MMC_BCM2835=y
-+CONFIG_MMC_BCM2835_DMA=y
-+CONFIG_MMC_BCM2835_SDHOST=y
- CONFIG_MMC_SDHCI=y
- CONFIG_MMC_SDHCI_PLTFM=y
- CONFIG_MMC_SDHCI_BCM2835=y
-+CONFIG_MMC_SPI=m
-+CONFIG_LEDS_CLASS=y
- CONFIG_LEDS_GPIO=y
- CONFIG_LEDS_TRIGGER_TIMER=y
- CONFIG_LEDS_TRIGGER_ONESHOT=y
- CONFIG_LEDS_TRIGGER_HEARTBEAT=y
-+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
- CONFIG_LEDS_TRIGGER_CPU=y
- CONFIG_LEDS_TRIGGER_GPIO=y
- CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
--CONFIG_LEDS_TRIGGER_TRANSIENT=y
--CONFIG_LEDS_TRIGGER_CAMERA=y
-+CONFIG_LEDS_TRIGGER_TRANSIENT=m
-+CONFIG_LEDS_TRIGGER_CAMERA=m
-+CONFIG_LEDS_TRIGGER_INPUT=y
-+CONFIG_RTC_CLASS=y
-+# CONFIG_RTC_HCTOSYS is not set
-+CONFIG_RTC_DRV_DS1307=m
-+CONFIG_RTC_DRV_DS1374=m
-+CONFIG_RTC_DRV_DS1672=m
-+CONFIG_RTC_DRV_DS3232=m
-+CONFIG_RTC_DRV_MAX6900=m
-+CONFIG_RTC_DRV_RS5C372=m
-+CONFIG_RTC_DRV_ISL1208=m
-+CONFIG_RTC_DRV_ISL12022=m
-+CONFIG_RTC_DRV_ISL12057=m
-+CONFIG_RTC_DRV_X1205=m
-+CONFIG_RTC_DRV_PCF2127=m
-+CONFIG_RTC_DRV_PCF8523=m
-+CONFIG_RTC_DRV_PCF8563=m
-+CONFIG_RTC_DRV_PCF8583=m
-+CONFIG_RTC_DRV_M41T80=m
-+CONFIG_RTC_DRV_BQ32K=m
-+CONFIG_RTC_DRV_S35390A=m
-+CONFIG_RTC_DRV_FM3130=m
-+CONFIG_RTC_DRV_RX8581=m
-+CONFIG_RTC_DRV_RX8025=m
-+CONFIG_RTC_DRV_EM3027=m
-+CONFIG_RTC_DRV_RV3029C2=m
-+CONFIG_RTC_DRV_M41T93=m
-+CONFIG_RTC_DRV_M41T94=m
-+CONFIG_RTC_DRV_DS1305=m
-+CONFIG_RTC_DRV_DS1390=m
-+CONFIG_RTC_DRV_MAX6902=m
-+CONFIG_RTC_DRV_R9701=m
-+CONFIG_RTC_DRV_RS5C348=m
-+CONFIG_RTC_DRV_DS3234=m
-+CONFIG_RTC_DRV_PCF2123=m
-+CONFIG_RTC_DRV_RX4581=m
-+CONFIG_DMADEVICES=y
-+CONFIG_DMA_BCM2835=y
-+CONFIG_DMA_BCM2708=y
-+CONFIG_UIO=m
-+CONFIG_UIO_PDRV_GENIRQ=m
- CONFIG_STAGING=y
--CONFIG_USB_DWC2=y
--CONFIG_USB_DWC2_HOST=y
-+CONFIG_PRISM2_USB=m
-+CONFIG_R8712U=m
-+CONFIG_R8188EU=m
-+CONFIG_R8723AU=m
-+CONFIG_VT6656=m
-+CONFIG_SPEAKUP=m
-+CONFIG_SPEAKUP_SYNTH_SOFT=m
-+CONFIG_STAGING_MEDIA=y
-+CONFIG_LIRC_STAGING=y
-+CONFIG_LIRC_IMON=m
-+CONFIG_LIRC_RPI=m
-+CONFIG_LIRC_SASEM=m
-+CONFIG_LIRC_SERIAL=m
-+CONFIG_FB_TFT=m
-+CONFIG_FB_TFT_AGM1264K_FL=m
-+CONFIG_FB_TFT_BD663474=m
-+CONFIG_FB_TFT_HX8340BN=m
-+CONFIG_FB_TFT_HX8347D=m
-+CONFIG_FB_TFT_HX8353D=m
-+CONFIG_FB_TFT_ILI9320=m
-+CONFIG_FB_TFT_ILI9325=m
-+CONFIG_FB_TFT_ILI9340=m
-+CONFIG_FB_TFT_ILI9341=m
-+CONFIG_FB_TFT_ILI9481=m
-+CONFIG_FB_TFT_ILI9486=m
-+CONFIG_FB_TFT_PCD8544=m
-+CONFIG_FB_TFT_RA8875=m
-+CONFIG_FB_TFT_S6D02A1=m
-+CONFIG_FB_TFT_S6D1121=m
-+CONFIG_FB_TFT_SSD1289=m
-+CONFIG_FB_TFT_SSD1306=m
-+CONFIG_FB_TFT_SSD1331=m
-+CONFIG_FB_TFT_SSD1351=m
-+CONFIG_FB_TFT_ST7735R=m
-+CONFIG_FB_TFT_TINYLCD=m
-+CONFIG_FB_TFT_TLS8204=m
-+CONFIG_FB_TFT_UC1701=m
-+CONFIG_FB_TFT_UPD161704=m
-+CONFIG_FB_TFT_WATTEROTT=m
-+CONFIG_FB_FLEX=m
-+CONFIG_FB_TFT_FBTFT_DEVICE=m
-+CONFIG_MAILBOX=y
-+CONFIG_BCM2835_MBOX=y
- # CONFIG_IOMMU_SUPPORT is not set
-+CONFIG_EXTCON=m
-+CONFIG_EXTCON_ARIZONA=m
-+CONFIG_IIO=m
-+CONFIG_IIO_BUFFER=y
-+CONFIG_IIO_BUFFER_CB=y
-+CONFIG_IIO_KFIFO_BUF=m
-+CONFIG_DHT11=m
-+CONFIG_RASPBERRYPI_FIRMWARE=y
- CONFIG_EXT2_FS=y
- CONFIG_EXT2_FS_XATTR=y
- CONFIG_EXT2_FS_POSIX_ACL=y
-@@ -107,18 +1105,110 @@ CONFIG_EXT3_FS=y
- CONFIG_EXT3_FS_POSIX_ACL=y
- CONFIG_EXT4_FS=y
- CONFIG_EXT4_FS_POSIX_ACL=y
-+CONFIG_EXT4_FS_SECURITY=y
-+CONFIG_REISERFS_FS=m
-+CONFIG_REISERFS_FS_XATTR=y
-+CONFIG_REISERFS_FS_POSIX_ACL=y
-+CONFIG_REISERFS_FS_SECURITY=y
-+CONFIG_JFS_FS=m
-+CONFIG_JFS_POSIX_ACL=y
-+CONFIG_JFS_SECURITY=y
-+CONFIG_JFS_STATISTICS=y
-+CONFIG_XFS_FS=m
-+CONFIG_XFS_QUOTA=y
-+CONFIG_XFS_POSIX_ACL=y
-+CONFIG_XFS_RT=y
-+CONFIG_GFS2_FS=m
-+CONFIG_OCFS2_FS=m
-+CONFIG_BTRFS_FS=m
-+CONFIG_BTRFS_FS_POSIX_ACL=y
-+CONFIG_NILFS2_FS=m
-+CONFIG_F2FS_FS=y
- CONFIG_FANOTIFY=y
-+CONFIG_QFMT_V1=m
-+CONFIG_QFMT_V2=m
-+CONFIG_AUTOFS4_FS=y
-+CONFIG_FUSE_FS=m
-+CONFIG_CUSE=m
-+CONFIG_FSCACHE=y
-+CONFIG_FSCACHE_STATS=y
-+CONFIG_FSCACHE_HISTOGRAM=y
-+CONFIG_CACHEFILES=y
-+CONFIG_ISO9660_FS=m
-+CONFIG_JOLIET=y
-+CONFIG_ZISOFS=y
-+CONFIG_UDF_FS=m
- CONFIG_MSDOS_FS=y
- CONFIG_VFAT_FS=y
-+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
-+CONFIG_NTFS_FS=m
-+CONFIG_NTFS_RW=y
- CONFIG_TMPFS=y
- CONFIG_TMPFS_POSIX_ACL=y
--# CONFIG_MISC_FILESYSTEMS is not set
-+CONFIG_CONFIGFS_FS=y
-+CONFIG_ECRYPT_FS=m
-+CONFIG_HFS_FS=m
-+CONFIG_HFSPLUS_FS=m
-+CONFIG_SQUASHFS=m
-+CONFIG_SQUASHFS_XATTR=y
-+CONFIG_SQUASHFS_LZO=y
-+CONFIG_SQUASHFS_XZ=y
- CONFIG_NFS_FS=y
--CONFIG_NFSD=y
-+CONFIG_NFS_V3_ACL=y
-+CONFIG_NFS_V4=y
-+CONFIG_NFS_SWAP=y
-+CONFIG_ROOT_NFS=y
-+CONFIG_NFS_FSCACHE=y
-+CONFIG_NFSD=m
-+CONFIG_NFSD_V3_ACL=y
-+CONFIG_NFSD_V4=y
-+CONFIG_CIFS=m
-+CONFIG_CIFS_WEAK_PW_HASH=y
-+CONFIG_CIFS_UPCALL=y
-+CONFIG_CIFS_XATTR=y
-+CONFIG_CIFS_POSIX=y
-+CONFIG_9P_FS=m
-+CONFIG_9P_FS_POSIX_ACL=y
-+CONFIG_NLS_DEFAULT="utf8"
- CONFIG_NLS_CODEPAGE_437=y
-+CONFIG_NLS_CODEPAGE_737=m
-+CONFIG_NLS_CODEPAGE_775=m
-+CONFIG_NLS_CODEPAGE_850=m
-+CONFIG_NLS_CODEPAGE_852=m
-+CONFIG_NLS_CODEPAGE_855=m
-+CONFIG_NLS_CODEPAGE_857=m
-+CONFIG_NLS_CODEPAGE_860=m
-+CONFIG_NLS_CODEPAGE_861=m
-+CONFIG_NLS_CODEPAGE_862=m
-+CONFIG_NLS_CODEPAGE_863=m
-+CONFIG_NLS_CODEPAGE_864=m
-+CONFIG_NLS_CODEPAGE_865=m
-+CONFIG_NLS_CODEPAGE_866=m
-+CONFIG_NLS_CODEPAGE_869=m
-+CONFIG_NLS_CODEPAGE_936=m
-+CONFIG_NLS_CODEPAGE_950=m
-+CONFIG_NLS_CODEPAGE_932=m
-+CONFIG_NLS_CODEPAGE_949=m
-+CONFIG_NLS_CODEPAGE_874=m
-+CONFIG_NLS_ISO8859_8=m
-+CONFIG_NLS_CODEPAGE_1250=m
-+CONFIG_NLS_CODEPAGE_1251=m
- CONFIG_NLS_ASCII=y
--CONFIG_NLS_ISO8859_1=y
-+CONFIG_NLS_ISO8859_1=m
-+CONFIG_NLS_ISO8859_2=m
-+CONFIG_NLS_ISO8859_3=m
-+CONFIG_NLS_ISO8859_4=m
-+CONFIG_NLS_ISO8859_5=m
-+CONFIG_NLS_ISO8859_6=m
-+CONFIG_NLS_ISO8859_7=m
-+CONFIG_NLS_ISO8859_9=m
-+CONFIG_NLS_ISO8859_13=m
-+CONFIG_NLS_ISO8859_14=m
-+CONFIG_NLS_ISO8859_15=m
-+CONFIG_NLS_KOI8_R=m
-+CONFIG_NLS_KOI8_U=m
- CONFIG_NLS_UTF8=y
-+CONFIG_DLM=m
- CONFIG_PRINTK_TIME=y
- CONFIG_BOOT_PRINTK_DELAY=y
- CONFIG_DYNAMIC_DEBUG=y
-@@ -128,14 +1218,38 @@ CONFIG_DEBUG_INFO=y
- CONFIG_UNUSED_SYMBOLS=y
- CONFIG_DEBUG_MEMORY_INIT=y
- CONFIG_LOCKUP_DETECTOR=y
-+CONFIG_TIMER_STATS=y
-+# CONFIG_DEBUG_PREEMPT is not set
-+CONFIG_LATENCYTOP=y
-+CONFIG_IRQSOFF_TRACER=y
- CONFIG_SCHED_TRACER=y
- CONFIG_STACK_TRACER=y
-+CONFIG_BLK_DEV_IO_TRACE=y
-+# CONFIG_KPROBE_EVENT is not set
- CONFIG_FUNCTION_PROFILER=y
- CONFIG_TEST_KSTRTOX=y
- CONFIG_KGDB=y
- CONFIG_KGDB_KDB=y
-+CONFIG_KDB_KEYBOARD=y
- CONFIG_STRICT_DEVMEM=y
- CONFIG_DEBUG_LL=y
- CONFIG_EARLY_PRINTK=y
-+CONFIG_CRYPTO_USER=m
-+CONFIG_CRYPTO_CRYPTD=m
-+CONFIG_CRYPTO_CBC=y
-+CONFIG_CRYPTO_CTS=m
-+CONFIG_CRYPTO_XTS=m
-+CONFIG_CRYPTO_XCBC=m
-+CONFIG_CRYPTO_SHA512=m
-+CONFIG_CRYPTO_TGR192=m
-+CONFIG_CRYPTO_WP512=m
-+CONFIG_CRYPTO_CAST5=m
-+CONFIG_CRYPTO_DES=y
-+# CONFIG_CRYPTO_HW is not set
-+CONFIG_ARM_CRYPTO=y
-+CONFIG_CRYPTO_SHA1_ARM=m
-+CONFIG_CRYPTO_AES_ARM=m
-+CONFIG_CRC_ITU_T=y
-+CONFIG_LIBCRC32C=y
- # CONFIG_XZ_DEC_ARM is not set
- # CONFIG_XZ_DEC_ARMTHUMB is not set
diff --git a/target/linux/brcm2708/patches-4.4/0078-rpi-ft5406-Add-touchscreen-driver-for-pi-LCD-display.patch b/target/linux/brcm2708/patches-4.4/0078-rpi-ft5406-Add-touchscreen-driver-for-pi-LCD-display.patch
new file mode 100644
index 0000000000..a43819a9f7
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0078-rpi-ft5406-Add-touchscreen-driver-for-pi-LCD-display.patch
@@ -0,0 +1,290 @@
+From c756311eb3ca94befe2d0b960232bebb03614a11 Mon Sep 17 00:00:00 2001
+From: Gordon Hollingworth <gordon@raspberrypi.org>
+Date: Tue, 12 May 2015 14:47:56 +0100
+Subject: [PATCH 078/381] rpi-ft5406: Add touchscreen driver for pi LCD display
+
+Fix driver detection failure Check that the buffer response is non-zero meaning the touchscreen was detected
+
+rpi-ft5406: Use firmware API
+---
+ drivers/input/touchscreen/Kconfig | 7 +
+ drivers/input/touchscreen/Makefile | 1 +
+ drivers/input/touchscreen/rpi-ft5406.c | 246 +++++++++++++++++++++++++++++++++
+ 3 files changed, 254 insertions(+)
+ create mode 100644 drivers/input/touchscreen/rpi-ft5406.c
+
+--- a/drivers/input/touchscreen/Kconfig
++++ b/drivers/input/touchscreen/Kconfig
+@@ -608,6 +608,13 @@ config TOUCHSCREEN_EDT_FT5X06
+ To compile this driver as a module, choose M here: the
+ module will be called edt-ft5x06.
+
++config TOUCHSCREEN_RPI_FT5406
++ tristate "Raspberry Pi FT5406 driver"
++ depends on RASPBERRYPI_FIRMWARE
++ help
++ Say Y here to enable the Raspberry Pi memory based FT5406 device
++
++
+ config TOUCHSCREEN_MIGOR
+ tristate "Renesas MIGO-R touchscreen"
+ depends on SH_MIGOR && I2C
+--- a/drivers/input/touchscreen/Makefile
++++ b/drivers/input/touchscreen/Makefile
+@@ -29,6 +29,7 @@ obj-$(CONFIG_TOUCHSCREEN_DA9034) += da90
+ obj-$(CONFIG_TOUCHSCREEN_DA9052) += da9052_tsi.o
+ obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o
+ obj-$(CONFIG_TOUCHSCREEN_EDT_FT5X06) += edt-ft5x06.o
++obj-$(CONFIG_TOUCHSCREEN_RPI_FT5406) += rpi-ft5406.o
+ obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o
+ obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
+ obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o
+--- /dev/null
++++ b/drivers/input/touchscreen/rpi-ft5406.c
+@@ -0,0 +1,246 @@
++/*
++ * Driver for memory based ft5406 touchscreen
++ *
++ * Copyright (C) 2015 Raspberry Pi
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/input.h>
++#include <linux/irq.h>
++#include <linux/delay.h>
++#include <linux/slab.h>
++#include <linux/bitops.h>
++#include <linux/input/mt.h>
++#include <linux/kthread.h>
++#include <linux/platform_device.h>
++#include <asm/io.h>
++#include <soc/bcm2835/raspberrypi-firmware.h>
++
++#define MAXIMUM_SUPPORTED_POINTS 10
++struct ft5406_regs {
++ uint8_t device_mode;
++ uint8_t gesture_id;
++ uint8_t num_points;
++ struct ft5406_touch {
++ uint8_t xh;
++ uint8_t xl;
++ uint8_t yh;
++ uint8_t yl;
++ uint8_t res1;
++ uint8_t res2;
++ } point[MAXIMUM_SUPPORTED_POINTS];
++};
++
++#define SCREEN_WIDTH 800
++#define SCREEN_HEIGHT 480
++
++struct ft5406 {
++ struct platform_device * pdev;
++ struct input_dev * input_dev;
++ void __iomem * ts_base;
++ struct ft5406_regs * regs;
++ struct task_struct * thread;
++};
++
++/* Thread to poll for touchscreen events
++ *
++ * This thread polls the memory based register copy of the ft5406 registers
++ * using the number of points register to know whether the copy has been
++ * updated (we write 99 to the memory copy, the GPU will write between
++ * 0 - 10 points)
++ */
++static int ft5406_thread(void *arg)
++{
++ struct ft5406 *ts = (struct ft5406 *) arg;
++ struct ft5406_regs regs;
++ int known_ids = 0;
++
++ while(!kthread_should_stop())
++ {
++ // 60fps polling
++ msleep_interruptible(17);
++ memcpy_fromio(&regs, ts->regs, sizeof(*ts->regs));
++ writel(99, &ts->regs->num_points);
++ // Do not output if theres no new information (num_points is 99)
++ // or we have no touch points and don't need to release any
++ if(!(regs.num_points == 99 || (regs.num_points == 0 && known_ids == 0)))
++ {
++ int i;
++ int modified_ids = 0, released_ids;
++ for(i = 0; i < regs.num_points; i++)
++ {
++ int x = (((int) regs.point[i].xh & 0xf) << 8) + regs.point[i].xl;
++ int y = (((int) regs.point[i].yh & 0xf) << 8) + regs.point[i].yl;
++ int touchid = (regs.point[i].yh >> 4) & 0xf;
++
++ modified_ids |= 1 << touchid;
++
++ if(!((1 << touchid) & known_ids))
++ dev_dbg(&ts->pdev->dev, "x = %d, y = %d, touchid = %d\n", x, y, touchid);
++
++ input_mt_slot(ts->input_dev, touchid);
++ input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 1);
++
++ input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x);
++ input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y);
++
++ }
++
++ released_ids = known_ids & ~modified_ids;
++ for(i = 0; released_ids && i < MAXIMUM_SUPPORTED_POINTS; i++)
++ {
++ if(released_ids & (1<<i))
++ {
++ dev_dbg(&ts->pdev->dev, "Released %d, known = %x modified = %x\n", i, known_ids, modified_ids);
++ input_mt_slot(ts->input_dev, i);
++ input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0);
++ modified_ids &= ~(1 << i);
++ }
++ }
++ known_ids = modified_ids;
++
++ input_mt_report_pointer_emulation(ts->input_dev, true);
++ input_sync(ts->input_dev);
++ }
++
++ }
++
++ return 0;
++}
++
++static int ft5406_probe(struct platform_device *pdev)
++{
++ int ret;
++ struct input_dev * input_dev = input_allocate_device();
++ struct ft5406 * ts;
++ struct device_node *fw_node;
++ struct rpi_firmware *fw;
++ u32 touchbuf;
++
++ dev_info(&pdev->dev, "Probing device\n");
++
++ fw_node = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
++ if (!fw_node) {
++ dev_err(&pdev->dev, "Missing firmware node\n");
++ return -ENOENT;
++ }
++
++ fw = rpi_firmware_get(fw_node);
++ if (!fw)
++ return -EPROBE_DEFER;
++
++ ret = rpi_firmware_property(fw, RPI_FIRMWARE_FRAMEBUFFER_GET_TOUCHBUF,
++ &touchbuf, sizeof(touchbuf));
++ if (ret) {
++ dev_err(&pdev->dev, "Failed to get touch buffer\n");
++ return ret;
++ }
++
++ if (!touchbuf) {
++ dev_err(&pdev->dev, "Touchscreen not detected\n");
++ return -ENODEV;
++ }
++
++ dev_dbg(&pdev->dev, "Got TS buffer 0x%x\n", touchbuf);
++
++ ts = kzalloc(sizeof(struct ft5406), GFP_KERNEL);
++
++ if (!ts || !input_dev) {
++ ret = -ENOMEM;
++ dev_err(&pdev->dev, "Failed to allocate memory\n");
++ return ret;
++ }
++ ts->input_dev = input_dev;
++ platform_set_drvdata(pdev, ts);
++ ts->pdev = pdev;
++
++ input_dev->name = "FT5406 memory based driver";
++
++ __set_bit(EV_KEY, input_dev->evbit);
++ __set_bit(EV_SYN, input_dev->evbit);
++ __set_bit(EV_ABS, input_dev->evbit);
++
++ input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0,
++ SCREEN_WIDTH, 0, 0);
++ input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,
++ SCREEN_HEIGHT, 0, 0);
++
++ input_mt_init_slots(input_dev, MAXIMUM_SUPPORTED_POINTS, INPUT_MT_DIRECT);
++
++ input_set_drvdata(input_dev, ts);
++
++ ret = input_register_device(input_dev);
++ if (ret) {
++ dev_err(&pdev->dev, "could not register input device, %d\n",
++ ret);
++ return ret;
++ }
++
++ // mmap the physical memory
++ touchbuf &= ~0xc0000000;
++ ts->ts_base = ioremap(touchbuf, sizeof(*ts->regs));
++ if(ts->ts_base == NULL)
++ {
++ dev_err(&pdev->dev, "Failed to map physical address\n");
++ input_unregister_device(input_dev);
++ kzfree(ts);
++ return -ENOMEM;
++ }
++
++ ts->regs = (struct ft5406_regs *) ts->ts_base;
++
++ // create thread to poll the touch events
++ ts->thread = kthread_run(ft5406_thread, ts, "ft5406");
++ if(ts->thread == NULL)
++ {
++ dev_err(&pdev->dev, "Failed to create kernel thread");
++ iounmap(ts->ts_base);
++ input_unregister_device(input_dev);
++ kzfree(ts);
++ }
++
++ return 0;
++}
++
++static int ft5406_remove(struct platform_device *pdev)
++{
++ struct ft5406 *ts = (struct ft5406 *) platform_get_drvdata(pdev);
++
++ dev_info(&pdev->dev, "Removing rpi-ft5406\n");
++
++ kthread_stop(ts->thread);
++ iounmap(ts->ts_base);
++ input_unregister_device(ts->input_dev);
++ kzfree(ts);
++
++ return 0;
++}
++
++static const struct of_device_id ft5406_match[] = {
++ { .compatible = "rpi,rpi-ft5406", },
++ {},
++};
++MODULE_DEVICE_TABLE(of, ft5406_match);
++
++static struct platform_driver ft5406_driver = {
++ .driver = {
++ .name = "rpi-ft5406",
++ .owner = THIS_MODULE,
++ .of_match_table = ft5406_match,
++ },
++ .probe = ft5406_probe,
++ .remove = ft5406_remove,
++};
++
++module_platform_driver(ft5406_driver);
++
++MODULE_AUTHOR("Gordon Hollingworth");
++MODULE_DESCRIPTION("Touchscreen driver for memory based FT5406");
++MODULE_LICENSE("GPL");
diff --git a/target/linux/brcm2708/patches-4.4/0079-Improve-__copy_to_user-and-__copy_from_user-performa.patch b/target/linux/brcm2708/patches-4.4/0079-Improve-__copy_to_user-and-__copy_from_user-performa.patch
new file mode 100644
index 0000000000..87f5c5eeed
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0079-Improve-__copy_to_user-and-__copy_from_user-performa.patch
@@ -0,0 +1,1510 @@
+From c8fda14cc4b13b9a3612ecc5c3c7456a57e2029b Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 13 Oct 2014 11:47:53 +0100
+Subject: [PATCH 079/381] Improve __copy_to_user and __copy_from_user
+ performance
+
+Provide a __copy_from_user that uses memcpy. On BCM2708, use
+optimised memcpy/memmove/memcmp/memset implementations.
+
+arch/arm: Add mmiocpy/set aliases for memcpy/set
+
+See: https://github.com/raspberrypi/linux/issues/1082
+---
+ arch/arm/include/asm/string.h | 5 +
+ arch/arm/include/asm/uaccess.h | 3 +
+ arch/arm/lib/Makefile | 15 +-
+ arch/arm/lib/arm-mem.h | 159 ++++++++++++
+ arch/arm/lib/copy_from_user.S | 4 +-
+ arch/arm/lib/exports_rpi.c | 37 +++
+ arch/arm/lib/memcmp_rpi.S | 285 +++++++++++++++++++++
+ arch/arm/lib/memcpy_rpi.S | 61 +++++
+ arch/arm/lib/memcpymove.h | 506 +++++++++++++++++++++++++++++++++++++
+ arch/arm/lib/memmove_rpi.S | 61 +++++
+ arch/arm/lib/memset_rpi.S | 123 +++++++++
+ arch/arm/lib/uaccess_with_memcpy.c | 112 +++++++-
+ 12 files changed, 1365 insertions(+), 6 deletions(-)
+ create mode 100644 arch/arm/lib/arm-mem.h
+ create mode 100644 arch/arm/lib/exports_rpi.c
+ create mode 100644 arch/arm/lib/memcmp_rpi.S
+ create mode 100644 arch/arm/lib/memcpy_rpi.S
+ create mode 100644 arch/arm/lib/memcpymove.h
+ create mode 100644 arch/arm/lib/memmove_rpi.S
+ create mode 100644 arch/arm/lib/memset_rpi.S
+
+--- a/arch/arm/include/asm/string.h
++++ b/arch/arm/include/asm/string.h
+@@ -24,6 +24,11 @@ extern void * memchr(const void *, int,
+ #define __HAVE_ARCH_MEMSET
+ extern void * memset(void *, int, __kernel_size_t);
+
++#ifdef CONFIG_MACH_BCM2708
++#define __HAVE_ARCH_MEMCMP
++extern int memcmp(const void *, const void *, size_t);
++#endif
++
+ extern void __memzero(void *ptr, __kernel_size_t n);
+
+ #define memset(p,v,n) \
+--- a/arch/arm/include/asm/uaccess.h
++++ b/arch/arm/include/asm/uaccess.h
+@@ -493,6 +493,9 @@ do { \
+ extern unsigned long __must_check
+ arm_copy_from_user(void *to, const void __user *from, unsigned long n);
+
++extern unsigned long __must_check
++__copy_from_user_std(void *to, const void __user *from, unsigned long n);
++
+ static inline unsigned long __must_check
+ __copy_from_user(void *to, const void __user *from, unsigned long n)
+ {
+--- a/arch/arm/lib/Makefile
++++ b/arch/arm/lib/Makefile
+@@ -6,9 +6,8 @@
+
+ lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \
+ csumpartialcopy.o csumpartialcopyuser.o clearbit.o \
+- delay.o delay-loop.o findbit.o memchr.o memcpy.o \
+- memmove.o memset.o memzero.o setbit.o \
+- strchr.o strrchr.o \
++ delay.o delay-loop.o findbit.o memchr.o memzero.o \
++ setbit.o strchr.o strrchr.o \
+ testchangebit.o testclearbit.o testsetbit.o \
+ ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \
+ ucmpdi2.o lib1funcs.o div64.o \
+@@ -18,6 +17,16 @@ lib-y := backtrace.o changebit.o csumip
+ mmu-y := clear_user.o copy_page.o getuser.o putuser.o \
+ copy_from_user.o copy_to_user.o
+
++# Choose optimised implementations for Raspberry Pi
++ifeq ($(CONFIG_MACH_BCM2708),y)
++ CFLAGS_uaccess_with_memcpy.o += -DCOPY_FROM_USER_THRESHOLD=1600
++ CFLAGS_uaccess_with_memcpy.o += -DCOPY_TO_USER_THRESHOLD=672
++ obj-$(CONFIG_MODULES) += exports_rpi.o
++ lib-y += memcpy_rpi.o memmove_rpi.o memset_rpi.o memcmp_rpi.o
++else
++ lib-y += memcpy.o memmove.o memset.o
++endif
++
+ # using lib_ here won't override already available weak symbols
+ obj-$(CONFIG_UACCESS_WITH_MEMCPY) += uaccess_with_memcpy.o
+
+--- /dev/null
++++ b/arch/arm/lib/arm-mem.h
+@@ -0,0 +1,159 @@
++/*
++Copyright (c) 2013, Raspberry Pi Foundation
++Copyright (c) 2013, RISC OS Open Ltd
++All rights reserved.
++
++Redistribution and use in source and binary forms, with or without
++modification, are permitted provided that the following conditions are met:
++ * Redistributions of source code must retain the above copyright
++ notice, this list of conditions and the following disclaimer.
++ * Redistributions in binary form must reproduce the above copyright
++ notice, this list of conditions and the following disclaimer in the
++ documentation and/or other materials provided with the distribution.
++ * Neither the name of the copyright holder nor the
++ names of its contributors may be used to endorse or promote products
++ derived from this software without specific prior written permission.
++
++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
++*/
++
++.macro myfunc fname
++ .func fname
++ .global fname
++fname:
++.endm
++
++.macro preload_leading_step1 backwards, ptr, base
++/* If the destination is already 16-byte aligned, then we need to preload
++ * between 0 and prefetch_distance (inclusive) cache lines ahead so there
++ * are no gaps when the inner loop starts.
++ */
++ .if backwards
++ sub ptr, base, #1
++ bic ptr, ptr, #31
++ .else
++ bic ptr, base, #31
++ .endif
++ .set OFFSET, 0
++ .rept prefetch_distance+1
++ pld [ptr, #OFFSET]
++ .if backwards
++ .set OFFSET, OFFSET-32
++ .else
++ .set OFFSET, OFFSET+32
++ .endif
++ .endr
++.endm
++
++.macro preload_leading_step2 backwards, ptr, base, leading_bytes, tmp
++/* However, if the destination is not 16-byte aligned, we may need to
++ * preload one more cache line than that. The question we need to ask is:
++ * are the leading bytes more than the amount by which the source
++ * pointer will be rounded down for preloading, and if so, by how many
++ * cache lines?
++ */
++ .if backwards
++/* Here we compare against how many bytes we are into the
++ * cache line, counting down from the highest such address.
++ * Effectively, we want to calculate
++ * leading_bytes = dst&15
++ * cacheline_offset = 31-((src-leading_bytes-1)&31)
++ * extra_needed = leading_bytes - cacheline_offset
++ * and test if extra_needed is <= 0, or rearranging:
++ * leading_bytes + (src-leading_bytes-1)&31 <= 31
++ */
++ mov tmp, base, lsl #32-5
++ sbc tmp, tmp, leading_bytes, lsl #32-5
++ adds tmp, tmp, leading_bytes, lsl #32-5
++ bcc 61f
++ pld [ptr, #-32*(prefetch_distance+1)]
++ .else
++/* Effectively, we want to calculate
++ * leading_bytes = (-dst)&15
++ * cacheline_offset = (src+leading_bytes)&31
++ * extra_needed = leading_bytes - cacheline_offset
++ * and test if extra_needed is <= 0.
++ */
++ mov tmp, base, lsl #32-5
++ add tmp, tmp, leading_bytes, lsl #32-5
++ rsbs tmp, tmp, leading_bytes, lsl #32-5
++ bls 61f
++ pld [ptr, #32*(prefetch_distance+1)]
++ .endif
++61:
++.endm
++
++.macro preload_trailing backwards, base, remain, tmp
++ /* We need either 0, 1 or 2 extra preloads */
++ .if backwards
++ rsb tmp, base, #0
++ mov tmp, tmp, lsl #32-5
++ .else
++ mov tmp, base, lsl #32-5
++ .endif
++ adds tmp, tmp, remain, lsl #32-5
++ adceqs tmp, tmp, #0
++ /* The instruction above has two effects: ensures Z is only
++ * set if C was clear (so Z indicates that both shifted quantities
++ * were 0), and clears C if Z was set (so C indicates that the sum
++ * of the shifted quantities was greater and not equal to 32) */
++ beq 82f
++ .if backwards
++ sub tmp, base, #1
++ bic tmp, tmp, #31
++ .else
++ bic tmp, base, #31
++ .endif
++ bcc 81f
++ .if backwards
++ pld [tmp, #-32*(prefetch_distance+1)]
++81:
++ pld [tmp, #-32*prefetch_distance]
++ .else
++ pld [tmp, #32*(prefetch_distance+2)]
++81:
++ pld [tmp, #32*(prefetch_distance+1)]
++ .endif
++82:
++.endm
++
++.macro preload_all backwards, narrow_case, shift, base, remain, tmp0, tmp1
++ .if backwards
++ sub tmp0, base, #1
++ bic tmp0, tmp0, #31
++ pld [tmp0]
++ sub tmp1, base, remain, lsl #shift
++ .else
++ bic tmp0, base, #31
++ pld [tmp0]
++ add tmp1, base, remain, lsl #shift
++ sub tmp1, tmp1, #1
++ .endif
++ bic tmp1, tmp1, #31
++ cmp tmp1, tmp0
++ beq 92f
++ .if narrow_case
++ /* In this case, all the data fits in either 1 or 2 cache lines */
++ pld [tmp1]
++ .else
++91:
++ .if backwards
++ sub tmp0, tmp0, #32
++ .else
++ add tmp0, tmp0, #32
++ .endif
++ cmp tmp0, tmp1
++ pld [tmp0]
++ bne 91b
++ .endif
++92:
++.endm
+--- a/arch/arm/lib/copy_from_user.S
++++ b/arch/arm/lib/copy_from_user.S
+@@ -89,11 +89,13 @@
+
+ .text
+
+-ENTRY(arm_copy_from_user)
++ENTRY(__copy_from_user_std)
++WEAK(arm_copy_from_user)
+
+ #include "copy_template.S"
+
+ ENDPROC(arm_copy_from_user)
++ENDPROC(__copy_from_user_std)
+
+ .pushsection .fixup,"ax"
+ .align 0
+--- /dev/null
++++ b/arch/arm/lib/exports_rpi.c
+@@ -0,0 +1,37 @@
++/**
++ * Copyright (c) 2014, Raspberry Pi (Trading) Ltd.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++
++EXPORT_SYMBOL(memcmp);
+--- /dev/null
++++ b/arch/arm/lib/memcmp_rpi.S
+@@ -0,0 +1,285 @@
++/*
++Copyright (c) 2013, Raspberry Pi Foundation
++Copyright (c) 2013, RISC OS Open Ltd
++All rights reserved.
++
++Redistribution and use in source and binary forms, with or without
++modification, are permitted provided that the following conditions are met:
++ * Redistributions of source code must retain the above copyright
++ notice, this list of conditions and the following disclaimer.
++ * Redistributions in binary form must reproduce the above copyright
++ notice, this list of conditions and the following disclaimer in the
++ documentation and/or other materials provided with the distribution.
++ * Neither the name of the copyright holder nor the
++ names of its contributors may be used to endorse or promote products
++ derived from this software without specific prior written permission.
++
++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
++*/
++
++#include <linux/linkage.h>
++#include "arm-mem.h"
++
++/* Prevent the stack from becoming executable */
++#if defined(__linux__) && defined(__ELF__)
++.section .note.GNU-stack,"",%progbits
++#endif
++
++ .text
++ .arch armv6
++ .object_arch armv4
++ .arm
++ .altmacro
++ .p2align 2
++
++.macro memcmp_process_head unaligned
++ .if unaligned
++ ldr DAT0, [S_1], #4
++ ldr DAT1, [S_1], #4
++ ldr DAT2, [S_1], #4
++ ldr DAT3, [S_1], #4
++ .else
++ ldmia S_1!, {DAT0, DAT1, DAT2, DAT3}
++ .endif
++ ldmia S_2!, {DAT4, DAT5, DAT6, DAT7}
++.endm
++
++.macro memcmp_process_tail
++ cmp DAT0, DAT4
++ cmpeq DAT1, DAT5
++ cmpeq DAT2, DAT6
++ cmpeq DAT3, DAT7
++ bne 200f
++.endm
++
++.macro memcmp_leading_31bytes
++ movs DAT0, OFF, lsl #31
++ ldrmib DAT0, [S_1], #1
++ ldrcsh DAT1, [S_1], #2
++ ldrmib DAT4, [S_2], #1
++ ldrcsh DAT5, [S_2], #2
++ movpl DAT0, #0
++ movcc DAT1, #0
++ movpl DAT4, #0
++ movcc DAT5, #0
++ submi N, N, #1
++ subcs N, N, #2
++ cmp DAT0, DAT4
++ cmpeq DAT1, DAT5
++ bne 200f
++ movs DAT0, OFF, lsl #29
++ ldrmi DAT0, [S_1], #4
++ ldrcs DAT1, [S_1], #4
++ ldrcs DAT2, [S_1], #4
++ ldrmi DAT4, [S_2], #4
++ ldmcsia S_2!, {DAT5, DAT6}
++ movpl DAT0, #0
++ movcc DAT1, #0
++ movcc DAT2, #0
++ movpl DAT4, #0
++ movcc DAT5, #0
++ movcc DAT6, #0
++ submi N, N, #4
++ subcs N, N, #8
++ cmp DAT0, DAT4
++ cmpeq DAT1, DAT5
++ cmpeq DAT2, DAT6
++ bne 200f
++ tst OFF, #16
++ beq 105f
++ memcmp_process_head 1
++ sub N, N, #16
++ memcmp_process_tail
++105:
++.endm
++
++.macro memcmp_trailing_15bytes unaligned
++ movs N, N, lsl #29
++ .if unaligned
++ ldrcs DAT0, [S_1], #4
++ ldrcs DAT1, [S_1], #4
++ .else
++ ldmcsia S_1!, {DAT0, DAT1}
++ .endif
++ ldrmi DAT2, [S_1], #4
++ ldmcsia S_2!, {DAT4, DAT5}
++ ldrmi DAT6, [S_2], #4
++ movcc DAT0, #0
++ movcc DAT1, #0
++ movpl DAT2, #0
++ movcc DAT4, #0
++ movcc DAT5, #0
++ movpl DAT6, #0
++ cmp DAT0, DAT4
++ cmpeq DAT1, DAT5
++ cmpeq DAT2, DAT6
++ bne 200f
++ movs N, N, lsl #2
++ ldrcsh DAT0, [S_1], #2
++ ldrmib DAT1, [S_1]
++ ldrcsh DAT4, [S_2], #2
++ ldrmib DAT5, [S_2]
++ movcc DAT0, #0
++ movpl DAT1, #0
++ movcc DAT4, #0
++ movpl DAT5, #0
++ cmp DAT0, DAT4
++ cmpeq DAT1, DAT5
++ bne 200f
++.endm
++
++.macro memcmp_long_inner_loop unaligned
++110:
++ memcmp_process_head unaligned
++ pld [S_2, #prefetch_distance*32 + 16]
++ memcmp_process_tail
++ memcmp_process_head unaligned
++ pld [S_1, OFF]
++ memcmp_process_tail
++ subs N, N, #32
++ bhs 110b
++ /* Just before the final (prefetch_distance+1) 32-byte blocks,
++ * deal with final preloads */
++ preload_trailing 0, S_1, N, DAT0
++ preload_trailing 0, S_2, N, DAT0
++ add N, N, #(prefetch_distance+2)*32 - 16
++120:
++ memcmp_process_head unaligned
++ memcmp_process_tail
++ subs N, N, #16
++ bhs 120b
++ /* Trailing words and bytes */
++ tst N, #15
++ beq 199f
++ memcmp_trailing_15bytes unaligned
++199: /* Reached end without detecting a difference */
++ mov a1, #0
++ setend le
++ pop {DAT1-DAT6, pc}
++.endm
++
++.macro memcmp_short_inner_loop unaligned
++ subs N, N, #16 /* simplifies inner loop termination */
++ blo 122f
++120:
++ memcmp_process_head unaligned
++ memcmp_process_tail
++ subs N, N, #16
++ bhs 120b
++122: /* Trailing words and bytes */
++ tst N, #15
++ beq 199f
++ memcmp_trailing_15bytes unaligned
++199: /* Reached end without detecting a difference */
++ mov a1, #0
++ setend le
++ pop {DAT1-DAT6, pc}
++.endm
++
++/*
++ * int memcmp(const void *s1, const void *s2, size_t n);
++ * On entry:
++ * a1 = pointer to buffer 1
++ * a2 = pointer to buffer 2
++ * a3 = number of bytes to compare (as unsigned chars)
++ * On exit:
++ * a1 = >0/=0/<0 if s1 >/=/< s2
++ */
++
++.set prefetch_distance, 2
++
++ENTRY(memcmp)
++ S_1 .req a1
++ S_2 .req a2
++ N .req a3
++ DAT0 .req a4
++ DAT1 .req v1
++ DAT2 .req v2
++ DAT3 .req v3
++ DAT4 .req v4
++ DAT5 .req v5
++ DAT6 .req v6
++ DAT7 .req ip
++ OFF .req lr
++
++ push {DAT1-DAT6, lr}
++ setend be /* lowest-addressed bytes are most significant */
++
++ /* To preload ahead as we go, we need at least (prefetch_distance+2) 32-byte blocks */
++ cmp N, #(prefetch_distance+3)*32 - 1
++ blo 170f
++
++ /* Long case */
++ /* Adjust N so that the decrement instruction can also test for
++ * inner loop termination. We want it to stop when there are
++ * (prefetch_distance+1) complete blocks to go. */
++ sub N, N, #(prefetch_distance+2)*32
++ preload_leading_step1 0, DAT0, S_1
++ preload_leading_step1 0, DAT1, S_2
++ tst S_2, #31
++ beq 154f
++ rsb OFF, S_2, #0 /* no need to AND with 15 here */
++ preload_leading_step2 0, DAT0, S_1, OFF, DAT2
++ preload_leading_step2 0, DAT1, S_2, OFF, DAT2
++ memcmp_leading_31bytes
++154: /* Second source now cacheline (32-byte) aligned; we have at
++ * least one prefetch to go. */
++ /* Prefetch offset is best selected such that it lies in the
++ * first 8 of each 32 bytes - but it's just as easy to aim for
++ * the first one */
++ and OFF, S_1, #31
++ rsb OFF, OFF, #32*prefetch_distance
++ tst S_1, #3
++ bne 140f
++ memcmp_long_inner_loop 0
++140: memcmp_long_inner_loop 1
++
++170: /* Short case */
++ teq N, #0
++ beq 199f
++ preload_all 0, 0, 0, S_1, N, DAT0, DAT1
++ preload_all 0, 0, 0, S_2, N, DAT0, DAT1
++ tst S_2, #3
++ beq 174f
++172: subs N, N, #1
++ blo 199f
++ ldrb DAT0, [S_1], #1
++ ldrb DAT4, [S_2], #1
++ cmp DAT0, DAT4
++ bne 200f
++ tst S_2, #3
++ bne 172b
++174: /* Second source now 4-byte aligned; we have 0 or more bytes to go */
++ tst S_1, #3
++ bne 140f
++ memcmp_short_inner_loop 0
++140: memcmp_short_inner_loop 1
++
++200: /* Difference found: determine sign. */
++ movhi a1, #1
++ movlo a1, #-1
++ setend le
++ pop {DAT1-DAT6, pc}
++
++ .unreq S_1
++ .unreq S_2
++ .unreq N
++ .unreq DAT0
++ .unreq DAT1
++ .unreq DAT2
++ .unreq DAT3
++ .unreq DAT4
++ .unreq DAT5
++ .unreq DAT6
++ .unreq DAT7
++ .unreq OFF
++ENDPROC(memcmp)
+--- /dev/null
++++ b/arch/arm/lib/memcpy_rpi.S
+@@ -0,0 +1,61 @@
++/*
++Copyright (c) 2013, Raspberry Pi Foundation
++Copyright (c) 2013, RISC OS Open Ltd
++All rights reserved.
++
++Redistribution and use in source and binary forms, with or without
++modification, are permitted provided that the following conditions are met:
++ * Redistributions of source code must retain the above copyright
++ notice, this list of conditions and the following disclaimer.
++ * Redistributions in binary form must reproduce the above copyright
++ notice, this list of conditions and the following disclaimer in the
++ documentation and/or other materials provided with the distribution.
++ * Neither the name of the copyright holder nor the
++ names of its contributors may be used to endorse or promote products
++ derived from this software without specific prior written permission.
++
++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
++*/
++
++#include <linux/linkage.h>
++#include "arm-mem.h"
++#include "memcpymove.h"
++
++/* Prevent the stack from becoming executable */
++#if defined(__linux__) && defined(__ELF__)
++.section .note.GNU-stack,"",%progbits
++#endif
++
++ .text
++ .arch armv6
++ .object_arch armv4
++ .arm
++ .altmacro
++ .p2align 2
++
++/*
++ * void *memcpy(void * restrict s1, const void * restrict s2, size_t n);
++ * On entry:
++ * a1 = pointer to destination
++ * a2 = pointer to source
++ * a3 = number of bytes to copy
++ * On exit:
++ * a1 preserved
++ */
++
++.set prefetch_distance, 3
++
++ENTRY(mmiocpy)
++ENTRY(memcpy)
++ memcpy 0
++ENDPROC(memcpy)
++ENDPROC(mmiocpy)
+--- /dev/null
++++ b/arch/arm/lib/memcpymove.h
+@@ -0,0 +1,506 @@
++/*
++Copyright (c) 2013, Raspberry Pi Foundation
++Copyright (c) 2013, RISC OS Open Ltd
++All rights reserved.
++
++Redistribution and use in source and binary forms, with or without
++modification, are permitted provided that the following conditions are met:
++ * Redistributions of source code must retain the above copyright
++ notice, this list of conditions and the following disclaimer.
++ * Redistributions in binary form must reproduce the above copyright
++ notice, this list of conditions and the following disclaimer in the
++ documentation and/or other materials provided with the distribution.
++ * Neither the name of the copyright holder nor the
++ names of its contributors may be used to endorse or promote products
++ derived from this software without specific prior written permission.
++
++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
++*/
++
++.macro unaligned_words backwards, align, use_pld, words, r0, r1, r2, r3, r4, r5, r6, r7, r8
++ .if words == 1
++ .if backwards
++ mov r1, r0, lsl #32-align*8
++ ldr r0, [S, #-4]!
++ orr r1, r1, r0, lsr #align*8
++ str r1, [D, #-4]!
++ .else
++ mov r0, r1, lsr #align*8
++ ldr r1, [S, #4]!
++ orr r0, r0, r1, lsl #32-align*8
++ str r0, [D], #4
++ .endif
++ .elseif words == 2
++ .if backwards
++ ldr r1, [S, #-4]!
++ mov r2, r0, lsl #32-align*8
++ ldr r0, [S, #-4]!
++ orr r2, r2, r1, lsr #align*8
++ mov r1, r1, lsl #32-align*8
++ orr r1, r1, r0, lsr #align*8
++ stmdb D!, {r1, r2}
++ .else
++ ldr r1, [S, #4]!
++ mov r0, r2, lsr #align*8
++ ldr r2, [S, #4]!
++ orr r0, r0, r1, lsl #32-align*8
++ mov r1, r1, lsr #align*8
++ orr r1, r1, r2, lsl #32-align*8
++ stmia D!, {r0, r1}
++ .endif
++ .elseif words == 4
++ .if backwards
++ ldmdb S!, {r2, r3}
++ mov r4, r0, lsl #32-align*8
++ ldmdb S!, {r0, r1}
++ orr r4, r4, r3, lsr #align*8
++ mov r3, r3, lsl #32-align*8
++ orr r3, r3, r2, lsr #align*8
++ mov r2, r2, lsl #32-align*8
++ orr r2, r2, r1, lsr #align*8
++ mov r1, r1, lsl #32-align*8
++ orr r1, r1, r0, lsr #align*8
++ stmdb D!, {r1, r2, r3, r4}
++ .else
++ ldmib S!, {r1, r2}
++ mov r0, r4, lsr #align*8
++ ldmib S!, {r3, r4}
++ orr r0, r0, r1, lsl #32-align*8
++ mov r1, r1, lsr #align*8
++ orr r1, r1, r2, lsl #32-align*8
++ mov r2, r2, lsr #align*8
++ orr r2, r2, r3, lsl #32-align*8
++ mov r3, r3, lsr #align*8
++ orr r3, r3, r4, lsl #32-align*8
++ stmia D!, {r0, r1, r2, r3}
++ .endif
++ .elseif words == 8
++ .if backwards
++ ldmdb S!, {r4, r5, r6, r7}
++ mov r8, r0, lsl #32-align*8
++ ldmdb S!, {r0, r1, r2, r3}
++ .if use_pld
++ pld [S, OFF]
++ .endif
++ orr r8, r8, r7, lsr #align*8
++ mov r7, r7, lsl #32-align*8
++ orr r7, r7, r6, lsr #align*8
++ mov r6, r6, lsl #32-align*8
++ orr r6, r6, r5, lsr #align*8
++ mov r5, r5, lsl #32-align*8
++ orr r5, r5, r4, lsr #align*8
++ mov r4, r4, lsl #32-align*8
++ orr r4, r4, r3, lsr #align*8
++ mov r3, r3, lsl #32-align*8
++ orr r3, r3, r2, lsr #align*8
++ mov r2, r2, lsl #32-align*8
++ orr r2, r2, r1, lsr #align*8
++ mov r1, r1, lsl #32-align*8
++ orr r1, r1, r0, lsr #align*8
++ stmdb D!, {r5, r6, r7, r8}
++ stmdb D!, {r1, r2, r3, r4}
++ .else
++ ldmib S!, {r1, r2, r3, r4}
++ mov r0, r8, lsr #align*8
++ ldmib S!, {r5, r6, r7, r8}
++ .if use_pld
++ pld [S, OFF]
++ .endif
++ orr r0, r0, r1, lsl #32-align*8
++ mov r1, r1, lsr #align*8
++ orr r1, r1, r2, lsl #32-align*8
++ mov r2, r2, lsr #align*8
++ orr r2, r2, r3, lsl #32-align*8
++ mov r3, r3, lsr #align*8
++ orr r3, r3, r4, lsl #32-align*8
++ mov r4, r4, lsr #align*8
++ orr r4, r4, r5, lsl #32-align*8
++ mov r5, r5, lsr #align*8
++ orr r5, r5, r6, lsl #32-align*8
++ mov r6, r6, lsr #align*8
++ orr r6, r6, r7, lsl #32-align*8
++ mov r7, r7, lsr #align*8
++ orr r7, r7, r8, lsl #32-align*8
++ stmia D!, {r0, r1, r2, r3}
++ stmia D!, {r4, r5, r6, r7}
++ .endif
++ .endif
++.endm
++
++.macro memcpy_leading_15bytes backwards, align
++ movs DAT1, DAT2, lsl #31
++ sub N, N, DAT2
++ .if backwards
++ ldrmib DAT0, [S, #-1]!
++ ldrcsh DAT1, [S, #-2]!
++ strmib DAT0, [D, #-1]!
++ strcsh DAT1, [D, #-2]!
++ .else
++ ldrmib DAT0, [S], #1
++ ldrcsh DAT1, [S], #2
++ strmib DAT0, [D], #1
++ strcsh DAT1, [D], #2
++ .endif
++ movs DAT1, DAT2, lsl #29
++ .if backwards
++ ldrmi DAT0, [S, #-4]!
++ .if align == 0
++ ldmcsdb S!, {DAT1, DAT2}
++ .else
++ ldrcs DAT2, [S, #-4]!
++ ldrcs DAT1, [S, #-4]!
++ .endif
++ strmi DAT0, [D, #-4]!
++ stmcsdb D!, {DAT1, DAT2}
++ .else
++ ldrmi DAT0, [S], #4
++ .if align == 0
++ ldmcsia S!, {DAT1, DAT2}
++ .else
++ ldrcs DAT1, [S], #4
++ ldrcs DAT2, [S], #4
++ .endif
++ strmi DAT0, [D], #4
++ stmcsia D!, {DAT1, DAT2}
++ .endif
++.endm
++
++.macro memcpy_trailing_15bytes backwards, align
++ movs N, N, lsl #29
++ .if backwards
++ .if align == 0
++ ldmcsdb S!, {DAT0, DAT1}
++ .else
++ ldrcs DAT1, [S, #-4]!
++ ldrcs DAT0, [S, #-4]!
++ .endif
++ ldrmi DAT2, [S, #-4]!
++ stmcsdb D!, {DAT0, DAT1}
++ strmi DAT2, [D, #-4]!
++ .else
++ .if align == 0
++ ldmcsia S!, {DAT0, DAT1}
++ .else
++ ldrcs DAT0, [S], #4
++ ldrcs DAT1, [S], #4
++ .endif
++ ldrmi DAT2, [S], #4
++ stmcsia D!, {DAT0, DAT1}
++ strmi DAT2, [D], #4
++ .endif
++ movs N, N, lsl #2
++ .if backwards
++ ldrcsh DAT0, [S, #-2]!
++ ldrmib DAT1, [S, #-1]
++ strcsh DAT0, [D, #-2]!
++ strmib DAT1, [D, #-1]
++ .else
++ ldrcsh DAT0, [S], #2
++ ldrmib DAT1, [S]
++ strcsh DAT0, [D], #2
++ strmib DAT1, [D]
++ .endif
++.endm
++
++.macro memcpy_long_inner_loop backwards, align
++ .if align != 0
++ .if backwards
++ ldr DAT0, [S, #-align]!
++ .else
++ ldr LAST, [S, #-align]!
++ .endif
++ .endif
++110:
++ .if align == 0
++ .if backwards
++ ldmdb S!, {DAT0, DAT1, DAT2, DAT3, DAT4, DAT5, DAT6, LAST}
++ pld [S, OFF]
++ stmdb D!, {DAT4, DAT5, DAT6, LAST}
++ stmdb D!, {DAT0, DAT1, DAT2, DAT3}
++ .else
++ ldmia S!, {DAT0, DAT1, DAT2, DAT3, DAT4, DAT5, DAT6, LAST}
++ pld [S, OFF]
++ stmia D!, {DAT0, DAT1, DAT2, DAT3}
++ stmia D!, {DAT4, DAT5, DAT6, LAST}
++ .endif
++ .else
++ unaligned_words backwards, align, 1, 8, DAT0, DAT1, DAT2, DAT3, DAT4, DAT5, DAT6, DAT7, LAST
++ .endif
++ subs N, N, #32
++ bhs 110b
++ /* Just before the final (prefetch_distance+1) 32-byte blocks, deal with final preloads */
++ preload_trailing backwards, S, N, OFF
++ add N, N, #(prefetch_distance+2)*32 - 32
++120:
++ .if align == 0
++ .if backwards
++ ldmdb S!, {DAT0, DAT1, DAT2, DAT3, DAT4, DAT5, DAT6, LAST}
++ stmdb D!, {DAT4, DAT5, DAT6, LAST}
++ stmdb D!, {DAT0, DAT1, DAT2, DAT3}
++ .else
++ ldmia S!, {DAT0, DAT1, DAT2, DAT3, DAT4, DAT5, DAT6, LAST}
++ stmia D!, {DAT0, DAT1, DAT2, DAT3}
++ stmia D!, {DAT4, DAT5, DAT6, LAST}
++ .endif
++ .else
++ unaligned_words backwards, align, 0, 8, DAT0, DAT1, DAT2, DAT3, DAT4, DAT5, DAT6, DAT7, LAST
++ .endif
++ subs N, N, #32
++ bhs 120b
++ tst N, #16
++ .if align == 0
++ .if backwards
++ ldmnedb S!, {DAT0, DAT1, DAT2, LAST}
++ stmnedb D!, {DAT0, DAT1, DAT2, LAST}
++ .else
++ ldmneia S!, {DAT0, DAT1, DAT2, LAST}
++ stmneia D!, {DAT0, DAT1, DAT2, LAST}
++ .endif
++ .else
++ beq 130f
++ unaligned_words backwards, align, 0, 4, DAT0, DAT1, DAT2, DAT3, LAST
++130:
++ .endif
++ /* Trailing words and bytes */
++ tst N, #15
++ beq 199f
++ .if align != 0
++ add S, S, #align
++ .endif
++ memcpy_trailing_15bytes backwards, align
++199:
++ pop {DAT3, DAT4, DAT5, DAT6, DAT7}
++ pop {D, DAT1, DAT2, pc}
++.endm
++
++.macro memcpy_medium_inner_loop backwards, align
++120:
++ .if backwards
++ .if align == 0
++ ldmdb S!, {DAT0, DAT1, DAT2, LAST}
++ .else
++ ldr LAST, [S, #-4]!
++ ldr DAT2, [S, #-4]!
++ ldr DAT1, [S, #-4]!
++ ldr DAT0, [S, #-4]!
++ .endif
++ stmdb D!, {DAT0, DAT1, DAT2, LAST}
++ .else
++ .if align == 0
++ ldmia S!, {DAT0, DAT1, DAT2, LAST}
++ .else
++ ldr DAT0, [S], #4
++ ldr DAT1, [S], #4
++ ldr DAT2, [S], #4
++ ldr LAST, [S], #4
++ .endif
++ stmia D!, {DAT0, DAT1, DAT2, LAST}
++ .endif
++ subs N, N, #16
++ bhs 120b
++ /* Trailing words and bytes */
++ tst N, #15
++ beq 199f
++ memcpy_trailing_15bytes backwards, align
++199:
++ pop {D, DAT1, DAT2, pc}
++.endm
++
++.macro memcpy_short_inner_loop backwards, align
++ tst N, #16
++ .if backwards
++ .if align == 0
++ ldmnedb S!, {DAT0, DAT1, DAT2, LAST}
++ .else
++ ldrne LAST, [S, #-4]!
++ ldrne DAT2, [S, #-4]!
++ ldrne DAT1, [S, #-4]!
++ ldrne DAT0, [S, #-4]!
++ .endif
++ stmnedb D!, {DAT0, DAT1, DAT2, LAST}
++ .else
++ .if align == 0
++ ldmneia S!, {DAT0, DAT1, DAT2, LAST}
++ .else
++ ldrne DAT0, [S], #4
++ ldrne DAT1, [S], #4
++ ldrne DAT2, [S], #4
++ ldrne LAST, [S], #4
++ .endif
++ stmneia D!, {DAT0, DAT1, DAT2, LAST}
++ .endif
++ memcpy_trailing_15bytes backwards, align
++199:
++ pop {D, DAT1, DAT2, pc}
++.endm
++
++.macro memcpy backwards
++ D .req a1
++ S .req a2
++ N .req a3
++ DAT0 .req a4
++ DAT1 .req v1
++ DAT2 .req v2
++ DAT3 .req v3
++ DAT4 .req v4
++ DAT5 .req v5
++ DAT6 .req v6
++ DAT7 .req sl
++ LAST .req ip
++ OFF .req lr
++
++ .cfi_startproc
++
++ push {D, DAT1, DAT2, lr}
++
++ .cfi_def_cfa_offset 16
++ .cfi_rel_offset D, 0
++ .cfi_undefined S
++ .cfi_undefined N
++ .cfi_undefined DAT0
++ .cfi_rel_offset DAT1, 4
++ .cfi_rel_offset DAT2, 8
++ .cfi_undefined LAST
++ .cfi_rel_offset lr, 12
++
++ .if backwards
++ add D, D, N
++ add S, S, N
++ .endif
++
++ /* See if we're guaranteed to have at least one 16-byte aligned 16-byte write */
++ cmp N, #31
++ blo 170f
++ /* To preload ahead as we go, we need at least (prefetch_distance+2) 32-byte blocks */
++ cmp N, #(prefetch_distance+3)*32 - 1
++ blo 160f
++
++ /* Long case */
++ push {DAT3, DAT4, DAT5, DAT6, DAT7}
++
++ .cfi_def_cfa_offset 36
++ .cfi_rel_offset D, 20
++ .cfi_rel_offset DAT1, 24
++ .cfi_rel_offset DAT2, 28
++ .cfi_rel_offset DAT3, 0
++ .cfi_rel_offset DAT4, 4
++ .cfi_rel_offset DAT5, 8
++ .cfi_rel_offset DAT6, 12
++ .cfi_rel_offset DAT7, 16
++ .cfi_rel_offset lr, 32
++
++ /* Adjust N so that the decrement instruction can also test for
++ * inner loop termination. We want it to stop when there are
++ * (prefetch_distance+1) complete blocks to go. */
++ sub N, N, #(prefetch_distance+2)*32
++ preload_leading_step1 backwards, DAT0, S
++ .if backwards
++ /* Bug in GAS: it accepts, but mis-assembles the instruction
++ * ands DAT2, D, #60, 2
++ * which sets DAT2 to the number of leading bytes until destination is aligned and also clears C (sets borrow)
++ */
++ .word 0xE210513C
++ beq 154f
++ .else
++ ands DAT2, D, #15
++ beq 154f
++ rsb DAT2, DAT2, #16 /* number of leading bytes until destination aligned */
++ .endif
++ preload_leading_step2 backwards, DAT0, S, DAT2, OFF
++ memcpy_leading_15bytes backwards, 1
++154: /* Destination now 16-byte aligned; we have at least one prefetch as well as at least one 16-byte output block */
++ /* Prefetch offset is best selected such that it lies in the first 8 of each 32 bytes - but it's just as easy to aim for the first one */
++ .if backwards
++ rsb OFF, S, #3
++ and OFF, OFF, #28
++ sub OFF, OFF, #32*(prefetch_distance+1)
++ .else
++ and OFF, S, #28
++ rsb OFF, OFF, #32*prefetch_distance
++ .endif
++ movs DAT0, S, lsl #31
++ bhi 157f
++ bcs 156f
++ bmi 155f
++ memcpy_long_inner_loop backwards, 0
++155: memcpy_long_inner_loop backwards, 1
++156: memcpy_long_inner_loop backwards, 2
++157: memcpy_long_inner_loop backwards, 3
++
++ .cfi_def_cfa_offset 16
++ .cfi_rel_offset D, 0
++ .cfi_rel_offset DAT1, 4
++ .cfi_rel_offset DAT2, 8
++ .cfi_same_value DAT3
++ .cfi_same_value DAT4
++ .cfi_same_value DAT5
++ .cfi_same_value DAT6
++ .cfi_same_value DAT7
++ .cfi_rel_offset lr, 12
++
++160: /* Medium case */
++ preload_all backwards, 0, 0, S, N, DAT2, OFF
++ sub N, N, #16 /* simplifies inner loop termination */
++ .if backwards
++ ands DAT2, D, #15
++ beq 164f
++ .else
++ ands DAT2, D, #15
++ beq 164f
++ rsb DAT2, DAT2, #16
++ .endif
++ memcpy_leading_15bytes backwards, align
++164: /* Destination now 16-byte aligned; we have at least one 16-byte output block */
++ tst S, #3
++ bne 140f
++ memcpy_medium_inner_loop backwards, 0
++140: memcpy_medium_inner_loop backwards, 1
++
++170: /* Short case, less than 31 bytes, so no guarantee of at least one 16-byte block */
++ teq N, #0
++ beq 199f
++ preload_all backwards, 1, 0, S, N, DAT2, LAST
++ tst D, #3
++ beq 174f
++172: subs N, N, #1
++ blo 199f
++ .if backwards
++ ldrb DAT0, [S, #-1]!
++ strb DAT0, [D, #-1]!
++ .else
++ ldrb DAT0, [S], #1
++ strb DAT0, [D], #1
++ .endif
++ tst D, #3
++ bne 172b
++174: /* Destination now 4-byte aligned; we have 0 or more output bytes to go */
++ tst S, #3
++ bne 140f
++ memcpy_short_inner_loop backwards, 0
++140: memcpy_short_inner_loop backwards, 1
++
++ .cfi_endproc
++
++ .unreq D
++ .unreq S
++ .unreq N
++ .unreq DAT0
++ .unreq DAT1
++ .unreq DAT2
++ .unreq DAT3
++ .unreq DAT4
++ .unreq DAT5
++ .unreq DAT6
++ .unreq DAT7
++ .unreq LAST
++ .unreq OFF
++.endm
+--- /dev/null
++++ b/arch/arm/lib/memmove_rpi.S
+@@ -0,0 +1,61 @@
++/*
++Copyright (c) 2013, Raspberry Pi Foundation
++Copyright (c) 2013, RISC OS Open Ltd
++All rights reserved.
++
++Redistribution and use in source and binary forms, with or without
++modification, are permitted provided that the following conditions are met:
++ * Redistributions of source code must retain the above copyright
++ notice, this list of conditions and the following disclaimer.
++ * Redistributions in binary form must reproduce the above copyright
++ notice, this list of conditions and the following disclaimer in the
++ documentation and/or other materials provided with the distribution.
++ * Neither the name of the copyright holder nor the
++ names of its contributors may be used to endorse or promote products
++ derived from this software without specific prior written permission.
++
++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
++*/
++
++#include <linux/linkage.h>
++#include "arm-mem.h"
++#include "memcpymove.h"
++
++/* Prevent the stack from becoming executable */
++#if defined(__linux__) && defined(__ELF__)
++.section .note.GNU-stack,"",%progbits
++#endif
++
++ .text
++ .arch armv6
++ .object_arch armv4
++ .arm
++ .altmacro
++ .p2align 2
++
++/*
++ * void *memmove(void *s1, const void *s2, size_t n);
++ * On entry:
++ * a1 = pointer to destination
++ * a2 = pointer to source
++ * a3 = number of bytes to copy
++ * On exit:
++ * a1 preserved
++ */
++
++.set prefetch_distance, 3
++
++ENTRY(memmove)
++ cmp a2, a1
++ bpl memcpy /* pl works even over -1 - 0 and 0x7fffffff - 0x80000000 boundaries */
++ memcpy 1
++ENDPROC(memmove)
+--- /dev/null
++++ b/arch/arm/lib/memset_rpi.S
+@@ -0,0 +1,123 @@
++/*
++Copyright (c) 2013, Raspberry Pi Foundation
++Copyright (c) 2013, RISC OS Open Ltd
++All rights reserved.
++
++Redistribution and use in source and binary forms, with or without
++modification, are permitted provided that the following conditions are met:
++ * Redistributions of source code must retain the above copyright
++ notice, this list of conditions and the following disclaimer.
++ * Redistributions in binary form must reproduce the above copyright
++ notice, this list of conditions and the following disclaimer in the
++ documentation and/or other materials provided with the distribution.
++ * Neither the name of the copyright holder nor the
++ names of its contributors may be used to endorse or promote products
++ derived from this software without specific prior written permission.
++
++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
++*/
++
++#include <linux/linkage.h>
++#include "arm-mem.h"
++
++/* Prevent the stack from becoming executable */
++#if defined(__linux__) && defined(__ELF__)
++.section .note.GNU-stack,"",%progbits
++#endif
++
++ .text
++ .arch armv6
++ .object_arch armv4
++ .arm
++ .altmacro
++ .p2align 2
++
++/*
++ * void *memset(void *s, int c, size_t n);
++ * On entry:
++ * a1 = pointer to buffer to fill
++ * a2 = byte pattern to fill with (caller-narrowed)
++ * a3 = number of bytes to fill
++ * On exit:
++ * a1 preserved
++ */
++ENTRY(mmioset)
++ENTRY(memset)
++ S .req a1
++ DAT0 .req a2
++ N .req a3
++ DAT1 .req a4
++ DAT2 .req ip
++ DAT3 .req lr
++
++ orr DAT0, DAT0, lsl #8
++ push {S, lr}
++ orr DAT0, DAT0, lsl #16
++ mov DAT1, DAT0
++
++ /* See if we're guaranteed to have at least one 16-byte aligned 16-byte write */
++ cmp N, #31
++ blo 170f
++
++161: sub N, N, #16 /* simplifies inner loop termination */
++ /* Leading words and bytes */
++ tst S, #15
++ beq 164f
++ rsb DAT3, S, #0 /* bits 0-3 = number of leading bytes until aligned */
++ movs DAT2, DAT3, lsl #31
++ submi N, N, #1
++ strmib DAT0, [S], #1
++ subcs N, N, #2
++ strcsh DAT0, [S], #2
++ movs DAT2, DAT3, lsl #29
++ submi N, N, #4
++ strmi DAT0, [S], #4
++ subcs N, N, #8
++ stmcsia S!, {DAT0, DAT1}
++164: /* Delayed set up of DAT2 and DAT3 so we could use them as scratch registers above */
++ mov DAT2, DAT0
++ mov DAT3, DAT0
++ /* Now the inner loop of 16-byte stores */
++165: stmia S!, {DAT0, DAT1, DAT2, DAT3}
++ subs N, N, #16
++ bhs 165b
++166: /* Trailing words and bytes */
++ movs N, N, lsl #29
++ stmcsia S!, {DAT0, DAT1}
++ strmi DAT0, [S], #4
++ movs N, N, lsl #2
++ strcsh DAT0, [S], #2
++ strmib DAT0, [S]
++199: pop {S, pc}
++
++170: /* Short case */
++ mov DAT2, DAT0
++ mov DAT3, DAT0
++ tst S, #3
++ beq 174f
++172: subs N, N, #1
++ blo 199b
++ strb DAT0, [S], #1
++ tst S, #3
++ bne 172b
++174: tst N, #16
++ stmneia S!, {DAT0, DAT1, DAT2, DAT3}
++ b 166b
++
++ .unreq S
++ .unreq DAT0
++ .unreq N
++ .unreq DAT1
++ .unreq DAT2
++ .unreq DAT3
++ENDPROC(memset)
++ENDPROC(mmioset)
+--- a/arch/arm/lib/uaccess_with_memcpy.c
++++ b/arch/arm/lib/uaccess_with_memcpy.c
+@@ -22,6 +22,14 @@
+ #include <asm/current.h>
+ #include <asm/page.h>
+
++#ifndef COPY_FROM_USER_THRESHOLD
++#define COPY_FROM_USER_THRESHOLD 64
++#endif
++
++#ifndef COPY_TO_USER_THRESHOLD
++#define COPY_TO_USER_THRESHOLD 64
++#endif
++
+ static int
+ pin_page_for_write(const void __user *_addr, pte_t **ptep, spinlock_t **ptlp)
+ {
+@@ -85,7 +93,44 @@ pin_page_for_write(const void __user *_a
+ return 1;
+ }
+
+-static unsigned long noinline
++static int
++pin_page_for_read(const void __user *_addr, pte_t **ptep, spinlock_t **ptlp)
++{
++ unsigned long addr = (unsigned long)_addr;
++ pgd_t *pgd;
++ pmd_t *pmd;
++ pte_t *pte;
++ pud_t *pud;
++ spinlock_t *ptl;
++
++ pgd = pgd_offset(current->mm, addr);
++ if (unlikely(pgd_none(*pgd) || pgd_bad(*pgd)))
++ {
++ return 0;
++ }
++ pud = pud_offset(pgd, addr);
++ if (unlikely(pud_none(*pud) || pud_bad(*pud)))
++ {
++ return 0;
++ }
++
++ pmd = pmd_offset(pud, addr);
++ if (unlikely(pmd_none(*pmd) || pmd_bad(*pmd)))
++ return 0;
++
++ pte = pte_offset_map_lock(current->mm, pmd, addr, &ptl);
++ if (unlikely(!pte_present(*pte) || !pte_young(*pte))) {
++ pte_unmap_unlock(pte, ptl);
++ return 0;
++ }
++
++ *ptep = pte;
++ *ptlp = ptl;
++
++ return 1;
++}
++
++unsigned long noinline
+ __copy_to_user_memcpy(void __user *to, const void *from, unsigned long n)
+ {
+ unsigned long ua_flags;
+@@ -138,6 +183,54 @@ out:
+ return n;
+ }
+
++unsigned long noinline
++__copy_from_user_memcpy(void *to, const void __user *from, unsigned long n)
++{
++ int atomic;
++
++ if (unlikely(segment_eq(get_fs(), KERNEL_DS))) {
++ memcpy(to, (const void *)from, n);
++ return 0;
++ }
++
++ /* the mmap semaphore is taken only if not in an atomic context */
++ atomic = in_atomic();
++
++ if (!atomic)
++ down_read(&current->mm->mmap_sem);
++ while (n) {
++ pte_t *pte;
++ spinlock_t *ptl;
++ int tocopy;
++
++ while (!pin_page_for_read(from, &pte, &ptl)) {
++ char temp;
++ if (!atomic)
++ up_read(&current->mm->mmap_sem);
++ if (__get_user(temp, (char __user *)from))
++ goto out;
++ if (!atomic)
++ down_read(&current->mm->mmap_sem);
++ }
++
++ tocopy = (~(unsigned long)from & ~PAGE_MASK) + 1;
++ if (tocopy > n)
++ tocopy = n;
++
++ memcpy(to, (const void *)from, tocopy);
++ to += tocopy;
++ from += tocopy;
++ n -= tocopy;
++
++ pte_unmap_unlock(pte, ptl);
++ }
++ if (!atomic)
++ up_read(&current->mm->mmap_sem);
++
++out:
++ return n;
++}
++
+ unsigned long
+ arm_copy_to_user(void __user *to, const void *from, unsigned long n)
+ {
+@@ -148,7 +241,7 @@ arm_copy_to_user(void __user *to, const
+ * With frame pointer disabled, tail call optimization kicks in
+ * as well making this test almost invisible.
+ */
+- if (n < 64) {
++ if (n < COPY_TO_USER_THRESHOLD) {
+ unsigned long ua_flags = uaccess_save_and_enable();
+ n = __copy_to_user_std(to, from, n);
+ uaccess_restore(ua_flags);
+@@ -157,6 +250,21 @@ arm_copy_to_user(void __user *to, const
+ }
+ return n;
+ }
++
++unsigned long __must_check
++arm_copy_from_user(void *to, const void __user *from, unsigned long n)
++{
++ /*
++ * This test is stubbed out of the main function above to keep
++ * the overhead for small copies low by avoiding a large
++ * register dump on the stack just to reload them right away.
++ * With frame pointer disabled, tail call optimization kicks in
++ * as well making this test almost invisible.
++ */
++ if (n < COPY_FROM_USER_THRESHOLD)
++ return __copy_from_user_std(to, from, n);
++ return __copy_from_user_memcpy(to, from, n);
++}
+
+ static unsigned long noinline
+ __clear_user_memset(void __user *addr, unsigned long n)
diff --git a/target/linux/brcm2708/patches-4.4/0079-rpi-ft5406-Add-touchscreen-driver-for-pi-LCD-display.patch b/target/linux/brcm2708/patches-4.4/0079-rpi-ft5406-Add-touchscreen-driver-for-pi-LCD-display.patch
deleted file mode 100644
index 0b3f67848d..0000000000
--- a/target/linux/brcm2708/patches-4.4/0079-rpi-ft5406-Add-touchscreen-driver-for-pi-LCD-display.patch
+++ /dev/null
@@ -1,290 +0,0 @@
-From 6fb12ee15eb9b0f5b6fea66c861a9db8ec6671ed Mon Sep 17 00:00:00 2001
-From: Gordon Hollingworth <gordon@raspberrypi.org>
-Date: Tue, 12 May 2015 14:47:56 +0100
-Subject: [PATCH 079/170] rpi-ft5406: Add touchscreen driver for pi LCD display
-
-Fix driver detection failure Check that the buffer response is non-zero meaning the touchscreen was detected
-
-rpi-ft5406: Use firmware API
----
- drivers/input/touchscreen/Kconfig | 7 +
- drivers/input/touchscreen/Makefile | 1 +
- drivers/input/touchscreen/rpi-ft5406.c | 246 +++++++++++++++++++++++++++++++++
- 3 files changed, 254 insertions(+)
- create mode 100644 drivers/input/touchscreen/rpi-ft5406.c
-
---- a/drivers/input/touchscreen/Kconfig
-+++ b/drivers/input/touchscreen/Kconfig
-@@ -608,6 +608,13 @@ config TOUCHSCREEN_EDT_FT5X06
- To compile this driver as a module, choose M here: the
- module will be called edt-ft5x06.
-
-+config TOUCHSCREEN_RPI_FT5406
-+ tristate "Raspberry Pi FT5406 driver"
-+ depends on RASPBERRYPI_FIRMWARE
-+ help
-+ Say Y here to enable the Raspberry Pi memory based FT5406 device
-+
-+
- config TOUCHSCREEN_MIGOR
- tristate "Renesas MIGO-R touchscreen"
- depends on SH_MIGOR && I2C
---- a/drivers/input/touchscreen/Makefile
-+++ b/drivers/input/touchscreen/Makefile
-@@ -29,6 +29,7 @@ obj-$(CONFIG_TOUCHSCREEN_DA9034) += da90
- obj-$(CONFIG_TOUCHSCREEN_DA9052) += da9052_tsi.o
- obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o
- obj-$(CONFIG_TOUCHSCREEN_EDT_FT5X06) += edt-ft5x06.o
-+obj-$(CONFIG_TOUCHSCREEN_RPI_FT5406) += rpi-ft5406.o
- obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o
- obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
- obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o
---- /dev/null
-+++ b/drivers/input/touchscreen/rpi-ft5406.c
-@@ -0,0 +1,246 @@
-+/*
-+ * Driver for memory based ft5406 touchscreen
-+ *
-+ * Copyright (C) 2015 Raspberry Pi
-+ *
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ */
-+
-+
-+#include <linux/module.h>
-+#include <linux/interrupt.h>
-+#include <linux/input.h>
-+#include <linux/irq.h>
-+#include <linux/delay.h>
-+#include <linux/slab.h>
-+#include <linux/bitops.h>
-+#include <linux/input/mt.h>
-+#include <linux/kthread.h>
-+#include <linux/platform_device.h>
-+#include <asm/io.h>
-+#include <soc/bcm2835/raspberrypi-firmware.h>
-+
-+#define MAXIMUM_SUPPORTED_POINTS 10
-+struct ft5406_regs {
-+ uint8_t device_mode;
-+ uint8_t gesture_id;
-+ uint8_t num_points;
-+ struct ft5406_touch {
-+ uint8_t xh;
-+ uint8_t xl;
-+ uint8_t yh;
-+ uint8_t yl;
-+ uint8_t res1;
-+ uint8_t res2;
-+ } point[MAXIMUM_SUPPORTED_POINTS];
-+};
-+
-+#define SCREEN_WIDTH 800
-+#define SCREEN_HEIGHT 480
-+
-+struct ft5406 {
-+ struct platform_device * pdev;
-+ struct input_dev * input_dev;
-+ void __iomem * ts_base;
-+ struct ft5406_regs * regs;
-+ struct task_struct * thread;
-+};
-+
-+/* Thread to poll for touchscreen events
-+ *
-+ * This thread polls the memory based register copy of the ft5406 registers
-+ * using the number of points register to know whether the copy has been
-+ * updated (we write 99 to the memory copy, the GPU will write between
-+ * 0 - 10 points)
-+ */
-+static int ft5406_thread(void *arg)
-+{
-+ struct ft5406 *ts = (struct ft5406 *) arg;
-+ struct ft5406_regs regs;
-+ int known_ids = 0;
-+
-+ while(!kthread_should_stop())
-+ {
-+ // 60fps polling
-+ msleep_interruptible(17);
-+ memcpy_fromio(&regs, ts->regs, sizeof(*ts->regs));
-+ writel(99, &ts->regs->num_points);
-+ // Do not output if theres no new information (num_points is 99)
-+ // or we have no touch points and don't need to release any
-+ if(!(regs.num_points == 99 || (regs.num_points == 0 && known_ids == 0)))
-+ {
-+ int i;
-+ int modified_ids = 0, released_ids;
-+ for(i = 0; i < regs.num_points; i++)
-+ {
-+ int x = (((int) regs.point[i].xh & 0xf) << 8) + regs.point[i].xl;
-+ int y = (((int) regs.point[i].yh & 0xf) << 8) + regs.point[i].yl;
-+ int touchid = (regs.point[i].yh >> 4) & 0xf;
-+
-+ modified_ids |= 1 << touchid;
-+
-+ if(!((1 << touchid) & known_ids))
-+ dev_dbg(&ts->pdev->dev, "x = %d, y = %d, touchid = %d\n", x, y, touchid);
-+
-+ input_mt_slot(ts->input_dev, touchid);
-+ input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 1);
-+
-+ input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x);
-+ input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y);
-+
-+ }
-+
-+ released_ids = known_ids & ~modified_ids;
-+ for(i = 0; released_ids && i < MAXIMUM_SUPPORTED_POINTS; i++)
-+ {
-+ if(released_ids & (1<<i))
-+ {
-+ dev_dbg(&ts->pdev->dev, "Released %d, known = %x modified = %x\n", i, known_ids, modified_ids);
-+ input_mt_slot(ts->input_dev, i);
-+ input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0);
-+ modified_ids &= ~(1 << i);
-+ }
-+ }
-+ known_ids = modified_ids;
-+
-+ input_mt_report_pointer_emulation(ts->input_dev, true);
-+ input_sync(ts->input_dev);
-+ }
-+
-+ }
-+
-+ return 0;
-+}
-+
-+static int ft5406_probe(struct platform_device *pdev)
-+{
-+ int ret;
-+ struct input_dev * input_dev = input_allocate_device();
-+ struct ft5406 * ts;
-+ struct device_node *fw_node;
-+ struct rpi_firmware *fw;
-+ u32 touchbuf;
-+
-+ dev_info(&pdev->dev, "Probing device\n");
-+
-+ fw_node = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
-+ if (!fw_node) {
-+ dev_err(&pdev->dev, "Missing firmware node\n");
-+ return -ENOENT;
-+ }
-+
-+ fw = rpi_firmware_get(fw_node);
-+ if (!fw)
-+ return -EPROBE_DEFER;
-+
-+ ret = rpi_firmware_property(fw, RPI_FIRMWARE_FRAMEBUFFER_GET_TOUCHBUF,
-+ &touchbuf, sizeof(touchbuf));
-+ if (ret) {
-+ dev_err(&pdev->dev, "Failed to get touch buffer\n");
-+ return ret;
-+ }
-+
-+ if (!touchbuf) {
-+ dev_err(&pdev->dev, "Touchscreen not detected\n");
-+ return -ENODEV;
-+ }
-+
-+ dev_dbg(&pdev->dev, "Got TS buffer 0x%x\n", touchbuf);
-+
-+ ts = kzalloc(sizeof(struct ft5406), GFP_KERNEL);
-+
-+ if (!ts || !input_dev) {
-+ ret = -ENOMEM;
-+ dev_err(&pdev->dev, "Failed to allocate memory\n");
-+ return ret;
-+ }
-+ ts->input_dev = input_dev;
-+ platform_set_drvdata(pdev, ts);
-+ ts->pdev = pdev;
-+
-+ input_dev->name = "FT5406 memory based driver";
-+
-+ __set_bit(EV_KEY, input_dev->evbit);
-+ __set_bit(EV_SYN, input_dev->evbit);
-+ __set_bit(EV_ABS, input_dev->evbit);
-+
-+ input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0,
-+ SCREEN_WIDTH, 0, 0);
-+ input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,
-+ SCREEN_HEIGHT, 0, 0);
-+
-+ input_mt_init_slots(input_dev, MAXIMUM_SUPPORTED_POINTS, INPUT_MT_DIRECT);
-+
-+ input_set_drvdata(input_dev, ts);
-+
-+ ret = input_register_device(input_dev);
-+ if (ret) {
-+ dev_err(&pdev->dev, "could not register input device, %d\n",
-+ ret);
-+ return ret;
-+ }
-+
-+ // mmap the physical memory
-+ touchbuf &= ~0xc0000000;
-+ ts->ts_base = ioremap(touchbuf, sizeof(*ts->regs));
-+ if(ts->ts_base == NULL)
-+ {
-+ dev_err(&pdev->dev, "Failed to map physical address\n");
-+ input_unregister_device(input_dev);
-+ kzfree(ts);
-+ return -ENOMEM;
-+ }
-+
-+ ts->regs = (struct ft5406_regs *) ts->ts_base;
-+
-+ // create thread to poll the touch events
-+ ts->thread = kthread_run(ft5406_thread, ts, "ft5406");
-+ if(ts->thread == NULL)
-+ {
-+ dev_err(&pdev->dev, "Failed to create kernel thread");
-+ iounmap(ts->ts_base);
-+ input_unregister_device(input_dev);
-+ kzfree(ts);
-+ }
-+
-+ return 0;
-+}
-+
-+static int ft5406_remove(struct platform_device *pdev)
-+{
-+ struct ft5406 *ts = (struct ft5406 *) platform_get_drvdata(pdev);
-+
-+ dev_info(&pdev->dev, "Removing rpi-ft5406\n");
-+
-+ kthread_stop(ts->thread);
-+ iounmap(ts->ts_base);
-+ input_unregister_device(ts->input_dev);
-+ kzfree(ts);
-+
-+ return 0;
-+}
-+
-+static const struct of_device_id ft5406_match[] = {
-+ { .compatible = "rpi,rpi-ft5406", },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(of, ft5406_match);
-+
-+static struct platform_driver ft5406_driver = {
-+ .driver = {
-+ .name = "rpi-ft5406",
-+ .owner = THIS_MODULE,
-+ .of_match_table = ft5406_match,
-+ },
-+ .probe = ft5406_probe,
-+ .remove = ft5406_remove,
-+};
-+
-+module_platform_driver(ft5406_driver);
-+
-+MODULE_AUTHOR("Gordon Hollingworth");
-+MODULE_DESCRIPTION("Touchscreen driver for memory based FT5406");
-+MODULE_LICENSE("GPL");
diff --git a/target/linux/brcm2708/patches-4.4/0080-Improve-__copy_to_user-and-__copy_from_user-performa.patch b/target/linux/brcm2708/patches-4.4/0080-Improve-__copy_to_user-and-__copy_from_user-performa.patch
deleted file mode 100644
index d09b5ae86f..0000000000
--- a/target/linux/brcm2708/patches-4.4/0080-Improve-__copy_to_user-and-__copy_from_user-performa.patch
+++ /dev/null
@@ -1,1510 +0,0 @@
-From b57a6269e03fe055f78ab50add6e2c68d43254e2 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Mon, 13 Oct 2014 11:47:53 +0100
-Subject: [PATCH 080/170] Improve __copy_to_user and __copy_from_user
- performance
-
-Provide a __copy_from_user that uses memcpy. On BCM2708, use
-optimised memcpy/memmove/memcmp/memset implementations.
-
-arch/arm: Add mmiocpy/set aliases for memcpy/set
-
-See: https://github.com/raspberrypi/linux/issues/1082
----
- arch/arm/include/asm/string.h | 5 +
- arch/arm/include/asm/uaccess.h | 3 +
- arch/arm/lib/Makefile | 15 +-
- arch/arm/lib/arm-mem.h | 159 ++++++++++++
- arch/arm/lib/copy_from_user.S | 4 +-
- arch/arm/lib/exports_rpi.c | 37 +++
- arch/arm/lib/memcmp_rpi.S | 285 +++++++++++++++++++++
- arch/arm/lib/memcpy_rpi.S | 61 +++++
- arch/arm/lib/memcpymove.h | 506 +++++++++++++++++++++++++++++++++++++
- arch/arm/lib/memmove_rpi.S | 61 +++++
- arch/arm/lib/memset_rpi.S | 123 +++++++++
- arch/arm/lib/uaccess_with_memcpy.c | 112 +++++++-
- 12 files changed, 1365 insertions(+), 6 deletions(-)
- create mode 100644 arch/arm/lib/arm-mem.h
- create mode 100644 arch/arm/lib/exports_rpi.c
- create mode 100644 arch/arm/lib/memcmp_rpi.S
- create mode 100644 arch/arm/lib/memcpy_rpi.S
- create mode 100644 arch/arm/lib/memcpymove.h
- create mode 100644 arch/arm/lib/memmove_rpi.S
- create mode 100644 arch/arm/lib/memset_rpi.S
-
---- a/arch/arm/include/asm/string.h
-+++ b/arch/arm/include/asm/string.h
-@@ -24,6 +24,11 @@ extern void * memchr(const void *, int,
- #define __HAVE_ARCH_MEMSET
- extern void * memset(void *, int, __kernel_size_t);
-
-+#ifdef CONFIG_MACH_BCM2708
-+#define __HAVE_ARCH_MEMCMP
-+extern int memcmp(const void *, const void *, size_t);
-+#endif
-+
- extern void __memzero(void *ptr, __kernel_size_t n);
-
- #define memset(p,v,n) \
---- a/arch/arm/include/asm/uaccess.h
-+++ b/arch/arm/include/asm/uaccess.h
-@@ -493,6 +493,9 @@ do { \
- extern unsigned long __must_check
- arm_copy_from_user(void *to, const void __user *from, unsigned long n);
-
-+extern unsigned long __must_check
-+__copy_from_user_std(void *to, const void __user *from, unsigned long n);
-+
- static inline unsigned long __must_check
- __copy_from_user(void *to, const void __user *from, unsigned long n)
- {
---- a/arch/arm/lib/Makefile
-+++ b/arch/arm/lib/Makefile
-@@ -6,9 +6,8 @@
-
- lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \
- csumpartialcopy.o csumpartialcopyuser.o clearbit.o \
-- delay.o delay-loop.o findbit.o memchr.o memcpy.o \
-- memmove.o memset.o memzero.o setbit.o \
-- strchr.o strrchr.o \
-+ delay.o delay-loop.o findbit.o memchr.o memzero.o \
-+ setbit.o strchr.o strrchr.o \
- testchangebit.o testclearbit.o testsetbit.o \
- ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \
- ucmpdi2.o lib1funcs.o div64.o \
-@@ -18,6 +17,16 @@ lib-y := backtrace.o changebit.o csumip
- mmu-y := clear_user.o copy_page.o getuser.o putuser.o \
- copy_from_user.o copy_to_user.o
-
-+# Choose optimised implementations for Raspberry Pi
-+ifeq ($(CONFIG_MACH_BCM2708),y)
-+ CFLAGS_uaccess_with_memcpy.o += -DCOPY_FROM_USER_THRESHOLD=1600
-+ CFLAGS_uaccess_with_memcpy.o += -DCOPY_TO_USER_THRESHOLD=672
-+ obj-$(CONFIG_MODULES) += exports_rpi.o
-+ lib-y += memcpy_rpi.o memmove_rpi.o memset_rpi.o memcmp_rpi.o
-+else
-+ lib-y += memcpy.o memmove.o memset.o
-+endif
-+
- # using lib_ here won't override already available weak symbols
- obj-$(CONFIG_UACCESS_WITH_MEMCPY) += uaccess_with_memcpy.o
-
---- /dev/null
-+++ b/arch/arm/lib/arm-mem.h
-@@ -0,0 +1,159 @@
-+/*
-+Copyright (c) 2013, Raspberry Pi Foundation
-+Copyright (c) 2013, RISC OS Open Ltd
-+All rights reserved.
-+
-+Redistribution and use in source and binary forms, with or without
-+modification, are permitted provided that the following conditions are met:
-+ * Redistributions of source code must retain the above copyright
-+ notice, this list of conditions and the following disclaimer.
-+ * Redistributions in binary form must reproduce the above copyright
-+ notice, this list of conditions and the following disclaimer in the
-+ documentation and/or other materials provided with the distribution.
-+ * Neither the name of the copyright holder nor the
-+ names of its contributors may be used to endorse or promote products
-+ derived from this software without specific prior written permission.
-+
-+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
-+*/
-+
-+.macro myfunc fname
-+ .func fname
-+ .global fname
-+fname:
-+.endm
-+
-+.macro preload_leading_step1 backwards, ptr, base
-+/* If the destination is already 16-byte aligned, then we need to preload
-+ * between 0 and prefetch_distance (inclusive) cache lines ahead so there
-+ * are no gaps when the inner loop starts.
-+ */
-+ .if backwards
-+ sub ptr, base, #1
-+ bic ptr, ptr, #31
-+ .else
-+ bic ptr, base, #31
-+ .endif
-+ .set OFFSET, 0
-+ .rept prefetch_distance+1
-+ pld [ptr, #OFFSET]
-+ .if backwards
-+ .set OFFSET, OFFSET-32
-+ .else
-+ .set OFFSET, OFFSET+32
-+ .endif
-+ .endr
-+.endm
-+
-+.macro preload_leading_step2 backwards, ptr, base, leading_bytes, tmp
-+/* However, if the destination is not 16-byte aligned, we may need to
-+ * preload one more cache line than that. The question we need to ask is:
-+ * are the leading bytes more than the amount by which the source
-+ * pointer will be rounded down for preloading, and if so, by how many
-+ * cache lines?
-+ */
-+ .if backwards
-+/* Here we compare against how many bytes we are into the
-+ * cache line, counting down from the highest such address.
-+ * Effectively, we want to calculate
-+ * leading_bytes = dst&15
-+ * cacheline_offset = 31-((src-leading_bytes-1)&31)
-+ * extra_needed = leading_bytes - cacheline_offset
-+ * and test if extra_needed is <= 0, or rearranging:
-+ * leading_bytes + (src-leading_bytes-1)&31 <= 31
-+ */
-+ mov tmp, base, lsl #32-5
-+ sbc tmp, tmp, leading_bytes, lsl #32-5
-+ adds tmp, tmp, leading_bytes, lsl #32-5
-+ bcc 61f
-+ pld [ptr, #-32*(prefetch_distance+1)]
-+ .else
-+/* Effectively, we want to calculate
-+ * leading_bytes = (-dst)&15
-+ * cacheline_offset = (src+leading_bytes)&31
-+ * extra_needed = leading_bytes - cacheline_offset
-+ * and test if extra_needed is <= 0.
-+ */
-+ mov tmp, base, lsl #32-5
-+ add tmp, tmp, leading_bytes, lsl #32-5
-+ rsbs tmp, tmp, leading_bytes, lsl #32-5
-+ bls 61f
-+ pld [ptr, #32*(prefetch_distance+1)]
-+ .endif
-+61:
-+.endm
-+
-+.macro preload_trailing backwards, base, remain, tmp
-+ /* We need either 0, 1 or 2 extra preloads */
-+ .if backwards
-+ rsb tmp, base, #0
-+ mov tmp, tmp, lsl #32-5
-+ .else
-+ mov tmp, base, lsl #32-5
-+ .endif
-+ adds tmp, tmp, remain, lsl #32-5
-+ adceqs tmp, tmp, #0
-+ /* The instruction above has two effects: ensures Z is only
-+ * set if C was clear (so Z indicates that both shifted quantities
-+ * were 0), and clears C if Z was set (so C indicates that the sum
-+ * of the shifted quantities was greater and not equal to 32) */
-+ beq 82f
-+ .if backwards
-+ sub tmp, base, #1
-+ bic tmp, tmp, #31
-+ .else
-+ bic tmp, base, #31
-+ .endif
-+ bcc 81f
-+ .if backwards
-+ pld [tmp, #-32*(prefetch_distance+1)]
-+81:
-+ pld [tmp, #-32*prefetch_distance]
-+ .else
-+ pld [tmp, #32*(prefetch_distance+2)]
-+81:
-+ pld [tmp, #32*(prefetch_distance+1)]
-+ .endif
-+82:
-+.endm
-+
-+.macro preload_all backwards, narrow_case, shift, base, remain, tmp0, tmp1
-+ .if backwards
-+ sub tmp0, base, #1
-+ bic tmp0, tmp0, #31
-+ pld [tmp0]
-+ sub tmp1, base, remain, lsl #shift
-+ .else
-+ bic tmp0, base, #31
-+ pld [tmp0]
-+ add tmp1, base, remain, lsl #shift
-+ sub tmp1, tmp1, #1
-+ .endif
-+ bic tmp1, tmp1, #31
-+ cmp tmp1, tmp0
-+ beq 92f
-+ .if narrow_case
-+ /* In this case, all the data fits in either 1 or 2 cache lines */
-+ pld [tmp1]
-+ .else
-+91:
-+ .if backwards
-+ sub tmp0, tmp0, #32
-+ .else
-+ add tmp0, tmp0, #32
-+ .endif
-+ cmp tmp0, tmp1
-+ pld [tmp0]
-+ bne 91b
-+ .endif
-+92:
-+.endm
---- a/arch/arm/lib/copy_from_user.S
-+++ b/arch/arm/lib/copy_from_user.S
-@@ -89,11 +89,13 @@
-
- .text
-
--ENTRY(arm_copy_from_user)
-+ENTRY(__copy_from_user_std)
-+WEAK(arm_copy_from_user)
-
- #include "copy_template.S"
-
- ENDPROC(arm_copy_from_user)
-+ENDPROC(__copy_from_user_std)
-
- .pushsection .fixup,"ax"
- .align 0
---- /dev/null
-+++ b/arch/arm/lib/exports_rpi.c
-@@ -0,0 +1,37 @@
-+/**
-+ * Copyright (c) 2014, Raspberry Pi (Trading) Ltd.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+
-+EXPORT_SYMBOL(memcmp);
---- /dev/null
-+++ b/arch/arm/lib/memcmp_rpi.S
-@@ -0,0 +1,285 @@
-+/*
-+Copyright (c) 2013, Raspberry Pi Foundation
-+Copyright (c) 2013, RISC OS Open Ltd
-+All rights reserved.
-+
-+Redistribution and use in source and binary forms, with or without
-+modification, are permitted provided that the following conditions are met:
-+ * Redistributions of source code must retain the above copyright
-+ notice, this list of conditions and the following disclaimer.
-+ * Redistributions in binary form must reproduce the above copyright
-+ notice, this list of conditions and the following disclaimer in the
-+ documentation and/or other materials provided with the distribution.
-+ * Neither the name of the copyright holder nor the
-+ names of its contributors may be used to endorse or promote products
-+ derived from this software without specific prior written permission.
-+
-+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
-+*/
-+
-+#include <linux/linkage.h>
-+#include "arm-mem.h"
-+
-+/* Prevent the stack from becoming executable */
-+#if defined(__linux__) && defined(__ELF__)
-+.section .note.GNU-stack,"",%progbits
-+#endif
-+
-+ .text
-+ .arch armv6
-+ .object_arch armv4
-+ .arm
-+ .altmacro
-+ .p2align 2
-+
-+.macro memcmp_process_head unaligned
-+ .if unaligned
-+ ldr DAT0, [S_1], #4
-+ ldr DAT1, [S_1], #4
-+ ldr DAT2, [S_1], #4
-+ ldr DAT3, [S_1], #4
-+ .else
-+ ldmia S_1!, {DAT0, DAT1, DAT2, DAT3}
-+ .endif
-+ ldmia S_2!, {DAT4, DAT5, DAT6, DAT7}
-+.endm
-+
-+.macro memcmp_process_tail
-+ cmp DAT0, DAT4
-+ cmpeq DAT1, DAT5
-+ cmpeq DAT2, DAT6
-+ cmpeq DAT3, DAT7
-+ bne 200f
-+.endm
-+
-+.macro memcmp_leading_31bytes
-+ movs DAT0, OFF, lsl #31
-+ ldrmib DAT0, [S_1], #1
-+ ldrcsh DAT1, [S_1], #2
-+ ldrmib DAT4, [S_2], #1
-+ ldrcsh DAT5, [S_2], #2
-+ movpl DAT0, #0
-+ movcc DAT1, #0
-+ movpl DAT4, #0
-+ movcc DAT5, #0
-+ submi N, N, #1
-+ subcs N, N, #2
-+ cmp DAT0, DAT4
-+ cmpeq DAT1, DAT5
-+ bne 200f
-+ movs DAT0, OFF, lsl #29
-+ ldrmi DAT0, [S_1], #4
-+ ldrcs DAT1, [S_1], #4
-+ ldrcs DAT2, [S_1], #4
-+ ldrmi DAT4, [S_2], #4
-+ ldmcsia S_2!, {DAT5, DAT6}
-+ movpl DAT0, #0
-+ movcc DAT1, #0
-+ movcc DAT2, #0
-+ movpl DAT4, #0
-+ movcc DAT5, #0
-+ movcc DAT6, #0
-+ submi N, N, #4
-+ subcs N, N, #8
-+ cmp DAT0, DAT4
-+ cmpeq DAT1, DAT5
-+ cmpeq DAT2, DAT6
-+ bne 200f
-+ tst OFF, #16
-+ beq 105f
-+ memcmp_process_head 1
-+ sub N, N, #16
-+ memcmp_process_tail
-+105:
-+.endm
-+
-+.macro memcmp_trailing_15bytes unaligned
-+ movs N, N, lsl #29
-+ .if unaligned
-+ ldrcs DAT0, [S_1], #4
-+ ldrcs DAT1, [S_1], #4
-+ .else
-+ ldmcsia S_1!, {DAT0, DAT1}
-+ .endif
-+ ldrmi DAT2, [S_1], #4
-+ ldmcsia S_2!, {DAT4, DAT5}
-+ ldrmi DAT6, [S_2], #4
-+ movcc DAT0, #0
-+ movcc DAT1, #0
-+ movpl DAT2, #0
-+ movcc DAT4, #0
-+ movcc DAT5, #0
-+ movpl DAT6, #0
-+ cmp DAT0, DAT4
-+ cmpeq DAT1, DAT5
-+ cmpeq DAT2, DAT6
-+ bne 200f
-+ movs N, N, lsl #2
-+ ldrcsh DAT0, [S_1], #2
-+ ldrmib DAT1, [S_1]
-+ ldrcsh DAT4, [S_2], #2
-+ ldrmib DAT5, [S_2]
-+ movcc DAT0, #0
-+ movpl DAT1, #0
-+ movcc DAT4, #0
-+ movpl DAT5, #0
-+ cmp DAT0, DAT4
-+ cmpeq DAT1, DAT5
-+ bne 200f
-+.endm
-+
-+.macro memcmp_long_inner_loop unaligned
-+110:
-+ memcmp_process_head unaligned
-+ pld [S_2, #prefetch_distance*32 + 16]
-+ memcmp_process_tail
-+ memcmp_process_head unaligned
-+ pld [S_1, OFF]
-+ memcmp_process_tail
-+ subs N, N, #32
-+ bhs 110b
-+ /* Just before the final (prefetch_distance+1) 32-byte blocks,
-+ * deal with final preloads */
-+ preload_trailing 0, S_1, N, DAT0
-+ preload_trailing 0, S_2, N, DAT0
-+ add N, N, #(prefetch_distance+2)*32 - 16
-+120:
-+ memcmp_process_head unaligned
-+ memcmp_process_tail
-+ subs N, N, #16
-+ bhs 120b
-+ /* Trailing words and bytes */
-+ tst N, #15
-+ beq 199f
-+ memcmp_trailing_15bytes unaligned
-+199: /* Reached end without detecting a difference */
-+ mov a1, #0
-+ setend le
-+ pop {DAT1-DAT6, pc}
-+.endm
-+
-+.macro memcmp_short_inner_loop unaligned
-+ subs N, N, #16 /* simplifies inner loop termination */
-+ blo 122f
-+120:
-+ memcmp_process_head unaligned
-+ memcmp_process_tail
-+ subs N, N, #16
-+ bhs 120b
-+122: /* Trailing words and bytes */
-+ tst N, #15
-+ beq 199f
-+ memcmp_trailing_15bytes unaligned
-+199: /* Reached end without detecting a difference */
-+ mov a1, #0
-+ setend le
-+ pop {DAT1-DAT6, pc}
-+.endm
-+
-+/*
-+ * int memcmp(const void *s1, const void *s2, size_t n);
-+ * On entry:
-+ * a1 = pointer to buffer 1
-+ * a2 = pointer to buffer 2
-+ * a3 = number of bytes to compare (as unsigned chars)
-+ * On exit:
-+ * a1 = >0/=0/<0 if s1 >/=/< s2
-+ */
-+
-+.set prefetch_distance, 2
-+
-+ENTRY(memcmp)
-+ S_1 .req a1
-+ S_2 .req a2
-+ N .req a3
-+ DAT0 .req a4
-+ DAT1 .req v1
-+ DAT2 .req v2
-+ DAT3 .req v3
-+ DAT4 .req v4
-+ DAT5 .req v5
-+ DAT6 .req v6
-+ DAT7 .req ip
-+ OFF .req lr
-+
-+ push {DAT1-DAT6, lr}
-+ setend be /* lowest-addressed bytes are most significant */
-+
-+ /* To preload ahead as we go, we need at least (prefetch_distance+2) 32-byte blocks */
-+ cmp N, #(prefetch_distance+3)*32 - 1
-+ blo 170f
-+
-+ /* Long case */
-+ /* Adjust N so that the decrement instruction can also test for
-+ * inner loop termination. We want it to stop when there are
-+ * (prefetch_distance+1) complete blocks to go. */
-+ sub N, N, #(prefetch_distance+2)*32
-+ preload_leading_step1 0, DAT0, S_1
-+ preload_leading_step1 0, DAT1, S_2
-+ tst S_2, #31
-+ beq 154f
-+ rsb OFF, S_2, #0 /* no need to AND with 15 here */
-+ preload_leading_step2 0, DAT0, S_1, OFF, DAT2
-+ preload_leading_step2 0, DAT1, S_2, OFF, DAT2
-+ memcmp_leading_31bytes
-+154: /* Second source now cacheline (32-byte) aligned; we have at
-+ * least one prefetch to go. */
-+ /* Prefetch offset is best selected such that it lies in the
-+ * first 8 of each 32 bytes - but it's just as easy to aim for
-+ * the first one */
-+ and OFF, S_1, #31
-+ rsb OFF, OFF, #32*prefetch_distance
-+ tst S_1, #3
-+ bne 140f
-+ memcmp_long_inner_loop 0
-+140: memcmp_long_inner_loop 1
-+
-+170: /* Short case */
-+ teq N, #0
-+ beq 199f
-+ preload_all 0, 0, 0, S_1, N, DAT0, DAT1
-+ preload_all 0, 0, 0, S_2, N, DAT0, DAT1
-+ tst S_2, #3
-+ beq 174f
-+172: subs N, N, #1
-+ blo 199f
-+ ldrb DAT0, [S_1], #1
-+ ldrb DAT4, [S_2], #1
-+ cmp DAT0, DAT4
-+ bne 200f
-+ tst S_2, #3
-+ bne 172b
-+174: /* Second source now 4-byte aligned; we have 0 or more bytes to go */
-+ tst S_1, #3
-+ bne 140f
-+ memcmp_short_inner_loop 0
-+140: memcmp_short_inner_loop 1
-+
-+200: /* Difference found: determine sign. */
-+ movhi a1, #1
-+ movlo a1, #-1
-+ setend le
-+ pop {DAT1-DAT6, pc}
-+
-+ .unreq S_1
-+ .unreq S_2
-+ .unreq N
-+ .unreq DAT0
-+ .unreq DAT1
-+ .unreq DAT2
-+ .unreq DAT3
-+ .unreq DAT4
-+ .unreq DAT5
-+ .unreq DAT6
-+ .unreq DAT7
-+ .unreq OFF
-+ENDPROC(memcmp)
---- /dev/null
-+++ b/arch/arm/lib/memcpy_rpi.S
-@@ -0,0 +1,61 @@
-+/*
-+Copyright (c) 2013, Raspberry Pi Foundation
-+Copyright (c) 2013, RISC OS Open Ltd
-+All rights reserved.
-+
-+Redistribution and use in source and binary forms, with or without
-+modification, are permitted provided that the following conditions are met:
-+ * Redistributions of source code must retain the above copyright
-+ notice, this list of conditions and the following disclaimer.
-+ * Redistributions in binary form must reproduce the above copyright
-+ notice, this list of conditions and the following disclaimer in the
-+ documentation and/or other materials provided with the distribution.
-+ * Neither the name of the copyright holder nor the
-+ names of its contributors may be used to endorse or promote products
-+ derived from this software without specific prior written permission.
-+
-+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
-+*/
-+
-+#include <linux/linkage.h>
-+#include "arm-mem.h"
-+#include "memcpymove.h"
-+
-+/* Prevent the stack from becoming executable */
-+#if defined(__linux__) && defined(__ELF__)
-+.section .note.GNU-stack,"",%progbits
-+#endif
-+
-+ .text
-+ .arch armv6
-+ .object_arch armv4
-+ .arm
-+ .altmacro
-+ .p2align 2
-+
-+/*
-+ * void *memcpy(void * restrict s1, const void * restrict s2, size_t n);
-+ * On entry:
-+ * a1 = pointer to destination
-+ * a2 = pointer to source
-+ * a3 = number of bytes to copy
-+ * On exit:
-+ * a1 preserved
-+ */
-+
-+.set prefetch_distance, 3
-+
-+ENTRY(mmiocpy)
-+ENTRY(memcpy)
-+ memcpy 0
-+ENDPROC(memcpy)
-+ENDPROC(mmiocpy)
---- /dev/null
-+++ b/arch/arm/lib/memcpymove.h
-@@ -0,0 +1,506 @@
-+/*
-+Copyright (c) 2013, Raspberry Pi Foundation
-+Copyright (c) 2013, RISC OS Open Ltd
-+All rights reserved.
-+
-+Redistribution and use in source and binary forms, with or without
-+modification, are permitted provided that the following conditions are met:
-+ * Redistributions of source code must retain the above copyright
-+ notice, this list of conditions and the following disclaimer.
-+ * Redistributions in binary form must reproduce the above copyright
-+ notice, this list of conditions and the following disclaimer in the
-+ documentation and/or other materials provided with the distribution.
-+ * Neither the name of the copyright holder nor the
-+ names of its contributors may be used to endorse or promote products
-+ derived from this software without specific prior written permission.
-+
-+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
-+*/
-+
-+.macro unaligned_words backwards, align, use_pld, words, r0, r1, r2, r3, r4, r5, r6, r7, r8
-+ .if words == 1
-+ .if backwards
-+ mov r1, r0, lsl #32-align*8
-+ ldr r0, [S, #-4]!
-+ orr r1, r1, r0, lsr #align*8
-+ str r1, [D, #-4]!
-+ .else
-+ mov r0, r1, lsr #align*8
-+ ldr r1, [S, #4]!
-+ orr r0, r0, r1, lsl #32-align*8
-+ str r0, [D], #4
-+ .endif
-+ .elseif words == 2
-+ .if backwards
-+ ldr r1, [S, #-4]!
-+ mov r2, r0, lsl #32-align*8
-+ ldr r0, [S, #-4]!
-+ orr r2, r2, r1, lsr #align*8
-+ mov r1, r1, lsl #32-align*8
-+ orr r1, r1, r0, lsr #align*8
-+ stmdb D!, {r1, r2}
-+ .else
-+ ldr r1, [S, #4]!
-+ mov r0, r2, lsr #align*8
-+ ldr r2, [S, #4]!
-+ orr r0, r0, r1, lsl #32-align*8
-+ mov r1, r1, lsr #align*8
-+ orr r1, r1, r2, lsl #32-align*8
-+ stmia D!, {r0, r1}
-+ .endif
-+ .elseif words == 4
-+ .if backwards
-+ ldmdb S!, {r2, r3}
-+ mov r4, r0, lsl #32-align*8
-+ ldmdb S!, {r0, r1}
-+ orr r4, r4, r3, lsr #align*8
-+ mov r3, r3, lsl #32-align*8
-+ orr r3, r3, r2, lsr #align*8
-+ mov r2, r2, lsl #32-align*8
-+ orr r2, r2, r1, lsr #align*8
-+ mov r1, r1, lsl #32-align*8
-+ orr r1, r1, r0, lsr #align*8
-+ stmdb D!, {r1, r2, r3, r4}
-+ .else
-+ ldmib S!, {r1, r2}
-+ mov r0, r4, lsr #align*8
-+ ldmib S!, {r3, r4}
-+ orr r0, r0, r1, lsl #32-align*8
-+ mov r1, r1, lsr #align*8
-+ orr r1, r1, r2, lsl #32-align*8
-+ mov r2, r2, lsr #align*8
-+ orr r2, r2, r3, lsl #32-align*8
-+ mov r3, r3, lsr #align*8
-+ orr r3, r3, r4, lsl #32-align*8
-+ stmia D!, {r0, r1, r2, r3}
-+ .endif
-+ .elseif words == 8
-+ .if backwards
-+ ldmdb S!, {r4, r5, r6, r7}
-+ mov r8, r0, lsl #32-align*8
-+ ldmdb S!, {r0, r1, r2, r3}
-+ .if use_pld
-+ pld [S, OFF]
-+ .endif
-+ orr r8, r8, r7, lsr #align*8
-+ mov r7, r7, lsl #32-align*8
-+ orr r7, r7, r6, lsr #align*8
-+ mov r6, r6, lsl #32-align*8
-+ orr r6, r6, r5, lsr #align*8
-+ mov r5, r5, lsl #32-align*8
-+ orr r5, r5, r4, lsr #align*8
-+ mov r4, r4, lsl #32-align*8
-+ orr r4, r4, r3, lsr #align*8
-+ mov r3, r3, lsl #32-align*8
-+ orr r3, r3, r2, lsr #align*8
-+ mov r2, r2, lsl #32-align*8
-+ orr r2, r2, r1, lsr #align*8
-+ mov r1, r1, lsl #32-align*8
-+ orr r1, r1, r0, lsr #align*8
-+ stmdb D!, {r5, r6, r7, r8}
-+ stmdb D!, {r1, r2, r3, r4}
-+ .else
-+ ldmib S!, {r1, r2, r3, r4}
-+ mov r0, r8, lsr #align*8
-+ ldmib S!, {r5, r6, r7, r8}
-+ .if use_pld
-+ pld [S, OFF]
-+ .endif
-+ orr r0, r0, r1, lsl #32-align*8
-+ mov r1, r1, lsr #align*8
-+ orr r1, r1, r2, lsl #32-align*8
-+ mov r2, r2, lsr #align*8
-+ orr r2, r2, r3, lsl #32-align*8
-+ mov r3, r3, lsr #align*8
-+ orr r3, r3, r4, lsl #32-align*8
-+ mov r4, r4, lsr #align*8
-+ orr r4, r4, r5, lsl #32-align*8
-+ mov r5, r5, lsr #align*8
-+ orr r5, r5, r6, lsl #32-align*8
-+ mov r6, r6, lsr #align*8
-+ orr r6, r6, r7, lsl #32-align*8
-+ mov r7, r7, lsr #align*8
-+ orr r7, r7, r8, lsl #32-align*8
-+ stmia D!, {r0, r1, r2, r3}
-+ stmia D!, {r4, r5, r6, r7}
-+ .endif
-+ .endif
-+.endm
-+
-+.macro memcpy_leading_15bytes backwards, align
-+ movs DAT1, DAT2, lsl #31
-+ sub N, N, DAT2
-+ .if backwards
-+ ldrmib DAT0, [S, #-1]!
-+ ldrcsh DAT1, [S, #-2]!
-+ strmib DAT0, [D, #-1]!
-+ strcsh DAT1, [D, #-2]!
-+ .else
-+ ldrmib DAT0, [S], #1
-+ ldrcsh DAT1, [S], #2
-+ strmib DAT0, [D], #1
-+ strcsh DAT1, [D], #2
-+ .endif
-+ movs DAT1, DAT2, lsl #29
-+ .if backwards
-+ ldrmi DAT0, [S, #-4]!
-+ .if align == 0
-+ ldmcsdb S!, {DAT1, DAT2}
-+ .else
-+ ldrcs DAT2, [S, #-4]!
-+ ldrcs DAT1, [S, #-4]!
-+ .endif
-+ strmi DAT0, [D, #-4]!
-+ stmcsdb D!, {DAT1, DAT2}
-+ .else
-+ ldrmi DAT0, [S], #4
-+ .if align == 0
-+ ldmcsia S!, {DAT1, DAT2}
-+ .else
-+ ldrcs DAT1, [S], #4
-+ ldrcs DAT2, [S], #4
-+ .endif
-+ strmi DAT0, [D], #4
-+ stmcsia D!, {DAT1, DAT2}
-+ .endif
-+.endm
-+
-+.macro memcpy_trailing_15bytes backwards, align
-+ movs N, N, lsl #29
-+ .if backwards
-+ .if align == 0
-+ ldmcsdb S!, {DAT0, DAT1}
-+ .else
-+ ldrcs DAT1, [S, #-4]!
-+ ldrcs DAT0, [S, #-4]!
-+ .endif
-+ ldrmi DAT2, [S, #-4]!
-+ stmcsdb D!, {DAT0, DAT1}
-+ strmi DAT2, [D, #-4]!
-+ .else
-+ .if align == 0
-+ ldmcsia S!, {DAT0, DAT1}
-+ .else
-+ ldrcs DAT0, [S], #4
-+ ldrcs DAT1, [S], #4
-+ .endif
-+ ldrmi DAT2, [S], #4
-+ stmcsia D!, {DAT0, DAT1}
-+ strmi DAT2, [D], #4
-+ .endif
-+ movs N, N, lsl #2
-+ .if backwards
-+ ldrcsh DAT0, [S, #-2]!
-+ ldrmib DAT1, [S, #-1]
-+ strcsh DAT0, [D, #-2]!
-+ strmib DAT1, [D, #-1]
-+ .else
-+ ldrcsh DAT0, [S], #2
-+ ldrmib DAT1, [S]
-+ strcsh DAT0, [D], #2
-+ strmib DAT1, [D]
-+ .endif
-+.endm
-+
-+.macro memcpy_long_inner_loop backwards, align
-+ .if align != 0
-+ .if backwards
-+ ldr DAT0, [S, #-align]!
-+ .else
-+ ldr LAST, [S, #-align]!
-+ .endif
-+ .endif
-+110:
-+ .if align == 0
-+ .if backwards
-+ ldmdb S!, {DAT0, DAT1, DAT2, DAT3, DAT4, DAT5, DAT6, LAST}
-+ pld [S, OFF]
-+ stmdb D!, {DAT4, DAT5, DAT6, LAST}
-+ stmdb D!, {DAT0, DAT1, DAT2, DAT3}
-+ .else
-+ ldmia S!, {DAT0, DAT1, DAT2, DAT3, DAT4, DAT5, DAT6, LAST}
-+ pld [S, OFF]
-+ stmia D!, {DAT0, DAT1, DAT2, DAT3}
-+ stmia D!, {DAT4, DAT5, DAT6, LAST}
-+ .endif
-+ .else
-+ unaligned_words backwards, align, 1, 8, DAT0, DAT1, DAT2, DAT3, DAT4, DAT5, DAT6, DAT7, LAST
-+ .endif
-+ subs N, N, #32
-+ bhs 110b
-+ /* Just before the final (prefetch_distance+1) 32-byte blocks, deal with final preloads */
-+ preload_trailing backwards, S, N, OFF
-+ add N, N, #(prefetch_distance+2)*32 - 32
-+120:
-+ .if align == 0
-+ .if backwards
-+ ldmdb S!, {DAT0, DAT1, DAT2, DAT3, DAT4, DAT5, DAT6, LAST}
-+ stmdb D!, {DAT4, DAT5, DAT6, LAST}
-+ stmdb D!, {DAT0, DAT1, DAT2, DAT3}
-+ .else
-+ ldmia S!, {DAT0, DAT1, DAT2, DAT3, DAT4, DAT5, DAT6, LAST}
-+ stmia D!, {DAT0, DAT1, DAT2, DAT3}
-+ stmia D!, {DAT4, DAT5, DAT6, LAST}
-+ .endif
-+ .else
-+ unaligned_words backwards, align, 0, 8, DAT0, DAT1, DAT2, DAT3, DAT4, DAT5, DAT6, DAT7, LAST
-+ .endif
-+ subs N, N, #32
-+ bhs 120b
-+ tst N, #16
-+ .if align == 0
-+ .if backwards
-+ ldmnedb S!, {DAT0, DAT1, DAT2, LAST}
-+ stmnedb D!, {DAT0, DAT1, DAT2, LAST}
-+ .else
-+ ldmneia S!, {DAT0, DAT1, DAT2, LAST}
-+ stmneia D!, {DAT0, DAT1, DAT2, LAST}
-+ .endif
-+ .else
-+ beq 130f
-+ unaligned_words backwards, align, 0, 4, DAT0, DAT1, DAT2, DAT3, LAST
-+130:
-+ .endif
-+ /* Trailing words and bytes */
-+ tst N, #15
-+ beq 199f
-+ .if align != 0
-+ add S, S, #align
-+ .endif
-+ memcpy_trailing_15bytes backwards, align
-+199:
-+ pop {DAT3, DAT4, DAT5, DAT6, DAT7}
-+ pop {D, DAT1, DAT2, pc}
-+.endm
-+
-+.macro memcpy_medium_inner_loop backwards, align
-+120:
-+ .if backwards
-+ .if align == 0
-+ ldmdb S!, {DAT0, DAT1, DAT2, LAST}
-+ .else
-+ ldr LAST, [S, #-4]!
-+ ldr DAT2, [S, #-4]!
-+ ldr DAT1, [S, #-4]!
-+ ldr DAT0, [S, #-4]!
-+ .endif
-+ stmdb D!, {DAT0, DAT1, DAT2, LAST}
-+ .else
-+ .if align == 0
-+ ldmia S!, {DAT0, DAT1, DAT2, LAST}
-+ .else
-+ ldr DAT0, [S], #4
-+ ldr DAT1, [S], #4
-+ ldr DAT2, [S], #4
-+ ldr LAST, [S], #4
-+ .endif
-+ stmia D!, {DAT0, DAT1, DAT2, LAST}
-+ .endif
-+ subs N, N, #16
-+ bhs 120b
-+ /* Trailing words and bytes */
-+ tst N, #15
-+ beq 199f
-+ memcpy_trailing_15bytes backwards, align
-+199:
-+ pop {D, DAT1, DAT2, pc}
-+.endm
-+
-+.macro memcpy_short_inner_loop backwards, align
-+ tst N, #16
-+ .if backwards
-+ .if align == 0
-+ ldmnedb S!, {DAT0, DAT1, DAT2, LAST}
-+ .else
-+ ldrne LAST, [S, #-4]!
-+ ldrne DAT2, [S, #-4]!
-+ ldrne DAT1, [S, #-4]!
-+ ldrne DAT0, [S, #-4]!
-+ .endif
-+ stmnedb D!, {DAT0, DAT1, DAT2, LAST}
-+ .else
-+ .if align == 0
-+ ldmneia S!, {DAT0, DAT1, DAT2, LAST}
-+ .else
-+ ldrne DAT0, [S], #4
-+ ldrne DAT1, [S], #4
-+ ldrne DAT2, [S], #4
-+ ldrne LAST, [S], #4
-+ .endif
-+ stmneia D!, {DAT0, DAT1, DAT2, LAST}
-+ .endif
-+ memcpy_trailing_15bytes backwards, align
-+199:
-+ pop {D, DAT1, DAT2, pc}
-+.endm
-+
-+.macro memcpy backwards
-+ D .req a1
-+ S .req a2
-+ N .req a3
-+ DAT0 .req a4
-+ DAT1 .req v1
-+ DAT2 .req v2
-+ DAT3 .req v3
-+ DAT4 .req v4
-+ DAT5 .req v5
-+ DAT6 .req v6
-+ DAT7 .req sl
-+ LAST .req ip
-+ OFF .req lr
-+
-+ .cfi_startproc
-+
-+ push {D, DAT1, DAT2, lr}
-+
-+ .cfi_def_cfa_offset 16
-+ .cfi_rel_offset D, 0
-+ .cfi_undefined S
-+ .cfi_undefined N
-+ .cfi_undefined DAT0
-+ .cfi_rel_offset DAT1, 4
-+ .cfi_rel_offset DAT2, 8
-+ .cfi_undefined LAST
-+ .cfi_rel_offset lr, 12
-+
-+ .if backwards
-+ add D, D, N
-+ add S, S, N
-+ .endif
-+
-+ /* See if we're guaranteed to have at least one 16-byte aligned 16-byte write */
-+ cmp N, #31
-+ blo 170f
-+ /* To preload ahead as we go, we need at least (prefetch_distance+2) 32-byte blocks */
-+ cmp N, #(prefetch_distance+3)*32 - 1
-+ blo 160f
-+
-+ /* Long case */
-+ push {DAT3, DAT4, DAT5, DAT6, DAT7}
-+
-+ .cfi_def_cfa_offset 36
-+ .cfi_rel_offset D, 20
-+ .cfi_rel_offset DAT1, 24
-+ .cfi_rel_offset DAT2, 28
-+ .cfi_rel_offset DAT3, 0
-+ .cfi_rel_offset DAT4, 4
-+ .cfi_rel_offset DAT5, 8
-+ .cfi_rel_offset DAT6, 12
-+ .cfi_rel_offset DAT7, 16
-+ .cfi_rel_offset lr, 32
-+
-+ /* Adjust N so that the decrement instruction can also test for
-+ * inner loop termination. We want it to stop when there are
-+ * (prefetch_distance+1) complete blocks to go. */
-+ sub N, N, #(prefetch_distance+2)*32
-+ preload_leading_step1 backwards, DAT0, S
-+ .if backwards
-+ /* Bug in GAS: it accepts, but mis-assembles the instruction
-+ * ands DAT2, D, #60, 2
-+ * which sets DAT2 to the number of leading bytes until destination is aligned and also clears C (sets borrow)
-+ */
-+ .word 0xE210513C
-+ beq 154f
-+ .else
-+ ands DAT2, D, #15
-+ beq 154f
-+ rsb DAT2, DAT2, #16 /* number of leading bytes until destination aligned */
-+ .endif
-+ preload_leading_step2 backwards, DAT0, S, DAT2, OFF
-+ memcpy_leading_15bytes backwards, 1
-+154: /* Destination now 16-byte aligned; we have at least one prefetch as well as at least one 16-byte output block */
-+ /* Prefetch offset is best selected such that it lies in the first 8 of each 32 bytes - but it's just as easy to aim for the first one */
-+ .if backwards
-+ rsb OFF, S, #3
-+ and OFF, OFF, #28
-+ sub OFF, OFF, #32*(prefetch_distance+1)
-+ .else
-+ and OFF, S, #28
-+ rsb OFF, OFF, #32*prefetch_distance
-+ .endif
-+ movs DAT0, S, lsl #31
-+ bhi 157f
-+ bcs 156f
-+ bmi 155f
-+ memcpy_long_inner_loop backwards, 0
-+155: memcpy_long_inner_loop backwards, 1
-+156: memcpy_long_inner_loop backwards, 2
-+157: memcpy_long_inner_loop backwards, 3
-+
-+ .cfi_def_cfa_offset 16
-+ .cfi_rel_offset D, 0
-+ .cfi_rel_offset DAT1, 4
-+ .cfi_rel_offset DAT2, 8
-+ .cfi_same_value DAT3
-+ .cfi_same_value DAT4
-+ .cfi_same_value DAT5
-+ .cfi_same_value DAT6
-+ .cfi_same_value DAT7
-+ .cfi_rel_offset lr, 12
-+
-+160: /* Medium case */
-+ preload_all backwards, 0, 0, S, N, DAT2, OFF
-+ sub N, N, #16 /* simplifies inner loop termination */
-+ .if backwards
-+ ands DAT2, D, #15
-+ beq 164f
-+ .else
-+ ands DAT2, D, #15
-+ beq 164f
-+ rsb DAT2, DAT2, #16
-+ .endif
-+ memcpy_leading_15bytes backwards, align
-+164: /* Destination now 16-byte aligned; we have at least one 16-byte output block */
-+ tst S, #3
-+ bne 140f
-+ memcpy_medium_inner_loop backwards, 0
-+140: memcpy_medium_inner_loop backwards, 1
-+
-+170: /* Short case, less than 31 bytes, so no guarantee of at least one 16-byte block */
-+ teq N, #0
-+ beq 199f
-+ preload_all backwards, 1, 0, S, N, DAT2, LAST
-+ tst D, #3
-+ beq 174f
-+172: subs N, N, #1
-+ blo 199f
-+ .if backwards
-+ ldrb DAT0, [S, #-1]!
-+ strb DAT0, [D, #-1]!
-+ .else
-+ ldrb DAT0, [S], #1
-+ strb DAT0, [D], #1
-+ .endif
-+ tst D, #3
-+ bne 172b
-+174: /* Destination now 4-byte aligned; we have 0 or more output bytes to go */
-+ tst S, #3
-+ bne 140f
-+ memcpy_short_inner_loop backwards, 0
-+140: memcpy_short_inner_loop backwards, 1
-+
-+ .cfi_endproc
-+
-+ .unreq D
-+ .unreq S
-+ .unreq N
-+ .unreq DAT0
-+ .unreq DAT1
-+ .unreq DAT2
-+ .unreq DAT3
-+ .unreq DAT4
-+ .unreq DAT5
-+ .unreq DAT6
-+ .unreq DAT7
-+ .unreq LAST
-+ .unreq OFF
-+.endm
---- /dev/null
-+++ b/arch/arm/lib/memmove_rpi.S
-@@ -0,0 +1,61 @@
-+/*
-+Copyright (c) 2013, Raspberry Pi Foundation
-+Copyright (c) 2013, RISC OS Open Ltd
-+All rights reserved.
-+
-+Redistribution and use in source and binary forms, with or without
-+modification, are permitted provided that the following conditions are met:
-+ * Redistributions of source code must retain the above copyright
-+ notice, this list of conditions and the following disclaimer.
-+ * Redistributions in binary form must reproduce the above copyright
-+ notice, this list of conditions and the following disclaimer in the
-+ documentation and/or other materials provided with the distribution.
-+ * Neither the name of the copyright holder nor the
-+ names of its contributors may be used to endorse or promote products
-+ derived from this software without specific prior written permission.
-+
-+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
-+*/
-+
-+#include <linux/linkage.h>
-+#include "arm-mem.h"
-+#include "memcpymove.h"
-+
-+/* Prevent the stack from becoming executable */
-+#if defined(__linux__) && defined(__ELF__)
-+.section .note.GNU-stack,"",%progbits
-+#endif
-+
-+ .text
-+ .arch armv6
-+ .object_arch armv4
-+ .arm
-+ .altmacro
-+ .p2align 2
-+
-+/*
-+ * void *memmove(void *s1, const void *s2, size_t n);
-+ * On entry:
-+ * a1 = pointer to destination
-+ * a2 = pointer to source
-+ * a3 = number of bytes to copy
-+ * On exit:
-+ * a1 preserved
-+ */
-+
-+.set prefetch_distance, 3
-+
-+ENTRY(memmove)
-+ cmp a2, a1
-+ bpl memcpy /* pl works even over -1 - 0 and 0x7fffffff - 0x80000000 boundaries */
-+ memcpy 1
-+ENDPROC(memmove)
---- /dev/null
-+++ b/arch/arm/lib/memset_rpi.S
-@@ -0,0 +1,123 @@
-+/*
-+Copyright (c) 2013, Raspberry Pi Foundation
-+Copyright (c) 2013, RISC OS Open Ltd
-+All rights reserved.
-+
-+Redistribution and use in source and binary forms, with or without
-+modification, are permitted provided that the following conditions are met:
-+ * Redistributions of source code must retain the above copyright
-+ notice, this list of conditions and the following disclaimer.
-+ * Redistributions in binary form must reproduce the above copyright
-+ notice, this list of conditions and the following disclaimer in the
-+ documentation and/or other materials provided with the distribution.
-+ * Neither the name of the copyright holder nor the
-+ names of its contributors may be used to endorse or promote products
-+ derived from this software without specific prior written permission.
-+
-+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
-+*/
-+
-+#include <linux/linkage.h>
-+#include "arm-mem.h"
-+
-+/* Prevent the stack from becoming executable */
-+#if defined(__linux__) && defined(__ELF__)
-+.section .note.GNU-stack,"",%progbits
-+#endif
-+
-+ .text
-+ .arch armv6
-+ .object_arch armv4
-+ .arm
-+ .altmacro
-+ .p2align 2
-+
-+/*
-+ * void *memset(void *s, int c, size_t n);
-+ * On entry:
-+ * a1 = pointer to buffer to fill
-+ * a2 = byte pattern to fill with (caller-narrowed)
-+ * a3 = number of bytes to fill
-+ * On exit:
-+ * a1 preserved
-+ */
-+ENTRY(mmioset)
-+ENTRY(memset)
-+ S .req a1
-+ DAT0 .req a2
-+ N .req a3
-+ DAT1 .req a4
-+ DAT2 .req ip
-+ DAT3 .req lr
-+
-+ orr DAT0, DAT0, lsl #8
-+ push {S, lr}
-+ orr DAT0, DAT0, lsl #16
-+ mov DAT1, DAT0
-+
-+ /* See if we're guaranteed to have at least one 16-byte aligned 16-byte write */
-+ cmp N, #31
-+ blo 170f
-+
-+161: sub N, N, #16 /* simplifies inner loop termination */
-+ /* Leading words and bytes */
-+ tst S, #15
-+ beq 164f
-+ rsb DAT3, S, #0 /* bits 0-3 = number of leading bytes until aligned */
-+ movs DAT2, DAT3, lsl #31
-+ submi N, N, #1
-+ strmib DAT0, [S], #1
-+ subcs N, N, #2
-+ strcsh DAT0, [S], #2
-+ movs DAT2, DAT3, lsl #29
-+ submi N, N, #4
-+ strmi DAT0, [S], #4
-+ subcs N, N, #8
-+ stmcsia S!, {DAT0, DAT1}
-+164: /* Delayed set up of DAT2 and DAT3 so we could use them as scratch registers above */
-+ mov DAT2, DAT0
-+ mov DAT3, DAT0
-+ /* Now the inner loop of 16-byte stores */
-+165: stmia S!, {DAT0, DAT1, DAT2, DAT3}
-+ subs N, N, #16
-+ bhs 165b
-+166: /* Trailing words and bytes */
-+ movs N, N, lsl #29
-+ stmcsia S!, {DAT0, DAT1}
-+ strmi DAT0, [S], #4
-+ movs N, N, lsl #2
-+ strcsh DAT0, [S], #2
-+ strmib DAT0, [S]
-+199: pop {S, pc}
-+
-+170: /* Short case */
-+ mov DAT2, DAT0
-+ mov DAT3, DAT0
-+ tst S, #3
-+ beq 174f
-+172: subs N, N, #1
-+ blo 199b
-+ strb DAT0, [S], #1
-+ tst S, #3
-+ bne 172b
-+174: tst N, #16
-+ stmneia S!, {DAT0, DAT1, DAT2, DAT3}
-+ b 166b
-+
-+ .unreq S
-+ .unreq DAT0
-+ .unreq N
-+ .unreq DAT1
-+ .unreq DAT2
-+ .unreq DAT3
-+ENDPROC(memset)
-+ENDPROC(mmioset)
---- a/arch/arm/lib/uaccess_with_memcpy.c
-+++ b/arch/arm/lib/uaccess_with_memcpy.c
-@@ -22,6 +22,14 @@
- #include <asm/current.h>
- #include <asm/page.h>
-
-+#ifndef COPY_FROM_USER_THRESHOLD
-+#define COPY_FROM_USER_THRESHOLD 64
-+#endif
-+
-+#ifndef COPY_TO_USER_THRESHOLD
-+#define COPY_TO_USER_THRESHOLD 64
-+#endif
-+
- static int
- pin_page_for_write(const void __user *_addr, pte_t **ptep, spinlock_t **ptlp)
- {
-@@ -85,7 +93,44 @@ pin_page_for_write(const void __user *_a
- return 1;
- }
-
--static unsigned long noinline
-+static int
-+pin_page_for_read(const void __user *_addr, pte_t **ptep, spinlock_t **ptlp)
-+{
-+ unsigned long addr = (unsigned long)_addr;
-+ pgd_t *pgd;
-+ pmd_t *pmd;
-+ pte_t *pte;
-+ pud_t *pud;
-+ spinlock_t *ptl;
-+
-+ pgd = pgd_offset(current->mm, addr);
-+ if (unlikely(pgd_none(*pgd) || pgd_bad(*pgd)))
-+ {
-+ return 0;
-+ }
-+ pud = pud_offset(pgd, addr);
-+ if (unlikely(pud_none(*pud) || pud_bad(*pud)))
-+ {
-+ return 0;
-+ }
-+
-+ pmd = pmd_offset(pud, addr);
-+ if (unlikely(pmd_none(*pmd) || pmd_bad(*pmd)))
-+ return 0;
-+
-+ pte = pte_offset_map_lock(current->mm, pmd, addr, &ptl);
-+ if (unlikely(!pte_present(*pte) || !pte_young(*pte))) {
-+ pte_unmap_unlock(pte, ptl);
-+ return 0;
-+ }
-+
-+ *ptep = pte;
-+ *ptlp = ptl;
-+
-+ return 1;
-+}
-+
-+unsigned long noinline
- __copy_to_user_memcpy(void __user *to, const void *from, unsigned long n)
- {
- unsigned long ua_flags;
-@@ -138,6 +183,54 @@ out:
- return n;
- }
-
-+unsigned long noinline
-+__copy_from_user_memcpy(void *to, const void __user *from, unsigned long n)
-+{
-+ int atomic;
-+
-+ if (unlikely(segment_eq(get_fs(), KERNEL_DS))) {
-+ memcpy(to, (const void *)from, n);
-+ return 0;
-+ }
-+
-+ /* the mmap semaphore is taken only if not in an atomic context */
-+ atomic = in_atomic();
-+
-+ if (!atomic)
-+ down_read(&current->mm->mmap_sem);
-+ while (n) {
-+ pte_t *pte;
-+ spinlock_t *ptl;
-+ int tocopy;
-+
-+ while (!pin_page_for_read(from, &pte, &ptl)) {
-+ char temp;
-+ if (!atomic)
-+ up_read(&current->mm->mmap_sem);
-+ if (__get_user(temp, (char __user *)from))
-+ goto out;
-+ if (!atomic)
-+ down_read(&current->mm->mmap_sem);
-+ }
-+
-+ tocopy = (~(unsigned long)from & ~PAGE_MASK) + 1;
-+ if (tocopy > n)
-+ tocopy = n;
-+
-+ memcpy(to, (const void *)from, tocopy);
-+ to += tocopy;
-+ from += tocopy;
-+ n -= tocopy;
-+
-+ pte_unmap_unlock(pte, ptl);
-+ }
-+ if (!atomic)
-+ up_read(&current->mm->mmap_sem);
-+
-+out:
-+ return n;
-+}
-+
- unsigned long
- arm_copy_to_user(void __user *to, const void *from, unsigned long n)
- {
-@@ -148,7 +241,7 @@ arm_copy_to_user(void __user *to, const
- * With frame pointer disabled, tail call optimization kicks in
- * as well making this test almost invisible.
- */
-- if (n < 64) {
-+ if (n < COPY_TO_USER_THRESHOLD) {
- unsigned long ua_flags = uaccess_save_and_enable();
- n = __copy_to_user_std(to, from, n);
- uaccess_restore(ua_flags);
-@@ -157,6 +250,21 @@ arm_copy_to_user(void __user *to, const
- }
- return n;
- }
-+
-+unsigned long __must_check
-+arm_copy_from_user(void *to, const void __user *from, unsigned long n)
-+{
-+ /*
-+ * This test is stubbed out of the main function above to keep
-+ * the overhead for small copies low by avoiding a large
-+ * register dump on the stack just to reload them right away.
-+ * With frame pointer disabled, tail call optimization kicks in
-+ * as well making this test almost invisible.
-+ */
-+ if (n < COPY_FROM_USER_THRESHOLD)
-+ return __copy_from_user_std(to, from, n);
-+ return __copy_from_user_memcpy(to, from, n);
-+}
-
- static unsigned long noinline
- __clear_user_memset(void __user *addr, unsigned long n)
diff --git a/target/linux/brcm2708/patches-4.4/0080-gpio-poweroff-Allow-it-to-work-on-Raspberry-Pi.patch b/target/linux/brcm2708/patches-4.4/0080-gpio-poweroff-Allow-it-to-work-on-Raspberry-Pi.patch
new file mode 100644
index 0000000000..006469e68e
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0080-gpio-poweroff-Allow-it-to-work-on-Raspberry-Pi.patch
@@ -0,0 +1,35 @@
+From 5b9146b6d47d409c98832d67447a78246e203a36 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Thu, 25 Jun 2015 12:16:11 +0100
+Subject: [PATCH 080/381] gpio-poweroff: Allow it to work on Raspberry Pi
+
+The Raspberry Pi firmware manages the power-down and reboot
+process. To do this it installs a pm_power_off handler, causing
+the gpio-poweroff module to abort the probe function.
+
+This patch introduces a "force" DT property that overrides that
+behaviour, and also adds a DT overlay to enable and control it.
+
+Note that running in an active-low configuration (DT parameter
+"active_low") requires a custom dt-blob.bin and probably won't
+allow a reboot without switching off, so an external inversion
+of the trigger signal may be preferable.
+---
+ drivers/power/reset/gpio-poweroff.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/power/reset/gpio-poweroff.c
++++ b/drivers/power/reset/gpio-poweroff.c
+@@ -49,9 +49,11 @@ static int gpio_poweroff_probe(struct pl
+ {
+ bool input = false;
+ enum gpiod_flags flags;
++ bool force = false;
+
+ /* If a pm_power_off function has already been added, leave it alone */
+- if (pm_power_off != NULL) {
++ force = of_property_read_bool(pdev->dev.of_node, "force");
++ if (!force && (pm_power_off != NULL)) {
+ dev_err(&pdev->dev,
+ "%s: pm_power_off function already registered",
+ __func__);
diff --git a/target/linux/brcm2708/patches-4.4/0081-gpio-poweroff-Allow-it-to-work-on-Raspberry-Pi.patch b/target/linux/brcm2708/patches-4.4/0081-gpio-poweroff-Allow-it-to-work-on-Raspberry-Pi.patch
deleted file mode 100644
index 804813246d..0000000000
--- a/target/linux/brcm2708/patches-4.4/0081-gpio-poweroff-Allow-it-to-work-on-Raspberry-Pi.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-From 44d43099a94c8b2db818c80c67789ef5f9857b81 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Thu, 25 Jun 2015 12:16:11 +0100
-Subject: [PATCH 081/170] gpio-poweroff: Allow it to work on Raspberry Pi
-
-The Raspberry Pi firmware manages the power-down and reboot
-process. To do this it installs a pm_power_off handler, causing
-the gpio-poweroff module to abort the probe function.
-
-This patch introduces a "force" DT property that overrides that
-behaviour, and also adds a DT overlay to enable and control it.
-
-Note that running in an active-low configuration (DT parameter
-"active_low") requires a custom dt-blob.bin and probably won't
-allow a reboot without switching off, so an external inversion
-of the trigger signal may be preferable.
----
- drivers/power/reset/gpio-poweroff.c | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
---- a/drivers/power/reset/gpio-poweroff.c
-+++ b/drivers/power/reset/gpio-poweroff.c
-@@ -49,9 +49,11 @@ static int gpio_poweroff_probe(struct pl
- {
- bool input = false;
- enum gpiod_flags flags;
-+ bool force = false;
-
- /* If a pm_power_off function has already been added, leave it alone */
-- if (pm_power_off != NULL) {
-+ force = of_property_read_bool(pdev->dev.of_node, "force");
-+ if (!force && (pm_power_off != NULL)) {
- dev_err(&pdev->dev,
- "%s: pm_power_off function already registered",
- __func__);
diff --git a/target/linux/brcm2708/patches-4.4/0081-spidev-Add-spidev-compatible-string-to-silence-warni.patch b/target/linux/brcm2708/patches-4.4/0081-spidev-Add-spidev-compatible-string-to-silence-warni.patch
new file mode 100644
index 0000000000..4dc1432fcd
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0081-spidev-Add-spidev-compatible-string-to-silence-warni.patch
@@ -0,0 +1,21 @@
+From f50f0fbeb5a66ee6bd4e7bc4b911bd46fc76804c Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Tue, 14 Jul 2015 10:26:09 +0100
+Subject: [PATCH 081/381] spidev: Add "spidev" compatible string to silence
+ warning
+
+See: https://github.com/raspberrypi/linux/issues/1054
+---
+ drivers/spi/spidev.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/spi/spidev.c
++++ b/drivers/spi/spidev.c
+@@ -695,6 +695,7 @@ static struct class *spidev_class;
+ static const struct of_device_id spidev_dt_ids[] = {
+ { .compatible = "rohm,dh2228fv" },
+ { .compatible = "lineartechnology,ltc2488" },
++ { .compatible = "spidev" },
+ {},
+ };
+ MODULE_DEVICE_TABLE(of, spidev_dt_ids);
diff --git a/target/linux/brcm2708/patches-4.4/0082-scripts-dtc-Add-overlay-support.patch b/target/linux/brcm2708/patches-4.4/0082-scripts-dtc-Add-overlay-support.patch
new file mode 100644
index 0000000000..c3f6f213f6
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0082-scripts-dtc-Add-overlay-support.patch
@@ -0,0 +1,4389 @@
+From 89380bfcda436c4602001f09d1777957304e1c41 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Tue, 14 Jul 2015 17:00:18 +0100
+Subject: [PATCH 082/381] scripts/dtc: Add overlay support
+
+---
+ scripts/dtc/checks.c | 119 ++-
+ scripts/dtc/dtc-lexer.l | 5 +
+ scripts/dtc/dtc-lexer.lex.c_shipped | 490 ++++-----
+ scripts/dtc/dtc-parser.tab.c_shipped | 1896 +++++++++++++++++++---------------
+ scripts/dtc/dtc-parser.tab.h_shipped | 107 +-
+ scripts/dtc/dtc-parser.y | 23 +-
+ scripts/dtc/dtc.c | 9 +-
+ scripts/dtc/dtc.h | 38 +
+ scripts/dtc/flattree.c | 141 ++-
+ scripts/dtc/version_gen.h | 2 +-
+ 10 files changed, 1685 insertions(+), 1145 deletions(-)
+
+--- a/scripts/dtc/checks.c
++++ b/scripts/dtc/checks.c
+@@ -458,21 +458,91 @@ static void fixup_phandle_references(str
+ struct node *node, struct property *prop)
+ {
+ struct marker *m = prop->val.markers;
++ struct fixup *f, **fp;
++ struct fixup_entry *fe, **fep;
+ struct node *refnode;
+ cell_t phandle;
++ int has_phandle_refs;
++
++ has_phandle_refs = 0;
++ for_each_marker_of_type(m, REF_PHANDLE) {
++ has_phandle_refs = 1;
++ break;
++ }
++
++ if (!has_phandle_refs)
++ return;
+
+ for_each_marker_of_type(m, REF_PHANDLE) {
+ assert(m->offset + sizeof(cell_t) <= prop->val.len);
+
+ refnode = get_node_by_ref(dt, m->ref);
+- if (! refnode) {
++ if (!refnode && !symbol_fixup_support) {
+ FAIL(c, "Reference to non-existent node or label \"%s\"\n",
+- m->ref);
++ m->ref);
+ continue;
+ }
+
+- phandle = get_node_phandle(dt, refnode);
+- *((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
++ if (!refnode) {
++ /* allocate fixup entry */
++ fe = xmalloc(sizeof(*fe));
++
++ fe->node = node;
++ fe->prop = prop;
++ fe->offset = m->offset;
++ fe->next = NULL;
++
++ /* search for an already existing fixup */
++ for_each_fixup(dt, f)
++ if (strcmp(f->ref, m->ref) == 0)
++ break;
++
++ /* no fixup found, add new */
++ if (f == NULL) {
++ f = xmalloc(sizeof(*f));
++ f->ref = m->ref;
++ f->entries = NULL;
++ f->next = NULL;
++
++ /* add it to the tree */
++ fp = &dt->fixups;
++ while (*fp)
++ fp = &(*fp)->next;
++ *fp = f;
++ }
++
++ /* and now append fixup entry */
++ fep = &f->entries;
++ while (*fep)
++ fep = &(*fep)->next;
++ *fep = fe;
++
++ /* mark the entry as unresolved */
++ phandle = 0xdeadbeef;
++ } else {
++ phandle = get_node_phandle(dt, refnode);
++
++ /* if it's a plugin, we need to record it */
++ if (symbol_fixup_support && dt->is_plugin) {
++
++ /* allocate a new local fixup entry */
++ fe = xmalloc(sizeof(*fe));
++
++ fe->node = node;
++ fe->prop = prop;
++ fe->offset = m->offset;
++ fe->next = NULL;
++
++ /* append it to the local fixups */
++ fep = &dt->local_fixups;
++ while (*fep)
++ fep = &(*fep)->next;
++ *fep = fe;
++ }
++ }
++
++ *((cell_t *)(prop->val.val + m->offset)) =
++ cpu_to_fdt32(phandle);
+ }
+ }
+ ERROR(phandle_references, NULL, NULL, fixup_phandle_references, NULL,
+@@ -652,6 +722,45 @@ static void check_obsolete_chosen_interr
+ }
+ TREE_WARNING(obsolete_chosen_interrupt_controller, NULL);
+
++static void check_auto_label_phandles(struct check *c, struct node *dt,
++ struct node *node)
++{
++ struct label *l;
++ struct symbol *s, **sp;
++ int has_label;
++
++ if (!symbol_fixup_support)
++ return;
++
++ has_label = 0;
++ for_each_label(node->labels, l) {
++ has_label = 1;
++ break;
++ }
++
++ if (!has_label)
++ return;
++
++ /* force allocation of a phandle for this node */
++ (void)get_node_phandle(dt, node);
++
++ /* add the symbol */
++ for_each_label(node->labels, l) {
++
++ s = xmalloc(sizeof(*s));
++ s->label = l;
++ s->node = node;
++ s->next = NULL;
++
++ /* add it to the symbols list */
++ sp = &dt->symbols;
++ while (*sp)
++ sp = &((*sp)->next);
++ *sp = s;
++ }
++}
++NODE_WARNING(auto_label_phandles, NULL);
++
+ static struct check *check_table[] = {
+ &duplicate_node_names, &duplicate_property_names,
+ &node_name_chars, &node_name_format, &property_name_chars,
+@@ -670,6 +779,8 @@ static struct check *check_table[] = {
+ &avoid_default_addr_size,
+ &obsolete_chosen_interrupt_controller,
+
++ &auto_label_phandles,
++
+ &always_fail,
+ };
+
+--- a/scripts/dtc/dtc-lexer.l
++++ b/scripts/dtc/dtc-lexer.l
+@@ -113,6 +113,11 @@ static void lexical_error(const char *fm
+ return DT_V1;
+ }
+
++<*>"/plugin/" {
++ DPRINT("Keyword: /plugin/\n");
++ return DT_PLUGIN;
++ }
++
+ <*>"/memreserve/" {
+ DPRINT("Keyword: /memreserve/\n");
+ BEGIN_DEFAULT();
+--- a/scripts/dtc/dtc-lexer.lex.c_shipped
++++ b/scripts/dtc/dtc-lexer.lex.c_shipped
+@@ -9,7 +9,7 @@
+ #define FLEX_SCANNER
+ #define YY_FLEX_MAJOR_VERSION 2
+ #define YY_FLEX_MINOR_VERSION 5
+-#define YY_FLEX_SUBMINOR_VERSION 39
++#define YY_FLEX_SUBMINOR_VERSION 35
+ #if YY_FLEX_SUBMINOR_VERSION > 0
+ #define FLEX_BETA
+ #endif
+@@ -162,12 +162,7 @@ typedef unsigned int flex_uint32_t;
+ typedef struct yy_buffer_state *YY_BUFFER_STATE;
+ #endif
+
+-#ifndef YY_TYPEDEF_YY_SIZE_T
+-#define YY_TYPEDEF_YY_SIZE_T
+-typedef size_t yy_size_t;
+-#endif
+-
+-extern yy_size_t yyleng;
++extern int yyleng;
+
+ extern FILE *yyin, *yyout;
+
+@@ -176,7 +171,6 @@ extern FILE *yyin, *yyout;
+ #define EOB_ACT_LAST_MATCH 2
+
+ #define YY_LESS_LINENO(n)
+- #define YY_LINENO_REWIND_TO(ptr)
+
+ /* Return all but the first "n" matched characters back to the input stream. */
+ #define yyless(n) \
+@@ -194,6 +188,11 @@ extern FILE *yyin, *yyout;
+
+ #define unput(c) yyunput( c, (yytext_ptr) )
+
++#ifndef YY_TYPEDEF_YY_SIZE_T
++#define YY_TYPEDEF_YY_SIZE_T
++typedef size_t yy_size_t;
++#endif
++
+ #ifndef YY_STRUCT_YY_BUFFER_STATE
+ #define YY_STRUCT_YY_BUFFER_STATE
+ struct yy_buffer_state
+@@ -211,7 +210,7 @@ struct yy_buffer_state
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+- yy_size_t yy_n_chars;
++ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+@@ -281,8 +280,8 @@ static YY_BUFFER_STATE * yy_buffer_stack
+
+ /* yy_hold_char holds the character lost when yytext is formed. */
+ static char yy_hold_char;
+-static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */
+-yy_size_t yyleng;
++static int yy_n_chars; /* number of characters read into yy_ch_buf */
++int yyleng;
+
+ /* Points to current character in buffer. */
+ static char *yy_c_buf_p = (char *) 0;
+@@ -310,7 +309,7 @@ static void yy_init_buffer (YY_BUFFER_ST
+
+ YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size );
+ YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str );
+-YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len );
++YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len );
+
+ void *yyalloc (yy_size_t );
+ void *yyrealloc (void *,yy_size_t );
+@@ -342,7 +341,7 @@ void yyfree (void * );
+
+ /* Begin user sect3 */
+
+-#define yywrap() 1
++#define yywrap(n) 1
+ #define YY_SKIP_YYWRAP
+
+ typedef unsigned char YY_CHAR;
+@@ -373,8 +372,8 @@ static void yy_fatal_error (yyconst char
+ *yy_cp = '\0'; \
+ (yy_c_buf_p) = yy_cp;
+
+-#define YY_NUM_RULES 30
+-#define YY_END_OF_BUFFER 31
++#define YY_NUM_RULES 31
++#define YY_END_OF_BUFFER 32
+ /* This struct is not used in this scanner,
+ but its presence is necessary. */
+ struct yy_trans_info
+@@ -382,25 +381,26 @@ struct yy_trans_info
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+-static yyconst flex_int16_t yy_accept[159] =
++static yyconst flex_int16_t yy_accept[166] =
+ { 0,
+- 0, 0, 0, 0, 0, 0, 0, 0, 31, 29,
+- 18, 18, 29, 29, 29, 29, 29, 29, 29, 29,
+- 29, 29, 29, 29, 29, 29, 15, 16, 16, 29,
+- 16, 10, 10, 18, 26, 0, 3, 0, 27, 12,
+- 0, 0, 11, 0, 0, 0, 0, 0, 0, 0,
+- 21, 23, 25, 24, 22, 0, 9, 28, 0, 0,
+- 0, 14, 14, 16, 16, 16, 10, 10, 10, 0,
+- 12, 0, 11, 0, 0, 0, 20, 0, 0, 0,
+- 0, 0, 0, 0, 0, 16, 10, 10, 10, 0,
+- 13, 19, 0, 0, 0, 0, 0, 0, 0, 0,
+-
+- 0, 16, 0, 0, 0, 0, 0, 0, 0, 0,
+- 0, 16, 6, 0, 0, 0, 0, 0, 0, 2,
+- 0, 0, 0, 0, 0, 0, 0, 0, 4, 17,
+- 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
+- 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+- 5, 8, 0, 0, 0, 0, 7, 0
++ 0, 0, 0, 0, 0, 0, 0, 0, 32, 30,
++ 19, 19, 30, 30, 30, 30, 30, 30, 30, 30,
++ 30, 30, 30, 30, 30, 30, 16, 17, 17, 30,
++ 17, 11, 11, 19, 27, 0, 3, 0, 28, 13,
++ 0, 0, 12, 0, 0, 0, 0, 0, 0, 0,
++ 0, 22, 24, 26, 25, 23, 0, 10, 29, 0,
++ 0, 0, 15, 15, 17, 17, 17, 11, 11, 11,
++ 0, 13, 0, 12, 0, 0, 0, 21, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 17, 11, 11,
++ 11, 0, 14, 20, 0, 0, 0, 0, 0, 0,
++
++ 0, 0, 0, 0, 17, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 17, 7, 0, 0, 0,
++ 0, 0, 0, 0, 2, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 4, 18, 0, 0, 5, 2,
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 1, 0, 0, 0, 0, 6, 9, 0,
++ 0, 0, 0, 8, 0
+ } ;
+
+ static yyconst flex_int32_t yy_ec[256] =
+@@ -416,9 +416,9 @@ static yyconst flex_int32_t yy_ec[256] =
+ 22, 22, 22, 22, 24, 22, 22, 25, 22, 22,
+ 1, 26, 27, 1, 22, 1, 21, 28, 29, 30,
+
+- 31, 21, 22, 22, 32, 22, 22, 33, 34, 35,
+- 36, 37, 22, 38, 39, 40, 41, 42, 22, 25,
+- 43, 22, 44, 45, 46, 1, 1, 1, 1, 1,
++ 31, 21, 32, 22, 33, 22, 22, 34, 35, 36,
++ 37, 38, 22, 39, 40, 41, 42, 43, 22, 25,
++ 44, 22, 45, 46, 47, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+@@ -435,163 +435,165 @@ static yyconst flex_int32_t yy_ec[256] =
+ 1, 1, 1, 1, 1
+ } ;
+
+-static yyconst flex_int32_t yy_meta[47] =
++static yyconst flex_int32_t yy_meta[48] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 2, 3, 1, 2,
+ 2, 2, 4, 5, 5, 5, 6, 1, 1, 1,
+ 7, 8, 8, 8, 8, 1, 1, 7, 7, 7,
+ 7, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+- 8, 8, 8, 3, 1, 4
++ 8, 8, 8, 8, 3, 1, 4
+ } ;
+
+-static yyconst flex_int16_t yy_base[173] =
++static yyconst flex_int16_t yy_base[180] =
+ { 0,
+- 0, 383, 34, 382, 65, 381, 37, 105, 387, 391,
+- 54, 111, 367, 110, 109, 109, 112, 41, 366, 104,
+- 367, 338, 124, 117, 0, 144, 391, 0, 121, 0,
+- 135, 155, 140, 179, 391, 160, 391, 379, 391, 0,
+- 368, 141, 391, 167, 370, 376, 346, 103, 342, 345,
+- 391, 391, 391, 391, 391, 358, 391, 391, 175, 342,
+- 338, 391, 355, 0, 185, 339, 184, 347, 346, 0,
+- 0, 322, 175, 357, 175, 363, 352, 324, 330, 323,
+- 332, 326, 201, 324, 329, 322, 391, 333, 181, 309,
+- 391, 341, 340, 313, 320, 338, 178, 311, 146, 317,
+-
+- 314, 315, 335, 331, 303, 300, 309, 299, 308, 188,
+- 336, 335, 391, 305, 320, 281, 283, 271, 203, 288,
+- 281, 271, 266, 264, 245, 242, 208, 104, 391, 391,
+- 244, 218, 204, 219, 206, 224, 201, 212, 204, 229,
+- 215, 208, 207, 200, 219, 391, 233, 221, 200, 181,
+- 391, 391, 149, 122, 86, 41, 391, 391, 245, 251,
+- 259, 263, 267, 273, 280, 284, 292, 300, 304, 310,
+- 318, 326
++ 0, 393, 35, 392, 66, 391, 38, 107, 397, 401,
++ 55, 113, 377, 112, 111, 111, 114, 42, 376, 106,
++ 377, 347, 126, 120, 0, 147, 401, 0, 124, 0,
++ 137, 158, 170, 163, 401, 153, 401, 389, 401, 0,
++ 378, 120, 401, 131, 380, 386, 355, 139, 351, 355,
++ 351, 401, 401, 401, 401, 401, 367, 401, 401, 185,
++ 350, 346, 401, 364, 0, 185, 347, 189, 356, 355,
++ 0, 0, 330, 180, 366, 141, 372, 361, 332, 338,
++ 331, 341, 334, 326, 205, 331, 337, 329, 401, 341,
++ 167, 316, 401, 349, 348, 320, 328, 346, 180, 318,
++
++ 324, 209, 324, 320, 322, 342, 338, 309, 306, 315,
++ 305, 315, 312, 192, 342, 341, 401, 293, 306, 282,
++ 268, 252, 255, 203, 285, 282, 272, 268, 252, 233,
++ 232, 239, 208, 107, 401, 401, 238, 211, 401, 211,
++ 212, 208, 228, 203, 215, 207, 233, 222, 212, 211,
++ 203, 227, 401, 237, 225, 204, 185, 401, 401, 149,
++ 128, 88, 42, 401, 401, 253, 259, 267, 271, 275,
++ 281, 288, 292, 300, 308, 312, 318, 326, 334
+ } ;
+
+-static yyconst flex_int16_t yy_def[173] =
++static yyconst flex_int16_t yy_def[180] =
+ { 0,
+- 158, 1, 1, 3, 158, 5, 1, 1, 158, 158,
+- 158, 158, 158, 159, 160, 161, 158, 158, 158, 158,
+- 162, 158, 158, 158, 163, 162, 158, 164, 165, 164,
+- 164, 158, 158, 158, 158, 159, 158, 159, 158, 166,
+- 158, 161, 158, 161, 167, 168, 158, 158, 158, 158,
+- 158, 158, 158, 158, 158, 162, 158, 158, 158, 158,
+- 158, 158, 162, 164, 165, 164, 158, 158, 158, 169,
+- 166, 170, 161, 167, 167, 168, 158, 158, 158, 158,
+- 158, 158, 158, 158, 158, 164, 158, 158, 169, 170,
+- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+-
+- 158, 164, 158, 158, 158, 158, 158, 158, 158, 171,
+- 158, 164, 158, 158, 158, 158, 158, 158, 171, 158,
+- 171, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+- 172, 158, 158, 158, 172, 158, 172, 158, 158, 158,
+- 158, 158, 158, 158, 158, 158, 158, 0, 158, 158,
+- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+- 158, 158
++ 165, 1, 1, 3, 165, 5, 1, 1, 165, 165,
++ 165, 165, 165, 166, 167, 168, 165, 165, 165, 165,
++ 169, 165, 165, 165, 170, 169, 165, 171, 172, 171,
++ 171, 165, 165, 165, 165, 166, 165, 166, 165, 173,
++ 165, 168, 165, 168, 174, 175, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 169, 165, 165, 165,
++ 165, 165, 165, 169, 171, 172, 171, 165, 165, 165,
++ 176, 173, 177, 168, 174, 174, 175, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 171, 165, 165,
++ 176, 177, 165, 165, 165, 165, 165, 165, 165, 165,
++
++ 165, 165, 165, 165, 171, 165, 165, 165, 165, 165,
++ 165, 165, 165, 178, 165, 171, 165, 165, 165, 165,
++ 165, 165, 165, 178, 165, 178, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 179, 165, 165,
++ 165, 179, 165, 179, 165, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 0, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 165, 165
+ } ;
+
+-static yyconst flex_int16_t yy_nxt[438] =
++static yyconst flex_int16_t yy_nxt[449] =
+ { 0,
+ 10, 11, 12, 11, 13, 14, 10, 15, 16, 10,
+ 10, 10, 17, 10, 10, 10, 10, 18, 19, 20,
+ 21, 21, 21, 21, 21, 10, 10, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+- 21, 21, 21, 10, 22, 10, 24, 25, 25, 25,
+- 32, 33, 33, 157, 26, 34, 34, 34, 51, 52,
+- 27, 26, 26, 26, 26, 10, 11, 12, 11, 13,
+- 14, 28, 15, 16, 28, 28, 28, 24, 28, 28,
+- 28, 10, 18, 19, 20, 29, 29, 29, 29, 29,
+- 30, 10, 29, 29, 29, 29, 29, 29, 29, 29,
+-
+- 29, 29, 29, 29, 29, 29, 29, 29, 10, 22,
+- 10, 23, 34, 34, 34, 37, 39, 43, 32, 33,
+- 33, 45, 54, 55, 46, 59, 45, 64, 156, 46,
+- 64, 64, 64, 79, 44, 38, 59, 57, 134, 47,
+- 135, 48, 80, 49, 47, 50, 48, 99, 61, 43,
+- 50, 110, 41, 67, 67, 67, 60, 63, 63, 63,
+- 57, 155, 68, 69, 63, 37, 44, 66, 67, 67,
+- 67, 63, 63, 63, 63, 73, 59, 68, 69, 70,
+- 34, 34, 34, 43, 75, 38, 154, 92, 83, 83,
+- 83, 64, 44, 120, 64, 64, 64, 67, 67, 67,
+-
+- 44, 57, 99, 68, 69, 107, 68, 69, 120, 127,
+- 108, 153, 152, 121, 83, 83, 83, 133, 133, 133,
+- 146, 133, 133, 133, 146, 140, 140, 140, 121, 141,
+- 140, 140, 140, 151, 141, 158, 150, 149, 148, 144,
+- 147, 143, 142, 139, 147, 36, 36, 36, 36, 36,
+- 36, 36, 36, 40, 138, 137, 136, 40, 40, 42,
+- 42, 42, 42, 42, 42, 42, 42, 56, 56, 56,
+- 56, 62, 132, 62, 64, 131, 130, 64, 129, 64,
+- 64, 65, 128, 158, 65, 65, 65, 65, 71, 127,
+- 71, 71, 74, 74, 74, 74, 74, 74, 74, 74,
+-
+- 76, 76, 76, 76, 76, 76, 76, 76, 89, 126,
+- 89, 90, 125, 90, 90, 124, 90, 90, 119, 119,
+- 119, 119, 119, 119, 119, 119, 145, 145, 145, 145,
+- 145, 145, 145, 145, 123, 122, 59, 59, 118, 117,
+- 116, 115, 114, 113, 45, 112, 108, 111, 109, 106,
+- 105, 104, 46, 103, 91, 87, 102, 101, 100, 98,
+- 97, 96, 95, 94, 93, 77, 75, 91, 88, 87,
+- 86, 57, 85, 84, 57, 82, 81, 78, 77, 75,
+- 72, 158, 58, 57, 53, 35, 158, 31, 23, 23,
+- 9, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+-
+- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+- 158, 158, 158, 158, 158, 158, 158
++ 21, 21, 21, 21, 10, 22, 10, 24, 25, 25,
++ 25, 32, 33, 33, 164, 26, 34, 34, 34, 52,
++ 53, 27, 26, 26, 26, 26, 10, 11, 12, 11,
++ 13, 14, 28, 15, 16, 28, 28, 28, 24, 28,
++ 28, 28, 10, 18, 19, 20, 29, 29, 29, 29,
++ 29, 30, 10, 29, 29, 29, 29, 29, 29, 29,
++
++ 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
++ 10, 22, 10, 23, 34, 34, 34, 37, 39, 43,
++ 32, 33, 33, 45, 55, 56, 46, 60, 43, 45,
++ 65, 163, 46, 65, 65, 65, 44, 38, 60, 74,
++ 58, 47, 141, 48, 142, 44, 49, 47, 50, 48,
++ 76, 51, 62, 94, 50, 41, 44, 51, 37, 61,
++ 64, 64, 64, 58, 34, 34, 34, 64, 162, 80,
++ 67, 68, 68, 68, 64, 64, 64, 64, 38, 81,
++ 69, 70, 71, 68, 68, 68, 60, 161, 43, 69,
++ 70, 65, 69, 70, 65, 65, 65, 125, 85, 85,
++
++ 85, 58, 68, 68, 68, 44, 102, 110, 125, 133,
++ 102, 69, 70, 111, 114, 160, 159, 126, 85, 85,
++ 85, 140, 140, 140, 140, 140, 140, 153, 126, 147,
++ 147, 147, 153, 148, 147, 147, 147, 158, 148, 165,
++ 157, 156, 155, 151, 150, 149, 146, 154, 145, 144,
++ 143, 139, 154, 36, 36, 36, 36, 36, 36, 36,
++ 36, 40, 138, 137, 136, 40, 40, 42, 42, 42,
++ 42, 42, 42, 42, 42, 57, 57, 57, 57, 63,
++ 135, 63, 65, 134, 165, 65, 133, 65, 65, 66,
++ 132, 131, 66, 66, 66, 66, 72, 130, 72, 72,
++
++ 75, 75, 75, 75, 75, 75, 75, 75, 77, 77,
++ 77, 77, 77, 77, 77, 77, 91, 129, 91, 92,
++ 128, 92, 92, 127, 92, 92, 124, 124, 124, 124,
++ 124, 124, 124, 124, 152, 152, 152, 152, 152, 152,
++ 152, 152, 60, 60, 123, 122, 121, 120, 119, 118,
++ 117, 45, 116, 111, 115, 113, 112, 109, 108, 107,
++ 46, 106, 93, 89, 105, 104, 103, 101, 100, 99,
++ 98, 97, 96, 95, 78, 76, 93, 90, 89, 88,
++ 58, 87, 86, 58, 84, 83, 82, 79, 78, 76,
++ 73, 165, 59, 58, 54, 35, 165, 31, 23, 23,
++
++ 9, 165, 165, 165, 165, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 165
+ } ;
+
+-static yyconst flex_int16_t yy_chk[438] =
++static yyconst flex_int16_t yy_chk[449] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+- 1, 1, 1, 1, 1, 1, 3, 3, 3, 3,
+- 7, 7, 7, 156, 3, 11, 11, 11, 18, 18,
+- 3, 3, 3, 3, 3, 5, 5, 5, 5, 5,
++ 1, 1, 1, 1, 1, 1, 1, 3, 3, 3,
++ 3, 7, 7, 7, 163, 3, 11, 11, 11, 18,
++ 18, 3, 3, 3, 3, 3, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+- 5, 8, 12, 12, 12, 14, 15, 16, 8, 8,
+- 8, 17, 20, 20, 17, 23, 24, 29, 155, 24,
+- 29, 29, 29, 48, 16, 14, 31, 29, 128, 17,
+- 128, 17, 48, 17, 24, 17, 24, 99, 24, 42,
+- 24, 99, 15, 33, 33, 33, 23, 26, 26, 26,
+- 26, 154, 33, 33, 26, 36, 42, 31, 32, 32,
+- 32, 26, 26, 26, 26, 44, 59, 32, 32, 32,
+- 34, 34, 34, 73, 75, 36, 153, 75, 59, 59,
+- 59, 65, 44, 110, 65, 65, 65, 67, 67, 67,
+-
+- 73, 65, 83, 89, 89, 97, 67, 67, 119, 127,
+- 97, 150, 149, 110, 83, 83, 83, 133, 133, 133,
+- 141, 127, 127, 127, 145, 136, 136, 136, 119, 136,
+- 140, 140, 140, 148, 140, 147, 144, 143, 142, 139,
+- 141, 138, 137, 135, 145, 159, 159, 159, 159, 159,
+- 159, 159, 159, 160, 134, 132, 131, 160, 160, 161,
+- 161, 161, 161, 161, 161, 161, 161, 162, 162, 162,
+- 162, 163, 126, 163, 164, 125, 124, 164, 123, 164,
+- 164, 165, 122, 121, 165, 165, 165, 165, 166, 120,
+- 166, 166, 167, 167, 167, 167, 167, 167, 167, 167,
+-
+- 168, 168, 168, 168, 168, 168, 168, 168, 169, 118,
+- 169, 170, 117, 170, 170, 116, 170, 170, 171, 171,
+- 171, 171, 171, 171, 171, 171, 172, 172, 172, 172,
+- 172, 172, 172, 172, 115, 114, 112, 111, 109, 108,
+- 107, 106, 105, 104, 103, 102, 101, 100, 98, 96,
+- 95, 94, 93, 92, 90, 88, 86, 85, 84, 82,
+- 81, 80, 79, 78, 77, 76, 74, 72, 69, 68,
+- 66, 63, 61, 60, 56, 50, 49, 47, 46, 45,
++ 5, 5, 5, 8, 12, 12, 12, 14, 15, 16,
++ 8, 8, 8, 17, 20, 20, 17, 23, 42, 24,
++ 29, 162, 24, 29, 29, 29, 16, 14, 31, 44,
++ 29, 17, 134, 17, 134, 42, 17, 24, 17, 24,
++ 76, 17, 24, 76, 24, 15, 44, 24, 36, 23,
++ 26, 26, 26, 26, 34, 34, 34, 26, 161, 48,
++ 31, 32, 32, 32, 26, 26, 26, 26, 36, 48,
++ 32, 32, 32, 33, 33, 33, 60, 160, 74, 91,
++ 91, 66, 33, 33, 66, 66, 66, 114, 60, 60,
++
++ 60, 66, 68, 68, 68, 74, 85, 99, 124, 133,
++ 102, 68, 68, 99, 102, 157, 156, 114, 85, 85,
++ 85, 133, 133, 133, 140, 140, 140, 148, 124, 143,
++ 143, 143, 152, 143, 147, 147, 147, 155, 147, 154,
++ 151, 150, 149, 146, 145, 144, 142, 148, 141, 138,
++ 137, 132, 152, 166, 166, 166, 166, 166, 166, 166,
++ 166, 167, 131, 130, 129, 167, 167, 168, 168, 168,
++ 168, 168, 168, 168, 168, 169, 169, 169, 169, 170,
++ 128, 170, 171, 127, 126, 171, 125, 171, 171, 172,
++ 123, 122, 172, 172, 172, 172, 173, 121, 173, 173,
++
++ 174, 174, 174, 174, 174, 174, 174, 174, 175, 175,
++ 175, 175, 175, 175, 175, 175, 176, 120, 176, 177,
++ 119, 177, 177, 118, 177, 177, 178, 178, 178, 178,
++ 178, 178, 178, 178, 179, 179, 179, 179, 179, 179,
++ 179, 179, 116, 115, 113, 112, 111, 110, 109, 108,
++ 107, 106, 105, 104, 103, 101, 100, 98, 97, 96,
++ 95, 94, 92, 90, 88, 87, 86, 84, 83, 82,
++ 81, 80, 79, 78, 77, 75, 73, 70, 69, 67,
++ 64, 62, 61, 57, 51, 50, 49, 47, 46, 45,
+ 41, 38, 22, 21, 19, 13, 9, 6, 4, 2,
+- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+
+- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+- 158, 158, 158, 158, 158, 158, 158
++ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 165
+ } ;
+
+ static yy_state_type yy_last_accepting_state;
+@@ -662,7 +664,7 @@ static int dts_version = 1;
+ static void push_input_file(const char *filename);
+ static bool pop_input_file(void);
+ static void lexical_error(const char *fmt, ...);
+-#line 666 "dtc-lexer.lex.c"
++#line 668 "dtc-lexer.lex.c"
+
+ #define INITIAL 0
+ #define BYTESTRING 1
+@@ -704,7 +706,7 @@ FILE *yyget_out (void );
+
+ void yyset_out (FILE * out_str );
+
+-yy_size_t yyget_leng (void );
++int yyget_leng (void );
+
+ char *yyget_text (void );
+
+@@ -853,6 +855,10 @@ YY_DECL
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
++#line 68 "dtc-lexer.l"
++
++#line 861 "dtc-lexer.lex.c"
++
+ if ( !(yy_init) )
+ {
+ (yy_init) = 1;
+@@ -879,11 +885,6 @@ YY_DECL
+ yy_load_buffer_state( );
+ }
+
+- {
+-#line 68 "dtc-lexer.l"
+-
+-#line 886 "dtc-lexer.lex.c"
+-
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = (yy_c_buf_p);
+@@ -901,7 +902,7 @@ YY_DECL
+ yy_match:
+ do
+ {
+- register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
++ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+@@ -910,13 +911,13 @@ yy_match:
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+- if ( yy_current_state >= 159 )
++ if ( yy_current_state >= 166 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+- while ( yy_current_state != 158 );
++ while ( yy_current_state != 165 );
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+
+@@ -1007,23 +1008,31 @@ case 5:
+ YY_RULE_SETUP
+ #line 116 "dtc-lexer.l"
+ {
++ DPRINT("Keyword: /plugin/\n");
++ return DT_PLUGIN;
++ }
++ YY_BREAK
++case 6:
++YY_RULE_SETUP
++#line 121 "dtc-lexer.l"
++{
+ DPRINT("Keyword: /memreserve/\n");
+ BEGIN_DEFAULT();
+ return DT_MEMRESERVE;
+ }
+ YY_BREAK
+-case 6:
++case 7:
+ YY_RULE_SETUP
+-#line 122 "dtc-lexer.l"
++#line 127 "dtc-lexer.l"
+ {
+ DPRINT("Keyword: /bits/\n");
+ BEGIN_DEFAULT();
+ return DT_BITS;
+ }
+ YY_BREAK
+-case 7:
++case 8:
+ YY_RULE_SETUP
+-#line 128 "dtc-lexer.l"
++#line 133 "dtc-lexer.l"
+ {
+ DPRINT("Keyword: /delete-property/\n");
+ DPRINT("<PROPNODENAME>\n");
+@@ -1031,9 +1040,9 @@ YY_RULE_SETUP
+ return DT_DEL_PROP;
+ }
+ YY_BREAK
+-case 8:
++case 9:
+ YY_RULE_SETUP
+-#line 135 "dtc-lexer.l"
++#line 140 "dtc-lexer.l"
+ {
+ DPRINT("Keyword: /delete-node/\n");
+ DPRINT("<PROPNODENAME>\n");
+@@ -1041,9 +1050,9 @@ YY_RULE_SETUP
+ return DT_DEL_NODE;
+ }
+ YY_BREAK
+-case 9:
++case 10:
+ YY_RULE_SETUP
+-#line 142 "dtc-lexer.l"
++#line 147 "dtc-lexer.l"
+ {
+ DPRINT("Label: %s\n", yytext);
+ yylval.labelref = xstrdup(yytext);
+@@ -1051,9 +1060,9 @@ YY_RULE_SETUP
+ return DT_LABEL;
+ }
+ YY_BREAK
+-case 10:
++case 11:
+ YY_RULE_SETUP
+-#line 149 "dtc-lexer.l"
++#line 154 "dtc-lexer.l"
+ {
+ char *e;
+ DPRINT("Integer Literal: '%s'\n", yytext);
+@@ -1073,10 +1082,10 @@ YY_RULE_SETUP
+ return DT_LITERAL;
+ }
+ YY_BREAK
+-case 11:
+-/* rule 11 can match eol */
++case 12:
++/* rule 12 can match eol */
+ YY_RULE_SETUP
+-#line 168 "dtc-lexer.l"
++#line 173 "dtc-lexer.l"
+ {
+ struct data d;
+ DPRINT("Character literal: %s\n", yytext);
+@@ -1098,18 +1107,18 @@ YY_RULE_SETUP
+ return DT_CHAR_LITERAL;
+ }
+ YY_BREAK
+-case 12:
++case 13:
+ YY_RULE_SETUP
+-#line 189 "dtc-lexer.l"
++#line 194 "dtc-lexer.l"
+ { /* label reference */
+ DPRINT("Ref: %s\n", yytext+1);
+ yylval.labelref = xstrdup(yytext+1);
+ return DT_REF;
+ }
+ YY_BREAK
+-case 13:
++case 14:
+ YY_RULE_SETUP
+-#line 195 "dtc-lexer.l"
++#line 200 "dtc-lexer.l"
+ { /* new-style path reference */
+ yytext[yyleng-1] = '\0';
+ DPRINT("Ref: %s\n", yytext+2);
+@@ -1117,27 +1126,27 @@ YY_RULE_SETUP
+ return DT_REF;
+ }
+ YY_BREAK
+-case 14:
++case 15:
+ YY_RULE_SETUP
+-#line 202 "dtc-lexer.l"
++#line 207 "dtc-lexer.l"
+ {
+ yylval.byte = strtol(yytext, NULL, 16);
+ DPRINT("Byte: %02x\n", (int)yylval.byte);
+ return DT_BYTE;
+ }
+ YY_BREAK
+-case 15:
++case 16:
+ YY_RULE_SETUP
+-#line 208 "dtc-lexer.l"
++#line 213 "dtc-lexer.l"
+ {
+ DPRINT("/BYTESTRING\n");
+ BEGIN_DEFAULT();
+ return ']';
+ }
+ YY_BREAK
+-case 16:
++case 17:
+ YY_RULE_SETUP
+-#line 214 "dtc-lexer.l"
++#line 219 "dtc-lexer.l"
+ {
+ DPRINT("PropNodeName: %s\n", yytext);
+ yylval.propnodename = xstrdup((yytext[0] == '\\') ?
+@@ -1146,75 +1155,75 @@ YY_RULE_SETUP
+ return DT_PROPNODENAME;
+ }
+ YY_BREAK
+-case 17:
++case 18:
+ YY_RULE_SETUP
+-#line 222 "dtc-lexer.l"
++#line 227 "dtc-lexer.l"
+ {
+ DPRINT("Binary Include\n");
+ return DT_INCBIN;
+ }
+ YY_BREAK
+-case 18:
+-/* rule 18 can match eol */
+-YY_RULE_SETUP
+-#line 227 "dtc-lexer.l"
+-/* eat whitespace */
+- YY_BREAK
+ case 19:
+ /* rule 19 can match eol */
+ YY_RULE_SETUP
+-#line 228 "dtc-lexer.l"
+-/* eat C-style comments */
++#line 232 "dtc-lexer.l"
++/* eat whitespace */
+ YY_BREAK
+ case 20:
+ /* rule 20 can match eol */
+ YY_RULE_SETUP
+-#line 229 "dtc-lexer.l"
+-/* eat C++-style comments */
++#line 233 "dtc-lexer.l"
++/* eat C-style comments */
+ YY_BREAK
+ case 21:
++/* rule 21 can match eol */
+ YY_RULE_SETUP
+-#line 231 "dtc-lexer.l"
+-{ return DT_LSHIFT; };
++#line 234 "dtc-lexer.l"
++/* eat C++-style comments */
+ YY_BREAK
+ case 22:
+ YY_RULE_SETUP
+-#line 232 "dtc-lexer.l"
+-{ return DT_RSHIFT; };
++#line 236 "dtc-lexer.l"
++{ return DT_LSHIFT; };
+ YY_BREAK
+ case 23:
+ YY_RULE_SETUP
+-#line 233 "dtc-lexer.l"
+-{ return DT_LE; };
++#line 237 "dtc-lexer.l"
++{ return DT_RSHIFT; };
+ YY_BREAK
+ case 24:
+ YY_RULE_SETUP
+-#line 234 "dtc-lexer.l"
+-{ return DT_GE; };
++#line 238 "dtc-lexer.l"
++{ return DT_LE; };
+ YY_BREAK
+ case 25:
+ YY_RULE_SETUP
+-#line 235 "dtc-lexer.l"
+-{ return DT_EQ; };
++#line 239 "dtc-lexer.l"
++{ return DT_GE; };
+ YY_BREAK
+ case 26:
+ YY_RULE_SETUP
+-#line 236 "dtc-lexer.l"
+-{ return DT_NE; };
++#line 240 "dtc-lexer.l"
++{ return DT_EQ; };
+ YY_BREAK
+ case 27:
+ YY_RULE_SETUP
+-#line 237 "dtc-lexer.l"
+-{ return DT_AND; };
++#line 241 "dtc-lexer.l"
++{ return DT_NE; };
+ YY_BREAK
+ case 28:
+ YY_RULE_SETUP
+-#line 238 "dtc-lexer.l"
+-{ return DT_OR; };
++#line 242 "dtc-lexer.l"
++{ return DT_AND; };
+ YY_BREAK
+ case 29:
+ YY_RULE_SETUP
+-#line 240 "dtc-lexer.l"
++#line 243 "dtc-lexer.l"
++{ return DT_OR; };
++ YY_BREAK
++case 30:
++YY_RULE_SETUP
++#line 245 "dtc-lexer.l"
+ {
+ DPRINT("Char: %c (\\x%02x)\n", yytext[0],
+ (unsigned)yytext[0]);
+@@ -1230,12 +1239,12 @@ YY_RULE_SETUP
+ return yytext[0];
+ }
+ YY_BREAK
+-case 30:
++case 31:
+ YY_RULE_SETUP
+-#line 255 "dtc-lexer.l"
++#line 260 "dtc-lexer.l"
+ ECHO;
+ YY_BREAK
+-#line 1239 "dtc-lexer.lex.c"
++#line 1248 "dtc-lexer.lex.c"
+
+ case YY_END_OF_BUFFER:
+ {
+@@ -1365,7 +1374,6 @@ ECHO;
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+- } /* end of user's declarations */
+ } /* end of yylex */
+
+ /* yy_get_next_buffer - try to read in a new buffer
+@@ -1421,21 +1429,21 @@ static int yy_get_next_buffer (void)
+
+ else
+ {
+- yy_size_t num_to_read =
++ int num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+- YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
++ YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+ int yy_c_buf_p_offset =
+ (int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+- yy_size_t new_size = b->yy_buf_size * 2;
++ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+@@ -1466,7 +1474,7 @@ static int yy_get_next_buffer (void)
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+- (yy_n_chars), num_to_read );
++ (yy_n_chars), (size_t) num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+@@ -1528,7 +1536,7 @@ static int yy_get_next_buffer (void)
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+- if ( yy_current_state >= 159 )
++ if ( yy_current_state >= 166 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+@@ -1556,13 +1564,13 @@ static int yy_get_next_buffer (void)
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+- if ( yy_current_state >= 159 )
++ if ( yy_current_state >= 166 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+- yy_is_jam = (yy_current_state == 158);
++ yy_is_jam = (yy_current_state == 165);
+
+- return yy_is_jam ? 0 : yy_current_state;
++ return yy_is_jam ? 0 : yy_current_state;
+ }
+
+ #ifndef YY_NO_INPUT
+@@ -1589,7 +1597,7 @@ static int yy_get_next_buffer (void)
+
+ else
+ { /* need more input */
+- yy_size_t offset = (yy_c_buf_p) - (yytext_ptr);
++ int offset = (yy_c_buf_p) - (yytext_ptr);
+ ++(yy_c_buf_p);
+
+ switch ( yy_get_next_buffer( ) )
+@@ -1863,7 +1871,7 @@ void yypop_buffer_state (void)
+ */
+ static void yyensure_buffer_stack (void)
+ {
+- yy_size_t num_to_alloc;
++ int num_to_alloc;
+
+ if (!(yy_buffer_stack)) {
+
+@@ -1960,12 +1968,12 @@ YY_BUFFER_STATE yy_scan_string (yyconst
+ *
+ * @return the newly allocated buffer state object.
+ */
+-YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len )
++YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len )
+ {
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+- yy_size_t i;
++ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+@@ -2047,7 +2055,7 @@ FILE *yyget_out (void)
+ /** Get the length of the current token.
+ *
+ */
+-yy_size_t yyget_leng (void)
++int yyget_leng (void)
+ {
+ return yyleng;
+ }
+@@ -2195,7 +2203,7 @@ void yyfree (void * ptr )
+
+ #define YYTABLES_NAME "yytables"
+
+-#line 254 "dtc-lexer.l"
++#line 260 "dtc-lexer.l"
+
+
+
+--- a/scripts/dtc/dtc-parser.tab.c_shipped
++++ b/scripts/dtc/dtc-parser.tab.c_shipped
+@@ -1,19 +1,19 @@
+-/* A Bison parser, made by GNU Bison 3.0.2. */
++/* A Bison parser, made by GNU Bison 2.5. */
+
+ /* Bison implementation for Yacc-like parsers in C
+-
+- Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
+-
++
++ Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
++
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. */
+
+@@ -26,7 +26,7 @@
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+-
++
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+@@ -44,7 +44,7 @@
+ #define YYBISON 1
+
+ /* Bison version. */
+-#define YYBISON_VERSION "3.0.2"
++#define YYBISON_VERSION "2.5"
+
+ /* Skeleton name. */
+ #define YYSKELETON_NAME "yacc.c"
+@@ -58,13 +58,18 @@
+ /* Pull parsers. */
+ #define YYPULL 1
+
++/* Using locations. */
++#define YYLSP_NEEDED 1
+
+
+
+ /* Copy the first part of user declarations. */
+-#line 20 "dtc-parser.y" /* yacc.c:339 */
++
++/* Line 268 of yacc.c */
++#line 20 "dtc-parser.y"
+
+ #include <stdio.h>
++#include <inttypes.h>
+
+ #include "dtc.h"
+ #include "srcpos.h"
+@@ -80,15 +85,14 @@ extern void yyerror(char const *s);
+ extern struct boot_info *the_boot_info;
+ extern bool treesource_error;
+
+-#line 84 "dtc-parser.tab.c" /* yacc.c:339 */
+
+-# ifndef YY_NULLPTR
+-# if defined __cplusplus && 201103L <= __cplusplus
+-# define YY_NULLPTR nullptr
+-# else
+-# define YY_NULLPTR 0
+-# endif
+-# endif
++/* Line 268 of yacc.c */
++#line 91 "dtc-parser.tab.c"
++
++/* Enabling traces. */
++#ifndef YYDEBUG
++# define YYDEBUG 0
++#endif
+
+ /* Enabling verbose error messages. */
+ #ifdef YYERROR_VERBOSE
+@@ -98,53 +102,51 @@ extern bool treesource_error;
+ # define YYERROR_VERBOSE 0
+ #endif
+
+-/* In a future release of Bison, this section will be replaced
+- by #include "dtc-parser.tab.h". */
+-#ifndef YY_YY_DTC_PARSER_TAB_H_INCLUDED
+-# define YY_YY_DTC_PARSER_TAB_H_INCLUDED
+-/* Debug traces. */
+-#ifndef YYDEBUG
+-# define YYDEBUG 0
+-#endif
+-#if YYDEBUG
+-extern int yydebug;
++/* Enabling the token table. */
++#ifndef YYTOKEN_TABLE
++# define YYTOKEN_TABLE 0
+ #endif
+
+-/* Token type. */
++
++/* Tokens. */
+ #ifndef YYTOKENTYPE
+ # define YYTOKENTYPE
+- enum yytokentype
+- {
+- DT_V1 = 258,
+- DT_MEMRESERVE = 259,
+- DT_LSHIFT = 260,
+- DT_RSHIFT = 261,
+- DT_LE = 262,
+- DT_GE = 263,
+- DT_EQ = 264,
+- DT_NE = 265,
+- DT_AND = 266,
+- DT_OR = 267,
+- DT_BITS = 268,
+- DT_DEL_PROP = 269,
+- DT_DEL_NODE = 270,
+- DT_PROPNODENAME = 271,
+- DT_LITERAL = 272,
+- DT_CHAR_LITERAL = 273,
+- DT_BYTE = 274,
+- DT_STRING = 275,
+- DT_LABEL = 276,
+- DT_REF = 277,
+- DT_INCBIN = 278
+- };
++ /* Put the tokens into the symbol table, so that GDB and other debuggers
++ know about them. */
++ enum yytokentype {
++ DT_V1 = 258,
++ DT_PLUGIN = 259,
++ DT_MEMRESERVE = 260,
++ DT_LSHIFT = 261,
++ DT_RSHIFT = 262,
++ DT_LE = 263,
++ DT_GE = 264,
++ DT_EQ = 265,
++ DT_NE = 266,
++ DT_AND = 267,
++ DT_OR = 268,
++ DT_BITS = 269,
++ DT_DEL_PROP = 270,
++ DT_DEL_NODE = 271,
++ DT_PROPNODENAME = 272,
++ DT_LITERAL = 273,
++ DT_CHAR_LITERAL = 274,
++ DT_BYTE = 275,
++ DT_STRING = 276,
++ DT_LABEL = 277,
++ DT_REF = 278,
++ DT_INCBIN = 279
++ };
+ #endif
+
+-/* Value type. */
++
++
+ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+-typedef union YYSTYPE YYSTYPE;
+-union YYSTYPE
++typedef union YYSTYPE
+ {
+-#line 38 "dtc-parser.y" /* yacc.c:355 */
++
++/* Line 293 of yacc.c */
++#line 39 "dtc-parser.y"
+
+ char *propnodename;
+ char *labelref;
+@@ -162,37 +164,37 @@ union YYSTYPE
+ struct node *nodelist;
+ struct reserve_info *re;
+ uint64_t integer;
++ int is_plugin;
+
+-#line 167 "dtc-parser.tab.c" /* yacc.c:355 */
+-};
++
++
++/* Line 293 of yacc.c */
++#line 173 "dtc-parser.tab.c"
++} YYSTYPE;
+ # define YYSTYPE_IS_TRIVIAL 1
++# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+ # define YYSTYPE_IS_DECLARED 1
+ #endif
+
+-/* Location type. */
+ #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
+-typedef struct YYLTYPE YYLTYPE;
+-struct YYLTYPE
++typedef struct YYLTYPE
+ {
+ int first_line;
+ int first_column;
+ int last_line;
+ int last_column;
+-};
++} YYLTYPE;
++# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
+ # define YYLTYPE_IS_DECLARED 1
+ # define YYLTYPE_IS_TRIVIAL 1
+ #endif
+
+
+-extern YYSTYPE yylval;
+-extern YYLTYPE yylloc;
+-int yyparse (void);
+-
+-#endif /* !YY_YY_DTC_PARSER_TAB_H_INCLUDED */
+-
+ /* Copy the second part of user declarations. */
+
+-#line 196 "dtc-parser.tab.c" /* yacc.c:358 */
++
++/* Line 343 of yacc.c */
++#line 198 "dtc-parser.tab.c"
+
+ #ifdef short
+ # undef short
+@@ -206,8 +208,11 @@ typedef unsigned char yytype_uint8;
+
+ #ifdef YYTYPE_INT8
+ typedef YYTYPE_INT8 yytype_int8;
+-#else
++#elif (defined __STDC__ || defined __C99__FUNC__ \
++ || defined __cplusplus || defined _MSC_VER)
+ typedef signed char yytype_int8;
++#else
++typedef short int yytype_int8;
+ #endif
+
+ #ifdef YYTYPE_UINT16
+@@ -227,7 +232,8 @@ typedef short int yytype_int16;
+ # define YYSIZE_T __SIZE_TYPE__
+ # elif defined size_t
+ # define YYSIZE_T size_t
+-# elif ! defined YYSIZE_T
++# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
++ || defined __cplusplus || defined _MSC_VER)
+ # include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+ # define YYSIZE_T size_t
+ # else
+@@ -241,68 +247,39 @@ typedef short int yytype_int16;
+ # if defined YYENABLE_NLS && YYENABLE_NLS
+ # if ENABLE_NLS
+ # include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+-# define YY_(Msgid) dgettext ("bison-runtime", Msgid)
++# define YY_(msgid) dgettext ("bison-runtime", msgid)
+ # endif
+ # endif
+ # ifndef YY_
+-# define YY_(Msgid) Msgid
+-# endif
+-#endif
+-
+-#ifndef YY_ATTRIBUTE
+-# if (defined __GNUC__ \
+- && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \
+- || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C
+-# define YY_ATTRIBUTE(Spec) __attribute__(Spec)
+-# else
+-# define YY_ATTRIBUTE(Spec) /* empty */
+-# endif
+-#endif
+-
+-#ifndef YY_ATTRIBUTE_PURE
+-# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__))
+-#endif
+-
+-#ifndef YY_ATTRIBUTE_UNUSED
+-# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__))
+-#endif
+-
+-#if !defined _Noreturn \
+- && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112)
+-# if defined _MSC_VER && 1200 <= _MSC_VER
+-# define _Noreturn __declspec (noreturn)
+-# else
+-# define _Noreturn YY_ATTRIBUTE ((__noreturn__))
++# define YY_(msgid) msgid
+ # endif
+ #endif
+
+ /* Suppress unused-variable warnings by "using" E. */
+ #if ! defined lint || defined __GNUC__
+-# define YYUSE(E) ((void) (E))
++# define YYUSE(e) ((void) (e))
+ #else
+-# define YYUSE(E) /* empty */
++# define YYUSE(e) /* empty */
+ #endif
+
+-#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
+-/* Suppress an incorrect diagnostic about yylval being uninitialized. */
+-# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
+- _Pragma ("GCC diagnostic push") \
+- _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\
+- _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+-# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
+- _Pragma ("GCC diagnostic pop")
++/* Identity function, used to suppress warnings about constant conditions. */
++#ifndef lint
++# define YYID(n) (n)
+ #else
+-# define YY_INITIAL_VALUE(Value) Value
+-#endif
+-#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+-# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+-# define YY_IGNORE_MAYBE_UNINITIALIZED_END
++#if (defined __STDC__ || defined __C99__FUNC__ \
++ || defined __cplusplus || defined _MSC_VER)
++static int
++YYID (int yyi)
++#else
++static int
++YYID (yyi)
++ int yyi;
+ #endif
+-#ifndef YY_INITIAL_VALUE
+-# define YY_INITIAL_VALUE(Value) /* Nothing. */
++{
++ return yyi;
++}
+ #endif
+
+-
+ #if ! defined yyoverflow || YYERROR_VERBOSE
+
+ /* The parser invokes alloca or malloc; define the necessary symbols. */
+@@ -320,9 +297,9 @@ typedef short int yytype_int16;
+ # define alloca _alloca
+ # else
+ # define YYSTACK_ALLOC alloca
+-# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS
++# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
++ || defined __cplusplus || defined _MSC_VER)
+ # include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+- /* Use EXIT_SUCCESS as a witness for stdlib.h. */
+ # ifndef EXIT_SUCCESS
+ # define EXIT_SUCCESS 0
+ # endif
+@@ -332,8 +309,8 @@ typedef short int yytype_int16;
+ # endif
+
+ # ifdef YYSTACK_ALLOC
+- /* Pacify GCC's 'empty if-body' warning. */
+-# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
++ /* Pacify GCC's `empty if-body' warning. */
++# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+ # ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+@@ -349,7 +326,7 @@ typedef short int yytype_int16;
+ # endif
+ # if (defined __cplusplus && ! defined EXIT_SUCCESS \
+ && ! ((defined YYMALLOC || defined malloc) \
+- && (defined YYFREE || defined free)))
++ && (defined YYFREE || defined free)))
+ # include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+ # ifndef EXIT_SUCCESS
+ # define EXIT_SUCCESS 0
+@@ -357,13 +334,15 @@ typedef short int yytype_int16;
+ # endif
+ # ifndef YYMALLOC
+ # define YYMALLOC malloc
+-# if ! defined malloc && ! defined EXIT_SUCCESS
++# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
++ || defined __cplusplus || defined _MSC_VER)
+ void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+ # endif
+ # endif
+ # ifndef YYFREE
+ # define YYFREE free
+-# if ! defined free && ! defined EXIT_SUCCESS
++# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
++ || defined __cplusplus || defined _MSC_VER)
+ void free (void *); /* INFRINGES ON USER NAME SPACE */
+ # endif
+ # endif
+@@ -373,8 +352,8 @@ void free (void *); /* INFRINGES ON USER
+
+ #if (! defined yyoverflow \
+ && (! defined __cplusplus \
+- || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
+- && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
++ || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
++ && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+ /* A type that is properly aligned for any stack member. */
+ union yyalloc
+@@ -400,35 +379,35 @@ union yyalloc
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+-# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+- do \
+- { \
+- YYSIZE_T yynewbytes; \
+- YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+- Stack = &yyptr->Stack_alloc; \
+- yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+- yyptr += yynewbytes / sizeof (*yyptr); \
+- } \
+- while (0)
++# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
++ do \
++ { \
++ YYSIZE_T yynewbytes; \
++ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
++ Stack = &yyptr->Stack_alloc; \
++ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
++ yyptr += yynewbytes / sizeof (*yyptr); \
++ } \
++ while (YYID (0))
+
+ #endif
+
+ #if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+-/* Copy COUNT objects from SRC to DST. The source and destination do
++/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+ # ifndef YYCOPY
+ # if defined __GNUC__ && 1 < __GNUC__
+-# define YYCOPY(Dst, Src, Count) \
+- __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
++# define YYCOPY(To, From, Count) \
++ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+ # else
+-# define YYCOPY(Dst, Src, Count) \
+- do \
+- { \
+- YYSIZE_T yyi; \
+- for (yyi = 0; yyi < (Count); yyi++) \
+- (Dst)[yyi] = (Src)[yyi]; \
+- } \
+- while (0)
++# define YYCOPY(To, From, Count) \
++ do \
++ { \
++ YYSIZE_T yyi; \
++ for (yyi = 0; yyi < (Count); yyi++) \
++ (To)[yyi] = (From)[yyi]; \
++ } \
++ while (YYID (0))
+ # endif
+ # endif
+ #endif /* !YYCOPY_NEEDED */
+@@ -439,39 +418,37 @@ union yyalloc
+ #define YYLAST 136
+
+ /* YYNTOKENS -- Number of terminals. */
+-#define YYNTOKENS 47
++#define YYNTOKENS 48
+ /* YYNNTS -- Number of nonterminals. */
+-#define YYNNTS 28
++#define YYNNTS 29
+ /* YYNRULES -- Number of rules. */
+-#define YYNRULES 80
+-/* YYNSTATES -- Number of states. */
+-#define YYNSTATES 144
++#define YYNRULES 82
++/* YYNRULES -- Number of states. */
++#define YYNSTATES 147
+
+-/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
+- by yylex, with out-of-bounds checking. */
++/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+ #define YYUNDEFTOK 2
+-#define YYMAXUTOK 278
++#define YYMAXUTOK 279
+
+-#define YYTRANSLATE(YYX) \
++#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+-/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
+- as returned by yylex, without out-of-bounds checking. */
++/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+ static const yytype_uint8 yytranslate[] =
+ {
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+- 2, 2, 2, 46, 2, 2, 2, 44, 40, 2,
+- 32, 34, 43, 41, 33, 42, 2, 25, 2, 2,
+- 2, 2, 2, 2, 2, 2, 2, 2, 37, 24,
+- 35, 28, 29, 36, 2, 2, 2, 2, 2, 2,
++ 2, 2, 2, 47, 2, 2, 2, 45, 41, 2,
++ 33, 35, 44, 42, 34, 43, 2, 26, 2, 2,
++ 2, 2, 2, 2, 2, 2, 2, 2, 38, 25,
++ 36, 29, 30, 37, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+- 2, 30, 2, 31, 39, 2, 2, 2, 2, 2,
++ 2, 31, 2, 32, 40, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+- 2, 2, 2, 26, 38, 27, 45, 2, 2, 2,
++ 2, 2, 2, 27, 39, 28, 46, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+@@ -486,292 +463,335 @@ static const yytype_uint8 yytranslate[]
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+- 15, 16, 17, 18, 19, 20, 21, 22, 23
++ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24
+ };
+
+ #if YYDEBUG
+- /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
++/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
++ YYRHS. */
++static const yytype_uint16 yyprhs[] =
++{
++ 0, 0, 3, 9, 10, 13, 14, 17, 22, 25,
++ 28, 32, 37, 41, 46, 52, 53, 56, 61, 64,
++ 68, 71, 74, 78, 83, 86, 96, 102, 105, 106,
++ 109, 112, 116, 118, 121, 124, 127, 129, 131, 135,
++ 137, 139, 145, 147, 151, 153, 157, 159, 163, 165,
++ 169, 171, 175, 177, 181, 185, 187, 191, 195, 199,
++ 203, 207, 211, 213, 217, 221, 223, 227, 231, 235,
++ 237, 239, 242, 245, 248, 249, 252, 255, 256, 259,
++ 262, 265, 269
++};
++
++/* YYRHS -- A `-1'-separated list of the rules' RHS. */
++static const yytype_int8 yyrhs[] =
++{
++ 49, 0, -1, 3, 25, 50, 51, 53, -1, -1,
++ 4, 25, -1, -1, 52, 51, -1, 5, 60, 60,
++ 25, -1, 22, 52, -1, 26, 54, -1, 53, 26,
++ 54, -1, 53, 22, 23, 54, -1, 53, 23, 54,
++ -1, 53, 16, 23, 25, -1, 27, 55, 75, 28,
++ 25, -1, -1, 55, 56, -1, 17, 29, 57, 25,
++ -1, 17, 25, -1, 15, 17, 25, -1, 22, 56,
++ -1, 58, 21, -1, 58, 59, 30, -1, 58, 31,
++ 74, 32, -1, 58, 23, -1, 58, 24, 33, 21,
++ 34, 60, 34, 60, 35, -1, 58, 24, 33, 21,
++ 35, -1, 57, 22, -1, -1, 57, 34, -1, 58,
++ 22, -1, 14, 18, 36, -1, 36, -1, 59, 60,
++ -1, 59, 23, -1, 59, 22, -1, 18, -1, 19,
++ -1, 33, 61, 35, -1, 62, -1, 63, -1, 63,
++ 37, 61, 38, 62, -1, 64, -1, 63, 13, 64,
++ -1, 65, -1, 64, 12, 65, -1, 66, -1, 65,
++ 39, 66, -1, 67, -1, 66, 40, 67, -1, 68,
++ -1, 67, 41, 68, -1, 69, -1, 68, 10, 69,
++ -1, 68, 11, 69, -1, 70, -1, 69, 36, 70,
++ -1, 69, 30, 70, -1, 69, 8, 70, -1, 69,
++ 9, 70, -1, 70, 6, 71, -1, 70, 7, 71,
++ -1, 71, -1, 71, 42, 72, -1, 71, 43, 72,
++ -1, 72, -1, 72, 44, 73, -1, 72, 26, 73,
++ -1, 72, 45, 73, -1, 73, -1, 60, -1, 43,
++ 73, -1, 46, 73, -1, 47, 73, -1, -1, 74,
++ 20, -1, 74, 22, -1, -1, 76, 75, -1, 76,
++ 56, -1, 17, 54, -1, 16, 17, 25, -1, 22,
++ 76, -1
++};
++
++/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+ static const yytype_uint16 yyrline[] =
+ {
+- 0, 104, 104, 113, 116, 123, 127, 135, 139, 144,
+- 155, 165, 180, 188, 191, 198, 202, 206, 210, 218,
+- 222, 226, 230, 234, 250, 260, 268, 271, 275, 282,
+- 298, 303, 322, 336, 343, 344, 345, 352, 356, 357,
+- 361, 362, 366, 367, 371, 372, 376, 377, 381, 382,
+- 386, 387, 388, 392, 393, 394, 395, 396, 400, 401,
+- 402, 406, 407, 408, 412, 413, 414, 415, 419, 420,
+- 421, 422, 427, 430, 434, 442, 445, 449, 457, 461,
+- 465
++ 0, 108, 108, 119, 122, 130, 133, 140, 144, 152,
++ 156, 161, 172, 182, 197, 205, 208, 215, 219, 223,
++ 227, 235, 239, 243, 247, 251, 267, 277, 285, 288,
++ 292, 299, 315, 320, 339, 353, 360, 361, 362, 369,
++ 373, 374, 378, 379, 383, 384, 388, 389, 393, 394,
++ 398, 399, 403, 404, 405, 409, 410, 411, 412, 413,
++ 417, 418, 419, 423, 424, 425, 429, 430, 431, 432,
++ 436, 437, 438, 439, 444, 447, 451, 459, 462, 466,
++ 474, 478, 482
+ };
+ #endif
+
+-#if YYDEBUG || YYERROR_VERBOSE || 0
++#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+ /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+ static const char *const yytname[] =
+ {
+- "$end", "error", "$undefined", "DT_V1", "DT_MEMRESERVE", "DT_LSHIFT",
+- "DT_RSHIFT", "DT_LE", "DT_GE", "DT_EQ", "DT_NE", "DT_AND", "DT_OR",
+- "DT_BITS", "DT_DEL_PROP", "DT_DEL_NODE", "DT_PROPNODENAME", "DT_LITERAL",
+- "DT_CHAR_LITERAL", "DT_BYTE", "DT_STRING", "DT_LABEL", "DT_REF",
+- "DT_INCBIN", "';'", "'/'", "'{'", "'}'", "'='", "'>'", "'['", "']'",
+- "'('", "','", "')'", "'<'", "'?'", "':'", "'|'", "'^'", "'&'", "'+'",
+- "'-'", "'*'", "'%'", "'~'", "'!'", "$accept", "sourcefile",
+- "memreserves", "memreserve", "devicetree", "nodedef", "proplist",
+- "propdef", "propdata", "propdataprefix", "arrayprefix", "integer_prim",
+- "integer_expr", "integer_trinary", "integer_or", "integer_and",
+- "integer_bitor", "integer_bitxor", "integer_bitand", "integer_eq",
+- "integer_rela", "integer_shift", "integer_add", "integer_mul",
+- "integer_unary", "bytestring", "subnodes", "subnode", YY_NULLPTR
++ "$end", "error", "$undefined", "DT_V1", "DT_PLUGIN", "DT_MEMRESERVE",
++ "DT_LSHIFT", "DT_RSHIFT", "DT_LE", "DT_GE", "DT_EQ", "DT_NE", "DT_AND",
++ "DT_OR", "DT_BITS", "DT_DEL_PROP", "DT_DEL_NODE", "DT_PROPNODENAME",
++ "DT_LITERAL", "DT_CHAR_LITERAL", "DT_BYTE", "DT_STRING", "DT_LABEL",
++ "DT_REF", "DT_INCBIN", "';'", "'/'", "'{'", "'}'", "'='", "'>'", "'['",
++ "']'", "'('", "','", "')'", "'<'", "'?'", "':'", "'|'", "'^'", "'&'",
++ "'+'", "'-'", "'*'", "'%'", "'~'", "'!'", "$accept", "sourcefile",
++ "plugindecl", "memreserves", "memreserve", "devicetree", "nodedef",
++ "proplist", "propdef", "propdata", "propdataprefix", "arrayprefix",
++ "integer_prim", "integer_expr", "integer_trinary", "integer_or",
++ "integer_and", "integer_bitor", "integer_bitxor", "integer_bitand",
++ "integer_eq", "integer_rela", "integer_shift", "integer_add",
++ "integer_mul", "integer_unary", "bytestring", "subnodes", "subnode", 0
+ };
+ #endif
+
+ # ifdef YYPRINT
+-/* YYTOKNUM[NUM] -- (External) token number corresponding to the
+- (internal) symbol number NUM (which must be that of a token). */
++/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
++ token YYLEX-NUM. */
+ static const yytype_uint16 yytoknum[] =
+ {
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+- 275, 276, 277, 278, 59, 47, 123, 125, 61, 62,
+- 91, 93, 40, 44, 41, 60, 63, 58, 124, 94,
+- 38, 43, 45, 42, 37, 126, 33
++ 275, 276, 277, 278, 279, 59, 47, 123, 125, 61,
++ 62, 91, 93, 40, 44, 41, 60, 63, 58, 124,
++ 94, 38, 43, 45, 42, 37, 126, 33
+ };
+ # endif
+
+-#define YYPACT_NINF -81
+-
+-#define yypact_value_is_default(Yystate) \
+- (!!((Yystate) == (-81)))
+-
+-#define YYTABLE_NINF -1
+-
+-#define yytable_value_is_error(Yytable_value) \
+- 0
+-
+- /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+- STATE-NUM. */
+-static const yytype_int8 yypact[] =
++/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
++static const yytype_uint8 yyr1[] =
+ {
+- 16, -11, 21, 10, -81, 25, 10, 19, 10, -81,
+- -81, -9, 25, -81, 2, 51, -81, -9, -9, -9,
+- -81, 1, -81, -6, 50, 14, 28, 29, 36, 3,
+- 58, 44, -3, -81, 47, -81, -81, 65, 68, 2,
+- 2, -81, -81, -81, -81, -9, -9, -9, -9, -9,
+- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
+- -9, -9, -9, -9, -81, 63, 69, 2, -81, -81,
+- 50, 57, 14, 28, 29, 36, 3, 3, 58, 58,
+- 58, 58, 44, 44, -3, -3, -81, -81, -81, 79,
+- 80, -8, 63, -81, 72, 63, -81, -81, -9, 76,
+- 77, -81, -81, -81, -81, -81, 78, -81, -81, -81,
+- -81, -81, 35, 4, -81, -81, -81, -81, 86, -81,
+- -81, -81, 73, -81, -81, 33, 71, 84, 39, -81,
+- -81, -81, -81, -81, 41, -81, -81, -81, 25, -81,
+- 74, 25, 75, -81
++ 0, 48, 49, 50, 50, 51, 51, 52, 52, 53,
++ 53, 53, 53, 53, 54, 55, 55, 56, 56, 56,
++ 56, 57, 57, 57, 57, 57, 57, 57, 58, 58,
++ 58, 59, 59, 59, 59, 59, 60, 60, 60, 61,
++ 62, 62, 63, 63, 64, 64, 65, 65, 66, 66,
++ 67, 67, 68, 68, 68, 69, 69, 69, 69, 69,
++ 70, 70, 70, 71, 71, 71, 72, 72, 72, 72,
++ 73, 73, 73, 73, 74, 74, 74, 75, 75, 75,
++ 76, 76, 76
+ };
+
+- /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
+- Performed when YYTABLE does not specify something else to do. Zero
+- means the default is an error. */
+-static const yytype_uint8 yydefact[] =
++/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
++static const yytype_uint8 yyr2[] =
+ {
+- 0, 0, 0, 3, 1, 0, 0, 0, 3, 34,
+- 35, 0, 0, 6, 0, 2, 4, 0, 0, 0,
+- 68, 0, 37, 38, 40, 42, 44, 46, 48, 50,
+- 53, 60, 63, 67, 0, 13, 7, 0, 0, 0,
+- 0, 69, 70, 71, 36, 0, 0, 0, 0, 0,
+- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+- 0, 0, 0, 0, 5, 75, 0, 0, 10, 8,
+- 41, 0, 43, 45, 47, 49, 51, 52, 56, 57,
+- 55, 54, 58, 59, 61, 62, 65, 64, 66, 0,
+- 0, 0, 0, 14, 0, 75, 11, 9, 0, 0,
+- 0, 16, 26, 78, 18, 80, 0, 77, 76, 39,
+- 17, 79, 0, 0, 12, 25, 15, 27, 0, 19,
+- 28, 22, 0, 72, 30, 0, 0, 0, 0, 33,
+- 32, 20, 31, 29, 0, 73, 74, 21, 0, 24,
+- 0, 0, 0, 23
++ 0, 2, 5, 0, 2, 0, 2, 4, 2, 2,
++ 3, 4, 3, 4, 5, 0, 2, 4, 2, 3,
++ 2, 2, 3, 4, 2, 9, 5, 2, 0, 2,
++ 2, 3, 1, 2, 2, 2, 1, 1, 3, 1,
++ 1, 5, 1, 3, 1, 3, 1, 3, 1, 3,
++ 1, 3, 1, 3, 3, 1, 3, 3, 3, 3,
++ 3, 3, 1, 3, 3, 1, 3, 3, 3, 1,
++ 1, 2, 2, 2, 0, 2, 2, 0, 2, 2,
++ 2, 3, 2
+ };
+
+- /* YYPGOTO[NTERM-NUM]. */
+-static const yytype_int8 yypgoto[] =
++/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
++ Performed when YYTABLE doesn't specify something else to do. Zero
++ means the default is an error. */
++static const yytype_uint8 yydefact[] =
+ {
+- -81, -81, 100, 104, -81, -38, -81, -80, -81, -81,
+- -81, -5, 66, 13, -81, 70, 67, 81, 64, 82,
+- 37, 27, 34, 38, -14, -81, 22, 24
++ 0, 0, 0, 3, 1, 0, 5, 4, 0, 0,
++ 0, 5, 36, 37, 0, 0, 8, 0, 2, 6,
++ 0, 0, 0, 70, 0, 39, 40, 42, 44, 46,
++ 48, 50, 52, 55, 62, 65, 69, 0, 15, 9,
++ 0, 0, 0, 0, 71, 72, 73, 38, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 7, 77, 0,
++ 0, 12, 10, 43, 0, 45, 47, 49, 51, 53,
++ 54, 58, 59, 57, 56, 60, 61, 63, 64, 67,
++ 66, 68, 0, 0, 0, 0, 16, 0, 77, 13,
++ 11, 0, 0, 0, 18, 28, 80, 20, 82, 0,
++ 79, 78, 41, 19, 81, 0, 0, 14, 27, 17,
++ 29, 0, 21, 30, 24, 0, 74, 32, 0, 0,
++ 0, 0, 35, 34, 22, 33, 31, 0, 75, 76,
++ 23, 0, 26, 0, 0, 0, 25
+ };
+
+- /* YYDEFGOTO[NTERM-NUM]. */
++/* YYDEFGOTO[NTERM-NUM]. */
+ static const yytype_int16 yydefgoto[] =
+ {
+- -1, 2, 7, 8, 15, 36, 65, 93, 112, 113,
+- 125, 20, 21, 22, 23, 24, 25, 26, 27, 28,
+- 29, 30, 31, 32, 33, 128, 94, 95
++ -1, 2, 6, 10, 11, 18, 39, 68, 96, 115,
++ 116, 128, 23, 24, 25, 26, 27, 28, 29, 30,
++ 31, 32, 33, 34, 35, 36, 131, 97, 98
+ };
+
+- /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
+- positive, shift that token. If negative, reduce the rule whose
+- number is the opposite. If YYTABLE_NINF, syntax error. */
+-static const yytype_uint8 yytable[] =
++/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
++ STATE-NUM. */
++#define YYPACT_NINF -84
++static const yytype_int8 yypact[] =
+ {
+- 12, 68, 69, 41, 42, 43, 45, 34, 9, 10,
+- 53, 54, 104, 3, 5, 107, 101, 118, 35, 1,
+- 102, 4, 61, 11, 119, 120, 121, 122, 35, 97,
+- 46, 6, 55, 17, 123, 44, 18, 19, 56, 124,
+- 62, 63, 9, 10, 14, 51, 52, 86, 87, 88,
+- 9, 10, 48, 103, 129, 130, 115, 11, 135, 116,
+- 136, 47, 131, 57, 58, 11, 37, 49, 117, 50,
+- 137, 64, 38, 39, 138, 139, 40, 89, 90, 91,
+- 78, 79, 80, 81, 92, 59, 60, 66, 76, 77,
+- 67, 82, 83, 96, 98, 99, 100, 84, 85, 106,
+- 110, 111, 114, 126, 134, 127, 133, 141, 16, 143,
+- 13, 109, 71, 74, 72, 70, 105, 108, 0, 0,
+- 132, 0, 0, 0, 0, 0, 0, 0, 0, 73,
+- 0, 0, 75, 140, 0, 0, 142
++ 15, -12, 35, 42, -84, 27, 9, -84, 24, 9,
++ 43, 9, -84, -84, -10, 24, -84, 60, 44, -84,
++ -10, -10, -10, -84, 55, -84, -7, 52, 53, 51,
++ 54, 10, 2, 38, 37, -4, -84, 68, -84, -84,
++ 71, 73, 60, 60, -84, -84, -84, -84, -10, -10,
++ -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
++ -10, -10, -10, -10, -10, -10, -10, -84, 56, 72,
++ 60, -84, -84, 52, 61, 53, 51, 54, 10, 2,
++ 2, 38, 38, 38, 38, 37, 37, -4, -4, -84,
++ -84, -84, 81, 83, 34, 56, -84, 74, 56, -84,
++ -84, -10, 76, 78, -84, -84, -84, -84, -84, 79,
++ -84, -84, -84, -84, -84, -6, 3, -84, -84, -84,
++ -84, 87, -84, -84, -84, 75, -84, -84, 32, 70,
++ 86, 36, -84, -84, -84, -84, -84, 47, -84, -84,
++ -84, 24, -84, 77, 24, 80, -84
+ };
+
+-static const yytype_int16 yycheck[] =
++/* YYPGOTO[NTERM-NUM]. */
++static const yytype_int8 yypgoto[] =
+ {
+- 5, 39, 40, 17, 18, 19, 12, 12, 17, 18,
+- 7, 8, 92, 24, 4, 95, 24, 13, 26, 3,
+- 28, 0, 25, 32, 20, 21, 22, 23, 26, 67,
+- 36, 21, 29, 42, 30, 34, 45, 46, 35, 35,
+- 43, 44, 17, 18, 25, 9, 10, 61, 62, 63,
+- 17, 18, 38, 91, 21, 22, 21, 32, 19, 24,
+- 21, 11, 29, 5, 6, 32, 15, 39, 33, 40,
+- 31, 24, 21, 22, 33, 34, 25, 14, 15, 16,
+- 53, 54, 55, 56, 21, 41, 42, 22, 51, 52,
+- 22, 57, 58, 24, 37, 16, 16, 59, 60, 27,
+- 24, 24, 24, 17, 20, 32, 35, 33, 8, 34,
+- 6, 98, 46, 49, 47, 45, 92, 95, -1, -1,
+- 125, -1, -1, -1, -1, -1, -1, -1, -1, 48,
+- -1, -1, 50, 138, -1, -1, 141
++ -84, -84, -84, 98, 101, -84, -41, -84, -83, -84,
++ -84, -84, -8, 63, 12, -84, 66, 67, 65, 69,
++ 82, 29, 18, 25, 26, -17, -84, 20, 28
+ };
+
+- /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+- symbol of state STATE-NUM. */
+-static const yytype_uint8 yystos[] =
++/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
++ positive, shift that token. If negative, reduce the rule which
++ number is the opposite. If YYTABLE_NINF, syntax error. */
++#define YYTABLE_NINF -1
++static const yytype_uint8 yytable[] =
+ {
+- 0, 3, 48, 24, 0, 4, 21, 49, 50, 17,
+- 18, 32, 58, 50, 25, 51, 49, 42, 45, 46,
+- 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
+- 68, 69, 70, 71, 58, 26, 52, 15, 21, 22,
+- 25, 71, 71, 71, 34, 12, 36, 11, 38, 39,
+- 40, 9, 10, 7, 8, 29, 35, 5, 6, 41,
+- 42, 25, 43, 44, 24, 53, 22, 22, 52, 52,
+- 62, 59, 63, 64, 65, 66, 67, 67, 68, 68,
+- 68, 68, 69, 69, 70, 70, 71, 71, 71, 14,
+- 15, 16, 21, 54, 73, 74, 24, 52, 37, 16,
+- 16, 24, 28, 52, 54, 74, 27, 54, 73, 60,
+- 24, 24, 55, 56, 24, 21, 24, 33, 13, 20,
+- 21, 22, 23, 30, 35, 57, 17, 32, 72, 21,
+- 22, 29, 58, 35, 20, 19, 21, 31, 33, 34,
+- 58, 33, 58, 34
++ 15, 71, 72, 44, 45, 46, 48, 37, 12, 13,
++ 56, 57, 107, 3, 8, 110, 118, 121, 1, 119,
++ 54, 55, 64, 14, 122, 123, 124, 125, 120, 100,
++ 49, 9, 58, 20, 126, 4, 21, 22, 59, 127,
++ 65, 66, 12, 13, 60, 61, 5, 89, 90, 91,
++ 12, 13, 7, 106, 132, 133, 138, 14, 139, 104,
++ 40, 38, 134, 105, 50, 14, 41, 42, 140, 17,
++ 43, 92, 93, 94, 81, 82, 83, 84, 95, 62,
++ 63, 141, 142, 79, 80, 85, 86, 38, 87, 88,
++ 47, 52, 51, 67, 69, 53, 70, 99, 102, 101,
++ 103, 113, 109, 114, 117, 129, 136, 137, 130, 19,
++ 16, 144, 74, 112, 73, 146, 76, 75, 111, 0,
++ 135, 77, 0, 108, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 143, 0, 78, 145
+ };
+
+- /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+-static const yytype_uint8 yyr1[] =
++#define yypact_value_is_default(yystate) \
++ ((yystate) == (-84))
++
++#define yytable_value_is_error(yytable_value) \
++ YYID (0)
++
++static const yytype_int16 yycheck[] =
+ {
+- 0, 47, 48, 49, 49, 50, 50, 51, 51, 51,
+- 51, 51, 52, 53, 53, 54, 54, 54, 54, 55,
+- 55, 55, 55, 55, 55, 55, 56, 56, 56, 57,
+- 57, 57, 57, 57, 58, 58, 58, 59, 60, 60,
+- 61, 61, 62, 62, 63, 63, 64, 64, 65, 65,
+- 66, 66, 66, 67, 67, 67, 67, 67, 68, 68,
+- 68, 69, 69, 69, 70, 70, 70, 70, 71, 71,
+- 71, 71, 72, 72, 72, 73, 73, 73, 74, 74,
+- 74
++ 8, 42, 43, 20, 21, 22, 13, 15, 18, 19,
++ 8, 9, 95, 25, 5, 98, 22, 14, 3, 25,
++ 10, 11, 26, 33, 21, 22, 23, 24, 34, 70,
++ 37, 22, 30, 43, 31, 0, 46, 47, 36, 36,
++ 44, 45, 18, 19, 6, 7, 4, 64, 65, 66,
++ 18, 19, 25, 94, 22, 23, 20, 33, 22, 25,
++ 16, 27, 30, 29, 12, 33, 22, 23, 32, 26,
++ 26, 15, 16, 17, 56, 57, 58, 59, 22, 42,
++ 43, 34, 35, 54, 55, 60, 61, 27, 62, 63,
++ 35, 40, 39, 25, 23, 41, 23, 25, 17, 38,
++ 17, 25, 28, 25, 25, 18, 36, 21, 33, 11,
++ 9, 34, 49, 101, 48, 35, 51, 50, 98, -1,
++ 128, 52, -1, 95, -1, -1, -1, -1, -1, -1,
++ -1, -1, -1, 141, -1, 53, 144
+ };
+
+- /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */
+-static const yytype_uint8 yyr2[] =
++/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
++ symbol of state STATE-NUM. */
++static const yytype_uint8 yystos[] =
+ {
+- 0, 2, 4, 0, 2, 4, 2, 2, 3, 4,
+- 3, 4, 5, 0, 2, 4, 2, 3, 2, 2,
+- 3, 4, 2, 9, 5, 2, 0, 2, 2, 3,
+- 1, 2, 2, 2, 1, 1, 3, 1, 1, 5,
+- 1, 3, 1, 3, 1, 3, 1, 3, 1, 3,
+- 1, 3, 3, 1, 3, 3, 3, 3, 3, 3,
+- 1, 3, 3, 1, 3, 3, 3, 1, 1, 2,
+- 2, 2, 0, 2, 2, 0, 2, 2, 2, 3,
+- 2
++ 0, 3, 49, 25, 0, 4, 50, 25, 5, 22,
++ 51, 52, 18, 19, 33, 60, 52, 26, 53, 51,
++ 43, 46, 47, 60, 61, 62, 63, 64, 65, 66,
++ 67, 68, 69, 70, 71, 72, 73, 60, 27, 54,
++ 16, 22, 23, 26, 73, 73, 73, 35, 13, 37,
++ 12, 39, 40, 41, 10, 11, 8, 9, 30, 36,
++ 6, 7, 42, 43, 26, 44, 45, 25, 55, 23,
++ 23, 54, 54, 64, 61, 65, 66, 67, 68, 69,
++ 69, 70, 70, 70, 70, 71, 71, 72, 72, 73,
++ 73, 73, 15, 16, 17, 22, 56, 75, 76, 25,
++ 54, 38, 17, 17, 25, 29, 54, 56, 76, 28,
++ 56, 75, 62, 25, 25, 57, 58, 25, 22, 25,
++ 34, 14, 21, 22, 23, 24, 31, 36, 59, 18,
++ 33, 74, 22, 23, 30, 60, 36, 21, 20, 22,
++ 32, 34, 35, 60, 34, 60, 35
+ };
+
+-
+-#define yyerrok (yyerrstatus = 0)
+-#define yyclearin (yychar = YYEMPTY)
+-#define YYEMPTY (-2)
+-#define YYEOF 0
+-
+-#define YYACCEPT goto yyacceptlab
+-#define YYABORT goto yyabortlab
+-#define YYERROR goto yyerrorlab
+-
++#define yyerrok (yyerrstatus = 0)
++#define yyclearin (yychar = YYEMPTY)
++#define YYEMPTY (-2)
++#define YYEOF 0
++
++#define YYACCEPT goto yyacceptlab
++#define YYABORT goto yyabortlab
++#define YYERROR goto yyerrorlab
++
++
++/* Like YYERROR except do call yyerror. This remains here temporarily
++ to ease the transition to the new meaning of YYERROR, for GCC.
++ Once GCC version 2 has supplanted version 1, this can go. However,
++ YYFAIL appears to be in use. Nevertheless, it is formally deprecated
++ in Bison 2.4.2's NEWS entry, where a plan to phase it out is
++ discussed. */
++
++#define YYFAIL goto yyerrlab
++#if defined YYFAIL
++ /* This is here to suppress warnings from the GCC cpp's
++ -Wunused-macros. Normally we don't worry about that warning, but
++ some users do, and we want to make it easy for users to remove
++ YYFAIL uses, which will produce warnings from Bison 2.5. */
++#endif
+
+ #define YYRECOVERING() (!!yyerrstatus)
+
+-#define YYBACKUP(Token, Value) \
+-do \
+- if (yychar == YYEMPTY) \
+- { \
+- yychar = (Token); \
+- yylval = (Value); \
+- YYPOPSTACK (yylen); \
+- yystate = *yyssp; \
+- goto yybackup; \
+- } \
+- else \
+- { \
++#define YYBACKUP(Token, Value) \
++do \
++ if (yychar == YYEMPTY && yylen == 1) \
++ { \
++ yychar = (Token); \
++ yylval = (Value); \
++ YYPOPSTACK (1); \
++ goto yybackup; \
++ } \
++ else \
++ { \
+ yyerror (YY_("syntax error: cannot back up")); \
+- YYERROR; \
+- } \
+-while (0)
+-
+-/* Error token number */
+-#define YYTERROR 1
+-#define YYERRCODE 256
++ YYERROR; \
++ } \
++while (YYID (0))
++
++
++#define YYTERROR 1
++#define YYERRCODE 256
+
+
+ /* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
++#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+ #ifndef YYLLOC_DEFAULT
+-# define YYLLOC_DEFAULT(Current, Rhs, N) \
+- do \
+- if (N) \
+- { \
+- (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+- (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+- (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+- (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+- } \
+- else \
+- { \
+- (Current).first_line = (Current).last_line = \
+- YYRHSLOC (Rhs, 0).last_line; \
+- (Current).first_column = (Current).last_column = \
+- YYRHSLOC (Rhs, 0).last_column; \
+- } \
+- while (0)
++# define YYLLOC_DEFAULT(Current, Rhs, N) \
++ do \
++ if (YYID (N)) \
++ { \
++ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
++ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
++ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
++ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
++ } \
++ else \
++ { \
++ (Current).first_line = (Current).last_line = \
++ YYRHSLOC (Rhs, 0).last_line; \
++ (Current).first_column = (Current).last_column = \
++ YYRHSLOC (Rhs, 0).last_column; \
++ } \
++ while (YYID (0))
+ #endif
+
+-#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+-
+-
+-/* Enable debugging if requested. */
+-#if YYDEBUG
+-
+-# ifndef YYFPRINTF
+-# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+-# define YYFPRINTF fprintf
+-# endif
+-
+-# define YYDPRINTF(Args) \
+-do { \
+- if (yydebug) \
+- YYFPRINTF Args; \
+-} while (0)
+-
+
+ /* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+@@ -779,73 +799,82 @@ do {
+
+ #ifndef YY_LOCATION_PRINT
+ # if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+-
+-/* Print *YYLOCP on YYO. Private, do not rely on its existence. */
+-
+-YY_ATTRIBUTE_UNUSED
+-static unsigned
+-yy_location_print_ (FILE *yyo, YYLTYPE const * const yylocp)
+-{
+- unsigned res = 0;
+- int end_col = 0 != yylocp->last_column ? yylocp->last_column - 1 : 0;
+- if (0 <= yylocp->first_line)
+- {
+- res += YYFPRINTF (yyo, "%d", yylocp->first_line);
+- if (0 <= yylocp->first_column)
+- res += YYFPRINTF (yyo, ".%d", yylocp->first_column);
+- }
+- if (0 <= yylocp->last_line)
+- {
+- if (yylocp->first_line < yylocp->last_line)
+- {
+- res += YYFPRINTF (yyo, "-%d", yylocp->last_line);
+- if (0 <= end_col)
+- res += YYFPRINTF (yyo, ".%d", end_col);
+- }
+- else if (0 <= end_col && yylocp->first_column < end_col)
+- res += YYFPRINTF (yyo, "-%d", end_col);
+- }
+- return res;
+- }
+-
+-# define YY_LOCATION_PRINT(File, Loc) \
+- yy_location_print_ (File, &(Loc))
+-
++# define YY_LOCATION_PRINT(File, Loc) \
++ fprintf (File, "%d.%d-%d.%d", \
++ (Loc).first_line, (Loc).first_column, \
++ (Loc).last_line, (Loc).last_column)
+ # else
+ # define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+ # endif
+ #endif
+
+
+-# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+-do { \
+- if (yydebug) \
+- { \
+- YYFPRINTF (stderr, "%s ", Title); \
+- yy_symbol_print (stderr, \
+- Type, Value, Location); \
+- YYFPRINTF (stderr, "\n"); \
+- } \
+-} while (0)
++/* YYLEX -- calling `yylex' with the right arguments. */
+
++#ifdef YYLEX_PARAM
++# define YYLEX yylex (YYLEX_PARAM)
++#else
++# define YYLEX yylex ()
++#endif
+
+-/*----------------------------------------.
+-| Print this symbol's value on YYOUTPUT. |
+-`----------------------------------------*/
++/* Enable debugging if requested. */
++#if YYDEBUG
+
++# ifndef YYFPRINTF
++# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
++# define YYFPRINTF fprintf
++# endif
++
++# define YYDPRINTF(Args) \
++do { \
++ if (yydebug) \
++ YYFPRINTF Args; \
++} while (YYID (0))
++
++# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
++do { \
++ if (yydebug) \
++ { \
++ YYFPRINTF (stderr, "%s ", Title); \
++ yy_symbol_print (stderr, \
++ Type, Value, Location); \
++ YYFPRINTF (stderr, "\n"); \
++ } \
++} while (YYID (0))
++
++
++/*--------------------------------.
++| Print this symbol on YYOUTPUT. |
++`--------------------------------*/
++
++/*ARGSUSED*/
++#if (defined __STDC__ || defined __C99__FUNC__ \
++ || defined __cplusplus || defined _MSC_VER)
+ static void
+ yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp)
++#else
++static void
++yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp)
++ FILE *yyoutput;
++ int yytype;
++ YYSTYPE const * const yyvaluep;
++ YYLTYPE const * const yylocationp;
++#endif
+ {
+- FILE *yyo = yyoutput;
+- YYUSE (yyo);
+- YYUSE (yylocationp);
+ if (!yyvaluep)
+ return;
++ YYUSE (yylocationp);
+ # ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
++# else
++ YYUSE (yyoutput);
+ # endif
+- YYUSE (yytype);
++ switch (yytype)
++ {
++ default:
++ break;
++ }
+ }
+
+
+@@ -853,11 +882,23 @@ yy_symbol_value_print (FILE *yyoutput, i
+ | Print this symbol on YYOUTPUT. |
+ `--------------------------------*/
+
++#if (defined __STDC__ || defined __C99__FUNC__ \
++ || defined __cplusplus || defined _MSC_VER)
+ static void
+ yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp)
++#else
++static void
++yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp)
++ FILE *yyoutput;
++ int yytype;
++ YYSTYPE const * const yyvaluep;
++ YYLTYPE const * const yylocationp;
++#endif
+ {
+- YYFPRINTF (yyoutput, "%s %s (",
+- yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]);
++ if (yytype < YYNTOKENS)
++ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
++ else
++ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ YY_LOCATION_PRINT (yyoutput, *yylocationp);
+ YYFPRINTF (yyoutput, ": ");
+@@ -870,8 +911,16 @@ yy_symbol_print (FILE *yyoutput, int yyt
+ | TOP (included). |
+ `------------------------------------------------------------------*/
+
++#if (defined __STDC__ || defined __C99__FUNC__ \
++ || defined __cplusplus || defined _MSC_VER)
+ static void
+ yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
++#else
++static void
++yy_stack_print (yybottom, yytop)
++ yytype_int16 *yybottom;
++ yytype_int16 *yytop;
++#endif
+ {
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+@@ -882,42 +931,50 @@ yy_stack_print (yytype_int16 *yybottom,
+ YYFPRINTF (stderr, "\n");
+ }
+
+-# define YY_STACK_PRINT(Bottom, Top) \
+-do { \
+- if (yydebug) \
+- yy_stack_print ((Bottom), (Top)); \
+-} while (0)
++# define YY_STACK_PRINT(Bottom, Top) \
++do { \
++ if (yydebug) \
++ yy_stack_print ((Bottom), (Top)); \
++} while (YYID (0))
+
+
+ /*------------------------------------------------.
+ | Report that the YYRULE is going to be reduced. |
+ `------------------------------------------------*/
+
++#if (defined __STDC__ || defined __C99__FUNC__ \
++ || defined __cplusplus || defined _MSC_VER)
++static void
++yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule)
++#else
+ static void
+-yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule)
++yy_reduce_print (yyvsp, yylsp, yyrule)
++ YYSTYPE *yyvsp;
++ YYLTYPE *yylsp;
++ int yyrule;
++#endif
+ {
+- unsigned long int yylno = yyrline[yyrule];
+ int yynrhs = yyr2[yyrule];
+ int yyi;
++ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+- yyrule - 1, yylno);
++ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+- yy_symbol_print (stderr,
+- yystos[yyssp[yyi + 1 - yynrhs]],
+- &(yyvsp[(yyi + 1) - (yynrhs)])
+- , &(yylsp[(yyi + 1) - (yynrhs)]) );
++ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
++ &(yyvsp[(yyi + 1) - (yynrhs)])
++ , &(yylsp[(yyi + 1) - (yynrhs)]) );
+ YYFPRINTF (stderr, "\n");
+ }
+ }
+
+-# define YY_REDUCE_PRINT(Rule) \
+-do { \
+- if (yydebug) \
+- yy_reduce_print (yyssp, yyvsp, yylsp, Rule); \
+-} while (0)
++# define YY_REDUCE_PRINT(Rule) \
++do { \
++ if (yydebug) \
++ yy_reduce_print (yyvsp, yylsp, Rule); \
++} while (YYID (0))
+
+ /* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+@@ -931,7 +988,7 @@ int yydebug;
+
+
+ /* YYINITDEPTH -- initial size of the parser's stacks. */
+-#ifndef YYINITDEPTH
++#ifndef YYINITDEPTH
+ # define YYINITDEPTH 200
+ #endif
+
+@@ -954,8 +1011,15 @@ int yydebug;
+ # define yystrlen strlen
+ # else
+ /* Return the length of YYSTR. */
++#if (defined __STDC__ || defined __C99__FUNC__ \
++ || defined __cplusplus || defined _MSC_VER)
+ static YYSIZE_T
+ yystrlen (const char *yystr)
++#else
++static YYSIZE_T
++yystrlen (yystr)
++ const char *yystr;
++#endif
+ {
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+@@ -971,8 +1035,16 @@ yystrlen (const char *yystr)
+ # else
+ /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
++#if (defined __STDC__ || defined __C99__FUNC__ \
++ || defined __cplusplus || defined _MSC_VER)
+ static char *
+ yystpcpy (char *yydest, const char *yysrc)
++#else
++static char *
++yystpcpy (yydest, yysrc)
++ char *yydest;
++ const char *yysrc;
++#endif
+ {
+ char *yyd = yydest;
+ const char *yys = yysrc;
+@@ -1002,27 +1074,27 @@ yytnamerr (char *yyres, const char *yyst
+ char const *yyp = yystr;
+
+ for (;;)
+- switch (*++yyp)
+- {
+- case '\'':
+- case ',':
+- goto do_not_strip_quotes;
+-
+- case '\\':
+- if (*++yyp != '\\')
+- goto do_not_strip_quotes;
+- /* Fall through. */
+- default:
+- if (yyres)
+- yyres[yyn] = *yyp;
+- yyn++;
+- break;
+-
+- case '"':
+- if (yyres)
+- yyres[yyn] = '\0';
+- return yyn;
+- }
++ switch (*++yyp)
++ {
++ case '\'':
++ case ',':
++ goto do_not_strip_quotes;
++
++ case '\\':
++ if (*++yyp != '\\')
++ goto do_not_strip_quotes;
++ /* Fall through. */
++ default:
++ if (yyres)
++ yyres[yyn] = *yyp;
++ yyn++;
++ break;
++
++ case '"':
++ if (yyres)
++ yyres[yyn] = '\0';
++ return yyn;
++ }
+ do_not_strip_quotes: ;
+ }
+
+@@ -1045,11 +1117,12 @@ static int
+ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
+ yytype_int16 *yyssp, int yytoken)
+ {
+- YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]);
++ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]);
+ YYSIZE_T yysize = yysize0;
++ YYSIZE_T yysize1;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ /* Internationalized format string. */
+- const char *yyformat = YY_NULLPTR;
++ const char *yyformat = 0;
+ /* Arguments of yyformat. */
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ /* Number of reported tokens (one for the "unexpected", one per
+@@ -1057,6 +1130,10 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, c
+ int yycount = 0;
+
+ /* There are many possibilities here to consider:
++ - Assume YYFAIL is not used. It's too flawed to consider. See
++ <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
++ for details. YYERROR is fine as it does not invoke this
++ function.
+ - If this state is a consistent state with a default action, then
+ the only way this function was invoked is if the default action
+ is an error action. In that case, don't check for expected
+@@ -1105,13 +1182,11 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, c
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+- {
+- YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]);
+- if (! (yysize <= yysize1
+- && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+- return 2;
+- yysize = yysize1;
+- }
++ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
++ if (! (yysize <= yysize1
++ && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
++ return 2;
++ yysize = yysize1;
+ }
+ }
+ }
+@@ -1131,12 +1206,10 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, c
+ # undef YYCASE_
+ }
+
+- {
+- YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
+- if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+- return 2;
+- yysize = yysize1;
+- }
++ yysize1 = yysize + yystrlen (yyformat);
++ if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
++ return 2;
++ yysize = yysize1;
+
+ if (*yymsg_alloc < yysize)
+ {
+@@ -1173,21 +1246,50 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, c
+ | Release the memory associated to this symbol. |
+ `-----------------------------------------------*/
+
++/*ARGSUSED*/
++#if (defined __STDC__ || defined __C99__FUNC__ \
++ || defined __cplusplus || defined _MSC_VER)
+ static void
+ yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp)
++#else
++static void
++yydestruct (yymsg, yytype, yyvaluep, yylocationp)
++ const char *yymsg;
++ int yytype;
++ YYSTYPE *yyvaluep;
++ YYLTYPE *yylocationp;
++#endif
+ {
+ YYUSE (yyvaluep);
+ YYUSE (yylocationp);
++
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+- YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+- YYUSE (yytype);
+- YY_IGNORE_MAYBE_UNINITIALIZED_END
++ switch (yytype)
++ {
++
++ default:
++ break;
++ }
+ }
+
+
++/* Prevent warnings from -Wmissing-prototypes. */
++#ifdef YYPARSE_PARAM
++#if defined __STDC__ || defined __cplusplus
++int yyparse (void *YYPARSE_PARAM);
++#else
++int yyparse ();
++#endif
++#else /* ! YYPARSE_PARAM */
++#if defined __STDC__ || defined __cplusplus
++int yyparse (void);
++#else
++int yyparse ();
++#endif
++#endif /* ! YYPARSE_PARAM */
+
+
+ /* The lookahead symbol. */
+@@ -1195,12 +1297,10 @@ int yychar;
+
+ /* The semantic value of the lookahead symbol. */
+ YYSTYPE yylval;
++
+ /* Location data for the lookahead symbol. */
+-YYLTYPE yylloc
+-# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+- = { 1, 1, 1, 1 }
+-# endif
+-;
++YYLTYPE yylloc;
++
+ /* Number of syntax errors so far. */
+ int yynerrs;
+
+@@ -1209,19 +1309,38 @@ int yynerrs;
+ | yyparse. |
+ `----------*/
+
++#ifdef YYPARSE_PARAM
++#if (defined __STDC__ || defined __C99__FUNC__ \
++ || defined __cplusplus || defined _MSC_VER)
++int
++yyparse (void *YYPARSE_PARAM)
++#else
++int
++yyparse (YYPARSE_PARAM)
++ void *YYPARSE_PARAM;
++#endif
++#else /* ! YYPARSE_PARAM */
++#if (defined __STDC__ || defined __C99__FUNC__ \
++ || defined __cplusplus || defined _MSC_VER)
+ int
+ yyparse (void)
++#else
++int
++yyparse ()
++
++#endif
++#endif
+ {
+ int yystate;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+
+ /* The stacks and their tools:
+- 'yyss': related to states.
+- 'yyvs': related to semantic values.
+- 'yyls': related to locations.
++ `yyss': related to states.
++ `yyvs': related to semantic values.
++ `yyls': related to locations.
+
+- Refer to the stacks through separate pointers, to allow yyoverflow
++ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+@@ -1247,7 +1366,7 @@ yyparse (void)
+ int yyn;
+ int yyresult;
+ /* Lookahead token as an internal (translated) token number. */
+- int yytoken = 0;
++ int yytoken;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+@@ -1266,9 +1385,10 @@ yyparse (void)
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+- yyssp = yyss = yyssa;
+- yyvsp = yyvs = yyvsa;
+- yylsp = yyls = yylsa;
++ yytoken = 0;
++ yyss = yyssa;
++ yyvs = yyvsa;
++ yyls = yylsa;
+ yystacksize = YYINITDEPTH;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+@@ -1277,7 +1397,21 @@ yyparse (void)
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+- yylsp[0] = yylloc;
++
++ /* Initialize stack pointers.
++ Waste one element of value and location stack
++ so that they stay on the same level as the state stack.
++ The wasted elements are never initialized. */
++ yyssp = yyss;
++ yyvsp = yyvs;
++ yylsp = yyls;
++
++#if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
++ /* Initialize the default location before parsing starts. */
++ yylloc.first_line = yylloc.last_line = 1;
++ yylloc.first_column = yylloc.last_column = 1;
++#endif
++
+ goto yysetstate;
+
+ /*------------------------------------------------------------.
+@@ -1298,26 +1432,26 @@ yyparse (void)
+
+ #ifdef yyoverflow
+ {
+- /* Give user a chance to reallocate the stack. Use copies of
+- these so that the &'s don't force the real ones into
+- memory. */
+- YYSTYPE *yyvs1 = yyvs;
+- yytype_int16 *yyss1 = yyss;
+- YYLTYPE *yyls1 = yyls;
+-
+- /* Each stack pointer address is followed by the size of the
+- data in use in that stack, in bytes. This used to be a
+- conditional around just the two extra args, but that might
+- be undefined if yyoverflow is a macro. */
+- yyoverflow (YY_("memory exhausted"),
+- &yyss1, yysize * sizeof (*yyssp),
+- &yyvs1, yysize * sizeof (*yyvsp),
+- &yyls1, yysize * sizeof (*yylsp),
+- &yystacksize);
+-
+- yyls = yyls1;
+- yyss = yyss1;
+- yyvs = yyvs1;
++ /* Give user a chance to reallocate the stack. Use copies of
++ these so that the &'s don't force the real ones into
++ memory. */
++ YYSTYPE *yyvs1 = yyvs;
++ yytype_int16 *yyss1 = yyss;
++ YYLTYPE *yyls1 = yyls;
++
++ /* Each stack pointer address is followed by the size of the
++ data in use in that stack, in bytes. This used to be a
++ conditional around just the two extra args, but that might
++ be undefined if yyoverflow is a macro. */
++ yyoverflow (YY_("memory exhausted"),
++ &yyss1, yysize * sizeof (*yyssp),
++ &yyvs1, yysize * sizeof (*yyvsp),
++ &yyls1, yysize * sizeof (*yylsp),
++ &yystacksize);
++
++ yyls = yyls1;
++ yyss = yyss1;
++ yyvs = yyvs1;
+ }
+ #else /* no yyoverflow */
+ # ifndef YYSTACK_RELOCATE
+@@ -1325,23 +1459,23 @@ yyparse (void)
+ # else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+- goto yyexhaustedlab;
++ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+- yystacksize = YYMAXDEPTH;
++ yystacksize = YYMAXDEPTH;
+
+ {
+- yytype_int16 *yyss1 = yyss;
+- union yyalloc *yyptr =
+- (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+- if (! yyptr)
+- goto yyexhaustedlab;
+- YYSTACK_RELOCATE (yyss_alloc, yyss);
+- YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+- YYSTACK_RELOCATE (yyls_alloc, yyls);
++ yytype_int16 *yyss1 = yyss;
++ union yyalloc *yyptr =
++ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
++ if (! yyptr)
++ goto yyexhaustedlab;
++ YYSTACK_RELOCATE (yyss_alloc, yyss);
++ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
++ YYSTACK_RELOCATE (yyls_alloc, yyls);
+ # undef YYSTACK_RELOCATE
+- if (yyss1 != yyssa)
+- YYSTACK_FREE (yyss1);
++ if (yyss1 != yyssa)
++ YYSTACK_FREE (yyss1);
+ }
+ # endif
+ #endif /* no yyoverflow */
+@@ -1351,10 +1485,10 @@ yyparse (void)
+ yylsp = yyls + yysize - 1;
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+- (unsigned long int) yystacksize));
++ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+- YYABORT;
++ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+@@ -1383,7 +1517,7 @@ yybackup:
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+- yychar = yylex ();
++ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+@@ -1423,9 +1557,7 @@ yybackup:
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+- YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+- YY_IGNORE_MAYBE_UNINITIALIZED_END
+ *++yylsp = yylloc;
+ goto yynewstate;
+
+@@ -1448,7 +1580,7 @@ yyreduce:
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+- '$$ = $1'.
++ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+@@ -1463,273 +1595,322 @@ yyreduce:
+ switch (yyn)
+ {
+ case 2:
+-#line 105 "dtc-parser.y" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 109 "dtc-parser.y"
+ {
+- the_boot_info = build_boot_info((yyvsp[-1].re), (yyvsp[0].node),
+- guess_boot_cpuid((yyvsp[0].node)));
++ (yyvsp[(5) - (5)].node)->is_plugin = (yyvsp[(3) - (5)].is_plugin);
++ (yyvsp[(5) - (5)].node)->is_root = 1;
++ the_boot_info = build_boot_info((yyvsp[(4) - (5)].re), (yyvsp[(5) - (5)].node),
++ guess_boot_cpuid((yyvsp[(5) - (5)].node)));
+ }
+-#line 1472 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 3:
+-#line 113 "dtc-parser.y" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 119 "dtc-parser.y"
+ {
+- (yyval.re) = NULL;
++ (yyval.is_plugin) = 0;
+ }
+-#line 1480 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 4:
+-#line 117 "dtc-parser.y" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 123 "dtc-parser.y"
+ {
+- (yyval.re) = chain_reserve_entry((yyvsp[-1].re), (yyvsp[0].re));
++ (yyval.is_plugin) = 1;
+ }
+-#line 1488 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 5:
+-#line 124 "dtc-parser.y" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 130 "dtc-parser.y"
+ {
+- (yyval.re) = build_reserve_entry((yyvsp[-2].integer), (yyvsp[-1].integer));
++ (yyval.re) = NULL;
+ }
+-#line 1496 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 6:
+-#line 128 "dtc-parser.y" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 134 "dtc-parser.y"
+ {
+- add_label(&(yyvsp[0].re)->labels, (yyvsp[-1].labelref));
+- (yyval.re) = (yyvsp[0].re);
++ (yyval.re) = chain_reserve_entry((yyvsp[(1) - (2)].re), (yyvsp[(2) - (2)].re));
+ }
+-#line 1505 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 7:
+-#line 136 "dtc-parser.y" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 141 "dtc-parser.y"
+ {
+- (yyval.node) = name_node((yyvsp[0].node), "");
++ (yyval.re) = build_reserve_entry((yyvsp[(2) - (4)].integer), (yyvsp[(3) - (4)].integer));
+ }
+-#line 1513 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 8:
+-#line 140 "dtc-parser.y" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 145 "dtc-parser.y"
+ {
+- (yyval.node) = merge_nodes((yyvsp[-2].node), (yyvsp[0].node));
++ add_label(&(yyvsp[(2) - (2)].re)->labels, (yyvsp[(1) - (2)].labelref));
++ (yyval.re) = (yyvsp[(2) - (2)].re);
+ }
+-#line 1521 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 9:
+-#line 145 "dtc-parser.y" /* yacc.c:1646 */
+- {
+- struct node *target = get_node_by_ref((yyvsp[-3].node), (yyvsp[-1].labelref));
+
+- add_label(&target->labels, (yyvsp[-2].labelref));
+- if (target)
+- merge_nodes(target, (yyvsp[0].node));
+- else
+- ERROR(&(yylsp[-1]), "Label or path %s not found", (yyvsp[-1].labelref));
+- (yyval.node) = (yyvsp[-3].node);
++/* Line 1806 of yacc.c */
++#line 153 "dtc-parser.y"
++ {
++ (yyval.node) = name_node((yyvsp[(2) - (2)].node), "");
+ }
+-#line 1536 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 10:
+-#line 156 "dtc-parser.y" /* yacc.c:1646 */
+- {
+- struct node *target = get_node_by_ref((yyvsp[-2].node), (yyvsp[-1].labelref));
+
+- if (target)
+- merge_nodes(target, (yyvsp[0].node));
+- else
+- ERROR(&(yylsp[-1]), "Label or path %s not found", (yyvsp[-1].labelref));
+- (yyval.node) = (yyvsp[-2].node);
++/* Line 1806 of yacc.c */
++#line 157 "dtc-parser.y"
++ {
++ (yyval.node) = merge_nodes((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+-#line 1550 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 11:
+-#line 166 "dtc-parser.y" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 162 "dtc-parser.y"
+ {
+- struct node *target = get_node_by_ref((yyvsp[-3].node), (yyvsp[-1].labelref));
++ struct node *target = get_node_by_ref((yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].labelref));
+
++ add_label(&target->labels, (yyvsp[(2) - (4)].labelref));
+ if (target)
+- delete_node(target);
++ merge_nodes(target, (yyvsp[(4) - (4)].node));
+ else
+- ERROR(&(yylsp[-1]), "Label or path %s not found", (yyvsp[-1].labelref));
+-
+-
+- (yyval.node) = (yyvsp[-3].node);
++ ERROR(&(yylsp[(3) - (4)]), "Label or path %s not found", (yyvsp[(3) - (4)].labelref));
++ (yyval.node) = (yyvsp[(1) - (4)].node);
+ }
+-#line 1566 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 12:
+-#line 181 "dtc-parser.y" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 173 "dtc-parser.y"
+ {
+- (yyval.node) = build_node((yyvsp[-3].proplist), (yyvsp[-2].nodelist));
++ struct node *target = get_node_by_ref((yyvsp[(1) - (3)].node), (yyvsp[(2) - (3)].labelref));
++
++ if (target)
++ merge_nodes(target, (yyvsp[(3) - (3)].node));
++ else
++ ERROR(&(yylsp[(2) - (3)]), "Label or path %s not found", (yyvsp[(2) - (3)].labelref));
++ (yyval.node) = (yyvsp[(1) - (3)].node);
+ }
+-#line 1574 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 13:
+-#line 188 "dtc-parser.y" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 183 "dtc-parser.y"
+ {
+- (yyval.proplist) = NULL;
++ struct node *target = get_node_by_ref((yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].labelref));
++
++ if (target)
++ delete_node(target);
++ else
++ ERROR(&(yylsp[(3) - (4)]), "Label or path %s not found", (yyvsp[(3) - (4)].labelref));
++
++
++ (yyval.node) = (yyvsp[(1) - (4)].node);
+ }
+-#line 1582 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 14:
+-#line 192 "dtc-parser.y" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 198 "dtc-parser.y"
+ {
+- (yyval.proplist) = chain_property((yyvsp[0].prop), (yyvsp[-1].proplist));
++ (yyval.node) = build_node((yyvsp[(2) - (5)].proplist), (yyvsp[(3) - (5)].nodelist));
+ }
+-#line 1590 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 15:
+-#line 199 "dtc-parser.y" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 205 "dtc-parser.y"
+ {
+- (yyval.prop) = build_property((yyvsp[-3].propnodename), (yyvsp[-1].data));
++ (yyval.proplist) = NULL;
+ }
+-#line 1598 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 16:
+-#line 203 "dtc-parser.y" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 209 "dtc-parser.y"
+ {
+- (yyval.prop) = build_property((yyvsp[-1].propnodename), empty_data);
++ (yyval.proplist) = chain_property((yyvsp[(2) - (2)].prop), (yyvsp[(1) - (2)].proplist));
+ }
+-#line 1606 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 17:
+-#line 207 "dtc-parser.y" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 216 "dtc-parser.y"
+ {
+- (yyval.prop) = build_property_delete((yyvsp[-1].propnodename));
++ (yyval.prop) = build_property((yyvsp[(1) - (4)].propnodename), (yyvsp[(3) - (4)].data));
+ }
+-#line 1614 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 18:
+-#line 211 "dtc-parser.y" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 220 "dtc-parser.y"
+ {
+- add_label(&(yyvsp[0].prop)->labels, (yyvsp[-1].labelref));
+- (yyval.prop) = (yyvsp[0].prop);
++ (yyval.prop) = build_property((yyvsp[(1) - (2)].propnodename), empty_data);
+ }
+-#line 1623 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 19:
+-#line 219 "dtc-parser.y" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 224 "dtc-parser.y"
+ {
+- (yyval.data) = data_merge((yyvsp[-1].data), (yyvsp[0].data));
++ (yyval.prop) = build_property_delete((yyvsp[(2) - (3)].propnodename));
+ }
+-#line 1631 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 20:
+-#line 223 "dtc-parser.y" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 228 "dtc-parser.y"
+ {
+- (yyval.data) = data_merge((yyvsp[-2].data), (yyvsp[-1].array).data);
++ add_label(&(yyvsp[(2) - (2)].prop)->labels, (yyvsp[(1) - (2)].labelref));
++ (yyval.prop) = (yyvsp[(2) - (2)].prop);
+ }
+-#line 1639 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 21:
+-#line 227 "dtc-parser.y" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 236 "dtc-parser.y"
+ {
+- (yyval.data) = data_merge((yyvsp[-3].data), (yyvsp[-1].data));
++ (yyval.data) = data_merge((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].data));
+ }
+-#line 1647 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 22:
+-#line 231 "dtc-parser.y" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 240 "dtc-parser.y"
+ {
+- (yyval.data) = data_add_marker((yyvsp[-1].data), REF_PATH, (yyvsp[0].labelref));
++ (yyval.data) = data_merge((yyvsp[(1) - (3)].data), (yyvsp[(2) - (3)].array).data);
+ }
+-#line 1655 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 23:
+-#line 235 "dtc-parser.y" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 244 "dtc-parser.y"
++ {
++ (yyval.data) = data_merge((yyvsp[(1) - (4)].data), (yyvsp[(3) - (4)].data));
++ }
++ break;
++
++ case 24:
++
++/* Line 1806 of yacc.c */
++#line 248 "dtc-parser.y"
++ {
++ (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), REF_PATH, (yyvsp[(2) - (2)].labelref));
++ }
++ break;
++
++ case 25:
++
++/* Line 1806 of yacc.c */
++#line 252 "dtc-parser.y"
+ {
+- FILE *f = srcfile_relative_open((yyvsp[-5].data).val, NULL);
++ FILE *f = srcfile_relative_open((yyvsp[(4) - (9)].data).val, NULL);
+ struct data d;
+
+- if ((yyvsp[-3].integer) != 0)
+- if (fseek(f, (yyvsp[-3].integer), SEEK_SET) != 0)
++ if ((yyvsp[(6) - (9)].integer) != 0)
++ if (fseek(f, (yyvsp[(6) - (9)].integer), SEEK_SET) != 0)
+ die("Couldn't seek to offset %llu in \"%s\": %s",
+- (unsigned long long)(yyvsp[-3].integer), (yyvsp[-5].data).val,
++ (unsigned long long)(yyvsp[(6) - (9)].integer), (yyvsp[(4) - (9)].data).val,
+ strerror(errno));
+
+- d = data_copy_file(f, (yyvsp[-1].integer));
++ d = data_copy_file(f, (yyvsp[(8) - (9)].integer));
+
+- (yyval.data) = data_merge((yyvsp[-8].data), d);
++ (yyval.data) = data_merge((yyvsp[(1) - (9)].data), d);
+ fclose(f);
+ }
+-#line 1675 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 24:
+-#line 251 "dtc-parser.y" /* yacc.c:1646 */
++ case 26:
++
++/* Line 1806 of yacc.c */
++#line 268 "dtc-parser.y"
+ {
+- FILE *f = srcfile_relative_open((yyvsp[-1].data).val, NULL);
++ FILE *f = srcfile_relative_open((yyvsp[(4) - (5)].data).val, NULL);
+ struct data d = empty_data;
+
+ d = data_copy_file(f, -1);
+
+- (yyval.data) = data_merge((yyvsp[-4].data), d);
++ (yyval.data) = data_merge((yyvsp[(1) - (5)].data), d);
+ fclose(f);
+ }
+-#line 1689 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 25:
+-#line 261 "dtc-parser.y" /* yacc.c:1646 */
++ case 27:
++
++/* Line 1806 of yacc.c */
++#line 278 "dtc-parser.y"
+ {
+- (yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref));
++ (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref));
+ }
+-#line 1697 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 26:
+-#line 268 "dtc-parser.y" /* yacc.c:1646 */
++ case 28:
++
++/* Line 1806 of yacc.c */
++#line 285 "dtc-parser.y"
+ {
+ (yyval.data) = empty_data;
+ }
+-#line 1705 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 27:
+-#line 272 "dtc-parser.y" /* yacc.c:1646 */
++ case 29:
++
++/* Line 1806 of yacc.c */
++#line 289 "dtc-parser.y"
+ {
+- (yyval.data) = (yyvsp[-1].data);
++ (yyval.data) = (yyvsp[(1) - (2)].data);
+ }
+-#line 1713 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 28:
+-#line 276 "dtc-parser.y" /* yacc.c:1646 */
++ case 30:
++
++/* Line 1806 of yacc.c */
++#line 293 "dtc-parser.y"
+ {
+- (yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref));
++ (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref));
+ }
+-#line 1721 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 29:
+-#line 283 "dtc-parser.y" /* yacc.c:1646 */
++ case 31:
++
++/* Line 1806 of yacc.c */
++#line 300 "dtc-parser.y"
+ {
+ unsigned long long bits;
+
+- bits = (yyvsp[-1].integer);
++ bits = (yyvsp[(2) - (3)].integer);
+
+ if ((bits != 8) && (bits != 16) &&
+ (bits != 32) && (bits != 64)) {
+- ERROR(&(yylsp[-1]), "Array elements must be"
++ ERROR(&(yylsp[(2) - (3)]), "Array elements must be"
+ " 8, 16, 32 or 64-bits");
+ bits = 32;
+ }
+@@ -1737,23 +1918,25 @@ yyreduce:
+ (yyval.array).data = empty_data;
+ (yyval.array).bits = bits;
+ }
+-#line 1741 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 30:
+-#line 299 "dtc-parser.y" /* yacc.c:1646 */
++ case 32:
++
++/* Line 1806 of yacc.c */
++#line 316 "dtc-parser.y"
+ {
+ (yyval.array).data = empty_data;
+ (yyval.array).bits = 32;
+ }
+-#line 1750 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 31:
+-#line 304 "dtc-parser.y" /* yacc.c:1646 */
++ case 33:
++
++/* Line 1806 of yacc.c */
++#line 321 "dtc-parser.y"
+ {
+- if ((yyvsp[-1].array).bits < 64) {
+- uint64_t mask = (1ULL << (yyvsp[-1].array).bits) - 1;
++ if ((yyvsp[(1) - (2)].array).bits < 64) {
++ uint64_t mask = (1ULL << (yyvsp[(1) - (2)].array).bits) - 1;
+ /*
+ * Bits above mask must either be all zero
+ * (positive within range of mask) or all one
+@@ -1762,258 +1945,293 @@ yyreduce:
+ * within the mask to one (i.e. | in the
+ * mask), all bits are one.
+ */
+- if (((yyvsp[0].integer) > mask) && (((yyvsp[0].integer) | mask) != -1ULL))
+- ERROR(&(yylsp[0]), "Value out of range for"
+- " %d-bit array element", (yyvsp[-1].array).bits);
++ if (((yyvsp[(2) - (2)].integer) > mask) && (((yyvsp[(2) - (2)].integer) | mask) != -1ULL))
++ ERROR(&(yylsp[(2) - (2)]), "Value out of range for"
++ " %d-bit array element", (yyvsp[(1) - (2)].array).bits);
+ }
+
+- (yyval.array).data = data_append_integer((yyvsp[-1].array).data, (yyvsp[0].integer), (yyvsp[-1].array).bits);
++ (yyval.array).data = data_append_integer((yyvsp[(1) - (2)].array).data, (yyvsp[(2) - (2)].integer), (yyvsp[(1) - (2)].array).bits);
+ }
+-#line 1773 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 32:
+-#line 323 "dtc-parser.y" /* yacc.c:1646 */
++ case 34:
++
++/* Line 1806 of yacc.c */
++#line 340 "dtc-parser.y"
+ {
+- uint64_t val = ~0ULL >> (64 - (yyvsp[-1].array).bits);
++ uint64_t val = ~0ULL >> (64 - (yyvsp[(1) - (2)].array).bits);
+
+- if ((yyvsp[-1].array).bits == 32)
+- (yyvsp[-1].array).data = data_add_marker((yyvsp[-1].array).data,
++ if ((yyvsp[(1) - (2)].array).bits == 32)
++ (yyvsp[(1) - (2)].array).data = data_add_marker((yyvsp[(1) - (2)].array).data,
+ REF_PHANDLE,
+- (yyvsp[0].labelref));
++ (yyvsp[(2) - (2)].labelref));
+ else
+- ERROR(&(yylsp[0]), "References are only allowed in "
++ ERROR(&(yylsp[(2) - (2)]), "References are only allowed in "
+ "arrays with 32-bit elements.");
+
+- (yyval.array).data = data_append_integer((yyvsp[-1].array).data, val, (yyvsp[-1].array).bits);
++ (yyval.array).data = data_append_integer((yyvsp[(1) - (2)].array).data, val, (yyvsp[(1) - (2)].array).bits);
+ }
+-#line 1791 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 33:
+-#line 337 "dtc-parser.y" /* yacc.c:1646 */
++ case 35:
++
++/* Line 1806 of yacc.c */
++#line 354 "dtc-parser.y"
+ {
+- (yyval.array).data = data_add_marker((yyvsp[-1].array).data, LABEL, (yyvsp[0].labelref));
++ (yyval.array).data = data_add_marker((yyvsp[(1) - (2)].array).data, LABEL, (yyvsp[(2) - (2)].labelref));
+ }
+-#line 1799 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 36:
+-#line 346 "dtc-parser.y" /* yacc.c:1646 */
++ case 38:
++
++/* Line 1806 of yacc.c */
++#line 363 "dtc-parser.y"
+ {
+- (yyval.integer) = (yyvsp[-1].integer);
++ (yyval.integer) = (yyvsp[(2) - (3)].integer);
+ }
+-#line 1807 "dtc-parser.tab.c" /* yacc.c:1646 */
+- break;
+-
+- case 39:
+-#line 357 "dtc-parser.y" /* yacc.c:1646 */
+- { (yyval.integer) = (yyvsp[-4].integer) ? (yyvsp[-2].integer) : (yyvsp[0].integer); }
+-#line 1813 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 41:
+-#line 362 "dtc-parser.y" /* yacc.c:1646 */
+- { (yyval.integer) = (yyvsp[-2].integer) || (yyvsp[0].integer); }
+-#line 1819 "dtc-parser.tab.c" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 374 "dtc-parser.y"
++ { (yyval.integer) = (yyvsp[(1) - (5)].integer) ? (yyvsp[(3) - (5)].integer) : (yyvsp[(5) - (5)].integer); }
+ break;
+
+ case 43:
+-#line 367 "dtc-parser.y" /* yacc.c:1646 */
+- { (yyval.integer) = (yyvsp[-2].integer) && (yyvsp[0].integer); }
+-#line 1825 "dtc-parser.tab.c" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 379 "dtc-parser.y"
++ { (yyval.integer) = (yyvsp[(1) - (3)].integer) || (yyvsp[(3) - (3)].integer); }
+ break;
+
+ case 45:
+-#line 372 "dtc-parser.y" /* yacc.c:1646 */
+- { (yyval.integer) = (yyvsp[-2].integer) | (yyvsp[0].integer); }
+-#line 1831 "dtc-parser.tab.c" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 384 "dtc-parser.y"
++ { (yyval.integer) = (yyvsp[(1) - (3)].integer) && (yyvsp[(3) - (3)].integer); }
+ break;
+
+ case 47:
+-#line 377 "dtc-parser.y" /* yacc.c:1646 */
+- { (yyval.integer) = (yyvsp[-2].integer) ^ (yyvsp[0].integer); }
+-#line 1837 "dtc-parser.tab.c" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 389 "dtc-parser.y"
++ { (yyval.integer) = (yyvsp[(1) - (3)].integer) | (yyvsp[(3) - (3)].integer); }
+ break;
+
+ case 49:
+-#line 382 "dtc-parser.y" /* yacc.c:1646 */
+- { (yyval.integer) = (yyvsp[-2].integer) & (yyvsp[0].integer); }
+-#line 1843 "dtc-parser.tab.c" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 394 "dtc-parser.y"
++ { (yyval.integer) = (yyvsp[(1) - (3)].integer) ^ (yyvsp[(3) - (3)].integer); }
+ break;
+
+ case 51:
+-#line 387 "dtc-parser.y" /* yacc.c:1646 */
+- { (yyval.integer) = (yyvsp[-2].integer) == (yyvsp[0].integer); }
+-#line 1849 "dtc-parser.tab.c" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 399 "dtc-parser.y"
++ { (yyval.integer) = (yyvsp[(1) - (3)].integer) & (yyvsp[(3) - (3)].integer); }
+ break;
+
+- case 52:
+-#line 388 "dtc-parser.y" /* yacc.c:1646 */
+- { (yyval.integer) = (yyvsp[-2].integer) != (yyvsp[0].integer); }
+-#line 1855 "dtc-parser.tab.c" /* yacc.c:1646 */
++ case 53:
++
++/* Line 1806 of yacc.c */
++#line 404 "dtc-parser.y"
++ { (yyval.integer) = (yyvsp[(1) - (3)].integer) == (yyvsp[(3) - (3)].integer); }
+ break;
+
+ case 54:
+-#line 393 "dtc-parser.y" /* yacc.c:1646 */
+- { (yyval.integer) = (yyvsp[-2].integer) < (yyvsp[0].integer); }
+-#line 1861 "dtc-parser.tab.c" /* yacc.c:1646 */
+- break;
+
+- case 55:
+-#line 394 "dtc-parser.y" /* yacc.c:1646 */
+- { (yyval.integer) = (yyvsp[-2].integer) > (yyvsp[0].integer); }
+-#line 1867 "dtc-parser.tab.c" /* yacc.c:1646 */
++/* Line 1806 of yacc.c */
++#line 405 "dtc-parser.y"
++ { (yyval.integer) = (yyvsp[(1) - (3)].integer) != (yyvsp[(3) - (3)].integer); }
+ break;
+
+ case 56:
+-#line 395 "dtc-parser.y" /* yacc.c:1646 */
+- { (yyval.integer) = (yyvsp[-2].integer) <= (yyvsp[0].integer); }
+-#line 1873 "dtc-parser.tab.c" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 410 "dtc-parser.y"
++ { (yyval.integer) = (yyvsp[(1) - (3)].integer) < (yyvsp[(3) - (3)].integer); }
+ break;
+
+ case 57:
+-#line 396 "dtc-parser.y" /* yacc.c:1646 */
+- { (yyval.integer) = (yyvsp[-2].integer) >= (yyvsp[0].integer); }
+-#line 1879 "dtc-parser.tab.c" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 411 "dtc-parser.y"
++ { (yyval.integer) = (yyvsp[(1) - (3)].integer) > (yyvsp[(3) - (3)].integer); }
+ break;
+
+ case 58:
+-#line 400 "dtc-parser.y" /* yacc.c:1646 */
+- { (yyval.integer) = (yyvsp[-2].integer) << (yyvsp[0].integer); }
+-#line 1885 "dtc-parser.tab.c" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 412 "dtc-parser.y"
++ { (yyval.integer) = (yyvsp[(1) - (3)].integer) <= (yyvsp[(3) - (3)].integer); }
+ break;
+
+ case 59:
+-#line 401 "dtc-parser.y" /* yacc.c:1646 */
+- { (yyval.integer) = (yyvsp[-2].integer) >> (yyvsp[0].integer); }
+-#line 1891 "dtc-parser.tab.c" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 413 "dtc-parser.y"
++ { (yyval.integer) = (yyvsp[(1) - (3)].integer) >= (yyvsp[(3) - (3)].integer); }
++ break;
++
++ case 60:
++
++/* Line 1806 of yacc.c */
++#line 417 "dtc-parser.y"
++ { (yyval.integer) = (yyvsp[(1) - (3)].integer) << (yyvsp[(3) - (3)].integer); }
+ break;
+
+ case 61:
+-#line 406 "dtc-parser.y" /* yacc.c:1646 */
+- { (yyval.integer) = (yyvsp[-2].integer) + (yyvsp[0].integer); }
+-#line 1897 "dtc-parser.tab.c" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 418 "dtc-parser.y"
++ { (yyval.integer) = (yyvsp[(1) - (3)].integer) >> (yyvsp[(3) - (3)].integer); }
+ break;
+
+- case 62:
+-#line 407 "dtc-parser.y" /* yacc.c:1646 */
+- { (yyval.integer) = (yyvsp[-2].integer) - (yyvsp[0].integer); }
+-#line 1903 "dtc-parser.tab.c" /* yacc.c:1646 */
++ case 63:
++
++/* Line 1806 of yacc.c */
++#line 423 "dtc-parser.y"
++ { (yyval.integer) = (yyvsp[(1) - (3)].integer) + (yyvsp[(3) - (3)].integer); }
+ break;
+
+ case 64:
+-#line 412 "dtc-parser.y" /* yacc.c:1646 */
+- { (yyval.integer) = (yyvsp[-2].integer) * (yyvsp[0].integer); }
+-#line 1909 "dtc-parser.tab.c" /* yacc.c:1646 */
+- break;
+
+- case 65:
+-#line 413 "dtc-parser.y" /* yacc.c:1646 */
+- { (yyval.integer) = (yyvsp[-2].integer) / (yyvsp[0].integer); }
+-#line 1915 "dtc-parser.tab.c" /* yacc.c:1646 */
++/* Line 1806 of yacc.c */
++#line 424 "dtc-parser.y"
++ { (yyval.integer) = (yyvsp[(1) - (3)].integer) - (yyvsp[(3) - (3)].integer); }
+ break;
+
+ case 66:
+-#line 414 "dtc-parser.y" /* yacc.c:1646 */
+- { (yyval.integer) = (yyvsp[-2].integer) % (yyvsp[0].integer); }
+-#line 1921 "dtc-parser.tab.c" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 429 "dtc-parser.y"
++ { (yyval.integer) = (yyvsp[(1) - (3)].integer) * (yyvsp[(3) - (3)].integer); }
+ break;
+
+- case 69:
+-#line 420 "dtc-parser.y" /* yacc.c:1646 */
+- { (yyval.integer) = -(yyvsp[0].integer); }
+-#line 1927 "dtc-parser.tab.c" /* yacc.c:1646 */
++ case 67:
++
++/* Line 1806 of yacc.c */
++#line 430 "dtc-parser.y"
++ { (yyval.integer) = (yyvsp[(1) - (3)].integer) / (yyvsp[(3) - (3)].integer); }
+ break;
+
+- case 70:
+-#line 421 "dtc-parser.y" /* yacc.c:1646 */
+- { (yyval.integer) = ~(yyvsp[0].integer); }
+-#line 1933 "dtc-parser.tab.c" /* yacc.c:1646 */
++ case 68:
++
++/* Line 1806 of yacc.c */
++#line 431 "dtc-parser.y"
++ { (yyval.integer) = (yyvsp[(1) - (3)].integer) % (yyvsp[(3) - (3)].integer); }
+ break;
+
+ case 71:
+-#line 422 "dtc-parser.y" /* yacc.c:1646 */
+- { (yyval.integer) = !(yyvsp[0].integer); }
+-#line 1939 "dtc-parser.tab.c" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 437 "dtc-parser.y"
++ { (yyval.integer) = -(yyvsp[(2) - (2)].integer); }
+ break;
+
+ case 72:
+-#line 427 "dtc-parser.y" /* yacc.c:1646 */
+- {
+- (yyval.data) = empty_data;
+- }
+-#line 1947 "dtc-parser.tab.c" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 438 "dtc-parser.y"
++ { (yyval.integer) = ~(yyvsp[(2) - (2)].integer); }
+ break;
+
+ case 73:
+-#line 431 "dtc-parser.y" /* yacc.c:1646 */
+- {
+- (yyval.data) = data_append_byte((yyvsp[-1].data), (yyvsp[0].byte));
+- }
+-#line 1955 "dtc-parser.tab.c" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 439 "dtc-parser.y"
++ { (yyval.integer) = !(yyvsp[(2) - (2)].integer); }
+ break;
+
+ case 74:
+-#line 435 "dtc-parser.y" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 444 "dtc-parser.y"
+ {
+- (yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref));
++ (yyval.data) = empty_data;
+ }
+-#line 1963 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 75:
+-#line 442 "dtc-parser.y" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 448 "dtc-parser.y"
+ {
+- (yyval.nodelist) = NULL;
++ (yyval.data) = data_append_byte((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].byte));
+ }
+-#line 1971 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 76:
+-#line 446 "dtc-parser.y" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 452 "dtc-parser.y"
+ {
+- (yyval.nodelist) = chain_node((yyvsp[-1].node), (yyvsp[0].nodelist));
++ (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref));
+ }
+-#line 1979 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 77:
+-#line 450 "dtc-parser.y" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 459 "dtc-parser.y"
+ {
+- ERROR(&(yylsp[0]), "Properties must precede subnodes");
+- YYERROR;
++ (yyval.nodelist) = NULL;
+ }
+-#line 1988 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 78:
+-#line 458 "dtc-parser.y" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 463 "dtc-parser.y"
+ {
+- (yyval.node) = name_node((yyvsp[0].node), (yyvsp[-1].propnodename));
++ (yyval.nodelist) = chain_node((yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].nodelist));
+ }
+-#line 1996 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 79:
+-#line 462 "dtc-parser.y" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 467 "dtc-parser.y"
+ {
+- (yyval.node) = name_node(build_node_delete(), (yyvsp[-1].propnodename));
++ ERROR(&(yylsp[(2) - (2)]), "Properties must precede subnodes");
++ YYERROR;
+ }
+-#line 2004 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 80:
+-#line 466 "dtc-parser.y" /* yacc.c:1646 */
++
++/* Line 1806 of yacc.c */
++#line 475 "dtc-parser.y"
+ {
+- add_label(&(yyvsp[0].node)->labels, (yyvsp[-1].labelref));
+- (yyval.node) = (yyvsp[0].node);
++ (yyval.node) = name_node((yyvsp[(2) - (2)].node), (yyvsp[(1) - (2)].propnodename));
+ }
+-#line 2013 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
++ case 81:
+
+-#line 2017 "dtc-parser.tab.c" /* yacc.c:1646 */
++/* Line 1806 of yacc.c */
++#line 479 "dtc-parser.y"
++ {
++ (yyval.node) = name_node(build_node_delete(), (yyvsp[(2) - (3)].propnodename));
++ }
++ break;
++
++ case 82:
++
++/* Line 1806 of yacc.c */
++#line 483 "dtc-parser.y"
++ {
++ add_label(&(yyvsp[(2) - (2)].node)->labels, (yyvsp[(1) - (2)].labelref));
++ (yyval.node) = (yyvsp[(2) - (2)].node);
++ }
++ break;
++
++
++
++/* Line 1806 of yacc.c */
++#line 2235 "dtc-parser.tab.c"
+ default: break;
+ }
+ /* User semantic actions sometimes alter yychar, and that requires
+@@ -2036,7 +2254,7 @@ yyreduce:
+ *++yyvsp = yyval;
+ *++yylsp = yyloc;
+
+- /* Now 'shift' the result of the reduction. Determine what state
++ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+@@ -2051,9 +2269,9 @@ yyreduce:
+ goto yynewstate;
+
+
+-/*--------------------------------------.
+-| yyerrlab -- here on detecting error. |
+-`--------------------------------------*/
++/*------------------------------------.
++| yyerrlab -- here on detecting error |
++`------------------------------------*/
+ yyerrlab:
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+@@ -2104,20 +2322,20 @@ yyerrlab:
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+- error, discard it. */
++ error, discard it. */
+
+ if (yychar <= YYEOF)
+- {
+- /* Return failure if at end of input. */
+- if (yychar == YYEOF)
+- YYABORT;
+- }
++ {
++ /* Return failure if at end of input. */
++ if (yychar == YYEOF)
++ YYABORT;
++ }
+ else
+- {
+- yydestruct ("Error: discarding",
+- yytoken, &yylval, &yylloc);
+- yychar = YYEMPTY;
+- }
++ {
++ yydestruct ("Error: discarding",
++ yytoken, &yylval, &yylloc);
++ yychar = YYEMPTY;
++ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+@@ -2137,7 +2355,7 @@ yyerrorlab:
+ goto yyerrorlab;
+
+ yyerror_range[1] = yylsp[1-yylen];
+- /* Do not reclaim the symbols of the rule whose action triggered
++ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+@@ -2150,37 +2368,35 @@ yyerrorlab:
+ | yyerrlab1 -- common code for both syntax error and YYERROR. |
+ `-------------------------------------------------------------*/
+ yyerrlab1:
+- yyerrstatus = 3; /* Each real token shifted decrements this. */
++ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (!yypact_value_is_default (yyn))
+- {
+- yyn += YYTERROR;
+- if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+- {
+- yyn = yytable[yyn];
+- if (0 < yyn)
+- break;
+- }
+- }
++ {
++ yyn += YYTERROR;
++ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
++ {
++ yyn = yytable[yyn];
++ if (0 < yyn)
++ break;
++ }
++ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+- YYABORT;
++ YYABORT;
+
+ yyerror_range[1] = *yylsp;
+ yydestruct ("Error: popping",
+- yystos[yystate], yyvsp, yylsp);
++ yystos[yystate], yyvsp, yylsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+- YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+- YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+ yyerror_range[2] = yylloc;
+ /* Using YYLLOC is tempting, but would change the location of
+@@ -2209,7 +2425,7 @@ yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+-#if !defined yyoverflow || YYERROR_VERBOSE
++#if !defined(yyoverflow) || YYERROR_VERBOSE
+ /*-------------------------------------------------.
+ | yyexhaustedlab -- memory exhaustion comes here. |
+ `-------------------------------------------------*/
+@@ -2228,14 +2444,14 @@ yyreturn:
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval, &yylloc);
+ }
+- /* Do not reclaim the symbols of the rule whose action triggered
++ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+- yystos[*yyssp], yyvsp, yylsp);
++ yystos[*yyssp], yyvsp, yylsp);
+ YYPOPSTACK (1);
+ }
+ #ifndef yyoverflow
+@@ -2246,12 +2462,18 @@ yyreturn:
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ #endif
+- return yyresult;
++ /* Make sure YYID is used. */
++ return YYID (yyresult);
+ }
+-#line 472 "dtc-parser.y" /* yacc.c:1906 */
++
++
++
++/* Line 2067 of yacc.c */
++#line 489 "dtc-parser.y"
+
+
+ void yyerror(char const *s)
+ {
+ ERROR(&yylloc, "%s", s);
+ }
++
+--- a/scripts/dtc/dtc-parser.tab.h_shipped
++++ b/scripts/dtc/dtc-parser.tab.h_shipped
+@@ -1,19 +1,19 @@
+-/* A Bison parser, made by GNU Bison 3.0.2. */
++/* A Bison parser, made by GNU Bison 2.5. */
+
+ /* Bison interface for Yacc-like parsers in C
+-
+- Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
+-
++
++ Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
++
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. */
+
+@@ -26,55 +26,50 @@
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+-
++
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+-#ifndef YY_YY_DTC_PARSER_TAB_H_INCLUDED
+-# define YY_YY_DTC_PARSER_TAB_H_INCLUDED
+-/* Debug traces. */
+-#ifndef YYDEBUG
+-# define YYDEBUG 0
+-#endif
+-#if YYDEBUG
+-extern int yydebug;
+-#endif
+
+-/* Token type. */
++/* Tokens. */
+ #ifndef YYTOKENTYPE
+ # define YYTOKENTYPE
+- enum yytokentype
+- {
+- DT_V1 = 258,
+- DT_MEMRESERVE = 259,
+- DT_LSHIFT = 260,
+- DT_RSHIFT = 261,
+- DT_LE = 262,
+- DT_GE = 263,
+- DT_EQ = 264,
+- DT_NE = 265,
+- DT_AND = 266,
+- DT_OR = 267,
+- DT_BITS = 268,
+- DT_DEL_PROP = 269,
+- DT_DEL_NODE = 270,
+- DT_PROPNODENAME = 271,
+- DT_LITERAL = 272,
+- DT_CHAR_LITERAL = 273,
+- DT_BYTE = 274,
+- DT_STRING = 275,
+- DT_LABEL = 276,
+- DT_REF = 277,
+- DT_INCBIN = 278
+- };
++ /* Put the tokens into the symbol table, so that GDB and other debuggers
++ know about them. */
++ enum yytokentype {
++ DT_V1 = 258,
++ DT_PLUGIN = 259,
++ DT_MEMRESERVE = 260,
++ DT_LSHIFT = 261,
++ DT_RSHIFT = 262,
++ DT_LE = 263,
++ DT_GE = 264,
++ DT_EQ = 265,
++ DT_NE = 266,
++ DT_AND = 267,
++ DT_OR = 268,
++ DT_BITS = 269,
++ DT_DEL_PROP = 270,
++ DT_DEL_NODE = 271,
++ DT_PROPNODENAME = 272,
++ DT_LITERAL = 273,
++ DT_CHAR_LITERAL = 274,
++ DT_BYTE = 275,
++ DT_STRING = 276,
++ DT_LABEL = 277,
++ DT_REF = 278,
++ DT_INCBIN = 279
++ };
+ #endif
+
+-/* Value type. */
++
++
+ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+-typedef union YYSTYPE YYSTYPE;
+-union YYSTYPE
++typedef union YYSTYPE
+ {
+-#line 38 "dtc-parser.y" /* yacc.c:1909 */
++
++/* Line 2068 of yacc.c */
++#line 39 "dtc-parser.y"
+
+ char *propnodename;
+ char *labelref;
+@@ -92,30 +87,32 @@ union YYSTYPE
+ struct node *nodelist;
+ struct reserve_info *re;
+ uint64_t integer;
++ int is_plugin;
++
++
+
+-#line 97 "dtc-parser.tab.h" /* yacc.c:1909 */
+-};
++/* Line 2068 of yacc.c */
++#line 96 "dtc-parser.tab.h"
++} YYSTYPE;
+ # define YYSTYPE_IS_TRIVIAL 1
++# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+ # define YYSTYPE_IS_DECLARED 1
+ #endif
+
+-/* Location type. */
++extern YYSTYPE yylval;
++
+ #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
+-typedef struct YYLTYPE YYLTYPE;
+-struct YYLTYPE
++typedef struct YYLTYPE
+ {
+ int first_line;
+ int first_column;
+ int last_line;
+ int last_column;
+-};
++} YYLTYPE;
++# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
+ # define YYLTYPE_IS_DECLARED 1
+ # define YYLTYPE_IS_TRIVIAL 1
+ #endif
+
+-
+-extern YYSTYPE yylval;
+ extern YYLTYPE yylloc;
+-int yyparse (void);
+
+-#endif /* !YY_YY_DTC_PARSER_TAB_H_INCLUDED */
+--- a/scripts/dtc/dtc-parser.y
++++ b/scripts/dtc/dtc-parser.y
+@@ -19,6 +19,7 @@
+ */
+ %{
+ #include <stdio.h>
++#include <inttypes.h>
+
+ #include "dtc.h"
+ #include "srcpos.h"
+@@ -52,9 +53,11 @@ extern bool treesource_error;
+ struct node *nodelist;
+ struct reserve_info *re;
+ uint64_t integer;
++ int is_plugin;
+ }
+
+ %token DT_V1
++%token DT_PLUGIN
+ %token DT_MEMRESERVE
+ %token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR
+ %token DT_BITS
+@@ -71,6 +74,7 @@ extern bool treesource_error;
+
+ %type <data> propdata
+ %type <data> propdataprefix
++%type <is_plugin> plugindecl
+ %type <re> memreserve
+ %type <re> memreserves
+ %type <array> arrayprefix
+@@ -101,10 +105,23 @@ extern bool treesource_error;
+ %%
+
+ sourcefile:
+- DT_V1 ';' memreserves devicetree
++ DT_V1 ';' plugindecl memreserves devicetree
+ {
+- the_boot_info = build_boot_info($3, $4,
+- guess_boot_cpuid($4));
++ $5->is_plugin = $3;
++ $5->is_root = 1;
++ the_boot_info = build_boot_info($4, $5,
++ guess_boot_cpuid($5));
++ }
++ ;
++
++plugindecl:
++ /* empty */
++ {
++ $$ = 0;
++ }
++ | DT_PLUGIN ';'
++ {
++ $$ = 1;
+ }
+ ;
+
+--- a/scripts/dtc/dtc.c
++++ b/scripts/dtc/dtc.c
+@@ -29,6 +29,7 @@ int reservenum; /* Number of memory res
+ int minsize; /* Minimum blob size */
+ int padsize; /* Additional padding to blob */
+ int phandle_format = PHANDLE_BOTH; /* Use linux,phandle or phandle properties */
++int symbol_fixup_support = 0;
+
+ static void fill_fullpaths(struct node *tree, const char *prefix)
+ {
+@@ -51,7 +52,7 @@ static void fill_fullpaths(struct node *
+ #define FDT_VERSION(version) _FDT_VERSION(version)
+ #define _FDT_VERSION(version) #version
+ static const char usage_synopsis[] = "dtc [options] <input file>";
+-static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:hv";
++static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:hv@";
+ static struct option const usage_long_opts[] = {
+ {"quiet", no_argument, NULL, 'q'},
+ {"in-format", a_argument, NULL, 'I'},
+@@ -69,6 +70,7 @@ static struct option const usage_long_op
+ {"phandle", a_argument, NULL, 'H'},
+ {"warning", a_argument, NULL, 'W'},
+ {"error", a_argument, NULL, 'E'},
++ {"symbols", a_argument, NULL, '@'},
+ {"help", no_argument, NULL, 'h'},
+ {"version", no_argument, NULL, 'v'},
+ {NULL, no_argument, NULL, 0x0},
+@@ -99,6 +101,7 @@ static const char * const usage_opts_hel
+ "\t\tboth - Both \"linux,phandle\" and \"phandle\" properties",
+ "\n\tEnable/disable warnings (prefix with \"no-\")",
+ "\n\tEnable/disable errors (prefix with \"no-\")",
++ "\n\tSymbols and Fixups support",
+ "\n\tPrint this help and exit",
+ "\n\tPrint version and exit",
+ NULL,
+@@ -186,7 +189,9 @@ int main(int argc, char *argv[])
+ case 'E':
+ parse_checks_option(false, true, optarg);
+ break;
+-
++ case '@':
++ symbol_fixup_support = 1;
++ break;
+ case 'h':
+ usage(NULL);
+ default:
+--- a/scripts/dtc/dtc.h
++++ b/scripts/dtc/dtc.h
+@@ -54,6 +54,7 @@ extern int reservenum; /* Number of mem
+ extern int minsize; /* Minimum blob size */
+ extern int padsize; /* Additional padding to blob */
+ extern int phandle_format; /* Use linux,phandle or phandle properties */
++extern int symbol_fixup_support;/* enable symbols & fixup support */
+
+ #define PHANDLE_LEGACY 0x1
+ #define PHANDLE_EPAPR 0x2
+@@ -132,6 +133,25 @@ struct label {
+ struct label *next;
+ };
+
++struct fixup_entry {
++ int offset;
++ struct node *node;
++ struct property *prop;
++ struct fixup_entry *next;
++};
++
++struct fixup {
++ char *ref;
++ struct fixup_entry *entries;
++ struct fixup *next;
++};
++
++struct symbol {
++ struct label *label;
++ struct node *node;
++ struct symbol *next;
++};
++
+ struct property {
+ bool deleted;
+ char *name;
+@@ -158,6 +178,12 @@ struct node {
+ int addr_cells, size_cells;
+
+ struct label *labels;
++
++ int is_root;
++ int is_plugin;
++ struct fixup *fixups;
++ struct symbol *symbols;
++ struct fixup_entry *local_fixups;
+ };
+
+ #define for_each_label_withdel(l0, l) \
+@@ -181,6 +207,18 @@ struct node {
+ for_each_child_withdel(n, c) \
+ if (!(c)->deleted)
+
++#define for_each_fixup(n, f) \
++ for ((f) = (n)->fixups; (f); (f) = (f)->next)
++
++#define for_each_fixup_entry(f, fe) \
++ for ((fe) = (f)->entries; (fe); (fe) = (fe)->next)
++
++#define for_each_symbol(n, s) \
++ for ((s) = (n)->symbols; (s); (s) = (s)->next)
++
++#define for_each_local_fixup_entry(n, fe) \
++ for ((fe) = (n)->local_fixups; (fe); (fe) = (fe)->next)
++
+ void add_label(struct label **labels, char *label);
+ void delete_labels(struct label **labels);
+
+--- a/scripts/dtc/flattree.c
++++ b/scripts/dtc/flattree.c
+@@ -262,6 +262,12 @@ static void flatten_tree(struct node *tr
+ struct property *prop;
+ struct node *child;
+ bool seen_name_prop = false;
++ struct symbol *sym;
++ struct fixup *f;
++ struct fixup_entry *fe;
++ char *name, *s;
++ const char *fullpath;
++ int namesz, nameoff, vallen;
+
+ if (tree->deleted)
+ return;
+@@ -276,8 +282,6 @@ static void flatten_tree(struct node *tr
+ emit->align(etarget, sizeof(cell_t));
+
+ for_each_property(tree, prop) {
+- int nameoff;
+-
+ if (streq(prop->name, "name"))
+ seen_name_prop = true;
+
+@@ -310,6 +314,139 @@ static void flatten_tree(struct node *tr
+ flatten_tree(child, emit, etarget, strbuf, vi);
+ }
+
++ if (!symbol_fixup_support)
++ goto no_symbols;
++
++ /* add the symbol nodes (if any) */
++ if (tree->symbols) {
++
++ emit->beginnode(etarget, NULL);
++ emit->string(etarget, "__symbols__", 0);
++ emit->align(etarget, sizeof(cell_t));
++
++ for_each_symbol(tree, sym) {
++
++ vallen = strlen(sym->node->fullpath);
++
++ nameoff = stringtable_insert(strbuf, sym->label->label);
++
++ emit->property(etarget, NULL);
++ emit->cell(etarget, vallen + 1);
++ emit->cell(etarget, nameoff);
++
++ if ((vi->flags & FTF_VARALIGN) && vallen >= 8)
++ emit->align(etarget, 8);
++
++ emit->string(etarget, sym->node->fullpath,
++ strlen(sym->node->fullpath));
++ emit->align(etarget, sizeof(cell_t));
++ }
++
++ emit->endnode(etarget, NULL);
++ }
++
++ /* add the fixup nodes */
++ if (tree->fixups) {
++
++ /* emit the external fixups */
++ emit->beginnode(etarget, NULL);
++ emit->string(etarget, "__fixups__", 0);
++ emit->align(etarget, sizeof(cell_t));
++
++ for_each_fixup(tree, f) {
++
++ namesz = 0;
++ for_each_fixup_entry(f, fe) {
++ fullpath = fe->node->fullpath;
++ if (fullpath[0] == '\0')
++ fullpath = "/";
++ namesz += strlen(fullpath) + 1;
++ namesz += strlen(fe->prop->name) + 1;
++ namesz += 32; /* space for :<number> + '\0' */
++ }
++
++ name = xmalloc(namesz);
++
++ s = name;
++ for_each_fixup_entry(f, fe) {
++ fullpath = fe->node->fullpath;
++ if (fullpath[0] == '\0')
++ fullpath = "/";
++ snprintf(s, name + namesz - s, "%s:%s:%d",
++ fullpath,
++ fe->prop->name, fe->offset);
++ s += strlen(s) + 1;
++ }
++
++ nameoff = stringtable_insert(strbuf, f->ref);
++ vallen = s - name - 1;
++
++ emit->property(etarget, NULL);
++ emit->cell(etarget, vallen + 1);
++ emit->cell(etarget, nameoff);
++
++ if ((vi->flags & FTF_VARALIGN) && vallen >= 8)
++ emit->align(etarget, 8);
++
++ emit->string(etarget, name, vallen);
++ emit->align(etarget, sizeof(cell_t));
++
++ free(name);
++ }
++
++ emit->endnode(etarget, tree->labels);
++ }
++
++ /* add the local fixup property */
++ if (tree->local_fixups) {
++
++ /* emit the external fixups */
++ emit->beginnode(etarget, NULL);
++ emit->string(etarget, "__local_fixups__", 0);
++ emit->align(etarget, sizeof(cell_t));
++
++ namesz = 0;
++ for_each_local_fixup_entry(tree, fe) {
++ fullpath = fe->node->fullpath;
++ if (fullpath[0] == '\0')
++ fullpath = "/";
++ namesz += strlen(fullpath) + 1;
++ namesz += strlen(fe->prop->name) + 1;
++ namesz += 32; /* space for :<number> + '\0' */
++ }
++
++ name = xmalloc(namesz);
++
++ s = name;
++ for_each_local_fixup_entry(tree, fe) {
++ fullpath = fe->node->fullpath;
++ if (fullpath[0] == '\0')
++ fullpath = "/";
++ snprintf(s, name + namesz - s, "%s:%s:%d",
++ fullpath, fe->prop->name,
++ fe->offset);
++ s += strlen(s) + 1;
++ }
++
++ nameoff = stringtable_insert(strbuf, "fixup");
++ vallen = s - name - 1;
++
++ emit->property(etarget, NULL);
++ emit->cell(etarget, vallen + 1);
++ emit->cell(etarget, nameoff);
++
++ if ((vi->flags & FTF_VARALIGN) && vallen >= 8)
++ emit->align(etarget, 8);
++
++ emit->string(etarget, name, vallen);
++ emit->align(etarget, sizeof(cell_t));
++
++ free(name);
++
++ emit->endnode(etarget, tree->labels);
++ }
++
++no_symbols:
+ emit->endnode(etarget, tree->labels);
+ }
+
+--- a/scripts/dtc/version_gen.h
++++ b/scripts/dtc/version_gen.h
+@@ -1 +1 @@
+-#define DTC_VERSION "DTC 1.4.1-g9d3649bd"
++#define DTC_VERSION "DTC 1.4.1-g9d3649bd-dirty"
diff --git a/target/linux/brcm2708/patches-4.4/0082-spidev-Add-spidev-compatible-string-to-silence-warni.patch b/target/linux/brcm2708/patches-4.4/0082-spidev-Add-spidev-compatible-string-to-silence-warni.patch
deleted file mode 100644
index e27e143c97..0000000000
--- a/target/linux/brcm2708/patches-4.4/0082-spidev-Add-spidev-compatible-string-to-silence-warni.patch
+++ /dev/null
@@ -1,21 +0,0 @@
-From 5b2d8bca046bd6f1a426e9205f194ece5b95e300 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Tue, 14 Jul 2015 10:26:09 +0100
-Subject: [PATCH 082/170] spidev: Add "spidev" compatible string to silence
- warning
-
-See: https://github.com/raspberrypi/linux/issues/1054
----
- drivers/spi/spidev.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/spi/spidev.c
-+++ b/drivers/spi/spidev.c
-@@ -695,6 +695,7 @@ static struct class *spidev_class;
- static const struct of_device_id spidev_dt_ids[] = {
- { .compatible = "rohm,dh2228fv" },
- { .compatible = "lineartechnology,ltc2488" },
-+ { .compatible = "spidev" },
- {},
- };
- MODULE_DEVICE_TABLE(of, spidev_dt_ids);
diff --git a/target/linux/brcm2708/patches-4.4/0083-mfd-Add-Raspberry-Pi-Sense-HAT-core-driver.patch b/target/linux/brcm2708/patches-4.4/0083-mfd-Add-Raspberry-Pi-Sense-HAT-core-driver.patch
new file mode 100644
index 0000000000..3e3cca534b
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0083-mfd-Add-Raspberry-Pi-Sense-HAT-core-driver.patch
@@ -0,0 +1,838 @@
+From 17ec32c056210154217ea601c86a16685d58f408 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <pelwell@users.noreply.github.com>
+Date: Tue, 14 Jul 2015 14:32:47 +0100
+Subject: [PATCH 083/381] mfd: Add Raspberry Pi Sense HAT core driver
+
+---
+ drivers/input/joystick/Kconfig | 8 +
+ drivers/input/joystick/Makefile | 1 +
+ drivers/input/joystick/rpisense-js.c | 153 ++++++++++++++++
+ drivers/mfd/Kconfig | 8 +
+ drivers/mfd/Makefile | 2 +
+ drivers/mfd/rpisense-core.c | 157 +++++++++++++++++
+ drivers/video/fbdev/Kconfig | 13 ++
+ drivers/video/fbdev/Makefile | 1 +
+ drivers/video/fbdev/rpisense-fb.c | 293 +++++++++++++++++++++++++++++++
+ include/linux/mfd/rpisense/core.h | 47 +++++
+ include/linux/mfd/rpisense/framebuffer.h | 32 ++++
+ include/linux/mfd/rpisense/joystick.h | 35 ++++
+ 12 files changed, 750 insertions(+)
+ create mode 100644 drivers/input/joystick/rpisense-js.c
+ create mode 100644 drivers/mfd/rpisense-core.c
+ create mode 100644 drivers/video/fbdev/rpisense-fb.c
+ create mode 100644 include/linux/mfd/rpisense/core.h
+ create mode 100644 include/linux/mfd/rpisense/framebuffer.h
+ create mode 100644 include/linux/mfd/rpisense/joystick.h
+
+--- a/drivers/input/joystick/Kconfig
++++ b/drivers/input/joystick/Kconfig
+@@ -330,4 +330,12 @@ config JOYSTICK_MAPLE
+ To compile this as a module choose M here: the module will be called
+ maplecontrol.
+
++config JOYSTICK_RPISENSE
++ tristate "Raspberry Pi Sense HAT joystick"
++ depends on GPIOLIB && INPUT
++ select MFD_RPISENSE_CORE
++
++ help
++ This is the joystick driver for the Raspberry Pi Sense HAT
++
+ endif
+--- a/drivers/input/joystick/Makefile
++++ b/drivers/input/joystick/Makefile
+@@ -32,4 +32,5 @@ obj-$(CONFIG_JOYSTICK_WARRIOR) += warri
+ obj-$(CONFIG_JOYSTICK_XPAD) += xpad.o
+ obj-$(CONFIG_JOYSTICK_ZHENHUA) += zhenhua.o
+ obj-$(CONFIG_JOYSTICK_WALKERA0701) += walkera0701.o
++obj-$(CONFIG_JOYSTICK_RPISENSE) += rpisense-js.o
+
+--- /dev/null
++++ b/drivers/input/joystick/rpisense-js.c
+@@ -0,0 +1,153 @@
++/*
++ * Raspberry Pi Sense HAT joystick driver
++ * http://raspberrypi.org
++ *
++ * Copyright (C) 2015 Raspberry Pi
++ *
++ * Author: Serge Schneider
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ */
++
++#include <linux/module.h>
++
++#include <linux/mfd/rpisense/joystick.h>
++#include <linux/mfd/rpisense/core.h>
++
++static struct rpisense *rpisense;
++static unsigned char keymap[5] = {KEY_DOWN, KEY_RIGHT, KEY_UP, KEY_ENTER, KEY_LEFT,};
++
++static void keys_work_fn(struct work_struct *work)
++{
++ int i;
++ static s32 prev_keys;
++ struct rpisense_js *rpisense_js = &rpisense->joystick;
++ s32 keys = rpisense_reg_read(rpisense, RPISENSE_KEYS);
++ s32 changes = keys ^ prev_keys;
++
++ prev_keys = keys;
++ for (i = 0; i < 5; i++) {
++ if (changes & 1) {
++ input_report_key(rpisense_js->keys_dev,
++ keymap[i], keys & 1);
++ }
++ changes >>= 1;
++ keys >>= 1;
++ }
++ input_sync(rpisense_js->keys_dev);
++}
++
++static irqreturn_t keys_irq_handler(int irq, void *pdev)
++{
++ struct rpisense_js *rpisense_js = &rpisense->joystick;
++
++ schedule_work(&rpisense_js->keys_work_s);
++ return IRQ_HANDLED;
++}
++
++static int rpisense_js_probe(struct platform_device *pdev)
++{
++ int ret;
++ int i;
++ struct rpisense_js *rpisense_js;
++
++ rpisense = rpisense_get_dev();
++ rpisense_js = &rpisense->joystick;
++
++ INIT_WORK(&rpisense_js->keys_work_s, keys_work_fn);
++
++ rpisense_js->keys_dev = input_allocate_device();
++ if (!rpisense_js->keys_dev) {
++ dev_err(&pdev->dev, "Could not allocate input device.\n");
++ return -ENOMEM;
++ }
++
++ rpisense_js->keys_dev->evbit[0] = BIT_MASK(EV_KEY);
++ for (i = 0; i < ARRAY_SIZE(keymap); i++) {
++ set_bit(keymap[i],
++ rpisense_js->keys_dev->keybit);
++ }
++
++ rpisense_js->keys_dev->name = "Raspberry Pi Sense HAT Joystick";
++ rpisense_js->keys_dev->phys = "rpi-sense-joy/input0";
++ rpisense_js->keys_dev->id.bustype = BUS_I2C;
++ rpisense_js->keys_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
++ rpisense_js->keys_dev->keycode = keymap;
++ rpisense_js->keys_dev->keycodesize = sizeof(unsigned char);
++ rpisense_js->keys_dev->keycodemax = ARRAY_SIZE(keymap);
++
++ ret = input_register_device(rpisense_js->keys_dev);
++ if (ret) {
++ dev_err(&pdev->dev, "Could not register input device.\n");
++ goto err_keys_alloc;
++ }
++
++ ret = gpiod_direction_input(rpisense_js->keys_desc);
++ if (ret) {
++ dev_err(&pdev->dev, "Could not set keys-int direction.\n");
++ goto err_keys_reg;
++ }
++
++ rpisense_js->keys_irq = gpiod_to_irq(rpisense_js->keys_desc);
++ if (rpisense_js->keys_irq < 0) {
++ dev_err(&pdev->dev, "Could not determine keys-int IRQ.\n");
++ ret = rpisense_js->keys_irq;
++ goto err_keys_reg;
++ }
++
++ ret = devm_request_irq(&pdev->dev, rpisense_js->keys_irq,
++ keys_irq_handler, IRQF_TRIGGER_RISING,
++ "keys", &pdev->dev);
++ if (ret) {
++ dev_err(&pdev->dev, "IRQ request failed.\n");
++ goto err_keys_reg;
++ }
++ return 0;
++err_keys_reg:
++ input_unregister_device(rpisense_js->keys_dev);
++err_keys_alloc:
++ input_free_device(rpisense_js->keys_dev);
++ return ret;
++}
++
++static int rpisense_js_remove(struct platform_device *pdev)
++{
++ struct rpisense_js *rpisense_js = &rpisense->joystick;
++
++ input_unregister_device(rpisense_js->keys_dev);
++ input_free_device(rpisense_js->keys_dev);
++ return 0;
++}
++
++#ifdef CONFIG_OF
++static const struct of_device_id rpisense_js_id[] = {
++ { .compatible = "rpi,rpi-sense-js" },
++ { },
++};
++MODULE_DEVICE_TABLE(of, rpisense_js_id);
++#endif
++
++static struct platform_device_id rpisense_js_device_id[] = {
++ { .name = "rpi-sense-js" },
++ { },
++};
++MODULE_DEVICE_TABLE(platform, rpisense_js_device_id);
++
++static struct platform_driver rpisense_js_driver = {
++ .probe = rpisense_js_probe,
++ .remove = rpisense_js_remove,
++ .driver = {
++ .name = "rpi-sense-js",
++ .owner = THIS_MODULE,
++ },
++};
++
++module_platform_driver(rpisense_js_driver);
++
++MODULE_DESCRIPTION("Raspberry Pi Sense HAT joystick driver");
++MODULE_AUTHOR("Serge Schneider <serge@raspberrypi.org>");
++MODULE_LICENSE("GPL");
+--- a/drivers/mfd/Kconfig
++++ b/drivers/mfd/Kconfig
+@@ -10,6 +10,14 @@ config MFD_CORE
+ select IRQ_DOMAIN
+ default n
+
++config MFD_RPISENSE_CORE
++ tristate "Raspberry Pi Sense HAT core functions"
++ depends on I2C
++ select MFD_CORE
++ help
++ This is the core driver for the Raspberry Pi Sense HAT. This provides
++ the necessary functions to communicate with the hardware.
++
+ config MFD_CS5535
+ tristate "AMD CS5535 and CS5536 southbridge core functions"
+ select MFD_CORE
+--- a/drivers/mfd/Makefile
++++ b/drivers/mfd/Makefile
+@@ -194,3 +194,5 @@ intel-soc-pmic-objs := intel_soc_pmic_c
+ intel-soc-pmic-$(CONFIG_INTEL_PMC_IPC) += intel_soc_pmic_bxtwc.o
+ obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o
+ obj-$(CONFIG_MFD_MT6397) += mt6397-core.o
++
++obj-$(CONFIG_MFD_RPISENSE_CORE) += rpisense-core.o
+--- /dev/null
++++ b/drivers/mfd/rpisense-core.c
+@@ -0,0 +1,157 @@
++/*
++ * Raspberry Pi Sense HAT core driver
++ * http://raspberrypi.org
++ *
++ * Copyright (C) 2015 Raspberry Pi
++ *
++ * Author: Serge Schneider
++ *
++ * 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 driver is based on wm8350 implementation.
++ */
++
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/err.h>
++#include <linux/init.h>
++#include <linux/i2c.h>
++#include <linux/platform_device.h>
++#include <linux/mfd/rpisense/core.h>
++#include <linux/slab.h>
++
++static struct rpisense *rpisense;
++
++static void rpisense_client_dev_register(struct rpisense *rpisense,
++ const char *name,
++ struct platform_device **pdev)
++{
++ int ret;
++
++ *pdev = platform_device_alloc(name, -1);
++ if (*pdev == NULL) {
++ dev_err(rpisense->dev, "Failed to allocate %s\n", name);
++ return;
++ }
++
++ (*pdev)->dev.parent = rpisense->dev;
++ platform_set_drvdata(*pdev, rpisense);
++ ret = platform_device_add(*pdev);
++ if (ret != 0) {
++ dev_err(rpisense->dev, "Failed to register %s: %d\n",
++ name, ret);
++ platform_device_put(*pdev);
++ *pdev = NULL;
++ }
++}
++
++static int rpisense_probe(struct i2c_client *i2c,
++ const struct i2c_device_id *id)
++{
++ int ret;
++ struct rpisense_js *rpisense_js;
++
++ rpisense = devm_kzalloc(&i2c->dev, sizeof(struct rpisense), GFP_KERNEL);
++ if (rpisense == NULL)
++ return -ENOMEM;
++
++ i2c_set_clientdata(i2c, rpisense);
++ rpisense->dev = &i2c->dev;
++ rpisense->i2c_client = i2c;
++
++ ret = rpisense_reg_read(rpisense, RPISENSE_WAI);
++ if (ret > 0) {
++ if (ret != 's')
++ return -EINVAL;
++ } else {
++ return ret;
++ }
++ ret = rpisense_reg_read(rpisense, RPISENSE_VER);
++ if (ret < 0)
++ return ret;
++
++ dev_info(rpisense->dev,
++ "Raspberry Pi Sense HAT firmware version %i\n", ret);
++
++ rpisense_js = &rpisense->joystick;
++ rpisense_js->keys_desc = devm_gpiod_get(&i2c->dev,
++ "keys-int", GPIOD_IN);
++ if (IS_ERR(rpisense_js->keys_desc)) {
++ dev_warn(&i2c->dev, "Failed to get keys-int descriptor.\n");
++ rpisense_js->keys_desc = gpio_to_desc(23);
++ if (rpisense_js->keys_desc == NULL) {
++ dev_err(&i2c->dev, "GPIO23 fallback failed.\n");
++ return PTR_ERR(rpisense_js->keys_desc);
++ }
++ }
++ rpisense_client_dev_register(rpisense, "rpi-sense-js",
++ &(rpisense->joystick.pdev));
++ rpisense_client_dev_register(rpisense, "rpi-sense-fb",
++ &(rpisense->framebuffer.pdev));
++
++ return 0;
++}
++
++static int rpisense_remove(struct i2c_client *i2c)
++{
++ struct rpisense *rpisense = i2c_get_clientdata(i2c);
++
++ platform_device_unregister(rpisense->joystick.pdev);
++ return 0;
++}
++
++struct rpisense *rpisense_get_dev(void)
++{
++ return rpisense;
++}
++EXPORT_SYMBOL_GPL(rpisense_get_dev);
++
++s32 rpisense_reg_read(struct rpisense *rpisense, int reg)
++{
++ int ret = i2c_smbus_read_byte_data(rpisense->i2c_client, reg);
++
++ if (ret < 0)
++ dev_err(rpisense->dev, "Read from reg %d failed\n", reg);
++ /* Due to the BCM270x I2C clock stretching bug, some values
++ * may have MSB set. Clear it to avoid incorrect values.
++ * */
++ return ret & 0x7F;
++}
++EXPORT_SYMBOL_GPL(rpisense_reg_read);
++
++int rpisense_block_write(struct rpisense *rpisense, const char *buf, int count)
++{
++ int ret = i2c_master_send(rpisense->i2c_client, buf, count);
++
++ if (ret < 0)
++ dev_err(rpisense->dev, "Block write failed\n");
++ return ret;
++}
++EXPORT_SYMBOL_GPL(rpisense_block_write);
++
++static const struct i2c_device_id rpisense_i2c_id[] = {
++ { "rpi-sense", 0 },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, rpisense_i2c_id);
++
++
++static struct i2c_driver rpisense_driver = {
++ .driver = {
++ .name = "rpi-sense",
++ .owner = THIS_MODULE,
++ },
++ .probe = rpisense_probe,
++ .remove = rpisense_remove,
++ .id_table = rpisense_i2c_id,
++};
++
++module_i2c_driver(rpisense_driver);
++
++MODULE_DESCRIPTION("Raspberry Pi Sense HAT core driver");
++MODULE_AUTHOR("Serge Schneider <serge@raspberrypi.org>");
++MODULE_LICENSE("GPL");
++
+--- a/drivers/video/fbdev/Kconfig
++++ b/drivers/video/fbdev/Kconfig
+@@ -2505,3 +2505,16 @@ config FB_SM712
+ This driver is also available as a module. The module will be
+ called sm712fb. If you want to compile it as a module, say M
+ here and read <file:Documentation/kbuild/modules.txt>.
++
++config FB_RPISENSE
++ tristate "Raspberry Pi Sense HAT framebuffer"
++ depends on FB
++ select MFD_RPISENSE_CORE
++ select FB_SYS_FOPS
++ select FB_SYS_FILLRECT
++ select FB_SYS_COPYAREA
++ select FB_SYS_IMAGEBLIT
++ select FB_DEFERRED_IO
++
++ help
++ This is the framebuffer driver for the Raspberry Pi Sense HAT
+--- a/drivers/video/fbdev/Makefile
++++ b/drivers/video/fbdev/Makefile
+@@ -150,6 +150,7 @@ obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o
+ obj-$(CONFIG_FB_MXS) += mxsfb.o
+ obj-$(CONFIG_FB_SSD1307) += ssd1307fb.o
+ obj-$(CONFIG_FB_SIMPLE) += simplefb.o
++obj-$(CONFIG_FB_RPISENSE) += rpisense-fb.o
+
+ # the test framebuffer is last
+ obj-$(CONFIG_FB_VIRTUAL) += vfb.o
+--- /dev/null
++++ b/drivers/video/fbdev/rpisense-fb.c
+@@ -0,0 +1,293 @@
++/*
++ * Raspberry Pi Sense HAT framebuffer driver
++ * http://raspberrypi.org
++ *
++ * Copyright (C) 2015 Raspberry Pi
++ *
++ * Author: Serge Schneider
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/string.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/uaccess.h>
++#include <linux/delay.h>
++#include <linux/fb.h>
++#include <linux/init.h>
++
++#include <linux/mfd/rpisense/framebuffer.h>
++#include <linux/mfd/rpisense/core.h>
++
++static bool lowlight;
++module_param(lowlight, bool, 0);
++MODULE_PARM_DESC(lowlight, "Reduce LED matrix brightness to one third");
++
++static struct rpisense *rpisense;
++
++struct rpisense_fb_param {
++ char __iomem *vmem;
++ u8 *vmem_work;
++ u32 vmemsize;
++ u8 *gamma;
++};
++
++static u8 gamma_default[32] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
++ 0x02, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x07,
++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0E, 0x0F, 0x11,
++ 0x12, 0x14, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F,};
++
++static u8 gamma_low[32] = {0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
++ 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02,
++ 0x03, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06,
++ 0x06, 0x07, 0x07, 0x08, 0x08, 0x09, 0x0A, 0x0A,};
++
++static u8 gamma_user[32];
++
++static struct rpisense_fb_param rpisense_fb_param = {
++ .vmem = NULL,
++ .vmemsize = 128,
++ .gamma = gamma_default,
++};
++
++static struct fb_deferred_io rpisense_fb_defio;
++
++static struct fb_fix_screeninfo rpisense_fb_fix = {
++ .id = "RPi-Sense FB",
++ .type = FB_TYPE_PACKED_PIXELS,
++ .visual = FB_VISUAL_TRUECOLOR,
++ .xpanstep = 0,
++ .ypanstep = 0,
++ .ywrapstep = 0,
++ .accel = FB_ACCEL_NONE,
++ .line_length = 16,
++};
++
++static struct fb_var_screeninfo rpisense_fb_var = {
++ .xres = 8,
++ .yres = 8,
++ .xres_virtual = 8,
++ .yres_virtual = 8,
++ .bits_per_pixel = 16,
++ .red = {11, 5, 0},
++ .green = {5, 6, 0},
++ .blue = {0, 5, 0},
++};
++
++static ssize_t rpisense_fb_write(struct fb_info *info,
++ const char __user *buf, size_t count,
++ loff_t *ppos)
++{
++ ssize_t res = fb_sys_write(info, buf, count, ppos);
++
++ schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
++ return res;
++}
++
++static void rpisense_fb_fillrect(struct fb_info *info,
++ const struct fb_fillrect *rect)
++{
++ sys_fillrect(info, rect);
++ schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
++}
++
++static void rpisense_fb_copyarea(struct fb_info *info,
++ const struct fb_copyarea *area)
++{
++ sys_copyarea(info, area);
++ schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
++}
++
++static void rpisense_fb_imageblit(struct fb_info *info,
++ const struct fb_image *image)
++{
++ sys_imageblit(info, image);
++ schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
++}
++
++static void rpisense_fb_deferred_io(struct fb_info *info,
++ struct list_head *pagelist)
++{
++ int i;
++ int j;
++ u8 *vmem_work = rpisense_fb_param.vmem_work;
++ u16 *mem = (u16 *)rpisense_fb_param.vmem;
++ u8 *gamma = rpisense_fb_param.gamma;
++
++ vmem_work[0] = 0;
++ for (j = 0; j < 8; j++) {
++ for (i = 0; i < 8; i++) {
++ vmem_work[(j * 24) + i + 1] =
++ gamma[(mem[(j * 8) + i] >> 11) & 0x1F];
++ vmem_work[(j * 24) + (i + 8) + 1] =
++ gamma[(mem[(j * 8) + i] >> 6) & 0x1F];
++ vmem_work[(j * 24) + (i + 16) + 1] =
++ gamma[(mem[(j * 8) + i]) & 0x1F];
++ }
++ }
++ rpisense_block_write(rpisense, vmem_work, 193);
++}
++
++static struct fb_deferred_io rpisense_fb_defio = {
++ .delay = HZ/100,
++ .deferred_io = rpisense_fb_deferred_io,
++};
++
++static int rpisense_fb_ioctl(struct fb_info *info, unsigned int cmd,
++ unsigned long arg)
++{
++ switch (cmd) {
++ case SENSEFB_FBIOGET_GAMMA:
++ if (copy_to_user((void __user *) arg, rpisense_fb_param.gamma,
++ sizeof(u8[32])))
++ return -EFAULT;
++ return 0;
++ case SENSEFB_FBIOSET_GAMMA:
++ if (copy_from_user(gamma_user, (void __user *)arg,
++ sizeof(u8[32])))
++ return -EFAULT;
++ rpisense_fb_param.gamma = gamma_user;
++ schedule_delayed_work(&info->deferred_work,
++ rpisense_fb_defio.delay);
++ return 0;
++ case SENSEFB_FBIORESET_GAMMA:
++ switch (arg) {
++ case 0:
++ rpisense_fb_param.gamma = gamma_default;
++ break;
++ case 1:
++ rpisense_fb_param.gamma = gamma_low;
++ break;
++ case 2:
++ rpisense_fb_param.gamma = gamma_user;
++ break;
++ default:
++ return -EINVAL;
++ }
++ schedule_delayed_work(&info->deferred_work,
++ rpisense_fb_defio.delay);
++ break;
++ default:
++ return -EINVAL;
++ }
++ return 0;
++}
++
++static struct fb_ops rpisense_fb_ops = {
++ .owner = THIS_MODULE,
++ .fb_read = fb_sys_read,
++ .fb_write = rpisense_fb_write,
++ .fb_fillrect = rpisense_fb_fillrect,
++ .fb_copyarea = rpisense_fb_copyarea,
++ .fb_imageblit = rpisense_fb_imageblit,
++ .fb_ioctl = rpisense_fb_ioctl,
++};
++
++static int rpisense_fb_probe(struct platform_device *pdev)
++{
++ struct fb_info *info;
++ int ret = -ENOMEM;
++ struct rpisense_fb *rpisense_fb;
++
++ rpisense = rpisense_get_dev();
++ rpisense_fb = &rpisense->framebuffer;
++
++ rpisense_fb_param.vmem = vzalloc(rpisense_fb_param.vmemsize);
++ if (!rpisense_fb_param.vmem)
++ return ret;
++
++ rpisense_fb_param.vmem_work = devm_kmalloc(&pdev->dev, 193, GFP_KERNEL);
++ if (!rpisense_fb_param.vmem_work)
++ goto err_malloc;
++
++ info = framebuffer_alloc(0, &pdev->dev);
++ if (!info) {
++ dev_err(&pdev->dev, "Could not allocate framebuffer.\n");
++ goto err_malloc;
++ }
++ rpisense_fb->info = info;
++
++ rpisense_fb_fix.smem_start = (unsigned long)rpisense_fb_param.vmem;
++ rpisense_fb_fix.smem_len = rpisense_fb_param.vmemsize;
++
++ info->fbops = &rpisense_fb_ops;
++ info->fix = rpisense_fb_fix;
++ info->var = rpisense_fb_var;
++ info->fbdefio = &rpisense_fb_defio;
++ info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB;
++ info->screen_base = rpisense_fb_param.vmem;
++ info->screen_size = rpisense_fb_param.vmemsize;
++
++ if (lowlight)
++ rpisense_fb_param.gamma = gamma_low;
++
++ fb_deferred_io_init(info);
++
++ ret = register_framebuffer(info);
++ if (ret < 0) {
++ dev_err(&pdev->dev, "Could not register framebuffer.\n");
++ goto err_fballoc;
++ }
++
++ fb_info(info, "%s frame buffer device\n", info->fix.id);
++ schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
++ return 0;
++err_fballoc:
++ framebuffer_release(info);
++err_malloc:
++ vfree(rpisense_fb_param.vmem);
++ return ret;
++}
++
++static int rpisense_fb_remove(struct platform_device *pdev)
++{
++ struct rpisense_fb *rpisense_fb = &rpisense->framebuffer;
++ struct fb_info *info = rpisense_fb->info;
++
++ if (info) {
++ unregister_framebuffer(info);
++ fb_deferred_io_cleanup(info);
++ framebuffer_release(info);
++ vfree(rpisense_fb_param.vmem);
++ }
++
++ return 0;
++}
++
++#ifdef CONFIG_OF
++static const struct of_device_id rpisense_fb_id[] = {
++ { .compatible = "rpi,rpi-sense-fb" },
++ { },
++};
++MODULE_DEVICE_TABLE(of, rpisense_fb_id);
++#endif
++
++static struct platform_device_id rpisense_fb_device_id[] = {
++ { .name = "rpi-sense-fb" },
++ { },
++};
++MODULE_DEVICE_TABLE(platform, rpisense_fb_device_id);
++
++static struct platform_driver rpisense_fb_driver = {
++ .probe = rpisense_fb_probe,
++ .remove = rpisense_fb_remove,
++ .driver = {
++ .name = "rpi-sense-fb",
++ .owner = THIS_MODULE,
++ },
++};
++
++module_platform_driver(rpisense_fb_driver);
++
++MODULE_DESCRIPTION("Raspberry Pi Sense HAT framebuffer driver");
++MODULE_AUTHOR("Serge Schneider <serge@raspberrypi.org>");
++MODULE_LICENSE("GPL");
++
+--- /dev/null
++++ b/include/linux/mfd/rpisense/core.h
+@@ -0,0 +1,47 @@
++/*
++ * Raspberry Pi Sense HAT core driver
++ * http://raspberrypi.org
++ *
++ * Copyright (C) 2015 Raspberry Pi
++ *
++ * Author: Serge Schneider
++ *
++ * 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.
++ *
++ */
++
++#ifndef __LINUX_MFD_RPISENSE_CORE_H_
++#define __LINUX_MFD_RPISENSE_CORE_H_
++
++#include <linux/mfd/rpisense/joystick.h>
++#include <linux/mfd/rpisense/framebuffer.h>
++
++/*
++ * Register values.
++ */
++#define RPISENSE_FB 0x00
++#define RPISENSE_WAI 0xF0
++#define RPISENSE_VER 0xF1
++#define RPISENSE_KEYS 0xF2
++#define RPISENSE_EE_WP 0xF3
++
++#define RPISENSE_ID 's'
++
++struct rpisense {
++ struct device *dev;
++ struct i2c_client *i2c_client;
++
++ /* Client devices */
++ struct rpisense_js joystick;
++ struct rpisense_fb framebuffer;
++};
++
++struct rpisense *rpisense_get_dev(void);
++s32 rpisense_reg_read(struct rpisense *rpisense, int reg);
++int rpisense_reg_write(struct rpisense *rpisense, int reg, u16 val);
++int rpisense_block_write(struct rpisense *rpisense, const char *buf, int count);
++
++#endif
+--- /dev/null
++++ b/include/linux/mfd/rpisense/framebuffer.h
+@@ -0,0 +1,32 @@
++/*
++ * Raspberry Pi Sense HAT framebuffer driver
++ * http://raspberrypi.org
++ *
++ * Copyright (C) 2015 Raspberry Pi
++ *
++ * Author: Serge Schneider
++ *
++ * 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.
++ *
++ */
++
++#ifndef __LINUX_RPISENSE_FB_H_
++#define __LINUX_RPISENSE_FB_H_
++
++#define SENSEFB_FBIO_IOC_MAGIC 0xF1
++
++#define SENSEFB_FBIOGET_GAMMA _IO(SENSEFB_FBIO_IOC_MAGIC, 0)
++#define SENSEFB_FBIOSET_GAMMA _IO(SENSEFB_FBIO_IOC_MAGIC, 1)
++#define SENSEFB_FBIORESET_GAMMA _IO(SENSEFB_FBIO_IOC_MAGIC, 2)
++
++struct rpisense;
++
++struct rpisense_fb {
++ struct platform_device *pdev;
++ struct fb_info *info;
++};
++
++#endif
+--- /dev/null
++++ b/include/linux/mfd/rpisense/joystick.h
+@@ -0,0 +1,35 @@
++/*
++ * Raspberry Pi Sense HAT joystick driver
++ * http://raspberrypi.org
++ *
++ * Copyright (C) 2015 Raspberry Pi
++ *
++ * Author: Serge Schneider
++ *
++ * 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.
++ *
++ */
++
++#ifndef __LINUX_RPISENSE_JOYSTICK_H_
++#define __LINUX_RPISENSE_JOYSTICK_H_
++
++#include <linux/input.h>
++#include <linux/interrupt.h>
++#include <linux/gpio/consumer.h>
++#include <linux/platform_device.h>
++
++struct rpisense;
++
++struct rpisense_js {
++ struct platform_device *pdev;
++ struct input_dev *keys_dev;
++ struct gpio_desc *keys_desc;
++ struct work_struct keys_work_s;
++ int keys_irq;
++};
++
++
++#endif
diff --git a/target/linux/brcm2708/patches-4.4/0083-scripts-dtc-Add-overlay-support.patch b/target/linux/brcm2708/patches-4.4/0083-scripts-dtc-Add-overlay-support.patch
deleted file mode 100644
index 404f10f4cf..0000000000
--- a/target/linux/brcm2708/patches-4.4/0083-scripts-dtc-Add-overlay-support.patch
+++ /dev/null
@@ -1,4389 +0,0 @@
-From 534c337ea28bee34f886a1d1e00d281365c94efa Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Tue, 14 Jul 2015 17:00:18 +0100
-Subject: [PATCH 083/170] scripts/dtc: Add overlay support
-
----
- scripts/dtc/checks.c | 119 ++-
- scripts/dtc/dtc-lexer.l | 5 +
- scripts/dtc/dtc-lexer.lex.c_shipped | 490 ++++-----
- scripts/dtc/dtc-parser.tab.c_shipped | 1896 +++++++++++++++++++---------------
- scripts/dtc/dtc-parser.tab.h_shipped | 107 +-
- scripts/dtc/dtc-parser.y | 23 +-
- scripts/dtc/dtc.c | 9 +-
- scripts/dtc/dtc.h | 38 +
- scripts/dtc/flattree.c | 141 ++-
- scripts/dtc/version_gen.h | 2 +-
- 10 files changed, 1685 insertions(+), 1145 deletions(-)
-
---- a/scripts/dtc/checks.c
-+++ b/scripts/dtc/checks.c
-@@ -458,21 +458,91 @@ static void fixup_phandle_references(str
- struct node *node, struct property *prop)
- {
- struct marker *m = prop->val.markers;
-+ struct fixup *f, **fp;
-+ struct fixup_entry *fe, **fep;
- struct node *refnode;
- cell_t phandle;
-+ int has_phandle_refs;
-+
-+ has_phandle_refs = 0;
-+ for_each_marker_of_type(m, REF_PHANDLE) {
-+ has_phandle_refs = 1;
-+ break;
-+ }
-+
-+ if (!has_phandle_refs)
-+ return;
-
- for_each_marker_of_type(m, REF_PHANDLE) {
- assert(m->offset + sizeof(cell_t) <= prop->val.len);
-
- refnode = get_node_by_ref(dt, m->ref);
-- if (! refnode) {
-+ if (!refnode && !symbol_fixup_support) {
- FAIL(c, "Reference to non-existent node or label \"%s\"\n",
-- m->ref);
-+ m->ref);
- continue;
- }
-
-- phandle = get_node_phandle(dt, refnode);
-- *((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
-+ if (!refnode) {
-+ /* allocate fixup entry */
-+ fe = xmalloc(sizeof(*fe));
-+
-+ fe->node = node;
-+ fe->prop = prop;
-+ fe->offset = m->offset;
-+ fe->next = NULL;
-+
-+ /* search for an already existing fixup */
-+ for_each_fixup(dt, f)
-+ if (strcmp(f->ref, m->ref) == 0)
-+ break;
-+
-+ /* no fixup found, add new */
-+ if (f == NULL) {
-+ f = xmalloc(sizeof(*f));
-+ f->ref = m->ref;
-+ f->entries = NULL;
-+ f->next = NULL;
-+
-+ /* add it to the tree */
-+ fp = &dt->fixups;
-+ while (*fp)
-+ fp = &(*fp)->next;
-+ *fp = f;
-+ }
-+
-+ /* and now append fixup entry */
-+ fep = &f->entries;
-+ while (*fep)
-+ fep = &(*fep)->next;
-+ *fep = fe;
-+
-+ /* mark the entry as unresolved */
-+ phandle = 0xdeadbeef;
-+ } else {
-+ phandle = get_node_phandle(dt, refnode);
-+
-+ /* if it's a plugin, we need to record it */
-+ if (symbol_fixup_support && dt->is_plugin) {
-+
-+ /* allocate a new local fixup entry */
-+ fe = xmalloc(sizeof(*fe));
-+
-+ fe->node = node;
-+ fe->prop = prop;
-+ fe->offset = m->offset;
-+ fe->next = NULL;
-+
-+ /* append it to the local fixups */
-+ fep = &dt->local_fixups;
-+ while (*fep)
-+ fep = &(*fep)->next;
-+ *fep = fe;
-+ }
-+ }
-+
-+ *((cell_t *)(prop->val.val + m->offset)) =
-+ cpu_to_fdt32(phandle);
- }
- }
- ERROR(phandle_references, NULL, NULL, fixup_phandle_references, NULL,
-@@ -652,6 +722,45 @@ static void check_obsolete_chosen_interr
- }
- TREE_WARNING(obsolete_chosen_interrupt_controller, NULL);
-
-+static void check_auto_label_phandles(struct check *c, struct node *dt,
-+ struct node *node)
-+{
-+ struct label *l;
-+ struct symbol *s, **sp;
-+ int has_label;
-+
-+ if (!symbol_fixup_support)
-+ return;
-+
-+ has_label = 0;
-+ for_each_label(node->labels, l) {
-+ has_label = 1;
-+ break;
-+ }
-+
-+ if (!has_label)
-+ return;
-+
-+ /* force allocation of a phandle for this node */
-+ (void)get_node_phandle(dt, node);
-+
-+ /* add the symbol */
-+ for_each_label(node->labels, l) {
-+
-+ s = xmalloc(sizeof(*s));
-+ s->label = l;
-+ s->node = node;
-+ s->next = NULL;
-+
-+ /* add it to the symbols list */
-+ sp = &dt->symbols;
-+ while (*sp)
-+ sp = &((*sp)->next);
-+ *sp = s;
-+ }
-+}
-+NODE_WARNING(auto_label_phandles, NULL);
-+
- static struct check *check_table[] = {
- &duplicate_node_names, &duplicate_property_names,
- &node_name_chars, &node_name_format, &property_name_chars,
-@@ -670,6 +779,8 @@ static struct check *check_table[] = {
- &avoid_default_addr_size,
- &obsolete_chosen_interrupt_controller,
-
-+ &auto_label_phandles,
-+
- &always_fail,
- };
-
---- a/scripts/dtc/dtc-lexer.l
-+++ b/scripts/dtc/dtc-lexer.l
-@@ -113,6 +113,11 @@ static void lexical_error(const char *fm
- return DT_V1;
- }
-
-+<*>"/plugin/" {
-+ DPRINT("Keyword: /plugin/\n");
-+ return DT_PLUGIN;
-+ }
-+
- <*>"/memreserve/" {
- DPRINT("Keyword: /memreserve/\n");
- BEGIN_DEFAULT();
---- a/scripts/dtc/dtc-lexer.lex.c_shipped
-+++ b/scripts/dtc/dtc-lexer.lex.c_shipped
-@@ -9,7 +9,7 @@
- #define FLEX_SCANNER
- #define YY_FLEX_MAJOR_VERSION 2
- #define YY_FLEX_MINOR_VERSION 5
--#define YY_FLEX_SUBMINOR_VERSION 39
-+#define YY_FLEX_SUBMINOR_VERSION 35
- #if YY_FLEX_SUBMINOR_VERSION > 0
- #define FLEX_BETA
- #endif
-@@ -162,12 +162,7 @@ typedef unsigned int flex_uint32_t;
- typedef struct yy_buffer_state *YY_BUFFER_STATE;
- #endif
-
--#ifndef YY_TYPEDEF_YY_SIZE_T
--#define YY_TYPEDEF_YY_SIZE_T
--typedef size_t yy_size_t;
--#endif
--
--extern yy_size_t yyleng;
-+extern int yyleng;
-
- extern FILE *yyin, *yyout;
-
-@@ -176,7 +171,6 @@ extern FILE *yyin, *yyout;
- #define EOB_ACT_LAST_MATCH 2
-
- #define YY_LESS_LINENO(n)
-- #define YY_LINENO_REWIND_TO(ptr)
-
- /* Return all but the first "n" matched characters back to the input stream. */
- #define yyless(n) \
-@@ -194,6 +188,11 @@ extern FILE *yyin, *yyout;
-
- #define unput(c) yyunput( c, (yytext_ptr) )
-
-+#ifndef YY_TYPEDEF_YY_SIZE_T
-+#define YY_TYPEDEF_YY_SIZE_T
-+typedef size_t yy_size_t;
-+#endif
-+
- #ifndef YY_STRUCT_YY_BUFFER_STATE
- #define YY_STRUCT_YY_BUFFER_STATE
- struct yy_buffer_state
-@@ -211,7 +210,7 @@ struct yy_buffer_state
- /* Number of characters read into yy_ch_buf, not including EOB
- * characters.
- */
-- yy_size_t yy_n_chars;
-+ int yy_n_chars;
-
- /* Whether we "own" the buffer - i.e., we know we created it,
- * and can realloc() it to grow it, and should free() it to
-@@ -281,8 +280,8 @@ static YY_BUFFER_STATE * yy_buffer_stack
-
- /* yy_hold_char holds the character lost when yytext is formed. */
- static char yy_hold_char;
--static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */
--yy_size_t yyleng;
-+static int yy_n_chars; /* number of characters read into yy_ch_buf */
-+int yyleng;
-
- /* Points to current character in buffer. */
- static char *yy_c_buf_p = (char *) 0;
-@@ -310,7 +309,7 @@ static void yy_init_buffer (YY_BUFFER_ST
-
- YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size );
- YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str );
--YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len );
-+YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len );
-
- void *yyalloc (yy_size_t );
- void *yyrealloc (void *,yy_size_t );
-@@ -342,7 +341,7 @@ void yyfree (void * );
-
- /* Begin user sect3 */
-
--#define yywrap() 1
-+#define yywrap(n) 1
- #define YY_SKIP_YYWRAP
-
- typedef unsigned char YY_CHAR;
-@@ -373,8 +372,8 @@ static void yy_fatal_error (yyconst char
- *yy_cp = '\0'; \
- (yy_c_buf_p) = yy_cp;
-
--#define YY_NUM_RULES 30
--#define YY_END_OF_BUFFER 31
-+#define YY_NUM_RULES 31
-+#define YY_END_OF_BUFFER 32
- /* This struct is not used in this scanner,
- but its presence is necessary. */
- struct yy_trans_info
-@@ -382,25 +381,26 @@ struct yy_trans_info
- flex_int32_t yy_verify;
- flex_int32_t yy_nxt;
- };
--static yyconst flex_int16_t yy_accept[159] =
-+static yyconst flex_int16_t yy_accept[166] =
- { 0,
-- 0, 0, 0, 0, 0, 0, 0, 0, 31, 29,
-- 18, 18, 29, 29, 29, 29, 29, 29, 29, 29,
-- 29, 29, 29, 29, 29, 29, 15, 16, 16, 29,
-- 16, 10, 10, 18, 26, 0, 3, 0, 27, 12,
-- 0, 0, 11, 0, 0, 0, 0, 0, 0, 0,
-- 21, 23, 25, 24, 22, 0, 9, 28, 0, 0,
-- 0, 14, 14, 16, 16, 16, 10, 10, 10, 0,
-- 12, 0, 11, 0, 0, 0, 20, 0, 0, 0,
-- 0, 0, 0, 0, 0, 16, 10, 10, 10, 0,
-- 13, 19, 0, 0, 0, 0, 0, 0, 0, 0,
--
-- 0, 16, 0, 0, 0, 0, 0, 0, 0, 0,
-- 0, 16, 6, 0, 0, 0, 0, 0, 0, 2,
-- 0, 0, 0, 0, 0, 0, 0, 0, 4, 17,
-- 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
-- 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
-- 5, 8, 0, 0, 0, 0, 7, 0
-+ 0, 0, 0, 0, 0, 0, 0, 0, 32, 30,
-+ 19, 19, 30, 30, 30, 30, 30, 30, 30, 30,
-+ 30, 30, 30, 30, 30, 30, 16, 17, 17, 30,
-+ 17, 11, 11, 19, 27, 0, 3, 0, 28, 13,
-+ 0, 0, 12, 0, 0, 0, 0, 0, 0, 0,
-+ 0, 22, 24, 26, 25, 23, 0, 10, 29, 0,
-+ 0, 0, 15, 15, 17, 17, 17, 11, 11, 11,
-+ 0, 13, 0, 12, 0, 0, 0, 21, 0, 0,
-+ 0, 0, 0, 0, 0, 0, 0, 17, 11, 11,
-+ 11, 0, 14, 20, 0, 0, 0, 0, 0, 0,
-+
-+ 0, 0, 0, 0, 17, 0, 0, 0, 0, 0,
-+ 0, 0, 0, 0, 0, 17, 7, 0, 0, 0,
-+ 0, 0, 0, 0, 2, 0, 0, 0, 0, 0,
-+ 0, 0, 0, 0, 4, 18, 0, 0, 5, 2,
-+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-+ 0, 0, 1, 0, 0, 0, 0, 6, 9, 0,
-+ 0, 0, 0, 8, 0
- } ;
-
- static yyconst flex_int32_t yy_ec[256] =
-@@ -416,9 +416,9 @@ static yyconst flex_int32_t yy_ec[256] =
- 22, 22, 22, 22, 24, 22, 22, 25, 22, 22,
- 1, 26, 27, 1, 22, 1, 21, 28, 29, 30,
-
-- 31, 21, 22, 22, 32, 22, 22, 33, 34, 35,
-- 36, 37, 22, 38, 39, 40, 41, 42, 22, 25,
-- 43, 22, 44, 45, 46, 1, 1, 1, 1, 1,
-+ 31, 21, 32, 22, 33, 22, 22, 34, 35, 36,
-+ 37, 38, 22, 39, 40, 41, 42, 43, 22, 25,
-+ 44, 22, 45, 46, 47, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-@@ -435,163 +435,165 @@ static yyconst flex_int32_t yy_ec[256] =
- 1, 1, 1, 1, 1
- } ;
-
--static yyconst flex_int32_t yy_meta[47] =
-+static yyconst flex_int32_t yy_meta[48] =
- { 0,
- 1, 1, 1, 1, 1, 1, 2, 3, 1, 2,
- 2, 2, 4, 5, 5, 5, 6, 1, 1, 1,
- 7, 8, 8, 8, 8, 1, 1, 7, 7, 7,
- 7, 8, 8, 8, 8, 8, 8, 8, 8, 8,
-- 8, 8, 8, 3, 1, 4
-+ 8, 8, 8, 8, 3, 1, 4
- } ;
-
--static yyconst flex_int16_t yy_base[173] =
-+static yyconst flex_int16_t yy_base[180] =
- { 0,
-- 0, 383, 34, 382, 65, 381, 37, 105, 387, 391,
-- 54, 111, 367, 110, 109, 109, 112, 41, 366, 104,
-- 367, 338, 124, 117, 0, 144, 391, 0, 121, 0,
-- 135, 155, 140, 179, 391, 160, 391, 379, 391, 0,
-- 368, 141, 391, 167, 370, 376, 346, 103, 342, 345,
-- 391, 391, 391, 391, 391, 358, 391, 391, 175, 342,
-- 338, 391, 355, 0, 185, 339, 184, 347, 346, 0,
-- 0, 322, 175, 357, 175, 363, 352, 324, 330, 323,
-- 332, 326, 201, 324, 329, 322, 391, 333, 181, 309,
-- 391, 341, 340, 313, 320, 338, 178, 311, 146, 317,
--
-- 314, 315, 335, 331, 303, 300, 309, 299, 308, 188,
-- 336, 335, 391, 305, 320, 281, 283, 271, 203, 288,
-- 281, 271, 266, 264, 245, 242, 208, 104, 391, 391,
-- 244, 218, 204, 219, 206, 224, 201, 212, 204, 229,
-- 215, 208, 207, 200, 219, 391, 233, 221, 200, 181,
-- 391, 391, 149, 122, 86, 41, 391, 391, 245, 251,
-- 259, 263, 267, 273, 280, 284, 292, 300, 304, 310,
-- 318, 326
-+ 0, 393, 35, 392, 66, 391, 38, 107, 397, 401,
-+ 55, 113, 377, 112, 111, 111, 114, 42, 376, 106,
-+ 377, 347, 126, 120, 0, 147, 401, 0, 124, 0,
-+ 137, 158, 170, 163, 401, 153, 401, 389, 401, 0,
-+ 378, 120, 401, 131, 380, 386, 355, 139, 351, 355,
-+ 351, 401, 401, 401, 401, 401, 367, 401, 401, 185,
-+ 350, 346, 401, 364, 0, 185, 347, 189, 356, 355,
-+ 0, 0, 330, 180, 366, 141, 372, 361, 332, 338,
-+ 331, 341, 334, 326, 205, 331, 337, 329, 401, 341,
-+ 167, 316, 401, 349, 348, 320, 328, 346, 180, 318,
-+
-+ 324, 209, 324, 320, 322, 342, 338, 309, 306, 315,
-+ 305, 315, 312, 192, 342, 341, 401, 293, 306, 282,
-+ 268, 252, 255, 203, 285, 282, 272, 268, 252, 233,
-+ 232, 239, 208, 107, 401, 401, 238, 211, 401, 211,
-+ 212, 208, 228, 203, 215, 207, 233, 222, 212, 211,
-+ 203, 227, 401, 237, 225, 204, 185, 401, 401, 149,
-+ 128, 88, 42, 401, 401, 253, 259, 267, 271, 275,
-+ 281, 288, 292, 300, 308, 312, 318, 326, 334
- } ;
-
--static yyconst flex_int16_t yy_def[173] =
-+static yyconst flex_int16_t yy_def[180] =
- { 0,
-- 158, 1, 1, 3, 158, 5, 1, 1, 158, 158,
-- 158, 158, 158, 159, 160, 161, 158, 158, 158, 158,
-- 162, 158, 158, 158, 163, 162, 158, 164, 165, 164,
-- 164, 158, 158, 158, 158, 159, 158, 159, 158, 166,
-- 158, 161, 158, 161, 167, 168, 158, 158, 158, 158,
-- 158, 158, 158, 158, 158, 162, 158, 158, 158, 158,
-- 158, 158, 162, 164, 165, 164, 158, 158, 158, 169,
-- 166, 170, 161, 167, 167, 168, 158, 158, 158, 158,
-- 158, 158, 158, 158, 158, 164, 158, 158, 169, 170,
-- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
--
-- 158, 164, 158, 158, 158, 158, 158, 158, 158, 171,
-- 158, 164, 158, 158, 158, 158, 158, 158, 171, 158,
-- 171, 158, 158, 158, 158, 158, 158, 158, 158, 158,
-- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
-- 172, 158, 158, 158, 172, 158, 172, 158, 158, 158,
-- 158, 158, 158, 158, 158, 158, 158, 0, 158, 158,
-- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
-- 158, 158
-+ 165, 1, 1, 3, 165, 5, 1, 1, 165, 165,
-+ 165, 165, 165, 166, 167, 168, 165, 165, 165, 165,
-+ 169, 165, 165, 165, 170, 169, 165, 171, 172, 171,
-+ 171, 165, 165, 165, 165, 166, 165, 166, 165, 173,
-+ 165, 168, 165, 168, 174, 175, 165, 165, 165, 165,
-+ 165, 165, 165, 165, 165, 165, 169, 165, 165, 165,
-+ 165, 165, 165, 169, 171, 172, 171, 165, 165, 165,
-+ 176, 173, 177, 168, 174, 174, 175, 165, 165, 165,
-+ 165, 165, 165, 165, 165, 165, 165, 171, 165, 165,
-+ 176, 177, 165, 165, 165, 165, 165, 165, 165, 165,
-+
-+ 165, 165, 165, 165, 171, 165, 165, 165, 165, 165,
-+ 165, 165, 165, 178, 165, 171, 165, 165, 165, 165,
-+ 165, 165, 165, 178, 165, 178, 165, 165, 165, 165,
-+ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
-+ 165, 165, 165, 165, 165, 165, 165, 179, 165, 165,
-+ 165, 179, 165, 179, 165, 165, 165, 165, 165, 165,
-+ 165, 165, 165, 165, 0, 165, 165, 165, 165, 165,
-+ 165, 165, 165, 165, 165, 165, 165, 165, 165
- } ;
-
--static yyconst flex_int16_t yy_nxt[438] =
-+static yyconst flex_int16_t yy_nxt[449] =
- { 0,
- 10, 11, 12, 11, 13, 14, 10, 15, 16, 10,
- 10, 10, 17, 10, 10, 10, 10, 18, 19, 20,
- 21, 21, 21, 21, 21, 10, 10, 21, 21, 21,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
-- 21, 21, 21, 10, 22, 10, 24, 25, 25, 25,
-- 32, 33, 33, 157, 26, 34, 34, 34, 51, 52,
-- 27, 26, 26, 26, 26, 10, 11, 12, 11, 13,
-- 14, 28, 15, 16, 28, 28, 28, 24, 28, 28,
-- 28, 10, 18, 19, 20, 29, 29, 29, 29, 29,
-- 30, 10, 29, 29, 29, 29, 29, 29, 29, 29,
--
-- 29, 29, 29, 29, 29, 29, 29, 29, 10, 22,
-- 10, 23, 34, 34, 34, 37, 39, 43, 32, 33,
-- 33, 45, 54, 55, 46, 59, 45, 64, 156, 46,
-- 64, 64, 64, 79, 44, 38, 59, 57, 134, 47,
-- 135, 48, 80, 49, 47, 50, 48, 99, 61, 43,
-- 50, 110, 41, 67, 67, 67, 60, 63, 63, 63,
-- 57, 155, 68, 69, 63, 37, 44, 66, 67, 67,
-- 67, 63, 63, 63, 63, 73, 59, 68, 69, 70,
-- 34, 34, 34, 43, 75, 38, 154, 92, 83, 83,
-- 83, 64, 44, 120, 64, 64, 64, 67, 67, 67,
--
-- 44, 57, 99, 68, 69, 107, 68, 69, 120, 127,
-- 108, 153, 152, 121, 83, 83, 83, 133, 133, 133,
-- 146, 133, 133, 133, 146, 140, 140, 140, 121, 141,
-- 140, 140, 140, 151, 141, 158, 150, 149, 148, 144,
-- 147, 143, 142, 139, 147, 36, 36, 36, 36, 36,
-- 36, 36, 36, 40, 138, 137, 136, 40, 40, 42,
-- 42, 42, 42, 42, 42, 42, 42, 56, 56, 56,
-- 56, 62, 132, 62, 64, 131, 130, 64, 129, 64,
-- 64, 65, 128, 158, 65, 65, 65, 65, 71, 127,
-- 71, 71, 74, 74, 74, 74, 74, 74, 74, 74,
--
-- 76, 76, 76, 76, 76, 76, 76, 76, 89, 126,
-- 89, 90, 125, 90, 90, 124, 90, 90, 119, 119,
-- 119, 119, 119, 119, 119, 119, 145, 145, 145, 145,
-- 145, 145, 145, 145, 123, 122, 59, 59, 118, 117,
-- 116, 115, 114, 113, 45, 112, 108, 111, 109, 106,
-- 105, 104, 46, 103, 91, 87, 102, 101, 100, 98,
-- 97, 96, 95, 94, 93, 77, 75, 91, 88, 87,
-- 86, 57, 85, 84, 57, 82, 81, 78, 77, 75,
-- 72, 158, 58, 57, 53, 35, 158, 31, 23, 23,
-- 9, 158, 158, 158, 158, 158, 158, 158, 158, 158,
--
-- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
-- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
-- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
-- 158, 158, 158, 158, 158, 158, 158
-+ 21, 21, 21, 21, 10, 22, 10, 24, 25, 25,
-+ 25, 32, 33, 33, 164, 26, 34, 34, 34, 52,
-+ 53, 27, 26, 26, 26, 26, 10, 11, 12, 11,
-+ 13, 14, 28, 15, 16, 28, 28, 28, 24, 28,
-+ 28, 28, 10, 18, 19, 20, 29, 29, 29, 29,
-+ 29, 30, 10, 29, 29, 29, 29, 29, 29, 29,
-+
-+ 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
-+ 10, 22, 10, 23, 34, 34, 34, 37, 39, 43,
-+ 32, 33, 33, 45, 55, 56, 46, 60, 43, 45,
-+ 65, 163, 46, 65, 65, 65, 44, 38, 60, 74,
-+ 58, 47, 141, 48, 142, 44, 49, 47, 50, 48,
-+ 76, 51, 62, 94, 50, 41, 44, 51, 37, 61,
-+ 64, 64, 64, 58, 34, 34, 34, 64, 162, 80,
-+ 67, 68, 68, 68, 64, 64, 64, 64, 38, 81,
-+ 69, 70, 71, 68, 68, 68, 60, 161, 43, 69,
-+ 70, 65, 69, 70, 65, 65, 65, 125, 85, 85,
-+
-+ 85, 58, 68, 68, 68, 44, 102, 110, 125, 133,
-+ 102, 69, 70, 111, 114, 160, 159, 126, 85, 85,
-+ 85, 140, 140, 140, 140, 140, 140, 153, 126, 147,
-+ 147, 147, 153, 148, 147, 147, 147, 158, 148, 165,
-+ 157, 156, 155, 151, 150, 149, 146, 154, 145, 144,
-+ 143, 139, 154, 36, 36, 36, 36, 36, 36, 36,
-+ 36, 40, 138, 137, 136, 40, 40, 42, 42, 42,
-+ 42, 42, 42, 42, 42, 57, 57, 57, 57, 63,
-+ 135, 63, 65, 134, 165, 65, 133, 65, 65, 66,
-+ 132, 131, 66, 66, 66, 66, 72, 130, 72, 72,
-+
-+ 75, 75, 75, 75, 75, 75, 75, 75, 77, 77,
-+ 77, 77, 77, 77, 77, 77, 91, 129, 91, 92,
-+ 128, 92, 92, 127, 92, 92, 124, 124, 124, 124,
-+ 124, 124, 124, 124, 152, 152, 152, 152, 152, 152,
-+ 152, 152, 60, 60, 123, 122, 121, 120, 119, 118,
-+ 117, 45, 116, 111, 115, 113, 112, 109, 108, 107,
-+ 46, 106, 93, 89, 105, 104, 103, 101, 100, 99,
-+ 98, 97, 96, 95, 78, 76, 93, 90, 89, 88,
-+ 58, 87, 86, 58, 84, 83, 82, 79, 78, 76,
-+ 73, 165, 59, 58, 54, 35, 165, 31, 23, 23,
-+
-+ 9, 165, 165, 165, 165, 165, 165, 165, 165, 165,
-+ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
-+ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
-+ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
-+ 165, 165, 165, 165, 165, 165, 165, 165
- } ;
-
--static yyconst flex_int16_t yy_chk[438] =
-+static yyconst flex_int16_t yy_chk[449] =
- { 0,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-- 1, 1, 1, 1, 1, 1, 3, 3, 3, 3,
-- 7, 7, 7, 156, 3, 11, 11, 11, 18, 18,
-- 3, 3, 3, 3, 3, 5, 5, 5, 5, 5,
-+ 1, 1, 1, 1, 1, 1, 1, 3, 3, 3,
-+ 3, 7, 7, 7, 163, 3, 11, 11, 11, 18,
-+ 18, 3, 3, 3, 3, 3, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-- 5, 8, 12, 12, 12, 14, 15, 16, 8, 8,
-- 8, 17, 20, 20, 17, 23, 24, 29, 155, 24,
-- 29, 29, 29, 48, 16, 14, 31, 29, 128, 17,
-- 128, 17, 48, 17, 24, 17, 24, 99, 24, 42,
-- 24, 99, 15, 33, 33, 33, 23, 26, 26, 26,
-- 26, 154, 33, 33, 26, 36, 42, 31, 32, 32,
-- 32, 26, 26, 26, 26, 44, 59, 32, 32, 32,
-- 34, 34, 34, 73, 75, 36, 153, 75, 59, 59,
-- 59, 65, 44, 110, 65, 65, 65, 67, 67, 67,
--
-- 73, 65, 83, 89, 89, 97, 67, 67, 119, 127,
-- 97, 150, 149, 110, 83, 83, 83, 133, 133, 133,
-- 141, 127, 127, 127, 145, 136, 136, 136, 119, 136,
-- 140, 140, 140, 148, 140, 147, 144, 143, 142, 139,
-- 141, 138, 137, 135, 145, 159, 159, 159, 159, 159,
-- 159, 159, 159, 160, 134, 132, 131, 160, 160, 161,
-- 161, 161, 161, 161, 161, 161, 161, 162, 162, 162,
-- 162, 163, 126, 163, 164, 125, 124, 164, 123, 164,
-- 164, 165, 122, 121, 165, 165, 165, 165, 166, 120,
-- 166, 166, 167, 167, 167, 167, 167, 167, 167, 167,
--
-- 168, 168, 168, 168, 168, 168, 168, 168, 169, 118,
-- 169, 170, 117, 170, 170, 116, 170, 170, 171, 171,
-- 171, 171, 171, 171, 171, 171, 172, 172, 172, 172,
-- 172, 172, 172, 172, 115, 114, 112, 111, 109, 108,
-- 107, 106, 105, 104, 103, 102, 101, 100, 98, 96,
-- 95, 94, 93, 92, 90, 88, 86, 85, 84, 82,
-- 81, 80, 79, 78, 77, 76, 74, 72, 69, 68,
-- 66, 63, 61, 60, 56, 50, 49, 47, 46, 45,
-+ 5, 5, 5, 8, 12, 12, 12, 14, 15, 16,
-+ 8, 8, 8, 17, 20, 20, 17, 23, 42, 24,
-+ 29, 162, 24, 29, 29, 29, 16, 14, 31, 44,
-+ 29, 17, 134, 17, 134, 42, 17, 24, 17, 24,
-+ 76, 17, 24, 76, 24, 15, 44, 24, 36, 23,
-+ 26, 26, 26, 26, 34, 34, 34, 26, 161, 48,
-+ 31, 32, 32, 32, 26, 26, 26, 26, 36, 48,
-+ 32, 32, 32, 33, 33, 33, 60, 160, 74, 91,
-+ 91, 66, 33, 33, 66, 66, 66, 114, 60, 60,
-+
-+ 60, 66, 68, 68, 68, 74, 85, 99, 124, 133,
-+ 102, 68, 68, 99, 102, 157, 156, 114, 85, 85,
-+ 85, 133, 133, 133, 140, 140, 140, 148, 124, 143,
-+ 143, 143, 152, 143, 147, 147, 147, 155, 147, 154,
-+ 151, 150, 149, 146, 145, 144, 142, 148, 141, 138,
-+ 137, 132, 152, 166, 166, 166, 166, 166, 166, 166,
-+ 166, 167, 131, 130, 129, 167, 167, 168, 168, 168,
-+ 168, 168, 168, 168, 168, 169, 169, 169, 169, 170,
-+ 128, 170, 171, 127, 126, 171, 125, 171, 171, 172,
-+ 123, 122, 172, 172, 172, 172, 173, 121, 173, 173,
-+
-+ 174, 174, 174, 174, 174, 174, 174, 174, 175, 175,
-+ 175, 175, 175, 175, 175, 175, 176, 120, 176, 177,
-+ 119, 177, 177, 118, 177, 177, 178, 178, 178, 178,
-+ 178, 178, 178, 178, 179, 179, 179, 179, 179, 179,
-+ 179, 179, 116, 115, 113, 112, 111, 110, 109, 108,
-+ 107, 106, 105, 104, 103, 101, 100, 98, 97, 96,
-+ 95, 94, 92, 90, 88, 87, 86, 84, 83, 82,
-+ 81, 80, 79, 78, 77, 75, 73, 70, 69, 67,
-+ 64, 62, 61, 57, 51, 50, 49, 47, 46, 45,
- 41, 38, 22, 21, 19, 13, 9, 6, 4, 2,
-- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
-
-- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
-- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
-- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
-- 158, 158, 158, 158, 158, 158, 158
-+ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
-+ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
-+ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
-+ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
-+ 165, 165, 165, 165, 165, 165, 165, 165
- } ;
-
- static yy_state_type yy_last_accepting_state;
-@@ -662,7 +664,7 @@ static int dts_version = 1;
- static void push_input_file(const char *filename);
- static bool pop_input_file(void);
- static void lexical_error(const char *fmt, ...);
--#line 666 "dtc-lexer.lex.c"
-+#line 668 "dtc-lexer.lex.c"
-
- #define INITIAL 0
- #define BYTESTRING 1
-@@ -704,7 +706,7 @@ FILE *yyget_out (void );
-
- void yyset_out (FILE * out_str );
-
--yy_size_t yyget_leng (void );
-+int yyget_leng (void );
-
- char *yyget_text (void );
-
-@@ -853,6 +855,10 @@ YY_DECL
- register char *yy_cp, *yy_bp;
- register int yy_act;
-
-+#line 68 "dtc-lexer.l"
-+
-+#line 861 "dtc-lexer.lex.c"
-+
- if ( !(yy_init) )
- {
- (yy_init) = 1;
-@@ -879,11 +885,6 @@ YY_DECL
- yy_load_buffer_state( );
- }
-
-- {
--#line 68 "dtc-lexer.l"
--
--#line 886 "dtc-lexer.lex.c"
--
- while ( 1 ) /* loops until end-of-file is reached */
- {
- yy_cp = (yy_c_buf_p);
-@@ -901,7 +902,7 @@ YY_DECL
- yy_match:
- do
- {
-- register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
-+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
- if ( yy_accept[yy_current_state] )
- {
- (yy_last_accepting_state) = yy_current_state;
-@@ -910,13 +911,13 @@ yy_match:
- while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
- {
- yy_current_state = (int) yy_def[yy_current_state];
-- if ( yy_current_state >= 159 )
-+ if ( yy_current_state >= 166 )
- yy_c = yy_meta[(unsigned int) yy_c];
- }
- yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
- ++yy_cp;
- }
-- while ( yy_current_state != 158 );
-+ while ( yy_current_state != 165 );
- yy_cp = (yy_last_accepting_cpos);
- yy_current_state = (yy_last_accepting_state);
-
-@@ -1007,23 +1008,31 @@ case 5:
- YY_RULE_SETUP
- #line 116 "dtc-lexer.l"
- {
-+ DPRINT("Keyword: /plugin/\n");
-+ return DT_PLUGIN;
-+ }
-+ YY_BREAK
-+case 6:
-+YY_RULE_SETUP
-+#line 121 "dtc-lexer.l"
-+{
- DPRINT("Keyword: /memreserve/\n");
- BEGIN_DEFAULT();
- return DT_MEMRESERVE;
- }
- YY_BREAK
--case 6:
-+case 7:
- YY_RULE_SETUP
--#line 122 "dtc-lexer.l"
-+#line 127 "dtc-lexer.l"
- {
- DPRINT("Keyword: /bits/\n");
- BEGIN_DEFAULT();
- return DT_BITS;
- }
- YY_BREAK
--case 7:
-+case 8:
- YY_RULE_SETUP
--#line 128 "dtc-lexer.l"
-+#line 133 "dtc-lexer.l"
- {
- DPRINT("Keyword: /delete-property/\n");
- DPRINT("<PROPNODENAME>\n");
-@@ -1031,9 +1040,9 @@ YY_RULE_SETUP
- return DT_DEL_PROP;
- }
- YY_BREAK
--case 8:
-+case 9:
- YY_RULE_SETUP
--#line 135 "dtc-lexer.l"
-+#line 140 "dtc-lexer.l"
- {
- DPRINT("Keyword: /delete-node/\n");
- DPRINT("<PROPNODENAME>\n");
-@@ -1041,9 +1050,9 @@ YY_RULE_SETUP
- return DT_DEL_NODE;
- }
- YY_BREAK
--case 9:
-+case 10:
- YY_RULE_SETUP
--#line 142 "dtc-lexer.l"
-+#line 147 "dtc-lexer.l"
- {
- DPRINT("Label: %s\n", yytext);
- yylval.labelref = xstrdup(yytext);
-@@ -1051,9 +1060,9 @@ YY_RULE_SETUP
- return DT_LABEL;
- }
- YY_BREAK
--case 10:
-+case 11:
- YY_RULE_SETUP
--#line 149 "dtc-lexer.l"
-+#line 154 "dtc-lexer.l"
- {
- char *e;
- DPRINT("Integer Literal: '%s'\n", yytext);
-@@ -1073,10 +1082,10 @@ YY_RULE_SETUP
- return DT_LITERAL;
- }
- YY_BREAK
--case 11:
--/* rule 11 can match eol */
-+case 12:
-+/* rule 12 can match eol */
- YY_RULE_SETUP
--#line 168 "dtc-lexer.l"
-+#line 173 "dtc-lexer.l"
- {
- struct data d;
- DPRINT("Character literal: %s\n", yytext);
-@@ -1098,18 +1107,18 @@ YY_RULE_SETUP
- return DT_CHAR_LITERAL;
- }
- YY_BREAK
--case 12:
-+case 13:
- YY_RULE_SETUP
--#line 189 "dtc-lexer.l"
-+#line 194 "dtc-lexer.l"
- { /* label reference */
- DPRINT("Ref: %s\n", yytext+1);
- yylval.labelref = xstrdup(yytext+1);
- return DT_REF;
- }
- YY_BREAK
--case 13:
-+case 14:
- YY_RULE_SETUP
--#line 195 "dtc-lexer.l"
-+#line 200 "dtc-lexer.l"
- { /* new-style path reference */
- yytext[yyleng-1] = '\0';
- DPRINT("Ref: %s\n", yytext+2);
-@@ -1117,27 +1126,27 @@ YY_RULE_SETUP
- return DT_REF;
- }
- YY_BREAK
--case 14:
-+case 15:
- YY_RULE_SETUP
--#line 202 "dtc-lexer.l"
-+#line 207 "dtc-lexer.l"
- {
- yylval.byte = strtol(yytext, NULL, 16);
- DPRINT("Byte: %02x\n", (int)yylval.byte);
- return DT_BYTE;
- }
- YY_BREAK
--case 15:
-+case 16:
- YY_RULE_SETUP
--#line 208 "dtc-lexer.l"
-+#line 213 "dtc-lexer.l"
- {
- DPRINT("/BYTESTRING\n");
- BEGIN_DEFAULT();
- return ']';
- }
- YY_BREAK
--case 16:
-+case 17:
- YY_RULE_SETUP
--#line 214 "dtc-lexer.l"
-+#line 219 "dtc-lexer.l"
- {
- DPRINT("PropNodeName: %s\n", yytext);
- yylval.propnodename = xstrdup((yytext[0] == '\\') ?
-@@ -1146,75 +1155,75 @@ YY_RULE_SETUP
- return DT_PROPNODENAME;
- }
- YY_BREAK
--case 17:
-+case 18:
- YY_RULE_SETUP
--#line 222 "dtc-lexer.l"
-+#line 227 "dtc-lexer.l"
- {
- DPRINT("Binary Include\n");
- return DT_INCBIN;
- }
- YY_BREAK
--case 18:
--/* rule 18 can match eol */
--YY_RULE_SETUP
--#line 227 "dtc-lexer.l"
--/* eat whitespace */
-- YY_BREAK
- case 19:
- /* rule 19 can match eol */
- YY_RULE_SETUP
--#line 228 "dtc-lexer.l"
--/* eat C-style comments */
-+#line 232 "dtc-lexer.l"
-+/* eat whitespace */
- YY_BREAK
- case 20:
- /* rule 20 can match eol */
- YY_RULE_SETUP
--#line 229 "dtc-lexer.l"
--/* eat C++-style comments */
-+#line 233 "dtc-lexer.l"
-+/* eat C-style comments */
- YY_BREAK
- case 21:
-+/* rule 21 can match eol */
- YY_RULE_SETUP
--#line 231 "dtc-lexer.l"
--{ return DT_LSHIFT; };
-+#line 234 "dtc-lexer.l"
-+/* eat C++-style comments */
- YY_BREAK
- case 22:
- YY_RULE_SETUP
--#line 232 "dtc-lexer.l"
--{ return DT_RSHIFT; };
-+#line 236 "dtc-lexer.l"
-+{ return DT_LSHIFT; };
- YY_BREAK
- case 23:
- YY_RULE_SETUP
--#line 233 "dtc-lexer.l"
--{ return DT_LE; };
-+#line 237 "dtc-lexer.l"
-+{ return DT_RSHIFT; };
- YY_BREAK
- case 24:
- YY_RULE_SETUP
--#line 234 "dtc-lexer.l"
--{ return DT_GE; };
-+#line 238 "dtc-lexer.l"
-+{ return DT_LE; };
- YY_BREAK
- case 25:
- YY_RULE_SETUP
--#line 235 "dtc-lexer.l"
--{ return DT_EQ; };
-+#line 239 "dtc-lexer.l"
-+{ return DT_GE; };
- YY_BREAK
- case 26:
- YY_RULE_SETUP
--#line 236 "dtc-lexer.l"
--{ return DT_NE; };
-+#line 240 "dtc-lexer.l"
-+{ return DT_EQ; };
- YY_BREAK
- case 27:
- YY_RULE_SETUP
--#line 237 "dtc-lexer.l"
--{ return DT_AND; };
-+#line 241 "dtc-lexer.l"
-+{ return DT_NE; };
- YY_BREAK
- case 28:
- YY_RULE_SETUP
--#line 238 "dtc-lexer.l"
--{ return DT_OR; };
-+#line 242 "dtc-lexer.l"
-+{ return DT_AND; };
- YY_BREAK
- case 29:
- YY_RULE_SETUP
--#line 240 "dtc-lexer.l"
-+#line 243 "dtc-lexer.l"
-+{ return DT_OR; };
-+ YY_BREAK
-+case 30:
-+YY_RULE_SETUP
-+#line 245 "dtc-lexer.l"
- {
- DPRINT("Char: %c (\\x%02x)\n", yytext[0],
- (unsigned)yytext[0]);
-@@ -1230,12 +1239,12 @@ YY_RULE_SETUP
- return yytext[0];
- }
- YY_BREAK
--case 30:
-+case 31:
- YY_RULE_SETUP
--#line 255 "dtc-lexer.l"
-+#line 260 "dtc-lexer.l"
- ECHO;
- YY_BREAK
--#line 1239 "dtc-lexer.lex.c"
-+#line 1248 "dtc-lexer.lex.c"
-
- case YY_END_OF_BUFFER:
- {
-@@ -1365,7 +1374,6 @@ ECHO;
- "fatal flex scanner internal error--no action found" );
- } /* end of action switch */
- } /* end of scanning one token */
-- } /* end of user's declarations */
- } /* end of yylex */
-
- /* yy_get_next_buffer - try to read in a new buffer
-@@ -1421,21 +1429,21 @@ static int yy_get_next_buffer (void)
-
- else
- {
-- yy_size_t num_to_read =
-+ int num_to_read =
- YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
-
- while ( num_to_read <= 0 )
- { /* Not enough room in the buffer - grow it. */
-
- /* just a shorter name for the current buffer */
-- YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
-+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
-
- int yy_c_buf_p_offset =
- (int) ((yy_c_buf_p) - b->yy_ch_buf);
-
- if ( b->yy_is_our_buffer )
- {
-- yy_size_t new_size = b->yy_buf_size * 2;
-+ int new_size = b->yy_buf_size * 2;
-
- if ( new_size <= 0 )
- b->yy_buf_size += b->yy_buf_size / 8;
-@@ -1466,7 +1474,7 @@ static int yy_get_next_buffer (void)
-
- /* Read in more data. */
- YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
-- (yy_n_chars), num_to_read );
-+ (yy_n_chars), (size_t) num_to_read );
-
- YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
- }
-@@ -1528,7 +1536,7 @@ static int yy_get_next_buffer (void)
- while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
- {
- yy_current_state = (int) yy_def[yy_current_state];
-- if ( yy_current_state >= 159 )
-+ if ( yy_current_state >= 166 )
- yy_c = yy_meta[(unsigned int) yy_c];
- }
- yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-@@ -1556,13 +1564,13 @@ static int yy_get_next_buffer (void)
- while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
- {
- yy_current_state = (int) yy_def[yy_current_state];
-- if ( yy_current_state >= 159 )
-+ if ( yy_current_state >= 166 )
- yy_c = yy_meta[(unsigned int) yy_c];
- }
- yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-- yy_is_jam = (yy_current_state == 158);
-+ yy_is_jam = (yy_current_state == 165);
-
-- return yy_is_jam ? 0 : yy_current_state;
-+ return yy_is_jam ? 0 : yy_current_state;
- }
-
- #ifndef YY_NO_INPUT
-@@ -1589,7 +1597,7 @@ static int yy_get_next_buffer (void)
-
- else
- { /* need more input */
-- yy_size_t offset = (yy_c_buf_p) - (yytext_ptr);
-+ int offset = (yy_c_buf_p) - (yytext_ptr);
- ++(yy_c_buf_p);
-
- switch ( yy_get_next_buffer( ) )
-@@ -1863,7 +1871,7 @@ void yypop_buffer_state (void)
- */
- static void yyensure_buffer_stack (void)
- {
-- yy_size_t num_to_alloc;
-+ int num_to_alloc;
-
- if (!(yy_buffer_stack)) {
-
-@@ -1960,12 +1968,12 @@ YY_BUFFER_STATE yy_scan_string (yyconst
- *
- * @return the newly allocated buffer state object.
- */
--YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len )
-+YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len )
- {
- YY_BUFFER_STATE b;
- char *buf;
- yy_size_t n;
-- yy_size_t i;
-+ int i;
-
- /* Get memory for full buffer, including space for trailing EOB's. */
- n = _yybytes_len + 2;
-@@ -2047,7 +2055,7 @@ FILE *yyget_out (void)
- /** Get the length of the current token.
- *
- */
--yy_size_t yyget_leng (void)
-+int yyget_leng (void)
- {
- return yyleng;
- }
-@@ -2195,7 +2203,7 @@ void yyfree (void * ptr )
-
- #define YYTABLES_NAME "yytables"
-
--#line 254 "dtc-lexer.l"
-+#line 260 "dtc-lexer.l"
-
-
-
---- a/scripts/dtc/dtc-parser.tab.c_shipped
-+++ b/scripts/dtc/dtc-parser.tab.c_shipped
-@@ -1,19 +1,19 @@
--/* A Bison parser, made by GNU Bison 3.0.2. */
-+/* A Bison parser, made by GNU Bison 2.5. */
-
- /* Bison implementation for Yacc-like parsers in C
--
-- Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
--
-+
-+ Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
-+
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. */
-
-@@ -26,7 +26,7 @@
- special exception, which will cause the skeleton and the resulting
- Bison output files to be licensed under the GNU General Public
- License without this special exception.
--
-+
- This special exception was added by the Free Software Foundation in
- version 2.2 of Bison. */
-
-@@ -44,7 +44,7 @@
- #define YYBISON 1
-
- /* Bison version. */
--#define YYBISON_VERSION "3.0.2"
-+#define YYBISON_VERSION "2.5"
-
- /* Skeleton name. */
- #define YYSKELETON_NAME "yacc.c"
-@@ -58,13 +58,18 @@
- /* Pull parsers. */
- #define YYPULL 1
-
-+/* Using locations. */
-+#define YYLSP_NEEDED 1
-
-
-
- /* Copy the first part of user declarations. */
--#line 20 "dtc-parser.y" /* yacc.c:339 */
-+
-+/* Line 268 of yacc.c */
-+#line 20 "dtc-parser.y"
-
- #include <stdio.h>
-+#include <inttypes.h>
-
- #include "dtc.h"
- #include "srcpos.h"
-@@ -80,15 +85,14 @@ extern void yyerror(char const *s);
- extern struct boot_info *the_boot_info;
- extern bool treesource_error;
-
--#line 84 "dtc-parser.tab.c" /* yacc.c:339 */
-
--# ifndef YY_NULLPTR
--# if defined __cplusplus && 201103L <= __cplusplus
--# define YY_NULLPTR nullptr
--# else
--# define YY_NULLPTR 0
--# endif
--# endif
-+/* Line 268 of yacc.c */
-+#line 91 "dtc-parser.tab.c"
-+
-+/* Enabling traces. */
-+#ifndef YYDEBUG
-+# define YYDEBUG 0
-+#endif
-
- /* Enabling verbose error messages. */
- #ifdef YYERROR_VERBOSE
-@@ -98,53 +102,51 @@ extern bool treesource_error;
- # define YYERROR_VERBOSE 0
- #endif
-
--/* In a future release of Bison, this section will be replaced
-- by #include "dtc-parser.tab.h". */
--#ifndef YY_YY_DTC_PARSER_TAB_H_INCLUDED
--# define YY_YY_DTC_PARSER_TAB_H_INCLUDED
--/* Debug traces. */
--#ifndef YYDEBUG
--# define YYDEBUG 0
--#endif
--#if YYDEBUG
--extern int yydebug;
-+/* Enabling the token table. */
-+#ifndef YYTOKEN_TABLE
-+# define YYTOKEN_TABLE 0
- #endif
-
--/* Token type. */
-+
-+/* Tokens. */
- #ifndef YYTOKENTYPE
- # define YYTOKENTYPE
-- enum yytokentype
-- {
-- DT_V1 = 258,
-- DT_MEMRESERVE = 259,
-- DT_LSHIFT = 260,
-- DT_RSHIFT = 261,
-- DT_LE = 262,
-- DT_GE = 263,
-- DT_EQ = 264,
-- DT_NE = 265,
-- DT_AND = 266,
-- DT_OR = 267,
-- DT_BITS = 268,
-- DT_DEL_PROP = 269,
-- DT_DEL_NODE = 270,
-- DT_PROPNODENAME = 271,
-- DT_LITERAL = 272,
-- DT_CHAR_LITERAL = 273,
-- DT_BYTE = 274,
-- DT_STRING = 275,
-- DT_LABEL = 276,
-- DT_REF = 277,
-- DT_INCBIN = 278
-- };
-+ /* Put the tokens into the symbol table, so that GDB and other debuggers
-+ know about them. */
-+ enum yytokentype {
-+ DT_V1 = 258,
-+ DT_PLUGIN = 259,
-+ DT_MEMRESERVE = 260,
-+ DT_LSHIFT = 261,
-+ DT_RSHIFT = 262,
-+ DT_LE = 263,
-+ DT_GE = 264,
-+ DT_EQ = 265,
-+ DT_NE = 266,
-+ DT_AND = 267,
-+ DT_OR = 268,
-+ DT_BITS = 269,
-+ DT_DEL_PROP = 270,
-+ DT_DEL_NODE = 271,
-+ DT_PROPNODENAME = 272,
-+ DT_LITERAL = 273,
-+ DT_CHAR_LITERAL = 274,
-+ DT_BYTE = 275,
-+ DT_STRING = 276,
-+ DT_LABEL = 277,
-+ DT_REF = 278,
-+ DT_INCBIN = 279
-+ };
- #endif
-
--/* Value type. */
-+
-+
- #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
--typedef union YYSTYPE YYSTYPE;
--union YYSTYPE
-+typedef union YYSTYPE
- {
--#line 38 "dtc-parser.y" /* yacc.c:355 */
-+
-+/* Line 293 of yacc.c */
-+#line 39 "dtc-parser.y"
-
- char *propnodename;
- char *labelref;
-@@ -162,37 +164,37 @@ union YYSTYPE
- struct node *nodelist;
- struct reserve_info *re;
- uint64_t integer;
-+ int is_plugin;
-
--#line 167 "dtc-parser.tab.c" /* yacc.c:355 */
--};
-+
-+
-+/* Line 293 of yacc.c */
-+#line 173 "dtc-parser.tab.c"
-+} YYSTYPE;
- # define YYSTYPE_IS_TRIVIAL 1
-+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
- # define YYSTYPE_IS_DECLARED 1
- #endif
-
--/* Location type. */
- #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
--typedef struct YYLTYPE YYLTYPE;
--struct YYLTYPE
-+typedef struct YYLTYPE
- {
- int first_line;
- int first_column;
- int last_line;
- int last_column;
--};
-+} YYLTYPE;
-+# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
- # define YYLTYPE_IS_DECLARED 1
- # define YYLTYPE_IS_TRIVIAL 1
- #endif
-
-
--extern YYSTYPE yylval;
--extern YYLTYPE yylloc;
--int yyparse (void);
--
--#endif /* !YY_YY_DTC_PARSER_TAB_H_INCLUDED */
--
- /* Copy the second part of user declarations. */
-
--#line 196 "dtc-parser.tab.c" /* yacc.c:358 */
-+
-+/* Line 343 of yacc.c */
-+#line 198 "dtc-parser.tab.c"
-
- #ifdef short
- # undef short
-@@ -206,8 +208,11 @@ typedef unsigned char yytype_uint8;
-
- #ifdef YYTYPE_INT8
- typedef YYTYPE_INT8 yytype_int8;
--#else
-+#elif (defined __STDC__ || defined __C99__FUNC__ \
-+ || defined __cplusplus || defined _MSC_VER)
- typedef signed char yytype_int8;
-+#else
-+typedef short int yytype_int8;
- #endif
-
- #ifdef YYTYPE_UINT16
-@@ -227,7 +232,8 @@ typedef short int yytype_int16;
- # define YYSIZE_T __SIZE_TYPE__
- # elif defined size_t
- # define YYSIZE_T size_t
--# elif ! defined YYSIZE_T
-+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
-+ || defined __cplusplus || defined _MSC_VER)
- # include <stddef.h> /* INFRINGES ON USER NAME SPACE */
- # define YYSIZE_T size_t
- # else
-@@ -241,68 +247,39 @@ typedef short int yytype_int16;
- # if defined YYENABLE_NLS && YYENABLE_NLS
- # if ENABLE_NLS
- # include <libintl.h> /* INFRINGES ON USER NAME SPACE */
--# define YY_(Msgid) dgettext ("bison-runtime", Msgid)
-+# define YY_(msgid) dgettext ("bison-runtime", msgid)
- # endif
- # endif
- # ifndef YY_
--# define YY_(Msgid) Msgid
--# endif
--#endif
--
--#ifndef YY_ATTRIBUTE
--# if (defined __GNUC__ \
-- && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \
-- || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C
--# define YY_ATTRIBUTE(Spec) __attribute__(Spec)
--# else
--# define YY_ATTRIBUTE(Spec) /* empty */
--# endif
--#endif
--
--#ifndef YY_ATTRIBUTE_PURE
--# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__))
--#endif
--
--#ifndef YY_ATTRIBUTE_UNUSED
--# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__))
--#endif
--
--#if !defined _Noreturn \
-- && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112)
--# if defined _MSC_VER && 1200 <= _MSC_VER
--# define _Noreturn __declspec (noreturn)
--# else
--# define _Noreturn YY_ATTRIBUTE ((__noreturn__))
-+# define YY_(msgid) msgid
- # endif
- #endif
-
- /* Suppress unused-variable warnings by "using" E. */
- #if ! defined lint || defined __GNUC__
--# define YYUSE(E) ((void) (E))
-+# define YYUSE(e) ((void) (e))
- #else
--# define YYUSE(E) /* empty */
-+# define YYUSE(e) /* empty */
- #endif
-
--#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
--/* Suppress an incorrect diagnostic about yylval being uninitialized. */
--# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
-- _Pragma ("GCC diagnostic push") \
-- _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\
-- _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
--# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
-- _Pragma ("GCC diagnostic pop")
-+/* Identity function, used to suppress warnings about constant conditions. */
-+#ifndef lint
-+# define YYID(n) (n)
- #else
--# define YY_INITIAL_VALUE(Value) Value
--#endif
--#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
--# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
--# define YY_IGNORE_MAYBE_UNINITIALIZED_END
-+#if (defined __STDC__ || defined __C99__FUNC__ \
-+ || defined __cplusplus || defined _MSC_VER)
-+static int
-+YYID (int yyi)
-+#else
-+static int
-+YYID (yyi)
-+ int yyi;
- #endif
--#ifndef YY_INITIAL_VALUE
--# define YY_INITIAL_VALUE(Value) /* Nothing. */
-+{
-+ return yyi;
-+}
- #endif
-
--
- #if ! defined yyoverflow || YYERROR_VERBOSE
-
- /* The parser invokes alloca or malloc; define the necessary symbols. */
-@@ -320,9 +297,9 @@ typedef short int yytype_int16;
- # define alloca _alloca
- # else
- # define YYSTACK_ALLOC alloca
--# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS
-+# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
-+ || defined __cplusplus || defined _MSC_VER)
- # include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-- /* Use EXIT_SUCCESS as a witness for stdlib.h. */
- # ifndef EXIT_SUCCESS
- # define EXIT_SUCCESS 0
- # endif
-@@ -332,8 +309,8 @@ typedef short int yytype_int16;
- # endif
-
- # ifdef YYSTACK_ALLOC
-- /* Pacify GCC's 'empty if-body' warning. */
--# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
-+ /* Pacify GCC's `empty if-body' warning. */
-+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
- # ifndef YYSTACK_ALLOC_MAXIMUM
- /* The OS might guarantee only one guard page at the bottom of the stack,
- and a page size can be as small as 4096 bytes. So we cannot safely
-@@ -349,7 +326,7 @@ typedef short int yytype_int16;
- # endif
- # if (defined __cplusplus && ! defined EXIT_SUCCESS \
- && ! ((defined YYMALLOC || defined malloc) \
-- && (defined YYFREE || defined free)))
-+ && (defined YYFREE || defined free)))
- # include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
- # ifndef EXIT_SUCCESS
- # define EXIT_SUCCESS 0
-@@ -357,13 +334,15 @@ typedef short int yytype_int16;
- # endif
- # ifndef YYMALLOC
- # define YYMALLOC malloc
--# if ! defined malloc && ! defined EXIT_SUCCESS
-+# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
-+ || defined __cplusplus || defined _MSC_VER)
- void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
- # endif
- # endif
- # ifndef YYFREE
- # define YYFREE free
--# if ! defined free && ! defined EXIT_SUCCESS
-+# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
-+ || defined __cplusplus || defined _MSC_VER)
- void free (void *); /* INFRINGES ON USER NAME SPACE */
- # endif
- # endif
-@@ -373,8 +352,8 @@ void free (void *); /* INFRINGES ON USER
-
- #if (! defined yyoverflow \
- && (! defined __cplusplus \
-- || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
-- && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
-+ || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
-+ && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
-
- /* A type that is properly aligned for any stack member. */
- union yyalloc
-@@ -400,35 +379,35 @@ union yyalloc
- elements in the stack, and YYPTR gives the new location of the
- stack. Advance YYPTR to a properly aligned location for the next
- stack. */
--# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
-- do \
-- { \
-- YYSIZE_T yynewbytes; \
-- YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
-- Stack = &yyptr->Stack_alloc; \
-- yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
-- yyptr += yynewbytes / sizeof (*yyptr); \
-- } \
-- while (0)
-+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
-+ do \
-+ { \
-+ YYSIZE_T yynewbytes; \
-+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
-+ Stack = &yyptr->Stack_alloc; \
-+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
-+ yyptr += yynewbytes / sizeof (*yyptr); \
-+ } \
-+ while (YYID (0))
-
- #endif
-
- #if defined YYCOPY_NEEDED && YYCOPY_NEEDED
--/* Copy COUNT objects from SRC to DST. The source and destination do
-+/* Copy COUNT objects from FROM to TO. The source and destination do
- not overlap. */
- # ifndef YYCOPY
- # if defined __GNUC__ && 1 < __GNUC__
--# define YYCOPY(Dst, Src, Count) \
-- __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
-+# define YYCOPY(To, From, Count) \
-+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
- # else
--# define YYCOPY(Dst, Src, Count) \
-- do \
-- { \
-- YYSIZE_T yyi; \
-- for (yyi = 0; yyi < (Count); yyi++) \
-- (Dst)[yyi] = (Src)[yyi]; \
-- } \
-- while (0)
-+# define YYCOPY(To, From, Count) \
-+ do \
-+ { \
-+ YYSIZE_T yyi; \
-+ for (yyi = 0; yyi < (Count); yyi++) \
-+ (To)[yyi] = (From)[yyi]; \
-+ } \
-+ while (YYID (0))
- # endif
- # endif
- #endif /* !YYCOPY_NEEDED */
-@@ -439,39 +418,37 @@ union yyalloc
- #define YYLAST 136
-
- /* YYNTOKENS -- Number of terminals. */
--#define YYNTOKENS 47
-+#define YYNTOKENS 48
- /* YYNNTS -- Number of nonterminals. */
--#define YYNNTS 28
-+#define YYNNTS 29
- /* YYNRULES -- Number of rules. */
--#define YYNRULES 80
--/* YYNSTATES -- Number of states. */
--#define YYNSTATES 144
-+#define YYNRULES 82
-+/* YYNRULES -- Number of states. */
-+#define YYNSTATES 147
-
--/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
-- by yylex, with out-of-bounds checking. */
-+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
- #define YYUNDEFTOK 2
--#define YYMAXUTOK 278
-+#define YYMAXUTOK 279
-
--#define YYTRANSLATE(YYX) \
-+#define YYTRANSLATE(YYX) \
- ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
-
--/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
-- as returned by yylex, without out-of-bounds checking. */
-+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
- static const yytype_uint8 yytranslate[] =
- {
- 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-- 2, 2, 2, 46, 2, 2, 2, 44, 40, 2,
-- 32, 34, 43, 41, 33, 42, 2, 25, 2, 2,
-- 2, 2, 2, 2, 2, 2, 2, 2, 37, 24,
-- 35, 28, 29, 36, 2, 2, 2, 2, 2, 2,
-+ 2, 2, 2, 47, 2, 2, 2, 45, 41, 2,
-+ 33, 35, 44, 42, 34, 43, 2, 26, 2, 2,
-+ 2, 2, 2, 2, 2, 2, 2, 2, 38, 25,
-+ 36, 29, 30, 37, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-- 2, 30, 2, 31, 39, 2, 2, 2, 2, 2,
-+ 2, 31, 2, 32, 40, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-- 2, 2, 2, 26, 38, 27, 45, 2, 2, 2,
-+ 2, 2, 2, 27, 39, 28, 46, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-@@ -486,292 +463,335 @@ static const yytype_uint8 yytranslate[]
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
- 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
-- 15, 16, 17, 18, 19, 20, 21, 22, 23
-+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24
- };
-
- #if YYDEBUG
-- /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
-+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
-+ YYRHS. */
-+static const yytype_uint16 yyprhs[] =
-+{
-+ 0, 0, 3, 9, 10, 13, 14, 17, 22, 25,
-+ 28, 32, 37, 41, 46, 52, 53, 56, 61, 64,
-+ 68, 71, 74, 78, 83, 86, 96, 102, 105, 106,
-+ 109, 112, 116, 118, 121, 124, 127, 129, 131, 135,
-+ 137, 139, 145, 147, 151, 153, 157, 159, 163, 165,
-+ 169, 171, 175, 177, 181, 185, 187, 191, 195, 199,
-+ 203, 207, 211, 213, 217, 221, 223, 227, 231, 235,
-+ 237, 239, 242, 245, 248, 249, 252, 255, 256, 259,
-+ 262, 265, 269
-+};
-+
-+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
-+static const yytype_int8 yyrhs[] =
-+{
-+ 49, 0, -1, 3, 25, 50, 51, 53, -1, -1,
-+ 4, 25, -1, -1, 52, 51, -1, 5, 60, 60,
-+ 25, -1, 22, 52, -1, 26, 54, -1, 53, 26,
-+ 54, -1, 53, 22, 23, 54, -1, 53, 23, 54,
-+ -1, 53, 16, 23, 25, -1, 27, 55, 75, 28,
-+ 25, -1, -1, 55, 56, -1, 17, 29, 57, 25,
-+ -1, 17, 25, -1, 15, 17, 25, -1, 22, 56,
-+ -1, 58, 21, -1, 58, 59, 30, -1, 58, 31,
-+ 74, 32, -1, 58, 23, -1, 58, 24, 33, 21,
-+ 34, 60, 34, 60, 35, -1, 58, 24, 33, 21,
-+ 35, -1, 57, 22, -1, -1, 57, 34, -1, 58,
-+ 22, -1, 14, 18, 36, -1, 36, -1, 59, 60,
-+ -1, 59, 23, -1, 59, 22, -1, 18, -1, 19,
-+ -1, 33, 61, 35, -1, 62, -1, 63, -1, 63,
-+ 37, 61, 38, 62, -1, 64, -1, 63, 13, 64,
-+ -1, 65, -1, 64, 12, 65, -1, 66, -1, 65,
-+ 39, 66, -1, 67, -1, 66, 40, 67, -1, 68,
-+ -1, 67, 41, 68, -1, 69, -1, 68, 10, 69,
-+ -1, 68, 11, 69, -1, 70, -1, 69, 36, 70,
-+ -1, 69, 30, 70, -1, 69, 8, 70, -1, 69,
-+ 9, 70, -1, 70, 6, 71, -1, 70, 7, 71,
-+ -1, 71, -1, 71, 42, 72, -1, 71, 43, 72,
-+ -1, 72, -1, 72, 44, 73, -1, 72, 26, 73,
-+ -1, 72, 45, 73, -1, 73, -1, 60, -1, 43,
-+ 73, -1, 46, 73, -1, 47, 73, -1, -1, 74,
-+ 20, -1, 74, 22, -1, -1, 76, 75, -1, 76,
-+ 56, -1, 17, 54, -1, 16, 17, 25, -1, 22,
-+ 76, -1
-+};
-+
-+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
- static const yytype_uint16 yyrline[] =
- {
-- 0, 104, 104, 113, 116, 123, 127, 135, 139, 144,
-- 155, 165, 180, 188, 191, 198, 202, 206, 210, 218,
-- 222, 226, 230, 234, 250, 260, 268, 271, 275, 282,
-- 298, 303, 322, 336, 343, 344, 345, 352, 356, 357,
-- 361, 362, 366, 367, 371, 372, 376, 377, 381, 382,
-- 386, 387, 388, 392, 393, 394, 395, 396, 400, 401,
-- 402, 406, 407, 408, 412, 413, 414, 415, 419, 420,
-- 421, 422, 427, 430, 434, 442, 445, 449, 457, 461,
-- 465
-+ 0, 108, 108, 119, 122, 130, 133, 140, 144, 152,
-+ 156, 161, 172, 182, 197, 205, 208, 215, 219, 223,
-+ 227, 235, 239, 243, 247, 251, 267, 277, 285, 288,
-+ 292, 299, 315, 320, 339, 353, 360, 361, 362, 369,
-+ 373, 374, 378, 379, 383, 384, 388, 389, 393, 394,
-+ 398, 399, 403, 404, 405, 409, 410, 411, 412, 413,
-+ 417, 418, 419, 423, 424, 425, 429, 430, 431, 432,
-+ 436, 437, 438, 439, 444, 447, 451, 459, 462, 466,
-+ 474, 478, 482
- };
- #endif
-
--#if YYDEBUG || YYERROR_VERBOSE || 0
-+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
- /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
- First, the terminals, then, starting at YYNTOKENS, nonterminals. */
- static const char *const yytname[] =
- {
-- "$end", "error", "$undefined", "DT_V1", "DT_MEMRESERVE", "DT_LSHIFT",
-- "DT_RSHIFT", "DT_LE", "DT_GE", "DT_EQ", "DT_NE", "DT_AND", "DT_OR",
-- "DT_BITS", "DT_DEL_PROP", "DT_DEL_NODE", "DT_PROPNODENAME", "DT_LITERAL",
-- "DT_CHAR_LITERAL", "DT_BYTE", "DT_STRING", "DT_LABEL", "DT_REF",
-- "DT_INCBIN", "';'", "'/'", "'{'", "'}'", "'='", "'>'", "'['", "']'",
-- "'('", "','", "')'", "'<'", "'?'", "':'", "'|'", "'^'", "'&'", "'+'",
-- "'-'", "'*'", "'%'", "'~'", "'!'", "$accept", "sourcefile",
-- "memreserves", "memreserve", "devicetree", "nodedef", "proplist",
-- "propdef", "propdata", "propdataprefix", "arrayprefix", "integer_prim",
-- "integer_expr", "integer_trinary", "integer_or", "integer_and",
-- "integer_bitor", "integer_bitxor", "integer_bitand", "integer_eq",
-- "integer_rela", "integer_shift", "integer_add", "integer_mul",
-- "integer_unary", "bytestring", "subnodes", "subnode", YY_NULLPTR
-+ "$end", "error", "$undefined", "DT_V1", "DT_PLUGIN", "DT_MEMRESERVE",
-+ "DT_LSHIFT", "DT_RSHIFT", "DT_LE", "DT_GE", "DT_EQ", "DT_NE", "DT_AND",
-+ "DT_OR", "DT_BITS", "DT_DEL_PROP", "DT_DEL_NODE", "DT_PROPNODENAME",
-+ "DT_LITERAL", "DT_CHAR_LITERAL", "DT_BYTE", "DT_STRING", "DT_LABEL",
-+ "DT_REF", "DT_INCBIN", "';'", "'/'", "'{'", "'}'", "'='", "'>'", "'['",
-+ "']'", "'('", "','", "')'", "'<'", "'?'", "':'", "'|'", "'^'", "'&'",
-+ "'+'", "'-'", "'*'", "'%'", "'~'", "'!'", "$accept", "sourcefile",
-+ "plugindecl", "memreserves", "memreserve", "devicetree", "nodedef",
-+ "proplist", "propdef", "propdata", "propdataprefix", "arrayprefix",
-+ "integer_prim", "integer_expr", "integer_trinary", "integer_or",
-+ "integer_and", "integer_bitor", "integer_bitxor", "integer_bitand",
-+ "integer_eq", "integer_rela", "integer_shift", "integer_add",
-+ "integer_mul", "integer_unary", "bytestring", "subnodes", "subnode", 0
- };
- #endif
-
- # ifdef YYPRINT
--/* YYTOKNUM[NUM] -- (External) token number corresponding to the
-- (internal) symbol number NUM (which must be that of a token). */
-+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
-+ token YYLEX-NUM. */
- static const yytype_uint16 yytoknum[] =
- {
- 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
- 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
-- 275, 276, 277, 278, 59, 47, 123, 125, 61, 62,
-- 91, 93, 40, 44, 41, 60, 63, 58, 124, 94,
-- 38, 43, 45, 42, 37, 126, 33
-+ 275, 276, 277, 278, 279, 59, 47, 123, 125, 61,
-+ 62, 91, 93, 40, 44, 41, 60, 63, 58, 124,
-+ 94, 38, 43, 45, 42, 37, 126, 33
- };
- # endif
-
--#define YYPACT_NINF -81
--
--#define yypact_value_is_default(Yystate) \
-- (!!((Yystate) == (-81)))
--
--#define YYTABLE_NINF -1
--
--#define yytable_value_is_error(Yytable_value) \
-- 0
--
-- /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
-- STATE-NUM. */
--static const yytype_int8 yypact[] =
-+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
-+static const yytype_uint8 yyr1[] =
- {
-- 16, -11, 21, 10, -81, 25, 10, 19, 10, -81,
-- -81, -9, 25, -81, 2, 51, -81, -9, -9, -9,
-- -81, 1, -81, -6, 50, 14, 28, 29, 36, 3,
-- 58, 44, -3, -81, 47, -81, -81, 65, 68, 2,
-- 2, -81, -81, -81, -81, -9, -9, -9, -9, -9,
-- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
-- -9, -9, -9, -9, -81, 63, 69, 2, -81, -81,
-- 50, 57, 14, 28, 29, 36, 3, 3, 58, 58,
-- 58, 58, 44, 44, -3, -3, -81, -81, -81, 79,
-- 80, -8, 63, -81, 72, 63, -81, -81, -9, 76,
-- 77, -81, -81, -81, -81, -81, 78, -81, -81, -81,
-- -81, -81, 35, 4, -81, -81, -81, -81, 86, -81,
-- -81, -81, 73, -81, -81, 33, 71, 84, 39, -81,
-- -81, -81, -81, -81, 41, -81, -81, -81, 25, -81,
-- 74, 25, 75, -81
-+ 0, 48, 49, 50, 50, 51, 51, 52, 52, 53,
-+ 53, 53, 53, 53, 54, 55, 55, 56, 56, 56,
-+ 56, 57, 57, 57, 57, 57, 57, 57, 58, 58,
-+ 58, 59, 59, 59, 59, 59, 60, 60, 60, 61,
-+ 62, 62, 63, 63, 64, 64, 65, 65, 66, 66,
-+ 67, 67, 68, 68, 68, 69, 69, 69, 69, 69,
-+ 70, 70, 70, 71, 71, 71, 72, 72, 72, 72,
-+ 73, 73, 73, 73, 74, 74, 74, 75, 75, 75,
-+ 76, 76, 76
- };
-
-- /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
-- Performed when YYTABLE does not specify something else to do. Zero
-- means the default is an error. */
--static const yytype_uint8 yydefact[] =
-+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
-+static const yytype_uint8 yyr2[] =
- {
-- 0, 0, 0, 3, 1, 0, 0, 0, 3, 34,
-- 35, 0, 0, 6, 0, 2, 4, 0, 0, 0,
-- 68, 0, 37, 38, 40, 42, 44, 46, 48, 50,
-- 53, 60, 63, 67, 0, 13, 7, 0, 0, 0,
-- 0, 69, 70, 71, 36, 0, 0, 0, 0, 0,
-- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-- 0, 0, 0, 0, 5, 75, 0, 0, 10, 8,
-- 41, 0, 43, 45, 47, 49, 51, 52, 56, 57,
-- 55, 54, 58, 59, 61, 62, 65, 64, 66, 0,
-- 0, 0, 0, 14, 0, 75, 11, 9, 0, 0,
-- 0, 16, 26, 78, 18, 80, 0, 77, 76, 39,
-- 17, 79, 0, 0, 12, 25, 15, 27, 0, 19,
-- 28, 22, 0, 72, 30, 0, 0, 0, 0, 33,
-- 32, 20, 31, 29, 0, 73, 74, 21, 0, 24,
-- 0, 0, 0, 23
-+ 0, 2, 5, 0, 2, 0, 2, 4, 2, 2,
-+ 3, 4, 3, 4, 5, 0, 2, 4, 2, 3,
-+ 2, 2, 3, 4, 2, 9, 5, 2, 0, 2,
-+ 2, 3, 1, 2, 2, 2, 1, 1, 3, 1,
-+ 1, 5, 1, 3, 1, 3, 1, 3, 1, 3,
-+ 1, 3, 1, 3, 3, 1, 3, 3, 3, 3,
-+ 3, 3, 1, 3, 3, 1, 3, 3, 3, 1,
-+ 1, 2, 2, 2, 0, 2, 2, 0, 2, 2,
-+ 2, 3, 2
- };
-
-- /* YYPGOTO[NTERM-NUM]. */
--static const yytype_int8 yypgoto[] =
-+/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
-+ Performed when YYTABLE doesn't specify something else to do. Zero
-+ means the default is an error. */
-+static const yytype_uint8 yydefact[] =
- {
-- -81, -81, 100, 104, -81, -38, -81, -80, -81, -81,
-- -81, -5, 66, 13, -81, 70, 67, 81, 64, 82,
-- 37, 27, 34, 38, -14, -81, 22, 24
-+ 0, 0, 0, 3, 1, 0, 5, 4, 0, 0,
-+ 0, 5, 36, 37, 0, 0, 8, 0, 2, 6,
-+ 0, 0, 0, 70, 0, 39, 40, 42, 44, 46,
-+ 48, 50, 52, 55, 62, 65, 69, 0, 15, 9,
-+ 0, 0, 0, 0, 71, 72, 73, 38, 0, 0,
-+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-+ 0, 0, 0, 0, 0, 0, 0, 7, 77, 0,
-+ 0, 12, 10, 43, 0, 45, 47, 49, 51, 53,
-+ 54, 58, 59, 57, 56, 60, 61, 63, 64, 67,
-+ 66, 68, 0, 0, 0, 0, 16, 0, 77, 13,
-+ 11, 0, 0, 0, 18, 28, 80, 20, 82, 0,
-+ 79, 78, 41, 19, 81, 0, 0, 14, 27, 17,
-+ 29, 0, 21, 30, 24, 0, 74, 32, 0, 0,
-+ 0, 0, 35, 34, 22, 33, 31, 0, 75, 76,
-+ 23, 0, 26, 0, 0, 0, 25
- };
-
-- /* YYDEFGOTO[NTERM-NUM]. */
-+/* YYDEFGOTO[NTERM-NUM]. */
- static const yytype_int16 yydefgoto[] =
- {
-- -1, 2, 7, 8, 15, 36, 65, 93, 112, 113,
-- 125, 20, 21, 22, 23, 24, 25, 26, 27, 28,
-- 29, 30, 31, 32, 33, 128, 94, 95
-+ -1, 2, 6, 10, 11, 18, 39, 68, 96, 115,
-+ 116, 128, 23, 24, 25, 26, 27, 28, 29, 30,
-+ 31, 32, 33, 34, 35, 36, 131, 97, 98
- };
-
-- /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
-- positive, shift that token. If negative, reduce the rule whose
-- number is the opposite. If YYTABLE_NINF, syntax error. */
--static const yytype_uint8 yytable[] =
-+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
-+ STATE-NUM. */
-+#define YYPACT_NINF -84
-+static const yytype_int8 yypact[] =
- {
-- 12, 68, 69, 41, 42, 43, 45, 34, 9, 10,
-- 53, 54, 104, 3, 5, 107, 101, 118, 35, 1,
-- 102, 4, 61, 11, 119, 120, 121, 122, 35, 97,
-- 46, 6, 55, 17, 123, 44, 18, 19, 56, 124,
-- 62, 63, 9, 10, 14, 51, 52, 86, 87, 88,
-- 9, 10, 48, 103, 129, 130, 115, 11, 135, 116,
-- 136, 47, 131, 57, 58, 11, 37, 49, 117, 50,
-- 137, 64, 38, 39, 138, 139, 40, 89, 90, 91,
-- 78, 79, 80, 81, 92, 59, 60, 66, 76, 77,
-- 67, 82, 83, 96, 98, 99, 100, 84, 85, 106,
-- 110, 111, 114, 126, 134, 127, 133, 141, 16, 143,
-- 13, 109, 71, 74, 72, 70, 105, 108, 0, 0,
-- 132, 0, 0, 0, 0, 0, 0, 0, 0, 73,
-- 0, 0, 75, 140, 0, 0, 142
-+ 15, -12, 35, 42, -84, 27, 9, -84, 24, 9,
-+ 43, 9, -84, -84, -10, 24, -84, 60, 44, -84,
-+ -10, -10, -10, -84, 55, -84, -7, 52, 53, 51,
-+ 54, 10, 2, 38, 37, -4, -84, 68, -84, -84,
-+ 71, 73, 60, 60, -84, -84, -84, -84, -10, -10,
-+ -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
-+ -10, -10, -10, -10, -10, -10, -10, -84, 56, 72,
-+ 60, -84, -84, 52, 61, 53, 51, 54, 10, 2,
-+ 2, 38, 38, 38, 38, 37, 37, -4, -4, -84,
-+ -84, -84, 81, 83, 34, 56, -84, 74, 56, -84,
-+ -84, -10, 76, 78, -84, -84, -84, -84, -84, 79,
-+ -84, -84, -84, -84, -84, -6, 3, -84, -84, -84,
-+ -84, 87, -84, -84, -84, 75, -84, -84, 32, 70,
-+ 86, 36, -84, -84, -84, -84, -84, 47, -84, -84,
-+ -84, 24, -84, 77, 24, 80, -84
- };
-
--static const yytype_int16 yycheck[] =
-+/* YYPGOTO[NTERM-NUM]. */
-+static const yytype_int8 yypgoto[] =
- {
-- 5, 39, 40, 17, 18, 19, 12, 12, 17, 18,
-- 7, 8, 92, 24, 4, 95, 24, 13, 26, 3,
-- 28, 0, 25, 32, 20, 21, 22, 23, 26, 67,
-- 36, 21, 29, 42, 30, 34, 45, 46, 35, 35,
-- 43, 44, 17, 18, 25, 9, 10, 61, 62, 63,
-- 17, 18, 38, 91, 21, 22, 21, 32, 19, 24,
-- 21, 11, 29, 5, 6, 32, 15, 39, 33, 40,
-- 31, 24, 21, 22, 33, 34, 25, 14, 15, 16,
-- 53, 54, 55, 56, 21, 41, 42, 22, 51, 52,
-- 22, 57, 58, 24, 37, 16, 16, 59, 60, 27,
-- 24, 24, 24, 17, 20, 32, 35, 33, 8, 34,
-- 6, 98, 46, 49, 47, 45, 92, 95, -1, -1,
-- 125, -1, -1, -1, -1, -1, -1, -1, -1, 48,
-- -1, -1, 50, 138, -1, -1, 141
-+ -84, -84, -84, 98, 101, -84, -41, -84, -83, -84,
-+ -84, -84, -8, 63, 12, -84, 66, 67, 65, 69,
-+ 82, 29, 18, 25, 26, -17, -84, 20, 28
- };
-
-- /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
-- symbol of state STATE-NUM. */
--static const yytype_uint8 yystos[] =
-+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
-+ positive, shift that token. If negative, reduce the rule which
-+ number is the opposite. If YYTABLE_NINF, syntax error. */
-+#define YYTABLE_NINF -1
-+static const yytype_uint8 yytable[] =
- {
-- 0, 3, 48, 24, 0, 4, 21, 49, 50, 17,
-- 18, 32, 58, 50, 25, 51, 49, 42, 45, 46,
-- 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
-- 68, 69, 70, 71, 58, 26, 52, 15, 21, 22,
-- 25, 71, 71, 71, 34, 12, 36, 11, 38, 39,
-- 40, 9, 10, 7, 8, 29, 35, 5, 6, 41,
-- 42, 25, 43, 44, 24, 53, 22, 22, 52, 52,
-- 62, 59, 63, 64, 65, 66, 67, 67, 68, 68,
-- 68, 68, 69, 69, 70, 70, 71, 71, 71, 14,
-- 15, 16, 21, 54, 73, 74, 24, 52, 37, 16,
-- 16, 24, 28, 52, 54, 74, 27, 54, 73, 60,
-- 24, 24, 55, 56, 24, 21, 24, 33, 13, 20,
-- 21, 22, 23, 30, 35, 57, 17, 32, 72, 21,
-- 22, 29, 58, 35, 20, 19, 21, 31, 33, 34,
-- 58, 33, 58, 34
-+ 15, 71, 72, 44, 45, 46, 48, 37, 12, 13,
-+ 56, 57, 107, 3, 8, 110, 118, 121, 1, 119,
-+ 54, 55, 64, 14, 122, 123, 124, 125, 120, 100,
-+ 49, 9, 58, 20, 126, 4, 21, 22, 59, 127,
-+ 65, 66, 12, 13, 60, 61, 5, 89, 90, 91,
-+ 12, 13, 7, 106, 132, 133, 138, 14, 139, 104,
-+ 40, 38, 134, 105, 50, 14, 41, 42, 140, 17,
-+ 43, 92, 93, 94, 81, 82, 83, 84, 95, 62,
-+ 63, 141, 142, 79, 80, 85, 86, 38, 87, 88,
-+ 47, 52, 51, 67, 69, 53, 70, 99, 102, 101,
-+ 103, 113, 109, 114, 117, 129, 136, 137, 130, 19,
-+ 16, 144, 74, 112, 73, 146, 76, 75, 111, 0,
-+ 135, 77, 0, 108, 0, 0, 0, 0, 0, 0,
-+ 0, 0, 0, 143, 0, 78, 145
- };
-
-- /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
--static const yytype_uint8 yyr1[] =
-+#define yypact_value_is_default(yystate) \
-+ ((yystate) == (-84))
-+
-+#define yytable_value_is_error(yytable_value) \
-+ YYID (0)
-+
-+static const yytype_int16 yycheck[] =
- {
-- 0, 47, 48, 49, 49, 50, 50, 51, 51, 51,
-- 51, 51, 52, 53, 53, 54, 54, 54, 54, 55,
-- 55, 55, 55, 55, 55, 55, 56, 56, 56, 57,
-- 57, 57, 57, 57, 58, 58, 58, 59, 60, 60,
-- 61, 61, 62, 62, 63, 63, 64, 64, 65, 65,
-- 66, 66, 66, 67, 67, 67, 67, 67, 68, 68,
-- 68, 69, 69, 69, 70, 70, 70, 70, 71, 71,
-- 71, 71, 72, 72, 72, 73, 73, 73, 74, 74,
-- 74
-+ 8, 42, 43, 20, 21, 22, 13, 15, 18, 19,
-+ 8, 9, 95, 25, 5, 98, 22, 14, 3, 25,
-+ 10, 11, 26, 33, 21, 22, 23, 24, 34, 70,
-+ 37, 22, 30, 43, 31, 0, 46, 47, 36, 36,
-+ 44, 45, 18, 19, 6, 7, 4, 64, 65, 66,
-+ 18, 19, 25, 94, 22, 23, 20, 33, 22, 25,
-+ 16, 27, 30, 29, 12, 33, 22, 23, 32, 26,
-+ 26, 15, 16, 17, 56, 57, 58, 59, 22, 42,
-+ 43, 34, 35, 54, 55, 60, 61, 27, 62, 63,
-+ 35, 40, 39, 25, 23, 41, 23, 25, 17, 38,
-+ 17, 25, 28, 25, 25, 18, 36, 21, 33, 11,
-+ 9, 34, 49, 101, 48, 35, 51, 50, 98, -1,
-+ 128, 52, -1, 95, -1, -1, -1, -1, -1, -1,
-+ -1, -1, -1, 141, -1, 53, 144
- };
-
-- /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */
--static const yytype_uint8 yyr2[] =
-+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
-+ symbol of state STATE-NUM. */
-+static const yytype_uint8 yystos[] =
- {
-- 0, 2, 4, 0, 2, 4, 2, 2, 3, 4,
-- 3, 4, 5, 0, 2, 4, 2, 3, 2, 2,
-- 3, 4, 2, 9, 5, 2, 0, 2, 2, 3,
-- 1, 2, 2, 2, 1, 1, 3, 1, 1, 5,
-- 1, 3, 1, 3, 1, 3, 1, 3, 1, 3,
-- 1, 3, 3, 1, 3, 3, 3, 3, 3, 3,
-- 1, 3, 3, 1, 3, 3, 3, 1, 1, 2,
-- 2, 2, 0, 2, 2, 0, 2, 2, 2, 3,
-- 2
-+ 0, 3, 49, 25, 0, 4, 50, 25, 5, 22,
-+ 51, 52, 18, 19, 33, 60, 52, 26, 53, 51,
-+ 43, 46, 47, 60, 61, 62, 63, 64, 65, 66,
-+ 67, 68, 69, 70, 71, 72, 73, 60, 27, 54,
-+ 16, 22, 23, 26, 73, 73, 73, 35, 13, 37,
-+ 12, 39, 40, 41, 10, 11, 8, 9, 30, 36,
-+ 6, 7, 42, 43, 26, 44, 45, 25, 55, 23,
-+ 23, 54, 54, 64, 61, 65, 66, 67, 68, 69,
-+ 69, 70, 70, 70, 70, 71, 71, 72, 72, 73,
-+ 73, 73, 15, 16, 17, 22, 56, 75, 76, 25,
-+ 54, 38, 17, 17, 25, 29, 54, 56, 76, 28,
-+ 56, 75, 62, 25, 25, 57, 58, 25, 22, 25,
-+ 34, 14, 21, 22, 23, 24, 31, 36, 59, 18,
-+ 33, 74, 22, 23, 30, 60, 36, 21, 20, 22,
-+ 32, 34, 35, 60, 34, 60, 35
- };
-
--
--#define yyerrok (yyerrstatus = 0)
--#define yyclearin (yychar = YYEMPTY)
--#define YYEMPTY (-2)
--#define YYEOF 0
--
--#define YYACCEPT goto yyacceptlab
--#define YYABORT goto yyabortlab
--#define YYERROR goto yyerrorlab
--
-+#define yyerrok (yyerrstatus = 0)
-+#define yyclearin (yychar = YYEMPTY)
-+#define YYEMPTY (-2)
-+#define YYEOF 0
-+
-+#define YYACCEPT goto yyacceptlab
-+#define YYABORT goto yyabortlab
-+#define YYERROR goto yyerrorlab
-+
-+
-+/* Like YYERROR except do call yyerror. This remains here temporarily
-+ to ease the transition to the new meaning of YYERROR, for GCC.
-+ Once GCC version 2 has supplanted version 1, this can go. However,
-+ YYFAIL appears to be in use. Nevertheless, it is formally deprecated
-+ in Bison 2.4.2's NEWS entry, where a plan to phase it out is
-+ discussed. */
-+
-+#define YYFAIL goto yyerrlab
-+#if defined YYFAIL
-+ /* This is here to suppress warnings from the GCC cpp's
-+ -Wunused-macros. Normally we don't worry about that warning, but
-+ some users do, and we want to make it easy for users to remove
-+ YYFAIL uses, which will produce warnings from Bison 2.5. */
-+#endif
-
- #define YYRECOVERING() (!!yyerrstatus)
-
--#define YYBACKUP(Token, Value) \
--do \
-- if (yychar == YYEMPTY) \
-- { \
-- yychar = (Token); \
-- yylval = (Value); \
-- YYPOPSTACK (yylen); \
-- yystate = *yyssp; \
-- goto yybackup; \
-- } \
-- else \
-- { \
-+#define YYBACKUP(Token, Value) \
-+do \
-+ if (yychar == YYEMPTY && yylen == 1) \
-+ { \
-+ yychar = (Token); \
-+ yylval = (Value); \
-+ YYPOPSTACK (1); \
-+ goto yybackup; \
-+ } \
-+ else \
-+ { \
- yyerror (YY_("syntax error: cannot back up")); \
-- YYERROR; \
-- } \
--while (0)
--
--/* Error token number */
--#define YYTERROR 1
--#define YYERRCODE 256
-+ YYERROR; \
-+ } \
-+while (YYID (0))
-+
-+
-+#define YYTERROR 1
-+#define YYERRCODE 256
-
-
- /* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
- If N is 0, then set CURRENT to the empty location which ends
- the previous symbol: RHS[0] (always defined). */
-
-+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
- #ifndef YYLLOC_DEFAULT
--# define YYLLOC_DEFAULT(Current, Rhs, N) \
-- do \
-- if (N) \
-- { \
-- (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
-- (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
-- (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
-- (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
-- } \
-- else \
-- { \
-- (Current).first_line = (Current).last_line = \
-- YYRHSLOC (Rhs, 0).last_line; \
-- (Current).first_column = (Current).last_column = \
-- YYRHSLOC (Rhs, 0).last_column; \
-- } \
-- while (0)
-+# define YYLLOC_DEFAULT(Current, Rhs, N) \
-+ do \
-+ if (YYID (N)) \
-+ { \
-+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
-+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
-+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
-+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
-+ } \
-+ else \
-+ { \
-+ (Current).first_line = (Current).last_line = \
-+ YYRHSLOC (Rhs, 0).last_line; \
-+ (Current).first_column = (Current).last_column = \
-+ YYRHSLOC (Rhs, 0).last_column; \
-+ } \
-+ while (YYID (0))
- #endif
-
--#define YYRHSLOC(Rhs, K) ((Rhs)[K])
--
--
--/* Enable debugging if requested. */
--#if YYDEBUG
--
--# ifndef YYFPRINTF
--# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
--# define YYFPRINTF fprintf
--# endif
--
--# define YYDPRINTF(Args) \
--do { \
-- if (yydebug) \
-- YYFPRINTF Args; \
--} while (0)
--
-
- /* YY_LOCATION_PRINT -- Print the location on the stream.
- This macro was not mandated originally: define only if we know
-@@ -779,73 +799,82 @@ do {
-
- #ifndef YY_LOCATION_PRINT
- # if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
--
--/* Print *YYLOCP on YYO. Private, do not rely on its existence. */
--
--YY_ATTRIBUTE_UNUSED
--static unsigned
--yy_location_print_ (FILE *yyo, YYLTYPE const * const yylocp)
--{
-- unsigned res = 0;
-- int end_col = 0 != yylocp->last_column ? yylocp->last_column - 1 : 0;
-- if (0 <= yylocp->first_line)
-- {
-- res += YYFPRINTF (yyo, "%d", yylocp->first_line);
-- if (0 <= yylocp->first_column)
-- res += YYFPRINTF (yyo, ".%d", yylocp->first_column);
-- }
-- if (0 <= yylocp->last_line)
-- {
-- if (yylocp->first_line < yylocp->last_line)
-- {
-- res += YYFPRINTF (yyo, "-%d", yylocp->last_line);
-- if (0 <= end_col)
-- res += YYFPRINTF (yyo, ".%d", end_col);
-- }
-- else if (0 <= end_col && yylocp->first_column < end_col)
-- res += YYFPRINTF (yyo, "-%d", end_col);
-- }
-- return res;
-- }
--
--# define YY_LOCATION_PRINT(File, Loc) \
-- yy_location_print_ (File, &(Loc))
--
-+# define YY_LOCATION_PRINT(File, Loc) \
-+ fprintf (File, "%d.%d-%d.%d", \
-+ (Loc).first_line, (Loc).first_column, \
-+ (Loc).last_line, (Loc).last_column)
- # else
- # define YY_LOCATION_PRINT(File, Loc) ((void) 0)
- # endif
- #endif
-
-
--# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
--do { \
-- if (yydebug) \
-- { \
-- YYFPRINTF (stderr, "%s ", Title); \
-- yy_symbol_print (stderr, \
-- Type, Value, Location); \
-- YYFPRINTF (stderr, "\n"); \
-- } \
--} while (0)
-+/* YYLEX -- calling `yylex' with the right arguments. */
-
-+#ifdef YYLEX_PARAM
-+# define YYLEX yylex (YYLEX_PARAM)
-+#else
-+# define YYLEX yylex ()
-+#endif
-
--/*----------------------------------------.
--| Print this symbol's value on YYOUTPUT. |
--`----------------------------------------*/
-+/* Enable debugging if requested. */
-+#if YYDEBUG
-
-+# ifndef YYFPRINTF
-+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
-+# define YYFPRINTF fprintf
-+# endif
-+
-+# define YYDPRINTF(Args) \
-+do { \
-+ if (yydebug) \
-+ YYFPRINTF Args; \
-+} while (YYID (0))
-+
-+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
-+do { \
-+ if (yydebug) \
-+ { \
-+ YYFPRINTF (stderr, "%s ", Title); \
-+ yy_symbol_print (stderr, \
-+ Type, Value, Location); \
-+ YYFPRINTF (stderr, "\n"); \
-+ } \
-+} while (YYID (0))
-+
-+
-+/*--------------------------------.
-+| Print this symbol on YYOUTPUT. |
-+`--------------------------------*/
-+
-+/*ARGSUSED*/
-+#if (defined __STDC__ || defined __C99__FUNC__ \
-+ || defined __cplusplus || defined _MSC_VER)
- static void
- yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp)
-+#else
-+static void
-+yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp)
-+ FILE *yyoutput;
-+ int yytype;
-+ YYSTYPE const * const yyvaluep;
-+ YYLTYPE const * const yylocationp;
-+#endif
- {
-- FILE *yyo = yyoutput;
-- YYUSE (yyo);
-- YYUSE (yylocationp);
- if (!yyvaluep)
- return;
-+ YYUSE (yylocationp);
- # ifdef YYPRINT
- if (yytype < YYNTOKENS)
- YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
-+# else
-+ YYUSE (yyoutput);
- # endif
-- YYUSE (yytype);
-+ switch (yytype)
-+ {
-+ default:
-+ break;
-+ }
- }
-
-
-@@ -853,11 +882,23 @@ yy_symbol_value_print (FILE *yyoutput, i
- | Print this symbol on YYOUTPUT. |
- `--------------------------------*/
-
-+#if (defined __STDC__ || defined __C99__FUNC__ \
-+ || defined __cplusplus || defined _MSC_VER)
- static void
- yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp)
-+#else
-+static void
-+yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp)
-+ FILE *yyoutput;
-+ int yytype;
-+ YYSTYPE const * const yyvaluep;
-+ YYLTYPE const * const yylocationp;
-+#endif
- {
-- YYFPRINTF (yyoutput, "%s %s (",
-- yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]);
-+ if (yytype < YYNTOKENS)
-+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
-+ else
-+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
-
- YY_LOCATION_PRINT (yyoutput, *yylocationp);
- YYFPRINTF (yyoutput, ": ");
-@@ -870,8 +911,16 @@ yy_symbol_print (FILE *yyoutput, int yyt
- | TOP (included). |
- `------------------------------------------------------------------*/
-
-+#if (defined __STDC__ || defined __C99__FUNC__ \
-+ || defined __cplusplus || defined _MSC_VER)
- static void
- yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
-+#else
-+static void
-+yy_stack_print (yybottom, yytop)
-+ yytype_int16 *yybottom;
-+ yytype_int16 *yytop;
-+#endif
- {
- YYFPRINTF (stderr, "Stack now");
- for (; yybottom <= yytop; yybottom++)
-@@ -882,42 +931,50 @@ yy_stack_print (yytype_int16 *yybottom,
- YYFPRINTF (stderr, "\n");
- }
-
--# define YY_STACK_PRINT(Bottom, Top) \
--do { \
-- if (yydebug) \
-- yy_stack_print ((Bottom), (Top)); \
--} while (0)
-+# define YY_STACK_PRINT(Bottom, Top) \
-+do { \
-+ if (yydebug) \
-+ yy_stack_print ((Bottom), (Top)); \
-+} while (YYID (0))
-
-
- /*------------------------------------------------.
- | Report that the YYRULE is going to be reduced. |
- `------------------------------------------------*/
-
-+#if (defined __STDC__ || defined __C99__FUNC__ \
-+ || defined __cplusplus || defined _MSC_VER)
-+static void
-+yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule)
-+#else
- static void
--yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule)
-+yy_reduce_print (yyvsp, yylsp, yyrule)
-+ YYSTYPE *yyvsp;
-+ YYLTYPE *yylsp;
-+ int yyrule;
-+#endif
- {
-- unsigned long int yylno = yyrline[yyrule];
- int yynrhs = yyr2[yyrule];
- int yyi;
-+ unsigned long int yylno = yyrline[yyrule];
- YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
-- yyrule - 1, yylno);
-+ yyrule - 1, yylno);
- /* The symbols being reduced. */
- for (yyi = 0; yyi < yynrhs; yyi++)
- {
- YYFPRINTF (stderr, " $%d = ", yyi + 1);
-- yy_symbol_print (stderr,
-- yystos[yyssp[yyi + 1 - yynrhs]],
-- &(yyvsp[(yyi + 1) - (yynrhs)])
-- , &(yylsp[(yyi + 1) - (yynrhs)]) );
-+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
-+ &(yyvsp[(yyi + 1) - (yynrhs)])
-+ , &(yylsp[(yyi + 1) - (yynrhs)]) );
- YYFPRINTF (stderr, "\n");
- }
- }
-
--# define YY_REDUCE_PRINT(Rule) \
--do { \
-- if (yydebug) \
-- yy_reduce_print (yyssp, yyvsp, yylsp, Rule); \
--} while (0)
-+# define YY_REDUCE_PRINT(Rule) \
-+do { \
-+ if (yydebug) \
-+ yy_reduce_print (yyvsp, yylsp, Rule); \
-+} while (YYID (0))
-
- /* Nonzero means print parse trace. It is left uninitialized so that
- multiple parsers can coexist. */
-@@ -931,7 +988,7 @@ int yydebug;
-
-
- /* YYINITDEPTH -- initial size of the parser's stacks. */
--#ifndef YYINITDEPTH
-+#ifndef YYINITDEPTH
- # define YYINITDEPTH 200
- #endif
-
-@@ -954,8 +1011,15 @@ int yydebug;
- # define yystrlen strlen
- # else
- /* Return the length of YYSTR. */
-+#if (defined __STDC__ || defined __C99__FUNC__ \
-+ || defined __cplusplus || defined _MSC_VER)
- static YYSIZE_T
- yystrlen (const char *yystr)
-+#else
-+static YYSIZE_T
-+yystrlen (yystr)
-+ const char *yystr;
-+#endif
- {
- YYSIZE_T yylen;
- for (yylen = 0; yystr[yylen]; yylen++)
-@@ -971,8 +1035,16 @@ yystrlen (const char *yystr)
- # else
- /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
- YYDEST. */
-+#if (defined __STDC__ || defined __C99__FUNC__ \
-+ || defined __cplusplus || defined _MSC_VER)
- static char *
- yystpcpy (char *yydest, const char *yysrc)
-+#else
-+static char *
-+yystpcpy (yydest, yysrc)
-+ char *yydest;
-+ const char *yysrc;
-+#endif
- {
- char *yyd = yydest;
- const char *yys = yysrc;
-@@ -1002,27 +1074,27 @@ yytnamerr (char *yyres, const char *yyst
- char const *yyp = yystr;
-
- for (;;)
-- switch (*++yyp)
-- {
-- case '\'':
-- case ',':
-- goto do_not_strip_quotes;
--
-- case '\\':
-- if (*++yyp != '\\')
-- goto do_not_strip_quotes;
-- /* Fall through. */
-- default:
-- if (yyres)
-- yyres[yyn] = *yyp;
-- yyn++;
-- break;
--
-- case '"':
-- if (yyres)
-- yyres[yyn] = '\0';
-- return yyn;
-- }
-+ switch (*++yyp)
-+ {
-+ case '\'':
-+ case ',':
-+ goto do_not_strip_quotes;
-+
-+ case '\\':
-+ if (*++yyp != '\\')
-+ goto do_not_strip_quotes;
-+ /* Fall through. */
-+ default:
-+ if (yyres)
-+ yyres[yyn] = *yyp;
-+ yyn++;
-+ break;
-+
-+ case '"':
-+ if (yyres)
-+ yyres[yyn] = '\0';
-+ return yyn;
-+ }
- do_not_strip_quotes: ;
- }
-
-@@ -1045,11 +1117,12 @@ static int
- yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
- yytype_int16 *yyssp, int yytoken)
- {
-- YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]);
-+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]);
- YYSIZE_T yysize = yysize0;
-+ YYSIZE_T yysize1;
- enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
- /* Internationalized format string. */
-- const char *yyformat = YY_NULLPTR;
-+ const char *yyformat = 0;
- /* Arguments of yyformat. */
- char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
- /* Number of reported tokens (one for the "unexpected", one per
-@@ -1057,6 +1130,10 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, c
- int yycount = 0;
-
- /* There are many possibilities here to consider:
-+ - Assume YYFAIL is not used. It's too flawed to consider. See
-+ <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
-+ for details. YYERROR is fine as it does not invoke this
-+ function.
- - If this state is a consistent state with a default action, then
- the only way this function was invoked is if the default action
- is an error action. In that case, don't check for expected
-@@ -1105,13 +1182,11 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, c
- break;
- }
- yyarg[yycount++] = yytname[yyx];
-- {
-- YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]);
-- if (! (yysize <= yysize1
-- && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
-- return 2;
-- yysize = yysize1;
-- }
-+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
-+ if (! (yysize <= yysize1
-+ && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
-+ return 2;
-+ yysize = yysize1;
- }
- }
- }
-@@ -1131,12 +1206,10 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, c
- # undef YYCASE_
- }
-
-- {
-- YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
-- if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
-- return 2;
-- yysize = yysize1;
-- }
-+ yysize1 = yysize + yystrlen (yyformat);
-+ if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
-+ return 2;
-+ yysize = yysize1;
-
- if (*yymsg_alloc < yysize)
- {
-@@ -1173,21 +1246,50 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, c
- | Release the memory associated to this symbol. |
- `-----------------------------------------------*/
-
-+/*ARGSUSED*/
-+#if (defined __STDC__ || defined __C99__FUNC__ \
-+ || defined __cplusplus || defined _MSC_VER)
- static void
- yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp)
-+#else
-+static void
-+yydestruct (yymsg, yytype, yyvaluep, yylocationp)
-+ const char *yymsg;
-+ int yytype;
-+ YYSTYPE *yyvaluep;
-+ YYLTYPE *yylocationp;
-+#endif
- {
- YYUSE (yyvaluep);
- YYUSE (yylocationp);
-+
- if (!yymsg)
- yymsg = "Deleting";
- YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
-
-- YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-- YYUSE (yytype);
-- YY_IGNORE_MAYBE_UNINITIALIZED_END
-+ switch (yytype)
-+ {
-+
-+ default:
-+ break;
-+ }
- }
-
-
-+/* Prevent warnings from -Wmissing-prototypes. */
-+#ifdef YYPARSE_PARAM
-+#if defined __STDC__ || defined __cplusplus
-+int yyparse (void *YYPARSE_PARAM);
-+#else
-+int yyparse ();
-+#endif
-+#else /* ! YYPARSE_PARAM */
-+#if defined __STDC__ || defined __cplusplus
-+int yyparse (void);
-+#else
-+int yyparse ();
-+#endif
-+#endif /* ! YYPARSE_PARAM */
-
-
- /* The lookahead symbol. */
-@@ -1195,12 +1297,10 @@ int yychar;
-
- /* The semantic value of the lookahead symbol. */
- YYSTYPE yylval;
-+
- /* Location data for the lookahead symbol. */
--YYLTYPE yylloc
--# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
-- = { 1, 1, 1, 1 }
--# endif
--;
-+YYLTYPE yylloc;
-+
- /* Number of syntax errors so far. */
- int yynerrs;
-
-@@ -1209,19 +1309,38 @@ int yynerrs;
- | yyparse. |
- `----------*/
-
-+#ifdef YYPARSE_PARAM
-+#if (defined __STDC__ || defined __C99__FUNC__ \
-+ || defined __cplusplus || defined _MSC_VER)
-+int
-+yyparse (void *YYPARSE_PARAM)
-+#else
-+int
-+yyparse (YYPARSE_PARAM)
-+ void *YYPARSE_PARAM;
-+#endif
-+#else /* ! YYPARSE_PARAM */
-+#if (defined __STDC__ || defined __C99__FUNC__ \
-+ || defined __cplusplus || defined _MSC_VER)
- int
- yyparse (void)
-+#else
-+int
-+yyparse ()
-+
-+#endif
-+#endif
- {
- int yystate;
- /* Number of tokens to shift before error messages enabled. */
- int yyerrstatus;
-
- /* The stacks and their tools:
-- 'yyss': related to states.
-- 'yyvs': related to semantic values.
-- 'yyls': related to locations.
-+ `yyss': related to states.
-+ `yyvs': related to semantic values.
-+ `yyls': related to locations.
-
-- Refer to the stacks through separate pointers, to allow yyoverflow
-+ Refer to the stacks thru separate pointers, to allow yyoverflow
- to reallocate them elsewhere. */
-
- /* The state stack. */
-@@ -1247,7 +1366,7 @@ yyparse (void)
- int yyn;
- int yyresult;
- /* Lookahead token as an internal (translated) token number. */
-- int yytoken = 0;
-+ int yytoken;
- /* The variables used to return semantic value and location from the
- action routines. */
- YYSTYPE yyval;
-@@ -1266,9 +1385,10 @@ yyparse (void)
- Keep to zero when no symbol should be popped. */
- int yylen = 0;
-
-- yyssp = yyss = yyssa;
-- yyvsp = yyvs = yyvsa;
-- yylsp = yyls = yylsa;
-+ yytoken = 0;
-+ yyss = yyssa;
-+ yyvs = yyvsa;
-+ yyls = yylsa;
- yystacksize = YYINITDEPTH;
-
- YYDPRINTF ((stderr, "Starting parse\n"));
-@@ -1277,7 +1397,21 @@ yyparse (void)
- yyerrstatus = 0;
- yynerrs = 0;
- yychar = YYEMPTY; /* Cause a token to be read. */
-- yylsp[0] = yylloc;
-+
-+ /* Initialize stack pointers.
-+ Waste one element of value and location stack
-+ so that they stay on the same level as the state stack.
-+ The wasted elements are never initialized. */
-+ yyssp = yyss;
-+ yyvsp = yyvs;
-+ yylsp = yyls;
-+
-+#if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
-+ /* Initialize the default location before parsing starts. */
-+ yylloc.first_line = yylloc.last_line = 1;
-+ yylloc.first_column = yylloc.last_column = 1;
-+#endif
-+
- goto yysetstate;
-
- /*------------------------------------------------------------.
-@@ -1298,26 +1432,26 @@ yyparse (void)
-
- #ifdef yyoverflow
- {
-- /* Give user a chance to reallocate the stack. Use copies of
-- these so that the &'s don't force the real ones into
-- memory. */
-- YYSTYPE *yyvs1 = yyvs;
-- yytype_int16 *yyss1 = yyss;
-- YYLTYPE *yyls1 = yyls;
--
-- /* Each stack pointer address is followed by the size of the
-- data in use in that stack, in bytes. This used to be a
-- conditional around just the two extra args, but that might
-- be undefined if yyoverflow is a macro. */
-- yyoverflow (YY_("memory exhausted"),
-- &yyss1, yysize * sizeof (*yyssp),
-- &yyvs1, yysize * sizeof (*yyvsp),
-- &yyls1, yysize * sizeof (*yylsp),
-- &yystacksize);
--
-- yyls = yyls1;
-- yyss = yyss1;
-- yyvs = yyvs1;
-+ /* Give user a chance to reallocate the stack. Use copies of
-+ these so that the &'s don't force the real ones into
-+ memory. */
-+ YYSTYPE *yyvs1 = yyvs;
-+ yytype_int16 *yyss1 = yyss;
-+ YYLTYPE *yyls1 = yyls;
-+
-+ /* Each stack pointer address is followed by the size of the
-+ data in use in that stack, in bytes. This used to be a
-+ conditional around just the two extra args, but that might
-+ be undefined if yyoverflow is a macro. */
-+ yyoverflow (YY_("memory exhausted"),
-+ &yyss1, yysize * sizeof (*yyssp),
-+ &yyvs1, yysize * sizeof (*yyvsp),
-+ &yyls1, yysize * sizeof (*yylsp),
-+ &yystacksize);
-+
-+ yyls = yyls1;
-+ yyss = yyss1;
-+ yyvs = yyvs1;
- }
- #else /* no yyoverflow */
- # ifndef YYSTACK_RELOCATE
-@@ -1325,23 +1459,23 @@ yyparse (void)
- # else
- /* Extend the stack our own way. */
- if (YYMAXDEPTH <= yystacksize)
-- goto yyexhaustedlab;
-+ goto yyexhaustedlab;
- yystacksize *= 2;
- if (YYMAXDEPTH < yystacksize)
-- yystacksize = YYMAXDEPTH;
-+ yystacksize = YYMAXDEPTH;
-
- {
-- yytype_int16 *yyss1 = yyss;
-- union yyalloc *yyptr =
-- (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
-- if (! yyptr)
-- goto yyexhaustedlab;
-- YYSTACK_RELOCATE (yyss_alloc, yyss);
-- YYSTACK_RELOCATE (yyvs_alloc, yyvs);
-- YYSTACK_RELOCATE (yyls_alloc, yyls);
-+ yytype_int16 *yyss1 = yyss;
-+ union yyalloc *yyptr =
-+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
-+ if (! yyptr)
-+ goto yyexhaustedlab;
-+ YYSTACK_RELOCATE (yyss_alloc, yyss);
-+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
-+ YYSTACK_RELOCATE (yyls_alloc, yyls);
- # undef YYSTACK_RELOCATE
-- if (yyss1 != yyssa)
-- YYSTACK_FREE (yyss1);
-+ if (yyss1 != yyssa)
-+ YYSTACK_FREE (yyss1);
- }
- # endif
- #endif /* no yyoverflow */
-@@ -1351,10 +1485,10 @@ yyparse (void)
- yylsp = yyls + yysize - 1;
-
- YYDPRINTF ((stderr, "Stack size increased to %lu\n",
-- (unsigned long int) yystacksize));
-+ (unsigned long int) yystacksize));
-
- if (yyss + yystacksize - 1 <= yyssp)
-- YYABORT;
-+ YYABORT;
- }
-
- YYDPRINTF ((stderr, "Entering state %d\n", yystate));
-@@ -1383,7 +1517,7 @@ yybackup:
- if (yychar == YYEMPTY)
- {
- YYDPRINTF ((stderr, "Reading a token: "));
-- yychar = yylex ();
-+ yychar = YYLEX;
- }
-
- if (yychar <= YYEOF)
-@@ -1423,9 +1557,7 @@ yybackup:
- yychar = YYEMPTY;
-
- yystate = yyn;
-- YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
- *++yyvsp = yylval;
-- YY_IGNORE_MAYBE_UNINITIALIZED_END
- *++yylsp = yylloc;
- goto yynewstate;
-
-@@ -1448,7 +1580,7 @@ yyreduce:
- yylen = yyr2[yyn];
-
- /* If YYLEN is nonzero, implement the default value of the action:
-- '$$ = $1'.
-+ `$$ = $1'.
-
- Otherwise, the following line sets YYVAL to garbage.
- This behavior is undocumented and Bison
-@@ -1463,273 +1595,322 @@ yyreduce:
- switch (yyn)
- {
- case 2:
--#line 105 "dtc-parser.y" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 109 "dtc-parser.y"
- {
-- the_boot_info = build_boot_info((yyvsp[-1].re), (yyvsp[0].node),
-- guess_boot_cpuid((yyvsp[0].node)));
-+ (yyvsp[(5) - (5)].node)->is_plugin = (yyvsp[(3) - (5)].is_plugin);
-+ (yyvsp[(5) - (5)].node)->is_root = 1;
-+ the_boot_info = build_boot_info((yyvsp[(4) - (5)].re), (yyvsp[(5) - (5)].node),
-+ guess_boot_cpuid((yyvsp[(5) - (5)].node)));
- }
--#line 1472 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
- case 3:
--#line 113 "dtc-parser.y" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 119 "dtc-parser.y"
- {
-- (yyval.re) = NULL;
-+ (yyval.is_plugin) = 0;
- }
--#line 1480 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
- case 4:
--#line 117 "dtc-parser.y" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 123 "dtc-parser.y"
- {
-- (yyval.re) = chain_reserve_entry((yyvsp[-1].re), (yyvsp[0].re));
-+ (yyval.is_plugin) = 1;
- }
--#line 1488 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
- case 5:
--#line 124 "dtc-parser.y" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 130 "dtc-parser.y"
- {
-- (yyval.re) = build_reserve_entry((yyvsp[-2].integer), (yyvsp[-1].integer));
-+ (yyval.re) = NULL;
- }
--#line 1496 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
- case 6:
--#line 128 "dtc-parser.y" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 134 "dtc-parser.y"
- {
-- add_label(&(yyvsp[0].re)->labels, (yyvsp[-1].labelref));
-- (yyval.re) = (yyvsp[0].re);
-+ (yyval.re) = chain_reserve_entry((yyvsp[(1) - (2)].re), (yyvsp[(2) - (2)].re));
- }
--#line 1505 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
- case 7:
--#line 136 "dtc-parser.y" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 141 "dtc-parser.y"
- {
-- (yyval.node) = name_node((yyvsp[0].node), "");
-+ (yyval.re) = build_reserve_entry((yyvsp[(2) - (4)].integer), (yyvsp[(3) - (4)].integer));
- }
--#line 1513 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
- case 8:
--#line 140 "dtc-parser.y" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 145 "dtc-parser.y"
- {
-- (yyval.node) = merge_nodes((yyvsp[-2].node), (yyvsp[0].node));
-+ add_label(&(yyvsp[(2) - (2)].re)->labels, (yyvsp[(1) - (2)].labelref));
-+ (yyval.re) = (yyvsp[(2) - (2)].re);
- }
--#line 1521 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
- case 9:
--#line 145 "dtc-parser.y" /* yacc.c:1646 */
-- {
-- struct node *target = get_node_by_ref((yyvsp[-3].node), (yyvsp[-1].labelref));
-
-- add_label(&target->labels, (yyvsp[-2].labelref));
-- if (target)
-- merge_nodes(target, (yyvsp[0].node));
-- else
-- ERROR(&(yylsp[-1]), "Label or path %s not found", (yyvsp[-1].labelref));
-- (yyval.node) = (yyvsp[-3].node);
-+/* Line 1806 of yacc.c */
-+#line 153 "dtc-parser.y"
-+ {
-+ (yyval.node) = name_node((yyvsp[(2) - (2)].node), "");
- }
--#line 1536 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
- case 10:
--#line 156 "dtc-parser.y" /* yacc.c:1646 */
-- {
-- struct node *target = get_node_by_ref((yyvsp[-2].node), (yyvsp[-1].labelref));
-
-- if (target)
-- merge_nodes(target, (yyvsp[0].node));
-- else
-- ERROR(&(yylsp[-1]), "Label or path %s not found", (yyvsp[-1].labelref));
-- (yyval.node) = (yyvsp[-2].node);
-+/* Line 1806 of yacc.c */
-+#line 157 "dtc-parser.y"
-+ {
-+ (yyval.node) = merge_nodes((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
- }
--#line 1550 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
- case 11:
--#line 166 "dtc-parser.y" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 162 "dtc-parser.y"
- {
-- struct node *target = get_node_by_ref((yyvsp[-3].node), (yyvsp[-1].labelref));
-+ struct node *target = get_node_by_ref((yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].labelref));
-
-+ add_label(&target->labels, (yyvsp[(2) - (4)].labelref));
- if (target)
-- delete_node(target);
-+ merge_nodes(target, (yyvsp[(4) - (4)].node));
- else
-- ERROR(&(yylsp[-1]), "Label or path %s not found", (yyvsp[-1].labelref));
--
--
-- (yyval.node) = (yyvsp[-3].node);
-+ ERROR(&(yylsp[(3) - (4)]), "Label or path %s not found", (yyvsp[(3) - (4)].labelref));
-+ (yyval.node) = (yyvsp[(1) - (4)].node);
- }
--#line 1566 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
- case 12:
--#line 181 "dtc-parser.y" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 173 "dtc-parser.y"
- {
-- (yyval.node) = build_node((yyvsp[-3].proplist), (yyvsp[-2].nodelist));
-+ struct node *target = get_node_by_ref((yyvsp[(1) - (3)].node), (yyvsp[(2) - (3)].labelref));
-+
-+ if (target)
-+ merge_nodes(target, (yyvsp[(3) - (3)].node));
-+ else
-+ ERROR(&(yylsp[(2) - (3)]), "Label or path %s not found", (yyvsp[(2) - (3)].labelref));
-+ (yyval.node) = (yyvsp[(1) - (3)].node);
- }
--#line 1574 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
- case 13:
--#line 188 "dtc-parser.y" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 183 "dtc-parser.y"
- {
-- (yyval.proplist) = NULL;
-+ struct node *target = get_node_by_ref((yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].labelref));
-+
-+ if (target)
-+ delete_node(target);
-+ else
-+ ERROR(&(yylsp[(3) - (4)]), "Label or path %s not found", (yyvsp[(3) - (4)].labelref));
-+
-+
-+ (yyval.node) = (yyvsp[(1) - (4)].node);
- }
--#line 1582 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
- case 14:
--#line 192 "dtc-parser.y" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 198 "dtc-parser.y"
- {
-- (yyval.proplist) = chain_property((yyvsp[0].prop), (yyvsp[-1].proplist));
-+ (yyval.node) = build_node((yyvsp[(2) - (5)].proplist), (yyvsp[(3) - (5)].nodelist));
- }
--#line 1590 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
- case 15:
--#line 199 "dtc-parser.y" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 205 "dtc-parser.y"
- {
-- (yyval.prop) = build_property((yyvsp[-3].propnodename), (yyvsp[-1].data));
-+ (yyval.proplist) = NULL;
- }
--#line 1598 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
- case 16:
--#line 203 "dtc-parser.y" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 209 "dtc-parser.y"
- {
-- (yyval.prop) = build_property((yyvsp[-1].propnodename), empty_data);
-+ (yyval.proplist) = chain_property((yyvsp[(2) - (2)].prop), (yyvsp[(1) - (2)].proplist));
- }
--#line 1606 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
- case 17:
--#line 207 "dtc-parser.y" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 216 "dtc-parser.y"
- {
-- (yyval.prop) = build_property_delete((yyvsp[-1].propnodename));
-+ (yyval.prop) = build_property((yyvsp[(1) - (4)].propnodename), (yyvsp[(3) - (4)].data));
- }
--#line 1614 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
- case 18:
--#line 211 "dtc-parser.y" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 220 "dtc-parser.y"
- {
-- add_label(&(yyvsp[0].prop)->labels, (yyvsp[-1].labelref));
-- (yyval.prop) = (yyvsp[0].prop);
-+ (yyval.prop) = build_property((yyvsp[(1) - (2)].propnodename), empty_data);
- }
--#line 1623 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
- case 19:
--#line 219 "dtc-parser.y" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 224 "dtc-parser.y"
- {
-- (yyval.data) = data_merge((yyvsp[-1].data), (yyvsp[0].data));
-+ (yyval.prop) = build_property_delete((yyvsp[(2) - (3)].propnodename));
- }
--#line 1631 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
- case 20:
--#line 223 "dtc-parser.y" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 228 "dtc-parser.y"
- {
-- (yyval.data) = data_merge((yyvsp[-2].data), (yyvsp[-1].array).data);
-+ add_label(&(yyvsp[(2) - (2)].prop)->labels, (yyvsp[(1) - (2)].labelref));
-+ (yyval.prop) = (yyvsp[(2) - (2)].prop);
- }
--#line 1639 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
- case 21:
--#line 227 "dtc-parser.y" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 236 "dtc-parser.y"
- {
-- (yyval.data) = data_merge((yyvsp[-3].data), (yyvsp[-1].data));
-+ (yyval.data) = data_merge((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].data));
- }
--#line 1647 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
- case 22:
--#line 231 "dtc-parser.y" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 240 "dtc-parser.y"
- {
-- (yyval.data) = data_add_marker((yyvsp[-1].data), REF_PATH, (yyvsp[0].labelref));
-+ (yyval.data) = data_merge((yyvsp[(1) - (3)].data), (yyvsp[(2) - (3)].array).data);
- }
--#line 1655 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
- case 23:
--#line 235 "dtc-parser.y" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 244 "dtc-parser.y"
-+ {
-+ (yyval.data) = data_merge((yyvsp[(1) - (4)].data), (yyvsp[(3) - (4)].data));
-+ }
-+ break;
-+
-+ case 24:
-+
-+/* Line 1806 of yacc.c */
-+#line 248 "dtc-parser.y"
-+ {
-+ (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), REF_PATH, (yyvsp[(2) - (2)].labelref));
-+ }
-+ break;
-+
-+ case 25:
-+
-+/* Line 1806 of yacc.c */
-+#line 252 "dtc-parser.y"
- {
-- FILE *f = srcfile_relative_open((yyvsp[-5].data).val, NULL);
-+ FILE *f = srcfile_relative_open((yyvsp[(4) - (9)].data).val, NULL);
- struct data d;
-
-- if ((yyvsp[-3].integer) != 0)
-- if (fseek(f, (yyvsp[-3].integer), SEEK_SET) != 0)
-+ if ((yyvsp[(6) - (9)].integer) != 0)
-+ if (fseek(f, (yyvsp[(6) - (9)].integer), SEEK_SET) != 0)
- die("Couldn't seek to offset %llu in \"%s\": %s",
-- (unsigned long long)(yyvsp[-3].integer), (yyvsp[-5].data).val,
-+ (unsigned long long)(yyvsp[(6) - (9)].integer), (yyvsp[(4) - (9)].data).val,
- strerror(errno));
-
-- d = data_copy_file(f, (yyvsp[-1].integer));
-+ d = data_copy_file(f, (yyvsp[(8) - (9)].integer));
-
-- (yyval.data) = data_merge((yyvsp[-8].data), d);
-+ (yyval.data) = data_merge((yyvsp[(1) - (9)].data), d);
- fclose(f);
- }
--#line 1675 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
-- case 24:
--#line 251 "dtc-parser.y" /* yacc.c:1646 */
-+ case 26:
-+
-+/* Line 1806 of yacc.c */
-+#line 268 "dtc-parser.y"
- {
-- FILE *f = srcfile_relative_open((yyvsp[-1].data).val, NULL);
-+ FILE *f = srcfile_relative_open((yyvsp[(4) - (5)].data).val, NULL);
- struct data d = empty_data;
-
- d = data_copy_file(f, -1);
-
-- (yyval.data) = data_merge((yyvsp[-4].data), d);
-+ (yyval.data) = data_merge((yyvsp[(1) - (5)].data), d);
- fclose(f);
- }
--#line 1689 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
-- case 25:
--#line 261 "dtc-parser.y" /* yacc.c:1646 */
-+ case 27:
-+
-+/* Line 1806 of yacc.c */
-+#line 278 "dtc-parser.y"
- {
-- (yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref));
-+ (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref));
- }
--#line 1697 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
-- case 26:
--#line 268 "dtc-parser.y" /* yacc.c:1646 */
-+ case 28:
-+
-+/* Line 1806 of yacc.c */
-+#line 285 "dtc-parser.y"
- {
- (yyval.data) = empty_data;
- }
--#line 1705 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
-- case 27:
--#line 272 "dtc-parser.y" /* yacc.c:1646 */
-+ case 29:
-+
-+/* Line 1806 of yacc.c */
-+#line 289 "dtc-parser.y"
- {
-- (yyval.data) = (yyvsp[-1].data);
-+ (yyval.data) = (yyvsp[(1) - (2)].data);
- }
--#line 1713 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
-- case 28:
--#line 276 "dtc-parser.y" /* yacc.c:1646 */
-+ case 30:
-+
-+/* Line 1806 of yacc.c */
-+#line 293 "dtc-parser.y"
- {
-- (yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref));
-+ (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref));
- }
--#line 1721 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
-- case 29:
--#line 283 "dtc-parser.y" /* yacc.c:1646 */
-+ case 31:
-+
-+/* Line 1806 of yacc.c */
-+#line 300 "dtc-parser.y"
- {
- unsigned long long bits;
-
-- bits = (yyvsp[-1].integer);
-+ bits = (yyvsp[(2) - (3)].integer);
-
- if ((bits != 8) && (bits != 16) &&
- (bits != 32) && (bits != 64)) {
-- ERROR(&(yylsp[-1]), "Array elements must be"
-+ ERROR(&(yylsp[(2) - (3)]), "Array elements must be"
- " 8, 16, 32 or 64-bits");
- bits = 32;
- }
-@@ -1737,23 +1918,25 @@ yyreduce:
- (yyval.array).data = empty_data;
- (yyval.array).bits = bits;
- }
--#line 1741 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
-- case 30:
--#line 299 "dtc-parser.y" /* yacc.c:1646 */
-+ case 32:
-+
-+/* Line 1806 of yacc.c */
-+#line 316 "dtc-parser.y"
- {
- (yyval.array).data = empty_data;
- (yyval.array).bits = 32;
- }
--#line 1750 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
-- case 31:
--#line 304 "dtc-parser.y" /* yacc.c:1646 */
-+ case 33:
-+
-+/* Line 1806 of yacc.c */
-+#line 321 "dtc-parser.y"
- {
-- if ((yyvsp[-1].array).bits < 64) {
-- uint64_t mask = (1ULL << (yyvsp[-1].array).bits) - 1;
-+ if ((yyvsp[(1) - (2)].array).bits < 64) {
-+ uint64_t mask = (1ULL << (yyvsp[(1) - (2)].array).bits) - 1;
- /*
- * Bits above mask must either be all zero
- * (positive within range of mask) or all one
-@@ -1762,258 +1945,293 @@ yyreduce:
- * within the mask to one (i.e. | in the
- * mask), all bits are one.
- */
-- if (((yyvsp[0].integer) > mask) && (((yyvsp[0].integer) | mask) != -1ULL))
-- ERROR(&(yylsp[0]), "Value out of range for"
-- " %d-bit array element", (yyvsp[-1].array).bits);
-+ if (((yyvsp[(2) - (2)].integer) > mask) && (((yyvsp[(2) - (2)].integer) | mask) != -1ULL))
-+ ERROR(&(yylsp[(2) - (2)]), "Value out of range for"
-+ " %d-bit array element", (yyvsp[(1) - (2)].array).bits);
- }
-
-- (yyval.array).data = data_append_integer((yyvsp[-1].array).data, (yyvsp[0].integer), (yyvsp[-1].array).bits);
-+ (yyval.array).data = data_append_integer((yyvsp[(1) - (2)].array).data, (yyvsp[(2) - (2)].integer), (yyvsp[(1) - (2)].array).bits);
- }
--#line 1773 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
-- case 32:
--#line 323 "dtc-parser.y" /* yacc.c:1646 */
-+ case 34:
-+
-+/* Line 1806 of yacc.c */
-+#line 340 "dtc-parser.y"
- {
-- uint64_t val = ~0ULL >> (64 - (yyvsp[-1].array).bits);
-+ uint64_t val = ~0ULL >> (64 - (yyvsp[(1) - (2)].array).bits);
-
-- if ((yyvsp[-1].array).bits == 32)
-- (yyvsp[-1].array).data = data_add_marker((yyvsp[-1].array).data,
-+ if ((yyvsp[(1) - (2)].array).bits == 32)
-+ (yyvsp[(1) - (2)].array).data = data_add_marker((yyvsp[(1) - (2)].array).data,
- REF_PHANDLE,
-- (yyvsp[0].labelref));
-+ (yyvsp[(2) - (2)].labelref));
- else
-- ERROR(&(yylsp[0]), "References are only allowed in "
-+ ERROR(&(yylsp[(2) - (2)]), "References are only allowed in "
- "arrays with 32-bit elements.");
-
-- (yyval.array).data = data_append_integer((yyvsp[-1].array).data, val, (yyvsp[-1].array).bits);
-+ (yyval.array).data = data_append_integer((yyvsp[(1) - (2)].array).data, val, (yyvsp[(1) - (2)].array).bits);
- }
--#line 1791 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
-- case 33:
--#line 337 "dtc-parser.y" /* yacc.c:1646 */
-+ case 35:
-+
-+/* Line 1806 of yacc.c */
-+#line 354 "dtc-parser.y"
- {
-- (yyval.array).data = data_add_marker((yyvsp[-1].array).data, LABEL, (yyvsp[0].labelref));
-+ (yyval.array).data = data_add_marker((yyvsp[(1) - (2)].array).data, LABEL, (yyvsp[(2) - (2)].labelref));
- }
--#line 1799 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
-- case 36:
--#line 346 "dtc-parser.y" /* yacc.c:1646 */
-+ case 38:
-+
-+/* Line 1806 of yacc.c */
-+#line 363 "dtc-parser.y"
- {
-- (yyval.integer) = (yyvsp[-1].integer);
-+ (yyval.integer) = (yyvsp[(2) - (3)].integer);
- }
--#line 1807 "dtc-parser.tab.c" /* yacc.c:1646 */
-- break;
--
-- case 39:
--#line 357 "dtc-parser.y" /* yacc.c:1646 */
-- { (yyval.integer) = (yyvsp[-4].integer) ? (yyvsp[-2].integer) : (yyvsp[0].integer); }
--#line 1813 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
- case 41:
--#line 362 "dtc-parser.y" /* yacc.c:1646 */
-- { (yyval.integer) = (yyvsp[-2].integer) || (yyvsp[0].integer); }
--#line 1819 "dtc-parser.tab.c" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 374 "dtc-parser.y"
-+ { (yyval.integer) = (yyvsp[(1) - (5)].integer) ? (yyvsp[(3) - (5)].integer) : (yyvsp[(5) - (5)].integer); }
- break;
-
- case 43:
--#line 367 "dtc-parser.y" /* yacc.c:1646 */
-- { (yyval.integer) = (yyvsp[-2].integer) && (yyvsp[0].integer); }
--#line 1825 "dtc-parser.tab.c" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 379 "dtc-parser.y"
-+ { (yyval.integer) = (yyvsp[(1) - (3)].integer) || (yyvsp[(3) - (3)].integer); }
- break;
-
- case 45:
--#line 372 "dtc-parser.y" /* yacc.c:1646 */
-- { (yyval.integer) = (yyvsp[-2].integer) | (yyvsp[0].integer); }
--#line 1831 "dtc-parser.tab.c" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 384 "dtc-parser.y"
-+ { (yyval.integer) = (yyvsp[(1) - (3)].integer) && (yyvsp[(3) - (3)].integer); }
- break;
-
- case 47:
--#line 377 "dtc-parser.y" /* yacc.c:1646 */
-- { (yyval.integer) = (yyvsp[-2].integer) ^ (yyvsp[0].integer); }
--#line 1837 "dtc-parser.tab.c" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 389 "dtc-parser.y"
-+ { (yyval.integer) = (yyvsp[(1) - (3)].integer) | (yyvsp[(3) - (3)].integer); }
- break;
-
- case 49:
--#line 382 "dtc-parser.y" /* yacc.c:1646 */
-- { (yyval.integer) = (yyvsp[-2].integer) & (yyvsp[0].integer); }
--#line 1843 "dtc-parser.tab.c" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 394 "dtc-parser.y"
-+ { (yyval.integer) = (yyvsp[(1) - (3)].integer) ^ (yyvsp[(3) - (3)].integer); }
- break;
-
- case 51:
--#line 387 "dtc-parser.y" /* yacc.c:1646 */
-- { (yyval.integer) = (yyvsp[-2].integer) == (yyvsp[0].integer); }
--#line 1849 "dtc-parser.tab.c" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 399 "dtc-parser.y"
-+ { (yyval.integer) = (yyvsp[(1) - (3)].integer) & (yyvsp[(3) - (3)].integer); }
- break;
-
-- case 52:
--#line 388 "dtc-parser.y" /* yacc.c:1646 */
-- { (yyval.integer) = (yyvsp[-2].integer) != (yyvsp[0].integer); }
--#line 1855 "dtc-parser.tab.c" /* yacc.c:1646 */
-+ case 53:
-+
-+/* Line 1806 of yacc.c */
-+#line 404 "dtc-parser.y"
-+ { (yyval.integer) = (yyvsp[(1) - (3)].integer) == (yyvsp[(3) - (3)].integer); }
- break;
-
- case 54:
--#line 393 "dtc-parser.y" /* yacc.c:1646 */
-- { (yyval.integer) = (yyvsp[-2].integer) < (yyvsp[0].integer); }
--#line 1861 "dtc-parser.tab.c" /* yacc.c:1646 */
-- break;
-
-- case 55:
--#line 394 "dtc-parser.y" /* yacc.c:1646 */
-- { (yyval.integer) = (yyvsp[-2].integer) > (yyvsp[0].integer); }
--#line 1867 "dtc-parser.tab.c" /* yacc.c:1646 */
-+/* Line 1806 of yacc.c */
-+#line 405 "dtc-parser.y"
-+ { (yyval.integer) = (yyvsp[(1) - (3)].integer) != (yyvsp[(3) - (3)].integer); }
- break;
-
- case 56:
--#line 395 "dtc-parser.y" /* yacc.c:1646 */
-- { (yyval.integer) = (yyvsp[-2].integer) <= (yyvsp[0].integer); }
--#line 1873 "dtc-parser.tab.c" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 410 "dtc-parser.y"
-+ { (yyval.integer) = (yyvsp[(1) - (3)].integer) < (yyvsp[(3) - (3)].integer); }
- break;
-
- case 57:
--#line 396 "dtc-parser.y" /* yacc.c:1646 */
-- { (yyval.integer) = (yyvsp[-2].integer) >= (yyvsp[0].integer); }
--#line 1879 "dtc-parser.tab.c" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 411 "dtc-parser.y"
-+ { (yyval.integer) = (yyvsp[(1) - (3)].integer) > (yyvsp[(3) - (3)].integer); }
- break;
-
- case 58:
--#line 400 "dtc-parser.y" /* yacc.c:1646 */
-- { (yyval.integer) = (yyvsp[-2].integer) << (yyvsp[0].integer); }
--#line 1885 "dtc-parser.tab.c" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 412 "dtc-parser.y"
-+ { (yyval.integer) = (yyvsp[(1) - (3)].integer) <= (yyvsp[(3) - (3)].integer); }
- break;
-
- case 59:
--#line 401 "dtc-parser.y" /* yacc.c:1646 */
-- { (yyval.integer) = (yyvsp[-2].integer) >> (yyvsp[0].integer); }
--#line 1891 "dtc-parser.tab.c" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 413 "dtc-parser.y"
-+ { (yyval.integer) = (yyvsp[(1) - (3)].integer) >= (yyvsp[(3) - (3)].integer); }
-+ break;
-+
-+ case 60:
-+
-+/* Line 1806 of yacc.c */
-+#line 417 "dtc-parser.y"
-+ { (yyval.integer) = (yyvsp[(1) - (3)].integer) << (yyvsp[(3) - (3)].integer); }
- break;
-
- case 61:
--#line 406 "dtc-parser.y" /* yacc.c:1646 */
-- { (yyval.integer) = (yyvsp[-2].integer) + (yyvsp[0].integer); }
--#line 1897 "dtc-parser.tab.c" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 418 "dtc-parser.y"
-+ { (yyval.integer) = (yyvsp[(1) - (3)].integer) >> (yyvsp[(3) - (3)].integer); }
- break;
-
-- case 62:
--#line 407 "dtc-parser.y" /* yacc.c:1646 */
-- { (yyval.integer) = (yyvsp[-2].integer) - (yyvsp[0].integer); }
--#line 1903 "dtc-parser.tab.c" /* yacc.c:1646 */
-+ case 63:
-+
-+/* Line 1806 of yacc.c */
-+#line 423 "dtc-parser.y"
-+ { (yyval.integer) = (yyvsp[(1) - (3)].integer) + (yyvsp[(3) - (3)].integer); }
- break;
-
- case 64:
--#line 412 "dtc-parser.y" /* yacc.c:1646 */
-- { (yyval.integer) = (yyvsp[-2].integer) * (yyvsp[0].integer); }
--#line 1909 "dtc-parser.tab.c" /* yacc.c:1646 */
-- break;
-
-- case 65:
--#line 413 "dtc-parser.y" /* yacc.c:1646 */
-- { (yyval.integer) = (yyvsp[-2].integer) / (yyvsp[0].integer); }
--#line 1915 "dtc-parser.tab.c" /* yacc.c:1646 */
-+/* Line 1806 of yacc.c */
-+#line 424 "dtc-parser.y"
-+ { (yyval.integer) = (yyvsp[(1) - (3)].integer) - (yyvsp[(3) - (3)].integer); }
- break;
-
- case 66:
--#line 414 "dtc-parser.y" /* yacc.c:1646 */
-- { (yyval.integer) = (yyvsp[-2].integer) % (yyvsp[0].integer); }
--#line 1921 "dtc-parser.tab.c" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 429 "dtc-parser.y"
-+ { (yyval.integer) = (yyvsp[(1) - (3)].integer) * (yyvsp[(3) - (3)].integer); }
- break;
-
-- case 69:
--#line 420 "dtc-parser.y" /* yacc.c:1646 */
-- { (yyval.integer) = -(yyvsp[0].integer); }
--#line 1927 "dtc-parser.tab.c" /* yacc.c:1646 */
-+ case 67:
-+
-+/* Line 1806 of yacc.c */
-+#line 430 "dtc-parser.y"
-+ { (yyval.integer) = (yyvsp[(1) - (3)].integer) / (yyvsp[(3) - (3)].integer); }
- break;
-
-- case 70:
--#line 421 "dtc-parser.y" /* yacc.c:1646 */
-- { (yyval.integer) = ~(yyvsp[0].integer); }
--#line 1933 "dtc-parser.tab.c" /* yacc.c:1646 */
-+ case 68:
-+
-+/* Line 1806 of yacc.c */
-+#line 431 "dtc-parser.y"
-+ { (yyval.integer) = (yyvsp[(1) - (3)].integer) % (yyvsp[(3) - (3)].integer); }
- break;
-
- case 71:
--#line 422 "dtc-parser.y" /* yacc.c:1646 */
-- { (yyval.integer) = !(yyvsp[0].integer); }
--#line 1939 "dtc-parser.tab.c" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 437 "dtc-parser.y"
-+ { (yyval.integer) = -(yyvsp[(2) - (2)].integer); }
- break;
-
- case 72:
--#line 427 "dtc-parser.y" /* yacc.c:1646 */
-- {
-- (yyval.data) = empty_data;
-- }
--#line 1947 "dtc-parser.tab.c" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 438 "dtc-parser.y"
-+ { (yyval.integer) = ~(yyvsp[(2) - (2)].integer); }
- break;
-
- case 73:
--#line 431 "dtc-parser.y" /* yacc.c:1646 */
-- {
-- (yyval.data) = data_append_byte((yyvsp[-1].data), (yyvsp[0].byte));
-- }
--#line 1955 "dtc-parser.tab.c" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 439 "dtc-parser.y"
-+ { (yyval.integer) = !(yyvsp[(2) - (2)].integer); }
- break;
-
- case 74:
--#line 435 "dtc-parser.y" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 444 "dtc-parser.y"
- {
-- (yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref));
-+ (yyval.data) = empty_data;
- }
--#line 1963 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
- case 75:
--#line 442 "dtc-parser.y" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 448 "dtc-parser.y"
- {
-- (yyval.nodelist) = NULL;
-+ (yyval.data) = data_append_byte((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].byte));
- }
--#line 1971 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
- case 76:
--#line 446 "dtc-parser.y" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 452 "dtc-parser.y"
- {
-- (yyval.nodelist) = chain_node((yyvsp[-1].node), (yyvsp[0].nodelist));
-+ (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref));
- }
--#line 1979 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
- case 77:
--#line 450 "dtc-parser.y" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 459 "dtc-parser.y"
- {
-- ERROR(&(yylsp[0]), "Properties must precede subnodes");
-- YYERROR;
-+ (yyval.nodelist) = NULL;
- }
--#line 1988 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
- case 78:
--#line 458 "dtc-parser.y" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 463 "dtc-parser.y"
- {
-- (yyval.node) = name_node((yyvsp[0].node), (yyvsp[-1].propnodename));
-+ (yyval.nodelist) = chain_node((yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].nodelist));
- }
--#line 1996 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
- case 79:
--#line 462 "dtc-parser.y" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 467 "dtc-parser.y"
- {
-- (yyval.node) = name_node(build_node_delete(), (yyvsp[-1].propnodename));
-+ ERROR(&(yylsp[(2) - (2)]), "Properties must precede subnodes");
-+ YYERROR;
- }
--#line 2004 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
- case 80:
--#line 466 "dtc-parser.y" /* yacc.c:1646 */
-+
-+/* Line 1806 of yacc.c */
-+#line 475 "dtc-parser.y"
- {
-- add_label(&(yyvsp[0].node)->labels, (yyvsp[-1].labelref));
-- (yyval.node) = (yyvsp[0].node);
-+ (yyval.node) = name_node((yyvsp[(2) - (2)].node), (yyvsp[(1) - (2)].propnodename));
- }
--#line 2013 "dtc-parser.tab.c" /* yacc.c:1646 */
- break;
-
-+ case 81:
-
--#line 2017 "dtc-parser.tab.c" /* yacc.c:1646 */
-+/* Line 1806 of yacc.c */
-+#line 479 "dtc-parser.y"
-+ {
-+ (yyval.node) = name_node(build_node_delete(), (yyvsp[(2) - (3)].propnodename));
-+ }
-+ break;
-+
-+ case 82:
-+
-+/* Line 1806 of yacc.c */
-+#line 483 "dtc-parser.y"
-+ {
-+ add_label(&(yyvsp[(2) - (2)].node)->labels, (yyvsp[(1) - (2)].labelref));
-+ (yyval.node) = (yyvsp[(2) - (2)].node);
-+ }
-+ break;
-+
-+
-+
-+/* Line 1806 of yacc.c */
-+#line 2235 "dtc-parser.tab.c"
- default: break;
- }
- /* User semantic actions sometimes alter yychar, and that requires
-@@ -2036,7 +2254,7 @@ yyreduce:
- *++yyvsp = yyval;
- *++yylsp = yyloc;
-
-- /* Now 'shift' the result of the reduction. Determine what state
-+ /* Now `shift' the result of the reduction. Determine what state
- that goes to, based on the state we popped back to and the rule
- number reduced by. */
-
-@@ -2051,9 +2269,9 @@ yyreduce:
- goto yynewstate;
-
-
--/*--------------------------------------.
--| yyerrlab -- here on detecting error. |
--`--------------------------------------*/
-+/*------------------------------------.
-+| yyerrlab -- here on detecting error |
-+`------------------------------------*/
- yyerrlab:
- /* Make sure we have latest lookahead translation. See comments at
- user semantic actions for why this is necessary. */
-@@ -2104,20 +2322,20 @@ yyerrlab:
- if (yyerrstatus == 3)
- {
- /* If just tried and failed to reuse lookahead token after an
-- error, discard it. */
-+ error, discard it. */
-
- if (yychar <= YYEOF)
-- {
-- /* Return failure if at end of input. */
-- if (yychar == YYEOF)
-- YYABORT;
-- }
-+ {
-+ /* Return failure if at end of input. */
-+ if (yychar == YYEOF)
-+ YYABORT;
-+ }
- else
-- {
-- yydestruct ("Error: discarding",
-- yytoken, &yylval, &yylloc);
-- yychar = YYEMPTY;
-- }
-+ {
-+ yydestruct ("Error: discarding",
-+ yytoken, &yylval, &yylloc);
-+ yychar = YYEMPTY;
-+ }
- }
-
- /* Else will try to reuse lookahead token after shifting the error
-@@ -2137,7 +2355,7 @@ yyerrorlab:
- goto yyerrorlab;
-
- yyerror_range[1] = yylsp[1-yylen];
-- /* Do not reclaim the symbols of the rule whose action triggered
-+ /* Do not reclaim the symbols of the rule which action triggered
- this YYERROR. */
- YYPOPSTACK (yylen);
- yylen = 0;
-@@ -2150,37 +2368,35 @@ yyerrorlab:
- | yyerrlab1 -- common code for both syntax error and YYERROR. |
- `-------------------------------------------------------------*/
- yyerrlab1:
-- yyerrstatus = 3; /* Each real token shifted decrements this. */
-+ yyerrstatus = 3; /* Each real token shifted decrements this. */
-
- for (;;)
- {
- yyn = yypact[yystate];
- if (!yypact_value_is_default (yyn))
-- {
-- yyn += YYTERROR;
-- if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
-- {
-- yyn = yytable[yyn];
-- if (0 < yyn)
-- break;
-- }
-- }
-+ {
-+ yyn += YYTERROR;
-+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
-+ {
-+ yyn = yytable[yyn];
-+ if (0 < yyn)
-+ break;
-+ }
-+ }
-
- /* Pop the current state because it cannot handle the error token. */
- if (yyssp == yyss)
-- YYABORT;
-+ YYABORT;
-
- yyerror_range[1] = *yylsp;
- yydestruct ("Error: popping",
-- yystos[yystate], yyvsp, yylsp);
-+ yystos[yystate], yyvsp, yylsp);
- YYPOPSTACK (1);
- yystate = *yyssp;
- YY_STACK_PRINT (yyss, yyssp);
- }
-
-- YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
- *++yyvsp = yylval;
-- YY_IGNORE_MAYBE_UNINITIALIZED_END
-
- yyerror_range[2] = yylloc;
- /* Using YYLLOC is tempting, but would change the location of
-@@ -2209,7 +2425,7 @@ yyabortlab:
- yyresult = 1;
- goto yyreturn;
-
--#if !defined yyoverflow || YYERROR_VERBOSE
-+#if !defined(yyoverflow) || YYERROR_VERBOSE
- /*-------------------------------------------------.
- | yyexhaustedlab -- memory exhaustion comes here. |
- `-------------------------------------------------*/
-@@ -2228,14 +2444,14 @@ yyreturn:
- yydestruct ("Cleanup: discarding lookahead",
- yytoken, &yylval, &yylloc);
- }
-- /* Do not reclaim the symbols of the rule whose action triggered
-+ /* Do not reclaim the symbols of the rule which action triggered
- this YYABORT or YYACCEPT. */
- YYPOPSTACK (yylen);
- YY_STACK_PRINT (yyss, yyssp);
- while (yyssp != yyss)
- {
- yydestruct ("Cleanup: popping",
-- yystos[*yyssp], yyvsp, yylsp);
-+ yystos[*yyssp], yyvsp, yylsp);
- YYPOPSTACK (1);
- }
- #ifndef yyoverflow
-@@ -2246,12 +2462,18 @@ yyreturn:
- if (yymsg != yymsgbuf)
- YYSTACK_FREE (yymsg);
- #endif
-- return yyresult;
-+ /* Make sure YYID is used. */
-+ return YYID (yyresult);
- }
--#line 472 "dtc-parser.y" /* yacc.c:1906 */
-+
-+
-+
-+/* Line 2067 of yacc.c */
-+#line 489 "dtc-parser.y"
-
-
- void yyerror(char const *s)
- {
- ERROR(&yylloc, "%s", s);
- }
-+
---- a/scripts/dtc/dtc-parser.tab.h_shipped
-+++ b/scripts/dtc/dtc-parser.tab.h_shipped
-@@ -1,19 +1,19 @@
--/* A Bison parser, made by GNU Bison 3.0.2. */
-+/* A Bison parser, made by GNU Bison 2.5. */
-
- /* Bison interface for Yacc-like parsers in C
--
-- Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
--
-+
-+ Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
-+
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. */
-
-@@ -26,55 +26,50 @@
- special exception, which will cause the skeleton and the resulting
- Bison output files to be licensed under the GNU General Public
- License without this special exception.
--
-+
- This special exception was added by the Free Software Foundation in
- version 2.2 of Bison. */
-
--#ifndef YY_YY_DTC_PARSER_TAB_H_INCLUDED
--# define YY_YY_DTC_PARSER_TAB_H_INCLUDED
--/* Debug traces. */
--#ifndef YYDEBUG
--# define YYDEBUG 0
--#endif
--#if YYDEBUG
--extern int yydebug;
--#endif
-
--/* Token type. */
-+/* Tokens. */
- #ifndef YYTOKENTYPE
- # define YYTOKENTYPE
-- enum yytokentype
-- {
-- DT_V1 = 258,
-- DT_MEMRESERVE = 259,
-- DT_LSHIFT = 260,
-- DT_RSHIFT = 261,
-- DT_LE = 262,
-- DT_GE = 263,
-- DT_EQ = 264,
-- DT_NE = 265,
-- DT_AND = 266,
-- DT_OR = 267,
-- DT_BITS = 268,
-- DT_DEL_PROP = 269,
-- DT_DEL_NODE = 270,
-- DT_PROPNODENAME = 271,
-- DT_LITERAL = 272,
-- DT_CHAR_LITERAL = 273,
-- DT_BYTE = 274,
-- DT_STRING = 275,
-- DT_LABEL = 276,
-- DT_REF = 277,
-- DT_INCBIN = 278
-- };
-+ /* Put the tokens into the symbol table, so that GDB and other debuggers
-+ know about them. */
-+ enum yytokentype {
-+ DT_V1 = 258,
-+ DT_PLUGIN = 259,
-+ DT_MEMRESERVE = 260,
-+ DT_LSHIFT = 261,
-+ DT_RSHIFT = 262,
-+ DT_LE = 263,
-+ DT_GE = 264,
-+ DT_EQ = 265,
-+ DT_NE = 266,
-+ DT_AND = 267,
-+ DT_OR = 268,
-+ DT_BITS = 269,
-+ DT_DEL_PROP = 270,
-+ DT_DEL_NODE = 271,
-+ DT_PROPNODENAME = 272,
-+ DT_LITERAL = 273,
-+ DT_CHAR_LITERAL = 274,
-+ DT_BYTE = 275,
-+ DT_STRING = 276,
-+ DT_LABEL = 277,
-+ DT_REF = 278,
-+ DT_INCBIN = 279
-+ };
- #endif
-
--/* Value type. */
-+
-+
- #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
--typedef union YYSTYPE YYSTYPE;
--union YYSTYPE
-+typedef union YYSTYPE
- {
--#line 38 "dtc-parser.y" /* yacc.c:1909 */
-+
-+/* Line 2068 of yacc.c */
-+#line 39 "dtc-parser.y"
-
- char *propnodename;
- char *labelref;
-@@ -92,30 +87,32 @@ union YYSTYPE
- struct node *nodelist;
- struct reserve_info *re;
- uint64_t integer;
-+ int is_plugin;
-+
-+
-
--#line 97 "dtc-parser.tab.h" /* yacc.c:1909 */
--};
-+/* Line 2068 of yacc.c */
-+#line 96 "dtc-parser.tab.h"
-+} YYSTYPE;
- # define YYSTYPE_IS_TRIVIAL 1
-+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
- # define YYSTYPE_IS_DECLARED 1
- #endif
-
--/* Location type. */
-+extern YYSTYPE yylval;
-+
- #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
--typedef struct YYLTYPE YYLTYPE;
--struct YYLTYPE
-+typedef struct YYLTYPE
- {
- int first_line;
- int first_column;
- int last_line;
- int last_column;
--};
-+} YYLTYPE;
-+# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
- # define YYLTYPE_IS_DECLARED 1
- # define YYLTYPE_IS_TRIVIAL 1
- #endif
-
--
--extern YYSTYPE yylval;
- extern YYLTYPE yylloc;
--int yyparse (void);
-
--#endif /* !YY_YY_DTC_PARSER_TAB_H_INCLUDED */
---- a/scripts/dtc/dtc-parser.y
-+++ b/scripts/dtc/dtc-parser.y
-@@ -19,6 +19,7 @@
- */
- %{
- #include <stdio.h>
-+#include <inttypes.h>
-
- #include "dtc.h"
- #include "srcpos.h"
-@@ -52,9 +53,11 @@ extern bool treesource_error;
- struct node *nodelist;
- struct reserve_info *re;
- uint64_t integer;
-+ int is_plugin;
- }
-
- %token DT_V1
-+%token DT_PLUGIN
- %token DT_MEMRESERVE
- %token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR
- %token DT_BITS
-@@ -71,6 +74,7 @@ extern bool treesource_error;
-
- %type <data> propdata
- %type <data> propdataprefix
-+%type <is_plugin> plugindecl
- %type <re> memreserve
- %type <re> memreserves
- %type <array> arrayprefix
-@@ -101,10 +105,23 @@ extern bool treesource_error;
- %%
-
- sourcefile:
-- DT_V1 ';' memreserves devicetree
-+ DT_V1 ';' plugindecl memreserves devicetree
- {
-- the_boot_info = build_boot_info($3, $4,
-- guess_boot_cpuid($4));
-+ $5->is_plugin = $3;
-+ $5->is_root = 1;
-+ the_boot_info = build_boot_info($4, $5,
-+ guess_boot_cpuid($5));
-+ }
-+ ;
-+
-+plugindecl:
-+ /* empty */
-+ {
-+ $$ = 0;
-+ }
-+ | DT_PLUGIN ';'
-+ {
-+ $$ = 1;
- }
- ;
-
---- a/scripts/dtc/dtc.c
-+++ b/scripts/dtc/dtc.c
-@@ -29,6 +29,7 @@ int reservenum; /* Number of memory res
- int minsize; /* Minimum blob size */
- int padsize; /* Additional padding to blob */
- int phandle_format = PHANDLE_BOTH; /* Use linux,phandle or phandle properties */
-+int symbol_fixup_support = 0;
-
- static void fill_fullpaths(struct node *tree, const char *prefix)
- {
-@@ -51,7 +52,7 @@ static void fill_fullpaths(struct node *
- #define FDT_VERSION(version) _FDT_VERSION(version)
- #define _FDT_VERSION(version) #version
- static const char usage_synopsis[] = "dtc [options] <input file>";
--static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:hv";
-+static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:hv@";
- static struct option const usage_long_opts[] = {
- {"quiet", no_argument, NULL, 'q'},
- {"in-format", a_argument, NULL, 'I'},
-@@ -69,6 +70,7 @@ static struct option const usage_long_op
- {"phandle", a_argument, NULL, 'H'},
- {"warning", a_argument, NULL, 'W'},
- {"error", a_argument, NULL, 'E'},
-+ {"symbols", a_argument, NULL, '@'},
- {"help", no_argument, NULL, 'h'},
- {"version", no_argument, NULL, 'v'},
- {NULL, no_argument, NULL, 0x0},
-@@ -99,6 +101,7 @@ static const char * const usage_opts_hel
- "\t\tboth - Both \"linux,phandle\" and \"phandle\" properties",
- "\n\tEnable/disable warnings (prefix with \"no-\")",
- "\n\tEnable/disable errors (prefix with \"no-\")",
-+ "\n\tSymbols and Fixups support",
- "\n\tPrint this help and exit",
- "\n\tPrint version and exit",
- NULL,
-@@ -186,7 +189,9 @@ int main(int argc, char *argv[])
- case 'E':
- parse_checks_option(false, true, optarg);
- break;
--
-+ case '@':
-+ symbol_fixup_support = 1;
-+ break;
- case 'h':
- usage(NULL);
- default:
---- a/scripts/dtc/dtc.h
-+++ b/scripts/dtc/dtc.h
-@@ -54,6 +54,7 @@ extern int reservenum; /* Number of mem
- extern int minsize; /* Minimum blob size */
- extern int padsize; /* Additional padding to blob */
- extern int phandle_format; /* Use linux,phandle or phandle properties */
-+extern int symbol_fixup_support;/* enable symbols & fixup support */
-
- #define PHANDLE_LEGACY 0x1
- #define PHANDLE_EPAPR 0x2
-@@ -132,6 +133,25 @@ struct label {
- struct label *next;
- };
-
-+struct fixup_entry {
-+ int offset;
-+ struct node *node;
-+ struct property *prop;
-+ struct fixup_entry *next;
-+};
-+
-+struct fixup {
-+ char *ref;
-+ struct fixup_entry *entries;
-+ struct fixup *next;
-+};
-+
-+struct symbol {
-+ struct label *label;
-+ struct node *node;
-+ struct symbol *next;
-+};
-+
- struct property {
- bool deleted;
- char *name;
-@@ -158,6 +178,12 @@ struct node {
- int addr_cells, size_cells;
-
- struct label *labels;
-+
-+ int is_root;
-+ int is_plugin;
-+ struct fixup *fixups;
-+ struct symbol *symbols;
-+ struct fixup_entry *local_fixups;
- };
-
- #define for_each_label_withdel(l0, l) \
-@@ -181,6 +207,18 @@ struct node {
- for_each_child_withdel(n, c) \
- if (!(c)->deleted)
-
-+#define for_each_fixup(n, f) \
-+ for ((f) = (n)->fixups; (f); (f) = (f)->next)
-+
-+#define for_each_fixup_entry(f, fe) \
-+ for ((fe) = (f)->entries; (fe); (fe) = (fe)->next)
-+
-+#define for_each_symbol(n, s) \
-+ for ((s) = (n)->symbols; (s); (s) = (s)->next)
-+
-+#define for_each_local_fixup_entry(n, fe) \
-+ for ((fe) = (n)->local_fixups; (fe); (fe) = (fe)->next)
-+
- void add_label(struct label **labels, char *label);
- void delete_labels(struct label **labels);
-
---- a/scripts/dtc/flattree.c
-+++ b/scripts/dtc/flattree.c
-@@ -262,6 +262,12 @@ static void flatten_tree(struct node *tr
- struct property *prop;
- struct node *child;
- bool seen_name_prop = false;
-+ struct symbol *sym;
-+ struct fixup *f;
-+ struct fixup_entry *fe;
-+ char *name, *s;
-+ const char *fullpath;
-+ int namesz, nameoff, vallen;
-
- if (tree->deleted)
- return;
-@@ -276,8 +282,6 @@ static void flatten_tree(struct node *tr
- emit->align(etarget, sizeof(cell_t));
-
- for_each_property(tree, prop) {
-- int nameoff;
--
- if (streq(prop->name, "name"))
- seen_name_prop = true;
-
-@@ -310,6 +314,139 @@ static void flatten_tree(struct node *tr
- flatten_tree(child, emit, etarget, strbuf, vi);
- }
-
-+ if (!symbol_fixup_support)
-+ goto no_symbols;
-+
-+ /* add the symbol nodes (if any) */
-+ if (tree->symbols) {
-+
-+ emit->beginnode(etarget, NULL);
-+ emit->string(etarget, "__symbols__", 0);
-+ emit->align(etarget, sizeof(cell_t));
-+
-+ for_each_symbol(tree, sym) {
-+
-+ vallen = strlen(sym->node->fullpath);
-+
-+ nameoff = stringtable_insert(strbuf, sym->label->label);
-+
-+ emit->property(etarget, NULL);
-+ emit->cell(etarget, vallen + 1);
-+ emit->cell(etarget, nameoff);
-+
-+ if ((vi->flags & FTF_VARALIGN) && vallen >= 8)
-+ emit->align(etarget, 8);
-+
-+ emit->string(etarget, sym->node->fullpath,
-+ strlen(sym->node->fullpath));
-+ emit->align(etarget, sizeof(cell_t));
-+ }
-+
-+ emit->endnode(etarget, NULL);
-+ }
-+
-+ /* add the fixup nodes */
-+ if (tree->fixups) {
-+
-+ /* emit the external fixups */
-+ emit->beginnode(etarget, NULL);
-+ emit->string(etarget, "__fixups__", 0);
-+ emit->align(etarget, sizeof(cell_t));
-+
-+ for_each_fixup(tree, f) {
-+
-+ namesz = 0;
-+ for_each_fixup_entry(f, fe) {
-+ fullpath = fe->node->fullpath;
-+ if (fullpath[0] == '\0')
-+ fullpath = "/";
-+ namesz += strlen(fullpath) + 1;
-+ namesz += strlen(fe->prop->name) + 1;
-+ namesz += 32; /* space for :<number> + '\0' */
-+ }
-+
-+ name = xmalloc(namesz);
-+
-+ s = name;
-+ for_each_fixup_entry(f, fe) {
-+ fullpath = fe->node->fullpath;
-+ if (fullpath[0] == '\0')
-+ fullpath = "/";
-+ snprintf(s, name + namesz - s, "%s:%s:%d",
-+ fullpath,
-+ fe->prop->name, fe->offset);
-+ s += strlen(s) + 1;
-+ }
-+
-+ nameoff = stringtable_insert(strbuf, f->ref);
-+ vallen = s - name - 1;
-+
-+ emit->property(etarget, NULL);
-+ emit->cell(etarget, vallen + 1);
-+ emit->cell(etarget, nameoff);
-+
-+ if ((vi->flags & FTF_VARALIGN) && vallen >= 8)
-+ emit->align(etarget, 8);
-+
-+ emit->string(etarget, name, vallen);
-+ emit->align(etarget, sizeof(cell_t));
-+
-+ free(name);
-+ }
-+
-+ emit->endnode(etarget, tree->labels);
-+ }
-+
-+ /* add the local fixup property */
-+ if (tree->local_fixups) {
-+
-+ /* emit the external fixups */
-+ emit->beginnode(etarget, NULL);
-+ emit->string(etarget, "__local_fixups__", 0);
-+ emit->align(etarget, sizeof(cell_t));
-+
-+ namesz = 0;
-+ for_each_local_fixup_entry(tree, fe) {
-+ fullpath = fe->node->fullpath;
-+ if (fullpath[0] == '\0')
-+ fullpath = "/";
-+ namesz += strlen(fullpath) + 1;
-+ namesz += strlen(fe->prop->name) + 1;
-+ namesz += 32; /* space for :<number> + '\0' */
-+ }
-+
-+ name = xmalloc(namesz);
-+
-+ s = name;
-+ for_each_local_fixup_entry(tree, fe) {
-+ fullpath = fe->node->fullpath;
-+ if (fullpath[0] == '\0')
-+ fullpath = "/";
-+ snprintf(s, name + namesz - s, "%s:%s:%d",
-+ fullpath, fe->prop->name,
-+ fe->offset);
-+ s += strlen(s) + 1;
-+ }
-+
-+ nameoff = stringtable_insert(strbuf, "fixup");
-+ vallen = s - name - 1;
-+
-+ emit->property(etarget, NULL);
-+ emit->cell(etarget, vallen + 1);
-+ emit->cell(etarget, nameoff);
-+
-+ if ((vi->flags & FTF_VARALIGN) && vallen >= 8)
-+ emit->align(etarget, 8);
-+
-+ emit->string(etarget, name, vallen);
-+ emit->align(etarget, sizeof(cell_t));
-+
-+ free(name);
-+
-+ emit->endnode(etarget, tree->labels);
-+ }
-+
-+no_symbols:
- emit->endnode(etarget, tree->labels);
- }
-
---- a/scripts/dtc/version_gen.h
-+++ b/scripts/dtc/version_gen.h
-@@ -1 +1 @@
--#define DTC_VERSION "DTC 1.4.1-g9d3649bd"
-+#define DTC_VERSION "DTC 1.4.1-g9d3649bd-dirty"
diff --git a/target/linux/brcm2708/patches-4.4/0084-RaspiDAC3-support.patch b/target/linux/brcm2708/patches-4.4/0084-RaspiDAC3-support.patch
new file mode 100644
index 0000000000..3c9ad066ab
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0084-RaspiDAC3-support.patch
@@ -0,0 +1,243 @@
+From c7773e6daa5df456d6e0b935321425f3cb7a55b8 Mon Sep 17 00:00:00 2001
+From: Jan Grulich <jan@grulich.eu>
+Date: Mon, 24 Aug 2015 16:03:47 +0100
+Subject: [PATCH 084/381] RaspiDAC3 support
+
+Signed-off-by: Jan Grulich <jan@grulich.eu>
+
+config: fix RaspiDAC Rev.3x dependencies
+
+Change depends to SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+like the other I2S soundcard drivers.
+
+Signed-off-by: Matthias Reichl <hias@horus.com>
+---
+ sound/soc/bcm/Kconfig | 8 ++
+ sound/soc/bcm/Makefile | 2 +
+ sound/soc/bcm/raspidac3.c | 191 ++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 201 insertions(+)
+ create mode 100644 sound/soc/bcm/raspidac3.c
+
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -56,3 +56,11 @@ config SND_BCM2708_SOC_IQAUDIO_DAC
+ select SND_SOC_PCM512x_I2C
+ help
+ Say Y or M if you want to add support for IQaudIO-DAC.
++
++config SND_BCM2708_SOC_RASPIDAC3
++ tristate "Support for RaspiDAC Rev.3x"
++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
++ select SND_SOC_PCM512x_I2C
++ select SND_SOC_TPA6130A2
++ help
++ Say Y or M if you want to add support for RaspiDAC Rev.3x.
+--- a/sound/soc/bcm/Makefile
++++ b/sound/soc/bcm/Makefile
+@@ -11,6 +11,7 @@ snd-soc-hifiberry-amp-objs := hifiberry_
+ snd-soc-rpi-dac-objs := rpi-dac.o
+ snd-soc-rpi-proto-objs := rpi-proto.o
+ snd-soc-iqaudio-dac-objs := iqaudio-dac.o
++snd-soc-raspidac3-objs := raspidac3.o
+
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
+@@ -19,3 +20,4 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_A
+ obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o
+ obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
+ obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
++obj-$(CONFIG_SND_BCM2708_SOC_RASPIDAC3) += snd-soc-raspidac3.o
+--- /dev/null
++++ b/sound/soc/bcm/raspidac3.c
+@@ -0,0 +1,191 @@
++/*
++ * ASoC Driver for RaspiDAC v3
++ *
++ * Author: Jan Grulich <jan@grulich.eu>
++ * Copyright 2015
++ * based on code by Daniel Matuschek <daniel@hifiberry.com>
++ * based on code by Florian Meier <florian.meier@koalo.de>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/jack.h>
++#include <sound/soc-dapm.h>
++
++#include "../codecs/pcm512x.h"
++#include "../codecs/tpa6130a2.h"
++
++/* sound card init */
++static int snd_rpi_raspidac3_init(struct snd_soc_pcm_runtime *rtd)
++{
++ int ret;
++ struct snd_soc_card *card = rtd->card;
++ struct snd_soc_codec *codec = rtd->codec;
++ snd_soc_update_bits(codec, PCM512x_GPIO_EN, 0x08, 0x08);
++ snd_soc_update_bits(codec, PCM512x_GPIO_OUTPUT_4, 0xf, 0x02);
++ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08,0x00);
++
++ ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207);
++ if (ret < 0)
++ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
++ else {
++ struct snd_kcontrol *kctl;
++
++ ret = tpa6130a2_add_controls(codec);
++ if (ret < 0)
++ dev_warn(card->dev, "Failed to add TPA6130A2 controls: %d\n",
++ ret);
++ ret = snd_soc_limit_volume(card,
++ "TPA6130A2 Headphone Playback Volume",
++ 54);
++ if (ret < 0)
++ dev_warn(card->dev, "Failed to set TPA6130A2 volume limit: %d\n",
++ ret);
++ kctl = snd_soc_card_get_kcontrol(card,
++ "TPA6130A2 Headphone Playback Volume");
++ if (kctl) {
++ strcpy(kctl->id.name, "Headphones Playback Volume");
++ /* disable the volume dB scale so alsamixer works */
++ kctl->vd[0].access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
++ }
++
++ kctl = snd_soc_card_get_kcontrol(card,
++ "TPA6130A2 Headphone Playback Switch");
++ if (kctl)
++ strcpy(kctl->id.name, "Headphones Playback Switch");
++ }
++
++ return 0;
++}
++
++/* set hw parameters */
++static int snd_rpi_raspidac3_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
++
++ unsigned int sample_bits =
++ snd_pcm_format_physical_width(params_format(params));
++
++ return snd_soc_dai_set_bclk_ratio(cpu_dai, sample_bits * 2);
++}
++
++/* startup */
++static int snd_rpi_raspidac3_startup(struct snd_pcm_substream *substream) {
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_codec *codec = rtd->codec;
++ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08,0x08);
++ tpa6130a2_stereo_enable(codec, 1);
++ return 0;
++}
++
++/* shutdown */
++static void snd_rpi_raspidac3_shutdown(struct snd_pcm_substream *substream) {
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_codec *codec = rtd->codec;
++ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08,0x00);
++ tpa6130a2_stereo_enable(codec, 0);
++}
++
++/* machine stream operations */
++static struct snd_soc_ops snd_rpi_raspidac3_ops = {
++ .hw_params = snd_rpi_raspidac3_hw_params,
++ .startup = snd_rpi_raspidac3_startup,
++ .shutdown = snd_rpi_raspidac3_shutdown,
++};
++
++/* interface setup */
++static struct snd_soc_dai_link snd_rpi_raspidac3_dai[] = {
++{
++ .name = "RaspiDAC Rev.3x",
++ .stream_name = "RaspiDAC HiFi",
++ .cpu_dai_name = "bcm2708-i2s.0",
++ .codec_dai_name = "pcm512x-hifi",
++ .platform_name = "bcm2708-i2s.0",
++ .codec_name = "pcm512x.1-004c",
++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBS_CFS,
++ .ops = &snd_rpi_raspidac3_ops,
++ .init = snd_rpi_raspidac3_init,
++},
++};
++
++/* audio machine driver */
++static struct snd_soc_card snd_rpi_raspidac3 = {
++ .name = "RaspiDAC Rev.3x HiFi Audio Card",
++ .dai_link = snd_rpi_raspidac3_dai,
++ .num_links = ARRAY_SIZE(snd_rpi_raspidac3_dai),
++};
++
++/* sound card test */
++static int snd_rpi_raspidac3_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++
++ snd_rpi_raspidac3.dev = &pdev->dev;
++
++ if (pdev->dev.of_node) {
++ struct device_node *i2s_node;
++ struct snd_soc_dai_link *dai = &snd_rpi_raspidac3_dai[0];
++ i2s_node = of_parse_phandle(pdev->dev.of_node,
++ "i2s-controller", 0);
++
++ if (i2s_node) {
++ dai->cpu_dai_name = NULL;
++ dai->cpu_of_node = i2s_node;
++ dai->platform_name = NULL;
++ dai->platform_of_node = i2s_node;
++ }
++ }
++
++ ret = snd_soc_register_card(&snd_rpi_raspidac3);
++ if (ret)
++ dev_err(&pdev->dev,
++ "snd_soc_register_card() failed: %d\n", ret);
++
++ return ret;
++}
++
++/* sound card disconnect */
++static int snd_rpi_raspidac3_remove(struct platform_device *pdev)
++{
++ return snd_soc_unregister_card(&snd_rpi_raspidac3);
++}
++
++static const struct of_device_id raspidac3_of_match[] = {
++ { .compatible = "jg,raspidacv3", },
++ {},
++};
++MODULE_DEVICE_TABLE(of, raspidac3_of_match);
++
++/* sound card platform driver */
++static struct platform_driver snd_rpi_raspidac3_driver = {
++ .driver = {
++ .name = "snd-rpi-raspidac3",
++ .owner = THIS_MODULE,
++ .of_match_table = raspidac3_of_match,
++ },
++ .probe = snd_rpi_raspidac3_probe,
++ .remove = snd_rpi_raspidac3_remove,
++};
++
++module_platform_driver(snd_rpi_raspidac3_driver);
++
++MODULE_AUTHOR("Jan Grulich <jan@grulich.eu>");
++MODULE_DESCRIPTION("ASoC Driver for RaspiDAC Rev.3x");
++MODULE_LICENSE("GPL v2");
diff --git a/target/linux/brcm2708/patches-4.4/0084-mfd-Add-Raspberry-Pi-Sense-HAT-core-driver.patch b/target/linux/brcm2708/patches-4.4/0084-mfd-Add-Raspberry-Pi-Sense-HAT-core-driver.patch
deleted file mode 100644
index 9e41391993..0000000000
--- a/target/linux/brcm2708/patches-4.4/0084-mfd-Add-Raspberry-Pi-Sense-HAT-core-driver.patch
+++ /dev/null
@@ -1,838 +0,0 @@
-From b065c580329ecb7c7e77bb7019c6059d7db83398 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <pelwell@users.noreply.github.com>
-Date: Tue, 14 Jul 2015 14:32:47 +0100
-Subject: [PATCH 084/170] mfd: Add Raspberry Pi Sense HAT core driver
-
----
- drivers/input/joystick/Kconfig | 8 +
- drivers/input/joystick/Makefile | 1 +
- drivers/input/joystick/rpisense-js.c | 153 ++++++++++++++++
- drivers/mfd/Kconfig | 8 +
- drivers/mfd/Makefile | 2 +
- drivers/mfd/rpisense-core.c | 157 +++++++++++++++++
- drivers/video/fbdev/Kconfig | 13 ++
- drivers/video/fbdev/Makefile | 1 +
- drivers/video/fbdev/rpisense-fb.c | 293 +++++++++++++++++++++++++++++++
- include/linux/mfd/rpisense/core.h | 47 +++++
- include/linux/mfd/rpisense/framebuffer.h | 32 ++++
- include/linux/mfd/rpisense/joystick.h | 35 ++++
- 12 files changed, 750 insertions(+)
- create mode 100644 drivers/input/joystick/rpisense-js.c
- create mode 100644 drivers/mfd/rpisense-core.c
- create mode 100644 drivers/video/fbdev/rpisense-fb.c
- create mode 100644 include/linux/mfd/rpisense/core.h
- create mode 100644 include/linux/mfd/rpisense/framebuffer.h
- create mode 100644 include/linux/mfd/rpisense/joystick.h
-
---- a/drivers/input/joystick/Kconfig
-+++ b/drivers/input/joystick/Kconfig
-@@ -330,4 +330,12 @@ config JOYSTICK_MAPLE
- To compile this as a module choose M here: the module will be called
- maplecontrol.
-
-+config JOYSTICK_RPISENSE
-+ tristate "Raspberry Pi Sense HAT joystick"
-+ depends on GPIOLIB && INPUT
-+ select MFD_RPISENSE_CORE
-+
-+ help
-+ This is the joystick driver for the Raspberry Pi Sense HAT
-+
- endif
---- a/drivers/input/joystick/Makefile
-+++ b/drivers/input/joystick/Makefile
-@@ -32,4 +32,5 @@ obj-$(CONFIG_JOYSTICK_WARRIOR) += warri
- obj-$(CONFIG_JOYSTICK_XPAD) += xpad.o
- obj-$(CONFIG_JOYSTICK_ZHENHUA) += zhenhua.o
- obj-$(CONFIG_JOYSTICK_WALKERA0701) += walkera0701.o
-+obj-$(CONFIG_JOYSTICK_RPISENSE) += rpisense-js.o
-
---- /dev/null
-+++ b/drivers/input/joystick/rpisense-js.c
-@@ -0,0 +1,153 @@
-+/*
-+ * Raspberry Pi Sense HAT joystick driver
-+ * http://raspberrypi.org
-+ *
-+ * Copyright (C) 2015 Raspberry Pi
-+ *
-+ * Author: Serge Schneider
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License as published by the
-+ * Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version.
-+ *
-+ */
-+
-+#include <linux/module.h>
-+
-+#include <linux/mfd/rpisense/joystick.h>
-+#include <linux/mfd/rpisense/core.h>
-+
-+static struct rpisense *rpisense;
-+static unsigned char keymap[5] = {KEY_DOWN, KEY_RIGHT, KEY_UP, KEY_ENTER, KEY_LEFT,};
-+
-+static void keys_work_fn(struct work_struct *work)
-+{
-+ int i;
-+ static s32 prev_keys;
-+ struct rpisense_js *rpisense_js = &rpisense->joystick;
-+ s32 keys = rpisense_reg_read(rpisense, RPISENSE_KEYS);
-+ s32 changes = keys ^ prev_keys;
-+
-+ prev_keys = keys;
-+ for (i = 0; i < 5; i++) {
-+ if (changes & 1) {
-+ input_report_key(rpisense_js->keys_dev,
-+ keymap[i], keys & 1);
-+ }
-+ changes >>= 1;
-+ keys >>= 1;
-+ }
-+ input_sync(rpisense_js->keys_dev);
-+}
-+
-+static irqreturn_t keys_irq_handler(int irq, void *pdev)
-+{
-+ struct rpisense_js *rpisense_js = &rpisense->joystick;
-+
-+ schedule_work(&rpisense_js->keys_work_s);
-+ return IRQ_HANDLED;
-+}
-+
-+static int rpisense_js_probe(struct platform_device *pdev)
-+{
-+ int ret;
-+ int i;
-+ struct rpisense_js *rpisense_js;
-+
-+ rpisense = rpisense_get_dev();
-+ rpisense_js = &rpisense->joystick;
-+
-+ INIT_WORK(&rpisense_js->keys_work_s, keys_work_fn);
-+
-+ rpisense_js->keys_dev = input_allocate_device();
-+ if (!rpisense_js->keys_dev) {
-+ dev_err(&pdev->dev, "Could not allocate input device.\n");
-+ return -ENOMEM;
-+ }
-+
-+ rpisense_js->keys_dev->evbit[0] = BIT_MASK(EV_KEY);
-+ for (i = 0; i < ARRAY_SIZE(keymap); i++) {
-+ set_bit(keymap[i],
-+ rpisense_js->keys_dev->keybit);
-+ }
-+
-+ rpisense_js->keys_dev->name = "Raspberry Pi Sense HAT Joystick";
-+ rpisense_js->keys_dev->phys = "rpi-sense-joy/input0";
-+ rpisense_js->keys_dev->id.bustype = BUS_I2C;
-+ rpisense_js->keys_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
-+ rpisense_js->keys_dev->keycode = keymap;
-+ rpisense_js->keys_dev->keycodesize = sizeof(unsigned char);
-+ rpisense_js->keys_dev->keycodemax = ARRAY_SIZE(keymap);
-+
-+ ret = input_register_device(rpisense_js->keys_dev);
-+ if (ret) {
-+ dev_err(&pdev->dev, "Could not register input device.\n");
-+ goto err_keys_alloc;
-+ }
-+
-+ ret = gpiod_direction_input(rpisense_js->keys_desc);
-+ if (ret) {
-+ dev_err(&pdev->dev, "Could not set keys-int direction.\n");
-+ goto err_keys_reg;
-+ }
-+
-+ rpisense_js->keys_irq = gpiod_to_irq(rpisense_js->keys_desc);
-+ if (rpisense_js->keys_irq < 0) {
-+ dev_err(&pdev->dev, "Could not determine keys-int IRQ.\n");
-+ ret = rpisense_js->keys_irq;
-+ goto err_keys_reg;
-+ }
-+
-+ ret = devm_request_irq(&pdev->dev, rpisense_js->keys_irq,
-+ keys_irq_handler, IRQF_TRIGGER_RISING,
-+ "keys", &pdev->dev);
-+ if (ret) {
-+ dev_err(&pdev->dev, "IRQ request failed.\n");
-+ goto err_keys_reg;
-+ }
-+ return 0;
-+err_keys_reg:
-+ input_unregister_device(rpisense_js->keys_dev);
-+err_keys_alloc:
-+ input_free_device(rpisense_js->keys_dev);
-+ return ret;
-+}
-+
-+static int rpisense_js_remove(struct platform_device *pdev)
-+{
-+ struct rpisense_js *rpisense_js = &rpisense->joystick;
-+
-+ input_unregister_device(rpisense_js->keys_dev);
-+ input_free_device(rpisense_js->keys_dev);
-+ return 0;
-+}
-+
-+#ifdef CONFIG_OF
-+static const struct of_device_id rpisense_js_id[] = {
-+ { .compatible = "rpi,rpi-sense-js" },
-+ { },
-+};
-+MODULE_DEVICE_TABLE(of, rpisense_js_id);
-+#endif
-+
-+static struct platform_device_id rpisense_js_device_id[] = {
-+ { .name = "rpi-sense-js" },
-+ { },
-+};
-+MODULE_DEVICE_TABLE(platform, rpisense_js_device_id);
-+
-+static struct platform_driver rpisense_js_driver = {
-+ .probe = rpisense_js_probe,
-+ .remove = rpisense_js_remove,
-+ .driver = {
-+ .name = "rpi-sense-js",
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+module_platform_driver(rpisense_js_driver);
-+
-+MODULE_DESCRIPTION("Raspberry Pi Sense HAT joystick driver");
-+MODULE_AUTHOR("Serge Schneider <serge@raspberrypi.org>");
-+MODULE_LICENSE("GPL");
---- a/drivers/mfd/Kconfig
-+++ b/drivers/mfd/Kconfig
-@@ -10,6 +10,14 @@ config MFD_CORE
- select IRQ_DOMAIN
- default n
-
-+config MFD_RPISENSE_CORE
-+ tristate "Raspberry Pi Sense HAT core functions"
-+ depends on I2C
-+ select MFD_CORE
-+ help
-+ This is the core driver for the Raspberry Pi Sense HAT. This provides
-+ the necessary functions to communicate with the hardware.
-+
- config MFD_CS5535
- tristate "AMD CS5535 and CS5536 southbridge core functions"
- select MFD_CORE
---- a/drivers/mfd/Makefile
-+++ b/drivers/mfd/Makefile
-@@ -194,3 +194,5 @@ intel-soc-pmic-objs := intel_soc_pmic_c
- intel-soc-pmic-$(CONFIG_INTEL_PMC_IPC) += intel_soc_pmic_bxtwc.o
- obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o
- obj-$(CONFIG_MFD_MT6397) += mt6397-core.o
-+
-+obj-$(CONFIG_MFD_RPISENSE_CORE) += rpisense-core.o
---- /dev/null
-+++ b/drivers/mfd/rpisense-core.c
-@@ -0,0 +1,157 @@
-+/*
-+ * Raspberry Pi Sense HAT core driver
-+ * http://raspberrypi.org
-+ *
-+ * Copyright (C) 2015 Raspberry Pi
-+ *
-+ * Author: Serge Schneider
-+ *
-+ * 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 driver is based on wm8350 implementation.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/moduleparam.h>
-+#include <linux/err.h>
-+#include <linux/init.h>
-+#include <linux/i2c.h>
-+#include <linux/platform_device.h>
-+#include <linux/mfd/rpisense/core.h>
-+#include <linux/slab.h>
-+
-+static struct rpisense *rpisense;
-+
-+static void rpisense_client_dev_register(struct rpisense *rpisense,
-+ const char *name,
-+ struct platform_device **pdev)
-+{
-+ int ret;
-+
-+ *pdev = platform_device_alloc(name, -1);
-+ if (*pdev == NULL) {
-+ dev_err(rpisense->dev, "Failed to allocate %s\n", name);
-+ return;
-+ }
-+
-+ (*pdev)->dev.parent = rpisense->dev;
-+ platform_set_drvdata(*pdev, rpisense);
-+ ret = platform_device_add(*pdev);
-+ if (ret != 0) {
-+ dev_err(rpisense->dev, "Failed to register %s: %d\n",
-+ name, ret);
-+ platform_device_put(*pdev);
-+ *pdev = NULL;
-+ }
-+}
-+
-+static int rpisense_probe(struct i2c_client *i2c,
-+ const struct i2c_device_id *id)
-+{
-+ int ret;
-+ struct rpisense_js *rpisense_js;
-+
-+ rpisense = devm_kzalloc(&i2c->dev, sizeof(struct rpisense), GFP_KERNEL);
-+ if (rpisense == NULL)
-+ return -ENOMEM;
-+
-+ i2c_set_clientdata(i2c, rpisense);
-+ rpisense->dev = &i2c->dev;
-+ rpisense->i2c_client = i2c;
-+
-+ ret = rpisense_reg_read(rpisense, RPISENSE_WAI);
-+ if (ret > 0) {
-+ if (ret != 's')
-+ return -EINVAL;
-+ } else {
-+ return ret;
-+ }
-+ ret = rpisense_reg_read(rpisense, RPISENSE_VER);
-+ if (ret < 0)
-+ return ret;
-+
-+ dev_info(rpisense->dev,
-+ "Raspberry Pi Sense HAT firmware version %i\n", ret);
-+
-+ rpisense_js = &rpisense->joystick;
-+ rpisense_js->keys_desc = devm_gpiod_get(&i2c->dev,
-+ "keys-int", GPIOD_IN);
-+ if (IS_ERR(rpisense_js->keys_desc)) {
-+ dev_warn(&i2c->dev, "Failed to get keys-int descriptor.\n");
-+ rpisense_js->keys_desc = gpio_to_desc(23);
-+ if (rpisense_js->keys_desc == NULL) {
-+ dev_err(&i2c->dev, "GPIO23 fallback failed.\n");
-+ return PTR_ERR(rpisense_js->keys_desc);
-+ }
-+ }
-+ rpisense_client_dev_register(rpisense, "rpi-sense-js",
-+ &(rpisense->joystick.pdev));
-+ rpisense_client_dev_register(rpisense, "rpi-sense-fb",
-+ &(rpisense->framebuffer.pdev));
-+
-+ return 0;
-+}
-+
-+static int rpisense_remove(struct i2c_client *i2c)
-+{
-+ struct rpisense *rpisense = i2c_get_clientdata(i2c);
-+
-+ platform_device_unregister(rpisense->joystick.pdev);
-+ return 0;
-+}
-+
-+struct rpisense *rpisense_get_dev(void)
-+{
-+ return rpisense;
-+}
-+EXPORT_SYMBOL_GPL(rpisense_get_dev);
-+
-+s32 rpisense_reg_read(struct rpisense *rpisense, int reg)
-+{
-+ int ret = i2c_smbus_read_byte_data(rpisense->i2c_client, reg);
-+
-+ if (ret < 0)
-+ dev_err(rpisense->dev, "Read from reg %d failed\n", reg);
-+ /* Due to the BCM270x I2C clock stretching bug, some values
-+ * may have MSB set. Clear it to avoid incorrect values.
-+ * */
-+ return ret & 0x7F;
-+}
-+EXPORT_SYMBOL_GPL(rpisense_reg_read);
-+
-+int rpisense_block_write(struct rpisense *rpisense, const char *buf, int count)
-+{
-+ int ret = i2c_master_send(rpisense->i2c_client, buf, count);
-+
-+ if (ret < 0)
-+ dev_err(rpisense->dev, "Block write failed\n");
-+ return ret;
-+}
-+EXPORT_SYMBOL_GPL(rpisense_block_write);
-+
-+static const struct i2c_device_id rpisense_i2c_id[] = {
-+ { "rpi-sense", 0 },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(i2c, rpisense_i2c_id);
-+
-+
-+static struct i2c_driver rpisense_driver = {
-+ .driver = {
-+ .name = "rpi-sense",
-+ .owner = THIS_MODULE,
-+ },
-+ .probe = rpisense_probe,
-+ .remove = rpisense_remove,
-+ .id_table = rpisense_i2c_id,
-+};
-+
-+module_i2c_driver(rpisense_driver);
-+
-+MODULE_DESCRIPTION("Raspberry Pi Sense HAT core driver");
-+MODULE_AUTHOR("Serge Schneider <serge@raspberrypi.org>");
-+MODULE_LICENSE("GPL");
-+
---- a/drivers/video/fbdev/Kconfig
-+++ b/drivers/video/fbdev/Kconfig
-@@ -2506,3 +2506,16 @@ config FB_SM712
- This driver is also available as a module. The module will be
- called sm712fb. If you want to compile it as a module, say M
- here and read <file:Documentation/kbuild/modules.txt>.
-+
-+config FB_RPISENSE
-+ tristate "Raspberry Pi Sense HAT framebuffer"
-+ depends on FB
-+ select MFD_RPISENSE_CORE
-+ select FB_SYS_FOPS
-+ select FB_SYS_FILLRECT
-+ select FB_SYS_COPYAREA
-+ select FB_SYS_IMAGEBLIT
-+ select FB_DEFERRED_IO
-+
-+ help
-+ This is the framebuffer driver for the Raspberry Pi Sense HAT
---- a/drivers/video/fbdev/Makefile
-+++ b/drivers/video/fbdev/Makefile
-@@ -150,6 +150,7 @@ obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o
- obj-$(CONFIG_FB_MXS) += mxsfb.o
- obj-$(CONFIG_FB_SSD1307) += ssd1307fb.o
- obj-$(CONFIG_FB_SIMPLE) += simplefb.o
-+obj-$(CONFIG_FB_RPISENSE) += rpisense-fb.o
-
- # the test framebuffer is last
- obj-$(CONFIG_FB_VIRTUAL) += vfb.o
---- /dev/null
-+++ b/drivers/video/fbdev/rpisense-fb.c
-@@ -0,0 +1,293 @@
-+/*
-+ * Raspberry Pi Sense HAT framebuffer driver
-+ * http://raspberrypi.org
-+ *
-+ * Copyright (C) 2015 Raspberry Pi
-+ *
-+ * Author: Serge Schneider
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License as published by the
-+ * Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version.
-+ *
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/errno.h>
-+#include <linux/string.h>
-+#include <linux/mm.h>
-+#include <linux/slab.h>
-+#include <linux/uaccess.h>
-+#include <linux/delay.h>
-+#include <linux/fb.h>
-+#include <linux/init.h>
-+
-+#include <linux/mfd/rpisense/framebuffer.h>
-+#include <linux/mfd/rpisense/core.h>
-+
-+static bool lowlight;
-+module_param(lowlight, bool, 0);
-+MODULE_PARM_DESC(lowlight, "Reduce LED matrix brightness to one third");
-+
-+static struct rpisense *rpisense;
-+
-+struct rpisense_fb_param {
-+ char __iomem *vmem;
-+ u8 *vmem_work;
-+ u32 vmemsize;
-+ u8 *gamma;
-+};
-+
-+static u8 gamma_default[32] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
-+ 0x02, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x07,
-+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0E, 0x0F, 0x11,
-+ 0x12, 0x14, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F,};
-+
-+static u8 gamma_low[32] = {0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02,
-+ 0x03, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06,
-+ 0x06, 0x07, 0x07, 0x08, 0x08, 0x09, 0x0A, 0x0A,};
-+
-+static u8 gamma_user[32];
-+
-+static struct rpisense_fb_param rpisense_fb_param = {
-+ .vmem = NULL,
-+ .vmemsize = 128,
-+ .gamma = gamma_default,
-+};
-+
-+static struct fb_deferred_io rpisense_fb_defio;
-+
-+static struct fb_fix_screeninfo rpisense_fb_fix = {
-+ .id = "RPi-Sense FB",
-+ .type = FB_TYPE_PACKED_PIXELS,
-+ .visual = FB_VISUAL_TRUECOLOR,
-+ .xpanstep = 0,
-+ .ypanstep = 0,
-+ .ywrapstep = 0,
-+ .accel = FB_ACCEL_NONE,
-+ .line_length = 16,
-+};
-+
-+static struct fb_var_screeninfo rpisense_fb_var = {
-+ .xres = 8,
-+ .yres = 8,
-+ .xres_virtual = 8,
-+ .yres_virtual = 8,
-+ .bits_per_pixel = 16,
-+ .red = {11, 5, 0},
-+ .green = {5, 6, 0},
-+ .blue = {0, 5, 0},
-+};
-+
-+static ssize_t rpisense_fb_write(struct fb_info *info,
-+ const char __user *buf, size_t count,
-+ loff_t *ppos)
-+{
-+ ssize_t res = fb_sys_write(info, buf, count, ppos);
-+
-+ schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
-+ return res;
-+}
-+
-+static void rpisense_fb_fillrect(struct fb_info *info,
-+ const struct fb_fillrect *rect)
-+{
-+ sys_fillrect(info, rect);
-+ schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
-+}
-+
-+static void rpisense_fb_copyarea(struct fb_info *info,
-+ const struct fb_copyarea *area)
-+{
-+ sys_copyarea(info, area);
-+ schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
-+}
-+
-+static void rpisense_fb_imageblit(struct fb_info *info,
-+ const struct fb_image *image)
-+{
-+ sys_imageblit(info, image);
-+ schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
-+}
-+
-+static void rpisense_fb_deferred_io(struct fb_info *info,
-+ struct list_head *pagelist)
-+{
-+ int i;
-+ int j;
-+ u8 *vmem_work = rpisense_fb_param.vmem_work;
-+ u16 *mem = (u16 *)rpisense_fb_param.vmem;
-+ u8 *gamma = rpisense_fb_param.gamma;
-+
-+ vmem_work[0] = 0;
-+ for (j = 0; j < 8; j++) {
-+ for (i = 0; i < 8; i++) {
-+ vmem_work[(j * 24) + i + 1] =
-+ gamma[(mem[(j * 8) + i] >> 11) & 0x1F];
-+ vmem_work[(j * 24) + (i + 8) + 1] =
-+ gamma[(mem[(j * 8) + i] >> 6) & 0x1F];
-+ vmem_work[(j * 24) + (i + 16) + 1] =
-+ gamma[(mem[(j * 8) + i]) & 0x1F];
-+ }
-+ }
-+ rpisense_block_write(rpisense, vmem_work, 193);
-+}
-+
-+static struct fb_deferred_io rpisense_fb_defio = {
-+ .delay = HZ/100,
-+ .deferred_io = rpisense_fb_deferred_io,
-+};
-+
-+static int rpisense_fb_ioctl(struct fb_info *info, unsigned int cmd,
-+ unsigned long arg)
-+{
-+ switch (cmd) {
-+ case SENSEFB_FBIOGET_GAMMA:
-+ if (copy_to_user((void __user *) arg, rpisense_fb_param.gamma,
-+ sizeof(u8[32])))
-+ return -EFAULT;
-+ return 0;
-+ case SENSEFB_FBIOSET_GAMMA:
-+ if (copy_from_user(gamma_user, (void __user *)arg,
-+ sizeof(u8[32])))
-+ return -EFAULT;
-+ rpisense_fb_param.gamma = gamma_user;
-+ schedule_delayed_work(&info->deferred_work,
-+ rpisense_fb_defio.delay);
-+ return 0;
-+ case SENSEFB_FBIORESET_GAMMA:
-+ switch (arg) {
-+ case 0:
-+ rpisense_fb_param.gamma = gamma_default;
-+ break;
-+ case 1:
-+ rpisense_fb_param.gamma = gamma_low;
-+ break;
-+ case 2:
-+ rpisense_fb_param.gamma = gamma_user;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ schedule_delayed_work(&info->deferred_work,
-+ rpisense_fb_defio.delay);
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ return 0;
-+}
-+
-+static struct fb_ops rpisense_fb_ops = {
-+ .owner = THIS_MODULE,
-+ .fb_read = fb_sys_read,
-+ .fb_write = rpisense_fb_write,
-+ .fb_fillrect = rpisense_fb_fillrect,
-+ .fb_copyarea = rpisense_fb_copyarea,
-+ .fb_imageblit = rpisense_fb_imageblit,
-+ .fb_ioctl = rpisense_fb_ioctl,
-+};
-+
-+static int rpisense_fb_probe(struct platform_device *pdev)
-+{
-+ struct fb_info *info;
-+ int ret = -ENOMEM;
-+ struct rpisense_fb *rpisense_fb;
-+
-+ rpisense = rpisense_get_dev();
-+ rpisense_fb = &rpisense->framebuffer;
-+
-+ rpisense_fb_param.vmem = vzalloc(rpisense_fb_param.vmemsize);
-+ if (!rpisense_fb_param.vmem)
-+ return ret;
-+
-+ rpisense_fb_param.vmem_work = devm_kmalloc(&pdev->dev, 193, GFP_KERNEL);
-+ if (!rpisense_fb_param.vmem_work)
-+ goto err_malloc;
-+
-+ info = framebuffer_alloc(0, &pdev->dev);
-+ if (!info) {
-+ dev_err(&pdev->dev, "Could not allocate framebuffer.\n");
-+ goto err_malloc;
-+ }
-+ rpisense_fb->info = info;
-+
-+ rpisense_fb_fix.smem_start = (unsigned long)rpisense_fb_param.vmem;
-+ rpisense_fb_fix.smem_len = rpisense_fb_param.vmemsize;
-+
-+ info->fbops = &rpisense_fb_ops;
-+ info->fix = rpisense_fb_fix;
-+ info->var = rpisense_fb_var;
-+ info->fbdefio = &rpisense_fb_defio;
-+ info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB;
-+ info->screen_base = rpisense_fb_param.vmem;
-+ info->screen_size = rpisense_fb_param.vmemsize;
-+
-+ if (lowlight)
-+ rpisense_fb_param.gamma = gamma_low;
-+
-+ fb_deferred_io_init(info);
-+
-+ ret = register_framebuffer(info);
-+ if (ret < 0) {
-+ dev_err(&pdev->dev, "Could not register framebuffer.\n");
-+ goto err_fballoc;
-+ }
-+
-+ fb_info(info, "%s frame buffer device\n", info->fix.id);
-+ schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
-+ return 0;
-+err_fballoc:
-+ framebuffer_release(info);
-+err_malloc:
-+ vfree(rpisense_fb_param.vmem);
-+ return ret;
-+}
-+
-+static int rpisense_fb_remove(struct platform_device *pdev)
-+{
-+ struct rpisense_fb *rpisense_fb = &rpisense->framebuffer;
-+ struct fb_info *info = rpisense_fb->info;
-+
-+ if (info) {
-+ unregister_framebuffer(info);
-+ fb_deferred_io_cleanup(info);
-+ framebuffer_release(info);
-+ vfree(rpisense_fb_param.vmem);
-+ }
-+
-+ return 0;
-+}
-+
-+#ifdef CONFIG_OF
-+static const struct of_device_id rpisense_fb_id[] = {
-+ { .compatible = "rpi,rpi-sense-fb" },
-+ { },
-+};
-+MODULE_DEVICE_TABLE(of, rpisense_fb_id);
-+#endif
-+
-+static struct platform_device_id rpisense_fb_device_id[] = {
-+ { .name = "rpi-sense-fb" },
-+ { },
-+};
-+MODULE_DEVICE_TABLE(platform, rpisense_fb_device_id);
-+
-+static struct platform_driver rpisense_fb_driver = {
-+ .probe = rpisense_fb_probe,
-+ .remove = rpisense_fb_remove,
-+ .driver = {
-+ .name = "rpi-sense-fb",
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+module_platform_driver(rpisense_fb_driver);
-+
-+MODULE_DESCRIPTION("Raspberry Pi Sense HAT framebuffer driver");
-+MODULE_AUTHOR("Serge Schneider <serge@raspberrypi.org>");
-+MODULE_LICENSE("GPL");
-+
---- /dev/null
-+++ b/include/linux/mfd/rpisense/core.h
-@@ -0,0 +1,47 @@
-+/*
-+ * Raspberry Pi Sense HAT core driver
-+ * http://raspberrypi.org
-+ *
-+ * Copyright (C) 2015 Raspberry Pi
-+ *
-+ * Author: Serge Schneider
-+ *
-+ * 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.
-+ *
-+ */
-+
-+#ifndef __LINUX_MFD_RPISENSE_CORE_H_
-+#define __LINUX_MFD_RPISENSE_CORE_H_
-+
-+#include <linux/mfd/rpisense/joystick.h>
-+#include <linux/mfd/rpisense/framebuffer.h>
-+
-+/*
-+ * Register values.
-+ */
-+#define RPISENSE_FB 0x00
-+#define RPISENSE_WAI 0xF0
-+#define RPISENSE_VER 0xF1
-+#define RPISENSE_KEYS 0xF2
-+#define RPISENSE_EE_WP 0xF3
-+
-+#define RPISENSE_ID 's'
-+
-+struct rpisense {
-+ struct device *dev;
-+ struct i2c_client *i2c_client;
-+
-+ /* Client devices */
-+ struct rpisense_js joystick;
-+ struct rpisense_fb framebuffer;
-+};
-+
-+struct rpisense *rpisense_get_dev(void);
-+s32 rpisense_reg_read(struct rpisense *rpisense, int reg);
-+int rpisense_reg_write(struct rpisense *rpisense, int reg, u16 val);
-+int rpisense_block_write(struct rpisense *rpisense, const char *buf, int count);
-+
-+#endif
---- /dev/null
-+++ b/include/linux/mfd/rpisense/framebuffer.h
-@@ -0,0 +1,32 @@
-+/*
-+ * Raspberry Pi Sense HAT framebuffer driver
-+ * http://raspberrypi.org
-+ *
-+ * Copyright (C) 2015 Raspberry Pi
-+ *
-+ * Author: Serge Schneider
-+ *
-+ * 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.
-+ *
-+ */
-+
-+#ifndef __LINUX_RPISENSE_FB_H_
-+#define __LINUX_RPISENSE_FB_H_
-+
-+#define SENSEFB_FBIO_IOC_MAGIC 0xF1
-+
-+#define SENSEFB_FBIOGET_GAMMA _IO(SENSEFB_FBIO_IOC_MAGIC, 0)
-+#define SENSEFB_FBIOSET_GAMMA _IO(SENSEFB_FBIO_IOC_MAGIC, 1)
-+#define SENSEFB_FBIORESET_GAMMA _IO(SENSEFB_FBIO_IOC_MAGIC, 2)
-+
-+struct rpisense;
-+
-+struct rpisense_fb {
-+ struct platform_device *pdev;
-+ struct fb_info *info;
-+};
-+
-+#endif
---- /dev/null
-+++ b/include/linux/mfd/rpisense/joystick.h
-@@ -0,0 +1,35 @@
-+/*
-+ * Raspberry Pi Sense HAT joystick driver
-+ * http://raspberrypi.org
-+ *
-+ * Copyright (C) 2015 Raspberry Pi
-+ *
-+ * Author: Serge Schneider
-+ *
-+ * 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.
-+ *
-+ */
-+
-+#ifndef __LINUX_RPISENSE_JOYSTICK_H_
-+#define __LINUX_RPISENSE_JOYSTICK_H_
-+
-+#include <linux/input.h>
-+#include <linux/interrupt.h>
-+#include <linux/gpio/consumer.h>
-+#include <linux/platform_device.h>
-+
-+struct rpisense;
-+
-+struct rpisense_js {
-+ struct platform_device *pdev;
-+ struct input_dev *keys_dev;
-+ struct gpio_desc *keys_desc;
-+ struct work_struct keys_work_s;
-+ int keys_irq;
-+};
-+
-+
-+#endif
diff --git a/target/linux/brcm2708/patches-4.4/0085-RaspiDAC3-support.patch b/target/linux/brcm2708/patches-4.4/0085-RaspiDAC3-support.patch
deleted file mode 100644
index f161a53394..0000000000
--- a/target/linux/brcm2708/patches-4.4/0085-RaspiDAC3-support.patch
+++ /dev/null
@@ -1,243 +0,0 @@
-From c86a74aaff9bc42b3cb04881b3aaf7f822edda04 Mon Sep 17 00:00:00 2001
-From: Jan Grulich <jan@grulich.eu>
-Date: Mon, 24 Aug 2015 16:03:47 +0100
-Subject: [PATCH 085/170] RaspiDAC3 support
-
-Signed-off-by: Jan Grulich <jan@grulich.eu>
-
-config: fix RaspiDAC Rev.3x dependencies
-
-Change depends to SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
-like the other I2S soundcard drivers.
-
-Signed-off-by: Matthias Reichl <hias@horus.com>
----
- sound/soc/bcm/Kconfig | 8 ++
- sound/soc/bcm/Makefile | 2 +
- sound/soc/bcm/raspidac3.c | 191 ++++++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 201 insertions(+)
- create mode 100644 sound/soc/bcm/raspidac3.c
-
---- a/sound/soc/bcm/Kconfig
-+++ b/sound/soc/bcm/Kconfig
-@@ -56,3 +56,11 @@ config SND_BCM2708_SOC_IQAUDIO_DAC
- select SND_SOC_PCM512x_I2C
- help
- Say Y or M if you want to add support for IQaudIO-DAC.
-+
-+config SND_BCM2708_SOC_RASPIDAC3
-+ tristate "Support for RaspiDAC Rev.3x"
-+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
-+ select SND_SOC_PCM512x_I2C
-+ select SND_SOC_TPA6130A2
-+ help
-+ Say Y or M if you want to add support for RaspiDAC Rev.3x.
---- a/sound/soc/bcm/Makefile
-+++ b/sound/soc/bcm/Makefile
-@@ -11,6 +11,7 @@ snd-soc-hifiberry-amp-objs := hifiberry_
- snd-soc-rpi-dac-objs := rpi-dac.o
- snd-soc-rpi-proto-objs := rpi-proto.o
- snd-soc-iqaudio-dac-objs := iqaudio-dac.o
-+snd-soc-raspidac3-objs := raspidac3.o
-
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
-@@ -19,3 +20,4 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_A
- obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o
- obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
- obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
-+obj-$(CONFIG_SND_BCM2708_SOC_RASPIDAC3) += snd-soc-raspidac3.o
---- /dev/null
-+++ b/sound/soc/bcm/raspidac3.c
-@@ -0,0 +1,191 @@
-+/*
-+ * ASoC Driver for RaspiDAC v3
-+ *
-+ * Author: Jan Grulich <jan@grulich.eu>
-+ * Copyright 2015
-+ * based on code by Daniel Matuschek <daniel@hifiberry.com>
-+ * based on code by Florian Meier <florian.meier@koalo.de>
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+
-+#include <sound/core.h>
-+#include <sound/pcm.h>
-+#include <sound/pcm_params.h>
-+#include <sound/soc.h>
-+#include <sound/jack.h>
-+#include <sound/soc-dapm.h>
-+
-+#include "../codecs/pcm512x.h"
-+#include "../codecs/tpa6130a2.h"
-+
-+/* sound card init */
-+static int snd_rpi_raspidac3_init(struct snd_soc_pcm_runtime *rtd)
-+{
-+ int ret;
-+ struct snd_soc_card *card = rtd->card;
-+ struct snd_soc_codec *codec = rtd->codec;
-+ snd_soc_update_bits(codec, PCM512x_GPIO_EN, 0x08, 0x08);
-+ snd_soc_update_bits(codec, PCM512x_GPIO_OUTPUT_4, 0xf, 0x02);
-+ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08,0x00);
-+
-+ ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207);
-+ if (ret < 0)
-+ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
-+ else {
-+ struct snd_kcontrol *kctl;
-+
-+ ret = tpa6130a2_add_controls(codec);
-+ if (ret < 0)
-+ dev_warn(card->dev, "Failed to add TPA6130A2 controls: %d\n",
-+ ret);
-+ ret = snd_soc_limit_volume(card,
-+ "TPA6130A2 Headphone Playback Volume",
-+ 54);
-+ if (ret < 0)
-+ dev_warn(card->dev, "Failed to set TPA6130A2 volume limit: %d\n",
-+ ret);
-+ kctl = snd_soc_card_get_kcontrol(card,
-+ "TPA6130A2 Headphone Playback Volume");
-+ if (kctl) {
-+ strcpy(kctl->id.name, "Headphones Playback Volume");
-+ /* disable the volume dB scale so alsamixer works */
-+ kctl->vd[0].access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
-+ }
-+
-+ kctl = snd_soc_card_get_kcontrol(card,
-+ "TPA6130A2 Headphone Playback Switch");
-+ if (kctl)
-+ strcpy(kctl->id.name, "Headphones Playback Switch");
-+ }
-+
-+ return 0;
-+}
-+
-+/* set hw parameters */
-+static int snd_rpi_raspidac3_hw_params(struct snd_pcm_substream *substream,
-+ struct snd_pcm_hw_params *params)
-+{
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-+
-+ unsigned int sample_bits =
-+ snd_pcm_format_physical_width(params_format(params));
-+
-+ return snd_soc_dai_set_bclk_ratio(cpu_dai, sample_bits * 2);
-+}
-+
-+/* startup */
-+static int snd_rpi_raspidac3_startup(struct snd_pcm_substream *substream) {
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ struct snd_soc_codec *codec = rtd->codec;
-+ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08,0x08);
-+ tpa6130a2_stereo_enable(codec, 1);
-+ return 0;
-+}
-+
-+/* shutdown */
-+static void snd_rpi_raspidac3_shutdown(struct snd_pcm_substream *substream) {
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ struct snd_soc_codec *codec = rtd->codec;
-+ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08,0x00);
-+ tpa6130a2_stereo_enable(codec, 0);
-+}
-+
-+/* machine stream operations */
-+static struct snd_soc_ops snd_rpi_raspidac3_ops = {
-+ .hw_params = snd_rpi_raspidac3_hw_params,
-+ .startup = snd_rpi_raspidac3_startup,
-+ .shutdown = snd_rpi_raspidac3_shutdown,
-+};
-+
-+/* interface setup */
-+static struct snd_soc_dai_link snd_rpi_raspidac3_dai[] = {
-+{
-+ .name = "RaspiDAC Rev.3x",
-+ .stream_name = "RaspiDAC HiFi",
-+ .cpu_dai_name = "bcm2708-i2s.0",
-+ .codec_dai_name = "pcm512x-hifi",
-+ .platform_name = "bcm2708-i2s.0",
-+ .codec_name = "pcm512x.1-004c",
-+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-+ SND_SOC_DAIFMT_CBS_CFS,
-+ .ops = &snd_rpi_raspidac3_ops,
-+ .init = snd_rpi_raspidac3_init,
-+},
-+};
-+
-+/* audio machine driver */
-+static struct snd_soc_card snd_rpi_raspidac3 = {
-+ .name = "RaspiDAC Rev.3x HiFi Audio Card",
-+ .dai_link = snd_rpi_raspidac3_dai,
-+ .num_links = ARRAY_SIZE(snd_rpi_raspidac3_dai),
-+};
-+
-+/* sound card test */
-+static int snd_rpi_raspidac3_probe(struct platform_device *pdev)
-+{
-+ int ret = 0;
-+
-+ snd_rpi_raspidac3.dev = &pdev->dev;
-+
-+ if (pdev->dev.of_node) {
-+ struct device_node *i2s_node;
-+ struct snd_soc_dai_link *dai = &snd_rpi_raspidac3_dai[0];
-+ i2s_node = of_parse_phandle(pdev->dev.of_node,
-+ "i2s-controller", 0);
-+
-+ if (i2s_node) {
-+ dai->cpu_dai_name = NULL;
-+ dai->cpu_of_node = i2s_node;
-+ dai->platform_name = NULL;
-+ dai->platform_of_node = i2s_node;
-+ }
-+ }
-+
-+ ret = snd_soc_register_card(&snd_rpi_raspidac3);
-+ if (ret)
-+ dev_err(&pdev->dev,
-+ "snd_soc_register_card() failed: %d\n", ret);
-+
-+ return ret;
-+}
-+
-+/* sound card disconnect */
-+static int snd_rpi_raspidac3_remove(struct platform_device *pdev)
-+{
-+ return snd_soc_unregister_card(&snd_rpi_raspidac3);
-+}
-+
-+static const struct of_device_id raspidac3_of_match[] = {
-+ { .compatible = "jg,raspidacv3", },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(of, raspidac3_of_match);
-+
-+/* sound card platform driver */
-+static struct platform_driver snd_rpi_raspidac3_driver = {
-+ .driver = {
-+ .name = "snd-rpi-raspidac3",
-+ .owner = THIS_MODULE,
-+ .of_match_table = raspidac3_of_match,
-+ },
-+ .probe = snd_rpi_raspidac3_probe,
-+ .remove = snd_rpi_raspidac3_remove,
-+};
-+
-+module_platform_driver(snd_rpi_raspidac3_driver);
-+
-+MODULE_AUTHOR("Jan Grulich <jan@grulich.eu>");
-+MODULE_DESCRIPTION("ASoC Driver for RaspiDAC Rev.3x");
-+MODULE_LICENSE("GPL v2");
diff --git a/target/linux/brcm2708/patches-4.4/0085-tpa6130a2-Add-headphone-switch-control.patch b/target/linux/brcm2708/patches-4.4/0085-tpa6130a2-Add-headphone-switch-control.patch
new file mode 100644
index 0000000000..22f90a2043
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0085-tpa6130a2-Add-headphone-switch-control.patch
@@ -0,0 +1,91 @@
+From 669d4b324d47078cffaa557b8fe7ab13ff484cbe Mon Sep 17 00:00:00 2001
+From: Jan Grulich <jan@grulich.eu>
+Date: Mon, 24 Aug 2015 16:02:34 +0100
+Subject: [PATCH 085/381] tpa6130a2: Add headphone switch control
+
+Signed-off-by: Jan Grulich <jan@grulich.eu>
+---
+ sound/soc/codecs/tpa6130a2.c | 29 ++++++++++++++++++++++++++---
+ 1 file changed, 26 insertions(+), 3 deletions(-)
+
+--- a/sound/soc/codecs/tpa6130a2.c
++++ b/sound/soc/codecs/tpa6130a2.c
+@@ -4,6 +4,7 @@
+ * Copyright (C) Nokia Corporation
+ *
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
++ * Modified: Jan Grulich <jan@grulich.eu>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+@@ -52,6 +53,8 @@ struct tpa6130a2_data {
+ enum tpa_model id;
+ };
+
++static void tpa6130a2_channel_enable(u8 channel, int enable);
++
+ static int tpa6130a2_i2c_read(int reg)
+ {
+ struct tpa6130a2_data *data;
+@@ -189,7 +192,7 @@ exit:
+ }
+
+ static int tpa6130a2_get_volsw(struct snd_kcontrol *kcontrol,
+- struct snd_ctl_elem_value *ucontrol)
++ struct snd_ctl_elem_value *ucontrol)
+ {
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+@@ -218,7 +221,7 @@ static int tpa6130a2_get_volsw(struct sn
+ }
+
+ static int tpa6130a2_put_volsw(struct snd_kcontrol *kcontrol,
+- struct snd_ctl_elem_value *ucontrol)
++ struct snd_ctl_elem_value *ucontrol)
+ {
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+@@ -255,8 +258,22 @@ static int tpa6130a2_put_volsw(struct sn
+ return 1;
+ }
+
++static int tpa6130a2_put_hp_sw(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ int enable = ucontrol->value.integer.value[0];
++ unsigned int state;
++
++ state = (tpa6130a2_read(TPA6130A2_REG_VOL_MUTE) & 0x80) == 0;
++ if (state == enable)
++ return 0; /* No change */
++
++ tpa6130a2_channel_enable(TPA6130A2_HP_EN_R | TPA6130A2_HP_EN_L, enable);
++ return 1; /* Changed */
++}
++
+ /*
+- * TPA6130 volume. From -59.5 to 4 dB with increasing step size when going
++ * TPA6130 volume. From -59.5 to +4.0 dB with increasing step size when going
+ * down in gain.
+ */
+ static const DECLARE_TLV_DB_RANGE(tpa6130_tlv,
+@@ -277,6 +294,9 @@ static const struct snd_kcontrol_new tpa
+ TPA6130A2_REG_VOL_MUTE, 0, 0x3f, 0,
+ tpa6130a2_get_volsw, tpa6130a2_put_volsw,
+ tpa6130_tlv),
++ SOC_SINGLE_EXT("TPA6130A2 Headphone Playback Switch",
++ TPA6130A2_REG_VOL_MUTE, 7, 1, 1,
++ tpa6130a2_get_volsw, tpa6130a2_put_hp_sw),
+ };
+
+ static const DECLARE_TLV_DB_RANGE(tpa6140_tlv,
+@@ -290,6 +310,9 @@ static const struct snd_kcontrol_new tpa
+ TPA6130A2_REG_VOL_MUTE, 1, 0x1f, 0,
+ tpa6130a2_get_volsw, tpa6130a2_put_volsw,
+ tpa6140_tlv),
++ SOC_SINGLE_EXT("TPA6140A2 Headphone Playback Switch",
++ TPA6130A2_REG_VOL_MUTE, 7, 1, 1,
++ tpa6130a2_get_volsw, tpa6130a2_put_hp_sw),
+ };
+
+ /*
diff --git a/target/linux/brcm2708/patches-4.4/0086-irq-bcm2835-Fix-building-with-2708.patch b/target/linux/brcm2708/patches-4.4/0086-irq-bcm2835-Fix-building-with-2708.patch
new file mode 100644
index 0000000000..3b39f38275
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0086-irq-bcm2835-Fix-building-with-2708.patch
@@ -0,0 +1,28 @@
+From 5f1f5e7db749eeaa307b0ba384e29d99b10e3290 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Mon, 28 Sep 2015 23:38:59 +0100
+Subject: [PATCH 086/381] irq-bcm2835: Fix building with 2708
+
+---
+ drivers/irqchip/irq-bcm2835.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/irqchip/irq-bcm2835.c
++++ b/drivers/irqchip/irq-bcm2835.c
+@@ -82,6 +82,7 @@
+ #define NR_BANKS 3
+ #define IRQS_PER_BANK 32
+ #define NUMBER_IRQS MAKE_HWIRQ(NR_BANKS, 0)
++#undef FIQ_START
+ #define FIQ_START (NR_IRQS_BANK0 + MAKE_HWIRQ(NR_BANKS - 1, 0))
+
+ static const int reg_pending[] __initconst = { 0x00, 0x04, 0x08 };
+@@ -256,7 +257,7 @@ static int __init armctrl_of_init(struct
+ MAKE_HWIRQ(b, i) + NUMBER_IRQS);
+ BUG_ON(irq <= 0);
+ irq_set_chip(irq, &armctrl_chip);
+- set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
++ irq_set_probe(irq);
+ }
+ }
+ init_FIQ(FIQ_START);
diff --git a/target/linux/brcm2708/patches-4.4/0086-tpa6130a2-Add-headphone-switch-control.patch b/target/linux/brcm2708/patches-4.4/0086-tpa6130a2-Add-headphone-switch-control.patch
deleted file mode 100644
index 0daaee22c6..0000000000
--- a/target/linux/brcm2708/patches-4.4/0086-tpa6130a2-Add-headphone-switch-control.patch
+++ /dev/null
@@ -1,91 +0,0 @@
-From 2d340e2fbbc9f4735b798601a43ae9f0f4cc5742 Mon Sep 17 00:00:00 2001
-From: Jan Grulich <jan@grulich.eu>
-Date: Mon, 24 Aug 2015 16:02:34 +0100
-Subject: [PATCH 086/170] tpa6130a2: Add headphone switch control
-
-Signed-off-by: Jan Grulich <jan@grulich.eu>
----
- sound/soc/codecs/tpa6130a2.c | 29 ++++++++++++++++++++++++++---
- 1 file changed, 26 insertions(+), 3 deletions(-)
-
---- a/sound/soc/codecs/tpa6130a2.c
-+++ b/sound/soc/codecs/tpa6130a2.c
-@@ -4,6 +4,7 @@
- * Copyright (C) Nokia Corporation
- *
- * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
-+ * Modified: Jan Grulich <jan@grulich.eu>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
-@@ -52,6 +53,8 @@ struct tpa6130a2_data {
- enum tpa_model id;
- };
-
-+static void tpa6130a2_channel_enable(u8 channel, int enable);
-+
- static int tpa6130a2_i2c_read(int reg)
- {
- struct tpa6130a2_data *data;
-@@ -189,7 +192,7 @@ exit:
- }
-
- static int tpa6130a2_get_volsw(struct snd_kcontrol *kcontrol,
-- struct snd_ctl_elem_value *ucontrol)
-+ struct snd_ctl_elem_value *ucontrol)
- {
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
-@@ -218,7 +221,7 @@ static int tpa6130a2_get_volsw(struct sn
- }
-
- static int tpa6130a2_put_volsw(struct snd_kcontrol *kcontrol,
-- struct snd_ctl_elem_value *ucontrol)
-+ struct snd_ctl_elem_value *ucontrol)
- {
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
-@@ -255,8 +258,22 @@ static int tpa6130a2_put_volsw(struct sn
- return 1;
- }
-
-+static int tpa6130a2_put_hp_sw(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_value *ucontrol)
-+{
-+ int enable = ucontrol->value.integer.value[0];
-+ unsigned int state;
-+
-+ state = (tpa6130a2_read(TPA6130A2_REG_VOL_MUTE) & 0x80) == 0;
-+ if (state == enable)
-+ return 0; /* No change */
-+
-+ tpa6130a2_channel_enable(TPA6130A2_HP_EN_R | TPA6130A2_HP_EN_L, enable);
-+ return 1; /* Changed */
-+}
-+
- /*
-- * TPA6130 volume. From -59.5 to 4 dB with increasing step size when going
-+ * TPA6130 volume. From -59.5 to +4.0 dB with increasing step size when going
- * down in gain.
- */
- static const DECLARE_TLV_DB_RANGE(tpa6130_tlv,
-@@ -277,6 +294,9 @@ static const struct snd_kcontrol_new tpa
- TPA6130A2_REG_VOL_MUTE, 0, 0x3f, 0,
- tpa6130a2_get_volsw, tpa6130a2_put_volsw,
- tpa6130_tlv),
-+ SOC_SINGLE_EXT("TPA6130A2 Headphone Playback Switch",
-+ TPA6130A2_REG_VOL_MUTE, 7, 1, 1,
-+ tpa6130a2_get_volsw, tpa6130a2_put_hp_sw),
- };
-
- static const DECLARE_TLV_DB_RANGE(tpa6140_tlv,
-@@ -290,6 +310,9 @@ static const struct snd_kcontrol_new tpa
- TPA6130A2_REG_VOL_MUTE, 1, 0x1f, 0,
- tpa6130a2_get_volsw, tpa6130a2_put_volsw,
- tpa6140_tlv),
-+ SOC_SINGLE_EXT("TPA6140A2 Headphone Playback Switch",
-+ TPA6130A2_REG_VOL_MUTE, 7, 1, 1,
-+ tpa6130a2_get_volsw, tpa6130a2_put_hp_sw),
- };
-
- /*
diff --git a/target/linux/brcm2708/patches-4.4/0087-irq-bcm2835-Fix-building-with-2708.patch b/target/linux/brcm2708/patches-4.4/0087-irq-bcm2835-Fix-building-with-2708.patch
deleted file mode 100644
index 5c7c661363..0000000000
--- a/target/linux/brcm2708/patches-4.4/0087-irq-bcm2835-Fix-building-with-2708.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From 6fc9d40bec5dbcf3ae8b52ab6850ed0b18193c82 Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Mon, 28 Sep 2015 23:38:59 +0100
-Subject: [PATCH 087/170] irq-bcm2835: Fix building with 2708
-
----
- drivers/irqchip/irq-bcm2835.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/drivers/irqchip/irq-bcm2835.c
-+++ b/drivers/irqchip/irq-bcm2835.c
-@@ -82,6 +82,7 @@
- #define NR_BANKS 3
- #define IRQS_PER_BANK 32
- #define NUMBER_IRQS MAKE_HWIRQ(NR_BANKS, 0)
-+#undef FIQ_START
- #define FIQ_START (NR_IRQS_BANK0 + MAKE_HWIRQ(NR_BANKS - 1, 0))
-
- static const int reg_pending[] __initconst = { 0x00, 0x04, 0x08 };
-@@ -256,7 +257,7 @@ static int __init armctrl_of_init(struct
- MAKE_HWIRQ(b, i) + NUMBER_IRQS);
- BUG_ON(irq <= 0);
- irq_set_chip(irq, &armctrl_chip);
-- set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
-+ irq_set_probe(irq);
- }
- }
- init_FIQ(FIQ_START);
diff --git a/target/linux/brcm2708/patches-4.4/0087-rpi_display-add-backlight-driver-and-overlay.patch b/target/linux/brcm2708/patches-4.4/0087-rpi_display-add-backlight-driver-and-overlay.patch
new file mode 100644
index 0000000000..9305a93a24
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0087-rpi_display-add-backlight-driver-and-overlay.patch
@@ -0,0 +1,250 @@
+From bfcb98a5f383cd1cdd08156f8f7267447ab1b7cd Mon Sep 17 00:00:00 2001
+From: P33M <P33M@github.com>
+Date: Wed, 21 Oct 2015 14:55:21 +0100
+Subject: [PATCH 087/381] rpi_display: add backlight driver and overlay
+
+Add a mailbox-driven backlight controller for the Raspberry Pi DSI
+touchscreen display. Requires updated GPU firmware to recognise the
+mailbox request.
+
+Signed-off-by: Gordon Hollingworth <gordon@raspberrypi.org>
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 6 ++
+ .../boot/dts/overlays/rpi-backlight-overlay.dts | 21 ++++
+ arch/arm/configs/bcm2709_defconfig | 1 +
+ arch/arm/configs/bcmrpi_defconfig | 1 +
+ drivers/video/backlight/Kconfig | 6 ++
+ drivers/video/backlight/Makefile | 1 +
+ drivers/video/backlight/rpi_backlight.c | 119 +++++++++++++++++++++
+ include/soc/bcm2835/raspberrypi-firmware.h | 1 +
+ 9 files changed, 157 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/rpi-backlight-overlay.dts
+ create mode 100644 drivers/video/backlight/rpi_backlight.c
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -38,6 +38,7 @@ dtb-$(RPI_DT_OVERLAYS) += pps-gpio-overl
+ dtb-$(RPI_DT_OVERLAYS) += pwm-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += pwm-2chan-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += raspidac3-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += rpi-backlight-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += rpi-dac-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += rpi-display-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += rpi-ft5406-overlay.dtb
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -462,6 +462,12 @@ Load: dtoverlay=raspidac3
+ Params: <None>
+
+
++Name: rpi-backlight
++Info: Raspberry Pi official display backlight driver
++Load: dtoverlay=rpi-backlight
++Params: <None>
++
++
+ Name: rpi-dac
+ Info: Configures the RPi DAC audio card
+ Load: dtoverlay=rpi-dac
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/rpi-backlight-overlay.dts
+@@ -0,0 +1,21 @@
++/*
++ * Devicetree overlay for mailbox-driven Raspberry Pi DSI Display
++ * backlight controller
++ */
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target-path = "/";
++ __overlay__ {
++ rpi_backlight: rpi_backlight {
++ compatible = "raspberrypi,rpi-backlight";
++ firmware = <&firmware>;
++ status = "okay";
++ };
++ };
++ };
++};
+--- a/arch/arm/configs/bcm2709_defconfig
++++ b/arch/arm/configs/bcm2709_defconfig
+@@ -808,6 +808,7 @@ CONFIG_FB_UDL=m
+ CONFIG_FB_SSD1307=m
+ CONFIG_FB_RPISENSE=m
+ # CONFIG_BACKLIGHT_GENERIC is not set
++CONFIG_BACKLIGHT_RPI=m
+ CONFIG_BACKLIGHT_GPIO=m
+ CONFIG_FRAMEBUFFER_CONSOLE=y
+ CONFIG_LOGO=y
+--- a/arch/arm/configs/bcmrpi_defconfig
++++ b/arch/arm/configs/bcmrpi_defconfig
+@@ -801,6 +801,7 @@ CONFIG_FB_UDL=m
+ CONFIG_FB_SSD1307=m
+ CONFIG_FB_RPISENSE=m
+ # CONFIG_BACKLIGHT_GENERIC is not set
++CONFIG_BACKLIGHT_RPI=m
+ CONFIG_BACKLIGHT_GPIO=m
+ CONFIG_FRAMEBUFFER_CONSOLE=y
+ CONFIG_LOGO=y
+--- a/drivers/video/backlight/Kconfig
++++ b/drivers/video/backlight/Kconfig
+@@ -265,6 +265,12 @@ config BACKLIGHT_PWM
+ If you have a LCD backlight adjustable by PWM, say Y to enable
+ this driver.
+
++config BACKLIGHT_RPI
++ tristate "Raspberry Pi display firmware driven backlight"
++ help
++ If you have the Raspberry Pi DSI touchscreen display, say Y to
++ enable the mailbox-controlled backlight driver.
++
+ config BACKLIGHT_DA903X
+ tristate "Backlight Driver for DA9030/DA9034 using WLED"
+ depends on PMIC_DA903X
+--- a/drivers/video/backlight/Makefile
++++ b/drivers/video/backlight/Makefile
+@@ -50,6 +50,7 @@ obj-$(CONFIG_BACKLIGHT_PANDORA) += pand
+ obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o
+ obj-$(CONFIG_BACKLIGHT_PM8941_WLED) += pm8941-wled.o
+ obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o
++obj-$(CONFIG_BACKLIGHT_RPI) += rpi_backlight.o
+ obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o
+ obj-$(CONFIG_BACKLIGHT_SKY81452) += sky81452-backlight.o
+ obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o
+--- /dev/null
++++ b/drivers/video/backlight/rpi_backlight.c
+@@ -0,0 +1,119 @@
++/*
++ * rpi_bl.c - Backlight controller through VPU
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/backlight.h>
++#include <linux/err.h>
++#include <linux/fb.h>
++#include <linux/gpio.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_gpio.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <soc/bcm2835/raspberrypi-firmware.h>
++
++struct rpi_backlight {
++ struct device *dev;
++ struct device *fbdev;
++ struct rpi_firmware *fw;
++};
++
++static int rpi_backlight_update_status(struct backlight_device *bl)
++{
++ struct rpi_backlight *gbl = bl_get_data(bl);
++ int brightness = bl->props.brightness;
++ int ret;
++
++ if (bl->props.power != FB_BLANK_UNBLANK ||
++ bl->props.fb_blank != FB_BLANK_UNBLANK ||
++ bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
++ brightness = 0;
++
++ ret = rpi_firmware_property(gbl->fw,
++ RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT,
++ &brightness, sizeof(brightness));
++ if (ret) {
++ dev_err(gbl->dev, "Failed to set brightness\n");
++ return ret;
++ }
++
++ if (brightness < 0) {
++ dev_err(gbl->dev, "Backlight change failed\n");
++ return -EAGAIN;
++ }
++
++ return 0;
++}
++
++static const struct backlight_ops rpi_backlight_ops = {
++ .options = BL_CORE_SUSPENDRESUME,
++ .update_status = rpi_backlight_update_status,
++};
++
++static int rpi_backlight_probe(struct platform_device *pdev)
++{
++ struct backlight_properties props;
++ struct backlight_device *bl;
++ struct rpi_backlight *gbl;
++ struct device_node *fw_node;
++
++ gbl = devm_kzalloc(&pdev->dev, sizeof(*gbl), GFP_KERNEL);
++ if (gbl == NULL)
++ return -ENOMEM;
++
++ gbl->dev = &pdev->dev;
++
++ fw_node = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
++ if (!fw_node) {
++ dev_err(&pdev->dev, "Missing firmware node\n");
++ return -ENOENT;
++ }
++
++ gbl->fw = rpi_firmware_get(fw_node);
++ if (!gbl->fw)
++ return -EPROBE_DEFER;
++
++ memset(&props, 0, sizeof(props));
++ props.type = BACKLIGHT_RAW;
++ props.max_brightness = 255;
++ bl = devm_backlight_device_register(&pdev->dev, dev_name(&pdev->dev),
++ &pdev->dev, gbl, &rpi_backlight_ops,
++ &props);
++ if (IS_ERR(bl)) {
++ dev_err(&pdev->dev, "failed to register backlight\n");
++ return PTR_ERR(bl);
++ }
++
++ bl->props.brightness = 255;
++ backlight_update_status(bl);
++
++ platform_set_drvdata(pdev, bl);
++ return 0;
++}
++
++static const struct of_device_id rpi_backlight_of_match[] = {
++ { .compatible = "raspberrypi,rpi-backlight" },
++ { /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, rpi_backlight_of_match);
++
++static struct platform_driver rpi_backlight_driver = {
++ .driver = {
++ .name = "rpi-backlight",
++ .of_match_table = of_match_ptr(rpi_backlight_of_match),
++ },
++ .probe = rpi_backlight_probe,
++};
++
++module_platform_driver(rpi_backlight_driver);
++
++MODULE_AUTHOR("Gordon Hollingworth <gordon@raspberrypi.org>");
++MODULE_DESCRIPTION("Raspberry Pi mailbox based Backlight Driver");
++MODULE_LICENSE("GPL");
+--- a/include/soc/bcm2835/raspberrypi-firmware.h
++++ b/include/soc/bcm2835/raspberrypi-firmware.h
+@@ -112,6 +112,7 @@ enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_FRAMEBUFFER_SET_OVERSCAN = 0x0004800a,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE = 0x0004800b,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC = 0x0004800e,
++ RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT = 0x0004800f,
+
+ RPI_FIRMWARE_VCHIQ_INIT = 0x00048010,
+
diff --git a/target/linux/brcm2708/patches-4.4/0088-bcm2835-dma-Fix-up-convert-to-DMA-pool.patch b/target/linux/brcm2708/patches-4.4/0088-bcm2835-dma-Fix-up-convert-to-DMA-pool.patch
new file mode 100644
index 0000000000..f3b5b741e5
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0088-bcm2835-dma-Fix-up-convert-to-DMA-pool.patch
@@ -0,0 +1,85 @@
+From 5bb7ea036f5dfa3e3e3e1c674cb3f06e8204743e Mon Sep 17 00:00:00 2001
+From: Matthias Reichl <hias@horus.com>
+Date: Mon, 16 Nov 2015 14:05:35 +0000
+Subject: [PATCH 088/381] bcm2835-dma: Fix up convert to DMA pool
+
+---
+ drivers/dma/bcm2835-dma.c | 36 ++++++++++++++++++++++++++----------
+ 1 file changed, 26 insertions(+), 10 deletions(-)
+
+--- a/drivers/dma/bcm2835-dma.c
++++ b/drivers/dma/bcm2835-dma.c
+@@ -488,6 +488,17 @@ static struct dma_async_tx_descriptor *b
+ c->cyclic = true;
+
+ return vchan_tx_prep(&c->vc, &d->vd, flags);
++error_cb:
++ i--;
++ for (; i >= 0; i--) {
++ struct bcm2835_cb_entry *cb_entry = &d->cb_list[i];
++
++ dma_pool_free(c->cb_pool, cb_entry->cb, cb_entry->paddr);
++ }
++
++ kfree(d->cb_list);
++ kfree(d);
++ return NULL;
+ }
+
+ static struct dma_async_tx_descriptor *
+@@ -534,6 +545,7 @@ bcm2835_dma_prep_slave_sg(struct dma_cha
+ if (!d)
+ return NULL;
+
++ d->c = c;
+ d->dir = direction;
+
+ if (c->ch >= 8) /* LITE channel */
+@@ -553,15 +565,21 @@ bcm2835_dma_prep_slave_sg(struct dma_cha
+ 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) {
++ d->cb_list = kcalloc(d->frames, sizeof(*d->cb_list), GFP_KERNEL);
++ if (!d->cb_list) {
+ kfree(d);
+ return NULL;
+ }
++ /* Allocate memory for control blocks */
++ for (i = 0; i < d->frames; i++) {
++ struct bcm2835_cb_entry *cb_entry = &d->cb_list[i];
++
++ cb_entry->cb = dma_pool_zalloc(c->cb_pool, GFP_ATOMIC,
++ &cb_entry->paddr);
++
++ if (!cb_entry->cb)
++ goto error_cb;
++ }
+
+ /*
+ * Iterate over all SG entries, create a control block
+@@ -578,7 +596,7 @@ bcm2835_dma_prep_slave_sg(struct dma_cha
+
+ for (j = 0; j < len; j += max_size) {
+ struct bcm2835_dma_cb *control_block =
+- &d->control_block_base[i + split_cnt];
++ d->cb_list[i + split_cnt].cb;
+
+ /* Setup addresses */
+ if (d->dir == DMA_DEV_TO_MEM) {
+@@ -620,9 +638,7 @@ bcm2835_dma_prep_slave_sg(struct dma_cha
+ 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);
++ d->cb_list[i + split_cnt + 1].paddr;
+ } else {
+ /* Next block is empty. */
+ control_block->next = 0;
diff --git a/target/linux/brcm2708/patches-4.4/0088-rpi_display-add-backlight-driver-and-overlay.patch b/target/linux/brcm2708/patches-4.4/0088-rpi_display-add-backlight-driver-and-overlay.patch
deleted file mode 100644
index 02a78c8e07..0000000000
--- a/target/linux/brcm2708/patches-4.4/0088-rpi_display-add-backlight-driver-and-overlay.patch
+++ /dev/null
@@ -1,250 +0,0 @@
-From 0e7ec1e61b149567d5af63169cd4d701c133356f Mon Sep 17 00:00:00 2001
-From: P33M <P33M@github.com>
-Date: Wed, 21 Oct 2015 14:55:21 +0100
-Subject: [PATCH 088/170] rpi_display: add backlight driver and overlay
-
-Add a mailbox-driven backlight controller for the Raspberry Pi DSI
-touchscreen display. Requires updated GPU firmware to recognise the
-mailbox request.
-
-Signed-off-by: Gordon Hollingworth <gordon@raspberrypi.org>
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 6 ++
- .../boot/dts/overlays/rpi-backlight-overlay.dts | 21 ++++
- arch/arm/configs/bcm2709_defconfig | 1 +
- arch/arm/configs/bcmrpi_defconfig | 1 +
- drivers/video/backlight/Kconfig | 6 ++
- drivers/video/backlight/Makefile | 1 +
- drivers/video/backlight/rpi_backlight.c | 119 +++++++++++++++++++++
- include/soc/bcm2835/raspberrypi-firmware.h | 1 +
- 9 files changed, 157 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/rpi-backlight-overlay.dts
- create mode 100644 drivers/video/backlight/rpi_backlight.c
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -38,6 +38,7 @@ dtb-$(RPI_DT_OVERLAYS) += pps-gpio-overl
- dtb-$(RPI_DT_OVERLAYS) += pwm-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += pwm-2chan-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += raspidac3-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += rpi-backlight-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += rpi-dac-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += rpi-display-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += rpi-ft5406-overlay.dtb
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -462,6 +462,12 @@ Load: dtoverlay=raspidac3
- Params: <None>
-
-
-+Name: rpi-backlight
-+Info: Raspberry Pi official display backlight driver
-+Load: dtoverlay=rpi-backlight
-+Params: <None>
-+
-+
- Name: rpi-dac
- Info: Configures the RPi DAC audio card
- Load: dtoverlay=rpi-dac
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/rpi-backlight-overlay.dts
-@@ -0,0 +1,21 @@
-+/*
-+ * Devicetree overlay for mailbox-driven Raspberry Pi DSI Display
-+ * backlight controller
-+ */
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target-path = "/";
-+ __overlay__ {
-+ rpi_backlight: rpi_backlight {
-+ compatible = "raspberrypi,rpi-backlight";
-+ firmware = <&firmware>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+};
---- a/arch/arm/configs/bcm2709_defconfig
-+++ b/arch/arm/configs/bcm2709_defconfig
-@@ -808,6 +808,7 @@ CONFIG_FB_UDL=m
- CONFIG_FB_SSD1307=m
- CONFIG_FB_RPISENSE=m
- # CONFIG_BACKLIGHT_GENERIC is not set
-+CONFIG_BACKLIGHT_RPI=m
- CONFIG_BACKLIGHT_GPIO=m
- CONFIG_FRAMEBUFFER_CONSOLE=y
- CONFIG_LOGO=y
---- a/arch/arm/configs/bcmrpi_defconfig
-+++ b/arch/arm/configs/bcmrpi_defconfig
-@@ -801,6 +801,7 @@ CONFIG_FB_UDL=m
- CONFIG_FB_SSD1307=m
- CONFIG_FB_RPISENSE=m
- # CONFIG_BACKLIGHT_GENERIC is not set
-+CONFIG_BACKLIGHT_RPI=m
- CONFIG_BACKLIGHT_GPIO=m
- CONFIG_FRAMEBUFFER_CONSOLE=y
- CONFIG_LOGO=y
---- a/drivers/video/backlight/Kconfig
-+++ b/drivers/video/backlight/Kconfig
-@@ -265,6 +265,12 @@ config BACKLIGHT_PWM
- If you have a LCD backlight adjustable by PWM, say Y to enable
- this driver.
-
-+config BACKLIGHT_RPI
-+ tristate "Raspberry Pi display firmware driven backlight"
-+ help
-+ If you have the Raspberry Pi DSI touchscreen display, say Y to
-+ enable the mailbox-controlled backlight driver.
-+
- config BACKLIGHT_DA903X
- tristate "Backlight Driver for DA9030/DA9034 using WLED"
- depends on PMIC_DA903X
---- a/drivers/video/backlight/Makefile
-+++ b/drivers/video/backlight/Makefile
-@@ -50,6 +50,7 @@ obj-$(CONFIG_BACKLIGHT_PANDORA) += pand
- obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o
- obj-$(CONFIG_BACKLIGHT_PM8941_WLED) += pm8941-wled.o
- obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o
-+obj-$(CONFIG_BACKLIGHT_RPI) += rpi_backlight.o
- obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o
- obj-$(CONFIG_BACKLIGHT_SKY81452) += sky81452-backlight.o
- obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o
---- /dev/null
-+++ b/drivers/video/backlight/rpi_backlight.c
-@@ -0,0 +1,119 @@
-+/*
-+ * rpi_bl.c - Backlight controller through VPU
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ */
-+
-+#include <linux/backlight.h>
-+#include <linux/err.h>
-+#include <linux/fb.h>
-+#include <linux/gpio.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/of_gpio.h>
-+#include <linux/platform_device.h>
-+#include <linux/slab.h>
-+#include <soc/bcm2835/raspberrypi-firmware.h>
-+
-+struct rpi_backlight {
-+ struct device *dev;
-+ struct device *fbdev;
-+ struct rpi_firmware *fw;
-+};
-+
-+static int rpi_backlight_update_status(struct backlight_device *bl)
-+{
-+ struct rpi_backlight *gbl = bl_get_data(bl);
-+ int brightness = bl->props.brightness;
-+ int ret;
-+
-+ if (bl->props.power != FB_BLANK_UNBLANK ||
-+ bl->props.fb_blank != FB_BLANK_UNBLANK ||
-+ bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
-+ brightness = 0;
-+
-+ ret = rpi_firmware_property(gbl->fw,
-+ RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT,
-+ &brightness, sizeof(brightness));
-+ if (ret) {
-+ dev_err(gbl->dev, "Failed to set brightness\n");
-+ return ret;
-+ }
-+
-+ if (brightness < 0) {
-+ dev_err(gbl->dev, "Backlight change failed\n");
-+ return -EAGAIN;
-+ }
-+
-+ return 0;
-+}
-+
-+static const struct backlight_ops rpi_backlight_ops = {
-+ .options = BL_CORE_SUSPENDRESUME,
-+ .update_status = rpi_backlight_update_status,
-+};
-+
-+static int rpi_backlight_probe(struct platform_device *pdev)
-+{
-+ struct backlight_properties props;
-+ struct backlight_device *bl;
-+ struct rpi_backlight *gbl;
-+ struct device_node *fw_node;
-+
-+ gbl = devm_kzalloc(&pdev->dev, sizeof(*gbl), GFP_KERNEL);
-+ if (gbl == NULL)
-+ return -ENOMEM;
-+
-+ gbl->dev = &pdev->dev;
-+
-+ fw_node = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
-+ if (!fw_node) {
-+ dev_err(&pdev->dev, "Missing firmware node\n");
-+ return -ENOENT;
-+ }
-+
-+ gbl->fw = rpi_firmware_get(fw_node);
-+ if (!gbl->fw)
-+ return -EPROBE_DEFER;
-+
-+ memset(&props, 0, sizeof(props));
-+ props.type = BACKLIGHT_RAW;
-+ props.max_brightness = 255;
-+ bl = devm_backlight_device_register(&pdev->dev, dev_name(&pdev->dev),
-+ &pdev->dev, gbl, &rpi_backlight_ops,
-+ &props);
-+ if (IS_ERR(bl)) {
-+ dev_err(&pdev->dev, "failed to register backlight\n");
-+ return PTR_ERR(bl);
-+ }
-+
-+ bl->props.brightness = 255;
-+ backlight_update_status(bl);
-+
-+ platform_set_drvdata(pdev, bl);
-+ return 0;
-+}
-+
-+static const struct of_device_id rpi_backlight_of_match[] = {
-+ { .compatible = "raspberrypi,rpi-backlight" },
-+ { /* sentinel */ }
-+};
-+MODULE_DEVICE_TABLE(of, rpi_backlight_of_match);
-+
-+static struct platform_driver rpi_backlight_driver = {
-+ .driver = {
-+ .name = "rpi-backlight",
-+ .of_match_table = of_match_ptr(rpi_backlight_of_match),
-+ },
-+ .probe = rpi_backlight_probe,
-+};
-+
-+module_platform_driver(rpi_backlight_driver);
-+
-+MODULE_AUTHOR("Gordon Hollingworth <gordon@raspberrypi.org>");
-+MODULE_DESCRIPTION("Raspberry Pi mailbox based Backlight Driver");
-+MODULE_LICENSE("GPL");
---- a/include/soc/bcm2835/raspberrypi-firmware.h
-+++ b/include/soc/bcm2835/raspberrypi-firmware.h
-@@ -112,6 +112,7 @@ enum rpi_firmware_property_tag {
- RPI_FIRMWARE_FRAMEBUFFER_SET_OVERSCAN = 0x0004800a,
- RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE = 0x0004800b,
- RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC = 0x0004800e,
-+ RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT = 0x0004800f,
-
- RPI_FIRMWARE_VCHIQ_INIT = 0x00048010,
-
diff --git a/target/linux/brcm2708/patches-4.4/0089-bcm2835-dma-Fix-up-convert-to-DMA-pool.patch b/target/linux/brcm2708/patches-4.4/0089-bcm2835-dma-Fix-up-convert-to-DMA-pool.patch
deleted file mode 100644
index cfeccd2a43..0000000000
--- a/target/linux/brcm2708/patches-4.4/0089-bcm2835-dma-Fix-up-convert-to-DMA-pool.patch
+++ /dev/null
@@ -1,85 +0,0 @@
-From 0459ca97c1f2753ce805ab58ff17847cb4c142e0 Mon Sep 17 00:00:00 2001
-From: Matthias Reichl <hias@horus.com>
-Date: Mon, 16 Nov 2015 14:05:35 +0000
-Subject: [PATCH 089/170] bcm2835-dma: Fix up convert to DMA pool
-
----
- drivers/dma/bcm2835-dma.c | 36 ++++++++++++++++++++++++++----------
- 1 file changed, 26 insertions(+), 10 deletions(-)
-
---- a/drivers/dma/bcm2835-dma.c
-+++ b/drivers/dma/bcm2835-dma.c
-@@ -488,6 +488,17 @@ static struct dma_async_tx_descriptor *b
- c->cyclic = true;
-
- return vchan_tx_prep(&c->vc, &d->vd, flags);
-+error_cb:
-+ i--;
-+ for (; i >= 0; i--) {
-+ struct bcm2835_cb_entry *cb_entry = &d->cb_list[i];
-+
-+ dma_pool_free(c->cb_pool, cb_entry->cb, cb_entry->paddr);
-+ }
-+
-+ kfree(d->cb_list);
-+ kfree(d);
-+ return NULL;
- }
-
- static struct dma_async_tx_descriptor *
-@@ -534,6 +545,7 @@ bcm2835_dma_prep_slave_sg(struct dma_cha
- if (!d)
- return NULL;
-
-+ d->c = c;
- d->dir = direction;
-
- if (c->ch >= 8) /* LITE channel */
-@@ -553,15 +565,21 @@ bcm2835_dma_prep_slave_sg(struct dma_cha
- 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) {
-+ d->cb_list = kcalloc(d->frames, sizeof(*d->cb_list), GFP_KERNEL);
-+ if (!d->cb_list) {
- kfree(d);
- return NULL;
- }
-+ /* Allocate memory for control blocks */
-+ for (i = 0; i < d->frames; i++) {
-+ struct bcm2835_cb_entry *cb_entry = &d->cb_list[i];
-+
-+ cb_entry->cb = dma_pool_zalloc(c->cb_pool, GFP_ATOMIC,
-+ &cb_entry->paddr);
-+
-+ if (!cb_entry->cb)
-+ goto error_cb;
-+ }
-
- /*
- * Iterate over all SG entries, create a control block
-@@ -578,7 +596,7 @@ bcm2835_dma_prep_slave_sg(struct dma_cha
-
- for (j = 0; j < len; j += max_size) {
- struct bcm2835_dma_cb *control_block =
-- &d->control_block_base[i + split_cnt];
-+ d->cb_list[i + split_cnt].cb;
-
- /* Setup addresses */
- if (d->dir == DMA_DEV_TO_MEM) {
-@@ -620,9 +638,7 @@ bcm2835_dma_prep_slave_sg(struct dma_cha
- 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);
-+ d->cb_list[i + split_cnt + 1].paddr;
- } else {
- /* Next block is empty. */
- control_block->next = 0;
diff --git a/target/linux/brcm2708/patches-4.4/0089-scripts-Multi-platform-support-for-mkknlimg-and-knli.patch b/target/linux/brcm2708/patches-4.4/0089-scripts-Multi-platform-support-for-mkknlimg-and-knli.patch
new file mode 100644
index 0000000000..a551dce5a4
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0089-scripts-Multi-platform-support-for-mkknlimg-and-knli.patch
@@ -0,0 +1,247 @@
+From 5e591b39b106e20e3f8128cbd46a20d01eedb185 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Wed, 11 Nov 2015 11:38:59 +0000
+Subject: [PATCH 089/381] scripts: Multi-platform support for mkknlimg and
+ knlinfo
+
+The firmware uses tags in the kernel trailer to choose which dtb file
+to load. Current firmware loads bcm2835-*.dtb if the '283x' tag is true,
+otherwise it loads bcm270*.dtb. This scheme breaks if an image supports
+multiple platforms.
+
+This patch adds '270X' and '283X' tags to indicate support for RPi and
+upstream platforms, respectively. '283x' (note lower case 'x') is left
+for old firmware, and is only set if the image only supports upstream
+builds.
+---
+ scripts/knlinfo | 2 +
+ scripts/mkknlimg | 136 +++++++++++++++++++++++++++++++------------------------
+ 2 files changed, 80 insertions(+), 58 deletions(-)
+
+--- a/scripts/knlinfo
++++ b/scripts/knlinfo
+@@ -18,6 +18,8 @@ my %atom_formats =
+ (
+ 'DTOK' => \&format_bool,
+ 'KVer' => \&format_string,
++ '270X' => \&format_bool,
++ '283X' => \&format_bool,
+ '283x' => \&format_bool,
+ );
+
+--- a/scripts/mkknlimg
++++ b/scripts/mkknlimg
+@@ -13,12 +13,20 @@ use strict;
+ use warnings;
+ use integer;
+
++use constant FLAG_PI => 0x01;
++use constant FLAG_DTOK => 0x02;
++use constant FLAG_DDTK => 0x04;
++use constant FLAG_270X => 0x08;
++use constant FLAG_283X => 0x10;
++
+ my $trailer_magic = 'RPTL';
+
+ my $tmpfile1 = "/tmp/mkknlimg_$$.1";
+ my $tmpfile2 = "/tmp/mkknlimg_$$.2";
+
+ my $dtok = 0;
++my $ddtk = 0;
++my $is_270x = 0;
+ my $is_283x = 0;
+
+ while (@ARGV && ($ARGV[0] =~ /^-/))
+@@ -28,6 +36,14 @@ while (@ARGV && ($ARGV[0] =~ /^-/))
+ {
+ $dtok = 1;
+ }
++ elsif ($arg eq '--ddtk')
++ {
++ $ddtk = 1;
++ }
++ elsif ($arg eq '--270x')
++ {
++ $is_270x = 1;
++ }
+ elsif ($arg eq '--283x')
+ {
+ $is_283x = 1;
+@@ -50,30 +66,33 @@ if (! -r $kernel_file)
+ usage();
+ }
+
+-my @wanted_strings =
+-(
+- 'bcm2708_fb',
+- 'brcm,bcm2835-mmc',
+- 'brcm,bcm2835-sdhost',
+- 'brcm,bcm2708-pinctrl',
+- 'brcm,bcm2835-gpio',
+- 'brcm,bcm2835',
+- 'brcm,bcm2836'
+-);
++my $wanted_strings =
++{
++ 'bcm2708_fb' => FLAG_PI,
++ 'brcm,bcm2835-mmc' => FLAG_PI,
++ 'brcm,bcm2835-sdhost' => FLAG_PI,
++ 'brcm,bcm2708-pinctrl' => FLAG_PI | FLAG_DTOK,
++ 'brcm,bcm2835-gpio' => FLAG_PI | FLAG_DTOK,
++ 'brcm,bcm2708' => FLAG_PI | FLAG_DTOK | FLAG_270X,
++ 'brcm,bcm2709' => FLAG_PI | FLAG_DTOK | FLAG_270X,
++ 'brcm,bcm2835' => FLAG_PI | FLAG_DTOK | FLAG_283X,
++ 'brcm,bcm2836' => FLAG_PI | FLAG_DTOK | FLAG_283X,
++ 'of_overlay_apply' => FLAG_DTOK | FLAG_DDTK,
++};
+
+ my $res = try_extract($kernel_file, $tmpfile1);
+-$res = try_decompress('\037\213\010', 'xy', 'gunzip', 0,
+- $kernel_file, $tmpfile1, $tmpfile2) if (!$res);
+-$res = try_decompress('\3757zXZ\000', 'abcde', 'unxz --single-stream', -1,
+- $kernel_file, $tmpfile1, $tmpfile2) if (!$res);
+-$res = try_decompress('BZh', 'xy', 'bunzip2', 0,
+- $kernel_file, $tmpfile1, $tmpfile2) if (!$res);
+-$res = try_decompress('\135\0\0\0', 'xxx', 'unlzma', 0,
+- $kernel_file, $tmpfile1, $tmpfile2) if (!$res);
+-$res = try_decompress('\211\114\132', 'xy', 'lzop -d', 0,
+- $kernel_file, $tmpfile1, $tmpfile2) if (!$res);
+-$res = try_decompress('\002\041\114\030', 'xy', 'lz4 -d', 1,
+- $kernel_file, $tmpfile1, $tmpfile2) if (!$res);
++$res ||= try_decompress('\037\213\010', 'xy', 'gunzip', 0,
++ $kernel_file, $tmpfile1, $tmpfile2);
++$res ||= try_decompress('\3757zXZ\000', 'abcde', 'unxz --single-stream', -1,
++ $kernel_file, $tmpfile1, $tmpfile2);
++$res ||= try_decompress('BZh', 'xy', 'bunzip2', 0,
++ $kernel_file, $tmpfile1, $tmpfile2);
++$res ||= try_decompress('\135\0\0\0', 'xxx', 'unlzma', 0,
++ $kernel_file, $tmpfile1, $tmpfile2);
++$res ||= try_decompress('\211\114\132', 'xy', 'lzop -d', 0,
++ $kernel_file, $tmpfile1, $tmpfile2);
++$res ||= try_decompress('\002\041\114\030', 'xy', 'lz4 -d', 1,
++ $kernel_file, $tmpfile1, $tmpfile2);
+
+ my $append_trailer;
+ my $trailer;
+@@ -83,27 +102,21 @@ $append_trailer = $dtok;
+
+ if ($res)
+ {
+- $kver = $res->{''} || '?';
++ $kver = $res->{'kver'} || '?';
++ my $flags = $res->{'flags'};
+ print("Version: $kver\n");
+
+- $append_trailer = $dtok;
+- if (!$dtok)
++ if ($flags & FLAG_PI)
+ {
+- if (config_bool($res, 'bcm2708_fb') ||
+- config_bool($res, 'brcm,bcm2835-mmc') ||
+- config_bool($res, 'brcm,bcm2835-sdhost'))
+- {
+- $dtok ||= config_bool($res, 'brcm,bcm2708-pinctrl');
+- $dtok ||= config_bool($res, 'brcm,bcm2835-gpio');
+- $is_283x ||= config_bool($res, 'brcm,bcm2835');
+- $is_283x ||= config_bool($res, 'brcm,bcm2836');
+- $dtok ||= $is_283x;
+- $append_trailer = 1;
+- }
+- else
+- {
+- print ("* This doesn't look like a Raspberry Pi kernel. In pass-through mode.\n");
+- }
++ $append_trailer = 1;
++ $dtok ||= ($flags & FLAG_DTOK) != 0;
++ $is_270x ||= ($flags & FLAG_270X) != 0;
++ $is_283x ||= ($flags & FLAG_283X) != 0;
++ $ddtk ||= ($flags & FLAG_DDTK) != 0;
++ }
++ else
++ {
++ print ("* This doesn't look like a Raspberry Pi kernel. In pass-through mode.\n");
+ }
+ }
+ elsif (!$dtok)
+@@ -114,6 +127,8 @@ elsif (!$dtok)
+ if ($append_trailer)
+ {
+ printf("DT: %s\n", $dtok ? "y" : "n");
++ printf("DDT: %s\n", $ddtk ? "y" : "n") if ($ddtk);
++ printf("270x: %s\n", $is_270x ? "y" : "n");
+ printf("283x: %s\n", $is_283x ? "y" : "n");
+
+ my @atoms;
+@@ -121,7 +136,10 @@ if ($append_trailer)
+ push @atoms, [ $trailer_magic, pack('V', 0) ];
+ push @atoms, [ 'KVer', $kver ];
+ push @atoms, [ 'DTOK', pack('V', $dtok) ];
+- push @atoms, [ '283x', pack('V', $is_283x) ];
++ push @atoms, [ 'DDTK', pack('V', $ddtk) ] if ($ddtk);
++ push @atoms, [ '270X', pack('V', $is_270x) ];
++ push @atoms, [ '283X', pack('V', $is_283x) ];
++ push @atoms, [ '283x', pack('V', $is_283x && !$is_270x) ];
+
+ $trailer = pack_trailer(\@atoms);
+ $atoms[0]->[1] = pack('V', length($trailer));
+@@ -175,7 +193,7 @@ END {
+
+ sub usage
+ {
+- print ("Usage: mkknlimg [--dtok] [--283x] <vmlinux|zImage|bzImage> <outfile>\n");
++ print ("Usage: mkknlimg [--dtok] [--270x] [--283x] <vmlinux|zImage|bzImage> <outfile>\n");
+ exit(1);
+ }
+
+@@ -189,15 +207,8 @@ sub try_extract
+
+ chomp($ver);
+
+- my $res = { ''=>$ver };
+- my $string_pattern = '^('.join('|', @wanted_strings).')$';
+-
+- my @matches = `strings \"$knl\" | grep -E \"$string_pattern\"`;
+- foreach my $match (@matches)
+- {
+- chomp($match);
+- $res->{$match} = 1;
+- }
++ my $res = { 'kver'=>$ver };
++ $res->{'flags'} = strings_to_flags($knl, $wanted_strings);
+
+ return $res;
+ }
+@@ -224,6 +235,22 @@ sub try_decompress
+ return undef;
+ }
+
++sub strings_to_flags
++{
++ my ($knl, $strings) = @_;
++ my $string_pattern = '^('.join('|', keys(%$strings)).')$';
++ my $flags = 0;
++
++ my @matches = `strings \"$knl\" | grep -E \"$string_pattern\"`;
++ foreach my $match (@matches)
++ {
++ chomp($match);
++ $flags |= $strings->{$match};
++ }
++
++ return $flags;
++}
++
+ sub pack_trailer
+ {
+ my ($atoms) = @_;
+@@ -235,10 +262,3 @@ sub pack_trailer
+ }
+ return $trailer;
+ }
+-
+-sub config_bool
+-{
+- my ($configs, $wanted) = @_;
+- my $val = $configs->{$wanted} || 'n';
+- return (($val eq 'y') || ($val eq '1'));
+-}
diff --git a/target/linux/brcm2708/patches-4.4/0090-drm-vc4-Add-suport-for-3D-rendering-using-the-V3D-en.patch b/target/linux/brcm2708/patches-4.4/0090-drm-vc4-Add-suport-for-3D-rendering-using-the-V3D-en.patch
new file mode 100644
index 0000000000..b6b672644e
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0090-drm-vc4-Add-suport-for-3D-rendering-using-the-V3D-en.patch
@@ -0,0 +1,5558 @@
+From d6b537db6d9208d3d512aac65d03a47913787576 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 2 Mar 2015 13:01:12 -0800
+Subject: [PATCH 090/381] drm/vc4: Add suport for 3D rendering using the V3D
+ engine.
+
+This is a squash of the out-of-tree development series. Since that
+series contained code from the first "get a demo triangle rendered
+using a hacked up driver using binary shader code" to "plug the last
+known security hole", it's hard to reconstruct a different series of
+incremental development that's mergeable without security holes
+throughout it.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/Makefile | 11 +-
+ drivers/gpu/drm/vc4/vc4_bo.c | 476 +++++++++++++-
+ drivers/gpu/drm/vc4/vc4_crtc.c | 98 ++-
+ drivers/gpu/drm/vc4/vc4_debugfs.c | 3 +
+ drivers/gpu/drm/vc4/vc4_drv.c | 45 +-
+ drivers/gpu/drm/vc4/vc4_drv.h | 317 ++++++++++
+ drivers/gpu/drm/vc4/vc4_gem.c | 686 +++++++++++++++++++++
+ drivers/gpu/drm/vc4/vc4_irq.c | 211 +++++++
+ drivers/gpu/drm/vc4/vc4_kms.c | 148 ++++-
+ drivers/gpu/drm/vc4/vc4_packet.h | 384 ++++++++++++
+ drivers/gpu/drm/vc4/vc4_plane.c | 40 ++
+ drivers/gpu/drm/vc4/vc4_qpu_defines.h | 268 ++++++++
+ drivers/gpu/drm/vc4/vc4_render_cl.c | 448 ++++++++++++++
+ drivers/gpu/drm/vc4/vc4_trace.h | 63 ++
+ drivers/gpu/drm/vc4/vc4_trace_points.c | 14 +
+ drivers/gpu/drm/vc4/vc4_v3d.c | 268 ++++++++
+ drivers/gpu/drm/vc4/vc4_validate.c | 958 +++++++++++++++++++++++++++++
+ drivers/gpu/drm/vc4/vc4_validate_shaders.c | 521 ++++++++++++++++
+ include/uapi/drm/vc4_drm.h | 229 +++++++
+ 19 files changed, 5173 insertions(+), 15 deletions(-)
+ create mode 100644 drivers/gpu/drm/vc4/vc4_gem.c
+ create mode 100644 drivers/gpu/drm/vc4/vc4_irq.c
+ create mode 100644 drivers/gpu/drm/vc4/vc4_packet.h
+ create mode 100644 drivers/gpu/drm/vc4/vc4_qpu_defines.h
+ create mode 100644 drivers/gpu/drm/vc4/vc4_render_cl.c
+ create mode 100644 drivers/gpu/drm/vc4/vc4_trace.h
+ create mode 100644 drivers/gpu/drm/vc4/vc4_trace_points.c
+ create mode 100644 drivers/gpu/drm/vc4/vc4_v3d.c
+ create mode 100644 drivers/gpu/drm/vc4/vc4_validate.c
+ create mode 100644 drivers/gpu/drm/vc4/vc4_validate_shaders.c
+ create mode 100644 include/uapi/drm/vc4_drm.h
+
+--- a/drivers/gpu/drm/vc4/Makefile
++++ b/drivers/gpu/drm/vc4/Makefile
+@@ -8,10 +8,19 @@ vc4-y := \
+ vc4_crtc.o \
+ vc4_drv.o \
+ vc4_kms.o \
++ vc4_gem.o \
+ vc4_hdmi.o \
+ vc4_hvs.o \
+- vc4_plane.o
++ vc4_irq.o \
++ vc4_plane.o \
++ vc4_render_cl.o \
++ vc4_trace_points.o \
++ vc4_v3d.o \
++ vc4_validate.o \
++ vc4_validate_shaders.o
+
+ vc4-$(CONFIG_DEBUG_FS) += vc4_debugfs.o
+
+ obj-$(CONFIG_DRM_VC4) += vc4.o
++
++CFLAGS_vc4_trace_points.o := -I$(src)
+--- a/drivers/gpu/drm/vc4/vc4_bo.c
++++ b/drivers/gpu/drm/vc4/vc4_bo.c
+@@ -15,16 +15,174 @@
+ */
+
+ #include "vc4_drv.h"
++#include "uapi/drm/vc4_drm.h"
+
+-struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t size)
++static void vc4_bo_stats_dump(struct vc4_dev *vc4)
+ {
++ DRM_INFO("num bos allocated: %d\n",
++ vc4->bo_stats.num_allocated);
++ DRM_INFO("size bos allocated: %dkb\n",
++ vc4->bo_stats.size_allocated / 1024);
++ DRM_INFO("num bos used: %d\n",
++ vc4->bo_stats.num_allocated - vc4->bo_stats.num_cached);
++ DRM_INFO("size bos used: %dkb\n",
++ (vc4->bo_stats.size_allocated -
++ vc4->bo_stats.size_cached) / 1024);
++ DRM_INFO("num bos cached: %d\n",
++ vc4->bo_stats.num_cached);
++ DRM_INFO("size bos cached: %dkb\n",
++ vc4->bo_stats.size_cached / 1024);
++}
++
++static uint32_t bo_page_index(size_t size)
++{
++ return (size / PAGE_SIZE) - 1;
++}
++
++/* Must be called with bo_lock held. */
++static void vc4_bo_destroy(struct vc4_bo *bo)
++{
++ struct drm_gem_object *obj = &bo->base.base;
++ struct vc4_dev *vc4 = to_vc4_dev(obj->dev);
++
++ if (bo->validated_shader) {
++ kfree(bo->validated_shader->texture_samples);
++ kfree(bo->validated_shader);
++ bo->validated_shader = NULL;
++ }
++
++ vc4->bo_stats.num_allocated--;
++ vc4->bo_stats.size_allocated -= obj->size;
++ drm_gem_cma_free_object(obj);
++}
++
++/* Must be called with bo_lock held. */
++static void vc4_bo_remove_from_cache(struct vc4_bo *bo)
++{
++ struct drm_gem_object *obj = &bo->base.base;
++ struct vc4_dev *vc4 = to_vc4_dev(obj->dev);
++
++ vc4->bo_stats.num_cached--;
++ vc4->bo_stats.size_cached -= obj->size;
++
++ list_del(&bo->unref_head);
++ list_del(&bo->size_head);
++}
++
++static struct list_head *vc4_get_cache_list_for_size(struct drm_device *dev,
++ size_t size)
++{
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ uint32_t page_index = bo_page_index(size);
++
++ if (vc4->bo_cache.size_list_size <= page_index) {
++ uint32_t new_size = max(vc4->bo_cache.size_list_size * 2,
++ page_index + 1);
++ struct list_head *new_list;
++ uint32_t i;
++
++ new_list = kmalloc(new_size * sizeof(struct list_head),
++ GFP_KERNEL);
++ if (!new_list)
++ return NULL;
++
++ /* Rebase the old cached BO lists to their new list
++ * head locations.
++ */
++ for (i = 0; i < vc4->bo_cache.size_list_size; i++) {
++ struct list_head *old_list = &vc4->bo_cache.size_list[i];
++ if (list_empty(old_list))
++ INIT_LIST_HEAD(&new_list[i]);
++ else
++ list_replace(old_list, &new_list[i]);
++ }
++ /* And initialize the brand new BO list heads. */
++ for (i = vc4->bo_cache.size_list_size; i < new_size; i++)
++ INIT_LIST_HEAD(&new_list[i]);
++
++ kfree(vc4->bo_cache.size_list);
++ vc4->bo_cache.size_list = new_list;
++ vc4->bo_cache.size_list_size = new_size;
++ }
++
++ return &vc4->bo_cache.size_list[page_index];
++}
++
++void vc4_bo_cache_purge(struct drm_device *dev)
++{
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++
++ spin_lock(&vc4->bo_lock);
++ while (!list_empty(&vc4->bo_cache.time_list)) {
++ struct vc4_bo *bo = list_last_entry(&vc4->bo_cache.time_list,
++ struct vc4_bo, unref_head);
++ vc4_bo_remove_from_cache(bo);
++ vc4_bo_destroy(bo);
++ }
++ spin_unlock(&vc4->bo_lock);
++}
++
++struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size)
++{
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ uint32_t size = roundup(unaligned_size, PAGE_SIZE);
++ uint32_t page_index = bo_page_index(size);
+ struct drm_gem_cma_object *cma_obj;
++ int pass;
+
+- cma_obj = drm_gem_cma_create(dev, size);
+- if (IS_ERR(cma_obj))
++ if (size == 0)
+ return NULL;
+- else
+- return to_vc4_bo(&cma_obj->base);
++
++ /* First, try to get a vc4_bo from the kernel BO cache. */
++ spin_lock(&vc4->bo_lock);
++ if (page_index < vc4->bo_cache.size_list_size &&
++ !list_empty(&vc4->bo_cache.size_list[page_index])) {
++ struct vc4_bo *bo =
++ list_first_entry(&vc4->bo_cache.size_list[page_index],
++ struct vc4_bo, size_head);
++ vc4_bo_remove_from_cache(bo);
++ spin_unlock(&vc4->bo_lock);
++ kref_init(&bo->base.base.refcount);
++ return bo;
++ }
++ spin_unlock(&vc4->bo_lock);
++
++ /* Otherwise, make a new BO. */
++ for (pass = 0; ; pass++) {
++ cma_obj = drm_gem_cma_create(dev, size);
++ if (!IS_ERR(cma_obj))
++ break;
++
++ switch (pass) {
++ case 0:
++ /*
++ * If we've run out of CMA memory, kill the cache of
++ * CMA allocations we've got laying around and try again.
++ */
++ vc4_bo_cache_purge(dev);
++ break;
++ case 1:
++ /*
++ * Getting desperate, so try to wait for any
++ * previous rendering to finish, free its
++ * unreferenced BOs to the cache, and then
++ * free the cache.
++ */
++ vc4_wait_for_seqno(dev, vc4->emit_seqno, ~0ull, true);
++ vc4_job_handle_completed(vc4);
++ vc4_bo_cache_purge(dev);
++ break;
++ case 3:
++ DRM_ERROR("Failed to allocate from CMA:\n");
++ vc4_bo_stats_dump(vc4);
++ return NULL;
++ }
++ }
++
++ vc4->bo_stats.num_allocated++;
++ vc4->bo_stats.size_allocated += size;
++
++ return to_vc4_bo(&cma_obj->base);
+ }
+
+ int vc4_dumb_create(struct drm_file *file_priv,
+@@ -41,7 +199,129 @@ int vc4_dumb_create(struct drm_file *fil
+ if (args->size < args->pitch * args->height)
+ args->size = args->pitch * args->height;
+
+- bo = vc4_bo_create(dev, roundup(args->size, PAGE_SIZE));
++ bo = vc4_bo_create(dev, args->size);
++ if (!bo)
++ return -ENOMEM;
++
++ ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle);
++ drm_gem_object_unreference_unlocked(&bo->base.base);
++
++ return ret;
++}
++
++static void
++vc4_bo_cache_free_old(struct drm_device *dev)
++{
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ unsigned long expire_time = jiffies - msecs_to_jiffies(1000);
++
++ spin_lock(&vc4->bo_lock);
++ while (!list_empty(&vc4->bo_cache.time_list)) {
++ struct vc4_bo *bo = list_last_entry(&vc4->bo_cache.time_list,
++ struct vc4_bo, unref_head);
++ if (time_before(expire_time, bo->free_time)) {
++ mod_timer(&vc4->bo_cache.time_timer,
++ round_jiffies_up(jiffies +
++ msecs_to_jiffies(1000)));
++ spin_unlock(&vc4->bo_lock);
++ return;
++ }
++
++ vc4_bo_remove_from_cache(bo);
++ vc4_bo_destroy(bo);
++ }
++ spin_unlock(&vc4->bo_lock);
++}
++
++/* Called on the last userspace/kernel unreference of the BO. Returns
++ * it to the BO cache if possible, otherwise frees it.
++ *
++ * Note that this is called with the struct_mutex held.
++ */
++void vc4_free_object(struct drm_gem_object *gem_bo)
++{
++ struct drm_device *dev = gem_bo->dev;
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ struct vc4_bo *bo = to_vc4_bo(gem_bo);
++ struct list_head *cache_list;
++
++ /* If the object references someone else's memory, we can't cache it.
++ */
++ if (gem_bo->import_attach) {
++ vc4_bo_destroy(bo);
++ return;
++ }
++
++ /* Don't cache if it was publicly named. */
++ if (gem_bo->name) {
++ vc4_bo_destroy(bo);
++ return;
++ }
++
++ spin_lock(&vc4->bo_lock);
++ cache_list = vc4_get_cache_list_for_size(dev, gem_bo->size);
++ if (!cache_list) {
++ vc4_bo_destroy(bo);
++ spin_unlock(&vc4->bo_lock);
++ return;
++ }
++
++ if (bo->validated_shader) {
++ kfree(bo->validated_shader->texture_samples);
++ kfree(bo->validated_shader);
++ bo->validated_shader = NULL;
++ }
++
++ bo->free_time = jiffies;
++ list_add(&bo->size_head, cache_list);
++ list_add(&bo->unref_head, &vc4->bo_cache.time_list);
++
++ vc4->bo_stats.num_cached++;
++ vc4->bo_stats.size_cached += gem_bo->size;
++ spin_unlock(&vc4->bo_lock);
++
++ vc4_bo_cache_free_old(dev);
++}
++
++static void vc4_bo_cache_time_work(struct work_struct *work)
++{
++ struct vc4_dev *vc4 =
++ container_of(work, struct vc4_dev, bo_cache.time_work);
++ struct drm_device *dev = vc4->dev;
++
++ vc4_bo_cache_free_old(dev);
++}
++
++static void vc4_bo_cache_time_timer(unsigned long data)
++{
++ struct drm_device *dev = (struct drm_device *)data;
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++
++ schedule_work(&vc4->bo_cache.time_work);
++}
++
++struct dma_buf *
++vc4_prime_export(struct drm_device *dev, struct drm_gem_object *obj, int flags)
++{
++ struct vc4_bo *bo = to_vc4_bo(obj);
++
++ if (bo->validated_shader) {
++ DRM_ERROR("Attempting to export shader BO\n");
++ return ERR_PTR(-EINVAL);
++ }
++
++ return drm_gem_prime_export(dev, obj, flags);
++}
++
++int
++vc4_create_bo_ioctl(struct drm_device *dev, void *data,
++ struct drm_file *file_priv)
++{
++ struct drm_vc4_create_bo *args = data;
++ struct vc4_bo *bo = NULL;
++ int ret;
++
++ bo = vc4_bo_create(dev, args->size);
+ if (!bo)
+ return -ENOMEM;
+
+@@ -50,3 +330,187 @@ int vc4_dumb_create(struct drm_file *fil
+
+ return ret;
+ }
++
++int
++vc4_create_shader_bo_ioctl(struct drm_device *dev, void *data,
++ struct drm_file *file_priv)
++{
++ struct drm_vc4_create_shader_bo *args = data;
++ struct vc4_bo *bo = NULL;
++ int ret;
++
++ if (args->size == 0)
++ return -EINVAL;
++
++ if (args->size % sizeof(u64) != 0)
++ return -EINVAL;
++
++ if (args->flags != 0) {
++ DRM_INFO("Unknown flags set: 0x%08x\n", args->flags);
++ return -EINVAL;
++ }
++
++ if (args->pad != 0) {
++ DRM_INFO("Pad set: 0x%08x\n", args->pad);
++ return -EINVAL;
++ }
++
++ bo = vc4_bo_create(dev, args->size);
++ if (!bo)
++ return -ENOMEM;
++
++ ret = copy_from_user(bo->base.vaddr,
++ (void __user *)(uintptr_t)args->data,
++ args->size);
++ if (ret != 0)
++ goto fail;
++
++ bo->validated_shader = vc4_validate_shader(&bo->base);
++ if (!bo->validated_shader) {
++ ret = -EINVAL;
++ goto fail;
++ }
++
++ /* We have to create the handle after validation, to avoid
++ * races for users to do doing things like mmap the shader BO.
++ */
++ ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle);
++
++ fail:
++ drm_gem_object_unreference_unlocked(&bo->base.base);
++
++ return ret;
++}
++
++int
++vc4_mmap_bo_ioctl(struct drm_device *dev, void *data,
++ struct drm_file *file_priv)
++{
++ struct drm_vc4_mmap_bo *args = data;
++ struct drm_gem_object *gem_obj;
++
++ gem_obj = drm_gem_object_lookup(dev, file_priv, args->handle);
++ if (!gem_obj) {
++ DRM_ERROR("Failed to look up GEM BO %d\n", args->handle);
++ return -EINVAL;
++ }
++
++ /* The mmap offset was set up at BO allocation time. */
++ args->offset = drm_vma_node_offset_addr(&gem_obj->vma_node);
++
++ drm_gem_object_unreference(gem_obj);
++ return 0;
++}
++
++int vc4_mmap(struct file *filp, struct vm_area_struct *vma)
++{
++ struct drm_gem_object *gem_obj;
++ struct vc4_bo *bo;
++ int ret;
++
++ ret = drm_gem_mmap(filp, vma);
++ if (ret)
++ return ret;
++
++ gem_obj = vma->vm_private_data;
++ bo = to_vc4_bo(gem_obj);
++
++ if (bo->validated_shader) {
++ DRM_ERROR("mmaping of shader BOs not allowed.\n");
++ return -EINVAL;
++ }
++
++ /*
++ * Clear the VM_PFNMAP flag that was set by drm_gem_mmap(), and set the
++ * vm_pgoff (used as a fake buffer offset by DRM) to 0 as we want to map
++ * the whole buffer.
++ */
++ vma->vm_flags &= ~VM_PFNMAP;
++ vma->vm_pgoff = 0;
++
++ ret = dma_mmap_writecombine(bo->base.base.dev->dev, vma,
++ bo->base.vaddr, bo->base.paddr,
++ vma->vm_end - vma->vm_start);
++ if (ret)
++ drm_gem_vm_close(vma);
++
++ return ret;
++}
++
++int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
++{
++ struct vc4_bo *bo = to_vc4_bo(obj);
++
++ if (bo->validated_shader) {
++ DRM_ERROR("mmaping of shader BOs not allowed.\n");
++ return -EINVAL;
++ }
++
++ return drm_gem_cma_prime_mmap(obj, vma);
++}
++
++void *vc4_prime_vmap(struct drm_gem_object *obj)
++{
++ struct vc4_bo *bo = to_vc4_bo(obj);
++
++ if (bo->validated_shader) {
++ DRM_ERROR("mmaping of shader BOs not allowed.\n");
++ return ERR_PTR(-EINVAL);
++ }
++
++ return drm_gem_cma_prime_vmap(obj);
++}
++
++void vc4_bo_cache_init(struct drm_device *dev)
++{
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++
++ spin_lock_init(&vc4->bo_lock);
++
++ INIT_LIST_HEAD(&vc4->bo_cache.time_list);
++
++ INIT_WORK(&vc4->bo_cache.time_work, vc4_bo_cache_time_work);
++ setup_timer(&vc4->bo_cache.time_timer,
++ vc4_bo_cache_time_timer,
++ (unsigned long) dev);
++}
++
++void vc4_bo_cache_destroy(struct drm_device *dev)
++{
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++
++ del_timer(&vc4->bo_cache.time_timer);
++ cancel_work_sync(&vc4->bo_cache.time_work);
++
++ vc4_bo_cache_purge(dev);
++
++ if (vc4->bo_stats.num_allocated) {
++ DRM_ERROR("Destroying BO cache while BOs still allocated:\n");
++ vc4_bo_stats_dump(vc4);
++ }
++}
++
++#ifdef CONFIG_DEBUG_FS
++int vc4_bo_stats_debugfs(struct seq_file *m, void *unused)
++{
++ struct drm_info_node *node = (struct drm_info_node *) m->private;
++ struct drm_device *dev = node->minor->dev;
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ struct vc4_bo_stats stats;
++
++ spin_lock(&vc4->bo_lock);
++ stats = vc4->bo_stats;
++ spin_unlock(&vc4->bo_lock);
++
++ seq_printf(m, "num bos allocated: %d\n", stats.num_allocated);
++ seq_printf(m, "size bos allocated: %dkb\n", stats.size_allocated / 1024);
++ seq_printf(m, "num bos used: %d\n", (stats.num_allocated -
++ stats.num_cached));
++ seq_printf(m, "size bos used: %dkb\n", (stats.size_allocated -
++ stats.size_cached) / 1024);
++ seq_printf(m, "num bos cached: %d\n", stats.num_cached);
++ seq_printf(m, "size bos cached: %dkb\n", stats.size_cached / 1024);
++
++ return 0;
++}
++#endif
+--- a/drivers/gpu/drm/vc4/vc4_crtc.c
++++ b/drivers/gpu/drm/vc4/vc4_crtc.c
+@@ -35,6 +35,7 @@
+ #include "drm_atomic_helper.h"
+ #include "drm_crtc_helper.h"
+ #include "linux/clk.h"
++#include "drm_fb_cma_helper.h"
+ #include "linux/component.h"
+ #include "linux/of_device.h"
+ #include "vc4_drv.h"
+@@ -476,10 +477,105 @@ static irqreturn_t vc4_crtc_irq_handler(
+ return ret;
+ }
+
++struct vc4_async_flip_state {
++ struct drm_crtc *crtc;
++ struct drm_framebuffer *fb;
++ struct drm_pending_vblank_event *event;
++
++ struct vc4_seqno_cb cb;
++};
++
++/* Called when the V3D execution for the BO being flipped to is done, so that
++ * we can actually update the plane's address to point to it.
++ */
++static void
++vc4_async_page_flip_complete(struct vc4_seqno_cb *cb)
++{
++ struct vc4_async_flip_state *flip_state =
++ container_of(cb, struct vc4_async_flip_state, cb);
++ struct drm_crtc *crtc = flip_state->crtc;
++ struct drm_device *dev = crtc->dev;
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ struct drm_plane *plane = crtc->primary;
++
++ vc4_plane_async_set_fb(plane, flip_state->fb);
++ if (flip_state->event) {
++ unsigned long flags;
++ spin_lock_irqsave(&dev->event_lock, flags);
++ drm_crtc_send_vblank_event(crtc, flip_state->event);
++ spin_unlock_irqrestore(&dev->event_lock, flags);
++ }
++
++ drm_framebuffer_unreference(flip_state->fb);
++ kfree(flip_state);
++
++ up(&vc4->async_modeset);
++}
++
++/* Implements async (non-vblank-synced) page flips.
++ *
++ * The page flip ioctl needs to return immediately, so we grab the
++ * modeset semaphore on the pipe, and queue the address update for
++ * when V3D is done with the BO being flipped to.
++ */
++static int vc4_async_page_flip(struct drm_crtc *crtc,
++ struct drm_framebuffer *fb,
++ struct drm_pending_vblank_event *event,
++ uint32_t flags)
++{
++ struct drm_device *dev = crtc->dev;
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ struct drm_plane *plane = crtc->primary;
++ int ret = 0;
++ struct vc4_async_flip_state *flip_state;
++ struct drm_gem_cma_object *cma_bo = drm_fb_cma_get_gem_obj(fb, 0);
++ struct vc4_bo *bo = to_vc4_bo(&cma_bo->base);
++
++ flip_state = kzalloc(sizeof(*flip_state), GFP_KERNEL);
++ if (!flip_state)
++ return -ENOMEM;
++
++ drm_framebuffer_reference(fb);
++ flip_state->fb = fb;
++ flip_state->crtc = crtc;
++ flip_state->event = event;
++
++ /* Make sure all other async modesetes have landed. */
++ ret = down_interruptible(&vc4->async_modeset);
++ if (ret) {
++ kfree(flip_state);
++ return ret;
++ }
++
++ /* Immediately update the plane's legacy fb pointer, so that later
++ * modeset prep sees the state that will be present when the semaphore
++ * is released.
++ */
++ drm_atomic_set_fb_for_plane(plane->state, fb);
++ plane->fb = fb;
++
++ vc4_queue_seqno_cb(dev, &flip_state->cb, bo->seqno,
++ vc4_async_page_flip_complete);
++
++ /* Driver takes ownership of state on successful async commit. */
++ return 0;
++}
++
++static int vc4_page_flip(struct drm_crtc *crtc,
++ struct drm_framebuffer *fb,
++ struct drm_pending_vblank_event *event,
++ uint32_t flags)
++{
++ if (flags & DRM_MODE_PAGE_FLIP_ASYNC)
++ return vc4_async_page_flip(crtc, fb, event, flags);
++ else
++ return drm_atomic_helper_page_flip(crtc, fb, event, flags);
++}
++
+ static const struct drm_crtc_funcs vc4_crtc_funcs = {
+ .set_config = drm_atomic_helper_set_config,
+ .destroy = vc4_crtc_destroy,
+- .page_flip = drm_atomic_helper_page_flip,
++ .page_flip = vc4_page_flip,
+ .set_property = NULL,
+ .cursor_set = NULL, /* handled by drm_mode_cursor_universal */
+ .cursor_move = NULL, /* handled by drm_mode_cursor_universal */
+--- a/drivers/gpu/drm/vc4/vc4_debugfs.c
++++ b/drivers/gpu/drm/vc4/vc4_debugfs.c
+@@ -16,11 +16,14 @@
+ #include "vc4_regs.h"
+
+ static const struct drm_info_list vc4_debugfs_list[] = {
++ {"bo_stats", vc4_bo_stats_debugfs, 0},
+ {"hdmi_regs", vc4_hdmi_debugfs_regs, 0},
+ {"hvs_regs", vc4_hvs_debugfs_regs, 0},
+ {"crtc0_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)0},
+ {"crtc1_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)1},
+ {"crtc2_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)2},
++ {"v3d_ident", vc4_v3d_debugfs_ident, 0},
++ {"v3d_regs", vc4_v3d_debugfs_regs, 0},
+ };
+
+ #define VC4_DEBUGFS_ENTRIES ARRAY_SIZE(vc4_debugfs_list)
+--- a/drivers/gpu/drm/vc4/vc4_drv.c
++++ b/drivers/gpu/drm/vc4/vc4_drv.c
+@@ -14,8 +14,10 @@
+ #include <linux/module.h>
+ #include <linux/of_platform.h>
+ #include <linux/platform_device.h>
++#include <soc/bcm2835/raspberrypi-firmware.h>
+ #include "drm_fb_cma_helper.h"
+
++#include "uapi/drm/vc4_drm.h"
+ #include "vc4_drv.h"
+ #include "vc4_regs.h"
+
+@@ -63,7 +65,7 @@ static const struct file_operations vc4_
+ .open = drm_open,
+ .release = drm_release,
+ .unlocked_ioctl = drm_ioctl,
+- .mmap = drm_gem_cma_mmap,
++ .mmap = vc4_mmap,
+ .poll = drm_poll,
+ .read = drm_read,
+ #ifdef CONFIG_COMPAT
+@@ -73,16 +75,28 @@ static const struct file_operations vc4_
+ };
+
+ static const struct drm_ioctl_desc vc4_drm_ioctls[] = {
++ DRM_IOCTL_DEF_DRV(VC4_SUBMIT_CL, vc4_submit_cl_ioctl, 0),
++ DRM_IOCTL_DEF_DRV(VC4_WAIT_SEQNO, vc4_wait_seqno_ioctl, 0),
++ DRM_IOCTL_DEF_DRV(VC4_WAIT_BO, vc4_wait_bo_ioctl, 0),
++ DRM_IOCTL_DEF_DRV(VC4_CREATE_BO, vc4_create_bo_ioctl, 0),
++ DRM_IOCTL_DEF_DRV(VC4_MMAP_BO, vc4_mmap_bo_ioctl, 0),
++ DRM_IOCTL_DEF_DRV(VC4_CREATE_SHADER_BO, vc4_create_shader_bo_ioctl, 0),
+ };
+
+ static struct drm_driver vc4_drm_driver = {
+ .driver_features = (DRIVER_MODESET |
+ DRIVER_ATOMIC |
+ DRIVER_GEM |
++ DRIVER_HAVE_IRQ |
+ DRIVER_PRIME),
+ .lastclose = vc4_lastclose,
+ .preclose = vc4_drm_preclose,
+
++ .irq_handler = vc4_irq,
++ .irq_preinstall = vc4_irq_preinstall,
++ .irq_postinstall = vc4_irq_postinstall,
++ .irq_uninstall = vc4_irq_uninstall,
++
+ .enable_vblank = vc4_enable_vblank,
+ .disable_vblank = vc4_disable_vblank,
+ .get_vblank_counter = drm_vblank_count,
+@@ -92,18 +106,18 @@ static struct drm_driver vc4_drm_driver
+ .debugfs_cleanup = vc4_debugfs_cleanup,
+ #endif
+
+- .gem_free_object = drm_gem_cma_free_object,
++ .gem_free_object = vc4_free_object,
+ .gem_vm_ops = &drm_gem_cma_vm_ops,
+
+ .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+ .gem_prime_import = drm_gem_prime_import,
+- .gem_prime_export = drm_gem_prime_export,
++ .gem_prime_export = vc4_prime_export,
+ .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
+ .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
+- .gem_prime_vmap = drm_gem_cma_prime_vmap,
++ .gem_prime_vmap = vc4_prime_vmap,
+ .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
+- .gem_prime_mmap = drm_gem_cma_prime_mmap,
++ .gem_prime_mmap = vc4_prime_mmap,
+
+ .dumb_create = vc4_dumb_create,
+ .dumb_map_offset = drm_gem_cma_dumb_map_offset,
+@@ -113,6 +127,8 @@ static struct drm_driver vc4_drm_driver
+ .num_ioctls = ARRAY_SIZE(vc4_drm_ioctls),
+ .fops = &vc4_drm_fops,
+
++ .gem_obj_size = sizeof(struct vc4_bo),
++
+ .name = DRIVER_NAME,
+ .desc = DRIVER_DESC,
+ .date = DRIVER_DATE,
+@@ -153,6 +169,7 @@ static int vc4_drm_bind(struct device *d
+ struct drm_device *drm;
+ struct drm_connector *connector;
+ struct vc4_dev *vc4;
++ struct device_node *firmware_node;
+ int ret = 0;
+
+ dev->coherent_dma_mask = DMA_BIT_MASK(32);
+@@ -161,6 +178,14 @@ static int vc4_drm_bind(struct device *d
+ if (!vc4)
+ return -ENOMEM;
+
++ firmware_node = of_parse_phandle(dev->of_node, "firmware", 0);
++ vc4->firmware = rpi_firmware_get(firmware_node);
++ if (!vc4->firmware) {
++ DRM_DEBUG("Failed to get Raspberry Pi firmware reference.\n");
++ return -EPROBE_DEFER;
++ }
++ of_node_put(firmware_node);
++
+ drm = drm_dev_alloc(&vc4_drm_driver, dev);
+ if (!drm)
+ return -ENOMEM;
+@@ -170,13 +195,17 @@ static int vc4_drm_bind(struct device *d
+
+ drm_dev_set_unique(drm, dev_name(dev));
+
++ vc4_bo_cache_init(drm);
++
+ drm_mode_config_init(drm);
+ if (ret)
+ goto unref;
+
++ vc4_gem_init(drm);
++
+ ret = component_bind_all(dev, drm);
+ if (ret)
+- goto unref;
++ goto gem_destroy;
+
+ ret = drm_dev_register(drm, 0);
+ if (ret < 0)
+@@ -200,8 +229,11 @@ unregister:
+ drm_dev_unregister(drm);
+ unbind_all:
+ component_unbind_all(dev, drm);
++gem_destroy:
++ vc4_gem_destroy(drm);
+ unref:
+ drm_dev_unref(drm);
++ vc4_bo_cache_destroy(drm);
+ return ret;
+ }
+
+@@ -228,6 +260,7 @@ static struct platform_driver *const com
+ &vc4_hdmi_driver,
+ &vc4_crtc_driver,
+ &vc4_hvs_driver,
++ &vc4_v3d_driver,
+ };
+
+ static int vc4_platform_drm_probe(struct platform_device *pdev)
+--- a/drivers/gpu/drm/vc4/vc4_drv.h
++++ b/drivers/gpu/drm/vc4/vc4_drv.h
+@@ -15,8 +15,85 @@ struct vc4_dev {
+ struct vc4_hdmi *hdmi;
+ struct vc4_hvs *hvs;
+ struct vc4_crtc *crtc[3];
++ struct vc4_v3d *v3d;
+
+ struct drm_fbdev_cma *fbdev;
++ struct rpi_firmware *firmware;
++
++ /* The kernel-space BO cache. Tracks buffers that have been
++ * unreferenced by all other users (refcounts of 0!) but not
++ * yet freed, so we can do cheap allocations.
++ */
++ struct vc4_bo_cache {
++ /* Array of list heads for entries in the BO cache,
++ * based on number of pages, so we can do O(1) lookups
++ * in the cache when allocating.
++ */
++ struct list_head *size_list;
++ uint32_t size_list_size;
++
++ /* List of all BOs in the cache, ordered by age, so we
++ * can do O(1) lookups when trying to free old
++ * buffers.
++ */
++ struct list_head time_list;
++ struct work_struct time_work;
++ struct timer_list time_timer;
++ } bo_cache;
++
++ struct vc4_bo_stats {
++ u32 num_allocated;
++ u32 size_allocated;
++ u32 num_cached;
++ u32 size_cached;
++ } bo_stats;
++
++ /* Protects bo_cache and the BO stats. */
++ spinlock_t bo_lock;
++
++ /* Sequence number for the last job queued in job_list.
++ * Starts at 0 (no jobs emitted).
++ */
++ uint64_t emit_seqno;
++
++ /* Sequence number for the last completed job on the GPU.
++ * Starts at 0 (no jobs completed).
++ */
++ uint64_t finished_seqno;
++
++ /* List of all struct vc4_exec_info for jobs to be executed.
++ * The first job in the list is the one currently programmed
++ * into ct0ca/ct1ca for execution.
++ */
++ struct list_head job_list;
++ /* List of the finished vc4_exec_infos waiting to be freed by
++ * job_done_work.
++ */
++ struct list_head job_done_list;
++ spinlock_t job_lock;
++ wait_queue_head_t job_wait_queue;
++ struct work_struct job_done_work;
++
++ /* List of struct vc4_seqno_cb for callbacks to be made from a
++ * workqueue when the given seqno is passed.
++ */
++ struct list_head seqno_cb_list;
++
++ /* The binner overflow memory that's currently set up in
++ * BPOA/BPOS registers. When overflow occurs and a new one is
++ * allocated, the previous one will be moved to
++ * vc4->current_exec's free list.
++ */
++ struct vc4_bo *overflow_mem;
++ struct work_struct overflow_mem_work;
++
++ struct {
++ uint32_t last_ct0ca, last_ct1ca;
++ struct timer_list timer;
++ struct work_struct reset_work;
++ } hangcheck;
++
++ struct semaphore async_modeset;
+ };
+
+ static inline struct vc4_dev *
+@@ -27,6 +104,25 @@ to_vc4_dev(struct drm_device *dev)
+
+ struct vc4_bo {
+ struct drm_gem_cma_object base;
++
++ /* seqno of the last job to render to this BO. */
++ uint64_t seqno;
++
++ /* List entry for the BO's position in either
++ * vc4_exec_info->unref_list or vc4_dev->bo_cache.time_list
++ */
++ struct list_head unref_head;
++
++ /* Time in jiffies when the BO was put in vc4->bo_cache. */
++ unsigned long free_time;
++
++ /* List entry for the BO's position in vc4_dev->bo_cache.size_list */
++ struct list_head size_head;
++
++ /* Struct for shader validation state, if created by
++ * DRM_IOCTL_VC4_CREATE_SHADER_BO.
++ */
++ struct vc4_validated_shader_info *validated_shader;
+ };
+
+ static inline struct vc4_bo *
+@@ -35,6 +131,17 @@ to_vc4_bo(struct drm_gem_object *bo)
+ return (struct vc4_bo *)bo;
+ }
+
++struct vc4_seqno_cb {
++ struct work_struct work;
++ uint64_t seqno;
++ void (*func)(struct vc4_seqno_cb *cb);
++};
++
++struct vc4_v3d {
++ struct platform_device *pdev;
++ void __iomem *regs;
++};
++
+ struct vc4_hvs {
+ struct platform_device *pdev;
+ void __iomem *regs;
+@@ -72,9 +179,151 @@ to_vc4_encoder(struct drm_encoder *encod
+ return container_of(encoder, struct vc4_encoder, base);
+ }
+
++#define V3D_READ(offset) readl(vc4->v3d->regs + offset)
++#define V3D_WRITE(offset, val) writel(val, vc4->v3d->regs + offset)
+ #define HVS_READ(offset) readl(vc4->hvs->regs + offset)
+ #define HVS_WRITE(offset, val) writel(val, vc4->hvs->regs + offset)
+
++enum vc4_bo_mode {
++ VC4_MODE_UNDECIDED,
++ VC4_MODE_RENDER,
++ VC4_MODE_SHADER,
++};
++
++struct vc4_bo_exec_state {
++ struct drm_gem_cma_object *bo;
++ enum vc4_bo_mode mode;
++};
++
++struct vc4_exec_info {
++ /* Sequence number for this bin/render job. */
++ uint64_t seqno;
++
++ /* Kernel-space copy of the ioctl arguments */
++ struct drm_vc4_submit_cl *args;
++
++ /* This is the array of BOs that were looked up at the start of exec.
++ * Command validation will use indices into this array.
++ */
++ struct vc4_bo_exec_state *bo;
++ uint32_t bo_count;
++
++ /* Pointers for our position in vc4->job_list */
++ struct list_head head;
++
++ /* List of other BOs used in the job that need to be released
++ * once the job is complete.
++ */
++ struct list_head unref_list;
++
++ /* Current unvalidated indices into @bo loaded by the non-hardware
++ * VC4_PACKET_GEM_HANDLES.
++ */
++ uint32_t bo_index[2];
++
++ /* This is the BO where we store the validated command lists, shader
++ * records, and uniforms.
++ */
++ struct drm_gem_cma_object *exec_bo;
++
++ /**
++ * This tracks the per-shader-record state (packet 64) that
++ * determines the length of the shader record and the offset
++ * it's expected to be found at. It gets read in from the
++ * command lists.
++ */
++ struct vc4_shader_state {
++ uint8_t packet;
++ uint32_t addr;
++ /* Maximum vertex index referenced by any primitive using this
++ * shader state.
++ */
++ uint32_t max_index;
++ } *shader_state;
++
++ /** How many shader states the user declared they were using. */
++ uint32_t shader_state_size;
++ /** How many shader state records the validator has seen. */
++ uint32_t shader_state_count;
++
++ bool found_tile_binning_mode_config_packet;
++ bool found_start_tile_binning_packet;
++ bool found_increment_semaphore_packet;
++ uint8_t bin_tiles_x, bin_tiles_y;
++ struct drm_gem_cma_object *tile_bo;
++ uint32_t tile_alloc_offset;
++
++ /**
++ * Computed addresses pointing into exec_bo where we start the
++ * bin thread (ct0) and render thread (ct1).
++ */
++ uint32_t ct0ca, ct0ea;
++ uint32_t ct1ca, ct1ea;
++
++ /* Pointers to the shader recs. These paddr gets incremented as CL
++ * packets are relocated in validate_gl_shader_state, and the vaddrs
++ * (u and v) get incremented and size decremented as the shader recs
++ * themselves are validated.
++ */
++ void *shader_rec_u;
++ void *shader_rec_v;
++ uint32_t shader_rec_p;
++ uint32_t shader_rec_size;
++
++ /* Pointers to the uniform data. These pointers are incremented, and
++ * size decremented, as each batch of uniforms is uploaded.
++ */
++ void *uniforms_u;
++ void *uniforms_v;
++ uint32_t uniforms_p;
++ uint32_t uniforms_size;
++};
++
++static inline struct vc4_exec_info *
++vc4_first_job(struct vc4_dev *vc4)
++{
++ if (list_empty(&vc4->job_list))
++ return NULL;
++ return list_first_entry(&vc4->job_list, struct vc4_exec_info, head);
++}
++
++/**
++ * struct vc4_texture_sample_info - saves the offsets into the UBO for texture
++ * setup parameters.
++ *
++ * This will be used at draw time to relocate the reference to the texture
++ * contents in p0, and validate that the offset combined with
++ * width/height/stride/etc. from p1 and p2/p3 doesn't sample outside the BO.
++ * Note that the hardware treats unprovided config parameters as 0, so not all
++ * of them need to be set up for every texure sample, and we'll store ~0 as
++ * the offset to mark the unused ones.
++ *
++ * See the VC4 3D architecture guide page 41 ("Texture and Memory Lookup Unit
++ * Setup") for definitions of the texture parameters.
++ */
++struct vc4_texture_sample_info {
++ bool is_direct;
++ uint32_t p_offset[4];
++};
++
++/**
++ * struct vc4_validated_shader_info - information about validated shaders that
++ * needs to be used from command list validation.
++ *
++ * For a given shader, each time a shader state record references it, we need
++ * to verify that the shader doesn't read more uniforms than the shader state
++ * record's uniform BO pointer can provide, and we need to apply relocations
++ * and validate the shader state record's uniforms that define the texture
++ * samples.
++ */
++struct vc4_validated_shader_info
++{
++ uint32_t uniforms_size;
++ uint32_t uniforms_src_size;
++ uint32_t num_texture_samples;
++ struct vc4_texture_sample_info *texture_samples;
++};
++
+ /**
+ * _wait_for - magic (register) wait macro
+ *
+@@ -111,6 +360,18 @@ int vc4_dumb_create(struct drm_file *fil
+ struct drm_mode_create_dumb *args);
+ struct dma_buf *vc4_prime_export(struct drm_device *dev,
+ struct drm_gem_object *obj, int flags);
++int vc4_create_bo_ioctl(struct drm_device *dev, void *data,
++ struct drm_file *file_priv);
++int vc4_create_shader_bo_ioctl(struct drm_device *dev, void *data,
++ struct drm_file *file_priv);
++int vc4_mmap_bo_ioctl(struct drm_device *dev, void *data,
++ struct drm_file *file_priv);
++int vc4_mmap(struct file *filp, struct vm_area_struct *vma);
++int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma);
++void *vc4_prime_vmap(struct drm_gem_object *obj);
++void vc4_bo_cache_init(struct drm_device *dev);
++void vc4_bo_cache_destroy(struct drm_device *dev);
++int vc4_bo_stats_debugfs(struct seq_file *m, void *arg);
+
+ /* vc4_crtc.c */
+ extern struct platform_driver vc4_crtc_driver;
+@@ -126,10 +387,34 @@ void vc4_debugfs_cleanup(struct drm_mino
+ /* vc4_drv.c */
+ void __iomem *vc4_ioremap_regs(struct platform_device *dev, int index);
+
++/* vc4_gem.c */
++void vc4_gem_init(struct drm_device *dev);
++void vc4_gem_destroy(struct drm_device *dev);
++int vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
++ struct drm_file *file_priv);
++int vc4_wait_seqno_ioctl(struct drm_device *dev, void *data,
++ struct drm_file *file_priv);
++int vc4_wait_bo_ioctl(struct drm_device *dev, void *data,
++ struct drm_file *file_priv);
++void vc4_submit_next_job(struct drm_device *dev);
++int vc4_wait_for_seqno(struct drm_device *dev, uint64_t seqno,
++ uint64_t timeout_ns, bool interruptible);
++void vc4_job_handle_completed(struct vc4_dev *vc4);
++int vc4_queue_seqno_cb(struct drm_device *dev,
++ struct vc4_seqno_cb *cb, uint64_t seqno,
++ void (*func)(struct vc4_seqno_cb *cb));
++
+ /* vc4_hdmi.c */
+ extern struct platform_driver vc4_hdmi_driver;
+ int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused);
+
++/* vc4_irq.c */
++irqreturn_t vc4_irq(int irq, void *arg);
++void vc4_irq_preinstall(struct drm_device *dev);
++int vc4_irq_postinstall(struct drm_device *dev);
++void vc4_irq_uninstall(struct drm_device *dev);
++void vc4_irq_reset(struct drm_device *dev);
++
+ /* vc4_hvs.c */
+ extern struct platform_driver vc4_hvs_driver;
+ void vc4_hvs_dump_state(struct drm_device *dev);
+@@ -143,3 +428,35 @@ struct drm_plane *vc4_plane_init(struct
+ enum drm_plane_type type);
+ u32 vc4_plane_write_dlist(struct drm_plane *plane, u32 __iomem *dlist);
+ u32 vc4_plane_dlist_size(struct drm_plane_state *state);
++void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb);
++
++/* vc4_v3d.c */
++extern struct platform_driver vc4_v3d_driver;
++int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused);
++int vc4_v3d_debugfs_regs(struct seq_file *m, void *unused);
++int vc4_v3d_set_power(struct vc4_dev *vc4, bool on);
++
++/* vc4_validate.c */
++int
++vc4_validate_bin_cl(struct drm_device *dev,
++ void *validated,
++ void *unvalidated,
++ struct vc4_exec_info *exec);
++
++int
++vc4_validate_shader_recs(struct drm_device *dev, struct vc4_exec_info *exec);
++
++struct vc4_validated_shader_info *
++vc4_validate_shader(struct drm_gem_cma_object *shader_obj);
++
++bool vc4_use_bo(struct vc4_exec_info *exec,
++ uint32_t hindex,
++ enum vc4_bo_mode mode,
++ struct drm_gem_cma_object **obj);
++
++int vc4_get_rcl(struct drm_device *dev, struct vc4_exec_info *exec);
++
++bool vc4_check_tex_size(struct vc4_exec_info *exec,
++ struct drm_gem_cma_object *fbo,
++ uint32_t offset, uint8_t tiling_format,
++ uint32_t width, uint32_t height, uint8_t cpp);
+--- /dev/null
++++ b/drivers/gpu/drm/vc4/vc4_gem.c
+@@ -0,0 +1,686 @@
++/*
++ * Copyright © 2014 Broadcom
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice (including the next
++ * paragraph) shall be included in all copies or substantial portions of the
++ * Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/device.h>
++#include <linux/io.h>
++
++#include "uapi/drm/vc4_drm.h"
++#include "vc4_drv.h"
++#include "vc4_regs.h"
++#include "vc4_trace.h"
++
++static void
++vc4_queue_hangcheck(struct drm_device *dev)
++{
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++
++ mod_timer(&vc4->hangcheck.timer,
++ round_jiffies_up(jiffies + msecs_to_jiffies(100)));
++}
++
++static void
++vc4_reset(struct drm_device *dev)
++{
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++
++ DRM_INFO("Resetting GPU.\n");
++ vc4_v3d_set_power(vc4, false);
++ vc4_v3d_set_power(vc4, true);
++
++ vc4_irq_reset(dev);
++
++ /* Rearm the hangcheck -- another job might have been waiting
++ * for our hung one to get kicked off, and vc4_irq_reset()
++ * would have started it.
++ */
++ vc4_queue_hangcheck(dev);
++}
++
++static void
++vc4_reset_work(struct work_struct *work)
++{
++ struct vc4_dev *vc4 =
++ container_of(work, struct vc4_dev, hangcheck.reset_work);
++
++ vc4_reset(vc4->dev);
++}
++
++static void
++vc4_hangcheck_elapsed(unsigned long data)
++{
++ struct drm_device *dev = (struct drm_device *)data;
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ uint32_t ct0ca, ct1ca;
++
++ /* If idle, we can stop watching for hangs. */
++ if (list_empty(&vc4->job_list))
++ return;
++
++ ct0ca = V3D_READ(V3D_CTNCA(0));
++ ct1ca = V3D_READ(V3D_CTNCA(1));
++
++ /* If we've made any progress in execution, rearm the timer
++ * and wait.
++ */
++ if (ct0ca != vc4->hangcheck.last_ct0ca ||
++ ct1ca != vc4->hangcheck.last_ct1ca) {
++ vc4->hangcheck.last_ct0ca = ct0ca;
++ vc4->hangcheck.last_ct1ca = ct1ca;
++ vc4_queue_hangcheck(dev);
++ return;
++ }
++
++ /* We've gone too long with no progress, reset. This has to
++ * be done from a work struct, since resetting can sleep and
++ * this timer hook isn't allowed to.
++ */
++ schedule_work(&vc4->hangcheck.reset_work);
++}
++
++static void
++submit_cl(struct drm_device *dev, uint32_t thread, uint32_t start, uint32_t end)
++{
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++
++ /* Stop any existing thread and set state to "stopped at halt" */
++ V3D_WRITE(V3D_CTNCS(thread), V3D_CTRUN);
++ barrier();
++
++ V3D_WRITE(V3D_CTNCA(thread), start);
++ barrier();
++
++ /* Set the end address of the control list. Writing this
++ * register is what starts the job.
++ */
++ V3D_WRITE(V3D_CTNEA(thread), end);
++ barrier();
++}
++
++int
++vc4_wait_for_seqno(struct drm_device *dev, uint64_t seqno, uint64_t timeout_ns,
++ bool interruptible)
++{
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ int ret = 0;
++ unsigned long timeout_expire;
++ DEFINE_WAIT(wait);
++
++ if (vc4->finished_seqno >= seqno)
++ return 0;
++
++ if (timeout_ns == 0)
++ return -ETIME;
++
++ timeout_expire = jiffies + nsecs_to_jiffies(timeout_ns);
++
++ trace_vc4_wait_for_seqno_begin(dev, seqno, timeout_ns);
++ for (;;) {
++ prepare_to_wait(&vc4->job_wait_queue, &wait,
++ interruptible ? TASK_INTERRUPTIBLE :
++ TASK_UNINTERRUPTIBLE);
++
++ if (interruptible && signal_pending(current)) {
++ ret = -ERESTARTSYS;
++ break;
++ }
++
++ if (vc4->finished_seqno >= seqno)
++ break;
++
++ if (timeout_ns != ~0ull) {
++ if (time_after_eq(jiffies, timeout_expire)) {
++ ret = -ETIME;
++ break;
++ }
++ schedule_timeout(timeout_expire - jiffies);
++ } else {
++ schedule();
++ }
++ }
++
++ finish_wait(&vc4->job_wait_queue, &wait);
++ trace_vc4_wait_for_seqno_end(dev, seqno);
++
++ if (ret && ret != -ERESTARTSYS) {
++ DRM_ERROR("timeout waiting for render thread idle\n");
++ return ret;
++ }
++
++ return 0;
++}
++
++static void
++vc4_flush_caches(struct drm_device *dev)
++{
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++
++ /* Flush the GPU L2 caches. These caches sit on top of system
++ * L3 (the 128kb or so shared with the CPU), and are
++ * non-allocating in the L3.
++ */
++ V3D_WRITE(V3D_L2CACTL,
++ V3D_L2CACTL_L2CCLR);
++
++ V3D_WRITE(V3D_SLCACTL,
++ VC4_SET_FIELD(0xf, V3D_SLCACTL_T1CC) |
++ VC4_SET_FIELD(0xf, V3D_SLCACTL_T0CC) |
++ VC4_SET_FIELD(0xf, V3D_SLCACTL_UCC) |
++ VC4_SET_FIELD(0xf, V3D_SLCACTL_ICC));
++}
++
++/* Sets the registers for the next job to be actually be executed in
++ * the hardware.
++ *
++ * The job_lock should be held during this.
++ */
++void
++vc4_submit_next_job(struct drm_device *dev)
++{
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ struct vc4_exec_info *exec = vc4_first_job(vc4);
++
++ if (!exec)
++ return;
++
++ vc4_flush_caches(dev);
++
++ /* Disable the binner's pre-loaded overflow memory address */
++ V3D_WRITE(V3D_BPOA, 0);
++ V3D_WRITE(V3D_BPOS, 0);
++
++ if (exec->ct0ca != exec->ct0ea)
++ submit_cl(dev, 0, exec->ct0ca, exec->ct0ea);
++ submit_cl(dev, 1, exec->ct1ca, exec->ct1ea);
++}
++
++static void
++vc4_update_bo_seqnos(struct vc4_exec_info *exec, uint64_t seqno)
++{
++ struct vc4_bo *bo;
++ unsigned i;
++
++ for (i = 0; i < exec->bo_count; i++) {
++ bo = to_vc4_bo(&exec->bo[i].bo->base);
++ bo->seqno = seqno;
++ }
++
++ list_for_each_entry(bo, &exec->unref_list, unref_head) {
++ bo->seqno = seqno;
++ }
++}
++
++/* Queues a struct vc4_exec_info for execution. If no job is
++ * currently executing, then submits it.
++ *
++ * Unlike most GPUs, our hardware only handles one command list at a
++ * time. To queue multiple jobs at once, we'd need to edit the
++ * previous command list to have a jump to the new one at the end, and
++ * then bump the end address. That's a change for a later date,
++ * though.
++ */
++static void
++vc4_queue_submit(struct drm_device *dev, struct vc4_exec_info *exec)
++{
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ uint64_t seqno = ++vc4->emit_seqno;
++ unsigned long irqflags;
++
++ exec->seqno = seqno;
++ vc4_update_bo_seqnos(exec, seqno);
++
++ spin_lock_irqsave(&vc4->job_lock, irqflags);
++ list_add_tail(&exec->head, &vc4->job_list);
++
++ /* If no job was executing, kick ours off. Otherwise, it'll
++ * get started when the previous job's frame done interrupt
++ * occurs.
++ */
++ if (vc4_first_job(vc4) == exec) {
++ vc4_submit_next_job(dev);
++ vc4_queue_hangcheck(dev);
++ }
++
++ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
++}
++
++/**
++ * Looks up a bunch of GEM handles for BOs and stores the array for
++ * use in the command validator that actually writes relocated
++ * addresses pointing to them.
++ */
++static int
++vc4_cl_lookup_bos(struct drm_device *dev,
++ struct drm_file *file_priv,
++ struct vc4_exec_info *exec)
++{
++ struct drm_vc4_submit_cl *args = exec->args;
++ uint32_t *handles;
++ int ret = 0;
++ int i;
++
++ exec->bo_count = args->bo_handle_count;
++
++ if (!exec->bo_count) {
++ /* See comment on bo_index for why we have to check
++ * this.
++ */
++ DRM_ERROR("Rendering requires BOs to validate\n");
++ return -EINVAL;
++ }
++
++ exec->bo = kcalloc(exec->bo_count, sizeof(struct vc4_bo_exec_state),
++ GFP_KERNEL);
++ if (!exec->bo) {
++ DRM_ERROR("Failed to allocate validated BO pointers\n");
++ return -ENOMEM;
++ }
++
++ handles = drm_malloc_ab(exec->bo_count, sizeof(uint32_t));
++ if (!handles) {
++ DRM_ERROR("Failed to allocate incoming GEM handles\n");
++ goto fail;
++ }
++
++ ret = copy_from_user(handles,
++ (void __user *)(uintptr_t)args->bo_handles,
++ exec->bo_count * sizeof(uint32_t));
++ if (ret) {
++ DRM_ERROR("Failed to copy in GEM handles\n");
++ goto fail;
++ }
++
++ spin_lock(&file_priv->table_lock);
++ for (i = 0; i < exec->bo_count; i++) {
++ struct drm_gem_object *bo = idr_find(&file_priv->object_idr,
++ handles[i]);
++ if (!bo) {
++ DRM_ERROR("Failed to look up GEM BO %d: %d\n",
++ i, handles[i]);
++ ret = -EINVAL;
++ spin_unlock(&file_priv->table_lock);
++ goto fail;
++ }
++ drm_gem_object_reference(bo);
++ exec->bo[i].bo = (struct drm_gem_cma_object *)bo;
++ }
++ spin_unlock(&file_priv->table_lock);
++
++fail:
++ kfree(handles);
++ return 0;
++}
++
++static int
++vc4_get_bcl(struct drm_device *dev, struct vc4_exec_info *exec)
++{
++ struct drm_vc4_submit_cl *args = exec->args;
++ void *temp = NULL;
++ void *bin;
++ int ret = 0;
++ uint32_t bin_offset = 0;
++ uint32_t shader_rec_offset = roundup(bin_offset + args->bin_cl_size,
++ 16);
++ uint32_t uniforms_offset = shader_rec_offset + args->shader_rec_size;
++ uint32_t exec_size = uniforms_offset + args->uniforms_size;
++ uint32_t temp_size = exec_size + (sizeof(struct vc4_shader_state) *
++ args->shader_rec_count);
++ struct vc4_bo *bo;
++
++ if (uniforms_offset < shader_rec_offset ||
++ exec_size < uniforms_offset ||
++ args->shader_rec_count >= (UINT_MAX /
++ sizeof(struct vc4_shader_state)) ||
++ temp_size < exec_size) {
++ DRM_ERROR("overflow in exec arguments\n");
++ goto fail;
++ }
++
++ /* Allocate space where we'll store the copied in user command lists
++ * and shader records.
++ *
++ * We don't just copy directly into the BOs because we need to
++ * read the contents back for validation, and I think the
++ * bo->vaddr is uncached access.
++ */
++ temp = kmalloc(temp_size, GFP_KERNEL);
++ if (!temp) {
++ DRM_ERROR("Failed to allocate storage for copying "
++ "in bin/render CLs.\n");
++ ret = -ENOMEM;
++ goto fail;
++ }
++ bin = temp + bin_offset;
++ exec->shader_rec_u = temp + shader_rec_offset;
++ exec->uniforms_u = temp + uniforms_offset;
++ exec->shader_state = temp + exec_size;
++ exec->shader_state_size = args->shader_rec_count;
++
++ ret = copy_from_user(bin,
++ (void __user *)(uintptr_t)args->bin_cl,
++ args->bin_cl_size);
++ if (ret) {
++ DRM_ERROR("Failed to copy in bin cl\n");
++ goto fail;
++ }
++
++ ret = copy_from_user(exec->shader_rec_u,
++ (void __user *)(uintptr_t)args->shader_rec,
++ args->shader_rec_size);
++ if (ret) {
++ DRM_ERROR("Failed to copy in shader recs\n");
++ goto fail;
++ }
++
++ ret = copy_from_user(exec->uniforms_u,
++ (void __user *)(uintptr_t)args->uniforms,
++ args->uniforms_size);
++ if (ret) {
++ DRM_ERROR("Failed to copy in uniforms cl\n");
++ goto fail;
++ }
++
++ bo = vc4_bo_create(dev, exec_size);
++ if (!bo) {
++ DRM_ERROR("Couldn't allocate BO for binning\n");
++ ret = PTR_ERR(exec->exec_bo);
++ goto fail;
++ }
++ exec->exec_bo = &bo->base;
++
++ list_add_tail(&to_vc4_bo(&exec->exec_bo->base)->unref_head,
++ &exec->unref_list);
++
++ exec->ct0ca = exec->exec_bo->paddr + bin_offset;
++
++ exec->shader_rec_v = exec->exec_bo->vaddr + shader_rec_offset;
++ exec->shader_rec_p = exec->exec_bo->paddr + shader_rec_offset;
++ exec->shader_rec_size = args->shader_rec_size;
++
++ exec->uniforms_v = exec->exec_bo->vaddr + uniforms_offset;
++ exec->uniforms_p = exec->exec_bo->paddr + uniforms_offset;
++ exec->uniforms_size = args->uniforms_size;
++
++ ret = vc4_validate_bin_cl(dev,
++ exec->exec_bo->vaddr + bin_offset,
++ bin,
++ exec);
++ if (ret)
++ goto fail;
++
++ ret = vc4_validate_shader_recs(dev, exec);
++
++fail:
++ kfree(temp);
++ return ret;
++}
++
++static void
++vc4_complete_exec(struct vc4_exec_info *exec)
++{
++ unsigned i;
++
++ if (exec->bo) {
++ for (i = 0; i < exec->bo_count; i++)
++ drm_gem_object_unreference(&exec->bo[i].bo->base);
++ kfree(exec->bo);
++ }
++
++ while (!list_empty(&exec->unref_list)) {
++ struct vc4_bo *bo = list_first_entry(&exec->unref_list,
++ struct vc4_bo, unref_head);
++ list_del(&bo->unref_head);
++ drm_gem_object_unreference(&bo->base.base);
++ }
++
++ kfree(exec);
++}
++
++void
++vc4_job_handle_completed(struct vc4_dev *vc4)
++{
++ unsigned long irqflags;
++ struct vc4_seqno_cb *cb, *cb_temp;
++
++ spin_lock_irqsave(&vc4->job_lock, irqflags);
++ while (!list_empty(&vc4->job_done_list)) {
++ struct vc4_exec_info *exec =
++ list_first_entry(&vc4->job_done_list,
++ struct vc4_exec_info, head);
++ list_del(&exec->head);
++
++ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
++ vc4_complete_exec(exec);
++ spin_lock_irqsave(&vc4->job_lock, irqflags);
++ }
++ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
++
++ list_for_each_entry_safe(cb, cb_temp, &vc4->seqno_cb_list, work.entry) {
++ if (cb->seqno <= vc4->finished_seqno) {
++ list_del_init(&cb->work.entry);
++ schedule_work(&cb->work);
++ }
++ }
++}
++
++static void vc4_seqno_cb_work(struct work_struct *work)
++{
++ struct vc4_seqno_cb *cb = container_of(work, struct vc4_seqno_cb, work);
++ cb->func(cb);
++}
++
++int vc4_queue_seqno_cb(struct drm_device *dev,
++ struct vc4_seqno_cb *cb, uint64_t seqno,
++ void (*func)(struct vc4_seqno_cb *cb))
++{
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ int ret = 0;
++
++ cb->func = func;
++ INIT_WORK(&cb->work, vc4_seqno_cb_work);
++
++ mutex_lock(&dev->struct_mutex);
++ if (seqno > vc4->finished_seqno) {
++ cb->seqno = seqno;
++ list_add_tail(&cb->work.entry, &vc4->seqno_cb_list);
++ } else {
++ schedule_work(&cb->work);
++ }
++ mutex_unlock(&dev->struct_mutex);
++
++ return ret;
++}
++
++/* Scheduled when any job has been completed, this walks the list of
++ * jobs that had completed and unrefs their BOs and frees their exec
++ * structs.
++ */
++static void
++vc4_job_done_work(struct work_struct *work)
++{
++ struct vc4_dev *vc4 =
++ container_of(work, struct vc4_dev, job_done_work);
++ struct drm_device *dev = vc4->dev;
++
++ /* Need the struct lock for drm_gem_object_unreference(). */
++ mutex_lock(&dev->struct_mutex);
++ vc4_job_handle_completed(vc4);
++ mutex_unlock(&dev->struct_mutex);
++}
++
++static int
++vc4_wait_for_seqno_ioctl_helper(struct drm_device *dev,
++ uint64_t seqno,
++ uint64_t *timeout_ns)
++{
++ unsigned long start = jiffies;
++ int ret = vc4_wait_for_seqno(dev, seqno, *timeout_ns, true);
++
++ if ((ret == -EINTR || ret == -ERESTARTSYS) && *timeout_ns != ~0ull) {
++ uint64_t delta = jiffies_to_nsecs(jiffies - start);
++ if (*timeout_ns >= delta)
++ *timeout_ns -= delta;
++ }
++
++ return ret;
++}
++
++int
++vc4_wait_seqno_ioctl(struct drm_device *dev, void *data,
++ struct drm_file *file_priv)
++{
++ struct drm_vc4_wait_seqno *args = data;
++
++ return vc4_wait_for_seqno_ioctl_helper(dev, args->seqno,
++ &args->timeout_ns);
++}
++
++int
++vc4_wait_bo_ioctl(struct drm_device *dev, void *data,
++ struct drm_file *file_priv)
++{
++ int ret;
++ struct drm_vc4_wait_bo *args = data;
++ struct drm_gem_object *gem_obj;
++ struct vc4_bo *bo;
++
++ gem_obj = drm_gem_object_lookup(dev, file_priv, args->handle);
++ if (!gem_obj) {
++ DRM_ERROR("Failed to look up GEM BO %d\n", args->handle);
++ return -EINVAL;
++ }
++ bo = to_vc4_bo(gem_obj);
++
++ ret = vc4_wait_for_seqno_ioctl_helper(dev, bo->seqno, &args->timeout_ns);
++
++ drm_gem_object_unreference(gem_obj);
++ return ret;
++}
++
++/**
++ * Submits a command list to the VC4.
++ *
++ * This is what is called batchbuffer emitting on other hardware.
++ */
++int
++vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
++ struct drm_file *file_priv)
++{
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ struct drm_vc4_submit_cl *args = data;
++ struct vc4_exec_info *exec;
++ int ret;
++
++ if ((args->flags & ~VC4_SUBMIT_CL_USE_CLEAR_COLOR) != 0) {
++ DRM_ERROR("Unknown flags: 0x%02x\n", args->flags);
++ return -EINVAL;
++ }
++
++ exec = kcalloc(1, sizeof(*exec), GFP_KERNEL);
++ if (!exec) {
++ DRM_ERROR("malloc failure on exec struct\n");
++ return -ENOMEM;
++ }
++
++ exec->args = args;
++ INIT_LIST_HEAD(&exec->unref_list);
++
++ mutex_lock(&dev->struct_mutex);
++
++ ret = vc4_cl_lookup_bos(dev, file_priv, exec);
++ if (ret)
++ goto fail;
++
++ if (exec->args->bin_cl_size != 0) {
++ ret = vc4_get_bcl(dev, exec);
++ if (ret)
++ goto fail;
++ } else {
++ exec->ct0ca = exec->ct0ea = 0;
++ }
++
++ ret = vc4_get_rcl(dev, exec);
++ if (ret)
++ goto fail;
++
++ /* Clear this out of the struct we'll be putting in the queue,
++ * since it's part of our stack.
++ */
++ exec->args = NULL;
++
++ vc4_queue_submit(dev, exec);
++
++ /* Return the seqno for our job. */
++ args->seqno = vc4->emit_seqno;
++
++ mutex_unlock(&dev->struct_mutex);
++
++ return 0;
++
++fail:
++ vc4_complete_exec(exec);
++
++ mutex_unlock(&dev->struct_mutex);
++
++ return ret;
++}
++
++void
++vc4_gem_init(struct drm_device *dev)
++{
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++
++ INIT_LIST_HEAD(&vc4->job_list);
++ INIT_LIST_HEAD(&vc4->job_done_list);
++ INIT_LIST_HEAD(&vc4->seqno_cb_list);
++ spin_lock_init(&vc4->job_lock);
++
++ INIT_WORK(&vc4->hangcheck.reset_work, vc4_reset_work);
++ setup_timer(&vc4->hangcheck.timer,
++ vc4_hangcheck_elapsed,
++ (unsigned long) dev);
++
++ INIT_WORK(&vc4->job_done_work, vc4_job_done_work);
++}
++
++void
++vc4_gem_destroy(struct drm_device *dev)
++{
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++
++ /* Waiting for exec to finish would need to be done before
++ * unregistering V3D.
++ */
++ WARN_ON(vc4->emit_seqno != vc4->finished_seqno);
++
++ /* V3D should already have disabled its interrupt and cleared
++ * the overflow allocation registers. Now free the object.
++ */
++ if (vc4->overflow_mem) {
++ drm_gem_object_unreference_unlocked(&vc4->overflow_mem->base.base);
++ vc4->overflow_mem = NULL;
++ }
++
++ vc4_bo_cache_destroy(dev);
++}
+--- /dev/null
++++ b/drivers/gpu/drm/vc4/vc4_irq.c
+@@ -0,0 +1,211 @@
++/*
++ * Copyright © 2014 Broadcom
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice (including the next
++ * paragraph) shall be included in all copies or substantial portions of the
++ * Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++/** DOC: Interrupt management for the V3D engine.
++ *
++ * We have an interrupt status register (V3D_INTCTL) which reports
++ * interrupts, and where writing 1 bits clears those interrupts.
++ * There are also a pair of interrupt registers
++ * (V3D_INTENA/V3D_INTDIS) where writing a 1 to their bits enables or
++ * disables that specific interrupt, and 0s written are ignored
++ * (reading either one returns the set of enabled interrupts).
++ *
++ * When we take a render frame interrupt, we need to wake the
++ * processes waiting for some frame to be done, and get the next frame
++ * submitted ASAP (so the hardware doesn't sit idle when there's work
++ * to do).
++ *
++ * When we take the binner out of memory interrupt, we need to
++ * allocate some new memory and pass it to the binner so that the
++ * current job can make progress.
++ */
++
++#include "vc4_drv.h"
++#include "vc4_regs.h"
++
++#define V3D_DRIVER_IRQS (V3D_INT_OUTOMEM | \
++ V3D_INT_FRDONE)
++
++DECLARE_WAIT_QUEUE_HEAD(render_wait);
++
++static void
++vc4_overflow_mem_work(struct work_struct *work)
++{
++ struct vc4_dev *vc4 =
++ container_of(work, struct vc4_dev, overflow_mem_work);
++ struct drm_device *dev = vc4->dev;
++ struct vc4_bo *bo;
++
++ bo = vc4_bo_create(dev, 256 * 1024);
++ if (!bo) {
++ DRM_ERROR("Couldn't allocate binner overflow mem\n");
++ return;
++ }
++
++ /* If there's a job executing currently, then our previous
++ * overflow allocation is getting used in that job and we need
++ * to queue it to be released when the job is done. But if no
++ * job is executing at all, then we can free the old overflow
++ * object direcctly.
++ *
++ * No lock necessary for this pointer since we're the only
++ * ones that update the pointer, and our workqueue won't
++ * reenter.
++ */
++ if (vc4->overflow_mem) {
++ struct vc4_exec_info *current_exec;
++ unsigned long irqflags;
++
++ spin_lock_irqsave(&vc4->job_lock, irqflags);
++ current_exec = vc4_first_job(vc4);
++ if (current_exec) {
++ vc4->overflow_mem->seqno = vc4->finished_seqno + 1;
++ list_add_tail(&vc4->overflow_mem->unref_head,
++ &current_exec->unref_list);
++ vc4->overflow_mem = NULL;
++ }
++ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
++ }
++
++ if (vc4->overflow_mem) {
++ drm_gem_object_unreference_unlocked(&vc4->overflow_mem->base.base);
++ }
++ vc4->overflow_mem = bo;
++
++ V3D_WRITE(V3D_BPOA, bo->base.paddr);
++ V3D_WRITE(V3D_BPOS, bo->base.base.size);
++ V3D_WRITE(V3D_INTCTL, V3D_INT_OUTOMEM);
++ V3D_WRITE(V3D_INTENA, V3D_INT_OUTOMEM);
++}
++
++static void
++vc4_irq_finish_job(struct drm_device *dev)
++{
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ struct vc4_exec_info *exec = vc4_first_job(vc4);
++
++ if (!exec)
++ return;
++
++ vc4->finished_seqno++;
++ list_move_tail(&exec->head, &vc4->job_done_list);
++ vc4_submit_next_job(dev);
++
++ wake_up_all(&vc4->job_wait_queue);
++ schedule_work(&vc4->job_done_work);
++}
++
++irqreturn_t
++vc4_irq(int irq, void *arg)
++{
++ struct drm_device *dev = arg;
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ uint32_t intctl;
++ irqreturn_t status = IRQ_NONE;
++
++ barrier();
++ intctl = V3D_READ(V3D_INTCTL);
++
++ /* Acknowledge the interrupts we're handling here. The render
++ * frame done interrupt will be cleared, while OUTOMEM will
++ * stay high until the underlying cause is cleared.
++ */
++ V3D_WRITE(V3D_INTCTL, intctl);
++
++ if (intctl & V3D_INT_OUTOMEM) {
++ /* Disable OUTOMEM until the work is done. */
++ V3D_WRITE(V3D_INTDIS, V3D_INT_OUTOMEM);
++ schedule_work(&vc4->overflow_mem_work);
++ status = IRQ_HANDLED;
++ }
++
++ if (intctl & V3D_INT_FRDONE) {
++ spin_lock(&vc4->job_lock);
++ vc4_irq_finish_job(dev);
++ spin_unlock(&vc4->job_lock);
++ status = IRQ_HANDLED;
++ }
++
++ return status;
++}
++
++void
++vc4_irq_preinstall(struct drm_device *dev)
++{
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++
++ init_waitqueue_head(&vc4->job_wait_queue);
++ INIT_WORK(&vc4->overflow_mem_work, vc4_overflow_mem_work);
++
++ /* Clear any pending interrupts someone might have left around
++ * for us.
++ */
++ V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS);
++}
++
++int
++vc4_irq_postinstall(struct drm_device *dev)
++{
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++
++ /* Enable both the render done and out of memory interrupts. */
++ V3D_WRITE(V3D_INTENA, V3D_DRIVER_IRQS);
++
++ return 0;
++}
++
++void
++vc4_irq_uninstall(struct drm_device *dev)
++{
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++
++ /* Disable sending interrupts for our driver's IRQs. */
++ V3D_WRITE(V3D_INTDIS, V3D_DRIVER_IRQS);
++
++ /* Clear any pending interrupts we might have left. */
++ V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS);
++
++ cancel_work_sync(&vc4->overflow_mem_work);
++}
++
++/** Reinitializes interrupt registers when a GPU reset is performed. */
++void vc4_irq_reset(struct drm_device *dev)
++{
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ unsigned long irqflags;
++
++ /* Acknowledge any stale IRQs. */
++ V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS);
++
++ /*
++ * Turn all our interrupts on. Binner out of memory is the
++ * only one we expect to trigger at this point, since we've
++ * just come from poweron and haven't supplied any overflow
++ * memory yet.
++ */
++ V3D_WRITE(V3D_INTENA, V3D_DRIVER_IRQS);
++
++ spin_lock_irqsave(&vc4->job_lock, irqflags);
++ vc4_irq_finish_job(dev);
++ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
++}
+--- a/drivers/gpu/drm/vc4/vc4_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_kms.c
+@@ -15,6 +15,7 @@
+ */
+
+ #include "drm_crtc.h"
++#include "drm_atomic.h"
+ #include "drm_atomic_helper.h"
+ #include "drm_crtc_helper.h"
+ #include "drm_plane_helper.h"
+@@ -29,10 +30,151 @@ static void vc4_output_poll_changed(stru
+ drm_fbdev_cma_hotplug_event(vc4->fbdev);
+ }
+
++struct vc4_commit {
++ struct drm_device *dev;
++ struct drm_atomic_state *state;
++ struct vc4_seqno_cb cb;
++};
++
++static void
++vc4_atomic_complete_commit(struct vc4_commit *c)
++{
++ struct drm_atomic_state *state = c->state;
++ struct drm_device *dev = state->dev;
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++
++ drm_atomic_helper_commit_modeset_disables(dev, state);
++
++ drm_atomic_helper_commit_planes(dev, state);
++
++ drm_atomic_helper_commit_modeset_enables(dev, state);
++
++ drm_atomic_helper_wait_for_vblanks(dev, state);
++
++ drm_atomic_helper_cleanup_planes(dev, state);
++
++ drm_atomic_state_free(state);
++
++ up(&vc4->async_modeset);
++
++ kfree(c);
++}
++
++static void
++vc4_atomic_complete_commit_seqno_cb(struct vc4_seqno_cb *cb)
++{
++ struct vc4_commit *c = container_of(cb, struct vc4_commit, cb);
++
++ vc4_atomic_complete_commit(c);
++}
++
++static struct vc4_commit *commit_init(struct drm_atomic_state *state)
++{
++ struct vc4_commit *c = kzalloc(sizeof(*c), GFP_KERNEL);
++
++ if (!c)
++ return NULL;
++ c->dev = state->dev;
++ c->state = state;
++
++ return c;
++}
++
++/**
++ * vc4_atomic_commit - commit validated state object
++ * @dev: DRM device
++ * @state: the driver state object
++ * @async: asynchronous commit
++ *
++ * This function commits a with drm_atomic_helper_check() pre-validated state
++ * object. This can still fail when e.g. the framebuffer reservation fails. For
++ * now this doesn't implement asynchronous commits.
++ *
++ * RETURNS
++ * Zero for success or -errno.
++ */
++static int vc4_atomic_commit(struct drm_device *dev,
++ struct drm_atomic_state *state,
++ bool async)
++{
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ int ret;
++ int i;
++ uint64_t wait_seqno = 0;
++ struct vc4_commit *c;
++
++ c = commit_init(state);
++ if (!c)
++ return -ENOMEM;
++
++ /* Make sure that any outstanding modesets have finished. */
++ ret = down_interruptible(&vc4->async_modeset);
++ if (ret) {
++ kfree(c);
++ return ret;
++ }
++
++ ret = drm_atomic_helper_prepare_planes(dev, state);
++ if (ret) {
++ kfree(c);
++ up(&vc4->async_modeset);
++ return ret;
++ }
++
++ for (i = 0; i < dev->mode_config.num_total_plane; i++) {
++ struct drm_plane *plane = state->planes[i];
++ struct drm_plane_state *new_state = state->plane_states[i];
++
++ if (!plane)
++ continue;
++
++ if ((plane->state->fb != new_state->fb) && new_state->fb) {
++ struct drm_gem_cma_object *cma_bo =
++ drm_fb_cma_get_gem_obj(new_state->fb, 0);
++ struct vc4_bo *bo = to_vc4_bo(&cma_bo->base);
++ wait_seqno = max(bo->seqno, wait_seqno);
++ }
++ }
++
++ /*
++ * This is the point of no return - everything below never fails except
++ * when the hw goes bonghits. Which means we can commit the new state on
++ * the software side now.
++ */
++
++ drm_atomic_helper_swap_state(dev, state);
++
++ /*
++ * Everything below can be run asynchronously without the need to grab
++ * any modeset locks at all under one condition: It must be guaranteed
++ * that the asynchronous work has either been cancelled (if the driver
++ * supports it, which at least requires that the framebuffers get
++ * cleaned up with drm_atomic_helper_cleanup_planes()) or completed
++ * before the new state gets committed on the software side with
++ * drm_atomic_helper_swap_state().
++ *
++ * This scheme allows new atomic state updates to be prepared and
++ * checked in parallel to the asynchronous completion of the previous
++ * update. Which is important since compositors need to figure out the
++ * composition of the next frame right after having submitted the
++ * current layout.
++ */
++
++ if (async) {
++ vc4_queue_seqno_cb(dev, &c->cb, wait_seqno,
++ vc4_atomic_complete_commit_seqno_cb);
++ } else {
++ vc4_wait_for_seqno(dev, wait_seqno, ~0ull, false);
++ vc4_atomic_complete_commit(c);
++ }
++
++ return 0;
++}
++
+ static const struct drm_mode_config_funcs vc4_mode_funcs = {
+ .output_poll_changed = vc4_output_poll_changed,
+ .atomic_check = drm_atomic_helper_check,
+- .atomic_commit = drm_atomic_helper_commit,
++ .atomic_commit = vc4_atomic_commit,
+ .fb_create = drm_fb_cma_create,
+ };
+
+@@ -41,6 +183,8 @@ int vc4_kms_load(struct drm_device *dev)
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ int ret;
+
++ sema_init(&vc4->async_modeset, 1);
++
+ ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
+ if (ret < 0) {
+ dev_err(dev->dev, "failed to initialize vblank\n");
+@@ -51,6 +195,8 @@ int vc4_kms_load(struct drm_device *dev)
+ dev->mode_config.max_height = 2048;
+ dev->mode_config.funcs = &vc4_mode_funcs;
+ dev->mode_config.preferred_depth = 24;
++ dev->mode_config.async_page_flip = true;
++
+ dev->vblank_disable_allowed = true;
+
+ drm_mode_config_reset(dev);
+--- /dev/null
++++ b/drivers/gpu/drm/vc4/vc4_packet.h
+@@ -0,0 +1,384 @@
++/*
++ * Copyright © 2014 Broadcom
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice (including the next
++ * paragraph) shall be included in all copies or substantial portions of the
++ * Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#ifndef VC4_PACKET_H
++#define VC4_PACKET_H
++
++#include "vc4_regs.h" /* for VC4_MASK, VC4_GET_FIELD, VC4_SET_FIELD */
++
++enum vc4_packet {
++ VC4_PACKET_HALT = 0,
++ VC4_PACKET_NOP = 1,
++
++ VC4_PACKET_FLUSH = 4,
++ VC4_PACKET_FLUSH_ALL = 5,
++ VC4_PACKET_START_TILE_BINNING = 6,
++ VC4_PACKET_INCREMENT_SEMAPHORE = 7,
++ VC4_PACKET_WAIT_ON_SEMAPHORE = 8,
++
++ VC4_PACKET_BRANCH = 16,
++ VC4_PACKET_BRANCH_TO_SUB_LIST = 17,
++
++ VC4_PACKET_STORE_MS_TILE_BUFFER = 24,
++ VC4_PACKET_STORE_MS_TILE_BUFFER_AND_EOF = 25,
++ VC4_PACKET_STORE_FULL_RES_TILE_BUFFER = 26,
++ VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER = 27,
++ VC4_PACKET_STORE_TILE_BUFFER_GENERAL = 28,
++ VC4_PACKET_LOAD_TILE_BUFFER_GENERAL = 29,
++
++ VC4_PACKET_GL_INDEXED_PRIMITIVE = 32,
++ VC4_PACKET_GL_ARRAY_PRIMITIVE = 33,
++
++ VC4_PACKET_COMPRESSED_PRIMITIVE = 48,
++ VC4_PACKET_CLIPPED_COMPRESSED_PRIMITIVE = 49,
++
++ VC4_PACKET_PRIMITIVE_LIST_FORMAT = 56,
++
++ VC4_PACKET_GL_SHADER_STATE = 64,
++ VC4_PACKET_NV_SHADER_STATE = 65,
++ VC4_PACKET_VG_SHADER_STATE = 66,
++
++ VC4_PACKET_CONFIGURATION_BITS = 96,
++ VC4_PACKET_FLAT_SHADE_FLAGS = 97,
++ VC4_PACKET_POINT_SIZE = 98,
++ VC4_PACKET_LINE_WIDTH = 99,
++ VC4_PACKET_RHT_X_BOUNDARY = 100,
++ VC4_PACKET_DEPTH_OFFSET = 101,
++ VC4_PACKET_CLIP_WINDOW = 102,
++ VC4_PACKET_VIEWPORT_OFFSET = 103,
++ VC4_PACKET_Z_CLIPPING = 104,
++ VC4_PACKET_CLIPPER_XY_SCALING = 105,
++ VC4_PACKET_CLIPPER_Z_SCALING = 106,
++
++ VC4_PACKET_TILE_BINNING_MODE_CONFIG = 112,
++ VC4_PACKET_TILE_RENDERING_MODE_CONFIG = 113,
++ VC4_PACKET_CLEAR_COLORS = 114,
++ VC4_PACKET_TILE_COORDINATES = 115,
++
++ /* Not an actual hardware packet -- this is what we use to put
++ * references to GEM bos in the command stream, since we need the u32
++ * int the actual address packet in order to store the offset from the
++ * start of the BO.
++ */
++ VC4_PACKET_GEM_HANDLES = 254,
++} __attribute__ ((__packed__));
++
++#define VC4_PACKET_HALT_SIZE 1
++#define VC4_PACKET_NOP_SIZE 1
++#define VC4_PACKET_FLUSH_SIZE 1
++#define VC4_PACKET_FLUSH_ALL_SIZE 1
++#define VC4_PACKET_START_TILE_BINNING_SIZE 1
++#define VC4_PACKET_INCREMENT_SEMAPHORE_SIZE 1
++#define VC4_PACKET_WAIT_ON_SEMAPHORE_SIZE 1
++#define VC4_PACKET_BRANCH_SIZE 5
++#define VC4_PACKET_BRANCH_TO_SUB_LIST_SIZE 5
++#define VC4_PACKET_STORE_MS_TILE_BUFFER_SIZE 1
++#define VC4_PACKET_STORE_MS_TILE_BUFFER_AND_EOF_SIZE 1
++#define VC4_PACKET_STORE_FULL_RES_TILE_BUFFER_SIZE 5
++#define VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER_SIZE 5
++#define VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE 7
++#define VC4_PACKET_LOAD_TILE_BUFFER_GENERAL_SIZE 7
++#define VC4_PACKET_GL_INDEXED_PRIMITIVE_SIZE 14
++#define VC4_PACKET_GL_ARRAY_PRIMITIVE_SIZE 10
++#define VC4_PACKET_COMPRESSED_PRIMITIVE_SIZE 1
++#define VC4_PACKET_CLIPPED_COMPRESSED_PRIMITIVE_SIZE 1
++#define VC4_PACKET_PRIMITIVE_LIST_FORMAT_SIZE 2
++#define VC4_PACKET_GL_SHADER_STATE_SIZE 5
++#define VC4_PACKET_NV_SHADER_STATE_SIZE 5
++#define VC4_PACKET_VG_SHADER_STATE_SIZE 5
++#define VC4_PACKET_CONFIGURATION_BITS_SIZE 4
++#define VC4_PACKET_FLAT_SHADE_FLAGS_SIZE 5
++#define VC4_PACKET_POINT_SIZE_SIZE 5
++#define VC4_PACKET_LINE_WIDTH_SIZE 5
++#define VC4_PACKET_RHT_X_BOUNDARY_SIZE 3
++#define VC4_PACKET_DEPTH_OFFSET_SIZE 5
++#define VC4_PACKET_CLIP_WINDOW_SIZE 9
++#define VC4_PACKET_VIEWPORT_OFFSET_SIZE 5
++#define VC4_PACKET_Z_CLIPPING_SIZE 9
++#define VC4_PACKET_CLIPPER_XY_SCALING_SIZE 9
++#define VC4_PACKET_CLIPPER_Z_SCALING_SIZE 9
++#define VC4_PACKET_TILE_BINNING_MODE_CONFIG_SIZE 16
++#define VC4_PACKET_TILE_RENDERING_MODE_CONFIG_SIZE 11
++#define VC4_PACKET_CLEAR_COLORS_SIZE 14
++#define VC4_PACKET_TILE_COORDINATES_SIZE 3
++#define VC4_PACKET_GEM_HANDLES_SIZE 9
++
++/** @{
++ * Bits used by packets like VC4_PACKET_STORE_TILE_BUFFER_GENERAL and
++ * VC4_PACKET_TILE_RENDERING_MODE_CONFIG.
++*/
++#define VC4_TILING_FORMAT_LINEAR 0
++#define VC4_TILING_FORMAT_T 1
++#define VC4_TILING_FORMAT_LT 2
++/** @} */
++
++/** @{
++ *
++ * low bits of VC4_PACKET_STORE_FULL_RES_TILE_BUFFER and
++ * VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER.
++ */
++#define VC4_LOADSTORE_FULL_RES_EOF (1 << 3)
++#define VC4_LOADSTORE_FULL_RES_DISABLE_CLEAR_ALL (1 << 2)
++#define VC4_LOADSTORE_FULL_RES_DISABLE_ZS (1 << 1)
++#define VC4_LOADSTORE_FULL_RES_DISABLE_COLOR (1 << 0)
++
++/** @{
++ *
++ * byte 2 of VC4_PACKET_STORE_TILE_BUFFER_GENERAL and
++ * VC4_PACKET_LOAD_TILE_BUFFER_GENERAL (low bits of the address)
++ */
++
++#define VC4_LOADSTORE_TILE_BUFFER_EOF (1 << 3)
++#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_VG_MASK (1 << 2)
++#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_ZS (1 << 1)
++#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_COLOR (1 << 0)
++
++/** @} */
++
++/** @{
++ *
++ * byte 0-1 of VC4_PACKET_STORE_TILE_BUFFER_GENERAL and
++ * VC4_PACKET_LOAD_TILE_BUFFER_GENERAL
++ */
++#define VC4_STORE_TILE_BUFFER_DISABLE_VG_MASK_CLEAR (1 << 15)
++#define VC4_STORE_TILE_BUFFER_DISABLE_ZS_CLEAR (1 << 14)
++#define VC4_STORE_TILE_BUFFER_DISABLE_COLOR_CLEAR (1 << 13)
++#define VC4_STORE_TILE_BUFFER_DISABLE_SWAP (1 << 12)
++
++#define VC4_LOADSTORE_TILE_BUFFER_FORMAT_MASK VC4_MASK(9, 8)
++#define VC4_LOADSTORE_TILE_BUFFER_FORMAT_SHIFT 8
++#define VC4_LOADSTORE_TILE_BUFFER_RGBA8888 0
++#define VC4_LOADSTORE_TILE_BUFFER_BGR565_DITHER 1
++#define VC4_LOADSTORE_TILE_BUFFER_BGR565 2
++/** @} */
++
++/** @{
++ *
++ * byte 0 of VC4_PACKET_STORE_TILE_BUFFER_GENERAL and
++ * VC4_PACKET_LOAD_TILE_BUFFER_GENERAL
++ */
++#define VC4_STORE_TILE_BUFFER_MODE_MASK VC4_MASK(7, 6)
++#define VC4_STORE_TILE_BUFFER_MODE_SHIFT 6
++#define VC4_STORE_TILE_BUFFER_MODE_SAMPLE0 (0 << 6)
++#define VC4_STORE_TILE_BUFFER_MODE_DECIMATE_X4 (1 << 6)
++#define VC4_STORE_TILE_BUFFER_MODE_DECIMATE_X16 (2 << 6)
++
++/** The values of the field are VC4_TILING_FORMAT_* */
++#define VC4_LOADSTORE_TILE_BUFFER_TILING_MASK VC4_MASK(5, 4)
++#define VC4_LOADSTORE_TILE_BUFFER_TILING_SHIFT 4
++
++#define VC4_LOADSTORE_TILE_BUFFER_BUFFER_MASK VC4_MASK(2, 0)
++#define VC4_LOADSTORE_TILE_BUFFER_BUFFER_SHIFT 0
++#define VC4_LOADSTORE_TILE_BUFFER_NONE 0
++#define VC4_LOADSTORE_TILE_BUFFER_COLOR 1
++#define VC4_LOADSTORE_TILE_BUFFER_ZS 2
++#define VC4_LOADSTORE_TILE_BUFFER_Z 3
++#define VC4_LOADSTORE_TILE_BUFFER_VG_MASK 4
++#define VC4_LOADSTORE_TILE_BUFFER_FULL 5
++/** @} */
++
++#define VC4_INDEX_BUFFER_U8 (0 << 4)
++#define VC4_INDEX_BUFFER_U16 (1 << 4)
++
++/* This flag is only present in NV shader state. */
++#define VC4_SHADER_FLAG_SHADED_CLIP_COORDS (1 << 3)
++#define VC4_SHADER_FLAG_ENABLE_CLIPPING (1 << 2)
++#define VC4_SHADER_FLAG_VS_POINT_SIZE (1 << 1)
++#define VC4_SHADER_FLAG_FS_SINGLE_THREAD (1 << 0)
++
++/** @{ byte 2 of config bits. */
++#define VC4_CONFIG_BITS_EARLY_Z_UPDATE (1 << 1)
++#define VC4_CONFIG_BITS_EARLY_Z (1 << 0)
++/** @} */
++
++/** @{ byte 1 of config bits. */
++#define VC4_CONFIG_BITS_Z_UPDATE (1 << 7)
++/** same values in this 3-bit field as PIPE_FUNC_* */
++#define VC4_CONFIG_BITS_DEPTH_FUNC_SHIFT 4
++#define VC4_CONFIG_BITS_COVERAGE_READ_LEAVE (1 << 3)
++
++#define VC4_CONFIG_BITS_COVERAGE_UPDATE_NONZERO (0 << 1)
++#define VC4_CONFIG_BITS_COVERAGE_UPDATE_ODD (1 << 1)
++#define VC4_CONFIG_BITS_COVERAGE_UPDATE_OR (2 << 1)
++#define VC4_CONFIG_BITS_COVERAGE_UPDATE_ZERO (3 << 1)
++
++#define VC4_CONFIG_BITS_COVERAGE_PIPE_SELECT (1 << 0)
++/** @} */
++
++/** @{ byte 0 of config bits. */
++#define VC4_CONFIG_BITS_RASTERIZER_OVERSAMPLE_NONE (0 << 6)
++#define VC4_CONFIG_BITS_RASTERIZER_OVERSAMPLE_4X (1 << 6)
++#define VC4_CONFIG_BITS_RASTERIZER_OVERSAMPLE_16X (2 << 6)
++
++#define VC4_CONFIG_BITS_AA_POINTS_AND_LINES (1 << 4)
++#define VC4_CONFIG_BITS_ENABLE_DEPTH_OFFSET (1 << 3)
++#define VC4_CONFIG_BITS_CW_PRIMITIVES (1 << 2)
++#define VC4_CONFIG_BITS_ENABLE_PRIM_BACK (1 << 1)
++#define VC4_CONFIG_BITS_ENABLE_PRIM_FRONT (1 << 0)
++/** @} */
++
++/** @{ bits in the last u8 of VC4_PACKET_TILE_BINNING_MODE_CONFIG */
++#define VC4_BIN_CONFIG_DB_NON_MS (1 << 7)
++
++#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_MASK VC4_MASK(6, 5)
++#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_SHIFT 5
++#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_32 0
++#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_64 1
++#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_128 2
++#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_256 3
++
++#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_MASK VC4_MASK(4, 3)
++#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_SHIFT 3
++#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_32 0
++#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_64 1
++#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_128 2
++#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_256 3
++
++#define VC4_BIN_CONFIG_AUTO_INIT_TSDA (1 << 2)
++#define VC4_BIN_CONFIG_TILE_BUFFER_64BIT (1 << 1)
++#define VC4_BIN_CONFIG_MS_MODE_4X (1 << 0)
++/** @} */
++
++/** @{ bits in the last u16 of VC4_PACKET_TILE_RENDERING_MODE_CONFIG */
++#define VC4_RENDER_CONFIG_DB_NON_MS (1 << 12)
++#define VC4_RENDER_CONFIG_EARLY_Z_COVERAGE_DISABLE (1 << 11)
++#define VC4_RENDER_CONFIG_EARLY_Z_DIRECTION_G (1 << 10)
++#define VC4_RENDER_CONFIG_COVERAGE_MODE (1 << 9)
++#define VC4_RENDER_CONFIG_ENABLE_VG_MASK (1 << 8)
++
++/** The values of the field are VC4_TILING_FORMAT_* */
++#define VC4_RENDER_CONFIG_MEMORY_FORMAT_MASK VC4_MASK(7, 6)
++#define VC4_RENDER_CONFIG_MEMORY_FORMAT_SHIFT 6
++
++#define VC4_RENDER_CONFIG_DECIMATE_MODE_1X (0 << 4)
++#define VC4_RENDER_CONFIG_DECIMATE_MODE_4X (1 << 4)
++#define VC4_RENDER_CONFIG_DECIMATE_MODE_16X (2 << 4)
++
++#define VC4_RENDER_CONFIG_FORMAT_MASK VC4_MASK(3, 2)
++#define VC4_RENDER_CONFIG_FORMAT_SHIFT 2
++#define VC4_RENDER_CONFIG_FORMAT_BGR565_DITHERED 0
++#define VC4_RENDER_CONFIG_FORMAT_RGBA8888 1
++#define VC4_RENDER_CONFIG_FORMAT_BGR565 2
++
++#define VC4_RENDER_CONFIG_TILE_BUFFER_64BIT (1 << 1)
++#define VC4_RENDER_CONFIG_MS_MODE_4X (1 << 0)
++
++#define VC4_PRIMITIVE_LIST_FORMAT_16_INDEX (1 << 4)
++#define VC4_PRIMITIVE_LIST_FORMAT_32_XY (3 << 4)
++#define VC4_PRIMITIVE_LIST_FORMAT_TYPE_POINTS (0 << 0)
++#define VC4_PRIMITIVE_LIST_FORMAT_TYPE_LINES (1 << 0)
++#define VC4_PRIMITIVE_LIST_FORMAT_TYPE_TRIANGLES (2 << 0)
++#define VC4_PRIMITIVE_LIST_FORMAT_TYPE_RHT (3 << 0)
++
++enum vc4_texture_data_type {
++ VC4_TEXTURE_TYPE_RGBA8888 = 0,
++ VC4_TEXTURE_TYPE_RGBX8888 = 1,
++ VC4_TEXTURE_TYPE_RGBA4444 = 2,
++ VC4_TEXTURE_TYPE_RGBA5551 = 3,
++ VC4_TEXTURE_TYPE_RGB565 = 4,
++ VC4_TEXTURE_TYPE_LUMINANCE = 5,
++ VC4_TEXTURE_TYPE_ALPHA = 6,
++ VC4_TEXTURE_TYPE_LUMALPHA = 7,
++ VC4_TEXTURE_TYPE_ETC1 = 8,
++ VC4_TEXTURE_TYPE_S16F = 9,
++ VC4_TEXTURE_TYPE_S8 = 10,
++ VC4_TEXTURE_TYPE_S16 = 11,
++ VC4_TEXTURE_TYPE_BW1 = 12,
++ VC4_TEXTURE_TYPE_A4 = 13,
++ VC4_TEXTURE_TYPE_A1 = 14,
++ VC4_TEXTURE_TYPE_RGBA64 = 15,
++ VC4_TEXTURE_TYPE_RGBA32R = 16,
++ VC4_TEXTURE_TYPE_YUV422R = 17,
++};
++
++#define VC4_TEX_P0_OFFSET_MASK VC4_MASK(31, 12)
++#define VC4_TEX_P0_OFFSET_SHIFT 12
++#define VC4_TEX_P0_CSWIZ_MASK VC4_MASK(11, 10)
++#define VC4_TEX_P0_CSWIZ_SHIFT 10
++#define VC4_TEX_P0_CMMODE_MASK VC4_MASK(9, 9)
++#define VC4_TEX_P0_CMMODE_SHIFT 9
++#define VC4_TEX_P0_FLIPY_MASK VC4_MASK(8, 8)
++#define VC4_TEX_P0_FLIPY_SHIFT 8
++#define VC4_TEX_P0_TYPE_MASK VC4_MASK(7, 4)
++#define VC4_TEX_P0_TYPE_SHIFT 4
++#define VC4_TEX_P0_MIPLVLS_MASK VC4_MASK(3, 0)
++#define VC4_TEX_P0_MIPLVLS_SHIFT 0
++
++#define VC4_TEX_P1_TYPE4_MASK VC4_MASK(31, 31)
++#define VC4_TEX_P1_TYPE4_SHIFT 31
++#define VC4_TEX_P1_HEIGHT_MASK VC4_MASK(30, 20)
++#define VC4_TEX_P1_HEIGHT_SHIFT 20
++#define VC4_TEX_P1_ETCFLIP_MASK VC4_MASK(19, 19)
++#define VC4_TEX_P1_ETCFLIP_SHIFT 19
++#define VC4_TEX_P1_WIDTH_MASK VC4_MASK(18, 8)
++#define VC4_TEX_P1_WIDTH_SHIFT 8
++
++#define VC4_TEX_P1_MAGFILT_MASK VC4_MASK(7, 7)
++#define VC4_TEX_P1_MAGFILT_SHIFT 7
++# define VC4_TEX_P1_MAGFILT_LINEAR 0
++# define VC4_TEX_P1_MAGFILT_NEAREST 1
++
++#define VC4_TEX_P1_MINFILT_MASK VC4_MASK(6, 4)
++#define VC4_TEX_P1_MINFILT_SHIFT 4
++# define VC4_TEX_P1_MINFILT_LINEAR 0
++# define VC4_TEX_P1_MINFILT_NEAREST 1
++# define VC4_TEX_P1_MINFILT_NEAR_MIP_NEAR 2
++# define VC4_TEX_P1_MINFILT_NEAR_MIP_LIN 3
++# define VC4_TEX_P1_MINFILT_LIN_MIP_NEAR 4
++# define VC4_TEX_P1_MINFILT_LIN_MIP_LIN 5
++
++#define VC4_TEX_P1_WRAP_T_MASK VC4_MASK(3, 2)
++#define VC4_TEX_P1_WRAP_T_SHIFT 2
++#define VC4_TEX_P1_WRAP_S_MASK VC4_MASK(1, 0)
++#define VC4_TEX_P1_WRAP_S_SHIFT 0
++# define VC4_TEX_P1_WRAP_REPEAT 0
++# define VC4_TEX_P1_WRAP_CLAMP 1
++# define VC4_TEX_P1_WRAP_MIRROR 2
++# define VC4_TEX_P1_WRAP_BORDER 3
++
++#define VC4_TEX_P2_PTYPE_MASK VC4_MASK(31, 30)
++#define VC4_TEX_P2_PTYPE_SHIFT 30
++# define VC4_TEX_P2_PTYPE_IGNORED 0
++# define VC4_TEX_P2_PTYPE_CUBE_MAP_STRIDE 1
++# define VC4_TEX_P2_PTYPE_CHILD_IMAGE_DIMENSIONS 2
++# define VC4_TEX_P2_PTYPE_CHILD_IMAGE_OFFSETS 3
++
++/* VC4_TEX_P2_PTYPE_CUBE_MAP_STRIDE bits */
++#define VC4_TEX_P2_CMST_MASK VC4_MASK(29, 12)
++#define VC4_TEX_P2_CMST_SHIFT 12
++#define VC4_TEX_P2_BSLOD_MASK VC4_MASK(0, 0)
++#define VC4_TEX_P2_BSLOD_SHIFT 0
++
++/* VC4_TEX_P2_PTYPE_CHILD_IMAGE_DIMENSIONS */
++#define VC4_TEX_P2_CHEIGHT_MASK VC4_MASK(22, 12)
++#define VC4_TEX_P2_CHEIGHT_SHIFT 12
++#define VC4_TEX_P2_CWIDTH_MASK VC4_MASK(10, 0)
++#define VC4_TEX_P2_CWIDTH_SHIFT 0
++
++/* VC4_TEX_P2_PTYPE_CHILD_IMAGE_OFFSETS */
++#define VC4_TEX_P2_CYOFF_MASK VC4_MASK(22, 12)
++#define VC4_TEX_P2_CYOFF_SHIFT 12
++#define VC4_TEX_P2_CXOFF_MASK VC4_MASK(10, 0)
++#define VC4_TEX_P2_CXOFF_SHIFT 0
++
++#endif /* VC4_PACKET_H */
+--- a/drivers/gpu/drm/vc4/vc4_plane.c
++++ b/drivers/gpu/drm/vc4/vc4_plane.c
+@@ -29,6 +29,14 @@ struct vc4_plane_state {
+ u32 *dlist;
+ u32 dlist_size; /* Number of dwords in allocated for the display list */
+ u32 dlist_count; /* Number of used dwords in the display list. */
++
++ /* Offset in the dlist to pointer word 0. */
++ u32 pw0_offset;
++
++ /* Offset where the plane's dlist was last stored in the
++ hardware at vc4_crtc_atomic_flush() time.
++ */
++ u32 *hw_dlist;
+ };
+
+ static inline struct vc4_plane_state *
+@@ -207,6 +215,8 @@ static int vc4_plane_mode_set(struct drm
+ /* Position Word 3: Context. Written by the HVS. */
+ vc4_dlist_write(vc4_state, 0xc0c0c0c0);
+
++ vc4_state->pw0_offset = vc4_state->dlist_count;
++
+ /* Pointer Word 0: RGB / Y Pointer */
+ vc4_dlist_write(vc4_state, bo->paddr + offset);
+
+@@ -258,6 +268,8 @@ u32 vc4_plane_write_dlist(struct drm_pla
+ struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state);
+ int i;
+
++ vc4_state->hw_dlist = dlist;
++
+ /* Can't memcpy_toio() because it needs to be 32-bit writes. */
+ for (i = 0; i < vc4_state->dlist_count; i++)
+ writel(vc4_state->dlist[i], &dlist[i]);
+@@ -272,6 +284,34 @@ u32 vc4_plane_dlist_size(struct drm_plan
+ return vc4_state->dlist_count;
+ }
+
++/* Updates the plane to immediately (well, once the FIFO needs
++ * refilling) scan out from at a new framebuffer.
++ */
++void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb)
++{
++ struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state);
++ struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
++ uint32_t addr;
++
++ /* We're skipping the address adjustment for negative origin,
++ * because this is only called on the primary plane.
++ */
++ WARN_ON_ONCE(plane->state->crtc_x < 0 || plane->state->crtc_y < 0);
++ addr = bo->paddr + fb->offsets[0];
++
++ /* Write the new address into the hardware immediately. The
++ * scanout will start from this address as soon as the FIFO
++ * needs to refill with pixels.
++ */
++ writel(addr, &vc4_state->hw_dlist[vc4_state->pw0_offset]);
++
++ /* Also update the CPU-side dlist copy, so that any later
++ * atomic updates that don't do a new modeset on our plane
++ * also use our updated address.
++ */
++ vc4_state->dlist[vc4_state->pw0_offset] = addr;
++}
++
+ static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
+ .prepare_fb = NULL,
+ .cleanup_fb = NULL,
+--- /dev/null
++++ b/drivers/gpu/drm/vc4/vc4_qpu_defines.h
+@@ -0,0 +1,268 @@
++/*
++ * Copyright © 2014 Broadcom
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice (including the next
++ * paragraph) shall be included in all copies or substantial portions of the
++ * Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#ifndef VC4_QPU_DEFINES_H
++#define VC4_QPU_DEFINES_H
++
++enum qpu_op_add {
++ QPU_A_NOP,
++ QPU_A_FADD,
++ QPU_A_FSUB,
++ QPU_A_FMIN,
++ QPU_A_FMAX,
++ QPU_A_FMINABS,
++ QPU_A_FMAXABS,
++ QPU_A_FTOI,
++ QPU_A_ITOF,
++ QPU_A_ADD = 12,
++ QPU_A_SUB,
++ QPU_A_SHR,
++ QPU_A_ASR,
++ QPU_A_ROR,
++ QPU_A_SHL,
++ QPU_A_MIN,
++ QPU_A_MAX,
++ QPU_A_AND,
++ QPU_A_OR,
++ QPU_A_XOR,
++ QPU_A_NOT,
++ QPU_A_CLZ,
++ QPU_A_V8ADDS = 30,
++ QPU_A_V8SUBS = 31,
++};
++
++enum qpu_op_mul {
++ QPU_M_NOP,
++ QPU_M_FMUL,
++ QPU_M_MUL24,
++ QPU_M_V8MULD,
++ QPU_M_V8MIN,
++ QPU_M_V8MAX,
++ QPU_M_V8ADDS,
++ QPU_M_V8SUBS,
++};
++
++enum qpu_raddr {
++ QPU_R_FRAG_PAYLOAD_ZW = 15, /* W for A file, Z for B file */
++ /* 0-31 are the plain regfile a or b fields */
++ QPU_R_UNIF = 32,
++ QPU_R_VARY = 35,
++ QPU_R_ELEM_QPU = 38,
++ QPU_R_NOP,
++ QPU_R_XY_PIXEL_COORD = 41,
++ QPU_R_MS_REV_FLAGS = 41,
++ QPU_R_VPM = 48,
++ QPU_R_VPM_LD_BUSY,
++ QPU_R_VPM_LD_WAIT,
++ QPU_R_MUTEX_ACQUIRE,
++};
++
++enum qpu_waddr {
++ /* 0-31 are the plain regfile a or b fields */
++ QPU_W_ACC0 = 32, /* aka r0 */
++ QPU_W_ACC1,
++ QPU_W_ACC2,
++ QPU_W_ACC3,
++ QPU_W_TMU_NOSWAP,
++ QPU_W_ACC5,
++ QPU_W_HOST_INT,
++ QPU_W_NOP,
++ QPU_W_UNIFORMS_ADDRESS,
++ QPU_W_QUAD_XY, /* X for regfile a, Y for regfile b */
++ QPU_W_MS_FLAGS = 42,
++ QPU_W_REV_FLAG = 42,
++ QPU_W_TLB_STENCIL_SETUP = 43,
++ QPU_W_TLB_Z,
++ QPU_W_TLB_COLOR_MS,
++ QPU_W_TLB_COLOR_ALL,
++ QPU_W_TLB_ALPHA_MASK,
++ QPU_W_VPM,
++ QPU_W_VPMVCD_SETUP, /* LD for regfile a, ST for regfile b */
++ QPU_W_VPM_ADDR, /* LD for regfile a, ST for regfile b */
++ QPU_W_MUTEX_RELEASE,
++ QPU_W_SFU_RECIP,
++ QPU_W_SFU_RECIPSQRT,
++ QPU_W_SFU_EXP,
++ QPU_W_SFU_LOG,
++ QPU_W_TMU0_S,
++ QPU_W_TMU0_T,
++ QPU_W_TMU0_R,
++ QPU_W_TMU0_B,
++ QPU_W_TMU1_S,
++ QPU_W_TMU1_T,
++ QPU_W_TMU1_R,
++ QPU_W_TMU1_B,
++};
++
++enum qpu_sig_bits {
++ QPU_SIG_SW_BREAKPOINT,
++ QPU_SIG_NONE,
++ QPU_SIG_THREAD_SWITCH,
++ QPU_SIG_PROG_END,
++ QPU_SIG_WAIT_FOR_SCOREBOARD,
++ QPU_SIG_SCOREBOARD_UNLOCK,
++ QPU_SIG_LAST_THREAD_SWITCH,
++ QPU_SIG_COVERAGE_LOAD,
++ QPU_SIG_COLOR_LOAD,
++ QPU_SIG_COLOR_LOAD_END,
++ QPU_SIG_LOAD_TMU0,
++ QPU_SIG_LOAD_TMU1,
++ QPU_SIG_ALPHA_MASK_LOAD,
++ QPU_SIG_SMALL_IMM,
++ QPU_SIG_LOAD_IMM,
++ QPU_SIG_BRANCH
++};
++
++enum qpu_mux {
++ /* hardware mux values */
++ QPU_MUX_R0,
++ QPU_MUX_R1,
++ QPU_MUX_R2,
++ QPU_MUX_R3,
++ QPU_MUX_R4,
++ QPU_MUX_R5,
++ QPU_MUX_A,
++ QPU_MUX_B,
++
++ /* non-hardware mux values */
++ QPU_MUX_IMM,
++};
++
++enum qpu_cond {
++ QPU_COND_NEVER,
++ QPU_COND_ALWAYS,
++ QPU_COND_ZS,
++ QPU_COND_ZC,
++ QPU_COND_NS,
++ QPU_COND_NC,
++ QPU_COND_CS,
++ QPU_COND_CC,
++};
++
++enum qpu_pack_mul {
++ QPU_PACK_MUL_NOP,
++ QPU_PACK_MUL_8888 = 3, /* replicated to each 8 bits of the 32-bit dst. */
++ QPU_PACK_MUL_8A,
++ QPU_PACK_MUL_8B,
++ QPU_PACK_MUL_8C,
++ QPU_PACK_MUL_8D,
++};
++
++enum qpu_pack_a {
++ QPU_PACK_A_NOP,
++ /* convert to 16 bit float if float input, or to int16. */
++ QPU_PACK_A_16A,
++ QPU_PACK_A_16B,
++ /* replicated to each 8 bits of the 32-bit dst. */
++ QPU_PACK_A_8888,
++ /* Convert to 8-bit unsigned int. */
++ QPU_PACK_A_8A,
++ QPU_PACK_A_8B,
++ QPU_PACK_A_8C,
++ QPU_PACK_A_8D,
++
++ /* Saturating variants of the previous instructions. */
++ QPU_PACK_A_32_SAT, /* int-only */
++ QPU_PACK_A_16A_SAT, /* int or float */
++ QPU_PACK_A_16B_SAT,
++ QPU_PACK_A_8888_SAT,
++ QPU_PACK_A_8A_SAT,
++ QPU_PACK_A_8B_SAT,
++ QPU_PACK_A_8C_SAT,
++ QPU_PACK_A_8D_SAT,
++};
++
++enum qpu_unpack_r4 {
++ QPU_UNPACK_R4_NOP,
++ QPU_UNPACK_R4_F16A_TO_F32,
++ QPU_UNPACK_R4_F16B_TO_F32,
++ QPU_UNPACK_R4_8D_REP,
++ QPU_UNPACK_R4_8A,
++ QPU_UNPACK_R4_8B,
++ QPU_UNPACK_R4_8C,
++ QPU_UNPACK_R4_8D,
++};
++
++#define QPU_MASK(high, low) ((((uint64_t)1<<((high)-(low)+1))-1)<<(low))
++/* Using the GNU statement expression extension */
++#define QPU_SET_FIELD(value, field) \
++ ({ \
++ uint64_t fieldval = (uint64_t)(value) << field ## _SHIFT; \
++ assert((fieldval & ~ field ## _MASK) == 0); \
++ fieldval & field ## _MASK; \
++ })
++
++#define QPU_GET_FIELD(word, field) ((uint32_t)(((word) & field ## _MASK) >> field ## _SHIFT))
++
++#define QPU_SIG_SHIFT 60
++#define QPU_SIG_MASK QPU_MASK(63, 60)
++
++#define QPU_UNPACK_SHIFT 57
++#define QPU_UNPACK_MASK QPU_MASK(59, 57)
++
++/**
++ * If set, the pack field means PACK_MUL or R4 packing, instead of normal
++ * regfile a packing.
++ */
++#define QPU_PM ((uint64_t)1 << 56)
++
++#define QPU_PACK_SHIFT 52
++#define QPU_PACK_MASK QPU_MASK(55, 52)
++
++#define QPU_COND_ADD_SHIFT 49
++#define QPU_COND_ADD_MASK QPU_MASK(51, 49)
++#define QPU_COND_MUL_SHIFT 46
++#define QPU_COND_MUL_MASK QPU_MASK(48, 46)
++
++#define QPU_SF ((uint64_t)1 << 45)
++
++#define QPU_WADDR_ADD_SHIFT 38
++#define QPU_WADDR_ADD_MASK QPU_MASK(43, 38)
++#define QPU_WADDR_MUL_SHIFT 32
++#define QPU_WADDR_MUL_MASK QPU_MASK(37, 32)
++
++#define QPU_OP_MUL_SHIFT 29
++#define QPU_OP_MUL_MASK QPU_MASK(31, 29)
++
++#define QPU_RADDR_A_SHIFT 18
++#define QPU_RADDR_A_MASK QPU_MASK(23, 18)
++#define QPU_RADDR_B_SHIFT 12
++#define QPU_RADDR_B_MASK QPU_MASK(17, 12)
++#define QPU_SMALL_IMM_SHIFT 12
++#define QPU_SMALL_IMM_MASK QPU_MASK(17, 12)
++
++#define QPU_ADD_A_SHIFT 9
++#define QPU_ADD_A_MASK QPU_MASK(11, 9)
++#define QPU_ADD_B_SHIFT 6
++#define QPU_ADD_B_MASK QPU_MASK(8, 6)
++#define QPU_MUL_A_SHIFT 3
++#define QPU_MUL_A_MASK QPU_MASK(5, 3)
++#define QPU_MUL_B_SHIFT 0
++#define QPU_MUL_B_MASK QPU_MASK(2, 0)
++
++#define QPU_WS ((uint64_t)1 << 44)
++
++#define QPU_OP_ADD_SHIFT 24
++#define QPU_OP_ADD_MASK QPU_MASK(28, 24)
++
++#endif /* VC4_QPU_DEFINES_H */
+--- /dev/null
++++ b/drivers/gpu/drm/vc4/vc4_render_cl.c
+@@ -0,0 +1,448 @@
++/*
++ * Copyright © 2014-2015 Broadcom
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice (including the next
++ * paragraph) shall be included in all copies or substantial portions of the
++ * Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++/**
++ * DOC: Render command list generation
++ *
++ * In the VC4 driver, render command list generation is performed by the
++ * kernel instead of userspace. We do this because validating a
++ * user-submitted command list is hard to get right and has high CPU overhead,
++ * while the number of valid configurations for render command lists is
++ * actually fairly low.
++ */
++
++#include "uapi/drm/vc4_drm.h"
++#include "vc4_drv.h"
++#include "vc4_packet.h"
++
++struct vc4_rcl_setup {
++ struct drm_gem_cma_object *color_read;
++ struct drm_gem_cma_object *color_ms_write;
++ struct drm_gem_cma_object *zs_read;
++ struct drm_gem_cma_object *zs_write;
++
++ struct drm_gem_cma_object *rcl;
++ u32 next_offset;
++};
++
++static inline void rcl_u8(struct vc4_rcl_setup *setup, u8 val)
++{
++ *(u8 *)(setup->rcl->vaddr + setup->next_offset) = val;
++ setup->next_offset += 1;
++}
++
++static inline void rcl_u16(struct vc4_rcl_setup *setup, u16 val)
++{
++ *(u16 *)(setup->rcl->vaddr + setup->next_offset) = val;
++ setup->next_offset += 2;
++}
++
++static inline void rcl_u32(struct vc4_rcl_setup *setup, u32 val)
++{
++ *(u32 *)(setup->rcl->vaddr + setup->next_offset) = val;
++ setup->next_offset += 4;
++}
++
++
++/*
++ * Emits a no-op STORE_TILE_BUFFER_GENERAL.
++ *
++ * If we emit a PACKET_TILE_COORDINATES, it must be followed by a store of
++ * some sort before another load is triggered.
++ */
++static void vc4_store_before_load(struct vc4_rcl_setup *setup)
++{
++ rcl_u8(setup, VC4_PACKET_STORE_TILE_BUFFER_GENERAL);
++ rcl_u16(setup,
++ VC4_SET_FIELD(VC4_LOADSTORE_TILE_BUFFER_NONE,
++ VC4_LOADSTORE_TILE_BUFFER_BUFFER) |
++ VC4_STORE_TILE_BUFFER_DISABLE_COLOR_CLEAR |
++ VC4_STORE_TILE_BUFFER_DISABLE_ZS_CLEAR |
++ VC4_STORE_TILE_BUFFER_DISABLE_VG_MASK_CLEAR);
++ rcl_u32(setup, 0); /* no address, since we're in None mode */
++}
++
++/*
++ * Emits a PACKET_TILE_COORDINATES if one isn't already pending.
++ *
++ * The tile coordinates packet triggers a pending load if there is one, are
++ * used for clipping during rendering, and determine where loads/stores happen
++ * relative to their base address.
++ */
++static void vc4_tile_coordinates(struct vc4_rcl_setup *setup,
++ uint32_t x, uint32_t y)
++{
++ rcl_u8(setup, VC4_PACKET_TILE_COORDINATES);
++ rcl_u8(setup, x);
++ rcl_u8(setup, y);
++}
++
++static void emit_tile(struct vc4_exec_info *exec,
++ struct vc4_rcl_setup *setup,
++ uint8_t x, uint8_t y, bool first, bool last)
++{
++ struct drm_vc4_submit_cl *args = exec->args;
++ bool has_bin = args->bin_cl_size != 0;
++
++ /* Note that the load doesn't actually occur until the
++ * tile coords packet is processed, and only one load
++ * may be outstanding at a time.
++ */
++ if (setup->color_read) {
++ rcl_u8(setup, VC4_PACKET_LOAD_TILE_BUFFER_GENERAL);
++ rcl_u16(setup, args->color_read.bits);
++ rcl_u32(setup,
++ setup->color_read->paddr + args->color_read.offset);
++ }
++
++ if (setup->zs_read) {
++ if (setup->color_read) {
++ /* Exec previous load. */
++ vc4_tile_coordinates(setup, x, y);
++ vc4_store_before_load(setup);
++ }
++
++ rcl_u8(setup, VC4_PACKET_LOAD_TILE_BUFFER_GENERAL);
++ rcl_u16(setup, args->zs_read.bits);
++ rcl_u32(setup, setup->zs_read->paddr + args->zs_read.offset);
++ }
++
++ /* Clipping depends on tile coordinates having been
++ * emitted, so we always need one here.
++ */
++ vc4_tile_coordinates(setup, x, y);
++
++ /* Wait for the binner before jumping to the first
++ * tile's lists.
++ */
++ if (first && has_bin)
++ rcl_u8(setup, VC4_PACKET_WAIT_ON_SEMAPHORE);
++
++ if (has_bin) {
++ rcl_u8(setup, VC4_PACKET_BRANCH_TO_SUB_LIST);
++ rcl_u32(setup, (exec->tile_bo->paddr +
++ exec->tile_alloc_offset +
++ (y * exec->bin_tiles_x + x) * 32));
++ }
++
++ if (setup->zs_write) {
++ rcl_u8(setup, VC4_PACKET_STORE_TILE_BUFFER_GENERAL);
++ rcl_u16(setup, args->zs_write.bits |
++ (setup->color_ms_write ?
++ VC4_STORE_TILE_BUFFER_DISABLE_COLOR_CLEAR : 0));
++ rcl_u32(setup,
++ (setup->zs_write->paddr + args->zs_write.offset) |
++ ((last && !setup->color_ms_write) ?
++ VC4_LOADSTORE_TILE_BUFFER_EOF : 0));
++ }
++
++ if (setup->color_ms_write) {
++ if (setup->zs_write) {
++ /* Reset after previous store */
++ vc4_tile_coordinates(setup, x, y);
++ }
++
++ if (last)
++ rcl_u8(setup, VC4_PACKET_STORE_MS_TILE_BUFFER_AND_EOF);
++ else
++ rcl_u8(setup, VC4_PACKET_STORE_MS_TILE_BUFFER);
++ }
++}
++
++static int vc4_create_rcl_bo(struct drm_device *dev, struct vc4_exec_info *exec,
++ struct vc4_rcl_setup *setup)
++{
++ struct drm_vc4_submit_cl *args = exec->args;
++ bool has_bin = args->bin_cl_size != 0;
++ uint8_t min_x_tile = args->min_x_tile;
++ uint8_t min_y_tile = args->min_y_tile;
++ uint8_t max_x_tile = args->max_x_tile;
++ uint8_t max_y_tile = args->max_y_tile;
++ uint8_t xtiles = max_x_tile - min_x_tile + 1;
++ uint8_t ytiles = max_y_tile - min_y_tile + 1;
++ uint8_t x, y;
++ uint32_t size, loop_body_size;
++
++ size = VC4_PACKET_TILE_RENDERING_MODE_CONFIG_SIZE;
++ loop_body_size = VC4_PACKET_TILE_COORDINATES_SIZE;
++
++ if (args->flags & VC4_SUBMIT_CL_USE_CLEAR_COLOR) {
++ size += VC4_PACKET_CLEAR_COLORS_SIZE +
++ VC4_PACKET_TILE_COORDINATES_SIZE +
++ VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE;
++ }
++
++ if (setup->color_read) {
++ loop_body_size += (VC4_PACKET_LOAD_TILE_BUFFER_GENERAL_SIZE);
++ }
++ if (setup->zs_read) {
++ if (setup->color_read) {
++ loop_body_size += VC4_PACKET_TILE_COORDINATES_SIZE;
++ loop_body_size += VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE;
++ }
++ loop_body_size += VC4_PACKET_LOAD_TILE_BUFFER_GENERAL_SIZE;
++ }
++
++ if (has_bin) {
++ size += VC4_PACKET_WAIT_ON_SEMAPHORE_SIZE;
++ loop_body_size += VC4_PACKET_BRANCH_TO_SUB_LIST_SIZE;
++ }
++
++ if (setup->zs_write)
++ loop_body_size += VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE;
++ if (setup->color_ms_write) {
++ if (setup->zs_write)
++ loop_body_size += VC4_PACKET_TILE_COORDINATES_SIZE;
++ loop_body_size += VC4_PACKET_STORE_MS_TILE_BUFFER_SIZE;
++ }
++ size += xtiles * ytiles * loop_body_size;
++
++ setup->rcl = &vc4_bo_create(dev, size)->base;
++ if (!setup->rcl)
++ return -ENOMEM;
++ list_add_tail(&to_vc4_bo(&setup->rcl->base)->unref_head,
++ &exec->unref_list);
++
++ rcl_u8(setup, VC4_PACKET_TILE_RENDERING_MODE_CONFIG);
++ rcl_u32(setup,
++ (setup->color_ms_write ?
++ (setup->color_ms_write->paddr +
++ args->color_ms_write.offset) :
++ 0));
++ rcl_u16(setup, args->width);
++ rcl_u16(setup, args->height);
++ rcl_u16(setup, args->color_ms_write.bits);
++
++ /* The tile buffer gets cleared when the previous tile is stored. If
++ * the clear values changed between frames, then the tile buffer has
++ * stale clear values in it, so we have to do a store in None mode (no
++ * writes) so that we trigger the tile buffer clear.
++ */
++ if (args->flags & VC4_SUBMIT_CL_USE_CLEAR_COLOR) {
++ rcl_u8(setup, VC4_PACKET_CLEAR_COLORS);
++ rcl_u32(setup, args->clear_color[0]);
++ rcl_u32(setup, args->clear_color[1]);
++ rcl_u32(setup, args->clear_z);
++ rcl_u8(setup, args->clear_s);
++
++ vc4_tile_coordinates(setup, 0, 0);
++
++ rcl_u8(setup, VC4_PACKET_STORE_TILE_BUFFER_GENERAL);
++ rcl_u16(setup, VC4_LOADSTORE_TILE_BUFFER_NONE);
++ rcl_u32(setup, 0); /* no address, since we're in None mode */
++ }
++
++ for (y = min_y_tile; y <= max_y_tile; y++) {
++ for (x = min_x_tile; x <= max_x_tile; x++) {
++ bool first = (x == min_x_tile && y == min_y_tile);
++ bool last = (x == max_x_tile && y == max_y_tile);
++ emit_tile(exec, setup, x, y, first, last);
++ }
++ }
++
++ BUG_ON(setup->next_offset != size);
++ exec->ct1ca = setup->rcl->paddr;
++ exec->ct1ea = setup->rcl->paddr + setup->next_offset;
++
++ return 0;
++}
++
++static int vc4_rcl_surface_setup(struct vc4_exec_info *exec,
++ struct drm_gem_cma_object **obj,
++ struct drm_vc4_submit_rcl_surface *surf)
++{
++ uint8_t tiling = VC4_GET_FIELD(surf->bits,
++ VC4_LOADSTORE_TILE_BUFFER_TILING);
++ uint8_t buffer = VC4_GET_FIELD(surf->bits,
++ VC4_LOADSTORE_TILE_BUFFER_BUFFER);
++ uint8_t format = VC4_GET_FIELD(surf->bits,
++ VC4_LOADSTORE_TILE_BUFFER_FORMAT);
++ int cpp;
++
++ if (surf->pad != 0) {
++ DRM_ERROR("Padding unset\n");
++ return -EINVAL;
++ }
++
++ if (surf->hindex == ~0)
++ return 0;
++
++ if (!vc4_use_bo(exec, surf->hindex, VC4_MODE_RENDER, obj))
++ return -EINVAL;
++
++ if (surf->bits & ~(VC4_LOADSTORE_TILE_BUFFER_TILING_MASK |
++ VC4_LOADSTORE_TILE_BUFFER_BUFFER_MASK |
++ VC4_LOADSTORE_TILE_BUFFER_FORMAT_MASK)) {
++ DRM_ERROR("Unknown bits in load/store: 0x%04x\n",
++ surf->bits);
++ return -EINVAL;
++ }
++
++ if (tiling > VC4_TILING_FORMAT_LT) {
++ DRM_ERROR("Bad tiling format\n");
++ return -EINVAL;
++ }
++
++ if (buffer == VC4_LOADSTORE_TILE_BUFFER_ZS) {
++ if (format != 0) {
++ DRM_ERROR("No color format should be set for ZS\n");
++ return -EINVAL;
++ }
++ cpp = 4;
++ } else if (buffer == VC4_LOADSTORE_TILE_BUFFER_COLOR) {
++ switch (format) {
++ case VC4_LOADSTORE_TILE_BUFFER_BGR565:
++ case VC4_LOADSTORE_TILE_BUFFER_BGR565_DITHER:
++ cpp = 2;
++ break;
++ case VC4_LOADSTORE_TILE_BUFFER_RGBA8888:
++ cpp = 4;
++ break;
++ default:
++ DRM_ERROR("Bad tile buffer format\n");
++ return -EINVAL;
++ }
++ } else {
++ DRM_ERROR("Bad load/store buffer %d.\n", buffer);
++ return -EINVAL;
++ }
++
++ if (surf->offset & 0xf) {
++ DRM_ERROR("load/store buffer must be 16b aligned.\n");
++ return -EINVAL;
++ }
++
++ if (!vc4_check_tex_size(exec, *obj, surf->offset, tiling,
++ exec->args->width, exec->args->height, cpp)) {
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static int
++vc4_rcl_ms_surface_setup(struct vc4_exec_info *exec,
++ struct drm_gem_cma_object **obj,
++ struct drm_vc4_submit_rcl_surface *surf)
++{
++ uint8_t tiling = VC4_GET_FIELD(surf->bits,
++ VC4_RENDER_CONFIG_MEMORY_FORMAT);
++ uint8_t format = VC4_GET_FIELD(surf->bits,
++ VC4_RENDER_CONFIG_FORMAT);
++ int cpp;
++
++ if (surf->pad != 0) {
++ DRM_ERROR("Padding unset\n");
++ return -EINVAL;
++ }
++
++ if (surf->bits & ~(VC4_RENDER_CONFIG_MEMORY_FORMAT_MASK |
++ VC4_RENDER_CONFIG_FORMAT_MASK)) {
++ DRM_ERROR("Unknown bits in render config: 0x%04x\n",
++ surf->bits);
++ return -EINVAL;
++ }
++
++ if (surf->hindex == ~0)
++ return 0;
++
++ if (!vc4_use_bo(exec, surf->hindex, VC4_MODE_RENDER, obj))
++ return -EINVAL;
++
++ if (tiling > VC4_TILING_FORMAT_LT) {
++ DRM_ERROR("Bad tiling format\n");
++ return -EINVAL;
++ }
++
++ switch (format) {
++ case VC4_RENDER_CONFIG_FORMAT_BGR565_DITHERED:
++ case VC4_RENDER_CONFIG_FORMAT_BGR565:
++ cpp = 2;
++ break;
++ case VC4_RENDER_CONFIG_FORMAT_RGBA8888:
++ cpp = 4;
++ break;
++ default:
++ DRM_ERROR("Bad tile buffer format\n");
++ return -EINVAL;
++ }
++
++ if (!vc4_check_tex_size(exec, *obj, surf->offset, tiling,
++ exec->args->width, exec->args->height, cpp)) {
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++int vc4_get_rcl(struct drm_device *dev, struct vc4_exec_info *exec)
++{
++ struct vc4_rcl_setup setup = {0};
++ struct drm_vc4_submit_cl *args = exec->args;
++ bool has_bin = args->bin_cl_size != 0;
++ int ret;
++
++ if (args->min_x_tile > args->max_x_tile ||
++ args->min_y_tile > args->max_y_tile) {
++ DRM_ERROR("Bad render tile set (%d,%d)-(%d,%d)\n",
++ args->min_x_tile, args->min_y_tile,
++ args->max_x_tile, args->max_y_tile);
++ return -EINVAL;
++ }
++
++ if (has_bin &&
++ (args->max_x_tile > exec->bin_tiles_x ||
++ args->max_y_tile > exec->bin_tiles_y)) {
++ DRM_ERROR("Render tiles (%d,%d) outside of bin config (%d,%d)\n",
++ args->max_x_tile, args->max_y_tile,
++ exec->bin_tiles_x, exec->bin_tiles_y);
++ return -EINVAL;
++ }
++
++ ret = vc4_rcl_surface_setup(exec, &setup.color_read, &args->color_read);
++ if (ret)
++ return ret;
++
++ ret = vc4_rcl_ms_surface_setup(exec, &setup.color_ms_write,
++ &args->color_ms_write);
++ if (ret)
++ return ret;
++
++ ret = vc4_rcl_surface_setup(exec, &setup.zs_read, &args->zs_read);
++ if (ret)
++ return ret;
++
++ ret = vc4_rcl_surface_setup(exec, &setup.zs_write, &args->zs_write);
++ if (ret)
++ return ret;
++
++ /* We shouldn't even have the job submitted to us if there's no
++ * surface to write out.
++ */
++ if (!setup.color_ms_write && !setup.zs_write) {
++ DRM_ERROR("RCL requires color or Z/S write\n");
++ return -EINVAL;
++ }
++
++ return vc4_create_rcl_bo(dev, exec, &setup);
++}
+--- /dev/null
++++ b/drivers/gpu/drm/vc4/vc4_trace.h
+@@ -0,0 +1,63 @@
++/*
++ * Copyright (C) 2015 Broadcom
++ *
++ * 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.
++ */
++
++#if !defined(_VC4_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
++#define _VC4_TRACE_H_
++
++#include <linux/stringify.h>
++#include <linux/types.h>
++#include <linux/tracepoint.h>
++
++#undef TRACE_SYSTEM
++#define TRACE_SYSTEM vc4
++#define TRACE_INCLUDE_FILE vc4_trace
++
++TRACE_EVENT(vc4_wait_for_seqno_begin,
++ TP_PROTO(struct drm_device *dev, uint64_t seqno, uint64_t timeout),
++ TP_ARGS(dev, seqno, timeout),
++
++ TP_STRUCT__entry(
++ __field(u32, dev)
++ __field(u64, seqno)
++ __field(u64, timeout)
++ ),
++
++ TP_fast_assign(
++ __entry->dev = dev->primary->index;
++ __entry->seqno = seqno;
++ __entry->timeout = timeout;
++ ),
++
++ TP_printk("dev=%u, seqno=%llu, timeout=%llu",
++ __entry->dev, __entry->seqno, __entry->timeout)
++);
++
++TRACE_EVENT(vc4_wait_for_seqno_end,
++ TP_PROTO(struct drm_device *dev, uint64_t seqno),
++ TP_ARGS(dev, seqno),
++
++ TP_STRUCT__entry(
++ __field(u32, dev)
++ __field(u64, seqno)
++ ),
++
++ TP_fast_assign(
++ __entry->dev = dev->primary->index;
++ __entry->seqno = seqno;
++ ),
++
++ TP_printk("dev=%u, seqno=%llu",
++ __entry->dev, __entry->seqno)
++);
++
++#endif /* _VC4_TRACE_H_ */
++
++/* This part must be outside protection */
++#undef TRACE_INCLUDE_PATH
++#define TRACE_INCLUDE_PATH .
++#include <trace/define_trace.h>
+--- /dev/null
++++ b/drivers/gpu/drm/vc4/vc4_trace_points.c
+@@ -0,0 +1,14 @@
++/*
++ * Copyright (C) 2015 Broadcom
++ *
++ * 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 "vc4_drv.h"
++
++#ifndef __CHECKER__
++#define CREATE_TRACE_POINTS
++#include "vc4_trace.h"
++#endif
+--- /dev/null
++++ b/drivers/gpu/drm/vc4/vc4_v3d.c
+@@ -0,0 +1,268 @@
++/*
++ * Copyright (c) 2014 The Linux Foundation. All rights reserved.
++ * Copyright (C) 2013 Red Hat
++ * Author: Rob Clark <robdclark@gmail.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published by
++ * the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include "linux/component.h"
++#include "soc/bcm2835/raspberrypi-firmware.h"
++#include "vc4_drv.h"
++#include "vc4_regs.h"
++
++#ifdef CONFIG_DEBUG_FS
++#define REGDEF(reg) { reg, #reg }
++static const struct {
++ uint32_t reg;
++ const char *name;
++} vc4_reg_defs[] = {
++ REGDEF(V3D_IDENT0),
++ REGDEF(V3D_IDENT1),
++ REGDEF(V3D_IDENT2),
++ REGDEF(V3D_SCRATCH),
++ REGDEF(V3D_L2CACTL),
++ REGDEF(V3D_SLCACTL),
++ REGDEF(V3D_INTCTL),
++ REGDEF(V3D_INTENA),
++ REGDEF(V3D_INTDIS),
++ REGDEF(V3D_CT0CS),
++ REGDEF(V3D_CT1CS),
++ REGDEF(V3D_CT0EA),
++ REGDEF(V3D_CT1EA),
++ REGDEF(V3D_CT0CA),
++ REGDEF(V3D_CT1CA),
++ REGDEF(V3D_CT00RA0),
++ REGDEF(V3D_CT01RA0),
++ REGDEF(V3D_CT0LC),
++ REGDEF(V3D_CT1LC),
++ REGDEF(V3D_CT0PC),
++ REGDEF(V3D_CT1PC),
++ REGDEF(V3D_PCS),
++ REGDEF(V3D_BFC),
++ REGDEF(V3D_RFC),
++ REGDEF(V3D_BPCA),
++ REGDEF(V3D_BPCS),
++ REGDEF(V3D_BPOA),
++ REGDEF(V3D_BPOS),
++ REGDEF(V3D_BXCF),
++ REGDEF(V3D_SQRSV0),
++ REGDEF(V3D_SQRSV1),
++ REGDEF(V3D_SQCNTL),
++ REGDEF(V3D_SRQPC),
++ REGDEF(V3D_SRQUA),
++ REGDEF(V3D_SRQUL),
++ REGDEF(V3D_SRQCS),
++ REGDEF(V3D_VPACNTL),
++ REGDEF(V3D_VPMBASE),
++ REGDEF(V3D_PCTRC),
++ REGDEF(V3D_PCTRE),
++ REGDEF(V3D_PCTR0),
++ REGDEF(V3D_PCTRS0),
++ REGDEF(V3D_PCTR1),
++ REGDEF(V3D_PCTRS1),
++ REGDEF(V3D_PCTR2),
++ REGDEF(V3D_PCTRS2),
++ REGDEF(V3D_PCTR3),
++ REGDEF(V3D_PCTRS3),
++ REGDEF(V3D_PCTR4),
++ REGDEF(V3D_PCTRS4),
++ REGDEF(V3D_PCTR5),
++ REGDEF(V3D_PCTRS5),
++ REGDEF(V3D_PCTR6),
++ REGDEF(V3D_PCTRS6),
++ REGDEF(V3D_PCTR7),
++ REGDEF(V3D_PCTRS7),
++ REGDEF(V3D_PCTR8),
++ REGDEF(V3D_PCTRS8),
++ REGDEF(V3D_PCTR9),
++ REGDEF(V3D_PCTRS9),
++ REGDEF(V3D_PCTR10),
++ REGDEF(V3D_PCTRS10),
++ REGDEF(V3D_PCTR11),
++ REGDEF(V3D_PCTRS11),
++ REGDEF(V3D_PCTR12),
++ REGDEF(V3D_PCTRS12),
++ REGDEF(V3D_PCTR13),
++ REGDEF(V3D_PCTRS13),
++ REGDEF(V3D_PCTR14),
++ REGDEF(V3D_PCTRS14),
++ REGDEF(V3D_PCTR15),
++ REGDEF(V3D_PCTRS15),
++ REGDEF(V3D_BGE),
++ REGDEF(V3D_FDBGO),
++ REGDEF(V3D_FDBGB),
++ REGDEF(V3D_FDBGR),
++ REGDEF(V3D_FDBGS),
++ REGDEF(V3D_ERRSTAT),
++};
++
++int vc4_v3d_debugfs_regs(struct seq_file *m, void *unused)
++{
++ struct drm_info_node *node = (struct drm_info_node *) m->private;
++ struct drm_device *dev = node->minor->dev;
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(vc4_reg_defs); i++) {
++ seq_printf(m, "%s (0x%04x): 0x%08x\n",
++ vc4_reg_defs[i].name, vc4_reg_defs[i].reg,
++ V3D_READ(vc4_reg_defs[i].reg));
++ }
++
++ return 0;
++}
++
++int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused)
++{
++ struct drm_info_node *node = (struct drm_info_node *) m->private;
++ struct drm_device *dev = node->minor->dev;
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ uint32_t ident1 = V3D_READ(V3D_IDENT1);
++ uint32_t nslc = VC4_GET_FIELD(ident1, V3D_IDENT1_NSLC);
++ uint32_t tups = VC4_GET_FIELD(ident1, V3D_IDENT1_TUPS);
++ uint32_t qups = VC4_GET_FIELD(ident1, V3D_IDENT1_QUPS);
++
++ seq_printf(m, "Revision: %d\n", VC4_GET_FIELD(ident1, V3D_IDENT1_REV));
++ seq_printf(m, "Slices: %d\n", nslc);
++ seq_printf(m, "TMUs: %d\n", nslc * tups);
++ seq_printf(m, "QPUs: %d\n", nslc * qups);
++ seq_printf(m, "Semaphores: %d\n", VC4_GET_FIELD(ident1, V3D_IDENT1_NSEM));
++
++ return 0;
++}
++#endif /* CONFIG_DEBUG_FS */
++
++/*
++ * Asks the firmware to turn on power to the V3D engine.
++ *
++ * This may be doable with just the clocks interface, though this
++ * packet does some other register setup from the firmware, too.
++ */
++int
++vc4_v3d_set_power(struct vc4_dev *vc4, bool on)
++{
++ u32 packet = on;
++
++ return rpi_firmware_property(vc4->firmware,
++ RPI_FIRMWARE_SET_ENABLE_QPU,
++ &packet, sizeof(packet));
++}
++
++static void vc4_v3d_init_hw(struct drm_device *dev)
++{
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++
++ /* Take all the memory that would have been reserved for user
++ * QPU programs, since we don't have an interface for running
++ * them, anyway.
++ */
++ V3D_WRITE(V3D_VPMBASE, 0);
++}
++
++static int vc4_v3d_bind(struct device *dev, struct device *master, void *data)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ struct drm_device *drm = dev_get_drvdata(master);
++ struct vc4_dev *vc4 = to_vc4_dev(drm);
++ struct vc4_v3d *v3d = NULL;
++ int ret;
++
++ v3d = devm_kzalloc(&pdev->dev, sizeof(*v3d), GFP_KERNEL);
++ if (!v3d)
++ return -ENOMEM;
++
++ v3d->pdev = pdev;
++
++ v3d->regs = vc4_ioremap_regs(pdev, 0);
++ if (IS_ERR(v3d->regs))
++ return PTR_ERR(v3d->regs);
++
++ vc4->v3d = v3d;
++
++ ret = vc4_v3d_set_power(vc4, true);
++ if (ret)
++ return ret;
++
++ if (V3D_READ(V3D_IDENT0) != V3D_EXPECTED_IDENT0) {
++ DRM_ERROR("V3D_IDENT0 read 0x%08x instead of 0x%08x\n",
++ V3D_READ(V3D_IDENT0), V3D_EXPECTED_IDENT0);
++ return -EINVAL;
++ }
++
++ /* Reset the binner overflow address/size at setup, to be sure
++ * we don't reuse an old one.
++ */
++ V3D_WRITE(V3D_BPOA, 0);
++ V3D_WRITE(V3D_BPOS, 0);
++
++ vc4_v3d_init_hw(drm);
++
++ ret = drm_irq_install(drm, platform_get_irq(pdev, 0));
++ if (ret) {
++ DRM_ERROR("Failed to install IRQ handler\n");
++ return ret;
++ }
++
++ return 0;
++}
++
++static void vc4_v3d_unbind(struct device *dev, struct device *master,
++ void *data)
++{
++ struct drm_device *drm = dev_get_drvdata(master);
++ struct vc4_dev *vc4 = to_vc4_dev(drm);
++
++ drm_irq_uninstall(drm);
++
++ /* Disable the binner's overflow memory address, so the next
++ * driver probe (if any) doesn't try to reuse our old
++ * allocation.
++ */
++ V3D_WRITE(V3D_BPOA, 0);
++ V3D_WRITE(V3D_BPOS, 0);
++
++ vc4_v3d_set_power(vc4, false);
++
++ vc4->v3d = NULL;
++}
++
++static const struct component_ops vc4_v3d_ops = {
++ .bind = vc4_v3d_bind,
++ .unbind = vc4_v3d_unbind,
++};
++
++static int vc4_v3d_dev_probe(struct platform_device *pdev)
++{
++ return component_add(&pdev->dev, &vc4_v3d_ops);
++}
++
++static int vc4_v3d_dev_remove(struct platform_device *pdev)
++{
++ component_del(&pdev->dev, &vc4_v3d_ops);
++ return 0;
++}
++
++static const struct of_device_id vc4_v3d_dt_match[] = {
++ { .compatible = "brcm,vc4-v3d" },
++ {}
++};
++
++struct platform_driver vc4_v3d_driver = {
++ .probe = vc4_v3d_dev_probe,
++ .remove = vc4_v3d_dev_remove,
++ .driver = {
++ .name = "vc4_v3d",
++ .of_match_table = vc4_v3d_dt_match,
++ },
++};
+--- /dev/null
++++ b/drivers/gpu/drm/vc4/vc4_validate.c
+@@ -0,0 +1,958 @@
++/*
++ * Copyright © 2014 Broadcom
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice (including the next
++ * paragraph) shall be included in all copies or substantial portions of the
++ * Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++/**
++ * Command list validator for VC4.
++ *
++ * The VC4 has no IOMMU between it and system memory. So, a user with
++ * access to execute command lists could escalate privilege by
++ * overwriting system memory (drawing to it as a framebuffer) or
++ * reading system memory it shouldn't (reading it as a texture, or
++ * uniform data, or vertex data).
++ *
++ * This validates command lists to ensure that all accesses are within
++ * the bounds of the GEM objects referenced. It explicitly whitelists
++ * packets, and looks at the offsets in any address fields to make
++ * sure they're constrained within the BOs they reference.
++ *
++ * Note that because of the validation that's happening anyway, this
++ * is where GEM relocation processing happens.
++ */
++
++#include "uapi/drm/vc4_drm.h"
++#include "vc4_drv.h"
++#include "vc4_packet.h"
++
++#define VALIDATE_ARGS \
++ struct vc4_exec_info *exec, \
++ void *validated, \
++ void *untrusted
++
++
++/** Return the width in pixels of a 64-byte microtile. */
++static uint32_t
++utile_width(int cpp)
++{
++ switch (cpp) {
++ case 1:
++ case 2:
++ return 8;
++ case 4:
++ return 4;
++ case 8:
++ return 2;
++ default:
++ DRM_ERROR("unknown cpp: %d\n", cpp);
++ return 1;
++ }
++}
++
++/** Return the height in pixels of a 64-byte microtile. */
++static uint32_t
++utile_height(int cpp)
++{
++ switch (cpp) {
++ case 1:
++ return 8;
++ case 2:
++ case 4:
++ case 8:
++ return 4;
++ default:
++ DRM_ERROR("unknown cpp: %d\n", cpp);
++ return 1;
++ }
++}
++
++/**
++ * The texture unit decides what tiling format a particular miplevel is using
++ * this function, so we lay out our miptrees accordingly.
++ */
++static bool
++size_is_lt(uint32_t width, uint32_t height, int cpp)
++{
++ return (width <= 4 * utile_width(cpp) ||
++ height <= 4 * utile_height(cpp));
++}
++
++bool
++vc4_use_bo(struct vc4_exec_info *exec,
++ uint32_t hindex,
++ enum vc4_bo_mode mode,
++ struct drm_gem_cma_object **obj)
++{
++ *obj = NULL;
++
++ if (hindex >= exec->bo_count) {
++ DRM_ERROR("BO index %d greater than BO count %d\n",
++ hindex, exec->bo_count);
++ return false;
++ }
++
++ if (exec->bo[hindex].mode != mode) {
++ if (exec->bo[hindex].mode == VC4_MODE_UNDECIDED) {
++ exec->bo[hindex].mode = mode;
++ } else {
++ DRM_ERROR("BO index %d reused with mode %d vs %d\n",
++ hindex, exec->bo[hindex].mode, mode);
++ return false;
++ }
++ }
++
++ *obj = exec->bo[hindex].bo;
++ return true;
++}
++
++static bool
++vc4_use_handle(struct vc4_exec_info *exec,
++ uint32_t gem_handles_packet_index,
++ enum vc4_bo_mode mode,
++ struct drm_gem_cma_object **obj)
++{
++ return vc4_use_bo(exec, exec->bo_index[gem_handles_packet_index],
++ mode, obj);
++}
++
++static uint32_t
++gl_shader_rec_size(uint32_t pointer_bits)
++{
++ uint32_t attribute_count = pointer_bits & 7;
++ bool extended = pointer_bits & 8;
++
++ if (attribute_count == 0)
++ attribute_count = 8;
++
++ if (extended)
++ return 100 + attribute_count * 4;
++ else
++ return 36 + attribute_count * 8;
++}
++
++bool
++vc4_check_tex_size(struct vc4_exec_info *exec, struct drm_gem_cma_object *fbo,
++ uint32_t offset, uint8_t tiling_format,
++ uint32_t width, uint32_t height, uint8_t cpp)
++{
++ uint32_t aligned_width, aligned_height, stride, size;
++ uint32_t utile_w = utile_width(cpp);
++ uint32_t utile_h = utile_height(cpp);
++
++ /* The shaded vertex format stores signed 12.4 fixed point
++ * (-2048,2047) offsets from the viewport center, so we should
++ * never have a render target larger than 4096. The texture
++ * unit can only sample from 2048x2048, so it's even more
++ * restricted. This lets us avoid worrying about overflow in
++ * our math.
++ */
++ if (width > 4096 || height > 4096) {
++ DRM_ERROR("Surface dimesions (%d,%d) too large", width, height);
++ return false;
++ }
++
++ switch (tiling_format) {
++ case VC4_TILING_FORMAT_LINEAR:
++ aligned_width = round_up(width, utile_w);
++ aligned_height = height;
++ break;
++ case VC4_TILING_FORMAT_T:
++ aligned_width = round_up(width, utile_w * 8);
++ aligned_height = round_up(height, utile_h * 8);
++ break;
++ case VC4_TILING_FORMAT_LT:
++ aligned_width = round_up(width, utile_w);
++ aligned_height = round_up(height, utile_h);
++ break;
++ default:
++ DRM_ERROR("buffer tiling %d unsupported\n", tiling_format);
++ return false;
++ }
++
++ stride = aligned_width * cpp;
++ size = stride * aligned_height;
++
++ if (size + offset < size ||
++ size + offset > fbo->base.size) {
++ DRM_ERROR("Overflow in %dx%d (%dx%d) fbo size (%d + %d > %d)\n",
++ width, height,
++ aligned_width, aligned_height,
++ size, offset, fbo->base.size);
++ return false;
++ }
++
++ return true;
++}
++
++static int
++validate_flush_all(VALIDATE_ARGS)
++{
++ if (exec->found_increment_semaphore_packet) {
++ DRM_ERROR("VC4_PACKET_FLUSH_ALL after "
++ "VC4_PACKET_INCREMENT_SEMAPHORE\n");
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static int
++validate_start_tile_binning(VALIDATE_ARGS)
++{
++ if (exec->found_start_tile_binning_packet) {
++ DRM_ERROR("Duplicate VC4_PACKET_START_TILE_BINNING\n");
++ return -EINVAL;
++ }
++ exec->found_start_tile_binning_packet = true;
++
++ if (!exec->found_tile_binning_mode_config_packet) {
++ DRM_ERROR("missing VC4_PACKET_TILE_BINNING_MODE_CONFIG\n");
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static int
++validate_increment_semaphore(VALIDATE_ARGS)
++{
++ if (exec->found_increment_semaphore_packet) {
++ DRM_ERROR("Duplicate VC4_PACKET_INCREMENT_SEMAPHORE\n");
++ return -EINVAL;
++ }
++ exec->found_increment_semaphore_packet = true;
++
++ /* Once we've found the semaphore increment, there should be one FLUSH
++ * then the end of the command list. The FLUSH actually triggers the
++ * increment, so we only need to make sure there
++ */
++
++ return 0;
++}
++
++static int
++validate_indexed_prim_list(VALIDATE_ARGS)
++{
++ struct drm_gem_cma_object *ib;
++ uint32_t length = *(uint32_t *)(untrusted + 1);
++ uint32_t offset = *(uint32_t *)(untrusted + 5);
++ uint32_t max_index = *(uint32_t *)(untrusted + 9);
++ uint32_t index_size = (*(uint8_t *)(untrusted + 0) >> 4) ? 2 : 1;
++ struct vc4_shader_state *shader_state;
++
++ if (exec->found_increment_semaphore_packet) {
++ DRM_ERROR("Drawing after VC4_PACKET_INCREMENT_SEMAPHORE\n");
++ return -EINVAL;
++ }
++
++ /* Check overflow condition */
++ if (exec->shader_state_count == 0) {
++ DRM_ERROR("shader state must precede primitives\n");
++ return -EINVAL;
++ }
++ shader_state = &exec->shader_state[exec->shader_state_count - 1];
++
++ if (max_index > shader_state->max_index)
++ shader_state->max_index = max_index;
++
++ if (!vc4_use_handle(exec, 0, VC4_MODE_RENDER, &ib))
++ return -EINVAL;
++
++ if (offset > ib->base.size ||
++ (ib->base.size - offset) / index_size < length) {
++ DRM_ERROR("IB access overflow (%d + %d*%d > %d)\n",
++ offset, length, index_size, ib->base.size);
++ return -EINVAL;
++ }
++
++ *(uint32_t *)(validated + 5) = ib->paddr + offset;
++
++ return 0;
++}
++
++static int
++validate_gl_array_primitive(VALIDATE_ARGS)
++{
++ uint32_t length = *(uint32_t *)(untrusted + 1);
++ uint32_t base_index = *(uint32_t *)(untrusted + 5);
++ uint32_t max_index;
++ struct vc4_shader_state *shader_state;
++
++ if (exec->found_increment_semaphore_packet) {
++ DRM_ERROR("Drawing after VC4_PACKET_INCREMENT_SEMAPHORE\n");
++ return -EINVAL;
++ }
++
++ /* Check overflow condition */
++ if (exec->shader_state_count == 0) {
++ DRM_ERROR("shader state must precede primitives\n");
++ return -EINVAL;
++ }
++ shader_state = &exec->shader_state[exec->shader_state_count - 1];
++
++ if (length + base_index < length) {
++ DRM_ERROR("primitive vertex count overflow\n");
++ return -EINVAL;
++ }
++ max_index = length + base_index - 1;
++
++ if (max_index > shader_state->max_index)
++ shader_state->max_index = max_index;
++
++ return 0;
++}
++
++static int
++validate_gl_shader_state(VALIDATE_ARGS)
++{
++ uint32_t i = exec->shader_state_count++;
++
++ if (i >= exec->shader_state_size) {
++ DRM_ERROR("More requests for shader states than declared\n");
++ return -EINVAL;
++ }
++
++ exec->shader_state[i].packet = VC4_PACKET_GL_SHADER_STATE;
++ exec->shader_state[i].addr = *(uint32_t *)untrusted;
++ exec->shader_state[i].max_index = 0;
++
++ if (exec->shader_state[i].addr & ~0xf) {
++ DRM_ERROR("high bits set in GL shader rec reference\n");
++ return -EINVAL;
++ }
++
++ *(uint32_t *)validated = (exec->shader_rec_p +
++ exec->shader_state[i].addr);
++
++ exec->shader_rec_p +=
++ roundup(gl_shader_rec_size(exec->shader_state[i].addr), 16);
++
++ return 0;
++}
++
++static int
++validate_nv_shader_state(VALIDATE_ARGS)
++{
++ uint32_t i = exec->shader_state_count++;
++
++ if (i >= exec->shader_state_size) {
++ DRM_ERROR("More requests for shader states than declared\n");
++ return -EINVAL;
++ }
++
++ exec->shader_state[i].packet = VC4_PACKET_NV_SHADER_STATE;
++ exec->shader_state[i].addr = *(uint32_t *)untrusted;
++
++ if (exec->shader_state[i].addr & 15) {
++ DRM_ERROR("NV shader state address 0x%08x misaligned\n",
++ exec->shader_state[i].addr);
++ return -EINVAL;
++ }
++
++ *(uint32_t *)validated = (exec->shader_state[i].addr +
++ exec->shader_rec_p);
++
++ return 0;
++}
++
++static int
++validate_tile_binning_config(VALIDATE_ARGS)
++{
++ struct drm_device *dev = exec->exec_bo->base.dev;
++ uint8_t flags;
++ uint32_t tile_state_size, tile_alloc_size;
++ uint32_t tile_count;
++
++ if (exec->found_tile_binning_mode_config_packet) {
++ DRM_ERROR("Duplicate VC4_PACKET_TILE_BINNING_MODE_CONFIG\n");
++ return -EINVAL;
++ }
++ exec->found_tile_binning_mode_config_packet = true;
++
++ exec->bin_tiles_x = *(uint8_t *)(untrusted + 12);
++ exec->bin_tiles_y = *(uint8_t *)(untrusted + 13);
++ tile_count = exec->bin_tiles_x * exec->bin_tiles_y;
++ flags = *(uint8_t *)(untrusted + 14);
++
++ if (exec->bin_tiles_x == 0 ||
++ exec->bin_tiles_y == 0) {
++ DRM_ERROR("Tile binning config of %dx%d too small\n",
++ exec->bin_tiles_x, exec->bin_tiles_y);
++ return -EINVAL;
++ }
++
++ if (flags & (VC4_BIN_CONFIG_DB_NON_MS |
++ VC4_BIN_CONFIG_TILE_BUFFER_64BIT |
++ VC4_BIN_CONFIG_MS_MODE_4X)) {
++ DRM_ERROR("unsupported bining config flags 0x%02x\n", flags);
++ return -EINVAL;
++ }
++
++ /* The tile state data array is 48 bytes per tile, and we put it at
++ * the start of a BO containing both it and the tile alloc.
++ */
++ tile_state_size = 48 * tile_count;
++
++ /* Since the tile alloc array will follow us, align. */
++ exec->tile_alloc_offset = roundup(tile_state_size, 4096);
++
++ *(uint8_t *)(validated + 14) =
++ ((flags & ~(VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_MASK |
++ VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_MASK)) |
++ VC4_BIN_CONFIG_AUTO_INIT_TSDA |
++ VC4_SET_FIELD(VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_32,
++ VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE) |
++ VC4_SET_FIELD(VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_128,
++ VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE));
++
++ /* Initial block size. */
++ tile_alloc_size = 32 * tile_count;
++
++ /*
++ * The initial allocation gets rounded to the next 256 bytes before
++ * the hardware starts fulfilling further allocations.
++ */
++ tile_alloc_size = roundup(tile_alloc_size, 256);
++
++ /* Add space for the extra allocations. This is what gets used first,
++ * before overflow memory. It must have at least 4096 bytes, but we
++ * want to avoid overflow memory usage if possible.
++ */
++ tile_alloc_size += 1024 * 1024;
++
++ exec->tile_bo = &vc4_bo_create(dev, exec->tile_alloc_offset +
++ tile_alloc_size)->base;
++ if (!exec->tile_bo)
++ return -ENOMEM;
++ list_add_tail(&to_vc4_bo(&exec->tile_bo->base)->unref_head,
++ &exec->unref_list);
++
++ /* tile alloc address. */
++ *(uint32_t *)(validated + 0) = (exec->tile_bo->paddr +
++ exec->tile_alloc_offset);
++ /* tile alloc size. */
++ *(uint32_t *)(validated + 4) = tile_alloc_size;
++ /* tile state address. */
++ *(uint32_t *)(validated + 8) = exec->tile_bo->paddr;
++
++ return 0;
++}
++
++static int
++validate_gem_handles(VALIDATE_ARGS)
++{
++ memcpy(exec->bo_index, untrusted, sizeof(exec->bo_index));
++ return 0;
++}
++
++#define VC4_DEFINE_PACKET(packet, name, func) \
++ [packet] = { packet ## _SIZE, name, func }
++
++static const struct cmd_info {
++ uint16_t len;
++ const char *name;
++ int (*func)(struct vc4_exec_info *exec, void *validated,
++ void *untrusted);
++} cmd_info[] = {
++ VC4_DEFINE_PACKET(VC4_PACKET_HALT, "halt", NULL),
++ VC4_DEFINE_PACKET(VC4_PACKET_NOP, "nop", NULL),
++ VC4_DEFINE_PACKET(VC4_PACKET_FLUSH, "flush", NULL),
++ VC4_DEFINE_PACKET(VC4_PACKET_FLUSH_ALL, "flush all state", validate_flush_all),
++ VC4_DEFINE_PACKET(VC4_PACKET_START_TILE_BINNING, "start tile binning", validate_start_tile_binning),
++ VC4_DEFINE_PACKET(VC4_PACKET_INCREMENT_SEMAPHORE, "increment semaphore", validate_increment_semaphore),
++
++ VC4_DEFINE_PACKET(VC4_PACKET_GL_INDEXED_PRIMITIVE, "Indexed Primitive List", validate_indexed_prim_list),
++
++ VC4_DEFINE_PACKET(VC4_PACKET_GL_ARRAY_PRIMITIVE, "Vertex Array Primitives", validate_gl_array_primitive),
++
++ /* This is only used by clipped primitives (packets 48 and 49), which
++ * we don't support parsing yet.
++ */
++ VC4_DEFINE_PACKET(VC4_PACKET_PRIMITIVE_LIST_FORMAT, "primitive list format", NULL),
++
++ VC4_DEFINE_PACKET(VC4_PACKET_GL_SHADER_STATE, "GL Shader State", validate_gl_shader_state),
++ VC4_DEFINE_PACKET(VC4_PACKET_NV_SHADER_STATE, "NV Shader State", validate_nv_shader_state),
++
++ VC4_DEFINE_PACKET(VC4_PACKET_CONFIGURATION_BITS, "configuration bits", NULL),
++ VC4_DEFINE_PACKET(VC4_PACKET_FLAT_SHADE_FLAGS, "flat shade flags", NULL),
++ VC4_DEFINE_PACKET(VC4_PACKET_POINT_SIZE, "point size", NULL),
++ VC4_DEFINE_PACKET(VC4_PACKET_LINE_WIDTH, "line width", NULL),
++ VC4_DEFINE_PACKET(VC4_PACKET_RHT_X_BOUNDARY, "RHT X boundary", NULL),
++ VC4_DEFINE_PACKET(VC4_PACKET_DEPTH_OFFSET, "Depth Offset", NULL),
++ VC4_DEFINE_PACKET(VC4_PACKET_CLIP_WINDOW, "Clip Window", NULL),
++ VC4_DEFINE_PACKET(VC4_PACKET_VIEWPORT_OFFSET, "Viewport Offset", NULL),
++ VC4_DEFINE_PACKET(VC4_PACKET_CLIPPER_XY_SCALING, "Clipper XY Scaling", NULL),
++ /* Note: The docs say this was also 105, but it was 106 in the
++ * initial userland code drop.
++ */
++ VC4_DEFINE_PACKET(VC4_PACKET_CLIPPER_Z_SCALING, "Clipper Z Scale and Offset", NULL),
++
++ VC4_DEFINE_PACKET(VC4_PACKET_TILE_BINNING_MODE_CONFIG, "tile binning configuration", validate_tile_binning_config),
++
++ VC4_DEFINE_PACKET(VC4_PACKET_GEM_HANDLES, "GEM handles", validate_gem_handles),
++};
++
++int
++vc4_validate_bin_cl(struct drm_device *dev,
++ void *validated,
++ void *unvalidated,
++ struct vc4_exec_info *exec)
++{
++ uint32_t len = exec->args->bin_cl_size;
++ uint32_t dst_offset = 0;
++ uint32_t src_offset = 0;
++
++ while (src_offset < len) {
++ void *dst_pkt = validated + dst_offset;
++ void *src_pkt = unvalidated + src_offset;
++ u8 cmd = *(uint8_t *)src_pkt;
++ const struct cmd_info *info;
++
++ if (cmd > ARRAY_SIZE(cmd_info)) {
++ DRM_ERROR("0x%08x: packet %d out of bounds\n",
++ src_offset, cmd);
++ return -EINVAL;
++ }
++
++ info = &cmd_info[cmd];
++ if (!info->name) {
++ DRM_ERROR("0x%08x: packet %d invalid\n",
++ src_offset, cmd);
++ return -EINVAL;
++ }
++
++#if 0
++ DRM_INFO("0x%08x: packet %d (%s) size %d processing...\n",
++ src_offset, cmd, info->name, info->len);
++#endif
++
++ if (src_offset + info->len > len) {
++ DRM_ERROR("0x%08x: packet %d (%s) length 0x%08x "
++ "exceeds bounds (0x%08x)\n",
++ src_offset, cmd, info->name, info->len,
++ src_offset + len);
++ return -EINVAL;
++ }
++
++ if (cmd != VC4_PACKET_GEM_HANDLES)
++ memcpy(dst_pkt, src_pkt, info->len);
++
++ if (info->func && info->func(exec,
++ dst_pkt + 1,
++ src_pkt + 1)) {
++ DRM_ERROR("0x%08x: packet %d (%s) failed to "
++ "validate\n",
++ src_offset, cmd, info->name);
++ return -EINVAL;
++ }
++
++ src_offset += info->len;
++ /* GEM handle loading doesn't produce HW packets. */
++ if (cmd != VC4_PACKET_GEM_HANDLES)
++ dst_offset += info->len;
++
++ /* When the CL hits halt, it'll stop reading anything else. */
++ if (cmd == VC4_PACKET_HALT)
++ break;
++ }
++
++ exec->ct0ea = exec->ct0ca + dst_offset;
++
++ if (!exec->found_start_tile_binning_packet) {
++ DRM_ERROR("Bin CL missing VC4_PACKET_START_TILE_BINNING\n");
++ return -EINVAL;
++ }
++
++ if (!exec->found_increment_semaphore_packet) {
++ DRM_ERROR("Bin CL missing VC4_PACKET_INCREMENT_SEMAPHORE\n");
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static bool
++reloc_tex(struct vc4_exec_info *exec,
++ void *uniform_data_u,
++ struct vc4_texture_sample_info *sample,
++ uint32_t texture_handle_index)
++
++{
++ struct drm_gem_cma_object *tex;
++ uint32_t p0 = *(uint32_t *)(uniform_data_u + sample->p_offset[0]);
++ uint32_t p1 = *(uint32_t *)(uniform_data_u + sample->p_offset[1]);
++ uint32_t p2 = (sample->p_offset[2] != ~0 ?
++ *(uint32_t *)(uniform_data_u + sample->p_offset[2]) : 0);
++ uint32_t p3 = (sample->p_offset[3] != ~0 ?
++ *(uint32_t *)(uniform_data_u + sample->p_offset[3]) : 0);
++ uint32_t *validated_p0 = exec->uniforms_v + sample->p_offset[0];
++ uint32_t offset = p0 & VC4_TEX_P0_OFFSET_MASK;
++ uint32_t miplevels = VC4_GET_FIELD(p0, VC4_TEX_P0_MIPLVLS);
++ uint32_t width = VC4_GET_FIELD(p1, VC4_TEX_P1_WIDTH);
++ uint32_t height = VC4_GET_FIELD(p1, VC4_TEX_P1_HEIGHT);
++ uint32_t cpp, tiling_format, utile_w, utile_h;
++ uint32_t i;
++ uint32_t cube_map_stride = 0;
++ enum vc4_texture_data_type type;
++
++ if (!vc4_use_bo(exec, texture_handle_index, VC4_MODE_RENDER, &tex))
++ return false;
++
++ if (sample->is_direct) {
++ uint32_t remaining_size = tex->base.size - p0;
++ if (p0 > tex->base.size - 4) {
++ DRM_ERROR("UBO offset greater than UBO size\n");
++ goto fail;
++ }
++ if (p1 > remaining_size - 4) {
++ DRM_ERROR("UBO clamp would allow reads outside of UBO\n");
++ goto fail;
++ }
++ *validated_p0 = tex->paddr + p0;
++ return true;
++ }
++
++ if (width == 0)
++ width = 2048;
++ if (height == 0)
++ height = 2048;
++
++ if (p0 & VC4_TEX_P0_CMMODE_MASK) {
++ if (VC4_GET_FIELD(p2, VC4_TEX_P2_PTYPE) ==
++ VC4_TEX_P2_PTYPE_CUBE_MAP_STRIDE)
++ cube_map_stride = p2 & VC4_TEX_P2_CMST_MASK;
++ if (VC4_GET_FIELD(p3, VC4_TEX_P2_PTYPE) ==
++ VC4_TEX_P2_PTYPE_CUBE_MAP_STRIDE) {
++ if (cube_map_stride) {
++ DRM_ERROR("Cube map stride set twice\n");
++ goto fail;
++ }
++
++ cube_map_stride = p3 & VC4_TEX_P2_CMST_MASK;
++ }
++ if (!cube_map_stride) {
++ DRM_ERROR("Cube map stride not set\n");
++ goto fail;
++ }
++ }
++
++ type = (VC4_GET_FIELD(p0, VC4_TEX_P0_TYPE) |
++ (VC4_GET_FIELD(p1, VC4_TEX_P1_TYPE4) << 4));
++
++ switch (type) {
++ case VC4_TEXTURE_TYPE_RGBA8888:
++ case VC4_TEXTURE_TYPE_RGBX8888:
++ case VC4_TEXTURE_TYPE_RGBA32R:
++ cpp = 4;
++ break;
++ case VC4_TEXTURE_TYPE_RGBA4444:
++ case VC4_TEXTURE_TYPE_RGBA5551:
++ case VC4_TEXTURE_TYPE_RGB565:
++ case VC4_TEXTURE_TYPE_LUMALPHA:
++ case VC4_TEXTURE_TYPE_S16F:
++ case VC4_TEXTURE_TYPE_S16:
++ cpp = 2;
++ break;
++ case VC4_TEXTURE_TYPE_LUMINANCE:
++ case VC4_TEXTURE_TYPE_ALPHA:
++ case VC4_TEXTURE_TYPE_S8:
++ cpp = 1;
++ break;
++ case VC4_TEXTURE_TYPE_ETC1:
++ case VC4_TEXTURE_TYPE_BW1:
++ case VC4_TEXTURE_TYPE_A4:
++ case VC4_TEXTURE_TYPE_A1:
++ case VC4_TEXTURE_TYPE_RGBA64:
++ case VC4_TEXTURE_TYPE_YUV422R:
++ default:
++ DRM_ERROR("Texture format %d unsupported\n", type);
++ goto fail;
++ }
++ utile_w = utile_width(cpp);
++ utile_h = utile_height(cpp);
++
++ if (type == VC4_TEXTURE_TYPE_RGBA32R) {
++ tiling_format = VC4_TILING_FORMAT_LINEAR;
++ } else {
++ if (size_is_lt(width, height, cpp))
++ tiling_format = VC4_TILING_FORMAT_LT;
++ else
++ tiling_format = VC4_TILING_FORMAT_T;
++ }
++
++ if (!vc4_check_tex_size(exec, tex, offset + cube_map_stride * 5,
++ tiling_format, width, height, cpp)) {
++ goto fail;
++ }
++
++ /* The mipmap levels are stored before the base of the texture. Make
++ * sure there is actually space in the BO.
++ */
++ for (i = 1; i <= miplevels; i++) {
++ uint32_t level_width = max(width >> i, 1u);
++ uint32_t level_height = max(height >> i, 1u);
++ uint32_t aligned_width, aligned_height;
++ uint32_t level_size;
++
++ /* Once the levels get small enough, they drop from T to LT. */
++ if (tiling_format == VC4_TILING_FORMAT_T &&
++ size_is_lt(level_width, level_height, cpp)) {
++ tiling_format = VC4_TILING_FORMAT_LT;
++ }
++
++ switch (tiling_format) {
++ case VC4_TILING_FORMAT_T:
++ aligned_width = round_up(level_width, utile_w * 8);
++ aligned_height = round_up(level_height, utile_h * 8);
++ break;
++ case VC4_TILING_FORMAT_LT:
++ aligned_width = round_up(level_width, utile_w);
++ aligned_height = round_up(level_height, utile_h);
++ break;
++ default:
++ aligned_width = round_up(level_width, utile_w);
++ aligned_height = level_height;
++ break;
++ }
++
++ level_size = aligned_width * cpp * aligned_height;
++
++ if (offset < level_size) {
++ DRM_ERROR("Level %d (%dx%d -> %dx%d) size %db "
++ "overflowed buffer bounds (offset %d)\n",
++ i, level_width, level_height,
++ aligned_width, aligned_height,
++ level_size, offset);
++ goto fail;
++ }
++
++ offset -= level_size;
++ }
++
++ *validated_p0 = tex->paddr + p0;
++
++ return true;
++ fail:
++ DRM_INFO("Texture p0 at %d: 0x%08x\n", sample->p_offset[0], p0);
++ DRM_INFO("Texture p1 at %d: 0x%08x\n", sample->p_offset[1], p1);
++ DRM_INFO("Texture p2 at %d: 0x%08x\n", sample->p_offset[2], p2);
++ DRM_INFO("Texture p3 at %d: 0x%08x\n", sample->p_offset[3], p3);
++ return false;
++}
++
++static int
++validate_shader_rec(struct drm_device *dev,
++ struct vc4_exec_info *exec,
++ struct vc4_shader_state *state)
++{
++ uint32_t *src_handles;
++ void *pkt_u, *pkt_v;
++ enum shader_rec_reloc_type {
++ RELOC_CODE,
++ RELOC_VBO,
++ };
++ struct shader_rec_reloc {
++ enum shader_rec_reloc_type type;
++ uint32_t offset;
++ };
++ static const struct shader_rec_reloc gl_relocs[] = {
++ { RELOC_CODE, 4 }, /* fs */
++ { RELOC_CODE, 16 }, /* vs */
++ { RELOC_CODE, 28 }, /* cs */
++ };
++ static const struct shader_rec_reloc nv_relocs[] = {
++ { RELOC_CODE, 4 }, /* fs */
++ { RELOC_VBO, 12 }
++ };
++ const struct shader_rec_reloc *relocs;
++ struct drm_gem_cma_object *bo[ARRAY_SIZE(gl_relocs) + 8];
++ uint32_t nr_attributes = 0, nr_fixed_relocs, nr_relocs, packet_size;
++ int i;
++ struct vc4_validated_shader_info *validated_shader;
++
++ if (state->packet == VC4_PACKET_NV_SHADER_STATE) {
++ relocs = nv_relocs;
++ nr_fixed_relocs = ARRAY_SIZE(nv_relocs);
++
++ packet_size = 16;
++ } else {
++ relocs = gl_relocs;
++ nr_fixed_relocs = ARRAY_SIZE(gl_relocs);
++
++ nr_attributes = state->addr & 0x7;
++ if (nr_attributes == 0)
++ nr_attributes = 8;
++ packet_size = gl_shader_rec_size(state->addr);
++ }
++ nr_relocs = nr_fixed_relocs + nr_attributes;
++
++ if (nr_relocs * 4 > exec->shader_rec_size) {
++ DRM_ERROR("overflowed shader recs reading %d handles "
++ "from %d bytes left\n",
++ nr_relocs, exec->shader_rec_size);
++ return -EINVAL;
++ }
++ src_handles = exec->shader_rec_u;
++ exec->shader_rec_u += nr_relocs * 4;
++ exec->shader_rec_size -= nr_relocs * 4;
++
++ if (packet_size > exec->shader_rec_size) {
++ DRM_ERROR("overflowed shader recs copying %db packet "
++ "from %d bytes left\n",
++ packet_size, exec->shader_rec_size);
++ return -EINVAL;
++ }
++ pkt_u = exec->shader_rec_u;
++ pkt_v = exec->shader_rec_v;
++ memcpy(pkt_v, pkt_u, packet_size);
++ exec->shader_rec_u += packet_size;
++ /* Shader recs have to be aligned to 16 bytes (due to the attribute
++ * flags being in the low bytes), so round the next validated shader
++ * rec address up. This should be safe, since we've got so many
++ * relocations in a shader rec packet.
++ */
++ BUG_ON(roundup(packet_size, 16) - packet_size > nr_relocs * 4);
++ exec->shader_rec_v += roundup(packet_size, 16);
++ exec->shader_rec_size -= packet_size;
++
++ for (i = 0; i < nr_relocs; i++) {
++ enum vc4_bo_mode mode;
++
++ if (i < nr_fixed_relocs && relocs[i].type == RELOC_CODE)
++ mode = VC4_MODE_SHADER;
++ else
++ mode = VC4_MODE_RENDER;
++
++ if (!vc4_use_bo(exec, src_handles[i], mode, &bo[i])) {
++ return false;
++ }
++ }
++
++ for (i = 0; i < nr_fixed_relocs; i++) {
++ uint32_t o = relocs[i].offset;
++ uint32_t src_offset = *(uint32_t *)(pkt_u + o);
++ uint32_t *texture_handles_u;
++ void *uniform_data_u;
++ uint32_t tex;
++
++ *(uint32_t *)(pkt_v + o) = bo[i]->paddr + src_offset;
++
++ switch (relocs[i].type) {
++ case RELOC_CODE:
++ if (src_offset != 0) {
++ DRM_ERROR("Shaders must be at offset 0 of "
++ "the BO.\n");
++ goto fail;
++ }
++
++ validated_shader = to_vc4_bo(&bo[i]->base)->validated_shader;
++ if (!validated_shader)
++ goto fail;
++
++ if (validated_shader->uniforms_src_size >
++ exec->uniforms_size) {
++ DRM_ERROR("Uniforms src buffer overflow\n");
++ goto fail;
++ }
++
++ texture_handles_u = exec->uniforms_u;
++ uniform_data_u = (texture_handles_u +
++ validated_shader->num_texture_samples);
++
++ memcpy(exec->uniforms_v, uniform_data_u,
++ validated_shader->uniforms_size);
++
++ for (tex = 0;
++ tex < validated_shader->num_texture_samples;
++ tex++) {
++ if (!reloc_tex(exec,
++ uniform_data_u,
++ &validated_shader->texture_samples[tex],
++ texture_handles_u[tex])) {
++ goto fail;
++ }
++ }
++
++ *(uint32_t *)(pkt_v + o + 4) = exec->uniforms_p;
++
++ exec->uniforms_u += validated_shader->uniforms_src_size;
++ exec->uniforms_v += validated_shader->uniforms_size;
++ exec->uniforms_p += validated_shader->uniforms_size;
++
++ break;
++
++ case RELOC_VBO:
++ break;
++ }
++ }
++
++ for (i = 0; i < nr_attributes; i++) {
++ struct drm_gem_cma_object *vbo = bo[nr_fixed_relocs + i];
++ uint32_t o = 36 + i * 8;
++ uint32_t offset = *(uint32_t *)(pkt_u + o + 0);
++ uint32_t attr_size = *(uint8_t *)(pkt_u + o + 4) + 1;
++ uint32_t stride = *(uint8_t *)(pkt_u + o + 5);
++ uint32_t max_index;
++
++ if (state->addr & 0x8)
++ stride |= (*(uint32_t *)(pkt_u + 100 + i * 4)) & ~0xff;
++
++ if (vbo->base.size < offset ||
++ vbo->base.size - offset < attr_size) {
++ DRM_ERROR("BO offset overflow (%d + %d > %d)\n",
++ offset, attr_size, vbo->base.size);
++ return -EINVAL;
++ }
++
++ if (stride != 0) {
++ max_index = ((vbo->base.size - offset - attr_size) /
++ stride);
++ if (state->max_index > max_index) {
++ DRM_ERROR("primitives use index %d out of supplied %d\n",
++ state->max_index, max_index);
++ return -EINVAL;
++ }
++ }
++
++ *(uint32_t *)(pkt_v + o) = vbo->paddr + offset;
++ }
++
++ return 0;
++
++fail:
++ return -EINVAL;
++}
++
++int
++vc4_validate_shader_recs(struct drm_device *dev,
++ struct vc4_exec_info *exec)
++{
++ uint32_t i;
++ int ret = 0;
++
++ for (i = 0; i < exec->shader_state_count; i++) {
++ ret = validate_shader_rec(dev, exec, &exec->shader_state[i]);
++ if (ret)
++ return ret;
++ }
++
++ return ret;
++}
+--- /dev/null
++++ b/drivers/gpu/drm/vc4/vc4_validate_shaders.c
+@@ -0,0 +1,521 @@
++/*
++ * Copyright © 2014 Broadcom
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice (including the next
++ * paragraph) shall be included in all copies or substantial portions of the
++ * Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++/**
++ * DOC: Shader validator for VC4.
++ *
++ * The VC4 has no IOMMU between it and system memory. So, a user with access
++ * to execute shaders could escalate privilege by overwriting system memory
++ * (using the VPM write address register in the general-purpose DMA mode) or
++ * reading system memory it shouldn't (reading it as a texture, or uniform
++ * data, or vertex data).
++ *
++ * This walks over a shader starting from some offset within a BO, ensuring
++ * that its accesses are appropriately bounded, and recording how many texture
++ * accesses are made and where so that we can do relocations for them in the
++ * uniform stream.
++ *
++ * The kernel API has shaders stored in user-mapped BOs. The BOs will be
++ * forcibly unmapped from the process before validation, and any cache of
++ * validated state will be flushed if the mapping is faulted back in.
++ *
++ * Storing the shaders in BOs means that the validation process will be slow
++ * due to uncached reads, but since shaders are long-lived and shader BOs are
++ * never actually modified, this shouldn't be a problem.
++ */
++
++#include "vc4_drv.h"
++#include "vc4_qpu_defines.h"
++
++struct vc4_shader_validation_state {
++ struct vc4_texture_sample_info tmu_setup[2];
++ int tmu_write_count[2];
++
++ /* For registers that were last written to by a MIN instruction with
++ * one argument being a uniform, the address of the uniform.
++ * Otherwise, ~0.
++ *
++ * This is used for the validation of direct address memory reads.
++ */
++ uint32_t live_min_clamp_offsets[32 + 32 + 4];
++ bool live_max_clamp_regs[32 + 32 + 4];
++};
++
++static uint32_t
++waddr_to_live_reg_index(uint32_t waddr, bool is_b)
++{
++ if (waddr < 32) {
++ if (is_b)
++ return 32 + waddr;
++ else
++ return waddr;
++ } else if (waddr <= QPU_W_ACC3) {
++
++ return 64 + waddr - QPU_W_ACC0;
++ } else {
++ return ~0;
++ }
++}
++
++static uint32_t
++raddr_add_a_to_live_reg_index(uint64_t inst)
++{
++ uint32_t sig = QPU_GET_FIELD(inst, QPU_SIG);
++ uint32_t add_a = QPU_GET_FIELD(inst, QPU_ADD_A);
++ uint32_t raddr_a = QPU_GET_FIELD(inst, QPU_RADDR_A);
++ uint32_t raddr_b = QPU_GET_FIELD(inst, QPU_RADDR_B);
++
++ if (add_a == QPU_MUX_A) {
++ return raddr_a;
++ } else if (add_a == QPU_MUX_B && sig != QPU_SIG_SMALL_IMM) {
++ return 32 + raddr_b;
++ } else if (add_a <= QPU_MUX_R3) {
++ return 64 + add_a;
++ } else {
++ return ~0;
++ }
++}
++
++static bool
++is_tmu_submit(uint32_t waddr)
++{
++ return (waddr == QPU_W_TMU0_S ||
++ waddr == QPU_W_TMU1_S);
++}
++
++static bool
++is_tmu_write(uint32_t waddr)
++{
++ return (waddr >= QPU_W_TMU0_S &&
++ waddr <= QPU_W_TMU1_B);
++}
++
++static bool
++record_validated_texture_sample(struct vc4_validated_shader_info *validated_shader,
++ struct vc4_shader_validation_state *validation_state,
++ int tmu)
++{
++ uint32_t s = validated_shader->num_texture_samples;
++ int i;
++ struct vc4_texture_sample_info *temp_samples;
++
++ temp_samples = krealloc(validated_shader->texture_samples,
++ (s + 1) * sizeof(*temp_samples),
++ GFP_KERNEL);
++ if (!temp_samples)
++ return false;
++
++ memcpy(&temp_samples[s],
++ &validation_state->tmu_setup[tmu],
++ sizeof(*temp_samples));
++
++ validated_shader->num_texture_samples = s + 1;
++ validated_shader->texture_samples = temp_samples;
++
++ for (i = 0; i < 4; i++)
++ validation_state->tmu_setup[tmu].p_offset[i] = ~0;
++
++ return true;
++}
++
++static bool
++check_tmu_write(uint64_t inst,
++ struct vc4_validated_shader_info *validated_shader,
++ struct vc4_shader_validation_state *validation_state,
++ bool is_mul)
++{
++ uint32_t waddr = (is_mul ?
++ QPU_GET_FIELD(inst, QPU_WADDR_MUL) :
++ QPU_GET_FIELD(inst, QPU_WADDR_ADD));
++ uint32_t raddr_a = QPU_GET_FIELD(inst, QPU_RADDR_A);
++ uint32_t raddr_b = QPU_GET_FIELD(inst, QPU_RADDR_B);
++ int tmu = waddr > QPU_W_TMU0_B;
++ bool submit = is_tmu_submit(waddr);
++ bool is_direct = submit && validation_state->tmu_write_count[tmu] == 0;
++ uint32_t sig = QPU_GET_FIELD(inst, QPU_SIG);
++
++ if (is_direct) {
++ uint32_t add_b = QPU_GET_FIELD(inst, QPU_ADD_B);
++ uint32_t clamp_reg, clamp_offset;
++
++ if (sig == QPU_SIG_SMALL_IMM) {
++ DRM_ERROR("direct TMU read used small immediate\n");
++ return false;
++ }
++
++ /* Make sure that this texture load is an add of the base
++ * address of the UBO to a clamped offset within the UBO.
++ */
++ if (is_mul ||
++ QPU_GET_FIELD(inst, QPU_OP_ADD) != QPU_A_ADD) {
++ DRM_ERROR("direct TMU load wasn't an add\n");
++ return false;
++ }
++
++ /* We assert that the the clamped address is the first
++ * argument, and the UBO base address is the second argument.
++ * This is arbitrary, but simpler than supporting flipping the
++ * two either way.
++ */
++ clamp_reg = raddr_add_a_to_live_reg_index(inst);
++ if (clamp_reg == ~0) {
++ DRM_ERROR("direct TMU load wasn't clamped\n");
++ return false;
++ }
++
++ clamp_offset = validation_state->live_min_clamp_offsets[clamp_reg];
++ if (clamp_offset == ~0) {
++ DRM_ERROR("direct TMU load wasn't clamped\n");
++ return false;
++ }
++
++ /* Store the clamp value's offset in p1 (see reloc_tex() in
++ * vc4_validate.c).
++ */
++ validation_state->tmu_setup[tmu].p_offset[1] =
++ clamp_offset;
++
++ if (!(add_b == QPU_MUX_A && raddr_a == QPU_R_UNIF) &&
++ !(add_b == QPU_MUX_B && raddr_b == QPU_R_UNIF)) {
++ DRM_ERROR("direct TMU load didn't add to a uniform\n");
++ return false;
++ }
++
++ validation_state->tmu_setup[tmu].is_direct = true;
++ } else {
++ if (raddr_a == QPU_R_UNIF || (sig != QPU_SIG_SMALL_IMM &&
++ raddr_b == QPU_R_UNIF)) {
++ DRM_ERROR("uniform read in the same instruction as "
++ "texture setup.\n");
++ return false;
++ }
++ }
++
++ if (validation_state->tmu_write_count[tmu] >= 4) {
++ DRM_ERROR("TMU%d got too many parameters before dispatch\n",
++ tmu);
++ return false;
++ }
++ validation_state->tmu_setup[tmu].p_offset[validation_state->tmu_write_count[tmu]] =
++ validated_shader->uniforms_size;
++ validation_state->tmu_write_count[tmu]++;
++ /* Since direct uses a RADDR uniform reference, it will get counted in
++ * check_instruction_reads()
++ */
++ if (!is_direct)
++ validated_shader->uniforms_size += 4;
++
++ if (submit) {
++ if (!record_validated_texture_sample(validated_shader,
++ validation_state, tmu)) {
++ return false;
++ }
++
++ validation_state->tmu_write_count[tmu] = 0;
++ }
++
++ return true;
++}
++
++static bool
++check_register_write(uint64_t inst,
++ struct vc4_validated_shader_info *validated_shader,
++ struct vc4_shader_validation_state *validation_state,
++ bool is_mul)
++{
++ uint32_t waddr = (is_mul ?
++ QPU_GET_FIELD(inst, QPU_WADDR_MUL) :
++ QPU_GET_FIELD(inst, QPU_WADDR_ADD));
++
++ switch (waddr) {
++ case QPU_W_UNIFORMS_ADDRESS:
++ /* XXX: We'll probably need to support this for reladdr, but
++ * it's definitely a security-related one.
++ */
++ DRM_ERROR("uniforms address load unsupported\n");
++ return false;
++
++ case QPU_W_TLB_COLOR_MS:
++ case QPU_W_TLB_COLOR_ALL:
++ case QPU_W_TLB_Z:
++ /* These only interact with the tile buffer, not main memory,
++ * so they're safe.
++ */
++ return true;
++
++ case QPU_W_TMU0_S:
++ case QPU_W_TMU0_T:
++ case QPU_W_TMU0_R:
++ case QPU_W_TMU0_B:
++ case QPU_W_TMU1_S:
++ case QPU_W_TMU1_T:
++ case QPU_W_TMU1_R:
++ case QPU_W_TMU1_B:
++ return check_tmu_write(inst, validated_shader, validation_state,
++ is_mul);
++
++ case QPU_W_HOST_INT:
++ case QPU_W_TMU_NOSWAP:
++ case QPU_W_TLB_ALPHA_MASK:
++ case QPU_W_MUTEX_RELEASE:
++ /* XXX: I haven't thought about these, so don't support them
++ * for now.
++ */
++ DRM_ERROR("Unsupported waddr %d\n", waddr);
++ return false;
++
++ case QPU_W_VPM_ADDR:
++ DRM_ERROR("General VPM DMA unsupported\n");
++ return false;
++
++ case QPU_W_VPM:
++ case QPU_W_VPMVCD_SETUP:
++ /* We allow VPM setup in general, even including VPM DMA
++ * configuration setup, because the (unsafe) DMA can only be
++ * triggered by QPU_W_VPM_ADDR writes.
++ */
++ return true;
++
++ case QPU_W_TLB_STENCIL_SETUP:
++ return true;
++ }
++
++ return true;
++}
++
++static void
++track_live_clamps(uint64_t inst,
++ struct vc4_validated_shader_info *validated_shader,
++ struct vc4_shader_validation_state *validation_state)
++{
++ uint32_t op_add = QPU_GET_FIELD(inst, QPU_OP_ADD);
++ uint32_t waddr_add = QPU_GET_FIELD(inst, QPU_WADDR_ADD);
++ uint32_t waddr_mul = QPU_GET_FIELD(inst, QPU_WADDR_MUL);
++ uint32_t cond_add = QPU_GET_FIELD(inst, QPU_COND_ADD);
++ uint32_t add_a = QPU_GET_FIELD(inst, QPU_ADD_A);
++ uint32_t add_b = QPU_GET_FIELD(inst, QPU_ADD_B);
++ uint32_t raddr_a = QPU_GET_FIELD(inst, QPU_RADDR_A);
++ uint32_t raddr_b = QPU_GET_FIELD(inst, QPU_RADDR_B);
++ uint32_t sig = QPU_GET_FIELD(inst, QPU_SIG);
++ bool ws = inst & QPU_WS;
++ uint32_t lri_add_a, lri_add, lri_mul;
++ bool add_a_is_min_0;
++
++ /* Check whether OP_ADD's A argumennt comes from a live MAX(x, 0),
++ * before we clear previous live state.
++ */
++ lri_add_a = raddr_add_a_to_live_reg_index(inst);
++ add_a_is_min_0 = (lri_add_a != ~0 &&
++ validation_state->live_max_clamp_regs[lri_add_a]);
++
++ /* Clear live state for registers written by our instruction. */
++ lri_add = waddr_to_live_reg_index(waddr_add, ws);
++ lri_mul = waddr_to_live_reg_index(waddr_mul, !ws);
++ if (lri_mul != ~0) {
++ validation_state->live_max_clamp_regs[lri_mul] = false;
++ validation_state->live_min_clamp_offsets[lri_mul] = ~0;
++ }
++ if (lri_add != ~0) {
++ validation_state->live_max_clamp_regs[lri_add] = false;
++ validation_state->live_min_clamp_offsets[lri_add] = ~0;
++ } else {
++ /* Nothing further to do for live tracking, since only ADDs
++ * generate new live clamp registers.
++ */
++ return;
++ }
++
++ /* Now, handle remaining live clamp tracking for the ADD operation. */
++
++ if (cond_add != QPU_COND_ALWAYS)
++ return;
++
++ if (op_add == QPU_A_MAX) {
++ /* Track live clamps of a value to a minimum of 0 (in either
++ * arg).
++ */
++ if (sig != QPU_SIG_SMALL_IMM || raddr_b != 0 ||
++ (add_a != QPU_MUX_B && add_b != QPU_MUX_B)) {
++ return;
++ }
++
++ validation_state->live_max_clamp_regs[lri_add] = true;
++ } if (op_add == QPU_A_MIN) {
++ /* Track live clamps of a value clamped to a minimum of 0 and
++ * a maximum of some uniform's offset.
++ */
++ if (!add_a_is_min_0)
++ return;
++
++ if (!(add_b == QPU_MUX_A && raddr_a == QPU_R_UNIF) &&
++ !(add_b == QPU_MUX_B && raddr_b == QPU_R_UNIF &&
++ sig != QPU_SIG_SMALL_IMM)) {
++ return;
++ }
++
++ validation_state->live_min_clamp_offsets[lri_add] =
++ validated_shader->uniforms_size;
++ }
++}
++
++static bool
++check_instruction_writes(uint64_t inst,
++ struct vc4_validated_shader_info *validated_shader,
++ struct vc4_shader_validation_state *validation_state)
++{
++ uint32_t waddr_add = QPU_GET_FIELD(inst, QPU_WADDR_ADD);
++ uint32_t waddr_mul = QPU_GET_FIELD(inst, QPU_WADDR_MUL);
++ bool ok;
++
++ if (is_tmu_write(waddr_add) && is_tmu_write(waddr_mul)) {
++ DRM_ERROR("ADD and MUL both set up textures\n");
++ return false;
++ }
++
++ ok = (check_register_write(inst, validated_shader, validation_state, false) &&
++ check_register_write(inst, validated_shader, validation_state, true));
++
++ track_live_clamps(inst, validated_shader, validation_state);
++
++ return ok;
++}
++
++static bool
++check_instruction_reads(uint64_t inst,
++ struct vc4_validated_shader_info *validated_shader)
++{
++ uint32_t raddr_a = QPU_GET_FIELD(inst, QPU_RADDR_A);
++ uint32_t raddr_b = QPU_GET_FIELD(inst, QPU_RADDR_B);
++ uint32_t sig = QPU_GET_FIELD(inst, QPU_SIG);
++
++ if (raddr_a == QPU_R_UNIF ||
++ (raddr_b == QPU_R_UNIF && sig != QPU_SIG_SMALL_IMM)) {
++ /* This can't overflow the uint32_t, because we're reading 8
++ * bytes of instruction to increment by 4 here, so we'd
++ * already be OOM.
++ */
++ validated_shader->uniforms_size += 4;
++ }
++
++ return true;
++}
++
++struct vc4_validated_shader_info *
++vc4_validate_shader(struct drm_gem_cma_object *shader_obj)
++{
++ bool found_shader_end = false;
++ int shader_end_ip = 0;
++ uint32_t ip, max_ip;
++ uint64_t *shader;
++ struct vc4_validated_shader_info *validated_shader;
++ struct vc4_shader_validation_state validation_state;
++ int i;
++
++ memset(&validation_state, 0, sizeof(validation_state));
++
++ for (i = 0; i < 8; i++)
++ validation_state.tmu_setup[i / 4].p_offset[i % 4] = ~0;
++ for (i = 0; i < ARRAY_SIZE(validation_state.live_min_clamp_offsets); i++)
++ validation_state.live_min_clamp_offsets[i] = ~0;
++
++ shader = shader_obj->vaddr;
++ max_ip = shader_obj->base.size / sizeof(uint64_t);
++
++ validated_shader = kcalloc(sizeof(*validated_shader), 1, GFP_KERNEL);
++ if (!validated_shader)
++ return NULL;
++
++ for (ip = 0; ip < max_ip; ip++) {
++ uint64_t inst = shader[ip];
++ uint32_t sig = QPU_GET_FIELD(inst, QPU_SIG);
++
++ switch (sig) {
++ case QPU_SIG_NONE:
++ case QPU_SIG_WAIT_FOR_SCOREBOARD:
++ case QPU_SIG_SCOREBOARD_UNLOCK:
++ case QPU_SIG_COLOR_LOAD:
++ case QPU_SIG_LOAD_TMU0:
++ case QPU_SIG_LOAD_TMU1:
++ case QPU_SIG_PROG_END:
++ case QPU_SIG_SMALL_IMM:
++ if (!check_instruction_writes(inst, validated_shader,
++ &validation_state)) {
++ DRM_ERROR("Bad write at ip %d\n", ip);
++ goto fail;
++ }
++
++ if (!check_instruction_reads(inst, validated_shader))
++ goto fail;
++
++ if (sig == QPU_SIG_PROG_END) {
++ found_shader_end = true;
++ shader_end_ip = ip;
++ }
++
++ break;
++
++ case QPU_SIG_LOAD_IMM:
++ if (!check_instruction_writes(inst, validated_shader,
++ &validation_state)) {
++ DRM_ERROR("Bad LOAD_IMM write at ip %d\n", ip);
++ goto fail;
++ }
++ break;
++
++ default:
++ DRM_ERROR("Unsupported QPU signal %d at "
++ "instruction %d\n", sig, ip);
++ goto fail;
++ }
++
++ /* There are two delay slots after program end is signaled
++ * that are still executed, then we're finished.
++ */
++ if (found_shader_end && ip == shader_end_ip + 2)
++ break;
++ }
++
++ if (ip == max_ip) {
++ DRM_ERROR("shader failed to terminate before "
++ "shader BO end at %d\n",
++ shader_obj->base.size);
++ goto fail;
++ }
++
++ /* Again, no chance of integer overflow here because the worst case
++ * scenario is 8 bytes of uniforms plus handles per 8-byte
++ * instruction.
++ */
++ validated_shader->uniforms_src_size =
++ (validated_shader->uniforms_size +
++ 4 * validated_shader->num_texture_samples);
++
++ return validated_shader;
++
++fail:
++ if (validated_shader) {
++ kfree(validated_shader->texture_samples);
++ kfree(validated_shader);
++ }
++ return NULL;
++}
+--- /dev/null
++++ b/include/uapi/drm/vc4_drm.h
+@@ -0,0 +1,229 @@
++/*
++ * Copyright © 2014-2015 Broadcom
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice (including the next
++ * paragraph) shall be included in all copies or substantial portions of the
++ * Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#ifndef _UAPI_VC4_DRM_H_
++#define _UAPI_VC4_DRM_H_
++
++#include <drm/drm.h>
++
++#define DRM_VC4_SUBMIT_CL 0x00
++#define DRM_VC4_WAIT_SEQNO 0x01
++#define DRM_VC4_WAIT_BO 0x02
++#define DRM_VC4_CREATE_BO 0x03
++#define DRM_VC4_MMAP_BO 0x04
++#define DRM_VC4_CREATE_SHADER_BO 0x05
++
++#define DRM_IOCTL_VC4_SUBMIT_CL DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_SUBMIT_CL, struct drm_vc4_submit_cl)
++#define DRM_IOCTL_VC4_WAIT_SEQNO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_WAIT_SEQNO, struct drm_vc4_wait_seqno)
++#define DRM_IOCTL_VC4_WAIT_BO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_WAIT_BO, struct drm_vc4_wait_bo)
++#define DRM_IOCTL_VC4_CREATE_BO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_CREATE_BO, struct drm_vc4_create_bo)
++#define DRM_IOCTL_VC4_MMAP_BO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_MMAP_BO, struct drm_vc4_mmap_bo)
++#define DRM_IOCTL_VC4_CREATE_SHADER_BO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_CREATE_SHADER_BO, struct drm_vc4_create_shader_bo)
++
++struct drm_vc4_submit_rcl_surface {
++ uint32_t hindex; /* Handle index, or ~0 if not present. */
++ uint32_t offset; /* Offset to start of buffer. */
++ /*
++ * Bits for either render config (color_ms_write) or load/store packet.
++ */
++ uint16_t bits;
++ uint16_t pad;
++};
++
++/**
++ * struct drm_vc4_submit_cl - ioctl argument for submitting commands to the 3D
++ * engine.
++ *
++ * Drivers typically use GPU BOs to store batchbuffers / command lists and
++ * their associated state. However, because the VC4 lacks an MMU, we have to
++ * do validation of memory accesses by the GPU commands. If we were to store
++ * our commands in BOs, we'd need to do uncached readback from them to do the
++ * validation process, which is too expensive. Instead, userspace accumulates
++ * commands and associated state in plain memory, then the kernel copies the
++ * data to its own address space, and then validates and stores it in a GPU
++ * BO.
++ */
++struct drm_vc4_submit_cl {
++ /* Pointer to the binner command list.
++ *
++ * This is the first set of commands executed, which runs the
++ * coordinate shader to determine where primitives land on the screen,
++ * then writes out the state updates and draw calls necessary per tile
++ * to the tile allocation BO.
++ */
++ uint64_t bin_cl;
++
++ /* Pointer to the shader records.
++ *
++ * Shader records are the structures read by the hardware that contain
++ * pointers to uniforms, shaders, and vertex attributes. The
++ * reference to the shader record has enough information to determine
++ * how many pointers are necessary (fixed number for shaders/uniforms,
++ * and an attribute count), so those BO indices into bo_handles are
++ * just stored as uint32_ts before each shader record passed in.
++ */
++ uint64_t shader_rec;
++
++ /* Pointer to uniform data and texture handles for the textures
++ * referenced by the shader.
++ *
++ * For each shader state record, there is a set of uniform data in the
++ * order referenced by the record (FS, VS, then CS). Each set of
++ * uniform data has a uint32_t index into bo_handles per texture
++ * sample operation, in the order the QPU_W_TMUn_S writes appear in
++ * the program. Following the texture BO handle indices is the actual
++ * uniform data.
++ *
++ * The individual uniform state blocks don't have sizes passed in,
++ * because the kernel has to determine the sizes anyway during shader
++ * code validation.
++ */
++ uint64_t uniforms;
++ uint64_t bo_handles;
++
++ /* Size in bytes of the binner command list. */
++ uint32_t bin_cl_size;
++ /* Size in bytes of the set of shader records. */
++ uint32_t shader_rec_size;
++ /* Number of shader records.
++ *
++ * This could just be computed from the contents of shader_records and
++ * the address bits of references to them from the bin CL, but it
++ * keeps the kernel from having to resize some allocations it makes.
++ */
++ uint32_t shader_rec_count;
++ /* Size in bytes of the uniform state. */
++ uint32_t uniforms_size;
++
++ /* Number of BO handles passed in (size is that times 4). */
++ uint32_t bo_handle_count;
++
++ /* RCL setup: */
++ uint16_t width;
++ uint16_t height;
++ uint8_t min_x_tile;
++ uint8_t min_y_tile;
++ uint8_t max_x_tile;
++ uint8_t max_y_tile;
++ struct drm_vc4_submit_rcl_surface color_read;
++ struct drm_vc4_submit_rcl_surface color_ms_write;
++ struct drm_vc4_submit_rcl_surface zs_read;
++ struct drm_vc4_submit_rcl_surface zs_write;
++ uint32_t clear_color[2];
++ uint32_t clear_z;
++ uint8_t clear_s;
++
++ uint32_t pad:24;
++
++#define VC4_SUBMIT_CL_USE_CLEAR_COLOR (1 << 0)
++ uint32_t flags;
++
++ /* Returned value of the seqno of this render job (for the
++ * wait ioctl).
++ */
++ uint64_t seqno;
++};
++
++/**
++ * struct drm_vc4_wait_seqno - ioctl argument for waiting for
++ * DRM_VC4_SUBMIT_CL completion using its returned seqno.
++ *
++ * timeout_ns is the timeout in nanoseconds, where "0" means "don't
++ * block, just return the status."
++ */
++struct drm_vc4_wait_seqno {
++ uint64_t seqno;
++ uint64_t timeout_ns;
++};
++
++/**
++ * struct drm_vc4_wait_bo - ioctl argument for waiting for
++ * completion of the last DRM_VC4_SUBMIT_CL on a BO.
++ *
++ * This is useful for cases where multiple processes might be
++ * rendering to a BO and you want to wait for all rendering to be
++ * completed.
++ */
++struct drm_vc4_wait_bo {
++ uint32_t handle;
++ uint32_t pad;
++ uint64_t timeout_ns;
++};
++
++/**
++ * struct drm_vc4_create_bo - ioctl argument for creating VC4 BOs.
++ *
++ * There are currently no values for the flags argument, but it may be
++ * used in a future extension.
++ */
++struct drm_vc4_create_bo {
++ uint32_t size;
++ uint32_t flags;
++ /** Returned GEM handle for the BO. */
++ uint32_t handle;
++ uint32_t pad;
++};
++
++/**
++ * struct drm_vc4_create_shader_bo - ioctl argument for creating VC4
++ * shader BOs.
++ *
++ * Since allowing a shader to be overwritten while it's also being
++ * executed from would allow privlege escalation, shaders must be
++ * created using this ioctl, and they can't be mmapped later.
++ */
++struct drm_vc4_create_shader_bo {
++ /* Size of the data argument. */
++ uint32_t size;
++ /* Flags, currently must be 0. */
++ uint32_t flags;
++
++ /* Pointer to the data. */
++ uint64_t data;
++
++ /** Returned GEM handle for the BO. */
++ uint32_t handle;
++ /* Pad, must be 0. */
++ uint32_t pad;
++};
++
++/**
++ * struct drm_vc4_mmap_bo - ioctl argument for mapping VC4 BOs.
++ *
++ * This doesn't actually perform an mmap. Instead, it returns the
++ * offset you need to use in an mmap on the DRM device node. This
++ * means that tools like valgrind end up knowing about the mapped
++ * memory.
++ *
++ * There are currently no values for the flags argument, but it may be
++ * used in a future extension.
++ */
++struct drm_vc4_mmap_bo {
++ /** Handle for the object being mapped. */
++ uint32_t handle;
++ uint32_t flags;
++ /** offset into the drm node to use for subsequent mmap call. */
++ uint64_t offset;
++};
++
++#endif /* _UAPI_VC4_DRM_H_ */
diff --git a/target/linux/brcm2708/patches-4.4/0090-scripts-Multi-platform-support-for-mkknlimg-and-knli.patch b/target/linux/brcm2708/patches-4.4/0090-scripts-Multi-platform-support-for-mkknlimg-and-knli.patch
deleted file mode 100644
index 3651d18121..0000000000
--- a/target/linux/brcm2708/patches-4.4/0090-scripts-Multi-platform-support-for-mkknlimg-and-knli.patch
+++ /dev/null
@@ -1,247 +0,0 @@
-From f6dd60426dc7970ef4e9e3d9e00d374f80a6abd2 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Wed, 11 Nov 2015 11:38:59 +0000
-Subject: [PATCH 090/170] scripts: Multi-platform support for mkknlimg and
- knlinfo
-
-The firmware uses tags in the kernel trailer to choose which dtb file
-to load. Current firmware loads bcm2835-*.dtb if the '283x' tag is true,
-otherwise it loads bcm270*.dtb. This scheme breaks if an image supports
-multiple platforms.
-
-This patch adds '270X' and '283X' tags to indicate support for RPi and
-upstream platforms, respectively. '283x' (note lower case 'x') is left
-for old firmware, and is only set if the image only supports upstream
-builds.
----
- scripts/knlinfo | 2 +
- scripts/mkknlimg | 136 +++++++++++++++++++++++++++++++------------------------
- 2 files changed, 80 insertions(+), 58 deletions(-)
-
---- a/scripts/knlinfo
-+++ b/scripts/knlinfo
-@@ -18,6 +18,8 @@ my %atom_formats =
- (
- 'DTOK' => \&format_bool,
- 'KVer' => \&format_string,
-+ '270X' => \&format_bool,
-+ '283X' => \&format_bool,
- '283x' => \&format_bool,
- );
-
---- a/scripts/mkknlimg
-+++ b/scripts/mkknlimg
-@@ -13,12 +13,20 @@ use strict;
- use warnings;
- use integer;
-
-+use constant FLAG_PI => 0x01;
-+use constant FLAG_DTOK => 0x02;
-+use constant FLAG_DDTK => 0x04;
-+use constant FLAG_270X => 0x08;
-+use constant FLAG_283X => 0x10;
-+
- my $trailer_magic = 'RPTL';
-
- my $tmpfile1 = "/tmp/mkknlimg_$$.1";
- my $tmpfile2 = "/tmp/mkknlimg_$$.2";
-
- my $dtok = 0;
-+my $ddtk = 0;
-+my $is_270x = 0;
- my $is_283x = 0;
-
- while (@ARGV && ($ARGV[0] =~ /^-/))
-@@ -28,6 +36,14 @@ while (@ARGV && ($ARGV[0] =~ /^-/))
- {
- $dtok = 1;
- }
-+ elsif ($arg eq '--ddtk')
-+ {
-+ $ddtk = 1;
-+ }
-+ elsif ($arg eq '--270x')
-+ {
-+ $is_270x = 1;
-+ }
- elsif ($arg eq '--283x')
- {
- $is_283x = 1;
-@@ -50,30 +66,33 @@ if (! -r $kernel_file)
- usage();
- }
-
--my @wanted_strings =
--(
-- 'bcm2708_fb',
-- 'brcm,bcm2835-mmc',
-- 'brcm,bcm2835-sdhost',
-- 'brcm,bcm2708-pinctrl',
-- 'brcm,bcm2835-gpio',
-- 'brcm,bcm2835',
-- 'brcm,bcm2836'
--);
-+my $wanted_strings =
-+{
-+ 'bcm2708_fb' => FLAG_PI,
-+ 'brcm,bcm2835-mmc' => FLAG_PI,
-+ 'brcm,bcm2835-sdhost' => FLAG_PI,
-+ 'brcm,bcm2708-pinctrl' => FLAG_PI | FLAG_DTOK,
-+ 'brcm,bcm2835-gpio' => FLAG_PI | FLAG_DTOK,
-+ 'brcm,bcm2708' => FLAG_PI | FLAG_DTOK | FLAG_270X,
-+ 'brcm,bcm2709' => FLAG_PI | FLAG_DTOK | FLAG_270X,
-+ 'brcm,bcm2835' => FLAG_PI | FLAG_DTOK | FLAG_283X,
-+ 'brcm,bcm2836' => FLAG_PI | FLAG_DTOK | FLAG_283X,
-+ 'of_overlay_apply' => FLAG_DTOK | FLAG_DDTK,
-+};
-
- my $res = try_extract($kernel_file, $tmpfile1);
--$res = try_decompress('\037\213\010', 'xy', 'gunzip', 0,
-- $kernel_file, $tmpfile1, $tmpfile2) if (!$res);
--$res = try_decompress('\3757zXZ\000', 'abcde', 'unxz --single-stream', -1,
-- $kernel_file, $tmpfile1, $tmpfile2) if (!$res);
--$res = try_decompress('BZh', 'xy', 'bunzip2', 0,
-- $kernel_file, $tmpfile1, $tmpfile2) if (!$res);
--$res = try_decompress('\135\0\0\0', 'xxx', 'unlzma', 0,
-- $kernel_file, $tmpfile1, $tmpfile2) if (!$res);
--$res = try_decompress('\211\114\132', 'xy', 'lzop -d', 0,
-- $kernel_file, $tmpfile1, $tmpfile2) if (!$res);
--$res = try_decompress('\002\041\114\030', 'xy', 'lz4 -d', 1,
-- $kernel_file, $tmpfile1, $tmpfile2) if (!$res);
-+$res ||= try_decompress('\037\213\010', 'xy', 'gunzip', 0,
-+ $kernel_file, $tmpfile1, $tmpfile2);
-+$res ||= try_decompress('\3757zXZ\000', 'abcde', 'unxz --single-stream', -1,
-+ $kernel_file, $tmpfile1, $tmpfile2);
-+$res ||= try_decompress('BZh', 'xy', 'bunzip2', 0,
-+ $kernel_file, $tmpfile1, $tmpfile2);
-+$res ||= try_decompress('\135\0\0\0', 'xxx', 'unlzma', 0,
-+ $kernel_file, $tmpfile1, $tmpfile2);
-+$res ||= try_decompress('\211\114\132', 'xy', 'lzop -d', 0,
-+ $kernel_file, $tmpfile1, $tmpfile2);
-+$res ||= try_decompress('\002\041\114\030', 'xy', 'lz4 -d', 1,
-+ $kernel_file, $tmpfile1, $tmpfile2);
-
- my $append_trailer;
- my $trailer;
-@@ -83,27 +102,21 @@ $append_trailer = $dtok;
-
- if ($res)
- {
-- $kver = $res->{''} || '?';
-+ $kver = $res->{'kver'} || '?';
-+ my $flags = $res->{'flags'};
- print("Version: $kver\n");
-
-- $append_trailer = $dtok;
-- if (!$dtok)
-+ if ($flags & FLAG_PI)
- {
-- if (config_bool($res, 'bcm2708_fb') ||
-- config_bool($res, 'brcm,bcm2835-mmc') ||
-- config_bool($res, 'brcm,bcm2835-sdhost'))
-- {
-- $dtok ||= config_bool($res, 'brcm,bcm2708-pinctrl');
-- $dtok ||= config_bool($res, 'brcm,bcm2835-gpio');
-- $is_283x ||= config_bool($res, 'brcm,bcm2835');
-- $is_283x ||= config_bool($res, 'brcm,bcm2836');
-- $dtok ||= $is_283x;
-- $append_trailer = 1;
-- }
-- else
-- {
-- print ("* This doesn't look like a Raspberry Pi kernel. In pass-through mode.\n");
-- }
-+ $append_trailer = 1;
-+ $dtok ||= ($flags & FLAG_DTOK) != 0;
-+ $is_270x ||= ($flags & FLAG_270X) != 0;
-+ $is_283x ||= ($flags & FLAG_283X) != 0;
-+ $ddtk ||= ($flags & FLAG_DDTK) != 0;
-+ }
-+ else
-+ {
-+ print ("* This doesn't look like a Raspberry Pi kernel. In pass-through mode.\n");
- }
- }
- elsif (!$dtok)
-@@ -114,6 +127,8 @@ elsif (!$dtok)
- if ($append_trailer)
- {
- printf("DT: %s\n", $dtok ? "y" : "n");
-+ printf("DDT: %s\n", $ddtk ? "y" : "n") if ($ddtk);
-+ printf("270x: %s\n", $is_270x ? "y" : "n");
- printf("283x: %s\n", $is_283x ? "y" : "n");
-
- my @atoms;
-@@ -121,7 +136,10 @@ if ($append_trailer)
- push @atoms, [ $trailer_magic, pack('V', 0) ];
- push @atoms, [ 'KVer', $kver ];
- push @atoms, [ 'DTOK', pack('V', $dtok) ];
-- push @atoms, [ '283x', pack('V', $is_283x) ];
-+ push @atoms, [ 'DDTK', pack('V', $ddtk) ] if ($ddtk);
-+ push @atoms, [ '270X', pack('V', $is_270x) ];
-+ push @atoms, [ '283X', pack('V', $is_283x) ];
-+ push @atoms, [ '283x', pack('V', $is_283x && !$is_270x) ];
-
- $trailer = pack_trailer(\@atoms);
- $atoms[0]->[1] = pack('V', length($trailer));
-@@ -175,7 +193,7 @@ END {
-
- sub usage
- {
-- print ("Usage: mkknlimg [--dtok] [--283x] <vmlinux|zImage|bzImage> <outfile>\n");
-+ print ("Usage: mkknlimg [--dtok] [--270x] [--283x] <vmlinux|zImage|bzImage> <outfile>\n");
- exit(1);
- }
-
-@@ -189,15 +207,8 @@ sub try_extract
-
- chomp($ver);
-
-- my $res = { ''=>$ver };
-- my $string_pattern = '^('.join('|', @wanted_strings).')$';
--
-- my @matches = `strings \"$knl\" | grep -E \"$string_pattern\"`;
-- foreach my $match (@matches)
-- {
-- chomp($match);
-- $res->{$match} = 1;
-- }
-+ my $res = { 'kver'=>$ver };
-+ $res->{'flags'} = strings_to_flags($knl, $wanted_strings);
-
- return $res;
- }
-@@ -224,6 +235,22 @@ sub try_decompress
- return undef;
- }
-
-+sub strings_to_flags
-+{
-+ my ($knl, $strings) = @_;
-+ my $string_pattern = '^('.join('|', keys(%$strings)).')$';
-+ my $flags = 0;
-+
-+ my @matches = `strings \"$knl\" | grep -E \"$string_pattern\"`;
-+ foreach my $match (@matches)
-+ {
-+ chomp($match);
-+ $flags |= $strings->{$match};
-+ }
-+
-+ return $flags;
-+}
-+
- sub pack_trailer
- {
- my ($atoms) = @_;
-@@ -235,10 +262,3 @@ sub pack_trailer
- }
- return $trailer;
- }
--
--sub config_bool
--{
-- my ($configs, $wanted) = @_;
-- my $val = $configs->{$wanted} || 'n';
-- return (($val eq 'y') || ($val eq '1'));
--}
diff --git a/target/linux/brcm2708/patches-4.4/0091-drm-vc4-Add-suport-for-3D-rendering-using-the-V3D-en.patch b/target/linux/brcm2708/patches-4.4/0091-drm-vc4-Add-suport-for-3D-rendering-using-the-V3D-en.patch
deleted file mode 100644
index df0296d233..0000000000
--- a/target/linux/brcm2708/patches-4.4/0091-drm-vc4-Add-suport-for-3D-rendering-using-the-V3D-en.patch
+++ /dev/null
@@ -1,5558 +0,0 @@
-From 6d38553e5ce7fb70dd1f89665caf58064a7e97d7 Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Mon, 2 Mar 2015 13:01:12 -0800
-Subject: [PATCH 091/170] drm/vc4: Add suport for 3D rendering using the V3D
- engine.
-
-This is a squash of the out-of-tree development series. Since that
-series contained code from the first "get a demo triangle rendered
-using a hacked up driver using binary shader code" to "plug the last
-known security hole", it's hard to reconstruct a different series of
-incremental development that's mergeable without security holes
-throughout it.
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
----
- drivers/gpu/drm/vc4/Makefile | 11 +-
- drivers/gpu/drm/vc4/vc4_bo.c | 476 +++++++++++++-
- drivers/gpu/drm/vc4/vc4_crtc.c | 98 ++-
- drivers/gpu/drm/vc4/vc4_debugfs.c | 3 +
- drivers/gpu/drm/vc4/vc4_drv.c | 45 +-
- drivers/gpu/drm/vc4/vc4_drv.h | 317 ++++++++++
- drivers/gpu/drm/vc4/vc4_gem.c | 686 +++++++++++++++++++++
- drivers/gpu/drm/vc4/vc4_irq.c | 211 +++++++
- drivers/gpu/drm/vc4/vc4_kms.c | 148 ++++-
- drivers/gpu/drm/vc4/vc4_packet.h | 384 ++++++++++++
- drivers/gpu/drm/vc4/vc4_plane.c | 40 ++
- drivers/gpu/drm/vc4/vc4_qpu_defines.h | 268 ++++++++
- drivers/gpu/drm/vc4/vc4_render_cl.c | 448 ++++++++++++++
- drivers/gpu/drm/vc4/vc4_trace.h | 63 ++
- drivers/gpu/drm/vc4/vc4_trace_points.c | 14 +
- drivers/gpu/drm/vc4/vc4_v3d.c | 268 ++++++++
- drivers/gpu/drm/vc4/vc4_validate.c | 958 +++++++++++++++++++++++++++++
- drivers/gpu/drm/vc4/vc4_validate_shaders.c | 521 ++++++++++++++++
- include/uapi/drm/vc4_drm.h | 229 +++++++
- 19 files changed, 5173 insertions(+), 15 deletions(-)
- create mode 100644 drivers/gpu/drm/vc4/vc4_gem.c
- create mode 100644 drivers/gpu/drm/vc4/vc4_irq.c
- create mode 100644 drivers/gpu/drm/vc4/vc4_packet.h
- create mode 100644 drivers/gpu/drm/vc4/vc4_qpu_defines.h
- create mode 100644 drivers/gpu/drm/vc4/vc4_render_cl.c
- create mode 100644 drivers/gpu/drm/vc4/vc4_trace.h
- create mode 100644 drivers/gpu/drm/vc4/vc4_trace_points.c
- create mode 100644 drivers/gpu/drm/vc4/vc4_v3d.c
- create mode 100644 drivers/gpu/drm/vc4/vc4_validate.c
- create mode 100644 drivers/gpu/drm/vc4/vc4_validate_shaders.c
- create mode 100644 include/uapi/drm/vc4_drm.h
-
---- a/drivers/gpu/drm/vc4/Makefile
-+++ b/drivers/gpu/drm/vc4/Makefile
-@@ -8,10 +8,19 @@ vc4-y := \
- vc4_crtc.o \
- vc4_drv.o \
- vc4_kms.o \
-+ vc4_gem.o \
- vc4_hdmi.o \
- vc4_hvs.o \
-- vc4_plane.o
-+ vc4_irq.o \
-+ vc4_plane.o \
-+ vc4_render_cl.o \
-+ vc4_trace_points.o \
-+ vc4_v3d.o \
-+ vc4_validate.o \
-+ vc4_validate_shaders.o
-
- vc4-$(CONFIG_DEBUG_FS) += vc4_debugfs.o
-
- obj-$(CONFIG_DRM_VC4) += vc4.o
-+
-+CFLAGS_vc4_trace_points.o := -I$(src)
---- a/drivers/gpu/drm/vc4/vc4_bo.c
-+++ b/drivers/gpu/drm/vc4/vc4_bo.c
-@@ -15,16 +15,174 @@
- */
-
- #include "vc4_drv.h"
-+#include "uapi/drm/vc4_drm.h"
-
--struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t size)
-+static void vc4_bo_stats_dump(struct vc4_dev *vc4)
- {
-+ DRM_INFO("num bos allocated: %d\n",
-+ vc4->bo_stats.num_allocated);
-+ DRM_INFO("size bos allocated: %dkb\n",
-+ vc4->bo_stats.size_allocated / 1024);
-+ DRM_INFO("num bos used: %d\n",
-+ vc4->bo_stats.num_allocated - vc4->bo_stats.num_cached);
-+ DRM_INFO("size bos used: %dkb\n",
-+ (vc4->bo_stats.size_allocated -
-+ vc4->bo_stats.size_cached) / 1024);
-+ DRM_INFO("num bos cached: %d\n",
-+ vc4->bo_stats.num_cached);
-+ DRM_INFO("size bos cached: %dkb\n",
-+ vc4->bo_stats.size_cached / 1024);
-+}
-+
-+static uint32_t bo_page_index(size_t size)
-+{
-+ return (size / PAGE_SIZE) - 1;
-+}
-+
-+/* Must be called with bo_lock held. */
-+static void vc4_bo_destroy(struct vc4_bo *bo)
-+{
-+ struct drm_gem_object *obj = &bo->base.base;
-+ struct vc4_dev *vc4 = to_vc4_dev(obj->dev);
-+
-+ if (bo->validated_shader) {
-+ kfree(bo->validated_shader->texture_samples);
-+ kfree(bo->validated_shader);
-+ bo->validated_shader = NULL;
-+ }
-+
-+ vc4->bo_stats.num_allocated--;
-+ vc4->bo_stats.size_allocated -= obj->size;
-+ drm_gem_cma_free_object(obj);
-+}
-+
-+/* Must be called with bo_lock held. */
-+static void vc4_bo_remove_from_cache(struct vc4_bo *bo)
-+{
-+ struct drm_gem_object *obj = &bo->base.base;
-+ struct vc4_dev *vc4 = to_vc4_dev(obj->dev);
-+
-+ vc4->bo_stats.num_cached--;
-+ vc4->bo_stats.size_cached -= obj->size;
-+
-+ list_del(&bo->unref_head);
-+ list_del(&bo->size_head);
-+}
-+
-+static struct list_head *vc4_get_cache_list_for_size(struct drm_device *dev,
-+ size_t size)
-+{
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+ uint32_t page_index = bo_page_index(size);
-+
-+ if (vc4->bo_cache.size_list_size <= page_index) {
-+ uint32_t new_size = max(vc4->bo_cache.size_list_size * 2,
-+ page_index + 1);
-+ struct list_head *new_list;
-+ uint32_t i;
-+
-+ new_list = kmalloc(new_size * sizeof(struct list_head),
-+ GFP_KERNEL);
-+ if (!new_list)
-+ return NULL;
-+
-+ /* Rebase the old cached BO lists to their new list
-+ * head locations.
-+ */
-+ for (i = 0; i < vc4->bo_cache.size_list_size; i++) {
-+ struct list_head *old_list = &vc4->bo_cache.size_list[i];
-+ if (list_empty(old_list))
-+ INIT_LIST_HEAD(&new_list[i]);
-+ else
-+ list_replace(old_list, &new_list[i]);
-+ }
-+ /* And initialize the brand new BO list heads. */
-+ for (i = vc4->bo_cache.size_list_size; i < new_size; i++)
-+ INIT_LIST_HEAD(&new_list[i]);
-+
-+ kfree(vc4->bo_cache.size_list);
-+ vc4->bo_cache.size_list = new_list;
-+ vc4->bo_cache.size_list_size = new_size;
-+ }
-+
-+ return &vc4->bo_cache.size_list[page_index];
-+}
-+
-+void vc4_bo_cache_purge(struct drm_device *dev)
-+{
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+
-+ spin_lock(&vc4->bo_lock);
-+ while (!list_empty(&vc4->bo_cache.time_list)) {
-+ struct vc4_bo *bo = list_last_entry(&vc4->bo_cache.time_list,
-+ struct vc4_bo, unref_head);
-+ vc4_bo_remove_from_cache(bo);
-+ vc4_bo_destroy(bo);
-+ }
-+ spin_unlock(&vc4->bo_lock);
-+}
-+
-+struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size)
-+{
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+ uint32_t size = roundup(unaligned_size, PAGE_SIZE);
-+ uint32_t page_index = bo_page_index(size);
- struct drm_gem_cma_object *cma_obj;
-+ int pass;
-
-- cma_obj = drm_gem_cma_create(dev, size);
-- if (IS_ERR(cma_obj))
-+ if (size == 0)
- return NULL;
-- else
-- return to_vc4_bo(&cma_obj->base);
-+
-+ /* First, try to get a vc4_bo from the kernel BO cache. */
-+ spin_lock(&vc4->bo_lock);
-+ if (page_index < vc4->bo_cache.size_list_size &&
-+ !list_empty(&vc4->bo_cache.size_list[page_index])) {
-+ struct vc4_bo *bo =
-+ list_first_entry(&vc4->bo_cache.size_list[page_index],
-+ struct vc4_bo, size_head);
-+ vc4_bo_remove_from_cache(bo);
-+ spin_unlock(&vc4->bo_lock);
-+ kref_init(&bo->base.base.refcount);
-+ return bo;
-+ }
-+ spin_unlock(&vc4->bo_lock);
-+
-+ /* Otherwise, make a new BO. */
-+ for (pass = 0; ; pass++) {
-+ cma_obj = drm_gem_cma_create(dev, size);
-+ if (!IS_ERR(cma_obj))
-+ break;
-+
-+ switch (pass) {
-+ case 0:
-+ /*
-+ * If we've run out of CMA memory, kill the cache of
-+ * CMA allocations we've got laying around and try again.
-+ */
-+ vc4_bo_cache_purge(dev);
-+ break;
-+ case 1:
-+ /*
-+ * Getting desperate, so try to wait for any
-+ * previous rendering to finish, free its
-+ * unreferenced BOs to the cache, and then
-+ * free the cache.
-+ */
-+ vc4_wait_for_seqno(dev, vc4->emit_seqno, ~0ull, true);
-+ vc4_job_handle_completed(vc4);
-+ vc4_bo_cache_purge(dev);
-+ break;
-+ case 3:
-+ DRM_ERROR("Failed to allocate from CMA:\n");
-+ vc4_bo_stats_dump(vc4);
-+ return NULL;
-+ }
-+ }
-+
-+ vc4->bo_stats.num_allocated++;
-+ vc4->bo_stats.size_allocated += size;
-+
-+ return to_vc4_bo(&cma_obj->base);
- }
-
- int vc4_dumb_create(struct drm_file *file_priv,
-@@ -41,7 +199,129 @@ int vc4_dumb_create(struct drm_file *fil
- if (args->size < args->pitch * args->height)
- args->size = args->pitch * args->height;
-
-- bo = vc4_bo_create(dev, roundup(args->size, PAGE_SIZE));
-+ bo = vc4_bo_create(dev, args->size);
-+ if (!bo)
-+ return -ENOMEM;
-+
-+ ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle);
-+ drm_gem_object_unreference_unlocked(&bo->base.base);
-+
-+ return ret;
-+}
-+
-+static void
-+vc4_bo_cache_free_old(struct drm_device *dev)
-+{
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+ unsigned long expire_time = jiffies - msecs_to_jiffies(1000);
-+
-+ spin_lock(&vc4->bo_lock);
-+ while (!list_empty(&vc4->bo_cache.time_list)) {
-+ struct vc4_bo *bo = list_last_entry(&vc4->bo_cache.time_list,
-+ struct vc4_bo, unref_head);
-+ if (time_before(expire_time, bo->free_time)) {
-+ mod_timer(&vc4->bo_cache.time_timer,
-+ round_jiffies_up(jiffies +
-+ msecs_to_jiffies(1000)));
-+ spin_unlock(&vc4->bo_lock);
-+ return;
-+ }
-+
-+ vc4_bo_remove_from_cache(bo);
-+ vc4_bo_destroy(bo);
-+ }
-+ spin_unlock(&vc4->bo_lock);
-+}
-+
-+/* Called on the last userspace/kernel unreference of the BO. Returns
-+ * it to the BO cache if possible, otherwise frees it.
-+ *
-+ * Note that this is called with the struct_mutex held.
-+ */
-+void vc4_free_object(struct drm_gem_object *gem_bo)
-+{
-+ struct drm_device *dev = gem_bo->dev;
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+ struct vc4_bo *bo = to_vc4_bo(gem_bo);
-+ struct list_head *cache_list;
-+
-+ /* If the object references someone else's memory, we can't cache it.
-+ */
-+ if (gem_bo->import_attach) {
-+ vc4_bo_destroy(bo);
-+ return;
-+ }
-+
-+ /* Don't cache if it was publicly named. */
-+ if (gem_bo->name) {
-+ vc4_bo_destroy(bo);
-+ return;
-+ }
-+
-+ spin_lock(&vc4->bo_lock);
-+ cache_list = vc4_get_cache_list_for_size(dev, gem_bo->size);
-+ if (!cache_list) {
-+ vc4_bo_destroy(bo);
-+ spin_unlock(&vc4->bo_lock);
-+ return;
-+ }
-+
-+ if (bo->validated_shader) {
-+ kfree(bo->validated_shader->texture_samples);
-+ kfree(bo->validated_shader);
-+ bo->validated_shader = NULL;
-+ }
-+
-+ bo->free_time = jiffies;
-+ list_add(&bo->size_head, cache_list);
-+ list_add(&bo->unref_head, &vc4->bo_cache.time_list);
-+
-+ vc4->bo_stats.num_cached++;
-+ vc4->bo_stats.size_cached += gem_bo->size;
-+ spin_unlock(&vc4->bo_lock);
-+
-+ vc4_bo_cache_free_old(dev);
-+}
-+
-+static void vc4_bo_cache_time_work(struct work_struct *work)
-+{
-+ struct vc4_dev *vc4 =
-+ container_of(work, struct vc4_dev, bo_cache.time_work);
-+ struct drm_device *dev = vc4->dev;
-+
-+ vc4_bo_cache_free_old(dev);
-+}
-+
-+static void vc4_bo_cache_time_timer(unsigned long data)
-+{
-+ struct drm_device *dev = (struct drm_device *)data;
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+
-+ schedule_work(&vc4->bo_cache.time_work);
-+}
-+
-+struct dma_buf *
-+vc4_prime_export(struct drm_device *dev, struct drm_gem_object *obj, int flags)
-+{
-+ struct vc4_bo *bo = to_vc4_bo(obj);
-+
-+ if (bo->validated_shader) {
-+ DRM_ERROR("Attempting to export shader BO\n");
-+ return ERR_PTR(-EINVAL);
-+ }
-+
-+ return drm_gem_prime_export(dev, obj, flags);
-+}
-+
-+int
-+vc4_create_bo_ioctl(struct drm_device *dev, void *data,
-+ struct drm_file *file_priv)
-+{
-+ struct drm_vc4_create_bo *args = data;
-+ struct vc4_bo *bo = NULL;
-+ int ret;
-+
-+ bo = vc4_bo_create(dev, args->size);
- if (!bo)
- return -ENOMEM;
-
-@@ -50,3 +330,187 @@ int vc4_dumb_create(struct drm_file *fil
-
- return ret;
- }
-+
-+int
-+vc4_create_shader_bo_ioctl(struct drm_device *dev, void *data,
-+ struct drm_file *file_priv)
-+{
-+ struct drm_vc4_create_shader_bo *args = data;
-+ struct vc4_bo *bo = NULL;
-+ int ret;
-+
-+ if (args->size == 0)
-+ return -EINVAL;
-+
-+ if (args->size % sizeof(u64) != 0)
-+ return -EINVAL;
-+
-+ if (args->flags != 0) {
-+ DRM_INFO("Unknown flags set: 0x%08x\n", args->flags);
-+ return -EINVAL;
-+ }
-+
-+ if (args->pad != 0) {
-+ DRM_INFO("Pad set: 0x%08x\n", args->pad);
-+ return -EINVAL;
-+ }
-+
-+ bo = vc4_bo_create(dev, args->size);
-+ if (!bo)
-+ return -ENOMEM;
-+
-+ ret = copy_from_user(bo->base.vaddr,
-+ (void __user *)(uintptr_t)args->data,
-+ args->size);
-+ if (ret != 0)
-+ goto fail;
-+
-+ bo->validated_shader = vc4_validate_shader(&bo->base);
-+ if (!bo->validated_shader) {
-+ ret = -EINVAL;
-+ goto fail;
-+ }
-+
-+ /* We have to create the handle after validation, to avoid
-+ * races for users to do doing things like mmap the shader BO.
-+ */
-+ ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle);
-+
-+ fail:
-+ drm_gem_object_unreference_unlocked(&bo->base.base);
-+
-+ return ret;
-+}
-+
-+int
-+vc4_mmap_bo_ioctl(struct drm_device *dev, void *data,
-+ struct drm_file *file_priv)
-+{
-+ struct drm_vc4_mmap_bo *args = data;
-+ struct drm_gem_object *gem_obj;
-+
-+ gem_obj = drm_gem_object_lookup(dev, file_priv, args->handle);
-+ if (!gem_obj) {
-+ DRM_ERROR("Failed to look up GEM BO %d\n", args->handle);
-+ return -EINVAL;
-+ }
-+
-+ /* The mmap offset was set up at BO allocation time. */
-+ args->offset = drm_vma_node_offset_addr(&gem_obj->vma_node);
-+
-+ drm_gem_object_unreference(gem_obj);
-+ return 0;
-+}
-+
-+int vc4_mmap(struct file *filp, struct vm_area_struct *vma)
-+{
-+ struct drm_gem_object *gem_obj;
-+ struct vc4_bo *bo;
-+ int ret;
-+
-+ ret = drm_gem_mmap(filp, vma);
-+ if (ret)
-+ return ret;
-+
-+ gem_obj = vma->vm_private_data;
-+ bo = to_vc4_bo(gem_obj);
-+
-+ if (bo->validated_shader) {
-+ DRM_ERROR("mmaping of shader BOs not allowed.\n");
-+ return -EINVAL;
-+ }
-+
-+ /*
-+ * Clear the VM_PFNMAP flag that was set by drm_gem_mmap(), and set the
-+ * vm_pgoff (used as a fake buffer offset by DRM) to 0 as we want to map
-+ * the whole buffer.
-+ */
-+ vma->vm_flags &= ~VM_PFNMAP;
-+ vma->vm_pgoff = 0;
-+
-+ ret = dma_mmap_writecombine(bo->base.base.dev->dev, vma,
-+ bo->base.vaddr, bo->base.paddr,
-+ vma->vm_end - vma->vm_start);
-+ if (ret)
-+ drm_gem_vm_close(vma);
-+
-+ return ret;
-+}
-+
-+int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
-+{
-+ struct vc4_bo *bo = to_vc4_bo(obj);
-+
-+ if (bo->validated_shader) {
-+ DRM_ERROR("mmaping of shader BOs not allowed.\n");
-+ return -EINVAL;
-+ }
-+
-+ return drm_gem_cma_prime_mmap(obj, vma);
-+}
-+
-+void *vc4_prime_vmap(struct drm_gem_object *obj)
-+{
-+ struct vc4_bo *bo = to_vc4_bo(obj);
-+
-+ if (bo->validated_shader) {
-+ DRM_ERROR("mmaping of shader BOs not allowed.\n");
-+ return ERR_PTR(-EINVAL);
-+ }
-+
-+ return drm_gem_cma_prime_vmap(obj);
-+}
-+
-+void vc4_bo_cache_init(struct drm_device *dev)
-+{
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+
-+ spin_lock_init(&vc4->bo_lock);
-+
-+ INIT_LIST_HEAD(&vc4->bo_cache.time_list);
-+
-+ INIT_WORK(&vc4->bo_cache.time_work, vc4_bo_cache_time_work);
-+ setup_timer(&vc4->bo_cache.time_timer,
-+ vc4_bo_cache_time_timer,
-+ (unsigned long) dev);
-+}
-+
-+void vc4_bo_cache_destroy(struct drm_device *dev)
-+{
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+
-+ del_timer(&vc4->bo_cache.time_timer);
-+ cancel_work_sync(&vc4->bo_cache.time_work);
-+
-+ vc4_bo_cache_purge(dev);
-+
-+ if (vc4->bo_stats.num_allocated) {
-+ DRM_ERROR("Destroying BO cache while BOs still allocated:\n");
-+ vc4_bo_stats_dump(vc4);
-+ }
-+}
-+
-+#ifdef CONFIG_DEBUG_FS
-+int vc4_bo_stats_debugfs(struct seq_file *m, void *unused)
-+{
-+ struct drm_info_node *node = (struct drm_info_node *) m->private;
-+ struct drm_device *dev = node->minor->dev;
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+ struct vc4_bo_stats stats;
-+
-+ spin_lock(&vc4->bo_lock);
-+ stats = vc4->bo_stats;
-+ spin_unlock(&vc4->bo_lock);
-+
-+ seq_printf(m, "num bos allocated: %d\n", stats.num_allocated);
-+ seq_printf(m, "size bos allocated: %dkb\n", stats.size_allocated / 1024);
-+ seq_printf(m, "num bos used: %d\n", (stats.num_allocated -
-+ stats.num_cached));
-+ seq_printf(m, "size bos used: %dkb\n", (stats.size_allocated -
-+ stats.size_cached) / 1024);
-+ seq_printf(m, "num bos cached: %d\n", stats.num_cached);
-+ seq_printf(m, "size bos cached: %dkb\n", stats.size_cached / 1024);
-+
-+ return 0;
-+}
-+#endif
---- a/drivers/gpu/drm/vc4/vc4_crtc.c
-+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
-@@ -35,6 +35,7 @@
- #include "drm_atomic_helper.h"
- #include "drm_crtc_helper.h"
- #include "linux/clk.h"
-+#include "drm_fb_cma_helper.h"
- #include "linux/component.h"
- #include "linux/of_device.h"
- #include "vc4_drv.h"
-@@ -476,10 +477,105 @@ static irqreturn_t vc4_crtc_irq_handler(
- return ret;
- }
-
-+struct vc4_async_flip_state {
-+ struct drm_crtc *crtc;
-+ struct drm_framebuffer *fb;
-+ struct drm_pending_vblank_event *event;
-+
-+ struct vc4_seqno_cb cb;
-+};
-+
-+/* Called when the V3D execution for the BO being flipped to is done, so that
-+ * we can actually update the plane's address to point to it.
-+ */
-+static void
-+vc4_async_page_flip_complete(struct vc4_seqno_cb *cb)
-+{
-+ struct vc4_async_flip_state *flip_state =
-+ container_of(cb, struct vc4_async_flip_state, cb);
-+ struct drm_crtc *crtc = flip_state->crtc;
-+ struct drm_device *dev = crtc->dev;
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+ struct drm_plane *plane = crtc->primary;
-+
-+ vc4_plane_async_set_fb(plane, flip_state->fb);
-+ if (flip_state->event) {
-+ unsigned long flags;
-+ spin_lock_irqsave(&dev->event_lock, flags);
-+ drm_crtc_send_vblank_event(crtc, flip_state->event);
-+ spin_unlock_irqrestore(&dev->event_lock, flags);
-+ }
-+
-+ drm_framebuffer_unreference(flip_state->fb);
-+ kfree(flip_state);
-+
-+ up(&vc4->async_modeset);
-+}
-+
-+/* Implements async (non-vblank-synced) page flips.
-+ *
-+ * The page flip ioctl needs to return immediately, so we grab the
-+ * modeset semaphore on the pipe, and queue the address update for
-+ * when V3D is done with the BO being flipped to.
-+ */
-+static int vc4_async_page_flip(struct drm_crtc *crtc,
-+ struct drm_framebuffer *fb,
-+ struct drm_pending_vblank_event *event,
-+ uint32_t flags)
-+{
-+ struct drm_device *dev = crtc->dev;
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+ struct drm_plane *plane = crtc->primary;
-+ int ret = 0;
-+ struct vc4_async_flip_state *flip_state;
-+ struct drm_gem_cma_object *cma_bo = drm_fb_cma_get_gem_obj(fb, 0);
-+ struct vc4_bo *bo = to_vc4_bo(&cma_bo->base);
-+
-+ flip_state = kzalloc(sizeof(*flip_state), GFP_KERNEL);
-+ if (!flip_state)
-+ return -ENOMEM;
-+
-+ drm_framebuffer_reference(fb);
-+ flip_state->fb = fb;
-+ flip_state->crtc = crtc;
-+ flip_state->event = event;
-+
-+ /* Make sure all other async modesetes have landed. */
-+ ret = down_interruptible(&vc4->async_modeset);
-+ if (ret) {
-+ kfree(flip_state);
-+ return ret;
-+ }
-+
-+ /* Immediately update the plane's legacy fb pointer, so that later
-+ * modeset prep sees the state that will be present when the semaphore
-+ * is released.
-+ */
-+ drm_atomic_set_fb_for_plane(plane->state, fb);
-+ plane->fb = fb;
-+
-+ vc4_queue_seqno_cb(dev, &flip_state->cb, bo->seqno,
-+ vc4_async_page_flip_complete);
-+
-+ /* Driver takes ownership of state on successful async commit. */
-+ return 0;
-+}
-+
-+static int vc4_page_flip(struct drm_crtc *crtc,
-+ struct drm_framebuffer *fb,
-+ struct drm_pending_vblank_event *event,
-+ uint32_t flags)
-+{
-+ if (flags & DRM_MODE_PAGE_FLIP_ASYNC)
-+ return vc4_async_page_flip(crtc, fb, event, flags);
-+ else
-+ return drm_atomic_helper_page_flip(crtc, fb, event, flags);
-+}
-+
- static const struct drm_crtc_funcs vc4_crtc_funcs = {
- .set_config = drm_atomic_helper_set_config,
- .destroy = vc4_crtc_destroy,
-- .page_flip = drm_atomic_helper_page_flip,
-+ .page_flip = vc4_page_flip,
- .set_property = NULL,
- .cursor_set = NULL, /* handled by drm_mode_cursor_universal */
- .cursor_move = NULL, /* handled by drm_mode_cursor_universal */
---- a/drivers/gpu/drm/vc4/vc4_debugfs.c
-+++ b/drivers/gpu/drm/vc4/vc4_debugfs.c
-@@ -16,11 +16,14 @@
- #include "vc4_regs.h"
-
- static const struct drm_info_list vc4_debugfs_list[] = {
-+ {"bo_stats", vc4_bo_stats_debugfs, 0},
- {"hdmi_regs", vc4_hdmi_debugfs_regs, 0},
- {"hvs_regs", vc4_hvs_debugfs_regs, 0},
- {"crtc0_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)0},
- {"crtc1_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)1},
- {"crtc2_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)2},
-+ {"v3d_ident", vc4_v3d_debugfs_ident, 0},
-+ {"v3d_regs", vc4_v3d_debugfs_regs, 0},
- };
-
- #define VC4_DEBUGFS_ENTRIES ARRAY_SIZE(vc4_debugfs_list)
---- a/drivers/gpu/drm/vc4/vc4_drv.c
-+++ b/drivers/gpu/drm/vc4/vc4_drv.c
-@@ -14,8 +14,10 @@
- #include <linux/module.h>
- #include <linux/of_platform.h>
- #include <linux/platform_device.h>
-+#include <soc/bcm2835/raspberrypi-firmware.h>
- #include "drm_fb_cma_helper.h"
-
-+#include "uapi/drm/vc4_drm.h"
- #include "vc4_drv.h"
- #include "vc4_regs.h"
-
-@@ -63,7 +65,7 @@ static const struct file_operations vc4_
- .open = drm_open,
- .release = drm_release,
- .unlocked_ioctl = drm_ioctl,
-- .mmap = drm_gem_cma_mmap,
-+ .mmap = vc4_mmap,
- .poll = drm_poll,
- .read = drm_read,
- #ifdef CONFIG_COMPAT
-@@ -73,16 +75,28 @@ static const struct file_operations vc4_
- };
-
- static const struct drm_ioctl_desc vc4_drm_ioctls[] = {
-+ DRM_IOCTL_DEF_DRV(VC4_SUBMIT_CL, vc4_submit_cl_ioctl, 0),
-+ DRM_IOCTL_DEF_DRV(VC4_WAIT_SEQNO, vc4_wait_seqno_ioctl, 0),
-+ DRM_IOCTL_DEF_DRV(VC4_WAIT_BO, vc4_wait_bo_ioctl, 0),
-+ DRM_IOCTL_DEF_DRV(VC4_CREATE_BO, vc4_create_bo_ioctl, 0),
-+ DRM_IOCTL_DEF_DRV(VC4_MMAP_BO, vc4_mmap_bo_ioctl, 0),
-+ DRM_IOCTL_DEF_DRV(VC4_CREATE_SHADER_BO, vc4_create_shader_bo_ioctl, 0),
- };
-
- static struct drm_driver vc4_drm_driver = {
- .driver_features = (DRIVER_MODESET |
- DRIVER_ATOMIC |
- DRIVER_GEM |
-+ DRIVER_HAVE_IRQ |
- DRIVER_PRIME),
- .lastclose = vc4_lastclose,
- .preclose = vc4_drm_preclose,
-
-+ .irq_handler = vc4_irq,
-+ .irq_preinstall = vc4_irq_preinstall,
-+ .irq_postinstall = vc4_irq_postinstall,
-+ .irq_uninstall = vc4_irq_uninstall,
-+
- .enable_vblank = vc4_enable_vblank,
- .disable_vblank = vc4_disable_vblank,
- .get_vblank_counter = drm_vblank_count,
-@@ -92,18 +106,18 @@ static struct drm_driver vc4_drm_driver
- .debugfs_cleanup = vc4_debugfs_cleanup,
- #endif
-
-- .gem_free_object = drm_gem_cma_free_object,
-+ .gem_free_object = vc4_free_object,
- .gem_vm_ops = &drm_gem_cma_vm_ops,
-
- .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
- .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
- .gem_prime_import = drm_gem_prime_import,
-- .gem_prime_export = drm_gem_prime_export,
-+ .gem_prime_export = vc4_prime_export,
- .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
- .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
-- .gem_prime_vmap = drm_gem_cma_prime_vmap,
-+ .gem_prime_vmap = vc4_prime_vmap,
- .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
-- .gem_prime_mmap = drm_gem_cma_prime_mmap,
-+ .gem_prime_mmap = vc4_prime_mmap,
-
- .dumb_create = vc4_dumb_create,
- .dumb_map_offset = drm_gem_cma_dumb_map_offset,
-@@ -113,6 +127,8 @@ static struct drm_driver vc4_drm_driver
- .num_ioctls = ARRAY_SIZE(vc4_drm_ioctls),
- .fops = &vc4_drm_fops,
-
-+ .gem_obj_size = sizeof(struct vc4_bo),
-+
- .name = DRIVER_NAME,
- .desc = DRIVER_DESC,
- .date = DRIVER_DATE,
-@@ -153,6 +169,7 @@ static int vc4_drm_bind(struct device *d
- struct drm_device *drm;
- struct drm_connector *connector;
- struct vc4_dev *vc4;
-+ struct device_node *firmware_node;
- int ret = 0;
-
- dev->coherent_dma_mask = DMA_BIT_MASK(32);
-@@ -161,6 +178,14 @@ static int vc4_drm_bind(struct device *d
- if (!vc4)
- return -ENOMEM;
-
-+ firmware_node = of_parse_phandle(dev->of_node, "firmware", 0);
-+ vc4->firmware = rpi_firmware_get(firmware_node);
-+ if (!vc4->firmware) {
-+ DRM_DEBUG("Failed to get Raspberry Pi firmware reference.\n");
-+ return -EPROBE_DEFER;
-+ }
-+ of_node_put(firmware_node);
-+
- drm = drm_dev_alloc(&vc4_drm_driver, dev);
- if (!drm)
- return -ENOMEM;
-@@ -170,13 +195,17 @@ static int vc4_drm_bind(struct device *d
-
- drm_dev_set_unique(drm, dev_name(dev));
-
-+ vc4_bo_cache_init(drm);
-+
- drm_mode_config_init(drm);
- if (ret)
- goto unref;
-
-+ vc4_gem_init(drm);
-+
- ret = component_bind_all(dev, drm);
- if (ret)
-- goto unref;
-+ goto gem_destroy;
-
- ret = drm_dev_register(drm, 0);
- if (ret < 0)
-@@ -200,8 +229,11 @@ unregister:
- drm_dev_unregister(drm);
- unbind_all:
- component_unbind_all(dev, drm);
-+gem_destroy:
-+ vc4_gem_destroy(drm);
- unref:
- drm_dev_unref(drm);
-+ vc4_bo_cache_destroy(drm);
- return ret;
- }
-
-@@ -228,6 +260,7 @@ static struct platform_driver *const com
- &vc4_hdmi_driver,
- &vc4_crtc_driver,
- &vc4_hvs_driver,
-+ &vc4_v3d_driver,
- };
-
- static int vc4_platform_drm_probe(struct platform_device *pdev)
---- a/drivers/gpu/drm/vc4/vc4_drv.h
-+++ b/drivers/gpu/drm/vc4/vc4_drv.h
-@@ -15,8 +15,85 @@ struct vc4_dev {
- struct vc4_hdmi *hdmi;
- struct vc4_hvs *hvs;
- struct vc4_crtc *crtc[3];
-+ struct vc4_v3d *v3d;
-
- struct drm_fbdev_cma *fbdev;
-+ struct rpi_firmware *firmware;
-+
-+ /* The kernel-space BO cache. Tracks buffers that have been
-+ * unreferenced by all other users (refcounts of 0!) but not
-+ * yet freed, so we can do cheap allocations.
-+ */
-+ struct vc4_bo_cache {
-+ /* Array of list heads for entries in the BO cache,
-+ * based on number of pages, so we can do O(1) lookups
-+ * in the cache when allocating.
-+ */
-+ struct list_head *size_list;
-+ uint32_t size_list_size;
-+
-+ /* List of all BOs in the cache, ordered by age, so we
-+ * can do O(1) lookups when trying to free old
-+ * buffers.
-+ */
-+ struct list_head time_list;
-+ struct work_struct time_work;
-+ struct timer_list time_timer;
-+ } bo_cache;
-+
-+ struct vc4_bo_stats {
-+ u32 num_allocated;
-+ u32 size_allocated;
-+ u32 num_cached;
-+ u32 size_cached;
-+ } bo_stats;
-+
-+ /* Protects bo_cache and the BO stats. */
-+ spinlock_t bo_lock;
-+
-+ /* Sequence number for the last job queued in job_list.
-+ * Starts at 0 (no jobs emitted).
-+ */
-+ uint64_t emit_seqno;
-+
-+ /* Sequence number for the last completed job on the GPU.
-+ * Starts at 0 (no jobs completed).
-+ */
-+ uint64_t finished_seqno;
-+
-+ /* List of all struct vc4_exec_info for jobs to be executed.
-+ * The first job in the list is the one currently programmed
-+ * into ct0ca/ct1ca for execution.
-+ */
-+ struct list_head job_list;
-+ /* List of the finished vc4_exec_infos waiting to be freed by
-+ * job_done_work.
-+ */
-+ struct list_head job_done_list;
-+ spinlock_t job_lock;
-+ wait_queue_head_t job_wait_queue;
-+ struct work_struct job_done_work;
-+
-+ /* List of struct vc4_seqno_cb for callbacks to be made from a
-+ * workqueue when the given seqno is passed.
-+ */
-+ struct list_head seqno_cb_list;
-+
-+ /* The binner overflow memory that's currently set up in
-+ * BPOA/BPOS registers. When overflow occurs and a new one is
-+ * allocated, the previous one will be moved to
-+ * vc4->current_exec's free list.
-+ */
-+ struct vc4_bo *overflow_mem;
-+ struct work_struct overflow_mem_work;
-+
-+ struct {
-+ uint32_t last_ct0ca, last_ct1ca;
-+ struct timer_list timer;
-+ struct work_struct reset_work;
-+ } hangcheck;
-+
-+ struct semaphore async_modeset;
- };
-
- static inline struct vc4_dev *
-@@ -27,6 +104,25 @@ to_vc4_dev(struct drm_device *dev)
-
- struct vc4_bo {
- struct drm_gem_cma_object base;
-+
-+ /* seqno of the last job to render to this BO. */
-+ uint64_t seqno;
-+
-+ /* List entry for the BO's position in either
-+ * vc4_exec_info->unref_list or vc4_dev->bo_cache.time_list
-+ */
-+ struct list_head unref_head;
-+
-+ /* Time in jiffies when the BO was put in vc4->bo_cache. */
-+ unsigned long free_time;
-+
-+ /* List entry for the BO's position in vc4_dev->bo_cache.size_list */
-+ struct list_head size_head;
-+
-+ /* Struct for shader validation state, if created by
-+ * DRM_IOCTL_VC4_CREATE_SHADER_BO.
-+ */
-+ struct vc4_validated_shader_info *validated_shader;
- };
-
- static inline struct vc4_bo *
-@@ -35,6 +131,17 @@ to_vc4_bo(struct drm_gem_object *bo)
- return (struct vc4_bo *)bo;
- }
-
-+struct vc4_seqno_cb {
-+ struct work_struct work;
-+ uint64_t seqno;
-+ void (*func)(struct vc4_seqno_cb *cb);
-+};
-+
-+struct vc4_v3d {
-+ struct platform_device *pdev;
-+ void __iomem *regs;
-+};
-+
- struct vc4_hvs {
- struct platform_device *pdev;
- void __iomem *regs;
-@@ -72,9 +179,151 @@ to_vc4_encoder(struct drm_encoder *encod
- return container_of(encoder, struct vc4_encoder, base);
- }
-
-+#define V3D_READ(offset) readl(vc4->v3d->regs + offset)
-+#define V3D_WRITE(offset, val) writel(val, vc4->v3d->regs + offset)
- #define HVS_READ(offset) readl(vc4->hvs->regs + offset)
- #define HVS_WRITE(offset, val) writel(val, vc4->hvs->regs + offset)
-
-+enum vc4_bo_mode {
-+ VC4_MODE_UNDECIDED,
-+ VC4_MODE_RENDER,
-+ VC4_MODE_SHADER,
-+};
-+
-+struct vc4_bo_exec_state {
-+ struct drm_gem_cma_object *bo;
-+ enum vc4_bo_mode mode;
-+};
-+
-+struct vc4_exec_info {
-+ /* Sequence number for this bin/render job. */
-+ uint64_t seqno;
-+
-+ /* Kernel-space copy of the ioctl arguments */
-+ struct drm_vc4_submit_cl *args;
-+
-+ /* This is the array of BOs that were looked up at the start of exec.
-+ * Command validation will use indices into this array.
-+ */
-+ struct vc4_bo_exec_state *bo;
-+ uint32_t bo_count;
-+
-+ /* Pointers for our position in vc4->job_list */
-+ struct list_head head;
-+
-+ /* List of other BOs used in the job that need to be released
-+ * once the job is complete.
-+ */
-+ struct list_head unref_list;
-+
-+ /* Current unvalidated indices into @bo loaded by the non-hardware
-+ * VC4_PACKET_GEM_HANDLES.
-+ */
-+ uint32_t bo_index[2];
-+
-+ /* This is the BO where we store the validated command lists, shader
-+ * records, and uniforms.
-+ */
-+ struct drm_gem_cma_object *exec_bo;
-+
-+ /**
-+ * This tracks the per-shader-record state (packet 64) that
-+ * determines the length of the shader record and the offset
-+ * it's expected to be found at. It gets read in from the
-+ * command lists.
-+ */
-+ struct vc4_shader_state {
-+ uint8_t packet;
-+ uint32_t addr;
-+ /* Maximum vertex index referenced by any primitive using this
-+ * shader state.
-+ */
-+ uint32_t max_index;
-+ } *shader_state;
-+
-+ /** How many shader states the user declared they were using. */
-+ uint32_t shader_state_size;
-+ /** How many shader state records the validator has seen. */
-+ uint32_t shader_state_count;
-+
-+ bool found_tile_binning_mode_config_packet;
-+ bool found_start_tile_binning_packet;
-+ bool found_increment_semaphore_packet;
-+ uint8_t bin_tiles_x, bin_tiles_y;
-+ struct drm_gem_cma_object *tile_bo;
-+ uint32_t tile_alloc_offset;
-+
-+ /**
-+ * Computed addresses pointing into exec_bo where we start the
-+ * bin thread (ct0) and render thread (ct1).
-+ */
-+ uint32_t ct0ca, ct0ea;
-+ uint32_t ct1ca, ct1ea;
-+
-+ /* Pointers to the shader recs. These paddr gets incremented as CL
-+ * packets are relocated in validate_gl_shader_state, and the vaddrs
-+ * (u and v) get incremented and size decremented as the shader recs
-+ * themselves are validated.
-+ */
-+ void *shader_rec_u;
-+ void *shader_rec_v;
-+ uint32_t shader_rec_p;
-+ uint32_t shader_rec_size;
-+
-+ /* Pointers to the uniform data. These pointers are incremented, and
-+ * size decremented, as each batch of uniforms is uploaded.
-+ */
-+ void *uniforms_u;
-+ void *uniforms_v;
-+ uint32_t uniforms_p;
-+ uint32_t uniforms_size;
-+};
-+
-+static inline struct vc4_exec_info *
-+vc4_first_job(struct vc4_dev *vc4)
-+{
-+ if (list_empty(&vc4->job_list))
-+ return NULL;
-+ return list_first_entry(&vc4->job_list, struct vc4_exec_info, head);
-+}
-+
-+/**
-+ * struct vc4_texture_sample_info - saves the offsets into the UBO for texture
-+ * setup parameters.
-+ *
-+ * This will be used at draw time to relocate the reference to the texture
-+ * contents in p0, and validate that the offset combined with
-+ * width/height/stride/etc. from p1 and p2/p3 doesn't sample outside the BO.
-+ * Note that the hardware treats unprovided config parameters as 0, so not all
-+ * of them need to be set up for every texure sample, and we'll store ~0 as
-+ * the offset to mark the unused ones.
-+ *
-+ * See the VC4 3D architecture guide page 41 ("Texture and Memory Lookup Unit
-+ * Setup") for definitions of the texture parameters.
-+ */
-+struct vc4_texture_sample_info {
-+ bool is_direct;
-+ uint32_t p_offset[4];
-+};
-+
-+/**
-+ * struct vc4_validated_shader_info - information about validated shaders that
-+ * needs to be used from command list validation.
-+ *
-+ * For a given shader, each time a shader state record references it, we need
-+ * to verify that the shader doesn't read more uniforms than the shader state
-+ * record's uniform BO pointer can provide, and we need to apply relocations
-+ * and validate the shader state record's uniforms that define the texture
-+ * samples.
-+ */
-+struct vc4_validated_shader_info
-+{
-+ uint32_t uniforms_size;
-+ uint32_t uniforms_src_size;
-+ uint32_t num_texture_samples;
-+ struct vc4_texture_sample_info *texture_samples;
-+};
-+
- /**
- * _wait_for - magic (register) wait macro
- *
-@@ -111,6 +360,18 @@ int vc4_dumb_create(struct drm_file *fil
- struct drm_mode_create_dumb *args);
- struct dma_buf *vc4_prime_export(struct drm_device *dev,
- struct drm_gem_object *obj, int flags);
-+int vc4_create_bo_ioctl(struct drm_device *dev, void *data,
-+ struct drm_file *file_priv);
-+int vc4_create_shader_bo_ioctl(struct drm_device *dev, void *data,
-+ struct drm_file *file_priv);
-+int vc4_mmap_bo_ioctl(struct drm_device *dev, void *data,
-+ struct drm_file *file_priv);
-+int vc4_mmap(struct file *filp, struct vm_area_struct *vma);
-+int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma);
-+void *vc4_prime_vmap(struct drm_gem_object *obj);
-+void vc4_bo_cache_init(struct drm_device *dev);
-+void vc4_bo_cache_destroy(struct drm_device *dev);
-+int vc4_bo_stats_debugfs(struct seq_file *m, void *arg);
-
- /* vc4_crtc.c */
- extern struct platform_driver vc4_crtc_driver;
-@@ -126,10 +387,34 @@ void vc4_debugfs_cleanup(struct drm_mino
- /* vc4_drv.c */
- void __iomem *vc4_ioremap_regs(struct platform_device *dev, int index);
-
-+/* vc4_gem.c */
-+void vc4_gem_init(struct drm_device *dev);
-+void vc4_gem_destroy(struct drm_device *dev);
-+int vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
-+ struct drm_file *file_priv);
-+int vc4_wait_seqno_ioctl(struct drm_device *dev, void *data,
-+ struct drm_file *file_priv);
-+int vc4_wait_bo_ioctl(struct drm_device *dev, void *data,
-+ struct drm_file *file_priv);
-+void vc4_submit_next_job(struct drm_device *dev);
-+int vc4_wait_for_seqno(struct drm_device *dev, uint64_t seqno,
-+ uint64_t timeout_ns, bool interruptible);
-+void vc4_job_handle_completed(struct vc4_dev *vc4);
-+int vc4_queue_seqno_cb(struct drm_device *dev,
-+ struct vc4_seqno_cb *cb, uint64_t seqno,
-+ void (*func)(struct vc4_seqno_cb *cb));
-+
- /* vc4_hdmi.c */
- extern struct platform_driver vc4_hdmi_driver;
- int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused);
-
-+/* vc4_irq.c */
-+irqreturn_t vc4_irq(int irq, void *arg);
-+void vc4_irq_preinstall(struct drm_device *dev);
-+int vc4_irq_postinstall(struct drm_device *dev);
-+void vc4_irq_uninstall(struct drm_device *dev);
-+void vc4_irq_reset(struct drm_device *dev);
-+
- /* vc4_hvs.c */
- extern struct platform_driver vc4_hvs_driver;
- void vc4_hvs_dump_state(struct drm_device *dev);
-@@ -143,3 +428,35 @@ struct drm_plane *vc4_plane_init(struct
- enum drm_plane_type type);
- u32 vc4_plane_write_dlist(struct drm_plane *plane, u32 __iomem *dlist);
- u32 vc4_plane_dlist_size(struct drm_plane_state *state);
-+void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb);
-+
-+/* vc4_v3d.c */
-+extern struct platform_driver vc4_v3d_driver;
-+int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused);
-+int vc4_v3d_debugfs_regs(struct seq_file *m, void *unused);
-+int vc4_v3d_set_power(struct vc4_dev *vc4, bool on);
-+
-+/* vc4_validate.c */
-+int
-+vc4_validate_bin_cl(struct drm_device *dev,
-+ void *validated,
-+ void *unvalidated,
-+ struct vc4_exec_info *exec);
-+
-+int
-+vc4_validate_shader_recs(struct drm_device *dev, struct vc4_exec_info *exec);
-+
-+struct vc4_validated_shader_info *
-+vc4_validate_shader(struct drm_gem_cma_object *shader_obj);
-+
-+bool vc4_use_bo(struct vc4_exec_info *exec,
-+ uint32_t hindex,
-+ enum vc4_bo_mode mode,
-+ struct drm_gem_cma_object **obj);
-+
-+int vc4_get_rcl(struct drm_device *dev, struct vc4_exec_info *exec);
-+
-+bool vc4_check_tex_size(struct vc4_exec_info *exec,
-+ struct drm_gem_cma_object *fbo,
-+ uint32_t offset, uint8_t tiling_format,
-+ uint32_t width, uint32_t height, uint8_t cpp);
---- /dev/null
-+++ b/drivers/gpu/drm/vc4/vc4_gem.c
-@@ -0,0 +1,686 @@
-+/*
-+ * Copyright © 2014 Broadcom
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/device.h>
-+#include <linux/io.h>
-+
-+#include "uapi/drm/vc4_drm.h"
-+#include "vc4_drv.h"
-+#include "vc4_regs.h"
-+#include "vc4_trace.h"
-+
-+static void
-+vc4_queue_hangcheck(struct drm_device *dev)
-+{
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+
-+ mod_timer(&vc4->hangcheck.timer,
-+ round_jiffies_up(jiffies + msecs_to_jiffies(100)));
-+}
-+
-+static void
-+vc4_reset(struct drm_device *dev)
-+{
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+
-+ DRM_INFO("Resetting GPU.\n");
-+ vc4_v3d_set_power(vc4, false);
-+ vc4_v3d_set_power(vc4, true);
-+
-+ vc4_irq_reset(dev);
-+
-+ /* Rearm the hangcheck -- another job might have been waiting
-+ * for our hung one to get kicked off, and vc4_irq_reset()
-+ * would have started it.
-+ */
-+ vc4_queue_hangcheck(dev);
-+}
-+
-+static void
-+vc4_reset_work(struct work_struct *work)
-+{
-+ struct vc4_dev *vc4 =
-+ container_of(work, struct vc4_dev, hangcheck.reset_work);
-+
-+ vc4_reset(vc4->dev);
-+}
-+
-+static void
-+vc4_hangcheck_elapsed(unsigned long data)
-+{
-+ struct drm_device *dev = (struct drm_device *)data;
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+ uint32_t ct0ca, ct1ca;
-+
-+ /* If idle, we can stop watching for hangs. */
-+ if (list_empty(&vc4->job_list))
-+ return;
-+
-+ ct0ca = V3D_READ(V3D_CTNCA(0));
-+ ct1ca = V3D_READ(V3D_CTNCA(1));
-+
-+ /* If we've made any progress in execution, rearm the timer
-+ * and wait.
-+ */
-+ if (ct0ca != vc4->hangcheck.last_ct0ca ||
-+ ct1ca != vc4->hangcheck.last_ct1ca) {
-+ vc4->hangcheck.last_ct0ca = ct0ca;
-+ vc4->hangcheck.last_ct1ca = ct1ca;
-+ vc4_queue_hangcheck(dev);
-+ return;
-+ }
-+
-+ /* We've gone too long with no progress, reset. This has to
-+ * be done from a work struct, since resetting can sleep and
-+ * this timer hook isn't allowed to.
-+ */
-+ schedule_work(&vc4->hangcheck.reset_work);
-+}
-+
-+static void
-+submit_cl(struct drm_device *dev, uint32_t thread, uint32_t start, uint32_t end)
-+{
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+
-+ /* Stop any existing thread and set state to "stopped at halt" */
-+ V3D_WRITE(V3D_CTNCS(thread), V3D_CTRUN);
-+ barrier();
-+
-+ V3D_WRITE(V3D_CTNCA(thread), start);
-+ barrier();
-+
-+ /* Set the end address of the control list. Writing this
-+ * register is what starts the job.
-+ */
-+ V3D_WRITE(V3D_CTNEA(thread), end);
-+ barrier();
-+}
-+
-+int
-+vc4_wait_for_seqno(struct drm_device *dev, uint64_t seqno, uint64_t timeout_ns,
-+ bool interruptible)
-+{
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+ int ret = 0;
-+ unsigned long timeout_expire;
-+ DEFINE_WAIT(wait);
-+
-+ if (vc4->finished_seqno >= seqno)
-+ return 0;
-+
-+ if (timeout_ns == 0)
-+ return -ETIME;
-+
-+ timeout_expire = jiffies + nsecs_to_jiffies(timeout_ns);
-+
-+ trace_vc4_wait_for_seqno_begin(dev, seqno, timeout_ns);
-+ for (;;) {
-+ prepare_to_wait(&vc4->job_wait_queue, &wait,
-+ interruptible ? TASK_INTERRUPTIBLE :
-+ TASK_UNINTERRUPTIBLE);
-+
-+ if (interruptible && signal_pending(current)) {
-+ ret = -ERESTARTSYS;
-+ break;
-+ }
-+
-+ if (vc4->finished_seqno >= seqno)
-+ break;
-+
-+ if (timeout_ns != ~0ull) {
-+ if (time_after_eq(jiffies, timeout_expire)) {
-+ ret = -ETIME;
-+ break;
-+ }
-+ schedule_timeout(timeout_expire - jiffies);
-+ } else {
-+ schedule();
-+ }
-+ }
-+
-+ finish_wait(&vc4->job_wait_queue, &wait);
-+ trace_vc4_wait_for_seqno_end(dev, seqno);
-+
-+ if (ret && ret != -ERESTARTSYS) {
-+ DRM_ERROR("timeout waiting for render thread idle\n");
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static void
-+vc4_flush_caches(struct drm_device *dev)
-+{
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+
-+ /* Flush the GPU L2 caches. These caches sit on top of system
-+ * L3 (the 128kb or so shared with the CPU), and are
-+ * non-allocating in the L3.
-+ */
-+ V3D_WRITE(V3D_L2CACTL,
-+ V3D_L2CACTL_L2CCLR);
-+
-+ V3D_WRITE(V3D_SLCACTL,
-+ VC4_SET_FIELD(0xf, V3D_SLCACTL_T1CC) |
-+ VC4_SET_FIELD(0xf, V3D_SLCACTL_T0CC) |
-+ VC4_SET_FIELD(0xf, V3D_SLCACTL_UCC) |
-+ VC4_SET_FIELD(0xf, V3D_SLCACTL_ICC));
-+}
-+
-+/* Sets the registers for the next job to be actually be executed in
-+ * the hardware.
-+ *
-+ * The job_lock should be held during this.
-+ */
-+void
-+vc4_submit_next_job(struct drm_device *dev)
-+{
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+ struct vc4_exec_info *exec = vc4_first_job(vc4);
-+
-+ if (!exec)
-+ return;
-+
-+ vc4_flush_caches(dev);
-+
-+ /* Disable the binner's pre-loaded overflow memory address */
-+ V3D_WRITE(V3D_BPOA, 0);
-+ V3D_WRITE(V3D_BPOS, 0);
-+
-+ if (exec->ct0ca != exec->ct0ea)
-+ submit_cl(dev, 0, exec->ct0ca, exec->ct0ea);
-+ submit_cl(dev, 1, exec->ct1ca, exec->ct1ea);
-+}
-+
-+static void
-+vc4_update_bo_seqnos(struct vc4_exec_info *exec, uint64_t seqno)
-+{
-+ struct vc4_bo *bo;
-+ unsigned i;
-+
-+ for (i = 0; i < exec->bo_count; i++) {
-+ bo = to_vc4_bo(&exec->bo[i].bo->base);
-+ bo->seqno = seqno;
-+ }
-+
-+ list_for_each_entry(bo, &exec->unref_list, unref_head) {
-+ bo->seqno = seqno;
-+ }
-+}
-+
-+/* Queues a struct vc4_exec_info for execution. If no job is
-+ * currently executing, then submits it.
-+ *
-+ * Unlike most GPUs, our hardware only handles one command list at a
-+ * time. To queue multiple jobs at once, we'd need to edit the
-+ * previous command list to have a jump to the new one at the end, and
-+ * then bump the end address. That's a change for a later date,
-+ * though.
-+ */
-+static void
-+vc4_queue_submit(struct drm_device *dev, struct vc4_exec_info *exec)
-+{
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+ uint64_t seqno = ++vc4->emit_seqno;
-+ unsigned long irqflags;
-+
-+ exec->seqno = seqno;
-+ vc4_update_bo_seqnos(exec, seqno);
-+
-+ spin_lock_irqsave(&vc4->job_lock, irqflags);
-+ list_add_tail(&exec->head, &vc4->job_list);
-+
-+ /* If no job was executing, kick ours off. Otherwise, it'll
-+ * get started when the previous job's frame done interrupt
-+ * occurs.
-+ */
-+ if (vc4_first_job(vc4) == exec) {
-+ vc4_submit_next_job(dev);
-+ vc4_queue_hangcheck(dev);
-+ }
-+
-+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
-+}
-+
-+/**
-+ * Looks up a bunch of GEM handles for BOs and stores the array for
-+ * use in the command validator that actually writes relocated
-+ * addresses pointing to them.
-+ */
-+static int
-+vc4_cl_lookup_bos(struct drm_device *dev,
-+ struct drm_file *file_priv,
-+ struct vc4_exec_info *exec)
-+{
-+ struct drm_vc4_submit_cl *args = exec->args;
-+ uint32_t *handles;
-+ int ret = 0;
-+ int i;
-+
-+ exec->bo_count = args->bo_handle_count;
-+
-+ if (!exec->bo_count) {
-+ /* See comment on bo_index for why we have to check
-+ * this.
-+ */
-+ DRM_ERROR("Rendering requires BOs to validate\n");
-+ return -EINVAL;
-+ }
-+
-+ exec->bo = kcalloc(exec->bo_count, sizeof(struct vc4_bo_exec_state),
-+ GFP_KERNEL);
-+ if (!exec->bo) {
-+ DRM_ERROR("Failed to allocate validated BO pointers\n");
-+ return -ENOMEM;
-+ }
-+
-+ handles = drm_malloc_ab(exec->bo_count, sizeof(uint32_t));
-+ if (!handles) {
-+ DRM_ERROR("Failed to allocate incoming GEM handles\n");
-+ goto fail;
-+ }
-+
-+ ret = copy_from_user(handles,
-+ (void __user *)(uintptr_t)args->bo_handles,
-+ exec->bo_count * sizeof(uint32_t));
-+ if (ret) {
-+ DRM_ERROR("Failed to copy in GEM handles\n");
-+ goto fail;
-+ }
-+
-+ spin_lock(&file_priv->table_lock);
-+ for (i = 0; i < exec->bo_count; i++) {
-+ struct drm_gem_object *bo = idr_find(&file_priv->object_idr,
-+ handles[i]);
-+ if (!bo) {
-+ DRM_ERROR("Failed to look up GEM BO %d: %d\n",
-+ i, handles[i]);
-+ ret = -EINVAL;
-+ spin_unlock(&file_priv->table_lock);
-+ goto fail;
-+ }
-+ drm_gem_object_reference(bo);
-+ exec->bo[i].bo = (struct drm_gem_cma_object *)bo;
-+ }
-+ spin_unlock(&file_priv->table_lock);
-+
-+fail:
-+ kfree(handles);
-+ return 0;
-+}
-+
-+static int
-+vc4_get_bcl(struct drm_device *dev, struct vc4_exec_info *exec)
-+{
-+ struct drm_vc4_submit_cl *args = exec->args;
-+ void *temp = NULL;
-+ void *bin;
-+ int ret = 0;
-+ uint32_t bin_offset = 0;
-+ uint32_t shader_rec_offset = roundup(bin_offset + args->bin_cl_size,
-+ 16);
-+ uint32_t uniforms_offset = shader_rec_offset + args->shader_rec_size;
-+ uint32_t exec_size = uniforms_offset + args->uniforms_size;
-+ uint32_t temp_size = exec_size + (sizeof(struct vc4_shader_state) *
-+ args->shader_rec_count);
-+ struct vc4_bo *bo;
-+
-+ if (uniforms_offset < shader_rec_offset ||
-+ exec_size < uniforms_offset ||
-+ args->shader_rec_count >= (UINT_MAX /
-+ sizeof(struct vc4_shader_state)) ||
-+ temp_size < exec_size) {
-+ DRM_ERROR("overflow in exec arguments\n");
-+ goto fail;
-+ }
-+
-+ /* Allocate space where we'll store the copied in user command lists
-+ * and shader records.
-+ *
-+ * We don't just copy directly into the BOs because we need to
-+ * read the contents back for validation, and I think the
-+ * bo->vaddr is uncached access.
-+ */
-+ temp = kmalloc(temp_size, GFP_KERNEL);
-+ if (!temp) {
-+ DRM_ERROR("Failed to allocate storage for copying "
-+ "in bin/render CLs.\n");
-+ ret = -ENOMEM;
-+ goto fail;
-+ }
-+ bin = temp + bin_offset;
-+ exec->shader_rec_u = temp + shader_rec_offset;
-+ exec->uniforms_u = temp + uniforms_offset;
-+ exec->shader_state = temp + exec_size;
-+ exec->shader_state_size = args->shader_rec_count;
-+
-+ ret = copy_from_user(bin,
-+ (void __user *)(uintptr_t)args->bin_cl,
-+ args->bin_cl_size);
-+ if (ret) {
-+ DRM_ERROR("Failed to copy in bin cl\n");
-+ goto fail;
-+ }
-+
-+ ret = copy_from_user(exec->shader_rec_u,
-+ (void __user *)(uintptr_t)args->shader_rec,
-+ args->shader_rec_size);
-+ if (ret) {
-+ DRM_ERROR("Failed to copy in shader recs\n");
-+ goto fail;
-+ }
-+
-+ ret = copy_from_user(exec->uniforms_u,
-+ (void __user *)(uintptr_t)args->uniforms,
-+ args->uniforms_size);
-+ if (ret) {
-+ DRM_ERROR("Failed to copy in uniforms cl\n");
-+ goto fail;
-+ }
-+
-+ bo = vc4_bo_create(dev, exec_size);
-+ if (!bo) {
-+ DRM_ERROR("Couldn't allocate BO for binning\n");
-+ ret = PTR_ERR(exec->exec_bo);
-+ goto fail;
-+ }
-+ exec->exec_bo = &bo->base;
-+
-+ list_add_tail(&to_vc4_bo(&exec->exec_bo->base)->unref_head,
-+ &exec->unref_list);
-+
-+ exec->ct0ca = exec->exec_bo->paddr + bin_offset;
-+
-+ exec->shader_rec_v = exec->exec_bo->vaddr + shader_rec_offset;
-+ exec->shader_rec_p = exec->exec_bo->paddr + shader_rec_offset;
-+ exec->shader_rec_size = args->shader_rec_size;
-+
-+ exec->uniforms_v = exec->exec_bo->vaddr + uniforms_offset;
-+ exec->uniforms_p = exec->exec_bo->paddr + uniforms_offset;
-+ exec->uniforms_size = args->uniforms_size;
-+
-+ ret = vc4_validate_bin_cl(dev,
-+ exec->exec_bo->vaddr + bin_offset,
-+ bin,
-+ exec);
-+ if (ret)
-+ goto fail;
-+
-+ ret = vc4_validate_shader_recs(dev, exec);
-+
-+fail:
-+ kfree(temp);
-+ return ret;
-+}
-+
-+static void
-+vc4_complete_exec(struct vc4_exec_info *exec)
-+{
-+ unsigned i;
-+
-+ if (exec->bo) {
-+ for (i = 0; i < exec->bo_count; i++)
-+ drm_gem_object_unreference(&exec->bo[i].bo->base);
-+ kfree(exec->bo);
-+ }
-+
-+ while (!list_empty(&exec->unref_list)) {
-+ struct vc4_bo *bo = list_first_entry(&exec->unref_list,
-+ struct vc4_bo, unref_head);
-+ list_del(&bo->unref_head);
-+ drm_gem_object_unreference(&bo->base.base);
-+ }
-+
-+ kfree(exec);
-+}
-+
-+void
-+vc4_job_handle_completed(struct vc4_dev *vc4)
-+{
-+ unsigned long irqflags;
-+ struct vc4_seqno_cb *cb, *cb_temp;
-+
-+ spin_lock_irqsave(&vc4->job_lock, irqflags);
-+ while (!list_empty(&vc4->job_done_list)) {
-+ struct vc4_exec_info *exec =
-+ list_first_entry(&vc4->job_done_list,
-+ struct vc4_exec_info, head);
-+ list_del(&exec->head);
-+
-+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
-+ vc4_complete_exec(exec);
-+ spin_lock_irqsave(&vc4->job_lock, irqflags);
-+ }
-+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
-+
-+ list_for_each_entry_safe(cb, cb_temp, &vc4->seqno_cb_list, work.entry) {
-+ if (cb->seqno <= vc4->finished_seqno) {
-+ list_del_init(&cb->work.entry);
-+ schedule_work(&cb->work);
-+ }
-+ }
-+}
-+
-+static void vc4_seqno_cb_work(struct work_struct *work)
-+{
-+ struct vc4_seqno_cb *cb = container_of(work, struct vc4_seqno_cb, work);
-+ cb->func(cb);
-+}
-+
-+int vc4_queue_seqno_cb(struct drm_device *dev,
-+ struct vc4_seqno_cb *cb, uint64_t seqno,
-+ void (*func)(struct vc4_seqno_cb *cb))
-+{
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+ int ret = 0;
-+
-+ cb->func = func;
-+ INIT_WORK(&cb->work, vc4_seqno_cb_work);
-+
-+ mutex_lock(&dev->struct_mutex);
-+ if (seqno > vc4->finished_seqno) {
-+ cb->seqno = seqno;
-+ list_add_tail(&cb->work.entry, &vc4->seqno_cb_list);
-+ } else {
-+ schedule_work(&cb->work);
-+ }
-+ mutex_unlock(&dev->struct_mutex);
-+
-+ return ret;
-+}
-+
-+/* Scheduled when any job has been completed, this walks the list of
-+ * jobs that had completed and unrefs their BOs and frees their exec
-+ * structs.
-+ */
-+static void
-+vc4_job_done_work(struct work_struct *work)
-+{
-+ struct vc4_dev *vc4 =
-+ container_of(work, struct vc4_dev, job_done_work);
-+ struct drm_device *dev = vc4->dev;
-+
-+ /* Need the struct lock for drm_gem_object_unreference(). */
-+ mutex_lock(&dev->struct_mutex);
-+ vc4_job_handle_completed(vc4);
-+ mutex_unlock(&dev->struct_mutex);
-+}
-+
-+static int
-+vc4_wait_for_seqno_ioctl_helper(struct drm_device *dev,
-+ uint64_t seqno,
-+ uint64_t *timeout_ns)
-+{
-+ unsigned long start = jiffies;
-+ int ret = vc4_wait_for_seqno(dev, seqno, *timeout_ns, true);
-+
-+ if ((ret == -EINTR || ret == -ERESTARTSYS) && *timeout_ns != ~0ull) {
-+ uint64_t delta = jiffies_to_nsecs(jiffies - start);
-+ if (*timeout_ns >= delta)
-+ *timeout_ns -= delta;
-+ }
-+
-+ return ret;
-+}
-+
-+int
-+vc4_wait_seqno_ioctl(struct drm_device *dev, void *data,
-+ struct drm_file *file_priv)
-+{
-+ struct drm_vc4_wait_seqno *args = data;
-+
-+ return vc4_wait_for_seqno_ioctl_helper(dev, args->seqno,
-+ &args->timeout_ns);
-+}
-+
-+int
-+vc4_wait_bo_ioctl(struct drm_device *dev, void *data,
-+ struct drm_file *file_priv)
-+{
-+ int ret;
-+ struct drm_vc4_wait_bo *args = data;
-+ struct drm_gem_object *gem_obj;
-+ struct vc4_bo *bo;
-+
-+ gem_obj = drm_gem_object_lookup(dev, file_priv, args->handle);
-+ if (!gem_obj) {
-+ DRM_ERROR("Failed to look up GEM BO %d\n", args->handle);
-+ return -EINVAL;
-+ }
-+ bo = to_vc4_bo(gem_obj);
-+
-+ ret = vc4_wait_for_seqno_ioctl_helper(dev, bo->seqno, &args->timeout_ns);
-+
-+ drm_gem_object_unreference(gem_obj);
-+ return ret;
-+}
-+
-+/**
-+ * Submits a command list to the VC4.
-+ *
-+ * This is what is called batchbuffer emitting on other hardware.
-+ */
-+int
-+vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
-+ struct drm_file *file_priv)
-+{
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+ struct drm_vc4_submit_cl *args = data;
-+ struct vc4_exec_info *exec;
-+ int ret;
-+
-+ if ((args->flags & ~VC4_SUBMIT_CL_USE_CLEAR_COLOR) != 0) {
-+ DRM_ERROR("Unknown flags: 0x%02x\n", args->flags);
-+ return -EINVAL;
-+ }
-+
-+ exec = kcalloc(1, sizeof(*exec), GFP_KERNEL);
-+ if (!exec) {
-+ DRM_ERROR("malloc failure on exec struct\n");
-+ return -ENOMEM;
-+ }
-+
-+ exec->args = args;
-+ INIT_LIST_HEAD(&exec->unref_list);
-+
-+ mutex_lock(&dev->struct_mutex);
-+
-+ ret = vc4_cl_lookup_bos(dev, file_priv, exec);
-+ if (ret)
-+ goto fail;
-+
-+ if (exec->args->bin_cl_size != 0) {
-+ ret = vc4_get_bcl(dev, exec);
-+ if (ret)
-+ goto fail;
-+ } else {
-+ exec->ct0ca = exec->ct0ea = 0;
-+ }
-+
-+ ret = vc4_get_rcl(dev, exec);
-+ if (ret)
-+ goto fail;
-+
-+ /* Clear this out of the struct we'll be putting in the queue,
-+ * since it's part of our stack.
-+ */
-+ exec->args = NULL;
-+
-+ vc4_queue_submit(dev, exec);
-+
-+ /* Return the seqno for our job. */
-+ args->seqno = vc4->emit_seqno;
-+
-+ mutex_unlock(&dev->struct_mutex);
-+
-+ return 0;
-+
-+fail:
-+ vc4_complete_exec(exec);
-+
-+ mutex_unlock(&dev->struct_mutex);
-+
-+ return ret;
-+}
-+
-+void
-+vc4_gem_init(struct drm_device *dev)
-+{
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+
-+ INIT_LIST_HEAD(&vc4->job_list);
-+ INIT_LIST_HEAD(&vc4->job_done_list);
-+ INIT_LIST_HEAD(&vc4->seqno_cb_list);
-+ spin_lock_init(&vc4->job_lock);
-+
-+ INIT_WORK(&vc4->hangcheck.reset_work, vc4_reset_work);
-+ setup_timer(&vc4->hangcheck.timer,
-+ vc4_hangcheck_elapsed,
-+ (unsigned long) dev);
-+
-+ INIT_WORK(&vc4->job_done_work, vc4_job_done_work);
-+}
-+
-+void
-+vc4_gem_destroy(struct drm_device *dev)
-+{
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+
-+ /* Waiting for exec to finish would need to be done before
-+ * unregistering V3D.
-+ */
-+ WARN_ON(vc4->emit_seqno != vc4->finished_seqno);
-+
-+ /* V3D should already have disabled its interrupt and cleared
-+ * the overflow allocation registers. Now free the object.
-+ */
-+ if (vc4->overflow_mem) {
-+ drm_gem_object_unreference_unlocked(&vc4->overflow_mem->base.base);
-+ vc4->overflow_mem = NULL;
-+ }
-+
-+ vc4_bo_cache_destroy(dev);
-+}
---- /dev/null
-+++ b/drivers/gpu/drm/vc4/vc4_irq.c
-@@ -0,0 +1,211 @@
-+/*
-+ * Copyright © 2014 Broadcom
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
-+ */
-+
-+/** DOC: Interrupt management for the V3D engine.
-+ *
-+ * We have an interrupt status register (V3D_INTCTL) which reports
-+ * interrupts, and where writing 1 bits clears those interrupts.
-+ * There are also a pair of interrupt registers
-+ * (V3D_INTENA/V3D_INTDIS) where writing a 1 to their bits enables or
-+ * disables that specific interrupt, and 0s written are ignored
-+ * (reading either one returns the set of enabled interrupts).
-+ *
-+ * When we take a render frame interrupt, we need to wake the
-+ * processes waiting for some frame to be done, and get the next frame
-+ * submitted ASAP (so the hardware doesn't sit idle when there's work
-+ * to do).
-+ *
-+ * When we take the binner out of memory interrupt, we need to
-+ * allocate some new memory and pass it to the binner so that the
-+ * current job can make progress.
-+ */
-+
-+#include "vc4_drv.h"
-+#include "vc4_regs.h"
-+
-+#define V3D_DRIVER_IRQS (V3D_INT_OUTOMEM | \
-+ V3D_INT_FRDONE)
-+
-+DECLARE_WAIT_QUEUE_HEAD(render_wait);
-+
-+static void
-+vc4_overflow_mem_work(struct work_struct *work)
-+{
-+ struct vc4_dev *vc4 =
-+ container_of(work, struct vc4_dev, overflow_mem_work);
-+ struct drm_device *dev = vc4->dev;
-+ struct vc4_bo *bo;
-+
-+ bo = vc4_bo_create(dev, 256 * 1024);
-+ if (!bo) {
-+ DRM_ERROR("Couldn't allocate binner overflow mem\n");
-+ return;
-+ }
-+
-+ /* If there's a job executing currently, then our previous
-+ * overflow allocation is getting used in that job and we need
-+ * to queue it to be released when the job is done. But if no
-+ * job is executing at all, then we can free the old overflow
-+ * object direcctly.
-+ *
-+ * No lock necessary for this pointer since we're the only
-+ * ones that update the pointer, and our workqueue won't
-+ * reenter.
-+ */
-+ if (vc4->overflow_mem) {
-+ struct vc4_exec_info *current_exec;
-+ unsigned long irqflags;
-+
-+ spin_lock_irqsave(&vc4->job_lock, irqflags);
-+ current_exec = vc4_first_job(vc4);
-+ if (current_exec) {
-+ vc4->overflow_mem->seqno = vc4->finished_seqno + 1;
-+ list_add_tail(&vc4->overflow_mem->unref_head,
-+ &current_exec->unref_list);
-+ vc4->overflow_mem = NULL;
-+ }
-+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
-+ }
-+
-+ if (vc4->overflow_mem) {
-+ drm_gem_object_unreference_unlocked(&vc4->overflow_mem->base.base);
-+ }
-+ vc4->overflow_mem = bo;
-+
-+ V3D_WRITE(V3D_BPOA, bo->base.paddr);
-+ V3D_WRITE(V3D_BPOS, bo->base.base.size);
-+ V3D_WRITE(V3D_INTCTL, V3D_INT_OUTOMEM);
-+ V3D_WRITE(V3D_INTENA, V3D_INT_OUTOMEM);
-+}
-+
-+static void
-+vc4_irq_finish_job(struct drm_device *dev)
-+{
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+ struct vc4_exec_info *exec = vc4_first_job(vc4);
-+
-+ if (!exec)
-+ return;
-+
-+ vc4->finished_seqno++;
-+ list_move_tail(&exec->head, &vc4->job_done_list);
-+ vc4_submit_next_job(dev);
-+
-+ wake_up_all(&vc4->job_wait_queue);
-+ schedule_work(&vc4->job_done_work);
-+}
-+
-+irqreturn_t
-+vc4_irq(int irq, void *arg)
-+{
-+ struct drm_device *dev = arg;
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+ uint32_t intctl;
-+ irqreturn_t status = IRQ_NONE;
-+
-+ barrier();
-+ intctl = V3D_READ(V3D_INTCTL);
-+
-+ /* Acknowledge the interrupts we're handling here. The render
-+ * frame done interrupt will be cleared, while OUTOMEM will
-+ * stay high until the underlying cause is cleared.
-+ */
-+ V3D_WRITE(V3D_INTCTL, intctl);
-+
-+ if (intctl & V3D_INT_OUTOMEM) {
-+ /* Disable OUTOMEM until the work is done. */
-+ V3D_WRITE(V3D_INTDIS, V3D_INT_OUTOMEM);
-+ schedule_work(&vc4->overflow_mem_work);
-+ status = IRQ_HANDLED;
-+ }
-+
-+ if (intctl & V3D_INT_FRDONE) {
-+ spin_lock(&vc4->job_lock);
-+ vc4_irq_finish_job(dev);
-+ spin_unlock(&vc4->job_lock);
-+ status = IRQ_HANDLED;
-+ }
-+
-+ return status;
-+}
-+
-+void
-+vc4_irq_preinstall(struct drm_device *dev)
-+{
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+
-+ init_waitqueue_head(&vc4->job_wait_queue);
-+ INIT_WORK(&vc4->overflow_mem_work, vc4_overflow_mem_work);
-+
-+ /* Clear any pending interrupts someone might have left around
-+ * for us.
-+ */
-+ V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS);
-+}
-+
-+int
-+vc4_irq_postinstall(struct drm_device *dev)
-+{
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+
-+ /* Enable both the render done and out of memory interrupts. */
-+ V3D_WRITE(V3D_INTENA, V3D_DRIVER_IRQS);
-+
-+ return 0;
-+}
-+
-+void
-+vc4_irq_uninstall(struct drm_device *dev)
-+{
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+
-+ /* Disable sending interrupts for our driver's IRQs. */
-+ V3D_WRITE(V3D_INTDIS, V3D_DRIVER_IRQS);
-+
-+ /* Clear any pending interrupts we might have left. */
-+ V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS);
-+
-+ cancel_work_sync(&vc4->overflow_mem_work);
-+}
-+
-+/** Reinitializes interrupt registers when a GPU reset is performed. */
-+void vc4_irq_reset(struct drm_device *dev)
-+{
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+ unsigned long irqflags;
-+
-+ /* Acknowledge any stale IRQs. */
-+ V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS);
-+
-+ /*
-+ * Turn all our interrupts on. Binner out of memory is the
-+ * only one we expect to trigger at this point, since we've
-+ * just come from poweron and haven't supplied any overflow
-+ * memory yet.
-+ */
-+ V3D_WRITE(V3D_INTENA, V3D_DRIVER_IRQS);
-+
-+ spin_lock_irqsave(&vc4->job_lock, irqflags);
-+ vc4_irq_finish_job(dev);
-+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
-+}
---- a/drivers/gpu/drm/vc4/vc4_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_kms.c
-@@ -15,6 +15,7 @@
- */
-
- #include "drm_crtc.h"
-+#include "drm_atomic.h"
- #include "drm_atomic_helper.h"
- #include "drm_crtc_helper.h"
- #include "drm_plane_helper.h"
-@@ -29,10 +30,151 @@ static void vc4_output_poll_changed(stru
- drm_fbdev_cma_hotplug_event(vc4->fbdev);
- }
-
-+struct vc4_commit {
-+ struct drm_device *dev;
-+ struct drm_atomic_state *state;
-+ struct vc4_seqno_cb cb;
-+};
-+
-+static void
-+vc4_atomic_complete_commit(struct vc4_commit *c)
-+{
-+ struct drm_atomic_state *state = c->state;
-+ struct drm_device *dev = state->dev;
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+
-+ drm_atomic_helper_commit_modeset_disables(dev, state);
-+
-+ drm_atomic_helper_commit_planes(dev, state);
-+
-+ drm_atomic_helper_commit_modeset_enables(dev, state);
-+
-+ drm_atomic_helper_wait_for_vblanks(dev, state);
-+
-+ drm_atomic_helper_cleanup_planes(dev, state);
-+
-+ drm_atomic_state_free(state);
-+
-+ up(&vc4->async_modeset);
-+
-+ kfree(c);
-+}
-+
-+static void
-+vc4_atomic_complete_commit_seqno_cb(struct vc4_seqno_cb *cb)
-+{
-+ struct vc4_commit *c = container_of(cb, struct vc4_commit, cb);
-+
-+ vc4_atomic_complete_commit(c);
-+}
-+
-+static struct vc4_commit *commit_init(struct drm_atomic_state *state)
-+{
-+ struct vc4_commit *c = kzalloc(sizeof(*c), GFP_KERNEL);
-+
-+ if (!c)
-+ return NULL;
-+ c->dev = state->dev;
-+ c->state = state;
-+
-+ return c;
-+}
-+
-+/**
-+ * vc4_atomic_commit - commit validated state object
-+ * @dev: DRM device
-+ * @state: the driver state object
-+ * @async: asynchronous commit
-+ *
-+ * This function commits a with drm_atomic_helper_check() pre-validated state
-+ * object. This can still fail when e.g. the framebuffer reservation fails. For
-+ * now this doesn't implement asynchronous commits.
-+ *
-+ * RETURNS
-+ * Zero for success or -errno.
-+ */
-+static int vc4_atomic_commit(struct drm_device *dev,
-+ struct drm_atomic_state *state,
-+ bool async)
-+{
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+ int ret;
-+ int i;
-+ uint64_t wait_seqno = 0;
-+ struct vc4_commit *c;
-+
-+ c = commit_init(state);
-+ if (!c)
-+ return -ENOMEM;
-+
-+ /* Make sure that any outstanding modesets have finished. */
-+ ret = down_interruptible(&vc4->async_modeset);
-+ if (ret) {
-+ kfree(c);
-+ return ret;
-+ }
-+
-+ ret = drm_atomic_helper_prepare_planes(dev, state);
-+ if (ret) {
-+ kfree(c);
-+ up(&vc4->async_modeset);
-+ return ret;
-+ }
-+
-+ for (i = 0; i < dev->mode_config.num_total_plane; i++) {
-+ struct drm_plane *plane = state->planes[i];
-+ struct drm_plane_state *new_state = state->plane_states[i];
-+
-+ if (!plane)
-+ continue;
-+
-+ if ((plane->state->fb != new_state->fb) && new_state->fb) {
-+ struct drm_gem_cma_object *cma_bo =
-+ drm_fb_cma_get_gem_obj(new_state->fb, 0);
-+ struct vc4_bo *bo = to_vc4_bo(&cma_bo->base);
-+ wait_seqno = max(bo->seqno, wait_seqno);
-+ }
-+ }
-+
-+ /*
-+ * This is the point of no return - everything below never fails except
-+ * when the hw goes bonghits. Which means we can commit the new state on
-+ * the software side now.
-+ */
-+
-+ drm_atomic_helper_swap_state(dev, state);
-+
-+ /*
-+ * Everything below can be run asynchronously without the need to grab
-+ * any modeset locks at all under one condition: It must be guaranteed
-+ * that the asynchronous work has either been cancelled (if the driver
-+ * supports it, which at least requires that the framebuffers get
-+ * cleaned up with drm_atomic_helper_cleanup_planes()) or completed
-+ * before the new state gets committed on the software side with
-+ * drm_atomic_helper_swap_state().
-+ *
-+ * This scheme allows new atomic state updates to be prepared and
-+ * checked in parallel to the asynchronous completion of the previous
-+ * update. Which is important since compositors need to figure out the
-+ * composition of the next frame right after having submitted the
-+ * current layout.
-+ */
-+
-+ if (async) {
-+ vc4_queue_seqno_cb(dev, &c->cb, wait_seqno,
-+ vc4_atomic_complete_commit_seqno_cb);
-+ } else {
-+ vc4_wait_for_seqno(dev, wait_seqno, ~0ull, false);
-+ vc4_atomic_complete_commit(c);
-+ }
-+
-+ return 0;
-+}
-+
- static const struct drm_mode_config_funcs vc4_mode_funcs = {
- .output_poll_changed = vc4_output_poll_changed,
- .atomic_check = drm_atomic_helper_check,
-- .atomic_commit = drm_atomic_helper_commit,
-+ .atomic_commit = vc4_atomic_commit,
- .fb_create = drm_fb_cma_create,
- };
-
-@@ -41,6 +183,8 @@ int vc4_kms_load(struct drm_device *dev)
- struct vc4_dev *vc4 = to_vc4_dev(dev);
- int ret;
-
-+ sema_init(&vc4->async_modeset, 1);
-+
- ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
- if (ret < 0) {
- dev_err(dev->dev, "failed to initialize vblank\n");
-@@ -51,6 +195,8 @@ int vc4_kms_load(struct drm_device *dev)
- dev->mode_config.max_height = 2048;
- dev->mode_config.funcs = &vc4_mode_funcs;
- dev->mode_config.preferred_depth = 24;
-+ dev->mode_config.async_page_flip = true;
-+
- dev->vblank_disable_allowed = true;
-
- drm_mode_config_reset(dev);
---- /dev/null
-+++ b/drivers/gpu/drm/vc4/vc4_packet.h
-@@ -0,0 +1,384 @@
-+/*
-+ * Copyright © 2014 Broadcom
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
-+ */
-+
-+#ifndef VC4_PACKET_H
-+#define VC4_PACKET_H
-+
-+#include "vc4_regs.h" /* for VC4_MASK, VC4_GET_FIELD, VC4_SET_FIELD */
-+
-+enum vc4_packet {
-+ VC4_PACKET_HALT = 0,
-+ VC4_PACKET_NOP = 1,
-+
-+ VC4_PACKET_FLUSH = 4,
-+ VC4_PACKET_FLUSH_ALL = 5,
-+ VC4_PACKET_START_TILE_BINNING = 6,
-+ VC4_PACKET_INCREMENT_SEMAPHORE = 7,
-+ VC4_PACKET_WAIT_ON_SEMAPHORE = 8,
-+
-+ VC4_PACKET_BRANCH = 16,
-+ VC4_PACKET_BRANCH_TO_SUB_LIST = 17,
-+
-+ VC4_PACKET_STORE_MS_TILE_BUFFER = 24,
-+ VC4_PACKET_STORE_MS_TILE_BUFFER_AND_EOF = 25,
-+ VC4_PACKET_STORE_FULL_RES_TILE_BUFFER = 26,
-+ VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER = 27,
-+ VC4_PACKET_STORE_TILE_BUFFER_GENERAL = 28,
-+ VC4_PACKET_LOAD_TILE_BUFFER_GENERAL = 29,
-+
-+ VC4_PACKET_GL_INDEXED_PRIMITIVE = 32,
-+ VC4_PACKET_GL_ARRAY_PRIMITIVE = 33,
-+
-+ VC4_PACKET_COMPRESSED_PRIMITIVE = 48,
-+ VC4_PACKET_CLIPPED_COMPRESSED_PRIMITIVE = 49,
-+
-+ VC4_PACKET_PRIMITIVE_LIST_FORMAT = 56,
-+
-+ VC4_PACKET_GL_SHADER_STATE = 64,
-+ VC4_PACKET_NV_SHADER_STATE = 65,
-+ VC4_PACKET_VG_SHADER_STATE = 66,
-+
-+ VC4_PACKET_CONFIGURATION_BITS = 96,
-+ VC4_PACKET_FLAT_SHADE_FLAGS = 97,
-+ VC4_PACKET_POINT_SIZE = 98,
-+ VC4_PACKET_LINE_WIDTH = 99,
-+ VC4_PACKET_RHT_X_BOUNDARY = 100,
-+ VC4_PACKET_DEPTH_OFFSET = 101,
-+ VC4_PACKET_CLIP_WINDOW = 102,
-+ VC4_PACKET_VIEWPORT_OFFSET = 103,
-+ VC4_PACKET_Z_CLIPPING = 104,
-+ VC4_PACKET_CLIPPER_XY_SCALING = 105,
-+ VC4_PACKET_CLIPPER_Z_SCALING = 106,
-+
-+ VC4_PACKET_TILE_BINNING_MODE_CONFIG = 112,
-+ VC4_PACKET_TILE_RENDERING_MODE_CONFIG = 113,
-+ VC4_PACKET_CLEAR_COLORS = 114,
-+ VC4_PACKET_TILE_COORDINATES = 115,
-+
-+ /* Not an actual hardware packet -- this is what we use to put
-+ * references to GEM bos in the command stream, since we need the u32
-+ * int the actual address packet in order to store the offset from the
-+ * start of the BO.
-+ */
-+ VC4_PACKET_GEM_HANDLES = 254,
-+} __attribute__ ((__packed__));
-+
-+#define VC4_PACKET_HALT_SIZE 1
-+#define VC4_PACKET_NOP_SIZE 1
-+#define VC4_PACKET_FLUSH_SIZE 1
-+#define VC4_PACKET_FLUSH_ALL_SIZE 1
-+#define VC4_PACKET_START_TILE_BINNING_SIZE 1
-+#define VC4_PACKET_INCREMENT_SEMAPHORE_SIZE 1
-+#define VC4_PACKET_WAIT_ON_SEMAPHORE_SIZE 1
-+#define VC4_PACKET_BRANCH_SIZE 5
-+#define VC4_PACKET_BRANCH_TO_SUB_LIST_SIZE 5
-+#define VC4_PACKET_STORE_MS_TILE_BUFFER_SIZE 1
-+#define VC4_PACKET_STORE_MS_TILE_BUFFER_AND_EOF_SIZE 1
-+#define VC4_PACKET_STORE_FULL_RES_TILE_BUFFER_SIZE 5
-+#define VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER_SIZE 5
-+#define VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE 7
-+#define VC4_PACKET_LOAD_TILE_BUFFER_GENERAL_SIZE 7
-+#define VC4_PACKET_GL_INDEXED_PRIMITIVE_SIZE 14
-+#define VC4_PACKET_GL_ARRAY_PRIMITIVE_SIZE 10
-+#define VC4_PACKET_COMPRESSED_PRIMITIVE_SIZE 1
-+#define VC4_PACKET_CLIPPED_COMPRESSED_PRIMITIVE_SIZE 1
-+#define VC4_PACKET_PRIMITIVE_LIST_FORMAT_SIZE 2
-+#define VC4_PACKET_GL_SHADER_STATE_SIZE 5
-+#define VC4_PACKET_NV_SHADER_STATE_SIZE 5
-+#define VC4_PACKET_VG_SHADER_STATE_SIZE 5
-+#define VC4_PACKET_CONFIGURATION_BITS_SIZE 4
-+#define VC4_PACKET_FLAT_SHADE_FLAGS_SIZE 5
-+#define VC4_PACKET_POINT_SIZE_SIZE 5
-+#define VC4_PACKET_LINE_WIDTH_SIZE 5
-+#define VC4_PACKET_RHT_X_BOUNDARY_SIZE 3
-+#define VC4_PACKET_DEPTH_OFFSET_SIZE 5
-+#define VC4_PACKET_CLIP_WINDOW_SIZE 9
-+#define VC4_PACKET_VIEWPORT_OFFSET_SIZE 5
-+#define VC4_PACKET_Z_CLIPPING_SIZE 9
-+#define VC4_PACKET_CLIPPER_XY_SCALING_SIZE 9
-+#define VC4_PACKET_CLIPPER_Z_SCALING_SIZE 9
-+#define VC4_PACKET_TILE_BINNING_MODE_CONFIG_SIZE 16
-+#define VC4_PACKET_TILE_RENDERING_MODE_CONFIG_SIZE 11
-+#define VC4_PACKET_CLEAR_COLORS_SIZE 14
-+#define VC4_PACKET_TILE_COORDINATES_SIZE 3
-+#define VC4_PACKET_GEM_HANDLES_SIZE 9
-+
-+/** @{
-+ * Bits used by packets like VC4_PACKET_STORE_TILE_BUFFER_GENERAL and
-+ * VC4_PACKET_TILE_RENDERING_MODE_CONFIG.
-+*/
-+#define VC4_TILING_FORMAT_LINEAR 0
-+#define VC4_TILING_FORMAT_T 1
-+#define VC4_TILING_FORMAT_LT 2
-+/** @} */
-+
-+/** @{
-+ *
-+ * low bits of VC4_PACKET_STORE_FULL_RES_TILE_BUFFER and
-+ * VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER.
-+ */
-+#define VC4_LOADSTORE_FULL_RES_EOF (1 << 3)
-+#define VC4_LOADSTORE_FULL_RES_DISABLE_CLEAR_ALL (1 << 2)
-+#define VC4_LOADSTORE_FULL_RES_DISABLE_ZS (1 << 1)
-+#define VC4_LOADSTORE_FULL_RES_DISABLE_COLOR (1 << 0)
-+
-+/** @{
-+ *
-+ * byte 2 of VC4_PACKET_STORE_TILE_BUFFER_GENERAL and
-+ * VC4_PACKET_LOAD_TILE_BUFFER_GENERAL (low bits of the address)
-+ */
-+
-+#define VC4_LOADSTORE_TILE_BUFFER_EOF (1 << 3)
-+#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_VG_MASK (1 << 2)
-+#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_ZS (1 << 1)
-+#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_COLOR (1 << 0)
-+
-+/** @} */
-+
-+/** @{
-+ *
-+ * byte 0-1 of VC4_PACKET_STORE_TILE_BUFFER_GENERAL and
-+ * VC4_PACKET_LOAD_TILE_BUFFER_GENERAL
-+ */
-+#define VC4_STORE_TILE_BUFFER_DISABLE_VG_MASK_CLEAR (1 << 15)
-+#define VC4_STORE_TILE_BUFFER_DISABLE_ZS_CLEAR (1 << 14)
-+#define VC4_STORE_TILE_BUFFER_DISABLE_COLOR_CLEAR (1 << 13)
-+#define VC4_STORE_TILE_BUFFER_DISABLE_SWAP (1 << 12)
-+
-+#define VC4_LOADSTORE_TILE_BUFFER_FORMAT_MASK VC4_MASK(9, 8)
-+#define VC4_LOADSTORE_TILE_BUFFER_FORMAT_SHIFT 8
-+#define VC4_LOADSTORE_TILE_BUFFER_RGBA8888 0
-+#define VC4_LOADSTORE_TILE_BUFFER_BGR565_DITHER 1
-+#define VC4_LOADSTORE_TILE_BUFFER_BGR565 2
-+/** @} */
-+
-+/** @{
-+ *
-+ * byte 0 of VC4_PACKET_STORE_TILE_BUFFER_GENERAL and
-+ * VC4_PACKET_LOAD_TILE_BUFFER_GENERAL
-+ */
-+#define VC4_STORE_TILE_BUFFER_MODE_MASK VC4_MASK(7, 6)
-+#define VC4_STORE_TILE_BUFFER_MODE_SHIFT 6
-+#define VC4_STORE_TILE_BUFFER_MODE_SAMPLE0 (0 << 6)
-+#define VC4_STORE_TILE_BUFFER_MODE_DECIMATE_X4 (1 << 6)
-+#define VC4_STORE_TILE_BUFFER_MODE_DECIMATE_X16 (2 << 6)
-+
-+/** The values of the field are VC4_TILING_FORMAT_* */
-+#define VC4_LOADSTORE_TILE_BUFFER_TILING_MASK VC4_MASK(5, 4)
-+#define VC4_LOADSTORE_TILE_BUFFER_TILING_SHIFT 4
-+
-+#define VC4_LOADSTORE_TILE_BUFFER_BUFFER_MASK VC4_MASK(2, 0)
-+#define VC4_LOADSTORE_TILE_BUFFER_BUFFER_SHIFT 0
-+#define VC4_LOADSTORE_TILE_BUFFER_NONE 0
-+#define VC4_LOADSTORE_TILE_BUFFER_COLOR 1
-+#define VC4_LOADSTORE_TILE_BUFFER_ZS 2
-+#define VC4_LOADSTORE_TILE_BUFFER_Z 3
-+#define VC4_LOADSTORE_TILE_BUFFER_VG_MASK 4
-+#define VC4_LOADSTORE_TILE_BUFFER_FULL 5
-+/** @} */
-+
-+#define VC4_INDEX_BUFFER_U8 (0 << 4)
-+#define VC4_INDEX_BUFFER_U16 (1 << 4)
-+
-+/* This flag is only present in NV shader state. */
-+#define VC4_SHADER_FLAG_SHADED_CLIP_COORDS (1 << 3)
-+#define VC4_SHADER_FLAG_ENABLE_CLIPPING (1 << 2)
-+#define VC4_SHADER_FLAG_VS_POINT_SIZE (1 << 1)
-+#define VC4_SHADER_FLAG_FS_SINGLE_THREAD (1 << 0)
-+
-+/** @{ byte 2 of config bits. */
-+#define VC4_CONFIG_BITS_EARLY_Z_UPDATE (1 << 1)
-+#define VC4_CONFIG_BITS_EARLY_Z (1 << 0)
-+/** @} */
-+
-+/** @{ byte 1 of config bits. */
-+#define VC4_CONFIG_BITS_Z_UPDATE (1 << 7)
-+/** same values in this 3-bit field as PIPE_FUNC_* */
-+#define VC4_CONFIG_BITS_DEPTH_FUNC_SHIFT 4
-+#define VC4_CONFIG_BITS_COVERAGE_READ_LEAVE (1 << 3)
-+
-+#define VC4_CONFIG_BITS_COVERAGE_UPDATE_NONZERO (0 << 1)
-+#define VC4_CONFIG_BITS_COVERAGE_UPDATE_ODD (1 << 1)
-+#define VC4_CONFIG_BITS_COVERAGE_UPDATE_OR (2 << 1)
-+#define VC4_CONFIG_BITS_COVERAGE_UPDATE_ZERO (3 << 1)
-+
-+#define VC4_CONFIG_BITS_COVERAGE_PIPE_SELECT (1 << 0)
-+/** @} */
-+
-+/** @{ byte 0 of config bits. */
-+#define VC4_CONFIG_BITS_RASTERIZER_OVERSAMPLE_NONE (0 << 6)
-+#define VC4_CONFIG_BITS_RASTERIZER_OVERSAMPLE_4X (1 << 6)
-+#define VC4_CONFIG_BITS_RASTERIZER_OVERSAMPLE_16X (2 << 6)
-+
-+#define VC4_CONFIG_BITS_AA_POINTS_AND_LINES (1 << 4)
-+#define VC4_CONFIG_BITS_ENABLE_DEPTH_OFFSET (1 << 3)
-+#define VC4_CONFIG_BITS_CW_PRIMITIVES (1 << 2)
-+#define VC4_CONFIG_BITS_ENABLE_PRIM_BACK (1 << 1)
-+#define VC4_CONFIG_BITS_ENABLE_PRIM_FRONT (1 << 0)
-+/** @} */
-+
-+/** @{ bits in the last u8 of VC4_PACKET_TILE_BINNING_MODE_CONFIG */
-+#define VC4_BIN_CONFIG_DB_NON_MS (1 << 7)
-+
-+#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_MASK VC4_MASK(6, 5)
-+#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_SHIFT 5
-+#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_32 0
-+#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_64 1
-+#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_128 2
-+#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_256 3
-+
-+#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_MASK VC4_MASK(4, 3)
-+#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_SHIFT 3
-+#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_32 0
-+#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_64 1
-+#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_128 2
-+#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_256 3
-+
-+#define VC4_BIN_CONFIG_AUTO_INIT_TSDA (1 << 2)
-+#define VC4_BIN_CONFIG_TILE_BUFFER_64BIT (1 << 1)
-+#define VC4_BIN_CONFIG_MS_MODE_4X (1 << 0)
-+/** @} */
-+
-+/** @{ bits in the last u16 of VC4_PACKET_TILE_RENDERING_MODE_CONFIG */
-+#define VC4_RENDER_CONFIG_DB_NON_MS (1 << 12)
-+#define VC4_RENDER_CONFIG_EARLY_Z_COVERAGE_DISABLE (1 << 11)
-+#define VC4_RENDER_CONFIG_EARLY_Z_DIRECTION_G (1 << 10)
-+#define VC4_RENDER_CONFIG_COVERAGE_MODE (1 << 9)
-+#define VC4_RENDER_CONFIG_ENABLE_VG_MASK (1 << 8)
-+
-+/** The values of the field are VC4_TILING_FORMAT_* */
-+#define VC4_RENDER_CONFIG_MEMORY_FORMAT_MASK VC4_MASK(7, 6)
-+#define VC4_RENDER_CONFIG_MEMORY_FORMAT_SHIFT 6
-+
-+#define VC4_RENDER_CONFIG_DECIMATE_MODE_1X (0 << 4)
-+#define VC4_RENDER_CONFIG_DECIMATE_MODE_4X (1 << 4)
-+#define VC4_RENDER_CONFIG_DECIMATE_MODE_16X (2 << 4)
-+
-+#define VC4_RENDER_CONFIG_FORMAT_MASK VC4_MASK(3, 2)
-+#define VC4_RENDER_CONFIG_FORMAT_SHIFT 2
-+#define VC4_RENDER_CONFIG_FORMAT_BGR565_DITHERED 0
-+#define VC4_RENDER_CONFIG_FORMAT_RGBA8888 1
-+#define VC4_RENDER_CONFIG_FORMAT_BGR565 2
-+
-+#define VC4_RENDER_CONFIG_TILE_BUFFER_64BIT (1 << 1)
-+#define VC4_RENDER_CONFIG_MS_MODE_4X (1 << 0)
-+
-+#define VC4_PRIMITIVE_LIST_FORMAT_16_INDEX (1 << 4)
-+#define VC4_PRIMITIVE_LIST_FORMAT_32_XY (3 << 4)
-+#define VC4_PRIMITIVE_LIST_FORMAT_TYPE_POINTS (0 << 0)
-+#define VC4_PRIMITIVE_LIST_FORMAT_TYPE_LINES (1 << 0)
-+#define VC4_PRIMITIVE_LIST_FORMAT_TYPE_TRIANGLES (2 << 0)
-+#define VC4_PRIMITIVE_LIST_FORMAT_TYPE_RHT (3 << 0)
-+
-+enum vc4_texture_data_type {
-+ VC4_TEXTURE_TYPE_RGBA8888 = 0,
-+ VC4_TEXTURE_TYPE_RGBX8888 = 1,
-+ VC4_TEXTURE_TYPE_RGBA4444 = 2,
-+ VC4_TEXTURE_TYPE_RGBA5551 = 3,
-+ VC4_TEXTURE_TYPE_RGB565 = 4,
-+ VC4_TEXTURE_TYPE_LUMINANCE = 5,
-+ VC4_TEXTURE_TYPE_ALPHA = 6,
-+ VC4_TEXTURE_TYPE_LUMALPHA = 7,
-+ VC4_TEXTURE_TYPE_ETC1 = 8,
-+ VC4_TEXTURE_TYPE_S16F = 9,
-+ VC4_TEXTURE_TYPE_S8 = 10,
-+ VC4_TEXTURE_TYPE_S16 = 11,
-+ VC4_TEXTURE_TYPE_BW1 = 12,
-+ VC4_TEXTURE_TYPE_A4 = 13,
-+ VC4_TEXTURE_TYPE_A1 = 14,
-+ VC4_TEXTURE_TYPE_RGBA64 = 15,
-+ VC4_TEXTURE_TYPE_RGBA32R = 16,
-+ VC4_TEXTURE_TYPE_YUV422R = 17,
-+};
-+
-+#define VC4_TEX_P0_OFFSET_MASK VC4_MASK(31, 12)
-+#define VC4_TEX_P0_OFFSET_SHIFT 12
-+#define VC4_TEX_P0_CSWIZ_MASK VC4_MASK(11, 10)
-+#define VC4_TEX_P0_CSWIZ_SHIFT 10
-+#define VC4_TEX_P0_CMMODE_MASK VC4_MASK(9, 9)
-+#define VC4_TEX_P0_CMMODE_SHIFT 9
-+#define VC4_TEX_P0_FLIPY_MASK VC4_MASK(8, 8)
-+#define VC4_TEX_P0_FLIPY_SHIFT 8
-+#define VC4_TEX_P0_TYPE_MASK VC4_MASK(7, 4)
-+#define VC4_TEX_P0_TYPE_SHIFT 4
-+#define VC4_TEX_P0_MIPLVLS_MASK VC4_MASK(3, 0)
-+#define VC4_TEX_P0_MIPLVLS_SHIFT 0
-+
-+#define VC4_TEX_P1_TYPE4_MASK VC4_MASK(31, 31)
-+#define VC4_TEX_P1_TYPE4_SHIFT 31
-+#define VC4_TEX_P1_HEIGHT_MASK VC4_MASK(30, 20)
-+#define VC4_TEX_P1_HEIGHT_SHIFT 20
-+#define VC4_TEX_P1_ETCFLIP_MASK VC4_MASK(19, 19)
-+#define VC4_TEX_P1_ETCFLIP_SHIFT 19
-+#define VC4_TEX_P1_WIDTH_MASK VC4_MASK(18, 8)
-+#define VC4_TEX_P1_WIDTH_SHIFT 8
-+
-+#define VC4_TEX_P1_MAGFILT_MASK VC4_MASK(7, 7)
-+#define VC4_TEX_P1_MAGFILT_SHIFT 7
-+# define VC4_TEX_P1_MAGFILT_LINEAR 0
-+# define VC4_TEX_P1_MAGFILT_NEAREST 1
-+
-+#define VC4_TEX_P1_MINFILT_MASK VC4_MASK(6, 4)
-+#define VC4_TEX_P1_MINFILT_SHIFT 4
-+# define VC4_TEX_P1_MINFILT_LINEAR 0
-+# define VC4_TEX_P1_MINFILT_NEAREST 1
-+# define VC4_TEX_P1_MINFILT_NEAR_MIP_NEAR 2
-+# define VC4_TEX_P1_MINFILT_NEAR_MIP_LIN 3
-+# define VC4_TEX_P1_MINFILT_LIN_MIP_NEAR 4
-+# define VC4_TEX_P1_MINFILT_LIN_MIP_LIN 5
-+
-+#define VC4_TEX_P1_WRAP_T_MASK VC4_MASK(3, 2)
-+#define VC4_TEX_P1_WRAP_T_SHIFT 2
-+#define VC4_TEX_P1_WRAP_S_MASK VC4_MASK(1, 0)
-+#define VC4_TEX_P1_WRAP_S_SHIFT 0
-+# define VC4_TEX_P1_WRAP_REPEAT 0
-+# define VC4_TEX_P1_WRAP_CLAMP 1
-+# define VC4_TEX_P1_WRAP_MIRROR 2
-+# define VC4_TEX_P1_WRAP_BORDER 3
-+
-+#define VC4_TEX_P2_PTYPE_MASK VC4_MASK(31, 30)
-+#define VC4_TEX_P2_PTYPE_SHIFT 30
-+# define VC4_TEX_P2_PTYPE_IGNORED 0
-+# define VC4_TEX_P2_PTYPE_CUBE_MAP_STRIDE 1
-+# define VC4_TEX_P2_PTYPE_CHILD_IMAGE_DIMENSIONS 2
-+# define VC4_TEX_P2_PTYPE_CHILD_IMAGE_OFFSETS 3
-+
-+/* VC4_TEX_P2_PTYPE_CUBE_MAP_STRIDE bits */
-+#define VC4_TEX_P2_CMST_MASK VC4_MASK(29, 12)
-+#define VC4_TEX_P2_CMST_SHIFT 12
-+#define VC4_TEX_P2_BSLOD_MASK VC4_MASK(0, 0)
-+#define VC4_TEX_P2_BSLOD_SHIFT 0
-+
-+/* VC4_TEX_P2_PTYPE_CHILD_IMAGE_DIMENSIONS */
-+#define VC4_TEX_P2_CHEIGHT_MASK VC4_MASK(22, 12)
-+#define VC4_TEX_P2_CHEIGHT_SHIFT 12
-+#define VC4_TEX_P2_CWIDTH_MASK VC4_MASK(10, 0)
-+#define VC4_TEX_P2_CWIDTH_SHIFT 0
-+
-+/* VC4_TEX_P2_PTYPE_CHILD_IMAGE_OFFSETS */
-+#define VC4_TEX_P2_CYOFF_MASK VC4_MASK(22, 12)
-+#define VC4_TEX_P2_CYOFF_SHIFT 12
-+#define VC4_TEX_P2_CXOFF_MASK VC4_MASK(10, 0)
-+#define VC4_TEX_P2_CXOFF_SHIFT 0
-+
-+#endif /* VC4_PACKET_H */
---- a/drivers/gpu/drm/vc4/vc4_plane.c
-+++ b/drivers/gpu/drm/vc4/vc4_plane.c
-@@ -29,6 +29,14 @@ struct vc4_plane_state {
- u32 *dlist;
- u32 dlist_size; /* Number of dwords in allocated for the display list */
- u32 dlist_count; /* Number of used dwords in the display list. */
-+
-+ /* Offset in the dlist to pointer word 0. */
-+ u32 pw0_offset;
-+
-+ /* Offset where the plane's dlist was last stored in the
-+ hardware at vc4_crtc_atomic_flush() time.
-+ */
-+ u32 *hw_dlist;
- };
-
- static inline struct vc4_plane_state *
-@@ -207,6 +215,8 @@ static int vc4_plane_mode_set(struct drm
- /* Position Word 3: Context. Written by the HVS. */
- vc4_dlist_write(vc4_state, 0xc0c0c0c0);
-
-+ vc4_state->pw0_offset = vc4_state->dlist_count;
-+
- /* Pointer Word 0: RGB / Y Pointer */
- vc4_dlist_write(vc4_state, bo->paddr + offset);
-
-@@ -258,6 +268,8 @@ u32 vc4_plane_write_dlist(struct drm_pla
- struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state);
- int i;
-
-+ vc4_state->hw_dlist = dlist;
-+
- /* Can't memcpy_toio() because it needs to be 32-bit writes. */
- for (i = 0; i < vc4_state->dlist_count; i++)
- writel(vc4_state->dlist[i], &dlist[i]);
-@@ -272,6 +284,34 @@ u32 vc4_plane_dlist_size(struct drm_plan
- return vc4_state->dlist_count;
- }
-
-+/* Updates the plane to immediately (well, once the FIFO needs
-+ * refilling) scan out from at a new framebuffer.
-+ */
-+void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb)
-+{
-+ struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state);
-+ struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
-+ uint32_t addr;
-+
-+ /* We're skipping the address adjustment for negative origin,
-+ * because this is only called on the primary plane.
-+ */
-+ WARN_ON_ONCE(plane->state->crtc_x < 0 || plane->state->crtc_y < 0);
-+ addr = bo->paddr + fb->offsets[0];
-+
-+ /* Write the new address into the hardware immediately. The
-+ * scanout will start from this address as soon as the FIFO
-+ * needs to refill with pixels.
-+ */
-+ writel(addr, &vc4_state->hw_dlist[vc4_state->pw0_offset]);
-+
-+ /* Also update the CPU-side dlist copy, so that any later
-+ * atomic updates that don't do a new modeset on our plane
-+ * also use our updated address.
-+ */
-+ vc4_state->dlist[vc4_state->pw0_offset] = addr;
-+}
-+
- static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
- .prepare_fb = NULL,
- .cleanup_fb = NULL,
---- /dev/null
-+++ b/drivers/gpu/drm/vc4/vc4_qpu_defines.h
-@@ -0,0 +1,268 @@
-+/*
-+ * Copyright © 2014 Broadcom
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
-+ */
-+
-+#ifndef VC4_QPU_DEFINES_H
-+#define VC4_QPU_DEFINES_H
-+
-+enum qpu_op_add {
-+ QPU_A_NOP,
-+ QPU_A_FADD,
-+ QPU_A_FSUB,
-+ QPU_A_FMIN,
-+ QPU_A_FMAX,
-+ QPU_A_FMINABS,
-+ QPU_A_FMAXABS,
-+ QPU_A_FTOI,
-+ QPU_A_ITOF,
-+ QPU_A_ADD = 12,
-+ QPU_A_SUB,
-+ QPU_A_SHR,
-+ QPU_A_ASR,
-+ QPU_A_ROR,
-+ QPU_A_SHL,
-+ QPU_A_MIN,
-+ QPU_A_MAX,
-+ QPU_A_AND,
-+ QPU_A_OR,
-+ QPU_A_XOR,
-+ QPU_A_NOT,
-+ QPU_A_CLZ,
-+ QPU_A_V8ADDS = 30,
-+ QPU_A_V8SUBS = 31,
-+};
-+
-+enum qpu_op_mul {
-+ QPU_M_NOP,
-+ QPU_M_FMUL,
-+ QPU_M_MUL24,
-+ QPU_M_V8MULD,
-+ QPU_M_V8MIN,
-+ QPU_M_V8MAX,
-+ QPU_M_V8ADDS,
-+ QPU_M_V8SUBS,
-+};
-+
-+enum qpu_raddr {
-+ QPU_R_FRAG_PAYLOAD_ZW = 15, /* W for A file, Z for B file */
-+ /* 0-31 are the plain regfile a or b fields */
-+ QPU_R_UNIF = 32,
-+ QPU_R_VARY = 35,
-+ QPU_R_ELEM_QPU = 38,
-+ QPU_R_NOP,
-+ QPU_R_XY_PIXEL_COORD = 41,
-+ QPU_R_MS_REV_FLAGS = 41,
-+ QPU_R_VPM = 48,
-+ QPU_R_VPM_LD_BUSY,
-+ QPU_R_VPM_LD_WAIT,
-+ QPU_R_MUTEX_ACQUIRE,
-+};
-+
-+enum qpu_waddr {
-+ /* 0-31 are the plain regfile a or b fields */
-+ QPU_W_ACC0 = 32, /* aka r0 */
-+ QPU_W_ACC1,
-+ QPU_W_ACC2,
-+ QPU_W_ACC3,
-+ QPU_W_TMU_NOSWAP,
-+ QPU_W_ACC5,
-+ QPU_W_HOST_INT,
-+ QPU_W_NOP,
-+ QPU_W_UNIFORMS_ADDRESS,
-+ QPU_W_QUAD_XY, /* X for regfile a, Y for regfile b */
-+ QPU_W_MS_FLAGS = 42,
-+ QPU_W_REV_FLAG = 42,
-+ QPU_W_TLB_STENCIL_SETUP = 43,
-+ QPU_W_TLB_Z,
-+ QPU_W_TLB_COLOR_MS,
-+ QPU_W_TLB_COLOR_ALL,
-+ QPU_W_TLB_ALPHA_MASK,
-+ QPU_W_VPM,
-+ QPU_W_VPMVCD_SETUP, /* LD for regfile a, ST for regfile b */
-+ QPU_W_VPM_ADDR, /* LD for regfile a, ST for regfile b */
-+ QPU_W_MUTEX_RELEASE,
-+ QPU_W_SFU_RECIP,
-+ QPU_W_SFU_RECIPSQRT,
-+ QPU_W_SFU_EXP,
-+ QPU_W_SFU_LOG,
-+ QPU_W_TMU0_S,
-+ QPU_W_TMU0_T,
-+ QPU_W_TMU0_R,
-+ QPU_W_TMU0_B,
-+ QPU_W_TMU1_S,
-+ QPU_W_TMU1_T,
-+ QPU_W_TMU1_R,
-+ QPU_W_TMU1_B,
-+};
-+
-+enum qpu_sig_bits {
-+ QPU_SIG_SW_BREAKPOINT,
-+ QPU_SIG_NONE,
-+ QPU_SIG_THREAD_SWITCH,
-+ QPU_SIG_PROG_END,
-+ QPU_SIG_WAIT_FOR_SCOREBOARD,
-+ QPU_SIG_SCOREBOARD_UNLOCK,
-+ QPU_SIG_LAST_THREAD_SWITCH,
-+ QPU_SIG_COVERAGE_LOAD,
-+ QPU_SIG_COLOR_LOAD,
-+ QPU_SIG_COLOR_LOAD_END,
-+ QPU_SIG_LOAD_TMU0,
-+ QPU_SIG_LOAD_TMU1,
-+ QPU_SIG_ALPHA_MASK_LOAD,
-+ QPU_SIG_SMALL_IMM,
-+ QPU_SIG_LOAD_IMM,
-+ QPU_SIG_BRANCH
-+};
-+
-+enum qpu_mux {
-+ /* hardware mux values */
-+ QPU_MUX_R0,
-+ QPU_MUX_R1,
-+ QPU_MUX_R2,
-+ QPU_MUX_R3,
-+ QPU_MUX_R4,
-+ QPU_MUX_R5,
-+ QPU_MUX_A,
-+ QPU_MUX_B,
-+
-+ /* non-hardware mux values */
-+ QPU_MUX_IMM,
-+};
-+
-+enum qpu_cond {
-+ QPU_COND_NEVER,
-+ QPU_COND_ALWAYS,
-+ QPU_COND_ZS,
-+ QPU_COND_ZC,
-+ QPU_COND_NS,
-+ QPU_COND_NC,
-+ QPU_COND_CS,
-+ QPU_COND_CC,
-+};
-+
-+enum qpu_pack_mul {
-+ QPU_PACK_MUL_NOP,
-+ QPU_PACK_MUL_8888 = 3, /* replicated to each 8 bits of the 32-bit dst. */
-+ QPU_PACK_MUL_8A,
-+ QPU_PACK_MUL_8B,
-+ QPU_PACK_MUL_8C,
-+ QPU_PACK_MUL_8D,
-+};
-+
-+enum qpu_pack_a {
-+ QPU_PACK_A_NOP,
-+ /* convert to 16 bit float if float input, or to int16. */
-+ QPU_PACK_A_16A,
-+ QPU_PACK_A_16B,
-+ /* replicated to each 8 bits of the 32-bit dst. */
-+ QPU_PACK_A_8888,
-+ /* Convert to 8-bit unsigned int. */
-+ QPU_PACK_A_8A,
-+ QPU_PACK_A_8B,
-+ QPU_PACK_A_8C,
-+ QPU_PACK_A_8D,
-+
-+ /* Saturating variants of the previous instructions. */
-+ QPU_PACK_A_32_SAT, /* int-only */
-+ QPU_PACK_A_16A_SAT, /* int or float */
-+ QPU_PACK_A_16B_SAT,
-+ QPU_PACK_A_8888_SAT,
-+ QPU_PACK_A_8A_SAT,
-+ QPU_PACK_A_8B_SAT,
-+ QPU_PACK_A_8C_SAT,
-+ QPU_PACK_A_8D_SAT,
-+};
-+
-+enum qpu_unpack_r4 {
-+ QPU_UNPACK_R4_NOP,
-+ QPU_UNPACK_R4_F16A_TO_F32,
-+ QPU_UNPACK_R4_F16B_TO_F32,
-+ QPU_UNPACK_R4_8D_REP,
-+ QPU_UNPACK_R4_8A,
-+ QPU_UNPACK_R4_8B,
-+ QPU_UNPACK_R4_8C,
-+ QPU_UNPACK_R4_8D,
-+};
-+
-+#define QPU_MASK(high, low) ((((uint64_t)1<<((high)-(low)+1))-1)<<(low))
-+/* Using the GNU statement expression extension */
-+#define QPU_SET_FIELD(value, field) \
-+ ({ \
-+ uint64_t fieldval = (uint64_t)(value) << field ## _SHIFT; \
-+ assert((fieldval & ~ field ## _MASK) == 0); \
-+ fieldval & field ## _MASK; \
-+ })
-+
-+#define QPU_GET_FIELD(word, field) ((uint32_t)(((word) & field ## _MASK) >> field ## _SHIFT))
-+
-+#define QPU_SIG_SHIFT 60
-+#define QPU_SIG_MASK QPU_MASK(63, 60)
-+
-+#define QPU_UNPACK_SHIFT 57
-+#define QPU_UNPACK_MASK QPU_MASK(59, 57)
-+
-+/**
-+ * If set, the pack field means PACK_MUL or R4 packing, instead of normal
-+ * regfile a packing.
-+ */
-+#define QPU_PM ((uint64_t)1 << 56)
-+
-+#define QPU_PACK_SHIFT 52
-+#define QPU_PACK_MASK QPU_MASK(55, 52)
-+
-+#define QPU_COND_ADD_SHIFT 49
-+#define QPU_COND_ADD_MASK QPU_MASK(51, 49)
-+#define QPU_COND_MUL_SHIFT 46
-+#define QPU_COND_MUL_MASK QPU_MASK(48, 46)
-+
-+#define QPU_SF ((uint64_t)1 << 45)
-+
-+#define QPU_WADDR_ADD_SHIFT 38
-+#define QPU_WADDR_ADD_MASK QPU_MASK(43, 38)
-+#define QPU_WADDR_MUL_SHIFT 32
-+#define QPU_WADDR_MUL_MASK QPU_MASK(37, 32)
-+
-+#define QPU_OP_MUL_SHIFT 29
-+#define QPU_OP_MUL_MASK QPU_MASK(31, 29)
-+
-+#define QPU_RADDR_A_SHIFT 18
-+#define QPU_RADDR_A_MASK QPU_MASK(23, 18)
-+#define QPU_RADDR_B_SHIFT 12
-+#define QPU_RADDR_B_MASK QPU_MASK(17, 12)
-+#define QPU_SMALL_IMM_SHIFT 12
-+#define QPU_SMALL_IMM_MASK QPU_MASK(17, 12)
-+
-+#define QPU_ADD_A_SHIFT 9
-+#define QPU_ADD_A_MASK QPU_MASK(11, 9)
-+#define QPU_ADD_B_SHIFT 6
-+#define QPU_ADD_B_MASK QPU_MASK(8, 6)
-+#define QPU_MUL_A_SHIFT 3
-+#define QPU_MUL_A_MASK QPU_MASK(5, 3)
-+#define QPU_MUL_B_SHIFT 0
-+#define QPU_MUL_B_MASK QPU_MASK(2, 0)
-+
-+#define QPU_WS ((uint64_t)1 << 44)
-+
-+#define QPU_OP_ADD_SHIFT 24
-+#define QPU_OP_ADD_MASK QPU_MASK(28, 24)
-+
-+#endif /* VC4_QPU_DEFINES_H */
---- /dev/null
-+++ b/drivers/gpu/drm/vc4/vc4_render_cl.c
-@@ -0,0 +1,448 @@
-+/*
-+ * Copyright © 2014-2015 Broadcom
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
-+ */
-+
-+/**
-+ * DOC: Render command list generation
-+ *
-+ * In the VC4 driver, render command list generation is performed by the
-+ * kernel instead of userspace. We do this because validating a
-+ * user-submitted command list is hard to get right and has high CPU overhead,
-+ * while the number of valid configurations for render command lists is
-+ * actually fairly low.
-+ */
-+
-+#include "uapi/drm/vc4_drm.h"
-+#include "vc4_drv.h"
-+#include "vc4_packet.h"
-+
-+struct vc4_rcl_setup {
-+ struct drm_gem_cma_object *color_read;
-+ struct drm_gem_cma_object *color_ms_write;
-+ struct drm_gem_cma_object *zs_read;
-+ struct drm_gem_cma_object *zs_write;
-+
-+ struct drm_gem_cma_object *rcl;
-+ u32 next_offset;
-+};
-+
-+static inline void rcl_u8(struct vc4_rcl_setup *setup, u8 val)
-+{
-+ *(u8 *)(setup->rcl->vaddr + setup->next_offset) = val;
-+ setup->next_offset += 1;
-+}
-+
-+static inline void rcl_u16(struct vc4_rcl_setup *setup, u16 val)
-+{
-+ *(u16 *)(setup->rcl->vaddr + setup->next_offset) = val;
-+ setup->next_offset += 2;
-+}
-+
-+static inline void rcl_u32(struct vc4_rcl_setup *setup, u32 val)
-+{
-+ *(u32 *)(setup->rcl->vaddr + setup->next_offset) = val;
-+ setup->next_offset += 4;
-+}
-+
-+
-+/*
-+ * Emits a no-op STORE_TILE_BUFFER_GENERAL.
-+ *
-+ * If we emit a PACKET_TILE_COORDINATES, it must be followed by a store of
-+ * some sort before another load is triggered.
-+ */
-+static void vc4_store_before_load(struct vc4_rcl_setup *setup)
-+{
-+ rcl_u8(setup, VC4_PACKET_STORE_TILE_BUFFER_GENERAL);
-+ rcl_u16(setup,
-+ VC4_SET_FIELD(VC4_LOADSTORE_TILE_BUFFER_NONE,
-+ VC4_LOADSTORE_TILE_BUFFER_BUFFER) |
-+ VC4_STORE_TILE_BUFFER_DISABLE_COLOR_CLEAR |
-+ VC4_STORE_TILE_BUFFER_DISABLE_ZS_CLEAR |
-+ VC4_STORE_TILE_BUFFER_DISABLE_VG_MASK_CLEAR);
-+ rcl_u32(setup, 0); /* no address, since we're in None mode */
-+}
-+
-+/*
-+ * Emits a PACKET_TILE_COORDINATES if one isn't already pending.
-+ *
-+ * The tile coordinates packet triggers a pending load if there is one, are
-+ * used for clipping during rendering, and determine where loads/stores happen
-+ * relative to their base address.
-+ */
-+static void vc4_tile_coordinates(struct vc4_rcl_setup *setup,
-+ uint32_t x, uint32_t y)
-+{
-+ rcl_u8(setup, VC4_PACKET_TILE_COORDINATES);
-+ rcl_u8(setup, x);
-+ rcl_u8(setup, y);
-+}
-+
-+static void emit_tile(struct vc4_exec_info *exec,
-+ struct vc4_rcl_setup *setup,
-+ uint8_t x, uint8_t y, bool first, bool last)
-+{
-+ struct drm_vc4_submit_cl *args = exec->args;
-+ bool has_bin = args->bin_cl_size != 0;
-+
-+ /* Note that the load doesn't actually occur until the
-+ * tile coords packet is processed, and only one load
-+ * may be outstanding at a time.
-+ */
-+ if (setup->color_read) {
-+ rcl_u8(setup, VC4_PACKET_LOAD_TILE_BUFFER_GENERAL);
-+ rcl_u16(setup, args->color_read.bits);
-+ rcl_u32(setup,
-+ setup->color_read->paddr + args->color_read.offset);
-+ }
-+
-+ if (setup->zs_read) {
-+ if (setup->color_read) {
-+ /* Exec previous load. */
-+ vc4_tile_coordinates(setup, x, y);
-+ vc4_store_before_load(setup);
-+ }
-+
-+ rcl_u8(setup, VC4_PACKET_LOAD_TILE_BUFFER_GENERAL);
-+ rcl_u16(setup, args->zs_read.bits);
-+ rcl_u32(setup, setup->zs_read->paddr + args->zs_read.offset);
-+ }
-+
-+ /* Clipping depends on tile coordinates having been
-+ * emitted, so we always need one here.
-+ */
-+ vc4_tile_coordinates(setup, x, y);
-+
-+ /* Wait for the binner before jumping to the first
-+ * tile's lists.
-+ */
-+ if (first && has_bin)
-+ rcl_u8(setup, VC4_PACKET_WAIT_ON_SEMAPHORE);
-+
-+ if (has_bin) {
-+ rcl_u8(setup, VC4_PACKET_BRANCH_TO_SUB_LIST);
-+ rcl_u32(setup, (exec->tile_bo->paddr +
-+ exec->tile_alloc_offset +
-+ (y * exec->bin_tiles_x + x) * 32));
-+ }
-+
-+ if (setup->zs_write) {
-+ rcl_u8(setup, VC4_PACKET_STORE_TILE_BUFFER_GENERAL);
-+ rcl_u16(setup, args->zs_write.bits |
-+ (setup->color_ms_write ?
-+ VC4_STORE_TILE_BUFFER_DISABLE_COLOR_CLEAR : 0));
-+ rcl_u32(setup,
-+ (setup->zs_write->paddr + args->zs_write.offset) |
-+ ((last && !setup->color_ms_write) ?
-+ VC4_LOADSTORE_TILE_BUFFER_EOF : 0));
-+ }
-+
-+ if (setup->color_ms_write) {
-+ if (setup->zs_write) {
-+ /* Reset after previous store */
-+ vc4_tile_coordinates(setup, x, y);
-+ }
-+
-+ if (last)
-+ rcl_u8(setup, VC4_PACKET_STORE_MS_TILE_BUFFER_AND_EOF);
-+ else
-+ rcl_u8(setup, VC4_PACKET_STORE_MS_TILE_BUFFER);
-+ }
-+}
-+
-+static int vc4_create_rcl_bo(struct drm_device *dev, struct vc4_exec_info *exec,
-+ struct vc4_rcl_setup *setup)
-+{
-+ struct drm_vc4_submit_cl *args = exec->args;
-+ bool has_bin = args->bin_cl_size != 0;
-+ uint8_t min_x_tile = args->min_x_tile;
-+ uint8_t min_y_tile = args->min_y_tile;
-+ uint8_t max_x_tile = args->max_x_tile;
-+ uint8_t max_y_tile = args->max_y_tile;
-+ uint8_t xtiles = max_x_tile - min_x_tile + 1;
-+ uint8_t ytiles = max_y_tile - min_y_tile + 1;
-+ uint8_t x, y;
-+ uint32_t size, loop_body_size;
-+
-+ size = VC4_PACKET_TILE_RENDERING_MODE_CONFIG_SIZE;
-+ loop_body_size = VC4_PACKET_TILE_COORDINATES_SIZE;
-+
-+ if (args->flags & VC4_SUBMIT_CL_USE_CLEAR_COLOR) {
-+ size += VC4_PACKET_CLEAR_COLORS_SIZE +
-+ VC4_PACKET_TILE_COORDINATES_SIZE +
-+ VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE;
-+ }
-+
-+ if (setup->color_read) {
-+ loop_body_size += (VC4_PACKET_LOAD_TILE_BUFFER_GENERAL_SIZE);
-+ }
-+ if (setup->zs_read) {
-+ if (setup->color_read) {
-+ loop_body_size += VC4_PACKET_TILE_COORDINATES_SIZE;
-+ loop_body_size += VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE;
-+ }
-+ loop_body_size += VC4_PACKET_LOAD_TILE_BUFFER_GENERAL_SIZE;
-+ }
-+
-+ if (has_bin) {
-+ size += VC4_PACKET_WAIT_ON_SEMAPHORE_SIZE;
-+ loop_body_size += VC4_PACKET_BRANCH_TO_SUB_LIST_SIZE;
-+ }
-+
-+ if (setup->zs_write)
-+ loop_body_size += VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE;
-+ if (setup->color_ms_write) {
-+ if (setup->zs_write)
-+ loop_body_size += VC4_PACKET_TILE_COORDINATES_SIZE;
-+ loop_body_size += VC4_PACKET_STORE_MS_TILE_BUFFER_SIZE;
-+ }
-+ size += xtiles * ytiles * loop_body_size;
-+
-+ setup->rcl = &vc4_bo_create(dev, size)->base;
-+ if (!setup->rcl)
-+ return -ENOMEM;
-+ list_add_tail(&to_vc4_bo(&setup->rcl->base)->unref_head,
-+ &exec->unref_list);
-+
-+ rcl_u8(setup, VC4_PACKET_TILE_RENDERING_MODE_CONFIG);
-+ rcl_u32(setup,
-+ (setup->color_ms_write ?
-+ (setup->color_ms_write->paddr +
-+ args->color_ms_write.offset) :
-+ 0));
-+ rcl_u16(setup, args->width);
-+ rcl_u16(setup, args->height);
-+ rcl_u16(setup, args->color_ms_write.bits);
-+
-+ /* The tile buffer gets cleared when the previous tile is stored. If
-+ * the clear values changed between frames, then the tile buffer has
-+ * stale clear values in it, so we have to do a store in None mode (no
-+ * writes) so that we trigger the tile buffer clear.
-+ */
-+ if (args->flags & VC4_SUBMIT_CL_USE_CLEAR_COLOR) {
-+ rcl_u8(setup, VC4_PACKET_CLEAR_COLORS);
-+ rcl_u32(setup, args->clear_color[0]);
-+ rcl_u32(setup, args->clear_color[1]);
-+ rcl_u32(setup, args->clear_z);
-+ rcl_u8(setup, args->clear_s);
-+
-+ vc4_tile_coordinates(setup, 0, 0);
-+
-+ rcl_u8(setup, VC4_PACKET_STORE_TILE_BUFFER_GENERAL);
-+ rcl_u16(setup, VC4_LOADSTORE_TILE_BUFFER_NONE);
-+ rcl_u32(setup, 0); /* no address, since we're in None mode */
-+ }
-+
-+ for (y = min_y_tile; y <= max_y_tile; y++) {
-+ for (x = min_x_tile; x <= max_x_tile; x++) {
-+ bool first = (x == min_x_tile && y == min_y_tile);
-+ bool last = (x == max_x_tile && y == max_y_tile);
-+ emit_tile(exec, setup, x, y, first, last);
-+ }
-+ }
-+
-+ BUG_ON(setup->next_offset != size);
-+ exec->ct1ca = setup->rcl->paddr;
-+ exec->ct1ea = setup->rcl->paddr + setup->next_offset;
-+
-+ return 0;
-+}
-+
-+static int vc4_rcl_surface_setup(struct vc4_exec_info *exec,
-+ struct drm_gem_cma_object **obj,
-+ struct drm_vc4_submit_rcl_surface *surf)
-+{
-+ uint8_t tiling = VC4_GET_FIELD(surf->bits,
-+ VC4_LOADSTORE_TILE_BUFFER_TILING);
-+ uint8_t buffer = VC4_GET_FIELD(surf->bits,
-+ VC4_LOADSTORE_TILE_BUFFER_BUFFER);
-+ uint8_t format = VC4_GET_FIELD(surf->bits,
-+ VC4_LOADSTORE_TILE_BUFFER_FORMAT);
-+ int cpp;
-+
-+ if (surf->pad != 0) {
-+ DRM_ERROR("Padding unset\n");
-+ return -EINVAL;
-+ }
-+
-+ if (surf->hindex == ~0)
-+ return 0;
-+
-+ if (!vc4_use_bo(exec, surf->hindex, VC4_MODE_RENDER, obj))
-+ return -EINVAL;
-+
-+ if (surf->bits & ~(VC4_LOADSTORE_TILE_BUFFER_TILING_MASK |
-+ VC4_LOADSTORE_TILE_BUFFER_BUFFER_MASK |
-+ VC4_LOADSTORE_TILE_BUFFER_FORMAT_MASK)) {
-+ DRM_ERROR("Unknown bits in load/store: 0x%04x\n",
-+ surf->bits);
-+ return -EINVAL;
-+ }
-+
-+ if (tiling > VC4_TILING_FORMAT_LT) {
-+ DRM_ERROR("Bad tiling format\n");
-+ return -EINVAL;
-+ }
-+
-+ if (buffer == VC4_LOADSTORE_TILE_BUFFER_ZS) {
-+ if (format != 0) {
-+ DRM_ERROR("No color format should be set for ZS\n");
-+ return -EINVAL;
-+ }
-+ cpp = 4;
-+ } else if (buffer == VC4_LOADSTORE_TILE_BUFFER_COLOR) {
-+ switch (format) {
-+ case VC4_LOADSTORE_TILE_BUFFER_BGR565:
-+ case VC4_LOADSTORE_TILE_BUFFER_BGR565_DITHER:
-+ cpp = 2;
-+ break;
-+ case VC4_LOADSTORE_TILE_BUFFER_RGBA8888:
-+ cpp = 4;
-+ break;
-+ default:
-+ DRM_ERROR("Bad tile buffer format\n");
-+ return -EINVAL;
-+ }
-+ } else {
-+ DRM_ERROR("Bad load/store buffer %d.\n", buffer);
-+ return -EINVAL;
-+ }
-+
-+ if (surf->offset & 0xf) {
-+ DRM_ERROR("load/store buffer must be 16b aligned.\n");
-+ return -EINVAL;
-+ }
-+
-+ if (!vc4_check_tex_size(exec, *obj, surf->offset, tiling,
-+ exec->args->width, exec->args->height, cpp)) {
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+static int
-+vc4_rcl_ms_surface_setup(struct vc4_exec_info *exec,
-+ struct drm_gem_cma_object **obj,
-+ struct drm_vc4_submit_rcl_surface *surf)
-+{
-+ uint8_t tiling = VC4_GET_FIELD(surf->bits,
-+ VC4_RENDER_CONFIG_MEMORY_FORMAT);
-+ uint8_t format = VC4_GET_FIELD(surf->bits,
-+ VC4_RENDER_CONFIG_FORMAT);
-+ int cpp;
-+
-+ if (surf->pad != 0) {
-+ DRM_ERROR("Padding unset\n");
-+ return -EINVAL;
-+ }
-+
-+ if (surf->bits & ~(VC4_RENDER_CONFIG_MEMORY_FORMAT_MASK |
-+ VC4_RENDER_CONFIG_FORMAT_MASK)) {
-+ DRM_ERROR("Unknown bits in render config: 0x%04x\n",
-+ surf->bits);
-+ return -EINVAL;
-+ }
-+
-+ if (surf->hindex == ~0)
-+ return 0;
-+
-+ if (!vc4_use_bo(exec, surf->hindex, VC4_MODE_RENDER, obj))
-+ return -EINVAL;
-+
-+ if (tiling > VC4_TILING_FORMAT_LT) {
-+ DRM_ERROR("Bad tiling format\n");
-+ return -EINVAL;
-+ }
-+
-+ switch (format) {
-+ case VC4_RENDER_CONFIG_FORMAT_BGR565_DITHERED:
-+ case VC4_RENDER_CONFIG_FORMAT_BGR565:
-+ cpp = 2;
-+ break;
-+ case VC4_RENDER_CONFIG_FORMAT_RGBA8888:
-+ cpp = 4;
-+ break;
-+ default:
-+ DRM_ERROR("Bad tile buffer format\n");
-+ return -EINVAL;
-+ }
-+
-+ if (!vc4_check_tex_size(exec, *obj, surf->offset, tiling,
-+ exec->args->width, exec->args->height, cpp)) {
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+int vc4_get_rcl(struct drm_device *dev, struct vc4_exec_info *exec)
-+{
-+ struct vc4_rcl_setup setup = {0};
-+ struct drm_vc4_submit_cl *args = exec->args;
-+ bool has_bin = args->bin_cl_size != 0;
-+ int ret;
-+
-+ if (args->min_x_tile > args->max_x_tile ||
-+ args->min_y_tile > args->max_y_tile) {
-+ DRM_ERROR("Bad render tile set (%d,%d)-(%d,%d)\n",
-+ args->min_x_tile, args->min_y_tile,
-+ args->max_x_tile, args->max_y_tile);
-+ return -EINVAL;
-+ }
-+
-+ if (has_bin &&
-+ (args->max_x_tile > exec->bin_tiles_x ||
-+ args->max_y_tile > exec->bin_tiles_y)) {
-+ DRM_ERROR("Render tiles (%d,%d) outside of bin config (%d,%d)\n",
-+ args->max_x_tile, args->max_y_tile,
-+ exec->bin_tiles_x, exec->bin_tiles_y);
-+ return -EINVAL;
-+ }
-+
-+ ret = vc4_rcl_surface_setup(exec, &setup.color_read, &args->color_read);
-+ if (ret)
-+ return ret;
-+
-+ ret = vc4_rcl_ms_surface_setup(exec, &setup.color_ms_write,
-+ &args->color_ms_write);
-+ if (ret)
-+ return ret;
-+
-+ ret = vc4_rcl_surface_setup(exec, &setup.zs_read, &args->zs_read);
-+ if (ret)
-+ return ret;
-+
-+ ret = vc4_rcl_surface_setup(exec, &setup.zs_write, &args->zs_write);
-+ if (ret)
-+ return ret;
-+
-+ /* We shouldn't even have the job submitted to us if there's no
-+ * surface to write out.
-+ */
-+ if (!setup.color_ms_write && !setup.zs_write) {
-+ DRM_ERROR("RCL requires color or Z/S write\n");
-+ return -EINVAL;
-+ }
-+
-+ return vc4_create_rcl_bo(dev, exec, &setup);
-+}
---- /dev/null
-+++ b/drivers/gpu/drm/vc4/vc4_trace.h
-@@ -0,0 +1,63 @@
-+/*
-+ * Copyright (C) 2015 Broadcom
-+ *
-+ * 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.
-+ */
-+
-+#if !defined(_VC4_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
-+#define _VC4_TRACE_H_
-+
-+#include <linux/stringify.h>
-+#include <linux/types.h>
-+#include <linux/tracepoint.h>
-+
-+#undef TRACE_SYSTEM
-+#define TRACE_SYSTEM vc4
-+#define TRACE_INCLUDE_FILE vc4_trace
-+
-+TRACE_EVENT(vc4_wait_for_seqno_begin,
-+ TP_PROTO(struct drm_device *dev, uint64_t seqno, uint64_t timeout),
-+ TP_ARGS(dev, seqno, timeout),
-+
-+ TP_STRUCT__entry(
-+ __field(u32, dev)
-+ __field(u64, seqno)
-+ __field(u64, timeout)
-+ ),
-+
-+ TP_fast_assign(
-+ __entry->dev = dev->primary->index;
-+ __entry->seqno = seqno;
-+ __entry->timeout = timeout;
-+ ),
-+
-+ TP_printk("dev=%u, seqno=%llu, timeout=%llu",
-+ __entry->dev, __entry->seqno, __entry->timeout)
-+);
-+
-+TRACE_EVENT(vc4_wait_for_seqno_end,
-+ TP_PROTO(struct drm_device *dev, uint64_t seqno),
-+ TP_ARGS(dev, seqno),
-+
-+ TP_STRUCT__entry(
-+ __field(u32, dev)
-+ __field(u64, seqno)
-+ ),
-+
-+ TP_fast_assign(
-+ __entry->dev = dev->primary->index;
-+ __entry->seqno = seqno;
-+ ),
-+
-+ TP_printk("dev=%u, seqno=%llu",
-+ __entry->dev, __entry->seqno)
-+);
-+
-+#endif /* _VC4_TRACE_H_ */
-+
-+/* This part must be outside protection */
-+#undef TRACE_INCLUDE_PATH
-+#define TRACE_INCLUDE_PATH .
-+#include <trace/define_trace.h>
---- /dev/null
-+++ b/drivers/gpu/drm/vc4/vc4_trace_points.c
-@@ -0,0 +1,14 @@
-+/*
-+ * Copyright (C) 2015 Broadcom
-+ *
-+ * 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 "vc4_drv.h"
-+
-+#ifndef __CHECKER__
-+#define CREATE_TRACE_POINTS
-+#include "vc4_trace.h"
-+#endif
---- /dev/null
-+++ b/drivers/gpu/drm/vc4/vc4_v3d.c
-@@ -0,0 +1,268 @@
-+/*
-+ * Copyright (c) 2014 The Linux Foundation. All rights reserved.
-+ * Copyright (C) 2013 Red Hat
-+ * Author: Rob Clark <robdclark@gmail.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License version 2 as published by
-+ * the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but WITHOUT
-+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
-+ * more details.
-+ *
-+ * You should have received a copy of the GNU General Public License along with
-+ * this program. If not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#include "linux/component.h"
-+#include "soc/bcm2835/raspberrypi-firmware.h"
-+#include "vc4_drv.h"
-+#include "vc4_regs.h"
-+
-+#ifdef CONFIG_DEBUG_FS
-+#define REGDEF(reg) { reg, #reg }
-+static const struct {
-+ uint32_t reg;
-+ const char *name;
-+} vc4_reg_defs[] = {
-+ REGDEF(V3D_IDENT0),
-+ REGDEF(V3D_IDENT1),
-+ REGDEF(V3D_IDENT2),
-+ REGDEF(V3D_SCRATCH),
-+ REGDEF(V3D_L2CACTL),
-+ REGDEF(V3D_SLCACTL),
-+ REGDEF(V3D_INTCTL),
-+ REGDEF(V3D_INTENA),
-+ REGDEF(V3D_INTDIS),
-+ REGDEF(V3D_CT0CS),
-+ REGDEF(V3D_CT1CS),
-+ REGDEF(V3D_CT0EA),
-+ REGDEF(V3D_CT1EA),
-+ REGDEF(V3D_CT0CA),
-+ REGDEF(V3D_CT1CA),
-+ REGDEF(V3D_CT00RA0),
-+ REGDEF(V3D_CT01RA0),
-+ REGDEF(V3D_CT0LC),
-+ REGDEF(V3D_CT1LC),
-+ REGDEF(V3D_CT0PC),
-+ REGDEF(V3D_CT1PC),
-+ REGDEF(V3D_PCS),
-+ REGDEF(V3D_BFC),
-+ REGDEF(V3D_RFC),
-+ REGDEF(V3D_BPCA),
-+ REGDEF(V3D_BPCS),
-+ REGDEF(V3D_BPOA),
-+ REGDEF(V3D_BPOS),
-+ REGDEF(V3D_BXCF),
-+ REGDEF(V3D_SQRSV0),
-+ REGDEF(V3D_SQRSV1),
-+ REGDEF(V3D_SQCNTL),
-+ REGDEF(V3D_SRQPC),
-+ REGDEF(V3D_SRQUA),
-+ REGDEF(V3D_SRQUL),
-+ REGDEF(V3D_SRQCS),
-+ REGDEF(V3D_VPACNTL),
-+ REGDEF(V3D_VPMBASE),
-+ REGDEF(V3D_PCTRC),
-+ REGDEF(V3D_PCTRE),
-+ REGDEF(V3D_PCTR0),
-+ REGDEF(V3D_PCTRS0),
-+ REGDEF(V3D_PCTR1),
-+ REGDEF(V3D_PCTRS1),
-+ REGDEF(V3D_PCTR2),
-+ REGDEF(V3D_PCTRS2),
-+ REGDEF(V3D_PCTR3),
-+ REGDEF(V3D_PCTRS3),
-+ REGDEF(V3D_PCTR4),
-+ REGDEF(V3D_PCTRS4),
-+ REGDEF(V3D_PCTR5),
-+ REGDEF(V3D_PCTRS5),
-+ REGDEF(V3D_PCTR6),
-+ REGDEF(V3D_PCTRS6),
-+ REGDEF(V3D_PCTR7),
-+ REGDEF(V3D_PCTRS7),
-+ REGDEF(V3D_PCTR8),
-+ REGDEF(V3D_PCTRS8),
-+ REGDEF(V3D_PCTR9),
-+ REGDEF(V3D_PCTRS9),
-+ REGDEF(V3D_PCTR10),
-+ REGDEF(V3D_PCTRS10),
-+ REGDEF(V3D_PCTR11),
-+ REGDEF(V3D_PCTRS11),
-+ REGDEF(V3D_PCTR12),
-+ REGDEF(V3D_PCTRS12),
-+ REGDEF(V3D_PCTR13),
-+ REGDEF(V3D_PCTRS13),
-+ REGDEF(V3D_PCTR14),
-+ REGDEF(V3D_PCTRS14),
-+ REGDEF(V3D_PCTR15),
-+ REGDEF(V3D_PCTRS15),
-+ REGDEF(V3D_BGE),
-+ REGDEF(V3D_FDBGO),
-+ REGDEF(V3D_FDBGB),
-+ REGDEF(V3D_FDBGR),
-+ REGDEF(V3D_FDBGS),
-+ REGDEF(V3D_ERRSTAT),
-+};
-+
-+int vc4_v3d_debugfs_regs(struct seq_file *m, void *unused)
-+{
-+ struct drm_info_node *node = (struct drm_info_node *) m->private;
-+ struct drm_device *dev = node->minor->dev;
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+ int i;
-+
-+ for (i = 0; i < ARRAY_SIZE(vc4_reg_defs); i++) {
-+ seq_printf(m, "%s (0x%04x): 0x%08x\n",
-+ vc4_reg_defs[i].name, vc4_reg_defs[i].reg,
-+ V3D_READ(vc4_reg_defs[i].reg));
-+ }
-+
-+ return 0;
-+}
-+
-+int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused)
-+{
-+ struct drm_info_node *node = (struct drm_info_node *) m->private;
-+ struct drm_device *dev = node->minor->dev;
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+ uint32_t ident1 = V3D_READ(V3D_IDENT1);
-+ uint32_t nslc = VC4_GET_FIELD(ident1, V3D_IDENT1_NSLC);
-+ uint32_t tups = VC4_GET_FIELD(ident1, V3D_IDENT1_TUPS);
-+ uint32_t qups = VC4_GET_FIELD(ident1, V3D_IDENT1_QUPS);
-+
-+ seq_printf(m, "Revision: %d\n", VC4_GET_FIELD(ident1, V3D_IDENT1_REV));
-+ seq_printf(m, "Slices: %d\n", nslc);
-+ seq_printf(m, "TMUs: %d\n", nslc * tups);
-+ seq_printf(m, "QPUs: %d\n", nslc * qups);
-+ seq_printf(m, "Semaphores: %d\n", VC4_GET_FIELD(ident1, V3D_IDENT1_NSEM));
-+
-+ return 0;
-+}
-+#endif /* CONFIG_DEBUG_FS */
-+
-+/*
-+ * Asks the firmware to turn on power to the V3D engine.
-+ *
-+ * This may be doable with just the clocks interface, though this
-+ * packet does some other register setup from the firmware, too.
-+ */
-+int
-+vc4_v3d_set_power(struct vc4_dev *vc4, bool on)
-+{
-+ u32 packet = on;
-+
-+ return rpi_firmware_property(vc4->firmware,
-+ RPI_FIRMWARE_SET_ENABLE_QPU,
-+ &packet, sizeof(packet));
-+}
-+
-+static void vc4_v3d_init_hw(struct drm_device *dev)
-+{
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+
-+ /* Take all the memory that would have been reserved for user
-+ * QPU programs, since we don't have an interface for running
-+ * them, anyway.
-+ */
-+ V3D_WRITE(V3D_VPMBASE, 0);
-+}
-+
-+static int vc4_v3d_bind(struct device *dev, struct device *master, void *data)
-+{
-+ struct platform_device *pdev = to_platform_device(dev);
-+ struct drm_device *drm = dev_get_drvdata(master);
-+ struct vc4_dev *vc4 = to_vc4_dev(drm);
-+ struct vc4_v3d *v3d = NULL;
-+ int ret;
-+
-+ v3d = devm_kzalloc(&pdev->dev, sizeof(*v3d), GFP_KERNEL);
-+ if (!v3d)
-+ return -ENOMEM;
-+
-+ v3d->pdev = pdev;
-+
-+ v3d->regs = vc4_ioremap_regs(pdev, 0);
-+ if (IS_ERR(v3d->regs))
-+ return PTR_ERR(v3d->regs);
-+
-+ vc4->v3d = v3d;
-+
-+ ret = vc4_v3d_set_power(vc4, true);
-+ if (ret)
-+ return ret;
-+
-+ if (V3D_READ(V3D_IDENT0) != V3D_EXPECTED_IDENT0) {
-+ DRM_ERROR("V3D_IDENT0 read 0x%08x instead of 0x%08x\n",
-+ V3D_READ(V3D_IDENT0), V3D_EXPECTED_IDENT0);
-+ return -EINVAL;
-+ }
-+
-+ /* Reset the binner overflow address/size at setup, to be sure
-+ * we don't reuse an old one.
-+ */
-+ V3D_WRITE(V3D_BPOA, 0);
-+ V3D_WRITE(V3D_BPOS, 0);
-+
-+ vc4_v3d_init_hw(drm);
-+
-+ ret = drm_irq_install(drm, platform_get_irq(pdev, 0));
-+ if (ret) {
-+ DRM_ERROR("Failed to install IRQ handler\n");
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static void vc4_v3d_unbind(struct device *dev, struct device *master,
-+ void *data)
-+{
-+ struct drm_device *drm = dev_get_drvdata(master);
-+ struct vc4_dev *vc4 = to_vc4_dev(drm);
-+
-+ drm_irq_uninstall(drm);
-+
-+ /* Disable the binner's overflow memory address, so the next
-+ * driver probe (if any) doesn't try to reuse our old
-+ * allocation.
-+ */
-+ V3D_WRITE(V3D_BPOA, 0);
-+ V3D_WRITE(V3D_BPOS, 0);
-+
-+ vc4_v3d_set_power(vc4, false);
-+
-+ vc4->v3d = NULL;
-+}
-+
-+static const struct component_ops vc4_v3d_ops = {
-+ .bind = vc4_v3d_bind,
-+ .unbind = vc4_v3d_unbind,
-+};
-+
-+static int vc4_v3d_dev_probe(struct platform_device *pdev)
-+{
-+ return component_add(&pdev->dev, &vc4_v3d_ops);
-+}
-+
-+static int vc4_v3d_dev_remove(struct platform_device *pdev)
-+{
-+ component_del(&pdev->dev, &vc4_v3d_ops);
-+ return 0;
-+}
-+
-+static const struct of_device_id vc4_v3d_dt_match[] = {
-+ { .compatible = "brcm,vc4-v3d" },
-+ {}
-+};
-+
-+struct platform_driver vc4_v3d_driver = {
-+ .probe = vc4_v3d_dev_probe,
-+ .remove = vc4_v3d_dev_remove,
-+ .driver = {
-+ .name = "vc4_v3d",
-+ .of_match_table = vc4_v3d_dt_match,
-+ },
-+};
---- /dev/null
-+++ b/drivers/gpu/drm/vc4/vc4_validate.c
-@@ -0,0 +1,958 @@
-+/*
-+ * Copyright © 2014 Broadcom
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
-+ */
-+
-+/**
-+ * Command list validator for VC4.
-+ *
-+ * The VC4 has no IOMMU between it and system memory. So, a user with
-+ * access to execute command lists could escalate privilege by
-+ * overwriting system memory (drawing to it as a framebuffer) or
-+ * reading system memory it shouldn't (reading it as a texture, or
-+ * uniform data, or vertex data).
-+ *
-+ * This validates command lists to ensure that all accesses are within
-+ * the bounds of the GEM objects referenced. It explicitly whitelists
-+ * packets, and looks at the offsets in any address fields to make
-+ * sure they're constrained within the BOs they reference.
-+ *
-+ * Note that because of the validation that's happening anyway, this
-+ * is where GEM relocation processing happens.
-+ */
-+
-+#include "uapi/drm/vc4_drm.h"
-+#include "vc4_drv.h"
-+#include "vc4_packet.h"
-+
-+#define VALIDATE_ARGS \
-+ struct vc4_exec_info *exec, \
-+ void *validated, \
-+ void *untrusted
-+
-+
-+/** Return the width in pixels of a 64-byte microtile. */
-+static uint32_t
-+utile_width(int cpp)
-+{
-+ switch (cpp) {
-+ case 1:
-+ case 2:
-+ return 8;
-+ case 4:
-+ return 4;
-+ case 8:
-+ return 2;
-+ default:
-+ DRM_ERROR("unknown cpp: %d\n", cpp);
-+ return 1;
-+ }
-+}
-+
-+/** Return the height in pixels of a 64-byte microtile. */
-+static uint32_t
-+utile_height(int cpp)
-+{
-+ switch (cpp) {
-+ case 1:
-+ return 8;
-+ case 2:
-+ case 4:
-+ case 8:
-+ return 4;
-+ default:
-+ DRM_ERROR("unknown cpp: %d\n", cpp);
-+ return 1;
-+ }
-+}
-+
-+/**
-+ * The texture unit decides what tiling format a particular miplevel is using
-+ * this function, so we lay out our miptrees accordingly.
-+ */
-+static bool
-+size_is_lt(uint32_t width, uint32_t height, int cpp)
-+{
-+ return (width <= 4 * utile_width(cpp) ||
-+ height <= 4 * utile_height(cpp));
-+}
-+
-+bool
-+vc4_use_bo(struct vc4_exec_info *exec,
-+ uint32_t hindex,
-+ enum vc4_bo_mode mode,
-+ struct drm_gem_cma_object **obj)
-+{
-+ *obj = NULL;
-+
-+ if (hindex >= exec->bo_count) {
-+ DRM_ERROR("BO index %d greater than BO count %d\n",
-+ hindex, exec->bo_count);
-+ return false;
-+ }
-+
-+ if (exec->bo[hindex].mode != mode) {
-+ if (exec->bo[hindex].mode == VC4_MODE_UNDECIDED) {
-+ exec->bo[hindex].mode = mode;
-+ } else {
-+ DRM_ERROR("BO index %d reused with mode %d vs %d\n",
-+ hindex, exec->bo[hindex].mode, mode);
-+ return false;
-+ }
-+ }
-+
-+ *obj = exec->bo[hindex].bo;
-+ return true;
-+}
-+
-+static bool
-+vc4_use_handle(struct vc4_exec_info *exec,
-+ uint32_t gem_handles_packet_index,
-+ enum vc4_bo_mode mode,
-+ struct drm_gem_cma_object **obj)
-+{
-+ return vc4_use_bo(exec, exec->bo_index[gem_handles_packet_index],
-+ mode, obj);
-+}
-+
-+static uint32_t
-+gl_shader_rec_size(uint32_t pointer_bits)
-+{
-+ uint32_t attribute_count = pointer_bits & 7;
-+ bool extended = pointer_bits & 8;
-+
-+ if (attribute_count == 0)
-+ attribute_count = 8;
-+
-+ if (extended)
-+ return 100 + attribute_count * 4;
-+ else
-+ return 36 + attribute_count * 8;
-+}
-+
-+bool
-+vc4_check_tex_size(struct vc4_exec_info *exec, struct drm_gem_cma_object *fbo,
-+ uint32_t offset, uint8_t tiling_format,
-+ uint32_t width, uint32_t height, uint8_t cpp)
-+{
-+ uint32_t aligned_width, aligned_height, stride, size;
-+ uint32_t utile_w = utile_width(cpp);
-+ uint32_t utile_h = utile_height(cpp);
-+
-+ /* The shaded vertex format stores signed 12.4 fixed point
-+ * (-2048,2047) offsets from the viewport center, so we should
-+ * never have a render target larger than 4096. The texture
-+ * unit can only sample from 2048x2048, so it's even more
-+ * restricted. This lets us avoid worrying about overflow in
-+ * our math.
-+ */
-+ if (width > 4096 || height > 4096) {
-+ DRM_ERROR("Surface dimesions (%d,%d) too large", width, height);
-+ return false;
-+ }
-+
-+ switch (tiling_format) {
-+ case VC4_TILING_FORMAT_LINEAR:
-+ aligned_width = round_up(width, utile_w);
-+ aligned_height = height;
-+ break;
-+ case VC4_TILING_FORMAT_T:
-+ aligned_width = round_up(width, utile_w * 8);
-+ aligned_height = round_up(height, utile_h * 8);
-+ break;
-+ case VC4_TILING_FORMAT_LT:
-+ aligned_width = round_up(width, utile_w);
-+ aligned_height = round_up(height, utile_h);
-+ break;
-+ default:
-+ DRM_ERROR("buffer tiling %d unsupported\n", tiling_format);
-+ return false;
-+ }
-+
-+ stride = aligned_width * cpp;
-+ size = stride * aligned_height;
-+
-+ if (size + offset < size ||
-+ size + offset > fbo->base.size) {
-+ DRM_ERROR("Overflow in %dx%d (%dx%d) fbo size (%d + %d > %d)\n",
-+ width, height,
-+ aligned_width, aligned_height,
-+ size, offset, fbo->base.size);
-+ return false;
-+ }
-+
-+ return true;
-+}
-+
-+static int
-+validate_flush_all(VALIDATE_ARGS)
-+{
-+ if (exec->found_increment_semaphore_packet) {
-+ DRM_ERROR("VC4_PACKET_FLUSH_ALL after "
-+ "VC4_PACKET_INCREMENT_SEMAPHORE\n");
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+static int
-+validate_start_tile_binning(VALIDATE_ARGS)
-+{
-+ if (exec->found_start_tile_binning_packet) {
-+ DRM_ERROR("Duplicate VC4_PACKET_START_TILE_BINNING\n");
-+ return -EINVAL;
-+ }
-+ exec->found_start_tile_binning_packet = true;
-+
-+ if (!exec->found_tile_binning_mode_config_packet) {
-+ DRM_ERROR("missing VC4_PACKET_TILE_BINNING_MODE_CONFIG\n");
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+static int
-+validate_increment_semaphore(VALIDATE_ARGS)
-+{
-+ if (exec->found_increment_semaphore_packet) {
-+ DRM_ERROR("Duplicate VC4_PACKET_INCREMENT_SEMAPHORE\n");
-+ return -EINVAL;
-+ }
-+ exec->found_increment_semaphore_packet = true;
-+
-+ /* Once we've found the semaphore increment, there should be one FLUSH
-+ * then the end of the command list. The FLUSH actually triggers the
-+ * increment, so we only need to make sure there
-+ */
-+
-+ return 0;
-+}
-+
-+static int
-+validate_indexed_prim_list(VALIDATE_ARGS)
-+{
-+ struct drm_gem_cma_object *ib;
-+ uint32_t length = *(uint32_t *)(untrusted + 1);
-+ uint32_t offset = *(uint32_t *)(untrusted + 5);
-+ uint32_t max_index = *(uint32_t *)(untrusted + 9);
-+ uint32_t index_size = (*(uint8_t *)(untrusted + 0) >> 4) ? 2 : 1;
-+ struct vc4_shader_state *shader_state;
-+
-+ if (exec->found_increment_semaphore_packet) {
-+ DRM_ERROR("Drawing after VC4_PACKET_INCREMENT_SEMAPHORE\n");
-+ return -EINVAL;
-+ }
-+
-+ /* Check overflow condition */
-+ if (exec->shader_state_count == 0) {
-+ DRM_ERROR("shader state must precede primitives\n");
-+ return -EINVAL;
-+ }
-+ shader_state = &exec->shader_state[exec->shader_state_count - 1];
-+
-+ if (max_index > shader_state->max_index)
-+ shader_state->max_index = max_index;
-+
-+ if (!vc4_use_handle(exec, 0, VC4_MODE_RENDER, &ib))
-+ return -EINVAL;
-+
-+ if (offset > ib->base.size ||
-+ (ib->base.size - offset) / index_size < length) {
-+ DRM_ERROR("IB access overflow (%d + %d*%d > %d)\n",
-+ offset, length, index_size, ib->base.size);
-+ return -EINVAL;
-+ }
-+
-+ *(uint32_t *)(validated + 5) = ib->paddr + offset;
-+
-+ return 0;
-+}
-+
-+static int
-+validate_gl_array_primitive(VALIDATE_ARGS)
-+{
-+ uint32_t length = *(uint32_t *)(untrusted + 1);
-+ uint32_t base_index = *(uint32_t *)(untrusted + 5);
-+ uint32_t max_index;
-+ struct vc4_shader_state *shader_state;
-+
-+ if (exec->found_increment_semaphore_packet) {
-+ DRM_ERROR("Drawing after VC4_PACKET_INCREMENT_SEMAPHORE\n");
-+ return -EINVAL;
-+ }
-+
-+ /* Check overflow condition */
-+ if (exec->shader_state_count == 0) {
-+ DRM_ERROR("shader state must precede primitives\n");
-+ return -EINVAL;
-+ }
-+ shader_state = &exec->shader_state[exec->shader_state_count - 1];
-+
-+ if (length + base_index < length) {
-+ DRM_ERROR("primitive vertex count overflow\n");
-+ return -EINVAL;
-+ }
-+ max_index = length + base_index - 1;
-+
-+ if (max_index > shader_state->max_index)
-+ shader_state->max_index = max_index;
-+
-+ return 0;
-+}
-+
-+static int
-+validate_gl_shader_state(VALIDATE_ARGS)
-+{
-+ uint32_t i = exec->shader_state_count++;
-+
-+ if (i >= exec->shader_state_size) {
-+ DRM_ERROR("More requests for shader states than declared\n");
-+ return -EINVAL;
-+ }
-+
-+ exec->shader_state[i].packet = VC4_PACKET_GL_SHADER_STATE;
-+ exec->shader_state[i].addr = *(uint32_t *)untrusted;
-+ exec->shader_state[i].max_index = 0;
-+
-+ if (exec->shader_state[i].addr & ~0xf) {
-+ DRM_ERROR("high bits set in GL shader rec reference\n");
-+ return -EINVAL;
-+ }
-+
-+ *(uint32_t *)validated = (exec->shader_rec_p +
-+ exec->shader_state[i].addr);
-+
-+ exec->shader_rec_p +=
-+ roundup(gl_shader_rec_size(exec->shader_state[i].addr), 16);
-+
-+ return 0;
-+}
-+
-+static int
-+validate_nv_shader_state(VALIDATE_ARGS)
-+{
-+ uint32_t i = exec->shader_state_count++;
-+
-+ if (i >= exec->shader_state_size) {
-+ DRM_ERROR("More requests for shader states than declared\n");
-+ return -EINVAL;
-+ }
-+
-+ exec->shader_state[i].packet = VC4_PACKET_NV_SHADER_STATE;
-+ exec->shader_state[i].addr = *(uint32_t *)untrusted;
-+
-+ if (exec->shader_state[i].addr & 15) {
-+ DRM_ERROR("NV shader state address 0x%08x misaligned\n",
-+ exec->shader_state[i].addr);
-+ return -EINVAL;
-+ }
-+
-+ *(uint32_t *)validated = (exec->shader_state[i].addr +
-+ exec->shader_rec_p);
-+
-+ return 0;
-+}
-+
-+static int
-+validate_tile_binning_config(VALIDATE_ARGS)
-+{
-+ struct drm_device *dev = exec->exec_bo->base.dev;
-+ uint8_t flags;
-+ uint32_t tile_state_size, tile_alloc_size;
-+ uint32_t tile_count;
-+
-+ if (exec->found_tile_binning_mode_config_packet) {
-+ DRM_ERROR("Duplicate VC4_PACKET_TILE_BINNING_MODE_CONFIG\n");
-+ return -EINVAL;
-+ }
-+ exec->found_tile_binning_mode_config_packet = true;
-+
-+ exec->bin_tiles_x = *(uint8_t *)(untrusted + 12);
-+ exec->bin_tiles_y = *(uint8_t *)(untrusted + 13);
-+ tile_count = exec->bin_tiles_x * exec->bin_tiles_y;
-+ flags = *(uint8_t *)(untrusted + 14);
-+
-+ if (exec->bin_tiles_x == 0 ||
-+ exec->bin_tiles_y == 0) {
-+ DRM_ERROR("Tile binning config of %dx%d too small\n",
-+ exec->bin_tiles_x, exec->bin_tiles_y);
-+ return -EINVAL;
-+ }
-+
-+ if (flags & (VC4_BIN_CONFIG_DB_NON_MS |
-+ VC4_BIN_CONFIG_TILE_BUFFER_64BIT |
-+ VC4_BIN_CONFIG_MS_MODE_4X)) {
-+ DRM_ERROR("unsupported bining config flags 0x%02x\n", flags);
-+ return -EINVAL;
-+ }
-+
-+ /* The tile state data array is 48 bytes per tile, and we put it at
-+ * the start of a BO containing both it and the tile alloc.
-+ */
-+ tile_state_size = 48 * tile_count;
-+
-+ /* Since the tile alloc array will follow us, align. */
-+ exec->tile_alloc_offset = roundup(tile_state_size, 4096);
-+
-+ *(uint8_t *)(validated + 14) =
-+ ((flags & ~(VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_MASK |
-+ VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_MASK)) |
-+ VC4_BIN_CONFIG_AUTO_INIT_TSDA |
-+ VC4_SET_FIELD(VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_32,
-+ VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE) |
-+ VC4_SET_FIELD(VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_128,
-+ VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE));
-+
-+ /* Initial block size. */
-+ tile_alloc_size = 32 * tile_count;
-+
-+ /*
-+ * The initial allocation gets rounded to the next 256 bytes before
-+ * the hardware starts fulfilling further allocations.
-+ */
-+ tile_alloc_size = roundup(tile_alloc_size, 256);
-+
-+ /* Add space for the extra allocations. This is what gets used first,
-+ * before overflow memory. It must have at least 4096 bytes, but we
-+ * want to avoid overflow memory usage if possible.
-+ */
-+ tile_alloc_size += 1024 * 1024;
-+
-+ exec->tile_bo = &vc4_bo_create(dev, exec->tile_alloc_offset +
-+ tile_alloc_size)->base;
-+ if (!exec->tile_bo)
-+ return -ENOMEM;
-+ list_add_tail(&to_vc4_bo(&exec->tile_bo->base)->unref_head,
-+ &exec->unref_list);
-+
-+ /* tile alloc address. */
-+ *(uint32_t *)(validated + 0) = (exec->tile_bo->paddr +
-+ exec->tile_alloc_offset);
-+ /* tile alloc size. */
-+ *(uint32_t *)(validated + 4) = tile_alloc_size;
-+ /* tile state address. */
-+ *(uint32_t *)(validated + 8) = exec->tile_bo->paddr;
-+
-+ return 0;
-+}
-+
-+static int
-+validate_gem_handles(VALIDATE_ARGS)
-+{
-+ memcpy(exec->bo_index, untrusted, sizeof(exec->bo_index));
-+ return 0;
-+}
-+
-+#define VC4_DEFINE_PACKET(packet, name, func) \
-+ [packet] = { packet ## _SIZE, name, func }
-+
-+static const struct cmd_info {
-+ uint16_t len;
-+ const char *name;
-+ int (*func)(struct vc4_exec_info *exec, void *validated,
-+ void *untrusted);
-+} cmd_info[] = {
-+ VC4_DEFINE_PACKET(VC4_PACKET_HALT, "halt", NULL),
-+ VC4_DEFINE_PACKET(VC4_PACKET_NOP, "nop", NULL),
-+ VC4_DEFINE_PACKET(VC4_PACKET_FLUSH, "flush", NULL),
-+ VC4_DEFINE_PACKET(VC4_PACKET_FLUSH_ALL, "flush all state", validate_flush_all),
-+ VC4_DEFINE_PACKET(VC4_PACKET_START_TILE_BINNING, "start tile binning", validate_start_tile_binning),
-+ VC4_DEFINE_PACKET(VC4_PACKET_INCREMENT_SEMAPHORE, "increment semaphore", validate_increment_semaphore),
-+
-+ VC4_DEFINE_PACKET(VC4_PACKET_GL_INDEXED_PRIMITIVE, "Indexed Primitive List", validate_indexed_prim_list),
-+
-+ VC4_DEFINE_PACKET(VC4_PACKET_GL_ARRAY_PRIMITIVE, "Vertex Array Primitives", validate_gl_array_primitive),
-+
-+ /* This is only used by clipped primitives (packets 48 and 49), which
-+ * we don't support parsing yet.
-+ */
-+ VC4_DEFINE_PACKET(VC4_PACKET_PRIMITIVE_LIST_FORMAT, "primitive list format", NULL),
-+
-+ VC4_DEFINE_PACKET(VC4_PACKET_GL_SHADER_STATE, "GL Shader State", validate_gl_shader_state),
-+ VC4_DEFINE_PACKET(VC4_PACKET_NV_SHADER_STATE, "NV Shader State", validate_nv_shader_state),
-+
-+ VC4_DEFINE_PACKET(VC4_PACKET_CONFIGURATION_BITS, "configuration bits", NULL),
-+ VC4_DEFINE_PACKET(VC4_PACKET_FLAT_SHADE_FLAGS, "flat shade flags", NULL),
-+ VC4_DEFINE_PACKET(VC4_PACKET_POINT_SIZE, "point size", NULL),
-+ VC4_DEFINE_PACKET(VC4_PACKET_LINE_WIDTH, "line width", NULL),
-+ VC4_DEFINE_PACKET(VC4_PACKET_RHT_X_BOUNDARY, "RHT X boundary", NULL),
-+ VC4_DEFINE_PACKET(VC4_PACKET_DEPTH_OFFSET, "Depth Offset", NULL),
-+ VC4_DEFINE_PACKET(VC4_PACKET_CLIP_WINDOW, "Clip Window", NULL),
-+ VC4_DEFINE_PACKET(VC4_PACKET_VIEWPORT_OFFSET, "Viewport Offset", NULL),
-+ VC4_DEFINE_PACKET(VC4_PACKET_CLIPPER_XY_SCALING, "Clipper XY Scaling", NULL),
-+ /* Note: The docs say this was also 105, but it was 106 in the
-+ * initial userland code drop.
-+ */
-+ VC4_DEFINE_PACKET(VC4_PACKET_CLIPPER_Z_SCALING, "Clipper Z Scale and Offset", NULL),
-+
-+ VC4_DEFINE_PACKET(VC4_PACKET_TILE_BINNING_MODE_CONFIG, "tile binning configuration", validate_tile_binning_config),
-+
-+ VC4_DEFINE_PACKET(VC4_PACKET_GEM_HANDLES, "GEM handles", validate_gem_handles),
-+};
-+
-+int
-+vc4_validate_bin_cl(struct drm_device *dev,
-+ void *validated,
-+ void *unvalidated,
-+ struct vc4_exec_info *exec)
-+{
-+ uint32_t len = exec->args->bin_cl_size;
-+ uint32_t dst_offset = 0;
-+ uint32_t src_offset = 0;
-+
-+ while (src_offset < len) {
-+ void *dst_pkt = validated + dst_offset;
-+ void *src_pkt = unvalidated + src_offset;
-+ u8 cmd = *(uint8_t *)src_pkt;
-+ const struct cmd_info *info;
-+
-+ if (cmd > ARRAY_SIZE(cmd_info)) {
-+ DRM_ERROR("0x%08x: packet %d out of bounds\n",
-+ src_offset, cmd);
-+ return -EINVAL;
-+ }
-+
-+ info = &cmd_info[cmd];
-+ if (!info->name) {
-+ DRM_ERROR("0x%08x: packet %d invalid\n",
-+ src_offset, cmd);
-+ return -EINVAL;
-+ }
-+
-+#if 0
-+ DRM_INFO("0x%08x: packet %d (%s) size %d processing...\n",
-+ src_offset, cmd, info->name, info->len);
-+#endif
-+
-+ if (src_offset + info->len > len) {
-+ DRM_ERROR("0x%08x: packet %d (%s) length 0x%08x "
-+ "exceeds bounds (0x%08x)\n",
-+ src_offset, cmd, info->name, info->len,
-+ src_offset + len);
-+ return -EINVAL;
-+ }
-+
-+ if (cmd != VC4_PACKET_GEM_HANDLES)
-+ memcpy(dst_pkt, src_pkt, info->len);
-+
-+ if (info->func && info->func(exec,
-+ dst_pkt + 1,
-+ src_pkt + 1)) {
-+ DRM_ERROR("0x%08x: packet %d (%s) failed to "
-+ "validate\n",
-+ src_offset, cmd, info->name);
-+ return -EINVAL;
-+ }
-+
-+ src_offset += info->len;
-+ /* GEM handle loading doesn't produce HW packets. */
-+ if (cmd != VC4_PACKET_GEM_HANDLES)
-+ dst_offset += info->len;
-+
-+ /* When the CL hits halt, it'll stop reading anything else. */
-+ if (cmd == VC4_PACKET_HALT)
-+ break;
-+ }
-+
-+ exec->ct0ea = exec->ct0ca + dst_offset;
-+
-+ if (!exec->found_start_tile_binning_packet) {
-+ DRM_ERROR("Bin CL missing VC4_PACKET_START_TILE_BINNING\n");
-+ return -EINVAL;
-+ }
-+
-+ if (!exec->found_increment_semaphore_packet) {
-+ DRM_ERROR("Bin CL missing VC4_PACKET_INCREMENT_SEMAPHORE\n");
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+static bool
-+reloc_tex(struct vc4_exec_info *exec,
-+ void *uniform_data_u,
-+ struct vc4_texture_sample_info *sample,
-+ uint32_t texture_handle_index)
-+
-+{
-+ struct drm_gem_cma_object *tex;
-+ uint32_t p0 = *(uint32_t *)(uniform_data_u + sample->p_offset[0]);
-+ uint32_t p1 = *(uint32_t *)(uniform_data_u + sample->p_offset[1]);
-+ uint32_t p2 = (sample->p_offset[2] != ~0 ?
-+ *(uint32_t *)(uniform_data_u + sample->p_offset[2]) : 0);
-+ uint32_t p3 = (sample->p_offset[3] != ~0 ?
-+ *(uint32_t *)(uniform_data_u + sample->p_offset[3]) : 0);
-+ uint32_t *validated_p0 = exec->uniforms_v + sample->p_offset[0];
-+ uint32_t offset = p0 & VC4_TEX_P0_OFFSET_MASK;
-+ uint32_t miplevels = VC4_GET_FIELD(p0, VC4_TEX_P0_MIPLVLS);
-+ uint32_t width = VC4_GET_FIELD(p1, VC4_TEX_P1_WIDTH);
-+ uint32_t height = VC4_GET_FIELD(p1, VC4_TEX_P1_HEIGHT);
-+ uint32_t cpp, tiling_format, utile_w, utile_h;
-+ uint32_t i;
-+ uint32_t cube_map_stride = 0;
-+ enum vc4_texture_data_type type;
-+
-+ if (!vc4_use_bo(exec, texture_handle_index, VC4_MODE_RENDER, &tex))
-+ return false;
-+
-+ if (sample->is_direct) {
-+ uint32_t remaining_size = tex->base.size - p0;
-+ if (p0 > tex->base.size - 4) {
-+ DRM_ERROR("UBO offset greater than UBO size\n");
-+ goto fail;
-+ }
-+ if (p1 > remaining_size - 4) {
-+ DRM_ERROR("UBO clamp would allow reads outside of UBO\n");
-+ goto fail;
-+ }
-+ *validated_p0 = tex->paddr + p0;
-+ return true;
-+ }
-+
-+ if (width == 0)
-+ width = 2048;
-+ if (height == 0)
-+ height = 2048;
-+
-+ if (p0 & VC4_TEX_P0_CMMODE_MASK) {
-+ if (VC4_GET_FIELD(p2, VC4_TEX_P2_PTYPE) ==
-+ VC4_TEX_P2_PTYPE_CUBE_MAP_STRIDE)
-+ cube_map_stride = p2 & VC4_TEX_P2_CMST_MASK;
-+ if (VC4_GET_FIELD(p3, VC4_TEX_P2_PTYPE) ==
-+ VC4_TEX_P2_PTYPE_CUBE_MAP_STRIDE) {
-+ if (cube_map_stride) {
-+ DRM_ERROR("Cube map stride set twice\n");
-+ goto fail;
-+ }
-+
-+ cube_map_stride = p3 & VC4_TEX_P2_CMST_MASK;
-+ }
-+ if (!cube_map_stride) {
-+ DRM_ERROR("Cube map stride not set\n");
-+ goto fail;
-+ }
-+ }
-+
-+ type = (VC4_GET_FIELD(p0, VC4_TEX_P0_TYPE) |
-+ (VC4_GET_FIELD(p1, VC4_TEX_P1_TYPE4) << 4));
-+
-+ switch (type) {
-+ case VC4_TEXTURE_TYPE_RGBA8888:
-+ case VC4_TEXTURE_TYPE_RGBX8888:
-+ case VC4_TEXTURE_TYPE_RGBA32R:
-+ cpp = 4;
-+ break;
-+ case VC4_TEXTURE_TYPE_RGBA4444:
-+ case VC4_TEXTURE_TYPE_RGBA5551:
-+ case VC4_TEXTURE_TYPE_RGB565:
-+ case VC4_TEXTURE_TYPE_LUMALPHA:
-+ case VC4_TEXTURE_TYPE_S16F:
-+ case VC4_TEXTURE_TYPE_S16:
-+ cpp = 2;
-+ break;
-+ case VC4_TEXTURE_TYPE_LUMINANCE:
-+ case VC4_TEXTURE_TYPE_ALPHA:
-+ case VC4_TEXTURE_TYPE_S8:
-+ cpp = 1;
-+ break;
-+ case VC4_TEXTURE_TYPE_ETC1:
-+ case VC4_TEXTURE_TYPE_BW1:
-+ case VC4_TEXTURE_TYPE_A4:
-+ case VC4_TEXTURE_TYPE_A1:
-+ case VC4_TEXTURE_TYPE_RGBA64:
-+ case VC4_TEXTURE_TYPE_YUV422R:
-+ default:
-+ DRM_ERROR("Texture format %d unsupported\n", type);
-+ goto fail;
-+ }
-+ utile_w = utile_width(cpp);
-+ utile_h = utile_height(cpp);
-+
-+ if (type == VC4_TEXTURE_TYPE_RGBA32R) {
-+ tiling_format = VC4_TILING_FORMAT_LINEAR;
-+ } else {
-+ if (size_is_lt(width, height, cpp))
-+ tiling_format = VC4_TILING_FORMAT_LT;
-+ else
-+ tiling_format = VC4_TILING_FORMAT_T;
-+ }
-+
-+ if (!vc4_check_tex_size(exec, tex, offset + cube_map_stride * 5,
-+ tiling_format, width, height, cpp)) {
-+ goto fail;
-+ }
-+
-+ /* The mipmap levels are stored before the base of the texture. Make
-+ * sure there is actually space in the BO.
-+ */
-+ for (i = 1; i <= miplevels; i++) {
-+ uint32_t level_width = max(width >> i, 1u);
-+ uint32_t level_height = max(height >> i, 1u);
-+ uint32_t aligned_width, aligned_height;
-+ uint32_t level_size;
-+
-+ /* Once the levels get small enough, they drop from T to LT. */
-+ if (tiling_format == VC4_TILING_FORMAT_T &&
-+ size_is_lt(level_width, level_height, cpp)) {
-+ tiling_format = VC4_TILING_FORMAT_LT;
-+ }
-+
-+ switch (tiling_format) {
-+ case VC4_TILING_FORMAT_T:
-+ aligned_width = round_up(level_width, utile_w * 8);
-+ aligned_height = round_up(level_height, utile_h * 8);
-+ break;
-+ case VC4_TILING_FORMAT_LT:
-+ aligned_width = round_up(level_width, utile_w);
-+ aligned_height = round_up(level_height, utile_h);
-+ break;
-+ default:
-+ aligned_width = round_up(level_width, utile_w);
-+ aligned_height = level_height;
-+ break;
-+ }
-+
-+ level_size = aligned_width * cpp * aligned_height;
-+
-+ if (offset < level_size) {
-+ DRM_ERROR("Level %d (%dx%d -> %dx%d) size %db "
-+ "overflowed buffer bounds (offset %d)\n",
-+ i, level_width, level_height,
-+ aligned_width, aligned_height,
-+ level_size, offset);
-+ goto fail;
-+ }
-+
-+ offset -= level_size;
-+ }
-+
-+ *validated_p0 = tex->paddr + p0;
-+
-+ return true;
-+ fail:
-+ DRM_INFO("Texture p0 at %d: 0x%08x\n", sample->p_offset[0], p0);
-+ DRM_INFO("Texture p1 at %d: 0x%08x\n", sample->p_offset[1], p1);
-+ DRM_INFO("Texture p2 at %d: 0x%08x\n", sample->p_offset[2], p2);
-+ DRM_INFO("Texture p3 at %d: 0x%08x\n", sample->p_offset[3], p3);
-+ return false;
-+}
-+
-+static int
-+validate_shader_rec(struct drm_device *dev,
-+ struct vc4_exec_info *exec,
-+ struct vc4_shader_state *state)
-+{
-+ uint32_t *src_handles;
-+ void *pkt_u, *pkt_v;
-+ enum shader_rec_reloc_type {
-+ RELOC_CODE,
-+ RELOC_VBO,
-+ };
-+ struct shader_rec_reloc {
-+ enum shader_rec_reloc_type type;
-+ uint32_t offset;
-+ };
-+ static const struct shader_rec_reloc gl_relocs[] = {
-+ { RELOC_CODE, 4 }, /* fs */
-+ { RELOC_CODE, 16 }, /* vs */
-+ { RELOC_CODE, 28 }, /* cs */
-+ };
-+ static const struct shader_rec_reloc nv_relocs[] = {
-+ { RELOC_CODE, 4 }, /* fs */
-+ { RELOC_VBO, 12 }
-+ };
-+ const struct shader_rec_reloc *relocs;
-+ struct drm_gem_cma_object *bo[ARRAY_SIZE(gl_relocs) + 8];
-+ uint32_t nr_attributes = 0, nr_fixed_relocs, nr_relocs, packet_size;
-+ int i;
-+ struct vc4_validated_shader_info *validated_shader;
-+
-+ if (state->packet == VC4_PACKET_NV_SHADER_STATE) {
-+ relocs = nv_relocs;
-+ nr_fixed_relocs = ARRAY_SIZE(nv_relocs);
-+
-+ packet_size = 16;
-+ } else {
-+ relocs = gl_relocs;
-+ nr_fixed_relocs = ARRAY_SIZE(gl_relocs);
-+
-+ nr_attributes = state->addr & 0x7;
-+ if (nr_attributes == 0)
-+ nr_attributes = 8;
-+ packet_size = gl_shader_rec_size(state->addr);
-+ }
-+ nr_relocs = nr_fixed_relocs + nr_attributes;
-+
-+ if (nr_relocs * 4 > exec->shader_rec_size) {
-+ DRM_ERROR("overflowed shader recs reading %d handles "
-+ "from %d bytes left\n",
-+ nr_relocs, exec->shader_rec_size);
-+ return -EINVAL;
-+ }
-+ src_handles = exec->shader_rec_u;
-+ exec->shader_rec_u += nr_relocs * 4;
-+ exec->shader_rec_size -= nr_relocs * 4;
-+
-+ if (packet_size > exec->shader_rec_size) {
-+ DRM_ERROR("overflowed shader recs copying %db packet "
-+ "from %d bytes left\n",
-+ packet_size, exec->shader_rec_size);
-+ return -EINVAL;
-+ }
-+ pkt_u = exec->shader_rec_u;
-+ pkt_v = exec->shader_rec_v;
-+ memcpy(pkt_v, pkt_u, packet_size);
-+ exec->shader_rec_u += packet_size;
-+ /* Shader recs have to be aligned to 16 bytes (due to the attribute
-+ * flags being in the low bytes), so round the next validated shader
-+ * rec address up. This should be safe, since we've got so many
-+ * relocations in a shader rec packet.
-+ */
-+ BUG_ON(roundup(packet_size, 16) - packet_size > nr_relocs * 4);
-+ exec->shader_rec_v += roundup(packet_size, 16);
-+ exec->shader_rec_size -= packet_size;
-+
-+ for (i = 0; i < nr_relocs; i++) {
-+ enum vc4_bo_mode mode;
-+
-+ if (i < nr_fixed_relocs && relocs[i].type == RELOC_CODE)
-+ mode = VC4_MODE_SHADER;
-+ else
-+ mode = VC4_MODE_RENDER;
-+
-+ if (!vc4_use_bo(exec, src_handles[i], mode, &bo[i])) {
-+ return false;
-+ }
-+ }
-+
-+ for (i = 0; i < nr_fixed_relocs; i++) {
-+ uint32_t o = relocs[i].offset;
-+ uint32_t src_offset = *(uint32_t *)(pkt_u + o);
-+ uint32_t *texture_handles_u;
-+ void *uniform_data_u;
-+ uint32_t tex;
-+
-+ *(uint32_t *)(pkt_v + o) = bo[i]->paddr + src_offset;
-+
-+ switch (relocs[i].type) {
-+ case RELOC_CODE:
-+ if (src_offset != 0) {
-+ DRM_ERROR("Shaders must be at offset 0 of "
-+ "the BO.\n");
-+ goto fail;
-+ }
-+
-+ validated_shader = to_vc4_bo(&bo[i]->base)->validated_shader;
-+ if (!validated_shader)
-+ goto fail;
-+
-+ if (validated_shader->uniforms_src_size >
-+ exec->uniforms_size) {
-+ DRM_ERROR("Uniforms src buffer overflow\n");
-+ goto fail;
-+ }
-+
-+ texture_handles_u = exec->uniforms_u;
-+ uniform_data_u = (texture_handles_u +
-+ validated_shader->num_texture_samples);
-+
-+ memcpy(exec->uniforms_v, uniform_data_u,
-+ validated_shader->uniforms_size);
-+
-+ for (tex = 0;
-+ tex < validated_shader->num_texture_samples;
-+ tex++) {
-+ if (!reloc_tex(exec,
-+ uniform_data_u,
-+ &validated_shader->texture_samples[tex],
-+ texture_handles_u[tex])) {
-+ goto fail;
-+ }
-+ }
-+
-+ *(uint32_t *)(pkt_v + o + 4) = exec->uniforms_p;
-+
-+ exec->uniforms_u += validated_shader->uniforms_src_size;
-+ exec->uniforms_v += validated_shader->uniforms_size;
-+ exec->uniforms_p += validated_shader->uniforms_size;
-+
-+ break;
-+
-+ case RELOC_VBO:
-+ break;
-+ }
-+ }
-+
-+ for (i = 0; i < nr_attributes; i++) {
-+ struct drm_gem_cma_object *vbo = bo[nr_fixed_relocs + i];
-+ uint32_t o = 36 + i * 8;
-+ uint32_t offset = *(uint32_t *)(pkt_u + o + 0);
-+ uint32_t attr_size = *(uint8_t *)(pkt_u + o + 4) + 1;
-+ uint32_t stride = *(uint8_t *)(pkt_u + o + 5);
-+ uint32_t max_index;
-+
-+ if (state->addr & 0x8)
-+ stride |= (*(uint32_t *)(pkt_u + 100 + i * 4)) & ~0xff;
-+
-+ if (vbo->base.size < offset ||
-+ vbo->base.size - offset < attr_size) {
-+ DRM_ERROR("BO offset overflow (%d + %d > %d)\n",
-+ offset, attr_size, vbo->base.size);
-+ return -EINVAL;
-+ }
-+
-+ if (stride != 0) {
-+ max_index = ((vbo->base.size - offset - attr_size) /
-+ stride);
-+ if (state->max_index > max_index) {
-+ DRM_ERROR("primitives use index %d out of supplied %d\n",
-+ state->max_index, max_index);
-+ return -EINVAL;
-+ }
-+ }
-+
-+ *(uint32_t *)(pkt_v + o) = vbo->paddr + offset;
-+ }
-+
-+ return 0;
-+
-+fail:
-+ return -EINVAL;
-+}
-+
-+int
-+vc4_validate_shader_recs(struct drm_device *dev,
-+ struct vc4_exec_info *exec)
-+{
-+ uint32_t i;
-+ int ret = 0;
-+
-+ for (i = 0; i < exec->shader_state_count; i++) {
-+ ret = validate_shader_rec(dev, exec, &exec->shader_state[i]);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ return ret;
-+}
---- /dev/null
-+++ b/drivers/gpu/drm/vc4/vc4_validate_shaders.c
-@@ -0,0 +1,521 @@
-+/*
-+ * Copyright © 2014 Broadcom
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
-+ */
-+
-+/**
-+ * DOC: Shader validator for VC4.
-+ *
-+ * The VC4 has no IOMMU between it and system memory. So, a user with access
-+ * to execute shaders could escalate privilege by overwriting system memory
-+ * (using the VPM write address register in the general-purpose DMA mode) or
-+ * reading system memory it shouldn't (reading it as a texture, or uniform
-+ * data, or vertex data).
-+ *
-+ * This walks over a shader starting from some offset within a BO, ensuring
-+ * that its accesses are appropriately bounded, and recording how many texture
-+ * accesses are made and where so that we can do relocations for them in the
-+ * uniform stream.
-+ *
-+ * The kernel API has shaders stored in user-mapped BOs. The BOs will be
-+ * forcibly unmapped from the process before validation, and any cache of
-+ * validated state will be flushed if the mapping is faulted back in.
-+ *
-+ * Storing the shaders in BOs means that the validation process will be slow
-+ * due to uncached reads, but since shaders are long-lived and shader BOs are
-+ * never actually modified, this shouldn't be a problem.
-+ */
-+
-+#include "vc4_drv.h"
-+#include "vc4_qpu_defines.h"
-+
-+struct vc4_shader_validation_state {
-+ struct vc4_texture_sample_info tmu_setup[2];
-+ int tmu_write_count[2];
-+
-+ /* For registers that were last written to by a MIN instruction with
-+ * one argument being a uniform, the address of the uniform.
-+ * Otherwise, ~0.
-+ *
-+ * This is used for the validation of direct address memory reads.
-+ */
-+ uint32_t live_min_clamp_offsets[32 + 32 + 4];
-+ bool live_max_clamp_regs[32 + 32 + 4];
-+};
-+
-+static uint32_t
-+waddr_to_live_reg_index(uint32_t waddr, bool is_b)
-+{
-+ if (waddr < 32) {
-+ if (is_b)
-+ return 32 + waddr;
-+ else
-+ return waddr;
-+ } else if (waddr <= QPU_W_ACC3) {
-+
-+ return 64 + waddr - QPU_W_ACC0;
-+ } else {
-+ return ~0;
-+ }
-+}
-+
-+static uint32_t
-+raddr_add_a_to_live_reg_index(uint64_t inst)
-+{
-+ uint32_t sig = QPU_GET_FIELD(inst, QPU_SIG);
-+ uint32_t add_a = QPU_GET_FIELD(inst, QPU_ADD_A);
-+ uint32_t raddr_a = QPU_GET_FIELD(inst, QPU_RADDR_A);
-+ uint32_t raddr_b = QPU_GET_FIELD(inst, QPU_RADDR_B);
-+
-+ if (add_a == QPU_MUX_A) {
-+ return raddr_a;
-+ } else if (add_a == QPU_MUX_B && sig != QPU_SIG_SMALL_IMM) {
-+ return 32 + raddr_b;
-+ } else if (add_a <= QPU_MUX_R3) {
-+ return 64 + add_a;
-+ } else {
-+ return ~0;
-+ }
-+}
-+
-+static bool
-+is_tmu_submit(uint32_t waddr)
-+{
-+ return (waddr == QPU_W_TMU0_S ||
-+ waddr == QPU_W_TMU1_S);
-+}
-+
-+static bool
-+is_tmu_write(uint32_t waddr)
-+{
-+ return (waddr >= QPU_W_TMU0_S &&
-+ waddr <= QPU_W_TMU1_B);
-+}
-+
-+static bool
-+record_validated_texture_sample(struct vc4_validated_shader_info *validated_shader,
-+ struct vc4_shader_validation_state *validation_state,
-+ int tmu)
-+{
-+ uint32_t s = validated_shader->num_texture_samples;
-+ int i;
-+ struct vc4_texture_sample_info *temp_samples;
-+
-+ temp_samples = krealloc(validated_shader->texture_samples,
-+ (s + 1) * sizeof(*temp_samples),
-+ GFP_KERNEL);
-+ if (!temp_samples)
-+ return false;
-+
-+ memcpy(&temp_samples[s],
-+ &validation_state->tmu_setup[tmu],
-+ sizeof(*temp_samples));
-+
-+ validated_shader->num_texture_samples = s + 1;
-+ validated_shader->texture_samples = temp_samples;
-+
-+ for (i = 0; i < 4; i++)
-+ validation_state->tmu_setup[tmu].p_offset[i] = ~0;
-+
-+ return true;
-+}
-+
-+static bool
-+check_tmu_write(uint64_t inst,
-+ struct vc4_validated_shader_info *validated_shader,
-+ struct vc4_shader_validation_state *validation_state,
-+ bool is_mul)
-+{
-+ uint32_t waddr = (is_mul ?
-+ QPU_GET_FIELD(inst, QPU_WADDR_MUL) :
-+ QPU_GET_FIELD(inst, QPU_WADDR_ADD));
-+ uint32_t raddr_a = QPU_GET_FIELD(inst, QPU_RADDR_A);
-+ uint32_t raddr_b = QPU_GET_FIELD(inst, QPU_RADDR_B);
-+ int tmu = waddr > QPU_W_TMU0_B;
-+ bool submit = is_tmu_submit(waddr);
-+ bool is_direct = submit && validation_state->tmu_write_count[tmu] == 0;
-+ uint32_t sig = QPU_GET_FIELD(inst, QPU_SIG);
-+
-+ if (is_direct) {
-+ uint32_t add_b = QPU_GET_FIELD(inst, QPU_ADD_B);
-+ uint32_t clamp_reg, clamp_offset;
-+
-+ if (sig == QPU_SIG_SMALL_IMM) {
-+ DRM_ERROR("direct TMU read used small immediate\n");
-+ return false;
-+ }
-+
-+ /* Make sure that this texture load is an add of the base
-+ * address of the UBO to a clamped offset within the UBO.
-+ */
-+ if (is_mul ||
-+ QPU_GET_FIELD(inst, QPU_OP_ADD) != QPU_A_ADD) {
-+ DRM_ERROR("direct TMU load wasn't an add\n");
-+ return false;
-+ }
-+
-+ /* We assert that the the clamped address is the first
-+ * argument, and the UBO base address is the second argument.
-+ * This is arbitrary, but simpler than supporting flipping the
-+ * two either way.
-+ */
-+ clamp_reg = raddr_add_a_to_live_reg_index(inst);
-+ if (clamp_reg == ~0) {
-+ DRM_ERROR("direct TMU load wasn't clamped\n");
-+ return false;
-+ }
-+
-+ clamp_offset = validation_state->live_min_clamp_offsets[clamp_reg];
-+ if (clamp_offset == ~0) {
-+ DRM_ERROR("direct TMU load wasn't clamped\n");
-+ return false;
-+ }
-+
-+ /* Store the clamp value's offset in p1 (see reloc_tex() in
-+ * vc4_validate.c).
-+ */
-+ validation_state->tmu_setup[tmu].p_offset[1] =
-+ clamp_offset;
-+
-+ if (!(add_b == QPU_MUX_A && raddr_a == QPU_R_UNIF) &&
-+ !(add_b == QPU_MUX_B && raddr_b == QPU_R_UNIF)) {
-+ DRM_ERROR("direct TMU load didn't add to a uniform\n");
-+ return false;
-+ }
-+
-+ validation_state->tmu_setup[tmu].is_direct = true;
-+ } else {
-+ if (raddr_a == QPU_R_UNIF || (sig != QPU_SIG_SMALL_IMM &&
-+ raddr_b == QPU_R_UNIF)) {
-+ DRM_ERROR("uniform read in the same instruction as "
-+ "texture setup.\n");
-+ return false;
-+ }
-+ }
-+
-+ if (validation_state->tmu_write_count[tmu] >= 4) {
-+ DRM_ERROR("TMU%d got too many parameters before dispatch\n",
-+ tmu);
-+ return false;
-+ }
-+ validation_state->tmu_setup[tmu].p_offset[validation_state->tmu_write_count[tmu]] =
-+ validated_shader->uniforms_size;
-+ validation_state->tmu_write_count[tmu]++;
-+ /* Since direct uses a RADDR uniform reference, it will get counted in
-+ * check_instruction_reads()
-+ */
-+ if (!is_direct)
-+ validated_shader->uniforms_size += 4;
-+
-+ if (submit) {
-+ if (!record_validated_texture_sample(validated_shader,
-+ validation_state, tmu)) {
-+ return false;
-+ }
-+
-+ validation_state->tmu_write_count[tmu] = 0;
-+ }
-+
-+ return true;
-+}
-+
-+static bool
-+check_register_write(uint64_t inst,
-+ struct vc4_validated_shader_info *validated_shader,
-+ struct vc4_shader_validation_state *validation_state,
-+ bool is_mul)
-+{
-+ uint32_t waddr = (is_mul ?
-+ QPU_GET_FIELD(inst, QPU_WADDR_MUL) :
-+ QPU_GET_FIELD(inst, QPU_WADDR_ADD));
-+
-+ switch (waddr) {
-+ case QPU_W_UNIFORMS_ADDRESS:
-+ /* XXX: We'll probably need to support this for reladdr, but
-+ * it's definitely a security-related one.
-+ */
-+ DRM_ERROR("uniforms address load unsupported\n");
-+ return false;
-+
-+ case QPU_W_TLB_COLOR_MS:
-+ case QPU_W_TLB_COLOR_ALL:
-+ case QPU_W_TLB_Z:
-+ /* These only interact with the tile buffer, not main memory,
-+ * so they're safe.
-+ */
-+ return true;
-+
-+ case QPU_W_TMU0_S:
-+ case QPU_W_TMU0_T:
-+ case QPU_W_TMU0_R:
-+ case QPU_W_TMU0_B:
-+ case QPU_W_TMU1_S:
-+ case QPU_W_TMU1_T:
-+ case QPU_W_TMU1_R:
-+ case QPU_W_TMU1_B:
-+ return check_tmu_write(inst, validated_shader, validation_state,
-+ is_mul);
-+
-+ case QPU_W_HOST_INT:
-+ case QPU_W_TMU_NOSWAP:
-+ case QPU_W_TLB_ALPHA_MASK:
-+ case QPU_W_MUTEX_RELEASE:
-+ /* XXX: I haven't thought about these, so don't support them
-+ * for now.
-+ */
-+ DRM_ERROR("Unsupported waddr %d\n", waddr);
-+ return false;
-+
-+ case QPU_W_VPM_ADDR:
-+ DRM_ERROR("General VPM DMA unsupported\n");
-+ return false;
-+
-+ case QPU_W_VPM:
-+ case QPU_W_VPMVCD_SETUP:
-+ /* We allow VPM setup in general, even including VPM DMA
-+ * configuration setup, because the (unsafe) DMA can only be
-+ * triggered by QPU_W_VPM_ADDR writes.
-+ */
-+ return true;
-+
-+ case QPU_W_TLB_STENCIL_SETUP:
-+ return true;
-+ }
-+
-+ return true;
-+}
-+
-+static void
-+track_live_clamps(uint64_t inst,
-+ struct vc4_validated_shader_info *validated_shader,
-+ struct vc4_shader_validation_state *validation_state)
-+{
-+ uint32_t op_add = QPU_GET_FIELD(inst, QPU_OP_ADD);
-+ uint32_t waddr_add = QPU_GET_FIELD(inst, QPU_WADDR_ADD);
-+ uint32_t waddr_mul = QPU_GET_FIELD(inst, QPU_WADDR_MUL);
-+ uint32_t cond_add = QPU_GET_FIELD(inst, QPU_COND_ADD);
-+ uint32_t add_a = QPU_GET_FIELD(inst, QPU_ADD_A);
-+ uint32_t add_b = QPU_GET_FIELD(inst, QPU_ADD_B);
-+ uint32_t raddr_a = QPU_GET_FIELD(inst, QPU_RADDR_A);
-+ uint32_t raddr_b = QPU_GET_FIELD(inst, QPU_RADDR_B);
-+ uint32_t sig = QPU_GET_FIELD(inst, QPU_SIG);
-+ bool ws = inst & QPU_WS;
-+ uint32_t lri_add_a, lri_add, lri_mul;
-+ bool add_a_is_min_0;
-+
-+ /* Check whether OP_ADD's A argumennt comes from a live MAX(x, 0),
-+ * before we clear previous live state.
-+ */
-+ lri_add_a = raddr_add_a_to_live_reg_index(inst);
-+ add_a_is_min_0 = (lri_add_a != ~0 &&
-+ validation_state->live_max_clamp_regs[lri_add_a]);
-+
-+ /* Clear live state for registers written by our instruction. */
-+ lri_add = waddr_to_live_reg_index(waddr_add, ws);
-+ lri_mul = waddr_to_live_reg_index(waddr_mul, !ws);
-+ if (lri_mul != ~0) {
-+ validation_state->live_max_clamp_regs[lri_mul] = false;
-+ validation_state->live_min_clamp_offsets[lri_mul] = ~0;
-+ }
-+ if (lri_add != ~0) {
-+ validation_state->live_max_clamp_regs[lri_add] = false;
-+ validation_state->live_min_clamp_offsets[lri_add] = ~0;
-+ } else {
-+ /* Nothing further to do for live tracking, since only ADDs
-+ * generate new live clamp registers.
-+ */
-+ return;
-+ }
-+
-+ /* Now, handle remaining live clamp tracking for the ADD operation. */
-+
-+ if (cond_add != QPU_COND_ALWAYS)
-+ return;
-+
-+ if (op_add == QPU_A_MAX) {
-+ /* Track live clamps of a value to a minimum of 0 (in either
-+ * arg).
-+ */
-+ if (sig != QPU_SIG_SMALL_IMM || raddr_b != 0 ||
-+ (add_a != QPU_MUX_B && add_b != QPU_MUX_B)) {
-+ return;
-+ }
-+
-+ validation_state->live_max_clamp_regs[lri_add] = true;
-+ } if (op_add == QPU_A_MIN) {
-+ /* Track live clamps of a value clamped to a minimum of 0 and
-+ * a maximum of some uniform's offset.
-+ */
-+ if (!add_a_is_min_0)
-+ return;
-+
-+ if (!(add_b == QPU_MUX_A && raddr_a == QPU_R_UNIF) &&
-+ !(add_b == QPU_MUX_B && raddr_b == QPU_R_UNIF &&
-+ sig != QPU_SIG_SMALL_IMM)) {
-+ return;
-+ }
-+
-+ validation_state->live_min_clamp_offsets[lri_add] =
-+ validated_shader->uniforms_size;
-+ }
-+}
-+
-+static bool
-+check_instruction_writes(uint64_t inst,
-+ struct vc4_validated_shader_info *validated_shader,
-+ struct vc4_shader_validation_state *validation_state)
-+{
-+ uint32_t waddr_add = QPU_GET_FIELD(inst, QPU_WADDR_ADD);
-+ uint32_t waddr_mul = QPU_GET_FIELD(inst, QPU_WADDR_MUL);
-+ bool ok;
-+
-+ if (is_tmu_write(waddr_add) && is_tmu_write(waddr_mul)) {
-+ DRM_ERROR("ADD and MUL both set up textures\n");
-+ return false;
-+ }
-+
-+ ok = (check_register_write(inst, validated_shader, validation_state, false) &&
-+ check_register_write(inst, validated_shader, validation_state, true));
-+
-+ track_live_clamps(inst, validated_shader, validation_state);
-+
-+ return ok;
-+}
-+
-+static bool
-+check_instruction_reads(uint64_t inst,
-+ struct vc4_validated_shader_info *validated_shader)
-+{
-+ uint32_t raddr_a = QPU_GET_FIELD(inst, QPU_RADDR_A);
-+ uint32_t raddr_b = QPU_GET_FIELD(inst, QPU_RADDR_B);
-+ uint32_t sig = QPU_GET_FIELD(inst, QPU_SIG);
-+
-+ if (raddr_a == QPU_R_UNIF ||
-+ (raddr_b == QPU_R_UNIF && sig != QPU_SIG_SMALL_IMM)) {
-+ /* This can't overflow the uint32_t, because we're reading 8
-+ * bytes of instruction to increment by 4 here, so we'd
-+ * already be OOM.
-+ */
-+ validated_shader->uniforms_size += 4;
-+ }
-+
-+ return true;
-+}
-+
-+struct vc4_validated_shader_info *
-+vc4_validate_shader(struct drm_gem_cma_object *shader_obj)
-+{
-+ bool found_shader_end = false;
-+ int shader_end_ip = 0;
-+ uint32_t ip, max_ip;
-+ uint64_t *shader;
-+ struct vc4_validated_shader_info *validated_shader;
-+ struct vc4_shader_validation_state validation_state;
-+ int i;
-+
-+ memset(&validation_state, 0, sizeof(validation_state));
-+
-+ for (i = 0; i < 8; i++)
-+ validation_state.tmu_setup[i / 4].p_offset[i % 4] = ~0;
-+ for (i = 0; i < ARRAY_SIZE(validation_state.live_min_clamp_offsets); i++)
-+ validation_state.live_min_clamp_offsets[i] = ~0;
-+
-+ shader = shader_obj->vaddr;
-+ max_ip = shader_obj->base.size / sizeof(uint64_t);
-+
-+ validated_shader = kcalloc(sizeof(*validated_shader), 1, GFP_KERNEL);
-+ if (!validated_shader)
-+ return NULL;
-+
-+ for (ip = 0; ip < max_ip; ip++) {
-+ uint64_t inst = shader[ip];
-+ uint32_t sig = QPU_GET_FIELD(inst, QPU_SIG);
-+
-+ switch (sig) {
-+ case QPU_SIG_NONE:
-+ case QPU_SIG_WAIT_FOR_SCOREBOARD:
-+ case QPU_SIG_SCOREBOARD_UNLOCK:
-+ case QPU_SIG_COLOR_LOAD:
-+ case QPU_SIG_LOAD_TMU0:
-+ case QPU_SIG_LOAD_TMU1:
-+ case QPU_SIG_PROG_END:
-+ case QPU_SIG_SMALL_IMM:
-+ if (!check_instruction_writes(inst, validated_shader,
-+ &validation_state)) {
-+ DRM_ERROR("Bad write at ip %d\n", ip);
-+ goto fail;
-+ }
-+
-+ if (!check_instruction_reads(inst, validated_shader))
-+ goto fail;
-+
-+ if (sig == QPU_SIG_PROG_END) {
-+ found_shader_end = true;
-+ shader_end_ip = ip;
-+ }
-+
-+ break;
-+
-+ case QPU_SIG_LOAD_IMM:
-+ if (!check_instruction_writes(inst, validated_shader,
-+ &validation_state)) {
-+ DRM_ERROR("Bad LOAD_IMM write at ip %d\n", ip);
-+ goto fail;
-+ }
-+ break;
-+
-+ default:
-+ DRM_ERROR("Unsupported QPU signal %d at "
-+ "instruction %d\n", sig, ip);
-+ goto fail;
-+ }
-+
-+ /* There are two delay slots after program end is signaled
-+ * that are still executed, then we're finished.
-+ */
-+ if (found_shader_end && ip == shader_end_ip + 2)
-+ break;
-+ }
-+
-+ if (ip == max_ip) {
-+ DRM_ERROR("shader failed to terminate before "
-+ "shader BO end at %d\n",
-+ shader_obj->base.size);
-+ goto fail;
-+ }
-+
-+ /* Again, no chance of integer overflow here because the worst case
-+ * scenario is 8 bytes of uniforms plus handles per 8-byte
-+ * instruction.
-+ */
-+ validated_shader->uniforms_src_size =
-+ (validated_shader->uniforms_size +
-+ 4 * validated_shader->num_texture_samples);
-+
-+ return validated_shader;
-+
-+fail:
-+ if (validated_shader) {
-+ kfree(validated_shader->texture_samples);
-+ kfree(validated_shader);
-+ }
-+ return NULL;
-+}
---- /dev/null
-+++ b/include/uapi/drm/vc4_drm.h
-@@ -0,0 +1,229 @@
-+/*
-+ * Copyright © 2014-2015 Broadcom
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
-+ */
-+
-+#ifndef _UAPI_VC4_DRM_H_
-+#define _UAPI_VC4_DRM_H_
-+
-+#include <drm/drm.h>
-+
-+#define DRM_VC4_SUBMIT_CL 0x00
-+#define DRM_VC4_WAIT_SEQNO 0x01
-+#define DRM_VC4_WAIT_BO 0x02
-+#define DRM_VC4_CREATE_BO 0x03
-+#define DRM_VC4_MMAP_BO 0x04
-+#define DRM_VC4_CREATE_SHADER_BO 0x05
-+
-+#define DRM_IOCTL_VC4_SUBMIT_CL DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_SUBMIT_CL, struct drm_vc4_submit_cl)
-+#define DRM_IOCTL_VC4_WAIT_SEQNO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_WAIT_SEQNO, struct drm_vc4_wait_seqno)
-+#define DRM_IOCTL_VC4_WAIT_BO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_WAIT_BO, struct drm_vc4_wait_bo)
-+#define DRM_IOCTL_VC4_CREATE_BO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_CREATE_BO, struct drm_vc4_create_bo)
-+#define DRM_IOCTL_VC4_MMAP_BO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_MMAP_BO, struct drm_vc4_mmap_bo)
-+#define DRM_IOCTL_VC4_CREATE_SHADER_BO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_CREATE_SHADER_BO, struct drm_vc4_create_shader_bo)
-+
-+struct drm_vc4_submit_rcl_surface {
-+ uint32_t hindex; /* Handle index, or ~0 if not present. */
-+ uint32_t offset; /* Offset to start of buffer. */
-+ /*
-+ * Bits for either render config (color_ms_write) or load/store packet.
-+ */
-+ uint16_t bits;
-+ uint16_t pad;
-+};
-+
-+/**
-+ * struct drm_vc4_submit_cl - ioctl argument for submitting commands to the 3D
-+ * engine.
-+ *
-+ * Drivers typically use GPU BOs to store batchbuffers / command lists and
-+ * their associated state. However, because the VC4 lacks an MMU, we have to
-+ * do validation of memory accesses by the GPU commands. If we were to store
-+ * our commands in BOs, we'd need to do uncached readback from them to do the
-+ * validation process, which is too expensive. Instead, userspace accumulates
-+ * commands and associated state in plain memory, then the kernel copies the
-+ * data to its own address space, and then validates and stores it in a GPU
-+ * BO.
-+ */
-+struct drm_vc4_submit_cl {
-+ /* Pointer to the binner command list.
-+ *
-+ * This is the first set of commands executed, which runs the
-+ * coordinate shader to determine where primitives land on the screen,
-+ * then writes out the state updates and draw calls necessary per tile
-+ * to the tile allocation BO.
-+ */
-+ uint64_t bin_cl;
-+
-+ /* Pointer to the shader records.
-+ *
-+ * Shader records are the structures read by the hardware that contain
-+ * pointers to uniforms, shaders, and vertex attributes. The
-+ * reference to the shader record has enough information to determine
-+ * how many pointers are necessary (fixed number for shaders/uniforms,
-+ * and an attribute count), so those BO indices into bo_handles are
-+ * just stored as uint32_ts before each shader record passed in.
-+ */
-+ uint64_t shader_rec;
-+
-+ /* Pointer to uniform data and texture handles for the textures
-+ * referenced by the shader.
-+ *
-+ * For each shader state record, there is a set of uniform data in the
-+ * order referenced by the record (FS, VS, then CS). Each set of
-+ * uniform data has a uint32_t index into bo_handles per texture
-+ * sample operation, in the order the QPU_W_TMUn_S writes appear in
-+ * the program. Following the texture BO handle indices is the actual
-+ * uniform data.
-+ *
-+ * The individual uniform state blocks don't have sizes passed in,
-+ * because the kernel has to determine the sizes anyway during shader
-+ * code validation.
-+ */
-+ uint64_t uniforms;
-+ uint64_t bo_handles;
-+
-+ /* Size in bytes of the binner command list. */
-+ uint32_t bin_cl_size;
-+ /* Size in bytes of the set of shader records. */
-+ uint32_t shader_rec_size;
-+ /* Number of shader records.
-+ *
-+ * This could just be computed from the contents of shader_records and
-+ * the address bits of references to them from the bin CL, but it
-+ * keeps the kernel from having to resize some allocations it makes.
-+ */
-+ uint32_t shader_rec_count;
-+ /* Size in bytes of the uniform state. */
-+ uint32_t uniforms_size;
-+
-+ /* Number of BO handles passed in (size is that times 4). */
-+ uint32_t bo_handle_count;
-+
-+ /* RCL setup: */
-+ uint16_t width;
-+ uint16_t height;
-+ uint8_t min_x_tile;
-+ uint8_t min_y_tile;
-+ uint8_t max_x_tile;
-+ uint8_t max_y_tile;
-+ struct drm_vc4_submit_rcl_surface color_read;
-+ struct drm_vc4_submit_rcl_surface color_ms_write;
-+ struct drm_vc4_submit_rcl_surface zs_read;
-+ struct drm_vc4_submit_rcl_surface zs_write;
-+ uint32_t clear_color[2];
-+ uint32_t clear_z;
-+ uint8_t clear_s;
-+
-+ uint32_t pad:24;
-+
-+#define VC4_SUBMIT_CL_USE_CLEAR_COLOR (1 << 0)
-+ uint32_t flags;
-+
-+ /* Returned value of the seqno of this render job (for the
-+ * wait ioctl).
-+ */
-+ uint64_t seqno;
-+};
-+
-+/**
-+ * struct drm_vc4_wait_seqno - ioctl argument for waiting for
-+ * DRM_VC4_SUBMIT_CL completion using its returned seqno.
-+ *
-+ * timeout_ns is the timeout in nanoseconds, where "0" means "don't
-+ * block, just return the status."
-+ */
-+struct drm_vc4_wait_seqno {
-+ uint64_t seqno;
-+ uint64_t timeout_ns;
-+};
-+
-+/**
-+ * struct drm_vc4_wait_bo - ioctl argument for waiting for
-+ * completion of the last DRM_VC4_SUBMIT_CL on a BO.
-+ *
-+ * This is useful for cases where multiple processes might be
-+ * rendering to a BO and you want to wait for all rendering to be
-+ * completed.
-+ */
-+struct drm_vc4_wait_bo {
-+ uint32_t handle;
-+ uint32_t pad;
-+ uint64_t timeout_ns;
-+};
-+
-+/**
-+ * struct drm_vc4_create_bo - ioctl argument for creating VC4 BOs.
-+ *
-+ * There are currently no values for the flags argument, but it may be
-+ * used in a future extension.
-+ */
-+struct drm_vc4_create_bo {
-+ uint32_t size;
-+ uint32_t flags;
-+ /** Returned GEM handle for the BO. */
-+ uint32_t handle;
-+ uint32_t pad;
-+};
-+
-+/**
-+ * struct drm_vc4_create_shader_bo - ioctl argument for creating VC4
-+ * shader BOs.
-+ *
-+ * Since allowing a shader to be overwritten while it's also being
-+ * executed from would allow privlege escalation, shaders must be
-+ * created using this ioctl, and they can't be mmapped later.
-+ */
-+struct drm_vc4_create_shader_bo {
-+ /* Size of the data argument. */
-+ uint32_t size;
-+ /* Flags, currently must be 0. */
-+ uint32_t flags;
-+
-+ /* Pointer to the data. */
-+ uint64_t data;
-+
-+ /** Returned GEM handle for the BO. */
-+ uint32_t handle;
-+ /* Pad, must be 0. */
-+ uint32_t pad;
-+};
-+
-+/**
-+ * struct drm_vc4_mmap_bo - ioctl argument for mapping VC4 BOs.
-+ *
-+ * This doesn't actually perform an mmap. Instead, it returns the
-+ * offset you need to use in an mmap on the DRM device node. This
-+ * means that tools like valgrind end up knowing about the mapped
-+ * memory.
-+ *
-+ * There are currently no values for the flags argument, but it may be
-+ * used in a future extension.
-+ */
-+struct drm_vc4_mmap_bo {
-+ /** Handle for the object being mapped. */
-+ uint32_t handle;
-+ uint32_t flags;
-+ /** offset into the drm node to use for subsequent mmap call. */
-+ uint64_t offset;
-+};
-+
-+#endif /* _UAPI_VC4_DRM_H_ */
diff --git a/target/linux/brcm2708/patches-4.4/0091-drm-vc4-Force-HDMI-to-connected.patch b/target/linux/brcm2708/patches-4.4/0091-drm-vc4-Force-HDMI-to-connected.patch
new file mode 100644
index 0000000000..a6391c7fb1
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0091-drm-vc4-Force-HDMI-to-connected.patch
@@ -0,0 +1,23 @@
+From 92de07785e3ece5672448a5efa7b3b45957059f6 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Wed, 14 Oct 2015 11:32:14 -0700
+Subject: [PATCH 091/381] drm/vc4: Force HDMI to connected.
+
+For some reason on the downstream tree, the HPD GPIO isn't working.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_hdmi.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
+@@ -164,6 +164,8 @@ vc4_hdmi_connector_detect(struct drm_con
+ struct drm_device *dev = connector->dev;
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+
++ return connector_status_connected;
++
+ if (vc4->hdmi->hpd_gpio) {
+ if (gpio_get_value(vc4->hdmi->hpd_gpio))
+ return connector_status_connected;
diff --git a/target/linux/brcm2708/patches-4.4/0092-drm-vc4-Force-HDMI-to-connected.patch b/target/linux/brcm2708/patches-4.4/0092-drm-vc4-Force-HDMI-to-connected.patch
deleted file mode 100644
index 3c3417ca87..0000000000
--- a/target/linux/brcm2708/patches-4.4/0092-drm-vc4-Force-HDMI-to-connected.patch
+++ /dev/null
@@ -1,23 +0,0 @@
-From aa579c7485e1bae681c50b223e89cd658dd0b2c1 Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Wed, 14 Oct 2015 11:32:14 -0700
-Subject: [PATCH 092/170] drm/vc4: Force HDMI to connected.
-
-For some reason on the downstream tree, the HPD GPIO isn't working.
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
----
- drivers/gpu/drm/vc4/vc4_hdmi.c | 2 ++
- 1 file changed, 2 insertions(+)
-
---- a/drivers/gpu/drm/vc4/vc4_hdmi.c
-+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
-@@ -164,6 +164,8 @@ vc4_hdmi_connector_detect(struct drm_con
- struct drm_device *dev = connector->dev;
- struct vc4_dev *vc4 = to_vc4_dev(dev);
-
-+ return connector_status_connected;
-+
- if (vc4->hdmi->hpd_gpio) {
- if (gpio_get_value(vc4->hdmi->hpd_gpio))
- return connector_status_connected;
diff --git a/target/linux/brcm2708/patches-4.4/0092-drm-vc4-bo-cache-locking-fixes.patch b/target/linux/brcm2708/patches-4.4/0092-drm-vc4-bo-cache-locking-fixes.patch
new file mode 100644
index 0000000000..e7c3cb17e3
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0092-drm-vc4-bo-cache-locking-fixes.patch
@@ -0,0 +1,147 @@
+From 9d9f602905f1d7de7b0d93d8293ed144f7af0e21 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 19 Oct 2015 08:23:18 -0700
+Subject: [PATCH 092/381] drm/vc4: bo cache locking fixes.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_bo.c | 32 ++++++++++++++++++--------------
+ drivers/gpu/drm/vc4/vc4_drv.h | 2 +-
+ 2 files changed, 19 insertions(+), 15 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_bo.c
++++ b/drivers/gpu/drm/vc4/vc4_bo.c
+@@ -112,14 +112,14 @@ void vc4_bo_cache_purge(struct drm_devic
+ {
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+
+- spin_lock(&vc4->bo_lock);
++ mutex_lock(&vc4->bo_lock);
+ while (!list_empty(&vc4->bo_cache.time_list)) {
+ struct vc4_bo *bo = list_last_entry(&vc4->bo_cache.time_list,
+ struct vc4_bo, unref_head);
+ vc4_bo_remove_from_cache(bo);
+ vc4_bo_destroy(bo);
+ }
+- spin_unlock(&vc4->bo_lock);
++ mutex_unlock(&vc4->bo_lock);
+ }
+
+ struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size)
+@@ -134,18 +134,18 @@ struct vc4_bo *vc4_bo_create(struct drm_
+ return NULL;
+
+ /* First, try to get a vc4_bo from the kernel BO cache. */
+- spin_lock(&vc4->bo_lock);
++ mutex_lock(&vc4->bo_lock);
+ if (page_index < vc4->bo_cache.size_list_size &&
+ !list_empty(&vc4->bo_cache.size_list[page_index])) {
+ struct vc4_bo *bo =
+ list_first_entry(&vc4->bo_cache.size_list[page_index],
+ struct vc4_bo, size_head);
+ vc4_bo_remove_from_cache(bo);
+- spin_unlock(&vc4->bo_lock);
++ mutex_unlock(&vc4->bo_lock);
+ kref_init(&bo->base.base.refcount);
+ return bo;
+ }
+- spin_unlock(&vc4->bo_lock);
++ mutex_unlock(&vc4->bo_lock);
+
+ /* Otherwise, make a new BO. */
+ for (pass = 0; ; pass++) {
+@@ -215,7 +215,7 @@ vc4_bo_cache_free_old(struct drm_device
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ unsigned long expire_time = jiffies - msecs_to_jiffies(1000);
+
+- spin_lock(&vc4->bo_lock);
++ mutex_lock(&vc4->bo_lock);
+ while (!list_empty(&vc4->bo_cache.time_list)) {
+ struct vc4_bo *bo = list_last_entry(&vc4->bo_cache.time_list,
+ struct vc4_bo, unref_head);
+@@ -223,14 +223,14 @@ vc4_bo_cache_free_old(struct drm_device
+ mod_timer(&vc4->bo_cache.time_timer,
+ round_jiffies_up(jiffies +
+ msecs_to_jiffies(1000)));
+- spin_unlock(&vc4->bo_lock);
++ mutex_unlock(&vc4->bo_lock);
+ return;
+ }
+
+ vc4_bo_remove_from_cache(bo);
+ vc4_bo_destroy(bo);
+ }
+- spin_unlock(&vc4->bo_lock);
++ mutex_unlock(&vc4->bo_lock);
+ }
+
+ /* Called on the last userspace/kernel unreference of the BO. Returns
+@@ -248,21 +248,25 @@ void vc4_free_object(struct drm_gem_obje
+ /* If the object references someone else's memory, we can't cache it.
+ */
+ if (gem_bo->import_attach) {
++ mutex_lock(&vc4->bo_lock);
+ vc4_bo_destroy(bo);
++ mutex_unlock(&vc4->bo_lock);
+ return;
+ }
+
+ /* Don't cache if it was publicly named. */
+ if (gem_bo->name) {
++ mutex_lock(&vc4->bo_lock);
+ vc4_bo_destroy(bo);
++ mutex_unlock(&vc4->bo_lock);
+ return;
+ }
+
+- spin_lock(&vc4->bo_lock);
++ mutex_lock(&vc4->bo_lock);
+ cache_list = vc4_get_cache_list_for_size(dev, gem_bo->size);
+ if (!cache_list) {
+ vc4_bo_destroy(bo);
+- spin_unlock(&vc4->bo_lock);
++ mutex_unlock(&vc4->bo_lock);
+ return;
+ }
+
+@@ -278,7 +282,7 @@ void vc4_free_object(struct drm_gem_obje
+
+ vc4->bo_stats.num_cached++;
+ vc4->bo_stats.size_cached += gem_bo->size;
+- spin_unlock(&vc4->bo_lock);
++ mutex_unlock(&vc4->bo_lock);
+
+ vc4_bo_cache_free_old(dev);
+ }
+@@ -465,7 +469,7 @@ void vc4_bo_cache_init(struct drm_device
+ {
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+
+- spin_lock_init(&vc4->bo_lock);
++ mutex_init(&vc4->bo_lock);
+
+ INIT_LIST_HEAD(&vc4->bo_cache.time_list);
+
+@@ -498,9 +502,9 @@ int vc4_bo_stats_debugfs(struct seq_file
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ struct vc4_bo_stats stats;
+
+- spin_lock(&vc4->bo_lock);
++ mutex_lock(&vc4->bo_lock);
+ stats = vc4->bo_stats;
+- spin_unlock(&vc4->bo_lock);
++ mutex_unlock(&vc4->bo_lock);
+
+ seq_printf(m, "num bos allocated: %d\n", stats.num_allocated);
+ seq_printf(m, "size bos allocated: %dkb\n", stats.size_allocated / 1024);
+--- a/drivers/gpu/drm/vc4/vc4_drv.h
++++ b/drivers/gpu/drm/vc4/vc4_drv.h
+@@ -49,7 +49,7 @@ struct vc4_dev {
+ } bo_stats;
+
+ /* Protects bo_cache and the BO stats. */
+- spinlock_t bo_lock;
++ struct mutex bo_lock;
+
+ /* Sequence number for the last job queued in job_list.
+ * Starts at 0 (no jobs emitted).
diff --git a/target/linux/brcm2708/patches-4.4/0093-drm-vc4-bo-cache-locking-cleanup.patch b/target/linux/brcm2708/patches-4.4/0093-drm-vc4-bo-cache-locking-cleanup.patch
new file mode 100644
index 0000000000..37bbd51453
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0093-drm-vc4-bo-cache-locking-cleanup.patch
@@ -0,0 +1,92 @@
+From 2520f46f0d6e44f5ecfa534fb5a5f1a11302c83c Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 19 Oct 2015 08:29:41 -0700
+Subject: [PATCH 093/381] drm/vc4: bo cache locking cleanup.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_bo.c | 22 +++++++++-------------
+ 1 file changed, 9 insertions(+), 13 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_bo.c
++++ b/drivers/gpu/drm/vc4/vc4_bo.c
+@@ -215,7 +215,6 @@ vc4_bo_cache_free_old(struct drm_device
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ unsigned long expire_time = jiffies - msecs_to_jiffies(1000);
+
+- mutex_lock(&vc4->bo_lock);
+ while (!list_empty(&vc4->bo_cache.time_list)) {
+ struct vc4_bo *bo = list_last_entry(&vc4->bo_cache.time_list,
+ struct vc4_bo, unref_head);
+@@ -223,14 +222,12 @@ vc4_bo_cache_free_old(struct drm_device
+ mod_timer(&vc4->bo_cache.time_timer,
+ round_jiffies_up(jiffies +
+ msecs_to_jiffies(1000)));
+- mutex_unlock(&vc4->bo_lock);
+ return;
+ }
+
+ vc4_bo_remove_from_cache(bo);
+ vc4_bo_destroy(bo);
+ }
+- mutex_unlock(&vc4->bo_lock);
+ }
+
+ /* Called on the last userspace/kernel unreference of the BO. Returns
+@@ -245,29 +242,24 @@ void vc4_free_object(struct drm_gem_obje
+ struct vc4_bo *bo = to_vc4_bo(gem_bo);
+ struct list_head *cache_list;
+
++ mutex_lock(&vc4->bo_lock);
+ /* If the object references someone else's memory, we can't cache it.
+ */
+ if (gem_bo->import_attach) {
+- mutex_lock(&vc4->bo_lock);
+ vc4_bo_destroy(bo);
+- mutex_unlock(&vc4->bo_lock);
+- return;
++ goto out;
+ }
+
+ /* Don't cache if it was publicly named. */
+ if (gem_bo->name) {
+- mutex_lock(&vc4->bo_lock);
+ vc4_bo_destroy(bo);
+- mutex_unlock(&vc4->bo_lock);
+- return;
++ goto out;
+ }
+
+- mutex_lock(&vc4->bo_lock);
+ cache_list = vc4_get_cache_list_for_size(dev, gem_bo->size);
+ if (!cache_list) {
+ vc4_bo_destroy(bo);
+- mutex_unlock(&vc4->bo_lock);
+- return;
++ goto out;
+ }
+
+ if (bo->validated_shader) {
+@@ -282,9 +274,11 @@ void vc4_free_object(struct drm_gem_obje
+
+ vc4->bo_stats.num_cached++;
+ vc4->bo_stats.size_cached += gem_bo->size;
+- mutex_unlock(&vc4->bo_lock);
+
+ vc4_bo_cache_free_old(dev);
++
++out:
++ mutex_unlock(&vc4->bo_lock);
+ }
+
+ static void vc4_bo_cache_time_work(struct work_struct *work)
+@@ -293,7 +287,9 @@ static void vc4_bo_cache_time_work(struc
+ container_of(work, struct vc4_dev, bo_cache.time_work);
+ struct drm_device *dev = vc4->dev;
+
++ mutex_lock(&vc4->bo_lock);
+ vc4_bo_cache_free_old(dev);
++ mutex_unlock(&vc4->bo_lock);
+ }
+
+ static void vc4_bo_cache_time_timer(unsigned long data)
diff --git a/target/linux/brcm2708/patches-4.4/0093-drm-vc4-bo-cache-locking-fixes.patch b/target/linux/brcm2708/patches-4.4/0093-drm-vc4-bo-cache-locking-fixes.patch
deleted file mode 100644
index 927d0dc782..0000000000
--- a/target/linux/brcm2708/patches-4.4/0093-drm-vc4-bo-cache-locking-fixes.patch
+++ /dev/null
@@ -1,147 +0,0 @@
-From edb828d91374e8fa4f05d68be008c40d4f9a158d Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Mon, 19 Oct 2015 08:23:18 -0700
-Subject: [PATCH 093/170] drm/vc4: bo cache locking fixes.
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
----
- drivers/gpu/drm/vc4/vc4_bo.c | 32 ++++++++++++++++++--------------
- drivers/gpu/drm/vc4/vc4_drv.h | 2 +-
- 2 files changed, 19 insertions(+), 15 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_bo.c
-+++ b/drivers/gpu/drm/vc4/vc4_bo.c
-@@ -112,14 +112,14 @@ void vc4_bo_cache_purge(struct drm_devic
- {
- struct vc4_dev *vc4 = to_vc4_dev(dev);
-
-- spin_lock(&vc4->bo_lock);
-+ mutex_lock(&vc4->bo_lock);
- while (!list_empty(&vc4->bo_cache.time_list)) {
- struct vc4_bo *bo = list_last_entry(&vc4->bo_cache.time_list,
- struct vc4_bo, unref_head);
- vc4_bo_remove_from_cache(bo);
- vc4_bo_destroy(bo);
- }
-- spin_unlock(&vc4->bo_lock);
-+ mutex_unlock(&vc4->bo_lock);
- }
-
- struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size)
-@@ -134,18 +134,18 @@ struct vc4_bo *vc4_bo_create(struct drm_
- return NULL;
-
- /* First, try to get a vc4_bo from the kernel BO cache. */
-- spin_lock(&vc4->bo_lock);
-+ mutex_lock(&vc4->bo_lock);
- if (page_index < vc4->bo_cache.size_list_size &&
- !list_empty(&vc4->bo_cache.size_list[page_index])) {
- struct vc4_bo *bo =
- list_first_entry(&vc4->bo_cache.size_list[page_index],
- struct vc4_bo, size_head);
- vc4_bo_remove_from_cache(bo);
-- spin_unlock(&vc4->bo_lock);
-+ mutex_unlock(&vc4->bo_lock);
- kref_init(&bo->base.base.refcount);
- return bo;
- }
-- spin_unlock(&vc4->bo_lock);
-+ mutex_unlock(&vc4->bo_lock);
-
- /* Otherwise, make a new BO. */
- for (pass = 0; ; pass++) {
-@@ -215,7 +215,7 @@ vc4_bo_cache_free_old(struct drm_device
- struct vc4_dev *vc4 = to_vc4_dev(dev);
- unsigned long expire_time = jiffies - msecs_to_jiffies(1000);
-
-- spin_lock(&vc4->bo_lock);
-+ mutex_lock(&vc4->bo_lock);
- while (!list_empty(&vc4->bo_cache.time_list)) {
- struct vc4_bo *bo = list_last_entry(&vc4->bo_cache.time_list,
- struct vc4_bo, unref_head);
-@@ -223,14 +223,14 @@ vc4_bo_cache_free_old(struct drm_device
- mod_timer(&vc4->bo_cache.time_timer,
- round_jiffies_up(jiffies +
- msecs_to_jiffies(1000)));
-- spin_unlock(&vc4->bo_lock);
-+ mutex_unlock(&vc4->bo_lock);
- return;
- }
-
- vc4_bo_remove_from_cache(bo);
- vc4_bo_destroy(bo);
- }
-- spin_unlock(&vc4->bo_lock);
-+ mutex_unlock(&vc4->bo_lock);
- }
-
- /* Called on the last userspace/kernel unreference of the BO. Returns
-@@ -248,21 +248,25 @@ void vc4_free_object(struct drm_gem_obje
- /* If the object references someone else's memory, we can't cache it.
- */
- if (gem_bo->import_attach) {
-+ mutex_lock(&vc4->bo_lock);
- vc4_bo_destroy(bo);
-+ mutex_unlock(&vc4->bo_lock);
- return;
- }
-
- /* Don't cache if it was publicly named. */
- if (gem_bo->name) {
-+ mutex_lock(&vc4->bo_lock);
- vc4_bo_destroy(bo);
-+ mutex_unlock(&vc4->bo_lock);
- return;
- }
-
-- spin_lock(&vc4->bo_lock);
-+ mutex_lock(&vc4->bo_lock);
- cache_list = vc4_get_cache_list_for_size(dev, gem_bo->size);
- if (!cache_list) {
- vc4_bo_destroy(bo);
-- spin_unlock(&vc4->bo_lock);
-+ mutex_unlock(&vc4->bo_lock);
- return;
- }
-
-@@ -278,7 +282,7 @@ void vc4_free_object(struct drm_gem_obje
-
- vc4->bo_stats.num_cached++;
- vc4->bo_stats.size_cached += gem_bo->size;
-- spin_unlock(&vc4->bo_lock);
-+ mutex_unlock(&vc4->bo_lock);
-
- vc4_bo_cache_free_old(dev);
- }
-@@ -465,7 +469,7 @@ void vc4_bo_cache_init(struct drm_device
- {
- struct vc4_dev *vc4 = to_vc4_dev(dev);
-
-- spin_lock_init(&vc4->bo_lock);
-+ mutex_init(&vc4->bo_lock);
-
- INIT_LIST_HEAD(&vc4->bo_cache.time_list);
-
-@@ -498,9 +502,9 @@ int vc4_bo_stats_debugfs(struct seq_file
- struct vc4_dev *vc4 = to_vc4_dev(dev);
- struct vc4_bo_stats stats;
-
-- spin_lock(&vc4->bo_lock);
-+ mutex_lock(&vc4->bo_lock);
- stats = vc4->bo_stats;
-- spin_unlock(&vc4->bo_lock);
-+ mutex_unlock(&vc4->bo_lock);
-
- seq_printf(m, "num bos allocated: %d\n", stats.num_allocated);
- seq_printf(m, "size bos allocated: %dkb\n", stats.size_allocated / 1024);
---- a/drivers/gpu/drm/vc4/vc4_drv.h
-+++ b/drivers/gpu/drm/vc4/vc4_drv.h
-@@ -49,7 +49,7 @@ struct vc4_dev {
- } bo_stats;
-
- /* Protects bo_cache and the BO stats. */
-- spinlock_t bo_lock;
-+ struct mutex bo_lock;
-
- /* Sequence number for the last job queued in job_list.
- * Starts at 0 (no jobs emitted).
diff --git a/target/linux/brcm2708/patches-4.4/0094-drm-vc4-Use-job_lock-to-protect-seqno_cb_list.patch b/target/linux/brcm2708/patches-4.4/0094-drm-vc4-Use-job_lock-to-protect-seqno_cb_list.patch
new file mode 100644
index 0000000000..d8e845f33b
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0094-drm-vc4-Use-job_lock-to-protect-seqno_cb_list.patch
@@ -0,0 +1,54 @@
+From e7530cfb655bb473d5c99e27bb44a15f1c921441 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 19 Oct 2015 08:32:24 -0700
+Subject: [PATCH 094/381] drm/vc4: Use job_lock to protect seqno_cb_list.
+
+We're (mostly) not supposed to be using struct_mutex in drivers these
+days.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_gem.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_gem.c
++++ b/drivers/gpu/drm/vc4/vc4_gem.c
+@@ -474,7 +474,6 @@ vc4_job_handle_completed(struct vc4_dev
+ vc4_complete_exec(exec);
+ spin_lock_irqsave(&vc4->job_lock, irqflags);
+ }
+- spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+
+ list_for_each_entry_safe(cb, cb_temp, &vc4->seqno_cb_list, work.entry) {
+ if (cb->seqno <= vc4->finished_seqno) {
+@@ -482,6 +481,8 @@ vc4_job_handle_completed(struct vc4_dev
+ schedule_work(&cb->work);
+ }
+ }
++
++ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+ }
+
+ static void vc4_seqno_cb_work(struct work_struct *work)
+@@ -496,18 +497,19 @@ int vc4_queue_seqno_cb(struct drm_device
+ {
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ int ret = 0;
++ unsigned long irqflags;
+
+ cb->func = func;
+ INIT_WORK(&cb->work, vc4_seqno_cb_work);
+
+- mutex_lock(&dev->struct_mutex);
++ spin_lock_irqsave(&vc4->job_lock, irqflags);
+ if (seqno > vc4->finished_seqno) {
+ cb->seqno = seqno;
+ list_add_tail(&cb->work.entry, &vc4->seqno_cb_list);
+ } else {
+ schedule_work(&cb->work);
+ }
+- mutex_unlock(&dev->struct_mutex);
++ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+
+ return ret;
+ }
diff --git a/target/linux/brcm2708/patches-4.4/0094-drm-vc4-bo-cache-locking-cleanup.patch b/target/linux/brcm2708/patches-4.4/0094-drm-vc4-bo-cache-locking-cleanup.patch
deleted file mode 100644
index bf61ac14cf..0000000000
--- a/target/linux/brcm2708/patches-4.4/0094-drm-vc4-bo-cache-locking-cleanup.patch
+++ /dev/null
@@ -1,92 +0,0 @@
-From eafd7a031a15fb0d51a86b89e42ccde4f23434b4 Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Mon, 19 Oct 2015 08:29:41 -0700
-Subject: [PATCH 094/170] drm/vc4: bo cache locking cleanup.
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
----
- drivers/gpu/drm/vc4/vc4_bo.c | 22 +++++++++-------------
- 1 file changed, 9 insertions(+), 13 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_bo.c
-+++ b/drivers/gpu/drm/vc4/vc4_bo.c
-@@ -215,7 +215,6 @@ vc4_bo_cache_free_old(struct drm_device
- struct vc4_dev *vc4 = to_vc4_dev(dev);
- unsigned long expire_time = jiffies - msecs_to_jiffies(1000);
-
-- mutex_lock(&vc4->bo_lock);
- while (!list_empty(&vc4->bo_cache.time_list)) {
- struct vc4_bo *bo = list_last_entry(&vc4->bo_cache.time_list,
- struct vc4_bo, unref_head);
-@@ -223,14 +222,12 @@ vc4_bo_cache_free_old(struct drm_device
- mod_timer(&vc4->bo_cache.time_timer,
- round_jiffies_up(jiffies +
- msecs_to_jiffies(1000)));
-- mutex_unlock(&vc4->bo_lock);
- return;
- }
-
- vc4_bo_remove_from_cache(bo);
- vc4_bo_destroy(bo);
- }
-- mutex_unlock(&vc4->bo_lock);
- }
-
- /* Called on the last userspace/kernel unreference of the BO. Returns
-@@ -245,29 +242,24 @@ void vc4_free_object(struct drm_gem_obje
- struct vc4_bo *bo = to_vc4_bo(gem_bo);
- struct list_head *cache_list;
-
-+ mutex_lock(&vc4->bo_lock);
- /* If the object references someone else's memory, we can't cache it.
- */
- if (gem_bo->import_attach) {
-- mutex_lock(&vc4->bo_lock);
- vc4_bo_destroy(bo);
-- mutex_unlock(&vc4->bo_lock);
-- return;
-+ goto out;
- }
-
- /* Don't cache if it was publicly named. */
- if (gem_bo->name) {
-- mutex_lock(&vc4->bo_lock);
- vc4_bo_destroy(bo);
-- mutex_unlock(&vc4->bo_lock);
-- return;
-+ goto out;
- }
-
-- mutex_lock(&vc4->bo_lock);
- cache_list = vc4_get_cache_list_for_size(dev, gem_bo->size);
- if (!cache_list) {
- vc4_bo_destroy(bo);
-- mutex_unlock(&vc4->bo_lock);
-- return;
-+ goto out;
- }
-
- if (bo->validated_shader) {
-@@ -282,9 +274,11 @@ void vc4_free_object(struct drm_gem_obje
-
- vc4->bo_stats.num_cached++;
- vc4->bo_stats.size_cached += gem_bo->size;
-- mutex_unlock(&vc4->bo_lock);
-
- vc4_bo_cache_free_old(dev);
-+
-+out:
-+ mutex_unlock(&vc4->bo_lock);
- }
-
- static void vc4_bo_cache_time_work(struct work_struct *work)
-@@ -293,7 +287,9 @@ static void vc4_bo_cache_time_work(struc
- container_of(work, struct vc4_dev, bo_cache.time_work);
- struct drm_device *dev = vc4->dev;
-
-+ mutex_lock(&vc4->bo_lock);
- vc4_bo_cache_free_old(dev);
-+ mutex_unlock(&vc4->bo_lock);
- }
-
- static void vc4_bo_cache_time_timer(unsigned long data)
diff --git a/target/linux/brcm2708/patches-4.4/0095-drm-vc4-Drop-struct_mutex-around-CL-validation.patch b/target/linux/brcm2708/patches-4.4/0095-drm-vc4-Drop-struct_mutex-around-CL-validation.patch
new file mode 100644
index 0000000000..efa4a395de
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0095-drm-vc4-Drop-struct_mutex-around-CL-validation.patch
@@ -0,0 +1,63 @@
+From e619bff96bd0dab8ecf1c8df64ce3d605784fa57 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 19 Oct 2015 08:44:35 -0700
+Subject: [PATCH 095/381] drm/vc4: Drop struct_mutex around CL validation.
+
+We were using it so that we could make sure that shader validation
+state didn't change while we were validating, but now shader
+validation state is immutable. The bcl/rcl generation doesn't do any
+other BO dereferencing, and seems to have no other global state
+dependency not covered by job_lock / bo_lock.
+
+Fixes a lock order reversal between mmap_sem and struct_mutex.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_gem.c | 12 ++++--------
+ 1 file changed, 4 insertions(+), 8 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_gem.c
++++ b/drivers/gpu/drm/vc4/vc4_gem.c
+@@ -244,13 +244,15 @@ static void
+ vc4_queue_submit(struct drm_device *dev, struct vc4_exec_info *exec)
+ {
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+- uint64_t seqno = ++vc4->emit_seqno;
++ uint64_t seqno;
+ unsigned long irqflags;
+
++ spin_lock_irqsave(&vc4->job_lock, irqflags);
++
++ seqno = ++vc4->emit_seqno;
+ exec->seqno = seqno;
+ vc4_update_bo_seqnos(exec, seqno);
+
+- spin_lock_irqsave(&vc4->job_lock, irqflags);
+ list_add_tail(&exec->head, &vc4->job_list);
+
+ /* If no job was executing, kick ours off. Otherwise, it'll
+@@ -608,8 +610,6 @@ vc4_submit_cl_ioctl(struct drm_device *d
+ exec->args = args;
+ INIT_LIST_HEAD(&exec->unref_list);
+
+- mutex_lock(&dev->struct_mutex);
+-
+ ret = vc4_cl_lookup_bos(dev, file_priv, exec);
+ if (ret)
+ goto fail;
+@@ -636,15 +636,11 @@ vc4_submit_cl_ioctl(struct drm_device *d
+ /* Return the seqno for our job. */
+ args->seqno = vc4->emit_seqno;
+
+- mutex_unlock(&dev->struct_mutex);
+-
+ return 0;
+
+ fail:
+ vc4_complete_exec(exec);
+
+- mutex_unlock(&dev->struct_mutex);
+-
+ return ret;
+ }
+
diff --git a/target/linux/brcm2708/patches-4.4/0095-drm-vc4-Use-job_lock-to-protect-seqno_cb_list.patch b/target/linux/brcm2708/patches-4.4/0095-drm-vc4-Use-job_lock-to-protect-seqno_cb_list.patch
deleted file mode 100644
index 730355aea6..0000000000
--- a/target/linux/brcm2708/patches-4.4/0095-drm-vc4-Use-job_lock-to-protect-seqno_cb_list.patch
+++ /dev/null
@@ -1,54 +0,0 @@
-From 482f2b3e97e919ac0ebc55a6040747495563b9a7 Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Mon, 19 Oct 2015 08:32:24 -0700
-Subject: [PATCH 095/170] drm/vc4: Use job_lock to protect seqno_cb_list.
-
-We're (mostly) not supposed to be using struct_mutex in drivers these
-days.
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
----
- drivers/gpu/drm/vc4/vc4_gem.c | 8 +++++---
- 1 file changed, 5 insertions(+), 3 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_gem.c
-+++ b/drivers/gpu/drm/vc4/vc4_gem.c
-@@ -474,7 +474,6 @@ vc4_job_handle_completed(struct vc4_dev
- vc4_complete_exec(exec);
- spin_lock_irqsave(&vc4->job_lock, irqflags);
- }
-- spin_unlock_irqrestore(&vc4->job_lock, irqflags);
-
- list_for_each_entry_safe(cb, cb_temp, &vc4->seqno_cb_list, work.entry) {
- if (cb->seqno <= vc4->finished_seqno) {
-@@ -482,6 +481,8 @@ vc4_job_handle_completed(struct vc4_dev
- schedule_work(&cb->work);
- }
- }
-+
-+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
- }
-
- static void vc4_seqno_cb_work(struct work_struct *work)
-@@ -496,18 +497,19 @@ int vc4_queue_seqno_cb(struct drm_device
- {
- struct vc4_dev *vc4 = to_vc4_dev(dev);
- int ret = 0;
-+ unsigned long irqflags;
-
- cb->func = func;
- INIT_WORK(&cb->work, vc4_seqno_cb_work);
-
-- mutex_lock(&dev->struct_mutex);
-+ spin_lock_irqsave(&vc4->job_lock, irqflags);
- if (seqno > vc4->finished_seqno) {
- cb->seqno = seqno;
- list_add_tail(&cb->work.entry, &vc4->seqno_cb_list);
- } else {
- schedule_work(&cb->work);
- }
-- mutex_unlock(&dev->struct_mutex);
-+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
-
- return ret;
- }
diff --git a/target/linux/brcm2708/patches-4.4/0096-drm-vc4-Drop-struct_mutex-around-CL-validation.patch b/target/linux/brcm2708/patches-4.4/0096-drm-vc4-Drop-struct_mutex-around-CL-validation.patch
index 75adab38d9..36843e1c3a 100644
--- a/target/linux/brcm2708/patches-4.4/0096-drm-vc4-Drop-struct_mutex-around-CL-validation.patch
+++ b/target/linux/brcm2708/patches-4.4/0096-drm-vc4-Drop-struct_mutex-around-CL-validation.patch
@@ -1,63 +1,74 @@
-From 4dc15a296586679d5b014011e44a093cf962123e Mon Sep 17 00:00:00 2001
+From 4b137e2962b14c62089f4368391fa1ed03cac391 Mon Sep 17 00:00:00 2001
From: Eric Anholt <eric@anholt.net>
Date: Mon, 19 Oct 2015 08:44:35 -0700
-Subject: [PATCH 096/170] drm/vc4: Drop struct_mutex around CL validation.
+Subject: [PATCH 096/381] drm/vc4: Drop struct_mutex around CL validation.
We were using it so that we could make sure that shader validation
state didn't change while we were validating, but now shader
validation state is immutable. The bcl/rcl generation doesn't do any
other BO dereferencing, and seems to have no other global state
-dependency not covered by job_lock / bo_lock.
+dependency not covered by job_lock / bo_lock. We only need to hold
+struct_mutex for object unreferencing.
Fixes a lock order reversal between mmap_sem and struct_mutex.
Signed-off-by: Eric Anholt <eric@anholt.net>
---
- drivers/gpu/drm/vc4/vc4_gem.c | 12 ++++--------
- 1 file changed, 4 insertions(+), 8 deletions(-)
+ drivers/gpu/drm/vc4/vc4_gem.c | 13 ++++++-------
+ 1 file changed, 6 insertions(+), 7 deletions(-)
--- a/drivers/gpu/drm/vc4/vc4_gem.c
+++ b/drivers/gpu/drm/vc4/vc4_gem.c
-@@ -244,13 +244,15 @@ static void
- vc4_queue_submit(struct drm_device *dev, struct vc4_exec_info *exec)
+@@ -439,10 +439,12 @@ fail:
+ }
+
+ static void
+-vc4_complete_exec(struct vc4_exec_info *exec)
++vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec)
{
- struct vc4_dev *vc4 = to_vc4_dev(dev);
-- uint64_t seqno = ++vc4->emit_seqno;
-+ uint64_t seqno;
- unsigned long irqflags;
+ unsigned i;
-+ spin_lock_irqsave(&vc4->job_lock, irqflags);
-+
-+ seqno = ++vc4->emit_seqno;
- exec->seqno = seqno;
- vc4_update_bo_seqnos(exec, seqno);
++ /* Need the struct lock for drm_gem_object_unreference(). */
++ mutex_lock(&dev->struct_mutex);
+ if (exec->bo) {
+ for (i = 0; i < exec->bo_count; i++)
+ drm_gem_object_unreference(&exec->bo[i].bo->base);
+@@ -455,6 +457,7 @@ vc4_complete_exec(struct vc4_exec_info *
+ list_del(&bo->unref_head);
+ drm_gem_object_unreference(&bo->base.base);
+ }
++ mutex_unlock(&dev->struct_mutex);
-- spin_lock_irqsave(&vc4->job_lock, irqflags);
- list_add_tail(&exec->head, &vc4->job_list);
+ kfree(exec);
+ }
+@@ -473,7 +476,7 @@ vc4_job_handle_completed(struct vc4_dev
+ list_del(&exec->head);
- /* If no job was executing, kick ours off. Otherwise, it'll
-@@ -608,8 +610,6 @@ vc4_submit_cl_ioctl(struct drm_device *d
- exec->args = args;
- INIT_LIST_HEAD(&exec->unref_list);
+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+- vc4_complete_exec(exec);
++ vc4_complete_exec(vc4->dev, exec);
+ spin_lock_irqsave(&vc4->job_lock, irqflags);
+ }
-- mutex_lock(&dev->struct_mutex);
--
- ret = vc4_cl_lookup_bos(dev, file_priv, exec);
- if (ret)
- goto fail;
-@@ -636,15 +636,11 @@ vc4_submit_cl_ioctl(struct drm_device *d
- /* Return the seqno for our job. */
- args->seqno = vc4->emit_seqno;
+@@ -525,12 +528,8 @@ vc4_job_done_work(struct work_struct *wo
+ {
+ struct vc4_dev *vc4 =
+ container_of(work, struct vc4_dev, job_done_work);
+- struct drm_device *dev = vc4->dev;
+- /* Need the struct lock for drm_gem_object_unreference(). */
+- mutex_lock(&dev->struct_mutex);
+ vc4_job_handle_completed(vc4);
- mutex_unlock(&dev->struct_mutex);
--
+ }
+
+ static int
+@@ -639,7 +638,7 @@ vc4_submit_cl_ioctl(struct drm_device *d
return 0;
fail:
- vc4_complete_exec(exec);
+- vc4_complete_exec(exec);
++ vc4_complete_exec(vc4->dev, exec);
-- mutex_unlock(&dev->struct_mutex);
--
return ret;
}
-
diff --git a/target/linux/brcm2708/patches-4.4/0097-drm-vc4-Add-support-for-more-display-plane-formats.patch b/target/linux/brcm2708/patches-4.4/0097-drm-vc4-Add-support-for-more-display-plane-formats.patch
new file mode 100644
index 0000000000..66d85596ef
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0097-drm-vc4-Add-support-for-more-display-plane-formats.patch
@@ -0,0 +1,35 @@
+From 7a94e7c745428eb542ebbfe6370ae138ad76be4c Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Tue, 20 Oct 2015 13:59:15 +0100
+Subject: [PATCH 097/381] drm/vc4: Add support for more display plane formats.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_plane.c | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_plane.c
++++ b/drivers/gpu/drm/vc4/vc4_plane.c
+@@ -59,6 +59,22 @@ static const struct hvs_format {
+ .drm = DRM_FORMAT_ARGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
+ .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = true,
+ },
++ {
++ .drm = DRM_FORMAT_RGB565, .hvs = HVS_PIXEL_FORMAT_RGB565,
++ .pixel_order = HVS_PIXEL_ORDER_XRGB, .has_alpha = false,
++ },
++ {
++ .drm = DRM_FORMAT_BGR565, .hvs = HVS_PIXEL_FORMAT_RGB565,
++ .pixel_order = HVS_PIXEL_ORDER_XBGR, .has_alpha = false,
++ },
++ {
++ .drm = DRM_FORMAT_ARGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551,
++ .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = true,
++ },
++ {
++ .drm = DRM_FORMAT_XRGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551,
++ .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = false,
++ },
+ };
+
+ static const struct hvs_format *vc4_get_hvs_format(u32 drm_format)
diff --git a/target/linux/brcm2708/patches-4.4/0097-drm-vc4-Drop-struct_mutex-around-CL-validation.patch b/target/linux/brcm2708/patches-4.4/0097-drm-vc4-Drop-struct_mutex-around-CL-validation.patch
deleted file mode 100644
index 064e1170ed..0000000000
--- a/target/linux/brcm2708/patches-4.4/0097-drm-vc4-Drop-struct_mutex-around-CL-validation.patch
+++ /dev/null
@@ -1,74 +0,0 @@
-From f1924e632d16f98eee1fe1be636249b8cee4ee6e Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Mon, 19 Oct 2015 08:44:35 -0700
-Subject: [PATCH 097/170] drm/vc4: Drop struct_mutex around CL validation.
-
-We were using it so that we could make sure that shader validation
-state didn't change while we were validating, but now shader
-validation state is immutable. The bcl/rcl generation doesn't do any
-other BO dereferencing, and seems to have no other global state
-dependency not covered by job_lock / bo_lock. We only need to hold
-struct_mutex for object unreferencing.
-
-Fixes a lock order reversal between mmap_sem and struct_mutex.
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
----
- drivers/gpu/drm/vc4/vc4_gem.c | 13 ++++++-------
- 1 file changed, 6 insertions(+), 7 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_gem.c
-+++ b/drivers/gpu/drm/vc4/vc4_gem.c
-@@ -439,10 +439,12 @@ fail:
- }
-
- static void
--vc4_complete_exec(struct vc4_exec_info *exec)
-+vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec)
- {
- unsigned i;
-
-+ /* Need the struct lock for drm_gem_object_unreference(). */
-+ mutex_lock(&dev->struct_mutex);
- if (exec->bo) {
- for (i = 0; i < exec->bo_count; i++)
- drm_gem_object_unreference(&exec->bo[i].bo->base);
-@@ -455,6 +457,7 @@ vc4_complete_exec(struct vc4_exec_info *
- list_del(&bo->unref_head);
- drm_gem_object_unreference(&bo->base.base);
- }
-+ mutex_unlock(&dev->struct_mutex);
-
- kfree(exec);
- }
-@@ -473,7 +476,7 @@ vc4_job_handle_completed(struct vc4_dev
- list_del(&exec->head);
-
- spin_unlock_irqrestore(&vc4->job_lock, irqflags);
-- vc4_complete_exec(exec);
-+ vc4_complete_exec(vc4->dev, exec);
- spin_lock_irqsave(&vc4->job_lock, irqflags);
- }
-
-@@ -525,12 +528,8 @@ vc4_job_done_work(struct work_struct *wo
- {
- struct vc4_dev *vc4 =
- container_of(work, struct vc4_dev, job_done_work);
-- struct drm_device *dev = vc4->dev;
-
-- /* Need the struct lock for drm_gem_object_unreference(). */
-- mutex_lock(&dev->struct_mutex);
- vc4_job_handle_completed(vc4);
-- mutex_unlock(&dev->struct_mutex);
- }
-
- static int
-@@ -639,7 +638,7 @@ vc4_submit_cl_ioctl(struct drm_device *d
- return 0;
-
- fail:
-- vc4_complete_exec(exec);
-+ vc4_complete_exec(vc4->dev, exec);
-
- return ret;
- }
diff --git a/target/linux/brcm2708/patches-4.4/0098-drm-vc4-Add-support-for-more-display-plane-formats.patch b/target/linux/brcm2708/patches-4.4/0098-drm-vc4-Add-support-for-more-display-plane-formats.patch
deleted file mode 100644
index 817271a4a6..0000000000
--- a/target/linux/brcm2708/patches-4.4/0098-drm-vc4-Add-support-for-more-display-plane-formats.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-From 0193a1e5b931c7363279282b4169c2152af1a621 Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Tue, 20 Oct 2015 13:59:15 +0100
-Subject: [PATCH 098/170] drm/vc4: Add support for more display plane formats.
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
----
- drivers/gpu/drm/vc4/vc4_plane.c | 16 ++++++++++++++++
- 1 file changed, 16 insertions(+)
-
---- a/drivers/gpu/drm/vc4/vc4_plane.c
-+++ b/drivers/gpu/drm/vc4/vc4_plane.c
-@@ -59,6 +59,22 @@ static const struct hvs_format {
- .drm = DRM_FORMAT_ARGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
- .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = true,
- },
-+ {
-+ .drm = DRM_FORMAT_RGB565, .hvs = HVS_PIXEL_FORMAT_RGB565,
-+ .pixel_order = HVS_PIXEL_ORDER_XRGB, .has_alpha = false,
-+ },
-+ {
-+ .drm = DRM_FORMAT_BGR565, .hvs = HVS_PIXEL_FORMAT_RGB565,
-+ .pixel_order = HVS_PIXEL_ORDER_XBGR, .has_alpha = false,
-+ },
-+ {
-+ .drm = DRM_FORMAT_ARGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551,
-+ .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = true,
-+ },
-+ {
-+ .drm = DRM_FORMAT_XRGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551,
-+ .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = false,
-+ },
- };
-
- static const struct hvs_format *vc4_get_hvs_format(u32 drm_format)
diff --git a/target/linux/brcm2708/patches-4.4/0098-drm-vc4-No-need-to-stop-the-stopped-threads.patch b/target/linux/brcm2708/patches-4.4/0098-drm-vc4-No-need-to-stop-the-stopped-threads.patch
new file mode 100644
index 0000000000..18e54c2965
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0098-drm-vc4-No-need-to-stop-the-stopped-threads.patch
@@ -0,0 +1,26 @@
+From c3634a10a0b792baedf12691a83598c89976830c Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Fri, 23 Oct 2015 12:31:56 +0100
+Subject: [PATCH 098/381] drm/vc4: No need to stop the stopped threads.
+
+This was leftover debug code from the hackdriver. We never submit
+unless the thread is already idle.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_gem.c | 4 ----
+ 1 file changed, 4 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_gem.c
++++ b/drivers/gpu/drm/vc4/vc4_gem.c
+@@ -104,10 +104,6 @@ submit_cl(struct drm_device *dev, uint32
+ {
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+
+- /* Stop any existing thread and set state to "stopped at halt" */
+- V3D_WRITE(V3D_CTNCS(thread), V3D_CTRUN);
+- barrier();
+-
+ V3D_WRITE(V3D_CTNCA(thread), start);
+ barrier();
+
diff --git a/target/linux/brcm2708/patches-4.4/0099-drm-vc4-No-need-to-stop-the-stopped-threads.patch b/target/linux/brcm2708/patches-4.4/0099-drm-vc4-No-need-to-stop-the-stopped-threads.patch
deleted file mode 100644
index 7265078cf0..0000000000
--- a/target/linux/brcm2708/patches-4.4/0099-drm-vc4-No-need-to-stop-the-stopped-threads.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-From 8faa3b83201819d56f997a2b2ecaf8c690080852 Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Fri, 23 Oct 2015 12:31:56 +0100
-Subject: [PATCH 099/170] drm/vc4: No need to stop the stopped threads.
-
-This was leftover debug code from the hackdriver. We never submit
-unless the thread is already idle.
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
----
- drivers/gpu/drm/vc4/vc4_gem.c | 4 ----
- 1 file changed, 4 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_gem.c
-+++ b/drivers/gpu/drm/vc4/vc4_gem.c
-@@ -104,10 +104,6 @@ submit_cl(struct drm_device *dev, uint32
- {
- struct vc4_dev *vc4 = to_vc4_dev(dev);
-
-- /* Stop any existing thread and set state to "stopped at halt" */
-- V3D_WRITE(V3D_CTNCS(thread), V3D_CTRUN);
-- barrier();
--
- V3D_WRITE(V3D_CTNCA(thread), start);
- barrier();
-
diff --git a/target/linux/brcm2708/patches-4.4/0099-drm-vc4-Remove-extra-barrier-s-aroudn-CTnCA-CTnEA-se.patch b/target/linux/brcm2708/patches-4.4/0099-drm-vc4-Remove-extra-barrier-s-aroudn-CTnCA-CTnEA-se.patch
new file mode 100644
index 0000000000..7563f33ee8
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0099-drm-vc4-Remove-extra-barrier-s-aroudn-CTnCA-CTnEA-se.patch
@@ -0,0 +1,33 @@
+From f57845691b2419259210ddc7c18fd54240199567 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Fri, 23 Oct 2015 12:33:43 +0100
+Subject: [PATCH 099/381] drm/vc4: Remove extra barrier()s aroudn CTnCA/CTnEA
+ setup.
+
+The writel() that these expand to already does barriers.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_gem.c | 9 +++------
+ 1 file changed, 3 insertions(+), 6 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_gem.c
++++ b/drivers/gpu/drm/vc4/vc4_gem.c
+@@ -104,14 +104,11 @@ submit_cl(struct drm_device *dev, uint32
+ {
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+
+- V3D_WRITE(V3D_CTNCA(thread), start);
+- barrier();
+-
+- /* Set the end address of the control list. Writing this
+- * register is what starts the job.
++ /* Set the current and end address of the control list.
++ * Writing the end register is what starts the job.
+ */
++ V3D_WRITE(V3D_CTNCA(thread), start);
+ V3D_WRITE(V3D_CTNEA(thread), end);
+- barrier();
+ }
+
+ int
diff --git a/target/linux/brcm2708/patches-4.4/0100-drm-vc4-Fix-a-typo-in-a-V3D-debug-register.patch b/target/linux/brcm2708/patches-4.4/0100-drm-vc4-Fix-a-typo-in-a-V3D-debug-register.patch
new file mode 100644
index 0000000000..7bcc65c888
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0100-drm-vc4-Fix-a-typo-in-a-V3D-debug-register.patch
@@ -0,0 +1,33 @@
+From b750beb58d214d6a5ed458eb5b2e7a304685a587 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Fri, 23 Oct 2015 14:57:22 +0100
+Subject: [PATCH 100/381] drm/vc4: Fix a typo in a V3D debug register.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_regs.h | 2 +-
+ drivers/gpu/drm/vc4/vc4_v3d.c | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_regs.h
++++ b/drivers/gpu/drm/vc4/vc4_regs.h
+@@ -154,7 +154,7 @@
+ #define V3D_PCTRS14 0x006f4
+ #define V3D_PCTR15 0x006f8
+ #define V3D_PCTRS15 0x006fc
+-#define V3D_BGE 0x00f00
++#define V3D_DBGE 0x00f00
+ #define V3D_FDBGO 0x00f04
+ #define V3D_FDBGB 0x00f08
+ #define V3D_FDBGR 0x00f0c
+--- a/drivers/gpu/drm/vc4/vc4_v3d.c
++++ b/drivers/gpu/drm/vc4/vc4_v3d.c
+@@ -99,7 +99,7 @@ static const struct {
+ REGDEF(V3D_PCTRS14),
+ REGDEF(V3D_PCTR15),
+ REGDEF(V3D_PCTRS15),
+- REGDEF(V3D_BGE),
++ REGDEF(V3D_DBGE),
+ REGDEF(V3D_FDBGO),
+ REGDEF(V3D_FDBGB),
+ REGDEF(V3D_FDBGR),
diff --git a/target/linux/brcm2708/patches-4.4/0100-drm-vc4-Remove-extra-barrier-s-aroudn-CTnCA-CTnEA-se.patch b/target/linux/brcm2708/patches-4.4/0100-drm-vc4-Remove-extra-barrier-s-aroudn-CTnCA-CTnEA-se.patch
deleted file mode 100644
index d727a1b8e5..0000000000
--- a/target/linux/brcm2708/patches-4.4/0100-drm-vc4-Remove-extra-barrier-s-aroudn-CTnCA-CTnEA-se.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-From d102d0e145b58bccbea52e89bbe52dcefc044aaa Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Fri, 23 Oct 2015 12:33:43 +0100
-Subject: [PATCH 100/170] drm/vc4: Remove extra barrier()s aroudn CTnCA/CTnEA
- setup.
-
-The writel() that these expand to already does barriers.
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
----
- drivers/gpu/drm/vc4/vc4_gem.c | 9 +++------
- 1 file changed, 3 insertions(+), 6 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_gem.c
-+++ b/drivers/gpu/drm/vc4/vc4_gem.c
-@@ -104,14 +104,11 @@ submit_cl(struct drm_device *dev, uint32
- {
- struct vc4_dev *vc4 = to_vc4_dev(dev);
-
-- V3D_WRITE(V3D_CTNCA(thread), start);
-- barrier();
--
-- /* Set the end address of the control list. Writing this
-- * register is what starts the job.
-+ /* Set the current and end address of the control list.
-+ * Writing the end register is what starts the job.
- */
-+ V3D_WRITE(V3D_CTNCA(thread), start);
- V3D_WRITE(V3D_CTNEA(thread), end);
-- barrier();
- }
-
- int
diff --git a/target/linux/brcm2708/patches-4.4/0101-drm-vc4-Enable-VC4-modules-and-increase-CMA-size-wit.patch b/target/linux/brcm2708/patches-4.4/0101-drm-vc4-Enable-VC4-modules-and-increase-CMA-size-wit.patch
new file mode 100644
index 0000000000..52b92eab18
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0101-drm-vc4-Enable-VC4-modules-and-increase-CMA-size-wit.patch
@@ -0,0 +1,153 @@
+From 932891dd324ddfc1f8dc2e064a3504f3e120f874 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 2 Nov 2015 17:07:33 +0000
+Subject: [PATCH 101/381] drm/vc4: Enable VC4 modules, and increase CMA size
+ with overlay
+
+If using the overlay, be careful not to boot to GUI or run startx,
+or the Pi will almost hang, reporting stalls in kernel threads.
+---
+ arch/arm/boot/dts/overlays/README | 8 ++
+ arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts | 95 ++++++++++++++++++++++
+ arch/arm/configs/bcm2709_defconfig | 2 +
+ arch/arm/configs/bcmrpi_defconfig | 2 +
+ 4 files changed, 107 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -601,6 +601,14 @@ Params: txd1_pin GPIO pi
+ rxd1_pin GPIO pin for RXD1 (15, 33 or 41 - default 15)
+
+
++Name: vc4-kms-v3d
++Info: Enable Eric Anholt's DRM VC4 HDMI/HVS/V3D driver. Running startx or
++ booting to GUI while this overlay is in use will cause interesting
++ lockups.
++Load: dtoverlay=vc4-kms-v3d
++Params: <None>
++
++
+ Name: vga666
+ Info: Overlay for the Fen Logic VGA666 board
+ This uses GPIOs 2-21 (so no I2C), and activates the output 2-3 seconds
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts
+@@ -0,0 +1,95 @@
++/*
++ * vc4-kms-v3d-overlay.dts
++ */
++
++/dts-v1/;
++/plugin/;
++
++#include "dt-bindings/clock/bcm2835.h"
++#include "dt-bindings/gpio/gpio.h"
++
++/ {
++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++
++ fragment@0 {
++ target = <&i2c2>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&cprman>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@2 {
++ target = <&fb>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@3 {
++ target = <&soc>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ pixelvalve@7e206000 {
++ compatible = "brcm,bcm2835-pixelvalve0";
++ reg = <0x7e206000 0x100>;
++ interrupts = <2 13>; /* pwa0 */
++ };
++
++ pixelvalve@7e207000 {
++ compatible = "brcm,bcm2835-pixelvalve1";
++ reg = <0x7e207000 0x100>;
++ interrupts = <2 14>; /* pwa1 */
++ };
++
++ hvs@7e400000 {
++ compatible = "brcm,bcm2835-hvs";
++ reg = <0x7e400000 0x6000>;
++ interrupts = <2 1>;
++ };
++
++ pixelvalve@7e807000 {
++ compatible = "brcm,bcm2835-pixelvalve2";
++ reg = <0x7e807000 0x100>;
++ interrupts = <2 10>; /* pixelvalve */
++ };
++
++ hdmi@7e902000 {
++ compatible = "brcm,bcm2835-hdmi";
++ reg = <0x7e902000 0x600>,
++ <0x7e808000 0x100>;
++ interrupts = <2 8>, <2 9>;
++ ddc = <&i2c2>;
++ hpd-gpio = <&gpio 46 GPIO_ACTIVE_HIGH>;
++ clocks = <&cprman BCM2835_PLLH_PIX>,
++ <&cprman BCM2835_CLOCK_HSM>;
++ clock-names = "pixel", "hdmi";
++ };
++
++ v3d@7ec00000 {
++ compatible = "brcm,vc4-v3d";
++ reg = <0x7ec00000 0x1000>;
++ interrupts = <1 10>;
++ };
++
++ gpu@7e4c0000 {
++ compatible = "brcm,bcm2835-vc4";
++ };
++ };
++ };
++
++ fragment@4 {
++ target-path = "/chosen";
++ __overlay__ {
++ bootargs = "cma=256M@512M";
++ };
++ };
++};
+--- a/arch/arm/configs/bcm2709_defconfig
++++ b/arch/arm/configs/bcm2709_defconfig
+@@ -802,6 +802,8 @@ CONFIG_VIDEO_TW9903=m
+ CONFIG_VIDEO_TW9906=m
+ CONFIG_VIDEO_OV7640=m
+ CONFIG_VIDEO_MT9V011=m
++CONFIG_DRM=m
++CONFIG_DRM_VC4=m
+ CONFIG_FB=y
+ CONFIG_FB_BCM2708=y
+ CONFIG_FB_UDL=m
+--- a/arch/arm/configs/bcmrpi_defconfig
++++ b/arch/arm/configs/bcmrpi_defconfig
+@@ -795,6 +795,8 @@ CONFIG_VIDEO_TW9903=m
+ CONFIG_VIDEO_TW9906=m
+ CONFIG_VIDEO_OV7640=m
+ CONFIG_VIDEO_MT9V011=m
++CONFIG_DRM=m
++CONFIG_DRM_VC4=m
+ CONFIG_FB=y
+ CONFIG_FB_BCM2708=y
+ CONFIG_FB_UDL=m
diff --git a/target/linux/brcm2708/patches-4.4/0101-drm-vc4-Fix-a-typo-in-a-V3D-debug-register.patch b/target/linux/brcm2708/patches-4.4/0101-drm-vc4-Fix-a-typo-in-a-V3D-debug-register.patch
deleted file mode 100644
index c920f40ba6..0000000000
--- a/target/linux/brcm2708/patches-4.4/0101-drm-vc4-Fix-a-typo-in-a-V3D-debug-register.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-From 0f099b4b1354b0377376b91ae60c6c16d82683a7 Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Fri, 23 Oct 2015 14:57:22 +0100
-Subject: [PATCH 101/170] drm/vc4: Fix a typo in a V3D debug register.
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
----
- drivers/gpu/drm/vc4/vc4_regs.h | 2 +-
- drivers/gpu/drm/vc4/vc4_v3d.c | 2 +-
- 2 files changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_regs.h
-+++ b/drivers/gpu/drm/vc4/vc4_regs.h
-@@ -154,7 +154,7 @@
- #define V3D_PCTRS14 0x006f4
- #define V3D_PCTR15 0x006f8
- #define V3D_PCTRS15 0x006fc
--#define V3D_BGE 0x00f00
-+#define V3D_DBGE 0x00f00
- #define V3D_FDBGO 0x00f04
- #define V3D_FDBGB 0x00f08
- #define V3D_FDBGR 0x00f0c
---- a/drivers/gpu/drm/vc4/vc4_v3d.c
-+++ b/drivers/gpu/drm/vc4/vc4_v3d.c
-@@ -99,7 +99,7 @@ static const struct {
- REGDEF(V3D_PCTRS14),
- REGDEF(V3D_PCTR15),
- REGDEF(V3D_PCTRS15),
-- REGDEF(V3D_BGE),
-+ REGDEF(V3D_DBGE),
- REGDEF(V3D_FDBGO),
- REGDEF(V3D_FDBGB),
- REGDEF(V3D_FDBGR),
diff --git a/target/linux/brcm2708/patches-4.4/0102-drm-vc4-Enable-VC4-modules-and-increase-CMA-size-wit.patch b/target/linux/brcm2708/patches-4.4/0102-drm-vc4-Enable-VC4-modules-and-increase-CMA-size-wit.patch
deleted file mode 100644
index 5531673c59..0000000000
--- a/target/linux/brcm2708/patches-4.4/0102-drm-vc4-Enable-VC4-modules-and-increase-CMA-size-wit.patch
+++ /dev/null
@@ -1,153 +0,0 @@
-From 22182768add611b53e33c5dd2e8901acc3d08181 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Mon, 2 Nov 2015 17:07:33 +0000
-Subject: [PATCH 102/170] drm/vc4: Enable VC4 modules, and increase CMA size
- with overlay
-
-If using the overlay, be careful not to boot to GUI or run startx,
-or the Pi will almost hang, reporting stalls in kernel threads.
----
- arch/arm/boot/dts/overlays/README | 8 ++
- arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts | 95 ++++++++++++++++++++++
- arch/arm/configs/bcm2709_defconfig | 2 +
- arch/arm/configs/bcmrpi_defconfig | 2 +
- 4 files changed, 107 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -601,6 +601,14 @@ Params: txd1_pin GPIO pi
- rxd1_pin GPIO pin for RXD1 (15, 33 or 41 - default 15)
-
-
-+Name: vc4-kms-v3d
-+Info: Enable Eric Anholt's DRM VC4 HDMI/HVS/V3D driver. Running startx or
-+ booting to GUI while this overlay is in use will cause interesting
-+ lockups.
-+Load: dtoverlay=vc4-kms-v3d
-+Params: <None>
-+
-+
- Name: vga666
- Info: Overlay for the Fen Logic VGA666 board
- This uses GPIOs 2-21 (so no I2C), and activates the output 2-3 seconds
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts
-@@ -0,0 +1,95 @@
-+/*
-+ * vc4-kms-v3d-overlay.dts
-+ */
-+
-+/dts-v1/;
-+/plugin/;
-+
-+#include "dt-bindings/clock/bcm2835.h"
-+#include "dt-bindings/gpio/gpio.h"
-+
-+/ {
-+ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+
-+ fragment@0 {
-+ target = <&i2c2>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&cprman>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&fb>;
-+ __overlay__ {
-+ status = "disabled";
-+ };
-+ };
-+
-+ fragment@3 {
-+ target = <&soc>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+
-+ pixelvalve@7e206000 {
-+ compatible = "brcm,bcm2835-pixelvalve0";
-+ reg = <0x7e206000 0x100>;
-+ interrupts = <2 13>; /* pwa0 */
-+ };
-+
-+ pixelvalve@7e207000 {
-+ compatible = "brcm,bcm2835-pixelvalve1";
-+ reg = <0x7e207000 0x100>;
-+ interrupts = <2 14>; /* pwa1 */
-+ };
-+
-+ hvs@7e400000 {
-+ compatible = "brcm,bcm2835-hvs";
-+ reg = <0x7e400000 0x6000>;
-+ interrupts = <2 1>;
-+ };
-+
-+ pixelvalve@7e807000 {
-+ compatible = "brcm,bcm2835-pixelvalve2";
-+ reg = <0x7e807000 0x100>;
-+ interrupts = <2 10>; /* pixelvalve */
-+ };
-+
-+ hdmi@7e902000 {
-+ compatible = "brcm,bcm2835-hdmi";
-+ reg = <0x7e902000 0x600>,
-+ <0x7e808000 0x100>;
-+ interrupts = <2 8>, <2 9>;
-+ ddc = <&i2c2>;
-+ hpd-gpio = <&gpio 46 GPIO_ACTIVE_HIGH>;
-+ clocks = <&cprman BCM2835_PLLH_PIX>,
-+ <&cprman BCM2835_CLOCK_HSM>;
-+ clock-names = "pixel", "hdmi";
-+ };
-+
-+ v3d@7ec00000 {
-+ compatible = "brcm,vc4-v3d";
-+ reg = <0x7ec00000 0x1000>;
-+ interrupts = <1 10>;
-+ };
-+
-+ gpu@7e4c0000 {
-+ compatible = "brcm,bcm2835-vc4";
-+ };
-+ };
-+ };
-+
-+ fragment@4 {
-+ target-path = "/chosen";
-+ __overlay__ {
-+ bootargs = "cma=256M@512M";
-+ };
-+ };
-+};
---- a/arch/arm/configs/bcm2709_defconfig
-+++ b/arch/arm/configs/bcm2709_defconfig
-@@ -802,6 +802,8 @@ CONFIG_VIDEO_TW9903=m
- CONFIG_VIDEO_TW9906=m
- CONFIG_VIDEO_OV7640=m
- CONFIG_VIDEO_MT9V011=m
-+CONFIG_DRM=m
-+CONFIG_DRM_VC4=m
- CONFIG_FB=y
- CONFIG_FB_BCM2708=y
- CONFIG_FB_UDL=m
---- a/arch/arm/configs/bcmrpi_defconfig
-+++ b/arch/arm/configs/bcmrpi_defconfig
-@@ -795,6 +795,8 @@ CONFIG_VIDEO_TW9903=m
- CONFIG_VIDEO_TW9906=m
- CONFIG_VIDEO_OV7640=m
- CONFIG_VIDEO_MT9V011=m
-+CONFIG_DRM=m
-+CONFIG_DRM_VC4=m
- CONFIG_FB=y
- CONFIG_FB_BCM2708=y
- CONFIG_FB_UDL=m
diff --git a/target/linux/brcm2708/patches-4.4/0102-squash-fixups.patch b/target/linux/brcm2708/patches-4.4/0102-squash-fixups.patch
new file mode 100644
index 0000000000..e081501c7a
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0102-squash-fixups.patch
@@ -0,0 +1,43 @@
+From bdbaa2432c1a111c5a2fd492bb1751e4a355b16d Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Wed, 18 Nov 2015 18:29:58 +0000
+Subject: [PATCH 102/381] squash: fixups
+
+---
+ drivers/gpu/drm/vc4/Kconfig | 2 +-
+ drivers/gpu/drm/vc4/vc4_drv.c | 2 +-
+ drivers/gpu/drm/vc4/vc4_kms.c | 2 +-
+ 3 files changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/Kconfig
++++ b/drivers/gpu/drm/vc4/Kconfig
+@@ -1,6 +1,6 @@
+ config DRM_VC4
+ tristate "Broadcom VC4 Graphics"
+- depends on ARCH_BCM2835 || COMPILE_TEST
++ depends on ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709 || COMPILE_TEST
+ depends on DRM && HAVE_DMA_ATTRS
+ select DRM_KMS_HELPER
+ select DRM_KMS_CMA_HELPER
+--- a/drivers/gpu/drm/vc4/vc4_drv.c
++++ b/drivers/gpu/drm/vc4/vc4_drv.c
+@@ -127,7 +127,7 @@ static struct drm_driver vc4_drm_driver
+ .num_ioctls = ARRAY_SIZE(vc4_drm_ioctls),
+ .fops = &vc4_drm_fops,
+
+- .gem_obj_size = sizeof(struct vc4_bo),
++ //.gem_obj_size = sizeof(struct vc4_bo),
+
+ .name = DRIVER_NAME,
+ .desc = DRIVER_DESC,
+--- a/drivers/gpu/drm/vc4/vc4_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_kms.c
+@@ -45,7 +45,7 @@ vc4_atomic_complete_commit(struct vc4_co
+
+ drm_atomic_helper_commit_modeset_disables(dev, state);
+
+- drm_atomic_helper_commit_planes(dev, state);
++ drm_atomic_helper_commit_planes(dev, state, false);
+
+ drm_atomic_helper_commit_modeset_enables(dev, state);
+
diff --git a/target/linux/brcm2708/patches-4.4/0103-squash-add-missing-vc4-kms-v3d-overlay.dtb-to-makefi.patch b/target/linux/brcm2708/patches-4.4/0103-squash-add-missing-vc4-kms-v3d-overlay.dtb-to-makefi.patch
new file mode 100644
index 0000000000..5684fa3c3a
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0103-squash-add-missing-vc4-kms-v3d-overlay.dtb-to-makefi.patch
@@ -0,0 +1,20 @@
+From b72cb75fa858d098d497ed5404b06f1603015ce9 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Wed, 18 Nov 2015 20:26:03 +0000
+Subject: [PATCH 103/381] squash: add missing vc4-kms-v3d-overlay.dtb to
+ makefile
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -52,6 +52,7 @@ dtb-$(RPI_DT_OVERLAYS) += smi-overlay.dt
+ dtb-$(RPI_DT_OVERLAYS) += spi-gpio35-39-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += tinylcd35-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += uart1-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += vc4-kms-v3d-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += vga666-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += w1-gpio-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += w1-gpio-pullup-overlay.dtb
diff --git a/target/linux/brcm2708/patches-4.4/0103-squash-fixups.patch b/target/linux/brcm2708/patches-4.4/0103-squash-fixups.patch
deleted file mode 100644
index 25c0137905..0000000000
--- a/target/linux/brcm2708/patches-4.4/0103-squash-fixups.patch
+++ /dev/null
@@ -1,43 +0,0 @@
-From 88315025318218ac04fcc66614083bb1a51f662f Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Wed, 18 Nov 2015 18:29:58 +0000
-Subject: [PATCH 103/170] squash: fixups
-
----
- drivers/gpu/drm/vc4/Kconfig | 2 +-
- drivers/gpu/drm/vc4/vc4_drv.c | 2 +-
- drivers/gpu/drm/vc4/vc4_kms.c | 2 +-
- 3 files changed, 3 insertions(+), 3 deletions(-)
-
---- a/drivers/gpu/drm/vc4/Kconfig
-+++ b/drivers/gpu/drm/vc4/Kconfig
-@@ -1,6 +1,6 @@
- config DRM_VC4
- tristate "Broadcom VC4 Graphics"
-- depends on ARCH_BCM2835 || COMPILE_TEST
-+ depends on ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709 || COMPILE_TEST
- depends on DRM && HAVE_DMA_ATTRS
- select DRM_KMS_HELPER
- select DRM_KMS_CMA_HELPER
---- a/drivers/gpu/drm/vc4/vc4_drv.c
-+++ b/drivers/gpu/drm/vc4/vc4_drv.c
-@@ -127,7 +127,7 @@ static struct drm_driver vc4_drm_driver
- .num_ioctls = ARRAY_SIZE(vc4_drm_ioctls),
- .fops = &vc4_drm_fops,
-
-- .gem_obj_size = sizeof(struct vc4_bo),
-+ //.gem_obj_size = sizeof(struct vc4_bo),
-
- .name = DRIVER_NAME,
- .desc = DRIVER_DESC,
---- a/drivers/gpu/drm/vc4/vc4_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_kms.c
-@@ -45,7 +45,7 @@ vc4_atomic_complete_commit(struct vc4_co
-
- drm_atomic_helper_commit_modeset_disables(dev, state);
-
-- drm_atomic_helper_commit_planes(dev, state);
-+ drm_atomic_helper_commit_planes(dev, state, false);
-
- drm_atomic_helper_commit_modeset_enables(dev, state);
-
diff --git a/target/linux/brcm2708/patches-4.4/0104-clk-bcm2835-Also-build-the-driver-for-downstream-ker.patch b/target/linux/brcm2708/patches-4.4/0104-clk-bcm2835-Also-build-the-driver-for-downstream-ker.patch
new file mode 100644
index 0000000000..f9afbeb808
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0104-clk-bcm2835-Also-build-the-driver-for-downstream-ker.patch
@@ -0,0 +1,22 @@
+From df922ac1dfc712933c25f68d31107d96cde7c549 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 12 Oct 2015 11:23:34 -0700
+Subject: [PATCH 104/381] clk: bcm2835: Also build the driver for downstream
+ kernels.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/clk/bcm/Makefile | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/clk/bcm/Makefile
++++ b/drivers/clk/bcm/Makefile
+@@ -3,7 +3,7 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-s
+ obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o
+ obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o
+ obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-asiu.o
+-obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o
++obj-$(CONFIG_ARCH_BCM2835)$(CONFIG_ARCH_BCM2708)$(CONFIG_ARCH_BCM2709) += clk-bcm2835.o
+ obj-$(CONFIG_COMMON_CLK_IPROC) += clk-ns2.o
+ obj-$(CONFIG_ARCH_BCM_CYGNUS) += clk-cygnus.o
+ obj-$(CONFIG_ARCH_BCM_NSP) += clk-nsp.o
diff --git a/target/linux/brcm2708/patches-4.4/0104-squash-add-missing-vc4-kms-v3d-overlay.dtb-to-makefi.patch b/target/linux/brcm2708/patches-4.4/0104-squash-add-missing-vc4-kms-v3d-overlay.dtb-to-makefi.patch
deleted file mode 100644
index 23d73e83d4..0000000000
--- a/target/linux/brcm2708/patches-4.4/0104-squash-add-missing-vc4-kms-v3d-overlay.dtb-to-makefi.patch
+++ /dev/null
@@ -1,20 +0,0 @@
-From 3fc233b798ac8498b4e24b42ad67fb3499a30f07 Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Wed, 18 Nov 2015 20:26:03 +0000
-Subject: [PATCH 104/170] squash: add missing vc4-kms-v3d-overlay.dtb to
- makefile
-
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -52,6 +52,7 @@ dtb-$(RPI_DT_OVERLAYS) += smi-overlay.dt
- dtb-$(RPI_DT_OVERLAYS) += spi-gpio35-39-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += tinylcd35-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += uart1-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += vc4-kms-v3d-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += vga666-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += w1-gpio-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += w1-gpio-pullup-overlay.dtb
diff --git a/target/linux/brcm2708/patches-4.4/0105-clk-bcm2835-Also-build-the-driver-for-downstream-ker.patch b/target/linux/brcm2708/patches-4.4/0105-clk-bcm2835-Also-build-the-driver-for-downstream-ker.patch
deleted file mode 100644
index f66e151e52..0000000000
--- a/target/linux/brcm2708/patches-4.4/0105-clk-bcm2835-Also-build-the-driver-for-downstream-ker.patch
+++ /dev/null
@@ -1,22 +0,0 @@
-From d9888c76bcee2a7c118ab8ba93a1204fb5ff4e44 Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Mon, 12 Oct 2015 11:23:34 -0700
-Subject: [PATCH 105/170] clk: bcm2835: Also build the driver for downstream
- kernels.
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
----
- drivers/clk/bcm/Makefile | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/clk/bcm/Makefile
-+++ b/drivers/clk/bcm/Makefile
-@@ -3,7 +3,7 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-s
- obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o
- obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o
- obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-asiu.o
--obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o
-+obj-$(CONFIG_ARCH_BCM2835)$(CONFIG_ARCH_BCM2708)$(CONFIG_ARCH_BCM2709) += clk-bcm2835.o
- obj-$(CONFIG_COMMON_CLK_IPROC) += clk-ns2.o
- obj-$(CONFIG_ARCH_BCM_CYGNUS) += clk-cygnus.o
- obj-$(CONFIG_ARCH_BCM_NSP) += clk-nsp.o
diff --git a/target/linux/brcm2708/patches-4.4/0105-dts-Added-overlay-for-gpio_ir_recv-driver.patch b/target/linux/brcm2708/patches-4.4/0105-dts-Added-overlay-for-gpio_ir_recv-driver.patch
new file mode 100644
index 0000000000..c5c24ad2e7
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0105-dts-Added-overlay-for-gpio_ir_recv-driver.patch
@@ -0,0 +1,104 @@
+From 95a5908e69f5b3040ee0eedb2a3aceac662464ae Mon Sep 17 00:00:00 2001
+From: Holger Steinhaus <hsteinhaus@gmx.de>
+Date: Sat, 14 Nov 2015 18:37:43 +0100
+Subject: [PATCH 105/381] dts: Added overlay for gpio_ir_recv driver
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 18 ++++++++++-
+ arch/arm/boot/dts/overlays/gpio-ir-overlay.dts | 45 ++++++++++++++++++++++++++
+ 3 files changed, 63 insertions(+), 1 deletion(-)
+ create mode 100644 arch/arm/boot/dts/overlays/gpio-ir-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -16,6 +16,7 @@ dtb-$(RPI_DT_OVERLAYS) += ads7846-overla
+ dtb-$(RPI_DT_OVERLAYS) += bmp085_i2c-sensor-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += dht11-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += enc28j60-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += gpio-ir-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += gpio-poweroff-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += hifiberry-amp-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += hifiberry-dac-overlay.dtb
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -196,6 +196,22 @@ Params: int_pin GPIO us
+ speed SPI bus speed (default 12000000)
+
+
++Name: gpio-ir
++Info: Use GPIO pin as rc-core style infrared receiver input. The rc-core-
++ based gpio_ir_recv driver maps received keys directly to a
++ /dev/input/event* device, all decoding is done by the kernel - LIRC is
++ not required! The key mapping and other decoding parameters can be
++ configured by "ir-keytable" tool.
++Load: dtoverlay=gpio-ir,<param>=<val>
++Params: gpio_pin Input pin number. Default is 18.
++
++ gpio_pull Desired pull-up/down state (off, down, up)
++ Default is "down".
++
++ rc-map-name Default rc keymap (can also be changed by
++ ir-keytable), defaults to "rc-rc6-mce"
++
++
+ Name: gpio-poweroff
+ Info: Drives a GPIO high or low on reboot
+ Load: dtoverlay=gpio-poweroff,<param>=<val>
+@@ -308,7 +324,7 @@ Params: <None>
+ Name: lirc-rpi
+ Info: Configures lirc-rpi (Linux Infrared Remote Control for Raspberry Pi)
+ Consult the module documentation for more details.
+-Load: dtoverlay=lirc-rpi,<param>=<val>,...
++Load: dtoverlay=lirc-rpi,<param>=<val>
+ Params: gpio_out_pin GPIO for output (default "17")
+
+ gpio_in_pin GPIO for input (default "18")
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/gpio-ir-overlay.dts
+@@ -0,0 +1,45 @@
++// Definitions for ir-gpio module
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target-path = "/";
++ __overlay__ {
++ gpio_ir: ir-receiver {
++ compatible = "gpio-ir-receiver";
++
++ // pin number, high or low
++ gpios = <&gpio 18 1>;
++
++ // parameter for keymap name
++ linux,rc-map-name = "rc-rc6-mce";
++
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ gpio_ir_pins: gpio_ir_pins {
++ brcm,pins = <18>; // pin 18
++ brcm,function = <0>; // in
++ brcm,pull = <1>; // down
++ };
++ };
++ };
++
++ __overrides__ {
++ // parameters
++ gpio_pin = <&gpio_ir>,"gpios:4",
++ <&gpio_ir_pins>,"brcm,pins:0",
++ <&gpio_ir_pins>,"brcm,pull:0"; // pin number
++ gpio_pull = <&gpio_ir_pins>,"brcm,pull:0"; // pull-up/down state
++
++ rc-map-name = <&gpio_ir>,"linux,rc-map-name"; // default rc map
++ };
++};
diff --git a/target/linux/brcm2708/patches-4.4/0106-Build-i2c_gpio-module-and-add-a-device-tree-overlay-.patch b/target/linux/brcm2708/patches-4.4/0106-Build-i2c_gpio-module-and-add-a-device-tree-overlay-.patch
new file mode 100644
index 0000000000..2afb0cdcd7
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0106-Build-i2c_gpio-module-and-add-a-device-tree-overlay-.patch
@@ -0,0 +1,100 @@
+From 75803fb0ecf8fcb8e2803feb8ee4b8e3d274c835 Mon Sep 17 00:00:00 2001
+From: Alistair Buxton <a.j.buxton@gmail.com>
+Date: Sun, 1 Nov 2015 22:27:56 +0000
+Subject: [PATCH 106/381] Build i2c_gpio module and add a device tree overlay
+ to configure it.
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 13 +++++++++++-
+ arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts | 28 +++++++++++++++++++++++++
+ arch/arm/configs/bcm2709_defconfig | 1 +
+ arch/arm/configs/bcmrpi_defconfig | 1 +
+ 5 files changed, 43 insertions(+), 1 deletion(-)
+ create mode 100644 arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -25,6 +25,7 @@ dtb-$(RPI_DT_OVERLAYS) += hifiberry-digi
+ dtb-$(RPI_DT_OVERLAYS) += hy28a-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += hy28b-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += i2c-rtc-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += i2c-gpio-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += i2s-mmap-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += iqaudio-dac-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += iqaudio-dacplus-overlay.dtb
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -287,9 +287,20 @@ Params: speed Display
+ ledgpio GPIO used to control backlight
+
+
++Name: i2c-gpio
++Info: Adds support for software i2c controller on gpio pins
++Load: dtoverlay=i2c-gpio,<param>=<val>
++Params: i2c_gpio_sda GPIO used for I2C data (default "23")
++
++ i2c_gpio_scl GPIO used for I2C clock (default "24")
++
++ i2c_gpio_delay_us Clock delay in microseconds
++ (default "2" = ~100kHz)
++
++
+ Name: i2c-rtc
+ Info: Adds support for a number of I2C Real Time Clock devices
+-Load: dtoverlay=i2c-rtc,<param>
++Load: dtoverlay=i2c-rtc,<param>=<val>
+ Params: ds1307 Select the DS1307 device
+
+ ds3231 Select the DS3231 device
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts
+@@ -0,0 +1,28 @@
++// Overlay for i2c_gpio bitbanging host bus.
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target-path = "/";
++ __overlay__ {
++ i2c_gpio: i2c@0 {
++ compatible = "i2c-gpio";
++ gpios = <&gpio 23 0 /* sda */
++ &gpio 24 0 /* scl */
++ >;
++ i2c-gpio,delay-us = <2>; /* ~100 kHz */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++ };
++ };
++ __overrides__ {
++ i2c_gpio_sda = <&i2c_gpio>,"gpios:4";
++ i2c_gpio_scl = <&i2c_gpio>,"gpios:16";
++ i2c_gpio_delay_us = <&i2c_gpio>,"i2c-gpio,delay-us:0";
++ };
++};
++
+--- a/arch/arm/configs/bcm2709_defconfig
++++ b/arch/arm/configs/bcm2709_defconfig
+@@ -595,6 +595,7 @@ CONFIG_RAW_DRIVER=y
+ CONFIG_I2C=y
+ CONFIG_I2C_CHARDEV=m
+ CONFIG_I2C_BCM2708=m
++CONFIG_I2C_GPIO=m
+ CONFIG_SPI=y
+ CONFIG_SPI_BCM2835=m
+ CONFIG_SPI_SPIDEV=y
+--- a/arch/arm/configs/bcmrpi_defconfig
++++ b/arch/arm/configs/bcmrpi_defconfig
+@@ -588,6 +588,7 @@ CONFIG_RAW_DRIVER=y
+ CONFIG_I2C=y
+ CONFIG_I2C_CHARDEV=m
+ CONFIG_I2C_BCM2708=m
++CONFIG_I2C_GPIO=m
+ CONFIG_SPI=y
+ CONFIG_SPI_BCM2835=m
+ CONFIG_SPI_SPIDEV=y
diff --git a/target/linux/brcm2708/patches-4.4/0106-dts-Added-overlay-for-gpio_ir_recv-driver.patch b/target/linux/brcm2708/patches-4.4/0106-dts-Added-overlay-for-gpio_ir_recv-driver.patch
deleted file mode 100644
index 54fb05dd02..0000000000
--- a/target/linux/brcm2708/patches-4.4/0106-dts-Added-overlay-for-gpio_ir_recv-driver.patch
+++ /dev/null
@@ -1,104 +0,0 @@
-From 0dbc0fe760a54bbcff587657062df49dc0eaf2b9 Mon Sep 17 00:00:00 2001
-From: Holger Steinhaus <hsteinhaus@gmx.de>
-Date: Sat, 14 Nov 2015 18:37:43 +0100
-Subject: [PATCH 106/170] dts: Added overlay for gpio_ir_recv driver
-
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 18 ++++++++++-
- arch/arm/boot/dts/overlays/gpio-ir-overlay.dts | 45 ++++++++++++++++++++++++++
- 3 files changed, 63 insertions(+), 1 deletion(-)
- create mode 100644 arch/arm/boot/dts/overlays/gpio-ir-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -16,6 +16,7 @@ dtb-$(RPI_DT_OVERLAYS) += ads7846-overla
- dtb-$(RPI_DT_OVERLAYS) += bmp085_i2c-sensor-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += dht11-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += enc28j60-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += gpio-ir-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += gpio-poweroff-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += hifiberry-amp-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += hifiberry-dac-overlay.dtb
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -196,6 +196,22 @@ Params: int_pin GPIO us
- speed SPI bus speed (default 12000000)
-
-
-+Name: gpio-ir
-+Info: Use GPIO pin as rc-core style infrared receiver input. The rc-core-
-+ based gpio_ir_recv driver maps received keys directly to a
-+ /dev/input/event* device, all decoding is done by the kernel - LIRC is
-+ not required! The key mapping and other decoding parameters can be
-+ configured by "ir-keytable" tool.
-+Load: dtoverlay=gpio-ir,<param>=<val>
-+Params: gpio_pin Input pin number. Default is 18.
-+
-+ gpio_pull Desired pull-up/down state (off, down, up)
-+ Default is "down".
-+
-+ rc-map-name Default rc keymap (can also be changed by
-+ ir-keytable), defaults to "rc-rc6-mce"
-+
-+
- Name: gpio-poweroff
- Info: Drives a GPIO high or low on reboot
- Load: dtoverlay=gpio-poweroff,<param>=<val>
-@@ -308,7 +324,7 @@ Params: <None>
- Name: lirc-rpi
- Info: Configures lirc-rpi (Linux Infrared Remote Control for Raspberry Pi)
- Consult the module documentation for more details.
--Load: dtoverlay=lirc-rpi,<param>=<val>,...
-+Load: dtoverlay=lirc-rpi,<param>=<val>
- Params: gpio_out_pin GPIO for output (default "17")
-
- gpio_in_pin GPIO for input (default "18")
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/gpio-ir-overlay.dts
-@@ -0,0 +1,45 @@
-+// Definitions for ir-gpio module
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target-path = "/";
-+ __overlay__ {
-+ gpio_ir: ir-receiver {
-+ compatible = "gpio-ir-receiver";
-+
-+ // pin number, high or low
-+ gpios = <&gpio 18 1>;
-+
-+ // parameter for keymap name
-+ linux,rc-map-name = "rc-rc6-mce";
-+
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ gpio_ir_pins: gpio_ir_pins {
-+ brcm,pins = <18>; // pin 18
-+ brcm,function = <0>; // in
-+ brcm,pull = <1>; // down
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ // parameters
-+ gpio_pin = <&gpio_ir>,"gpios:4",
-+ <&gpio_ir_pins>,"brcm,pins:0",
-+ <&gpio_ir_pins>,"brcm,pull:0"; // pin number
-+ gpio_pull = <&gpio_ir_pins>,"brcm,pull:0"; // pull-up/down state
-+
-+ rc-map-name = <&gpio_ir>,"linux,rc-map-name"; // default rc map
-+ };
-+};
diff --git a/target/linux/brcm2708/patches-4.4/0107-Build-i2c_gpio-module-and-add-a-device-tree-overlay-.patch b/target/linux/brcm2708/patches-4.4/0107-Build-i2c_gpio-module-and-add-a-device-tree-overlay-.patch
deleted file mode 100644
index 3654797e66..0000000000
--- a/target/linux/brcm2708/patches-4.4/0107-Build-i2c_gpio-module-and-add-a-device-tree-overlay-.patch
+++ /dev/null
@@ -1,100 +0,0 @@
-From 938b09ce6c6736d0861c2c9eec3a7e739585b589 Mon Sep 17 00:00:00 2001
-From: Alistair Buxton <a.j.buxton@gmail.com>
-Date: Sun, 1 Nov 2015 22:27:56 +0000
-Subject: [PATCH 107/170] Build i2c_gpio module and add a device tree overlay
- to configure it.
-
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 13 +++++++++++-
- arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts | 28 +++++++++++++++++++++++++
- arch/arm/configs/bcm2709_defconfig | 1 +
- arch/arm/configs/bcmrpi_defconfig | 1 +
- 5 files changed, 43 insertions(+), 1 deletion(-)
- create mode 100644 arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -25,6 +25,7 @@ dtb-$(RPI_DT_OVERLAYS) += hifiberry-digi
- dtb-$(RPI_DT_OVERLAYS) += hy28a-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += hy28b-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += i2c-rtc-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += i2c-gpio-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += i2s-mmap-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += iqaudio-dac-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += iqaudio-dacplus-overlay.dtb
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -287,9 +287,20 @@ Params: speed Display
- ledgpio GPIO used to control backlight
-
-
-+Name: i2c-gpio
-+Info: Adds support for software i2c controller on gpio pins
-+Load: dtoverlay=i2c-gpio,<param>=<val>
-+Params: i2c_gpio_sda GPIO used for I2C data (default "23")
-+
-+ i2c_gpio_scl GPIO used for I2C clock (default "24")
-+
-+ i2c_gpio_delay_us Clock delay in microseconds
-+ (default "2" = ~100kHz)
-+
-+
- Name: i2c-rtc
- Info: Adds support for a number of I2C Real Time Clock devices
--Load: dtoverlay=i2c-rtc,<param>
-+Load: dtoverlay=i2c-rtc,<param>=<val>
- Params: ds1307 Select the DS1307 device
-
- ds3231 Select the DS3231 device
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts
-@@ -0,0 +1,28 @@
-+// Overlay for i2c_gpio bitbanging host bus.
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target-path = "/";
-+ __overlay__ {
-+ i2c_gpio: i2c@0 {
-+ compatible = "i2c-gpio";
-+ gpios = <&gpio 23 0 /* sda */
-+ &gpio 24 0 /* scl */
-+ >;
-+ i2c-gpio,delay-us = <2>; /* ~100 kHz */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ };
-+ };
-+ };
-+ __overrides__ {
-+ i2c_gpio_sda = <&i2c_gpio>,"gpios:4";
-+ i2c_gpio_scl = <&i2c_gpio>,"gpios:16";
-+ i2c_gpio_delay_us = <&i2c_gpio>,"i2c-gpio,delay-us:0";
-+ };
-+};
-+
---- a/arch/arm/configs/bcm2709_defconfig
-+++ b/arch/arm/configs/bcm2709_defconfig
-@@ -595,6 +595,7 @@ CONFIG_RAW_DRIVER=y
- CONFIG_I2C=y
- CONFIG_I2C_CHARDEV=m
- CONFIG_I2C_BCM2708=m
-+CONFIG_I2C_GPIO=m
- CONFIG_SPI=y
- CONFIG_SPI_BCM2835=m
- CONFIG_SPI_SPIDEV=y
---- a/arch/arm/configs/bcmrpi_defconfig
-+++ b/arch/arm/configs/bcmrpi_defconfig
-@@ -588,6 +588,7 @@ CONFIG_RAW_DRIVER=y
- CONFIG_I2C=y
- CONFIG_I2C_CHARDEV=m
- CONFIG_I2C_BCM2708=m
-+CONFIG_I2C_GPIO=m
- CONFIG_SPI=y
- CONFIG_SPI_BCM2835=m
- CONFIG_SPI_SPIDEV=y
diff --git a/target/linux/brcm2708/patches-4.4/0107-New-overlay-for-PiScreen2r.patch b/target/linux/brcm2708/patches-4.4/0107-New-overlay-for-PiScreen2r.patch
new file mode 100644
index 0000000000..0334aec78b
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0107-New-overlay-for-PiScreen2r.patch
@@ -0,0 +1,148 @@
+From 2f5387400fcd2aff2120e945dc0b8050c5ae5dbf Mon Sep 17 00:00:00 2001
+From: mwilliams03 <mark.mwilliams@gmail.com>
+Date: Sun, 18 Oct 2015 17:07:24 -0700
+Subject: [PATCH 107/381] New overlay for PiScreen2r
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 14 +++
+ arch/arm/boot/dts/overlays/piscreen2r-overlay.dts | 100 ++++++++++++++++++++++
+ 3 files changed, 115 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/piscreen2r-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -35,6 +35,7 @@ dtb-$(RPI_DT_OVERLAYS) += mcp2515-can1-o
+ dtb-$(RPI_DT_OVERLAYS) += mmc-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += mz61581-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += piscreen-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += piscreen2r-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += pitft28-resistive-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += pps-gpio-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += pwm-overlay.dtb
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -425,6 +425,20 @@ Params: speed Display
+ xohms Touchpanel sensitivity (X-plate resistance)
+
+
++Name: piscreen2r
++Info: PiScreen 2 with resistive TP display by OzzMaker.com
++Load: dtoverlay=piscreen2r,<param>=<val>
++Params: speed Display SPI bus speed
++
++ rotate Display rotation {0,90,180,270}
++
++ fps Delay between frame updates
++
++ debug Debug output level {0-7}
++
++ xohms Touchpanel sensitivity (X-plate resistance)
++
++
+ Name: pitft28-resistive
+ Info: Adafruit PiTFT 2.8" resistive touch screen
+ Load: dtoverlay=pitft28-resistive,<param>=<val>
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/piscreen2r-overlay.dts
+@@ -0,0 +1,100 @@
++ /*
++ * Device Tree overlay for PiScreen2 3.5" TFT with resistive touch by Ozzmaker.com
++ *
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++
++ fragment@0 {
++ target = <&spi0>;
++ __overlay__ {
++ status = "okay";
++
++ spidev@0{
++ status = "disabled";
++ };
++
++ spidev@1{
++ status = "disabled";
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ piscreen2_pins: piscreen2_pins {
++ brcm,pins = <17 25 24 22>;
++ brcm,function = <0 1 1 1>; /* in out out out */
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&spi0>;
++ __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ piscreen2: piscreen2@0{
++ compatible = "ilitek,ili9486";
++ reg = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&piscreen2_pins>;
++ bgr;
++ spi-max-frequency = <64000000>;
++ rotate = <90>;
++ fps = <30>;
++ buswidth = <8>;
++ regwidth = <16>;
++ txbuflen = <32768>;
++ reset-gpios = <&gpio 25 0>;
++ dc-gpios = <&gpio 24 0>;
++ led-gpios = <&gpio 22 1>;
++ debug = <0>;
++
++ init = <0x10000b0 0x00
++ 0x1000011
++ 0x20000ff
++ 0x100003a 0x55
++ 0x1000036 0x28
++ 0x10000c0 0x11 0x09
++ 0x10000c1 0x41
++ 0x10000c5 0x00 0x00 0x00 0x00
++ 0x10000b6 0x00 0x02
++ 0x10000f7 0xa9 0x51 0x2c 0x2
++ 0x10000be 0x00 0x04
++ 0x10000e9 0x00
++ 0x1000011
++ 0x1000029>;
++
++ };
++
++ piscreen2_ts: piscreen2-ts@1 {
++ compatible = "ti,ads7846";
++ reg = <1>;
++
++ spi-max-frequency = <2000000>;
++ interrupts = <17 2>; /* high-to-low edge triggered */
++ interrupt-parent = <&gpio>;
++ pendown-gpio = <&gpio 17 0>;
++ ti,swap-xy;
++ ti,x-plate-ohms = /bits/ 16 <100>;
++ ti,pressure-max = /bits/ 16 <255>;
++ };
++ };
++ };
++ __overrides__ {
++ speed = <&piscreen2>,"spi-max-frequency:0";
++ rotate = <&piscreen2>,"rotate:0";
++ fps = <&piscreen2>,"fps:0";
++ debug = <&piscreen2>,"debug:0";
++ xohms = <&piscreen2_ts>,"ti,x-plate-ohms;0";
++ };
++};
++
diff --git a/target/linux/brcm2708/patches-4.4/0108-New-overlay-for-PiScreen2r.patch b/target/linux/brcm2708/patches-4.4/0108-New-overlay-for-PiScreen2r.patch
deleted file mode 100644
index f56543ea77..0000000000
--- a/target/linux/brcm2708/patches-4.4/0108-New-overlay-for-PiScreen2r.patch
+++ /dev/null
@@ -1,148 +0,0 @@
-From a4b5aa412585674d4a4f2ba7c0d818fd796f51c3 Mon Sep 17 00:00:00 2001
-From: mwilliams03 <mark.mwilliams@gmail.com>
-Date: Sun, 18 Oct 2015 17:07:24 -0700
-Subject: [PATCH 108/170] New overlay for PiScreen2r
-
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 14 +++
- arch/arm/boot/dts/overlays/piscreen2r-overlay.dts | 100 ++++++++++++++++++++++
- 3 files changed, 115 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/piscreen2r-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -35,6 +35,7 @@ dtb-$(RPI_DT_OVERLAYS) += mcp2515-can1-o
- dtb-$(RPI_DT_OVERLAYS) += mmc-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += mz61581-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += piscreen-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += piscreen2r-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += pitft28-resistive-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += pps-gpio-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += pwm-overlay.dtb
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -425,6 +425,20 @@ Params: speed Display
- xohms Touchpanel sensitivity (X-plate resistance)
-
-
-+Name: piscreen2r
-+Info: PiScreen 2 with resistive TP display by OzzMaker.com
-+Load: dtoverlay=piscreen2r,<param>=<val>
-+Params: speed Display SPI bus speed
-+
-+ rotate Display rotation {0,90,180,270}
-+
-+ fps Delay between frame updates
-+
-+ debug Debug output level {0-7}
-+
-+ xohms Touchpanel sensitivity (X-plate resistance)
-+
-+
- Name: pitft28-resistive
- Info: Adafruit PiTFT 2.8" resistive touch screen
- Load: dtoverlay=pitft28-resistive,<param>=<val>
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/piscreen2r-overlay.dts
-@@ -0,0 +1,100 @@
-+ /*
-+ * Device Tree overlay for PiScreen2 3.5" TFT with resistive touch by Ozzmaker.com
-+ *
-+ */
-+
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+
-+ fragment@0 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ status = "okay";
-+
-+ spidev@0{
-+ status = "disabled";
-+ };
-+
-+ spidev@1{
-+ status = "disabled";
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ piscreen2_pins: piscreen2_pins {
-+ brcm,pins = <17 25 24 22>;
-+ brcm,function = <0 1 1 1>; /* in out out out */
-+ };
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ piscreen2: piscreen2@0{
-+ compatible = "ilitek,ili9486";
-+ reg = <0>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&piscreen2_pins>;
-+ bgr;
-+ spi-max-frequency = <64000000>;
-+ rotate = <90>;
-+ fps = <30>;
-+ buswidth = <8>;
-+ regwidth = <16>;
-+ txbuflen = <32768>;
-+ reset-gpios = <&gpio 25 0>;
-+ dc-gpios = <&gpio 24 0>;
-+ led-gpios = <&gpio 22 1>;
-+ debug = <0>;
-+
-+ init = <0x10000b0 0x00
-+ 0x1000011
-+ 0x20000ff
-+ 0x100003a 0x55
-+ 0x1000036 0x28
-+ 0x10000c0 0x11 0x09
-+ 0x10000c1 0x41
-+ 0x10000c5 0x00 0x00 0x00 0x00
-+ 0x10000b6 0x00 0x02
-+ 0x10000f7 0xa9 0x51 0x2c 0x2
-+ 0x10000be 0x00 0x04
-+ 0x10000e9 0x00
-+ 0x1000011
-+ 0x1000029>;
-+
-+ };
-+
-+ piscreen2_ts: piscreen2-ts@1 {
-+ compatible = "ti,ads7846";
-+ reg = <1>;
-+
-+ spi-max-frequency = <2000000>;
-+ interrupts = <17 2>; /* high-to-low edge triggered */
-+ interrupt-parent = <&gpio>;
-+ pendown-gpio = <&gpio 17 0>;
-+ ti,swap-xy;
-+ ti,x-plate-ohms = /bits/ 16 <100>;
-+ ti,pressure-max = /bits/ 16 <255>;
-+ };
-+ };
-+ };
-+ __overrides__ {
-+ speed = <&piscreen2>,"spi-max-frequency:0";
-+ rotate = <&piscreen2>,"rotate:0";
-+ fps = <&piscreen2>,"fps:0";
-+ debug = <&piscreen2>,"debug:0";
-+ xohms = <&piscreen2_ts>,"ti,x-plate-ohms;0";
-+ };
-+};
-+
diff --git a/target/linux/brcm2708/patches-4.4/0108-dts-Added-overlay-for-Adafruit-PiTFT-2.8-capacitive-.patch b/target/linux/brcm2708/patches-4.4/0108-dts-Added-overlay-for-Adafruit-PiTFT-2.8-capacitive-.patch
new file mode 100644
index 0000000000..89c10c93c3
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0108-dts-Added-overlay-for-Adafruit-PiTFT-2.8-capacitive-.patch
@@ -0,0 +1,145 @@
+From 56cec891d108d33915dd835fa83844f7653ef4dd Mon Sep 17 00:00:00 2001
+From: Ondrej Wisniewski <ondrej.wisniewski@gmail.com>
+Date: Fri, 6 Nov 2015 15:01:28 +0100
+Subject: [PATCH 108/381] dts: Added overlay for Adafruit PiTFT 2.8" capacitive
+ touch screen
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 22 ++++++
+ .../dts/overlays/pitft28-capacitive-overlay.dts | 88 ++++++++++++++++++++++
+ 3 files changed, 111 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/pitft28-capacitive-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -36,6 +36,7 @@ dtb-$(RPI_DT_OVERLAYS) += mmc-overlay.dt
+ dtb-$(RPI_DT_OVERLAYS) += mz61581-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += piscreen-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += piscreen2r-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += pitft28-capacitive-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += pitft28-resistive-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += pps-gpio-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += pwm-overlay.dtb
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -439,6 +439,28 @@ Params: speed Display
+ xohms Touchpanel sensitivity (X-plate resistance)
+
+
++Name: pitft28-capacitive
++Info: Adafruit PiTFT 2.8" capacitive touch screen
++Load: dtoverlay=pitft28-capacitive,<param>=<val>
++Params: speed Display SPI bus speed
++
++ rotate Display rotation {0,90,180,270}
++
++ fps Delay between frame updates
++
++ debug Debug output level {0-7}
++
++ touch-sizex Touchscreen size x (default 240)
++
++ touch-sizey Touchscreen size y (default 320)
++
++ touch-invx Touchscreen inverted x axis
++
++ touch-invy Touchscreen inverted y axis
++
++ touch-swapxy Touchscreen swapped x y axis
++
++
+ Name: pitft28-resistive
+ Info: Adafruit PiTFT 2.8" resistive touch screen
+ Load: dtoverlay=pitft28-resistive,<param>=<val>
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/pitft28-capacitive-overlay.dts
+@@ -0,0 +1,88 @@
++/*
++ * Device Tree overlay for Adafruit PiTFT 2.8" capacitive touch screen
++ *
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++
++ fragment@0 {
++ target = <&spi0>;
++ __overlay__ {
++ status = "okay";
++
++ spidev@0{
++ status = "disabled";
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ pitft_pins: pitft_pins {
++ brcm,pins = <24 25>;
++ brcm,function = <0 1>; /* in out */
++ brcm,pull = <2 0>; /* pullup none */
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&spi0>;
++ __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ pitft: pitft@0{
++ compatible = "ilitek,ili9340";
++ reg = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pitft_pins>;
++
++ spi-max-frequency = <32000000>;
++ rotate = <90>;
++ fps = <25>;
++ bgr;
++ buswidth = <8>;
++ dc-gpios = <&gpio 25 0>;
++ debug = <0>;
++ };
++ };
++ };
++
++ fragment@3 {
++ target = <&i2c1>;
++ __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ ft6236: ft6236@38 {
++ compatible = "focaltech,ft6236";
++ reg = <0x38>;
++
++ interrupt-parent = <&gpio>;
++ interrupts = <24 2>;
++ touchscreen-size-x = <240>;
++ touchscreen-size-y = <320>;
++ };
++ };
++ };
++
++ __overrides__ {
++ speed = <&pitft>,"spi-max-frequency:0";
++ rotate = <&pitft>,"rotate:0";
++ fps = <&pitft>,"fps:0";
++ debug = <&pitft>,"debug:0";
++ touch-sizex = <&ft6236>,"touchscreen-size-x?";
++ touch-sizey = <&ft6236>,"touchscreen-size-y?";
++ touch-invx = <&ft6236>,"touchscreen-inverted-x?";
++ touch-invy = <&ft6236>,"touchscreen-inverted-y?";
++ touch-swapxy = <&ft6236>,"touchscreen-swapped-x-y?";
++ };
++};
diff --git a/target/linux/brcm2708/patches-4.4/0109-Add-support-for-the-HiFiBerry-DAC-Pro.patch b/target/linux/brcm2708/patches-4.4/0109-Add-support-for-the-HiFiBerry-DAC-Pro.patch
new file mode 100644
index 0000000000..b496659115
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0109-Add-support-for-the-HiFiBerry-DAC-Pro.patch
@@ -0,0 +1,539 @@
+From df78c185490e8f728cd0a2a61ae20ab489075bf2 Mon Sep 17 00:00:00 2001
+From: Stuart MacLean <stuart@hifiberry.com>
+Date: Fri, 2 Oct 2015 15:12:59 +0100
+Subject: [PATCH 109/381] Add support for the HiFiBerry DAC+ Pro.
+
+The HiFiBerry DAC+ and DAC+ Pro products both use the existing bcm sound driver with the DAC+ Pro having a special clock device driver representing the two high precision oscillators.
+
+An addition bug fix is included for the PCM512x codec where by the physical size of the sample frame is used in the calculation of the LRCK divisor as it was found to be wrong when using 24-bit depth sample contained in a little endian 4-byte sample frame.
+---
+ .../dts/overlays/hifiberry-dacplus-overlay.dts | 15 +-
+ drivers/clk/Makefile | 1 +
+ drivers/clk/clk-hifiberry-dacpro.c | 160 ++++++++++++++
+ sound/soc/bcm/hifiberry_dacplus.c | 244 +++++++++++++++++++--
+ sound/soc/codecs/pcm512x.c | 3 +-
+ 5 files changed, 396 insertions(+), 27 deletions(-)
+ create mode 100644 drivers/clk/clk-hifiberry-dacpro.c
+
+--- a/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
+@@ -6,6 +6,16 @@
+ compatible = "brcm,bcm2708";
+
+ fragment@0 {
++ target-path = "/clocks";
++ __overlay__ {
++ dacpro_osc: dacpro_osc {
++ compatible = "hifiberry,dacpro-clk";
++ #clock-cells = <0>;
++ };
++ };
++ };
++
++ fragment@1 {
+ target = <&sound>;
+ __overlay__ {
+ compatible = "hifiberry,hifiberry-dacplus";
+@@ -14,14 +24,14 @@
+ };
+ };
+
+- fragment@1 {
++ fragment@2 {
+ target = <&i2s>;
+ __overlay__ {
+ status = "okay";
+ };
+ };
+
+- fragment@2 {
++ fragment@3 {
+ target = <&i2c1>;
+ __overlay__ {
+ #address-cells = <1>;
+@@ -32,6 +42,7 @@
+ #sound-dai-cells = <0>;
+ compatible = "ti,pcm5122";
+ reg = <0x4d>;
++ clocks = <&dacpro_osc>;
+ status = "okay";
+ };
+ };
+--- a/drivers/clk/Makefile
++++ b/drivers/clk/Makefile
+@@ -24,6 +24,7 @@ obj-$(CONFIG_COMMON_CLK_CDCE706) += clk-
+ obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
+ obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o
+ obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
++obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += clk-hifiberry-dacpro.o
+ obj-$(CONFIG_MACH_LOONGSON32) += clk-ls1x.o
+ obj-$(CONFIG_COMMON_CLK_MAX_GEN) += clk-max-gen.o
+ obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
+--- /dev/null
++++ b/drivers/clk/clk-hifiberry-dacpro.c
+@@ -0,0 +1,160 @@
++/*
++ * Clock Driver for HiFiBerry DAC Pro
++ *
++ * Author: Stuart MacLean
++ * Copyright 2015
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++#include <linux/clk-provider.h>
++#include <linux/clkdev.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/slab.h>
++#include <linux/platform_device.h>
++
++/* Clock rate of CLK44EN attached to GPIO6 pin */
++#define CLK_44EN_RATE 22579200UL
++/* Clock rate of CLK48EN attached to GPIO3 pin */
++#define CLK_48EN_RATE 24576000UL
++
++/**
++ * struct hifiberry_dacpro_clk - Common struct to the HiFiBerry DAC Pro
++ * @hw: clk_hw for the common clk framework
++ * @mode: 0 => CLK44EN, 1 => CLK48EN
++ */
++struct clk_hifiberry_hw {
++ struct clk_hw hw;
++ uint8_t mode;
++};
++
++#define to_hifiberry_clk(_hw) container_of(_hw, struct clk_hifiberry_hw, hw)
++
++static const struct of_device_id clk_hifiberry_dacpro_dt_ids[] = {
++ { .compatible = "hifiberry,dacpro-clk",},
++ { }
++};
++MODULE_DEVICE_TABLE(of, clk_hifiberry_dacpro_dt_ids);
++
++static unsigned long clk_hifiberry_dacpro_recalc_rate(struct clk_hw *hw,
++ unsigned long parent_rate)
++{
++ return (to_hifiberry_clk(hw)->mode == 0) ? CLK_44EN_RATE :
++ CLK_48EN_RATE;
++}
++
++static long clk_hifiberry_dacpro_round_rate(struct clk_hw *hw,
++ unsigned long rate, unsigned long *parent_rate)
++{
++ long actual_rate;
++
++ if (rate <= CLK_44EN_RATE) {
++ actual_rate = (long)CLK_44EN_RATE;
++ } else if (rate >= CLK_48EN_RATE) {
++ actual_rate = (long)CLK_48EN_RATE;
++ } else {
++ long diff44Rate = (long)(rate - CLK_44EN_RATE);
++ long diff48Rate = (long)(CLK_48EN_RATE - rate);
++
++ if (diff44Rate < diff48Rate)
++ actual_rate = (long)CLK_44EN_RATE;
++ else
++ actual_rate = (long)CLK_48EN_RATE;
++ }
++ return actual_rate;
++}
++
++
++static int clk_hifiberry_dacpro_set_rate(struct clk_hw *hw,
++ unsigned long rate, unsigned long parent_rate)
++{
++ unsigned long actual_rate;
++ struct clk_hifiberry_hw *clk = to_hifiberry_clk(hw);
++
++ actual_rate = (unsigned long)clk_hifiberry_dacpro_round_rate(hw, rate,
++ &parent_rate);
++ clk->mode = (actual_rate == CLK_44EN_RATE) ? 0 : 1;
++ return 0;
++}
++
++
++const struct clk_ops clk_hifiberry_dacpro_rate_ops = {
++ .recalc_rate = clk_hifiberry_dacpro_recalc_rate,
++ .round_rate = clk_hifiberry_dacpro_round_rate,
++ .set_rate = clk_hifiberry_dacpro_set_rate,
++};
++
++static int clk_hifiberry_dacpro_probe(struct platform_device *pdev)
++{
++ int ret;
++ struct clk_hifiberry_hw *proclk;
++ struct clk *clk;
++ struct device *dev;
++ struct clk_init_data init;
++
++ dev = &pdev->dev;
++
++ proclk = kzalloc(sizeof(struct clk_hifiberry_hw), GFP_KERNEL);
++ if (!proclk)
++ return -ENOMEM;
++
++ init.name = "clk-hifiberry-dacpro";
++ init.ops = &clk_hifiberry_dacpro_rate_ops;
++ init.flags = CLK_IS_ROOT | CLK_IS_BASIC;
++ init.parent_names = NULL;
++ init.num_parents = 0;
++
++ proclk->mode = 0;
++ proclk->hw.init = &init;
++
++ clk = devm_clk_register(dev, &proclk->hw);
++ if (!IS_ERR(clk)) {
++ ret = of_clk_add_provider(dev->of_node, of_clk_src_simple_get,
++ clk);
++ } else {
++ dev_err(dev, "Fail to register clock driver\n");
++ kfree(proclk);
++ ret = PTR_ERR(clk);
++ }
++ return ret;
++}
++
++static int clk_hifiberry_dacpro_remove(struct platform_device *pdev)
++{
++ of_clk_del_provider(pdev->dev.of_node);
++ return 0;
++}
++
++static struct platform_driver clk_hifiberry_dacpro_driver = {
++ .probe = clk_hifiberry_dacpro_probe,
++ .remove = clk_hifiberry_dacpro_remove,
++ .driver = {
++ .name = "clk-hifiberry-dacpro",
++ .of_match_table = clk_hifiberry_dacpro_dt_ids,
++ },
++};
++
++static int __init clk_hifiberry_dacpro_init(void)
++{
++ return platform_driver_register(&clk_hifiberry_dacpro_driver);
++}
++core_initcall(clk_hifiberry_dacpro_init);
++
++static void __exit clk_hifiberry_dacpro_exit(void)
++{
++ platform_driver_unregister(&clk_hifiberry_dacpro_driver);
++}
++module_exit(clk_hifiberry_dacpro_exit);
++
++MODULE_DESCRIPTION("HiFiBerry DAC Pro clock driver");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:clk-hifiberry-dacpro");
+--- a/sound/soc/bcm/hifiberry_dacplus.c
++++ b/sound/soc/bcm/hifiberry_dacplus.c
+@@ -1,8 +1,8 @@
+ /*
+- * ASoC Driver for HiFiBerry DAC+
++ * ASoC Driver for HiFiBerry DAC+ / DAC Pro
+ *
+- * Author: Daniel Matuschek
+- * Copyright 2014
++ * Author: Daniel Matuschek, Stuart MacLean <stuart@hifiberry.com>
++ * Copyright 2014-2015
+ * based on code by Florian Meier <florian.meier@koalo.de>
+ *
+ * This program is free software; you can redistribute it and/or
+@@ -17,6 +17,13 @@
+
+ #include <linux/module.h>
+ #include <linux/platform_device.h>
++#include <linux/kernel.h>
++#include <linux/clk.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
+
+ #include <sound/core.h>
+ #include <sound/pcm.h>
+@@ -26,34 +33,222 @@
+
+ #include "../codecs/pcm512x.h"
+
++#define HIFIBERRY_DACPRO_NOCLOCK 0
++#define HIFIBERRY_DACPRO_CLK44EN 1
++#define HIFIBERRY_DACPRO_CLK48EN 2
++
++struct pcm512x_priv {
++ struct regmap *regmap;
++ struct clk *sclk;
++};
++
++/* Clock rate of CLK44EN attached to GPIO6 pin */
++#define CLK_44EN_RATE 22579200UL
++/* Clock rate of CLK48EN attached to GPIO3 pin */
++#define CLK_48EN_RATE 24576000UL
++
++static bool snd_rpi_hifiberry_is_dacpro;
++
++static void snd_rpi_hifiberry_dacplus_select_clk(struct snd_soc_codec *codec,
++ int clk_id)
++{
++ switch (clk_id) {
++ case HIFIBERRY_DACPRO_NOCLOCK:
++ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x24, 0x00);
++ break;
++ case HIFIBERRY_DACPRO_CLK44EN:
++ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x24, 0x20);
++ break;
++ case HIFIBERRY_DACPRO_CLK48EN:
++ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x24, 0x04);
++ break;
++ }
++}
++
++static void snd_rpi_hifiberry_dacplus_clk_gpio(struct snd_soc_codec *codec)
++{
++ snd_soc_update_bits(codec, PCM512x_GPIO_EN, 0x24, 0x24);
++ snd_soc_update_bits(codec, PCM512x_GPIO_OUTPUT_3, 0x0f, 0x02);
++ snd_soc_update_bits(codec, PCM512x_GPIO_OUTPUT_6, 0x0f, 0x02);
++}
++
++static bool snd_rpi_hifiberry_dacplus_is_sclk(struct snd_soc_codec *codec)
++{
++ int sck;
++
++ sck = snd_soc_read(codec, PCM512x_RATE_DET_4);
++ return (!(sck & 0x40));
++}
++
++static bool snd_rpi_hifiberry_dacplus_is_sclk_sleep(
++ struct snd_soc_codec *codec)
++{
++ msleep(2);
++ return snd_rpi_hifiberry_dacplus_is_sclk(codec);
++}
++
++static bool snd_rpi_hifiberry_dacplus_is_pro_card(struct snd_soc_codec *codec)
++{
++ bool isClk44EN, isClk48En, isNoClk;
++
++ snd_rpi_hifiberry_dacplus_clk_gpio(codec);
++
++ snd_rpi_hifiberry_dacplus_select_clk(codec, HIFIBERRY_DACPRO_CLK44EN);
++ isClk44EN = snd_rpi_hifiberry_dacplus_is_sclk_sleep(codec);
++
++ snd_rpi_hifiberry_dacplus_select_clk(codec, HIFIBERRY_DACPRO_NOCLOCK);
++ isNoClk = snd_rpi_hifiberry_dacplus_is_sclk_sleep(codec);
++
++ snd_rpi_hifiberry_dacplus_select_clk(codec, HIFIBERRY_DACPRO_CLK48EN);
++ isClk48En = snd_rpi_hifiberry_dacplus_is_sclk_sleep(codec);
++
++ return (isClk44EN && isClk48En && !isNoClk);
++}
++
++static int snd_rpi_hifiberry_dacplus_clk_for_rate(int sample_rate)
++{
++ int type;
++
++ switch (sample_rate) {
++ case 11025:
++ case 22050:
++ case 44100:
++ case 88200:
++ case 176400:
++ type = HIFIBERRY_DACPRO_CLK44EN;
++ break;
++ default:
++ type = HIFIBERRY_DACPRO_CLK48EN;
++ break;
++ }
++ return type;
++}
++
++static void snd_rpi_hifiberry_dacplus_set_sclk(struct snd_soc_codec *codec,
++ int sample_rate)
++{
++ struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
++
++ if (!IS_ERR(pcm512x->sclk)) {
++ int ctype;
++
++ ctype = snd_rpi_hifiberry_dacplus_clk_for_rate(sample_rate);
++ clk_set_rate(pcm512x->sclk, (ctype == HIFIBERRY_DACPRO_CLK44EN)
++ ? CLK_44EN_RATE : CLK_48EN_RATE);
++ snd_rpi_hifiberry_dacplus_select_clk(codec, ctype);
++ }
++}
++
+ static int snd_rpi_hifiberry_dacplus_init(struct snd_soc_pcm_runtime *rtd)
+ {
+ struct snd_soc_codec *codec = rtd->codec;
++ struct pcm512x_priv *priv;
++
++ snd_rpi_hifiberry_is_dacpro
++ = snd_rpi_hifiberry_dacplus_is_pro_card(codec);
++
++ if (snd_rpi_hifiberry_is_dacpro) {
++ struct snd_soc_dai_link *dai = rtd->dai_link;
++
++ dai->name = "HiFiBerry DAC+ Pro";
++ dai->stream_name = "HiFiBerry DAC+ Pro HiFi";
++ dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
++ | SND_SOC_DAIFMT_CBM_CFM;
++
++ snd_soc_update_bits(codec, PCM512x_BCLK_LRCLK_CFG, 0x31, 0x11);
++ snd_soc_update_bits(codec, PCM512x_MASTER_MODE, 0x03, 0x03);
++ snd_soc_update_bits(codec, PCM512x_MASTER_CLKDIV_2, 0x7f, 63);
++ } else {
++ priv = snd_soc_codec_get_drvdata(codec);
++ priv->sclk = ERR_PTR(-ENOENT);
++ }
++
+ snd_soc_update_bits(codec, PCM512x_GPIO_EN, 0x08, 0x08);
+- snd_soc_update_bits(codec, PCM512x_GPIO_OUTPUT_4, 0xf, 0x02);
+- snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08,0x08);
++ snd_soc_update_bits(codec, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02);
++ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
++
++ return 0;
++}
++
++static int snd_rpi_hifiberry_dacplus_update_rate_den(
++ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_codec *codec = rtd->codec;
++ struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
++ struct snd_ratnum *rats_no_pll;
++ unsigned int num = 0, den = 0;
++ int err;
++
++ rats_no_pll = devm_kzalloc(rtd->dev, sizeof(*rats_no_pll), GFP_KERNEL);
++ if (!rats_no_pll)
++ return -ENOMEM;
++
++ rats_no_pll->num = clk_get_rate(pcm512x->sclk) / 64;
++ rats_no_pll->den_min = 1;
++ rats_no_pll->den_max = 128;
++ rats_no_pll->den_step = 1;
++
++ err = snd_interval_ratnum(hw_param_interval(params,
++ SNDRV_PCM_HW_PARAM_RATE), 1, rats_no_pll, &num, &den);
++ if (err >= 0 && den) {
++ params->rate_num = num;
++ params->rate_den = den;
++ }
++
++ devm_kfree(rtd->dev, rats_no_pll);
+ return 0;
+ }
+
+-static int snd_rpi_hifiberry_dacplus_hw_params(struct snd_pcm_substream *substream,
+- struct snd_pcm_hw_params *params)
++static int snd_rpi_hifiberry_dacplus_set_bclk_ratio_pro(
++ struct snd_soc_dai *cpu_dai, struct snd_pcm_hw_params *params)
++{
++ int bratio = snd_pcm_format_physical_width(params_format(params))
++ * params_channels(params);
++ return snd_soc_dai_set_bclk_ratio(cpu_dai, bratio);
++}
++
++static int snd_rpi_hifiberry_dacplus_hw_params(
++ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
+ {
++ int ret;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+- return snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
++
++ if (snd_rpi_hifiberry_is_dacpro) {
++ struct snd_soc_codec *codec = rtd->codec;
++
++ snd_rpi_hifiberry_dacplus_set_sclk(codec,
++ params_rate(params));
++
++ ret = snd_rpi_hifiberry_dacplus_set_bclk_ratio_pro(cpu_dai,
++ params);
++ if (!ret)
++ ret = snd_rpi_hifiberry_dacplus_update_rate_den(
++ substream, params);
++ } else {
++ ret = snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
++ }
++ return ret;
+ }
+
+-static int snd_rpi_hifiberry_dacplus_startup(struct snd_pcm_substream *substream) {
++static int snd_rpi_hifiberry_dacplus_startup(
++ struct snd_pcm_substream *substream)
++{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->codec;
+- snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08,0x08);
++
++ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
+ return 0;
+ }
+
+-static void snd_rpi_hifiberry_dacplus_shutdown(struct snd_pcm_substream *substream) {
++static void snd_rpi_hifiberry_dacplus_shutdown(
++ struct snd_pcm_substream *substream)
++{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->codec;
+- snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08,0x00);
++
++ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08, 0x00);
+ }
+
+ /* machine stream operations */
+@@ -90,19 +285,20 @@ static int snd_rpi_hifiberry_dacplus_pro
+ int ret = 0;
+
+ snd_rpi_hifiberry_dacplus.dev = &pdev->dev;
+-
+ if (pdev->dev.of_node) {
+- struct device_node *i2s_node;
+- struct snd_soc_dai_link *dai = &snd_rpi_hifiberry_dacplus_dai[0];
+- i2s_node = of_parse_phandle(pdev->dev.of_node,
+- "i2s-controller", 0);
+-
+- if (i2s_node) {
+- dai->cpu_dai_name = NULL;
+- dai->cpu_of_node = i2s_node;
+- dai->platform_name = NULL;
+- dai->platform_of_node = i2s_node;
+- }
++ struct device_node *i2s_node;
++ struct snd_soc_dai_link *dai;
++
++ dai = &snd_rpi_hifiberry_dacplus_dai[0];
++ i2s_node = of_parse_phandle(pdev->dev.of_node,
++ "i2s-controller", 0);
++
++ if (i2s_node) {
++ dai->cpu_dai_name = NULL;
++ dai->cpu_of_node = i2s_node;
++ dai->platform_name = NULL;
++ dai->platform_of_node = i2s_node;
++ }
+ }
+
+ ret = snd_soc_register_card(&snd_rpi_hifiberry_dacplus);
+--- a/sound/soc/codecs/pcm512x.c
++++ b/sound/soc/codecs/pcm512x.c
+@@ -854,7 +854,8 @@ static int pcm512x_set_dividers(struct s
+ int fssp;
+ int gpio;
+
+- lrclk_div = snd_soc_params_to_frame_size(params);
++ lrclk_div = snd_pcm_format_physical_width(params_format(params))
++ * params_channels(params);
+ if (lrclk_div == 0) {
+ dev_err(dev, "No LRCLK?\n");
+ return -EINVAL;
diff --git a/target/linux/brcm2708/patches-4.4/0109-dts-Added-overlay-for-Adafruit-PiTFT-2.8-capacitive-.patch b/target/linux/brcm2708/patches-4.4/0109-dts-Added-overlay-for-Adafruit-PiTFT-2.8-capacitive-.patch
deleted file mode 100644
index 480d8db6a0..0000000000
--- a/target/linux/brcm2708/patches-4.4/0109-dts-Added-overlay-for-Adafruit-PiTFT-2.8-capacitive-.patch
+++ /dev/null
@@ -1,145 +0,0 @@
-From 1a4fac1ea6bb33a963b06406f6f44b527daa3a90 Mon Sep 17 00:00:00 2001
-From: Ondrej Wisniewski <ondrej.wisniewski@gmail.com>
-Date: Fri, 6 Nov 2015 15:01:28 +0100
-Subject: [PATCH 109/170] dts: Added overlay for Adafruit PiTFT 2.8" capacitive
- touch screen
-
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 22 ++++++
- .../dts/overlays/pitft28-capacitive-overlay.dts | 88 ++++++++++++++++++++++
- 3 files changed, 111 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/pitft28-capacitive-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -36,6 +36,7 @@ dtb-$(RPI_DT_OVERLAYS) += mmc-overlay.dt
- dtb-$(RPI_DT_OVERLAYS) += mz61581-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += piscreen-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += piscreen2r-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += pitft28-capacitive-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += pitft28-resistive-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += pps-gpio-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += pwm-overlay.dtb
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -439,6 +439,28 @@ Params: speed Display
- xohms Touchpanel sensitivity (X-plate resistance)
-
-
-+Name: pitft28-capacitive
-+Info: Adafruit PiTFT 2.8" capacitive touch screen
-+Load: dtoverlay=pitft28-capacitive,<param>=<val>
-+Params: speed Display SPI bus speed
-+
-+ rotate Display rotation {0,90,180,270}
-+
-+ fps Delay between frame updates
-+
-+ debug Debug output level {0-7}
-+
-+ touch-sizex Touchscreen size x (default 240)
-+
-+ touch-sizey Touchscreen size y (default 320)
-+
-+ touch-invx Touchscreen inverted x axis
-+
-+ touch-invy Touchscreen inverted y axis
-+
-+ touch-swapxy Touchscreen swapped x y axis
-+
-+
- Name: pitft28-resistive
- Info: Adafruit PiTFT 2.8" resistive touch screen
- Load: dtoverlay=pitft28-resistive,<param>=<val>
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/pitft28-capacitive-overlay.dts
-@@ -0,0 +1,88 @@
-+/*
-+ * Device Tree overlay for Adafruit PiTFT 2.8" capacitive touch screen
-+ *
-+ */
-+
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+
-+ fragment@0 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ status = "okay";
-+
-+ spidev@0{
-+ status = "disabled";
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ pitft_pins: pitft_pins {
-+ brcm,pins = <24 25>;
-+ brcm,function = <0 1>; /* in out */
-+ brcm,pull = <2 0>; /* pullup none */
-+ };
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ pitft: pitft@0{
-+ compatible = "ilitek,ili9340";
-+ reg = <0>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&pitft_pins>;
-+
-+ spi-max-frequency = <32000000>;
-+ rotate = <90>;
-+ fps = <25>;
-+ bgr;
-+ buswidth = <8>;
-+ dc-gpios = <&gpio 25 0>;
-+ debug = <0>;
-+ };
-+ };
-+ };
-+
-+ fragment@3 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ ft6236: ft6236@38 {
-+ compatible = "focaltech,ft6236";
-+ reg = <0x38>;
-+
-+ interrupt-parent = <&gpio>;
-+ interrupts = <24 2>;
-+ touchscreen-size-x = <240>;
-+ touchscreen-size-y = <320>;
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ speed = <&pitft>,"spi-max-frequency:0";
-+ rotate = <&pitft>,"rotate:0";
-+ fps = <&pitft>,"fps:0";
-+ debug = <&pitft>,"debug:0";
-+ touch-sizex = <&ft6236>,"touchscreen-size-x?";
-+ touch-sizey = <&ft6236>,"touchscreen-size-y?";
-+ touch-invx = <&ft6236>,"touchscreen-inverted-x?";
-+ touch-invy = <&ft6236>,"touchscreen-inverted-y?";
-+ touch-swapxy = <&ft6236>,"touchscreen-swapped-x-y?";
-+ };
-+};
diff --git a/target/linux/brcm2708/patches-4.4/0110-Add-support-for-the-HiFiBerry-DAC-Pro.patch b/target/linux/brcm2708/patches-4.4/0110-Add-support-for-the-HiFiBerry-DAC-Pro.patch
deleted file mode 100644
index 594388eda0..0000000000
--- a/target/linux/brcm2708/patches-4.4/0110-Add-support-for-the-HiFiBerry-DAC-Pro.patch
+++ /dev/null
@@ -1,539 +0,0 @@
-From 660ba9173ca14b48d7cd2f69ff45e67ebe4d947a Mon Sep 17 00:00:00 2001
-From: Stuart MacLean <stuart@hifiberry.com>
-Date: Fri, 2 Oct 2015 15:12:59 +0100
-Subject: [PATCH 110/170] Add support for the HiFiBerry DAC+ Pro.
-
-The HiFiBerry DAC+ and DAC+ Pro products both use the existing bcm sound driver with the DAC+ Pro having a special clock device driver representing the two high precision oscillators.
-
-An addition bug fix is included for the PCM512x codec where by the physical size of the sample frame is used in the calculation of the LRCK divisor as it was found to be wrong when using 24-bit depth sample contained in a little endian 4-byte sample frame.
----
- .../dts/overlays/hifiberry-dacplus-overlay.dts | 15 +-
- drivers/clk/Makefile | 1 +
- drivers/clk/clk-hifiberry-dacpro.c | 160 ++++++++++++++
- sound/soc/bcm/hifiberry_dacplus.c | 244 +++++++++++++++++++--
- sound/soc/codecs/pcm512x.c | 3 +-
- 5 files changed, 396 insertions(+), 27 deletions(-)
- create mode 100644 drivers/clk/clk-hifiberry-dacpro.c
-
---- a/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
-@@ -6,6 +6,16 @@
- compatible = "brcm,bcm2708";
-
- fragment@0 {
-+ target-path = "/clocks";
-+ __overlay__ {
-+ dacpro_osc: dacpro_osc {
-+ compatible = "hifiberry,dacpro-clk";
-+ #clock-cells = <0>;
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
- target = <&sound>;
- __overlay__ {
- compatible = "hifiberry,hifiberry-dacplus";
-@@ -14,14 +24,14 @@
- };
- };
-
-- fragment@1 {
-+ fragment@2 {
- target = <&i2s>;
- __overlay__ {
- status = "okay";
- };
- };
-
-- fragment@2 {
-+ fragment@3 {
- target = <&i2c1>;
- __overlay__ {
- #address-cells = <1>;
-@@ -32,6 +42,7 @@
- #sound-dai-cells = <0>;
- compatible = "ti,pcm5122";
- reg = <0x4d>;
-+ clocks = <&dacpro_osc>;
- status = "okay";
- };
- };
---- a/drivers/clk/Makefile
-+++ b/drivers/clk/Makefile
-@@ -24,6 +24,7 @@ obj-$(CONFIG_COMMON_CLK_CDCE706) += clk-
- obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
- obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o
- obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
-+obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += clk-hifiberry-dacpro.o
- obj-$(CONFIG_MACH_LOONGSON32) += clk-ls1x.o
- obj-$(CONFIG_COMMON_CLK_MAX_GEN) += clk-max-gen.o
- obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
---- /dev/null
-+++ b/drivers/clk/clk-hifiberry-dacpro.c
-@@ -0,0 +1,160 @@
-+/*
-+ * Clock Driver for HiFiBerry DAC Pro
-+ *
-+ * Author: Stuart MacLean
-+ * Copyright 2015
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ */
-+
-+#include <linux/clk-provider.h>
-+#include <linux/clkdev.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/slab.h>
-+#include <linux/platform_device.h>
-+
-+/* Clock rate of CLK44EN attached to GPIO6 pin */
-+#define CLK_44EN_RATE 22579200UL
-+/* Clock rate of CLK48EN attached to GPIO3 pin */
-+#define CLK_48EN_RATE 24576000UL
-+
-+/**
-+ * struct hifiberry_dacpro_clk - Common struct to the HiFiBerry DAC Pro
-+ * @hw: clk_hw for the common clk framework
-+ * @mode: 0 => CLK44EN, 1 => CLK48EN
-+ */
-+struct clk_hifiberry_hw {
-+ struct clk_hw hw;
-+ uint8_t mode;
-+};
-+
-+#define to_hifiberry_clk(_hw) container_of(_hw, struct clk_hifiberry_hw, hw)
-+
-+static const struct of_device_id clk_hifiberry_dacpro_dt_ids[] = {
-+ { .compatible = "hifiberry,dacpro-clk",},
-+ { }
-+};
-+MODULE_DEVICE_TABLE(of, clk_hifiberry_dacpro_dt_ids);
-+
-+static unsigned long clk_hifiberry_dacpro_recalc_rate(struct clk_hw *hw,
-+ unsigned long parent_rate)
-+{
-+ return (to_hifiberry_clk(hw)->mode == 0) ? CLK_44EN_RATE :
-+ CLK_48EN_RATE;
-+}
-+
-+static long clk_hifiberry_dacpro_round_rate(struct clk_hw *hw,
-+ unsigned long rate, unsigned long *parent_rate)
-+{
-+ long actual_rate;
-+
-+ if (rate <= CLK_44EN_RATE) {
-+ actual_rate = (long)CLK_44EN_RATE;
-+ } else if (rate >= CLK_48EN_RATE) {
-+ actual_rate = (long)CLK_48EN_RATE;
-+ } else {
-+ long diff44Rate = (long)(rate - CLK_44EN_RATE);
-+ long diff48Rate = (long)(CLK_48EN_RATE - rate);
-+
-+ if (diff44Rate < diff48Rate)
-+ actual_rate = (long)CLK_44EN_RATE;
-+ else
-+ actual_rate = (long)CLK_48EN_RATE;
-+ }
-+ return actual_rate;
-+}
-+
-+
-+static int clk_hifiberry_dacpro_set_rate(struct clk_hw *hw,
-+ unsigned long rate, unsigned long parent_rate)
-+{
-+ unsigned long actual_rate;
-+ struct clk_hifiberry_hw *clk = to_hifiberry_clk(hw);
-+
-+ actual_rate = (unsigned long)clk_hifiberry_dacpro_round_rate(hw, rate,
-+ &parent_rate);
-+ clk->mode = (actual_rate == CLK_44EN_RATE) ? 0 : 1;
-+ return 0;
-+}
-+
-+
-+const struct clk_ops clk_hifiberry_dacpro_rate_ops = {
-+ .recalc_rate = clk_hifiberry_dacpro_recalc_rate,
-+ .round_rate = clk_hifiberry_dacpro_round_rate,
-+ .set_rate = clk_hifiberry_dacpro_set_rate,
-+};
-+
-+static int clk_hifiberry_dacpro_probe(struct platform_device *pdev)
-+{
-+ int ret;
-+ struct clk_hifiberry_hw *proclk;
-+ struct clk *clk;
-+ struct device *dev;
-+ struct clk_init_data init;
-+
-+ dev = &pdev->dev;
-+
-+ proclk = kzalloc(sizeof(struct clk_hifiberry_hw), GFP_KERNEL);
-+ if (!proclk)
-+ return -ENOMEM;
-+
-+ init.name = "clk-hifiberry-dacpro";
-+ init.ops = &clk_hifiberry_dacpro_rate_ops;
-+ init.flags = CLK_IS_ROOT | CLK_IS_BASIC;
-+ init.parent_names = NULL;
-+ init.num_parents = 0;
-+
-+ proclk->mode = 0;
-+ proclk->hw.init = &init;
-+
-+ clk = devm_clk_register(dev, &proclk->hw);
-+ if (!IS_ERR(clk)) {
-+ ret = of_clk_add_provider(dev->of_node, of_clk_src_simple_get,
-+ clk);
-+ } else {
-+ dev_err(dev, "Fail to register clock driver\n");
-+ kfree(proclk);
-+ ret = PTR_ERR(clk);
-+ }
-+ return ret;
-+}
-+
-+static int clk_hifiberry_dacpro_remove(struct platform_device *pdev)
-+{
-+ of_clk_del_provider(pdev->dev.of_node);
-+ return 0;
-+}
-+
-+static struct platform_driver clk_hifiberry_dacpro_driver = {
-+ .probe = clk_hifiberry_dacpro_probe,
-+ .remove = clk_hifiberry_dacpro_remove,
-+ .driver = {
-+ .name = "clk-hifiberry-dacpro",
-+ .of_match_table = clk_hifiberry_dacpro_dt_ids,
-+ },
-+};
-+
-+static int __init clk_hifiberry_dacpro_init(void)
-+{
-+ return platform_driver_register(&clk_hifiberry_dacpro_driver);
-+}
-+core_initcall(clk_hifiberry_dacpro_init);
-+
-+static void __exit clk_hifiberry_dacpro_exit(void)
-+{
-+ platform_driver_unregister(&clk_hifiberry_dacpro_driver);
-+}
-+module_exit(clk_hifiberry_dacpro_exit);
-+
-+MODULE_DESCRIPTION("HiFiBerry DAC Pro clock driver");
-+MODULE_LICENSE("GPL v2");
-+MODULE_ALIAS("platform:clk-hifiberry-dacpro");
---- a/sound/soc/bcm/hifiberry_dacplus.c
-+++ b/sound/soc/bcm/hifiberry_dacplus.c
-@@ -1,8 +1,8 @@
- /*
-- * ASoC Driver for HiFiBerry DAC+
-+ * ASoC Driver for HiFiBerry DAC+ / DAC Pro
- *
-- * Author: Daniel Matuschek
-- * Copyright 2014
-+ * Author: Daniel Matuschek, Stuart MacLean <stuart@hifiberry.com>
-+ * Copyright 2014-2015
- * based on code by Florian Meier <florian.meier@koalo.de>
- *
- * This program is free software; you can redistribute it and/or
-@@ -17,6 +17,13 @@
-
- #include <linux/module.h>
- #include <linux/platform_device.h>
-+#include <linux/kernel.h>
-+#include <linux/clk.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/slab.h>
-+#include <linux/delay.h>
-
- #include <sound/core.h>
- #include <sound/pcm.h>
-@@ -26,34 +33,222 @@
-
- #include "../codecs/pcm512x.h"
-
-+#define HIFIBERRY_DACPRO_NOCLOCK 0
-+#define HIFIBERRY_DACPRO_CLK44EN 1
-+#define HIFIBERRY_DACPRO_CLK48EN 2
-+
-+struct pcm512x_priv {
-+ struct regmap *regmap;
-+ struct clk *sclk;
-+};
-+
-+/* Clock rate of CLK44EN attached to GPIO6 pin */
-+#define CLK_44EN_RATE 22579200UL
-+/* Clock rate of CLK48EN attached to GPIO3 pin */
-+#define CLK_48EN_RATE 24576000UL
-+
-+static bool snd_rpi_hifiberry_is_dacpro;
-+
-+static void snd_rpi_hifiberry_dacplus_select_clk(struct snd_soc_codec *codec,
-+ int clk_id)
-+{
-+ switch (clk_id) {
-+ case HIFIBERRY_DACPRO_NOCLOCK:
-+ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x24, 0x00);
-+ break;
-+ case HIFIBERRY_DACPRO_CLK44EN:
-+ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x24, 0x20);
-+ break;
-+ case HIFIBERRY_DACPRO_CLK48EN:
-+ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x24, 0x04);
-+ break;
-+ }
-+}
-+
-+static void snd_rpi_hifiberry_dacplus_clk_gpio(struct snd_soc_codec *codec)
-+{
-+ snd_soc_update_bits(codec, PCM512x_GPIO_EN, 0x24, 0x24);
-+ snd_soc_update_bits(codec, PCM512x_GPIO_OUTPUT_3, 0x0f, 0x02);
-+ snd_soc_update_bits(codec, PCM512x_GPIO_OUTPUT_6, 0x0f, 0x02);
-+}
-+
-+static bool snd_rpi_hifiberry_dacplus_is_sclk(struct snd_soc_codec *codec)
-+{
-+ int sck;
-+
-+ sck = snd_soc_read(codec, PCM512x_RATE_DET_4);
-+ return (!(sck & 0x40));
-+}
-+
-+static bool snd_rpi_hifiberry_dacplus_is_sclk_sleep(
-+ struct snd_soc_codec *codec)
-+{
-+ msleep(2);
-+ return snd_rpi_hifiberry_dacplus_is_sclk(codec);
-+}
-+
-+static bool snd_rpi_hifiberry_dacplus_is_pro_card(struct snd_soc_codec *codec)
-+{
-+ bool isClk44EN, isClk48En, isNoClk;
-+
-+ snd_rpi_hifiberry_dacplus_clk_gpio(codec);
-+
-+ snd_rpi_hifiberry_dacplus_select_clk(codec, HIFIBERRY_DACPRO_CLK44EN);
-+ isClk44EN = snd_rpi_hifiberry_dacplus_is_sclk_sleep(codec);
-+
-+ snd_rpi_hifiberry_dacplus_select_clk(codec, HIFIBERRY_DACPRO_NOCLOCK);
-+ isNoClk = snd_rpi_hifiberry_dacplus_is_sclk_sleep(codec);
-+
-+ snd_rpi_hifiberry_dacplus_select_clk(codec, HIFIBERRY_DACPRO_CLK48EN);
-+ isClk48En = snd_rpi_hifiberry_dacplus_is_sclk_sleep(codec);
-+
-+ return (isClk44EN && isClk48En && !isNoClk);
-+}
-+
-+static int snd_rpi_hifiberry_dacplus_clk_for_rate(int sample_rate)
-+{
-+ int type;
-+
-+ switch (sample_rate) {
-+ case 11025:
-+ case 22050:
-+ case 44100:
-+ case 88200:
-+ case 176400:
-+ type = HIFIBERRY_DACPRO_CLK44EN;
-+ break;
-+ default:
-+ type = HIFIBERRY_DACPRO_CLK48EN;
-+ break;
-+ }
-+ return type;
-+}
-+
-+static void snd_rpi_hifiberry_dacplus_set_sclk(struct snd_soc_codec *codec,
-+ int sample_rate)
-+{
-+ struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
-+
-+ if (!IS_ERR(pcm512x->sclk)) {
-+ int ctype;
-+
-+ ctype = snd_rpi_hifiberry_dacplus_clk_for_rate(sample_rate);
-+ clk_set_rate(pcm512x->sclk, (ctype == HIFIBERRY_DACPRO_CLK44EN)
-+ ? CLK_44EN_RATE : CLK_48EN_RATE);
-+ snd_rpi_hifiberry_dacplus_select_clk(codec, ctype);
-+ }
-+}
-+
- static int snd_rpi_hifiberry_dacplus_init(struct snd_soc_pcm_runtime *rtd)
- {
- struct snd_soc_codec *codec = rtd->codec;
-+ struct pcm512x_priv *priv;
-+
-+ snd_rpi_hifiberry_is_dacpro
-+ = snd_rpi_hifiberry_dacplus_is_pro_card(codec);
-+
-+ if (snd_rpi_hifiberry_is_dacpro) {
-+ struct snd_soc_dai_link *dai = rtd->dai_link;
-+
-+ dai->name = "HiFiBerry DAC+ Pro";
-+ dai->stream_name = "HiFiBerry DAC+ Pro HiFi";
-+ dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
-+ | SND_SOC_DAIFMT_CBM_CFM;
-+
-+ snd_soc_update_bits(codec, PCM512x_BCLK_LRCLK_CFG, 0x31, 0x11);
-+ snd_soc_update_bits(codec, PCM512x_MASTER_MODE, 0x03, 0x03);
-+ snd_soc_update_bits(codec, PCM512x_MASTER_CLKDIV_2, 0x7f, 63);
-+ } else {
-+ priv = snd_soc_codec_get_drvdata(codec);
-+ priv->sclk = ERR_PTR(-ENOENT);
-+ }
-+
- snd_soc_update_bits(codec, PCM512x_GPIO_EN, 0x08, 0x08);
-- snd_soc_update_bits(codec, PCM512x_GPIO_OUTPUT_4, 0xf, 0x02);
-- snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08,0x08);
-+ snd_soc_update_bits(codec, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02);
-+ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
-+
-+ return 0;
-+}
-+
-+static int snd_rpi_hifiberry_dacplus_update_rate_den(
-+ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
-+{
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ struct snd_soc_codec *codec = rtd->codec;
-+ struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
-+ struct snd_ratnum *rats_no_pll;
-+ unsigned int num = 0, den = 0;
-+ int err;
-+
-+ rats_no_pll = devm_kzalloc(rtd->dev, sizeof(*rats_no_pll), GFP_KERNEL);
-+ if (!rats_no_pll)
-+ return -ENOMEM;
-+
-+ rats_no_pll->num = clk_get_rate(pcm512x->sclk) / 64;
-+ rats_no_pll->den_min = 1;
-+ rats_no_pll->den_max = 128;
-+ rats_no_pll->den_step = 1;
-+
-+ err = snd_interval_ratnum(hw_param_interval(params,
-+ SNDRV_PCM_HW_PARAM_RATE), 1, rats_no_pll, &num, &den);
-+ if (err >= 0 && den) {
-+ params->rate_num = num;
-+ params->rate_den = den;
-+ }
-+
-+ devm_kfree(rtd->dev, rats_no_pll);
- return 0;
- }
-
--static int snd_rpi_hifiberry_dacplus_hw_params(struct snd_pcm_substream *substream,
-- struct snd_pcm_hw_params *params)
-+static int snd_rpi_hifiberry_dacplus_set_bclk_ratio_pro(
-+ struct snd_soc_dai *cpu_dai, struct snd_pcm_hw_params *params)
-+{
-+ int bratio = snd_pcm_format_physical_width(params_format(params))
-+ * params_channels(params);
-+ return snd_soc_dai_set_bclk_ratio(cpu_dai, bratio);
-+}
-+
-+static int snd_rpi_hifiberry_dacplus_hw_params(
-+ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
- {
-+ int ret;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-- return snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
-+
-+ if (snd_rpi_hifiberry_is_dacpro) {
-+ struct snd_soc_codec *codec = rtd->codec;
-+
-+ snd_rpi_hifiberry_dacplus_set_sclk(codec,
-+ params_rate(params));
-+
-+ ret = snd_rpi_hifiberry_dacplus_set_bclk_ratio_pro(cpu_dai,
-+ params);
-+ if (!ret)
-+ ret = snd_rpi_hifiberry_dacplus_update_rate_den(
-+ substream, params);
-+ } else {
-+ ret = snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
-+ }
-+ return ret;
- }
-
--static int snd_rpi_hifiberry_dacplus_startup(struct snd_pcm_substream *substream) {
-+static int snd_rpi_hifiberry_dacplus_startup(
-+ struct snd_pcm_substream *substream)
-+{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
-- snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08,0x08);
-+
-+ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
- return 0;
- }
-
--static void snd_rpi_hifiberry_dacplus_shutdown(struct snd_pcm_substream *substream) {
-+static void snd_rpi_hifiberry_dacplus_shutdown(
-+ struct snd_pcm_substream *substream)
-+{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
-- snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08,0x00);
-+
-+ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08, 0x00);
- }
-
- /* machine stream operations */
-@@ -90,19 +285,20 @@ static int snd_rpi_hifiberry_dacplus_pro
- int ret = 0;
-
- snd_rpi_hifiberry_dacplus.dev = &pdev->dev;
--
- if (pdev->dev.of_node) {
-- struct device_node *i2s_node;
-- struct snd_soc_dai_link *dai = &snd_rpi_hifiberry_dacplus_dai[0];
-- i2s_node = of_parse_phandle(pdev->dev.of_node,
-- "i2s-controller", 0);
--
-- if (i2s_node) {
-- dai->cpu_dai_name = NULL;
-- dai->cpu_of_node = i2s_node;
-- dai->platform_name = NULL;
-- dai->platform_of_node = i2s_node;
-- }
-+ struct device_node *i2s_node;
-+ struct snd_soc_dai_link *dai;
-+
-+ dai = &snd_rpi_hifiberry_dacplus_dai[0];
-+ i2s_node = of_parse_phandle(pdev->dev.of_node,
-+ "i2s-controller", 0);
-+
-+ if (i2s_node) {
-+ dai->cpu_dai_name = NULL;
-+ dai->cpu_of_node = i2s_node;
-+ dai->platform_name = NULL;
-+ dai->platform_of_node = i2s_node;
-+ }
- }
-
- ret = snd_soc_register_card(&snd_rpi_hifiberry_dacplus);
---- a/sound/soc/codecs/pcm512x.c
-+++ b/sound/soc/codecs/pcm512x.c
-@@ -854,7 +854,8 @@ static int pcm512x_set_dividers(struct s
- int fssp;
- int gpio;
-
-- lrclk_div = snd_soc_params_to_frame_size(params);
-+ lrclk_div = snd_pcm_format_physical_width(params_format(params))
-+ * params_channels(params);
- if (lrclk_div == 0) {
- dev_err(dev, "No LRCLK?\n");
- return -EINVAL;
diff --git a/target/linux/brcm2708/patches-4.4/0110-BCM270X_DT-Add-at86rf233-overlay.patch b/target/linux/brcm2708/patches-4.4/0110-BCM270X_DT-Add-at86rf233-overlay.patch
new file mode 100644
index 0000000000..c9453a6101
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0110-BCM270X_DT-Add-at86rf233-overlay.patch
@@ -0,0 +1,130 @@
+From 7a9f95c67cbfc0975e1109b904ad03e061fb6877 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 5 Oct 2015 10:47:45 +0100
+Subject: [PATCH 110/381] BCM270X_DT: Add at86rf233 overlay
+
+Add an overlay to support the Atmel AT86RF233 WPAN transceiver on spi0.0.
+
+See: https://github.com/raspberrypi/linux/issues/1151
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 21 +++++++--
+ arch/arm/boot/dts/overlays/at86rf233-overlay.dts | 54 ++++++++++++++++++++++++
+ 3 files changed, 72 insertions(+), 4 deletions(-)
+ create mode 100644 arch/arm/boot/dts/overlays/at86rf233-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -13,6 +13,7 @@ ifeq ($(CONFIG_ARCH_BCM2835),y)
+ endif
+
+ dtb-$(RPI_DT_OVERLAYS) += ads7846-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += at86rf233-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += bmp085_i2c-sensor-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += dht11-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += enc28j60-overlay.dtb
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -69,13 +69,14 @@ DT parameters:
+
+ Parameters always have default values, although in some cases (e.g. "w1-gpio")
+ it is necessary to provided multiple overlays in order to get the desired
+-behaviour. See the list of overlays below for a description of the parameters and their defaults.
++behaviour. See the list of overlays below for a description of the parameters
++and their defaults.
+
+ The Overlay and Parameter Reference
+ ===================================
+
+-N.B. When editing this file, please preserve the indentation levels to make it simple to parse
+-programmatically. NO HARD TABS.
++N.B. When editing this file, please preserve the indentation levels to make it
++simple to parse programmatically. NO HARD TABS.
+
+
+ Name: <The base DTB>
+@@ -149,7 +150,7 @@ Name: ads7846
+ Info: ADS7846 Touch controller
+ Load: dtoverlay=ads7846,<param>=<val>
+ Params: cs SPI bus Chip Select (default 1)
+- speed SPI bus speed (default 2Mhz, max 3.25MHz)
++ speed SPI bus speed (default 2MHz, max 3.25MHz)
+ penirq GPIO used for PENIRQ. REQUIRED
+ penirq_pull Set GPIO pull (default 0=none, 2=pullup)
+ swapxy Swap x and y axis
+@@ -170,6 +171,18 @@ Params: cs SPI bus
+ www.kernel.org/doc/Documentation/devicetree/bindings/input/ads7846.txt
+
+
++Name: at86rf233
++Info: Configures the Atmel AT86RF233 802.15.4 low-power WPAN transceiver,
++ connected to spi0.0
++Load: dtoverlay=at86rf233,<param>=<val>
++Params: interrupt GPIO used for INT (default 23)
++ reset GPIO used for Reset (default 24)
++ sleep GPIO used for Sleep (default 25)
++ speed SPI bus speed in Hz (default 6000000)
++ trim Fine tuning of the internal capacitance
++ arrays (0=+0pF, 15=+4.5pF, default 15)
++
++
+ Name: bmp085_i2c-sensor
+ Info: Configures the BMP085/BMP180 digital barometric pressure and temperature
+ sensors from Bosch Sensortec
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/at86rf233-overlay.dts
+@@ -0,0 +1,54 @@
++/dts-v1/;
++/plugin/;
++
++/* Overlay for Atmel AT86RF233 IEEE 802.15.4 WPAN transceiver on spi0.0 */
++
++/ {
++ compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709";
++
++ fragment@0 {
++ target = <&spi0>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ status = "okay";
++
++ spidev@0{
++ status = "disabled";
++ };
++
++ lowpan0: at86rf233@0 {
++ compatible = "atmel,at86rf233";
++ reg = <0>;
++ interrupt-parent = <&gpio>;
++ interrupts = <23 4>; /* active high */
++ reset-gpio = <&gpio 24 1>;
++ sleep-gpio = <&gpio 25 1>;
++ spi-max-frequency = <6000000>;
++ xtal-trim = /bits/ 8 <0xf>;
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ lowpan0_pins: lowpan0_pins {
++ brcm,pins = <23 24 25>;
++ brcm,function = <0 1 1>; /* in out out */
++ };
++ };
++ };
++
++ __overrides__ {
++ interrupt = <&lowpan0>, "interrupts:0",
++ <&lowpan0_pins>, "brcm,pins:0";
++ reset = <&lowpan0>, "reset-gpio:4",
++ <&lowpan0_pins>, "brcm,pins:4";
++ sleep = <&lowpan0>, "sleep-gpio:4",
++ <&lowpan0_pins>, "brcm,pins:8";
++ speed = <&lowpan0>, "spi-max-frequency:0";
++ trim = <&lowpan0>, "xtal-trim.0";
++ };
++};
diff --git a/target/linux/brcm2708/patches-4.4/0111-BCM270X_DT-Add-at86rf233-overlay.patch b/target/linux/brcm2708/patches-4.4/0111-BCM270X_DT-Add-at86rf233-overlay.patch
deleted file mode 100644
index cc7ec22567..0000000000
--- a/target/linux/brcm2708/patches-4.4/0111-BCM270X_DT-Add-at86rf233-overlay.patch
+++ /dev/null
@@ -1,130 +0,0 @@
-From 14b6c7013e62b3917ce73841dc8e379d011d37a5 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Mon, 5 Oct 2015 10:47:45 +0100
-Subject: [PATCH 111/170] BCM270X_DT: Add at86rf233 overlay
-
-Add an overlay to support the Atmel AT86RF233 WPAN transceiver on spi0.0.
-
-See: https://github.com/raspberrypi/linux/issues/1151
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 21 +++++++--
- arch/arm/boot/dts/overlays/at86rf233-overlay.dts | 54 ++++++++++++++++++++++++
- 3 files changed, 72 insertions(+), 4 deletions(-)
- create mode 100644 arch/arm/boot/dts/overlays/at86rf233-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -13,6 +13,7 @@ ifeq ($(CONFIG_ARCH_BCM2835),y)
- endif
-
- dtb-$(RPI_DT_OVERLAYS) += ads7846-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += at86rf233-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += bmp085_i2c-sensor-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += dht11-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += enc28j60-overlay.dtb
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -69,13 +69,14 @@ DT parameters:
-
- Parameters always have default values, although in some cases (e.g. "w1-gpio")
- it is necessary to provided multiple overlays in order to get the desired
--behaviour. See the list of overlays below for a description of the parameters and their defaults.
-+behaviour. See the list of overlays below for a description of the parameters
-+and their defaults.
-
- The Overlay and Parameter Reference
- ===================================
-
--N.B. When editing this file, please preserve the indentation levels to make it simple to parse
--programmatically. NO HARD TABS.
-+N.B. When editing this file, please preserve the indentation levels to make it
-+simple to parse programmatically. NO HARD TABS.
-
-
- Name: <The base DTB>
-@@ -149,7 +150,7 @@ Name: ads7846
- Info: ADS7846 Touch controller
- Load: dtoverlay=ads7846,<param>=<val>
- Params: cs SPI bus Chip Select (default 1)
-- speed SPI bus speed (default 2Mhz, max 3.25MHz)
-+ speed SPI bus speed (default 2MHz, max 3.25MHz)
- penirq GPIO used for PENIRQ. REQUIRED
- penirq_pull Set GPIO pull (default 0=none, 2=pullup)
- swapxy Swap x and y axis
-@@ -170,6 +171,18 @@ Params: cs SPI bus
- www.kernel.org/doc/Documentation/devicetree/bindings/input/ads7846.txt
-
-
-+Name: at86rf233
-+Info: Configures the Atmel AT86RF233 802.15.4 low-power WPAN transceiver,
-+ connected to spi0.0
-+Load: dtoverlay=at86rf233,<param>=<val>
-+Params: interrupt GPIO used for INT (default 23)
-+ reset GPIO used for Reset (default 24)
-+ sleep GPIO used for Sleep (default 25)
-+ speed SPI bus speed in Hz (default 6000000)
-+ trim Fine tuning of the internal capacitance
-+ arrays (0=+0pF, 15=+4.5pF, default 15)
-+
-+
- Name: bmp085_i2c-sensor
- Info: Configures the BMP085/BMP180 digital barometric pressure and temperature
- sensors from Bosch Sensortec
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/at86rf233-overlay.dts
-@@ -0,0 +1,54 @@
-+/dts-v1/;
-+/plugin/;
-+
-+/* Overlay for Atmel AT86RF233 IEEE 802.15.4 WPAN transceiver on spi0.0 */
-+
-+/ {
-+ compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709";
-+
-+ fragment@0 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ status = "okay";
-+
-+ spidev@0{
-+ status = "disabled";
-+ };
-+
-+ lowpan0: at86rf233@0 {
-+ compatible = "atmel,at86rf233";
-+ reg = <0>;
-+ interrupt-parent = <&gpio>;
-+ interrupts = <23 4>; /* active high */
-+ reset-gpio = <&gpio 24 1>;
-+ sleep-gpio = <&gpio 25 1>;
-+ spi-max-frequency = <6000000>;
-+ xtal-trim = /bits/ 8 <0xf>;
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ lowpan0_pins: lowpan0_pins {
-+ brcm,pins = <23 24 25>;
-+ brcm,function = <0 1 1>; /* in out out */
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ interrupt = <&lowpan0>, "interrupts:0",
-+ <&lowpan0_pins>, "brcm,pins:0";
-+ reset = <&lowpan0>, "reset-gpio:4",
-+ <&lowpan0_pins>, "brcm,pins:4";
-+ sleep = <&lowpan0>, "sleep-gpio:4",
-+ <&lowpan0_pins>, "brcm,pins:8";
-+ speed = <&lowpan0>, "spi-max-frequency:0";
-+ trim = <&lowpan0>, "xtal-trim.0";
-+ };
-+};
diff --git a/target/linux/brcm2708/patches-4.4/0111-mm-Remove-the-PFN-busy-warning.patch b/target/linux/brcm2708/patches-4.4/0111-mm-Remove-the-PFN-busy-warning.patch
new file mode 100644
index 0000000000..197c87824c
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0111-mm-Remove-the-PFN-busy-warning.patch
@@ -0,0 +1,25 @@
+From c9d6f1cb070a832bd49f381dbcc2b7e03c325a6a Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Thu, 18 Dec 2014 16:07:15 -0800
+Subject: [PATCH 111/381] mm: Remove the PFN busy warning
+
+See commit dae803e165a11bc88ca8dbc07a11077caf97bbcb -- the warning is
+expected sometimes when using CMA. However, that commit still spams
+my kernel log with these warnings.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ mm/page_alloc.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/mm/page_alloc.c
++++ b/mm/page_alloc.c
+@@ -6780,8 +6780,6 @@ int alloc_contig_range(unsigned long sta
+
+ /* Make sure the range is really isolated. */
+ if (test_pages_isolated(outer_start, end, false)) {
+- pr_info("%s: [%lx, %lx) PFNs busy\n",
+- __func__, outer_start, end);
+ ret = -EBUSY;
+ goto done;
+ }
diff --git a/target/linux/brcm2708/patches-4.4/0112-drm-Put-an-optional-field-in-the-driver-struct-for-G.patch b/target/linux/brcm2708/patches-4.4/0112-drm-Put-an-optional-field-in-the-driver-struct-for-G.patch
new file mode 100644
index 0000000000..643b8ff12e
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0112-drm-Put-an-optional-field-in-the-driver-struct-for-G.patch
@@ -0,0 +1,40 @@
+From 51c3910db1015b46ce2a3973cf10ba8e61514821 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Wed, 19 Nov 2014 12:06:38 -0800
+Subject: [PATCH 112/381] drm: Put an optional field in the driver struct for
+ GEM obj struct size.
+
+This allows a driver to derive from the CMA object without copying all
+of the code.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/drm_gem_cma_helper.c | 5 ++++-
+ include/drm/drmP.h | 1 +
+ 2 files changed, 5 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/drm_gem_cma_helper.c
++++ b/drivers/gpu/drm/drm_gem_cma_helper.c
+@@ -58,8 +58,11 @@ __drm_gem_cma_create(struct drm_device *
+ struct drm_gem_cma_object *cma_obj;
+ struct drm_gem_object *gem_obj;
+ int ret;
++ size_t obj_size = (drm->driver->gem_obj_size ?
++ drm->driver->gem_obj_size :
++ sizeof(*cma_obj));
+
+- cma_obj = kzalloc(sizeof(*cma_obj), GFP_KERNEL);
++ cma_obj = kzalloc(obj_size, GFP_KERNEL);
+ if (!cma_obj)
+ return ERR_PTR(-ENOMEM);
+
+--- a/include/drm/drmP.h
++++ b/include/drm/drmP.h
+@@ -639,6 +639,7 @@ struct drm_driver {
+
+ u32 driver_features;
+ int dev_priv_size;
++ size_t gem_obj_size;
+ const struct drm_ioctl_desc *ioctls;
+ int num_ioctls;
+ const struct file_operations *fops;
diff --git a/target/linux/brcm2708/patches-4.4/0112-mm-Remove-the-PFN-busy-warning.patch b/target/linux/brcm2708/patches-4.4/0112-mm-Remove-the-PFN-busy-warning.patch
deleted file mode 100644
index a4f6ec19e3..0000000000
--- a/target/linux/brcm2708/patches-4.4/0112-mm-Remove-the-PFN-busy-warning.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-From d33b3717e86cd6aa28c58d465a22e6c11a66bc13 Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Thu, 18 Dec 2014 16:07:15 -0800
-Subject: [PATCH 112/170] mm: Remove the PFN busy warning
-
-See commit dae803e165a11bc88ca8dbc07a11077caf97bbcb -- the warning is
-expected sometimes when using CMA. However, that commit still spams
-my kernel log with these warnings.
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
----
- mm/page_alloc.c | 2 --
- 1 file changed, 2 deletions(-)
-
---- a/mm/page_alloc.c
-+++ b/mm/page_alloc.c
-@@ -6780,8 +6780,6 @@ int alloc_contig_range(unsigned long sta
-
- /* Make sure the range is really isolated. */
- if (test_pages_isolated(outer_start, end, false)) {
-- pr_info("%s: [%lx, %lx) PFNs busy\n",
-- __func__, outer_start, end);
- ret = -EBUSY;
- goto done;
- }
diff --git a/target/linux/brcm2708/patches-4.4/0113-drm-Put-an-optional-field-in-the-driver-struct-for-G.patch b/target/linux/brcm2708/patches-4.4/0113-drm-Put-an-optional-field-in-the-driver-struct-for-G.patch
deleted file mode 100644
index 775d46a553..0000000000
--- a/target/linux/brcm2708/patches-4.4/0113-drm-Put-an-optional-field-in-the-driver-struct-for-G.patch
+++ /dev/null
@@ -1,40 +0,0 @@
-From a71d6ebfcbc401e520fa4a5aa185d027dfbe5ce1 Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Wed, 19 Nov 2014 12:06:38 -0800
-Subject: [PATCH 113/170] drm: Put an optional field in the driver struct for
- GEM obj struct size.
-
-This allows a driver to derive from the CMA object without copying all
-of the code.
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
----
- drivers/gpu/drm/drm_gem_cma_helper.c | 5 ++++-
- include/drm/drmP.h | 1 +
- 2 files changed, 5 insertions(+), 1 deletion(-)
-
---- a/drivers/gpu/drm/drm_gem_cma_helper.c
-+++ b/drivers/gpu/drm/drm_gem_cma_helper.c
-@@ -58,8 +58,11 @@ __drm_gem_cma_create(struct drm_device *
- struct drm_gem_cma_object *cma_obj;
- struct drm_gem_object *gem_obj;
- int ret;
-+ size_t obj_size = (drm->driver->gem_obj_size ?
-+ drm->driver->gem_obj_size :
-+ sizeof(*cma_obj));
-
-- cma_obj = kzalloc(sizeof(*cma_obj), GFP_KERNEL);
-+ cma_obj = kzalloc(obj_size, GFP_KERNEL);
- if (!cma_obj)
- return ERR_PTR(-ENOMEM);
-
---- a/include/drm/drmP.h
-+++ b/include/drm/drmP.h
-@@ -639,6 +639,7 @@ struct drm_driver {
-
- u32 driver_features;
- int dev_priv_size;
-+ size_t gem_obj_size;
- const struct drm_ioctl_desc *ioctls;
- int num_ioctls;
- const struct file_operations *fops;
diff --git a/target/linux/brcm2708/patches-4.4/0113-drm-vc4-Add-an-interface-for-capturing-the-GPU-state.patch b/target/linux/brcm2708/patches-4.4/0113-drm-vc4-Add-an-interface-for-capturing-the-GPU-state.patch
new file mode 100644
index 0000000000..3cf0c25e3e
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0113-drm-vc4-Add-an-interface-for-capturing-the-GPU-state.patch
@@ -0,0 +1,333 @@
+From 04b14cd6be101594b46fedf0b5a50734ef55af1e Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Fri, 30 Oct 2015 10:09:02 -0700
+Subject: [PATCH 113/381] drm/vc4: Add an interface for capturing the GPU state
+ after a hang.
+
+This can be parsed with vc4-gpu-tools tools for trying to figure out
+what was going on.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_bo.c | 4 +-
+ drivers/gpu/drm/vc4/vc4_drv.c | 1 +
+ drivers/gpu/drm/vc4/vc4_drv.h | 4 +
+ drivers/gpu/drm/vc4/vc4_gem.c | 185 ++++++++++++++++++++++++++++++++++++++++++
+ include/uapi/drm/vc4_drm.h | 45 ++++++++++
+ 5 files changed, 237 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_bo.c
++++ b/drivers/gpu/drm/vc4/vc4_bo.c
+@@ -415,8 +415,8 @@ int vc4_mmap(struct file *filp, struct v
+ gem_obj = vma->vm_private_data;
+ bo = to_vc4_bo(gem_obj);
+
+- if (bo->validated_shader) {
+- DRM_ERROR("mmaping of shader BOs not allowed.\n");
++ if (bo->validated_shader && (vma->vm_flags & VM_WRITE)) {
++ DRM_ERROR("mmaping of shader BOs for writing not allowed.\n");
+ return -EINVAL;
+ }
+
+--- a/drivers/gpu/drm/vc4/vc4_drv.c
++++ b/drivers/gpu/drm/vc4/vc4_drv.c
+@@ -81,6 +81,7 @@ static const struct drm_ioctl_desc vc4_d
+ DRM_IOCTL_DEF_DRV(VC4_CREATE_BO, vc4_create_bo_ioctl, 0),
+ DRM_IOCTL_DEF_DRV(VC4_MMAP_BO, vc4_mmap_bo_ioctl, 0),
+ DRM_IOCTL_DEF_DRV(VC4_CREATE_SHADER_BO, vc4_create_shader_bo_ioctl, 0),
++ DRM_IOCTL_DEF_DRV(VC4_GET_HANG_STATE, vc4_get_hang_state_ioctl, DRM_ROOT_ONLY),
+ };
+
+ static struct drm_driver vc4_drm_driver = {
+--- a/drivers/gpu/drm/vc4/vc4_drv.h
++++ b/drivers/gpu/drm/vc4/vc4_drv.h
+@@ -20,6 +20,8 @@ struct vc4_dev {
+ struct drm_fbdev_cma *fbdev;
+ struct rpi_firmware *firmware;
+
++ struct vc4_hang_state *hang_state;
++
+ /* The kernel-space BO cache. Tracks buffers that have been
+ * unreferenced by all other users (refcounts of 0!) but not
+ * yet freed, so we can do cheap allocations.
+@@ -366,6 +368,8 @@ int vc4_create_shader_bo_ioctl(struct dr
+ struct drm_file *file_priv);
+ int vc4_mmap_bo_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
++int vc4_get_hang_state_ioctl(struct drm_device *dev, void *data,
++ struct drm_file *file_priv);
+ int vc4_mmap(struct file *filp, struct vm_area_struct *vma);
+ int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma);
+ void *vc4_prime_vmap(struct drm_gem_object *obj);
+--- a/drivers/gpu/drm/vc4/vc4_gem.c
++++ b/drivers/gpu/drm/vc4/vc4_gem.c
+@@ -40,6 +40,186 @@ vc4_queue_hangcheck(struct drm_device *d
+ round_jiffies_up(jiffies + msecs_to_jiffies(100)));
+ }
+
++struct vc4_hang_state {
++ struct drm_vc4_get_hang_state user_state;
++
++ u32 bo_count;
++ struct drm_gem_object **bo;
++};
++
++static void
++vc4_free_hang_state(struct drm_device *dev, struct vc4_hang_state *state)
++{
++ unsigned int i;
++
++ mutex_lock(&dev->struct_mutex);
++ for (i = 0; i < state->user_state.bo_count; i++) {
++ drm_gem_object_unreference(state->bo[i]);
++ }
++ mutex_unlock(&dev->struct_mutex);
++
++ kfree(state);
++}
++
++int
++vc4_get_hang_state_ioctl(struct drm_device *dev, void *data,
++ struct drm_file *file_priv)
++{
++ struct drm_vc4_get_hang_state *get_state = data;
++ struct drm_vc4_get_hang_state_bo *bo_state;
++ struct vc4_hang_state *kernel_state;
++ struct drm_vc4_get_hang_state *state;
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ unsigned long irqflags;
++ u32 i;
++ int ret;
++
++ spin_lock_irqsave(&vc4->job_lock, irqflags);
++ kernel_state = vc4->hang_state;
++ if (!kernel_state) {
++ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
++ return -ENOENT;
++ }
++ state = &kernel_state->user_state;
++
++ /* If the user's array isn't big enough, just return the
++ * required array size.
++ */
++ if (get_state->bo_count < state->bo_count) {
++ get_state->bo_count = state->bo_count;
++ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
++ return 0;
++ }
++
++ vc4->hang_state = NULL;
++ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
++
++ /* Save the user's BO pointer, so we don't stomp it with the memcpy. */
++ state->bo = get_state->bo;
++ memcpy(get_state, state, sizeof(*state));
++
++ bo_state = kcalloc(state->bo_count, sizeof(*bo_state), GFP_KERNEL);
++ if (!bo_state) {
++ ret = -ENOMEM;
++ goto err_free;
++ }
++
++ for (i = 0; i < state->bo_count; i++) {
++ struct vc4_bo *vc4_bo = to_vc4_bo(kernel_state->bo[i]);
++ u32 handle;
++ ret = drm_gem_handle_create(file_priv, kernel_state->bo[i],
++ &handle);
++
++ if (ret) {
++ state->bo_count = i - 1;
++ goto err;
++ }
++ bo_state[i].handle = handle;
++ bo_state[i].paddr = vc4_bo->base.paddr;
++ bo_state[i].size = vc4_bo->base.base.size;
++ }
++
++ ret = copy_to_user((void __user *)(uintptr_t)get_state->bo,
++ bo_state,
++ state->bo_count * sizeof(*bo_state));
++ kfree(bo_state);
++
++ err_free:
++
++ vc4_free_hang_state(dev, kernel_state);
++
++err:
++ return ret;
++}
++
++static void
++vc4_save_hang_state(struct drm_device *dev)
++{
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ struct drm_vc4_get_hang_state *state;
++ struct vc4_hang_state *kernel_state;
++ struct vc4_exec_info *exec;
++ struct vc4_bo *bo;
++ unsigned long irqflags;
++ unsigned int i, unref_list_count;
++
++ kernel_state = kcalloc(1, sizeof(*state), GFP_KERNEL);
++ if (!kernel_state)
++ return;
++
++ state = &kernel_state->user_state;
++
++ spin_lock_irqsave(&vc4->job_lock, irqflags);
++ exec = vc4_first_job(vc4);
++ if (!exec) {
++ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
++ return;
++ }
++
++ unref_list_count = 0;
++ list_for_each_entry(bo, &exec->unref_list, unref_head)
++ unref_list_count++;
++
++ state->bo_count = exec->bo_count + unref_list_count;
++ kernel_state->bo = kcalloc(state->bo_count, sizeof(*kernel_state->bo),
++ GFP_ATOMIC);
++ if (!kernel_state->bo) {
++ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
++ return;
++ }
++
++ for (i = 0; i < exec->bo_count; i++) {
++ drm_gem_object_reference(&exec->bo[i].bo->base);
++ kernel_state->bo[i] = &exec->bo[i].bo->base;
++ }
++
++ list_for_each_entry(bo, &exec->unref_list, unref_head) {
++ drm_gem_object_reference(&bo->base.base);
++ kernel_state->bo[i] = &bo->base.base;
++ i++;
++ }
++
++ state->start_bin = exec->ct0ca;
++ state->start_render = exec->ct1ca;
++
++ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
++
++ state->ct0ca = V3D_READ(V3D_CTNCA(0));
++ state->ct0ea = V3D_READ(V3D_CTNEA(0));
++
++ state->ct1ca = V3D_READ(V3D_CTNCA(1));
++ state->ct1ea = V3D_READ(V3D_CTNEA(1));
++
++ state->ct0cs = V3D_READ(V3D_CTNCS(0));
++ state->ct1cs = V3D_READ(V3D_CTNCS(1));
++
++ state->ct0ra0 = V3D_READ(V3D_CT00RA0);
++ state->ct1ra0 = V3D_READ(V3D_CT01RA0);
++
++ state->bpca = V3D_READ(V3D_BPCA);
++ state->bpcs = V3D_READ(V3D_BPCS);
++ state->bpoa = V3D_READ(V3D_BPOA);
++ state->bpos = V3D_READ(V3D_BPOS);
++
++ state->vpmbase = V3D_READ(V3D_VPMBASE);
++
++ state->dbge = V3D_READ(V3D_DBGE);
++ state->fdbgo = V3D_READ(V3D_FDBGO);
++ state->fdbgb = V3D_READ(V3D_FDBGB);
++ state->fdbgr = V3D_READ(V3D_FDBGR);
++ state->fdbgs = V3D_READ(V3D_FDBGS);
++ state->errstat = V3D_READ(V3D_ERRSTAT);
++
++ spin_lock_irqsave(&vc4->job_lock, irqflags);
++ if (vc4->hang_state) {
++ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
++ vc4_free_hang_state(dev, kernel_state);
++ } else {
++ vc4->hang_state = kernel_state;
++ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
++ }
++}
++
+ static void
+ vc4_reset(struct drm_device *dev)
+ {
+@@ -64,6 +244,8 @@ vc4_reset_work(struct work_struct *work)
+ struct vc4_dev *vc4 =
+ container_of(work, struct vc4_dev, hangcheck.reset_work);
+
++ vc4_save_hang_state(vc4->dev);
++
+ vc4_reset(vc4->dev);
+ }
+
+@@ -673,4 +855,7 @@ vc4_gem_destroy(struct drm_device *dev)
+ }
+
+ vc4_bo_cache_destroy(dev);
++
++ if (vc4->hang_state)
++ vc4_free_hang_state(dev, vc4->hang_state);
+ }
+--- a/include/uapi/drm/vc4_drm.h
++++ b/include/uapi/drm/vc4_drm.h
+@@ -32,6 +32,7 @@
+ #define DRM_VC4_CREATE_BO 0x03
+ #define DRM_VC4_MMAP_BO 0x04
+ #define DRM_VC4_CREATE_SHADER_BO 0x05
++#define DRM_VC4_GET_HANG_STATE 0x06
+
+ #define DRM_IOCTL_VC4_SUBMIT_CL DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_SUBMIT_CL, struct drm_vc4_submit_cl)
+ #define DRM_IOCTL_VC4_WAIT_SEQNO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_WAIT_SEQNO, struct drm_vc4_wait_seqno)
+@@ -39,6 +40,7 @@
+ #define DRM_IOCTL_VC4_CREATE_BO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_CREATE_BO, struct drm_vc4_create_bo)
+ #define DRM_IOCTL_VC4_MMAP_BO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_MMAP_BO, struct drm_vc4_mmap_bo)
+ #define DRM_IOCTL_VC4_CREATE_SHADER_BO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_CREATE_SHADER_BO, struct drm_vc4_create_shader_bo)
++#define DRM_IOCTL_VC4_GET_HANG_STATE DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_GET_HANG_STATE, struct drm_vc4_get_hang_state)
+
+ struct drm_vc4_submit_rcl_surface {
+ uint32_t hindex; /* Handle index, or ~0 if not present. */
+@@ -226,4 +228,47 @@ struct drm_vc4_mmap_bo {
+ uint64_t offset;
+ };
+
++struct drm_vc4_get_hang_state_bo {
++ uint32_t handle;
++ uint32_t paddr;
++ uint32_t size;
++ uint32_t pad;
++};
++
++/**
++ * struct drm_vc4_hang_state - ioctl argument for collecting state
++ * from a GPU hang for analysis.
++*/
++struct drm_vc4_get_hang_state {
++ /** Pointer to array of struct drm_vc4_get_hang_state_bo. */
++ uint64_t bo;
++ /**
++ * On input, the size of the bo array. Output is the number
++ * of bos to be returned.
++ */
++ uint32_t bo_count;
++
++ uint32_t start_bin, start_render;
++
++ uint32_t ct0ca, ct0ea;
++ uint32_t ct1ca, ct1ea;
++ uint32_t ct0cs, ct1cs;
++ uint32_t ct0ra0, ct1ra0;
++
++ uint32_t bpca, bpcs;
++ uint32_t bpoa, bpos;
++
++ uint32_t vpmbase;
++
++ uint32_t dbge;
++ uint32_t fdbgo;
++ uint32_t fdbgb;
++ uint32_t fdbgr;
++ uint32_t fdbgs;
++ uint32_t errstat;
++
++ /* Pad that we may save more registers into in the future. */
++ uint32_t pad[16];
++};
++
+ #endif /* _UAPI_VC4_DRM_H_ */
diff --git a/target/linux/brcm2708/patches-4.4/0114-drm-vc4-Add-an-interface-for-capturing-the-GPU-state.patch b/target/linux/brcm2708/patches-4.4/0114-drm-vc4-Add-an-interface-for-capturing-the-GPU-state.patch
deleted file mode 100644
index 3e40eb646c..0000000000
--- a/target/linux/brcm2708/patches-4.4/0114-drm-vc4-Add-an-interface-for-capturing-the-GPU-state.patch
+++ /dev/null
@@ -1,333 +0,0 @@
-From 1c343ed1f86866d2625518774536bbef77f7a20a Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Fri, 30 Oct 2015 10:09:02 -0700
-Subject: [PATCH 114/170] drm/vc4: Add an interface for capturing the GPU state
- after a hang.
-
-This can be parsed with vc4-gpu-tools tools for trying to figure out
-what was going on.
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
----
- drivers/gpu/drm/vc4/vc4_bo.c | 4 +-
- drivers/gpu/drm/vc4/vc4_drv.c | 1 +
- drivers/gpu/drm/vc4/vc4_drv.h | 4 +
- drivers/gpu/drm/vc4/vc4_gem.c | 185 ++++++++++++++++++++++++++++++++++++++++++
- include/uapi/drm/vc4_drm.h | 45 ++++++++++
- 5 files changed, 237 insertions(+), 2 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_bo.c
-+++ b/drivers/gpu/drm/vc4/vc4_bo.c
-@@ -415,8 +415,8 @@ int vc4_mmap(struct file *filp, struct v
- gem_obj = vma->vm_private_data;
- bo = to_vc4_bo(gem_obj);
-
-- if (bo->validated_shader) {
-- DRM_ERROR("mmaping of shader BOs not allowed.\n");
-+ if (bo->validated_shader && (vma->vm_flags & VM_WRITE)) {
-+ DRM_ERROR("mmaping of shader BOs for writing not allowed.\n");
- return -EINVAL;
- }
-
---- a/drivers/gpu/drm/vc4/vc4_drv.c
-+++ b/drivers/gpu/drm/vc4/vc4_drv.c
-@@ -81,6 +81,7 @@ static const struct drm_ioctl_desc vc4_d
- DRM_IOCTL_DEF_DRV(VC4_CREATE_BO, vc4_create_bo_ioctl, 0),
- DRM_IOCTL_DEF_DRV(VC4_MMAP_BO, vc4_mmap_bo_ioctl, 0),
- DRM_IOCTL_DEF_DRV(VC4_CREATE_SHADER_BO, vc4_create_shader_bo_ioctl, 0),
-+ DRM_IOCTL_DEF_DRV(VC4_GET_HANG_STATE, vc4_get_hang_state_ioctl, DRM_ROOT_ONLY),
- };
-
- static struct drm_driver vc4_drm_driver = {
---- a/drivers/gpu/drm/vc4/vc4_drv.h
-+++ b/drivers/gpu/drm/vc4/vc4_drv.h
-@@ -20,6 +20,8 @@ struct vc4_dev {
- struct drm_fbdev_cma *fbdev;
- struct rpi_firmware *firmware;
-
-+ struct vc4_hang_state *hang_state;
-+
- /* The kernel-space BO cache. Tracks buffers that have been
- * unreferenced by all other users (refcounts of 0!) but not
- * yet freed, so we can do cheap allocations.
-@@ -366,6 +368,8 @@ int vc4_create_shader_bo_ioctl(struct dr
- struct drm_file *file_priv);
- int vc4_mmap_bo_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
-+int vc4_get_hang_state_ioctl(struct drm_device *dev, void *data,
-+ struct drm_file *file_priv);
- int vc4_mmap(struct file *filp, struct vm_area_struct *vma);
- int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma);
- void *vc4_prime_vmap(struct drm_gem_object *obj);
---- a/drivers/gpu/drm/vc4/vc4_gem.c
-+++ b/drivers/gpu/drm/vc4/vc4_gem.c
-@@ -40,6 +40,186 @@ vc4_queue_hangcheck(struct drm_device *d
- round_jiffies_up(jiffies + msecs_to_jiffies(100)));
- }
-
-+struct vc4_hang_state {
-+ struct drm_vc4_get_hang_state user_state;
-+
-+ u32 bo_count;
-+ struct drm_gem_object **bo;
-+};
-+
-+static void
-+vc4_free_hang_state(struct drm_device *dev, struct vc4_hang_state *state)
-+{
-+ unsigned int i;
-+
-+ mutex_lock(&dev->struct_mutex);
-+ for (i = 0; i < state->user_state.bo_count; i++) {
-+ drm_gem_object_unreference(state->bo[i]);
-+ }
-+ mutex_unlock(&dev->struct_mutex);
-+
-+ kfree(state);
-+}
-+
-+int
-+vc4_get_hang_state_ioctl(struct drm_device *dev, void *data,
-+ struct drm_file *file_priv)
-+{
-+ struct drm_vc4_get_hang_state *get_state = data;
-+ struct drm_vc4_get_hang_state_bo *bo_state;
-+ struct vc4_hang_state *kernel_state;
-+ struct drm_vc4_get_hang_state *state;
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+ unsigned long irqflags;
-+ u32 i;
-+ int ret;
-+
-+ spin_lock_irqsave(&vc4->job_lock, irqflags);
-+ kernel_state = vc4->hang_state;
-+ if (!kernel_state) {
-+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
-+ return -ENOENT;
-+ }
-+ state = &kernel_state->user_state;
-+
-+ /* If the user's array isn't big enough, just return the
-+ * required array size.
-+ */
-+ if (get_state->bo_count < state->bo_count) {
-+ get_state->bo_count = state->bo_count;
-+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
-+ return 0;
-+ }
-+
-+ vc4->hang_state = NULL;
-+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
-+
-+ /* Save the user's BO pointer, so we don't stomp it with the memcpy. */
-+ state->bo = get_state->bo;
-+ memcpy(get_state, state, sizeof(*state));
-+
-+ bo_state = kcalloc(state->bo_count, sizeof(*bo_state), GFP_KERNEL);
-+ if (!bo_state) {
-+ ret = -ENOMEM;
-+ goto err_free;
-+ }
-+
-+ for (i = 0; i < state->bo_count; i++) {
-+ struct vc4_bo *vc4_bo = to_vc4_bo(kernel_state->bo[i]);
-+ u32 handle;
-+ ret = drm_gem_handle_create(file_priv, kernel_state->bo[i],
-+ &handle);
-+
-+ if (ret) {
-+ state->bo_count = i - 1;
-+ goto err;
-+ }
-+ bo_state[i].handle = handle;
-+ bo_state[i].paddr = vc4_bo->base.paddr;
-+ bo_state[i].size = vc4_bo->base.base.size;
-+ }
-+
-+ ret = copy_to_user((void __user *)(uintptr_t)get_state->bo,
-+ bo_state,
-+ state->bo_count * sizeof(*bo_state));
-+ kfree(bo_state);
-+
-+ err_free:
-+
-+ vc4_free_hang_state(dev, kernel_state);
-+
-+err:
-+ return ret;
-+}
-+
-+static void
-+vc4_save_hang_state(struct drm_device *dev)
-+{
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+ struct drm_vc4_get_hang_state *state;
-+ struct vc4_hang_state *kernel_state;
-+ struct vc4_exec_info *exec;
-+ struct vc4_bo *bo;
-+ unsigned long irqflags;
-+ unsigned int i, unref_list_count;
-+
-+ kernel_state = kcalloc(1, sizeof(*state), GFP_KERNEL);
-+ if (!kernel_state)
-+ return;
-+
-+ state = &kernel_state->user_state;
-+
-+ spin_lock_irqsave(&vc4->job_lock, irqflags);
-+ exec = vc4_first_job(vc4);
-+ if (!exec) {
-+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
-+ return;
-+ }
-+
-+ unref_list_count = 0;
-+ list_for_each_entry(bo, &exec->unref_list, unref_head)
-+ unref_list_count++;
-+
-+ state->bo_count = exec->bo_count + unref_list_count;
-+ kernel_state->bo = kcalloc(state->bo_count, sizeof(*kernel_state->bo),
-+ GFP_ATOMIC);
-+ if (!kernel_state->bo) {
-+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
-+ return;
-+ }
-+
-+ for (i = 0; i < exec->bo_count; i++) {
-+ drm_gem_object_reference(&exec->bo[i].bo->base);
-+ kernel_state->bo[i] = &exec->bo[i].bo->base;
-+ }
-+
-+ list_for_each_entry(bo, &exec->unref_list, unref_head) {
-+ drm_gem_object_reference(&bo->base.base);
-+ kernel_state->bo[i] = &bo->base.base;
-+ i++;
-+ }
-+
-+ state->start_bin = exec->ct0ca;
-+ state->start_render = exec->ct1ca;
-+
-+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
-+
-+ state->ct0ca = V3D_READ(V3D_CTNCA(0));
-+ state->ct0ea = V3D_READ(V3D_CTNEA(0));
-+
-+ state->ct1ca = V3D_READ(V3D_CTNCA(1));
-+ state->ct1ea = V3D_READ(V3D_CTNEA(1));
-+
-+ state->ct0cs = V3D_READ(V3D_CTNCS(0));
-+ state->ct1cs = V3D_READ(V3D_CTNCS(1));
-+
-+ state->ct0ra0 = V3D_READ(V3D_CT00RA0);
-+ state->ct1ra0 = V3D_READ(V3D_CT01RA0);
-+
-+ state->bpca = V3D_READ(V3D_BPCA);
-+ state->bpcs = V3D_READ(V3D_BPCS);
-+ state->bpoa = V3D_READ(V3D_BPOA);
-+ state->bpos = V3D_READ(V3D_BPOS);
-+
-+ state->vpmbase = V3D_READ(V3D_VPMBASE);
-+
-+ state->dbge = V3D_READ(V3D_DBGE);
-+ state->fdbgo = V3D_READ(V3D_FDBGO);
-+ state->fdbgb = V3D_READ(V3D_FDBGB);
-+ state->fdbgr = V3D_READ(V3D_FDBGR);
-+ state->fdbgs = V3D_READ(V3D_FDBGS);
-+ state->errstat = V3D_READ(V3D_ERRSTAT);
-+
-+ spin_lock_irqsave(&vc4->job_lock, irqflags);
-+ if (vc4->hang_state) {
-+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
-+ vc4_free_hang_state(dev, kernel_state);
-+ } else {
-+ vc4->hang_state = kernel_state;
-+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
-+ }
-+}
-+
- static void
- vc4_reset(struct drm_device *dev)
- {
-@@ -64,6 +244,8 @@ vc4_reset_work(struct work_struct *work)
- struct vc4_dev *vc4 =
- container_of(work, struct vc4_dev, hangcheck.reset_work);
-
-+ vc4_save_hang_state(vc4->dev);
-+
- vc4_reset(vc4->dev);
- }
-
-@@ -673,4 +855,7 @@ vc4_gem_destroy(struct drm_device *dev)
- }
-
- vc4_bo_cache_destroy(dev);
-+
-+ if (vc4->hang_state)
-+ vc4_free_hang_state(dev, vc4->hang_state);
- }
---- a/include/uapi/drm/vc4_drm.h
-+++ b/include/uapi/drm/vc4_drm.h
-@@ -32,6 +32,7 @@
- #define DRM_VC4_CREATE_BO 0x03
- #define DRM_VC4_MMAP_BO 0x04
- #define DRM_VC4_CREATE_SHADER_BO 0x05
-+#define DRM_VC4_GET_HANG_STATE 0x06
-
- #define DRM_IOCTL_VC4_SUBMIT_CL DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_SUBMIT_CL, struct drm_vc4_submit_cl)
- #define DRM_IOCTL_VC4_WAIT_SEQNO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_WAIT_SEQNO, struct drm_vc4_wait_seqno)
-@@ -39,6 +40,7 @@
- #define DRM_IOCTL_VC4_CREATE_BO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_CREATE_BO, struct drm_vc4_create_bo)
- #define DRM_IOCTL_VC4_MMAP_BO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_MMAP_BO, struct drm_vc4_mmap_bo)
- #define DRM_IOCTL_VC4_CREATE_SHADER_BO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_CREATE_SHADER_BO, struct drm_vc4_create_shader_bo)
-+#define DRM_IOCTL_VC4_GET_HANG_STATE DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_GET_HANG_STATE, struct drm_vc4_get_hang_state)
-
- struct drm_vc4_submit_rcl_surface {
- uint32_t hindex; /* Handle index, or ~0 if not present. */
-@@ -226,4 +228,47 @@ struct drm_vc4_mmap_bo {
- uint64_t offset;
- };
-
-+struct drm_vc4_get_hang_state_bo {
-+ uint32_t handle;
-+ uint32_t paddr;
-+ uint32_t size;
-+ uint32_t pad;
-+};
-+
-+/**
-+ * struct drm_vc4_hang_state - ioctl argument for collecting state
-+ * from a GPU hang for analysis.
-+*/
-+struct drm_vc4_get_hang_state {
-+ /** Pointer to array of struct drm_vc4_get_hang_state_bo. */
-+ uint64_t bo;
-+ /**
-+ * On input, the size of the bo array. Output is the number
-+ * of bos to be returned.
-+ */
-+ uint32_t bo_count;
-+
-+ uint32_t start_bin, start_render;
-+
-+ uint32_t ct0ca, ct0ea;
-+ uint32_t ct1ca, ct1ea;
-+ uint32_t ct0cs, ct1cs;
-+ uint32_t ct0ra0, ct1ra0;
-+
-+ uint32_t bpca, bpcs;
-+ uint32_t bpoa, bpos;
-+
-+ uint32_t vpmbase;
-+
-+ uint32_t dbge;
-+ uint32_t fdbgo;
-+ uint32_t fdbgb;
-+ uint32_t fdbgr;
-+ uint32_t fdbgs;
-+ uint32_t errstat;
-+
-+ /* Pad that we may save more registers into in the future. */
-+ uint32_t pad[16];
-+};
-+
- #endif /* _UAPI_VC4_DRM_H_ */
diff --git a/target/linux/brcm2708/patches-4.4/0114-drm-vc4-Update-a-bunch-of-code-to-match-upstream-sub.patch b/target/linux/brcm2708/patches-4.4/0114-drm-vc4-Update-a-bunch-of-code-to-match-upstream-sub.patch
new file mode 100644
index 0000000000..4193a16eaf
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0114-drm-vc4-Update-a-bunch-of-code-to-match-upstream-sub.patch
@@ -0,0 +1,1894 @@
+From 75f8451653673c272e11dea1c49522424a6b748c Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Fri, 4 Dec 2015 11:35:34 -0800
+Subject: [PATCH 114/381] drm/vc4: Update a bunch of code to match upstream
+ submission.
+
+This gets almost everything matching, except for the MSAA support and
+using generic PM domains.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/drm_gem_cma_helper.c | 13 +-
+ drivers/gpu/drm/vc4/vc4_bo.c | 322 +++++++++++++++++------------
+ drivers/gpu/drm/vc4/vc4_crtc.c | 7 +-
+ drivers/gpu/drm/vc4/vc4_drv.c | 6 +-
+ drivers/gpu/drm/vc4/vc4_drv.h | 20 +-
+ drivers/gpu/drm/vc4/vc4_gem.c | 24 ++-
+ drivers/gpu/drm/vc4/vc4_irq.c | 5 +-
+ drivers/gpu/drm/vc4/vc4_kms.c | 1 +
+ drivers/gpu/drm/vc4/vc4_packet.h | 210 +++++++++----------
+ drivers/gpu/drm/vc4/vc4_qpu_defines.h | 308 ++++++++++++++-------------
+ drivers/gpu/drm/vc4/vc4_render_cl.c | 4 +-
+ drivers/gpu/drm/vc4/vc4_v3d.c | 10 +-
+ drivers/gpu/drm/vc4/vc4_validate.c | 130 ++++++------
+ drivers/gpu/drm/vc4/vc4_validate_shaders.c | 66 +++---
+ include/drm/drmP.h | 8 +-
+ 15 files changed, 598 insertions(+), 536 deletions(-)
+
+--- a/drivers/gpu/drm/drm_gem_cma_helper.c
++++ b/drivers/gpu/drm/drm_gem_cma_helper.c
+@@ -58,15 +58,14 @@ __drm_gem_cma_create(struct drm_device *
+ struct drm_gem_cma_object *cma_obj;
+ struct drm_gem_object *gem_obj;
+ int ret;
+- size_t obj_size = (drm->driver->gem_obj_size ?
+- drm->driver->gem_obj_size :
+- sizeof(*cma_obj));
+
+- cma_obj = kzalloc(obj_size, GFP_KERNEL);
+- if (!cma_obj)
++ if (drm->driver->gem_create_object)
++ gem_obj = drm->driver->gem_create_object(drm, size);
++ else
++ gem_obj = kzalloc(sizeof(*cma_obj), GFP_KERNEL);
++ if (!gem_obj)
+ return ERR_PTR(-ENOMEM);
+-
+- gem_obj = &cma_obj->base;
++ cma_obj = container_of(gem_obj, struct drm_gem_cma_object, base);
+
+ ret = drm_gem_object_init(drm, gem_obj, size);
+ if (ret)
+--- a/drivers/gpu/drm/vc4/vc4_bo.c
++++ b/drivers/gpu/drm/vc4/vc4_bo.c
+@@ -12,6 +12,10 @@
+ * access to system memory with no MMU in between. To support it, we
+ * use the GEM CMA helper functions to allocate contiguous ranges of
+ * physical memory for our BOs.
++ *
++ * Since the CMA allocator is very slow, we keep a cache of recently
++ * freed BOs around so that the kernel's allocation of objects for 3D
++ * rendering can return quickly.
+ */
+
+ #include "vc4_drv.h"
+@@ -34,6 +38,36 @@ static void vc4_bo_stats_dump(struct vc4
+ vc4->bo_stats.size_cached / 1024);
+ }
+
++#ifdef CONFIG_DEBUG_FS
++int vc4_bo_stats_debugfs(struct seq_file *m, void *unused)
++{
++ struct drm_info_node *node = (struct drm_info_node *)m->private;
++ struct drm_device *dev = node->minor->dev;
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ struct vc4_bo_stats stats;
++
++ /* Take a snapshot of the current stats with the lock held. */
++ mutex_lock(&vc4->bo_lock);
++ stats = vc4->bo_stats;
++ mutex_unlock(&vc4->bo_lock);
++
++ seq_printf(m, "num bos allocated: %d\n",
++ stats.num_allocated);
++ seq_printf(m, "size bos allocated: %dkb\n",
++ stats.size_allocated / 1024);
++ seq_printf(m, "num bos used: %d\n",
++ stats.num_allocated - stats.num_cached);
++ seq_printf(m, "size bos used: %dkb\n",
++ (stats.size_allocated - stats.size_cached) / 1024);
++ seq_printf(m, "num bos cached: %d\n",
++ stats.num_cached);
++ seq_printf(m, "size bos cached: %dkb\n",
++ stats.size_cached / 1024);
++
++ return 0;
++}
++#endif
++
+ static uint32_t bo_page_index(size_t size)
+ {
+ return (size / PAGE_SIZE) - 1;
+@@ -81,8 +115,8 @@ static struct list_head *vc4_get_cache_l
+ struct list_head *new_list;
+ uint32_t i;
+
+- new_list = kmalloc(new_size * sizeof(struct list_head),
+- GFP_KERNEL);
++ new_list = kmalloc_array(new_size, sizeof(struct list_head),
++ GFP_KERNEL);
+ if (!new_list)
+ return NULL;
+
+@@ -90,7 +124,9 @@ static struct list_head *vc4_get_cache_l
+ * head locations.
+ */
+ for (i = 0; i < vc4->bo_cache.size_list_size; i++) {
+- struct list_head *old_list = &vc4->bo_cache.size_list[i];
++ struct list_head *old_list =
++ &vc4->bo_cache.size_list[i];
++
+ if (list_empty(old_list))
+ INIT_LIST_HEAD(&new_list[i]);
+ else
+@@ -122,11 +158,60 @@ void vc4_bo_cache_purge(struct drm_devic
+ mutex_unlock(&vc4->bo_lock);
+ }
+
+-struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size)
++static struct vc4_bo *vc4_bo_get_from_cache(struct drm_device *dev,
++ uint32_t size)
+ {
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+- uint32_t size = roundup(unaligned_size, PAGE_SIZE);
+ uint32_t page_index = bo_page_index(size);
++ struct vc4_bo *bo = NULL;
++
++ size = roundup(size, PAGE_SIZE);
++
++ mutex_lock(&vc4->bo_lock);
++ if (page_index >= vc4->bo_cache.size_list_size)
++ goto out;
++
++ if (list_empty(&vc4->bo_cache.size_list[page_index]))
++ goto out;
++
++ bo = list_first_entry(&vc4->bo_cache.size_list[page_index],
++ struct vc4_bo, size_head);
++ vc4_bo_remove_from_cache(bo);
++ kref_init(&bo->base.base.refcount);
++
++out:
++ mutex_unlock(&vc4->bo_lock);
++ return bo;
++}
++
++/**
++ * vc4_gem_create_object - Implementation of driver->gem_create_object.
++ *
++ * This lets the CMA helpers allocate object structs for us, and keep
++ * our BO stats correct.
++ */
++struct drm_gem_object *vc4_create_object(struct drm_device *dev, size_t size)
++{
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ struct vc4_bo *bo;
++
++ bo = kzalloc(sizeof(*bo), GFP_KERNEL);
++ if (!bo)
++ return ERR_PTR(-ENOMEM);
++
++ mutex_lock(&vc4->bo_lock);
++ vc4->bo_stats.num_allocated++;
++ vc4->bo_stats.size_allocated += size;
++ mutex_unlock(&vc4->bo_lock);
++
++ return &bo->base.base;
++}
++
++struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size,
++ bool from_cache)
++{
++ size_t size = roundup(unaligned_size, PAGE_SIZE);
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ struct drm_gem_cma_object *cma_obj;
+ int pass;
+
+@@ -134,18 +219,12 @@ struct vc4_bo *vc4_bo_create(struct drm_
+ return NULL;
+
+ /* First, try to get a vc4_bo from the kernel BO cache. */
+- mutex_lock(&vc4->bo_lock);
+- if (page_index < vc4->bo_cache.size_list_size &&
+- !list_empty(&vc4->bo_cache.size_list[page_index])) {
+- struct vc4_bo *bo =
+- list_first_entry(&vc4->bo_cache.size_list[page_index],
+- struct vc4_bo, size_head);
+- vc4_bo_remove_from_cache(bo);
+- mutex_unlock(&vc4->bo_lock);
+- kref_init(&bo->base.base.refcount);
+- return bo;
++ if (from_cache) {
++ struct vc4_bo *bo = vc4_bo_get_from_cache(dev, size);
++
++ if (bo)
++ return bo;
+ }
+- mutex_unlock(&vc4->bo_lock);
+
+ /* Otherwise, make a new BO. */
+ for (pass = 0; ; pass++) {
+@@ -179,9 +258,6 @@ struct vc4_bo *vc4_bo_create(struct drm_
+ }
+ }
+
+- vc4->bo_stats.num_allocated++;
+- vc4->bo_stats.size_allocated += size;
+-
+ return to_vc4_bo(&cma_obj->base);
+ }
+
+@@ -199,7 +275,7 @@ int vc4_dumb_create(struct drm_file *fil
+ if (args->size < args->pitch * args->height)
+ args->size = args->pitch * args->height;
+
+- bo = vc4_bo_create(dev, args->size);
++ bo = vc4_bo_create(dev, args->size, false);
+ if (!bo)
+ return -ENOMEM;
+
+@@ -209,8 +285,8 @@ int vc4_dumb_create(struct drm_file *fil
+ return ret;
+ }
+
+-static void
+-vc4_bo_cache_free_old(struct drm_device *dev)
++/* Must be called with bo_lock held. */
++static void vc4_bo_cache_free_old(struct drm_device *dev)
+ {
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ unsigned long expire_time = jiffies - msecs_to_jiffies(1000);
+@@ -313,15 +389,77 @@ vc4_prime_export(struct drm_device *dev,
+ return drm_gem_prime_export(dev, obj, flags);
+ }
+
+-int
+-vc4_create_bo_ioctl(struct drm_device *dev, void *data,
+- struct drm_file *file_priv)
++int vc4_mmap(struct file *filp, struct vm_area_struct *vma)
++{
++ struct drm_gem_object *gem_obj;
++ struct vc4_bo *bo;
++ int ret;
++
++ ret = drm_gem_mmap(filp, vma);
++ if (ret)
++ return ret;
++
++ gem_obj = vma->vm_private_data;
++ bo = to_vc4_bo(gem_obj);
++
++ if (bo->validated_shader && (vma->vm_flags & VM_WRITE)) {
++ DRM_ERROR("mmaping of shader BOs for writing not allowed.\n");
++ return -EINVAL;
++ }
++
++ /*
++ * Clear the VM_PFNMAP flag that was set by drm_gem_mmap(), and set the
++ * vm_pgoff (used as a fake buffer offset by DRM) to 0 as we want to map
++ * the whole buffer.
++ */
++ vma->vm_flags &= ~VM_PFNMAP;
++ vma->vm_pgoff = 0;
++
++ ret = dma_mmap_writecombine(bo->base.base.dev->dev, vma,
++ bo->base.vaddr, bo->base.paddr,
++ vma->vm_end - vma->vm_start);
++ if (ret)
++ drm_gem_vm_close(vma);
++
++ return ret;
++}
++
++int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
++{
++ struct vc4_bo *bo = to_vc4_bo(obj);
++
++ if (bo->validated_shader && (vma->vm_flags & VM_WRITE)) {
++ DRM_ERROR("mmaping of shader BOs for writing not allowed.\n");
++ return -EINVAL;
++ }
++
++ return drm_gem_cma_prime_mmap(obj, vma);
++}
++
++void *vc4_prime_vmap(struct drm_gem_object *obj)
++{
++ struct vc4_bo *bo = to_vc4_bo(obj);
++
++ if (bo->validated_shader) {
++ DRM_ERROR("mmaping of shader BOs not allowed.\n");
++ return ERR_PTR(-EINVAL);
++ }
++
++ return drm_gem_cma_prime_vmap(obj);
++}
++
++int vc4_create_bo_ioctl(struct drm_device *dev, void *data,
++ struct drm_file *file_priv)
+ {
+ struct drm_vc4_create_bo *args = data;
+ struct vc4_bo *bo = NULL;
+ int ret;
+
+- bo = vc4_bo_create(dev, args->size);
++ /*
++ * We can't allocate from the BO cache, because the BOs don't
++ * get zeroed, and that might leak data between users.
++ */
++ bo = vc4_bo_create(dev, args->size, false);
+ if (!bo)
+ return -ENOMEM;
+
+@@ -331,6 +469,25 @@ vc4_create_bo_ioctl(struct drm_device *d
+ return ret;
+ }
+
++int vc4_mmap_bo_ioctl(struct drm_device *dev, void *data,
++ struct drm_file *file_priv)
++{
++ struct drm_vc4_mmap_bo *args = data;
++ struct drm_gem_object *gem_obj;
++
++ gem_obj = drm_gem_object_lookup(dev, file_priv, args->handle);
++ if (!gem_obj) {
++ DRM_ERROR("Failed to look up GEM BO %d\n", args->handle);
++ return -EINVAL;
++ }
++
++ /* The mmap offset was set up at BO allocation time. */
++ args->offset = drm_vma_node_offset_addr(&gem_obj->vma_node);
++
++ drm_gem_object_unreference_unlocked(gem_obj);
++ return 0;
++}
++
+ int
+ vc4_create_shader_bo_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+@@ -355,7 +512,7 @@ vc4_create_shader_bo_ioctl(struct drm_de
+ return -EINVAL;
+ }
+
+- bo = vc4_bo_create(dev, args->size);
++ bo = vc4_bo_create(dev, args->size, true);
+ if (!bo)
+ return -ENOMEM;
+
+@@ -364,6 +521,11 @@ vc4_create_shader_bo_ioctl(struct drm_de
+ args->size);
+ if (ret != 0)
+ goto fail;
++ /* Clear the rest of the memory from allocating from the BO
++ * cache.
++ */
++ memset(bo->base.vaddr + args->size, 0,
++ bo->base.base.size - args->size);
+
+ bo->validated_shader = vc4_validate_shader(&bo->base);
+ if (!bo->validated_shader) {
+@@ -382,85 +544,6 @@ vc4_create_shader_bo_ioctl(struct drm_de
+ return ret;
+ }
+
+-int
+-vc4_mmap_bo_ioctl(struct drm_device *dev, void *data,
+- struct drm_file *file_priv)
+-{
+- struct drm_vc4_mmap_bo *args = data;
+- struct drm_gem_object *gem_obj;
+-
+- gem_obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+- if (!gem_obj) {
+- DRM_ERROR("Failed to look up GEM BO %d\n", args->handle);
+- return -EINVAL;
+- }
+-
+- /* The mmap offset was set up at BO allocation time. */
+- args->offset = drm_vma_node_offset_addr(&gem_obj->vma_node);
+-
+- drm_gem_object_unreference(gem_obj);
+- return 0;
+-}
+-
+-int vc4_mmap(struct file *filp, struct vm_area_struct *vma)
+-{
+- struct drm_gem_object *gem_obj;
+- struct vc4_bo *bo;
+- int ret;
+-
+- ret = drm_gem_mmap(filp, vma);
+- if (ret)
+- return ret;
+-
+- gem_obj = vma->vm_private_data;
+- bo = to_vc4_bo(gem_obj);
+-
+- if (bo->validated_shader && (vma->vm_flags & VM_WRITE)) {
+- DRM_ERROR("mmaping of shader BOs for writing not allowed.\n");
+- return -EINVAL;
+- }
+-
+- /*
+- * Clear the VM_PFNMAP flag that was set by drm_gem_mmap(), and set the
+- * vm_pgoff (used as a fake buffer offset by DRM) to 0 as we want to map
+- * the whole buffer.
+- */
+- vma->vm_flags &= ~VM_PFNMAP;
+- vma->vm_pgoff = 0;
+-
+- ret = dma_mmap_writecombine(bo->base.base.dev->dev, vma,
+- bo->base.vaddr, bo->base.paddr,
+- vma->vm_end - vma->vm_start);
+- if (ret)
+- drm_gem_vm_close(vma);
+-
+- return ret;
+-}
+-
+-int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
+-{
+- struct vc4_bo *bo = to_vc4_bo(obj);
+-
+- if (bo->validated_shader) {
+- DRM_ERROR("mmaping of shader BOs not allowed.\n");
+- return -EINVAL;
+- }
+-
+- return drm_gem_cma_prime_mmap(obj, vma);
+-}
+-
+-void *vc4_prime_vmap(struct drm_gem_object *obj)
+-{
+- struct vc4_bo *bo = to_vc4_bo(obj);
+-
+- if (bo->validated_shader) {
+- DRM_ERROR("mmaping of shader BOs not allowed.\n");
+- return ERR_PTR(-EINVAL);
+- }
+-
+- return drm_gem_cma_prime_vmap(obj);
+-}
+-
+ void vc4_bo_cache_init(struct drm_device *dev)
+ {
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+@@ -472,7 +555,7 @@ void vc4_bo_cache_init(struct drm_device
+ INIT_WORK(&vc4->bo_cache.time_work, vc4_bo_cache_time_work);
+ setup_timer(&vc4->bo_cache.time_timer,
+ vc4_bo_cache_time_timer,
+- (unsigned long) dev);
++ (unsigned long)dev);
+ }
+
+ void vc4_bo_cache_destroy(struct drm_device *dev)
+@@ -489,28 +572,3 @@ void vc4_bo_cache_destroy(struct drm_dev
+ vc4_bo_stats_dump(vc4);
+ }
+ }
+-
+-#ifdef CONFIG_DEBUG_FS
+-int vc4_bo_stats_debugfs(struct seq_file *m, void *unused)
+-{
+- struct drm_info_node *node = (struct drm_info_node *) m->private;
+- struct drm_device *dev = node->minor->dev;
+- struct vc4_dev *vc4 = to_vc4_dev(dev);
+- struct vc4_bo_stats stats;
+-
+- mutex_lock(&vc4->bo_lock);
+- stats = vc4->bo_stats;
+- mutex_unlock(&vc4->bo_lock);
+-
+- seq_printf(m, "num bos allocated: %d\n", stats.num_allocated);
+- seq_printf(m, "size bos allocated: %dkb\n", stats.size_allocated / 1024);
+- seq_printf(m, "num bos used: %d\n", (stats.num_allocated -
+- stats.num_cached));
+- seq_printf(m, "size bos used: %dkb\n", (stats.size_allocated -
+- stats.size_cached) / 1024);
+- seq_printf(m, "num bos cached: %d\n", stats.num_cached);
+- seq_printf(m, "size bos cached: %dkb\n", stats.size_cached / 1024);
+-
+- return 0;
+-}
+-#endif
+--- a/drivers/gpu/drm/vc4/vc4_crtc.c
++++ b/drivers/gpu/drm/vc4/vc4_crtc.c
+@@ -501,6 +501,7 @@ vc4_async_page_flip_complete(struct vc4_
+ vc4_plane_async_set_fb(plane, flip_state->fb);
+ if (flip_state->event) {
+ unsigned long flags;
++
+ spin_lock_irqsave(&dev->event_lock, flags);
+ drm_crtc_send_vblank_event(crtc, flip_state->event);
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+@@ -562,9 +563,9 @@ static int vc4_async_page_flip(struct dr
+ }
+
+ static int vc4_page_flip(struct drm_crtc *crtc,
+- struct drm_framebuffer *fb,
+- struct drm_pending_vblank_event *event,
+- uint32_t flags)
++ struct drm_framebuffer *fb,
++ struct drm_pending_vblank_event *event,
++ uint32_t flags)
+ {
+ if (flags & DRM_MODE_PAGE_FLIP_ASYNC)
+ return vc4_async_page_flip(crtc, fb, event, flags);
+--- a/drivers/gpu/drm/vc4/vc4_drv.c
++++ b/drivers/gpu/drm/vc4/vc4_drv.c
+@@ -81,7 +81,8 @@ static const struct drm_ioctl_desc vc4_d
+ DRM_IOCTL_DEF_DRV(VC4_CREATE_BO, vc4_create_bo_ioctl, 0),
+ DRM_IOCTL_DEF_DRV(VC4_MMAP_BO, vc4_mmap_bo_ioctl, 0),
+ DRM_IOCTL_DEF_DRV(VC4_CREATE_SHADER_BO, vc4_create_shader_bo_ioctl, 0),
+- DRM_IOCTL_DEF_DRV(VC4_GET_HANG_STATE, vc4_get_hang_state_ioctl, DRM_ROOT_ONLY),
++ DRM_IOCTL_DEF_DRV(VC4_GET_HANG_STATE, vc4_get_hang_state_ioctl,
++ DRM_ROOT_ONLY),
+ };
+
+ static struct drm_driver vc4_drm_driver = {
+@@ -107,6 +108,7 @@ static struct drm_driver vc4_drm_driver
+ .debugfs_cleanup = vc4_debugfs_cleanup,
+ #endif
+
++ .gem_create_object = vc4_create_object,
+ .gem_free_object = vc4_free_object,
+ .gem_vm_ops = &drm_gem_cma_vm_ops,
+
+@@ -128,8 +130,6 @@ static struct drm_driver vc4_drm_driver
+ .num_ioctls = ARRAY_SIZE(vc4_drm_ioctls),
+ .fops = &vc4_drm_fops,
+
+- //.gem_obj_size = sizeof(struct vc4_bo),
+-
+ .name = DRIVER_NAME,
+ .desc = DRIVER_DESC,
+ .date = DRIVER_DATE,
+--- a/drivers/gpu/drm/vc4/vc4_drv.h
++++ b/drivers/gpu/drm/vc4/vc4_drv.h
+@@ -72,6 +72,9 @@ struct vc4_dev {
+ * job_done_work.
+ */
+ struct list_head job_done_list;
++ /* Spinlock used to synchronize the job_list and seqno
++ * accesses between the IRQ handler and GEM ioctls.
++ */
+ spinlock_t job_lock;
+ wait_queue_head_t job_wait_queue;
+ struct work_struct job_done_work;
+@@ -318,8 +321,7 @@ struct vc4_texture_sample_info {
+ * and validate the shader state record's uniforms that define the texture
+ * samples.
+ */
+-struct vc4_validated_shader_info
+-{
++struct vc4_validated_shader_info {
+ uint32_t uniforms_size;
+ uint32_t uniforms_src_size;
+ uint32_t num_texture_samples;
+@@ -355,8 +357,10 @@ struct vc4_validated_shader_info
+ #define wait_for(COND, MS) _wait_for(COND, MS, 1)
+
+ /* vc4_bo.c */
++struct drm_gem_object *vc4_create_object(struct drm_device *dev, size_t size);
+ void vc4_free_object(struct drm_gem_object *gem_obj);
+-struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t size);
++struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t size,
++ bool from_cache);
+ int vc4_dumb_create(struct drm_file *file_priv,
+ struct drm_device *dev,
+ struct drm_mode_create_dumb *args);
+@@ -432,7 +436,8 @@ struct drm_plane *vc4_plane_init(struct
+ enum drm_plane_type type);
+ u32 vc4_plane_write_dlist(struct drm_plane *plane, u32 __iomem *dlist);
+ u32 vc4_plane_dlist_size(struct drm_plane_state *state);
+-void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb);
++void vc4_plane_async_set_fb(struct drm_plane *plane,
++ struct drm_framebuffer *fb);
+
+ /* vc4_v3d.c */
+ extern struct platform_driver vc4_v3d_driver;
+@@ -450,9 +455,6 @@ vc4_validate_bin_cl(struct drm_device *d
+ int
+ vc4_validate_shader_recs(struct drm_device *dev, struct vc4_exec_info *exec);
+
+-struct vc4_validated_shader_info *
+-vc4_validate_shader(struct drm_gem_cma_object *shader_obj);
+-
+ bool vc4_use_bo(struct vc4_exec_info *exec,
+ uint32_t hindex,
+ enum vc4_bo_mode mode,
+@@ -464,3 +466,7 @@ bool vc4_check_tex_size(struct vc4_exec_
+ struct drm_gem_cma_object *fbo,
+ uint32_t offset, uint8_t tiling_format,
+ uint32_t width, uint32_t height, uint8_t cpp);
++
++/* vc4_validate_shader.c */
++struct vc4_validated_shader_info *
++vc4_validate_shader(struct drm_gem_cma_object *shader_obj);
+--- a/drivers/gpu/drm/vc4/vc4_gem.c
++++ b/drivers/gpu/drm/vc4/vc4_gem.c
+@@ -53,9 +53,8 @@ vc4_free_hang_state(struct drm_device *d
+ unsigned int i;
+
+ mutex_lock(&dev->struct_mutex);
+- for (i = 0; i < state->user_state.bo_count; i++) {
++ for (i = 0; i < state->user_state.bo_count; i++)
+ drm_gem_object_unreference(state->bo[i]);
+- }
+ mutex_unlock(&dev->struct_mutex);
+
+ kfree(state);
+@@ -65,10 +64,10 @@ int
+ vc4_get_hang_state_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+ {
+- struct drm_vc4_get_hang_state *get_state = data;
++ struct drm_vc4_get_hang_state *get_state = data;
+ struct drm_vc4_get_hang_state_bo *bo_state;
+ struct vc4_hang_state *kernel_state;
+- struct drm_vc4_get_hang_state *state;
++ struct drm_vc4_get_hang_state *state;
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ unsigned long irqflags;
+ u32 i;
+@@ -107,6 +106,7 @@ vc4_get_hang_state_ioctl(struct drm_devi
+ for (i = 0; i < state->bo_count; i++) {
+ struct vc4_bo *vc4_bo = to_vc4_bo(kernel_state->bo[i]);
+ u32 handle;
++
+ ret = drm_gem_handle_create(file_priv, kernel_state->bo[i],
+ &handle);
+
+@@ -124,7 +124,7 @@ vc4_get_hang_state_ioctl(struct drm_devi
+ state->bo_count * sizeof(*bo_state));
+ kfree(bo_state);
+
+- err_free:
++err_free:
+
+ vc4_free_hang_state(dev, kernel_state);
+
+@@ -578,7 +578,7 @@ vc4_get_bcl(struct drm_device *dev, stru
+ goto fail;
+ }
+
+- bo = vc4_bo_create(dev, exec_size);
++ bo = vc4_bo_create(dev, exec_size, true);
+ if (!bo) {
+ DRM_ERROR("Couldn't allocate BO for binning\n");
+ ret = PTR_ERR(exec->exec_bo);
+@@ -668,6 +668,7 @@ vc4_job_handle_completed(struct vc4_dev
+ static void vc4_seqno_cb_work(struct work_struct *work)
+ {
+ struct vc4_seqno_cb *cb = container_of(work, struct vc4_seqno_cb, work);
++
+ cb->func(cb);
+ }
+
+@@ -717,6 +718,7 @@ vc4_wait_for_seqno_ioctl_helper(struct d
+
+ if ((ret == -EINTR || ret == -ERESTARTSYS) && *timeout_ns != ~0ull) {
+ uint64_t delta = jiffies_to_nsecs(jiffies - start);
++
+ if (*timeout_ns >= delta)
+ *timeout_ns -= delta;
+ }
+@@ -750,9 +752,10 @@ vc4_wait_bo_ioctl(struct drm_device *dev
+ }
+ bo = to_vc4_bo(gem_obj);
+
+- ret = vc4_wait_for_seqno_ioctl_helper(dev, bo->seqno, &args->timeout_ns);
++ ret = vc4_wait_for_seqno_ioctl_helper(dev, bo->seqno,
++ &args->timeout_ns);
+
+- drm_gem_object_unreference(gem_obj);
++ drm_gem_object_unreference_unlocked(gem_obj);
+ return ret;
+ }
+
+@@ -793,7 +796,8 @@ vc4_submit_cl_ioctl(struct drm_device *d
+ if (ret)
+ goto fail;
+ } else {
+- exec->ct0ca = exec->ct0ea = 0;
++ exec->ct0ca = 0;
++ exec->ct0ea = 0;
+ }
+
+ ret = vc4_get_rcl(dev, exec);
+@@ -831,7 +835,7 @@ vc4_gem_init(struct drm_device *dev)
+ INIT_WORK(&vc4->hangcheck.reset_work, vc4_reset_work);
+ setup_timer(&vc4->hangcheck.timer,
+ vc4_hangcheck_elapsed,
+- (unsigned long) dev);
++ (unsigned long)dev);
+
+ INIT_WORK(&vc4->job_done_work, vc4_job_done_work);
+ }
+--- a/drivers/gpu/drm/vc4/vc4_irq.c
++++ b/drivers/gpu/drm/vc4/vc4_irq.c
+@@ -56,7 +56,7 @@ vc4_overflow_mem_work(struct work_struct
+ struct drm_device *dev = vc4->dev;
+ struct vc4_bo *bo;
+
+- bo = vc4_bo_create(dev, 256 * 1024);
++ bo = vc4_bo_create(dev, 256 * 1024, true);
+ if (!bo) {
+ DRM_ERROR("Couldn't allocate binner overflow mem\n");
+ return;
+@@ -87,9 +87,8 @@ vc4_overflow_mem_work(struct work_struct
+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+ }
+
+- if (vc4->overflow_mem) {
++ if (vc4->overflow_mem)
+ drm_gem_object_unreference_unlocked(&vc4->overflow_mem->base.base);
+- }
+ vc4->overflow_mem = bo;
+
+ V3D_WRITE(V3D_BPOA, bo->base.paddr);
+--- a/drivers/gpu/drm/vc4/vc4_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_kms.c
+@@ -132,6 +132,7 @@ static int vc4_atomic_commit(struct drm_
+ struct drm_gem_cma_object *cma_bo =
+ drm_fb_cma_get_gem_obj(new_state->fb, 0);
+ struct vc4_bo *bo = to_vc4_bo(&cma_bo->base);
++
+ wait_seqno = max(bo->seqno, wait_seqno);
+ }
+ }
+--- a/drivers/gpu/drm/vc4/vc4_packet.h
++++ b/drivers/gpu/drm/vc4/vc4_packet.h
+@@ -27,60 +27,60 @@
+ #include "vc4_regs.h" /* for VC4_MASK, VC4_GET_FIELD, VC4_SET_FIELD */
+
+ enum vc4_packet {
+- VC4_PACKET_HALT = 0,
+- VC4_PACKET_NOP = 1,
++ VC4_PACKET_HALT = 0,
++ VC4_PACKET_NOP = 1,
+
+- VC4_PACKET_FLUSH = 4,
+- VC4_PACKET_FLUSH_ALL = 5,
+- VC4_PACKET_START_TILE_BINNING = 6,
+- VC4_PACKET_INCREMENT_SEMAPHORE = 7,
+- VC4_PACKET_WAIT_ON_SEMAPHORE = 8,
+-
+- VC4_PACKET_BRANCH = 16,
+- VC4_PACKET_BRANCH_TO_SUB_LIST = 17,
+-
+- VC4_PACKET_STORE_MS_TILE_BUFFER = 24,
+- VC4_PACKET_STORE_MS_TILE_BUFFER_AND_EOF = 25,
+- VC4_PACKET_STORE_FULL_RES_TILE_BUFFER = 26,
+- VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER = 27,
+- VC4_PACKET_STORE_TILE_BUFFER_GENERAL = 28,
+- VC4_PACKET_LOAD_TILE_BUFFER_GENERAL = 29,
+-
+- VC4_PACKET_GL_INDEXED_PRIMITIVE = 32,
+- VC4_PACKET_GL_ARRAY_PRIMITIVE = 33,
+-
+- VC4_PACKET_COMPRESSED_PRIMITIVE = 48,
+- VC4_PACKET_CLIPPED_COMPRESSED_PRIMITIVE = 49,
+-
+- VC4_PACKET_PRIMITIVE_LIST_FORMAT = 56,
+-
+- VC4_PACKET_GL_SHADER_STATE = 64,
+- VC4_PACKET_NV_SHADER_STATE = 65,
+- VC4_PACKET_VG_SHADER_STATE = 66,
+-
+- VC4_PACKET_CONFIGURATION_BITS = 96,
+- VC4_PACKET_FLAT_SHADE_FLAGS = 97,
+- VC4_PACKET_POINT_SIZE = 98,
+- VC4_PACKET_LINE_WIDTH = 99,
+- VC4_PACKET_RHT_X_BOUNDARY = 100,
+- VC4_PACKET_DEPTH_OFFSET = 101,
+- VC4_PACKET_CLIP_WINDOW = 102,
+- VC4_PACKET_VIEWPORT_OFFSET = 103,
+- VC4_PACKET_Z_CLIPPING = 104,
+- VC4_PACKET_CLIPPER_XY_SCALING = 105,
+- VC4_PACKET_CLIPPER_Z_SCALING = 106,
+-
+- VC4_PACKET_TILE_BINNING_MODE_CONFIG = 112,
+- VC4_PACKET_TILE_RENDERING_MODE_CONFIG = 113,
+- VC4_PACKET_CLEAR_COLORS = 114,
+- VC4_PACKET_TILE_COORDINATES = 115,
+-
+- /* Not an actual hardware packet -- this is what we use to put
+- * references to GEM bos in the command stream, since we need the u32
+- * int the actual address packet in order to store the offset from the
+- * start of the BO.
+- */
+- VC4_PACKET_GEM_HANDLES = 254,
++ VC4_PACKET_FLUSH = 4,
++ VC4_PACKET_FLUSH_ALL = 5,
++ VC4_PACKET_START_TILE_BINNING = 6,
++ VC4_PACKET_INCREMENT_SEMAPHORE = 7,
++ VC4_PACKET_WAIT_ON_SEMAPHORE = 8,
++
++ VC4_PACKET_BRANCH = 16,
++ VC4_PACKET_BRANCH_TO_SUB_LIST = 17,
++
++ VC4_PACKET_STORE_MS_TILE_BUFFER = 24,
++ VC4_PACKET_STORE_MS_TILE_BUFFER_AND_EOF = 25,
++ VC4_PACKET_STORE_FULL_RES_TILE_BUFFER = 26,
++ VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER = 27,
++ VC4_PACKET_STORE_TILE_BUFFER_GENERAL = 28,
++ VC4_PACKET_LOAD_TILE_BUFFER_GENERAL = 29,
++
++ VC4_PACKET_GL_INDEXED_PRIMITIVE = 32,
++ VC4_PACKET_GL_ARRAY_PRIMITIVE = 33,
++
++ VC4_PACKET_COMPRESSED_PRIMITIVE = 48,
++ VC4_PACKET_CLIPPED_COMPRESSED_PRIMITIVE = 49,
++
++ VC4_PACKET_PRIMITIVE_LIST_FORMAT = 56,
++
++ VC4_PACKET_GL_SHADER_STATE = 64,
++ VC4_PACKET_NV_SHADER_STATE = 65,
++ VC4_PACKET_VG_SHADER_STATE = 66,
++
++ VC4_PACKET_CONFIGURATION_BITS = 96,
++ VC4_PACKET_FLAT_SHADE_FLAGS = 97,
++ VC4_PACKET_POINT_SIZE = 98,
++ VC4_PACKET_LINE_WIDTH = 99,
++ VC4_PACKET_RHT_X_BOUNDARY = 100,
++ VC4_PACKET_DEPTH_OFFSET = 101,
++ VC4_PACKET_CLIP_WINDOW = 102,
++ VC4_PACKET_VIEWPORT_OFFSET = 103,
++ VC4_PACKET_Z_CLIPPING = 104,
++ VC4_PACKET_CLIPPER_XY_SCALING = 105,
++ VC4_PACKET_CLIPPER_Z_SCALING = 106,
++
++ VC4_PACKET_TILE_BINNING_MODE_CONFIG = 112,
++ VC4_PACKET_TILE_RENDERING_MODE_CONFIG = 113,
++ VC4_PACKET_CLEAR_COLORS = 114,
++ VC4_PACKET_TILE_COORDINATES = 115,
++
++ /* Not an actual hardware packet -- this is what we use to put
++ * references to GEM bos in the command stream, since we need the u32
++ * int the actual address packet in order to store the offset from the
++ * start of the BO.
++ */
++ VC4_PACKET_GEM_HANDLES = 254,
+ } __attribute__ ((__packed__));
+
+ #define VC4_PACKET_HALT_SIZE 1
+@@ -148,10 +148,10 @@ enum vc4_packet {
+ * VC4_PACKET_LOAD_TILE_BUFFER_GENERAL (low bits of the address)
+ */
+
+-#define VC4_LOADSTORE_TILE_BUFFER_EOF (1 << 3)
+-#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_VG_MASK (1 << 2)
+-#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_ZS (1 << 1)
+-#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_COLOR (1 << 0)
++#define VC4_LOADSTORE_TILE_BUFFER_EOF BIT(3)
++#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_VG_MASK BIT(2)
++#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_ZS BIT(1)
++#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_COLOR BIT(0)
+
+ /** @} */
+
+@@ -160,10 +160,10 @@ enum vc4_packet {
+ * byte 0-1 of VC4_PACKET_STORE_TILE_BUFFER_GENERAL and
+ * VC4_PACKET_LOAD_TILE_BUFFER_GENERAL
+ */
+-#define VC4_STORE_TILE_BUFFER_DISABLE_VG_MASK_CLEAR (1 << 15)
+-#define VC4_STORE_TILE_BUFFER_DISABLE_ZS_CLEAR (1 << 14)
+-#define VC4_STORE_TILE_BUFFER_DISABLE_COLOR_CLEAR (1 << 13)
+-#define VC4_STORE_TILE_BUFFER_DISABLE_SWAP (1 << 12)
++#define VC4_STORE_TILE_BUFFER_DISABLE_VG_MASK_CLEAR BIT(15)
++#define VC4_STORE_TILE_BUFFER_DISABLE_ZS_CLEAR BIT(14)
++#define VC4_STORE_TILE_BUFFER_DISABLE_COLOR_CLEAR BIT(13)
++#define VC4_STORE_TILE_BUFFER_DISABLE_SWAP BIT(12)
+
+ #define VC4_LOADSTORE_TILE_BUFFER_FORMAT_MASK VC4_MASK(9, 8)
+ #define VC4_LOADSTORE_TILE_BUFFER_FORMAT_SHIFT 8
+@@ -201,28 +201,28 @@ enum vc4_packet {
+ #define VC4_INDEX_BUFFER_U16 (1 << 4)
+
+ /* This flag is only present in NV shader state. */
+-#define VC4_SHADER_FLAG_SHADED_CLIP_COORDS (1 << 3)
+-#define VC4_SHADER_FLAG_ENABLE_CLIPPING (1 << 2)
+-#define VC4_SHADER_FLAG_VS_POINT_SIZE (1 << 1)
+-#define VC4_SHADER_FLAG_FS_SINGLE_THREAD (1 << 0)
++#define VC4_SHADER_FLAG_SHADED_CLIP_COORDS BIT(3)
++#define VC4_SHADER_FLAG_ENABLE_CLIPPING BIT(2)
++#define VC4_SHADER_FLAG_VS_POINT_SIZE BIT(1)
++#define VC4_SHADER_FLAG_FS_SINGLE_THREAD BIT(0)
+
+ /** @{ byte 2 of config bits. */
+-#define VC4_CONFIG_BITS_EARLY_Z_UPDATE (1 << 1)
+-#define VC4_CONFIG_BITS_EARLY_Z (1 << 0)
++#define VC4_CONFIG_BITS_EARLY_Z_UPDATE BIT(1)
++#define VC4_CONFIG_BITS_EARLY_Z BIT(0)
+ /** @} */
+
+ /** @{ byte 1 of config bits. */
+-#define VC4_CONFIG_BITS_Z_UPDATE (1 << 7)
++#define VC4_CONFIG_BITS_Z_UPDATE BIT(7)
+ /** same values in this 3-bit field as PIPE_FUNC_* */
+ #define VC4_CONFIG_BITS_DEPTH_FUNC_SHIFT 4
+-#define VC4_CONFIG_BITS_COVERAGE_READ_LEAVE (1 << 3)
++#define VC4_CONFIG_BITS_COVERAGE_READ_LEAVE BIT(3)
+
+ #define VC4_CONFIG_BITS_COVERAGE_UPDATE_NONZERO (0 << 1)
+ #define VC4_CONFIG_BITS_COVERAGE_UPDATE_ODD (1 << 1)
+ #define VC4_CONFIG_BITS_COVERAGE_UPDATE_OR (2 << 1)
+ #define VC4_CONFIG_BITS_COVERAGE_UPDATE_ZERO (3 << 1)
+
+-#define VC4_CONFIG_BITS_COVERAGE_PIPE_SELECT (1 << 0)
++#define VC4_CONFIG_BITS_COVERAGE_PIPE_SELECT BIT(0)
+ /** @} */
+
+ /** @{ byte 0 of config bits. */
+@@ -230,15 +230,15 @@ enum vc4_packet {
+ #define VC4_CONFIG_BITS_RASTERIZER_OVERSAMPLE_4X (1 << 6)
+ #define VC4_CONFIG_BITS_RASTERIZER_OVERSAMPLE_16X (2 << 6)
+
+-#define VC4_CONFIG_BITS_AA_POINTS_AND_LINES (1 << 4)
+-#define VC4_CONFIG_BITS_ENABLE_DEPTH_OFFSET (1 << 3)
+-#define VC4_CONFIG_BITS_CW_PRIMITIVES (1 << 2)
+-#define VC4_CONFIG_BITS_ENABLE_PRIM_BACK (1 << 1)
+-#define VC4_CONFIG_BITS_ENABLE_PRIM_FRONT (1 << 0)
++#define VC4_CONFIG_BITS_AA_POINTS_AND_LINES BIT(4)
++#define VC4_CONFIG_BITS_ENABLE_DEPTH_OFFSET BIT(3)
++#define VC4_CONFIG_BITS_CW_PRIMITIVES BIT(2)
++#define VC4_CONFIG_BITS_ENABLE_PRIM_BACK BIT(1)
++#define VC4_CONFIG_BITS_ENABLE_PRIM_FRONT BIT(0)
+ /** @} */
+
+ /** @{ bits in the last u8 of VC4_PACKET_TILE_BINNING_MODE_CONFIG */
+-#define VC4_BIN_CONFIG_DB_NON_MS (1 << 7)
++#define VC4_BIN_CONFIG_DB_NON_MS BIT(7)
+
+ #define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_MASK VC4_MASK(6, 5)
+ #define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_SHIFT 5
+@@ -254,17 +254,17 @@ enum vc4_packet {
+ #define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_128 2
+ #define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_256 3
+
+-#define VC4_BIN_CONFIG_AUTO_INIT_TSDA (1 << 2)
+-#define VC4_BIN_CONFIG_TILE_BUFFER_64BIT (1 << 1)
+-#define VC4_BIN_CONFIG_MS_MODE_4X (1 << 0)
++#define VC4_BIN_CONFIG_AUTO_INIT_TSDA BIT(2)
++#define VC4_BIN_CONFIG_TILE_BUFFER_64BIT BIT(1)
++#define VC4_BIN_CONFIG_MS_MODE_4X BIT(0)
+ /** @} */
+
+ /** @{ bits in the last u16 of VC4_PACKET_TILE_RENDERING_MODE_CONFIG */
+-#define VC4_RENDER_CONFIG_DB_NON_MS (1 << 12)
+-#define VC4_RENDER_CONFIG_EARLY_Z_COVERAGE_DISABLE (1 << 11)
+-#define VC4_RENDER_CONFIG_EARLY_Z_DIRECTION_G (1 << 10)
+-#define VC4_RENDER_CONFIG_COVERAGE_MODE (1 << 9)
+-#define VC4_RENDER_CONFIG_ENABLE_VG_MASK (1 << 8)
++#define VC4_RENDER_CONFIG_DB_NON_MS BIT(12)
++#define VC4_RENDER_CONFIG_EARLY_Z_COVERAGE_DISABLE BIT(11)
++#define VC4_RENDER_CONFIG_EARLY_Z_DIRECTION_G BIT(10)
++#define VC4_RENDER_CONFIG_COVERAGE_MODE BIT(9)
++#define VC4_RENDER_CONFIG_ENABLE_VG_MASK BIT(8)
+
+ /** The values of the field are VC4_TILING_FORMAT_* */
+ #define VC4_RENDER_CONFIG_MEMORY_FORMAT_MASK VC4_MASK(7, 6)
+@@ -280,8 +280,8 @@ enum vc4_packet {
+ #define VC4_RENDER_CONFIG_FORMAT_RGBA8888 1
+ #define VC4_RENDER_CONFIG_FORMAT_BGR565 2
+
+-#define VC4_RENDER_CONFIG_TILE_BUFFER_64BIT (1 << 1)
+-#define VC4_RENDER_CONFIG_MS_MODE_4X (1 << 0)
++#define VC4_RENDER_CONFIG_TILE_BUFFER_64BIT BIT(1)
++#define VC4_RENDER_CONFIG_MS_MODE_4X BIT(0)
+
+ #define VC4_PRIMITIVE_LIST_FORMAT_16_INDEX (1 << 4)
+ #define VC4_PRIMITIVE_LIST_FORMAT_32_XY (3 << 4)
+@@ -291,24 +291,24 @@ enum vc4_packet {
+ #define VC4_PRIMITIVE_LIST_FORMAT_TYPE_RHT (3 << 0)
+
+ enum vc4_texture_data_type {
+- VC4_TEXTURE_TYPE_RGBA8888 = 0,
+- VC4_TEXTURE_TYPE_RGBX8888 = 1,
+- VC4_TEXTURE_TYPE_RGBA4444 = 2,
+- VC4_TEXTURE_TYPE_RGBA5551 = 3,
+- VC4_TEXTURE_TYPE_RGB565 = 4,
+- VC4_TEXTURE_TYPE_LUMINANCE = 5,
+- VC4_TEXTURE_TYPE_ALPHA = 6,
+- VC4_TEXTURE_TYPE_LUMALPHA = 7,
+- VC4_TEXTURE_TYPE_ETC1 = 8,
+- VC4_TEXTURE_TYPE_S16F = 9,
+- VC4_TEXTURE_TYPE_S8 = 10,
+- VC4_TEXTURE_TYPE_S16 = 11,
+- VC4_TEXTURE_TYPE_BW1 = 12,
+- VC4_TEXTURE_TYPE_A4 = 13,
+- VC4_TEXTURE_TYPE_A1 = 14,
+- VC4_TEXTURE_TYPE_RGBA64 = 15,
+- VC4_TEXTURE_TYPE_RGBA32R = 16,
+- VC4_TEXTURE_TYPE_YUV422R = 17,
++ VC4_TEXTURE_TYPE_RGBA8888 = 0,
++ VC4_TEXTURE_TYPE_RGBX8888 = 1,
++ VC4_TEXTURE_TYPE_RGBA4444 = 2,
++ VC4_TEXTURE_TYPE_RGBA5551 = 3,
++ VC4_TEXTURE_TYPE_RGB565 = 4,
++ VC4_TEXTURE_TYPE_LUMINANCE = 5,
++ VC4_TEXTURE_TYPE_ALPHA = 6,
++ VC4_TEXTURE_TYPE_LUMALPHA = 7,
++ VC4_TEXTURE_TYPE_ETC1 = 8,
++ VC4_TEXTURE_TYPE_S16F = 9,
++ VC4_TEXTURE_TYPE_S8 = 10,
++ VC4_TEXTURE_TYPE_S16 = 11,
++ VC4_TEXTURE_TYPE_BW1 = 12,
++ VC4_TEXTURE_TYPE_A4 = 13,
++ VC4_TEXTURE_TYPE_A1 = 14,
++ VC4_TEXTURE_TYPE_RGBA64 = 15,
++ VC4_TEXTURE_TYPE_RGBA32R = 16,
++ VC4_TEXTURE_TYPE_YUV422R = 17,
+ };
+
+ #define VC4_TEX_P0_OFFSET_MASK VC4_MASK(31, 12)
+--- a/drivers/gpu/drm/vc4/vc4_qpu_defines.h
++++ b/drivers/gpu/drm/vc4/vc4_qpu_defines.h
+@@ -25,194 +25,190 @@
+ #define VC4_QPU_DEFINES_H
+
+ enum qpu_op_add {
+- QPU_A_NOP,
+- QPU_A_FADD,
+- QPU_A_FSUB,
+- QPU_A_FMIN,
+- QPU_A_FMAX,
+- QPU_A_FMINABS,
+- QPU_A_FMAXABS,
+- QPU_A_FTOI,
+- QPU_A_ITOF,
+- QPU_A_ADD = 12,
+- QPU_A_SUB,
+- QPU_A_SHR,
+- QPU_A_ASR,
+- QPU_A_ROR,
+- QPU_A_SHL,
+- QPU_A_MIN,
+- QPU_A_MAX,
+- QPU_A_AND,
+- QPU_A_OR,
+- QPU_A_XOR,
+- QPU_A_NOT,
+- QPU_A_CLZ,
+- QPU_A_V8ADDS = 30,
+- QPU_A_V8SUBS = 31,
++ QPU_A_NOP,
++ QPU_A_FADD,
++ QPU_A_FSUB,
++ QPU_A_FMIN,
++ QPU_A_FMAX,
++ QPU_A_FMINABS,
++ QPU_A_FMAXABS,
++ QPU_A_FTOI,
++ QPU_A_ITOF,
++ QPU_A_ADD = 12,
++ QPU_A_SUB,
++ QPU_A_SHR,
++ QPU_A_ASR,
++ QPU_A_ROR,
++ QPU_A_SHL,
++ QPU_A_MIN,
++ QPU_A_MAX,
++ QPU_A_AND,
++ QPU_A_OR,
++ QPU_A_XOR,
++ QPU_A_NOT,
++ QPU_A_CLZ,
++ QPU_A_V8ADDS = 30,
++ QPU_A_V8SUBS = 31,
+ };
+
+ enum qpu_op_mul {
+- QPU_M_NOP,
+- QPU_M_FMUL,
+- QPU_M_MUL24,
+- QPU_M_V8MULD,
+- QPU_M_V8MIN,
+- QPU_M_V8MAX,
+- QPU_M_V8ADDS,
+- QPU_M_V8SUBS,
++ QPU_M_NOP,
++ QPU_M_FMUL,
++ QPU_M_MUL24,
++ QPU_M_V8MULD,
++ QPU_M_V8MIN,
++ QPU_M_V8MAX,
++ QPU_M_V8ADDS,
++ QPU_M_V8SUBS,
+ };
+
+ enum qpu_raddr {
+- QPU_R_FRAG_PAYLOAD_ZW = 15, /* W for A file, Z for B file */
+- /* 0-31 are the plain regfile a or b fields */
+- QPU_R_UNIF = 32,
+- QPU_R_VARY = 35,
+- QPU_R_ELEM_QPU = 38,
+- QPU_R_NOP,
+- QPU_R_XY_PIXEL_COORD = 41,
+- QPU_R_MS_REV_FLAGS = 41,
+- QPU_R_VPM = 48,
+- QPU_R_VPM_LD_BUSY,
+- QPU_R_VPM_LD_WAIT,
+- QPU_R_MUTEX_ACQUIRE,
++ QPU_R_FRAG_PAYLOAD_ZW = 15, /* W for A file, Z for B file */
++ /* 0-31 are the plain regfile a or b fields */
++ QPU_R_UNIF = 32,
++ QPU_R_VARY = 35,
++ QPU_R_ELEM_QPU = 38,
++ QPU_R_NOP,
++ QPU_R_XY_PIXEL_COORD = 41,
++ QPU_R_MS_REV_FLAGS = 41,
++ QPU_R_VPM = 48,
++ QPU_R_VPM_LD_BUSY,
++ QPU_R_VPM_LD_WAIT,
++ QPU_R_MUTEX_ACQUIRE,
+ };
+
+ enum qpu_waddr {
+- /* 0-31 are the plain regfile a or b fields */
+- QPU_W_ACC0 = 32, /* aka r0 */
+- QPU_W_ACC1,
+- QPU_W_ACC2,
+- QPU_W_ACC3,
+- QPU_W_TMU_NOSWAP,
+- QPU_W_ACC5,
+- QPU_W_HOST_INT,
+- QPU_W_NOP,
+- QPU_W_UNIFORMS_ADDRESS,
+- QPU_W_QUAD_XY, /* X for regfile a, Y for regfile b */
+- QPU_W_MS_FLAGS = 42,
+- QPU_W_REV_FLAG = 42,
+- QPU_W_TLB_STENCIL_SETUP = 43,
+- QPU_W_TLB_Z,
+- QPU_W_TLB_COLOR_MS,
+- QPU_W_TLB_COLOR_ALL,
+- QPU_W_TLB_ALPHA_MASK,
+- QPU_W_VPM,
+- QPU_W_VPMVCD_SETUP, /* LD for regfile a, ST for regfile b */
+- QPU_W_VPM_ADDR, /* LD for regfile a, ST for regfile b */
+- QPU_W_MUTEX_RELEASE,
+- QPU_W_SFU_RECIP,
+- QPU_W_SFU_RECIPSQRT,
+- QPU_W_SFU_EXP,
+- QPU_W_SFU_LOG,
+- QPU_W_TMU0_S,
+- QPU_W_TMU0_T,
+- QPU_W_TMU0_R,
+- QPU_W_TMU0_B,
+- QPU_W_TMU1_S,
+- QPU_W_TMU1_T,
+- QPU_W_TMU1_R,
+- QPU_W_TMU1_B,
++ /* 0-31 are the plain regfile a or b fields */
++ QPU_W_ACC0 = 32, /* aka r0 */
++ QPU_W_ACC1,
++ QPU_W_ACC2,
++ QPU_W_ACC3,
++ QPU_W_TMU_NOSWAP,
++ QPU_W_ACC5,
++ QPU_W_HOST_INT,
++ QPU_W_NOP,
++ QPU_W_UNIFORMS_ADDRESS,
++ QPU_W_QUAD_XY, /* X for regfile a, Y for regfile b */
++ QPU_W_MS_FLAGS = 42,
++ QPU_W_REV_FLAG = 42,
++ QPU_W_TLB_STENCIL_SETUP = 43,
++ QPU_W_TLB_Z,
++ QPU_W_TLB_COLOR_MS,
++ QPU_W_TLB_COLOR_ALL,
++ QPU_W_TLB_ALPHA_MASK,
++ QPU_W_VPM,
++ QPU_W_VPMVCD_SETUP, /* LD for regfile a, ST for regfile b */
++ QPU_W_VPM_ADDR, /* LD for regfile a, ST for regfile b */
++ QPU_W_MUTEX_RELEASE,
++ QPU_W_SFU_RECIP,
++ QPU_W_SFU_RECIPSQRT,
++ QPU_W_SFU_EXP,
++ QPU_W_SFU_LOG,
++ QPU_W_TMU0_S,
++ QPU_W_TMU0_T,
++ QPU_W_TMU0_R,
++ QPU_W_TMU0_B,
++ QPU_W_TMU1_S,
++ QPU_W_TMU1_T,
++ QPU_W_TMU1_R,
++ QPU_W_TMU1_B,
+ };
+
+ enum qpu_sig_bits {
+- QPU_SIG_SW_BREAKPOINT,
+- QPU_SIG_NONE,
+- QPU_SIG_THREAD_SWITCH,
+- QPU_SIG_PROG_END,
+- QPU_SIG_WAIT_FOR_SCOREBOARD,
+- QPU_SIG_SCOREBOARD_UNLOCK,
+- QPU_SIG_LAST_THREAD_SWITCH,
+- QPU_SIG_COVERAGE_LOAD,
+- QPU_SIG_COLOR_LOAD,
+- QPU_SIG_COLOR_LOAD_END,
+- QPU_SIG_LOAD_TMU0,
+- QPU_SIG_LOAD_TMU1,
+- QPU_SIG_ALPHA_MASK_LOAD,
+- QPU_SIG_SMALL_IMM,
+- QPU_SIG_LOAD_IMM,
+- QPU_SIG_BRANCH
++ QPU_SIG_SW_BREAKPOINT,
++ QPU_SIG_NONE,
++ QPU_SIG_THREAD_SWITCH,
++ QPU_SIG_PROG_END,
++ QPU_SIG_WAIT_FOR_SCOREBOARD,
++ QPU_SIG_SCOREBOARD_UNLOCK,
++ QPU_SIG_LAST_THREAD_SWITCH,
++ QPU_SIG_COVERAGE_LOAD,
++ QPU_SIG_COLOR_LOAD,
++ QPU_SIG_COLOR_LOAD_END,
++ QPU_SIG_LOAD_TMU0,
++ QPU_SIG_LOAD_TMU1,
++ QPU_SIG_ALPHA_MASK_LOAD,
++ QPU_SIG_SMALL_IMM,
++ QPU_SIG_LOAD_IMM,
++ QPU_SIG_BRANCH
+ };
+
+ enum qpu_mux {
+- /* hardware mux values */
+- QPU_MUX_R0,
+- QPU_MUX_R1,
+- QPU_MUX_R2,
+- QPU_MUX_R3,
+- QPU_MUX_R4,
+- QPU_MUX_R5,
+- QPU_MUX_A,
+- QPU_MUX_B,
++ /* hardware mux values */
++ QPU_MUX_R0,
++ QPU_MUX_R1,
++ QPU_MUX_R2,
++ QPU_MUX_R3,
++ QPU_MUX_R4,
++ QPU_MUX_R5,
++ QPU_MUX_A,
++ QPU_MUX_B,
+
+- /* non-hardware mux values */
+- QPU_MUX_IMM,
++ /* non-hardware mux values */
++ QPU_MUX_IMM,
+ };
+
+ enum qpu_cond {
+- QPU_COND_NEVER,
+- QPU_COND_ALWAYS,
+- QPU_COND_ZS,
+- QPU_COND_ZC,
+- QPU_COND_NS,
+- QPU_COND_NC,
+- QPU_COND_CS,
+- QPU_COND_CC,
++ QPU_COND_NEVER,
++ QPU_COND_ALWAYS,
++ QPU_COND_ZS,
++ QPU_COND_ZC,
++ QPU_COND_NS,
++ QPU_COND_NC,
++ QPU_COND_CS,
++ QPU_COND_CC,
+ };
+
+ enum qpu_pack_mul {
+- QPU_PACK_MUL_NOP,
+- QPU_PACK_MUL_8888 = 3, /* replicated to each 8 bits of the 32-bit dst. */
+- QPU_PACK_MUL_8A,
+- QPU_PACK_MUL_8B,
+- QPU_PACK_MUL_8C,
+- QPU_PACK_MUL_8D,
++ QPU_PACK_MUL_NOP,
++ /* replicated to each 8 bits of the 32-bit dst. */
++ QPU_PACK_MUL_8888 = 3,
++ QPU_PACK_MUL_8A,
++ QPU_PACK_MUL_8B,
++ QPU_PACK_MUL_8C,
++ QPU_PACK_MUL_8D,
+ };
+
+ enum qpu_pack_a {
+- QPU_PACK_A_NOP,
+- /* convert to 16 bit float if float input, or to int16. */
+- QPU_PACK_A_16A,
+- QPU_PACK_A_16B,
+- /* replicated to each 8 bits of the 32-bit dst. */
+- QPU_PACK_A_8888,
+- /* Convert to 8-bit unsigned int. */
+- QPU_PACK_A_8A,
+- QPU_PACK_A_8B,
+- QPU_PACK_A_8C,
+- QPU_PACK_A_8D,
+-
+- /* Saturating variants of the previous instructions. */
+- QPU_PACK_A_32_SAT, /* int-only */
+- QPU_PACK_A_16A_SAT, /* int or float */
+- QPU_PACK_A_16B_SAT,
+- QPU_PACK_A_8888_SAT,
+- QPU_PACK_A_8A_SAT,
+- QPU_PACK_A_8B_SAT,
+- QPU_PACK_A_8C_SAT,
+- QPU_PACK_A_8D_SAT,
++ QPU_PACK_A_NOP,
++ /* convert to 16 bit float if float input, or to int16. */
++ QPU_PACK_A_16A,
++ QPU_PACK_A_16B,
++ /* replicated to each 8 bits of the 32-bit dst. */
++ QPU_PACK_A_8888,
++ /* Convert to 8-bit unsigned int. */
++ QPU_PACK_A_8A,
++ QPU_PACK_A_8B,
++ QPU_PACK_A_8C,
++ QPU_PACK_A_8D,
++
++ /* Saturating variants of the previous instructions. */
++ QPU_PACK_A_32_SAT, /* int-only */
++ QPU_PACK_A_16A_SAT, /* int or float */
++ QPU_PACK_A_16B_SAT,
++ QPU_PACK_A_8888_SAT,
++ QPU_PACK_A_8A_SAT,
++ QPU_PACK_A_8B_SAT,
++ QPU_PACK_A_8C_SAT,
++ QPU_PACK_A_8D_SAT,
+ };
+
+ enum qpu_unpack_r4 {
+- QPU_UNPACK_R4_NOP,
+- QPU_UNPACK_R4_F16A_TO_F32,
+- QPU_UNPACK_R4_F16B_TO_F32,
+- QPU_UNPACK_R4_8D_REP,
+- QPU_UNPACK_R4_8A,
+- QPU_UNPACK_R4_8B,
+- QPU_UNPACK_R4_8C,
+- QPU_UNPACK_R4_8D,
+-};
+-
+-#define QPU_MASK(high, low) ((((uint64_t)1<<((high)-(low)+1))-1)<<(low))
+-/* Using the GNU statement expression extension */
+-#define QPU_SET_FIELD(value, field) \
+- ({ \
+- uint64_t fieldval = (uint64_t)(value) << field ## _SHIFT; \
+- assert((fieldval & ~ field ## _MASK) == 0); \
+- fieldval & field ## _MASK; \
+- })
++ QPU_UNPACK_R4_NOP,
++ QPU_UNPACK_R4_F16A_TO_F32,
++ QPU_UNPACK_R4_F16B_TO_F32,
++ QPU_UNPACK_R4_8D_REP,
++ QPU_UNPACK_R4_8A,
++ QPU_UNPACK_R4_8B,
++ QPU_UNPACK_R4_8C,
++ QPU_UNPACK_R4_8D,
++};
++
++#define QPU_MASK(high, low) \
++ ((((uint64_t)1 << ((high) - (low) + 1)) - 1) << (low))
+
+-#define QPU_GET_FIELD(word, field) ((uint32_t)(((word) & field ## _MASK) >> field ## _SHIFT))
++#define QPU_GET_FIELD(word, field) \
++ ((uint32_t)(((word) & field ## _MASK) >> field ## _SHIFT))
+
+ #define QPU_SIG_SHIFT 60
+ #define QPU_SIG_MASK QPU_MASK(63, 60)
+--- a/drivers/gpu/drm/vc4/vc4_render_cl.c
++++ b/drivers/gpu/drm/vc4/vc4_render_cl.c
+@@ -63,7 +63,6 @@ static inline void rcl_u32(struct vc4_rc
+ setup->next_offset += 4;
+ }
+
+-
+ /*
+ * Emits a no-op STORE_TILE_BUFFER_GENERAL.
+ *
+@@ -217,7 +216,7 @@ static int vc4_create_rcl_bo(struct drm_
+ }
+ size += xtiles * ytiles * loop_body_size;
+
+- setup->rcl = &vc4_bo_create(dev, size)->base;
++ setup->rcl = &vc4_bo_create(dev, size, true)->base;
+ if (!setup->rcl)
+ return -ENOMEM;
+ list_add_tail(&to_vc4_bo(&setup->rcl->base)->unref_head,
+@@ -256,6 +255,7 @@ static int vc4_create_rcl_bo(struct drm_
+ for (x = min_x_tile; x <= max_x_tile; x++) {
+ bool first = (x == min_x_tile && y == min_y_tile);
+ bool last = (x == max_x_tile && y == max_y_tile);
++
+ emit_tile(exec, setup, x, y, first, last);
+ }
+ }
+--- a/drivers/gpu/drm/vc4/vc4_v3d.c
++++ b/drivers/gpu/drm/vc4/vc4_v3d.c
+@@ -125,7 +125,7 @@ int vc4_v3d_debugfs_regs(struct seq_file
+
+ int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused)
+ {
+- struct drm_info_node *node = (struct drm_info_node *) m->private;
++ struct drm_info_node *node = (struct drm_info_node *)m->private;
+ struct drm_device *dev = node->minor->dev;
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ uint32_t ident1 = V3D_READ(V3D_IDENT1);
+@@ -133,11 +133,13 @@ int vc4_v3d_debugfs_ident(struct seq_fil
+ uint32_t tups = VC4_GET_FIELD(ident1, V3D_IDENT1_TUPS);
+ uint32_t qups = VC4_GET_FIELD(ident1, V3D_IDENT1_QUPS);
+
+- seq_printf(m, "Revision: %d\n", VC4_GET_FIELD(ident1, V3D_IDENT1_REV));
++ seq_printf(m, "Revision: %d\n",
++ VC4_GET_FIELD(ident1, V3D_IDENT1_REV));
+ seq_printf(m, "Slices: %d\n", nslc);
+ seq_printf(m, "TMUs: %d\n", nslc * tups);
+ seq_printf(m, "QPUs: %d\n", nslc * qups);
+- seq_printf(m, "Semaphores: %d\n", VC4_GET_FIELD(ident1, V3D_IDENT1_NSEM));
++ seq_printf(m, "Semaphores: %d\n",
++ VC4_GET_FIELD(ident1, V3D_IDENT1_NSEM));
+
+ return 0;
+ }
+@@ -218,7 +220,7 @@ static int vc4_v3d_bind(struct device *d
+ }
+
+ static void vc4_v3d_unbind(struct device *dev, struct device *master,
+- void *data)
++ void *data)
+ {
+ struct drm_device *drm = dev_get_drvdata(master);
+ struct vc4_dev *vc4 = to_vc4_dev(drm);
+--- a/drivers/gpu/drm/vc4/vc4_validate.c
++++ b/drivers/gpu/drm/vc4/vc4_validate.c
+@@ -48,7 +48,6 @@
+ void *validated, \
+ void *untrusted
+
+-
+ /** Return the width in pixels of a 64-byte microtile. */
+ static uint32_t
+ utile_width(int cpp)
+@@ -192,7 +191,7 @@ vc4_check_tex_size(struct vc4_exec_info
+
+ if (size + offset < size ||
+ size + offset > fbo->base.size) {
+- DRM_ERROR("Overflow in %dx%d (%dx%d) fbo size (%d + %d > %d)\n",
++ DRM_ERROR("Overflow in %dx%d (%dx%d) fbo size (%d + %d > %zd)\n",
+ width, height,
+ aligned_width, aligned_height,
+ size, offset, fbo->base.size);
+@@ -278,7 +277,7 @@ validate_indexed_prim_list(VALIDATE_ARGS
+
+ if (offset > ib->base.size ||
+ (ib->base.size - offset) / index_size < length) {
+- DRM_ERROR("IB access overflow (%d + %d*%d > %d)\n",
++ DRM_ERROR("IB access overflow (%d + %d*%d > %zd)\n",
+ offset, length, index_size, ib->base.size);
+ return -EINVAL;
+ }
+@@ -377,6 +376,7 @@ static int
+ validate_tile_binning_config(VALIDATE_ARGS)
+ {
+ struct drm_device *dev = exec->exec_bo->base.dev;
++ struct vc4_bo *tile_bo;
+ uint8_t flags;
+ uint32_t tile_state_size, tile_alloc_size;
+ uint32_t tile_count;
+@@ -438,12 +438,12 @@ validate_tile_binning_config(VALIDATE_AR
+ */
+ tile_alloc_size += 1024 * 1024;
+
+- exec->tile_bo = &vc4_bo_create(dev, exec->tile_alloc_offset +
+- tile_alloc_size)->base;
++ tile_bo = vc4_bo_create(dev, exec->tile_alloc_offset + tile_alloc_size,
++ true);
++ exec->tile_bo = &tile_bo->base;
+ if (!exec->tile_bo)
+ return -ENOMEM;
+- list_add_tail(&to_vc4_bo(&exec->tile_bo->base)->unref_head,
+- &exec->unref_list);
++ list_add_tail(&tile_bo->unref_head, &exec->unref_list);
+
+ /* tile alloc address. */
+ *(uint32_t *)(validated + 0) = (exec->tile_bo->paddr +
+@@ -463,8 +463,8 @@ validate_gem_handles(VALIDATE_ARGS)
+ return 0;
+ }
+
+-#define VC4_DEFINE_PACKET(packet, name, func) \
+- [packet] = { packet ## _SIZE, name, func }
++#define VC4_DEFINE_PACKET(packet, func) \
++ [packet] = { packet ## _SIZE, #packet, func }
+
+ static const struct cmd_info {
+ uint16_t len;
+@@ -472,42 +472,43 @@ static const struct cmd_info {
+ int (*func)(struct vc4_exec_info *exec, void *validated,
+ void *untrusted);
+ } cmd_info[] = {
+- VC4_DEFINE_PACKET(VC4_PACKET_HALT, "halt", NULL),
+- VC4_DEFINE_PACKET(VC4_PACKET_NOP, "nop", NULL),
+- VC4_DEFINE_PACKET(VC4_PACKET_FLUSH, "flush", NULL),
+- VC4_DEFINE_PACKET(VC4_PACKET_FLUSH_ALL, "flush all state", validate_flush_all),
+- VC4_DEFINE_PACKET(VC4_PACKET_START_TILE_BINNING, "start tile binning", validate_start_tile_binning),
+- VC4_DEFINE_PACKET(VC4_PACKET_INCREMENT_SEMAPHORE, "increment semaphore", validate_increment_semaphore),
+-
+- VC4_DEFINE_PACKET(VC4_PACKET_GL_INDEXED_PRIMITIVE, "Indexed Primitive List", validate_indexed_prim_list),
+-
+- VC4_DEFINE_PACKET(VC4_PACKET_GL_ARRAY_PRIMITIVE, "Vertex Array Primitives", validate_gl_array_primitive),
+-
+- /* This is only used by clipped primitives (packets 48 and 49), which
+- * we don't support parsing yet.
+- */
+- VC4_DEFINE_PACKET(VC4_PACKET_PRIMITIVE_LIST_FORMAT, "primitive list format", NULL),
+-
+- VC4_DEFINE_PACKET(VC4_PACKET_GL_SHADER_STATE, "GL Shader State", validate_gl_shader_state),
+- VC4_DEFINE_PACKET(VC4_PACKET_NV_SHADER_STATE, "NV Shader State", validate_nv_shader_state),
+-
+- VC4_DEFINE_PACKET(VC4_PACKET_CONFIGURATION_BITS, "configuration bits", NULL),
+- VC4_DEFINE_PACKET(VC4_PACKET_FLAT_SHADE_FLAGS, "flat shade flags", NULL),
+- VC4_DEFINE_PACKET(VC4_PACKET_POINT_SIZE, "point size", NULL),
+- VC4_DEFINE_PACKET(VC4_PACKET_LINE_WIDTH, "line width", NULL),
+- VC4_DEFINE_PACKET(VC4_PACKET_RHT_X_BOUNDARY, "RHT X boundary", NULL),
+- VC4_DEFINE_PACKET(VC4_PACKET_DEPTH_OFFSET, "Depth Offset", NULL),
+- VC4_DEFINE_PACKET(VC4_PACKET_CLIP_WINDOW, "Clip Window", NULL),
+- VC4_DEFINE_PACKET(VC4_PACKET_VIEWPORT_OFFSET, "Viewport Offset", NULL),
+- VC4_DEFINE_PACKET(VC4_PACKET_CLIPPER_XY_SCALING, "Clipper XY Scaling", NULL),
++ VC4_DEFINE_PACKET(VC4_PACKET_HALT, NULL),
++ VC4_DEFINE_PACKET(VC4_PACKET_NOP, NULL),
++ VC4_DEFINE_PACKET(VC4_PACKET_FLUSH, NULL),
++ VC4_DEFINE_PACKET(VC4_PACKET_FLUSH_ALL, validate_flush_all),
++ VC4_DEFINE_PACKET(VC4_PACKET_START_TILE_BINNING,
++ validate_start_tile_binning),
++ VC4_DEFINE_PACKET(VC4_PACKET_INCREMENT_SEMAPHORE,
++ validate_increment_semaphore),
++
++ VC4_DEFINE_PACKET(VC4_PACKET_GL_INDEXED_PRIMITIVE,
++ validate_indexed_prim_list),
++ VC4_DEFINE_PACKET(VC4_PACKET_GL_ARRAY_PRIMITIVE,
++ validate_gl_array_primitive),
++
++ VC4_DEFINE_PACKET(VC4_PACKET_PRIMITIVE_LIST_FORMAT, NULL),
++
++ VC4_DEFINE_PACKET(VC4_PACKET_GL_SHADER_STATE, validate_gl_shader_state),
++ VC4_DEFINE_PACKET(VC4_PACKET_NV_SHADER_STATE, validate_nv_shader_state),
++
++ VC4_DEFINE_PACKET(VC4_PACKET_CONFIGURATION_BITS, NULL),
++ VC4_DEFINE_PACKET(VC4_PACKET_FLAT_SHADE_FLAGS, NULL),
++ VC4_DEFINE_PACKET(VC4_PACKET_POINT_SIZE, NULL),
++ VC4_DEFINE_PACKET(VC4_PACKET_LINE_WIDTH, NULL),
++ VC4_DEFINE_PACKET(VC4_PACKET_RHT_X_BOUNDARY, NULL),
++ VC4_DEFINE_PACKET(VC4_PACKET_DEPTH_OFFSET, NULL),
++ VC4_DEFINE_PACKET(VC4_PACKET_CLIP_WINDOW, NULL),
++ VC4_DEFINE_PACKET(VC4_PACKET_VIEWPORT_OFFSET, NULL),
++ VC4_DEFINE_PACKET(VC4_PACKET_CLIPPER_XY_SCALING, NULL),
+ /* Note: The docs say this was also 105, but it was 106 in the
+ * initial userland code drop.
+ */
+- VC4_DEFINE_PACKET(VC4_PACKET_CLIPPER_Z_SCALING, "Clipper Z Scale and Offset", NULL),
++ VC4_DEFINE_PACKET(VC4_PACKET_CLIPPER_Z_SCALING, NULL),
+
+- VC4_DEFINE_PACKET(VC4_PACKET_TILE_BINNING_MODE_CONFIG, "tile binning configuration", validate_tile_binning_config),
++ VC4_DEFINE_PACKET(VC4_PACKET_TILE_BINNING_MODE_CONFIG,
++ validate_tile_binning_config),
+
+- VC4_DEFINE_PACKET(VC4_PACKET_GEM_HANDLES, "GEM handles", validate_gem_handles),
++ VC4_DEFINE_PACKET(VC4_PACKET_GEM_HANDLES, validate_gem_handles),
+ };
+
+ int
+@@ -526,7 +527,7 @@ vc4_validate_bin_cl(struct drm_device *d
+ u8 cmd = *(uint8_t *)src_pkt;
+ const struct cmd_info *info;
+
+- if (cmd > ARRAY_SIZE(cmd_info)) {
++ if (cmd >= ARRAY_SIZE(cmd_info)) {
+ DRM_ERROR("0x%08x: packet %d out of bounds\n",
+ src_offset, cmd);
+ return -EINVAL;
+@@ -539,11 +540,6 @@ vc4_validate_bin_cl(struct drm_device *d
+ return -EINVAL;
+ }
+
+-#if 0
+- DRM_INFO("0x%08x: packet %d (%s) size %d processing...\n",
+- src_offset, cmd, info->name, info->len);
+-#endif
+-
+ if (src_offset + info->len > len) {
+ DRM_ERROR("0x%08x: packet %d (%s) length 0x%08x "
+ "exceeds bounds (0x%08x)\n",
+@@ -558,8 +554,7 @@ vc4_validate_bin_cl(struct drm_device *d
+ if (info->func && info->func(exec,
+ dst_pkt + 1,
+ src_pkt + 1)) {
+- DRM_ERROR("0x%08x: packet %d (%s) failed to "
+- "validate\n",
++ DRM_ERROR("0x%08x: packet %d (%s) failed to validate\n",
+ src_offset, cmd, info->name);
+ return -EINVAL;
+ }
+@@ -618,12 +613,14 @@ reloc_tex(struct vc4_exec_info *exec,
+
+ if (sample->is_direct) {
+ uint32_t remaining_size = tex->base.size - p0;
++
+ if (p0 > tex->base.size - 4) {
+ DRM_ERROR("UBO offset greater than UBO size\n");
+ goto fail;
+ }
+ if (p1 > remaining_size - 4) {
+- DRM_ERROR("UBO clamp would allow reads outside of UBO\n");
++ DRM_ERROR("UBO clamp would allow reads "
++ "outside of UBO\n");
+ goto fail;
+ }
+ *validated_p0 = tex->paddr + p0;
+@@ -786,7 +783,7 @@ validate_shader_rec(struct drm_device *d
+ struct drm_gem_cma_object *bo[ARRAY_SIZE(gl_relocs) + 8];
+ uint32_t nr_attributes = 0, nr_fixed_relocs, nr_relocs, packet_size;
+ int i;
+- struct vc4_validated_shader_info *validated_shader;
++ struct vc4_validated_shader_info *shader;
+
+ if (state->packet == VC4_PACKET_NV_SHADER_STATE) {
+ relocs = nv_relocs;
+@@ -841,12 +838,12 @@ validate_shader_rec(struct drm_device *d
+ else
+ mode = VC4_MODE_RENDER;
+
+- if (!vc4_use_bo(exec, src_handles[i], mode, &bo[i])) {
++ if (!vc4_use_bo(exec, src_handles[i], mode, &bo[i]))
+ return false;
+- }
+ }
+
+ for (i = 0; i < nr_fixed_relocs; i++) {
++ struct vc4_bo *vc4_bo;
+ uint32_t o = relocs[i].offset;
+ uint32_t src_offset = *(uint32_t *)(pkt_u + o);
+ uint32_t *texture_handles_u;
+@@ -858,34 +855,34 @@ validate_shader_rec(struct drm_device *d
+ switch (relocs[i].type) {
+ case RELOC_CODE:
+ if (src_offset != 0) {
+- DRM_ERROR("Shaders must be at offset 0 of "
+- "the BO.\n");
++ DRM_ERROR("Shaders must be at offset 0 "
++ "of the BO.\n");
+ goto fail;
+ }
+
+- validated_shader = to_vc4_bo(&bo[i]->base)->validated_shader;
+- if (!validated_shader)
++ vc4_bo = to_vc4_bo(&bo[i]->base);
++ shader = vc4_bo->validated_shader;
++ if (!shader)
+ goto fail;
+
+- if (validated_shader->uniforms_src_size >
+- exec->uniforms_size) {
++ if (shader->uniforms_src_size > exec->uniforms_size) {
+ DRM_ERROR("Uniforms src buffer overflow\n");
+ goto fail;
+ }
+
+ texture_handles_u = exec->uniforms_u;
+ uniform_data_u = (texture_handles_u +
+- validated_shader->num_texture_samples);
++ shader->num_texture_samples);
+
+ memcpy(exec->uniforms_v, uniform_data_u,
+- validated_shader->uniforms_size);
++ shader->uniforms_size);
+
+ for (tex = 0;
+- tex < validated_shader->num_texture_samples;
++ tex < shader->num_texture_samples;
+ tex++) {
+ if (!reloc_tex(exec,
+ uniform_data_u,
+- &validated_shader->texture_samples[tex],
++ &shader->texture_samples[tex],
+ texture_handles_u[tex])) {
+ goto fail;
+ }
+@@ -893,9 +890,9 @@ validate_shader_rec(struct drm_device *d
+
+ *(uint32_t *)(pkt_v + o + 4) = exec->uniforms_p;
+
+- exec->uniforms_u += validated_shader->uniforms_src_size;
+- exec->uniforms_v += validated_shader->uniforms_size;
+- exec->uniforms_p += validated_shader->uniforms_size;
++ exec->uniforms_u += shader->uniforms_src_size;
++ exec->uniforms_v += shader->uniforms_size;
++ exec->uniforms_p += shader->uniforms_size;
+
+ break;
+
+@@ -926,7 +923,8 @@ validate_shader_rec(struct drm_device *d
+ max_index = ((vbo->base.size - offset - attr_size) /
+ stride);
+ if (state->max_index > max_index) {
+- DRM_ERROR("primitives use index %d out of supplied %d\n",
++ DRM_ERROR("primitives use index %d out of "
++ "supplied %d\n",
+ state->max_index, max_index);
+ return -EINVAL;
+ }
+--- a/drivers/gpu/drm/vc4/vc4_validate_shaders.c
++++ b/drivers/gpu/drm/vc4/vc4_validate_shaders.c
+@@ -24,24 +24,16 @@
+ /**
+ * DOC: Shader validator for VC4.
+ *
+- * The VC4 has no IOMMU between it and system memory. So, a user with access
+- * to execute shaders could escalate privilege by overwriting system memory
+- * (using the VPM write address register in the general-purpose DMA mode) or
+- * reading system memory it shouldn't (reading it as a texture, or uniform
+- * data, or vertex data).
++ * The VC4 has no IOMMU between it and system memory, so a user with
++ * access to execute shaders could escalate privilege by overwriting
++ * system memory (using the VPM write address register in the
++ * general-purpose DMA mode) or reading system memory it shouldn't
++ * (reading it as a texture, or uniform data, or vertex data).
+ *
+- * This walks over a shader starting from some offset within a BO, ensuring
+- * that its accesses are appropriately bounded, and recording how many texture
+- * accesses are made and where so that we can do relocations for them in the
++ * This walks over a shader BO, ensuring that its accesses are
++ * appropriately bounded, and recording how many texture accesses are
++ * made and where so that we can do relocations for them in the
+ * uniform stream.
+- *
+- * The kernel API has shaders stored in user-mapped BOs. The BOs will be
+- * forcibly unmapped from the process before validation, and any cache of
+- * validated state will be flushed if the mapping is faulted back in.
+- *
+- * Storing the shaders in BOs means that the validation process will be slow
+- * due to uncached reads, but since shaders are long-lived and shader BOs are
+- * never actually modified, this shouldn't be a problem.
+ */
+
+ #include "vc4_drv.h"
+@@ -70,7 +62,6 @@ waddr_to_live_reg_index(uint32_t waddr,
+ else
+ return waddr;
+ } else if (waddr <= QPU_W_ACC3) {
+-
+ return 64 + waddr - QPU_W_ACC0;
+ } else {
+ return ~0;
+@@ -85,15 +76,14 @@ raddr_add_a_to_live_reg_index(uint64_t i
+ uint32_t raddr_a = QPU_GET_FIELD(inst, QPU_RADDR_A);
+ uint32_t raddr_b = QPU_GET_FIELD(inst, QPU_RADDR_B);
+
+- if (add_a == QPU_MUX_A) {
++ if (add_a == QPU_MUX_A)
+ return raddr_a;
+- } else if (add_a == QPU_MUX_B && sig != QPU_SIG_SMALL_IMM) {
++ else if (add_a == QPU_MUX_B && sig != QPU_SIG_SMALL_IMM)
+ return 32 + raddr_b;
+- } else if (add_a <= QPU_MUX_R3) {
++ else if (add_a <= QPU_MUX_R3)
+ return 64 + add_a;
+- } else {
++ else
+ return ~0;
+- }
+ }
+
+ static bool
+@@ -111,9 +101,9 @@ is_tmu_write(uint32_t waddr)
+ }
+
+ static bool
+-record_validated_texture_sample(struct vc4_validated_shader_info *validated_shader,
+- struct vc4_shader_validation_state *validation_state,
+- int tmu)
++record_texture_sample(struct vc4_validated_shader_info *validated_shader,
++ struct vc4_shader_validation_state *validation_state,
++ int tmu)
+ {
+ uint32_t s = validated_shader->num_texture_samples;
+ int i;
+@@ -226,8 +216,8 @@ check_tmu_write(uint64_t inst,
+ validated_shader->uniforms_size += 4;
+
+ if (submit) {
+- if (!record_validated_texture_sample(validated_shader,
+- validation_state, tmu)) {
++ if (!record_texture_sample(validated_shader,
++ validation_state, tmu)) {
+ return false;
+ }
+
+@@ -238,10 +228,10 @@ check_tmu_write(uint64_t inst,
+ }
+
+ static bool
+-check_register_write(uint64_t inst,
+- struct vc4_validated_shader_info *validated_shader,
+- struct vc4_shader_validation_state *validation_state,
+- bool is_mul)
++check_reg_write(uint64_t inst,
++ struct vc4_validated_shader_info *validated_shader,
++ struct vc4_shader_validation_state *validation_state,
++ bool is_mul)
+ {
+ uint32_t waddr = (is_mul ?
+ QPU_GET_FIELD(inst, QPU_WADDR_MUL) :
+@@ -297,7 +287,7 @@ check_register_write(uint64_t inst,
+ return true;
+
+ case QPU_W_TLB_STENCIL_SETUP:
+- return true;
++ return true;
+ }
+
+ return true;
+@@ -360,7 +350,7 @@ track_live_clamps(uint64_t inst,
+ }
+
+ validation_state->live_max_clamp_regs[lri_add] = true;
+- } if (op_add == QPU_A_MIN) {
++ } else if (op_add == QPU_A_MIN) {
+ /* Track live clamps of a value clamped to a minimum of 0 and
+ * a maximum of some uniform's offset.
+ */
+@@ -392,8 +382,10 @@ check_instruction_writes(uint64_t inst,
+ return false;
+ }
+
+- ok = (check_register_write(inst, validated_shader, validation_state, false) &&
+- check_register_write(inst, validated_shader, validation_state, true));
++ ok = (check_reg_write(inst, validated_shader, validation_state,
++ false) &&
++ check_reg_write(inst, validated_shader, validation_state,
++ true));
+
+ track_live_clamps(inst, validated_shader, validation_state);
+
+@@ -441,7 +433,7 @@ vc4_validate_shader(struct drm_gem_cma_o
+ shader = shader_obj->vaddr;
+ max_ip = shader_obj->base.size / sizeof(uint64_t);
+
+- validated_shader = kcalloc(sizeof(*validated_shader), 1, GFP_KERNEL);
++ validated_shader = kcalloc(1, sizeof(*validated_shader), GFP_KERNEL);
+ if (!validated_shader)
+ return NULL;
+
+@@ -497,7 +489,7 @@ vc4_validate_shader(struct drm_gem_cma_o
+
+ if (ip == max_ip) {
+ DRM_ERROR("shader failed to terminate before "
+- "shader BO end at %d\n",
++ "shader BO end at %zd\n",
+ shader_obj->base.size);
+ goto fail;
+ }
+--- a/include/drm/drmP.h
++++ b/include/drm/drmP.h
+@@ -585,6 +585,13 @@ struct drm_driver {
+ int (*gem_open_object) (struct drm_gem_object *, struct drm_file *);
+ void (*gem_close_object) (struct drm_gem_object *, struct drm_file *);
+
++ /**
++ * Hook for allocating the GEM object struct, for use by core
++ * helpers.
++ */
++ struct drm_gem_object *(*gem_create_object)(struct drm_device *dev,
++ size_t size);
++
+ /* prime: */
+ /* export handle -> fd (see drm_gem_prime_handle_to_fd() helper) */
+ int (*prime_handle_to_fd)(struct drm_device *dev, struct drm_file *file_priv,
+@@ -639,7 +646,6 @@ struct drm_driver {
+
+ u32 driver_features;
+ int dev_priv_size;
+- size_t gem_obj_size;
+ const struct drm_ioctl_desc *ioctls;
+ int num_ioctls;
+ const struct file_operations *fops;
diff --git a/target/linux/brcm2708/patches-4.4/0115-drm-Use-the-driver-s-gem_object_free-function-from-C.patch b/target/linux/brcm2708/patches-4.4/0115-drm-Use-the-driver-s-gem_object_free-function-from-C.patch
new file mode 100644
index 0000000000..c737079cab
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0115-drm-Use-the-driver-s-gem_object_free-function-from-C.patch
@@ -0,0 +1,59 @@
+From 3f01cb691c249a57394e64523ba979aaf181f999 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Fri, 11 Dec 2015 19:45:03 -0800
+Subject: [PATCH 115/381] drm: Use the driver's gem_object_free function from
+ CMA helpers.
+
+VC4 wraps the CMA objects in its own structures, so it needs to do its
+own teardown (waiting for GPU to finish, updating bo_stats tracking).
+The other CMA drivers are using drm_gem_cma_free_object as their
+gem_free_object, so this should be a no-op for them.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/drm_fb_cma_helper.c | 6 +++---
+ drivers/gpu/drm/drm_gem_cma_helper.c | 4 ++--
+ 2 files changed, 5 insertions(+), 5 deletions(-)
+
+--- a/drivers/gpu/drm/drm_fb_cma_helper.c
++++ b/drivers/gpu/drm/drm_fb_cma_helper.c
+@@ -266,7 +266,7 @@ static int drm_fbdev_cma_create(struct d
+ fbi = drm_fb_helper_alloc_fbi(helper);
+ if (IS_ERR(fbi)) {
+ ret = PTR_ERR(fbi);
+- goto err_drm_gem_cma_free_object;
++ goto err_gem_free_object;
+ }
+
+ fbdev_cma->fb = drm_fb_cma_alloc(dev, &mode_cmd, &obj, 1);
+@@ -299,8 +299,8 @@ static int drm_fbdev_cma_create(struct d
+
+ err_fb_info_destroy:
+ drm_fb_helper_release_fbi(helper);
+-err_drm_gem_cma_free_object:
+- drm_gem_cma_free_object(&obj->base);
++err_gem_free_object:
++ dev->driver->gem_free_object(&obj->base);
+ return ret;
+ }
+
+--- a/drivers/gpu/drm/drm_gem_cma_helper.c
++++ b/drivers/gpu/drm/drm_gem_cma_helper.c
+@@ -121,7 +121,7 @@ struct drm_gem_cma_object *drm_gem_cma_c
+ return cma_obj;
+
+ error:
+- drm_gem_cma_free_object(&cma_obj->base);
++ drm->driver->gem_free_object(&cma_obj->base);
+ return ERR_PTR(ret);
+ }
+ EXPORT_SYMBOL_GPL(drm_gem_cma_create);
+@@ -171,7 +171,7 @@ drm_gem_cma_create_with_handle(struct dr
+ return cma_obj;
+
+ err_handle_create:
+- drm_gem_cma_free_object(gem_obj);
++ drm->driver->gem_free_object(gem_obj);
+
+ return ERR_PTR(ret);
+ }
diff --git a/target/linux/brcm2708/patches-4.4/0115-drm-vc4-Update-a-bunch-of-code-to-match-upstream-sub.patch b/target/linux/brcm2708/patches-4.4/0115-drm-vc4-Update-a-bunch-of-code-to-match-upstream-sub.patch
deleted file mode 100644
index 70f32ca552..0000000000
--- a/target/linux/brcm2708/patches-4.4/0115-drm-vc4-Update-a-bunch-of-code-to-match-upstream-sub.patch
+++ /dev/null
@@ -1,1894 +0,0 @@
-From 431be9af0aa88da94986effdff649330cfde1f5a Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Fri, 4 Dec 2015 11:35:34 -0800
-Subject: [PATCH 115/170] drm/vc4: Update a bunch of code to match upstream
- submission.
-
-This gets almost everything matching, except for the MSAA support and
-using generic PM domains.
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
----
- drivers/gpu/drm/drm_gem_cma_helper.c | 13 +-
- drivers/gpu/drm/vc4/vc4_bo.c | 322 +++++++++++++++++------------
- drivers/gpu/drm/vc4/vc4_crtc.c | 7 +-
- drivers/gpu/drm/vc4/vc4_drv.c | 6 +-
- drivers/gpu/drm/vc4/vc4_drv.h | 20 +-
- drivers/gpu/drm/vc4/vc4_gem.c | 24 ++-
- drivers/gpu/drm/vc4/vc4_irq.c | 5 +-
- drivers/gpu/drm/vc4/vc4_kms.c | 1 +
- drivers/gpu/drm/vc4/vc4_packet.h | 210 +++++++++----------
- drivers/gpu/drm/vc4/vc4_qpu_defines.h | 308 ++++++++++++++-------------
- drivers/gpu/drm/vc4/vc4_render_cl.c | 4 +-
- drivers/gpu/drm/vc4/vc4_v3d.c | 10 +-
- drivers/gpu/drm/vc4/vc4_validate.c | 130 ++++++------
- drivers/gpu/drm/vc4/vc4_validate_shaders.c | 66 +++---
- include/drm/drmP.h | 8 +-
- 15 files changed, 598 insertions(+), 536 deletions(-)
-
---- a/drivers/gpu/drm/drm_gem_cma_helper.c
-+++ b/drivers/gpu/drm/drm_gem_cma_helper.c
-@@ -58,15 +58,14 @@ __drm_gem_cma_create(struct drm_device *
- struct drm_gem_cma_object *cma_obj;
- struct drm_gem_object *gem_obj;
- int ret;
-- size_t obj_size = (drm->driver->gem_obj_size ?
-- drm->driver->gem_obj_size :
-- sizeof(*cma_obj));
-
-- cma_obj = kzalloc(obj_size, GFP_KERNEL);
-- if (!cma_obj)
-+ if (drm->driver->gem_create_object)
-+ gem_obj = drm->driver->gem_create_object(drm, size);
-+ else
-+ gem_obj = kzalloc(sizeof(*cma_obj), GFP_KERNEL);
-+ if (!gem_obj)
- return ERR_PTR(-ENOMEM);
--
-- gem_obj = &cma_obj->base;
-+ cma_obj = container_of(gem_obj, struct drm_gem_cma_object, base);
-
- ret = drm_gem_object_init(drm, gem_obj, size);
- if (ret)
---- a/drivers/gpu/drm/vc4/vc4_bo.c
-+++ b/drivers/gpu/drm/vc4/vc4_bo.c
-@@ -12,6 +12,10 @@
- * access to system memory with no MMU in between. To support it, we
- * use the GEM CMA helper functions to allocate contiguous ranges of
- * physical memory for our BOs.
-+ *
-+ * Since the CMA allocator is very slow, we keep a cache of recently
-+ * freed BOs around so that the kernel's allocation of objects for 3D
-+ * rendering can return quickly.
- */
-
- #include "vc4_drv.h"
-@@ -34,6 +38,36 @@ static void vc4_bo_stats_dump(struct vc4
- vc4->bo_stats.size_cached / 1024);
- }
-
-+#ifdef CONFIG_DEBUG_FS
-+int vc4_bo_stats_debugfs(struct seq_file *m, void *unused)
-+{
-+ struct drm_info_node *node = (struct drm_info_node *)m->private;
-+ struct drm_device *dev = node->minor->dev;
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+ struct vc4_bo_stats stats;
-+
-+ /* Take a snapshot of the current stats with the lock held. */
-+ mutex_lock(&vc4->bo_lock);
-+ stats = vc4->bo_stats;
-+ mutex_unlock(&vc4->bo_lock);
-+
-+ seq_printf(m, "num bos allocated: %d\n",
-+ stats.num_allocated);
-+ seq_printf(m, "size bos allocated: %dkb\n",
-+ stats.size_allocated / 1024);
-+ seq_printf(m, "num bos used: %d\n",
-+ stats.num_allocated - stats.num_cached);
-+ seq_printf(m, "size bos used: %dkb\n",
-+ (stats.size_allocated - stats.size_cached) / 1024);
-+ seq_printf(m, "num bos cached: %d\n",
-+ stats.num_cached);
-+ seq_printf(m, "size bos cached: %dkb\n",
-+ stats.size_cached / 1024);
-+
-+ return 0;
-+}
-+#endif
-+
- static uint32_t bo_page_index(size_t size)
- {
- return (size / PAGE_SIZE) - 1;
-@@ -81,8 +115,8 @@ static struct list_head *vc4_get_cache_l
- struct list_head *new_list;
- uint32_t i;
-
-- new_list = kmalloc(new_size * sizeof(struct list_head),
-- GFP_KERNEL);
-+ new_list = kmalloc_array(new_size, sizeof(struct list_head),
-+ GFP_KERNEL);
- if (!new_list)
- return NULL;
-
-@@ -90,7 +124,9 @@ static struct list_head *vc4_get_cache_l
- * head locations.
- */
- for (i = 0; i < vc4->bo_cache.size_list_size; i++) {
-- struct list_head *old_list = &vc4->bo_cache.size_list[i];
-+ struct list_head *old_list =
-+ &vc4->bo_cache.size_list[i];
-+
- if (list_empty(old_list))
- INIT_LIST_HEAD(&new_list[i]);
- else
-@@ -122,11 +158,60 @@ void vc4_bo_cache_purge(struct drm_devic
- mutex_unlock(&vc4->bo_lock);
- }
-
--struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size)
-+static struct vc4_bo *vc4_bo_get_from_cache(struct drm_device *dev,
-+ uint32_t size)
- {
- struct vc4_dev *vc4 = to_vc4_dev(dev);
-- uint32_t size = roundup(unaligned_size, PAGE_SIZE);
- uint32_t page_index = bo_page_index(size);
-+ struct vc4_bo *bo = NULL;
-+
-+ size = roundup(size, PAGE_SIZE);
-+
-+ mutex_lock(&vc4->bo_lock);
-+ if (page_index >= vc4->bo_cache.size_list_size)
-+ goto out;
-+
-+ if (list_empty(&vc4->bo_cache.size_list[page_index]))
-+ goto out;
-+
-+ bo = list_first_entry(&vc4->bo_cache.size_list[page_index],
-+ struct vc4_bo, size_head);
-+ vc4_bo_remove_from_cache(bo);
-+ kref_init(&bo->base.base.refcount);
-+
-+out:
-+ mutex_unlock(&vc4->bo_lock);
-+ return bo;
-+}
-+
-+/**
-+ * vc4_gem_create_object - Implementation of driver->gem_create_object.
-+ *
-+ * This lets the CMA helpers allocate object structs for us, and keep
-+ * our BO stats correct.
-+ */
-+struct drm_gem_object *vc4_create_object(struct drm_device *dev, size_t size)
-+{
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+ struct vc4_bo *bo;
-+
-+ bo = kzalloc(sizeof(*bo), GFP_KERNEL);
-+ if (!bo)
-+ return ERR_PTR(-ENOMEM);
-+
-+ mutex_lock(&vc4->bo_lock);
-+ vc4->bo_stats.num_allocated++;
-+ vc4->bo_stats.size_allocated += size;
-+ mutex_unlock(&vc4->bo_lock);
-+
-+ return &bo->base.base;
-+}
-+
-+struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size,
-+ bool from_cache)
-+{
-+ size_t size = roundup(unaligned_size, PAGE_SIZE);
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
- struct drm_gem_cma_object *cma_obj;
- int pass;
-
-@@ -134,18 +219,12 @@ struct vc4_bo *vc4_bo_create(struct drm_
- return NULL;
-
- /* First, try to get a vc4_bo from the kernel BO cache. */
-- mutex_lock(&vc4->bo_lock);
-- if (page_index < vc4->bo_cache.size_list_size &&
-- !list_empty(&vc4->bo_cache.size_list[page_index])) {
-- struct vc4_bo *bo =
-- list_first_entry(&vc4->bo_cache.size_list[page_index],
-- struct vc4_bo, size_head);
-- vc4_bo_remove_from_cache(bo);
-- mutex_unlock(&vc4->bo_lock);
-- kref_init(&bo->base.base.refcount);
-- return bo;
-+ if (from_cache) {
-+ struct vc4_bo *bo = vc4_bo_get_from_cache(dev, size);
-+
-+ if (bo)
-+ return bo;
- }
-- mutex_unlock(&vc4->bo_lock);
-
- /* Otherwise, make a new BO. */
- for (pass = 0; ; pass++) {
-@@ -179,9 +258,6 @@ struct vc4_bo *vc4_bo_create(struct drm_
- }
- }
-
-- vc4->bo_stats.num_allocated++;
-- vc4->bo_stats.size_allocated += size;
--
- return to_vc4_bo(&cma_obj->base);
- }
-
-@@ -199,7 +275,7 @@ int vc4_dumb_create(struct drm_file *fil
- if (args->size < args->pitch * args->height)
- args->size = args->pitch * args->height;
-
-- bo = vc4_bo_create(dev, args->size);
-+ bo = vc4_bo_create(dev, args->size, false);
- if (!bo)
- return -ENOMEM;
-
-@@ -209,8 +285,8 @@ int vc4_dumb_create(struct drm_file *fil
- return ret;
- }
-
--static void
--vc4_bo_cache_free_old(struct drm_device *dev)
-+/* Must be called with bo_lock held. */
-+static void vc4_bo_cache_free_old(struct drm_device *dev)
- {
- struct vc4_dev *vc4 = to_vc4_dev(dev);
- unsigned long expire_time = jiffies - msecs_to_jiffies(1000);
-@@ -313,15 +389,77 @@ vc4_prime_export(struct drm_device *dev,
- return drm_gem_prime_export(dev, obj, flags);
- }
-
--int
--vc4_create_bo_ioctl(struct drm_device *dev, void *data,
-- struct drm_file *file_priv)
-+int vc4_mmap(struct file *filp, struct vm_area_struct *vma)
-+{
-+ struct drm_gem_object *gem_obj;
-+ struct vc4_bo *bo;
-+ int ret;
-+
-+ ret = drm_gem_mmap(filp, vma);
-+ if (ret)
-+ return ret;
-+
-+ gem_obj = vma->vm_private_data;
-+ bo = to_vc4_bo(gem_obj);
-+
-+ if (bo->validated_shader && (vma->vm_flags & VM_WRITE)) {
-+ DRM_ERROR("mmaping of shader BOs for writing not allowed.\n");
-+ return -EINVAL;
-+ }
-+
-+ /*
-+ * Clear the VM_PFNMAP flag that was set by drm_gem_mmap(), and set the
-+ * vm_pgoff (used as a fake buffer offset by DRM) to 0 as we want to map
-+ * the whole buffer.
-+ */
-+ vma->vm_flags &= ~VM_PFNMAP;
-+ vma->vm_pgoff = 0;
-+
-+ ret = dma_mmap_writecombine(bo->base.base.dev->dev, vma,
-+ bo->base.vaddr, bo->base.paddr,
-+ vma->vm_end - vma->vm_start);
-+ if (ret)
-+ drm_gem_vm_close(vma);
-+
-+ return ret;
-+}
-+
-+int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
-+{
-+ struct vc4_bo *bo = to_vc4_bo(obj);
-+
-+ if (bo->validated_shader && (vma->vm_flags & VM_WRITE)) {
-+ DRM_ERROR("mmaping of shader BOs for writing not allowed.\n");
-+ return -EINVAL;
-+ }
-+
-+ return drm_gem_cma_prime_mmap(obj, vma);
-+}
-+
-+void *vc4_prime_vmap(struct drm_gem_object *obj)
-+{
-+ struct vc4_bo *bo = to_vc4_bo(obj);
-+
-+ if (bo->validated_shader) {
-+ DRM_ERROR("mmaping of shader BOs not allowed.\n");
-+ return ERR_PTR(-EINVAL);
-+ }
-+
-+ return drm_gem_cma_prime_vmap(obj);
-+}
-+
-+int vc4_create_bo_ioctl(struct drm_device *dev, void *data,
-+ struct drm_file *file_priv)
- {
- struct drm_vc4_create_bo *args = data;
- struct vc4_bo *bo = NULL;
- int ret;
-
-- bo = vc4_bo_create(dev, args->size);
-+ /*
-+ * We can't allocate from the BO cache, because the BOs don't
-+ * get zeroed, and that might leak data between users.
-+ */
-+ bo = vc4_bo_create(dev, args->size, false);
- if (!bo)
- return -ENOMEM;
-
-@@ -331,6 +469,25 @@ vc4_create_bo_ioctl(struct drm_device *d
- return ret;
- }
-
-+int vc4_mmap_bo_ioctl(struct drm_device *dev, void *data,
-+ struct drm_file *file_priv)
-+{
-+ struct drm_vc4_mmap_bo *args = data;
-+ struct drm_gem_object *gem_obj;
-+
-+ gem_obj = drm_gem_object_lookup(dev, file_priv, args->handle);
-+ if (!gem_obj) {
-+ DRM_ERROR("Failed to look up GEM BO %d\n", args->handle);
-+ return -EINVAL;
-+ }
-+
-+ /* The mmap offset was set up at BO allocation time. */
-+ args->offset = drm_vma_node_offset_addr(&gem_obj->vma_node);
-+
-+ drm_gem_object_unreference_unlocked(gem_obj);
-+ return 0;
-+}
-+
- int
- vc4_create_shader_bo_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-@@ -355,7 +512,7 @@ vc4_create_shader_bo_ioctl(struct drm_de
- return -EINVAL;
- }
-
-- bo = vc4_bo_create(dev, args->size);
-+ bo = vc4_bo_create(dev, args->size, true);
- if (!bo)
- return -ENOMEM;
-
-@@ -364,6 +521,11 @@ vc4_create_shader_bo_ioctl(struct drm_de
- args->size);
- if (ret != 0)
- goto fail;
-+ /* Clear the rest of the memory from allocating from the BO
-+ * cache.
-+ */
-+ memset(bo->base.vaddr + args->size, 0,
-+ bo->base.base.size - args->size);
-
- bo->validated_shader = vc4_validate_shader(&bo->base);
- if (!bo->validated_shader) {
-@@ -382,85 +544,6 @@ vc4_create_shader_bo_ioctl(struct drm_de
- return ret;
- }
-
--int
--vc4_mmap_bo_ioctl(struct drm_device *dev, void *data,
-- struct drm_file *file_priv)
--{
-- struct drm_vc4_mmap_bo *args = data;
-- struct drm_gem_object *gem_obj;
--
-- gem_obj = drm_gem_object_lookup(dev, file_priv, args->handle);
-- if (!gem_obj) {
-- DRM_ERROR("Failed to look up GEM BO %d\n", args->handle);
-- return -EINVAL;
-- }
--
-- /* The mmap offset was set up at BO allocation time. */
-- args->offset = drm_vma_node_offset_addr(&gem_obj->vma_node);
--
-- drm_gem_object_unreference(gem_obj);
-- return 0;
--}
--
--int vc4_mmap(struct file *filp, struct vm_area_struct *vma)
--{
-- struct drm_gem_object *gem_obj;
-- struct vc4_bo *bo;
-- int ret;
--
-- ret = drm_gem_mmap(filp, vma);
-- if (ret)
-- return ret;
--
-- gem_obj = vma->vm_private_data;
-- bo = to_vc4_bo(gem_obj);
--
-- if (bo->validated_shader && (vma->vm_flags & VM_WRITE)) {
-- DRM_ERROR("mmaping of shader BOs for writing not allowed.\n");
-- return -EINVAL;
-- }
--
-- /*
-- * Clear the VM_PFNMAP flag that was set by drm_gem_mmap(), and set the
-- * vm_pgoff (used as a fake buffer offset by DRM) to 0 as we want to map
-- * the whole buffer.
-- */
-- vma->vm_flags &= ~VM_PFNMAP;
-- vma->vm_pgoff = 0;
--
-- ret = dma_mmap_writecombine(bo->base.base.dev->dev, vma,
-- bo->base.vaddr, bo->base.paddr,
-- vma->vm_end - vma->vm_start);
-- if (ret)
-- drm_gem_vm_close(vma);
--
-- return ret;
--}
--
--int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
--{
-- struct vc4_bo *bo = to_vc4_bo(obj);
--
-- if (bo->validated_shader) {
-- DRM_ERROR("mmaping of shader BOs not allowed.\n");
-- return -EINVAL;
-- }
--
-- return drm_gem_cma_prime_mmap(obj, vma);
--}
--
--void *vc4_prime_vmap(struct drm_gem_object *obj)
--{
-- struct vc4_bo *bo = to_vc4_bo(obj);
--
-- if (bo->validated_shader) {
-- DRM_ERROR("mmaping of shader BOs not allowed.\n");
-- return ERR_PTR(-EINVAL);
-- }
--
-- return drm_gem_cma_prime_vmap(obj);
--}
--
- void vc4_bo_cache_init(struct drm_device *dev)
- {
- struct vc4_dev *vc4 = to_vc4_dev(dev);
-@@ -472,7 +555,7 @@ void vc4_bo_cache_init(struct drm_device
- INIT_WORK(&vc4->bo_cache.time_work, vc4_bo_cache_time_work);
- setup_timer(&vc4->bo_cache.time_timer,
- vc4_bo_cache_time_timer,
-- (unsigned long) dev);
-+ (unsigned long)dev);
- }
-
- void vc4_bo_cache_destroy(struct drm_device *dev)
-@@ -489,28 +572,3 @@ void vc4_bo_cache_destroy(struct drm_dev
- vc4_bo_stats_dump(vc4);
- }
- }
--
--#ifdef CONFIG_DEBUG_FS
--int vc4_bo_stats_debugfs(struct seq_file *m, void *unused)
--{
-- struct drm_info_node *node = (struct drm_info_node *) m->private;
-- struct drm_device *dev = node->minor->dev;
-- struct vc4_dev *vc4 = to_vc4_dev(dev);
-- struct vc4_bo_stats stats;
--
-- mutex_lock(&vc4->bo_lock);
-- stats = vc4->bo_stats;
-- mutex_unlock(&vc4->bo_lock);
--
-- seq_printf(m, "num bos allocated: %d\n", stats.num_allocated);
-- seq_printf(m, "size bos allocated: %dkb\n", stats.size_allocated / 1024);
-- seq_printf(m, "num bos used: %d\n", (stats.num_allocated -
-- stats.num_cached));
-- seq_printf(m, "size bos used: %dkb\n", (stats.size_allocated -
-- stats.size_cached) / 1024);
-- seq_printf(m, "num bos cached: %d\n", stats.num_cached);
-- seq_printf(m, "size bos cached: %dkb\n", stats.size_cached / 1024);
--
-- return 0;
--}
--#endif
---- a/drivers/gpu/drm/vc4/vc4_crtc.c
-+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
-@@ -501,6 +501,7 @@ vc4_async_page_flip_complete(struct vc4_
- vc4_plane_async_set_fb(plane, flip_state->fb);
- if (flip_state->event) {
- unsigned long flags;
-+
- spin_lock_irqsave(&dev->event_lock, flags);
- drm_crtc_send_vblank_event(crtc, flip_state->event);
- spin_unlock_irqrestore(&dev->event_lock, flags);
-@@ -562,9 +563,9 @@ static int vc4_async_page_flip(struct dr
- }
-
- static int vc4_page_flip(struct drm_crtc *crtc,
-- struct drm_framebuffer *fb,
-- struct drm_pending_vblank_event *event,
-- uint32_t flags)
-+ struct drm_framebuffer *fb,
-+ struct drm_pending_vblank_event *event,
-+ uint32_t flags)
- {
- if (flags & DRM_MODE_PAGE_FLIP_ASYNC)
- return vc4_async_page_flip(crtc, fb, event, flags);
---- a/drivers/gpu/drm/vc4/vc4_drv.c
-+++ b/drivers/gpu/drm/vc4/vc4_drv.c
-@@ -81,7 +81,8 @@ static const struct drm_ioctl_desc vc4_d
- DRM_IOCTL_DEF_DRV(VC4_CREATE_BO, vc4_create_bo_ioctl, 0),
- DRM_IOCTL_DEF_DRV(VC4_MMAP_BO, vc4_mmap_bo_ioctl, 0),
- DRM_IOCTL_DEF_DRV(VC4_CREATE_SHADER_BO, vc4_create_shader_bo_ioctl, 0),
-- DRM_IOCTL_DEF_DRV(VC4_GET_HANG_STATE, vc4_get_hang_state_ioctl, DRM_ROOT_ONLY),
-+ DRM_IOCTL_DEF_DRV(VC4_GET_HANG_STATE, vc4_get_hang_state_ioctl,
-+ DRM_ROOT_ONLY),
- };
-
- static struct drm_driver vc4_drm_driver = {
-@@ -107,6 +108,7 @@ static struct drm_driver vc4_drm_driver
- .debugfs_cleanup = vc4_debugfs_cleanup,
- #endif
-
-+ .gem_create_object = vc4_create_object,
- .gem_free_object = vc4_free_object,
- .gem_vm_ops = &drm_gem_cma_vm_ops,
-
-@@ -128,8 +130,6 @@ static struct drm_driver vc4_drm_driver
- .num_ioctls = ARRAY_SIZE(vc4_drm_ioctls),
- .fops = &vc4_drm_fops,
-
-- //.gem_obj_size = sizeof(struct vc4_bo),
--
- .name = DRIVER_NAME,
- .desc = DRIVER_DESC,
- .date = DRIVER_DATE,
---- a/drivers/gpu/drm/vc4/vc4_drv.h
-+++ b/drivers/gpu/drm/vc4/vc4_drv.h
-@@ -72,6 +72,9 @@ struct vc4_dev {
- * job_done_work.
- */
- struct list_head job_done_list;
-+ /* Spinlock used to synchronize the job_list and seqno
-+ * accesses between the IRQ handler and GEM ioctls.
-+ */
- spinlock_t job_lock;
- wait_queue_head_t job_wait_queue;
- struct work_struct job_done_work;
-@@ -318,8 +321,7 @@ struct vc4_texture_sample_info {
- * and validate the shader state record's uniforms that define the texture
- * samples.
- */
--struct vc4_validated_shader_info
--{
-+struct vc4_validated_shader_info {
- uint32_t uniforms_size;
- uint32_t uniforms_src_size;
- uint32_t num_texture_samples;
-@@ -355,8 +357,10 @@ struct vc4_validated_shader_info
- #define wait_for(COND, MS) _wait_for(COND, MS, 1)
-
- /* vc4_bo.c */
-+struct drm_gem_object *vc4_create_object(struct drm_device *dev, size_t size);
- void vc4_free_object(struct drm_gem_object *gem_obj);
--struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t size);
-+struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t size,
-+ bool from_cache);
- int vc4_dumb_create(struct drm_file *file_priv,
- struct drm_device *dev,
- struct drm_mode_create_dumb *args);
-@@ -432,7 +436,8 @@ struct drm_plane *vc4_plane_init(struct
- enum drm_plane_type type);
- u32 vc4_plane_write_dlist(struct drm_plane *plane, u32 __iomem *dlist);
- u32 vc4_plane_dlist_size(struct drm_plane_state *state);
--void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb);
-+void vc4_plane_async_set_fb(struct drm_plane *plane,
-+ struct drm_framebuffer *fb);
-
- /* vc4_v3d.c */
- extern struct platform_driver vc4_v3d_driver;
-@@ -450,9 +455,6 @@ vc4_validate_bin_cl(struct drm_device *d
- int
- vc4_validate_shader_recs(struct drm_device *dev, struct vc4_exec_info *exec);
-
--struct vc4_validated_shader_info *
--vc4_validate_shader(struct drm_gem_cma_object *shader_obj);
--
- bool vc4_use_bo(struct vc4_exec_info *exec,
- uint32_t hindex,
- enum vc4_bo_mode mode,
-@@ -464,3 +466,7 @@ bool vc4_check_tex_size(struct vc4_exec_
- struct drm_gem_cma_object *fbo,
- uint32_t offset, uint8_t tiling_format,
- uint32_t width, uint32_t height, uint8_t cpp);
-+
-+/* vc4_validate_shader.c */
-+struct vc4_validated_shader_info *
-+vc4_validate_shader(struct drm_gem_cma_object *shader_obj);
---- a/drivers/gpu/drm/vc4/vc4_gem.c
-+++ b/drivers/gpu/drm/vc4/vc4_gem.c
-@@ -53,9 +53,8 @@ vc4_free_hang_state(struct drm_device *d
- unsigned int i;
-
- mutex_lock(&dev->struct_mutex);
-- for (i = 0; i < state->user_state.bo_count; i++) {
-+ for (i = 0; i < state->user_state.bo_count; i++)
- drm_gem_object_unreference(state->bo[i]);
-- }
- mutex_unlock(&dev->struct_mutex);
-
- kfree(state);
-@@ -65,10 +64,10 @@ int
- vc4_get_hang_state_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
- {
-- struct drm_vc4_get_hang_state *get_state = data;
-+ struct drm_vc4_get_hang_state *get_state = data;
- struct drm_vc4_get_hang_state_bo *bo_state;
- struct vc4_hang_state *kernel_state;
-- struct drm_vc4_get_hang_state *state;
-+ struct drm_vc4_get_hang_state *state;
- struct vc4_dev *vc4 = to_vc4_dev(dev);
- unsigned long irqflags;
- u32 i;
-@@ -107,6 +106,7 @@ vc4_get_hang_state_ioctl(struct drm_devi
- for (i = 0; i < state->bo_count; i++) {
- struct vc4_bo *vc4_bo = to_vc4_bo(kernel_state->bo[i]);
- u32 handle;
-+
- ret = drm_gem_handle_create(file_priv, kernel_state->bo[i],
- &handle);
-
-@@ -124,7 +124,7 @@ vc4_get_hang_state_ioctl(struct drm_devi
- state->bo_count * sizeof(*bo_state));
- kfree(bo_state);
-
-- err_free:
-+err_free:
-
- vc4_free_hang_state(dev, kernel_state);
-
-@@ -578,7 +578,7 @@ vc4_get_bcl(struct drm_device *dev, stru
- goto fail;
- }
-
-- bo = vc4_bo_create(dev, exec_size);
-+ bo = vc4_bo_create(dev, exec_size, true);
- if (!bo) {
- DRM_ERROR("Couldn't allocate BO for binning\n");
- ret = PTR_ERR(exec->exec_bo);
-@@ -668,6 +668,7 @@ vc4_job_handle_completed(struct vc4_dev
- static void vc4_seqno_cb_work(struct work_struct *work)
- {
- struct vc4_seqno_cb *cb = container_of(work, struct vc4_seqno_cb, work);
-+
- cb->func(cb);
- }
-
-@@ -717,6 +718,7 @@ vc4_wait_for_seqno_ioctl_helper(struct d
-
- if ((ret == -EINTR || ret == -ERESTARTSYS) && *timeout_ns != ~0ull) {
- uint64_t delta = jiffies_to_nsecs(jiffies - start);
-+
- if (*timeout_ns >= delta)
- *timeout_ns -= delta;
- }
-@@ -750,9 +752,10 @@ vc4_wait_bo_ioctl(struct drm_device *dev
- }
- bo = to_vc4_bo(gem_obj);
-
-- ret = vc4_wait_for_seqno_ioctl_helper(dev, bo->seqno, &args->timeout_ns);
-+ ret = vc4_wait_for_seqno_ioctl_helper(dev, bo->seqno,
-+ &args->timeout_ns);
-
-- drm_gem_object_unreference(gem_obj);
-+ drm_gem_object_unreference_unlocked(gem_obj);
- return ret;
- }
-
-@@ -793,7 +796,8 @@ vc4_submit_cl_ioctl(struct drm_device *d
- if (ret)
- goto fail;
- } else {
-- exec->ct0ca = exec->ct0ea = 0;
-+ exec->ct0ca = 0;
-+ exec->ct0ea = 0;
- }
-
- ret = vc4_get_rcl(dev, exec);
-@@ -831,7 +835,7 @@ vc4_gem_init(struct drm_device *dev)
- INIT_WORK(&vc4->hangcheck.reset_work, vc4_reset_work);
- setup_timer(&vc4->hangcheck.timer,
- vc4_hangcheck_elapsed,
-- (unsigned long) dev);
-+ (unsigned long)dev);
-
- INIT_WORK(&vc4->job_done_work, vc4_job_done_work);
- }
---- a/drivers/gpu/drm/vc4/vc4_irq.c
-+++ b/drivers/gpu/drm/vc4/vc4_irq.c
-@@ -56,7 +56,7 @@ vc4_overflow_mem_work(struct work_struct
- struct drm_device *dev = vc4->dev;
- struct vc4_bo *bo;
-
-- bo = vc4_bo_create(dev, 256 * 1024);
-+ bo = vc4_bo_create(dev, 256 * 1024, true);
- if (!bo) {
- DRM_ERROR("Couldn't allocate binner overflow mem\n");
- return;
-@@ -87,9 +87,8 @@ vc4_overflow_mem_work(struct work_struct
- spin_unlock_irqrestore(&vc4->job_lock, irqflags);
- }
-
-- if (vc4->overflow_mem) {
-+ if (vc4->overflow_mem)
- drm_gem_object_unreference_unlocked(&vc4->overflow_mem->base.base);
-- }
- vc4->overflow_mem = bo;
-
- V3D_WRITE(V3D_BPOA, bo->base.paddr);
---- a/drivers/gpu/drm/vc4/vc4_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_kms.c
-@@ -132,6 +132,7 @@ static int vc4_atomic_commit(struct drm_
- struct drm_gem_cma_object *cma_bo =
- drm_fb_cma_get_gem_obj(new_state->fb, 0);
- struct vc4_bo *bo = to_vc4_bo(&cma_bo->base);
-+
- wait_seqno = max(bo->seqno, wait_seqno);
- }
- }
---- a/drivers/gpu/drm/vc4/vc4_packet.h
-+++ b/drivers/gpu/drm/vc4/vc4_packet.h
-@@ -27,60 +27,60 @@
- #include "vc4_regs.h" /* for VC4_MASK, VC4_GET_FIELD, VC4_SET_FIELD */
-
- enum vc4_packet {
-- VC4_PACKET_HALT = 0,
-- VC4_PACKET_NOP = 1,
-+ VC4_PACKET_HALT = 0,
-+ VC4_PACKET_NOP = 1,
-
-- VC4_PACKET_FLUSH = 4,
-- VC4_PACKET_FLUSH_ALL = 5,
-- VC4_PACKET_START_TILE_BINNING = 6,
-- VC4_PACKET_INCREMENT_SEMAPHORE = 7,
-- VC4_PACKET_WAIT_ON_SEMAPHORE = 8,
--
-- VC4_PACKET_BRANCH = 16,
-- VC4_PACKET_BRANCH_TO_SUB_LIST = 17,
--
-- VC4_PACKET_STORE_MS_TILE_BUFFER = 24,
-- VC4_PACKET_STORE_MS_TILE_BUFFER_AND_EOF = 25,
-- VC4_PACKET_STORE_FULL_RES_TILE_BUFFER = 26,
-- VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER = 27,
-- VC4_PACKET_STORE_TILE_BUFFER_GENERAL = 28,
-- VC4_PACKET_LOAD_TILE_BUFFER_GENERAL = 29,
--
-- VC4_PACKET_GL_INDEXED_PRIMITIVE = 32,
-- VC4_PACKET_GL_ARRAY_PRIMITIVE = 33,
--
-- VC4_PACKET_COMPRESSED_PRIMITIVE = 48,
-- VC4_PACKET_CLIPPED_COMPRESSED_PRIMITIVE = 49,
--
-- VC4_PACKET_PRIMITIVE_LIST_FORMAT = 56,
--
-- VC4_PACKET_GL_SHADER_STATE = 64,
-- VC4_PACKET_NV_SHADER_STATE = 65,
-- VC4_PACKET_VG_SHADER_STATE = 66,
--
-- VC4_PACKET_CONFIGURATION_BITS = 96,
-- VC4_PACKET_FLAT_SHADE_FLAGS = 97,
-- VC4_PACKET_POINT_SIZE = 98,
-- VC4_PACKET_LINE_WIDTH = 99,
-- VC4_PACKET_RHT_X_BOUNDARY = 100,
-- VC4_PACKET_DEPTH_OFFSET = 101,
-- VC4_PACKET_CLIP_WINDOW = 102,
-- VC4_PACKET_VIEWPORT_OFFSET = 103,
-- VC4_PACKET_Z_CLIPPING = 104,
-- VC4_PACKET_CLIPPER_XY_SCALING = 105,
-- VC4_PACKET_CLIPPER_Z_SCALING = 106,
--
-- VC4_PACKET_TILE_BINNING_MODE_CONFIG = 112,
-- VC4_PACKET_TILE_RENDERING_MODE_CONFIG = 113,
-- VC4_PACKET_CLEAR_COLORS = 114,
-- VC4_PACKET_TILE_COORDINATES = 115,
--
-- /* Not an actual hardware packet -- this is what we use to put
-- * references to GEM bos in the command stream, since we need the u32
-- * int the actual address packet in order to store the offset from the
-- * start of the BO.
-- */
-- VC4_PACKET_GEM_HANDLES = 254,
-+ VC4_PACKET_FLUSH = 4,
-+ VC4_PACKET_FLUSH_ALL = 5,
-+ VC4_PACKET_START_TILE_BINNING = 6,
-+ VC4_PACKET_INCREMENT_SEMAPHORE = 7,
-+ VC4_PACKET_WAIT_ON_SEMAPHORE = 8,
-+
-+ VC4_PACKET_BRANCH = 16,
-+ VC4_PACKET_BRANCH_TO_SUB_LIST = 17,
-+
-+ VC4_PACKET_STORE_MS_TILE_BUFFER = 24,
-+ VC4_PACKET_STORE_MS_TILE_BUFFER_AND_EOF = 25,
-+ VC4_PACKET_STORE_FULL_RES_TILE_BUFFER = 26,
-+ VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER = 27,
-+ VC4_PACKET_STORE_TILE_BUFFER_GENERAL = 28,
-+ VC4_PACKET_LOAD_TILE_BUFFER_GENERAL = 29,
-+
-+ VC4_PACKET_GL_INDEXED_PRIMITIVE = 32,
-+ VC4_PACKET_GL_ARRAY_PRIMITIVE = 33,
-+
-+ VC4_PACKET_COMPRESSED_PRIMITIVE = 48,
-+ VC4_PACKET_CLIPPED_COMPRESSED_PRIMITIVE = 49,
-+
-+ VC4_PACKET_PRIMITIVE_LIST_FORMAT = 56,
-+
-+ VC4_PACKET_GL_SHADER_STATE = 64,
-+ VC4_PACKET_NV_SHADER_STATE = 65,
-+ VC4_PACKET_VG_SHADER_STATE = 66,
-+
-+ VC4_PACKET_CONFIGURATION_BITS = 96,
-+ VC4_PACKET_FLAT_SHADE_FLAGS = 97,
-+ VC4_PACKET_POINT_SIZE = 98,
-+ VC4_PACKET_LINE_WIDTH = 99,
-+ VC4_PACKET_RHT_X_BOUNDARY = 100,
-+ VC4_PACKET_DEPTH_OFFSET = 101,
-+ VC4_PACKET_CLIP_WINDOW = 102,
-+ VC4_PACKET_VIEWPORT_OFFSET = 103,
-+ VC4_PACKET_Z_CLIPPING = 104,
-+ VC4_PACKET_CLIPPER_XY_SCALING = 105,
-+ VC4_PACKET_CLIPPER_Z_SCALING = 106,
-+
-+ VC4_PACKET_TILE_BINNING_MODE_CONFIG = 112,
-+ VC4_PACKET_TILE_RENDERING_MODE_CONFIG = 113,
-+ VC4_PACKET_CLEAR_COLORS = 114,
-+ VC4_PACKET_TILE_COORDINATES = 115,
-+
-+ /* Not an actual hardware packet -- this is what we use to put
-+ * references to GEM bos in the command stream, since we need the u32
-+ * int the actual address packet in order to store the offset from the
-+ * start of the BO.
-+ */
-+ VC4_PACKET_GEM_HANDLES = 254,
- } __attribute__ ((__packed__));
-
- #define VC4_PACKET_HALT_SIZE 1
-@@ -148,10 +148,10 @@ enum vc4_packet {
- * VC4_PACKET_LOAD_TILE_BUFFER_GENERAL (low bits of the address)
- */
-
--#define VC4_LOADSTORE_TILE_BUFFER_EOF (1 << 3)
--#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_VG_MASK (1 << 2)
--#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_ZS (1 << 1)
--#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_COLOR (1 << 0)
-+#define VC4_LOADSTORE_TILE_BUFFER_EOF BIT(3)
-+#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_VG_MASK BIT(2)
-+#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_ZS BIT(1)
-+#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_COLOR BIT(0)
-
- /** @} */
-
-@@ -160,10 +160,10 @@ enum vc4_packet {
- * byte 0-1 of VC4_PACKET_STORE_TILE_BUFFER_GENERAL and
- * VC4_PACKET_LOAD_TILE_BUFFER_GENERAL
- */
--#define VC4_STORE_TILE_BUFFER_DISABLE_VG_MASK_CLEAR (1 << 15)
--#define VC4_STORE_TILE_BUFFER_DISABLE_ZS_CLEAR (1 << 14)
--#define VC4_STORE_TILE_BUFFER_DISABLE_COLOR_CLEAR (1 << 13)
--#define VC4_STORE_TILE_BUFFER_DISABLE_SWAP (1 << 12)
-+#define VC4_STORE_TILE_BUFFER_DISABLE_VG_MASK_CLEAR BIT(15)
-+#define VC4_STORE_TILE_BUFFER_DISABLE_ZS_CLEAR BIT(14)
-+#define VC4_STORE_TILE_BUFFER_DISABLE_COLOR_CLEAR BIT(13)
-+#define VC4_STORE_TILE_BUFFER_DISABLE_SWAP BIT(12)
-
- #define VC4_LOADSTORE_TILE_BUFFER_FORMAT_MASK VC4_MASK(9, 8)
- #define VC4_LOADSTORE_TILE_BUFFER_FORMAT_SHIFT 8
-@@ -201,28 +201,28 @@ enum vc4_packet {
- #define VC4_INDEX_BUFFER_U16 (1 << 4)
-
- /* This flag is only present in NV shader state. */
--#define VC4_SHADER_FLAG_SHADED_CLIP_COORDS (1 << 3)
--#define VC4_SHADER_FLAG_ENABLE_CLIPPING (1 << 2)
--#define VC4_SHADER_FLAG_VS_POINT_SIZE (1 << 1)
--#define VC4_SHADER_FLAG_FS_SINGLE_THREAD (1 << 0)
-+#define VC4_SHADER_FLAG_SHADED_CLIP_COORDS BIT(3)
-+#define VC4_SHADER_FLAG_ENABLE_CLIPPING BIT(2)
-+#define VC4_SHADER_FLAG_VS_POINT_SIZE BIT(1)
-+#define VC4_SHADER_FLAG_FS_SINGLE_THREAD BIT(0)
-
- /** @{ byte 2 of config bits. */
--#define VC4_CONFIG_BITS_EARLY_Z_UPDATE (1 << 1)
--#define VC4_CONFIG_BITS_EARLY_Z (1 << 0)
-+#define VC4_CONFIG_BITS_EARLY_Z_UPDATE BIT(1)
-+#define VC4_CONFIG_BITS_EARLY_Z BIT(0)
- /** @} */
-
- /** @{ byte 1 of config bits. */
--#define VC4_CONFIG_BITS_Z_UPDATE (1 << 7)
-+#define VC4_CONFIG_BITS_Z_UPDATE BIT(7)
- /** same values in this 3-bit field as PIPE_FUNC_* */
- #define VC4_CONFIG_BITS_DEPTH_FUNC_SHIFT 4
--#define VC4_CONFIG_BITS_COVERAGE_READ_LEAVE (1 << 3)
-+#define VC4_CONFIG_BITS_COVERAGE_READ_LEAVE BIT(3)
-
- #define VC4_CONFIG_BITS_COVERAGE_UPDATE_NONZERO (0 << 1)
- #define VC4_CONFIG_BITS_COVERAGE_UPDATE_ODD (1 << 1)
- #define VC4_CONFIG_BITS_COVERAGE_UPDATE_OR (2 << 1)
- #define VC4_CONFIG_BITS_COVERAGE_UPDATE_ZERO (3 << 1)
-
--#define VC4_CONFIG_BITS_COVERAGE_PIPE_SELECT (1 << 0)
-+#define VC4_CONFIG_BITS_COVERAGE_PIPE_SELECT BIT(0)
- /** @} */
-
- /** @{ byte 0 of config bits. */
-@@ -230,15 +230,15 @@ enum vc4_packet {
- #define VC4_CONFIG_BITS_RASTERIZER_OVERSAMPLE_4X (1 << 6)
- #define VC4_CONFIG_BITS_RASTERIZER_OVERSAMPLE_16X (2 << 6)
-
--#define VC4_CONFIG_BITS_AA_POINTS_AND_LINES (1 << 4)
--#define VC4_CONFIG_BITS_ENABLE_DEPTH_OFFSET (1 << 3)
--#define VC4_CONFIG_BITS_CW_PRIMITIVES (1 << 2)
--#define VC4_CONFIG_BITS_ENABLE_PRIM_BACK (1 << 1)
--#define VC4_CONFIG_BITS_ENABLE_PRIM_FRONT (1 << 0)
-+#define VC4_CONFIG_BITS_AA_POINTS_AND_LINES BIT(4)
-+#define VC4_CONFIG_BITS_ENABLE_DEPTH_OFFSET BIT(3)
-+#define VC4_CONFIG_BITS_CW_PRIMITIVES BIT(2)
-+#define VC4_CONFIG_BITS_ENABLE_PRIM_BACK BIT(1)
-+#define VC4_CONFIG_BITS_ENABLE_PRIM_FRONT BIT(0)
- /** @} */
-
- /** @{ bits in the last u8 of VC4_PACKET_TILE_BINNING_MODE_CONFIG */
--#define VC4_BIN_CONFIG_DB_NON_MS (1 << 7)
-+#define VC4_BIN_CONFIG_DB_NON_MS BIT(7)
-
- #define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_MASK VC4_MASK(6, 5)
- #define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_SHIFT 5
-@@ -254,17 +254,17 @@ enum vc4_packet {
- #define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_128 2
- #define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_256 3
-
--#define VC4_BIN_CONFIG_AUTO_INIT_TSDA (1 << 2)
--#define VC4_BIN_CONFIG_TILE_BUFFER_64BIT (1 << 1)
--#define VC4_BIN_CONFIG_MS_MODE_4X (1 << 0)
-+#define VC4_BIN_CONFIG_AUTO_INIT_TSDA BIT(2)
-+#define VC4_BIN_CONFIG_TILE_BUFFER_64BIT BIT(1)
-+#define VC4_BIN_CONFIG_MS_MODE_4X BIT(0)
- /** @} */
-
- /** @{ bits in the last u16 of VC4_PACKET_TILE_RENDERING_MODE_CONFIG */
--#define VC4_RENDER_CONFIG_DB_NON_MS (1 << 12)
--#define VC4_RENDER_CONFIG_EARLY_Z_COVERAGE_DISABLE (1 << 11)
--#define VC4_RENDER_CONFIG_EARLY_Z_DIRECTION_G (1 << 10)
--#define VC4_RENDER_CONFIG_COVERAGE_MODE (1 << 9)
--#define VC4_RENDER_CONFIG_ENABLE_VG_MASK (1 << 8)
-+#define VC4_RENDER_CONFIG_DB_NON_MS BIT(12)
-+#define VC4_RENDER_CONFIG_EARLY_Z_COVERAGE_DISABLE BIT(11)
-+#define VC4_RENDER_CONFIG_EARLY_Z_DIRECTION_G BIT(10)
-+#define VC4_RENDER_CONFIG_COVERAGE_MODE BIT(9)
-+#define VC4_RENDER_CONFIG_ENABLE_VG_MASK BIT(8)
-
- /** The values of the field are VC4_TILING_FORMAT_* */
- #define VC4_RENDER_CONFIG_MEMORY_FORMAT_MASK VC4_MASK(7, 6)
-@@ -280,8 +280,8 @@ enum vc4_packet {
- #define VC4_RENDER_CONFIG_FORMAT_RGBA8888 1
- #define VC4_RENDER_CONFIG_FORMAT_BGR565 2
-
--#define VC4_RENDER_CONFIG_TILE_BUFFER_64BIT (1 << 1)
--#define VC4_RENDER_CONFIG_MS_MODE_4X (1 << 0)
-+#define VC4_RENDER_CONFIG_TILE_BUFFER_64BIT BIT(1)
-+#define VC4_RENDER_CONFIG_MS_MODE_4X BIT(0)
-
- #define VC4_PRIMITIVE_LIST_FORMAT_16_INDEX (1 << 4)
- #define VC4_PRIMITIVE_LIST_FORMAT_32_XY (3 << 4)
-@@ -291,24 +291,24 @@ enum vc4_packet {
- #define VC4_PRIMITIVE_LIST_FORMAT_TYPE_RHT (3 << 0)
-
- enum vc4_texture_data_type {
-- VC4_TEXTURE_TYPE_RGBA8888 = 0,
-- VC4_TEXTURE_TYPE_RGBX8888 = 1,
-- VC4_TEXTURE_TYPE_RGBA4444 = 2,
-- VC4_TEXTURE_TYPE_RGBA5551 = 3,
-- VC4_TEXTURE_TYPE_RGB565 = 4,
-- VC4_TEXTURE_TYPE_LUMINANCE = 5,
-- VC4_TEXTURE_TYPE_ALPHA = 6,
-- VC4_TEXTURE_TYPE_LUMALPHA = 7,
-- VC4_TEXTURE_TYPE_ETC1 = 8,
-- VC4_TEXTURE_TYPE_S16F = 9,
-- VC4_TEXTURE_TYPE_S8 = 10,
-- VC4_TEXTURE_TYPE_S16 = 11,
-- VC4_TEXTURE_TYPE_BW1 = 12,
-- VC4_TEXTURE_TYPE_A4 = 13,
-- VC4_TEXTURE_TYPE_A1 = 14,
-- VC4_TEXTURE_TYPE_RGBA64 = 15,
-- VC4_TEXTURE_TYPE_RGBA32R = 16,
-- VC4_TEXTURE_TYPE_YUV422R = 17,
-+ VC4_TEXTURE_TYPE_RGBA8888 = 0,
-+ VC4_TEXTURE_TYPE_RGBX8888 = 1,
-+ VC4_TEXTURE_TYPE_RGBA4444 = 2,
-+ VC4_TEXTURE_TYPE_RGBA5551 = 3,
-+ VC4_TEXTURE_TYPE_RGB565 = 4,
-+ VC4_TEXTURE_TYPE_LUMINANCE = 5,
-+ VC4_TEXTURE_TYPE_ALPHA = 6,
-+ VC4_TEXTURE_TYPE_LUMALPHA = 7,
-+ VC4_TEXTURE_TYPE_ETC1 = 8,
-+ VC4_TEXTURE_TYPE_S16F = 9,
-+ VC4_TEXTURE_TYPE_S8 = 10,
-+ VC4_TEXTURE_TYPE_S16 = 11,
-+ VC4_TEXTURE_TYPE_BW1 = 12,
-+ VC4_TEXTURE_TYPE_A4 = 13,
-+ VC4_TEXTURE_TYPE_A1 = 14,
-+ VC4_TEXTURE_TYPE_RGBA64 = 15,
-+ VC4_TEXTURE_TYPE_RGBA32R = 16,
-+ VC4_TEXTURE_TYPE_YUV422R = 17,
- };
-
- #define VC4_TEX_P0_OFFSET_MASK VC4_MASK(31, 12)
---- a/drivers/gpu/drm/vc4/vc4_qpu_defines.h
-+++ b/drivers/gpu/drm/vc4/vc4_qpu_defines.h
-@@ -25,194 +25,190 @@
- #define VC4_QPU_DEFINES_H
-
- enum qpu_op_add {
-- QPU_A_NOP,
-- QPU_A_FADD,
-- QPU_A_FSUB,
-- QPU_A_FMIN,
-- QPU_A_FMAX,
-- QPU_A_FMINABS,
-- QPU_A_FMAXABS,
-- QPU_A_FTOI,
-- QPU_A_ITOF,
-- QPU_A_ADD = 12,
-- QPU_A_SUB,
-- QPU_A_SHR,
-- QPU_A_ASR,
-- QPU_A_ROR,
-- QPU_A_SHL,
-- QPU_A_MIN,
-- QPU_A_MAX,
-- QPU_A_AND,
-- QPU_A_OR,
-- QPU_A_XOR,
-- QPU_A_NOT,
-- QPU_A_CLZ,
-- QPU_A_V8ADDS = 30,
-- QPU_A_V8SUBS = 31,
-+ QPU_A_NOP,
-+ QPU_A_FADD,
-+ QPU_A_FSUB,
-+ QPU_A_FMIN,
-+ QPU_A_FMAX,
-+ QPU_A_FMINABS,
-+ QPU_A_FMAXABS,
-+ QPU_A_FTOI,
-+ QPU_A_ITOF,
-+ QPU_A_ADD = 12,
-+ QPU_A_SUB,
-+ QPU_A_SHR,
-+ QPU_A_ASR,
-+ QPU_A_ROR,
-+ QPU_A_SHL,
-+ QPU_A_MIN,
-+ QPU_A_MAX,
-+ QPU_A_AND,
-+ QPU_A_OR,
-+ QPU_A_XOR,
-+ QPU_A_NOT,
-+ QPU_A_CLZ,
-+ QPU_A_V8ADDS = 30,
-+ QPU_A_V8SUBS = 31,
- };
-
- enum qpu_op_mul {
-- QPU_M_NOP,
-- QPU_M_FMUL,
-- QPU_M_MUL24,
-- QPU_M_V8MULD,
-- QPU_M_V8MIN,
-- QPU_M_V8MAX,
-- QPU_M_V8ADDS,
-- QPU_M_V8SUBS,
-+ QPU_M_NOP,
-+ QPU_M_FMUL,
-+ QPU_M_MUL24,
-+ QPU_M_V8MULD,
-+ QPU_M_V8MIN,
-+ QPU_M_V8MAX,
-+ QPU_M_V8ADDS,
-+ QPU_M_V8SUBS,
- };
-
- enum qpu_raddr {
-- QPU_R_FRAG_PAYLOAD_ZW = 15, /* W for A file, Z for B file */
-- /* 0-31 are the plain regfile a or b fields */
-- QPU_R_UNIF = 32,
-- QPU_R_VARY = 35,
-- QPU_R_ELEM_QPU = 38,
-- QPU_R_NOP,
-- QPU_R_XY_PIXEL_COORD = 41,
-- QPU_R_MS_REV_FLAGS = 41,
-- QPU_R_VPM = 48,
-- QPU_R_VPM_LD_BUSY,
-- QPU_R_VPM_LD_WAIT,
-- QPU_R_MUTEX_ACQUIRE,
-+ QPU_R_FRAG_PAYLOAD_ZW = 15, /* W for A file, Z for B file */
-+ /* 0-31 are the plain regfile a or b fields */
-+ QPU_R_UNIF = 32,
-+ QPU_R_VARY = 35,
-+ QPU_R_ELEM_QPU = 38,
-+ QPU_R_NOP,
-+ QPU_R_XY_PIXEL_COORD = 41,
-+ QPU_R_MS_REV_FLAGS = 41,
-+ QPU_R_VPM = 48,
-+ QPU_R_VPM_LD_BUSY,
-+ QPU_R_VPM_LD_WAIT,
-+ QPU_R_MUTEX_ACQUIRE,
- };
-
- enum qpu_waddr {
-- /* 0-31 are the plain regfile a or b fields */
-- QPU_W_ACC0 = 32, /* aka r0 */
-- QPU_W_ACC1,
-- QPU_W_ACC2,
-- QPU_W_ACC3,
-- QPU_W_TMU_NOSWAP,
-- QPU_W_ACC5,
-- QPU_W_HOST_INT,
-- QPU_W_NOP,
-- QPU_W_UNIFORMS_ADDRESS,
-- QPU_W_QUAD_XY, /* X for regfile a, Y for regfile b */
-- QPU_W_MS_FLAGS = 42,
-- QPU_W_REV_FLAG = 42,
-- QPU_W_TLB_STENCIL_SETUP = 43,
-- QPU_W_TLB_Z,
-- QPU_W_TLB_COLOR_MS,
-- QPU_W_TLB_COLOR_ALL,
-- QPU_W_TLB_ALPHA_MASK,
-- QPU_W_VPM,
-- QPU_W_VPMVCD_SETUP, /* LD for regfile a, ST for regfile b */
-- QPU_W_VPM_ADDR, /* LD for regfile a, ST for regfile b */
-- QPU_W_MUTEX_RELEASE,
-- QPU_W_SFU_RECIP,
-- QPU_W_SFU_RECIPSQRT,
-- QPU_W_SFU_EXP,
-- QPU_W_SFU_LOG,
-- QPU_W_TMU0_S,
-- QPU_W_TMU0_T,
-- QPU_W_TMU0_R,
-- QPU_W_TMU0_B,
-- QPU_W_TMU1_S,
-- QPU_W_TMU1_T,
-- QPU_W_TMU1_R,
-- QPU_W_TMU1_B,
-+ /* 0-31 are the plain regfile a or b fields */
-+ QPU_W_ACC0 = 32, /* aka r0 */
-+ QPU_W_ACC1,
-+ QPU_W_ACC2,
-+ QPU_W_ACC3,
-+ QPU_W_TMU_NOSWAP,
-+ QPU_W_ACC5,
-+ QPU_W_HOST_INT,
-+ QPU_W_NOP,
-+ QPU_W_UNIFORMS_ADDRESS,
-+ QPU_W_QUAD_XY, /* X for regfile a, Y for regfile b */
-+ QPU_W_MS_FLAGS = 42,
-+ QPU_W_REV_FLAG = 42,
-+ QPU_W_TLB_STENCIL_SETUP = 43,
-+ QPU_W_TLB_Z,
-+ QPU_W_TLB_COLOR_MS,
-+ QPU_W_TLB_COLOR_ALL,
-+ QPU_W_TLB_ALPHA_MASK,
-+ QPU_W_VPM,
-+ QPU_W_VPMVCD_SETUP, /* LD for regfile a, ST for regfile b */
-+ QPU_W_VPM_ADDR, /* LD for regfile a, ST for regfile b */
-+ QPU_W_MUTEX_RELEASE,
-+ QPU_W_SFU_RECIP,
-+ QPU_W_SFU_RECIPSQRT,
-+ QPU_W_SFU_EXP,
-+ QPU_W_SFU_LOG,
-+ QPU_W_TMU0_S,
-+ QPU_W_TMU0_T,
-+ QPU_W_TMU0_R,
-+ QPU_W_TMU0_B,
-+ QPU_W_TMU1_S,
-+ QPU_W_TMU1_T,
-+ QPU_W_TMU1_R,
-+ QPU_W_TMU1_B,
- };
-
- enum qpu_sig_bits {
-- QPU_SIG_SW_BREAKPOINT,
-- QPU_SIG_NONE,
-- QPU_SIG_THREAD_SWITCH,
-- QPU_SIG_PROG_END,
-- QPU_SIG_WAIT_FOR_SCOREBOARD,
-- QPU_SIG_SCOREBOARD_UNLOCK,
-- QPU_SIG_LAST_THREAD_SWITCH,
-- QPU_SIG_COVERAGE_LOAD,
-- QPU_SIG_COLOR_LOAD,
-- QPU_SIG_COLOR_LOAD_END,
-- QPU_SIG_LOAD_TMU0,
-- QPU_SIG_LOAD_TMU1,
-- QPU_SIG_ALPHA_MASK_LOAD,
-- QPU_SIG_SMALL_IMM,
-- QPU_SIG_LOAD_IMM,
-- QPU_SIG_BRANCH
-+ QPU_SIG_SW_BREAKPOINT,
-+ QPU_SIG_NONE,
-+ QPU_SIG_THREAD_SWITCH,
-+ QPU_SIG_PROG_END,
-+ QPU_SIG_WAIT_FOR_SCOREBOARD,
-+ QPU_SIG_SCOREBOARD_UNLOCK,
-+ QPU_SIG_LAST_THREAD_SWITCH,
-+ QPU_SIG_COVERAGE_LOAD,
-+ QPU_SIG_COLOR_LOAD,
-+ QPU_SIG_COLOR_LOAD_END,
-+ QPU_SIG_LOAD_TMU0,
-+ QPU_SIG_LOAD_TMU1,
-+ QPU_SIG_ALPHA_MASK_LOAD,
-+ QPU_SIG_SMALL_IMM,
-+ QPU_SIG_LOAD_IMM,
-+ QPU_SIG_BRANCH
- };
-
- enum qpu_mux {
-- /* hardware mux values */
-- QPU_MUX_R0,
-- QPU_MUX_R1,
-- QPU_MUX_R2,
-- QPU_MUX_R3,
-- QPU_MUX_R4,
-- QPU_MUX_R5,
-- QPU_MUX_A,
-- QPU_MUX_B,
-+ /* hardware mux values */
-+ QPU_MUX_R0,
-+ QPU_MUX_R1,
-+ QPU_MUX_R2,
-+ QPU_MUX_R3,
-+ QPU_MUX_R4,
-+ QPU_MUX_R5,
-+ QPU_MUX_A,
-+ QPU_MUX_B,
-
-- /* non-hardware mux values */
-- QPU_MUX_IMM,
-+ /* non-hardware mux values */
-+ QPU_MUX_IMM,
- };
-
- enum qpu_cond {
-- QPU_COND_NEVER,
-- QPU_COND_ALWAYS,
-- QPU_COND_ZS,
-- QPU_COND_ZC,
-- QPU_COND_NS,
-- QPU_COND_NC,
-- QPU_COND_CS,
-- QPU_COND_CC,
-+ QPU_COND_NEVER,
-+ QPU_COND_ALWAYS,
-+ QPU_COND_ZS,
-+ QPU_COND_ZC,
-+ QPU_COND_NS,
-+ QPU_COND_NC,
-+ QPU_COND_CS,
-+ QPU_COND_CC,
- };
-
- enum qpu_pack_mul {
-- QPU_PACK_MUL_NOP,
-- QPU_PACK_MUL_8888 = 3, /* replicated to each 8 bits of the 32-bit dst. */
-- QPU_PACK_MUL_8A,
-- QPU_PACK_MUL_8B,
-- QPU_PACK_MUL_8C,
-- QPU_PACK_MUL_8D,
-+ QPU_PACK_MUL_NOP,
-+ /* replicated to each 8 bits of the 32-bit dst. */
-+ QPU_PACK_MUL_8888 = 3,
-+ QPU_PACK_MUL_8A,
-+ QPU_PACK_MUL_8B,
-+ QPU_PACK_MUL_8C,
-+ QPU_PACK_MUL_8D,
- };
-
- enum qpu_pack_a {
-- QPU_PACK_A_NOP,
-- /* convert to 16 bit float if float input, or to int16. */
-- QPU_PACK_A_16A,
-- QPU_PACK_A_16B,
-- /* replicated to each 8 bits of the 32-bit dst. */
-- QPU_PACK_A_8888,
-- /* Convert to 8-bit unsigned int. */
-- QPU_PACK_A_8A,
-- QPU_PACK_A_8B,
-- QPU_PACK_A_8C,
-- QPU_PACK_A_8D,
--
-- /* Saturating variants of the previous instructions. */
-- QPU_PACK_A_32_SAT, /* int-only */
-- QPU_PACK_A_16A_SAT, /* int or float */
-- QPU_PACK_A_16B_SAT,
-- QPU_PACK_A_8888_SAT,
-- QPU_PACK_A_8A_SAT,
-- QPU_PACK_A_8B_SAT,
-- QPU_PACK_A_8C_SAT,
-- QPU_PACK_A_8D_SAT,
-+ QPU_PACK_A_NOP,
-+ /* convert to 16 bit float if float input, or to int16. */
-+ QPU_PACK_A_16A,
-+ QPU_PACK_A_16B,
-+ /* replicated to each 8 bits of the 32-bit dst. */
-+ QPU_PACK_A_8888,
-+ /* Convert to 8-bit unsigned int. */
-+ QPU_PACK_A_8A,
-+ QPU_PACK_A_8B,
-+ QPU_PACK_A_8C,
-+ QPU_PACK_A_8D,
-+
-+ /* Saturating variants of the previous instructions. */
-+ QPU_PACK_A_32_SAT, /* int-only */
-+ QPU_PACK_A_16A_SAT, /* int or float */
-+ QPU_PACK_A_16B_SAT,
-+ QPU_PACK_A_8888_SAT,
-+ QPU_PACK_A_8A_SAT,
-+ QPU_PACK_A_8B_SAT,
-+ QPU_PACK_A_8C_SAT,
-+ QPU_PACK_A_8D_SAT,
- };
-
- enum qpu_unpack_r4 {
-- QPU_UNPACK_R4_NOP,
-- QPU_UNPACK_R4_F16A_TO_F32,
-- QPU_UNPACK_R4_F16B_TO_F32,
-- QPU_UNPACK_R4_8D_REP,
-- QPU_UNPACK_R4_8A,
-- QPU_UNPACK_R4_8B,
-- QPU_UNPACK_R4_8C,
-- QPU_UNPACK_R4_8D,
--};
--
--#define QPU_MASK(high, low) ((((uint64_t)1<<((high)-(low)+1))-1)<<(low))
--/* Using the GNU statement expression extension */
--#define QPU_SET_FIELD(value, field) \
-- ({ \
-- uint64_t fieldval = (uint64_t)(value) << field ## _SHIFT; \
-- assert((fieldval & ~ field ## _MASK) == 0); \
-- fieldval & field ## _MASK; \
-- })
-+ QPU_UNPACK_R4_NOP,
-+ QPU_UNPACK_R4_F16A_TO_F32,
-+ QPU_UNPACK_R4_F16B_TO_F32,
-+ QPU_UNPACK_R4_8D_REP,
-+ QPU_UNPACK_R4_8A,
-+ QPU_UNPACK_R4_8B,
-+ QPU_UNPACK_R4_8C,
-+ QPU_UNPACK_R4_8D,
-+};
-+
-+#define QPU_MASK(high, low) \
-+ ((((uint64_t)1 << ((high) - (low) + 1)) - 1) << (low))
-
--#define QPU_GET_FIELD(word, field) ((uint32_t)(((word) & field ## _MASK) >> field ## _SHIFT))
-+#define QPU_GET_FIELD(word, field) \
-+ ((uint32_t)(((word) & field ## _MASK) >> field ## _SHIFT))
-
- #define QPU_SIG_SHIFT 60
- #define QPU_SIG_MASK QPU_MASK(63, 60)
---- a/drivers/gpu/drm/vc4/vc4_render_cl.c
-+++ b/drivers/gpu/drm/vc4/vc4_render_cl.c
-@@ -63,7 +63,6 @@ static inline void rcl_u32(struct vc4_rc
- setup->next_offset += 4;
- }
-
--
- /*
- * Emits a no-op STORE_TILE_BUFFER_GENERAL.
- *
-@@ -217,7 +216,7 @@ static int vc4_create_rcl_bo(struct drm_
- }
- size += xtiles * ytiles * loop_body_size;
-
-- setup->rcl = &vc4_bo_create(dev, size)->base;
-+ setup->rcl = &vc4_bo_create(dev, size, true)->base;
- if (!setup->rcl)
- return -ENOMEM;
- list_add_tail(&to_vc4_bo(&setup->rcl->base)->unref_head,
-@@ -256,6 +255,7 @@ static int vc4_create_rcl_bo(struct drm_
- for (x = min_x_tile; x <= max_x_tile; x++) {
- bool first = (x == min_x_tile && y == min_y_tile);
- bool last = (x == max_x_tile && y == max_y_tile);
-+
- emit_tile(exec, setup, x, y, first, last);
- }
- }
---- a/drivers/gpu/drm/vc4/vc4_v3d.c
-+++ b/drivers/gpu/drm/vc4/vc4_v3d.c
-@@ -125,7 +125,7 @@ int vc4_v3d_debugfs_regs(struct seq_file
-
- int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused)
- {
-- struct drm_info_node *node = (struct drm_info_node *) m->private;
-+ struct drm_info_node *node = (struct drm_info_node *)m->private;
- struct drm_device *dev = node->minor->dev;
- struct vc4_dev *vc4 = to_vc4_dev(dev);
- uint32_t ident1 = V3D_READ(V3D_IDENT1);
-@@ -133,11 +133,13 @@ int vc4_v3d_debugfs_ident(struct seq_fil
- uint32_t tups = VC4_GET_FIELD(ident1, V3D_IDENT1_TUPS);
- uint32_t qups = VC4_GET_FIELD(ident1, V3D_IDENT1_QUPS);
-
-- seq_printf(m, "Revision: %d\n", VC4_GET_FIELD(ident1, V3D_IDENT1_REV));
-+ seq_printf(m, "Revision: %d\n",
-+ VC4_GET_FIELD(ident1, V3D_IDENT1_REV));
- seq_printf(m, "Slices: %d\n", nslc);
- seq_printf(m, "TMUs: %d\n", nslc * tups);
- seq_printf(m, "QPUs: %d\n", nslc * qups);
-- seq_printf(m, "Semaphores: %d\n", VC4_GET_FIELD(ident1, V3D_IDENT1_NSEM));
-+ seq_printf(m, "Semaphores: %d\n",
-+ VC4_GET_FIELD(ident1, V3D_IDENT1_NSEM));
-
- return 0;
- }
-@@ -218,7 +220,7 @@ static int vc4_v3d_bind(struct device *d
- }
-
- static void vc4_v3d_unbind(struct device *dev, struct device *master,
-- void *data)
-+ void *data)
- {
- struct drm_device *drm = dev_get_drvdata(master);
- struct vc4_dev *vc4 = to_vc4_dev(drm);
---- a/drivers/gpu/drm/vc4/vc4_validate.c
-+++ b/drivers/gpu/drm/vc4/vc4_validate.c
-@@ -48,7 +48,6 @@
- void *validated, \
- void *untrusted
-
--
- /** Return the width in pixels of a 64-byte microtile. */
- static uint32_t
- utile_width(int cpp)
-@@ -192,7 +191,7 @@ vc4_check_tex_size(struct vc4_exec_info
-
- if (size + offset < size ||
- size + offset > fbo->base.size) {
-- DRM_ERROR("Overflow in %dx%d (%dx%d) fbo size (%d + %d > %d)\n",
-+ DRM_ERROR("Overflow in %dx%d (%dx%d) fbo size (%d + %d > %zd)\n",
- width, height,
- aligned_width, aligned_height,
- size, offset, fbo->base.size);
-@@ -278,7 +277,7 @@ validate_indexed_prim_list(VALIDATE_ARGS
-
- if (offset > ib->base.size ||
- (ib->base.size - offset) / index_size < length) {
-- DRM_ERROR("IB access overflow (%d + %d*%d > %d)\n",
-+ DRM_ERROR("IB access overflow (%d + %d*%d > %zd)\n",
- offset, length, index_size, ib->base.size);
- return -EINVAL;
- }
-@@ -377,6 +376,7 @@ static int
- validate_tile_binning_config(VALIDATE_ARGS)
- {
- struct drm_device *dev = exec->exec_bo->base.dev;
-+ struct vc4_bo *tile_bo;
- uint8_t flags;
- uint32_t tile_state_size, tile_alloc_size;
- uint32_t tile_count;
-@@ -438,12 +438,12 @@ validate_tile_binning_config(VALIDATE_AR
- */
- tile_alloc_size += 1024 * 1024;
-
-- exec->tile_bo = &vc4_bo_create(dev, exec->tile_alloc_offset +
-- tile_alloc_size)->base;
-+ tile_bo = vc4_bo_create(dev, exec->tile_alloc_offset + tile_alloc_size,
-+ true);
-+ exec->tile_bo = &tile_bo->base;
- if (!exec->tile_bo)
- return -ENOMEM;
-- list_add_tail(&to_vc4_bo(&exec->tile_bo->base)->unref_head,
-- &exec->unref_list);
-+ list_add_tail(&tile_bo->unref_head, &exec->unref_list);
-
- /* tile alloc address. */
- *(uint32_t *)(validated + 0) = (exec->tile_bo->paddr +
-@@ -463,8 +463,8 @@ validate_gem_handles(VALIDATE_ARGS)
- return 0;
- }
-
--#define VC4_DEFINE_PACKET(packet, name, func) \
-- [packet] = { packet ## _SIZE, name, func }
-+#define VC4_DEFINE_PACKET(packet, func) \
-+ [packet] = { packet ## _SIZE, #packet, func }
-
- static const struct cmd_info {
- uint16_t len;
-@@ -472,42 +472,43 @@ static const struct cmd_info {
- int (*func)(struct vc4_exec_info *exec, void *validated,
- void *untrusted);
- } cmd_info[] = {
-- VC4_DEFINE_PACKET(VC4_PACKET_HALT, "halt", NULL),
-- VC4_DEFINE_PACKET(VC4_PACKET_NOP, "nop", NULL),
-- VC4_DEFINE_PACKET(VC4_PACKET_FLUSH, "flush", NULL),
-- VC4_DEFINE_PACKET(VC4_PACKET_FLUSH_ALL, "flush all state", validate_flush_all),
-- VC4_DEFINE_PACKET(VC4_PACKET_START_TILE_BINNING, "start tile binning", validate_start_tile_binning),
-- VC4_DEFINE_PACKET(VC4_PACKET_INCREMENT_SEMAPHORE, "increment semaphore", validate_increment_semaphore),
--
-- VC4_DEFINE_PACKET(VC4_PACKET_GL_INDEXED_PRIMITIVE, "Indexed Primitive List", validate_indexed_prim_list),
--
-- VC4_DEFINE_PACKET(VC4_PACKET_GL_ARRAY_PRIMITIVE, "Vertex Array Primitives", validate_gl_array_primitive),
--
-- /* This is only used by clipped primitives (packets 48 and 49), which
-- * we don't support parsing yet.
-- */
-- VC4_DEFINE_PACKET(VC4_PACKET_PRIMITIVE_LIST_FORMAT, "primitive list format", NULL),
--
-- VC4_DEFINE_PACKET(VC4_PACKET_GL_SHADER_STATE, "GL Shader State", validate_gl_shader_state),
-- VC4_DEFINE_PACKET(VC4_PACKET_NV_SHADER_STATE, "NV Shader State", validate_nv_shader_state),
--
-- VC4_DEFINE_PACKET(VC4_PACKET_CONFIGURATION_BITS, "configuration bits", NULL),
-- VC4_DEFINE_PACKET(VC4_PACKET_FLAT_SHADE_FLAGS, "flat shade flags", NULL),
-- VC4_DEFINE_PACKET(VC4_PACKET_POINT_SIZE, "point size", NULL),
-- VC4_DEFINE_PACKET(VC4_PACKET_LINE_WIDTH, "line width", NULL),
-- VC4_DEFINE_PACKET(VC4_PACKET_RHT_X_BOUNDARY, "RHT X boundary", NULL),
-- VC4_DEFINE_PACKET(VC4_PACKET_DEPTH_OFFSET, "Depth Offset", NULL),
-- VC4_DEFINE_PACKET(VC4_PACKET_CLIP_WINDOW, "Clip Window", NULL),
-- VC4_DEFINE_PACKET(VC4_PACKET_VIEWPORT_OFFSET, "Viewport Offset", NULL),
-- VC4_DEFINE_PACKET(VC4_PACKET_CLIPPER_XY_SCALING, "Clipper XY Scaling", NULL),
-+ VC4_DEFINE_PACKET(VC4_PACKET_HALT, NULL),
-+ VC4_DEFINE_PACKET(VC4_PACKET_NOP, NULL),
-+ VC4_DEFINE_PACKET(VC4_PACKET_FLUSH, NULL),
-+ VC4_DEFINE_PACKET(VC4_PACKET_FLUSH_ALL, validate_flush_all),
-+ VC4_DEFINE_PACKET(VC4_PACKET_START_TILE_BINNING,
-+ validate_start_tile_binning),
-+ VC4_DEFINE_PACKET(VC4_PACKET_INCREMENT_SEMAPHORE,
-+ validate_increment_semaphore),
-+
-+ VC4_DEFINE_PACKET(VC4_PACKET_GL_INDEXED_PRIMITIVE,
-+ validate_indexed_prim_list),
-+ VC4_DEFINE_PACKET(VC4_PACKET_GL_ARRAY_PRIMITIVE,
-+ validate_gl_array_primitive),
-+
-+ VC4_DEFINE_PACKET(VC4_PACKET_PRIMITIVE_LIST_FORMAT, NULL),
-+
-+ VC4_DEFINE_PACKET(VC4_PACKET_GL_SHADER_STATE, validate_gl_shader_state),
-+ VC4_DEFINE_PACKET(VC4_PACKET_NV_SHADER_STATE, validate_nv_shader_state),
-+
-+ VC4_DEFINE_PACKET(VC4_PACKET_CONFIGURATION_BITS, NULL),
-+ VC4_DEFINE_PACKET(VC4_PACKET_FLAT_SHADE_FLAGS, NULL),
-+ VC4_DEFINE_PACKET(VC4_PACKET_POINT_SIZE, NULL),
-+ VC4_DEFINE_PACKET(VC4_PACKET_LINE_WIDTH, NULL),
-+ VC4_DEFINE_PACKET(VC4_PACKET_RHT_X_BOUNDARY, NULL),
-+ VC4_DEFINE_PACKET(VC4_PACKET_DEPTH_OFFSET, NULL),
-+ VC4_DEFINE_PACKET(VC4_PACKET_CLIP_WINDOW, NULL),
-+ VC4_DEFINE_PACKET(VC4_PACKET_VIEWPORT_OFFSET, NULL),
-+ VC4_DEFINE_PACKET(VC4_PACKET_CLIPPER_XY_SCALING, NULL),
- /* Note: The docs say this was also 105, but it was 106 in the
- * initial userland code drop.
- */
-- VC4_DEFINE_PACKET(VC4_PACKET_CLIPPER_Z_SCALING, "Clipper Z Scale and Offset", NULL),
-+ VC4_DEFINE_PACKET(VC4_PACKET_CLIPPER_Z_SCALING, NULL),
-
-- VC4_DEFINE_PACKET(VC4_PACKET_TILE_BINNING_MODE_CONFIG, "tile binning configuration", validate_tile_binning_config),
-+ VC4_DEFINE_PACKET(VC4_PACKET_TILE_BINNING_MODE_CONFIG,
-+ validate_tile_binning_config),
-
-- VC4_DEFINE_PACKET(VC4_PACKET_GEM_HANDLES, "GEM handles", validate_gem_handles),
-+ VC4_DEFINE_PACKET(VC4_PACKET_GEM_HANDLES, validate_gem_handles),
- };
-
- int
-@@ -526,7 +527,7 @@ vc4_validate_bin_cl(struct drm_device *d
- u8 cmd = *(uint8_t *)src_pkt;
- const struct cmd_info *info;
-
-- if (cmd > ARRAY_SIZE(cmd_info)) {
-+ if (cmd >= ARRAY_SIZE(cmd_info)) {
- DRM_ERROR("0x%08x: packet %d out of bounds\n",
- src_offset, cmd);
- return -EINVAL;
-@@ -539,11 +540,6 @@ vc4_validate_bin_cl(struct drm_device *d
- return -EINVAL;
- }
-
--#if 0
-- DRM_INFO("0x%08x: packet %d (%s) size %d processing...\n",
-- src_offset, cmd, info->name, info->len);
--#endif
--
- if (src_offset + info->len > len) {
- DRM_ERROR("0x%08x: packet %d (%s) length 0x%08x "
- "exceeds bounds (0x%08x)\n",
-@@ -558,8 +554,7 @@ vc4_validate_bin_cl(struct drm_device *d
- if (info->func && info->func(exec,
- dst_pkt + 1,
- src_pkt + 1)) {
-- DRM_ERROR("0x%08x: packet %d (%s) failed to "
-- "validate\n",
-+ DRM_ERROR("0x%08x: packet %d (%s) failed to validate\n",
- src_offset, cmd, info->name);
- return -EINVAL;
- }
-@@ -618,12 +613,14 @@ reloc_tex(struct vc4_exec_info *exec,
-
- if (sample->is_direct) {
- uint32_t remaining_size = tex->base.size - p0;
-+
- if (p0 > tex->base.size - 4) {
- DRM_ERROR("UBO offset greater than UBO size\n");
- goto fail;
- }
- if (p1 > remaining_size - 4) {
-- DRM_ERROR("UBO clamp would allow reads outside of UBO\n");
-+ DRM_ERROR("UBO clamp would allow reads "
-+ "outside of UBO\n");
- goto fail;
- }
- *validated_p0 = tex->paddr + p0;
-@@ -786,7 +783,7 @@ validate_shader_rec(struct drm_device *d
- struct drm_gem_cma_object *bo[ARRAY_SIZE(gl_relocs) + 8];
- uint32_t nr_attributes = 0, nr_fixed_relocs, nr_relocs, packet_size;
- int i;
-- struct vc4_validated_shader_info *validated_shader;
-+ struct vc4_validated_shader_info *shader;
-
- if (state->packet == VC4_PACKET_NV_SHADER_STATE) {
- relocs = nv_relocs;
-@@ -841,12 +838,12 @@ validate_shader_rec(struct drm_device *d
- else
- mode = VC4_MODE_RENDER;
-
-- if (!vc4_use_bo(exec, src_handles[i], mode, &bo[i])) {
-+ if (!vc4_use_bo(exec, src_handles[i], mode, &bo[i]))
- return false;
-- }
- }
-
- for (i = 0; i < nr_fixed_relocs; i++) {
-+ struct vc4_bo *vc4_bo;
- uint32_t o = relocs[i].offset;
- uint32_t src_offset = *(uint32_t *)(pkt_u + o);
- uint32_t *texture_handles_u;
-@@ -858,34 +855,34 @@ validate_shader_rec(struct drm_device *d
- switch (relocs[i].type) {
- case RELOC_CODE:
- if (src_offset != 0) {
-- DRM_ERROR("Shaders must be at offset 0 of "
-- "the BO.\n");
-+ DRM_ERROR("Shaders must be at offset 0 "
-+ "of the BO.\n");
- goto fail;
- }
-
-- validated_shader = to_vc4_bo(&bo[i]->base)->validated_shader;
-- if (!validated_shader)
-+ vc4_bo = to_vc4_bo(&bo[i]->base);
-+ shader = vc4_bo->validated_shader;
-+ if (!shader)
- goto fail;
-
-- if (validated_shader->uniforms_src_size >
-- exec->uniforms_size) {
-+ if (shader->uniforms_src_size > exec->uniforms_size) {
- DRM_ERROR("Uniforms src buffer overflow\n");
- goto fail;
- }
-
- texture_handles_u = exec->uniforms_u;
- uniform_data_u = (texture_handles_u +
-- validated_shader->num_texture_samples);
-+ shader->num_texture_samples);
-
- memcpy(exec->uniforms_v, uniform_data_u,
-- validated_shader->uniforms_size);
-+ shader->uniforms_size);
-
- for (tex = 0;
-- tex < validated_shader->num_texture_samples;
-+ tex < shader->num_texture_samples;
- tex++) {
- if (!reloc_tex(exec,
- uniform_data_u,
-- &validated_shader->texture_samples[tex],
-+ &shader->texture_samples[tex],
- texture_handles_u[tex])) {
- goto fail;
- }
-@@ -893,9 +890,9 @@ validate_shader_rec(struct drm_device *d
-
- *(uint32_t *)(pkt_v + o + 4) = exec->uniforms_p;
-
-- exec->uniforms_u += validated_shader->uniforms_src_size;
-- exec->uniforms_v += validated_shader->uniforms_size;
-- exec->uniforms_p += validated_shader->uniforms_size;
-+ exec->uniforms_u += shader->uniforms_src_size;
-+ exec->uniforms_v += shader->uniforms_size;
-+ exec->uniforms_p += shader->uniforms_size;
-
- break;
-
-@@ -926,7 +923,8 @@ validate_shader_rec(struct drm_device *d
- max_index = ((vbo->base.size - offset - attr_size) /
- stride);
- if (state->max_index > max_index) {
-- DRM_ERROR("primitives use index %d out of supplied %d\n",
-+ DRM_ERROR("primitives use index %d out of "
-+ "supplied %d\n",
- state->max_index, max_index);
- return -EINVAL;
- }
---- a/drivers/gpu/drm/vc4/vc4_validate_shaders.c
-+++ b/drivers/gpu/drm/vc4/vc4_validate_shaders.c
-@@ -24,24 +24,16 @@
- /**
- * DOC: Shader validator for VC4.
- *
-- * The VC4 has no IOMMU between it and system memory. So, a user with access
-- * to execute shaders could escalate privilege by overwriting system memory
-- * (using the VPM write address register in the general-purpose DMA mode) or
-- * reading system memory it shouldn't (reading it as a texture, or uniform
-- * data, or vertex data).
-+ * The VC4 has no IOMMU between it and system memory, so a user with
-+ * access to execute shaders could escalate privilege by overwriting
-+ * system memory (using the VPM write address register in the
-+ * general-purpose DMA mode) or reading system memory it shouldn't
-+ * (reading it as a texture, or uniform data, or vertex data).
- *
-- * This walks over a shader starting from some offset within a BO, ensuring
-- * that its accesses are appropriately bounded, and recording how many texture
-- * accesses are made and where so that we can do relocations for them in the
-+ * This walks over a shader BO, ensuring that its accesses are
-+ * appropriately bounded, and recording how many texture accesses are
-+ * made and where so that we can do relocations for them in the
- * uniform stream.
-- *
-- * The kernel API has shaders stored in user-mapped BOs. The BOs will be
-- * forcibly unmapped from the process before validation, and any cache of
-- * validated state will be flushed if the mapping is faulted back in.
-- *
-- * Storing the shaders in BOs means that the validation process will be slow
-- * due to uncached reads, but since shaders are long-lived and shader BOs are
-- * never actually modified, this shouldn't be a problem.
- */
-
- #include "vc4_drv.h"
-@@ -70,7 +62,6 @@ waddr_to_live_reg_index(uint32_t waddr,
- else
- return waddr;
- } else if (waddr <= QPU_W_ACC3) {
--
- return 64 + waddr - QPU_W_ACC0;
- } else {
- return ~0;
-@@ -85,15 +76,14 @@ raddr_add_a_to_live_reg_index(uint64_t i
- uint32_t raddr_a = QPU_GET_FIELD(inst, QPU_RADDR_A);
- uint32_t raddr_b = QPU_GET_FIELD(inst, QPU_RADDR_B);
-
-- if (add_a == QPU_MUX_A) {
-+ if (add_a == QPU_MUX_A)
- return raddr_a;
-- } else if (add_a == QPU_MUX_B && sig != QPU_SIG_SMALL_IMM) {
-+ else if (add_a == QPU_MUX_B && sig != QPU_SIG_SMALL_IMM)
- return 32 + raddr_b;
-- } else if (add_a <= QPU_MUX_R3) {
-+ else if (add_a <= QPU_MUX_R3)
- return 64 + add_a;
-- } else {
-+ else
- return ~0;
-- }
- }
-
- static bool
-@@ -111,9 +101,9 @@ is_tmu_write(uint32_t waddr)
- }
-
- static bool
--record_validated_texture_sample(struct vc4_validated_shader_info *validated_shader,
-- struct vc4_shader_validation_state *validation_state,
-- int tmu)
-+record_texture_sample(struct vc4_validated_shader_info *validated_shader,
-+ struct vc4_shader_validation_state *validation_state,
-+ int tmu)
- {
- uint32_t s = validated_shader->num_texture_samples;
- int i;
-@@ -226,8 +216,8 @@ check_tmu_write(uint64_t inst,
- validated_shader->uniforms_size += 4;
-
- if (submit) {
-- if (!record_validated_texture_sample(validated_shader,
-- validation_state, tmu)) {
-+ if (!record_texture_sample(validated_shader,
-+ validation_state, tmu)) {
- return false;
- }
-
-@@ -238,10 +228,10 @@ check_tmu_write(uint64_t inst,
- }
-
- static bool
--check_register_write(uint64_t inst,
-- struct vc4_validated_shader_info *validated_shader,
-- struct vc4_shader_validation_state *validation_state,
-- bool is_mul)
-+check_reg_write(uint64_t inst,
-+ struct vc4_validated_shader_info *validated_shader,
-+ struct vc4_shader_validation_state *validation_state,
-+ bool is_mul)
- {
- uint32_t waddr = (is_mul ?
- QPU_GET_FIELD(inst, QPU_WADDR_MUL) :
-@@ -297,7 +287,7 @@ check_register_write(uint64_t inst,
- return true;
-
- case QPU_W_TLB_STENCIL_SETUP:
-- return true;
-+ return true;
- }
-
- return true;
-@@ -360,7 +350,7 @@ track_live_clamps(uint64_t inst,
- }
-
- validation_state->live_max_clamp_regs[lri_add] = true;
-- } if (op_add == QPU_A_MIN) {
-+ } else if (op_add == QPU_A_MIN) {
- /* Track live clamps of a value clamped to a minimum of 0 and
- * a maximum of some uniform's offset.
- */
-@@ -392,8 +382,10 @@ check_instruction_writes(uint64_t inst,
- return false;
- }
-
-- ok = (check_register_write(inst, validated_shader, validation_state, false) &&
-- check_register_write(inst, validated_shader, validation_state, true));
-+ ok = (check_reg_write(inst, validated_shader, validation_state,
-+ false) &&
-+ check_reg_write(inst, validated_shader, validation_state,
-+ true));
-
- track_live_clamps(inst, validated_shader, validation_state);
-
-@@ -441,7 +433,7 @@ vc4_validate_shader(struct drm_gem_cma_o
- shader = shader_obj->vaddr;
- max_ip = shader_obj->base.size / sizeof(uint64_t);
-
-- validated_shader = kcalloc(sizeof(*validated_shader), 1, GFP_KERNEL);
-+ validated_shader = kcalloc(1, sizeof(*validated_shader), GFP_KERNEL);
- if (!validated_shader)
- return NULL;
-
-@@ -497,7 +489,7 @@ vc4_validate_shader(struct drm_gem_cma_o
-
- if (ip == max_ip) {
- DRM_ERROR("shader failed to terminate before "
-- "shader BO end at %d\n",
-+ "shader BO end at %zd\n",
- shader_obj->base.size);
- goto fail;
- }
---- a/include/drm/drmP.h
-+++ b/include/drm/drmP.h
-@@ -585,6 +585,13 @@ struct drm_driver {
- int (*gem_open_object) (struct drm_gem_object *, struct drm_file *);
- void (*gem_close_object) (struct drm_gem_object *, struct drm_file *);
-
-+ /**
-+ * Hook for allocating the GEM object struct, for use by core
-+ * helpers.
-+ */
-+ struct drm_gem_object *(*gem_create_object)(struct drm_device *dev,
-+ size_t size);
-+
- /* prime: */
- /* export handle -> fd (see drm_gem_prime_handle_to_fd() helper) */
- int (*prime_handle_to_fd)(struct drm_device *dev, struct drm_file *file_priv,
-@@ -639,7 +646,6 @@ struct drm_driver {
-
- u32 driver_features;
- int dev_priv_size;
-- size_t gem_obj_size;
- const struct drm_ioctl_desc *ioctls;
- int num_ioctls;
- const struct file_operations *fops;
diff --git a/target/linux/brcm2708/patches-4.4/0116-drm-Use-the-driver-s-gem_object_free-function-from-C.patch b/target/linux/brcm2708/patches-4.4/0116-drm-Use-the-driver-s-gem_object_free-function-from-C.patch
deleted file mode 100644
index 7f1ce7b15d..0000000000
--- a/target/linux/brcm2708/patches-4.4/0116-drm-Use-the-driver-s-gem_object_free-function-from-C.patch
+++ /dev/null
@@ -1,59 +0,0 @@
-From 7d4ed9f40e9484ded3965b13fbb7914a1daf85d7 Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Fri, 11 Dec 2015 19:45:03 -0800
-Subject: [PATCH 116/170] drm: Use the driver's gem_object_free function from
- CMA helpers.
-
-VC4 wraps the CMA objects in its own structures, so it needs to do its
-own teardown (waiting for GPU to finish, updating bo_stats tracking).
-The other CMA drivers are using drm_gem_cma_free_object as their
-gem_free_object, so this should be a no-op for them.
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
----
- drivers/gpu/drm/drm_fb_cma_helper.c | 6 +++---
- drivers/gpu/drm/drm_gem_cma_helper.c | 4 ++--
- 2 files changed, 5 insertions(+), 5 deletions(-)
-
---- a/drivers/gpu/drm/drm_fb_cma_helper.c
-+++ b/drivers/gpu/drm/drm_fb_cma_helper.c
-@@ -266,7 +266,7 @@ static int drm_fbdev_cma_create(struct d
- fbi = drm_fb_helper_alloc_fbi(helper);
- if (IS_ERR(fbi)) {
- ret = PTR_ERR(fbi);
-- goto err_drm_gem_cma_free_object;
-+ goto err_gem_free_object;
- }
-
- fbdev_cma->fb = drm_fb_cma_alloc(dev, &mode_cmd, &obj, 1);
-@@ -299,8 +299,8 @@ static int drm_fbdev_cma_create(struct d
-
- err_fb_info_destroy:
- drm_fb_helper_release_fbi(helper);
--err_drm_gem_cma_free_object:
-- drm_gem_cma_free_object(&obj->base);
-+err_gem_free_object:
-+ dev->driver->gem_free_object(&obj->base);
- return ret;
- }
-
---- a/drivers/gpu/drm/drm_gem_cma_helper.c
-+++ b/drivers/gpu/drm/drm_gem_cma_helper.c
-@@ -121,7 +121,7 @@ struct drm_gem_cma_object *drm_gem_cma_c
- return cma_obj;
-
- error:
-- drm_gem_cma_free_object(&cma_obj->base);
-+ drm->driver->gem_free_object(&cma_obj->base);
- return ERR_PTR(ret);
- }
- EXPORT_SYMBOL_GPL(drm_gem_cma_create);
-@@ -171,7 +171,7 @@ drm_gem_cma_create_with_handle(struct dr
- return cma_obj;
-
- err_handle_create:
-- drm_gem_cma_free_object(gem_obj);
-+ drm->driver->gem_free_object(gem_obj);
-
- return ERR_PTR(ret);
- }
diff --git a/target/linux/brcm2708/patches-4.4/0116-drm-vc4-Add-support-for-MSAA-rendering.patch b/target/linux/brcm2708/patches-4.4/0116-drm-vc4-Add-support-for-MSAA-rendering.patch
new file mode 100644
index 0000000000..8e6232a8a9
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0116-drm-vc4-Add-support-for-MSAA-rendering.patch
@@ -0,0 +1,518 @@
+From 5405b6f75f7021db041e2dd0bb8720baf6d3122b Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Fri, 17 Jul 2015 13:15:50 -0700
+Subject: [PATCH 116/381] drm/vc4: Add support for MSAA rendering.
+
+For MSAA, you set a bit in the binner that halves the size of tiles in
+each direction, so you can pack 4 samples per pixel in the tile
+buffer. During rendering, you can load and store raw tile buffer
+contents (to save the per-sample MSAA contents), or you can load/store
+resolved tile buffer contents (loads spam the pixel value to all 4
+samples, and stores either average the 4 color samples, or store the
+first sample for Z/S).
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_packet.h | 23 ++-
+ drivers/gpu/drm/vc4/vc4_render_cl.c | 274 ++++++++++++++++++++++++++++++------
+ drivers/gpu/drm/vc4/vc4_validate.c | 5 +-
+ include/uapi/drm/vc4_drm.h | 11 +-
+ 4 files changed, 258 insertions(+), 55 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_packet.h
++++ b/drivers/gpu/drm/vc4/vc4_packet.h
+@@ -123,6 +123,11 @@ enum vc4_packet {
+ #define VC4_PACKET_TILE_COORDINATES_SIZE 3
+ #define VC4_PACKET_GEM_HANDLES_SIZE 9
+
++/* Number of multisamples supported. */
++#define VC4_MAX_SAMPLES 4
++/* Size of a full resolution color or Z tile buffer load/store. */
++#define VC4_TILE_BUFFER_SIZE (64 * 64 * 4)
++
+ /** @{
+ * Bits used by packets like VC4_PACKET_STORE_TILE_BUFFER_GENERAL and
+ * VC4_PACKET_TILE_RENDERING_MODE_CONFIG.
+@@ -137,10 +142,20 @@ enum vc4_packet {
+ * low bits of VC4_PACKET_STORE_FULL_RES_TILE_BUFFER and
+ * VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER.
+ */
+-#define VC4_LOADSTORE_FULL_RES_EOF (1 << 3)
+-#define VC4_LOADSTORE_FULL_RES_DISABLE_CLEAR_ALL (1 << 2)
+-#define VC4_LOADSTORE_FULL_RES_DISABLE_ZS (1 << 1)
+-#define VC4_LOADSTORE_FULL_RES_DISABLE_COLOR (1 << 0)
++#define VC4_LOADSTORE_FULL_RES_EOF BIT(3)
++#define VC4_LOADSTORE_FULL_RES_DISABLE_CLEAR_ALL BIT(2)
++#define VC4_LOADSTORE_FULL_RES_DISABLE_ZS BIT(1)
++#define VC4_LOADSTORE_FULL_RES_DISABLE_COLOR BIT(0)
++
++/** @{
++ *
++ * low bits of VC4_PACKET_STORE_FULL_RES_TILE_BUFFER and
++ * VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER.
++ */
++#define VC4_LOADSTORE_FULL_RES_EOF BIT(3)
++#define VC4_LOADSTORE_FULL_RES_DISABLE_CLEAR_ALL BIT(2)
++#define VC4_LOADSTORE_FULL_RES_DISABLE_ZS BIT(1)
++#define VC4_LOADSTORE_FULL_RES_DISABLE_COLOR BIT(0)
+
+ /** @{
+ *
+--- a/drivers/gpu/drm/vc4/vc4_render_cl.c
++++ b/drivers/gpu/drm/vc4/vc4_render_cl.c
+@@ -37,9 +37,11 @@
+
+ struct vc4_rcl_setup {
+ struct drm_gem_cma_object *color_read;
+- struct drm_gem_cma_object *color_ms_write;
++ struct drm_gem_cma_object *color_write;
+ struct drm_gem_cma_object *zs_read;
+ struct drm_gem_cma_object *zs_write;
++ struct drm_gem_cma_object *msaa_color_write;
++ struct drm_gem_cma_object *msaa_zs_write;
+
+ struct drm_gem_cma_object *rcl;
+ u32 next_offset;
+@@ -82,6 +84,22 @@ static void vc4_store_before_load(struct
+ }
+
+ /*
++ * Calculates the physical address of the start of a tile in a RCL surface.
++ *
++ * Unlike the other load/store packets,
++ * VC4_PACKET_LOAD/STORE_FULL_RES_TILE_BUFFER don't look at the tile
++ * coordinates packet, and instead just store to the address given.
++ */
++static uint32_t vc4_full_res_offset(struct vc4_exec_info *exec,
++ struct drm_gem_cma_object *bo,
++ struct drm_vc4_submit_rcl_surface *surf,
++ uint8_t x, uint8_t y)
++{
++ return bo->paddr + surf->offset + VC4_TILE_BUFFER_SIZE *
++ (DIV_ROUND_UP(exec->args->width, 32) * y + x);
++}
++
++/*
+ * Emits a PACKET_TILE_COORDINATES if one isn't already pending.
+ *
+ * The tile coordinates packet triggers a pending load if there is one, are
+@@ -108,22 +126,41 @@ static void emit_tile(struct vc4_exec_in
+ * may be outstanding at a time.
+ */
+ if (setup->color_read) {
+- rcl_u8(setup, VC4_PACKET_LOAD_TILE_BUFFER_GENERAL);
+- rcl_u16(setup, args->color_read.bits);
+- rcl_u32(setup,
+- setup->color_read->paddr + args->color_read.offset);
++ if (args->color_read.flags &
++ VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) {
++ rcl_u8(setup, VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER);
++ rcl_u32(setup,
++ vc4_full_res_offset(exec, setup->color_read,
++ &args->color_read, x, y) |
++ VC4_LOADSTORE_FULL_RES_DISABLE_ZS);
++ } else {
++ rcl_u8(setup, VC4_PACKET_LOAD_TILE_BUFFER_GENERAL);
++ rcl_u16(setup, args->color_read.bits);
++ rcl_u32(setup, setup->color_read->paddr +
++ args->color_read.offset);
++ }
+ }
+
+ if (setup->zs_read) {
+- if (setup->color_read) {
+- /* Exec previous load. */
+- vc4_tile_coordinates(setup, x, y);
+- vc4_store_before_load(setup);
++ if (args->zs_read.flags &
++ VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) {
++ rcl_u8(setup, VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER);
++ rcl_u32(setup,
++ vc4_full_res_offset(exec, setup->zs_read,
++ &args->zs_read, x, y) |
++ VC4_LOADSTORE_FULL_RES_DISABLE_COLOR);
++ } else {
++ if (setup->color_read) {
++ /* Exec previous load. */
++ vc4_tile_coordinates(setup, x, y);
++ vc4_store_before_load(setup);
++ }
++
++ rcl_u8(setup, VC4_PACKET_LOAD_TILE_BUFFER_GENERAL);
++ rcl_u16(setup, args->zs_read.bits);
++ rcl_u32(setup, setup->zs_read->paddr +
++ args->zs_read.offset);
+ }
+-
+- rcl_u8(setup, VC4_PACKET_LOAD_TILE_BUFFER_GENERAL);
+- rcl_u16(setup, args->zs_read.bits);
+- rcl_u32(setup, setup->zs_read->paddr + args->zs_read.offset);
+ }
+
+ /* Clipping depends on tile coordinates having been
+@@ -144,20 +181,60 @@ static void emit_tile(struct vc4_exec_in
+ (y * exec->bin_tiles_x + x) * 32));
+ }
+
++ if (setup->msaa_color_write) {
++ bool last_tile_write = (!setup->msaa_zs_write &&
++ !setup->zs_write &&
++ !setup->color_write);
++ uint32_t bits = VC4_LOADSTORE_FULL_RES_DISABLE_ZS;
++
++ if (!last_tile_write)
++ bits |= VC4_LOADSTORE_FULL_RES_DISABLE_CLEAR_ALL;
++ else if (last)
++ bits |= VC4_LOADSTORE_FULL_RES_EOF;
++ rcl_u8(setup, VC4_PACKET_STORE_FULL_RES_TILE_BUFFER);
++ rcl_u32(setup,
++ vc4_full_res_offset(exec, setup->msaa_color_write,
++ &args->msaa_color_write, x, y) |
++ bits);
++ }
++
++ if (setup->msaa_zs_write) {
++ bool last_tile_write = (!setup->zs_write &&
++ !setup->color_write);
++ uint32_t bits = VC4_LOADSTORE_FULL_RES_DISABLE_COLOR;
++
++ if (setup->msaa_color_write)
++ vc4_tile_coordinates(setup, x, y);
++ if (!last_tile_write)
++ bits |= VC4_LOADSTORE_FULL_RES_DISABLE_CLEAR_ALL;
++ else if (last)
++ bits |= VC4_LOADSTORE_FULL_RES_EOF;
++ rcl_u8(setup, VC4_PACKET_STORE_FULL_RES_TILE_BUFFER);
++ rcl_u32(setup,
++ vc4_full_res_offset(exec, setup->msaa_zs_write,
++ &args->msaa_zs_write, x, y) |
++ bits);
++ }
++
+ if (setup->zs_write) {
++ bool last_tile_write = !setup->color_write;
++
++ if (setup->msaa_color_write || setup->msaa_zs_write)
++ vc4_tile_coordinates(setup, x, y);
++
+ rcl_u8(setup, VC4_PACKET_STORE_TILE_BUFFER_GENERAL);
+ rcl_u16(setup, args->zs_write.bits |
+- (setup->color_ms_write ?
+- VC4_STORE_TILE_BUFFER_DISABLE_COLOR_CLEAR : 0));
++ (last_tile_write ?
++ 0 : VC4_STORE_TILE_BUFFER_DISABLE_COLOR_CLEAR));
+ rcl_u32(setup,
+ (setup->zs_write->paddr + args->zs_write.offset) |
+- ((last && !setup->color_ms_write) ?
++ ((last && last_tile_write) ?
+ VC4_LOADSTORE_TILE_BUFFER_EOF : 0));
+ }
+
+- if (setup->color_ms_write) {
+- if (setup->zs_write) {
+- /* Reset after previous store */
++ if (setup->color_write) {
++ if (setup->msaa_color_write || setup->msaa_zs_write ||
++ setup->zs_write) {
+ vc4_tile_coordinates(setup, x, y);
+ }
+
+@@ -192,14 +269,26 @@ static int vc4_create_rcl_bo(struct drm_
+ }
+
+ if (setup->color_read) {
+- loop_body_size += (VC4_PACKET_LOAD_TILE_BUFFER_GENERAL_SIZE);
++ if (args->color_read.flags &
++ VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) {
++ loop_body_size += VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER_SIZE;
++ } else {
++ loop_body_size += VC4_PACKET_LOAD_TILE_BUFFER_GENERAL_SIZE;
++ }
+ }
+ if (setup->zs_read) {
+- if (setup->color_read) {
+- loop_body_size += VC4_PACKET_TILE_COORDINATES_SIZE;
+- loop_body_size += VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE;
++ if (args->zs_read.flags &
++ VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) {
++ loop_body_size += VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER_SIZE;
++ } else {
++ if (setup->color_read &&
++ !(args->color_read.flags &
++ VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES)) {
++ loop_body_size += VC4_PACKET_TILE_COORDINATES_SIZE;
++ loop_body_size += VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE;
++ }
++ loop_body_size += VC4_PACKET_LOAD_TILE_BUFFER_GENERAL_SIZE;
+ }
+- loop_body_size += VC4_PACKET_LOAD_TILE_BUFFER_GENERAL_SIZE;
+ }
+
+ if (has_bin) {
+@@ -207,13 +296,23 @@ static int vc4_create_rcl_bo(struct drm_
+ loop_body_size += VC4_PACKET_BRANCH_TO_SUB_LIST_SIZE;
+ }
+
++ if (setup->msaa_color_write)
++ loop_body_size += VC4_PACKET_STORE_FULL_RES_TILE_BUFFER_SIZE;
++ if (setup->msaa_zs_write)
++ loop_body_size += VC4_PACKET_STORE_FULL_RES_TILE_BUFFER_SIZE;
++
+ if (setup->zs_write)
+ loop_body_size += VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE;
+- if (setup->color_ms_write) {
+- if (setup->zs_write)
+- loop_body_size += VC4_PACKET_TILE_COORDINATES_SIZE;
++ if (setup->color_write)
+ loop_body_size += VC4_PACKET_STORE_MS_TILE_BUFFER_SIZE;
+- }
++
++ /* We need a VC4_PACKET_TILE_COORDINATES in between each store. */
++ loop_body_size += VC4_PACKET_TILE_COORDINATES_SIZE *
++ ((setup->msaa_color_write != NULL) +
++ (setup->msaa_zs_write != NULL) +
++ (setup->color_write != NULL) +
++ (setup->zs_write != NULL) - 1);
++
+ size += xtiles * ytiles * loop_body_size;
+
+ setup->rcl = &vc4_bo_create(dev, size, true)->base;
+@@ -224,13 +323,12 @@ static int vc4_create_rcl_bo(struct drm_
+
+ rcl_u8(setup, VC4_PACKET_TILE_RENDERING_MODE_CONFIG);
+ rcl_u32(setup,
+- (setup->color_ms_write ?
+- (setup->color_ms_write->paddr +
+- args->color_ms_write.offset) :
++ (setup->color_write ? (setup->color_write->paddr +
++ args->color_write.offset) :
+ 0));
+ rcl_u16(setup, args->width);
+ rcl_u16(setup, args->height);
+- rcl_u16(setup, args->color_ms_write.bits);
++ rcl_u16(setup, args->color_write.bits);
+
+ /* The tile buffer gets cleared when the previous tile is stored. If
+ * the clear values changed between frames, then the tile buffer has
+@@ -267,6 +365,56 @@ static int vc4_create_rcl_bo(struct drm_
+ return 0;
+ }
+
++static int vc4_full_res_bounds_check(struct vc4_exec_info *exec,
++ struct drm_gem_cma_object *obj,
++ struct drm_vc4_submit_rcl_surface *surf)
++{
++ struct drm_vc4_submit_cl *args = exec->args;
++ u32 render_tiles_stride = DIV_ROUND_UP(exec->args->width, 32);
++
++ if (surf->offset > obj->base.size) {
++ DRM_ERROR("surface offset %d > BO size %zd\n",
++ surf->offset, obj->base.size);
++ return -EINVAL;
++ }
++
++ if ((obj->base.size - surf->offset) / VC4_TILE_BUFFER_SIZE <
++ render_tiles_stride * args->max_y_tile + args->max_x_tile) {
++ DRM_ERROR("MSAA tile %d, %d out of bounds "
++ "(bo size %zd, offset %d).\n",
++ args->max_x_tile, args->max_y_tile,
++ obj->base.size,
++ surf->offset);
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static int vc4_rcl_msaa_surface_setup(struct vc4_exec_info *exec,
++ struct drm_gem_cma_object **obj,
++ struct drm_vc4_submit_rcl_surface *surf)
++{
++ if (surf->flags != 0 || surf->bits != 0) {
++ DRM_ERROR("MSAA surface had nonzero flags/bits\n");
++ return -EINVAL;
++ }
++
++ if (surf->hindex == ~0)
++ return 0;
++
++ *obj = vc4_use_bo(exec, surf->hindex);
++ if (!*obj)
++ return -EINVAL;
++
++ if (surf->offset & 0xf) {
++ DRM_ERROR("MSAA write must be 16b aligned.\n");
++ return -EINVAL;
++ }
++
++ return vc4_full_res_bounds_check(exec, *obj, surf);
++}
++
+ static int vc4_rcl_surface_setup(struct vc4_exec_info *exec,
+ struct drm_gem_cma_object **obj,
+ struct drm_vc4_submit_rcl_surface *surf)
+@@ -278,9 +426,10 @@ static int vc4_rcl_surface_setup(struct
+ uint8_t format = VC4_GET_FIELD(surf->bits,
+ VC4_LOADSTORE_TILE_BUFFER_FORMAT);
+ int cpp;
++ int ret;
+
+- if (surf->pad != 0) {
+- DRM_ERROR("Padding unset\n");
++ if (surf->flags & ~VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) {
++ DRM_ERROR("Extra flags set\n");
+ return -EINVAL;
+ }
+
+@@ -290,6 +439,25 @@ static int vc4_rcl_surface_setup(struct
+ if (!vc4_use_bo(exec, surf->hindex, VC4_MODE_RENDER, obj))
+ return -EINVAL;
+
++ if (surf->flags & VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) {
++ if (surf == &exec->args->zs_write) {
++ DRM_ERROR("general zs write may not be a full-res.\n");
++ return -EINVAL;
++ }
++
++ if (surf->bits != 0) {
++ DRM_ERROR("load/store general bits set with "
++ "full res load/store.\n");
++ return -EINVAL;
++ }
++
++ ret = vc4_full_res_bounds_check(exec, *obj, surf);
++ if (!ret)
++ return ret;
++
++ return 0;
++ }
++
+ if (surf->bits & ~(VC4_LOADSTORE_TILE_BUFFER_TILING_MASK |
+ VC4_LOADSTORE_TILE_BUFFER_BUFFER_MASK |
+ VC4_LOADSTORE_TILE_BUFFER_FORMAT_MASK)) {
+@@ -341,9 +509,10 @@ static int vc4_rcl_surface_setup(struct
+ }
+
+ static int
+-vc4_rcl_ms_surface_setup(struct vc4_exec_info *exec,
+- struct drm_gem_cma_object **obj,
+- struct drm_vc4_submit_rcl_surface *surf)
++vc4_rcl_render_config_surface_setup(struct vc4_exec_info *exec,
++ struct vc4_rcl_setup *setup,
++ struct drm_gem_cma_object **obj,
++ struct drm_vc4_submit_rcl_surface *surf)
+ {
+ uint8_t tiling = VC4_GET_FIELD(surf->bits,
+ VC4_RENDER_CONFIG_MEMORY_FORMAT);
+@@ -351,13 +520,15 @@ vc4_rcl_ms_surface_setup(struct vc4_exec
+ VC4_RENDER_CONFIG_FORMAT);
+ int cpp;
+
+- if (surf->pad != 0) {
+- DRM_ERROR("Padding unset\n");
++ if (surf->flags != 0) {
++ DRM_ERROR("No flags supported on render config.\n");
+ return -EINVAL;
+ }
+
+ if (surf->bits & ~(VC4_RENDER_CONFIG_MEMORY_FORMAT_MASK |
+- VC4_RENDER_CONFIG_FORMAT_MASK)) {
++ VC4_RENDER_CONFIG_FORMAT_MASK |
++ VC4_RENDER_CONFIG_MS_MODE_4X |
++ VC4_RENDER_CONFIG_DECIMATE_MODE_4X)) {
+ DRM_ERROR("Unknown bits in render config: 0x%04x\n",
+ surf->bits);
+ return -EINVAL;
+@@ -413,18 +584,20 @@ int vc4_get_rcl(struct drm_device *dev,
+ if (has_bin &&
+ (args->max_x_tile > exec->bin_tiles_x ||
+ args->max_y_tile > exec->bin_tiles_y)) {
+- DRM_ERROR("Render tiles (%d,%d) outside of bin config (%d,%d)\n",
++ DRM_ERROR("Render tiles (%d,%d) outside of bin config "
++ "(%d,%d)\n",
+ args->max_x_tile, args->max_y_tile,
+ exec->bin_tiles_x, exec->bin_tiles_y);
+ return -EINVAL;
+ }
+
+- ret = vc4_rcl_surface_setup(exec, &setup.color_read, &args->color_read);
++ ret = vc4_rcl_render_config_surface_setup(exec, &setup,
++ &setup.color_write,
++ &args->color_write);
+ if (ret)
+ return ret;
+
+- ret = vc4_rcl_ms_surface_setup(exec, &setup.color_ms_write,
+- &args->color_ms_write);
++ ret = vc4_rcl_surface_setup(exec, &setup.color_read, &args->color_read);
+ if (ret)
+ return ret;
+
+@@ -436,10 +609,21 @@ int vc4_get_rcl(struct drm_device *dev,
+ if (ret)
+ return ret;
+
++ ret = vc4_rcl_msaa_surface_setup(exec, &setup.msaa_color_write,
++ &args->msaa_color_write);
++ if (ret)
++ return ret;
++
++ ret = vc4_rcl_msaa_surface_setup(exec, &setup.msaa_zs_write,
++ &args->msaa_zs_write);
++ if (ret)
++ return ret;
++
+ /* We shouldn't even have the job submitted to us if there's no
+ * surface to write out.
+ */
+- if (!setup.color_ms_write && !setup.zs_write) {
++ if (!setup.color_write && !setup.zs_write &&
++ !setup.msaa_color_write && !setup.msaa_zs_write) {
+ DRM_ERROR("RCL requires color or Z/S write\n");
+ return -EINVAL;
+ }
+--- a/drivers/gpu/drm/vc4/vc4_validate.c
++++ b/drivers/gpu/drm/vc4/vc4_validate.c
+@@ -400,9 +400,8 @@ validate_tile_binning_config(VALIDATE_AR
+ }
+
+ if (flags & (VC4_BIN_CONFIG_DB_NON_MS |
+- VC4_BIN_CONFIG_TILE_BUFFER_64BIT |
+- VC4_BIN_CONFIG_MS_MODE_4X)) {
+- DRM_ERROR("unsupported bining config flags 0x%02x\n", flags);
++ VC4_BIN_CONFIG_TILE_BUFFER_64BIT)) {
++ DRM_ERROR("unsupported binning config flags 0x%02x\n", flags);
+ return -EINVAL;
+ }
+
+--- a/include/uapi/drm/vc4_drm.h
++++ b/include/uapi/drm/vc4_drm.h
+@@ -46,10 +46,13 @@ struct drm_vc4_submit_rcl_surface {
+ uint32_t hindex; /* Handle index, or ~0 if not present. */
+ uint32_t offset; /* Offset to start of buffer. */
+ /*
+- * Bits for either render config (color_ms_write) or load/store packet.
++ * Bits for either render config (color_write) or load/store packet.
++ * Bits should all be 0 for MSAA load/stores.
+ */
+ uint16_t bits;
+- uint16_t pad;
++
++#define VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES (1 << 0)
++ uint16_t flags;
+ };
+
+ /**
+@@ -128,9 +131,11 @@ struct drm_vc4_submit_cl {
+ uint8_t max_x_tile;
+ uint8_t max_y_tile;
+ struct drm_vc4_submit_rcl_surface color_read;
+- struct drm_vc4_submit_rcl_surface color_ms_write;
++ struct drm_vc4_submit_rcl_surface color_write;
+ struct drm_vc4_submit_rcl_surface zs_read;
+ struct drm_vc4_submit_rcl_surface zs_write;
++ struct drm_vc4_submit_rcl_surface msaa_color_write;
++ struct drm_vc4_submit_rcl_surface msaa_zs_write;
+ uint32_t clear_color[2];
+ uint32_t clear_z;
+ uint8_t clear_s;
diff --git a/target/linux/brcm2708/patches-4.4/0117-drm-vc4-A-few-more-non-functional-changes-to-sync-to.patch b/target/linux/brcm2708/patches-4.4/0117-drm-vc4-A-few-more-non-functional-changes-to-sync-to.patch
new file mode 100644
index 0000000000..3ffab7f67c
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0117-drm-vc4-A-few-more-non-functional-changes-to-sync-to.patch
@@ -0,0 +1,345 @@
+From 95ef989ba2f3a5e10c742a3f6ed88e16a9f11e56 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Tue, 8 Dec 2015 14:00:43 -0800
+Subject: [PATCH 117/381] drm/vc4: A few more non-functional changes to sync to
+ upstream.
+
+At this point all that's left is the force-enable of HDMI connector,
+and using direct firmware calls to turn on V3D instead of the generic
+power domain support.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_v3d.c | 2 +-
+ include/uapi/drm/vc4_drm.h | 182 +++++++++++++++++++++---------------------
+ 2 files changed, 92 insertions(+), 92 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_v3d.c
++++ b/drivers/gpu/drm/vc4/vc4_v3d.c
+@@ -109,7 +109,7 @@ static const struct {
+
+ int vc4_v3d_debugfs_regs(struct seq_file *m, void *unused)
+ {
+- struct drm_info_node *node = (struct drm_info_node *) m->private;
++ struct drm_info_node *node = (struct drm_info_node *)m->private;
+ struct drm_device *dev = node->minor->dev;
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ int i;
+--- a/include/uapi/drm/vc4_drm.h
++++ b/include/uapi/drm/vc4_drm.h
+@@ -24,7 +24,7 @@
+ #ifndef _UAPI_VC4_DRM_H_
+ #define _UAPI_VC4_DRM_H_
+
+-#include <drm/drm.h>
++#include "drm.h"
+
+ #define DRM_VC4_SUBMIT_CL 0x00
+ #define DRM_VC4_WAIT_SEQNO 0x01
+@@ -34,25 +34,25 @@
+ #define DRM_VC4_CREATE_SHADER_BO 0x05
+ #define DRM_VC4_GET_HANG_STATE 0x06
+
+-#define DRM_IOCTL_VC4_SUBMIT_CL DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_SUBMIT_CL, struct drm_vc4_submit_cl)
+-#define DRM_IOCTL_VC4_WAIT_SEQNO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_WAIT_SEQNO, struct drm_vc4_wait_seqno)
+-#define DRM_IOCTL_VC4_WAIT_BO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_WAIT_BO, struct drm_vc4_wait_bo)
+-#define DRM_IOCTL_VC4_CREATE_BO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_CREATE_BO, struct drm_vc4_create_bo)
+-#define DRM_IOCTL_VC4_MMAP_BO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_MMAP_BO, struct drm_vc4_mmap_bo)
+-#define DRM_IOCTL_VC4_CREATE_SHADER_BO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_CREATE_SHADER_BO, struct drm_vc4_create_shader_bo)
+-#define DRM_IOCTL_VC4_GET_HANG_STATE DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_GET_HANG_STATE, struct drm_vc4_get_hang_state)
++#define DRM_IOCTL_VC4_SUBMIT_CL DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_SUBMIT_CL, struct drm_vc4_submit_cl)
++#define DRM_IOCTL_VC4_WAIT_SEQNO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_WAIT_SEQNO, struct drm_vc4_wait_seqno)
++#define DRM_IOCTL_VC4_WAIT_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_WAIT_BO, struct drm_vc4_wait_bo)
++#define DRM_IOCTL_VC4_CREATE_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_CREATE_BO, struct drm_vc4_create_bo)
++#define DRM_IOCTL_VC4_MMAP_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_MMAP_BO, struct drm_vc4_mmap_bo)
++#define DRM_IOCTL_VC4_CREATE_SHADER_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_CREATE_SHADER_BO, struct drm_vc4_create_shader_bo)
++#define DRM_IOCTL_VC4_GET_HANG_STATE DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_GET_HANG_STATE, struct drm_vc4_get_hang_state)
+
+ struct drm_vc4_submit_rcl_surface {
+- uint32_t hindex; /* Handle index, or ~0 if not present. */
+- uint32_t offset; /* Offset to start of buffer. */
++ __u32 hindex; /* Handle index, or ~0 if not present. */
++ __u32 offset; /* Offset to start of buffer. */
+ /*
+- * Bits for either render config (color_write) or load/store packet.
+- * Bits should all be 0 for MSAA load/stores.
++ * Bits for either render config (color_write) or load/store packet.
++ * Bits should all be 0 for MSAA load/stores.
+ */
+- uint16_t bits;
++ __u16 bits;
+
+ #define VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES (1 << 0)
+- uint16_t flags;
++ __u16 flags;
+ };
+
+ /**
+@@ -76,7 +76,7 @@ struct drm_vc4_submit_cl {
+ * then writes out the state updates and draw calls necessary per tile
+ * to the tile allocation BO.
+ */
+- uint64_t bin_cl;
++ __u64 bin_cl;
+
+ /* Pointer to the shader records.
+ *
+@@ -85,16 +85,16 @@ struct drm_vc4_submit_cl {
+ * reference to the shader record has enough information to determine
+ * how many pointers are necessary (fixed number for shaders/uniforms,
+ * and an attribute count), so those BO indices into bo_handles are
+- * just stored as uint32_ts before each shader record passed in.
++ * just stored as __u32s before each shader record passed in.
+ */
+- uint64_t shader_rec;
++ __u64 shader_rec;
+
+ /* Pointer to uniform data and texture handles for the textures
+ * referenced by the shader.
+ *
+ * For each shader state record, there is a set of uniform data in the
+ * order referenced by the record (FS, VS, then CS). Each set of
+- * uniform data has a uint32_t index into bo_handles per texture
++ * uniform data has a __u32 index into bo_handles per texture
+ * sample operation, in the order the QPU_W_TMUn_S writes appear in
+ * the program. Following the texture BO handle indices is the actual
+ * uniform data.
+@@ -103,52 +103,52 @@ struct drm_vc4_submit_cl {
+ * because the kernel has to determine the sizes anyway during shader
+ * code validation.
+ */
+- uint64_t uniforms;
+- uint64_t bo_handles;
++ __u64 uniforms;
++ __u64 bo_handles;
+
+ /* Size in bytes of the binner command list. */
+- uint32_t bin_cl_size;
++ __u32 bin_cl_size;
+ /* Size in bytes of the set of shader records. */
+- uint32_t shader_rec_size;
++ __u32 shader_rec_size;
+ /* Number of shader records.
+ *
+ * This could just be computed from the contents of shader_records and
+ * the address bits of references to them from the bin CL, but it
+ * keeps the kernel from having to resize some allocations it makes.
+ */
+- uint32_t shader_rec_count;
++ __u32 shader_rec_count;
+ /* Size in bytes of the uniform state. */
+- uint32_t uniforms_size;
++ __u32 uniforms_size;
+
+ /* Number of BO handles passed in (size is that times 4). */
+- uint32_t bo_handle_count;
++ __u32 bo_handle_count;
+
+ /* RCL setup: */
+- uint16_t width;
+- uint16_t height;
+- uint8_t min_x_tile;
+- uint8_t min_y_tile;
+- uint8_t max_x_tile;
+- uint8_t max_y_tile;
++ __u16 width;
++ __u16 height;
++ __u8 min_x_tile;
++ __u8 min_y_tile;
++ __u8 max_x_tile;
++ __u8 max_y_tile;
+ struct drm_vc4_submit_rcl_surface color_read;
+ struct drm_vc4_submit_rcl_surface color_write;
+ struct drm_vc4_submit_rcl_surface zs_read;
+ struct drm_vc4_submit_rcl_surface zs_write;
+ struct drm_vc4_submit_rcl_surface msaa_color_write;
+ struct drm_vc4_submit_rcl_surface msaa_zs_write;
+- uint32_t clear_color[2];
+- uint32_t clear_z;
+- uint8_t clear_s;
++ __u32 clear_color[2];
++ __u32 clear_z;
++ __u8 clear_s;
+
+- uint32_t pad:24;
++ __u32 pad:24;
+
+ #define VC4_SUBMIT_CL_USE_CLEAR_COLOR (1 << 0)
+- uint32_t flags;
++ __u32 flags;
+
+ /* Returned value of the seqno of this render job (for the
+ * wait ioctl).
+ */
+- uint64_t seqno;
++ __u64 seqno;
+ };
+
+ /**
+@@ -159,8 +159,8 @@ struct drm_vc4_submit_cl {
+ * block, just return the status."
+ */
+ struct drm_vc4_wait_seqno {
+- uint64_t seqno;
+- uint64_t timeout_ns;
++ __u64 seqno;
++ __u64 timeout_ns;
+ };
+
+ /**
+@@ -172,9 +172,9 @@ struct drm_vc4_wait_seqno {
+ * completed.
+ */
+ struct drm_vc4_wait_bo {
+- uint32_t handle;
+- uint32_t pad;
+- uint64_t timeout_ns;
++ __u32 handle;
++ __u32 pad;
++ __u64 timeout_ns;
+ };
+
+ /**
+@@ -184,11 +184,30 @@ struct drm_vc4_wait_bo {
+ * used in a future extension.
+ */
+ struct drm_vc4_create_bo {
+- uint32_t size;
+- uint32_t flags;
++ __u32 size;
++ __u32 flags;
+ /** Returned GEM handle for the BO. */
+- uint32_t handle;
+- uint32_t pad;
++ __u32 handle;
++ __u32 pad;
++};
++
++/**
++ * struct drm_vc4_mmap_bo - ioctl argument for mapping VC4 BOs.
++ *
++ * This doesn't actually perform an mmap. Instead, it returns the
++ * offset you need to use in an mmap on the DRM device node. This
++ * means that tools like valgrind end up knowing about the mapped
++ * memory.
++ *
++ * There are currently no values for the flags argument, but it may be
++ * used in a future extension.
++ */
++struct drm_vc4_mmap_bo {
++ /** Handle for the object being mapped. */
++ __u32 handle;
++ __u32 flags;
++ /** offset into the drm node to use for subsequent mmap call. */
++ __u64 offset;
+ };
+
+ /**
+@@ -201,43 +220,24 @@ struct drm_vc4_create_bo {
+ */
+ struct drm_vc4_create_shader_bo {
+ /* Size of the data argument. */
+- uint32_t size;
++ __u32 size;
+ /* Flags, currently must be 0. */
+- uint32_t flags;
++ __u32 flags;
+
+ /* Pointer to the data. */
+- uint64_t data;
++ __u64 data;
+
+ /** Returned GEM handle for the BO. */
+- uint32_t handle;
++ __u32 handle;
+ /* Pad, must be 0. */
+- uint32_t pad;
+-};
+-
+-/**
+- * struct drm_vc4_mmap_bo - ioctl argument for mapping VC4 BOs.
+- *
+- * This doesn't actually perform an mmap. Instead, it returns the
+- * offset you need to use in an mmap on the DRM device node. This
+- * means that tools like valgrind end up knowing about the mapped
+- * memory.
+- *
+- * There are currently no values for the flags argument, but it may be
+- * used in a future extension.
+- */
+-struct drm_vc4_mmap_bo {
+- /** Handle for the object being mapped. */
+- uint32_t handle;
+- uint32_t flags;
+- /** offset into the drm node to use for subsequent mmap call. */
+- uint64_t offset;
++ __u32 pad;
+ };
+
+ struct drm_vc4_get_hang_state_bo {
+- uint32_t handle;
+- uint32_t paddr;
+- uint32_t size;
+- uint32_t pad;
++ __u32 handle;
++ __u32 paddr;
++ __u32 size;
++ __u32 pad;
+ };
+
+ /**
+@@ -246,34 +246,34 @@ struct drm_vc4_get_hang_state_bo {
+ */
+ struct drm_vc4_get_hang_state {
+ /** Pointer to array of struct drm_vc4_get_hang_state_bo. */
+- uint64_t bo;
++ __u64 bo;
+ /**
+ * On input, the size of the bo array. Output is the number
+ * of bos to be returned.
+ */
+- uint32_t bo_count;
++ __u32 bo_count;
+
+- uint32_t start_bin, start_render;
++ __u32 start_bin, start_render;
+
+- uint32_t ct0ca, ct0ea;
+- uint32_t ct1ca, ct1ea;
+- uint32_t ct0cs, ct1cs;
+- uint32_t ct0ra0, ct1ra0;
+-
+- uint32_t bpca, bpcs;
+- uint32_t bpoa, bpos;
+-
+- uint32_t vpmbase;
+-
+- uint32_t dbge;
+- uint32_t fdbgo;
+- uint32_t fdbgb;
+- uint32_t fdbgr;
+- uint32_t fdbgs;
+- uint32_t errstat;
++ __u32 ct0ca, ct0ea;
++ __u32 ct1ca, ct1ea;
++ __u32 ct0cs, ct1cs;
++ __u32 ct0ra0, ct1ra0;
++
++ __u32 bpca, bpcs;
++ __u32 bpoa, bpos;
++
++ __u32 vpmbase;
++
++ __u32 dbge;
++ __u32 fdbgo;
++ __u32 fdbgb;
++ __u32 fdbgr;
++ __u32 fdbgs;
++ __u32 errstat;
+
+ /* Pad that we may save more registers into in the future. */
+- uint32_t pad[16];
++ __u32 pad[16];
+ };
+
+ #endif /* _UAPI_VC4_DRM_H_ */
diff --git a/target/linux/brcm2708/patches-4.4/0117-drm-vc4-Add-support-for-MSAA-rendering.patch b/target/linux/brcm2708/patches-4.4/0117-drm-vc4-Add-support-for-MSAA-rendering.patch
deleted file mode 100644
index 92d7eedcdb..0000000000
--- a/target/linux/brcm2708/patches-4.4/0117-drm-vc4-Add-support-for-MSAA-rendering.patch
+++ /dev/null
@@ -1,518 +0,0 @@
-From 522e6f9cc4376fe49e8b41b40e7ddb98cf385a9e Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Fri, 17 Jul 2015 13:15:50 -0700
-Subject: [PATCH 117/170] drm/vc4: Add support for MSAA rendering.
-
-For MSAA, you set a bit in the binner that halves the size of tiles in
-each direction, so you can pack 4 samples per pixel in the tile
-buffer. During rendering, you can load and store raw tile buffer
-contents (to save the per-sample MSAA contents), or you can load/store
-resolved tile buffer contents (loads spam the pixel value to all 4
-samples, and stores either average the 4 color samples, or store the
-first sample for Z/S).
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
----
- drivers/gpu/drm/vc4/vc4_packet.h | 23 ++-
- drivers/gpu/drm/vc4/vc4_render_cl.c | 274 ++++++++++++++++++++++++++++++------
- drivers/gpu/drm/vc4/vc4_validate.c | 5 +-
- include/uapi/drm/vc4_drm.h | 11 +-
- 4 files changed, 258 insertions(+), 55 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_packet.h
-+++ b/drivers/gpu/drm/vc4/vc4_packet.h
-@@ -123,6 +123,11 @@ enum vc4_packet {
- #define VC4_PACKET_TILE_COORDINATES_SIZE 3
- #define VC4_PACKET_GEM_HANDLES_SIZE 9
-
-+/* Number of multisamples supported. */
-+#define VC4_MAX_SAMPLES 4
-+/* Size of a full resolution color or Z tile buffer load/store. */
-+#define VC4_TILE_BUFFER_SIZE (64 * 64 * 4)
-+
- /** @{
- * Bits used by packets like VC4_PACKET_STORE_TILE_BUFFER_GENERAL and
- * VC4_PACKET_TILE_RENDERING_MODE_CONFIG.
-@@ -137,10 +142,20 @@ enum vc4_packet {
- * low bits of VC4_PACKET_STORE_FULL_RES_TILE_BUFFER and
- * VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER.
- */
--#define VC4_LOADSTORE_FULL_RES_EOF (1 << 3)
--#define VC4_LOADSTORE_FULL_RES_DISABLE_CLEAR_ALL (1 << 2)
--#define VC4_LOADSTORE_FULL_RES_DISABLE_ZS (1 << 1)
--#define VC4_LOADSTORE_FULL_RES_DISABLE_COLOR (1 << 0)
-+#define VC4_LOADSTORE_FULL_RES_EOF BIT(3)
-+#define VC4_LOADSTORE_FULL_RES_DISABLE_CLEAR_ALL BIT(2)
-+#define VC4_LOADSTORE_FULL_RES_DISABLE_ZS BIT(1)
-+#define VC4_LOADSTORE_FULL_RES_DISABLE_COLOR BIT(0)
-+
-+/** @{
-+ *
-+ * low bits of VC4_PACKET_STORE_FULL_RES_TILE_BUFFER and
-+ * VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER.
-+ */
-+#define VC4_LOADSTORE_FULL_RES_EOF BIT(3)
-+#define VC4_LOADSTORE_FULL_RES_DISABLE_CLEAR_ALL BIT(2)
-+#define VC4_LOADSTORE_FULL_RES_DISABLE_ZS BIT(1)
-+#define VC4_LOADSTORE_FULL_RES_DISABLE_COLOR BIT(0)
-
- /** @{
- *
---- a/drivers/gpu/drm/vc4/vc4_render_cl.c
-+++ b/drivers/gpu/drm/vc4/vc4_render_cl.c
-@@ -37,9 +37,11 @@
-
- struct vc4_rcl_setup {
- struct drm_gem_cma_object *color_read;
-- struct drm_gem_cma_object *color_ms_write;
-+ struct drm_gem_cma_object *color_write;
- struct drm_gem_cma_object *zs_read;
- struct drm_gem_cma_object *zs_write;
-+ struct drm_gem_cma_object *msaa_color_write;
-+ struct drm_gem_cma_object *msaa_zs_write;
-
- struct drm_gem_cma_object *rcl;
- u32 next_offset;
-@@ -82,6 +84,22 @@ static void vc4_store_before_load(struct
- }
-
- /*
-+ * Calculates the physical address of the start of a tile in a RCL surface.
-+ *
-+ * Unlike the other load/store packets,
-+ * VC4_PACKET_LOAD/STORE_FULL_RES_TILE_BUFFER don't look at the tile
-+ * coordinates packet, and instead just store to the address given.
-+ */
-+static uint32_t vc4_full_res_offset(struct vc4_exec_info *exec,
-+ struct drm_gem_cma_object *bo,
-+ struct drm_vc4_submit_rcl_surface *surf,
-+ uint8_t x, uint8_t y)
-+{
-+ return bo->paddr + surf->offset + VC4_TILE_BUFFER_SIZE *
-+ (DIV_ROUND_UP(exec->args->width, 32) * y + x);
-+}
-+
-+/*
- * Emits a PACKET_TILE_COORDINATES if one isn't already pending.
- *
- * The tile coordinates packet triggers a pending load if there is one, are
-@@ -108,22 +126,41 @@ static void emit_tile(struct vc4_exec_in
- * may be outstanding at a time.
- */
- if (setup->color_read) {
-- rcl_u8(setup, VC4_PACKET_LOAD_TILE_BUFFER_GENERAL);
-- rcl_u16(setup, args->color_read.bits);
-- rcl_u32(setup,
-- setup->color_read->paddr + args->color_read.offset);
-+ if (args->color_read.flags &
-+ VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) {
-+ rcl_u8(setup, VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER);
-+ rcl_u32(setup,
-+ vc4_full_res_offset(exec, setup->color_read,
-+ &args->color_read, x, y) |
-+ VC4_LOADSTORE_FULL_RES_DISABLE_ZS);
-+ } else {
-+ rcl_u8(setup, VC4_PACKET_LOAD_TILE_BUFFER_GENERAL);
-+ rcl_u16(setup, args->color_read.bits);
-+ rcl_u32(setup, setup->color_read->paddr +
-+ args->color_read.offset);
-+ }
- }
-
- if (setup->zs_read) {
-- if (setup->color_read) {
-- /* Exec previous load. */
-- vc4_tile_coordinates(setup, x, y);
-- vc4_store_before_load(setup);
-+ if (args->zs_read.flags &
-+ VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) {
-+ rcl_u8(setup, VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER);
-+ rcl_u32(setup,
-+ vc4_full_res_offset(exec, setup->zs_read,
-+ &args->zs_read, x, y) |
-+ VC4_LOADSTORE_FULL_RES_DISABLE_COLOR);
-+ } else {
-+ if (setup->color_read) {
-+ /* Exec previous load. */
-+ vc4_tile_coordinates(setup, x, y);
-+ vc4_store_before_load(setup);
-+ }
-+
-+ rcl_u8(setup, VC4_PACKET_LOAD_TILE_BUFFER_GENERAL);
-+ rcl_u16(setup, args->zs_read.bits);
-+ rcl_u32(setup, setup->zs_read->paddr +
-+ args->zs_read.offset);
- }
--
-- rcl_u8(setup, VC4_PACKET_LOAD_TILE_BUFFER_GENERAL);
-- rcl_u16(setup, args->zs_read.bits);
-- rcl_u32(setup, setup->zs_read->paddr + args->zs_read.offset);
- }
-
- /* Clipping depends on tile coordinates having been
-@@ -144,20 +181,60 @@ static void emit_tile(struct vc4_exec_in
- (y * exec->bin_tiles_x + x) * 32));
- }
-
-+ if (setup->msaa_color_write) {
-+ bool last_tile_write = (!setup->msaa_zs_write &&
-+ !setup->zs_write &&
-+ !setup->color_write);
-+ uint32_t bits = VC4_LOADSTORE_FULL_RES_DISABLE_ZS;
-+
-+ if (!last_tile_write)
-+ bits |= VC4_LOADSTORE_FULL_RES_DISABLE_CLEAR_ALL;
-+ else if (last)
-+ bits |= VC4_LOADSTORE_FULL_RES_EOF;
-+ rcl_u8(setup, VC4_PACKET_STORE_FULL_RES_TILE_BUFFER);
-+ rcl_u32(setup,
-+ vc4_full_res_offset(exec, setup->msaa_color_write,
-+ &args->msaa_color_write, x, y) |
-+ bits);
-+ }
-+
-+ if (setup->msaa_zs_write) {
-+ bool last_tile_write = (!setup->zs_write &&
-+ !setup->color_write);
-+ uint32_t bits = VC4_LOADSTORE_FULL_RES_DISABLE_COLOR;
-+
-+ if (setup->msaa_color_write)
-+ vc4_tile_coordinates(setup, x, y);
-+ if (!last_tile_write)
-+ bits |= VC4_LOADSTORE_FULL_RES_DISABLE_CLEAR_ALL;
-+ else if (last)
-+ bits |= VC4_LOADSTORE_FULL_RES_EOF;
-+ rcl_u8(setup, VC4_PACKET_STORE_FULL_RES_TILE_BUFFER);
-+ rcl_u32(setup,
-+ vc4_full_res_offset(exec, setup->msaa_zs_write,
-+ &args->msaa_zs_write, x, y) |
-+ bits);
-+ }
-+
- if (setup->zs_write) {
-+ bool last_tile_write = !setup->color_write;
-+
-+ if (setup->msaa_color_write || setup->msaa_zs_write)
-+ vc4_tile_coordinates(setup, x, y);
-+
- rcl_u8(setup, VC4_PACKET_STORE_TILE_BUFFER_GENERAL);
- rcl_u16(setup, args->zs_write.bits |
-- (setup->color_ms_write ?
-- VC4_STORE_TILE_BUFFER_DISABLE_COLOR_CLEAR : 0));
-+ (last_tile_write ?
-+ 0 : VC4_STORE_TILE_BUFFER_DISABLE_COLOR_CLEAR));
- rcl_u32(setup,
- (setup->zs_write->paddr + args->zs_write.offset) |
-- ((last && !setup->color_ms_write) ?
-+ ((last && last_tile_write) ?
- VC4_LOADSTORE_TILE_BUFFER_EOF : 0));
- }
-
-- if (setup->color_ms_write) {
-- if (setup->zs_write) {
-- /* Reset after previous store */
-+ if (setup->color_write) {
-+ if (setup->msaa_color_write || setup->msaa_zs_write ||
-+ setup->zs_write) {
- vc4_tile_coordinates(setup, x, y);
- }
-
-@@ -192,14 +269,26 @@ static int vc4_create_rcl_bo(struct drm_
- }
-
- if (setup->color_read) {
-- loop_body_size += (VC4_PACKET_LOAD_TILE_BUFFER_GENERAL_SIZE);
-+ if (args->color_read.flags &
-+ VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) {
-+ loop_body_size += VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER_SIZE;
-+ } else {
-+ loop_body_size += VC4_PACKET_LOAD_TILE_BUFFER_GENERAL_SIZE;
-+ }
- }
- if (setup->zs_read) {
-- if (setup->color_read) {
-- loop_body_size += VC4_PACKET_TILE_COORDINATES_SIZE;
-- loop_body_size += VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE;
-+ if (args->zs_read.flags &
-+ VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) {
-+ loop_body_size += VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER_SIZE;
-+ } else {
-+ if (setup->color_read &&
-+ !(args->color_read.flags &
-+ VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES)) {
-+ loop_body_size += VC4_PACKET_TILE_COORDINATES_SIZE;
-+ loop_body_size += VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE;
-+ }
-+ loop_body_size += VC4_PACKET_LOAD_TILE_BUFFER_GENERAL_SIZE;
- }
-- loop_body_size += VC4_PACKET_LOAD_TILE_BUFFER_GENERAL_SIZE;
- }
-
- if (has_bin) {
-@@ -207,13 +296,23 @@ static int vc4_create_rcl_bo(struct drm_
- loop_body_size += VC4_PACKET_BRANCH_TO_SUB_LIST_SIZE;
- }
-
-+ if (setup->msaa_color_write)
-+ loop_body_size += VC4_PACKET_STORE_FULL_RES_TILE_BUFFER_SIZE;
-+ if (setup->msaa_zs_write)
-+ loop_body_size += VC4_PACKET_STORE_FULL_RES_TILE_BUFFER_SIZE;
-+
- if (setup->zs_write)
- loop_body_size += VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE;
-- if (setup->color_ms_write) {
-- if (setup->zs_write)
-- loop_body_size += VC4_PACKET_TILE_COORDINATES_SIZE;
-+ if (setup->color_write)
- loop_body_size += VC4_PACKET_STORE_MS_TILE_BUFFER_SIZE;
-- }
-+
-+ /* We need a VC4_PACKET_TILE_COORDINATES in between each store. */
-+ loop_body_size += VC4_PACKET_TILE_COORDINATES_SIZE *
-+ ((setup->msaa_color_write != NULL) +
-+ (setup->msaa_zs_write != NULL) +
-+ (setup->color_write != NULL) +
-+ (setup->zs_write != NULL) - 1);
-+
- size += xtiles * ytiles * loop_body_size;
-
- setup->rcl = &vc4_bo_create(dev, size, true)->base;
-@@ -224,13 +323,12 @@ static int vc4_create_rcl_bo(struct drm_
-
- rcl_u8(setup, VC4_PACKET_TILE_RENDERING_MODE_CONFIG);
- rcl_u32(setup,
-- (setup->color_ms_write ?
-- (setup->color_ms_write->paddr +
-- args->color_ms_write.offset) :
-+ (setup->color_write ? (setup->color_write->paddr +
-+ args->color_write.offset) :
- 0));
- rcl_u16(setup, args->width);
- rcl_u16(setup, args->height);
-- rcl_u16(setup, args->color_ms_write.bits);
-+ rcl_u16(setup, args->color_write.bits);
-
- /* The tile buffer gets cleared when the previous tile is stored. If
- * the clear values changed between frames, then the tile buffer has
-@@ -267,6 +365,56 @@ static int vc4_create_rcl_bo(struct drm_
- return 0;
- }
-
-+static int vc4_full_res_bounds_check(struct vc4_exec_info *exec,
-+ struct drm_gem_cma_object *obj,
-+ struct drm_vc4_submit_rcl_surface *surf)
-+{
-+ struct drm_vc4_submit_cl *args = exec->args;
-+ u32 render_tiles_stride = DIV_ROUND_UP(exec->args->width, 32);
-+
-+ if (surf->offset > obj->base.size) {
-+ DRM_ERROR("surface offset %d > BO size %zd\n",
-+ surf->offset, obj->base.size);
-+ return -EINVAL;
-+ }
-+
-+ if ((obj->base.size - surf->offset) / VC4_TILE_BUFFER_SIZE <
-+ render_tiles_stride * args->max_y_tile + args->max_x_tile) {
-+ DRM_ERROR("MSAA tile %d, %d out of bounds "
-+ "(bo size %zd, offset %d).\n",
-+ args->max_x_tile, args->max_y_tile,
-+ obj->base.size,
-+ surf->offset);
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+static int vc4_rcl_msaa_surface_setup(struct vc4_exec_info *exec,
-+ struct drm_gem_cma_object **obj,
-+ struct drm_vc4_submit_rcl_surface *surf)
-+{
-+ if (surf->flags != 0 || surf->bits != 0) {
-+ DRM_ERROR("MSAA surface had nonzero flags/bits\n");
-+ return -EINVAL;
-+ }
-+
-+ if (surf->hindex == ~0)
-+ return 0;
-+
-+ *obj = vc4_use_bo(exec, surf->hindex);
-+ if (!*obj)
-+ return -EINVAL;
-+
-+ if (surf->offset & 0xf) {
-+ DRM_ERROR("MSAA write must be 16b aligned.\n");
-+ return -EINVAL;
-+ }
-+
-+ return vc4_full_res_bounds_check(exec, *obj, surf);
-+}
-+
- static int vc4_rcl_surface_setup(struct vc4_exec_info *exec,
- struct drm_gem_cma_object **obj,
- struct drm_vc4_submit_rcl_surface *surf)
-@@ -278,9 +426,10 @@ static int vc4_rcl_surface_setup(struct
- uint8_t format = VC4_GET_FIELD(surf->bits,
- VC4_LOADSTORE_TILE_BUFFER_FORMAT);
- int cpp;
-+ int ret;
-
-- if (surf->pad != 0) {
-- DRM_ERROR("Padding unset\n");
-+ if (surf->flags & ~VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) {
-+ DRM_ERROR("Extra flags set\n");
- return -EINVAL;
- }
-
-@@ -290,6 +439,25 @@ static int vc4_rcl_surface_setup(struct
- if (!vc4_use_bo(exec, surf->hindex, VC4_MODE_RENDER, obj))
- return -EINVAL;
-
-+ if (surf->flags & VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) {
-+ if (surf == &exec->args->zs_write) {
-+ DRM_ERROR("general zs write may not be a full-res.\n");
-+ return -EINVAL;
-+ }
-+
-+ if (surf->bits != 0) {
-+ DRM_ERROR("load/store general bits set with "
-+ "full res load/store.\n");
-+ return -EINVAL;
-+ }
-+
-+ ret = vc4_full_res_bounds_check(exec, *obj, surf);
-+ if (!ret)
-+ return ret;
-+
-+ return 0;
-+ }
-+
- if (surf->bits & ~(VC4_LOADSTORE_TILE_BUFFER_TILING_MASK |
- VC4_LOADSTORE_TILE_BUFFER_BUFFER_MASK |
- VC4_LOADSTORE_TILE_BUFFER_FORMAT_MASK)) {
-@@ -341,9 +509,10 @@ static int vc4_rcl_surface_setup(struct
- }
-
- static int
--vc4_rcl_ms_surface_setup(struct vc4_exec_info *exec,
-- struct drm_gem_cma_object **obj,
-- struct drm_vc4_submit_rcl_surface *surf)
-+vc4_rcl_render_config_surface_setup(struct vc4_exec_info *exec,
-+ struct vc4_rcl_setup *setup,
-+ struct drm_gem_cma_object **obj,
-+ struct drm_vc4_submit_rcl_surface *surf)
- {
- uint8_t tiling = VC4_GET_FIELD(surf->bits,
- VC4_RENDER_CONFIG_MEMORY_FORMAT);
-@@ -351,13 +520,15 @@ vc4_rcl_ms_surface_setup(struct vc4_exec
- VC4_RENDER_CONFIG_FORMAT);
- int cpp;
-
-- if (surf->pad != 0) {
-- DRM_ERROR("Padding unset\n");
-+ if (surf->flags != 0) {
-+ DRM_ERROR("No flags supported on render config.\n");
- return -EINVAL;
- }
-
- if (surf->bits & ~(VC4_RENDER_CONFIG_MEMORY_FORMAT_MASK |
-- VC4_RENDER_CONFIG_FORMAT_MASK)) {
-+ VC4_RENDER_CONFIG_FORMAT_MASK |
-+ VC4_RENDER_CONFIG_MS_MODE_4X |
-+ VC4_RENDER_CONFIG_DECIMATE_MODE_4X)) {
- DRM_ERROR("Unknown bits in render config: 0x%04x\n",
- surf->bits);
- return -EINVAL;
-@@ -413,18 +584,20 @@ int vc4_get_rcl(struct drm_device *dev,
- if (has_bin &&
- (args->max_x_tile > exec->bin_tiles_x ||
- args->max_y_tile > exec->bin_tiles_y)) {
-- DRM_ERROR("Render tiles (%d,%d) outside of bin config (%d,%d)\n",
-+ DRM_ERROR("Render tiles (%d,%d) outside of bin config "
-+ "(%d,%d)\n",
- args->max_x_tile, args->max_y_tile,
- exec->bin_tiles_x, exec->bin_tiles_y);
- return -EINVAL;
- }
-
-- ret = vc4_rcl_surface_setup(exec, &setup.color_read, &args->color_read);
-+ ret = vc4_rcl_render_config_surface_setup(exec, &setup,
-+ &setup.color_write,
-+ &args->color_write);
- if (ret)
- return ret;
-
-- ret = vc4_rcl_ms_surface_setup(exec, &setup.color_ms_write,
-- &args->color_ms_write);
-+ ret = vc4_rcl_surface_setup(exec, &setup.color_read, &args->color_read);
- if (ret)
- return ret;
-
-@@ -436,10 +609,21 @@ int vc4_get_rcl(struct drm_device *dev,
- if (ret)
- return ret;
-
-+ ret = vc4_rcl_msaa_surface_setup(exec, &setup.msaa_color_write,
-+ &args->msaa_color_write);
-+ if (ret)
-+ return ret;
-+
-+ ret = vc4_rcl_msaa_surface_setup(exec, &setup.msaa_zs_write,
-+ &args->msaa_zs_write);
-+ if (ret)
-+ return ret;
-+
- /* We shouldn't even have the job submitted to us if there's no
- * surface to write out.
- */
-- if (!setup.color_ms_write && !setup.zs_write) {
-+ if (!setup.color_write && !setup.zs_write &&
-+ !setup.msaa_color_write && !setup.msaa_zs_write) {
- DRM_ERROR("RCL requires color or Z/S write\n");
- return -EINVAL;
- }
---- a/drivers/gpu/drm/vc4/vc4_validate.c
-+++ b/drivers/gpu/drm/vc4/vc4_validate.c
-@@ -400,9 +400,8 @@ validate_tile_binning_config(VALIDATE_AR
- }
-
- if (flags & (VC4_BIN_CONFIG_DB_NON_MS |
-- VC4_BIN_CONFIG_TILE_BUFFER_64BIT |
-- VC4_BIN_CONFIG_MS_MODE_4X)) {
-- DRM_ERROR("unsupported bining config flags 0x%02x\n", flags);
-+ VC4_BIN_CONFIG_TILE_BUFFER_64BIT)) {
-+ DRM_ERROR("unsupported binning config flags 0x%02x\n", flags);
- return -EINVAL;
- }
-
---- a/include/uapi/drm/vc4_drm.h
-+++ b/include/uapi/drm/vc4_drm.h
-@@ -46,10 +46,13 @@ struct drm_vc4_submit_rcl_surface {
- uint32_t hindex; /* Handle index, or ~0 if not present. */
- uint32_t offset; /* Offset to start of buffer. */
- /*
-- * Bits for either render config (color_ms_write) or load/store packet.
-+ * Bits for either render config (color_write) or load/store packet.
-+ * Bits should all be 0 for MSAA load/stores.
- */
- uint16_t bits;
-- uint16_t pad;
-+
-+#define VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES (1 << 0)
-+ uint16_t flags;
- };
-
- /**
-@@ -128,9 +131,11 @@ struct drm_vc4_submit_cl {
- uint8_t max_x_tile;
- uint8_t max_y_tile;
- struct drm_vc4_submit_rcl_surface color_read;
-- struct drm_vc4_submit_rcl_surface color_ms_write;
-+ struct drm_vc4_submit_rcl_surface color_write;
- struct drm_vc4_submit_rcl_surface zs_read;
- struct drm_vc4_submit_rcl_surface zs_write;
-+ struct drm_vc4_submit_rcl_surface msaa_color_write;
-+ struct drm_vc4_submit_rcl_surface msaa_zs_write;
- uint32_t clear_color[2];
- uint32_t clear_z;
- uint8_t clear_s;
diff --git a/target/linux/brcm2708/patches-4.4/0118-drm-vc4-A-few-more-non-functional-changes-to-sync-to.patch b/target/linux/brcm2708/patches-4.4/0118-drm-vc4-A-few-more-non-functional-changes-to-sync-to.patch
deleted file mode 100644
index 9e6989ca12..0000000000
--- a/target/linux/brcm2708/patches-4.4/0118-drm-vc4-A-few-more-non-functional-changes-to-sync-to.patch
+++ /dev/null
@@ -1,345 +0,0 @@
-From 50a1843ffd2e6f408dcb6a64ca0a2ef3b062fd5a Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Tue, 8 Dec 2015 14:00:43 -0800
-Subject: [PATCH 118/170] drm/vc4: A few more non-functional changes to sync to
- upstream.
-
-At this point all that's left is the force-enable of HDMI connector,
-and using direct firmware calls to turn on V3D instead of the generic
-power domain support.
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
----
- drivers/gpu/drm/vc4/vc4_v3d.c | 2 +-
- include/uapi/drm/vc4_drm.h | 182 +++++++++++++++++++++---------------------
- 2 files changed, 92 insertions(+), 92 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_v3d.c
-+++ b/drivers/gpu/drm/vc4/vc4_v3d.c
-@@ -109,7 +109,7 @@ static const struct {
-
- int vc4_v3d_debugfs_regs(struct seq_file *m, void *unused)
- {
-- struct drm_info_node *node = (struct drm_info_node *) m->private;
-+ struct drm_info_node *node = (struct drm_info_node *)m->private;
- struct drm_device *dev = node->minor->dev;
- struct vc4_dev *vc4 = to_vc4_dev(dev);
- int i;
---- a/include/uapi/drm/vc4_drm.h
-+++ b/include/uapi/drm/vc4_drm.h
-@@ -24,7 +24,7 @@
- #ifndef _UAPI_VC4_DRM_H_
- #define _UAPI_VC4_DRM_H_
-
--#include <drm/drm.h>
-+#include "drm.h"
-
- #define DRM_VC4_SUBMIT_CL 0x00
- #define DRM_VC4_WAIT_SEQNO 0x01
-@@ -34,25 +34,25 @@
- #define DRM_VC4_CREATE_SHADER_BO 0x05
- #define DRM_VC4_GET_HANG_STATE 0x06
-
--#define DRM_IOCTL_VC4_SUBMIT_CL DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_SUBMIT_CL, struct drm_vc4_submit_cl)
--#define DRM_IOCTL_VC4_WAIT_SEQNO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_WAIT_SEQNO, struct drm_vc4_wait_seqno)
--#define DRM_IOCTL_VC4_WAIT_BO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_WAIT_BO, struct drm_vc4_wait_bo)
--#define DRM_IOCTL_VC4_CREATE_BO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_CREATE_BO, struct drm_vc4_create_bo)
--#define DRM_IOCTL_VC4_MMAP_BO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_MMAP_BO, struct drm_vc4_mmap_bo)
--#define DRM_IOCTL_VC4_CREATE_SHADER_BO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_CREATE_SHADER_BO, struct drm_vc4_create_shader_bo)
--#define DRM_IOCTL_VC4_GET_HANG_STATE DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_GET_HANG_STATE, struct drm_vc4_get_hang_state)
-+#define DRM_IOCTL_VC4_SUBMIT_CL DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_SUBMIT_CL, struct drm_vc4_submit_cl)
-+#define DRM_IOCTL_VC4_WAIT_SEQNO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_WAIT_SEQNO, struct drm_vc4_wait_seqno)
-+#define DRM_IOCTL_VC4_WAIT_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_WAIT_BO, struct drm_vc4_wait_bo)
-+#define DRM_IOCTL_VC4_CREATE_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_CREATE_BO, struct drm_vc4_create_bo)
-+#define DRM_IOCTL_VC4_MMAP_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_MMAP_BO, struct drm_vc4_mmap_bo)
-+#define DRM_IOCTL_VC4_CREATE_SHADER_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_CREATE_SHADER_BO, struct drm_vc4_create_shader_bo)
-+#define DRM_IOCTL_VC4_GET_HANG_STATE DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_GET_HANG_STATE, struct drm_vc4_get_hang_state)
-
- struct drm_vc4_submit_rcl_surface {
-- uint32_t hindex; /* Handle index, or ~0 if not present. */
-- uint32_t offset; /* Offset to start of buffer. */
-+ __u32 hindex; /* Handle index, or ~0 if not present. */
-+ __u32 offset; /* Offset to start of buffer. */
- /*
-- * Bits for either render config (color_write) or load/store packet.
-- * Bits should all be 0 for MSAA load/stores.
-+ * Bits for either render config (color_write) or load/store packet.
-+ * Bits should all be 0 for MSAA load/stores.
- */
-- uint16_t bits;
-+ __u16 bits;
-
- #define VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES (1 << 0)
-- uint16_t flags;
-+ __u16 flags;
- };
-
- /**
-@@ -76,7 +76,7 @@ struct drm_vc4_submit_cl {
- * then writes out the state updates and draw calls necessary per tile
- * to the tile allocation BO.
- */
-- uint64_t bin_cl;
-+ __u64 bin_cl;
-
- /* Pointer to the shader records.
- *
-@@ -85,16 +85,16 @@ struct drm_vc4_submit_cl {
- * reference to the shader record has enough information to determine
- * how many pointers are necessary (fixed number for shaders/uniforms,
- * and an attribute count), so those BO indices into bo_handles are
-- * just stored as uint32_ts before each shader record passed in.
-+ * just stored as __u32s before each shader record passed in.
- */
-- uint64_t shader_rec;
-+ __u64 shader_rec;
-
- /* Pointer to uniform data and texture handles for the textures
- * referenced by the shader.
- *
- * For each shader state record, there is a set of uniform data in the
- * order referenced by the record (FS, VS, then CS). Each set of
-- * uniform data has a uint32_t index into bo_handles per texture
-+ * uniform data has a __u32 index into bo_handles per texture
- * sample operation, in the order the QPU_W_TMUn_S writes appear in
- * the program. Following the texture BO handle indices is the actual
- * uniform data.
-@@ -103,52 +103,52 @@ struct drm_vc4_submit_cl {
- * because the kernel has to determine the sizes anyway during shader
- * code validation.
- */
-- uint64_t uniforms;
-- uint64_t bo_handles;
-+ __u64 uniforms;
-+ __u64 bo_handles;
-
- /* Size in bytes of the binner command list. */
-- uint32_t bin_cl_size;
-+ __u32 bin_cl_size;
- /* Size in bytes of the set of shader records. */
-- uint32_t shader_rec_size;
-+ __u32 shader_rec_size;
- /* Number of shader records.
- *
- * This could just be computed from the contents of shader_records and
- * the address bits of references to them from the bin CL, but it
- * keeps the kernel from having to resize some allocations it makes.
- */
-- uint32_t shader_rec_count;
-+ __u32 shader_rec_count;
- /* Size in bytes of the uniform state. */
-- uint32_t uniforms_size;
-+ __u32 uniforms_size;
-
- /* Number of BO handles passed in (size is that times 4). */
-- uint32_t bo_handle_count;
-+ __u32 bo_handle_count;
-
- /* RCL setup: */
-- uint16_t width;
-- uint16_t height;
-- uint8_t min_x_tile;
-- uint8_t min_y_tile;
-- uint8_t max_x_tile;
-- uint8_t max_y_tile;
-+ __u16 width;
-+ __u16 height;
-+ __u8 min_x_tile;
-+ __u8 min_y_tile;
-+ __u8 max_x_tile;
-+ __u8 max_y_tile;
- struct drm_vc4_submit_rcl_surface color_read;
- struct drm_vc4_submit_rcl_surface color_write;
- struct drm_vc4_submit_rcl_surface zs_read;
- struct drm_vc4_submit_rcl_surface zs_write;
- struct drm_vc4_submit_rcl_surface msaa_color_write;
- struct drm_vc4_submit_rcl_surface msaa_zs_write;
-- uint32_t clear_color[2];
-- uint32_t clear_z;
-- uint8_t clear_s;
-+ __u32 clear_color[2];
-+ __u32 clear_z;
-+ __u8 clear_s;
-
-- uint32_t pad:24;
-+ __u32 pad:24;
-
- #define VC4_SUBMIT_CL_USE_CLEAR_COLOR (1 << 0)
-- uint32_t flags;
-+ __u32 flags;
-
- /* Returned value of the seqno of this render job (for the
- * wait ioctl).
- */
-- uint64_t seqno;
-+ __u64 seqno;
- };
-
- /**
-@@ -159,8 +159,8 @@ struct drm_vc4_submit_cl {
- * block, just return the status."
- */
- struct drm_vc4_wait_seqno {
-- uint64_t seqno;
-- uint64_t timeout_ns;
-+ __u64 seqno;
-+ __u64 timeout_ns;
- };
-
- /**
-@@ -172,9 +172,9 @@ struct drm_vc4_wait_seqno {
- * completed.
- */
- struct drm_vc4_wait_bo {
-- uint32_t handle;
-- uint32_t pad;
-- uint64_t timeout_ns;
-+ __u32 handle;
-+ __u32 pad;
-+ __u64 timeout_ns;
- };
-
- /**
-@@ -184,11 +184,30 @@ struct drm_vc4_wait_bo {
- * used in a future extension.
- */
- struct drm_vc4_create_bo {
-- uint32_t size;
-- uint32_t flags;
-+ __u32 size;
-+ __u32 flags;
- /** Returned GEM handle for the BO. */
-- uint32_t handle;
-- uint32_t pad;
-+ __u32 handle;
-+ __u32 pad;
-+};
-+
-+/**
-+ * struct drm_vc4_mmap_bo - ioctl argument for mapping VC4 BOs.
-+ *
-+ * This doesn't actually perform an mmap. Instead, it returns the
-+ * offset you need to use in an mmap on the DRM device node. This
-+ * means that tools like valgrind end up knowing about the mapped
-+ * memory.
-+ *
-+ * There are currently no values for the flags argument, but it may be
-+ * used in a future extension.
-+ */
-+struct drm_vc4_mmap_bo {
-+ /** Handle for the object being mapped. */
-+ __u32 handle;
-+ __u32 flags;
-+ /** offset into the drm node to use for subsequent mmap call. */
-+ __u64 offset;
- };
-
- /**
-@@ -201,43 +220,24 @@ struct drm_vc4_create_bo {
- */
- struct drm_vc4_create_shader_bo {
- /* Size of the data argument. */
-- uint32_t size;
-+ __u32 size;
- /* Flags, currently must be 0. */
-- uint32_t flags;
-+ __u32 flags;
-
- /* Pointer to the data. */
-- uint64_t data;
-+ __u64 data;
-
- /** Returned GEM handle for the BO. */
-- uint32_t handle;
-+ __u32 handle;
- /* Pad, must be 0. */
-- uint32_t pad;
--};
--
--/**
-- * struct drm_vc4_mmap_bo - ioctl argument for mapping VC4 BOs.
-- *
-- * This doesn't actually perform an mmap. Instead, it returns the
-- * offset you need to use in an mmap on the DRM device node. This
-- * means that tools like valgrind end up knowing about the mapped
-- * memory.
-- *
-- * There are currently no values for the flags argument, but it may be
-- * used in a future extension.
-- */
--struct drm_vc4_mmap_bo {
-- /** Handle for the object being mapped. */
-- uint32_t handle;
-- uint32_t flags;
-- /** offset into the drm node to use for subsequent mmap call. */
-- uint64_t offset;
-+ __u32 pad;
- };
-
- struct drm_vc4_get_hang_state_bo {
-- uint32_t handle;
-- uint32_t paddr;
-- uint32_t size;
-- uint32_t pad;
-+ __u32 handle;
-+ __u32 paddr;
-+ __u32 size;
-+ __u32 pad;
- };
-
- /**
-@@ -246,34 +246,34 @@ struct drm_vc4_get_hang_state_bo {
- */
- struct drm_vc4_get_hang_state {
- /** Pointer to array of struct drm_vc4_get_hang_state_bo. */
-- uint64_t bo;
-+ __u64 bo;
- /**
- * On input, the size of the bo array. Output is the number
- * of bos to be returned.
- */
-- uint32_t bo_count;
-+ __u32 bo_count;
-
-- uint32_t start_bin, start_render;
-+ __u32 start_bin, start_render;
-
-- uint32_t ct0ca, ct0ea;
-- uint32_t ct1ca, ct1ea;
-- uint32_t ct0cs, ct1cs;
-- uint32_t ct0ra0, ct1ra0;
--
-- uint32_t bpca, bpcs;
-- uint32_t bpoa, bpos;
--
-- uint32_t vpmbase;
--
-- uint32_t dbge;
-- uint32_t fdbgo;
-- uint32_t fdbgb;
-- uint32_t fdbgr;
-- uint32_t fdbgs;
-- uint32_t errstat;
-+ __u32 ct0ca, ct0ea;
-+ __u32 ct1ca, ct1ea;
-+ __u32 ct0cs, ct1cs;
-+ __u32 ct0ra0, ct1ra0;
-+
-+ __u32 bpca, bpcs;
-+ __u32 bpoa, bpos;
-+
-+ __u32 vpmbase;
-+
-+ __u32 dbge;
-+ __u32 fdbgo;
-+ __u32 fdbgb;
-+ __u32 fdbgr;
-+ __u32 fdbgs;
-+ __u32 errstat;
-
- /* Pad that we may save more registers into in the future. */
-- uint32_t pad[16];
-+ __u32 pad[16];
- };
-
- #endif /* _UAPI_VC4_DRM_H_ */
diff --git a/target/linux/brcm2708/patches-4.4/0118-drm-vc4-Use-hpd-gpios-for-HDMI-GPIO-like-what-landed.patch b/target/linux/brcm2708/patches-4.4/0118-drm-vc4-Use-hpd-gpios-for-HDMI-GPIO-like-what-landed.patch
new file mode 100644
index 0000000000..aa8e53860a
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0118-drm-vc4-Use-hpd-gpios-for-HDMI-GPIO-like-what-landed.patch
@@ -0,0 +1,22 @@
+From dc02b5bdc0f962c1c9da85d98c11612e858280b3 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Tue, 15 Dec 2015 23:46:32 +0000
+Subject: [PATCH 118/381] drm/vc4: Use "hpd-gpios" for HDMI GPIO, like what
+ landed upstream.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts
++++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts
+@@ -68,7 +68,7 @@
+ <0x7e808000 0x100>;
+ interrupts = <2 8>, <2 9>;
+ ddc = <&i2c2>;
+- hpd-gpio = <&gpio 46 GPIO_ACTIVE_HIGH>;
++ hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>;
+ clocks = <&cprman BCM2835_PLLH_PIX>,
+ <&cprman BCM2835_CLOCK_HSM>;
+ clock-names = "pixel", "hdmi";
diff --git a/target/linux/brcm2708/patches-4.4/0119-drm-vc4-Synchronize-validation-code-for-v2-submissio.patch b/target/linux/brcm2708/patches-4.4/0119-drm-vc4-Synchronize-validation-code-for-v2-submissio.patch
new file mode 100644
index 0000000000..9f45f0f106
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0119-drm-vc4-Synchronize-validation-code-for-v2-submissio.patch
@@ -0,0 +1,612 @@
+From 2181b6ab6f7cddcd5ca908007a14fde90cc8d2b1 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 7 Dec 2015 12:35:01 -0800
+Subject: [PATCH 119/381] drm/vc4: Synchronize validation code for v2
+ submission upstream.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_drv.h | 24 +--
+ drivers/gpu/drm/vc4/vc4_gem.c | 14 +-
+ drivers/gpu/drm/vc4/vc4_render_cl.c | 6 +-
+ drivers/gpu/drm/vc4/vc4_validate.c | 287 +++++++++++++++---------------------
+ 4 files changed, 135 insertions(+), 196 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_drv.h
++++ b/drivers/gpu/drm/vc4/vc4_drv.h
+@@ -189,17 +189,6 @@ to_vc4_encoder(struct drm_encoder *encod
+ #define HVS_READ(offset) readl(vc4->hvs->regs + offset)
+ #define HVS_WRITE(offset, val) writel(val, vc4->hvs->regs + offset)
+
+-enum vc4_bo_mode {
+- VC4_MODE_UNDECIDED,
+- VC4_MODE_RENDER,
+- VC4_MODE_SHADER,
+-};
+-
+-struct vc4_bo_exec_state {
+- struct drm_gem_cma_object *bo;
+- enum vc4_bo_mode mode;
+-};
+-
+ struct vc4_exec_info {
+ /* Sequence number for this bin/render job. */
+ uint64_t seqno;
+@@ -210,7 +199,7 @@ struct vc4_exec_info {
+ /* This is the array of BOs that were looked up at the start of exec.
+ * Command validation will use indices into this array.
+ */
+- struct vc4_bo_exec_state *bo;
++ struct drm_gem_cma_object **bo;
+ uint32_t bo_count;
+
+ /* Pointers for our position in vc4->job_list */
+@@ -238,7 +227,6 @@ struct vc4_exec_info {
+ * command lists.
+ */
+ struct vc4_shader_state {
+- uint8_t packet;
+ uint32_t addr;
+ /* Maximum vertex index referenced by any primitive using this
+ * shader state.
+@@ -254,6 +242,7 @@ struct vc4_exec_info {
+ bool found_tile_binning_mode_config_packet;
+ bool found_start_tile_binning_packet;
+ bool found_increment_semaphore_packet;
++ bool found_flush;
+ uint8_t bin_tiles_x, bin_tiles_y;
+ struct drm_gem_cma_object *tile_bo;
+ uint32_t tile_alloc_offset;
+@@ -265,6 +254,9 @@ struct vc4_exec_info {
+ uint32_t ct0ca, ct0ea;
+ uint32_t ct1ca, ct1ea;
+
++ /* Pointer to the unvalidated bin CL (if present). */
++ void *bin_u;
++
+ /* Pointers to the shader recs. These paddr gets incremented as CL
+ * packets are relocated in validate_gl_shader_state, and the vaddrs
+ * (u and v) get incremented and size decremented as the shader recs
+@@ -455,10 +447,8 @@ vc4_validate_bin_cl(struct drm_device *d
+ int
+ vc4_validate_shader_recs(struct drm_device *dev, struct vc4_exec_info *exec);
+
+-bool vc4_use_bo(struct vc4_exec_info *exec,
+- uint32_t hindex,
+- enum vc4_bo_mode mode,
+- struct drm_gem_cma_object **obj);
++struct drm_gem_cma_object *vc4_use_bo(struct vc4_exec_info *exec,
++ uint32_t hindex);
+
+ int vc4_get_rcl(struct drm_device *dev, struct vc4_exec_info *exec);
+
+--- a/drivers/gpu/drm/vc4/vc4_gem.c
++++ b/drivers/gpu/drm/vc4/vc4_gem.c
+@@ -169,8 +169,8 @@ vc4_save_hang_state(struct drm_device *d
+ }
+
+ for (i = 0; i < exec->bo_count; i++) {
+- drm_gem_object_reference(&exec->bo[i].bo->base);
+- kernel_state->bo[i] = &exec->bo[i].bo->base;
++ drm_gem_object_reference(&exec->bo[i]->base);
++ kernel_state->bo[i] = &exec->bo[i]->base;
+ }
+
+ list_for_each_entry(bo, &exec->unref_list, unref_head) {
+@@ -397,7 +397,7 @@ vc4_update_bo_seqnos(struct vc4_exec_inf
+ unsigned i;
+
+ for (i = 0; i < exec->bo_count; i++) {
+- bo = to_vc4_bo(&exec->bo[i].bo->base);
++ bo = to_vc4_bo(&exec->bo[i]->base);
+ bo->seqno = seqno;
+ }
+
+@@ -467,7 +467,7 @@ vc4_cl_lookup_bos(struct drm_device *dev
+ return -EINVAL;
+ }
+
+- exec->bo = kcalloc(exec->bo_count, sizeof(struct vc4_bo_exec_state),
++ exec->bo = kcalloc(exec->bo_count, sizeof(struct drm_gem_cma_object *),
+ GFP_KERNEL);
+ if (!exec->bo) {
+ DRM_ERROR("Failed to allocate validated BO pointers\n");
+@@ -500,7 +500,7 @@ vc4_cl_lookup_bos(struct drm_device *dev
+ goto fail;
+ }
+ drm_gem_object_reference(bo);
+- exec->bo[i].bo = (struct drm_gem_cma_object *)bo;
++ exec->bo[i] = (struct drm_gem_cma_object *)bo;
+ }
+ spin_unlock(&file_priv->table_lock);
+
+@@ -591,6 +591,8 @@ vc4_get_bcl(struct drm_device *dev, stru
+
+ exec->ct0ca = exec->exec_bo->paddr + bin_offset;
+
++ exec->bin_u = bin;
++
+ exec->shader_rec_v = exec->exec_bo->vaddr + shader_rec_offset;
+ exec->shader_rec_p = exec->exec_bo->paddr + shader_rec_offset;
+ exec->shader_rec_size = args->shader_rec_size;
+@@ -622,7 +624,7 @@ vc4_complete_exec(struct drm_device *dev
+ mutex_lock(&dev->struct_mutex);
+ if (exec->bo) {
+ for (i = 0; i < exec->bo_count; i++)
+- drm_gem_object_unreference(&exec->bo[i].bo->base);
++ drm_gem_object_unreference(&exec->bo[i]->base);
+ kfree(exec->bo);
+ }
+
+--- a/drivers/gpu/drm/vc4/vc4_render_cl.c
++++ b/drivers/gpu/drm/vc4/vc4_render_cl.c
+@@ -436,7 +436,8 @@ static int vc4_rcl_surface_setup(struct
+ if (surf->hindex == ~0)
+ return 0;
+
+- if (!vc4_use_bo(exec, surf->hindex, VC4_MODE_RENDER, obj))
++ *obj = vc4_use_bo(exec, surf->hindex);
++ if (!*obj)
+ return -EINVAL;
+
+ if (surf->flags & VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) {
+@@ -537,7 +538,8 @@ vc4_rcl_render_config_surface_setup(stru
+ if (surf->hindex == ~0)
+ return 0;
+
+- if (!vc4_use_bo(exec, surf->hindex, VC4_MODE_RENDER, obj))
++ *obj = vc4_use_bo(exec, surf->hindex);
++ if (!*obj)
+ return -EINVAL;
+
+ if (tiling > VC4_TILING_FORMAT_LT) {
+--- a/drivers/gpu/drm/vc4/vc4_validate.c
++++ b/drivers/gpu/drm/vc4/vc4_validate.c
+@@ -94,42 +94,42 @@ size_is_lt(uint32_t width, uint32_t heig
+ height <= 4 * utile_height(cpp));
+ }
+
+-bool
+-vc4_use_bo(struct vc4_exec_info *exec,
+- uint32_t hindex,
+- enum vc4_bo_mode mode,
+- struct drm_gem_cma_object **obj)
++struct drm_gem_cma_object *
++vc4_use_bo(struct vc4_exec_info *exec, uint32_t hindex)
+ {
+- *obj = NULL;
++ struct drm_gem_cma_object *obj;
++ struct vc4_bo *bo;
+
+ if (hindex >= exec->bo_count) {
+ DRM_ERROR("BO index %d greater than BO count %d\n",
+ hindex, exec->bo_count);
+- return false;
++ return NULL;
+ }
++ obj = exec->bo[hindex];
++ bo = to_vc4_bo(&obj->base);
+
+- if (exec->bo[hindex].mode != mode) {
+- if (exec->bo[hindex].mode == VC4_MODE_UNDECIDED) {
+- exec->bo[hindex].mode = mode;
+- } else {
+- DRM_ERROR("BO index %d reused with mode %d vs %d\n",
+- hindex, exec->bo[hindex].mode, mode);
+- return false;
+- }
++ if (bo->validated_shader) {
++ DRM_ERROR("Trying to use shader BO as something other than "
++ "a shader\n");
++ return NULL;
+ }
+
+- *obj = exec->bo[hindex].bo;
+- return true;
++ return obj;
++}
++
++static struct drm_gem_cma_object *
++vc4_use_handle(struct vc4_exec_info *exec, uint32_t gem_handles_packet_index)
++{
++ return vc4_use_bo(exec, exec->bo_index[gem_handles_packet_index]);
+ }
+
+ static bool
+-vc4_use_handle(struct vc4_exec_info *exec,
+- uint32_t gem_handles_packet_index,
+- enum vc4_bo_mode mode,
+- struct drm_gem_cma_object **obj)
++validate_bin_pos(struct vc4_exec_info *exec, void *untrusted, uint32_t pos)
+ {
+- return vc4_use_bo(exec, exec->bo_index[gem_handles_packet_index],
+- mode, obj);
++ /* Note that the untrusted pointer passed to these functions is
++ * incremented past the packet byte.
++ */
++ return (untrusted - 1 == exec->bin_u + pos);
+ }
+
+ static uint32_t
+@@ -202,13 +202,13 @@ vc4_check_tex_size(struct vc4_exec_info
+ }
+
+ static int
+-validate_flush_all(VALIDATE_ARGS)
++validate_flush(VALIDATE_ARGS)
+ {
+- if (exec->found_increment_semaphore_packet) {
+- DRM_ERROR("VC4_PACKET_FLUSH_ALL after "
+- "VC4_PACKET_INCREMENT_SEMAPHORE\n");
++ if (!validate_bin_pos(exec, untrusted, exec->args->bin_cl_size - 1)) {
++ DRM_ERROR("Bin CL must end with VC4_PACKET_FLUSH\n");
+ return -EINVAL;
+ }
++ exec->found_flush = true;
+
+ return 0;
+ }
+@@ -233,17 +233,13 @@ validate_start_tile_binning(VALIDATE_ARG
+ static int
+ validate_increment_semaphore(VALIDATE_ARGS)
+ {
+- if (exec->found_increment_semaphore_packet) {
+- DRM_ERROR("Duplicate VC4_PACKET_INCREMENT_SEMAPHORE\n");
++ if (!validate_bin_pos(exec, untrusted, exec->args->bin_cl_size - 2)) {
++ DRM_ERROR("Bin CL must end with "
++ "VC4_PACKET_INCREMENT_SEMAPHORE\n");
+ return -EINVAL;
+ }
+ exec->found_increment_semaphore_packet = true;
+
+- /* Once we've found the semaphore increment, there should be one FLUSH
+- * then the end of the command list. The FLUSH actually triggers the
+- * increment, so we only need to make sure there
+- */
+-
+ return 0;
+ }
+
+@@ -257,11 +253,6 @@ validate_indexed_prim_list(VALIDATE_ARGS
+ uint32_t index_size = (*(uint8_t *)(untrusted + 0) >> 4) ? 2 : 1;
+ struct vc4_shader_state *shader_state;
+
+- if (exec->found_increment_semaphore_packet) {
+- DRM_ERROR("Drawing after VC4_PACKET_INCREMENT_SEMAPHORE\n");
+- return -EINVAL;
+- }
+-
+ /* Check overflow condition */
+ if (exec->shader_state_count == 0) {
+ DRM_ERROR("shader state must precede primitives\n");
+@@ -272,7 +263,8 @@ validate_indexed_prim_list(VALIDATE_ARGS
+ if (max_index > shader_state->max_index)
+ shader_state->max_index = max_index;
+
+- if (!vc4_use_handle(exec, 0, VC4_MODE_RENDER, &ib))
++ ib = vc4_use_handle(exec, 0);
++ if (!ib)
+ return -EINVAL;
+
+ if (offset > ib->base.size ||
+@@ -295,11 +287,6 @@ validate_gl_array_primitive(VALIDATE_ARG
+ uint32_t max_index;
+ struct vc4_shader_state *shader_state;
+
+- if (exec->found_increment_semaphore_packet) {
+- DRM_ERROR("Drawing after VC4_PACKET_INCREMENT_SEMAPHORE\n");
+- return -EINVAL;
+- }
+-
+ /* Check overflow condition */
+ if (exec->shader_state_count == 0) {
+ DRM_ERROR("shader state must precede primitives\n");
+@@ -329,7 +316,6 @@ validate_gl_shader_state(VALIDATE_ARGS)
+ return -EINVAL;
+ }
+
+- exec->shader_state[i].packet = VC4_PACKET_GL_SHADER_STATE;
+ exec->shader_state[i].addr = *(uint32_t *)untrusted;
+ exec->shader_state[i].max_index = 0;
+
+@@ -348,31 +334,6 @@ validate_gl_shader_state(VALIDATE_ARGS)
+ }
+
+ static int
+-validate_nv_shader_state(VALIDATE_ARGS)
+-{
+- uint32_t i = exec->shader_state_count++;
+-
+- if (i >= exec->shader_state_size) {
+- DRM_ERROR("More requests for shader states than declared\n");
+- return -EINVAL;
+- }
+-
+- exec->shader_state[i].packet = VC4_PACKET_NV_SHADER_STATE;
+- exec->shader_state[i].addr = *(uint32_t *)untrusted;
+-
+- if (exec->shader_state[i].addr & 15) {
+- DRM_ERROR("NV shader state address 0x%08x misaligned\n",
+- exec->shader_state[i].addr);
+- return -EINVAL;
+- }
+-
+- *(uint32_t *)validated = (exec->shader_state[i].addr +
+- exec->shader_rec_p);
+-
+- return 0;
+-}
+-
+-static int
+ validate_tile_binning_config(VALIDATE_ARGS)
+ {
+ struct drm_device *dev = exec->exec_bo->base.dev;
+@@ -473,8 +434,8 @@ static const struct cmd_info {
+ } cmd_info[] = {
+ VC4_DEFINE_PACKET(VC4_PACKET_HALT, NULL),
+ VC4_DEFINE_PACKET(VC4_PACKET_NOP, NULL),
+- VC4_DEFINE_PACKET(VC4_PACKET_FLUSH, NULL),
+- VC4_DEFINE_PACKET(VC4_PACKET_FLUSH_ALL, validate_flush_all),
++ VC4_DEFINE_PACKET(VC4_PACKET_FLUSH, validate_flush),
++ VC4_DEFINE_PACKET(VC4_PACKET_FLUSH_ALL, NULL),
+ VC4_DEFINE_PACKET(VC4_PACKET_START_TILE_BINNING,
+ validate_start_tile_binning),
+ VC4_DEFINE_PACKET(VC4_PACKET_INCREMENT_SEMAPHORE,
+@@ -488,7 +449,6 @@ static const struct cmd_info {
+ VC4_DEFINE_PACKET(VC4_PACKET_PRIMITIVE_LIST_FORMAT, NULL),
+
+ VC4_DEFINE_PACKET(VC4_PACKET_GL_SHADER_STATE, validate_gl_shader_state),
+- VC4_DEFINE_PACKET(VC4_PACKET_NV_SHADER_STATE, validate_nv_shader_state),
+
+ VC4_DEFINE_PACKET(VC4_PACKET_CONFIGURATION_BITS, NULL),
+ VC4_DEFINE_PACKET(VC4_PACKET_FLAT_SHADE_FLAGS, NULL),
+@@ -575,8 +535,16 @@ vc4_validate_bin_cl(struct drm_device *d
+ return -EINVAL;
+ }
+
+- if (!exec->found_increment_semaphore_packet) {
+- DRM_ERROR("Bin CL missing VC4_PACKET_INCREMENT_SEMAPHORE\n");
++ /* The bin CL must be ended with INCREMENT_SEMAPHORE and FLUSH. The
++ * semaphore is used to trigger the render CL to start up, and the
++ * FLUSH is what caps the bin lists with
++ * VC4_PACKET_RETURN_FROM_SUB_LIST (so they jump back to the main
++ * render CL when they get called to) and actually triggers the queued
++ * semaphore increment.
++ */
++ if (!exec->found_increment_semaphore_packet || !exec->found_flush) {
++ DRM_ERROR("Bin CL missing VC4_PACKET_INCREMENT_SEMAPHORE + "
++ "VC4_PACKET_FLUSH\n");
+ return -EINVAL;
+ }
+
+@@ -607,7 +575,8 @@ reloc_tex(struct vc4_exec_info *exec,
+ uint32_t cube_map_stride = 0;
+ enum vc4_texture_data_type type;
+
+- if (!vc4_use_bo(exec, texture_handle_index, VC4_MODE_RENDER, &tex))
++ tex = vc4_use_bo(exec, texture_handle_index);
++ if (!tex)
+ return false;
+
+ if (sample->is_direct) {
+@@ -755,51 +724,28 @@ reloc_tex(struct vc4_exec_info *exec,
+ }
+
+ static int
+-validate_shader_rec(struct drm_device *dev,
+- struct vc4_exec_info *exec,
+- struct vc4_shader_state *state)
++validate_gl_shader_rec(struct drm_device *dev,
++ struct vc4_exec_info *exec,
++ struct vc4_shader_state *state)
+ {
+ uint32_t *src_handles;
+ void *pkt_u, *pkt_v;
+- enum shader_rec_reloc_type {
+- RELOC_CODE,
+- RELOC_VBO,
+- };
+- struct shader_rec_reloc {
+- enum shader_rec_reloc_type type;
+- uint32_t offset;
+- };
+- static const struct shader_rec_reloc gl_relocs[] = {
+- { RELOC_CODE, 4 }, /* fs */
+- { RELOC_CODE, 16 }, /* vs */
+- { RELOC_CODE, 28 }, /* cs */
+- };
+- static const struct shader_rec_reloc nv_relocs[] = {
+- { RELOC_CODE, 4 }, /* fs */
+- { RELOC_VBO, 12 }
++ static const uint32_t shader_reloc_offsets[] = {
++ 4, /* fs */
++ 16, /* vs */
++ 28, /* cs */
+ };
+- const struct shader_rec_reloc *relocs;
+- struct drm_gem_cma_object *bo[ARRAY_SIZE(gl_relocs) + 8];
+- uint32_t nr_attributes = 0, nr_fixed_relocs, nr_relocs, packet_size;
++ uint32_t shader_reloc_count = ARRAY_SIZE(shader_reloc_offsets);
++ struct drm_gem_cma_object *bo[shader_reloc_count + 8];
++ uint32_t nr_attributes, nr_relocs, packet_size;
+ int i;
+- struct vc4_validated_shader_info *shader;
+
+- if (state->packet == VC4_PACKET_NV_SHADER_STATE) {
+- relocs = nv_relocs;
+- nr_fixed_relocs = ARRAY_SIZE(nv_relocs);
+-
+- packet_size = 16;
+- } else {
+- relocs = gl_relocs;
+- nr_fixed_relocs = ARRAY_SIZE(gl_relocs);
+-
+- nr_attributes = state->addr & 0x7;
+- if (nr_attributes == 0)
+- nr_attributes = 8;
+- packet_size = gl_shader_rec_size(state->addr);
+- }
+- nr_relocs = nr_fixed_relocs + nr_attributes;
++ nr_attributes = state->addr & 0x7;
++ if (nr_attributes == 0)
++ nr_attributes = 8;
++ packet_size = gl_shader_rec_size(state->addr);
+
++ nr_relocs = ARRAY_SIZE(shader_reloc_offsets) + nr_attributes;
+ if (nr_relocs * 4 > exec->shader_rec_size) {
+ DRM_ERROR("overflowed shader recs reading %d handles "
+ "from %d bytes left\n",
+@@ -829,21 +775,30 @@ validate_shader_rec(struct drm_device *d
+ exec->shader_rec_v += roundup(packet_size, 16);
+ exec->shader_rec_size -= packet_size;
+
+- for (i = 0; i < nr_relocs; i++) {
+- enum vc4_bo_mode mode;
++ if (!(*(uint16_t *)pkt_u & VC4_SHADER_FLAG_FS_SINGLE_THREAD)) {
++ DRM_ERROR("Multi-threaded fragment shaders not supported.\n");
++ return -EINVAL;
++ }
+
+- if (i < nr_fixed_relocs && relocs[i].type == RELOC_CODE)
+- mode = VC4_MODE_SHADER;
+- else
+- mode = VC4_MODE_RENDER;
++ for (i = 0; i < shader_reloc_count; i++) {
++ if (src_handles[i] > exec->bo_count) {
++ DRM_ERROR("Shader handle %d too big\n", src_handles[i]);
++ return -EINVAL;
++ }
+
+- if (!vc4_use_bo(exec, src_handles[i], mode, &bo[i]))
+- return false;
++ bo[i] = exec->bo[src_handles[i]];
++ if (!bo[i])
++ return -EINVAL;
++ }
++ for (i = shader_reloc_count; i < nr_relocs; i++) {
++ bo[i] = vc4_use_bo(exec, src_handles[i]);
++ if (!bo[i])
++ return -EINVAL;
+ }
+
+- for (i = 0; i < nr_fixed_relocs; i++) {
+- struct vc4_bo *vc4_bo;
+- uint32_t o = relocs[i].offset;
++ for (i = 0; i < shader_reloc_count; i++) {
++ struct vc4_validated_shader_info *validated_shader;
++ uint32_t o = shader_reloc_offsets[i];
+ uint32_t src_offset = *(uint32_t *)(pkt_u + o);
+ uint32_t *texture_handles_u;
+ void *uniform_data_u;
+@@ -851,57 +806,50 @@ validate_shader_rec(struct drm_device *d
+
+ *(uint32_t *)(pkt_v + o) = bo[i]->paddr + src_offset;
+
+- switch (relocs[i].type) {
+- case RELOC_CODE:
+- if (src_offset != 0) {
+- DRM_ERROR("Shaders must be at offset 0 "
+- "of the BO.\n");
+- goto fail;
+- }
++ if (src_offset != 0) {
++ DRM_ERROR("Shaders must be at offset 0 of "
++ "the BO.\n");
++ return -EINVAL;
++ }
+
+- vc4_bo = to_vc4_bo(&bo[i]->base);
+- shader = vc4_bo->validated_shader;
+- if (!shader)
+- goto fail;
++ validated_shader = to_vc4_bo(&bo[i]->base)->validated_shader;
++ if (!validated_shader)
++ return -EINVAL;
+
+- if (shader->uniforms_src_size > exec->uniforms_size) {
+- DRM_ERROR("Uniforms src buffer overflow\n");
+- goto fail;
+- }
++ if (validated_shader->uniforms_src_size >
++ exec->uniforms_size) {
++ DRM_ERROR("Uniforms src buffer overflow\n");
++ return -EINVAL;
++ }
+
+- texture_handles_u = exec->uniforms_u;
+- uniform_data_u = (texture_handles_u +
+- shader->num_texture_samples);
+-
+- memcpy(exec->uniforms_v, uniform_data_u,
+- shader->uniforms_size);
+-
+- for (tex = 0;
+- tex < shader->num_texture_samples;
+- tex++) {
+- if (!reloc_tex(exec,
+- uniform_data_u,
+- &shader->texture_samples[tex],
+- texture_handles_u[tex])) {
+- goto fail;
+- }
++ texture_handles_u = exec->uniforms_u;
++ uniform_data_u = (texture_handles_u +
++ validated_shader->num_texture_samples);
++
++ memcpy(exec->uniforms_v, uniform_data_u,
++ validated_shader->uniforms_size);
++
++ for (tex = 0;
++ tex < validated_shader->num_texture_samples;
++ tex++) {
++ if (!reloc_tex(exec,
++ uniform_data_u,
++ &validated_shader->texture_samples[tex],
++ texture_handles_u[tex])) {
++ return -EINVAL;
+ }
++ }
+
+- *(uint32_t *)(pkt_v + o + 4) = exec->uniforms_p;
+-
+- exec->uniforms_u += shader->uniforms_src_size;
+- exec->uniforms_v += shader->uniforms_size;
+- exec->uniforms_p += shader->uniforms_size;
+-
+- break;
++ *(uint32_t *)(pkt_v + o + 4) = exec->uniforms_p;
+
+- case RELOC_VBO:
+- break;
+- }
++ exec->uniforms_u += validated_shader->uniforms_src_size;
++ exec->uniforms_v += validated_shader->uniforms_size;
++ exec->uniforms_p += validated_shader->uniforms_size;
+ }
+
+ for (i = 0; i < nr_attributes; i++) {
+- struct drm_gem_cma_object *vbo = bo[nr_fixed_relocs + i];
++ struct drm_gem_cma_object *vbo =
++ bo[ARRAY_SIZE(shader_reloc_offsets) + i];
+ uint32_t o = 36 + i * 8;
+ uint32_t offset = *(uint32_t *)(pkt_u + o + 0);
+ uint32_t attr_size = *(uint8_t *)(pkt_u + o + 4) + 1;
+@@ -933,9 +881,6 @@ validate_shader_rec(struct drm_device *d
+ }
+
+ return 0;
+-
+-fail:
+- return -EINVAL;
+ }
+
+ int
+@@ -946,7 +891,7 @@ vc4_validate_shader_recs(struct drm_devi
+ int ret = 0;
+
+ for (i = 0; i < exec->shader_state_count; i++) {
+- ret = validate_shader_rec(dev, exec, &exec->shader_state[i]);
++ ret = validate_gl_shader_rec(dev, exec, &exec->shader_state[i]);
+ if (ret)
+ return ret;
+ }
diff --git a/target/linux/brcm2708/patches-4.4/0119-drm-vc4-Use-hpd-gpios-for-HDMI-GPIO-like-what-landed.patch b/target/linux/brcm2708/patches-4.4/0119-drm-vc4-Use-hpd-gpios-for-HDMI-GPIO-like-what-landed.patch
deleted file mode 100644
index e66eaed9b0..0000000000
--- a/target/linux/brcm2708/patches-4.4/0119-drm-vc4-Use-hpd-gpios-for-HDMI-GPIO-like-what-landed.patch
+++ /dev/null
@@ -1,22 +0,0 @@
-From 0a373a81664b9e9b8994512fb3d15ed296526e89 Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Tue, 15 Dec 2015 23:46:32 +0000
-Subject: [PATCH 119/170] drm/vc4: Use "hpd-gpios" for HDMI GPIO, like what
- landed upstream.
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
----
- arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts
-@@ -68,7 +68,7 @@
- <0x7e808000 0x100>;
- interrupts = <2 8>, <2 9>;
- ddc = <&i2c2>;
-- hpd-gpio = <&gpio 46 GPIO_ACTIVE_HIGH>;
-+ hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>;
- clocks = <&cprman BCM2835_PLLH_PIX>,
- <&cprman BCM2835_CLOCK_HSM>;
- clock-names = "pixel", "hdmi";
diff --git a/target/linux/brcm2708/patches-4.4/0120-MMC-Do-not-use-mmc_debug-if-CONFIG_MMC_BCM2835-is-no.patch b/target/linux/brcm2708/patches-4.4/0120-MMC-Do-not-use-mmc_debug-if-CONFIG_MMC_BCM2835-is-no.patch
new file mode 100644
index 0000000000..ebc6df5377
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0120-MMC-Do-not-use-mmc_debug-if-CONFIG_MMC_BCM2835-is-no.patch
@@ -0,0 +1,37 @@
+From f507706440ee0505e7533660f19781ea279355b0 Mon Sep 17 00:00:00 2001
+From: janluca <janluca@zedat.fu-berlin.de>
+Date: Sun, 27 Dec 2015 14:34:04 +0100
+Subject: [PATCH 120/381] MMC: Do not use mmc_debug if CONFIG_MMC_BCM2835 is
+ not set
+
+If CONFIG_MMC_BCM2835 was not set the compiling of the kernel failed
+since mmc_debug was not defined but used in drivers/mmc/core/quirks.c.
+
+This patch add a ifdef-check for CONFIG_MMC_BCM2835 to the change of
+commit 64d395457f793250d2e582eeb38cc3403b1db98c
+---
+ drivers/mmc/core/quirks.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/mmc/core/quirks.c
++++ b/drivers/mmc/core/quirks.c
+@@ -53,7 +53,9 @@ static const struct mmc_fixup mmc_fixup_
+
+ void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table)
+ {
++#ifdef CONFIG_MMC_BCM2835
+ extern unsigned mmc_debug;
++#endif
+ const struct mmc_fixup *f;
+ u64 rev = cid_rev_card(card);
+
+@@ -81,7 +83,9 @@ void mmc_fixup_device(struct mmc_card *c
+ /* SDHCI on BCM2708 - bug causes a certain sequence of CMD23 operations to fail.
+ * Disable this flag for all cards (fall-back to CMD25/CMD18 multi-block transfers).
+ */
++#ifdef CONFIG_MMC_BCM2835
+ if (mmc_debug & (1<<13))
+ card->quirks |= MMC_QUIRK_BLK_NO_CMD23;
++#endif
+ }
+ EXPORT_SYMBOL(mmc_fixup_device);
diff --git a/target/linux/brcm2708/patches-4.4/0120-drm-vc4-Synchronize-validation-code-for-v2-submissio.patch b/target/linux/brcm2708/patches-4.4/0120-drm-vc4-Synchronize-validation-code-for-v2-submissio.patch
deleted file mode 100644
index a6a4d5e039..0000000000
--- a/target/linux/brcm2708/patches-4.4/0120-drm-vc4-Synchronize-validation-code-for-v2-submissio.patch
+++ /dev/null
@@ -1,612 +0,0 @@
-From f8453aacbe60712c31c57580a126017b798bd339 Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Mon, 7 Dec 2015 12:35:01 -0800
-Subject: [PATCH 120/170] drm/vc4: Synchronize validation code for v2
- submission upstream.
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
----
- drivers/gpu/drm/vc4/vc4_drv.h | 24 +--
- drivers/gpu/drm/vc4/vc4_gem.c | 14 +-
- drivers/gpu/drm/vc4/vc4_render_cl.c | 6 +-
- drivers/gpu/drm/vc4/vc4_validate.c | 287 +++++++++++++++---------------------
- 4 files changed, 135 insertions(+), 196 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_drv.h
-+++ b/drivers/gpu/drm/vc4/vc4_drv.h
-@@ -189,17 +189,6 @@ to_vc4_encoder(struct drm_encoder *encod
- #define HVS_READ(offset) readl(vc4->hvs->regs + offset)
- #define HVS_WRITE(offset, val) writel(val, vc4->hvs->regs + offset)
-
--enum vc4_bo_mode {
-- VC4_MODE_UNDECIDED,
-- VC4_MODE_RENDER,
-- VC4_MODE_SHADER,
--};
--
--struct vc4_bo_exec_state {
-- struct drm_gem_cma_object *bo;
-- enum vc4_bo_mode mode;
--};
--
- struct vc4_exec_info {
- /* Sequence number for this bin/render job. */
- uint64_t seqno;
-@@ -210,7 +199,7 @@ struct vc4_exec_info {
- /* This is the array of BOs that were looked up at the start of exec.
- * Command validation will use indices into this array.
- */
-- struct vc4_bo_exec_state *bo;
-+ struct drm_gem_cma_object **bo;
- uint32_t bo_count;
-
- /* Pointers for our position in vc4->job_list */
-@@ -238,7 +227,6 @@ struct vc4_exec_info {
- * command lists.
- */
- struct vc4_shader_state {
-- uint8_t packet;
- uint32_t addr;
- /* Maximum vertex index referenced by any primitive using this
- * shader state.
-@@ -254,6 +242,7 @@ struct vc4_exec_info {
- bool found_tile_binning_mode_config_packet;
- bool found_start_tile_binning_packet;
- bool found_increment_semaphore_packet;
-+ bool found_flush;
- uint8_t bin_tiles_x, bin_tiles_y;
- struct drm_gem_cma_object *tile_bo;
- uint32_t tile_alloc_offset;
-@@ -265,6 +254,9 @@ struct vc4_exec_info {
- uint32_t ct0ca, ct0ea;
- uint32_t ct1ca, ct1ea;
-
-+ /* Pointer to the unvalidated bin CL (if present). */
-+ void *bin_u;
-+
- /* Pointers to the shader recs. These paddr gets incremented as CL
- * packets are relocated in validate_gl_shader_state, and the vaddrs
- * (u and v) get incremented and size decremented as the shader recs
-@@ -455,10 +447,8 @@ vc4_validate_bin_cl(struct drm_device *d
- int
- vc4_validate_shader_recs(struct drm_device *dev, struct vc4_exec_info *exec);
-
--bool vc4_use_bo(struct vc4_exec_info *exec,
-- uint32_t hindex,
-- enum vc4_bo_mode mode,
-- struct drm_gem_cma_object **obj);
-+struct drm_gem_cma_object *vc4_use_bo(struct vc4_exec_info *exec,
-+ uint32_t hindex);
-
- int vc4_get_rcl(struct drm_device *dev, struct vc4_exec_info *exec);
-
---- a/drivers/gpu/drm/vc4/vc4_gem.c
-+++ b/drivers/gpu/drm/vc4/vc4_gem.c
-@@ -169,8 +169,8 @@ vc4_save_hang_state(struct drm_device *d
- }
-
- for (i = 0; i < exec->bo_count; i++) {
-- drm_gem_object_reference(&exec->bo[i].bo->base);
-- kernel_state->bo[i] = &exec->bo[i].bo->base;
-+ drm_gem_object_reference(&exec->bo[i]->base);
-+ kernel_state->bo[i] = &exec->bo[i]->base;
- }
-
- list_for_each_entry(bo, &exec->unref_list, unref_head) {
-@@ -397,7 +397,7 @@ vc4_update_bo_seqnos(struct vc4_exec_inf
- unsigned i;
-
- for (i = 0; i < exec->bo_count; i++) {
-- bo = to_vc4_bo(&exec->bo[i].bo->base);
-+ bo = to_vc4_bo(&exec->bo[i]->base);
- bo->seqno = seqno;
- }
-
-@@ -467,7 +467,7 @@ vc4_cl_lookup_bos(struct drm_device *dev
- return -EINVAL;
- }
-
-- exec->bo = kcalloc(exec->bo_count, sizeof(struct vc4_bo_exec_state),
-+ exec->bo = kcalloc(exec->bo_count, sizeof(struct drm_gem_cma_object *),
- GFP_KERNEL);
- if (!exec->bo) {
- DRM_ERROR("Failed to allocate validated BO pointers\n");
-@@ -500,7 +500,7 @@ vc4_cl_lookup_bos(struct drm_device *dev
- goto fail;
- }
- drm_gem_object_reference(bo);
-- exec->bo[i].bo = (struct drm_gem_cma_object *)bo;
-+ exec->bo[i] = (struct drm_gem_cma_object *)bo;
- }
- spin_unlock(&file_priv->table_lock);
-
-@@ -591,6 +591,8 @@ vc4_get_bcl(struct drm_device *dev, stru
-
- exec->ct0ca = exec->exec_bo->paddr + bin_offset;
-
-+ exec->bin_u = bin;
-+
- exec->shader_rec_v = exec->exec_bo->vaddr + shader_rec_offset;
- exec->shader_rec_p = exec->exec_bo->paddr + shader_rec_offset;
- exec->shader_rec_size = args->shader_rec_size;
-@@ -622,7 +624,7 @@ vc4_complete_exec(struct drm_device *dev
- mutex_lock(&dev->struct_mutex);
- if (exec->bo) {
- for (i = 0; i < exec->bo_count; i++)
-- drm_gem_object_unreference(&exec->bo[i].bo->base);
-+ drm_gem_object_unreference(&exec->bo[i]->base);
- kfree(exec->bo);
- }
-
---- a/drivers/gpu/drm/vc4/vc4_render_cl.c
-+++ b/drivers/gpu/drm/vc4/vc4_render_cl.c
-@@ -436,7 +436,8 @@ static int vc4_rcl_surface_setup(struct
- if (surf->hindex == ~0)
- return 0;
-
-- if (!vc4_use_bo(exec, surf->hindex, VC4_MODE_RENDER, obj))
-+ *obj = vc4_use_bo(exec, surf->hindex);
-+ if (!*obj)
- return -EINVAL;
-
- if (surf->flags & VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) {
-@@ -537,7 +538,8 @@ vc4_rcl_render_config_surface_setup(stru
- if (surf->hindex == ~0)
- return 0;
-
-- if (!vc4_use_bo(exec, surf->hindex, VC4_MODE_RENDER, obj))
-+ *obj = vc4_use_bo(exec, surf->hindex);
-+ if (!*obj)
- return -EINVAL;
-
- if (tiling > VC4_TILING_FORMAT_LT) {
---- a/drivers/gpu/drm/vc4/vc4_validate.c
-+++ b/drivers/gpu/drm/vc4/vc4_validate.c
-@@ -94,42 +94,42 @@ size_is_lt(uint32_t width, uint32_t heig
- height <= 4 * utile_height(cpp));
- }
-
--bool
--vc4_use_bo(struct vc4_exec_info *exec,
-- uint32_t hindex,
-- enum vc4_bo_mode mode,
-- struct drm_gem_cma_object **obj)
-+struct drm_gem_cma_object *
-+vc4_use_bo(struct vc4_exec_info *exec, uint32_t hindex)
- {
-- *obj = NULL;
-+ struct drm_gem_cma_object *obj;
-+ struct vc4_bo *bo;
-
- if (hindex >= exec->bo_count) {
- DRM_ERROR("BO index %d greater than BO count %d\n",
- hindex, exec->bo_count);
-- return false;
-+ return NULL;
- }
-+ obj = exec->bo[hindex];
-+ bo = to_vc4_bo(&obj->base);
-
-- if (exec->bo[hindex].mode != mode) {
-- if (exec->bo[hindex].mode == VC4_MODE_UNDECIDED) {
-- exec->bo[hindex].mode = mode;
-- } else {
-- DRM_ERROR("BO index %d reused with mode %d vs %d\n",
-- hindex, exec->bo[hindex].mode, mode);
-- return false;
-- }
-+ if (bo->validated_shader) {
-+ DRM_ERROR("Trying to use shader BO as something other than "
-+ "a shader\n");
-+ return NULL;
- }
-
-- *obj = exec->bo[hindex].bo;
-- return true;
-+ return obj;
-+}
-+
-+static struct drm_gem_cma_object *
-+vc4_use_handle(struct vc4_exec_info *exec, uint32_t gem_handles_packet_index)
-+{
-+ return vc4_use_bo(exec, exec->bo_index[gem_handles_packet_index]);
- }
-
- static bool
--vc4_use_handle(struct vc4_exec_info *exec,
-- uint32_t gem_handles_packet_index,
-- enum vc4_bo_mode mode,
-- struct drm_gem_cma_object **obj)
-+validate_bin_pos(struct vc4_exec_info *exec, void *untrusted, uint32_t pos)
- {
-- return vc4_use_bo(exec, exec->bo_index[gem_handles_packet_index],
-- mode, obj);
-+ /* Note that the untrusted pointer passed to these functions is
-+ * incremented past the packet byte.
-+ */
-+ return (untrusted - 1 == exec->bin_u + pos);
- }
-
- static uint32_t
-@@ -202,13 +202,13 @@ vc4_check_tex_size(struct vc4_exec_info
- }
-
- static int
--validate_flush_all(VALIDATE_ARGS)
-+validate_flush(VALIDATE_ARGS)
- {
-- if (exec->found_increment_semaphore_packet) {
-- DRM_ERROR("VC4_PACKET_FLUSH_ALL after "
-- "VC4_PACKET_INCREMENT_SEMAPHORE\n");
-+ if (!validate_bin_pos(exec, untrusted, exec->args->bin_cl_size - 1)) {
-+ DRM_ERROR("Bin CL must end with VC4_PACKET_FLUSH\n");
- return -EINVAL;
- }
-+ exec->found_flush = true;
-
- return 0;
- }
-@@ -233,17 +233,13 @@ validate_start_tile_binning(VALIDATE_ARG
- static int
- validate_increment_semaphore(VALIDATE_ARGS)
- {
-- if (exec->found_increment_semaphore_packet) {
-- DRM_ERROR("Duplicate VC4_PACKET_INCREMENT_SEMAPHORE\n");
-+ if (!validate_bin_pos(exec, untrusted, exec->args->bin_cl_size - 2)) {
-+ DRM_ERROR("Bin CL must end with "
-+ "VC4_PACKET_INCREMENT_SEMAPHORE\n");
- return -EINVAL;
- }
- exec->found_increment_semaphore_packet = true;
-
-- /* Once we've found the semaphore increment, there should be one FLUSH
-- * then the end of the command list. The FLUSH actually triggers the
-- * increment, so we only need to make sure there
-- */
--
- return 0;
- }
-
-@@ -257,11 +253,6 @@ validate_indexed_prim_list(VALIDATE_ARGS
- uint32_t index_size = (*(uint8_t *)(untrusted + 0) >> 4) ? 2 : 1;
- struct vc4_shader_state *shader_state;
-
-- if (exec->found_increment_semaphore_packet) {
-- DRM_ERROR("Drawing after VC4_PACKET_INCREMENT_SEMAPHORE\n");
-- return -EINVAL;
-- }
--
- /* Check overflow condition */
- if (exec->shader_state_count == 0) {
- DRM_ERROR("shader state must precede primitives\n");
-@@ -272,7 +263,8 @@ validate_indexed_prim_list(VALIDATE_ARGS
- if (max_index > shader_state->max_index)
- shader_state->max_index = max_index;
-
-- if (!vc4_use_handle(exec, 0, VC4_MODE_RENDER, &ib))
-+ ib = vc4_use_handle(exec, 0);
-+ if (!ib)
- return -EINVAL;
-
- if (offset > ib->base.size ||
-@@ -295,11 +287,6 @@ validate_gl_array_primitive(VALIDATE_ARG
- uint32_t max_index;
- struct vc4_shader_state *shader_state;
-
-- if (exec->found_increment_semaphore_packet) {
-- DRM_ERROR("Drawing after VC4_PACKET_INCREMENT_SEMAPHORE\n");
-- return -EINVAL;
-- }
--
- /* Check overflow condition */
- if (exec->shader_state_count == 0) {
- DRM_ERROR("shader state must precede primitives\n");
-@@ -329,7 +316,6 @@ validate_gl_shader_state(VALIDATE_ARGS)
- return -EINVAL;
- }
-
-- exec->shader_state[i].packet = VC4_PACKET_GL_SHADER_STATE;
- exec->shader_state[i].addr = *(uint32_t *)untrusted;
- exec->shader_state[i].max_index = 0;
-
-@@ -348,31 +334,6 @@ validate_gl_shader_state(VALIDATE_ARGS)
- }
-
- static int
--validate_nv_shader_state(VALIDATE_ARGS)
--{
-- uint32_t i = exec->shader_state_count++;
--
-- if (i >= exec->shader_state_size) {
-- DRM_ERROR("More requests for shader states than declared\n");
-- return -EINVAL;
-- }
--
-- exec->shader_state[i].packet = VC4_PACKET_NV_SHADER_STATE;
-- exec->shader_state[i].addr = *(uint32_t *)untrusted;
--
-- if (exec->shader_state[i].addr & 15) {
-- DRM_ERROR("NV shader state address 0x%08x misaligned\n",
-- exec->shader_state[i].addr);
-- return -EINVAL;
-- }
--
-- *(uint32_t *)validated = (exec->shader_state[i].addr +
-- exec->shader_rec_p);
--
-- return 0;
--}
--
--static int
- validate_tile_binning_config(VALIDATE_ARGS)
- {
- struct drm_device *dev = exec->exec_bo->base.dev;
-@@ -473,8 +434,8 @@ static const struct cmd_info {
- } cmd_info[] = {
- VC4_DEFINE_PACKET(VC4_PACKET_HALT, NULL),
- VC4_DEFINE_PACKET(VC4_PACKET_NOP, NULL),
-- VC4_DEFINE_PACKET(VC4_PACKET_FLUSH, NULL),
-- VC4_DEFINE_PACKET(VC4_PACKET_FLUSH_ALL, validate_flush_all),
-+ VC4_DEFINE_PACKET(VC4_PACKET_FLUSH, validate_flush),
-+ VC4_DEFINE_PACKET(VC4_PACKET_FLUSH_ALL, NULL),
- VC4_DEFINE_PACKET(VC4_PACKET_START_TILE_BINNING,
- validate_start_tile_binning),
- VC4_DEFINE_PACKET(VC4_PACKET_INCREMENT_SEMAPHORE,
-@@ -488,7 +449,6 @@ static const struct cmd_info {
- VC4_DEFINE_PACKET(VC4_PACKET_PRIMITIVE_LIST_FORMAT, NULL),
-
- VC4_DEFINE_PACKET(VC4_PACKET_GL_SHADER_STATE, validate_gl_shader_state),
-- VC4_DEFINE_PACKET(VC4_PACKET_NV_SHADER_STATE, validate_nv_shader_state),
-
- VC4_DEFINE_PACKET(VC4_PACKET_CONFIGURATION_BITS, NULL),
- VC4_DEFINE_PACKET(VC4_PACKET_FLAT_SHADE_FLAGS, NULL),
-@@ -575,8 +535,16 @@ vc4_validate_bin_cl(struct drm_device *d
- return -EINVAL;
- }
-
-- if (!exec->found_increment_semaphore_packet) {
-- DRM_ERROR("Bin CL missing VC4_PACKET_INCREMENT_SEMAPHORE\n");
-+ /* The bin CL must be ended with INCREMENT_SEMAPHORE and FLUSH. The
-+ * semaphore is used to trigger the render CL to start up, and the
-+ * FLUSH is what caps the bin lists with
-+ * VC4_PACKET_RETURN_FROM_SUB_LIST (so they jump back to the main
-+ * render CL when they get called to) and actually triggers the queued
-+ * semaphore increment.
-+ */
-+ if (!exec->found_increment_semaphore_packet || !exec->found_flush) {
-+ DRM_ERROR("Bin CL missing VC4_PACKET_INCREMENT_SEMAPHORE + "
-+ "VC4_PACKET_FLUSH\n");
- return -EINVAL;
- }
-
-@@ -607,7 +575,8 @@ reloc_tex(struct vc4_exec_info *exec,
- uint32_t cube_map_stride = 0;
- enum vc4_texture_data_type type;
-
-- if (!vc4_use_bo(exec, texture_handle_index, VC4_MODE_RENDER, &tex))
-+ tex = vc4_use_bo(exec, texture_handle_index);
-+ if (!tex)
- return false;
-
- if (sample->is_direct) {
-@@ -755,51 +724,28 @@ reloc_tex(struct vc4_exec_info *exec,
- }
-
- static int
--validate_shader_rec(struct drm_device *dev,
-- struct vc4_exec_info *exec,
-- struct vc4_shader_state *state)
-+validate_gl_shader_rec(struct drm_device *dev,
-+ struct vc4_exec_info *exec,
-+ struct vc4_shader_state *state)
- {
- uint32_t *src_handles;
- void *pkt_u, *pkt_v;
-- enum shader_rec_reloc_type {
-- RELOC_CODE,
-- RELOC_VBO,
-- };
-- struct shader_rec_reloc {
-- enum shader_rec_reloc_type type;
-- uint32_t offset;
-- };
-- static const struct shader_rec_reloc gl_relocs[] = {
-- { RELOC_CODE, 4 }, /* fs */
-- { RELOC_CODE, 16 }, /* vs */
-- { RELOC_CODE, 28 }, /* cs */
-- };
-- static const struct shader_rec_reloc nv_relocs[] = {
-- { RELOC_CODE, 4 }, /* fs */
-- { RELOC_VBO, 12 }
-+ static const uint32_t shader_reloc_offsets[] = {
-+ 4, /* fs */
-+ 16, /* vs */
-+ 28, /* cs */
- };
-- const struct shader_rec_reloc *relocs;
-- struct drm_gem_cma_object *bo[ARRAY_SIZE(gl_relocs) + 8];
-- uint32_t nr_attributes = 0, nr_fixed_relocs, nr_relocs, packet_size;
-+ uint32_t shader_reloc_count = ARRAY_SIZE(shader_reloc_offsets);
-+ struct drm_gem_cma_object *bo[shader_reloc_count + 8];
-+ uint32_t nr_attributes, nr_relocs, packet_size;
- int i;
-- struct vc4_validated_shader_info *shader;
-
-- if (state->packet == VC4_PACKET_NV_SHADER_STATE) {
-- relocs = nv_relocs;
-- nr_fixed_relocs = ARRAY_SIZE(nv_relocs);
--
-- packet_size = 16;
-- } else {
-- relocs = gl_relocs;
-- nr_fixed_relocs = ARRAY_SIZE(gl_relocs);
--
-- nr_attributes = state->addr & 0x7;
-- if (nr_attributes == 0)
-- nr_attributes = 8;
-- packet_size = gl_shader_rec_size(state->addr);
-- }
-- nr_relocs = nr_fixed_relocs + nr_attributes;
-+ nr_attributes = state->addr & 0x7;
-+ if (nr_attributes == 0)
-+ nr_attributes = 8;
-+ packet_size = gl_shader_rec_size(state->addr);
-
-+ nr_relocs = ARRAY_SIZE(shader_reloc_offsets) + nr_attributes;
- if (nr_relocs * 4 > exec->shader_rec_size) {
- DRM_ERROR("overflowed shader recs reading %d handles "
- "from %d bytes left\n",
-@@ -829,21 +775,30 @@ validate_shader_rec(struct drm_device *d
- exec->shader_rec_v += roundup(packet_size, 16);
- exec->shader_rec_size -= packet_size;
-
-- for (i = 0; i < nr_relocs; i++) {
-- enum vc4_bo_mode mode;
-+ if (!(*(uint16_t *)pkt_u & VC4_SHADER_FLAG_FS_SINGLE_THREAD)) {
-+ DRM_ERROR("Multi-threaded fragment shaders not supported.\n");
-+ return -EINVAL;
-+ }
-
-- if (i < nr_fixed_relocs && relocs[i].type == RELOC_CODE)
-- mode = VC4_MODE_SHADER;
-- else
-- mode = VC4_MODE_RENDER;
-+ for (i = 0; i < shader_reloc_count; i++) {
-+ if (src_handles[i] > exec->bo_count) {
-+ DRM_ERROR("Shader handle %d too big\n", src_handles[i]);
-+ return -EINVAL;
-+ }
-
-- if (!vc4_use_bo(exec, src_handles[i], mode, &bo[i]))
-- return false;
-+ bo[i] = exec->bo[src_handles[i]];
-+ if (!bo[i])
-+ return -EINVAL;
-+ }
-+ for (i = shader_reloc_count; i < nr_relocs; i++) {
-+ bo[i] = vc4_use_bo(exec, src_handles[i]);
-+ if (!bo[i])
-+ return -EINVAL;
- }
-
-- for (i = 0; i < nr_fixed_relocs; i++) {
-- struct vc4_bo *vc4_bo;
-- uint32_t o = relocs[i].offset;
-+ for (i = 0; i < shader_reloc_count; i++) {
-+ struct vc4_validated_shader_info *validated_shader;
-+ uint32_t o = shader_reloc_offsets[i];
- uint32_t src_offset = *(uint32_t *)(pkt_u + o);
- uint32_t *texture_handles_u;
- void *uniform_data_u;
-@@ -851,57 +806,50 @@ validate_shader_rec(struct drm_device *d
-
- *(uint32_t *)(pkt_v + o) = bo[i]->paddr + src_offset;
-
-- switch (relocs[i].type) {
-- case RELOC_CODE:
-- if (src_offset != 0) {
-- DRM_ERROR("Shaders must be at offset 0 "
-- "of the BO.\n");
-- goto fail;
-- }
-+ if (src_offset != 0) {
-+ DRM_ERROR("Shaders must be at offset 0 of "
-+ "the BO.\n");
-+ return -EINVAL;
-+ }
-
-- vc4_bo = to_vc4_bo(&bo[i]->base);
-- shader = vc4_bo->validated_shader;
-- if (!shader)
-- goto fail;
-+ validated_shader = to_vc4_bo(&bo[i]->base)->validated_shader;
-+ if (!validated_shader)
-+ return -EINVAL;
-
-- if (shader->uniforms_src_size > exec->uniforms_size) {
-- DRM_ERROR("Uniforms src buffer overflow\n");
-- goto fail;
-- }
-+ if (validated_shader->uniforms_src_size >
-+ exec->uniforms_size) {
-+ DRM_ERROR("Uniforms src buffer overflow\n");
-+ return -EINVAL;
-+ }
-
-- texture_handles_u = exec->uniforms_u;
-- uniform_data_u = (texture_handles_u +
-- shader->num_texture_samples);
--
-- memcpy(exec->uniforms_v, uniform_data_u,
-- shader->uniforms_size);
--
-- for (tex = 0;
-- tex < shader->num_texture_samples;
-- tex++) {
-- if (!reloc_tex(exec,
-- uniform_data_u,
-- &shader->texture_samples[tex],
-- texture_handles_u[tex])) {
-- goto fail;
-- }
-+ texture_handles_u = exec->uniforms_u;
-+ uniform_data_u = (texture_handles_u +
-+ validated_shader->num_texture_samples);
-+
-+ memcpy(exec->uniforms_v, uniform_data_u,
-+ validated_shader->uniforms_size);
-+
-+ for (tex = 0;
-+ tex < validated_shader->num_texture_samples;
-+ tex++) {
-+ if (!reloc_tex(exec,
-+ uniform_data_u,
-+ &validated_shader->texture_samples[tex],
-+ texture_handles_u[tex])) {
-+ return -EINVAL;
- }
-+ }
-
-- *(uint32_t *)(pkt_v + o + 4) = exec->uniforms_p;
--
-- exec->uniforms_u += shader->uniforms_src_size;
-- exec->uniforms_v += shader->uniforms_size;
-- exec->uniforms_p += shader->uniforms_size;
--
-- break;
-+ *(uint32_t *)(pkt_v + o + 4) = exec->uniforms_p;
-
-- case RELOC_VBO:
-- break;
-- }
-+ exec->uniforms_u += validated_shader->uniforms_src_size;
-+ exec->uniforms_v += validated_shader->uniforms_size;
-+ exec->uniforms_p += validated_shader->uniforms_size;
- }
-
- for (i = 0; i < nr_attributes; i++) {
-- struct drm_gem_cma_object *vbo = bo[nr_fixed_relocs + i];
-+ struct drm_gem_cma_object *vbo =
-+ bo[ARRAY_SIZE(shader_reloc_offsets) + i];
- uint32_t o = 36 + i * 8;
- uint32_t offset = *(uint32_t *)(pkt_u + o + 0);
- uint32_t attr_size = *(uint8_t *)(pkt_u + o + 4) + 1;
-@@ -933,9 +881,6 @@ validate_shader_rec(struct drm_device *d
- }
-
- return 0;
--
--fail:
-- return -EINVAL;
- }
-
- int
-@@ -946,7 +891,7 @@ vc4_validate_shader_recs(struct drm_devi
- int ret = 0;
-
- for (i = 0; i < exec->shader_state_count; i++) {
-- ret = validate_shader_rec(dev, exec, &exec->shader_state[i]);
-+ ret = validate_gl_shader_rec(dev, exec, &exec->shader_state[i]);
- if (ret)
- return ret;
- }
diff --git a/target/linux/brcm2708/patches-4.4/0121-Extend-clock-timeout-fix-modprobe-baudrate-parameter.patch b/target/linux/brcm2708/patches-4.4/0121-Extend-clock-timeout-fix-modprobe-baudrate-parameter.patch
new file mode 100644
index 0000000000..3436f07290
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0121-Extend-clock-timeout-fix-modprobe-baudrate-parameter.patch
@@ -0,0 +1,108 @@
+From 7d0e8dc92007a9ad6193e8cda7d954e78e6556ee Mon Sep 17 00:00:00 2001
+From: Devon Fyson <devonfyson@gmail.com>
+Date: Wed, 30 Dec 2015 16:40:47 -0500
+Subject: [PATCH 121/381] Extend clock timeout, fix modprobe baudrate
+ parameter.
+
+Set the BSC_CLKT clock streching timeout to 35ms as per SMBus specs.\n- Increase priority of baudrate parameter passed to modprobe (in /etc/modprobe.d/*.conf or command line). Currently custom baudrates don't work because they are overridden by clock-frequency in the platform_device passed to the function.
+---
+ drivers/i2c/busses/i2c-bcm2708.c | 45 ++++++++++++++++++++++++++--------------
+ 1 file changed, 29 insertions(+), 16 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-bcm2708.c
++++ b/drivers/i2c/busses/i2c-bcm2708.c
+@@ -71,7 +71,8 @@
+
+ #define DRV_NAME "bcm2708_i2c"
+
+-static unsigned int baudrate = CONFIG_I2C_BCM2708_BAUDRATE;
++static unsigned int baudrate_default = CONFIG_I2C_BCM2708_BAUDRATE;
++static unsigned int baudrate;
+ module_param(baudrate, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+ MODULE_PARM_DESC(baudrate, "The I2C baudrate");
+
+@@ -87,6 +88,7 @@ struct bcm2708_i2c {
+ int irq;
+ struct clk *clk;
+ u32 cdiv;
++ u32 clk_tout;
+
+ struct completion done;
+
+@@ -126,7 +128,7 @@ static inline void bcm2708_bsc_fifo_fill
+
+ static inline int bcm2708_bsc_setup(struct bcm2708_i2c *bi)
+ {
+- u32 cdiv, s;
++ u32 cdiv, s, clk_tout;
+ u32 c = BSC_C_I2CEN | BSC_C_INTD | BSC_C_ST | BSC_C_CLEAR_1;
+ int wait_loops = I2C_WAIT_LOOP_COUNT;
+
+@@ -134,12 +136,14 @@ static inline int bcm2708_bsc_setup(stru
+ * Use the value that we cached in the probe.
+ */
+ cdiv = bi->cdiv;
++ clk_tout = bi->clk_tout;
+
+ if (bi->msg->flags & I2C_M_RD)
+ c |= BSC_C_INTR | BSC_C_READ;
+ else
+ c |= BSC_C_INTT;
+
++ bcm2708_wr(bi, BSC_CLKT, clk_tout);
+ bcm2708_wr(bi, BSC_DIV, cdiv);
+ bcm2708_wr(bi, BSC_A, bi->msg->addr);
+ bcm2708_wr(bi, BSC_DLEN, bi->msg->len);
+@@ -312,21 +316,24 @@ static int bcm2708_i2c_probe(struct plat
+ struct bcm2708_i2c *bi;
+ struct i2c_adapter *adap;
+ unsigned long bus_hz;
+- u32 cdiv;
+-
+- if (pdev->dev.of_node) {
+- u32 bus_clk_rate;
+- pdev->id = of_alias_get_id(pdev->dev.of_node, "i2c");
+- if (pdev->id < 0) {
+- dev_err(&pdev->dev, "alias is missing\n");
+- return -EINVAL;
++ u32 cdiv, clk_tout;
++
++ if (!baudrate) {
++ baudrate = baudrate_default;
++ if (pdev->dev.of_node) {
++ u32 bus_clk_rate;
++ pdev->id = of_alias_get_id(pdev->dev.of_node, "i2c");
++ if (pdev->id < 0) {
++ dev_err(&pdev->dev, "alias is missing\n");
++ return -EINVAL;
++ }
++ if (!of_property_read_u32(pdev->dev.of_node,
++ "clock-frequency", &bus_clk_rate))
++ baudrate = bus_clk_rate;
++ else
++ dev_warn(&pdev->dev,
++ "Could not read clock-frequency property\n");
+ }
+- if (!of_property_read_u32(pdev->dev.of_node,
+- "clock-frequency", &bus_clk_rate))
+- baudrate = bus_clk_rate;
+- else
+- dev_warn(&pdev->dev,
+- "Could not read clock-frequency property\n");
+ }
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+@@ -417,7 +424,13 @@ static int bcm2708_i2c_probe(struct plat
+ cdiv = 0xffff;
+ baudrate = bus_hz / cdiv;
+ }
++
++ clk_tout = 35/1000*baudrate; //35ms timeout as per SMBus specs.
++ if (clk_tout > 0xffff)
++ clk_tout = 0xffff;
++
+ bi->cdiv = cdiv;
++ bi->clk_tout = clk_tout;
+
+ dev_info(&pdev->dev, "BSC%d Controller at 0x%08lx (irq %d) (baudrate %d)\n",
+ pdev->id, (unsigned long)regs->start, irq, baudrate);
diff --git a/target/linux/brcm2708/patches-4.4/0121-MMC-Do-not-use-mmc_debug-if-CONFIG_MMC_BCM2835-is-no.patch b/target/linux/brcm2708/patches-4.4/0121-MMC-Do-not-use-mmc_debug-if-CONFIG_MMC_BCM2835-is-no.patch
deleted file mode 100644
index 5a0c685474..0000000000
--- a/target/linux/brcm2708/patches-4.4/0121-MMC-Do-not-use-mmc_debug-if-CONFIG_MMC_BCM2835-is-no.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-From 280bea89916813978b81811c2769411d438eb52f Mon Sep 17 00:00:00 2001
-From: janluca <janluca@zedat.fu-berlin.de>
-Date: Sun, 27 Dec 2015 14:34:04 +0100
-Subject: [PATCH 121/170] MMC: Do not use mmc_debug if CONFIG_MMC_BCM2835 is
- not set
-
-If CONFIG_MMC_BCM2835 was not set the compiling of the kernel failed
-since mmc_debug was not defined but used in drivers/mmc/core/quirks.c.
-
-This patch add a ifdef-check for CONFIG_MMC_BCM2835 to the change of
-commit 64d395457f793250d2e582eeb38cc3403b1db98c
----
- drivers/mmc/core/quirks.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/drivers/mmc/core/quirks.c
-+++ b/drivers/mmc/core/quirks.c
-@@ -53,7 +53,9 @@ static const struct mmc_fixup mmc_fixup_
-
- void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table)
- {
-+#ifdef CONFIG_MMC_BCM2835
- extern unsigned mmc_debug;
-+#endif
- const struct mmc_fixup *f;
- u64 rev = cid_rev_card(card);
-
-@@ -81,7 +83,9 @@ void mmc_fixup_device(struct mmc_card *c
- /* SDHCI on BCM2708 - bug causes a certain sequence of CMD23 operations to fail.
- * Disable this flag for all cards (fall-back to CMD25/CMD18 multi-block transfers).
- */
-+#ifdef CONFIG_MMC_BCM2835
- if (mmc_debug & (1<<13))
- card->quirks |= MMC_QUIRK_BLK_NO_CMD23;
-+#endif
- }
- EXPORT_SYMBOL(mmc_fixup_device);
diff --git a/target/linux/brcm2708/patches-4.4/0122-Extend-clock-timeout-fix-modprobe-baudrate-parameter.patch b/target/linux/brcm2708/patches-4.4/0122-Extend-clock-timeout-fix-modprobe-baudrate-parameter.patch
deleted file mode 100644
index 1059ae3445..0000000000
--- a/target/linux/brcm2708/patches-4.4/0122-Extend-clock-timeout-fix-modprobe-baudrate-parameter.patch
+++ /dev/null
@@ -1,108 +0,0 @@
-From d0390ae0ff774d8e7b5b4d5f38c33726354996bc Mon Sep 17 00:00:00 2001
-From: Devon Fyson <devonfyson@gmail.com>
-Date: Wed, 30 Dec 2015 16:40:47 -0500
-Subject: [PATCH 122/170] Extend clock timeout, fix modprobe baudrate
- parameter.
-
-Set the BSC_CLKT clock streching timeout to 35ms as per SMBus specs.\n- Increase priority of baudrate parameter passed to modprobe (in /etc/modprobe.d/*.conf or command line). Currently custom baudrates don't work because they are overridden by clock-frequency in the platform_device passed to the function.
----
- drivers/i2c/busses/i2c-bcm2708.c | 45 ++++++++++++++++++++++++++--------------
- 1 file changed, 29 insertions(+), 16 deletions(-)
-
---- a/drivers/i2c/busses/i2c-bcm2708.c
-+++ b/drivers/i2c/busses/i2c-bcm2708.c
-@@ -71,7 +71,8 @@
-
- #define DRV_NAME "bcm2708_i2c"
-
--static unsigned int baudrate = CONFIG_I2C_BCM2708_BAUDRATE;
-+static unsigned int baudrate_default = CONFIG_I2C_BCM2708_BAUDRATE;
-+static unsigned int baudrate;
- module_param(baudrate, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
- MODULE_PARM_DESC(baudrate, "The I2C baudrate");
-
-@@ -87,6 +88,7 @@ struct bcm2708_i2c {
- int irq;
- struct clk *clk;
- u32 cdiv;
-+ u32 clk_tout;
-
- struct completion done;
-
-@@ -126,7 +128,7 @@ static inline void bcm2708_bsc_fifo_fill
-
- static inline int bcm2708_bsc_setup(struct bcm2708_i2c *bi)
- {
-- u32 cdiv, s;
-+ u32 cdiv, s, clk_tout;
- u32 c = BSC_C_I2CEN | BSC_C_INTD | BSC_C_ST | BSC_C_CLEAR_1;
- int wait_loops = I2C_WAIT_LOOP_COUNT;
-
-@@ -134,12 +136,14 @@ static inline int bcm2708_bsc_setup(stru
- * Use the value that we cached in the probe.
- */
- cdiv = bi->cdiv;
-+ clk_tout = bi->clk_tout;
-
- if (bi->msg->flags & I2C_M_RD)
- c |= BSC_C_INTR | BSC_C_READ;
- else
- c |= BSC_C_INTT;
-
-+ bcm2708_wr(bi, BSC_CLKT, clk_tout);
- bcm2708_wr(bi, BSC_DIV, cdiv);
- bcm2708_wr(bi, BSC_A, bi->msg->addr);
- bcm2708_wr(bi, BSC_DLEN, bi->msg->len);
-@@ -312,21 +316,24 @@ static int bcm2708_i2c_probe(struct plat
- struct bcm2708_i2c *bi;
- struct i2c_adapter *adap;
- unsigned long bus_hz;
-- u32 cdiv;
--
-- if (pdev->dev.of_node) {
-- u32 bus_clk_rate;
-- pdev->id = of_alias_get_id(pdev->dev.of_node, "i2c");
-- if (pdev->id < 0) {
-- dev_err(&pdev->dev, "alias is missing\n");
-- return -EINVAL;
-+ u32 cdiv, clk_tout;
-+
-+ if (!baudrate) {
-+ baudrate = baudrate_default;
-+ if (pdev->dev.of_node) {
-+ u32 bus_clk_rate;
-+ pdev->id = of_alias_get_id(pdev->dev.of_node, "i2c");
-+ if (pdev->id < 0) {
-+ dev_err(&pdev->dev, "alias is missing\n");
-+ return -EINVAL;
-+ }
-+ if (!of_property_read_u32(pdev->dev.of_node,
-+ "clock-frequency", &bus_clk_rate))
-+ baudrate = bus_clk_rate;
-+ else
-+ dev_warn(&pdev->dev,
-+ "Could not read clock-frequency property\n");
- }
-- if (!of_property_read_u32(pdev->dev.of_node,
-- "clock-frequency", &bus_clk_rate))
-- baudrate = bus_clk_rate;
-- else
-- dev_warn(&pdev->dev,
-- "Could not read clock-frequency property\n");
- }
-
- regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-@@ -417,7 +424,13 @@ static int bcm2708_i2c_probe(struct plat
- cdiv = 0xffff;
- baudrate = bus_hz / cdiv;
- }
-+
-+ clk_tout = 35/1000*baudrate; //35ms timeout as per SMBus specs.
-+ if (clk_tout > 0xffff)
-+ clk_tout = 0xffff;
-+
- bi->cdiv = cdiv;
-+ bi->clk_tout = clk_tout;
-
- dev_info(&pdev->dev, "BSC%d Controller at 0x%08lx (irq %d) (baudrate %d)\n",
- pdev->id, (unsigned long)regs->start, irq, baudrate);
diff --git a/target/linux/brcm2708/patches-4.4/0122-bcm270x_dt-Add-dwc2-and-dwc-otg-overlays.patch b/target/linux/brcm2708/patches-4.4/0122-bcm270x_dt-Add-dwc2-and-dwc-otg-overlays.patch
new file mode 100644
index 0000000000..6702203dc2
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0122-bcm270x_dt-Add-dwc2-and-dwc-otg-overlays.patch
@@ -0,0 +1,110 @@
+From 7883c7188ab1259b74c2442690fedf3d71c534fb Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
+Date: Thu, 31 Dec 2015 16:44:58 +0100
+Subject: [PATCH 122/381] bcm270x_dt: Add dwc2 and dwc-otg overlays
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 2 ++
+ arch/arm/boot/dts/overlays/README | 21 +++++++++++++++++++
+ arch/arm/boot/dts/overlays/dwc-otg-overlay.dts | 20 ++++++++++++++++++
+ arch/arm/boot/dts/overlays/dwc2-overlay.dts | 29 ++++++++++++++++++++++++++
+ 4 files changed, 72 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/dwc-otg-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/dwc2-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -15,6 +15,8 @@ endif
+ dtb-$(RPI_DT_OVERLAYS) += ads7846-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += at86rf233-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += bmp085_i2c-sensor-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += dwc2-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += dwc-otg-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += dht11-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += enc28j60-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += gpio-ir-overlay.dtb
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -198,6 +198,27 @@ Params: gpiopin GPIO co
+ (default 4)
+
+
++Name: dwc-otg
++Info: Selects the dwc_otg USB controller driver which has fiq support. This
++ is the default on all except the Pi Zero which defaults to dwc2.
++Load: dtoverlay=dwc-otg
++Params: <None>
++
++
++Name: dwc2
++Info: Selects the dwc2 USB controller driver
++Load: dtoverlay=dwc2,<param>=<val>
++Params: dr_mode Dual role mode: "host", "peripheral" or "otg"
++
++ g-rx-fifo-size Size of rx fifo size in gadget mode
++
++ g-np-tx-fifo-size Size of non-periodic tx fifo size in gadget
++ mode
++
++ g-tx-fifo-size Size of periodic tx fifo per endpoint
++ (except ep0) in gadget mode
++
++
+ [ The ds1307-rtc overlay has been deleted. See i2c-rtc. ]
+
+
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/dwc-otg-overlay.dts
+@@ -0,0 +1,20 @@
++/dts-v1/;
++/plugin/;
++
++/{
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&usb>;
++ #address-cells = <1>;
++ #size-cells = <1>;
++ __overlay__ {
++ compatible = "brcm,bcm2708-usb";
++ reg = <0x7e980000 0x10000>,
++ <0x7e006000 0x1000>;
++ interrupts = <2 0>,
++ <1 9>;
++ status = "okay";
++ };
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/dwc2-overlay.dts
+@@ -0,0 +1,29 @@
++/dts-v1/;
++/plugin/;
++
++/{
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&usb>;
++ #address-cells = <1>;
++ #size-cells = <1>;
++ __overlay__ {
++ compatible = "brcm,bcm2835-usb";
++ reg = <0x7e980000 0x10000>;
++ interrupts = <1 9>;
++ dr_mode = "otg";
++ g-np-tx-fifo-size = <32>;
++ g-rx-fifo-size = <256>;
++ g-tx-fifo-size = <256 128 128 64 64 64 32>;
++ status = "okay";
++ };
++ };
++
++ __overrides__ {
++ dr_mode = <&usb>, "dr_mode";
++ g-np-tx-fifo-size = <&usb>,"g-np-tx-fifo-size:0";
++ g-rx-fifo-size = <&usb>,"g-rx-fifo-size:0";
++ g-tx-fifo-size = <&usb>,"g-tx-fifo-size:0";
++ };
++};
diff --git a/target/linux/brcm2708/patches-4.4/0123-BCM270X_DT-Add-the-sdtweak-overlay-for-tuning-sdhost.patch b/target/linux/brcm2708/patches-4.4/0123-BCM270X_DT-Add-the-sdtweak-overlay-for-tuning-sdhost.patch
new file mode 100644
index 0000000000..0d9689094f
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0123-BCM270X_DT-Add-the-sdtweak-overlay-for-tuning-sdhost.patch
@@ -0,0 +1,74 @@
+From e1d87aa570e5a036160f35d7b95f6a2c10f96bed Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 4 Jan 2016 14:42:17 +0000
+Subject: [PATCH 123/381] BCM270X_DT: Add the sdtweak overlay, for tuning
+ sdhost
+
+The sdhost overlay declares the sdhost interface and allows parameters
+to be set. This is overkill for situations where the user just wants to
+tweak the parameters of a pre-declared sdhost interface, so create an
+sdtweak overlay that does just that.
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 14 ++++++++++++++
+ arch/arm/boot/dts/overlays/sdtweak-overlay.dts | 21 +++++++++++++++++++++
+ 3 files changed, 36 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/sdtweak-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -53,6 +53,7 @@ dtb-$(RPI_DT_OVERLAYS) += rpi-proto-over
+ dtb-$(RPI_DT_OVERLAYS) += rpi-sense-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += sdhost-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += sdio-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += sdtweak-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += smi-dev-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += smi-nand-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += smi-overlay.dtb
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -635,6 +635,20 @@ Params: overclock_50 Clock (
+ (default on: polling once at boot-time)
+
+
++Name: sdtweak
++Info: Tunes the bcm2835-sdhost SD/MMC driver
++Load: dtoverlay=sdtweak,<param>=<val>
++Params: overclock_50 Clock (in MHz) to use when the MMC framework
++ requests 50MHz
++
++ force_pio Disable DMA support (default off)
++
++ pio_limit Number of blocks above which to use DMA
++ (default 1)
++
++ debug Enable debug output (default off)
++
++
+ Name: smi
+ Info: Enables the Secondary Memory Interface peripheral. Uses GPIOs 2-25!
+ Load: dtoverlay=smi
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/sdtweak-overlay.dts
+@@ -0,0 +1,21 @@
++/dts-v1/;
++/plugin/;
++
++/{
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&sdhost>;
++ frag1: __overlay__ {
++ brcm,overclock-50 = <0>;
++ brcm,pio-limit = <1>;
++ };
++ };
++
++ __overrides__ {
++ overclock_50 = <&frag1>,"brcm,overclock-50:0";
++ force_pio = <&frag1>,"brcm,force-pio?";
++ pio_limit = <&frag1>,"brcm,pio-limit:0";
++ debug = <&frag1>,"brcm,debug?";
++ };
++};
diff --git a/target/linux/brcm2708/patches-4.4/0123-bcm270x_dt-Add-dwc2-and-dwc-otg-overlays.patch b/target/linux/brcm2708/patches-4.4/0123-bcm270x_dt-Add-dwc2-and-dwc-otg-overlays.patch
deleted file mode 100644
index e4c8afa349..0000000000
--- a/target/linux/brcm2708/patches-4.4/0123-bcm270x_dt-Add-dwc2-and-dwc-otg-overlays.patch
+++ /dev/null
@@ -1,110 +0,0 @@
-From 62dca1937fc3acfe4b6471607b7a4d58c34e73b7 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
-Date: Thu, 31 Dec 2015 16:44:58 +0100
-Subject: [PATCH 123/170] bcm270x_dt: Add dwc2 and dwc-otg overlays
-
----
- arch/arm/boot/dts/overlays/Makefile | 2 ++
- arch/arm/boot/dts/overlays/README | 21 +++++++++++++++++++
- arch/arm/boot/dts/overlays/dwc-otg-overlay.dts | 20 ++++++++++++++++++
- arch/arm/boot/dts/overlays/dwc2-overlay.dts | 29 ++++++++++++++++++++++++++
- 4 files changed, 72 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/dwc-otg-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/dwc2-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -15,6 +15,8 @@ endif
- dtb-$(RPI_DT_OVERLAYS) += ads7846-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += at86rf233-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += bmp085_i2c-sensor-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += dwc2-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += dwc-otg-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += dht11-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += enc28j60-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += gpio-ir-overlay.dtb
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -198,6 +198,27 @@ Params: gpiopin GPIO co
- (default 4)
-
-
-+Name: dwc-otg
-+Info: Selects the dwc_otg USB controller driver which has fiq support. This
-+ is the default on all except the Pi Zero which defaults to dwc2.
-+Load: dtoverlay=dwc-otg
-+Params: <None>
-+
-+
-+Name: dwc2
-+Info: Selects the dwc2 USB controller driver
-+Load: dtoverlay=dwc2,<param>=<val>
-+Params: dr_mode Dual role mode: "host", "peripheral" or "otg"
-+
-+ g-rx-fifo-size Size of rx fifo size in gadget mode
-+
-+ g-np-tx-fifo-size Size of non-periodic tx fifo size in gadget
-+ mode
-+
-+ g-tx-fifo-size Size of periodic tx fifo per endpoint
-+ (except ep0) in gadget mode
-+
-+
- [ The ds1307-rtc overlay has been deleted. See i2c-rtc. ]
-
-
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/dwc-otg-overlay.dts
-@@ -0,0 +1,20 @@
-+/dts-v1/;
-+/plugin/;
-+
-+/{
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target = <&usb>;
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+ __overlay__ {
-+ compatible = "brcm,bcm2708-usb";
-+ reg = <0x7e980000 0x10000>,
-+ <0x7e006000 0x1000>;
-+ interrupts = <2 0>,
-+ <1 9>;
-+ status = "okay";
-+ };
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/dwc2-overlay.dts
-@@ -0,0 +1,29 @@
-+/dts-v1/;
-+/plugin/;
-+
-+/{
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target = <&usb>;
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+ __overlay__ {
-+ compatible = "brcm,bcm2835-usb";
-+ reg = <0x7e980000 0x10000>;
-+ interrupts = <1 9>;
-+ dr_mode = "otg";
-+ g-np-tx-fifo-size = <32>;
-+ g-rx-fifo-size = <256>;
-+ g-tx-fifo-size = <256 128 128 64 64 64 32>;
-+ status = "okay";
-+ };
-+ };
-+
-+ __overrides__ {
-+ dr_mode = <&usb>, "dr_mode";
-+ g-np-tx-fifo-size = <&usb>,"g-np-tx-fifo-size:0";
-+ g-rx-fifo-size = <&usb>,"g-rx-fifo-size:0";
-+ g-tx-fifo-size = <&usb>,"g-tx-fifo-size:0";
-+ };
-+};
diff --git a/target/linux/brcm2708/patches-4.4/0124-BCM270X_DT-Add-the-sdtweak-overlay-for-tuning-sdhost.patch b/target/linux/brcm2708/patches-4.4/0124-BCM270X_DT-Add-the-sdtweak-overlay-for-tuning-sdhost.patch
deleted file mode 100644
index 584033d453..0000000000
--- a/target/linux/brcm2708/patches-4.4/0124-BCM270X_DT-Add-the-sdtweak-overlay-for-tuning-sdhost.patch
+++ /dev/null
@@ -1,74 +0,0 @@
-From 162dd00041afb2995f90a928ea80aeaa0d141ce5 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Mon, 4 Jan 2016 14:42:17 +0000
-Subject: [PATCH 124/170] BCM270X_DT: Add the sdtweak overlay, for tuning
- sdhost
-
-The sdhost overlay declares the sdhost interface and allows parameters
-to be set. This is overkill for situations where the user just wants to
-tweak the parameters of a pre-declared sdhost interface, so create an
-sdtweak overlay that does just that.
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 14 ++++++++++++++
- arch/arm/boot/dts/overlays/sdtweak-overlay.dts | 21 +++++++++++++++++++++
- 3 files changed, 36 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/sdtweak-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -53,6 +53,7 @@ dtb-$(RPI_DT_OVERLAYS) += rpi-proto-over
- dtb-$(RPI_DT_OVERLAYS) += rpi-sense-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += sdhost-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += sdio-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += sdtweak-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += smi-dev-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += smi-nand-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += smi-overlay.dtb
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -635,6 +635,20 @@ Params: overclock_50 Clock (
- (default on: polling once at boot-time)
-
-
-+Name: sdtweak
-+Info: Tunes the bcm2835-sdhost SD/MMC driver
-+Load: dtoverlay=sdtweak,<param>=<val>
-+Params: overclock_50 Clock (in MHz) to use when the MMC framework
-+ requests 50MHz
-+
-+ force_pio Disable DMA support (default off)
-+
-+ pio_limit Number of blocks above which to use DMA
-+ (default 1)
-+
-+ debug Enable debug output (default off)
-+
-+
- Name: smi
- Info: Enables the Secondary Memory Interface peripheral. Uses GPIOs 2-25!
- Load: dtoverlay=smi
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/sdtweak-overlay.dts
-@@ -0,0 +1,21 @@
-+/dts-v1/;
-+/plugin/;
-+
-+/{
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target = <&sdhost>;
-+ frag1: __overlay__ {
-+ brcm,overclock-50 = <0>;
-+ brcm,pio-limit = <1>;
-+ };
-+ };
-+
-+ __overrides__ {
-+ overclock_50 = <&frag1>,"brcm,overclock-50:0";
-+ force_pio = <&frag1>,"brcm,force-pio?";
-+ pio_limit = <&frag1>,"brcm,pio-limit:0";
-+ debug = <&frag1>,"brcm,debug?";
-+ };
-+};
diff --git a/target/linux/brcm2708/patches-4.4/0124-bcm2835-mmc-Don-t-override-bus-width-capabilities-fr.patch b/target/linux/brcm2708/patches-4.4/0124-bcm2835-mmc-Don-t-override-bus-width-capabilities-fr.patch
new file mode 100644
index 0000000000..891c389cf4
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0124-bcm2835-mmc-Don-t-override-bus-width-capabilities-fr.patch
@@ -0,0 +1,24 @@
+From a41f23a2a756f274f1ddc67d6cccc36fa4624f88 Mon Sep 17 00:00:00 2001
+From: Andrew Litt <ajlitt@splunge.net>
+Date: Mon, 11 Jan 2016 07:54:21 +0000
+Subject: [PATCH 124/381] bcm2835-mmc: Don't override bus width capabilities
+ from devicetree
+
+Take out the force setting of the MMC_CAP_4_BIT_DATA host capability
+so that the result read from devicetree via mmc_of_parse() is
+preserved.
+---
+ drivers/mmc/host/bcm2835-mmc.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/mmc/host/bcm2835-mmc.c
++++ b/drivers/mmc/host/bcm2835-mmc.c
+@@ -1305,7 +1305,7 @@ static int bcm2835_mmc_add_host(struct b
+ /* host controller capabilities */
+ mmc->caps |= MMC_CAP_CMD23 | MMC_CAP_ERASE | MMC_CAP_NEEDS_POLL |
+ MMC_CAP_SDIO_IRQ | MMC_CAP_SD_HIGHSPEED |
+- MMC_CAP_MMC_HIGHSPEED | MMC_CAP_4_BIT_DATA;
++ MMC_CAP_MMC_HIGHSPEED;
+
+ mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
+
diff --git a/target/linux/brcm2708/patches-4.4/0125-SDIO-overlay-add-bus_width-parameter.patch b/target/linux/brcm2708/patches-4.4/0125-SDIO-overlay-add-bus_width-parameter.patch
new file mode 100644
index 0000000000..025006a3f9
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0125-SDIO-overlay-add-bus_width-parameter.patch
@@ -0,0 +1,42 @@
+From 4ea24183d081b6bf9d6a89de906543719b82ed54 Mon Sep 17 00:00:00 2001
+From: Andrew Litt <ajlitt@splunge.net>
+Date: Mon, 11 Jan 2016 07:55:54 +0000
+Subject: [PATCH 125/381] SDIO-overlay: add bus_width parameter
+
+Allow setting of the SDIO bus width capability of the bcm2835-mmc
+host. This is helpful when only a 1 bit wide bus is connected
+between host and device but both host and device advertise 4 bit
+mode.
+---
+ arch/arm/boot/dts/overlays/README | 2 ++
+ arch/arm/boot/dts/overlays/sdio-overlay.dts | 2 ++
+ 2 files changed, 4 insertions(+)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -634,6 +634,8 @@ Params: overclock_50 Clock (
+ poll_once Disable SDIO-device polling every second
+ (default on: polling once at boot-time)
+
++ bus_width Set the SDIO host bus width (default 4 bits)
++
+
+ Name: sdtweak
+ Info: Tunes the bcm2835-sdhost SD/MMC driver
+--- a/arch/arm/boot/dts/overlays/sdio-overlay.dts
++++ b/arch/arm/boot/dts/overlays/sdio-overlay.dts
+@@ -11,6 +11,7 @@
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdio_pins>;
+ non-removable;
++ bus-width = <4>;
+ status = "okay";
+ };
+ };
+@@ -28,5 +29,6 @@
+
+ __overrides__ {
+ poll_once = <&sdio_mmc>,"non-removable?";
++ bus_width = <&sdio_mmc>,"bus-width:0";
+ };
+ };
diff --git a/target/linux/brcm2708/patches-4.4/0125-bcm2835-mmc-Don-t-override-bus-width-capabilities-fr.patch b/target/linux/brcm2708/patches-4.4/0125-bcm2835-mmc-Don-t-override-bus-width-capabilities-fr.patch
deleted file mode 100644
index 0413ece4ce..0000000000
--- a/target/linux/brcm2708/patches-4.4/0125-bcm2835-mmc-Don-t-override-bus-width-capabilities-fr.patch
+++ /dev/null
@@ -1,24 +0,0 @@
-From b07c427a7732a0fabcf521085e0fd61b0ef9047c Mon Sep 17 00:00:00 2001
-From: Andrew Litt <ajlitt@splunge.net>
-Date: Mon, 11 Jan 2016 07:54:21 +0000
-Subject: [PATCH 125/170] bcm2835-mmc: Don't override bus width capabilities
- from devicetree
-
-Take out the force setting of the MMC_CAP_4_BIT_DATA host capability
-so that the result read from devicetree via mmc_of_parse() is
-preserved.
----
- drivers/mmc/host/bcm2835-mmc.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/mmc/host/bcm2835-mmc.c
-+++ b/drivers/mmc/host/bcm2835-mmc.c
-@@ -1305,7 +1305,7 @@ static int bcm2835_mmc_add_host(struct b
- /* host controller capabilities */
- mmc->caps |= MMC_CAP_CMD23 | MMC_CAP_ERASE | MMC_CAP_NEEDS_POLL |
- MMC_CAP_SDIO_IRQ | MMC_CAP_SD_HIGHSPEED |
-- MMC_CAP_MMC_HIGHSPEED | MMC_CAP_4_BIT_DATA;
-+ MMC_CAP_MMC_HIGHSPEED;
-
- mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
-
diff --git a/target/linux/brcm2708/patches-4.4/0126-SDIO-overlay-add-bus_width-parameter.patch b/target/linux/brcm2708/patches-4.4/0126-SDIO-overlay-add-bus_width-parameter.patch
deleted file mode 100644
index 0dcf03e3e5..0000000000
--- a/target/linux/brcm2708/patches-4.4/0126-SDIO-overlay-add-bus_width-parameter.patch
+++ /dev/null
@@ -1,42 +0,0 @@
-From f74652d026105ecc4a87b581a9c1c89a6e504d2c Mon Sep 17 00:00:00 2001
-From: Andrew Litt <ajlitt@splunge.net>
-Date: Mon, 11 Jan 2016 07:55:54 +0000
-Subject: [PATCH 126/170] SDIO-overlay: add bus_width parameter
-
-Allow setting of the SDIO bus width capability of the bcm2835-mmc
-host. This is helpful when only a 1 bit wide bus is connected
-between host and device but both host and device advertise 4 bit
-mode.
----
- arch/arm/boot/dts/overlays/README | 2 ++
- arch/arm/boot/dts/overlays/sdio-overlay.dts | 2 ++
- 2 files changed, 4 insertions(+)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -634,6 +634,8 @@ Params: overclock_50 Clock (
- poll_once Disable SDIO-device polling every second
- (default on: polling once at boot-time)
-
-+ bus_width Set the SDIO host bus width (default 4 bits)
-+
-
- Name: sdtweak
- Info: Tunes the bcm2835-sdhost SD/MMC driver
---- a/arch/arm/boot/dts/overlays/sdio-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/sdio-overlay.dts
-@@ -11,6 +11,7 @@
- pinctrl-names = "default";
- pinctrl-0 = <&sdio_pins>;
- non-removable;
-+ bus-width = <4>;
- status = "okay";
- };
- };
-@@ -28,5 +29,6 @@
-
- __overrides__ {
- poll_once = <&sdio_mmc>,"non-removable?";
-+ bus_width = <&sdio_mmc>,"bus-width:0";
- };
- };
diff --git a/target/linux/brcm2708/patches-4.4/0126-bcm2835-extend-allowed-range-of-channels-and-sampler.patch b/target/linux/brcm2708/patches-4.4/0126-bcm2835-extend-allowed-range-of-channels-and-sampler.patch
new file mode 100644
index 0000000000..966d092db2
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0126-bcm2835-extend-allowed-range-of-channels-and-sampler.patch
@@ -0,0 +1,37 @@
+From 807249934e7f9453ba64a5724daecf9f61f42e07 Mon Sep 17 00:00:00 2001
+From: wm4 <wm4@nowhere>
+Date: Wed, 13 Jan 2016 19:41:45 +0100
+Subject: [PATCH 126/381] bcm2835: extend allowed range of channels and
+ samplerates
+
+Allow everything the videocore accepts.
+---
+ sound/arm/bcm2835-pcm.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/sound/arm/bcm2835-pcm.c
++++ b/sound/arm/bcm2835-pcm.c
+@@ -26,9 +26,9 @@ static struct snd_pcm_hardware snd_bcm28
+ .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
+ .rate_min = 8000,
+- .rate_max = 48000,
++ .rate_max = 192000,
+ .channels_min = 1,
+- .channels_max = 2,
++ .channels_max = 8,
+ .buffer_bytes_max = 128 * 1024,
+ .period_bytes_min = 1 * 1024,
+ .period_bytes_max = 128 * 1024,
+@@ -43,9 +43,9 @@ static struct snd_pcm_hardware snd_bcm28
+ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000,
+ .rate_min = 44100,
+- .rate_max = 48000,
++ .rate_max = 192000,
+ .channels_min = 2,
+- .channels_max = 2,
++ .channels_max = 8,
+ .buffer_bytes_max = 128 * 1024,
+ .period_bytes_min = 1 * 1024,
+ .period_bytes_max = 128 * 1024,
diff --git a/target/linux/brcm2708/patches-4.4/0127-FIXUP-BCM270X_DT-random-HWRNG-dtparam-default-is-on.patch b/target/linux/brcm2708/patches-4.4/0127-FIXUP-BCM270X_DT-random-HWRNG-dtparam-default-is-on.patch
deleted file mode 100644
index 86f381cf1f..0000000000
--- a/target/linux/brcm2708/patches-4.4/0127-FIXUP-BCM270X_DT-random-HWRNG-dtparam-default-is-on.patch
+++ /dev/null
@@ -1,21 +0,0 @@
-From 232754cb0ecd1967a8b72d6bd05467843d65a441 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Fri, 8 Jan 2016 13:42:06 +0000
-Subject: [PATCH 127/170] FIXUP BCM270X_DT: "random" (HWRNG) dtparam default is
- on
-
----
- arch/arm/boot/dts/overlays/README | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -110,7 +110,7 @@ Params:
- (default "off")
-
- random Set to "on" to enable the hardware random
-- number generator (default "off")
-+ number generator (default "on")
-
- uart0 Set to "off" to disable uart0 (default "on")
-
diff --git a/target/linux/brcm2708/patches-4.4/0127-bcm2835-restrict-channels-rate-to-8-960000.patch b/target/linux/brcm2708/patches-4.4/0127-bcm2835-restrict-channels-rate-to-8-960000.patch
new file mode 100644
index 0000000000..28300233d8
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0127-bcm2835-restrict-channels-rate-to-8-960000.patch
@@ -0,0 +1,80 @@
+From 8148bc7d4147c2197d13425686a56b7c40c78157 Mon Sep 17 00:00:00 2001
+From: wm4 <wm4@nowhere>
+Date: Wed, 13 Jan 2016 19:42:18 +0100
+Subject: [PATCH 127/381] bcm2835: restrict channels*rate to 8*960000
+
+This is required at least for SPDIF. If the bitrate goes above,
+videocore will either resample the audio or corrupt it due to
+underruns. Supposedly the hardware isn't designed to output
+higher rates, but it can still resample it down to supported
+rates.
+
+Some code is based on ac97_pcm.c.
+---
+ sound/arm/bcm2835-pcm.c | 41 +++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 41 insertions(+)
+
+--- a/sound/arm/bcm2835-pcm.c
++++ b/sound/arm/bcm2835-pcm.c
+@@ -19,6 +19,9 @@
+
+ #include "bcm2835.h"
+
++/* The hardware can not do much more num_channels*samplerate then this value */
++#define MAX_COMBINED_RATE 768000
++
+ /* hardware definition */
+ static struct snd_pcm_hardware snd_bcm2835_playback_hw = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+@@ -107,6 +110,31 @@ static irqreturn_t bcm2835_playback_fifo
+ return IRQ_HANDLED;
+ }
+
++
++static int rate_hw_constraint_rate(struct snd_pcm_hw_params *params,
++ struct snd_pcm_hw_rule *rule)
++{
++ struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
++ struct snd_interval rates = {
++ .min = 8000,
++ .max = min(192000u, MAX_COMBINED_RATE / max(channels->min, 1u)),
++ };
++ struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
++ return snd_interval_refine(rate, &rates);
++}
++
++static int rate_hw_constraint_channels(struct snd_pcm_hw_params *params,
++ struct snd_pcm_hw_rule *rule)
++{
++ struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
++ struct snd_interval channels_interval = {
++ .min = 1,
++ .max = min(8u, MAX_COMBINED_RATE / max(rate->min, 1u)),
++ };
++ struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
++ return snd_interval_refine(channels, &channels_interval);
++}
++
+ /* open callback */
+ static int snd_bcm2835_playback_open_generic(
+ struct snd_pcm_substream *substream, int spdif)
+@@ -188,6 +216,19 @@ static int snd_bcm2835_playback_open_gen
+ snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+ 16);
+
++ /* When playing PCM, pretend that we support the full range of channels
++ * and sample rates. The GPU can't output it, but is able to resample
++ * the data to a rate the hardware can handle it. This won't work with
++ * compressed data; the resampler would just destroy it. */
++ if (spdif) {
++ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
++ rate_hw_constraint_rate, NULL,
++ SNDRV_PCM_HW_PARAM_CHANNELS, -1);
++ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
++ rate_hw_constraint_channels, NULL,
++ SNDRV_PCM_HW_PARAM_RATE, -1);
++ }
++
+ chip->alsa_stream[idx] = alsa_stream;
+
+ chip->opened |= (1 << idx);
diff --git a/target/linux/brcm2708/patches-4.4/0128-bcm2835-extend-allowed-range-of-channels-and-sampler.patch b/target/linux/brcm2708/patches-4.4/0128-bcm2835-extend-allowed-range-of-channels-and-sampler.patch
deleted file mode 100644
index 5fc9c99529..0000000000
--- a/target/linux/brcm2708/patches-4.4/0128-bcm2835-extend-allowed-range-of-channels-and-sampler.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-From 320bdec200197f074541e3999fa4b87889c5eb18 Mon Sep 17 00:00:00 2001
-From: wm4 <wm4@nowhere>
-Date: Wed, 13 Jan 2016 19:41:45 +0100
-Subject: [PATCH 128/170] bcm2835: extend allowed range of channels and
- samplerates
-
-Allow everything the videocore accepts.
----
- sound/arm/bcm2835-pcm.c | 8 ++++----
- 1 file changed, 4 insertions(+), 4 deletions(-)
-
---- a/sound/arm/bcm2835-pcm.c
-+++ b/sound/arm/bcm2835-pcm.c
-@@ -26,9 +26,9 @@ static struct snd_pcm_hardware snd_bcm28
- .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
- .rate_min = 8000,
-- .rate_max = 48000,
-+ .rate_max = 192000,
- .channels_min = 1,
-- .channels_max = 2,
-+ .channels_max = 8,
- .buffer_bytes_max = 128 * 1024,
- .period_bytes_min = 1 * 1024,
- .period_bytes_max = 128 * 1024,
-@@ -43,9 +43,9 @@ static struct snd_pcm_hardware snd_bcm28
- .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_44100 |
- SNDRV_PCM_RATE_48000,
- .rate_min = 44100,
-- .rate_max = 48000,
-+ .rate_max = 192000,
- .channels_min = 2,
-- .channels_max = 2,
-+ .channels_max = 8,
- .buffer_bytes_max = 128 * 1024,
- .period_bytes_min = 1 * 1024,
- .period_bytes_max = 128 * 1024,
diff --git a/target/linux/brcm2708/patches-4.4/0128-rpi-update-vc_vchi_audioserv_defs.h.patch b/target/linux/brcm2708/patches-4.4/0128-rpi-update-vc_vchi_audioserv_defs.h.patch
new file mode 100644
index 0000000000..1841afab46
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0128-rpi-update-vc_vchi_audioserv_defs.h.patch
@@ -0,0 +1,66 @@
+From cd33640409eb73b99703273192971e0ea874652f Mon Sep 17 00:00:00 2001
+From: wm4 <wm4@nowhere>
+Date: Wed, 13 Jan 2016 19:42:48 +0100
+Subject: [PATCH 128/381] rpi: update vc_vchi_audioserv_defs.h
+
+Add audioserv 3 extensions. The changes were taken from the paste
+linked here:
+
+https://github.com/raspberrypi/linux/pull/1166#issuecomment-151917067
+---
+ sound/arm/vc_vchi_audioserv_defs.h | 13 +++++++++++--
+ 1 file changed, 11 insertions(+), 2 deletions(-)
+
+--- a/sound/arm/vc_vchi_audioserv_defs.h
++++ b/sound/arm/vc_vchi_audioserv_defs.h
+@@ -16,7 +16,7 @@
+ #define _VC_AUDIO_DEFS_H_
+
+ #define VC_AUDIOSERV_MIN_VER 1
+-#define VC_AUDIOSERV_VER 2
++#define VC_AUDIOSERV_VER 3
+
+ // FourCC code used for VCHI connection
+ #define VC_AUDIO_SERVER_NAME MAKE_FOURCC("AUDS")
+@@ -36,6 +36,7 @@ typedef enum {
+ VC_AUDIO_MSG_TYPE_START, // Configure audio
+ VC_AUDIO_MSG_TYPE_STOP, // Configure audio
+ VC_AUDIO_MSG_TYPE_WRITE, // Configure audio
++ VC_AUDIO_MSG_TYPE_LATENCY, // request latency in cycles
+ VC_AUDIO_MSG_TYPE_MAX
+ } VC_AUDIO_MSG_TYPE;
+
+@@ -44,6 +45,7 @@ typedef struct {
+ uint32_t channels;
+ uint32_t samplerate;
+ uint32_t bps;
++ uint32_t channelmap;
+
+ } VC_AUDIO_CONFIG_T;
+
+@@ -84,6 +86,12 @@ typedef struct {
+ uint16_t max_packet;
+ } VC_AUDIO_WRITE_T;
+
++// query latency in samples of sink
++typedef struct
++{
++ uint32_t dummy;
++} VC_AUDIO_LATENCY_T;
++
+ // Generic result for a request (VC->HOST)
+ typedef struct {
+ int32_t success; // Success value
+@@ -108,9 +116,10 @@ typedef struct {
+ VC_AUDIO_START_T start;
+ VC_AUDIO_STOP_T stop;
+ VC_AUDIO_WRITE_T write;
++ VC_AUDIO_LATENCY_T latency;
+ VC_AUDIO_RESULT_T result;
+ VC_AUDIO_COMPLETE_T complete;
+ } u;
+ } VC_AUDIO_MSG_T;
+
+-#endif // _VC_AUDIO_DEFS_H_
++#endif // _VC_AUDIO_DEFS_H_
+\ No newline at end of file
diff --git a/target/linux/brcm2708/patches-4.4/0129-bcm2835-implement-channel-map-API.patch b/target/linux/brcm2708/patches-4.4/0129-bcm2835-implement-channel-map-API.patch
new file mode 100644
index 0000000000..3b19baa473
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0129-bcm2835-implement-channel-map-API.patch
@@ -0,0 +1,421 @@
+From a6dd2b7d0cf90158755da4949006feebde8c9fe5 Mon Sep 17 00:00:00 2001
+From: wm4 <wm4@nowhere>
+Date: Wed, 13 Jan 2016 19:43:12 +0100
+Subject: [PATCH 129/381] bcm2835: implement channel map API
+
+Report all layouts supported by the HDMI protocol to userspace.
+Make the videocore set the correct layout according to the
+userspace request.
+
+Some code taken from patch_hdmi.c. In particular, the HDMI channel
+layout table was copied without changes - with the idea in mind that
+hopefully it can be shared one day. Or at least updating it will be
+simpler.
+
+In my tests, everything appears to work, except when outputting
+FL FR RL RR. Then my receiver outputs RL on both the RL and RR
+speakers, while RR is never heard.
+---
+ sound/arm/bcm2835-ctl.c | 276 ++++++++++++++++++++++++++++++++++++++++++++++
+ sound/arm/bcm2835-pcm.c | 22 +++-
+ sound/arm/bcm2835-vchiq.c | 13 +++
+ sound/arm/bcm2835.h | 4 +
+ 4 files changed, 311 insertions(+), 4 deletions(-)
+
+--- a/sound/arm/bcm2835-ctl.c
++++ b/sound/arm/bcm2835-ctl.c
+@@ -300,6 +300,281 @@ static struct snd_kcontrol_new snd_bcm28
+ },
+ };
+
++struct cea_channel_speaker_allocation {
++ int ca_index;
++ int speakers[8];
++};
++
++#define FL SNDRV_CHMAP_FL
++#define FR SNDRV_CHMAP_FR
++#define RL SNDRV_CHMAP_RL
++#define RR SNDRV_CHMAP_RR
++#define LFE SNDRV_CHMAP_LFE
++#define FC SNDRV_CHMAP_FC
++#define RLC SNDRV_CHMAP_RLC
++#define RRC SNDRV_CHMAP_RRC
++#define RC SNDRV_CHMAP_RC
++#define FLC SNDRV_CHMAP_FLC
++#define FRC SNDRV_CHMAP_FRC
++#define FLH SNDRV_CHMAP_TFL
++#define FRH SNDRV_CHMAP_TFR
++#define FLW SNDRV_CHMAP_FLW
++#define FRW SNDRV_CHMAP_FRW
++#define TC SNDRV_CHMAP_TC
++#define FCH SNDRV_CHMAP_TFC
++
++/*
++ * CEA-861 channel maps
++ *
++ * Stolen from sound/pci/hda/patch_hdmi.c
++ * (unlike the source, this uses SNDRV_* constants directly, as by the
++ * map_tables array in patch_hdmi.c)
++ * Unknown entries use 0, which unfortunately is SNDRV_CHMAP_UNKNOWN instead
++ * of SNDRV_CHMAP_NA.
++ */
++static struct cea_channel_speaker_allocation channel_allocations[] = {
++/* channel: 7 6 5 4 3 2 1 0 */
++{ .ca_index = 0x00, .speakers = { 0, 0, 0, 0, 0, 0, FR, FL } },
++ /* 2.1 */
++{ .ca_index = 0x01, .speakers = { 0, 0, 0, 0, 0, LFE, FR, FL } },
++ /* Dolby Surround */
++{ .ca_index = 0x02, .speakers = { 0, 0, 0, 0, FC, 0, FR, FL } },
++ /* surround40 */
++{ .ca_index = 0x08, .speakers = { 0, 0, RR, RL, 0, 0, FR, FL } },
++ /* surround41 */
++{ .ca_index = 0x09, .speakers = { 0, 0, RR, RL, 0, LFE, FR, FL } },
++ /* surround50 */
++{ .ca_index = 0x0a, .speakers = { 0, 0, RR, RL, FC, 0, FR, FL } },
++ /* surround51 */
++{ .ca_index = 0x0b, .speakers = { 0, 0, RR, RL, FC, LFE, FR, FL } },
++ /* 6.1 */
++{ .ca_index = 0x0f, .speakers = { 0, RC, RR, RL, FC, LFE, FR, FL } },
++ /* surround71 */
++{ .ca_index = 0x13, .speakers = { RRC, RLC, RR, RL, FC, LFE, FR, FL } },
++
++{ .ca_index = 0x03, .speakers = { 0, 0, 0, 0, FC, LFE, FR, FL } },
++{ .ca_index = 0x04, .speakers = { 0, 0, 0, RC, 0, 0, FR, FL } },
++{ .ca_index = 0x05, .speakers = { 0, 0, 0, RC, 0, LFE, FR, FL } },
++{ .ca_index = 0x06, .speakers = { 0, 0, 0, RC, FC, 0, FR, FL } },
++{ .ca_index = 0x07, .speakers = { 0, 0, 0, RC, FC, LFE, FR, FL } },
++{ .ca_index = 0x0c, .speakers = { 0, RC, RR, RL, 0, 0, FR, FL } },
++{ .ca_index = 0x0d, .speakers = { 0, RC, RR, RL, 0, LFE, FR, FL } },
++{ .ca_index = 0x0e, .speakers = { 0, RC, RR, RL, FC, 0, FR, FL } },
++{ .ca_index = 0x10, .speakers = { RRC, RLC, RR, RL, 0, 0, FR, FL } },
++{ .ca_index = 0x11, .speakers = { RRC, RLC, RR, RL, 0, LFE, FR, FL } },
++{ .ca_index = 0x12, .speakers = { RRC, RLC, RR, RL, FC, 0, FR, FL } },
++{ .ca_index = 0x14, .speakers = { FRC, FLC, 0, 0, 0, 0, FR, FL } },
++{ .ca_index = 0x15, .speakers = { FRC, FLC, 0, 0, 0, LFE, FR, FL } },
++{ .ca_index = 0x16, .speakers = { FRC, FLC, 0, 0, FC, 0, FR, FL } },
++{ .ca_index = 0x17, .speakers = { FRC, FLC, 0, 0, FC, LFE, FR, FL } },
++{ .ca_index = 0x18, .speakers = { FRC, FLC, 0, RC, 0, 0, FR, FL } },
++{ .ca_index = 0x19, .speakers = { FRC, FLC, 0, RC, 0, LFE, FR, FL } },
++{ .ca_index = 0x1a, .speakers = { FRC, FLC, 0, RC, FC, 0, FR, FL } },
++{ .ca_index = 0x1b, .speakers = { FRC, FLC, 0, RC, FC, LFE, FR, FL } },
++{ .ca_index = 0x1c, .speakers = { FRC, FLC, RR, RL, 0, 0, FR, FL } },
++{ .ca_index = 0x1d, .speakers = { FRC, FLC, RR, RL, 0, LFE, FR, FL } },
++{ .ca_index = 0x1e, .speakers = { FRC, FLC, RR, RL, FC, 0, FR, FL } },
++{ .ca_index = 0x1f, .speakers = { FRC, FLC, RR, RL, FC, LFE, FR, FL } },
++{ .ca_index = 0x20, .speakers = { 0, FCH, RR, RL, FC, 0, FR, FL } },
++{ .ca_index = 0x21, .speakers = { 0, FCH, RR, RL, FC, LFE, FR, FL } },
++{ .ca_index = 0x22, .speakers = { TC, 0, RR, RL, FC, 0, FR, FL } },
++{ .ca_index = 0x23, .speakers = { TC, 0, RR, RL, FC, LFE, FR, FL } },
++{ .ca_index = 0x24, .speakers = { FRH, FLH, RR, RL, 0, 0, FR, FL } },
++{ .ca_index = 0x25, .speakers = { FRH, FLH, RR, RL, 0, LFE, FR, FL } },
++{ .ca_index = 0x26, .speakers = { FRW, FLW, RR, RL, 0, 0, FR, FL } },
++{ .ca_index = 0x27, .speakers = { FRW, FLW, RR, RL, 0, LFE, FR, FL } },
++{ .ca_index = 0x28, .speakers = { TC, RC, RR, RL, FC, 0, FR, FL } },
++{ .ca_index = 0x29, .speakers = { TC, RC, RR, RL, FC, LFE, FR, FL } },
++{ .ca_index = 0x2a, .speakers = { FCH, RC, RR, RL, FC, 0, FR, FL } },
++{ .ca_index = 0x2b, .speakers = { FCH, RC, RR, RL, FC, LFE, FR, FL } },
++{ .ca_index = 0x2c, .speakers = { TC, FCH, RR, RL, FC, 0, FR, FL } },
++{ .ca_index = 0x2d, .speakers = { TC, FCH, RR, RL, FC, LFE, FR, FL } },
++{ .ca_index = 0x2e, .speakers = { FRH, FLH, RR, RL, FC, 0, FR, FL } },
++{ .ca_index = 0x2f, .speakers = { FRH, FLH, RR, RL, FC, LFE, FR, FL } },
++{ .ca_index = 0x30, .speakers = { FRW, FLW, RR, RL, FC, 0, FR, FL } },
++{ .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } },
++};
++
++static int snd_bcm2835_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag,
++ unsigned int size, unsigned int __user *tlv)
++{
++ unsigned int __user *dst;
++ int count = 0;
++ int i;
++
++ if (size < 8)
++ return -ENOMEM;
++ if (put_user(SNDRV_CTL_TLVT_CONTAINER, tlv))
++ return -EFAULT;
++ size -= 8;
++ dst = tlv + 2;
++ for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
++ struct cea_channel_speaker_allocation *ch = &channel_allocations[i];
++ int num_chs = 0;
++ int chs_bytes;
++ int c;
++
++ for (c = 0; c < 8; c++) {
++ if (ch->speakers[c])
++ num_chs++;
++ }
++
++ chs_bytes = num_chs * 4;
++ if (size < 8)
++ return -ENOMEM;
++ if (put_user(SNDRV_CTL_TLVT_CHMAP_FIXED, dst) ||
++ put_user(chs_bytes, dst + 1))
++ return -EFAULT;
++ dst += 2;
++ size -= 8;
++ count += 8;
++ if (size < chs_bytes)
++ return -ENOMEM;
++ size -= chs_bytes;
++ count += chs_bytes;
++ for (c = 0; c < 8; c++) {
++ int sp = ch->speakers[7 - c];
++ if (sp) {
++ if (put_user(sp, dst))
++ return -EFAULT;
++ dst++;
++ }
++ }
++ }
++ if (put_user(count, tlv + 1))
++ return -EFAULT;
++ return 0;
++}
++
++static int snd_bcm2835_chmap_ctl_get(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
++ bcm2835_chip_t *chip = info->private_data;
++ unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
++ struct snd_pcm_substream *substream = snd_pcm_chmap_substream(info, idx);
++ struct cea_channel_speaker_allocation *ch = NULL;
++ int cur = 0;
++ int i;
++
++ if (!substream || !substream->runtime)
++ return -ENODEV;
++
++ for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
++ if (channel_allocations[i].ca_index == chip->cea_chmap)
++ ch = &channel_allocations[i];
++ }
++
++ /* If no layout was set yet, return a dummy. Apparently the userspace
++ * API will be confused if we don't. */
++ if (!ch)
++ ch = &channel_allocations[0];
++
++ for (i = 0; i < 8; i++) {
++ if (ch->speakers[7 - i])
++ ucontrol->value.integer.value[cur++] = ch->speakers[7 - i];
++ }
++ while (cur < 8)
++ ucontrol->value.integer.value[cur++] = SNDRV_CHMAP_NA;
++ return 0;
++}
++
++static int snd_bcm2835_chmap_ctl_put(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
++ bcm2835_chip_t *chip = info->private_data;
++ unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
++ struct snd_pcm_substream *substream = snd_pcm_chmap_substream(info, idx);
++ int i, prepared = 0, cea_chmap = -1;
++ int remap[8];
++
++ if (!substream || !substream->runtime)
++ return -ENODEV;
++
++ switch (substream->runtime->status->state) {
++ case SNDRV_PCM_STATE_OPEN:
++ case SNDRV_PCM_STATE_SETUP:
++ break;
++ case SNDRV_PCM_STATE_PREPARED:
++ prepared = 1;
++ break;
++ default:
++ return -EBUSY;
++ }
++
++ for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
++ struct cea_channel_speaker_allocation *ch = &channel_allocations[i];
++ int matches = 1;
++ int cur = 0;
++ int x;
++ memset(remap, 0, sizeof(remap));
++ for (x = 0; x < substream->runtime->channels; x++) {
++ int sp = ucontrol->value.integer.value[x];
++ while (cur < 8 && !ch->speakers[7 - cur])
++ cur++;
++ if (cur >= 8) {
++ /* user has more channels than ch */
++ matches = 0;
++ break;
++ }
++ if (ch->speakers[7 - cur] != sp) {
++ matches = 0;
++ break;
++ }
++ remap[x] = cur;
++ cur++;
++ }
++ for (x = cur; x < 8; x++) {
++ if (ch->speakers[7 - x]) {
++ /* ch has more channels than user */
++ matches = 0;
++ break;
++ }
++ }
++ if (matches) {
++ cea_chmap = ch->ca_index;
++ break;
++ }
++ }
++
++ if (cea_chmap < 0)
++ return -EINVAL;
++
++ /* don't change the layout if another substream is active */
++ if (chip->opened != (1 << substream->number) && chip->cea_chmap != cea_chmap)
++ return -EBUSY; /* unsure whether this is a good error code */
++
++ chip->cea_chmap = cea_chmap;
++ for (i = 0; i < 8; i++)
++ chip->map_channels[i] = remap[i];
++ if (prepared)
++ snd_bcm2835_pcm_prepare_again(substream);
++ return 0;
++}
++
++static int snd_bcm2835_add_chmap_ctl(bcm2835_chip_t * chip)
++{
++ struct snd_pcm_chmap *chmap;
++ struct snd_kcontrol *kctl;
++ int err, i;
++
++ err = snd_pcm_add_chmap_ctls(chip->pcm,
++ SNDRV_PCM_STREAM_PLAYBACK,
++ NULL, 8, 0, &chmap);
++ if (err < 0)
++ return err;
++ /* override handlers */
++ chmap->private_data = chip;
++ kctl = chmap->kctl;
++ for (i = 0; i < kctl->count; i++)
++ kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
++ kctl->get = snd_bcm2835_chmap_ctl_get;
++ kctl->put = snd_bcm2835_chmap_ctl_put;
++ kctl->tlv.c = snd_bcm2835_chmap_ctl_tlv;
++ return 0;
++}
++
+ int snd_bcm2835_new_ctl(bcm2835_chip_t * chip)
+ {
+ int err;
+@@ -313,6 +588,7 @@ int snd_bcm2835_new_ctl(bcm2835_chip_t *
+ if (err < 0)
+ return err;
+ }
++ snd_bcm2835_add_chmap_ctl(chip);
+ for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_spdif); idx++) {
+ err = snd_ctl_add(chip->card,
+ snd_ctl_new1(&snd_bcm2835_spdif[idx], chip));
+--- a/sound/arm/bcm2835-pcm.c
++++ b/sound/arm/bcm2835-pcm.c
+@@ -231,6 +231,9 @@ static int snd_bcm2835_playback_open_gen
+
+ chip->alsa_stream[idx] = alsa_stream;
+
++ if (!chip->opened)
++ chip->cea_chmap = -1;
++
+ chip->opened |= (1 << idx);
+ alsa_stream->open = 1;
+ alsa_stream->draining = 1;
+@@ -341,8 +344,7 @@ static int snd_bcm2835_pcm_hw_free(struc
+ return snd_pcm_lib_free_pages(substream);
+ }
+
+-/* prepare callback */
+-static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
++int snd_bcm2835_pcm_prepare_again(struct snd_pcm_substream *substream)
+ {
+ bcm2835_chip_t *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+@@ -350,8 +352,6 @@ static int snd_bcm2835_pcm_prepare(struc
+ int channels;
+ int err;
+
+- audio_info(" .. IN\n");
+-
+ /* notify the vchiq that it should enter spdif passthrough mode by
+ * setting channels=0 (see
+ * https://github.com/raspberrypi/linux/issues/528) */
+@@ -367,6 +367,20 @@ static int snd_bcm2835_pcm_prepare(struc
+ audio_error(" error setting hw params\n");
+ }
+
++ return err;
++}
++
++/* prepare callback */
++static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
++{
++ bcm2835_chip_t *chip = snd_pcm_substream_chip(substream);
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
++
++ audio_info(" .. IN\n");
++
++ snd_bcm2835_pcm_prepare_again(substream);
++
+ bcm2835_audio_setup(alsa_stream);
+
+ /* in preparation of the stream, set the controls (volume level) of the stream */
+--- a/sound/arm/bcm2835-vchiq.c
++++ b/sound/arm/bcm2835-vchiq.c
+@@ -570,6 +570,8 @@ int bcm2835_audio_set_params(bcm2835_als
+ VC_AUDIO_MSG_T m;
+ AUDIO_INSTANCE_T *instance = alsa_stream->instance;
+ int32_t success;
++ uint32_t chmap_value;
++ int i;
+ int ret;
+ LOG_DBG(" .. IN\n");
+
+@@ -593,10 +595,21 @@ int bcm2835_audio_set_params(bcm2835_als
+
+ instance->result = -1;
+
++ if (alsa_stream->chip->cea_chmap >= 0) {
++ chmap_value = (unsigned)alsa_stream->chip->cea_chmap << 24;
++ } else {
++ chmap_value = 0; /* force stereo */
++ for (i = 0; i < 8; i++)
++ alsa_stream->chip->map_channels[i] = i;
++ }
++ for (i = 0; i < 8; i++)
++ chmap_value |= alsa_stream->chip->map_channels[i] << (i * 3);
++
+ m.type = VC_AUDIO_MSG_TYPE_CONFIG;
+ m.u.config.channels = channels;
+ m.u.config.samplerate = samplerate;
+ m.u.config.bps = bps;
++ m.u.config.channelmap = chmap_value;
+
+ /* Create the message available completion */
+ init_completion(&instance->msg_avail_comp);
+--- a/sound/arm/bcm2835.h
++++ b/sound/arm/bcm2835.h
+@@ -107,6 +107,8 @@ typedef struct bcm2835_chip {
+ int old_volume; /* stores the volume value whist muted */
+ int dest;
+ int mute;
++ int cea_chmap; /* currently requested Audio InfoFrame Data Byte 4 */
++ int map_channels[8];
+
+ unsigned int opened;
+ unsigned int spdif_status;
+@@ -149,6 +151,8 @@ int snd_bcm2835_new_ctl(bcm2835_chip_t *
+ int snd_bcm2835_new_pcm(bcm2835_chip_t * chip);
+ int snd_bcm2835_new_spdif_pcm(bcm2835_chip_t * chip);
+
++int snd_bcm2835_pcm_prepare_again(struct snd_pcm_substream *substream);
++
+ int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream);
+ int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream);
+ int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
diff --git a/target/linux/brcm2708/patches-4.4/0129-bcm2835-restrict-channels-rate-to-8-960000.patch b/target/linux/brcm2708/patches-4.4/0129-bcm2835-restrict-channels-rate-to-8-960000.patch
deleted file mode 100644
index 29bd6ecd99..0000000000
--- a/target/linux/brcm2708/patches-4.4/0129-bcm2835-restrict-channels-rate-to-8-960000.patch
+++ /dev/null
@@ -1,80 +0,0 @@
-From 7e634c8f8fe70286e0b8b404494d3143aa7bc3fc Mon Sep 17 00:00:00 2001
-From: wm4 <wm4@nowhere>
-Date: Wed, 13 Jan 2016 19:42:18 +0100
-Subject: [PATCH 129/170] bcm2835: restrict channels*rate to 8*960000
-
-This is required at least for SPDIF. If the bitrate goes above,
-videocore will either resample the audio or corrupt it due to
-underruns. Supposedly the hardware isn't designed to output
-higher rates, but it can still resample it down to supported
-rates.
-
-Some code is based on ac97_pcm.c.
----
- sound/arm/bcm2835-pcm.c | 41 +++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 41 insertions(+)
-
---- a/sound/arm/bcm2835-pcm.c
-+++ b/sound/arm/bcm2835-pcm.c
-@@ -19,6 +19,9 @@
-
- #include "bcm2835.h"
-
-+/* The hardware can not do much more num_channels*samplerate then this value */
-+#define MAX_COMBINED_RATE 768000
-+
- /* hardware definition */
- static struct snd_pcm_hardware snd_bcm2835_playback_hw = {
- .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
-@@ -107,6 +110,31 @@ static irqreturn_t bcm2835_playback_fifo
- return IRQ_HANDLED;
- }
-
-+
-+static int rate_hw_constraint_rate(struct snd_pcm_hw_params *params,
-+ struct snd_pcm_hw_rule *rule)
-+{
-+ struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
-+ struct snd_interval rates = {
-+ .min = 8000,
-+ .max = min(192000u, MAX_COMBINED_RATE / max(channels->min, 1u)),
-+ };
-+ struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
-+ return snd_interval_refine(rate, &rates);
-+}
-+
-+static int rate_hw_constraint_channels(struct snd_pcm_hw_params *params,
-+ struct snd_pcm_hw_rule *rule)
-+{
-+ struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
-+ struct snd_interval channels_interval = {
-+ .min = 1,
-+ .max = min(8u, MAX_COMBINED_RATE / max(rate->min, 1u)),
-+ };
-+ struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
-+ return snd_interval_refine(channels, &channels_interval);
-+}
-+
- /* open callback */
- static int snd_bcm2835_playback_open_generic(
- struct snd_pcm_substream *substream, int spdif)
-@@ -188,6 +216,19 @@ static int snd_bcm2835_playback_open_gen
- snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
- 16);
-
-+ /* When playing PCM, pretend that we support the full range of channels
-+ * and sample rates. The GPU can't output it, but is able to resample
-+ * the data to a rate the hardware can handle it. This won't work with
-+ * compressed data; the resampler would just destroy it. */
-+ if (spdif) {
-+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
-+ rate_hw_constraint_rate, NULL,
-+ SNDRV_PCM_HW_PARAM_CHANNELS, -1);
-+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
-+ rate_hw_constraint_channels, NULL,
-+ SNDRV_PCM_HW_PARAM_RATE, -1);
-+ }
-+
- chip->alsa_stream[idx] = alsa_stream;
-
- chip->opened |= (1 << idx);
diff --git a/target/linux/brcm2708/patches-4.4/0130-bcm2835-access-controls-under-the-audio-mutex.patch b/target/linux/brcm2708/patches-4.4/0130-bcm2835-access-controls-under-the-audio-mutex.patch
new file mode 100644
index 0000000000..ce1c05c62e
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0130-bcm2835-access-controls-under-the-audio-mutex.patch
@@ -0,0 +1,237 @@
+From 16a8daf3e66584f5c1bd3b113675d3fc3b44adc1 Mon Sep 17 00:00:00 2001
+From: wm4 <wm4@nowhere>
+Date: Wed, 13 Jan 2016 19:43:35 +0100
+Subject: [PATCH 130/381] bcm2835: access controls under the audio mutex
+
+I don't think the ALSA framework provides any kind of automatic
+synchronization within the control callbacks. We most likely need
+to ensure this manually, so add locking around all access to shared
+mutable data. In particular, bcm2835_audio_set_ctls() should
+probably always be called under our own audio lock.
+---
+ sound/arm/bcm2835-ctl.c | 74 +++++++++++++++++++++++++++++++++++++++++--------
+ sound/arm/bcm2835-pcm.c | 4 +++
+ 2 files changed, 66 insertions(+), 12 deletions(-)
+
+--- a/sound/arm/bcm2835-ctl.c
++++ b/sound/arm/bcm2835-ctl.c
+@@ -94,6 +94,9 @@ static int snd_bcm2835_ctl_get(struct sn
+ {
+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
+
++ if (mutex_lock_interruptible(&chip->audio_mutex))
++ return -EINTR;
++
+ BUG_ON(!chip && !(chip->avail_substreams & AVAIL_SUBSTREAMS_MASK));
+
+ if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
+@@ -103,6 +106,7 @@ static int snd_bcm2835_ctl_get(struct sn
+ else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
+ ucontrol->value.integer.value[0] = chip->dest;
+
++ mutex_unlock(&chip->audio_mutex);
+ return 0;
+ }
+
+@@ -112,11 +116,15 @@ static int snd_bcm2835_ctl_put(struct sn
+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
+ int changed = 0;
+
++ if (mutex_lock_interruptible(&chip->audio_mutex))
++ return -EINTR;
++
+ if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
+ audio_info("Volume change attempted.. volume = %d new_volume = %d\n", chip->volume, (int)ucontrol->value.integer.value[0]);
+ if (chip->mute == CTRL_VOL_MUTE) {
+ /* changed = toggle_mute(chip, CTRL_VOL_UNMUTE); */
+- return 1; /* should return 0 to signify no change but the mixer takes this as the opposite sign (no idea why) */
++ changed = 1; /* should return 0 to signify no change but the mixer takes this as the opposite sign (no idea why) */
++ goto unlock;
+ }
+ if (changed
+ || (ucontrol->value.integer.value[0] != chip2alsa(chip->volume))) {
+@@ -142,6 +150,8 @@ static int snd_bcm2835_ctl_put(struct sn
+ printk(KERN_ERR "Failed to set ALSA controls..\n");
+ }
+
++unlock:
++ mutex_unlock(&chip->audio_mutex);
+ return changed;
+ }
+
+@@ -198,10 +208,14 @@ static int snd_bcm2835_spdif_default_get
+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
+ int i;
+
++ if (mutex_lock_interruptible(&chip->audio_mutex))
++ return -EINTR;
++
+ for (i = 0; i < 4; i++)
+ ucontrol->value.iec958.status[i] =
+ (chip->spdif_status >> (i * 8)) && 0xff;
+
++ mutex_unlock(&chip->audio_mutex);
+ return 0;
+ }
+
+@@ -212,12 +226,16 @@ static int snd_bcm2835_spdif_default_put
+ unsigned int val = 0;
+ int i, change;
+
++ if (mutex_lock_interruptible(&chip->audio_mutex))
++ return -EINTR;
++
+ for (i = 0; i < 4; i++)
+ val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
+
+ change = val != chip->spdif_status;
+ chip->spdif_status = val;
+
++ mutex_unlock(&chip->audio_mutex);
+ return change;
+ }
+
+@@ -253,9 +271,14 @@ static int snd_bcm2835_spdif_stream_get(
+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
+ int i;
+
++ if (mutex_lock_interruptible(&chip->audio_mutex))
++ return -EINTR;
++
+ for (i = 0; i < 4; i++)
+ ucontrol->value.iec958.status[i] =
+ (chip->spdif_status >> (i * 8)) & 0xff;
++
++ mutex_unlock(&chip->audio_mutex);
+ return 0;
+ }
+
+@@ -266,11 +289,15 @@ static int snd_bcm2835_spdif_stream_put(
+ unsigned int val = 0;
+ int i, change;
+
++ if (mutex_lock_interruptible(&chip->audio_mutex))
++ return -EINTR;
++
+ for (i = 0; i < 4; i++)
+ val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
+ change = val != chip->spdif_status;
+ chip->spdif_status = val;
+
++ mutex_unlock(&chip->audio_mutex);
+ return change;
+ }
+
+@@ -454,11 +481,17 @@ static int snd_bcm2835_chmap_ctl_get(str
+ unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ struct snd_pcm_substream *substream = snd_pcm_chmap_substream(info, idx);
+ struct cea_channel_speaker_allocation *ch = NULL;
++ int res = 0;
+ int cur = 0;
+ int i;
+
+- if (!substream || !substream->runtime)
+- return -ENODEV;
++ if (mutex_lock_interruptible(&chip->audio_mutex))
++ return -EINTR;
++
++ if (!substream || !substream->runtime) {
++ res = -ENODEV;
++ goto unlock;
++ }
+
+ for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
+ if (channel_allocations[i].ca_index == chip->cea_chmap)
+@@ -476,7 +509,10 @@ static int snd_bcm2835_chmap_ctl_get(str
+ }
+ while (cur < 8)
+ ucontrol->value.integer.value[cur++] = SNDRV_CHMAP_NA;
+- return 0;
++
++unlock:
++ mutex_unlock(&chip->audio_mutex);
++ return res;
+ }
+
+ static int snd_bcm2835_chmap_ctl_put(struct snd_kcontrol *kcontrol,
+@@ -487,10 +523,16 @@ static int snd_bcm2835_chmap_ctl_put(str
+ unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ struct snd_pcm_substream *substream = snd_pcm_chmap_substream(info, idx);
+ int i, prepared = 0, cea_chmap = -1;
++ int res = 0;
+ int remap[8];
+
+- if (!substream || !substream->runtime)
+- return -ENODEV;
++ if (mutex_lock_interruptible(&chip->audio_mutex))
++ return -EINTR;
++
++ if (!substream || !substream->runtime) {
++ res = -ENODEV;
++ goto unlock;
++ }
+
+ switch (substream->runtime->status->state) {
+ case SNDRV_PCM_STATE_OPEN:
+@@ -500,7 +542,8 @@ static int snd_bcm2835_chmap_ctl_put(str
+ prepared = 1;
+ break;
+ default:
+- return -EBUSY;
++ res = -EBUSY;
++ goto unlock;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
+@@ -538,19 +581,26 @@ static int snd_bcm2835_chmap_ctl_put(str
+ }
+ }
+
+- if (cea_chmap < 0)
+- return -EINVAL;
++ if (cea_chmap < 0) {
++ res = -EINVAL;
++ goto unlock;
++ }
+
+ /* don't change the layout if another substream is active */
+- if (chip->opened != (1 << substream->number) && chip->cea_chmap != cea_chmap)
+- return -EBUSY; /* unsure whether this is a good error code */
++ if (chip->opened != (1 << substream->number) && chip->cea_chmap != cea_chmap) {
++ res = -EBUSY; /* unsure whether this is a good error code */
++ goto unlock;
++ }
+
+ chip->cea_chmap = cea_chmap;
+ for (i = 0; i < 8; i++)
+ chip->map_channels[i] = remap[i];
+ if (prepared)
+ snd_bcm2835_pcm_prepare_again(substream);
+- return 0;
++
++unlock:
++ mutex_unlock(&chip->audio_mutex);
++ return res;
+ }
+
+ static int snd_bcm2835_add_chmap_ctl(bcm2835_chip_t * chip)
+--- a/sound/arm/bcm2835-pcm.c
++++ b/sound/arm/bcm2835-pcm.c
+@@ -379,6 +379,9 @@ static int snd_bcm2835_pcm_prepare(struc
+
+ audio_info(" .. IN\n");
+
++ if (mutex_lock_interruptible(&chip->audio_mutex))
++ return -EINTR;
++
+ snd_bcm2835_pcm_prepare_again(substream);
+
+ bcm2835_audio_setup(alsa_stream);
+@@ -401,6 +404,7 @@ static int snd_bcm2835_pcm_prepare(struc
+ alsa_stream->buffer_size, alsa_stream->period_size,
+ alsa_stream->pos, runtime->frame_bits);
+
++ mutex_unlock(&chip->audio_mutex);
+ audio_info(" .. OUT\n");
+ return 0;
+ }
diff --git a/target/linux/brcm2708/patches-4.4/0130-rpi-update-vc_vchi_audioserv_defs.h.patch b/target/linux/brcm2708/patches-4.4/0130-rpi-update-vc_vchi_audioserv_defs.h.patch
deleted file mode 100644
index 63f26aa931..0000000000
--- a/target/linux/brcm2708/patches-4.4/0130-rpi-update-vc_vchi_audioserv_defs.h.patch
+++ /dev/null
@@ -1,66 +0,0 @@
-From dcead34f063fc8c37ebfcfc9ab6696060c336bad Mon Sep 17 00:00:00 2001
-From: wm4 <wm4@nowhere>
-Date: Wed, 13 Jan 2016 19:42:48 +0100
-Subject: [PATCH 130/170] rpi: update vc_vchi_audioserv_defs.h
-
-Add audioserv 3 extensions. The changes were taken from the paste
-linked here:
-
-https://github.com/raspberrypi/linux/pull/1166#issuecomment-151917067
----
- sound/arm/vc_vchi_audioserv_defs.h | 13 +++++++++++--
- 1 file changed, 11 insertions(+), 2 deletions(-)
-
---- a/sound/arm/vc_vchi_audioserv_defs.h
-+++ b/sound/arm/vc_vchi_audioserv_defs.h
-@@ -16,7 +16,7 @@
- #define _VC_AUDIO_DEFS_H_
-
- #define VC_AUDIOSERV_MIN_VER 1
--#define VC_AUDIOSERV_VER 2
-+#define VC_AUDIOSERV_VER 3
-
- // FourCC code used for VCHI connection
- #define VC_AUDIO_SERVER_NAME MAKE_FOURCC("AUDS")
-@@ -36,6 +36,7 @@ typedef enum {
- VC_AUDIO_MSG_TYPE_START, // Configure audio
- VC_AUDIO_MSG_TYPE_STOP, // Configure audio
- VC_AUDIO_MSG_TYPE_WRITE, // Configure audio
-+ VC_AUDIO_MSG_TYPE_LATENCY, // request latency in cycles
- VC_AUDIO_MSG_TYPE_MAX
- } VC_AUDIO_MSG_TYPE;
-
-@@ -44,6 +45,7 @@ typedef struct {
- uint32_t channels;
- uint32_t samplerate;
- uint32_t bps;
-+ uint32_t channelmap;
-
- } VC_AUDIO_CONFIG_T;
-
-@@ -84,6 +86,12 @@ typedef struct {
- uint16_t max_packet;
- } VC_AUDIO_WRITE_T;
-
-+// query latency in samples of sink
-+typedef struct
-+{
-+ uint32_t dummy;
-+} VC_AUDIO_LATENCY_T;
-+
- // Generic result for a request (VC->HOST)
- typedef struct {
- int32_t success; // Success value
-@@ -108,9 +116,10 @@ typedef struct {
- VC_AUDIO_START_T start;
- VC_AUDIO_STOP_T stop;
- VC_AUDIO_WRITE_T write;
-+ VC_AUDIO_LATENCY_T latency;
- VC_AUDIO_RESULT_T result;
- VC_AUDIO_COMPLETE_T complete;
- } u;
- } VC_AUDIO_MSG_T;
-
--#endif // _VC_AUDIO_DEFS_H_
-+#endif // _VC_AUDIO_DEFS_H_
-\ No newline at end of file
diff --git a/target/linux/brcm2708/patches-4.4/0131-bcm2835-always-use-2-4-8-channels-for-multichannel-l.patch b/target/linux/brcm2708/patches-4.4/0131-bcm2835-always-use-2-4-8-channels-for-multichannel-l.patch
new file mode 100644
index 0000000000..31d08e2ca9
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0131-bcm2835-always-use-2-4-8-channels-for-multichannel-l.patch
@@ -0,0 +1,139 @@
+From b5a3fcac12091441ee4d692ad90b7cb7afe7c83d Mon Sep 17 00:00:00 2001
+From: wm4 <wm4@nowhere>
+Date: Wed, 13 Jan 2016 19:44:03 +0100
+Subject: [PATCH 131/381] bcm2835: always use 2/4/8 channels for multichannel
+ layouts
+
+Pad the unused channels with NA. This means userspace needs to write
+additional, silent padding channels, which is not ideal, but better
+than noise.
+
+Works around noise at the following channel counts: 3, 5, 6, 7
+---
+ sound/arm/bcm2835-ctl.c | 89 +++++++++++++++++++++++++------------------------
+ 1 file changed, 45 insertions(+), 44 deletions(-)
+
+--- a/sound/arm/bcm2835-ctl.c
++++ b/sound/arm/bcm2835-ctl.c
+@@ -349,6 +349,7 @@ struct cea_channel_speaker_allocation {
+ #define FRW SNDRV_CHMAP_FRW
+ #define TC SNDRV_CHMAP_TC
+ #define FCH SNDRV_CHMAP_TFC
++#define NA SNDRV_CHMAP_NA
+
+ /*
+ * CEA-861 channel maps
+@@ -356,69 +357,69 @@ struct cea_channel_speaker_allocation {
+ * Stolen from sound/pci/hda/patch_hdmi.c
+ * (unlike the source, this uses SNDRV_* constants directly, as by the
+ * map_tables array in patch_hdmi.c)
+- * Unknown entries use 0, which unfortunately is SNDRV_CHMAP_UNKNOWN instead
+- * of SNDRV_CHMAP_NA.
++ * Entries which do not have a physical output channel use 0. Entries which
++ * require userspace to output silence use NA (SNDRV_CHMAP_NA).
+ */
+ static struct cea_channel_speaker_allocation channel_allocations[] = {
+ /* channel: 7 6 5 4 3 2 1 0 */
+ { .ca_index = 0x00, .speakers = { 0, 0, 0, 0, 0, 0, FR, FL } },
+ /* 2.1 */
+-{ .ca_index = 0x01, .speakers = { 0, 0, 0, 0, 0, LFE, FR, FL } },
++{ .ca_index = 0x01, .speakers = { 0, 0, 0, 0, NA, LFE, FR, FL } },
+ /* Dolby Surround */
+-{ .ca_index = 0x02, .speakers = { 0, 0, 0, 0, FC, 0, FR, FL } },
++{ .ca_index = 0x02, .speakers = { 0, 0, 0, 0, FC, NA, FR, FL } },
+ /* surround40 */
+-{ .ca_index = 0x08, .speakers = { 0, 0, RR, RL, 0, 0, FR, FL } },
++{ .ca_index = 0x08, .speakers = { NA, NA, RR, RL, NA, NA, FR, FL } },
+ /* surround41 */
+-{ .ca_index = 0x09, .speakers = { 0, 0, RR, RL, 0, LFE, FR, FL } },
++{ .ca_index = 0x09, .speakers = { NA, NA, RR, RL, NA, LFE, FR, FL } },
+ /* surround50 */
+-{ .ca_index = 0x0a, .speakers = { 0, 0, RR, RL, FC, 0, FR, FL } },
++{ .ca_index = 0x0a, .speakers = { NA, NA, RR, RL, FC, NA, FR, FL } },
+ /* surround51 */
+-{ .ca_index = 0x0b, .speakers = { 0, 0, RR, RL, FC, LFE, FR, FL } },
++{ .ca_index = 0x0b, .speakers = { NA, NA, RR, RL, FC, LFE, FR, FL } },
+ /* 6.1 */
+-{ .ca_index = 0x0f, .speakers = { 0, RC, RR, RL, FC, LFE, FR, FL } },
++{ .ca_index = 0x0f, .speakers = { NA, RC, RR, RL, FC, LFE, FR, FL } },
+ /* surround71 */
+ { .ca_index = 0x13, .speakers = { RRC, RLC, RR, RL, FC, LFE, FR, FL } },
+
+-{ .ca_index = 0x03, .speakers = { 0, 0, 0, 0, FC, LFE, FR, FL } },
+-{ .ca_index = 0x04, .speakers = { 0, 0, 0, RC, 0, 0, FR, FL } },
+-{ .ca_index = 0x05, .speakers = { 0, 0, 0, RC, 0, LFE, FR, FL } },
+-{ .ca_index = 0x06, .speakers = { 0, 0, 0, RC, FC, 0, FR, FL } },
+-{ .ca_index = 0x07, .speakers = { 0, 0, 0, RC, FC, LFE, FR, FL } },
+-{ .ca_index = 0x0c, .speakers = { 0, RC, RR, RL, 0, 0, FR, FL } },
+-{ .ca_index = 0x0d, .speakers = { 0, RC, RR, RL, 0, LFE, FR, FL } },
+-{ .ca_index = 0x0e, .speakers = { 0, RC, RR, RL, FC, 0, FR, FL } },
+-{ .ca_index = 0x10, .speakers = { RRC, RLC, RR, RL, 0, 0, FR, FL } },
+-{ .ca_index = 0x11, .speakers = { RRC, RLC, RR, RL, 0, LFE, FR, FL } },
+-{ .ca_index = 0x12, .speakers = { RRC, RLC, RR, RL, FC, 0, FR, FL } },
+-{ .ca_index = 0x14, .speakers = { FRC, FLC, 0, 0, 0, 0, FR, FL } },
+-{ .ca_index = 0x15, .speakers = { FRC, FLC, 0, 0, 0, LFE, FR, FL } },
+-{ .ca_index = 0x16, .speakers = { FRC, FLC, 0, 0, FC, 0, FR, FL } },
+-{ .ca_index = 0x17, .speakers = { FRC, FLC, 0, 0, FC, LFE, FR, FL } },
+-{ .ca_index = 0x18, .speakers = { FRC, FLC, 0, RC, 0, 0, FR, FL } },
+-{ .ca_index = 0x19, .speakers = { FRC, FLC, 0, RC, 0, LFE, FR, FL } },
+-{ .ca_index = 0x1a, .speakers = { FRC, FLC, 0, RC, FC, 0, FR, FL } },
+-{ .ca_index = 0x1b, .speakers = { FRC, FLC, 0, RC, FC, LFE, FR, FL } },
+-{ .ca_index = 0x1c, .speakers = { FRC, FLC, RR, RL, 0, 0, FR, FL } },
+-{ .ca_index = 0x1d, .speakers = { FRC, FLC, RR, RL, 0, LFE, FR, FL } },
+-{ .ca_index = 0x1e, .speakers = { FRC, FLC, RR, RL, FC, 0, FR, FL } },
++{ .ca_index = 0x03, .speakers = { NA, NA, NA, NA, FC, LFE, FR, FL } },
++{ .ca_index = 0x04, .speakers = { NA, NA, NA, RC, NA, NA, FR, FL } },
++{ .ca_index = 0x05, .speakers = { NA, NA, NA, RC, NA, LFE, FR, FL } },
++{ .ca_index = 0x06, .speakers = { NA, NA, NA, RC, FC, NA, FR, FL } },
++{ .ca_index = 0x07, .speakers = { NA, NA, NA, RC, FC, LFE, FR, FL } },
++{ .ca_index = 0x0c, .speakers = { NA, RC, RR, RL, NA, NA, FR, FL } },
++{ .ca_index = 0x0d, .speakers = { NA, RC, RR, RL, NA, LFE, FR, FL } },
++{ .ca_index = 0x0e, .speakers = { NA, RC, RR, RL, FC, NA, FR, FL } },
++{ .ca_index = 0x10, .speakers = { RRC, RLC, RR, RL, NA, NA, FR, FL } },
++{ .ca_index = 0x11, .speakers = { RRC, RLC, RR, RL, NA, LFE, FR, FL } },
++{ .ca_index = 0x12, .speakers = { RRC, RLC, RR, RL, FC, NA, FR, FL } },
++{ .ca_index = 0x14, .speakers = { FRC, FLC, NA, NA, NA, NA, FR, FL } },
++{ .ca_index = 0x15, .speakers = { FRC, FLC, NA, NA, NA, LFE, FR, FL } },
++{ .ca_index = 0x16, .speakers = { FRC, FLC, NA, NA, FC, NA, FR, FL } },
++{ .ca_index = 0x17, .speakers = { FRC, FLC, NA, NA, FC, LFE, FR, FL } },
++{ .ca_index = 0x18, .speakers = { FRC, FLC, NA, RC, NA, NA, FR, FL } },
++{ .ca_index = 0x19, .speakers = { FRC, FLC, NA, RC, NA, LFE, FR, FL } },
++{ .ca_index = 0x1a, .speakers = { FRC, FLC, NA, RC, FC, NA, FR, FL } },
++{ .ca_index = 0x1b, .speakers = { FRC, FLC, NA, RC, FC, LFE, FR, FL } },
++{ .ca_index = 0x1c, .speakers = { FRC, FLC, RR, RL, NA, NA, FR, FL } },
++{ .ca_index = 0x1d, .speakers = { FRC, FLC, RR, RL, NA, LFE, FR, FL } },
++{ .ca_index = 0x1e, .speakers = { FRC, FLC, RR, RL, FC, NA, FR, FL } },
+ { .ca_index = 0x1f, .speakers = { FRC, FLC, RR, RL, FC, LFE, FR, FL } },
+-{ .ca_index = 0x20, .speakers = { 0, FCH, RR, RL, FC, 0, FR, FL } },
+-{ .ca_index = 0x21, .speakers = { 0, FCH, RR, RL, FC, LFE, FR, FL } },
+-{ .ca_index = 0x22, .speakers = { TC, 0, RR, RL, FC, 0, FR, FL } },
+-{ .ca_index = 0x23, .speakers = { TC, 0, RR, RL, FC, LFE, FR, FL } },
+-{ .ca_index = 0x24, .speakers = { FRH, FLH, RR, RL, 0, 0, FR, FL } },
+-{ .ca_index = 0x25, .speakers = { FRH, FLH, RR, RL, 0, LFE, FR, FL } },
+-{ .ca_index = 0x26, .speakers = { FRW, FLW, RR, RL, 0, 0, FR, FL } },
+-{ .ca_index = 0x27, .speakers = { FRW, FLW, RR, RL, 0, LFE, FR, FL } },
+-{ .ca_index = 0x28, .speakers = { TC, RC, RR, RL, FC, 0, FR, FL } },
++{ .ca_index = 0x20, .speakers = { NA, FCH, RR, RL, FC, NA, FR, FL } },
++{ .ca_index = 0x21, .speakers = { NA, FCH, RR, RL, FC, LFE, FR, FL } },
++{ .ca_index = 0x22, .speakers = { TC, NA, RR, RL, FC, NA, FR, FL } },
++{ .ca_index = 0x23, .speakers = { TC, NA, RR, RL, FC, LFE, FR, FL } },
++{ .ca_index = 0x24, .speakers = { FRH, FLH, RR, RL, NA, NA, FR, FL } },
++{ .ca_index = 0x25, .speakers = { FRH, FLH, RR, RL, NA, LFE, FR, FL } },
++{ .ca_index = 0x26, .speakers = { FRW, FLW, RR, RL, NA, NA, FR, FL } },
++{ .ca_index = 0x27, .speakers = { FRW, FLW, RR, RL, NA, LFE, FR, FL } },
++{ .ca_index = 0x28, .speakers = { TC, RC, RR, RL, FC, NA, FR, FL } },
+ { .ca_index = 0x29, .speakers = { TC, RC, RR, RL, FC, LFE, FR, FL } },
+-{ .ca_index = 0x2a, .speakers = { FCH, RC, RR, RL, FC, 0, FR, FL } },
++{ .ca_index = 0x2a, .speakers = { FCH, RC, RR, RL, FC, NA, FR, FL } },
+ { .ca_index = 0x2b, .speakers = { FCH, RC, RR, RL, FC, LFE, FR, FL } },
+-{ .ca_index = 0x2c, .speakers = { TC, FCH, RR, RL, FC, 0, FR, FL } },
++{ .ca_index = 0x2c, .speakers = { TC, FCH, RR, RL, FC, NA, FR, FL } },
+ { .ca_index = 0x2d, .speakers = { TC, FCH, RR, RL, FC, LFE, FR, FL } },
+-{ .ca_index = 0x2e, .speakers = { FRH, FLH, RR, RL, FC, 0, FR, FL } },
++{ .ca_index = 0x2e, .speakers = { FRH, FLH, RR, RL, FC, NA, FR, FL } },
+ { .ca_index = 0x2f, .speakers = { FRH, FLH, RR, RL, FC, LFE, FR, FL } },
+-{ .ca_index = 0x30, .speakers = { FRW, FLW, RR, RL, FC, 0, FR, FL } },
++{ .ca_index = 0x30, .speakers = { FRW, FLW, RR, RL, FC, NA, FR, FL } },
+ { .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } },
+ };
+
diff --git a/target/linux/brcm2708/patches-4.4/0131-bcm2835-implement-channel-map-API.patch b/target/linux/brcm2708/patches-4.4/0131-bcm2835-implement-channel-map-API.patch
deleted file mode 100644
index bdcdb8a558..0000000000
--- a/target/linux/brcm2708/patches-4.4/0131-bcm2835-implement-channel-map-API.patch
+++ /dev/null
@@ -1,421 +0,0 @@
-From 7c7d2db494fbf1fd0b014dab0bb4c5c740f90442 Mon Sep 17 00:00:00 2001
-From: wm4 <wm4@nowhere>
-Date: Wed, 13 Jan 2016 19:43:12 +0100
-Subject: [PATCH 131/170] bcm2835: implement channel map API
-
-Report all layouts supported by the HDMI protocol to userspace.
-Make the videocore set the correct layout according to the
-userspace request.
-
-Some code taken from patch_hdmi.c. In particular, the HDMI channel
-layout table was copied without changes - with the idea in mind that
-hopefully it can be shared one day. Or at least updating it will be
-simpler.
-
-In my tests, everything appears to work, except when outputting
-FL FR RL RR. Then my receiver outputs RL on both the RL and RR
-speakers, while RR is never heard.
----
- sound/arm/bcm2835-ctl.c | 276 ++++++++++++++++++++++++++++++++++++++++++++++
- sound/arm/bcm2835-pcm.c | 22 +++-
- sound/arm/bcm2835-vchiq.c | 13 +++
- sound/arm/bcm2835.h | 4 +
- 4 files changed, 311 insertions(+), 4 deletions(-)
-
---- a/sound/arm/bcm2835-ctl.c
-+++ b/sound/arm/bcm2835-ctl.c
-@@ -300,6 +300,281 @@ static struct snd_kcontrol_new snd_bcm28
- },
- };
-
-+struct cea_channel_speaker_allocation {
-+ int ca_index;
-+ int speakers[8];
-+};
-+
-+#define FL SNDRV_CHMAP_FL
-+#define FR SNDRV_CHMAP_FR
-+#define RL SNDRV_CHMAP_RL
-+#define RR SNDRV_CHMAP_RR
-+#define LFE SNDRV_CHMAP_LFE
-+#define FC SNDRV_CHMAP_FC
-+#define RLC SNDRV_CHMAP_RLC
-+#define RRC SNDRV_CHMAP_RRC
-+#define RC SNDRV_CHMAP_RC
-+#define FLC SNDRV_CHMAP_FLC
-+#define FRC SNDRV_CHMAP_FRC
-+#define FLH SNDRV_CHMAP_TFL
-+#define FRH SNDRV_CHMAP_TFR
-+#define FLW SNDRV_CHMAP_FLW
-+#define FRW SNDRV_CHMAP_FRW
-+#define TC SNDRV_CHMAP_TC
-+#define FCH SNDRV_CHMAP_TFC
-+
-+/*
-+ * CEA-861 channel maps
-+ *
-+ * Stolen from sound/pci/hda/patch_hdmi.c
-+ * (unlike the source, this uses SNDRV_* constants directly, as by the
-+ * map_tables array in patch_hdmi.c)
-+ * Unknown entries use 0, which unfortunately is SNDRV_CHMAP_UNKNOWN instead
-+ * of SNDRV_CHMAP_NA.
-+ */
-+static struct cea_channel_speaker_allocation channel_allocations[] = {
-+/* channel: 7 6 5 4 3 2 1 0 */
-+{ .ca_index = 0x00, .speakers = { 0, 0, 0, 0, 0, 0, FR, FL } },
-+ /* 2.1 */
-+{ .ca_index = 0x01, .speakers = { 0, 0, 0, 0, 0, LFE, FR, FL } },
-+ /* Dolby Surround */
-+{ .ca_index = 0x02, .speakers = { 0, 0, 0, 0, FC, 0, FR, FL } },
-+ /* surround40 */
-+{ .ca_index = 0x08, .speakers = { 0, 0, RR, RL, 0, 0, FR, FL } },
-+ /* surround41 */
-+{ .ca_index = 0x09, .speakers = { 0, 0, RR, RL, 0, LFE, FR, FL } },
-+ /* surround50 */
-+{ .ca_index = 0x0a, .speakers = { 0, 0, RR, RL, FC, 0, FR, FL } },
-+ /* surround51 */
-+{ .ca_index = 0x0b, .speakers = { 0, 0, RR, RL, FC, LFE, FR, FL } },
-+ /* 6.1 */
-+{ .ca_index = 0x0f, .speakers = { 0, RC, RR, RL, FC, LFE, FR, FL } },
-+ /* surround71 */
-+{ .ca_index = 0x13, .speakers = { RRC, RLC, RR, RL, FC, LFE, FR, FL } },
-+
-+{ .ca_index = 0x03, .speakers = { 0, 0, 0, 0, FC, LFE, FR, FL } },
-+{ .ca_index = 0x04, .speakers = { 0, 0, 0, RC, 0, 0, FR, FL } },
-+{ .ca_index = 0x05, .speakers = { 0, 0, 0, RC, 0, LFE, FR, FL } },
-+{ .ca_index = 0x06, .speakers = { 0, 0, 0, RC, FC, 0, FR, FL } },
-+{ .ca_index = 0x07, .speakers = { 0, 0, 0, RC, FC, LFE, FR, FL } },
-+{ .ca_index = 0x0c, .speakers = { 0, RC, RR, RL, 0, 0, FR, FL } },
-+{ .ca_index = 0x0d, .speakers = { 0, RC, RR, RL, 0, LFE, FR, FL } },
-+{ .ca_index = 0x0e, .speakers = { 0, RC, RR, RL, FC, 0, FR, FL } },
-+{ .ca_index = 0x10, .speakers = { RRC, RLC, RR, RL, 0, 0, FR, FL } },
-+{ .ca_index = 0x11, .speakers = { RRC, RLC, RR, RL, 0, LFE, FR, FL } },
-+{ .ca_index = 0x12, .speakers = { RRC, RLC, RR, RL, FC, 0, FR, FL } },
-+{ .ca_index = 0x14, .speakers = { FRC, FLC, 0, 0, 0, 0, FR, FL } },
-+{ .ca_index = 0x15, .speakers = { FRC, FLC, 0, 0, 0, LFE, FR, FL } },
-+{ .ca_index = 0x16, .speakers = { FRC, FLC, 0, 0, FC, 0, FR, FL } },
-+{ .ca_index = 0x17, .speakers = { FRC, FLC, 0, 0, FC, LFE, FR, FL } },
-+{ .ca_index = 0x18, .speakers = { FRC, FLC, 0, RC, 0, 0, FR, FL } },
-+{ .ca_index = 0x19, .speakers = { FRC, FLC, 0, RC, 0, LFE, FR, FL } },
-+{ .ca_index = 0x1a, .speakers = { FRC, FLC, 0, RC, FC, 0, FR, FL } },
-+{ .ca_index = 0x1b, .speakers = { FRC, FLC, 0, RC, FC, LFE, FR, FL } },
-+{ .ca_index = 0x1c, .speakers = { FRC, FLC, RR, RL, 0, 0, FR, FL } },
-+{ .ca_index = 0x1d, .speakers = { FRC, FLC, RR, RL, 0, LFE, FR, FL } },
-+{ .ca_index = 0x1e, .speakers = { FRC, FLC, RR, RL, FC, 0, FR, FL } },
-+{ .ca_index = 0x1f, .speakers = { FRC, FLC, RR, RL, FC, LFE, FR, FL } },
-+{ .ca_index = 0x20, .speakers = { 0, FCH, RR, RL, FC, 0, FR, FL } },
-+{ .ca_index = 0x21, .speakers = { 0, FCH, RR, RL, FC, LFE, FR, FL } },
-+{ .ca_index = 0x22, .speakers = { TC, 0, RR, RL, FC, 0, FR, FL } },
-+{ .ca_index = 0x23, .speakers = { TC, 0, RR, RL, FC, LFE, FR, FL } },
-+{ .ca_index = 0x24, .speakers = { FRH, FLH, RR, RL, 0, 0, FR, FL } },
-+{ .ca_index = 0x25, .speakers = { FRH, FLH, RR, RL, 0, LFE, FR, FL } },
-+{ .ca_index = 0x26, .speakers = { FRW, FLW, RR, RL, 0, 0, FR, FL } },
-+{ .ca_index = 0x27, .speakers = { FRW, FLW, RR, RL, 0, LFE, FR, FL } },
-+{ .ca_index = 0x28, .speakers = { TC, RC, RR, RL, FC, 0, FR, FL } },
-+{ .ca_index = 0x29, .speakers = { TC, RC, RR, RL, FC, LFE, FR, FL } },
-+{ .ca_index = 0x2a, .speakers = { FCH, RC, RR, RL, FC, 0, FR, FL } },
-+{ .ca_index = 0x2b, .speakers = { FCH, RC, RR, RL, FC, LFE, FR, FL } },
-+{ .ca_index = 0x2c, .speakers = { TC, FCH, RR, RL, FC, 0, FR, FL } },
-+{ .ca_index = 0x2d, .speakers = { TC, FCH, RR, RL, FC, LFE, FR, FL } },
-+{ .ca_index = 0x2e, .speakers = { FRH, FLH, RR, RL, FC, 0, FR, FL } },
-+{ .ca_index = 0x2f, .speakers = { FRH, FLH, RR, RL, FC, LFE, FR, FL } },
-+{ .ca_index = 0x30, .speakers = { FRW, FLW, RR, RL, FC, 0, FR, FL } },
-+{ .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } },
-+};
-+
-+static int snd_bcm2835_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag,
-+ unsigned int size, unsigned int __user *tlv)
-+{
-+ unsigned int __user *dst;
-+ int count = 0;
-+ int i;
-+
-+ if (size < 8)
-+ return -ENOMEM;
-+ if (put_user(SNDRV_CTL_TLVT_CONTAINER, tlv))
-+ return -EFAULT;
-+ size -= 8;
-+ dst = tlv + 2;
-+ for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
-+ struct cea_channel_speaker_allocation *ch = &channel_allocations[i];
-+ int num_chs = 0;
-+ int chs_bytes;
-+ int c;
-+
-+ for (c = 0; c < 8; c++) {
-+ if (ch->speakers[c])
-+ num_chs++;
-+ }
-+
-+ chs_bytes = num_chs * 4;
-+ if (size < 8)
-+ return -ENOMEM;
-+ if (put_user(SNDRV_CTL_TLVT_CHMAP_FIXED, dst) ||
-+ put_user(chs_bytes, dst + 1))
-+ return -EFAULT;
-+ dst += 2;
-+ size -= 8;
-+ count += 8;
-+ if (size < chs_bytes)
-+ return -ENOMEM;
-+ size -= chs_bytes;
-+ count += chs_bytes;
-+ for (c = 0; c < 8; c++) {
-+ int sp = ch->speakers[7 - c];
-+ if (sp) {
-+ if (put_user(sp, dst))
-+ return -EFAULT;
-+ dst++;
-+ }
-+ }
-+ }
-+ if (put_user(count, tlv + 1))
-+ return -EFAULT;
-+ return 0;
-+}
-+
-+static int snd_bcm2835_chmap_ctl_get(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_value *ucontrol)
-+{
-+ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
-+ bcm2835_chip_t *chip = info->private_data;
-+ unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-+ struct snd_pcm_substream *substream = snd_pcm_chmap_substream(info, idx);
-+ struct cea_channel_speaker_allocation *ch = NULL;
-+ int cur = 0;
-+ int i;
-+
-+ if (!substream || !substream->runtime)
-+ return -ENODEV;
-+
-+ for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
-+ if (channel_allocations[i].ca_index == chip->cea_chmap)
-+ ch = &channel_allocations[i];
-+ }
-+
-+ /* If no layout was set yet, return a dummy. Apparently the userspace
-+ * API will be confused if we don't. */
-+ if (!ch)
-+ ch = &channel_allocations[0];
-+
-+ for (i = 0; i < 8; i++) {
-+ if (ch->speakers[7 - i])
-+ ucontrol->value.integer.value[cur++] = ch->speakers[7 - i];
-+ }
-+ while (cur < 8)
-+ ucontrol->value.integer.value[cur++] = SNDRV_CHMAP_NA;
-+ return 0;
-+}
-+
-+static int snd_bcm2835_chmap_ctl_put(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_value *ucontrol)
-+{
-+ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
-+ bcm2835_chip_t *chip = info->private_data;
-+ unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-+ struct snd_pcm_substream *substream = snd_pcm_chmap_substream(info, idx);
-+ int i, prepared = 0, cea_chmap = -1;
-+ int remap[8];
-+
-+ if (!substream || !substream->runtime)
-+ return -ENODEV;
-+
-+ switch (substream->runtime->status->state) {
-+ case SNDRV_PCM_STATE_OPEN:
-+ case SNDRV_PCM_STATE_SETUP:
-+ break;
-+ case SNDRV_PCM_STATE_PREPARED:
-+ prepared = 1;
-+ break;
-+ default:
-+ return -EBUSY;
-+ }
-+
-+ for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
-+ struct cea_channel_speaker_allocation *ch = &channel_allocations[i];
-+ int matches = 1;
-+ int cur = 0;
-+ int x;
-+ memset(remap, 0, sizeof(remap));
-+ for (x = 0; x < substream->runtime->channels; x++) {
-+ int sp = ucontrol->value.integer.value[x];
-+ while (cur < 8 && !ch->speakers[7 - cur])
-+ cur++;
-+ if (cur >= 8) {
-+ /* user has more channels than ch */
-+ matches = 0;
-+ break;
-+ }
-+ if (ch->speakers[7 - cur] != sp) {
-+ matches = 0;
-+ break;
-+ }
-+ remap[x] = cur;
-+ cur++;
-+ }
-+ for (x = cur; x < 8; x++) {
-+ if (ch->speakers[7 - x]) {
-+ /* ch has more channels than user */
-+ matches = 0;
-+ break;
-+ }
-+ }
-+ if (matches) {
-+ cea_chmap = ch->ca_index;
-+ break;
-+ }
-+ }
-+
-+ if (cea_chmap < 0)
-+ return -EINVAL;
-+
-+ /* don't change the layout if another substream is active */
-+ if (chip->opened != (1 << substream->number) && chip->cea_chmap != cea_chmap)
-+ return -EBUSY; /* unsure whether this is a good error code */
-+
-+ chip->cea_chmap = cea_chmap;
-+ for (i = 0; i < 8; i++)
-+ chip->map_channels[i] = remap[i];
-+ if (prepared)
-+ snd_bcm2835_pcm_prepare_again(substream);
-+ return 0;
-+}
-+
-+static int snd_bcm2835_add_chmap_ctl(bcm2835_chip_t * chip)
-+{
-+ struct snd_pcm_chmap *chmap;
-+ struct snd_kcontrol *kctl;
-+ int err, i;
-+
-+ err = snd_pcm_add_chmap_ctls(chip->pcm,
-+ SNDRV_PCM_STREAM_PLAYBACK,
-+ NULL, 8, 0, &chmap);
-+ if (err < 0)
-+ return err;
-+ /* override handlers */
-+ chmap->private_data = chip;
-+ kctl = chmap->kctl;
-+ for (i = 0; i < kctl->count; i++)
-+ kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
-+ kctl->get = snd_bcm2835_chmap_ctl_get;
-+ kctl->put = snd_bcm2835_chmap_ctl_put;
-+ kctl->tlv.c = snd_bcm2835_chmap_ctl_tlv;
-+ return 0;
-+}
-+
- int snd_bcm2835_new_ctl(bcm2835_chip_t * chip)
- {
- int err;
-@@ -313,6 +588,7 @@ int snd_bcm2835_new_ctl(bcm2835_chip_t *
- if (err < 0)
- return err;
- }
-+ snd_bcm2835_add_chmap_ctl(chip);
- for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_spdif); idx++) {
- err = snd_ctl_add(chip->card,
- snd_ctl_new1(&snd_bcm2835_spdif[idx], chip));
---- a/sound/arm/bcm2835-pcm.c
-+++ b/sound/arm/bcm2835-pcm.c
-@@ -231,6 +231,9 @@ static int snd_bcm2835_playback_open_gen
-
- chip->alsa_stream[idx] = alsa_stream;
-
-+ if (!chip->opened)
-+ chip->cea_chmap = -1;
-+
- chip->opened |= (1 << idx);
- alsa_stream->open = 1;
- alsa_stream->draining = 1;
-@@ -341,8 +344,7 @@ static int snd_bcm2835_pcm_hw_free(struc
- return snd_pcm_lib_free_pages(substream);
- }
-
--/* prepare callback */
--static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
-+int snd_bcm2835_pcm_prepare_again(struct snd_pcm_substream *substream)
- {
- bcm2835_chip_t *chip = snd_pcm_substream_chip(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
-@@ -350,8 +352,6 @@ static int snd_bcm2835_pcm_prepare(struc
- int channels;
- int err;
-
-- audio_info(" .. IN\n");
--
- /* notify the vchiq that it should enter spdif passthrough mode by
- * setting channels=0 (see
- * https://github.com/raspberrypi/linux/issues/528) */
-@@ -367,6 +367,20 @@ static int snd_bcm2835_pcm_prepare(struc
- audio_error(" error setting hw params\n");
- }
-
-+ return err;
-+}
-+
-+/* prepare callback */
-+static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
-+{
-+ bcm2835_chip_t *chip = snd_pcm_substream_chip(substream);
-+ struct snd_pcm_runtime *runtime = substream->runtime;
-+ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
-+
-+ audio_info(" .. IN\n");
-+
-+ snd_bcm2835_pcm_prepare_again(substream);
-+
- bcm2835_audio_setup(alsa_stream);
-
- /* in preparation of the stream, set the controls (volume level) of the stream */
---- a/sound/arm/bcm2835-vchiq.c
-+++ b/sound/arm/bcm2835-vchiq.c
-@@ -570,6 +570,8 @@ int bcm2835_audio_set_params(bcm2835_als
- VC_AUDIO_MSG_T m;
- AUDIO_INSTANCE_T *instance = alsa_stream->instance;
- int32_t success;
-+ uint32_t chmap_value;
-+ int i;
- int ret;
- LOG_DBG(" .. IN\n");
-
-@@ -593,10 +595,21 @@ int bcm2835_audio_set_params(bcm2835_als
-
- instance->result = -1;
-
-+ if (alsa_stream->chip->cea_chmap >= 0) {
-+ chmap_value = (unsigned)alsa_stream->chip->cea_chmap << 24;
-+ } else {
-+ chmap_value = 0; /* force stereo */
-+ for (i = 0; i < 8; i++)
-+ alsa_stream->chip->map_channels[i] = i;
-+ }
-+ for (i = 0; i < 8; i++)
-+ chmap_value |= alsa_stream->chip->map_channels[i] << (i * 3);
-+
- m.type = VC_AUDIO_MSG_TYPE_CONFIG;
- m.u.config.channels = channels;
- m.u.config.samplerate = samplerate;
- m.u.config.bps = bps;
-+ m.u.config.channelmap = chmap_value;
-
- /* Create the message available completion */
- init_completion(&instance->msg_avail_comp);
---- a/sound/arm/bcm2835.h
-+++ b/sound/arm/bcm2835.h
-@@ -107,6 +107,8 @@ typedef struct bcm2835_chip {
- int old_volume; /* stores the volume value whist muted */
- int dest;
- int mute;
-+ int cea_chmap; /* currently requested Audio InfoFrame Data Byte 4 */
-+ int map_channels[8];
-
- unsigned int opened;
- unsigned int spdif_status;
-@@ -149,6 +151,8 @@ int snd_bcm2835_new_ctl(bcm2835_chip_t *
- int snd_bcm2835_new_pcm(bcm2835_chip_t * chip);
- int snd_bcm2835_new_spdif_pcm(bcm2835_chip_t * chip);
-
-+int snd_bcm2835_pcm_prepare_again(struct snd_pcm_substream *substream);
-+
- int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream);
- int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream);
- int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
diff --git a/target/linux/brcm2708/patches-4.4/0132-bcm2835-access-controls-under-the-audio-mutex.patch b/target/linux/brcm2708/patches-4.4/0132-bcm2835-access-controls-under-the-audio-mutex.patch
deleted file mode 100644
index d6d9cf297c..0000000000
--- a/target/linux/brcm2708/patches-4.4/0132-bcm2835-access-controls-under-the-audio-mutex.patch
+++ /dev/null
@@ -1,237 +0,0 @@
-From 2a64337156d0f84537e04338b2ebd89eb6ec1f09 Mon Sep 17 00:00:00 2001
-From: wm4 <wm4@nowhere>
-Date: Wed, 13 Jan 2016 19:43:35 +0100
-Subject: [PATCH 132/170] bcm2835: access controls under the audio mutex
-
-I don't think the ALSA framework provides any kind of automatic
-synchronization within the control callbacks. We most likely need
-to ensure this manually, so add locking around all access to shared
-mutable data. In particular, bcm2835_audio_set_ctls() should
-probably always be called under our own audio lock.
----
- sound/arm/bcm2835-ctl.c | 74 +++++++++++++++++++++++++++++++++++++++++--------
- sound/arm/bcm2835-pcm.c | 4 +++
- 2 files changed, 66 insertions(+), 12 deletions(-)
-
---- a/sound/arm/bcm2835-ctl.c
-+++ b/sound/arm/bcm2835-ctl.c
-@@ -94,6 +94,9 @@ static int snd_bcm2835_ctl_get(struct sn
- {
- struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
-
-+ if (mutex_lock_interruptible(&chip->audio_mutex))
-+ return -EINTR;
-+
- BUG_ON(!chip && !(chip->avail_substreams & AVAIL_SUBSTREAMS_MASK));
-
- if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
-@@ -103,6 +106,7 @@ static int snd_bcm2835_ctl_get(struct sn
- else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
- ucontrol->value.integer.value[0] = chip->dest;
-
-+ mutex_unlock(&chip->audio_mutex);
- return 0;
- }
-
-@@ -112,11 +116,15 @@ static int snd_bcm2835_ctl_put(struct sn
- struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
- int changed = 0;
-
-+ if (mutex_lock_interruptible(&chip->audio_mutex))
-+ return -EINTR;
-+
- if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
- audio_info("Volume change attempted.. volume = %d new_volume = %d\n", chip->volume, (int)ucontrol->value.integer.value[0]);
- if (chip->mute == CTRL_VOL_MUTE) {
- /* changed = toggle_mute(chip, CTRL_VOL_UNMUTE); */
-- return 1; /* should return 0 to signify no change but the mixer takes this as the opposite sign (no idea why) */
-+ changed = 1; /* should return 0 to signify no change but the mixer takes this as the opposite sign (no idea why) */
-+ goto unlock;
- }
- if (changed
- || (ucontrol->value.integer.value[0] != chip2alsa(chip->volume))) {
-@@ -142,6 +150,8 @@ static int snd_bcm2835_ctl_put(struct sn
- printk(KERN_ERR "Failed to set ALSA controls..\n");
- }
-
-+unlock:
-+ mutex_unlock(&chip->audio_mutex);
- return changed;
- }
-
-@@ -198,10 +208,14 @@ static int snd_bcm2835_spdif_default_get
- struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
- int i;
-
-+ if (mutex_lock_interruptible(&chip->audio_mutex))
-+ return -EINTR;
-+
- for (i = 0; i < 4; i++)
- ucontrol->value.iec958.status[i] =
- (chip->spdif_status >> (i * 8)) && 0xff;
-
-+ mutex_unlock(&chip->audio_mutex);
- return 0;
- }
-
-@@ -212,12 +226,16 @@ static int snd_bcm2835_spdif_default_put
- unsigned int val = 0;
- int i, change;
-
-+ if (mutex_lock_interruptible(&chip->audio_mutex))
-+ return -EINTR;
-+
- for (i = 0; i < 4; i++)
- val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
-
- change = val != chip->spdif_status;
- chip->spdif_status = val;
-
-+ mutex_unlock(&chip->audio_mutex);
- return change;
- }
-
-@@ -253,9 +271,14 @@ static int snd_bcm2835_spdif_stream_get(
- struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
- int i;
-
-+ if (mutex_lock_interruptible(&chip->audio_mutex))
-+ return -EINTR;
-+
- for (i = 0; i < 4; i++)
- ucontrol->value.iec958.status[i] =
- (chip->spdif_status >> (i * 8)) & 0xff;
-+
-+ mutex_unlock(&chip->audio_mutex);
- return 0;
- }
-
-@@ -266,11 +289,15 @@ static int snd_bcm2835_spdif_stream_put(
- unsigned int val = 0;
- int i, change;
-
-+ if (mutex_lock_interruptible(&chip->audio_mutex))
-+ return -EINTR;
-+
- for (i = 0; i < 4; i++)
- val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
- change = val != chip->spdif_status;
- chip->spdif_status = val;
-
-+ mutex_unlock(&chip->audio_mutex);
- return change;
- }
-
-@@ -454,11 +481,17 @@ static int snd_bcm2835_chmap_ctl_get(str
- unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
- struct snd_pcm_substream *substream = snd_pcm_chmap_substream(info, idx);
- struct cea_channel_speaker_allocation *ch = NULL;
-+ int res = 0;
- int cur = 0;
- int i;
-
-- if (!substream || !substream->runtime)
-- return -ENODEV;
-+ if (mutex_lock_interruptible(&chip->audio_mutex))
-+ return -EINTR;
-+
-+ if (!substream || !substream->runtime) {
-+ res = -ENODEV;
-+ goto unlock;
-+ }
-
- for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
- if (channel_allocations[i].ca_index == chip->cea_chmap)
-@@ -476,7 +509,10 @@ static int snd_bcm2835_chmap_ctl_get(str
- }
- while (cur < 8)
- ucontrol->value.integer.value[cur++] = SNDRV_CHMAP_NA;
-- return 0;
-+
-+unlock:
-+ mutex_unlock(&chip->audio_mutex);
-+ return res;
- }
-
- static int snd_bcm2835_chmap_ctl_put(struct snd_kcontrol *kcontrol,
-@@ -487,10 +523,16 @@ static int snd_bcm2835_chmap_ctl_put(str
- unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
- struct snd_pcm_substream *substream = snd_pcm_chmap_substream(info, idx);
- int i, prepared = 0, cea_chmap = -1;
-+ int res = 0;
- int remap[8];
-
-- if (!substream || !substream->runtime)
-- return -ENODEV;
-+ if (mutex_lock_interruptible(&chip->audio_mutex))
-+ return -EINTR;
-+
-+ if (!substream || !substream->runtime) {
-+ res = -ENODEV;
-+ goto unlock;
-+ }
-
- switch (substream->runtime->status->state) {
- case SNDRV_PCM_STATE_OPEN:
-@@ -500,7 +542,8 @@ static int snd_bcm2835_chmap_ctl_put(str
- prepared = 1;
- break;
- default:
-- return -EBUSY;
-+ res = -EBUSY;
-+ goto unlock;
- }
-
- for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
-@@ -538,19 +581,26 @@ static int snd_bcm2835_chmap_ctl_put(str
- }
- }
-
-- if (cea_chmap < 0)
-- return -EINVAL;
-+ if (cea_chmap < 0) {
-+ res = -EINVAL;
-+ goto unlock;
-+ }
-
- /* don't change the layout if another substream is active */
-- if (chip->opened != (1 << substream->number) && chip->cea_chmap != cea_chmap)
-- return -EBUSY; /* unsure whether this is a good error code */
-+ if (chip->opened != (1 << substream->number) && chip->cea_chmap != cea_chmap) {
-+ res = -EBUSY; /* unsure whether this is a good error code */
-+ goto unlock;
-+ }
-
- chip->cea_chmap = cea_chmap;
- for (i = 0; i < 8; i++)
- chip->map_channels[i] = remap[i];
- if (prepared)
- snd_bcm2835_pcm_prepare_again(substream);
-- return 0;
-+
-+unlock:
-+ mutex_unlock(&chip->audio_mutex);
-+ return res;
- }
-
- static int snd_bcm2835_add_chmap_ctl(bcm2835_chip_t * chip)
---- a/sound/arm/bcm2835-pcm.c
-+++ b/sound/arm/bcm2835-pcm.c
-@@ -379,6 +379,9 @@ static int snd_bcm2835_pcm_prepare(struc
-
- audio_info(" .. IN\n");
-
-+ if (mutex_lock_interruptible(&chip->audio_mutex))
-+ return -EINTR;
-+
- snd_bcm2835_pcm_prepare_again(substream);
-
- bcm2835_audio_setup(alsa_stream);
-@@ -401,6 +404,7 @@ static int snd_bcm2835_pcm_prepare(struc
- alsa_stream->buffer_size, alsa_stream->period_size,
- alsa_stream->pos, runtime->frame_bits);
-
-+ mutex_unlock(&chip->audio_mutex);
- audio_info(" .. OUT\n");
- return 0;
- }
diff --git a/target/linux/brcm2708/patches-4.4/0132-bcm2835-only-allow-stereo-if-analogue-jack-is-select.patch b/target/linux/brcm2708/patches-4.4/0132-bcm2835-only-allow-stereo-if-analogue-jack-is-select.patch
new file mode 100644
index 0000000000..64a3fff882
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0132-bcm2835-only-allow-stereo-if-analogue-jack-is-select.patch
@@ -0,0 +1,62 @@
+From 1a2d7c95e3ee81f352345ecf1f65944739c7cf53 Mon Sep 17 00:00:00 2001
+From: wm4 <wm4@nowhere>
+Date: Wed, 13 Jan 2016 19:44:24 +0100
+Subject: [PATCH 132/381] bcm2835: only allow stereo if analogue jack is
+ selected
+
+Sending more than 2 channels to videocore while outputting to analogue
+mysteriously outputs heavy artifacts. So just paint it over with a
+hack: if analogue is explicitly selected as destination, do not
+reporting support for anything other than stereo.
+
+I'm not sure how to deal with the auto case (destination 0). There's
+probably way to retrieve this and even to listen to plug events, but
+I didn't find one yet, and it's probably not worth the trouble. Just
+don't use this setting, I guess. Unless you like noise.
+
+Changing the setting while an audio stream is active also doesn't
+work properly. We could probably interrupt running streams by
+returning ENODEV or using kernel hotplug stuff (maybe), but that
+also doesn't seem worth the trouble.
+---
+ sound/arm/bcm2835-ctl.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/sound/arm/bcm2835-ctl.c
++++ b/sound/arm/bcm2835-ctl.c
+@@ -423,9 +423,16 @@ static struct cea_channel_speaker_alloca
+ { .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } },
+ };
+
++static int uses_analogue(bcm2835_chip_t *chip)
++{
++ return chip->dest == 1;
++}
++
+ static int snd_bcm2835_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag,
+ unsigned int size, unsigned int __user *tlv)
+ {
++ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
++ bcm2835_chip_t *chip = info->private_data;
+ unsigned int __user *dst;
+ int count = 0;
+ int i;
+@@ -442,6 +449,9 @@ static int snd_bcm2835_chmap_ctl_tlv(str
+ int chs_bytes;
+ int c;
+
++ if (i > 0 && uses_analogue(chip))
++ break;
++
+ for (c = 0; c < 8; c++) {
+ if (ch->speakers[c])
+ num_chs++;
+@@ -552,6 +562,8 @@ static int snd_bcm2835_chmap_ctl_put(str
+ int matches = 1;
+ int cur = 0;
+ int x;
++ if (i > 0 && uses_analogue(chip))
++ break;
+ memset(remap, 0, sizeof(remap));
+ for (x = 0; x < substream->runtime->channels; x++) {
+ int sp = ucontrol->value.integer.value[x];
diff --git a/target/linux/brcm2708/patches-4.4/0133-bcm2835-always-use-2-4-8-channels-for-multichannel-l.patch b/target/linux/brcm2708/patches-4.4/0133-bcm2835-always-use-2-4-8-channels-for-multichannel-l.patch
deleted file mode 100644
index 72304988ef..0000000000
--- a/target/linux/brcm2708/patches-4.4/0133-bcm2835-always-use-2-4-8-channels-for-multichannel-l.patch
+++ /dev/null
@@ -1,139 +0,0 @@
-From 6e781f631f7e23f7d88256d020d83950c9bf213a Mon Sep 17 00:00:00 2001
-From: wm4 <wm4@nowhere>
-Date: Wed, 13 Jan 2016 19:44:03 +0100
-Subject: [PATCH 133/170] bcm2835: always use 2/4/8 channels for multichannel
- layouts
-
-Pad the unused channels with NA. This means userspace needs to write
-additional, silent padding channels, which is not ideal, but better
-than noise.
-
-Works around noise at the following channel counts: 3, 5, 6, 7
----
- sound/arm/bcm2835-ctl.c | 89 +++++++++++++++++++++++++------------------------
- 1 file changed, 45 insertions(+), 44 deletions(-)
-
---- a/sound/arm/bcm2835-ctl.c
-+++ b/sound/arm/bcm2835-ctl.c
-@@ -349,6 +349,7 @@ struct cea_channel_speaker_allocation {
- #define FRW SNDRV_CHMAP_FRW
- #define TC SNDRV_CHMAP_TC
- #define FCH SNDRV_CHMAP_TFC
-+#define NA SNDRV_CHMAP_NA
-
- /*
- * CEA-861 channel maps
-@@ -356,69 +357,69 @@ struct cea_channel_speaker_allocation {
- * Stolen from sound/pci/hda/patch_hdmi.c
- * (unlike the source, this uses SNDRV_* constants directly, as by the
- * map_tables array in patch_hdmi.c)
-- * Unknown entries use 0, which unfortunately is SNDRV_CHMAP_UNKNOWN instead
-- * of SNDRV_CHMAP_NA.
-+ * Entries which do not have a physical output channel use 0. Entries which
-+ * require userspace to output silence use NA (SNDRV_CHMAP_NA).
- */
- static struct cea_channel_speaker_allocation channel_allocations[] = {
- /* channel: 7 6 5 4 3 2 1 0 */
- { .ca_index = 0x00, .speakers = { 0, 0, 0, 0, 0, 0, FR, FL } },
- /* 2.1 */
--{ .ca_index = 0x01, .speakers = { 0, 0, 0, 0, 0, LFE, FR, FL } },
-+{ .ca_index = 0x01, .speakers = { 0, 0, 0, 0, NA, LFE, FR, FL } },
- /* Dolby Surround */
--{ .ca_index = 0x02, .speakers = { 0, 0, 0, 0, FC, 0, FR, FL } },
-+{ .ca_index = 0x02, .speakers = { 0, 0, 0, 0, FC, NA, FR, FL } },
- /* surround40 */
--{ .ca_index = 0x08, .speakers = { 0, 0, RR, RL, 0, 0, FR, FL } },
-+{ .ca_index = 0x08, .speakers = { NA, NA, RR, RL, NA, NA, FR, FL } },
- /* surround41 */
--{ .ca_index = 0x09, .speakers = { 0, 0, RR, RL, 0, LFE, FR, FL } },
-+{ .ca_index = 0x09, .speakers = { NA, NA, RR, RL, NA, LFE, FR, FL } },
- /* surround50 */
--{ .ca_index = 0x0a, .speakers = { 0, 0, RR, RL, FC, 0, FR, FL } },
-+{ .ca_index = 0x0a, .speakers = { NA, NA, RR, RL, FC, NA, FR, FL } },
- /* surround51 */
--{ .ca_index = 0x0b, .speakers = { 0, 0, RR, RL, FC, LFE, FR, FL } },
-+{ .ca_index = 0x0b, .speakers = { NA, NA, RR, RL, FC, LFE, FR, FL } },
- /* 6.1 */
--{ .ca_index = 0x0f, .speakers = { 0, RC, RR, RL, FC, LFE, FR, FL } },
-+{ .ca_index = 0x0f, .speakers = { NA, RC, RR, RL, FC, LFE, FR, FL } },
- /* surround71 */
- { .ca_index = 0x13, .speakers = { RRC, RLC, RR, RL, FC, LFE, FR, FL } },
-
--{ .ca_index = 0x03, .speakers = { 0, 0, 0, 0, FC, LFE, FR, FL } },
--{ .ca_index = 0x04, .speakers = { 0, 0, 0, RC, 0, 0, FR, FL } },
--{ .ca_index = 0x05, .speakers = { 0, 0, 0, RC, 0, LFE, FR, FL } },
--{ .ca_index = 0x06, .speakers = { 0, 0, 0, RC, FC, 0, FR, FL } },
--{ .ca_index = 0x07, .speakers = { 0, 0, 0, RC, FC, LFE, FR, FL } },
--{ .ca_index = 0x0c, .speakers = { 0, RC, RR, RL, 0, 0, FR, FL } },
--{ .ca_index = 0x0d, .speakers = { 0, RC, RR, RL, 0, LFE, FR, FL } },
--{ .ca_index = 0x0e, .speakers = { 0, RC, RR, RL, FC, 0, FR, FL } },
--{ .ca_index = 0x10, .speakers = { RRC, RLC, RR, RL, 0, 0, FR, FL } },
--{ .ca_index = 0x11, .speakers = { RRC, RLC, RR, RL, 0, LFE, FR, FL } },
--{ .ca_index = 0x12, .speakers = { RRC, RLC, RR, RL, FC, 0, FR, FL } },
--{ .ca_index = 0x14, .speakers = { FRC, FLC, 0, 0, 0, 0, FR, FL } },
--{ .ca_index = 0x15, .speakers = { FRC, FLC, 0, 0, 0, LFE, FR, FL } },
--{ .ca_index = 0x16, .speakers = { FRC, FLC, 0, 0, FC, 0, FR, FL } },
--{ .ca_index = 0x17, .speakers = { FRC, FLC, 0, 0, FC, LFE, FR, FL } },
--{ .ca_index = 0x18, .speakers = { FRC, FLC, 0, RC, 0, 0, FR, FL } },
--{ .ca_index = 0x19, .speakers = { FRC, FLC, 0, RC, 0, LFE, FR, FL } },
--{ .ca_index = 0x1a, .speakers = { FRC, FLC, 0, RC, FC, 0, FR, FL } },
--{ .ca_index = 0x1b, .speakers = { FRC, FLC, 0, RC, FC, LFE, FR, FL } },
--{ .ca_index = 0x1c, .speakers = { FRC, FLC, RR, RL, 0, 0, FR, FL } },
--{ .ca_index = 0x1d, .speakers = { FRC, FLC, RR, RL, 0, LFE, FR, FL } },
--{ .ca_index = 0x1e, .speakers = { FRC, FLC, RR, RL, FC, 0, FR, FL } },
-+{ .ca_index = 0x03, .speakers = { NA, NA, NA, NA, FC, LFE, FR, FL } },
-+{ .ca_index = 0x04, .speakers = { NA, NA, NA, RC, NA, NA, FR, FL } },
-+{ .ca_index = 0x05, .speakers = { NA, NA, NA, RC, NA, LFE, FR, FL } },
-+{ .ca_index = 0x06, .speakers = { NA, NA, NA, RC, FC, NA, FR, FL } },
-+{ .ca_index = 0x07, .speakers = { NA, NA, NA, RC, FC, LFE, FR, FL } },
-+{ .ca_index = 0x0c, .speakers = { NA, RC, RR, RL, NA, NA, FR, FL } },
-+{ .ca_index = 0x0d, .speakers = { NA, RC, RR, RL, NA, LFE, FR, FL } },
-+{ .ca_index = 0x0e, .speakers = { NA, RC, RR, RL, FC, NA, FR, FL } },
-+{ .ca_index = 0x10, .speakers = { RRC, RLC, RR, RL, NA, NA, FR, FL } },
-+{ .ca_index = 0x11, .speakers = { RRC, RLC, RR, RL, NA, LFE, FR, FL } },
-+{ .ca_index = 0x12, .speakers = { RRC, RLC, RR, RL, FC, NA, FR, FL } },
-+{ .ca_index = 0x14, .speakers = { FRC, FLC, NA, NA, NA, NA, FR, FL } },
-+{ .ca_index = 0x15, .speakers = { FRC, FLC, NA, NA, NA, LFE, FR, FL } },
-+{ .ca_index = 0x16, .speakers = { FRC, FLC, NA, NA, FC, NA, FR, FL } },
-+{ .ca_index = 0x17, .speakers = { FRC, FLC, NA, NA, FC, LFE, FR, FL } },
-+{ .ca_index = 0x18, .speakers = { FRC, FLC, NA, RC, NA, NA, FR, FL } },
-+{ .ca_index = 0x19, .speakers = { FRC, FLC, NA, RC, NA, LFE, FR, FL } },
-+{ .ca_index = 0x1a, .speakers = { FRC, FLC, NA, RC, FC, NA, FR, FL } },
-+{ .ca_index = 0x1b, .speakers = { FRC, FLC, NA, RC, FC, LFE, FR, FL } },
-+{ .ca_index = 0x1c, .speakers = { FRC, FLC, RR, RL, NA, NA, FR, FL } },
-+{ .ca_index = 0x1d, .speakers = { FRC, FLC, RR, RL, NA, LFE, FR, FL } },
-+{ .ca_index = 0x1e, .speakers = { FRC, FLC, RR, RL, FC, NA, FR, FL } },
- { .ca_index = 0x1f, .speakers = { FRC, FLC, RR, RL, FC, LFE, FR, FL } },
--{ .ca_index = 0x20, .speakers = { 0, FCH, RR, RL, FC, 0, FR, FL } },
--{ .ca_index = 0x21, .speakers = { 0, FCH, RR, RL, FC, LFE, FR, FL } },
--{ .ca_index = 0x22, .speakers = { TC, 0, RR, RL, FC, 0, FR, FL } },
--{ .ca_index = 0x23, .speakers = { TC, 0, RR, RL, FC, LFE, FR, FL } },
--{ .ca_index = 0x24, .speakers = { FRH, FLH, RR, RL, 0, 0, FR, FL } },
--{ .ca_index = 0x25, .speakers = { FRH, FLH, RR, RL, 0, LFE, FR, FL } },
--{ .ca_index = 0x26, .speakers = { FRW, FLW, RR, RL, 0, 0, FR, FL } },
--{ .ca_index = 0x27, .speakers = { FRW, FLW, RR, RL, 0, LFE, FR, FL } },
--{ .ca_index = 0x28, .speakers = { TC, RC, RR, RL, FC, 0, FR, FL } },
-+{ .ca_index = 0x20, .speakers = { NA, FCH, RR, RL, FC, NA, FR, FL } },
-+{ .ca_index = 0x21, .speakers = { NA, FCH, RR, RL, FC, LFE, FR, FL } },
-+{ .ca_index = 0x22, .speakers = { TC, NA, RR, RL, FC, NA, FR, FL } },
-+{ .ca_index = 0x23, .speakers = { TC, NA, RR, RL, FC, LFE, FR, FL } },
-+{ .ca_index = 0x24, .speakers = { FRH, FLH, RR, RL, NA, NA, FR, FL } },
-+{ .ca_index = 0x25, .speakers = { FRH, FLH, RR, RL, NA, LFE, FR, FL } },
-+{ .ca_index = 0x26, .speakers = { FRW, FLW, RR, RL, NA, NA, FR, FL } },
-+{ .ca_index = 0x27, .speakers = { FRW, FLW, RR, RL, NA, LFE, FR, FL } },
-+{ .ca_index = 0x28, .speakers = { TC, RC, RR, RL, FC, NA, FR, FL } },
- { .ca_index = 0x29, .speakers = { TC, RC, RR, RL, FC, LFE, FR, FL } },
--{ .ca_index = 0x2a, .speakers = { FCH, RC, RR, RL, FC, 0, FR, FL } },
-+{ .ca_index = 0x2a, .speakers = { FCH, RC, RR, RL, FC, NA, FR, FL } },
- { .ca_index = 0x2b, .speakers = { FCH, RC, RR, RL, FC, LFE, FR, FL } },
--{ .ca_index = 0x2c, .speakers = { TC, FCH, RR, RL, FC, 0, FR, FL } },
-+{ .ca_index = 0x2c, .speakers = { TC, FCH, RR, RL, FC, NA, FR, FL } },
- { .ca_index = 0x2d, .speakers = { TC, FCH, RR, RL, FC, LFE, FR, FL } },
--{ .ca_index = 0x2e, .speakers = { FRH, FLH, RR, RL, FC, 0, FR, FL } },
-+{ .ca_index = 0x2e, .speakers = { FRH, FLH, RR, RL, FC, NA, FR, FL } },
- { .ca_index = 0x2f, .speakers = { FRH, FLH, RR, RL, FC, LFE, FR, FL } },
--{ .ca_index = 0x30, .speakers = { FRW, FLW, RR, RL, FC, 0, FR, FL } },
-+{ .ca_index = 0x30, .speakers = { FRW, FLW, RR, RL, FC, NA, FR, FL } },
- { .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } },
- };
-
diff --git a/target/linux/brcm2708/patches-4.4/0133-bcm2835-interpolate-audio-delay.patch b/target/linux/brcm2708/patches-4.4/0133-bcm2835-interpolate-audio-delay.patch
new file mode 100644
index 0000000000..6c3bc9d8e9
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0133-bcm2835-interpolate-audio-delay.patch
@@ -0,0 +1,90 @@
+From dffcc96ee1cf290f59191c715076c866e6019c17 Mon Sep 17 00:00:00 2001
+From: wm4 <wm4@nowhere>
+Date: Wed, 13 Jan 2016 19:44:47 +0100
+Subject: [PATCH 133/381] bcm2835: interpolate audio delay
+
+It appears the GPU only sends us a message all 10ms to update
+the playback progress. Other than this, the playback position
+(what SNDRV_PCM_IOCTL_DELAY will return) is not updated at all.
+Userspace will see jitter up to 10ms in the audio position.
+
+Make this a bit nicer for userspace by interpolating the
+position using the CPU clock.
+
+I'm not sure if setting snd_pcm_runtime.delay is the right
+approach for this. Or if there is maybe an already existing
+mechanism for position interpolation in the ALSA core.
+
+I only set SNDRV_PCM_INFO_BATCH because this appears to remove
+at least one situation snd_pcm_runtime.delay is used, so I have
+to worry less in which place I have to update this field, or
+how it interacts with the rest of ALSA.
+
+In the future, it might be nice to use VC_AUDIO_MSG_TYPE_LATENCY.
+One problem is that it requires sending a videocore message, and
+waiting for a reply, which could make the implementation much
+harder due to locking and synchronization requirements.
+---
+ sound/arm/bcm2835-pcm.c | 12 +++++++++++-
+ sound/arm/bcm2835.h | 1 +
+ 2 files changed, 12 insertions(+), 1 deletion(-)
+
+--- a/sound/arm/bcm2835-pcm.c
++++ b/sound/arm/bcm2835-pcm.c
+@@ -25,7 +25,7 @@
+ /* hardware definition */
+ static struct snd_pcm_hardware snd_bcm2835_playback_hw = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+- SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
++ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BATCH),
+ .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
+ .rate_min = 8000,
+@@ -99,6 +99,8 @@ static irqreturn_t bcm2835_playback_fifo
+ alsa_stream->pos %= alsa_stream->buffer_size;
+ }
+
++ alsa_stream->interpolate_start = ktime_get_ns();
++
+ if (alsa_stream->substream) {
+ if (new_period)
+ snd_pcm_period_elapsed(alsa_stream->substream);
+@@ -399,6 +401,7 @@ static int snd_bcm2835_pcm_prepare(struc
+ alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
+ alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
+ alsa_stream->pos = 0;
++ alsa_stream->interpolate_start = ktime_get_ns();
+
+ audio_debug("buffer_size=%d, period_size=%d pos=%d frame_bits=%d\n",
+ alsa_stream->buffer_size, alsa_stream->period_size,
+@@ -495,6 +498,7 @@ snd_bcm2835_pcm_pointer(struct snd_pcm_s
+ {
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
++ u64 now = ktime_get_ns();
+
+ audio_info(" .. IN\n");
+
+@@ -503,6 +507,12 @@ snd_bcm2835_pcm_pointer(struct snd_pcm_s
+ frames_to_bytes(runtime, runtime->control->appl_ptr),
+ alsa_stream->pos);
+
++ /* Give userspace better delay reporting by interpolating between GPU
++ * notifications, assuming audio speed is close enough to the clock
++ * used for ktime */
++ if (alsa_stream->interpolate_start && alsa_stream->interpolate_start < now)
++ runtime->delay = -(int)div_u64((now - alsa_stream->interpolate_start) * runtime->rate, 1000000000);
++
+ audio_info(" .. OUT\n");
+ return snd_pcm_indirect_playback_pointer(substream,
+ &alsa_stream->pcm_indirect,
+--- a/sound/arm/bcm2835.h
++++ b/sound/arm/bcm2835.h
+@@ -137,6 +137,7 @@ typedef struct bcm2835_alsa_stream {
+ unsigned int pos;
+ unsigned int buffer_size;
+ unsigned int period_size;
++ u64 interpolate_start;
+
+ uint32_t enable_fifo_irq;
+ irq_handler_t fifo_irq_handler;
diff --git a/target/linux/brcm2708/patches-4.4/0134-bcm2835-only-allow-stereo-if-analogue-jack-is-select.patch b/target/linux/brcm2708/patches-4.4/0134-bcm2835-only-allow-stereo-if-analogue-jack-is-select.patch
deleted file mode 100644
index 76a0e01ad1..0000000000
--- a/target/linux/brcm2708/patches-4.4/0134-bcm2835-only-allow-stereo-if-analogue-jack-is-select.patch
+++ /dev/null
@@ -1,62 +0,0 @@
-From aaa2a41f44a0fc141b9a983a5f9f30bb8b6dbc8b Mon Sep 17 00:00:00 2001
-From: wm4 <wm4@nowhere>
-Date: Wed, 13 Jan 2016 19:44:24 +0100
-Subject: [PATCH 134/170] bcm2835: only allow stereo if analogue jack is
- selected
-
-Sending more than 2 channels to videocore while outputting to analogue
-mysteriously outputs heavy artifacts. So just paint it over with a
-hack: if analogue is explicitly selected as destination, do not
-reporting support for anything other than stereo.
-
-I'm not sure how to deal with the auto case (destination 0). There's
-probably way to retrieve this and even to listen to plug events, but
-I didn't find one yet, and it's probably not worth the trouble. Just
-don't use this setting, I guess. Unless you like noise.
-
-Changing the setting while an audio stream is active also doesn't
-work properly. We could probably interrupt running streams by
-returning ENODEV or using kernel hotplug stuff (maybe), but that
-also doesn't seem worth the trouble.
----
- sound/arm/bcm2835-ctl.c | 12 ++++++++++++
- 1 file changed, 12 insertions(+)
-
---- a/sound/arm/bcm2835-ctl.c
-+++ b/sound/arm/bcm2835-ctl.c
-@@ -423,9 +423,16 @@ static struct cea_channel_speaker_alloca
- { .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } },
- };
-
-+static int uses_analogue(bcm2835_chip_t *chip)
-+{
-+ return chip->dest == 1;
-+}
-+
- static int snd_bcm2835_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag,
- unsigned int size, unsigned int __user *tlv)
- {
-+ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
-+ bcm2835_chip_t *chip = info->private_data;
- unsigned int __user *dst;
- int count = 0;
- int i;
-@@ -442,6 +449,9 @@ static int snd_bcm2835_chmap_ctl_tlv(str
- int chs_bytes;
- int c;
-
-+ if (i > 0 && uses_analogue(chip))
-+ break;
-+
- for (c = 0; c < 8; c++) {
- if (ch->speakers[c])
- num_chs++;
-@@ -552,6 +562,8 @@ static int snd_bcm2835_chmap_ctl_put(str
- int matches = 1;
- int cur = 0;
- int x;
-+ if (i > 0 && uses_analogue(chip))
-+ break;
- memset(remap, 0, sizeof(remap));
- for (x = 0; x < substream->runtime->channels; x++) {
- int sp = ucontrol->value.integer.value[x];
diff --git a/target/linux/brcm2708/patches-4.4/0134-bcm2835-sdhost-Add-workaround-for-odd-behaviour-on-s.patch b/target/linux/brcm2708/patches-4.4/0134-bcm2835-sdhost-Add-workaround-for-odd-behaviour-on-s.patch
new file mode 100644
index 0000000000..3b1d14c738
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0134-bcm2835-sdhost-Add-workaround-for-odd-behaviour-on-s.patch
@@ -0,0 +1,137 @@
+From 3162c03da716f865fb9b766c8bd7d1dac0386f88 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Tue, 19 Jan 2016 17:16:38 +0000
+Subject: [PATCH 134/381] bcm2835-sdhost: Add workaround for odd behaviour on
+ some cards
+
+For reasons not understood, the sdhost driver fails when reading
+sectors very near the end of some SD cards. The problem could
+be related to the similar issue that reading the final sector
+of any card as part of a multiple read never completes, and the
+workaround is an extension of the mechanism introduced to solve
+that problem which ensures those sectors are always read singly.
+---
+ drivers/mmc/host/bcm2835-sdhost.c | 61 +++++++++++++++++++++++++++++++++------
+ 1 file changed, 52 insertions(+), 9 deletions(-)
+
+--- a/drivers/mmc/host/bcm2835-sdhost.c
++++ b/drivers/mmc/host/bcm2835-sdhost.c
+@@ -173,6 +173,9 @@ struct bcm2835_host {
+ u32 overclock_50; /* frequency to use when 50MHz is requested (in MHz) */
+ u32 overclock; /* Current frequency if overclocked, else zero */
+ u32 pio_limit; /* Maximum block count for PIO (0 = always DMA) */
++
++ u32 sectors; /* Cached card size in sectors */
++ u32 single_read_sectors[8];
+ };
+
+
+@@ -277,6 +280,9 @@ static void bcm2835_sdhost_reset_interna
+ {
+ u32 temp;
+
++ if (host->debug)
++ pr_info("%s: reset\n", mmc_hostname(host->mmc));
++
+ bcm2835_sdhost_set_power(host, false);
+
+ bcm2835_sdhost_write(host, 0, SDCMD);
+@@ -299,6 +305,8 @@ static void bcm2835_sdhost_reset_interna
+ bcm2835_sdhost_set_power(host, true);
+ mdelay(10);
+ host->clock = 0;
++ host->sectors = 0;
++ host->single_read_sectors[0] = ~0;
+ bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
+ bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
+ mmiowb();
+@@ -309,8 +317,6 @@ static void bcm2835_sdhost_reset(struct
+ {
+ struct bcm2835_host *host = mmc_priv(mmc);
+ unsigned long flags;
+- if (host->debug)
+- pr_info("%s: reset\n", mmc_hostname(mmc));
+ spin_lock_irqsave(&host->lock, flags);
+
+ bcm2835_sdhost_reset_internal(host);
+@@ -676,6 +682,32 @@ static void bcm2835_sdhost_prepare_data(
+ host->flush_fifo = 0;
+ host->data->bytes_xfered = 0;
+
++ if (!host->sectors && host->mmc->card)
++ {
++ struct mmc_card *card = host->mmc->card;
++ if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
++ /*
++ * The EXT_CSD sector count is in number of 512 byte
++ * sectors.
++ */
++ host->sectors = card->ext_csd.sectors;
++ pr_err("%s: using ext_csd!\n", mmc_hostname(host->mmc));
++ } else {
++ /*
++ * The CSD capacity field is in units of read_blkbits.
++ * set_capacity takes units of 512 bytes.
++ */
++ host->sectors = card->csd.capacity <<
++ (card->csd.read_blkbits - 9);
++ }
++ host->single_read_sectors[0] = host->sectors - 65;
++ host->single_read_sectors[1] = host->sectors - 64;
++ host->single_read_sectors[2] = host->sectors - 33;
++ host->single_read_sectors[3] = host->sectors - 32;
++ host->single_read_sectors[4] = host->sectors - 1;
++ host->single_read_sectors[5] = ~0; /* Safety net */
++ }
++
+ host->use_dma = host->have_dma && (data->blocks > host->pio_limit);
+ if (!host->use_dma) {
+ int flags;
+@@ -1246,6 +1278,10 @@ static u32 bcm2835_sdhost_block_irq(stru
+
+ bcm2835_sdhost_finish_data(host);
+ } else {
++ /* Reset the timer */
++ mod_timer(&host->pio_timer,
++ jiffies + host->pio_timeout);
++
+ bcm2835_sdhost_transfer_pio(host);
+
+ /* Reset the timer */
+@@ -1450,8 +1486,8 @@ void bcm2835_sdhost_set_clock(struct bcm
+ host->cdiv = div;
+ bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
+
+- /* Set the timeout to 500ms */
+- bcm2835_sdhost_write(host, host->mmc->actual_clock/2, SDTOUT);
++ /* Set the timeout to 250ms */
++ bcm2835_sdhost_write(host, host->mmc->actual_clock/4, SDTOUT);
+
+ if (host->debug)
+ pr_info("%s: clock=%d -> max_clk=%d, cdiv=%x (actual clock %d)\n",
+@@ -1566,13 +1602,20 @@ static int bcm2835_sdhost_multi_io_quirk
+ reading the final sector of the card as part of a multiple read
+ problematic. Detect that case and shorten the read accordingly.
+ */
+- /* csd.capacity is in weird units - convert to sectors */
+- u32 card_sectors = (card->csd.capacity << (card->csd.read_blkbits - 9));
++ struct bcm2835_host *host;
++
++ host = mmc_priv(card->host);
+
+- if ((direction == MMC_DATA_READ) &&
+- ((blk_pos + blk_size) == card_sectors))
+- blk_size--;
++ if (direction == MMC_DATA_READ)
++ {
++ int i;
++ int sector;
++ for (i = 0; blk_pos > (sector = host->single_read_sectors[i]); i++)
++ continue;
+
++ if ((blk_pos + blk_size) > sector)
++ blk_size = (blk_pos == sector) ? 1 : (sector - blk_pos);
++ }
+ return blk_size;
+ }
+
diff --git a/target/linux/brcm2708/patches-4.4/0135-bcm2835-interpolate-audio-delay.patch b/target/linux/brcm2708/patches-4.4/0135-bcm2835-interpolate-audio-delay.patch
deleted file mode 100644
index 1c1724e3f6..0000000000
--- a/target/linux/brcm2708/patches-4.4/0135-bcm2835-interpolate-audio-delay.patch
+++ /dev/null
@@ -1,90 +0,0 @@
-From 2c967fa0f5b0d10c86c796098574ba09ffe66cd5 Mon Sep 17 00:00:00 2001
-From: wm4 <wm4@nowhere>
-Date: Wed, 13 Jan 2016 19:44:47 +0100
-Subject: [PATCH 135/170] bcm2835: interpolate audio delay
-
-It appears the GPU only sends us a message all 10ms to update
-the playback progress. Other than this, the playback position
-(what SNDRV_PCM_IOCTL_DELAY will return) is not updated at all.
-Userspace will see jitter up to 10ms in the audio position.
-
-Make this a bit nicer for userspace by interpolating the
-position using the CPU clock.
-
-I'm not sure if setting snd_pcm_runtime.delay is the right
-approach for this. Or if there is maybe an already existing
-mechanism for position interpolation in the ALSA core.
-
-I only set SNDRV_PCM_INFO_BATCH because this appears to remove
-at least one situation snd_pcm_runtime.delay is used, so I have
-to worry less in which place I have to update this field, or
-how it interacts with the rest of ALSA.
-
-In the future, it might be nice to use VC_AUDIO_MSG_TYPE_LATENCY.
-One problem is that it requires sending a videocore message, and
-waiting for a reply, which could make the implementation much
-harder due to locking and synchronization requirements.
----
- sound/arm/bcm2835-pcm.c | 12 +++++++++++-
- sound/arm/bcm2835.h | 1 +
- 2 files changed, 12 insertions(+), 1 deletion(-)
-
---- a/sound/arm/bcm2835-pcm.c
-+++ b/sound/arm/bcm2835-pcm.c
-@@ -25,7 +25,7 @@
- /* hardware definition */
- static struct snd_pcm_hardware snd_bcm2835_playback_hw = {
- .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
-- SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
-+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BATCH),
- .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
- .rate_min = 8000,
-@@ -99,6 +99,8 @@ static irqreturn_t bcm2835_playback_fifo
- alsa_stream->pos %= alsa_stream->buffer_size;
- }
-
-+ alsa_stream->interpolate_start = ktime_get_ns();
-+
- if (alsa_stream->substream) {
- if (new_period)
- snd_pcm_period_elapsed(alsa_stream->substream);
-@@ -399,6 +401,7 @@ static int snd_bcm2835_pcm_prepare(struc
- alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
- alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
- alsa_stream->pos = 0;
-+ alsa_stream->interpolate_start = ktime_get_ns();
-
- audio_debug("buffer_size=%d, period_size=%d pos=%d frame_bits=%d\n",
- alsa_stream->buffer_size, alsa_stream->period_size,
-@@ -495,6 +498,7 @@ snd_bcm2835_pcm_pointer(struct snd_pcm_s
- {
- struct snd_pcm_runtime *runtime = substream->runtime;
- bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
-+ u64 now = ktime_get_ns();
-
- audio_info(" .. IN\n");
-
-@@ -503,6 +507,12 @@ snd_bcm2835_pcm_pointer(struct snd_pcm_s
- frames_to_bytes(runtime, runtime->control->appl_ptr),
- alsa_stream->pos);
-
-+ /* Give userspace better delay reporting by interpolating between GPU
-+ * notifications, assuming audio speed is close enough to the clock
-+ * used for ktime */
-+ if (alsa_stream->interpolate_start && alsa_stream->interpolate_start < now)
-+ runtime->delay = -(int)div_u64((now - alsa_stream->interpolate_start) * runtime->rate, 1000000000);
-+
- audio_info(" .. OUT\n");
- return snd_pcm_indirect_playback_pointer(substream,
- &alsa_stream->pcm_indirect,
---- a/sound/arm/bcm2835.h
-+++ b/sound/arm/bcm2835.h
-@@ -137,6 +137,7 @@ typedef struct bcm2835_alsa_stream {
- unsigned int pos;
- unsigned int buffer_size;
- unsigned int period_size;
-+ u64 interpolate_start;
-
- uint32_t enable_fifo_irq;
- irq_handler_t fifo_irq_handler;
diff --git a/target/linux/brcm2708/patches-4.4/0135-bcm2835-sdhost-Add-debug_flags-dtparam.patch b/target/linux/brcm2708/patches-4.4/0135-bcm2835-sdhost-Add-debug_flags-dtparam.patch
new file mode 100644
index 0000000000..b4fee06a38
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0135-bcm2835-sdhost-Add-debug_flags-dtparam.patch
@@ -0,0 +1,120 @@
+From 594abef9e9d240d6f97a22e8f6cdc6cf0c272cd7 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 22 Jan 2016 16:03:24 +0000
+Subject: [PATCH 135/381] bcm2835-sdhost: Add debug_flags dtparam
+
+Bit zero disables the single-read-sectors map:
+
+If the default MMC driver is bcm2835-mmc:
+ dtoverlay=sdhost,debug_flags=1
+If the default MMC driver is bcm2835-sdhost:
+ dtoverlay=sdtweak,debug_flags=1
+(although the sdhost overlay may also work, sdtweak is
+less invasive and will work in more circumstances).
+
+Also revert the timeout change, just in case.
+---
+ arch/arm/boot/dts/overlays/sdhost-overlay.dts | 2 ++
+ arch/arm/boot/dts/overlays/sdtweak-overlay.dts | 2 ++
+ drivers/mmc/host/bcm2835-sdhost.c | 26 +++++++++++++++++++++-----
+ 3 files changed, 25 insertions(+), 5 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/sdhost-overlay.dts
++++ b/arch/arm/boot/dts/overlays/sdhost-overlay.dts
+@@ -16,6 +16,7 @@
+ frag1: __overlay__ {
+ brcm,overclock-50 = <0>;
+ brcm,pio-limit = <1>;
++ brcm,debug-flags = <0>;
+ status = "okay";
+ };
+ };
+@@ -25,5 +26,6 @@
+ force_pio = <&frag1>,"brcm,force-pio?";
+ pio_limit = <&frag1>,"brcm,pio-limit:0";
+ debug = <&frag1>,"brcm,debug?";
++ debug_flags = <&frag1>,"brcm,debug-flags:0";
+ };
+ };
+--- a/arch/arm/boot/dts/overlays/sdtweak-overlay.dts
++++ b/arch/arm/boot/dts/overlays/sdtweak-overlay.dts
+@@ -9,6 +9,7 @@
+ frag1: __overlay__ {
+ brcm,overclock-50 = <0>;
+ brcm,pio-limit = <1>;
++ brcm,debug-flags = <0>;
+ };
+ };
+
+@@ -17,5 +18,6 @@
+ force_pio = <&frag1>,"brcm,force-pio?";
+ pio_limit = <&frag1>,"brcm,pio-limit:0";
+ debug = <&frag1>,"brcm,debug?";
++ debug_flags = <&frag1>,"brcm,debug-flags:0";
+ };
+ };
+--- a/drivers/mmc/host/bcm2835-sdhost.c
++++ b/drivers/mmc/host/bcm2835-sdhost.c
+@@ -174,6 +174,8 @@ struct bcm2835_host {
+ u32 overclock; /* Current frequency if overclocked, else zero */
+ u32 pio_limit; /* Maximum block count for PIO (0 = always DMA) */
+
++ u32 debug_flags;
++
+ u32 sectors; /* Cached card size in sectors */
+ u32 single_read_sectors[8];
+ };
+@@ -682,7 +684,7 @@ static void bcm2835_sdhost_prepare_data(
+ host->flush_fifo = 0;
+ host->data->bytes_xfered = 0;
+
+- if (!host->sectors && host->mmc->card)
++ if (!host->sectors && host->mmc->card && !(host->debug_flags & 1))
+ {
+ struct mmc_card *card = host->mmc->card;
+ if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
+@@ -1486,8 +1488,8 @@ void bcm2835_sdhost_set_clock(struct bcm
+ host->cdiv = div;
+ bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
+
+- /* Set the timeout to 250ms */
+- bcm2835_sdhost_write(host, host->mmc->actual_clock/4, SDTOUT);
++ /* Set the timeout to 500ms */
++ bcm2835_sdhost_write(host, host->mmc->actual_clock/2, SDTOUT);
+
+ if (host->debug)
+ pr_info("%s: clock=%d -> max_clk=%d, cdiv=%x (actual clock %d)\n",
+@@ -1606,8 +1608,16 @@ static int bcm2835_sdhost_multi_io_quirk
+
+ host = mmc_priv(card->host);
+
+- if (direction == MMC_DATA_READ)
+- {
++ if (!host->sectors) {
++ /* csd.capacity is in weird units - convert to sectors */
++ u32 card_sectors = (card->csd.capacity << (card->csd.read_blkbits - 9));
++ if ((direction == MMC_DATA_READ) &&
++ ((blk_pos + blk_size) == card_sectors))
++ blk_size--;
++ return blk_size;
++ }
++
++ if (direction == MMC_DATA_READ) {
+ int i;
+ int sector;
+ for (i = 0; blk_pos > (sector = host->single_read_sectors[i]); i++)
+@@ -1838,8 +1848,14 @@ static int bcm2835_sdhost_probe(struct p
+ host->allow_dma = ALLOW_DMA &&
+ !of_property_read_bool(node, "brcm,force-pio");
+ host->debug = of_property_read_bool(node, "brcm,debug");
++ of_property_read_u32(node,
++ "brcm,debug-flags",
++ &host->debug_flags);
+ }
+
++ if (host->debug_flags)
++ dev_err(dev, "debug_flags=%x\n", host->debug_flags);
++
+ if (host->allow_dma) {
+ if (node) {
+ host->dma_chan_tx =
diff --git a/target/linux/brcm2708/patches-4.4/0136-BCM270X_DT-Add-sdio_overclock-parameter-to-sdio-over.patch b/target/linux/brcm2708/patches-4.4/0136-BCM270X_DT-Add-sdio_overclock-parameter-to-sdio-over.patch
new file mode 100644
index 0000000000..65b404ad52
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0136-BCM270X_DT-Add-sdio_overclock-parameter-to-sdio-over.patch
@@ -0,0 +1,69 @@
+From 263629c941a7da06b8cce7f73fe8d8d20d1357b7 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 25 Jan 2016 09:12:06 +0000
+Subject: [PATCH 136/381] BCM270X_DT: Add sdio_overclock parameter to sdio
+ overlay
+
+The sdio_overclock parameter is like the overclock_50 parameter, i.e.
+it sets an alternate frequency (in MHz) to use when the MMC framework
+requests 50MHz, except that it applies to the SDIO bus.
+
+Be aware that the actual frequencies achievable are limited to even integer
+divisions of 250MHz, and that the driver will round up to include fractions
+(e.g. 62 will include 62.5) but then round down to the nearest frequency.
+In other words, the chosen frequency is the highest possible that is less than
+the parameter value + 1. In practise this means that 62 is the only sensible
+value.
+
+Examples:
+ 250MHz/4 = 62.5MHz (sdio_overclock=62)
+ 250MHz/2 = 125MHz (sdio_overclock=125) # Too fast
+---
+ arch/arm/boot/dts/overlays/README | 9 ++++++---
+ arch/arm/boot/dts/overlays/sdio-overlay.dts | 2 ++
+ 2 files changed, 8 insertions(+), 3 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -53,8 +53,8 @@ have its contents deleted (or commented
+ Using Overlays
+ ==============
+
+-Overlays are loaded using the "dtoverlay" directive. As an example, consider the
+-popular lirc-rpi module, the Linux Infrared Remote Control driver. In the
++Overlays are loaded using the "dtoverlay" directive. As an example, consider
++the popular lirc-rpi module, the Linux Infrared Remote Control driver. In the
+ pre-DT world this would be loaded from /etc/modules, with an explicit
+ "modprobe lirc-rpi" command, or programmatically by lircd. With DT enabled,
+ this becomes a line in config.txt:
+@@ -621,9 +621,12 @@ Name: sdio
+ Info: Selects the bcm2835-sdhost SD/MMC driver, optionally with overclock,
+ and enables SDIO via GPIOs 22-27.
+ Load: dtoverlay=sdio,<param>=<val>
+-Params: overclock_50 Clock (in MHz) to use when the MMC framework
++Params: overclock_50 SD Clock (in MHz) to use when the MMC framework
+ requests 50MHz
+
++ sdio_overclock SDIO Clock (in MHz) to use when the MMC
++ framework requests 50MHz
++
+ force_pio Disable DMA support (default off)
+
+ pio_limit Number of blocks above which to use DMA
+--- a/arch/arm/boot/dts/overlays/sdio-overlay.dts
++++ b/arch/arm/boot/dts/overlays/sdio-overlay.dts
+@@ -12,6 +12,7 @@
+ pinctrl-0 = <&sdio_pins>;
+ non-removable;
+ bus-width = <4>;
++ brcm,overclock-50 = <0>;
+ status = "okay";
+ };
+ };
+@@ -30,5 +31,6 @@
+ __overrides__ {
+ poll_once = <&sdio_mmc>,"non-removable?";
+ bus_width = <&sdio_mmc>,"bus-width:0";
++ sdio_overclock = <&sdio_mmc>,"brcm,overclock-50:0";
+ };
+ };
diff --git a/target/linux/brcm2708/patches-4.4/0136-bcm2835-sdhost-Add-workaround-for-odd-behaviour-on-s.patch b/target/linux/brcm2708/patches-4.4/0136-bcm2835-sdhost-Add-workaround-for-odd-behaviour-on-s.patch
deleted file mode 100644
index dbe4bbfe5b..0000000000
--- a/target/linux/brcm2708/patches-4.4/0136-bcm2835-sdhost-Add-workaround-for-odd-behaviour-on-s.patch
+++ /dev/null
@@ -1,137 +0,0 @@
-From 205e27a7f94a5531764cc517ce43623361ca466c Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Tue, 19 Jan 2016 17:16:38 +0000
-Subject: [PATCH 136/170] bcm2835-sdhost: Add workaround for odd behaviour on
- some cards
-
-For reasons not understood, the sdhost driver fails when reading
-sectors very near the end of some SD cards. The problem could
-be related to the similar issue that reading the final sector
-of any card as part of a multiple read never completes, and the
-workaround is an extension of the mechanism introduced to solve
-that problem which ensures those sectors are always read singly.
----
- drivers/mmc/host/bcm2835-sdhost.c | 61 +++++++++++++++++++++++++++++++++------
- 1 file changed, 52 insertions(+), 9 deletions(-)
-
---- a/drivers/mmc/host/bcm2835-sdhost.c
-+++ b/drivers/mmc/host/bcm2835-sdhost.c
-@@ -173,6 +173,9 @@ struct bcm2835_host {
- u32 overclock_50; /* frequency to use when 50MHz is requested (in MHz) */
- u32 overclock; /* Current frequency if overclocked, else zero */
- u32 pio_limit; /* Maximum block count for PIO (0 = always DMA) */
-+
-+ u32 sectors; /* Cached card size in sectors */
-+ u32 single_read_sectors[8];
- };
-
-
-@@ -277,6 +280,9 @@ static void bcm2835_sdhost_reset_interna
- {
- u32 temp;
-
-+ if (host->debug)
-+ pr_info("%s: reset\n", mmc_hostname(host->mmc));
-+
- bcm2835_sdhost_set_power(host, false);
-
- bcm2835_sdhost_write(host, 0, SDCMD);
-@@ -299,6 +305,8 @@ static void bcm2835_sdhost_reset_interna
- bcm2835_sdhost_set_power(host, true);
- mdelay(10);
- host->clock = 0;
-+ host->sectors = 0;
-+ host->single_read_sectors[0] = ~0;
- bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
- bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
- mmiowb();
-@@ -309,8 +317,6 @@ static void bcm2835_sdhost_reset(struct
- {
- struct bcm2835_host *host = mmc_priv(mmc);
- unsigned long flags;
-- if (host->debug)
-- pr_info("%s: reset\n", mmc_hostname(mmc));
- spin_lock_irqsave(&host->lock, flags);
-
- bcm2835_sdhost_reset_internal(host);
-@@ -676,6 +682,32 @@ static void bcm2835_sdhost_prepare_data(
- host->flush_fifo = 0;
- host->data->bytes_xfered = 0;
-
-+ if (!host->sectors && host->mmc->card)
-+ {
-+ struct mmc_card *card = host->mmc->card;
-+ if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
-+ /*
-+ * The EXT_CSD sector count is in number of 512 byte
-+ * sectors.
-+ */
-+ host->sectors = card->ext_csd.sectors;
-+ pr_err("%s: using ext_csd!\n", mmc_hostname(host->mmc));
-+ } else {
-+ /*
-+ * The CSD capacity field is in units of read_blkbits.
-+ * set_capacity takes units of 512 bytes.
-+ */
-+ host->sectors = card->csd.capacity <<
-+ (card->csd.read_blkbits - 9);
-+ }
-+ host->single_read_sectors[0] = host->sectors - 65;
-+ host->single_read_sectors[1] = host->sectors - 64;
-+ host->single_read_sectors[2] = host->sectors - 33;
-+ host->single_read_sectors[3] = host->sectors - 32;
-+ host->single_read_sectors[4] = host->sectors - 1;
-+ host->single_read_sectors[5] = ~0; /* Safety net */
-+ }
-+
- host->use_dma = host->have_dma && (data->blocks > host->pio_limit);
- if (!host->use_dma) {
- int flags;
-@@ -1246,6 +1278,10 @@ static u32 bcm2835_sdhost_block_irq(stru
-
- bcm2835_sdhost_finish_data(host);
- } else {
-+ /* Reset the timer */
-+ mod_timer(&host->pio_timer,
-+ jiffies + host->pio_timeout);
-+
- bcm2835_sdhost_transfer_pio(host);
-
- /* Reset the timer */
-@@ -1450,8 +1486,8 @@ void bcm2835_sdhost_set_clock(struct bcm
- host->cdiv = div;
- bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
-
-- /* Set the timeout to 500ms */
-- bcm2835_sdhost_write(host, host->mmc->actual_clock/2, SDTOUT);
-+ /* Set the timeout to 250ms */
-+ bcm2835_sdhost_write(host, host->mmc->actual_clock/4, SDTOUT);
-
- if (host->debug)
- pr_info("%s: clock=%d -> max_clk=%d, cdiv=%x (actual clock %d)\n",
-@@ -1566,13 +1602,20 @@ static int bcm2835_sdhost_multi_io_quirk
- reading the final sector of the card as part of a multiple read
- problematic. Detect that case and shorten the read accordingly.
- */
-- /* csd.capacity is in weird units - convert to sectors */
-- u32 card_sectors = (card->csd.capacity << (card->csd.read_blkbits - 9));
-+ struct bcm2835_host *host;
-+
-+ host = mmc_priv(card->host);
-
-- if ((direction == MMC_DATA_READ) &&
-- ((blk_pos + blk_size) == card_sectors))
-- blk_size--;
-+ if (direction == MMC_DATA_READ)
-+ {
-+ int i;
-+ int sector;
-+ for (i = 0; blk_pos > (sector = host->single_read_sectors[i]); i++)
-+ continue;
-
-+ if ((blk_pos + blk_size) > sector)
-+ blk_size = (blk_pos == sector) ? 1 : (sector - blk_pos);
-+ }
- return blk_size;
- }
-
diff --git a/target/linux/brcm2708/patches-4.4/0137-bcm2835-sdhost-Add-debug_flags-dtparam.patch b/target/linux/brcm2708/patches-4.4/0137-bcm2835-sdhost-Add-debug_flags-dtparam.patch
deleted file mode 100644
index cb56259066..0000000000
--- a/target/linux/brcm2708/patches-4.4/0137-bcm2835-sdhost-Add-debug_flags-dtparam.patch
+++ /dev/null
@@ -1,120 +0,0 @@
-From c5d24cba808118647d01a1869cf1c46d0658d78b Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Fri, 22 Jan 2016 16:03:24 +0000
-Subject: [PATCH 137/170] bcm2835-sdhost: Add debug_flags dtparam
-
-Bit zero disables the single-read-sectors map:
-
-If the default MMC driver is bcm2835-mmc:
- dtoverlay=sdhost,debug_flags=1
-If the default MMC driver is bcm2835-sdhost:
- dtoverlay=sdtweak,debug_flags=1
-(although the sdhost overlay may also work, sdtweak is
-less invasive and will work in more circumstances).
-
-Also revert the timeout change, just in case.
----
- arch/arm/boot/dts/overlays/sdhost-overlay.dts | 2 ++
- arch/arm/boot/dts/overlays/sdtweak-overlay.dts | 2 ++
- drivers/mmc/host/bcm2835-sdhost.c | 26 +++++++++++++++++++++-----
- 3 files changed, 25 insertions(+), 5 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/sdhost-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/sdhost-overlay.dts
-@@ -16,6 +16,7 @@
- frag1: __overlay__ {
- brcm,overclock-50 = <0>;
- brcm,pio-limit = <1>;
-+ brcm,debug-flags = <0>;
- status = "okay";
- };
- };
-@@ -25,5 +26,6 @@
- force_pio = <&frag1>,"brcm,force-pio?";
- pio_limit = <&frag1>,"brcm,pio-limit:0";
- debug = <&frag1>,"brcm,debug?";
-+ debug_flags = <&frag1>,"brcm,debug-flags:0";
- };
- };
---- a/arch/arm/boot/dts/overlays/sdtweak-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/sdtweak-overlay.dts
-@@ -9,6 +9,7 @@
- frag1: __overlay__ {
- brcm,overclock-50 = <0>;
- brcm,pio-limit = <1>;
-+ brcm,debug-flags = <0>;
- };
- };
-
-@@ -17,5 +18,6 @@
- force_pio = <&frag1>,"brcm,force-pio?";
- pio_limit = <&frag1>,"brcm,pio-limit:0";
- debug = <&frag1>,"brcm,debug?";
-+ debug_flags = <&frag1>,"brcm,debug-flags:0";
- };
- };
---- a/drivers/mmc/host/bcm2835-sdhost.c
-+++ b/drivers/mmc/host/bcm2835-sdhost.c
-@@ -174,6 +174,8 @@ struct bcm2835_host {
- u32 overclock; /* Current frequency if overclocked, else zero */
- u32 pio_limit; /* Maximum block count for PIO (0 = always DMA) */
-
-+ u32 debug_flags;
-+
- u32 sectors; /* Cached card size in sectors */
- u32 single_read_sectors[8];
- };
-@@ -682,7 +684,7 @@ static void bcm2835_sdhost_prepare_data(
- host->flush_fifo = 0;
- host->data->bytes_xfered = 0;
-
-- if (!host->sectors && host->mmc->card)
-+ if (!host->sectors && host->mmc->card && !(host->debug_flags & 1))
- {
- struct mmc_card *card = host->mmc->card;
- if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
-@@ -1486,8 +1488,8 @@ void bcm2835_sdhost_set_clock(struct bcm
- host->cdiv = div;
- bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
-
-- /* Set the timeout to 250ms */
-- bcm2835_sdhost_write(host, host->mmc->actual_clock/4, SDTOUT);
-+ /* Set the timeout to 500ms */
-+ bcm2835_sdhost_write(host, host->mmc->actual_clock/2, SDTOUT);
-
- if (host->debug)
- pr_info("%s: clock=%d -> max_clk=%d, cdiv=%x (actual clock %d)\n",
-@@ -1606,8 +1608,16 @@ static int bcm2835_sdhost_multi_io_quirk
-
- host = mmc_priv(card->host);
-
-- if (direction == MMC_DATA_READ)
-- {
-+ if (!host->sectors) {
-+ /* csd.capacity is in weird units - convert to sectors */
-+ u32 card_sectors = (card->csd.capacity << (card->csd.read_blkbits - 9));
-+ if ((direction == MMC_DATA_READ) &&
-+ ((blk_pos + blk_size) == card_sectors))
-+ blk_size--;
-+ return blk_size;
-+ }
-+
-+ if (direction == MMC_DATA_READ) {
- int i;
- int sector;
- for (i = 0; blk_pos > (sector = host->single_read_sectors[i]); i++)
-@@ -1838,8 +1848,14 @@ static int bcm2835_sdhost_probe(struct p
- host->allow_dma = ALLOW_DMA &&
- !of_property_read_bool(node, "brcm,force-pio");
- host->debug = of_property_read_bool(node, "brcm,debug");
-+ of_property_read_u32(node,
-+ "brcm,debug-flags",
-+ &host->debug_flags);
- }
-
-+ if (host->debug_flags)
-+ dev_err(dev, "debug_flags=%x\n", host->debug_flags);
-+
- if (host->allow_dma) {
- if (node) {
- host->dma_chan_tx =
diff --git a/target/linux/brcm2708/patches-4.4/0137-rtc-ds1307-add-support-for-the-DT-property-wakeup-so.patch b/target/linux/brcm2708/patches-4.4/0137-rtc-ds1307-add-support-for-the-DT-property-wakeup-so.patch
new file mode 100644
index 0000000000..f4d6cf1f26
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0137-rtc-ds1307-add-support-for-the-DT-property-wakeup-so.patch
@@ -0,0 +1,94 @@
+From c762fb624a6a4d3228fcd2f26bbbb19af44d000c Mon Sep 17 00:00:00 2001
+From: Michael Lange <linuxstuff@milaw.biz>
+Date: Thu, 21 Jan 2016 18:10:16 +0100
+Subject: [PATCH 137/381] rtc: ds1307: add support for the DT property
+ 'wakeup-source'
+
+For RTC chips with no IRQ directly connected to the SoC, the RTC chip
+can be forced as a wakeup source by stating that explicitly in
+the device's .dts file using the "wakeup-source" boolean property.
+This will guarantee the 'wakealarm' sysfs entry is available on the
+device, if supported by the RTC.
+
+With these changes to the driver rtc-ds1307 and the necessary entries
+in the .dts file, I get an working ds1337 RTC on the Witty Pi extension
+board by UUGear for the Raspberry Pi.
+
+An example for the entry in the .dts file:
+
+ rtc: ds1337@68 {
+ compatible = "dallas,ds1337";
+ reg = <0x68>;
+ wakeup-source;
+
+If the "wakeup-source" property is set, do not request an IRQ.
+Set also UIE mode to unsupported, to get a working 'hwclock' binary.
+
+Signed-off-by: Michael Lange <linuxstuff@milaw.biz>
+Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
+---
+ drivers/rtc/rtc-ds1307.c | 29 +++++++++++++++++++++++++++--
+ 1 file changed, 27 insertions(+), 2 deletions(-)
+
+--- a/drivers/rtc/rtc-ds1307.c
++++ b/drivers/rtc/rtc-ds1307.c
+@@ -860,6 +860,7 @@ static int ds1307_probe(struct i2c_clien
+ struct chip_desc *chip = &chips[id->driver_data];
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ bool want_irq = false;
++ bool ds1307_can_wakeup_device = false;
+ unsigned char *buf;
+ struct ds1307_platform_data *pdata = dev_get_platdata(&client->dev);
+ irq_handler_t irq_handler = ds1307_irq;
+@@ -907,6 +908,20 @@ static int ds1307_probe(struct i2c_clien
+ ds1307->write_block_data = ds1307_write_block_data;
+ }
+
++#ifdef CONFIG_OF
++/*
++ * For devices with no IRQ directly connected to the SoC, the RTC chip
++ * can be forced as a wakeup source by stating that explicitly in
++ * the device's .dts file using the "wakeup-source" boolean property.
++ * If the "wakeup-source" property is set, don't request an IRQ.
++ * This will guarantee the 'wakealarm' sysfs entry is available on the device,
++ * if supported by the RTC.
++ */
++ if (of_property_read_bool(client->dev.of_node, "wakeup-source")) {
++ ds1307_can_wakeup_device = true;
++ }
++#endif
++
+ switch (ds1307->type) {
+ case ds_1337:
+ case ds_1339:
+@@ -925,11 +940,13 @@ static int ds1307_probe(struct i2c_clien
+ ds1307->regs[0] &= ~DS1337_BIT_nEOSC;
+
+ /*
+- * Using IRQ? Disable the square wave and both alarms.
++ * Using IRQ or defined as wakeup-source?
++ * Disable the square wave and both alarms.
+ * For some variants, be sure alarms can trigger when we're
+ * running on Vbackup (BBSQI/BBSQW)
+ */
+- if (ds1307->client->irq > 0 && chip->alarm) {
++ if (chip->alarm && (ds1307->client->irq > 0 ||
++ ds1307_can_wakeup_device)) {
+ ds1307->regs[0] |= DS1337_BIT_INTCN
+ | bbsqi_bitpos[ds1307->type];
+ ds1307->regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE);
+@@ -1144,6 +1161,14 @@ read_rtc:
+ return PTR_ERR(ds1307->rtc);
+ }
+
++ if (ds1307_can_wakeup_device) {
++ /* Disable request for an IRQ */
++ want_irq = false;
++ dev_info(&client->dev, "'wakeup-source' is set, request for an IRQ is disabled!\n");
++ /* We cannot support UIE mode if we do not have an IRQ line */
++ ds1307->rtc->uie_unsupported = 1;
++ }
++
+ if (want_irq) {
+ err = devm_request_threaded_irq(&client->dev,
+ client->irq, NULL, irq_handler,
diff --git a/target/linux/brcm2708/patches-4.4/0138-BCM270X_DT-Add-sdio_overclock-parameter-to-sdio-over.patch b/target/linux/brcm2708/patches-4.4/0138-BCM270X_DT-Add-sdio_overclock-parameter-to-sdio-over.patch
deleted file mode 100644
index 8468f39ce8..0000000000
--- a/target/linux/brcm2708/patches-4.4/0138-BCM270X_DT-Add-sdio_overclock-parameter-to-sdio-over.patch
+++ /dev/null
@@ -1,69 +0,0 @@
-From 1a451a35b70fa9ed32f23a4ba925e5b2c2c3af78 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Mon, 25 Jan 2016 09:12:06 +0000
-Subject: [PATCH 138/170] BCM270X_DT: Add sdio_overclock parameter to sdio
- overlay
-
-The sdio_overclock parameter is like the overclock_50 parameter, i.e.
-it sets an alternate frequency (in MHz) to use when the MMC framework
-requests 50MHz, except that it applies to the SDIO bus.
-
-Be aware that the actual frequencies achievable are limited to even integer
-divisions of 250MHz, and that the driver will round up to include fractions
-(e.g. 62 will include 62.5) but then round down to the nearest frequency.
-In other words, the chosen frequency is the highest possible that is less than
-the parameter value + 1. In practise this means that 62 is the only sensible
-value.
-
-Examples:
- 250MHz/4 = 62.5MHz (sdio_overclock=62)
- 250MHz/2 = 125MHz (sdio_overclock=125) # Too fast
----
- arch/arm/boot/dts/overlays/README | 9 ++++++---
- arch/arm/boot/dts/overlays/sdio-overlay.dts | 2 ++
- 2 files changed, 8 insertions(+), 3 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -53,8 +53,8 @@ have its contents deleted (or commented
- Using Overlays
- ==============
-
--Overlays are loaded using the "dtoverlay" directive. As an example, consider the
--popular lirc-rpi module, the Linux Infrared Remote Control driver. In the
-+Overlays are loaded using the "dtoverlay" directive. As an example, consider
-+the popular lirc-rpi module, the Linux Infrared Remote Control driver. In the
- pre-DT world this would be loaded from /etc/modules, with an explicit
- "modprobe lirc-rpi" command, or programmatically by lircd. With DT enabled,
- this becomes a line in config.txt:
-@@ -621,9 +621,12 @@ Name: sdio
- Info: Selects the bcm2835-sdhost SD/MMC driver, optionally with overclock,
- and enables SDIO via GPIOs 22-27.
- Load: dtoverlay=sdio,<param>=<val>
--Params: overclock_50 Clock (in MHz) to use when the MMC framework
-+Params: overclock_50 SD Clock (in MHz) to use when the MMC framework
- requests 50MHz
-
-+ sdio_overclock SDIO Clock (in MHz) to use when the MMC
-+ framework requests 50MHz
-+
- force_pio Disable DMA support (default off)
-
- pio_limit Number of blocks above which to use DMA
---- a/arch/arm/boot/dts/overlays/sdio-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/sdio-overlay.dts
-@@ -12,6 +12,7 @@
- pinctrl-0 = <&sdio_pins>;
- non-removable;
- bus-width = <4>;
-+ brcm,overclock-50 = <0>;
- status = "okay";
- };
- };
-@@ -30,5 +31,6 @@
- __overrides__ {
- poll_once = <&sdio_mmc>,"non-removable?";
- bus_width = <&sdio_mmc>,"bus-width:0";
-+ sdio_overclock = <&sdio_mmc>,"brcm,overclock-50:0";
- };
- };
diff --git a/target/linux/brcm2708/patches-4.4/0138-dt-overlay-add-wittypi-overlay.dts.patch b/target/linux/brcm2708/patches-4.4/0138-dt-overlay-add-wittypi-overlay.dts.patch
new file mode 100644
index 0000000000..93104dfb79
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0138-dt-overlay-add-wittypi-overlay.dts.patch
@@ -0,0 +1,57 @@
+From 44c996c04b54ff4babbfb9432b3d82cb009e5d8c Mon Sep 17 00:00:00 2001
+From: vitalogy <vitalogy_github@milaw.biz>
+Date: Tue, 19 Jan 2016 07:02:02 +0100
+Subject: [PATCH 138/381] dt-overlay: add wittypi-overlay.dts
+
+---
+ arch/arm/boot/dts/overlays/wittypi-overlay.dts | 44 ++++++++++++++++++++++++++
+ 1 file changed, 44 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/wittypi-overlay.dts
+
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/wittypi-overlay.dts
+@@ -0,0 +1,44 @@
++/*
++ * Device Tree overlay for Witty Pi extension board by UUGear
++ *
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++
++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++
++ fragment@0 {
++ target = <&leds>;
++ __overlay__ {
++ compatible = "gpio-leds";
++ wittypi_led: wittypi_led {
++ label = "wittypi_led";
++ linux,default-trigger = "default-on";
++ gpios = <&gpio 17 0>;
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ rtc: ds1337@68 {
++ compatible = "dallas,ds1337";
++ reg = <0x68>;
++ wakeup-source;
++ };
++ };
++ };
++
++ __overrides__ {
++ led_gpio = <&wittypi_led>,"gpios:4";
++ led_trigger = <&wittypi_led>,"linux,default-trigger";
++ };
++
++};
diff --git a/target/linux/brcm2708/patches-4.4/0139-FIXUP-i2c_bcm2708-Don-t-change-module-baudrate-param.patch b/target/linux/brcm2708/patches-4.4/0139-FIXUP-i2c_bcm2708-Don-t-change-module-baudrate-param.patch
new file mode 100644
index 0000000000..4656c19152
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0139-FIXUP-i2c_bcm2708-Don-t-change-module-baudrate-param.patch
@@ -0,0 +1,99 @@
+From 2df3762d6b10aab005679b549ccb656577d788fc Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Tue, 19 Jan 2016 16:28:05 +0000
+Subject: [PATCH 139/381] FIXUP i2c_bcm2708: Don't change module baudrate
+ parameter
+
+Overwriting the baudrate module parameter creates an apparent
+forced baudrate for i2c busses after the first. Not only does this
+override the baudrate from DT it also prevents the bus ID from
+being initialised.
+
+Also fix whitespace errors.
+---
+ drivers/i2c/busses/i2c-bcm2708.c | 48 +++++++++++++++++++++-------------------
+ 1 file changed, 25 insertions(+), 23 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-bcm2708.c
++++ b/drivers/i2c/busses/i2c-bcm2708.c
+@@ -71,7 +71,6 @@
+
+ #define DRV_NAME "bcm2708_i2c"
+
+-static unsigned int baudrate_default = CONFIG_I2C_BCM2708_BAUDRATE;
+ static unsigned int baudrate;
+ module_param(baudrate, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+ MODULE_PARM_DESC(baudrate, "The I2C baudrate");
+@@ -317,25 +316,28 @@ static int bcm2708_i2c_probe(struct plat
+ struct i2c_adapter *adap;
+ unsigned long bus_hz;
+ u32 cdiv, clk_tout;
+-
+- if (!baudrate) {
+- baudrate = baudrate_default;
+- if (pdev->dev.of_node) {
+- u32 bus_clk_rate;
+- pdev->id = of_alias_get_id(pdev->dev.of_node, "i2c");
+- if (pdev->id < 0) {
+- dev_err(&pdev->dev, "alias is missing\n");
+- return -EINVAL;
+- }
+- if (!of_property_read_u32(pdev->dev.of_node,
+- "clock-frequency", &bus_clk_rate))
+- baudrate = bus_clk_rate;
+- else
+- dev_warn(&pdev->dev,
+- "Could not read clock-frequency property\n");
++ u32 baud;
++
++ baud = CONFIG_I2C_BCM2708_BAUDRATE;
++
++ if (pdev->dev.of_node) {
++ u32 bus_clk_rate;
++ pdev->id = of_alias_get_id(pdev->dev.of_node, "i2c");
++ if (pdev->id < 0) {
++ dev_err(&pdev->dev, "alias is missing\n");
++ return -EINVAL;
+ }
++ if (!of_property_read_u32(pdev->dev.of_node,
++ "clock-frequency", &bus_clk_rate))
++ baud = bus_clk_rate;
++ else
++ dev_warn(&pdev->dev,
++ "Could not read clock-frequency property\n");
+ }
+
++ if (baudrate)
++ baud = baudrate;
++
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!regs) {
+ dev_err(&pdev->dev, "could not get IO memory\n");
+@@ -419,21 +421,21 @@ static int bcm2708_i2c_probe(struct plat
+ }
+
+ bus_hz = clk_get_rate(bi->clk);
+- cdiv = bus_hz / baudrate;
++ cdiv = bus_hz / baud;
+ if (cdiv > 0xffff) {
+ cdiv = 0xffff;
+- baudrate = bus_hz / cdiv;
++ baud = bus_hz / cdiv;
+ }
+-
+- clk_tout = 35/1000*baudrate; //35ms timeout as per SMBus specs.
+- if (clk_tout > 0xffff)
++
++ clk_tout = 35/1000*baud; //35ms timeout as per SMBus specs.
++ if (clk_tout > 0xffff)
+ clk_tout = 0xffff;
+
+ bi->cdiv = cdiv;
+ bi->clk_tout = clk_tout;
+
+ dev_info(&pdev->dev, "BSC%d Controller at 0x%08lx (irq %d) (baudrate %d)\n",
+- pdev->id, (unsigned long)regs->start, irq, baudrate);
++ pdev->id, (unsigned long)regs->start, irq, baud);
+
+ return 0;
+
diff --git a/target/linux/brcm2708/patches-4.4/0139-rtc-ds1307-add-support-for-the-DT-property-wakeup-so.patch b/target/linux/brcm2708/patches-4.4/0139-rtc-ds1307-add-support-for-the-DT-property-wakeup-so.patch
deleted file mode 100644
index 741cdf57ea..0000000000
--- a/target/linux/brcm2708/patches-4.4/0139-rtc-ds1307-add-support-for-the-DT-property-wakeup-so.patch
+++ /dev/null
@@ -1,94 +0,0 @@
-From 49ff16d7af98e6191d6dd60ba75b711612e948ab Mon Sep 17 00:00:00 2001
-From: Michael Lange <linuxstuff@milaw.biz>
-Date: Thu, 21 Jan 2016 18:10:16 +0100
-Subject: [PATCH 139/170] rtc: ds1307: add support for the DT property
- 'wakeup-source'
-
-For RTC chips with no IRQ directly connected to the SoC, the RTC chip
-can be forced as a wakeup source by stating that explicitly in
-the device's .dts file using the "wakeup-source" boolean property.
-This will guarantee the 'wakealarm' sysfs entry is available on the
-device, if supported by the RTC.
-
-With these changes to the driver rtc-ds1307 and the necessary entries
-in the .dts file, I get an working ds1337 RTC on the Witty Pi extension
-board by UUGear for the Raspberry Pi.
-
-An example for the entry in the .dts file:
-
- rtc: ds1337@68 {
- compatible = "dallas,ds1337";
- reg = <0x68>;
- wakeup-source;
-
-If the "wakeup-source" property is set, do not request an IRQ.
-Set also UIE mode to unsupported, to get a working 'hwclock' binary.
-
-Signed-off-by: Michael Lange <linuxstuff@milaw.biz>
-Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
----
- drivers/rtc/rtc-ds1307.c | 29 +++++++++++++++++++++++++++--
- 1 file changed, 27 insertions(+), 2 deletions(-)
-
---- a/drivers/rtc/rtc-ds1307.c
-+++ b/drivers/rtc/rtc-ds1307.c
-@@ -860,6 +860,7 @@ static int ds1307_probe(struct i2c_clien
- struct chip_desc *chip = &chips[id->driver_data];
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
- bool want_irq = false;
-+ bool ds1307_can_wakeup_device = false;
- unsigned char *buf;
- struct ds1307_platform_data *pdata = dev_get_platdata(&client->dev);
- irq_handler_t irq_handler = ds1307_irq;
-@@ -907,6 +908,20 @@ static int ds1307_probe(struct i2c_clien
- ds1307->write_block_data = ds1307_write_block_data;
- }
-
-+#ifdef CONFIG_OF
-+/*
-+ * For devices with no IRQ directly connected to the SoC, the RTC chip
-+ * can be forced as a wakeup source by stating that explicitly in
-+ * the device's .dts file using the "wakeup-source" boolean property.
-+ * If the "wakeup-source" property is set, don't request an IRQ.
-+ * This will guarantee the 'wakealarm' sysfs entry is available on the device,
-+ * if supported by the RTC.
-+ */
-+ if (of_property_read_bool(client->dev.of_node, "wakeup-source")) {
-+ ds1307_can_wakeup_device = true;
-+ }
-+#endif
-+
- switch (ds1307->type) {
- case ds_1337:
- case ds_1339:
-@@ -925,11 +940,13 @@ static int ds1307_probe(struct i2c_clien
- ds1307->regs[0] &= ~DS1337_BIT_nEOSC;
-
- /*
-- * Using IRQ? Disable the square wave and both alarms.
-+ * Using IRQ or defined as wakeup-source?
-+ * Disable the square wave and both alarms.
- * For some variants, be sure alarms can trigger when we're
- * running on Vbackup (BBSQI/BBSQW)
- */
-- if (ds1307->client->irq > 0 && chip->alarm) {
-+ if (chip->alarm && (ds1307->client->irq > 0 ||
-+ ds1307_can_wakeup_device)) {
- ds1307->regs[0] |= DS1337_BIT_INTCN
- | bbsqi_bitpos[ds1307->type];
- ds1307->regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE);
-@@ -1144,6 +1161,14 @@ read_rtc:
- return PTR_ERR(ds1307->rtc);
- }
-
-+ if (ds1307_can_wakeup_device) {
-+ /* Disable request for an IRQ */
-+ want_irq = false;
-+ dev_info(&client->dev, "'wakeup-source' is set, request for an IRQ is disabled!\n");
-+ /* We cannot support UIE mode if we do not have an IRQ line */
-+ ds1307->rtc->uie_unsupported = 1;
-+ }
-+
- if (want_irq) {
- err = devm_request_threaded_irq(&client->dev,
- client->irq, NULL, irq_handler,
diff --git a/target/linux/brcm2708/patches-4.4/0140-Allow-up-to-24dB-digital-gain-to-be-applied-when-usi.patch b/target/linux/brcm2708/patches-4.4/0140-Allow-up-to-24dB-digital-gain-to-be-applied-when-usi.patch
new file mode 100644
index 0000000000..1a7c25b96c
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0140-Allow-up-to-24dB-digital-gain-to-be-applied-when-usi.patch
@@ -0,0 +1,99 @@
+From 3bb2e01fd397f375e54f6fe8a33af25aef1c981f Mon Sep 17 00:00:00 2001
+From: Digital Dreamtime <clive.messer@digitaldreamtime.co.uk>
+Date: Thu, 4 Feb 2016 14:14:44 +0000
+Subject: [PATCH 140/381] Allow up to 24dB digital gain to be applied when
+ using IQAudIO DAC+
+
+24db_digital_gain DT param can be used to specify that PCM512x
+codec "Digital" volume control should not be limited to 0dB gain,
+and if specified will allow the full 24dB gain.
+---
+ arch/arm/boot/dts/overlays/README | 17 +++++++++++++++--
+ .../boot/dts/overlays/iqaudio-dacplus-overlay.dts | 6 +++++-
+ sound/soc/bcm/iqaudio-dac.c | 20 ++++++++++++++------
+ 3 files changed, 34 insertions(+), 9 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -362,8 +362,21 @@ Params: <None>
+
+ Name: iqaudio-dacplus
+ Info: Configures the IQaudio DAC+ audio card
+-Load: dtoverlay=iqaudio-dacplus
+-Params: <None>
++Load: dtoverlay=iqaudio-dacplus,<param>=<val>
++Params: 24db_digital_gain Allow gain to be applied via the PCM512x codec
++ Digital volume control. Enable with
++ "dtoverlay=iqaudio-dacplus,24db_digital_gain"
++ (The default behaviour is that the Digital
++ volume control is limited to a maximum of
++ 0dB. ie. it can attenuate but not provide
++ gain. For most users, this will be desired
++ as it will prevent clipping. By appending
++ the 24db_digital_gain parameter, the Digital
++ volume control will allow up to 24dB of
++ gain. If this parameter is enabled, it is the
++ responsibility of the user to ensure that
++ the Digital volume control is set to a value
++ that does not result in clipping/distortion!)
+
+
+ Name: lirc-rpi
+--- a/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts
++++ b/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts
+@@ -7,7 +7,7 @@
+
+ fragment@0 {
+ target = <&sound>;
+- __overlay__ {
++ frag0: __overlay__ {
+ compatible = "iqaudio,iqaudio-dac";
+ i2s-controller = <&i2s>;
+ status = "okay";
+@@ -36,4 +36,8 @@
+ };
+ };
+ };
++
++ __overrides__ {
++ 24db_digital_gain = <&frag0>,"iqaudio,24db_digital_gain?";
++ };
+ };
+--- a/sound/soc/bcm/iqaudio-dac.c
++++ b/sound/soc/bcm/iqaudio-dac.c
+@@ -23,14 +23,19 @@
+ #include <sound/soc.h>
+ #include <sound/jack.h>
+
++static bool digital_gain_0db_limit = true;
++
+ static int snd_rpi_iqaudio_dac_init(struct snd_soc_pcm_runtime *rtd)
+ {
+- int ret;
+- struct snd_soc_card *card = rtd->card;
+-
+- ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207);
+- if (ret < 0)
+- dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
++ if (digital_gain_0db_limit)
++ {
++ int ret;
++ struct snd_soc_card *card = rtd->card;
++
++ ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207);
++ if (ret < 0)
++ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
++ }
+
+ return 0;
+ }
+@@ -94,6 +99,9 @@ static int snd_rpi_iqaudio_dac_probe(str
+ dai->platform_name = NULL;
+ dai->platform_of_node = i2s_node;
+ }
++
++ digital_gain_0db_limit = !of_property_read_bool(pdev->dev.of_node,
++ "iqaudio,24db_digital_gain");
+ }
+
+ ret = snd_soc_register_card(&snd_rpi_iqaudio_dac);
diff --git a/target/linux/brcm2708/patches-4.4/0140-dt-overlay-add-wittypi-overlay.dts.patch b/target/linux/brcm2708/patches-4.4/0140-dt-overlay-add-wittypi-overlay.dts.patch
deleted file mode 100644
index b740c826f1..0000000000
--- a/target/linux/brcm2708/patches-4.4/0140-dt-overlay-add-wittypi-overlay.dts.patch
+++ /dev/null
@@ -1,57 +0,0 @@
-From e382e888be3f59b0ba3645809ae686947313e0c1 Mon Sep 17 00:00:00 2001
-From: vitalogy <vitalogy_github@milaw.biz>
-Date: Tue, 19 Jan 2016 07:02:02 +0100
-Subject: [PATCH 140/170] dt-overlay: add wittypi-overlay.dts
-
----
- arch/arm/boot/dts/overlays/wittypi-overlay.dts | 44 ++++++++++++++++++++++++++
- 1 file changed, 44 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/wittypi-overlay.dts
-
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/wittypi-overlay.dts
-@@ -0,0 +1,44 @@
-+/*
-+ * Device Tree overlay for Witty Pi extension board by UUGear
-+ *
-+ */
-+
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+
-+ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+
-+ fragment@0 {
-+ target = <&leds>;
-+ __overlay__ {
-+ compatible = "gpio-leds";
-+ wittypi_led: wittypi_led {
-+ label = "wittypi_led";
-+ linux,default-trigger = "default-on";
-+ gpios = <&gpio 17 0>;
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ rtc: ds1337@68 {
-+ compatible = "dallas,ds1337";
-+ reg = <0x68>;
-+ wakeup-source;
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ led_gpio = <&wittypi_led>,"gpios:4";
-+ led_trigger = <&wittypi_led>,"linux,default-trigger";
-+ };
-+
-+};
diff --git a/target/linux/brcm2708/patches-4.4/0141-BCM270X_DT-Disable-DMA-for-bcm2835-sdhost-on-Pi2.patch b/target/linux/brcm2708/patches-4.4/0141-BCM270X_DT-Disable-DMA-for-bcm2835-sdhost-on-Pi2.patch
deleted file mode 100644
index b06b4786ce..0000000000
--- a/target/linux/brcm2708/patches-4.4/0141-BCM270X_DT-Disable-DMA-for-bcm2835-sdhost-on-Pi2.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From 6dcfc3daab7c1c459b36261163b4e1dc15a6e965 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Wed, 3 Feb 2016 16:12:54 +0000
-Subject: [PATCH 141/170] BCM270X_DT: Disable DMA for bcm2835-sdhost on Pi2
-
-This is an interim patch to verify that problems seen with
-some cards can be worked around at the expense of an increased
-CPU load by forcing PIO mode.
-
-Although this could have used the brcm,force-pio attribute, that
-is a boolean (true if present, false if absent) and attributes
-can't be deleted by overlays. Instead, make brcm,pio-limit
-unfeasibly high instead to allow DMA to be re-enabled using the
-pio_limit parameter of the sdhost or sdtweak overlays.
----
- arch/arm/boot/dts/bcm2709-rpi-2-b.dts | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts
-+++ b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts
-@@ -43,6 +43,7 @@
- pinctrl-names = "default";
- pinctrl-0 = <&sdhost_pins>;
- bus-width = <4>;
-+ brcm,pio-limit = <0x7fffffff>;
- status = "okay";
- };
-
diff --git a/target/linux/brcm2708/patches-4.4/0141-Limit-PCM512x-Digital-gain-to-0dB-by-default-with-Hi.patch b/target/linux/brcm2708/patches-4.4/0141-Limit-PCM512x-Digital-gain-to-0dB-by-default-with-Hi.patch
new file mode 100644
index 0000000000..030d16ba13
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0141-Limit-PCM512x-Digital-gain-to-0dB-by-default-with-Hi.patch
@@ -0,0 +1,98 @@
+From 6e6173c6faef9a7188ea8d397e339ca5881a6f3a Mon Sep 17 00:00:00 2001
+From: Digital Dreamtime <clive.messer@digitaldreamtime.co.uk>
+Date: Thu, 4 Feb 2016 20:04:00 +0000
+Subject: [PATCH 141/381] Limit PCM512x "Digital" gain to 0dB by default with
+ HiFiBerry DAC+
+
+24db_digital_gain DT param can be used to specify that PCM512x
+codec "Digital" volume control should not be limited to 0dB gain,
+and if specified will allow the full 24dB gain.
+---
+ arch/arm/boot/dts/overlays/README | 17 +++++++++++++++--
+ .../arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts | 6 +++++-
+ sound/soc/bcm/hifiberry_dacplus.c | 14 ++++++++++++++
+ 3 files changed, 34 insertions(+), 3 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -273,8 +273,21 @@ Params: <None>
+
+ Name: hifiberry-dacplus
+ Info: Configures the HifiBerry DAC+ audio card
+-Load: dtoverlay=hifiberry-dacplus
+-Params: <None>
++Load: dtoverlay=hifiberry-dacplus,<param>=<val>
++Params: 24db_digital_gain Allow gain to be applied via the PCM512x codec
++ Digital volume control. Enable with
++ "dtoverlay=hifiberry-dacplus,24db_digital_gain"
++ (The default behaviour is that the Digital
++ volume control is limited to a maximum of
++ 0dB. ie. it can attenuate but not provide
++ gain. For most users, this will be desired
++ as it will prevent clipping. By appending
++ the 24dB_digital_gain parameter, the Digital
++ volume control will allow up to 24dB of
++ gain. If this parameter is enabled, it is the
++ responsibility of the user to ensure that
++ the Digital volume control is set to a value
++ that does not result in clipping/distortion!)
+
+
+ Name: hifiberry-digi
+--- a/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
+@@ -17,7 +17,7 @@
+
+ fragment@1 {
+ target = <&sound>;
+- __overlay__ {
++ frag1: __overlay__ {
+ compatible = "hifiberry,hifiberry-dacplus";
+ i2s-controller = <&i2s>;
+ status = "okay";
+@@ -47,4 +47,8 @@
+ };
+ };
+ };
++
++ __overrides__ {
++ 24db_digital_gain = <&frag1>,"hifiberry,24db_digital_gain?";
++ };
+ };
+--- a/sound/soc/bcm/hifiberry_dacplus.c
++++ b/sound/soc/bcm/hifiberry_dacplus.c
+@@ -48,6 +48,7 @@ struct pcm512x_priv {
+ #define CLK_48EN_RATE 24576000UL
+
+ static bool snd_rpi_hifiberry_is_dacpro;
++static bool digital_gain_0db_limit = true;
+
+ static void snd_rpi_hifiberry_dacplus_select_clk(struct snd_soc_codec *codec,
+ int clk_id)
+@@ -167,6 +168,16 @@ static int snd_rpi_hifiberry_dacplus_ini
+ snd_soc_update_bits(codec, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02);
+ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
+
++ if (digital_gain_0db_limit)
++ {
++ int ret;
++ struct snd_soc_card *card = rtd->card;
++
++ ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207);
++ if (ret < 0)
++ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
++ }
++
+ return 0;
+ }
+
+@@ -299,6 +310,9 @@ static int snd_rpi_hifiberry_dacplus_pro
+ dai->platform_name = NULL;
+ dai->platform_of_node = i2s_node;
+ }
++
++ digital_gain_0db_limit = !of_property_read_bool(
++ pdev->dev.of_node, "hifiberry,24db_digital_gain");
+ }
+
+ ret = snd_soc_register_card(&snd_rpi_hifiberry_dacplus);
diff --git a/target/linux/brcm2708/patches-4.4/0142-BCM270X_DT-Adjust-overlay-README-formatting.patch b/target/linux/brcm2708/patches-4.4/0142-BCM270X_DT-Adjust-overlay-README-formatting.patch
new file mode 100644
index 0000000000..ae3b967f0c
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0142-BCM270X_DT-Adjust-overlay-README-formatting.patch
@@ -0,0 +1,729 @@
+From 6f043ba868aaad8a5c7a802baafbba4e43f787e0 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 8 Feb 2016 09:46:33 +0000
+Subject: [PATCH 142/381] BCM270X_DT: Adjust overlay README formatting
+
+---
+ arch/arm/boot/dts/overlays/README | 414 +++++++++++++++++++-------------------
+ 1 file changed, 207 insertions(+), 207 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -83,58 +83,58 @@ Name: <The base DTB>
+ Info: Configures the base Raspberry Pi hardware
+ Load: <loaded automatically>
+ Params:
+- audio Set to "on" to enable the onboard ALSA audio
+- interface (default "off")
++ audio Set to "on" to enable the onboard ALSA audio
++ interface (default "off")
+
+- i2c_arm Set to "on" to enable the ARM's i2c interface
+- (default "off")
++ i2c_arm Set to "on" to enable the ARM's i2c interface
++ (default "off")
+
+- i2c_vc Set to "on" to enable the i2c interface
+- usually reserved for the VideoCore processor
+- (default "off")
++ i2c_vc Set to "on" to enable the i2c interface
++ usually reserved for the VideoCore processor
++ (default "off")
+
+- i2c An alias for i2c_arm
++ i2c An alias for i2c_arm
+
+- i2c_arm_baudrate Set the baudrate of the ARM's i2c interface
+- (default "100000")
++ i2c_arm_baudrate Set the baudrate of the ARM's i2c interface
++ (default "100000")
+
+- i2c_vc_baudrate Set the baudrate of the VideoCore i2c interface
+- (default "100000")
++ i2c_vc_baudrate Set the baudrate of the VideoCore i2c interface
++ (default "100000")
+
+- i2c_baudrate An alias for i2c_arm_baudrate
++ i2c_baudrate An alias for i2c_arm_baudrate
+
+- i2s Set to "on" to enable the i2s interface
+- (default "off")
++ i2s Set to "on" to enable the i2s interface
++ (default "off")
+
+- spi Set to "on" to enable the spi interfaces
+- (default "off")
++ spi Set to "on" to enable the spi interfaces
++ (default "off")
+
+- random Set to "on" to enable the hardware random
+- number generator (default "on")
++ random Set to "on" to enable the hardware random
++ number generator (default "on")
+
+- uart0 Set to "off" to disable uart0 (default "on")
++ uart0 Set to "off" to disable uart0 (default "on")
+
+- watchdog Set to "on" to enable the hardware watchdog
+- (default "off")
++ watchdog Set to "on" to enable the hardware watchdog
++ (default "off")
+
+- act_led_trigger Choose which activity the LED tracks.
+- Use "heartbeat" for a nice load indicator.
+- (default "mmc")
++ act_led_trigger Choose which activity the LED tracks.
++ Use "heartbeat" for a nice load indicator.
++ (default "mmc")
+
+- act_led_activelow Set to "on" to invert the sense of the LED
+- (default "off")
++ act_led_activelow Set to "on" to invert the sense of the LED
++ (default "off")
+
+- act_led_gpio Set which GPIO to use for the activity LED
+- (in case you want to connect it to an external
+- device)
+- (default "16" on a non-Plus board, "47" on a
+- Plus or Pi 2)
++ act_led_gpio Set which GPIO to use for the activity LED
++ (in case you want to connect it to an external
++ device)
++ (default "16" on a non-Plus board, "47" on a
++ Plus or Pi 2)
+
+ pwr_led_trigger
+ pwr_led_activelow
+ pwr_led_gpio
+- As for act_led_*, but using the PWR LED.
+- Not available on Model A/B boards.
++ As for act_led_*, but using the PWR LED.
++ Not available on Model A/B boards.
+
+ N.B. It is recommended to only enable those interfaces that are needed.
+ Leaving all interfaces enabled can lead to unwanted behaviour (i2c_vc
+@@ -149,19 +149,19 @@ Params:
+ Name: ads7846
+ Info: ADS7846 Touch controller
+ Load: dtoverlay=ads7846,<param>=<val>
+-Params: cs SPI bus Chip Select (default 1)
+- speed SPI bus speed (default 2MHz, max 3.25MHz)
+- penirq GPIO used for PENIRQ. REQUIRED
+- penirq_pull Set GPIO pull (default 0=none, 2=pullup)
+- swapxy Swap x and y axis
+- xmin Minimum value on the X axis (default 0)
+- ymin Minimum value on the Y axis (default 0)
+- xmax Maximum value on the X axis (default 4095)
+- ymax Maximum value on the Y axis (default 4095)
+- pmin Minimum reported pressure value (default 0)
+- pmax Maximum reported pressure value (default 65535)
+- xohms Touchpanel sensitivity (X-plate resistance)
+- (default 400)
++Params: cs SPI bus Chip Select (default 1)
++ speed SPI bus speed (default 2MHz, max 3.25MHz)
++ penirq GPIO used for PENIRQ. REQUIRED
++ penirq_pull Set GPIO pull (default 0=none, 2=pullup)
++ swapxy Swap x and y axis
++ xmin Minimum value on the X axis (default 0)
++ ymin Minimum value on the Y axis (default 0)
++ xmax Maximum value on the X axis (default 4095)
++ ymax Maximum value on the Y axis (default 4095)
++ pmin Minimum reported pressure value (default 0)
++ pmax Maximum reported pressure value (default 65535)
++ xohms Touchpanel sensitivity (X-plate resistance)
++ (default 400)
+
+ penirq is required and usually xohms (60-100) has to be set as well.
+ Apart from that, pmax (255) and swapxy are also common.
+@@ -175,12 +175,12 @@ Name: at86rf233
+ Info: Configures the Atmel AT86RF233 802.15.4 low-power WPAN transceiver,
+ connected to spi0.0
+ Load: dtoverlay=at86rf233,<param>=<val>
+-Params: interrupt GPIO used for INT (default 23)
+- reset GPIO used for Reset (default 24)
+- sleep GPIO used for Sleep (default 25)
+- speed SPI bus speed in Hz (default 6000000)
+- trim Fine tuning of the internal capacitance
+- arrays (0=+0pF, 15=+4.5pF, default 15)
++Params: interrupt GPIO used for INT (default 23)
++ reset GPIO used for Reset (default 24)
++ sleep GPIO used for Sleep (default 25)
++ speed SPI bus speed in Hz (default 6000000)
++ trim Fine tuning of the internal capacitance
++ arrays (0=+0pF, 15=+4.5pF, default 15)
+
+
+ Name: bmp085_i2c-sensor
+@@ -194,8 +194,8 @@ Name: dht11
+ Info: Overlay for the DHT11/DHT21/DHT22 humidity/temperature sensors
+ Also sometimes found with the part number(s) AM230x.
+ Load: dtoverlay=dht11,<param>=<val>
+-Params: gpiopin GPIO connected to the sensor's DATA output.
+- (default 4)
++Params: gpiopin GPIO connected to the sensor's DATA output.
++ (default 4)
+
+
+ Name: dwc-otg
+@@ -208,15 +208,15 @@ Params: <None>
+ Name: dwc2
+ Info: Selects the dwc2 USB controller driver
+ Load: dtoverlay=dwc2,<param>=<val>
+-Params: dr_mode Dual role mode: "host", "peripheral" or "otg"
++Params: dr_mode Dual role mode: "host", "peripheral" or "otg"
+
+- g-rx-fifo-size Size of rx fifo size in gadget mode
++ g-rx-fifo-size Size of rx fifo size in gadget mode
+
+- g-np-tx-fifo-size Size of non-periodic tx fifo size in gadget
+- mode
++ g-np-tx-fifo-size Size of non-periodic tx fifo size in gadget
++ mode
+
+- g-tx-fifo-size Size of periodic tx fifo per endpoint
+- (except ep0) in gadget mode
++ g-tx-fifo-size Size of periodic tx fifo per endpoint
++ (except ep0) in gadget mode
+
+
+ [ The ds1307-rtc overlay has been deleted. See i2c-rtc. ]
+@@ -225,9 +225,9 @@ Params: dr_mode Dual ro
+ Name: enc28j60
+ Info: Overlay for the Microchip ENC28J60 Ethernet Controller (SPI)
+ Load: dtoverlay=enc28j60,<param>=<val>
+-Params: int_pin GPIO used for INT (default 25)
++Params: int_pin GPIO used for INT (default 25)
+
+- speed SPI bus speed (default 12000000)
++ speed SPI bus speed (default 12000000)
+
+
+ Name: gpio-ir
+@@ -237,26 +237,26 @@ Info: Use GPIO pin as rc-core style in
+ not required! The key mapping and other decoding parameters can be
+ configured by "ir-keytable" tool.
+ Load: dtoverlay=gpio-ir,<param>=<val>
+-Params: gpio_pin Input pin number. Default is 18.
++Params: gpio_pin Input pin number. Default is 18.
+
+- gpio_pull Desired pull-up/down state (off, down, up)
+- Default is "down".
++ gpio_pull Desired pull-up/down state (off, down, up)
++ Default is "down".
+
+- rc-map-name Default rc keymap (can also be changed by
+- ir-keytable), defaults to "rc-rc6-mce"
++ rc-map-name Default rc keymap (can also be changed by
++ ir-keytable), defaults to "rc-rc6-mce"
+
+
+ Name: gpio-poweroff
+ Info: Drives a GPIO high or low on reboot
+ Load: dtoverlay=gpio-poweroff,<param>=<val>
+-Params: gpiopin GPIO for signalling (default 26)
++Params: gpiopin GPIO for signalling (default 26)
+
+- active_low Set if the power control device requires a
+- high->low transition to trigger a power-down.
+- Note that this will require the support of a
+- custom dt-blob.bin to prevent a power-down
+- during the boot process, and that a reboot
+- will also cause the pin to go low.
++ active_low Set if the power control device requires a
++ high->low transition to trigger a power-down.
++ Note that this will require the support of a
++ custom dt-blob.bin to prevent a power-down
++ during the boot process, and that a reboot
++ will also cause the pin to go low.
+
+
+ Name: hifiberry-amp
+@@ -300,65 +300,65 @@ Name: hy28a
+ Info: HY28A - 2.8" TFT LCD Display Module by HAOYU Electronics
+ Default values match Texy's display shield
+ Load: dtoverlay=hy28a,<param>=<val>
+-Params: speed Display SPI bus speed
++Params: speed Display SPI bus speed
+
+- rotate Display rotation {0,90,180,270}
++ rotate Display rotation {0,90,180,270}
+
+- fps Delay between frame updates
++ fps Delay between frame updates
+
+- debug Debug output level {0-7}
++ debug Debug output level {0-7}
+
+- xohms Touchpanel sensitivity (X-plate resistance)
++ xohms Touchpanel sensitivity (X-plate resistance)
+
+- resetgpio GPIO used to reset controller
++ resetgpio GPIO used to reset controller
+
+- ledgpio GPIO used to control backlight
++ ledgpio GPIO used to control backlight
+
+
+ Name: hy28b
+ Info: HY28B - 2.8" TFT LCD Display Module by HAOYU Electronics
+ Default values match Texy's display shield
+ Load: dtoverlay=hy28b,<param>=<val>
+-Params: speed Display SPI bus speed
++Params: speed Display SPI bus speed
+
+- rotate Display rotation {0,90,180,270}
++ rotate Display rotation {0,90,180,270}
+
+- fps Delay between frame updates
++ fps Delay between frame updates
+
+- debug Debug output level {0-7}
++ debug Debug output level {0-7}
+
+- xohms Touchpanel sensitivity (X-plate resistance)
++ xohms Touchpanel sensitivity (X-plate resistance)
+
+- resetgpio GPIO used to reset controller
++ resetgpio GPIO used to reset controller
+
+- ledgpio GPIO used to control backlight
++ ledgpio GPIO used to control backlight
+
+
+ Name: i2c-gpio
+ Info: Adds support for software i2c controller on gpio pins
+ Load: dtoverlay=i2c-gpio,<param>=<val>
+-Params: i2c_gpio_sda GPIO used for I2C data (default "23")
++Params: i2c_gpio_sda GPIO used for I2C data (default "23")
+
+- i2c_gpio_scl GPIO used for I2C clock (default "24")
++ i2c_gpio_scl GPIO used for I2C clock (default "24")
+
+- i2c_gpio_delay_us Clock delay in microseconds
+- (default "2" = ~100kHz)
++ i2c_gpio_delay_us Clock delay in microseconds
++ (default "2" = ~100kHz)
+
+
+ Name: i2c-rtc
+ Info: Adds support for a number of I2C Real Time Clock devices
+ Load: dtoverlay=i2c-rtc,<param>=<val>
+-Params: ds1307 Select the DS1307 device
++Params: ds1307 Select the DS1307 device
+
+- ds3231 Select the DS3231 device
++ ds3231 Select the DS3231 device
+
+- mcp7941x Select the MCP7941x device
++ mcp7941x Select the MCP7941x device
+
+- pcf2127 Select the PCF2127 device
++ pcf2127 Select the PCF2127 device
+
+- pcf8523 Select the PCF8523 device
++ pcf8523 Select the PCF8523 device
+
+- pcf8563 Select the PCF8563 device
++ pcf8563 Select the PCF8563 device
+
+
+ Name: i2s-mmap
+@@ -396,70 +396,70 @@ Name: lirc-rpi
+ Info: Configures lirc-rpi (Linux Infrared Remote Control for Raspberry Pi)
+ Consult the module documentation for more details.
+ Load: dtoverlay=lirc-rpi,<param>=<val>
+-Params: gpio_out_pin GPIO for output (default "17")
++Params: gpio_out_pin GPIO for output (default "17")
+
+- gpio_in_pin GPIO for input (default "18")
++ gpio_in_pin GPIO for input (default "18")
+
+- gpio_in_pull Pull up/down/off on the input pin
+- (default "down")
++ gpio_in_pull Pull up/down/off on the input pin
++ (default "down")
+
+- sense Override the IR receive auto-detection logic:
+- "0" = force active-high
+- "1" = force active-low
+- "-1" = use auto-detection
+- (default "-1")
++ sense Override the IR receive auto-detection logic:
++ "0" = force active-high
++ "1" = force active-low
++ "-1" = use auto-detection
++ (default "-1")
+
+- softcarrier Turn the software carrier "on" or "off"
+- (default "on")
++ softcarrier Turn the software carrier "on" or "off"
++ (default "on")
+
+- invert "on" = invert the output pin (default "off")
++ invert "on" = invert the output pin (default "off")
+
+- debug "on" = enable additional debug messages
+- (default "off")
++ debug "on" = enable additional debug messages
++ (default "off")
+
+
+ Name: mcp2515-can0
+ Info: Configures the MCP2515 CAN controller on spi0.0
+ Load: dtoverlay=mcp2515-can0,<param>=<val>
+-Params: oscillator Clock frequency for the CAN controller (Hz)
++Params: oscillator Clock frequency for the CAN controller (Hz)
+
+- spimaxfrequency Maximum SPI frequence (Hz)
++ spimaxfrequency Maximum SPI frequence (Hz)
+
+- interrupt GPIO for interrupt signal
++ interrupt GPIO for interrupt signal
+
+
+ Name: mcp2515-can1
+ Info: Configures the MCP2515 CAN controller on spi0.1
+ Load: dtoverlay=mcp2515-can1,<param>=<val>
+-Params: oscillator Clock frequency for the CAN controller (Hz)
++Params: oscillator Clock frequency for the CAN controller (Hz)
+
+- spimaxfrequency Maximum SPI frequence (Hz)
++ spimaxfrequency Maximum SPI frequence (Hz)
+
+- interrupt GPIO for interrupt signal
++ interrupt GPIO for interrupt signal
+
+
+ Name: mmc
+ Info: Selects the bcm2835-mmc SD/MMC driver, optionally with overclock
+ Load: dtoverlay=mmc,<param>=<val>
+-Params: overclock_50 Clock (in MHz) to use when the MMC framework
+- requests 50MHz
+- force_pio Disable DMA support
++Params: overclock_50 Clock (in MHz) to use when the MMC framework
++ requests 50MHz
++ force_pio Disable DMA support
+
+
+ Name: mz61581
+ Info: MZ61581 display by Tontec
+ Load: dtoverlay=mz61581,<param>=<val>
+-Params: speed Display SPI bus speed
++Params: speed Display SPI bus speed
+
+- rotate Display rotation {0,90,180,270}
++ rotate Display rotation {0,90,180,270}
+
+- fps Delay between frame updates
++ fps Delay between frame updates
+
+- txbuflen Transmit buffer length (default 32768)
++ txbuflen Transmit buffer length (default 32768)
+
+- debug Debug output level {0-7}
++ debug Debug output level {0-7}
+
+- xohms Touchpanel sensitivity (X-plate resistance)
++ xohms Touchpanel sensitivity (X-plate resistance)
+
+
+ [ The pcf2127-rtc overlay has been deleted. See i2c-rtc. ]
+@@ -474,69 +474,69 @@ Params: speed Display
+ Name: piscreen
+ Info: PiScreen display by OzzMaker.com
+ Load: dtoverlay=piscreen,<param>=<val>
+-Params: speed Display SPI bus speed
++Params: speed Display SPI bus speed
+
+- rotate Display rotation {0,90,180,270}
++ rotate Display rotation {0,90,180,270}
+
+- fps Delay between frame updates
++ fps Delay between frame updates
+
+- debug Debug output level {0-7}
++ debug Debug output level {0-7}
+
+- xohms Touchpanel sensitivity (X-plate resistance)
++ xohms Touchpanel sensitivity (X-plate resistance)
+
+
+ Name: piscreen2r
+ Info: PiScreen 2 with resistive TP display by OzzMaker.com
+ Load: dtoverlay=piscreen2r,<param>=<val>
+-Params: speed Display SPI bus speed
++Params: speed Display SPI bus speed
+
+- rotate Display rotation {0,90,180,270}
++ rotate Display rotation {0,90,180,270}
+
+- fps Delay between frame updates
++ fps Delay between frame updates
+
+- debug Debug output level {0-7}
++ debug Debug output level {0-7}
+
+- xohms Touchpanel sensitivity (X-plate resistance)
++ xohms Touchpanel sensitivity (X-plate resistance)
+
+
+ Name: pitft28-capacitive
+ Info: Adafruit PiTFT 2.8" capacitive touch screen
+ Load: dtoverlay=pitft28-capacitive,<param>=<val>
+-Params: speed Display SPI bus speed
++Params: speed Display SPI bus speed
+
+- rotate Display rotation {0,90,180,270}
++ rotate Display rotation {0,90,180,270}
+
+- fps Delay between frame updates
++ fps Delay between frame updates
+
+- debug Debug output level {0-7}
++ debug Debug output level {0-7}
+
+- touch-sizex Touchscreen size x (default 240)
++ touch-sizex Touchscreen size x (default 240)
+
+- touch-sizey Touchscreen size y (default 320)
++ touch-sizey Touchscreen size y (default 320)
+
+- touch-invx Touchscreen inverted x axis
++ touch-invx Touchscreen inverted x axis
+
+- touch-invy Touchscreen inverted y axis
++ touch-invy Touchscreen inverted y axis
+
+- touch-swapxy Touchscreen swapped x y axis
++ touch-swapxy Touchscreen swapped x y axis
+
+
+ Name: pitft28-resistive
+ Info: Adafruit PiTFT 2.8" resistive touch screen
+ Load: dtoverlay=pitft28-resistive,<param>=<val>
+-Params: speed Display SPI bus speed
++Params: speed Display SPI bus speed
+
+- rotate Display rotation {0,90,180,270}
++ rotate Display rotation {0,90,180,270}
+
+- fps Delay between frame updates
++ fps Delay between frame updates
+
+- debug Debug output level {0-7}
++ debug Debug output level {0-7}
+
+
+ Name: pps-gpio
+ Info: Configures the pps-gpio (pulse-per-second time signal via GPIO).
+ Load: dtoverlay=pps-gpio,<param>=<val>
+-Params: gpiopin Input GPIO (default "18")
++Params: gpiopin Input GPIO (default "18")
+
+
+ Name: pwm
+@@ -553,9 +553,9 @@ Info: Configures a single PWM channel
+ 4) Currently the clock must have been enabled and configured
+ by other means.
+ Load: dtoverlay=pwm,<param>=<val>
+-Params: pin Output pin (default 18) - see table
+- func Pin function (default 2 = Alt5) - see above
+- clock PWM clock frequency (informational)
++Params: pin Output pin (default 18) - see table
++ func Pin function (default 2 = Alt5) - see above
++ clock PWM clock frequency (informational)
+
+
+ Name: pwm-2chan
+@@ -572,11 +572,11 @@ Info: Configures both PWM channels
+ 4) Currently the clock must have been enabled and configured
+ by other means.
+ Load: dtoverlay=pwm-2chan,<param>=<val>
+-Params: pin Output pin (default 18) - see table
+- pin2 Output pin for other channel (default 19)
+- func Pin function (default 2 = Alt5) - see above
+- func2 Function for pin2 (default 2 = Alt5)
+- clock PWM clock frequency (informational)
++Params: pin Output pin (default 18) - see table
++ pin2 Output pin for other channel (default 19)
++ func Pin function (default 2 = Alt5) - see above
++ func2 Function for pin2 (default 2 = Alt5)
++ clock PWM clock frequency (informational)
+
+
+ Name: raspidac3
+@@ -600,15 +600,15 @@ Params: <None>
+ Name: rpi-display
+ Info: RPi-Display - 2.8" Touch Display by Watterott
+ Load: dtoverlay=rpi-display,<param>=<val>
+-Params: speed Display SPI bus speed
++Params: speed Display SPI bus speed
+
+- rotate Display rotation {0,90,180,270}
++ rotate Display rotation {0,90,180,270}
+
+- fps Delay between frame updates
++ fps Delay between frame updates
+
+- debug Debug output level {0-7}
++ debug Debug output level {0-7}
+
+- xohms Touchpanel sensitivity (X-plate resistance)
++ xohms Touchpanel sensitivity (X-plate resistance)
+
+
+ Name: rpi-ft5406
+@@ -632,52 +632,52 @@ Params: <None>
+ Name: sdhost
+ Info: Selects the bcm2835-sdhost SD/MMC driver, optionally with overclock
+ Load: dtoverlay=sdhost,<param>=<val>
+-Params: overclock_50 Clock (in MHz) to use when the MMC framework
+- requests 50MHz
++Params: overclock_50 Clock (in MHz) to use when the MMC framework
++ requests 50MHz
+
+- force_pio Disable DMA support (default off)
++ force_pio Disable DMA support (default off)
+
+- pio_limit Number of blocks above which to use DMA
+- (default 1)
++ pio_limit Number of blocks above which to use DMA
++ (default 1)
+
+- debug Enable debug output (default off)
++ debug Enable debug output (default off)
+
+
+ Name: sdio
+ Info: Selects the bcm2835-sdhost SD/MMC driver, optionally with overclock,
+ and enables SDIO via GPIOs 22-27.
+ Load: dtoverlay=sdio,<param>=<val>
+-Params: overclock_50 SD Clock (in MHz) to use when the MMC framework
+- requests 50MHz
++Params: overclock_50 SD Clock (in MHz) to use when the MMC framework
++ requests 50MHz
+
+- sdio_overclock SDIO Clock (in MHz) to use when the MMC
+- framework requests 50MHz
++ sdio_overclock SDIO Clock (in MHz) to use when the MMC
++ framework requests 50MHz
+
+- force_pio Disable DMA support (default off)
++ force_pio Disable DMA support (default off)
+
+- pio_limit Number of blocks above which to use DMA
+- (default 1)
++ pio_limit Number of blocks above which to use DMA
++ (default 1)
+
+- debug Enable debug output (default off)
++ debug Enable debug output (default off)
+
+- poll_once Disable SDIO-device polling every second
+- (default on: polling once at boot-time)
++ poll_once Disable SDIO-device polling every second
++ (default on: polling once at boot-time)
+
+- bus_width Set the SDIO host bus width (default 4 bits)
++ bus_width Set the SDIO host bus width (default 4 bits)
+
+
+ Name: sdtweak
+ Info: Tunes the bcm2835-sdhost SD/MMC driver
+ Load: dtoverlay=sdtweak,<param>=<val>
+-Params: overclock_50 Clock (in MHz) to use when the MMC framework
+- requests 50MHz
++Params: overclock_50 Clock (in MHz) to use when the MMC framework
++ requests 50MHz
+
+- force_pio Disable DMA support (default off)
++ force_pio Disable DMA support (default off)
+
+- pio_limit Number of blocks above which to use DMA
+- (default 1)
++ pio_limit Number of blocks above which to use DMA
++ (default 1)
+
+- debug Enable debug output (default off)
++ debug Enable debug output (default off)
+
+
+ Name: smi
+@@ -708,25 +708,25 @@ Name: tinylcd35
+ Info: 3.5" Color TFT Display by www.tinylcd.com
+ Options: Touch, RTC, keypad
+ Load: dtoverlay=tinylcd35,<param>=<val>
+-Params: speed Display SPI bus speed
++Params: speed Display SPI bus speed
+
+- rotate Display rotation {0,90,180,270}
++ rotate Display rotation {0,90,180,270}
+
+- fps Delay between frame updates
++ fps Delay between frame updates
+
+- debug Debug output level {0-7}
++ debug Debug output level {0-7}
+
+- touch Enable touch panel
++ touch Enable touch panel
+
+- touchgpio Touch controller IRQ GPIO
++ touchgpio Touch controller IRQ GPIO
+
+- xohms Touchpanel: Resistance of X-plate in ohms
++ xohms Touchpanel: Resistance of X-plate in ohms
+
+- rtc-pcf PCF8563 Real Time Clock
++ rtc-pcf PCF8563 Real Time Clock
+
+- rtc-ds DS1307 Real Time Clock
++ rtc-ds DS1307 Real Time Clock
+
+- keypad Enable keypad
++ keypad Enable keypad
+
+ Examples:
+ Display with touchpanel, PCF8563 RTC and keypad:
+@@ -738,9 +738,9 @@ Params: speed Display
+ Name: uart1
+ Info: Enable uart1 in place of uart0
+ Load: dtoverlay=uart1,<param>=<val>
+-Params: txd1_pin GPIO pin for TXD1 (14, 32 or 40 - default 14)
++Params: txd1_pin GPIO pin for TXD1 (14, 32 or 40 - default 14)
+
+- rxd1_pin GPIO pin for RXD1 (15, 33 or 41 - default 15)
++ rxd1_pin GPIO pin for RXD1 (15, 33 or 41 - default 15)
+
+
+ Name: vc4-kms-v3d
+@@ -763,22 +763,22 @@ Name: w1-gpio
+ Info: Configures the w1-gpio Onewire interface module.
+ Use this overlay if you *don't* need a GPIO to drive an external pullup.
+ Load: dtoverlay=w1-gpio,<param>=<val>
+-Params: gpiopin GPIO for I/O (default "4")
++Params: gpiopin GPIO for I/O (default "4")
+
+- pullup Non-zero, "on", or "y" to enable the parasitic
+- power (2-wire, power-on-data) feature
++ pullup Non-zero, "on", or "y" to enable the parasitic
++ power (2-wire, power-on-data) feature
+
+
+ Name: w1-gpio-pullup
+ Info: Configures the w1-gpio Onewire interface module.
+ Use this overlay if you *do* need a GPIO to drive an external pullup.
+ Load: dtoverlay=w1-gpio-pullup,<param>=<val>
+-Params: gpiopin GPIO for I/O (default "4")
++Params: gpiopin GPIO for I/O (default "4")
+
+- pullup Non-zero, "on", or "y" to enable the parasitic
+- power (2-wire, power-on-data) feature
++ pullup Non-zero, "on", or "y" to enable the parasitic
++ power (2-wire, power-on-data) feature
+
+- extpullup GPIO for external pullup (default "5")
++ extpullup GPIO for external pullup (default "5")
+
+
+ Troubleshooting
diff --git a/target/linux/brcm2708/patches-4.4/0142-FIXUP-i2c_bcm2708-Don-t-change-module-baudrate-param.patch b/target/linux/brcm2708/patches-4.4/0142-FIXUP-i2c_bcm2708-Don-t-change-module-baudrate-param.patch
deleted file mode 100644
index b3ce9719ac..0000000000
--- a/target/linux/brcm2708/patches-4.4/0142-FIXUP-i2c_bcm2708-Don-t-change-module-baudrate-param.patch
+++ /dev/null
@@ -1,99 +0,0 @@
-From 7519a79f61a67792e238a118db58600fb5f60ec8 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Tue, 19 Jan 2016 16:28:05 +0000
-Subject: [PATCH 142/170] FIXUP i2c_bcm2708: Don't change module baudrate
- parameter
-
-Overwriting the baudrate module parameter creates an apparent
-forced baudrate for i2c busses after the first. Not only does this
-override the baudrate from DT it also prevents the bus ID from
-being initialised.
-
-Also fix whitespace errors.
----
- drivers/i2c/busses/i2c-bcm2708.c | 48 +++++++++++++++++++++-------------------
- 1 file changed, 25 insertions(+), 23 deletions(-)
-
---- a/drivers/i2c/busses/i2c-bcm2708.c
-+++ b/drivers/i2c/busses/i2c-bcm2708.c
-@@ -71,7 +71,6 @@
-
- #define DRV_NAME "bcm2708_i2c"
-
--static unsigned int baudrate_default = CONFIG_I2C_BCM2708_BAUDRATE;
- static unsigned int baudrate;
- module_param(baudrate, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
- MODULE_PARM_DESC(baudrate, "The I2C baudrate");
-@@ -317,25 +316,28 @@ static int bcm2708_i2c_probe(struct plat
- struct i2c_adapter *adap;
- unsigned long bus_hz;
- u32 cdiv, clk_tout;
--
-- if (!baudrate) {
-- baudrate = baudrate_default;
-- if (pdev->dev.of_node) {
-- u32 bus_clk_rate;
-- pdev->id = of_alias_get_id(pdev->dev.of_node, "i2c");
-- if (pdev->id < 0) {
-- dev_err(&pdev->dev, "alias is missing\n");
-- return -EINVAL;
-- }
-- if (!of_property_read_u32(pdev->dev.of_node,
-- "clock-frequency", &bus_clk_rate))
-- baudrate = bus_clk_rate;
-- else
-- dev_warn(&pdev->dev,
-- "Could not read clock-frequency property\n");
-+ u32 baud;
-+
-+ baud = CONFIG_I2C_BCM2708_BAUDRATE;
-+
-+ if (pdev->dev.of_node) {
-+ u32 bus_clk_rate;
-+ pdev->id = of_alias_get_id(pdev->dev.of_node, "i2c");
-+ if (pdev->id < 0) {
-+ dev_err(&pdev->dev, "alias is missing\n");
-+ return -EINVAL;
- }
-+ if (!of_property_read_u32(pdev->dev.of_node,
-+ "clock-frequency", &bus_clk_rate))
-+ baud = bus_clk_rate;
-+ else
-+ dev_warn(&pdev->dev,
-+ "Could not read clock-frequency property\n");
- }
-
-+ if (baudrate)
-+ baud = baudrate;
-+
- regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!regs) {
- dev_err(&pdev->dev, "could not get IO memory\n");
-@@ -419,21 +421,21 @@ static int bcm2708_i2c_probe(struct plat
- }
-
- bus_hz = clk_get_rate(bi->clk);
-- cdiv = bus_hz / baudrate;
-+ cdiv = bus_hz / baud;
- if (cdiv > 0xffff) {
- cdiv = 0xffff;
-- baudrate = bus_hz / cdiv;
-+ baud = bus_hz / cdiv;
- }
--
-- clk_tout = 35/1000*baudrate; //35ms timeout as per SMBus specs.
-- if (clk_tout > 0xffff)
-+
-+ clk_tout = 35/1000*baud; //35ms timeout as per SMBus specs.
-+ if (clk_tout > 0xffff)
- clk_tout = 0xffff;
-
- bi->cdiv = cdiv;
- bi->clk_tout = clk_tout;
-
- dev_info(&pdev->dev, "BSC%d Controller at 0x%08lx (irq %d) (baudrate %d)\n",
-- pdev->id, (unsigned long)regs->start, irq, baudrate);
-+ pdev->id, (unsigned long)regs->start, irq, baud);
-
- return 0;
-
diff --git a/target/linux/brcm2708/patches-4.4/0143-Allow-up-to-24dB-digital-gain-to-be-applied-when-usi.patch b/target/linux/brcm2708/patches-4.4/0143-Allow-up-to-24dB-digital-gain-to-be-applied-when-usi.patch
deleted file mode 100644
index 646bb27845..0000000000
--- a/target/linux/brcm2708/patches-4.4/0143-Allow-up-to-24dB-digital-gain-to-be-applied-when-usi.patch
+++ /dev/null
@@ -1,99 +0,0 @@
-From f2d36d57d7e17b9f44ff914824df5b150eb9e3bd Mon Sep 17 00:00:00 2001
-From: Digital Dreamtime <clive.messer@digitaldreamtime.co.uk>
-Date: Thu, 4 Feb 2016 14:14:44 +0000
-Subject: [PATCH 143/170] Allow up to 24dB digital gain to be applied when
- using IQAudIO DAC+
-
-24db_digital_gain DT param can be used to specify that PCM512x
-codec "Digital" volume control should not be limited to 0dB gain,
-and if specified will allow the full 24dB gain.
----
- arch/arm/boot/dts/overlays/README | 17 +++++++++++++++--
- .../boot/dts/overlays/iqaudio-dacplus-overlay.dts | 6 +++++-
- sound/soc/bcm/iqaudio-dac.c | 20 ++++++++++++++------
- 3 files changed, 34 insertions(+), 9 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -362,8 +362,21 @@ Params: <None>
-
- Name: iqaudio-dacplus
- Info: Configures the IQaudio DAC+ audio card
--Load: dtoverlay=iqaudio-dacplus
--Params: <None>
-+Load: dtoverlay=iqaudio-dacplus,<param>=<val>
-+Params: 24db_digital_gain Allow gain to be applied via the PCM512x codec
-+ Digital volume control. Enable with
-+ "dtoverlay=iqaudio-dacplus,24db_digital_gain"
-+ (The default behaviour is that the Digital
-+ volume control is limited to a maximum of
-+ 0dB. ie. it can attenuate but not provide
-+ gain. For most users, this will be desired
-+ as it will prevent clipping. By appending
-+ the 24db_digital_gain parameter, the Digital
-+ volume control will allow up to 24dB of
-+ gain. If this parameter is enabled, it is the
-+ responsibility of the user to ensure that
-+ the Digital volume control is set to a value
-+ that does not result in clipping/distortion!)
-
-
- Name: lirc-rpi
---- a/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts
-@@ -7,7 +7,7 @@
-
- fragment@0 {
- target = <&sound>;
-- __overlay__ {
-+ frag0: __overlay__ {
- compatible = "iqaudio,iqaudio-dac";
- i2s-controller = <&i2s>;
- status = "okay";
-@@ -36,4 +36,8 @@
- };
- };
- };
-+
-+ __overrides__ {
-+ 24db_digital_gain = <&frag0>,"iqaudio,24db_digital_gain?";
-+ };
- };
---- a/sound/soc/bcm/iqaudio-dac.c
-+++ b/sound/soc/bcm/iqaudio-dac.c
-@@ -23,14 +23,19 @@
- #include <sound/soc.h>
- #include <sound/jack.h>
-
-+static bool digital_gain_0db_limit = true;
-+
- static int snd_rpi_iqaudio_dac_init(struct snd_soc_pcm_runtime *rtd)
- {
-- int ret;
-- struct snd_soc_card *card = rtd->card;
--
-- ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207);
-- if (ret < 0)
-- dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
-+ if (digital_gain_0db_limit)
-+ {
-+ int ret;
-+ struct snd_soc_card *card = rtd->card;
-+
-+ ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207);
-+ if (ret < 0)
-+ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
-+ }
-
- return 0;
- }
-@@ -94,6 +99,9 @@ static int snd_rpi_iqaudio_dac_probe(str
- dai->platform_name = NULL;
- dai->platform_of_node = i2s_node;
- }
-+
-+ digital_gain_0db_limit = !of_property_read_bool(pdev->dev.of_node,
-+ "iqaudio,24db_digital_gain");
- }
-
- ret = snd_soc_register_card(&snd_rpi_iqaudio_dac);
diff --git a/target/linux/brcm2708/patches-4.4/0143-bcm2835-sdhost-Major-revision.patch b/target/linux/brcm2708/patches-4.4/0143-bcm2835-sdhost-Major-revision.patch
new file mode 100644
index 0000000000..85f25b2c89
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0143-bcm2835-sdhost-Major-revision.patch
@@ -0,0 +1,2070 @@
+From 6e7c35ac419f74f7edbbc5a09aaa2b4c75b63133 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Thu, 11 Feb 2016 16:51:01 +0000
+Subject: [PATCH 143/381] bcm2835-sdhost: Major revision
+
+This is a significant revision of the bcm2835-sdhost driver. It
+improves on the original in a number of ways:
+
+1) Through the use of CMD23 for reads it appears to avoid problems
+ reading some sectors on certain high speed cards.
+2) Better atomicity to prevent crashes.
+3) Higher performance.
+4) Activity logging included, for easier diagnosis in the event
+ of a problem.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/mmc/host/bcm2835-sdhost.c | 1284 ++++++++++++++++++++-----------------
+ 1 file changed, 686 insertions(+), 598 deletions(-)
+
+--- a/drivers/mmc/host/bcm2835-sdhost.c
++++ b/drivers/mmc/host/bcm2835-sdhost.c
+@@ -2,7 +2,7 @@
+ * BCM2835 SD host driver.
+ *
+ * Author: Phil Elwell <phil@raspberrypi.org>
+- * Copyright 2015
++ * Copyright (C) 2015-2016 Raspberry Pi (Trading) Ltd.
+ *
+ * Based on
+ * mmc-bcm2835.c by Gellert Weisz
+@@ -24,12 +24,13 @@
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+-#define SAFE_READ_THRESHOLD 4
+-#define SAFE_WRITE_THRESHOLD 4
+-#define ALLOW_DMA 1
+-#define ALLOW_CMD23 0
+-#define ALLOW_FAST 1
+-#define USE_BLOCK_IRQ 1
++#define FIFO_READ_THRESHOLD 4
++#define FIFO_WRITE_THRESHOLD 4
++#define ALLOW_CMD23_READ 1
++#define ALLOW_CMD23_WRITE 0
++#define ENABLE_LOG 1
++#define SDDATA_FIFO_PIO_BURST 8
++#define CMD_DALLY_US 1
+
+ #include <linux/delay.h>
+ #include <linux/module.h>
+@@ -48,6 +49,7 @@
+ #include <linux/dma-mapping.h>
+ #include <linux/of_dma.h>
+ #include <linux/time.h>
++#include <linux/workqueue.h>
+
+ #define DRIVER_NAME "sdhost-bcm2835"
+
+@@ -110,6 +112,28 @@
+ #define SDEDM_READ_THRESHOLD_SHIFT 14
+ #define SDEDM_THRESHOLD_MASK 0x1f
+
++#define SDEDM_FSM_MASK 0xf
++#define SDEDM_FSM_IDENTMODE 0x0
++#define SDEDM_FSM_DATAMODE 0x1
++#define SDEDM_FSM_READDATA 0x2
++#define SDEDM_FSM_WRITEDATA 0x3
++#define SDEDM_FSM_READWAIT 0x4
++#define SDEDM_FSM_READCRC 0x5
++#define SDEDM_FSM_WRITECRC 0x6
++#define SDEDM_FSM_WRITEWAIT1 0x7
++#define SDEDM_FSM_POWERDOWN 0x8
++#define SDEDM_FSM_POWERUP 0x9
++#define SDEDM_FSM_WRITESTART1 0xa
++#define SDEDM_FSM_WRITESTART2 0xb
++#define SDEDM_FSM_GENPULSES 0xc
++#define SDEDM_FSM_WRITEWAIT2 0xd
++#define SDEDM_FSM_STARTPOWDOWN 0xf
++
++#define SDDATA_FIFO_WORDS 16
++
++#define USE_CMD23_FLAGS ((ALLOW_CMD23_READ * MMC_DATA_READ) | \
++ (ALLOW_CMD23_WRITE * MMC_DATA_WRITE))
++
+ #define MHZ 1000000
+
+
+@@ -131,15 +155,17 @@ struct bcm2835_host {
+
+ struct tasklet_struct finish_tasklet; /* Tasklet structures */
+
+- struct timer_list timer; /* Timer for timeouts */
++ struct work_struct cmd_wait_wq; /* Workqueue function */
+
+- struct timer_list pio_timer; /* PIO error detection timer */
++ struct timer_list timer; /* Timer for timeouts */
+
+ struct sg_mapping_iter sg_miter; /* SG state for PIO */
+ unsigned int blocks; /* remaining PIO blocks */
+
+ int irq; /* Device IRQ */
+
++ u32 cmd_quick_poll_retries;
++ u32 ns_per_fifo_word;
+
+ /* cached registers */
+ u32 hcfg;
+@@ -154,16 +180,21 @@ struct bcm2835_host {
+
+ unsigned int use_busy:1; /* Wait for busy interrupt */
+
+- unsigned int debug:1; /* Enable debug output */
++ unsigned int use_sbc:1; /* Send CMD23 */
+
+- u32 thread_isr;
++ unsigned int debug:1; /* Enable debug output */
+
+ /*DMA part*/
+ struct dma_chan *dma_chan_rx; /* DMA channel for reads */
+ struct dma_chan *dma_chan_tx; /* DMA channel for writes */
++ struct dma_chan *dma_chan; /* Channel in used */
++ struct dma_async_tx_descriptor *dma_desc;
++ u32 dma_dir;
++ u32 drain_words;
++ struct page *drain_page;
++ u32 drain_offset;
+
+ bool allow_dma;
+- bool have_dma;
+ bool use_dma;
+ /*end of DMA part*/
+
+@@ -173,13 +204,98 @@ struct bcm2835_host {
+ u32 overclock_50; /* frequency to use when 50MHz is requested (in MHz) */
+ u32 overclock; /* Current frequency if overclocked, else zero */
+ u32 pio_limit; /* Maximum block count for PIO (0 = always DMA) */
++};
+
+- u32 debug_flags;
++#if ENABLE_LOG
+
+- u32 sectors; /* Cached card size in sectors */
+- u32 single_read_sectors[8];
++struct log_entry_struct {
++ char event[4];
++ u32 timestamp;
++ u32 param1;
++ u32 param2;
+ };
+
++typedef struct log_entry_struct LOG_ENTRY_T;
++
++LOG_ENTRY_T *sdhost_log_buf;
++dma_addr_t sdhost_log_addr;
++static u32 sdhost_log_idx;
++static spinlock_t log_lock;
++static void __iomem *timer_base;
++
++#define LOG_ENTRIES (256*1)
++#define LOG_SIZE (sizeof(LOG_ENTRY_T)*LOG_ENTRIES)
++
++static void log_init(u32 bus_to_phys)
++{
++ spin_lock_init(&log_lock);
++ sdhost_log_buf = dma_zalloc_coherent(NULL, LOG_SIZE, &sdhost_log_addr,
++ GFP_KERNEL);
++ if (sdhost_log_buf) {
++ pr_err("sdhost: log_buf @ %p (%x)\n",
++ sdhost_log_buf, sdhost_log_addr);
++ timer_base = ioremap_nocache(bus_to_phys + 0x7e003000, SZ_4K);
++ if (!timer_base)
++ pr_err("sdhost: failed to remap timer\n");
++ }
++ else
++ pr_err("sdhost: failed to allocate log buf\n");
++}
++
++static void log_event_impl(const char *event, u32 param1, u32 param2)
++{
++ if (sdhost_log_buf) {
++ LOG_ENTRY_T *entry;
++ unsigned long flags;
++
++ spin_lock_irqsave(&log_lock, flags);
++
++ entry = sdhost_log_buf + sdhost_log_idx;
++ memcpy(entry->event, event, 4);
++ entry->timestamp = (readl(timer_base + 4) & 0x3fffffff) +
++ (smp_processor_id()<<30);
++ entry->param1 = param1;
++ entry->param2 = param2;
++ sdhost_log_idx = (sdhost_log_idx + 1) % LOG_ENTRIES;
++
++ spin_unlock_irqrestore(&log_lock, flags);
++ }
++}
++
++static void log_dump(void)
++{
++ if (sdhost_log_buf) {
++ LOG_ENTRY_T *entry;
++ unsigned long flags;
++ int idx;
++
++ spin_lock_irqsave(&log_lock, flags);
++
++ idx = sdhost_log_idx;
++ do {
++ entry = sdhost_log_buf + idx;
++ if (entry->event[0] != '\0')
++ pr_err("[%08x] %.4s %x %x\n",
++ entry->timestamp,
++ entry->event,
++ entry->param1,
++ entry->param2);
++ idx = (idx + 1) % LOG_ENTRIES;
++ } while (idx != sdhost_log_idx);
++
++ spin_unlock_irqrestore(&log_lock, flags);
++ }
++}
++
++#define log_event(event, param1, param2) log_event_impl(event, param1, param2)
++
++#else
++
++#define log_init(x) (void)0
++#define log_event(event, param1, param2) (void)0
++#define log_dump() (void)0
++
++#endif
+
+ static inline void bcm2835_sdhost_write(struct bcm2835_host *host, u32 val, int reg)
+ {
+@@ -201,7 +317,7 @@ static void bcm2835_sdhost_dumpcmd(struc
+ const char *label)
+ {
+ if (cmd)
+- pr_info("%s:%c%s op %d arg 0x%x flags 0x%x - resp %08x %08x %08x %08x, err %d\n",
++ pr_err("%s:%c%s op %d arg 0x%x flags 0x%x - resp %08x %08x %08x %08x, err %d\n",
+ mmc_hostname(host->mmc),
+ (cmd == host->cmd) ? '>' : ' ',
+ label, cmd->opcode, cmd->arg, cmd->flags,
+@@ -211,73 +327,74 @@ static void bcm2835_sdhost_dumpcmd(struc
+
+ static void bcm2835_sdhost_dumpregs(struct bcm2835_host *host)
+ {
+- bcm2835_sdhost_dumpcmd(host, host->mrq->sbc, "sbc");
+- bcm2835_sdhost_dumpcmd(host, host->mrq->cmd, "cmd");
+- if (host->mrq->data)
+- pr_err("%s: data blocks %x blksz %x - err %d\n",
+- mmc_hostname(host->mmc),
+- host->mrq->data->blocks,
+- host->mrq->data->blksz,
+- host->mrq->data->error);
+- bcm2835_sdhost_dumpcmd(host, host->mrq->stop, "stop");
++ if (host->mrq)
++ {
++ bcm2835_sdhost_dumpcmd(host, host->mrq->sbc, "sbc");
++ bcm2835_sdhost_dumpcmd(host, host->mrq->cmd, "cmd");
++ if (host->mrq->data)
++ pr_err("%s: data blocks %x blksz %x - err %d\n",
++ mmc_hostname(host->mmc),
++ host->mrq->data->blocks,
++ host->mrq->data->blksz,
++ host->mrq->data->error);
++ bcm2835_sdhost_dumpcmd(host, host->mrq->stop, "stop");
++ }
+
+- pr_info("%s: =========== REGISTER DUMP ===========\n",
++ pr_err("%s: =========== REGISTER DUMP ===========\n",
+ mmc_hostname(host->mmc));
+
+- pr_info("%s: SDCMD 0x%08x\n",
++ pr_err("%s: SDCMD 0x%08x\n",
+ mmc_hostname(host->mmc),
+ bcm2835_sdhost_read(host, SDCMD));
+- pr_info("%s: SDARG 0x%08x\n",
++ pr_err("%s: SDARG 0x%08x\n",
+ mmc_hostname(host->mmc),
+ bcm2835_sdhost_read(host, SDARG));
+- pr_info("%s: SDTOUT 0x%08x\n",
++ pr_err("%s: SDTOUT 0x%08x\n",
+ mmc_hostname(host->mmc),
+ bcm2835_sdhost_read(host, SDTOUT));
+- pr_info("%s: SDCDIV 0x%08x\n",
++ pr_err("%s: SDCDIV 0x%08x\n",
+ mmc_hostname(host->mmc),
+ bcm2835_sdhost_read(host, SDCDIV));
+- pr_info("%s: SDRSP0 0x%08x\n",
++ pr_err("%s: SDRSP0 0x%08x\n",
+ mmc_hostname(host->mmc),
+ bcm2835_sdhost_read(host, SDRSP0));
+- pr_info("%s: SDRSP1 0x%08x\n",
++ pr_err("%s: SDRSP1 0x%08x\n",
+ mmc_hostname(host->mmc),
+ bcm2835_sdhost_read(host, SDRSP1));
+- pr_info("%s: SDRSP2 0x%08x\n",
++ pr_err("%s: SDRSP2 0x%08x\n",
+ mmc_hostname(host->mmc),
+ bcm2835_sdhost_read(host, SDRSP2));
+- pr_info("%s: SDRSP3 0x%08x\n",
++ pr_err("%s: SDRSP3 0x%08x\n",
+ mmc_hostname(host->mmc),
+ bcm2835_sdhost_read(host, SDRSP3));
+- pr_info("%s: SDHSTS 0x%08x\n",
++ pr_err("%s: SDHSTS 0x%08x\n",
+ mmc_hostname(host->mmc),
+ bcm2835_sdhost_read(host, SDHSTS));
+- pr_info("%s: SDVDD 0x%08x\n",
++ pr_err("%s: SDVDD 0x%08x\n",
+ mmc_hostname(host->mmc),
+ bcm2835_sdhost_read(host, SDVDD));
+- pr_info("%s: SDEDM 0x%08x\n",
++ pr_err("%s: SDEDM 0x%08x\n",
+ mmc_hostname(host->mmc),
+ bcm2835_sdhost_read(host, SDEDM));
+- pr_info("%s: SDHCFG 0x%08x\n",
++ pr_err("%s: SDHCFG 0x%08x\n",
+ mmc_hostname(host->mmc),
+ bcm2835_sdhost_read(host, SDHCFG));
+- pr_info("%s: SDHBCT 0x%08x\n",
++ pr_err("%s: SDHBCT 0x%08x\n",
+ mmc_hostname(host->mmc),
+ bcm2835_sdhost_read(host, SDHBCT));
+- pr_info("%s: SDHBLC 0x%08x\n",
++ pr_err("%s: SDHBLC 0x%08x\n",
+ mmc_hostname(host->mmc),
+ bcm2835_sdhost_read(host, SDHBLC));
+
+- pr_info("%s: ===========================================\n",
++ pr_err("%s: ===========================================\n",
+ mmc_hostname(host->mmc));
+ }
+
+-
+ static void bcm2835_sdhost_set_power(struct bcm2835_host *host, bool on)
+ {
+ bcm2835_sdhost_write(host, on ? 1 : 0, SDVDD);
+ }
+
+-
+ static void bcm2835_sdhost_reset_internal(struct bcm2835_host *host)
+ {
+ u32 temp;
+@@ -300,26 +417,24 @@ static void bcm2835_sdhost_reset_interna
+ temp = bcm2835_sdhost_read(host, SDEDM);
+ temp &= ~((SDEDM_THRESHOLD_MASK<<SDEDM_READ_THRESHOLD_SHIFT) |
+ (SDEDM_THRESHOLD_MASK<<SDEDM_WRITE_THRESHOLD_SHIFT));
+- temp |= (SAFE_READ_THRESHOLD << SDEDM_READ_THRESHOLD_SHIFT) |
+- (SAFE_WRITE_THRESHOLD << SDEDM_WRITE_THRESHOLD_SHIFT);
++ temp |= (FIFO_READ_THRESHOLD << SDEDM_READ_THRESHOLD_SHIFT) |
++ (FIFO_WRITE_THRESHOLD << SDEDM_WRITE_THRESHOLD_SHIFT);
+ bcm2835_sdhost_write(host, temp, SDEDM);
+ mdelay(10);
+ bcm2835_sdhost_set_power(host, true);
+ mdelay(10);
+ host->clock = 0;
+- host->sectors = 0;
+- host->single_read_sectors[0] = ~0;
+ bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
+ bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
+ mmiowb();
+ }
+
+-
+ static void bcm2835_sdhost_reset(struct mmc_host *mmc)
+ {
+ struct bcm2835_host *host = mmc_priv(mmc);
+ unsigned long flags;
+ spin_lock_irqsave(&host->lock, flags);
++ log_event("RST<", 0, 0);
+
+ bcm2835_sdhost_reset_internal(host);
+
+@@ -344,82 +459,48 @@ static void bcm2835_sdhost_init(struct b
+ }
+ }
+
+-static bool bcm2835_sdhost_is_write_complete(struct bcm2835_host *host)
++static void bcm2835_sdhost_wait_transfer_complete(struct bcm2835_host *host)
+ {
+- bool write_complete = ((bcm2835_sdhost_read(host, SDEDM) & 0xf) == 1);
++ int timediff;
++ u32 alternate_idle;
++ u32 edm;
+
+- if (!write_complete) {
+- /* Request an IRQ for the last block */
+- host->hcfg |= SDHCFG_BLOCK_IRPT_EN;
+- bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
+- if ((bcm2835_sdhost_read(host, SDEDM) & 0xf) == 1) {
+- /* The write has now completed. Disable the interrupt
+- and clear the status flag */
+- host->hcfg &= ~SDHCFG_BLOCK_IRPT_EN;
+- bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
+- bcm2835_sdhost_write(host, SDHSTS_BLOCK_IRPT, SDHSTS);
+- write_complete = true;
+- }
+- }
++ alternate_idle = (host->mrq->data->flags & MMC_DATA_READ) ?
++ SDEDM_FSM_READWAIT : SDEDM_FSM_WRITESTART1;
+
+- return write_complete;
+-}
++ edm = bcm2835_sdhost_read(host, SDEDM);
+
+-static void bcm2835_sdhost_wait_write_complete(struct bcm2835_host *host)
+-{
+- int timediff;
+-#ifdef DEBUG
+- static struct timeval start_time;
+- static int max_stall_time = 0;
+- static int total_stall_time = 0;
+- struct timeval before, after;
+-
+- do_gettimeofday(&before);
+- if (max_stall_time == 0)
+- start_time = before;
+-#endif
++ log_event("WTC<", edm, 0);
+
+ timediff = 0;
+
+ while (1) {
+- u32 edm = bcm2835_sdhost_read(host, SDEDM);
+- if ((edm & 0xf) == 1)
++ u32 fsm = edm & SDEDM_FSM_MASK;
++ if ((fsm == SDEDM_FSM_IDENTMODE) ||
++ (fsm == SDEDM_FSM_DATAMODE))
+ break;
+- timediff++;
+- if (timediff > 5000000) {
+-#ifdef DEBUG
+- do_gettimeofday(&after);
+- timediff = (after.tv_sec - before.tv_sec)*1000000 +
+- (after.tv_usec - before.tv_usec);
++ if (fsm == alternate_idle) {
++ bcm2835_sdhost_write(host,
++ edm | SDEDM_FORCE_DATA_MODE,
++ SDEDM);
++ break;
++ }
+
+- pr_err(" wait_write_complete - still waiting after %dus\n",
+- timediff);
+-#else
+- pr_err(" wait_write_complete - still waiting after %d retries\n",
++ timediff++;
++ if (timediff == 100000) {
++ pr_err("%s: wait_transfer_complete - still waiting after %d retries\n",
++ mmc_hostname(host->mmc),
+ timediff);
+-#endif
++ log_dump();
+ bcm2835_sdhost_dumpregs(host);
+- host->data->error = -ETIMEDOUT;
++ host->mrq->data->error = -ETIMEDOUT;
++ log_event("WTC!", edm, 0);
+ return;
+ }
++ cpu_relax();
++ edm = bcm2835_sdhost_read(host, SDEDM);
+ }
+-
+-#ifdef DEBUG
+- do_gettimeofday(&after);
+- timediff = (after.tv_sec - before.tv_sec)*1000000 + (after.tv_usec - before.tv_usec);
+-
+- total_stall_time += timediff;
+- if (timediff > max_stall_time)
+- max_stall_time = timediff;
+-
+- if ((after.tv_sec - start_time.tv_sec) > 10) {
+- pr_debug(" wait_write_complete - max wait %dus, total %dus\n",
+- max_stall_time, total_stall_time);
+- start_time = after;
+- max_stall_time = 0;
+- total_stall_time = 0;
+- }
+-#endif
++ log_event("WTC>", edm, 0);
+ }
+
+ static void bcm2835_sdhost_finish_data(struct bcm2835_host *host);
+@@ -427,65 +508,44 @@ static void bcm2835_sdhost_finish_data(s
+ static void bcm2835_sdhost_dma_complete(void *param)
+ {
+ struct bcm2835_host *host = param;
+- struct dma_chan *dma_chan;
++ struct mmc_data *data = host->data;
+ unsigned long flags;
+- u32 dir_data;
+
+ spin_lock_irqsave(&host->lock, flags);
++ log_event("DMA<", (u32)host->data, bcm2835_sdhost_read(host, SDHSTS));
++ log_event("DMA ", bcm2835_sdhost_read(host, SDCMD),
++ bcm2835_sdhost_read(host, SDEDM));
+
+- if (host->data) {
+- bool write_complete;
+- if (USE_BLOCK_IRQ)
+- write_complete = bcm2835_sdhost_is_write_complete(host);
+- else {
+- bcm2835_sdhost_wait_write_complete(host);
+- write_complete = true;
+- }
+- pr_debug("dma_complete() - write_complete=%d\n",
+- write_complete);
+-
+- if (write_complete || (host->data->flags & MMC_DATA_READ))
+- {
+- if (write_complete) {
+- dma_chan = host->dma_chan_tx;
+- dir_data = DMA_TO_DEVICE;
+- } else {
+- dma_chan = host->dma_chan_rx;
+- dir_data = DMA_FROM_DEVICE;
+- }
+-
+- dma_unmap_sg(dma_chan->device->dev,
+- host->data->sg, host->data->sg_len,
+- dir_data);
++ if (host->dma_chan) {
++ dma_unmap_sg(host->dma_chan->device->dev,
++ data->sg, data->sg_len,
++ host->dma_dir);
+
+- bcm2835_sdhost_finish_data(host);
+- }
++ host->dma_chan = NULL;
+ }
+
+- spin_unlock_irqrestore(&host->lock, flags);
+-}
++ if (host->drain_words) {
++ void *page;
++ u32 *buf;
+
+-static bool data_transfer_wait(struct bcm2835_host *host)
+-{
+- unsigned long timeout = 1000000;
+- while (timeout)
+- {
+- u32 sdhsts = bcm2835_sdhost_read(host, SDHSTS);
+- if (sdhsts & SDHSTS_DATA_FLAG) {
+- bcm2835_sdhost_write(host, SDHSTS_DATA_FLAG, SDHSTS);
+- break;
++ page = kmap_atomic(host->drain_page);
++ buf = page + host->drain_offset;
++
++ while (host->drain_words) {
++ u32 edm = bcm2835_sdhost_read(host, SDEDM);
++ if ((edm >> 4) & 0x1f)
++ *(buf++) = bcm2835_sdhost_read(host,
++ SDDATA);
++ host->drain_words--;
+ }
+- timeout--;
+- }
+- if (timeout == 0) {
+- pr_err("%s: Data %s timeout\n",
+- mmc_hostname(host->mmc),
+- (host->data->flags & MMC_DATA_READ) ? "read" : "write");
+- bcm2835_sdhost_dumpregs(host);
+- host->data->error = -ETIMEDOUT;
+- return false;
++
++ kunmap_atomic(page);
+ }
+- return true;
++
++ bcm2835_sdhost_finish_data(host);
++
++ log_event("DMA>", (u32)host->data, 0);
++ spin_unlock_irqrestore(&host->lock, flags);
+ }
+
+ static void bcm2835_sdhost_read_block_pio(struct bcm2835_host *host)
+@@ -493,32 +553,83 @@ static void bcm2835_sdhost_read_block_pi
+ unsigned long flags;
+ size_t blksize, len;
+ u32 *buf;
++ unsigned long wait_max;
+
+ blksize = host->data->blksz;
+
++ wait_max = jiffies + msecs_to_jiffies(host->pio_timeout);
++
+ local_irq_save(flags);
+
+ while (blksize) {
+- if (!sg_miter_next(&host->sg_miter))
+- BUG();
++ int copy_words;
++ u32 hsts = 0;
++
++ if (!sg_miter_next(&host->sg_miter)) {
++ host->data->error = -EINVAL;
++ break;
++ }
+
+ len = min(host->sg_miter.length, blksize);
+- BUG_ON(len % 4);
++ if (len % 4) {
++ host->data->error = -EINVAL;
++ break;
++ }
+
+ blksize -= len;
+ host->sg_miter.consumed = len;
+
+ buf = (u32 *)host->sg_miter.addr;
+
+- while (len) {
+- if (!data_transfer_wait(host))
+- break;
++ copy_words = len/4;
++
++ while (copy_words) {
++ int burst_words, words;
++ u32 edm;
++
++ burst_words = SDDATA_FIFO_PIO_BURST;
++ if (burst_words > copy_words)
++ burst_words = copy_words;
++ edm = bcm2835_sdhost_read(host, SDEDM);
++ words = ((edm >> 4) & 0x1f);
++
++ if (words < burst_words) {
++ int fsm_state = (edm & SDEDM_FSM_MASK);
++ if ((fsm_state != SDEDM_FSM_READDATA) &&
++ (fsm_state != SDEDM_FSM_READWAIT) &&
++ (fsm_state != SDEDM_FSM_READCRC)) {
++ hsts = bcm2835_sdhost_read(host,
++ SDHSTS);
++ pr_err("%s: fsm %x, hsts %x\n",
++ mmc_hostname(host->mmc),
++ fsm_state, hsts);
++ if (hsts & SDHSTS_ERROR_MASK)
++ break;
++ }
++
++ if (time_after(jiffies, wait_max)) {
++ pr_err("%s: PIO read timeout - EDM %x\n",
++ mmc_hostname(host->mmc),
++ edm);
++ hsts = SDHSTS_REW_TIME_OUT;
++ break;
++ }
++ ndelay((burst_words - words) *
++ host->ns_per_fifo_word);
++ continue;
++ } else if (words > copy_words) {
++ words = copy_words;
++ }
++
++ copy_words -= words;
+
+- *(buf++) = bcm2835_sdhost_read(host, SDDATA);
+- len -= 4;
++ while (words) {
++ *(buf++) = bcm2835_sdhost_read(host, SDDATA);
++ words--;
++ }
+ }
+
+- if (host->data->error)
++ if (hsts & SDHSTS_ERROR_MASK)
+ break;
+ }
+
+@@ -532,32 +643,83 @@ static void bcm2835_sdhost_write_block_p
+ unsigned long flags;
+ size_t blksize, len;
+ u32 *buf;
++ unsigned long wait_max;
+
+ blksize = host->data->blksz;
+
++ wait_max = jiffies + msecs_to_jiffies(host->pio_timeout);
++
+ local_irq_save(flags);
+
+ while (blksize) {
+- if (!sg_miter_next(&host->sg_miter))
+- BUG();
++ int copy_words;
++ u32 hsts = 0;
++
++ if (!sg_miter_next(&host->sg_miter)) {
++ host->data->error = -EINVAL;
++ break;
++ }
+
+ len = min(host->sg_miter.length, blksize);
+- BUG_ON(len % 4);
++ if (len % 4) {
++ host->data->error = -EINVAL;
++ break;
++ }
+
+ blksize -= len;
+ host->sg_miter.consumed = len;
+
+- buf = host->sg_miter.addr;
++ buf = (u32 *)host->sg_miter.addr;
+
+- while (len) {
+- if (!data_transfer_wait(host))
+- break;
++ copy_words = len/4;
++
++ while (copy_words) {
++ int burst_words, words;
++ u32 edm;
++
++ burst_words = SDDATA_FIFO_PIO_BURST;
++ if (burst_words > copy_words)
++ burst_words = copy_words;
++ edm = bcm2835_sdhost_read(host, SDEDM);
++ words = SDDATA_FIFO_WORDS - ((edm >> 4) & 0x1f);
++
++ if (words < burst_words) {
++ int fsm_state = (edm & SDEDM_FSM_MASK);
++ if ((fsm_state != SDEDM_FSM_WRITEDATA) &&
++ (fsm_state != SDEDM_FSM_WRITESTART1) &&
++ (fsm_state != SDEDM_FSM_WRITESTART2)) {
++ hsts = bcm2835_sdhost_read(host,
++ SDHSTS);
++ pr_err("%s: fsm %x, hsts %x\n",
++ mmc_hostname(host->mmc),
++ fsm_state, hsts);
++ if (hsts & SDHSTS_ERROR_MASK)
++ break;
++ }
+
+- bcm2835_sdhost_write(host, *(buf++), SDDATA);
+- len -= 4;
++ if (time_after(jiffies, wait_max)) {
++ pr_err("%s: PIO write timeout - EDM %x\n",
++ mmc_hostname(host->mmc),
++ edm);
++ hsts = SDHSTS_REW_TIME_OUT;
++ break;
++ }
++ ndelay((burst_words - words) *
++ host->ns_per_fifo_word);
++ continue;
++ } else if (words > copy_words) {
++ words = copy_words;
++ }
++
++ copy_words -= words;
++
++ while (words) {
++ bcm2835_sdhost_write(host, *(buf++), SDDATA);
++ words--;
++ }
+ }
+
+- if (host->data->error)
++ if (hsts & SDHSTS_ERROR_MASK)
+ break;
+ }
+
+@@ -566,12 +728,12 @@ static void bcm2835_sdhost_write_block_p
+ local_irq_restore(flags);
+ }
+
+-
+ static void bcm2835_sdhost_transfer_pio(struct bcm2835_host *host)
+ {
+ u32 sdhsts;
+ bool is_read;
+ BUG_ON(!host->data);
++ log_event("XFP<", (u32)host->data, host->blocks);
+
+ is_read = (host->data->flags & MMC_DATA_READ) != 0;
+ if (is_read)
+@@ -595,28 +757,21 @@ static void bcm2835_sdhost_transfer_pio(
+ is_read ? "read" : "write",
+ sdhsts);
+ host->data->error = -ETIMEDOUT;
+- } else if (!is_read && !host->data->error) {
+- /* Start a timer in case a transfer error occurs because
+- there is no error interrupt */
+- mod_timer(&host->pio_timer, jiffies + host->pio_timeout);
+ }
++ log_event("XFP>", (u32)host->data, host->blocks);
+ }
+
+-
+-static void bcm2835_sdhost_transfer_dma(struct bcm2835_host *host)
++static void bcm2835_sdhost_prepare_dma(struct bcm2835_host *host,
++ struct mmc_data *data)
+ {
+- u32 len, dir_data, dir_slave;
++ int len, dir_data, dir_slave;
+ struct dma_async_tx_descriptor *desc = NULL;
+ struct dma_chan *dma_chan;
+
+- pr_debug("bcm2835_sdhost_transfer_dma()\n");
+-
+- WARN_ON(!host->data);
++ log_event("PRD<", (u32)data, 0);
++ pr_debug("bcm2835_sdhost_prepare_dma()\n");
+
+- if (!host->data)
+- return;
+-
+- if (host->data->flags & MMC_DATA_READ) {
++ if (data->flags & MMC_DATA_READ) {
+ dma_chan = host->dma_chan_rx;
+ dir_data = DMA_FROM_DEVICE;
+ dir_slave = DMA_DEV_TO_MEM;
+@@ -625,35 +780,71 @@ static void bcm2835_sdhost_transfer_dma(
+ dir_data = DMA_TO_DEVICE;
+ dir_slave = DMA_MEM_TO_DEV;
+ }
++ log_event("PRD1", (u32)dma_chan, 0);
+
+ BUG_ON(!dma_chan->device);
+ BUG_ON(!dma_chan->device->dev);
+- BUG_ON(!host->data->sg);
++ BUG_ON(!data->sg);
+
+- len = dma_map_sg(dma_chan->device->dev, host->data->sg,
+- host->data->sg_len, dir_data);
+- if (len > 0) {
+- desc = dmaengine_prep_slave_sg(dma_chan, host->data->sg,
++ /* The block doesn't manage the FIFO DREQs properly for multi-block
++ transfers, so don't attempt to DMA the final few words.
++ Unfortunately this requires the final sg entry to be trimmed.
++ N.B. This code demands that the overspill is contained in
++ a single sg entry.
++ */
++
++ host->drain_words = 0;
++ if ((data->blocks > 1) && (dir_data == DMA_FROM_DEVICE)) {
++ struct scatterlist *sg;
++ u32 len;
++ int i;
++
++ len = min((u32)(FIFO_READ_THRESHOLD - 1) * 4,
++ (u32)data->blocks * data->blksz);
++
++ for_each_sg(data->sg, sg, data->sg_len, i) {
++ if (sg_is_last(sg)) {
++ BUG_ON(sg->length < len);
++ sg->length -= len;
++ host->drain_page = (struct page *)sg->page_link;
++ host->drain_offset = sg->offset + sg->length;
++ }
++ }
++ host->drain_words = len/4;
++ }
++
++ len = dma_map_sg(dma_chan->device->dev, data->sg, data->sg_len,
++ dir_data);
++
++ log_event("PRD2", len, 0);
++ if (len > 0)
++ desc = dmaengine_prep_slave_sg(dma_chan, data->sg,
+ len, dir_slave,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+- } else {
+- dev_err(mmc_dev(host->mmc), "dma_map_sg returned zero length\n");
+- }
++ log_event("PRD3", (u32)desc, 0);
++
+ if (desc) {
+ desc->callback = bcm2835_sdhost_dma_complete;
+ desc->callback_param = host;
+- dmaengine_submit(desc);
+- dma_async_issue_pending(dma_chan);
++ host->dma_desc = desc;
++ host->dma_chan = dma_chan;
++ host->dma_dir = dir_data;
+ }
+-
++ log_event("PDM>", (u32)data, 0);
+ }
+
++static void bcm2835_sdhost_start_dma(struct bcm2835_host *host)
++{
++ log_event("SDMA", (u32)host->data, (u32)host->dma_chan);
++ dmaengine_submit(host->dma_desc);
++ dma_async_issue_pending(host->dma_chan);
++}
+
+ static void bcm2835_sdhost_set_transfer_irqs(struct bcm2835_host *host)
+ {
+ u32 all_irqs = SDHCFG_DATA_IRPT_EN | SDHCFG_BLOCK_IRPT_EN |
+ SDHCFG_BUSY_IRPT_EN;
+- if (host->use_dma)
++ if (host->dma_desc)
+ host->hcfg = (host->hcfg & ~all_irqs) |
+ SDHCFG_BUSY_IRPT_EN;
+ else
+@@ -664,13 +855,13 @@ static void bcm2835_sdhost_set_transfer_
+ bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
+ }
+
+-
+ static void bcm2835_sdhost_prepare_data(struct bcm2835_host *host, struct mmc_command *cmd)
+ {
+ struct mmc_data *data = cmd->data;
+
+ WARN_ON(host->data);
+
++ host->data = data;
+ if (!data)
+ return;
+
+@@ -679,46 +870,19 @@ static void bcm2835_sdhost_prepare_data(
+ BUG_ON(data->blksz > host->mmc->max_blk_size);
+ BUG_ON(data->blocks > 65535);
+
+- host->data = data;
+ host->data_complete = 0;
+ host->flush_fifo = 0;
+ host->data->bytes_xfered = 0;
+
+- if (!host->sectors && host->mmc->card && !(host->debug_flags & 1))
+- {
+- struct mmc_card *card = host->mmc->card;
+- if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
+- /*
+- * The EXT_CSD sector count is in number of 512 byte
+- * sectors.
+- */
+- host->sectors = card->ext_csd.sectors;
+- pr_err("%s: using ext_csd!\n", mmc_hostname(host->mmc));
+- } else {
+- /*
+- * The CSD capacity field is in units of read_blkbits.
+- * set_capacity takes units of 512 bytes.
+- */
+- host->sectors = card->csd.capacity <<
+- (card->csd.read_blkbits - 9);
+- }
+- host->single_read_sectors[0] = host->sectors - 65;
+- host->single_read_sectors[1] = host->sectors - 64;
+- host->single_read_sectors[2] = host->sectors - 33;
+- host->single_read_sectors[3] = host->sectors - 32;
+- host->single_read_sectors[4] = host->sectors - 1;
+- host->single_read_sectors[5] = ~0; /* Safety net */
+- }
+
+- host->use_dma = host->have_dma && (data->blocks > host->pio_limit);
+- if (!host->use_dma) {
++ if (!host->dma_desc) {
++ /* Use PIO */
+ int flags;
+
+- flags = SG_MITER_ATOMIC;
+ if (data->flags & MMC_DATA_READ)
+- flags |= SG_MITER_TO_SG;
++ flags = SG_MITER_TO_SG;
+ else
+- flags |= SG_MITER_FROM_SG;
++ flags = SG_MITER_FROM_SG;
+ sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
+ host->blocks = data->blocks;
+ }
+@@ -726,19 +890,20 @@ static void bcm2835_sdhost_prepare_data(
+ bcm2835_sdhost_set_transfer_irqs(host);
+
+ bcm2835_sdhost_write(host, data->blksz, SDHBCT);
+- bcm2835_sdhost_write(host, host->use_dma ? data->blocks : 0, SDHBLC);
++ bcm2835_sdhost_write(host, data->blocks, SDHBLC);
+
+ BUG_ON(!host->data);
+ }
+
+-
+-void bcm2835_sdhost_send_command(struct bcm2835_host *host, struct mmc_command *cmd)
++bool bcm2835_sdhost_send_command(struct bcm2835_host *host,
++ struct mmc_command *cmd)
+ {
+ u32 sdcmd, sdhsts;
+ unsigned long timeout;
+ int delay;
+
+ WARN_ON(host->cmd);
++ log_event("CMD<", cmd->opcode, cmd->arg);
+
+ if (cmd->data)
+ pr_debug("%s: send_command %d 0x%x "
+@@ -761,9 +926,9 @@ void bcm2835_sdhost_send_command(struct
+ pr_err("%s: previous command never completed.\n",
+ mmc_hostname(host->mmc));
+ bcm2835_sdhost_dumpregs(host);
+- cmd->error = -EIO;
++ cmd->error = -EILSEQ;
+ tasklet_schedule(&host->finish_tasklet);
+- return;
++ return false;
+ }
+ timeout--;
+ udelay(10);
+@@ -791,23 +956,24 @@ void bcm2835_sdhost_send_command(struct
+ if (sdhsts & SDHSTS_ERROR_MASK)
+ bcm2835_sdhost_write(host, sdhsts, SDHSTS);
+
+- bcm2835_sdhost_prepare_data(host, cmd);
+-
+- bcm2835_sdhost_write(host, cmd->arg, SDARG);
+-
+ if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
+ pr_err("%s: unsupported response type!\n",
+ mmc_hostname(host->mmc));
+ cmd->error = -EINVAL;
+ tasklet_schedule(&host->finish_tasklet);
+- return;
++ return false;
+ }
+
++ bcm2835_sdhost_prepare_data(host, cmd);
++
++ bcm2835_sdhost_write(host, cmd->arg, SDARG);
++
+ sdcmd = cmd->opcode & SDCMD_CMD_MASK;
+
+- if (!(cmd->flags & MMC_RSP_PRESENT))
++ host->use_busy = 0;
++ if (!(cmd->flags & MMC_RSP_PRESENT)) {
+ sdcmd |= SDCMD_NO_RESPONSE;
+- else {
++ } else {
+ if (cmd->flags & MMC_RSP_136)
+ sdcmd |= SDCMD_LONG_RESPONSE;
+ if (cmd->flags & MMC_RSP_BUSY) {
+@@ -817,6 +983,7 @@ void bcm2835_sdhost_send_command(struct
+ }
+
+ if (cmd->data) {
++ log_event("CMDD", cmd->data->blocks, cmd->data->blksz);
+ if (host->delay_after_stop) {
+ struct timeval now;
+ int time_since_stop;
+@@ -839,10 +1006,12 @@ void bcm2835_sdhost_send_command(struct
+ }
+
+ bcm2835_sdhost_write(host, sdcmd | SDCMD_NEW_FLAG, SDCMD);
+-}
+
++ return true;
++}
+
+-static void bcm2835_sdhost_finish_command(struct bcm2835_host *host);
++static void bcm2835_sdhost_finish_command(struct bcm2835_host *host,
++ unsigned long *irq_flags);
+ static void bcm2835_sdhost_transfer_complete(struct bcm2835_host *host);
+
+ static void bcm2835_sdhost_finish_data(struct bcm2835_host *host)
+@@ -852,6 +1021,7 @@ static void bcm2835_sdhost_finish_data(s
+ data = host->data;
+ BUG_ON(!data);
+
++ log_event("FDA<", (u32)host->mrq, (u32)host->cmd);
+ pr_debug("finish_data(error %d, stop %d, sbc %d)\n",
+ data->error, data->stop ? 1 : 0,
+ host->mrq->sbc ? 1 : 0);
+@@ -859,10 +1029,7 @@ static void bcm2835_sdhost_finish_data(s
+ host->hcfg &= ~(SDHCFG_DATA_IRPT_EN | SDHCFG_BLOCK_IRPT_EN);
+ bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
+
+- if (data->error) {
+- data->bytes_xfered = 0;
+- } else
+- data->bytes_xfered = data->blksz * data->blocks;
++ data->bytes_xfered = data->error ? 0 : (data->blksz * data->blocks);
+
+ host->data_complete = 1;
+
+@@ -877,9 +1044,9 @@ static void bcm2835_sdhost_finish_data(s
+ }
+ else
+ bcm2835_sdhost_transfer_complete(host);
++ log_event("FDA>", (u32)host->mrq, (u32)host->cmd);
+ }
+
+-
+ static void bcm2835_sdhost_transfer_complete(struct bcm2835_host *host)
+ {
+ struct mmc_data *data;
+@@ -891,6 +1058,7 @@ static void bcm2835_sdhost_transfer_comp
+ data = host->data;
+ host->data = NULL;
+
++ log_event("TCM<", (u32)data, data->error);
+ pr_debug("transfer_complete(error %d, stop %d)\n",
+ data->error, data->stop ? 1 : 0);
+
+@@ -899,88 +1067,114 @@ static void bcm2835_sdhost_transfer_comp
+ * a) open-ended multiblock transfer (no CMD23)
+ * b) error in multiblock transfer
+ */
+- if (data->stop &&
+- (data->error ||
+- !host->mrq->sbc)) {
+- host->flush_fifo = 1;
+- bcm2835_sdhost_send_command(host, data->stop);
+- if (host->delay_after_stop)
+- do_gettimeofday(&host->stop_time);
+- if (!host->use_busy)
+- bcm2835_sdhost_finish_command(host);
++ if (host->mrq->stop && (data->error || !host->use_sbc)) {
++ if (bcm2835_sdhost_send_command(host, host->mrq->stop)) {
++ /* No busy, so poll for completion */
++ if (!host->use_busy)
++ bcm2835_sdhost_finish_command(host, NULL);
++
++ if (host->delay_after_stop)
++ do_gettimeofday(&host->stop_time);
++ }
+ } else {
++ bcm2835_sdhost_wait_transfer_complete(host);
+ tasklet_schedule(&host->finish_tasklet);
+ }
++ log_event("TCM>", (u32)data, 0);
+ }
+
+-static void bcm2835_sdhost_finish_command(struct bcm2835_host *host)
++/* If irq_flags is valid, the caller is in a thread context and is allowed
++ to sleep */
++static void bcm2835_sdhost_finish_command(struct bcm2835_host *host,
++ unsigned long *irq_flags)
+ {
+ u32 sdcmd;
+- unsigned long timeout;
++ u32 retries;
+ #ifdef DEBUG
+ struct timeval before, after;
+ int timediff = 0;
+ #endif
+
++ log_event("FCM<", (u32)host->mrq, (u32)host->cmd);
+ pr_debug("finish_command(%x)\n", bcm2835_sdhost_read(host, SDCMD));
+
+ BUG_ON(!host->cmd || !host->mrq);
+
+-#ifdef DEBUG
+- do_gettimeofday(&before);
+-#endif
+- /* Wait max 100 ms */
+- timeout = 10000;
++ /* Poll quickly at first */
++
++ retries = host->cmd_quick_poll_retries;
++ if (!retries) {
++ /* Work out how many polls take 1us by timing 10us */
++ struct timeval start, now;
++ int us_diff;
++
++ retries = 1;
++ do {
++ int i;
++
++ retries *= 2;
++
++ do_gettimeofday(&start);
++
++ for (i = 0; i < retries; i++) {
++ cpu_relax();
++ sdcmd = bcm2835_sdhost_read(host, SDCMD);
++ }
++
++ do_gettimeofday(&now);
++ us_diff = (now.tv_sec - start.tv_sec) * 1000000 +
++ (now.tv_usec - start.tv_usec);
++ } while (us_diff < 10);
++
++ host->cmd_quick_poll_retries = ((retries * us_diff + 9)*CMD_DALLY_US)/10 + 1;
++ retries = 1; // We've already waited long enough this time
++ }
++
++ retries = host->cmd_quick_poll_retries;
+ for (sdcmd = bcm2835_sdhost_read(host, SDCMD);
+- (sdcmd & SDCMD_NEW_FLAG) && timeout;
+- timeout--) {
+- if (host->flush_fifo) {
+- while (bcm2835_sdhost_read(host, SDHSTS) &
+- SDHSTS_DATA_FLAG)
+- (void)bcm2835_sdhost_read(host, SDDATA);
+- }
+- udelay(10);
++ (sdcmd & SDCMD_NEW_FLAG) && !(sdcmd & SDCMD_FAIL_FLAG) && retries;
++ retries--) {
++ cpu_relax();
+ sdcmd = bcm2835_sdhost_read(host, SDCMD);
+ }
+-#ifdef DEBUG
+- do_gettimeofday(&after);
+- timediff = (after.tv_sec - before.tv_sec)*1000000 +
+- (after.tv_usec - before.tv_usec);
+
+- pr_debug(" finish_command - waited %dus\n", timediff);
+-#endif
++ if (!retries) {
++ unsigned long wait_max;
++
++ if (!irq_flags) {
++ /* Schedule the work */
++ log_event("CWWQ", 0, 0);
++ schedule_work(&host->cmd_wait_wq);
++ return;
++ }
++
++ /* Wait max 100 ms */
++ wait_max = jiffies + msecs_to_jiffies(100);
++ while (time_before(jiffies, wait_max)) {
++ spin_unlock_irqrestore(&host->lock, *irq_flags);
++ usleep_range(1, 10);
++ spin_lock_irqsave(&host->lock, *irq_flags);
++ sdcmd = bcm2835_sdhost_read(host, SDCMD);
++ if (!(sdcmd & SDCMD_NEW_FLAG) ||
++ (sdcmd & SDCMD_FAIL_FLAG))
++ break;
++ }
++ }
+
+- if (timeout == 0) {
++ /* Check for errors */
++ if (sdcmd & SDCMD_NEW_FLAG) {
+ pr_err("%s: command never completed.\n",
+ mmc_hostname(host->mmc));
+ bcm2835_sdhost_dumpregs(host);
+ host->cmd->error = -EIO;
+ tasklet_schedule(&host->finish_tasklet);
+ return;
+- }
+-
+- if (host->flush_fifo) {
+- for (timeout = 100;
+- (bcm2835_sdhost_read(host, SDHSTS) & SDHSTS_DATA_FLAG) && timeout;
+- timeout--) {
+- (void)bcm2835_sdhost_read(host, SDDATA);
+- }
+- host->flush_fifo = 0;
+- if (timeout == 0) {
+- pr_err("%s: FIFO never drained.\n",
+- mmc_hostname(host->mmc));
+- bcm2835_sdhost_dumpregs(host);
+- host->cmd->error = -EIO;
+- tasklet_schedule(&host->finish_tasklet);
+- return;
+- }
+- }
+-
+- /* Check for errors */
+- if (sdcmd & SDCMD_FAIL_FLAG)
+- {
++ } else if (sdcmd & SDCMD_FAIL_FLAG) {
+ u32 sdhsts = bcm2835_sdhost_read(host, SDHSTS);
+
++ /* Clear the errors */
++ bcm2835_sdhost_write(host, SDHSTS_ERROR_MASK, SDHSTS);
++
+ if (host->debug)
+ pr_info("%s: error detected - CMD %x, HSTS %03x, EDM %x\n",
+ mmc_hostname(host->mmc), sdcmd, sdhsts,
+@@ -1003,7 +1197,7 @@ static void bcm2835_sdhost_finish_comman
+ mmc_hostname(host->mmc),
+ host->cmd->opcode);
+ bcm2835_sdhost_dumpregs(host);
+- host->cmd->error = -EIO;
++ host->cmd->error = -EILSEQ;
+ }
+ tasklet_schedule(&host->finish_tasklet);
+ return;
+@@ -1018,31 +1212,31 @@ static void bcm2835_sdhost_finish_comman
+ pr_debug("%s: finish_command %08x %08x %08x %08x\n",
+ mmc_hostname(host->mmc),
+ host->cmd->resp[0], host->cmd->resp[1], host->cmd->resp[2], host->cmd->resp[3]);
++ log_event("RSP ", host->cmd->resp[0], host->cmd->resp[1]);
+ } else {
+ host->cmd->resp[0] = bcm2835_sdhost_read(host, SDRSP0);
+ pr_debug("%s: finish_command %08x\n",
+ mmc_hostname(host->mmc),
+ host->cmd->resp[0]);
++ log_event("RSP ", host->cmd->resp[0], 0);
+ }
+ }
+
+- host->cmd->error = 0;
+-
+ if (host->cmd == host->mrq->sbc) {
+ /* Finished CMD23, now send actual command. */
+ host->cmd = NULL;
+- bcm2835_sdhost_send_command(host, host->mrq->cmd);
++ if (bcm2835_sdhost_send_command(host, host->mrq->cmd)) {
++ if (host->data && host->dma_desc)
++ /* DMA transfer starts now, PIO starts after irq */
++ bcm2835_sdhost_start_dma(host);
+
+- if (host->cmd->data && host->use_dma)
+- /* DMA transfer starts now, PIO starts after irq */
+- bcm2835_sdhost_transfer_dma(host);
+-
+- if (!host->use_busy)
+- bcm2835_sdhost_finish_command(host);
+- } else if (host->cmd == host->mrq->stop)
++ if (!host->use_busy)
++ bcm2835_sdhost_finish_command(host, NULL);
++ }
++ } else if (host->cmd == host->mrq->stop) {
+ /* Finished CMD12 */
+ tasklet_schedule(&host->finish_tasklet);
+- else {
++ } else {
+ /* Processed actual command. */
+ host->cmd = NULL;
+ if (!host->data)
+@@ -1050,6 +1244,7 @@ static void bcm2835_sdhost_finish_comman
+ else if (host->data_complete)
+ bcm2835_sdhost_transfer_complete(host);
+ }
++ log_event("FCM>", (u32)host->mrq, (u32)host->cmd);
+ }
+
+ static void bcm2835_sdhost_timeout(unsigned long data)
+@@ -1060,10 +1255,12 @@ static void bcm2835_sdhost_timeout(unsig
+ host = (struct bcm2835_host *)data;
+
+ spin_lock_irqsave(&host->lock, flags);
++ log_event("TIM<", 0, 0);
+
+ if (host->mrq) {
+ pr_err("%s: timeout waiting for hardware interrupt.\n",
+ mmc_hostname(host->mmc));
++ log_dump();
+ bcm2835_sdhost_dumpregs(host);
+
+ if (host->data) {
+@@ -1084,74 +1281,15 @@ static void bcm2835_sdhost_timeout(unsig
+ spin_unlock_irqrestore(&host->lock, flags);
+ }
+
+-static void bcm2835_sdhost_pio_timeout(unsigned long data)
+-{
+- struct bcm2835_host *host;
+- unsigned long flags;
+-
+- host = (struct bcm2835_host *)data;
+-
+- spin_lock_irqsave(&host->lock, flags);
+-
+- if (host->data) {
+- u32 sdhsts = bcm2835_sdhost_read(host, SDHSTS);
+-
+- if (sdhsts & SDHSTS_REW_TIME_OUT) {
+- pr_err("%s: transfer timeout\n",
+- mmc_hostname(host->mmc));
+- if (host->debug)
+- bcm2835_sdhost_dumpregs(host);
+- } else {
+- pr_err("%s: unexpected transfer timeout\n",
+- mmc_hostname(host->mmc));
+- bcm2835_sdhost_dumpregs(host);
+- }
+-
+- bcm2835_sdhost_write(host, SDHSTS_TRANSFER_ERROR_MASK,
+- SDHSTS);
+-
+- host->data->error = -ETIMEDOUT;
+-
+- bcm2835_sdhost_finish_data(host);
+- }
+-
+- mmiowb();
+- spin_unlock_irqrestore(&host->lock, flags);
+-}
+-
+-static void bcm2835_sdhost_enable_sdio_irq_nolock(struct bcm2835_host *host, int enable)
+-{
+- if (enable)
+- host->hcfg |= SDHCFG_SDIO_IRPT_EN;
+- else
+- host->hcfg &= ~SDHCFG_SDIO_IRPT_EN;
+- bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
+- mmiowb();
+-}
+-
+-static void bcm2835_sdhost_enable_sdio_irq(struct mmc_host *mmc, int enable)
+-{
+- struct bcm2835_host *host = mmc_priv(mmc);
+- unsigned long flags;
+-
+- pr_debug("%s: enable_sdio_irq(%d)\n", mmc_hostname(mmc), enable);
+- spin_lock_irqsave(&host->lock, flags);
+- bcm2835_sdhost_enable_sdio_irq_nolock(host, enable);
+- spin_unlock_irqrestore(&host->lock, flags);
+-}
+-
+-static u32 bcm2835_sdhost_busy_irq(struct bcm2835_host *host, u32 intmask)
++static void bcm2835_sdhost_busy_irq(struct bcm2835_host *host, u32 intmask)
+ {
+- const u32 handled = (SDHSTS_REW_TIME_OUT | SDHSTS_CMD_TIME_OUT |
+- SDHSTS_CRC16_ERROR | SDHSTS_CRC7_ERROR |
+- SDHSTS_FIFO_ERROR);
+-
++ log_event("IRQB", (u32)host->cmd, intmask);
+ if (!host->cmd) {
+ pr_err("%s: got command busy interrupt 0x%08x even "
+ "though no command operation was in progress.\n",
+ mmc_hostname(host->mmc), (unsigned)intmask);
+ bcm2835_sdhost_dumpregs(host);
+- return 0;
++ return;
+ }
+
+ if (!host->use_busy) {
+@@ -1159,7 +1297,7 @@ static u32 bcm2835_sdhost_busy_irq(struc
+ "though not expecting one.\n",
+ mmc_hostname(host->mmc), (unsigned)intmask);
+ bcm2835_sdhost_dumpregs(host);
+- return 0;
++ return;
+ }
+ host->use_busy = 0;
+
+@@ -1182,28 +1320,23 @@ static u32 bcm2835_sdhost_busy_irq(struc
+ } else if (intmask & SDHSTS_CMD_TIME_OUT)
+ host->cmd->error = -ETIMEDOUT;
+
++ log_dump();
+ bcm2835_sdhost_dumpregs(host);
+- tasklet_schedule(&host->finish_tasklet);
+ }
+ else
+- bcm2835_sdhost_finish_command(host);
+-
+- return handled;
++ bcm2835_sdhost_finish_command(host, NULL);
+ }
+
+-static u32 bcm2835_sdhost_data_irq(struct bcm2835_host *host, u32 intmask)
++static void bcm2835_sdhost_data_irq(struct bcm2835_host *host, u32 intmask)
+ {
+- const u32 handled = (SDHSTS_REW_TIME_OUT |
+- SDHSTS_CRC16_ERROR |
+- SDHSTS_FIFO_ERROR);
+-
+ /* There are no dedicated data/space available interrupt
+ status bits, so it is necessary to use the single shared
+ data/space available FIFO status bits. It is therefore not
+ an error to get here when there is no data transfer in
+ progress. */
++ log_event("IRQD", (u32)host->data, intmask);
+ if (!host->data)
+- return 0;
++ return;
+
+ if (intmask & (SDHSTS_CRC16_ERROR |
+ SDHSTS_FIFO_ERROR |
+@@ -1214,46 +1347,37 @@ static u32 bcm2835_sdhost_data_irq(struc
+ else
+ host->data->error = -ETIMEDOUT;
+
+- bcm2835_sdhost_dumpregs(host);
+- tasklet_schedule(&host->finish_tasklet);
+- return handled;
++ if (host->debug) {
++ log_dump();
++ bcm2835_sdhost_dumpregs(host);
++ }
+ }
+
+- /* Use the block interrupt for writes after the first block */
+- if (host->data->flags & MMC_DATA_WRITE) {
++ if (host->data->error) {
++ bcm2835_sdhost_finish_data(host);
++ } else if (host->data->flags & MMC_DATA_WRITE) {
++ /* Use the block interrupt for writes after the first block */
+ host->hcfg &= ~(SDHCFG_DATA_IRPT_EN);
+ host->hcfg |= SDHCFG_BLOCK_IRPT_EN;
+ bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
+- if (host->data->error)
+- bcm2835_sdhost_finish_data(host);
+- else
+- bcm2835_sdhost_transfer_pio(host);
++ bcm2835_sdhost_transfer_pio(host);
+ } else {
+- if (!host->data->error) {
+- bcm2835_sdhost_transfer_pio(host);
+- host->blocks--;
+- }
++ bcm2835_sdhost_transfer_pio(host);
++ host->blocks--;
+ if ((host->blocks == 0) || host->data->error)
+ bcm2835_sdhost_finish_data(host);
+ }
+-
+- return handled;
+ }
+
+-static u32 bcm2835_sdhost_block_irq(struct bcm2835_host *host, u32 intmask)
++static void bcm2835_sdhost_block_irq(struct bcm2835_host *host, u32 intmask)
+ {
+- struct dma_chan *dma_chan;
+- u32 dir_data;
+- const u32 handled = (SDHSTS_REW_TIME_OUT |
+- SDHSTS_CRC16_ERROR |
+- SDHSTS_FIFO_ERROR);
+-
++ log_event("IRQK", (u32)host->data, intmask);
+ if (!host->data) {
+ pr_err("%s: got block interrupt 0x%08x even "
+ "though no data operation was in progress.\n",
+ mmc_hostname(host->mmc), (unsigned)intmask);
+ bcm2835_sdhost_dumpregs(host);
+- return handled;
++ return;
+ }
+
+ if (intmask & (SDHSTS_CRC16_ERROR |
+@@ -1265,149 +1389,69 @@ static u32 bcm2835_sdhost_block_irq(stru
+ else
+ host->data->error = -ETIMEDOUT;
+
+- if (host->debug)
++ if (host->debug) {
++ log_dump();
+ bcm2835_sdhost_dumpregs(host);
+- tasklet_schedule(&host->finish_tasklet);
+- return handled;
++ }
+ }
+
+- if (!host->use_dma) {
++ if (!host->dma_desc) {
+ BUG_ON(!host->blocks);
+- host->blocks--;
+- if ((host->blocks == 0) || host->data->error) {
+- /* Cancel the timer */
+- del_timer(&host->pio_timer);
+-
++ if (host->data->error || (--host->blocks == 0)) {
+ bcm2835_sdhost_finish_data(host);
+ } else {
+- /* Reset the timer */
+- mod_timer(&host->pio_timer,
+- jiffies + host->pio_timeout);
+-
+ bcm2835_sdhost_transfer_pio(host);
+-
+- /* Reset the timer */
+- mod_timer(&host->pio_timer,
+- jiffies + host->pio_timeout);
+ }
+ } else if (host->data->flags & MMC_DATA_WRITE) {
+- dma_chan = host->dma_chan_tx;
+- dir_data = DMA_TO_DEVICE;
+- dma_unmap_sg(dma_chan->device->dev,
+- host->data->sg, host->data->sg_len,
+- dir_data);
+-
+ bcm2835_sdhost_finish_data(host);
+ }
+-
+- return handled;
+ }
+
+-
+ static irqreturn_t bcm2835_sdhost_irq(int irq, void *dev_id)
+ {
+ irqreturn_t result = IRQ_NONE;
+ struct bcm2835_host *host = dev_id;
+- u32 unexpected = 0, early = 0;
+- int loops = 0;
++ u32 intmask;
+
+ spin_lock(&host->lock);
+
+- for (loops = 0; loops < 1; loops++) {
+- u32 intmask, handled;
+-
+- intmask = bcm2835_sdhost_read(host, SDHSTS);
+- handled = intmask & (SDHSTS_BUSY_IRPT |
+- SDHSTS_BLOCK_IRPT |
+- SDHSTS_SDIO_IRPT |
+- SDHSTS_DATA_FLAG);
+- if ((handled == SDHSTS_DATA_FLAG) &&
+- (loops == 0) && !host->data) {
+- pr_err("%s: sdhost_irq data interrupt 0x%08x even "
+- "though no data operation was in progress.\n",
+- mmc_hostname(host->mmc),
+- (unsigned)intmask);
+-
+- bcm2835_sdhost_dumpregs(host);
+- }
+-
+- if (!handled)
+- break;
++ intmask = bcm2835_sdhost_read(host, SDHSTS);
++ log_event("IRQ<", intmask, 0);
+
+- if (loops)
+- early |= handled;
++ bcm2835_sdhost_write(host,
++ SDHSTS_BUSY_IRPT |
++ SDHSTS_BLOCK_IRPT |
++ SDHSTS_SDIO_IRPT |
++ SDHSTS_DATA_FLAG,
++ SDHSTS);
+
++ if (intmask & SDHSTS_BLOCK_IRPT) {
++ bcm2835_sdhost_block_irq(host, intmask);
+ result = IRQ_HANDLED;
++ }
+
+- /* Clear all interrupts and notifications */
+- bcm2835_sdhost_write(host, intmask, SDHSTS);
+-
+- if (intmask & SDHSTS_BUSY_IRPT)
+- handled |= bcm2835_sdhost_busy_irq(host, intmask);
+-
+- /* There is no true data interrupt status bit, so it is
+- necessary to qualify the data flag with the interrupt
+- enable bit */
+- if ((intmask & SDHSTS_DATA_FLAG) &&
+- (host->hcfg & SDHCFG_DATA_IRPT_EN))
+- handled |= bcm2835_sdhost_data_irq(host, intmask);
+-
+- if (intmask & SDHSTS_BLOCK_IRPT)
+- handled |= bcm2835_sdhost_block_irq(host, intmask);
+-
+- if (intmask & SDHSTS_SDIO_IRPT) {
+- bcm2835_sdhost_enable_sdio_irq_nolock(host, false);
+- host->thread_isr |= SDHSTS_SDIO_IRPT;
+- result = IRQ_WAKE_THREAD;
+- }
++ if (intmask & SDHSTS_BUSY_IRPT) {
++ bcm2835_sdhost_busy_irq(host, intmask);
++ result = IRQ_HANDLED;
++ }
+
+- unexpected |= (intmask & ~handled);
++ /* There is no true data interrupt status bit, so it is
++ necessary to qualify the data flag with the interrupt
++ enable bit */
++ if ((intmask & SDHSTS_DATA_FLAG) &&
++ (host->hcfg & SDHCFG_DATA_IRPT_EN)) {
++ bcm2835_sdhost_data_irq(host, intmask);
++ result = IRQ_HANDLED;
+ }
+
+ mmiowb();
+
++ log_event("IRQ>", bcm2835_sdhost_read(host, SDHSTS), 0);
+ spin_unlock(&host->lock);
+
+- if (early)
+- pr_debug("%s: early %x (loops %d)\n",
+- mmc_hostname(host->mmc), early, loops);
+-
+- if (unexpected) {
+- pr_err("%s: unexpected interrupt 0x%08x.\n",
+- mmc_hostname(host->mmc), unexpected);
+- bcm2835_sdhost_dumpregs(host);
+- }
+-
+ return result;
+ }
+
+-static irqreturn_t bcm2835_sdhost_thread_irq(int irq, void *dev_id)
+-{
+- struct bcm2835_host *host = dev_id;
+- unsigned long flags;
+- u32 isr;
+-
+- spin_lock_irqsave(&host->lock, flags);
+- isr = host->thread_isr;
+- host->thread_isr = 0;
+- spin_unlock_irqrestore(&host->lock, flags);
+-
+- if (isr & SDHSTS_SDIO_IRPT) {
+- sdio_run_irqs(host->mmc);
+-
+-/* Is this necessary? Why re-enable an interrupt which is enabled?
+- spin_lock_irqsave(&host->lock, flags);
+- if (host->flags & SDHSTS_SDIO_IRPT_ENABLED)
+- bcm2835_sdhost_enable_sdio_irq_nolock(host, true);
+- spin_unlock_irqrestore(&host->lock, flags);
+-*/
+- }
+-
+- return isr ? IRQ_HANDLED : IRQ_NONE;
+-}
+-
+-
+-
+ void bcm2835_sdhost_set_clock(struct bcm2835_host *host, unsigned int clock)
+ {
+ int div = 0; /* Initialized for compiler warning */
+@@ -1417,9 +1461,8 @@ void bcm2835_sdhost_set_clock(struct bcm
+ pr_info("%s: set_clock(%d)\n", mmc_hostname(host->mmc), clock);
+
+ if ((host->overclock_50 > 50) &&
+- (clock == 50*MHZ)) {
++ (clock == 50*MHZ))
+ clock = host->overclock_50 * MHZ + (MHZ - 1);
+- }
+
+ /* The SDCDIV register has 11 bits, and holds (div - 2).
+ But in data mode the max is 50MHz wihout a minimum, and only the
+@@ -1466,6 +1509,11 @@ void bcm2835_sdhost_set_clock(struct bcm
+ clock = host->max_clk / (div + 2);
+ host->mmc->actual_clock = clock;
+
++ /* Calibrate some delays */
++
++ host->ns_per_fifo_word = (1000000000/clock) *
++ ((host->mmc->caps & MMC_CAP_4_BIT_DATA) ? 8 : 32);
++
+ if (clock > input_clock) {
+ /* Save the closest value, to make it easier
+ to reduce in the event of error */
+@@ -1501,6 +1549,7 @@ static void bcm2835_sdhost_request(struc
+ {
+ struct bcm2835_host *host;
+ unsigned long flags;
++ u32 edm, fsm;
+
+ host = mmc_priv(mmc);
+
+@@ -1521,6 +1570,8 @@ static void bcm2835_sdhost_request(struc
+ }
+
+ /* Reset the error statuses in case this is a retry */
++ if (mrq->sbc)
++ mrq->sbc->error = 0;
+ if (mrq->cmd)
+ mrq->cmd->error = 0;
+ if (mrq->data)
+@@ -1536,28 +1587,58 @@ static void bcm2835_sdhost_request(struc
+ return;
+ }
+
++ if (host->use_dma && mrq->data &&
++ (mrq->data->blocks > host->pio_limit))
++ bcm2835_sdhost_prepare_dma(host, mrq->data);
++
+ spin_lock_irqsave(&host->lock, flags);
+
+ WARN_ON(host->mrq != NULL);
+-
+ host->mrq = mrq;
+
+- if (mrq->sbc)
+- bcm2835_sdhost_send_command(host, mrq->sbc);
+- else
+- bcm2835_sdhost_send_command(host, mrq->cmd);
++ edm = bcm2835_sdhost_read(host, SDEDM);
++ fsm = edm & SDEDM_FSM_MASK;
+
+- mmiowb();
+- spin_unlock_irqrestore(&host->lock, flags);
++ log_event("REQ<", (u32)mrq, edm);
++ if ((fsm != SDEDM_FSM_IDENTMODE) &&
++ (fsm != SDEDM_FSM_DATAMODE)) {
++ pr_err("%s: previous command (%d) not complete (EDM %x)\n",
++ mmc_hostname(host->mmc),
++ bcm2835_sdhost_read(host, SDCMD) & SDCMD_CMD_MASK,
++ edm);
++ log_event("REQ!", (u32)mrq, edm);
++ log_dump();
++ bcm2835_sdhost_dumpregs(host);
++ mrq->cmd->error = -EILSEQ;
++ tasklet_schedule(&host->finish_tasklet);
++ mmiowb();
++ spin_unlock_irqrestore(&host->lock, flags);
++ return;
++ }
++
++ host->use_sbc = !!mrq->sbc &&
++ (host->mrq->data->flags & USE_CMD23_FLAGS);
++ if (host->use_sbc) {
++ if (bcm2835_sdhost_send_command(host, mrq->sbc)) {
++ if (!host->use_busy)
++ bcm2835_sdhost_finish_command(host, &flags);
++ }
++ } else if (bcm2835_sdhost_send_command(host, mrq->cmd)) {
++ if (host->data && host->dma_desc)
++ /* DMA transfer starts now, PIO starts after irq */
++ bcm2835_sdhost_start_dma(host);
+
+- if (!mrq->sbc && mrq->cmd->data && host->use_dma)
+- /* DMA transfer starts now, PIO starts after irq */
+- bcm2835_sdhost_transfer_dma(host);
++ if (!host->use_busy)
++ bcm2835_sdhost_finish_command(host, &flags);
++ }
+
+- if (!host->use_busy)
+- bcm2835_sdhost_finish_command(host);
+-}
++ log_event("CMD ", (u32)mrq->cmd->opcode,
++ mrq->data ? (u32)mrq->data->blksz : 0);
++ mmiowb();
+
++ log_event("REQ>", (u32)mrq, 0);
++ spin_unlock_irqrestore(&host->lock, flags);
++}
+
+ static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+ {
+@@ -1574,6 +1655,8 @@ static void bcm2835_sdhost_set_ios(struc
+
+ spin_lock_irqsave(&host->lock, flags);
+
++ log_event("IOS<", ios->clock, 0);
++
+ if (!ios->clock || ios->clock != host->clock) {
+ bcm2835_sdhost_set_clock(host, ios->clock);
+ host->clock = ios->clock;
+@@ -1596,59 +1679,53 @@ static void bcm2835_sdhost_set_ios(struc
+ spin_unlock_irqrestore(&host->lock, flags);
+ }
+
+-static int bcm2835_sdhost_multi_io_quirk(struct mmc_card *card,
+- unsigned int direction,
+- u32 blk_pos, int blk_size)
+-{
+- /* There is a bug in the host controller hardware that makes
+- reading the final sector of the card as part of a multiple read
+- problematic. Detect that case and shorten the read accordingly.
+- */
++static struct mmc_host_ops bcm2835_sdhost_ops = {
++ .request = bcm2835_sdhost_request,
++ .set_ios = bcm2835_sdhost_set_ios,
++ .hw_reset = bcm2835_sdhost_reset,
++};
++
++static void bcm2835_sdhost_cmd_wait_work(struct work_struct *work)
++{
+ struct bcm2835_host *host;
++ unsigned long flags;
+
+- host = mmc_priv(card->host);
++ host = container_of(work, struct bcm2835_host, cmd_wait_wq);
+
+- if (!host->sectors) {
+- /* csd.capacity is in weird units - convert to sectors */
+- u32 card_sectors = (card->csd.capacity << (card->csd.read_blkbits - 9));
+- if ((direction == MMC_DATA_READ) &&
+- ((blk_pos + blk_size) == card_sectors))
+- blk_size--;
+- return blk_size;
+- }
++ spin_lock_irqsave(&host->lock, flags);
+
+- if (direction == MMC_DATA_READ) {
+- int i;
+- int sector;
+- for (i = 0; blk_pos > (sector = host->single_read_sectors[i]); i++)
+- continue;
++ log_event("CWK<", (u32)host->cmd, (u32)host->mrq);
+
+- if ((blk_pos + blk_size) > sector)
+- blk_size = (blk_pos == sector) ? 1 : (sector - blk_pos);
++ /*
++ * If this tasklet gets rescheduled while running, it will
++ * be run again afterwards but without any active request.
++ */
++ if (!host->mrq) {
++ spin_unlock_irqrestore(&host->lock, flags);
++ return;
+ }
+- return blk_size;
+-}
+
++ bcm2835_sdhost_finish_command(host, &flags);
+
+-static struct mmc_host_ops bcm2835_sdhost_ops = {
+- .request = bcm2835_sdhost_request,
+- .set_ios = bcm2835_sdhost_set_ios,
+- .enable_sdio_irq = bcm2835_sdhost_enable_sdio_irq,
+- .hw_reset = bcm2835_sdhost_reset,
+- .multi_io_quirk = bcm2835_sdhost_multi_io_quirk,
+-};
++ mmiowb();
++
++ log_event("CWK>", (u32)host->cmd, 0);
+
++ spin_unlock_irqrestore(&host->lock, flags);
++}
+
+ static void bcm2835_sdhost_tasklet_finish(unsigned long param)
+ {
+ struct bcm2835_host *host;
+ unsigned long flags;
+ struct mmc_request *mrq;
++ struct dma_chan *terminate_chan = NULL;
+
+ host = (struct bcm2835_host *)param;
+
+ spin_lock_irqsave(&host->lock, flags);
+
++ log_event("TSK<", (u32)host->mrq, 0);
+ /*
+ * If this tasklet gets rescheduled while running, it will
+ * be run again afterwards but without any active request.
+@@ -1683,11 +1760,23 @@ static void bcm2835_sdhost_tasklet_finis
+
+ mmiowb();
+
++ host->dma_desc = NULL;
++ terminate_chan = host->dma_chan;
++ host->dma_chan = NULL;
++
+ spin_unlock_irqrestore(&host->lock, flags);
+- mmc_request_done(host->mmc, mrq);
+-}
+
++ if (terminate_chan)
++ {
++ int err = dmaengine_terminate_all(terminate_chan);
++ if (err)
++ pr_err("%s: failed to terminate DMA (%d)\n",
++ mmc_hostname(host->mmc), err);
++ }
+
++ mmc_request_done(host->mmc, mrq);
++ log_event("TSK>", (u32)mrq, 0);
++}
+
+ int bcm2835_sdhost_add_host(struct bcm2835_host *host)
+ {
+@@ -1709,10 +1798,10 @@ int bcm2835_sdhost_add_host(struct bcm28
+ mmc->f_max, mmc->f_min, mmc->max_busy_timeout);
+
+ /* host controller capabilities */
+- mmc->caps |= /* MMC_CAP_SDIO_IRQ |*/ MMC_CAP_4_BIT_DATA |
++ mmc->caps |=
+ MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED |
+ MMC_CAP_NEEDS_POLL | MMC_CAP_HW_RESET | MMC_CAP_ERASE |
+- (ALLOW_CMD23 * MMC_CAP_CMD23);
++ ((ALLOW_CMD23_READ|ALLOW_CMD23_WRITE) * MMC_CAP_CMD23);
+
+ spin_lock_init(&host->lock);
+
+@@ -1722,9 +1811,9 @@ int bcm2835_sdhost_add_host(struct bcm28
+ pr_err("%s: unable to initialise DMA channels. "
+ "Falling back to PIO\n",
+ mmc_hostname(mmc));
+- host->have_dma = false;
++ host->use_dma = false;
+ } else {
+- host->have_dma = true;
++ host->use_dma = true;
+
+ cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+@@ -1741,7 +1830,7 @@ int bcm2835_sdhost_add_host(struct bcm28
+ ret = dmaengine_slave_config(host->dma_chan_rx, &cfg);
+ }
+ } else {
+- host->have_dma = false;
++ host->use_dma = false;
+ }
+
+ mmc->max_segs = 128;
+@@ -1756,16 +1845,15 @@ int bcm2835_sdhost_add_host(struct bcm28
+ tasklet_init(&host->finish_tasklet,
+ bcm2835_sdhost_tasklet_finish, (unsigned long)host);
+
+- setup_timer(&host->timer, bcm2835_sdhost_timeout,
+- (unsigned long)host);
++ INIT_WORK(&host->cmd_wait_wq, bcm2835_sdhost_cmd_wait_work);
+
+- setup_timer(&host->pio_timer, bcm2835_sdhost_pio_timeout,
++ setup_timer(&host->timer, bcm2835_sdhost_timeout,
+ (unsigned long)host);
+
+ bcm2835_sdhost_init(host, 0);
+- ret = request_threaded_irq(host->irq, bcm2835_sdhost_irq,
+- bcm2835_sdhost_thread_irq,
+- IRQF_SHARED, mmc_hostname(mmc), host);
++
++ ret = request_irq(host->irq, bcm2835_sdhost_irq, 0 /*IRQF_SHARED*/,
++ mmc_hostname(mmc), host);
+ if (ret) {
+ pr_err("%s: failed to request IRQ %d: %d\n",
+ mmc_hostname(mmc), host->irq, ret);
+@@ -1776,11 +1864,11 @@ int bcm2835_sdhost_add_host(struct bcm28
+ mmc_add_host(mmc);
+
+ pio_limit_string[0] = '\0';
+- if (host->have_dma && (host->pio_limit > 0))
++ if (host->use_dma && (host->pio_limit > 0))
+ sprintf(pio_limit_string, " (>%d)", host->pio_limit);
+ pr_info("%s: %s loaded - DMA %s%s\n",
+ mmc_hostname(mmc), DRIVER_NAME,
+- host->have_dma ? "enabled" : "disabled",
++ host->use_dma ? "enabled" : "disabled",
+ pio_limit_string);
+
+ return 0;
+@@ -1810,8 +1898,11 @@ static int bcm2835_sdhost_probe(struct p
+ mmc->ops = &bcm2835_sdhost_ops;
+ host = mmc_priv(mmc);
+ host->mmc = mmc;
++ host->cmd_quick_poll_retries = 0;
+ host->pio_timeout = msecs_to_jiffies(500);
++ host->pio_limit = 1;
+ host->max_delay = 1; /* Warn if over 1ms */
++ host->allow_dma = 1;
+ spin_lock_init(&host->lock);
+
+ iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+@@ -1827,13 +1918,12 @@ static int bcm2835_sdhost_probe(struct p
+ return -ENODEV;
+ }
+ host->bus_addr = be32_to_cpup(addr);
++ log_init(iomem->start - host->bus_addr);
+ pr_debug(" - ioaddr %lx, iomem->start %lx, bus_addr %lx\n",
+ (unsigned long)host->ioaddr,
+ (unsigned long)iomem->start,
+ (unsigned long)host->bus_addr);
+
+- host->allow_dma = ALLOW_DMA;
+-
+ if (node) {
+ /* Read any custom properties */
+ of_property_read_u32(node,
+@@ -1845,16 +1935,17 @@ static int bcm2835_sdhost_probe(struct p
+ of_property_read_u32(node,
+ "brcm,pio-limit",
+ &host->pio_limit);
+- host->allow_dma = ALLOW_DMA &&
++ host->allow_dma =
+ !of_property_read_bool(node, "brcm,force-pio");
+ host->debug = of_property_read_bool(node, "brcm,debug");
+- of_property_read_u32(node,
+- "brcm,debug-flags",
+- &host->debug_flags);
+ }
+
+- if (host->debug_flags)
+- dev_err(dev, "debug_flags=%x\n", host->debug_flags);
++ host->dma_chan = NULL;
++ host->dma_desc = NULL;
++
++ /* Formally recognise the other way of disabling DMA */
++ if (host->pio_limit == 0x7fffffff)
++ host->allow_dma = false;
+
+ if (host->allow_dma) {
+ if (node) {
+@@ -1940,15 +2031,12 @@ static int bcm2835_sdhost_remove(struct
+ return 0;
+ }
+
+-
+ static const struct of_device_id bcm2835_sdhost_match[] = {
+ { .compatible = "brcm,bcm2835-sdhost" },
+ { }
+ };
+ MODULE_DEVICE_TABLE(of, bcm2835_sdhost_match);
+
+-
+-
+ static struct platform_driver bcm2835_sdhost_driver = {
+ .probe = bcm2835_sdhost_probe,
+ .remove = bcm2835_sdhost_remove,
diff --git a/target/linux/brcm2708/patches-4.4/0144-BCM270X_DT-Add-dtparams-for-the-SD-interface.patch b/target/linux/brcm2708/patches-4.4/0144-BCM270X_DT-Add-dtparams-for-the-SD-interface.patch
new file mode 100644
index 0000000000..fcd8f77b2a
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0144-BCM270X_DT-Add-dtparams-for-the-SD-interface.patch
@@ -0,0 +1,235 @@
+From 6b9beded9c5f2c6d834a51e64cca92fafbc65fbf Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 12 Feb 2016 15:38:00 +0000
+Subject: [PATCH 144/381] BCM270X_DT: Add dtparams for the SD interface
+
+Add new base dtparams sd_overclock, sd_force_pio, sd_pio_limit
+and sd_debug.
+---
+ arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 4 ++++
+ arch/arm/boot/dts/bcm2708-rpi-b.dts | 4 ++++
+ arch/arm/boot/dts/bcm2708-rpi-cm.dts | 1 -
+ arch/arm/boot/dts/bcm2708-rpi-cm.dtsi | 13 +++++++++++++
+ arch/arm/boot/dts/bcm2708_common.dtsi | 2 ++
+ arch/arm/boot/dts/bcm2709-rpi-2-b.dts | 4 ++++
+ arch/arm/boot/dts/overlays/README | 11 ++++++++++-
+ arch/arm/boot/dts/overlays/mmc-overlay.dts | 1 -
+ arch/arm/boot/dts/overlays/sdhost-overlay.dts | 27 +++++++++++++-------------
+ arch/arm/boot/dts/overlays/sdtweak-overlay.dts | 14 ++++++-------
+ 10 files changed, 58 insertions(+), 23 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
++++ b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
+@@ -141,5 +141,9 @@
+ audio = <&audio>,"status";
+ watchdog = <&watchdog>,"status";
+ random = <&random>,"status";
++ sd_overclock = <&sdhost>,"brcm,overclock-50:0";
++ sd_force_pio = <&sdhost>,"brcm,force-pio?";
++ sd_pio_limit = <&sdhost>,"brcm,pio-limit:0";
++ sd_debug = <&sdhost>,"brcm,debug";
+ };
+ };
+--- a/arch/arm/boot/dts/bcm2708-rpi-b.dts
++++ b/arch/arm/boot/dts/bcm2708-rpi-b.dts
+@@ -131,5 +131,9 @@
+ audio = <&audio>,"status";
+ watchdog = <&watchdog>,"status";
+ random = <&random>,"status";
++ sd_overclock = <&sdhost>,"brcm,overclock-50:0";
++ sd_force_pio = <&sdhost>,"brcm,force-pio?";
++ sd_pio_limit = <&sdhost>,"brcm,pio-limit:0";
++ sd_debug = <&sdhost>,"brcm,debug";
+ };
+ };
+--- a/arch/arm/boot/dts/bcm2708-rpi-cm.dts
++++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dts
+@@ -97,6 +97,5 @@
+ i2c0_baudrate = <&i2c0>,"clock-frequency:0";
+ i2c1_baudrate = <&i2c1>,"clock-frequency:0";
+ i2c2_baudrate = <&i2c2>,"clock-frequency:0";
+- core_freq = <&clk_core>,"clock-frequency:0";
+ };
+ };
+--- a/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi
++++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi
+@@ -7,6 +7,13 @@
+ };
+ };
+
++&gpio {
++ sdhost_pins: sdhost_pins {
++ brcm,pins = <48 49 50 51 52 53>;
++ brcm,function = <4>; /* alt0 */
++ };
++};
++
+ &leds {
+ act_led: act {
+ label = "led0";
+@@ -29,6 +36,8 @@
+
+ / {
+ __overrides__ {
++ core_freq = <&clk_core>,"clock-frequency:0";
++
+ act_led_gpio = <&act_led>,"gpios:4";
+ act_led_activelow = <&act_led>,"gpios:8";
+ act_led_trigger = <&act_led>,"linux,default-trigger";
+@@ -36,5 +45,9 @@
+ audio = <&audio>,"status";
+ watchdog = <&watchdog>,"status";
+ random = <&random>,"status";
++ sd_overclock = <&sdhost>,"brcm,overclock-50:0";
++ sd_force_pio = <&sdhost>,"brcm,force-pio?";
++ sd_pio_limit = <&sdhost>,"brcm,pio-limit:0";
++ sd_debug = <&sdhost>,"brcm,debug";
+ };
+ };
+--- a/arch/arm/boot/dts/bcm2708_common.dtsi
++++ b/arch/arm/boot/dts/bcm2708_common.dtsi
+@@ -135,6 +135,7 @@
+ dmas = <&dma 13>,
+ <&dma 13>;
+ dma-names = "tx", "rx";
++ brcm,overclock-50 = <0>;
+ brcm,pio-limit = <1>;
+ status = "disabled";
+ };
+@@ -203,6 +204,7 @@
+ dmas = <&dma 11>,
+ <&dma 11>;
+ dma-names = "tx", "rx";
++ brcm,overclock-50 = <0>;
+ status = "disabled";
+ };
+
+--- a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts
++++ b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts
+@@ -141,5 +141,9 @@
+ audio = <&audio>,"status";
+ watchdog = <&watchdog>,"status";
+ random = <&random>,"status";
++ sd_overclock = <&sdhost>,"brcm,overclock-50:0";
++ sd_force_pio = <&sdhost>,"brcm,force-pio?";
++ sd_pio_limit = <&sdhost>,"brcm,pio-limit:0";
++ sd_debug = <&sdhost>,"brcm,debug";
+ };
+ };
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -112,6 +112,16 @@ Params:
+ random Set to "on" to enable the hardware random
+ number generator (default "on")
+
++ sd_overclock Clock (in MHz) to use when the MMC framework
++ requests 50MHz
++
++ sd_force_pio Disable DMA support for SD driver (default off)
++
++ sd_pio_limit Number of blocks above which to use DMA for
++ SD card (default 1)
++
++ sd_debug Enable debug output from SD driver (default off)
++
+ uart0 Set to "off" to disable uart0 (default "on")
+
+ watchdog Set to "on" to enable the hardware watchdog
+@@ -443,7 +453,6 @@ Info: Selects the bcm2835-mmc SD/MMC d
+ Load: dtoverlay=mmc,<param>=<val>
+ Params: overclock_50 Clock (in MHz) to use when the MMC framework
+ requests 50MHz
+- force_pio Disable DMA support
+
+
+ Name: mz61581
+--- a/arch/arm/boot/dts/overlays/mmc-overlay.dts
++++ b/arch/arm/boot/dts/overlays/mmc-overlay.dts
+@@ -34,6 +34,5 @@
+
+ __overrides__ {
+ overclock_50 = <&frag0>,"brcm,overclock-50:0";
+- force_pio = <&frag0>,"brcm,force-pio?";
+ };
+ };
+--- a/arch/arm/boot/dts/overlays/sdhost-overlay.dts
++++ b/arch/arm/boot/dts/overlays/sdhost-overlay.dts
+@@ -1,19 +1,14 @@
+ /dts-v1/;
+ /plugin/;
+
++/* Provide backwards compatible aliases for the old sdhost dtparams. */
++
+ /{
+ compatible = "brcm,bcm2708";
+
+ fragment@0 {
+- target = <&mmc>;
+- __overlay__ {
+- status = "disabled";
+- };
+- };
+-
+- fragment@1 {
+ target = <&sdhost>;
+- frag1: __overlay__ {
++ frag0: __overlay__ {
+ brcm,overclock-50 = <0>;
+ brcm,pio-limit = <1>;
+ brcm,debug-flags = <0>;
+@@ -21,11 +16,17 @@
+ };
+ };
+
++ fragment@1 {
++ target = <&mmc>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
+ __overrides__ {
+- overclock_50 = <&frag1>,"brcm,overclock-50:0";
+- force_pio = <&frag1>,"brcm,force-pio?";
+- pio_limit = <&frag1>,"brcm,pio-limit:0";
+- debug = <&frag1>,"brcm,debug?";
+- debug_flags = <&frag1>,"brcm,debug-flags:0";
++ overclock_50 = <&frag0>,"brcm,overclock-50:0";
++ force_pio = <&frag0>,"brcm,force-pio?";
++ pio_limit = <&frag0>,"brcm,pio-limit:0";
++ debug = <&frag0>,"brcm,debug?";
+ };
+ };
+--- a/arch/arm/boot/dts/overlays/sdtweak-overlay.dts
++++ b/arch/arm/boot/dts/overlays/sdtweak-overlay.dts
+@@ -1,23 +1,23 @@
+ /dts-v1/;
+ /plugin/;
+
++/* Provide backwards compatible aliases for the old sdhost dtparams. */
++
+ /{
+ compatible = "brcm,bcm2708";
+
+ fragment@0 {
+ target = <&sdhost>;
+- frag1: __overlay__ {
++ frag0: __overlay__ {
+ brcm,overclock-50 = <0>;
+ brcm,pio-limit = <1>;
+- brcm,debug-flags = <0>;
+ };
+ };
+
+ __overrides__ {
+- overclock_50 = <&frag1>,"brcm,overclock-50:0";
+- force_pio = <&frag1>,"brcm,force-pio?";
+- pio_limit = <&frag1>,"brcm,pio-limit:0";
+- debug = <&frag1>,"brcm,debug?";
+- debug_flags = <&frag1>,"brcm,debug-flags:0";
++ overclock_50 = <&frag0>,"brcm,overclock-50:0";
++ force_pio = <&frag0>,"brcm,force-pio?";
++ pio_limit = <&frag0>,"brcm,pio-limit:0";
++ debug = <&frag0>,"brcm,debug?";
+ };
+ };
diff --git a/target/linux/brcm2708/patches-4.4/0144-Limit-PCM512x-Digital-gain-to-0dB-by-default-with-Hi.patch b/target/linux/brcm2708/patches-4.4/0144-Limit-PCM512x-Digital-gain-to-0dB-by-default-with-Hi.patch
deleted file mode 100644
index 1633cfe6ed..0000000000
--- a/target/linux/brcm2708/patches-4.4/0144-Limit-PCM512x-Digital-gain-to-0dB-by-default-with-Hi.patch
+++ /dev/null
@@ -1,98 +0,0 @@
-From 8a189f18de820c6facd00ba2db97ba7c4a75156f Mon Sep 17 00:00:00 2001
-From: Digital Dreamtime <clive.messer@digitaldreamtime.co.uk>
-Date: Thu, 4 Feb 2016 20:04:00 +0000
-Subject: [PATCH 144/170] Limit PCM512x "Digital" gain to 0dB by default with
- HiFiBerry DAC+
-
-24db_digital_gain DT param can be used to specify that PCM512x
-codec "Digital" volume control should not be limited to 0dB gain,
-and if specified will allow the full 24dB gain.
----
- arch/arm/boot/dts/overlays/README | 17 +++++++++++++++--
- .../arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts | 6 +++++-
- sound/soc/bcm/hifiberry_dacplus.c | 14 ++++++++++++++
- 3 files changed, 34 insertions(+), 3 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -273,8 +273,21 @@ Params: <None>
-
- Name: hifiberry-dacplus
- Info: Configures the HifiBerry DAC+ audio card
--Load: dtoverlay=hifiberry-dacplus
--Params: <None>
-+Load: dtoverlay=hifiberry-dacplus,<param>=<val>
-+Params: 24db_digital_gain Allow gain to be applied via the PCM512x codec
-+ Digital volume control. Enable with
-+ "dtoverlay=hifiberry-dacplus,24db_digital_gain"
-+ (The default behaviour is that the Digital
-+ volume control is limited to a maximum of
-+ 0dB. ie. it can attenuate but not provide
-+ gain. For most users, this will be desired
-+ as it will prevent clipping. By appending
-+ the 24dB_digital_gain parameter, the Digital
-+ volume control will allow up to 24dB of
-+ gain. If this parameter is enabled, it is the
-+ responsibility of the user to ensure that
-+ the Digital volume control is set to a value
-+ that does not result in clipping/distortion!)
-
-
- Name: hifiberry-digi
---- a/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
-@@ -17,7 +17,7 @@
-
- fragment@1 {
- target = <&sound>;
-- __overlay__ {
-+ frag1: __overlay__ {
- compatible = "hifiberry,hifiberry-dacplus";
- i2s-controller = <&i2s>;
- status = "okay";
-@@ -47,4 +47,8 @@
- };
- };
- };
-+
-+ __overrides__ {
-+ 24db_digital_gain = <&frag1>,"hifiberry,24db_digital_gain?";
-+ };
- };
---- a/sound/soc/bcm/hifiberry_dacplus.c
-+++ b/sound/soc/bcm/hifiberry_dacplus.c
-@@ -48,6 +48,7 @@ struct pcm512x_priv {
- #define CLK_48EN_RATE 24576000UL
-
- static bool snd_rpi_hifiberry_is_dacpro;
-+static bool digital_gain_0db_limit = true;
-
- static void snd_rpi_hifiberry_dacplus_select_clk(struct snd_soc_codec *codec,
- int clk_id)
-@@ -167,6 +168,16 @@ static int snd_rpi_hifiberry_dacplus_ini
- snd_soc_update_bits(codec, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02);
- snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
-
-+ if (digital_gain_0db_limit)
-+ {
-+ int ret;
-+ struct snd_soc_card *card = rtd->card;
-+
-+ ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207);
-+ if (ret < 0)
-+ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
-+ }
-+
- return 0;
- }
-
-@@ -299,6 +310,9 @@ static int snd_rpi_hifiberry_dacplus_pro
- dai->platform_name = NULL;
- dai->platform_of_node = i2s_node;
- }
-+
-+ digital_gain_0db_limit = !of_property_read_bool(
-+ pdev->dev.of_node, "hifiberry,24db_digital_gain");
- }
-
- ret = snd_soc_register_card(&snd_rpi_hifiberry_dacplus);
diff --git a/target/linux/brcm2708/patches-4.4/0145-BCM270X_DT-Adjust-overlay-README-formatting.patch b/target/linux/brcm2708/patches-4.4/0145-BCM270X_DT-Adjust-overlay-README-formatting.patch
deleted file mode 100644
index 24084e5f48..0000000000
--- a/target/linux/brcm2708/patches-4.4/0145-BCM270X_DT-Adjust-overlay-README-formatting.patch
+++ /dev/null
@@ -1,746 +0,0 @@
-From 14ba431031afa218c0db43a7c20fe54916f8d357 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Mon, 8 Feb 2016 09:46:33 +0000
-Subject: [PATCH 145/170] BCM270X_DT: Adjust overlay README formatting
-
----
- arch/arm/boot/dts/overlays/README | 420 +++++++++++++++++++-------------------
- 1 file changed, 210 insertions(+), 210 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -83,58 +83,58 @@ Name: <The base DTB>
- Info: Configures the base Raspberry Pi hardware
- Load: <loaded automatically>
- Params:
-- audio Set to "on" to enable the onboard ALSA audio
-- interface (default "off")
-+ audio Set to "on" to enable the onboard ALSA audio
-+ interface (default "off")
-
-- i2c_arm Set to "on" to enable the ARM's i2c interface
-- (default "off")
-+ i2c_arm Set to "on" to enable the ARM's i2c interface
-+ (default "off")
-
-- i2c_vc Set to "on" to enable the i2c interface
-- usually reserved for the VideoCore processor
-- (default "off")
-+ i2c_vc Set to "on" to enable the i2c interface
-+ usually reserved for the VideoCore processor
-+ (default "off")
-
-- i2c An alias for i2c_arm
-+ i2c An alias for i2c_arm
-
-- i2c_arm_baudrate Set the baudrate of the ARM's i2c interface
-- (default "100000")
-+ i2c_arm_baudrate Set the baudrate of the ARM's i2c interface
-+ (default "100000")
-
-- i2c_vc_baudrate Set the baudrate of the VideoCore i2c interface
-- (default "100000")
-+ i2c_vc_baudrate Set the baudrate of the VideoCore i2c interface
-+ (default "100000")
-
-- i2c_baudrate An alias for i2c_arm_baudrate
-+ i2c_baudrate An alias for i2c_arm_baudrate
-
-- i2s Set to "on" to enable the i2s interface
-- (default "off")
-+ i2s Set to "on" to enable the i2s interface
-+ (default "off")
-
-- spi Set to "on" to enable the spi interfaces
-- (default "off")
-+ spi Set to "on" to enable the spi interfaces
-+ (default "off")
-
-- random Set to "on" to enable the hardware random
-- number generator (default "on")
-+ random Set to "on" to enable the hardware random
-+ number generator (default "on")
-
-- uart0 Set to "off" to disable uart0 (default "on")
-+ uart0 Set to "off" to disable uart0 (default "on")
-
-- watchdog Set to "on" to enable the hardware watchdog
-- (default "off")
-+ watchdog Set to "on" to enable the hardware watchdog
-+ (default "off")
-
-- act_led_trigger Choose which activity the LED tracks.
-- Use "heartbeat" for a nice load indicator.
-- (default "mmc")
-+ act_led_trigger Choose which activity the LED tracks.
-+ Use "heartbeat" for a nice load indicator.
-+ (default "mmc")
-
-- act_led_activelow Set to "on" to invert the sense of the LED
-- (default "off")
-+ act_led_activelow Set to "on" to invert the sense of the LED
-+ (default "off")
-
-- act_led_gpio Set which GPIO to use for the activity LED
-- (in case you want to connect it to an external
-- device)
-- (default "16" on a non-Plus board, "47" on a
-- Plus or Pi 2)
-+ act_led_gpio Set which GPIO to use for the activity LED
-+ (in case you want to connect it to an external
-+ device)
-+ (default "16" on a non-Plus board, "47" on a
-+ Plus or Pi 2)
-
- pwr_led_trigger
- pwr_led_activelow
- pwr_led_gpio
-- As for act_led_*, but using the PWR LED.
-- Not available on Model A/B boards.
-+ As for act_led_*, but using the PWR LED.
-+ Not available on Model A/B boards.
-
- N.B. It is recommended to only enable those interfaces that are needed.
- Leaving all interfaces enabled can lead to unwanted behaviour (i2c_vc
-@@ -149,19 +149,19 @@ Params:
- Name: ads7846
- Info: ADS7846 Touch controller
- Load: dtoverlay=ads7846,<param>=<val>
--Params: cs SPI bus Chip Select (default 1)
-- speed SPI bus speed (default 2MHz, max 3.25MHz)
-- penirq GPIO used for PENIRQ. REQUIRED
-- penirq_pull Set GPIO pull (default 0=none, 2=pullup)
-- swapxy Swap x and y axis
-- xmin Minimum value on the X axis (default 0)
-- ymin Minimum value on the Y axis (default 0)
-- xmax Maximum value on the X axis (default 4095)
-- ymax Maximum value on the Y axis (default 4095)
-- pmin Minimum reported pressure value (default 0)
-- pmax Maximum reported pressure value (default 65535)
-- xohms Touchpanel sensitivity (X-plate resistance)
-- (default 400)
-+Params: cs SPI bus Chip Select (default 1)
-+ speed SPI bus speed (default 2MHz, max 3.25MHz)
-+ penirq GPIO used for PENIRQ. REQUIRED
-+ penirq_pull Set GPIO pull (default 0=none, 2=pullup)
-+ swapxy Swap x and y axis
-+ xmin Minimum value on the X axis (default 0)
-+ ymin Minimum value on the Y axis (default 0)
-+ xmax Maximum value on the X axis (default 4095)
-+ ymax Maximum value on the Y axis (default 4095)
-+ pmin Minimum reported pressure value (default 0)
-+ pmax Maximum reported pressure value (default 65535)
-+ xohms Touchpanel sensitivity (X-plate resistance)
-+ (default 400)
-
- penirq is required and usually xohms (60-100) has to be set as well.
- Apart from that, pmax (255) and swapxy are also common.
-@@ -175,12 +175,12 @@ Name: at86rf233
- Info: Configures the Atmel AT86RF233 802.15.4 low-power WPAN transceiver,
- connected to spi0.0
- Load: dtoverlay=at86rf233,<param>=<val>
--Params: interrupt GPIO used for INT (default 23)
-- reset GPIO used for Reset (default 24)
-- sleep GPIO used for Sleep (default 25)
-- speed SPI bus speed in Hz (default 6000000)
-- trim Fine tuning of the internal capacitance
-- arrays (0=+0pF, 15=+4.5pF, default 15)
-+Params: interrupt GPIO used for INT (default 23)
-+ reset GPIO used for Reset (default 24)
-+ sleep GPIO used for Sleep (default 25)
-+ speed SPI bus speed in Hz (default 6000000)
-+ trim Fine tuning of the internal capacitance
-+ arrays (0=+0pF, 15=+4.5pF, default 15)
-
-
- Name: bmp085_i2c-sensor
-@@ -194,8 +194,8 @@ Name: dht11
- Info: Overlay for the DHT11/DHT21/DHT22 humidity/temperature sensors
- Also sometimes found with the part number(s) AM230x.
- Load: dtoverlay=dht11,<param>=<val>
--Params: gpiopin GPIO connected to the sensor's DATA output.
-- (default 4)
-+Params: gpiopin GPIO connected to the sensor's DATA output.
-+ (default 4)
-
-
- Name: dwc-otg
-@@ -208,15 +208,15 @@ Params: <None>
- Name: dwc2
- Info: Selects the dwc2 USB controller driver
- Load: dtoverlay=dwc2,<param>=<val>
--Params: dr_mode Dual role mode: "host", "peripheral" or "otg"
-+Params: dr_mode Dual role mode: "host", "peripheral" or "otg"
-
-- g-rx-fifo-size Size of rx fifo size in gadget mode
-+ g-rx-fifo-size Size of rx fifo size in gadget mode
-
-- g-np-tx-fifo-size Size of non-periodic tx fifo size in gadget
-- mode
-+ g-np-tx-fifo-size Size of non-periodic tx fifo size in gadget
-+ mode
-
-- g-tx-fifo-size Size of periodic tx fifo per endpoint
-- (except ep0) in gadget mode
-+ g-tx-fifo-size Size of periodic tx fifo per endpoint
-+ (except ep0) in gadget mode
-
-
- [ The ds1307-rtc overlay has been deleted. See i2c-rtc. ]
-@@ -225,9 +225,9 @@ Params: dr_mode Dual ro
- Name: enc28j60
- Info: Overlay for the Microchip ENC28J60 Ethernet Controller (SPI)
- Load: dtoverlay=enc28j60,<param>=<val>
--Params: int_pin GPIO used for INT (default 25)
-+Params: int_pin GPIO used for INT (default 25)
-
-- speed SPI bus speed (default 12000000)
-+ speed SPI bus speed (default 12000000)
-
-
- Name: gpio-ir
-@@ -237,26 +237,26 @@ Info: Use GPIO pin as rc-core style in
- not required! The key mapping and other decoding parameters can be
- configured by "ir-keytable" tool.
- Load: dtoverlay=gpio-ir,<param>=<val>
--Params: gpio_pin Input pin number. Default is 18.
-+Params: gpio_pin Input pin number. Default is 18.
-
-- gpio_pull Desired pull-up/down state (off, down, up)
-- Default is "down".
-+ gpio_pull Desired pull-up/down state (off, down, up)
-+ Default is "down".
-
-- rc-map-name Default rc keymap (can also be changed by
-- ir-keytable), defaults to "rc-rc6-mce"
-+ rc-map-name Default rc keymap (can also be changed by
-+ ir-keytable), defaults to "rc-rc6-mce"
-
-
- Name: gpio-poweroff
- Info: Drives a GPIO high or low on reboot
- Load: dtoverlay=gpio-poweroff,<param>=<val>
--Params: gpiopin GPIO for signalling (default 26)
-+Params: gpiopin GPIO for signalling (default 26)
-
-- active_low Set if the power control device requires a
-- high->low transition to trigger a power-down.
-- Note that this will require the support of a
-- custom dt-blob.bin to prevent a power-down
-- during the boot process, and that a reboot
-- will also cause the pin to go low.
-+ active_low Set if the power control device requires a
-+ high->low transition to trigger a power-down.
-+ Note that this will require the support of a
-+ custom dt-blob.bin to prevent a power-down
-+ during the boot process, and that a reboot
-+ will also cause the pin to go low.
-
-
- Name: hifiberry-amp
-@@ -300,65 +300,65 @@ Name: hy28a
- Info: HY28A - 2.8" TFT LCD Display Module by HAOYU Electronics
- Default values match Texy's display shield
- Load: dtoverlay=hy28a,<param>=<val>
--Params: speed Display SPI bus speed
-+Params: speed Display SPI bus speed
-
-- rotate Display rotation {0,90,180,270}
-+ rotate Display rotation {0,90,180,270}
-
-- fps Delay between frame updates
-+ fps Delay between frame updates
-
-- debug Debug output level {0-7}
-+ debug Debug output level {0-7}
-
-- xohms Touchpanel sensitivity (X-plate resistance)
-+ xohms Touchpanel sensitivity (X-plate resistance)
-
-- resetgpio GPIO used to reset controller
-+ resetgpio GPIO used to reset controller
-
-- ledgpio GPIO used to control backlight
-+ ledgpio GPIO used to control backlight
-
-
- Name: hy28b
- Info: HY28B - 2.8" TFT LCD Display Module by HAOYU Electronics
- Default values match Texy's display shield
- Load: dtoverlay=hy28b,<param>=<val>
--Params: speed Display SPI bus speed
-+Params: speed Display SPI bus speed
-
-- rotate Display rotation {0,90,180,270}
-+ rotate Display rotation {0,90,180,270}
-
-- fps Delay between frame updates
-+ fps Delay between frame updates
-
-- debug Debug output level {0-7}
-+ debug Debug output level {0-7}
-
-- xohms Touchpanel sensitivity (X-plate resistance)
-+ xohms Touchpanel sensitivity (X-plate resistance)
-
-- resetgpio GPIO used to reset controller
-+ resetgpio GPIO used to reset controller
-
-- ledgpio GPIO used to control backlight
-+ ledgpio GPIO used to control backlight
-
-
- Name: i2c-gpio
- Info: Adds support for software i2c controller on gpio pins
- Load: dtoverlay=i2c-gpio,<param>=<val>
--Params: i2c_gpio_sda GPIO used for I2C data (default "23")
-+Params: i2c_gpio_sda GPIO used for I2C data (default "23")
-
-- i2c_gpio_scl GPIO used for I2C clock (default "24")
-+ i2c_gpio_scl GPIO used for I2C clock (default "24")
-
-- i2c_gpio_delay_us Clock delay in microseconds
-- (default "2" = ~100kHz)
-+ i2c_gpio_delay_us Clock delay in microseconds
-+ (default "2" = ~100kHz)
-
-
- Name: i2c-rtc
- Info: Adds support for a number of I2C Real Time Clock devices
- Load: dtoverlay=i2c-rtc,<param>=<val>
--Params: ds1307 Select the DS1307 device
-+Params: ds1307 Select the DS1307 device
-
-- ds3231 Select the DS3231 device
-+ ds3231 Select the DS3231 device
-
-- mcp7941x Select the MCP7941x device
-+ mcp7941x Select the MCP7941x device
-
-- pcf2127 Select the PCF2127 device
-+ pcf2127 Select the PCF2127 device
-
-- pcf8523 Select the PCF8523 device
-+ pcf8523 Select the PCF8523 device
-
-- pcf8563 Select the PCF8563 device
-+ pcf8563 Select the PCF8563 device
-
-
- Name: i2s-mmap
-@@ -396,70 +396,70 @@ Name: lirc-rpi
- Info: Configures lirc-rpi (Linux Infrared Remote Control for Raspberry Pi)
- Consult the module documentation for more details.
- Load: dtoverlay=lirc-rpi,<param>=<val>
--Params: gpio_out_pin GPIO for output (default "17")
-+Params: gpio_out_pin GPIO for output (default "17")
-
-- gpio_in_pin GPIO for input (default "18")
-+ gpio_in_pin GPIO for input (default "18")
-
-- gpio_in_pull Pull up/down/off on the input pin
-- (default "down")
-+ gpio_in_pull Pull up/down/off on the input pin
-+ (default "down")
-
-- sense Override the IR receive auto-detection logic:
-- "0" = force active-high
-- "1" = force active-low
-- "-1" = use auto-detection
-- (default "-1")
-+ sense Override the IR receive auto-detection logic:
-+ "0" = force active-high
-+ "1" = force active-low
-+ "-1" = use auto-detection
-+ (default "-1")
-
-- softcarrier Turn the software carrier "on" or "off"
-- (default "on")
-+ softcarrier Turn the software carrier "on" or "off"
-+ (default "on")
-
-- invert "on" = invert the output pin (default "off")
-+ invert "on" = invert the output pin (default "off")
-
-- debug "on" = enable additional debug messages
-- (default "off")
-+ debug "on" = enable additional debug messages
-+ (default "off")
-
-
- Name: mcp2515-can0
- Info: Configures the MCP2515 CAN controller on spi0.0
- Load: dtoverlay=mcp2515-can0,<param>=<val>
--Params: oscillator Clock frequency for the CAN controller (Hz)
-+Params: oscillator Clock frequency for the CAN controller (Hz)
-
-- spimaxfrequency Maximum SPI frequence (Hz)
-+ spimaxfrequency Maximum SPI frequence (Hz)
-
-- interrupt GPIO for interrupt signal
-+ interrupt GPIO for interrupt signal
-
-
- Name: mcp2515-can1
- Info: Configures the MCP2515 CAN controller on spi0.1
- Load: dtoverlay=mcp2515-can1,<param>=<val>
--Params: oscillator Clock frequency for the CAN controller (Hz)
-+Params: oscillator Clock frequency for the CAN controller (Hz)
-
-- spimaxfrequency Maximum SPI frequence (Hz)
-+ spimaxfrequency Maximum SPI frequence (Hz)
-
-- interrupt GPIO for interrupt signal
-+ interrupt GPIO for interrupt signal
-
-
- Name: mmc
- Info: Selects the bcm2835-mmc SD/MMC driver, optionally with overclock
- Load: dtoverlay=mmc,<param>=<val>
--Params: overclock_50 Clock (in MHz) to use when the MMC framework
-- requests 50MHz
-- force_pio Disable DMA support
-+Params: overclock_50 Clock (in MHz) to use when the MMC framework
-+ requests 50MHz
-+ force_pio Disable DMA support
-
-
- Name: mz61581
- Info: MZ61581 display by Tontec
- Load: dtoverlay=mz61581,<param>=<val>
--Params: speed Display SPI bus speed
-+Params: speed Display SPI bus speed
-
-- rotate Display rotation {0,90,180,270}
-+ rotate Display rotation {0,90,180,270}
-
-- fps Delay between frame updates
-+ fps Delay between frame updates
-
-- txbuflen Transmit buffer length (default 32768)
-+ txbuflen Transmit buffer length (default 32768)
-
-- debug Debug output level {0-7}
-+ debug Debug output level {0-7}
-
-- xohms Touchpanel sensitivity (X-plate resistance)
-+ xohms Touchpanel sensitivity (X-plate resistance)
-
-
- [ The pcf2127-rtc overlay has been deleted. See i2c-rtc. ]
-@@ -474,69 +474,69 @@ Params: speed Display
- Name: piscreen
- Info: PiScreen display by OzzMaker.com
- Load: dtoverlay=piscreen,<param>=<val>
--Params: speed Display SPI bus speed
-+Params: speed Display SPI bus speed
-
-- rotate Display rotation {0,90,180,270}
-+ rotate Display rotation {0,90,180,270}
-
-- fps Delay between frame updates
-+ fps Delay between frame updates
-
-- debug Debug output level {0-7}
-+ debug Debug output level {0-7}
-
-- xohms Touchpanel sensitivity (X-plate resistance)
-+ xohms Touchpanel sensitivity (X-plate resistance)
-
-
- Name: piscreen2r
- Info: PiScreen 2 with resistive TP display by OzzMaker.com
- Load: dtoverlay=piscreen2r,<param>=<val>
--Params: speed Display SPI bus speed
-+Params: speed Display SPI bus speed
-
-- rotate Display rotation {0,90,180,270}
-+ rotate Display rotation {0,90,180,270}
-
-- fps Delay between frame updates
-+ fps Delay between frame updates
-
-- debug Debug output level {0-7}
-+ debug Debug output level {0-7}
-
-- xohms Touchpanel sensitivity (X-plate resistance)
-+ xohms Touchpanel sensitivity (X-plate resistance)
-
-
- Name: pitft28-capacitive
- Info: Adafruit PiTFT 2.8" capacitive touch screen
- Load: dtoverlay=pitft28-capacitive,<param>=<val>
--Params: speed Display SPI bus speed
-+Params: speed Display SPI bus speed
-
-- rotate Display rotation {0,90,180,270}
-+ rotate Display rotation {0,90,180,270}
-
-- fps Delay between frame updates
-+ fps Delay between frame updates
-
-- debug Debug output level {0-7}
-+ debug Debug output level {0-7}
-
-- touch-sizex Touchscreen size x (default 240)
-+ touch-sizex Touchscreen size x (default 240)
-
-- touch-sizey Touchscreen size y (default 320)
-+ touch-sizey Touchscreen size y (default 320)
-
-- touch-invx Touchscreen inverted x axis
-+ touch-invx Touchscreen inverted x axis
-
-- touch-invy Touchscreen inverted y axis
-+ touch-invy Touchscreen inverted y axis
-
-- touch-swapxy Touchscreen swapped x y axis
-+ touch-swapxy Touchscreen swapped x y axis
-
-
- Name: pitft28-resistive
- Info: Adafruit PiTFT 2.8" resistive touch screen
- Load: dtoverlay=pitft28-resistive,<param>=<val>
--Params: speed Display SPI bus speed
-+Params: speed Display SPI bus speed
-
-- rotate Display rotation {0,90,180,270}
-+ rotate Display rotation {0,90,180,270}
-
-- fps Delay between frame updates
-+ fps Delay between frame updates
-
-- debug Debug output level {0-7}
-+ debug Debug output level {0-7}
-
-
- Name: pps-gpio
- Info: Configures the pps-gpio (pulse-per-second time signal via GPIO).
- Load: dtoverlay=pps-gpio,<param>=<val>
--Params: gpiopin Input GPIO (default "18")
-+Params: gpiopin Input GPIO (default "18")
-
-
- Name: pwm
-@@ -550,12 +550,12 @@ Info: Configures a single PWM channel
- Pins 12 and 13 might be better choices on an A+, B+ or Pi2.
- 2) The onboard analogue audio output uses both PWM channels.
- 3) So be careful mixing audio and PWM.
-- 4) Currently the clock must have been enabled and configured
-+ 4) Currently the clockmust have been enabled and configured
- by other means.
- Load: dtoverlay=pwm,<param>=<val>
--Params: pin Output pin (default 18) - see table
-- func Pin function (default 2 = Alt5) - see above
-- clock PWM clock frequency (informational)
-+Params: pin Output pin (default 18) - see table
-+ func Pin function (default 2 = Alt5) - see above
-+ clock PWM clock frequency (informational)
-
-
- Name: pwm-2chan
-@@ -569,14 +569,14 @@ Info: Configures both PWM channels
- Pins 12 and 13 might be better choices on an A+, B+ or Pi2.
- 2) The onboard analogue audio output uses both PWM channels.
- 3) So be careful mixing audio and PWM.
-- 4) Currently the clock must have been enabled and configured
-+ 4) Currently the clockmust have been enabled and configured
- by other means.
- Load: dtoverlay=pwm-2chan,<param>=<val>
--Params: pin Output pin (default 18) - see table
-- pin2 Output pin for other channel (default 19)
-- func Pin function (default 2 = Alt5) - see above
-- func2 Function for pin2 (default 2 = Alt5)
-- clock PWM clock frequency (informational)
-+Params: pin Output pin (default 18) - see table
-+ pin2 Output pin for other channel (default 19)
-+ func Pin function (default 2 = Alt5) - see above
-+ func2 Function for pin2 (default 2 = Alt5)
-+ clock PWM clock frequency (informational)
-
-
- Name: raspidac3
-@@ -600,15 +600,15 @@ Params: <None>
- Name: rpi-display
- Info: RPi-Display - 2.8" Touch Display by Watterott
- Load: dtoverlay=rpi-display,<param>=<val>
--Params: speed Display SPI bus speed
-+Params: speed Display SPI bus speed
-
-- rotate Display rotation {0,90,180,270}
-+ rotate Display rotation {0,90,180,270}
-
-- fps Delay between frame updates
-+ fps Delay between frame updates
-
-- debug Debug output level {0-7}
-+ debug Debug output level {0-7}
-
-- xohms Touchpanel sensitivity (X-plate resistance)
-+ xohms Touchpanel sensitivity (X-plate resistance)
-
-
- Name: rpi-ft5406
-@@ -632,52 +632,52 @@ Params: <None>
- Name: sdhost
- Info: Selects the bcm2835-sdhost SD/MMC driver, optionally with overclock
- Load: dtoverlay=sdhost,<param>=<val>
--Params: overclock_50 Clock (in MHz) to use when the MMC framework
-- requests 50MHz
-+Params: overclock_50 Clock (in MHz) to use when the MMC framework
-+ requests 50MHz
-
-- force_pio Disable DMA support (default off)
-+ force_pio Disable DMA support (default off)
-
-- pio_limit Number of blocks above which to use DMA
-- (default 1)
-+ pio_limit Number of blocks above which to use DMA
-+ (default 1)
-
-- debug Enable debug output (default off)
-+ debug Enable debug output (default off)
-
-
- Name: sdio
- Info: Selects the bcm2835-sdhost SD/MMC driver, optionally with overclock,
- and enables SDIO via GPIOs 22-27.
- Load: dtoverlay=sdio,<param>=<val>
--Params: overclock_50 SD Clock (in MHz) to use when the MMC framework
-- requests 50MHz
-+Params: overclock_50 SD Clock (in MHz) to use when the MMC framework
-+ requests 50MHz
-
-- sdio_overclock SDIO Clock (in MHz) to use when the MMC
-- framework requests 50MHz
-+ sdio_overclock SDIO Clock (in MHz) to use when the MMC
-+ framework requests 50MHz
-
-- force_pio Disable DMA support (default off)
-+ force_pio Disable DMA support (default off)
-
-- pio_limit Number of blocks above which to use DMA
-- (default 1)
-+ pio_limit Number of blocks above which to use DMA
-+ (default 1)
-
-- debug Enable debug output (default off)
-+ debug Enable debug output (default off)
-
-- poll_once Disable SDIO-device polling every second
-- (default on: polling once at boot-time)
-+ poll_once Disable SDIO-device polling every second
-+ (default on: polling once at boot-time)
-
-- bus_width Set the SDIO host bus width (default 4 bits)
-+ bus_width Set the SDIO host bus width (default 4 bits)
-
-
- Name: sdtweak
- Info: Tunes the bcm2835-sdhost SD/MMC driver
- Load: dtoverlay=sdtweak,<param>=<val>
--Params: overclock_50 Clock (in MHz) to use when the MMC framework
-- requests 50MHz
-+Params: overclock_50 Clock (in MHz) to use when the MMC framework
-+ requests 50MHz
-
-- force_pio Disable DMA support (default off)
-+ force_pio Disable DMA support (default off)
-
-- pio_limit Number of blocks above which to use DMA
-- (default 1)
-+ pio_limit Number of blocks above which to use DMA
-+ (default 1)
-
-- debug Enable debug output (default off)
-+ debug Enable debug output (default off)
-
-
- Name: smi
-@@ -708,25 +708,25 @@ Name: tinylcd35
- Info: 3.5" Color TFT Display by www.tinylcd.com
- Options: Touch, RTC, keypad
- Load: dtoverlay=tinylcd35,<param>=<val>
--Params: speed Display SPI bus speed
-+Params: speed Display SPI bus speed
-
-- rotate Display rotation {0,90,180,270}
-+ rotate Display rotation {0,90,180,270}
-
-- fps Delay between frame updates
-+ fps Delay between frame updates
-
-- debug Debug output level {0-7}
-+ debug Debug output level {0-7}
-
-- touch Enable touch panel
-+ touch Enable touch panel
-
-- touchgpio Touch controller IRQ GPIO
-+ touchgpio Touch controller IRQ GPIO
-
-- xohms Touchpanel: Resistance of X-plate in ohms
-+ xohms Touchpanel: Resistance of X-plate in ohms
-
-- rtc-pcf PCF8563 Real Time Clock
-+ rtc-pcf PCF8563 Real Time Clock
-
-- rtc-ds DS1307 Real Time Clock
-+ rtc-ds DS1307 Real Time Clock
-
-- keypad Enable keypad
-+ keypad Enable keypad
-
- Examples:
- Display with touchpanel, PCF8563 RTC and keypad:
-@@ -738,9 +738,9 @@ Params: speed Display
- Name: uart1
- Info: Enable uart1 in place of uart0
- Load: dtoverlay=uart1,<param>=<val>
--Params: txd1_pin GPIO pin for TXD1 (14, 32 or 40 - default 14)
-+Params: txd1_pin GPIO pin for TXD1 (14, 32 or 40 - default 14)
-
-- rxd1_pin GPIO pin for RXD1 (15, 33 or 41 - default 15)
-+ rxd1_pin GPIO pin for RXD1 (15, 33 or 41 - default 15)
-
-
- Name: vc4-kms-v3d
-@@ -753,7 +753,7 @@ Params: <None>
-
- Name: vga666
- Info: Overlay for the Fen Logic VGA666 board
-- This uses GPIOs 2-21 (so no I2C), and activates the output 2-3 seconds
-+ This uses GPIOs 2-21 (sono I2C), and activates the output 2-3 seconds
- after the kernel has started.
- Load: dtoverlay=vga666
- Params: <None>
-@@ -763,22 +763,22 @@ Name: w1-gpio
- Info: Configures the w1-gpio Onewire interface module.
- Use this overlay if you *don't* need a GPIO to drive an external pullup.
- Load: dtoverlay=w1-gpio,<param>=<val>
--Params: gpiopin GPIO for I/O (default "4")
-+Params: gpiopin GPIO for I/O (default "4")
-
-- pullup Non-zero, "on", or "y" to enable the parasitic
-- power (2-wire, power-on-data) feature
-+ pullup Non-zero, "on", or "y" to enable the parasitic
-+ power (2-wire, power-on-data) feature
-
-
- Name: w1-gpio-pullup
- Info: Configures the w1-gpio Onewire interface module.
- Use this overlay if you *do* need a GPIO to drive an external pullup.
- Load: dtoverlay=w1-gpio-pullup,<param>=<val>
--Params: gpiopin GPIO for I/O (default "4")
-+Params: gpiopin GPIO for I/O (default "4")
-
-- pullup Non-zero, "on", or "y" to enable the parasitic
-- power (2-wire, power-on-data) feature
-+ pullup Non-zero, "on", or "y" to enable the parasitic
-+ power (2-wire, power-on-data) feature
-
-- extpullup GPIO for external pullup (default "5")
-+ extpullup GPIO for external pullup (default "5")
-
-
- Troubleshooting
diff --git a/target/linux/brcm2708/patches-4.4/0145-dcw_otg-trim-xfer-length-when-buffer-larger-than-all.patch b/target/linux/brcm2708/patches-4.4/0145-dcw_otg-trim-xfer-length-when-buffer-larger-than-all.patch
new file mode 100644
index 0000000000..5a2dffe06b
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0145-dcw_otg-trim-xfer-length-when-buffer-larger-than-all.patch
@@ -0,0 +1,37 @@
+From f61457732dafaccb0804b0d45a4ae751e60e1db4 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Fri, 12 Feb 2016 14:50:25 +0000
+Subject: [PATCH 145/381] dcw_otg: trim xfer length when buffer larger than
+ allocated size is received
+
+---
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
+@@ -737,6 +737,11 @@ static int update_urb_state_xfer_comp(dw
+ DWC_OTG_HC_XFER_COMPLETE,
+ &short_read);
+
++ if (urb->actual_length + xfer_length > urb->length) {
++ DWC_WARN("%s(): trimming xfer length\n", __func__);
++ xfer_length = urb->length - urb->actual_length;
++ }
++
+ /* non DWORD-aligned buffer case handling. */
+ if (hc->align_buff && xfer_length && hc->ep_is_in) {
+ dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf,
+@@ -1423,6 +1428,12 @@ static void update_urb_state_xfer_intr(d
+ {
+ uint32_t bytes_transferred = get_actual_xfer_length(hc, hc_regs, qtd,
+ halt_status, NULL);
++
++ if (urb->actual_length + bytes_transferred > urb->length) {
++ DWC_WARN("%s(): trimming xfer length\n", __func__);
++ bytes_transferred = urb->length - urb->actual_length;
++ }
++
+ /* non DWORD-aligned buffer case handling. */
+ if (hc->align_buff && bytes_transferred && hc->ep_is_in) {
+ dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf,
diff --git a/target/linux/brcm2708/patches-4.4/0146-FIXUP-Overlay-README-Restore-spaces-deleted-in-error.patch b/target/linux/brcm2708/patches-4.4/0146-FIXUP-Overlay-README-Restore-spaces-deleted-in-error.patch
deleted file mode 100644
index 70a9fc7718..0000000000
--- a/target/linux/brcm2708/patches-4.4/0146-FIXUP-Overlay-README-Restore-spaces-deleted-in-error.patch
+++ /dev/null
@@ -1,39 +0,0 @@
-From d32795d2be55748552ddacd9b1e47efc61264a98 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Mon, 8 Feb 2016 12:53:44 +0000
-Subject: [PATCH 146/170] FIXUP: Overlay README - Restore spaces deleted in
- error
-
----
- arch/arm/boot/dts/overlays/README | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -550,7 +550,7 @@ Info: Configures a single PWM channel
- Pins 12 and 13 might be better choices on an A+, B+ or Pi2.
- 2) The onboard analogue audio output uses both PWM channels.
- 3) So be careful mixing audio and PWM.
-- 4) Currently the clockmust have been enabled and configured
-+ 4) Currently the clock must have been enabled and configured
- by other means.
- Load: dtoverlay=pwm,<param>=<val>
- Params: pin Output pin (default 18) - see table
-@@ -569,7 +569,7 @@ Info: Configures both PWM channels
- Pins 12 and 13 might be better choices on an A+, B+ or Pi2.
- 2) The onboard analogue audio output uses both PWM channels.
- 3) So be careful mixing audio and PWM.
-- 4) Currently the clockmust have been enabled and configured
-+ 4) Currently the clock must have been enabled and configured
- by other means.
- Load: dtoverlay=pwm-2chan,<param>=<val>
- Params: pin Output pin (default 18) - see table
-@@ -753,7 +753,7 @@ Params: <None>
-
- Name: vga666
- Info: Overlay for the Fen Logic VGA666 board
-- This uses GPIOs 2-21 (sono I2C), and activates the output 2-3 seconds
-+ This uses GPIOs 2-21 (so no I2C), and activates the output 2-3 seconds
- after the kernel has started.
- Load: dtoverlay=vga666
- Params: <None>
diff --git a/target/linux/brcm2708/patches-4.4/0146-bcm2835-sdhost-Restore-ATOMIC-flag-to-PIO-sg-mapping.patch b/target/linux/brcm2708/patches-4.4/0146-bcm2835-sdhost-Restore-ATOMIC-flag-to-PIO-sg-mapping.patch
new file mode 100644
index 0000000000..48cf4473c6
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0146-bcm2835-sdhost-Restore-ATOMIC-flag-to-PIO-sg-mapping.patch
@@ -0,0 +1,32 @@
+From 681233bfac9474a1defb720fddf90a3087cd1ef4 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 15 Feb 2016 10:00:27 +0000
+Subject: [PATCH 146/381] bcm2835-sdhost: Restore ATOMIC flag to PIO sg mapping
+
+Allocation problems have been seen in a wireless driver, and
+this is the only change which might have been responsible.
+---
+ drivers/mmc/host/bcm2835-sdhost.c | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+--- a/drivers/mmc/host/bcm2835-sdhost.c
++++ b/drivers/mmc/host/bcm2835-sdhost.c
+@@ -874,15 +874,14 @@ static void bcm2835_sdhost_prepare_data(
+ host->flush_fifo = 0;
+ host->data->bytes_xfered = 0;
+
+-
+ if (!host->dma_desc) {
+ /* Use PIO */
+- int flags;
++ int flags = SG_MITER_ATOMIC;
+
+ if (data->flags & MMC_DATA_READ)
+- flags = SG_MITER_TO_SG;
++ flags |= SG_MITER_TO_SG;
+ else
+- flags = SG_MITER_FROM_SG;
++ flags |= SG_MITER_FROM_SG;
+ sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
+ host->blocks = data->blocks;
+ }
diff --git a/target/linux/brcm2708/patches-4.4/0147-Updated-smsc95xx-driver-to-check-for-a-valid-MAC-add.patch b/target/linux/brcm2708/patches-4.4/0147-Updated-smsc95xx-driver-to-check-for-a-valid-MAC-add.patch
new file mode 100644
index 0000000000..145874a7cc
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0147-Updated-smsc95xx-driver-to-check-for-a-valid-MAC-add.patch
@@ -0,0 +1,40 @@
+From 97c4f995a385631934b1d732271997d44fab0c87 Mon Sep 17 00:00:00 2001
+From: Craig Roberts <cjr@craigroberts.net>
+Date: Tue, 16 Feb 2016 10:03:42 +0000
+Subject: [PATCH 147/381] Updated smsc95xx driver to check for a valid MAC
+ address in eeprom before using smsc95xx.macaddr parameter passed on command
+ line.
+
+The built-in RPi adaptor will still get a MAC address based on the parameter passed on the command line as the RPi hardware does not have an eeprom,
+however usb->ethernet adaptors using the same driver should have an eeprom with MAC address as part of their hardware and therefore will use this
+meaning they don't end up with the same MAC address as the built-in RPi adaptor.
+---
+ drivers/net/usb/smsc95xx.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/usb/smsc95xx.c
++++ b/drivers/net/usb/smsc95xx.c
+@@ -817,10 +817,6 @@ static int smsc95xx_is_macaddr_param(str
+
+ static void smsc95xx_init_mac_address(struct usbnet *dev)
+ {
+- /* Check module parameters */
+- if (smsc95xx_is_macaddr_param(dev, dev->net->dev_addr))
+- return;
+-
+ /* try reading mac address from EEPROM */
+ if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN,
+ dev->net->dev_addr) == 0) {
+@@ -831,7 +827,11 @@ static void smsc95xx_init_mac_address(st
+ }
+ }
+
+- /* no eeprom, or eeprom values are invalid. generate random MAC */
++ /* Check module parameters */
++ if (smsc95xx_is_macaddr_param(dev, dev->net->dev_addr))
++ return;
++
++ /* no eeprom, or eeprom values are invalid, and no module parameter specified to set MAC. Generate random MAC */
+ eth_hw_addr_random(dev->net);
+ netif_dbg(dev, ifup, dev->net, "MAC address set to eth_random_addr\n");
+ }
diff --git a/target/linux/brcm2708/patches-4.4/0148-Revert-BCM270X_DT-Disable-DMA-for-bcm2835-sdhost-on-.patch b/target/linux/brcm2708/patches-4.4/0148-Revert-BCM270X_DT-Disable-DMA-for-bcm2835-sdhost-on-.patch
deleted file mode 100644
index e71eda57b4..0000000000
--- a/target/linux/brcm2708/patches-4.4/0148-Revert-BCM270X_DT-Disable-DMA-for-bcm2835-sdhost-on-.patch
+++ /dev/null
@@ -1,21 +0,0 @@
-From 14e35b8cca5bf1f6223ebc6cc4d527645076a3a3 Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Thu, 11 Feb 2016 17:30:49 +0000
-Subject: [PATCH 148/170] Revert "BCM270X_DT: Disable DMA for bcm2835-sdhost on
- Pi2"
-
-This reverts commit 9c1adcc07a40f762fd4ac580f07646784de135e1.
----
- arch/arm/boot/dts/bcm2709-rpi-2-b.dts | 1 -
- 1 file changed, 1 deletion(-)
-
---- a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts
-+++ b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts
-@@ -43,7 +43,6 @@
- pinctrl-names = "default";
- pinctrl-0 = <&sdhost_pins>;
- bus-width = <4>;
-- brcm,pio-limit = <0x7fffffff>;
- status = "okay";
- };
-
diff --git a/target/linux/brcm2708/patches-4.4/0148-dcw_otg-Make-trimming-messages-less-noisy.patch b/target/linux/brcm2708/patches-4.4/0148-dcw_otg-Make-trimming-messages-less-noisy.patch
new file mode 100644
index 0000000000..28e57bc795
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0148-dcw_otg-Make-trimming-messages-less-noisy.patch
@@ -0,0 +1,31 @@
+From 585b22b783df4649751b4ce40074b77ad0cc959b Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Wed, 17 Feb 2016 19:02:31 +0000
+Subject: [PATCH 148/381] dcw_otg: Make trimming messages less noisy
+
+---
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
+@@ -738,7 +738,8 @@ static int update_urb_state_xfer_comp(dw
+ &short_read);
+
+ if (urb->actual_length + xfer_length > urb->length) {
+- DWC_WARN("%s(): trimming xfer length\n", __func__);
++ printk_once(KERN_DEBUG "dwc_otg: DEVICE:%03d : %s:%d:trimming xfer length\n",
++ hc->dev_addr, __func__, __LINE__);
+ xfer_length = urb->length - urb->actual_length;
+ }
+
+@@ -1430,7 +1431,8 @@ static void update_urb_state_xfer_intr(d
+ halt_status, NULL);
+
+ if (urb->actual_length + bytes_transferred > urb->length) {
+- DWC_WARN("%s(): trimming xfer length\n", __func__);
++ printk_once(KERN_DEBUG "dwc_otg: DEVICE:%03d : %s:%d:trimming xfer length\n",
++ hc->dev_addr, __func__, __LINE__);
+ bytes_transferred = urb->length - urb->actual_length;
+ }
+
diff --git a/target/linux/brcm2708/patches-4.4/0149-BCM270X_DT-at86rf233-overlay-drop-to-3MHz.patch b/target/linux/brcm2708/patches-4.4/0149-BCM270X_DT-at86rf233-overlay-drop-to-3MHz.patch
new file mode 100644
index 0000000000..894b15fdb6
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0149-BCM270X_DT-at86rf233-overlay-drop-to-3MHz.patch
@@ -0,0 +1,36 @@
+From 71f287127dd0aafa0346f198c5eef0c4aac7a5f6 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Thu, 18 Feb 2016 15:28:14 +0000
+Subject: [PATCH 149/381] BCM270X_DT: at86rf233 overlay - drop to 3MHz
+
+The consensus is that 6MHz is too fast, but that 3MHz is OK.
+
+See: https://github.com/raspberrypi/linux/issues/1294
+ https://github.com/raspberrypi/linux/issues/1151
+---
+ arch/arm/boot/dts/overlays/README | 2 +-
+ arch/arm/boot/dts/overlays/at86rf233-overlay.dts | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -188,7 +188,7 @@ Load: dtoverlay=at86rf233,<param>=<val
+ Params: interrupt GPIO used for INT (default 23)
+ reset GPIO used for Reset (default 24)
+ sleep GPIO used for Sleep (default 25)
+- speed SPI bus speed in Hz (default 6000000)
++ speed SPI bus speed in Hz (default 3000000)
+ trim Fine tuning of the internal capacitance
+ arrays (0=+0pF, 15=+4.5pF, default 15)
+
+--- a/arch/arm/boot/dts/overlays/at86rf233-overlay.dts
++++ b/arch/arm/boot/dts/overlays/at86rf233-overlay.dts
+@@ -25,7 +25,7 @@
+ interrupts = <23 4>; /* active high */
+ reset-gpio = <&gpio 24 1>;
+ sleep-gpio = <&gpio 25 1>;
+- spi-max-frequency = <6000000>;
++ spi-max-frequency = <3000000>;
+ xtal-trim = /bits/ 8 <0xf>;
+ };
+ };
diff --git a/target/linux/brcm2708/patches-4.4/0149-bcm2835-sdhost-Major-revision.patch b/target/linux/brcm2708/patches-4.4/0149-bcm2835-sdhost-Major-revision.patch
deleted file mode 100644
index c7772cbc0c..0000000000
--- a/target/linux/brcm2708/patches-4.4/0149-bcm2835-sdhost-Major-revision.patch
+++ /dev/null
@@ -1,2070 +0,0 @@
-From 5a117bd925d13a305d94eeb28919dedeaa9be17d Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Thu, 11 Feb 2016 16:51:01 +0000
-Subject: [PATCH 149/170] bcm2835-sdhost: Major revision
-
-This is a significant revision of the bcm2835-sdhost driver. It
-improves on the original in a number of ways:
-
-1) Through the use of CMD23 for reads it appears to avoid problems
- reading some sectors on certain high speed cards.
-2) Better atomicity to prevent crashes.
-3) Higher performance.
-4) Activity logging included, for easier diagnosis in the event
- of a problem.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/mmc/host/bcm2835-sdhost.c | 1284 ++++++++++++++++++++-----------------
- 1 file changed, 686 insertions(+), 598 deletions(-)
-
---- a/drivers/mmc/host/bcm2835-sdhost.c
-+++ b/drivers/mmc/host/bcm2835-sdhost.c
-@@ -2,7 +2,7 @@
- * BCM2835 SD host driver.
- *
- * Author: Phil Elwell <phil@raspberrypi.org>
-- * Copyright 2015
-+ * Copyright (C) 2015-2016 Raspberry Pi (Trading) Ltd.
- *
- * Based on
- * mmc-bcm2835.c by Gellert Weisz
-@@ -24,12 +24,13 @@
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
--#define SAFE_READ_THRESHOLD 4
--#define SAFE_WRITE_THRESHOLD 4
--#define ALLOW_DMA 1
--#define ALLOW_CMD23 0
--#define ALLOW_FAST 1
--#define USE_BLOCK_IRQ 1
-+#define FIFO_READ_THRESHOLD 4
-+#define FIFO_WRITE_THRESHOLD 4
-+#define ALLOW_CMD23_READ 1
-+#define ALLOW_CMD23_WRITE 0
-+#define ENABLE_LOG 1
-+#define SDDATA_FIFO_PIO_BURST 8
-+#define CMD_DALLY_US 1
-
- #include <linux/delay.h>
- #include <linux/module.h>
-@@ -48,6 +49,7 @@
- #include <linux/dma-mapping.h>
- #include <linux/of_dma.h>
- #include <linux/time.h>
-+#include <linux/workqueue.h>
-
- #define DRIVER_NAME "sdhost-bcm2835"
-
-@@ -110,6 +112,28 @@
- #define SDEDM_READ_THRESHOLD_SHIFT 14
- #define SDEDM_THRESHOLD_MASK 0x1f
-
-+#define SDEDM_FSM_MASK 0xf
-+#define SDEDM_FSM_IDENTMODE 0x0
-+#define SDEDM_FSM_DATAMODE 0x1
-+#define SDEDM_FSM_READDATA 0x2
-+#define SDEDM_FSM_WRITEDATA 0x3
-+#define SDEDM_FSM_READWAIT 0x4
-+#define SDEDM_FSM_READCRC 0x5
-+#define SDEDM_FSM_WRITECRC 0x6
-+#define SDEDM_FSM_WRITEWAIT1 0x7
-+#define SDEDM_FSM_POWERDOWN 0x8
-+#define SDEDM_FSM_POWERUP 0x9
-+#define SDEDM_FSM_WRITESTART1 0xa
-+#define SDEDM_FSM_WRITESTART2 0xb
-+#define SDEDM_FSM_GENPULSES 0xc
-+#define SDEDM_FSM_WRITEWAIT2 0xd
-+#define SDEDM_FSM_STARTPOWDOWN 0xf
-+
-+#define SDDATA_FIFO_WORDS 16
-+
-+#define USE_CMD23_FLAGS ((ALLOW_CMD23_READ * MMC_DATA_READ) | \
-+ (ALLOW_CMD23_WRITE * MMC_DATA_WRITE))
-+
- #define MHZ 1000000
-
-
-@@ -131,15 +155,17 @@ struct bcm2835_host {
-
- struct tasklet_struct finish_tasklet; /* Tasklet structures */
-
-- struct timer_list timer; /* Timer for timeouts */
-+ struct work_struct cmd_wait_wq; /* Workqueue function */
-
-- struct timer_list pio_timer; /* PIO error detection timer */
-+ struct timer_list timer; /* Timer for timeouts */
-
- struct sg_mapping_iter sg_miter; /* SG state for PIO */
- unsigned int blocks; /* remaining PIO blocks */
-
- int irq; /* Device IRQ */
-
-+ u32 cmd_quick_poll_retries;
-+ u32 ns_per_fifo_word;
-
- /* cached registers */
- u32 hcfg;
-@@ -154,16 +180,21 @@ struct bcm2835_host {
-
- unsigned int use_busy:1; /* Wait for busy interrupt */
-
-- unsigned int debug:1; /* Enable debug output */
-+ unsigned int use_sbc:1; /* Send CMD23 */
-
-- u32 thread_isr;
-+ unsigned int debug:1; /* Enable debug output */
-
- /*DMA part*/
- struct dma_chan *dma_chan_rx; /* DMA channel for reads */
- struct dma_chan *dma_chan_tx; /* DMA channel for writes */
-+ struct dma_chan *dma_chan; /* Channel in used */
-+ struct dma_async_tx_descriptor *dma_desc;
-+ u32 dma_dir;
-+ u32 drain_words;
-+ struct page *drain_page;
-+ u32 drain_offset;
-
- bool allow_dma;
-- bool have_dma;
- bool use_dma;
- /*end of DMA part*/
-
-@@ -173,13 +204,98 @@ struct bcm2835_host {
- u32 overclock_50; /* frequency to use when 50MHz is requested (in MHz) */
- u32 overclock; /* Current frequency if overclocked, else zero */
- u32 pio_limit; /* Maximum block count for PIO (0 = always DMA) */
-+};
-
-- u32 debug_flags;
-+#if ENABLE_LOG
-
-- u32 sectors; /* Cached card size in sectors */
-- u32 single_read_sectors[8];
-+struct log_entry_struct {
-+ char event[4];
-+ u32 timestamp;
-+ u32 param1;
-+ u32 param2;
- };
-
-+typedef struct log_entry_struct LOG_ENTRY_T;
-+
-+LOG_ENTRY_T *sdhost_log_buf;
-+dma_addr_t sdhost_log_addr;
-+static u32 sdhost_log_idx;
-+static spinlock_t log_lock;
-+static void __iomem *timer_base;
-+
-+#define LOG_ENTRIES (256*1)
-+#define LOG_SIZE (sizeof(LOG_ENTRY_T)*LOG_ENTRIES)
-+
-+static void log_init(u32 bus_to_phys)
-+{
-+ spin_lock_init(&log_lock);
-+ sdhost_log_buf = dma_zalloc_coherent(NULL, LOG_SIZE, &sdhost_log_addr,
-+ GFP_KERNEL);
-+ if (sdhost_log_buf) {
-+ pr_err("sdhost: log_buf @ %p (%x)\n",
-+ sdhost_log_buf, sdhost_log_addr);
-+ timer_base = ioremap_nocache(bus_to_phys + 0x7e003000, SZ_4K);
-+ if (!timer_base)
-+ pr_err("sdhost: failed to remap timer\n");
-+ }
-+ else
-+ pr_err("sdhost: failed to allocate log buf\n");
-+}
-+
-+static void log_event_impl(const char *event, u32 param1, u32 param2)
-+{
-+ if (sdhost_log_buf) {
-+ LOG_ENTRY_T *entry;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&log_lock, flags);
-+
-+ entry = sdhost_log_buf + sdhost_log_idx;
-+ memcpy(entry->event, event, 4);
-+ entry->timestamp = (readl(timer_base + 4) & 0x3fffffff) +
-+ (smp_processor_id()<<30);
-+ entry->param1 = param1;
-+ entry->param2 = param2;
-+ sdhost_log_idx = (sdhost_log_idx + 1) % LOG_ENTRIES;
-+
-+ spin_unlock_irqrestore(&log_lock, flags);
-+ }
-+}
-+
-+static void log_dump(void)
-+{
-+ if (sdhost_log_buf) {
-+ LOG_ENTRY_T *entry;
-+ unsigned long flags;
-+ int idx;
-+
-+ spin_lock_irqsave(&log_lock, flags);
-+
-+ idx = sdhost_log_idx;
-+ do {
-+ entry = sdhost_log_buf + idx;
-+ if (entry->event[0] != '\0')
-+ pr_err("[%08x] %.4s %x %x\n",
-+ entry->timestamp,
-+ entry->event,
-+ entry->param1,
-+ entry->param2);
-+ idx = (idx + 1) % LOG_ENTRIES;
-+ } while (idx != sdhost_log_idx);
-+
-+ spin_unlock_irqrestore(&log_lock, flags);
-+ }
-+}
-+
-+#define log_event(event, param1, param2) log_event_impl(event, param1, param2)
-+
-+#else
-+
-+#define log_init(x) (void)0
-+#define log_event(event, param1, param2) (void)0
-+#define log_dump() (void)0
-+
-+#endif
-
- static inline void bcm2835_sdhost_write(struct bcm2835_host *host, u32 val, int reg)
- {
-@@ -201,7 +317,7 @@ static void bcm2835_sdhost_dumpcmd(struc
- const char *label)
- {
- if (cmd)
-- pr_info("%s:%c%s op %d arg 0x%x flags 0x%x - resp %08x %08x %08x %08x, err %d\n",
-+ pr_err("%s:%c%s op %d arg 0x%x flags 0x%x - resp %08x %08x %08x %08x, err %d\n",
- mmc_hostname(host->mmc),
- (cmd == host->cmd) ? '>' : ' ',
- label, cmd->opcode, cmd->arg, cmd->flags,
-@@ -211,73 +327,74 @@ static void bcm2835_sdhost_dumpcmd(struc
-
- static void bcm2835_sdhost_dumpregs(struct bcm2835_host *host)
- {
-- bcm2835_sdhost_dumpcmd(host, host->mrq->sbc, "sbc");
-- bcm2835_sdhost_dumpcmd(host, host->mrq->cmd, "cmd");
-- if (host->mrq->data)
-- pr_err("%s: data blocks %x blksz %x - err %d\n",
-- mmc_hostname(host->mmc),
-- host->mrq->data->blocks,
-- host->mrq->data->blksz,
-- host->mrq->data->error);
-- bcm2835_sdhost_dumpcmd(host, host->mrq->stop, "stop");
-+ if (host->mrq)
-+ {
-+ bcm2835_sdhost_dumpcmd(host, host->mrq->sbc, "sbc");
-+ bcm2835_sdhost_dumpcmd(host, host->mrq->cmd, "cmd");
-+ if (host->mrq->data)
-+ pr_err("%s: data blocks %x blksz %x - err %d\n",
-+ mmc_hostname(host->mmc),
-+ host->mrq->data->blocks,
-+ host->mrq->data->blksz,
-+ host->mrq->data->error);
-+ bcm2835_sdhost_dumpcmd(host, host->mrq->stop, "stop");
-+ }
-
-- pr_info("%s: =========== REGISTER DUMP ===========\n",
-+ pr_err("%s: =========== REGISTER DUMP ===========\n",
- mmc_hostname(host->mmc));
-
-- pr_info("%s: SDCMD 0x%08x\n",
-+ pr_err("%s: SDCMD 0x%08x\n",
- mmc_hostname(host->mmc),
- bcm2835_sdhost_read(host, SDCMD));
-- pr_info("%s: SDARG 0x%08x\n",
-+ pr_err("%s: SDARG 0x%08x\n",
- mmc_hostname(host->mmc),
- bcm2835_sdhost_read(host, SDARG));
-- pr_info("%s: SDTOUT 0x%08x\n",
-+ pr_err("%s: SDTOUT 0x%08x\n",
- mmc_hostname(host->mmc),
- bcm2835_sdhost_read(host, SDTOUT));
-- pr_info("%s: SDCDIV 0x%08x\n",
-+ pr_err("%s: SDCDIV 0x%08x\n",
- mmc_hostname(host->mmc),
- bcm2835_sdhost_read(host, SDCDIV));
-- pr_info("%s: SDRSP0 0x%08x\n",
-+ pr_err("%s: SDRSP0 0x%08x\n",
- mmc_hostname(host->mmc),
- bcm2835_sdhost_read(host, SDRSP0));
-- pr_info("%s: SDRSP1 0x%08x\n",
-+ pr_err("%s: SDRSP1 0x%08x\n",
- mmc_hostname(host->mmc),
- bcm2835_sdhost_read(host, SDRSP1));
-- pr_info("%s: SDRSP2 0x%08x\n",
-+ pr_err("%s: SDRSP2 0x%08x\n",
- mmc_hostname(host->mmc),
- bcm2835_sdhost_read(host, SDRSP2));
-- pr_info("%s: SDRSP3 0x%08x\n",
-+ pr_err("%s: SDRSP3 0x%08x\n",
- mmc_hostname(host->mmc),
- bcm2835_sdhost_read(host, SDRSP3));
-- pr_info("%s: SDHSTS 0x%08x\n",
-+ pr_err("%s: SDHSTS 0x%08x\n",
- mmc_hostname(host->mmc),
- bcm2835_sdhost_read(host, SDHSTS));
-- pr_info("%s: SDVDD 0x%08x\n",
-+ pr_err("%s: SDVDD 0x%08x\n",
- mmc_hostname(host->mmc),
- bcm2835_sdhost_read(host, SDVDD));
-- pr_info("%s: SDEDM 0x%08x\n",
-+ pr_err("%s: SDEDM 0x%08x\n",
- mmc_hostname(host->mmc),
- bcm2835_sdhost_read(host, SDEDM));
-- pr_info("%s: SDHCFG 0x%08x\n",
-+ pr_err("%s: SDHCFG 0x%08x\n",
- mmc_hostname(host->mmc),
- bcm2835_sdhost_read(host, SDHCFG));
-- pr_info("%s: SDHBCT 0x%08x\n",
-+ pr_err("%s: SDHBCT 0x%08x\n",
- mmc_hostname(host->mmc),
- bcm2835_sdhost_read(host, SDHBCT));
-- pr_info("%s: SDHBLC 0x%08x\n",
-+ pr_err("%s: SDHBLC 0x%08x\n",
- mmc_hostname(host->mmc),
- bcm2835_sdhost_read(host, SDHBLC));
-
-- pr_info("%s: ===========================================\n",
-+ pr_err("%s: ===========================================\n",
- mmc_hostname(host->mmc));
- }
-
--
- static void bcm2835_sdhost_set_power(struct bcm2835_host *host, bool on)
- {
- bcm2835_sdhost_write(host, on ? 1 : 0, SDVDD);
- }
-
--
- static void bcm2835_sdhost_reset_internal(struct bcm2835_host *host)
- {
- u32 temp;
-@@ -300,26 +417,24 @@ static void bcm2835_sdhost_reset_interna
- temp = bcm2835_sdhost_read(host, SDEDM);
- temp &= ~((SDEDM_THRESHOLD_MASK<<SDEDM_READ_THRESHOLD_SHIFT) |
- (SDEDM_THRESHOLD_MASK<<SDEDM_WRITE_THRESHOLD_SHIFT));
-- temp |= (SAFE_READ_THRESHOLD << SDEDM_READ_THRESHOLD_SHIFT) |
-- (SAFE_WRITE_THRESHOLD << SDEDM_WRITE_THRESHOLD_SHIFT);
-+ temp |= (FIFO_READ_THRESHOLD << SDEDM_READ_THRESHOLD_SHIFT) |
-+ (FIFO_WRITE_THRESHOLD << SDEDM_WRITE_THRESHOLD_SHIFT);
- bcm2835_sdhost_write(host, temp, SDEDM);
- mdelay(10);
- bcm2835_sdhost_set_power(host, true);
- mdelay(10);
- host->clock = 0;
-- host->sectors = 0;
-- host->single_read_sectors[0] = ~0;
- bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
- bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
- mmiowb();
- }
-
--
- static void bcm2835_sdhost_reset(struct mmc_host *mmc)
- {
- struct bcm2835_host *host = mmc_priv(mmc);
- unsigned long flags;
- spin_lock_irqsave(&host->lock, flags);
-+ log_event("RST<", 0, 0);
-
- bcm2835_sdhost_reset_internal(host);
-
-@@ -344,82 +459,48 @@ static void bcm2835_sdhost_init(struct b
- }
- }
-
--static bool bcm2835_sdhost_is_write_complete(struct bcm2835_host *host)
-+static void bcm2835_sdhost_wait_transfer_complete(struct bcm2835_host *host)
- {
-- bool write_complete = ((bcm2835_sdhost_read(host, SDEDM) & 0xf) == 1);
-+ int timediff;
-+ u32 alternate_idle;
-+ u32 edm;
-
-- if (!write_complete) {
-- /* Request an IRQ for the last block */
-- host->hcfg |= SDHCFG_BLOCK_IRPT_EN;
-- bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
-- if ((bcm2835_sdhost_read(host, SDEDM) & 0xf) == 1) {
-- /* The write has now completed. Disable the interrupt
-- and clear the status flag */
-- host->hcfg &= ~SDHCFG_BLOCK_IRPT_EN;
-- bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
-- bcm2835_sdhost_write(host, SDHSTS_BLOCK_IRPT, SDHSTS);
-- write_complete = true;
-- }
-- }
-+ alternate_idle = (host->mrq->data->flags & MMC_DATA_READ) ?
-+ SDEDM_FSM_READWAIT : SDEDM_FSM_WRITESTART1;
-
-- return write_complete;
--}
-+ edm = bcm2835_sdhost_read(host, SDEDM);
-
--static void bcm2835_sdhost_wait_write_complete(struct bcm2835_host *host)
--{
-- int timediff;
--#ifdef DEBUG
-- static struct timeval start_time;
-- static int max_stall_time = 0;
-- static int total_stall_time = 0;
-- struct timeval before, after;
--
-- do_gettimeofday(&before);
-- if (max_stall_time == 0)
-- start_time = before;
--#endif
-+ log_event("WTC<", edm, 0);
-
- timediff = 0;
-
- while (1) {
-- u32 edm = bcm2835_sdhost_read(host, SDEDM);
-- if ((edm & 0xf) == 1)
-+ u32 fsm = edm & SDEDM_FSM_MASK;
-+ if ((fsm == SDEDM_FSM_IDENTMODE) ||
-+ (fsm == SDEDM_FSM_DATAMODE))
- break;
-- timediff++;
-- if (timediff > 5000000) {
--#ifdef DEBUG
-- do_gettimeofday(&after);
-- timediff = (after.tv_sec - before.tv_sec)*1000000 +
-- (after.tv_usec - before.tv_usec);
-+ if (fsm == alternate_idle) {
-+ bcm2835_sdhost_write(host,
-+ edm | SDEDM_FORCE_DATA_MODE,
-+ SDEDM);
-+ break;
-+ }
-
-- pr_err(" wait_write_complete - still waiting after %dus\n",
-- timediff);
--#else
-- pr_err(" wait_write_complete - still waiting after %d retries\n",
-+ timediff++;
-+ if (timediff == 100000) {
-+ pr_err("%s: wait_transfer_complete - still waiting after %d retries\n",
-+ mmc_hostname(host->mmc),
- timediff);
--#endif
-+ log_dump();
- bcm2835_sdhost_dumpregs(host);
-- host->data->error = -ETIMEDOUT;
-+ host->mrq->data->error = -ETIMEDOUT;
-+ log_event("WTC!", edm, 0);
- return;
- }
-+ cpu_relax();
-+ edm = bcm2835_sdhost_read(host, SDEDM);
- }
--
--#ifdef DEBUG
-- do_gettimeofday(&after);
-- timediff = (after.tv_sec - before.tv_sec)*1000000 + (after.tv_usec - before.tv_usec);
--
-- total_stall_time += timediff;
-- if (timediff > max_stall_time)
-- max_stall_time = timediff;
--
-- if ((after.tv_sec - start_time.tv_sec) > 10) {
-- pr_debug(" wait_write_complete - max wait %dus, total %dus\n",
-- max_stall_time, total_stall_time);
-- start_time = after;
-- max_stall_time = 0;
-- total_stall_time = 0;
-- }
--#endif
-+ log_event("WTC>", edm, 0);
- }
-
- static void bcm2835_sdhost_finish_data(struct bcm2835_host *host);
-@@ -427,65 +508,44 @@ static void bcm2835_sdhost_finish_data(s
- static void bcm2835_sdhost_dma_complete(void *param)
- {
- struct bcm2835_host *host = param;
-- struct dma_chan *dma_chan;
-+ struct mmc_data *data = host->data;
- unsigned long flags;
-- u32 dir_data;
-
- spin_lock_irqsave(&host->lock, flags);
-+ log_event("DMA<", (u32)host->data, bcm2835_sdhost_read(host, SDHSTS));
-+ log_event("DMA ", bcm2835_sdhost_read(host, SDCMD),
-+ bcm2835_sdhost_read(host, SDEDM));
-
-- if (host->data) {
-- bool write_complete;
-- if (USE_BLOCK_IRQ)
-- write_complete = bcm2835_sdhost_is_write_complete(host);
-- else {
-- bcm2835_sdhost_wait_write_complete(host);
-- write_complete = true;
-- }
-- pr_debug("dma_complete() - write_complete=%d\n",
-- write_complete);
--
-- if (write_complete || (host->data->flags & MMC_DATA_READ))
-- {
-- if (write_complete) {
-- dma_chan = host->dma_chan_tx;
-- dir_data = DMA_TO_DEVICE;
-- } else {
-- dma_chan = host->dma_chan_rx;
-- dir_data = DMA_FROM_DEVICE;
-- }
--
-- dma_unmap_sg(dma_chan->device->dev,
-- host->data->sg, host->data->sg_len,
-- dir_data);
-+ if (host->dma_chan) {
-+ dma_unmap_sg(host->dma_chan->device->dev,
-+ data->sg, data->sg_len,
-+ host->dma_dir);
-
-- bcm2835_sdhost_finish_data(host);
-- }
-+ host->dma_chan = NULL;
- }
-
-- spin_unlock_irqrestore(&host->lock, flags);
--}
-+ if (host->drain_words) {
-+ void *page;
-+ u32 *buf;
-
--static bool data_transfer_wait(struct bcm2835_host *host)
--{
-- unsigned long timeout = 1000000;
-- while (timeout)
-- {
-- u32 sdhsts = bcm2835_sdhost_read(host, SDHSTS);
-- if (sdhsts & SDHSTS_DATA_FLAG) {
-- bcm2835_sdhost_write(host, SDHSTS_DATA_FLAG, SDHSTS);
-- break;
-+ page = kmap_atomic(host->drain_page);
-+ buf = page + host->drain_offset;
-+
-+ while (host->drain_words) {
-+ u32 edm = bcm2835_sdhost_read(host, SDEDM);
-+ if ((edm >> 4) & 0x1f)
-+ *(buf++) = bcm2835_sdhost_read(host,
-+ SDDATA);
-+ host->drain_words--;
- }
-- timeout--;
-- }
-- if (timeout == 0) {
-- pr_err("%s: Data %s timeout\n",
-- mmc_hostname(host->mmc),
-- (host->data->flags & MMC_DATA_READ) ? "read" : "write");
-- bcm2835_sdhost_dumpregs(host);
-- host->data->error = -ETIMEDOUT;
-- return false;
-+
-+ kunmap_atomic(page);
- }
-- return true;
-+
-+ bcm2835_sdhost_finish_data(host);
-+
-+ log_event("DMA>", (u32)host->data, 0);
-+ spin_unlock_irqrestore(&host->lock, flags);
- }
-
- static void bcm2835_sdhost_read_block_pio(struct bcm2835_host *host)
-@@ -493,32 +553,83 @@ static void bcm2835_sdhost_read_block_pi
- unsigned long flags;
- size_t blksize, len;
- u32 *buf;
-+ unsigned long wait_max;
-
- blksize = host->data->blksz;
-
-+ wait_max = jiffies + msecs_to_jiffies(host->pio_timeout);
-+
- local_irq_save(flags);
-
- while (blksize) {
-- if (!sg_miter_next(&host->sg_miter))
-- BUG();
-+ int copy_words;
-+ u32 hsts = 0;
-+
-+ if (!sg_miter_next(&host->sg_miter)) {
-+ host->data->error = -EINVAL;
-+ break;
-+ }
-
- len = min(host->sg_miter.length, blksize);
-- BUG_ON(len % 4);
-+ if (len % 4) {
-+ host->data->error = -EINVAL;
-+ break;
-+ }
-
- blksize -= len;
- host->sg_miter.consumed = len;
-
- buf = (u32 *)host->sg_miter.addr;
-
-- while (len) {
-- if (!data_transfer_wait(host))
-- break;
-+ copy_words = len/4;
-+
-+ while (copy_words) {
-+ int burst_words, words;
-+ u32 edm;
-+
-+ burst_words = SDDATA_FIFO_PIO_BURST;
-+ if (burst_words > copy_words)
-+ burst_words = copy_words;
-+ edm = bcm2835_sdhost_read(host, SDEDM);
-+ words = ((edm >> 4) & 0x1f);
-+
-+ if (words < burst_words) {
-+ int fsm_state = (edm & SDEDM_FSM_MASK);
-+ if ((fsm_state != SDEDM_FSM_READDATA) &&
-+ (fsm_state != SDEDM_FSM_READWAIT) &&
-+ (fsm_state != SDEDM_FSM_READCRC)) {
-+ hsts = bcm2835_sdhost_read(host,
-+ SDHSTS);
-+ pr_err("%s: fsm %x, hsts %x\n",
-+ mmc_hostname(host->mmc),
-+ fsm_state, hsts);
-+ if (hsts & SDHSTS_ERROR_MASK)
-+ break;
-+ }
-+
-+ if (time_after(jiffies, wait_max)) {
-+ pr_err("%s: PIO read timeout - EDM %x\n",
-+ mmc_hostname(host->mmc),
-+ edm);
-+ hsts = SDHSTS_REW_TIME_OUT;
-+ break;
-+ }
-+ ndelay((burst_words - words) *
-+ host->ns_per_fifo_word);
-+ continue;
-+ } else if (words > copy_words) {
-+ words = copy_words;
-+ }
-+
-+ copy_words -= words;
-
-- *(buf++) = bcm2835_sdhost_read(host, SDDATA);
-- len -= 4;
-+ while (words) {
-+ *(buf++) = bcm2835_sdhost_read(host, SDDATA);
-+ words--;
-+ }
- }
-
-- if (host->data->error)
-+ if (hsts & SDHSTS_ERROR_MASK)
- break;
- }
-
-@@ -532,32 +643,83 @@ static void bcm2835_sdhost_write_block_p
- unsigned long flags;
- size_t blksize, len;
- u32 *buf;
-+ unsigned long wait_max;
-
- blksize = host->data->blksz;
-
-+ wait_max = jiffies + msecs_to_jiffies(host->pio_timeout);
-+
- local_irq_save(flags);
-
- while (blksize) {
-- if (!sg_miter_next(&host->sg_miter))
-- BUG();
-+ int copy_words;
-+ u32 hsts = 0;
-+
-+ if (!sg_miter_next(&host->sg_miter)) {
-+ host->data->error = -EINVAL;
-+ break;
-+ }
-
- len = min(host->sg_miter.length, blksize);
-- BUG_ON(len % 4);
-+ if (len % 4) {
-+ host->data->error = -EINVAL;
-+ break;
-+ }
-
- blksize -= len;
- host->sg_miter.consumed = len;
-
-- buf = host->sg_miter.addr;
-+ buf = (u32 *)host->sg_miter.addr;
-
-- while (len) {
-- if (!data_transfer_wait(host))
-- break;
-+ copy_words = len/4;
-+
-+ while (copy_words) {
-+ int burst_words, words;
-+ u32 edm;
-+
-+ burst_words = SDDATA_FIFO_PIO_BURST;
-+ if (burst_words > copy_words)
-+ burst_words = copy_words;
-+ edm = bcm2835_sdhost_read(host, SDEDM);
-+ words = SDDATA_FIFO_WORDS - ((edm >> 4) & 0x1f);
-+
-+ if (words < burst_words) {
-+ int fsm_state = (edm & SDEDM_FSM_MASK);
-+ if ((fsm_state != SDEDM_FSM_WRITEDATA) &&
-+ (fsm_state != SDEDM_FSM_WRITESTART1) &&
-+ (fsm_state != SDEDM_FSM_WRITESTART2)) {
-+ hsts = bcm2835_sdhost_read(host,
-+ SDHSTS);
-+ pr_err("%s: fsm %x, hsts %x\n",
-+ mmc_hostname(host->mmc),
-+ fsm_state, hsts);
-+ if (hsts & SDHSTS_ERROR_MASK)
-+ break;
-+ }
-
-- bcm2835_sdhost_write(host, *(buf++), SDDATA);
-- len -= 4;
-+ if (time_after(jiffies, wait_max)) {
-+ pr_err("%s: PIO write timeout - EDM %x\n",
-+ mmc_hostname(host->mmc),
-+ edm);
-+ hsts = SDHSTS_REW_TIME_OUT;
-+ break;
-+ }
-+ ndelay((burst_words - words) *
-+ host->ns_per_fifo_word);
-+ continue;
-+ } else if (words > copy_words) {
-+ words = copy_words;
-+ }
-+
-+ copy_words -= words;
-+
-+ while (words) {
-+ bcm2835_sdhost_write(host, *(buf++), SDDATA);
-+ words--;
-+ }
- }
-
-- if (host->data->error)
-+ if (hsts & SDHSTS_ERROR_MASK)
- break;
- }
-
-@@ -566,12 +728,12 @@ static void bcm2835_sdhost_write_block_p
- local_irq_restore(flags);
- }
-
--
- static void bcm2835_sdhost_transfer_pio(struct bcm2835_host *host)
- {
- u32 sdhsts;
- bool is_read;
- BUG_ON(!host->data);
-+ log_event("XFP<", (u32)host->data, host->blocks);
-
- is_read = (host->data->flags & MMC_DATA_READ) != 0;
- if (is_read)
-@@ -595,28 +757,21 @@ static void bcm2835_sdhost_transfer_pio(
- is_read ? "read" : "write",
- sdhsts);
- host->data->error = -ETIMEDOUT;
-- } else if (!is_read && !host->data->error) {
-- /* Start a timer in case a transfer error occurs because
-- there is no error interrupt */
-- mod_timer(&host->pio_timer, jiffies + host->pio_timeout);
- }
-+ log_event("XFP>", (u32)host->data, host->blocks);
- }
-
--
--static void bcm2835_sdhost_transfer_dma(struct bcm2835_host *host)
-+static void bcm2835_sdhost_prepare_dma(struct bcm2835_host *host,
-+ struct mmc_data *data)
- {
-- u32 len, dir_data, dir_slave;
-+ int len, dir_data, dir_slave;
- struct dma_async_tx_descriptor *desc = NULL;
- struct dma_chan *dma_chan;
-
-- pr_debug("bcm2835_sdhost_transfer_dma()\n");
--
-- WARN_ON(!host->data);
-+ log_event("PRD<", (u32)data, 0);
-+ pr_debug("bcm2835_sdhost_prepare_dma()\n");
-
-- if (!host->data)
-- return;
--
-- if (host->data->flags & MMC_DATA_READ) {
-+ if (data->flags & MMC_DATA_READ) {
- dma_chan = host->dma_chan_rx;
- dir_data = DMA_FROM_DEVICE;
- dir_slave = DMA_DEV_TO_MEM;
-@@ -625,35 +780,71 @@ static void bcm2835_sdhost_transfer_dma(
- dir_data = DMA_TO_DEVICE;
- dir_slave = DMA_MEM_TO_DEV;
- }
-+ log_event("PRD1", (u32)dma_chan, 0);
-
- BUG_ON(!dma_chan->device);
- BUG_ON(!dma_chan->device->dev);
-- BUG_ON(!host->data->sg);
-+ BUG_ON(!data->sg);
-
-- len = dma_map_sg(dma_chan->device->dev, host->data->sg,
-- host->data->sg_len, dir_data);
-- if (len > 0) {
-- desc = dmaengine_prep_slave_sg(dma_chan, host->data->sg,
-+ /* The block doesn't manage the FIFO DREQs properly for multi-block
-+ transfers, so don't attempt to DMA the final few words.
-+ Unfortunately this requires the final sg entry to be trimmed.
-+ N.B. This code demands that the overspill is contained in
-+ a single sg entry.
-+ */
-+
-+ host->drain_words = 0;
-+ if ((data->blocks > 1) && (dir_data == DMA_FROM_DEVICE)) {
-+ struct scatterlist *sg;
-+ u32 len;
-+ int i;
-+
-+ len = min((u32)(FIFO_READ_THRESHOLD - 1) * 4,
-+ (u32)data->blocks * data->blksz);
-+
-+ for_each_sg(data->sg, sg, data->sg_len, i) {
-+ if (sg_is_last(sg)) {
-+ BUG_ON(sg->length < len);
-+ sg->length -= len;
-+ host->drain_page = (struct page *)sg->page_link;
-+ host->drain_offset = sg->offset + sg->length;
-+ }
-+ }
-+ host->drain_words = len/4;
-+ }
-+
-+ len = dma_map_sg(dma_chan->device->dev, data->sg, data->sg_len,
-+ dir_data);
-+
-+ log_event("PRD2", len, 0);
-+ if (len > 0)
-+ desc = dmaengine_prep_slave_sg(dma_chan, data->sg,
- len, dir_slave,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-- } else {
-- dev_err(mmc_dev(host->mmc), "dma_map_sg returned zero length\n");
-- }
-+ log_event("PRD3", (u32)desc, 0);
-+
- if (desc) {
- desc->callback = bcm2835_sdhost_dma_complete;
- desc->callback_param = host;
-- dmaengine_submit(desc);
-- dma_async_issue_pending(dma_chan);
-+ host->dma_desc = desc;
-+ host->dma_chan = dma_chan;
-+ host->dma_dir = dir_data;
- }
--
-+ log_event("PDM>", (u32)data, 0);
- }
-
-+static void bcm2835_sdhost_start_dma(struct bcm2835_host *host)
-+{
-+ log_event("SDMA", (u32)host->data, (u32)host->dma_chan);
-+ dmaengine_submit(host->dma_desc);
-+ dma_async_issue_pending(host->dma_chan);
-+}
-
- static void bcm2835_sdhost_set_transfer_irqs(struct bcm2835_host *host)
- {
- u32 all_irqs = SDHCFG_DATA_IRPT_EN | SDHCFG_BLOCK_IRPT_EN |
- SDHCFG_BUSY_IRPT_EN;
-- if (host->use_dma)
-+ if (host->dma_desc)
- host->hcfg = (host->hcfg & ~all_irqs) |
- SDHCFG_BUSY_IRPT_EN;
- else
-@@ -664,13 +855,13 @@ static void bcm2835_sdhost_set_transfer_
- bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
- }
-
--
- static void bcm2835_sdhost_prepare_data(struct bcm2835_host *host, struct mmc_command *cmd)
- {
- struct mmc_data *data = cmd->data;
-
- WARN_ON(host->data);
-
-+ host->data = data;
- if (!data)
- return;
-
-@@ -679,46 +870,19 @@ static void bcm2835_sdhost_prepare_data(
- BUG_ON(data->blksz > host->mmc->max_blk_size);
- BUG_ON(data->blocks > 65535);
-
-- host->data = data;
- host->data_complete = 0;
- host->flush_fifo = 0;
- host->data->bytes_xfered = 0;
-
-- if (!host->sectors && host->mmc->card && !(host->debug_flags & 1))
-- {
-- struct mmc_card *card = host->mmc->card;
-- if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
-- /*
-- * The EXT_CSD sector count is in number of 512 byte
-- * sectors.
-- */
-- host->sectors = card->ext_csd.sectors;
-- pr_err("%s: using ext_csd!\n", mmc_hostname(host->mmc));
-- } else {
-- /*
-- * The CSD capacity field is in units of read_blkbits.
-- * set_capacity takes units of 512 bytes.
-- */
-- host->sectors = card->csd.capacity <<
-- (card->csd.read_blkbits - 9);
-- }
-- host->single_read_sectors[0] = host->sectors - 65;
-- host->single_read_sectors[1] = host->sectors - 64;
-- host->single_read_sectors[2] = host->sectors - 33;
-- host->single_read_sectors[3] = host->sectors - 32;
-- host->single_read_sectors[4] = host->sectors - 1;
-- host->single_read_sectors[5] = ~0; /* Safety net */
-- }
-
-- host->use_dma = host->have_dma && (data->blocks > host->pio_limit);
-- if (!host->use_dma) {
-+ if (!host->dma_desc) {
-+ /* Use PIO */
- int flags;
-
-- flags = SG_MITER_ATOMIC;
- if (data->flags & MMC_DATA_READ)
-- flags |= SG_MITER_TO_SG;
-+ flags = SG_MITER_TO_SG;
- else
-- flags |= SG_MITER_FROM_SG;
-+ flags = SG_MITER_FROM_SG;
- sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
- host->blocks = data->blocks;
- }
-@@ -726,19 +890,20 @@ static void bcm2835_sdhost_prepare_data(
- bcm2835_sdhost_set_transfer_irqs(host);
-
- bcm2835_sdhost_write(host, data->blksz, SDHBCT);
-- bcm2835_sdhost_write(host, host->use_dma ? data->blocks : 0, SDHBLC);
-+ bcm2835_sdhost_write(host, data->blocks, SDHBLC);
-
- BUG_ON(!host->data);
- }
-
--
--void bcm2835_sdhost_send_command(struct bcm2835_host *host, struct mmc_command *cmd)
-+bool bcm2835_sdhost_send_command(struct bcm2835_host *host,
-+ struct mmc_command *cmd)
- {
- u32 sdcmd, sdhsts;
- unsigned long timeout;
- int delay;
-
- WARN_ON(host->cmd);
-+ log_event("CMD<", cmd->opcode, cmd->arg);
-
- if (cmd->data)
- pr_debug("%s: send_command %d 0x%x "
-@@ -761,9 +926,9 @@ void bcm2835_sdhost_send_command(struct
- pr_err("%s: previous command never completed.\n",
- mmc_hostname(host->mmc));
- bcm2835_sdhost_dumpregs(host);
-- cmd->error = -EIO;
-+ cmd->error = -EILSEQ;
- tasklet_schedule(&host->finish_tasklet);
-- return;
-+ return false;
- }
- timeout--;
- udelay(10);
-@@ -791,23 +956,24 @@ void bcm2835_sdhost_send_command(struct
- if (sdhsts & SDHSTS_ERROR_MASK)
- bcm2835_sdhost_write(host, sdhsts, SDHSTS);
-
-- bcm2835_sdhost_prepare_data(host, cmd);
--
-- bcm2835_sdhost_write(host, cmd->arg, SDARG);
--
- if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
- pr_err("%s: unsupported response type!\n",
- mmc_hostname(host->mmc));
- cmd->error = -EINVAL;
- tasklet_schedule(&host->finish_tasklet);
-- return;
-+ return false;
- }
-
-+ bcm2835_sdhost_prepare_data(host, cmd);
-+
-+ bcm2835_sdhost_write(host, cmd->arg, SDARG);
-+
- sdcmd = cmd->opcode & SDCMD_CMD_MASK;
-
-- if (!(cmd->flags & MMC_RSP_PRESENT))
-+ host->use_busy = 0;
-+ if (!(cmd->flags & MMC_RSP_PRESENT)) {
- sdcmd |= SDCMD_NO_RESPONSE;
-- else {
-+ } else {
- if (cmd->flags & MMC_RSP_136)
- sdcmd |= SDCMD_LONG_RESPONSE;
- if (cmd->flags & MMC_RSP_BUSY) {
-@@ -817,6 +983,7 @@ void bcm2835_sdhost_send_command(struct
- }
-
- if (cmd->data) {
-+ log_event("CMDD", cmd->data->blocks, cmd->data->blksz);
- if (host->delay_after_stop) {
- struct timeval now;
- int time_since_stop;
-@@ -839,10 +1006,12 @@ void bcm2835_sdhost_send_command(struct
- }
-
- bcm2835_sdhost_write(host, sdcmd | SDCMD_NEW_FLAG, SDCMD);
--}
-
-+ return true;
-+}
-
--static void bcm2835_sdhost_finish_command(struct bcm2835_host *host);
-+static void bcm2835_sdhost_finish_command(struct bcm2835_host *host,
-+ unsigned long *irq_flags);
- static void bcm2835_sdhost_transfer_complete(struct bcm2835_host *host);
-
- static void bcm2835_sdhost_finish_data(struct bcm2835_host *host)
-@@ -852,6 +1021,7 @@ static void bcm2835_sdhost_finish_data(s
- data = host->data;
- BUG_ON(!data);
-
-+ log_event("FDA<", (u32)host->mrq, (u32)host->cmd);
- pr_debug("finish_data(error %d, stop %d, sbc %d)\n",
- data->error, data->stop ? 1 : 0,
- host->mrq->sbc ? 1 : 0);
-@@ -859,10 +1029,7 @@ static void bcm2835_sdhost_finish_data(s
- host->hcfg &= ~(SDHCFG_DATA_IRPT_EN | SDHCFG_BLOCK_IRPT_EN);
- bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
-
-- if (data->error) {
-- data->bytes_xfered = 0;
-- } else
-- data->bytes_xfered = data->blksz * data->blocks;
-+ data->bytes_xfered = data->error ? 0 : (data->blksz * data->blocks);
-
- host->data_complete = 1;
-
-@@ -877,9 +1044,9 @@ static void bcm2835_sdhost_finish_data(s
- }
- else
- bcm2835_sdhost_transfer_complete(host);
-+ log_event("FDA>", (u32)host->mrq, (u32)host->cmd);
- }
-
--
- static void bcm2835_sdhost_transfer_complete(struct bcm2835_host *host)
- {
- struct mmc_data *data;
-@@ -891,6 +1058,7 @@ static void bcm2835_sdhost_transfer_comp
- data = host->data;
- host->data = NULL;
-
-+ log_event("TCM<", (u32)data, data->error);
- pr_debug("transfer_complete(error %d, stop %d)\n",
- data->error, data->stop ? 1 : 0);
-
-@@ -899,88 +1067,114 @@ static void bcm2835_sdhost_transfer_comp
- * a) open-ended multiblock transfer (no CMD23)
- * b) error in multiblock transfer
- */
-- if (data->stop &&
-- (data->error ||
-- !host->mrq->sbc)) {
-- host->flush_fifo = 1;
-- bcm2835_sdhost_send_command(host, data->stop);
-- if (host->delay_after_stop)
-- do_gettimeofday(&host->stop_time);
-- if (!host->use_busy)
-- bcm2835_sdhost_finish_command(host);
-+ if (host->mrq->stop && (data->error || !host->use_sbc)) {
-+ if (bcm2835_sdhost_send_command(host, host->mrq->stop)) {
-+ /* No busy, so poll for completion */
-+ if (!host->use_busy)
-+ bcm2835_sdhost_finish_command(host, NULL);
-+
-+ if (host->delay_after_stop)
-+ do_gettimeofday(&host->stop_time);
-+ }
- } else {
-+ bcm2835_sdhost_wait_transfer_complete(host);
- tasklet_schedule(&host->finish_tasklet);
- }
-+ log_event("TCM>", (u32)data, 0);
- }
-
--static void bcm2835_sdhost_finish_command(struct bcm2835_host *host)
-+/* If irq_flags is valid, the caller is in a thread context and is allowed
-+ to sleep */
-+static void bcm2835_sdhost_finish_command(struct bcm2835_host *host,
-+ unsigned long *irq_flags)
- {
- u32 sdcmd;
-- unsigned long timeout;
-+ u32 retries;
- #ifdef DEBUG
- struct timeval before, after;
- int timediff = 0;
- #endif
-
-+ log_event("FCM<", (u32)host->mrq, (u32)host->cmd);
- pr_debug("finish_command(%x)\n", bcm2835_sdhost_read(host, SDCMD));
-
- BUG_ON(!host->cmd || !host->mrq);
-
--#ifdef DEBUG
-- do_gettimeofday(&before);
--#endif
-- /* Wait max 100 ms */
-- timeout = 10000;
-+ /* Poll quickly at first */
-+
-+ retries = host->cmd_quick_poll_retries;
-+ if (!retries) {
-+ /* Work out how many polls take 1us by timing 10us */
-+ struct timeval start, now;
-+ int us_diff;
-+
-+ retries = 1;
-+ do {
-+ int i;
-+
-+ retries *= 2;
-+
-+ do_gettimeofday(&start);
-+
-+ for (i = 0; i < retries; i++) {
-+ cpu_relax();
-+ sdcmd = bcm2835_sdhost_read(host, SDCMD);
-+ }
-+
-+ do_gettimeofday(&now);
-+ us_diff = (now.tv_sec - start.tv_sec) * 1000000 +
-+ (now.tv_usec - start.tv_usec);
-+ } while (us_diff < 10);
-+
-+ host->cmd_quick_poll_retries = ((retries * us_diff + 9)*CMD_DALLY_US)/10 + 1;
-+ retries = 1; // We've already waited long enough this time
-+ }
-+
-+ retries = host->cmd_quick_poll_retries;
- for (sdcmd = bcm2835_sdhost_read(host, SDCMD);
-- (sdcmd & SDCMD_NEW_FLAG) && timeout;
-- timeout--) {
-- if (host->flush_fifo) {
-- while (bcm2835_sdhost_read(host, SDHSTS) &
-- SDHSTS_DATA_FLAG)
-- (void)bcm2835_sdhost_read(host, SDDATA);
-- }
-- udelay(10);
-+ (sdcmd & SDCMD_NEW_FLAG) && !(sdcmd & SDCMD_FAIL_FLAG) && retries;
-+ retries--) {
-+ cpu_relax();
- sdcmd = bcm2835_sdhost_read(host, SDCMD);
- }
--#ifdef DEBUG
-- do_gettimeofday(&after);
-- timediff = (after.tv_sec - before.tv_sec)*1000000 +
-- (after.tv_usec - before.tv_usec);
-
-- pr_debug(" finish_command - waited %dus\n", timediff);
--#endif
-+ if (!retries) {
-+ unsigned long wait_max;
-+
-+ if (!irq_flags) {
-+ /* Schedule the work */
-+ log_event("CWWQ", 0, 0);
-+ schedule_work(&host->cmd_wait_wq);
-+ return;
-+ }
-+
-+ /* Wait max 100 ms */
-+ wait_max = jiffies + msecs_to_jiffies(100);
-+ while (time_before(jiffies, wait_max)) {
-+ spin_unlock_irqrestore(&host->lock, *irq_flags);
-+ usleep_range(1, 10);
-+ spin_lock_irqsave(&host->lock, *irq_flags);
-+ sdcmd = bcm2835_sdhost_read(host, SDCMD);
-+ if (!(sdcmd & SDCMD_NEW_FLAG) ||
-+ (sdcmd & SDCMD_FAIL_FLAG))
-+ break;
-+ }
-+ }
-
-- if (timeout == 0) {
-+ /* Check for errors */
-+ if (sdcmd & SDCMD_NEW_FLAG) {
- pr_err("%s: command never completed.\n",
- mmc_hostname(host->mmc));
- bcm2835_sdhost_dumpregs(host);
- host->cmd->error = -EIO;
- tasklet_schedule(&host->finish_tasklet);
- return;
-- }
--
-- if (host->flush_fifo) {
-- for (timeout = 100;
-- (bcm2835_sdhost_read(host, SDHSTS) & SDHSTS_DATA_FLAG) && timeout;
-- timeout--) {
-- (void)bcm2835_sdhost_read(host, SDDATA);
-- }
-- host->flush_fifo = 0;
-- if (timeout == 0) {
-- pr_err("%s: FIFO never drained.\n",
-- mmc_hostname(host->mmc));
-- bcm2835_sdhost_dumpregs(host);
-- host->cmd->error = -EIO;
-- tasklet_schedule(&host->finish_tasklet);
-- return;
-- }
-- }
--
-- /* Check for errors */
-- if (sdcmd & SDCMD_FAIL_FLAG)
-- {
-+ } else if (sdcmd & SDCMD_FAIL_FLAG) {
- u32 sdhsts = bcm2835_sdhost_read(host, SDHSTS);
-
-+ /* Clear the errors */
-+ bcm2835_sdhost_write(host, SDHSTS_ERROR_MASK, SDHSTS);
-+
- if (host->debug)
- pr_info("%s: error detected - CMD %x, HSTS %03x, EDM %x\n",
- mmc_hostname(host->mmc), sdcmd, sdhsts,
-@@ -1003,7 +1197,7 @@ static void bcm2835_sdhost_finish_comman
- mmc_hostname(host->mmc),
- host->cmd->opcode);
- bcm2835_sdhost_dumpregs(host);
-- host->cmd->error = -EIO;
-+ host->cmd->error = -EILSEQ;
- }
- tasklet_schedule(&host->finish_tasklet);
- return;
-@@ -1018,31 +1212,31 @@ static void bcm2835_sdhost_finish_comman
- pr_debug("%s: finish_command %08x %08x %08x %08x\n",
- mmc_hostname(host->mmc),
- host->cmd->resp[0], host->cmd->resp[1], host->cmd->resp[2], host->cmd->resp[3]);
-+ log_event("RSP ", host->cmd->resp[0], host->cmd->resp[1]);
- } else {
- host->cmd->resp[0] = bcm2835_sdhost_read(host, SDRSP0);
- pr_debug("%s: finish_command %08x\n",
- mmc_hostname(host->mmc),
- host->cmd->resp[0]);
-+ log_event("RSP ", host->cmd->resp[0], 0);
- }
- }
-
-- host->cmd->error = 0;
--
- if (host->cmd == host->mrq->sbc) {
- /* Finished CMD23, now send actual command. */
- host->cmd = NULL;
-- bcm2835_sdhost_send_command(host, host->mrq->cmd);
-+ if (bcm2835_sdhost_send_command(host, host->mrq->cmd)) {
-+ if (host->data && host->dma_desc)
-+ /* DMA transfer starts now, PIO starts after irq */
-+ bcm2835_sdhost_start_dma(host);
-
-- if (host->cmd->data && host->use_dma)
-- /* DMA transfer starts now, PIO starts after irq */
-- bcm2835_sdhost_transfer_dma(host);
--
-- if (!host->use_busy)
-- bcm2835_sdhost_finish_command(host);
-- } else if (host->cmd == host->mrq->stop)
-+ if (!host->use_busy)
-+ bcm2835_sdhost_finish_command(host, NULL);
-+ }
-+ } else if (host->cmd == host->mrq->stop) {
- /* Finished CMD12 */
- tasklet_schedule(&host->finish_tasklet);
-- else {
-+ } else {
- /* Processed actual command. */
- host->cmd = NULL;
- if (!host->data)
-@@ -1050,6 +1244,7 @@ static void bcm2835_sdhost_finish_comman
- else if (host->data_complete)
- bcm2835_sdhost_transfer_complete(host);
- }
-+ log_event("FCM>", (u32)host->mrq, (u32)host->cmd);
- }
-
- static void bcm2835_sdhost_timeout(unsigned long data)
-@@ -1060,10 +1255,12 @@ static void bcm2835_sdhost_timeout(unsig
- host = (struct bcm2835_host *)data;
-
- spin_lock_irqsave(&host->lock, flags);
-+ log_event("TIM<", 0, 0);
-
- if (host->mrq) {
- pr_err("%s: timeout waiting for hardware interrupt.\n",
- mmc_hostname(host->mmc));
-+ log_dump();
- bcm2835_sdhost_dumpregs(host);
-
- if (host->data) {
-@@ -1084,74 +1281,15 @@ static void bcm2835_sdhost_timeout(unsig
- spin_unlock_irqrestore(&host->lock, flags);
- }
-
--static void bcm2835_sdhost_pio_timeout(unsigned long data)
--{
-- struct bcm2835_host *host;
-- unsigned long flags;
--
-- host = (struct bcm2835_host *)data;
--
-- spin_lock_irqsave(&host->lock, flags);
--
-- if (host->data) {
-- u32 sdhsts = bcm2835_sdhost_read(host, SDHSTS);
--
-- if (sdhsts & SDHSTS_REW_TIME_OUT) {
-- pr_err("%s: transfer timeout\n",
-- mmc_hostname(host->mmc));
-- if (host->debug)
-- bcm2835_sdhost_dumpregs(host);
-- } else {
-- pr_err("%s: unexpected transfer timeout\n",
-- mmc_hostname(host->mmc));
-- bcm2835_sdhost_dumpregs(host);
-- }
--
-- bcm2835_sdhost_write(host, SDHSTS_TRANSFER_ERROR_MASK,
-- SDHSTS);
--
-- host->data->error = -ETIMEDOUT;
--
-- bcm2835_sdhost_finish_data(host);
-- }
--
-- mmiowb();
-- spin_unlock_irqrestore(&host->lock, flags);
--}
--
--static void bcm2835_sdhost_enable_sdio_irq_nolock(struct bcm2835_host *host, int enable)
--{
-- if (enable)
-- host->hcfg |= SDHCFG_SDIO_IRPT_EN;
-- else
-- host->hcfg &= ~SDHCFG_SDIO_IRPT_EN;
-- bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
-- mmiowb();
--}
--
--static void bcm2835_sdhost_enable_sdio_irq(struct mmc_host *mmc, int enable)
--{
-- struct bcm2835_host *host = mmc_priv(mmc);
-- unsigned long flags;
--
-- pr_debug("%s: enable_sdio_irq(%d)\n", mmc_hostname(mmc), enable);
-- spin_lock_irqsave(&host->lock, flags);
-- bcm2835_sdhost_enable_sdio_irq_nolock(host, enable);
-- spin_unlock_irqrestore(&host->lock, flags);
--}
--
--static u32 bcm2835_sdhost_busy_irq(struct bcm2835_host *host, u32 intmask)
-+static void bcm2835_sdhost_busy_irq(struct bcm2835_host *host, u32 intmask)
- {
-- const u32 handled = (SDHSTS_REW_TIME_OUT | SDHSTS_CMD_TIME_OUT |
-- SDHSTS_CRC16_ERROR | SDHSTS_CRC7_ERROR |
-- SDHSTS_FIFO_ERROR);
--
-+ log_event("IRQB", (u32)host->cmd, intmask);
- if (!host->cmd) {
- pr_err("%s: got command busy interrupt 0x%08x even "
- "though no command operation was in progress.\n",
- mmc_hostname(host->mmc), (unsigned)intmask);
- bcm2835_sdhost_dumpregs(host);
-- return 0;
-+ return;
- }
-
- if (!host->use_busy) {
-@@ -1159,7 +1297,7 @@ static u32 bcm2835_sdhost_busy_irq(struc
- "though not expecting one.\n",
- mmc_hostname(host->mmc), (unsigned)intmask);
- bcm2835_sdhost_dumpregs(host);
-- return 0;
-+ return;
- }
- host->use_busy = 0;
-
-@@ -1182,28 +1320,23 @@ static u32 bcm2835_sdhost_busy_irq(struc
- } else if (intmask & SDHSTS_CMD_TIME_OUT)
- host->cmd->error = -ETIMEDOUT;
-
-+ log_dump();
- bcm2835_sdhost_dumpregs(host);
-- tasklet_schedule(&host->finish_tasklet);
- }
- else
-- bcm2835_sdhost_finish_command(host);
--
-- return handled;
-+ bcm2835_sdhost_finish_command(host, NULL);
- }
-
--static u32 bcm2835_sdhost_data_irq(struct bcm2835_host *host, u32 intmask)
-+static void bcm2835_sdhost_data_irq(struct bcm2835_host *host, u32 intmask)
- {
-- const u32 handled = (SDHSTS_REW_TIME_OUT |
-- SDHSTS_CRC16_ERROR |
-- SDHSTS_FIFO_ERROR);
--
- /* There are no dedicated data/space available interrupt
- status bits, so it is necessary to use the single shared
- data/space available FIFO status bits. It is therefore not
- an error to get here when there is no data transfer in
- progress. */
-+ log_event("IRQD", (u32)host->data, intmask);
- if (!host->data)
-- return 0;
-+ return;
-
- if (intmask & (SDHSTS_CRC16_ERROR |
- SDHSTS_FIFO_ERROR |
-@@ -1214,46 +1347,37 @@ static u32 bcm2835_sdhost_data_irq(struc
- else
- host->data->error = -ETIMEDOUT;
-
-- bcm2835_sdhost_dumpregs(host);
-- tasklet_schedule(&host->finish_tasklet);
-- return handled;
-+ if (host->debug) {
-+ log_dump();
-+ bcm2835_sdhost_dumpregs(host);
-+ }
- }
-
-- /* Use the block interrupt for writes after the first block */
-- if (host->data->flags & MMC_DATA_WRITE) {
-+ if (host->data->error) {
-+ bcm2835_sdhost_finish_data(host);
-+ } else if (host->data->flags & MMC_DATA_WRITE) {
-+ /* Use the block interrupt for writes after the first block */
- host->hcfg &= ~(SDHCFG_DATA_IRPT_EN);
- host->hcfg |= SDHCFG_BLOCK_IRPT_EN;
- bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
-- if (host->data->error)
-- bcm2835_sdhost_finish_data(host);
-- else
-- bcm2835_sdhost_transfer_pio(host);
-+ bcm2835_sdhost_transfer_pio(host);
- } else {
-- if (!host->data->error) {
-- bcm2835_sdhost_transfer_pio(host);
-- host->blocks--;
-- }
-+ bcm2835_sdhost_transfer_pio(host);
-+ host->blocks--;
- if ((host->blocks == 0) || host->data->error)
- bcm2835_sdhost_finish_data(host);
- }
--
-- return handled;
- }
-
--static u32 bcm2835_sdhost_block_irq(struct bcm2835_host *host, u32 intmask)
-+static void bcm2835_sdhost_block_irq(struct bcm2835_host *host, u32 intmask)
- {
-- struct dma_chan *dma_chan;
-- u32 dir_data;
-- const u32 handled = (SDHSTS_REW_TIME_OUT |
-- SDHSTS_CRC16_ERROR |
-- SDHSTS_FIFO_ERROR);
--
-+ log_event("IRQK", (u32)host->data, intmask);
- if (!host->data) {
- pr_err("%s: got block interrupt 0x%08x even "
- "though no data operation was in progress.\n",
- mmc_hostname(host->mmc), (unsigned)intmask);
- bcm2835_sdhost_dumpregs(host);
-- return handled;
-+ return;
- }
-
- if (intmask & (SDHSTS_CRC16_ERROR |
-@@ -1265,149 +1389,69 @@ static u32 bcm2835_sdhost_block_irq(stru
- else
- host->data->error = -ETIMEDOUT;
-
-- if (host->debug)
-+ if (host->debug) {
-+ log_dump();
- bcm2835_sdhost_dumpregs(host);
-- tasklet_schedule(&host->finish_tasklet);
-- return handled;
-+ }
- }
-
-- if (!host->use_dma) {
-+ if (!host->dma_desc) {
- BUG_ON(!host->blocks);
-- host->blocks--;
-- if ((host->blocks == 0) || host->data->error) {
-- /* Cancel the timer */
-- del_timer(&host->pio_timer);
--
-+ if (host->data->error || (--host->blocks == 0)) {
- bcm2835_sdhost_finish_data(host);
- } else {
-- /* Reset the timer */
-- mod_timer(&host->pio_timer,
-- jiffies + host->pio_timeout);
--
- bcm2835_sdhost_transfer_pio(host);
--
-- /* Reset the timer */
-- mod_timer(&host->pio_timer,
-- jiffies + host->pio_timeout);
- }
- } else if (host->data->flags & MMC_DATA_WRITE) {
-- dma_chan = host->dma_chan_tx;
-- dir_data = DMA_TO_DEVICE;
-- dma_unmap_sg(dma_chan->device->dev,
-- host->data->sg, host->data->sg_len,
-- dir_data);
--
- bcm2835_sdhost_finish_data(host);
- }
--
-- return handled;
- }
-
--
- static irqreturn_t bcm2835_sdhost_irq(int irq, void *dev_id)
- {
- irqreturn_t result = IRQ_NONE;
- struct bcm2835_host *host = dev_id;
-- u32 unexpected = 0, early = 0;
-- int loops = 0;
-+ u32 intmask;
-
- spin_lock(&host->lock);
-
-- for (loops = 0; loops < 1; loops++) {
-- u32 intmask, handled;
--
-- intmask = bcm2835_sdhost_read(host, SDHSTS);
-- handled = intmask & (SDHSTS_BUSY_IRPT |
-- SDHSTS_BLOCK_IRPT |
-- SDHSTS_SDIO_IRPT |
-- SDHSTS_DATA_FLAG);
-- if ((handled == SDHSTS_DATA_FLAG) &&
-- (loops == 0) && !host->data) {
-- pr_err("%s: sdhost_irq data interrupt 0x%08x even "
-- "though no data operation was in progress.\n",
-- mmc_hostname(host->mmc),
-- (unsigned)intmask);
--
-- bcm2835_sdhost_dumpregs(host);
-- }
--
-- if (!handled)
-- break;
-+ intmask = bcm2835_sdhost_read(host, SDHSTS);
-+ log_event("IRQ<", intmask, 0);
-
-- if (loops)
-- early |= handled;
-+ bcm2835_sdhost_write(host,
-+ SDHSTS_BUSY_IRPT |
-+ SDHSTS_BLOCK_IRPT |
-+ SDHSTS_SDIO_IRPT |
-+ SDHSTS_DATA_FLAG,
-+ SDHSTS);
-
-+ if (intmask & SDHSTS_BLOCK_IRPT) {
-+ bcm2835_sdhost_block_irq(host, intmask);
- result = IRQ_HANDLED;
-+ }
-
-- /* Clear all interrupts and notifications */
-- bcm2835_sdhost_write(host, intmask, SDHSTS);
--
-- if (intmask & SDHSTS_BUSY_IRPT)
-- handled |= bcm2835_sdhost_busy_irq(host, intmask);
--
-- /* There is no true data interrupt status bit, so it is
-- necessary to qualify the data flag with the interrupt
-- enable bit */
-- if ((intmask & SDHSTS_DATA_FLAG) &&
-- (host->hcfg & SDHCFG_DATA_IRPT_EN))
-- handled |= bcm2835_sdhost_data_irq(host, intmask);
--
-- if (intmask & SDHSTS_BLOCK_IRPT)
-- handled |= bcm2835_sdhost_block_irq(host, intmask);
--
-- if (intmask & SDHSTS_SDIO_IRPT) {
-- bcm2835_sdhost_enable_sdio_irq_nolock(host, false);
-- host->thread_isr |= SDHSTS_SDIO_IRPT;
-- result = IRQ_WAKE_THREAD;
-- }
-+ if (intmask & SDHSTS_BUSY_IRPT) {
-+ bcm2835_sdhost_busy_irq(host, intmask);
-+ result = IRQ_HANDLED;
-+ }
-
-- unexpected |= (intmask & ~handled);
-+ /* There is no true data interrupt status bit, so it is
-+ necessary to qualify the data flag with the interrupt
-+ enable bit */
-+ if ((intmask & SDHSTS_DATA_FLAG) &&
-+ (host->hcfg & SDHCFG_DATA_IRPT_EN)) {
-+ bcm2835_sdhost_data_irq(host, intmask);
-+ result = IRQ_HANDLED;
- }
-
- mmiowb();
-
-+ log_event("IRQ>", bcm2835_sdhost_read(host, SDHSTS), 0);
- spin_unlock(&host->lock);
-
-- if (early)
-- pr_debug("%s: early %x (loops %d)\n",
-- mmc_hostname(host->mmc), early, loops);
--
-- if (unexpected) {
-- pr_err("%s: unexpected interrupt 0x%08x.\n",
-- mmc_hostname(host->mmc), unexpected);
-- bcm2835_sdhost_dumpregs(host);
-- }
--
- return result;
- }
-
--static irqreturn_t bcm2835_sdhost_thread_irq(int irq, void *dev_id)
--{
-- struct bcm2835_host *host = dev_id;
-- unsigned long flags;
-- u32 isr;
--
-- spin_lock_irqsave(&host->lock, flags);
-- isr = host->thread_isr;
-- host->thread_isr = 0;
-- spin_unlock_irqrestore(&host->lock, flags);
--
-- if (isr & SDHSTS_SDIO_IRPT) {
-- sdio_run_irqs(host->mmc);
--
--/* Is this necessary? Why re-enable an interrupt which is enabled?
-- spin_lock_irqsave(&host->lock, flags);
-- if (host->flags & SDHSTS_SDIO_IRPT_ENABLED)
-- bcm2835_sdhost_enable_sdio_irq_nolock(host, true);
-- spin_unlock_irqrestore(&host->lock, flags);
--*/
-- }
--
-- return isr ? IRQ_HANDLED : IRQ_NONE;
--}
--
--
--
- void bcm2835_sdhost_set_clock(struct bcm2835_host *host, unsigned int clock)
- {
- int div = 0; /* Initialized for compiler warning */
-@@ -1417,9 +1461,8 @@ void bcm2835_sdhost_set_clock(struct bcm
- pr_info("%s: set_clock(%d)\n", mmc_hostname(host->mmc), clock);
-
- if ((host->overclock_50 > 50) &&
-- (clock == 50*MHZ)) {
-+ (clock == 50*MHZ))
- clock = host->overclock_50 * MHZ + (MHZ - 1);
-- }
-
- /* The SDCDIV register has 11 bits, and holds (div - 2).
- But in data mode the max is 50MHz wihout a minimum, and only the
-@@ -1466,6 +1509,11 @@ void bcm2835_sdhost_set_clock(struct bcm
- clock = host->max_clk / (div + 2);
- host->mmc->actual_clock = clock;
-
-+ /* Calibrate some delays */
-+
-+ host->ns_per_fifo_word = (1000000000/clock) *
-+ ((host->mmc->caps & MMC_CAP_4_BIT_DATA) ? 8 : 32);
-+
- if (clock > input_clock) {
- /* Save the closest value, to make it easier
- to reduce in the event of error */
-@@ -1501,6 +1549,7 @@ static void bcm2835_sdhost_request(struc
- {
- struct bcm2835_host *host;
- unsigned long flags;
-+ u32 edm, fsm;
-
- host = mmc_priv(mmc);
-
-@@ -1521,6 +1570,8 @@ static void bcm2835_sdhost_request(struc
- }
-
- /* Reset the error statuses in case this is a retry */
-+ if (mrq->sbc)
-+ mrq->sbc->error = 0;
- if (mrq->cmd)
- mrq->cmd->error = 0;
- if (mrq->data)
-@@ -1536,28 +1587,58 @@ static void bcm2835_sdhost_request(struc
- return;
- }
-
-+ if (host->use_dma && mrq->data &&
-+ (mrq->data->blocks > host->pio_limit))
-+ bcm2835_sdhost_prepare_dma(host, mrq->data);
-+
- spin_lock_irqsave(&host->lock, flags);
-
- WARN_ON(host->mrq != NULL);
--
- host->mrq = mrq;
-
-- if (mrq->sbc)
-- bcm2835_sdhost_send_command(host, mrq->sbc);
-- else
-- bcm2835_sdhost_send_command(host, mrq->cmd);
-+ edm = bcm2835_sdhost_read(host, SDEDM);
-+ fsm = edm & SDEDM_FSM_MASK;
-
-- mmiowb();
-- spin_unlock_irqrestore(&host->lock, flags);
-+ log_event("REQ<", (u32)mrq, edm);
-+ if ((fsm != SDEDM_FSM_IDENTMODE) &&
-+ (fsm != SDEDM_FSM_DATAMODE)) {
-+ pr_err("%s: previous command (%d) not complete (EDM %x)\n",
-+ mmc_hostname(host->mmc),
-+ bcm2835_sdhost_read(host, SDCMD) & SDCMD_CMD_MASK,
-+ edm);
-+ log_event("REQ!", (u32)mrq, edm);
-+ log_dump();
-+ bcm2835_sdhost_dumpregs(host);
-+ mrq->cmd->error = -EILSEQ;
-+ tasklet_schedule(&host->finish_tasklet);
-+ mmiowb();
-+ spin_unlock_irqrestore(&host->lock, flags);
-+ return;
-+ }
-+
-+ host->use_sbc = !!mrq->sbc &&
-+ (host->mrq->data->flags & USE_CMD23_FLAGS);
-+ if (host->use_sbc) {
-+ if (bcm2835_sdhost_send_command(host, mrq->sbc)) {
-+ if (!host->use_busy)
-+ bcm2835_sdhost_finish_command(host, &flags);
-+ }
-+ } else if (bcm2835_sdhost_send_command(host, mrq->cmd)) {
-+ if (host->data && host->dma_desc)
-+ /* DMA transfer starts now, PIO starts after irq */
-+ bcm2835_sdhost_start_dma(host);
-
-- if (!mrq->sbc && mrq->cmd->data && host->use_dma)
-- /* DMA transfer starts now, PIO starts after irq */
-- bcm2835_sdhost_transfer_dma(host);
-+ if (!host->use_busy)
-+ bcm2835_sdhost_finish_command(host, &flags);
-+ }
-
-- if (!host->use_busy)
-- bcm2835_sdhost_finish_command(host);
--}
-+ log_event("CMD ", (u32)mrq->cmd->opcode,
-+ mrq->data ? (u32)mrq->data->blksz : 0);
-+ mmiowb();
-
-+ log_event("REQ>", (u32)mrq, 0);
-+ spin_unlock_irqrestore(&host->lock, flags);
-+}
-
- static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
- {
-@@ -1574,6 +1655,8 @@ static void bcm2835_sdhost_set_ios(struc
-
- spin_lock_irqsave(&host->lock, flags);
-
-+ log_event("IOS<", ios->clock, 0);
-+
- if (!ios->clock || ios->clock != host->clock) {
- bcm2835_sdhost_set_clock(host, ios->clock);
- host->clock = ios->clock;
-@@ -1596,59 +1679,53 @@ static void bcm2835_sdhost_set_ios(struc
- spin_unlock_irqrestore(&host->lock, flags);
- }
-
--static int bcm2835_sdhost_multi_io_quirk(struct mmc_card *card,
-- unsigned int direction,
-- u32 blk_pos, int blk_size)
--{
-- /* There is a bug in the host controller hardware that makes
-- reading the final sector of the card as part of a multiple read
-- problematic. Detect that case and shorten the read accordingly.
-- */
-+static struct mmc_host_ops bcm2835_sdhost_ops = {
-+ .request = bcm2835_sdhost_request,
-+ .set_ios = bcm2835_sdhost_set_ios,
-+ .hw_reset = bcm2835_sdhost_reset,
-+};
-+
-+static void bcm2835_sdhost_cmd_wait_work(struct work_struct *work)
-+{
- struct bcm2835_host *host;
-+ unsigned long flags;
-
-- host = mmc_priv(card->host);
-+ host = container_of(work, struct bcm2835_host, cmd_wait_wq);
-
-- if (!host->sectors) {
-- /* csd.capacity is in weird units - convert to sectors */
-- u32 card_sectors = (card->csd.capacity << (card->csd.read_blkbits - 9));
-- if ((direction == MMC_DATA_READ) &&
-- ((blk_pos + blk_size) == card_sectors))
-- blk_size--;
-- return blk_size;
-- }
-+ spin_lock_irqsave(&host->lock, flags);
-
-- if (direction == MMC_DATA_READ) {
-- int i;
-- int sector;
-- for (i = 0; blk_pos > (sector = host->single_read_sectors[i]); i++)
-- continue;
-+ log_event("CWK<", (u32)host->cmd, (u32)host->mrq);
-
-- if ((blk_pos + blk_size) > sector)
-- blk_size = (blk_pos == sector) ? 1 : (sector - blk_pos);
-+ /*
-+ * If this tasklet gets rescheduled while running, it will
-+ * be run again afterwards but without any active request.
-+ */
-+ if (!host->mrq) {
-+ spin_unlock_irqrestore(&host->lock, flags);
-+ return;
- }
-- return blk_size;
--}
-
-+ bcm2835_sdhost_finish_command(host, &flags);
-
--static struct mmc_host_ops bcm2835_sdhost_ops = {
-- .request = bcm2835_sdhost_request,
-- .set_ios = bcm2835_sdhost_set_ios,
-- .enable_sdio_irq = bcm2835_sdhost_enable_sdio_irq,
-- .hw_reset = bcm2835_sdhost_reset,
-- .multi_io_quirk = bcm2835_sdhost_multi_io_quirk,
--};
-+ mmiowb();
-+
-+ log_event("CWK>", (u32)host->cmd, 0);
-
-+ spin_unlock_irqrestore(&host->lock, flags);
-+}
-
- static void bcm2835_sdhost_tasklet_finish(unsigned long param)
- {
- struct bcm2835_host *host;
- unsigned long flags;
- struct mmc_request *mrq;
-+ struct dma_chan *terminate_chan = NULL;
-
- host = (struct bcm2835_host *)param;
-
- spin_lock_irqsave(&host->lock, flags);
-
-+ log_event("TSK<", (u32)host->mrq, 0);
- /*
- * If this tasklet gets rescheduled while running, it will
- * be run again afterwards but without any active request.
-@@ -1683,11 +1760,23 @@ static void bcm2835_sdhost_tasklet_finis
-
- mmiowb();
-
-+ host->dma_desc = NULL;
-+ terminate_chan = host->dma_chan;
-+ host->dma_chan = NULL;
-+
- spin_unlock_irqrestore(&host->lock, flags);
-- mmc_request_done(host->mmc, mrq);
--}
-
-+ if (terminate_chan)
-+ {
-+ int err = dmaengine_terminate_all(terminate_chan);
-+ if (err)
-+ pr_err("%s: failed to terminate DMA (%d)\n",
-+ mmc_hostname(host->mmc), err);
-+ }
-
-+ mmc_request_done(host->mmc, mrq);
-+ log_event("TSK>", (u32)mrq, 0);
-+}
-
- int bcm2835_sdhost_add_host(struct bcm2835_host *host)
- {
-@@ -1709,10 +1798,10 @@ int bcm2835_sdhost_add_host(struct bcm28
- mmc->f_max, mmc->f_min, mmc->max_busy_timeout);
-
- /* host controller capabilities */
-- mmc->caps |= /* MMC_CAP_SDIO_IRQ |*/ MMC_CAP_4_BIT_DATA |
-+ mmc->caps |=
- MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED |
- MMC_CAP_NEEDS_POLL | MMC_CAP_HW_RESET | MMC_CAP_ERASE |
-- (ALLOW_CMD23 * MMC_CAP_CMD23);
-+ ((ALLOW_CMD23_READ|ALLOW_CMD23_WRITE) * MMC_CAP_CMD23);
-
- spin_lock_init(&host->lock);
-
-@@ -1722,9 +1811,9 @@ int bcm2835_sdhost_add_host(struct bcm28
- pr_err("%s: unable to initialise DMA channels. "
- "Falling back to PIO\n",
- mmc_hostname(mmc));
-- host->have_dma = false;
-+ host->use_dma = false;
- } else {
-- host->have_dma = true;
-+ host->use_dma = true;
-
- cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-@@ -1741,7 +1830,7 @@ int bcm2835_sdhost_add_host(struct bcm28
- ret = dmaengine_slave_config(host->dma_chan_rx, &cfg);
- }
- } else {
-- host->have_dma = false;
-+ host->use_dma = false;
- }
-
- mmc->max_segs = 128;
-@@ -1756,16 +1845,15 @@ int bcm2835_sdhost_add_host(struct bcm28
- tasklet_init(&host->finish_tasklet,
- bcm2835_sdhost_tasklet_finish, (unsigned long)host);
-
-- setup_timer(&host->timer, bcm2835_sdhost_timeout,
-- (unsigned long)host);
-+ INIT_WORK(&host->cmd_wait_wq, bcm2835_sdhost_cmd_wait_work);
-
-- setup_timer(&host->pio_timer, bcm2835_sdhost_pio_timeout,
-+ setup_timer(&host->timer, bcm2835_sdhost_timeout,
- (unsigned long)host);
-
- bcm2835_sdhost_init(host, 0);
-- ret = request_threaded_irq(host->irq, bcm2835_sdhost_irq,
-- bcm2835_sdhost_thread_irq,
-- IRQF_SHARED, mmc_hostname(mmc), host);
-+
-+ ret = request_irq(host->irq, bcm2835_sdhost_irq, 0 /*IRQF_SHARED*/,
-+ mmc_hostname(mmc), host);
- if (ret) {
- pr_err("%s: failed to request IRQ %d: %d\n",
- mmc_hostname(mmc), host->irq, ret);
-@@ -1776,11 +1864,11 @@ int bcm2835_sdhost_add_host(struct bcm28
- mmc_add_host(mmc);
-
- pio_limit_string[0] = '\0';
-- if (host->have_dma && (host->pio_limit > 0))
-+ if (host->use_dma && (host->pio_limit > 0))
- sprintf(pio_limit_string, " (>%d)", host->pio_limit);
- pr_info("%s: %s loaded - DMA %s%s\n",
- mmc_hostname(mmc), DRIVER_NAME,
-- host->have_dma ? "enabled" : "disabled",
-+ host->use_dma ? "enabled" : "disabled",
- pio_limit_string);
-
- return 0;
-@@ -1810,8 +1898,11 @@ static int bcm2835_sdhost_probe(struct p
- mmc->ops = &bcm2835_sdhost_ops;
- host = mmc_priv(mmc);
- host->mmc = mmc;
-+ host->cmd_quick_poll_retries = 0;
- host->pio_timeout = msecs_to_jiffies(500);
-+ host->pio_limit = 1;
- host->max_delay = 1; /* Warn if over 1ms */
-+ host->allow_dma = 1;
- spin_lock_init(&host->lock);
-
- iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-@@ -1827,13 +1918,12 @@ static int bcm2835_sdhost_probe(struct p
- return -ENODEV;
- }
- host->bus_addr = be32_to_cpup(addr);
-+ log_init(iomem->start - host->bus_addr);
- pr_debug(" - ioaddr %lx, iomem->start %lx, bus_addr %lx\n",
- (unsigned long)host->ioaddr,
- (unsigned long)iomem->start,
- (unsigned long)host->bus_addr);
-
-- host->allow_dma = ALLOW_DMA;
--
- if (node) {
- /* Read any custom properties */
- of_property_read_u32(node,
-@@ -1845,16 +1935,17 @@ static int bcm2835_sdhost_probe(struct p
- of_property_read_u32(node,
- "brcm,pio-limit",
- &host->pio_limit);
-- host->allow_dma = ALLOW_DMA &&
-+ host->allow_dma =
- !of_property_read_bool(node, "brcm,force-pio");
- host->debug = of_property_read_bool(node, "brcm,debug");
-- of_property_read_u32(node,
-- "brcm,debug-flags",
-- &host->debug_flags);
- }
-
-- if (host->debug_flags)
-- dev_err(dev, "debug_flags=%x\n", host->debug_flags);
-+ host->dma_chan = NULL;
-+ host->dma_desc = NULL;
-+
-+ /* Formally recognise the other way of disabling DMA */
-+ if (host->pio_limit == 0x7fffffff)
-+ host->allow_dma = false;
-
- if (host->allow_dma) {
- if (node) {
-@@ -1940,15 +2031,12 @@ static int bcm2835_sdhost_remove(struct
- return 0;
- }
-
--
- static const struct of_device_id bcm2835_sdhost_match[] = {
- { .compatible = "brcm,bcm2835-sdhost" },
- { }
- };
- MODULE_DEVICE_TABLE(of, bcm2835_sdhost_match);
-
--
--
- static struct platform_driver bcm2835_sdhost_driver = {
- .probe = bcm2835_sdhost_probe,
- .remove = bcm2835_sdhost_remove,
diff --git a/target/linux/brcm2708/patches-4.4/0150-BCM270X_DT-Add-dtparams-for-the-SD-interface.patch b/target/linux/brcm2708/patches-4.4/0150-BCM270X_DT-Add-dtparams-for-the-SD-interface.patch
deleted file mode 100644
index f4f3d6cc5f..0000000000
--- a/target/linux/brcm2708/patches-4.4/0150-BCM270X_DT-Add-dtparams-for-the-SD-interface.patch
+++ /dev/null
@@ -1,235 +0,0 @@
-From d15e041e838bd735a7ed3eaa5dbff785213baf6d Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Fri, 12 Feb 2016 15:38:00 +0000
-Subject: [PATCH 150/170] BCM270X_DT: Add dtparams for the SD interface
-
-Add new base dtparams sd_overclock, sd_force_pio, sd_pio_limit
-and sd_debug.
----
- arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 4 ++++
- arch/arm/boot/dts/bcm2708-rpi-b.dts | 4 ++++
- arch/arm/boot/dts/bcm2708-rpi-cm.dts | 1 -
- arch/arm/boot/dts/bcm2708-rpi-cm.dtsi | 13 +++++++++++++
- arch/arm/boot/dts/bcm2708_common.dtsi | 2 ++
- arch/arm/boot/dts/bcm2709-rpi-2-b.dts | 4 ++++
- arch/arm/boot/dts/overlays/README | 11 ++++++++++-
- arch/arm/boot/dts/overlays/mmc-overlay.dts | 1 -
- arch/arm/boot/dts/overlays/sdhost-overlay.dts | 27 +++++++++++++-------------
- arch/arm/boot/dts/overlays/sdtweak-overlay.dts | 14 ++++++-------
- 10 files changed, 58 insertions(+), 23 deletions(-)
-
---- a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
-+++ b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
-@@ -141,5 +141,9 @@
- audio = <&audio>,"status";
- watchdog = <&watchdog>,"status";
- random = <&random>,"status";
-+ sd_overclock = <&sdhost>,"brcm,overclock-50:0";
-+ sd_force_pio = <&sdhost>,"brcm,force-pio?";
-+ sd_pio_limit = <&sdhost>,"brcm,pio-limit:0";
-+ sd_debug = <&sdhost>,"brcm,debug";
- };
- };
---- a/arch/arm/boot/dts/bcm2708-rpi-b.dts
-+++ b/arch/arm/boot/dts/bcm2708-rpi-b.dts
-@@ -131,5 +131,9 @@
- audio = <&audio>,"status";
- watchdog = <&watchdog>,"status";
- random = <&random>,"status";
-+ sd_overclock = <&sdhost>,"brcm,overclock-50:0";
-+ sd_force_pio = <&sdhost>,"brcm,force-pio?";
-+ sd_pio_limit = <&sdhost>,"brcm,pio-limit:0";
-+ sd_debug = <&sdhost>,"brcm,debug";
- };
- };
---- a/arch/arm/boot/dts/bcm2708-rpi-cm.dts
-+++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dts
-@@ -97,6 +97,5 @@
- i2c0_baudrate = <&i2c0>,"clock-frequency:0";
- i2c1_baudrate = <&i2c1>,"clock-frequency:0";
- i2c2_baudrate = <&i2c2>,"clock-frequency:0";
-- core_freq = <&clk_core>,"clock-frequency:0";
- };
- };
---- a/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi
-+++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi
-@@ -7,6 +7,13 @@
- };
- };
-
-+&gpio {
-+ sdhost_pins: sdhost_pins {
-+ brcm,pins = <48 49 50 51 52 53>;
-+ brcm,function = <4>; /* alt0 */
-+ };
-+};
-+
- &leds {
- act_led: act {
- label = "led0";
-@@ -29,6 +36,8 @@
-
- / {
- __overrides__ {
-+ core_freq = <&clk_core>,"clock-frequency:0";
-+
- act_led_gpio = <&act_led>,"gpios:4";
- act_led_activelow = <&act_led>,"gpios:8";
- act_led_trigger = <&act_led>,"linux,default-trigger";
-@@ -36,5 +45,9 @@
- audio = <&audio>,"status";
- watchdog = <&watchdog>,"status";
- random = <&random>,"status";
-+ sd_overclock = <&sdhost>,"brcm,overclock-50:0";
-+ sd_force_pio = <&sdhost>,"brcm,force-pio?";
-+ sd_pio_limit = <&sdhost>,"brcm,pio-limit:0";
-+ sd_debug = <&sdhost>,"brcm,debug";
- };
- };
---- a/arch/arm/boot/dts/bcm2708_common.dtsi
-+++ b/arch/arm/boot/dts/bcm2708_common.dtsi
-@@ -135,6 +135,7 @@
- dmas = <&dma 13>,
- <&dma 13>;
- dma-names = "tx", "rx";
-+ brcm,overclock-50 = <0>;
- brcm,pio-limit = <1>;
- status = "disabled";
- };
-@@ -203,6 +204,7 @@
- dmas = <&dma 11>,
- <&dma 11>;
- dma-names = "tx", "rx";
-+ brcm,overclock-50 = <0>;
- status = "disabled";
- };
-
---- a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts
-+++ b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts
-@@ -141,5 +141,9 @@
- audio = <&audio>,"status";
- watchdog = <&watchdog>,"status";
- random = <&random>,"status";
-+ sd_overclock = <&sdhost>,"brcm,overclock-50:0";
-+ sd_force_pio = <&sdhost>,"brcm,force-pio?";
-+ sd_pio_limit = <&sdhost>,"brcm,pio-limit:0";
-+ sd_debug = <&sdhost>,"brcm,debug";
- };
- };
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -112,6 +112,16 @@ Params:
- random Set to "on" to enable the hardware random
- number generator (default "on")
-
-+ sd_overclock Clock (in MHz) to use when the MMC framework
-+ requests 50MHz
-+
-+ sd_force_pio Disable DMA support for SD driver (default off)
-+
-+ sd_pio_limit Number of blocks above which to use DMA for
-+ SD card (default 1)
-+
-+ sd_debug Enable debug output from SD driver (default off)
-+
- uart0 Set to "off" to disable uart0 (default "on")
-
- watchdog Set to "on" to enable the hardware watchdog
-@@ -443,7 +453,6 @@ Info: Selects the bcm2835-mmc SD/MMC d
- Load: dtoverlay=mmc,<param>=<val>
- Params: overclock_50 Clock (in MHz) to use when the MMC framework
- requests 50MHz
-- force_pio Disable DMA support
-
-
- Name: mz61581
---- a/arch/arm/boot/dts/overlays/mmc-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/mmc-overlay.dts
-@@ -34,6 +34,5 @@
-
- __overrides__ {
- overclock_50 = <&frag0>,"brcm,overclock-50:0";
-- force_pio = <&frag0>,"brcm,force-pio?";
- };
- };
---- a/arch/arm/boot/dts/overlays/sdhost-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/sdhost-overlay.dts
-@@ -1,19 +1,14 @@
- /dts-v1/;
- /plugin/;
-
-+/* Provide backwards compatible aliases for the old sdhost dtparams. */
-+
- /{
- compatible = "brcm,bcm2708";
-
- fragment@0 {
-- target = <&mmc>;
-- __overlay__ {
-- status = "disabled";
-- };
-- };
--
-- fragment@1 {
- target = <&sdhost>;
-- frag1: __overlay__ {
-+ frag0: __overlay__ {
- brcm,overclock-50 = <0>;
- brcm,pio-limit = <1>;
- brcm,debug-flags = <0>;
-@@ -21,11 +16,17 @@
- };
- };
-
-+ fragment@1 {
-+ target = <&mmc>;
-+ __overlay__ {
-+ status = "disabled";
-+ };
-+ };
-+
- __overrides__ {
-- overclock_50 = <&frag1>,"brcm,overclock-50:0";
-- force_pio = <&frag1>,"brcm,force-pio?";
-- pio_limit = <&frag1>,"brcm,pio-limit:0";
-- debug = <&frag1>,"brcm,debug?";
-- debug_flags = <&frag1>,"brcm,debug-flags:0";
-+ overclock_50 = <&frag0>,"brcm,overclock-50:0";
-+ force_pio = <&frag0>,"brcm,force-pio?";
-+ pio_limit = <&frag0>,"brcm,pio-limit:0";
-+ debug = <&frag0>,"brcm,debug?";
- };
- };
---- a/arch/arm/boot/dts/overlays/sdtweak-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/sdtweak-overlay.dts
-@@ -1,23 +1,23 @@
- /dts-v1/;
- /plugin/;
-
-+/* Provide backwards compatible aliases for the old sdhost dtparams. */
-+
- /{
- compatible = "brcm,bcm2708";
-
- fragment@0 {
- target = <&sdhost>;
-- frag1: __overlay__ {
-+ frag0: __overlay__ {
- brcm,overclock-50 = <0>;
- brcm,pio-limit = <1>;
-- brcm,debug-flags = <0>;
- };
- };
-
- __overrides__ {
-- overclock_50 = <&frag1>,"brcm,overclock-50:0";
-- force_pio = <&frag1>,"brcm,force-pio?";
-- pio_limit = <&frag1>,"brcm,pio-limit:0";
-- debug = <&frag1>,"brcm,debug?";
-- debug_flags = <&frag1>,"brcm,debug-flags:0";
-+ overclock_50 = <&frag0>,"brcm,overclock-50:0";
-+ force_pio = <&frag0>,"brcm,force-pio?";
-+ pio_limit = <&frag0>,"brcm,pio-limit:0";
-+ debug = <&frag0>,"brcm,debug?";
- };
- };
diff --git a/target/linux/brcm2708/patches-4.4/0150-bcm2835-sdhost-Downgrade-log-message-status.patch b/target/linux/brcm2708/patches-4.4/0150-bcm2835-sdhost-Downgrade-log-message-status.patch
new file mode 100644
index 0000000000..73e300208c
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0150-bcm2835-sdhost-Downgrade-log-message-status.patch
@@ -0,0 +1,22 @@
+From 217ac339f2d1d1d87a706a40746b565b2605c3e9 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 19 Feb 2016 12:04:48 +0000
+Subject: [PATCH 150/381] bcm2835-sdhost: Downgrade log message status
+
+---
+ drivers/mmc/host/bcm2835-sdhost.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/mmc/host/bcm2835-sdhost.c
++++ b/drivers/mmc/host/bcm2835-sdhost.c
+@@ -232,8 +232,8 @@ static void log_init(u32 bus_to_phys)
+ sdhost_log_buf = dma_zalloc_coherent(NULL, LOG_SIZE, &sdhost_log_addr,
+ GFP_KERNEL);
+ if (sdhost_log_buf) {
+- pr_err("sdhost: log_buf @ %p (%x)\n",
+- sdhost_log_buf, sdhost_log_addr);
++ pr_info("sdhost: log_buf @ %p (%x)\n",
++ sdhost_log_buf, sdhost_log_addr);
+ timer_base = ioremap_nocache(bus_to_phys + 0x7e003000, SZ_4K);
+ if (!timer_base)
+ pr_err("sdhost: failed to remap timer\n");
diff --git a/target/linux/brcm2708/patches-4.4/0151-config-Enable-HCI-over-UARTs.patch b/target/linux/brcm2708/patches-4.4/0151-config-Enable-HCI-over-UARTs.patch
new file mode 100644
index 0000000000..6109dea725
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0151-config-Enable-HCI-over-UARTs.patch
@@ -0,0 +1,33 @@
+From 87e7ae7002a6d1c8ca60c6081d4c2763940f6bef Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 15 Jan 2016 16:48:27 +0000
+Subject: [PATCH 151/381] config: Enable HCI over UARTs
+
+---
+ arch/arm/configs/bcm2709_defconfig | 3 +++
+ arch/arm/configs/bcmrpi_defconfig | 2 ++
+ 2 files changed, 5 insertions(+)
+
+--- a/arch/arm/configs/bcm2709_defconfig
++++ b/arch/arm/configs/bcm2709_defconfig
+@@ -376,6 +376,9 @@ CONFIG_BT_BNEP_PROTO_FILTER=y
+ CONFIG_BT_HIDP=m
+ CONFIG_BT_6LOWPAN=m
+ CONFIG_BT_HCIBTUSB=m
++CONFIG_BT_HCIUART=m
++CONFIG_BT_HCIUART_3WIRE=y
++CONFIG_BT_HCIUART_BCM=y
+ CONFIG_BT_HCIBCM203X=m
+ CONFIG_BT_HCIBPA10X=m
+ CONFIG_BT_HCIBFUSB=m
+--- a/arch/arm/configs/bcmrpi_defconfig
++++ b/arch/arm/configs/bcmrpi_defconfig
+@@ -370,6 +370,8 @@ CONFIG_BT_HIDP=m
+ CONFIG_BT_6LOWPAN=m
+ CONFIG_BT_HCIBTUSB=m
+ CONFIG_BT_HCIUART=m
++CONFIG_BT_HCIUART_3WIRE=y
++CONFIG_BT_HCIUART_BCM=y
+ CONFIG_BT_HCIBCM203X=m
+ CONFIG_BT_HCIBPA10X=m
+ CONFIG_BT_HCIBFUSB=m
diff --git a/target/linux/brcm2708/patches-4.4/0151-dcw_otg-trim-xfer-length-when-buffer-larger-than-all.patch b/target/linux/brcm2708/patches-4.4/0151-dcw_otg-trim-xfer-length-when-buffer-larger-than-all.patch
deleted file mode 100644
index 203e97b8e9..0000000000
--- a/target/linux/brcm2708/patches-4.4/0151-dcw_otg-trim-xfer-length-when-buffer-larger-than-all.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-From bc7400cadff6bf33451b124eac2e8bf80ebb0197 Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Fri, 12 Feb 2016 14:50:25 +0000
-Subject: [PATCH 151/170] dcw_otg: trim xfer length when buffer larger than
- allocated size is received
-
----
- drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 11 +++++++++++
- 1 file changed, 11 insertions(+)
-
---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
-@@ -737,6 +737,11 @@ static int update_urb_state_xfer_comp(dw
- DWC_OTG_HC_XFER_COMPLETE,
- &short_read);
-
-+ if (urb->actual_length + xfer_length > urb->length) {
-+ DWC_WARN("%s(): trimming xfer length\n", __func__);
-+ xfer_length = urb->length - urb->actual_length;
-+ }
-+
- /* non DWORD-aligned buffer case handling. */
- if (hc->align_buff && xfer_length && hc->ep_is_in) {
- dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf,
-@@ -1423,6 +1428,12 @@ static void update_urb_state_xfer_intr(d
- {
- uint32_t bytes_transferred = get_actual_xfer_length(hc, hc_regs, qtd,
- halt_status, NULL);
-+
-+ if (urb->actual_length + bytes_transferred > urb->length) {
-+ DWC_WARN("%s(): trimming xfer length\n", __func__);
-+ bytes_transferred = urb->length - urb->actual_length;
-+ }
-+
- /* non DWORD-aligned buffer case handling. */
- if (hc->align_buff && bytes_transferred && hc->ep_is_in) {
- dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf,
diff --git a/target/linux/brcm2708/patches-4.4/0152-bcm2835-sdhost-Restore-ATOMIC-flag-to-PIO-sg-mapping.patch b/target/linux/brcm2708/patches-4.4/0152-bcm2835-sdhost-Restore-ATOMIC-flag-to-PIO-sg-mapping.patch
deleted file mode 100644
index 48aca151dc..0000000000
--- a/target/linux/brcm2708/patches-4.4/0152-bcm2835-sdhost-Restore-ATOMIC-flag-to-PIO-sg-mapping.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-From f395ff998f2bde846499b1a0ef84519989dc2d4e Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Mon, 15 Feb 2016 10:00:27 +0000
-Subject: [PATCH 152/170] bcm2835-sdhost: Restore ATOMIC flag to PIO sg mapping
-
-Allocation problems have been seen in a wireless driver, and
-this is the only change which might have been responsible.
----
- drivers/mmc/host/bcm2835-sdhost.c | 7 +++----
- 1 file changed, 3 insertions(+), 4 deletions(-)
-
---- a/drivers/mmc/host/bcm2835-sdhost.c
-+++ b/drivers/mmc/host/bcm2835-sdhost.c
-@@ -874,15 +874,14 @@ static void bcm2835_sdhost_prepare_data(
- host->flush_fifo = 0;
- host->data->bytes_xfered = 0;
-
--
- if (!host->dma_desc) {
- /* Use PIO */
-- int flags;
-+ int flags = SG_MITER_ATOMIC;
-
- if (data->flags & MMC_DATA_READ)
-- flags = SG_MITER_TO_SG;
-+ flags |= SG_MITER_TO_SG;
- else
-- flags = SG_MITER_FROM_SG;
-+ flags |= SG_MITER_FROM_SG;
- sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
- host->blocks = data->blocks;
- }
diff --git a/target/linux/brcm2708/patches-4.4/0152-hci_h5-Don-t-send-conf_req-when-ACTIVE.patch b/target/linux/brcm2708/patches-4.4/0152-hci_h5-Don-t-send-conf_req-when-ACTIVE.patch
new file mode 100644
index 0000000000..f3b8dc3d5b
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0152-hci_h5-Don-t-send-conf_req-when-ACTIVE.patch
@@ -0,0 +1,23 @@
+From e5be45c39298a4e3a26bafd04f6fb2f88473465c Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Thu, 17 Dec 2015 13:37:07 +0000
+Subject: [PATCH 152/381] hci_h5: Don't send conf_req when ACTIVE
+
+Without this patch, a modem and kernel can continuously bombard each
+other with conf_req and conf_rsp messages, in a demented game of tag.
+---
+ drivers/bluetooth/hci_h5.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/bluetooth/hci_h5.c
++++ b/drivers/bluetooth/hci_h5.c
+@@ -314,7 +314,8 @@ static void h5_handle_internal_rx(struct
+ h5_link_control(hu, conf_req, 3);
+ } else if (memcmp(data, conf_req, 2) == 0) {
+ h5_link_control(hu, conf_rsp, 2);
+- h5_link_control(hu, conf_req, 3);
++ if (h5->state != H5_ACTIVE)
++ h5_link_control(hu, conf_req, 3);
+ } else if (memcmp(data, conf_rsp, 2) == 0) {
+ if (H5_HDR_LEN(hdr) > 2)
+ h5->tx_win = (data[2] & 7);
diff --git a/target/linux/brcm2708/patches-4.4/0153-Revert-Add-blk_pos-parameter-to-mmc-multi_io_quirk-c.patch b/target/linux/brcm2708/patches-4.4/0153-Revert-Add-blk_pos-parameter-to-mmc-multi_io_quirk-c.patch
deleted file mode 100644
index 1554f8a9b5..0000000000
--- a/target/linux/brcm2708/patches-4.4/0153-Revert-Add-blk_pos-parameter-to-mmc-multi_io_quirk-c.patch
+++ /dev/null
@@ -1,79 +0,0 @@
-From d2943c4ee1c52cb2c9802be194ca90442e4fe34f Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Tue, 16 Feb 2016 08:47:56 +0000
-Subject: [PATCH 153/170] Revert "Add blk_pos parameter to mmc multi_io_quirk
- callback"
-
-This reverts commit aab95f9b10e8c3d32de2bf163b86f220c88214fe.
-
-The bcm2835-sdhost driver no longer needs this patch.
----
- drivers/mmc/card/block.c | 1 -
- drivers/mmc/host/omap_hsmmc.c | 4 +---
- drivers/mmc/host/sh_mobile_sdhi.c | 4 +---
- drivers/mmc/host/tmio_mmc_pio.c | 4 +---
- include/linux/mmc/host.h | 4 +---
- 5 files changed, 4 insertions(+), 13 deletions(-)
-
---- a/drivers/mmc/card/block.c
-+++ b/drivers/mmc/card/block.c
-@@ -1518,7 +1518,6 @@ static void mmc_blk_rw_rq_prep(struct mm
- brq->data.blocks = card->host->ops->multi_io_quirk(card,
- (rq_data_dir(req) == READ) ?
- MMC_DATA_READ : MMC_DATA_WRITE,
-- blk_rq_pos(req),
- brq->data.blocks);
- }
-
---- a/drivers/mmc/host/omap_hsmmc.c
-+++ b/drivers/mmc/host/omap_hsmmc.c
-@@ -1832,9 +1832,7 @@ static void omap_hsmmc_conf_bus_power(st
- }
-
- static int omap_hsmmc_multi_io_quirk(struct mmc_card *card,
-- unsigned int direction,
-- u32 blk_pos,
-- int blk_size)
-+ unsigned int direction, int blk_size)
- {
- /* This controller can't do multiblock reads due to hw bugs */
- if (direction == MMC_DATA_READ)
---- a/drivers/mmc/host/sh_mobile_sdhi.c
-+++ b/drivers/mmc/host/sh_mobile_sdhi.c
-@@ -170,9 +170,7 @@ static int sh_mobile_sdhi_write16_hook(s
- }
-
- static int sh_mobile_sdhi_multi_io_quirk(struct mmc_card *card,
-- unsigned int direction,
-- u32 blk_pos,
-- int blk_size)
-+ unsigned int direction, int blk_size)
- {
- /*
- * In Renesas controllers, when performing a
---- a/drivers/mmc/host/tmio_mmc_pio.c
-+++ b/drivers/mmc/host/tmio_mmc_pio.c
-@@ -1003,9 +1003,7 @@ static int tmio_mmc_get_ro(struct mmc_ho
- }
-
- static int tmio_multi_io_quirk(struct mmc_card *card,
-- unsigned int direction,
-- u32 blk_pos,
-- int blk_size)
-+ unsigned int direction, int blk_size)
- {
- struct tmio_mmc_host *host = mmc_priv(card->host);
-
---- a/include/linux/mmc/host.h
-+++ b/include/linux/mmc/host.h
-@@ -143,9 +143,7 @@ struct mmc_host_ops {
- * I/O. Returns the number of supported blocks for the request.
- */
- int (*multi_io_quirk)(struct mmc_card *card,
-- unsigned int direction,
-- u32 blk_pos,
-- int blk_size);
-+ unsigned int direction, int blk_size);
- };
-
- struct mmc_card;
diff --git a/target/linux/brcm2708/patches-4.4/0153-amba_pl011-Don-t-use-DT-aliases-for-numbering.patch b/target/linux/brcm2708/patches-4.4/0153-amba_pl011-Don-t-use-DT-aliases-for-numbering.patch
new file mode 100644
index 0000000000..29716c9923
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0153-amba_pl011-Don-t-use-DT-aliases-for-numbering.patch
@@ -0,0 +1,29 @@
+From 7ade9aef124764cdb6b6d6bb2526f2507891bb36 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Tue, 23 Feb 2016 17:26:48 +0000
+Subject: [PATCH 153/381] amba_pl011: Don't use DT aliases for numbering
+
+The pl011 driver looks for DT aliases of the form "serial<n>",
+and if found uses <n> as the device ID. This can cause
+/dev/ttyAMA0 to become /dev/ttyAMA1, which is confusing if the
+other serial port is provided by the 8250 driver which doesn't
+use the same logic.
+---
+ drivers/tty/serial/amba-pl011.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/tty/serial/amba-pl011.c
++++ b/drivers/tty/serial/amba-pl011.c
+@@ -2313,7 +2313,12 @@ static int pl011_setup_port(struct devic
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
++ /* Don't use DT serial<n> aliases - it causes the device to
++ be renumbered to ttyAMA1 if it is the second serial port in the
++ system, even though the other one is ttyS0. The 8250 driver
++ doesn't use this logic, so always remains ttyS0.
+ index = pl011_probe_dt_alias(index, dev);
++ */
+
+ uap->old_cr = 0;
+ uap->port.dev = dev;
diff --git a/target/linux/brcm2708/patches-4.4/0154-Updated-smsc95xx-driver-to-check-for-a-valid-MAC-add.patch b/target/linux/brcm2708/patches-4.4/0154-Updated-smsc95xx-driver-to-check-for-a-valid-MAC-add.patch
deleted file mode 100644
index 058725d10b..0000000000
--- a/target/linux/brcm2708/patches-4.4/0154-Updated-smsc95xx-driver-to-check-for-a-valid-MAC-add.patch
+++ /dev/null
@@ -1,40 +0,0 @@
-From ee83592659ae5dc5ceee63790a8cba57ebfa57b3 Mon Sep 17 00:00:00 2001
-From: Craig Roberts <cjr@craigroberts.net>
-Date: Tue, 16 Feb 2016 10:03:42 +0000
-Subject: [PATCH 154/170] Updated smsc95xx driver to check for a valid MAC
- address in eeprom before using smsc95xx.macaddr parameter passed on command
- line.
-
-The built-in RPi adaptor will still get a MAC address based on the parameter passed on the command line as the RPi hardware does not have an eeprom,
-however usb->ethernet adaptors using the same driver should have an eeprom with MAC address as part of their hardware and therefore will use this
-meaning they don't end up with the same MAC address as the built-in RPi adaptor.
----
- drivers/net/usb/smsc95xx.c | 10 +++++-----
- 1 file changed, 5 insertions(+), 5 deletions(-)
-
---- a/drivers/net/usb/smsc95xx.c
-+++ b/drivers/net/usb/smsc95xx.c
-@@ -817,10 +817,6 @@ static int smsc95xx_is_macaddr_param(str
-
- static void smsc95xx_init_mac_address(struct usbnet *dev)
- {
-- /* Check module parameters */
-- if (smsc95xx_is_macaddr_param(dev, dev->net->dev_addr))
-- return;
--
- /* try reading mac address from EEPROM */
- if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN,
- dev->net->dev_addr) == 0) {
-@@ -831,7 +827,11 @@ static void smsc95xx_init_mac_address(st
- }
- }
-
-- /* no eeprom, or eeprom values are invalid. generate random MAC */
-+ /* Check module parameters */
-+ if (smsc95xx_is_macaddr_param(dev, dev->net->dev_addr))
-+ return;
-+
-+ /* no eeprom, or eeprom values are invalid, and no module parameter specified to set MAC. Generate random MAC */
- eth_hw_addr_random(dev->net);
- netif_dbg(dev, ifup, dev->net, "MAC address set to eth_random_addr\n");
- }
diff --git a/target/linux/brcm2708/patches-4.4/0154-clk-bcm2835-Add-bindings-for-the-auxiliary-periphera.patch b/target/linux/brcm2708/patches-4.4/0154-clk-bcm2835-Add-bindings-for-the-auxiliary-periphera.patch
new file mode 100644
index 0000000000..f9d4f497e1
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0154-clk-bcm2835-Add-bindings-for-the-auxiliary-periphera.patch
@@ -0,0 +1,72 @@
+From 78261b39857302418614c11e59bdc5626c147dcd Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Tue, 15 Dec 2015 15:35:57 -0800
+Subject: [PATCH 154/381] clk: bcm2835: Add bindings for the auxiliary
+ peripheral clock gates.
+
+These will be used for enabling UART1, SPI1, and SPI2.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Acked-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Michael Turquette <mturquette@baylibre.com>
+---
+ .../bindings/clock/brcm,bcm2835-aux-clock.txt | 31 ++++++++++++++++++++++
+ include/dt-bindings/clock/bcm2835-aux.h | 17 ++++++++++++
+ 2 files changed, 48 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/clock/brcm,bcm2835-aux-clock.txt
+ create mode 100644 include/dt-bindings/clock/bcm2835-aux.h
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/clock/brcm,bcm2835-aux-clock.txt
+@@ -0,0 +1,31 @@
++Broadcom BCM2835 auxiliary peripheral support
++
++This binding uses the common clock binding:
++ Documentation/devicetree/bindings/clock/clock-bindings.txt
++
++The auxiliary peripherals (UART, SPI1, and SPI2) have a small register
++area controlling clock gating to the peripherals, and providing an IRQ
++status register.
++
++Required properties:
++- compatible: Should be "brcm,bcm2835-aux"
++- #clock-cells: Should be <1>. The permitted clock-specifier values can be
++ found in include/dt-bindings/clock/bcm2835-aux.h
++- reg: Specifies base physical address and size of the registers
++- clocks: The parent clock phandle
++
++Example:
++
++ clocks: cprman@7e101000 {
++ compatible = "brcm,bcm2835-cprman";
++ #clock-cells = <1>;
++ reg = <0x7e101000 0x2000>;
++ clocks = <&clk_osc>;
++ };
++
++ aux: aux@0x7e215004 {
++ compatible = "brcm,bcm2835-aux";
++ #clock-cells = <1>;
++ reg = <0x7e215000 0x8>;
++ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ };
+--- /dev/null
++++ b/include/dt-bindings/clock/bcm2835-aux.h
+@@ -0,0 +1,17 @@
++/*
++ * Copyright (C) 2015 Broadcom Corporation
++ *
++ * 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 version 2.
++ *
++ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
++ * kind, whether express or implied; without even the implied warranty
++ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#define BCM2835_AUX_CLOCK_UART 0
++#define BCM2835_AUX_CLOCK_SPI1 1
++#define BCM2835_AUX_CLOCK_SPI2 2
++#define BCM2835_AUX_CLOCK_COUNT 3
diff --git a/target/linux/brcm2708/patches-4.4/0155-clk-bcm2835-Add-a-driver-for-the-auxiliary-periphera.patch b/target/linux/brcm2708/patches-4.4/0155-clk-bcm2835-Add-a-driver-for-the-auxiliary-periphera.patch
new file mode 100644
index 0000000000..ab1c2847ed
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0155-clk-bcm2835-Add-a-driver-for-the-auxiliary-periphera.patch
@@ -0,0 +1,118 @@
+From 9ff5452cee4edcadc86554d29a07e9e2ea8cf36c Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Tue, 15 Dec 2015 15:35:58 -0800
+Subject: [PATCH 155/381] clk: bcm2835: Add a driver for the auxiliary
+ peripheral clock gates.
+
+There are a pair of SPI masters and a mini UART that were last minute
+additions. As a result, they didn't get integrated in the same way as
+the other gates off of the VPU clock in CPRMAN.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Signed-off-by: Michael Turquette <mturquette@baylibre.com>
+
+updated Makefile to preserve the rasoberry pi architectures
+---
+ drivers/clk/bcm/Makefile | 1 +
+ drivers/clk/bcm/clk-bcm2835-aux.c | 85 +++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 86 insertions(+)
+ create mode 100644 drivers/clk/bcm/clk-bcm2835-aux.c
+
+--- a/drivers/clk/bcm/Makefile
++++ b/drivers/clk/bcm/Makefile
+@@ -4,6 +4,7 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281
+ obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o
+ obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-asiu.o
+ obj-$(CONFIG_ARCH_BCM2835)$(CONFIG_ARCH_BCM2708)$(CONFIG_ARCH_BCM2709) += clk-bcm2835.o
++obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835-aux.o
+ obj-$(CONFIG_COMMON_CLK_IPROC) += clk-ns2.o
+ obj-$(CONFIG_ARCH_BCM_CYGNUS) += clk-cygnus.o
+ obj-$(CONFIG_ARCH_BCM_NSP) += clk-nsp.o
+--- /dev/null
++++ b/drivers/clk/bcm/clk-bcm2835-aux.c
+@@ -0,0 +1,85 @@
++/*
++ * Copyright (C) 2015 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.
++ */
++
++#include <linux/clk.h>
++#include <linux/clk-provider.h>
++#include <linux/clk/bcm2835.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <dt-bindings/clock/bcm2835-aux.h>
++
++#define BCM2835_AUXIRQ 0x00
++#define BCM2835_AUXENB 0x04
++
++static int bcm2835_aux_clk_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct clk_onecell_data *onecell;
++ const char *parent;
++ struct clk *parent_clk;
++ struct resource *res;
++ void __iomem *reg, *gate;
++
++ parent_clk = devm_clk_get(dev, NULL);
++ if (IS_ERR(parent_clk))
++ return PTR_ERR(parent_clk);
++ parent = __clk_get_name(parent_clk);
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ reg = devm_ioremap_resource(dev, res);
++ if (!reg)
++ return -ENODEV;
++
++ onecell = devm_kmalloc(dev, sizeof(*onecell), GFP_KERNEL);
++ if (!onecell)
++ return -ENOMEM;
++ onecell->clk_num = BCM2835_AUX_CLOCK_COUNT;
++ onecell->clks = devm_kcalloc(dev, BCM2835_AUX_CLOCK_COUNT,
++ sizeof(*onecell->clks), GFP_KERNEL);
++ if (!onecell->clks)
++ return -ENOMEM;
++
++ gate = reg + BCM2835_AUXENB;
++ onecell->clks[BCM2835_AUX_CLOCK_UART] =
++ clk_register_gate(dev, "aux_uart", parent, 0, gate, 0, 0, NULL);
++
++ onecell->clks[BCM2835_AUX_CLOCK_SPI1] =
++ clk_register_gate(dev, "aux_spi1", parent, 0, gate, 1, 0, NULL);
++
++ onecell->clks[BCM2835_AUX_CLOCK_SPI2] =
++ clk_register_gate(dev, "aux_spi2", parent, 0, gate, 2, 0, NULL);
++
++ of_clk_add_provider(pdev->dev.of_node, of_clk_src_onecell_get, onecell);
++
++ return 0;
++}
++
++static const struct of_device_id bcm2835_aux_clk_of_match[] = {
++ { .compatible = "brcm,bcm2835-aux", },
++ {},
++};
++MODULE_DEVICE_TABLE(of, bcm2835_aux_clk_of_match);
++
++static struct platform_driver bcm2835_aux_clk_driver = {
++ .driver = {
++ .name = "bcm2835-aux-clk",
++ .of_match_table = bcm2835_aux_clk_of_match,
++ },
++ .probe = bcm2835_aux_clk_probe,
++};
++builtin_platform_driver(bcm2835_aux_clk_driver);
++
++MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
++MODULE_DESCRIPTION("BCM2835 auxiliary peripheral clock driver");
++MODULE_LICENSE("GPL v2");
diff --git a/target/linux/brcm2708/patches-4.4/0155-dcw_otg-Make-trimming-messages-less-noisy.patch b/target/linux/brcm2708/patches-4.4/0155-dcw_otg-Make-trimming-messages-less-noisy.patch
deleted file mode 100644
index ef188f1c66..0000000000
--- a/target/linux/brcm2708/patches-4.4/0155-dcw_otg-Make-trimming-messages-less-noisy.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-From 1c43ff69763f4537b76b3248850256da2bda211b Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Wed, 17 Feb 2016 19:02:31 +0000
-Subject: [PATCH 155/170] dcw_otg: Make trimming messages less noisy
-
----
- drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 6 ++++--
- 1 file changed, 4 insertions(+), 2 deletions(-)
-
---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
-@@ -738,7 +738,8 @@ static int update_urb_state_xfer_comp(dw
- &short_read);
-
- if (urb->actual_length + xfer_length > urb->length) {
-- DWC_WARN("%s(): trimming xfer length\n", __func__);
-+ printk_once(KERN_DEBUG "dwc_otg: DEVICE:%03d : %s:%d:trimming xfer length\n",
-+ hc->dev_addr, __func__, __LINE__);
- xfer_length = urb->length - urb->actual_length;
- }
-
-@@ -1430,7 +1431,8 @@ static void update_urb_state_xfer_intr(d
- halt_status, NULL);
-
- if (urb->actual_length + bytes_transferred > urb->length) {
-- DWC_WARN("%s(): trimming xfer length\n", __func__);
-+ printk_once(KERN_DEBUG "dwc_otg: DEVICE:%03d : %s:%d:trimming xfer length\n",
-+ hc->dev_addr, __func__, __LINE__);
- bytes_transferred = urb->length - urb->actual_length;
- }
-
diff --git a/target/linux/brcm2708/patches-4.4/0156-Aux-SPI-1-2-implementation.patch b/target/linux/brcm2708/patches-4.4/0156-Aux-SPI-1-2-implementation.patch
new file mode 100644
index 0000000000..dfe8a3c570
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0156-Aux-SPI-1-2-implementation.patch
@@ -0,0 +1,700 @@
+From 67fd5e9a91ad7abeb3ebfa30753c375e0953b52e Mon Sep 17 00:00:00 2001
+From: Fraser <github@frasersdev.net>
+Date: Tue, 23 Feb 2016 10:04:37 +1100
+Subject: [PATCH 156/381] Aux SPI 1&2 implementation
+
+Adds aux spi 1 & 2 devices to compatible raspberry PIs.
+* Minor config of the driver build environment to ensure they get built
+for CONFIG_ARCH_BCM2708 & CONFIG_ARCH_BCM2709 devices.
+* Adds the aux spi driver into the defconfigs as a module.
+* Adds the auxiliary and spi1/2 devices into the device tree in a
+disabled state
+* Provides decide tree overlays which enables the devices and gives
+users a degree of control over how they are setup.
+---
+ arch/arm/boot/dts/bcm2708_common.dtsi | 34 ++++++++-
+ arch/arm/boot/dts/overlays/Makefile | 6 ++
+ arch/arm/boot/dts/overlays/README | 99 +++++++++++++++++++++++++
+ arch/arm/boot/dts/overlays/spi1-1cs-overlay.dts | 57 ++++++++++++++
+ arch/arm/boot/dts/overlays/spi1-2cs-overlay.dts | 69 +++++++++++++++++
+ arch/arm/boot/dts/overlays/spi1-3cs-overlay.dts | 81 ++++++++++++++++++++
+ arch/arm/boot/dts/overlays/spi2-1cs-overlay.dts | 57 ++++++++++++++
+ arch/arm/boot/dts/overlays/spi2-2cs-overlay.dts | 69 +++++++++++++++++
+ arch/arm/boot/dts/overlays/spi2-3cs-overlay.dts | 81 ++++++++++++++++++++
+ arch/arm/configs/bcm2709_defconfig | 1 +
+ arch/arm/configs/bcmrpi_defconfig | 1 +
+ drivers/clk/bcm/Makefile | 2 +-
+ drivers/spi/Kconfig | 2 +-
+ 13 files changed, 556 insertions(+), 3 deletions(-)
+ create mode 100644 arch/arm/boot/dts/overlays/spi1-1cs-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/spi1-2cs-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/spi1-3cs-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/spi2-1cs-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/spi2-2cs-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/spi2-3cs-overlay.dts
+
+--- a/arch/arm/boot/dts/bcm2708_common.dtsi
++++ b/arch/arm/boot/dts/bcm2708_common.dtsi
+@@ -1,3 +1,4 @@
++#include <dt-bindings/clock/bcm2835-aux.h>
+ #include "skeleton.dtsi"
+
+ / {
+@@ -5,6 +6,7 @@
+
+ aliases {
+ audio = &audio;
++ aux = &aux;
+ sound = &sound;
+ soc = &soc;
+ dma = &dma;
+@@ -19,6 +21,8 @@
+ spi0 = &spi0;
+ i2c0 = &i2c0;
+ uart1 = &uart1;
++ spi1 = &spi1;
++ spi2 = &spi2;
+ mmc = &mmc;
+ i2c1 = &i2c1;
+ i2c2 = &i2c2;
+@@ -186,6 +190,14 @@
+ status = "disabled";
+ };
+
++ aux: aux@0x7e215004 {
++ compatible = "brcm,bcm2835-aux";
++ #clock-cells = <1>;
++ reg = <0x7e215000 0x8>;
++ clocks = <&clk_core>;
++ status = "disabled";
++ };
++
+ uart1: uart@7e215040 {
+ compatible = "brcm,bcm2835-aux-uart", "ns16550";
+ reg = <0x7e215040 0x40>;
+@@ -194,7 +206,27 @@
+ reg-shift = <2>;
+ no-loopback-test;
+ status = "disabled";
+- };
++ };
++
++ spi1: spi@7e215080 {
++ compatible = "brcm,bcm2835-aux-spi";
++ reg = <0x7e215080 0x40>, <0x7e215000 0x8>;
++ interrupts = <1 29>;
++ clocks = <&aux BCM2835_AUX_CLOCK_SPI1>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ spi2: spi@7e2150C0 {
++ compatible = "brcm,bcm2835-aux-spi";
++ reg = <0x7e2150C0 0x40>, <0x7e215000 0x8>;
++ interrupts = <1 29>;
++ clocks = <&aux BCM2835_AUX_CLOCK_SPI2>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
+
+ mmc: mmc@7e300000 {
+ compatible = "brcm,bcm2835-mmc";
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -57,6 +57,12 @@ dtb-$(RPI_DT_OVERLAYS) += sdtweak-overla
+ dtb-$(RPI_DT_OVERLAYS) += smi-dev-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += smi-nand-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += smi-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += spi1-1cs-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += spi1-2cs-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += spi1-3cs-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += spi2-1cs-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += spi2-2cs-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += spi2-3cs-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += spi-gpio35-39-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += tinylcd35-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += uart1-overlay.dtb
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -713,6 +713,105 @@ Load: dtoverlay=spi-gpio35-39
+ Params: <None>
+
+
++Name: spi1-1cs
++Info: Enables spi1 with a single chip select (CS) line and associated spidev
++ dev node. The gpio pin number for the CS line and spidev device node
++ creation are configurable.
++ N.B.: spi1 is only accessible on devices with a 40pin header, eg:
++ A+, B+, Zero and PI2 B; as well as the Compute Module.
++Load: dtoverlay=spi1-1cs,<param>=<val>
++Params: cs0_pin GPIO pin for CS0 (default 18 - BCM SPI1_CE0).
++ cs0_spidev Set to 'disabled' to stop the creation of a
++ userspace device node /dev/spidev1.0 (default
++ is 'okay' or enabled).
++
++
++Name: spi1-2cs
++Info: Enables spi1 with two chip select (CS) lines and associated spidev
++ dev nodes. The gpio pin numbers for the CS lines and spidev device node
++ creation are configurable.
++ N.B.: spi1 is only accessible on devices with a 40pin header, eg:
++ A+, B+, Zero and PI2 B; as well as the Compute Module.
++Load: dtoverlay=spi1-2cs,<param>=<val>
++Params: cs0_pin GPIO pin for CS0 (default 18 - BCM SPI1_CE0).
++ cs1_pin GPIO pin for CS1 (default 17 - BCM SPI1_CE1).
++ cs0_spidev Set to 'disabled' to stop the creation of a
++ userspace device node /dev/spidev1.0 (default
++ is 'okay' or enabled).
++ cs1_spidev Set to 'disabled' to stop the creation of a
++ userspace device node /dev/spidev1.1 (default
++ is 'okay' or enabled).
++
++
++Name: spi1-3cs
++Info: Enables spi1 with three chip select (CS) lines and associated spidev
++ dev nodes. The gpio pin numbers for the CS lines and spidev device node
++ creation are configurable.
++ N.B.: spi1 is only accessible on devices with a 40pin header, eg:
++ A+, B+, Zero and PI2 B; as well as the Compute Module.
++Load: dtoverlay=spi1-3cs,<param>=<val>
++Params: cs0_pin GPIO pin for CS0 (default 18 - BCM SPI1_CE0).
++ cs1_pin GPIO pin for CS1 (default 17 - BCM SPI1_CE1).
++ cs2_pin GPIO pin for CS2 (default 16 - BCM SPI1_CE2).
++ cs0_spidev Set to 'disabled' to stop the creation of a
++ userspace device node /dev/spidev1.0 (default
++ is 'okay' or enabled).
++ cs1_spidev Set to 'disabled' to stop the creation of a
++ userspace device node /dev/spidev1.1 (default
++ is 'okay' or enabled).
++ cs2_spidev Set to 'disabled' to stop the creation of a
++ userspace device node /dev/spidev1.2 (default
++ is 'okay' or enabled).
++
++
++Name: spi2-1cs
++Info: Enables spi2 with a single chip select (CS) line and associated spidev
++ dev node. The gpio pin number for the CS line and spidev device node
++ creation are configurable.
++ N.B.: spi2 is only accessible with the Compute Module.
++Load: dtoverlay=spi2-1cs,<param>=<val>
++Params: cs0_pin GPIO pin for CS0 (default 43 - BCM SPI2_CE0).
++ cs0_spidev Set to 'disabled' to stop the creation of a
++ userspace device node /dev/spidev2.0 (default
++ is 'okay' or enabled).
++
++
++Name: spi2-2cs
++Info: Enables spi2 with two chip select (CS) lines and associated spidev
++ dev nodes. The gpio pin numbers for the CS lines and spidev device node
++ creation are configurable.
++ N.B.: spi2 is only accessible with the Compute Module.
++Load: dtoverlay=spi2-2cs,<param>=<val>
++Params: cs0_pin GPIO pin for CS0 (default 43 - BCM SPI2_CE0).
++ cs1_pin GPIO pin for CS1 (default 44 - BCM SPI2_CE1).
++ cs0_spidev Set to 'disabled' to stop the creation of a
++ userspace device node /dev/spidev2.0 (default
++ is 'okay' or enabled).
++ cs1_spidev Set to 'disabled' to stop the creation of a
++ userspace device node /dev/spidev2.1 (default
++ is 'okay' or enabled).
++
++
++Name: spi2-3cs
++Info: Enables spi2 with three chip select (CS) lines and associated spidev
++ dev nodes. The gpio pin numbers for the CS lines and spidev device node
++ creation are configurable.
++ N.B.: spi2 is only accessible with the Compute Module.
++Load: dtoverlay=spi2-3cs,<param>=<val>
++Params: cs0_pin GPIO pin for CS0 (default 43 - BCM SPI2_CE0).
++ cs1_pin GPIO pin for CS1 (default 44 - BCM SPI2_CE1).
++ cs2_pin GPIO pin for CS2 (default 45 - BCM SPI2_CE2).
++ cs0_spidev Set to 'disabled' to stop the creation of a
++ userspace device node /dev/spidev2.0 (default
++ is 'okay' or enabled).
++ cs1_spidev Set to 'disabled' to stop the creation of a
++ userspace device node /dev/spidev2.1 (default
++ is 'okay' or enabled).
++ cs2_spidev Set to 'disabled' to stop the creation of a
++ userspace device node /dev/spidev2.2 (default
++ is 'okay' or enabled).
++
++
+ Name: tinylcd35
+ Info: 3.5" Color TFT Display by www.tinylcd.com
+ Options: Touch, RTC, keypad
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/spi1-1cs-overlay.dts
+@@ -0,0 +1,57 @@
++/dts-v1/;
++/plugin/;
++
++
++/ {
++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++
++ fragment@0 {
++ target = <&gpio>;
++ __overlay__ {
++ spi1_pins: spi1_pins {
++ brcm,pins = <19 20 21>;
++ brcm,function = <3>; /* alt4 */
++ };
++
++ spi1_cs_pins: spi1_cs_pins {
++ brcm,pins = <18>;
++ brcm,function = <1>; /* output */
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&spi1>;
++ frag1: __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi1_pins &spi1_cs_pins>;
++ cs-gpios = <&gpio 18 1>;
++ status = "okay";
++
++ spidev1_0: spidev@0 {
++ compatible = "spidev";
++ reg = <0>; /* CE0 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <500000>;
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&aux>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ __overrides__ {
++ cs0_pin = <&spi1_cs_pins>,"brcm,pins:0",
++ <&frag1>,"cs-gpios:4";
++ cs0_spidev = <&spidev1_0>,"status";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/spi1-2cs-overlay.dts
+@@ -0,0 +1,69 @@
++/dts-v1/;
++/plugin/;
++
++
++/ {
++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++
++ fragment@0 {
++ target = <&gpio>;
++ __overlay__ {
++ spi1_pins: spi1_pins {
++ brcm,pins = <19 20 21>;
++ brcm,function = <3>; /* alt4 */
++ };
++
++ spi1_cs_pins: spi1_cs_pins {
++ brcm,pins = <18 17>;
++ brcm,function = <1>; /* output */
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&spi1>;
++ frag1: __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi1_pins &spi1_cs_pins>;
++ cs-gpios = <&gpio 18 1>, <&gpio 17 1>;
++ status = "okay";
++
++ spidev1_0: spidev@0 {
++ compatible = "spidev";
++ reg = <0>; /* CE0 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <500000>;
++ status = "okay";
++ };
++
++ spidev1_1: spidev@1 {
++ compatible = "spidev";
++ reg = <1>; /* CE1 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <500000>;
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&aux>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ __overrides__ {
++ cs0_pin = <&spi1_cs_pins>,"brcm,pins:0",
++ <&frag1>,"cs-gpios:4";
++ cs1_pin = <&spi1_cs_pins>,"brcm,pins:4",
++ <&frag1>,"cs-gpios:16";
++ cs0_spidev = <&spidev1_0>,"status";
++ cs1_spidev = <&spidev1_1>,"status";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/spi1-3cs-overlay.dts
+@@ -0,0 +1,81 @@
++/dts-v1/;
++/plugin/;
++
++
++/ {
++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++
++ fragment@0 {
++ target = <&gpio>;
++ __overlay__ {
++ spi1_pins: spi1_pins {
++ brcm,pins = <19 20 21>;
++ brcm,function = <3>; /* alt4 */
++ };
++
++ spi1_cs_pins: spi1_cs_pins {
++ brcm,pins = <18 17 16>;
++ brcm,function = <1>; /* output */
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&spi1>;
++ frag1: __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi1_pins &spi1_cs_pins>;
++ cs-gpios = <&gpio 18 1>, <&gpio 17 1>, <&gpio 16 1>;
++ status = "okay";
++
++ spidev1_0: spidev@0 {
++ compatible = "spidev";
++ reg = <0>; /* CE0 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <500000>;
++ status = "okay";
++ };
++
++ spidev1_1: spidev@1 {
++ compatible = "spidev";
++ reg = <1>; /* CE1 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <500000>;
++ status = "okay";
++ };
++
++ spidev1_2: spidev@2 {
++ compatible = "spidev";
++ reg = <2>; /* CE2 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <500000>;
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&aux>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ __overrides__ {
++ cs0_pin = <&spi1_cs_pins>,"brcm,pins:0",
++ <&frag1>,"cs-gpios:4";
++ cs1_pin = <&spi1_cs_pins>,"brcm,pins:4",
++ <&frag1>,"cs-gpios:16";
++ cs2_pin = <&spi1_cs_pins>,"brcm,pins:8",
++ <&frag1>,"cs-gpios:28";
++ cs0_spidev = <&spidev1_0>,"status";
++ cs1_spidev = <&spidev1_1>,"status";
++ cs2_spidev = <&spidev1_2>,"status";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/spi2-1cs-overlay.dts
+@@ -0,0 +1,57 @@
++/dts-v1/;
++/plugin/;
++
++
++/ {
++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++
++ fragment@0 {
++ target = <&gpio>;
++ __overlay__ {
++ spi2_pins: spi2_pins {
++ brcm,pins = <40 41 42>;
++ brcm,function = <3>; /* alt4 */
++ };
++
++ spi2_cs_pins: spi2_cs_pins {
++ brcm,pins = <43>;
++ brcm,function = <1>; /* output */
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&spi2>;
++ frag1: __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi2_pins &spi2_cs_pins>;
++ cs-gpios = <&gpio 43 1>;
++ status = "okay";
++
++ spidev2_0: spidev@0 {
++ compatible = "spidev";
++ reg = <0>; /* CE0 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <500000>;
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&aux>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ __overrides__ {
++ cs0_pin = <&spi2_cs_pins>,"brcm,pins:0",
++ <&frag1>,"cs-gpios:4";
++ cs0_spidev = <&spidev2_0>,"status";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/spi2-2cs-overlay.dts
+@@ -0,0 +1,69 @@
++/dts-v1/;
++/plugin/;
++
++
++/ {
++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++
++ fragment@0 {
++ target = <&gpio>;
++ __overlay__ {
++ spi2_pins: spi2_pins {
++ brcm,pins = <40 41 42>;
++ brcm,function = <3>; /* alt4 */
++ };
++
++ spi2_cs_pins: spi2_cs_pins {
++ brcm,pins = <43 44>;
++ brcm,function = <1>; /* output */
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&spi2>;
++ frag1: __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi2_pins &spi2_cs_pins>;
++ cs-gpios = <&gpio 43 1>, <&gpio 44 1>;
++ status = "okay";
++
++ spidev2_0: spidev@0 {
++ compatible = "spidev";
++ reg = <0>; /* CE0 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <500000>;
++ status = "okay";
++ };
++
++ spidev2_1: spidev@1 {
++ compatible = "spidev";
++ reg = <1>; /* CE1 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <500000>;
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&aux>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ __overrides__ {
++ cs0_pin = <&spi2_cs_pins>,"brcm,pins:0",
++ <&frag1>,"cs-gpios:4";
++ cs1_pin = <&spi2_cs_pins>,"brcm,pins:4",
++ <&frag1>,"cs-gpios:16";
++ cs0_spidev = <&spidev2_0>,"status";
++ cs1_spidev = <&spidev2_1>,"status";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/spi2-3cs-overlay.dts
+@@ -0,0 +1,81 @@
++/dts-v1/;
++/plugin/;
++
++
++/ {
++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++
++ fragment@0 {
++ target = <&gpio>;
++ __overlay__ {
++ spi2_pins: spi2_pins {
++ brcm,pins = <40 41 42>;
++ brcm,function = <3>; /* alt4 */
++ };
++
++ spi2_cs_pins: spi2_cs_pins {
++ brcm,pins = <43 44 45>;
++ brcm,function = <1>; /* output */
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&spi2>;
++ frag1: __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi2_pins &spi2_cs_pins>;
++ cs-gpios = <&gpio 43 1>, <&gpio 44 1>, <&gpio 45 1>;
++ status = "okay";
++
++ spidev2_0: spidev@0 {
++ compatible = "spidev";
++ reg = <0>; /* CE0 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <500000>;
++ status = "okay";
++ };
++
++ spidev2_1: spidev@1 {
++ compatible = "spidev";
++ reg = <1>; /* CE1 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <500000>;
++ status = "okay";
++ };
++
++ spidev2_2: spidev@2 {
++ compatible = "spidev";
++ reg = <2>; /* CE2 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <500000>;
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&aux>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ __overrides__ {
++ cs0_pin = <&spi2_cs_pins>,"brcm,pins:0",
++ <&frag1>,"cs-gpios:4";
++ cs1_pin = <&spi2_cs_pins>,"brcm,pins:4",
++ <&frag1>,"cs-gpios:16";
++ cs2_pin = <&spi2_cs_pins>,"brcm,pins:8",
++ <&frag1>,"cs-gpios:28";
++ cs0_spidev = <&spidev2_0>,"status";
++ cs1_spidev = <&spidev2_1>,"status";
++ cs2_spidev = <&spidev2_2>,"status";
++ };
++};
+--- a/arch/arm/configs/bcm2709_defconfig
++++ b/arch/arm/configs/bcm2709_defconfig
+@@ -601,6 +601,7 @@ CONFIG_I2C_BCM2708=m
+ CONFIG_I2C_GPIO=m
+ CONFIG_SPI=y
+ CONFIG_SPI_BCM2835=m
++CONFIG_SPI_BCM2835AUX=m
+ CONFIG_SPI_SPIDEV=y
+ CONFIG_PPS=m
+ CONFIG_PPS_CLIENT_LDISC=m
+--- a/arch/arm/configs/bcmrpi_defconfig
++++ b/arch/arm/configs/bcmrpi_defconfig
+@@ -593,6 +593,7 @@ CONFIG_I2C_BCM2708=m
+ CONFIG_I2C_GPIO=m
+ CONFIG_SPI=y
+ CONFIG_SPI_BCM2835=m
++CONFIG_SPI_BCM2835AUX=m
+ CONFIG_SPI_SPIDEV=y
+ CONFIG_PPS=m
+ CONFIG_PPS_CLIENT_LDISC=m
+--- a/drivers/clk/bcm/Makefile
++++ b/drivers/clk/bcm/Makefile
+@@ -4,7 +4,7 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281
+ obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o
+ obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-asiu.o
+ obj-$(CONFIG_ARCH_BCM2835)$(CONFIG_ARCH_BCM2708)$(CONFIG_ARCH_BCM2709) += clk-bcm2835.o
+-obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835-aux.o
++obj-$(CONFIG_ARCH_BCM2835)$(CONFIG_ARCH_BCM2708)$(CONFIG_ARCH_BCM2709) += clk-bcm2835-aux.o
+ obj-$(CONFIG_COMMON_CLK_IPROC) += clk-ns2.o
+ obj-$(CONFIG_ARCH_BCM_CYGNUS) += clk-cygnus.o
+ obj-$(CONFIG_ARCH_BCM_NSP) += clk-nsp.o
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -90,7 +90,7 @@ config SPI_BCM2835
+
+ config SPI_BCM2835AUX
+ tristate "BCM2835 SPI auxiliary controller"
+- 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 aux master.
diff --git a/target/linux/brcm2708/patches-4.4/0156-BCM270X_DT-at86rf233-overlay-drop-to-3MHz.patch b/target/linux/brcm2708/patches-4.4/0156-BCM270X_DT-at86rf233-overlay-drop-to-3MHz.patch
deleted file mode 100644
index 9338280595..0000000000
--- a/target/linux/brcm2708/patches-4.4/0156-BCM270X_DT-at86rf233-overlay-drop-to-3MHz.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From 7f9781f9875f2aa638d5afdaa9709fa1ef9bda8d Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Thu, 18 Feb 2016 15:28:14 +0000
-Subject: [PATCH 156/170] BCM270X_DT: at86rf233 overlay - drop to 3MHz
-
-The consensus is that 6MHz is too fast, but that 3MHz is OK.
-
-See: https://github.com/raspberrypi/linux/issues/1294
- https://github.com/raspberrypi/linux/issues/1151
----
- arch/arm/boot/dts/overlays/README | 2 +-
- arch/arm/boot/dts/overlays/at86rf233-overlay.dts | 2 +-
- 2 files changed, 2 insertions(+), 2 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -188,7 +188,7 @@ Load: dtoverlay=at86rf233,<param>=<val
- Params: interrupt GPIO used for INT (default 23)
- reset GPIO used for Reset (default 24)
- sleep GPIO used for Sleep (default 25)
-- speed SPI bus speed in Hz (default 6000000)
-+ speed SPI bus speed in Hz (default 3000000)
- trim Fine tuning of the internal capacitance
- arrays (0=+0pF, 15=+4.5pF, default 15)
-
---- a/arch/arm/boot/dts/overlays/at86rf233-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/at86rf233-overlay.dts
-@@ -25,7 +25,7 @@
- interrupts = <23 4>; /* active high */
- reset-gpio = <&gpio 24 1>;
- sleep-gpio = <&gpio 25 1>;
-- spi-max-frequency = <6000000>;
-+ spi-max-frequency = <3000000>;
- xtal-trim = /bits/ 8 <0xf>;
- };
- };
diff --git a/target/linux/brcm2708/patches-4.4/0157-ASoC-bcm-add-missing-.owner-fields-in-sound-card-dri.patch b/target/linux/brcm2708/patches-4.4/0157-ASoC-bcm-add-missing-.owner-fields-in-sound-card-dri.patch
new file mode 100644
index 0000000000..0cf68e88b5
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0157-ASoC-bcm-add-missing-.owner-fields-in-sound-card-dri.patch
@@ -0,0 +1,108 @@
+From 0686b6a8e6a6bd951ef2a11228e976fde45749af Mon Sep 17 00:00:00 2001
+From: Matthias Reichl <hias@horus.com>
+Date: Tue, 23 Feb 2016 17:28:23 +0100
+Subject: [PATCH 157/381] ASoC: bcm: add missing .owner fields in sound card
+ drivers
+
+If snd_soc_card.owner is not set the kernel won't do usage refcounting
+and one can remove the card driver module while it's in use (eg playback
+active) - which leads to a kernel crash.
+
+The missing owner field also prevents ALSA slot ordering
+(options snd slots=module-name1,module-name-2,...) from working with
+the I2S cards as it has no module name to match against.
+
+Fix these issues by setting the .owner field in the snd_soc_card structs.
+
+Signed-off-by: Matthias Reichl <hias@horus.com>
+---
+ sound/soc/bcm/hifiberry_amp.c | 1 +
+ sound/soc/bcm/hifiberry_dac.c | 1 +
+ sound/soc/bcm/hifiberry_dacplus.c | 1 +
+ sound/soc/bcm/hifiberry_digi.c | 1 +
+ sound/soc/bcm/iqaudio-dac.c | 1 +
+ sound/soc/bcm/raspidac3.c | 1 +
+ sound/soc/bcm/rpi-dac.c | 1 +
+ sound/soc/bcm/rpi-proto.c | 1 +
+ 8 files changed, 8 insertions(+)
+
+--- a/sound/soc/bcm/hifiberry_amp.c
++++ b/sound/soc/bcm/hifiberry_amp.c
+@@ -61,6 +61,7 @@ static struct snd_soc_dai_link snd_rpi_h
+
+ static struct snd_soc_card snd_rpi_hifiberry_amp = {
+ .name = "snd_rpi_hifiberry_amp",
++ .owner = THIS_MODULE,
+ .dai_link = snd_rpi_hifiberry_amp_dai,
+ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_amp_dai),
+ };
+--- a/sound/soc/bcm/hifiberry_dac.c
++++ b/sound/soc/bcm/hifiberry_dac.c
+@@ -63,6 +63,7 @@ static struct snd_soc_dai_link snd_rpi_h
+ /* audio machine driver */
+ static struct snd_soc_card snd_rpi_hifiberry_dac = {
+ .name = "snd_rpi_hifiberry_dac",
++ .owner = THIS_MODULE,
+ .dai_link = snd_rpi_hifiberry_dac_dai,
+ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dac_dai),
+ };
+--- a/sound/soc/bcm/hifiberry_dacplus.c
++++ b/sound/soc/bcm/hifiberry_dacplus.c
+@@ -287,6 +287,7 @@ static struct snd_soc_dai_link snd_rpi_h
+ /* audio machine driver */
+ static struct snd_soc_card snd_rpi_hifiberry_dacplus = {
+ .name = "snd_rpi_hifiberry_dacplus",
++ .owner = THIS_MODULE,
+ .dai_link = snd_rpi_hifiberry_dacplus_dai,
+ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dacplus_dai),
+ };
+--- a/sound/soc/bcm/hifiberry_digi.c
++++ b/sound/soc/bcm/hifiberry_digi.c
+@@ -164,6 +164,7 @@ static struct snd_soc_dai_link snd_rpi_h
+ /* audio machine driver */
+ static struct snd_soc_card snd_rpi_hifiberry_digi = {
+ .name = "snd_rpi_hifiberry_digi",
++ .owner = THIS_MODULE,
+ .dai_link = snd_rpi_hifiberry_digi_dai,
+ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_digi_dai),
+ };
+--- a/sound/soc/bcm/iqaudio-dac.c
++++ b/sound/soc/bcm/iqaudio-dac.c
+@@ -77,6 +77,7 @@ static struct snd_soc_dai_link snd_rpi_i
+ /* audio machine driver */
+ static struct snd_soc_card snd_rpi_iqaudio_dac = {
+ .name = "IQaudIODAC",
++ .owner = THIS_MODULE,
+ .dai_link = snd_rpi_iqaudio_dac_dai,
+ .num_links = ARRAY_SIZE(snd_rpi_iqaudio_dac_dai),
+ };
+--- a/sound/soc/bcm/raspidac3.c
++++ b/sound/soc/bcm/raspidac3.c
+@@ -128,6 +128,7 @@ static struct snd_soc_dai_link snd_rpi_r
+ /* audio machine driver */
+ static struct snd_soc_card snd_rpi_raspidac3 = {
+ .name = "RaspiDAC Rev.3x HiFi Audio Card",
++ .owner = THIS_MODULE,
+ .dai_link = snd_rpi_raspidac3_dai,
+ .num_links = ARRAY_SIZE(snd_rpi_raspidac3_dai),
+ };
+--- a/sound/soc/bcm/rpi-dac.c
++++ b/sound/soc/bcm/rpi-dac.c
+@@ -60,6 +60,7 @@ static struct snd_soc_dai_link snd_rpi_r
+ /* audio machine driver */
+ static struct snd_soc_card snd_rpi_rpi_dac = {
+ .name = "snd_rpi_rpi_dac",
++ .owner = THIS_MODULE,
+ .dai_link = snd_rpi_rpi_dac_dai,
+ .num_links = ARRAY_SIZE(snd_rpi_rpi_dac_dai),
+ };
+--- a/sound/soc/bcm/rpi-proto.c
++++ b/sound/soc/bcm/rpi-proto.c
+@@ -91,6 +91,7 @@ static struct snd_soc_dai_link snd_rpi_p
+ /* audio machine driver */
+ static struct snd_soc_card snd_rpi_proto = {
+ .name = "snd_rpi_proto",
++ .owner = THIS_MODULE,
+ .dai_link = snd_rpi_proto_dai,
+ .num_links = ARRAY_SIZE(snd_rpi_proto_dai),
+ };
diff --git a/target/linux/brcm2708/patches-4.4/0157-bcm2835-sdhost-Downgrade-log-message-status.patch b/target/linux/brcm2708/patches-4.4/0157-bcm2835-sdhost-Downgrade-log-message-status.patch
deleted file mode 100644
index 6654a0c0d0..0000000000
--- a/target/linux/brcm2708/patches-4.4/0157-bcm2835-sdhost-Downgrade-log-message-status.patch
+++ /dev/null
@@ -1,22 +0,0 @@
-From 5af831a3f879c89c8c0b39c8f88e7600bdc3a765 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Fri, 19 Feb 2016 12:04:48 +0000
-Subject: [PATCH 157/170] bcm2835-sdhost: Downgrade log message status
-
----
- drivers/mmc/host/bcm2835-sdhost.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/mmc/host/bcm2835-sdhost.c
-+++ b/drivers/mmc/host/bcm2835-sdhost.c
-@@ -232,8 +232,8 @@ static void log_init(u32 bus_to_phys)
- sdhost_log_buf = dma_zalloc_coherent(NULL, LOG_SIZE, &sdhost_log_addr,
- GFP_KERNEL);
- if (sdhost_log_buf) {
-- pr_err("sdhost: log_buf @ %p (%x)\n",
-- sdhost_log_buf, sdhost_log_addr);
-+ pr_info("sdhost: log_buf @ %p (%x)\n",
-+ sdhost_log_buf, sdhost_log_addr);
- timer_base = ioremap_nocache(bus_to_phys + 0x7e003000, SZ_4K);
- if (!timer_base)
- pr_err("sdhost: failed to remap timer\n");
diff --git a/target/linux/brcm2708/patches-4.4/0158-config-Enable-HCI-over-UARTs.patch b/target/linux/brcm2708/patches-4.4/0158-config-Enable-HCI-over-UARTs.patch
deleted file mode 100644
index c55ff17b7d..0000000000
--- a/target/linux/brcm2708/patches-4.4/0158-config-Enable-HCI-over-UARTs.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-From e08f6b3aad073d8130d2ec0f8398f55983c0eac8 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Fri, 15 Jan 2016 16:48:27 +0000
-Subject: [PATCH 158/170] config: Enable HCI over UARTs
-
----
- arch/arm/configs/bcm2709_defconfig | 3 +++
- arch/arm/configs/bcmrpi_defconfig | 2 ++
- 2 files changed, 5 insertions(+)
-
---- a/arch/arm/configs/bcm2709_defconfig
-+++ b/arch/arm/configs/bcm2709_defconfig
-@@ -376,6 +376,9 @@ CONFIG_BT_BNEP_PROTO_FILTER=y
- CONFIG_BT_HIDP=m
- CONFIG_BT_6LOWPAN=m
- CONFIG_BT_HCIBTUSB=m
-+CONFIG_BT_HCIUART=m
-+CONFIG_BT_HCIUART_3WIRE=y
-+CONFIG_BT_HCIUART_BCM=y
- CONFIG_BT_HCIBCM203X=m
- CONFIG_BT_HCIBPA10X=m
- CONFIG_BT_HCIBFUSB=m
---- a/arch/arm/configs/bcmrpi_defconfig
-+++ b/arch/arm/configs/bcmrpi_defconfig
-@@ -370,6 +370,8 @@ CONFIG_BT_HIDP=m
- CONFIG_BT_6LOWPAN=m
- CONFIG_BT_HCIBTUSB=m
- CONFIG_BT_HCIUART=m
-+CONFIG_BT_HCIUART_3WIRE=y
-+CONFIG_BT_HCIUART_BCM=y
- CONFIG_BT_HCIBCM203X=m
- CONFIG_BT_HCIBPA10X=m
- CONFIG_BT_HCIBFUSB=m
diff --git a/target/linux/brcm2708/patches-4.4/0158-smsx95xx-Add-option-to-disable-the-crimes-against-tr.patch b/target/linux/brcm2708/patches-4.4/0158-smsx95xx-Add-option-to-disable-the-crimes-against-tr.patch
new file mode 100644
index 0000000000..90c4b0ad45
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0158-smsx95xx-Add-option-to-disable-the-crimes-against-tr.patch
@@ -0,0 +1,44 @@
+From 43203ed1c397e88a087ef6d4cf79de24a89e1fef Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Wed, 20 Jan 2016 17:50:09 +0000
+Subject: [PATCH 158/381] smsx95xx: Add option to disable the crimes against
+ truesize fix
+
+It may improve iperf numbers on Pi 1, but may generate dmesg warnings and possibly cause network issues
+See issue 1248.
+---
+ drivers/net/usb/smsc95xx.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+ mode change 100755 => 100644 drivers/net/usb/smsc95xx.c
+
+--- a/drivers/net/usb/smsc95xx.c
++++ b/drivers/net/usb/smsc95xx.c
+@@ -75,6 +75,10 @@ static bool turbo_mode = false;
+ module_param(turbo_mode, bool, 0644);
+ MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
+
++static bool truesize_mode = false;
++module_param(truesize_mode, bool, 0644);
++MODULE_PARM_DESC(truesize_mode, "Report larger truesize value");
++
+ static char *macaddr = ":";
+ module_param(macaddr, charp, 0);
+ MODULE_PARM_DESC(macaddr, "MAC address");
+@@ -1841,6 +1845,8 @@ 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 */
++ if (truesize_mode)
++ skb->truesize = size + sizeof(struct sk_buff);
+
+ return 1;
+ }
+@@ -1858,6 +1864,8 @@ 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 */
++ if (truesize_mode)
++ ax_skb->truesize = size + sizeof(struct sk_buff);
+
+ usbnet_skb_return(dev, ax_skb);
+ }
diff --git a/target/linux/brcm2708/patches-4.4/0159-bcm2835-virtgpio-Virtual-GPIO-driver.patch b/target/linux/brcm2708/patches-4.4/0159-bcm2835-virtgpio-Virtual-GPIO-driver.patch
new file mode 100644
index 0000000000..5413eeb33a
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0159-bcm2835-virtgpio-Virtual-GPIO-driver.patch
@@ -0,0 +1,244 @@
+From 79ea239874848e67d42b9274d4f7eeb51892ccd8 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Tue, 23 Feb 2016 19:56:04 +0000
+Subject: [PATCH 159/381] bcm2835-virtgpio: Virtual GPIO driver
+
+Add a virtual GPIO driver that uses the firmware mailbox interface to
+request that the VPU toggles LEDs.
+---
+ arch/arm/configs/bcm2709_defconfig | 1 +
+ drivers/gpio/Kconfig | 6 +
+ drivers/gpio/Makefile | 1 +
+ drivers/gpio/gpio-bcm-virt.c | 180 +++++++++++++++++++++++++++++
+ include/soc/bcm2835/raspberrypi-firmware.h | 1 +
+ 5 files changed, 189 insertions(+)
+ create mode 100644 drivers/gpio/gpio-bcm-virt.c
+
+--- a/arch/arm/configs/bcm2709_defconfig
++++ b/arch/arm/configs/bcm2709_defconfig
+@@ -607,6 +607,7 @@ CONFIG_PPS=m
+ CONFIG_PPS_CLIENT_LDISC=m
+ CONFIG_PPS_CLIENT_GPIO=m
+ CONFIG_GPIO_SYSFS=y
++CONFIG_GPIO_BCM_VIRT=y
+ CONFIG_GPIO_ARIZONA=m
+ CONFIG_GPIO_STMPE=y
+ CONFIG_W1=m
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -132,6 +132,12 @@ config GPIO_BCM_KONA
+ help
+ Turn on GPIO support for Broadcom "Kona" chips.
+
++config GPIO_BCM_VIRT
++ bool "Broadcom Virt GPIO"
++ depends on OF_GPIO && RASPBERRYPI_FIRMWARE && (ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709 || COMPILE_TEST)
++ help
++ Turn on virtual GPIO support for Broadcom BCM283X chips.
++
+ config GPIO_BRCMSTB
+ tristate "BRCMSTB GPIO support"
+ default y if ARCH_BRCMSTB
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -24,6 +24,7 @@ obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o
+ obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
+ obj-$(CONFIG_ATH79) += gpio-ath79.o
+ obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
++obj-$(CONFIG_GPIO_BCM_VIRT) += gpio-bcm-virt.o
+ obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
+ obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
+ obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o
+--- /dev/null
++++ b/drivers/gpio/gpio-bcm-virt.c
+@@ -0,0 +1,180 @@
++/*
++ * brcmvirt GPIO driver
++ *
++ * Copyright (C) 2012,2013 Dom Cobley <popcornmix@gmail.com>
++ * Based on gpio-clps711x.c by Alexander Shiyan <shc_work@mail.ru>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++
++#include <linux/err.h>
++#include <linux/gpio.h>
++#include <linux/module.h>
++#include <linux/basic_mmio_gpio.h>
++#include <linux/platform_device.h>
++#include <soc/bcm2835/raspberrypi-firmware.h>
++
++#define MODULE_NAME "brcmvirt-gpio"
++#define NUM_GPIO 2
++
++struct brcmvirt_gpio {
++ struct gpio_chip gc;
++ u32 __iomem *ts_base;
++ /* two packed 16-bit counts of enabled and disables
++ Allows host to detect a brief enable that was missed */
++ u32 enables_disables[NUM_GPIO];
++};
++
++static int brcmvirt_gpio_dir_in(struct gpio_chip *gc, unsigned off)
++{
++ struct brcmvirt_gpio *gpio;
++ gpio = container_of(gc, struct brcmvirt_gpio, gc);
++ return -EINVAL;
++}
++
++static int brcmvirt_gpio_dir_out(struct gpio_chip *gc, unsigned off, int val)
++{
++ struct brcmvirt_gpio *gpio;
++ gpio = container_of(gc, struct brcmvirt_gpio, gc);
++ return 0;
++}
++
++static int brcmvirt_gpio_get(struct gpio_chip *gc, unsigned off)
++{
++ struct brcmvirt_gpio *gpio;
++ unsigned v;
++ gpio = container_of(gc, struct brcmvirt_gpio, gc);
++ v = readl(gpio->ts_base + off);
++ return (v >> off) & 1;
++}
++
++static void brcmvirt_gpio_set(struct gpio_chip *gc, unsigned off, int val)
++{
++ struct brcmvirt_gpio *gpio;
++ u16 enables, disables;
++ s16 diff;
++ bool lit;
++ gpio = container_of(gc, struct brcmvirt_gpio, gc);
++ enables = gpio->enables_disables[off] >> 16;
++ disables = gpio->enables_disables[off] >> 0;
++ diff = (s16)(enables - disables);
++ lit = diff > 0;
++ if ((val && lit) || (!val && !lit))
++ return;
++ if (val)
++ enables++;
++ else
++ disables++;
++ diff = (s16)(enables - disables);
++ BUG_ON(diff != 0 && diff != 1);
++ gpio->enables_disables[off] = (enables << 16) | (disables << 0);
++ writel(gpio->enables_disables[off], gpio->ts_base + off);
++}
++
++static int brcmvirt_gpio_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct device_node *np = dev->of_node;
++ struct device_node *fw_node;
++ struct rpi_firmware *fw;
++ struct brcmvirt_gpio *ucb;
++ u32 gpiovirtbuf;
++ int err = 0;
++
++ fw_node = of_parse_phandle(np, "firmware", 0);
++ if (!fw_node) {
++ dev_err(dev, "Missing firmware node\n");
++ return -ENOENT;
++ }
++
++ fw = rpi_firmware_get(fw_node);
++ if (!fw)
++ return -EPROBE_DEFER;
++
++ err = rpi_firmware_property(fw, RPI_FIRMWARE_FRAMEBUFFER_GET_GPIOVIRTBUF,
++ &gpiovirtbuf, sizeof(gpiovirtbuf));
++
++ if (err) {
++ dev_err(dev, "Failed to get gpiovirtbuf\n");
++ goto err;
++ }
++
++ if (!gpiovirtbuf) {
++ dev_err(dev, "No virtgpio buffer\n");
++ err = -ENOENT;
++ goto err;
++ }
++
++ ucb = devm_kzalloc(dev, sizeof *ucb, GFP_KERNEL);
++ if (!ucb) {
++ err = -EINVAL;
++ goto err;
++ }
++
++ // mmap the physical memory
++ gpiovirtbuf &= ~0xc0000000;
++ ucb->ts_base = ioremap(gpiovirtbuf, 4096);
++ if (ucb->ts_base == NULL) {
++ dev_err(dev, "Failed to map physical address\n");
++ err = -ENOENT;
++ goto err;
++ }
++
++ ucb->gc.label = MODULE_NAME;
++ ucb->gc.owner = THIS_MODULE;
++ ucb->gc.dev = dev;
++ ucb->gc.of_node = np;
++ ucb->gc.base = 100;
++ ucb->gc.ngpio = NUM_GPIO;
++
++ ucb->gc.direction_input = brcmvirt_gpio_dir_in;
++ ucb->gc.direction_output = brcmvirt_gpio_dir_out;
++ ucb->gc.get = brcmvirt_gpio_get;
++ ucb->gc.set = brcmvirt_gpio_set;
++ ucb->gc.can_sleep = true;
++
++ err = gpiochip_add(&ucb->gc);
++ if (err)
++ goto err;
++
++ platform_set_drvdata(pdev, ucb);
++
++err:
++ return err;
++
++}
++
++static int brcmvirt_gpio_remove(struct platform_device *pdev)
++{
++ int err = 0;
++ struct brcmvirt_gpio *ucb = platform_get_drvdata(pdev);
++
++ gpiochip_remove(&ucb->gc);
++ iounmap(ucb->ts_base);
++ return err;
++}
++
++static const struct of_device_id __maybe_unused brcmvirt_gpio_ids[] = {
++ { .compatible = "brcm,bcm2835-virtgpio" },
++ { }
++};
++MODULE_DEVICE_TABLE(of, brcmvirt_gpio_ids);
++
++static struct platform_driver brcmvirt_gpio_driver = {
++ .driver = {
++ .name = MODULE_NAME,
++ .owner = THIS_MODULE,
++ .of_match_table = of_match_ptr(brcmvirt_gpio_ids),
++ },
++ .probe = brcmvirt_gpio_probe,
++ .remove = brcmvirt_gpio_remove,
++};
++module_platform_driver(brcmvirt_gpio_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Dom Cobley <popcornmix@gmail.com>");
++MODULE_DESCRIPTION("brcmvirt GPIO driver");
++MODULE_ALIAS("platform:brcmvirt-gpio");
+--- a/include/soc/bcm2835/raspberrypi-firmware.h
++++ b/include/soc/bcm2835/raspberrypi-firmware.h
+@@ -93,6 +93,7 @@ enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN = 0x0004000a,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_PALETTE = 0x0004000b,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_TOUCHBUF = 0x0004000f,
++ RPI_FIRMWARE_FRAMEBUFFER_GET_GPIOVIRTBUF = 0x00040010,
+ RPI_FIRMWARE_FRAMEBUFFER_RELEASE = 0x00048001,
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_PHYSICAL_WIDTH_HEIGHT = 0x00044003,
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_WIDTH_HEIGHT = 0x00044004,
diff --git a/target/linux/brcm2708/patches-4.4/0159-hci_h5-Don-t-send-conf_req-when-ACTIVE.patch b/target/linux/brcm2708/patches-4.4/0159-hci_h5-Don-t-send-conf_req-when-ACTIVE.patch
deleted file mode 100644
index 70e424b21a..0000000000
--- a/target/linux/brcm2708/patches-4.4/0159-hci_h5-Don-t-send-conf_req-when-ACTIVE.patch
+++ /dev/null
@@ -1,23 +0,0 @@
-From 20c4c47bca3674d746518b1cca1e066e46b52900 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Thu, 17 Dec 2015 13:37:07 +0000
-Subject: [PATCH 159/170] hci_h5: Don't send conf_req when ACTIVE
-
-Without this patch, a modem and kernel can continuously bombard each
-other with conf_req and conf_rsp messages, in a demented game of tag.
----
- drivers/bluetooth/hci_h5.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/drivers/bluetooth/hci_h5.c
-+++ b/drivers/bluetooth/hci_h5.c
-@@ -314,7 +314,8 @@ static void h5_handle_internal_rx(struct
- h5_link_control(hu, conf_req, 3);
- } else if (memcmp(data, conf_req, 2) == 0) {
- h5_link_control(hu, conf_rsp, 2);
-- h5_link_control(hu, conf_req, 3);
-+ if (h5->state != H5_ACTIVE)
-+ h5_link_control(hu, conf_req, 3);
- } else if (memcmp(data, conf_rsp, 2) == 0) {
- if (H5_HDR_LEN(hdr) > 2)
- h5->tx_win = (data[2] & 7);
diff --git a/target/linux/brcm2708/patches-4.4/0160-BCM270X_DT-Add-Pi3-support.patch b/target/linux/brcm2708/patches-4.4/0160-BCM270X_DT-Add-Pi3-support.patch
new file mode 100644
index 0000000000..e742f244ed
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0160-BCM270X_DT-Add-Pi3-support.patch
@@ -0,0 +1,323 @@
+From 195869e0239b2c28fc7f289ea94295ca57fb51a8 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Thu, 21 Jan 2016 17:57:49 +0000
+Subject: [PATCH 160/381] BCM270X_DT: Add Pi3 support
+
+---
+ arch/arm/boot/dts/Makefile | 1 +
+ arch/arm/boot/dts/bcm2710-rpi-3-b.dts | 192 ++++++++++++++++++++++++++++++++++
+ arch/arm/boot/dts/bcm2710.dtsi | 102 ++++++++++++++++++
+ 3 files changed, 295 insertions(+)
+ create mode 100644 arch/arm/boot/dts/bcm2710-rpi-3-b.dts
+ create mode 100644 arch/arm/boot/dts/bcm2710.dtsi
+
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -5,6 +5,7 @@ dtb-$(CONFIG_ARCH_BCM2708) += bcm2708-rp
+ dtb-$(CONFIG_ARCH_BCM2708) += bcm2708-rpi-cm.dtb
+ dtb-$(CONFIG_ARCH_BCM2835) += bcm2835-rpi-cm.dtb
+ dtb-$(CONFIG_ARCH_BCM2709) += bcm2709-rpi-2-b.dtb
++dtb-$(CONFIG_ARCH_BCM2709) += bcm2710-rpi-3-b.dtb
+
+ # Raspberry Pi
+ ifeq ($(CONFIG_ARCH_BCM2708),y)
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
+@@ -0,0 +1,192 @@
++/dts-v1/;
++
++#include "bcm2710.dtsi"
++
++/ {
++ compatible = "brcm,bcm2710","brcm,bcm2709";
++ model = "Raspberry Pi 3 Model B";
++};
++
++&gpio {
++ sdhost_pins: sdhost_pins {
++ brcm,pins = <48 49 50 51 52 53>;
++ brcm,function = <4>; /* alt0 */
++ };
++
++ spi0_pins: spi0_pins {
++ brcm,pins = <9 10 11>;
++ brcm,function = <4>; /* alt0 */
++ };
++
++ spi0_cs_pins: spi0_cs_pins {
++ brcm,pins = <8 7>;
++ brcm,function = <1>; /* output */
++ };
++
++ i2c0_pins: i2c0 {
++ brcm,pins = <0 1>;
++ brcm,function = <4>;
++ };
++
++ i2c1_pins: i2c1 {
++ brcm,pins = <2 3>;
++ brcm,function = <4>;
++ };
++
++ i2s_pins: i2s {
++ brcm,pins = <18 19 20 21>;
++ brcm,function = <4>; /* alt0 */
++ };
++
++ sdio_pins: sdio_pins {
++ brcm,pins = <34 35 36 37 38 39>;
++ brcm,function = <7>; // alt3 = SD1
++ brcm,pull = <0 2 2 2 2 2>;
++ };
++
++ bt_pins: bt_pins {
++ brcm,pins = <28 29 30 31 43>;
++ brcm,function = <6 6 6 6 4>; /* alt2:PCM alt0:GPCLK2 */
++ brcm,pull = <0 0 0 0 0>;
++ };
++
++ uart0_pins: uart0_pins {
++ brcm,pins = <32 33>;
++ brcm,function = <7>; /* alt3=UART0 */
++ brcm,pull = <0 0>;
++ };
++
++ uart1_pins: uart1_pins {
++ brcm,pins = <14 15>;
++ brcm,function = <2>; /* alt5=UART1 */
++ brcm,pull = <0 0>;
++ };
++};
++
++&sdhost {
++ pinctrl-names = "default";
++ pinctrl-0 = <&sdhost_pins>;
++ bus-width = <4>;
++ status = "okay";
++};
++
++&mmc {
++ pinctrl-names = "default";
++ pinctrl-0 = <&sdio_pins>;
++ non-removable;
++ bus-width = <4>;
++ status = "okay";
++ brcm,overclock-50 = <0>;
++};
++
++&soc {
++ virtgpio: virtgpio {
++ compatible = "brcm,bcm2835-virtgpio";
++ gpio-controller;
++ #gpio-cells = <2>;
++ firmware = <&firmware>;
++ status = "okay";
++ };
++};
++
++&fb {
++ status = "okay";
++};
++
++&uart0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&uart0_pins &bt_pins>;
++ status = "okay";
++};
++
++&uart1 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&uart1_pins>;
++ status = "okay";
++};
++
++&spi0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi0_pins &spi0_cs_pins>;
++ cs-gpios = <&gpio 8 1>, <&gpio 7 1>;
++
++ spidev@0{
++ compatible = "spidev";
++ reg = <0>; /* CE0 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <500000>;
++ };
++
++ spidev@1{
++ compatible = "spidev";
++ reg = <1>; /* CE1 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <500000>;
++ };
++};
++
++&i2c0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c0_pins>;
++ clock-frequency = <100000>;
++};
++
++&i2c1 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c1_pins>;
++ clock-frequency = <100000>;
++};
++
++&i2c2 {
++ clock-frequency = <100000>;
++};
++
++&i2s {
++ #sound-dai-cells = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2s_pins>;
++};
++
++&random {
++ status = "okay";
++};
++
++&leds {
++ act_led: act {
++ label = "led0";
++ linux,default-trigger = "mmc0";
++ gpios = <&virtgpio 0 0>;
++ };
++};
++
++/ {
++ chosen {
++ bootargs = "8250.nr_uarts=1";
++ };
++};
++
++/ {
++ __overrides__ {
++ uart0 = <&uart0>,"status";
++ uart0_clkrate = <&clk_uart0>,"clock-frequency:0";
++ i2s = <&i2s>,"status";
++ spi = <&spi0>,"status";
++ i2c0 = <&i2c0>,"status";
++ i2c1 = <&i2c1>,"status";
++ i2c2_iknowwhatimdoing = <&i2c2>,"status";
++ i2c0_baudrate = <&i2c0>,"clock-frequency:0";
++ i2c1_baudrate = <&i2c1>,"clock-frequency:0";
++ i2c2_baudrate = <&i2c2>,"clock-frequency:0";
++ core_freq = <&clk_core>,"clock-frequency:0";
++
++ act_led_gpio = <&act_led>,"gpios:4";
++ act_led_activelow = <&act_led>,"gpios:8";
++ act_led_trigger = <&act_led>,"linux,default-trigger";
++
++ audio = <&audio>,"status";
++ watchdog = <&watchdog>,"status";
++ random = <&random>,"status";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2710.dtsi
+@@ -0,0 +1,102 @@
++#include "bcm2708_common.dtsi"
++
++/ {
++ compatible = "brcm,bcm2710","brcm,bcm2709";
++ model = "BCM2710";
++
++ chosen {
++ /* No padding required - the boot loader can do that. */
++ bootargs = "";
++ };
++
++ soc {
++ ranges = <0x7e000000 0x3f000000 0x01000000>,
++ <0x40000000 0x40000000 0x00040000>;
++
++ local_intc: local_intc {
++ compatible = "brcm,bcm2836-l1-intc";
++ reg = <0x40000000 0x100>;
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ interrupt-parent = <&local_intc>;
++ };
++
++ arm-pmu {
++ compatible = "arm,cortex-a7-pmu";
++ interrupt-parent = <&local_intc>;
++ interrupts = <9>;
++ };
++
++ gpiomem {
++ compatible = "brcm,bcm2835-gpiomem";
++ reg = <0x7e200000 0x1000>;
++ status = "okay";
++ };
++
++ timer {
++ compatible = "arm,armv7-timer";
++ clock-frequency = <19200000>;
++ interrupt-parent = <&local_intc>;
++ interrupts = <0>, // PHYS_SECURE_PPI
++ <1>, // PHYS_NONSECURE_PPI
++ <3>, // VIRT_PPI
++ <2>; // HYP_PPI
++ always-on;
++ };
++
++ syscon@40000000 {
++ compatible = "brcm,bcm2836-arm-local", "syscon";
++ reg = <0x40000000 0x100>;
++ };
++ };
++
++ cpus: cpus {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ v7_cpu0: cpu@0 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a7";
++ reg = <0x000>;
++ clock-frequency = <800000000>;
++ };
++
++ v7_cpu1: cpu@1 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a7";
++ reg = <0x001>;
++ clock-frequency = <800000000>;
++ };
++
++ v7_cpu2: cpu@2 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a7";
++ reg = <0x002>;
++ clock-frequency = <800000000>;
++ };
++
++ v7_cpu3: cpu@3 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a7";
++ reg = <0x003>;
++ clock-frequency = <800000000>;
++ };
++ };
++
++ __overrides__ {
++ arm_freq = <&v7_cpu0>, "clock-frequency:0",
++ <&v7_cpu1>, "clock-frequency:0",
++ <&v7_cpu2>, "clock-frequency:0",
++ <&v7_cpu3>, "clock-frequency:0";
++ };
++};
++
++&watchdog {
++ status = "okay";
++};
++
++&intc {
++ compatible = "brcm,bcm2836-armctrl-ic";
++ interrupt-parent = <&local_intc>;
++ interrupts = <8>;
++};
diff --git a/target/linux/brcm2708/patches-4.4/0160-amba_pl011-Don-t-use-DT-aliases-for-numbering.patch b/target/linux/brcm2708/patches-4.4/0160-amba_pl011-Don-t-use-DT-aliases-for-numbering.patch
deleted file mode 100644
index 344fbd9103..0000000000
--- a/target/linux/brcm2708/patches-4.4/0160-amba_pl011-Don-t-use-DT-aliases-for-numbering.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-From 00dba6ec2ac004fc17075febd4504646eb3dc543 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Tue, 23 Feb 2016 17:26:48 +0000
-Subject: [PATCH 160/170] amba_pl011: Don't use DT aliases for numbering
-
-The pl011 driver looks for DT aliases of the form "serial<n>",
-and if found uses <n> as the device ID. This can cause
-/dev/ttyAMA0 to become /dev/ttyAMA1, which is confusing if the
-other serial port is provided by the 8250 driver which doesn't
-use the same logic.
----
- drivers/tty/serial/amba-pl011.c | 5 +++++
- 1 file changed, 5 insertions(+)
-
---- a/drivers/tty/serial/amba-pl011.c
-+++ b/drivers/tty/serial/amba-pl011.c
-@@ -2313,7 +2313,12 @@ static int pl011_setup_port(struct devic
- if (IS_ERR(base))
- return PTR_ERR(base);
-
-+ /* Don't use DT serial<n> aliases - it causes the device to
-+ be renumbered to ttyAMA1 if it is the second serial port in the
-+ system, even though the other one is ttyS0. The 8250 driver
-+ doesn't use this logic, so always remains ttyS0.
- index = pl011_probe_dt_alias(index, dev);
-+ */
-
- uap->old_cr = 0;
- uap->port.dev = dev;
diff --git a/target/linux/brcm2708/patches-4.4/0161-DT-Add-overlays-to-configure-I2C-pins.patch b/target/linux/brcm2708/patches-4.4/0161-DT-Add-overlays-to-configure-I2C-pins.patch
new file mode 100644
index 0000000000..75a510329c
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0161-DT-Add-overlays-to-configure-I2C-pins.patch
@@ -0,0 +1,134 @@
+From e4fc78fecfc8cf3cf04b252d0822b2ebd149c031 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <6by9@users.noreply.github.com>
+Date: Mon, 8 Feb 2016 23:49:41 +0000
+Subject: [PATCH 161/381] DT: Add overlays to configure I2C pins
+
+Lifted from
+https://www.raspberrypi.org/forums/viewtopic.php?f=107&t=120938&p=825883
+so not claiming this to be my own work.
+Adds overlays i2c0-bcm2708 and i2c1-bcm2708 that allow the pin
+allocations for i2c-0 and i2c-1 to be changed.
+---
+ arch/arm/boot/dts/overlays/Makefile | 2 ++
+ arch/arm/boot/dts/overlays/README | 16 ++++++++++
+ .../arm/boot/dts/overlays/i2c0-bcm2708-overlay.dts | 36 +++++++++++++++++++++
+ .../arm/boot/dts/overlays/i2c1-bcm2708-overlay.dts | 37 ++++++++++++++++++++++
+ 4 files changed, 91 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/i2c0-bcm2708-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/i2c1-bcm2708-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -29,6 +29,8 @@ dtb-$(RPI_DT_OVERLAYS) += hy28a-overlay.
+ dtb-$(RPI_DT_OVERLAYS) += hy28b-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += i2c-rtc-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += i2c-gpio-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += i2c0-bcm2708-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += i2c1-bcm2708-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += i2s-mmap-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += iqaudio-dac-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += iqaudio-dacplus-overlay.dtb
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -371,6 +371,22 @@ Params: ds1307 Select t
+ pcf8563 Select the PCF8563 device
+
+
++Name: i2c0-bcm2708
++Info: Enable the i2c_bcm2708 driver for the i2c0 bus
++Load: dtoverlay=i2c0-bcm2708,<param>=<val>
++Params: sda0_pin GPIO pin for SDA0 (0, 28 [or 44] - default 0)
++ scl0_pin GPIO pin for SCL0 (1, 29 [or 45] - default 1)
++
++
++Name: i2c1-bcm2708
++Info: Enable the i2c_bcm2708 driver for the i2c1 bus
++Load: dtoverlay=i2c1-bcm2708,<param>=<val>
++Params: sda1_pin GPIO pin for SDA1 (2 or 44 - default 2)
++ scl1_pin GPIO pin for SCL1 (3 or 45 - default 3)
++ pin_func Alternative pin function (4 (alt0), 6 (alt2) -
++ default 4)
++
++
+ Name: i2s-mmap
+ Info: Enables mmap support in the bcm2708-i2s driver
+ Load: dtoverlay=i2s-mmap
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/i2c0-bcm2708-overlay.dts
+@@ -0,0 +1,36 @@
++/*
++ * Device tree overlay for i2c_bcm2708, i2c0 bus
++ *
++ * Compile:
++ * dtc -@ -I dts -O dtb -o i2c0-bcm2708-overlay.dtb i2c0-bcm2708-overlay.dts
++ */
++
++/dts-v1/;
++/plugin/;
++
++/{
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&i2c0>;
++ __overlay__ {
++ pinctrl-0 = <&i2c0_pins>;
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ i2c0_pins: i2c0 {
++ brcm,pins = <0 1>;
++ brcm,function = <4>; /* alt0 */
++ };
++ };
++ };
++
++ __overrides__ {
++ sda0_pin = <&i2c0_pins>,"brcm,pins:0";
++ scl0_pin = <&i2c0_pins>,"brcm,pins:4";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/i2c1-bcm2708-overlay.dts
+@@ -0,0 +1,37 @@
++/*
++ * Device tree overlay for i2c_bcm2708, i2c1 bus
++ *
++ * Compile:
++ * dtc -@ -I dts -O dtb -o i2c1-bcm2708-overlay.dtb i2c1-bcm2708-overlay.dts
++ */
++
++/dts-v1/;
++/plugin/;
++
++/{
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&i2c1>;
++ __overlay__ {
++ pinctrl-0 = <&i2c1_pins>;
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ i2c1_pins: i2c1 {
++ brcm,pins = <2 3>;
++ brcm,function = <4>; /* alt0 */
++ };
++ };
++ };
++
++ __overrides__ {
++ sda1_pin = <&i2c1_pins>,"brcm,pins:0";
++ scl1_pin = <&i2c1_pins>,"brcm,pins:4";
++ pin_func = <&i2c1_pins>,"brcm,function:0";
++ };
++};
diff --git a/target/linux/brcm2708/patches-4.4/0161-clk-bcm2835-Add-bindings-for-the-auxiliary-periphera.patch b/target/linux/brcm2708/patches-4.4/0161-clk-bcm2835-Add-bindings-for-the-auxiliary-periphera.patch
deleted file mode 100644
index 1bee99e79b..0000000000
--- a/target/linux/brcm2708/patches-4.4/0161-clk-bcm2835-Add-bindings-for-the-auxiliary-periphera.patch
+++ /dev/null
@@ -1,72 +0,0 @@
-From 95136c932ac4433a6a50d394817812f8eb2cc914 Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Tue, 15 Dec 2015 15:35:57 -0800
-Subject: [PATCH 161/170] clk: bcm2835: Add bindings for the auxiliary
- peripheral clock gates.
-
-These will be used for enabling UART1, SPI1, and SPI2.
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
-Acked-by: Rob Herring <robh@kernel.org>
-Signed-off-by: Michael Turquette <mturquette@baylibre.com>
----
- .../bindings/clock/brcm,bcm2835-aux-clock.txt | 31 ++++++++++++++++++++++
- include/dt-bindings/clock/bcm2835-aux.h | 17 ++++++++++++
- 2 files changed, 48 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/clock/brcm,bcm2835-aux-clock.txt
- create mode 100644 include/dt-bindings/clock/bcm2835-aux.h
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/clock/brcm,bcm2835-aux-clock.txt
-@@ -0,0 +1,31 @@
-+Broadcom BCM2835 auxiliary peripheral support
-+
-+This binding uses the common clock binding:
-+ Documentation/devicetree/bindings/clock/clock-bindings.txt
-+
-+The auxiliary peripherals (UART, SPI1, and SPI2) have a small register
-+area controlling clock gating to the peripherals, and providing an IRQ
-+status register.
-+
-+Required properties:
-+- compatible: Should be "brcm,bcm2835-aux"
-+- #clock-cells: Should be <1>. The permitted clock-specifier values can be
-+ found in include/dt-bindings/clock/bcm2835-aux.h
-+- reg: Specifies base physical address and size of the registers
-+- clocks: The parent clock phandle
-+
-+Example:
-+
-+ clocks: cprman@7e101000 {
-+ compatible = "brcm,bcm2835-cprman";
-+ #clock-cells = <1>;
-+ reg = <0x7e101000 0x2000>;
-+ clocks = <&clk_osc>;
-+ };
-+
-+ aux: aux@0x7e215004 {
-+ compatible = "brcm,bcm2835-aux";
-+ #clock-cells = <1>;
-+ reg = <0x7e215000 0x8>;
-+ clocks = <&clocks BCM2835_CLOCK_VPU>;
-+ };
---- /dev/null
-+++ b/include/dt-bindings/clock/bcm2835-aux.h
-@@ -0,0 +1,17 @@
-+/*
-+ * Copyright (C) 2015 Broadcom Corporation
-+ *
-+ * 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 version 2.
-+ *
-+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
-+ * kind, whether express or implied; without even the implied warranty
-+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#define BCM2835_AUX_CLOCK_UART 0
-+#define BCM2835_AUX_CLOCK_SPI1 1
-+#define BCM2835_AUX_CLOCK_SPI2 2
-+#define BCM2835_AUX_CLOCK_COUNT 3
diff --git a/target/linux/brcm2708/patches-4.4/0162-bcm2835-camera-fix-a-bug-in-computation-of-frame-tim.patch b/target/linux/brcm2708/patches-4.4/0162-bcm2835-camera-fix-a-bug-in-computation-of-frame-tim.patch
new file mode 100644
index 0000000000..47c0094a75
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0162-bcm2835-camera-fix-a-bug-in-computation-of-frame-tim.patch
@@ -0,0 +1,23 @@
+From bece84be8a851aca4baff1b63a8a2c92866754d5 Mon Sep 17 00:00:00 2001
+From: Dhiraj Goel <dhiraj.goel@gmail.com>
+Date: Thu, 3 Mar 2016 21:10:50 -0800
+Subject: [PATCH 162/381] bcm2835-camera: fix a bug in computation of frame
+ timestamp
+
+Fixes #1318
+---
+ drivers/media/platform/bcm2835/bcm2835-camera.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/media/platform/bcm2835/bcm2835-camera.c
++++ b/drivers/media/platform/bcm2835/bcm2835-camera.c
+@@ -360,8 +360,7 @@ static void buffer_cb(struct vchiq_mmal_
+ div =
+ div_u64_rem(runtime_us, USEC_PER_SEC, &rem);
+ buf->vb.timestamp.tv_sec =
+- dev->capture.kernel_start_ts.tv_sec - 1 +
+- div;
++ dev->capture.kernel_start_ts.tv_sec + div;
+ buf->vb.timestamp.tv_usec =
+ dev->capture.kernel_start_ts.tv_usec + rem;
+
diff --git a/target/linux/brcm2708/patches-4.4/0162-clk-bcm2835-Add-a-driver-for-the-auxiliary-periphera.patch b/target/linux/brcm2708/patches-4.4/0162-clk-bcm2835-Add-a-driver-for-the-auxiliary-periphera.patch
deleted file mode 100644
index 3e9667a900..0000000000
--- a/target/linux/brcm2708/patches-4.4/0162-clk-bcm2835-Add-a-driver-for-the-auxiliary-periphera.patch
+++ /dev/null
@@ -1,118 +0,0 @@
-From 924276b92ff47f0e778a9405d00637be4ca88736 Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Tue, 15 Dec 2015 15:35:58 -0800
-Subject: [PATCH 162/170] clk: bcm2835: Add a driver for the auxiliary
- peripheral clock gates.
-
-There are a pair of SPI masters and a mini UART that were last minute
-additions. As a result, they didn't get integrated in the same way as
-the other gates off of the VPU clock in CPRMAN.
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
-Signed-off-by: Michael Turquette <mturquette@baylibre.com>
-
-updated Makefile to preserve the rasoberry pi architectures
----
- drivers/clk/bcm/Makefile | 1 +
- drivers/clk/bcm/clk-bcm2835-aux.c | 85 +++++++++++++++++++++++++++++++++++++++
- 2 files changed, 86 insertions(+)
- create mode 100644 drivers/clk/bcm/clk-bcm2835-aux.c
-
---- a/drivers/clk/bcm/Makefile
-+++ b/drivers/clk/bcm/Makefile
-@@ -4,6 +4,7 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281
- obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o
- obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-asiu.o
- obj-$(CONFIG_ARCH_BCM2835)$(CONFIG_ARCH_BCM2708)$(CONFIG_ARCH_BCM2709) += clk-bcm2835.o
-+obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835-aux.o
- obj-$(CONFIG_COMMON_CLK_IPROC) += clk-ns2.o
- obj-$(CONFIG_ARCH_BCM_CYGNUS) += clk-cygnus.o
- obj-$(CONFIG_ARCH_BCM_NSP) += clk-nsp.o
---- /dev/null
-+++ b/drivers/clk/bcm/clk-bcm2835-aux.c
-@@ -0,0 +1,85 @@
-+/*
-+ * Copyright (C) 2015 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.
-+ */
-+
-+#include <linux/clk.h>
-+#include <linux/clk-provider.h>
-+#include <linux/clk/bcm2835.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <dt-bindings/clock/bcm2835-aux.h>
-+
-+#define BCM2835_AUXIRQ 0x00
-+#define BCM2835_AUXENB 0x04
-+
-+static int bcm2835_aux_clk_probe(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ struct clk_onecell_data *onecell;
-+ const char *parent;
-+ struct clk *parent_clk;
-+ struct resource *res;
-+ void __iomem *reg, *gate;
-+
-+ parent_clk = devm_clk_get(dev, NULL);
-+ if (IS_ERR(parent_clk))
-+ return PTR_ERR(parent_clk);
-+ parent = __clk_get_name(parent_clk);
-+
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ reg = devm_ioremap_resource(dev, res);
-+ if (!reg)
-+ return -ENODEV;
-+
-+ onecell = devm_kmalloc(dev, sizeof(*onecell), GFP_KERNEL);
-+ if (!onecell)
-+ return -ENOMEM;
-+ onecell->clk_num = BCM2835_AUX_CLOCK_COUNT;
-+ onecell->clks = devm_kcalloc(dev, BCM2835_AUX_CLOCK_COUNT,
-+ sizeof(*onecell->clks), GFP_KERNEL);
-+ if (!onecell->clks)
-+ return -ENOMEM;
-+
-+ gate = reg + BCM2835_AUXENB;
-+ onecell->clks[BCM2835_AUX_CLOCK_UART] =
-+ clk_register_gate(dev, "aux_uart", parent, 0, gate, 0, 0, NULL);
-+
-+ onecell->clks[BCM2835_AUX_CLOCK_SPI1] =
-+ clk_register_gate(dev, "aux_spi1", parent, 0, gate, 1, 0, NULL);
-+
-+ onecell->clks[BCM2835_AUX_CLOCK_SPI2] =
-+ clk_register_gate(dev, "aux_spi2", parent, 0, gate, 2, 0, NULL);
-+
-+ of_clk_add_provider(pdev->dev.of_node, of_clk_src_onecell_get, onecell);
-+
-+ return 0;
-+}
-+
-+static const struct of_device_id bcm2835_aux_clk_of_match[] = {
-+ { .compatible = "brcm,bcm2835-aux", },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(of, bcm2835_aux_clk_of_match);
-+
-+static struct platform_driver bcm2835_aux_clk_driver = {
-+ .driver = {
-+ .name = "bcm2835-aux-clk",
-+ .of_match_table = bcm2835_aux_clk_of_match,
-+ },
-+ .probe = bcm2835_aux_clk_probe,
-+};
-+builtin_platform_driver(bcm2835_aux_clk_driver);
-+
-+MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
-+MODULE_DESCRIPTION("BCM2835 auxiliary peripheral clock driver");
-+MODULE_LICENSE("GPL v2");
diff --git a/target/linux/brcm2708/patches-4.4/0163-Aux-SPI-1-2-implementation.patch b/target/linux/brcm2708/patches-4.4/0163-Aux-SPI-1-2-implementation.patch
deleted file mode 100644
index c47f3bd5b1..0000000000
--- a/target/linux/brcm2708/patches-4.4/0163-Aux-SPI-1-2-implementation.patch
+++ /dev/null
@@ -1,700 +0,0 @@
-From 43477e669f736f6da34afbd8a96683b239b1fd1f Mon Sep 17 00:00:00 2001
-From: Fraser <github@frasersdev.net>
-Date: Tue, 23 Feb 2016 10:04:37 +1100
-Subject: [PATCH 163/170] Aux SPI 1&2 implementation
-
-Adds aux spi 1 & 2 devices to compatible raspberry PIs.
-* Minor config of the driver build environment to ensure they get built
-for CONFIG_ARCH_BCM2708 & CONFIG_ARCH_BCM2709 devices.
-* Adds the aux spi driver into the defconfigs as a module.
-* Adds the auxiliary and spi1/2 devices into the device tree in a
-disabled state
-* Provides decide tree overlays which enables the devices and gives
-users a degree of control over how they are setup.
----
- arch/arm/boot/dts/bcm2708_common.dtsi | 34 ++++++++-
- arch/arm/boot/dts/overlays/Makefile | 6 ++
- arch/arm/boot/dts/overlays/README | 99 +++++++++++++++++++++++++
- arch/arm/boot/dts/overlays/spi1-1cs-overlay.dts | 57 ++++++++++++++
- arch/arm/boot/dts/overlays/spi1-2cs-overlay.dts | 69 +++++++++++++++++
- arch/arm/boot/dts/overlays/spi1-3cs-overlay.dts | 81 ++++++++++++++++++++
- arch/arm/boot/dts/overlays/spi2-1cs-overlay.dts | 57 ++++++++++++++
- arch/arm/boot/dts/overlays/spi2-2cs-overlay.dts | 69 +++++++++++++++++
- arch/arm/boot/dts/overlays/spi2-3cs-overlay.dts | 81 ++++++++++++++++++++
- arch/arm/configs/bcm2709_defconfig | 1 +
- arch/arm/configs/bcmrpi_defconfig | 1 +
- drivers/clk/bcm/Makefile | 2 +-
- drivers/spi/Kconfig | 2 +-
- 13 files changed, 556 insertions(+), 3 deletions(-)
- create mode 100644 arch/arm/boot/dts/overlays/spi1-1cs-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/spi1-2cs-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/spi1-3cs-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/spi2-1cs-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/spi2-2cs-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/spi2-3cs-overlay.dts
-
---- a/arch/arm/boot/dts/bcm2708_common.dtsi
-+++ b/arch/arm/boot/dts/bcm2708_common.dtsi
-@@ -1,3 +1,4 @@
-+#include <dt-bindings/clock/bcm2835-aux.h>
- #include "skeleton.dtsi"
-
- / {
-@@ -5,6 +6,7 @@
-
- aliases {
- audio = &audio;
-+ aux = &aux;
- sound = &sound;
- soc = &soc;
- dma = &dma;
-@@ -19,6 +21,8 @@
- spi0 = &spi0;
- i2c0 = &i2c0;
- uart1 = &uart1;
-+ spi1 = &spi1;
-+ spi2 = &spi2;
- mmc = &mmc;
- i2c1 = &i2c1;
- i2c2 = &i2c2;
-@@ -186,6 +190,14 @@
- status = "disabled";
- };
-
-+ aux: aux@0x7e215004 {
-+ compatible = "brcm,bcm2835-aux";
-+ #clock-cells = <1>;
-+ reg = <0x7e215000 0x8>;
-+ clocks = <&clk_core>;
-+ status = "disabled";
-+ };
-+
- uart1: uart@7e215040 {
- compatible = "brcm,bcm2835-aux-uart", "ns16550";
- reg = <0x7e215040 0x40>;
-@@ -194,7 +206,27 @@
- reg-shift = <2>;
- no-loopback-test;
- status = "disabled";
-- };
-+ };
-+
-+ spi1: spi@7e215080 {
-+ compatible = "brcm,bcm2835-aux-spi";
-+ reg = <0x7e215080 0x40>, <0x7e215000 0x8>;
-+ interrupts = <1 29>;
-+ clocks = <&aux BCM2835_AUX_CLOCK_SPI1>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ spi2: spi@7e2150C0 {
-+ compatible = "brcm,bcm2835-aux-spi";
-+ reg = <0x7e2150C0 0x40>, <0x7e215000 0x8>;
-+ interrupts = <1 29>;
-+ clocks = <&aux BCM2835_AUX_CLOCK_SPI2>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-
- mmc: mmc@7e300000 {
- compatible = "brcm,bcm2835-mmc";
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -57,6 +57,12 @@ dtb-$(RPI_DT_OVERLAYS) += sdtweak-overla
- dtb-$(RPI_DT_OVERLAYS) += smi-dev-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += smi-nand-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += smi-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += spi1-1cs-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += spi1-2cs-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += spi1-3cs-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += spi2-1cs-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += spi2-2cs-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += spi2-3cs-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += spi-gpio35-39-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += tinylcd35-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += uart1-overlay.dtb
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -713,6 +713,105 @@ Load: dtoverlay=spi-gpio35-39
- Params: <None>
-
-
-+Name: spi1-1cs
-+Info: Enables spi1 with a single chip select (CS) line and associated spidev
-+ dev node. The gpio pin number for the CS line and spidev device node
-+ creation are configurable.
-+ N.B.: spi1 is only accessible on devices with a 40pin header, eg:
-+ A+, B+, Zero and PI2 B; as well as the Compute Module.
-+Load: dtoverlay=spi1-1cs,<param>=<val>
-+Params: cs0_pin GPIO pin for CS0 (default 18 - BCM SPI1_CE0).
-+ cs0_spidev Set to 'disabled' to stop the creation of a
-+ userspace device node /dev/spidev1.0 (default
-+ is 'okay' or enabled).
-+
-+
-+Name: spi1-2cs
-+Info: Enables spi1 with two chip select (CS) lines and associated spidev
-+ dev nodes. The gpio pin numbers for the CS lines and spidev device node
-+ creation are configurable.
-+ N.B.: spi1 is only accessible on devices with a 40pin header, eg:
-+ A+, B+, Zero and PI2 B; as well as the Compute Module.
-+Load: dtoverlay=spi1-2cs,<param>=<val>
-+Params: cs0_pin GPIO pin for CS0 (default 18 - BCM SPI1_CE0).
-+ cs1_pin GPIO pin for CS1 (default 17 - BCM SPI1_CE1).
-+ cs0_spidev Set to 'disabled' to stop the creation of a
-+ userspace device node /dev/spidev1.0 (default
-+ is 'okay' or enabled).
-+ cs1_spidev Set to 'disabled' to stop the creation of a
-+ userspace device node /dev/spidev1.1 (default
-+ is 'okay' or enabled).
-+
-+
-+Name: spi1-3cs
-+Info: Enables spi1 with three chip select (CS) lines and associated spidev
-+ dev nodes. The gpio pin numbers for the CS lines and spidev device node
-+ creation are configurable.
-+ N.B.: spi1 is only accessible on devices with a 40pin header, eg:
-+ A+, B+, Zero and PI2 B; as well as the Compute Module.
-+Load: dtoverlay=spi1-3cs,<param>=<val>
-+Params: cs0_pin GPIO pin for CS0 (default 18 - BCM SPI1_CE0).
-+ cs1_pin GPIO pin for CS1 (default 17 - BCM SPI1_CE1).
-+ cs2_pin GPIO pin for CS2 (default 16 - BCM SPI1_CE2).
-+ cs0_spidev Set to 'disabled' to stop the creation of a
-+ userspace device node /dev/spidev1.0 (default
-+ is 'okay' or enabled).
-+ cs1_spidev Set to 'disabled' to stop the creation of a
-+ userspace device node /dev/spidev1.1 (default
-+ is 'okay' or enabled).
-+ cs2_spidev Set to 'disabled' to stop the creation of a
-+ userspace device node /dev/spidev1.2 (default
-+ is 'okay' or enabled).
-+
-+
-+Name: spi2-1cs
-+Info: Enables spi2 with a single chip select (CS) line and associated spidev
-+ dev node. The gpio pin number for the CS line and spidev device node
-+ creation are configurable.
-+ N.B.: spi2 is only accessible with the Compute Module.
-+Load: dtoverlay=spi2-1cs,<param>=<val>
-+Params: cs0_pin GPIO pin for CS0 (default 43 - BCM SPI2_CE0).
-+ cs0_spidev Set to 'disabled' to stop the creation of a
-+ userspace device node /dev/spidev2.0 (default
-+ is 'okay' or enabled).
-+
-+
-+Name: spi2-2cs
-+Info: Enables spi2 with two chip select (CS) lines and associated spidev
-+ dev nodes. The gpio pin numbers for the CS lines and spidev device node
-+ creation are configurable.
-+ N.B.: spi2 is only accessible with the Compute Module.
-+Load: dtoverlay=spi2-2cs,<param>=<val>
-+Params: cs0_pin GPIO pin for CS0 (default 43 - BCM SPI2_CE0).
-+ cs1_pin GPIO pin for CS1 (default 44 - BCM SPI2_CE1).
-+ cs0_spidev Set to 'disabled' to stop the creation of a
-+ userspace device node /dev/spidev2.0 (default
-+ is 'okay' or enabled).
-+ cs1_spidev Set to 'disabled' to stop the creation of a
-+ userspace device node /dev/spidev2.1 (default
-+ is 'okay' or enabled).
-+
-+
-+Name: spi2-3cs
-+Info: Enables spi2 with three chip select (CS) lines and associated spidev
-+ dev nodes. The gpio pin numbers for the CS lines and spidev device node
-+ creation are configurable.
-+ N.B.: spi2 is only accessible with the Compute Module.
-+Load: dtoverlay=spi2-3cs,<param>=<val>
-+Params: cs0_pin GPIO pin for CS0 (default 43 - BCM SPI2_CE0).
-+ cs1_pin GPIO pin for CS1 (default 44 - BCM SPI2_CE1).
-+ cs2_pin GPIO pin for CS2 (default 45 - BCM SPI2_CE2).
-+ cs0_spidev Set to 'disabled' to stop the creation of a
-+ userspace device node /dev/spidev2.0 (default
-+ is 'okay' or enabled).
-+ cs1_spidev Set to 'disabled' to stop the creation of a
-+ userspace device node /dev/spidev2.1 (default
-+ is 'okay' or enabled).
-+ cs2_spidev Set to 'disabled' to stop the creation of a
-+ userspace device node /dev/spidev2.2 (default
-+ is 'okay' or enabled).
-+
-+
- Name: tinylcd35
- Info: 3.5" Color TFT Display by www.tinylcd.com
- Options: Touch, RTC, keypad
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/spi1-1cs-overlay.dts
-@@ -0,0 +1,57 @@
-+/dts-v1/;
-+/plugin/;
-+
-+
-+/ {
-+ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+
-+ fragment@0 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ spi1_pins: spi1_pins {
-+ brcm,pins = <19 20 21>;
-+ brcm,function = <3>; /* alt4 */
-+ };
-+
-+ spi1_cs_pins: spi1_cs_pins {
-+ brcm,pins = <18>;
-+ brcm,function = <1>; /* output */
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&spi1>;
-+ frag1: __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&spi1_pins &spi1_cs_pins>;
-+ cs-gpios = <&gpio 18 1>;
-+ status = "okay";
-+
-+ spidev1_0: spidev@0 {
-+ compatible = "spidev";
-+ reg = <0>; /* CE0 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <500000>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&aux>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ __overrides__ {
-+ cs0_pin = <&spi1_cs_pins>,"brcm,pins:0",
-+ <&frag1>,"cs-gpios:4";
-+ cs0_spidev = <&spidev1_0>,"status";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/spi1-2cs-overlay.dts
-@@ -0,0 +1,69 @@
-+/dts-v1/;
-+/plugin/;
-+
-+
-+/ {
-+ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+
-+ fragment@0 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ spi1_pins: spi1_pins {
-+ brcm,pins = <19 20 21>;
-+ brcm,function = <3>; /* alt4 */
-+ };
-+
-+ spi1_cs_pins: spi1_cs_pins {
-+ brcm,pins = <18 17>;
-+ brcm,function = <1>; /* output */
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&spi1>;
-+ frag1: __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&spi1_pins &spi1_cs_pins>;
-+ cs-gpios = <&gpio 18 1>, <&gpio 17 1>;
-+ status = "okay";
-+
-+ spidev1_0: spidev@0 {
-+ compatible = "spidev";
-+ reg = <0>; /* CE0 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <500000>;
-+ status = "okay";
-+ };
-+
-+ spidev1_1: spidev@1 {
-+ compatible = "spidev";
-+ reg = <1>; /* CE1 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <500000>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&aux>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ __overrides__ {
-+ cs0_pin = <&spi1_cs_pins>,"brcm,pins:0",
-+ <&frag1>,"cs-gpios:4";
-+ cs1_pin = <&spi1_cs_pins>,"brcm,pins:4",
-+ <&frag1>,"cs-gpios:16";
-+ cs0_spidev = <&spidev1_0>,"status";
-+ cs1_spidev = <&spidev1_1>,"status";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/spi1-3cs-overlay.dts
-@@ -0,0 +1,81 @@
-+/dts-v1/;
-+/plugin/;
-+
-+
-+/ {
-+ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+
-+ fragment@0 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ spi1_pins: spi1_pins {
-+ brcm,pins = <19 20 21>;
-+ brcm,function = <3>; /* alt4 */
-+ };
-+
-+ spi1_cs_pins: spi1_cs_pins {
-+ brcm,pins = <18 17 16>;
-+ brcm,function = <1>; /* output */
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&spi1>;
-+ frag1: __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&spi1_pins &spi1_cs_pins>;
-+ cs-gpios = <&gpio 18 1>, <&gpio 17 1>, <&gpio 16 1>;
-+ status = "okay";
-+
-+ spidev1_0: spidev@0 {
-+ compatible = "spidev";
-+ reg = <0>; /* CE0 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <500000>;
-+ status = "okay";
-+ };
-+
-+ spidev1_1: spidev@1 {
-+ compatible = "spidev";
-+ reg = <1>; /* CE1 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <500000>;
-+ status = "okay";
-+ };
-+
-+ spidev1_2: spidev@2 {
-+ compatible = "spidev";
-+ reg = <2>; /* CE2 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <500000>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&aux>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ __overrides__ {
-+ cs0_pin = <&spi1_cs_pins>,"brcm,pins:0",
-+ <&frag1>,"cs-gpios:4";
-+ cs1_pin = <&spi1_cs_pins>,"brcm,pins:4",
-+ <&frag1>,"cs-gpios:16";
-+ cs2_pin = <&spi1_cs_pins>,"brcm,pins:8",
-+ <&frag1>,"cs-gpios:28";
-+ cs0_spidev = <&spidev1_0>,"status";
-+ cs1_spidev = <&spidev1_1>,"status";
-+ cs2_spidev = <&spidev1_2>,"status";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/spi2-1cs-overlay.dts
-@@ -0,0 +1,57 @@
-+/dts-v1/;
-+/plugin/;
-+
-+
-+/ {
-+ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+
-+ fragment@0 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ spi2_pins: spi2_pins {
-+ brcm,pins = <40 41 42>;
-+ brcm,function = <3>; /* alt4 */
-+ };
-+
-+ spi2_cs_pins: spi2_cs_pins {
-+ brcm,pins = <43>;
-+ brcm,function = <1>; /* output */
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&spi2>;
-+ frag1: __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&spi2_pins &spi2_cs_pins>;
-+ cs-gpios = <&gpio 43 1>;
-+ status = "okay";
-+
-+ spidev2_0: spidev@0 {
-+ compatible = "spidev";
-+ reg = <0>; /* CE0 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <500000>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&aux>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ __overrides__ {
-+ cs0_pin = <&spi2_cs_pins>,"brcm,pins:0",
-+ <&frag1>,"cs-gpios:4";
-+ cs0_spidev = <&spidev2_0>,"status";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/spi2-2cs-overlay.dts
-@@ -0,0 +1,69 @@
-+/dts-v1/;
-+/plugin/;
-+
-+
-+/ {
-+ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+
-+ fragment@0 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ spi2_pins: spi2_pins {
-+ brcm,pins = <40 41 42>;
-+ brcm,function = <3>; /* alt4 */
-+ };
-+
-+ spi2_cs_pins: spi2_cs_pins {
-+ brcm,pins = <43 44>;
-+ brcm,function = <1>; /* output */
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&spi2>;
-+ frag1: __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&spi2_pins &spi2_cs_pins>;
-+ cs-gpios = <&gpio 43 1>, <&gpio 44 1>;
-+ status = "okay";
-+
-+ spidev2_0: spidev@0 {
-+ compatible = "spidev";
-+ reg = <0>; /* CE0 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <500000>;
-+ status = "okay";
-+ };
-+
-+ spidev2_1: spidev@1 {
-+ compatible = "spidev";
-+ reg = <1>; /* CE1 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <500000>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&aux>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ __overrides__ {
-+ cs0_pin = <&spi2_cs_pins>,"brcm,pins:0",
-+ <&frag1>,"cs-gpios:4";
-+ cs1_pin = <&spi2_cs_pins>,"brcm,pins:4",
-+ <&frag1>,"cs-gpios:16";
-+ cs0_spidev = <&spidev2_0>,"status";
-+ cs1_spidev = <&spidev2_1>,"status";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/spi2-3cs-overlay.dts
-@@ -0,0 +1,81 @@
-+/dts-v1/;
-+/plugin/;
-+
-+
-+/ {
-+ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+
-+ fragment@0 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ spi2_pins: spi2_pins {
-+ brcm,pins = <40 41 42>;
-+ brcm,function = <3>; /* alt4 */
-+ };
-+
-+ spi2_cs_pins: spi2_cs_pins {
-+ brcm,pins = <43 44 45>;
-+ brcm,function = <1>; /* output */
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&spi2>;
-+ frag1: __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&spi2_pins &spi2_cs_pins>;
-+ cs-gpios = <&gpio 43 1>, <&gpio 44 1>, <&gpio 45 1>;
-+ status = "okay";
-+
-+ spidev2_0: spidev@0 {
-+ compatible = "spidev";
-+ reg = <0>; /* CE0 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <500000>;
-+ status = "okay";
-+ };
-+
-+ spidev2_1: spidev@1 {
-+ compatible = "spidev";
-+ reg = <1>; /* CE1 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <500000>;
-+ status = "okay";
-+ };
-+
-+ spidev2_2: spidev@2 {
-+ compatible = "spidev";
-+ reg = <2>; /* CE2 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <500000>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&aux>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ __overrides__ {
-+ cs0_pin = <&spi2_cs_pins>,"brcm,pins:0",
-+ <&frag1>,"cs-gpios:4";
-+ cs1_pin = <&spi2_cs_pins>,"brcm,pins:4",
-+ <&frag1>,"cs-gpios:16";
-+ cs2_pin = <&spi2_cs_pins>,"brcm,pins:8",
-+ <&frag1>,"cs-gpios:28";
-+ cs0_spidev = <&spidev2_0>,"status";
-+ cs1_spidev = <&spidev2_1>,"status";
-+ cs2_spidev = <&spidev2_2>,"status";
-+ };
-+};
---- a/arch/arm/configs/bcm2709_defconfig
-+++ b/arch/arm/configs/bcm2709_defconfig
-@@ -601,6 +601,7 @@ CONFIG_I2C_BCM2708=m
- CONFIG_I2C_GPIO=m
- CONFIG_SPI=y
- CONFIG_SPI_BCM2835=m
-+CONFIG_SPI_BCM2835AUX=m
- CONFIG_SPI_SPIDEV=y
- CONFIG_PPS=m
- CONFIG_PPS_CLIENT_LDISC=m
---- a/arch/arm/configs/bcmrpi_defconfig
-+++ b/arch/arm/configs/bcmrpi_defconfig
-@@ -593,6 +593,7 @@ CONFIG_I2C_BCM2708=m
- CONFIG_I2C_GPIO=m
- CONFIG_SPI=y
- CONFIG_SPI_BCM2835=m
-+CONFIG_SPI_BCM2835AUX=m
- CONFIG_SPI_SPIDEV=y
- CONFIG_PPS=m
- CONFIG_PPS_CLIENT_LDISC=m
---- a/drivers/clk/bcm/Makefile
-+++ b/drivers/clk/bcm/Makefile
-@@ -4,7 +4,7 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281
- obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o
- obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-asiu.o
- obj-$(CONFIG_ARCH_BCM2835)$(CONFIG_ARCH_BCM2708)$(CONFIG_ARCH_BCM2709) += clk-bcm2835.o
--obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835-aux.o
-+obj-$(CONFIG_ARCH_BCM2835)$(CONFIG_ARCH_BCM2708)$(CONFIG_ARCH_BCM2709) += clk-bcm2835-aux.o
- obj-$(CONFIG_COMMON_CLK_IPROC) += clk-ns2.o
- obj-$(CONFIG_ARCH_BCM_CYGNUS) += clk-cygnus.o
- obj-$(CONFIG_ARCH_BCM_NSP) += clk-nsp.o
---- a/drivers/spi/Kconfig
-+++ b/drivers/spi/Kconfig
-@@ -90,7 +90,7 @@ config SPI_BCM2835
-
- config SPI_BCM2835AUX
- tristate "BCM2835 SPI auxiliary controller"
-- 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 aux master.
diff --git a/target/linux/brcm2708/patches-4.4/0163-BCM270X_DT-Add-pi3-disable-bt-overlay.patch b/target/linux/brcm2708/patches-4.4/0163-BCM270X_DT-Add-pi3-disable-bt-overlay.patch
new file mode 100644
index 0000000000..6ad6ab6c57
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0163-BCM270X_DT-Add-pi3-disable-bt-overlay.patch
@@ -0,0 +1,96 @@
+From 12cde6a9a34f49c31e2f1689b53cd40a165b35d9 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Wed, 2 Mar 2016 10:59:05 +0000
+Subject: [PATCH 163/381] BCM270X_DT: Add pi3-disable-bt overlay
+
+Disable Bluetooth and restore UART0/ttyAMA0 over GPIOs 14 & 15. To disable
+the systemd service that initialises the modem so it doesn't use the UART:
+
+ sudo systemctl disable hciuart
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 8 ++++
+ .../boot/dts/overlays/pi3-disable-bt-overlay.dts | 48 ++++++++++++++++++++++
+ 3 files changed, 57 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/pi3-disable-bt-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -39,6 +39,7 @@ dtb-$(RPI_DT_OVERLAYS) += mcp2515-can0-o
+ dtb-$(RPI_DT_OVERLAYS) += mcp2515-can1-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += mmc-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += mz61581-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += pi3-disable-bt-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += piscreen-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += piscreen2r-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += pitft28-capacitive-overlay.dtb
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -496,6 +496,14 @@ Params: speed Display
+ [ The pcf8563-rtc overlay has been deleted. See i2c-rtc. ]
+
+
++Name: pi3-disable-bt
++Info: Disable Pi3 Bluetooth and restore UART0/ttyAMA0 over GPIOs 14 & 15
++ N.B. To disable the systemd service that initialises the modem so it
++ doesn't use the UART, use 'sudo systemctl disable hciuart'.
++Load: dtoverlay=pi3-disable-bt
++Params: <None>
++
++
+ Name: piscreen
+ Info: PiScreen display by OzzMaker.com
+ Load: dtoverlay=piscreen,<param>=<val>
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/pi3-disable-bt-overlay.dts
+@@ -0,0 +1,48 @@
++/dts-v1/;
++/plugin/;
++
++/* Disable Bluetooth and restore UART0/ttyAMA0 over GPIOs 14 & 15.
++ To disable the systemd service that initialises the modem so it doesn't use
++ the UART:
++
++ sudo systemctl disable hciuart
++*/
++
++/{
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&uart1>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@1 {
++ target = <&uart0>;
++ __overlay__ {
++ pinctrl-names = "default";
++ pinctrl-0 = <&uart0_pins>;
++ status = "okay";
++ };
++ };
++
++ fragment@2 {
++ target = <&gpio>;
++ __overlay__ {
++ uart0_pins: uart0_pins {
++ brcm,pins = <14 15>;
++ brcm,function = <4>; /* alt0 */
++ brcm,pull = <0 2>;
++ };
++ };
++ };
++
++ fragment@3 {
++ target-path = "/aliases";
++ __overlay__ {
++ serial0 = "/soc/uart@7e201000";
++ serial1 = "/soc/uart@7e215040";
++ };
++ };
++};
diff --git a/target/linux/brcm2708/patches-4.4/0164-ASoC-bcm-add-missing-.owner-fields-in-sound-card-dri.patch b/target/linux/brcm2708/patches-4.4/0164-ASoC-bcm-add-missing-.owner-fields-in-sound-card-dri.patch
deleted file mode 100644
index 0a68d3c881..0000000000
--- a/target/linux/brcm2708/patches-4.4/0164-ASoC-bcm-add-missing-.owner-fields-in-sound-card-dri.patch
+++ /dev/null
@@ -1,108 +0,0 @@
-From 84c2e063885bb0ae3d5d2ad2e24e7a2bdb5729ae Mon Sep 17 00:00:00 2001
-From: Matthias Reichl <hias@horus.com>
-Date: Tue, 23 Feb 2016 17:28:23 +0100
-Subject: [PATCH 164/170] ASoC: bcm: add missing .owner fields in sound card
- drivers
-
-If snd_soc_card.owner is not set the kernel won't do usage refcounting
-and one can remove the card driver module while it's in use (eg playback
-active) - which leads to a kernel crash.
-
-The missing owner field also prevents ALSA slot ordering
-(options snd slots=module-name1,module-name-2,...) from working with
-the I2S cards as it has no module name to match against.
-
-Fix these issues by setting the .owner field in the snd_soc_card structs.
-
-Signed-off-by: Matthias Reichl <hias@horus.com>
----
- sound/soc/bcm/hifiberry_amp.c | 1 +
- sound/soc/bcm/hifiberry_dac.c | 1 +
- sound/soc/bcm/hifiberry_dacplus.c | 1 +
- sound/soc/bcm/hifiberry_digi.c | 1 +
- sound/soc/bcm/iqaudio-dac.c | 1 +
- sound/soc/bcm/raspidac3.c | 1 +
- sound/soc/bcm/rpi-dac.c | 1 +
- sound/soc/bcm/rpi-proto.c | 1 +
- 8 files changed, 8 insertions(+)
-
---- a/sound/soc/bcm/hifiberry_amp.c
-+++ b/sound/soc/bcm/hifiberry_amp.c
-@@ -61,6 +61,7 @@ static struct snd_soc_dai_link snd_rpi_h
-
- static struct snd_soc_card snd_rpi_hifiberry_amp = {
- .name = "snd_rpi_hifiberry_amp",
-+ .owner = THIS_MODULE,
- .dai_link = snd_rpi_hifiberry_amp_dai,
- .num_links = ARRAY_SIZE(snd_rpi_hifiberry_amp_dai),
- };
---- a/sound/soc/bcm/hifiberry_dac.c
-+++ b/sound/soc/bcm/hifiberry_dac.c
-@@ -63,6 +63,7 @@ static struct snd_soc_dai_link snd_rpi_h
- /* audio machine driver */
- static struct snd_soc_card snd_rpi_hifiberry_dac = {
- .name = "snd_rpi_hifiberry_dac",
-+ .owner = THIS_MODULE,
- .dai_link = snd_rpi_hifiberry_dac_dai,
- .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dac_dai),
- };
---- a/sound/soc/bcm/hifiberry_dacplus.c
-+++ b/sound/soc/bcm/hifiberry_dacplus.c
-@@ -287,6 +287,7 @@ static struct snd_soc_dai_link snd_rpi_h
- /* audio machine driver */
- static struct snd_soc_card snd_rpi_hifiberry_dacplus = {
- .name = "snd_rpi_hifiberry_dacplus",
-+ .owner = THIS_MODULE,
- .dai_link = snd_rpi_hifiberry_dacplus_dai,
- .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dacplus_dai),
- };
---- a/sound/soc/bcm/hifiberry_digi.c
-+++ b/sound/soc/bcm/hifiberry_digi.c
-@@ -164,6 +164,7 @@ static struct snd_soc_dai_link snd_rpi_h
- /* audio machine driver */
- static struct snd_soc_card snd_rpi_hifiberry_digi = {
- .name = "snd_rpi_hifiberry_digi",
-+ .owner = THIS_MODULE,
- .dai_link = snd_rpi_hifiberry_digi_dai,
- .num_links = ARRAY_SIZE(snd_rpi_hifiberry_digi_dai),
- };
---- a/sound/soc/bcm/iqaudio-dac.c
-+++ b/sound/soc/bcm/iqaudio-dac.c
-@@ -77,6 +77,7 @@ static struct snd_soc_dai_link snd_rpi_i
- /* audio machine driver */
- static struct snd_soc_card snd_rpi_iqaudio_dac = {
- .name = "IQaudIODAC",
-+ .owner = THIS_MODULE,
- .dai_link = snd_rpi_iqaudio_dac_dai,
- .num_links = ARRAY_SIZE(snd_rpi_iqaudio_dac_dai),
- };
---- a/sound/soc/bcm/raspidac3.c
-+++ b/sound/soc/bcm/raspidac3.c
-@@ -128,6 +128,7 @@ static struct snd_soc_dai_link snd_rpi_r
- /* audio machine driver */
- static struct snd_soc_card snd_rpi_raspidac3 = {
- .name = "RaspiDAC Rev.3x HiFi Audio Card",
-+ .owner = THIS_MODULE,
- .dai_link = snd_rpi_raspidac3_dai,
- .num_links = ARRAY_SIZE(snd_rpi_raspidac3_dai),
- };
---- a/sound/soc/bcm/rpi-dac.c
-+++ b/sound/soc/bcm/rpi-dac.c
-@@ -60,6 +60,7 @@ static struct snd_soc_dai_link snd_rpi_r
- /* audio machine driver */
- static struct snd_soc_card snd_rpi_rpi_dac = {
- .name = "snd_rpi_rpi_dac",
-+ .owner = THIS_MODULE,
- .dai_link = snd_rpi_rpi_dac_dai,
- .num_links = ARRAY_SIZE(snd_rpi_rpi_dac_dai),
- };
---- a/sound/soc/bcm/rpi-proto.c
-+++ b/sound/soc/bcm/rpi-proto.c
-@@ -91,6 +91,7 @@ static struct snd_soc_dai_link snd_rpi_p
- /* audio machine driver */
- static struct snd_soc_card snd_rpi_proto = {
- .name = "snd_rpi_proto",
-+ .owner = THIS_MODULE,
- .dai_link = snd_rpi_proto_dai,
- .num_links = ARRAY_SIZE(snd_rpi_proto_dai),
- };
diff --git a/target/linux/brcm2708/patches-4.4/0164-BCM270X_DT-Add-pi3-miniuart-bt-DT-overlay.patch b/target/linux/brcm2708/patches-4.4/0164-BCM270X_DT-Add-pi3-miniuart-bt-DT-overlay.patch
new file mode 100644
index 0000000000..e1a17e04c0
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0164-BCM270X_DT-Add-pi3-miniuart-bt-DT-overlay.patch
@@ -0,0 +1,117 @@
+From e75384cf32c8941478f24ce4e4cdd7baff047c75 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 7 Mar 2016 09:53:03 +0000
+Subject: [PATCH 164/381] BCM270X_DT: Add pi3-miniuart-bt DT overlay
+
+Switch Pi3 Bluetooth function to use the mini-UART (ttyS0) and restore
+UART0/ttyAMA0 over GPIOs 14 & 15. Note that this may reduce the maximum
+usable baudrate.
+
+It is also necessary to edit /lib/systemd/system/hciuart.server and
+replace ttyAMA0 with ttyS0.
+
+If cmdline.txt uses the alias serial0 to refer to the user-accessable port
+then the firmware will replace with the appropriate port whether or not
+this overlay is used.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 10 ++++
+ .../boot/dts/overlays/pi3-miniuart-bt-overlay.dts | 61 ++++++++++++++++++++++
+ 3 files changed, 72 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/pi3-miniuart-bt-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -40,6 +40,7 @@ dtb-$(RPI_DT_OVERLAYS) += mcp2515-can1-o
+ dtb-$(RPI_DT_OVERLAYS) += mmc-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += mz61581-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += pi3-disable-bt-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += pi3-miniuart-bt-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += piscreen-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += piscreen2r-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += pitft28-capacitive-overlay.dtb
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -504,6 +504,16 @@ Load: dtoverlay=pi3-disable-bt
+ Params: <None>
+
+
++Name: pi3-miniuart-bt
++Info: Switch Pi3 Bluetooth function to use the mini-UART (ttyS0) and restore
++ UART0/ttyAMA0 over GPIOs 14 & 15. Note that this may reduce the maximum
++ usable baudrate.
++ N.B. It is also necessary to edit /lib/systemd/system/hciuart.server
++ and replace ttyAMA0 with ttyS0.
++Load: dtoverlay=pi3-miniuart-bt
++Params: <None>
++
++
+ Name: piscreen
+ Info: PiScreen display by OzzMaker.com
+ Load: dtoverlay=piscreen,<param>=<val>
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/pi3-miniuart-bt-overlay.dts
+@@ -0,0 +1,61 @@
++/dts-v1/;
++/plugin/;
++
++/* Switch Pi3 Bluetooth function to use the mini-UART (ttyS0) and restore
++ UART0/ttyAMA0 over GPIOs 14 & 15. Note that this may reduce the maximum
++ usable baudrate.
++
++ It is also necessary to edit /lib/systemd/system/hciuart.server and
++ replace ttyAMA0 with ttyS0.
++
++ If cmdline.txt uses the alias serial0 to refer to the user-accessable port
++ then the firmware will replace with the appropriate port whether or not
++ this overlay is used.
++*/
++
++/{
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&uart0>;
++ __overlay__ {
++ pinctrl-names = "default";
++ pinctrl-0 = <&uart0_pins>;
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&uart1>;
++ __overlay__ {
++ pinctrl-names = "default";
++ pinctrl-0 = <&uart1_pins>;
++ status = "okay";
++ };
++ };
++
++ fragment@2 {
++ target = <&gpio>;
++ __overlay__ {
++ uart0_pins: uart0_pins {
++ brcm,pins = <14 15>;
++ brcm,function = <4>; /* alt0 */
++ brcm,pull = <0 2>;
++ };
++
++ uart1_pins: uart1_pins {
++ brcm,pins = <32 33>;
++ brcm,function = <2>; /* alt5=UART1 */
++ brcm,pull = <0 0>;
++ };
++ };
++ };
++
++ fragment@3 {
++ target-path = "/aliases";
++ __overlay__ {
++ serial0 = "/soc/uart@7e201000";
++ serial1 = "/soc/uart@7e215040";
++ };
++ };
++};
diff --git a/target/linux/brcm2708/patches-4.4/0165-Pi3-DT-Add-dtparams-for-the-SD-interface.patch b/target/linux/brcm2708/patches-4.4/0165-Pi3-DT-Add-dtparams-for-the-SD-interface.patch
new file mode 100644
index 0000000000..03cc51adec
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0165-Pi3-DT-Add-dtparams-for-the-SD-interface.patch
@@ -0,0 +1,25 @@
+From dcaae71fc22f563f5c918cb4b344992107c0c6bd Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 7 Mar 2016 13:38:39 +0000
+Subject: [PATCH 165/381] Pi3 DT: Add dtparams for the SD interface
+
+Add new base dtparams sd_overclock, sd_force_pio, sd_pio_limit
+and sd_debug. These were missed out of the initial Pi3 DTB.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/bcm2710-rpi-3-b.dts | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
++++ b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
+@@ -188,5 +188,9 @@
+ audio = <&audio>,"status";
+ watchdog = <&watchdog>,"status";
+ random = <&random>,"status";
++ sd_overclock = <&sdhost>,"brcm,overclock-50:0";
++ sd_force_pio = <&sdhost>,"brcm,force-pio?";
++ sd_pio_limit = <&sdhost>,"brcm,pio-limit:0";
++ sd_debug = <&sdhost>,"brcm,debug";
+ };
+ };
diff --git a/target/linux/brcm2708/patches-4.4/0165-smsx95xx-Add-option-to-disable-the-crimes-against-tr.patch b/target/linux/brcm2708/patches-4.4/0165-smsx95xx-Add-option-to-disable-the-crimes-against-tr.patch
deleted file mode 100644
index 81ac7cb9db..0000000000
--- a/target/linux/brcm2708/patches-4.4/0165-smsx95xx-Add-option-to-disable-the-crimes-against-tr.patch
+++ /dev/null
@@ -1,44 +0,0 @@
-From 18674a7da1c3d50d9c957a8f88aaea2aa653d223 Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Wed, 20 Jan 2016 17:50:09 +0000
-Subject: [PATCH 165/170] smsx95xx: Add option to disable the crimes against
- truesize fix
-
-It may improve iperf numbers on Pi 1, but may generate dmesg warnings and possibly cause network issues
-See issue 1248.
----
- drivers/net/usb/smsc95xx.c | 8 ++++++++
- 1 file changed, 8 insertions(+)
- mode change 100755 => 100644 drivers/net/usb/smsc95xx.c
-
---- a/drivers/net/usb/smsc95xx.c
-+++ b/drivers/net/usb/smsc95xx.c
-@@ -75,6 +75,10 @@ static bool turbo_mode = false;
- module_param(turbo_mode, bool, 0644);
- MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
-
-+static bool truesize_mode = false;
-+module_param(truesize_mode, bool, 0644);
-+MODULE_PARM_DESC(truesize_mode, "Report larger truesize value");
-+
- static char *macaddr = ":";
- module_param(macaddr, charp, 0);
- MODULE_PARM_DESC(macaddr, "MAC address");
-@@ -1841,6 +1845,8 @@ 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 */
-+ if (truesize_mode)
-+ skb->truesize = size + sizeof(struct sk_buff);
-
- return 1;
- }
-@@ -1858,6 +1864,8 @@ 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 */
-+ if (truesize_mode)
-+ ax_skb->truesize = size + sizeof(struct sk_buff);
-
- usbnet_skb_return(dev, ax_skb);
- }
diff --git a/target/linux/brcm2708/patches-4.4/0166-bcm2835-virtgpio-Virtual-GPIO-driver.patch b/target/linux/brcm2708/patches-4.4/0166-bcm2835-virtgpio-Virtual-GPIO-driver.patch
deleted file mode 100644
index 428c253c8d..0000000000
--- a/target/linux/brcm2708/patches-4.4/0166-bcm2835-virtgpio-Virtual-GPIO-driver.patch
+++ /dev/null
@@ -1,244 +0,0 @@
-From 5e3c3e845f998f86c2f22017576cb19e5d7fe9bb Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Tue, 23 Feb 2016 19:56:04 +0000
-Subject: [PATCH 166/170] bcm2835-virtgpio: Virtual GPIO driver
-
-Add a virtual GPIO driver that uses the firmware mailbox interface to
-request that the VPU toggles LEDs.
----
- arch/arm/configs/bcm2709_defconfig | 1 +
- drivers/gpio/Kconfig | 6 +
- drivers/gpio/Makefile | 1 +
- drivers/gpio/gpio-bcm-virt.c | 180 +++++++++++++++++++++++++++++
- include/soc/bcm2835/raspberrypi-firmware.h | 1 +
- 5 files changed, 189 insertions(+)
- create mode 100644 drivers/gpio/gpio-bcm-virt.c
-
---- a/arch/arm/configs/bcm2709_defconfig
-+++ b/arch/arm/configs/bcm2709_defconfig
-@@ -607,6 +607,7 @@ CONFIG_PPS=m
- CONFIG_PPS_CLIENT_LDISC=m
- CONFIG_PPS_CLIENT_GPIO=m
- CONFIG_GPIO_SYSFS=y
-+CONFIG_GPIO_BCM_VIRT=y
- CONFIG_GPIO_ARIZONA=m
- CONFIG_GPIO_STMPE=y
- CONFIG_W1=m
---- a/drivers/gpio/Kconfig
-+++ b/drivers/gpio/Kconfig
-@@ -132,6 +132,12 @@ config GPIO_BCM_KONA
- help
- Turn on GPIO support for Broadcom "Kona" chips.
-
-+config GPIO_BCM_VIRT
-+ bool "Broadcom Virt GPIO"
-+ depends on OF_GPIO && RASPBERRYPI_FIRMWARE && (ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709 || COMPILE_TEST)
-+ help
-+ Turn on virtual GPIO support for Broadcom BCM283X chips.
-+
- config GPIO_BRCMSTB
- tristate "BRCMSTB GPIO support"
- default y if ARCH_BRCMSTB
---- a/drivers/gpio/Makefile
-+++ b/drivers/gpio/Makefile
-@@ -24,6 +24,7 @@ obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o
- obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
- obj-$(CONFIG_ATH79) += gpio-ath79.o
- obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
-+obj-$(CONFIG_GPIO_BCM_VIRT) += gpio-bcm-virt.o
- obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
- obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
- obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o
---- /dev/null
-+++ b/drivers/gpio/gpio-bcm-virt.c
-@@ -0,0 +1,180 @@
-+/*
-+ * brcmvirt GPIO driver
-+ *
-+ * Copyright (C) 2012,2013 Dom Cobley <popcornmix@gmail.com>
-+ * Based on gpio-clps711x.c by Alexander Shiyan <shc_work@mail.ru>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ */
-+
-+#include <linux/err.h>
-+#include <linux/gpio.h>
-+#include <linux/module.h>
-+#include <linux/basic_mmio_gpio.h>
-+#include <linux/platform_device.h>
-+#include <soc/bcm2835/raspberrypi-firmware.h>
-+
-+#define MODULE_NAME "brcmvirt-gpio"
-+#define NUM_GPIO 2
-+
-+struct brcmvirt_gpio {
-+ struct gpio_chip gc;
-+ u32 __iomem *ts_base;
-+ /* two packed 16-bit counts of enabled and disables
-+ Allows host to detect a brief enable that was missed */
-+ u32 enables_disables[NUM_GPIO];
-+};
-+
-+static int brcmvirt_gpio_dir_in(struct gpio_chip *gc, unsigned off)
-+{
-+ struct brcmvirt_gpio *gpio;
-+ gpio = container_of(gc, struct brcmvirt_gpio, gc);
-+ return -EINVAL;
-+}
-+
-+static int brcmvirt_gpio_dir_out(struct gpio_chip *gc, unsigned off, int val)
-+{
-+ struct brcmvirt_gpio *gpio;
-+ gpio = container_of(gc, struct brcmvirt_gpio, gc);
-+ return 0;
-+}
-+
-+static int brcmvirt_gpio_get(struct gpio_chip *gc, unsigned off)
-+{
-+ struct brcmvirt_gpio *gpio;
-+ unsigned v;
-+ gpio = container_of(gc, struct brcmvirt_gpio, gc);
-+ v = readl(gpio->ts_base + off);
-+ return (v >> off) & 1;
-+}
-+
-+static void brcmvirt_gpio_set(struct gpio_chip *gc, unsigned off, int val)
-+{
-+ struct brcmvirt_gpio *gpio;
-+ u16 enables, disables;
-+ s16 diff;
-+ bool lit;
-+ gpio = container_of(gc, struct brcmvirt_gpio, gc);
-+ enables = gpio->enables_disables[off] >> 16;
-+ disables = gpio->enables_disables[off] >> 0;
-+ diff = (s16)(enables - disables);
-+ lit = diff > 0;
-+ if ((val && lit) || (!val && !lit))
-+ return;
-+ if (val)
-+ enables++;
-+ else
-+ disables++;
-+ diff = (s16)(enables - disables);
-+ BUG_ON(diff != 0 && diff != 1);
-+ gpio->enables_disables[off] = (enables << 16) | (disables << 0);
-+ writel(gpio->enables_disables[off], gpio->ts_base + off);
-+}
-+
-+static int brcmvirt_gpio_probe(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ struct device_node *np = dev->of_node;
-+ struct device_node *fw_node;
-+ struct rpi_firmware *fw;
-+ struct brcmvirt_gpio *ucb;
-+ u32 gpiovirtbuf;
-+ int err = 0;
-+
-+ fw_node = of_parse_phandle(np, "firmware", 0);
-+ if (!fw_node) {
-+ dev_err(dev, "Missing firmware node\n");
-+ return -ENOENT;
-+ }
-+
-+ fw = rpi_firmware_get(fw_node);
-+ if (!fw)
-+ return -EPROBE_DEFER;
-+
-+ err = rpi_firmware_property(fw, RPI_FIRMWARE_FRAMEBUFFER_GET_GPIOVIRTBUF,
-+ &gpiovirtbuf, sizeof(gpiovirtbuf));
-+
-+ if (err) {
-+ dev_err(dev, "Failed to get gpiovirtbuf\n");
-+ goto err;
-+ }
-+
-+ if (!gpiovirtbuf) {
-+ dev_err(dev, "No virtgpio buffer\n");
-+ err = -ENOENT;
-+ goto err;
-+ }
-+
-+ ucb = devm_kzalloc(dev, sizeof *ucb, GFP_KERNEL);
-+ if (!ucb) {
-+ err = -EINVAL;
-+ goto err;
-+ }
-+
-+ // mmap the physical memory
-+ gpiovirtbuf &= ~0xc0000000;
-+ ucb->ts_base = ioremap(gpiovirtbuf, 4096);
-+ if (ucb->ts_base == NULL) {
-+ dev_err(dev, "Failed to map physical address\n");
-+ err = -ENOENT;
-+ goto err;
-+ }
-+
-+ ucb->gc.label = MODULE_NAME;
-+ ucb->gc.owner = THIS_MODULE;
-+ ucb->gc.dev = dev;
-+ ucb->gc.of_node = np;
-+ ucb->gc.base = 100;
-+ ucb->gc.ngpio = NUM_GPIO;
-+
-+ ucb->gc.direction_input = brcmvirt_gpio_dir_in;
-+ ucb->gc.direction_output = brcmvirt_gpio_dir_out;
-+ ucb->gc.get = brcmvirt_gpio_get;
-+ ucb->gc.set = brcmvirt_gpio_set;
-+ ucb->gc.can_sleep = true;
-+
-+ err = gpiochip_add(&ucb->gc);
-+ if (err)
-+ goto err;
-+
-+ platform_set_drvdata(pdev, ucb);
-+
-+err:
-+ return err;
-+
-+}
-+
-+static int brcmvirt_gpio_remove(struct platform_device *pdev)
-+{
-+ int err = 0;
-+ struct brcmvirt_gpio *ucb = platform_get_drvdata(pdev);
-+
-+ gpiochip_remove(&ucb->gc);
-+ iounmap(ucb->ts_base);
-+ return err;
-+}
-+
-+static const struct of_device_id __maybe_unused brcmvirt_gpio_ids[] = {
-+ { .compatible = "brcm,bcm2835-virtgpio" },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(of, brcmvirt_gpio_ids);
-+
-+static struct platform_driver brcmvirt_gpio_driver = {
-+ .driver = {
-+ .name = MODULE_NAME,
-+ .owner = THIS_MODULE,
-+ .of_match_table = of_match_ptr(brcmvirt_gpio_ids),
-+ },
-+ .probe = brcmvirt_gpio_probe,
-+ .remove = brcmvirt_gpio_remove,
-+};
-+module_platform_driver(brcmvirt_gpio_driver);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Dom Cobley <popcornmix@gmail.com>");
-+MODULE_DESCRIPTION("brcmvirt GPIO driver");
-+MODULE_ALIAS("platform:brcmvirt-gpio");
---- a/include/soc/bcm2835/raspberrypi-firmware.h
-+++ b/include/soc/bcm2835/raspberrypi-firmware.h
-@@ -93,6 +93,7 @@ enum rpi_firmware_property_tag {
- RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN = 0x0004000a,
- RPI_FIRMWARE_FRAMEBUFFER_GET_PALETTE = 0x0004000b,
- RPI_FIRMWARE_FRAMEBUFFER_GET_TOUCHBUF = 0x0004000f,
-+ RPI_FIRMWARE_FRAMEBUFFER_GET_GPIOVIRTBUF = 0x00040010,
- RPI_FIRMWARE_FRAMEBUFFER_RELEASE = 0x00048001,
- RPI_FIRMWARE_FRAMEBUFFER_TEST_PHYSICAL_WIDTH_HEIGHT = 0x00044003,
- RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_WIDTH_HEIGHT = 0x00044004,
diff --git a/target/linux/brcm2708/patches-4.4/0166-vchiq_arm-Tweak-the-logging-output.patch b/target/linux/brcm2708/patches-4.4/0166-vchiq_arm-Tweak-the-logging-output.patch
new file mode 100644
index 0000000000..de876cafa0
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0166-vchiq_arm-Tweak-the-logging-output.patch
@@ -0,0 +1,75 @@
+From 21fd9cca44f4400b7c157e4698adb4134b3b9652 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 7 Mar 2016 15:05:11 +0000
+Subject: [PATCH 166/381] vchiq_arm: Tweak the logging output
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ .../vc04_services/interface/vchiq_arm/vchiq_core.c | 31 +++++++++-------------
+ 1 file changed, 13 insertions(+), 18 deletions(-)
+
+--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c
++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c
+@@ -891,16 +891,14 @@ queue_message(VCHIQ_STATE_T *state, VCHI
+ error_count);
+ return VCHIQ_ERROR;
+ }
+- if (i == 0) {
+- if (SRVTRACE_ENABLED(service,
+- VCHIQ_LOG_INFO))
+- vchiq_log_dump_mem("Sent", 0,
+- header->data + pos,
+- min(64u,
+- elements[0].size));
+- }
+ }
+
++ if (SRVTRACE_ENABLED(service,
++ VCHIQ_LOG_INFO))
++ vchiq_log_dump_mem("Sent", 0,
++ header->data,
++ min(16, pos));
++
+ spin_lock(&quota_spinlock);
+ service_quota->message_use_count++;
+
+@@ -1039,16 +1037,13 @@ queue_message_sync(VCHIQ_STATE_T *state,
+ error_count);
+ return VCHIQ_ERROR;
+ }
+- if (i == 0) {
+- if (vchiq_sync_log_level >=
+- VCHIQ_LOG_TRACE)
+- vchiq_log_dump_mem("Sent Sync",
+- 0, header->data + pos,
+- min(64u,
+- elements[0].size));
+- }
+ }
+
++ if (vchiq_sync_log_level >= VCHIQ_LOG_TRACE)
++ vchiq_log_dump_mem("Sent Sync",
++ 0, header->data,
++ min(16, pos));
++
+ VCHIQ_SERVICE_STATS_INC(service, ctrl_tx_count);
+ VCHIQ_SERVICE_STATS_ADD(service, ctrl_tx_bytes, size);
+ } else {
+@@ -1720,7 +1715,7 @@ parse_rx_slots(VCHIQ_STATE_T *state)
+ remoteport, localport, size);
+ if (size > 0)
+ vchiq_log_dump_mem("Rcvd", 0, header->data,
+- min(64, size));
++ min(16, size));
+ }
+
+ if (((unsigned int)header & VCHIQ_SLOT_MASK) + calc_stride(size)
+@@ -2187,7 +2182,7 @@ sync_func(void *v)
+ remoteport, localport, size);
+ if (size > 0)
+ vchiq_log_dump_mem("Rcvd", 0, header->data,
+- min(64, size));
++ min(16, size));
+ }
+
+ switch (type) {
diff --git a/target/linux/brcm2708/patches-4.4/0167-BCM270X_DT-Add-Pi3-support.patch b/target/linux/brcm2708/patches-4.4/0167-BCM270X_DT-Add-Pi3-support.patch
deleted file mode 100644
index dc11b76825..0000000000
--- a/target/linux/brcm2708/patches-4.4/0167-BCM270X_DT-Add-Pi3-support.patch
+++ /dev/null
@@ -1,305 +0,0 @@
-From 6aa2c847f76f21c830544e8c79f9030a170ef475 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Thu, 21 Jan 2016 17:57:49 +0000
-Subject: [PATCH 167/170] BCM270X_DT: Add Pi3 support
-
----
- arch/arm/boot/dts/Makefile | 1 +
- arch/arm/boot/dts/bcm2710-rpi-3-b.dts | 174 ++++++++++++++++++++++++++++++++++
- arch/arm/boot/dts/bcm2710.dtsi | 102 ++++++++++++++++++++
- 3 files changed, 277 insertions(+)
- create mode 100644 arch/arm/boot/dts/bcm2710-rpi-3-b.dts
- create mode 100644 arch/arm/boot/dts/bcm2710.dtsi
-
---- a/arch/arm/boot/dts/Makefile
-+++ b/arch/arm/boot/dts/Makefile
-@@ -5,6 +5,7 @@ dtb-$(CONFIG_ARCH_BCM2708) += bcm2708-rp
- dtb-$(CONFIG_ARCH_BCM2708) += bcm2708-rpi-cm.dtb
- dtb-$(CONFIG_ARCH_BCM2835) += bcm2835-rpi-cm.dtb
- dtb-$(CONFIG_ARCH_BCM2709) += bcm2709-rpi-2-b.dtb
-+dtb-$(CONFIG_ARCH_BCM2709) += bcm2710-rpi-3-b.dtb
-
- # Raspberry Pi
- ifeq ($(CONFIG_ARCH_BCM2708),y)
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
-@@ -0,0 +1,174 @@
-+/dts-v1/;
-+
-+#include "bcm2710.dtsi"
-+
-+/ {
-+ compatible = "brcm,bcm2710","brcm,bcm2709";
-+ model = "Raspberry Pi 3 Model B";
-+};
-+
-+&gpio {
-+ sdhost_pins: sdhost_pins {
-+ brcm,pins = <48 49 50 51 52 53>;
-+ brcm,function = <4>; /* alt0 */
-+ };
-+
-+ spi0_pins: spi0_pins {
-+ brcm,pins = <9 10 11>;
-+ brcm,function = <4>; /* alt0 */
-+ };
-+
-+ spi0_cs_pins: spi0_cs_pins {
-+ brcm,pins = <8 7>;
-+ brcm,function = <1>; /* output */
-+ };
-+
-+ i2c0_pins: i2c0 {
-+ brcm,pins = <0 1>;
-+ brcm,function = <4>;
-+ };
-+
-+ i2c1_pins: i2c1 {
-+ brcm,pins = <2 3>;
-+ brcm,function = <4>;
-+ };
-+
-+ i2s_pins: i2s {
-+ brcm,pins = <18 19 20 21>;
-+ brcm,function = <4>; /* alt0 */
-+ };
-+
-+ sdio_pins: sdio_pins {
-+ brcm,pins = <34 35 36 37 38 39>;
-+ brcm,function = <7>; // alt3 = SD1
-+ brcm,pull = <0 2 2 2 2 2>;
-+ };
-+
-+ bt_pins: bt_pins {
-+ brcm,pins = <28 29 30 31 14 15 43>;
-+ brcm,function = <6 6 6 6 2 2 4>;
-+ // alt2:PCM alt5:UART1 alt0:GPCLK2
-+ brcm,pull = <0 0 0 0 0 2 0>;
-+ };
-+
-+ uart1_pins: uart1_pins {
-+ brcm,pins = <32 33>;
-+ brcm,function = <7>; /* alt3=UART0 */
-+ brcm,pull = <0>;
-+ };
-+};
-+
-+&sdhost {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&sdhost_pins>;
-+ bus-width = <4>;
-+ status = "okay";
-+};
-+
-+&mmc {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&sdio_pins>;
-+ non-removable;
-+ bus-width = <4>;
-+ status = "okay";
-+};
-+
-+&fb {
-+ status = "okay";
-+};
-+
-+&uart0 {
-+ status = "okay";
-+};
-+
-+&uart1 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&uart1_pins &bt_pins>;
-+ status = "okay";
-+};
-+
-+&spi0 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&spi0_pins &spi0_cs_pins>;
-+ cs-gpios = <&gpio 8 1>, <&gpio 7 1>;
-+
-+ spidev@0{
-+ compatible = "spidev";
-+ reg = <0>; /* CE0 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <500000>;
-+ };
-+
-+ spidev@1{
-+ compatible = "spidev";
-+ reg = <1>; /* CE1 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <500000>;
-+ };
-+};
-+
-+&i2c0 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c0_pins>;
-+ clock-frequency = <100000>;
-+};
-+
-+&i2c1 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c1_pins>;
-+ clock-frequency = <100000>;
-+};
-+
-+&i2c2 {
-+ clock-frequency = <100000>;
-+};
-+
-+&i2s {
-+ #sound-dai-cells = <0>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2s_pins>;
-+};
-+
-+&random {
-+ status = "okay";
-+};
-+
-+&leds {
-+ act_led: act {
-+ label = "led0";
-+ linux,default-trigger = "mmc0";
-+ gpios = <&gpio 47 0>;
-+ };
-+};
-+
-+/ {
-+ chosen {
-+ bootargs = "8250.nr_uarts=1";
-+ };
-+};
-+
-+/ {
-+ __overrides__ {
-+ uart0 = <&uart0>,"status";
-+ uart0_clkrate = <&clk_uart0>,"clock-frequency:0";
-+ i2s = <&i2s>,"status";
-+ spi = <&spi0>,"status";
-+ i2c0 = <&i2c0>,"status";
-+ i2c1 = <&i2c1>,"status";
-+ i2c2_iknowwhatimdoing = <&i2c2>,"status";
-+ i2c0_baudrate = <&i2c0>,"clock-frequency:0";
-+ i2c1_baudrate = <&i2c1>,"clock-frequency:0";
-+ i2c2_baudrate = <&i2c2>,"clock-frequency:0";
-+ core_freq = <&clk_core>,"clock-frequency:0";
-+
-+ act_led_gpio = <&act_led>,"gpios:4";
-+ act_led_activelow = <&act_led>,"gpios:8";
-+ act_led_trigger = <&act_led>,"linux,default-trigger";
-+
-+ audio = <&audio>,"status";
-+ watchdog = <&watchdog>,"status";
-+ random = <&random>,"status";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2710.dtsi
-@@ -0,0 +1,102 @@
-+#include "bcm2708_common.dtsi"
-+
-+/ {
-+ compatible = "brcm,bcm2710","brcm,bcm2709";
-+ model = "BCM2710";
-+
-+ chosen {
-+ /* No padding required - the boot loader can do that. */
-+ bootargs = "";
-+ };
-+
-+ soc {
-+ ranges = <0x7e000000 0x3f000000 0x01000000>,
-+ <0x40000000 0x40000000 0x00040000>;
-+
-+ local_intc: local_intc {
-+ compatible = "brcm,bcm2836-l1-intc";
-+ reg = <0x40000000 0x100>;
-+ interrupt-controller;
-+ #interrupt-cells = <1>;
-+ interrupt-parent = <&local_intc>;
-+ };
-+
-+ arm-pmu {
-+ compatible = "arm,cortex-a7-pmu";
-+ interrupt-parent = <&local_intc>;
-+ interrupts = <9>;
-+ };
-+
-+ gpiomem {
-+ compatible = "brcm,bcm2835-gpiomem";
-+ reg = <0x7e200000 0x1000>;
-+ status = "okay";
-+ };
-+
-+ timer {
-+ compatible = "arm,armv7-timer";
-+ clock-frequency = <19200000>;
-+ interrupt-parent = <&local_intc>;
-+ interrupts = <0>, // PHYS_SECURE_PPI
-+ <1>, // PHYS_NONSECURE_PPI
-+ <3>, // VIRT_PPI
-+ <2>; // HYP_PPI
-+ always-on;
-+ };
-+
-+ syscon@40000000 {
-+ compatible = "brcm,bcm2836-arm-local", "syscon";
-+ reg = <0x40000000 0x100>;
-+ };
-+ };
-+
-+ cpus: cpus {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ v7_cpu0: cpu@0 {
-+ device_type = "cpu";
-+ compatible = "arm,cortex-a7";
-+ reg = <0x000>;
-+ clock-frequency = <800000000>;
-+ };
-+
-+ v7_cpu1: cpu@1 {
-+ device_type = "cpu";
-+ compatible = "arm,cortex-a7";
-+ reg = <0x001>;
-+ clock-frequency = <800000000>;
-+ };
-+
-+ v7_cpu2: cpu@2 {
-+ device_type = "cpu";
-+ compatible = "arm,cortex-a7";
-+ reg = <0x002>;
-+ clock-frequency = <800000000>;
-+ };
-+
-+ v7_cpu3: cpu@3 {
-+ device_type = "cpu";
-+ compatible = "arm,cortex-a7";
-+ reg = <0x003>;
-+ clock-frequency = <800000000>;
-+ };
-+ };
-+
-+ __overrides__ {
-+ arm_freq = <&v7_cpu0>, "clock-frequency:0",
-+ <&v7_cpu1>, "clock-frequency:0",
-+ <&v7_cpu2>, "clock-frequency:0",
-+ <&v7_cpu3>, "clock-frequency:0";
-+ };
-+};
-+
-+&watchdog {
-+ status = "okay";
-+};
-+
-+&intc {
-+ compatible = "brcm,bcm2836-armctrl-ic";
-+ interrupt-parent = <&local_intc>;
-+ interrupts = <8>;
-+};
diff --git a/target/linux/brcm2708/patches-4.4/0167-bcm2835-sdhost-Only-claim-one-DMA-channel.patch b/target/linux/brcm2708/patches-4.4/0167-bcm2835-sdhost-Only-claim-one-DMA-channel.patch
new file mode 100644
index 0000000000..cc40d2d354
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0167-bcm2835-sdhost-Only-claim-one-DMA-channel.patch
@@ -0,0 +1,160 @@
+From f76d188586952fcd3b55916f30c484c62c8fabab Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 7 Mar 2016 16:46:39 +0000
+Subject: [PATCH 167/381] bcm2835-sdhost: Only claim one DMA channel
+
+With both MMC controllers enabled there are few DMA channels left. The
+bcm2835-sdhost driver only uses DMA in one direction at a time, so it
+doesn't need to claim two channels.
+
+See: https://github.com/raspberrypi/linux/issues/1327
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/bcm2708_common.dtsi | 5 +--
+ drivers/mmc/host/bcm2835-sdhost.c | 70 ++++++++++++++++++++++++-----------
+ 2 files changed, 50 insertions(+), 25 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2708_common.dtsi
++++ b/arch/arm/boot/dts/bcm2708_common.dtsi
+@@ -136,9 +136,8 @@
+ reg = <0x7e202000 0x100>;
+ interrupts = <2 24>;
+ clocks = <&clk_core>;
+- dmas = <&dma 13>,
+- <&dma 13>;
+- dma-names = "tx", "rx";
++ dmas = <&dma 13>;
++ dma-names = "rx-tx";
+ brcm,overclock-50 = <0>;
+ brcm,pio-limit = <1>;
+ status = "disabled";
+--- a/drivers/mmc/host/bcm2835-sdhost.c
++++ b/drivers/mmc/host/bcm2835-sdhost.c
+@@ -185,9 +185,10 @@ struct bcm2835_host {
+ unsigned int debug:1; /* Enable debug output */
+
+ /*DMA part*/
+- struct dma_chan *dma_chan_rx; /* DMA channel for reads */
+- struct dma_chan *dma_chan_tx; /* DMA channel for writes */
+- struct dma_chan *dma_chan; /* Channel in used */
++ struct dma_chan *dma_chan_rxtx; /* DMA channel for reads and writes */
++ struct dma_chan *dma_chan; /* Channel in use */
++ struct dma_slave_config dma_cfg_rx;
++ struct dma_slave_config dma_cfg_tx;
+ struct dma_async_tx_descriptor *dma_desc;
+ u32 dma_dir;
+ u32 drain_words;
+@@ -771,12 +772,11 @@ static void bcm2835_sdhost_prepare_dma(s
+ log_event("PRD<", (u32)data, 0);
+ pr_debug("bcm2835_sdhost_prepare_dma()\n");
+
++ dma_chan = host->dma_chan_rxtx;
+ if (data->flags & MMC_DATA_READ) {
+- dma_chan = host->dma_chan_rx;
+ dir_data = DMA_FROM_DEVICE;
+ dir_slave = DMA_DEV_TO_MEM;
+ } else {
+- dma_chan = host->dma_chan_tx;
+ dir_data = DMA_TO_DEVICE;
+ dir_slave = DMA_MEM_TO_DEV;
+ }
+@@ -813,6 +813,12 @@ static void bcm2835_sdhost_prepare_dma(s
+ host->drain_words = len/4;
+ }
+
++ /* The parameters have already been validated, so this will not fail */
++ (void)dmaengine_slave_config(dma_chan,
++ (dir_data == DMA_FROM_DEVICE) ?
++ &host->dma_cfg_rx :
++ &host->dma_cfg_tx);
++
+ len = dma_map_sg(dma_chan->device->dev, data->sg, data->sg_len,
+ dir_data);
+
+@@ -1805,28 +1811,46 @@ int bcm2835_sdhost_add_host(struct bcm28
+ spin_lock_init(&host->lock);
+
+ if (host->allow_dma) {
+- if (IS_ERR_OR_NULL(host->dma_chan_tx) ||
+- IS_ERR_OR_NULL(host->dma_chan_rx)) {
+- pr_err("%s: unable to initialise DMA channels. "
++ if (IS_ERR_OR_NULL(host->dma_chan_rxtx)) {
++ pr_err("%s: unable to initialise DMA channel. "
+ "Falling back to PIO\n",
+ mmc_hostname(mmc));
+ host->use_dma = false;
+ } else {
+- host->use_dma = true;
+-
+ cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ cfg.slave_id = 13; /* DREQ channel */
+
++ /* Validate the slave configurations */
++
+ cfg.direction = DMA_MEM_TO_DEV;
+ cfg.src_addr = 0;
+ cfg.dst_addr = host->bus_addr + SDDATA;
+- ret = dmaengine_slave_config(host->dma_chan_tx, &cfg);
+
+- cfg.direction = DMA_DEV_TO_MEM;
+- cfg.src_addr = host->bus_addr + SDDATA;
+- cfg.dst_addr = 0;
+- ret = dmaengine_slave_config(host->dma_chan_rx, &cfg);
++ ret = dmaengine_slave_config(host->dma_chan_rxtx, &cfg);
++
++ if (ret == 0) {
++ host->dma_cfg_tx = cfg;
++
++ cfg.direction = DMA_DEV_TO_MEM;
++ cfg.src_addr = host->bus_addr + SDDATA;
++ cfg.dst_addr = 0;
++
++ ret = dmaengine_slave_config(host->dma_chan_rxtx, &cfg);
++ }
++
++ if (ret == 0) {
++ host->dma_cfg_rx = cfg;
++
++ host->use_dma = true;
++ } else {
++ pr_err("%s: unable to configure DMA channel. "
++ "Falling back to PIO\n",
++ mmc_hostname(mmc));
++ dma_release_channel(host->dma_chan_rxtx);
++ host->dma_chan_rxtx = NULL;
++ host->use_dma = false;
++ }
+ }
+ } else {
+ host->use_dma = false;
+@@ -1948,19 +1972,21 @@ static int bcm2835_sdhost_probe(struct p
+
+ if (host->allow_dma) {
+ if (node) {
+- host->dma_chan_tx =
+- dma_request_slave_channel(dev, "tx");
+- host->dma_chan_rx =
+- dma_request_slave_channel(dev, "rx");
++ host->dma_chan_rxtx =
++ dma_request_slave_channel(dev, "rx-tx");
++ if (!host->dma_chan_rxtx)
++ host->dma_chan_rxtx =
++ dma_request_slave_channel(dev, "tx");
++ if (!host->dma_chan_rxtx)
++ host->dma_chan_rxtx =
++ dma_request_slave_channel(dev, "rx");
+ } else {
+ dma_cap_mask_t mask;
+
+ dma_cap_zero(mask);
+ /* we don't care about the channel, any would work */
+ dma_cap_set(DMA_SLAVE, mask);
+- host->dma_chan_tx =
+- dma_request_channel(mask, NULL, NULL);
+- host->dma_chan_rx =
++ host->dma_chan_rxtx =
+ dma_request_channel(mask, NULL, NULL);
+ }
+ }
diff --git a/target/linux/brcm2708/patches-4.4/0168-FIXUP-BCM270X_DT-Update-to-latest-Pi3-DTS.patch b/target/linux/brcm2708/patches-4.4/0168-FIXUP-BCM270X_DT-Update-to-latest-Pi3-DTS.patch
deleted file mode 100644
index 686f5c6ac9..0000000000
--- a/target/linux/brcm2708/patches-4.4/0168-FIXUP-BCM270X_DT-Update-to-latest-Pi3-DTS.patch
+++ /dev/null
@@ -1,82 +0,0 @@
-From 52015bd5f0bb4d64ca51c5f8539cf2552dfb8a42 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Thu, 21 Jan 2016 17:57:49 +0000
-Subject: [PATCH 168/170] FIXUP: BCM270X_DT: Update to latest Pi3 DTS
-
----
- arch/arm/boot/dts/bcm2710-rpi-3-b.dts | 34 ++++++++++++++++++++++++++--------
- 1 file changed, 26 insertions(+), 8 deletions(-)
-
---- a/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
-+++ b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
-@@ -45,16 +45,21 @@
- };
-
- bt_pins: bt_pins {
-- brcm,pins = <28 29 30 31 14 15 43>;
-- brcm,function = <6 6 6 6 2 2 4>;
-- // alt2:PCM alt5:UART1 alt0:GPCLK2
-- brcm,pull = <0 0 0 0 0 2 0>;
-+ brcm,pins = <28 29 30 31 43>;
-+ brcm,function = <6 6 6 6 4>; /* alt2:PCM alt0:GPCLK2 */
-+ brcm,pull = <0 0 0 0 0>;
- };
-
-- uart1_pins: uart1_pins {
-+ uart0_pins: uart0_pins {
- brcm,pins = <32 33>;
- brcm,function = <7>; /* alt3=UART0 */
-- brcm,pull = <0>;
-+ brcm,pull = <0 0>;
-+ };
-+
-+ uart1_pins: uart1_pins {
-+ brcm,pins = <14 15>;
-+ brcm,function = <2>; /* alt5=UART1 */
-+ brcm,pull = <0 0>;
- };
- };
-
-@@ -71,6 +76,17 @@
- non-removable;
- bus-width = <4>;
- status = "okay";
-+ brcm,overclock-50 = <0>;
-+};
-+
-+&soc {
-+ virtgpio: virtgpio {
-+ compatible = "brcm,bcm2835-virtgpio";
-+ gpio-controller;
-+ #gpio-cells = <2>;
-+ firmware = <&firmware>;
-+ status = "okay";
-+ };
- };
-
- &fb {
-@@ -78,12 +94,14 @@
- };
-
- &uart0 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&uart0_pins &bt_pins>;
- status = "okay";
- };
-
- &uart1 {
- pinctrl-names = "default";
-- pinctrl-0 = <&uart1_pins &bt_pins>;
-+ pinctrl-0 = <&uart1_pins>;
- status = "okay";
- };
-
-@@ -139,7 +157,7 @@
- act_led: act {
- label = "led0";
- linux,default-trigger = "mmc0";
-- gpios = <&gpio 47 0>;
-+ gpios = <&virtgpio 0 0>;
- };
- };
-
diff --git a/target/linux/brcm2708/patches-4.4/0168-bcm2835-mmc-Only-claim-one-DMA-channel.patch b/target/linux/brcm2708/patches-4.4/0168-bcm2835-mmc-Only-claim-one-DMA-channel.patch
new file mode 100644
index 0000000000..8e741825e5
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0168-bcm2835-mmc-Only-claim-one-DMA-channel.patch
@@ -0,0 +1,170 @@
+From a42056ad2e3f74569611dd4f15ca698ccd9d7bea Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Tue, 8 Mar 2016 09:49:16 +0000
+Subject: [PATCH 168/381] bcm2835-mmc: Only claim one DMA channel
+
+With both MMC controllers enabled there are few DMA channels left. The
+bcm2835-mmc driver only uses DMA in one direction at a time, so it
+doesn't need to claim two channels.
+
+See: https://github.com/raspberrypi/linux/issues/1327
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/bcm2708_common.dtsi | 5 +--
+ drivers/mmc/host/bcm2835-mmc.c | 69 +++++++++++++++++++++++++----------
+ 2 files changed, 51 insertions(+), 23 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2708_common.dtsi
++++ b/arch/arm/boot/dts/bcm2708_common.dtsi
+@@ -232,9 +232,8 @@
+ reg = <0x7e300000 0x100>;
+ interrupts = <2 30>;
+ clocks = <&clk_mmc>;
+- dmas = <&dma 11>,
+- <&dma 11>;
+- dma-names = "tx", "rx";
++ dmas = <&dma 11>;
++ dma-names = "rx-tx";
+ brcm,overclock-50 = <0>;
+ status = "disabled";
+ };
+--- a/drivers/mmc/host/bcm2835-mmc.c
++++ b/drivers/mmc/host/bcm2835-mmc.c
+@@ -108,8 +108,9 @@ struct bcm2835_host {
+ u32 shadow;
+
+ /*DMA part*/
+- struct dma_chan *dma_chan_rx; /* DMA channel for reads */
+- struct dma_chan *dma_chan_tx; /* DMA channel for writes */
++ struct dma_chan *dma_chan_rxtx; /* DMA channel for reads and writes */
++ struct dma_slave_config dma_cfg_rx;
++ struct dma_slave_config dma_cfg_tx;
+ struct dma_async_tx_descriptor *tx_desc; /* descriptor */
+
+ bool have_dma;
+@@ -342,7 +343,7 @@ static void bcm2835_mmc_dma_complete(voi
+
+ if (host->data && !(host->data->flags & MMC_DATA_WRITE)) {
+ /* otherwise handled in SDHCI IRQ */
+- dma_chan = host->dma_chan_rx;
++ dma_chan = host->dma_chan_rxtx;
+ dir_data = DMA_FROM_DEVICE;
+
+ dma_unmap_sg(dma_chan->device->dev,
+@@ -493,16 +494,21 @@ static void bcm2835_mmc_transfer_dma(str
+ if (host->blocks == 0)
+ return;
+
++ dma_chan = host->dma_chan_rxtx;
+ if (host->data->flags & MMC_DATA_READ) {
+- dma_chan = host->dma_chan_rx;
+ dir_data = DMA_FROM_DEVICE;
+ dir_slave = DMA_DEV_TO_MEM;
+ } else {
+- dma_chan = host->dma_chan_tx;
+ dir_data = DMA_TO_DEVICE;
+ dir_slave = DMA_MEM_TO_DEV;
+ }
+
++ /* The parameters have already been validated, so this will not fail */
++ (void)dmaengine_slave_config(dma_chan,
++ (dir_data == DMA_FROM_DEVICE) ?
++ &host->dma_cfg_rx :
++ &host->dma_cfg_tx);
++
+ BUG_ON(!dma_chan->device);
+ BUG_ON(!dma_chan->device->dev);
+ BUG_ON(!host->data->sg);
+@@ -936,7 +942,7 @@ static void bcm2835_mmc_data_irq(struct
+ if (host->data->flags & MMC_DATA_WRITE) {
+ /* IRQ handled here */
+
+- dma_chan = host->dma_chan_tx;
++ dma_chan = host->dma_chan_rxtx;
+ dir_data = DMA_TO_DEVICE;
+ dma_unmap_sg(dma_chan->device->dev,
+ host->data->sg, host->data->sg_len,
+@@ -1316,28 +1322,47 @@ static int bcm2835_mmc_add_host(struct b
+ dev_info(dev, "Forcing PIO mode\n");
+ host->have_dma = false;
+ #else
+- if (IS_ERR_OR_NULL(host->dma_chan_tx) ||
+- IS_ERR_OR_NULL(host->dma_chan_rx)) {
+- dev_err(dev, "%s: Unable to initialise DMA channels. Falling back to PIO\n",
++ if (IS_ERR_OR_NULL(host->dma_chan_rxtx)) {
++ dev_err(dev, "%s: Unable to initialise DMA channel. Falling back to PIO\n",
+ DRIVER_NAME);
+ host->have_dma = false;
+ } else {
+- dev_info(dev, "DMA channels allocated");
+- host->have_dma = true;
++ dev_info(dev, "DMA channel allocated");
+
+ cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ cfg.slave_id = 11; /* DREQ channel */
+
++ /* Validate the slave configurations */
++
+ cfg.direction = DMA_MEM_TO_DEV;
+ cfg.src_addr = 0;
+ cfg.dst_addr = host->bus_addr + SDHCI_BUFFER;
+- ret = dmaengine_slave_config(host->dma_chan_tx, &cfg);
+
+- cfg.direction = DMA_DEV_TO_MEM;
+- cfg.src_addr = host->bus_addr + SDHCI_BUFFER;
+- cfg.dst_addr = 0;
+- ret = dmaengine_slave_config(host->dma_chan_rx, &cfg);
++ ret = dmaengine_slave_config(host->dma_chan_rxtx, &cfg);
++
++ if (ret == 0) {
++ host->dma_cfg_tx = cfg;
++
++ cfg.direction = DMA_DEV_TO_MEM;
++ cfg.src_addr = host->bus_addr + SDHCI_BUFFER;
++ cfg.dst_addr = 0;
++
++ ret = dmaengine_slave_config(host->dma_chan_rxtx, &cfg);
++ }
++
++ if (ret == 0) {
++ host->dma_cfg_rx = cfg;
++
++ host->use_dma = true;
++ } else {
++ pr_err("%s: unable to configure DMA channel. "
++ "Faling back to PIO\n",
++ mmc_hostname(mmc));
++ dma_release_channel(host->dma_chan_rxtx);
++ host->dma_chan_rxtx = NULL;
++ host->use_dma = false;
++ }
+ }
+ #endif
+ mmc->max_segs = 128;
+@@ -1416,16 +1441,20 @@ static int bcm2835_mmc_probe(struct plat
+
+ #ifndef FORCE_PIO
+ if (node) {
+- host->dma_chan_tx = dma_request_slave_channel(dev, "tx");
+- host->dma_chan_rx = dma_request_slave_channel(dev, "rx");
++ host->dma_chan_rxtx = dma_request_slave_channel(dev, "rx-tx");
++ if (!host->dma_chan_rxtx)
++ host->dma_chan_rxtx =
++ dma_request_slave_channel(dev, "tx");
++ if (!host->dma_chan_rxtx)
++ host->dma_chan_rxtx =
++ dma_request_slave_channel(dev, "rx");
+ } else {
+ dma_cap_mask_t mask;
+
+ dma_cap_zero(mask);
+ /* we don't care about the channel, any would work */
+ dma_cap_set(DMA_SLAVE, mask);
+- host->dma_chan_tx = dma_request_channel(mask, NULL, NULL);
+- host->dma_chan_rx = dma_request_channel(mask, NULL, NULL);
++ host->dma_chan_rxtx = dma_request_channel(mask, NULL, NULL);
+ }
+ #endif
+ clk = devm_clk_get(dev, NULL);
diff --git a/target/linux/brcm2708/patches-4.4/0169-DT-Add-overlays-to-configure-I2C-pins.patch b/target/linux/brcm2708/patches-4.4/0169-DT-Add-overlays-to-configure-I2C-pins.patch
deleted file mode 100644
index a010fca7b1..0000000000
--- a/target/linux/brcm2708/patches-4.4/0169-DT-Add-overlays-to-configure-I2C-pins.patch
+++ /dev/null
@@ -1,134 +0,0 @@
-From 310f5af54ca26b68795f0376c67b41e2bb18a0e0 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <6by9@users.noreply.github.com>
-Date: Mon, 8 Feb 2016 23:49:41 +0000
-Subject: [PATCH 169/170] DT: Add overlays to configure I2C pins
-
-Lifted from
-https://www.raspberrypi.org/forums/viewtopic.php?f=107&t=120938&p=825883
-so not claiming this to be my own work.
-Adds overlays i2c0-bcm2708 and i2c1-bcm2708 that allow the pin
-allocations for i2c-0 and i2c-1 to be changed.
----
- arch/arm/boot/dts/overlays/Makefile | 2 ++
- arch/arm/boot/dts/overlays/README | 16 ++++++++++
- .../arm/boot/dts/overlays/i2c0-bcm2708-overlay.dts | 36 +++++++++++++++++++++
- .../arm/boot/dts/overlays/i2c1-bcm2708-overlay.dts | 37 ++++++++++++++++++++++
- 4 files changed, 91 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/i2c0-bcm2708-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/i2c1-bcm2708-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -29,6 +29,8 @@ dtb-$(RPI_DT_OVERLAYS) += hy28a-overlay.
- dtb-$(RPI_DT_OVERLAYS) += hy28b-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += i2c-rtc-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += i2c-gpio-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += i2c0-bcm2708-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += i2c1-bcm2708-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += i2s-mmap-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += iqaudio-dac-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += iqaudio-dacplus-overlay.dtb
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -371,6 +371,22 @@ Params: ds1307 Select t
- pcf8563 Select the PCF8563 device
-
-
-+Name: i2c0-bcm2708
-+Info: Enable the i2c_bcm2708 driver for the i2c0 bus
-+Load: dtoverlay=i2c0-bcm2708,<param>=<val>
-+Params: sda0_pin GPIO pin for SDA0 (0, 28 [or 44] - default 0)
-+ scl0_pin GPIO pin for SCL0 (1, 29 [or 45] - default 1)
-+
-+
-+Name: i2c1-bcm2708
-+Info: Enable the i2c_bcm2708 driver for the i2c1 bus
-+Load: dtoverlay=i2c1-bcm2708,<param>=<val>
-+Params: sda1_pin GPIO pin for SDA1 (2 or 44 - default 2)
-+ scl1_pin GPIO pin for SCL1 (3 or 45 - default 3)
-+ pin_func Alternative pin function (4 (alt0), 6 (alt2) -
-+ default 4)
-+
-+
- Name: i2s-mmap
- Info: Enables mmap support in the bcm2708-i2s driver
- Load: dtoverlay=i2s-mmap
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/i2c0-bcm2708-overlay.dts
-@@ -0,0 +1,36 @@
-+/*
-+ * Device tree overlay for i2c_bcm2708, i2c0 bus
-+ *
-+ * Compile:
-+ * dtc -@ -I dts -O dtb -o i2c0-bcm2708-overlay.dtb i2c0-bcm2708-overlay.dts
-+ */
-+
-+/dts-v1/;
-+/plugin/;
-+
-+/{
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target = <&i2c0>;
-+ __overlay__ {
-+ pinctrl-0 = <&i2c0_pins>;
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ i2c0_pins: i2c0 {
-+ brcm,pins = <0 1>;
-+ brcm,function = <4>; /* alt0 */
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ sda0_pin = <&i2c0_pins>,"brcm,pins:0";
-+ scl0_pin = <&i2c0_pins>,"brcm,pins:4";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/i2c1-bcm2708-overlay.dts
-@@ -0,0 +1,37 @@
-+/*
-+ * Device tree overlay for i2c_bcm2708, i2c1 bus
-+ *
-+ * Compile:
-+ * dtc -@ -I dts -O dtb -o i2c1-bcm2708-overlay.dtb i2c1-bcm2708-overlay.dts
-+ */
-+
-+/dts-v1/;
-+/plugin/;
-+
-+/{
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ pinctrl-0 = <&i2c1_pins>;
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ i2c1_pins: i2c1 {
-+ brcm,pins = <2 3>;
-+ brcm,function = <4>; /* alt0 */
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ sda1_pin = <&i2c1_pins>,"brcm,pins:0";
-+ scl1_pin = <&i2c1_pins>,"brcm,pins:4";
-+ pin_func = <&i2c1_pins>,"brcm,function:0";
-+ };
-+};
diff --git a/target/linux/brcm2708/patches-4.4/0169-config-rebuild-with-savedefconfig.patch b/target/linux/brcm2708/patches-4.4/0169-config-rebuild-with-savedefconfig.patch
new file mode 100644
index 0000000000..c672a32847
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0169-config-rebuild-with-savedefconfig.patch
@@ -0,0 +1,28 @@
+From 6389bb210e68fe23e15260205b35c57f864b7c88 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Tue, 8 Mar 2016 17:08:39 +0000
+Subject: [PATCH 169/381] config: rebuild with savedefconfig
+
+---
+ arch/arm/configs/bcm2709_defconfig | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/arch/arm/configs/bcm2709_defconfig
++++ b/arch/arm/configs/bcm2709_defconfig
+@@ -593,7 +593,6 @@ CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+ CONFIG_SERIAL_OF_PLATFORM=y
+ CONFIG_TTY_PRINTK=y
+ CONFIG_HW_RANDOM=y
+-CONFIG_HW_RANDOM_BCM2835=y
+ CONFIG_RAW_DRIVER=y
+ CONFIG_I2C=y
+ CONFIG_I2C_CHARDEV=m
+@@ -1112,7 +1111,7 @@ CONFIG_EXTCON=m
+ CONFIG_EXTCON_ARIZONA=m
+ CONFIG_IIO=m
+ CONFIG_IIO_BUFFER=y
+-CONFIG_IIO_BUFFER_CB=y
++CONFIG_IIO_BUFFER_CB=m
+ CONFIG_IIO_KFIFO_BUF=m
+ CONFIG_MCP320X=m
+ CONFIG_DHT11=m
diff --git a/target/linux/brcm2708/patches-4.4/0170-bcm2835-camera-fix-a-bug-in-computation-of-frame-tim.patch b/target/linux/brcm2708/patches-4.4/0170-bcm2835-camera-fix-a-bug-in-computation-of-frame-tim.patch
deleted file mode 100644
index 95a193a881..0000000000
--- a/target/linux/brcm2708/patches-4.4/0170-bcm2835-camera-fix-a-bug-in-computation-of-frame-tim.patch
+++ /dev/null
@@ -1,23 +0,0 @@
-From c5cbb66686e7e289e8a7aff49a954f86893e628d Mon Sep 17 00:00:00 2001
-From: Dhiraj Goel <dhiraj.goel@gmail.com>
-Date: Thu, 3 Mar 2016 21:10:50 -0800
-Subject: [PATCH 170/170] bcm2835-camera: fix a bug in computation of frame
- timestamp
-
-Fixes #1318
----
- drivers/media/platform/bcm2835/bcm2835-camera.c | 3 +--
- 1 file changed, 1 insertion(+), 2 deletions(-)
-
---- a/drivers/media/platform/bcm2835/bcm2835-camera.c
-+++ b/drivers/media/platform/bcm2835/bcm2835-camera.c
-@@ -360,8 +360,7 @@ static void buffer_cb(struct vchiq_mmal_
- div =
- div_u64_rem(runtime_us, USEC_PER_SEC, &rem);
- buf->vb.timestamp.tv_sec =
-- dev->capture.kernel_start_ts.tv_sec - 1 +
-- div;
-+ dev->capture.kernel_start_ts.tv_sec + div;
- buf->vb.timestamp.tv_usec =
- dev->capture.kernel_start_ts.tv_usec + rem;
-
diff --git a/target/linux/brcm2708/patches-4.4/0170-config-Add-module-for-mcp3422-ADC.patch b/target/linux/brcm2708/patches-4.4/0170-config-Add-module-for-mcp3422-ADC.patch
new file mode 100644
index 0000000000..bd2be1a3c9
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0170-config-Add-module-for-mcp3422-ADC.patch
@@ -0,0 +1,30 @@
+From a4acb6ac185494a8fcfb02bd2278a25e89fc797c Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Tue, 8 Mar 2016 17:06:33 +0000
+Subject: [PATCH 170/381] config: Add module for mcp3422 ADC
+
+---
+ arch/arm/configs/bcm2709_defconfig | 1 +
+ arch/arm/configs/bcmrpi_defconfig | 1 +
+ 2 files changed, 2 insertions(+)
+
+--- a/arch/arm/configs/bcm2709_defconfig
++++ b/arch/arm/configs/bcm2709_defconfig
+@@ -1114,6 +1114,7 @@ CONFIG_IIO_BUFFER=y
+ CONFIG_IIO_BUFFER_CB=m
+ CONFIG_IIO_KFIFO_BUF=m
+ CONFIG_MCP320X=m
++CONFIG_MCP3422=m
+ CONFIG_DHT11=m
+ CONFIG_PWM_BCM2835=m
+ CONFIG_RASPBERRYPI_FIRMWARE=y
+--- a/arch/arm/configs/bcmrpi_defconfig
++++ b/arch/arm/configs/bcmrpi_defconfig
+@@ -1121,6 +1121,7 @@ CONFIG_IIO_BUFFER=y
+ CONFIG_IIO_BUFFER_CB=m
+ CONFIG_IIO_KFIFO_BUF=m
+ CONFIG_MCP320X=m
++CONFIG_MCP3422=m
+ CONFIG_DHT11=m
+ CONFIG_PWM_BCM2835=m
+ CONFIG_RASPBERRYPI_FIRMWARE=y
diff --git a/target/linux/brcm2708/patches-4.4/0171-BCM270X_DT-Add-pi3-disable-bt-overlay.patch b/target/linux/brcm2708/patches-4.4/0171-BCM270X_DT-Add-pi3-disable-bt-overlay.patch
deleted file mode 100644
index d00439eaa5..0000000000
--- a/target/linux/brcm2708/patches-4.4/0171-BCM270X_DT-Add-pi3-disable-bt-overlay.patch
+++ /dev/null
@@ -1,96 +0,0 @@
-From 42a9bb566fe376a1add4b3780c1b830f64500faa Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Wed, 2 Mar 2016 10:59:05 +0000
-Subject: [PATCH 171/180] BCM270X_DT: Add pi3-disable-bt overlay
-
-Disable Bluetooth and restore UART0/ttyAMA0 over GPIOs 14 & 15. To disable
-the systemd service that initialises the modem so it doesn't use the UART:
-
- sudo systemctl disable hciuart
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 8 ++++
- .../boot/dts/overlays/pi3-disable-bt-overlay.dts | 48 ++++++++++++++++++++++
- 3 files changed, 57 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/pi3-disable-bt-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -39,6 +39,7 @@ dtb-$(RPI_DT_OVERLAYS) += mcp2515-can0-o
- dtb-$(RPI_DT_OVERLAYS) += mcp2515-can1-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += mmc-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += mz61581-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += pi3-disable-bt-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += piscreen-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += piscreen2r-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += pitft28-capacitive-overlay.dtb
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -496,6 +496,14 @@ Params: speed Display
- [ The pcf8563-rtc overlay has been deleted. See i2c-rtc. ]
-
-
-+Name: pi3-disable-bt
-+Info: Disable Pi3 Bluetooth and restore UART0/ttyAMA0 over GPIOs 14 & 15
-+ N.B. To disable the systemd service that initialises the modem so it
-+ doesn't use the UART, use 'sudo systemctl disable hciuart'.
-+Load: dtoverlay=pi3-disable-bt
-+Params: <None>
-+
-+
- Name: piscreen
- Info: PiScreen display by OzzMaker.com
- Load: dtoverlay=piscreen,<param>=<val>
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/pi3-disable-bt-overlay.dts
-@@ -0,0 +1,48 @@
-+/dts-v1/;
-+/plugin/;
-+
-+/* Disable Bluetooth and restore UART0/ttyAMA0 over GPIOs 14 & 15.
-+ To disable the systemd service that initialises the modem so it doesn't use
-+ the UART:
-+
-+ sudo systemctl disable hciuart
-+*/
-+
-+/{
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target = <&uart1>;
-+ __overlay__ {
-+ status = "disabled";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&uart0>;
-+ __overlay__ {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&uart0_pins>;
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ uart0_pins: uart0_pins {
-+ brcm,pins = <14 15>;
-+ brcm,function = <4>; /* alt0 */
-+ brcm,pull = <0 2>;
-+ };
-+ };
-+ };
-+
-+ fragment@3 {
-+ target-path = "/aliases";
-+ __overlay__ {
-+ serial0 = "/soc/uart@7e201000";
-+ serial1 = "/soc/uart@7e215040";
-+ };
-+ };
-+};
diff --git a/target/linux/brcm2708/patches-4.4/0171-Pi3-DT-Add-pull-ups-on-the-UART-RX-lines.patch b/target/linux/brcm2708/patches-4.4/0171-Pi3-DT-Add-pull-ups-on-the-UART-RX-lines.patch
new file mode 100644
index 0000000000..68939338d9
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0171-Pi3-DT-Add-pull-ups-on-the-UART-RX-lines.patch
@@ -0,0 +1,40 @@
+From 511df9d018d5e4c253c36381139e94edb786624c Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Tue, 8 Mar 2016 16:18:57 +0000
+Subject: [PATCH 171/381] Pi3 DT: Add pull-ups on the UART RX lines
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/bcm2710-rpi-3-b.dts | 4 ++--
+ arch/arm/boot/dts/overlays/pi3-miniuart-bt-overlay.dts | 2 +-
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
++++ b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
+@@ -53,13 +53,13 @@
+ uart0_pins: uart0_pins {
+ brcm,pins = <32 33>;
+ brcm,function = <7>; /* alt3=UART0 */
+- brcm,pull = <0 0>;
++ brcm,pull = <0 2>;
+ };
+
+ uart1_pins: uart1_pins {
+ brcm,pins = <14 15>;
+ brcm,function = <2>; /* alt5=UART1 */
+- brcm,pull = <0 0>;
++ brcm,pull = <0 2>;
+ };
+ };
+
+--- a/arch/arm/boot/dts/overlays/pi3-miniuart-bt-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pi3-miniuart-bt-overlay.dts
+@@ -46,7 +46,7 @@
+ uart1_pins: uart1_pins {
+ brcm,pins = <32 33>;
+ brcm,function = <2>; /* alt5=UART1 */
+- brcm,pull = <0 0>;
++ brcm,pull = <0 2>;
+ };
+ };
+ };
diff --git a/target/linux/brcm2708/patches-4.4/0172-BCM270X_DT-Add-pi3-miniuart-bt-DT-overlay.patch b/target/linux/brcm2708/patches-4.4/0172-BCM270X_DT-Add-pi3-miniuart-bt-DT-overlay.patch
deleted file mode 100644
index 3e1031c109..0000000000
--- a/target/linux/brcm2708/patches-4.4/0172-BCM270X_DT-Add-pi3-miniuart-bt-DT-overlay.patch
+++ /dev/null
@@ -1,117 +0,0 @@
-From 3b93a5e60a2272bea6b50561c6e871dde5295dfb Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Mon, 7 Mar 2016 09:53:03 +0000
-Subject: [PATCH 172/180] BCM270X_DT: Add pi3-miniuart-bt DT overlay
-
-Switch Pi3 Bluetooth function to use the mini-UART (ttyS0) and restore
-UART0/ttyAMA0 over GPIOs 14 & 15. Note that this may reduce the maximum
-usable baudrate.
-
-It is also necessary to edit /lib/systemd/system/hciuart.server and
-replace ttyAMA0 with ttyS0.
-
-If cmdline.txt uses the alias serial0 to refer to the user-accessable port
-then the firmware will replace with the appropriate port whether or not
-this overlay is used.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 10 ++++
- .../boot/dts/overlays/pi3-miniuart-bt-overlay.dts | 61 ++++++++++++++++++++++
- 3 files changed, 72 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/pi3-miniuart-bt-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -40,6 +40,7 @@ dtb-$(RPI_DT_OVERLAYS) += mcp2515-can1-o
- dtb-$(RPI_DT_OVERLAYS) += mmc-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += mz61581-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += pi3-disable-bt-overlay.dtb
-+dtb-$(RPI_DT_OVERLAYS) += pi3-miniuart-bt-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += piscreen-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += piscreen2r-overlay.dtb
- dtb-$(RPI_DT_OVERLAYS) += pitft28-capacitive-overlay.dtb
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -504,6 +504,16 @@ Load: dtoverlay=pi3-disable-bt
- Params: <None>
-
-
-+Name: pi3-miniuart-bt
-+Info: Switch Pi3 Bluetooth function to use the mini-UART (ttyS0) and restore
-+ UART0/ttyAMA0 over GPIOs 14 & 15. Note that this may reduce the maximum
-+ usable baudrate.
-+ N.B. It is also necessary to edit /lib/systemd/system/hciuart.server
-+ and replace ttyAMA0 with ttyS0.
-+Load: dtoverlay=pi3-miniuart-bt
-+Params: <None>
-+
-+
- Name: piscreen
- Info: PiScreen display by OzzMaker.com
- Load: dtoverlay=piscreen,<param>=<val>
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/pi3-miniuart-bt-overlay.dts
-@@ -0,0 +1,61 @@
-+/dts-v1/;
-+/plugin/;
-+
-+/* Switch Pi3 Bluetooth function to use the mini-UART (ttyS0) and restore
-+ UART0/ttyAMA0 over GPIOs 14 & 15. Note that this may reduce the maximum
-+ usable baudrate.
-+
-+ It is also necessary to edit /lib/systemd/system/hciuart.server and
-+ replace ttyAMA0 with ttyS0.
-+
-+ If cmdline.txt uses the alias serial0 to refer to the user-accessable port
-+ then the firmware will replace with the appropriate port whether or not
-+ this overlay is used.
-+*/
-+
-+/{
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target = <&uart0>;
-+ __overlay__ {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&uart0_pins>;
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&uart1>;
-+ __overlay__ {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&uart1_pins>;
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ uart0_pins: uart0_pins {
-+ brcm,pins = <14 15>;
-+ brcm,function = <4>; /* alt0 */
-+ brcm,pull = <0 2>;
-+ };
-+
-+ uart1_pins: uart1_pins {
-+ brcm,pins = <32 33>;
-+ brcm,function = <2>; /* alt5=UART1 */
-+ brcm,pull = <0 0>;
-+ };
-+ };
-+ };
-+
-+ fragment@3 {
-+ target-path = "/aliases";
-+ __overlay__ {
-+ serial0 = "/soc/uart@7e201000";
-+ serial1 = "/soc/uart@7e215040";
-+ };
-+ };
-+};
diff --git a/target/linux/brcm2708/patches-4.4/0173-BCM270X_DT-rpi-display-overlay-add-swapxy-param.patch b/target/linux/brcm2708/patches-4.4/0173-BCM270X_DT-rpi-display-overlay-add-swapxy-param.patch
new file mode 100644
index 0000000000..fb0bf778fb
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0173-BCM270X_DT-rpi-display-overlay-add-swapxy-param.patch
@@ -0,0 +1,38 @@
+From ba5bc2239693e23712782093d5b2aa31d9e07dff Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Wed, 9 Mar 2016 21:28:52 +0000
+Subject: [PATCH 173/381] BCM270X_DT: rpi-display overlay - add swapxy param
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/overlays/README | 5 +----
+ arch/arm/boot/dts/overlays/rpi-display-overlay.dts | 1 +
+ 2 files changed, 2 insertions(+), 4 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -644,14 +644,11 @@ Name: rpi-display
+ Info: RPi-Display - 2.8" Touch Display by Watterott
+ Load: dtoverlay=rpi-display,<param>=<val>
+ Params: speed Display SPI bus speed
+-
+ rotate Display rotation {0,90,180,270}
+-
+ fps Delay between frame updates
+-
+ debug Debug output level {0-7}
+-
+ xohms Touchpanel sensitivity (X-plate resistance)
++ swapxy Swap x and y axis
+
+
+ Name: rpi-ft5406
+--- a/arch/arm/boot/dts/overlays/rpi-display-overlay.dts
++++ b/arch/arm/boot/dts/overlays/rpi-display-overlay.dts
+@@ -78,5 +78,6 @@
+ fps = <&rpidisplay>,"fps:0";
+ debug = <&rpidisplay>,"debug:0";
+ xohms = <&rpidisplay_ts>,"ti,x-plate-ohms;0";
++ swapxy = <&rpidisplay_ts>,"ti,swap-xy?";
+ };
+ };
diff --git a/target/linux/brcm2708/patches-4.4/0173-Pi3-DT-Add-dtparams-for-the-SD-interface.patch b/target/linux/brcm2708/patches-4.4/0173-Pi3-DT-Add-dtparams-for-the-SD-interface.patch
deleted file mode 100644
index f9e4767f8a..0000000000
--- a/target/linux/brcm2708/patches-4.4/0173-Pi3-DT-Add-dtparams-for-the-SD-interface.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-From c8b56d0359160d2aec2ab3168ef9d7c080ae9841 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Mon, 7 Mar 2016 13:38:39 +0000
-Subject: [PATCH 173/180] Pi3 DT: Add dtparams for the SD interface
-
-Add new base dtparams sd_overclock, sd_force_pio, sd_pio_limit
-and sd_debug. These were missed out of the initial Pi3 DTB.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- arch/arm/boot/dts/bcm2710-rpi-3-b.dts | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
-+++ b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
-@@ -188,5 +188,9 @@
- audio = <&audio>,"status";
- watchdog = <&watchdog>,"status";
- random = <&random>,"status";
-+ sd_overclock = <&sdhost>,"brcm,overclock-50:0";
-+ sd_force_pio = <&sdhost>,"brcm,force-pio?";
-+ sd_pio_limit = <&sdhost>,"brcm,pio-limit:0";
-+ sd_debug = <&sdhost>,"brcm,debug";
- };
- };
diff --git a/target/linux/brcm2708/patches-4.4/0174-Remove-I2S-config-from-bt_pins.patch b/target/linux/brcm2708/patches-4.4/0174-Remove-I2S-config-from-bt_pins.patch
new file mode 100644
index 0000000000..53005a3876
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0174-Remove-I2S-config-from-bt_pins.patch
@@ -0,0 +1,38 @@
+From 4ccd91956356493bd7d84c98123d972b827be02d Mon Sep 17 00:00:00 2001
+From: DigitalDreamtime <clive.messer@digitaldreamtime.co.uk>
+Date: Fri, 11 Mar 2016 11:44:35 +0000
+Subject: [PATCH 174/381] Remove I2S config from bt_pins.
+
+Remove I2S config from bt_pins. Causes issues with clock alignment when I2S is
+used by an external DAC via GPIO header.
+---
+ arch/arm/boot/dts/bcm2710-rpi-3-b.dts | 6 +++---
+ arch/arm/boot/dts/overlays/pi3-miniuart-bt-overlay.dts | 2 +-
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
++++ b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
+@@ -45,9 +45,9 @@
+ };
+
+ bt_pins: bt_pins {
+- brcm,pins = <28 29 30 31 43>;
+- brcm,function = <6 6 6 6 4>; /* alt2:PCM alt0:GPCLK2 */
+- brcm,pull = <0 0 0 0 0>;
++ brcm,pins = <43>;
++ brcm,function = <4>; /* alt0:GPCLK2 */
++ brcm,pull = <0>;
+ };
+
+ uart0_pins: uart0_pins {
+--- a/arch/arm/boot/dts/overlays/pi3-miniuart-bt-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pi3-miniuart-bt-overlay.dts
+@@ -29,7 +29,7 @@
+ target = <&uart1>;
+ __overlay__ {
+ pinctrl-names = "default";
+- pinctrl-0 = <&uart1_pins>;
++ pinctrl-0 = <&uart1_pins &bt_pins>;
+ status = "okay";
+ };
+ };
diff --git a/target/linux/brcm2708/patches-4.4/0174-vchiq_arm-Tweak-the-logging-output.patch b/target/linux/brcm2708/patches-4.4/0174-vchiq_arm-Tweak-the-logging-output.patch
deleted file mode 100644
index 536c6ce2bc..0000000000
--- a/target/linux/brcm2708/patches-4.4/0174-vchiq_arm-Tweak-the-logging-output.patch
+++ /dev/null
@@ -1,75 +0,0 @@
-From 48f3f7707a43b019e14216cec7376eba21972f9b Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Mon, 7 Mar 2016 15:05:11 +0000
-Subject: [PATCH 174/180] vchiq_arm: Tweak the logging output
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- .../vc04_services/interface/vchiq_arm/vchiq_core.c | 31 +++++++++-------------
- 1 file changed, 13 insertions(+), 18 deletions(-)
-
---- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c
-+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c
-@@ -891,16 +891,14 @@ queue_message(VCHIQ_STATE_T *state, VCHI
- error_count);
- return VCHIQ_ERROR;
- }
-- if (i == 0) {
-- if (SRVTRACE_ENABLED(service,
-- VCHIQ_LOG_INFO))
-- vchiq_log_dump_mem("Sent", 0,
-- header->data + pos,
-- min(64u,
-- elements[0].size));
-- }
- }
-
-+ if (SRVTRACE_ENABLED(service,
-+ VCHIQ_LOG_INFO))
-+ vchiq_log_dump_mem("Sent", 0,
-+ header->data,
-+ min(16, pos));
-+
- spin_lock(&quota_spinlock);
- service_quota->message_use_count++;
-
-@@ -1039,16 +1037,13 @@ queue_message_sync(VCHIQ_STATE_T *state,
- error_count);
- return VCHIQ_ERROR;
- }
-- if (i == 0) {
-- if (vchiq_sync_log_level >=
-- VCHIQ_LOG_TRACE)
-- vchiq_log_dump_mem("Sent Sync",
-- 0, header->data + pos,
-- min(64u,
-- elements[0].size));
-- }
- }
-
-+ if (vchiq_sync_log_level >= VCHIQ_LOG_TRACE)
-+ vchiq_log_dump_mem("Sent Sync",
-+ 0, header->data,
-+ min(16, pos));
-+
- VCHIQ_SERVICE_STATS_INC(service, ctrl_tx_count);
- VCHIQ_SERVICE_STATS_ADD(service, ctrl_tx_bytes, size);
- } else {
-@@ -1720,7 +1715,7 @@ parse_rx_slots(VCHIQ_STATE_T *state)
- remoteport, localport, size);
- if (size > 0)
- vchiq_log_dump_mem("Rcvd", 0, header->data,
-- min(64, size));
-+ min(16, size));
- }
-
- if (((unsigned int)header & VCHIQ_SLOT_MASK) + calc_stride(size)
-@@ -2187,7 +2182,7 @@ sync_func(void *v)
- remoteport, localport, size);
- if (size > 0)
- vchiq_log_dump_mem("Rcvd", 0, header->data,
-- min(64, size));
-+ min(16, size));
- }
-
- switch (type) {
diff --git a/target/linux/brcm2708/patches-4.4/0175-Revert-scripts-dtc-Add-overlay-support.patch b/target/linux/brcm2708/patches-4.4/0175-Revert-scripts-dtc-Add-overlay-support.patch
new file mode 100644
index 0000000000..23525f9d8e
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0175-Revert-scripts-dtc-Add-overlay-support.patch
@@ -0,0 +1,4390 @@
+From 8534735503255814ae6fffc19e30e03ca4ccbc75 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 10 Aug 2015 09:44:59 +0100
+Subject: [PATCH 175/381] Revert "scripts/dtc: Add overlay support"
+
+This reverts commit fa6d1755c2fdd9451077d8248e3804f0619f19b9.
+---
+ scripts/dtc/checks.c | 119 +--
+ scripts/dtc/dtc-lexer.l | 5 -
+ scripts/dtc/dtc-lexer.lex.c_shipped | 490 +++++----
+ scripts/dtc/dtc-parser.tab.c_shipped | 1896 +++++++++++++++-------------------
+ scripts/dtc/dtc-parser.tab.h_shipped | 107 +-
+ scripts/dtc/dtc-parser.y | 23 +-
+ scripts/dtc/dtc.c | 9 +-
+ scripts/dtc/dtc.h | 38 -
+ scripts/dtc/flattree.c | 141 +--
+ scripts/dtc/version_gen.h | 2 +-
+ 10 files changed, 1145 insertions(+), 1685 deletions(-)
+
+--- a/scripts/dtc/checks.c
++++ b/scripts/dtc/checks.c
+@@ -458,91 +458,21 @@ static void fixup_phandle_references(str
+ struct node *node, struct property *prop)
+ {
+ struct marker *m = prop->val.markers;
+- struct fixup *f, **fp;
+- struct fixup_entry *fe, **fep;
+ struct node *refnode;
+ cell_t phandle;
+- int has_phandle_refs;
+-
+- has_phandle_refs = 0;
+- for_each_marker_of_type(m, REF_PHANDLE) {
+- has_phandle_refs = 1;
+- break;
+- }
+-
+- if (!has_phandle_refs)
+- return;
+
+ for_each_marker_of_type(m, REF_PHANDLE) {
+ assert(m->offset + sizeof(cell_t) <= prop->val.len);
+
+ refnode = get_node_by_ref(dt, m->ref);
+- if (!refnode && !symbol_fixup_support) {
++ if (! refnode) {
+ FAIL(c, "Reference to non-existent node or label \"%s\"\n",
+- m->ref);
++ m->ref);
+ continue;
+ }
+
+- if (!refnode) {
+- /* allocate fixup entry */
+- fe = xmalloc(sizeof(*fe));
+-
+- fe->node = node;
+- fe->prop = prop;
+- fe->offset = m->offset;
+- fe->next = NULL;
+-
+- /* search for an already existing fixup */
+- for_each_fixup(dt, f)
+- if (strcmp(f->ref, m->ref) == 0)
+- break;
+-
+- /* no fixup found, add new */
+- if (f == NULL) {
+- f = xmalloc(sizeof(*f));
+- f->ref = m->ref;
+- f->entries = NULL;
+- f->next = NULL;
+-
+- /* add it to the tree */
+- fp = &dt->fixups;
+- while (*fp)
+- fp = &(*fp)->next;
+- *fp = f;
+- }
+-
+- /* and now append fixup entry */
+- fep = &f->entries;
+- while (*fep)
+- fep = &(*fep)->next;
+- *fep = fe;
+-
+- /* mark the entry as unresolved */
+- phandle = 0xdeadbeef;
+- } else {
+- phandle = get_node_phandle(dt, refnode);
+-
+- /* if it's a plugin, we need to record it */
+- if (symbol_fixup_support && dt->is_plugin) {
+-
+- /* allocate a new local fixup entry */
+- fe = xmalloc(sizeof(*fe));
+-
+- fe->node = node;
+- fe->prop = prop;
+- fe->offset = m->offset;
+- fe->next = NULL;
+-
+- /* append it to the local fixups */
+- fep = &dt->local_fixups;
+- while (*fep)
+- fep = &(*fep)->next;
+- *fep = fe;
+- }
+- }
+-
+- *((cell_t *)(prop->val.val + m->offset)) =
+- cpu_to_fdt32(phandle);
++ phandle = get_node_phandle(dt, refnode);
++ *((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
+ }
+ }
+ ERROR(phandle_references, NULL, NULL, fixup_phandle_references, NULL,
+@@ -722,45 +652,6 @@ static void check_obsolete_chosen_interr
+ }
+ TREE_WARNING(obsolete_chosen_interrupt_controller, NULL);
+
+-static void check_auto_label_phandles(struct check *c, struct node *dt,
+- struct node *node)
+-{
+- struct label *l;
+- struct symbol *s, **sp;
+- int has_label;
+-
+- if (!symbol_fixup_support)
+- return;
+-
+- has_label = 0;
+- for_each_label(node->labels, l) {
+- has_label = 1;
+- break;
+- }
+-
+- if (!has_label)
+- return;
+-
+- /* force allocation of a phandle for this node */
+- (void)get_node_phandle(dt, node);
+-
+- /* add the symbol */
+- for_each_label(node->labels, l) {
+-
+- s = xmalloc(sizeof(*s));
+- s->label = l;
+- s->node = node;
+- s->next = NULL;
+-
+- /* add it to the symbols list */
+- sp = &dt->symbols;
+- while (*sp)
+- sp = &((*sp)->next);
+- *sp = s;
+- }
+-}
+-NODE_WARNING(auto_label_phandles, NULL);
+-
+ static struct check *check_table[] = {
+ &duplicate_node_names, &duplicate_property_names,
+ &node_name_chars, &node_name_format, &property_name_chars,
+@@ -779,8 +670,6 @@ static struct check *check_table[] = {
+ &avoid_default_addr_size,
+ &obsolete_chosen_interrupt_controller,
+
+- &auto_label_phandles,
+-
+ &always_fail,
+ };
+
+--- a/scripts/dtc/dtc-lexer.l
++++ b/scripts/dtc/dtc-lexer.l
+@@ -113,11 +113,6 @@ static void lexical_error(const char *fm
+ return DT_V1;
+ }
+
+-<*>"/plugin/" {
+- DPRINT("Keyword: /plugin/\n");
+- return DT_PLUGIN;
+- }
+-
+ <*>"/memreserve/" {
+ DPRINT("Keyword: /memreserve/\n");
+ BEGIN_DEFAULT();
+--- a/scripts/dtc/dtc-lexer.lex.c_shipped
++++ b/scripts/dtc/dtc-lexer.lex.c_shipped
+@@ -9,7 +9,7 @@
+ #define FLEX_SCANNER
+ #define YY_FLEX_MAJOR_VERSION 2
+ #define YY_FLEX_MINOR_VERSION 5
+-#define YY_FLEX_SUBMINOR_VERSION 35
++#define YY_FLEX_SUBMINOR_VERSION 39
+ #if YY_FLEX_SUBMINOR_VERSION > 0
+ #define FLEX_BETA
+ #endif
+@@ -162,7 +162,12 @@ typedef unsigned int flex_uint32_t;
+ typedef struct yy_buffer_state *YY_BUFFER_STATE;
+ #endif
+
+-extern int yyleng;
++#ifndef YY_TYPEDEF_YY_SIZE_T
++#define YY_TYPEDEF_YY_SIZE_T
++typedef size_t yy_size_t;
++#endif
++
++extern yy_size_t yyleng;
+
+ extern FILE *yyin, *yyout;
+
+@@ -171,6 +176,7 @@ extern FILE *yyin, *yyout;
+ #define EOB_ACT_LAST_MATCH 2
+
+ #define YY_LESS_LINENO(n)
++ #define YY_LINENO_REWIND_TO(ptr)
+
+ /* Return all but the first "n" matched characters back to the input stream. */
+ #define yyless(n) \
+@@ -188,11 +194,6 @@ extern FILE *yyin, *yyout;
+
+ #define unput(c) yyunput( c, (yytext_ptr) )
+
+-#ifndef YY_TYPEDEF_YY_SIZE_T
+-#define YY_TYPEDEF_YY_SIZE_T
+-typedef size_t yy_size_t;
+-#endif
+-
+ #ifndef YY_STRUCT_YY_BUFFER_STATE
+ #define YY_STRUCT_YY_BUFFER_STATE
+ struct yy_buffer_state
+@@ -210,7 +211,7 @@ struct yy_buffer_state
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+- int yy_n_chars;
++ yy_size_t yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+@@ -280,8 +281,8 @@ static YY_BUFFER_STATE * yy_buffer_stack
+
+ /* yy_hold_char holds the character lost when yytext is formed. */
+ static char yy_hold_char;
+-static int yy_n_chars; /* number of characters read into yy_ch_buf */
+-int yyleng;
++static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */
++yy_size_t yyleng;
+
+ /* Points to current character in buffer. */
+ static char *yy_c_buf_p = (char *) 0;
+@@ -309,7 +310,7 @@ static void yy_init_buffer (YY_BUFFER_ST
+
+ YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size );
+ YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str );
+-YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len );
++YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len );
+
+ void *yyalloc (yy_size_t );
+ void *yyrealloc (void *,yy_size_t );
+@@ -341,7 +342,7 @@ void yyfree (void * );
+
+ /* Begin user sect3 */
+
+-#define yywrap(n) 1
++#define yywrap() 1
+ #define YY_SKIP_YYWRAP
+
+ typedef unsigned char YY_CHAR;
+@@ -372,8 +373,8 @@ static void yy_fatal_error (yyconst char
+ *yy_cp = '\0'; \
+ (yy_c_buf_p) = yy_cp;
+
+-#define YY_NUM_RULES 31
+-#define YY_END_OF_BUFFER 32
++#define YY_NUM_RULES 30
++#define YY_END_OF_BUFFER 31
+ /* This struct is not used in this scanner,
+ but its presence is necessary. */
+ struct yy_trans_info
+@@ -381,26 +382,25 @@ struct yy_trans_info
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+-static yyconst flex_int16_t yy_accept[166] =
++static yyconst flex_int16_t yy_accept[159] =
+ { 0,
+- 0, 0, 0, 0, 0, 0, 0, 0, 32, 30,
+- 19, 19, 30, 30, 30, 30, 30, 30, 30, 30,
+- 30, 30, 30, 30, 30, 30, 16, 17, 17, 30,
+- 17, 11, 11, 19, 27, 0, 3, 0, 28, 13,
+- 0, 0, 12, 0, 0, 0, 0, 0, 0, 0,
+- 0, 22, 24, 26, 25, 23, 0, 10, 29, 0,
+- 0, 0, 15, 15, 17, 17, 17, 11, 11, 11,
+- 0, 13, 0, 12, 0, 0, 0, 21, 0, 0,
+- 0, 0, 0, 0, 0, 0, 0, 17, 11, 11,
+- 11, 0, 14, 20, 0, 0, 0, 0, 0, 0,
+-
+- 0, 0, 0, 0, 17, 0, 0, 0, 0, 0,
+- 0, 0, 0, 0, 0, 17, 7, 0, 0, 0,
+- 0, 0, 0, 0, 2, 0, 0, 0, 0, 0,
+- 0, 0, 0, 0, 4, 18, 0, 0, 5, 2,
+- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+- 0, 0, 1, 0, 0, 0, 0, 6, 9, 0,
+- 0, 0, 0, 8, 0
++ 0, 0, 0, 0, 0, 0, 0, 0, 31, 29,
++ 18, 18, 29, 29, 29, 29, 29, 29, 29, 29,
++ 29, 29, 29, 29, 29, 29, 15, 16, 16, 29,
++ 16, 10, 10, 18, 26, 0, 3, 0, 27, 12,
++ 0, 0, 11, 0, 0, 0, 0, 0, 0, 0,
++ 21, 23, 25, 24, 22, 0, 9, 28, 0, 0,
++ 0, 14, 14, 16, 16, 16, 10, 10, 10, 0,
++ 12, 0, 11, 0, 0, 0, 20, 0, 0, 0,
++ 0, 0, 0, 0, 0, 16, 10, 10, 10, 0,
++ 13, 19, 0, 0, 0, 0, 0, 0, 0, 0,
++
++ 0, 16, 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 16, 6, 0, 0, 0, 0, 0, 0, 2,
++ 0, 0, 0, 0, 0, 0, 0, 0, 4, 17,
++ 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
++ 5, 8, 0, 0, 0, 0, 7, 0
+ } ;
+
+ static yyconst flex_int32_t yy_ec[256] =
+@@ -416,9 +416,9 @@ static yyconst flex_int32_t yy_ec[256] =
+ 22, 22, 22, 22, 24, 22, 22, 25, 22, 22,
+ 1, 26, 27, 1, 22, 1, 21, 28, 29, 30,
+
+- 31, 21, 32, 22, 33, 22, 22, 34, 35, 36,
+- 37, 38, 22, 39, 40, 41, 42, 43, 22, 25,
+- 44, 22, 45, 46, 47, 1, 1, 1, 1, 1,
++ 31, 21, 22, 22, 32, 22, 22, 33, 34, 35,
++ 36, 37, 22, 38, 39, 40, 41, 42, 22, 25,
++ 43, 22, 44, 45, 46, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+@@ -435,165 +435,163 @@ static yyconst flex_int32_t yy_ec[256] =
+ 1, 1, 1, 1, 1
+ } ;
+
+-static yyconst flex_int32_t yy_meta[48] =
++static yyconst flex_int32_t yy_meta[47] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 2, 3, 1, 2,
+ 2, 2, 4, 5, 5, 5, 6, 1, 1, 1,
+ 7, 8, 8, 8, 8, 1, 1, 7, 7, 7,
+ 7, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+- 8, 8, 8, 8, 3, 1, 4
++ 8, 8, 8, 3, 1, 4
+ } ;
+
+-static yyconst flex_int16_t yy_base[180] =
++static yyconst flex_int16_t yy_base[173] =
+ { 0,
+- 0, 393, 35, 392, 66, 391, 38, 107, 397, 401,
+- 55, 113, 377, 112, 111, 111, 114, 42, 376, 106,
+- 377, 347, 126, 120, 0, 147, 401, 0, 124, 0,
+- 137, 158, 170, 163, 401, 153, 401, 389, 401, 0,
+- 378, 120, 401, 131, 380, 386, 355, 139, 351, 355,
+- 351, 401, 401, 401, 401, 401, 367, 401, 401, 185,
+- 350, 346, 401, 364, 0, 185, 347, 189, 356, 355,
+- 0, 0, 330, 180, 366, 141, 372, 361, 332, 338,
+- 331, 341, 334, 326, 205, 331, 337, 329, 401, 341,
+- 167, 316, 401, 349, 348, 320, 328, 346, 180, 318,
+-
+- 324, 209, 324, 320, 322, 342, 338, 309, 306, 315,
+- 305, 315, 312, 192, 342, 341, 401, 293, 306, 282,
+- 268, 252, 255, 203, 285, 282, 272, 268, 252, 233,
+- 232, 239, 208, 107, 401, 401, 238, 211, 401, 211,
+- 212, 208, 228, 203, 215, 207, 233, 222, 212, 211,
+- 203, 227, 401, 237, 225, 204, 185, 401, 401, 149,
+- 128, 88, 42, 401, 401, 253, 259, 267, 271, 275,
+- 281, 288, 292, 300, 308, 312, 318, 326, 334
++ 0, 383, 34, 382, 65, 381, 37, 105, 387, 391,
++ 54, 111, 367, 110, 109, 109, 112, 41, 366, 104,
++ 367, 338, 124, 117, 0, 144, 391, 0, 121, 0,
++ 135, 155, 140, 179, 391, 160, 391, 379, 391, 0,
++ 368, 141, 391, 167, 370, 376, 346, 103, 342, 345,
++ 391, 391, 391, 391, 391, 358, 391, 391, 175, 342,
++ 338, 391, 355, 0, 185, 339, 184, 347, 346, 0,
++ 0, 322, 175, 357, 175, 363, 352, 324, 330, 323,
++ 332, 326, 201, 324, 329, 322, 391, 333, 181, 309,
++ 391, 341, 340, 313, 320, 338, 178, 311, 146, 317,
++
++ 314, 315, 335, 331, 303, 300, 309, 299, 308, 188,
++ 336, 335, 391, 305, 320, 281, 283, 271, 203, 288,
++ 281, 271, 266, 264, 245, 242, 208, 104, 391, 391,
++ 244, 218, 204, 219, 206, 224, 201, 212, 204, 229,
++ 215, 208, 207, 200, 219, 391, 233, 221, 200, 181,
++ 391, 391, 149, 122, 86, 41, 391, 391, 245, 251,
++ 259, 263, 267, 273, 280, 284, 292, 300, 304, 310,
++ 318, 326
+ } ;
+
+-static yyconst flex_int16_t yy_def[180] =
++static yyconst flex_int16_t yy_def[173] =
+ { 0,
+- 165, 1, 1, 3, 165, 5, 1, 1, 165, 165,
+- 165, 165, 165, 166, 167, 168, 165, 165, 165, 165,
+- 169, 165, 165, 165, 170, 169, 165, 171, 172, 171,
+- 171, 165, 165, 165, 165, 166, 165, 166, 165, 173,
+- 165, 168, 165, 168, 174, 175, 165, 165, 165, 165,
+- 165, 165, 165, 165, 165, 165, 169, 165, 165, 165,
+- 165, 165, 165, 169, 171, 172, 171, 165, 165, 165,
+- 176, 173, 177, 168, 174, 174, 175, 165, 165, 165,
+- 165, 165, 165, 165, 165, 165, 165, 171, 165, 165,
+- 176, 177, 165, 165, 165, 165, 165, 165, 165, 165,
+-
+- 165, 165, 165, 165, 171, 165, 165, 165, 165, 165,
+- 165, 165, 165, 178, 165, 171, 165, 165, 165, 165,
+- 165, 165, 165, 178, 165, 178, 165, 165, 165, 165,
+- 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
+- 165, 165, 165, 165, 165, 165, 165, 179, 165, 165,
+- 165, 179, 165, 179, 165, 165, 165, 165, 165, 165,
+- 165, 165, 165, 165, 0, 165, 165, 165, 165, 165,
+- 165, 165, 165, 165, 165, 165, 165, 165, 165
++ 158, 1, 1, 3, 158, 5, 1, 1, 158, 158,
++ 158, 158, 158, 159, 160, 161, 158, 158, 158, 158,
++ 162, 158, 158, 158, 163, 162, 158, 164, 165, 164,
++ 164, 158, 158, 158, 158, 159, 158, 159, 158, 166,
++ 158, 161, 158, 161, 167, 168, 158, 158, 158, 158,
++ 158, 158, 158, 158, 158, 162, 158, 158, 158, 158,
++ 158, 158, 162, 164, 165, 164, 158, 158, 158, 169,
++ 166, 170, 161, 167, 167, 168, 158, 158, 158, 158,
++ 158, 158, 158, 158, 158, 164, 158, 158, 169, 170,
++ 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
++
++ 158, 164, 158, 158, 158, 158, 158, 158, 158, 171,
++ 158, 164, 158, 158, 158, 158, 158, 158, 171, 158,
++ 171, 158, 158, 158, 158, 158, 158, 158, 158, 158,
++ 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
++ 172, 158, 158, 158, 172, 158, 172, 158, 158, 158,
++ 158, 158, 158, 158, 158, 158, 158, 0, 158, 158,
++ 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
++ 158, 158
+ } ;
+
+-static yyconst flex_int16_t yy_nxt[449] =
++static yyconst flex_int16_t yy_nxt[438] =
+ { 0,
+ 10, 11, 12, 11, 13, 14, 10, 15, 16, 10,
+ 10, 10, 17, 10, 10, 10, 10, 18, 19, 20,
+ 21, 21, 21, 21, 21, 10, 10, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+- 21, 21, 21, 21, 10, 22, 10, 24, 25, 25,
+- 25, 32, 33, 33, 164, 26, 34, 34, 34, 52,
+- 53, 27, 26, 26, 26, 26, 10, 11, 12, 11,
+- 13, 14, 28, 15, 16, 28, 28, 28, 24, 28,
+- 28, 28, 10, 18, 19, 20, 29, 29, 29, 29,
+- 29, 30, 10, 29, 29, 29, 29, 29, 29, 29,
+-
+- 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+- 10, 22, 10, 23, 34, 34, 34, 37, 39, 43,
+- 32, 33, 33, 45, 55, 56, 46, 60, 43, 45,
+- 65, 163, 46, 65, 65, 65, 44, 38, 60, 74,
+- 58, 47, 141, 48, 142, 44, 49, 47, 50, 48,
+- 76, 51, 62, 94, 50, 41, 44, 51, 37, 61,
+- 64, 64, 64, 58, 34, 34, 34, 64, 162, 80,
+- 67, 68, 68, 68, 64, 64, 64, 64, 38, 81,
+- 69, 70, 71, 68, 68, 68, 60, 161, 43, 69,
+- 70, 65, 69, 70, 65, 65, 65, 125, 85, 85,
+-
+- 85, 58, 68, 68, 68, 44, 102, 110, 125, 133,
+- 102, 69, 70, 111, 114, 160, 159, 126, 85, 85,
+- 85, 140, 140, 140, 140, 140, 140, 153, 126, 147,
+- 147, 147, 153, 148, 147, 147, 147, 158, 148, 165,
+- 157, 156, 155, 151, 150, 149, 146, 154, 145, 144,
+- 143, 139, 154, 36, 36, 36, 36, 36, 36, 36,
+- 36, 40, 138, 137, 136, 40, 40, 42, 42, 42,
+- 42, 42, 42, 42, 42, 57, 57, 57, 57, 63,
+- 135, 63, 65, 134, 165, 65, 133, 65, 65, 66,
+- 132, 131, 66, 66, 66, 66, 72, 130, 72, 72,
+-
+- 75, 75, 75, 75, 75, 75, 75, 75, 77, 77,
+- 77, 77, 77, 77, 77, 77, 91, 129, 91, 92,
+- 128, 92, 92, 127, 92, 92, 124, 124, 124, 124,
+- 124, 124, 124, 124, 152, 152, 152, 152, 152, 152,
+- 152, 152, 60, 60, 123, 122, 121, 120, 119, 118,
+- 117, 45, 116, 111, 115, 113, 112, 109, 108, 107,
+- 46, 106, 93, 89, 105, 104, 103, 101, 100, 99,
+- 98, 97, 96, 95, 78, 76, 93, 90, 89, 88,
+- 58, 87, 86, 58, 84, 83, 82, 79, 78, 76,
+- 73, 165, 59, 58, 54, 35, 165, 31, 23, 23,
+-
+- 9, 165, 165, 165, 165, 165, 165, 165, 165, 165,
+- 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
+- 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
+- 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
+- 165, 165, 165, 165, 165, 165, 165, 165
++ 21, 21, 21, 10, 22, 10, 24, 25, 25, 25,
++ 32, 33, 33, 157, 26, 34, 34, 34, 51, 52,
++ 27, 26, 26, 26, 26, 10, 11, 12, 11, 13,
++ 14, 28, 15, 16, 28, 28, 28, 24, 28, 28,
++ 28, 10, 18, 19, 20, 29, 29, 29, 29, 29,
++ 30, 10, 29, 29, 29, 29, 29, 29, 29, 29,
++
++ 29, 29, 29, 29, 29, 29, 29, 29, 10, 22,
++ 10, 23, 34, 34, 34, 37, 39, 43, 32, 33,
++ 33, 45, 54, 55, 46, 59, 45, 64, 156, 46,
++ 64, 64, 64, 79, 44, 38, 59, 57, 134, 47,
++ 135, 48, 80, 49, 47, 50, 48, 99, 61, 43,
++ 50, 110, 41, 67, 67, 67, 60, 63, 63, 63,
++ 57, 155, 68, 69, 63, 37, 44, 66, 67, 67,
++ 67, 63, 63, 63, 63, 73, 59, 68, 69, 70,
++ 34, 34, 34, 43, 75, 38, 154, 92, 83, 83,
++ 83, 64, 44, 120, 64, 64, 64, 67, 67, 67,
++
++ 44, 57, 99, 68, 69, 107, 68, 69, 120, 127,
++ 108, 153, 152, 121, 83, 83, 83, 133, 133, 133,
++ 146, 133, 133, 133, 146, 140, 140, 140, 121, 141,
++ 140, 140, 140, 151, 141, 158, 150, 149, 148, 144,
++ 147, 143, 142, 139, 147, 36, 36, 36, 36, 36,
++ 36, 36, 36, 40, 138, 137, 136, 40, 40, 42,
++ 42, 42, 42, 42, 42, 42, 42, 56, 56, 56,
++ 56, 62, 132, 62, 64, 131, 130, 64, 129, 64,
++ 64, 65, 128, 158, 65, 65, 65, 65, 71, 127,
++ 71, 71, 74, 74, 74, 74, 74, 74, 74, 74,
++
++ 76, 76, 76, 76, 76, 76, 76, 76, 89, 126,
++ 89, 90, 125, 90, 90, 124, 90, 90, 119, 119,
++ 119, 119, 119, 119, 119, 119, 145, 145, 145, 145,
++ 145, 145, 145, 145, 123, 122, 59, 59, 118, 117,
++ 116, 115, 114, 113, 45, 112, 108, 111, 109, 106,
++ 105, 104, 46, 103, 91, 87, 102, 101, 100, 98,
++ 97, 96, 95, 94, 93, 77, 75, 91, 88, 87,
++ 86, 57, 85, 84, 57, 82, 81, 78, 77, 75,
++ 72, 158, 58, 57, 53, 35, 158, 31, 23, 23,
++ 9, 158, 158, 158, 158, 158, 158, 158, 158, 158,
++
++ 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
++ 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
++ 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
++ 158, 158, 158, 158, 158, 158, 158
+ } ;
+
+-static yyconst flex_int16_t yy_chk[449] =
++static yyconst flex_int16_t yy_chk[438] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+- 1, 1, 1, 1, 1, 1, 1, 3, 3, 3,
+- 3, 7, 7, 7, 163, 3, 11, 11, 11, 18,
+- 18, 3, 3, 3, 3, 3, 5, 5, 5, 5,
++ 1, 1, 1, 1, 1, 1, 3, 3, 3, 3,
++ 7, 7, 7, 156, 3, 11, 11, 11, 18, 18,
++ 3, 3, 3, 3, 3, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+- 5, 5, 5, 8, 12, 12, 12, 14, 15, 16,
+- 8, 8, 8, 17, 20, 20, 17, 23, 42, 24,
+- 29, 162, 24, 29, 29, 29, 16, 14, 31, 44,
+- 29, 17, 134, 17, 134, 42, 17, 24, 17, 24,
+- 76, 17, 24, 76, 24, 15, 44, 24, 36, 23,
+- 26, 26, 26, 26, 34, 34, 34, 26, 161, 48,
+- 31, 32, 32, 32, 26, 26, 26, 26, 36, 48,
+- 32, 32, 32, 33, 33, 33, 60, 160, 74, 91,
+- 91, 66, 33, 33, 66, 66, 66, 114, 60, 60,
+-
+- 60, 66, 68, 68, 68, 74, 85, 99, 124, 133,
+- 102, 68, 68, 99, 102, 157, 156, 114, 85, 85,
+- 85, 133, 133, 133, 140, 140, 140, 148, 124, 143,
+- 143, 143, 152, 143, 147, 147, 147, 155, 147, 154,
+- 151, 150, 149, 146, 145, 144, 142, 148, 141, 138,
+- 137, 132, 152, 166, 166, 166, 166, 166, 166, 166,
+- 166, 167, 131, 130, 129, 167, 167, 168, 168, 168,
+- 168, 168, 168, 168, 168, 169, 169, 169, 169, 170,
+- 128, 170, 171, 127, 126, 171, 125, 171, 171, 172,
+- 123, 122, 172, 172, 172, 172, 173, 121, 173, 173,
+-
+- 174, 174, 174, 174, 174, 174, 174, 174, 175, 175,
+- 175, 175, 175, 175, 175, 175, 176, 120, 176, 177,
+- 119, 177, 177, 118, 177, 177, 178, 178, 178, 178,
+- 178, 178, 178, 178, 179, 179, 179, 179, 179, 179,
+- 179, 179, 116, 115, 113, 112, 111, 110, 109, 108,
+- 107, 106, 105, 104, 103, 101, 100, 98, 97, 96,
+- 95, 94, 92, 90, 88, 87, 86, 84, 83, 82,
+- 81, 80, 79, 78, 77, 75, 73, 70, 69, 67,
+- 64, 62, 61, 57, 51, 50, 49, 47, 46, 45,
++ 5, 8, 12, 12, 12, 14, 15, 16, 8, 8,
++ 8, 17, 20, 20, 17, 23, 24, 29, 155, 24,
++ 29, 29, 29, 48, 16, 14, 31, 29, 128, 17,
++ 128, 17, 48, 17, 24, 17, 24, 99, 24, 42,
++ 24, 99, 15, 33, 33, 33, 23, 26, 26, 26,
++ 26, 154, 33, 33, 26, 36, 42, 31, 32, 32,
++ 32, 26, 26, 26, 26, 44, 59, 32, 32, 32,
++ 34, 34, 34, 73, 75, 36, 153, 75, 59, 59,
++ 59, 65, 44, 110, 65, 65, 65, 67, 67, 67,
++
++ 73, 65, 83, 89, 89, 97, 67, 67, 119, 127,
++ 97, 150, 149, 110, 83, 83, 83, 133, 133, 133,
++ 141, 127, 127, 127, 145, 136, 136, 136, 119, 136,
++ 140, 140, 140, 148, 140, 147, 144, 143, 142, 139,
++ 141, 138, 137, 135, 145, 159, 159, 159, 159, 159,
++ 159, 159, 159, 160, 134, 132, 131, 160, 160, 161,
++ 161, 161, 161, 161, 161, 161, 161, 162, 162, 162,
++ 162, 163, 126, 163, 164, 125, 124, 164, 123, 164,
++ 164, 165, 122, 121, 165, 165, 165, 165, 166, 120,
++ 166, 166, 167, 167, 167, 167, 167, 167, 167, 167,
++
++ 168, 168, 168, 168, 168, 168, 168, 168, 169, 118,
++ 169, 170, 117, 170, 170, 116, 170, 170, 171, 171,
++ 171, 171, 171, 171, 171, 171, 172, 172, 172, 172,
++ 172, 172, 172, 172, 115, 114, 112, 111, 109, 108,
++ 107, 106, 105, 104, 103, 102, 101, 100, 98, 96,
++ 95, 94, 93, 92, 90, 88, 86, 85, 84, 82,
++ 81, 80, 79, 78, 77, 76, 74, 72, 69, 68,
++ 66, 63, 61, 60, 56, 50, 49, 47, 46, 45,
+ 41, 38, 22, 21, 19, 13, 9, 6, 4, 2,
++ 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+
+- 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
+- 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
+- 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
+- 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
+- 165, 165, 165, 165, 165, 165, 165, 165
++ 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
++ 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
++ 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
++ 158, 158, 158, 158, 158, 158, 158
+ } ;
+
+ static yy_state_type yy_last_accepting_state;
+@@ -664,7 +662,7 @@ static int dts_version = 1;
+ static void push_input_file(const char *filename);
+ static bool pop_input_file(void);
+ static void lexical_error(const char *fmt, ...);
+-#line 668 "dtc-lexer.lex.c"
++#line 666 "dtc-lexer.lex.c"
+
+ #define INITIAL 0
+ #define BYTESTRING 1
+@@ -706,7 +704,7 @@ FILE *yyget_out (void );
+
+ void yyset_out (FILE * out_str );
+
+-int yyget_leng (void );
++yy_size_t yyget_leng (void );
+
+ char *yyget_text (void );
+
+@@ -855,10 +853,6 @@ YY_DECL
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+-#line 68 "dtc-lexer.l"
+-
+-#line 861 "dtc-lexer.lex.c"
+-
+ if ( !(yy_init) )
+ {
+ (yy_init) = 1;
+@@ -885,6 +879,11 @@ YY_DECL
+ yy_load_buffer_state( );
+ }
+
++ {
++#line 68 "dtc-lexer.l"
++
++#line 886 "dtc-lexer.lex.c"
++
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = (yy_c_buf_p);
+@@ -902,7 +901,7 @@ YY_DECL
+ yy_match:
+ do
+ {
+- register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
++ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+@@ -911,13 +910,13 @@ yy_match:
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+- if ( yy_current_state >= 166 )
++ if ( yy_current_state >= 159 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+- while ( yy_current_state != 165 );
++ while ( yy_current_state != 158 );
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+
+@@ -1008,31 +1007,23 @@ case 5:
+ YY_RULE_SETUP
+ #line 116 "dtc-lexer.l"
+ {
+- DPRINT("Keyword: /plugin/\n");
+- return DT_PLUGIN;
+- }
+- YY_BREAK
+-case 6:
+-YY_RULE_SETUP
+-#line 121 "dtc-lexer.l"
+-{
+ DPRINT("Keyword: /memreserve/\n");
+ BEGIN_DEFAULT();
+ return DT_MEMRESERVE;
+ }
+ YY_BREAK
+-case 7:
++case 6:
+ YY_RULE_SETUP
+-#line 127 "dtc-lexer.l"
++#line 122 "dtc-lexer.l"
+ {
+ DPRINT("Keyword: /bits/\n");
+ BEGIN_DEFAULT();
+ return DT_BITS;
+ }
+ YY_BREAK
+-case 8:
++case 7:
+ YY_RULE_SETUP
+-#line 133 "dtc-lexer.l"
++#line 128 "dtc-lexer.l"
+ {
+ DPRINT("Keyword: /delete-property/\n");
+ DPRINT("<PROPNODENAME>\n");
+@@ -1040,9 +1031,9 @@ YY_RULE_SETUP
+ return DT_DEL_PROP;
+ }
+ YY_BREAK
+-case 9:
++case 8:
+ YY_RULE_SETUP
+-#line 140 "dtc-lexer.l"
++#line 135 "dtc-lexer.l"
+ {
+ DPRINT("Keyword: /delete-node/\n");
+ DPRINT("<PROPNODENAME>\n");
+@@ -1050,9 +1041,9 @@ YY_RULE_SETUP
+ return DT_DEL_NODE;
+ }
+ YY_BREAK
+-case 10:
++case 9:
+ YY_RULE_SETUP
+-#line 147 "dtc-lexer.l"
++#line 142 "dtc-lexer.l"
+ {
+ DPRINT("Label: %s\n", yytext);
+ yylval.labelref = xstrdup(yytext);
+@@ -1060,9 +1051,9 @@ YY_RULE_SETUP
+ return DT_LABEL;
+ }
+ YY_BREAK
+-case 11:
++case 10:
+ YY_RULE_SETUP
+-#line 154 "dtc-lexer.l"
++#line 149 "dtc-lexer.l"
+ {
+ char *e;
+ DPRINT("Integer Literal: '%s'\n", yytext);
+@@ -1082,10 +1073,10 @@ YY_RULE_SETUP
+ return DT_LITERAL;
+ }
+ YY_BREAK
+-case 12:
+-/* rule 12 can match eol */
++case 11:
++/* rule 11 can match eol */
+ YY_RULE_SETUP
+-#line 173 "dtc-lexer.l"
++#line 168 "dtc-lexer.l"
+ {
+ struct data d;
+ DPRINT("Character literal: %s\n", yytext);
+@@ -1107,18 +1098,18 @@ YY_RULE_SETUP
+ return DT_CHAR_LITERAL;
+ }
+ YY_BREAK
+-case 13:
++case 12:
+ YY_RULE_SETUP
+-#line 194 "dtc-lexer.l"
++#line 189 "dtc-lexer.l"
+ { /* label reference */
+ DPRINT("Ref: %s\n", yytext+1);
+ yylval.labelref = xstrdup(yytext+1);
+ return DT_REF;
+ }
+ YY_BREAK
+-case 14:
++case 13:
+ YY_RULE_SETUP
+-#line 200 "dtc-lexer.l"
++#line 195 "dtc-lexer.l"
+ { /* new-style path reference */
+ yytext[yyleng-1] = '\0';
+ DPRINT("Ref: %s\n", yytext+2);
+@@ -1126,27 +1117,27 @@ YY_RULE_SETUP
+ return DT_REF;
+ }
+ YY_BREAK
+-case 15:
++case 14:
+ YY_RULE_SETUP
+-#line 207 "dtc-lexer.l"
++#line 202 "dtc-lexer.l"
+ {
+ yylval.byte = strtol(yytext, NULL, 16);
+ DPRINT("Byte: %02x\n", (int)yylval.byte);
+ return DT_BYTE;
+ }
+ YY_BREAK
+-case 16:
++case 15:
+ YY_RULE_SETUP
+-#line 213 "dtc-lexer.l"
++#line 208 "dtc-lexer.l"
+ {
+ DPRINT("/BYTESTRING\n");
+ BEGIN_DEFAULT();
+ return ']';
+ }
+ YY_BREAK
+-case 17:
++case 16:
+ YY_RULE_SETUP
+-#line 219 "dtc-lexer.l"
++#line 214 "dtc-lexer.l"
+ {
+ DPRINT("PropNodeName: %s\n", yytext);
+ yylval.propnodename = xstrdup((yytext[0] == '\\') ?
+@@ -1155,75 +1146,75 @@ YY_RULE_SETUP
+ return DT_PROPNODENAME;
+ }
+ YY_BREAK
+-case 18:
++case 17:
+ YY_RULE_SETUP
+-#line 227 "dtc-lexer.l"
++#line 222 "dtc-lexer.l"
+ {
+ DPRINT("Binary Include\n");
+ return DT_INCBIN;
+ }
+ YY_BREAK
+-case 19:
+-/* rule 19 can match eol */
++case 18:
++/* rule 18 can match eol */
+ YY_RULE_SETUP
+-#line 232 "dtc-lexer.l"
++#line 227 "dtc-lexer.l"
+ /* eat whitespace */
+ YY_BREAK
+-case 20:
+-/* rule 20 can match eol */
++case 19:
++/* rule 19 can match eol */
+ YY_RULE_SETUP
+-#line 233 "dtc-lexer.l"
++#line 228 "dtc-lexer.l"
+ /* eat C-style comments */
+ YY_BREAK
+-case 21:
+-/* rule 21 can match eol */
++case 20:
++/* rule 20 can match eol */
+ YY_RULE_SETUP
+-#line 234 "dtc-lexer.l"
++#line 229 "dtc-lexer.l"
+ /* eat C++-style comments */
+ YY_BREAK
+-case 22:
++case 21:
+ YY_RULE_SETUP
+-#line 236 "dtc-lexer.l"
++#line 231 "dtc-lexer.l"
+ { return DT_LSHIFT; };
+ YY_BREAK
+-case 23:
++case 22:
+ YY_RULE_SETUP
+-#line 237 "dtc-lexer.l"
++#line 232 "dtc-lexer.l"
+ { return DT_RSHIFT; };
+ YY_BREAK
+-case 24:
++case 23:
+ YY_RULE_SETUP
+-#line 238 "dtc-lexer.l"
++#line 233 "dtc-lexer.l"
+ { return DT_LE; };
+ YY_BREAK
+-case 25:
++case 24:
+ YY_RULE_SETUP
+-#line 239 "dtc-lexer.l"
++#line 234 "dtc-lexer.l"
+ { return DT_GE; };
+ YY_BREAK
+-case 26:
++case 25:
+ YY_RULE_SETUP
+-#line 240 "dtc-lexer.l"
++#line 235 "dtc-lexer.l"
+ { return DT_EQ; };
+ YY_BREAK
+-case 27:
++case 26:
+ YY_RULE_SETUP
+-#line 241 "dtc-lexer.l"
++#line 236 "dtc-lexer.l"
+ { return DT_NE; };
+ YY_BREAK
+-case 28:
++case 27:
+ YY_RULE_SETUP
+-#line 242 "dtc-lexer.l"
++#line 237 "dtc-lexer.l"
+ { return DT_AND; };
+ YY_BREAK
+-case 29:
++case 28:
+ YY_RULE_SETUP
+-#line 243 "dtc-lexer.l"
++#line 238 "dtc-lexer.l"
+ { return DT_OR; };
+ YY_BREAK
+-case 30:
++case 29:
+ YY_RULE_SETUP
+-#line 245 "dtc-lexer.l"
++#line 240 "dtc-lexer.l"
+ {
+ DPRINT("Char: %c (\\x%02x)\n", yytext[0],
+ (unsigned)yytext[0]);
+@@ -1239,12 +1230,12 @@ YY_RULE_SETUP
+ return yytext[0];
+ }
+ YY_BREAK
+-case 31:
++case 30:
+ YY_RULE_SETUP
+-#line 260 "dtc-lexer.l"
++#line 255 "dtc-lexer.l"
+ ECHO;
+ YY_BREAK
+-#line 1248 "dtc-lexer.lex.c"
++#line 1239 "dtc-lexer.lex.c"
+
+ case YY_END_OF_BUFFER:
+ {
+@@ -1374,6 +1365,7 @@ ECHO;
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
++ } /* end of user's declarations */
+ } /* end of yylex */
+
+ /* yy_get_next_buffer - try to read in a new buffer
+@@ -1429,21 +1421,21 @@ static int yy_get_next_buffer (void)
+
+ else
+ {
+- int num_to_read =
++ yy_size_t num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+- YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
++ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
+
+ int yy_c_buf_p_offset =
+ (int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+- int new_size = b->yy_buf_size * 2;
++ yy_size_t new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+@@ -1474,7 +1466,7 @@ static int yy_get_next_buffer (void)
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+- (yy_n_chars), (size_t) num_to_read );
++ (yy_n_chars), num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+@@ -1536,7 +1528,7 @@ static int yy_get_next_buffer (void)
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+- if ( yy_current_state >= 166 )
++ if ( yy_current_state >= 159 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+@@ -1564,13 +1556,13 @@ static int yy_get_next_buffer (void)
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+- if ( yy_current_state >= 166 )
++ if ( yy_current_state >= 159 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+- yy_is_jam = (yy_current_state == 165);
++ yy_is_jam = (yy_current_state == 158);
+
+- return yy_is_jam ? 0 : yy_current_state;
++ return yy_is_jam ? 0 : yy_current_state;
+ }
+
+ #ifndef YY_NO_INPUT
+@@ -1597,7 +1589,7 @@ static int yy_get_next_buffer (void)
+
+ else
+ { /* need more input */
+- int offset = (yy_c_buf_p) - (yytext_ptr);
++ yy_size_t offset = (yy_c_buf_p) - (yytext_ptr);
+ ++(yy_c_buf_p);
+
+ switch ( yy_get_next_buffer( ) )
+@@ -1871,7 +1863,7 @@ void yypop_buffer_state (void)
+ */
+ static void yyensure_buffer_stack (void)
+ {
+- int num_to_alloc;
++ yy_size_t num_to_alloc;
+
+ if (!(yy_buffer_stack)) {
+
+@@ -1968,12 +1960,12 @@ YY_BUFFER_STATE yy_scan_string (yyconst
+ *
+ * @return the newly allocated buffer state object.
+ */
+-YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len )
++YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len )
+ {
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+- int i;
++ yy_size_t i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+@@ -2055,7 +2047,7 @@ FILE *yyget_out (void)
+ /** Get the length of the current token.
+ *
+ */
+-int yyget_leng (void)
++yy_size_t yyget_leng (void)
+ {
+ return yyleng;
+ }
+@@ -2203,7 +2195,7 @@ void yyfree (void * ptr )
+
+ #define YYTABLES_NAME "yytables"
+
+-#line 260 "dtc-lexer.l"
++#line 254 "dtc-lexer.l"
+
+
+
+--- a/scripts/dtc/dtc-parser.tab.c_shipped
++++ b/scripts/dtc/dtc-parser.tab.c_shipped
+@@ -1,19 +1,19 @@
+-/* A Bison parser, made by GNU Bison 2.5. */
++/* A Bison parser, made by GNU Bison 3.0.2. */
+
+ /* Bison implementation for Yacc-like parsers in C
+-
+- Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
+-
++
++ Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
++
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. */
+
+@@ -26,7 +26,7 @@
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+-
++
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+@@ -44,7 +44,7 @@
+ #define YYBISON 1
+
+ /* Bison version. */
+-#define YYBISON_VERSION "2.5"
++#define YYBISON_VERSION "3.0.2"
+
+ /* Skeleton name. */
+ #define YYSKELETON_NAME "yacc.c"
+@@ -58,18 +58,13 @@
+ /* Pull parsers. */
+ #define YYPULL 1
+
+-/* Using locations. */
+-#define YYLSP_NEEDED 1
+
+
+
+ /* Copy the first part of user declarations. */
+-
+-/* Line 268 of yacc.c */
+-#line 20 "dtc-parser.y"
++#line 20 "dtc-parser.y" /* yacc.c:339 */
+
+ #include <stdio.h>
+-#include <inttypes.h>
+
+ #include "dtc.h"
+ #include "srcpos.h"
+@@ -85,14 +80,15 @@ extern void yyerror(char const *s);
+ extern struct boot_info *the_boot_info;
+ extern bool treesource_error;
+
++#line 84 "dtc-parser.tab.c" /* yacc.c:339 */
+
+-/* Line 268 of yacc.c */
+-#line 91 "dtc-parser.tab.c"
+-
+-/* Enabling traces. */
+-#ifndef YYDEBUG
+-# define YYDEBUG 0
+-#endif
++# ifndef YY_NULLPTR
++# if defined __cplusplus && 201103L <= __cplusplus
++# define YY_NULLPTR nullptr
++# else
++# define YY_NULLPTR 0
++# endif
++# endif
+
+ /* Enabling verbose error messages. */
+ #ifdef YYERROR_VERBOSE
+@@ -102,51 +98,53 @@ extern bool treesource_error;
+ # define YYERROR_VERBOSE 0
+ #endif
+
+-/* Enabling the token table. */
+-#ifndef YYTOKEN_TABLE
+-# define YYTOKEN_TABLE 0
++/* In a future release of Bison, this section will be replaced
++ by #include "dtc-parser.tab.h". */
++#ifndef YY_YY_DTC_PARSER_TAB_H_INCLUDED
++# define YY_YY_DTC_PARSER_TAB_H_INCLUDED
++/* Debug traces. */
++#ifndef YYDEBUG
++# define YYDEBUG 0
++#endif
++#if YYDEBUG
++extern int yydebug;
+ #endif
+
+-
+-/* Tokens. */
++/* Token type. */
+ #ifndef YYTOKENTYPE
+ # define YYTOKENTYPE
+- /* Put the tokens into the symbol table, so that GDB and other debuggers
+- know about them. */
+- enum yytokentype {
+- DT_V1 = 258,
+- DT_PLUGIN = 259,
+- DT_MEMRESERVE = 260,
+- DT_LSHIFT = 261,
+- DT_RSHIFT = 262,
+- DT_LE = 263,
+- DT_GE = 264,
+- DT_EQ = 265,
+- DT_NE = 266,
+- DT_AND = 267,
+- DT_OR = 268,
+- DT_BITS = 269,
+- DT_DEL_PROP = 270,
+- DT_DEL_NODE = 271,
+- DT_PROPNODENAME = 272,
+- DT_LITERAL = 273,
+- DT_CHAR_LITERAL = 274,
+- DT_BYTE = 275,
+- DT_STRING = 276,
+- DT_LABEL = 277,
+- DT_REF = 278,
+- DT_INCBIN = 279
+- };
++ enum yytokentype
++ {
++ DT_V1 = 258,
++ DT_MEMRESERVE = 259,
++ DT_LSHIFT = 260,
++ DT_RSHIFT = 261,
++ DT_LE = 262,
++ DT_GE = 263,
++ DT_EQ = 264,
++ DT_NE = 265,
++ DT_AND = 266,
++ DT_OR = 267,
++ DT_BITS = 268,
++ DT_DEL_PROP = 269,
++ DT_DEL_NODE = 270,
++ DT_PROPNODENAME = 271,
++ DT_LITERAL = 272,
++ DT_CHAR_LITERAL = 273,
++ DT_BYTE = 274,
++ DT_STRING = 275,
++ DT_LABEL = 276,
++ DT_REF = 277,
++ DT_INCBIN = 278
++ };
+ #endif
+
+-
+-
++/* Value type. */
+ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+-typedef union YYSTYPE
++typedef union YYSTYPE YYSTYPE;
++union YYSTYPE
+ {
+-
+-/* Line 293 of yacc.c */
+-#line 39 "dtc-parser.y"
++#line 38 "dtc-parser.y" /* yacc.c:355 */
+
+ char *propnodename;
+ char *labelref;
+@@ -164,37 +162,37 @@ typedef union YYSTYPE
+ struct node *nodelist;
+ struct reserve_info *re;
+ uint64_t integer;
+- int is_plugin;
+-
+-
+
+-/* Line 293 of yacc.c */
+-#line 173 "dtc-parser.tab.c"
+-} YYSTYPE;
++#line 167 "dtc-parser.tab.c" /* yacc.c:355 */
++};
+ # define YYSTYPE_IS_TRIVIAL 1
+-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+ # define YYSTYPE_IS_DECLARED 1
+ #endif
+
++/* Location type. */
+ #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
+-typedef struct YYLTYPE
++typedef struct YYLTYPE YYLTYPE;
++struct YYLTYPE
+ {
+ int first_line;
+ int first_column;
+ int last_line;
+ int last_column;
+-} YYLTYPE;
+-# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
++};
+ # define YYLTYPE_IS_DECLARED 1
+ # define YYLTYPE_IS_TRIVIAL 1
+ #endif
+
+
+-/* Copy the second part of user declarations. */
++extern YYSTYPE yylval;
++extern YYLTYPE yylloc;
++int yyparse (void);
++
++#endif /* !YY_YY_DTC_PARSER_TAB_H_INCLUDED */
+
++/* Copy the second part of user declarations. */
+
+-/* Line 343 of yacc.c */
+-#line 198 "dtc-parser.tab.c"
++#line 196 "dtc-parser.tab.c" /* yacc.c:358 */
+
+ #ifdef short
+ # undef short
+@@ -208,11 +206,8 @@ typedef unsigned char yytype_uint8;
+
+ #ifdef YYTYPE_INT8
+ typedef YYTYPE_INT8 yytype_int8;
+-#elif (defined __STDC__ || defined __C99__FUNC__ \
+- || defined __cplusplus || defined _MSC_VER)
+-typedef signed char yytype_int8;
+ #else
+-typedef short int yytype_int8;
++typedef signed char yytype_int8;
+ #endif
+
+ #ifdef YYTYPE_UINT16
+@@ -232,8 +227,7 @@ typedef short int yytype_int16;
+ # define YYSIZE_T __SIZE_TYPE__
+ # elif defined size_t
+ # define YYSIZE_T size_t
+-# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+- || defined __cplusplus || defined _MSC_VER)
++# elif ! defined YYSIZE_T
+ # include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+ # define YYSIZE_T size_t
+ # else
+@@ -247,39 +241,68 @@ typedef short int yytype_int16;
+ # if defined YYENABLE_NLS && YYENABLE_NLS
+ # if ENABLE_NLS
+ # include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+-# define YY_(msgid) dgettext ("bison-runtime", msgid)
++# define YY_(Msgid) dgettext ("bison-runtime", Msgid)
+ # endif
+ # endif
+ # ifndef YY_
+-# define YY_(msgid) msgid
++# define YY_(Msgid) Msgid
++# endif
++#endif
++
++#ifndef YY_ATTRIBUTE
++# if (defined __GNUC__ \
++ && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \
++ || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C
++# define YY_ATTRIBUTE(Spec) __attribute__(Spec)
++# else
++# define YY_ATTRIBUTE(Spec) /* empty */
++# endif
++#endif
++
++#ifndef YY_ATTRIBUTE_PURE
++# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__))
++#endif
++
++#ifndef YY_ATTRIBUTE_UNUSED
++# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__))
++#endif
++
++#if !defined _Noreturn \
++ && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112)
++# if defined _MSC_VER && 1200 <= _MSC_VER
++# define _Noreturn __declspec (noreturn)
++# else
++# define _Noreturn YY_ATTRIBUTE ((__noreturn__))
+ # endif
+ #endif
+
+ /* Suppress unused-variable warnings by "using" E. */
+ #if ! defined lint || defined __GNUC__
+-# define YYUSE(e) ((void) (e))
++# define YYUSE(E) ((void) (E))
+ #else
+-# define YYUSE(e) /* empty */
++# define YYUSE(E) /* empty */
+ #endif
+
+-/* Identity function, used to suppress warnings about constant conditions. */
+-#ifndef lint
+-# define YYID(n) (n)
+-#else
+-#if (defined __STDC__ || defined __C99__FUNC__ \
+- || defined __cplusplus || defined _MSC_VER)
+-static int
+-YYID (int yyi)
++#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
++/* Suppress an incorrect diagnostic about yylval being uninitialized. */
++# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
++ _Pragma ("GCC diagnostic push") \
++ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\
++ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
++# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
++ _Pragma ("GCC diagnostic pop")
+ #else
+-static int
+-YYID (yyi)
+- int yyi;
++# define YY_INITIAL_VALUE(Value) Value
+ #endif
+-{
+- return yyi;
+-}
++#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
++# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
++# define YY_IGNORE_MAYBE_UNINITIALIZED_END
++#endif
++#ifndef YY_INITIAL_VALUE
++# define YY_INITIAL_VALUE(Value) /* Nothing. */
+ #endif
+
++
+ #if ! defined yyoverflow || YYERROR_VERBOSE
+
+ /* The parser invokes alloca or malloc; define the necessary symbols. */
+@@ -297,9 +320,9 @@ YYID (yyi)
+ # define alloca _alloca
+ # else
+ # define YYSTACK_ALLOC alloca
+-# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+- || defined __cplusplus || defined _MSC_VER)
++# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS
+ # include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
++ /* Use EXIT_SUCCESS as a witness for stdlib.h. */
+ # ifndef EXIT_SUCCESS
+ # define EXIT_SUCCESS 0
+ # endif
+@@ -309,8 +332,8 @@ YYID (yyi)
+ # endif
+
+ # ifdef YYSTACK_ALLOC
+- /* Pacify GCC's `empty if-body' warning. */
+-# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
++ /* Pacify GCC's 'empty if-body' warning. */
++# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+ # ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+@@ -326,7 +349,7 @@ YYID (yyi)
+ # endif
+ # if (defined __cplusplus && ! defined EXIT_SUCCESS \
+ && ! ((defined YYMALLOC || defined malloc) \
+- && (defined YYFREE || defined free)))
++ && (defined YYFREE || defined free)))
+ # include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+ # ifndef EXIT_SUCCESS
+ # define EXIT_SUCCESS 0
+@@ -334,15 +357,13 @@ YYID (yyi)
+ # endif
+ # ifndef YYMALLOC
+ # define YYMALLOC malloc
+-# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+- || defined __cplusplus || defined _MSC_VER)
++# if ! defined malloc && ! defined EXIT_SUCCESS
+ void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+ # endif
+ # endif
+ # ifndef YYFREE
+ # define YYFREE free
+-# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+- || defined __cplusplus || defined _MSC_VER)
++# if ! defined free && ! defined EXIT_SUCCESS
+ void free (void *); /* INFRINGES ON USER NAME SPACE */
+ # endif
+ # endif
+@@ -352,8 +373,8 @@ void free (void *); /* INFRINGES ON USER
+
+ #if (! defined yyoverflow \
+ && (! defined __cplusplus \
+- || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
+- && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
++ || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
++ && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+ /* A type that is properly aligned for any stack member. */
+ union yyalloc
+@@ -379,35 +400,35 @@ union yyalloc
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+-# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+- do \
+- { \
+- YYSIZE_T yynewbytes; \
+- YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+- Stack = &yyptr->Stack_alloc; \
+- yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+- yyptr += yynewbytes / sizeof (*yyptr); \
+- } \
+- while (YYID (0))
++# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
++ do \
++ { \
++ YYSIZE_T yynewbytes; \
++ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
++ Stack = &yyptr->Stack_alloc; \
++ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
++ yyptr += yynewbytes / sizeof (*yyptr); \
++ } \
++ while (0)
+
+ #endif
+
+ #if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+-/* Copy COUNT objects from FROM to TO. The source and destination do
++/* Copy COUNT objects from SRC to DST. The source and destination do
+ not overlap. */
+ # ifndef YYCOPY
+ # if defined __GNUC__ && 1 < __GNUC__
+-# define YYCOPY(To, From, Count) \
+- __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
++# define YYCOPY(Dst, Src, Count) \
++ __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
+ # else
+-# define YYCOPY(To, From, Count) \
+- do \
+- { \
+- YYSIZE_T yyi; \
+- for (yyi = 0; yyi < (Count); yyi++) \
+- (To)[yyi] = (From)[yyi]; \
+- } \
+- while (YYID (0))
++# define YYCOPY(Dst, Src, Count) \
++ do \
++ { \
++ YYSIZE_T yyi; \
++ for (yyi = 0; yyi < (Count); yyi++) \
++ (Dst)[yyi] = (Src)[yyi]; \
++ } \
++ while (0)
+ # endif
+ # endif
+ #endif /* !YYCOPY_NEEDED */
+@@ -418,37 +439,39 @@ union yyalloc
+ #define YYLAST 136
+
+ /* YYNTOKENS -- Number of terminals. */
+-#define YYNTOKENS 48
++#define YYNTOKENS 47
+ /* YYNNTS -- Number of nonterminals. */
+-#define YYNNTS 29
++#define YYNNTS 28
+ /* YYNRULES -- Number of rules. */
+-#define YYNRULES 82
+-/* YYNRULES -- Number of states. */
+-#define YYNSTATES 147
++#define YYNRULES 80
++/* YYNSTATES -- Number of states. */
++#define YYNSTATES 144
+
+-/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
++/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
++ by yylex, with out-of-bounds checking. */
+ #define YYUNDEFTOK 2
+-#define YYMAXUTOK 279
++#define YYMAXUTOK 278
+
+-#define YYTRANSLATE(YYX) \
++#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+-/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
++/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
++ as returned by yylex, without out-of-bounds checking. */
+ static const yytype_uint8 yytranslate[] =
+ {
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+- 2, 2, 2, 47, 2, 2, 2, 45, 41, 2,
+- 33, 35, 44, 42, 34, 43, 2, 26, 2, 2,
+- 2, 2, 2, 2, 2, 2, 2, 2, 38, 25,
+- 36, 29, 30, 37, 2, 2, 2, 2, 2, 2,
++ 2, 2, 2, 46, 2, 2, 2, 44, 40, 2,
++ 32, 34, 43, 41, 33, 42, 2, 25, 2, 2,
++ 2, 2, 2, 2, 2, 2, 2, 2, 37, 24,
++ 35, 28, 29, 36, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+- 2, 31, 2, 32, 40, 2, 2, 2, 2, 2,
++ 2, 30, 2, 31, 39, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+- 2, 2, 2, 27, 39, 28, 46, 2, 2, 2,
++ 2, 2, 2, 26, 38, 27, 45, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+@@ -463,335 +486,292 @@ static const yytype_uint8 yytranslate[]
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24
++ 15, 16, 17, 18, 19, 20, 21, 22, 23
+ };
+
+ #if YYDEBUG
+-/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+- YYRHS. */
+-static const yytype_uint16 yyprhs[] =
+-{
+- 0, 0, 3, 9, 10, 13, 14, 17, 22, 25,
+- 28, 32, 37, 41, 46, 52, 53, 56, 61, 64,
+- 68, 71, 74, 78, 83, 86, 96, 102, 105, 106,
+- 109, 112, 116, 118, 121, 124, 127, 129, 131, 135,
+- 137, 139, 145, 147, 151, 153, 157, 159, 163, 165,
+- 169, 171, 175, 177, 181, 185, 187, 191, 195, 199,
+- 203, 207, 211, 213, 217, 221, 223, 227, 231, 235,
+- 237, 239, 242, 245, 248, 249, 252, 255, 256, 259,
+- 262, 265, 269
+-};
+-
+-/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+-static const yytype_int8 yyrhs[] =
+-{
+- 49, 0, -1, 3, 25, 50, 51, 53, -1, -1,
+- 4, 25, -1, -1, 52, 51, -1, 5, 60, 60,
+- 25, -1, 22, 52, -1, 26, 54, -1, 53, 26,
+- 54, -1, 53, 22, 23, 54, -1, 53, 23, 54,
+- -1, 53, 16, 23, 25, -1, 27, 55, 75, 28,
+- 25, -1, -1, 55, 56, -1, 17, 29, 57, 25,
+- -1, 17, 25, -1, 15, 17, 25, -1, 22, 56,
+- -1, 58, 21, -1, 58, 59, 30, -1, 58, 31,
+- 74, 32, -1, 58, 23, -1, 58, 24, 33, 21,
+- 34, 60, 34, 60, 35, -1, 58, 24, 33, 21,
+- 35, -1, 57, 22, -1, -1, 57, 34, -1, 58,
+- 22, -1, 14, 18, 36, -1, 36, -1, 59, 60,
+- -1, 59, 23, -1, 59, 22, -1, 18, -1, 19,
+- -1, 33, 61, 35, -1, 62, -1, 63, -1, 63,
+- 37, 61, 38, 62, -1, 64, -1, 63, 13, 64,
+- -1, 65, -1, 64, 12, 65, -1, 66, -1, 65,
+- 39, 66, -1, 67, -1, 66, 40, 67, -1, 68,
+- -1, 67, 41, 68, -1, 69, -1, 68, 10, 69,
+- -1, 68, 11, 69, -1, 70, -1, 69, 36, 70,
+- -1, 69, 30, 70, -1, 69, 8, 70, -1, 69,
+- 9, 70, -1, 70, 6, 71, -1, 70, 7, 71,
+- -1, 71, -1, 71, 42, 72, -1, 71, 43, 72,
+- -1, 72, -1, 72, 44, 73, -1, 72, 26, 73,
+- -1, 72, 45, 73, -1, 73, -1, 60, -1, 43,
+- 73, -1, 46, 73, -1, 47, 73, -1, -1, 74,
+- 20, -1, 74, 22, -1, -1, 76, 75, -1, 76,
+- 56, -1, 17, 54, -1, 16, 17, 25, -1, 22,
+- 76, -1
+-};
+-
+-/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
++ /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
+ static const yytype_uint16 yyrline[] =
+ {
+- 0, 108, 108, 119, 122, 130, 133, 140, 144, 152,
+- 156, 161, 172, 182, 197, 205, 208, 215, 219, 223,
+- 227, 235, 239, 243, 247, 251, 267, 277, 285, 288,
+- 292, 299, 315, 320, 339, 353, 360, 361, 362, 369,
+- 373, 374, 378, 379, 383, 384, 388, 389, 393, 394,
+- 398, 399, 403, 404, 405, 409, 410, 411, 412, 413,
+- 417, 418, 419, 423, 424, 425, 429, 430, 431, 432,
+- 436, 437, 438, 439, 444, 447, 451, 459, 462, 466,
+- 474, 478, 482
++ 0, 104, 104, 113, 116, 123, 127, 135, 139, 144,
++ 155, 165, 180, 188, 191, 198, 202, 206, 210, 218,
++ 222, 226, 230, 234, 250, 260, 268, 271, 275, 282,
++ 298, 303, 322, 336, 343, 344, 345, 352, 356, 357,
++ 361, 362, 366, 367, 371, 372, 376, 377, 381, 382,
++ 386, 387, 388, 392, 393, 394, 395, 396, 400, 401,
++ 402, 406, 407, 408, 412, 413, 414, 415, 419, 420,
++ 421, 422, 427, 430, 434, 442, 445, 449, 457, 461,
++ 465
+ };
+ #endif
+
+-#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
++#if YYDEBUG || YYERROR_VERBOSE || 0
+ /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+ static const char *const yytname[] =
+ {
+- "$end", "error", "$undefined", "DT_V1", "DT_PLUGIN", "DT_MEMRESERVE",
+- "DT_LSHIFT", "DT_RSHIFT", "DT_LE", "DT_GE", "DT_EQ", "DT_NE", "DT_AND",
+- "DT_OR", "DT_BITS", "DT_DEL_PROP", "DT_DEL_NODE", "DT_PROPNODENAME",
+- "DT_LITERAL", "DT_CHAR_LITERAL", "DT_BYTE", "DT_STRING", "DT_LABEL",
+- "DT_REF", "DT_INCBIN", "';'", "'/'", "'{'", "'}'", "'='", "'>'", "'['",
+- "']'", "'('", "','", "')'", "'<'", "'?'", "':'", "'|'", "'^'", "'&'",
+- "'+'", "'-'", "'*'", "'%'", "'~'", "'!'", "$accept", "sourcefile",
+- "plugindecl", "memreserves", "memreserve", "devicetree", "nodedef",
+- "proplist", "propdef", "propdata", "propdataprefix", "arrayprefix",
+- "integer_prim", "integer_expr", "integer_trinary", "integer_or",
+- "integer_and", "integer_bitor", "integer_bitxor", "integer_bitand",
+- "integer_eq", "integer_rela", "integer_shift", "integer_add",
+- "integer_mul", "integer_unary", "bytestring", "subnodes", "subnode", 0
++ "$end", "error", "$undefined", "DT_V1", "DT_MEMRESERVE", "DT_LSHIFT",
++ "DT_RSHIFT", "DT_LE", "DT_GE", "DT_EQ", "DT_NE", "DT_AND", "DT_OR",
++ "DT_BITS", "DT_DEL_PROP", "DT_DEL_NODE", "DT_PROPNODENAME", "DT_LITERAL",
++ "DT_CHAR_LITERAL", "DT_BYTE", "DT_STRING", "DT_LABEL", "DT_REF",
++ "DT_INCBIN", "';'", "'/'", "'{'", "'}'", "'='", "'>'", "'['", "']'",
++ "'('", "','", "')'", "'<'", "'?'", "':'", "'|'", "'^'", "'&'", "'+'",
++ "'-'", "'*'", "'%'", "'~'", "'!'", "$accept", "sourcefile",
++ "memreserves", "memreserve", "devicetree", "nodedef", "proplist",
++ "propdef", "propdata", "propdataprefix", "arrayprefix", "integer_prim",
++ "integer_expr", "integer_trinary", "integer_or", "integer_and",
++ "integer_bitor", "integer_bitxor", "integer_bitand", "integer_eq",
++ "integer_rela", "integer_shift", "integer_add", "integer_mul",
++ "integer_unary", "bytestring", "subnodes", "subnode", YY_NULLPTR
+ };
+ #endif
+
+ # ifdef YYPRINT
+-/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+- token YYLEX-NUM. */
++/* YYTOKNUM[NUM] -- (External) token number corresponding to the
++ (internal) symbol number NUM (which must be that of a token). */
+ static const yytype_uint16 yytoknum[] =
+ {
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+- 275, 276, 277, 278, 279, 59, 47, 123, 125, 61,
+- 62, 91, 93, 40, 44, 41, 60, 63, 58, 124,
+- 94, 38, 43, 45, 42, 37, 126, 33
++ 275, 276, 277, 278, 59, 47, 123, 125, 61, 62,
++ 91, 93, 40, 44, 41, 60, 63, 58, 124, 94,
++ 38, 43, 45, 42, 37, 126, 33
+ };
+ # endif
+
+-/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+-static const yytype_uint8 yyr1[] =
+-{
+- 0, 48, 49, 50, 50, 51, 51, 52, 52, 53,
+- 53, 53, 53, 53, 54, 55, 55, 56, 56, 56,
+- 56, 57, 57, 57, 57, 57, 57, 57, 58, 58,
+- 58, 59, 59, 59, 59, 59, 60, 60, 60, 61,
+- 62, 62, 63, 63, 64, 64, 65, 65, 66, 66,
+- 67, 67, 68, 68, 68, 69, 69, 69, 69, 69,
+- 70, 70, 70, 71, 71, 71, 72, 72, 72, 72,
+- 73, 73, 73, 73, 74, 74, 74, 75, 75, 75,
+- 76, 76, 76
+-};
++#define YYPACT_NINF -81
+
+-/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+-static const yytype_uint8 yyr2[] =
++#define yypact_value_is_default(Yystate) \
++ (!!((Yystate) == (-81)))
++
++#define YYTABLE_NINF -1
++
++#define yytable_value_is_error(Yytable_value) \
++ 0
++
++ /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
++ STATE-NUM. */
++static const yytype_int8 yypact[] =
+ {
+- 0, 2, 5, 0, 2, 0, 2, 4, 2, 2,
+- 3, 4, 3, 4, 5, 0, 2, 4, 2, 3,
+- 2, 2, 3, 4, 2, 9, 5, 2, 0, 2,
+- 2, 3, 1, 2, 2, 2, 1, 1, 3, 1,
+- 1, 5, 1, 3, 1, 3, 1, 3, 1, 3,
+- 1, 3, 1, 3, 3, 1, 3, 3, 3, 3,
+- 3, 3, 1, 3, 3, 1, 3, 3, 3, 1,
+- 1, 2, 2, 2, 0, 2, 2, 0, 2, 2,
+- 2, 3, 2
++ 16, -11, 21, 10, -81, 25, 10, 19, 10, -81,
++ -81, -9, 25, -81, 2, 51, -81, -9, -9, -9,
++ -81, 1, -81, -6, 50, 14, 28, 29, 36, 3,
++ 58, 44, -3, -81, 47, -81, -81, 65, 68, 2,
++ 2, -81, -81, -81, -81, -9, -9, -9, -9, -9,
++ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
++ -9, -9, -9, -9, -81, 63, 69, 2, -81, -81,
++ 50, 57, 14, 28, 29, 36, 3, 3, 58, 58,
++ 58, 58, 44, 44, -3, -3, -81, -81, -81, 79,
++ 80, -8, 63, -81, 72, 63, -81, -81, -9, 76,
++ 77, -81, -81, -81, -81, -81, 78, -81, -81, -81,
++ -81, -81, 35, 4, -81, -81, -81, -81, 86, -81,
++ -81, -81, 73, -81, -81, 33, 71, 84, 39, -81,
++ -81, -81, -81, -81, 41, -81, -81, -81, 25, -81,
++ 74, 25, 75, -81
+ };
+
+-/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
+- Performed when YYTABLE doesn't specify something else to do. Zero
+- means the default is an error. */
++ /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
++ Performed when YYTABLE does not specify something else to do. Zero
++ means the default is an error. */
+ static const yytype_uint8 yydefact[] =
+ {
+- 0, 0, 0, 3, 1, 0, 5, 4, 0, 0,
+- 0, 5, 36, 37, 0, 0, 8, 0, 2, 6,
+- 0, 0, 0, 70, 0, 39, 40, 42, 44, 46,
+- 48, 50, 52, 55, 62, 65, 69, 0, 15, 9,
+- 0, 0, 0, 0, 71, 72, 73, 38, 0, 0,
++ 0, 0, 0, 3, 1, 0, 0, 0, 3, 34,
++ 35, 0, 0, 6, 0, 2, 4, 0, 0, 0,
++ 68, 0, 37, 38, 40, 42, 44, 46, 48, 50,
++ 53, 60, 63, 67, 0, 13, 7, 0, 0, 0,
++ 0, 69, 70, 71, 36, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+- 0, 0, 0, 0, 0, 0, 0, 7, 77, 0,
+- 0, 12, 10, 43, 0, 45, 47, 49, 51, 53,
+- 54, 58, 59, 57, 56, 60, 61, 63, 64, 67,
+- 66, 68, 0, 0, 0, 0, 16, 0, 77, 13,
+- 11, 0, 0, 0, 18, 28, 80, 20, 82, 0,
+- 79, 78, 41, 19, 81, 0, 0, 14, 27, 17,
+- 29, 0, 21, 30, 24, 0, 74, 32, 0, 0,
+- 0, 0, 35, 34, 22, 33, 31, 0, 75, 76,
+- 23, 0, 26, 0, 0, 0, 25
++ 0, 0, 0, 0, 5, 75, 0, 0, 10, 8,
++ 41, 0, 43, 45, 47, 49, 51, 52, 56, 57,
++ 55, 54, 58, 59, 61, 62, 65, 64, 66, 0,
++ 0, 0, 0, 14, 0, 75, 11, 9, 0, 0,
++ 0, 16, 26, 78, 18, 80, 0, 77, 76, 39,
++ 17, 79, 0, 0, 12, 25, 15, 27, 0, 19,
++ 28, 22, 0, 72, 30, 0, 0, 0, 0, 33,
++ 32, 20, 31, 29, 0, 73, 74, 21, 0, 24,
++ 0, 0, 0, 23
+ };
+
+-/* YYDEFGOTO[NTERM-NUM]. */
+-static const yytype_int16 yydefgoto[] =
++ /* YYPGOTO[NTERM-NUM]. */
++static const yytype_int8 yypgoto[] =
+ {
+- -1, 2, 6, 10, 11, 18, 39, 68, 96, 115,
+- 116, 128, 23, 24, 25, 26, 27, 28, 29, 30,
+- 31, 32, 33, 34, 35, 36, 131, 97, 98
++ -81, -81, 100, 104, -81, -38, -81, -80, -81, -81,
++ -81, -5, 66, 13, -81, 70, 67, 81, 64, 82,
++ 37, 27, 34, 38, -14, -81, 22, 24
+ };
+
+-/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+- STATE-NUM. */
+-#define YYPACT_NINF -84
+-static const yytype_int8 yypact[] =
++ /* YYDEFGOTO[NTERM-NUM]. */
++static const yytype_int16 yydefgoto[] =
+ {
+- 15, -12, 35, 42, -84, 27, 9, -84, 24, 9,
+- 43, 9, -84, -84, -10, 24, -84, 60, 44, -84,
+- -10, -10, -10, -84, 55, -84, -7, 52, 53, 51,
+- 54, 10, 2, 38, 37, -4, -84, 68, -84, -84,
+- 71, 73, 60, 60, -84, -84, -84, -84, -10, -10,
+- -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
+- -10, -10, -10, -10, -10, -10, -10, -84, 56, 72,
+- 60, -84, -84, 52, 61, 53, 51, 54, 10, 2,
+- 2, 38, 38, 38, 38, 37, 37, -4, -4, -84,
+- -84, -84, 81, 83, 34, 56, -84, 74, 56, -84,
+- -84, -10, 76, 78, -84, -84, -84, -84, -84, 79,
+- -84, -84, -84, -84, -84, -6, 3, -84, -84, -84,
+- -84, 87, -84, -84, -84, 75, -84, -84, 32, 70,
+- 86, 36, -84, -84, -84, -84, -84, 47, -84, -84,
+- -84, 24, -84, 77, 24, 80, -84
++ -1, 2, 7, 8, 15, 36, 65, 93, 112, 113,
++ 125, 20, 21, 22, 23, 24, 25, 26, 27, 28,
++ 29, 30, 31, 32, 33, 128, 94, 95
+ };
+
+-/* YYPGOTO[NTERM-NUM]. */
+-static const yytype_int8 yypgoto[] =
++ /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
++ positive, shift that token. If negative, reduce the rule whose
++ number is the opposite. If YYTABLE_NINF, syntax error. */
++static const yytype_uint8 yytable[] =
+ {
+- -84, -84, -84, 98, 101, -84, -41, -84, -83, -84,
+- -84, -84, -8, 63, 12, -84, 66, 67, 65, 69,
+- 82, 29, 18, 25, 26, -17, -84, 20, 28
++ 12, 68, 69, 41, 42, 43, 45, 34, 9, 10,
++ 53, 54, 104, 3, 5, 107, 101, 118, 35, 1,
++ 102, 4, 61, 11, 119, 120, 121, 122, 35, 97,
++ 46, 6, 55, 17, 123, 44, 18, 19, 56, 124,
++ 62, 63, 9, 10, 14, 51, 52, 86, 87, 88,
++ 9, 10, 48, 103, 129, 130, 115, 11, 135, 116,
++ 136, 47, 131, 57, 58, 11, 37, 49, 117, 50,
++ 137, 64, 38, 39, 138, 139, 40, 89, 90, 91,
++ 78, 79, 80, 81, 92, 59, 60, 66, 76, 77,
++ 67, 82, 83, 96, 98, 99, 100, 84, 85, 106,
++ 110, 111, 114, 126, 134, 127, 133, 141, 16, 143,
++ 13, 109, 71, 74, 72, 70, 105, 108, 0, 0,
++ 132, 0, 0, 0, 0, 0, 0, 0, 0, 73,
++ 0, 0, 75, 140, 0, 0, 142
+ };
+
+-/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+- positive, shift that token. If negative, reduce the rule which
+- number is the opposite. If YYTABLE_NINF, syntax error. */
+-#define YYTABLE_NINF -1
+-static const yytype_uint8 yytable[] =
++static const yytype_int16 yycheck[] =
+ {
+- 15, 71, 72, 44, 45, 46, 48, 37, 12, 13,
+- 56, 57, 107, 3, 8, 110, 118, 121, 1, 119,
+- 54, 55, 64, 14, 122, 123, 124, 125, 120, 100,
+- 49, 9, 58, 20, 126, 4, 21, 22, 59, 127,
+- 65, 66, 12, 13, 60, 61, 5, 89, 90, 91,
+- 12, 13, 7, 106, 132, 133, 138, 14, 139, 104,
+- 40, 38, 134, 105, 50, 14, 41, 42, 140, 17,
+- 43, 92, 93, 94, 81, 82, 83, 84, 95, 62,
+- 63, 141, 142, 79, 80, 85, 86, 38, 87, 88,
+- 47, 52, 51, 67, 69, 53, 70, 99, 102, 101,
+- 103, 113, 109, 114, 117, 129, 136, 137, 130, 19,
+- 16, 144, 74, 112, 73, 146, 76, 75, 111, 0,
+- 135, 77, 0, 108, 0, 0, 0, 0, 0, 0,
+- 0, 0, 0, 143, 0, 78, 145
++ 5, 39, 40, 17, 18, 19, 12, 12, 17, 18,
++ 7, 8, 92, 24, 4, 95, 24, 13, 26, 3,
++ 28, 0, 25, 32, 20, 21, 22, 23, 26, 67,
++ 36, 21, 29, 42, 30, 34, 45, 46, 35, 35,
++ 43, 44, 17, 18, 25, 9, 10, 61, 62, 63,
++ 17, 18, 38, 91, 21, 22, 21, 32, 19, 24,
++ 21, 11, 29, 5, 6, 32, 15, 39, 33, 40,
++ 31, 24, 21, 22, 33, 34, 25, 14, 15, 16,
++ 53, 54, 55, 56, 21, 41, 42, 22, 51, 52,
++ 22, 57, 58, 24, 37, 16, 16, 59, 60, 27,
++ 24, 24, 24, 17, 20, 32, 35, 33, 8, 34,
++ 6, 98, 46, 49, 47, 45, 92, 95, -1, -1,
++ 125, -1, -1, -1, -1, -1, -1, -1, -1, 48,
++ -1, -1, 50, 138, -1, -1, 141
+ };
+
+-#define yypact_value_is_default(yystate) \
+- ((yystate) == (-84))
+-
+-#define yytable_value_is_error(yytable_value) \
+- YYID (0)
++ /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
++ symbol of state STATE-NUM. */
++static const yytype_uint8 yystos[] =
++{
++ 0, 3, 48, 24, 0, 4, 21, 49, 50, 17,
++ 18, 32, 58, 50, 25, 51, 49, 42, 45, 46,
++ 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
++ 68, 69, 70, 71, 58, 26, 52, 15, 21, 22,
++ 25, 71, 71, 71, 34, 12, 36, 11, 38, 39,
++ 40, 9, 10, 7, 8, 29, 35, 5, 6, 41,
++ 42, 25, 43, 44, 24, 53, 22, 22, 52, 52,
++ 62, 59, 63, 64, 65, 66, 67, 67, 68, 68,
++ 68, 68, 69, 69, 70, 70, 71, 71, 71, 14,
++ 15, 16, 21, 54, 73, 74, 24, 52, 37, 16,
++ 16, 24, 28, 52, 54, 74, 27, 54, 73, 60,
++ 24, 24, 55, 56, 24, 21, 24, 33, 13, 20,
++ 21, 22, 23, 30, 35, 57, 17, 32, 72, 21,
++ 22, 29, 58, 35, 20, 19, 21, 31, 33, 34,
++ 58, 33, 58, 34
++};
+
+-static const yytype_int16 yycheck[] =
++ /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
++static const yytype_uint8 yyr1[] =
+ {
+- 8, 42, 43, 20, 21, 22, 13, 15, 18, 19,
+- 8, 9, 95, 25, 5, 98, 22, 14, 3, 25,
+- 10, 11, 26, 33, 21, 22, 23, 24, 34, 70,
+- 37, 22, 30, 43, 31, 0, 46, 47, 36, 36,
+- 44, 45, 18, 19, 6, 7, 4, 64, 65, 66,
+- 18, 19, 25, 94, 22, 23, 20, 33, 22, 25,
+- 16, 27, 30, 29, 12, 33, 22, 23, 32, 26,
+- 26, 15, 16, 17, 56, 57, 58, 59, 22, 42,
+- 43, 34, 35, 54, 55, 60, 61, 27, 62, 63,
+- 35, 40, 39, 25, 23, 41, 23, 25, 17, 38,
+- 17, 25, 28, 25, 25, 18, 36, 21, 33, 11,
+- 9, 34, 49, 101, 48, 35, 51, 50, 98, -1,
+- 128, 52, -1, 95, -1, -1, -1, -1, -1, -1,
+- -1, -1, -1, 141, -1, 53, 144
++ 0, 47, 48, 49, 49, 50, 50, 51, 51, 51,
++ 51, 51, 52, 53, 53, 54, 54, 54, 54, 55,
++ 55, 55, 55, 55, 55, 55, 56, 56, 56, 57,
++ 57, 57, 57, 57, 58, 58, 58, 59, 60, 60,
++ 61, 61, 62, 62, 63, 63, 64, 64, 65, 65,
++ 66, 66, 66, 67, 67, 67, 67, 67, 68, 68,
++ 68, 69, 69, 69, 70, 70, 70, 70, 71, 71,
++ 71, 71, 72, 72, 72, 73, 73, 73, 74, 74,
++ 74
+ };
+
+-/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+- symbol of state STATE-NUM. */
+-static const yytype_uint8 yystos[] =
++ /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */
++static const yytype_uint8 yyr2[] =
+ {
+- 0, 3, 49, 25, 0, 4, 50, 25, 5, 22,
+- 51, 52, 18, 19, 33, 60, 52, 26, 53, 51,
+- 43, 46, 47, 60, 61, 62, 63, 64, 65, 66,
+- 67, 68, 69, 70, 71, 72, 73, 60, 27, 54,
+- 16, 22, 23, 26, 73, 73, 73, 35, 13, 37,
+- 12, 39, 40, 41, 10, 11, 8, 9, 30, 36,
+- 6, 7, 42, 43, 26, 44, 45, 25, 55, 23,
+- 23, 54, 54, 64, 61, 65, 66, 67, 68, 69,
+- 69, 70, 70, 70, 70, 71, 71, 72, 72, 73,
+- 73, 73, 15, 16, 17, 22, 56, 75, 76, 25,
+- 54, 38, 17, 17, 25, 29, 54, 56, 76, 28,
+- 56, 75, 62, 25, 25, 57, 58, 25, 22, 25,
+- 34, 14, 21, 22, 23, 24, 31, 36, 59, 18,
+- 33, 74, 22, 23, 30, 60, 36, 21, 20, 22,
+- 32, 34, 35, 60, 34, 60, 35
++ 0, 2, 4, 0, 2, 4, 2, 2, 3, 4,
++ 3, 4, 5, 0, 2, 4, 2, 3, 2, 2,
++ 3, 4, 2, 9, 5, 2, 0, 2, 2, 3,
++ 1, 2, 2, 2, 1, 1, 3, 1, 1, 5,
++ 1, 3, 1, 3, 1, 3, 1, 3, 1, 3,
++ 1, 3, 3, 1, 3, 3, 3, 3, 3, 3,
++ 1, 3, 3, 1, 3, 3, 3, 1, 1, 2,
++ 2, 2, 0, 2, 2, 0, 2, 2, 2, 3,
++ 2
+ };
+
+-#define yyerrok (yyerrstatus = 0)
+-#define yyclearin (yychar = YYEMPTY)
+-#define YYEMPTY (-2)
+-#define YYEOF 0
+-
+-#define YYACCEPT goto yyacceptlab
+-#define YYABORT goto yyabortlab
+-#define YYERROR goto yyerrorlab
+-
+-
+-/* Like YYERROR except do call yyerror. This remains here temporarily
+- to ease the transition to the new meaning of YYERROR, for GCC.
+- Once GCC version 2 has supplanted version 1, this can go. However,
+- YYFAIL appears to be in use. Nevertheless, it is formally deprecated
+- in Bison 2.4.2's NEWS entry, where a plan to phase it out is
+- discussed. */
+-
+-#define YYFAIL goto yyerrlab
+-#if defined YYFAIL
+- /* This is here to suppress warnings from the GCC cpp's
+- -Wunused-macros. Normally we don't worry about that warning, but
+- some users do, and we want to make it easy for users to remove
+- YYFAIL uses, which will produce warnings from Bison 2.5. */
+-#endif
+
+-#define YYRECOVERING() (!!yyerrstatus)
++#define yyerrok (yyerrstatus = 0)
++#define yyclearin (yychar = YYEMPTY)
++#define YYEMPTY (-2)
++#define YYEOF 0
++
++#define YYACCEPT goto yyacceptlab
++#define YYABORT goto yyabortlab
++#define YYERROR goto yyerrorlab
+
+-#define YYBACKUP(Token, Value) \
+-do \
+- if (yychar == YYEMPTY && yylen == 1) \
+- { \
+- yychar = (Token); \
+- yylval = (Value); \
+- YYPOPSTACK (1); \
+- goto yybackup; \
+- } \
+- else \
+- { \
+- yyerror (YY_("syntax error: cannot back up")); \
+- YYERROR; \
+- } \
+-while (YYID (0))
+
++#define YYRECOVERING() (!!yyerrstatus)
+
+-#define YYTERROR 1
+-#define YYERRCODE 256
++#define YYBACKUP(Token, Value) \
++do \
++ if (yychar == YYEMPTY) \
++ { \
++ yychar = (Token); \
++ yylval = (Value); \
++ YYPOPSTACK (yylen); \
++ yystate = *yyssp; \
++ goto yybackup; \
++ } \
++ else \
++ { \
++ yyerror (YY_("syntax error: cannot back up")); \
++ YYERROR; \
++ } \
++while (0)
++
++/* Error token number */
++#define YYTERROR 1
++#define YYERRCODE 256
+
+
+ /* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+-#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+ #ifndef YYLLOC_DEFAULT
+-# define YYLLOC_DEFAULT(Current, Rhs, N) \
+- do \
+- if (YYID (N)) \
+- { \
+- (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+- (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+- (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+- (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+- } \
+- else \
+- { \
+- (Current).first_line = (Current).last_line = \
+- YYRHSLOC (Rhs, 0).last_line; \
+- (Current).first_column = (Current).last_column = \
+- YYRHSLOC (Rhs, 0).last_column; \
+- } \
+- while (YYID (0))
++# define YYLLOC_DEFAULT(Current, Rhs, N) \
++ do \
++ if (N) \
++ { \
++ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
++ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
++ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
++ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
++ } \
++ else \
++ { \
++ (Current).first_line = (Current).last_line = \
++ YYRHSLOC (Rhs, 0).last_line; \
++ (Current).first_column = (Current).last_column = \
++ YYRHSLOC (Rhs, 0).last_column; \
++ } \
++ while (0)
+ #endif
+
++#define YYRHSLOC(Rhs, K) ((Rhs)[K])
++
++
++/* Enable debugging if requested. */
++#if YYDEBUG
++
++# ifndef YYFPRINTF
++# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
++# define YYFPRINTF fprintf
++# endif
++
++# define YYDPRINTF(Args) \
++do { \
++ if (yydebug) \
++ YYFPRINTF Args; \
++} while (0)
++
+
+ /* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+@@ -799,82 +779,73 @@ while (YYID (0))
+
+ #ifndef YY_LOCATION_PRINT
+ # if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+-# define YY_LOCATION_PRINT(File, Loc) \
+- fprintf (File, "%d.%d-%d.%d", \
+- (Loc).first_line, (Loc).first_column, \
+- (Loc).last_line, (Loc).last_column)
+-# else
+-# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+-# endif
+-#endif
+-
+
+-/* YYLEX -- calling `yylex' with the right arguments. */
++/* Print *YYLOCP on YYO. Private, do not rely on its existence. */
+
+-#ifdef YYLEX_PARAM
+-# define YYLEX yylex (YYLEX_PARAM)
+-#else
+-# define YYLEX yylex ()
+-#endif
++YY_ATTRIBUTE_UNUSED
++static unsigned
++yy_location_print_ (FILE *yyo, YYLTYPE const * const yylocp)
++{
++ unsigned res = 0;
++ int end_col = 0 != yylocp->last_column ? yylocp->last_column - 1 : 0;
++ if (0 <= yylocp->first_line)
++ {
++ res += YYFPRINTF (yyo, "%d", yylocp->first_line);
++ if (0 <= yylocp->first_column)
++ res += YYFPRINTF (yyo, ".%d", yylocp->first_column);
++ }
++ if (0 <= yylocp->last_line)
++ {
++ if (yylocp->first_line < yylocp->last_line)
++ {
++ res += YYFPRINTF (yyo, "-%d", yylocp->last_line);
++ if (0 <= end_col)
++ res += YYFPRINTF (yyo, ".%d", end_col);
++ }
++ else if (0 <= end_col && yylocp->first_column < end_col)
++ res += YYFPRINTF (yyo, "-%d", end_col);
++ }
++ return res;
++ }
+
+-/* Enable debugging if requested. */
+-#if YYDEBUG
++# define YY_LOCATION_PRINT(File, Loc) \
++ yy_location_print_ (File, &(Loc))
+
+-# ifndef YYFPRINTF
+-# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+-# define YYFPRINTF fprintf
++# else
++# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+ # endif
++#endif
+
+-# define YYDPRINTF(Args) \
+-do { \
+- if (yydebug) \
+- YYFPRINTF Args; \
+-} while (YYID (0))
+-
+-# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+-do { \
+- if (yydebug) \
+- { \
+- YYFPRINTF (stderr, "%s ", Title); \
+- yy_symbol_print (stderr, \
+- Type, Value, Location); \
+- YYFPRINTF (stderr, "\n"); \
+- } \
+-} while (YYID (0))
+
++# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
++do { \
++ if (yydebug) \
++ { \
++ YYFPRINTF (stderr, "%s ", Title); \
++ yy_symbol_print (stderr, \
++ Type, Value, Location); \
++ YYFPRINTF (stderr, "\n"); \
++ } \
++} while (0)
+
+-/*--------------------------------.
+-| Print this symbol on YYOUTPUT. |
+-`--------------------------------*/
+
+-/*ARGSUSED*/
+-#if (defined __STDC__ || defined __C99__FUNC__ \
+- || defined __cplusplus || defined _MSC_VER)
++/*----------------------------------------.
++| Print this symbol's value on YYOUTPUT. |
++`----------------------------------------*/
++
+ static void
+ yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp)
+-#else
+-static void
+-yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp)
+- FILE *yyoutput;
+- int yytype;
+- YYSTYPE const * const yyvaluep;
+- YYLTYPE const * const yylocationp;
+-#endif
+ {
++ FILE *yyo = yyoutput;
++ YYUSE (yyo);
++ YYUSE (yylocationp);
+ if (!yyvaluep)
+ return;
+- YYUSE (yylocationp);
+ # ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+-# else
+- YYUSE (yyoutput);
+ # endif
+- switch (yytype)
+- {
+- default:
+- break;
+- }
++ YYUSE (yytype);
+ }
+
+
+@@ -882,23 +853,11 @@ yy_symbol_value_print (yyoutput, yytype,
+ | Print this symbol on YYOUTPUT. |
+ `--------------------------------*/
+
+-#if (defined __STDC__ || defined __C99__FUNC__ \
+- || defined __cplusplus || defined _MSC_VER)
+ static void
+ yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp)
+-#else
+-static void
+-yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp)
+- FILE *yyoutput;
+- int yytype;
+- YYSTYPE const * const yyvaluep;
+- YYLTYPE const * const yylocationp;
+-#endif
+ {
+- if (yytype < YYNTOKENS)
+- YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+- else
+- YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
++ YYFPRINTF (yyoutput, "%s %s (",
++ yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]);
+
+ YY_LOCATION_PRINT (yyoutput, *yylocationp);
+ YYFPRINTF (yyoutput, ": ");
+@@ -911,16 +870,8 @@ yy_symbol_print (yyoutput, yytype, yyval
+ | TOP (included). |
+ `------------------------------------------------------------------*/
+
+-#if (defined __STDC__ || defined __C99__FUNC__ \
+- || defined __cplusplus || defined _MSC_VER)
+ static void
+ yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+-#else
+-static void
+-yy_stack_print (yybottom, yytop)
+- yytype_int16 *yybottom;
+- yytype_int16 *yytop;
+-#endif
+ {
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+@@ -931,50 +882,42 @@ yy_stack_print (yybottom, yytop)
+ YYFPRINTF (stderr, "\n");
+ }
+
+-# define YY_STACK_PRINT(Bottom, Top) \
+-do { \
+- if (yydebug) \
+- yy_stack_print ((Bottom), (Top)); \
+-} while (YYID (0))
++# define YY_STACK_PRINT(Bottom, Top) \
++do { \
++ if (yydebug) \
++ yy_stack_print ((Bottom), (Top)); \
++} while (0)
+
+
+ /*------------------------------------------------.
+ | Report that the YYRULE is going to be reduced. |
+ `------------------------------------------------*/
+
+-#if (defined __STDC__ || defined __C99__FUNC__ \
+- || defined __cplusplus || defined _MSC_VER)
+-static void
+-yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule)
+-#else
+ static void
+-yy_reduce_print (yyvsp, yylsp, yyrule)
+- YYSTYPE *yyvsp;
+- YYLTYPE *yylsp;
+- int yyrule;
+-#endif
++yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule)
+ {
++ unsigned long int yylno = yyrline[yyrule];
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+- unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+- yyrule - 1, yylno);
++ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+- yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+- &(yyvsp[(yyi + 1) - (yynrhs)])
+- , &(yylsp[(yyi + 1) - (yynrhs)]) );
++ yy_symbol_print (stderr,
++ yystos[yyssp[yyi + 1 - yynrhs]],
++ &(yyvsp[(yyi + 1) - (yynrhs)])
++ , &(yylsp[(yyi + 1) - (yynrhs)]) );
+ YYFPRINTF (stderr, "\n");
+ }
+ }
+
+-# define YY_REDUCE_PRINT(Rule) \
+-do { \
+- if (yydebug) \
+- yy_reduce_print (yyvsp, yylsp, Rule); \
+-} while (YYID (0))
++# define YY_REDUCE_PRINT(Rule) \
++do { \
++ if (yydebug) \
++ yy_reduce_print (yyssp, yyvsp, yylsp, Rule); \
++} while (0)
+
+ /* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+@@ -988,7 +931,7 @@ int yydebug;
+
+
+ /* YYINITDEPTH -- initial size of the parser's stacks. */
+-#ifndef YYINITDEPTH
++#ifndef YYINITDEPTH
+ # define YYINITDEPTH 200
+ #endif
+
+@@ -1011,15 +954,8 @@ int yydebug;
+ # define yystrlen strlen
+ # else
+ /* Return the length of YYSTR. */
+-#if (defined __STDC__ || defined __C99__FUNC__ \
+- || defined __cplusplus || defined _MSC_VER)
+ static YYSIZE_T
+ yystrlen (const char *yystr)
+-#else
+-static YYSIZE_T
+-yystrlen (yystr)
+- const char *yystr;
+-#endif
+ {
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+@@ -1035,16 +971,8 @@ yystrlen (yystr)
+ # else
+ /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+-#if (defined __STDC__ || defined __C99__FUNC__ \
+- || defined __cplusplus || defined _MSC_VER)
+ static char *
+ yystpcpy (char *yydest, const char *yysrc)
+-#else
+-static char *
+-yystpcpy (yydest, yysrc)
+- char *yydest;
+- const char *yysrc;
+-#endif
+ {
+ char *yyd = yydest;
+ const char *yys = yysrc;
+@@ -1074,27 +1002,27 @@ yytnamerr (char *yyres, const char *yyst
+ char const *yyp = yystr;
+
+ for (;;)
+- switch (*++yyp)
+- {
+- case '\'':
+- case ',':
+- goto do_not_strip_quotes;
+-
+- case '\\':
+- if (*++yyp != '\\')
+- goto do_not_strip_quotes;
+- /* Fall through. */
+- default:
+- if (yyres)
+- yyres[yyn] = *yyp;
+- yyn++;
+- break;
+-
+- case '"':
+- if (yyres)
+- yyres[yyn] = '\0';
+- return yyn;
+- }
++ switch (*++yyp)
++ {
++ case '\'':
++ case ',':
++ goto do_not_strip_quotes;
++
++ case '\\':
++ if (*++yyp != '\\')
++ goto do_not_strip_quotes;
++ /* Fall through. */
++ default:
++ if (yyres)
++ yyres[yyn] = *yyp;
++ yyn++;
++ break;
++
++ case '"':
++ if (yyres)
++ yyres[yyn] = '\0';
++ return yyn;
++ }
+ do_not_strip_quotes: ;
+ }
+
+@@ -1117,12 +1045,11 @@ static int
+ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
+ yytype_int16 *yyssp, int yytoken)
+ {
+- YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]);
++ YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]);
+ YYSIZE_T yysize = yysize0;
+- YYSIZE_T yysize1;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ /* Internationalized format string. */
+- const char *yyformat = 0;
++ const char *yyformat = YY_NULLPTR;
+ /* Arguments of yyformat. */
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ /* Number of reported tokens (one for the "unexpected", one per
+@@ -1130,10 +1057,6 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, c
+ int yycount = 0;
+
+ /* There are many possibilities here to consider:
+- - Assume YYFAIL is not used. It's too flawed to consider. See
+- <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
+- for details. YYERROR is fine as it does not invoke this
+- function.
+ - If this state is a consistent state with a default action, then
+ the only way this function was invoked is if the default action
+ is an error action. In that case, don't check for expected
+@@ -1182,11 +1105,13 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, c
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+- yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+- if (! (yysize <= yysize1
+- && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+- return 2;
+- yysize = yysize1;
++ {
++ YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]);
++ if (! (yysize <= yysize1
++ && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
++ return 2;
++ yysize = yysize1;
++ }
+ }
+ }
+ }
+@@ -1206,10 +1131,12 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, c
+ # undef YYCASE_
+ }
+
+- yysize1 = yysize + yystrlen (yyformat);
+- if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+- return 2;
+- yysize = yysize1;
++ {
++ YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
++ if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
++ return 2;
++ yysize = yysize1;
++ }
+
+ if (*yymsg_alloc < yysize)
+ {
+@@ -1246,50 +1173,21 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, c
+ | Release the memory associated to this symbol. |
+ `-----------------------------------------------*/
+
+-/*ARGSUSED*/
+-#if (defined __STDC__ || defined __C99__FUNC__ \
+- || defined __cplusplus || defined _MSC_VER)
+ static void
+ yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp)
+-#else
+-static void
+-yydestruct (yymsg, yytype, yyvaluep, yylocationp)
+- const char *yymsg;
+- int yytype;
+- YYSTYPE *yyvaluep;
+- YYLTYPE *yylocationp;
+-#endif
+ {
+ YYUSE (yyvaluep);
+ YYUSE (yylocationp);
+-
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+- switch (yytype)
+- {
+-
+- default:
+- break;
+- }
++ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
++ YYUSE (yytype);
++ YY_IGNORE_MAYBE_UNINITIALIZED_END
+ }
+
+
+-/* Prevent warnings from -Wmissing-prototypes. */
+-#ifdef YYPARSE_PARAM
+-#if defined __STDC__ || defined __cplusplus
+-int yyparse (void *YYPARSE_PARAM);
+-#else
+-int yyparse ();
+-#endif
+-#else /* ! YYPARSE_PARAM */
+-#if defined __STDC__ || defined __cplusplus
+-int yyparse (void);
+-#else
+-int yyparse ();
+-#endif
+-#endif /* ! YYPARSE_PARAM */
+
+
+ /* The lookahead symbol. */
+@@ -1297,10 +1195,12 @@ int yychar;
+
+ /* The semantic value of the lookahead symbol. */
+ YYSTYPE yylval;
+-
+ /* Location data for the lookahead symbol. */
+-YYLTYPE yylloc;
+-
++YYLTYPE yylloc
++# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
++ = { 1, 1, 1, 1 }
++# endif
++;
+ /* Number of syntax errors so far. */
+ int yynerrs;
+
+@@ -1309,38 +1209,19 @@ int yynerrs;
+ | yyparse. |
+ `----------*/
+
+-#ifdef YYPARSE_PARAM
+-#if (defined __STDC__ || defined __C99__FUNC__ \
+- || defined __cplusplus || defined _MSC_VER)
+-int
+-yyparse (void *YYPARSE_PARAM)
+-#else
+-int
+-yyparse (YYPARSE_PARAM)
+- void *YYPARSE_PARAM;
+-#endif
+-#else /* ! YYPARSE_PARAM */
+-#if (defined __STDC__ || defined __C99__FUNC__ \
+- || defined __cplusplus || defined _MSC_VER)
+ int
+ yyparse (void)
+-#else
+-int
+-yyparse ()
+-
+-#endif
+-#endif
+ {
+ int yystate;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+
+ /* The stacks and their tools:
+- `yyss': related to states.
+- `yyvs': related to semantic values.
+- `yyls': related to locations.
++ 'yyss': related to states.
++ 'yyvs': related to semantic values.
++ 'yyls': related to locations.
+
+- Refer to the stacks thru separate pointers, to allow yyoverflow
++ Refer to the stacks through separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+@@ -1366,7 +1247,7 @@ yyparse ()
+ int yyn;
+ int yyresult;
+ /* Lookahead token as an internal (translated) token number. */
+- int yytoken;
++ int yytoken = 0;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+@@ -1385,10 +1266,9 @@ yyparse ()
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+- yytoken = 0;
+- yyss = yyssa;
+- yyvs = yyvsa;
+- yyls = yylsa;
++ yyssp = yyss = yyssa;
++ yyvsp = yyvs = yyvsa;
++ yylsp = yyls = yylsa;
+ yystacksize = YYINITDEPTH;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+@@ -1397,21 +1277,7 @@ yyparse ()
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+-
+- /* Initialize stack pointers.
+- Waste one element of value and location stack
+- so that they stay on the same level as the state stack.
+- The wasted elements are never initialized. */
+- yyssp = yyss;
+- yyvsp = yyvs;
+- yylsp = yyls;
+-
+-#if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+- /* Initialize the default location before parsing starts. */
+- yylloc.first_line = yylloc.last_line = 1;
+- yylloc.first_column = yylloc.last_column = 1;
+-#endif
+-
++ yylsp[0] = yylloc;
+ goto yysetstate;
+
+ /*------------------------------------------------------------.
+@@ -1432,26 +1298,26 @@ yyparse ()
+
+ #ifdef yyoverflow
+ {
+- /* Give user a chance to reallocate the stack. Use copies of
+- these so that the &'s don't force the real ones into
+- memory. */
+- YYSTYPE *yyvs1 = yyvs;
+- yytype_int16 *yyss1 = yyss;
+- YYLTYPE *yyls1 = yyls;
+-
+- /* Each stack pointer address is followed by the size of the
+- data in use in that stack, in bytes. This used to be a
+- conditional around just the two extra args, but that might
+- be undefined if yyoverflow is a macro. */
+- yyoverflow (YY_("memory exhausted"),
+- &yyss1, yysize * sizeof (*yyssp),
+- &yyvs1, yysize * sizeof (*yyvsp),
+- &yyls1, yysize * sizeof (*yylsp),
+- &yystacksize);
+-
+- yyls = yyls1;
+- yyss = yyss1;
+- yyvs = yyvs1;
++ /* Give user a chance to reallocate the stack. Use copies of
++ these so that the &'s don't force the real ones into
++ memory. */
++ YYSTYPE *yyvs1 = yyvs;
++ yytype_int16 *yyss1 = yyss;
++ YYLTYPE *yyls1 = yyls;
++
++ /* Each stack pointer address is followed by the size of the
++ data in use in that stack, in bytes. This used to be a
++ conditional around just the two extra args, but that might
++ be undefined if yyoverflow is a macro. */
++ yyoverflow (YY_("memory exhausted"),
++ &yyss1, yysize * sizeof (*yyssp),
++ &yyvs1, yysize * sizeof (*yyvsp),
++ &yyls1, yysize * sizeof (*yylsp),
++ &yystacksize);
++
++ yyls = yyls1;
++ yyss = yyss1;
++ yyvs = yyvs1;
+ }
+ #else /* no yyoverflow */
+ # ifndef YYSTACK_RELOCATE
+@@ -1459,23 +1325,23 @@ yyparse ()
+ # else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+- goto yyexhaustedlab;
++ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+- yystacksize = YYMAXDEPTH;
++ yystacksize = YYMAXDEPTH;
+
+ {
+- yytype_int16 *yyss1 = yyss;
+- union yyalloc *yyptr =
+- (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+- if (! yyptr)
+- goto yyexhaustedlab;
+- YYSTACK_RELOCATE (yyss_alloc, yyss);
+- YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+- YYSTACK_RELOCATE (yyls_alloc, yyls);
++ yytype_int16 *yyss1 = yyss;
++ union yyalloc *yyptr =
++ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
++ if (! yyptr)
++ goto yyexhaustedlab;
++ YYSTACK_RELOCATE (yyss_alloc, yyss);
++ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
++ YYSTACK_RELOCATE (yyls_alloc, yyls);
+ # undef YYSTACK_RELOCATE
+- if (yyss1 != yyssa)
+- YYSTACK_FREE (yyss1);
++ if (yyss1 != yyssa)
++ YYSTACK_FREE (yyss1);
+ }
+ # endif
+ #endif /* no yyoverflow */
+@@ -1485,10 +1351,10 @@ yyparse ()
+ yylsp = yyls + yysize - 1;
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+- (unsigned long int) yystacksize));
++ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+- YYABORT;
++ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+@@ -1517,7 +1383,7 @@ yybackup:
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+- yychar = YYLEX;
++ yychar = yylex ();
+ }
+
+ if (yychar <= YYEOF)
+@@ -1557,7 +1423,9 @@ yybackup:
+ yychar = YYEMPTY;
+
+ yystate = yyn;
++ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
++ YY_IGNORE_MAYBE_UNINITIALIZED_END
+ *++yylsp = yylloc;
+ goto yynewstate;
+
+@@ -1580,7 +1448,7 @@ yyreduce:
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+- `$$ = $1'.
++ '$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+@@ -1595,322 +1463,273 @@ yyreduce:
+ switch (yyn)
+ {
+ case 2:
+-
+-/* Line 1806 of yacc.c */
+-#line 109 "dtc-parser.y"
++#line 105 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- (yyvsp[(5) - (5)].node)->is_plugin = (yyvsp[(3) - (5)].is_plugin);
+- (yyvsp[(5) - (5)].node)->is_root = 1;
+- the_boot_info = build_boot_info((yyvsp[(4) - (5)].re), (yyvsp[(5) - (5)].node),
+- guess_boot_cpuid((yyvsp[(5) - (5)].node)));
++ the_boot_info = build_boot_info((yyvsp[-1].re), (yyvsp[0].node),
++ guess_boot_cpuid((yyvsp[0].node)));
+ }
++#line 1472 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 3:
+-
+-/* Line 1806 of yacc.c */
+-#line 119 "dtc-parser.y"
++#line 113 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- (yyval.is_plugin) = 0;
++ (yyval.re) = NULL;
+ }
++#line 1480 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 4:
+-
+-/* Line 1806 of yacc.c */
+-#line 123 "dtc-parser.y"
++#line 117 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- (yyval.is_plugin) = 1;
++ (yyval.re) = chain_reserve_entry((yyvsp[-1].re), (yyvsp[0].re));
+ }
++#line 1488 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 5:
+-
+-/* Line 1806 of yacc.c */
+-#line 130 "dtc-parser.y"
++#line 124 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- (yyval.re) = NULL;
++ (yyval.re) = build_reserve_entry((yyvsp[-2].integer), (yyvsp[-1].integer));
+ }
++#line 1496 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 6:
+-
+-/* Line 1806 of yacc.c */
+-#line 134 "dtc-parser.y"
++#line 128 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- (yyval.re) = chain_reserve_entry((yyvsp[(1) - (2)].re), (yyvsp[(2) - (2)].re));
++ add_label(&(yyvsp[0].re)->labels, (yyvsp[-1].labelref));
++ (yyval.re) = (yyvsp[0].re);
+ }
++#line 1505 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 7:
+-
+-/* Line 1806 of yacc.c */
+-#line 141 "dtc-parser.y"
++#line 136 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- (yyval.re) = build_reserve_entry((yyvsp[(2) - (4)].integer), (yyvsp[(3) - (4)].integer));
++ (yyval.node) = name_node((yyvsp[0].node), "");
+ }
++#line 1513 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 8:
+-
+-/* Line 1806 of yacc.c */
+-#line 145 "dtc-parser.y"
++#line 140 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- add_label(&(yyvsp[(2) - (2)].re)->labels, (yyvsp[(1) - (2)].labelref));
+- (yyval.re) = (yyvsp[(2) - (2)].re);
++ (yyval.node) = merge_nodes((yyvsp[-2].node), (yyvsp[0].node));
+ }
++#line 1521 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 9:
+-
+-/* Line 1806 of yacc.c */
+-#line 153 "dtc-parser.y"
++#line 145 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- (yyval.node) = name_node((yyvsp[(2) - (2)].node), "");
++ struct node *target = get_node_by_ref((yyvsp[-3].node), (yyvsp[-1].labelref));
++
++ add_label(&target->labels, (yyvsp[-2].labelref));
++ if (target)
++ merge_nodes(target, (yyvsp[0].node));
++ else
++ ERROR(&(yylsp[-1]), "Label or path %s not found", (yyvsp[-1].labelref));
++ (yyval.node) = (yyvsp[-3].node);
+ }
++#line 1536 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 10:
+-
+-/* Line 1806 of yacc.c */
+-#line 157 "dtc-parser.y"
++#line 156 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- (yyval.node) = merge_nodes((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
++ struct node *target = get_node_by_ref((yyvsp[-2].node), (yyvsp[-1].labelref));
++
++ if (target)
++ merge_nodes(target, (yyvsp[0].node));
++ else
++ ERROR(&(yylsp[-1]), "Label or path %s not found", (yyvsp[-1].labelref));
++ (yyval.node) = (yyvsp[-2].node);
+ }
++#line 1550 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 11:
+-
+-/* Line 1806 of yacc.c */
+-#line 162 "dtc-parser.y"
++#line 166 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- struct node *target = get_node_by_ref((yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].labelref));
++ struct node *target = get_node_by_ref((yyvsp[-3].node), (yyvsp[-1].labelref));
+
+- add_label(&target->labels, (yyvsp[(2) - (4)].labelref));
+ if (target)
+- merge_nodes(target, (yyvsp[(4) - (4)].node));
++ delete_node(target);
+ else
+- ERROR(&(yylsp[(3) - (4)]), "Label or path %s not found", (yyvsp[(3) - (4)].labelref));
+- (yyval.node) = (yyvsp[(1) - (4)].node);
++ ERROR(&(yylsp[-1]), "Label or path %s not found", (yyvsp[-1].labelref));
++
++
++ (yyval.node) = (yyvsp[-3].node);
+ }
++#line 1566 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 12:
+-
+-/* Line 1806 of yacc.c */
+-#line 173 "dtc-parser.y"
++#line 181 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- struct node *target = get_node_by_ref((yyvsp[(1) - (3)].node), (yyvsp[(2) - (3)].labelref));
+-
+- if (target)
+- merge_nodes(target, (yyvsp[(3) - (3)].node));
+- else
+- ERROR(&(yylsp[(2) - (3)]), "Label or path %s not found", (yyvsp[(2) - (3)].labelref));
+- (yyval.node) = (yyvsp[(1) - (3)].node);
++ (yyval.node) = build_node((yyvsp[-3].proplist), (yyvsp[-2].nodelist));
+ }
++#line 1574 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 13:
+-
+-/* Line 1806 of yacc.c */
+-#line 183 "dtc-parser.y"
++#line 188 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- struct node *target = get_node_by_ref((yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].labelref));
+-
+- if (target)
+- delete_node(target);
+- else
+- ERROR(&(yylsp[(3) - (4)]), "Label or path %s not found", (yyvsp[(3) - (4)].labelref));
+-
+-
+- (yyval.node) = (yyvsp[(1) - (4)].node);
++ (yyval.proplist) = NULL;
+ }
++#line 1582 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 14:
+-
+-/* Line 1806 of yacc.c */
+-#line 198 "dtc-parser.y"
++#line 192 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- (yyval.node) = build_node((yyvsp[(2) - (5)].proplist), (yyvsp[(3) - (5)].nodelist));
++ (yyval.proplist) = chain_property((yyvsp[0].prop), (yyvsp[-1].proplist));
+ }
++#line 1590 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 15:
+-
+-/* Line 1806 of yacc.c */
+-#line 205 "dtc-parser.y"
++#line 199 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- (yyval.proplist) = NULL;
++ (yyval.prop) = build_property((yyvsp[-3].propnodename), (yyvsp[-1].data));
+ }
++#line 1598 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 16:
+-
+-/* Line 1806 of yacc.c */
+-#line 209 "dtc-parser.y"
++#line 203 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- (yyval.proplist) = chain_property((yyvsp[(2) - (2)].prop), (yyvsp[(1) - (2)].proplist));
++ (yyval.prop) = build_property((yyvsp[-1].propnodename), empty_data);
+ }
++#line 1606 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 17:
+-
+-/* Line 1806 of yacc.c */
+-#line 216 "dtc-parser.y"
++#line 207 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- (yyval.prop) = build_property((yyvsp[(1) - (4)].propnodename), (yyvsp[(3) - (4)].data));
++ (yyval.prop) = build_property_delete((yyvsp[-1].propnodename));
+ }
++#line 1614 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 18:
+-
+-/* Line 1806 of yacc.c */
+-#line 220 "dtc-parser.y"
++#line 211 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- (yyval.prop) = build_property((yyvsp[(1) - (2)].propnodename), empty_data);
++ add_label(&(yyvsp[0].prop)->labels, (yyvsp[-1].labelref));
++ (yyval.prop) = (yyvsp[0].prop);
+ }
++#line 1623 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 19:
+-
+-/* Line 1806 of yacc.c */
+-#line 224 "dtc-parser.y"
++#line 219 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- (yyval.prop) = build_property_delete((yyvsp[(2) - (3)].propnodename));
++ (yyval.data) = data_merge((yyvsp[-1].data), (yyvsp[0].data));
+ }
++#line 1631 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 20:
+-
+-/* Line 1806 of yacc.c */
+-#line 228 "dtc-parser.y"
++#line 223 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- add_label(&(yyvsp[(2) - (2)].prop)->labels, (yyvsp[(1) - (2)].labelref));
+- (yyval.prop) = (yyvsp[(2) - (2)].prop);
++ (yyval.data) = data_merge((yyvsp[-2].data), (yyvsp[-1].array).data);
+ }
++#line 1639 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 21:
+-
+-/* Line 1806 of yacc.c */
+-#line 236 "dtc-parser.y"
++#line 227 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- (yyval.data) = data_merge((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].data));
++ (yyval.data) = data_merge((yyvsp[-3].data), (yyvsp[-1].data));
+ }
++#line 1647 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 22:
+-
+-/* Line 1806 of yacc.c */
+-#line 240 "dtc-parser.y"
++#line 231 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- (yyval.data) = data_merge((yyvsp[(1) - (3)].data), (yyvsp[(2) - (3)].array).data);
++ (yyval.data) = data_add_marker((yyvsp[-1].data), REF_PATH, (yyvsp[0].labelref));
+ }
++#line 1655 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 23:
+-
+-/* Line 1806 of yacc.c */
+-#line 244 "dtc-parser.y"
+- {
+- (yyval.data) = data_merge((yyvsp[(1) - (4)].data), (yyvsp[(3) - (4)].data));
+- }
+- break;
+-
+- case 24:
+-
+-/* Line 1806 of yacc.c */
+-#line 248 "dtc-parser.y"
+- {
+- (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), REF_PATH, (yyvsp[(2) - (2)].labelref));
+- }
+- break;
+-
+- case 25:
+-
+-/* Line 1806 of yacc.c */
+-#line 252 "dtc-parser.y"
++#line 235 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- FILE *f = srcfile_relative_open((yyvsp[(4) - (9)].data).val, NULL);
++ FILE *f = srcfile_relative_open((yyvsp[-5].data).val, NULL);
+ struct data d;
+
+- if ((yyvsp[(6) - (9)].integer) != 0)
+- if (fseek(f, (yyvsp[(6) - (9)].integer), SEEK_SET) != 0)
++ if ((yyvsp[-3].integer) != 0)
++ if (fseek(f, (yyvsp[-3].integer), SEEK_SET) != 0)
+ die("Couldn't seek to offset %llu in \"%s\": %s",
+- (unsigned long long)(yyvsp[(6) - (9)].integer), (yyvsp[(4) - (9)].data).val,
++ (unsigned long long)(yyvsp[-3].integer), (yyvsp[-5].data).val,
+ strerror(errno));
+
+- d = data_copy_file(f, (yyvsp[(8) - (9)].integer));
++ d = data_copy_file(f, (yyvsp[-1].integer));
+
+- (yyval.data) = data_merge((yyvsp[(1) - (9)].data), d);
++ (yyval.data) = data_merge((yyvsp[-8].data), d);
+ fclose(f);
+ }
++#line 1675 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 26:
+-
+-/* Line 1806 of yacc.c */
+-#line 268 "dtc-parser.y"
++ case 24:
++#line 251 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- FILE *f = srcfile_relative_open((yyvsp[(4) - (5)].data).val, NULL);
++ FILE *f = srcfile_relative_open((yyvsp[-1].data).val, NULL);
+ struct data d = empty_data;
+
+ d = data_copy_file(f, -1);
+
+- (yyval.data) = data_merge((yyvsp[(1) - (5)].data), d);
++ (yyval.data) = data_merge((yyvsp[-4].data), d);
+ fclose(f);
+ }
++#line 1689 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 27:
+-
+-/* Line 1806 of yacc.c */
+-#line 278 "dtc-parser.y"
++ case 25:
++#line 261 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref));
++ (yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref));
+ }
++#line 1697 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 28:
+-
+-/* Line 1806 of yacc.c */
+-#line 285 "dtc-parser.y"
++ case 26:
++#line 268 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.data) = empty_data;
+ }
++#line 1705 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 29:
+-
+-/* Line 1806 of yacc.c */
+-#line 289 "dtc-parser.y"
++ case 27:
++#line 272 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- (yyval.data) = (yyvsp[(1) - (2)].data);
++ (yyval.data) = (yyvsp[-1].data);
+ }
++#line 1713 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 30:
+-
+-/* Line 1806 of yacc.c */
+-#line 293 "dtc-parser.y"
++ case 28:
++#line 276 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref));
++ (yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref));
+ }
++#line 1721 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 31:
+-
+-/* Line 1806 of yacc.c */
+-#line 300 "dtc-parser.y"
++ case 29:
++#line 283 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ unsigned long long bits;
+
+- bits = (yyvsp[(2) - (3)].integer);
++ bits = (yyvsp[-1].integer);
+
+ if ((bits != 8) && (bits != 16) &&
+ (bits != 32) && (bits != 64)) {
+- ERROR(&(yylsp[(2) - (3)]), "Array elements must be"
++ ERROR(&(yylsp[-1]), "Array elements must be"
+ " 8, 16, 32 or 64-bits");
+ bits = 32;
+ }
+@@ -1918,25 +1737,23 @@ yyreduce:
+ (yyval.array).data = empty_data;
+ (yyval.array).bits = bits;
+ }
++#line 1741 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 32:
+-
+-/* Line 1806 of yacc.c */
+-#line 316 "dtc-parser.y"
++ case 30:
++#line 299 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.array).data = empty_data;
+ (yyval.array).bits = 32;
+ }
++#line 1750 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 33:
+-
+-/* Line 1806 of yacc.c */
+-#line 321 "dtc-parser.y"
++ case 31:
++#line 304 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- if ((yyvsp[(1) - (2)].array).bits < 64) {
+- uint64_t mask = (1ULL << (yyvsp[(1) - (2)].array).bits) - 1;
++ if ((yyvsp[-1].array).bits < 64) {
++ uint64_t mask = (1ULL << (yyvsp[-1].array).bits) - 1;
+ /*
+ * Bits above mask must either be all zero
+ * (positive within range of mask) or all one
+@@ -1945,293 +1762,258 @@ yyreduce:
+ * within the mask to one (i.e. | in the
+ * mask), all bits are one.
+ */
+- if (((yyvsp[(2) - (2)].integer) > mask) && (((yyvsp[(2) - (2)].integer) | mask) != -1ULL))
+- ERROR(&(yylsp[(2) - (2)]), "Value out of range for"
+- " %d-bit array element", (yyvsp[(1) - (2)].array).bits);
++ if (((yyvsp[0].integer) > mask) && (((yyvsp[0].integer) | mask) != -1ULL))
++ ERROR(&(yylsp[0]), "Value out of range for"
++ " %d-bit array element", (yyvsp[-1].array).bits);
+ }
+
+- (yyval.array).data = data_append_integer((yyvsp[(1) - (2)].array).data, (yyvsp[(2) - (2)].integer), (yyvsp[(1) - (2)].array).bits);
++ (yyval.array).data = data_append_integer((yyvsp[-1].array).data, (yyvsp[0].integer), (yyvsp[-1].array).bits);
+ }
++#line 1773 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 34:
+-
+-/* Line 1806 of yacc.c */
+-#line 340 "dtc-parser.y"
++ case 32:
++#line 323 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- uint64_t val = ~0ULL >> (64 - (yyvsp[(1) - (2)].array).bits);
++ uint64_t val = ~0ULL >> (64 - (yyvsp[-1].array).bits);
+
+- if ((yyvsp[(1) - (2)].array).bits == 32)
+- (yyvsp[(1) - (2)].array).data = data_add_marker((yyvsp[(1) - (2)].array).data,
++ if ((yyvsp[-1].array).bits == 32)
++ (yyvsp[-1].array).data = data_add_marker((yyvsp[-1].array).data,
+ REF_PHANDLE,
+- (yyvsp[(2) - (2)].labelref));
++ (yyvsp[0].labelref));
+ else
+- ERROR(&(yylsp[(2) - (2)]), "References are only allowed in "
++ ERROR(&(yylsp[0]), "References are only allowed in "
+ "arrays with 32-bit elements.");
+
+- (yyval.array).data = data_append_integer((yyvsp[(1) - (2)].array).data, val, (yyvsp[(1) - (2)].array).bits);
++ (yyval.array).data = data_append_integer((yyvsp[-1].array).data, val, (yyvsp[-1].array).bits);
+ }
++#line 1791 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 35:
+-
+-/* Line 1806 of yacc.c */
+-#line 354 "dtc-parser.y"
++ case 33:
++#line 337 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- (yyval.array).data = data_add_marker((yyvsp[(1) - (2)].array).data, LABEL, (yyvsp[(2) - (2)].labelref));
++ (yyval.array).data = data_add_marker((yyvsp[-1].array).data, LABEL, (yyvsp[0].labelref));
+ }
++#line 1799 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 38:
+-
+-/* Line 1806 of yacc.c */
+-#line 363 "dtc-parser.y"
++ case 36:
++#line 346 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- (yyval.integer) = (yyvsp[(2) - (3)].integer);
++ (yyval.integer) = (yyvsp[-1].integer);
+ }
++#line 1807 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 41:
++ case 39:
++#line 357 "dtc-parser.y" /* yacc.c:1646 */
++ { (yyval.integer) = (yyvsp[-4].integer) ? (yyvsp[-2].integer) : (yyvsp[0].integer); }
++#line 1813 "dtc-parser.tab.c" /* yacc.c:1646 */
++ break;
+
+-/* Line 1806 of yacc.c */
+-#line 374 "dtc-parser.y"
+- { (yyval.integer) = (yyvsp[(1) - (5)].integer) ? (yyvsp[(3) - (5)].integer) : (yyvsp[(5) - (5)].integer); }
++ case 41:
++#line 362 "dtc-parser.y" /* yacc.c:1646 */
++ { (yyval.integer) = (yyvsp[-2].integer) || (yyvsp[0].integer); }
++#line 1819 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 43:
+-
+-/* Line 1806 of yacc.c */
+-#line 379 "dtc-parser.y"
+- { (yyval.integer) = (yyvsp[(1) - (3)].integer) || (yyvsp[(3) - (3)].integer); }
++#line 367 "dtc-parser.y" /* yacc.c:1646 */
++ { (yyval.integer) = (yyvsp[-2].integer) && (yyvsp[0].integer); }
++#line 1825 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 45:
+-
+-/* Line 1806 of yacc.c */
+-#line 384 "dtc-parser.y"
+- { (yyval.integer) = (yyvsp[(1) - (3)].integer) && (yyvsp[(3) - (3)].integer); }
++#line 372 "dtc-parser.y" /* yacc.c:1646 */
++ { (yyval.integer) = (yyvsp[-2].integer) | (yyvsp[0].integer); }
++#line 1831 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 47:
+-
+-/* Line 1806 of yacc.c */
+-#line 389 "dtc-parser.y"
+- { (yyval.integer) = (yyvsp[(1) - (3)].integer) | (yyvsp[(3) - (3)].integer); }
++#line 377 "dtc-parser.y" /* yacc.c:1646 */
++ { (yyval.integer) = (yyvsp[-2].integer) ^ (yyvsp[0].integer); }
++#line 1837 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 49:
+-
+-/* Line 1806 of yacc.c */
+-#line 394 "dtc-parser.y"
+- { (yyval.integer) = (yyvsp[(1) - (3)].integer) ^ (yyvsp[(3) - (3)].integer); }
++#line 382 "dtc-parser.y" /* yacc.c:1646 */
++ { (yyval.integer) = (yyvsp[-2].integer) & (yyvsp[0].integer); }
++#line 1843 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 51:
+-
+-/* Line 1806 of yacc.c */
+-#line 399 "dtc-parser.y"
+- { (yyval.integer) = (yyvsp[(1) - (3)].integer) & (yyvsp[(3) - (3)].integer); }
++#line 387 "dtc-parser.y" /* yacc.c:1646 */
++ { (yyval.integer) = (yyvsp[-2].integer) == (yyvsp[0].integer); }
++#line 1849 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 53:
+-
+-/* Line 1806 of yacc.c */
+-#line 404 "dtc-parser.y"
+- { (yyval.integer) = (yyvsp[(1) - (3)].integer) == (yyvsp[(3) - (3)].integer); }
++ case 52:
++#line 388 "dtc-parser.y" /* yacc.c:1646 */
++ { (yyval.integer) = (yyvsp[-2].integer) != (yyvsp[0].integer); }
++#line 1855 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 54:
++#line 393 "dtc-parser.y" /* yacc.c:1646 */
++ { (yyval.integer) = (yyvsp[-2].integer) < (yyvsp[0].integer); }
++#line 1861 "dtc-parser.tab.c" /* yacc.c:1646 */
++ break;
+
+-/* Line 1806 of yacc.c */
+-#line 405 "dtc-parser.y"
+- { (yyval.integer) = (yyvsp[(1) - (3)].integer) != (yyvsp[(3) - (3)].integer); }
++ case 55:
++#line 394 "dtc-parser.y" /* yacc.c:1646 */
++ { (yyval.integer) = (yyvsp[-2].integer) > (yyvsp[0].integer); }
++#line 1867 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 56:
+-
+-/* Line 1806 of yacc.c */
+-#line 410 "dtc-parser.y"
+- { (yyval.integer) = (yyvsp[(1) - (3)].integer) < (yyvsp[(3) - (3)].integer); }
++#line 395 "dtc-parser.y" /* yacc.c:1646 */
++ { (yyval.integer) = (yyvsp[-2].integer) <= (yyvsp[0].integer); }
++#line 1873 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 57:
+-
+-/* Line 1806 of yacc.c */
+-#line 411 "dtc-parser.y"
+- { (yyval.integer) = (yyvsp[(1) - (3)].integer) > (yyvsp[(3) - (3)].integer); }
++#line 396 "dtc-parser.y" /* yacc.c:1646 */
++ { (yyval.integer) = (yyvsp[-2].integer) >= (yyvsp[0].integer); }
++#line 1879 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 58:
+-
+-/* Line 1806 of yacc.c */
+-#line 412 "dtc-parser.y"
+- { (yyval.integer) = (yyvsp[(1) - (3)].integer) <= (yyvsp[(3) - (3)].integer); }
++#line 400 "dtc-parser.y" /* yacc.c:1646 */
++ { (yyval.integer) = (yyvsp[-2].integer) << (yyvsp[0].integer); }
++#line 1885 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 59:
+-
+-/* Line 1806 of yacc.c */
+-#line 413 "dtc-parser.y"
+- { (yyval.integer) = (yyvsp[(1) - (3)].integer) >= (yyvsp[(3) - (3)].integer); }
+- break;
+-
+- case 60:
+-
+-/* Line 1806 of yacc.c */
+-#line 417 "dtc-parser.y"
+- { (yyval.integer) = (yyvsp[(1) - (3)].integer) << (yyvsp[(3) - (3)].integer); }
++#line 401 "dtc-parser.y" /* yacc.c:1646 */
++ { (yyval.integer) = (yyvsp[-2].integer) >> (yyvsp[0].integer); }
++#line 1891 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 61:
+-
+-/* Line 1806 of yacc.c */
+-#line 418 "dtc-parser.y"
+- { (yyval.integer) = (yyvsp[(1) - (3)].integer) >> (yyvsp[(3) - (3)].integer); }
++#line 406 "dtc-parser.y" /* yacc.c:1646 */
++ { (yyval.integer) = (yyvsp[-2].integer) + (yyvsp[0].integer); }
++#line 1897 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 63:
+-
+-/* Line 1806 of yacc.c */
+-#line 423 "dtc-parser.y"
+- { (yyval.integer) = (yyvsp[(1) - (3)].integer) + (yyvsp[(3) - (3)].integer); }
++ case 62:
++#line 407 "dtc-parser.y" /* yacc.c:1646 */
++ { (yyval.integer) = (yyvsp[-2].integer) - (yyvsp[0].integer); }
++#line 1903 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 64:
++#line 412 "dtc-parser.y" /* yacc.c:1646 */
++ { (yyval.integer) = (yyvsp[-2].integer) * (yyvsp[0].integer); }
++#line 1909 "dtc-parser.tab.c" /* yacc.c:1646 */
++ break;
+
+-/* Line 1806 of yacc.c */
+-#line 424 "dtc-parser.y"
+- { (yyval.integer) = (yyvsp[(1) - (3)].integer) - (yyvsp[(3) - (3)].integer); }
++ case 65:
++#line 413 "dtc-parser.y" /* yacc.c:1646 */
++ { (yyval.integer) = (yyvsp[-2].integer) / (yyvsp[0].integer); }
++#line 1915 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 66:
+-
+-/* Line 1806 of yacc.c */
+-#line 429 "dtc-parser.y"
+- { (yyval.integer) = (yyvsp[(1) - (3)].integer) * (yyvsp[(3) - (3)].integer); }
++#line 414 "dtc-parser.y" /* yacc.c:1646 */
++ { (yyval.integer) = (yyvsp[-2].integer) % (yyvsp[0].integer); }
++#line 1921 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 67:
+-
+-/* Line 1806 of yacc.c */
+-#line 430 "dtc-parser.y"
+- { (yyval.integer) = (yyvsp[(1) - (3)].integer) / (yyvsp[(3) - (3)].integer); }
++ case 69:
++#line 420 "dtc-parser.y" /* yacc.c:1646 */
++ { (yyval.integer) = -(yyvsp[0].integer); }
++#line 1927 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 68:
+-
+-/* Line 1806 of yacc.c */
+-#line 431 "dtc-parser.y"
+- { (yyval.integer) = (yyvsp[(1) - (3)].integer) % (yyvsp[(3) - (3)].integer); }
++ case 70:
++#line 421 "dtc-parser.y" /* yacc.c:1646 */
++ { (yyval.integer) = ~(yyvsp[0].integer); }
++#line 1933 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 71:
+-
+-/* Line 1806 of yacc.c */
+-#line 437 "dtc-parser.y"
+- { (yyval.integer) = -(yyvsp[(2) - (2)].integer); }
++#line 422 "dtc-parser.y" /* yacc.c:1646 */
++ { (yyval.integer) = !(yyvsp[0].integer); }
++#line 1939 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 72:
+-
+-/* Line 1806 of yacc.c */
+-#line 438 "dtc-parser.y"
+- { (yyval.integer) = ~(yyvsp[(2) - (2)].integer); }
++#line 427 "dtc-parser.y" /* yacc.c:1646 */
++ {
++ (yyval.data) = empty_data;
++ }
++#line 1947 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 73:
+-
+-/* Line 1806 of yacc.c */
+-#line 439 "dtc-parser.y"
+- { (yyval.integer) = !(yyvsp[(2) - (2)].integer); }
++#line 431 "dtc-parser.y" /* yacc.c:1646 */
++ {
++ (yyval.data) = data_append_byte((yyvsp[-1].data), (yyvsp[0].byte));
++ }
++#line 1955 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 74:
+-
+-/* Line 1806 of yacc.c */
+-#line 444 "dtc-parser.y"
++#line 435 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- (yyval.data) = empty_data;
++ (yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref));
+ }
++#line 1963 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 75:
+-
+-/* Line 1806 of yacc.c */
+-#line 448 "dtc-parser.y"
++#line 442 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- (yyval.data) = data_append_byte((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].byte));
++ (yyval.nodelist) = NULL;
+ }
++#line 1971 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 76:
+-
+-/* Line 1806 of yacc.c */
+-#line 452 "dtc-parser.y"
++#line 446 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref));
++ (yyval.nodelist) = chain_node((yyvsp[-1].node), (yyvsp[0].nodelist));
+ }
++#line 1979 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 77:
+-
+-/* Line 1806 of yacc.c */
+-#line 459 "dtc-parser.y"
++#line 450 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- (yyval.nodelist) = NULL;
++ ERROR(&(yylsp[0]), "Properties must precede subnodes");
++ YYERROR;
+ }
++#line 1988 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 78:
+-
+-/* Line 1806 of yacc.c */
+-#line 463 "dtc-parser.y"
++#line 458 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- (yyval.nodelist) = chain_node((yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].nodelist));
++ (yyval.node) = name_node((yyvsp[0].node), (yyvsp[-1].propnodename));
+ }
++#line 1996 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 79:
+-
+-/* Line 1806 of yacc.c */
+-#line 467 "dtc-parser.y"
++#line 462 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- ERROR(&(yylsp[(2) - (2)]), "Properties must precede subnodes");
+- YYERROR;
++ (yyval.node) = name_node(build_node_delete(), (yyvsp[-1].propnodename));
+ }
++#line 2004 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 80:
+-
+-/* Line 1806 of yacc.c */
+-#line 475 "dtc-parser.y"
++#line 466 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- (yyval.node) = name_node((yyvsp[(2) - (2)].node), (yyvsp[(1) - (2)].propnodename));
++ add_label(&(yyvsp[0].node)->labels, (yyvsp[-1].labelref));
++ (yyval.node) = (yyvsp[0].node);
+ }
++#line 2013 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 81:
+
+-/* Line 1806 of yacc.c */
+-#line 479 "dtc-parser.y"
+- {
+- (yyval.node) = name_node(build_node_delete(), (yyvsp[(2) - (3)].propnodename));
+- }
+- break;
+-
+- case 82:
+-
+-/* Line 1806 of yacc.c */
+-#line 483 "dtc-parser.y"
+- {
+- add_label(&(yyvsp[(2) - (2)].node)->labels, (yyvsp[(1) - (2)].labelref));
+- (yyval.node) = (yyvsp[(2) - (2)].node);
+- }
+- break;
+-
+-
+-
+-/* Line 1806 of yacc.c */
+-#line 2235 "dtc-parser.tab.c"
++#line 2017 "dtc-parser.tab.c" /* yacc.c:1646 */
+ default: break;
+ }
+ /* User semantic actions sometimes alter yychar, and that requires
+@@ -2254,7 +2036,7 @@ yyreduce:
+ *++yyvsp = yyval;
+ *++yylsp = yyloc;
+
+- /* Now `shift' the result of the reduction. Determine what state
++ /* Now 'shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+@@ -2269,9 +2051,9 @@ yyreduce:
+ goto yynewstate;
+
+
+-/*------------------------------------.
+-| yyerrlab -- here on detecting error |
+-`------------------------------------*/
++/*--------------------------------------.
++| yyerrlab -- here on detecting error. |
++`--------------------------------------*/
+ yyerrlab:
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+@@ -2322,20 +2104,20 @@ yyerrlab:
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+- error, discard it. */
++ error, discard it. */
+
+ if (yychar <= YYEOF)
+- {
+- /* Return failure if at end of input. */
+- if (yychar == YYEOF)
+- YYABORT;
+- }
++ {
++ /* Return failure if at end of input. */
++ if (yychar == YYEOF)
++ YYABORT;
++ }
+ else
+- {
+- yydestruct ("Error: discarding",
+- yytoken, &yylval, &yylloc);
+- yychar = YYEMPTY;
+- }
++ {
++ yydestruct ("Error: discarding",
++ yytoken, &yylval, &yylloc);
++ yychar = YYEMPTY;
++ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+@@ -2355,7 +2137,7 @@ yyerrorlab:
+ goto yyerrorlab;
+
+ yyerror_range[1] = yylsp[1-yylen];
+- /* Do not reclaim the symbols of the rule which action triggered
++ /* Do not reclaim the symbols of the rule whose action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+@@ -2368,35 +2150,37 @@ yyerrorlab:
+ | yyerrlab1 -- common code for both syntax error and YYERROR. |
+ `-------------------------------------------------------------*/
+ yyerrlab1:
+- yyerrstatus = 3; /* Each real token shifted decrements this. */
++ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (!yypact_value_is_default (yyn))
+- {
+- yyn += YYTERROR;
+- if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+- {
+- yyn = yytable[yyn];
+- if (0 < yyn)
+- break;
+- }
+- }
++ {
++ yyn += YYTERROR;
++ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
++ {
++ yyn = yytable[yyn];
++ if (0 < yyn)
++ break;
++ }
++ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+- YYABORT;
++ YYABORT;
+
+ yyerror_range[1] = *yylsp;
+ yydestruct ("Error: popping",
+- yystos[yystate], yyvsp, yylsp);
++ yystos[yystate], yyvsp, yylsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
++ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
++ YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+ yyerror_range[2] = yylloc;
+ /* Using YYLLOC is tempting, but would change the location of
+@@ -2425,7 +2209,7 @@ yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+-#if !defined(yyoverflow) || YYERROR_VERBOSE
++#if !defined yyoverflow || YYERROR_VERBOSE
+ /*-------------------------------------------------.
+ | yyexhaustedlab -- memory exhaustion comes here. |
+ `-------------------------------------------------*/
+@@ -2444,14 +2228,14 @@ yyreturn:
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval, &yylloc);
+ }
+- /* Do not reclaim the symbols of the rule which action triggered
++ /* Do not reclaim the symbols of the rule whose action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+- yystos[*yyssp], yyvsp, yylsp);
++ yystos[*yyssp], yyvsp, yylsp);
+ YYPOPSTACK (1);
+ }
+ #ifndef yyoverflow
+@@ -2462,18 +2246,12 @@ yyreturn:
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ #endif
+- /* Make sure YYID is used. */
+- return YYID (yyresult);
++ return yyresult;
+ }
+-
+-
+-
+-/* Line 2067 of yacc.c */
+-#line 489 "dtc-parser.y"
++#line 472 "dtc-parser.y" /* yacc.c:1906 */
+
+
+ void yyerror(char const *s)
+ {
+ ERROR(&yylloc, "%s", s);
+ }
+-
+--- a/scripts/dtc/dtc-parser.tab.h_shipped
++++ b/scripts/dtc/dtc-parser.tab.h_shipped
+@@ -1,19 +1,19 @@
+-/* A Bison parser, made by GNU Bison 2.5. */
++/* A Bison parser, made by GNU Bison 3.0.2. */
+
+ /* Bison interface for Yacc-like parsers in C
+-
+- Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
+-
++
++ Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
++
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. */
+
+@@ -26,50 +26,55 @@
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+-
++
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
++#ifndef YY_YY_DTC_PARSER_TAB_H_INCLUDED
++# define YY_YY_DTC_PARSER_TAB_H_INCLUDED
++/* Debug traces. */
++#ifndef YYDEBUG
++# define YYDEBUG 0
++#endif
++#if YYDEBUG
++extern int yydebug;
++#endif
+
+-/* Tokens. */
++/* Token type. */
+ #ifndef YYTOKENTYPE
+ # define YYTOKENTYPE
+- /* Put the tokens into the symbol table, so that GDB and other debuggers
+- know about them. */
+- enum yytokentype {
+- DT_V1 = 258,
+- DT_PLUGIN = 259,
+- DT_MEMRESERVE = 260,
+- DT_LSHIFT = 261,
+- DT_RSHIFT = 262,
+- DT_LE = 263,
+- DT_GE = 264,
+- DT_EQ = 265,
+- DT_NE = 266,
+- DT_AND = 267,
+- DT_OR = 268,
+- DT_BITS = 269,
+- DT_DEL_PROP = 270,
+- DT_DEL_NODE = 271,
+- DT_PROPNODENAME = 272,
+- DT_LITERAL = 273,
+- DT_CHAR_LITERAL = 274,
+- DT_BYTE = 275,
+- DT_STRING = 276,
+- DT_LABEL = 277,
+- DT_REF = 278,
+- DT_INCBIN = 279
+- };
++ enum yytokentype
++ {
++ DT_V1 = 258,
++ DT_MEMRESERVE = 259,
++ DT_LSHIFT = 260,
++ DT_RSHIFT = 261,
++ DT_LE = 262,
++ DT_GE = 263,
++ DT_EQ = 264,
++ DT_NE = 265,
++ DT_AND = 266,
++ DT_OR = 267,
++ DT_BITS = 268,
++ DT_DEL_PROP = 269,
++ DT_DEL_NODE = 270,
++ DT_PROPNODENAME = 271,
++ DT_LITERAL = 272,
++ DT_CHAR_LITERAL = 273,
++ DT_BYTE = 274,
++ DT_STRING = 275,
++ DT_LABEL = 276,
++ DT_REF = 277,
++ DT_INCBIN = 278
++ };
+ #endif
+
+-
+-
++/* Value type. */
+ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+-typedef union YYSTYPE
++typedef union YYSTYPE YYSTYPE;
++union YYSTYPE
+ {
+-
+-/* Line 2068 of yacc.c */
+-#line 39 "dtc-parser.y"
++#line 38 "dtc-parser.y" /* yacc.c:1909 */
+
+ char *propnodename;
+ char *labelref;
+@@ -87,32 +92,30 @@ typedef union YYSTYPE
+ struct node *nodelist;
+ struct reserve_info *re;
+ uint64_t integer;
+- int is_plugin;
+-
+-
+
+-/* Line 2068 of yacc.c */
+-#line 96 "dtc-parser.tab.h"
+-} YYSTYPE;
++#line 97 "dtc-parser.tab.h" /* yacc.c:1909 */
++};
+ # define YYSTYPE_IS_TRIVIAL 1
+-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+ # define YYSTYPE_IS_DECLARED 1
+ #endif
+
+-extern YYSTYPE yylval;
+-
++/* Location type. */
+ #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
+-typedef struct YYLTYPE
++typedef struct YYLTYPE YYLTYPE;
++struct YYLTYPE
+ {
+ int first_line;
+ int first_column;
+ int last_line;
+ int last_column;
+-} YYLTYPE;
+-# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
++};
+ # define YYLTYPE_IS_DECLARED 1
+ # define YYLTYPE_IS_TRIVIAL 1
+ #endif
+
++
++extern YYSTYPE yylval;
+ extern YYLTYPE yylloc;
++int yyparse (void);
+
++#endif /* !YY_YY_DTC_PARSER_TAB_H_INCLUDED */
+--- a/scripts/dtc/dtc-parser.y
++++ b/scripts/dtc/dtc-parser.y
+@@ -19,7 +19,6 @@
+ */
+ %{
+ #include <stdio.h>
+-#include <inttypes.h>
+
+ #include "dtc.h"
+ #include "srcpos.h"
+@@ -53,11 +52,9 @@ extern bool treesource_error;
+ struct node *nodelist;
+ struct reserve_info *re;
+ uint64_t integer;
+- int is_plugin;
+ }
+
+ %token DT_V1
+-%token DT_PLUGIN
+ %token DT_MEMRESERVE
+ %token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR
+ %token DT_BITS
+@@ -74,7 +71,6 @@ extern bool treesource_error;
+
+ %type <data> propdata
+ %type <data> propdataprefix
+-%type <is_plugin> plugindecl
+ %type <re> memreserve
+ %type <re> memreserves
+ %type <array> arrayprefix
+@@ -105,23 +101,10 @@ extern bool treesource_error;
+ %%
+
+ sourcefile:
+- DT_V1 ';' plugindecl memreserves devicetree
++ DT_V1 ';' memreserves devicetree
+ {
+- $5->is_plugin = $3;
+- $5->is_root = 1;
+- the_boot_info = build_boot_info($4, $5,
+- guess_boot_cpuid($5));
+- }
+- ;
+-
+-plugindecl:
+- /* empty */
+- {
+- $$ = 0;
+- }
+- | DT_PLUGIN ';'
+- {
+- $$ = 1;
++ the_boot_info = build_boot_info($3, $4,
++ guess_boot_cpuid($4));
+ }
+ ;
+
+--- a/scripts/dtc/dtc.c
++++ b/scripts/dtc/dtc.c
+@@ -29,7 +29,6 @@ int reservenum; /* Number of memory res
+ int minsize; /* Minimum blob size */
+ int padsize; /* Additional padding to blob */
+ int phandle_format = PHANDLE_BOTH; /* Use linux,phandle or phandle properties */
+-int symbol_fixup_support = 0;
+
+ static void fill_fullpaths(struct node *tree, const char *prefix)
+ {
+@@ -52,7 +51,7 @@ static void fill_fullpaths(struct node *
+ #define FDT_VERSION(version) _FDT_VERSION(version)
+ #define _FDT_VERSION(version) #version
+ static const char usage_synopsis[] = "dtc [options] <input file>";
+-static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:hv@";
++static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:hv";
+ static struct option const usage_long_opts[] = {
+ {"quiet", no_argument, NULL, 'q'},
+ {"in-format", a_argument, NULL, 'I'},
+@@ -70,7 +69,6 @@ static struct option const usage_long_op
+ {"phandle", a_argument, NULL, 'H'},
+ {"warning", a_argument, NULL, 'W'},
+ {"error", a_argument, NULL, 'E'},
+- {"symbols", a_argument, NULL, '@'},
+ {"help", no_argument, NULL, 'h'},
+ {"version", no_argument, NULL, 'v'},
+ {NULL, no_argument, NULL, 0x0},
+@@ -101,7 +99,6 @@ static const char * const usage_opts_hel
+ "\t\tboth - Both \"linux,phandle\" and \"phandle\" properties",
+ "\n\tEnable/disable warnings (prefix with \"no-\")",
+ "\n\tEnable/disable errors (prefix with \"no-\")",
+- "\n\tSymbols and Fixups support",
+ "\n\tPrint this help and exit",
+ "\n\tPrint version and exit",
+ NULL,
+@@ -189,9 +186,7 @@ int main(int argc, char *argv[])
+ case 'E':
+ parse_checks_option(false, true, optarg);
+ break;
+- case '@':
+- symbol_fixup_support = 1;
+- break;
++
+ case 'h':
+ usage(NULL);
+ default:
+--- a/scripts/dtc/dtc.h
++++ b/scripts/dtc/dtc.h
+@@ -54,7 +54,6 @@ extern int reservenum; /* Number of mem
+ extern int minsize; /* Minimum blob size */
+ extern int padsize; /* Additional padding to blob */
+ extern int phandle_format; /* Use linux,phandle or phandle properties */
+-extern int symbol_fixup_support;/* enable symbols & fixup support */
+
+ #define PHANDLE_LEGACY 0x1
+ #define PHANDLE_EPAPR 0x2
+@@ -133,25 +132,6 @@ struct label {
+ struct label *next;
+ };
+
+-struct fixup_entry {
+- int offset;
+- struct node *node;
+- struct property *prop;
+- struct fixup_entry *next;
+-};
+-
+-struct fixup {
+- char *ref;
+- struct fixup_entry *entries;
+- struct fixup *next;
+-};
+-
+-struct symbol {
+- struct label *label;
+- struct node *node;
+- struct symbol *next;
+-};
+-
+ struct property {
+ bool deleted;
+ char *name;
+@@ -178,12 +158,6 @@ struct node {
+ int addr_cells, size_cells;
+
+ struct label *labels;
+-
+- int is_root;
+- int is_plugin;
+- struct fixup *fixups;
+- struct symbol *symbols;
+- struct fixup_entry *local_fixups;
+ };
+
+ #define for_each_label_withdel(l0, l) \
+@@ -207,18 +181,6 @@ struct node {
+ for_each_child_withdel(n, c) \
+ if (!(c)->deleted)
+
+-#define for_each_fixup(n, f) \
+- for ((f) = (n)->fixups; (f); (f) = (f)->next)
+-
+-#define for_each_fixup_entry(f, fe) \
+- for ((fe) = (f)->entries; (fe); (fe) = (fe)->next)
+-
+-#define for_each_symbol(n, s) \
+- for ((s) = (n)->symbols; (s); (s) = (s)->next)
+-
+-#define for_each_local_fixup_entry(n, fe) \
+- for ((fe) = (n)->local_fixups; (fe); (fe) = (fe)->next)
+-
+ void add_label(struct label **labels, char *label);
+ void delete_labels(struct label **labels);
+
+--- a/scripts/dtc/flattree.c
++++ b/scripts/dtc/flattree.c
+@@ -262,12 +262,6 @@ static void flatten_tree(struct node *tr
+ struct property *prop;
+ struct node *child;
+ bool seen_name_prop = false;
+- struct symbol *sym;
+- struct fixup *f;
+- struct fixup_entry *fe;
+- char *name, *s;
+- const char *fullpath;
+- int namesz, nameoff, vallen;
+
+ if (tree->deleted)
+ return;
+@@ -282,6 +276,8 @@ static void flatten_tree(struct node *tr
+ emit->align(etarget, sizeof(cell_t));
+
+ for_each_property(tree, prop) {
++ int nameoff;
++
+ if (streq(prop->name, "name"))
+ seen_name_prop = true;
+
+@@ -314,139 +310,6 @@ static void flatten_tree(struct node *tr
+ flatten_tree(child, emit, etarget, strbuf, vi);
+ }
+
+- if (!symbol_fixup_support)
+- goto no_symbols;
+-
+- /* add the symbol nodes (if any) */
+- if (tree->symbols) {
+-
+- emit->beginnode(etarget, NULL);
+- emit->string(etarget, "__symbols__", 0);
+- emit->align(etarget, sizeof(cell_t));
+-
+- for_each_symbol(tree, sym) {
+-
+- vallen = strlen(sym->node->fullpath);
+-
+- nameoff = stringtable_insert(strbuf, sym->label->label);
+-
+- emit->property(etarget, NULL);
+- emit->cell(etarget, vallen + 1);
+- emit->cell(etarget, nameoff);
+-
+- if ((vi->flags & FTF_VARALIGN) && vallen >= 8)
+- emit->align(etarget, 8);
+-
+- emit->string(etarget, sym->node->fullpath,
+- strlen(sym->node->fullpath));
+- emit->align(etarget, sizeof(cell_t));
+- }
+-
+- emit->endnode(etarget, NULL);
+- }
+-
+- /* add the fixup nodes */
+- if (tree->fixups) {
+-
+- /* emit the external fixups */
+- emit->beginnode(etarget, NULL);
+- emit->string(etarget, "__fixups__", 0);
+- emit->align(etarget, sizeof(cell_t));
+-
+- for_each_fixup(tree, f) {
+-
+- namesz = 0;
+- for_each_fixup_entry(f, fe) {
+- fullpath = fe->node->fullpath;
+- if (fullpath[0] == '\0')
+- fullpath = "/";
+- namesz += strlen(fullpath) + 1;
+- namesz += strlen(fe->prop->name) + 1;
+- namesz += 32; /* space for :<number> + '\0' */
+- }
+-
+- name = xmalloc(namesz);
+-
+- s = name;
+- for_each_fixup_entry(f, fe) {
+- fullpath = fe->node->fullpath;
+- if (fullpath[0] == '\0')
+- fullpath = "/";
+- snprintf(s, name + namesz - s, "%s:%s:%d",
+- fullpath,
+- fe->prop->name, fe->offset);
+- s += strlen(s) + 1;
+- }
+-
+- nameoff = stringtable_insert(strbuf, f->ref);
+- vallen = s - name - 1;
+-
+- emit->property(etarget, NULL);
+- emit->cell(etarget, vallen + 1);
+- emit->cell(etarget, nameoff);
+-
+- if ((vi->flags & FTF_VARALIGN) && vallen >= 8)
+- emit->align(etarget, 8);
+-
+- emit->string(etarget, name, vallen);
+- emit->align(etarget, sizeof(cell_t));
+-
+- free(name);
+- }
+-
+- emit->endnode(etarget, tree->labels);
+- }
+-
+- /* add the local fixup property */
+- if (tree->local_fixups) {
+-
+- /* emit the external fixups */
+- emit->beginnode(etarget, NULL);
+- emit->string(etarget, "__local_fixups__", 0);
+- emit->align(etarget, sizeof(cell_t));
+-
+- namesz = 0;
+- for_each_local_fixup_entry(tree, fe) {
+- fullpath = fe->node->fullpath;
+- if (fullpath[0] == '\0')
+- fullpath = "/";
+- namesz += strlen(fullpath) + 1;
+- namesz += strlen(fe->prop->name) + 1;
+- namesz += 32; /* space for :<number> + '\0' */
+- }
+-
+- name = xmalloc(namesz);
+-
+- s = name;
+- for_each_local_fixup_entry(tree, fe) {
+- fullpath = fe->node->fullpath;
+- if (fullpath[0] == '\0')
+- fullpath = "/";
+- snprintf(s, name + namesz - s, "%s:%s:%d",
+- fullpath, fe->prop->name,
+- fe->offset);
+- s += strlen(s) + 1;
+- }
+-
+- nameoff = stringtable_insert(strbuf, "fixup");
+- vallen = s - name - 1;
+-
+- emit->property(etarget, NULL);
+- emit->cell(etarget, vallen + 1);
+- emit->cell(etarget, nameoff);
+-
+- if ((vi->flags & FTF_VARALIGN) && vallen >= 8)
+- emit->align(etarget, 8);
+-
+- emit->string(etarget, name, vallen);
+- emit->align(etarget, sizeof(cell_t));
+-
+- free(name);
+-
+- emit->endnode(etarget, tree->labels);
+- }
+-
+-no_symbols:
+ emit->endnode(etarget, tree->labels);
+ }
+
+--- a/scripts/dtc/version_gen.h
++++ b/scripts/dtc/version_gen.h
+@@ -1 +1 @@
+-#define DTC_VERSION "DTC 1.4.1-g9d3649bd-dirty"
++#define DTC_VERSION "DTC 1.4.1-g9d3649bd"
diff --git a/target/linux/brcm2708/patches-4.4/0175-bcm2835-sdhost-Only-claim-one-DMA-channel.patch b/target/linux/brcm2708/patches-4.4/0175-bcm2835-sdhost-Only-claim-one-DMA-channel.patch
deleted file mode 100644
index fb68bcb5f8..0000000000
--- a/target/linux/brcm2708/patches-4.4/0175-bcm2835-sdhost-Only-claim-one-DMA-channel.patch
+++ /dev/null
@@ -1,160 +0,0 @@
-From 06c169985c0884ce67377c79d27383e23f41e2cd Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Mon, 7 Mar 2016 16:46:39 +0000
-Subject: [PATCH 175/180] bcm2835-sdhost: Only claim one DMA channel
-
-With both MMC controllers enabled there are few DMA channels left. The
-bcm2835-sdhost driver only uses DMA in one direction at a time, so it
-doesn't need to claim two channels.
-
-See: https://github.com/raspberrypi/linux/issues/1327
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- arch/arm/boot/dts/bcm2708_common.dtsi | 5 +--
- drivers/mmc/host/bcm2835-sdhost.c | 70 ++++++++++++++++++++++++-----------
- 2 files changed, 50 insertions(+), 25 deletions(-)
-
---- a/arch/arm/boot/dts/bcm2708_common.dtsi
-+++ b/arch/arm/boot/dts/bcm2708_common.dtsi
-@@ -136,9 +136,8 @@
- reg = <0x7e202000 0x100>;
- interrupts = <2 24>;
- clocks = <&clk_core>;
-- dmas = <&dma 13>,
-- <&dma 13>;
-- dma-names = "tx", "rx";
-+ dmas = <&dma 13>;
-+ dma-names = "rx-tx";
- brcm,overclock-50 = <0>;
- brcm,pio-limit = <1>;
- status = "disabled";
---- a/drivers/mmc/host/bcm2835-sdhost.c
-+++ b/drivers/mmc/host/bcm2835-sdhost.c
-@@ -185,9 +185,10 @@ struct bcm2835_host {
- unsigned int debug:1; /* Enable debug output */
-
- /*DMA part*/
-- struct dma_chan *dma_chan_rx; /* DMA channel for reads */
-- struct dma_chan *dma_chan_tx; /* DMA channel for writes */
-- struct dma_chan *dma_chan; /* Channel in used */
-+ struct dma_chan *dma_chan_rxtx; /* DMA channel for reads and writes */
-+ struct dma_chan *dma_chan; /* Channel in use */
-+ struct dma_slave_config dma_cfg_rx;
-+ struct dma_slave_config dma_cfg_tx;
- struct dma_async_tx_descriptor *dma_desc;
- u32 dma_dir;
- u32 drain_words;
-@@ -771,12 +772,11 @@ static void bcm2835_sdhost_prepare_dma(s
- log_event("PRD<", (u32)data, 0);
- pr_debug("bcm2835_sdhost_prepare_dma()\n");
-
-+ dma_chan = host->dma_chan_rxtx;
- if (data->flags & MMC_DATA_READ) {
-- dma_chan = host->dma_chan_rx;
- dir_data = DMA_FROM_DEVICE;
- dir_slave = DMA_DEV_TO_MEM;
- } else {
-- dma_chan = host->dma_chan_tx;
- dir_data = DMA_TO_DEVICE;
- dir_slave = DMA_MEM_TO_DEV;
- }
-@@ -813,6 +813,12 @@ static void bcm2835_sdhost_prepare_dma(s
- host->drain_words = len/4;
- }
-
-+ /* The parameters have already been validated, so this will not fail */
-+ (void)dmaengine_slave_config(dma_chan,
-+ (dir_data == DMA_FROM_DEVICE) ?
-+ &host->dma_cfg_rx :
-+ &host->dma_cfg_tx);
-+
- len = dma_map_sg(dma_chan->device->dev, data->sg, data->sg_len,
- dir_data);
-
-@@ -1805,28 +1811,46 @@ int bcm2835_sdhost_add_host(struct bcm28
- spin_lock_init(&host->lock);
-
- if (host->allow_dma) {
-- if (IS_ERR_OR_NULL(host->dma_chan_tx) ||
-- IS_ERR_OR_NULL(host->dma_chan_rx)) {
-- pr_err("%s: unable to initialise DMA channels. "
-+ if (IS_ERR_OR_NULL(host->dma_chan_rxtx)) {
-+ pr_err("%s: unable to initialise DMA channel. "
- "Falling back to PIO\n",
- mmc_hostname(mmc));
- host->use_dma = false;
- } else {
-- host->use_dma = true;
--
- cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- cfg.slave_id = 13; /* DREQ channel */
-
-+ /* Validate the slave configurations */
-+
- cfg.direction = DMA_MEM_TO_DEV;
- cfg.src_addr = 0;
- cfg.dst_addr = host->bus_addr + SDDATA;
-- ret = dmaengine_slave_config(host->dma_chan_tx, &cfg);
-
-- cfg.direction = DMA_DEV_TO_MEM;
-- cfg.src_addr = host->bus_addr + SDDATA;
-- cfg.dst_addr = 0;
-- ret = dmaengine_slave_config(host->dma_chan_rx, &cfg);
-+ ret = dmaengine_slave_config(host->dma_chan_rxtx, &cfg);
-+
-+ if (ret == 0) {
-+ host->dma_cfg_tx = cfg;
-+
-+ cfg.direction = DMA_DEV_TO_MEM;
-+ cfg.src_addr = host->bus_addr + SDDATA;
-+ cfg.dst_addr = 0;
-+
-+ ret = dmaengine_slave_config(host->dma_chan_rxtx, &cfg);
-+ }
-+
-+ if (ret == 0) {
-+ host->dma_cfg_rx = cfg;
-+
-+ host->use_dma = true;
-+ } else {
-+ pr_err("%s: unable to configure DMA channel. "
-+ "Falling back to PIO\n",
-+ mmc_hostname(mmc));
-+ dma_release_channel(host->dma_chan_rxtx);
-+ host->dma_chan_rxtx = NULL;
-+ host->use_dma = false;
-+ }
- }
- } else {
- host->use_dma = false;
-@@ -1948,19 +1972,21 @@ static int bcm2835_sdhost_probe(struct p
-
- if (host->allow_dma) {
- if (node) {
-- host->dma_chan_tx =
-- dma_request_slave_channel(dev, "tx");
-- host->dma_chan_rx =
-- dma_request_slave_channel(dev, "rx");
-+ host->dma_chan_rxtx =
-+ dma_request_slave_channel(dev, "rx-tx");
-+ if (!host->dma_chan_rxtx)
-+ host->dma_chan_rxtx =
-+ dma_request_slave_channel(dev, "tx");
-+ if (!host->dma_chan_rxtx)
-+ host->dma_chan_rxtx =
-+ dma_request_slave_channel(dev, "rx");
- } else {
- dma_cap_mask_t mask;
-
- dma_cap_zero(mask);
- /* we don't care about the channel, any would work */
- dma_cap_set(DMA_SLAVE, mask);
-- host->dma_chan_tx =
-- dma_request_channel(mask, NULL, NULL);
-- host->dma_chan_rx =
-+ host->dma_chan_rxtx =
- dma_request_channel(mask, NULL, NULL);
- }
- }
diff --git a/target/linux/brcm2708/patches-4.4/0176-bcm2835-mmc-Only-claim-one-DMA-channel.patch b/target/linux/brcm2708/patches-4.4/0176-bcm2835-mmc-Only-claim-one-DMA-channel.patch
deleted file mode 100644
index 8f224faf88..0000000000
--- a/target/linux/brcm2708/patches-4.4/0176-bcm2835-mmc-Only-claim-one-DMA-channel.patch
+++ /dev/null
@@ -1,170 +0,0 @@
-From af80d75abc7604cd9eb1788b0171148d000db09d Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Tue, 8 Mar 2016 09:49:16 +0000
-Subject: [PATCH 176/180] bcm2835-mmc: Only claim one DMA channel
-
-With both MMC controllers enabled there are few DMA channels left. The
-bcm2835-mmc driver only uses DMA in one direction at a time, so it
-doesn't need to claim two channels.
-
-See: https://github.com/raspberrypi/linux/issues/1327
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- arch/arm/boot/dts/bcm2708_common.dtsi | 5 +--
- drivers/mmc/host/bcm2835-mmc.c | 69 +++++++++++++++++++++++++----------
- 2 files changed, 51 insertions(+), 23 deletions(-)
-
---- a/arch/arm/boot/dts/bcm2708_common.dtsi
-+++ b/arch/arm/boot/dts/bcm2708_common.dtsi
-@@ -232,9 +232,8 @@
- reg = <0x7e300000 0x100>;
- interrupts = <2 30>;
- clocks = <&clk_mmc>;
-- dmas = <&dma 11>,
-- <&dma 11>;
-- dma-names = "tx", "rx";
-+ dmas = <&dma 11>;
-+ dma-names = "rx-tx";
- brcm,overclock-50 = <0>;
- status = "disabled";
- };
---- a/drivers/mmc/host/bcm2835-mmc.c
-+++ b/drivers/mmc/host/bcm2835-mmc.c
-@@ -108,8 +108,9 @@ struct bcm2835_host {
- u32 shadow;
-
- /*DMA part*/
-- struct dma_chan *dma_chan_rx; /* DMA channel for reads */
-- struct dma_chan *dma_chan_tx; /* DMA channel for writes */
-+ struct dma_chan *dma_chan_rxtx; /* DMA channel for reads and writes */
-+ struct dma_slave_config dma_cfg_rx;
-+ struct dma_slave_config dma_cfg_tx;
- struct dma_async_tx_descriptor *tx_desc; /* descriptor */
-
- bool have_dma;
-@@ -342,7 +343,7 @@ static void bcm2835_mmc_dma_complete(voi
-
- if (host->data && !(host->data->flags & MMC_DATA_WRITE)) {
- /* otherwise handled in SDHCI IRQ */
-- dma_chan = host->dma_chan_rx;
-+ dma_chan = host->dma_chan_rxtx;
- dir_data = DMA_FROM_DEVICE;
-
- dma_unmap_sg(dma_chan->device->dev,
-@@ -493,16 +494,21 @@ static void bcm2835_mmc_transfer_dma(str
- if (host->blocks == 0)
- return;
-
-+ dma_chan = host->dma_chan_rxtx;
- if (host->data->flags & MMC_DATA_READ) {
-- dma_chan = host->dma_chan_rx;
- dir_data = DMA_FROM_DEVICE;
- dir_slave = DMA_DEV_TO_MEM;
- } else {
-- dma_chan = host->dma_chan_tx;
- dir_data = DMA_TO_DEVICE;
- dir_slave = DMA_MEM_TO_DEV;
- }
-
-+ /* The parameters have already been validated, so this will not fail */
-+ (void)dmaengine_slave_config(dma_chan,
-+ (dir_data == DMA_FROM_DEVICE) ?
-+ &host->dma_cfg_rx :
-+ &host->dma_cfg_tx);
-+
- BUG_ON(!dma_chan->device);
- BUG_ON(!dma_chan->device->dev);
- BUG_ON(!host->data->sg);
-@@ -936,7 +942,7 @@ static void bcm2835_mmc_data_irq(struct
- if (host->data->flags & MMC_DATA_WRITE) {
- /* IRQ handled here */
-
-- dma_chan = host->dma_chan_tx;
-+ dma_chan = host->dma_chan_rxtx;
- dir_data = DMA_TO_DEVICE;
- dma_unmap_sg(dma_chan->device->dev,
- host->data->sg, host->data->sg_len,
-@@ -1316,28 +1322,47 @@ static int bcm2835_mmc_add_host(struct b
- dev_info(dev, "Forcing PIO mode\n");
- host->have_dma = false;
- #else
-- if (IS_ERR_OR_NULL(host->dma_chan_tx) ||
-- IS_ERR_OR_NULL(host->dma_chan_rx)) {
-- dev_err(dev, "%s: Unable to initialise DMA channels. Falling back to PIO\n",
-+ if (IS_ERR_OR_NULL(host->dma_chan_rxtx)) {
-+ dev_err(dev, "%s: Unable to initialise DMA channel. Falling back to PIO\n",
- DRIVER_NAME);
- host->have_dma = false;
- } else {
-- dev_info(dev, "DMA channels allocated");
-- host->have_dma = true;
-+ dev_info(dev, "DMA channel allocated");
-
- cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- cfg.slave_id = 11; /* DREQ channel */
-
-+ /* Validate the slave configurations */
-+
- cfg.direction = DMA_MEM_TO_DEV;
- cfg.src_addr = 0;
- cfg.dst_addr = host->bus_addr + SDHCI_BUFFER;
-- ret = dmaengine_slave_config(host->dma_chan_tx, &cfg);
-
-- cfg.direction = DMA_DEV_TO_MEM;
-- cfg.src_addr = host->bus_addr + SDHCI_BUFFER;
-- cfg.dst_addr = 0;
-- ret = dmaengine_slave_config(host->dma_chan_rx, &cfg);
-+ ret = dmaengine_slave_config(host->dma_chan_rxtx, &cfg);
-+
-+ if (ret == 0) {
-+ host->dma_cfg_tx = cfg;
-+
-+ cfg.direction = DMA_DEV_TO_MEM;
-+ cfg.src_addr = host->bus_addr + SDHCI_BUFFER;
-+ cfg.dst_addr = 0;
-+
-+ ret = dmaengine_slave_config(host->dma_chan_rxtx, &cfg);
-+ }
-+
-+ if (ret == 0) {
-+ host->dma_cfg_rx = cfg;
-+
-+ host->use_dma = true;
-+ } else {
-+ pr_err("%s: unable to configure DMA channel. "
-+ "Faling back to PIO\n",
-+ mmc_hostname(mmc));
-+ dma_release_channel(host->dma_chan_rxtx);
-+ host->dma_chan_rxtx = NULL;
-+ host->use_dma = false;
-+ }
- }
- #endif
- mmc->max_segs = 128;
-@@ -1416,16 +1441,20 @@ static int bcm2835_mmc_probe(struct plat
-
- #ifndef FORCE_PIO
- if (node) {
-- host->dma_chan_tx = dma_request_slave_channel(dev, "tx");
-- host->dma_chan_rx = dma_request_slave_channel(dev, "rx");
-+ host->dma_chan_rxtx = dma_request_slave_channel(dev, "rx-tx");
-+ if (!host->dma_chan_rxtx)
-+ host->dma_chan_rxtx =
-+ dma_request_slave_channel(dev, "tx");
-+ if (!host->dma_chan_rxtx)
-+ host->dma_chan_rxtx =
-+ dma_request_slave_channel(dev, "rx");
- } else {
- dma_cap_mask_t mask;
-
- dma_cap_zero(mask);
- /* we don't care about the channel, any would work */
- dma_cap_set(DMA_SLAVE, mask);
-- host->dma_chan_tx = dma_request_channel(mask, NULL, NULL);
-- host->dma_chan_rx = dma_request_channel(mask, NULL, NULL);
-+ host->dma_chan_rxtx = dma_request_channel(mask, NULL, NULL);
- }
- #endif
- clk = devm_clk_get(dev, NULL);
diff --git a/target/linux/brcm2708/patches-4.4/0176-scripts-dtc-Update-to-upstream-version-1.4.1.patch b/target/linux/brcm2708/patches-4.4/0176-scripts-dtc-Update-to-upstream-version-1.4.1.patch
new file mode 100644
index 0000000000..3a8b835f4f
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0176-scripts-dtc-Update-to-upstream-version-1.4.1.patch
@@ -0,0 +1,2736 @@
+From 646dd14af89c2379b160d81fc54cca4d97b36416 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 10 Aug 2015 09:49:15 +0100
+Subject: [PATCH 176/381] scripts/dtc: Update to upstream version 1.4.1
+
+Includes the new localfixups format.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ scripts/dtc/checks.c | 105 ++++-
+ scripts/dtc/dtc-lexer.l | 5 +
+ scripts/dtc/dtc-lexer.lex.c_shipped | 490 ++++++++++++------------
+ scripts/dtc/dtc-parser.tab.c_shipped | 722 ++++++++++++++++++-----------------
+ scripts/dtc/dtc-parser.tab.h_shipped | 46 +--
+ scripts/dtc/dtc-parser.y | 22 +-
+ scripts/dtc/dtc.c | 9 +-
+ scripts/dtc/dtc.h | 40 ++
+ scripts/dtc/flattree.c | 202 ++++++++++
+ scripts/dtc/version_gen.h | 2 +-
+ 10 files changed, 1021 insertions(+), 622 deletions(-)
+
+--- a/scripts/dtc/checks.c
++++ b/scripts/dtc/checks.c
+@@ -458,6 +458,8 @@ static void fixup_phandle_references(str
+ struct node *node, struct property *prop)
+ {
+ struct marker *m = prop->val.markers;
++ struct fixup *f, **fp;
++ struct fixup_entry *fe, **fep;
+ struct node *refnode;
+ cell_t phandle;
+
+@@ -466,11 +468,69 @@ static void fixup_phandle_references(str
+
+ refnode = get_node_by_ref(dt, m->ref);
+ if (! refnode) {
+- FAIL(c, "Reference to non-existent node or label \"%s\"\n",
+- m->ref);
++ if (!dt->is_plugin) {
++ FAIL(c, "Reference to non-existent node or label \"%s\"\n",
++ m->ref);
++ continue;
++ }
++
++ /* allocate fixup entry */
++ fe = xmalloc(sizeof(*fe));
++
++ fe->node = node;
++ fe->prop = prop;
++ fe->offset = m->offset;
++ fe->next = NULL;
++
++ /* search for an already existing fixup */
++ for_each_fixup(dt, f)
++ if (strcmp(f->ref, m->ref) == 0)
++ break;
++
++ /* no fixup found, add new */
++ if (f == NULL) {
++ f = xmalloc(sizeof(*f));
++ f->ref = m->ref;
++ f->entries = NULL;
++ f->next = NULL;
++
++ /* add it to the tree */
++ fp = &dt->fixups;
++ while (*fp)
++ fp = &(*fp)->next;
++ *fp = f;
++ }
++
++ /* and now append fixup entry */
++ fep = &f->entries;
++ while (*fep)
++ fep = &(*fep)->next;
++ *fep = fe;
++
++ /* mark the entry as unresolved */
++ *((cell_t *)(prop->val.val + m->offset)) =
++ cpu_to_fdt32(0xdeadbeef);
+ continue;
+ }
+
++ /* if it's a local reference, we need to record it */
++ if (symbol_fixup_support) {
++
++ /* allocate a new local fixup entry */
++ fe = xmalloc(sizeof(*fe));
++
++ fe->node = node;
++ fe->prop = prop;
++ fe->offset = m->offset;
++ fe->next = NULL;
++
++ /* append it to the local fixups */
++ fep = &dt->local_fixups;
++ while (*fep)
++ fep = &(*fep)->next;
++ *fep = fe;
++ }
++
+ phandle = get_node_phandle(dt, refnode);
+ *((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
+ }
+@@ -652,6 +712,45 @@ static void check_obsolete_chosen_interr
+ }
+ TREE_WARNING(obsolete_chosen_interrupt_controller, NULL);
+
++static void check_auto_label_phandles(struct check *c, struct node *dt,
++ struct node *node)
++{
++ struct label *l;
++ struct symbol *s, **sp;
++ int has_label;
++
++ if (!symbol_fixup_support)
++ return;
++
++ has_label = 0;
++ for_each_label(node->labels, l) {
++ has_label = 1;
++ break;
++ }
++
++ if (!has_label)
++ return;
++
++ /* force allocation of a phandle for this node */
++ (void)get_node_phandle(dt, node);
++
++ /* add the symbol */
++ for_each_label(node->labels, l) {
++
++ s = xmalloc(sizeof(*s));
++ s->label = l;
++ s->node = node;
++ s->next = NULL;
++
++ /* add it to the symbols list */
++ sp = &dt->symbols;
++ while (*sp)
++ sp = &((*sp)->next);
++ *sp = s;
++ }
++}
++NODE_WARNING(auto_label_phandles, NULL);
++
+ static struct check *check_table[] = {
+ &duplicate_node_names, &duplicate_property_names,
+ &node_name_chars, &node_name_format, &property_name_chars,
+@@ -670,6 +769,8 @@ static struct check *check_table[] = {
+ &avoid_default_addr_size,
+ &obsolete_chosen_interrupt_controller,
+
++ &auto_label_phandles,
++
+ &always_fail,
+ };
+
+--- a/scripts/dtc/dtc-lexer.l
++++ b/scripts/dtc/dtc-lexer.l
+@@ -113,6 +113,11 @@ static void lexical_error(const char *fm
+ return DT_V1;
+ }
+
++<*>"/plugin/" {
++ DPRINT("Keyword: /plugin/\n");
++ return DT_PLUGIN;
++ }
++
+ <*>"/memreserve/" {
+ DPRINT("Keyword: /memreserve/\n");
+ BEGIN_DEFAULT();
+--- a/scripts/dtc/dtc-lexer.lex.c_shipped
++++ b/scripts/dtc/dtc-lexer.lex.c_shipped
+@@ -9,7 +9,7 @@
+ #define FLEX_SCANNER
+ #define YY_FLEX_MAJOR_VERSION 2
+ #define YY_FLEX_MINOR_VERSION 5
+-#define YY_FLEX_SUBMINOR_VERSION 39
++#define YY_FLEX_SUBMINOR_VERSION 35
+ #if YY_FLEX_SUBMINOR_VERSION > 0
+ #define FLEX_BETA
+ #endif
+@@ -162,12 +162,7 @@ typedef unsigned int flex_uint32_t;
+ typedef struct yy_buffer_state *YY_BUFFER_STATE;
+ #endif
+
+-#ifndef YY_TYPEDEF_YY_SIZE_T
+-#define YY_TYPEDEF_YY_SIZE_T
+-typedef size_t yy_size_t;
+-#endif
+-
+-extern yy_size_t yyleng;
++extern int yyleng;
+
+ extern FILE *yyin, *yyout;
+
+@@ -176,7 +171,6 @@ extern FILE *yyin, *yyout;
+ #define EOB_ACT_LAST_MATCH 2
+
+ #define YY_LESS_LINENO(n)
+- #define YY_LINENO_REWIND_TO(ptr)
+
+ /* Return all but the first "n" matched characters back to the input stream. */
+ #define yyless(n) \
+@@ -194,6 +188,11 @@ extern FILE *yyin, *yyout;
+
+ #define unput(c) yyunput( c, (yytext_ptr) )
+
++#ifndef YY_TYPEDEF_YY_SIZE_T
++#define YY_TYPEDEF_YY_SIZE_T
++typedef size_t yy_size_t;
++#endif
++
+ #ifndef YY_STRUCT_YY_BUFFER_STATE
+ #define YY_STRUCT_YY_BUFFER_STATE
+ struct yy_buffer_state
+@@ -211,7 +210,7 @@ struct yy_buffer_state
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+- yy_size_t yy_n_chars;
++ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+@@ -281,8 +280,8 @@ static YY_BUFFER_STATE * yy_buffer_stack
+
+ /* yy_hold_char holds the character lost when yytext is formed. */
+ static char yy_hold_char;
+-static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */
+-yy_size_t yyleng;
++static int yy_n_chars; /* number of characters read into yy_ch_buf */
++int yyleng;
+
+ /* Points to current character in buffer. */
+ static char *yy_c_buf_p = (char *) 0;
+@@ -310,7 +309,7 @@ static void yy_init_buffer (YY_BUFFER_ST
+
+ YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size );
+ YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str );
+-YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len );
++YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len );
+
+ void *yyalloc (yy_size_t );
+ void *yyrealloc (void *,yy_size_t );
+@@ -342,7 +341,7 @@ void yyfree (void * );
+
+ /* Begin user sect3 */
+
+-#define yywrap() 1
++#define yywrap(n) 1
+ #define YY_SKIP_YYWRAP
+
+ typedef unsigned char YY_CHAR;
+@@ -373,8 +372,8 @@ static void yy_fatal_error (yyconst char
+ *yy_cp = '\0'; \
+ (yy_c_buf_p) = yy_cp;
+
+-#define YY_NUM_RULES 30
+-#define YY_END_OF_BUFFER 31
++#define YY_NUM_RULES 31
++#define YY_END_OF_BUFFER 32
+ /* This struct is not used in this scanner,
+ but its presence is necessary. */
+ struct yy_trans_info
+@@ -382,25 +381,26 @@ struct yy_trans_info
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+-static yyconst flex_int16_t yy_accept[159] =
++static yyconst flex_int16_t yy_accept[166] =
+ { 0,
+- 0, 0, 0, 0, 0, 0, 0, 0, 31, 29,
+- 18, 18, 29, 29, 29, 29, 29, 29, 29, 29,
+- 29, 29, 29, 29, 29, 29, 15, 16, 16, 29,
+- 16, 10, 10, 18, 26, 0, 3, 0, 27, 12,
+- 0, 0, 11, 0, 0, 0, 0, 0, 0, 0,
+- 21, 23, 25, 24, 22, 0, 9, 28, 0, 0,
+- 0, 14, 14, 16, 16, 16, 10, 10, 10, 0,
+- 12, 0, 11, 0, 0, 0, 20, 0, 0, 0,
+- 0, 0, 0, 0, 0, 16, 10, 10, 10, 0,
+- 13, 19, 0, 0, 0, 0, 0, 0, 0, 0,
+-
+- 0, 16, 0, 0, 0, 0, 0, 0, 0, 0,
+- 0, 16, 6, 0, 0, 0, 0, 0, 0, 2,
+- 0, 0, 0, 0, 0, 0, 0, 0, 4, 17,
+- 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
+- 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+- 5, 8, 0, 0, 0, 0, 7, 0
++ 0, 0, 0, 0, 0, 0, 0, 0, 32, 30,
++ 19, 19, 30, 30, 30, 30, 30, 30, 30, 30,
++ 30, 30, 30, 30, 30, 30, 16, 17, 17, 30,
++ 17, 11, 11, 19, 27, 0, 3, 0, 28, 13,
++ 0, 0, 12, 0, 0, 0, 0, 0, 0, 0,
++ 0, 22, 24, 26, 25, 23, 0, 10, 29, 0,
++ 0, 0, 15, 15, 17, 17, 17, 11, 11, 11,
++ 0, 13, 0, 12, 0, 0, 0, 21, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 17, 11, 11,
++ 11, 0, 14, 20, 0, 0, 0, 0, 0, 0,
++
++ 0, 0, 0, 0, 17, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 17, 7, 0, 0, 0,
++ 0, 0, 0, 0, 2, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 4, 18, 0, 0, 5, 2,
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 1, 0, 0, 0, 0, 6, 9, 0,
++ 0, 0, 0, 8, 0
+ } ;
+
+ static yyconst flex_int32_t yy_ec[256] =
+@@ -416,9 +416,9 @@ static yyconst flex_int32_t yy_ec[256] =
+ 22, 22, 22, 22, 24, 22, 22, 25, 22, 22,
+ 1, 26, 27, 1, 22, 1, 21, 28, 29, 30,
+
+- 31, 21, 22, 22, 32, 22, 22, 33, 34, 35,
+- 36, 37, 22, 38, 39, 40, 41, 42, 22, 25,
+- 43, 22, 44, 45, 46, 1, 1, 1, 1, 1,
++ 31, 21, 32, 22, 33, 22, 22, 34, 35, 36,
++ 37, 38, 22, 39, 40, 41, 42, 43, 22, 25,
++ 44, 22, 45, 46, 47, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+@@ -435,163 +435,165 @@ static yyconst flex_int32_t yy_ec[256] =
+ 1, 1, 1, 1, 1
+ } ;
+
+-static yyconst flex_int32_t yy_meta[47] =
++static yyconst flex_int32_t yy_meta[48] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 2, 3, 1, 2,
+ 2, 2, 4, 5, 5, 5, 6, 1, 1, 1,
+ 7, 8, 8, 8, 8, 1, 1, 7, 7, 7,
+ 7, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+- 8, 8, 8, 3, 1, 4
++ 8, 8, 8, 8, 3, 1, 4
+ } ;
+
+-static yyconst flex_int16_t yy_base[173] =
++static yyconst flex_int16_t yy_base[180] =
+ { 0,
+- 0, 383, 34, 382, 65, 381, 37, 105, 387, 391,
+- 54, 111, 367, 110, 109, 109, 112, 41, 366, 104,
+- 367, 338, 124, 117, 0, 144, 391, 0, 121, 0,
+- 135, 155, 140, 179, 391, 160, 391, 379, 391, 0,
+- 368, 141, 391, 167, 370, 376, 346, 103, 342, 345,
+- 391, 391, 391, 391, 391, 358, 391, 391, 175, 342,
+- 338, 391, 355, 0, 185, 339, 184, 347, 346, 0,
+- 0, 322, 175, 357, 175, 363, 352, 324, 330, 323,
+- 332, 326, 201, 324, 329, 322, 391, 333, 181, 309,
+- 391, 341, 340, 313, 320, 338, 178, 311, 146, 317,
+-
+- 314, 315, 335, 331, 303, 300, 309, 299, 308, 188,
+- 336, 335, 391, 305, 320, 281, 283, 271, 203, 288,
+- 281, 271, 266, 264, 245, 242, 208, 104, 391, 391,
+- 244, 218, 204, 219, 206, 224, 201, 212, 204, 229,
+- 215, 208, 207, 200, 219, 391, 233, 221, 200, 181,
+- 391, 391, 149, 122, 86, 41, 391, 391, 245, 251,
+- 259, 263, 267, 273, 280, 284, 292, 300, 304, 310,
+- 318, 326
++ 0, 393, 35, 392, 66, 391, 38, 107, 397, 401,
++ 55, 113, 377, 112, 111, 111, 114, 42, 376, 106,
++ 377, 347, 126, 120, 0, 147, 401, 0, 124, 0,
++ 137, 158, 170, 163, 401, 153, 401, 389, 401, 0,
++ 378, 120, 401, 131, 380, 386, 355, 139, 351, 355,
++ 351, 401, 401, 401, 401, 401, 367, 401, 401, 185,
++ 350, 346, 401, 364, 0, 185, 347, 189, 356, 355,
++ 0, 0, 330, 180, 366, 141, 372, 361, 332, 338,
++ 331, 341, 334, 326, 205, 331, 337, 329, 401, 341,
++ 167, 316, 401, 349, 348, 320, 328, 346, 180, 318,
++
++ 324, 209, 324, 320, 322, 342, 338, 309, 306, 315,
++ 305, 315, 312, 192, 342, 341, 401, 293, 306, 282,
++ 268, 252, 255, 203, 285, 282, 272, 268, 252, 233,
++ 232, 239, 208, 107, 401, 401, 238, 211, 401, 211,
++ 212, 208, 228, 203, 215, 207, 233, 222, 212, 211,
++ 203, 227, 401, 237, 225, 204, 185, 401, 401, 149,
++ 128, 88, 42, 401, 401, 253, 259, 267, 271, 275,
++ 281, 288, 292, 300, 308, 312, 318, 326, 334
+ } ;
+
+-static yyconst flex_int16_t yy_def[173] =
++static yyconst flex_int16_t yy_def[180] =
+ { 0,
+- 158, 1, 1, 3, 158, 5, 1, 1, 158, 158,
+- 158, 158, 158, 159, 160, 161, 158, 158, 158, 158,
+- 162, 158, 158, 158, 163, 162, 158, 164, 165, 164,
+- 164, 158, 158, 158, 158, 159, 158, 159, 158, 166,
+- 158, 161, 158, 161, 167, 168, 158, 158, 158, 158,
+- 158, 158, 158, 158, 158, 162, 158, 158, 158, 158,
+- 158, 158, 162, 164, 165, 164, 158, 158, 158, 169,
+- 166, 170, 161, 167, 167, 168, 158, 158, 158, 158,
+- 158, 158, 158, 158, 158, 164, 158, 158, 169, 170,
+- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+-
+- 158, 164, 158, 158, 158, 158, 158, 158, 158, 171,
+- 158, 164, 158, 158, 158, 158, 158, 158, 171, 158,
+- 171, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+- 172, 158, 158, 158, 172, 158, 172, 158, 158, 158,
+- 158, 158, 158, 158, 158, 158, 158, 0, 158, 158,
+- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+- 158, 158
++ 165, 1, 1, 3, 165, 5, 1, 1, 165, 165,
++ 165, 165, 165, 166, 167, 168, 165, 165, 165, 165,
++ 169, 165, 165, 165, 170, 169, 165, 171, 172, 171,
++ 171, 165, 165, 165, 165, 166, 165, 166, 165, 173,
++ 165, 168, 165, 168, 174, 175, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 169, 165, 165, 165,
++ 165, 165, 165, 169, 171, 172, 171, 165, 165, 165,
++ 176, 173, 177, 168, 174, 174, 175, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 171, 165, 165,
++ 176, 177, 165, 165, 165, 165, 165, 165, 165, 165,
++
++ 165, 165, 165, 165, 171, 165, 165, 165, 165, 165,
++ 165, 165, 165, 178, 165, 171, 165, 165, 165, 165,
++ 165, 165, 165, 178, 165, 178, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 179, 165, 165,
++ 165, 179, 165, 179, 165, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 0, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 165, 165
+ } ;
+
+-static yyconst flex_int16_t yy_nxt[438] =
++static yyconst flex_int16_t yy_nxt[449] =
+ { 0,
+ 10, 11, 12, 11, 13, 14, 10, 15, 16, 10,
+ 10, 10, 17, 10, 10, 10, 10, 18, 19, 20,
+ 21, 21, 21, 21, 21, 10, 10, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+- 21, 21, 21, 10, 22, 10, 24, 25, 25, 25,
+- 32, 33, 33, 157, 26, 34, 34, 34, 51, 52,
+- 27, 26, 26, 26, 26, 10, 11, 12, 11, 13,
+- 14, 28, 15, 16, 28, 28, 28, 24, 28, 28,
+- 28, 10, 18, 19, 20, 29, 29, 29, 29, 29,
+- 30, 10, 29, 29, 29, 29, 29, 29, 29, 29,
+-
+- 29, 29, 29, 29, 29, 29, 29, 29, 10, 22,
+- 10, 23, 34, 34, 34, 37, 39, 43, 32, 33,
+- 33, 45, 54, 55, 46, 59, 45, 64, 156, 46,
+- 64, 64, 64, 79, 44, 38, 59, 57, 134, 47,
+- 135, 48, 80, 49, 47, 50, 48, 99, 61, 43,
+- 50, 110, 41, 67, 67, 67, 60, 63, 63, 63,
+- 57, 155, 68, 69, 63, 37, 44, 66, 67, 67,
+- 67, 63, 63, 63, 63, 73, 59, 68, 69, 70,
+- 34, 34, 34, 43, 75, 38, 154, 92, 83, 83,
+- 83, 64, 44, 120, 64, 64, 64, 67, 67, 67,
+-
+- 44, 57, 99, 68, 69, 107, 68, 69, 120, 127,
+- 108, 153, 152, 121, 83, 83, 83, 133, 133, 133,
+- 146, 133, 133, 133, 146, 140, 140, 140, 121, 141,
+- 140, 140, 140, 151, 141, 158, 150, 149, 148, 144,
+- 147, 143, 142, 139, 147, 36, 36, 36, 36, 36,
+- 36, 36, 36, 40, 138, 137, 136, 40, 40, 42,
+- 42, 42, 42, 42, 42, 42, 42, 56, 56, 56,
+- 56, 62, 132, 62, 64, 131, 130, 64, 129, 64,
+- 64, 65, 128, 158, 65, 65, 65, 65, 71, 127,
+- 71, 71, 74, 74, 74, 74, 74, 74, 74, 74,
+-
+- 76, 76, 76, 76, 76, 76, 76, 76, 89, 126,
+- 89, 90, 125, 90, 90, 124, 90, 90, 119, 119,
+- 119, 119, 119, 119, 119, 119, 145, 145, 145, 145,
+- 145, 145, 145, 145, 123, 122, 59, 59, 118, 117,
+- 116, 115, 114, 113, 45, 112, 108, 111, 109, 106,
+- 105, 104, 46, 103, 91, 87, 102, 101, 100, 98,
+- 97, 96, 95, 94, 93, 77, 75, 91, 88, 87,
+- 86, 57, 85, 84, 57, 82, 81, 78, 77, 75,
+- 72, 158, 58, 57, 53, 35, 158, 31, 23, 23,
+- 9, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+-
+- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+- 158, 158, 158, 158, 158, 158, 158
++ 21, 21, 21, 21, 10, 22, 10, 24, 25, 25,
++ 25, 32, 33, 33, 164, 26, 34, 34, 34, 52,
++ 53, 27, 26, 26, 26, 26, 10, 11, 12, 11,
++ 13, 14, 28, 15, 16, 28, 28, 28, 24, 28,
++ 28, 28, 10, 18, 19, 20, 29, 29, 29, 29,
++ 29, 30, 10, 29, 29, 29, 29, 29, 29, 29,
++
++ 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
++ 10, 22, 10, 23, 34, 34, 34, 37, 39, 43,
++ 32, 33, 33, 45, 55, 56, 46, 60, 43, 45,
++ 65, 163, 46, 65, 65, 65, 44, 38, 60, 74,
++ 58, 47, 141, 48, 142, 44, 49, 47, 50, 48,
++ 76, 51, 62, 94, 50, 41, 44, 51, 37, 61,
++ 64, 64, 64, 58, 34, 34, 34, 64, 162, 80,
++ 67, 68, 68, 68, 64, 64, 64, 64, 38, 81,
++ 69, 70, 71, 68, 68, 68, 60, 161, 43, 69,
++ 70, 65, 69, 70, 65, 65, 65, 125, 85, 85,
++
++ 85, 58, 68, 68, 68, 44, 102, 110, 125, 133,
++ 102, 69, 70, 111, 114, 160, 159, 126, 85, 85,
++ 85, 140, 140, 140, 140, 140, 140, 153, 126, 147,
++ 147, 147, 153, 148, 147, 147, 147, 158, 148, 165,
++ 157, 156, 155, 151, 150, 149, 146, 154, 145, 144,
++ 143, 139, 154, 36, 36, 36, 36, 36, 36, 36,
++ 36, 40, 138, 137, 136, 40, 40, 42, 42, 42,
++ 42, 42, 42, 42, 42, 57, 57, 57, 57, 63,
++ 135, 63, 65, 134, 165, 65, 133, 65, 65, 66,
++ 132, 131, 66, 66, 66, 66, 72, 130, 72, 72,
++
++ 75, 75, 75, 75, 75, 75, 75, 75, 77, 77,
++ 77, 77, 77, 77, 77, 77, 91, 129, 91, 92,
++ 128, 92, 92, 127, 92, 92, 124, 124, 124, 124,
++ 124, 124, 124, 124, 152, 152, 152, 152, 152, 152,
++ 152, 152, 60, 60, 123, 122, 121, 120, 119, 118,
++ 117, 45, 116, 111, 115, 113, 112, 109, 108, 107,
++ 46, 106, 93, 89, 105, 104, 103, 101, 100, 99,
++ 98, 97, 96, 95, 78, 76, 93, 90, 89, 88,
++ 58, 87, 86, 58, 84, 83, 82, 79, 78, 76,
++ 73, 165, 59, 58, 54, 35, 165, 31, 23, 23,
++
++ 9, 165, 165, 165, 165, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 165
+ } ;
+
+-static yyconst flex_int16_t yy_chk[438] =
++static yyconst flex_int16_t yy_chk[449] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+- 1, 1, 1, 1, 1, 1, 3, 3, 3, 3,
+- 7, 7, 7, 156, 3, 11, 11, 11, 18, 18,
+- 3, 3, 3, 3, 3, 5, 5, 5, 5, 5,
++ 1, 1, 1, 1, 1, 1, 1, 3, 3, 3,
++ 3, 7, 7, 7, 163, 3, 11, 11, 11, 18,
++ 18, 3, 3, 3, 3, 3, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+- 5, 8, 12, 12, 12, 14, 15, 16, 8, 8,
+- 8, 17, 20, 20, 17, 23, 24, 29, 155, 24,
+- 29, 29, 29, 48, 16, 14, 31, 29, 128, 17,
+- 128, 17, 48, 17, 24, 17, 24, 99, 24, 42,
+- 24, 99, 15, 33, 33, 33, 23, 26, 26, 26,
+- 26, 154, 33, 33, 26, 36, 42, 31, 32, 32,
+- 32, 26, 26, 26, 26, 44, 59, 32, 32, 32,
+- 34, 34, 34, 73, 75, 36, 153, 75, 59, 59,
+- 59, 65, 44, 110, 65, 65, 65, 67, 67, 67,
+-
+- 73, 65, 83, 89, 89, 97, 67, 67, 119, 127,
+- 97, 150, 149, 110, 83, 83, 83, 133, 133, 133,
+- 141, 127, 127, 127, 145, 136, 136, 136, 119, 136,
+- 140, 140, 140, 148, 140, 147, 144, 143, 142, 139,
+- 141, 138, 137, 135, 145, 159, 159, 159, 159, 159,
+- 159, 159, 159, 160, 134, 132, 131, 160, 160, 161,
+- 161, 161, 161, 161, 161, 161, 161, 162, 162, 162,
+- 162, 163, 126, 163, 164, 125, 124, 164, 123, 164,
+- 164, 165, 122, 121, 165, 165, 165, 165, 166, 120,
+- 166, 166, 167, 167, 167, 167, 167, 167, 167, 167,
+-
+- 168, 168, 168, 168, 168, 168, 168, 168, 169, 118,
+- 169, 170, 117, 170, 170, 116, 170, 170, 171, 171,
+- 171, 171, 171, 171, 171, 171, 172, 172, 172, 172,
+- 172, 172, 172, 172, 115, 114, 112, 111, 109, 108,
+- 107, 106, 105, 104, 103, 102, 101, 100, 98, 96,
+- 95, 94, 93, 92, 90, 88, 86, 85, 84, 82,
+- 81, 80, 79, 78, 77, 76, 74, 72, 69, 68,
+- 66, 63, 61, 60, 56, 50, 49, 47, 46, 45,
++ 5, 5, 5, 8, 12, 12, 12, 14, 15, 16,
++ 8, 8, 8, 17, 20, 20, 17, 23, 42, 24,
++ 29, 162, 24, 29, 29, 29, 16, 14, 31, 44,
++ 29, 17, 134, 17, 134, 42, 17, 24, 17, 24,
++ 76, 17, 24, 76, 24, 15, 44, 24, 36, 23,
++ 26, 26, 26, 26, 34, 34, 34, 26, 161, 48,
++ 31, 32, 32, 32, 26, 26, 26, 26, 36, 48,
++ 32, 32, 32, 33, 33, 33, 60, 160, 74, 91,
++ 91, 66, 33, 33, 66, 66, 66, 114, 60, 60,
++
++ 60, 66, 68, 68, 68, 74, 85, 99, 124, 133,
++ 102, 68, 68, 99, 102, 157, 156, 114, 85, 85,
++ 85, 133, 133, 133, 140, 140, 140, 148, 124, 143,
++ 143, 143, 152, 143, 147, 147, 147, 155, 147, 154,
++ 151, 150, 149, 146, 145, 144, 142, 148, 141, 138,
++ 137, 132, 152, 166, 166, 166, 166, 166, 166, 166,
++ 166, 167, 131, 130, 129, 167, 167, 168, 168, 168,
++ 168, 168, 168, 168, 168, 169, 169, 169, 169, 170,
++ 128, 170, 171, 127, 126, 171, 125, 171, 171, 172,
++ 123, 122, 172, 172, 172, 172, 173, 121, 173, 173,
++
++ 174, 174, 174, 174, 174, 174, 174, 174, 175, 175,
++ 175, 175, 175, 175, 175, 175, 176, 120, 176, 177,
++ 119, 177, 177, 118, 177, 177, 178, 178, 178, 178,
++ 178, 178, 178, 178, 179, 179, 179, 179, 179, 179,
++ 179, 179, 116, 115, 113, 112, 111, 110, 109, 108,
++ 107, 106, 105, 104, 103, 101, 100, 98, 97, 96,
++ 95, 94, 92, 90, 88, 87, 86, 84, 83, 82,
++ 81, 80, 79, 78, 77, 75, 73, 70, 69, 67,
++ 64, 62, 61, 57, 51, 50, 49, 47, 46, 45,
+ 41, 38, 22, 21, 19, 13, 9, 6, 4, 2,
+- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+
+- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+- 158, 158, 158, 158, 158, 158, 158
++ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 165
+ } ;
+
+ static yy_state_type yy_last_accepting_state;
+@@ -662,7 +664,7 @@ static int dts_version = 1;
+ static void push_input_file(const char *filename);
+ static bool pop_input_file(void);
+ static void lexical_error(const char *fmt, ...);
+-#line 666 "dtc-lexer.lex.c"
++#line 668 "dtc-lexer.lex.c"
+
+ #define INITIAL 0
+ #define BYTESTRING 1
+@@ -704,7 +706,7 @@ FILE *yyget_out (void );
+
+ void yyset_out (FILE * out_str );
+
+-yy_size_t yyget_leng (void );
++int yyget_leng (void );
+
+ char *yyget_text (void );
+
+@@ -853,6 +855,10 @@ YY_DECL
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
++#line 68 "dtc-lexer.l"
++
++#line 861 "dtc-lexer.lex.c"
++
+ if ( !(yy_init) )
+ {
+ (yy_init) = 1;
+@@ -879,11 +885,6 @@ YY_DECL
+ yy_load_buffer_state( );
+ }
+
+- {
+-#line 68 "dtc-lexer.l"
+-
+-#line 886 "dtc-lexer.lex.c"
+-
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = (yy_c_buf_p);
+@@ -901,7 +902,7 @@ YY_DECL
+ yy_match:
+ do
+ {
+- register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
++ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+@@ -910,13 +911,13 @@ yy_match:
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+- if ( yy_current_state >= 159 )
++ if ( yy_current_state >= 166 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+- while ( yy_current_state != 158 );
++ while ( yy_current_state != 165 );
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+
+@@ -1007,23 +1008,31 @@ case 5:
+ YY_RULE_SETUP
+ #line 116 "dtc-lexer.l"
+ {
++ DPRINT("Keyword: /plugin/\n");
++ return DT_PLUGIN;
++ }
++ YY_BREAK
++case 6:
++YY_RULE_SETUP
++#line 121 "dtc-lexer.l"
++{
+ DPRINT("Keyword: /memreserve/\n");
+ BEGIN_DEFAULT();
+ return DT_MEMRESERVE;
+ }
+ YY_BREAK
+-case 6:
++case 7:
+ YY_RULE_SETUP
+-#line 122 "dtc-lexer.l"
++#line 127 "dtc-lexer.l"
+ {
+ DPRINT("Keyword: /bits/\n");
+ BEGIN_DEFAULT();
+ return DT_BITS;
+ }
+ YY_BREAK
+-case 7:
++case 8:
+ YY_RULE_SETUP
+-#line 128 "dtc-lexer.l"
++#line 133 "dtc-lexer.l"
+ {
+ DPRINT("Keyword: /delete-property/\n");
+ DPRINT("<PROPNODENAME>\n");
+@@ -1031,9 +1040,9 @@ YY_RULE_SETUP
+ return DT_DEL_PROP;
+ }
+ YY_BREAK
+-case 8:
++case 9:
+ YY_RULE_SETUP
+-#line 135 "dtc-lexer.l"
++#line 140 "dtc-lexer.l"
+ {
+ DPRINT("Keyword: /delete-node/\n");
+ DPRINT("<PROPNODENAME>\n");
+@@ -1041,9 +1050,9 @@ YY_RULE_SETUP
+ return DT_DEL_NODE;
+ }
+ YY_BREAK
+-case 9:
++case 10:
+ YY_RULE_SETUP
+-#line 142 "dtc-lexer.l"
++#line 147 "dtc-lexer.l"
+ {
+ DPRINT("Label: %s\n", yytext);
+ yylval.labelref = xstrdup(yytext);
+@@ -1051,9 +1060,9 @@ YY_RULE_SETUP
+ return DT_LABEL;
+ }
+ YY_BREAK
+-case 10:
++case 11:
+ YY_RULE_SETUP
+-#line 149 "dtc-lexer.l"
++#line 154 "dtc-lexer.l"
+ {
+ char *e;
+ DPRINT("Integer Literal: '%s'\n", yytext);
+@@ -1073,10 +1082,10 @@ YY_RULE_SETUP
+ return DT_LITERAL;
+ }
+ YY_BREAK
+-case 11:
+-/* rule 11 can match eol */
++case 12:
++/* rule 12 can match eol */
+ YY_RULE_SETUP
+-#line 168 "dtc-lexer.l"
++#line 173 "dtc-lexer.l"
+ {
+ struct data d;
+ DPRINT("Character literal: %s\n", yytext);
+@@ -1098,18 +1107,18 @@ YY_RULE_SETUP
+ return DT_CHAR_LITERAL;
+ }
+ YY_BREAK
+-case 12:
++case 13:
+ YY_RULE_SETUP
+-#line 189 "dtc-lexer.l"
++#line 194 "dtc-lexer.l"
+ { /* label reference */
+ DPRINT("Ref: %s\n", yytext+1);
+ yylval.labelref = xstrdup(yytext+1);
+ return DT_REF;
+ }
+ YY_BREAK
+-case 13:
++case 14:
+ YY_RULE_SETUP
+-#line 195 "dtc-lexer.l"
++#line 200 "dtc-lexer.l"
+ { /* new-style path reference */
+ yytext[yyleng-1] = '\0';
+ DPRINT("Ref: %s\n", yytext+2);
+@@ -1117,27 +1126,27 @@ YY_RULE_SETUP
+ return DT_REF;
+ }
+ YY_BREAK
+-case 14:
++case 15:
+ YY_RULE_SETUP
+-#line 202 "dtc-lexer.l"
++#line 207 "dtc-lexer.l"
+ {
+ yylval.byte = strtol(yytext, NULL, 16);
+ DPRINT("Byte: %02x\n", (int)yylval.byte);
+ return DT_BYTE;
+ }
+ YY_BREAK
+-case 15:
++case 16:
+ YY_RULE_SETUP
+-#line 208 "dtc-lexer.l"
++#line 213 "dtc-lexer.l"
+ {
+ DPRINT("/BYTESTRING\n");
+ BEGIN_DEFAULT();
+ return ']';
+ }
+ YY_BREAK
+-case 16:
++case 17:
+ YY_RULE_SETUP
+-#line 214 "dtc-lexer.l"
++#line 219 "dtc-lexer.l"
+ {
+ DPRINT("PropNodeName: %s\n", yytext);
+ yylval.propnodename = xstrdup((yytext[0] == '\\') ?
+@@ -1146,75 +1155,75 @@ YY_RULE_SETUP
+ return DT_PROPNODENAME;
+ }
+ YY_BREAK
+-case 17:
++case 18:
+ YY_RULE_SETUP
+-#line 222 "dtc-lexer.l"
++#line 227 "dtc-lexer.l"
+ {
+ DPRINT("Binary Include\n");
+ return DT_INCBIN;
+ }
+ YY_BREAK
+-case 18:
+-/* rule 18 can match eol */
+-YY_RULE_SETUP
+-#line 227 "dtc-lexer.l"
+-/* eat whitespace */
+- YY_BREAK
+ case 19:
+ /* rule 19 can match eol */
+ YY_RULE_SETUP
+-#line 228 "dtc-lexer.l"
+-/* eat C-style comments */
++#line 232 "dtc-lexer.l"
++/* eat whitespace */
+ YY_BREAK
+ case 20:
+ /* rule 20 can match eol */
+ YY_RULE_SETUP
+-#line 229 "dtc-lexer.l"
+-/* eat C++-style comments */
++#line 233 "dtc-lexer.l"
++/* eat C-style comments */
+ YY_BREAK
+ case 21:
++/* rule 21 can match eol */
+ YY_RULE_SETUP
+-#line 231 "dtc-lexer.l"
+-{ return DT_LSHIFT; };
++#line 234 "dtc-lexer.l"
++/* eat C++-style comments */
+ YY_BREAK
+ case 22:
+ YY_RULE_SETUP
+-#line 232 "dtc-lexer.l"
+-{ return DT_RSHIFT; };
++#line 236 "dtc-lexer.l"
++{ return DT_LSHIFT; };
+ YY_BREAK
+ case 23:
+ YY_RULE_SETUP
+-#line 233 "dtc-lexer.l"
+-{ return DT_LE; };
++#line 237 "dtc-lexer.l"
++{ return DT_RSHIFT; };
+ YY_BREAK
+ case 24:
+ YY_RULE_SETUP
+-#line 234 "dtc-lexer.l"
+-{ return DT_GE; };
++#line 238 "dtc-lexer.l"
++{ return DT_LE; };
+ YY_BREAK
+ case 25:
+ YY_RULE_SETUP
+-#line 235 "dtc-lexer.l"
+-{ return DT_EQ; };
++#line 239 "dtc-lexer.l"
++{ return DT_GE; };
+ YY_BREAK
+ case 26:
+ YY_RULE_SETUP
+-#line 236 "dtc-lexer.l"
+-{ return DT_NE; };
++#line 240 "dtc-lexer.l"
++{ return DT_EQ; };
+ YY_BREAK
+ case 27:
+ YY_RULE_SETUP
+-#line 237 "dtc-lexer.l"
+-{ return DT_AND; };
++#line 241 "dtc-lexer.l"
++{ return DT_NE; };
+ YY_BREAK
+ case 28:
+ YY_RULE_SETUP
+-#line 238 "dtc-lexer.l"
+-{ return DT_OR; };
++#line 242 "dtc-lexer.l"
++{ return DT_AND; };
+ YY_BREAK
+ case 29:
+ YY_RULE_SETUP
+-#line 240 "dtc-lexer.l"
++#line 243 "dtc-lexer.l"
++{ return DT_OR; };
++ YY_BREAK
++case 30:
++YY_RULE_SETUP
++#line 245 "dtc-lexer.l"
+ {
+ DPRINT("Char: %c (\\x%02x)\n", yytext[0],
+ (unsigned)yytext[0]);
+@@ -1230,12 +1239,12 @@ YY_RULE_SETUP
+ return yytext[0];
+ }
+ YY_BREAK
+-case 30:
++case 31:
+ YY_RULE_SETUP
+-#line 255 "dtc-lexer.l"
++#line 260 "dtc-lexer.l"
+ ECHO;
+ YY_BREAK
+-#line 1239 "dtc-lexer.lex.c"
++#line 1248 "dtc-lexer.lex.c"
+
+ case YY_END_OF_BUFFER:
+ {
+@@ -1365,7 +1374,6 @@ ECHO;
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+- } /* end of user's declarations */
+ } /* end of yylex */
+
+ /* yy_get_next_buffer - try to read in a new buffer
+@@ -1421,21 +1429,21 @@ static int yy_get_next_buffer (void)
+
+ else
+ {
+- yy_size_t num_to_read =
++ int num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+- YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
++ YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+ int yy_c_buf_p_offset =
+ (int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+- yy_size_t new_size = b->yy_buf_size * 2;
++ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+@@ -1466,7 +1474,7 @@ static int yy_get_next_buffer (void)
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+- (yy_n_chars), num_to_read );
++ (yy_n_chars), (size_t) num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+@@ -1528,7 +1536,7 @@ static int yy_get_next_buffer (void)
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+- if ( yy_current_state >= 159 )
++ if ( yy_current_state >= 166 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+@@ -1556,13 +1564,13 @@ static int yy_get_next_buffer (void)
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+- if ( yy_current_state >= 159 )
++ if ( yy_current_state >= 166 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+- yy_is_jam = (yy_current_state == 158);
++ yy_is_jam = (yy_current_state == 165);
+
+- return yy_is_jam ? 0 : yy_current_state;
++ return yy_is_jam ? 0 : yy_current_state;
+ }
+
+ #ifndef YY_NO_INPUT
+@@ -1589,7 +1597,7 @@ static int yy_get_next_buffer (void)
+
+ else
+ { /* need more input */
+- yy_size_t offset = (yy_c_buf_p) - (yytext_ptr);
++ int offset = (yy_c_buf_p) - (yytext_ptr);
+ ++(yy_c_buf_p);
+
+ switch ( yy_get_next_buffer( ) )
+@@ -1863,7 +1871,7 @@ void yypop_buffer_state (void)
+ */
+ static void yyensure_buffer_stack (void)
+ {
+- yy_size_t num_to_alloc;
++ int num_to_alloc;
+
+ if (!(yy_buffer_stack)) {
+
+@@ -1960,12 +1968,12 @@ YY_BUFFER_STATE yy_scan_string (yyconst
+ *
+ * @return the newly allocated buffer state object.
+ */
+-YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len )
++YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len )
+ {
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+- yy_size_t i;
++ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+@@ -2047,7 +2055,7 @@ FILE *yyget_out (void)
+ /** Get the length of the current token.
+ *
+ */
+-yy_size_t yyget_leng (void)
++int yyget_leng (void)
+ {
+ return yyleng;
+ }
+@@ -2195,7 +2203,7 @@ void yyfree (void * ptr )
+
+ #define YYTABLES_NAME "yytables"
+
+-#line 254 "dtc-lexer.l"
++#line 260 "dtc-lexer.l"
+
+
+
+--- a/scripts/dtc/dtc-parser.tab.c_shipped
++++ b/scripts/dtc/dtc-parser.tab.c_shipped
+@@ -65,6 +65,7 @@
+ #line 20 "dtc-parser.y" /* yacc.c:339 */
+
+ #include <stdio.h>
++#include <inttypes.h>
+
+ #include "dtc.h"
+ #include "srcpos.h"
+@@ -80,7 +81,7 @@ extern void yyerror(char const *s);
+ extern struct boot_info *the_boot_info;
+ extern bool treesource_error;
+
+-#line 84 "dtc-parser.tab.c" /* yacc.c:339 */
++#line 85 "dtc-parser.tab.c" /* yacc.c:339 */
+
+ # ifndef YY_NULLPTR
+ # if defined __cplusplus && 201103L <= __cplusplus
+@@ -116,26 +117,27 @@ extern int yydebug;
+ enum yytokentype
+ {
+ DT_V1 = 258,
+- DT_MEMRESERVE = 259,
+- DT_LSHIFT = 260,
+- DT_RSHIFT = 261,
+- DT_LE = 262,
+- DT_GE = 263,
+- DT_EQ = 264,
+- DT_NE = 265,
+- DT_AND = 266,
+- DT_OR = 267,
+- DT_BITS = 268,
+- DT_DEL_PROP = 269,
+- DT_DEL_NODE = 270,
+- DT_PROPNODENAME = 271,
+- DT_LITERAL = 272,
+- DT_CHAR_LITERAL = 273,
+- DT_BYTE = 274,
+- DT_STRING = 275,
+- DT_LABEL = 276,
+- DT_REF = 277,
+- DT_INCBIN = 278
++ DT_PLUGIN = 259,
++ DT_MEMRESERVE = 260,
++ DT_LSHIFT = 261,
++ DT_RSHIFT = 262,
++ DT_LE = 263,
++ DT_GE = 264,
++ DT_EQ = 265,
++ DT_NE = 266,
++ DT_AND = 267,
++ DT_OR = 268,
++ DT_BITS = 269,
++ DT_DEL_PROP = 270,
++ DT_DEL_NODE = 271,
++ DT_PROPNODENAME = 272,
++ DT_LITERAL = 273,
++ DT_CHAR_LITERAL = 274,
++ DT_BYTE = 275,
++ DT_STRING = 276,
++ DT_LABEL = 277,
++ DT_REF = 278,
++ DT_INCBIN = 279
+ };
+ #endif
+
+@@ -144,7 +146,7 @@ extern int yydebug;
+ typedef union YYSTYPE YYSTYPE;
+ union YYSTYPE
+ {
+-#line 38 "dtc-parser.y" /* yacc.c:355 */
++#line 39 "dtc-parser.y" /* yacc.c:355 */
+
+ char *propnodename;
+ char *labelref;
+@@ -162,8 +164,9 @@ union YYSTYPE
+ struct node *nodelist;
+ struct reserve_info *re;
+ uint64_t integer;
++ bool is_plugin;
+
+-#line 167 "dtc-parser.tab.c" /* yacc.c:355 */
++#line 170 "dtc-parser.tab.c" /* yacc.c:355 */
+ };
+ # define YYSTYPE_IS_TRIVIAL 1
+ # define YYSTYPE_IS_DECLARED 1
+@@ -192,7 +195,7 @@ int yyparse (void);
+
+ /* Copy the second part of user declarations. */
+
+-#line 196 "dtc-parser.tab.c" /* yacc.c:358 */
++#line 199 "dtc-parser.tab.c" /* yacc.c:358 */
+
+ #ifdef short
+ # undef short
+@@ -439,18 +442,18 @@ union yyalloc
+ #define YYLAST 136
+
+ /* YYNTOKENS -- Number of terminals. */
+-#define YYNTOKENS 47
++#define YYNTOKENS 48
+ /* YYNNTS -- Number of nonterminals. */
+-#define YYNNTS 28
++#define YYNNTS 29
+ /* YYNRULES -- Number of rules. */
+-#define YYNRULES 80
++#define YYNRULES 82
+ /* YYNSTATES -- Number of states. */
+-#define YYNSTATES 144
++#define YYNSTATES 147
+
+ /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
+ by yylex, with out-of-bounds checking. */
+ #define YYUNDEFTOK 2
+-#define YYMAXUTOK 278
++#define YYMAXUTOK 279
+
+ #define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+@@ -462,16 +465,16 @@ static const yytype_uint8 yytranslate[]
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+- 2, 2, 2, 46, 2, 2, 2, 44, 40, 2,
+- 32, 34, 43, 41, 33, 42, 2, 25, 2, 2,
+- 2, 2, 2, 2, 2, 2, 2, 2, 37, 24,
+- 35, 28, 29, 36, 2, 2, 2, 2, 2, 2,
++ 2, 2, 2, 47, 2, 2, 2, 45, 41, 2,
++ 33, 35, 44, 42, 34, 43, 2, 26, 2, 2,
++ 2, 2, 2, 2, 2, 2, 2, 2, 38, 25,
++ 36, 29, 30, 37, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+- 2, 30, 2, 31, 39, 2, 2, 2, 2, 2,
++ 2, 31, 2, 32, 40, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+- 2, 2, 2, 26, 38, 27, 45, 2, 2, 2,
++ 2, 2, 2, 27, 39, 28, 46, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+@@ -486,22 +489,22 @@ static const yytype_uint8 yytranslate[]
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+- 15, 16, 17, 18, 19, 20, 21, 22, 23
++ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24
+ };
+
+ #if YYDEBUG
+ /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
+ static const yytype_uint16 yyrline[] =
+ {
+- 0, 104, 104, 113, 116, 123, 127, 135, 139, 144,
+- 155, 165, 180, 188, 191, 198, 202, 206, 210, 218,
+- 222, 226, 230, 234, 250, 260, 268, 271, 275, 282,
+- 298, 303, 322, 336, 343, 344, 345, 352, 356, 357,
+- 361, 362, 366, 367, 371, 372, 376, 377, 381, 382,
+- 386, 387, 388, 392, 393, 394, 395, 396, 400, 401,
+- 402, 406, 407, 408, 412, 413, 414, 415, 419, 420,
+- 421, 422, 427, 430, 434, 442, 445, 449, 457, 461,
+- 465
++ 0, 108, 108, 118, 121, 129, 132, 139, 143, 151,
++ 155, 160, 171, 181, 196, 204, 207, 214, 218, 222,
++ 226, 234, 238, 242, 246, 250, 266, 276, 284, 287,
++ 291, 298, 314, 319, 338, 352, 359, 360, 361, 368,
++ 372, 373, 377, 378, 382, 383, 387, 388, 392, 393,
++ 397, 398, 402, 403, 404, 408, 409, 410, 411, 412,
++ 416, 417, 418, 422, 423, 424, 428, 429, 430, 431,
++ 435, 436, 437, 438, 443, 446, 450, 458, 461, 465,
++ 473, 477, 481
+ };
+ #endif
+
+@@ -510,19 +513,19 @@ static const yytype_uint16 yyrline[] =
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+ static const char *const yytname[] =
+ {
+- "$end", "error", "$undefined", "DT_V1", "DT_MEMRESERVE", "DT_LSHIFT",
+- "DT_RSHIFT", "DT_LE", "DT_GE", "DT_EQ", "DT_NE", "DT_AND", "DT_OR",
+- "DT_BITS", "DT_DEL_PROP", "DT_DEL_NODE", "DT_PROPNODENAME", "DT_LITERAL",
+- "DT_CHAR_LITERAL", "DT_BYTE", "DT_STRING", "DT_LABEL", "DT_REF",
+- "DT_INCBIN", "';'", "'/'", "'{'", "'}'", "'='", "'>'", "'['", "']'",
+- "'('", "','", "')'", "'<'", "'?'", "':'", "'|'", "'^'", "'&'", "'+'",
+- "'-'", "'*'", "'%'", "'~'", "'!'", "$accept", "sourcefile",
+- "memreserves", "memreserve", "devicetree", "nodedef", "proplist",
+- "propdef", "propdata", "propdataprefix", "arrayprefix", "integer_prim",
+- "integer_expr", "integer_trinary", "integer_or", "integer_and",
+- "integer_bitor", "integer_bitxor", "integer_bitand", "integer_eq",
+- "integer_rela", "integer_shift", "integer_add", "integer_mul",
+- "integer_unary", "bytestring", "subnodes", "subnode", YY_NULLPTR
++ "$end", "error", "$undefined", "DT_V1", "DT_PLUGIN", "DT_MEMRESERVE",
++ "DT_LSHIFT", "DT_RSHIFT", "DT_LE", "DT_GE", "DT_EQ", "DT_NE", "DT_AND",
++ "DT_OR", "DT_BITS", "DT_DEL_PROP", "DT_DEL_NODE", "DT_PROPNODENAME",
++ "DT_LITERAL", "DT_CHAR_LITERAL", "DT_BYTE", "DT_STRING", "DT_LABEL",
++ "DT_REF", "DT_INCBIN", "';'", "'/'", "'{'", "'}'", "'='", "'>'", "'['",
++ "']'", "'('", "','", "')'", "'<'", "'?'", "':'", "'|'", "'^'", "'&'",
++ "'+'", "'-'", "'*'", "'%'", "'~'", "'!'", "$accept", "sourcefile",
++ "plugindecl", "memreserves", "memreserve", "devicetree", "nodedef",
++ "proplist", "propdef", "propdata", "propdataprefix", "arrayprefix",
++ "integer_prim", "integer_expr", "integer_trinary", "integer_or",
++ "integer_and", "integer_bitor", "integer_bitxor", "integer_bitand",
++ "integer_eq", "integer_rela", "integer_shift", "integer_add",
++ "integer_mul", "integer_unary", "bytestring", "subnodes", "subnode", YY_NULLPTR
+ };
+ #endif
+
+@@ -533,16 +536,16 @@ static const yytype_uint16 yytoknum[] =
+ {
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+- 275, 276, 277, 278, 59, 47, 123, 125, 61, 62,
+- 91, 93, 40, 44, 41, 60, 63, 58, 124, 94,
+- 38, 43, 45, 42, 37, 126, 33
++ 275, 276, 277, 278, 279, 59, 47, 123, 125, 61,
++ 62, 91, 93, 40, 44, 41, 60, 63, 58, 124,
++ 94, 38, 43, 45, 42, 37, 126, 33
+ };
+ # endif
+
+-#define YYPACT_NINF -81
++#define YYPACT_NINF -84
+
+ #define yypact_value_is_default(Yystate) \
+- (!!((Yystate) == (-81)))
++ (!!((Yystate) == (-84)))
+
+ #define YYTABLE_NINF -1
+
+@@ -553,21 +556,21 @@ static const yytype_uint16 yytoknum[] =
+ STATE-NUM. */
+ static const yytype_int8 yypact[] =
+ {
+- 16, -11, 21, 10, -81, 25, 10, 19, 10, -81,
+- -81, -9, 25, -81, 2, 51, -81, -9, -9, -9,
+- -81, 1, -81, -6, 50, 14, 28, 29, 36, 3,
+- 58, 44, -3, -81, 47, -81, -81, 65, 68, 2,
+- 2, -81, -81, -81, -81, -9, -9, -9, -9, -9,
+- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
+- -9, -9, -9, -9, -81, 63, 69, 2, -81, -81,
+- 50, 57, 14, 28, 29, 36, 3, 3, 58, 58,
+- 58, 58, 44, 44, -3, -3, -81, -81, -81, 79,
+- 80, -8, 63, -81, 72, 63, -81, -81, -9, 76,
+- 77, -81, -81, -81, -81, -81, 78, -81, -81, -81,
+- -81, -81, 35, 4, -81, -81, -81, -81, 86, -81,
+- -81, -81, 73, -81, -81, 33, 71, 84, 39, -81,
+- -81, -81, -81, -81, 41, -81, -81, -81, 25, -81,
+- 74, 25, 75, -81
++ 15, -12, 35, 42, -84, 27, 9, -84, 24, 9,
++ 43, 9, -84, -84, -10, 24, -84, 60, 44, -84,
++ -10, -10, -10, -84, 55, -84, -7, 52, 53, 51,
++ 54, 10, 2, 38, 37, -4, -84, 68, -84, -84,
++ 71, 73, 60, 60, -84, -84, -84, -84, -10, -10,
++ -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
++ -10, -10, -10, -10, -10, -10, -10, -84, 56, 72,
++ 60, -84, -84, 52, 61, 53, 51, 54, 10, 2,
++ 2, 38, 38, 38, 38, 37, 37, -4, -4, -84,
++ -84, -84, 81, 83, 34, 56, -84, 74, 56, -84,
++ -84, -10, 76, 78, -84, -84, -84, -84, -84, 79,
++ -84, -84, -84, -84, -84, -6, 3, -84, -84, -84,
++ -84, 87, -84, -84, -84, 75, -84, -84, 32, 70,
++ 86, 36, -84, -84, -84, -84, -84, 47, -84, -84,
++ -84, 24, -84, 77, 24, 80, -84
+ };
+
+ /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
+@@ -575,37 +578,37 @@ static const yytype_int8 yypact[] =
+ means the default is an error. */
+ static const yytype_uint8 yydefact[] =
+ {
+- 0, 0, 0, 3, 1, 0, 0, 0, 3, 34,
+- 35, 0, 0, 6, 0, 2, 4, 0, 0, 0,
+- 68, 0, 37, 38, 40, 42, 44, 46, 48, 50,
+- 53, 60, 63, 67, 0, 13, 7, 0, 0, 0,
+- 0, 69, 70, 71, 36, 0, 0, 0, 0, 0,
++ 0, 0, 0, 3, 1, 0, 5, 4, 0, 0,
++ 0, 5, 36, 37, 0, 0, 8, 0, 2, 6,
++ 0, 0, 0, 70, 0, 39, 40, 42, 44, 46,
++ 48, 50, 52, 55, 62, 65, 69, 0, 15, 9,
++ 0, 0, 0, 0, 71, 72, 73, 38, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+- 0, 0, 0, 0, 5, 75, 0, 0, 10, 8,
+- 41, 0, 43, 45, 47, 49, 51, 52, 56, 57,
+- 55, 54, 58, 59, 61, 62, 65, 64, 66, 0,
+- 0, 0, 0, 14, 0, 75, 11, 9, 0, 0,
+- 0, 16, 26, 78, 18, 80, 0, 77, 76, 39,
+- 17, 79, 0, 0, 12, 25, 15, 27, 0, 19,
+- 28, 22, 0, 72, 30, 0, 0, 0, 0, 33,
+- 32, 20, 31, 29, 0, 73, 74, 21, 0, 24,
+- 0, 0, 0, 23
++ 0, 0, 0, 0, 0, 0, 0, 7, 77, 0,
++ 0, 12, 10, 43, 0, 45, 47, 49, 51, 53,
++ 54, 58, 59, 57, 56, 60, 61, 63, 64, 67,
++ 66, 68, 0, 0, 0, 0, 16, 0, 77, 13,
++ 11, 0, 0, 0, 18, 28, 80, 20, 82, 0,
++ 79, 78, 41, 19, 81, 0, 0, 14, 27, 17,
++ 29, 0, 21, 30, 24, 0, 74, 32, 0, 0,
++ 0, 0, 35, 34, 22, 33, 31, 0, 75, 76,
++ 23, 0, 26, 0, 0, 0, 25
+ };
+
+ /* YYPGOTO[NTERM-NUM]. */
+ static const yytype_int8 yypgoto[] =
+ {
+- -81, -81, 100, 104, -81, -38, -81, -80, -81, -81,
+- -81, -5, 66, 13, -81, 70, 67, 81, 64, 82,
+- 37, 27, 34, 38, -14, -81, 22, 24
++ -84, -84, -84, 98, 101, -84, -41, -84, -83, -84,
++ -84, -84, -8, 63, 12, -84, 66, 67, 65, 69,
++ 82, 29, 18, 25, 26, -17, -84, 20, 28
+ };
+
+ /* YYDEFGOTO[NTERM-NUM]. */
+ static const yytype_int16 yydefgoto[] =
+ {
+- -1, 2, 7, 8, 15, 36, 65, 93, 112, 113,
+- 125, 20, 21, 22, 23, 24, 25, 26, 27, 28,
+- 29, 30, 31, 32, 33, 128, 94, 95
++ -1, 2, 6, 10, 11, 18, 39, 68, 96, 115,
++ 116, 128, 23, 24, 25, 26, 27, 28, 29, 30,
++ 31, 32, 33, 34, 35, 36, 131, 97, 98
+ };
+
+ /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
+@@ -613,87 +616,87 @@ static const yytype_int16 yydefgoto[] =
+ number is the opposite. If YYTABLE_NINF, syntax error. */
+ static const yytype_uint8 yytable[] =
+ {
+- 12, 68, 69, 41, 42, 43, 45, 34, 9, 10,
+- 53, 54, 104, 3, 5, 107, 101, 118, 35, 1,
+- 102, 4, 61, 11, 119, 120, 121, 122, 35, 97,
+- 46, 6, 55, 17, 123, 44, 18, 19, 56, 124,
+- 62, 63, 9, 10, 14, 51, 52, 86, 87, 88,
+- 9, 10, 48, 103, 129, 130, 115, 11, 135, 116,
+- 136, 47, 131, 57, 58, 11, 37, 49, 117, 50,
+- 137, 64, 38, 39, 138, 139, 40, 89, 90, 91,
+- 78, 79, 80, 81, 92, 59, 60, 66, 76, 77,
+- 67, 82, 83, 96, 98, 99, 100, 84, 85, 106,
+- 110, 111, 114, 126, 134, 127, 133, 141, 16, 143,
+- 13, 109, 71, 74, 72, 70, 105, 108, 0, 0,
+- 132, 0, 0, 0, 0, 0, 0, 0, 0, 73,
+- 0, 0, 75, 140, 0, 0, 142
++ 15, 71, 72, 44, 45, 46, 48, 37, 12, 13,
++ 56, 57, 107, 3, 8, 110, 118, 121, 1, 119,
++ 54, 55, 64, 14, 122, 123, 124, 125, 120, 100,
++ 49, 9, 58, 20, 126, 4, 21, 22, 59, 127,
++ 65, 66, 12, 13, 60, 61, 5, 89, 90, 91,
++ 12, 13, 7, 106, 132, 133, 138, 14, 139, 104,
++ 40, 38, 134, 105, 50, 14, 41, 42, 140, 17,
++ 43, 92, 93, 94, 81, 82, 83, 84, 95, 62,
++ 63, 141, 142, 79, 80, 85, 86, 38, 87, 88,
++ 47, 52, 51, 67, 69, 53, 70, 99, 102, 101,
++ 103, 113, 109, 114, 117, 129, 136, 137, 130, 19,
++ 16, 144, 74, 112, 73, 146, 76, 75, 111, 0,
++ 135, 77, 0, 108, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 143, 0, 78, 145
+ };
+
+ static const yytype_int16 yycheck[] =
+ {
+- 5, 39, 40, 17, 18, 19, 12, 12, 17, 18,
+- 7, 8, 92, 24, 4, 95, 24, 13, 26, 3,
+- 28, 0, 25, 32, 20, 21, 22, 23, 26, 67,
+- 36, 21, 29, 42, 30, 34, 45, 46, 35, 35,
+- 43, 44, 17, 18, 25, 9, 10, 61, 62, 63,
+- 17, 18, 38, 91, 21, 22, 21, 32, 19, 24,
+- 21, 11, 29, 5, 6, 32, 15, 39, 33, 40,
+- 31, 24, 21, 22, 33, 34, 25, 14, 15, 16,
+- 53, 54, 55, 56, 21, 41, 42, 22, 51, 52,
+- 22, 57, 58, 24, 37, 16, 16, 59, 60, 27,
+- 24, 24, 24, 17, 20, 32, 35, 33, 8, 34,
+- 6, 98, 46, 49, 47, 45, 92, 95, -1, -1,
+- 125, -1, -1, -1, -1, -1, -1, -1, -1, 48,
+- -1, -1, 50, 138, -1, -1, 141
++ 8, 42, 43, 20, 21, 22, 13, 15, 18, 19,
++ 8, 9, 95, 25, 5, 98, 22, 14, 3, 25,
++ 10, 11, 26, 33, 21, 22, 23, 24, 34, 70,
++ 37, 22, 30, 43, 31, 0, 46, 47, 36, 36,
++ 44, 45, 18, 19, 6, 7, 4, 64, 65, 66,
++ 18, 19, 25, 94, 22, 23, 20, 33, 22, 25,
++ 16, 27, 30, 29, 12, 33, 22, 23, 32, 26,
++ 26, 15, 16, 17, 56, 57, 58, 59, 22, 42,
++ 43, 34, 35, 54, 55, 60, 61, 27, 62, 63,
++ 35, 40, 39, 25, 23, 41, 23, 25, 17, 38,
++ 17, 25, 28, 25, 25, 18, 36, 21, 33, 11,
++ 9, 34, 49, 101, 48, 35, 51, 50, 98, -1,
++ 128, 52, -1, 95, -1, -1, -1, -1, -1, -1,
++ -1, -1, -1, 141, -1, 53, 144
+ };
+
+ /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+ static const yytype_uint8 yystos[] =
+ {
+- 0, 3, 48, 24, 0, 4, 21, 49, 50, 17,
+- 18, 32, 58, 50, 25, 51, 49, 42, 45, 46,
+- 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
+- 68, 69, 70, 71, 58, 26, 52, 15, 21, 22,
+- 25, 71, 71, 71, 34, 12, 36, 11, 38, 39,
+- 40, 9, 10, 7, 8, 29, 35, 5, 6, 41,
+- 42, 25, 43, 44, 24, 53, 22, 22, 52, 52,
+- 62, 59, 63, 64, 65, 66, 67, 67, 68, 68,
+- 68, 68, 69, 69, 70, 70, 71, 71, 71, 14,
+- 15, 16, 21, 54, 73, 74, 24, 52, 37, 16,
+- 16, 24, 28, 52, 54, 74, 27, 54, 73, 60,
+- 24, 24, 55, 56, 24, 21, 24, 33, 13, 20,
+- 21, 22, 23, 30, 35, 57, 17, 32, 72, 21,
+- 22, 29, 58, 35, 20, 19, 21, 31, 33, 34,
+- 58, 33, 58, 34
++ 0, 3, 49, 25, 0, 4, 50, 25, 5, 22,
++ 51, 52, 18, 19, 33, 60, 52, 26, 53, 51,
++ 43, 46, 47, 60, 61, 62, 63, 64, 65, 66,
++ 67, 68, 69, 70, 71, 72, 73, 60, 27, 54,
++ 16, 22, 23, 26, 73, 73, 73, 35, 13, 37,
++ 12, 39, 40, 41, 10, 11, 8, 9, 30, 36,
++ 6, 7, 42, 43, 26, 44, 45, 25, 55, 23,
++ 23, 54, 54, 64, 61, 65, 66, 67, 68, 69,
++ 69, 70, 70, 70, 70, 71, 71, 72, 72, 73,
++ 73, 73, 15, 16, 17, 22, 56, 75, 76, 25,
++ 54, 38, 17, 17, 25, 29, 54, 56, 76, 28,
++ 56, 75, 62, 25, 25, 57, 58, 25, 22, 25,
++ 34, 14, 21, 22, 23, 24, 31, 36, 59, 18,
++ 33, 74, 22, 23, 30, 60, 36, 21, 20, 22,
++ 32, 34, 35, 60, 34, 60, 35
+ };
+
+ /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+ static const yytype_uint8 yyr1[] =
+ {
+- 0, 47, 48, 49, 49, 50, 50, 51, 51, 51,
+- 51, 51, 52, 53, 53, 54, 54, 54, 54, 55,
+- 55, 55, 55, 55, 55, 55, 56, 56, 56, 57,
+- 57, 57, 57, 57, 58, 58, 58, 59, 60, 60,
+- 61, 61, 62, 62, 63, 63, 64, 64, 65, 65,
+- 66, 66, 66, 67, 67, 67, 67, 67, 68, 68,
+- 68, 69, 69, 69, 70, 70, 70, 70, 71, 71,
+- 71, 71, 72, 72, 72, 73, 73, 73, 74, 74,
+- 74
++ 0, 48, 49, 50, 50, 51, 51, 52, 52, 53,
++ 53, 53, 53, 53, 54, 55, 55, 56, 56, 56,
++ 56, 57, 57, 57, 57, 57, 57, 57, 58, 58,
++ 58, 59, 59, 59, 59, 59, 60, 60, 60, 61,
++ 62, 62, 63, 63, 64, 64, 65, 65, 66, 66,
++ 67, 67, 68, 68, 68, 69, 69, 69, 69, 69,
++ 70, 70, 70, 71, 71, 71, 72, 72, 72, 72,
++ 73, 73, 73, 73, 74, 74, 74, 75, 75, 75,
++ 76, 76, 76
+ };
+
+ /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */
+ static const yytype_uint8 yyr2[] =
+ {
+- 0, 2, 4, 0, 2, 4, 2, 2, 3, 4,
+- 3, 4, 5, 0, 2, 4, 2, 3, 2, 2,
+- 3, 4, 2, 9, 5, 2, 0, 2, 2, 3,
+- 1, 2, 2, 2, 1, 1, 3, 1, 1, 5,
+- 1, 3, 1, 3, 1, 3, 1, 3, 1, 3,
+- 1, 3, 3, 1, 3, 3, 3, 3, 3, 3,
+- 1, 3, 3, 1, 3, 3, 3, 1, 1, 2,
+- 2, 2, 0, 2, 2, 0, 2, 2, 2, 3,
+- 2
++ 0, 2, 5, 0, 2, 0, 2, 4, 2, 2,
++ 3, 4, 3, 4, 5, 0, 2, 4, 2, 3,
++ 2, 2, 3, 4, 2, 9, 5, 2, 0, 2,
++ 2, 3, 1, 2, 2, 2, 1, 1, 3, 1,
++ 1, 5, 1, 3, 1, 3, 1, 3, 1, 3,
++ 1, 3, 1, 3, 3, 1, 3, 3, 3, 3,
++ 3, 3, 1, 3, 3, 1, 3, 3, 3, 1,
++ 1, 2, 2, 2, 0, 2, 2, 0, 2, 2,
++ 2, 3, 2
+ };
+
+
+@@ -1463,65 +1466,82 @@ yyreduce:
+ switch (yyn)
+ {
+ case 2:
+-#line 105 "dtc-parser.y" /* yacc.c:1646 */
++#line 109 "dtc-parser.y" /* yacc.c:1646 */
+ {
++ (yyvsp[0].node)->is_plugin = (yyvsp[-2].is_plugin);
+ the_boot_info = build_boot_info((yyvsp[-1].re), (yyvsp[0].node),
+ guess_boot_cpuid((yyvsp[0].node)));
+ }
+-#line 1472 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1476 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 3:
+-#line 113 "dtc-parser.y" /* yacc.c:1646 */
++#line 118 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- (yyval.re) = NULL;
++ (yyval.is_plugin) = false;
+ }
+-#line 1480 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1484 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 4:
+-#line 117 "dtc-parser.y" /* yacc.c:1646 */
++#line 122 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- (yyval.re) = chain_reserve_entry((yyvsp[-1].re), (yyvsp[0].re));
++ (yyval.is_plugin) = true;
+ }
+-#line 1488 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1492 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 5:
+-#line 124 "dtc-parser.y" /* yacc.c:1646 */
++#line 129 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- (yyval.re) = build_reserve_entry((yyvsp[-2].integer), (yyvsp[-1].integer));
++ (yyval.re) = NULL;
+ }
+-#line 1496 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1500 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 6:
+-#line 128 "dtc-parser.y" /* yacc.c:1646 */
++#line 133 "dtc-parser.y" /* yacc.c:1646 */
++ {
++ (yyval.re) = chain_reserve_entry((yyvsp[-1].re), (yyvsp[0].re));
++ }
++#line 1508 "dtc-parser.tab.c" /* yacc.c:1646 */
++ break;
++
++ case 7:
++#line 140 "dtc-parser.y" /* yacc.c:1646 */
++ {
++ (yyval.re) = build_reserve_entry((yyvsp[-2].integer), (yyvsp[-1].integer));
++ }
++#line 1516 "dtc-parser.tab.c" /* yacc.c:1646 */
++ break;
++
++ case 8:
++#line 144 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ add_label(&(yyvsp[0].re)->labels, (yyvsp[-1].labelref));
+ (yyval.re) = (yyvsp[0].re);
+ }
+-#line 1505 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1525 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 7:
+-#line 136 "dtc-parser.y" /* yacc.c:1646 */
++ case 9:
++#line 152 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.node) = name_node((yyvsp[0].node), "");
+ }
+-#line 1513 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1533 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 8:
+-#line 140 "dtc-parser.y" /* yacc.c:1646 */
++ case 10:
++#line 156 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.node) = merge_nodes((yyvsp[-2].node), (yyvsp[0].node));
+ }
+-#line 1521 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1541 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 9:
+-#line 145 "dtc-parser.y" /* yacc.c:1646 */
++ case 11:
++#line 161 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ struct node *target = get_node_by_ref((yyvsp[-3].node), (yyvsp[-1].labelref));
+
+@@ -1532,11 +1552,11 @@ yyreduce:
+ ERROR(&(yylsp[-1]), "Label or path %s not found", (yyvsp[-1].labelref));
+ (yyval.node) = (yyvsp[-3].node);
+ }
+-#line 1536 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1556 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 10:
+-#line 156 "dtc-parser.y" /* yacc.c:1646 */
++ case 12:
++#line 172 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ struct node *target = get_node_by_ref((yyvsp[-2].node), (yyvsp[-1].labelref));
+
+@@ -1546,11 +1566,11 @@ yyreduce:
+ ERROR(&(yylsp[-1]), "Label or path %s not found", (yyvsp[-1].labelref));
+ (yyval.node) = (yyvsp[-2].node);
+ }
+-#line 1550 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1570 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 11:
+-#line 166 "dtc-parser.y" /* yacc.c:1646 */
++ case 13:
++#line 182 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ struct node *target = get_node_by_ref((yyvsp[-3].node), (yyvsp[-1].labelref));
+
+@@ -1562,100 +1582,100 @@ yyreduce:
+
+ (yyval.node) = (yyvsp[-3].node);
+ }
+-#line 1566 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1586 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 12:
+-#line 181 "dtc-parser.y" /* yacc.c:1646 */
++ case 14:
++#line 197 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.node) = build_node((yyvsp[-3].proplist), (yyvsp[-2].nodelist));
+ }
+-#line 1574 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1594 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 13:
+-#line 188 "dtc-parser.y" /* yacc.c:1646 */
++ case 15:
++#line 204 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.proplist) = NULL;
+ }
+-#line 1582 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1602 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 14:
+-#line 192 "dtc-parser.y" /* yacc.c:1646 */
++ case 16:
++#line 208 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.proplist) = chain_property((yyvsp[0].prop), (yyvsp[-1].proplist));
+ }
+-#line 1590 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1610 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 15:
+-#line 199 "dtc-parser.y" /* yacc.c:1646 */
++ case 17:
++#line 215 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.prop) = build_property((yyvsp[-3].propnodename), (yyvsp[-1].data));
+ }
+-#line 1598 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1618 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 16:
+-#line 203 "dtc-parser.y" /* yacc.c:1646 */
++ case 18:
++#line 219 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.prop) = build_property((yyvsp[-1].propnodename), empty_data);
+ }
+-#line 1606 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1626 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 17:
+-#line 207 "dtc-parser.y" /* yacc.c:1646 */
++ case 19:
++#line 223 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.prop) = build_property_delete((yyvsp[-1].propnodename));
+ }
+-#line 1614 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1634 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 18:
+-#line 211 "dtc-parser.y" /* yacc.c:1646 */
++ case 20:
++#line 227 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ add_label(&(yyvsp[0].prop)->labels, (yyvsp[-1].labelref));
+ (yyval.prop) = (yyvsp[0].prop);
+ }
+-#line 1623 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1643 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 19:
+-#line 219 "dtc-parser.y" /* yacc.c:1646 */
++ case 21:
++#line 235 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.data) = data_merge((yyvsp[-1].data), (yyvsp[0].data));
+ }
+-#line 1631 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1651 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 20:
+-#line 223 "dtc-parser.y" /* yacc.c:1646 */
++ case 22:
++#line 239 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.data) = data_merge((yyvsp[-2].data), (yyvsp[-1].array).data);
+ }
+-#line 1639 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1659 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 21:
+-#line 227 "dtc-parser.y" /* yacc.c:1646 */
++ case 23:
++#line 243 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.data) = data_merge((yyvsp[-3].data), (yyvsp[-1].data));
+ }
+-#line 1647 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1667 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 22:
+-#line 231 "dtc-parser.y" /* yacc.c:1646 */
++ case 24:
++#line 247 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.data) = data_add_marker((yyvsp[-1].data), REF_PATH, (yyvsp[0].labelref));
+ }
+-#line 1655 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1675 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 23:
+-#line 235 "dtc-parser.y" /* yacc.c:1646 */
++ case 25:
++#line 251 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ FILE *f = srcfile_relative_open((yyvsp[-5].data).val, NULL);
+ struct data d;
+@@ -1671,11 +1691,11 @@ yyreduce:
+ (yyval.data) = data_merge((yyvsp[-8].data), d);
+ fclose(f);
+ }
+-#line 1675 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1695 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 24:
+-#line 251 "dtc-parser.y" /* yacc.c:1646 */
++ case 26:
++#line 267 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ FILE *f = srcfile_relative_open((yyvsp[-1].data).val, NULL);
+ struct data d = empty_data;
+@@ -1685,43 +1705,43 @@ yyreduce:
+ (yyval.data) = data_merge((yyvsp[-4].data), d);
+ fclose(f);
+ }
+-#line 1689 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1709 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 25:
+-#line 261 "dtc-parser.y" /* yacc.c:1646 */
++ case 27:
++#line 277 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref));
+ }
+-#line 1697 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1717 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 26:
+-#line 268 "dtc-parser.y" /* yacc.c:1646 */
++ case 28:
++#line 284 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.data) = empty_data;
+ }
+-#line 1705 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1725 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 27:
+-#line 272 "dtc-parser.y" /* yacc.c:1646 */
++ case 29:
++#line 288 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.data) = (yyvsp[-1].data);
+ }
+-#line 1713 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1733 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 28:
+-#line 276 "dtc-parser.y" /* yacc.c:1646 */
++ case 30:
++#line 292 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref));
+ }
+-#line 1721 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1741 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 29:
+-#line 283 "dtc-parser.y" /* yacc.c:1646 */
++ case 31:
++#line 299 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ unsigned long long bits;
+
+@@ -1737,20 +1757,20 @@ yyreduce:
+ (yyval.array).data = empty_data;
+ (yyval.array).bits = bits;
+ }
+-#line 1741 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1761 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 30:
+-#line 299 "dtc-parser.y" /* yacc.c:1646 */
++ case 32:
++#line 315 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.array).data = empty_data;
+ (yyval.array).bits = 32;
+ }
+-#line 1750 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1770 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 31:
+-#line 304 "dtc-parser.y" /* yacc.c:1646 */
++ case 33:
++#line 320 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ if ((yyvsp[-1].array).bits < 64) {
+ uint64_t mask = (1ULL << (yyvsp[-1].array).bits) - 1;
+@@ -1769,11 +1789,11 @@ yyreduce:
+
+ (yyval.array).data = data_append_integer((yyvsp[-1].array).data, (yyvsp[0].integer), (yyvsp[-1].array).bits);
+ }
+-#line 1773 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1793 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 32:
+-#line 323 "dtc-parser.y" /* yacc.c:1646 */
++ case 34:
++#line 339 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ uint64_t val = ~0ULL >> (64 - (yyvsp[-1].array).bits);
+
+@@ -1787,233 +1807,233 @@ yyreduce:
+
+ (yyval.array).data = data_append_integer((yyvsp[-1].array).data, val, (yyvsp[-1].array).bits);
+ }
+-#line 1791 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1811 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 33:
+-#line 337 "dtc-parser.y" /* yacc.c:1646 */
++ case 35:
++#line 353 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.array).data = data_add_marker((yyvsp[-1].array).data, LABEL, (yyvsp[0].labelref));
+ }
+-#line 1799 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1819 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 36:
+-#line 346 "dtc-parser.y" /* yacc.c:1646 */
++ case 38:
++#line 362 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.integer) = (yyvsp[-1].integer);
+ }
+-#line 1807 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1827 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 39:
+-#line 357 "dtc-parser.y" /* yacc.c:1646 */
++ case 41:
++#line 373 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-4].integer) ? (yyvsp[-2].integer) : (yyvsp[0].integer); }
+-#line 1813 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1833 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 41:
+-#line 362 "dtc-parser.y" /* yacc.c:1646 */
++ case 43:
++#line 378 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) || (yyvsp[0].integer); }
+-#line 1819 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1839 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 43:
+-#line 367 "dtc-parser.y" /* yacc.c:1646 */
++ case 45:
++#line 383 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) && (yyvsp[0].integer); }
+-#line 1825 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1845 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 45:
+-#line 372 "dtc-parser.y" /* yacc.c:1646 */
++ case 47:
++#line 388 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) | (yyvsp[0].integer); }
+-#line 1831 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1851 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 47:
+-#line 377 "dtc-parser.y" /* yacc.c:1646 */
++ case 49:
++#line 393 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) ^ (yyvsp[0].integer); }
+-#line 1837 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1857 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 49:
+-#line 382 "dtc-parser.y" /* yacc.c:1646 */
++ case 51:
++#line 398 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) & (yyvsp[0].integer); }
+-#line 1843 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1863 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 51:
+-#line 387 "dtc-parser.y" /* yacc.c:1646 */
++ case 53:
++#line 403 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) == (yyvsp[0].integer); }
+-#line 1849 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1869 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 52:
+-#line 388 "dtc-parser.y" /* yacc.c:1646 */
++ case 54:
++#line 404 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) != (yyvsp[0].integer); }
+-#line 1855 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1875 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 54:
+-#line 393 "dtc-parser.y" /* yacc.c:1646 */
++ case 56:
++#line 409 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) < (yyvsp[0].integer); }
+-#line 1861 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1881 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 55:
+-#line 394 "dtc-parser.y" /* yacc.c:1646 */
++ case 57:
++#line 410 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) > (yyvsp[0].integer); }
+-#line 1867 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1887 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 56:
+-#line 395 "dtc-parser.y" /* yacc.c:1646 */
++ case 58:
++#line 411 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) <= (yyvsp[0].integer); }
+-#line 1873 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1893 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 57:
+-#line 396 "dtc-parser.y" /* yacc.c:1646 */
++ case 59:
++#line 412 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) >= (yyvsp[0].integer); }
+-#line 1879 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1899 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 58:
+-#line 400 "dtc-parser.y" /* yacc.c:1646 */
++ case 60:
++#line 416 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) << (yyvsp[0].integer); }
+-#line 1885 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1905 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 59:
+-#line 401 "dtc-parser.y" /* yacc.c:1646 */
++ case 61:
++#line 417 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) >> (yyvsp[0].integer); }
+-#line 1891 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1911 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 61:
+-#line 406 "dtc-parser.y" /* yacc.c:1646 */
++ case 63:
++#line 422 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) + (yyvsp[0].integer); }
+-#line 1897 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1917 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 62:
+-#line 407 "dtc-parser.y" /* yacc.c:1646 */
++ case 64:
++#line 423 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) - (yyvsp[0].integer); }
+-#line 1903 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1923 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 64:
+-#line 412 "dtc-parser.y" /* yacc.c:1646 */
++ case 66:
++#line 428 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) * (yyvsp[0].integer); }
+-#line 1909 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1929 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 65:
+-#line 413 "dtc-parser.y" /* yacc.c:1646 */
++ case 67:
++#line 429 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) / (yyvsp[0].integer); }
+-#line 1915 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1935 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 66:
+-#line 414 "dtc-parser.y" /* yacc.c:1646 */
++ case 68:
++#line 430 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) % (yyvsp[0].integer); }
+-#line 1921 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1941 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 69:
+-#line 420 "dtc-parser.y" /* yacc.c:1646 */
++ case 71:
++#line 436 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = -(yyvsp[0].integer); }
+-#line 1927 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1947 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 70:
+-#line 421 "dtc-parser.y" /* yacc.c:1646 */
++ case 72:
++#line 437 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = ~(yyvsp[0].integer); }
+-#line 1933 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1953 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 71:
+-#line 422 "dtc-parser.y" /* yacc.c:1646 */
++ case 73:
++#line 438 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = !(yyvsp[0].integer); }
+-#line 1939 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1959 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 72:
+-#line 427 "dtc-parser.y" /* yacc.c:1646 */
++ case 74:
++#line 443 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.data) = empty_data;
+ }
+-#line 1947 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1967 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 73:
+-#line 431 "dtc-parser.y" /* yacc.c:1646 */
++ case 75:
++#line 447 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.data) = data_append_byte((yyvsp[-1].data), (yyvsp[0].byte));
+ }
+-#line 1955 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1975 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 74:
+-#line 435 "dtc-parser.y" /* yacc.c:1646 */
++ case 76:
++#line 451 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref));
+ }
+-#line 1963 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1983 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 75:
+-#line 442 "dtc-parser.y" /* yacc.c:1646 */
++ case 77:
++#line 458 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.nodelist) = NULL;
+ }
+-#line 1971 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1991 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 76:
+-#line 446 "dtc-parser.y" /* yacc.c:1646 */
++ case 78:
++#line 462 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.nodelist) = chain_node((yyvsp[-1].node), (yyvsp[0].nodelist));
+ }
+-#line 1979 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1999 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 77:
+-#line 450 "dtc-parser.y" /* yacc.c:1646 */
++ case 79:
++#line 466 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ ERROR(&(yylsp[0]), "Properties must precede subnodes");
+ YYERROR;
+ }
+-#line 1988 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 2008 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 78:
+-#line 458 "dtc-parser.y" /* yacc.c:1646 */
++ case 80:
++#line 474 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.node) = name_node((yyvsp[0].node), (yyvsp[-1].propnodename));
+ }
+-#line 1996 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 2016 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 79:
+-#line 462 "dtc-parser.y" /* yacc.c:1646 */
++ case 81:
++#line 478 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.node) = name_node(build_node_delete(), (yyvsp[-1].propnodename));
+ }
+-#line 2004 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 2024 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 80:
+-#line 466 "dtc-parser.y" /* yacc.c:1646 */
++ case 82:
++#line 482 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ add_label(&(yyvsp[0].node)->labels, (yyvsp[-1].labelref));
+ (yyval.node) = (yyvsp[0].node);
+ }
+-#line 2013 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 2033 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+
+-#line 2017 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 2037 "dtc-parser.tab.c" /* yacc.c:1646 */
+ default: break;
+ }
+ /* User semantic actions sometimes alter yychar, and that requires
+@@ -2248,7 +2268,7 @@ yyreturn:
+ #endif
+ return yyresult;
+ }
+-#line 472 "dtc-parser.y" /* yacc.c:1906 */
++#line 488 "dtc-parser.y" /* yacc.c:1906 */
+
+
+ void yyerror(char const *s)
+--- a/scripts/dtc/dtc-parser.tab.h_shipped
++++ b/scripts/dtc/dtc-parser.tab.h_shipped
+@@ -46,26 +46,27 @@ extern int yydebug;
+ enum yytokentype
+ {
+ DT_V1 = 258,
+- DT_MEMRESERVE = 259,
+- DT_LSHIFT = 260,
+- DT_RSHIFT = 261,
+- DT_LE = 262,
+- DT_GE = 263,
+- DT_EQ = 264,
+- DT_NE = 265,
+- DT_AND = 266,
+- DT_OR = 267,
+- DT_BITS = 268,
+- DT_DEL_PROP = 269,
+- DT_DEL_NODE = 270,
+- DT_PROPNODENAME = 271,
+- DT_LITERAL = 272,
+- DT_CHAR_LITERAL = 273,
+- DT_BYTE = 274,
+- DT_STRING = 275,
+- DT_LABEL = 276,
+- DT_REF = 277,
+- DT_INCBIN = 278
++ DT_PLUGIN = 259,
++ DT_MEMRESERVE = 260,
++ DT_LSHIFT = 261,
++ DT_RSHIFT = 262,
++ DT_LE = 263,
++ DT_GE = 264,
++ DT_EQ = 265,
++ DT_NE = 266,
++ DT_AND = 267,
++ DT_OR = 268,
++ DT_BITS = 269,
++ DT_DEL_PROP = 270,
++ DT_DEL_NODE = 271,
++ DT_PROPNODENAME = 272,
++ DT_LITERAL = 273,
++ DT_CHAR_LITERAL = 274,
++ DT_BYTE = 275,
++ DT_STRING = 276,
++ DT_LABEL = 277,
++ DT_REF = 278,
++ DT_INCBIN = 279
+ };
+ #endif
+
+@@ -74,7 +75,7 @@ extern int yydebug;
+ typedef union YYSTYPE YYSTYPE;
+ union YYSTYPE
+ {
+-#line 38 "dtc-parser.y" /* yacc.c:1909 */
++#line 39 "dtc-parser.y" /* yacc.c:1909 */
+
+ char *propnodename;
+ char *labelref;
+@@ -92,8 +93,9 @@ union YYSTYPE
+ struct node *nodelist;
+ struct reserve_info *re;
+ uint64_t integer;
++ bool is_plugin;
+
+-#line 97 "dtc-parser.tab.h" /* yacc.c:1909 */
++#line 99 "dtc-parser.tab.h" /* yacc.c:1909 */
+ };
+ # define YYSTYPE_IS_TRIVIAL 1
+ # define YYSTYPE_IS_DECLARED 1
+--- a/scripts/dtc/dtc-parser.y
++++ b/scripts/dtc/dtc-parser.y
+@@ -19,6 +19,7 @@
+ */
+ %{
+ #include <stdio.h>
++#include <inttypes.h>
+
+ #include "dtc.h"
+ #include "srcpos.h"
+@@ -52,9 +53,11 @@ extern bool treesource_error;
+ struct node *nodelist;
+ struct reserve_info *re;
+ uint64_t integer;
++ bool is_plugin;
+ }
+
+ %token DT_V1
++%token DT_PLUGIN
+ %token DT_MEMRESERVE
+ %token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR
+ %token DT_BITS
+@@ -71,6 +74,7 @@ extern bool treesource_error;
+
+ %type <data> propdata
+ %type <data> propdataprefix
++%type <is_plugin> plugindecl
+ %type <re> memreserve
+ %type <re> memreserves
+ %type <array> arrayprefix
+@@ -101,10 +105,22 @@ extern bool treesource_error;
+ %%
+
+ sourcefile:
+- DT_V1 ';' memreserves devicetree
++ DT_V1 ';' plugindecl memreserves devicetree
+ {
+- the_boot_info = build_boot_info($3, $4,
+- guess_boot_cpuid($4));
++ $5->is_plugin = $3;
++ the_boot_info = build_boot_info($4, $5,
++ guess_boot_cpuid($5));
++ }
++ ;
++
++plugindecl:
++ /* empty */
++ {
++ $$ = false;
++ }
++ | DT_PLUGIN ';'
++ {
++ $$ = true;
+ }
+ ;
+
+--- a/scripts/dtc/dtc.c
++++ b/scripts/dtc/dtc.c
+@@ -29,6 +29,7 @@ int reservenum; /* Number of memory res
+ int minsize; /* Minimum blob size */
+ int padsize; /* Additional padding to blob */
+ int phandle_format = PHANDLE_BOTH; /* Use linux,phandle or phandle properties */
++int symbol_fixup_support = 0;
+
+ static void fill_fullpaths(struct node *tree, const char *prefix)
+ {
+@@ -51,7 +52,7 @@ static void fill_fullpaths(struct node *
+ #define FDT_VERSION(version) _FDT_VERSION(version)
+ #define _FDT_VERSION(version) #version
+ static const char usage_synopsis[] = "dtc [options] <input file>";
+-static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:hv";
++static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:@hv";
+ static struct option const usage_long_opts[] = {
+ {"quiet", no_argument, NULL, 'q'},
+ {"in-format", a_argument, NULL, 'I'},
+@@ -69,6 +70,7 @@ static struct option const usage_long_op
+ {"phandle", a_argument, NULL, 'H'},
+ {"warning", a_argument, NULL, 'W'},
+ {"error", a_argument, NULL, 'E'},
++ {"symbols", no_argument, NULL, '@'},
+ {"help", no_argument, NULL, 'h'},
+ {"version", no_argument, NULL, 'v'},
+ {NULL, no_argument, NULL, 0x0},
+@@ -99,6 +101,7 @@ static const char * const usage_opts_hel
+ "\t\tboth - Both \"linux,phandle\" and \"phandle\" properties",
+ "\n\tEnable/disable warnings (prefix with \"no-\")",
+ "\n\tEnable/disable errors (prefix with \"no-\")",
++ "\n\tEnable symbols/fixup support",
+ "\n\tPrint this help and exit",
+ "\n\tPrint version and exit",
+ NULL,
+@@ -186,7 +189,9 @@ int main(int argc, char *argv[])
+ case 'E':
+ parse_checks_option(false, true, optarg);
+ break;
+-
++ case '@':
++ symbol_fixup_support = 1;
++ break;
+ case 'h':
+ usage(NULL);
+ default:
+--- a/scripts/dtc/dtc.h
++++ b/scripts/dtc/dtc.h
+@@ -54,6 +54,7 @@ extern int reservenum; /* Number of mem
+ extern int minsize; /* Minimum blob size */
+ extern int padsize; /* Additional padding to blob */
+ extern int phandle_format; /* Use linux,phandle or phandle properties */
++extern int symbol_fixup_support;/* enable symbols & fixup support */
+
+ #define PHANDLE_LEGACY 0x1
+ #define PHANDLE_EPAPR 0x2
+@@ -132,6 +133,26 @@ struct label {
+ struct label *next;
+ };
+
++struct fixup_entry {
++ int offset;
++ struct node *node;
++ struct property *prop;
++ struct fixup_entry *next;
++ bool local_fixup_generated;
++};
++
++struct fixup {
++ char *ref;
++ struct fixup_entry *entries;
++ struct fixup *next;
++};
++
++struct symbol {
++ struct label *label;
++ struct node *node;
++ struct symbol *next;
++};
++
+ struct property {
+ bool deleted;
+ char *name;
+@@ -158,6 +179,13 @@ struct node {
+ int addr_cells, size_cells;
+
+ struct label *labels;
++
++ struct symbol *symbols;
++ struct fixup_entry *local_fixups;
++ bool emit_local_fixup_node;
++
++ bool is_plugin;
++ struct fixup *fixups;
+ };
+
+ #define for_each_label_withdel(l0, l) \
+@@ -181,6 +209,18 @@ struct node {
+ for_each_child_withdel(n, c) \
+ if (!(c)->deleted)
+
++#define for_each_fixup(n, f) \
++ for ((f) = (n)->fixups; (f); (f) = (f)->next)
++
++#define for_each_fixup_entry(f, fe) \
++ for ((fe) = (f)->entries; (fe); (fe) = (fe)->next)
++
++#define for_each_symbol(n, s) \
++ for ((s) = (n)->symbols; (s); (s) = (s)->next)
++
++#define for_each_local_fixup_entry(n, fe) \
++ for ((fe) = (n)->local_fixups; (fe); (fe) = (fe)->next)
++
+ void add_label(struct label **labels, char *label);
+ void delete_labels(struct label **labels);
+
+--- a/scripts/dtc/flattree.c
++++ b/scripts/dtc/flattree.c
+@@ -255,6 +255,204 @@ static int stringtable_insert(struct dat
+ return i;
+ }
+
++static void emit_local_fixups(struct node *tree, struct emitter *emit,
++ void *etarget, struct data *strbuf, struct version_info *vi,
++ struct node *node)
++{
++ struct fixup_entry *fe, *fen;
++ struct node *child;
++ int nameoff, count;
++ cell_t *buf;
++ struct data d;
++
++ if (node->emit_local_fixup_node) {
++
++ /* emit the external fixups (do not emit /) */
++ if (node != tree) {
++ emit->beginnode(etarget, NULL);
++ emit->string(etarget, node->name, 0);
++ emit->align(etarget, sizeof(cell_t));
++ }
++
++ for_each_local_fixup_entry(tree, fe) {
++ if (fe->node != node || fe->local_fixup_generated)
++ continue;
++
++ /* count the number of fixup entries */
++ count = 0;
++ for_each_local_fixup_entry(tree, fen) {
++ if (fen->prop != fe->prop)
++ continue;
++ fen->local_fixup_generated = true;
++ count++;
++ }
++
++ /* allocate buffer */
++ buf = xmalloc(count * sizeof(cell_t));
++
++ /* collect all the offsets in buffer */
++ count = 0;
++ for_each_local_fixup_entry(tree, fen) {
++ if (fen->prop != fe->prop)
++ continue;
++ fen->local_fixup_generated = true;
++ buf[count++] = cpu_to_fdt32(fen->offset);
++ }
++ d = empty_data;
++ d.len = count * sizeof(cell_t);
++ d.val = (char *)buf;
++
++ nameoff = stringtable_insert(strbuf, fe->prop->name);
++ emit->property(etarget, fe->prop->labels);
++ emit->cell(etarget, count * sizeof(cell_t));
++ emit->cell(etarget, nameoff);
++
++ if ((vi->flags & FTF_VARALIGN) &&
++ (count * sizeof(cell_t)) >= 8)
++ emit->align(etarget, 8);
++
++ emit->data(etarget, d);
++ emit->align(etarget, sizeof(cell_t));
++
++ free(buf);
++ }
++ }
++
++ for_each_child(node, child)
++ emit_local_fixups(tree, emit, etarget, strbuf, vi, child);
++
++ if (node->emit_local_fixup_node && node != tree)
++ emit->endnode(etarget, tree->labels);
++}
++
++static void emit_symbols_node(struct node *tree, struct emitter *emit,
++ void *etarget, struct data *strbuf,
++ struct version_info *vi)
++{
++ struct symbol *sym;
++ int nameoff, vallen;
++
++ /* do nothing if no symbols */
++ if (!tree->symbols)
++ return;
++
++ emit->beginnode(etarget, NULL);
++ emit->string(etarget, "__symbols__", 0);
++ emit->align(etarget, sizeof(cell_t));
++
++ for_each_symbol(tree, sym) {
++
++ vallen = strlen(sym->node->fullpath);
++
++ nameoff = stringtable_insert(strbuf, sym->label->label);
++
++ emit->property(etarget, NULL);
++ emit->cell(etarget, vallen + 1);
++ emit->cell(etarget, nameoff);
++
++ if ((vi->flags & FTF_VARALIGN) && vallen >= 8)
++ emit->align(etarget, 8);
++
++ emit->string(etarget, sym->node->fullpath,
++ strlen(sym->node->fullpath));
++ emit->align(etarget, sizeof(cell_t));
++ }
++
++ emit->endnode(etarget, NULL);
++}
++
++static void emit_local_fixups_node(struct node *tree, struct emitter *emit,
++ void *etarget, struct data *strbuf,
++ struct version_info *vi)
++{
++ struct fixup_entry *fe;
++ struct node *node;
++
++ /* do nothing if no local fixups */
++ if (!tree->local_fixups)
++ return;
++
++ /* mark all nodes that need a local fixup generated (and parents) */
++ for_each_local_fixup_entry(tree, fe) {
++ node = fe->node;
++ while (node != NULL && !node->emit_local_fixup_node) {
++ node->emit_local_fixup_node = true;
++ node = node->parent;
++ }
++ }
++
++ /* emit the local fixups node now */
++ emit->beginnode(etarget, NULL);
++ emit->string(etarget, "__local_fixups__", 0);
++ emit->align(etarget, sizeof(cell_t));
++
++ emit_local_fixups(tree, emit, etarget, strbuf, vi, tree);
++
++ emit->endnode(etarget, tree->labels);
++}
++
++static void emit_fixups_node(struct node *tree, struct emitter *emit,
++ void *etarget, struct data *strbuf,
++ struct version_info *vi)
++{
++ struct fixup *f;
++ struct fixup_entry *fe;
++ char *name, *s;
++ const char *fullpath;
++ int namesz, nameoff, vallen;
++
++ /* do nothing if no fixups */
++ if (!tree->fixups)
++ return;
++
++ /* emit the external fixups */
++ emit->beginnode(etarget, NULL);
++ emit->string(etarget, "__fixups__", 0);
++ emit->align(etarget, sizeof(cell_t));
++
++ for_each_fixup(tree, f) {
++
++ namesz = 0;
++ for_each_fixup_entry(f, fe) {
++ fullpath = fe->node->fullpath;
++ if (fullpath[0] == '\0')
++ fullpath = "/";
++ namesz += strlen(fullpath) + 1;
++ namesz += strlen(fe->prop->name) + 1;
++ namesz += 32; /* space for :<number> + '\0' */
++ }
++
++ name = xmalloc(namesz);
++
++ s = name;
++ for_each_fixup_entry(f, fe) {
++ fullpath = fe->node->fullpath;
++ if (fullpath[0] == '\0')
++ fullpath = "/";
++ snprintf(s, name + namesz - s, "%s:%s:%d", fullpath,
++ fe->prop->name, fe->offset);
++ s += strlen(s) + 1;
++ }
++
++ nameoff = stringtable_insert(strbuf, f->ref);
++ vallen = s - name - 1;
++
++ emit->property(etarget, NULL);
++ emit->cell(etarget, vallen + 1);
++ emit->cell(etarget, nameoff);
++
++ if ((vi->flags & FTF_VARALIGN) && vallen >= 8)
++ emit->align(etarget, 8);
++
++ emit->string(etarget, name, vallen);
++ emit->align(etarget, sizeof(cell_t));
++
++ free(name);
++ }
++
++ emit->endnode(etarget, tree->labels);
++}
++
+ static void flatten_tree(struct node *tree, struct emitter *emit,
+ void *etarget, struct data *strbuf,
+ struct version_info *vi)
+@@ -310,6 +508,10 @@ static void flatten_tree(struct node *tr
+ flatten_tree(child, emit, etarget, strbuf, vi);
+ }
+
++ emit_symbols_node(tree, emit, etarget, strbuf, vi);
++ emit_local_fixups_node(tree, emit, etarget, strbuf, vi);
++ emit_fixups_node(tree, emit, etarget, strbuf, vi);
++
+ emit->endnode(etarget, tree->labels);
+ }
+
+--- a/scripts/dtc/version_gen.h
++++ b/scripts/dtc/version_gen.h
+@@ -1 +1 @@
+-#define DTC_VERSION "DTC 1.4.1-g9d3649bd"
++#define DTC_VERSION "DTC 1.4.1-g25efc119"
diff --git a/target/linux/brcm2708/patches-4.4/0177-config-rebuild-with-savedefconfig.patch b/target/linux/brcm2708/patches-4.4/0177-config-rebuild-with-savedefconfig.patch
deleted file mode 100644
index 34eedc1076..0000000000
--- a/target/linux/brcm2708/patches-4.4/0177-config-rebuild-with-savedefconfig.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From 0b65dbd40ad6b3d7cc979e8b7817f74b823f66ef Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Tue, 8 Mar 2016 17:08:39 +0000
-Subject: [PATCH 177/180] config: rebuild with savedefconfig
-
----
- arch/arm/configs/bcm2709_defconfig | 3 +--
- 1 file changed, 1 insertion(+), 2 deletions(-)
-
---- a/arch/arm/configs/bcm2709_defconfig
-+++ b/arch/arm/configs/bcm2709_defconfig
-@@ -593,7 +593,6 @@ CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
- CONFIG_SERIAL_OF_PLATFORM=y
- CONFIG_TTY_PRINTK=y
- CONFIG_HW_RANDOM=y
--CONFIG_HW_RANDOM_BCM2835=y
- CONFIG_RAW_DRIVER=y
- CONFIG_I2C=y
- CONFIG_I2C_CHARDEV=m
-@@ -1112,7 +1111,7 @@ CONFIG_EXTCON=m
- CONFIG_EXTCON_ARIZONA=m
- CONFIG_IIO=m
- CONFIG_IIO_BUFFER=y
--CONFIG_IIO_BUFFER_CB=y
-+CONFIG_IIO_BUFFER_CB=m
- CONFIG_IIO_KFIFO_BUF=m
- CONFIG_MCP320X=m
- CONFIG_DHT11=m
diff --git a/target/linux/brcm2708/patches-4.4/0177-configfs-implement-binary-attributes.patch b/target/linux/brcm2708/patches-4.4/0177-configfs-implement-binary-attributes.patch
new file mode 100644
index 0000000000..57c4e5b0c9
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0177-configfs-implement-binary-attributes.patch
@@ -0,0 +1,639 @@
+From 25daa4b3566d9b695d965c48a8eae312c566c709 Mon Sep 17 00:00:00 2001
+From: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
+Date: Thu, 22 Oct 2015 23:30:04 +0300
+Subject: [PATCH 177/381] configfs: implement binary attributes
+
+ConfigFS lacked binary attributes up until now. This patch
+introduces support for binary attributes in a somewhat similar
+manner of sysfs binary attributes albeit with changes that
+fit the configfs usage model.
+
+Problems that configfs binary attributes fix are everything that
+requires a binary blob as part of the configuration of a resource,
+such as bitstream loading for FPGAs, DTBs for dynamically created
+devices etc.
+
+Look at Documentation/filesystems/configfs/configfs.txt for internals
+and howto use them.
+
+This patch is against linux-next as of today that contains
+Christoph's configfs rework.
+
+Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
+[hch: folded a fix from Geert Uytterhoeven <geert+renesas@glider.be>]
+[hch: a few tiny updates based on review feedback]
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+---
+ Documentation/filesystems/configfs/configfs.txt | 57 +++++-
+ fs/configfs/configfs_internal.h | 14 +-
+ fs/configfs/dir.c | 18 +-
+ fs/configfs/file.c | 255 +++++++++++++++++++++++-
+ fs/configfs/inode.c | 2 +-
+ include/linux/configfs.h | 50 +++++
+ 6 files changed, 374 insertions(+), 22 deletions(-)
+
+--- a/Documentation/filesystems/configfs/configfs.txt
++++ b/Documentation/filesystems/configfs/configfs.txt
+@@ -51,15 +51,27 @@ configfs tree is always there, whether m
+ An item is created via mkdir(2). The item's attributes will also
+ appear at this time. readdir(3) can determine what the attributes are,
+ read(2) can query their default values, and write(2) can store new
+-values. Like sysfs, attributes should be ASCII text files, preferably
+-with only one value per file. The same efficiency caveats from sysfs
+-apply. Don't mix more than one attribute in one attribute file.
+-
+-Like sysfs, configfs expects write(2) to store the entire buffer at
+-once. When writing to configfs attributes, userspace processes should
+-first read the entire file, modify the portions they wish to change, and
+-then write the entire buffer back. Attribute files have a maximum size
+-of one page (PAGE_SIZE, 4096 on i386).
++values. Don't mix more than one attribute in one attribute file.
++
++There are two types of configfs attributes:
++
++* Normal attributes, which similar to sysfs attributes, are small ASCII text
++files, with a maximum size of one page (PAGE_SIZE, 4096 on i386). Preferably
++only one value per file should be used, and the same caveats from sysfs apply.
++Configfs expects write(2) to store the entire buffer at once. When writing to
++normal configfs attributes, userspace processes should first read the entire
++file, modify the portions they wish to change, and then write the entire
++buffer back.
++
++* Binary attributes, which are somewhat similar to sysfs binary attributes,
++but with a few slight changes to semantics. The PAGE_SIZE limitation does not
++apply, but the whole binary item must fit in single kernel vmalloc'ed buffer.
++The write(2) calls from user space are buffered, and the attributes'
++write_bin_attribute method will be invoked on the final close, therefore it is
++imperative for user-space to check the return code of close(2) in order to
++verify that the operation finished successfully.
++To avoid a malicious user OOMing the kernel, there's a per-binary attribute
++maximum buffer value.
+
+ When an item needs to be destroyed, remove it with rmdir(2). An
+ item cannot be destroyed if any other item has a link to it (via
+@@ -171,6 +183,7 @@ among other things. For that, it needs
+ struct configfs_item_operations *ct_item_ops;
+ struct configfs_group_operations *ct_group_ops;
+ struct configfs_attribute **ct_attrs;
++ struct configfs_bin_attribute **ct_bin_attrs;
+ };
+
+ The most basic function of a config_item_type is to define what
+@@ -201,6 +214,32 @@ be called whenever userspace asks for a
+ attribute is writable and provides a ->store method, that method will be
+ be called whenever userspace asks for a write(2) on the attribute.
+
++[struct configfs_bin_attribute]
++
++ struct configfs_attribute {
++ struct configfs_attribute cb_attr;
++ void *cb_private;
++ size_t cb_max_size;
++ };
++
++The binary attribute is used when the one needs to use binary blob to
++appear as the contents of a file in the item's configfs directory.
++To do so add the binary attribute to the NULL-terminated array
++config_item_type->ct_bin_attrs, and the item appears in configfs, the
++attribute file will appear with the configfs_bin_attribute->cb_attr.ca_name
++filename. configfs_bin_attribute->cb_attr.ca_mode specifies the file
++permissions.
++The cb_private member is provided for use by the driver, while the
++cb_max_size member specifies the maximum amount of vmalloc buffer
++to be used.
++
++If binary attribute is readable and the config_item provides a
++ct_item_ops->read_bin_attribute() method, that method will be called
++whenever userspace asks for a read(2) on the attribute. The converse
++will happen for write(2). The reads/writes are bufferred so only a
++single read/write will occur; the attributes' need not concern itself
++with it.
++
+ [struct config_group]
+
+ A config_item cannot live in a vacuum. The only way one can be created
+--- a/fs/configfs/configfs_internal.h
++++ b/fs/configfs/configfs_internal.h
+@@ -53,13 +53,14 @@ struct configfs_dirent {
+ #define CONFIGFS_ROOT 0x0001
+ #define CONFIGFS_DIR 0x0002
+ #define CONFIGFS_ITEM_ATTR 0x0004
++#define CONFIGFS_ITEM_BIN_ATTR 0x0008
+ #define CONFIGFS_ITEM_LINK 0x0020
+ #define CONFIGFS_USET_DIR 0x0040
+ #define CONFIGFS_USET_DEFAULT 0x0080
+ #define CONFIGFS_USET_DROPPING 0x0100
+ #define CONFIGFS_USET_IN_MKDIR 0x0200
+ #define CONFIGFS_USET_CREATING 0x0400
+-#define CONFIGFS_NOT_PINNED (CONFIGFS_ITEM_ATTR)
++#define CONFIGFS_NOT_PINNED (CONFIGFS_ITEM_ATTR | CONFIGFS_ITEM_BIN_ATTR)
+
+ extern struct mutex configfs_symlink_mutex;
+ extern spinlock_t configfs_dirent_lock;
+@@ -72,6 +73,8 @@ extern struct inode * configfs_new_inode
+ extern int configfs_create(struct dentry *, umode_t mode, void (*init)(struct inode *));
+
+ extern int configfs_create_file(struct config_item *, const struct configfs_attribute *);
++extern int configfs_create_bin_file(struct config_item *,
++ const struct configfs_bin_attribute *);
+ extern int configfs_make_dirent(struct configfs_dirent *,
+ struct dentry *, void *, umode_t, int);
+ extern int configfs_dirent_is_ready(struct configfs_dirent *);
+@@ -88,7 +91,7 @@ extern void configfs_release_fs(void);
+ extern struct rw_semaphore configfs_rename_sem;
+ extern const struct file_operations configfs_dir_operations;
+ extern const struct file_operations configfs_file_operations;
+-extern const struct file_operations bin_fops;
++extern const struct file_operations configfs_bin_file_operations;
+ extern const struct inode_operations configfs_dir_inode_operations;
+ extern const struct inode_operations configfs_root_inode_operations;
+ extern const struct inode_operations configfs_symlink_inode_operations;
+@@ -119,6 +122,13 @@ static inline struct configfs_attribute
+ return ((struct configfs_attribute *) sd->s_element);
+ }
+
++static inline struct configfs_bin_attribute *to_bin_attr(struct dentry *dentry)
++{
++ struct configfs_attribute *attr = to_attr(dentry);
++
++ return container_of(attr, struct configfs_bin_attribute, cb_attr);
++}
++
+ static inline struct config_item *configfs_get_config_item(struct dentry *dentry)
+ {
+ struct config_item * item = NULL;
+--- a/fs/configfs/dir.c
++++ b/fs/configfs/dir.c
+@@ -255,6 +255,12 @@ static void configfs_init_file(struct in
+ inode->i_fop = &configfs_file_operations;
+ }
+
++static void configfs_init_bin_file(struct inode *inode)
++{
++ inode->i_size = 0;
++ inode->i_fop = &configfs_bin_file_operations;
++}
++
+ static void init_symlink(struct inode * inode)
+ {
+ inode->i_op = &configfs_symlink_inode_operations;
+@@ -423,7 +429,9 @@ static int configfs_attach_attr(struct c
+ spin_unlock(&configfs_dirent_lock);
+
+ error = configfs_create(dentry, (attr->ca_mode & S_IALLUGO) | S_IFREG,
+- configfs_init_file);
++ (sd->s_type & CONFIGFS_ITEM_BIN_ATTR) ?
++ configfs_init_bin_file :
++ configfs_init_file);
+ if (error) {
+ configfs_put(sd);
+ return error;
+@@ -583,6 +591,7 @@ static int populate_attrs(struct config_
+ {
+ struct config_item_type *t = item->ci_type;
+ struct configfs_attribute *attr;
++ struct configfs_bin_attribute *bin_attr;
+ int error = 0;
+ int i;
+
+@@ -594,6 +603,13 @@ static int populate_attrs(struct config_
+ break;
+ }
+ }
++ if (t->ct_bin_attrs) {
++ for (i = 0; (bin_attr = t->ct_bin_attrs[i]) != NULL; i++) {
++ error = configfs_create_bin_file(item, bin_attr);
++ if (error)
++ break;
++ }
++ }
+
+ if (error)
+ detach_attrs(item);
+--- a/fs/configfs/file.c
++++ b/fs/configfs/file.c
+@@ -28,6 +28,7 @@
+ #include <linux/module.h>
+ #include <linux/slab.h>
+ #include <linux/mutex.h>
++#include <linux/vmalloc.h>
+ #include <asm/uaccess.h>
+
+ #include <linux/configfs.h>
+@@ -48,6 +49,10 @@ struct configfs_buffer {
+ struct configfs_item_operations * ops;
+ struct mutex mutex;
+ int needs_read_fill;
++ bool read_in_progress;
++ bool write_in_progress;
++ char *bin_buffer;
++ int bin_buffer_size;
+ };
+
+
+@@ -123,6 +128,87 @@ out:
+ return retval;
+ }
+
++/**
++ * configfs_read_bin_file - read a binary attribute.
++ * @file: file pointer.
++ * @buf: buffer to fill.
++ * @count: number of bytes to read.
++ * @ppos: starting offset in file.
++ *
++ * Userspace wants to read a binary attribute file. The attribute
++ * descriptor is in the file's ->d_fsdata. The target item is in the
++ * directory's ->d_fsdata.
++ *
++ * We check whether we need to refill the buffer. If so we will
++ * call the attributes' attr->read() twice. The first time we
++ * will pass a NULL as a buffer pointer, which the attributes' method
++ * will use to return the size of the buffer required. If no error
++ * occurs we will allocate the buffer using vmalloc and call
++ * attr->read() again passing that buffer as an argument.
++ * Then we just copy to user-space using simple_read_from_buffer.
++ */
++
++static ssize_t
++configfs_read_bin_file(struct file *file, char __user *buf,
++ size_t count, loff_t *ppos)
++{
++ struct configfs_buffer *buffer = file->private_data;
++ struct dentry *dentry = file->f_path.dentry;
++ struct config_item *item = to_item(dentry->d_parent);
++ struct configfs_bin_attribute *bin_attr = to_bin_attr(dentry);
++ ssize_t retval = 0;
++ ssize_t len = min_t(size_t, count, PAGE_SIZE);
++
++ mutex_lock(&buffer->mutex);
++
++ /* we don't support switching read/write modes */
++ if (buffer->write_in_progress) {
++ retval = -ETXTBSY;
++ goto out;
++ }
++ buffer->read_in_progress = 1;
++
++ if (buffer->needs_read_fill) {
++ /* perform first read with buf == NULL to get extent */
++ len = bin_attr->read(item, NULL, 0);
++ if (len <= 0) {
++ retval = len;
++ goto out;
++ }
++
++ /* do not exceed the maximum value */
++ if (bin_attr->cb_max_size && len > bin_attr->cb_max_size) {
++ retval = -EFBIG;
++ goto out;
++ }
++
++ buffer->bin_buffer = vmalloc(len);
++ if (buffer->bin_buffer == NULL) {
++ retval = -ENOMEM;
++ goto out;
++ }
++ buffer->bin_buffer_size = len;
++
++ /* perform second read to fill buffer */
++ len = bin_attr->read(item, buffer->bin_buffer, len);
++ if (len < 0) {
++ retval = len;
++ vfree(buffer->bin_buffer);
++ buffer->bin_buffer_size = 0;
++ buffer->bin_buffer = NULL;
++ goto out;
++ }
++
++ buffer->needs_read_fill = 0;
++ }
++
++ retval = simple_read_from_buffer(buf, count, ppos, buffer->bin_buffer,
++ buffer->bin_buffer_size);
++out:
++ mutex_unlock(&buffer->mutex);
++ return retval;
++}
++
+
+ /**
+ * fill_write_buffer - copy buffer from userspace.
+@@ -209,10 +295,80 @@ configfs_write_file(struct file *file, c
+ return len;
+ }
+
+-static int check_perm(struct inode * inode, struct file * file)
++/**
++ * configfs_write_bin_file - write a binary attribute.
++ * @file: file pointer
++ * @buf: data to write
++ * @count: number of bytes
++ * @ppos: starting offset
++ *
++ * Writing to a binary attribute file is similar to a normal read.
++ * We buffer the consecutive writes (binary attribute files do not
++ * support lseek) in a continuously growing buffer, but we don't
++ * commit until the close of the file.
++ */
++
++static ssize_t
++configfs_write_bin_file(struct file *file, const char __user *buf,
++ size_t count, loff_t *ppos)
++{
++ struct configfs_buffer *buffer = file->private_data;
++ struct dentry *dentry = file->f_path.dentry;
++ struct configfs_bin_attribute *bin_attr = to_bin_attr(dentry);
++ void *tbuf = NULL;
++ ssize_t len;
++
++ mutex_lock(&buffer->mutex);
++
++ /* we don't support switching read/write modes */
++ if (buffer->read_in_progress) {
++ len = -ETXTBSY;
++ goto out;
++ }
++ buffer->write_in_progress = 1;
++
++ /* buffer grows? */
++ if (*ppos + count > buffer->bin_buffer_size) {
++
++ if (bin_attr->cb_max_size &&
++ *ppos + count > bin_attr->cb_max_size) {
++ len = -EFBIG;
++ }
++
++ tbuf = vmalloc(*ppos + count);
++ if (tbuf == NULL) {
++ len = -ENOMEM;
++ goto out;
++ }
++
++ /* copy old contents */
++ if (buffer->bin_buffer) {
++ memcpy(tbuf, buffer->bin_buffer,
++ buffer->bin_buffer_size);
++ vfree(buffer->bin_buffer);
++ }
++
++ /* clear the new area */
++ memset(tbuf + buffer->bin_buffer_size, 0,
++ *ppos + count - buffer->bin_buffer_size);
++ buffer->bin_buffer = tbuf;
++ buffer->bin_buffer_size = *ppos + count;
++ }
++
++ len = simple_write_to_buffer(buffer->bin_buffer,
++ buffer->bin_buffer_size, ppos, buf, count);
++ if (len > 0)
++ *ppos += len;
++out:
++ mutex_unlock(&buffer->mutex);
++ return len;
++}
++
++static int check_perm(struct inode * inode, struct file * file, int type)
+ {
+ struct config_item *item = configfs_get_config_item(file->f_path.dentry->d_parent);
+ struct configfs_attribute * attr = to_attr(file->f_path.dentry);
++ struct configfs_bin_attribute *bin_attr = NULL;
+ struct configfs_buffer * buffer;
+ struct configfs_item_operations * ops = NULL;
+ int error = 0;
+@@ -220,6 +376,9 @@ static int check_perm(struct inode * ino
+ if (!item || !attr)
+ goto Einval;
+
++ if (type & CONFIGFS_ITEM_BIN_ATTR)
++ bin_attr = to_bin_attr(file->f_path.dentry);
++
+ /* Grab the module reference for this attribute if we have one */
+ if (!try_module_get(attr->ca_owner)) {
+ error = -ENODEV;
+@@ -236,9 +395,14 @@ static int check_perm(struct inode * ino
+ * and we must have a store method.
+ */
+ if (file->f_mode & FMODE_WRITE) {
+- if (!(inode->i_mode & S_IWUGO) || !attr->store)
++ if (!(inode->i_mode & S_IWUGO))
+ goto Eaccess;
+
++ if ((type & CONFIGFS_ITEM_ATTR) && !attr->store)
++ goto Eaccess;
++
++ if ((type & CONFIGFS_ITEM_BIN_ATTR) && !bin_attr->write)
++ goto Eaccess;
+ }
+
+ /* File needs read support.
+@@ -246,7 +410,13 @@ static int check_perm(struct inode * ino
+ * must be a show method for it.
+ */
+ if (file->f_mode & FMODE_READ) {
+- if (!(inode->i_mode & S_IRUGO) || !attr->show)
++ if (!(inode->i_mode & S_IRUGO))
++ goto Eaccess;
++
++ if ((type & CONFIGFS_ITEM_ATTR) && !attr->show)
++ goto Eaccess;
++
++ if ((type & CONFIGFS_ITEM_BIN_ATTR) && !bin_attr->read)
+ goto Eaccess;
+ }
+
+@@ -260,6 +430,8 @@ static int check_perm(struct inode * ino
+ }
+ mutex_init(&buffer->mutex);
+ buffer->needs_read_fill = 1;
++ buffer->read_in_progress = 0;
++ buffer->write_in_progress = 0;
+ buffer->ops = ops;
+ file->private_data = buffer;
+ goto Done;
+@@ -277,12 +449,7 @@ static int check_perm(struct inode * ino
+ return error;
+ }
+
+-static int configfs_open_file(struct inode * inode, struct file * filp)
+-{
+- return check_perm(inode,filp);
+-}
+-
+-static int configfs_release(struct inode * inode, struct file * filp)
++static int configfs_release(struct inode *inode, struct file *filp)
+ {
+ struct config_item * item = to_item(filp->f_path.dentry->d_parent);
+ struct configfs_attribute * attr = to_attr(filp->f_path.dentry);
+@@ -303,6 +470,47 @@ static int configfs_release(struct inode
+ return 0;
+ }
+
++static int configfs_open_file(struct inode *inode, struct file *filp)
++{
++ return check_perm(inode, filp, CONFIGFS_ITEM_ATTR);
++}
++
++static int configfs_open_bin_file(struct inode *inode, struct file *filp)
++{
++ return check_perm(inode, filp, CONFIGFS_ITEM_BIN_ATTR);
++}
++
++static int configfs_release_bin_file(struct inode *inode, struct file *filp)
++{
++ struct configfs_buffer *buffer = filp->private_data;
++ struct dentry *dentry = filp->f_path.dentry;
++ struct config_item *item = to_item(dentry->d_parent);
++ struct configfs_bin_attribute *bin_attr = to_bin_attr(dentry);
++ ssize_t len = 0;
++ int ret;
++
++ buffer->read_in_progress = 0;
++
++ if (buffer->write_in_progress) {
++ buffer->write_in_progress = 0;
++
++ len = bin_attr->write(item, buffer->bin_buffer,
++ buffer->bin_buffer_size);
++
++ /* vfree on NULL is safe */
++ vfree(buffer->bin_buffer);
++ buffer->bin_buffer = NULL;
++ buffer->bin_buffer_size = 0;
++ buffer->needs_read_fill = 1;
++ }
++
++ ret = configfs_release(inode, filp);
++ if (len < 0)
++ return len;
++ return ret;
++}
++
++
+ const struct file_operations configfs_file_operations = {
+ .read = configfs_read_file,
+ .write = configfs_write_file,
+@@ -311,6 +519,14 @@ const struct file_operations configfs_fi
+ .release = configfs_release,
+ };
+
++const struct file_operations configfs_bin_file_operations = {
++ .read = configfs_read_bin_file,
++ .write = configfs_write_bin_file,
++ .llseek = NULL, /* bin file is not seekable */
++ .open = configfs_open_bin_file,
++ .release = configfs_release_bin_file,
++};
++
+ /**
+ * configfs_create_file - create an attribute file for an item.
+ * @item: item we're creating for.
+@@ -332,3 +548,24 @@ int configfs_create_file(struct config_i
+ return error;
+ }
+
++/**
++ * configfs_create_bin_file - create a binary attribute file for an item.
++ * @item: item we're creating for.
++ * @attr: atrribute descriptor.
++ */
++
++int configfs_create_bin_file(struct config_item *item,
++ const struct configfs_bin_attribute *bin_attr)
++{
++ struct dentry *dir = item->ci_dentry;
++ struct configfs_dirent *parent_sd = dir->d_fsdata;
++ umode_t mode = (bin_attr->cb_attr.ca_mode & S_IALLUGO) | S_IFREG;
++ int error = 0;
++
++ mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_NORMAL);
++ error = configfs_make_dirent(parent_sd, NULL, (void *) bin_attr, mode,
++ CONFIGFS_ITEM_BIN_ATTR);
++ mutex_unlock(&dir->d_inode->i_mutex);
++
++ return error;
++}
+--- a/fs/configfs/inode.c
++++ b/fs/configfs/inode.c
+@@ -218,7 +218,7 @@ const unsigned char * configfs_get_name(
+ if (sd->s_type & (CONFIGFS_DIR | CONFIGFS_ITEM_LINK))
+ return sd->s_dentry->d_name.name;
+
+- if (sd->s_type & CONFIGFS_ITEM_ATTR) {
++ if (sd->s_type & (CONFIGFS_ITEM_ATTR | CONFIGFS_ITEM_BIN_ATTR)) {
+ attr = sd->s_element;
+ return attr->ca_name;
+ }
+--- a/include/linux/configfs.h
++++ b/include/linux/configfs.h
+@@ -51,6 +51,7 @@ struct module;
+ struct configfs_item_operations;
+ struct configfs_group_operations;
+ struct configfs_attribute;
++struct configfs_bin_attribute;
+ struct configfs_subsystem;
+
+ struct config_item {
+@@ -84,6 +85,7 @@ struct config_item_type {
+ struct configfs_item_operations *ct_item_ops;
+ struct configfs_group_operations *ct_group_ops;
+ struct configfs_attribute **ct_attrs;
++ struct configfs_bin_attribute **ct_bin_attrs;
+ };
+
+ /**
+@@ -154,6 +156,54 @@ static struct configfs_attribute _pfx##a
+ .store = _pfx##_name##_store, \
+ }
+
++struct file;
++struct vm_area_struct;
++
++struct configfs_bin_attribute {
++ struct configfs_attribute cb_attr; /* std. attribute */
++ void *cb_private; /* for user */
++ size_t cb_max_size; /* max core size */
++ ssize_t (*read)(struct config_item *, void *, size_t);
++ ssize_t (*write)(struct config_item *, const void *, size_t);
++};
++
++#define CONFIGFS_BIN_ATTR(_pfx, _name, _priv, _maxsz) \
++static struct configfs_bin_attribute _pfx##attr_##_name = { \
++ .cb_attr = { \
++ .ca_name = __stringify(_name), \
++ .ca_mode = S_IRUGO | S_IWUSR, \
++ .ca_owner = THIS_MODULE, \
++ }, \
++ .cb_private = _priv, \
++ .cb_max_size = _maxsz, \
++ .read = _pfx##_name##_read, \
++ .write = _pfx##_name##_write, \
++}
++
++#define CONFIGFS_BIN_ATTR_RO(_pfx, _name, _priv, _maxsz) \
++static struct configfs_attribute _pfx##attr_##_name = { \
++ .cb_attr = { \
++ .ca_name = __stringify(_name), \
++ .ca_mode = S_IRUGO, \
++ .ca_owner = THIS_MODULE, \
++ }, \
++ .cb_private = _priv, \
++ .cb_max_size = _maxsz, \
++ .read = _pfx##_name##_read, \
++}
++
++#define CONFIGFS_BIN_ATTR_WO(_pfx, _name, _priv, _maxsz) \
++static struct configfs_attribute _pfx##attr_##_name = { \
++ .cb_attr = { \
++ .ca_name = __stringify(_name), \
++ .ca_mode = S_IWUSR, \
++ .ca_owner = THIS_MODULE, \
++ }, \
++ .cb_private = _priv, \
++ .cb_max_size = _maxsz, \
++ .write = _pfx##_name##_write, \
++}
++
+ /*
+ * If allow_link() exists, the item can symlink(2) out to other
+ * items. If the item is a group, it may support mkdir(2).
diff --git a/target/linux/brcm2708/patches-4.4/0178-OF-DT-Overlay-configfs-interface.patch b/target/linux/brcm2708/patches-4.4/0178-OF-DT-Overlay-configfs-interface.patch
new file mode 100644
index 0000000000..3403cb4a08
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0178-OF-DT-Overlay-configfs-interface.patch
@@ -0,0 +1,408 @@
+From 3aebc18959f03056ba7dae3b0f769aa283ed40c0 Mon Sep 17 00:00:00 2001
+From: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
+Date: Wed, 3 Dec 2014 13:23:28 +0200
+Subject: [PATCH 178/381] OF: DT-Overlay configfs interface
+
+This is a port of Pantelis Antoniou's v3 port that makes use of the
+new upstreamed configfs support for binary attributes.
+
+Original commit message:
+
+Add a runtime interface to using configfs for generic device tree overlay
+usage. With it its possible to use device tree overlays without having
+to use a per-platform overlay manager.
+
+Please see Documentation/devicetree/configfs-overlays.txt for more info.
+
+Changes since v2:
+- Removed ifdef CONFIG_OF_OVERLAY (since for now it's required)
+- Created a documentation entry
+- Slight rewording in Kconfig
+
+Changes since v1:
+- of_resolve() -> of_resolve_phandles().
+
+Originally-signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ Documentation/devicetree/configfs-overlays.txt | 31 +++
+ drivers/of/Kconfig | 7 +
+ drivers/of/Makefile | 1 +
+ drivers/of/configfs.c | 314 +++++++++++++++++++++++++
+ 4 files changed, 353 insertions(+)
+ create mode 100644 Documentation/devicetree/configfs-overlays.txt
+ create mode 100644 drivers/of/configfs.c
+
+--- /dev/null
++++ b/Documentation/devicetree/configfs-overlays.txt
+@@ -0,0 +1,31 @@
++Howto use the configfs overlay interface.
++
++A device-tree configfs entry is created in /config/device-tree/overlays
++and and it is manipulated using standard file system I/O.
++Note that this is a debug level interface, for use by developers and
++not necessarily something accessed by normal users due to the
++security implications of having direct access to the kernel's device tree.
++
++* To create an overlay you mkdir the directory:
++
++ # mkdir /config/device-tree/overlays/foo
++
++* Either you echo the overlay firmware file to the path property file.
++
++ # echo foo.dtbo >/config/device-tree/overlays/foo/path
++
++* Or you cat the contents of the overlay to the dtbo file
++
++ # cat foo.dtbo >/config/device-tree/overlays/foo/dtbo
++
++The overlay file will be applied, and devices will be created/destroyed
++as required.
++
++To remove it simply rmdir the directory.
++
++ # rmdir /config/device-tree/overlays/foo
++
++The rationalle of the dual interface (firmware & direct copy) is that each is
++better suited to different use patterns. The firmware interface is what's
++intended to be used by hardware managers in the kernel, while the copy interface
++make sense for developers (since it avoids problems with namespaces).
+--- a/drivers/of/Kconfig
++++ b/drivers/of/Kconfig
+@@ -112,4 +112,11 @@ config OF_OVERLAY
+ While this option is selected automatically when needed, you can
+ enable it manually to improve device tree unit test coverage.
+
++config OF_CONFIGFS
++ bool "Device Tree Overlay ConfigFS interface"
++ select CONFIGFS_FS
++ select OF_OVERLAY
++ help
++ Enable a simple user-space driven DT overlay interface.
++
+ endif # OF
+--- a/drivers/of/Makefile
++++ b/drivers/of/Makefile
+@@ -1,4 +1,5 @@
+ obj-y = base.o device.o platform.o
++obj-$(CONFIG_OF_CONFIGFS) += configfs.o
+ obj-$(CONFIG_OF_DYNAMIC) += dynamic.o
+ obj-$(CONFIG_OF_FLATTREE) += fdt.o
+ obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o
+--- /dev/null
++++ b/drivers/of/configfs.c
+@@ -0,0 +1,314 @@
++/*
++ * Configfs entries for device-tree
++ *
++ * Copyright (C) 2013 - Pantelis Antoniou <panto@antoniou-consulting.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ */
++#include <linux/ctype.h>
++#include <linux/cpu.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_fdt.h>
++#include <linux/spinlock.h>
++#include <linux/slab.h>
++#include <linux/proc_fs.h>
++#include <linux/configfs.h>
++#include <linux/types.h>
++#include <linux/stat.h>
++#include <linux/limits.h>
++#include <linux/file.h>
++#include <linux/vmalloc.h>
++#include <linux/firmware.h>
++
++#include "of_private.h"
++
++struct cfs_overlay_item {
++ struct config_item item;
++
++ char path[PATH_MAX];
++
++ const struct firmware *fw;
++ struct device_node *overlay;
++ int ov_id;
++
++ void *dtbo;
++ int dtbo_size;
++};
++
++static int create_overlay(struct cfs_overlay_item *overlay, void *blob)
++{
++ int err;
++
++ /* unflatten the tree */
++ of_fdt_unflatten_tree(blob, &overlay->overlay);
++ if (overlay->overlay == NULL) {
++ pr_err("%s: failed to unflatten tree\n", __func__);
++ err = -EINVAL;
++ goto out_err;
++ }
++ pr_debug("%s: unflattened OK\n", __func__);
++
++ /* mark it as detached */
++ of_node_set_flag(overlay->overlay, OF_DETACHED);
++
++ /* perform resolution */
++ err = of_resolve_phandles(overlay->overlay);
++ if (err != 0) {
++ pr_err("%s: Failed to resolve tree\n", __func__);
++ goto out_err;
++ }
++ pr_debug("%s: resolved OK\n", __func__);
++
++ err = of_overlay_create(overlay->overlay);
++ if (err < 0) {
++ pr_err("%s: Failed to create overlay (err=%d)\n",
++ __func__, err);
++ goto out_err;
++ }
++ overlay->ov_id = err;
++
++out_err:
++ return err;
++}
++
++static inline struct cfs_overlay_item *to_cfs_overlay_item(
++ struct config_item *item)
++{
++ return item ? container_of(item, struct cfs_overlay_item, item) : NULL;
++}
++
++static ssize_t cfs_overlay_item_path_show(struct config_item *item,
++ char *page)
++{
++ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
++ return sprintf(page, "%s\n", overlay->path);
++}
++
++static ssize_t cfs_overlay_item_path_store(struct config_item *item,
++ const char *page, size_t count)
++{
++ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
++ const char *p = page;
++ char *s;
++ int err;
++
++ /* if it's set do not allow changes */
++ if (overlay->path[0] != '\0' || overlay->dtbo_size > 0)
++ return -EPERM;
++
++ /* copy to path buffer (and make sure it's always zero terminated */
++ count = snprintf(overlay->path, sizeof(overlay->path) - 1, "%s", p);
++ overlay->path[sizeof(overlay->path) - 1] = '\0';
++
++ /* strip trailing newlines */
++ s = overlay->path + strlen(overlay->path);
++ while (s > overlay->path && *--s == '\n')
++ *s = '\0';
++
++ pr_debug("%s: path is '%s'\n", __func__, overlay->path);
++
++ err = request_firmware(&overlay->fw, overlay->path, NULL);
++ if (err != 0)
++ goto out_err;
++
++ err = create_overlay(overlay, (void *)overlay->fw->data);
++ if (err != 0)
++ goto out_err;
++
++ return count;
++
++out_err:
++
++ release_firmware(overlay->fw);
++ overlay->fw = NULL;
++
++ overlay->path[0] = '\0';
++ return err;
++}
++
++static ssize_t cfs_overlay_item_status_show(struct config_item *item,
++ char *page)
++{
++ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
++
++ return sprintf(page, "%s\n",
++ overlay->ov_id >= 0 ? "applied" : "unapplied");
++}
++
++CONFIGFS_ATTR(cfs_overlay_item_, path);
++CONFIGFS_ATTR_RO(cfs_overlay_item_, status);
++
++static struct configfs_attribute *cfs_overlay_attrs[] = {
++ &cfs_overlay_item_attr_path,
++ &cfs_overlay_item_attr_status,
++ NULL,
++};
++
++ssize_t cfs_overlay_item_dtbo_read(struct config_item *item,
++ void *buf, size_t max_count)
++{
++ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
++
++ pr_debug("%s: buf=%p max_count=%u\n", __func__,
++ buf, max_count);
++
++ if (overlay->dtbo == NULL)
++ return 0;
++
++ /* copy if buffer provided */
++ if (buf != NULL) {
++ /* the buffer must be large enough */
++ if (overlay->dtbo_size > max_count)
++ return -ENOSPC;
++
++ memcpy(buf, overlay->dtbo, overlay->dtbo_size);
++ }
++
++ return overlay->dtbo_size;
++}
++
++ssize_t cfs_overlay_item_dtbo_write(struct config_item *item,
++ const void *buf, size_t count)
++{
++ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
++ int err;
++
++ /* if it's set do not allow changes */
++ if (overlay->path[0] != '\0' || overlay->dtbo_size > 0)
++ return -EPERM;
++
++ /* copy the contents */
++ overlay->dtbo = kmemdup(buf, count, GFP_KERNEL);
++ if (overlay->dtbo == NULL)
++ return -ENOMEM;
++
++ overlay->dtbo_size = count;
++
++ err = create_overlay(overlay, overlay->dtbo);
++ if (err != 0)
++ goto out_err;
++
++ return count;
++
++out_err:
++ kfree(overlay->dtbo);
++ overlay->dtbo = NULL;
++ overlay->dtbo_size = 0;
++
++ return err;
++}
++
++CONFIGFS_BIN_ATTR(cfs_overlay_item_, dtbo, NULL, SZ_1M);
++
++static struct configfs_bin_attribute *cfs_overlay_bin_attrs[] = {
++ &cfs_overlay_item_attr_dtbo,
++ NULL,
++};
++
++static void cfs_overlay_release(struct config_item *item)
++{
++ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
++
++ if (overlay->ov_id >= 0)
++ of_overlay_destroy(overlay->ov_id);
++ if (overlay->fw)
++ release_firmware(overlay->fw);
++ /* kfree with NULL is safe */
++ kfree(overlay->dtbo);
++ kfree(overlay);
++}
++
++static struct configfs_item_operations cfs_overlay_item_ops = {
++ .release = cfs_overlay_release,
++};
++
++static struct config_item_type cfs_overlay_type = {
++ .ct_item_ops = &cfs_overlay_item_ops,
++ .ct_attrs = cfs_overlay_attrs,
++ .ct_bin_attrs = cfs_overlay_bin_attrs,
++ .ct_owner = THIS_MODULE,
++};
++
++static struct config_item *cfs_overlay_group_make_item(
++ struct config_group *group, const char *name)
++{
++ struct cfs_overlay_item *overlay;
++
++ overlay = kzalloc(sizeof(*overlay), GFP_KERNEL);
++ if (!overlay)
++ return ERR_PTR(-ENOMEM);
++ overlay->ov_id = -1;
++
++ config_item_init_type_name(&overlay->item, name, &cfs_overlay_type);
++ return &overlay->item;
++}
++
++static void cfs_overlay_group_drop_item(struct config_group *group,
++ struct config_item *item)
++{
++ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
++
++ config_item_put(&overlay->item);
++}
++
++static struct configfs_group_operations overlays_ops = {
++ .make_item = cfs_overlay_group_make_item,
++ .drop_item = cfs_overlay_group_drop_item,
++};
++
++static struct config_item_type overlays_type = {
++ .ct_group_ops = &overlays_ops,
++ .ct_owner = THIS_MODULE,
++};
++
++static struct configfs_group_operations of_cfs_ops = {
++ /* empty - we don't allow anything to be created */
++};
++
++static struct config_item_type of_cfs_type = {
++ .ct_group_ops = &of_cfs_ops,
++ .ct_owner = THIS_MODULE,
++};
++
++struct config_group of_cfs_overlay_group;
++
++struct config_group *of_cfs_def_groups[] = {
++ &of_cfs_overlay_group,
++ NULL
++};
++
++static struct configfs_subsystem of_cfs_subsys = {
++ .su_group = {
++ .cg_item = {
++ .ci_namebuf = "device-tree",
++ .ci_type = &of_cfs_type,
++ },
++ .default_groups = of_cfs_def_groups,
++ },
++ .su_mutex = __MUTEX_INITIALIZER(of_cfs_subsys.su_mutex),
++};
++
++static int __init of_cfs_init(void)
++{
++ int ret;
++
++ pr_info("%s\n", __func__);
++
++ config_group_init(&of_cfs_subsys.su_group);
++ config_group_init_type_name(&of_cfs_overlay_group, "overlays",
++ &overlays_type);
++
++ ret = configfs_register_subsystem(&of_cfs_subsys);
++ if (ret != 0) {
++ pr_err("%s: failed to register subsys\n", __func__);
++ goto out;
++ }
++ pr_info("%s: OK\n", __func__);
++out:
++ return ret;
++}
++late_initcall(of_cfs_init);
diff --git a/target/linux/brcm2708/patches-4.4/0178-config-Add-module-for-mcp3422-ADC.patch b/target/linux/brcm2708/patches-4.4/0178-config-Add-module-for-mcp3422-ADC.patch
deleted file mode 100644
index d6c1a75fa8..0000000000
--- a/target/linux/brcm2708/patches-4.4/0178-config-Add-module-for-mcp3422-ADC.patch
+++ /dev/null
@@ -1,30 +0,0 @@
-From 1e19acaf4b88ee6dcbe8843a07a04edf177be7c3 Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Tue, 8 Mar 2016 17:06:33 +0000
-Subject: [PATCH 178/180] config: Add module for mcp3422 ADC
-
----
- arch/arm/configs/bcm2709_defconfig | 1 +
- arch/arm/configs/bcmrpi_defconfig | 1 +
- 2 files changed, 2 insertions(+)
-
---- a/arch/arm/configs/bcm2709_defconfig
-+++ b/arch/arm/configs/bcm2709_defconfig
-@@ -1114,6 +1114,7 @@ CONFIG_IIO_BUFFER=y
- CONFIG_IIO_BUFFER_CB=m
- CONFIG_IIO_KFIFO_BUF=m
- CONFIG_MCP320X=m
-+CONFIG_MCP3422=m
- CONFIG_DHT11=m
- CONFIG_PWM_BCM2835=m
- CONFIG_RASPBERRYPI_FIRMWARE=y
---- a/arch/arm/configs/bcmrpi_defconfig
-+++ b/arch/arm/configs/bcmrpi_defconfig
-@@ -1121,6 +1121,7 @@ CONFIG_IIO_BUFFER=y
- CONFIG_IIO_BUFFER_CB=m
- CONFIG_IIO_KFIFO_BUF=m
- CONFIG_MCP320X=m
-+CONFIG_MCP3422=m
- CONFIG_DHT11=m
- CONFIG_PWM_BCM2835=m
- CONFIG_RASPBERRYPI_FIRMWARE=y
diff --git a/target/linux/brcm2708/patches-4.4/0179-Pi3-DT-Add-pull-ups-on-the-UART-RX-lines.patch b/target/linux/brcm2708/patches-4.4/0179-Pi3-DT-Add-pull-ups-on-the-UART-RX-lines.patch
deleted file mode 100644
index 794a7bb4d5..0000000000
--- a/target/linux/brcm2708/patches-4.4/0179-Pi3-DT-Add-pull-ups-on-the-UART-RX-lines.patch
+++ /dev/null
@@ -1,40 +0,0 @@
-From e064caf725672cb95cc8327f4dc55d3de257cd74 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Tue, 8 Mar 2016 16:18:57 +0000
-Subject: [PATCH 179/180] Pi3 DT: Add pull-ups on the UART RX lines
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- arch/arm/boot/dts/bcm2710-rpi-3-b.dts | 4 ++--
- arch/arm/boot/dts/overlays/pi3-miniuart-bt-overlay.dts | 2 +-
- 2 files changed, 3 insertions(+), 3 deletions(-)
-
---- a/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
-+++ b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
-@@ -53,13 +53,13 @@
- uart0_pins: uart0_pins {
- brcm,pins = <32 33>;
- brcm,function = <7>; /* alt3=UART0 */
-- brcm,pull = <0 0>;
-+ brcm,pull = <0 2>;
- };
-
- uart1_pins: uart1_pins {
- brcm,pins = <14 15>;
- brcm,function = <2>; /* alt5=UART1 */
-- brcm,pull = <0 0>;
-+ brcm,pull = <0 2>;
- };
- };
-
---- a/arch/arm/boot/dts/overlays/pi3-miniuart-bt-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/pi3-miniuart-bt-overlay.dts
-@@ -46,7 +46,7 @@
- uart1_pins: uart1_pins {
- brcm,pins = <32 33>;
- brcm,function = <2>; /* alt5=UART1 */
-- brcm,pull = <0 0>;
-+ brcm,pull = <0 2>;
- };
- };
- };
diff --git a/target/linux/brcm2708/patches-4.4/0179-Protect-__release_resource-against-resources-without.patch b/target/linux/brcm2708/patches-4.4/0179-Protect-__release_resource-against-resources-without.patch
new file mode 100644
index 0000000000..234244205a
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0179-Protect-__release_resource-against-resources-without.patch
@@ -0,0 +1,28 @@
+From e48f4b37e5fbb039bee4fde22469f383cc98a1d8 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 13 Mar 2015 12:43:36 +0000
+Subject: [PATCH 179/381] Protect __release_resource against resources without
+ parents
+
+Without this patch, removing a device tree overlay can crash here.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ kernel/resource.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/kernel/resource.c
++++ b/kernel/resource.c
+@@ -237,6 +237,12 @@ static int __release_resource(struct res
+ {
+ struct resource *tmp, **p;
+
++ if (!old->parent) {
++ WARN(old->sibling, "sibling but no parent");
++ if (old->sibling)
++ return -EINVAL;
++ return 0;
++ }
+ p = &old->parent->child;
+ for (;;) {
+ tmp = *p;
diff --git a/target/linux/brcm2708/patches-4.4/0180-BCM270X_DT-Add-a-.dtbo-target-use-for-overlays.patch b/target/linux/brcm2708/patches-4.4/0180-BCM270X_DT-Add-a-.dtbo-target-use-for-overlays.patch
new file mode 100644
index 0000000000..644a6bbdd9
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0180-BCM270X_DT-Add-a-.dtbo-target-use-for-overlays.patch
@@ -0,0 +1,193 @@
+From 4bc79db3fb0734cc6de0ddfc4b95c2db0f3f8607 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 13 Mar 2015 20:00:21 +0000
+Subject: [PATCH 180/381] BCM270X_DT: Add a .dtbo target, use for overlays
+
+Change the filenames and extensions to keep the pre-DDT style of
+overlay (<name>-overlay.dtb) distinct from new ones that use a
+different style of local fixups (<name>.dtbo), and to match other
+platforms.
+
+The RPi firmware uses the DDTK trailer atom to choose which type of
+overlay to use for each kernel.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/.gitignore | 2 +-
+ arch/arm/boot/dts/overlays/Makefile | 135 +++++++++++++++++-------------------
+ scripts/Makefile.lib | 10 +++
+ 3 files changed, 76 insertions(+), 71 deletions(-)
+
+--- a/arch/arm/boot/.gitignore
++++ b/arch/arm/boot/.gitignore
+@@ -3,4 +3,4 @@ zImage
+ xipImage
+ bootpImage
+ uImage
+-*.dtb
++*.dtb*
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -12,78 +12,73 @@ ifeq ($(CONFIG_ARCH_BCM2835),y)
+ RPI_DT_OVERLAYS=y
+ endif
+
+-dtb-$(RPI_DT_OVERLAYS) += ads7846-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += at86rf233-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += bmp085_i2c-sensor-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += dwc2-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += dwc-otg-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += dht11-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += enc28j60-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += gpio-ir-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += gpio-poweroff-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += hifiberry-amp-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += hifiberry-dac-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += hifiberry-dacplus-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += hifiberry-digi-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += hy28a-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += hy28b-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += i2c-rtc-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += i2c-gpio-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += i2c0-bcm2708-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += i2c1-bcm2708-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += i2s-mmap-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += iqaudio-dac-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += iqaudio-dacplus-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += lirc-rpi-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += mcp2515-can0-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += mcp2515-can1-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += mmc-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += mz61581-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += pi3-disable-bt-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += pi3-miniuart-bt-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += piscreen-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += piscreen2r-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += pitft28-capacitive-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += pitft28-resistive-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += pps-gpio-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += pwm-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += pwm-2chan-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += raspidac3-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += rpi-backlight-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += rpi-dac-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += rpi-display-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += rpi-ft5406-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += rpi-proto-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += rpi-sense-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += sdhost-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += sdio-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += sdtweak-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += smi-dev-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += smi-nand-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += smi-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += spi1-1cs-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += spi1-2cs-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += spi1-3cs-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += spi2-1cs-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += spi2-2cs-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += spi2-3cs-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += spi-gpio35-39-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += tinylcd35-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += uart1-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += vc4-kms-v3d-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += vga666-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += w1-gpio-overlay.dtb
+-dtb-$(RPI_DT_OVERLAYS) += w1-gpio-pullup-overlay.dtb
++dtbo-$(RPI_DT_OVERLAYS) += ads7846.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += at86rf233.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += bmp085_i2c-sensor.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += dwc2.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += dwc-otg.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += dht11.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += enc28j60.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += gpio-ir.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += gpio-poweroff.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += hifiberry-amp.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += hifiberry-dac.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += hifiberry-dacplus.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += hifiberry-digi.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += hy28a.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += hy28b.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += i2c-rtc.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += i2c-gpio.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += i2c0-bcm2708.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += i2c1-bcm2708.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += i2s-mmap.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += iqaudio-dac.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += iqaudio-dacplus.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += lirc-rpi.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += mcp2515-can0.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += mcp2515-can1.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += mmc.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += mz61581.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += pi3-disable-bt.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += pi3-miniuart-bt.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += piscreen.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += piscreen2r.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += pitft28-capacitive.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += pitft28-resistive.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += pps-gpio.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += pwm.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += pwm-2chan.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += raspidac3.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += rpi-backlight.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += rpi-dac.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += rpi-display.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += rpi-ft5406.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += rpi-proto.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += rpi-sense.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += sdhost.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += sdio.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += sdtweak.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += smi-dev.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += smi-nand.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += smi.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += spi1-1cs.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += spi1-2cs.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += spi1-3cs.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += spi2-1cs.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += spi2-2cs.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += spi2-3cs.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += spi-gpio35-39.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += tinylcd35.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += uart1.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += vc4-kms-v3d.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += vga666.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += w1-gpio.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += w1-gpio-pullup.dtbo
+
+ targets += dtbs dtbs_install
+-targets += $(dtb-y)
++targets += $(dtbo-y)
+
+ endif
+
+-always := $(dtb-y)
+-clean-files := *.dtb
+-
+-# Enable fixups to support overlays on BCM2708 platforms
+-ifeq ($(RPI_DT_OVERLAYS),y)
+- DTC_FLAGS ?= -@
+-endif
++always := $(dtbo-y)
++clean-files := *.dtbo
+--- a/scripts/Makefile.lib
++++ b/scripts/Makefile.lib
+@@ -292,6 +292,16 @@ cmd_dtc = mkdir -p $(dir ${dtc-tmp}) ; \
+ $(obj)/%.dtb: $(src)/%.dts FORCE
+ $(call if_changed_dep,dtc)
+
++quiet_cmd_dtco = DTCO $@
++cmd_dtco = $(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ; \
++ $(objtree)/scripts/dtc/dtc -@ -O dtb -o $@ -b 0 \
++ -i $(dir $<) $(DTC_FLAGS) \
++ -d $(depfile).dtc.tmp $(dtc-tmp) ; \
++ cat $(depfile).pre.tmp $(depfile).dtc.tmp > $(depfile)
++
++$(obj)/%.dtbo: $(src)/%-overlay.dts FORCE
++ $(call if_changed_dep,dtco)
++
+ dtc-tmp = $(subst $(comma),_,$(dot-target).dts.tmp)
+
+ # Bzip2
diff --git a/target/linux/brcm2708/patches-4.4/0181-scripts-knlinfo-Decode-DDTK-atom.patch b/target/linux/brcm2708/patches-4.4/0181-scripts-knlinfo-Decode-DDTK-atom.patch
new file mode 100644
index 0000000000..f5a7c5eaff
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0181-scripts-knlinfo-Decode-DDTK-atom.patch
@@ -0,0 +1,31 @@
+From 6d7bc67f5af641afffc88fdc55940ccf53831f00 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 29 May 2015 11:18:58 +0100
+Subject: [PATCH 181/381] scripts/knlinfo: Decode DDTK atom
+
+Show the DDTK atom as being a boolean.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ scripts/knlinfo | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/scripts/knlinfo
++++ b/scripts/knlinfo
+@@ -16,6 +16,7 @@ my $trailer_magic = 'RPTL';
+
+ my %atom_formats =
+ (
++ 'DDTK' => \&format_bool,
+ 'DTOK' => \&format_bool,
+ 'KVer' => \&format_string,
+ '270X' => \&format_bool,
+@@ -148,7 +149,7 @@ sub format_atom
+ sub format_bool
+ {
+ my ($data) = @_;
+- return unpack('V', $data) ? 'true' : 'false';
++ return unpack('V', $data) ? 'y' : 'n';
+ }
+
+ sub format_int
diff --git a/target/linux/brcm2708/patches-4.4/0182-Enable-Dynamic-Device-Tree-for-bcmrpi_defconfig-and-.patch b/target/linux/brcm2708/patches-4.4/0182-Enable-Dynamic-Device-Tree-for-bcmrpi_defconfig-and-.patch
new file mode 100644
index 0000000000..5a4bb8e2a0
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0182-Enable-Dynamic-Device-Tree-for-bcmrpi_defconfig-and-.patch
@@ -0,0 +1,40 @@
+From ec7710516621d3131c7e025a73ab8354ec21f7f8 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 29 May 2015 11:48:59 +0100
+Subject: [PATCH 182/381] Enable Dynamic Device Tree for bcmrpi_defconfig and
+ bcm2709_defconfig
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/configs/bcm2709_defconfig | 2 +-
+ arch/arm/configs/bcmrpi_defconfig | 1 +
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+--- a/arch/arm/configs/bcm2709_defconfig
++++ b/arch/arm/configs/bcm2709_defconfig
+@@ -403,6 +403,7 @@ CONFIG_MTD=m
+ CONFIG_MTD_BLOCK=m
+ CONFIG_MTD_NAND=m
+ CONFIG_MTD_UBI=m
++CONFIG_OF_CONFIGFS=y
+ CONFIG_ZRAM=m
+ CONFIG_ZRAM_LZ4_COMPRESS=y
+ CONFIG_BLK_DEV_LOOP=y
+@@ -1161,7 +1162,6 @@ CONFIG_NTFS_FS=m
+ CONFIG_NTFS_RW=y
+ CONFIG_TMPFS=y
+ CONFIG_TMPFS_POSIX_ACL=y
+-CONFIG_CONFIGFS_FS=y
+ CONFIG_ECRYPT_FS=m
+ CONFIG_HFS_FS=m
+ CONFIG_HFSPLUS_FS=m
+--- a/arch/arm/configs/bcmrpi_defconfig
++++ b/arch/arm/configs/bcmrpi_defconfig
+@@ -396,6 +396,7 @@ CONFIG_MTD=m
+ CONFIG_MTD_BLOCK=m
+ CONFIG_MTD_NAND=m
+ CONFIG_MTD_UBI=m
++CONFIG_OF_OVERLAY=y
+ CONFIG_ZRAM=m
+ CONFIG_ZRAM_LZ4_COMPRESS=y
+ CONFIG_BLK_DEV_LOOP=y
diff --git a/target/linux/brcm2708/patches-4.4/0183-SQUASH-Add-CONFIG_OF_CONFIGFS-to-bcmrpi_defconfig.patch b/target/linux/brcm2708/patches-4.4/0183-SQUASH-Add-CONFIG_OF_CONFIGFS-to-bcmrpi_defconfig.patch
new file mode 100644
index 0000000000..33f8af9958
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0183-SQUASH-Add-CONFIG_OF_CONFIGFS-to-bcmrpi_defconfig.patch
@@ -0,0 +1,29 @@
+From 47f46fe81c376e006950445ca739f48aad4432e5 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Sun, 13 Mar 2016 16:14:44 +0000
+Subject: [PATCH 183/381] SQUASH: Add CONFIG_OF_CONFIGFS to bcmrpi_defconfig
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/configs/bcmrpi_defconfig | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/arch/arm/configs/bcmrpi_defconfig
++++ b/arch/arm/configs/bcmrpi_defconfig
+@@ -396,7 +396,7 @@ CONFIG_MTD=m
+ CONFIG_MTD_BLOCK=m
+ CONFIG_MTD_NAND=m
+ CONFIG_MTD_UBI=m
+-CONFIG_OF_OVERLAY=y
++CONFIG_OF_CONFIGFS=y
+ CONFIG_ZRAM=m
+ CONFIG_ZRAM_LZ4_COMPRESS=y
+ CONFIG_BLK_DEV_LOOP=y
+@@ -1169,7 +1169,6 @@ CONFIG_NTFS_FS=m
+ CONFIG_NTFS_RW=y
+ CONFIG_TMPFS=y
+ CONFIG_TMPFS_POSIX_ACL=y
+-CONFIG_CONFIGFS_FS=y
+ CONFIG_ECRYPT_FS=m
+ CONFIG_HFS_FS=m
+ CONFIG_HFSPLUS_FS=m
diff --git a/target/linux/brcm2708/patches-4.4/0184-dts-kbuild-dtbs_install-installs-.dtbo-files-too.patch b/target/linux/brcm2708/patches-4.4/0184-dts-kbuild-dtbs_install-installs-.dtbo-files-too.patch
new file mode 100644
index 0000000000..794734c96d
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0184-dts-kbuild-dtbs_install-installs-.dtbo-files-too.patch
@@ -0,0 +1,42 @@
+From b05ecd40ad5513486d9e38752a1f64f48be20839 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 14 Mar 2016 16:56:54 +0000
+Subject: [PATCH 184/381] dts, kbuild: dtbs_install installs .dtbo files too
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ scripts/Makefile.dtbinst | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+--- a/scripts/Makefile.dtbinst
++++ b/scripts/Makefile.dtbinst
+@@ -29,6 +29,7 @@ ifeq ("$(dtbinst-root)", "$(obj)")
+ endif
+
+ dtbinst-files := $(dtb-y)
++dtboinst-files := $(dtbo-y)
+ dtbinst-dirs := $(dts-dirs)
+
+ # Helper targets for Installing DTBs into the boot directory
+@@ -37,15 +38,18 @@ quiet_cmd_dtb_install = INSTALL $<
+
+ install-dir = $(patsubst $(dtbinst-root)%,$(INSTALL_DTBS_PATH)%,$(obj))
+
+-$(dtbinst-files) $(dtbinst-dirs): | __dtbs_install_prep
++$(dtbinst-files) $(dtboinst-files) $(dtbinst-dirs): | __dtbs_install_prep
+
+ $(dtbinst-files): %.dtb: $(obj)/%.dtb
+ $(call cmd,dtb_install,$(install-dir))
+
++$(dtboinst-files): %.dtbo: $(obj)/%.dtbo
++ $(call cmd,dtb_install,$(install-dir))
++
+ $(dtbinst-dirs):
+ $(Q)$(MAKE) $(dtbinst)=$(obj)/$@
+
+-PHONY += $(dtbinst-files) $(dtbinst-dirs)
+-__dtbs_install: $(dtbinst-files) $(dtbinst-dirs)
++PHONY += $(dtbinst-files) $(dtboinst-files) $(dtbinst-dirs)
++__dtbs_install: $(dtbinst-files) $(dtboinst-files) $(dtbinst-dirs)
+
+ .PHONY: $(PHONY)
diff --git a/target/linux/brcm2708/patches-4.4/0185-bcm2835-sdhost-Workaround-for-slow-sectors.patch b/target/linux/brcm2708/patches-4.4/0185-bcm2835-sdhost-Workaround-for-slow-sectors.patch
new file mode 100644
index 0000000000..289aa1a94c
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0185-bcm2835-sdhost-Workaround-for-slow-sectors.patch
@@ -0,0 +1,118 @@
+From 34269be91afc30ac33e70f37418969b9694f9fad Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Tue, 15 Mar 2016 14:10:29 +0000
+Subject: [PATCH 185/381] bcm2835-sdhost: Workaround for "slow" sectors
+
+Some cards have been seen to cause timeouts after certain sectors are
+read. This workaround enforces a minimum delay between the stop after
+reading one of those sectors and a subsequent data command.
+
+Using CMD23 (SET_BLOCK_COUNT) avoids this problem, so good cards will
+not be penalised by this workaround.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/mmc/host/bcm2835-sdhost.c | 50 +++++++++++++++++++++++++++++++++++----
+ 1 file changed, 46 insertions(+), 4 deletions(-)
+
+--- a/drivers/mmc/host/bcm2835-sdhost.c
++++ b/drivers/mmc/host/bcm2835-sdhost.c
+@@ -202,9 +202,12 @@ struct bcm2835_host {
+ int max_delay; /* maximum length of time spent waiting */
+ struct timeval stop_time; /* when the last stop was issued */
+ u32 delay_after_stop; /* minimum time between stop and subsequent data transfer */
++ u32 delay_after_this_stop; /* minimum time between this stop and subsequent data transfer */
+ u32 overclock_50; /* frequency to use when 50MHz is requested (in MHz) */
+ u32 overclock; /* Current frequency if overclocked, else zero */
+ u32 pio_limit; /* Maximum block count for PIO (0 = always DMA) */
++
++ u32 sectors; /* Cached card size in sectors */
+ };
+
+ #if ENABLE_LOG
+@@ -425,6 +428,7 @@ static void bcm2835_sdhost_reset_interna
+ bcm2835_sdhost_set_power(host, true);
+ mdelay(10);
+ host->clock = 0;
++ host->sectors = 0;
+ bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
+ bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
+ mmiowb();
+@@ -880,6 +884,24 @@ static void bcm2835_sdhost_prepare_data(
+ host->flush_fifo = 0;
+ host->data->bytes_xfered = 0;
+
++ if (!host->sectors && host->mmc->card) {
++ struct mmc_card *card = host->mmc->card;
++ if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
++ /*
++ * The EXT_CSD sector count is in number of 512 byte
++ * sectors.
++ */
++ host->sectors = card->ext_csd.sectors;
++ } else {
++ /*
++ * The CSD capacity field is in units of read_blkbits.
++ * set_capacity takes units of 512 bytes.
++ */
++ host->sectors = card->csd.capacity <<
++ (card->csd.read_blkbits - 9);
++ }
++ }
++
+ if (!host->dma_desc) {
+ /* Use PIO */
+ int flags = SG_MITER_ATOMIC;
+@@ -989,7 +1011,7 @@ bool bcm2835_sdhost_send_command(struct
+
+ if (cmd->data) {
+ log_event("CMDD", cmd->data->blocks, cmd->data->blksz);
+- if (host->delay_after_stop) {
++ if (host->delay_after_this_stop) {
+ struct timeval now;
+ int time_since_stop;
+ do_gettimeofday(&now);
+@@ -998,12 +1020,32 @@ bool bcm2835_sdhost_send_command(struct
+ /* Possibly less than one second */
+ time_since_stop = time_since_stop * 1000000 +
+ (now.tv_usec - host->stop_time.tv_usec);
+- if (time_since_stop < host->delay_after_stop)
+- udelay(host->delay_after_stop -
++ if (time_since_stop <
++ host->delay_after_this_stop)
++ udelay(host->delay_after_this_stop -
+ time_since_stop);
+ }
+ }
+
++ host->delay_after_this_stop = host->delay_after_stop;
++ if ((cmd->data->flags & MMC_DATA_READ) && !host->use_sbc) {
++ /* See if read crosses one of the hazardous sectors */
++ u32 first_blk, last_blk;
++
++ /* Intentionally include the following sector because
++ without CMD23/SBC the read may run on. */
++ first_blk = host->mrq->cmd->arg;
++ last_blk = first_blk + cmd->data->blocks;
++
++ if (((last_blk >= (host->sectors - 64)) &&
++ (first_blk <= (host->sectors - 64))) ||
++ ((last_blk >= (host->sectors - 32)) &&
++ (first_blk <= (host->sectors - 32)))) {
++ host->delay_after_this_stop =
++ max(250u, host->delay_after_stop);
++ }
++ }
++
+ if (cmd->data->flags & MMC_DATA_WRITE)
+ sdcmd |= SDCMD_WRITE_CMD;
+ if (cmd->data->flags & MMC_DATA_READ)
+@@ -1078,7 +1120,7 @@ static void bcm2835_sdhost_transfer_comp
+ if (!host->use_busy)
+ bcm2835_sdhost_finish_command(host, NULL);
+
+- if (host->delay_after_stop)
++ if (host->delay_after_this_stop)
+ do_gettimeofday(&host->stop_time);
+ }
+ } else {
diff --git a/target/linux/brcm2708/patches-4.4/0186-BCM270X_DT-Add-labels-to-spidev-nodes.patch b/target/linux/brcm2708/patches-4.4/0186-BCM270X_DT-Add-labels-to-spidev-nodes.patch
new file mode 100644
index 0000000000..7d8c2531ee
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0186-BCM270X_DT-Add-labels-to-spidev-nodes.patch
@@ -0,0 +1,114 @@
+From a5b8204a864f7f9a5a30c6b673e735138c3bdba3 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Tue, 15 Mar 2016 15:49:16 +0000
+Subject: [PATCH 186/381] BCM270X_DT: Add labels to spidev nodes
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 4 ++--
+ arch/arm/boot/dts/bcm2708-rpi-b.dts | 4 ++--
+ arch/arm/boot/dts/bcm2708-rpi-cm.dts | 4 ++--
+ arch/arm/boot/dts/bcm2709-rpi-2-b.dts | 4 ++--
+ arch/arm/boot/dts/bcm2710-rpi-3-b.dts | 4 ++--
+ 5 files changed, 10 insertions(+), 10 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
++++ b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
+@@ -59,7 +59,7 @@
+ pinctrl-0 = <&spi0_pins &spi0_cs_pins>;
+ cs-gpios = <&gpio 8 1>, <&gpio 7 1>;
+
+- spidev@0{
++ spidev0: spidev@0{
+ compatible = "spidev";
+ reg = <0>; /* CE0 */
+ #address-cells = <1>;
+@@ -67,7 +67,7 @@
+ spi-max-frequency = <500000>;
+ };
+
+- spidev@1{
++ spidev1: spidev@1{
+ compatible = "spidev";
+ reg = <1>; /* CE1 */
+ #address-cells = <1>;
+--- a/arch/arm/boot/dts/bcm2708-rpi-b.dts
++++ b/arch/arm/boot/dts/bcm2708-rpi-b.dts
+@@ -59,7 +59,7 @@
+ pinctrl-0 = <&spi0_pins &spi0_cs_pins>;
+ cs-gpios = <&gpio 8 1>, <&gpio 7 1>;
+
+- spidev@0{
++ spidev0: spidev@0{
+ compatible = "spidev";
+ reg = <0>; /* CE0 */
+ #address-cells = <1>;
+@@ -67,7 +67,7 @@
+ spi-max-frequency = <500000>;
+ };
+
+- spidev@1{
++ spidev1: spidev@1{
+ compatible = "spidev";
+ reg = <1>; /* CE1 */
+ #address-cells = <1>;
+--- a/arch/arm/boot/dts/bcm2708-rpi-cm.dts
++++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dts
+@@ -42,7 +42,7 @@
+ pinctrl-0 = <&spi0_pins &spi0_cs_pins>;
+ cs-gpios = <&gpio 8 1>, <&gpio 7 1>;
+
+- spidev@0{
++ spidev0: spidev@0{
+ compatible = "spidev";
+ reg = <0>; /* CE0 */
+ #address-cells = <1>;
+@@ -50,7 +50,7 @@
+ spi-max-frequency = <500000>;
+ };
+
+- spidev@1{
++ spidev1: spidev@1{
+ compatible = "spidev";
+ reg = <1>; /* CE1 */
+ #address-cells = <1>;
+--- a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts
++++ b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts
+@@ -59,7 +59,7 @@
+ pinctrl-0 = <&spi0_pins &spi0_cs_pins>;
+ cs-gpios = <&gpio 8 1>, <&gpio 7 1>;
+
+- spidev@0{
++ spidev0: spidev@0{
+ compatible = "spidev";
+ reg = <0>; /* CE0 */
+ #address-cells = <1>;
+@@ -67,7 +67,7 @@
+ spi-max-frequency = <500000>;
+ };
+
+- spidev@1{
++ spidev1: spidev@1{
+ compatible = "spidev";
+ reg = <1>; /* CE1 */
+ #address-cells = <1>;
+--- a/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
++++ b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
+@@ -110,7 +110,7 @@
+ pinctrl-0 = <&spi0_pins &spi0_cs_pins>;
+ cs-gpios = <&gpio 8 1>, <&gpio 7 1>;
+
+- spidev@0{
++ spidev0: spidev@0{
+ compatible = "spidev";
+ reg = <0>; /* CE0 */
+ #address-cells = <1>;
+@@ -118,7 +118,7 @@
+ spi-max-frequency = <500000>;
+ };
+
+- spidev@1{
++ spidev1: spidev@1{
+ compatible = "spidev";
+ reg = <1>; /* CE1 */
+ #address-cells = <1>;
diff --git a/target/linux/brcm2708/patches-4.4/0187-BCM270X_DT-Use-spidev-labels-in-overlays.patch b/target/linux/brcm2708/patches-4.4/0187-BCM270X_DT-Use-spidev-labels-in-overlays.patch
new file mode 100644
index 0000000000..4eaeccca2d
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0187-BCM270X_DT-Use-spidev-labels-in-overlays.patch
@@ -0,0 +1,628 @@
+From 9bdfa67fd35978aed2d711821302bc30a3aa2667 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Tue, 15 Mar 2016 16:27:26 +0000
+Subject: [PATCH 187/381] BCM270X_DT: Use spidev labels in overlays
+
+---
+ arch/arm/boot/dts/overlays/ads7846-overlay.dts | 22 ++++++++++-------
+ arch/arm/boot/dts/overlays/at86rf233-overlay.dts | 11 +++++----
+ arch/arm/boot/dts/overlays/enc28j60-overlay.dts | 11 +++++----
+ arch/arm/boot/dts/overlays/hy28a-overlay.dts | 22 ++++++++++-------
+ arch/arm/boot/dts/overlays/hy28b-overlay.dts | 22 ++++++++++-------
+ .../arm/boot/dts/overlays/mcp2515-can0-overlay.dts | 16 ++++++++-----
+ .../arm/boot/dts/overlays/mcp2515-can1-overlay.dts | 16 ++++++++-----
+ arch/arm/boot/dts/overlays/mz61581-overlay.dts | 22 ++++++++++-------
+ arch/arm/boot/dts/overlays/piscreen-overlay.dts | 22 ++++++++++-------
+ arch/arm/boot/dts/overlays/piscreen2r-overlay.dts | 22 ++++++++++-------
+ .../dts/overlays/pitft28-capacitive-overlay.dts | 17 +++++++------
+ .../dts/overlays/pitft28-resistive-overlay.dts | 24 ++++++++++++-------
+ arch/arm/boot/dts/overlays/rpi-display-overlay.dts | 22 ++++++++++-------
+ arch/arm/boot/dts/overlays/tinylcd35-overlay.dts | 28 +++++++++++++---------
+ 14 files changed, 174 insertions(+), 103 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/ads7846-overlay.dts
++++ b/arch/arm/boot/dts/overlays/ads7846-overlay.dts
+@@ -13,18 +13,24 @@
+ target = <&spi0>;
+ __overlay__ {
+ status = "okay";
++ };
++ };
+
+- spidev@0{
+- status = "disabled";
+- };
++ fragment@1 {
++ target = <&spidev0>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
+
+- spidev@1{
+- status = "disabled";
+- };
++ fragment@2 {
++ target = <&spidev1>;
++ __overlay__ {
++ status = "disabled";
+ };
+ };
+
+- fragment@1 {
++ fragment@3 {
+ target = <&gpio>;
+ __overlay__ {
+ ads7846_pins: ads7846_pins {
+@@ -35,7 +41,7 @@
+ };
+ };
+
+- fragment@2 {
++ fragment@4 {
+ target = <&spi0>;
+ __overlay__ {
+ /* needed to avoid dtc warning */
+--- a/arch/arm/boot/dts/overlays/at86rf233-overlay.dts
++++ b/arch/arm/boot/dts/overlays/at86rf233-overlay.dts
+@@ -14,10 +14,6 @@
+
+ status = "okay";
+
+- spidev@0{
+- status = "disabled";
+- };
+-
+ lowpan0: at86rf233@0 {
+ compatible = "atmel,at86rf233";
+ reg = <0>;
+@@ -32,6 +28,13 @@
+ };
+
+ fragment@1 {
++ target = <&spidev0>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@2 {
+ target = <&gpio>;
+ __overlay__ {
+ lowpan0_pins: lowpan0_pins {
+--- a/arch/arm/boot/dts/overlays/enc28j60-overlay.dts
++++ b/arch/arm/boot/dts/overlays/enc28j60-overlay.dts
+@@ -14,10 +14,6 @@
+
+ status = "okay";
+
+- spidev@0{
+- status = "disabled";
+- };
+-
+ eth1: enc28j60@0{
+ compatible = "microchip,enc28j60";
+ reg = <0>; /* CE0 */
+@@ -32,6 +28,13 @@
+ };
+
+ fragment@1 {
++ target = <&spidev0>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@2 {
+ target = <&gpio>;
+ __overlay__ {
+ eth1_pins: eth1_pins {
+--- a/arch/arm/boot/dts/overlays/hy28a-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hy28a-overlay.dts
+@@ -13,18 +13,24 @@
+ target = <&spi0>;
+ __overlay__ {
+ status = "okay";
++ };
++ };
+
+- spidev@0{
+- status = "disabled";
+- };
++ fragment@1 {
++ target = <&spidev0>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
+
+- spidev@1{
+- status = "disabled";
+- };
++ fragment@2 {
++ target = <&spidev1>;
++ __overlay__ {
++ status = "disabled";
+ };
+ };
+
+- fragment@1 {
++ fragment@3 {
+ target = <&gpio>;
+ __overlay__ {
+ hy28a_pins: hy28a_pins {
+@@ -34,7 +40,7 @@
+ };
+ };
+
+- fragment@2 {
++ fragment@4 {
+ target = <&spi0>;
+ __overlay__ {
+ /* needed to avoid dtc warning */
+--- a/arch/arm/boot/dts/overlays/hy28b-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hy28b-overlay.dts
+@@ -13,18 +13,24 @@
+ target = <&spi0>;
+ __overlay__ {
+ status = "okay";
++ };
++ };
+
+- spidev@0{
+- status = "disabled";
+- };
++ fragment@1 {
++ target = <&spidev0>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
+
+- spidev@1{
+- status = "disabled";
+- };
++ fragment@2 {
++ target = <&spidev1>;
++ __overlay__ {
++ status = "disabled";
+ };
+ };
+
+- fragment@1 {
++ fragment@3 {
+ target = <&gpio>;
+ __overlay__ {
+ hy28b_pins: hy28b_pins {
+@@ -34,7 +40,7 @@
+ };
+ };
+
+- fragment@2 {
++ fragment@4 {
+ target = <&spi0>;
+ __overlay__ {
+ /* needed to avoid dtc warning */
+--- a/arch/arm/boot/dts/overlays/mcp2515-can0-overlay.dts
++++ b/arch/arm/boot/dts/overlays/mcp2515-can0-overlay.dts
+@@ -12,14 +12,18 @@
+ target = <&spi0>;
+ __overlay__ {
+ status = "okay";
+- spidev@0{
+- status = "disabled";
+- };
+ };
+ };
+
+- /* the interrupt pin of the can-controller */
+ fragment@1 {
++ target = <&spidev0>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
++ /* the interrupt pin of the can-controller */
++ fragment@2 {
+ target = <&gpio>;
+ __overlay__ {
+ can0_pins: can0_pins {
+@@ -30,7 +34,7 @@
+ };
+
+ /* the clock/oscillator of the can-controller */
+- fragment@2 {
++ fragment@3 {
+ target-path = "/clocks";
+ __overlay__ {
+ /* external oscillator of mcp2515 on SPI0.0 */
+@@ -43,7 +47,7 @@
+ };
+
+ /* the spi config of the can-controller itself binding everything together */
+- fragment@3 {
++ fragment@4 {
+ target = <&spi0>;
+ __overlay__ {
+ /* needed to avoid dtc warning */
+--- a/arch/arm/boot/dts/overlays/mcp2515-can1-overlay.dts
++++ b/arch/arm/boot/dts/overlays/mcp2515-can1-overlay.dts
+@@ -12,14 +12,18 @@
+ target = <&spi0>;
+ __overlay__ {
+ status = "okay";
+- spidev@1{
+- status = "disabled";
+- };
+ };
+ };
+
+- /* the interrupt pin of the can-controller */
+ fragment@1 {
++ target = <&spidev1>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
++ /* the interrupt pin of the can-controller */
++ fragment@2 {
+ target = <&gpio>;
+ __overlay__ {
+ can1_pins: can1_pins {
+@@ -30,7 +34,7 @@
+ };
+
+ /* the clock/oscillator of the can-controller */
+- fragment@2 {
++ fragment@3 {
+ target-path = "/clocks";
+ __overlay__ {
+ /* external oscillator of mcp2515 on spi0.1 */
+@@ -43,7 +47,7 @@
+ };
+
+ /* the spi config of the can-controller itself binding everything together */
+- fragment@3 {
++ fragment@4 {
+ target = <&spi0>;
+ __overlay__ {
+ /* needed to avoid dtc warning */
+--- a/arch/arm/boot/dts/overlays/mz61581-overlay.dts
++++ b/arch/arm/boot/dts/overlays/mz61581-overlay.dts
+@@ -13,18 +13,24 @@
+ target = <&spi0>;
+ __overlay__ {
+ status = "okay";
++ };
++ };
+
+- spidev@0{
+- status = "disabled";
+- };
++ fragment@1 {
++ target = <&spidev0>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
+
+- spidev@1{
+- status = "disabled";
+- };
++ fragment@2 {
++ target = <&spidev1>;
++ __overlay__ {
++ status = "disabled";
+ };
+ };
+
+- fragment@1 {
++ fragment@3 {
+ target = <&gpio>;
+ __overlay__ {
+ mz61581_pins: mz61581_pins {
+@@ -34,7 +40,7 @@
+ };
+ };
+
+- fragment@2 {
++ fragment@4 {
+ target = <&spi0>;
+ __overlay__ {
+ /* needed to avoid dtc warning */
+--- a/arch/arm/boot/dts/overlays/piscreen-overlay.dts
++++ b/arch/arm/boot/dts/overlays/piscreen-overlay.dts
+@@ -13,18 +13,24 @@
+ target = <&spi0>;
+ __overlay__ {
+ status = "okay";
++ };
++ };
+
+- spidev@0{
+- status = "disabled";
+- };
++ fragment@1 {
++ target = <&spidev0>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
+
+- spidev@1{
+- status = "disabled";
+- };
++ fragment@2 {
++ target = <&spidev1>;
++ __overlay__ {
++ status = "disabled";
+ };
+ };
+
+- fragment@1 {
++ fragment@3 {
+ target = <&gpio>;
+ __overlay__ {
+ piscreen_pins: piscreen_pins {
+@@ -34,7 +40,7 @@
+ };
+ };
+
+- fragment@2 {
++ fragment@4 {
+ target = <&spi0>;
+ __overlay__ {
+ /* needed to avoid dtc warning */
+--- a/arch/arm/boot/dts/overlays/piscreen2r-overlay.dts
++++ b/arch/arm/boot/dts/overlays/piscreen2r-overlay.dts
+@@ -13,18 +13,24 @@
+ target = <&spi0>;
+ __overlay__ {
+ status = "okay";
++ };
++ };
+
+- spidev@0{
+- status = "disabled";
+- };
++ fragment@1 {
++ target = <&spidev0>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
+
+- spidev@1{
+- status = "disabled";
+- };
++ fragment@2 {
++ target = <&spidev1>;
++ __overlay__ {
++ status = "disabled";
+ };
+ };
+
+- fragment@1 {
++ fragment@3 {
+ target = <&gpio>;
+ __overlay__ {
+ piscreen2_pins: piscreen2_pins {
+@@ -34,7 +40,7 @@
+ };
+ };
+
+- fragment@2 {
++ fragment@4 {
+ target = <&spi0>;
+ __overlay__ {
+ /* needed to avoid dtc warning */
+--- a/arch/arm/boot/dts/overlays/pitft28-capacitive-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pitft28-capacitive-overlay.dts
+@@ -13,14 +13,17 @@
+ target = <&spi0>;
+ __overlay__ {
+ status = "okay";
+-
+- spidev@0{
+- status = "disabled";
+- };
+ };
+ };
+
+- fragment@1 {
++ fragment@1 {
++ target = <&spidev0>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@2 {
+ target = <&gpio>;
+ __overlay__ {
+ pitft_pins: pitft_pins {
+@@ -31,7 +34,7 @@
+ };
+ };
+
+- fragment@2 {
++ fragment@3 {
+ target = <&spi0>;
+ __overlay__ {
+ /* needed to avoid dtc warning */
+@@ -55,7 +58,7 @@
+ };
+ };
+
+- fragment@3 {
++ fragment@4 {
+ target = <&i2c1>;
+ __overlay__ {
+ /* needed to avoid dtc warning */
+--- a/arch/arm/boot/dts/overlays/pitft28-resistive-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pitft28-resistive-overlay.dts
+@@ -13,18 +13,24 @@
+ target = <&spi0>;
+ __overlay__ {
+ status = "okay";
++ };
++ };
+
+- spidev@0{
+- status = "disabled";
+- };
++ fragment@1 {
++ target = <&spidev0>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
+
+- spidev@1{
+- status = "disabled";
+- };
++ fragment@2 {
++ target = <&spidev1>;
++ __overlay__ {
++ status = "disabled";
+ };
+ };
+
+- fragment@1 {
++ fragment@3 {
+ target = <&gpio>;
+ __overlay__ {
+ pitft_pins: pitft_pins {
+@@ -35,7 +41,7 @@
+ };
+ };
+
+- fragment@2 {
++ fragment@4 {
+ target = <&spi0>;
+ __overlay__ {
+ /* needed to avoid dtc warning */
+@@ -95,7 +101,7 @@
+ };
+ };
+
+- fragment@3 {
++ fragment@5 {
+ target-path = "/soc";
+ __overlay__ {
+ backlight {
+--- a/arch/arm/boot/dts/overlays/rpi-display-overlay.dts
++++ b/arch/arm/boot/dts/overlays/rpi-display-overlay.dts
+@@ -13,18 +13,24 @@
+ target = <&spi0>;
+ __overlay__ {
+ status = "okay";
++ };
++ };
+
+- spidev@0{
+- status = "disabled";
+- };
++ fragment@1 {
++ target = <&spidev0>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
+
+- spidev@1{
+- status = "disabled";
+- };
++ fragment@2 {
++ target = <&spidev1>;
++ __overlay__ {
++ status = "disabled";
+ };
+ };
+
+- fragment@1 {
++ fragment@3 {
+ target = <&gpio>;
+ __overlay__ {
+ rpi_display_pins: rpi_display_pins {
+@@ -35,7 +41,7 @@
+ };
+ };
+
+- fragment@2 {
++ fragment@4 {
+ target = <&spi0>;
+ __overlay__ {
+ /* needed to avoid dtc warning */
+--- a/arch/arm/boot/dts/overlays/tinylcd35-overlay.dts
++++ b/arch/arm/boot/dts/overlays/tinylcd35-overlay.dts
+@@ -30,18 +30,24 @@
+ target = <&spi0>;
+ __overlay__ {
+ status = "okay";
++ };
++ };
+
+- spidev@0{
+- status = "disabled";
+- };
++ fragment@1 {
++ target = <&spidev0>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
+
+- spidev@1{
+- status = "disabled";
+- };
++ fragment@2 {
++ target = <&spidev1>;
++ __overlay__ {
++ status = "disabled";
+ };
+ };
+
+- fragment@1 {
++ fragment@3 {
+ target = <&gpio>;
+ __overlay__ {
+ tinylcd35_pins: tinylcd35_pins {
+@@ -60,7 +66,7 @@
+ };
+ };
+
+- fragment@2 {
++ fragment@4 {
+ target = <&spi0>;
+ __overlay__ {
+ /* needed to avoid dtc warning */
+@@ -124,7 +130,7 @@
+
+ /* RTC */
+
+- fragment@3 {
++ fragment@5 {
+ target = <&i2c1>;
+ __overlay__ {
+ #address-cells = <1>;
+@@ -138,7 +144,7 @@
+ };
+ };
+
+- fragment@4 {
++ fragment@6 {
+ target = <&i2c1>;
+ __overlay__ {
+ #address-cells = <1>;
+@@ -156,7 +162,7 @@
+ * Values for input event code is found under the
+ * 'Keys and buttons' heading in include/uapi/linux/input.h
+ */
+- fragment@5 {
++ fragment@7 {
+ target-path = "/soc";
+ __overlay__ {
+ keypad: keypad {
diff --git a/target/linux/brcm2708/patches-4.4/0188-BCM270X_DT-Build-and-document-the-wittypi-overlay.patch b/target/linux/brcm2708/patches-4.4/0188-BCM270X_DT-Build-and-document-the-wittypi-overlay.patch
new file mode 100644
index 0000000000..4a98476f55
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0188-BCM270X_DT-Build-and-document-the-wittypi-overlay.patch
@@ -0,0 +1,50 @@
+From 32afb8961b9c5f51dc8e88832f47b8ef197acf32 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Tue, 15 Mar 2016 16:41:37 +0000
+Subject: [PATCH 188/381] BCM270X_DT: Build and document the wittypi overlay
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 8 ++++++++
+ arch/arm/boot/dts/overlays/wittypi-overlay.dts | 2 +-
+ 3 files changed, 10 insertions(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -74,6 +74,7 @@ dtbo-$(RPI_DT_OVERLAYS) += vc4-kms-v3d.d
+ dtbo-$(RPI_DT_OVERLAYS) += vga666.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += w1-gpio.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += w1-gpio-pullup.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += wittypi.dtbo
+
+ targets += dtbs dtbs_install
+ targets += $(dtbo-y)
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -920,6 +920,14 @@ Params: gpiopin GPIO for
+ extpullup GPIO for external pullup (default "5")
+
+
++Name: wittypi
++Info: Configures the wittypi RTC module.
++Load: dtoverlay=wittypi,<param>=<val>
++Params: led_gpio GPIO for LED (default "17")
++ led_trigger Choose which activity the LED tracks (default
++ "default-on")
++
++
+ Troubleshooting
+ ===============
+
+--- a/arch/arm/boot/dts/overlays/wittypi-overlay.dts
++++ b/arch/arm/boot/dts/overlays/wittypi-overlay.dts
+@@ -37,7 +37,7 @@
+ };
+
+ __overrides__ {
+- led_gpio = <&wittypi_led>,"gpios:4";
++ led_gpio = <&wittypi_led>,"gpios:4";
+ led_trigger = <&wittypi_led>,"linux,default-trigger";
+ };
+
diff --git a/target/linux/brcm2708/patches-4.4/0189-scripts-dtc-Fix-UMR-causing-corrupt-dtbo-overlay-fil.patch b/target/linux/brcm2708/patches-4.4/0189-scripts-dtc-Fix-UMR-causing-corrupt-dtbo-overlay-fil.patch
new file mode 100644
index 0000000000..e78f7d60a4
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0189-scripts-dtc-Fix-UMR-causing-corrupt-dtbo-overlay-fil.patch
@@ -0,0 +1,27 @@
+From e3a356dd422147d4d96aa0c9378551363b1a5b99 Mon Sep 17 00:00:00 2001
+From: Matthias Reichl <hias@horus.com>
+Date: Tue, 15 Mar 2016 21:13:39 +0100
+Subject: [PATCH 189/381] scripts/dtc: Fix UMR causing corrupt dtbo overlay
+ files
+
+struct fixup_entry is allocated from the heap but it's member
+local_fixup_generated was never initialized. This lead to
+corrupted dtbo files.
+
+Fix this by initializing local_fixup_generated to false.
+
+Signed-off-by: Matthias Reichl <hias@horus.com>
+---
+ scripts/dtc/checks.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/scripts/dtc/checks.c
++++ b/scripts/dtc/checks.c
+@@ -523,6 +523,7 @@ static void fixup_phandle_references(str
+ fe->prop = prop;
+ fe->offset = m->offset;
+ fe->next = NULL;
++ fe->local_fixup_generated = false;
+
+ /* append it to the local fixups */
+ fep = &dt->local_fixups;
diff --git a/target/linux/brcm2708/patches-4.4/0190-BCM270X_DT-Add-dtparam-for-uart1.patch b/target/linux/brcm2708/patches-4.4/0190-BCM270X_DT-Add-dtparam-for-uart1.patch
new file mode 100644
index 0000000000..14b8dc0fc1
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0190-BCM270X_DT-Add-dtparam-for-uart1.patch
@@ -0,0 +1,77 @@
+From 1f72100e701440d4c65e4eeaed3fcfdc553d69f5 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Wed, 16 Mar 2016 08:35:06 +0000
+Subject: [PATCH 190/381] BCM270X_DT: Add dtparam for uart1
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 1 +
+ arch/arm/boot/dts/bcm2708-rpi-b.dts | 1 +
+ arch/arm/boot/dts/bcm2708-rpi-cm.dts | 1 +
+ arch/arm/boot/dts/bcm2709-rpi-2-b.dts | 1 +
+ arch/arm/boot/dts/bcm2710-rpi-3-b.dts | 1 +
+ arch/arm/boot/dts/overlays/README | 3 +++
+ 6 files changed, 8 insertions(+)
+
+--- a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
++++ b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
+@@ -120,6 +120,7 @@
+ __overrides__ {
+ uart0 = <&uart0>,"status";
+ uart0_clkrate = <&clk_uart0>,"clock-frequency:0";
++ uart1 = <&uart1>,"status";
+ i2s = <&i2s>,"status";
+ spi = <&spi0>,"status";
+ i2c0 = <&i2c0>,"status";
+--- a/arch/arm/boot/dts/bcm2708-rpi-b.dts
++++ b/arch/arm/boot/dts/bcm2708-rpi-b.dts
+@@ -114,6 +114,7 @@
+ __overrides__ {
+ uart0 = <&uart0>,"status";
+ uart0_clkrate = <&clk_uart0>,"clock-frequency:0";
++ uart1 = <&uart1>,"status";
+ i2s = <&i2s>,"status";
+ spi = <&spi0>,"status";
+ i2c0 = <&i2c0>,"status";
+--- a/arch/arm/boot/dts/bcm2708-rpi-cm.dts
++++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dts
+@@ -89,6 +89,7 @@
+ __overrides__ {
+ uart0 = <&uart0>,"status";
+ uart0_clkrate = <&clk_uart0>,"clock-frequency:0";
++ uart1 = <&uart1>,"status";
+ i2s = <&i2s>,"status";
+ spi = <&spi0>,"status";
+ i2c0 = <&i2c0>,"status";
+--- a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts
++++ b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts
+@@ -120,6 +120,7 @@
+ __overrides__ {
+ uart0 = <&uart0>,"status";
+ uart0_clkrate = <&clk_uart0>,"clock-frequency:0";
++ uart1 = <&uart1>,"status";
+ i2s = <&i2s>,"status";
+ spi = <&spi0>,"status";
+ i2c0 = <&i2c0>,"status";
+--- a/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
++++ b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
+@@ -171,6 +171,7 @@
+ __overrides__ {
+ uart0 = <&uart0>,"status";
+ uart0_clkrate = <&clk_uart0>,"clock-frequency:0";
++ uart1 = <&uart1>,"status";
+ i2s = <&i2s>,"status";
+ spi = <&spi0>,"status";
+ i2c0 = <&i2c0>,"status";
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -124,6 +124,9 @@ Params:
+
+ uart0 Set to "off" to disable uart0 (default "on")
+
++ uart1 Set to "on" or "off" to enable or disable uart1
++ (default varies)
++
+ watchdog Set to "on" to enable the hardware watchdog
+ (default "off")
+
diff --git a/target/linux/brcm2708/patches-4.4/0191-dwc-overlay-Use-label-so-overrides-can-apply.patch b/target/linux/brcm2708/patches-4.4/0191-dwc-overlay-Use-label-so-overrides-can-apply.patch
new file mode 100644
index 0000000000..657138001e
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0191-dwc-overlay-Use-label-so-overrides-can-apply.patch
@@ -0,0 +1,34 @@
+From 0945d95f5b98b323f6a611e2bb96a3400fd91d41 Mon Sep 17 00:00:00 2001
+From: Przemek Rudy <prudy1@o2.pl>
+Date: Fri, 11 Mar 2016 22:41:26 +0100
+Subject: [PATCH 191/381] dwc-overlay: Use label so overrides can apply.
+
+---
+ arch/arm/boot/dts/overlays/dwc2-overlay.dts | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/dwc2-overlay.dts
++++ b/arch/arm/boot/dts/overlays/dwc2-overlay.dts
+@@ -8,7 +8,7 @@
+ target = <&usb>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+- __overlay__ {
++ dwc2_usb: __overlay__ {
+ compatible = "brcm,bcm2835-usb";
+ reg = <0x7e980000 0x10000>;
+ interrupts = <1 9>;
+@@ -21,9 +21,9 @@
+ };
+
+ __overrides__ {
+- dr_mode = <&usb>, "dr_mode";
+- g-np-tx-fifo-size = <&usb>,"g-np-tx-fifo-size:0";
+- g-rx-fifo-size = <&usb>,"g-rx-fifo-size:0";
+- g-tx-fifo-size = <&usb>,"g-tx-fifo-size:0";
++ dr_mode = <&dwc2_usb>, "dr_mode";
++ g-np-tx-fifo-size = <&dwc2_usb>,"g-np-tx-fifo-size:0";
++ g-rx-fifo-size = <&dwc2_usb>,"g-rx-fifo-size:0";
++ g-tx-fifo-size = <&dwc2_usb>,"g-tx-fifo-size:0";
+ };
+ };
diff --git a/target/linux/brcm2708/patches-4.4/0192-drm-vc4-Add-a-debugfs-node-for-tracking-execution-st.patch b/target/linux/brcm2708/patches-4.4/0192-drm-vc4-Add-a-debugfs-node-for-tracking-execution-st.patch
new file mode 100644
index 0000000000..8fe5b51baf
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0192-drm-vc4-Add-a-debugfs-node-for-tracking-execution-st.patch
@@ -0,0 +1,56 @@
+From fe67c3546abaaab10d826626fdd3dd147f6bd693 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Fri, 22 Jan 2016 13:06:39 -0800
+Subject: [PATCH 192/381] drm/vc4: Add a debugfs node for tracking execution
+ state.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_debugfs.c | 1 +
+ drivers/gpu/drm/vc4/vc4_drv.h | 1 +
+ drivers/gpu/drm/vc4/vc4_gem.c | 14 ++++++++++++++
+ 3 files changed, 16 insertions(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_debugfs.c
++++ b/drivers/gpu/drm/vc4/vc4_debugfs.c
+@@ -17,6 +17,7 @@
+
+ static const struct drm_info_list vc4_debugfs_list[] = {
+ {"bo_stats", vc4_bo_stats_debugfs, 0},
++ {"gem_exec", vc4_gem_exec_debugfs, 0},
+ {"hdmi_regs", vc4_hdmi_debugfs_regs, 0},
+ {"hvs_regs", vc4_hvs_debugfs_regs, 0},
+ {"crtc0_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)0},
+--- a/drivers/gpu/drm/vc4/vc4_drv.h
++++ b/drivers/gpu/drm/vc4/vc4_drv.h
+@@ -403,6 +403,7 @@ void vc4_job_handle_completed(struct vc4
+ int vc4_queue_seqno_cb(struct drm_device *dev,
+ struct vc4_seqno_cb *cb, uint64_t seqno,
+ void (*func)(struct vc4_seqno_cb *cb));
++int vc4_gem_exec_debugfs(struct seq_file *m, void *arg);
+
+ /* vc4_hdmi.c */
+ extern struct platform_driver vc4_hdmi_driver;
+--- a/drivers/gpu/drm/vc4/vc4_gem.c
++++ b/drivers/gpu/drm/vc4/vc4_gem.c
+@@ -31,6 +31,20 @@
+ #include "vc4_regs.h"
+ #include "vc4_trace.h"
+
++#ifdef CONFIG_DEBUG_FS
++int vc4_gem_exec_debugfs(struct seq_file *m, void *unused)
++{
++ struct drm_info_node *node = (struct drm_info_node *)m->private;
++ struct drm_device *dev = node->minor->dev;
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++
++ seq_printf(m, "Emitted seqno: 0x%016llx\n", vc4->emit_seqno);
++ seq_printf(m, "Finished seqno: 0x%016llx\n", vc4->finished_seqno);
++
++ return 0;
++}
++#endif /* CONFIG_DEBUG_FS */
++
+ static void
+ vc4_queue_hangcheck(struct drm_device *dev)
+ {
diff --git a/target/linux/brcm2708/patches-4.4/0193-drm-vc4-Include-vc4_drm.h-in-uapi-in-downstream-buil.patch b/target/linux/brcm2708/patches-4.4/0193-drm-vc4-Include-vc4_drm.h-in-uapi-in-downstream-buil.patch
new file mode 100644
index 0000000000..2e439ce95d
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0193-drm-vc4-Include-vc4_drm.h-in-uapi-in-downstream-buil.patch
@@ -0,0 +1,21 @@
+From 99d93febb6563b3f0f6ad5ec0240fa0c3e19f62f Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 25 Jan 2016 13:03:33 -0800
+Subject: [PATCH 193/381] drm/vc4: Include vc4_drm.h in uapi in downstream
+ build.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ include/uapi/drm/Kbuild | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/include/uapi/drm/Kbuild
++++ b/include/uapi/drm/Kbuild
+@@ -14,6 +14,7 @@ header-y += radeon_drm.h
+ header-y += savage_drm.h
+ header-y += sis_drm.h
+ header-y += tegra_drm.h
++header-y += vc4_drm.h
+ header-y += via_drm.h
+ header-y += vmwgfx_drm.h
+ header-y += msm_drm.h
diff --git a/target/linux/brcm2708/patches-4.4/0194-drm-vc4-Validate-that-WAIT_BO-padding-is-cleared.patch b/target/linux/brcm2708/patches-4.4/0194-drm-vc4-Validate-that-WAIT_BO-padding-is-cleared.patch
new file mode 100644
index 0000000000..85441a503c
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0194-drm-vc4-Validate-that-WAIT_BO-padding-is-cleared.patch
@@ -0,0 +1,25 @@
+From a88f349e6b9544d0e37ece0d1d94a7065151f92c Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 25 Jan 2016 13:05:00 -0800
+Subject: [PATCH 194/381] drm/vc4: Validate that WAIT_BO padding is cleared.
+
+This is ABI future-proofing if we ever want to extend the pad to mean
+something.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_gem.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_gem.c
++++ b/drivers/gpu/drm/vc4/vc4_gem.c
+@@ -761,6 +761,9 @@ vc4_wait_bo_ioctl(struct drm_device *dev
+ struct drm_gem_object *gem_obj;
+ struct vc4_bo *bo;
+
++ if (args->pad != 0)
++ return -EINVAL;
++
+ gem_obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+ if (!gem_obj) {
+ DRM_ERROR("Failed to look up GEM BO %d\n", args->handle);
diff --git a/target/linux/brcm2708/patches-4.4/0195-drm-vc4-Fix-the-clear-color-for-the-first-tile-rende.patch b/target/linux/brcm2708/patches-4.4/0195-drm-vc4-Fix-the-clear-color-for-the-first-tile-rende.patch
new file mode 100644
index 0000000000..980f4edaac
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0195-drm-vc4-Fix-the-clear-color-for-the-first-tile-rende.patch
@@ -0,0 +1,49 @@
+From ae56f926164bc10a43c6a1b1cb6576d59a96893c Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 25 Jan 2016 13:52:41 -0800
+Subject: [PATCH 195/381] drm/vc4: Fix the clear color for the first tile
+ rendered.
+
+Apparently in hardware (as opposed to simulation), the clear colors
+need to be uploaded before the render config, otherwise they won't
+take effect. Fixes igt's vc4_wait_bo/used-bo-* subtests.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_render_cl.c | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_render_cl.c
++++ b/drivers/gpu/drm/vc4/vc4_render_cl.c
+@@ -321,15 +321,6 @@ static int vc4_create_rcl_bo(struct drm_
+ list_add_tail(&to_vc4_bo(&setup->rcl->base)->unref_head,
+ &exec->unref_list);
+
+- rcl_u8(setup, VC4_PACKET_TILE_RENDERING_MODE_CONFIG);
+- rcl_u32(setup,
+- (setup->color_write ? (setup->color_write->paddr +
+- args->color_write.offset) :
+- 0));
+- rcl_u16(setup, args->width);
+- rcl_u16(setup, args->height);
+- rcl_u16(setup, args->color_write.bits);
+-
+ /* The tile buffer gets cleared when the previous tile is stored. If
+ * the clear values changed between frames, then the tile buffer has
+ * stale clear values in it, so we have to do a store in None mode (no
+@@ -349,6 +340,15 @@ static int vc4_create_rcl_bo(struct drm_
+ rcl_u32(setup, 0); /* no address, since we're in None mode */
+ }
+
++ rcl_u8(setup, VC4_PACKET_TILE_RENDERING_MODE_CONFIG);
++ rcl_u32(setup,
++ (setup->color_write ? (setup->color_write->paddr +
++ args->color_write.offset) :
++ 0));
++ rcl_u16(setup, args->width);
++ rcl_u16(setup, args->height);
++ rcl_u16(setup, args->color_write.bits);
++
+ for (y = min_y_tile; y <= max_y_tile; y++) {
+ for (x = min_x_tile; x <= max_x_tile; x++) {
+ bool first = (x == min_x_tile && y == min_y_tile);
diff --git a/target/linux/brcm2708/patches-4.4/0196-drm-vc4-Return-an-ERR_PTR-from-BO-creation-instead-o.patch b/target/linux/brcm2708/patches-4.4/0196-drm-vc4-Return-an-ERR_PTR-from-BO-creation-instead-o.patch
new file mode 100644
index 0000000000..aa43e4f2ab
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0196-drm-vc4-Return-an-ERR_PTR-from-BO-creation-instead-o.patch
@@ -0,0 +1,137 @@
+From 8db21da6d756efe530df2736c7dc99aeeca209ce Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 25 Jan 2016 14:13:12 -0800
+Subject: [PATCH 196/381] drm/vc4: Return an ERR_PTR from BO creation instead
+ of NULL.
+
+Fixes igt vc4_create_bo/create-bo-0 by returning -EINVAL from the
+ioctl instead of -ENOMEM.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_bo.c | 23 +++++++++++++----------
+ drivers/gpu/drm/vc4/vc4_gem.c | 4 ++--
+ drivers/gpu/drm/vc4/vc4_irq.c | 2 +-
+ drivers/gpu/drm/vc4/vc4_render_cl.c | 4 ++--
+ drivers/gpu/drm/vc4/vc4_validate.c | 4 ++--
+ 5 files changed, 20 insertions(+), 17 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_bo.c
++++ b/drivers/gpu/drm/vc4/vc4_bo.c
+@@ -213,10 +213,10 @@ struct vc4_bo *vc4_bo_create(struct drm_
+ size_t size = roundup(unaligned_size, PAGE_SIZE);
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ struct drm_gem_cma_object *cma_obj;
+- int pass;
++ int pass, ret;
+
+ if (size == 0)
+- return NULL;
++ return ERR_PTR(-EINVAL);
+
+ /* First, try to get a vc4_bo from the kernel BO cache. */
+ if (from_cache) {
+@@ -247,14 +247,17 @@ struct vc4_bo *vc4_bo_create(struct drm_
+ * unreferenced BOs to the cache, and then
+ * free the cache.
+ */
+- vc4_wait_for_seqno(dev, vc4->emit_seqno, ~0ull, true);
++ ret = vc4_wait_for_seqno(dev, vc4->emit_seqno, ~0ull,
++ true);
++ if (ret)
++ return ERR_PTR(ret);
+ vc4_job_handle_completed(vc4);
+ vc4_bo_cache_purge(dev);
+ break;
+ case 3:
+ DRM_ERROR("Failed to allocate from CMA:\n");
+ vc4_bo_stats_dump(vc4);
+- return NULL;
++ return ERR_PTR(-ENOMEM);
+ }
+ }
+
+@@ -276,8 +279,8 @@ int vc4_dumb_create(struct drm_file *fil
+ args->size = args->pitch * args->height;
+
+ bo = vc4_bo_create(dev, args->size, false);
+- if (!bo)
+- return -ENOMEM;
++ if (IS_ERR(bo))
++ return PTR_ERR(bo);
+
+ ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle);
+ drm_gem_object_unreference_unlocked(&bo->base.base);
+@@ -460,8 +463,8 @@ int vc4_create_bo_ioctl(struct drm_devic
+ * get zeroed, and that might leak data between users.
+ */
+ bo = vc4_bo_create(dev, args->size, false);
+- if (!bo)
+- return -ENOMEM;
++ if (IS_ERR(bo))
++ return PTR_ERR(bo);
+
+ ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle);
+ drm_gem_object_unreference_unlocked(&bo->base.base);
+@@ -513,8 +516,8 @@ vc4_create_shader_bo_ioctl(struct drm_de
+ }
+
+ bo = vc4_bo_create(dev, args->size, true);
+- if (!bo)
+- return -ENOMEM;
++ if (IS_ERR(bo))
++ return PTR_ERR(bo);
+
+ ret = copy_from_user(bo->base.vaddr,
+ (void __user *)(uintptr_t)args->data,
+--- a/drivers/gpu/drm/vc4/vc4_gem.c
++++ b/drivers/gpu/drm/vc4/vc4_gem.c
+@@ -593,9 +593,9 @@ vc4_get_bcl(struct drm_device *dev, stru
+ }
+
+ bo = vc4_bo_create(dev, exec_size, true);
+- if (!bo) {
++ if (IS_ERR(bo)) {
+ DRM_ERROR("Couldn't allocate BO for binning\n");
+- ret = PTR_ERR(exec->exec_bo);
++ ret = PTR_ERR(bo);
+ goto fail;
+ }
+ exec->exec_bo = &bo->base;
+--- a/drivers/gpu/drm/vc4/vc4_irq.c
++++ b/drivers/gpu/drm/vc4/vc4_irq.c
+@@ -57,7 +57,7 @@ vc4_overflow_mem_work(struct work_struct
+ struct vc4_bo *bo;
+
+ bo = vc4_bo_create(dev, 256 * 1024, true);
+- if (!bo) {
++ if (IS_ERR(bo)) {
+ DRM_ERROR("Couldn't allocate binner overflow mem\n");
+ return;
+ }
+--- a/drivers/gpu/drm/vc4/vc4_render_cl.c
++++ b/drivers/gpu/drm/vc4/vc4_render_cl.c
+@@ -316,8 +316,8 @@ static int vc4_create_rcl_bo(struct drm_
+ size += xtiles * ytiles * loop_body_size;
+
+ setup->rcl = &vc4_bo_create(dev, size, true)->base;
+- if (!setup->rcl)
+- return -ENOMEM;
++ if (IS_ERR(setup->rcl))
++ return PTR_ERR(setup->rcl);
+ list_add_tail(&to_vc4_bo(&setup->rcl->base)->unref_head,
+ &exec->unref_list);
+
+--- a/drivers/gpu/drm/vc4/vc4_validate.c
++++ b/drivers/gpu/drm/vc4/vc4_validate.c
+@@ -401,8 +401,8 @@ validate_tile_binning_config(VALIDATE_AR
+ tile_bo = vc4_bo_create(dev, exec->tile_alloc_offset + tile_alloc_size,
+ true);
+ exec->tile_bo = &tile_bo->base;
+- if (!exec->tile_bo)
+- return -ENOMEM;
++ if (IS_ERR(exec->tile_bo))
++ return PTR_ERR(exec->tile_bo);
+ list_add_tail(&tile_bo->unref_head, &exec->unref_list);
+
+ /* tile alloc address. */
diff --git a/target/linux/brcm2708/patches-4.4/0197-drm-vc4-Fix-ERESTARTSYS-error-return-from-BO-waits.patch b/target/linux/brcm2708/patches-4.4/0197-drm-vc4-Fix-ERESTARTSYS-error-return-from-BO-waits.patch
new file mode 100644
index 0000000000..0fa340c36e
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0197-drm-vc4-Fix-ERESTARTSYS-error-return-from-BO-waits.patch
@@ -0,0 +1,32 @@
+From a0554ab8b841b57b9bba5acb16b24763dfbf02e0 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 25 Jan 2016 14:32:41 -0800
+Subject: [PATCH 197/381] drm/vc4: Fix -ERESTARTSYS error return from BO waits.
+
+This caused the wait ioctls to claim that waiting had completed when
+we actually got interrupted by a signal before it was done. Fixes
+broken rendering throttling that produced serious lag in X window
+dragging.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_gem.c | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_gem.c
++++ b/drivers/gpu/drm/vc4/vc4_gem.c
+@@ -352,12 +352,10 @@ vc4_wait_for_seqno(struct drm_device *de
+ finish_wait(&vc4->job_wait_queue, &wait);
+ trace_vc4_wait_for_seqno_end(dev, seqno);
+
+- if (ret && ret != -ERESTARTSYS) {
++ if (ret && ret != -ERESTARTSYS)
+ DRM_ERROR("timeout waiting for render thread idle\n");
+- return ret;
+- }
+
+- return 0;
++ return ret;
+ }
+
+ static void
diff --git a/target/linux/brcm2708/patches-4.4/0198-drm-vc4-Drop-error-message-on-seqno-wait-timeouts.patch b/target/linux/brcm2708/patches-4.4/0198-drm-vc4-Drop-error-message-on-seqno-wait-timeouts.patch
new file mode 100644
index 0000000000..e06f54bff5
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0198-drm-vc4-Drop-error-message-on-seqno-wait-timeouts.patch
@@ -0,0 +1,27 @@
+From e9096f6a422bb37a87dd41bc2c01163946e1bc10 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 25 Jan 2016 14:33:50 -0800
+Subject: [PATCH 198/381] drm/vc4: Drop error message on seqno wait timeouts.
+
+These ioctls end up getting exposed to userspace, and having normal
+user requests print DRM errors is obviously wrong. The message was
+originally to give us some idea of what happened when a hang occurred,
+but we have a DRM_INFO from reset for that.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_gem.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_gem.c
++++ b/drivers/gpu/drm/vc4/vc4_gem.c
+@@ -352,9 +352,6 @@ vc4_wait_for_seqno(struct drm_device *de
+ finish_wait(&vc4->job_wait_queue, &wait);
+ trace_vc4_wait_for_seqno_end(dev, seqno);
+
+- if (ret && ret != -ERESTARTSYS)
+- DRM_ERROR("timeout waiting for render thread idle\n");
+-
+ return ret;
+ }
+
diff --git a/target/linux/brcm2708/patches-4.4/0199-BCM270X_DT-Add-1-bit-SDIO-using-minimal-pins.patch b/target/linux/brcm2708/patches-4.4/0199-BCM270X_DT-Add-1-bit-SDIO-using-minimal-pins.patch
new file mode 100644
index 0000000000..df057cd717
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0199-BCM270X_DT-Add-1-bit-SDIO-using-minimal-pins.patch
@@ -0,0 +1,81 @@
+From 337a299edf74d3866636363b675f1b48e01cf842 Mon Sep 17 00:00:00 2001
+From: campag <dave-lowe@ntlworld.com>
+Date: Wed, 24 Feb 2016 16:45:42 +0000
+Subject: [PATCH 199/381] BCM270X_DT: Add 1-bit SDIO using minimal pins...
+
+... for that mode: GPIOs 22-25.
+---
+ arch/arm/boot/dts/overlays/README | 21 ++++++++++++++
+ arch/arm/boot/dts/overlays/sdio-1bit-overlay.dts | 36 ++++++++++++++++++++++++
+ 2 files changed, 57 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/sdio-1bit-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -709,6 +709,27 @@ Params: overclock_50 SD Clock
+ bus_width Set the SDIO host bus width (default 4 bits)
+
+
++Name: sdio-1bit
++Info: Selects the bcm2835-sdhost SD/MMC driver, optionally with overclock,
++ and enables 1-bit SDIO via GPIOs 22-25.
++Load: dtoverlay=sdio-1bit,<param>=<val>
++Params: overclock_50 SD Clock (in MHz) to use when the MMC framework
++ requests 50MHz
++
++ sdio_overclock SDIO Clock (in MHz) to use when the MMC
++ framework requests 50MHz
++
++ force_pio Disable DMA support (default off)
++
++ pio_limit Number of blocks above which to use DMA
++ (default 1)
++
++ debug Enable debug output (default off)
++
++ poll_once Disable SDIO-device polling every second
++ (default on: polling once at boot-time)
++
++
+ Name: sdtweak
+ Info: Tunes the bcm2835-sdhost SD/MMC driver
+ Load: dtoverlay=sdtweak,<param>=<val>
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/sdio-1bit-overlay.dts
+@@ -0,0 +1,36 @@
++/* Enable 1-bit SDIO from MMC interface via GPIOs 22-25. Includes sdhost overlay. */
++
++/include/ "sdhost-overlay.dts"
++
++/{
++ compatible = "brcm,bcm2708";
++
++ fragment@3 {
++ target = <&mmc>;
++ sdio_mmc: __overlay__ {
++ compatible = "brcm,bcm2835-mmc";
++ pinctrl-names = "default";
++ pinctrl-0 = <&sdio_pins>;
++ non-removable;
++ bus-width = <1>;
++ brcm,overclock-50 = <0>;
++ status = "okay";
++ };
++ };
++
++ fragment@4 {
++ target = <&gpio>;
++ __overlay__ {
++ sdio_pins: sdio_pins {
++ brcm,pins = <22 23 24 25>;
++ brcm,function = <7 7 7 7>; /* ALT3 = SD1 */
++ brcm,pull = <0 2 2 2>;
++ };
++ };
++ };
++
++ __overrides__ {
++ poll_once = <&sdio_mmc>,"non-removable?";
++ sdio_overclock = <&sdio_mmc>,"brcm,overclock-50:0";
++ };
++};
diff --git a/target/linux/brcm2708/patches-4.4/0201-Add-overlay-and-enable-support-for-QCA7000-board.patch b/target/linux/brcm2708/patches-4.4/0201-Add-overlay-and-enable-support-for-QCA7000-board.patch
new file mode 100644
index 0000000000..7be1e80e0d
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0201-Add-overlay-and-enable-support-for-QCA7000-board.patch
@@ -0,0 +1,127 @@
+From ff63e16281a582d4ead28c797b10167515fd9898 Mon Sep 17 00:00:00 2001
+From: Michael Heimpold <michael.heimpold@i2se.com>
+Date: Fri, 29 Jan 2016 12:00:37 +0100
+Subject: [PATCH 201/381] Add overlay and enable support for QCA7000 board
+
+This adds a device tree overlay for the QCA7000 which can be used
+when attaching an I2SE's PLC Stamp micro EVK to the Raspberry Pi.
+
+This Evaluation Board embeds a QCA7000 chip, a Homeplug Green PHY
+powerline chip from Qualcomm/Atheros for the Internet of Things.
+
+This patch also enables the required QCA7000 driver module
+in the default configurations.
+
+Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
+Signed-off-by: Michael Heimpold <michael.heimpold@i2se.com>
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 8 ++++
+ arch/arm/boot/dts/overlays/qca7000-overlay.dts | 52 ++++++++++++++++++++++++++
+ arch/arm/configs/bcm2709_defconfig | 1 +
+ arch/arm/configs/bcmrpi_defconfig | 1 +
+ 5 files changed, 63 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/qca7000-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -48,6 +48,7 @@ dtbo-$(RPI_DT_OVERLAYS) += pitft28-resis
+ dtbo-$(RPI_DT_OVERLAYS) += pps-gpio.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += pwm.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += pwm-2chan.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += qca7000.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += raspidac3.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += rpi-backlight.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += rpi-dac.dtbo
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -625,6 +625,14 @@ Params: pin Output p
+ clock PWM clock frequency (informational)
+
+
++Name: qca7000
++Info: I2SE's Evaluation Board for PLC Stamp micro
++Load: dtoverlay=qca7000,<param>=<val>
++Params: int_pin GPIO pin for interrupt signal (default 23)
++
++ speed SPI bus speed (default 12 MHz)
++
++
+ Name: raspidac3
+ Info: Configures the RaspiDAV Rev.3x audio card
+ Load: dtoverlay=raspidac3
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/qca7000-overlay.dts
+@@ -0,0 +1,52 @@
++// Overlay for the Qualcomm Atheros QCA7000 on I2SE's PLC Stamp micro EVK
++// Visit: https://www.i2se.com/product/plc-stamp-micro-evk for details
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&spi0>;
++ __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ status = "okay";
++
++ spidev@0 {
++ status = "disabled";
++ };
++
++ eth1: qca7000@0 {
++ compatible = "qca,qca7000";
++ reg = <0>; /* CE0 */
++ pinctrl-names = "default";
++ pinctrl-0 = <&eth1_pins>;
++ interrupt-parent = <&gpio>;
++ interrupts = <23 0x1>; /* rising edge */
++ spi-max-frequency = <12000000>;
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ eth1_pins: eth1_pins {
++ brcm,pins = <23>;
++ brcm,function = <0>; /* in */
++ brcm,pull = <0>; /* none */
++ };
++ };
++ };
++
++ __overrides__ {
++ int_pin = <&eth1>, "interrupts:0",
++ <&eth1_pins>, "brcm,pins:0";
++ speed = <&eth1>, "spi-max-frequency:0";
++ };
++};
+--- a/arch/arm/configs/bcm2709_defconfig
++++ b/arch/arm/configs/bcm2709_defconfig
+@@ -446,6 +446,7 @@ CONFIG_NETCONSOLE=m
+ CONFIG_TUN=m
+ CONFIG_VETH=m
+ CONFIG_ENC28J60=m
++CONFIG_QCA7000=m
+ CONFIG_MDIO_BITBANG=m
+ CONFIG_PPP=m
+ CONFIG_PPP_BSDCOMP=m
+--- a/arch/arm/configs/bcmrpi_defconfig
++++ b/arch/arm/configs/bcmrpi_defconfig
+@@ -439,6 +439,7 @@ CONFIG_NETCONSOLE=m
+ CONFIG_TUN=m
+ CONFIG_VETH=m
+ CONFIG_ENC28J60=m
++CONFIG_QCA7000=m
+ CONFIG_MDIO_BITBANG=m
+ CONFIG_PPP=m
+ CONFIG_PPP_BSDCOMP=m
diff --git a/target/linux/brcm2708/patches-4.4/0202-serial-Take-care-starting-a-hung-up-tty-s-port.patch b/target/linux/brcm2708/patches-4.4/0202-serial-Take-care-starting-a-hung-up-tty-s-port.patch
new file mode 100644
index 0000000000..78a148bc76
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0202-serial-Take-care-starting-a-hung-up-tty-s-port.patch
@@ -0,0 +1,28 @@
+From 35370cf396896477ee7e8cb044779a3ee9257a7e Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Wed, 9 Mar 2016 13:28:24 +0000
+Subject: [PATCH 202/381] serial: Take care starting a hung-up tty's port
+
+tty_port_hangup sets a port's tty field to NULL (holding the port lock),
+but uart_tx_stopped, called from __uart_start (with the port lock),
+uses the tty field without checking for NULL.
+
+Change uart_tx_stopped to treat a NULL tty field as another stopped
+indication.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ include/linux/serial_core.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/include/linux/serial_core.h
++++ b/include/linux/serial_core.h
+@@ -397,7 +397,7 @@ int uart_resume_port(struct uart_driver
+ static inline int uart_tx_stopped(struct uart_port *port)
+ {
+ struct tty_struct *tty = port->state->port.tty;
+- if (tty->stopped || port->hw_stopped)
++ if (!tty || tty->stopped || port->hw_stopped)
+ return 1;
+ return 0;
+ }
diff --git a/target/linux/brcm2708/patches-4.4/0203-pi3-miniuart-bt-overlay-Correct-and-clarify-info.patch b/target/linux/brcm2708/patches-4.4/0203-pi3-miniuart-bt-overlay-Correct-and-clarify-info.patch
new file mode 100644
index 0000000000..e5b2b621e7
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0203-pi3-miniuart-bt-overlay-Correct-and-clarify-info.patch
@@ -0,0 +1,41 @@
+From f0f6dd227bbb171ad6b0dbe1d394de71d78eae21 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Thu, 17 Mar 2016 10:16:16 +0000
+Subject: [PATCH 203/381] pi3-miniuart-bt-overlay: Correct and clarify info
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/overlays/README | 6 ++++--
+ arch/arm/boot/dts/overlays/pi3-miniuart-bt-overlay.dts | 6 ++++--
+ 2 files changed, 8 insertions(+), 4 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -511,8 +511,10 @@ Name: pi3-miniuart-bt
+ Info: Switch Pi3 Bluetooth function to use the mini-UART (ttyS0) and restore
+ UART0/ttyAMA0 over GPIOs 14 & 15. Note that this may reduce the maximum
+ usable baudrate.
+- N.B. It is also necessary to edit /lib/systemd/system/hciuart.server
+- and replace ttyAMA0 with ttyS0.
++ N.B. It is also necessary to edit /lib/systemd/system/hciuart.service
++ and replace ttyAMA0 with ttyS0, unless you have a system with udev rules
++ that create /dev/serial0 and /dev/serial1, in which case use
++ /dev/serial1 instead because it will always be correct.
+ Load: dtoverlay=pi3-miniuart-bt
+ Params: <None>
+
+--- a/arch/arm/boot/dts/overlays/pi3-miniuart-bt-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pi3-miniuart-bt-overlay.dts
+@@ -5,8 +5,10 @@
+ UART0/ttyAMA0 over GPIOs 14 & 15. Note that this may reduce the maximum
+ usable baudrate.
+
+- It is also necessary to edit /lib/systemd/system/hciuart.server and
+- replace ttyAMA0 with ttyS0.
++ It is also necessary to edit /lib/systemd/system/hciuart.service and
++ replace ttyAMA0 with ttyS0, unless you have a system with udev rules
++ that create /dev/serial0 and /dev/serial1, in which case use /dev/serial1
++ instead because it will always be correct.
+
+ If cmdline.txt uses the alias serial0 to refer to the user-accessable port
+ then the firmware will replace with the appropriate port whether or not
diff --git a/target/linux/brcm2708/patches-4.4/0204-pwm-overlays-Params-must-have-in-overlay-targets.patch b/target/linux/brcm2708/patches-4.4/0204-pwm-overlays-Params-must-have-in-overlay-targets.patch
new file mode 100644
index 0000000000..de59c2e443
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0204-pwm-overlays-Params-must-have-in-overlay-targets.patch
@@ -0,0 +1,52 @@
+From b04fec7048465650101f83c29080de209a1c6446 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Thu, 17 Mar 2016 10:41:56 +0000
+Subject: [PATCH 204/381] pwm overlays: Params must have in-overlay targets
+
+---
+ arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts | 9 ++++++++-
+ arch/arm/boot/dts/overlays/pwm-overlay.dts | 9 ++++++++-
+ 2 files changed, 16 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts
+@@ -36,11 +36,18 @@ N.B.:
+ };
+ };
+
++ fragment@2 {
++ target = <&clk_pwm>;
++ frag2: __overlay__ {
++ clock-frequency = <100000000>;
++ };
++ };
++
+ __overrides__ {
+ pin = <&pwm_pins>,"brcm,pins:0";
+ pin2 = <&pwm_pins>,"brcm,pins:4";
+ func = <&pwm_pins>,"brcm,function:0";
+ func2 = <&pwm_pins>,"brcm,function:4";
+- clock = <&clk_pwm>,"clock-frequency:0";
++ clock = <&frag2>,"clock-frequency:0";
+ };
+ };
+--- a/arch/arm/boot/dts/overlays/pwm-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pwm-overlay.dts
+@@ -34,9 +34,16 @@ N.B.:
+ };
+ };
+
++ fragment@2 {
++ target = <&clk_pwm>;
++ frag2: __overlay__ {
++ clock-frequency = <100000000>;
++ };
++ };
++
+ __overrides__ {
+ pin = <&pwm_pins>,"brcm,pins:0";
+ func = <&pwm_pins>,"brcm,function:0";
+- clock = <&clk_pwm>,"clock-frequency:0";
++ clock = <&frag2>,"clock-frequency:0";
+ };
+ };
diff --git a/target/linux/brcm2708/patches-4.4/0205-BCM270X_DT-Switch-Compute-Module-to-MMC.patch b/target/linux/brcm2708/patches-4.4/0205-BCM270X_DT-Switch-Compute-Module-to-MMC.patch
new file mode 100644
index 0000000000..c67949d278
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0205-BCM270X_DT-Switch-Compute-Module-to-MMC.patch
@@ -0,0 +1,53 @@
+From 4212b2d0cd9638f926162efb7a4b3c477cfb212c Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 18 Mar 2016 13:06:29 +0000
+Subject: [PATCH 205/381] BCM270X_DT: Switch Compute Module to MMC
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/bcm2708-rpi-cm.dtsi | 17 ++++++++---------
+ 1 file changed, 8 insertions(+), 9 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi
++++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi
+@@ -8,9 +8,9 @@
+ };
+
+ &gpio {
+- sdhost_pins: sdhost_pins {
++ mmc_pins: mmc_pins {
+ brcm,pins = <48 49 50 51 52 53>;
+- brcm,function = <4>; /* alt0 */
++ brcm,function = <7>; /* alt3 */
+ };
+ };
+
+@@ -22,12 +22,14 @@
+ };
+ };
+
+-&sdhost {
++
++&mmc {
+ pinctrl-names = "default";
+- pinctrl-0 = <&sdhost_pins>;
+- bus-width = <4>;
++ pinctrl-0 = <&mmc_pins>;
+ non-removable;
++ bus-width = <4>;
+ status = "okay";
++ brcm,overclock-50 = <0>;
+ };
+
+ &fb {
+@@ -45,9 +47,6 @@
+ audio = <&audio>,"status";
+ watchdog = <&watchdog>,"status";
+ random = <&random>,"status";
+- sd_overclock = <&sdhost>,"brcm,overclock-50:0";
+- sd_force_pio = <&sdhost>,"brcm,force-pio?";
+- sd_pio_limit = <&sdhost>,"brcm,pio-limit:0";
+- sd_debug = <&sdhost>,"brcm,debug";
++ sd_overclock = <&mmc>,"brcm,overclock-50:0";
+ };
+ };
diff --git a/target/linux/brcm2708/patches-4.4/0206-dwc_otg-Don-t-free-qh-align-buffers-in-atomic-contex.patch b/target/linux/brcm2708/patches-4.4/0206-dwc_otg-Don-t-free-qh-align-buffers-in-atomic-contex.patch
new file mode 100644
index 0000000000..6bdbbcb5ae
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0206-dwc_otg-Don-t-free-qh-align-buffers-in-atomic-contex.patch
@@ -0,0 +1,44 @@
+From d5199adc79072f6cd49f8c79bc02769397a3456c Mon Sep 17 00:00:00 2001
+From: P33M <P33M@github.com>
+Date: Fri, 18 Mar 2016 17:38:37 +0000
+Subject: [PATCH 206/381] dwc_otg: Don't free qh align buffers in atomic
+ context
+
+---
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
+@@ -56,6 +56,9 @@ void dwc_otg_hcd_qh_free(dwc_otg_hcd_t *
+ {
+ dwc_otg_qtd_t *qtd, *qtd_tmp;
+ dwc_irqflags_t flags;
++ uint32_t buf_size = 0;
++ uint8_t *align_buf_virt = NULL;
++ dwc_dma_t align_buf_dma;
+
+ /* Free each QTD in the QTD list */
+ DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
+@@ -67,17 +70,19 @@ void dwc_otg_hcd_qh_free(dwc_otg_hcd_t *
+ if (hcd->core_if->dma_desc_enable) {
+ dwc_otg_hcd_qh_free_ddma(hcd, qh);
+ } else if (qh->dw_align_buf) {
+- uint32_t buf_size;
+ if (qh->ep_type == UE_ISOCHRONOUS) {
+ buf_size = 4096;
+ } else {
+ buf_size = hcd->core_if->core_params->max_transfer_size;
+ }
+- DWC_DMA_FREE(buf_size, qh->dw_align_buf, qh->dw_align_buf_dma);
++ align_buf_virt = qh->dw_align_buf;
++ align_buf_dma = qh->dw_align_buf_dma;
+ }
+
+ DWC_FREE(qh);
+ DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
++ if (align_buf_virt)
++ DWC_DMA_FREE(buf_size, align_buf_virt, align_buf_dma);
+ return;
+ }
+
diff --git a/target/linux/brcm2708/patches-4.4/0207-dwc_otg-Enable-the-hack-for-Split-Interrupt-transact.patch b/target/linux/brcm2708/patches-4.4/0207-dwc_otg-Enable-the-hack-for-Split-Interrupt-transact.patch
new file mode 100644
index 0000000000..f75002d71d
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0207-dwc_otg-Enable-the-hack-for-Split-Interrupt-transact.patch
@@ -0,0 +1,28 @@
+From e1e24dfafa725d849724cb9bf24c142a5cc8473a Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Mon, 21 Mar 2016 15:38:38 +0000
+Subject: [PATCH 207/381] dwc_otg: Enable the hack for Split Interrupt
+ transactions by default
+
+dwc_otg.fiq_fsm_mask=0xF has long been a suggestion for users with audio stutters or other USB bandwidth issues.
+So far we are aware of many success stories but no failure caused by this setting.
+Make it a default to learn more.
+
+See: https://www.raspberrypi.org/forums/viewtopic.php?f=28&t=70437
+
+Signed-off-by: popcornmix <popcornmix@gmail.com>
+---
+ drivers/usb/host/dwc_otg/dwc_otg_driver.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/usb/host/dwc_otg/dwc_otg_driver.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c
+@@ -247,7 +247,7 @@ bool fiq_fsm_enable = true;
+ //Bulk split-transaction NAK holdoff in microframes
+ uint16_t nak_holdoff = 8;
+
+-unsigned short fiq_fsm_mask = 0x07;
++unsigned short fiq_fsm_mask = 0x0F;
+
+ /**
+ * This function shows the Driver Version.
diff --git a/target/linux/brcm2708/patches-4.4/0208-BCM270X_DT-Remove-explicit-claiming-of-UART-pins.patch b/target/linux/brcm2708/patches-4.4/0208-BCM270X_DT-Remove-explicit-claiming-of-UART-pins.patch
new file mode 100644
index 0000000000..e4057025d4
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0208-BCM270X_DT-Remove-explicit-claiming-of-UART-pins.patch
@@ -0,0 +1,89 @@
+From 0fc64288fb36e30e77feeccb3fd68901891939f7 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Sat, 19 Mar 2016 16:51:37 +0000
+Subject: [PATCH 208/381] BCM270X_DT: Remove explicit claiming of UART pins
+
+It is convenient to be able to map a different function to the UART
+pins (e.g. DPI for vga666) without having to disable the UART first.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/bcm2710-rpi-3-b.dts | 6 +++---
+ .../boot/dts/overlays/pi3-disable-bt-overlay.dts | 10 ++++-----
+ .../boot/dts/overlays/pi3-miniuart-bt-overlay.dts | 25 +++++++++++-----------
+ 3 files changed, 20 insertions(+), 21 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
++++ b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
+@@ -57,9 +57,9 @@
+ };
+
+ uart1_pins: uart1_pins {
+- brcm,pins = <14 15>;
+- brcm,function = <2>; /* alt5=UART1 */
+- brcm,pull = <0 2>;
++ brcm,pins;
++ brcm,function;
++ brcm,pull;
+ };
+ };
+
+--- a/arch/arm/boot/dts/overlays/pi3-disable-bt-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pi3-disable-bt-overlay.dts
+@@ -28,13 +28,11 @@
+ };
+
+ fragment@2 {
+- target = <&gpio>;
++ target = <&uart0_pins>;
+ __overlay__ {
+- uart0_pins: uart0_pins {
+- brcm,pins = <14 15>;
+- brcm,function = <4>; /* alt0 */
+- brcm,pull = <0 2>;
+- };
++ brcm,pins;
++ brcm,function;
++ brcm,pull;
+ };
+ };
+
+--- a/arch/arm/boot/dts/overlays/pi3-miniuart-bt-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pi3-miniuart-bt-overlay.dts
+@@ -37,23 +37,24 @@
+ };
+
+ fragment@2 {
+- target = <&gpio>;
++ target = <&uart0_pins>;
+ __overlay__ {
+- uart0_pins: uart0_pins {
+- brcm,pins = <14 15>;
+- brcm,function = <4>; /* alt0 */
+- brcm,pull = <0 2>;
+- };
+-
+- uart1_pins: uart1_pins {
+- brcm,pins = <32 33>;
+- brcm,function = <2>; /* alt5=UART1 */
+- brcm,pull = <0 2>;
+- };
++ brcm,pins;
++ brcm,function;
++ brcm,pull;
+ };
+ };
+
+ fragment@3 {
++ target = <&uart1_pins>;
++ __overlay__ {
++ brcm,pins = <32 33>;
++ brcm,function = <2>; /* alt5=UART1 */
++ brcm,pull = <0 2>;
++ };
++ };
++
++ fragment@4 {
+ target-path = "/aliases";
+ __overlay__ {
+ serial0 = "/soc/uart@7e201000";
diff --git a/target/linux/brcm2708/patches-4.4/0209-lirc_rpi-Lower-IR-reception-error-to-debug.patch b/target/linux/brcm2708/patches-4.4/0209-lirc_rpi-Lower-IR-reception-error-to-debug.patch
new file mode 100644
index 0000000000..1990f05d3a
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0209-lirc_rpi-Lower-IR-reception-error-to-debug.patch
@@ -0,0 +1,21 @@
+From 61675cb7f40c9b93537351b9d225cfeb08968875 Mon Sep 17 00:00:00 2001
+From: Rodrigo Freire <rfreire@rf.usersys.redhat.com>
+Date: Tue, 22 Mar 2016 12:40:33 -0300
+Subject: [PATCH 209/381] lirc_rpi: Lower IR reception error to debug
+
+Lowers a IR reception error condition message to KERNEL_DEBUG
+---
+ drivers/staging/media/lirc/lirc_rpi.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/staging/media/lirc/lirc_rpi.c
++++ b/drivers/staging/media/lirc/lirc_rpi.c
+@@ -271,7 +271,7 @@ static irqreturn_t irq_handler(int i, vo
+ data = PULSE_MASK; /* really long time */
+ if (!(signal^sense)) {
+ /* sanity check */
+- printk(KERN_WARNING LIRC_DRIVER_NAME
++ printk(KERN_DEBUG LIRC_DRIVER_NAME
+ ": AIEEEE: %d %d %lx %lx %lx %lx\n",
+ signal, sense, tv.tv_sec, lasttv.tv_sec,
+ tv.tv_usec, lasttv.tv_usec);
diff --git a/target/linux/brcm2708/patches-4.4/0210-vchiq_arm-Access-the-dequeue_pending-flag-locked.patch b/target/linux/brcm2708/patches-4.4/0210-vchiq_arm-Access-the-dequeue_pending-flag-locked.patch
new file mode 100644
index 0000000000..29f09a6ca4
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0210-vchiq_arm-Access-the-dequeue_pending-flag-locked.patch
@@ -0,0 +1,58 @@
+From 1111ae49a509d672b43194d2e483f297f98d78ad Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Wed, 23 Mar 2016 14:16:25 +0000
+Subject: [PATCH 210/381] vchiq_arm: Access the dequeue_pending flag locked
+
+Reading through this code looking for another problem (now found in userland)
+the use of dequeue_pending outside a lock didn't seem safe.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ .../misc/vc04_services/interface/vchiq_arm/vchiq_arm.c | 17 ++++++++++++-----
+ 1 file changed, 12 insertions(+), 5 deletions(-)
+
+--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c
++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c
+@@ -279,6 +279,7 @@ service_callback(VCHIQ_REASON_T reason,
+ USER_SERVICE_T *user_service;
+ VCHIQ_SERVICE_T *service;
+ VCHIQ_INSTANCE_T instance;
++ int skip_completion = 0;
+ DEBUG_INITIALISE(g_state.local)
+
+ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
+@@ -345,9 +346,6 @@ service_callback(VCHIQ_REASON_T reason,
+ user_service->msg_queue[user_service->msg_insert &
+ (MSG_QUEUE_SIZE - 1)] = header;
+ user_service->msg_insert++;
+- spin_unlock(&msg_queue_spinlock);
+-
+- up(&user_service->insert_event);
+
+ /* If there is a thread waiting in DEQUEUE_MESSAGE, or if
+ ** there is a MESSAGE_AVAILABLE in the completion queue then
+@@ -356,13 +354,22 @@ service_callback(VCHIQ_REASON_T reason,
+ if (((user_service->message_available_pos -
+ instance->completion_remove) >= 0) ||
+ user_service->dequeue_pending) {
+- DEBUG_TRACE(SERVICE_CALLBACK_LINE);
+ user_service->dequeue_pending = 0;
+- return VCHIQ_SUCCESS;
++ skip_completion = 1;
+ }
+
++ spin_unlock(&msg_queue_spinlock);
++
++ up(&user_service->insert_event);
++
+ header = NULL;
+ }
++
++ if (skip_completion) {
++ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
++ return VCHIQ_SUCCESS;
++ }
++
+ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
+
+ return add_completion(instance, reason, header, user_service,
diff --git a/target/linux/brcm2708/patches-4.4/0211-BCM270X_DT-Add-pi3-act-led-overlay.patch b/target/linux/brcm2708/patches-4.4/0211-BCM270X_DT-Add-pi3-act-led-overlay.patch
new file mode 100644
index 0000000000..6d0f8d9ccd
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0211-BCM270X_DT-Add-pi3-act-led-overlay.patch
@@ -0,0 +1,94 @@
+From ad4f6a8fc5af2d320ded80d44017bbd2a83425b4 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Wed, 23 Mar 2016 15:57:14 +0000
+Subject: [PATCH 211/381] BCM270X_DT: Add pi3-act-led overlay
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 19 +++++++++++++++
+ arch/arm/boot/dts/overlays/pi3-act-led-overlay.dts | 27 ++++++++++++++++++++++
+ 3 files changed, 47 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/pi3-act-led-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -39,6 +39,7 @@ dtbo-$(RPI_DT_OVERLAYS) += mcp2515-can0.
+ dtbo-$(RPI_DT_OVERLAYS) += mcp2515-can1.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += mmc.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += mz61581.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += pi3-act-led.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += pi3-disable-bt.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += pi3-miniuart-bt.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += piscreen.dtbo
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -136,12 +136,14 @@ Params:
+
+ act_led_activelow Set to "on" to invert the sense of the LED
+ (default "off")
++ N.B. For Pi3 see pi3-act-led overlay.
+
+ act_led_gpio Set which GPIO to use for the activity LED
+ (in case you want to connect it to an external
+ device)
+ (default "16" on a non-Plus board, "47" on a
+ Plus or Pi 2)
++ N.B. For Pi3 see pi3-act-led overlay.
+
+ pwr_led_trigger
+ pwr_led_activelow
+@@ -499,6 +501,23 @@ Params: speed Display
+ [ The pcf8563-rtc overlay has been deleted. See i2c-rtc. ]
+
+
++Name: pi3-act-led
++Info: Pi3 uses a GPIO expander to drive the LEDs which can only be accessed
++ from the VPU. There is a special driver for this with a separate DT
++ node, which has the unfortunate consequence of breaking the
++ act_led_gpio and act_led_activelow dtparams.
++ This overlay changes the GPIO controller back to the standard one and
++ restores the dtparams.
++Load: dtoverlay=pi3-act-led,<param>=<val>
++Params: activelow Set to "on" to invert the sense of the LED
++ (default "off")
++
++ gpio Set which GPIO to use for the activity LED
++ (in case you want to connect it to an external
++ device)
++ REQUIRED
++
++
+ Name: pi3-disable-bt
+ Info: Disable Pi3 Bluetooth and restore UART0/ttyAMA0 over GPIOs 14 & 15
+ N.B. To disable the systemd service that initialises the modem so it
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/pi3-act-led-overlay.dts
+@@ -0,0 +1,27 @@
++/dts-v1/;
++/plugin/;
++
++/* Pi3 uses a GPIO expander to drive the LEDs which can only be accessed
++ from the VPU. There is a special driver for this with a separate DT node,
++ which has the unfortunate consequence of breaking the act_led_gpio and
++ act_led_activelow dtparams.
++
++ This overlay changes the GPIO controller back to the standard one and
++ restores the dtparams.
++*/
++
++/{
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&act_led>;
++ frag0: __overlay__ {
++ gpios = <&gpio 0 0>;
++ };
++ };
++
++ __overrides__ {
++ gpio = <&frag0>,"gpios:4";
++ activelow = <&frag0>,"gpios:8";
++ };
++};
diff --git a/target/linux/brcm2708/patches-4.4/0212-vchiq_arm-Service-callbacks-must-not-fail.patch b/target/linux/brcm2708/patches-4.4/0212-vchiq_arm-Service-callbacks-must-not-fail.patch
new file mode 100644
index 0000000000..c585e4c80e
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0212-vchiq_arm-Service-callbacks-must-not-fail.patch
@@ -0,0 +1,26 @@
+From 5e6d6c93611ce75ac6c33515785ff2a37e3845d5 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Wed, 23 Mar 2016 20:53:47 +0000
+Subject: [PATCH 212/381] vchiq_arm: Service callbacks must not fail
+
+Service callbacks are not allowed to return an error. The internal callback
+that delivers events and messages to user tasks does not enqueue them if
+the service is closing, but this is not an error and should not be
+reported as such.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c
++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c
+@@ -224,7 +224,7 @@ add_completion(VCHIQ_INSTANCE_T instance
+ } else if (instance->closing) {
+ vchiq_log_info(vchiq_arm_log_level,
+ "service_callback closing");
+- return VCHIQ_ERROR;
++ return VCHIQ_SUCCESS;
+ }
+ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
+ }
diff --git a/target/linux/brcm2708/patches-4.4/0213-Add-configs-and-overlay-for-PCA9548-I2C-mux.patch b/target/linux/brcm2708/patches-4.4/0213-Add-configs-and-overlay-for-PCA9548-I2C-mux.patch
new file mode 100644
index 0000000000..29fcdfcc2d
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0213-Add-configs-and-overlay-for-PCA9548-I2C-mux.patch
@@ -0,0 +1,133 @@
+From c00bcce082d0dc0b3b6ccd136b32da3c146784dc Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <6by9@users.noreply.github.com>
+Date: Thu, 17 Mar 2016 18:16:16 +0000
+Subject: [PATCH 213/381] Add configs and overlay for PCA9548 I2C mux
+
+Adds kernel configs for I2C muxes and a dt overlay for PCA9548
+that adds the 8 muxed I2C buses and mux device.
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 6 ++
+ .../boot/dts/overlays/i2c-mux-pca9548a-overlay.dts | 67 ++++++++++++++++++++++
+ arch/arm/configs/bcm2709_defconfig | 2 +
+ arch/arm/configs/bcmrpi_defconfig | 2 +
+ 5 files changed, 78 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/i2c-mux-pca9548a-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -29,6 +29,7 @@ dtbo-$(RPI_DT_OVERLAYS) += hy28a.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += hy28b.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += i2c-rtc.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += i2c-gpio.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += i2c-mux-pca9548a.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += i2c0-bcm2708.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += i2c1-bcm2708.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += i2s-mmap.dtbo
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -360,6 +360,12 @@ Params: i2c_gpio_sda GPIO use
+ (default "2" = ~100kHz)
+
+
++Name: i2c-mux-pca9548a
++Info: Adds support for an NXP PCA9548A I2C multiplexer on i2c_arm
++Load: dtoverlay=i2c-mux-pca9548a,<param>=<val>
++Params: addr I2C address of PCA9548A (default 0x70)
++
++
+ Name: i2c-rtc
+ Info: Adds support for a number of I2C Real Time Clock devices
+ Load: dtoverlay=i2c-rtc,<param>=<val>
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/i2c-mux-pca9548a-overlay.dts
+@@ -0,0 +1,67 @@
++// Definitions for NXP PCA9548A I2C mux on ARM I2C bus.
++/dts-v1/;
++/plugin/;
++
++/{
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&i2c_arm>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ i2cmux: mux@70 {
++ compatible = "nxp,pca9548";
++ reg = <0x70>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ i2c@0 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0>;
++ };
++ i2c@1 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <1>;
++ };
++ i2c@2 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <2>;
++ };
++ i2c@3 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <3>;
++ };
++ i2c@4 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <4>;
++ };
++ i2c@5 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <5>;
++ };
++ i2c@6 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <6>;
++ };
++ i2c@7 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <7>;
++ };
++ };
++ };
++ };
++ __overrides__ {
++ addr = <&i2cmux>,"reg:0";
++ };
++};
+--- a/arch/arm/configs/bcm2709_defconfig
++++ b/arch/arm/configs/bcm2709_defconfig
+@@ -600,6 +600,8 @@ CONFIG_I2C=y
+ CONFIG_I2C_CHARDEV=m
+ CONFIG_I2C_BCM2708=m
+ CONFIG_I2C_GPIO=m
++CONFIG_I2C_MUX=m
++CONFIG_I2C_MUX_PCA954x=m
+ CONFIG_SPI=y
+ CONFIG_SPI_BCM2835=m
+ CONFIG_SPI_BCM2835AUX=m
+--- a/arch/arm/configs/bcmrpi_defconfig
++++ b/arch/arm/configs/bcmrpi_defconfig
+@@ -593,6 +593,8 @@ CONFIG_I2C=y
+ CONFIG_I2C_CHARDEV=m
+ CONFIG_I2C_BCM2708=m
+ CONFIG_I2C_GPIO=m
++CONFIG_I2C_MUX=m
++CONFIG_I2C_MUX_PCA954x=m
+ CONFIG_SPI=y
+ CONFIG_SPI_BCM2835=m
+ CONFIG_SPI_BCM2835AUX=m
diff --git a/target/linux/brcm2708/patches-4.4/0214-BCM270X_DT-Add-DS1339-to-i2c-rtc-overlay.patch b/target/linux/brcm2708/patches-4.4/0214-BCM270X_DT-Add-DS1339-to-i2c-rtc-overlay.patch
new file mode 100644
index 0000000000..e3bd651dbd
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0214-BCM270X_DT-Add-DS1339-to-i2c-rtc-overlay.patch
@@ -0,0 +1,58 @@
+From 679482c3c45177399648d096b7336ba3b1894126 Mon Sep 17 00:00:00 2001
+From: Nicolas Boullis <nboullis@debian.org>
+Date: Wed, 23 Mar 2016 23:40:15 +0100
+Subject: [PATCH 214/381] BCM270X_DT: Add DS1339 to i2c-rtc overlay
+
+---
+ arch/arm/boot/dts/overlays/README | 4 ++++
+ arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts | 8 ++++++++
+ 2 files changed, 12 insertions(+)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -371,6 +371,8 @@ Info: Adds support for a number of I2C
+ Load: dtoverlay=i2c-rtc,<param>=<val>
+ Params: ds1307 Select the DS1307 device
+
++ ds1339 Select the DS1339 device
++
+ ds3231 Select the DS3231 device
+
+ mcp7941x Select the MCP7941x device
+@@ -381,6 +383,8 @@ Params: ds1307 Select t
+
+ pcf8563 Select the PCF8563 device
+
++ trickle-resistor-ohms Resistor value for trickle charge (DS1339-only)
++
+
+ Name: i2c0-bcm2708
+ Info: Enable the i2c_bcm2708 driver for the i2c0 bus
+--- a/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
+@@ -17,6 +17,12 @@
+ reg = <0x68>;
+ status = "disable";
+ };
++ ds1339: ds1339@68 {
++ compatible = "dallas,ds1339";
++ trickle-resistor-ohms = <0>;
++ reg = <0x68>;
++ status = "disable";
++ };
+ mcp7941x: mcp7941x@6f {
+ compatible = "microchip,mcp7941x";
+ reg = <0x6f>;
+@@ -46,10 +52,12 @@
+ };
+ __overrides__ {
+ ds1307 = <&ds1307>,"status";
++ ds1339 = <&ds1339>,"status";
+ ds3231 = <&ds3231>,"status";
+ mcp7941x = <&mcp7941x>,"status";
+ pcf2127 = <&pcf2127>,"status";
+ pcf8523 = <&pcf8523>,"status";
+ pcf8563 = <&pcf8563>,"status";
++ trickle-resistor-ohms = <&ds1339>,"trickle-resistor-ohms:0";
+ };
+ };
diff --git a/target/linux/brcm2708/patches-4.4/0215-copy_from_user-CPU_SW_DOMAIN_PAN-compatibility.patch b/target/linux/brcm2708/patches-4.4/0215-copy_from_user-CPU_SW_DOMAIN_PAN-compatibility.patch
new file mode 100644
index 0000000000..f5a2e942aa
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0215-copy_from_user-CPU_SW_DOMAIN_PAN-compatibility.patch
@@ -0,0 +1,53 @@
+From 226f58c078e55ba665fb49139cdc4990f4bde684 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Tue, 29 Mar 2016 15:32:30 +0100
+Subject: [PATCH 215/381] copy_from_user: CPU_SW_DOMAIN_PAN compatibility
+
+The downstream copy_from_user acceleration must also play nice with
+CONFIG_CPU_SW_DOMAIN_PAN.
+
+See: https://github.com/raspberrypi/linux/issues/1381
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/lib/uaccess_with_memcpy.c | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
+
+--- a/arch/arm/lib/uaccess_with_memcpy.c
++++ b/arch/arm/lib/uaccess_with_memcpy.c
+@@ -186,6 +186,7 @@ out:
+ unsigned long noinline
+ __copy_from_user_memcpy(void *to, const void __user *from, unsigned long n)
+ {
++ unsigned long ua_flags;
+ int atomic;
+
+ if (unlikely(segment_eq(get_fs(), KERNEL_DS))) {
+@@ -217,7 +218,9 @@ __copy_from_user_memcpy(void *to, const
+ if (tocopy > n)
+ tocopy = n;
+
++ ua_flags = uaccess_save_and_enable();
+ memcpy(to, (const void *)from, tocopy);
++ uaccess_restore(ua_flags);
+ to += tocopy;
+ from += tocopy;
+ n -= tocopy;
+@@ -261,9 +264,14 @@ arm_copy_from_user(void *to, const void
+ * With frame pointer disabled, tail call optimization kicks in
+ * as well making this test almost invisible.
+ */
+- if (n < COPY_FROM_USER_THRESHOLD)
+- return __copy_from_user_std(to, from, n);
+- return __copy_from_user_memcpy(to, from, n);
++ if (n < COPY_TO_USER_THRESHOLD) {
++ unsigned long ua_flags = uaccess_save_and_enable();
++ n = __copy_from_user_std(to, from, n);
++ uaccess_restore(ua_flags);
++ } else {
++ n = __copy_from_user_memcpy(to, from, n);
++ }
++ return n;
+ }
+
+ static unsigned long noinline
diff --git a/target/linux/brcm2708/patches-4.4/0216-bcm2835-sdhost-Adjust-to-core-clock-changes.patch b/target/linux/brcm2708/patches-4.4/0216-bcm2835-sdhost-Adjust-to-core-clock-changes.patch
new file mode 100644
index 0000000000..4f54dbe795
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0216-bcm2835-sdhost-Adjust-to-core-clock-changes.patch
@@ -0,0 +1,339 @@
+From 0608f91c0bf114dcd2b603b8e85866fe8d595854 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Wed, 30 Mar 2016 16:33:09 +0100
+Subject: [PATCH 216/381] bcm2835-sdhost: Adjust to core clock changes
+
+The SDHOST block uses the core clock, so previously it has been
+necessary to prevent the core clock from changing in order to maintain
+performance and prevent accidental SD bus overclocking.
+
+With this patch the sdhost driver is notified of clock changes, allowing
+it to delay them while an SD access is outstanding and to delay new SD
+accesses while the clock is changing. This feature is disabled in the
+case where the core frequency can never change.
+
+Now that the driver copes with changes to the core clock, it is safe
+to disable the io_is_busy feature of the on-demand governor.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/mmc/host/Kconfig | 1 +
+ drivers/mmc/host/bcm2835-sdhost.c | 140 ++++++++++++++++++++++++++++++++------
+ 2 files changed, 119 insertions(+), 22 deletions(-)
+
+--- a/drivers/mmc/host/Kconfig
++++ b/drivers/mmc/host/Kconfig
+@@ -36,6 +36,7 @@ config MMC_BCM2835_PIO_DMA_BARRIER
+ config MMC_BCM2835_SDHOST
+ tristate "Support for the SDHost controller on BCM2708/9"
+ depends on MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835
++ depends on RASPBERRYPI_FIRMWARE
+ help
+ This selects the SDHost controller on BCM2835/6.
+
+--- a/drivers/mmc/host/bcm2835-sdhost.c
++++ b/drivers/mmc/host/bcm2835-sdhost.c
+@@ -50,6 +50,10 @@
+ #include <linux/of_dma.h>
+ #include <linux/time.h>
+ #include <linux/workqueue.h>
++#include <linux/cpufreq.h>
++#include <linux/semaphore.h>
++#include <soc/bcm2835/raspberrypi-firmware.h>
++
+
+ #define DRIVER_NAME "sdhost-bcm2835"
+
+@@ -136,6 +140,8 @@
+
+ #define MHZ 1000000
+
++#define RPI_FIRMWARE_CLOCK_CORE 4
++
+
+ struct bcm2835_host {
+ spinlock_t lock;
+@@ -151,7 +157,9 @@ struct bcm2835_host {
+
+ bool slow_card; /* Force 11-bit divisor */
+
+- unsigned int max_clk; /* Max possible freq */
++ unsigned int max_clk; /* Max src clock freq */
++ unsigned int min_clk; /* Min src clock freq */
++ unsigned int cur_clk; /* Current src clock freq */
+
+ struct tasklet_struct finish_tasklet; /* Tasklet structures */
+
+@@ -183,6 +191,7 @@ struct bcm2835_host {
+ unsigned int use_sbc:1; /* Send CMD23 */
+
+ unsigned int debug:1; /* Enable debug output */
++ unsigned int variable_clock:1; /* The core clock may change */
+
+ /*DMA part*/
+ struct dma_chan *dma_chan_rxtx; /* DMA channel for reads and writes */
+@@ -208,6 +217,9 @@ struct bcm2835_host {
+ u32 pio_limit; /* Maximum block count for PIO (0 = always DMA) */
+
+ u32 sectors; /* Cached card size in sectors */
++
++ struct notifier_block cpufreq_nb; /* The cpufreq callback list item */
++ struct semaphore cpufreq_semaphore; /* Interlock between SD activity and cpufreq changes */
+ };
+
+ #if ENABLE_LOG
+@@ -227,6 +239,10 @@ static u32 sdhost_log_idx;
+ static spinlock_t log_lock;
+ static void __iomem *timer_base;
+
++static int bcm2835_sdhost_cpufreq_callback(struct notifier_block *nb,
++ unsigned long action, void *data);
++static unsigned int get_core_clock(unsigned int mode);
++
+ #define LOG_ENTRIES (256*1)
+ #define LOG_SIZE (sizeof(LOG_ENTRY_T)*LOG_ENTRIES)
+
+@@ -448,20 +464,14 @@ static void bcm2835_sdhost_reset(struct
+
+ static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
+
+-static void bcm2835_sdhost_init(struct bcm2835_host *host, int soft)
++static void bcm2835_sdhost_init(struct bcm2835_host *host)
+ {
+- pr_debug("bcm2835_sdhost_init(%d)\n", soft);
++ pr_debug("bcm2835_sdhost_init()\n");
+
+ /* Set interrupt enables */
+ host->hcfg = SDHCFG_BUSY_IRPT_EN;
+
+ bcm2835_sdhost_reset_internal(host);
+-
+- if (soft) {
+- /* force clock reconfiguration */
+- host->clock = 0;
+- bcm2835_sdhost_set_ios(host->mmc, &host->mmc->ios);
+- }
+ }
+
+ static void bcm2835_sdhost_wait_transfer_complete(struct bcm2835_host *host)
+@@ -1499,10 +1509,10 @@ static irqreturn_t bcm2835_sdhost_irq(in
+ return result;
+ }
+
+-void bcm2835_sdhost_set_clock(struct bcm2835_host *host, unsigned int clock)
++void bcm2835_sdhost_set_clock(struct bcm2835_host *host)
+ {
+ int div = 0; /* Initialized for compiler warning */
+- unsigned int input_clock = clock;
++ unsigned int clock = host->clock;
+
+ if (host->debug)
+ pr_info("%s: set_clock(%d)\n", mmc_hostname(host->mmc), clock);
+@@ -1543,17 +1553,17 @@ void bcm2835_sdhost_set_clock(struct bcm
+ return;
+ }
+
+- div = host->max_clk / clock;
++ div = host->cur_clk / clock;
+ if (div < 2)
+ div = 2;
+- if ((host->max_clk / div) > clock)
++ if ((host->cur_clk / div) > clock)
+ div++;
+ div -= 2;
+
+ if (div > SDCDIV_MAX_CDIV)
+ div = SDCDIV_MAX_CDIV;
+
+- clock = host->max_clk / (div + 2);
++ clock = host->cur_clk / (div + 2);
+ host->mmc->actual_clock = clock;
+
+ /* Calibrate some delays */
+@@ -1561,7 +1571,7 @@ void bcm2835_sdhost_set_clock(struct bcm
+ host->ns_per_fifo_word = (1000000000/clock) *
+ ((host->mmc->caps & MMC_CAP_4_BIT_DATA) ? 8 : 32);
+
+- if (clock > input_clock) {
++ if (clock > host->clock) {
+ /* Save the closest value, to make it easier
+ to reduce in the event of error */
+ host->overclock_50 = (clock/MHZ);
+@@ -1587,9 +1597,9 @@ void bcm2835_sdhost_set_clock(struct bcm
+ bcm2835_sdhost_write(host, host->mmc->actual_clock/2, SDTOUT);
+
+ if (host->debug)
+- pr_info("%s: clock=%d -> max_clk=%d, cdiv=%x (actual clock %d)\n",
+- mmc_hostname(host->mmc), input_clock,
+- host->max_clk, host->cdiv, host->mmc->actual_clock);
++ pr_info("%s: clock=%d -> cur_clk=%d, cdiv=%x (actual clock %d)\n",
++ mmc_hostname(host->mmc), host->clock,
++ host->cur_clk, host->cdiv, host->mmc->actual_clock);
+ }
+
+ static void bcm2835_sdhost_request(struct mmc_host *mmc, struct mmc_request *mrq)
+@@ -1638,6 +1648,13 @@ static void bcm2835_sdhost_request(struc
+ (mrq->data->blocks > host->pio_limit))
+ bcm2835_sdhost_prepare_dma(host, mrq->data);
+
++ if (host->variable_clock &&
++ (down_killable(&host->cpufreq_semaphore) != 0)) {
++ mrq->cmd->error = -EINTR;
++ mmc_request_done(mmc, mrq);
++ return;
++ }
++
+ spin_lock_irqsave(&host->lock, flags);
+
+ WARN_ON(host->mrq != NULL);
+@@ -1687,6 +1704,52 @@ static void bcm2835_sdhost_request(struc
+ spin_unlock_irqrestore(&host->lock, flags);
+ }
+
++static int bcm2835_sdhost_cpufreq_callback(struct notifier_block *nb,
++ unsigned long action, void *data)
++{
++ struct cpufreq_freqs *freq = data;
++ struct bcm2835_host *host;
++
++ host = container_of(nb, struct bcm2835_host, cpufreq_nb);
++
++ if (freq->cpu == 0) {
++ switch (action) {
++ case CPUFREQ_PRECHANGE:
++ if (down_killable(&host->cpufreq_semaphore) != 0)
++ return NOTIFY_BAD;
++ break;
++ case CPUFREQ_POSTCHANGE:
++ if (freq->new > freq->old)
++ host->cur_clk = host->max_clk;
++ else
++ host->cur_clk = host->min_clk;
++ bcm2835_sdhost_set_clock(host);
++ up(&host->cpufreq_semaphore);
++ break;
++ default:
++ break;
++ }
++ }
++ return NOTIFY_OK;
++}
++
++static unsigned int get_core_clock(unsigned int mode)
++{
++ struct rpi_firmware *fw = rpi_firmware_get(NULL);
++ struct {
++ u32 id;
++ u32 val;
++ } packet;
++ int ret;
++
++ packet.id = RPI_FIRMWARE_CLOCK_CORE;
++ ret = rpi_firmware_property(fw, mode, &packet, sizeof(packet));
++ if (ret)
++ return 0;
++
++ return packet.val;
++}
++
+ static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+ {
+
+@@ -1700,13 +1763,16 @@ static void bcm2835_sdhost_set_ios(struc
+ ios->clock, ios->power_mode, ios->bus_width,
+ ios->timing, ios->signal_voltage, ios->drv_type);
+
++ if (ios->clock && !host->cur_clk)
++ host->cur_clk = get_core_clock(RPI_FIRMWARE_GET_CLOCK_RATE);
++
+ spin_lock_irqsave(&host->lock, flags);
+
+ log_event("IOS<", ios->clock, 0);
+
+ if (!ios->clock || ios->clock != host->clock) {
+- bcm2835_sdhost_set_clock(host, ios->clock);
+ host->clock = ios->clock;
++ bcm2835_sdhost_set_clock(host);
+ }
+
+ /* set bus width */
+@@ -1795,7 +1861,7 @@ static void bcm2835_sdhost_tasklet_finis
+ host->overclock_50--;
+ pr_warn("%s: reducing overclock due to errors\n",
+ mmc_hostname(host->mmc));
+- bcm2835_sdhost_set_clock(host,50*MHZ);
++ bcm2835_sdhost_set_clock(host);
+ mrq->cmd->error = -EILSEQ;
+ mrq->cmd->retries = 1;
+ }
+@@ -1813,6 +1879,9 @@ static void bcm2835_sdhost_tasklet_finis
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
++ if (host->variable_clock)
++ up(&host->cpufreq_semaphore);
++
+ if (terminate_chan)
+ {
+ int err = dmaengine_terminate_all(terminate_chan);
+@@ -1915,10 +1984,10 @@ int bcm2835_sdhost_add_host(struct bcm28
+ setup_timer(&host->timer, bcm2835_sdhost_timeout,
+ (unsigned long)host);
+
+- bcm2835_sdhost_init(host, 0);
++ bcm2835_sdhost_init(host);
+
+ ret = request_irq(host->irq, bcm2835_sdhost_irq, 0 /*IRQF_SHARED*/,
+- mmc_hostname(mmc), host);
++ mmc_hostname(mmc), host);
+ if (ret) {
+ pr_err("%s: failed to request IRQ %d: %d\n",
+ mmc_hostname(mmc), host->irq, ret);
+@@ -1953,6 +2022,7 @@ static int bcm2835_sdhost_probe(struct p
+ struct bcm2835_host *host;
+ struct mmc_host *mmc;
+ const __be32 *addr;
++ unsigned int max_clk;
+ int ret;
+
+ pr_debug("bcm2835_sdhost_probe\n");
+@@ -2062,6 +2132,28 @@ static int bcm2835_sdhost_probe(struct p
+ if (ret)
+ goto err;
+
++ /* Query the core clock frequencies */
++ host->min_clk = get_core_clock(RPI_FIRMWARE_GET_MIN_CLOCK_RATE);
++ max_clk = get_core_clock(RPI_FIRMWARE_GET_MAX_CLOCK_RATE);
++ if (max_clk != host->max_clk) {
++ pr_warn("%s: Expected max clock %d, found %d\n",
++ mmc_hostname(mmc), host->max_clk, max_clk);
++ host->max_clk = max_clk;
++ }
++
++ if (host->min_clk != host->max_clk) {
++ host->cpufreq_nb.notifier_call =
++ bcm2835_sdhost_cpufreq_callback;
++ sema_init(&host->cpufreq_semaphore, 1);
++ cpufreq_register_notifier(&host->cpufreq_nb,
++ CPUFREQ_TRANSITION_NOTIFIER);
++ host->variable_clock = 1;
++ host->cur_clk = 0; /* Get this later */
++ } else {
++ host->variable_clock = 0;
++ host->cur_clk = host->max_clk;
++ }
++
+ platform_set_drvdata(pdev, host);
+
+ pr_debug("bcm2835_sdhost_probe -> OK\n");
+@@ -2081,6 +2173,10 @@ static int bcm2835_sdhost_remove(struct
+
+ pr_debug("bcm2835_sdhost_remove\n");
+
++ if (host->variable_clock)
++ cpufreq_unregister_notifier(&host->cpufreq_nb,
++ CPUFREQ_TRANSITION_NOTIFIER);
++
+ mmc_remove_host(host->mmc);
+
+ bcm2835_sdhost_set_power(host, false);
diff --git a/target/linux/brcm2708/patches-4.4/0217-BCM270X_DT-Document-hazards-of-sdhost-overlay.patch b/target/linux/brcm2708/patches-4.4/0217-BCM270X_DT-Document-hazards-of-sdhost-overlay.patch
new file mode 100644
index 0000000000..db505e57d8
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0217-BCM270X_DT-Document-hazards-of-sdhost-overlay.patch
@@ -0,0 +1,34 @@
+From 8cbaec5167f764d2c7b88c2f465970fd08c55582 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Wed, 30 Mar 2016 17:07:15 +0100
+Subject: [PATCH 217/381] BCM270X_DT: Document hazards of sdhost overlay
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/overlays/README | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -712,7 +712,11 @@ Params: <None>
+
+
+ Name: sdhost
+-Info: Selects the bcm2835-sdhost SD/MMC driver, optionally with overclock
++Info: Selects the bcm2835-sdhost SD/MMC driver, optionally with overclock.
++ N.B. This overlay is designed for situations where the mmc driver is
++ the default, so it disables the other (mmc) interface - this will kill
++ WiFi on a Pi3. If this isn't what you want, either use the sdtweak
++ overlay or the new sd_* dtparams of the base DTBs.
+ Load: dtoverlay=sdhost,<param>=<val>
+ Params: overclock_50 Clock (in MHz) to use when the MMC framework
+ requests 50MHz
+@@ -771,6 +775,8 @@ Params: overclock_50 SD Clock
+
+ Name: sdtweak
+ Info: Tunes the bcm2835-sdhost SD/MMC driver
++ N.B. This functionality is now available via the sd_* dtparams in the
++ base DTB.
+ Load: dtoverlay=sdtweak,<param>=<val>
+ Params: overclock_50 Clock (in MHz) to use when the MMC framework
+ requests 50MHz
diff --git a/target/linux/brcm2708/patches-4.4/0218-cpufreq-Temporarily-ignore-io_is_busy-1.patch b/target/linux/brcm2708/patches-4.4/0218-cpufreq-Temporarily-ignore-io_is_busy-1.patch
new file mode 100644
index 0000000000..f1f2a95cdc
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0218-cpufreq-Temporarily-ignore-io_is_busy-1.patch
@@ -0,0 +1,31 @@
+From bf137324a7f873dc90b9965398de259f5d992f9b Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Wed, 30 Mar 2016 17:23:15 +0100
+Subject: [PATCH 218/381] cpufreq: Temporarily ignore io_is_busy=1
+
+To speed testing of the new sdhost driver that adapts to changes in
+core_freq, hack the on-demand governor to treat io_is_busy=1 as
+io_is_busy=0. The io_is_busy feature can still be forced using
+io_is_busy=2.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/cpufreq/cpufreq_ondemand.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/drivers/cpufreq/cpufreq_ondemand.c
++++ b/drivers/cpufreq/cpufreq_ondemand.c
+@@ -307,7 +307,12 @@ static ssize_t store_io_is_busy(struct d
+ ret = sscanf(buf, "%u", &input);
+ if (ret != 1)
+ return -EINVAL;
+- od_tuners->io_is_busy = !!input;
++ // XXX temporary hack
++ if (input > 1)
++ input = 1;
++ else
++ input = 0;
++ od_tuners->io_is_busy = input;
+
+ /* we need to re-evaluate prev_cpu_idle */
+ for_each_online_cpu(j) {
diff --git a/target/linux/brcm2708/patches-4.4/0219-Revert-cpufreq-Temporarily-ignore-io_is_busy-1.patch b/target/linux/brcm2708/patches-4.4/0219-Revert-cpufreq-Temporarily-ignore-io_is_busy-1.patch
new file mode 100644
index 0000000000..6a293f4496
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0219-Revert-cpufreq-Temporarily-ignore-io_is_busy-1.patch
@@ -0,0 +1,26 @@
+From 7512663c7fc8117e3a57f0feef53de88fb8a2c89 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Wed, 30 Mar 2016 20:18:38 +0100
+Subject: [PATCH 219/381] Revert "cpufreq: Temporarily ignore io_is_busy=1"
+
+This reverts commit 2af1218a8a0220fec526f64d03977b8451afb4c8.
+---
+ drivers/cpufreq/cpufreq_ondemand.c | 7 +------
+ 1 file changed, 1 insertion(+), 6 deletions(-)
+
+--- a/drivers/cpufreq/cpufreq_ondemand.c
++++ b/drivers/cpufreq/cpufreq_ondemand.c
+@@ -307,12 +307,7 @@ static ssize_t store_io_is_busy(struct d
+ ret = sscanf(buf, "%u", &input);
+ if (ret != 1)
+ return -EINVAL;
+- // XXX temporary hack
+- if (input > 1)
+- input = 1;
+- else
+- input = 0;
+- od_tuners->io_is_busy = input;
++ od_tuners->io_is_busy = !!input;
+
+ /* we need to re-evaluate prev_cpu_idle */
+ for_each_online_cpu(j) {
diff --git a/target/linux/brcm2708/patches-4.4/0220-net-sched-add-skb_at_tc_ingress-helper.patch b/target/linux/brcm2708/patches-4.4/0220-net-sched-add-skb_at_tc_ingress-helper.patch
new file mode 100644
index 0000000000..f9006e5619
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0220-net-sched-add-skb_at_tc_ingress-helper.patch
@@ -0,0 +1,50 @@
+From 20f13356555bf192a95e2ea77a01746d754e37be Mon Sep 17 00:00:00 2001
+From: Daniel Borkmann <daniel@iogearbox.net>
+Date: Thu, 7 Jan 2016 15:50:22 +0100
+Subject: [PATCH 220/381] net, sched: add skb_at_tc_ingress helper
+
+Add a skb_at_tc_ingress() as this will be needed elsewhere as well and
+can hide the ugly ifdef.
+
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Acked-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ include/net/sch_generic.h | 9 +++++++++
+ net/sched/cls_bpf.c | 6 +-----
+ 2 files changed, 10 insertions(+), 5 deletions(-)
+
+--- a/include/net/sch_generic.h
++++ b/include/net/sch_generic.h
+@@ -409,6 +409,15 @@ bool tcf_destroy(struct tcf_proto *tp, b
+ void tcf_destroy_chain(struct tcf_proto __rcu **fl);
+ int skb_do_redirect(struct sk_buff *);
+
++static inline bool skb_at_tc_ingress(const struct sk_buff *skb)
++{
++#ifdef CONFIG_NET_CLS_ACT
++ return G_TC_AT(skb->tc_verd) & AT_INGRESS;
++#else
++ return false;
++#endif
++}
++
+ /* Reset all TX qdiscs greater then index of a device. */
+ static inline void qdisc_reset_all_tx_gt(struct net_device *dev, unsigned int i)
+ {
+--- a/net/sched/cls_bpf.c
++++ b/net/sched/cls_bpf.c
+@@ -79,12 +79,8 @@ static int cls_bpf_classify(struct sk_bu
+ struct tcf_result *res)
+ {
+ struct cls_bpf_head *head = rcu_dereference_bh(tp->root);
++ bool at_ingress = skb_at_tc_ingress(skb);
+ struct cls_bpf_prog *prog;
+-#ifdef CONFIG_NET_CLS_ACT
+- bool at_ingress = G_TC_AT(skb->tc_verd) & AT_INGRESS;
+-#else
+- bool at_ingress = false;
+-#endif
+ int ret = -1;
+
+ if (unlikely(!skb_mac_header_was_set(skb)))
diff --git a/target/linux/brcm2708/patches-4.4/0222-bcm2835-sdhost-Precalc-divisors-and-overclocks.patch b/target/linux/brcm2708/patches-4.4/0222-bcm2835-sdhost-Precalc-divisors-and-overclocks.patch
new file mode 100644
index 0000000000..663893855b
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0222-bcm2835-sdhost-Precalc-divisors-and-overclocks.patch
@@ -0,0 +1,270 @@
+From e87ddfc18bbca9beae107b274b317fb86420b0a5 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Thu, 31 Mar 2016 15:44:53 +0100
+Subject: [PATCH 222/381] bcm2835-sdhost: Precalc divisors and overclocks
+
+Recalculating the clock divisors when the core clock changes is wasteful
+and makes it harder to manage the overclock settings. Instead,
+precalculate them and only report significant changes.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/mmc/host/bcm2835-sdhost.c | 152 ++++++++++++++++++++++----------------
+ 1 file changed, 88 insertions(+), 64 deletions(-)
+
+--- a/drivers/mmc/host/bcm2835-sdhost.c
++++ b/drivers/mmc/host/bcm2835-sdhost.c
+@@ -154,12 +154,15 @@ struct bcm2835_host {
+ u32 pio_timeout; /* In jiffies */
+
+ int clock; /* Current clock speed */
++ int clocks[2];
+
+ bool slow_card; /* Force 11-bit divisor */
+
+ unsigned int max_clk; /* Max src clock freq */
+- unsigned int min_clk; /* Min src clock freq */
+- unsigned int cur_clk; /* Current src clock freq */
++ unsigned int src_clks[2]; /* Min/max src clock freqs */
++ unsigned int cur_clk_idx; /* Index of current clock */
++ unsigned int next_clk_idx; /* Next clock index */
++ unsigned int cdivs[2];
+
+ struct tasklet_struct finish_tasklet; /* Tasklet structures */
+
+@@ -213,7 +216,7 @@ struct bcm2835_host {
+ u32 delay_after_stop; /* minimum time between stop and subsequent data transfer */
+ u32 delay_after_this_stop; /* minimum time between this stop and subsequent data transfer */
+ u32 overclock_50; /* frequency to use when 50MHz is requested (in MHz) */
+- u32 overclock; /* Current frequency if overclocked, else zero */
++ u32 prev_overclock_50;
+ u32 pio_limit; /* Maximum block count for PIO (0 = always DMA) */
+
+ u32 sectors; /* Cached card size in sectors */
+@@ -1509,10 +1512,35 @@ static irqreturn_t bcm2835_sdhost_irq(in
+ return result;
+ }
+
++static void bcm2835_sdhost_select_clock(struct bcm2835_host *host, int idx)
++{
++ unsigned int clock = host->clocks[idx];
++ unsigned int cdiv = host->cdivs[idx];
++
++ host->mmc->actual_clock = clock;
++ host->ns_per_fifo_word = (1000000000/clock) *
++ ((host->mmc->caps & MMC_CAP_4_BIT_DATA) ? 8 : 32);
++
++ host->cdiv = cdiv;
++ bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
++
++ /* Set the timeout to 500ms */
++ bcm2835_sdhost_write(host, clock/2, SDTOUT);
++
++ host->cur_clk_idx = host->next_clk_idx = idx;
++
++ if (host->debug)
++ pr_info("%s: clock=%d -> src_clk=%d, cdiv=%x (actual %d)\n",
++ mmc_hostname(host->mmc), host->clock,
++ host->src_clks[idx], host->cdiv,
++ host->mmc->actual_clock);
++}
++
+ void bcm2835_sdhost_set_clock(struct bcm2835_host *host)
+ {
+ int div = 0; /* Initialized for compiler warning */
+ unsigned int clock = host->clock;
++ int clk_idx;
+
+ if (host->debug)
+ pr_info("%s: set_clock(%d)\n", mmc_hostname(host->mmc), clock);
+@@ -1553,53 +1581,45 @@ void bcm2835_sdhost_set_clock(struct bcm
+ return;
+ }
+
+- div = host->cur_clk / clock;
+- if (div < 2)
+- div = 2;
+- if ((host->cur_clk / div) > clock)
+- div++;
+- div -= 2;
+-
+- if (div > SDCDIV_MAX_CDIV)
+- div = SDCDIV_MAX_CDIV;
+-
+- clock = host->cur_clk / (div + 2);
+- host->mmc->actual_clock = clock;
+-
+- /* Calibrate some delays */
+-
+- host->ns_per_fifo_word = (1000000000/clock) *
+- ((host->mmc->caps & MMC_CAP_4_BIT_DATA) ? 8 : 32);
++ /* Calculate the clock divisors */
++ for (clk_idx = 0; clk_idx <= host->variable_clock; clk_idx++)
++ {
++ unsigned int cur_clk = host->src_clks[clk_idx];
++ unsigned int actual_clock;
+
+- if (clock > host->clock) {
+- /* Save the closest value, to make it easier
+- to reduce in the event of error */
+- host->overclock_50 = (clock/MHZ);
+-
+- if (clock != host->overclock) {
+- pr_warn("%s: overclocking to %dHz\n",
+- mmc_hostname(host->mmc), clock);
+- host->overclock = clock;
++ div = cur_clk / clock;
++ if (div < 2)
++ div = 2;
++ if ((cur_clk / div) > clock)
++ div++;
++ div -= 2;
++
++ if (div > SDCDIV_MAX_CDIV)
++ div = SDCDIV_MAX_CDIV;
++ actual_clock = cur_clk / (div + 2);
++
++ host->cdivs[clk_idx] = div;
++ host->clocks[clk_idx] = actual_clock;
++
++ if (host->overclock_50 != host->prev_overclock_50) {
++ const char *clk_name = "";
++ if (host->variable_clock)
++ clk_name = clk_idx ? " (turbo)" : " (normal)";
++ if (actual_clock > host->clock)
++ pr_info("%s: overclocking to %dHz%s\n",
++ mmc_hostname(host->mmc),
++ actual_clock, clk_name);
++ else if ((host->overclock_50 < 50) && (clk_idx == 0))
++ pr_info("%s: cancelling overclock%s\n",
++ mmc_hostname(host->mmc),
++ host->variable_clock ? "s" : "");
+ }
+ }
+- else if (host->overclock)
+- {
+- host->overclock = 0;
+- if (clock == 50 * MHZ)
+- pr_warn("%s: cancelling overclock\n",
+- mmc_hostname(host->mmc));
+- }
+
+- host->cdiv = div;
+- bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
++ if (host->clock == 50*MHZ)
++ host->prev_overclock_50 = host->overclock_50;
+
+- /* Set the timeout to 500ms */
+- bcm2835_sdhost_write(host, host->mmc->actual_clock/2, SDTOUT);
+-
+- if (host->debug)
+- pr_info("%s: clock=%d -> cur_clk=%d, cdiv=%x (actual clock %d)\n",
+- mmc_hostname(host->mmc), host->clock,
+- host->cur_clk, host->cdiv, host->mmc->actual_clock);
++ bcm2835_sdhost_select_clock(host, host->cur_clk_idx);
+ }
+
+ static void bcm2835_sdhost_request(struct mmc_host *mmc, struct mmc_request *mrq)
+@@ -1657,6 +1677,9 @@ static void bcm2835_sdhost_request(struc
+
+ spin_lock_irqsave(&host->lock, flags);
+
++ if (host->next_clk_idx != host->cur_clk_idx)
++ bcm2835_sdhost_select_clock(host, host->next_clk_idx);
++
+ WARN_ON(host->mrq != NULL);
+ host->mrq = mrq;
+
+@@ -1719,11 +1742,7 @@ static int bcm2835_sdhost_cpufreq_callba
+ return NOTIFY_BAD;
+ break;
+ case CPUFREQ_POSTCHANGE:
+- if (freq->new > freq->old)
+- host->cur_clk = host->max_clk;
+- else
+- host->cur_clk = host->min_clk;
+- bcm2835_sdhost_set_clock(host);
++ host->next_clk_idx = (freq->new > freq->old);
+ up(&host->cpufreq_semaphore);
+ break;
+ default:
+@@ -1763,8 +1782,11 @@ static void bcm2835_sdhost_set_ios(struc
+ ios->clock, ios->power_mode, ios->bus_width,
+ ios->timing, ios->signal_voltage, ios->drv_type);
+
+- if (ios->clock && !host->cur_clk)
+- host->cur_clk = get_core_clock(RPI_FIRMWARE_GET_CLOCK_RATE);
++ if (ios->clock && (host->cur_clk_idx == -1)) {
++ unsigned int cur_clk =
++ get_core_clock(RPI_FIRMWARE_GET_CLOCK_RATE);
++ host->cur_clk_idx = (cur_clk == host->src_clks[0]) ? 0 : 1;
++ }
+
+ spin_lock_irqsave(&host->lock, flags);
+
+@@ -1854,11 +1876,12 @@ static void bcm2835_sdhost_tasklet_finis
+
+ /* Drop the overclock after any data corruption, or after any
+ error overclocked */
+- if (host->overclock) {
++ if (host->clock > 50*MHZ) {
+ if ((mrq->cmd && mrq->cmd->error) ||
+ (mrq->data && mrq->data->error) ||
+ (mrq->stop && mrq->stop->error)) {
+- host->overclock_50--;
++ host->overclock_50 = (host->clock/MHZ) - 1;
++
+ pr_warn("%s: reducing overclock due to errors\n",
+ mmc_hostname(host->mmc));
+ bcm2835_sdhost_set_clock(host);
+@@ -2022,7 +2045,7 @@ static int bcm2835_sdhost_probe(struct p
+ struct bcm2835_host *host;
+ struct mmc_host *mmc;
+ const __be32 *addr;
+- unsigned int max_clk;
++ unsigned int max_clk, min_clk;
+ int ret;
+
+ pr_debug("bcm2835_sdhost_probe\n");
+@@ -2128,12 +2151,8 @@ static int bcm2835_sdhost_probe(struct p
+ else
+ mmc->caps |= MMC_CAP_4_BIT_DATA;
+
+- ret = bcm2835_sdhost_add_host(host);
+- if (ret)
+- goto err;
+-
+ /* Query the core clock frequencies */
+- host->min_clk = get_core_clock(RPI_FIRMWARE_GET_MIN_CLOCK_RATE);
++ min_clk = get_core_clock(RPI_FIRMWARE_GET_MIN_CLOCK_RATE);
+ max_clk = get_core_clock(RPI_FIRMWARE_GET_MAX_CLOCK_RATE);
+ if (max_clk != host->max_clk) {
+ pr_warn("%s: Expected max clock %d, found %d\n",
+@@ -2141,19 +2160,24 @@ static int bcm2835_sdhost_probe(struct p
+ host->max_clk = max_clk;
+ }
+
+- if (host->min_clk != host->max_clk) {
++ host->src_clks[0] = min_clk;
++ host->cur_clk_idx = -1;
++ if (max_clk != min_clk) {
++ host->src_clks[1] = max_clk;
+ host->cpufreq_nb.notifier_call =
+ bcm2835_sdhost_cpufreq_callback;
+ sema_init(&host->cpufreq_semaphore, 1);
+ cpufreq_register_notifier(&host->cpufreq_nb,
+ CPUFREQ_TRANSITION_NOTIFIER);
+ host->variable_clock = 1;
+- host->cur_clk = 0; /* Get this later */
+ } else {
+ host->variable_clock = 0;
+- host->cur_clk = host->max_clk;
+ }
+
++ ret = bcm2835_sdhost_add_host(host);
++ if (ret)
++ goto err;
++
+ platform_set_drvdata(pdev, host);
+
+ pr_debug("bcm2835_sdhost_probe -> OK\n");
diff --git a/target/linux/brcm2708/patches-4.4/0223-Revert-bcm2835-sdhost-Precalc-divisors-and-overclock.patch b/target/linux/brcm2708/patches-4.4/0223-Revert-bcm2835-sdhost-Precalc-divisors-and-overclock.patch
new file mode 100644
index 0000000000..958aa29da0
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0223-Revert-bcm2835-sdhost-Precalc-divisors-and-overclock.patch
@@ -0,0 +1,267 @@
+From 28d6ecd622da2efdb7a7c6c07ab8a92c82dded6b Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 4 Apr 2016 12:35:32 +0100
+Subject: [PATCH 223/381] Revert "bcm2835-sdhost: Precalc divisors and
+ overclocks"
+
+This reverts commit 20260462773366a5734e5268dae0a4c179a21a2d.
+---
+ drivers/mmc/host/bcm2835-sdhost.c | 152 ++++++++++++++++----------------------
+ 1 file changed, 64 insertions(+), 88 deletions(-)
+
+--- a/drivers/mmc/host/bcm2835-sdhost.c
++++ b/drivers/mmc/host/bcm2835-sdhost.c
+@@ -154,15 +154,12 @@ struct bcm2835_host {
+ u32 pio_timeout; /* In jiffies */
+
+ int clock; /* Current clock speed */
+- int clocks[2];
+
+ bool slow_card; /* Force 11-bit divisor */
+
+ unsigned int max_clk; /* Max src clock freq */
+- unsigned int src_clks[2]; /* Min/max src clock freqs */
+- unsigned int cur_clk_idx; /* Index of current clock */
+- unsigned int next_clk_idx; /* Next clock index */
+- unsigned int cdivs[2];
++ unsigned int min_clk; /* Min src clock freq */
++ unsigned int cur_clk; /* Current src clock freq */
+
+ struct tasklet_struct finish_tasklet; /* Tasklet structures */
+
+@@ -216,7 +213,7 @@ struct bcm2835_host {
+ u32 delay_after_stop; /* minimum time between stop and subsequent data transfer */
+ u32 delay_after_this_stop; /* minimum time between this stop and subsequent data transfer */
+ u32 overclock_50; /* frequency to use when 50MHz is requested (in MHz) */
+- u32 prev_overclock_50;
++ u32 overclock; /* Current frequency if overclocked, else zero */
+ u32 pio_limit; /* Maximum block count for PIO (0 = always DMA) */
+
+ u32 sectors; /* Cached card size in sectors */
+@@ -1512,35 +1509,10 @@ static irqreturn_t bcm2835_sdhost_irq(in
+ return result;
+ }
+
+-static void bcm2835_sdhost_select_clock(struct bcm2835_host *host, int idx)
+-{
+- unsigned int clock = host->clocks[idx];
+- unsigned int cdiv = host->cdivs[idx];
+-
+- host->mmc->actual_clock = clock;
+- host->ns_per_fifo_word = (1000000000/clock) *
+- ((host->mmc->caps & MMC_CAP_4_BIT_DATA) ? 8 : 32);
+-
+- host->cdiv = cdiv;
+- bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
+-
+- /* Set the timeout to 500ms */
+- bcm2835_sdhost_write(host, clock/2, SDTOUT);
+-
+- host->cur_clk_idx = host->next_clk_idx = idx;
+-
+- if (host->debug)
+- pr_info("%s: clock=%d -> src_clk=%d, cdiv=%x (actual %d)\n",
+- mmc_hostname(host->mmc), host->clock,
+- host->src_clks[idx], host->cdiv,
+- host->mmc->actual_clock);
+-}
+-
+ void bcm2835_sdhost_set_clock(struct bcm2835_host *host)
+ {
+ int div = 0; /* Initialized for compiler warning */
+ unsigned int clock = host->clock;
+- int clk_idx;
+
+ if (host->debug)
+ pr_info("%s: set_clock(%d)\n", mmc_hostname(host->mmc), clock);
+@@ -1581,45 +1553,53 @@ void bcm2835_sdhost_set_clock(struct bcm
+ return;
+ }
+
+- /* Calculate the clock divisors */
+- for (clk_idx = 0; clk_idx <= host->variable_clock; clk_idx++)
+- {
+- unsigned int cur_clk = host->src_clks[clk_idx];
+- unsigned int actual_clock;
++ div = host->cur_clk / clock;
++ if (div < 2)
++ div = 2;
++ if ((host->cur_clk / div) > clock)
++ div++;
++ div -= 2;
++
++ if (div > SDCDIV_MAX_CDIV)
++ div = SDCDIV_MAX_CDIV;
++
++ clock = host->cur_clk / (div + 2);
++ host->mmc->actual_clock = clock;
++
++ /* Calibrate some delays */
++
++ host->ns_per_fifo_word = (1000000000/clock) *
++ ((host->mmc->caps & MMC_CAP_4_BIT_DATA) ? 8 : 32);
+
+- div = cur_clk / clock;
+- if (div < 2)
+- div = 2;
+- if ((cur_clk / div) > clock)
+- div++;
+- div -= 2;
+-
+- if (div > SDCDIV_MAX_CDIV)
+- div = SDCDIV_MAX_CDIV;
+- actual_clock = cur_clk / (div + 2);
+-
+- host->cdivs[clk_idx] = div;
+- host->clocks[clk_idx] = actual_clock;
+-
+- if (host->overclock_50 != host->prev_overclock_50) {
+- const char *clk_name = "";
+- if (host->variable_clock)
+- clk_name = clk_idx ? " (turbo)" : " (normal)";
+- if (actual_clock > host->clock)
+- pr_info("%s: overclocking to %dHz%s\n",
+- mmc_hostname(host->mmc),
+- actual_clock, clk_name);
+- else if ((host->overclock_50 < 50) && (clk_idx == 0))
+- pr_info("%s: cancelling overclock%s\n",
+- mmc_hostname(host->mmc),
+- host->variable_clock ? "s" : "");
++ if (clock > host->clock) {
++ /* Save the closest value, to make it easier
++ to reduce in the event of error */
++ host->overclock_50 = (clock/MHZ);
++
++ if (clock != host->overclock) {
++ pr_warn("%s: overclocking to %dHz\n",
++ mmc_hostname(host->mmc), clock);
++ host->overclock = clock;
+ }
+ }
++ else if (host->overclock)
++ {
++ host->overclock = 0;
++ if (clock == 50 * MHZ)
++ pr_warn("%s: cancelling overclock\n",
++ mmc_hostname(host->mmc));
++ }
+
+- if (host->clock == 50*MHZ)
+- host->prev_overclock_50 = host->overclock_50;
++ host->cdiv = div;
++ bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
+
+- bcm2835_sdhost_select_clock(host, host->cur_clk_idx);
++ /* Set the timeout to 500ms */
++ bcm2835_sdhost_write(host, host->mmc->actual_clock/2, SDTOUT);
++
++ if (host->debug)
++ pr_info("%s: clock=%d -> cur_clk=%d, cdiv=%x (actual clock %d)\n",
++ mmc_hostname(host->mmc), host->clock,
++ host->cur_clk, host->cdiv, host->mmc->actual_clock);
+ }
+
+ static void bcm2835_sdhost_request(struct mmc_host *mmc, struct mmc_request *mrq)
+@@ -1677,9 +1657,6 @@ static void bcm2835_sdhost_request(struc
+
+ spin_lock_irqsave(&host->lock, flags);
+
+- if (host->next_clk_idx != host->cur_clk_idx)
+- bcm2835_sdhost_select_clock(host, host->next_clk_idx);
+-
+ WARN_ON(host->mrq != NULL);
+ host->mrq = mrq;
+
+@@ -1742,7 +1719,11 @@ static int bcm2835_sdhost_cpufreq_callba
+ return NOTIFY_BAD;
+ break;
+ case CPUFREQ_POSTCHANGE:
+- host->next_clk_idx = (freq->new > freq->old);
++ if (freq->new > freq->old)
++ host->cur_clk = host->max_clk;
++ else
++ host->cur_clk = host->min_clk;
++ bcm2835_sdhost_set_clock(host);
+ up(&host->cpufreq_semaphore);
+ break;
+ default:
+@@ -1782,11 +1763,8 @@ static void bcm2835_sdhost_set_ios(struc
+ ios->clock, ios->power_mode, ios->bus_width,
+ ios->timing, ios->signal_voltage, ios->drv_type);
+
+- if (ios->clock && (host->cur_clk_idx == -1)) {
+- unsigned int cur_clk =
+- get_core_clock(RPI_FIRMWARE_GET_CLOCK_RATE);
+- host->cur_clk_idx = (cur_clk == host->src_clks[0]) ? 0 : 1;
+- }
++ if (ios->clock && !host->cur_clk)
++ host->cur_clk = get_core_clock(RPI_FIRMWARE_GET_CLOCK_RATE);
+
+ spin_lock_irqsave(&host->lock, flags);
+
+@@ -1876,12 +1854,11 @@ static void bcm2835_sdhost_tasklet_finis
+
+ /* Drop the overclock after any data corruption, or after any
+ error overclocked */
+- if (host->clock > 50*MHZ) {
++ if (host->overclock) {
+ if ((mrq->cmd && mrq->cmd->error) ||
+ (mrq->data && mrq->data->error) ||
+ (mrq->stop && mrq->stop->error)) {
+- host->overclock_50 = (host->clock/MHZ) - 1;
+-
++ host->overclock_50--;
+ pr_warn("%s: reducing overclock due to errors\n",
+ mmc_hostname(host->mmc));
+ bcm2835_sdhost_set_clock(host);
+@@ -2045,7 +2022,7 @@ static int bcm2835_sdhost_probe(struct p
+ struct bcm2835_host *host;
+ struct mmc_host *mmc;
+ const __be32 *addr;
+- unsigned int max_clk, min_clk;
++ unsigned int max_clk;
+ int ret;
+
+ pr_debug("bcm2835_sdhost_probe\n");
+@@ -2151,8 +2128,12 @@ static int bcm2835_sdhost_probe(struct p
+ else
+ mmc->caps |= MMC_CAP_4_BIT_DATA;
+
++ ret = bcm2835_sdhost_add_host(host);
++ if (ret)
++ goto err;
++
+ /* Query the core clock frequencies */
+- min_clk = get_core_clock(RPI_FIRMWARE_GET_MIN_CLOCK_RATE);
++ host->min_clk = get_core_clock(RPI_FIRMWARE_GET_MIN_CLOCK_RATE);
+ max_clk = get_core_clock(RPI_FIRMWARE_GET_MAX_CLOCK_RATE);
+ if (max_clk != host->max_clk) {
+ pr_warn("%s: Expected max clock %d, found %d\n",
+@@ -2160,24 +2141,19 @@ static int bcm2835_sdhost_probe(struct p
+ host->max_clk = max_clk;
+ }
+
+- host->src_clks[0] = min_clk;
+- host->cur_clk_idx = -1;
+- if (max_clk != min_clk) {
+- host->src_clks[1] = max_clk;
++ if (host->min_clk != host->max_clk) {
+ host->cpufreq_nb.notifier_call =
+ bcm2835_sdhost_cpufreq_callback;
+ sema_init(&host->cpufreq_semaphore, 1);
+ cpufreq_register_notifier(&host->cpufreq_nb,
+ CPUFREQ_TRANSITION_NOTIFIER);
+ host->variable_clock = 1;
++ host->cur_clk = 0; /* Get this later */
+ } else {
+ host->variable_clock = 0;
++ host->cur_clk = host->max_clk;
+ }
+
+- ret = bcm2835_sdhost_add_host(host);
+- if (ret)
+- goto err;
+-
+ platform_set_drvdata(pdev, host);
+
+ pr_debug("bcm2835_sdhost_probe -> OK\n");
diff --git a/target/linux/brcm2708/patches-4.4/0224-Revert-bcm2835-sdhost-Adjust-to-core-clock-changes.patch b/target/linux/brcm2708/patches-4.4/0224-Revert-bcm2835-sdhost-Adjust-to-core-clock-changes.patch
new file mode 100644
index 0000000000..37b0d1e939
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0224-Revert-bcm2835-sdhost-Adjust-to-core-clock-changes.patch
@@ -0,0 +1,327 @@
+From 14c3f0b3a4fd51c2bb98146b3395ddc69a2b50ab Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 4 Apr 2016 12:35:51 +0100
+Subject: [PATCH 224/381] Revert "bcm2835-sdhost: Adjust to core clock changes"
+
+This reverts commit 4b89d07fd299a0f4e25321920cb74416ba2e638e.
+---
+ drivers/mmc/host/Kconfig | 1 -
+ drivers/mmc/host/bcm2835-sdhost.c | 140 ++++++--------------------------------
+ 2 files changed, 22 insertions(+), 119 deletions(-)
+
+--- a/drivers/mmc/host/Kconfig
++++ b/drivers/mmc/host/Kconfig
+@@ -36,7 +36,6 @@ config MMC_BCM2835_PIO_DMA_BARRIER
+ config MMC_BCM2835_SDHOST
+ tristate "Support for the SDHost controller on BCM2708/9"
+ depends on MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835
+- depends on RASPBERRYPI_FIRMWARE
+ help
+ This selects the SDHost controller on BCM2835/6.
+
+--- a/drivers/mmc/host/bcm2835-sdhost.c
++++ b/drivers/mmc/host/bcm2835-sdhost.c
+@@ -50,10 +50,6 @@
+ #include <linux/of_dma.h>
+ #include <linux/time.h>
+ #include <linux/workqueue.h>
+-#include <linux/cpufreq.h>
+-#include <linux/semaphore.h>
+-#include <soc/bcm2835/raspberrypi-firmware.h>
+-
+
+ #define DRIVER_NAME "sdhost-bcm2835"
+
+@@ -140,8 +136,6 @@
+
+ #define MHZ 1000000
+
+-#define RPI_FIRMWARE_CLOCK_CORE 4
+-
+
+ struct bcm2835_host {
+ spinlock_t lock;
+@@ -157,9 +151,7 @@ struct bcm2835_host {
+
+ bool slow_card; /* Force 11-bit divisor */
+
+- unsigned int max_clk; /* Max src clock freq */
+- unsigned int min_clk; /* Min src clock freq */
+- unsigned int cur_clk; /* Current src clock freq */
++ unsigned int max_clk; /* Max possible freq */
+
+ struct tasklet_struct finish_tasklet; /* Tasklet structures */
+
+@@ -191,7 +183,6 @@ struct bcm2835_host {
+ unsigned int use_sbc:1; /* Send CMD23 */
+
+ unsigned int debug:1; /* Enable debug output */
+- unsigned int variable_clock:1; /* The core clock may change */
+
+ /*DMA part*/
+ struct dma_chan *dma_chan_rxtx; /* DMA channel for reads and writes */
+@@ -217,9 +208,6 @@ struct bcm2835_host {
+ u32 pio_limit; /* Maximum block count for PIO (0 = always DMA) */
+
+ u32 sectors; /* Cached card size in sectors */
+-
+- struct notifier_block cpufreq_nb; /* The cpufreq callback list item */
+- struct semaphore cpufreq_semaphore; /* Interlock between SD activity and cpufreq changes */
+ };
+
+ #if ENABLE_LOG
+@@ -239,10 +227,6 @@ static u32 sdhost_log_idx;
+ static spinlock_t log_lock;
+ static void __iomem *timer_base;
+
+-static int bcm2835_sdhost_cpufreq_callback(struct notifier_block *nb,
+- unsigned long action, void *data);
+-static unsigned int get_core_clock(unsigned int mode);
+-
+ #define LOG_ENTRIES (256*1)
+ #define LOG_SIZE (sizeof(LOG_ENTRY_T)*LOG_ENTRIES)
+
+@@ -464,14 +448,20 @@ static void bcm2835_sdhost_reset(struct
+
+ static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
+
+-static void bcm2835_sdhost_init(struct bcm2835_host *host)
++static void bcm2835_sdhost_init(struct bcm2835_host *host, int soft)
+ {
+- pr_debug("bcm2835_sdhost_init()\n");
++ pr_debug("bcm2835_sdhost_init(%d)\n", soft);
+
+ /* Set interrupt enables */
+ host->hcfg = SDHCFG_BUSY_IRPT_EN;
+
+ bcm2835_sdhost_reset_internal(host);
++
++ if (soft) {
++ /* force clock reconfiguration */
++ host->clock = 0;
++ bcm2835_sdhost_set_ios(host->mmc, &host->mmc->ios);
++ }
+ }
+
+ static void bcm2835_sdhost_wait_transfer_complete(struct bcm2835_host *host)
+@@ -1509,10 +1499,10 @@ static irqreturn_t bcm2835_sdhost_irq(in
+ return result;
+ }
+
+-void bcm2835_sdhost_set_clock(struct bcm2835_host *host)
++void bcm2835_sdhost_set_clock(struct bcm2835_host *host, unsigned int clock)
+ {
+ int div = 0; /* Initialized for compiler warning */
+- unsigned int clock = host->clock;
++ unsigned int input_clock = clock;
+
+ if (host->debug)
+ pr_info("%s: set_clock(%d)\n", mmc_hostname(host->mmc), clock);
+@@ -1553,17 +1543,17 @@ void bcm2835_sdhost_set_clock(struct bcm
+ return;
+ }
+
+- div = host->cur_clk / clock;
++ div = host->max_clk / clock;
+ if (div < 2)
+ div = 2;
+- if ((host->cur_clk / div) > clock)
++ if ((host->max_clk / div) > clock)
+ div++;
+ div -= 2;
+
+ if (div > SDCDIV_MAX_CDIV)
+ div = SDCDIV_MAX_CDIV;
+
+- clock = host->cur_clk / (div + 2);
++ clock = host->max_clk / (div + 2);
+ host->mmc->actual_clock = clock;
+
+ /* Calibrate some delays */
+@@ -1571,7 +1561,7 @@ void bcm2835_sdhost_set_clock(struct bcm
+ host->ns_per_fifo_word = (1000000000/clock) *
+ ((host->mmc->caps & MMC_CAP_4_BIT_DATA) ? 8 : 32);
+
+- if (clock > host->clock) {
++ if (clock > input_clock) {
+ /* Save the closest value, to make it easier
+ to reduce in the event of error */
+ host->overclock_50 = (clock/MHZ);
+@@ -1597,9 +1587,9 @@ void bcm2835_sdhost_set_clock(struct bcm
+ bcm2835_sdhost_write(host, host->mmc->actual_clock/2, SDTOUT);
+
+ if (host->debug)
+- pr_info("%s: clock=%d -> cur_clk=%d, cdiv=%x (actual clock %d)\n",
+- mmc_hostname(host->mmc), host->clock,
+- host->cur_clk, host->cdiv, host->mmc->actual_clock);
++ pr_info("%s: clock=%d -> max_clk=%d, cdiv=%x (actual clock %d)\n",
++ mmc_hostname(host->mmc), input_clock,
++ host->max_clk, host->cdiv, host->mmc->actual_clock);
+ }
+
+ static void bcm2835_sdhost_request(struct mmc_host *mmc, struct mmc_request *mrq)
+@@ -1648,13 +1638,6 @@ static void bcm2835_sdhost_request(struc
+ (mrq->data->blocks > host->pio_limit))
+ bcm2835_sdhost_prepare_dma(host, mrq->data);
+
+- if (host->variable_clock &&
+- (down_killable(&host->cpufreq_semaphore) != 0)) {
+- mrq->cmd->error = -EINTR;
+- mmc_request_done(mmc, mrq);
+- return;
+- }
+-
+ spin_lock_irqsave(&host->lock, flags);
+
+ WARN_ON(host->mrq != NULL);
+@@ -1704,52 +1687,6 @@ static void bcm2835_sdhost_request(struc
+ spin_unlock_irqrestore(&host->lock, flags);
+ }
+
+-static int bcm2835_sdhost_cpufreq_callback(struct notifier_block *nb,
+- unsigned long action, void *data)
+-{
+- struct cpufreq_freqs *freq = data;
+- struct bcm2835_host *host;
+-
+- host = container_of(nb, struct bcm2835_host, cpufreq_nb);
+-
+- if (freq->cpu == 0) {
+- switch (action) {
+- case CPUFREQ_PRECHANGE:
+- if (down_killable(&host->cpufreq_semaphore) != 0)
+- return NOTIFY_BAD;
+- break;
+- case CPUFREQ_POSTCHANGE:
+- if (freq->new > freq->old)
+- host->cur_clk = host->max_clk;
+- else
+- host->cur_clk = host->min_clk;
+- bcm2835_sdhost_set_clock(host);
+- up(&host->cpufreq_semaphore);
+- break;
+- default:
+- break;
+- }
+- }
+- return NOTIFY_OK;
+-}
+-
+-static unsigned int get_core_clock(unsigned int mode)
+-{
+- struct rpi_firmware *fw = rpi_firmware_get(NULL);
+- struct {
+- u32 id;
+- u32 val;
+- } packet;
+- int ret;
+-
+- packet.id = RPI_FIRMWARE_CLOCK_CORE;
+- ret = rpi_firmware_property(fw, mode, &packet, sizeof(packet));
+- if (ret)
+- return 0;
+-
+- return packet.val;
+-}
+-
+ static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+ {
+
+@@ -1763,16 +1700,13 @@ static void bcm2835_sdhost_set_ios(struc
+ ios->clock, ios->power_mode, ios->bus_width,
+ ios->timing, ios->signal_voltage, ios->drv_type);
+
+- if (ios->clock && !host->cur_clk)
+- host->cur_clk = get_core_clock(RPI_FIRMWARE_GET_CLOCK_RATE);
+-
+ spin_lock_irqsave(&host->lock, flags);
+
+ log_event("IOS<", ios->clock, 0);
+
+ if (!ios->clock || ios->clock != host->clock) {
++ bcm2835_sdhost_set_clock(host, ios->clock);
+ host->clock = ios->clock;
+- bcm2835_sdhost_set_clock(host);
+ }
+
+ /* set bus width */
+@@ -1861,7 +1795,7 @@ static void bcm2835_sdhost_tasklet_finis
+ host->overclock_50--;
+ pr_warn("%s: reducing overclock due to errors\n",
+ mmc_hostname(host->mmc));
+- bcm2835_sdhost_set_clock(host);
++ bcm2835_sdhost_set_clock(host,50*MHZ);
+ mrq->cmd->error = -EILSEQ;
+ mrq->cmd->retries = 1;
+ }
+@@ -1879,9 +1813,6 @@ static void bcm2835_sdhost_tasklet_finis
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
+- if (host->variable_clock)
+- up(&host->cpufreq_semaphore);
+-
+ if (terminate_chan)
+ {
+ int err = dmaengine_terminate_all(terminate_chan);
+@@ -1984,10 +1915,10 @@ int bcm2835_sdhost_add_host(struct bcm28
+ setup_timer(&host->timer, bcm2835_sdhost_timeout,
+ (unsigned long)host);
+
+- bcm2835_sdhost_init(host);
++ bcm2835_sdhost_init(host, 0);
+
+ ret = request_irq(host->irq, bcm2835_sdhost_irq, 0 /*IRQF_SHARED*/,
+- mmc_hostname(mmc), host);
++ mmc_hostname(mmc), host);
+ if (ret) {
+ pr_err("%s: failed to request IRQ %d: %d\n",
+ mmc_hostname(mmc), host->irq, ret);
+@@ -2022,7 +1953,6 @@ static int bcm2835_sdhost_probe(struct p
+ struct bcm2835_host *host;
+ struct mmc_host *mmc;
+ const __be32 *addr;
+- unsigned int max_clk;
+ int ret;
+
+ pr_debug("bcm2835_sdhost_probe\n");
+@@ -2132,28 +2062,6 @@ static int bcm2835_sdhost_probe(struct p
+ if (ret)
+ goto err;
+
+- /* Query the core clock frequencies */
+- host->min_clk = get_core_clock(RPI_FIRMWARE_GET_MIN_CLOCK_RATE);
+- max_clk = get_core_clock(RPI_FIRMWARE_GET_MAX_CLOCK_RATE);
+- if (max_clk != host->max_clk) {
+- pr_warn("%s: Expected max clock %d, found %d\n",
+- mmc_hostname(mmc), host->max_clk, max_clk);
+- host->max_clk = max_clk;
+- }
+-
+- if (host->min_clk != host->max_clk) {
+- host->cpufreq_nb.notifier_call =
+- bcm2835_sdhost_cpufreq_callback;
+- sema_init(&host->cpufreq_semaphore, 1);
+- cpufreq_register_notifier(&host->cpufreq_nb,
+- CPUFREQ_TRANSITION_NOTIFIER);
+- host->variable_clock = 1;
+- host->cur_clk = 0; /* Get this later */
+- } else {
+- host->variable_clock = 0;
+- host->cur_clk = host->max_clk;
+- }
+-
+ platform_set_drvdata(pdev, host);
+
+ pr_debug("bcm2835_sdhost_probe -> OK\n");
+@@ -2173,10 +2081,6 @@ static int bcm2835_sdhost_remove(struct
+
+ pr_debug("bcm2835_sdhost_remove\n");
+
+- if (host->variable_clock)
+- cpufreq_unregister_notifier(&host->cpufreq_nb,
+- CPUFREQ_TRANSITION_NOTIFIER);
+-
+ mmc_remove_host(host->mmc);
+
+ bcm2835_sdhost_set_power(host, false);
diff --git a/target/linux/brcm2708/patches-4.4/0225-bcm2835-sdhost-Firmware-manages-the-clock-divisor.patch b/target/linux/brcm2708/patches-4.4/0225-bcm2835-sdhost-Firmware-manages-the-clock-divisor.patch
new file mode 100644
index 0000000000..995eafd147
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0225-bcm2835-sdhost-Firmware-manages-the-clock-divisor.patch
@@ -0,0 +1,226 @@
+From b14e4255f43ccf38b4f9df8f5793c9c4098e0ab9 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 4 Apr 2016 16:03:18 +0100
+Subject: [PATCH 225/381] bcm2835-sdhost: Firmware manages the clock divisor
+
+The bcm2835-sdhost driver hands control of the CDIV clock divisor
+register to matching firmware, allowing it to adjust to a changing
+core clock. This removes the need to use the performance governor or
+to enable io_is_busy on the on-demand governor in order to get the
+best SD performance.
+
+N.B. As SD clocks must be an integer divisor of the core clock, it is
+possible that the SD clock for "turbo" mode can be different (even
+lower) than "normal" mode.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/mmc/host/bcm2835-sdhost.c | 120 ++++++++++++++++++-----------
+ include/soc/bcm2835/raspberrypi-firmware.h | 1 +
+ 2 files changed, 74 insertions(+), 47 deletions(-)
+
+--- a/drivers/mmc/host/bcm2835-sdhost.c
++++ b/drivers/mmc/host/bcm2835-sdhost.c
+@@ -50,6 +50,7 @@
+ #include <linux/of_dma.h>
+ #include <linux/time.h>
+ #include <linux/workqueue.h>
++#include <soc/bcm2835/raspberrypi-firmware.h>
+
+ #define DRIVER_NAME "sdhost-bcm2835"
+
+@@ -183,6 +184,7 @@ struct bcm2835_host {
+ unsigned int use_sbc:1; /* Send CMD23 */
+
+ unsigned int debug:1; /* Enable debug output */
++ unsigned int firmware_sets_cdiv:1; /* Let the firmware manage the clock */
+
+ /*DMA part*/
+ struct dma_chan *dma_chan_rxtx; /* DMA channel for reads and writes */
+@@ -430,7 +432,7 @@ static void bcm2835_sdhost_reset_interna
+ host->clock = 0;
+ host->sectors = 0;
+ bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
+- bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
++ bcm2835_sdhost_write(host, SDCDIV_MAX_CDIV, SDCDIV);
+ mmiowb();
+ }
+
+@@ -1534,62 +1536,75 @@ void bcm2835_sdhost_set_clock(struct bcm
+
+ host->mmc->actual_clock = 0;
+
+- if (clock < 100000) {
+- /* Can't stop the clock, but make it as slow as possible
+- * to show willing
+- */
+- host->cdiv = SDCDIV_MAX_CDIV;
+- bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
+- return;
+- }
+-
+- div = host->max_clk / clock;
+- if (div < 2)
+- div = 2;
+- if ((host->max_clk / div) > clock)
+- div++;
+- div -= 2;
++ if (host->firmware_sets_cdiv) {
++ u32 msg[3] = { clock, 0, 0 };
+
+- if (div > SDCDIV_MAX_CDIV)
+- div = SDCDIV_MAX_CDIV;
++ rpi_firmware_property(rpi_firmware_get(NULL),
++ RPI_FIRMWARE_SET_SDHOST_CLOCK,
++ &msg, sizeof(msg));
+
+- clock = host->max_clk / (div + 2);
+- host->mmc->actual_clock = clock;
++ clock = max(msg[1], msg[2]);
++ } else {
++ if (clock < 100000) {
++ /* Can't stop the clock, but make it as slow as
++ * possible to show willing
++ */
++ host->cdiv = SDCDIV_MAX_CDIV;
++ bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
++ return;
++ }
++
++ div = host->max_clk / clock;
++ if (div < 2)
++ div = 2;
++ if ((host->max_clk / div) > clock)
++ div++;
++ div -= 2;
++
++ if (div > SDCDIV_MAX_CDIV)
++ div = SDCDIV_MAX_CDIV;
++
++ clock = host->max_clk / (div + 2);
++
++ host->cdiv = div;
++ bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
++
++ if (host->debug)
++ pr_info("%s: clock=%d -> max_clk=%d, cdiv=%x "
++ "(actual clock %d)\n",
++ mmc_hostname(host->mmc), input_clock,
++ host->max_clk, host->cdiv,
++ clock);
++ }
+
+ /* Calibrate some delays */
+
+ host->ns_per_fifo_word = (1000000000/clock) *
+ ((host->mmc->caps & MMC_CAP_4_BIT_DATA) ? 8 : 32);
+
+- if (clock > input_clock) {
+- /* Save the closest value, to make it easier
+- to reduce in the event of error */
+- host->overclock_50 = (clock/MHZ);
+-
+- if (clock != host->overclock) {
+- pr_warn("%s: overclocking to %dHz\n",
+- mmc_hostname(host->mmc), clock);
+- host->overclock = clock;
++ if (input_clock == 50 * MHZ) {
++ if (clock > input_clock) {
++ /* Save the closest value, to make it easier
++ to reduce in the event of error */
++ host->overclock_50 = (clock/MHZ);
++
++ if (clock != host->overclock) {
++ pr_warn("%s: overclocking to %dHz\n",
++ mmc_hostname(host->mmc), clock);
++ host->overclock = clock;
++ }
++ } else if (host->overclock) {
++ host->overclock = 0;
++ if (clock == 50 * MHZ)
++ pr_warn("%s: cancelling overclock\n",
++ mmc_hostname(host->mmc));
+ }
+ }
+- else if (host->overclock)
+- {
+- host->overclock = 0;
+- if (clock == 50 * MHZ)
+- pr_warn("%s: cancelling overclock\n",
+- mmc_hostname(host->mmc));
+- }
+-
+- host->cdiv = div;
+- bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
+
+ /* Set the timeout to 500ms */
+- bcm2835_sdhost_write(host, host->mmc->actual_clock/2, SDTOUT);
++ bcm2835_sdhost_write(host, clock/2, SDTOUT);
+
+- if (host->debug)
+- pr_info("%s: clock=%d -> max_clk=%d, cdiv=%x (actual clock %d)\n",
+- mmc_hostname(host->mmc), input_clock,
+- host->max_clk, host->cdiv, host->mmc->actual_clock);
++ host->mmc->actual_clock = clock;
+ }
+
+ static void bcm2835_sdhost_request(struct mmc_host *mmc, struct mmc_request *mrq)
+@@ -1704,11 +1719,6 @@ static void bcm2835_sdhost_set_ios(struc
+
+ log_event("IOS<", ios->clock, 0);
+
+- if (!ios->clock || ios->clock != host->clock) {
+- bcm2835_sdhost_set_clock(host, ios->clock);
+- host->clock = ios->clock;
+- }
+-
+ /* set bus width */
+ host->hcfg &= ~SDHCFG_WIDE_EXT_BUS;
+ if (ios->bus_width == MMC_BUS_WIDTH_4)
+@@ -1721,6 +1731,11 @@ static void bcm2835_sdhost_set_ios(struc
+
+ bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
+
++ if (!ios->clock || ios->clock != host->clock) {
++ bcm2835_sdhost_set_clock(host, ios->clock);
++ host->clock = ios->clock;
++ }
++
+ mmiowb();
+
+ spin_unlock_irqrestore(&host->lock, flags);
+@@ -1953,6 +1968,7 @@ static int bcm2835_sdhost_probe(struct p
+ struct bcm2835_host *host;
+ struct mmc_host *mmc;
+ const __be32 *addr;
++ u32 msg[3];
+ int ret;
+
+ pr_debug("bcm2835_sdhost_probe\n");
+@@ -2058,6 +2074,16 @@ static int bcm2835_sdhost_probe(struct p
+ else
+ mmc->caps |= MMC_CAP_4_BIT_DATA;
+
++ msg[0] = 0;
++ msg[1] = ~0;
++ msg[2] = ~0;
++
++ rpi_firmware_property(rpi_firmware_get(NULL),
++ RPI_FIRMWARE_SET_SDHOST_CLOCK,
++ &msg, sizeof(msg));
++
++ host->firmware_sets_cdiv = (msg[1] != ~0);
++
+ ret = bcm2835_sdhost_add_host(host);
+ if (ret)
+ goto err;
+--- a/include/soc/bcm2835/raspberrypi-firmware.h
++++ b/include/soc/bcm2835/raspberrypi-firmware.h
+@@ -79,6 +79,7 @@ enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_SET_VOLTAGE = 0x00038003,
+ RPI_FIRMWARE_SET_TURBO = 0x00038009,
+ RPI_FIRMWARE_SET_CUSTOMER_OTP = 0x00038021,
++ RPI_FIRMWARE_SET_SDHOST_CLOCK = 0x00038042,
+
+ /* Dispmanx TAGS */
+ RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE = 0x00040001,
diff --git a/target/linux/brcm2708/patches-4.4/0226-Revert-Revert-cpufreq-Temporarily-ignore-io_is_busy-.patch b/target/linux/brcm2708/patches-4.4/0226-Revert-Revert-cpufreq-Temporarily-ignore-io_is_busy-.patch
new file mode 100644
index 0000000000..8e0ed452ad
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0226-Revert-Revert-cpufreq-Temporarily-ignore-io_is_busy-.patch
@@ -0,0 +1,27 @@
+From 846df5e9c9f2510a68c26922eb6a04b76c576357 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Mon, 4 Apr 2016 19:52:27 +0100
+Subject: [PATCH 226/381] Revert "Revert "cpufreq: Temporarily ignore
+ io_is_busy=1""
+
+This reverts commit c353af0f83220068c10f6593b1767576b9b6cc18.
+---
+ drivers/cpufreq/cpufreq_ondemand.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/drivers/cpufreq/cpufreq_ondemand.c
++++ b/drivers/cpufreq/cpufreq_ondemand.c
+@@ -307,7 +307,12 @@ static ssize_t store_io_is_busy(struct d
+ ret = sscanf(buf, "%u", &input);
+ if (ret != 1)
+ return -EINVAL;
+- od_tuners->io_is_busy = !!input;
++ // XXX temporary hack
++ if (input > 1)
++ input = 1;
++ else
++ input = 0;
++ od_tuners->io_is_busy = input;
+
+ /* we need to re-evaluate prev_cpu_idle */
+ for_each_online_cpu(j) {
diff --git a/target/linux/brcm2708/patches-4.4/0227-config-Enabled-IPV6_SUBTREES.patch b/target/linux/brcm2708/patches-4.4/0227-config-Enabled-IPV6_SUBTREES.patch
new file mode 100644
index 0000000000..1a67b99da0
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0227-config-Enabled-IPV6_SUBTREES.patch
@@ -0,0 +1,30 @@
+From 61b0ef34ce5c2b75fdab896e50877be6becd267c Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Thu, 31 Mar 2016 16:49:52 +0100
+Subject: [PATCH 227/381] config: Enabled IPV6_SUBTREES
+
+---
+ arch/arm/configs/bcm2709_defconfig | 1 +
+ arch/arm/configs/bcmrpi_defconfig | 1 +
+ 2 files changed, 2 insertions(+)
+
+--- a/arch/arm/configs/bcm2709_defconfig
++++ b/arch/arm/configs/bcm2709_defconfig
+@@ -106,6 +106,7 @@ CONFIG_INET6_ESP=m
+ CONFIG_INET6_IPCOMP=m
+ CONFIG_IPV6_TUNNEL=m
+ CONFIG_IPV6_MULTIPLE_TABLES=y
++CONFIG_IPV6_SUBTREES=y
+ CONFIG_IPV6_MROUTE=y
+ CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
+ CONFIG_IPV6_PIMSM_V2=y
+--- a/arch/arm/configs/bcmrpi_defconfig
++++ b/arch/arm/configs/bcmrpi_defconfig
+@@ -73,6 +73,7 @@ CONFIG_INET=y
+ CONFIG_IP_MULTICAST=y
+ CONFIG_IP_ADVANCED_ROUTER=y
+ CONFIG_IP_MULTIPLE_TABLES=y
++CONFIG_IPV6_SUBTREES=y
+ CONFIG_IP_ROUTE_MULTIPATH=y
+ CONFIG_IP_ROUTE_VERBOSE=y
+ CONFIG_IP_PNP=y
diff --git a/target/linux/brcm2708/patches-4.4/0228-add-smsc95xx-packetsize-module_param.patch b/target/linux/brcm2708/patches-4.4/0228-add-smsc95xx-packetsize-module_param.patch
new file mode 100644
index 0000000000..f309904ea3
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0228-add-smsc95xx-packetsize-module_param.patch
@@ -0,0 +1,42 @@
+From 7cdc4c771efb56086a303784f012100382018da4 Mon Sep 17 00:00:00 2001
+From: Sam Nazarko <email@samnazarko.co.uk>
+Date: Fri, 1 Apr 2016 17:27:21 +0100
+Subject: [PATCH 228/381] add smsc95xx packetsize module_param
+
+Signed-off-by: Sam Nazarko <email@samnazarko.co.uk>
+---
+ drivers/net/usb/smsc95xx.c | 14 +++++++++-----
+ 1 file changed, 9 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/usb/smsc95xx.c
++++ b/drivers/net/usb/smsc95xx.c
+@@ -83,6 +83,10 @@ static char *macaddr = ":";
+ module_param(macaddr, charp, 0);
+ MODULE_PARM_DESC(macaddr, "MAC address");
+
++static int packetsize = 0;
++module_param(packetsize, int, 0644);
++MODULE_PARM_DESC(packetsize, "Override the RX URB packet size");
++
+ static int __must_check __smsc95xx_read_reg(struct usbnet *dev, u32 index,
+ u32 *data, int in_pm)
+ {
+@@ -1006,13 +1010,13 @@ static int smsc95xx_reset(struct usbnet
+
+ if (!turbo_mode) {
+ burst_cap = 0;
+- dev->rx_urb_size = MAX_SINGLE_PACKET_SIZE;
++ dev->rx_urb_size = packetsize ? packetsize : MAX_SINGLE_PACKET_SIZE;
+ } else if (dev->udev->speed == USB_SPEED_HIGH) {
+- burst_cap = DEFAULT_HS_BURST_CAP_SIZE / HS_USB_PKT_SIZE;
+- dev->rx_urb_size = DEFAULT_HS_BURST_CAP_SIZE;
++ dev->rx_urb_size = packetsize ? packetsize : DEFAULT_HS_BURST_CAP_SIZE;
++ burst_cap = dev->rx_urb_size / HS_USB_PKT_SIZE;
+ } else {
+- burst_cap = DEFAULT_FS_BURST_CAP_SIZE / FS_USB_PKT_SIZE;
+- dev->rx_urb_size = DEFAULT_FS_BURST_CAP_SIZE;
++ dev->rx_urb_size = packetsize ? packetsize : DEFAULT_FS_BURST_CAP_SIZE;
++ burst_cap = dev->rx_urb_size / FS_USB_PKT_SIZE;
+ }
+
+ netif_dbg(dev, ifup, dev->net, "rx_urb_size=%ld\n",
diff --git a/target/linux/brcm2708/patches-4.4/0229-reboot-Use-power-off-rather-than-busy-spinning-when-.patch b/target/linux/brcm2708/patches-4.4/0229-reboot-Use-power-off-rather-than-busy-spinning-when-.patch
new file mode 100644
index 0000000000..b0ecd96a20
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0229-reboot-Use-power-off-rather-than-busy-spinning-when-.patch
@@ -0,0 +1,25 @@
+From 1ddd9795a4933619754574c0f9d93542ee72d70d Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Tue, 5 Apr 2016 19:40:12 +0100
+Subject: [PATCH 229/381] reboot: Use power off rather than busy spinning when
+ halt is requested
+
+---
+ arch/arm/kernel/reboot.c | 6 +-----
+ 1 file changed, 1 insertion(+), 5 deletions(-)
+
+--- a/arch/arm/kernel/reboot.c
++++ b/arch/arm/kernel/reboot.c
+@@ -102,11 +102,7 @@ void machine_shutdown(void)
+ */
+ void machine_halt(void)
+ {
+- local_irq_disable();
+- smp_send_stop();
+-
+- local_irq_disable();
+- while (1);
++ machine_power_off();
+ }
+
+ /*
diff --git a/target/linux/brcm2708/patches-4.4/0230-Revert-bcm2835-dma-Fix-dreq-not-set-for-slave-transf.patch b/target/linux/brcm2708/patches-4.4/0230-Revert-bcm2835-dma-Fix-dreq-not-set-for-slave-transf.patch
new file mode 100644
index 0000000000..7d56e99033
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0230-Revert-bcm2835-dma-Fix-dreq-not-set-for-slave-transf.patch
@@ -0,0 +1,32 @@
+From 73667a3e1442c254de183d53492264b19fbe239f Mon Sep 17 00:00:00 2001
+From: HiassofT <github@hias.horus.com>
+Date: Wed, 6 Apr 2016 21:45:01 +0200
+Subject: [PATCH 230/381] Revert "bcm2835-dma: Fix dreq not set for slave
+ transfers"
+
+This reverts commit 8ad957e866a1fe1450f663f2b00a57d7de44904c.
+
+
+
+DMA channels are set in devicetree, thus dreq will be set,
+
+and this commit is no longer needed.
+
+
+
+Signed-off-by: Matthias Reichl <hias@horus.com>
+---
+ drivers/dma/bcm2835-dma.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/drivers/dma/bcm2835-dma.c
++++ b/drivers/dma/bcm2835-dma.c
+@@ -679,8 +679,6 @@ 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/0231-RPi-config-Add-CONFIG_PWM_PCA9685-for-NXP-PCA9685-dr.patch b/target/linux/brcm2708/patches-4.4/0231-RPi-config-Add-CONFIG_PWM_PCA9685-for-NXP-PCA9685-dr.patch
new file mode 100644
index 0000000000..4a17987e3e
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0231-RPi-config-Add-CONFIG_PWM_PCA9685-for-NXP-PCA9685-dr.patch
@@ -0,0 +1,92 @@
+From 7e582eea049788f8f4077e439030b03bd30c3a2b Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <6by9@users.noreply.github.com>
+Date: Fri, 1 Apr 2016 15:28:46 +0100
+Subject: [PATCH 231/381] RPi config: Add CONFIG_PWM_PCA9685 for NXP PCA9685
+ driver over I2C
+
+Includes DT overlay to configure it.
+
+Signed-off-by: Dave Stevenson <6by9@users.noreply.github.com>
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 6 +++++
+ .../boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts | 26 ++++++++++++++++++++++
+ arch/arm/configs/bcm2709_defconfig | 1 +
+ arch/arm/configs/bcmrpi_defconfig | 1 +
+ 5 files changed, 35 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -30,6 +30,7 @@ dtbo-$(RPI_DT_OVERLAYS) += hy28b.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += i2c-rtc.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += i2c-gpio.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += i2c-mux-pca9548a.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += i2c-pwm-pca9685a.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += i2c0-bcm2708.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += i2c1-bcm2708.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += i2s-mmap.dtbo
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -366,6 +366,12 @@ Load: dtoverlay=i2c-mux-pca9548a,<para
+ Params: addr I2C address of PCA9548A (default 0x70)
+
+
++Name: i2c-pwm-pca9685a
++Info: Adds support for an NXP PCA9685A I2C PWM controller on i2c_arm
++Load: dtoverlay=i2c-pwm-pca9685a,<param>=<val>
++Params: addr I2C address of PCA9685A (default 0x40)
++
++
+ Name: i2c-rtc
+ Info: Adds support for a number of I2C Real Time Clock devices
+ Load: dtoverlay=i2c-rtc,<param>=<val>
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts
+@@ -0,0 +1,26 @@
++// Definitions for NXP PCA9685A I2C PWM controller on ARM I2C bus.
++/dts-v1/;
++/plugin/;
++
++/{
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&i2c_arm>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ pca: pca@40 {
++ compatible = "nxp,pca9685";
++ #pwm-cells = <2>;
++ reg = <0x40>;
++ status = "okay";
++ };
++ };
++ };
++ __overrides__ {
++ addr = <&pca>,"reg:0";
++ };
++};
+--- a/arch/arm/configs/bcm2709_defconfig
++++ b/arch/arm/configs/bcm2709_defconfig
+@@ -1122,6 +1122,7 @@ CONFIG_MCP320X=m
+ CONFIG_MCP3422=m
+ CONFIG_DHT11=m
+ CONFIG_PWM_BCM2835=m
++CONFIG_PWM_PCA9685=m
+ CONFIG_RASPBERRYPI_FIRMWARE=y
+ CONFIG_EXT4_FS=y
+ CONFIG_EXT4_FS_POSIX_ACL=y
+--- a/arch/arm/configs/bcmrpi_defconfig
++++ b/arch/arm/configs/bcmrpi_defconfig
+@@ -1129,6 +1129,7 @@ CONFIG_MCP320X=m
+ CONFIG_MCP3422=m
+ CONFIG_DHT11=m
+ CONFIG_PWM_BCM2835=m
++CONFIG_PWM_PCA9685=m
+ CONFIG_RASPBERRYPI_FIRMWARE=y
+ CONFIG_EXT4_FS=y
+ CONFIG_EXT4_FS_POSIX_ACL=y
diff --git a/target/linux/brcm2708/patches-4.4/0232-BCM270X_DT-Don-t-generate-linux-phandle-props.patch b/target/linux/brcm2708/patches-4.4/0232-BCM270X_DT-Don-t-generate-linux-phandle-props.patch
new file mode 100644
index 0000000000..bbaf7e2f2a
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0232-BCM270X_DT-Don-t-generate-linux-phandle-props.patch
@@ -0,0 +1,36 @@
+From a7261327b85789623ba20744f44150308d15fb94 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 8 Apr 2016 17:43:27 +0100
+Subject: [PATCH 232/381] BCM270X_DT: Don't generate "linux,phandle" props
+
+The EPAPR standard says to use "phandle" properties to store phandles,
+rather than the deprecated "linux,phandle" version. By default, dtc
+generates both, but adding "-H epapr" causes it to only generate
+"phandle"s, saving some space and clutter.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/Makefile | 2 +-
+ scripts/Makefile.lib | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -813,5 +813,5 @@ clean-files := *.dtb
+
+ # Enable fixups to support overlays on BCM2708 platforms
+ ifeq ($(RPI_DT_OVERLAYS),y)
+- DTC_FLAGS ?= -@
++ DTC_FLAGS ?= -@ -H epapr
+ endif
+--- a/scripts/Makefile.lib
++++ b/scripts/Makefile.lib
+@@ -294,7 +294,7 @@ $(obj)/%.dtb: $(src)/%.dts FORCE
+
+ quiet_cmd_dtco = DTCO $@
+ cmd_dtco = $(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ; \
+- $(objtree)/scripts/dtc/dtc -@ -O dtb -o $@ -b 0 \
++ $(objtree)/scripts/dtc/dtc -@ -H epapr -O dtb -o $@ -b 0 \
+ -i $(dir $<) $(DTC_FLAGS) \
+ -d $(depfile).dtc.tmp $(dtc-tmp) ; \
+ cat $(depfile).pre.tmp $(depfile).dtc.tmp > $(depfile)
diff --git a/target/linux/brcm2708/patches-4.4/0233-V4L2-driver-updates-1393.patch b/target/linux/brcm2708/patches-4.4/0233-V4L2-driver-updates-1393.patch
new file mode 100644
index 0000000000..e95251b608
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0233-V4L2-driver-updates-1393.patch
@@ -0,0 +1,718 @@
+From 5490e6a851eec9f80f887c43f2e2031197527476 Mon Sep 17 00:00:00 2001
+From: 6by9 <6by9@users.noreply.github.com>
+Date: Fri, 8 Apr 2016 18:15:43 +0100
+Subject: [PATCH 233/381] V4L2 driver updates (#1393)
+
+* BCM2835-V4L2: Correct ISO control and add V4L2_CID_ISO_SENSITIVITY_AUTO
+
+https://github.com/raspberrypi/linux/issues/1251
+
+V4L2_CID_ISO_SENSITIVITY was not advertising ISO*1000 as it should.
+V4L2_CID_ISO_SENSITIVITY_AUTO was not implemented, so was taking
+V4L2_CID_ISO_SENSITIVITY as 0 for auto mode.
+Still accepts 0 for auto, but also abides by the new parameter.
+
+Signed-off-by: Dave Stevenson <6by9@users.noreply.github.com>
+
+* BCM2835-V4L2: Add a video_nr parameter.
+
+Adds a kernel parameter "video_nr" to specify the preferred
+/dev/videoX device node.
+https://www.raspberrypi.org/forums/viewtopic.php?f=38&t=136120&p=905545
+
+Signed-off-by: Dave Stevenson <6by9@users.noreply.github.com>
+
+* BCM2835-V4L2: Add support for multiple cameras
+
+Ask GPU on load how many cameras have been detected, and
+enumerate that number of devices.
+Only applicable on the Compute Module as no other device
+exposes multiple CSI2 interfaces.
+
+Signed-off-by: Dave Stevenson <6by9@users.noreply.github.com>
+
+* BCM2835-V4L2: Add control of the overlay location and alpha.
+
+Actually do something useful in vidioc_s_fmt_vid_overlay and
+vidioc_try_fmt_vid_overlay, rather than effectively having
+read-only fields.
+
+Signed-off-by: Dave Stevenson <6by9@users.noreply.github.com>
+
+* BCM2835-V4L2: V4L2-Compliance failure fix
+
+VIDIOC_TRY_FMT was failing due to bytesperline not
+being set correctly by default.
+
+Signed-off-by: Dave Stevenson <6by9@users.noreply.github.com>
+
+* BCM2835-V4L2: Make all module parameters static
+
+Clean up to correct variable scope
+
+Signed-off-by: Dave Stevenson <6by9@users.noreply.github.com>
+---
+ drivers/media/platform/bcm2835/bcm2835-camera.c | 372 +++++++++++++++--------
+ drivers/media/platform/bcm2835/bcm2835-camera.h | 19 +-
+ drivers/media/platform/bcm2835/controls.c | 31 +-
+ drivers/media/platform/bcm2835/mmal-parameters.h | 33 ++
+ 4 files changed, 320 insertions(+), 135 deletions(-)
+
+--- a/drivers/media/platform/bcm2835/bcm2835-camera.c
++++ b/drivers/media/platform/bcm2835/bcm2835-camera.c
+@@ -45,6 +45,8 @@
+ #define MAX_VIDEO_MODE_WIDTH 1280
+ #define MAX_VIDEO_MODE_HEIGHT 720
+
++#define MAX_BCM2835_CAMERAS 2
++
+ MODULE_DESCRIPTION("Broadcom 2835 MMAL video capture");
+ MODULE_AUTHOR("Vincent Sanders");
+ MODULE_LICENSE("GPL");
+@@ -54,8 +56,13 @@ int bcm2835_v4l2_debug;
+ module_param_named(debug, bcm2835_v4l2_debug, int, 0644);
+ MODULE_PARM_DESC(bcm2835_v4l2_debug, "Debug level 0-2");
+
+-int max_video_width = MAX_VIDEO_MODE_WIDTH;
+-int max_video_height = MAX_VIDEO_MODE_HEIGHT;
++#define UNSET (-1)
++static int video_nr[] = {[0 ... (MAX_BCM2835_CAMERAS - 1)] = UNSET };
++module_param_array(video_nr, int, NULL, 0644);
++MODULE_PARM_DESC(video_nr, "videoX start numbers, -1 is autodetect");
++
++static int max_video_width = MAX_VIDEO_MODE_WIDTH;
++static int max_video_height = MAX_VIDEO_MODE_HEIGHT;
+ module_param(max_video_width, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ MODULE_PARM_DESC(max_video_width, "Threshold for video mode");
+ module_param(max_video_height, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+@@ -70,11 +77,12 @@ MODULE_PARM_DESC(max_video_height, "Thre
+ * our function table list (actually switch to an alternate set, but same
+ * result).
+ */
+-int gst_v4l2src_is_broken = 0;
++static int gst_v4l2src_is_broken;
+ module_param(gst_v4l2src_is_broken, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ MODULE_PARM_DESC(gst_v4l2src_is_broken, "If non-zero, enable workaround for Gstreamer");
+
+-static struct bm2835_mmal_dev *gdev; /* global device data */
++/* global device data array */
++static struct bm2835_mmal_dev *gdev[MAX_BCM2835_CAMERAS];
+
+ #define FPS_MIN 1
+ #define FPS_MAX 90
+@@ -413,6 +421,17 @@ static int enable_camera(struct bm2835_m
+ {
+ int ret;
+ if (!dev->camera_use_count) {
++ ret = vchiq_mmal_port_parameter_set(
++ dev->instance,
++ &dev->component[MMAL_COMPONENT_CAMERA]->control,
++ MMAL_PARAMETER_CAMERA_NUM, &dev->camera_num,
++ sizeof(dev->camera_num));
++ if (ret < 0) {
++ v4l2_err(&dev->v4l2_dev,
++ "Failed setting camera num, ret %d\n", ret);
++ return -EINVAL;
++ }
++
+ ret = vchiq_mmal_component_enable(
+ dev->instance,
+ dev->component[MMAL_COMPONENT_CAMERA]);
+@@ -647,6 +666,30 @@ static struct vb2_ops bm2835_mmal_video_
+ IOCTL operations
+ ------------------------------------------------------------------*/
+
++static int set_overlay_params(struct bm2835_mmal_dev *dev,
++ struct vchiq_mmal_port *port)
++{
++ int ret;
++ struct mmal_parameter_displayregion prev_config = {
++ .set = MMAL_DISPLAY_SET_LAYER | MMAL_DISPLAY_SET_ALPHA |
++ MMAL_DISPLAY_SET_DEST_RECT | MMAL_DISPLAY_SET_FULLSCREEN,
++ .layer = PREVIEW_LAYER,
++ .alpha = dev->overlay.global_alpha,
++ .fullscreen = 0,
++ .dest_rect = {
++ .x = dev->overlay.w.left,
++ .y = dev->overlay.w.top,
++ .width = dev->overlay.w.width,
++ .height = dev->overlay.w.height,
++ },
++ };
++ ret = vchiq_mmal_port_parameter_set(dev->instance, port,
++ MMAL_PARAMETER_DISPLAYREGION,
++ &prev_config, sizeof(prev_config));
++
++ return ret;
++}
++
+ /* overlay ioctl */
+ static int vidioc_enum_fmt_vid_overlay(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+@@ -678,10 +721,31 @@ static int vidioc_g_fmt_vid_overlay(stru
+ static int vidioc_try_fmt_vid_overlay(struct file *file, void *priv,
+ struct v4l2_format *f)
+ {
+- /* Only support one format so get the current one. */
+- vidioc_g_fmt_vid_overlay(file, priv, f);
++ struct bm2835_mmal_dev *dev = video_drvdata(file);
+
+- /* todo: allow the size and/or offset to be changed. */
++ f->fmt.win.field = V4L2_FIELD_NONE;
++ f->fmt.win.chromakey = 0;
++ f->fmt.win.clips = NULL;
++ f->fmt.win.clipcount = 0;
++ f->fmt.win.bitmap = NULL;
++
++ v4l_bound_align_image(&f->fmt.win.w.width, MIN_WIDTH, MAX_WIDTH, 1,
++ &f->fmt.win.w.height, MIN_HEIGHT, MAX_HEIGHT,
++ 1, 0);
++ v4l_bound_align_image(&f->fmt.win.w.left, MIN_WIDTH, MAX_WIDTH, 1,
++ &f->fmt.win.w.top, MIN_HEIGHT, MAX_HEIGHT,
++ 1, 0);
++
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "Overlay: Now w/h %dx%d l/t %dx%d\n",
++ f->fmt.win.w.width, f->fmt.win.w.height,
++ f->fmt.win.w.left, f->fmt.win.w.top);
++
++ v4l2_dump_win_format(1,
++ bcm2835_v4l2_debug,
++ &dev->v4l2_dev,
++ &f->fmt.win,
++ __func__);
+ return 0;
+ }
+
+@@ -693,8 +757,11 @@ static int vidioc_s_fmt_vid_overlay(stru
+ vidioc_try_fmt_vid_overlay(file, priv, f);
+
+ dev->overlay = f->fmt.win;
++ if (dev->component[MMAL_COMPONENT_PREVIEW]->enabled) {
++ set_overlay_params(dev,
++ &dev->component[MMAL_COMPONENT_PREVIEW]->input[0]);
++ }
+
+- /* todo: program the preview port parameters */
+ return 0;
+ }
+
+@@ -704,20 +771,6 @@ static int vidioc_overlay(struct file *f
+ struct bm2835_mmal_dev *dev = video_drvdata(file);
+ struct vchiq_mmal_port *src;
+ struct vchiq_mmal_port *dst;
+- struct mmal_parameter_displayregion prev_config = {
+- .set = MMAL_DISPLAY_SET_LAYER | MMAL_DISPLAY_SET_ALPHA |
+- MMAL_DISPLAY_SET_DEST_RECT | MMAL_DISPLAY_SET_FULLSCREEN,
+- .layer = PREVIEW_LAYER,
+- .alpha = 255,
+- .fullscreen = 0,
+- .dest_rect = {
+- .x = dev->overlay.w.left,
+- .y = dev->overlay.w.top,
+- .width = dev->overlay.w.width,
+- .height = dev->overlay.w.height,
+- },
+- };
+-
+ if ((on && dev->component[MMAL_COMPONENT_PREVIEW]->enabled) ||
+ (!on && !dev->component[MMAL_COMPONENT_PREVIEW]->enabled))
+ return 0; /* already in requested state */
+@@ -749,9 +802,7 @@ static int vidioc_overlay(struct file *f
+ if (ret < 0)
+ goto error;
+
+- ret = vchiq_mmal_port_parameter_set(dev->instance, dst,
+- MMAL_PARAMETER_DISPLAYREGION,
+- &prev_config, sizeof(prev_config));
++ ret = set_overlay_params(dev, dst);
+ if (ret < 0)
+ goto error;
+
+@@ -782,6 +833,9 @@ static int vidioc_g_fbuf(struct file *fi
+ struct vchiq_mmal_port *preview_port =
+ &dev->component[MMAL_COMPONENT_CAMERA]->
+ output[MMAL_CAMERA_PORT_PREVIEW];
++
++ a->capability = V4L2_FBUF_CAP_EXTERNOVERLAY |
++ V4L2_FBUF_CAP_GLOBAL_ALPHA;
+ a->flags = V4L2_FBUF_FLAG_OVERLAY;
+ a->fmt.width = preview_port->es.video.width;
+ a->fmt.height = preview_port->es.video.height;
+@@ -1445,6 +1499,34 @@ static struct video_device vdev_template
+ .release = video_device_release_empty,
+ };
+
++static int get_num_cameras(struct vchiq_mmal_instance *instance)
++{
++ int ret;
++ struct vchiq_mmal_component *cam_info_component;
++ struct mmal_parameter_camera_info_t cam_info = {0};
++ int param_size = sizeof(cam_info);
++
++ /* create a camera_info component */
++ ret = vchiq_mmal_component_init(instance, "camera_info",
++ &cam_info_component);
++ if (ret < 0)
++ /* Unusual failure - let's guess one camera. */
++ return 1;
++
++ if (vchiq_mmal_port_parameter_get(instance,
++ &cam_info_component->control,
++ MMAL_PARAMETER_CAMERA_INFO,
++ &cam_info,
++ &param_size)) {
++ pr_info("Failed to get camera info\n");
++ }
++
++ vchiq_mmal_component_finalise(instance,
++ cam_info_component);
++
++ return cam_info.num_cameras;
++}
++
+ static int set_camera_parameters(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_component *camera)
+ {
+@@ -1685,7 +1767,9 @@ static int __init bm2835_mmal_init_devic
+ /* video device needs to be able to access instance data */
+ video_set_drvdata(vfd, dev);
+
+- ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
++ ret = video_register_device(vfd,
++ VFL_TYPE_GRABBER,
++ video_nr[dev->camera_num]);
+ if (ret < 0)
+ return ret;
+
+@@ -1696,10 +1780,52 @@ static int __init bm2835_mmal_init_devic
+ return 0;
+ }
+
++void bcm2835_cleanup_instance(struct bm2835_mmal_dev *dev)
++{
++ if (!dev)
++ return;
++
++ v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
++ video_device_node_name(&dev->vdev));
++
++ video_unregister_device(&dev->vdev);
++
++ if (dev->capture.encode_component) {
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "mmal_exit - disconnect tunnel\n");
++ vchiq_mmal_port_connect_tunnel(dev->instance,
++ dev->capture.camera_port, NULL);
++ vchiq_mmal_component_disable(dev->instance,
++ dev->capture.encode_component);
++ }
++ vchiq_mmal_component_disable(dev->instance,
++ dev->component[MMAL_COMPONENT_CAMERA]);
++
++ vchiq_mmal_component_finalise(dev->instance,
++ dev->
++ component[MMAL_COMPONENT_VIDEO_ENCODE]);
++
++ vchiq_mmal_component_finalise(dev->instance,
++ dev->
++ component[MMAL_COMPONENT_IMAGE_ENCODE]);
++
++ vchiq_mmal_component_finalise(dev->instance,
++ dev->component[MMAL_COMPONENT_PREVIEW]);
++
++ vchiq_mmal_component_finalise(dev->instance,
++ dev->component[MMAL_COMPONENT_CAMERA]);
++
++ v4l2_ctrl_handler_free(&dev->ctrl_handler);
++
++ v4l2_device_unregister(&dev->v4l2_dev);
++
++ kfree(dev);
++}
++
+ static struct v4l2_format default_v4l2_format = {
+ .fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG,
+ .fmt.pix.width = 1024,
+- .fmt.pix.bytesperline = 1024,
++ .fmt.pix.bytesperline = 0,
+ .fmt.pix.height = 768,
+ .fmt.pix.sizeimage = 1024*768,
+ };
+@@ -1709,76 +1835,93 @@ static int __init bm2835_mmal_init(void)
+ int ret;
+ struct bm2835_mmal_dev *dev;
+ struct vb2_queue *q;
++ int camera;
++ unsigned int num_cameras;
++ struct vchiq_mmal_instance *instance;
+
+- dev = kzalloc(sizeof(*gdev), GFP_KERNEL);
+- if (!dev)
+- return -ENOMEM;
+-
+- /* setup device defaults */
+- dev->overlay.w.left = 150;
+- dev->overlay.w.top = 50;
+- dev->overlay.w.width = 1024;
+- dev->overlay.w.height = 768;
+- dev->overlay.clipcount = 0;
+- dev->overlay.field = V4L2_FIELD_NONE;
+-
+- dev->capture.fmt = &formats[3]; /* JPEG */
+-
+- /* v4l device registration */
+- snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
+- "%s", BM2835_MMAL_MODULE_NAME);
+- ret = v4l2_device_register(NULL, &dev->v4l2_dev);
+- if (ret)
+- goto free_dev;
+-
+- /* setup v4l controls */
+- ret = bm2835_mmal_init_controls(dev, &dev->ctrl_handler);
+- if (ret < 0)
+- goto unreg_dev;
+- dev->v4l2_dev.ctrl_handler = &dev->ctrl_handler;
+-
+- /* mmal init */
+- ret = mmal_init(dev);
++ ret = vchiq_mmal_init(&instance);
+ if (ret < 0)
+- goto unreg_dev;
++ return ret;
+
+- /* initialize queue */
+- q = &dev->capture.vb_vidq;
+- memset(q, 0, sizeof(*q));
+- q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+- q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
+- q->drv_priv = dev;
+- q->buf_struct_size = sizeof(struct mmal_buffer);
+- q->ops = &bm2835_mmal_video_qops;
+- q->mem_ops = &vb2_vmalloc_memops;
+- q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+- ret = vb2_queue_init(q);
+- if (ret < 0)
+- goto unreg_dev;
++ num_cameras = get_num_cameras(instance);
++ if (num_cameras > MAX_BCM2835_CAMERAS)
++ num_cameras = MAX_BCM2835_CAMERAS;
++
++ for (camera = 0; camera < num_cameras; camera++) {
++ dev = kzalloc(sizeof(struct bm2835_mmal_dev), GFP_KERNEL);
++ if (!dev)
++ return -ENOMEM;
++
++ dev->camera_num = camera;
++
++ /* setup device defaults */
++ dev->overlay.w.left = 150;
++ dev->overlay.w.top = 50;
++ dev->overlay.w.width = 1024;
++ dev->overlay.w.height = 768;
++ dev->overlay.clipcount = 0;
++ dev->overlay.field = V4L2_FIELD_NONE;
++ dev->overlay.global_alpha = 255;
++
++ dev->capture.fmt = &formats[3]; /* JPEG */
++
++ /* v4l device registration */
++ snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
++ "%s", BM2835_MMAL_MODULE_NAME);
++ ret = v4l2_device_register(NULL, &dev->v4l2_dev);
++ if (ret)
++ goto free_dev;
+
+- /* v4l2 core mutex used to protect all fops and v4l2 ioctls. */
+- mutex_init(&dev->mutex);
++ /* setup v4l controls */
++ ret = bm2835_mmal_init_controls(dev, &dev->ctrl_handler);
++ if (ret < 0)
++ goto unreg_dev;
++ dev->v4l2_dev.ctrl_handler = &dev->ctrl_handler;
++
++ /* mmal init */
++ dev->instance = instance;
++ ret = mmal_init(dev);
++ if (ret < 0)
++ goto unreg_dev;
++
++ /* initialize queue */
++ q = &dev->capture.vb_vidq;
++ memset(q, 0, sizeof(*q));
++ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
++ q->drv_priv = dev;
++ q->buf_struct_size = sizeof(struct mmal_buffer);
++ q->ops = &bm2835_mmal_video_qops;
++ q->mem_ops = &vb2_vmalloc_memops;
++ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
++ ret = vb2_queue_init(q);
++ if (ret < 0)
++ goto unreg_dev;
++
++ /* v4l2 core mutex used to protect all fops and v4l2 ioctls. */
++ mutex_init(&dev->mutex);
++
++ /* initialise video devices */
++ ret = bm2835_mmal_init_device(dev, &dev->vdev);
++ if (ret < 0)
++ goto unreg_dev;
++
++ /* Really want to call vidioc_s_fmt_vid_cap with the default
++ * format, but currently the APIs don't join up.
++ */
++ ret = mmal_setup_components(dev, &default_v4l2_format);
++ if (ret < 0) {
++ v4l2_err(&dev->v4l2_dev,
++ "%s: could not setup components\n", __func__);
++ goto unreg_dev;
++ }
+
+- /* initialise video devices */
+- ret = bm2835_mmal_init_device(dev, &dev->vdev);
+- if (ret < 0)
+- goto unreg_dev;
++ v4l2_info(&dev->v4l2_dev,
++ "Broadcom 2835 MMAL video capture ver %s loaded.\n",
++ BM2835_MMAL_VERSION);
+
+- /* Really want to call vidioc_s_fmt_vid_cap with the default
+- * format, but currently the APIs don't join up.
+- */
+- ret = mmal_setup_components(dev, &default_v4l2_format);
+- if (ret < 0) {
+- v4l2_err(&dev->v4l2_dev,
+- "%s: could not setup components\n", __func__);
+- goto unreg_dev;
++ gdev[camera] = dev;
+ }
+-
+- v4l2_info(&dev->v4l2_dev,
+- "Broadcom 2835 MMAL video capture ver %s loaded.\n",
+- BM2835_MMAL_VERSION);
+-
+- gdev = dev;
+ return 0;
+
+ unreg_dev:
+@@ -1788,8 +1931,11 @@ unreg_dev:
+ free_dev:
+ kfree(dev);
+
+- v4l2_err(&dev->v4l2_dev,
+- "%s: error %d while loading driver\n",
++ for ( ; camera > 0; camera--) {
++ bcm2835_cleanup_instance(gdev[camera]);
++ gdev[camera] = NULL;
++ }
++ pr_info("%s: error %d while loading driver\n",
+ BM2835_MMAL_MODULE_NAME, ret);
+
+ return ret;
+@@ -1797,46 +1943,14 @@ free_dev:
+
+ static void __exit bm2835_mmal_exit(void)
+ {
+- if (!gdev)
+- return;
+-
+- v4l2_info(&gdev->v4l2_dev, "unregistering %s\n",
+- video_device_node_name(&gdev->vdev));
++ int camera;
++ struct vchiq_mmal_instance *instance = gdev[0]->instance;
+
+- video_unregister_device(&gdev->vdev);
+-
+- if (gdev->capture.encode_component) {
+- v4l2_dbg(1, bcm2835_v4l2_debug, &gdev->v4l2_dev,
+- "mmal_exit - disconnect tunnel\n");
+- vchiq_mmal_port_connect_tunnel(gdev->instance,
+- gdev->capture.camera_port, NULL);
+- vchiq_mmal_component_disable(gdev->instance,
+- gdev->capture.encode_component);
++ for (camera = 0; camera < MAX_BCM2835_CAMERAS; camera++) {
++ bcm2835_cleanup_instance(gdev[camera]);
++ gdev[camera] = NULL;
+ }
+- vchiq_mmal_component_disable(gdev->instance,
+- gdev->component[MMAL_COMPONENT_CAMERA]);
+-
+- vchiq_mmal_component_finalise(gdev->instance,
+- gdev->
+- component[MMAL_COMPONENT_VIDEO_ENCODE]);
+-
+- vchiq_mmal_component_finalise(gdev->instance,
+- gdev->
+- component[MMAL_COMPONENT_IMAGE_ENCODE]);
+-
+- vchiq_mmal_component_finalise(gdev->instance,
+- gdev->component[MMAL_COMPONENT_PREVIEW]);
+-
+- vchiq_mmal_component_finalise(gdev->instance,
+- gdev->component[MMAL_COMPONENT_CAMERA]);
+-
+- vchiq_mmal_finalise(gdev->instance);
+-
+- v4l2_ctrl_handler_free(&gdev->ctrl_handler);
+-
+- v4l2_device_unregister(&gdev->v4l2_dev);
+-
+- kfree(gdev);
++ vchiq_mmal_finalise(instance);
+ }
+
+ module_init(bm2835_mmal_init);
+--- a/drivers/media/platform/bcm2835/bcm2835-camera.h
++++ b/drivers/media/platform/bcm2835/bcm2835-camera.h
+@@ -15,7 +15,7 @@
+ * core driver device
+ */
+
+-#define V4L2_CTRL_COUNT 28 /* number of v4l controls */
++#define V4L2_CTRL_COUNT 29 /* number of v4l controls */
+
+ enum {
+ MMAL_COMPONENT_CAMERA = 0,
+@@ -58,6 +58,8 @@ struct bm2835_mmal_dev {
+ enum mmal_parameter_exposuremeteringmode metering_mode;
+ unsigned int manual_shutter_speed;
+ bool exp_auto_priority;
++ bool manual_iso_enabled;
++ uint32_t iso;
+
+ /* allocated mmal instance and components */
+ struct vchiq_mmal_instance *instance;
+@@ -104,6 +106,8 @@ struct bm2835_mmal_dev {
+
+ } capture;
+
++ unsigned int camera_num;
++
+ };
+
+ int bm2835_mmal_init_controls(
+@@ -124,3 +128,16 @@ int set_framerate_params(struct bm2835_m
+ (pix_fmt)->pixelformat, (pix_fmt)->bytesperline, \
+ (pix_fmt)->sizeimage, (pix_fmt)->colorspace, (pix_fmt)->priv); \
+ }
++#define v4l2_dump_win_format(level, debug, dev, win_fmt, desc) \
++{ \
++ v4l2_dbg(level, debug, dev, \
++"%s: w %u h %u l %u t %u field %u chromakey %06X clip %p " \
++"clipcount %u bitmap %p\n", \
++ desc == NULL ? "" : desc, \
++ (win_fmt)->w.width, (win_fmt)->w.height, \
++ (win_fmt)->w.left, (win_fmt)->w.top, \
++ (win_fmt)->field, \
++ (win_fmt)->chromakey, \
++ (win_fmt)->clips, (win_fmt)->clipcount, \
++ (win_fmt)->bitmap); \
++}
+--- a/drivers/media/platform/bcm2835/controls.c
++++ b/drivers/media/platform/bcm2835/controls.c
+@@ -49,10 +49,13 @@ static const s64 ev_bias_qmenu[] = {
+ 4000
+ };
+
+-/* Supported ISO values
++/* Supported ISO values (*1000)
+ * ISOO = auto ISO
+ */
+ static const s64 iso_qmenu[] = {
++ 0, 100000, 200000, 400000, 800000,
++};
++static const uint32_t iso_values[] = {
+ 0, 100, 200, 400, 800,
+ };
+
+@@ -201,7 +204,7 @@ static int ctrl_set_value(struct bm2835_
+ &u32_value, sizeof(u32_value));
+ }
+
+-static int ctrl_set_value_menu(struct bm2835_mmal_dev *dev,
++static int ctrl_set_iso(struct bm2835_mmal_dev *dev,
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+ {
+@@ -211,12 +214,23 @@ static int ctrl_set_value_menu(struct bm
+ if (ctrl->val > mmal_ctrl->max || ctrl->val < mmal_ctrl->min)
+ return 1;
+
++ if (ctrl->id == V4L2_CID_ISO_SENSITIVITY)
++ dev->iso = iso_values[ctrl->val];
++ else if (ctrl->id == V4L2_CID_ISO_SENSITIVITY_AUTO)
++ dev->manual_iso_enabled =
++ (ctrl->val == V4L2_ISO_SENSITIVITY_MANUAL ?
++ true :
++ false);
++
+ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+
+- u32_value = mmal_ctrl->imenu[ctrl->val];
++ if (dev->manual_iso_enabled)
++ u32_value = dev->iso;
++ else
++ u32_value = 0;
+
+ return vchiq_mmal_port_parameter_set(dev->instance, control,
+- mmal_ctrl->mmal_id,
++ MMAL_PARAMETER_ISO,
+ &u32_value, sizeof(u32_value));
+ }
+
+@@ -956,7 +970,14 @@ static const struct bm2835_mmal_v4l2_ctr
+ V4L2_CID_ISO_SENSITIVITY, MMAL_CONTROL_TYPE_INT_MENU,
+ 0, ARRAY_SIZE(iso_qmenu) - 1, 0, 1, iso_qmenu,
+ MMAL_PARAMETER_ISO,
+- &ctrl_set_value_menu,
++ &ctrl_set_iso,
++ false
++ },
++ {
++ V4L2_CID_ISO_SENSITIVITY_AUTO, MMAL_CONTROL_TYPE_STD_MENU,
++ 0, 1, V4L2_ISO_SENSITIVITY_AUTO, 1, NULL,
++ MMAL_PARAMETER_ISO,
++ &ctrl_set_iso,
+ false
+ },
+ {
+--- a/drivers/media/platform/bcm2835/mmal-parameters.h
++++ b/drivers/media/platform/bcm2835/mmal-parameters.h
+@@ -654,3 +654,36 @@ struct mmal_parameter_imagefx_parameters
+ u32 num_effect_params;
+ u32 effect_parameter[MMAL_MAX_IMAGEFX_PARAMETERS];
+ };
++
++#define MMAL_PARAMETER_CAMERA_INFO_MAX_CAMERAS 4
++#define MMAL_PARAMETER_CAMERA_INFO_MAX_FLASHES 2
++#define MMAL_PARAMETER_CAMERA_INFO_MAX_STR_LEN 16
++
++struct mmal_parameter_camera_info_camera_t {
++ u32 port_id;
++ u32 max_width;
++ u32 max_height;
++ u32 lens_present;
++ u8 camera_name[MMAL_PARAMETER_CAMERA_INFO_MAX_STR_LEN];
++};
++
++enum mmal_parameter_camera_info_flash_type_t {
++ /* Make values explicit to ensure they match values in config ini */
++ MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_XENON = 0,
++ MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_LED = 1,
++ MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_OTHER = 2,
++ MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_MAX = 0x7FFFFFFF
++};
++
++struct mmal_parameter_camera_info_flash_t {
++ enum mmal_parameter_camera_info_flash_type_t flash_type;
++};
++
++struct mmal_parameter_camera_info_t {
++ u32 num_cameras;
++ u32 num_flashes;
++ struct mmal_parameter_camera_info_camera_t
++ cameras[MMAL_PARAMETER_CAMERA_INFO_MAX_CAMERAS];
++ struct mmal_parameter_camera_info_flash_t
++ flashes[MMAL_PARAMETER_CAMERA_INFO_MAX_FLASHES];
++};
diff --git a/target/linux/brcm2708/patches-4.4/0234-bcm2835-sdhost-Reset-the-clock-in-task-context.patch b/target/linux/brcm2708/patches-4.4/0234-bcm2835-sdhost-Reset-the-clock-in-task-context.patch
new file mode 100644
index 0000000000..ddff7751d9
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0234-bcm2835-sdhost-Reset-the-clock-in-task-context.patch
@@ -0,0 +1,107 @@
+From 3ef58b428e66c86b2e36dbb0a17d561088688578 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 11 Apr 2016 12:50:58 +0100
+Subject: [PATCH 234/381] bcm2835-sdhost: Reset the clock in task context
+
+Since reprogramming the clock can now involve a round-trip to the
+firmware it must not be done at atomic context, and a tasklet
+is not a task.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/mmc/host/bcm2835-sdhost.c | 25 ++++++++++++++++++-------
+ 1 file changed, 18 insertions(+), 7 deletions(-)
+
+--- a/drivers/mmc/host/bcm2835-sdhost.c
++++ b/drivers/mmc/host/bcm2835-sdhost.c
+@@ -185,6 +185,7 @@ struct bcm2835_host {
+
+ unsigned int debug:1; /* Enable debug output */
+ unsigned int firmware_sets_cdiv:1; /* Let the firmware manage the clock */
++ unsigned int reset_clock:1; /* Reset the clock fore the next request */
+
+ /*DMA part*/
+ struct dma_chan *dma_chan_rxtx; /* DMA channel for reads and writes */
+@@ -1505,6 +1506,7 @@ void bcm2835_sdhost_set_clock(struct bcm
+ {
+ int div = 0; /* Initialized for compiler warning */
+ unsigned int input_clock = clock;
++ unsigned long flags;
+
+ if (host->debug)
+ pr_info("%s: set_clock(%d)\n", mmc_hostname(host->mmc), clock);
+@@ -1544,13 +1546,17 @@ void bcm2835_sdhost_set_clock(struct bcm
+ &msg, sizeof(msg));
+
+ clock = max(msg[1], msg[2]);
++ spin_lock_irqsave(&host->lock, flags);
+ } else {
++ spin_lock_irqsave(&host->lock, flags);
+ if (clock < 100000) {
+ /* Can't stop the clock, but make it as slow as
+ * possible to show willing
+ */
+ host->cdiv = SDCDIV_MAX_CDIV;
+ bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
++ mmiowb();
++ spin_unlock_irqrestore(&host->lock, flags);
+ return;
+ }
+
+@@ -1605,6 +1611,11 @@ void bcm2835_sdhost_set_clock(struct bcm
+ bcm2835_sdhost_write(host, clock/2, SDTOUT);
+
+ host->mmc->actual_clock = clock;
++ host->clock = input_clock;
++ host->reset_clock = 0;
++
++ mmiowb();
++ spin_unlock_irqrestore(&host->lock, flags);
+ }
+
+ static void bcm2835_sdhost_request(struct mmc_host *mmc, struct mmc_request *mrq)
+@@ -1653,6 +1664,9 @@ static void bcm2835_sdhost_request(struc
+ (mrq->data->blocks > host->pio_limit))
+ bcm2835_sdhost_prepare_dma(host, mrq->data);
+
++ if (host->reset_clock)
++ bcm2835_sdhost_set_clock(host, host->clock);
++
+ spin_lock_irqsave(&host->lock, flags);
+
+ WARN_ON(host->mrq != NULL);
+@@ -1731,14 +1745,12 @@ static void bcm2835_sdhost_set_ios(struc
+
+ bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
+
+- if (!ios->clock || ios->clock != host->clock) {
+- bcm2835_sdhost_set_clock(host, ios->clock);
+- host->clock = ios->clock;
+- }
+-
+ mmiowb();
+
+ spin_unlock_irqrestore(&host->lock, flags);
++
++ if (!ios->clock || ios->clock != host->clock)
++ bcm2835_sdhost_set_clock(host, ios->clock);
+ }
+
+ static struct mmc_host_ops bcm2835_sdhost_ops = {
+@@ -1810,7 +1822,7 @@ static void bcm2835_sdhost_tasklet_finis
+ host->overclock_50--;
+ pr_warn("%s: reducing overclock due to errors\n",
+ mmc_hostname(host->mmc));
+- bcm2835_sdhost_set_clock(host,50*MHZ);
++ host->reset_clock = 1;
+ mrq->cmd->error = -EILSEQ;
+ mrq->cmd->retries = 1;
+ }
+@@ -1979,7 +1991,6 @@ static int bcm2835_sdhost_probe(struct p
+ mmc->ops = &bcm2835_sdhost_ops;
+ host = mmc_priv(mmc);
+ host->mmc = mmc;
+- host->cmd_quick_poll_retries = 0;
+ host->pio_timeout = msecs_to_jiffies(500);
+ host->pio_limit = 1;
+ host->max_delay = 1; /* Warn if over 1ms */
diff --git a/target/linux/brcm2708/patches-4.4/0235-config-Enable-CONFIG_IPV6_ROUTER_PREF-for-networks-w.patch b/target/linux/brcm2708/patches-4.4/0235-config-Enable-CONFIG_IPV6_ROUTER_PREF-for-networks-w.patch
new file mode 100644
index 0000000000..3d85c9d70e
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0235-config-Enable-CONFIG_IPV6_ROUTER_PREF-for-networks-w.patch
@@ -0,0 +1,31 @@
+From 8e5424e69f62b365bcb158c6d4b28b7e1c100664 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Thu, 7 Apr 2016 12:44:24 +0100
+Subject: [PATCH 235/381] config: Enable CONFIG_IPV6_ROUTER_PREF for networks
+ with multiple routers
+
+---
+ arch/arm/configs/bcm2709_defconfig | 1 +
+ arch/arm/configs/bcmrpi_defconfig | 1 +
+ 2 files changed, 2 insertions(+)
+
+--- a/arch/arm/configs/bcm2709_defconfig
++++ b/arch/arm/configs/bcm2709_defconfig
+@@ -101,6 +101,7 @@ CONFIG_INET_XFRM_MODE_TUNNEL=m
+ CONFIG_INET_XFRM_MODE_BEET=m
+ CONFIG_INET_LRO=m
+ CONFIG_INET_DIAG=m
++CONFIG_IPV6_ROUTER_PREF=y
+ CONFIG_INET6_AH=m
+ CONFIG_INET6_ESP=m
+ CONFIG_INET6_IPCOMP=m
+--- a/arch/arm/configs/bcmrpi_defconfig
++++ b/arch/arm/configs/bcmrpi_defconfig
+@@ -95,6 +95,7 @@ CONFIG_INET_XFRM_MODE_TUNNEL=m
+ CONFIG_INET_XFRM_MODE_BEET=m
+ CONFIG_INET_LRO=m
+ CONFIG_INET_DIAG=m
++CONFIG_IPV6_ROUTER_PREF=y
+ CONFIG_INET6_AH=m
+ CONFIG_INET6_ESP=m
+ CONFIG_INET6_IPCOMP=m
diff --git a/target/linux/brcm2708/patches-4.4/0236-Enable-hid-betopff-module.patch b/target/linux/brcm2708/patches-4.4/0236-Enable-hid-betopff-module.patch
new file mode 100644
index 0000000000..1c0b1ac56f
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0236-Enable-hid-betopff-module.patch
@@ -0,0 +1,32 @@
+From 046f7b291b867d22eb2ba03b83201363acc89551 Mon Sep 17 00:00:00 2001
+From: jochenberger <fooberger@gmail.com>
+Date: Thu, 7 Apr 2016 21:38:46 +0200
+Subject: [PATCH 236/381] Enable hid-betopff module
+
+Add force feedback support for Betop based devices
+https://github.com/raspberrypi/linux/blob/rpi-4.1.y/drivers/hid/hid-betopff.c
+---
+ arch/arm/configs/bcm2709_defconfig | 1 +
+ arch/arm/configs/bcmrpi_defconfig | 1 +
+ 2 files changed, 2 insertions(+)
+
+--- a/arch/arm/configs/bcm2709_defconfig
++++ b/arch/arm/configs/bcm2709_defconfig
+@@ -867,6 +867,7 @@ CONFIG_HID_A4TECH=m
+ CONFIG_HID_ACRUX=m
+ CONFIG_HID_APPLE=m
+ CONFIG_HID_BELKIN=m
++CONFIG_HID_BETOP_FF=m
+ CONFIG_HID_CHERRY=m
+ CONFIG_HID_CHICONY=m
+ CONFIG_HID_CYPRESS=m
+--- a/arch/arm/configs/bcmrpi_defconfig
++++ b/arch/arm/configs/bcmrpi_defconfig
+@@ -859,6 +859,7 @@ CONFIG_HID_A4TECH=m
+ CONFIG_HID_ACRUX=m
+ CONFIG_HID_APPLE=m
+ CONFIG_HID_BELKIN=m
++CONFIG_HID_BETOP_FF=m
+ CONFIG_HID_CHERRY=m
+ CONFIG_HID_CHICONY=m
+ CONFIG_HID_CYPRESS=m
diff --git a/target/linux/brcm2708/patches-4.4/0237-config-Make-IPV6-a-module-and-regenerate-with-defcon.patch b/target/linux/brcm2708/patches-4.4/0237-config-Make-IPV6-a-module-and-regenerate-with-defcon.patch
new file mode 100644
index 0000000000..256b1791c0
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0237-config-Make-IPV6-a-module-and-regenerate-with-defcon.patch
@@ -0,0 +1,70 @@
+From a7e05883dcb747994f0d65dcff6cbae905584c7b Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Tue, 12 Apr 2016 12:45:16 +0100
+Subject: [PATCH 237/381] config: Make IPV6 a module and regenerate with
+ defconfig
+
+---
+ arch/arm/configs/bcm2709_defconfig | 4 ++--
+ arch/arm/configs/bcmrpi_defconfig | 6 +++---
+ 2 files changed, 5 insertions(+), 5 deletions(-)
+
+--- a/arch/arm/configs/bcm2709_defconfig
++++ b/arch/arm/configs/bcm2709_defconfig
+@@ -101,6 +101,7 @@ CONFIG_INET_XFRM_MODE_TUNNEL=m
+ CONFIG_INET_XFRM_MODE_BEET=m
+ CONFIG_INET_LRO=m
+ CONFIG_INET_DIAG=m
++CONFIG_IPV6=m
+ CONFIG_IPV6_ROUTER_PREF=y
+ CONFIG_INET6_AH=m
+ CONFIG_INET6_ESP=m
+@@ -600,10 +601,9 @@ CONFIG_HW_RANDOM=y
+ CONFIG_RAW_DRIVER=y
+ CONFIG_I2C=y
+ CONFIG_I2C_CHARDEV=m
++CONFIG_I2C_MUX_PCA954x=m
+ CONFIG_I2C_BCM2708=m
+ CONFIG_I2C_GPIO=m
+-CONFIG_I2C_MUX=m
+-CONFIG_I2C_MUX_PCA954x=m
+ CONFIG_SPI=y
+ CONFIG_SPI_BCM2835=m
+ CONFIG_SPI_BCM2835AUX=m
+--- a/arch/arm/configs/bcmrpi_defconfig
++++ b/arch/arm/configs/bcmrpi_defconfig
+@@ -73,7 +73,6 @@ CONFIG_INET=y
+ CONFIG_IP_MULTICAST=y
+ CONFIG_IP_ADVANCED_ROUTER=y
+ CONFIG_IP_MULTIPLE_TABLES=y
+-CONFIG_IPV6_SUBTREES=y
+ CONFIG_IP_ROUTE_MULTIPATH=y
+ CONFIG_IP_ROUTE_VERBOSE=y
+ CONFIG_IP_PNP=y
+@@ -95,12 +94,14 @@ CONFIG_INET_XFRM_MODE_TUNNEL=m
+ CONFIG_INET_XFRM_MODE_BEET=m
+ CONFIG_INET_LRO=m
+ CONFIG_INET_DIAG=m
++CONFIG_IPV6=m
+ CONFIG_IPV6_ROUTER_PREF=y
+ CONFIG_INET6_AH=m
+ CONFIG_INET6_ESP=m
+ CONFIG_INET6_IPCOMP=m
+ CONFIG_IPV6_TUNNEL=m
+ CONFIG_IPV6_MULTIPLE_TABLES=y
++CONFIG_IPV6_SUBTREES=y
+ CONFIG_IPV6_MROUTE=y
+ CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
+ CONFIG_IPV6_PIMSM_V2=y
+@@ -593,10 +594,9 @@ CONFIG_HW_RANDOM=y
+ CONFIG_RAW_DRIVER=y
+ CONFIG_I2C=y
+ CONFIG_I2C_CHARDEV=m
++CONFIG_I2C_MUX_PCA954x=m
+ CONFIG_I2C_BCM2708=m
+ CONFIG_I2C_GPIO=m
+-CONFIG_I2C_MUX=m
+-CONFIG_I2C_MUX_PCA954x=m
+ CONFIG_SPI=y
+ CONFIG_SPI_BCM2835=m
+ CONFIG_SPI_BCM2835AUX=m
diff --git a/target/linux/brcm2708/patches-4.4/0238-BCM270X_DT-Add-dpi24-overlay.patch b/target/linux/brcm2708/patches-4.4/0238-BCM270X_DT-Add-dpi24-overlay.patch
new file mode 100644
index 0000000000..4698a9ee50
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0238-BCM270X_DT-Add-dpi24-overlay.patch
@@ -0,0 +1,74 @@
+From eb5818121aa45fb1f379e4990f8040ef4e979fa0 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Tue, 5 Apr 2016 13:01:54 +0100
+Subject: [PATCH 238/381] BCM270X_DT: Add dpi24 overlay
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 8 +++++++
+ arch/arm/boot/dts/overlays/dpi24-overlay.dts | 31 ++++++++++++++++++++++++++++
+ 3 files changed, 40 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/dpi24-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -15,6 +15,7 @@ endif
+ dtbo-$(RPI_DT_OVERLAYS) += ads7846.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += at86rf233.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += bmp085_i2c-sensor.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += dpi24.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += dwc2.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += dwc-otg.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += dht11.dtbo
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -213,6 +213,14 @@ Params: gpiopin GPIO con
+ (default 4)
+
+
++Name: dpi24
++Info: Overlay for a generic 24-bit DPI display
++ This uses GPIOs 0-27 (so no I2C, uart etc.), and activates the output
++ 2-3 seconds after the kernel has started.
++Load: dtoverlay=dpi24
++Params: <None>
++
++
+ Name: dwc-otg
+ Info: Selects the dwc_otg USB controller driver which has fiq support. This
+ is the default on all except the Pi Zero which defaults to dwc2.
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/dpi24-overlay.dts
+@@ -0,0 +1,31 @@
++/dts-v1/;
++/plugin/;
++
++/{
++ compatible = "brcm,bcm2708";
++
++ // There is no DPI driver module, but we need a platform device
++ // node (that doesn't already use pinctrl) to hang the pinctrl
++ // reference on - leds will do
++
++ fragment@0 {
++ target = <&leds>;
++ __overlay__ {
++ pinctrl-names = "default";
++ pinctrl-0 = <&dpi24_pins>;
++ };
++ };
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ dpi24_pins: dpi24_pins {
++ brcm,pins = <0 1 2 3 4 5 6 7 8 9 10 11
++ 12 13 14 15 16 17 18 19 20
++ 21 22 23 24 25 26 27>;
++ brcm,function = <6>; /* alt2 */
++ brcm,pull = <0>; /* no pull */
++ };
++ };
++ };
++};
diff --git a/target/linux/brcm2708/patches-4.4/0239-Modify-IQAudIO-DAC-ASoC-driver-to-set-card-dai-confi.patch b/target/linux/brcm2708/patches-4.4/0239-Modify-IQAudIO-DAC-ASoC-driver-to-set-card-dai-confi.patch
new file mode 100644
index 0000000000..e0b39cc774
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0239-Modify-IQAudIO-DAC-ASoC-driver-to-set-card-dai-confi.patch
@@ -0,0 +1,57 @@
+From fabd181287bd52afc523f10c27a7fd3a10969aa7 Mon Sep 17 00:00:00 2001
+From: DigitalDreamtime <clive.messer@digitaldreamtime.co.uk>
+Date: Thu, 14 Apr 2016 00:57:33 +0100
+Subject: [PATCH 239/381] Modify IQAudIO DAC+ ASoC driver to set card/dai
+ config from dt
+
+Add the ability to set the card name, dai name and dai stream name, from
+dt config.
+
+Signed-off-by: DigitalDreamtime <clive.messer@digitaldreamtime.co.uk>
+---
+ sound/soc/bcm/iqaudio-dac.c | 13 ++++++++++---
+ 1 file changed, 10 insertions(+), 3 deletions(-)
+
+--- a/sound/soc/bcm/iqaudio-dac.c
++++ b/sound/soc/bcm/iqaudio-dac.c
+@@ -61,8 +61,6 @@ static struct snd_soc_ops snd_rpi_iqaudi
+
+ static struct snd_soc_dai_link snd_rpi_iqaudio_dac_dai[] = {
+ {
+- .name = "IQaudIO DAC",
+- .stream_name = "IQaudIO DAC HiFi",
+ .cpu_dai_name = "bcm2708-i2s.0",
+ .codec_dai_name = "pcm512x-hifi",
+ .platform_name = "bcm2708-i2s.0",
+@@ -76,7 +74,6 @@ static struct snd_soc_dai_link snd_rpi_i
+
+ /* audio machine driver */
+ static struct snd_soc_card snd_rpi_iqaudio_dac = {
+- .name = "IQaudIODAC",
+ .owner = THIS_MODULE,
+ .dai_link = snd_rpi_iqaudio_dac_dai,
+ .num_links = ARRAY_SIZE(snd_rpi_iqaudio_dac_dai),
+@@ -90,6 +87,7 @@ static int snd_rpi_iqaudio_dac_probe(str
+
+ if (pdev->dev.of_node) {
+ struct device_node *i2s_node;
++ struct snd_soc_card *card = &snd_rpi_iqaudio_dac;
+ struct snd_soc_dai_link *dai = &snd_rpi_iqaudio_dac_dai[0];
+ i2s_node = of_parse_phandle(pdev->dev.of_node,
+ "i2s-controller", 0);
+@@ -103,6 +101,15 @@ static int snd_rpi_iqaudio_dac_probe(str
+
+ digital_gain_0db_limit = !of_property_read_bool(pdev->dev.of_node,
+ "iqaudio,24db_digital_gain");
++ if (of_property_read_string(pdev->dev.of_node, "card_name",
++ &card->name))
++ card->name = "IQaudIODAC";
++ if (of_property_read_string(pdev->dev.of_node, "dai_name",
++ &dai->name))
++ dai->name = "IQaudIO DAC";
++ if (of_property_read_string(pdev->dev.of_node, "dai_stream_name",
++ &dai->stream_name))
++ dai->stream_name = "IQaudIO DAC HiFi";
+ }
+
+ ret = snd_soc_register_card(&snd_rpi_iqaudio_dac);
diff --git a/target/linux/brcm2708/patches-4.4/0240-Add-support-for-the-Digital-Dreamtime-Akkordion-musi.patch b/target/linux/brcm2708/patches-4.4/0240-Add-support-for-the-Digital-Dreamtime-Akkordion-musi.patch
new file mode 100644
index 0000000000..11e5fd202e
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0240-Add-support-for-the-Digital-Dreamtime-Akkordion-musi.patch
@@ -0,0 +1,105 @@
+From 84e674b139553b74fa118a3e41ba6ca31e2c0750 Mon Sep 17 00:00:00 2001
+From: DigitalDreamtime <clive.messer@digitaldreamtime.co.uk>
+Date: Thu, 14 Apr 2016 01:00:58 +0100
+Subject: [PATCH 240/381] Add support for the Digital Dreamtime Akkordion music
+ player.
+
+Support the Digital Dreamtime Akkordion using the OEM IQAudIO DAC+ or
+DACZero modules. Set ALSA card name, ("Akkordion"), from dt config.
+
+Signed-off-by: DigitalDreamtime <clive.messer@digitaldreamtime.co.uk>
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 20 ++++++++++
+ .../dts/overlays/akkordion-iqdacplus-overlay.dts | 46 ++++++++++++++++++++++
+ 3 files changed, 67 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/akkordion-iqdacplus-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -13,6 +13,7 @@ ifeq ($(CONFIG_ARCH_BCM2835),y)
+ endif
+
+ dtbo-$(RPI_DT_OVERLAYS) += ads7846.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += akkordion-iqdacplus.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += at86rf233.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += bmp085_i2c-sensor.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += dpi24.dtbo
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -186,6 +186,26 @@ Params: cs SPI bus
+ www.kernel.org/doc/Documentation/devicetree/bindings/input/ads7846.txt
+
+
++Name: akkordion-iqdacplus
++Info: Configures the Digital Dreamtime Akkordion Music Player (based on the
++ OEM IQAudIO DAC+ or DAC Zero module).
++Load: dtoverlay=akkordion-iqdacplus,<param>=<val>
++Params: 24db_digital_gain Allow gain to be applied via the PCM512x codec
++ Digital volume control. Enable with
++ dtoverlay=akkordion-iqdacplus,24db_digital_gain
++ (The default behaviour is that the Digital
++ volume control is limited to a maximum of
++ 0dB. ie. it can attenuate but not provide
++ gain. For most users, this will be desired
++ as it will prevent clipping. By appending
++ the 24db_digital_gain parameter, the Digital
++ volume control will allow up to 24dB of
++ gain. If this parameter is enabled, it is the
++ responsibility of the user to ensure that
++ the Digital volume control is set to a value
++ that does not result in clipping/distortion!)
++
++
+ Name: at86rf233
+ Info: Configures the Atmel AT86RF233 802.15.4 low-power WPAN transceiver,
+ connected to spi0.0
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/akkordion-iqdacplus-overlay.dts
+@@ -0,0 +1,46 @@
++// Definitions for Digital Dreamtime Akkordion using IQaudIO DAC+ or DACZero
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&sound>;
++ frag0: __overlay__ {
++ compatible = "iqaudio,iqaudio-dac";
++ card_name = "Akkordion";
++ dai_name = "IQaudIO DAC";
++ dai_stream_name = "IQaudIO DAC HiFi";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&i2s>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@2 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ pcm5122@4c {
++ #sound-dai-cells = <0>;
++ compatible = "ti,pcm5122";
++ reg = <0x4c>;
++ status = "okay";
++ };
++ };
++ };
++
++ __overrides__ {
++ 24db_digital_gain = <&frag0>,"iqaudio,24db_digital_gain?";
++ };
++};
diff --git a/target/linux/brcm2708/patches-4.4/0241-Add-Support-for-BoomBerry-Audio-boards.patch b/target/linux/brcm2708/patches-4.4/0241-Add-Support-for-BoomBerry-Audio-boards.patch
new file mode 100644
index 0000000000..f8271f1397
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0241-Add-Support-for-BoomBerry-Audio-boards.patch
@@ -0,0 +1,605 @@
+From d26cb19ea8e7c42a8b53e5a3a377e198c9cce73e Mon Sep 17 00:00:00 2001
+From: Aaron Shaw <shawaj@gmail.com>
+Date: Thu, 7 Apr 2016 21:26:21 +0100
+Subject: [PATCH 241/381] Add Support for BoomBerry Audio boards
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 2 +
+ arch/arm/boot/dts/overlays/README | 26 +++
+ .../boot/dts/overlays/boomberry-dac-overlay.dts | 43 +++++
+ .../boot/dts/overlays/boomberry-digi-overlay.dts | 39 ++++
+ arch/arm/configs/bcm2709_defconfig | 2 +
+ arch/arm/configs/bcmrpi_defconfig | 2 +
+ sound/soc/bcm/Kconfig | 14 ++
+ sound/soc/bcm/Makefile | 4 +
+ sound/soc/bcm/boomberry-dac.c | 163 ++++++++++++++++
+ sound/soc/bcm/boomberry-digi.c | 215 +++++++++++++++++++++
+ 10 files changed, 510 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/boomberry-dac-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/boomberry-digi-overlay.dts
+ create mode 100644 sound/soc/bcm/boomberry-dac.c
+ create mode 100644 sound/soc/bcm/boomberry-digi.c
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -16,6 +16,8 @@ dtbo-$(RPI_DT_OVERLAYS) += ads7846.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += akkordion-iqdacplus.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += at86rf233.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += bmp085_i2c-sensor.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += boomberry-dac.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += boomberry-digi.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += dpi24.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += dwc2.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += dwc-otg.dtbo
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -225,6 +225,32 @@ Load: dtoverlay=bmp085_i2c-sensor
+ Params: <None>
+
+
++Name: boomberry-dac
++Info: Configures the BoomBerry DAC HAT, Amp HAT, DAC Zero and Amp Zero audio
++ cards
++Load: dtoverlay=boomberry-dac,<param>=<val>
++Params: 24db_digital_gain Allow gain to be applied via the PCM512x codec
++ Digital volume control. Enable with
++ "dtoverlay=boomberry-dac,24db_digital_gain"
++ (The default behaviour is that the Digital
++ volume control is limited to a maximum of
++ 0dB. ie. it can attenuate but not provide
++ gain. For most users, this will be desired
++ as it will prevent clipping. By appending
++ the 24dB_digital_gain parameter, the Digital
++ volume control will allow up to 24dB of
++ gain. If this parameter is enabled, it is the
++ responsibility of the user to ensure that
++ the Digital volume control is set to a value
++ that does not result in clipping/distortion!)
++
++
++Name: boomberry-digi
++Info: Configures the BoomBerry Digi HAT and Digi Zero audio cards
++Load: dtoverlay=boomberry-digi
++Params: <None>
++
++
+ Name: dht11
+ Info: Overlay for the DHT11/DHT21/DHT22 humidity/temperature sensors
+ Also sometimes found with the part number(s) AM230x.
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/boomberry-dac-overlay.dts
+@@ -0,0 +1,43 @@
++// Definitions for BoomBerry DAC
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&sound>;
++ frag0: __overlay__ {
++ compatible = "boomberry,boomberry-dac";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&i2s>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@2 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ pcm5122@4d {
++ #sound-dai-cells = <0>;
++ compatible = "ti,pcm5122";
++ reg = <0x4d>;
++ status = "okay";
++ };
++ };
++ };
++
++ __overrides__ {
++ 24db_digital_gain = <&frag0>,"boomberry,24db_digital_gain?";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/boomberry-digi-overlay.dts
+@@ -0,0 +1,39 @@
++// Definitions for BoomBerry Digi
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&sound>;
++ __overlay__ {
++ compatible = "boomberry,boomberry-digi";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&i2s>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@2 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ wm8804@3b {
++ #sound-dai-cells = <0>;
++ compatible = "wlf,wm8804";
++ reg = <0x3b>;
++ status = "okay";
++ };
++ };
++ };
++};
+--- a/arch/arm/configs/bcm2709_defconfig
++++ b/arch/arm/configs/bcm2709_defconfig
+@@ -853,6 +853,8 @@ CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC=m
+ CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS=m
+ CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI=m
+ CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP=m
++CONFIG_SND_BCM2708_SOC_BOOMBERRY_DAC=m
++CONFIG_SNG_BCM2708_SOC_BOOMBERRY_DIGI=m
+ CONFIG_SND_BCM2708_SOC_RPI_DAC=m
+ CONFIG_SND_BCM2708_SOC_RPI_PROTO=m
+ CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m
+--- a/arch/arm/configs/bcmrpi_defconfig
++++ b/arch/arm/configs/bcmrpi_defconfig
+@@ -845,6 +845,8 @@ CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC=m
+ CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS=m
+ CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI=m
+ CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP=m
++CONFIG_SND_BCM2708_SOC_BOOMBERRY_DAC=m
++CONFIG_SND_BCM2708_SOC_BOOMBERRY_DIGI=m
+ CONFIG_SND_BCM2708_SOC_RPI_DAC=m
+ CONFIG_SND_BCM2708_SOC_RPI_PROTO=m
+ CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -50,6 +50,20 @@ config SND_BCM2708_SOC_RPI_PROTO
+ help
+ Say Y or M if you want to add support for Audio Codec Board PROTO (WM8731).
+
++config SND_BCM2708_SOC_BOOMBERRY_DAC
++ tristate "Support for BoomBerry DAC"
++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
++ select SND_SOC_PCM512x
++ help
++ Say Y or M if you want to add support for BoomBerry DAC.
++
++config SND_BCM2708_SOC_BOOMBERRY_DIGI
++ tristate "Support for BoomBerry Digi"
++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
++ select SND_SOC_WM8804
++ help
++ Say Y or M if you want to add support for BoomBerry Digi.
++
+ config SND_BCM2708_SOC_IQAUDIO_DAC
+ tristate "Support for IQaudIO-DAC"
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+--- a/sound/soc/bcm/Makefile
++++ b/sound/soc/bcm/Makefile
+@@ -8,6 +8,8 @@ snd-soc-hifiberry-dac-objs := hifiberry_
+ snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
+ snd-soc-hifiberry-digi-objs := hifiberry_digi.o
+ snd-soc-hifiberry-amp-objs := hifiberry_amp.o
++snd-soc-boomberry-dac-objs := boomberry-dac.o
++snd-soc-boomberry-digi-objs := boomberry-digi.o
+ snd-soc-rpi-dac-objs := rpi-dac.o
+ snd-soc-rpi-proto-objs := rpi-proto.o
+ snd-soc-iqaudio-dac-objs := iqaudio-dac.o
+@@ -17,6 +19,8 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_D
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o
++obj-$(CONFIG_SND_BCM2708_SOC_BOOMBERRY_DAC) += snd-soc-boomberry-dac.o
++obj-$(CONFIG_SND_BCM2708_SOC_BOOMBERRY_DIGI) += snd-soc-boomberry-digi.o
+ obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o
+ obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
+ obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
+--- /dev/null
++++ b/sound/soc/bcm/boomberry-dac.c
+@@ -0,0 +1,163 @@
++/*
++ * ASoC Driver for BoomBerry DAC Raspberry Pi HAT Sound Card
++ *
++ * Author: Milan Neskovic
++ * Copyright 2016
++ * based on code by Daniel Matuschek <info@crazy-audio.com>
++ * based on code by Florian Meier <florian.meier@koalo.de>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/jack.h>
++
++#include "../codecs/pcm512x.h"
++
++static bool digital_gain_0db_limit = true;
++
++static int snd_rpi_boomberry_dac_init(struct snd_soc_pcm_runtime *rtd)
++{
++ struct snd_soc_codec *codec = rtd->codec;
++ snd_soc_update_bits(codec, PCM512x_GPIO_EN, 0x08, 0x08);
++ snd_soc_update_bits(codec, PCM512x_GPIO_OUTPUT_4, 0xf, 0x02);
++ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08,0x08);
++
++ if (digital_gain_0db_limit)
++ {
++ int ret;
++ struct snd_soc_card *card = rtd->card;
++ struct snd_soc_codec *codec = rtd->codec;
++
++ ret = snd_soc_limit_volume(codec, "Digital Playback Volume", 207);
++ if (ret < 0)
++ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
++ }
++
++ return 0;
++}
++
++static int snd_rpi_boomberry_dac_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
++ /*return snd_soc_dai_set_bclk_ratio(cpu_dai, 64);*/
++ unsigned int sample_bits =
++ snd_pcm_format_physical_width(params_format(params));
++ return snd_soc_dai_set_bclk_ratio(cpu_dai, sample_bits * 2);
++}
++
++static int snd_rpi_boomberry_dac_startup(struct snd_pcm_substream *substream) {
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_codec *codec = rtd->codec;
++ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08,0x08);
++ return 0;
++}
++
++static void snd_rpi_boomberry_dac_shutdown(struct snd_pcm_substream *substream) {
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_codec *codec = rtd->codec;
++ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08,0x00);
++}
++
++/* machine stream operations */
++static struct snd_soc_ops snd_rpi_boomberry_dac_ops = {
++ .hw_params = snd_rpi_boomberry_dac_hw_params,
++ .startup = snd_rpi_boomberry_dac_startup,
++ .shutdown = snd_rpi_boomberry_dac_shutdown,
++};
++
++static struct snd_soc_dai_link snd_rpi_boomberry_dac_dai[] = {
++{
++ .name = "BoomBerry DAC",
++ .stream_name = "BoomBerry DAC HiFi",
++ .cpu_dai_name = "bcm2708-i2s.0",
++ .codec_dai_name = "pcm512x-hifi",
++ .platform_name = "bcm2708-i2s.0",
++ .codec_name = "pcm512x.1-004d",
++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBS_CFS,
++ .ops = &snd_rpi_boomberry_dac_ops,
++ .init = snd_rpi_boomberry_dac_init,
++},
++};
++
++/* audio machine driver */
++static struct snd_soc_card snd_rpi_boomberry_dac = {
++ .name = "snd_rpi_boomberry_dac",
++ .owner = THIS_MODULE,
++ .dai_link = snd_rpi_boomberry_dac_dai,
++ .num_links = ARRAY_SIZE(snd_rpi_boomberry_dac_dai),
++};
++
++static int snd_rpi_boomberry_dac_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++
++ snd_rpi_boomberry_dac.dev = &pdev->dev;
++
++ if (pdev->dev.of_node) {
++ struct device_node *i2s_node;
++ struct snd_soc_dai_link *dai = &snd_rpi_boomberry_dac_dai[0];
++ i2s_node = of_parse_phandle(pdev->dev.of_node,
++ "i2s-controller", 0);
++
++ if (i2s_node) {
++ dai->cpu_dai_name = NULL;
++ dai->cpu_of_node = i2s_node;
++ dai->platform_name = NULL;
++ dai->platform_of_node = i2s_node;
++ }
++
++ digital_gain_0db_limit = !of_property_read_bool(
++ pdev->dev.of_node, "boomberry,24db_digital_gain");
++ }
++
++ ret = snd_soc_register_card(&snd_rpi_boomberry_dac);
++ if (ret)
++ dev_err(&pdev->dev,
++ "snd_soc_register_card() failed: %d\n", ret);
++
++ return ret;
++}
++
++static int snd_rpi_boomberry_dac_remove(struct platform_device *pdev)
++{
++ return snd_soc_unregister_card(&snd_rpi_boomberry_dac);
++}
++
++static const struct of_device_id snd_rpi_boomberry_dac_of_match[] = {
++ { .compatible = "boomberry,boomberry-dac", },
++ {},
++};
++MODULE_DEVICE_TABLE(of, snd_rpi_boomberry_dac_of_match);
++
++static struct platform_driver snd_rpi_boomberry_dac_driver = {
++ .driver = {
++ .name = "snd-rpi-boomberry-dac",
++ .owner = THIS_MODULE,
++ .of_match_table = snd_rpi_boomberry_dac_of_match,
++ },
++ .probe = snd_rpi_boomberry_dac_probe,
++ .remove = snd_rpi_boomberry_dac_remove,
++};
++
++module_platform_driver(snd_rpi_boomberry_dac_driver);
++
++MODULE_AUTHOR("Milan Neskovic <info@boomberry.co>");
++MODULE_DESCRIPTION("ASoC Driver for BoomBerry PI DAC HAT Sound Card");
++MODULE_LICENSE("GPL v2");
+--- /dev/null
++++ b/sound/soc/bcm/boomberry-digi.c
+@@ -0,0 +1,215 @@
++/*
++ * ASoC Driver for BoomBerry Raspberry Pi Digi HAT Sound Card
++ *
++ * Author: Milan Neskovic
++ * Copyright 2016
++ * based on code by Daniel Matuschek <info@crazy-audio.com>
++ * based on code by Florian Meier <florian.meier@koalo.de>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/jack.h>
++
++#include "../codecs/wm8804.h"
++
++static int snd_rpi_boomberry_digi_init(struct snd_soc_pcm_runtime *rtd)
++{
++ struct snd_soc_codec *codec = rtd->codec;
++
++ /* enable TX output */
++ snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, 0x0);
++
++ return 0;
++}
++
++static int snd_rpi_boomberry_digi_startup(struct snd_pcm_substream *substream) {
++ /* turn on digital output */
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_codec *codec = rtd->codec;
++ snd_soc_update_bits(codec, WM8804_PWRDN, 0x3c, 0x00);
++ return 0;
++}
++
++static void snd_rpi_boomberry_digi_shutdown(struct snd_pcm_substream *substream) {
++ /* turn off output */
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_codec *codec = rtd->codec;
++ snd_soc_update_bits(codec, WM8804_PWRDN, 0x3c, 0x3c);
++}
++
++static int snd_rpi_boomberry_digi_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_dai *codec_dai = rtd->codec_dai;
++ struct snd_soc_codec *codec = rtd->codec;
++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
++
++ int sysclk = 27000000; /* This is fixed on this board */
++
++ long mclk_freq=0;
++ int mclk_div=1;
++ int sampling_freq=1;
++
++ int ret;
++
++ int samplerate = params_rate(params);
++
++ if (samplerate<=96000) {
++ mclk_freq=samplerate*256;
++ mclk_div=WM8804_MCLKDIV_256FS;
++ } else {
++ mclk_freq=samplerate*128;
++ mclk_div=WM8804_MCLKDIV_128FS;
++ }
++
++ switch (samplerate) {
++ case 32000:
++ sampling_freq=0x03;
++ break;
++ case 44100:
++ sampling_freq=0x00;
++ break;
++ case 48000:
++ sampling_freq=0x02;
++ break;
++ case 88200:
++ sampling_freq=0x08;
++ break;
++ case 96000:
++ sampling_freq=0x0a;
++ break;
++ case 176400:
++ sampling_freq=0x0c;
++ break;
++ case 192000:
++ sampling_freq=0x0e;
++ break;
++ default:
++ dev_err(codec->dev,
++ "Failed to set WM8804 SYSCLK, unsupported samplerate %d\n",
++ samplerate);
++ }
++
++ snd_soc_dai_set_clkdiv(codec_dai, WM8804_MCLK_DIV, mclk_div);
++ snd_soc_dai_set_pll(codec_dai, 0, 0, sysclk, mclk_freq);
++
++ ret = snd_soc_dai_set_sysclk(codec_dai, WM8804_TX_CLKSRC_PLL,
++ sysclk, SND_SOC_CLOCK_OUT);
++ if (ret < 0) {
++ dev_err(codec->dev,
++ "Failed to set WM8804 SYSCLK: %d\n", ret);
++ return ret;
++ }
++
++ /* Enable TX output */
++ snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, 0x0);
++
++ /* Power on */
++ snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0);
++
++ /* set sampling frequency status bits */
++ snd_soc_update_bits(codec, WM8804_SPDTX4, 0x0f, sampling_freq);
++
++ return snd_soc_dai_set_bclk_ratio(cpu_dai,64);
++}
++
++/* machine stream operations */
++static struct snd_soc_ops snd_rpi_boomberry_digi_ops = {
++ .hw_params = snd_rpi_boomberry_digi_hw_params,
++ .startup = snd_rpi_boomberry_digi_startup,
++ .shutdown = snd_rpi_boomberry_digi_shutdown,
++};
++
++static struct snd_soc_dai_link snd_rpi_boomberry_digi_dai[] = {
++{
++ .name = "BoomBerry Digi",
++ .stream_name = "BoomBerry Digi HiFi",
++ .cpu_dai_name = "bcm2708-i2s.0",
++ .codec_dai_name = "wm8804-spdif",
++ .platform_name = "bcm2708-i2s.0",
++ .codec_name = "wm8804.1-003b",
++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBM_CFM,
++ .ops = &snd_rpi_boomberry_digi_ops,
++ .init = snd_rpi_boomberry_digi_init,
++},
++};
++
++/* audio machine driver */
++static struct snd_soc_card snd_rpi_boomberry_digi = {
++ .name = "snd_rpi_boomberry_digi",
++ .owner = THIS_MODULE,
++ .dai_link = snd_rpi_boomberry_digi_dai,
++ .num_links = ARRAY_SIZE(snd_rpi_boomberry_digi_dai),
++};
++
++static int snd_rpi_boomberry_digi_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++
++ snd_rpi_boomberry_digi.dev = &pdev->dev;
++
++ if (pdev->dev.of_node) {
++ struct device_node *i2s_node;
++ struct snd_soc_dai_link *dai = &snd_rpi_boomberry_digi_dai[0];
++ i2s_node = of_parse_phandle(pdev->dev.of_node,
++ "i2s-controller", 0);
++
++ if (i2s_node) {
++ dai->cpu_dai_name = NULL;
++ dai->cpu_of_node = i2s_node;
++ dai->platform_name = NULL;
++ dai->platform_of_node = i2s_node;
++ }
++ }
++
++ ret = snd_soc_register_card(&snd_rpi_boomberry_digi);
++ if (ret)
++ dev_err(&pdev->dev,
++ "snd_soc_register_card() failed: %d\n", ret);
++
++ return ret;
++}
++
++static int snd_rpi_boomberry_digi_remove(struct platform_device *pdev)
++{
++ return snd_soc_unregister_card(&snd_rpi_boomberry_digi);
++}
++
++static const struct of_device_id snd_rpi_boomberry_digi_of_match[] = {
++ { .compatible = "boomberry,boomberry-digi", },
++ {},
++};
++MODULE_DEVICE_TABLE(of, snd_rpi_boomberry_digi_of_match);
++
++static struct platform_driver snd_rpi_boomberry_digi_driver = {
++ .driver = {
++ .name = "snd-rpi-boomberry-digi",
++ .owner = THIS_MODULE,
++ .of_match_table = snd_rpi_boomberry_digi_of_match,
++ },
++ .probe = snd_rpi_boomberry_digi_probe,
++ .remove = snd_rpi_boomberry_digi_remove,
++};
++
++module_platform_driver(snd_rpi_boomberry_digi_driver);
++
++MODULE_AUTHOR("Milan Neskovic <info@boomberry.co>");
++MODULE_DESCRIPTION("ASoC Driver for BoomBerry PI Digi HAT Sound Card");
++MODULE_LICENSE("GPL v2");
diff --git a/target/linux/brcm2708/patches-4.4/0242-Add-support-for-mcp7940x-family-of-RTC.patch b/target/linux/brcm2708/patches-4.4/0242-Add-support-for-mcp7940x-family-of-RTC.patch
new file mode 100644
index 0000000000..a12609c2ad
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0242-Add-support-for-mcp7940x-family-of-RTC.patch
@@ -0,0 +1,43 @@
+From 21b5809ad5be5bd18608c9258ff5f571065f8ff9 Mon Sep 17 00:00:00 2001
+From: Aaron Shaw <shawaj@gmail.com>
+Date: Fri, 8 Apr 2016 00:06:00 +0100
+Subject: [PATCH 242/381] Add support for mcp7940x family of RTC
+
+---
+ arch/arm/boot/dts/overlays/README | 2 ++
+ arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts | 6 ++++++
+ 2 files changed, 8 insertions(+)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -435,6 +435,8 @@ Params: ds1307 Select t
+
+ ds3231 Select the DS3231 device
+
++ mcp7940x Select the MCP7940x device
++
+ mcp7941x Select the MCP7941x device
+
+ pcf2127 Select the PCF2127 device
+--- a/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
+@@ -23,6 +23,11 @@
+ reg = <0x68>;
+ status = "disable";
+ };
++ mcp7940x: mcp7940x@6f {
++ compatible = "microchip,mcp7940x";
++ reg = <0x6f>;
++ status = "disable";
++ };
+ mcp7941x: mcp7941x@6f {
+ compatible = "microchip,mcp7941x";
+ reg = <0x6f>;
+@@ -54,6 +59,7 @@
+ ds1307 = <&ds1307>,"status";
+ ds1339 = <&ds1339>,"status";
+ ds3231 = <&ds3231>,"status";
++ mcp7940x = <&mcp7940x>,"status";
+ mcp7941x = <&mcp7941x>,"status";
+ pcf2127 = <&pcf2127>,"status";
+ pcf8523 = <&pcf8523>,"status";
diff --git a/target/linux/brcm2708/patches-4.4/0243-bcm2709_defconfig-Fix-typo-on-BoomBerry-configuratio.patch b/target/linux/brcm2708/patches-4.4/0243-bcm2709_defconfig-Fix-typo-on-BoomBerry-configuratio.patch
new file mode 100644
index 0000000000..1ee447b32a
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0243-bcm2709_defconfig-Fix-typo-on-BoomBerry-configuratio.patch
@@ -0,0 +1,22 @@
+From 56fb67d4ce06ff6140da52559e3e256e46e9ce56 Mon Sep 17 00:00:00 2001
+From: Jeremy McDermond <nh6z@nh6z.net>
+Date: Thu, 14 Apr 2016 09:39:20 -0700
+Subject: [PATCH 243/381] bcm2709_defconfig: Fix typo on BoomBerry
+ configuration directive
+
+The BoomBerry configuration directive in bcm2709_defconfig has a typo.
+---
+ arch/arm/configs/bcm2709_defconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/configs/bcm2709_defconfig
++++ b/arch/arm/configs/bcm2709_defconfig
+@@ -854,7 +854,7 @@ CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS
+ CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI=m
+ CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP=m
+ CONFIG_SND_BCM2708_SOC_BOOMBERRY_DAC=m
+-CONFIG_SNG_BCM2708_SOC_BOOMBERRY_DIGI=m
++CONFIG_SND_BCM2708_SOC_BOOMBERRY_DIGI=m
+ CONFIG_SND_BCM2708_SOC_RPI_DAC=m
+ CONFIG_SND_BCM2708_SOC_RPI_PROTO=m
+ CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m
diff --git a/target/linux/brcm2708/patches-4.4/0244-boomberry-dac-Adjust-for-ALSA-API-change.patch b/target/linux/brcm2708/patches-4.4/0244-boomberry-dac-Adjust-for-ALSA-API-change.patch
new file mode 100644
index 0000000000..d0af6dbeea
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0244-boomberry-dac-Adjust-for-ALSA-API-change.patch
@@ -0,0 +1,26 @@
+From 1fc5799ca5f6f2cc31f5b076d780e111de011cc3 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 15 Apr 2016 10:48:39 +0100
+Subject: [PATCH 244/381] boomberry-dac: Adjust for ALSA API change
+
+As of 4.4, snd_soc_limit_volume now takes a struct snd_soc_card *
+rather than a struct snd_soc_codec *.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ sound/soc/bcm/boomberry-dac.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/sound/soc/bcm/boomberry-dac.c
++++ b/sound/soc/bcm/boomberry-dac.c
+@@ -40,9 +40,8 @@ static int snd_rpi_boomberry_dac_init(st
+ {
+ int ret;
+ struct snd_soc_card *card = rtd->card;
+- struct snd_soc_codec *codec = rtd->codec;
+
+- ret = snd_soc_limit_volume(codec, "Digital Playback Volume", 207);
++ ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207);
+ if (ret < 0)
+ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
+ }
diff --git a/target/linux/brcm2708/patches-4.4/0245-vmcs-Remove-unused-sm_cache_map_vector-definition-14.patch b/target/linux/brcm2708/patches-4.4/0245-vmcs-Remove-unused-sm_cache_map_vector-definition-14.patch
new file mode 100644
index 0000000000..6488399e35
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0245-vmcs-Remove-unused-sm_cache_map_vector-definition-14.patch
@@ -0,0 +1,35 @@
+From e66d9d6665362899e85d666a5d7b6279747a7273 Mon Sep 17 00:00:00 2001
+From: Khem Raj <raj.khem@gmail.com>
+Date: Sun, 17 Apr 2016 04:44:47 -0700
+Subject: [PATCH 245/381] vmcs: Remove unused sm_cache_map_vector definition
+ (#1411)
+
+The code using it also ifdef'ed with 0, anyyd gcc 6
+complains
+
+error: 'sm_cache_map_vector' defined but not used
+
+The code using it also ifdef'ed out
+
+Signed-off-by: Khem Raj <raj.khem@gmail.com>
+---
+ drivers/char/broadcom/vc_sm/vmcs_sm.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/char/broadcom/vc_sm/vmcs_sm.c
++++ b/drivers/char/broadcom/vc_sm/vmcs_sm.c
+@@ -197,12 +197,14 @@ struct SM_STATE_T {
+ static struct SM_STATE_T *sm_state;
+ static int sm_inited;
+
++#if 0
+ static const char *const sm_cache_map_vector[] = {
+ "(null)",
+ "host",
+ "videocore",
+ "host+videocore",
+ };
++#endif
+
+ /* ---- Private Function Prototypes -------------------------------------- */
+
diff --git a/target/linux/brcm2708/patches-4.4/0246-scripts-mkknlimg-Append-a-trailer-for-all-input.patch b/target/linux/brcm2708/patches-4.4/0246-scripts-mkknlimg-Append-a-trailer-for-all-input.patch
new file mode 100644
index 0000000000..84b5bd356d
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0246-scripts-mkknlimg-Append-a-trailer-for-all-input.patch
@@ -0,0 +1,63 @@
+From ced7d5ba55445eb116abd68466d6caa1538ff482 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 18 Apr 2016 11:56:53 +0100
+Subject: [PATCH 246/381] scripts/mkknlimg: Append a trailer for all input
+
+Now that the firmware assumes an unsigned kernel is DT-capable, it is
+helpful to be able to mark a kernel as being non-DT-capable.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ scripts/mkknlimg | 11 +++++------
+ 1 file changed, 5 insertions(+), 6 deletions(-)
+
+--- a/scripts/mkknlimg
++++ b/scripts/mkknlimg
+@@ -98,7 +98,7 @@ my $append_trailer;
+ my $trailer;
+ my $kver = '?';
+
+-$append_trailer = $dtok;
++$append_trailer = 1;
+
+ if ($res)
+ {
+@@ -108,7 +108,6 @@ if ($res)
+
+ if ($flags & FLAG_PI)
+ {
+- $append_trailer = 1;
+ $dtok ||= ($flags & FLAG_DTOK) != 0;
+ $is_270x ||= ($flags & FLAG_270X) != 0;
+ $is_283x ||= ($flags & FLAG_283X) != 0;
+@@ -116,18 +115,18 @@ if ($res)
+ }
+ else
+ {
+- print ("* This doesn't look like a Raspberry Pi kernel. In pass-through mode.\n");
++ print ("* This doesn't look like a Raspberry Pi kernel.\n");
+ }
+ }
+ elsif (!$dtok)
+ {
+- print ("* Is this a valid kernel? In pass-through mode.\n");
++ print ("* Is this a valid kernel?\n");
+ }
+
+ if ($append_trailer)
+ {
+ printf("DT: %s\n", $dtok ? "y" : "n");
+- printf("DDT: %s\n", $ddtk ? "y" : "n") if ($ddtk);
++ printf("DDT: %s\n", $ddtk ? "y" : "n");
+ printf("270x: %s\n", $is_270x ? "y" : "n");
+ printf("283x: %s\n", $is_283x ? "y" : "n");
+
+@@ -136,7 +135,7 @@ if ($append_trailer)
+ push @atoms, [ $trailer_magic, pack('V', 0) ];
+ push @atoms, [ 'KVer', $kver ];
+ push @atoms, [ 'DTOK', pack('V', $dtok) ];
+- push @atoms, [ 'DDTK', pack('V', $ddtk) ] if ($ddtk);
++ push @atoms, [ 'DDTK', pack('V', $ddtk) ];
+ push @atoms, [ '270X', pack('V', $is_270x) ];
+ push @atoms, [ '283X', pack('V', $is_283x) ];
+ push @atoms, [ '283x', pack('V', $is_283x && !$is_270x) ];
diff --git a/target/linux/brcm2708/patches-4.4/0247-bcm2835_thermal-Don-t-report-unsupported-trip-type.patch b/target/linux/brcm2708/patches-4.4/0247-bcm2835_thermal-Don-t-report-unsupported-trip-type.patch
new file mode 100644
index 0000000000..ab578a473d
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0247-bcm2835_thermal-Don-t-report-unsupported-trip-type.patch
@@ -0,0 +1,69 @@
+From 6877cb849fe4953be1c9f056a83e218e09948d38 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Tue, 19 Apr 2016 12:57:52 +0100
+Subject: [PATCH 247/381] bcm2835_thermal: Don't report unsupported trip type
+
+---
+ drivers/thermal/bcm2835-thermal.c | 34 +---------------------------------
+ 1 file changed, 1 insertion(+), 33 deletions(-)
+
+--- a/drivers/thermal/bcm2835-thermal.c
++++ b/drivers/thermal/bcm2835-thermal.c
+@@ -49,38 +49,8 @@ static int bcm2835_thermal_get_temp(stru
+ RPI_FIRMWARE_GET_TEMPERATURE);
+ }
+
+-static int bcm2835_thermal_get_max_temp(struct thermal_zone_device *tz,
+- int trip, int *temp)
+-{
+- /*
+- * The maximum safe temperature of the SoC.
+- * Overclock may be disabled above this temperature.
+- */
+- return bcm2835_thermal_get_property(tz, temp,
+- RPI_FIRMWARE_GET_MAX_TEMPERATURE);
+-}
+-
+-static int bcm2835_thermal_get_trip_type(struct thermal_zone_device *tz,
+- int trip, enum thermal_trip_type *type)
+-{
+- *type = THERMAL_TRIP_HOT;
+-
+- return 0;
+-}
+-
+-static int bcm2835_thermal_get_mode(struct thermal_zone_device *tz,
+- enum thermal_device_mode *mode)
+-{
+- *mode = THERMAL_DEVICE_ENABLED;
+-
+- return 0;
+-}
+-
+ static struct thermal_zone_device_ops ops = {
+ .get_temp = bcm2835_thermal_get_temp,
+- .get_trip_temp = bcm2835_thermal_get_max_temp,
+- .get_trip_type = bcm2835_thermal_get_trip_type,
+- .get_mode = bcm2835_thermal_get_mode,
+ };
+
+ static int bcm2835_thermal_probe(struct platform_device *pdev)
+@@ -90,17 +60,15 @@ static int bcm2835_thermal_probe(struct
+ struct thermal_zone_device *tz;
+
+ fw_np = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
+-/* Remove comment when booting without Device Tree is no longer supported
+ if (!fw_np) {
+ dev_err(&pdev->dev, "Missing firmware node\n");
+ return -ENOENT;
+ }
+-*/
+ fw = rpi_firmware_get(fw_np);
+ if (!fw)
+ return -EPROBE_DEFER;
+
+- tz = thermal_zone_device_register("bcm2835_thermal", 1, 0, fw, &ops,
++ tz = thermal_zone_device_register("bcm2835_thermal", 0, 0, fw, &ops,
+ NULL, 0, 0);
+ if (IS_ERR(tz)) {
+ dev_err(&pdev->dev, "Failed to register the thermal device\n");
diff --git a/target/linux/brcm2708/patches-4.4/0248-scripts-dtc-Only-emit-local-fixups-for-overlays.patch b/target/linux/brcm2708/patches-4.4/0248-scripts-dtc-Only-emit-local-fixups-for-overlays.patch
new file mode 100644
index 0000000000..7a4a446c69
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0248-scripts-dtc-Only-emit-local-fixups-for-overlays.patch
@@ -0,0 +1,21 @@
+From 8cb95ac5aa3d9daebb4265bfac06b70bb3d24559 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Tue, 19 Apr 2016 13:55:29 +0100
+Subject: [PATCH 248/381] scripts/dtc: Only emit local fixups for overlays
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ scripts/dtc/checks.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/scripts/dtc/checks.c
++++ b/scripts/dtc/checks.c
+@@ -514,7 +514,7 @@ static void fixup_phandle_references(str
+ }
+
+ /* if it's a local reference, we need to record it */
+- if (symbol_fixup_support) {
++ if (symbol_fixup_support && dt->is_plugin) {
+
+ /* allocate a new local fixup entry */
+ fe = xmalloc(sizeof(*fe));
diff --git a/target/linux/brcm2708/patches-4.4/0249-bcm2835-do-not-require-substream-for-accessing-chmap.patch b/target/linux/brcm2708/patches-4.4/0249-bcm2835-do-not-require-substream-for-accessing-chmap.patch
new file mode 100644
index 0000000000..b353965501
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0249-bcm2835-do-not-require-substream-for-accessing-chmap.patch
@@ -0,0 +1,51 @@
+From 367f4ce11d5588d680ae50c405b1a9afa591a550 Mon Sep 17 00:00:00 2001
+From: wm4 <wm4@nowhere>
+Date: Tue, 19 Apr 2016 16:08:35 +0200
+Subject: [PATCH 249/381] bcm2835: do not require substream for accessing chmap
+ ctl
+
+Fixes alsasctl store/restore operation.
+---
+ sound/arm/bcm2835-ctl.c | 10 +---------
+ 1 file changed, 1 insertion(+), 9 deletions(-)
+
+--- a/sound/arm/bcm2835-ctl.c
++++ b/sound/arm/bcm2835-ctl.c
+@@ -489,8 +489,6 @@ static int snd_bcm2835_chmap_ctl_get(str
+ {
+ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+ bcm2835_chip_t *chip = info->private_data;
+- unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+- struct snd_pcm_substream *substream = snd_pcm_chmap_substream(info, idx);
+ struct cea_channel_speaker_allocation *ch = NULL;
+ int res = 0;
+ int cur = 0;
+@@ -499,11 +497,6 @@ static int snd_bcm2835_chmap_ctl_get(str
+ if (mutex_lock_interruptible(&chip->audio_mutex))
+ return -EINTR;
+
+- if (!substream || !substream->runtime) {
+- res = -ENODEV;
+- goto unlock;
+- }
+-
+ for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
+ if (channel_allocations[i].ca_index == chip->cea_chmap)
+ ch = &channel_allocations[i];
+@@ -521,7 +514,6 @@ static int snd_bcm2835_chmap_ctl_get(str
+ while (cur < 8)
+ ucontrol->value.integer.value[cur++] = SNDRV_CHMAP_NA;
+
+-unlock:
+ mutex_unlock(&chip->audio_mutex);
+ return res;
+ }
+@@ -541,7 +533,7 @@ static int snd_bcm2835_chmap_ctl_put(str
+ return -EINTR;
+
+ if (!substream || !substream->runtime) {
+- res = -ENODEV;
++ /* ignore and return success for the sake of alsactl */
+ goto unlock;
+ }
+
diff --git a/target/linux/brcm2708/patches-4.4/0250-bcm2835-add-fallback-channel-layouts-if-channel-map-.patch b/target/linux/brcm2708/patches-4.4/0250-bcm2835-add-fallback-channel-layouts-if-channel-map-.patch
new file mode 100644
index 0000000000..5614b9fa23
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0250-bcm2835-add-fallback-channel-layouts-if-channel-map-.patch
@@ -0,0 +1,41 @@
+From a9d3c50f084d4d6d1063969c04bc8233fe1437c1 Mon Sep 17 00:00:00 2001
+From: wm4 <wm4@nowhere>
+Date: Tue, 19 Apr 2016 16:29:41 +0200
+Subject: [PATCH 250/381] bcm2835: add fallback channel layouts if channel map
+ API is not used
+
+Should be more useful than just forcing stereo.
+
+We can't match the exact legacy ALSA channel layouts, so this is a
+"best effort" hack.
+
+I'm not sure what happens if the application requests channel counts
+that are not power-of-2s. The channel map API hopefully forces
+applications which use the channel map API to request the correct
+count by adding padding channels, but the bare API enforces
+nothing. Possibly this could be added to rate_hw_constraint_channels
+at a later point.
+---
+ sound/arm/bcm2835-vchiq.c | 11 ++++++++++-
+ 1 file changed, 10 insertions(+), 1 deletion(-)
+
+--- a/sound/arm/bcm2835-vchiq.c
++++ b/sound/arm/bcm2835-vchiq.c
+@@ -598,7 +598,16 @@ int bcm2835_audio_set_params(bcm2835_als
+ if (alsa_stream->chip->cea_chmap >= 0) {
+ chmap_value = (unsigned)alsa_stream->chip->cea_chmap << 24;
+ } else {
+- chmap_value = 0; /* force stereo */
++ /* fallback layouts for applications which do not use chmap API */
++ chmap_value = 0x00;
++ switch (channels) {
++ case 3: chmap_value = 0x01; break;
++ case 4: chmap_value = 0x03; break;
++ case 5: chmap_value = 0x07; break;
++ case 6: chmap_value = 0x0b; break;
++ case 7: chmap_value = 0x0f; break;
++ case 8: chmap_value = 0x13; break;
++ }
+ for (i = 0; i < 8; i++)
+ alsa_stream->chip->map_channels[i] = i;
+ }
diff --git a/target/linux/brcm2708/patches-4.4/0251-bcm2835-log-which-channel-map-is-set.patch b/target/linux/brcm2708/patches-4.4/0251-bcm2835-log-which-channel-map-is-set.patch
new file mode 100644
index 0000000000..b5ad4ae27d
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0251-bcm2835-log-which-channel-map-is-set.patch
@@ -0,0 +1,32 @@
+From c1a1f4c6d4e2d1bdba70de54bc204d2b3a80c0ea Mon Sep 17 00:00:00 2001
+From: wm4 <wm4@nowhere>
+Date: Tue, 19 Apr 2016 16:38:03 +0200
+Subject: [PATCH 251/381] bcm2835: log which channel map is set
+
+---
+ sound/arm/bcm2835-vchiq.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/sound/arm/bcm2835-vchiq.c
++++ b/sound/arm/bcm2835-vchiq.c
+@@ -596,8 +596,11 @@ int bcm2835_audio_set_params(bcm2835_als
+ instance->result = -1;
+
+ if (alsa_stream->chip->cea_chmap >= 0) {
++ LOG_INFO("Using application requested channel map: %d\n",
++ alsa_stream->chip->cea_chmap);
+ chmap_value = (unsigned)alsa_stream->chip->cea_chmap << 24;
+ } else {
++ LOG_INFO("Using fallback channel map.\n");
+ /* fallback layouts for applications which do not use chmap API */
+ chmap_value = 0x00;
+ switch (channels) {
+@@ -614,6 +617,8 @@ int bcm2835_audio_set_params(bcm2835_als
+ for (i = 0; i < 8; i++)
+ chmap_value |= alsa_stream->chip->map_channels[i] << (i * 3);
+
++ LOG_INFO("Requesting AUDS channel map: 0x%lx\n", (long)chmap_value);
++
+ m.type = VC_AUDIO_MSG_TYPE_CONFIG;
+ m.u.config.channels = channels;
+ m.u.config.samplerate = samplerate;
diff --git a/target/linux/brcm2708/patches-4.4/0252-clk-bcm2835-add-a-round-up-ability-to-the-clock-divi.patch b/target/linux/brcm2708/patches-4.4/0252-clk-bcm2835-add-a-round-up-ability-to-the-clock-divi.patch
new file mode 100644
index 0000000000..5866df4d38
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0252-clk-bcm2835-add-a-round-up-ability-to-the-clock-divi.patch
@@ -0,0 +1,70 @@
+From e9dccf5bbdb8d40477fe5ebedea548cf24407c1c Mon Sep 17 00:00:00 2001
+From: Remi Pommarel <repk@triplefau.lt>
+Date: Sun, 6 Dec 2015 17:22:46 +0100
+Subject: [PATCH 252/381] clk: bcm2835: add a round up ability to the clock
+ divisor
+
+Make bcm2835_clock_choose_div to optionally round up the chosen MASH divisor
+so that the resulting average rate will not be higher than the requested one.
+
+Signed-off-by: Remi Pommarel <repk@triplefau.lt>
+Reviewed-by: Eric Anholt <eric@anholt.net>
+Signed-off-by: Michael Turquette <mturquette@baylibre.com>
+(cherry picked from commit 9c95b32ca09364e4687b72c4e17b78dc1c420026)
+---
+ drivers/clk/bcm/clk-bcm2835.c | 22 ++++++++++++----------
+ 1 file changed, 12 insertions(+), 10 deletions(-)
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -1164,22 +1164,24 @@ static int bcm2835_clock_is_on(struct cl
+
+ static u32 bcm2835_clock_choose_div(struct clk_hw *hw,
+ unsigned long rate,
+- unsigned long parent_rate)
++ unsigned long parent_rate,
++ bool round_up)
+ {
+ struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+ const struct bcm2835_clock_data *data = clock->data;
+- u32 unused_frac_mask = GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0);
++ u32 unused_frac_mask =
++ GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0) >> 1;
+ u64 temp = (u64)parent_rate << CM_DIV_FRAC_BITS;
++ u64 rem;
+ u32 div;
+
+- do_div(temp, rate);
++ rem = do_div(temp, rate);
+ div = temp;
+
+- /* Round and mask off the unused bits */
+- if (unused_frac_mask != 0) {
+- div += unused_frac_mask >> 1;
+- div &= ~unused_frac_mask;
+- }
++ /* Round up and mask off the unused bits */
++ if (round_up && ((div & unused_frac_mask) != 0 || rem != 0))
++ div += unused_frac_mask + 1;
++ div &= ~unused_frac_mask;
+
+ /* clamp to min divider of 1 */
+ div = max_t(u32, div, 1 << CM_DIV_FRAC_BITS);
+@@ -1219,7 +1221,7 @@ static long bcm2835_clock_round_rate(str
+ unsigned long *parent_rate)
+ {
+ struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+- u32 div = bcm2835_clock_choose_div(hw, rate, *parent_rate);
++ u32 div = bcm2835_clock_choose_div(hw, rate, *parent_rate, false);
+
+ return bcm2835_clock_rate_from_divisor(clock, *parent_rate, div);
+ }
+@@ -1288,7 +1290,7 @@ static int bcm2835_clock_set_rate(struct
+ struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+ struct bcm2835_cprman *cprman = clock->cprman;
+ const struct bcm2835_clock_data *data = clock->data;
+- u32 div = bcm2835_clock_choose_div(hw, rate, parent_rate);
++ u32 div = bcm2835_clock_choose_div(hw, rate, parent_rate, false);
+
+ cprman_write(cprman, data->div_reg, div);
+
diff --git a/target/linux/brcm2708/patches-4.4/0253-clk-bcm2835-Support-for-clock-parent-selection.patch b/target/linux/brcm2708/patches-4.4/0253-clk-bcm2835-Support-for-clock-parent-selection.patch
new file mode 100644
index 0000000000..f2221f3d3f
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0253-clk-bcm2835-Support-for-clock-parent-selection.patch
@@ -0,0 +1,188 @@
+From 8578eeecb147439b7286e14cd0ce8a5078851f56 Mon Sep 17 00:00:00 2001
+From: Remi Pommarel <repk@triplefau.lt>
+Date: Sun, 6 Dec 2015 17:22:47 +0100
+Subject: [PATCH 253/381] clk: bcm2835: Support for clock parent selection
+
+Some bcm2835 clocks used by hardware (like "PWM" or "H264") can have multiple
+parent clocks. These clocks divide the rate of a parent which can be selected by
+setting the proper bits in the clock control register.
+
+Previously all these parents where handled by a mux clock. But a mux clock
+cannot be used because updating clock control register to select parent needs a
+password to be xor'd with the parent index.
+
+This patch get rid of mux clock and make these clocks handle their own parent,
+allowing them to select the one to use.
+
+Signed-off-by: Remi Pommarel <repk@triplefau.lt>
+Reviewed-by: Eric Anholt <eric@anholt.net>
+Signed-off-by: Michael Turquette <mturquette@baylibre.com>
+(cherry picked from commit 6d18b8adbe679b5947aa822b676efff230acc5f6)
+---
+ drivers/clk/bcm/clk-bcm2835.c | 122 ++++++++++++++++++++++++++----------------
+ 1 file changed, 77 insertions(+), 45 deletions(-)
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -1216,16 +1216,6 @@ static long bcm2835_clock_rate_from_divi
+ return temp;
+ }
+
+-static long bcm2835_clock_round_rate(struct clk_hw *hw,
+- unsigned long rate,
+- unsigned long *parent_rate)
+-{
+- struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+- u32 div = bcm2835_clock_choose_div(hw, rate, *parent_rate, false);
+-
+- return bcm2835_clock_rate_from_divisor(clock, *parent_rate, div);
+-}
+-
+ static unsigned long bcm2835_clock_get_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+ {
+@@ -1297,13 +1287,75 @@ static int bcm2835_clock_set_rate(struct
+ return 0;
+ }
+
++static int bcm2835_clock_determine_rate(struct clk_hw *hw,
++ struct clk_rate_request *req)
++{
++ struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
++ struct clk_hw *parent, *best_parent = NULL;
++ unsigned long rate, best_rate = 0;
++ unsigned long prate, best_prate = 0;
++ size_t i;
++ u32 div;
++
++ /*
++ * Select parent clock that results in the closest but lower rate
++ */
++ for (i = 0; i < clk_hw_get_num_parents(hw); ++i) {
++ parent = clk_hw_get_parent_by_index(hw, i);
++ if (!parent)
++ continue;
++ prate = clk_hw_get_rate(parent);
++ div = bcm2835_clock_choose_div(hw, req->rate, prate, true);
++ rate = bcm2835_clock_rate_from_divisor(clock, prate, div);
++ if (rate > best_rate && rate <= req->rate) {
++ best_parent = parent;
++ best_prate = prate;
++ best_rate = rate;
++ }
++ }
++
++ if (!best_parent)
++ return -EINVAL;
++
++ req->best_parent_hw = best_parent;
++ req->best_parent_rate = best_prate;
++
++ req->rate = best_rate;
++
++ return 0;
++}
++
++static int bcm2835_clock_set_parent(struct clk_hw *hw, u8 index)
++{
++ struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
++ struct bcm2835_cprman *cprman = clock->cprman;
++ const struct bcm2835_clock_data *data = clock->data;
++ u8 src = (index << CM_SRC_SHIFT) & CM_SRC_MASK;
++
++ cprman_write(cprman, data->ctl_reg, src);
++ return 0;
++}
++
++static u8 bcm2835_clock_get_parent(struct clk_hw *hw)
++{
++ struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
++ struct bcm2835_cprman *cprman = clock->cprman;
++ const struct bcm2835_clock_data *data = clock->data;
++ u32 src = cprman_read(cprman, data->ctl_reg);
++
++ return (src & CM_SRC_MASK) >> CM_SRC_SHIFT;
++}
++
++
+ static const struct clk_ops bcm2835_clock_clk_ops = {
+ .is_prepared = bcm2835_clock_is_on,
+ .prepare = bcm2835_clock_on,
+ .unprepare = bcm2835_clock_off,
+ .recalc_rate = bcm2835_clock_get_rate,
+ .set_rate = bcm2835_clock_set_rate,
+- .round_rate = bcm2835_clock_round_rate,
++ .determine_rate = bcm2835_clock_determine_rate,
++ .set_parent = bcm2835_clock_set_parent,
++ .get_parent = bcm2835_clock_get_parent,
+ };
+
+ static int bcm2835_vpu_clock_is_on(struct clk_hw *hw)
+@@ -1319,7 +1371,9 @@ static const struct clk_ops bcm2835_vpu_
+ .is_prepared = bcm2835_vpu_clock_is_on,
+ .recalc_rate = bcm2835_clock_get_rate,
+ .set_rate = bcm2835_clock_set_rate,
+- .round_rate = bcm2835_clock_round_rate,
++ .determine_rate = bcm2835_clock_determine_rate,
++ .set_parent = bcm2835_clock_set_parent,
++ .get_parent = bcm2835_clock_get_parent,
+ };
+
+ static struct clk *bcm2835_register_pll(struct bcm2835_cprman *cprman,
+@@ -1413,45 +1467,23 @@ static struct clk *bcm2835_register_cloc
+ {
+ struct bcm2835_clock *clock;
+ struct clk_init_data init;
+- const char *parent;
++ const char *parents[1 << CM_SRC_BITS];
++ size_t i;
+
+ /*
+- * Most of the clock generators have a mux field, so we
+- * instantiate a generic mux as our parent to handle it.
++ * Replace our "xosc" references with the oscillator's
++ * actual name.
+ */
+- if (data->num_mux_parents) {
+- const char *parents[1 << CM_SRC_BITS];
+- int i;
+-
+- parent = devm_kasprintf(cprman->dev, GFP_KERNEL,
+- "mux_%s", data->name);
+- if (!parent)
+- return NULL;
+-
+- /*
+- * Replace our "xosc" references with the oscillator's
+- * actual name.
+- */
+- for (i = 0; i < data->num_mux_parents; i++) {
+- if (strcmp(data->parents[i], "xosc") == 0)
+- parents[i] = cprman->osc_name;
+- else
+- parents[i] = data->parents[i];
+- }
+-
+- clk_register_mux(cprman->dev, parent,
+- parents, data->num_mux_parents,
+- CLK_SET_RATE_PARENT,
+- cprman->regs + data->ctl_reg,
+- CM_SRC_SHIFT, CM_SRC_BITS,
+- 0, &cprman->regs_lock);
+- } else {
+- parent = data->parents[0];
++ for (i = 0; i < data->num_mux_parents; i++) {
++ if (strcmp(data->parents[i], "xosc") == 0)
++ parents[i] = cprman->osc_name;
++ else
++ parents[i] = data->parents[i];
+ }
+
+ memset(&init, 0, sizeof(init));
+- init.parent_names = &parent;
+- init.num_parents = 1;
++ init.parent_names = parents;
++ init.num_parents = data->num_mux_parents;
+ init.name = data->name;
+ init.flags = CLK_IGNORE_UNUSED;
+
diff --git a/target/linux/brcm2708/patches-4.4/0254-clk-bcm2835-Add-PWM-clock-support.patch b/target/linux/brcm2708/patches-4.4/0254-clk-bcm2835-Add-PWM-clock-support.patch
new file mode 100644
index 0000000000..b0d2ec2917
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0254-clk-bcm2835-Add-PWM-clock-support.patch
@@ -0,0 +1,55 @@
+From c1f2dd85b1d53093fdf7af80ece7517ffed00f3a Mon Sep 17 00:00:00 2001
+From: Remi Pommarel <repk@triplefau.lt>
+Date: Sun, 6 Dec 2015 17:22:48 +0100
+Subject: [PATCH 254/381] clk: bcm2835: Add PWM clock support
+
+Register the pwm clock for bcm2835.
+
+Signed-off-by: Remi Pommarel <repk@triplefau.lt>
+Reviewed-by: Eric Anholt <eric@anholt.net>
+Signed-off-by: Michael Turquette <mturquette@baylibre.com>
+(cherry picked from commit cfbab8fbab9c330aca963095a439c451ac97c0dd)
+---
+ drivers/clk/bcm/clk-bcm2835.c | 13 +++++++++++++
+ include/dt-bindings/clock/bcm2835.h | 3 ++-
+ 2 files changed, 15 insertions(+), 1 deletion(-)
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -807,6 +807,16 @@ static const struct bcm2835_clock_data b
+ .frac_bits = 8,
+ };
+
++static const struct bcm2835_clock_data bcm2835_clock_pwm_data = {
++ .name = "pwm",
++ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents),
++ .parents = bcm2835_clock_per_parents,
++ .ctl_reg = CM_PWMCTL,
++ .div_reg = CM_PWMDIV,
++ .int_bits = 12,
++ .frac_bits = 12,
++};
++
+ struct bcm2835_pll {
+ struct clk_hw hw;
+ struct bcm2835_cprman *cprman;
+@@ -1601,6 +1611,9 @@ static int bcm2835_clk_probe(struct plat
+ cprman->regs + CM_PERIICTL, CM_GATE_BIT,
+ 0, &cprman->regs_lock);
+
++ clks[BCM2835_CLOCK_PWM] =
++ bcm2835_register_clock(cprman, &bcm2835_clock_pwm_data);
++
+ return of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
+ &cprman->onecell);
+ }
+--- a/include/dt-bindings/clock/bcm2835.h
++++ b/include/dt-bindings/clock/bcm2835.h
+@@ -43,5 +43,6 @@
+ #define BCM2835_CLOCK_TSENS 27
+ #define BCM2835_CLOCK_EMMC 28
+ #define BCM2835_CLOCK_PERI_IMAGE 29
++#define BCM2835_CLOCK_PWM 30
+
+-#define BCM2835_CLOCK_COUNT 30
++#define BCM2835_CLOCK_COUNT 31
diff --git a/target/linux/brcm2708/patches-4.4/0255-clk-bcm2835-added-missing-clock-register-definitions.patch b/target/linux/brcm2708/patches-4.4/0255-clk-bcm2835-added-missing-clock-register-definitions.patch
new file mode 100644
index 0000000000..6beadb258e
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0255-clk-bcm2835-added-missing-clock-register-definitions.patch
@@ -0,0 +1,49 @@
+From 4b1216203d83ff57820312dafb9a0b3500f03f80 Mon Sep 17 00:00:00 2001
+From: Martin Sperl <kernel@martin.sperl.org>
+Date: Tue, 22 Dec 2015 20:13:08 +0000
+Subject: [PATCH 255/381] clk: bcm2835: added missing clock register
+ definitions
+
+Added missing CTRL and DIV clock register definitions for:
+PCM, SLIM, TCNT, TEC, TD0, TD1
+
+Register information taken from:
+https://rawgit.com/msperl/rpi-registers/master/rpi-registers.html#CM
+which extracted the information from the header files shared by
+Broadcom/rpi foundation in this file:
+http://www.broadcom.com/docs/support/videocore/Brcm_Android_ICS_Graphics_Stack.tar.gz
+
+Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
+Reviewed-by: Eric Anholt <eric@anholt.net>
+Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+(cherry picked from commit 2103a2156119b30f5924af2a1094227954be4617)
+---
+ drivers/clk/bcm/clk-bcm2835.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -88,10 +88,23 @@
+ #define CM_HSMDIV 0x08c
+ #define CM_OTPCTL 0x090
+ #define CM_OTPDIV 0x094
++#define CM_PCMCTL 0x098
++#define CM_PCMDIV 0x09c
+ #define CM_PWMCTL 0x0a0
+ #define CM_PWMDIV 0x0a4
++#define CM_SLIMCTL 0x0a8
++#define CM_SLIMDIV 0x0ac
+ #define CM_SMICTL 0x0b0
+ #define CM_SMIDIV 0x0b4
++/* no definition for 0x0b8 and 0x0bc */
++#define CM_TCNTCTL 0x0c0
++#define CM_TCNTDIV 0x0c4
++#define CM_TECCTL 0x0c8
++#define CM_TECDIV 0x0cc
++#define CM_TD0CTL 0x0d0
++#define CM_TD0DIV 0x0d4
++#define CM_TD1CTL 0x0d8
++#define CM_TD1DIV 0x0dc
+ #define CM_TSENSCTL 0x0e0
+ #define CM_TSENSDIV 0x0e4
+ #define CM_TIMERCTL 0x0e8
diff --git a/target/linux/brcm2708/patches-4.4/0258-clk-bcm2835-correctly-enable-fractional-clock-suppor.patch b/target/linux/brcm2708/patches-4.4/0258-clk-bcm2835-correctly-enable-fractional-clock-suppor.patch
new file mode 100644
index 0000000000..73cf8d3abd
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0258-clk-bcm2835-correctly-enable-fractional-clock-suppor.patch
@@ -0,0 +1,134 @@
+From 926cfaabf67bd4a1d2b7e0153e56805066b5c8c5 Mon Sep 17 00:00:00 2001
+From: Martin Sperl <kernel@martin.sperl.org>
+Date: Mon, 29 Feb 2016 11:39:21 +0000
+Subject: [PATCH 258/381] clk: bcm2835: correctly enable fractional clock
+ support
+
+The current driver calculates the clock divider with
+fractional support enabled.
+
+But it does not enable fractional support in the
+control register itself resulting in an integer only divider,
+but in clk_set_rate responds back the fractionally divided
+clock frequency.
+
+This patch enables fractional support in the control register
+whenever there is a fractional bit set in the requested clock divider.
+
+Mash clock limits are are also handled for the PWM clock
+applying the correct divider limits (2 and max_int) applicable to
+basic fractional divider support (mash order of 1).
+
+It also adds locking to protect the read/modify/write cycle of
+the register modification.
+
+Fixes: 41691b8862e2 ("clk: bcm2835: Add support for programming the
+audio domain clocks")
+
+Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Reviewed-by: Eric Anholt <eric@anholt.net>
+(cherry picked from commit 959ca92a3235fc4b17c1e18483fc390b3d612254)
+---
+ drivers/clk/bcm/clk-bcm2835.c | 45 +++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 39 insertions(+), 6 deletions(-)
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -51,6 +51,7 @@
+ #define CM_GNRICCTL 0x000
+ #define CM_GNRICDIV 0x004
+ # define CM_DIV_FRAC_BITS 12
++# define CM_DIV_FRAC_MASK GENMASK(CM_DIV_FRAC_BITS - 1, 0)
+
+ #define CM_VPUCTL 0x008
+ #define CM_VPUDIV 0x00c
+@@ -128,6 +129,7 @@
+ # define CM_GATE BIT(CM_GATE_BIT)
+ # define CM_BUSY BIT(7)
+ # define CM_BUSYD BIT(8)
++# define CM_FRAC BIT(9)
+ # define CM_SRC_SHIFT 0
+ # define CM_SRC_BITS 4
+ # define CM_SRC_MASK 0xf
+@@ -647,6 +649,7 @@ struct bcm2835_clock_data {
+ u32 frac_bits;
+
+ bool is_vpu_clock;
++ bool is_mash_clock;
+ };
+
+ static const char *const bcm2835_clock_per_parents[] = {
+@@ -828,6 +831,7 @@ static const struct bcm2835_clock_data b
+ .div_reg = CM_PWMDIV,
+ .int_bits = 12,
+ .frac_bits = 12,
++ .is_mash_clock = true,
+ };
+
+ struct bcm2835_pll {
+@@ -1196,7 +1200,7 @@ static u32 bcm2835_clock_choose_div(stru
+ GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0) >> 1;
+ u64 temp = (u64)parent_rate << CM_DIV_FRAC_BITS;
+ u64 rem;
+- u32 div;
++ u32 div, mindiv, maxdiv;
+
+ rem = do_div(temp, rate);
+ div = temp;
+@@ -1206,11 +1210,23 @@ static u32 bcm2835_clock_choose_div(stru
+ div += unused_frac_mask + 1;
+ div &= ~unused_frac_mask;
+
+- /* clamp to min divider of 1 */
+- div = max_t(u32, div, 1 << CM_DIV_FRAC_BITS);
+- /* clamp to the highest possible fractional divider */
+- div = min_t(u32, div, GENMASK(data->int_bits + CM_DIV_FRAC_BITS - 1,
+- CM_DIV_FRAC_BITS - data->frac_bits));
++ /* different clamping limits apply for a mash clock */
++ if (data->is_mash_clock) {
++ /* clamp to min divider of 2 */
++ mindiv = 2 << CM_DIV_FRAC_BITS;
++ /* clamp to the highest possible integer divider */
++ maxdiv = (BIT(data->int_bits) - 1) << CM_DIV_FRAC_BITS;
++ } else {
++ /* clamp to min divider of 1 */
++ mindiv = 1 << CM_DIV_FRAC_BITS;
++ /* clamp to the highest possible fractional divider */
++ maxdiv = GENMASK(data->int_bits + CM_DIV_FRAC_BITS - 1,
++ CM_DIV_FRAC_BITS - data->frac_bits);
++ }
++
++ /* apply the clamping limits */
++ div = max_t(u32, div, mindiv);
++ div = min_t(u32, div, maxdiv);
+
+ return div;
+ }
+@@ -1304,9 +1320,26 @@ static int bcm2835_clock_set_rate(struct
+ struct bcm2835_cprman *cprman = clock->cprman;
+ const struct bcm2835_clock_data *data = clock->data;
+ u32 div = bcm2835_clock_choose_div(hw, rate, parent_rate, false);
++ u32 ctl;
++
++ spin_lock(&cprman->regs_lock);
++
++ /*
++ * Setting up frac support
++ *
++ * In principle it is recommended to stop/start the clock first,
++ * but as we set CLK_SET_RATE_GATE during registration of the
++ * clock this requirement should be take care of by the
++ * clk-framework.
++ */
++ ctl = cprman_read(cprman, data->ctl_reg) & ~CM_FRAC;
++ ctl |= (div & CM_DIV_FRAC_MASK) ? CM_FRAC : 0;
++ cprman_write(cprman, data->ctl_reg, ctl);
+
+ cprman_write(cprman, data->div_reg, div);
+
++ spin_unlock(&cprman->regs_lock);
++
+ return 0;
+ }
+
diff --git a/target/linux/brcm2708/patches-4.4/0259-clk-bcm2835-clean-up-coding-style-issues.patch b/target/linux/brcm2708/patches-4.4/0259-clk-bcm2835-clean-up-coding-style-issues.patch
new file mode 100644
index 0000000000..b9d6af5b28
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0259-clk-bcm2835-clean-up-coding-style-issues.patch
@@ -0,0 +1,52 @@
+From 97799edbda33efb8ebb20785bc7ad76c1b8a0aa9 Mon Sep 17 00:00:00 2001
+From: Martin Sperl <kernel@martin.sperl.org>
+Date: Mon, 29 Feb 2016 11:39:22 +0000
+Subject: [PATCH 259/381] clk: bcm2835: clean up coding style issues
+
+Fix all the checkpatch complaints for clk-bcm2835.c
+
+Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
+Signed-off-by: Eric Anholt <eric@anholt.net>
+(cherry picked from commit 6e1e60dacee7b32aef1468ea461b02e4c7a90a45)
+---
+ drivers/clk/bcm/clk-bcm2835.c | 8 ++------
+ 1 file changed, 2 insertions(+), 6 deletions(-)
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -12,9 +12,6 @@
+ * 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
+ */
+
+ /**
+@@ -299,7 +296,7 @@
+ struct bcm2835_cprman {
+ struct device *dev;
+ void __iomem *regs;
+- spinlock_t regs_lock;
++ spinlock_t regs_lock; /* spinlock for all clocks */
+ const char *osc_name;
+
+ struct clk_onecell_data onecell;
+@@ -1344,7 +1341,7 @@ static int bcm2835_clock_set_rate(struct
+ }
+
+ static int bcm2835_clock_determine_rate(struct clk_hw *hw,
+- struct clk_rate_request *req)
++ struct clk_rate_request *req)
+ {
+ struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+ struct clk_hw *parent, *best_parent = NULL;
+@@ -1402,7 +1399,6 @@ static u8 bcm2835_clock_get_parent(struc
+ return (src & CM_SRC_MASK) >> CM_SRC_SHIFT;
+ }
+
+-
+ static const struct clk_ops bcm2835_clock_clk_ops = {
+ .is_prepared = bcm2835_clock_is_on,
+ .prepare = bcm2835_clock_on,
diff --git a/target/linux/brcm2708/patches-4.4/0260-clk-bcm2835-expose-raw-clock-registers-via-debugfs.patch b/target/linux/brcm2708/patches-4.4/0260-clk-bcm2835-expose-raw-clock-registers-via-debugfs.patch
new file mode 100644
index 0000000000..8d301eac80
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0260-clk-bcm2835-expose-raw-clock-registers-via-debugfs.patch
@@ -0,0 +1,188 @@
+From d1f7529b457f1f1ff248e632ee8218b5d442baa0 Mon Sep 17 00:00:00 2001
+From: Martin Sperl <kernel@martin.sperl.org>
+Date: Mon, 29 Feb 2016 14:20:15 +0000
+Subject: [PATCH 260/381] clk: bcm2835: expose raw clock-registers via debugfs
+
+For debugging purposes under some circumstance
+it helps to be able to see the actual clock registers.
+
+E.g: when looking at the clock divider it is helpful to
+see what the actual clock divider is.
+
+This patch exposes all the clock registers specific to each
+clock/pll/pll-divider via debugfs.
+
+Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Acked-by: Eric Anholt <eric@anholt.net>
+(cherry picked from commit 96bf9c69d5729781018a00f08e2ae395ec3346b4)
+---
+ drivers/clk/bcm/clk-bcm2835.c | 101 ++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 101 insertions(+)
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -37,6 +37,7 @@
+ #include <linux/clk-provider.h>
+ #include <linux/clkdev.h>
+ #include <linux/clk/bcm2835.h>
++#include <linux/debugfs.h>
+ #include <linux/module.h>
+ #include <linux/of.h>
+ #include <linux/platform_device.h>
+@@ -313,6 +314,27 @@ static inline u32 cprman_read(struct bcm
+ return readl(cprman->regs + reg);
+ }
+
++static int bcm2835_debugfs_regset(struct bcm2835_cprman *cprman, u32 base,
++ struct debugfs_reg32 *regs, size_t nregs,
++ struct dentry *dentry)
++{
++ struct dentry *regdump;
++ struct debugfs_regset32 *regset;
++
++ regset = devm_kzalloc(cprman->dev, sizeof(*regset), GFP_KERNEL);
++ if (!regset)
++ return -ENOMEM;
++
++ regset->regs = regs;
++ regset->nregs = nregs;
++ regset->base = cprman->regs + base;
++
++ regdump = debugfs_create_regset32("regdump", S_IRUGO, dentry,
++ regset);
++
++ return regdump ? 0 : -ENOMEM;
++}
++
+ /*
+ * These are fixed clocks. They're probably not all root clocks and it may
+ * be possible to turn them on and off but until this is mapped out better
+@@ -1044,6 +1066,36 @@ static int bcm2835_pll_set_rate(struct c
+ return 0;
+ }
+
++static int bcm2835_pll_debug_init(struct clk_hw *hw,
++ struct dentry *dentry)
++{
++ struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw);
++ struct bcm2835_cprman *cprman = pll->cprman;
++ const struct bcm2835_pll_data *data = pll->data;
++ struct debugfs_reg32 *regs;
++
++ regs = devm_kzalloc(cprman->dev, 7 * sizeof(*regs), GFP_KERNEL);
++ if (!regs)
++ return -ENOMEM;
++
++ regs[0].name = "cm_ctrl";
++ regs[0].offset = data->cm_ctrl_reg;
++ regs[1].name = "a2w_ctrl";
++ regs[1].offset = data->a2w_ctrl_reg;
++ regs[2].name = "frac";
++ regs[2].offset = data->frac_reg;
++ regs[3].name = "ana0";
++ regs[3].offset = data->ana_reg_base + 0 * 4;
++ regs[4].name = "ana1";
++ regs[4].offset = data->ana_reg_base + 1 * 4;
++ regs[5].name = "ana2";
++ regs[5].offset = data->ana_reg_base + 2 * 4;
++ regs[6].name = "ana3";
++ regs[6].offset = data->ana_reg_base + 3 * 4;
++
++ return bcm2835_debugfs_regset(cprman, 0, regs, 7, dentry);
++}
++
+ static const struct clk_ops bcm2835_pll_clk_ops = {
+ .is_prepared = bcm2835_pll_is_on,
+ .prepare = bcm2835_pll_on,
+@@ -1051,6 +1103,7 @@ static const struct clk_ops bcm2835_pll_
+ .recalc_rate = bcm2835_pll_get_rate,
+ .set_rate = bcm2835_pll_set_rate,
+ .round_rate = bcm2835_pll_round_rate,
++ .debug_init = bcm2835_pll_debug_init,
+ };
+
+ struct bcm2835_pll_divider {
+@@ -1151,6 +1204,26 @@ static int bcm2835_pll_divider_set_rate(
+ return 0;
+ }
+
++static int bcm2835_pll_divider_debug_init(struct clk_hw *hw,
++ struct dentry *dentry)
++{
++ struct bcm2835_pll_divider *divider = bcm2835_pll_divider_from_hw(hw);
++ struct bcm2835_cprman *cprman = divider->cprman;
++ const struct bcm2835_pll_divider_data *data = divider->data;
++ struct debugfs_reg32 *regs;
++
++ regs = devm_kzalloc(cprman->dev, 7 * sizeof(*regs), GFP_KERNEL);
++ if (!regs)
++ return -ENOMEM;
++
++ regs[0].name = "cm";
++ regs[0].offset = data->cm_reg;
++ regs[1].name = "a2w";
++ regs[1].offset = data->a2w_reg;
++
++ return bcm2835_debugfs_regset(cprman, 0, regs, 2, dentry);
++}
++
+ static const struct clk_ops bcm2835_pll_divider_clk_ops = {
+ .is_prepared = bcm2835_pll_divider_is_on,
+ .prepare = bcm2835_pll_divider_on,
+@@ -1158,6 +1231,7 @@ static const struct clk_ops bcm2835_pll_
+ .recalc_rate = bcm2835_pll_divider_get_rate,
+ .set_rate = bcm2835_pll_divider_set_rate,
+ .round_rate = bcm2835_pll_divider_round_rate,
++ .debug_init = bcm2835_pll_divider_debug_init,
+ };
+
+ /*
+@@ -1399,6 +1473,31 @@ static u8 bcm2835_clock_get_parent(struc
+ return (src & CM_SRC_MASK) >> CM_SRC_SHIFT;
+ }
+
++static struct debugfs_reg32 bcm2835_debugfs_clock_reg32[] = {
++ {
++ .name = "ctl",
++ .offset = 0,
++ },
++ {
++ .name = "div",
++ .offset = 4,
++ },
++};
++
++static int bcm2835_clock_debug_init(struct clk_hw *hw,
++ struct dentry *dentry)
++{
++ struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
++ struct bcm2835_cprman *cprman = clock->cprman;
++ const struct bcm2835_clock_data *data = clock->data;
++
++ return bcm2835_debugfs_regset(
++ cprman, data->ctl_reg,
++ bcm2835_debugfs_clock_reg32,
++ ARRAY_SIZE(bcm2835_debugfs_clock_reg32),
++ dentry);
++}
++
+ static const struct clk_ops bcm2835_clock_clk_ops = {
+ .is_prepared = bcm2835_clock_is_on,
+ .prepare = bcm2835_clock_on,
+@@ -1408,6 +1507,7 @@ static const struct clk_ops bcm2835_cloc
+ .determine_rate = bcm2835_clock_determine_rate,
+ .set_parent = bcm2835_clock_set_parent,
+ .get_parent = bcm2835_clock_get_parent,
++ .debug_init = bcm2835_clock_debug_init,
+ };
+
+ static int bcm2835_vpu_clock_is_on(struct clk_hw *hw)
+@@ -1426,6 +1526,7 @@ static const struct clk_ops bcm2835_vpu_
+ .determine_rate = bcm2835_clock_determine_rate,
+ .set_parent = bcm2835_clock_set_parent,
+ .get_parent = bcm2835_clock_get_parent,
++ .debug_init = bcm2835_clock_debug_init,
+ };
+
+ static struct clk *bcm2835_register_pll(struct bcm2835_cprman *cprman,
diff --git a/target/linux/brcm2708/patches-4.4/0261-clk-bcm2835-remove-use-of-BCM2835_CLOCK_COUNT-in-dri.patch b/target/linux/brcm2708/patches-4.4/0261-clk-bcm2835-remove-use-of-BCM2835_CLOCK_COUNT-in-dri.patch
new file mode 100644
index 0000000000..0c338ce4a8
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0261-clk-bcm2835-remove-use-of-BCM2835_CLOCK_COUNT-in-dri.patch
@@ -0,0 +1,237 @@
+From 4af3eff3ca4b361018749b00b71426fa23cc58a4 Mon Sep 17 00:00:00 2001
+From: Martin Sperl <kernel@martin.sperl.org>
+Date: Mon, 29 Feb 2016 12:51:41 +0000
+Subject: [PATCH 261/381] clk: bcm2835: remove use of BCM2835_CLOCK_COUNT in
+ driver
+
+As the use of BCM2835_CLOCK_COUNT in
+include/dt-bindings/clock/bcm2835.h is frowned upon as
+it needs to get modified every time a new clock gets introduced
+this patch changes the clk-bcm2835 driver to use a different
+scheme for registration of clocks and pll, so that there
+is no more need for BCM2835_CLOCK_COUNT to be defined.
+
+Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Reviewed-by: Eric Anholt <eric@anholt.net>
+(cherry picked from commit 56eb3a2ed9726961e1bcfa69d4a3f86d68f0eb52)
+---
+ drivers/clk/bcm/clk-bcm2835.c | 167 ++++++++++++++++++++----------------
+ include/dt-bindings/clock/bcm2835.h | 2 -
+ 2 files changed, 94 insertions(+), 75 deletions(-)
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -301,7 +301,7 @@ struct bcm2835_cprman {
+ const char *osc_name;
+
+ struct clk_onecell_data onecell;
+- struct clk *clks[BCM2835_CLOCK_COUNT];
++ struct clk *clks[];
+ };
+
+ static inline void cprman_write(struct bcm2835_cprman *cprman, u32 reg, u32 val)
+@@ -853,6 +853,25 @@ static const struct bcm2835_clock_data b
+ .is_mash_clock = true,
+ };
+
++struct bcm2835_gate_data {
++ const char *name;
++ const char *parent;
++
++ u32 ctl_reg;
++};
++
++/*
++ * CM_PERIICTL (and CM_PERIACTL, CM_SYSCTL and CM_VPUCTL if
++ * you have the debug bit set in the power manager, which we
++ * don't bother exposing) are individual gates off of the
++ * non-stop vpu clock.
++ */
++static const struct bcm2835_gate_data bcm2835_clock_peri_image_data = {
++ .name = "peri_image",
++ .parent = "vpu",
++ .ctl_reg = CM_PERIICTL,
++};
++
+ struct bcm2835_pll {
+ struct clk_hw hw;
+ struct bcm2835_cprman *cprman;
+@@ -1658,14 +1677,81 @@ static struct clk *bcm2835_register_cloc
+ return devm_clk_register(cprman->dev, &clock->hw);
+ }
+
++static struct clk *bcm2835_register_gate(struct bcm2835_cprman *cprman,
++ const struct bcm2835_gate_data *data)
++{
++ return clk_register_gate(cprman->dev, data->name, data->parent,
++ CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE,
++ cprman->regs + data->ctl_reg,
++ CM_GATE_BIT, 0, &cprman->regs_lock);
++}
++
++typedef struct clk *(*bcm2835_clk_register)(struct bcm2835_cprman *cprman,
++ const void *data);
++struct bcm2835_clk_desc {
++ bcm2835_clk_register clk_register;
++ const void *data;
++};
++
++#define _REGISTER(f, d) { .clk_register = (bcm2835_clk_register)f, \
++ .data = d }
++#define REGISTER_PLL(d) _REGISTER(&bcm2835_register_pll, d)
++#define REGISTER_PLL_DIV(d) _REGISTER(&bcm2835_register_pll_divider, d)
++#define REGISTER_CLK(d) _REGISTER(&bcm2835_register_clock, d)
++#define REGISTER_GATE(d) _REGISTER(&bcm2835_register_gate, d)
++
++static const struct bcm2835_clk_desc clk_desc_array[] = {
++ /* register PLL */
++ [BCM2835_PLLA] = REGISTER_PLL(&bcm2835_plla_data),
++ [BCM2835_PLLB] = REGISTER_PLL(&bcm2835_pllb_data),
++ [BCM2835_PLLC] = REGISTER_PLL(&bcm2835_pllc_data),
++ [BCM2835_PLLD] = REGISTER_PLL(&bcm2835_plld_data),
++ [BCM2835_PLLH] = REGISTER_PLL(&bcm2835_pllh_data),
++ /* the PLL dividers */
++ [BCM2835_PLLA_CORE] = REGISTER_PLL_DIV(&bcm2835_plla_core_data),
++ [BCM2835_PLLA_PER] = REGISTER_PLL_DIV(&bcm2835_plla_per_data),
++ [BCM2835_PLLC_CORE0] = REGISTER_PLL_DIV(&bcm2835_pllc_core0_data),
++ [BCM2835_PLLC_CORE1] = REGISTER_PLL_DIV(&bcm2835_pllc_core1_data),
++ [BCM2835_PLLC_CORE2] = REGISTER_PLL_DIV(&bcm2835_pllc_core2_data),
++ [BCM2835_PLLC_PER] = REGISTER_PLL_DIV(&bcm2835_pllc_per_data),
++ [BCM2835_PLLD_CORE] = REGISTER_PLL_DIV(&bcm2835_plld_core_data),
++ [BCM2835_PLLD_PER] = REGISTER_PLL_DIV(&bcm2835_plld_per_data),
++ [BCM2835_PLLH_RCAL] = REGISTER_PLL_DIV(&bcm2835_pllh_rcal_data),
++ [BCM2835_PLLH_AUX] = REGISTER_PLL_DIV(&bcm2835_pllh_aux_data),
++ [BCM2835_PLLH_PIX] = REGISTER_PLL_DIV(&bcm2835_pllh_pix_data),
++ /* the clocks */
++ [BCM2835_CLOCK_TIMER] = REGISTER_CLK(&bcm2835_clock_timer_data),
++ [BCM2835_CLOCK_OTP] = REGISTER_CLK(&bcm2835_clock_otp_data),
++ [BCM2835_CLOCK_TSENS] = REGISTER_CLK(&bcm2835_clock_tsens_data),
++ [BCM2835_CLOCK_VPU] = REGISTER_CLK(&bcm2835_clock_vpu_data),
++ [BCM2835_CLOCK_V3D] = REGISTER_CLK(&bcm2835_clock_v3d_data),
++ [BCM2835_CLOCK_ISP] = REGISTER_CLK(&bcm2835_clock_isp_data),
++ [BCM2835_CLOCK_H264] = REGISTER_CLK(&bcm2835_clock_h264_data),
++ [BCM2835_CLOCK_V3D] = REGISTER_CLK(&bcm2835_clock_v3d_data),
++ [BCM2835_CLOCK_SDRAM] = REGISTER_CLK(&bcm2835_clock_sdram_data),
++ [BCM2835_CLOCK_UART] = REGISTER_CLK(&bcm2835_clock_uart_data),
++ [BCM2835_CLOCK_VEC] = REGISTER_CLK(&bcm2835_clock_vec_data),
++ [BCM2835_CLOCK_HSM] = REGISTER_CLK(&bcm2835_clock_hsm_data),
++ [BCM2835_CLOCK_EMMC] = REGISTER_CLK(&bcm2835_clock_emmc_data),
++ [BCM2835_CLOCK_PWM] = REGISTER_CLK(&bcm2835_clock_pwm_data),
++ /* the gates */
++ [BCM2835_CLOCK_PERI_IMAGE] = REGISTER_GATE(
++ &bcm2835_clock_peri_image_data),
++};
++
+ static int bcm2835_clk_probe(struct platform_device *pdev)
+ {
+ struct device *dev = &pdev->dev;
+ struct clk **clks;
+ struct bcm2835_cprman *cprman;
+ struct resource *res;
++ const struct bcm2835_clk_desc *desc;
++ const size_t asize = ARRAY_SIZE(clk_desc_array);
++ size_t i;
+
+- cprman = devm_kzalloc(dev, sizeof(*cprman), GFP_KERNEL);
++ cprman = devm_kzalloc(dev,
++ sizeof(*cprman) + asize * sizeof(*clks),
++ GFP_KERNEL);
+ if (!cprman)
+ return -ENOMEM;
+
+@@ -1682,80 +1768,15 @@ static int bcm2835_clk_probe(struct plat
+
+ platform_set_drvdata(pdev, cprman);
+
+- cprman->onecell.clk_num = BCM2835_CLOCK_COUNT;
++ cprman->onecell.clk_num = asize;
+ cprman->onecell.clks = cprman->clks;
+ clks = cprman->clks;
+
+- clks[BCM2835_PLLA] = bcm2835_register_pll(cprman, &bcm2835_plla_data);
+- clks[BCM2835_PLLB] = bcm2835_register_pll(cprman, &bcm2835_pllb_data);
+- clks[BCM2835_PLLC] = bcm2835_register_pll(cprman, &bcm2835_pllc_data);
+- clks[BCM2835_PLLD] = bcm2835_register_pll(cprman, &bcm2835_plld_data);
+- clks[BCM2835_PLLH] = bcm2835_register_pll(cprman, &bcm2835_pllh_data);
+-
+- clks[BCM2835_PLLA_CORE] =
+- bcm2835_register_pll_divider(cprman, &bcm2835_plla_core_data);
+- clks[BCM2835_PLLA_PER] =
+- bcm2835_register_pll_divider(cprman, &bcm2835_plla_per_data);
+- clks[BCM2835_PLLC_CORE0] =
+- bcm2835_register_pll_divider(cprman, &bcm2835_pllc_core0_data);
+- clks[BCM2835_PLLC_CORE1] =
+- bcm2835_register_pll_divider(cprman, &bcm2835_pllc_core1_data);
+- clks[BCM2835_PLLC_CORE2] =
+- bcm2835_register_pll_divider(cprman, &bcm2835_pllc_core2_data);
+- clks[BCM2835_PLLC_PER] =
+- bcm2835_register_pll_divider(cprman, &bcm2835_pllc_per_data);
+- clks[BCM2835_PLLD_CORE] =
+- bcm2835_register_pll_divider(cprman, &bcm2835_plld_core_data);
+- clks[BCM2835_PLLD_PER] =
+- bcm2835_register_pll_divider(cprman, &bcm2835_plld_per_data);
+- clks[BCM2835_PLLH_RCAL] =
+- bcm2835_register_pll_divider(cprman, &bcm2835_pllh_rcal_data);
+- clks[BCM2835_PLLH_AUX] =
+- bcm2835_register_pll_divider(cprman, &bcm2835_pllh_aux_data);
+- clks[BCM2835_PLLH_PIX] =
+- bcm2835_register_pll_divider(cprman, &bcm2835_pllh_pix_data);
+-
+- clks[BCM2835_CLOCK_TIMER] =
+- bcm2835_register_clock(cprman, &bcm2835_clock_timer_data);
+- clks[BCM2835_CLOCK_OTP] =
+- bcm2835_register_clock(cprman, &bcm2835_clock_otp_data);
+- clks[BCM2835_CLOCK_TSENS] =
+- bcm2835_register_clock(cprman, &bcm2835_clock_tsens_data);
+- clks[BCM2835_CLOCK_VPU] =
+- bcm2835_register_clock(cprman, &bcm2835_clock_vpu_data);
+- clks[BCM2835_CLOCK_V3D] =
+- bcm2835_register_clock(cprman, &bcm2835_clock_v3d_data);
+- clks[BCM2835_CLOCK_ISP] =
+- bcm2835_register_clock(cprman, &bcm2835_clock_isp_data);
+- clks[BCM2835_CLOCK_H264] =
+- bcm2835_register_clock(cprman, &bcm2835_clock_h264_data);
+- clks[BCM2835_CLOCK_V3D] =
+- bcm2835_register_clock(cprman, &bcm2835_clock_v3d_data);
+- clks[BCM2835_CLOCK_SDRAM] =
+- bcm2835_register_clock(cprman, &bcm2835_clock_sdram_data);
+- clks[BCM2835_CLOCK_UART] =
+- bcm2835_register_clock(cprman, &bcm2835_clock_uart_data);
+- clks[BCM2835_CLOCK_VEC] =
+- bcm2835_register_clock(cprman, &bcm2835_clock_vec_data);
+- clks[BCM2835_CLOCK_HSM] =
+- bcm2835_register_clock(cprman, &bcm2835_clock_hsm_data);
+- clks[BCM2835_CLOCK_EMMC] =
+- bcm2835_register_clock(cprman, &bcm2835_clock_emmc_data);
+-
+- /*
+- * CM_PERIICTL (and CM_PERIACTL, CM_SYSCTL and CM_VPUCTL if
+- * you have the debug bit set in the power manager, which we
+- * don't bother exposing) are individual gates off of the
+- * non-stop vpu clock.
+- */
+- clks[BCM2835_CLOCK_PERI_IMAGE] =
+- clk_register_gate(dev, "peri_image", "vpu",
+- CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE,
+- cprman->regs + CM_PERIICTL, CM_GATE_BIT,
+- 0, &cprman->regs_lock);
+-
+- clks[BCM2835_CLOCK_PWM] =
+- bcm2835_register_clock(cprman, &bcm2835_clock_pwm_data);
++ for (i = 0; i < asize; i++) {
++ desc = &clk_desc_array[i];
++ if (desc->clk_register && desc->data)
++ clks[i] = desc->clk_register(cprman, desc->data);
++ }
+
+ return of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
+ &cprman->onecell);
+--- a/include/dt-bindings/clock/bcm2835.h
++++ b/include/dt-bindings/clock/bcm2835.h
+@@ -44,5 +44,3 @@
+ #define BCM2835_CLOCK_EMMC 28
+ #define BCM2835_CLOCK_PERI_IMAGE 29
+ #define BCM2835_CLOCK_PWM 30
+-
+-#define BCM2835_CLOCK_COUNT 31
diff --git a/target/linux/brcm2708/patches-4.4/0262-clk-bcm2835-reorganize-bcm2835_clock_array-assignmen.patch b/target/linux/brcm2708/patches-4.4/0262-clk-bcm2835-reorganize-bcm2835_clock_array-assignmen.patch
new file mode 100644
index 0000000000..b1b574ceaf
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0262-clk-bcm2835-reorganize-bcm2835_clock_array-assignmen.patch
@@ -0,0 +1,926 @@
+From 34db3e8f383a79ea01a1fee31270e779956ec939 Mon Sep 17 00:00:00 2001
+From: Martin Sperl <kernel@martin.sperl.org>
+Date: Mon, 29 Feb 2016 12:51:42 +0000
+Subject: [PATCH 262/381] clk: bcm2835: reorganize bcm2835_clock_array
+ assignment
+
+Reorganize bcm2835_clock_array so that there is no more
+need for separate bcm2835_*_data structures to be defined.
+Instead the required structures are generated inline via
+helper macros.
+
+To allow this to also work for pll alone it was required that
+the parent_pll was changed from a pointer to bcm2835_pll_data
+to the name of the pll instead.
+
+Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Reviewed-by: Eric Anholt <eric@anholt.net>
+(cherry picked from commit 3b15afefbef9b5952e3d68ad73d93f981b9faca8)
+---
+ drivers/clk/bcm/clk-bcm2835.c | 852 +++++++++++++++++++-----------------------
+ 1 file changed, 393 insertions(+), 459 deletions(-)
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -418,115 +418,10 @@ static const struct bcm2835_pll_ana_bits
+ .fb_prediv_mask = BIT(11),
+ };
+
+-/*
+- * PLLA is the auxiliary PLL, used to drive the CCP2 (Compact Camera
+- * Port 2) transmitter clock.
+- *
+- * It is in the PX LDO power domain, which is on when the AUDIO domain
+- * is on.
+- */
+-static const struct bcm2835_pll_data bcm2835_plla_data = {
+- .name = "plla",
+- .cm_ctrl_reg = CM_PLLA,
+- .a2w_ctrl_reg = A2W_PLLA_CTRL,
+- .frac_reg = A2W_PLLA_FRAC,
+- .ana_reg_base = A2W_PLLA_ANA0,
+- .reference_enable_mask = A2W_XOSC_CTRL_PLLA_ENABLE,
+- .lock_mask = CM_LOCK_FLOCKA,
+-
+- .ana = &bcm2835_ana_default,
+-
+- .min_rate = 600000000u,
+- .max_rate = 2400000000u,
+- .max_fb_rate = BCM2835_MAX_FB_RATE,
+-};
+-
+-/* PLLB is used for the ARM's clock. */
+-static const struct bcm2835_pll_data bcm2835_pllb_data = {
+- .name = "pllb",
+- .cm_ctrl_reg = CM_PLLB,
+- .a2w_ctrl_reg = A2W_PLLB_CTRL,
+- .frac_reg = A2W_PLLB_FRAC,
+- .ana_reg_base = A2W_PLLB_ANA0,
+- .reference_enable_mask = A2W_XOSC_CTRL_PLLB_ENABLE,
+- .lock_mask = CM_LOCK_FLOCKB,
+-
+- .ana = &bcm2835_ana_default,
+-
+- .min_rate = 600000000u,
+- .max_rate = 3000000000u,
+- .max_fb_rate = BCM2835_MAX_FB_RATE,
+-};
+-
+-/*
+- * PLLC is the core PLL, used to drive the core VPU clock.
+- *
+- * It is in the PX LDO power domain, which is on when the AUDIO domain
+- * is on.
+-*/
+-static const struct bcm2835_pll_data bcm2835_pllc_data = {
+- .name = "pllc",
+- .cm_ctrl_reg = CM_PLLC,
+- .a2w_ctrl_reg = A2W_PLLC_CTRL,
+- .frac_reg = A2W_PLLC_FRAC,
+- .ana_reg_base = A2W_PLLC_ANA0,
+- .reference_enable_mask = A2W_XOSC_CTRL_PLLC_ENABLE,
+- .lock_mask = CM_LOCK_FLOCKC,
+-
+- .ana = &bcm2835_ana_default,
+-
+- .min_rate = 600000000u,
+- .max_rate = 3000000000u,
+- .max_fb_rate = BCM2835_MAX_FB_RATE,
+-};
+-
+-/*
+- * PLLD is the display PLL, used to drive DSI display panels.
+- *
+- * It is in the PX LDO power domain, which is on when the AUDIO domain
+- * is on.
+- */
+-static const struct bcm2835_pll_data bcm2835_plld_data = {
+- .name = "plld",
+- .cm_ctrl_reg = CM_PLLD,
+- .a2w_ctrl_reg = A2W_PLLD_CTRL,
+- .frac_reg = A2W_PLLD_FRAC,
+- .ana_reg_base = A2W_PLLD_ANA0,
+- .reference_enable_mask = A2W_XOSC_CTRL_DDR_ENABLE,
+- .lock_mask = CM_LOCK_FLOCKD,
+-
+- .ana = &bcm2835_ana_default,
+-
+- .min_rate = 600000000u,
+- .max_rate = 2400000000u,
+- .max_fb_rate = BCM2835_MAX_FB_RATE,
+-};
+-
+-/*
+- * PLLH is used to supply the pixel clock or the AUX clock for the TV
+- * encoder.
+- *
+- * It is in the HDMI power domain.
+- */
+-static const struct bcm2835_pll_data bcm2835_pllh_data = {
+- "pllh",
+- .cm_ctrl_reg = CM_PLLH,
+- .a2w_ctrl_reg = A2W_PLLH_CTRL,
+- .frac_reg = A2W_PLLH_FRAC,
+- .ana_reg_base = A2W_PLLH_ANA0,
+- .reference_enable_mask = A2W_XOSC_CTRL_PLLC_ENABLE,
+- .lock_mask = CM_LOCK_FLOCKH,
+-
+- .ana = &bcm2835_ana_pllh,
+-
+- .min_rate = 600000000u,
+- .max_rate = 3000000000u,
+- .max_fb_rate = BCM2835_MAX_FB_RATE,
+-};
+-
+ struct bcm2835_pll_divider_data {
+ const char *name;
+- const struct bcm2835_pll_data *source_pll;
++ const char *source_pll;
++
+ u32 cm_reg;
+ u32 a2w_reg;
+
+@@ -535,124 +430,6 @@ struct bcm2835_pll_divider_data {
+ u32 fixed_divider;
+ };
+
+-static const struct bcm2835_pll_divider_data bcm2835_plla_core_data = {
+- .name = "plla_core",
+- .source_pll = &bcm2835_plla_data,
+- .cm_reg = CM_PLLA,
+- .a2w_reg = A2W_PLLA_CORE,
+- .load_mask = CM_PLLA_LOADCORE,
+- .hold_mask = CM_PLLA_HOLDCORE,
+- .fixed_divider = 1,
+-};
+-
+-static const struct bcm2835_pll_divider_data bcm2835_plla_per_data = {
+- .name = "plla_per",
+- .source_pll = &bcm2835_plla_data,
+- .cm_reg = CM_PLLA,
+- .a2w_reg = A2W_PLLA_PER,
+- .load_mask = CM_PLLA_LOADPER,
+- .hold_mask = CM_PLLA_HOLDPER,
+- .fixed_divider = 1,
+-};
+-
+-static const struct bcm2835_pll_divider_data bcm2835_pllb_arm_data = {
+- .name = "pllb_arm",
+- .source_pll = &bcm2835_pllb_data,
+- .cm_reg = CM_PLLB,
+- .a2w_reg = A2W_PLLB_ARM,
+- .load_mask = CM_PLLB_LOADARM,
+- .hold_mask = CM_PLLB_HOLDARM,
+- .fixed_divider = 1,
+-};
+-
+-static const struct bcm2835_pll_divider_data bcm2835_pllc_core0_data = {
+- .name = "pllc_core0",
+- .source_pll = &bcm2835_pllc_data,
+- .cm_reg = CM_PLLC,
+- .a2w_reg = A2W_PLLC_CORE0,
+- .load_mask = CM_PLLC_LOADCORE0,
+- .hold_mask = CM_PLLC_HOLDCORE0,
+- .fixed_divider = 1,
+-};
+-
+-static const struct bcm2835_pll_divider_data bcm2835_pllc_core1_data = {
+- .name = "pllc_core1", .source_pll = &bcm2835_pllc_data,
+- .cm_reg = CM_PLLC, A2W_PLLC_CORE1,
+- .load_mask = CM_PLLC_LOADCORE1,
+- .hold_mask = CM_PLLC_HOLDCORE1,
+- .fixed_divider = 1,
+-};
+-
+-static const struct bcm2835_pll_divider_data bcm2835_pllc_core2_data = {
+- .name = "pllc_core2",
+- .source_pll = &bcm2835_pllc_data,
+- .cm_reg = CM_PLLC,
+- .a2w_reg = A2W_PLLC_CORE2,
+- .load_mask = CM_PLLC_LOADCORE2,
+- .hold_mask = CM_PLLC_HOLDCORE2,
+- .fixed_divider = 1,
+-};
+-
+-static const struct bcm2835_pll_divider_data bcm2835_pllc_per_data = {
+- .name = "pllc_per",
+- .source_pll = &bcm2835_pllc_data,
+- .cm_reg = CM_PLLC,
+- .a2w_reg = A2W_PLLC_PER,
+- .load_mask = CM_PLLC_LOADPER,
+- .hold_mask = CM_PLLC_HOLDPER,
+- .fixed_divider = 1,
+-};
+-
+-static const struct bcm2835_pll_divider_data bcm2835_plld_core_data = {
+- .name = "plld_core",
+- .source_pll = &bcm2835_plld_data,
+- .cm_reg = CM_PLLD,
+- .a2w_reg = A2W_PLLD_CORE,
+- .load_mask = CM_PLLD_LOADCORE,
+- .hold_mask = CM_PLLD_HOLDCORE,
+- .fixed_divider = 1,
+-};
+-
+-static const struct bcm2835_pll_divider_data bcm2835_plld_per_data = {
+- .name = "plld_per",
+- .source_pll = &bcm2835_plld_data,
+- .cm_reg = CM_PLLD,
+- .a2w_reg = A2W_PLLD_PER,
+- .load_mask = CM_PLLD_LOADPER,
+- .hold_mask = CM_PLLD_HOLDPER,
+- .fixed_divider = 1,
+-};
+-
+-static const struct bcm2835_pll_divider_data bcm2835_pllh_rcal_data = {
+- .name = "pllh_rcal",
+- .source_pll = &bcm2835_pllh_data,
+- .cm_reg = CM_PLLH,
+- .a2w_reg = A2W_PLLH_RCAL,
+- .load_mask = CM_PLLH_LOADRCAL,
+- .hold_mask = 0,
+- .fixed_divider = 10,
+-};
+-
+-static const struct bcm2835_pll_divider_data bcm2835_pllh_aux_data = {
+- .name = "pllh_aux",
+- .source_pll = &bcm2835_pllh_data,
+- .cm_reg = CM_PLLH,
+- .a2w_reg = A2W_PLLH_AUX,
+- .load_mask = CM_PLLH_LOADAUX,
+- .hold_mask = 0,
+- .fixed_divider = 10,
+-};
+-
+-static const struct bcm2835_pll_divider_data bcm2835_pllh_pix_data = {
+- .name = "pllh_pix",
+- .source_pll = &bcm2835_pllh_data,
+- .cm_reg = CM_PLLH,
+- .a2w_reg = A2W_PLLH_PIX,
+- .load_mask = CM_PLLH_LOADPIX,
+- .hold_mask = 0,
+- .fixed_divider = 10,
+-};
+-
+ struct bcm2835_clock_data {
+ const char *name;
+
+@@ -671,188 +448,6 @@ struct bcm2835_clock_data {
+ bool is_mash_clock;
+ };
+
+-static const char *const bcm2835_clock_per_parents[] = {
+- "gnd",
+- "xosc",
+- "testdebug0",
+- "testdebug1",
+- "plla_per",
+- "pllc_per",
+- "plld_per",
+- "pllh_aux",
+-};
+-
+-static const char *const bcm2835_clock_vpu_parents[] = {
+- "gnd",
+- "xosc",
+- "testdebug0",
+- "testdebug1",
+- "plla_core",
+- "pllc_core0",
+- "plld_core",
+- "pllh_aux",
+- "pllc_core1",
+- "pllc_core2",
+-};
+-
+-static const char *const bcm2835_clock_osc_parents[] = {
+- "gnd",
+- "xosc",
+- "testdebug0",
+- "testdebug1"
+-};
+-
+-/*
+- * Used for a 1Mhz clock for the system clocksource, and also used by
+- * the watchdog timer and the camera pulse generator.
+- */
+-static const struct bcm2835_clock_data bcm2835_clock_timer_data = {
+- .name = "timer",
+- .num_mux_parents = ARRAY_SIZE(bcm2835_clock_osc_parents),
+- .parents = bcm2835_clock_osc_parents,
+- .ctl_reg = CM_TIMERCTL,
+- .div_reg = CM_TIMERDIV,
+- .int_bits = 6,
+- .frac_bits = 12,
+-};
+-
+-/* One Time Programmable Memory clock. Maximum 10Mhz. */
+-static const struct bcm2835_clock_data bcm2835_clock_otp_data = {
+- .name = "otp",
+- .num_mux_parents = ARRAY_SIZE(bcm2835_clock_osc_parents),
+- .parents = bcm2835_clock_osc_parents,
+- .ctl_reg = CM_OTPCTL,
+- .div_reg = CM_OTPDIV,
+- .int_bits = 4,
+- .frac_bits = 0,
+-};
+-
+-/*
+- * VPU clock. This doesn't have an enable bit, since it drives the
+- * bus for everything else, and is special so it doesn't need to be
+- * gated for rate changes. It is also known as "clk_audio" in various
+- * hardware documentation.
+- */
+-static const struct bcm2835_clock_data bcm2835_clock_vpu_data = {
+- .name = "vpu",
+- .num_mux_parents = ARRAY_SIZE(bcm2835_clock_vpu_parents),
+- .parents = bcm2835_clock_vpu_parents,
+- .ctl_reg = CM_VPUCTL,
+- .div_reg = CM_VPUDIV,
+- .int_bits = 12,
+- .frac_bits = 8,
+- .is_vpu_clock = true,
+-};
+-
+-static const struct bcm2835_clock_data bcm2835_clock_v3d_data = {
+- .name = "v3d",
+- .num_mux_parents = ARRAY_SIZE(bcm2835_clock_vpu_parents),
+- .parents = bcm2835_clock_vpu_parents,
+- .ctl_reg = CM_V3DCTL,
+- .div_reg = CM_V3DDIV,
+- .int_bits = 4,
+- .frac_bits = 8,
+-};
+-
+-static const struct bcm2835_clock_data bcm2835_clock_isp_data = {
+- .name = "isp",
+- .num_mux_parents = ARRAY_SIZE(bcm2835_clock_vpu_parents),
+- .parents = bcm2835_clock_vpu_parents,
+- .ctl_reg = CM_ISPCTL,
+- .div_reg = CM_ISPDIV,
+- .int_bits = 4,
+- .frac_bits = 8,
+-};
+-
+-static const struct bcm2835_clock_data bcm2835_clock_h264_data = {
+- .name = "h264",
+- .num_mux_parents = ARRAY_SIZE(bcm2835_clock_vpu_parents),
+- .parents = bcm2835_clock_vpu_parents,
+- .ctl_reg = CM_H264CTL,
+- .div_reg = CM_H264DIV,
+- .int_bits = 4,
+- .frac_bits = 8,
+-};
+-
+-/* TV encoder clock. Only operating frequency is 108Mhz. */
+-static const struct bcm2835_clock_data bcm2835_clock_vec_data = {
+- .name = "vec",
+- .num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents),
+- .parents = bcm2835_clock_per_parents,
+- .ctl_reg = CM_VECCTL,
+- .div_reg = CM_VECDIV,
+- .int_bits = 4,
+- .frac_bits = 0,
+-};
+-
+-static const struct bcm2835_clock_data bcm2835_clock_uart_data = {
+- .name = "uart",
+- .num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents),
+- .parents = bcm2835_clock_per_parents,
+- .ctl_reg = CM_UARTCTL,
+- .div_reg = CM_UARTDIV,
+- .int_bits = 10,
+- .frac_bits = 12,
+-};
+-
+-/* HDMI state machine */
+-static const struct bcm2835_clock_data bcm2835_clock_hsm_data = {
+- .name = "hsm",
+- .num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents),
+- .parents = bcm2835_clock_per_parents,
+- .ctl_reg = CM_HSMCTL,
+- .div_reg = CM_HSMDIV,
+- .int_bits = 4,
+- .frac_bits = 8,
+-};
+-
+-/*
+- * Secondary SDRAM clock. Used for low-voltage modes when the PLL in
+- * the SDRAM controller can't be used.
+- */
+-static const struct bcm2835_clock_data bcm2835_clock_sdram_data = {
+- .name = "sdram",
+- .num_mux_parents = ARRAY_SIZE(bcm2835_clock_vpu_parents),
+- .parents = bcm2835_clock_vpu_parents,
+- .ctl_reg = CM_SDCCTL,
+- .div_reg = CM_SDCDIV,
+- .int_bits = 6,
+- .frac_bits = 0,
+-};
+-
+-/* Clock for the temperature sensor. Generally run at 2Mhz, max 5Mhz. */
+-static const struct bcm2835_clock_data bcm2835_clock_tsens_data = {
+- .name = "tsens",
+- .num_mux_parents = ARRAY_SIZE(bcm2835_clock_osc_parents),
+- .parents = bcm2835_clock_osc_parents,
+- .ctl_reg = CM_TSENSCTL,
+- .div_reg = CM_TSENSDIV,
+- .int_bits = 5,
+- .frac_bits = 0,
+-};
+-
+-/* Arasan EMMC clock */
+-static const struct bcm2835_clock_data bcm2835_clock_emmc_data = {
+- .name = "emmc",
+- .num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents),
+- .parents = bcm2835_clock_per_parents,
+- .ctl_reg = CM_EMMCCTL,
+- .div_reg = CM_EMMCDIV,
+- .int_bits = 4,
+- .frac_bits = 8,
+-};
+-
+-static const struct bcm2835_clock_data bcm2835_clock_pwm_data = {
+- .name = "pwm",
+- .num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents),
+- .parents = bcm2835_clock_per_parents,
+- .ctl_reg = CM_PWMCTL,
+- .div_reg = CM_PWMDIV,
+- .int_bits = 12,
+- .frac_bits = 12,
+- .is_mash_clock = true,
+-};
+-
+ struct bcm2835_gate_data {
+ const char *name;
+ const char *parent;
+@@ -860,18 +455,6 @@ struct bcm2835_gate_data {
+ u32 ctl_reg;
+ };
+
+-/*
+- * CM_PERIICTL (and CM_PERIACTL, CM_SYSCTL and CM_VPUCTL if
+- * you have the debug bit set in the power manager, which we
+- * don't bother exposing) are individual gates off of the
+- * non-stop vpu clock.
+- */
+-static const struct bcm2835_gate_data bcm2835_clock_peri_image_data = {
+- .name = "peri_image",
+- .parent = "vpu",
+- .ctl_reg = CM_PERIICTL,
+-};
+-
+ struct bcm2835_pll {
+ struct clk_hw hw;
+ struct bcm2835_cprman *cprman;
+@@ -1594,7 +1177,7 @@ bcm2835_register_pll_divider(struct bcm2
+
+ memset(&init, 0, sizeof(init));
+
+- init.parent_names = &data->source_pll->name;
++ init.parent_names = &data->source_pll;
+ init.num_parents = 1;
+ init.name = divider_name;
+ init.ops = &bcm2835_pll_divider_clk_ops;
+@@ -1693,50 +1276,401 @@ struct bcm2835_clk_desc {
+ const void *data;
+ };
+
+-#define _REGISTER(f, d) { .clk_register = (bcm2835_clk_register)f, \
+- .data = d }
+-#define REGISTER_PLL(d) _REGISTER(&bcm2835_register_pll, d)
+-#define REGISTER_PLL_DIV(d) _REGISTER(&bcm2835_register_pll_divider, d)
+-#define REGISTER_CLK(d) _REGISTER(&bcm2835_register_clock, d)
+-#define REGISTER_GATE(d) _REGISTER(&bcm2835_register_gate, d)
++/* assignment helper macros for different clock types */
++#define _REGISTER(f, ...) { .clk_register = (bcm2835_clk_register)f, \
++ .data = __VA_ARGS__ }
++#define REGISTER_PLL(...) _REGISTER(&bcm2835_register_pll, \
++ &(struct bcm2835_pll_data) \
++ {__VA_ARGS__})
++#define REGISTER_PLL_DIV(...) _REGISTER(&bcm2835_register_pll_divider, \
++ &(struct bcm2835_pll_divider_data) \
++ {__VA_ARGS__})
++#define REGISTER_CLK(...) _REGISTER(&bcm2835_register_clock, \
++ &(struct bcm2835_clock_data) \
++ {__VA_ARGS__})
++#define REGISTER_GATE(...) _REGISTER(&bcm2835_register_gate, \
++ &(struct bcm2835_gate_data) \
++ {__VA_ARGS__})
++
++/* parent mux arrays plus helper macros */
++
++/* main oscillator parent mux */
++static const char *const bcm2835_clock_osc_parents[] = {
++ "gnd",
++ "xosc",
++ "testdebug0",
++ "testdebug1"
++};
++
++#define REGISTER_OSC_CLK(...) REGISTER_CLK( \
++ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_osc_parents), \
++ .parents = bcm2835_clock_osc_parents, \
++ __VA_ARGS__)
++
++/* main peripherial parent mux */
++static const char *const bcm2835_clock_per_parents[] = {
++ "gnd",
++ "xosc",
++ "testdebug0",
++ "testdebug1",
++ "plla_per",
++ "pllc_per",
++ "plld_per",
++ "pllh_aux",
++};
++
++#define REGISTER_PER_CLK(...) REGISTER_CLK( \
++ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents), \
++ .parents = bcm2835_clock_per_parents, \
++ __VA_ARGS__)
++
++/* main vpu parent mux */
++static const char *const bcm2835_clock_vpu_parents[] = {
++ "gnd",
++ "xosc",
++ "testdebug0",
++ "testdebug1",
++ "plla_core",
++ "pllc_core0",
++ "plld_core",
++ "pllh_aux",
++ "pllc_core1",
++ "pllc_core2",
++};
++
++#define REGISTER_VPU_CLK(...) REGISTER_CLK( \
++ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_vpu_parents), \
++ .parents = bcm2835_clock_vpu_parents, \
++ __VA_ARGS__)
+
++/*
++ * the real definition of all the pll, pll_dividers and clocks
++ * these make use of the above REGISTER_* macros
++ */
+ static const struct bcm2835_clk_desc clk_desc_array[] = {
+- /* register PLL */
+- [BCM2835_PLLA] = REGISTER_PLL(&bcm2835_plla_data),
+- [BCM2835_PLLB] = REGISTER_PLL(&bcm2835_pllb_data),
+- [BCM2835_PLLC] = REGISTER_PLL(&bcm2835_pllc_data),
+- [BCM2835_PLLD] = REGISTER_PLL(&bcm2835_plld_data),
+- [BCM2835_PLLH] = REGISTER_PLL(&bcm2835_pllh_data),
+- /* the PLL dividers */
+- [BCM2835_PLLA_CORE] = REGISTER_PLL_DIV(&bcm2835_plla_core_data),
+- [BCM2835_PLLA_PER] = REGISTER_PLL_DIV(&bcm2835_plla_per_data),
+- [BCM2835_PLLC_CORE0] = REGISTER_PLL_DIV(&bcm2835_pllc_core0_data),
+- [BCM2835_PLLC_CORE1] = REGISTER_PLL_DIV(&bcm2835_pllc_core1_data),
+- [BCM2835_PLLC_CORE2] = REGISTER_PLL_DIV(&bcm2835_pllc_core2_data),
+- [BCM2835_PLLC_PER] = REGISTER_PLL_DIV(&bcm2835_pllc_per_data),
+- [BCM2835_PLLD_CORE] = REGISTER_PLL_DIV(&bcm2835_plld_core_data),
+- [BCM2835_PLLD_PER] = REGISTER_PLL_DIV(&bcm2835_plld_per_data),
+- [BCM2835_PLLH_RCAL] = REGISTER_PLL_DIV(&bcm2835_pllh_rcal_data),
+- [BCM2835_PLLH_AUX] = REGISTER_PLL_DIV(&bcm2835_pllh_aux_data),
+- [BCM2835_PLLH_PIX] = REGISTER_PLL_DIV(&bcm2835_pllh_pix_data),
++ /* the PLL + PLL dividers */
++
++ /*
++ * PLLA is the auxiliary PLL, used to drive the CCP2
++ * (Compact Camera Port 2) transmitter clock.
++ *
++ * It is in the PX LDO power domain, which is on when the
++ * AUDIO domain is on.
++ */
++ [BCM2835_PLLA] = REGISTER_PLL(
++ .name = "plla",
++ .cm_ctrl_reg = CM_PLLA,
++ .a2w_ctrl_reg = A2W_PLLA_CTRL,
++ .frac_reg = A2W_PLLA_FRAC,
++ .ana_reg_base = A2W_PLLA_ANA0,
++ .reference_enable_mask = A2W_XOSC_CTRL_PLLA_ENABLE,
++ .lock_mask = CM_LOCK_FLOCKA,
++
++ .ana = &bcm2835_ana_default,
++
++ .min_rate = 600000000u,
++ .max_rate = 2400000000u,
++ .max_fb_rate = BCM2835_MAX_FB_RATE),
++ [BCM2835_PLLA_CORE] = REGISTER_PLL_DIV(
++ .name = "plla_core",
++ .source_pll = "plla",
++ .cm_reg = CM_PLLA,
++ .a2w_reg = A2W_PLLA_CORE,
++ .load_mask = CM_PLLA_LOADCORE,
++ .hold_mask = CM_PLLA_HOLDCORE,
++ .fixed_divider = 1),
++ [BCM2835_PLLA_PER] = REGISTER_PLL_DIV(
++ .name = "plla_per",
++ .source_pll = "plla",
++ .cm_reg = CM_PLLA,
++ .a2w_reg = A2W_PLLA_PER,
++ .load_mask = CM_PLLA_LOADPER,
++ .hold_mask = CM_PLLA_HOLDPER,
++ .fixed_divider = 1),
++
++ /* PLLB is used for the ARM's clock. */
++ [BCM2835_PLLB] = REGISTER_PLL(
++ .name = "pllb",
++ .cm_ctrl_reg = CM_PLLB,
++ .a2w_ctrl_reg = A2W_PLLB_CTRL,
++ .frac_reg = A2W_PLLB_FRAC,
++ .ana_reg_base = A2W_PLLB_ANA0,
++ .reference_enable_mask = A2W_XOSC_CTRL_PLLB_ENABLE,
++ .lock_mask = CM_LOCK_FLOCKB,
++
++ .ana = &bcm2835_ana_default,
++
++ .min_rate = 600000000u,
++ .max_rate = 3000000000u,
++ .max_fb_rate = BCM2835_MAX_FB_RATE),
++ [BCM2835_PLLB_ARM] = REGISTER_PLL_DIV(
++ .name = "pllb_arm",
++ .source_pll = "pllb",
++ .cm_reg = CM_PLLB,
++ .a2w_reg = A2W_PLLB_ARM,
++ .load_mask = CM_PLLB_LOADARM,
++ .hold_mask = CM_PLLB_HOLDARM,
++ .fixed_divider = 1),
++
++ /*
++ * PLLC is the core PLL, used to drive the core VPU clock.
++ *
++ * It is in the PX LDO power domain, which is on when the
++ * AUDIO domain is on.
++ */
++ [BCM2835_PLLC] = REGISTER_PLL(
++ .name = "pllc",
++ .cm_ctrl_reg = CM_PLLC,
++ .a2w_ctrl_reg = A2W_PLLC_CTRL,
++ .frac_reg = A2W_PLLC_FRAC,
++ .ana_reg_base = A2W_PLLC_ANA0,
++ .reference_enable_mask = A2W_XOSC_CTRL_PLLC_ENABLE,
++ .lock_mask = CM_LOCK_FLOCKC,
++
++ .ana = &bcm2835_ana_default,
++
++ .min_rate = 600000000u,
++ .max_rate = 3000000000u,
++ .max_fb_rate = BCM2835_MAX_FB_RATE),
++ [BCM2835_PLLC_CORE0] = REGISTER_PLL_DIV(
++ .name = "pllc_core0",
++ .source_pll = "pllc",
++ .cm_reg = CM_PLLC,
++ .a2w_reg = A2W_PLLC_CORE0,
++ .load_mask = CM_PLLC_LOADCORE0,
++ .hold_mask = CM_PLLC_HOLDCORE0,
++ .fixed_divider = 1),
++ [BCM2835_PLLC_CORE1] = REGISTER_PLL_DIV(
++ .name = "pllc_core1",
++ .source_pll = "pllc",
++ .cm_reg = CM_PLLC,
++ .a2w_reg = A2W_PLLC_CORE1,
++ .load_mask = CM_PLLC_LOADCORE1,
++ .hold_mask = CM_PLLC_HOLDCORE1,
++ .fixed_divider = 1),
++ [BCM2835_PLLC_CORE2] = REGISTER_PLL_DIV(
++ .name = "pllc_core2",
++ .source_pll = "pllc",
++ .cm_reg = CM_PLLC,
++ .a2w_reg = A2W_PLLC_CORE2,
++ .load_mask = CM_PLLC_LOADCORE2,
++ .hold_mask = CM_PLLC_HOLDCORE2,
++ .fixed_divider = 1),
++ [BCM2835_PLLC_PER] = REGISTER_PLL_DIV(
++ .name = "pllc_per",
++ .source_pll = "pllc",
++ .cm_reg = CM_PLLC,
++ .a2w_reg = A2W_PLLC_PER,
++ .load_mask = CM_PLLC_LOADPER,
++ .hold_mask = CM_PLLC_HOLDPER,
++ .fixed_divider = 1),
++
++ /*
++ * PLLD is the display PLL, used to drive DSI display panels.
++ *
++ * It is in the PX LDO power domain, which is on when the
++ * AUDIO domain is on.
++ */
++ [BCM2835_PLLD] = REGISTER_PLL(
++ .name = "plld",
++ .cm_ctrl_reg = CM_PLLD,
++ .a2w_ctrl_reg = A2W_PLLD_CTRL,
++ .frac_reg = A2W_PLLD_FRAC,
++ .ana_reg_base = A2W_PLLD_ANA0,
++ .reference_enable_mask = A2W_XOSC_CTRL_DDR_ENABLE,
++ .lock_mask = CM_LOCK_FLOCKD,
++
++ .ana = &bcm2835_ana_default,
++
++ .min_rate = 600000000u,
++ .max_rate = 2400000000u,
++ .max_fb_rate = BCM2835_MAX_FB_RATE),
++ [BCM2835_PLLD_CORE] = REGISTER_PLL_DIV(
++ .name = "plld_core",
++ .source_pll = "plld",
++ .cm_reg = CM_PLLD,
++ .a2w_reg = A2W_PLLD_CORE,
++ .load_mask = CM_PLLD_LOADCORE,
++ .hold_mask = CM_PLLD_HOLDCORE,
++ .fixed_divider = 1),
++ [BCM2835_PLLD_PER] = REGISTER_PLL_DIV(
++ .name = "plld_per",
++ .source_pll = "plld",
++ .cm_reg = CM_PLLD,
++ .a2w_reg = A2W_PLLD_PER,
++ .load_mask = CM_PLLD_LOADPER,
++ .hold_mask = CM_PLLD_HOLDPER,
++ .fixed_divider = 1),
++
++ /*
++ * PLLH is used to supply the pixel clock or the AUX clock for the
++ * TV encoder.
++ *
++ * It is in the HDMI power domain.
++ */
++ [BCM2835_PLLH] = REGISTER_PLL(
++ "pllh",
++ .cm_ctrl_reg = CM_PLLH,
++ .a2w_ctrl_reg = A2W_PLLH_CTRL,
++ .frac_reg = A2W_PLLH_FRAC,
++ .ana_reg_base = A2W_PLLH_ANA0,
++ .reference_enable_mask = A2W_XOSC_CTRL_PLLC_ENABLE,
++ .lock_mask = CM_LOCK_FLOCKH,
++
++ .ana = &bcm2835_ana_pllh,
++
++ .min_rate = 600000000u,
++ .max_rate = 3000000000u,
++ .max_fb_rate = BCM2835_MAX_FB_RATE),
++ [BCM2835_PLLH_RCAL] = REGISTER_PLL_DIV(
++ .name = "pllh_rcal",
++ .source_pll = "pllh",
++ .cm_reg = CM_PLLH,
++ .a2w_reg = A2W_PLLH_RCAL,
++ .load_mask = CM_PLLH_LOADRCAL,
++ .hold_mask = 0,
++ .fixed_divider = 10),
++ [BCM2835_PLLH_AUX] = REGISTER_PLL_DIV(
++ .name = "pllh_aux",
++ .source_pll = "pllh",
++ .cm_reg = CM_PLLH,
++ .a2w_reg = A2W_PLLH_AUX,
++ .load_mask = CM_PLLH_LOADAUX,
++ .hold_mask = 0,
++ .fixed_divider = 10),
++ [BCM2835_PLLH_PIX] = REGISTER_PLL_DIV(
++ .name = "pllh_pix",
++ .source_pll = "pllh",
++ .cm_reg = CM_PLLH,
++ .a2w_reg = A2W_PLLH_PIX,
++ .load_mask = CM_PLLH_LOADPIX,
++ .hold_mask = 0,
++ .fixed_divider = 10),
++
+ /* the clocks */
+- [BCM2835_CLOCK_TIMER] = REGISTER_CLK(&bcm2835_clock_timer_data),
+- [BCM2835_CLOCK_OTP] = REGISTER_CLK(&bcm2835_clock_otp_data),
+- [BCM2835_CLOCK_TSENS] = REGISTER_CLK(&bcm2835_clock_tsens_data),
+- [BCM2835_CLOCK_VPU] = REGISTER_CLK(&bcm2835_clock_vpu_data),
+- [BCM2835_CLOCK_V3D] = REGISTER_CLK(&bcm2835_clock_v3d_data),
+- [BCM2835_CLOCK_ISP] = REGISTER_CLK(&bcm2835_clock_isp_data),
+- [BCM2835_CLOCK_H264] = REGISTER_CLK(&bcm2835_clock_h264_data),
+- [BCM2835_CLOCK_V3D] = REGISTER_CLK(&bcm2835_clock_v3d_data),
+- [BCM2835_CLOCK_SDRAM] = REGISTER_CLK(&bcm2835_clock_sdram_data),
+- [BCM2835_CLOCK_UART] = REGISTER_CLK(&bcm2835_clock_uart_data),
+- [BCM2835_CLOCK_VEC] = REGISTER_CLK(&bcm2835_clock_vec_data),
+- [BCM2835_CLOCK_HSM] = REGISTER_CLK(&bcm2835_clock_hsm_data),
+- [BCM2835_CLOCK_EMMC] = REGISTER_CLK(&bcm2835_clock_emmc_data),
+- [BCM2835_CLOCK_PWM] = REGISTER_CLK(&bcm2835_clock_pwm_data),
++
++ /* clocks with oscillator parent mux */
++
++ /* One Time Programmable Memory clock. Maximum 10Mhz. */
++ [BCM2835_CLOCK_OTP] = REGISTER_OSC_CLK(
++ .name = "otp",
++ .ctl_reg = CM_OTPCTL,
++ .div_reg = CM_OTPDIV,
++ .int_bits = 4,
++ .frac_bits = 0),
++ /*
++ * Used for a 1Mhz clock for the system clocksource, and also used
++ * bythe watchdog timer and the camera pulse generator.
++ */
++ [BCM2835_CLOCK_TIMER] = REGISTER_OSC_CLK(
++ .name = "timer",
++ .ctl_reg = CM_TIMERCTL,
++ .div_reg = CM_TIMERDIV,
++ .int_bits = 6,
++ .frac_bits = 12),
++ /*
++ * Clock for the temperature sensor.
++ * Generally run at 2Mhz, max 5Mhz.
++ */
++ [BCM2835_CLOCK_TSENS] = REGISTER_OSC_CLK(
++ .name = "tsens",
++ .ctl_reg = CM_TSENSCTL,
++ .div_reg = CM_TSENSDIV,
++ .int_bits = 5,
++ .frac_bits = 0),
++
++ /* clocks with vpu parent mux */
++ [BCM2835_CLOCK_H264] = REGISTER_VPU_CLK(
++ .name = "h264",
++ .ctl_reg = CM_H264CTL,
++ .div_reg = CM_H264DIV,
++ .int_bits = 4,
++ .frac_bits = 8),
++ [BCM2835_CLOCK_ISP] = REGISTER_VPU_CLK(
++ .name = "isp",
++ .ctl_reg = CM_ISPCTL,
++ .div_reg = CM_ISPDIV,
++ .int_bits = 4,
++ .frac_bits = 8),
++ /*
++ * Secondary SDRAM clock. Used for low-voltage modes when the PLL
++ * in the SDRAM controller can't be used.
++ */
++ [BCM2835_CLOCK_SDRAM] = REGISTER_VPU_CLK(
++ .name = "sdram",
++ .ctl_reg = CM_SDCCTL,
++ .div_reg = CM_SDCDIV,
++ .int_bits = 6,
++ .frac_bits = 0),
++ [BCM2835_CLOCK_V3D] = REGISTER_VPU_CLK(
++ .name = "v3d",
++ .ctl_reg = CM_V3DCTL,
++ .div_reg = CM_V3DDIV,
++ .int_bits = 4,
++ .frac_bits = 8),
++ /*
++ * VPU clock. This doesn't have an enable bit, since it drives
++ * the bus for everything else, and is special so it doesn't need
++ * to be gated for rate changes. It is also known as "clk_audio"
++ * in various hardware documentation.
++ */
++ [BCM2835_CLOCK_VPU] = REGISTER_VPU_CLK(
++ .name = "vpu",
++ .ctl_reg = CM_VPUCTL,
++ .div_reg = CM_VPUDIV,
++ .int_bits = 12,
++ .frac_bits = 8,
++ .is_vpu_clock = true),
++
++ /* clocks with per parent mux */
++
++ /* Arasan EMMC clock */
++ [BCM2835_CLOCK_EMMC] = REGISTER_PER_CLK(
++ .name = "emmc",
++ .ctl_reg = CM_EMMCCTL,
++ .div_reg = CM_EMMCDIV,
++ .int_bits = 4,
++ .frac_bits = 8),
++ /* HDMI state machine */
++ [BCM2835_CLOCK_HSM] = REGISTER_PER_CLK(
++ .name = "hsm",
++ .ctl_reg = CM_HSMCTL,
++ .div_reg = CM_HSMDIV,
++ .int_bits = 4,
++ .frac_bits = 8),
++ [BCM2835_CLOCK_PWM] = REGISTER_PER_CLK(
++ .name = "pwm",
++ .ctl_reg = CM_PWMCTL,
++ .div_reg = CM_PWMDIV,
++ .int_bits = 12,
++ .frac_bits = 12,
++ .is_mash_clock = true),
++ [BCM2835_CLOCK_UART] = REGISTER_PER_CLK(
++ .name = "uart",
++ .ctl_reg = CM_UARTCTL,
++ .div_reg = CM_UARTDIV,
++ .int_bits = 10,
++ .frac_bits = 12),
++ /* TV encoder clock. Only operating frequency is 108Mhz. */
++ [BCM2835_CLOCK_VEC] = REGISTER_PER_CLK(
++ .name = "vec",
++ .ctl_reg = CM_VECCTL,
++ .div_reg = CM_VECDIV,
++ .int_bits = 4,
++ .frac_bits = 0),
++
+ /* the gates */
++
++ /*
++ * CM_PERIICTL (and CM_PERIACTL, CM_SYSCTL and CM_VPUCTL if
++ * you have the debug bit set in the power manager, which we
++ * don't bother exposing) are individual gates off of the
++ * non-stop vpu clock.
++ */
+ [BCM2835_CLOCK_PERI_IMAGE] = REGISTER_GATE(
+- &bcm2835_clock_peri_image_data),
++ .name = "peri_image",
++ .parent = "vpu",
++ .ctl_reg = CM_PERIICTL),
+ };
+
+ static int bcm2835_clk_probe(struct platform_device *pdev)
diff --git a/target/linux/brcm2708/patches-4.4/0263-clk-bcm2835-enable-management-of-PCM-clock.patch b/target/linux/brcm2708/patches-4.4/0263-clk-bcm2835-enable-management-of-PCM-clock.patch
new file mode 100644
index 0000000000..8e9a441bc4
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0263-clk-bcm2835-enable-management-of-PCM-clock.patch
@@ -0,0 +1,40 @@
+From 54ed8266a3502b38b9c23e4fe08a21f666c9dc52 Mon Sep 17 00:00:00 2001
+From: Martin Sperl <kernel@martin.sperl.org>
+Date: Mon, 29 Feb 2016 12:51:43 +0000
+Subject: [PATCH 263/381] clk: bcm2835: enable management of PCM clock
+
+Enable the PCM clock in the SOC, which is used by the
+bcm2835-i2s driver.
+
+Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Reviewed-by: Eric Anholt <eric@anholt.net>
+(cherry picked from commit 33b689600f43094a9316a1b582f2286d17bc737b)
+---
+ drivers/clk/bcm/clk-bcm2835.c | 7 +++++++
+ include/dt-bindings/clock/bcm2835.h | 1 +
+ 2 files changed, 8 insertions(+)
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -1638,6 +1638,13 @@ static const struct bcm2835_clk_desc clk
+ .div_reg = CM_HSMDIV,
+ .int_bits = 4,
+ .frac_bits = 8),
++ [BCM2835_CLOCK_PCM] = REGISTER_PER_CLK(
++ .name = "pcm",
++ .ctl_reg = CM_PCMCTL,
++ .div_reg = CM_PCMDIV,
++ .int_bits = 12,
++ .frac_bits = 12,
++ .is_mash_clock = true),
+ [BCM2835_CLOCK_PWM] = REGISTER_PER_CLK(
+ .name = "pwm",
+ .ctl_reg = CM_PWMCTL,
+--- a/include/dt-bindings/clock/bcm2835.h
++++ b/include/dt-bindings/clock/bcm2835.h
+@@ -44,3 +44,4 @@
+ #define BCM2835_CLOCK_EMMC 28
+ #define BCM2835_CLOCK_PERI_IMAGE 29
+ #define BCM2835_CLOCK_PWM 30
++#define BCM2835_CLOCK_PCM 31
diff --git a/target/linux/brcm2708/patches-4.4/0264-clk-bcm2835-add-missing-PLL-clock-dividers.patch b/target/linux/brcm2708/patches-4.4/0264-clk-bcm2835-add-missing-PLL-clock-dividers.patch
new file mode 100644
index 0000000000..02385cc4f4
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0264-clk-bcm2835-add-missing-PLL-clock-dividers.patch
@@ -0,0 +1,73 @@
+From 108999bf5b0b9dba4094ca0cff0f0f7e193f3297 Mon Sep 17 00:00:00 2001
+From: Martin Sperl <kernel@martin.sperl.org>
+Date: Mon, 29 Feb 2016 15:43:56 +0000
+Subject: [PATCH 264/381] clk: bcm2835: add missing PLL clock dividers
+
+Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Reviewed-by: Eric Anholt <eric@anholt.net>
+(cherry picked from commit 728436956aa172b24a3212295f8b53feb6479f32)
+---
+ drivers/clk/bcm/clk-bcm2835.c | 32 ++++++++++++++++++++++++++++++++
+ include/dt-bindings/clock/bcm2835.h | 5 +++++
+ 2 files changed, 37 insertions(+)
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -1387,6 +1387,22 @@ static const struct bcm2835_clk_desc clk
+ .load_mask = CM_PLLA_LOADPER,
+ .hold_mask = CM_PLLA_HOLDPER,
+ .fixed_divider = 1),
++ [BCM2835_PLLA_DSI0] = REGISTER_PLL_DIV(
++ .name = "plla_dsi0",
++ .source_pll = "plla",
++ .cm_reg = CM_PLLA,
++ .a2w_reg = A2W_PLLA_DSI0,
++ .load_mask = CM_PLLA_LOADDSI0,
++ .hold_mask = CM_PLLA_HOLDDSI0,
++ .fixed_divider = 1),
++ [BCM2835_PLLA_CCP2] = REGISTER_PLL_DIV(
++ .name = "plla_ccp2",
++ .source_pll = "plla",
++ .cm_reg = CM_PLLA,
++ .a2w_reg = A2W_PLLA_CCP2,
++ .load_mask = CM_PLLA_LOADCCP2,
++ .hold_mask = CM_PLLA_HOLDCCP2,
++ .fixed_divider = 1),
+
+ /* PLLB is used for the ARM's clock. */
+ [BCM2835_PLLB] = REGISTER_PLL(
+@@ -1501,6 +1517,22 @@ static const struct bcm2835_clk_desc clk
+ .load_mask = CM_PLLD_LOADPER,
+ .hold_mask = CM_PLLD_HOLDPER,
+ .fixed_divider = 1),
++ [BCM2835_PLLD_DSI0] = REGISTER_PLL_DIV(
++ .name = "plld_dsi0",
++ .source_pll = "plld",
++ .cm_reg = CM_PLLD,
++ .a2w_reg = A2W_PLLD_DSI0,
++ .load_mask = CM_PLLD_LOADDSI0,
++ .hold_mask = CM_PLLD_HOLDDSI0,
++ .fixed_divider = 1),
++ [BCM2835_PLLD_DSI1] = REGISTER_PLL_DIV(
++ .name = "plld_dsi1",
++ .source_pll = "plld",
++ .cm_reg = CM_PLLD,
++ .a2w_reg = A2W_PLLD_DSI1,
++ .load_mask = CM_PLLD_LOADDSI1,
++ .hold_mask = CM_PLLD_HOLDDSI1,
++ .fixed_divider = 1),
+
+ /*
+ * PLLH is used to supply the pixel clock or the AUX clock for the
+--- a/include/dt-bindings/clock/bcm2835.h
++++ b/include/dt-bindings/clock/bcm2835.h
+@@ -45,3 +45,8 @@
+ #define BCM2835_CLOCK_PERI_IMAGE 29
+ #define BCM2835_CLOCK_PWM 30
+ #define BCM2835_CLOCK_PCM 31
++
++#define BCM2835_PLLA_DSI0 32
++#define BCM2835_PLLA_CCP2 33
++#define BCM2835_PLLD_DSI0 34
++#define BCM2835_PLLD_DSI1 35
diff --git a/target/linux/brcm2708/patches-4.4/0265-clk-bcm2835-add-missing-osc-and-per-clocks.patch b/target/linux/brcm2708/patches-4.4/0265-clk-bcm2835-add-missing-osc-and-per-clocks.patch
new file mode 100644
index 0000000000..8be0dce99e
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0265-clk-bcm2835-add-missing-osc-and-per-clocks.patch
@@ -0,0 +1,184 @@
+From 787e7372d221fad5da0ee1ee74d3c42d409fb22b Mon Sep 17 00:00:00 2001
+From: Martin Sperl <kernel@martin.sperl.org>
+Date: Mon, 29 Feb 2016 15:43:57 +0000
+Subject: [PATCH 265/381] clk: bcm2835: add missing osc and per clocks
+
+Add AVE0, DFT, GP0, GP1, GP2, SLIM, SMI, TEC, DPI, CAM0, CAM1, DSI0E,
+and DSI1E. PULSE is not added because it has an extra divider.
+
+Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Reviewed-by: Eric Anholt <eric@anholt.net>
+(cherry picked from commit d3d6f15fd376e3dbba851724057b112558c70b79)
+---
+ drivers/clk/bcm/clk-bcm2835.c | 90 +++++++++++++++++++++++++++++++++++++
+ include/dt-bindings/clock/bcm2835.h | 14 ++++++
+ 2 files changed, 104 insertions(+)
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -117,6 +117,8 @@
+ #define CM_SDCCTL 0x1a8
+ #define CM_SDCDIV 0x1ac
+ #define CM_ARMCTL 0x1b0
++#define CM_AVEOCTL 0x1b8
++#define CM_AVEODIV 0x1bc
+ #define CM_EMMCCTL 0x1c0
+ #define CM_EMMCDIV 0x1c4
+
+@@ -1610,6 +1612,12 @@ static const struct bcm2835_clk_desc clk
+ .div_reg = CM_TSENSDIV,
+ .int_bits = 5,
+ .frac_bits = 0),
++ [BCM2835_CLOCK_TEC] = REGISTER_OSC_CLK(
++ .name = "tec",
++ .ctl_reg = CM_TECCTL,
++ .div_reg = CM_TECDIV,
++ .int_bits = 6,
++ .frac_bits = 0),
+
+ /* clocks with vpu parent mux */
+ [BCM2835_CLOCK_H264] = REGISTER_VPU_CLK(
+@@ -1624,6 +1632,7 @@ static const struct bcm2835_clk_desc clk
+ .div_reg = CM_ISPDIV,
+ .int_bits = 4,
+ .frac_bits = 8),
++
+ /*
+ * Secondary SDRAM clock. Used for low-voltage modes when the PLL
+ * in the SDRAM controller can't be used.
+@@ -1655,6 +1664,36 @@ static const struct bcm2835_clk_desc clk
+ .is_vpu_clock = true),
+
+ /* clocks with per parent mux */
++ [BCM2835_CLOCK_AVEO] = REGISTER_PER_CLK(
++ .name = "aveo",
++ .ctl_reg = CM_AVEOCTL,
++ .div_reg = CM_AVEODIV,
++ .int_bits = 4,
++ .frac_bits = 0),
++ [BCM2835_CLOCK_CAM0] = REGISTER_PER_CLK(
++ .name = "cam0",
++ .ctl_reg = CM_CAM0CTL,
++ .div_reg = CM_CAM0DIV,
++ .int_bits = 4,
++ .frac_bits = 8),
++ [BCM2835_CLOCK_CAM1] = REGISTER_PER_CLK(
++ .name = "cam1",
++ .ctl_reg = CM_CAM1CTL,
++ .div_reg = CM_CAM1DIV,
++ .int_bits = 4,
++ .frac_bits = 8),
++ [BCM2835_CLOCK_DFT] = REGISTER_PER_CLK(
++ .name = "dft",
++ .ctl_reg = CM_DFTCTL,
++ .div_reg = CM_DFTDIV,
++ .int_bits = 5,
++ .frac_bits = 0),
++ [BCM2835_CLOCK_DPI] = REGISTER_PER_CLK(
++ .name = "dpi",
++ .ctl_reg = CM_DPICTL,
++ .div_reg = CM_DPIDIV,
++ .int_bits = 4,
++ .frac_bits = 8),
+
+ /* Arasan EMMC clock */
+ [BCM2835_CLOCK_EMMC] = REGISTER_PER_CLK(
+@@ -1663,6 +1702,29 @@ static const struct bcm2835_clk_desc clk
+ .div_reg = CM_EMMCDIV,
+ .int_bits = 4,
+ .frac_bits = 8),
++
++ /* General purpose (GPIO) clocks */
++ [BCM2835_CLOCK_GP0] = REGISTER_PER_CLK(
++ .name = "gp0",
++ .ctl_reg = CM_GP0CTL,
++ .div_reg = CM_GP0DIV,
++ .int_bits = 12,
++ .frac_bits = 12,
++ .is_mash_clock = true),
++ [BCM2835_CLOCK_GP1] = REGISTER_PER_CLK(
++ .name = "gp1",
++ .ctl_reg = CM_GP1CTL,
++ .div_reg = CM_GP1DIV,
++ .int_bits = 12,
++ .frac_bits = 12,
++ .is_mash_clock = true),
++ [BCM2835_CLOCK_GP2] = REGISTER_PER_CLK(
++ .name = "gp2",
++ .ctl_reg = CM_GP2CTL,
++ .div_reg = CM_GP2DIV,
++ .int_bits = 12,
++ .frac_bits = 12),
++
+ /* HDMI state machine */
+ [BCM2835_CLOCK_HSM] = REGISTER_PER_CLK(
+ .name = "hsm",
+@@ -1684,12 +1746,26 @@ static const struct bcm2835_clk_desc clk
+ .int_bits = 12,
+ .frac_bits = 12,
+ .is_mash_clock = true),
++ [BCM2835_CLOCK_SLIM] = REGISTER_PER_CLK(
++ .name = "slim",
++ .ctl_reg = CM_SLIMCTL,
++ .div_reg = CM_SLIMDIV,
++ .int_bits = 12,
++ .frac_bits = 12,
++ .is_mash_clock = true),
++ [BCM2835_CLOCK_SMI] = REGISTER_PER_CLK(
++ .name = "smi",
++ .ctl_reg = CM_SMICTL,
++ .div_reg = CM_SMIDIV,
++ .int_bits = 4,
++ .frac_bits = 8),
+ [BCM2835_CLOCK_UART] = REGISTER_PER_CLK(
+ .name = "uart",
+ .ctl_reg = CM_UARTCTL,
+ .div_reg = CM_UARTDIV,
+ .int_bits = 10,
+ .frac_bits = 12),
++
+ /* TV encoder clock. Only operating frequency is 108Mhz. */
+ [BCM2835_CLOCK_VEC] = REGISTER_PER_CLK(
+ .name = "vec",
+@@ -1698,6 +1774,20 @@ static const struct bcm2835_clk_desc clk
+ .int_bits = 4,
+ .frac_bits = 0),
+
++ /* dsi clocks */
++ [BCM2835_CLOCK_DSI0E] = REGISTER_PER_CLK(
++ .name = "dsi0e",
++ .ctl_reg = CM_DSI0ECTL,
++ .div_reg = CM_DSI0EDIV,
++ .int_bits = 4,
++ .frac_bits = 8),
++ [BCM2835_CLOCK_DSI1E] = REGISTER_PER_CLK(
++ .name = "dsi1e",
++ .ctl_reg = CM_DSI1ECTL,
++ .div_reg = CM_DSI1EDIV,
++ .int_bits = 4,
++ .frac_bits = 8),
++
+ /* the gates */
+
+ /*
+--- a/include/dt-bindings/clock/bcm2835.h
++++ b/include/dt-bindings/clock/bcm2835.h
+@@ -50,3 +50,17 @@
+ #define BCM2835_PLLA_CCP2 33
+ #define BCM2835_PLLD_DSI0 34
+ #define BCM2835_PLLD_DSI1 35
++
++#define BCM2835_CLOCK_AVEO 36
++#define BCM2835_CLOCK_DFT 37
++#define BCM2835_CLOCK_GP0 38
++#define BCM2835_CLOCK_GP1 39
++#define BCM2835_CLOCK_GP2 40
++#define BCM2835_CLOCK_SLIM 41
++#define BCM2835_CLOCK_SMI 42
++#define BCM2835_CLOCK_TEC 43
++#define BCM2835_CLOCK_DPI 44
++#define BCM2835_CLOCK_CAM0 45
++#define BCM2835_CLOCK_CAM1 46
++#define BCM2835_CLOCK_DSI0E 47
++#define BCM2835_CLOCK_DSI1E 48
diff --git a/target/linux/brcm2708/patches-4.4/0266-clk-bcm2835-Fix-PLL-poweron.patch b/target/linux/brcm2708/patches-4.4/0266-clk-bcm2835-Fix-PLL-poweron.patch
new file mode 100644
index 0000000000..fcc950df0f
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0266-clk-bcm2835-Fix-PLL-poweron.patch
@@ -0,0 +1,32 @@
+From 2ecc0a11eb0e77a75c2ae468d656c773877f3997 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Wed, 13 Apr 2016 13:05:03 -0700
+Subject: [PATCH 266/381] clk: bcm2835: Fix PLL poweron
+
+In poweroff, we set the reset bit and the power down bit, but only
+managed to unset the reset bit for poweron. This meant that if HDMI
+did -EPROBE_DEFER after it had grabbed its clocks, we'd power down the
+PLLH (that had been on at boot time) and never recover.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Fixes: 41691b8862e2 ("clk: bcm2835: Add support for programming the audio domain clocks")
+Cc: stable@vger.kernel.org
+Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+(cherry picked from commit d794a7b18350b7538e64248adf639f2cb8da5fb7)
+---
+ drivers/clk/bcm/clk-bcm2835.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -561,6 +561,10 @@ static int bcm2835_pll_on(struct clk_hw
+ cprman_read(cprman, data->a2w_ctrl_reg) &
+ ~A2W_PLL_CTRL_PWRDN);
+
++ cprman_write(cprman, data->a2w_ctrl_reg,
++ cprman_read(cprman, data->a2w_ctrl_reg) &
++ ~A2W_PLL_CTRL_PWRDN);
++
+ /* Take the PLL out of reset. */
+ cprman_write(cprman, data->cm_ctrl_reg,
+ cprman_read(cprman, data->cm_ctrl_reg) & ~CM_PLL_ANARST);
diff --git a/target/linux/brcm2708/patches-4.4/0267-ARM-bcm2835-Define-two-new-packets-from-the-latest-f.patch b/target/linux/brcm2708/patches-4.4/0267-ARM-bcm2835-Define-two-new-packets-from-the-latest-f.patch
new file mode 100644
index 0000000000..41ca22f81b
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0267-ARM-bcm2835-Define-two-new-packets-from-the-latest-f.patch
@@ -0,0 +1,33 @@
+From 90ec918fe0427b1b8c9d761a12f8ebcd888ab6e7 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Tue, 1 Dec 2015 16:49:12 -0800
+Subject: [PATCH 267/381] ARM: bcm2835: Define two new packets from the latest
+ firmware.
+
+These packets give us direct access to the firmware's power management
+code, as opposed to GET/SET_POWER_STATE packets that only had a couple
+of domains implemented.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Reviewed-by: Kevin Hilman <khilman@linaro.org>
+(cherry picked from commit 60d56333e869be6ad6926cdba3ba974512b2183b)
+---
+ include/soc/bcm2835/raspberrypi-firmware.h | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/include/soc/bcm2835/raspberrypi-firmware.h
++++ b/include/soc/bcm2835/raspberrypi-firmware.h
+@@ -74,11 +74,13 @@ enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_GET_DISPMANX_RESOURCE_MEM_HANDLE = 0x00030014,
+ RPI_FIRMWARE_GET_EDID_BLOCK = 0x00030020,
+ RPI_FIRMWARE_GET_CUSTOMER_OTP = 0x00030021,
++ RPI_FIRMWARE_GET_DOMAIN_STATE = 0x00030030,
+ 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,
++ RPI_FIRMWARE_SET_DOMAIN_STATE = 0x00038030,
+ RPI_FIRMWARE_SET_SDHOST_CLOCK = 0x00038042,
+
+ /* Dispmanx TAGS */
diff --git a/target/linux/brcm2708/patches-4.4/0268-ARM-bcm2835-add-rpi-power-domain-driver.patch b/target/linux/brcm2708/patches-4.4/0268-ARM-bcm2835-add-rpi-power-domain-driver.patch
new file mode 100644
index 0000000000..b64db53a17
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0268-ARM-bcm2835-add-rpi-power-domain-driver.patch
@@ -0,0 +1,361 @@
+From 9088d7b5c981548b23b8a5c96310bca88ef1503f Mon Sep 17 00:00:00 2001
+From: Alexander Aring <alex.aring@gmail.com>
+Date: Wed, 16 Dec 2015 16:26:47 -0800
+Subject: [PATCH 268/381] ARM: bcm2835: add rpi power domain driver
+
+This patch adds support for several power domains on Raspberry Pi,
+including USB (so it can be enabled even if the bootloader didn't do
+it), and graphics.
+
+This patch is the combined work of Eric Anholt (who wrote USB support
+inside of the Raspberry Pi firmware driver, and wrote the non-USB
+domain support) and Alexander Aring (who separated the original USB
+work out from the firmware driver).
+
+Signed-off-by: Alexander Aring <alex.aring@gmail.com>
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
+Reviewed-by: Kevin Hilman <khilman@linaro.org>
+(cherry picked from commit a09cd356586d33f64cbe64ee4f5c1a7c4a6abee5)
+---
+ drivers/soc/Kconfig | 1 +
+ drivers/soc/Makefile | 1 +
+ drivers/soc/bcm/Kconfig | 9 +
+ drivers/soc/bcm/Makefile | 1 +
+ drivers/soc/bcm/raspberrypi-power.c | 247 ++++++++++++++++++++++++++
+ include/dt-bindings/power/raspberrypi-power.h | 41 +++++
+ 6 files changed, 300 insertions(+)
+ create mode 100644 drivers/soc/bcm/Kconfig
+ create mode 100644 drivers/soc/bcm/Makefile
+ create mode 100644 drivers/soc/bcm/raspberrypi-power.c
+ create mode 100644 include/dt-bindings/power/raspberrypi-power.h
+
+--- a/drivers/soc/Kconfig
++++ b/drivers/soc/Kconfig
+@@ -1,5 +1,6 @@
+ menu "SOC (System On Chip) specific Drivers"
+
++source "drivers/soc/bcm/Kconfig"
+ source "drivers/soc/brcmstb/Kconfig"
+ source "drivers/soc/mediatek/Kconfig"
+ source "drivers/soc/qcom/Kconfig"
+--- a/drivers/soc/Makefile
++++ b/drivers/soc/Makefile
+@@ -2,6 +2,7 @@
+ # Makefile for the Linux Kernel SOC specific device drivers.
+ #
+
++obj-y += bcm/
+ obj-$(CONFIG_SOC_BRCMSTB) += brcmstb/
+ obj-$(CONFIG_MACH_DOVE) += dove/
+ obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/
+--- /dev/null
++++ b/drivers/soc/bcm/Kconfig
+@@ -0,0 +1,9 @@
++config RASPBERRYPI_POWER
++ bool "Raspberry Pi power domain driver"
++ depends on ARCH_BCM2835 || COMPILE_TEST
++ depends on RASPBERRYPI_FIRMWARE
++ select PM_GENERIC_DOMAINS if PM
++ select PM_GENERIC_DOMAINS_OF if PM
++ help
++ This enables support for the RPi power domains which can be enabled
++ or disabled via the RPi firmware.
+--- /dev/null
++++ b/drivers/soc/bcm/Makefile
+@@ -0,0 +1 @@
++obj-$(CONFIG_RASPBERRYPI_POWER) += raspberrypi-power.o
+--- /dev/null
++++ b/drivers/soc/bcm/raspberrypi-power.c
+@@ -0,0 +1,247 @@
++/* (C) 2015 Pengutronix, Alexander Aring <aar@pengutronix.de>
++ *
++ * 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.
++ *
++ * Authors:
++ * Alexander Aring <aar@pengutronix.de>
++ * Eric Anholt <eric@anholt.net>
++ */
++
++#include <linux/module.h>
++#include <linux/of_platform.h>
++#include <linux/platform_device.h>
++#include <linux/pm_domain.h>
++#include <dt-bindings/power/raspberrypi-power.h>
++#include <soc/bcm2835/raspberrypi-firmware.h>
++
++/*
++ * Firmware indices for the old power domains interface. Only a few
++ * of them were actually implemented.
++ */
++#define RPI_OLD_POWER_DOMAIN_USB 3
++#define RPI_OLD_POWER_DOMAIN_V3D 10
++
++struct rpi_power_domain {
++ u32 domain;
++ bool enabled;
++ bool old_interface;
++ struct generic_pm_domain base;
++ struct rpi_firmware *fw;
++};
++
++struct rpi_power_domains {
++ bool has_new_interface;
++ struct genpd_onecell_data xlate;
++ struct rpi_firmware *fw;
++ struct rpi_power_domain domains[RPI_POWER_DOMAIN_COUNT];
++};
++
++/*
++ * Packet definition used by RPI_FIRMWARE_SET_POWER_STATE and
++ * RPI_FIRMWARE_SET_DOMAIN_STATE
++ */
++struct rpi_power_domain_packet {
++ u32 domain;
++ u32 on;
++} __packet;
++
++/*
++ * Asks the firmware to enable or disable power on a specific power
++ * domain.
++ */
++static int rpi_firmware_set_power(struct rpi_power_domain *rpi_domain, bool on)
++{
++ struct rpi_power_domain_packet packet;
++
++ packet.domain = rpi_domain->domain;
++ packet.on = on;
++ return rpi_firmware_property(rpi_domain->fw,
++ rpi_domain->old_interface ?
++ RPI_FIRMWARE_SET_POWER_STATE :
++ RPI_FIRMWARE_SET_DOMAIN_STATE,
++ &packet, sizeof(packet));
++}
++
++static int rpi_domain_off(struct generic_pm_domain *domain)
++{
++ struct rpi_power_domain *rpi_domain =
++ container_of(domain, struct rpi_power_domain, base);
++
++ return rpi_firmware_set_power(rpi_domain, false);
++}
++
++static int rpi_domain_on(struct generic_pm_domain *domain)
++{
++ struct rpi_power_domain *rpi_domain =
++ container_of(domain, struct rpi_power_domain, base);
++
++ return rpi_firmware_set_power(rpi_domain, true);
++}
++
++static void rpi_common_init_power_domain(struct rpi_power_domains *rpi_domains,
++ int xlate_index, const char *name)
++{
++ struct rpi_power_domain *dom = &rpi_domains->domains[xlate_index];
++
++ dom->fw = rpi_domains->fw;
++
++ dom->base.name = name;
++ dom->base.power_on = rpi_domain_on;
++ dom->base.power_off = rpi_domain_off;
++
++ /*
++ * Treat all power domains as off at boot.
++ *
++ * The firmware itself may be keeping some domains on, but
++ * from Linux's perspective all we control is the refcounts
++ * that we give to the firmware, and we can't ask the firmware
++ * to turn off something that we haven't ourselves turned on.
++ */
++ pm_genpd_init(&dom->base, NULL, true);
++
++ rpi_domains->xlate.domains[xlate_index] = &dom->base;
++}
++
++static void rpi_init_power_domain(struct rpi_power_domains *rpi_domains,
++ int xlate_index, const char *name)
++{
++ struct rpi_power_domain *dom = &rpi_domains->domains[xlate_index];
++
++ if (!rpi_domains->has_new_interface)
++ return;
++
++ /* The DT binding index is the firmware's domain index minus one. */
++ dom->domain = xlate_index + 1;
++
++ rpi_common_init_power_domain(rpi_domains, xlate_index, name);
++}
++
++static void rpi_init_old_power_domain(struct rpi_power_domains *rpi_domains,
++ int xlate_index, int domain,
++ const char *name)
++{
++ struct rpi_power_domain *dom = &rpi_domains->domains[xlate_index];
++
++ dom->old_interface = true;
++ dom->domain = domain;
++
++ rpi_common_init_power_domain(rpi_domains, xlate_index, name);
++}
++
++/*
++ * Detects whether the firmware supports the new power domains interface.
++ *
++ * The firmware doesn't actually return an error on an unknown tag,
++ * and just skips over it, so we do the detection by putting an
++ * unexpected value in the return field and checking if it was
++ * unchanged.
++ */
++static bool
++rpi_has_new_domain_support(struct rpi_power_domains *rpi_domains)
++{
++ struct rpi_power_domain_packet packet;
++ int ret;
++
++ packet.domain = RPI_POWER_DOMAIN_ARM;
++ packet.on = ~0;
++
++ ret = rpi_firmware_property(rpi_domains->fw,
++ RPI_FIRMWARE_GET_DOMAIN_STATE,
++ &packet, sizeof(packet));
++
++ return ret == 0 && packet.on != ~0;
++}
++
++static int rpi_power_probe(struct platform_device *pdev)
++{
++ struct device_node *fw_np;
++ struct device *dev = &pdev->dev;
++ struct rpi_power_domains *rpi_domains;
++
++ rpi_domains = devm_kzalloc(dev, sizeof(*rpi_domains), GFP_KERNEL);
++ if (!rpi_domains)
++ return -ENOMEM;
++
++ rpi_domains->xlate.domains =
++ devm_kzalloc(dev, sizeof(*rpi_domains->xlate.domains) *
++ RPI_POWER_DOMAIN_COUNT, GFP_KERNEL);
++ if (!rpi_domains->xlate.domains)
++ return -ENOMEM;
++
++ rpi_domains->xlate.num_domains = RPI_POWER_DOMAIN_COUNT;
++
++ fw_np = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
++ if (!fw_np) {
++ dev_err(&pdev->dev, "no firmware node\n");
++ return -ENODEV;
++ }
++
++ rpi_domains->fw = rpi_firmware_get(fw_np);
++ of_node_put(fw_np);
++ if (!rpi_domains->fw)
++ return -EPROBE_DEFER;
++
++ rpi_domains->has_new_interface =
++ rpi_has_new_domain_support(rpi_domains);
++
++ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_I2C0, "I2C0");
++ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_I2C1, "I2C1");
++ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_I2C2, "I2C2");
++ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_VIDEO_SCALER,
++ "VIDEO_SCALER");
++ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_VPU1, "VPU1");
++ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_HDMI, "HDMI");
++
++ /*
++ * Use the old firmware interface for USB power, so that we
++ * can turn it on even if the firmware hasn't been updated.
++ */
++ rpi_init_old_power_domain(rpi_domains, RPI_POWER_DOMAIN_USB,
++ RPI_OLD_POWER_DOMAIN_USB, "USB");
++
++ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_VEC, "VEC");
++ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_JPEG, "JPEG");
++ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_H264, "H264");
++ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_V3D, "V3D");
++ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_ISP, "ISP");
++ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_UNICAM0, "UNICAM0");
++ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_UNICAM1, "UNICAM1");
++ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CCP2RX, "CCP2RX");
++ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CSI2, "CSI2");
++ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CPI, "CPI");
++ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_DSI0, "DSI0");
++ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_DSI1, "DSI1");
++ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_TRANSPOSER,
++ "TRANSPOSER");
++ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CCP2TX, "CCP2TX");
++ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CDP, "CDP");
++ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_ARM, "ARM");
++
++ of_genpd_add_provider_onecell(dev->of_node, &rpi_domains->xlate);
++
++ platform_set_drvdata(pdev, rpi_domains);
++
++ return 0;
++}
++
++static const struct of_device_id rpi_power_of_match[] = {
++ { .compatible = "raspberrypi,bcm2835-power", },
++ {},
++};
++MODULE_DEVICE_TABLE(of, rpi_power_of_match);
++
++static struct platform_driver rpi_power_driver = {
++ .driver = {
++ .name = "raspberrypi-power",
++ .of_match_table = rpi_power_of_match,
++ },
++ .probe = rpi_power_probe,
++};
++builtin_platform_driver(rpi_power_driver);
++
++MODULE_AUTHOR("Alexander Aring <aar@pengutronix.de>");
++MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
++MODULE_DESCRIPTION("Raspberry Pi power domain driver");
++MODULE_LICENSE("GPL v2");
+--- /dev/null
++++ b/include/dt-bindings/power/raspberrypi-power.h
+@@ -0,0 +1,41 @@
++/*
++ * Copyright © 2015 Broadcom
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#ifndef _DT_BINDINGS_ARM_BCM2835_RPI_POWER_H
++#define _DT_BINDINGS_ARM_BCM2835_RPI_POWER_H
++
++/* These power domain indices are the firmware interface's indices
++ * minus one.
++ */
++#define RPI_POWER_DOMAIN_I2C0 0
++#define RPI_POWER_DOMAIN_I2C1 1
++#define RPI_POWER_DOMAIN_I2C2 2
++#define RPI_POWER_DOMAIN_VIDEO_SCALER 3
++#define RPI_POWER_DOMAIN_VPU1 4
++#define RPI_POWER_DOMAIN_HDMI 5
++#define RPI_POWER_DOMAIN_USB 6
++#define RPI_POWER_DOMAIN_VEC 7
++#define RPI_POWER_DOMAIN_JPEG 8
++#define RPI_POWER_DOMAIN_H264 9
++#define RPI_POWER_DOMAIN_V3D 10
++#define RPI_POWER_DOMAIN_ISP 11
++#define RPI_POWER_DOMAIN_UNICAM0 12
++#define RPI_POWER_DOMAIN_UNICAM1 13
++#define RPI_POWER_DOMAIN_CCP2RX 14
++#define RPI_POWER_DOMAIN_CSI2 15
++#define RPI_POWER_DOMAIN_CPI 16
++#define RPI_POWER_DOMAIN_DSI0 17
++#define RPI_POWER_DOMAIN_DSI1 18
++#define RPI_POWER_DOMAIN_TRANSPOSER 19
++#define RPI_POWER_DOMAIN_CCP2TX 20
++#define RPI_POWER_DOMAIN_CDP 21
++#define RPI_POWER_DOMAIN_ARM 22
++
++#define RPI_POWER_DOMAIN_COUNT 23
++
++#endif /* _DT_BINDINGS_ARM_BCM2835_RPI_POWER_H */
diff --git a/target/linux/brcm2708/patches-4.4/0269-ARM-bcm2835-clarify-RASPBERRYPI_FIRMWARE-dependency.patch b/target/linux/brcm2708/patches-4.4/0269-ARM-bcm2835-clarify-RASPBERRYPI_FIRMWARE-dependency.patch
new file mode 100644
index 0000000000..e1e6240918
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0269-ARM-bcm2835-clarify-RASPBERRYPI_FIRMWARE-dependency.patch
@@ -0,0 +1,36 @@
+From 9cfa49abaf59e6f41da47f37caae6075741ca876 Mon Sep 17 00:00:00 2001
+From: Arnd Bergmann <arnd@arndb.de>
+Date: Thu, 31 Dec 2015 23:39:14 +0100
+Subject: [PATCH 269/381] ARM: bcm2835: clarify RASPBERRYPI_FIRMWARE dependency
+
+The firmware driver can be a loadable module, but the power domain
+can only be built-in, so we get a build error in an allmodconfig
+kernel:
+
+:(.text+0x17e59c): undefined reference to `rpi_firmware_property'
+:(.text+0x17e51c): undefined reference to `rpi_firmware_get'
+:(.text+0x17e244): undefined reference to `rpi_firmware_property'
+
+This changes the dependency to only allow the power domain code
+to be enabled when the firmware driver is built-in. Other users
+of the firmware driver may still be loadable modules and not
+everyone needs the power domains, so we don't change the firmware
+code.
+
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+(cherry picked from commit 22a5b1ddd83b991b96cb635898e011cce48bf6f8)
+---
+ drivers/soc/bcm/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/soc/bcm/Kconfig
++++ b/drivers/soc/bcm/Kconfig
+@@ -1,7 +1,7 @@
+ config RASPBERRYPI_POWER
+ bool "Raspberry Pi power domain driver"
+ depends on ARCH_BCM2835 || COMPILE_TEST
+- depends on RASPBERRYPI_FIRMWARE
++ depends on RASPBERRYPI_FIRMWARE=y
+ select PM_GENERIC_DOMAINS if PM
+ select PM_GENERIC_DOMAINS_OF if PM
+ help
diff --git a/target/linux/brcm2708/patches-4.4/0270-ARM-bcm2708-Enable-building-power-domain-driver.patch b/target/linux/brcm2708/patches-4.4/0270-ARM-bcm2708-Enable-building-power-domain-driver.patch
new file mode 100644
index 0000000000..0b931cd7bb
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0270-ARM-bcm2708-Enable-building-power-domain-driver.patch
@@ -0,0 +1,20 @@
+From 61c99da55170241f7d06ba6dc86630ae1890bea9 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Tue, 19 Apr 2016 15:55:02 -0700
+Subject: [PATCH 270/381] ARM: bcm2708: Enable building power domain driver.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/soc/bcm/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/soc/bcm/Kconfig
++++ b/drivers/soc/bcm/Kconfig
+@@ -1,6 +1,6 @@
+ config RASPBERRYPI_POWER
+ bool "Raspberry Pi power domain driver"
+- depends on ARCH_BCM2835 || COMPILE_TEST
++ depends on ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709 || COMPILE_TEST
+ depends on RASPBERRYPI_FIRMWARE=y
+ select PM_GENERIC_DOMAINS if PM
+ select PM_GENERIC_DOMAINS_OF if PM
diff --git a/target/linux/brcm2708/patches-4.4/0271-bcm2708-Add-RASPBERRYPI_POWER-to-the-defconfigs.patch b/target/linux/brcm2708/patches-4.4/0271-bcm2708-Add-RASPBERRYPI_POWER-to-the-defconfigs.patch
new file mode 100644
index 0000000000..33434ef34c
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0271-bcm2708-Add-RASPBERRYPI_POWER-to-the-defconfigs.patch
@@ -0,0 +1,50 @@
+From 0d2dc82a9fe4a2325df235180812065bcb47c3a6 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Tue, 19 Apr 2016 14:23:30 -0700
+Subject: [PATCH 271/381] bcm2708: Add RASPBERRYPI_POWER to the defconfigs.
+
+This will be used by the GPU driver for powering on HDMI at boot time
+and for 3D hang reset.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ arch/arm/configs/bcm2709_defconfig | 2 ++
+ arch/arm/configs/bcmrpi_defconfig | 2 ++
+ 2 files changed, 4 insertions(+)
+
+--- a/arch/arm/configs/bcm2709_defconfig
++++ b/arch/arm/configs/bcm2709_defconfig
+@@ -71,6 +71,7 @@ CONFIG_NEON=y
+ CONFIG_KERNEL_MODE_NEON=y
+ CONFIG_BINFMT_MISC=m
+ # CONFIG_SUSPEND is not set
++CONFIG_PM=y
+ CONFIG_NET=y
+ CONFIG_PACKET=y
+ CONFIG_UNIX=y
+@@ -1116,6 +1117,7 @@ CONFIG_FB_TFT_FBTFT_DEVICE=m
+ CONFIG_MAILBOX=y
+ CONFIG_BCM2835_MBOX=y
+ # CONFIG_IOMMU_SUPPORT is not set
++CONFIG_RASPBERRYPI_POWER=y
+ CONFIG_EXTCON=m
+ CONFIG_EXTCON_ARIZONA=m
+ CONFIG_IIO=m
+--- a/arch/arm/configs/bcmrpi_defconfig
++++ b/arch/arm/configs/bcmrpi_defconfig
+@@ -64,6 +64,7 @@ CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+ CONFIG_VFP=y
+ CONFIG_BINFMT_MISC=m
+ # CONFIG_SUSPEND is not set
++CONFIG_PM=y
+ CONFIG_NET=y
+ CONFIG_PACKET=y
+ CONFIG_UNIX=y
+@@ -1123,6 +1124,7 @@ CONFIG_FB_TFT_FBTFT_DEVICE=m
+ CONFIG_MAILBOX=y
+ CONFIG_BCM2835_MBOX=y
+ # CONFIG_IOMMU_SUPPORT is not set
++CONFIG_RASPBERRYPI_POWER=y
+ CONFIG_EXTCON=m
+ CONFIG_EXTCON_ARIZONA=m
+ CONFIG_IIO=m
diff --git a/target/linux/brcm2708/patches-4.4/0272-bcm2708-Add-the-power-domain-driver-to-the-device-tr.patch b/target/linux/brcm2708/patches-4.4/0272-bcm2708-Add-the-power-domain-driver-to-the-device-tr.patch
new file mode 100644
index 0000000000..8f4099226d
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0272-bcm2708-Add-the-power-domain-driver-to-the-device-tr.patch
@@ -0,0 +1,26 @@
+From 4eb2de8729beeae668d522478da951d1da91c42f Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Tue, 19 Apr 2016 14:36:31 -0700
+Subject: [PATCH 272/381] bcm2708: Add the power domain driver to the device
+ tree.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ arch/arm/boot/dts/bcm2708_common.dtsi | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/arch/arm/boot/dts/bcm2708_common.dtsi
++++ b/arch/arm/boot/dts/bcm2708_common.dtsi
+@@ -285,6 +285,12 @@
+ mboxes = <&mailbox>;
+ };
+
++ power: power {
++ compatible = "raspberrypi,bcm2835-power";
++ firmware = <&firmware>;
++ #power-domain-cells = <1>;
++ };
++
+ leds: leds {
+ compatible = "gpio-leds";
+ };
diff --git a/target/linux/brcm2708/patches-4.4/0273-bcm2708-Reference-the-HDMI-power-domain-for-the-HDMI.patch b/target/linux/brcm2708/patches-4.4/0273-bcm2708-Reference-the-HDMI-power-domain-for-the-HDMI.patch
new file mode 100644
index 0000000000..cef542b6c6
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0273-bcm2708-Reference-the-HDMI-power-domain-for-the-HDMI.patch
@@ -0,0 +1,29 @@
+From 9cdbf88aabf547503f85cc5b815b7b0dec444b3f Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Tue, 19 Apr 2016 14:40:08 -0700
+Subject: [PATCH 273/381] bcm2708: Reference the HDMI power domain for the HDMI
+ driver.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts
++++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts
+@@ -6,6 +6,7 @@
+ /plugin/;
+
+ #include "dt-bindings/clock/bcm2835.h"
++#include "dt-bindings/power/raspberrypi-power.h"
+ #include "dt-bindings/gpio/gpio.h"
+
+ / {
+@@ -72,6 +73,7 @@
+ clocks = <&cprman BCM2835_PLLH_PIX>,
+ <&cprman BCM2835_CLOCK_HSM>;
+ clock-names = "pixel", "hdmi";
++ power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
+ };
+
+ v3d@7ec00000 {
diff --git a/target/linux/brcm2708/patches-4.4/0274-drm-vc4-copy_to_user-returns-the-number-of-bytes-rem.patch b/target/linux/brcm2708/patches-4.4/0274-drm-vc4-copy_to_user-returns-the-number-of-bytes-rem.patch
new file mode 100644
index 0000000000..9df58b50da
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0274-drm-vc4-copy_to_user-returns-the-number-of-bytes-rem.patch
@@ -0,0 +1,87 @@
+From 2a995481084f14aa22c1f141d6494d87cb100703 Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <dan.carpenter@oracle.com>
+Date: Thu, 17 Dec 2015 15:36:28 +0300
+Subject: [PATCH 274/381] drm/vc4: copy_to_user() returns the number of bytes
+ remaining
+
+The copy_to/from_user() functions return the number of bytes remaining
+to be copied. We want to return error codes here.
+
+Also it's a bad idea to print an error message if a copy from user fails
+because users can use that to spam /var/log/messages which is annoying
+so I removed those.
+
+Fixes: 214613656b51 ('drm/vc4: Add an interface for capturing the GPU state after a hang.')
+Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
+Reviewed-by: Eric Anholt <eric@anholt.net>
+(cherry picked from commit 65c4777de54a39b2722a4b1ff3306d044014d511)
+---
+ drivers/gpu/drm/vc4/vc4_gem.c | 37 ++++++++++++++++++-------------------
+ 1 file changed, 18 insertions(+), 19 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_gem.c
++++ b/drivers/gpu/drm/vc4/vc4_gem.c
+@@ -85,7 +85,7 @@ vc4_get_hang_state_ioctl(struct drm_devi
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ unsigned long irqflags;
+ u32 i;
+- int ret;
++ int ret = 0;
+
+ spin_lock_irqsave(&vc4->job_lock, irqflags);
+ kernel_state = vc4->hang_state;
+@@ -133,9 +133,11 @@ vc4_get_hang_state_ioctl(struct drm_devi
+ bo_state[i].size = vc4_bo->base.base.size;
+ }
+
+- ret = copy_to_user((void __user *)(uintptr_t)get_state->bo,
+- bo_state,
+- state->bo_count * sizeof(*bo_state));
++ if (copy_to_user((void __user *)(uintptr_t)get_state->bo,
++ bo_state,
++ state->bo_count * sizeof(*bo_state)))
++ ret = -EFAULT;
++
+ kfree(bo_state);
+
+ err_free:
+@@ -563,27 +565,24 @@ vc4_get_bcl(struct drm_device *dev, stru
+ exec->shader_state = temp + exec_size;
+ exec->shader_state_size = args->shader_rec_count;
+
+- ret = copy_from_user(bin,
+- (void __user *)(uintptr_t)args->bin_cl,
+- args->bin_cl_size);
+- if (ret) {
+- DRM_ERROR("Failed to copy in bin cl\n");
++ if (copy_from_user(bin,
++ (void __user *)(uintptr_t)args->bin_cl,
++ args->bin_cl_size)) {
++ ret = -EFAULT;
+ goto fail;
+ }
+
+- ret = copy_from_user(exec->shader_rec_u,
+- (void __user *)(uintptr_t)args->shader_rec,
+- args->shader_rec_size);
+- if (ret) {
+- DRM_ERROR("Failed to copy in shader recs\n");
++ if (copy_from_user(exec->shader_rec_u,
++ (void __user *)(uintptr_t)args->shader_rec,
++ args->shader_rec_size)) {
++ ret = -EFAULT;
+ goto fail;
+ }
+
+- ret = copy_from_user(exec->uniforms_u,
+- (void __user *)(uintptr_t)args->uniforms,
+- args->uniforms_size);
+- if (ret) {
+- DRM_ERROR("Failed to copy in uniforms cl\n");
++ if (copy_from_user(exec->uniforms_u,
++ (void __user *)(uintptr_t)args->uniforms,
++ args->uniforms_size)) {
++ ret = -EFAULT;
+ goto fail;
+ }
+
diff --git a/target/linux/brcm2708/patches-4.4/0275-drm-vc4-allocate-enough-memory-in-vc4_save_hang_stat.patch b/target/linux/brcm2708/patches-4.4/0275-drm-vc4-allocate-enough-memory-in-vc4_save_hang_stat.patch
new file mode 100644
index 0000000000..02db6b50ad
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0275-drm-vc4-allocate-enough-memory-in-vc4_save_hang_stat.patch
@@ -0,0 +1,27 @@
+From c33b2893076c1ff4decffd300f84aaa2cc10d1a4 Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <dan.carpenter@oracle.com>
+Date: Thu, 17 Dec 2015 15:39:08 +0300
+Subject: [PATCH 275/381] drm/vc4: allocate enough memory in
+ vc4_save_hang_state()
+
+"state" is smaller than "kernel_state" so we end up corrupting memory.
+
+Fixes: 214613656b51 ('drm/vc4: Add an interface for capturing the GPU state after a hang.')
+Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
+Reviewed-by: Eric Anholt <eric@anholt.net>
+(cherry picked from commit 7e5082fbc00cc157e57a70cdb6b9bbb21289afb1)
+---
+ drivers/gpu/drm/vc4/vc4_gem.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_gem.c
++++ b/drivers/gpu/drm/vc4/vc4_gem.c
+@@ -159,7 +159,7 @@ vc4_save_hang_state(struct drm_device *d
+ unsigned long irqflags;
+ unsigned int i, unref_list_count;
+
+- kernel_state = kcalloc(1, sizeof(*state), GFP_KERNEL);
++ kernel_state = kcalloc(1, sizeof(*kernel_state), GFP_KERNEL);
+ if (!kernel_state)
+ return;
+
diff --git a/target/linux/brcm2708/patches-4.4/0276-drm-vc4-fix-warning-in-validate-printf.patch b/target/linux/brcm2708/patches-4.4/0276-drm-vc4-fix-warning-in-validate-printf.patch
new file mode 100644
index 0000000000..da968e6b71
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0276-drm-vc4-fix-warning-in-validate-printf.patch
@@ -0,0 +1,32 @@
+From 903b74d1a831985eced17d72de1634143031a077 Mon Sep 17 00:00:00 2001
+From: Dave Airlie <airlied@redhat.com>
+Date: Mon, 18 Jan 2016 09:10:42 +1000
+Subject: [PATCH 276/381] drm/vc4: fix warning in validate printf.
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This just fixes a warning on 64-bit builds:
+
+ drivers/gpu/drm/vc4/vc4_validate.c: In function ‘validate_gl_shader_rec’:
+ drivers/gpu/drm/vc4/vc4_validate.c:864:12: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘size_t {aka long unsigned int}’ [-Wformat=]
+
+Reported-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Dave Airlie <airlied@redhat.com>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+(cherry picked from commit c671e1e30259da587d7a0162895200601979ee65)
+---
+ drivers/gpu/drm/vc4/vc4_validate.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_validate.c
++++ b/drivers/gpu/drm/vc4/vc4_validate.c
+@@ -861,7 +861,7 @@ validate_gl_shader_rec(struct drm_device
+
+ if (vbo->base.size < offset ||
+ vbo->base.size - offset < attr_size) {
+- DRM_ERROR("BO offset overflow (%d + %d > %d)\n",
++ DRM_ERROR("BO offset overflow (%d + %d > %zu)\n",
+ offset, attr_size, vbo->base.size);
+ return -EINVAL;
+ }
diff --git a/target/linux/brcm2708/patches-4.4/0277-drm-vc4-Improve-comments-on-vc4_plane_state-members.patch b/target/linux/brcm2708/patches-4.4/0277-drm-vc4-Improve-comments-on-vc4_plane_state-members.patch
new file mode 100644
index 0000000000..0f3599f690
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0277-drm-vc4-Improve-comments-on-vc4_plane_state-members.patch
@@ -0,0 +1,36 @@
+From 0580ea4ba574d30d1725649a28ab3466904599ea Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 28 Dec 2015 14:14:09 -0800
+Subject: [PATCH 277/381] drm/vc4: Improve comments on vc4_plane_state members.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+(cherry picked from commit f427fb16cf756548c39256b569cf083f39bcc4e9)
+---
+ drivers/gpu/drm/vc4/vc4_plane.c | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_plane.c
++++ b/drivers/gpu/drm/vc4/vc4_plane.c
+@@ -26,16 +26,19 @@
+
+ struct vc4_plane_state {
+ struct drm_plane_state base;
++ /* System memory copy of the display list for this element, computed
++ * at atomic_check time.
++ */
+ u32 *dlist;
+- u32 dlist_size; /* Number of dwords in allocated for the display list */
++ u32 dlist_size; /* Number of dwords allocated for the display list */
+ u32 dlist_count; /* Number of used dwords in the display list. */
+
+ /* Offset in the dlist to pointer word 0. */
+ u32 pw0_offset;
+
+ /* Offset where the plane's dlist was last stored in the
+- hardware at vc4_crtc_atomic_flush() time.
+- */
++ * hardware at vc4_crtc_atomic_flush() time.
++ */
+ u32 *hw_dlist;
+ };
+
diff --git a/target/linux/brcm2708/patches-4.4/0278-drm-vc4-Add-missing-__iomem-annotation-to-hw_dlist.patch b/target/linux/brcm2708/patches-4.4/0278-drm-vc4-Add-missing-__iomem-annotation-to-hw_dlist.patch
new file mode 100644
index 0000000000..ccd7b233ee
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0278-drm-vc4-Add-missing-__iomem-annotation-to-hw_dlist.patch
@@ -0,0 +1,25 @@
+From 05edbd5f865d1c6a92bc3dcf59af28bbdb362a9f Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 28 Dec 2015 14:14:57 -0800
+Subject: [PATCH 278/381] drm/vc4: Add missing __iomem annotation to hw_dlist.
+
+This is the pointer to the HVS device's memory where we stored the
+contents of *dlist.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+(cherry picked from commit 17eac75111ebda33e13d8d8d98aaedfc1a9c2abf)
+---
+ drivers/gpu/drm/vc4/vc4_plane.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_plane.c
++++ b/drivers/gpu/drm/vc4/vc4_plane.c
+@@ -39,7 +39,7 @@ struct vc4_plane_state {
+ /* Offset where the plane's dlist was last stored in the
+ * hardware at vc4_crtc_atomic_flush() time.
+ */
+- u32 *hw_dlist;
++ u32 __iomem *hw_dlist;
+ };
+
+ static inline struct vc4_plane_state *
diff --git a/target/linux/brcm2708/patches-4.4/0279-drm-vc4-Move-the-plane-clipping-scaling-setup-to-a-s.patch b/target/linux/brcm2708/patches-4.4/0279-drm-vc4-Move-the-plane-clipping-scaling-setup-to-a-s.patch
new file mode 100644
index 0000000000..1410a874c3
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0279-drm-vc4-Move-the-plane-clipping-scaling-setup-to-a-s.patch
@@ -0,0 +1,143 @@
+From 647c62f1d368e2418d8abc6ea11c0c1bac7fae11 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 28 Dec 2015 14:34:44 -0800
+Subject: [PATCH 279/381] drm/vc4: Move the plane clipping/scaling setup to a
+ separate function.
+
+As we add actual scaling, this is going to get way more complicated.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+(cherry picked from commit 5c6799942003df91801b1d2277bba34d71f99603)
+---
+ drivers/gpu/drm/vc4/vc4_plane.c | 78 +++++++++++++++++++++++++++--------------
+ 1 file changed, 52 insertions(+), 26 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_plane.c
++++ b/drivers/gpu/drm/vc4/vc4_plane.c
+@@ -40,6 +40,14 @@ struct vc4_plane_state {
+ * hardware at vc4_crtc_atomic_flush() time.
+ */
+ u32 __iomem *hw_dlist;
++
++ /* Clipped coordinates of the plane on the display. */
++ int crtc_x, crtc_y, crtc_w, crtc_h;
++
++ /* Offset to start scanning out from the start of the plane's
++ * BO.
++ */
++ u32 offset;
+ };
+
+ static inline struct vc4_plane_state *
+@@ -167,22 +175,17 @@ static void vc4_dlist_write(struct vc4_p
+ vc4_state->dlist[vc4_state->dlist_count++] = val;
+ }
+
+-/* Writes out a full display list for an active plane to the plane's
+- * private dlist state.
+- */
+-static int vc4_plane_mode_set(struct drm_plane *plane,
+- struct drm_plane_state *state)
++static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
+ {
+ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
+ struct drm_framebuffer *fb = state->fb;
+- struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
+- u32 ctl0_offset = vc4_state->dlist_count;
+- const struct hvs_format *format = vc4_get_hvs_format(fb->pixel_format);
+- uint32_t offset = fb->offsets[0];
+- int crtc_x = state->crtc_x;
+- int crtc_y = state->crtc_y;
+- int crtc_w = state->crtc_w;
+- int crtc_h = state->crtc_h;
++
++ vc4_state->offset = fb->offsets[0];
++
++ vc4_state->crtc_x = state->crtc_x;
++ vc4_state->crtc_y = state->crtc_y;
++ vc4_state->crtc_w = state->crtc_w;
++ vc4_state->crtc_h = state->crtc_h;
+
+ if (state->crtc_w << 16 != state->src_w ||
+ state->crtc_h << 16 != state->src_h) {
+@@ -194,18 +197,41 @@ static int vc4_plane_mode_set(struct drm
+ return -EINVAL;
+ }
+
+- if (crtc_x < 0) {
+- offset += drm_format_plane_cpp(fb->pixel_format, 0) * -crtc_x;
+- crtc_w += crtc_x;
+- crtc_x = 0;
++ if (vc4_state->crtc_x < 0) {
++ vc4_state->offset += (drm_format_plane_cpp(fb->pixel_format,
++ 0) *
++ -vc4_state->crtc_x);
++ vc4_state->crtc_w += vc4_state->crtc_x;
++ vc4_state->crtc_x = 0;
+ }
+
+- if (crtc_y < 0) {
+- offset += fb->pitches[0] * -crtc_y;
+- crtc_h += crtc_y;
+- crtc_y = 0;
++ if (vc4_state->crtc_y < 0) {
++ vc4_state->offset += fb->pitches[0] * -vc4_state->crtc_y;
++ vc4_state->crtc_h += vc4_state->crtc_y;
++ vc4_state->crtc_y = 0;
+ }
+
++ return 0;
++}
++
++
++/* Writes out a full display list for an active plane to the plane's
++ * private dlist state.
++ */
++static int vc4_plane_mode_set(struct drm_plane *plane,
++ struct drm_plane_state *state)
++{
++ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
++ struct drm_framebuffer *fb = state->fb;
++ struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
++ u32 ctl0_offset = vc4_state->dlist_count;
++ const struct hvs_format *format = vc4_get_hvs_format(fb->pixel_format);
++ int ret;
++
++ ret = vc4_plane_setup_clipping_and_scaling(state);
++ if (ret)
++ return ret;
++
+ vc4_dlist_write(vc4_state,
+ SCALER_CTL0_VALID |
+ (format->pixel_order << SCALER_CTL0_ORDER_SHIFT) |
+@@ -215,8 +241,8 @@ static int vc4_plane_mode_set(struct drm
+ /* Position Word 0: Image Positions and Alpha Value */
+ vc4_dlist_write(vc4_state,
+ VC4_SET_FIELD(0xff, SCALER_POS0_FIXED_ALPHA) |
+- VC4_SET_FIELD(crtc_x, SCALER_POS0_START_X) |
+- VC4_SET_FIELD(crtc_y, SCALER_POS0_START_Y));
++ VC4_SET_FIELD(vc4_state->crtc_x, SCALER_POS0_START_X) |
++ VC4_SET_FIELD(vc4_state->crtc_y, SCALER_POS0_START_Y));
+
+ /* Position Word 1: Scaled Image Dimensions.
+ * Skipped due to SCALER_CTL0_UNITY scaling.
+@@ -228,8 +254,8 @@ static int vc4_plane_mode_set(struct drm
+ SCALER_POS2_ALPHA_MODE_PIPELINE :
+ SCALER_POS2_ALPHA_MODE_FIXED,
+ SCALER_POS2_ALPHA_MODE) |
+- VC4_SET_FIELD(crtc_w, SCALER_POS2_WIDTH) |
+- VC4_SET_FIELD(crtc_h, SCALER_POS2_HEIGHT));
++ VC4_SET_FIELD(vc4_state->crtc_w, SCALER_POS2_WIDTH) |
++ VC4_SET_FIELD(vc4_state->crtc_h, SCALER_POS2_HEIGHT));
+
+ /* Position Word 3: Context. Written by the HVS. */
+ vc4_dlist_write(vc4_state, 0xc0c0c0c0);
+@@ -237,7 +263,7 @@ static int vc4_plane_mode_set(struct drm
+ vc4_state->pw0_offset = vc4_state->dlist_count;
+
+ /* Pointer Word 0: RGB / Y Pointer */
+- vc4_dlist_write(vc4_state, bo->paddr + offset);
++ vc4_dlist_write(vc4_state, bo->paddr + vc4_state->offset);
+
+ /* Pointer Context Word 0: Written by the HVS */
+ vc4_dlist_write(vc4_state, 0xc0c0c0c0);
diff --git a/target/linux/brcm2708/patches-4.4/0280-drm-vc4-Add-a-proper-short-circut-path-for-legacy-cu.patch b/target/linux/brcm2708/patches-4.4/0280-drm-vc4-Add-a-proper-short-circut-path-for-legacy-cu.patch
new file mode 100644
index 0000000000..645a7a4260
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0280-drm-vc4-Add-a-proper-short-circut-path-for-legacy-cu.patch
@@ -0,0 +1,192 @@
+From bdd4e13374cb436ccb534f5f58bd840e7d055ec9 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Wed, 30 Dec 2015 11:50:22 -0800
+Subject: [PATCH 280/381] drm/vc4: Add a proper short-circut path for legacy
+ cursor updates.
+
+Previously, on every modeset we would allocate new display list
+memory, recompute changed planes, write all of them to the new memory,
+and pointed scanout at the new list (which will latch approximately at
+the next line of scanout). We let
+drm_atomic_helper_wait_for_vblanks() decide whether we needed to wait
+for a vblank after a modeset before cleaning up the old state and
+letting the next modeset proceed, and on legacy cursor updates we
+wouldn't wait. If you moved the cursor fast enough, we could
+potentially wrap around the display list memory area and overwrite the
+existing display list while it was still being scanned out, resulting
+in the HVS scanning out garbage or just halting.
+
+Instead of making cursor updates wait for scanout to move to the new
+display list area (which introduces significant cursor lag in X), we
+just rewrite our current display list.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+(cherry picked from commit 6674a904d68041d982ffb284d2827410765a097a)
+---
+ drivers/gpu/drm/vc4/vc4_kms.c | 9 ++++
+ drivers/gpu/drm/vc4/vc4_plane.c | 94 ++++++++++++++++++++++++++++++++++++++---
+ 2 files changed, 96 insertions(+), 7 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_kms.c
+@@ -49,6 +49,15 @@ vc4_atomic_complete_commit(struct vc4_co
+
+ drm_atomic_helper_commit_modeset_enables(dev, state);
+
++ /* Make sure that drm_atomic_helper_wait_for_vblanks()
++ * actually waits for vblank. If we're doing a full atomic
++ * modeset (as opposed to a vc4_update_plane() short circuit),
++ * then we need to wait for scanout to be done with our
++ * display lists before we free it and potentially reallocate
++ * and overwrite the dlist memory with a new modeset.
++ */
++ state->legacy_cursor_update = false;
++
+ drm_atomic_helper_wait_for_vblanks(dev, state);
+
+ drm_atomic_helper_cleanup_planes(dev, state);
+--- a/drivers/gpu/drm/vc4/vc4_plane.c
++++ b/drivers/gpu/drm/vc4/vc4_plane.c
+@@ -33,8 +33,12 @@ struct vc4_plane_state {
+ u32 dlist_size; /* Number of dwords allocated for the display list */
+ u32 dlist_count; /* Number of used dwords in the display list. */
+
+- /* Offset in the dlist to pointer word 0. */
+- u32 pw0_offset;
++ /* Offset in the dlist to various words, for pageflip or
++ * cursor updates.
++ */
++ u32 pos0_offset;
++ u32 pos2_offset;
++ u32 ptr0_offset;
+
+ /* Offset where the plane's dlist was last stored in the
+ * hardware at vc4_crtc_atomic_flush() time.
+@@ -239,6 +243,7 @@ static int vc4_plane_mode_set(struct drm
+ SCALER_CTL0_UNITY);
+
+ /* Position Word 0: Image Positions and Alpha Value */
++ vc4_state->pos0_offset = vc4_state->dlist_count;
+ vc4_dlist_write(vc4_state,
+ VC4_SET_FIELD(0xff, SCALER_POS0_FIXED_ALPHA) |
+ VC4_SET_FIELD(vc4_state->crtc_x, SCALER_POS0_START_X) |
+@@ -249,6 +254,7 @@ static int vc4_plane_mode_set(struct drm
+ */
+
+ /* Position Word 2: Source Image Size, Alpha Mode */
++ vc4_state->pos2_offset = vc4_state->dlist_count;
+ vc4_dlist_write(vc4_state,
+ VC4_SET_FIELD(format->has_alpha ?
+ SCALER_POS2_ALPHA_MODE_PIPELINE :
+@@ -260,9 +266,8 @@ static int vc4_plane_mode_set(struct drm
+ /* Position Word 3: Context. Written by the HVS. */
+ vc4_dlist_write(vc4_state, 0xc0c0c0c0);
+
+- vc4_state->pw0_offset = vc4_state->dlist_count;
+-
+ /* Pointer Word 0: RGB / Y Pointer */
++ vc4_state->ptr0_offset = vc4_state->dlist_count;
+ vc4_dlist_write(vc4_state, bo->paddr + vc4_state->offset);
+
+ /* Pointer Context Word 0: Written by the HVS */
+@@ -348,13 +353,13 @@ void vc4_plane_async_set_fb(struct drm_p
+ * scanout will start from this address as soon as the FIFO
+ * needs to refill with pixels.
+ */
+- writel(addr, &vc4_state->hw_dlist[vc4_state->pw0_offset]);
++ writel(addr, &vc4_state->hw_dlist[vc4_state->ptr0_offset]);
+
+ /* Also update the CPU-side dlist copy, so that any later
+ * atomic updates that don't do a new modeset on our plane
+ * also use our updated address.
+ */
+- vc4_state->dlist[vc4_state->pw0_offset] = addr;
++ vc4_state->dlist[vc4_state->ptr0_offset] = addr;
+ }
+
+ static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
+@@ -370,8 +375,83 @@ static void vc4_plane_destroy(struct drm
+ drm_plane_cleanup(plane);
+ }
+
++/* Implements immediate (non-vblank-synced) updates of the cursor
++ * position, or falls back to the atomic helper otherwise.
++ */
++static int
++vc4_update_plane(struct drm_plane *plane,
++ struct drm_crtc *crtc,
++ struct drm_framebuffer *fb,
++ int crtc_x, int crtc_y,
++ unsigned int crtc_w, unsigned int crtc_h,
++ uint32_t src_x, uint32_t src_y,
++ uint32_t src_w, uint32_t src_h)
++{
++ struct drm_plane_state *plane_state;
++ struct vc4_plane_state *vc4_state;
++
++ if (plane != crtc->cursor)
++ goto out;
++
++ plane_state = plane->state;
++ vc4_state = to_vc4_plane_state(plane_state);
++
++ if (!plane_state)
++ goto out;
++
++ /* If we're changing the cursor contents, do that in the
++ * normal vblank-synced atomic path.
++ */
++ if (fb != plane_state->fb)
++ goto out;
++
++ /* No configuring new scaling in the fast path. */
++ if (crtc_w != plane_state->crtc_w ||
++ crtc_h != plane_state->crtc_h ||
++ src_w != plane_state->src_w ||
++ src_h != plane_state->src_h) {
++ goto out;
++ }
++
++ /* Set the cursor's position on the screen. This is the
++ * expected change from the drm_mode_cursor_universal()
++ * helper.
++ */
++ plane_state->crtc_x = crtc_x;
++ plane_state->crtc_y = crtc_y;
++
++ /* Allow changing the start position within the cursor BO, if
++ * that matters.
++ */
++ plane_state->src_x = src_x;
++ plane_state->src_y = src_y;
++
++ /* Update the display list based on the new crtc_x/y. */
++ vc4_plane_atomic_check(plane, plane_state);
++
++ /* Note that we can't just call vc4_plane_write_dlist()
++ * because that would smash the context data that the HVS is
++ * currently using.
++ */
++ writel(vc4_state->dlist[vc4_state->pos0_offset],
++ &vc4_state->hw_dlist[vc4_state->pos0_offset]);
++ writel(vc4_state->dlist[vc4_state->pos2_offset],
++ &vc4_state->hw_dlist[vc4_state->pos2_offset]);
++ writel(vc4_state->dlist[vc4_state->ptr0_offset],
++ &vc4_state->hw_dlist[vc4_state->ptr0_offset]);
++
++ return 0;
++
++out:
++ return drm_atomic_helper_update_plane(plane, crtc, fb,
++ crtc_x, crtc_y,
++ crtc_w, crtc_h,
++ src_x, src_y,
++ src_w, src_h);
++}
++
+ static const struct drm_plane_funcs vc4_plane_funcs = {
+- .update_plane = drm_atomic_helper_update_plane,
++ .update_plane = vc4_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .destroy = vc4_plane_destroy,
+ .set_property = NULL,
diff --git a/target/linux/brcm2708/patches-4.4/0281-drm-vc4-Make-the-CRTCs-cooperate-on-allocating-displ.patch b/target/linux/brcm2708/patches-4.4/0281-drm-vc4-Make-the-CRTCs-cooperate-on-allocating-displ.patch
new file mode 100644
index 0000000000..76afc10550
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0281-drm-vc4-Make-the-CRTCs-cooperate-on-allocating-displ.patch
@@ -0,0 +1,248 @@
+From 645f9aea7c4c7880059f87a715a8bdd004ef9604 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 28 Dec 2015 13:25:41 -0800
+Subject: [PATCH 281/381] drm/vc4: Make the CRTCs cooperate on allocating
+ display lists.
+
+So far, we've only ever lit up one CRTC, so this has been fine. To
+extend to more displays or more planes, we need to make sure we don't
+run our display lists into each other.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+(cherry picked from commit d8dbf44f13b91185c618219d912b246817a8d132)
+---
+ drivers/gpu/drm/vc4/vc4_crtc.c | 115 +++++++++++++++++++++++------------------
+ drivers/gpu/drm/vc4/vc4_drv.h | 8 ++-
+ drivers/gpu/drm/vc4/vc4_hvs.c | 13 +++++
+ 3 files changed, 84 insertions(+), 52 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_crtc.c
++++ b/drivers/gpu/drm/vc4/vc4_crtc.c
+@@ -49,22 +49,27 @@ struct vc4_crtc {
+ /* Which HVS channel we're using for our CRTC. */
+ int channel;
+
+- /* Pointer to the actual hardware display list memory for the
+- * crtc.
+- */
+- u32 __iomem *dlist;
+-
+- u32 dlist_size; /* in dwords */
+-
+ struct drm_pending_vblank_event *event;
+ };
+
++struct vc4_crtc_state {
++ struct drm_crtc_state base;
++ /* Dlist area for this CRTC configuration. */
++ struct drm_mm_node mm;
++};
++
+ static inline struct vc4_crtc *
+ to_vc4_crtc(struct drm_crtc *crtc)
+ {
+ return (struct vc4_crtc *)crtc;
+ }
+
++static inline struct vc4_crtc_state *
++to_vc4_crtc_state(struct drm_crtc_state *crtc_state)
++{
++ return (struct vc4_crtc_state *)crtc_state;
++}
++
+ struct vc4_crtc_data {
+ /* Which channel of the HVS this pixelvalve sources from. */
+ int hvs_channel;
+@@ -319,11 +324,13 @@ static void vc4_crtc_enable(struct drm_c
+ static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+ {
++ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
+ struct drm_device *dev = crtc->dev;
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ struct drm_plane *plane;
+- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
++ unsigned long flags;
+ u32 dlist_count = 0;
++ int ret;
+
+ /* The pixelvalve can only feed one encoder (and encoders are
+ * 1:1 with connectors.)
+@@ -346,18 +353,12 @@ static int vc4_crtc_atomic_check(struct
+
+ dlist_count++; /* Account for SCALER_CTL0_END. */
+
+- if (!vc4_crtc->dlist || dlist_count > vc4_crtc->dlist_size) {
+- vc4_crtc->dlist = ((u32 __iomem *)vc4->hvs->dlist +
+- HVS_BOOTLOADER_DLIST_END);
+- vc4_crtc->dlist_size = ((SCALER_DLIST_SIZE >> 2) -
+- HVS_BOOTLOADER_DLIST_END);
+-
+- if (dlist_count > vc4_crtc->dlist_size) {
+- DRM_DEBUG_KMS("dlist too large for CRTC (%d > %d).\n",
+- dlist_count, vc4_crtc->dlist_size);
+- return -EINVAL;
+- }
+- }
++ spin_lock_irqsave(&vc4->hvs->mm_lock, flags);
++ ret = drm_mm_insert_node(&vc4->hvs->dlist_mm, &vc4_state->mm,
++ dlist_count, 1, 0);
++ spin_unlock_irqrestore(&vc4->hvs->mm_lock, flags);
++ if (ret)
++ return ret;
+
+ return 0;
+ }
+@@ -368,47 +369,29 @@ static void vc4_crtc_atomic_flush(struct
+ struct drm_device *dev = crtc->dev;
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
++ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
+ struct drm_plane *plane;
+ bool debug_dump_regs = false;
+- u32 __iomem *dlist_next = vc4_crtc->dlist;
++ u32 __iomem *dlist_start = vc4->hvs->dlist + vc4_state->mm.start;
++ u32 __iomem *dlist_next = dlist_start;
+
+ if (debug_dump_regs) {
+ DRM_INFO("CRTC %d HVS before:\n", drm_crtc_index(crtc));
+ vc4_hvs_dump_state(dev);
+ }
+
+- /* Copy all the active planes' dlist contents to the hardware dlist.
+- *
+- * XXX: If the new display list was large enough that it
+- * overlapped a currently-read display list, we need to do
+- * something like disable scanout before putting in the new
+- * list. For now, we're safe because we only have the two
+- * planes.
+- */
++ /* Copy all the active planes' dlist contents to the hardware dlist. */
+ drm_atomic_crtc_for_each_plane(plane, crtc) {
+ dlist_next += vc4_plane_write_dlist(plane, dlist_next);
+ }
+
+- if (dlist_next == vc4_crtc->dlist) {
+- /* If no planes were enabled, use the SCALER_CTL0_END
+- * at the start of the display list memory (in the
+- * bootloader section). We'll rewrite that
+- * SCALER_CTL0_END, just in case, though.
+- */
+- writel(SCALER_CTL0_END, vc4->hvs->dlist);
+- HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel), 0);
+- } else {
+- writel(SCALER_CTL0_END, dlist_next);
+- dlist_next++;
+-
+- HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel),
+- (u32 __iomem *)vc4_crtc->dlist -
+- (u32 __iomem *)vc4->hvs->dlist);
+-
+- /* Make the next display list start after ours. */
+- vc4_crtc->dlist_size -= (dlist_next - vc4_crtc->dlist);
+- vc4_crtc->dlist = dlist_next;
+- }
++ writel(SCALER_CTL0_END, dlist_next);
++ dlist_next++;
++
++ WARN_ON_ONCE(dlist_next - dlist_start != vc4_state->mm.size);
++
++ HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel),
++ vc4_state->mm.start);
+
+ if (debug_dump_regs) {
+ DRM_INFO("CRTC %d HVS after:\n", drm_crtc_index(crtc));
+@@ -573,6 +556,36 @@ static int vc4_page_flip(struct drm_crtc
+ return drm_atomic_helper_page_flip(crtc, fb, event, flags);
+ }
+
++static struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc)
++{
++ struct vc4_crtc_state *vc4_state;
++
++ vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);
++ if (!vc4_state)
++ return NULL;
++
++ __drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base);
++ return &vc4_state->base;
++}
++
++static void vc4_crtc_destroy_state(struct drm_crtc *crtc,
++ struct drm_crtc_state *state)
++{
++ struct vc4_dev *vc4 = to_vc4_dev(crtc->dev);
++ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
++
++ if (vc4_state->mm.allocated) {
++ unsigned long flags;
++
++ spin_lock_irqsave(&vc4->hvs->mm_lock, flags);
++ drm_mm_remove_node(&vc4_state->mm);
++ spin_unlock_irqrestore(&vc4->hvs->mm_lock, flags);
++
++ }
++
++ __drm_atomic_helper_crtc_destroy_state(crtc, state);
++}
++
+ static const struct drm_crtc_funcs vc4_crtc_funcs = {
+ .set_config = drm_atomic_helper_set_config,
+ .destroy = vc4_crtc_destroy,
+@@ -581,8 +594,8 @@ static const struct drm_crtc_funcs vc4_c
+ .cursor_set = NULL, /* handled by drm_mode_cursor_universal */
+ .cursor_move = NULL, /* handled by drm_mode_cursor_universal */
+ .reset = drm_atomic_helper_crtc_reset,
+- .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+- .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
++ .atomic_duplicate_state = vc4_crtc_duplicate_state,
++ .atomic_destroy_state = vc4_crtc_destroy_state,
+ };
+
+ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
+--- a/drivers/gpu/drm/vc4/vc4_drv.h
++++ b/drivers/gpu/drm/vc4/vc4_drv.h
+@@ -150,7 +150,13 @@ struct vc4_v3d {
+ struct vc4_hvs {
+ struct platform_device *pdev;
+ void __iomem *regs;
+- void __iomem *dlist;
++ u32 __iomem *dlist;
++
++ /* Memory manager for CRTCs to allocate space in the display
++ * list. Units are dwords.
++ */
++ struct drm_mm dlist_mm;
++ spinlock_t mm_lock;
+ };
+
+ struct vc4_plane {
+--- a/drivers/gpu/drm/vc4/vc4_hvs.c
++++ b/drivers/gpu/drm/vc4/vc4_hvs.c
+@@ -119,6 +119,17 @@ static int vc4_hvs_bind(struct device *d
+
+ hvs->dlist = hvs->regs + SCALER_DLIST_START;
+
++ spin_lock_init(&hvs->mm_lock);
++
++ /* Set up the HVS display list memory manager. We never
++ * overwrite the setup from the bootloader (just 128b out of
++ * our 16K), since we don't want to scramble the screen when
++ * transitioning from the firmware's boot setup to runtime.
++ */
++ drm_mm_init(&hvs->dlist_mm,
++ HVS_BOOTLOADER_DLIST_END,
++ (SCALER_DLIST_SIZE >> 2) - HVS_BOOTLOADER_DLIST_END);
++
+ vc4->hvs = hvs;
+ return 0;
+ }
+@@ -129,6 +140,8 @@ static void vc4_hvs_unbind(struct device
+ struct drm_device *drm = dev_get_drvdata(master);
+ struct vc4_dev *vc4 = drm->dev_private;
+
++ drm_mm_takedown(&vc4->hvs->dlist_mm);
++
+ vc4->hvs = NULL;
+ }
+
diff --git a/target/linux/brcm2708/patches-4.4/0282-drm-vc4-Add-more-display-planes-to-each-CRTC.patch b/target/linux/brcm2708/patches-4.4/0282-drm-vc4-Add-more-display-planes-to-each-CRTC.patch
new file mode 100644
index 0000000000..34d6a18e40
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0282-drm-vc4-Add-more-display-planes-to-each-CRTC.patch
@@ -0,0 +1,106 @@
+From 5735ac96c821e3caf84de2d2358d0993130bc999 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Tue, 20 Oct 2015 14:18:56 +0100
+Subject: [PATCH 282/381] drm/vc4: Add more display planes to each CRTC.
+
+Previously we only did the primary and cursor plane, but overlay
+planes are useful and just require this setup to add, since all planes
+go into the HVS display list in the same way.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+(cherry picked from commit fc2d6f1eabee9d971453da2a27a72471c2a347dd)
+---
+ drivers/gpu/drm/vc4/vc4_crtc.c | 56 ++++++++++++++++++++++++++++++------------
+ 1 file changed, 40 insertions(+), 16 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_crtc.c
++++ b/drivers/gpu/drm/vc4/vc4_crtc.c
+@@ -677,9 +677,9 @@ static int vc4_crtc_bind(struct device *
+ struct vc4_dev *vc4 = to_vc4_dev(drm);
+ struct vc4_crtc *vc4_crtc;
+ struct drm_crtc *crtc;
+- struct drm_plane *primary_plane, *cursor_plane;
++ struct drm_plane *primary_plane, *cursor_plane, *destroy_plane, *temp;
+ const struct of_device_id *match;
+- int ret;
++ int ret, i;
+
+ vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL);
+ if (!vc4_crtc)
+@@ -708,27 +708,49 @@ static int vc4_crtc_bind(struct device *
+ goto err;
+ }
+
+- cursor_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_CURSOR);
+- if (IS_ERR(cursor_plane)) {
+- dev_err(dev, "failed to construct cursor plane\n");
+- ret = PTR_ERR(cursor_plane);
+- goto err_primary;
+- }
+-
+- drm_crtc_init_with_planes(drm, crtc, primary_plane, cursor_plane,
++ drm_crtc_init_with_planes(drm, crtc, primary_plane, NULL,
+ &vc4_crtc_funcs);
+ drm_crtc_helper_add(crtc, &vc4_crtc_helper_funcs);
+ primary_plane->crtc = crtc;
+- cursor_plane->crtc = crtc;
+ vc4->crtc[drm_crtc_index(crtc)] = vc4_crtc;
+ vc4_crtc->channel = vc4_crtc->data->hvs_channel;
+
++ /* Set up some arbitrary number of planes. We're not limited
++ * by a set number of physical registers, just the space in
++ * the HVS (16k) and how small an plane can be (28 bytes).
++ * However, each plane we set up takes up some memory, and
++ * increases the cost of looping over planes, which atomic
++ * modesetting does quite a bit. As a result, we pick a
++ * modest number of planes to expose, that should hopefully
++ * still cover any sane usecase.
++ */
++ for (i = 0; i < 8; i++) {
++ struct drm_plane *plane =
++ vc4_plane_init(drm, DRM_PLANE_TYPE_OVERLAY);
++
++ if (IS_ERR(plane))
++ continue;
++
++ plane->possible_crtcs = 1 << drm_crtc_index(crtc);
++ }
++
++ /* Set up the legacy cursor after overlay initialization,
++ * since we overlay planes on the CRTC in the order they were
++ * initialized.
++ */
++ cursor_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_CURSOR);
++ if (!IS_ERR(cursor_plane)) {
++ cursor_plane->possible_crtcs = 1 << drm_crtc_index(crtc);
++ cursor_plane->crtc = crtc;
++ crtc->cursor = cursor_plane;
++ }
++
+ CRTC_WRITE(PV_INTEN, 0);
+ CRTC_WRITE(PV_INTSTAT, PV_INT_VFP_START);
+ ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
+ vc4_crtc_irq_handler, 0, "vc4 crtc", vc4_crtc);
+ if (ret)
+- goto err_cursor;
++ goto err_destroy_planes;
+
+ vc4_set_crtc_possible_masks(drm, crtc);
+
+@@ -736,10 +758,12 @@ static int vc4_crtc_bind(struct device *
+
+ return 0;
+
+-err_cursor:
+- cursor_plane->funcs->destroy(cursor_plane);
+-err_primary:
+- primary_plane->funcs->destroy(primary_plane);
++err_destroy_planes:
++ list_for_each_entry_safe(destroy_plane, temp,
++ &drm->mode_config.plane_list, head) {
++ if (destroy_plane->possible_crtcs == 1 << drm_crtc_index(crtc))
++ destroy_plane->funcs->destroy(destroy_plane);
++ }
+ err:
+ return ret;
+ }
diff --git a/target/linux/brcm2708/patches-4.4/0283-drm-vc4-Fix-which-value-is-being-used-for-source-ima.patch b/target/linux/brcm2708/patches-4.4/0283-drm-vc4-Fix-which-value-is-being-used-for-source-ima.patch
new file mode 100644
index 0000000000..6b32b37689
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0283-drm-vc4-Fix-which-value-is-being-used-for-source-ima.patch
@@ -0,0 +1,77 @@
+From b5b8069d79586dd9ff61b7e71fa0754a211dd0a8 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 28 Dec 2015 14:45:25 -0800
+Subject: [PATCH 283/381] drm/vc4: Fix which value is being used for source
+ image size.
+
+This doesn't matter yet since we only allow 1:1 scaling, but the
+comment clearly says we should be using the source size.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+(cherry picked from commit f863e356013d628fa65b1cd89aa298eed26fc936)
+---
+ drivers/gpu/drm/vc4/vc4_plane.c | 23 ++++++++++++++---------
+ 1 file changed, 14 insertions(+), 9 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_plane.c
++++ b/drivers/gpu/drm/vc4/vc4_plane.c
+@@ -47,6 +47,8 @@ struct vc4_plane_state {
+
+ /* Clipped coordinates of the plane on the display. */
+ int crtc_x, crtc_y, crtc_w, crtc_h;
++ /* Clipped size of the area scanned from in the FB. */
++ u32 src_w, src_h;
+
+ /* Offset to start scanning out from the start of the plane's
+ * BO.
+@@ -186,11 +188,6 @@ static int vc4_plane_setup_clipping_and_
+
+ vc4_state->offset = fb->offsets[0];
+
+- vc4_state->crtc_x = state->crtc_x;
+- vc4_state->crtc_y = state->crtc_y;
+- vc4_state->crtc_w = state->crtc_w;
+- vc4_state->crtc_h = state->crtc_h;
+-
+ if (state->crtc_w << 16 != state->src_w ||
+ state->crtc_h << 16 != state->src_h) {
+ /* We don't support scaling yet, which involves
+@@ -201,17 +198,25 @@ static int vc4_plane_setup_clipping_and_
+ return -EINVAL;
+ }
+
++ vc4_state->src_w = state->src_w >> 16;
++ vc4_state->src_h = state->src_h >> 16;
++
++ vc4_state->crtc_x = state->crtc_x;
++ vc4_state->crtc_y = state->crtc_y;
++ vc4_state->crtc_w = state->crtc_w;
++ vc4_state->crtc_h = state->crtc_h;
++
+ if (vc4_state->crtc_x < 0) {
+ vc4_state->offset += (drm_format_plane_cpp(fb->pixel_format,
+ 0) *
+ -vc4_state->crtc_x);
+- vc4_state->crtc_w += vc4_state->crtc_x;
++ vc4_state->src_w += vc4_state->crtc_x;
+ vc4_state->crtc_x = 0;
+ }
+
+ if (vc4_state->crtc_y < 0) {
+ vc4_state->offset += fb->pitches[0] * -vc4_state->crtc_y;
+- vc4_state->crtc_h += vc4_state->crtc_y;
++ vc4_state->src_h += vc4_state->crtc_y;
+ vc4_state->crtc_y = 0;
+ }
+
+@@ -260,8 +265,8 @@ static int vc4_plane_mode_set(struct drm
+ SCALER_POS2_ALPHA_MODE_PIPELINE :
+ SCALER_POS2_ALPHA_MODE_FIXED,
+ SCALER_POS2_ALPHA_MODE) |
+- VC4_SET_FIELD(vc4_state->crtc_w, SCALER_POS2_WIDTH) |
+- VC4_SET_FIELD(vc4_state->crtc_h, SCALER_POS2_HEIGHT));
++ VC4_SET_FIELD(vc4_state->src_w, SCALER_POS2_WIDTH) |
++ VC4_SET_FIELD(vc4_state->src_h, SCALER_POS2_HEIGHT));
+
+ /* Position Word 3: Context. Written by the HVS. */
+ vc4_dlist_write(vc4_state, 0xc0c0c0c0);
diff --git a/target/linux/brcm2708/patches-4.4/0284-drm-vc4-Add-support-for-scaling-of-display-planes.patch b/target/linux/brcm2708/patches-4.4/0284-drm-vc4-Add-support-for-scaling-of-display-planes.patch
new file mode 100644
index 0000000000..b7b985c803
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0284-drm-vc4-Add-support-for-scaling-of-display-planes.patch
@@ -0,0 +1,579 @@
+From 52e3b2b7276aebafa566574945c9d5854215add3 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Tue, 20 Oct 2015 16:06:57 +0100
+Subject: [PATCH 284/381] drm/vc4: Add support for scaling of display planes.
+
+This implements a simple policy for choosing scaling modes
+(trapezoidal for decimation, PPF for magnification), and a single PPF
+filter (Mitchell/Netravali's recommendation).
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+(cherry picked from commit 21af94cf1a4c2d3450ab7fead58e6e2291ab92a9)
+---
+ drivers/gpu/drm/vc4/vc4_drv.h | 4 +
+ drivers/gpu/drm/vc4/vc4_hvs.c | 84 +++++++++++++
+ drivers/gpu/drm/vc4/vc4_plane.c | 253 +++++++++++++++++++++++++++++++++++++---
+ drivers/gpu/drm/vc4/vc4_regs.h | 46 ++++++++
+ 4 files changed, 374 insertions(+), 13 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_drv.h
++++ b/drivers/gpu/drm/vc4/vc4_drv.h
+@@ -156,7 +156,11 @@ struct vc4_hvs {
+ * list. Units are dwords.
+ */
+ struct drm_mm dlist_mm;
++ /* Memory manager for the LBM memory used by HVS scaling. */
++ struct drm_mm lbm_mm;
+ spinlock_t mm_lock;
++
++ struct drm_mm_node mitchell_netravali_filter;
+ };
+
+ struct vc4_plane {
+--- a/drivers/gpu/drm/vc4/vc4_hvs.c
++++ b/drivers/gpu/drm/vc4/vc4_hvs.c
+@@ -100,12 +100,76 @@ int vc4_hvs_debugfs_regs(struct seq_file
+ }
+ #endif
+
++/* The filter kernel is composed of dwords each containing 3 9-bit
++ * signed integers packed next to each other.
++ */
++#define VC4_INT_TO_COEFF(coeff) (coeff & 0x1ff)
++#define VC4_PPF_FILTER_WORD(c0, c1, c2) \
++ ((((c0) & 0x1ff) << 0) | \
++ (((c1) & 0x1ff) << 9) | \
++ (((c2) & 0x1ff) << 18))
++
++/* The whole filter kernel is arranged as the coefficients 0-16 going
++ * up, then a pad, then 17-31 going down and reversed within the
++ * dwords. This means that a linear phase kernel (where it's
++ * symmetrical at the boundary between 15 and 16) has the last 5
++ * dwords matching the first 5, but reversed.
++ */
++#define VC4_LINEAR_PHASE_KERNEL(c0, c1, c2, c3, c4, c5, c6, c7, c8, \
++ c9, c10, c11, c12, c13, c14, c15) \
++ {VC4_PPF_FILTER_WORD(c0, c1, c2), \
++ VC4_PPF_FILTER_WORD(c3, c4, c5), \
++ VC4_PPF_FILTER_WORD(c6, c7, c8), \
++ VC4_PPF_FILTER_WORD(c9, c10, c11), \
++ VC4_PPF_FILTER_WORD(c12, c13, c14), \
++ VC4_PPF_FILTER_WORD(c15, c15, 0)}
++
++#define VC4_LINEAR_PHASE_KERNEL_DWORDS 6
++#define VC4_KERNEL_DWORDS (VC4_LINEAR_PHASE_KERNEL_DWORDS * 2 - 1)
++
++/* Recommended B=1/3, C=1/3 filter choice from Mitchell/Netravali.
++ * http://www.cs.utexas.edu/~fussell/courses/cs384g/lectures/mitchell/Mitchell.pdf
++ */
++static const u32 mitchell_netravali_1_3_1_3_kernel[] =
++ VC4_LINEAR_PHASE_KERNEL(0, -2, -6, -8, -10, -8, -3, 2, 18,
++ 50, 82, 119, 155, 187, 213, 227);
++
++static int vc4_hvs_upload_linear_kernel(struct vc4_hvs *hvs,
++ struct drm_mm_node *space,
++ const u32 *kernel)
++{
++ int ret, i;
++ u32 __iomem *dst_kernel;
++
++ ret = drm_mm_insert_node(&hvs->dlist_mm, space, VC4_KERNEL_DWORDS, 1,
++ 0);
++ if (ret) {
++ DRM_ERROR("Failed to allocate space for filter kernel: %d\n",
++ ret);
++ return ret;
++ }
++
++ dst_kernel = hvs->dlist + space->start;
++
++ for (i = 0; i < VC4_KERNEL_DWORDS; i++) {
++ if (i < VC4_LINEAR_PHASE_KERNEL_DWORDS)
++ writel(kernel[i], &dst_kernel[i]);
++ else {
++ writel(kernel[VC4_KERNEL_DWORDS - i - 1],
++ &dst_kernel[i]);
++ }
++ }
++
++ return 0;
++}
++
+ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
+ {
+ struct platform_device *pdev = to_platform_device(dev);
+ struct drm_device *drm = dev_get_drvdata(master);
+ struct vc4_dev *vc4 = drm->dev_private;
+ struct vc4_hvs *hvs = NULL;
++ int ret;
+
+ hvs = devm_kzalloc(&pdev->dev, sizeof(*hvs), GFP_KERNEL);
+ if (!hvs)
+@@ -130,6 +194,22 @@ static int vc4_hvs_bind(struct device *d
+ HVS_BOOTLOADER_DLIST_END,
+ (SCALER_DLIST_SIZE >> 2) - HVS_BOOTLOADER_DLIST_END);
+
++ /* Set up the HVS LBM memory manager. We could have some more
++ * complicated data structure that allowed reuse of LBM areas
++ * between planes when they don't overlap on the screen, but
++ * for now we just allocate globally.
++ */
++ drm_mm_init(&hvs->lbm_mm, 0, 96 * 1024);
++
++ /* Upload filter kernels. We only have the one for now, so we
++ * keep it around for the lifetime of the driver.
++ */
++ ret = vc4_hvs_upload_linear_kernel(hvs,
++ &hvs->mitchell_netravali_filter,
++ mitchell_netravali_1_3_1_3_kernel);
++ if (ret)
++ return ret;
++
+ vc4->hvs = hvs;
+ return 0;
+ }
+@@ -140,7 +220,11 @@ static void vc4_hvs_unbind(struct device
+ struct drm_device *drm = dev_get_drvdata(master);
+ struct vc4_dev *vc4 = drm->dev_private;
+
++ if (vc4->hvs->mitchell_netravali_filter.allocated)
++ drm_mm_remove_node(&vc4->hvs->mitchell_netravali_filter);
++
+ drm_mm_takedown(&vc4->hvs->dlist_mm);
++ drm_mm_takedown(&vc4->hvs->lbm_mm);
+
+ vc4->hvs = NULL;
+ }
+--- a/drivers/gpu/drm/vc4/vc4_plane.c
++++ b/drivers/gpu/drm/vc4/vc4_plane.c
+@@ -24,6 +24,12 @@
+ #include "drm_fb_cma_helper.h"
+ #include "drm_plane_helper.h"
+
++enum vc4_scaling_mode {
++ VC4_SCALING_NONE,
++ VC4_SCALING_TPZ,
++ VC4_SCALING_PPF,
++};
++
+ struct vc4_plane_state {
+ struct drm_plane_state base;
+ /* System memory copy of the display list for this element, computed
+@@ -47,13 +53,19 @@ struct vc4_plane_state {
+
+ /* Clipped coordinates of the plane on the display. */
+ int crtc_x, crtc_y, crtc_w, crtc_h;
+- /* Clipped size of the area scanned from in the FB. */
+- u32 src_w, src_h;
++ /* Clipped area being scanned from in the FB. */
++ u32 src_x, src_y, src_w, src_h;
++
++ enum vc4_scaling_mode x_scaling, y_scaling;
++ bool is_unity;
+
+ /* Offset to start scanning out from the start of the plane's
+ * BO.
+ */
+ u32 offset;
++
++ /* Our allocation in LBM for temporary storage during scaling. */
++ struct drm_mm_node lbm;
+ };
+
+ static inline struct vc4_plane_state *
+@@ -106,6 +118,16 @@ static const struct hvs_format *vc4_get_
+ return NULL;
+ }
+
++static enum vc4_scaling_mode vc4_get_scaling_mode(u32 src, u32 dst)
++{
++ if (dst > src)
++ return VC4_SCALING_PPF;
++ else if (dst < src)
++ return VC4_SCALING_TPZ;
++ else
++ return VC4_SCALING_NONE;
++}
++
+ static bool plane_enabled(struct drm_plane_state *state)
+ {
+ return state->fb && state->crtc;
+@@ -122,6 +144,8 @@ static struct drm_plane_state *vc4_plane
+ if (!vc4_state)
+ return NULL;
+
++ memset(&vc4_state->lbm, 0, sizeof(vc4_state->lbm));
++
+ __drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base);
+
+ if (vc4_state->dlist) {
+@@ -141,8 +165,17 @@ static struct drm_plane_state *vc4_plane
+ static void vc4_plane_destroy_state(struct drm_plane *plane,
+ struct drm_plane_state *state)
+ {
++ struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
+ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
+
++ if (vc4_state->lbm.allocated) {
++ unsigned long irqflags;
++
++ spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags);
++ drm_mm_remove_node(&vc4_state->lbm);
++ spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags);
++ }
++
+ kfree(vc4_state->dlist);
+ __drm_atomic_helper_plane_destroy_state(plane, &vc4_state->base);
+ kfree(state);
+@@ -181,23 +214,60 @@ static void vc4_dlist_write(struct vc4_p
+ vc4_state->dlist[vc4_state->dlist_count++] = val;
+ }
+
++/* Returns the scl0/scl1 field based on whether the dimensions need to
++ * be up/down/non-scaled.
++ *
++ * This is a replication of a table from the spec.
++ */
++static u32 vc4_get_scl_field(struct drm_plane_state *state)
++{
++ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
++
++ switch (vc4_state->x_scaling << 2 | vc4_state->y_scaling) {
++ case VC4_SCALING_PPF << 2 | VC4_SCALING_PPF:
++ return SCALER_CTL0_SCL_H_PPF_V_PPF;
++ case VC4_SCALING_TPZ << 2 | VC4_SCALING_PPF:
++ return SCALER_CTL0_SCL_H_TPZ_V_PPF;
++ case VC4_SCALING_PPF << 2 | VC4_SCALING_TPZ:
++ return SCALER_CTL0_SCL_H_PPF_V_TPZ;
++ case VC4_SCALING_TPZ << 2 | VC4_SCALING_TPZ:
++ return SCALER_CTL0_SCL_H_TPZ_V_TPZ;
++ case VC4_SCALING_PPF << 2 | VC4_SCALING_NONE:
++ return SCALER_CTL0_SCL_H_PPF_V_NONE;
++ case VC4_SCALING_NONE << 2 | VC4_SCALING_PPF:
++ return SCALER_CTL0_SCL_H_NONE_V_PPF;
++ case VC4_SCALING_NONE << 2 | VC4_SCALING_TPZ:
++ return SCALER_CTL0_SCL_H_NONE_V_TPZ;
++ case VC4_SCALING_TPZ << 2 | VC4_SCALING_NONE:
++ return SCALER_CTL0_SCL_H_TPZ_V_NONE;
++ default:
++ case VC4_SCALING_NONE << 2 | VC4_SCALING_NONE:
++ /* The unity case is independently handled by
++ * SCALER_CTL0_UNITY.
++ */
++ return 0;
++ }
++}
++
+ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
+ {
++ struct drm_plane *plane = state->plane;
+ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
+ struct drm_framebuffer *fb = state->fb;
++ u32 subpixel_src_mask = (1 << 16) - 1;
+
+ vc4_state->offset = fb->offsets[0];
+
+- if (state->crtc_w << 16 != state->src_w ||
+- state->crtc_h << 16 != state->src_h) {
+- /* We don't support scaling yet, which involves
+- * allocating the LBM memory for scaling temporary
+- * storage, and putting filter kernels in the HVS
+- * context.
+- */
++ /* We don't support subpixel source positioning for scaling. */
++ if ((state->src_x & subpixel_src_mask) ||
++ (state->src_y & subpixel_src_mask) ||
++ (state->src_w & subpixel_src_mask) ||
++ (state->src_h & subpixel_src_mask)) {
+ return -EINVAL;
+ }
+
++ vc4_state->src_x = state->src_x >> 16;
++ vc4_state->src_y = state->src_y >> 16;
+ vc4_state->src_w = state->src_w >> 16;
+ vc4_state->src_h = state->src_h >> 16;
+
+@@ -206,6 +276,23 @@ static int vc4_plane_setup_clipping_and_
+ vc4_state->crtc_w = state->crtc_w;
+ vc4_state->crtc_h = state->crtc_h;
+
++ vc4_state->x_scaling = vc4_get_scaling_mode(vc4_state->src_w,
++ vc4_state->crtc_w);
++ vc4_state->y_scaling = vc4_get_scaling_mode(vc4_state->src_h,
++ vc4_state->crtc_h);
++ vc4_state->is_unity = (vc4_state->x_scaling == VC4_SCALING_NONE &&
++ vc4_state->y_scaling == VC4_SCALING_NONE);
++
++ /* No configuring scaling on the cursor plane, since it gets
++ non-vblank-synced updates, and scaling requires requires
++ LBM changes which have to be vblank-synced.
++ */
++ if (plane->type == DRM_PLANE_TYPE_CURSOR && !vc4_state->is_unity)
++ return -EINVAL;
++
++ /* Clamp the on-screen start x/y to 0. The hardware doesn't
++ * support negative y, and negative x wastes bandwidth.
++ */
+ if (vc4_state->crtc_x < 0) {
+ vc4_state->offset += (drm_format_plane_cpp(fb->pixel_format,
+ 0) *
+@@ -223,6 +310,87 @@ static int vc4_plane_setup_clipping_and_
+ return 0;
+ }
+
++static void vc4_write_tpz(struct vc4_plane_state *vc4_state, u32 src, u32 dst)
++{
++ u32 scale, recip;
++
++ scale = (1 << 16) * src / dst;
++
++ /* The specs note that while the reciprocal would be defined
++ * as (1<<32)/scale, ~0 is close enough.
++ */
++ recip = ~0 / scale;
++
++ vc4_dlist_write(vc4_state,
++ VC4_SET_FIELD(scale, SCALER_TPZ0_SCALE) |
++ VC4_SET_FIELD(0, SCALER_TPZ0_IPHASE));
++ vc4_dlist_write(vc4_state,
++ VC4_SET_FIELD(recip, SCALER_TPZ1_RECIP));
++}
++
++static void vc4_write_ppf(struct vc4_plane_state *vc4_state, u32 src, u32 dst)
++{
++ u32 scale = (1 << 16) * src / dst;
++
++ vc4_dlist_write(vc4_state,
++ SCALER_PPF_AGC |
++ VC4_SET_FIELD(scale, SCALER_PPF_SCALE) |
++ VC4_SET_FIELD(0, SCALER_PPF_IPHASE));
++}
++
++static u32 vc4_lbm_size(struct drm_plane_state *state)
++{
++ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
++ /* This is the worst case number. One of the two sizes will
++ * be used depending on the scaling configuration.
++ */
++ u32 pix_per_line = max(vc4_state->src_w, (u32)vc4_state->crtc_w);
++ u32 lbm;
++
++ if (vc4_state->is_unity)
++ return 0;
++ else if (vc4_state->y_scaling == VC4_SCALING_TPZ)
++ lbm = pix_per_line * 8;
++ else {
++ /* In special cases, this multiplier might be 12. */
++ lbm = pix_per_line * 16;
++ }
++
++ lbm = roundup(lbm, 32);
++
++ return lbm;
++}
++
++static void vc4_write_scaling_parameters(struct drm_plane_state *state)
++{
++ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
++
++ /* Ch0 H-PPF Word 0: Scaling Parameters */
++ if (vc4_state->x_scaling == VC4_SCALING_PPF) {
++ vc4_write_ppf(vc4_state,
++ vc4_state->src_w, vc4_state->crtc_w);
++ }
++
++ /* Ch0 V-PPF Words 0-1: Scaling Parameters, Context */
++ if (vc4_state->y_scaling == VC4_SCALING_PPF) {
++ vc4_write_ppf(vc4_state,
++ vc4_state->src_h, vc4_state->crtc_h);
++ vc4_dlist_write(vc4_state, 0xc0c0c0c0);
++ }
++
++ /* Ch0 H-TPZ Words 0-1: Scaling Parameters, Recip */
++ if (vc4_state->x_scaling == VC4_SCALING_TPZ) {
++ vc4_write_tpz(vc4_state,
++ vc4_state->src_w, vc4_state->crtc_w);
++ }
++
++ /* Ch0 V-TPZ Words 0-2: Scaling Parameters, Recip, Context */
++ if (vc4_state->y_scaling == VC4_SCALING_TPZ) {
++ vc4_write_tpz(vc4_state,
++ vc4_state->src_h, vc4_state->crtc_h);
++ vc4_dlist_write(vc4_state, 0xc0c0c0c0);
++ }
++}
+
+ /* Writes out a full display list for an active plane to the plane's
+ * private dlist state.
+@@ -230,22 +398,50 @@ static int vc4_plane_setup_clipping_and_
+ static int vc4_plane_mode_set(struct drm_plane *plane,
+ struct drm_plane_state *state)
+ {
++ struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
+ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
+ struct drm_framebuffer *fb = state->fb;
+ struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
+ u32 ctl0_offset = vc4_state->dlist_count;
+ const struct hvs_format *format = vc4_get_hvs_format(fb->pixel_format);
++ u32 scl;
++ u32 lbm_size;
++ unsigned long irqflags;
+ int ret;
+
+ ret = vc4_plane_setup_clipping_and_scaling(state);
+ if (ret)
+ return ret;
+
++ /* Allocate the LBM memory that the HVS will use for temporary
++ * storage due to our scaling/format conversion.
++ */
++ lbm_size = vc4_lbm_size(state);
++ if (lbm_size) {
++ if (!vc4_state->lbm.allocated) {
++ spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags);
++ ret = drm_mm_insert_node(&vc4->hvs->lbm_mm,
++ &vc4_state->lbm,
++ lbm_size, 32, 0);
++ spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags);
++ } else {
++ WARN_ON_ONCE(lbm_size != vc4_state->lbm.size);
++ }
++ }
++
++ if (ret)
++ return ret;
++
++ scl = vc4_get_scl_field(state);
++
++ /* Control word */
+ vc4_dlist_write(vc4_state,
+ SCALER_CTL0_VALID |
+ (format->pixel_order << SCALER_CTL0_ORDER_SHIFT) |
+ (format->hvs << SCALER_CTL0_PIXEL_FORMAT_SHIFT) |
+- SCALER_CTL0_UNITY);
++ (vc4_state->is_unity ? SCALER_CTL0_UNITY : 0) |
++ VC4_SET_FIELD(scl, SCALER_CTL0_SCL0) |
++ VC4_SET_FIELD(scl, SCALER_CTL0_SCL1));
+
+ /* Position Word 0: Image Positions and Alpha Value */
+ vc4_state->pos0_offset = vc4_state->dlist_count;
+@@ -254,9 +450,14 @@ static int vc4_plane_mode_set(struct drm
+ VC4_SET_FIELD(vc4_state->crtc_x, SCALER_POS0_START_X) |
+ VC4_SET_FIELD(vc4_state->crtc_y, SCALER_POS0_START_Y));
+
+- /* Position Word 1: Scaled Image Dimensions.
+- * Skipped due to SCALER_CTL0_UNITY scaling.
+- */
++ /* Position Word 1: Scaled Image Dimensions. */
++ if (!vc4_state->is_unity) {
++ vc4_dlist_write(vc4_state,
++ VC4_SET_FIELD(vc4_state->crtc_w,
++ SCALER_POS1_SCL_WIDTH) |
++ VC4_SET_FIELD(vc4_state->crtc_h,
++ SCALER_POS1_SCL_HEIGHT));
++ }
+
+ /* Position Word 2: Source Image Size, Alpha Mode */
+ vc4_state->pos2_offset = vc4_state->dlist_count;
+@@ -282,6 +483,32 @@ static int vc4_plane_mode_set(struct drm
+ vc4_dlist_write(vc4_state,
+ VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH));
+
++ if (!vc4_state->is_unity) {
++ /* LBM Base Address. */
++ if (vc4_state->y_scaling != VC4_SCALING_NONE)
++ vc4_dlist_write(vc4_state, vc4_state->lbm.start);
++
++ vc4_write_scaling_parameters(state);
++
++ /* If any PPF setup was done, then all the kernel
++ * pointers get uploaded.
++ */
++ if (vc4_state->x_scaling == VC4_SCALING_PPF ||
++ vc4_state->y_scaling == VC4_SCALING_PPF) {
++ u32 kernel = VC4_SET_FIELD(vc4->hvs->mitchell_netravali_filter.start,
++ SCALER_PPF_KERNEL_OFFSET);
++
++ /* HPPF plane 0 */
++ vc4_dlist_write(vc4_state, kernel);
++ /* VPPF plane 0 */
++ vc4_dlist_write(vc4_state, kernel);
++ /* HPPF plane 1 */
++ vc4_dlist_write(vc4_state, kernel);
++ /* VPPF plane 1 */
++ vc4_dlist_write(vc4_state, kernel);
++ }
++ }
++
+ vc4_state->dlist[ctl0_offset] |=
+ VC4_SET_FIELD(vc4_state->dlist_count, SCALER_CTL0_SIZE);
+
+--- a/drivers/gpu/drm/vc4/vc4_regs.h
++++ b/drivers/gpu/drm/vc4/vc4_regs.h
+@@ -536,6 +536,21 @@ enum hvs_pixel_format {
+ #define SCALER_CTL0_ORDER_MASK VC4_MASK(14, 13)
+ #define SCALER_CTL0_ORDER_SHIFT 13
+
++#define SCALER_CTL0_SCL1_MASK VC4_MASK(10, 8)
++#define SCALER_CTL0_SCL1_SHIFT 8
++
++#define SCALER_CTL0_SCL0_MASK VC4_MASK(7, 5)
++#define SCALER_CTL0_SCL0_SHIFT 5
++
++#define SCALER_CTL0_SCL_H_PPF_V_PPF 0
++#define SCALER_CTL0_SCL_H_TPZ_V_PPF 1
++#define SCALER_CTL0_SCL_H_PPF_V_TPZ 2
++#define SCALER_CTL0_SCL_H_TPZ_V_TPZ 3
++#define SCALER_CTL0_SCL_H_PPF_V_NONE 4
++#define SCALER_CTL0_SCL_H_NONE_V_PPF 5
++#define SCALER_CTL0_SCL_H_NONE_V_TPZ 6
++#define SCALER_CTL0_SCL_H_TPZ_V_NONE 7
++
+ /* Set to indicate no scaling. */
+ #define SCALER_CTL0_UNITY BIT(4)
+
+@@ -551,6 +566,12 @@ enum hvs_pixel_format {
+ #define SCALER_POS0_START_X_MASK VC4_MASK(11, 0)
+ #define SCALER_POS0_START_X_SHIFT 0
+
++#define SCALER_POS1_SCL_HEIGHT_MASK VC4_MASK(27, 16)
++#define SCALER_POS1_SCL_HEIGHT_SHIFT 16
++
++#define SCALER_POS1_SCL_WIDTH_MASK VC4_MASK(11, 0)
++#define SCALER_POS1_SCL_WIDTH_SHIFT 0
++
+ #define SCALER_POS2_ALPHA_MODE_MASK VC4_MASK(31, 30)
+ #define SCALER_POS2_ALPHA_MODE_SHIFT 30
+ #define SCALER_POS2_ALPHA_MODE_PIPELINE 0
+@@ -564,6 +585,31 @@ enum hvs_pixel_format {
+ #define SCALER_POS2_WIDTH_MASK VC4_MASK(11, 0)
+ #define SCALER_POS2_WIDTH_SHIFT 0
+
++#define SCALER_TPZ0_VERT_RECALC BIT(31)
++#define SCALER_TPZ0_SCALE_MASK VC4_MASK(28, 8)
++#define SCALER_TPZ0_SCALE_SHIFT 8
++#define SCALER_TPZ0_IPHASE_MASK VC4_MASK(7, 0)
++#define SCALER_TPZ0_IPHASE_SHIFT 0
++#define SCALER_TPZ1_RECIP_MASK VC4_MASK(15, 0)
++#define SCALER_TPZ1_RECIP_SHIFT 0
++
++/* Skips interpolating coefficients to 64 phases, so just 8 are used.
++ * Required for nearest neighbor.
++ */
++#define SCALER_PPF_NOINTERP BIT(31)
++/* Replaes the highest valued coefficient with one that makes all 4
++ * sum to unity.
++ */
++#define SCALER_PPF_AGC BIT(30)
++#define SCALER_PPF_SCALE_MASK VC4_MASK(24, 8)
++#define SCALER_PPF_SCALE_SHIFT 8
++#define SCALER_PPF_IPHASE_MASK VC4_MASK(6, 0)
++#define SCALER_PPF_IPHASE_SHIFT 0
++
++#define SCALER_PPF_KERNEL_OFFSET_MASK VC4_MASK(13, 0)
++#define SCALER_PPF_KERNEL_OFFSET_SHIFT 0
++#define SCALER_PPF_KERNEL_UNCACHED BIT(31)
++
+ #define SCALER_SRC_PITCH_MASK VC4_MASK(15, 0)
+ #define SCALER_SRC_PITCH_SHIFT 0
+
diff --git a/target/linux/brcm2708/patches-4.4/0285-drm-vc4-Add-support-for-YUV-planes.patch b/target/linux/brcm2708/patches-4.4/0285-drm-vc4-Add-support-for-YUV-planes.patch
new file mode 100644
index 0000000000..594dcc6087
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0285-drm-vc4-Add-support-for-YUV-planes.patch
@@ -0,0 +1,519 @@
+From 4760d384fa61412cfff7ac9e4166610cff125f53 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Wed, 30 Dec 2015 12:25:44 -0800
+Subject: [PATCH 285/381] drm/vc4: Add support for YUV planes.
+
+This supports 420 and 422 subsampling with 2 or 3 planes, tested with
+modetest. It doesn't set up chroma subsampling position (which it
+appears KMS doesn't deal with yet).
+
+The LBM memory is overallocated in many cases, but apparently the docs
+aren't quite correct and I'll probably need to look at the hardware
+source to really figure it out.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+(cherry picked from commit fc04023fafecf19ebd09278d8d67dc5ed1f68b46)
+---
+ drivers/gpu/drm/vc4/vc4_plane.c | 256 +++++++++++++++++++++++++++++++---------
+ drivers/gpu/drm/vc4/vc4_regs.h | 56 ++++++++-
+ 2 files changed, 253 insertions(+), 59 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_plane.c
++++ b/drivers/gpu/drm/vc4/vc4_plane.c
+@@ -54,15 +54,19 @@ struct vc4_plane_state {
+ /* Clipped coordinates of the plane on the display. */
+ int crtc_x, crtc_y, crtc_w, crtc_h;
+ /* Clipped area being scanned from in the FB. */
+- u32 src_x, src_y, src_w, src_h;
++ u32 src_x, src_y;
+
+- enum vc4_scaling_mode x_scaling, y_scaling;
++ u32 src_w[2], src_h[2];
++
++ /* Scaling selection for the RGB/Y plane and the Cb/Cr planes. */
++ enum vc4_scaling_mode x_scaling[2], y_scaling[2];
+ bool is_unity;
++ bool is_yuv;
+
+ /* Offset to start scanning out from the start of the plane's
+ * BO.
+ */
+- u32 offset;
++ u32 offsets[3];
+
+ /* Our allocation in LBM for temporary storage during scaling. */
+ struct drm_mm_node lbm;
+@@ -79,6 +83,7 @@ static const struct hvs_format {
+ u32 hvs; /* HVS_FORMAT_* */
+ u32 pixel_order;
+ bool has_alpha;
++ bool flip_cbcr;
+ } hvs_formats[] = {
+ {
+ .drm = DRM_FORMAT_XRGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
+@@ -104,6 +109,32 @@ static const struct hvs_format {
+ .drm = DRM_FORMAT_XRGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551,
+ .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = false,
+ },
++ {
++ .drm = DRM_FORMAT_YUV422,
++ .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE,
++ },
++ {
++ .drm = DRM_FORMAT_YVU422,
++ .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE,
++ .flip_cbcr = true,
++ },
++ {
++ .drm = DRM_FORMAT_YUV420,
++ .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE,
++ },
++ {
++ .drm = DRM_FORMAT_YVU420,
++ .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE,
++ .flip_cbcr = true,
++ },
++ {
++ .drm = DRM_FORMAT_NV12,
++ .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE,
++ },
++ {
++ .drm = DRM_FORMAT_NV16,
++ .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE,
++ },
+ };
+
+ static const struct hvs_format *vc4_get_hvs_format(u32 drm_format)
+@@ -219,11 +250,11 @@ static void vc4_dlist_write(struct vc4_p
+ *
+ * This is a replication of a table from the spec.
+ */
+-static u32 vc4_get_scl_field(struct drm_plane_state *state)
++static u32 vc4_get_scl_field(struct drm_plane_state *state, int plane)
+ {
+ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
+
+- switch (vc4_state->x_scaling << 2 | vc4_state->y_scaling) {
++ switch (vc4_state->x_scaling[plane] << 2 | vc4_state->y_scaling[plane]) {
+ case VC4_SCALING_PPF << 2 | VC4_SCALING_PPF:
+ return SCALER_CTL0_SCL_H_PPF_V_PPF;
+ case VC4_SCALING_TPZ << 2 | VC4_SCALING_PPF:
+@@ -254,9 +285,16 @@ static int vc4_plane_setup_clipping_and_
+ struct drm_plane *plane = state->plane;
+ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
+ struct drm_framebuffer *fb = state->fb;
++ struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
+ u32 subpixel_src_mask = (1 << 16) - 1;
++ u32 format = fb->pixel_format;
++ int num_planes = drm_format_num_planes(format);
++ u32 h_subsample = 1;
++ u32 v_subsample = 1;
++ int i;
+
+- vc4_state->offset = fb->offsets[0];
++ for (i = 0; i < num_planes; i++)
++ vc4_state->offsets[i] = bo->paddr + fb->offsets[i];
+
+ /* We don't support subpixel source positioning for scaling. */
+ if ((state->src_x & subpixel_src_mask) ||
+@@ -268,20 +306,48 @@ static int vc4_plane_setup_clipping_and_
+
+ vc4_state->src_x = state->src_x >> 16;
+ vc4_state->src_y = state->src_y >> 16;
+- vc4_state->src_w = state->src_w >> 16;
+- vc4_state->src_h = state->src_h >> 16;
++ vc4_state->src_w[0] = state->src_w >> 16;
++ vc4_state->src_h[0] = state->src_h >> 16;
+
+ vc4_state->crtc_x = state->crtc_x;
+ vc4_state->crtc_y = state->crtc_y;
+ vc4_state->crtc_w = state->crtc_w;
+ vc4_state->crtc_h = state->crtc_h;
+
+- vc4_state->x_scaling = vc4_get_scaling_mode(vc4_state->src_w,
+- vc4_state->crtc_w);
+- vc4_state->y_scaling = vc4_get_scaling_mode(vc4_state->src_h,
+- vc4_state->crtc_h);
+- vc4_state->is_unity = (vc4_state->x_scaling == VC4_SCALING_NONE &&
+- vc4_state->y_scaling == VC4_SCALING_NONE);
++ vc4_state->x_scaling[0] = vc4_get_scaling_mode(vc4_state->src_w[0],
++ vc4_state->crtc_w);
++ vc4_state->y_scaling[0] = vc4_get_scaling_mode(vc4_state->src_h[0],
++ vc4_state->crtc_h);
++
++ if (num_planes > 1) {
++ vc4_state->is_yuv = true;
++
++ h_subsample = drm_format_horz_chroma_subsampling(format);
++ v_subsample = drm_format_vert_chroma_subsampling(format);
++ vc4_state->src_w[1] = vc4_state->src_w[0] / h_subsample;
++ vc4_state->src_h[1] = vc4_state->src_h[0] / v_subsample;
++
++ vc4_state->x_scaling[1] =
++ vc4_get_scaling_mode(vc4_state->src_w[1],
++ vc4_state->crtc_w);
++ vc4_state->y_scaling[1] =
++ vc4_get_scaling_mode(vc4_state->src_h[1],
++ vc4_state->crtc_h);
++
++ /* YUV conversion requires that scaling be enabled,
++ * even on a plane that's otherwise 1:1. Choose TPZ
++ * for simplicity.
++ */
++ if (vc4_state->x_scaling[0] == VC4_SCALING_NONE)
++ vc4_state->x_scaling[0] = VC4_SCALING_TPZ;
++ if (vc4_state->y_scaling[0] == VC4_SCALING_NONE)
++ vc4_state->y_scaling[0] = VC4_SCALING_TPZ;
++ }
++
++ vc4_state->is_unity = (vc4_state->x_scaling[0] == VC4_SCALING_NONE &&
++ vc4_state->y_scaling[0] == VC4_SCALING_NONE &&
++ vc4_state->x_scaling[1] == VC4_SCALING_NONE &&
++ vc4_state->y_scaling[1] == VC4_SCALING_NONE);
+
+ /* No configuring scaling on the cursor plane, since it gets
+ non-vblank-synced updates, and scaling requires requires
+@@ -294,16 +360,27 @@ static int vc4_plane_setup_clipping_and_
+ * support negative y, and negative x wastes bandwidth.
+ */
+ if (vc4_state->crtc_x < 0) {
+- vc4_state->offset += (drm_format_plane_cpp(fb->pixel_format,
+- 0) *
+- -vc4_state->crtc_x);
+- vc4_state->src_w += vc4_state->crtc_x;
++ for (i = 0; i < num_planes; i++) {
++ u32 cpp = drm_format_plane_cpp(fb->pixel_format, i);
++ u32 subs = ((i == 0) ? 1 : h_subsample);
++
++ vc4_state->offsets[i] += (cpp *
++ (-vc4_state->crtc_x) / subs);
++ }
++ vc4_state->src_w[0] += vc4_state->crtc_x;
++ vc4_state->src_w[1] += vc4_state->crtc_x / h_subsample;
+ vc4_state->crtc_x = 0;
+ }
+
+ if (vc4_state->crtc_y < 0) {
+- vc4_state->offset += fb->pitches[0] * -vc4_state->crtc_y;
+- vc4_state->src_h += vc4_state->crtc_y;
++ for (i = 0; i < num_planes; i++) {
++ u32 subs = ((i == 0) ? 1 : v_subsample);
++
++ vc4_state->offsets[i] += (fb->pitches[i] *
++ (-vc4_state->crtc_y) / subs);
++ }
++ vc4_state->src_h[0] += vc4_state->crtc_y;
++ vc4_state->src_h[1] += vc4_state->crtc_y / v_subsample;
+ vc4_state->crtc_y = 0;
+ }
+
+@@ -344,15 +421,23 @@ static u32 vc4_lbm_size(struct drm_plane
+ /* This is the worst case number. One of the two sizes will
+ * be used depending on the scaling configuration.
+ */
+- u32 pix_per_line = max(vc4_state->src_w, (u32)vc4_state->crtc_w);
++ u32 pix_per_line = max(vc4_state->src_w[0], (u32)vc4_state->crtc_w);
+ u32 lbm;
+
+- if (vc4_state->is_unity)
+- return 0;
+- else if (vc4_state->y_scaling == VC4_SCALING_TPZ)
+- lbm = pix_per_line * 8;
+- else {
+- /* In special cases, this multiplier might be 12. */
++ if (!vc4_state->is_yuv) {
++ if (vc4_state->is_unity)
++ return 0;
++ else if (vc4_state->y_scaling[0] == VC4_SCALING_TPZ)
++ lbm = pix_per_line * 8;
++ else {
++ /* In special cases, this multiplier might be 12. */
++ lbm = pix_per_line * 16;
++ }
++ } else {
++ /* There are cases for this going down to a multiplier
++ * of 2, but according to the firmware source, the
++ * table in the docs is somewhat wrong.
++ */
+ lbm = pix_per_line * 16;
+ }
+
+@@ -361,33 +446,34 @@ static u32 vc4_lbm_size(struct drm_plane
+ return lbm;
+ }
+
+-static void vc4_write_scaling_parameters(struct drm_plane_state *state)
++static void vc4_write_scaling_parameters(struct drm_plane_state *state,
++ int channel)
+ {
+ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
+
+ /* Ch0 H-PPF Word 0: Scaling Parameters */
+- if (vc4_state->x_scaling == VC4_SCALING_PPF) {
++ if (vc4_state->x_scaling[channel] == VC4_SCALING_PPF) {
+ vc4_write_ppf(vc4_state,
+- vc4_state->src_w, vc4_state->crtc_w);
++ vc4_state->src_w[channel], vc4_state->crtc_w);
+ }
+
+ /* Ch0 V-PPF Words 0-1: Scaling Parameters, Context */
+- if (vc4_state->y_scaling == VC4_SCALING_PPF) {
++ if (vc4_state->y_scaling[channel] == VC4_SCALING_PPF) {
+ vc4_write_ppf(vc4_state,
+- vc4_state->src_h, vc4_state->crtc_h);
++ vc4_state->src_h[channel], vc4_state->crtc_h);
+ vc4_dlist_write(vc4_state, 0xc0c0c0c0);
+ }
+
+ /* Ch0 H-TPZ Words 0-1: Scaling Parameters, Recip */
+- if (vc4_state->x_scaling == VC4_SCALING_TPZ) {
++ if (vc4_state->x_scaling[channel] == VC4_SCALING_TPZ) {
+ vc4_write_tpz(vc4_state,
+- vc4_state->src_w, vc4_state->crtc_w);
++ vc4_state->src_w[channel], vc4_state->crtc_w);
+ }
+
+ /* Ch0 V-TPZ Words 0-2: Scaling Parameters, Recip, Context */
+- if (vc4_state->y_scaling == VC4_SCALING_TPZ) {
++ if (vc4_state->y_scaling[channel] == VC4_SCALING_TPZ) {
+ vc4_write_tpz(vc4_state,
+- vc4_state->src_h, vc4_state->crtc_h);
++ vc4_state->src_h[channel], vc4_state->crtc_h);
+ vc4_dlist_write(vc4_state, 0xc0c0c0c0);
+ }
+ }
+@@ -401,13 +487,13 @@ static int vc4_plane_mode_set(struct drm
+ struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
+ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
+ struct drm_framebuffer *fb = state->fb;
+- struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
+ u32 ctl0_offset = vc4_state->dlist_count;
+ const struct hvs_format *format = vc4_get_hvs_format(fb->pixel_format);
+- u32 scl;
++ int num_planes = drm_format_num_planes(format->drm);
++ u32 scl0, scl1;
+ u32 lbm_size;
+ unsigned long irqflags;
+- int ret;
++ int ret, i;
+
+ ret = vc4_plane_setup_clipping_and_scaling(state);
+ if (ret)
+@@ -432,7 +518,19 @@ static int vc4_plane_mode_set(struct drm
+ if (ret)
+ return ret;
+
+- scl = vc4_get_scl_field(state);
++ /* SCL1 is used for Cb/Cr scaling of planar formats. For RGB
++ * and 4:4:4, scl1 should be set to scl0 so both channels of
++ * the scaler do the same thing. For YUV, the Y plane needs
++ * to be put in channel 1 and Cb/Cr in channel 0, so we swap
++ * the scl fields here.
++ */
++ if (num_planes == 1) {
++ scl0 = vc4_get_scl_field(state, 1);
++ scl1 = scl0;
++ } else {
++ scl0 = vc4_get_scl_field(state, 1);
++ scl1 = vc4_get_scl_field(state, 0);
++ }
+
+ /* Control word */
+ vc4_dlist_write(vc4_state,
+@@ -440,8 +538,8 @@ static int vc4_plane_mode_set(struct drm
+ (format->pixel_order << SCALER_CTL0_ORDER_SHIFT) |
+ (format->hvs << SCALER_CTL0_PIXEL_FORMAT_SHIFT) |
+ (vc4_state->is_unity ? SCALER_CTL0_UNITY : 0) |
+- VC4_SET_FIELD(scl, SCALER_CTL0_SCL0) |
+- VC4_SET_FIELD(scl, SCALER_CTL0_SCL1));
++ VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) |
++ VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1));
+
+ /* Position Word 0: Image Positions and Alpha Value */
+ vc4_state->pos0_offset = vc4_state->dlist_count;
+@@ -466,35 +564,68 @@ static int vc4_plane_mode_set(struct drm
+ SCALER_POS2_ALPHA_MODE_PIPELINE :
+ SCALER_POS2_ALPHA_MODE_FIXED,
+ SCALER_POS2_ALPHA_MODE) |
+- VC4_SET_FIELD(vc4_state->src_w, SCALER_POS2_WIDTH) |
+- VC4_SET_FIELD(vc4_state->src_h, SCALER_POS2_HEIGHT));
++ VC4_SET_FIELD(vc4_state->src_w[0], SCALER_POS2_WIDTH) |
++ VC4_SET_FIELD(vc4_state->src_h[0], SCALER_POS2_HEIGHT));
+
+ /* Position Word 3: Context. Written by the HVS. */
+ vc4_dlist_write(vc4_state, 0xc0c0c0c0);
+
+- /* Pointer Word 0: RGB / Y Pointer */
++
++ /* Pointer Word 0/1/2: RGB / Y / Cb / Cr Pointers
++ *
++ * The pointers may be any byte address.
++ */
+ vc4_state->ptr0_offset = vc4_state->dlist_count;
+- vc4_dlist_write(vc4_state, bo->paddr + vc4_state->offset);
++ if (!format->flip_cbcr) {
++ for (i = 0; i < num_planes; i++)
++ vc4_dlist_write(vc4_state, vc4_state->offsets[i]);
++ } else {
++ WARN_ON_ONCE(num_planes != 3);
++ vc4_dlist_write(vc4_state, vc4_state->offsets[0]);
++ vc4_dlist_write(vc4_state, vc4_state->offsets[2]);
++ vc4_dlist_write(vc4_state, vc4_state->offsets[1]);
++ }
+
+- /* Pointer Context Word 0: Written by the HVS */
+- vc4_dlist_write(vc4_state, 0xc0c0c0c0);
++ /* Pointer Context Word 0/1/2: Written by the HVS */
++ for (i = 0; i < num_planes; i++)
++ vc4_dlist_write(vc4_state, 0xc0c0c0c0);
+
+- /* Pitch word 0: Pointer 0 Pitch */
+- vc4_dlist_write(vc4_state,
+- VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH));
++ /* Pitch word 0/1/2 */
++ for (i = 0; i < num_planes; i++) {
++ vc4_dlist_write(vc4_state,
++ VC4_SET_FIELD(fb->pitches[i], SCALER_SRC_PITCH));
++ }
++
++ /* Colorspace conversion words */
++ if (vc4_state->is_yuv) {
++ vc4_dlist_write(vc4_state, SCALER_CSC0_ITR_R_601_5);
++ vc4_dlist_write(vc4_state, SCALER_CSC1_ITR_R_601_5);
++ vc4_dlist_write(vc4_state, SCALER_CSC2_ITR_R_601_5);
++ }
+
+ if (!vc4_state->is_unity) {
+ /* LBM Base Address. */
+- if (vc4_state->y_scaling != VC4_SCALING_NONE)
++ if (vc4_state->y_scaling[0] != VC4_SCALING_NONE ||
++ vc4_state->y_scaling[1] != VC4_SCALING_NONE) {
+ vc4_dlist_write(vc4_state, vc4_state->lbm.start);
++ }
+
+- vc4_write_scaling_parameters(state);
++ if (num_planes > 1) {
++ /* Emit Cb/Cr as channel 0 and Y as channel
++ * 1. This matches how we set up scl0/scl1
++ * above.
++ */
++ vc4_write_scaling_parameters(state, 1);
++ }
++ vc4_write_scaling_parameters(state, 0);
+
+ /* If any PPF setup was done, then all the kernel
+ * pointers get uploaded.
+ */
+- if (vc4_state->x_scaling == VC4_SCALING_PPF ||
+- vc4_state->y_scaling == VC4_SCALING_PPF) {
++ if (vc4_state->x_scaling[0] == VC4_SCALING_PPF ||
++ vc4_state->y_scaling[0] == VC4_SCALING_PPF ||
++ vc4_state->x_scaling[1] == VC4_SCALING_PPF ||
++ vc4_state->y_scaling[1] == VC4_SCALING_PPF) {
+ u32 kernel = VC4_SET_FIELD(vc4->hvs->mitchell_netravali_filter.start,
+ SCALER_PPF_KERNEL_OFFSET);
+
+@@ -698,6 +829,7 @@ struct drm_plane *vc4_plane_init(struct
+ struct drm_plane *plane = NULL;
+ struct vc4_plane *vc4_plane;
+ u32 formats[ARRAY_SIZE(hvs_formats)];
++ u32 num_formats = 0;
+ int ret = 0;
+ unsigned i;
+
+@@ -708,12 +840,20 @@ struct drm_plane *vc4_plane_init(struct
+ goto fail;
+ }
+
+- for (i = 0; i < ARRAY_SIZE(hvs_formats); i++)
+- formats[i] = hvs_formats[i].drm;
++ for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) {
++ /* Don't allow YUV in cursor planes, since that means
++ * tuning on the scaler, which we don't allow for the
++ * cursor.
++ */
++ if (type != DRM_PLANE_TYPE_CURSOR ||
++ hvs_formats[i].hvs < HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE) {
++ formats[num_formats++] = hvs_formats[i].drm;
++ }
++ }
+ plane = &vc4_plane->base;
+ ret = drm_universal_plane_init(dev, plane, 0xff,
+ &vc4_plane_funcs,
+- formats, ARRAY_SIZE(formats),
++ formats, num_formats,
+ type);
+
+ drm_plane_helper_add(plane, &vc4_plane_helper_funcs);
+--- a/drivers/gpu/drm/vc4/vc4_regs.h
++++ b/drivers/gpu/drm/vc4/vc4_regs.h
+@@ -503,7 +503,12 @@ enum hvs_pixel_format {
+ HVS_PIXEL_FORMAT_RGB888 = 5,
+ HVS_PIXEL_FORMAT_RGBA6666 = 6,
+ /* 32bpp */
+- HVS_PIXEL_FORMAT_RGBA8888 = 7
++ HVS_PIXEL_FORMAT_RGBA8888 = 7,
++
++ HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE = 8,
++ HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE = 9,
++ HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE = 10,
++ HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE = 11,
+ };
+
+ /* Note: the LSB is the rightmost character shown. Only valid for
+@@ -585,6 +590,55 @@ enum hvs_pixel_format {
+ #define SCALER_POS2_WIDTH_MASK VC4_MASK(11, 0)
+ #define SCALER_POS2_WIDTH_SHIFT 0
+
++/* Color Space Conversion words. Some values are S2.8 signed
++ * integers, except that the 2 integer bits map as {0x0: 0, 0x1: 1,
++ * 0x2: 2, 0x3: -1}
++ */
++/* bottom 8 bits of S2.8 contribution of Cr to Blue */
++#define SCALER_CSC0_COEF_CR_BLU_MASK VC4_MASK(31, 24)
++#define SCALER_CSC0_COEF_CR_BLU_SHIFT 24
++/* Signed offset to apply to Y before CSC. (Y' = Y + YY_OFS) */
++#define SCALER_CSC0_COEF_YY_OFS_MASK VC4_MASK(23, 16)
++#define SCALER_CSC0_COEF_YY_OFS_SHIFT 16
++/* Signed offset to apply to CB before CSC (Cb' = Cb - 128 + CB_OFS). */
++#define SCALER_CSC0_COEF_CB_OFS_MASK VC4_MASK(15, 8)
++#define SCALER_CSC0_COEF_CB_OFS_SHIFT 8
++/* Signed offset to apply to CB before CSC (Cr' = Cr - 128 + CR_OFS). */
++#define SCALER_CSC0_COEF_CR_OFS_MASK VC4_MASK(7, 0)
++#define SCALER_CSC0_COEF_CR_OFS_SHIFT 0
++#define SCALER_CSC0_ITR_R_601_5 0x00f00000
++#define SCALER_CSC0_ITR_R_709_3 0x00f00000
++#define SCALER_CSC0_JPEG_JFIF 0x00000000
++
++/* S2.8 contribution of Cb to Green */
++#define SCALER_CSC1_COEF_CB_GRN_MASK VC4_MASK(31, 22)
++#define SCALER_CSC1_COEF_CB_GRN_SHIFT 22
++/* S2.8 contribution of Cr to Green */
++#define SCALER_CSC1_COEF_CR_GRN_MASK VC4_MASK(21, 12)
++#define SCALER_CSC1_COEF_CR_GRN_SHIFT 12
++/* S2.8 contribution of Y to all of RGB */
++#define SCALER_CSC1_COEF_YY_ALL_MASK VC4_MASK(11, 2)
++#define SCALER_CSC1_COEF_YY_ALL_SHIFT 2
++/* top 2 bits of S2.8 contribution of Cr to Blue */
++#define SCALER_CSC1_COEF_CR_BLU_MASK VC4_MASK(1, 0)
++#define SCALER_CSC1_COEF_CR_BLU_SHIFT 0
++#define SCALER_CSC1_ITR_R_601_5 0xe73304a8
++#define SCALER_CSC1_ITR_R_709_3 0xf2b784a8
++#define SCALER_CSC1_JPEG_JFIF 0xea34a400
++
++/* S2.8 contribution of Cb to Red */
++#define SCALER_CSC2_COEF_CB_RED_MASK VC4_MASK(29, 20)
++#define SCALER_CSC2_COEF_CB_RED_SHIFT 20
++/* S2.8 contribution of Cr to Red */
++#define SCALER_CSC2_COEF_CR_RED_MASK VC4_MASK(19, 10)
++#define SCALER_CSC2_COEF_CR_RED_SHIFT 10
++/* S2.8 contribution of Cb to Blue */
++#define SCALER_CSC2_COEF_CB_BLU_MASK VC4_MASK(19, 10)
++#define SCALER_CSC2_COEF_CB_BLU_SHIFT 10
++#define SCALER_CSC2_ITR_R_601_5 0x00066204
++#define SCALER_CSC2_ITR_R_709_3 0x00072a1c
++#define SCALER_CSC2_JPEG_JFIF 0x000599c5
++
+ #define SCALER_TPZ0_VERT_RECALC BIT(31)
+ #define SCALER_TPZ0_SCALE_MASK VC4_MASK(28, 8)
+ #define SCALER_TPZ0_SCALE_SHIFT 8
diff --git a/target/linux/brcm2708/patches-4.4/0286-drm-vc4-Fix-spurious-GPU-resets-due-to-BO-reuse.patch b/target/linux/brcm2708/patches-4.4/0286-drm-vc4-Fix-spurious-GPU-resets-due-to-BO-reuse.patch
new file mode 100644
index 0000000000..367bb562d0
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0286-drm-vc4-Fix-spurious-GPU-resets-due-to-BO-reuse.patch
@@ -0,0 +1,81 @@
+From cc502edf8c0515a8b3c410d4bfda002a4db88e4f Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 8 Feb 2016 11:19:14 -0800
+Subject: [PATCH 286/381] drm/vc4: Fix spurious GPU resets due to BO reuse.
+
+We were tracking the "where are the head pointers pointing" globally,
+so if another job reused the same BOs and execution was at the same
+point as last time we checked, we'd stop and trigger a reset even
+though the GPU had made progress.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+(cherry picked from commit c4ce60dc30912df09b2438f1e5594eae1ef64d1e)
+---
+ drivers/gpu/drm/vc4/vc4_drv.h | 6 +++++-
+ drivers/gpu/drm/vc4/vc4_gem.c | 19 ++++++++++++++-----
+ 2 files changed, 19 insertions(+), 6 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_drv.h
++++ b/drivers/gpu/drm/vc4/vc4_drv.h
+@@ -93,7 +93,6 @@ struct vc4_dev {
+ struct work_struct overflow_mem_work;
+
+ struct {
+- uint32_t last_ct0ca, last_ct1ca;
+ struct timer_list timer;
+ struct work_struct reset_work;
+ } hangcheck;
+@@ -203,6 +202,11 @@ struct vc4_exec_info {
+ /* Sequence number for this bin/render job. */
+ uint64_t seqno;
+
++ /* Last current addresses the hardware was processing when the
++ * hangcheck timer checked on us.
++ */
++ uint32_t last_ct0ca, last_ct1ca;
++
+ /* Kernel-space copy of the ioctl arguments */
+ struct drm_vc4_submit_cl *args;
+
+--- a/drivers/gpu/drm/vc4/vc4_gem.c
++++ b/drivers/gpu/drm/vc4/vc4_gem.c
+@@ -271,10 +271,17 @@ vc4_hangcheck_elapsed(unsigned long data
+ struct drm_device *dev = (struct drm_device *)data;
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ uint32_t ct0ca, ct1ca;
++ unsigned long irqflags;
++ struct vc4_exec_info *exec;
++
++ spin_lock_irqsave(&vc4->job_lock, irqflags);
++ exec = vc4_first_job(vc4);
+
+ /* If idle, we can stop watching for hangs. */
+- if (list_empty(&vc4->job_list))
++ if (!exec) {
++ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+ return;
++ }
+
+ ct0ca = V3D_READ(V3D_CTNCA(0));
+ ct1ca = V3D_READ(V3D_CTNCA(1));
+@@ -282,14 +289,16 @@ vc4_hangcheck_elapsed(unsigned long data
+ /* If we've made any progress in execution, rearm the timer
+ * and wait.
+ */
+- if (ct0ca != vc4->hangcheck.last_ct0ca ||
+- ct1ca != vc4->hangcheck.last_ct1ca) {
+- vc4->hangcheck.last_ct0ca = ct0ca;
+- vc4->hangcheck.last_ct1ca = ct1ca;
++ if (ct0ca != exec->last_ct0ca || ct1ca != exec->last_ct1ca) {
++ exec->last_ct0ca = ct0ca;
++ exec->last_ct1ca = ct1ca;
++ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+ vc4_queue_hangcheck(dev);
+ return;
+ }
+
++ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
++
+ /* We've gone too long with no progress, reset. This has to
+ * be done from a work struct, since resetting can sleep and
+ * this timer hook isn't allowed to.
diff --git a/target/linux/brcm2708/patches-4.4/0287-drm-vc4-Fix-a-framebuffer-reference-leak-on-async-fl.patch b/target/linux/brcm2708/patches-4.4/0287-drm-vc4-Fix-a-framebuffer-reference-leak-on-async-fl.patch
new file mode 100644
index 0000000000..c32557b32f
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0287-drm-vc4-Fix-a-framebuffer-reference-leak-on-async-fl.patch
@@ -0,0 +1,26 @@
+From 73902ea67be85e6a5d440fed2c53e5364125c4e1 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Fri, 5 Feb 2016 15:06:15 -0800
+Subject: [PATCH 287/381] drm/vc4: Fix a framebuffer reference leak on async
+ flip interrupt.
+
+We'd need X to queue up an async pageflip while another is
+outstanding, and then take a SIGIO. I think X actually avoids sending
+out the next pageflip while one's already queued, but I'm not sure.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+(cherry picked from commit 48627eb8dc55c60d35794105f6f79fb627347dbd)
+---
+ drivers/gpu/drm/vc4/vc4_crtc.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_crtc.c
++++ b/drivers/gpu/drm/vc4/vc4_crtc.c
+@@ -527,6 +527,7 @@ static int vc4_async_page_flip(struct dr
+ /* Make sure all other async modesetes have landed. */
+ ret = down_interruptible(&vc4->async_modeset);
+ if (ret) {
++ drm_framebuffer_unreference(fb);
+ kfree(flip_state);
+ return ret;
+ }
diff --git a/target/linux/brcm2708/patches-4.4/0288-drm-vc4-Bring-HDMI-up-from-power-off-if-necessary.patch b/target/linux/brcm2708/patches-4.4/0288-drm-vc4-Bring-HDMI-up-from-power-off-if-necessary.patch
new file mode 100644
index 0000000000..9868cbbf3b
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0288-drm-vc4-Bring-HDMI-up-from-power-off-if-necessary.patch
@@ -0,0 +1,72 @@
+From b90794bb85c90b4276fea302cf75251021134e7a Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Fri, 12 Feb 2016 14:15:14 -0800
+Subject: [PATCH 288/381] drm/vc4: Bring HDMI up from power off if necessary.
+
+If the firmware hadn't brought up HDMI for us, we need to do its
+power-on reset sequence (reset HD and and clear its STANDBY bits,
+reset HDMI, and leave the PHY disabled).
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+(cherry picked from commit 851479ad5927b7b1aa141ca9dedb897a7bce2b1d)
+---
+ drivers/gpu/drm/vc4/vc4_hdmi.c | 29 ++++++++++++++++++++++++++++-
+ drivers/gpu/drm/vc4/vc4_regs.h | 2 ++
+ 2 files changed, 30 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
+@@ -497,6 +497,16 @@ static int vc4_hdmi_bind(struct device *
+ goto err_put_i2c;
+ }
+
++ /* This is the rate that is set by the firmware. The number
++ * needs to be a bit higher than the pixel clock rate
++ * (generally 148.5Mhz).
++ */
++ ret = clk_set_rate(hdmi->hsm_clock, 163682864);
++ if (ret) {
++ DRM_ERROR("Failed to set HSM clock rate: %d\n", ret);
++ goto err_unprepare_pix;
++ }
++
+ ret = clk_prepare_enable(hdmi->hsm_clock);
+ if (ret) {
+ DRM_ERROR("Failed to turn on HDMI state machine clock: %d\n",
+@@ -518,7 +528,24 @@ static int vc4_hdmi_bind(struct device *
+ vc4->hdmi = hdmi;
+
+ /* HDMI core must be enabled. */
+- WARN_ON_ONCE((HD_READ(VC4_HD_M_CTL) & VC4_HD_M_ENABLE) == 0);
++ if (!(HD_READ(VC4_HD_M_CTL) & VC4_HD_M_ENABLE)) {
++ HD_WRITE(VC4_HD_M_CTL, VC4_HD_M_SW_RST);
++ udelay(1);
++ HD_WRITE(VC4_HD_M_CTL, 0);
++
++ HD_WRITE(VC4_HD_M_CTL, VC4_HD_M_ENABLE);
++
++ HDMI_WRITE(VC4_HDMI_SW_RESET_CONTROL,
++ VC4_HDMI_SW_RESET_HDMI |
++ VC4_HDMI_SW_RESET_FORMAT_DETECT);
++
++ HDMI_WRITE(VC4_HDMI_SW_RESET_CONTROL, 0);
++
++ /* PHY should be in reset, like
++ * vc4_hdmi_encoder_disable() does.
++ */
++ HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0xf << 16);
++ }
+
+ drm_encoder_init(drm, hdmi->encoder, &vc4_hdmi_encoder_funcs,
+ DRM_MODE_ENCODER_TMDS);
+--- a/drivers/gpu/drm/vc4/vc4_regs.h
++++ b/drivers/gpu/drm/vc4/vc4_regs.h
+@@ -456,6 +456,8 @@
+ #define VC4_HDMI_TX_PHY_RESET_CTL 0x2c0
+
+ #define VC4_HD_M_CTL 0x00c
++# define VC4_HD_M_REGISTER_FILE_STANDBY (3 << 6)
++# define VC4_HD_M_RAM_STANDBY (3 << 4)
+ # define VC4_HD_M_SW_RST BIT(2)
+ # define VC4_HD_M_ENABLE BIT(0)
+
diff --git a/target/linux/brcm2708/patches-4.4/0289-drm-vc4-Add-another-reg-to-HDMI-debug-dumping.patch b/target/linux/brcm2708/patches-4.4/0289-drm-vc4-Add-another-reg-to-HDMI-debug-dumping.patch
new file mode 100644
index 0000000000..6497f12df5
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0289-drm-vc4-Add-another-reg-to-HDMI-debug-dumping.patch
@@ -0,0 +1,24 @@
+From 2f684276a677eb2133a9ec0c9fdc294a62a5d6dd Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Fri, 12 Feb 2016 15:16:56 -0800
+Subject: [PATCH 289/381] drm/vc4: Add another reg to HDMI debug dumping.
+
+This is also involved in the HDMI setup sequence so it's nice to see
+it.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+(cherry picked from commit 936f1a53f32148cc6164fad7c9a26ebf144e5ffb)
+---
+ drivers/gpu/drm/vc4/vc4_hdmi.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
+@@ -95,6 +95,7 @@ static const struct {
+ HDMI_REG(VC4_HDMI_SW_RESET_CONTROL),
+ HDMI_REG(VC4_HDMI_HOTPLUG_INT),
+ HDMI_REG(VC4_HDMI_HOTPLUG),
++ HDMI_REG(VC4_HDMI_RAM_PACKET_CONFIG),
+ HDMI_REG(VC4_HDMI_HORZA),
+ HDMI_REG(VC4_HDMI_HORZB),
+ HDMI_REG(VC4_HDMI_FIFO_CTL),
diff --git a/target/linux/brcm2708/patches-4.4/0290-drm-vc4-Fix-the-name-of-the-VSYNCD_EVEN-register.patch b/target/linux/brcm2708/patches-4.4/0290-drm-vc4-Fix-the-name-of-the-VSYNCD_EVEN-register.patch
new file mode 100644
index 0000000000..32d11946cf
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0290-drm-vc4-Fix-the-name-of-the-VSYNCD_EVEN-register.patch
@@ -0,0 +1,36 @@
+From 659c32d3344952ef9c49a18d512318e5dca9eff3 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 15 Feb 2016 17:06:02 -0800
+Subject: [PATCH 290/381] drm/vc4: Fix the name of the VSYNCD_EVEN register.
+
+It's used for delaying vsync in interlaced mode.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+(cherry picked from commit c31806fbdda910d337b60896040afa708bdfa2bd)
+---
+ drivers/gpu/drm/vc4/vc4_crtc.c | 2 +-
+ drivers/gpu/drm/vc4/vc4_regs.h | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_crtc.c
++++ b/drivers/gpu/drm/vc4/vc4_crtc.c
+@@ -88,7 +88,7 @@ static const struct {
+ } crtc_regs[] = {
+ CRTC_REG(PV_CONTROL),
+ CRTC_REG(PV_V_CONTROL),
+- CRTC_REG(PV_VSYNCD),
++ CRTC_REG(PV_VSYNCD_EVEN),
+ CRTC_REG(PV_HORZA),
+ CRTC_REG(PV_HORZB),
+ CRTC_REG(PV_VERTA),
+--- a/drivers/gpu/drm/vc4/vc4_regs.h
++++ b/drivers/gpu/drm/vc4/vc4_regs.h
+@@ -187,7 +187,7 @@
+ # define PV_VCONTROL_CONTINUOUS BIT(1)
+ # define PV_VCONTROL_VIDEN BIT(0)
+
+-#define PV_VSYNCD 0x08
++#define PV_VSYNCD_EVEN 0x08
+
+ #define PV_HORZA 0x0c
+ # define PV_HORZA_HBP_MASK VC4_MASK(31, 16)
diff --git a/target/linux/brcm2708/patches-4.4/0291-drm-vc4-Fix-setting-of-vertical-timings-in-the-CRTC.patch b/target/linux/brcm2708/patches-4.4/0291-drm-vc4-Fix-setting-of-vertical-timings-in-the-CRTC.patch
new file mode 100644
index 0000000000..319fc16a52
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0291-drm-vc4-Fix-setting-of-vertical-timings-in-the-CRTC.patch
@@ -0,0 +1,34 @@
+From c6f8dd873098c2c41e97606d55b806a8c5965b3e Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 15 Feb 2016 17:31:41 -0800
+Subject: [PATCH 291/381] drm/vc4: Fix setting of vertical timings in the CRTC.
+
+It looks like when I went to add the interlaced bits, I just took the
+existing PV_VERT* block and indented it, instead of copy and pasting
+it first. Without this, changing resolution never worked.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+(cherry picked from commit a7c5047d1ce178dd2b1fa577fc8909ad663d56d5)
+---
+ drivers/gpu/drm/vc4/vc4_crtc.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_crtc.c
++++ b/drivers/gpu/drm/vc4/vc4_crtc.c
+@@ -217,6 +217,16 @@ static void vc4_crtc_mode_set_nofb(struc
+ PV_HORZB_HFP) |
+ VC4_SET_FIELD(mode->hdisplay, PV_HORZB_HACTIVE));
+
++ CRTC_WRITE(PV_VERTA,
++ VC4_SET_FIELD(mode->vtotal - mode->vsync_end,
++ PV_VERTA_VBP) |
++ VC4_SET_FIELD(mode->vsync_end - mode->vsync_start,
++ PV_VERTA_VSYNC));
++ CRTC_WRITE(PV_VERTB,
++ VC4_SET_FIELD(mode->vsync_start - mode->vdisplay,
++ PV_VERTB_VFP) |
++ VC4_SET_FIELD(vactive, PV_VERTB_VACTIVE));
++
+ if (interlace) {
+ CRTC_WRITE(PV_VERTA_EVEN,
+ VC4_SET_FIELD(mode->vtotal - mode->vsync_end - 1,
diff --git a/target/linux/brcm2708/patches-4.4/0292-drm-vc4-Initialize-scaler-DISPBKGND-on-modeset.patch b/target/linux/brcm2708/patches-4.4/0292-drm-vc4-Initialize-scaler-DISPBKGND-on-modeset.patch
new file mode 100644
index 0000000000..f3bbefb371
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0292-drm-vc4-Initialize-scaler-DISPBKGND-on-modeset.patch
@@ -0,0 +1,68 @@
+From b7c76f75bc8e373d185a222bf7fa0ceb5f9d6d0a Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Tue, 16 Feb 2016 10:24:08 -0800
+Subject: [PATCH 292/381] drm/vc4: Initialize scaler DISPBKGND on modeset.
+
+We weren't updating the interlaced bit, so we'd scan out incorrectly
+if the firmware had brought up the TV encoder and we were switching to
+HDMI.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+(cherry picked from commit 6a609209865247cc748e90158c99f374f79b494c)
+---
+ drivers/gpu/drm/vc4/vc4_crtc.c | 6 ++++++
+ drivers/gpu/drm/vc4/vc4_regs.h | 14 ++++++++++++++
+ 2 files changed, 20 insertions(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_crtc.c
++++ b/drivers/gpu/drm/vc4/vc4_crtc.c
+@@ -188,6 +188,8 @@ static int vc4_get_clock_select(struct d
+
+ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
+ {
++ struct drm_device *dev = crtc->dev;
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+ struct drm_crtc_state *state = crtc->state;
+ struct drm_display_mode *mode = &state->adjusted_mode;
+@@ -256,6 +258,10 @@ static void vc4_crtc_mode_set_nofb(struc
+ PV_CONTROL_FIFO_CLR |
+ PV_CONTROL_EN);
+
++ HVS_WRITE(SCALER_DISPBKGNDX(vc4_crtc->channel),
++ SCALER_DISPBKGND_AUTOHS |
++ (interlace ? SCALER_DISPBKGND_INTERLACE : 0));
++
+ if (debug_dump_regs) {
+ DRM_INFO("CRTC %d regs after:\n", drm_crtc_index(crtc));
+ vc4_crtc_dump_regs(vc4_crtc);
+--- a/drivers/gpu/drm/vc4/vc4_regs.h
++++ b/drivers/gpu/drm/vc4/vc4_regs.h
+@@ -350,6 +350,17 @@
+ # define SCALER_DISPCTRLX_HEIGHT_SHIFT 0
+
+ #define SCALER_DISPBKGND0 0x00000044
++# define SCALER_DISPBKGND_AUTOHS BIT(31)
++# define SCALER_DISPBKGND_INTERLACE BIT(30)
++# define SCALER_DISPBKGND_GAMMA BIT(29)
++# define SCALER_DISPBKGND_TESTMODE_MASK VC4_MASK(28, 25)
++# define SCALER_DISPBKGND_TESTMODE_SHIFT 25
++/* Enables filling the scaler line with the RGB value in the low 24
++ * bits before compositing. Costs cycles, so should be skipped if
++ * opaque display planes will cover everything.
++ */
++# define SCALER_DISPBKGND_FILL BIT(24)
++
+ #define SCALER_DISPSTAT0 0x00000048
+ #define SCALER_DISPBASE0 0x0000004c
+ # define SCALER_DISPSTATX_MODE_MASK VC4_MASK(31, 30)
+@@ -362,6 +373,9 @@
+ # define SCALER_DISPSTATX_EMPTY BIT(28)
+ #define SCALER_DISPCTRL1 0x00000050
+ #define SCALER_DISPBKGND1 0x00000054
++#define SCALER_DISPBKGNDX(x) (SCALER_DISPBKGND0 + \
++ (x) * (SCALER_DISPBKGND1 - \
++ SCALER_DISPBKGND0))
+ #define SCALER_DISPSTAT1 0x00000058
+ #define SCALER_DISPSTATX(x) (SCALER_DISPSTAT0 + \
+ (x) * (SCALER_DISPSTAT1 - \
diff --git a/target/linux/brcm2708/patches-4.4/0293-drm-vc4-improve-throughput-by-pipelining-binning-and.patch b/target/linux/brcm2708/patches-4.4/0293-drm-vc4-improve-throughput-by-pipelining-binning-and.patch
new file mode 100644
index 0000000000..61bddd1dad
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0293-drm-vc4-improve-throughput-by-pipelining-binning-and.patch
@@ -0,0 +1,429 @@
+From 9e72968ae5f2e27c4f1d2b90337aa2d27c06cae4 Mon Sep 17 00:00:00 2001
+From: Varad Gautam <varadgautam@gmail.com>
+Date: Wed, 17 Feb 2016 19:08:21 +0530
+Subject: [PATCH 293/381] drm/vc4: improve throughput by pipelining binning and
+ rendering jobs
+
+The hardware provides us with separate threads for binning and
+rendering, and the existing model waits for them both to complete
+before submitting the next job.
+
+Splitting the binning and rendering submissions reduces idle time and
+gives us approx 20-30% speedup with some x11perf tests such as -line10
+and -tilerect1. Improves openarena performance by 1.01897% +/-
+0.247857% (n=16).
+
+Thanks to anholt for suggesting this.
+
+v2: Rebase on the spurious resets fix (change by anholt).
+
+Signed-off-by: Varad Gautam <varadgautam@gmail.com>
+Reviewed-by: Eric Anholt <eric@anholt.net>
+Signed-off-by: Eric Anholt <eric@anholt.net>
+(cherry picked from commit ca26d28bbaa39f31d5e7e4812603b015c8d54207)
+---
+ drivers/gpu/drm/vc4/vc4_drv.h | 37 +++++++++----
+ drivers/gpu/drm/vc4/vc4_gem.c | 123 ++++++++++++++++++++++++++++++------------
+ drivers/gpu/drm/vc4/vc4_irq.c | 58 ++++++++++++++++----
+ 3 files changed, 166 insertions(+), 52 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_drv.h
++++ b/drivers/gpu/drm/vc4/vc4_drv.h
+@@ -53,7 +53,7 @@ struct vc4_dev {
+ /* Protects bo_cache and the BO stats. */
+ struct mutex bo_lock;
+
+- /* Sequence number for the last job queued in job_list.
++ /* Sequence number for the last job queued in bin_job_list.
+ * Starts at 0 (no jobs emitted).
+ */
+ uint64_t emit_seqno;
+@@ -63,11 +63,19 @@ struct vc4_dev {
+ */
+ uint64_t finished_seqno;
+
+- /* List of all struct vc4_exec_info for jobs to be executed.
+- * The first job in the list is the one currently programmed
+- * into ct0ca/ct1ca for execution.
++ /* List of all struct vc4_exec_info for jobs to be executed in
++ * the binner. The first job in the list is the one currently
++ * programmed into ct0ca for execution.
++ */
++ struct list_head bin_job_list;
++
++ /* List of all struct vc4_exec_info for jobs that have
++ * completed binning and are ready for rendering. The first
++ * job in the list is the one currently programmed into ct1ca
++ * for execution.
+ */
+- struct list_head job_list;
++ struct list_head render_job_list;
++
+ /* List of the finished vc4_exec_infos waiting to be freed by
+ * job_done_work.
+ */
+@@ -291,11 +299,20 @@ struct vc4_exec_info {
+ };
+
+ static inline struct vc4_exec_info *
+-vc4_first_job(struct vc4_dev *vc4)
++vc4_first_bin_job(struct vc4_dev *vc4)
++{
++ if (list_empty(&vc4->bin_job_list))
++ return NULL;
++ return list_first_entry(&vc4->bin_job_list, struct vc4_exec_info, head);
++}
++
++static inline struct vc4_exec_info *
++vc4_first_render_job(struct vc4_dev *vc4)
+ {
+- if (list_empty(&vc4->job_list))
++ if (list_empty(&vc4->render_job_list))
+ return NULL;
+- return list_first_entry(&vc4->job_list, struct vc4_exec_info, head);
++ return list_first_entry(&vc4->render_job_list,
++ struct vc4_exec_info, head);
+ }
+
+ /**
+@@ -410,7 +427,9 @@ int vc4_wait_seqno_ioctl(struct drm_devi
+ struct drm_file *file_priv);
+ int vc4_wait_bo_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+-void vc4_submit_next_job(struct drm_device *dev);
++void vc4_submit_next_bin_job(struct drm_device *dev);
++void vc4_submit_next_render_job(struct drm_device *dev);
++void vc4_move_job_to_render(struct drm_device *dev, struct vc4_exec_info *exec);
+ int vc4_wait_for_seqno(struct drm_device *dev, uint64_t seqno,
+ uint64_t timeout_ns, bool interruptible);
+ void vc4_job_handle_completed(struct vc4_dev *vc4);
+--- a/drivers/gpu/drm/vc4/vc4_gem.c
++++ b/drivers/gpu/drm/vc4/vc4_gem.c
+@@ -154,10 +154,10 @@ vc4_save_hang_state(struct drm_device *d
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ struct drm_vc4_get_hang_state *state;
+ struct vc4_hang_state *kernel_state;
+- struct vc4_exec_info *exec;
++ struct vc4_exec_info *exec[2];
+ struct vc4_bo *bo;
+ unsigned long irqflags;
+- unsigned int i, unref_list_count;
++ unsigned int i, j, unref_list_count, prev_idx;
+
+ kernel_state = kcalloc(1, sizeof(*kernel_state), GFP_KERNEL);
+ if (!kernel_state)
+@@ -166,37 +166,55 @@ vc4_save_hang_state(struct drm_device *d
+ state = &kernel_state->user_state;
+
+ spin_lock_irqsave(&vc4->job_lock, irqflags);
+- exec = vc4_first_job(vc4);
+- if (!exec) {
++ exec[0] = vc4_first_bin_job(vc4);
++ exec[1] = vc4_first_render_job(vc4);
++ if (!exec[0] && !exec[1]) {
+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+ return;
+ }
+
+- unref_list_count = 0;
+- list_for_each_entry(bo, &exec->unref_list, unref_head)
+- unref_list_count++;
+-
+- state->bo_count = exec->bo_count + unref_list_count;
+- kernel_state->bo = kcalloc(state->bo_count, sizeof(*kernel_state->bo),
+- GFP_ATOMIC);
++ /* Get the bos from both binner and renderer into hang state. */
++ state->bo_count = 0;
++ for (i = 0; i < 2; i++) {
++ if (!exec[i])
++ continue;
++
++ unref_list_count = 0;
++ list_for_each_entry(bo, &exec[i]->unref_list, unref_head)
++ unref_list_count++;
++ state->bo_count += exec[i]->bo_count + unref_list_count;
++ }
++
++ kernel_state->bo = kcalloc(state->bo_count,
++ sizeof(*kernel_state->bo), GFP_ATOMIC);
++
+ if (!kernel_state->bo) {
+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+ return;
+ }
+
+- for (i = 0; i < exec->bo_count; i++) {
+- drm_gem_object_reference(&exec->bo[i]->base);
+- kernel_state->bo[i] = &exec->bo[i]->base;
+- }
++ prev_idx = 0;
++ for (i = 0; i < 2; i++) {
++ if (!exec[i])
++ continue;
++
++ for (j = 0; j < exec[i]->bo_count; j++) {
++ drm_gem_object_reference(&exec[i]->bo[j]->base);
++ kernel_state->bo[j + prev_idx] = &exec[i]->bo[j]->base;
++ }
+
+- list_for_each_entry(bo, &exec->unref_list, unref_head) {
+- drm_gem_object_reference(&bo->base.base);
+- kernel_state->bo[i] = &bo->base.base;
+- i++;
++ list_for_each_entry(bo, &exec[i]->unref_list, unref_head) {
++ drm_gem_object_reference(&bo->base.base);
++ kernel_state->bo[j + prev_idx] = &bo->base.base;
++ j++;
++ }
++ prev_idx = j + 1;
+ }
+
+- state->start_bin = exec->ct0ca;
+- state->start_render = exec->ct1ca;
++ if (exec[0])
++ state->start_bin = exec[0]->ct0ca;
++ if (exec[1])
++ state->start_render = exec[1]->ct1ca;
+
+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+
+@@ -272,13 +290,15 @@ vc4_hangcheck_elapsed(unsigned long data
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ uint32_t ct0ca, ct1ca;
+ unsigned long irqflags;
+- struct vc4_exec_info *exec;
++ struct vc4_exec_info *bin_exec, *render_exec;
+
+ spin_lock_irqsave(&vc4->job_lock, irqflags);
+- exec = vc4_first_job(vc4);
++
++ bin_exec = vc4_first_bin_job(vc4);
++ render_exec = vc4_first_render_job(vc4);
+
+ /* If idle, we can stop watching for hangs. */
+- if (!exec) {
++ if (!bin_exec && !render_exec) {
+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+ return;
+ }
+@@ -289,9 +309,12 @@ vc4_hangcheck_elapsed(unsigned long data
+ /* If we've made any progress in execution, rearm the timer
+ * and wait.
+ */
+- if (ct0ca != exec->last_ct0ca || ct1ca != exec->last_ct1ca) {
+- exec->last_ct0ca = ct0ca;
+- exec->last_ct1ca = ct1ca;
++ if ((bin_exec && ct0ca != bin_exec->last_ct0ca) ||
++ (render_exec && ct1ca != render_exec->last_ct1ca)) {
++ if (bin_exec)
++ bin_exec->last_ct0ca = ct0ca;
++ if (render_exec)
++ render_exec->last_ct1ca = ct1ca;
+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+ vc4_queue_hangcheck(dev);
+ return;
+@@ -391,11 +414,13 @@ vc4_flush_caches(struct drm_device *dev)
+ * The job_lock should be held during this.
+ */
+ void
+-vc4_submit_next_job(struct drm_device *dev)
++vc4_submit_next_bin_job(struct drm_device *dev)
+ {
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+- struct vc4_exec_info *exec = vc4_first_job(vc4);
++ struct vc4_exec_info *exec;
+
++again:
++ exec = vc4_first_bin_job(vc4);
+ if (!exec)
+ return;
+
+@@ -405,11 +430,40 @@ vc4_submit_next_job(struct drm_device *d
+ V3D_WRITE(V3D_BPOA, 0);
+ V3D_WRITE(V3D_BPOS, 0);
+
+- if (exec->ct0ca != exec->ct0ea)
++ /* Either put the job in the binner if it uses the binner, or
++ * immediately move it to the to-be-rendered queue.
++ */
++ if (exec->ct0ca != exec->ct0ea) {
+ submit_cl(dev, 0, exec->ct0ca, exec->ct0ea);
++ } else {
++ vc4_move_job_to_render(dev, exec);
++ goto again;
++ }
++}
++
++void
++vc4_submit_next_render_job(struct drm_device *dev)
++{
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ struct vc4_exec_info *exec = vc4_first_render_job(vc4);
++
++ if (!exec)
++ return;
++
+ submit_cl(dev, 1, exec->ct1ca, exec->ct1ea);
+ }
+
++void
++vc4_move_job_to_render(struct drm_device *dev, struct vc4_exec_info *exec)
++{
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ bool was_empty = list_empty(&vc4->render_job_list);
++
++ list_move_tail(&exec->head, &vc4->render_job_list);
++ if (was_empty)
++ vc4_submit_next_render_job(dev);
++}
++
+ static void
+ vc4_update_bo_seqnos(struct vc4_exec_info *exec, uint64_t seqno)
+ {
+@@ -448,14 +502,14 @@ vc4_queue_submit(struct drm_device *dev,
+ exec->seqno = seqno;
+ vc4_update_bo_seqnos(exec, seqno);
+
+- list_add_tail(&exec->head, &vc4->job_list);
++ list_add_tail(&exec->head, &vc4->bin_job_list);
+
+ /* If no job was executing, kick ours off. Otherwise, it'll
+- * get started when the previous job's frame done interrupt
++ * get started when the previous job's flush done interrupt
+ * occurs.
+ */
+- if (vc4_first_job(vc4) == exec) {
+- vc4_submit_next_job(dev);
++ if (vc4_first_bin_job(vc4) == exec) {
++ vc4_submit_next_bin_job(dev);
+ vc4_queue_hangcheck(dev);
+ }
+
+@@ -849,7 +903,8 @@ vc4_gem_init(struct drm_device *dev)
+ {
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+
+- INIT_LIST_HEAD(&vc4->job_list);
++ INIT_LIST_HEAD(&vc4->bin_job_list);
++ INIT_LIST_HEAD(&vc4->render_job_list);
+ INIT_LIST_HEAD(&vc4->job_done_list);
+ INIT_LIST_HEAD(&vc4->seqno_cb_list);
+ spin_lock_init(&vc4->job_lock);
+--- a/drivers/gpu/drm/vc4/vc4_irq.c
++++ b/drivers/gpu/drm/vc4/vc4_irq.c
+@@ -30,6 +30,10 @@
+ * disables that specific interrupt, and 0s written are ignored
+ * (reading either one returns the set of enabled interrupts).
+ *
++ * When we take a binning flush done interrupt, we need to submit the
++ * next frame for binning and move the finished frame to the render
++ * thread.
++ *
+ * When we take a render frame interrupt, we need to wake the
+ * processes waiting for some frame to be done, and get the next frame
+ * submitted ASAP (so the hardware doesn't sit idle when there's work
+@@ -44,6 +48,7 @@
+ #include "vc4_regs.h"
+
+ #define V3D_DRIVER_IRQS (V3D_INT_OUTOMEM | \
++ V3D_INT_FLDONE | \
+ V3D_INT_FRDONE)
+
+ DECLARE_WAIT_QUEUE_HEAD(render_wait);
+@@ -77,7 +82,7 @@ vc4_overflow_mem_work(struct work_struct
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&vc4->job_lock, irqflags);
+- current_exec = vc4_first_job(vc4);
++ current_exec = vc4_first_bin_job(vc4);
+ if (current_exec) {
+ vc4->overflow_mem->seqno = vc4->finished_seqno + 1;
+ list_add_tail(&vc4->overflow_mem->unref_head,
+@@ -98,17 +103,43 @@ vc4_overflow_mem_work(struct work_struct
+ }
+
+ static void
+-vc4_irq_finish_job(struct drm_device *dev)
++vc4_irq_finish_bin_job(struct drm_device *dev)
++{
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ struct vc4_exec_info *exec = vc4_first_bin_job(vc4);
++
++ if (!exec)
++ return;
++
++ vc4_move_job_to_render(dev, exec);
++ vc4_submit_next_bin_job(dev);
++}
++
++static void
++vc4_cancel_bin_job(struct drm_device *dev)
++{
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ struct vc4_exec_info *exec = vc4_first_bin_job(vc4);
++
++ if (!exec)
++ return;
++
++ list_move_tail(&exec->head, &vc4->bin_job_list);
++ vc4_submit_next_bin_job(dev);
++}
++
++static void
++vc4_irq_finish_render_job(struct drm_device *dev)
+ {
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+- struct vc4_exec_info *exec = vc4_first_job(vc4);
++ struct vc4_exec_info *exec = vc4_first_render_job(vc4);
+
+ if (!exec)
+ return;
+
+ vc4->finished_seqno++;
+ list_move_tail(&exec->head, &vc4->job_done_list);
+- vc4_submit_next_job(dev);
++ vc4_submit_next_render_job(dev);
+
+ wake_up_all(&vc4->job_wait_queue);
+ schedule_work(&vc4->job_done_work);
+@@ -125,9 +156,10 @@ vc4_irq(int irq, void *arg)
+ barrier();
+ intctl = V3D_READ(V3D_INTCTL);
+
+- /* Acknowledge the interrupts we're handling here. The render
+- * frame done interrupt will be cleared, while OUTOMEM will
+- * stay high until the underlying cause is cleared.
++ /* Acknowledge the interrupts we're handling here. The binner
++ * last flush / render frame done interrupt will be cleared,
++ * while OUTOMEM will stay high until the underlying cause is
++ * cleared.
+ */
+ V3D_WRITE(V3D_INTCTL, intctl);
+
+@@ -138,9 +170,16 @@ vc4_irq(int irq, void *arg)
+ status = IRQ_HANDLED;
+ }
+
++ if (intctl & V3D_INT_FLDONE) {
++ spin_lock(&vc4->job_lock);
++ vc4_irq_finish_bin_job(dev);
++ spin_unlock(&vc4->job_lock);
++ status = IRQ_HANDLED;
++ }
++
+ if (intctl & V3D_INT_FRDONE) {
+ spin_lock(&vc4->job_lock);
+- vc4_irq_finish_job(dev);
++ vc4_irq_finish_render_job(dev);
+ spin_unlock(&vc4->job_lock);
+ status = IRQ_HANDLED;
+ }
+@@ -205,6 +244,7 @@ void vc4_irq_reset(struct drm_device *de
+ V3D_WRITE(V3D_INTENA, V3D_DRIVER_IRQS);
+
+ spin_lock_irqsave(&vc4->job_lock, irqflags);
+- vc4_irq_finish_job(dev);
++ vc4_cancel_bin_job(dev);
++ vc4_irq_finish_render_job(dev);
+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+ }
diff --git a/target/linux/brcm2708/patches-4.4/0294-drm-vc4-Let-gpiolib-know-that-we-re-OK-with-sleeping.patch b/target/linux/brcm2708/patches-4.4/0294-drm-vc4-Let-gpiolib-know-that-we-re-OK-with-sleeping.patch
new file mode 100644
index 0000000000..df745860d8
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0294-drm-vc4-Let-gpiolib-know-that-we-re-OK-with-sleeping.patch
@@ -0,0 +1,27 @@
+From 5967aea469c030c3bc258b52b9f3704fd9873e63 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 29 Feb 2016 17:53:00 -0800
+Subject: [PATCH 294/381] drm/vc4: Let gpiolib know that we're OK with sleeping
+ for HPD.
+
+Fixes an error thrown every few seconds when we poll HPD when it's on
+a I2C to GPIO expander.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Tested-by: Daniel Stone <daniels@collabora.com>
+(cherry picked from commit 0e60eab57557bc06bb3a5ef8d5d6dcd9ddd47aff)
+---
+ drivers/gpu/drm/vc4/vc4_hdmi.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
+@@ -168,7 +168,7 @@ vc4_hdmi_connector_detect(struct drm_con
+ return connector_status_connected;
+
+ if (vc4->hdmi->hpd_gpio) {
+- if (gpio_get_value(vc4->hdmi->hpd_gpio))
++ if (gpio_get_value_cansleep(vc4->hdmi->hpd_gpio))
+ return connector_status_connected;
+ else
+ return connector_status_disconnected;
diff --git a/target/linux/brcm2708/patches-4.4/0295-drm-vc4-Respect-GPIO_ACTIVE_LOW-on-HDMI-HPD-if-set-i.patch b/target/linux/brcm2708/patches-4.4/0295-drm-vc4-Respect-GPIO_ACTIVE_LOW-on-HDMI-HPD-if-set-i.patch
new file mode 100644
index 0000000000..c068bd9dfd
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0295-drm-vc4-Respect-GPIO_ACTIVE_LOW-on-HDMI-HPD-if-set-i.patch
@@ -0,0 +1,57 @@
+From 2e6c1ee022829aa063838c244dbb94e2a8df04d2 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 29 Feb 2016 17:53:01 -0800
+Subject: [PATCH 295/381] drm/vc4: Respect GPIO_ACTIVE_LOW on HDMI HPD if set
+ in the devicetree.
+
+The original Raspberry Pi had the GPIO active high, but the later
+models are active low. The DT GPIO bindings allow specifying the
+active flag, except that it doesn't get propagated to the gpiodesc, so
+you have to handle it yourself.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Tested-by: Daniel Stone <daniels@collabora.com>
+(cherry picked from commit 0b06e0a7945130e6a187f7959529cba7725f573a)
+---
+ drivers/gpu/drm/vc4/vc4_hdmi.c | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
+@@ -47,6 +47,7 @@ struct vc4_hdmi {
+ void __iomem *hdmicore_regs;
+ void __iomem *hd_regs;
+ int hpd_gpio;
++ bool hpd_active_low;
+
+ struct clk *pixel_clock;
+ struct clk *hsm_clock;
+@@ -168,7 +169,8 @@ vc4_hdmi_connector_detect(struct drm_con
+ return connector_status_connected;
+
+ if (vc4->hdmi->hpd_gpio) {
+- if (gpio_get_value_cansleep(vc4->hdmi->hpd_gpio))
++ if (gpio_get_value_cansleep(vc4->hdmi->hpd_gpio) ^
++ vc4->hdmi->hpd_active_low)
+ return connector_status_connected;
+ else
+ return connector_status_disconnected;
+@@ -519,11 +521,17 @@ static int vc4_hdmi_bind(struct device *
+ * we'll use the HDMI core's register.
+ */
+ if (of_find_property(dev->of_node, "hpd-gpios", &value)) {
+- hdmi->hpd_gpio = of_get_named_gpio(dev->of_node, "hpd-gpios", 0);
++ enum of_gpio_flags hpd_gpio_flags;
++
++ hdmi->hpd_gpio = of_get_named_gpio_flags(dev->of_node,
++ "hpd-gpios", 0,
++ &hpd_gpio_flags);
+ if (hdmi->hpd_gpio < 0) {
+ ret = hdmi->hpd_gpio;
+ goto err_unprepare_hsm;
+ }
++
++ hdmi->hpd_active_low = hpd_gpio_flags & OF_GPIO_ACTIVE_LOW;
+ }
+
+ vc4->hdmi = hdmi;
diff --git a/target/linux/brcm2708/patches-4.4/0296-drm-vc4-Return-EFAULT-on-copy_from_user-failure.patch b/target/linux/brcm2708/patches-4.4/0296-drm-vc4-Return-EFAULT-on-copy_from_user-failure.patch
new file mode 100644
index 0000000000..9fc05426e2
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0296-drm-vc4-Return-EFAULT-on-copy_from_user-failure.patch
@@ -0,0 +1,36 @@
+From ca25ba22f36a3e55b94f650e402564d830843edb Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <dan.carpenter@oracle.com>
+Date: Tue, 8 Mar 2016 15:09:41 +0300
+Subject: [PATCH 296/381] drm/vc4: Return -EFAULT on copy_from_user() failure
+
+The copy_from_user() function returns the number of bytes not copied but
+we want to return a negative error code.
+
+Fixes: 463873d57014 ('drm/vc4: Add an API for creating GPU shaders in GEM BOs.')
+Cc: stable@vger.kernel.org
+Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
+Reviewed-by: Eric Anholt <eric@anholt.net>
+Signed-off-by: Eric Anholt <eric@anholt.net>
+(cherry picked from commit 585cb132a48190b554aecda2ebc3e2911fcbb665)
+---
+ drivers/gpu/drm/vc4/vc4_bo.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_bo.c
++++ b/drivers/gpu/drm/vc4/vc4_bo.c
+@@ -519,11 +519,12 @@ vc4_create_shader_bo_ioctl(struct drm_de
+ if (IS_ERR(bo))
+ return PTR_ERR(bo);
+
+- ret = copy_from_user(bo->base.vaddr,
++ if (copy_from_user(bo->base.vaddr,
+ (void __user *)(uintptr_t)args->data,
+- args->size);
+- if (ret != 0)
++ args->size)) {
++ ret = -EFAULT;
+ goto fail;
++ }
+ /* Clear the rest of the memory from allocating from the BO
+ * cache.
+ */
diff --git a/target/linux/brcm2708/patches-4.4/0297-drm-vc4-Recognize-a-more-specific-compatible-string-.patch b/target/linux/brcm2708/patches-4.4/0297-drm-vc4-Recognize-a-more-specific-compatible-string-.patch
new file mode 100644
index 0000000000..7060bf2d1d
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0297-drm-vc4-Recognize-a-more-specific-compatible-string-.patch
@@ -0,0 +1,29 @@
+From 73ecaa8211e2751d37bffc316cea700927b228b7 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Fri, 4 Mar 2016 12:32:07 -0800
+Subject: [PATCH 297/381] drm/vc4: Recognize a more specific compatible string
+ for V3D.
+
+The Raspberry Pi Foundation's firmware updates are shipping device
+trees using the old string, so we'll keep recognizing that as this rev
+of V3D. Still, we should use a more specific name in the upstream DT
+to clarify which board is being supported, in case we do other revs of
+V3D in the future.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Acked-by: Stephen Warren <swarren@wwwdotorg.org>
+(cherry picked from commit 90d7116061f86c1f8ea460806a0414addea7b58b)
+---
+ drivers/gpu/drm/vc4/vc4_v3d.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_v3d.c
++++ b/drivers/gpu/drm/vc4/vc4_v3d.c
+@@ -256,6 +256,7 @@ static int vc4_v3d_dev_remove(struct pla
+ }
+
+ static const struct of_device_id vc4_v3d_dt_match[] = {
++ { .compatible = "brcm,bcm2835-v3d" },
+ { .compatible = "brcm,vc4-v3d" },
+ {}
+ };
diff --git a/target/linux/brcm2708/patches-4.4/0298-ARM-bcm2708-Move-the-CMA-range-down-for-kernel-4.4.patch b/target/linux/brcm2708/patches-4.4/0298-ARM-bcm2708-Move-the-CMA-range-down-for-kernel-4.4.patch
new file mode 100644
index 0000000000..19243ccb37
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0298-ARM-bcm2708-Move-the-CMA-range-down-for-kernel-4.4.patch
@@ -0,0 +1,24 @@
+From 94f13d08b80c3470b57b7997766049f2860f22ba Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Tue, 19 Apr 2016 17:21:06 -0700
+Subject: [PATCH 298/381] ARM: bcm2708: Move the CMA range down for kernel 4.4.
+
+The previous area no longer works, for reasons I haven't investigated.
+Just move it somewhere that works.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts
++++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts
+@@ -91,7 +91,7 @@
+ fragment@4 {
+ target-path = "/chosen";
+ __overlay__ {
+- bootargs = "cma=256M@512M";
++ bootargs = "cma=256M@256M";
+ };
+ };
+ };
diff --git a/target/linux/brcm2708/patches-4.4/0299-clk-bcm2835-fix-check-of-error-code-returned-by-devm.patch b/target/linux/brcm2708/patches-4.4/0299-clk-bcm2835-fix-check-of-error-code-returned-by-devm.patch
new file mode 100644
index 0000000000..25b26a9614
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0299-clk-bcm2835-fix-check-of-error-code-returned-by-devm.patch
@@ -0,0 +1,33 @@
+From f083d686ec57e2b856f12a52978b594d719cddfc Mon Sep 17 00:00:00 2001
+From: Vladimir Zapolskiy <vz@mleia.com>
+Date: Sun, 6 Mar 2016 03:21:35 +0200
+Subject: [PATCH 299/381] clk: bcm2835: fix check of error code returned by
+ devm_ioremap_resource()
+
+The change fixes potential oops while accessing iomem on invalid
+address, if devm_ioremap_resource() fails due to some reason.
+
+The devm_ioremap_resource() function returns ERR_PTR() and never
+returns NULL, which makes useless a following check for NULL.
+
+Signed-off-by: Vladimir Zapolskiy <vz@mleia.com>
+Fixes: 5e63dcc74b30 ("clk: bcm2835: Add a driver for the auxiliary peripheral clock gates")
+Reviewed-by: Eric Anholt <eric@anholt.net>
+Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+---
+ drivers/clk/bcm/clk-bcm2835-aux.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/clk/bcm/clk-bcm2835-aux.c
++++ b/drivers/clk/bcm/clk-bcm2835-aux.c
+@@ -38,8 +38,8 @@ static int bcm2835_aux_clk_probe(struct
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ reg = devm_ioremap_resource(dev, res);
+- if (!reg)
+- return -ENODEV;
++ if (IS_ERR(reg))
++ return PTR_ERR(reg);
+
+ onecell = devm_kmalloc(dev, sizeof(*onecell), GFP_KERNEL);
+ if (!onecell)
diff --git a/target/linux/brcm2708/patches-4.4/0300-vchiq_arm-Add-completion-records-under-the-mutex.patch b/target/linux/brcm2708/patches-4.4/0300-vchiq_arm-Add-completion-records-under-the-mutex.patch
new file mode 100644
index 0000000000..14bb755d6c
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0300-vchiq_arm-Add-completion-records-under-the-mutex.patch
@@ -0,0 +1,63 @@
+From 9b9ba43bf2cfd1bde5651f69a4f141a66dd7a012 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Thu, 21 Apr 2016 13:49:32 +0100
+Subject: [PATCH 300/381] vchiq_arm: Add completion records under the mutex
+
+An issue was observed when flushing openmax components
+which generate a large number of messages returning
+buffers to host.
+
+We occasionally found a duplicate message from 16
+messages prior, resulting in a buffer returned twice.
+
+While only one thread adds completions, without the
+mutex you don't get the protection of the automatic
+memory barrier you get with synchronisation objects.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c
++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c
+@@ -210,6 +210,8 @@ add_completion(VCHIQ_INSTANCE_T instance
+ VCHIQ_COMPLETION_DATA_T *completion;
+ DEBUG_INITIALISE(g_state.local)
+
++ mutex_lock(&instance->completion_mutex);
++
+ while (instance->completion_insert ==
+ (instance->completion_remove + MAX_COMPLETIONS)) {
+ /* Out of space - wait for the client */
+@@ -217,11 +219,17 @@ add_completion(VCHIQ_INSTANCE_T instance
+ vchiq_log_trace(vchiq_arm_log_level,
+ "add_completion - completion queue full");
+ DEBUG_COUNT(COMPLETION_QUEUE_FULL_COUNT);
++
++ mutex_unlock(&instance->completion_mutex);
+ if (down_interruptible(&instance->remove_event) != 0) {
+ vchiq_log_info(vchiq_arm_log_level,
+ "service_callback interrupted");
+ return VCHIQ_RETRY;
+- } else if (instance->closing) {
++ }
++
++ mutex_lock(&instance->completion_mutex);
++ if (instance->closing) {
++ mutex_unlock(&instance->completion_mutex);
+ vchiq_log_info(vchiq_arm_log_level,
+ "service_callback closing");
+ return VCHIQ_SUCCESS;
+@@ -254,8 +262,11 @@ add_completion(VCHIQ_INSTANCE_T instance
+ if (reason == VCHIQ_MESSAGE_AVAILABLE)
+ user_service->message_available_pos =
+ instance->completion_insert;
++
+ instance->completion_insert++;
+
++ mutex_unlock(&instance->completion_mutex);
++
+ up(&instance->insert_event);
+
+ return VCHIQ_SUCCESS;
diff --git a/target/linux/brcm2708/patches-4.4/0301-config-Add-DRM_UDL-module.patch b/target/linux/brcm2708/patches-4.4/0301-config-Add-DRM_UDL-module.patch
new file mode 100644
index 0000000000..acaedb1528
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0301-config-Add-DRM_UDL-module.patch
@@ -0,0 +1,59 @@
+From dd6c8868f14136f8095b8cb1a35254b18cadc434 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Thu, 21 Apr 2016 16:07:15 +0100
+Subject: [PATCH 301/381] config: Add DRM_UDL module
+
+See: https://github.com/raspberrypi/linux/issues/1422
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/configs/bcm2709_defconfig | 5 +++--
+ arch/arm/configs/bcmrpi_defconfig | 5 +++--
+ 2 files changed, 6 insertions(+), 4 deletions(-)
+
+--- a/arch/arm/configs/bcm2709_defconfig
++++ b/arch/arm/configs/bcm2709_defconfig
+@@ -815,6 +815,7 @@ CONFIG_VIDEO_TW9906=m
+ CONFIG_VIDEO_OV7640=m
+ CONFIG_VIDEO_MT9V011=m
+ CONFIG_DRM=m
++CONFIG_DRM_UDL=m
+ CONFIG_DRM_VC4=m
+ CONFIG_FB=y
+ CONFIG_FB_BCM2708=y
+@@ -854,10 +855,10 @@ CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC=m
+ CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS=m
+ CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI=m
+ CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP=m
+-CONFIG_SND_BCM2708_SOC_BOOMBERRY_DAC=m
+-CONFIG_SND_BCM2708_SOC_BOOMBERRY_DIGI=m
+ CONFIG_SND_BCM2708_SOC_RPI_DAC=m
+ CONFIG_SND_BCM2708_SOC_RPI_PROTO=m
++CONFIG_SND_BCM2708_SOC_BOOMBERRY_DAC=m
++CONFIG_SND_BCM2708_SOC_BOOMBERRY_DIGI=m
+ CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m
+ CONFIG_SND_BCM2708_SOC_RASPIDAC3=m
+ CONFIG_SND_SOC_ADAU1701=m
+--- a/arch/arm/configs/bcmrpi_defconfig
++++ b/arch/arm/configs/bcmrpi_defconfig
+@@ -807,6 +807,7 @@ CONFIG_VIDEO_TW9906=m
+ CONFIG_VIDEO_OV7640=m
+ CONFIG_VIDEO_MT9V011=m
+ CONFIG_DRM=m
++CONFIG_DRM_UDL=m
+ CONFIG_DRM_VC4=m
+ CONFIG_FB=y
+ CONFIG_FB_BCM2708=y
+@@ -846,10 +847,10 @@ CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC=m
+ CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS=m
+ CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI=m
+ CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP=m
+-CONFIG_SND_BCM2708_SOC_BOOMBERRY_DAC=m
+-CONFIG_SND_BCM2708_SOC_BOOMBERRY_DIGI=m
+ CONFIG_SND_BCM2708_SOC_RPI_DAC=m
+ CONFIG_SND_BCM2708_SOC_RPI_PROTO=m
++CONFIG_SND_BCM2708_SOC_BOOMBERRY_DAC=m
++CONFIG_SND_BCM2708_SOC_BOOMBERRY_DIGI=m
+ CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m
+ CONFIG_SND_BCM2708_SOC_RASPIDAC3=m
+ CONFIG_SND_SOC_ADAU1701=m
diff --git a/target/linux/brcm2708/patches-4.4/0302-bcm2835-i2s-Reduce-the-TX-DREQ-threshold.patch b/target/linux/brcm2708/patches-4.4/0302-bcm2835-i2s-Reduce-the-TX-DREQ-threshold.patch
new file mode 100644
index 0000000000..7c6e4f07c8
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0302-bcm2835-i2s-Reduce-the-TX-DREQ-threshold.patch
@@ -0,0 +1,48 @@
+From 0d3f33f6f76201d8468a4da376b1b0e84740cecb Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Thu, 21 Apr 2016 15:44:14 +0100
+Subject: [PATCH 302/381] bcm2835-i2s: Reduce the TX DREQ threshold
+
+TX FIFO overrun is thought to be the cause of channel swapping, so
+reducing the DREQ threshold seems reasonable and appears to be
+effective.
+
+See: https://github.com/raspberrypi/linux/issues/1417
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ sound/soc/bcm/bcm2835-i2s.c | 21 ++++++++++++++-------
+ 1 file changed, 14 insertions(+), 7 deletions(-)
+
+--- a/sound/soc/bcm/bcm2835-i2s.c
++++ b/sound/soc/bcm/bcm2835-i2s.c
+@@ -555,15 +555,22 @@ static int bcm2835_i2s_hw_params(struct
+
+ /* Setup the DMA parameters */
+ regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG,
+- BCM2835_I2S_RXTHR(1)
+- | BCM2835_I2S_TXTHR(1)
+- | BCM2835_I2S_DMAEN, 0xffffffff);
++ BCM2835_I2S_RXTHR(3)
++ | BCM2835_I2S_TXTHR(3)
++ | BCM2835_I2S_DMAEN,
++ BCM2835_I2S_RXTHR(1)
++ | BCM2835_I2S_TXTHR(1)
++ | BCM2835_I2S_DMAEN);
+
+ regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_DREQ_A_REG,
+- BCM2835_I2S_TX_PANIC(0x10)
+- | BCM2835_I2S_RX_PANIC(0x30)
+- | BCM2835_I2S_TX(0x30)
+- | BCM2835_I2S_RX(0x20), 0xffffffff);
++ BCM2835_I2S_TX_PANIC(0x7f)
++ | BCM2835_I2S_RX_PANIC(0x7f)
++ | BCM2835_I2S_TX(0x7f)
++ | BCM2835_I2S_RX(0x7f),
++ BCM2835_I2S_TX_PANIC(0x10)
++ | BCM2835_I2S_RX_PANIC(0x30)
++ | BCM2835_I2S_TX(0x20)
++ | BCM2835_I2S_RX(0x20));
+
+ /* Clear FIFOs */
+ bcm2835_i2s_clear_fifos(dev, true, true);
diff --git a/target/linux/brcm2708/patches-4.4/0303-V4L2-Request-maximum-resolution-from-GPU.patch b/target/linux/brcm2708/patches-4.4/0303-V4L2-Request-maximum-resolution-from-GPU.patch
new file mode 100644
index 0000000000..c4d9b0c6dd
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0303-V4L2-Request-maximum-resolution-from-GPU.patch
@@ -0,0 +1,193 @@
+From 5646e586e0494722d5d0783b573819b6d238c71b Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <6by9@users.noreply.github.com>
+Date: Sat, 16 Apr 2016 23:09:54 +0100
+Subject: [PATCH 303/381] V4L2: Request maximum resolution from GPU
+
+Get resolution information about the sensors from the GPU
+and advertise it correctly.
+
+Signed-off-by: Dave Stevenson <6by9@users.noreply.github.com>
+---
+ drivers/media/platform/bcm2835/bcm2835-camera.c | 59 +++++++++++++++++--------
+ drivers/media/platform/bcm2835/bcm2835-camera.h | 3 +-
+ 2 files changed, 43 insertions(+), 19 deletions(-)
+
+--- a/drivers/media/platform/bcm2835/bcm2835-camera.c
++++ b/drivers/media/platform/bcm2835/bcm2835-camera.c
+@@ -38,8 +38,6 @@
+ #define BM2835_MMAL_MODULE_NAME "bcm2835-v4l2"
+ #define MIN_WIDTH 16
+ #define MIN_HEIGHT 16
+-#define MAX_WIDTH 2592
+-#define MAX_HEIGHT 1944
+ #define MIN_BUFFER_SIZE (80*1024)
+
+ #define MAX_VIDEO_MODE_WIDTH 1280
+@@ -729,11 +727,11 @@ static int vidioc_try_fmt_vid_overlay(st
+ f->fmt.win.clipcount = 0;
+ f->fmt.win.bitmap = NULL;
+
+- v4l_bound_align_image(&f->fmt.win.w.width, MIN_WIDTH, MAX_WIDTH, 1,
+- &f->fmt.win.w.height, MIN_HEIGHT, MAX_HEIGHT,
++ v4l_bound_align_image(&f->fmt.win.w.width, MIN_WIDTH, dev->max_width, 1,
++ &f->fmt.win.w.height, MIN_HEIGHT, dev->max_height,
+ 1, 0);
+- v4l_bound_align_image(&f->fmt.win.w.left, MIN_WIDTH, MAX_WIDTH, 1,
+- &f->fmt.win.w.top, MIN_HEIGHT, MAX_HEIGHT,
++ v4l_bound_align_image(&f->fmt.win.w.left, MIN_WIDTH, dev->max_width, 1,
++ &f->fmt.win.w.top, MIN_HEIGHT, dev->max_height,
+ 1, 0);
+
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+@@ -961,8 +959,9 @@ static int vidioc_try_fmt_vid_cap(struct
+ "Clipping/aligning %dx%d format %08X\n",
+ f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.pixelformat);
+
+- v4l_bound_align_image(&f->fmt.pix.width, MIN_WIDTH, MAX_WIDTH, 1,
+- &f->fmt.pix.height, MIN_HEIGHT, MAX_HEIGHT, 1, 0);
++ v4l_bound_align_image(&f->fmt.pix.width, MIN_WIDTH, dev->max_width, 1,
++ &f->fmt.pix.height, MIN_HEIGHT, dev->max_height,
++ 1, 0);
+ f->fmt.pix.bytesperline = f->fmt.pix.width * mfmt->ybbp;
+
+ /* Image buffer has to be padded to allow for alignment, even though
+@@ -1301,9 +1300,10 @@ static int vidioc_s_fmt_vid_cap(struct f
+ int vidioc_enum_framesizes(struct file *file, void *fh,
+ struct v4l2_frmsizeenum *fsize)
+ {
++ struct bm2835_mmal_dev *dev = video_drvdata(file);
+ static const struct v4l2_frmsize_stepwise sizes = {
+- MIN_WIDTH, MAX_WIDTH, 2,
+- MIN_HEIGHT, MAX_HEIGHT, 2
++ MIN_WIDTH, 0, 2,
++ MIN_HEIGHT, 0, 2
+ };
+ int i;
+
+@@ -1316,6 +1316,8 @@ int vidioc_enum_framesizes(struct file *
+ return -EINVAL;
+ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+ fsize->stepwise = sizes;
++ fsize->stepwise.max_width = dev->max_width;
++ fsize->stepwise.max_height = dev->max_height;
+ return 0;
+ }
+
+@@ -1323,6 +1325,7 @@ int vidioc_enum_framesizes(struct file *
+ static int vidioc_enum_frameintervals(struct file *file, void *priv,
+ struct v4l2_frmivalenum *fival)
+ {
++ struct bm2835_mmal_dev *dev = video_drvdata(file);
+ int i;
+
+ if (fival->index)
+@@ -1335,8 +1338,8 @@ static int vidioc_enum_frameintervals(st
+ return -EINVAL;
+
+ /* regarding width & height - we support any within range */
+- if (fival->width < MIN_WIDTH || fival->width > MAX_WIDTH ||
+- fival->height < MIN_HEIGHT || fival->height > MAX_HEIGHT)
++ if (fival->width < MIN_WIDTH || fival->width > dev->max_width ||
++ fival->height < MIN_HEIGHT || fival->height > dev->max_height)
+ return -EINVAL;
+
+ fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS;
+@@ -1499,12 +1502,17 @@ static struct video_device vdev_template
+ .release = video_device_release_empty,
+ };
+
+-static int get_num_cameras(struct vchiq_mmal_instance *instance)
++/* Returns the number of cameras, and also the max resolution supported
++ * by those cameras.
++ */
++static int get_num_cameras(struct vchiq_mmal_instance *instance,
++ unsigned int resolutions[][2], int num_resolutions)
+ {
+ int ret;
+ struct vchiq_mmal_component *cam_info_component;
+ struct mmal_parameter_camera_info_t cam_info = {0};
+ int param_size = sizeof(cam_info);
++ int i;
+
+ /* create a camera_info component */
+ ret = vchiq_mmal_component_init(instance, "camera_info",
+@@ -1520,6 +1528,14 @@ static int get_num_cameras(struct vchiq_
+ &param_size)) {
+ pr_info("Failed to get camera info\n");
+ }
++ for (i = 0;
++ i < (cam_info.num_cameras > num_resolutions ?
++ cam_info.num_cameras :
++ num_resolutions);
++ i++) {
++ resolutions[i][0] = cam_info.cameras[i].max_width;
++ resolutions[i][1] = cam_info.cameras[i].max_height;
++ }
+
+ vchiq_mmal_component_finalise(instance,
+ cam_info_component);
+@@ -1528,12 +1544,13 @@ static int get_num_cameras(struct vchiq_
+ }
+
+ static int set_camera_parameters(struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_component *camera)
++ struct vchiq_mmal_component *camera,
++ struct bm2835_mmal_dev *dev)
+ {
+ int ret;
+ struct mmal_parameter_camera_config cam_config = {
+- .max_stills_w = MAX_WIDTH,
+- .max_stills_h = MAX_HEIGHT,
++ .max_stills_w = dev->max_width,
++ .max_stills_h = dev->max_height,
+ .stills_yuv422 = 1,
+ .one_shot_stills = 1,
+ .max_preview_video_w = (max_video_width > 1920) ?
+@@ -1576,7 +1593,8 @@ static int __init mmal_init(struct bm283
+ }
+
+ ret = set_camera_parameters(dev->instance,
+- dev->component[MMAL_COMPONENT_CAMERA]);
++ dev->component[MMAL_COMPONENT_CAMERA],
++ dev);
+ if (ret < 0)
+ goto unreg_camera;
+
+@@ -1838,12 +1856,15 @@ static int __init bm2835_mmal_init(void)
+ int camera;
+ unsigned int num_cameras;
+ struct vchiq_mmal_instance *instance;
++ unsigned int resolutions[MAX_BCM2835_CAMERAS][2];
+
+ ret = vchiq_mmal_init(&instance);
+ if (ret < 0)
+ return ret;
+
+- num_cameras = get_num_cameras(instance);
++ num_cameras = get_num_cameras(instance,
++ resolutions,
++ MAX_BCM2835_CAMERAS);
+ if (num_cameras > MAX_BCM2835_CAMERAS)
+ num_cameras = MAX_BCM2835_CAMERAS;
+
+@@ -1853,6 +1874,8 @@ static int __init bm2835_mmal_init(void)
+ return -ENOMEM;
+
+ dev->camera_num = camera;
++ dev->max_width = resolutions[camera][0];
++ dev->max_height = resolutions[camera][1];
+
+ /* setup device defaults */
+ dev->overlay.w.left = 150;
+--- a/drivers/media/platform/bcm2835/bcm2835-camera.h
++++ b/drivers/media/platform/bcm2835/bcm2835-camera.h
+@@ -107,7 +107,8 @@ struct bm2835_mmal_dev {
+ } capture;
+
+ unsigned int camera_num;
+-
++ unsigned int max_width;
++ unsigned int max_height;
+ };
+
+ int bm2835_mmal_init_controls(
diff --git a/target/linux/brcm2708/patches-4.4/0304-ARM-bcm2835-add-i2s-gpio28-31-for-cm.patch b/target/linux/brcm2708/patches-4.4/0304-ARM-bcm2835-add-i2s-gpio28-31-for-cm.patch
new file mode 100644
index 0000000000..05cac0ee9f
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0304-ARM-bcm2835-add-i2s-gpio28-31-for-cm.patch
@@ -0,0 +1,62 @@
+From 791046d531f798944715a214748387449ae9c4b8 Mon Sep 17 00:00:00 2001
+From: Martin Sperl <kernel@martin.sperl.org>
+Date: Sat, 23 Apr 2016 15:21:41 +0000
+Subject: [PATCH 304/381] ARM: bcm2835: add i2s-gpio28-31 for cm
+
+Add i2s-gpio28-31 overlay for compute module
+so that i2s is using gpio28-31
+
+Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 6 ++++++
+ arch/arm/boot/dts/overlays/i2s-gpio28-31-overlay.dts | 18 ++++++++++++++++++
+ 3 files changed, 25 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/i2s-gpio28-31-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -37,6 +37,7 @@ dtbo-$(RPI_DT_OVERLAYS) += i2c-mux-pca95
+ dtbo-$(RPI_DT_OVERLAYS) += i2c-pwm-pca9685a.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += i2c0-bcm2708.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += i2c1-bcm2708.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += i2s-gpio28-31.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += i2s-mmap.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += iqaudio-dac.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += iqaudio-dacplus.dtbo
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -464,6 +464,12 @@ Params: sda1_pin GPIO pin
+ default 4)
+
+
++Name: i2s-gpio28-31
++Info: move I2S function block to GPIO 28 to 31
++Load: dtoverlay=i2s-gpio28-31
++Params: <None>
++
++
+ Name: i2s-mmap
+ Info: Enables mmap support in the bcm2708-i2s driver
+ Load: dtoverlay=i2s-mmap
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/i2s-gpio28-31-overlay.dts
+@@ -0,0 +1,18 @@
++/*
++ * Device tree overlay to move i2s to gpio 28 to 31 on CM
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709";
++
++ fragment@0 {
++ target = <&i2s_pins>;
++ __overlay__ {
++ brcm,pins = <28 29 30 31>;
++ brcm,function = <6>; /* alt2 */
++ };
++ };
++};
diff --git a/target/linux/brcm2708/patches-4.4/0305-drm-vc4-Add-DT-parameters-to-control-CMA-usage.patch b/target/linux/brcm2708/patches-4.4/0305-drm-vc4-Add-DT-parameters-to-control-CMA-usage.patch
new file mode 100644
index 0000000000..797023d037
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0305-drm-vc4-Add-DT-parameters-to-control-CMA-usage.patch
@@ -0,0 +1,75 @@
+From 937dd48dd631d45dbee39853dcb1cd98220bb1e5 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Sun, 24 Apr 2016 17:28:15 +0100
+Subject: [PATCH 305/381] drm/vc4: Add DT parameters to control CMA usage
+
+Example: dtoverlay=vc4-kms-v3d,cma-128
+
+See: https://github.com/raspberrypi/linux/pull/1431
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/overlays/README | 8 +++--
+ arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts | 36 ++++++++++++++++++++++
+ 2 files changed, 42 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1023,8 +1023,12 @@ Name: vc4-kms-v3d
+ Info: Enable Eric Anholt's DRM VC4 HDMI/HVS/V3D driver. Running startx or
+ booting to GUI while this overlay is in use will cause interesting
+ lockups.
+-Load: dtoverlay=vc4-kms-v3d
+-Params: <None>
++Load: dtoverlay=vc4-kms-v3d,<param>
++Params: cma-256 CMA is 256MB, 256MB-aligned (needs 1GB)
++ cma-192 CMA is 192MB, 256MB-aligned (needs 1GB)
++ cma-128 CMA is 128MB, 128MB-aligned
++ cma-96 CMA is 96MB, 128MB-aligned
++ cma-64 CMA is 64MB, 64MB-aligned
+
+
+ Name: vga666
+--- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts
++++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts
+@@ -94,4 +94,40 @@
+ bootargs = "cma=256M@256M";
+ };
+ };
++
++ fragment@5 {
++ target-path = "/chosen";
++ __dormant__ {
++ bootargs = "cma=192M@256M";
++ };
++ };
++
++ fragment@6 {
++ target-path = "/chosen";
++ __dormant__ {
++ bootargs = "cma=128M@128M";
++ };
++ };
++
++ fragment@7 {
++ target-path = "/chosen";
++ __dormant__ {
++ bootargs = "cma=96M@128M";
++ };
++ };
++
++ fragment@8 {
++ target-path = "/chosen";
++ __dormant__ {
++ bootargs = "cma=64M@64M";
++ };
++ };
++
++ __overrides__ {
++ cma-256 = <0>,"+4-5-6-7-8";
++ cma-192 = <0>,"-4+5-6-7-8";
++ cma-128 = <0>,"-4-5+6-7-8";
++ cma-96 = <0>,"-4-5-6+7-8";
++ cma-64 = <0>,"-4-5-6-7+8";
++ };
+ };
diff --git a/target/linux/brcm2708/patches-4.4/0306-SQUASH-BCM270X_DT-Add-make-rule-for-sdio-1bit.patch b/target/linux/brcm2708/patches-4.4/0306-SQUASH-BCM270X_DT-Add-make-rule-for-sdio-1bit.patch
new file mode 100644
index 0000000000..9d23d4cc81
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0306-SQUASH-BCM270X_DT-Add-make-rule-for-sdio-1bit.patch
@@ -0,0 +1,22 @@
+From 3fc5b9e6d4ec9ed6dc6e6165099e3e5e552eb446 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 25 Apr 2016 10:43:36 +0100
+Subject: [PATCH 306/381] SQUASH: BCM270X_DT: Add make rule for sdio-1bit
+
+See: https://github.com/raspberrypi/linux/pull/1301
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -66,6 +66,7 @@ dtbo-$(RPI_DT_OVERLAYS) += rpi-proto.dtb
+ dtbo-$(RPI_DT_OVERLAYS) += rpi-sense.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += sdhost.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += sdio.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += sdio-1bit.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += sdtweak.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += smi-dev.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += smi-nand.dtbo
diff --git a/target/linux/brcm2708/patches-4.4/0307-dts-add-overlay-for-pitft22.patch b/target/linux/brcm2708/patches-4.4/0307-dts-add-overlay-for-pitft22.patch
new file mode 100644
index 0000000000..32174775a6
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0307-dts-add-overlay-for-pitft22.patch
@@ -0,0 +1,123 @@
+From 56fa6791fbd2021cec1eeb45462b2ad3d1631a05 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Petter=20Mab=C3=A4cker?= <petter@technux.se>
+Date: Fri, 8 Jan 2016 09:02:44 +0100
+Subject: [PATCH 307/381] dts: add overlay for pitft22
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add the pitft22 overlay from adafruit Adafruit-Pi-Kernel-o-Matic repo:
+https://github.com/adafruit/Adafruit-Pi-Kernel-o-Matic
+
+Signed-off-by: Petter Mabäcker <petter@technux.se>
+Signed-off-by: Andrei Gherzan <andrei@resin.io>
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 12 +++++
+ arch/arm/boot/dts/overlays/pitft22-overlay.dts | 69 ++++++++++++++++++++++++++
+ 3 files changed, 82 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/pitft22-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -51,6 +51,7 @@ dtbo-$(RPI_DT_OVERLAYS) += pi3-disable-b
+ dtbo-$(RPI_DT_OVERLAYS) += pi3-miniuart-bt.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += piscreen.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += piscreen2r.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += pitft22.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += pitft28-capacitive.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += pitft28-resistive.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += pps-gpio.dtbo
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -644,6 +644,18 @@ Params: speed Display
+ xohms Touchpanel sensitivity (X-plate resistance)
+
+
++Name: pitft22
++Info: Adafruit PiTFT 2.2" screen
++Load: dtoverlay=pitft22,<param>=<val>
++Params: speed Display SPI bus speed
++
++ rotate Display rotation {0,90,180,270}
++
++ fps Delay between frame updates
++
++ debug Debug output level {0-7}
++
++
+ Name: pitft28-capacitive
+ Info: Adafruit PiTFT 2.8" capacitive touch screen
+ Load: dtoverlay=pitft28-capacitive,<param>=<val>
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/pitft22-overlay.dts
+@@ -0,0 +1,69 @@
++/*
++ * Device Tree overlay for pitft by Adafruit
++ *
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++
++ fragment@0 {
++ target = <&spi0>;
++ __overlay__ {
++ status = "okay";
++
++ spidev@0{
++ status = "disabled";
++ };
++
++ spidev@1{
++ status = "disabled";
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ pitft_pins: pitft_pins {
++ brcm,pins = <25>;
++ brcm,function = <1>; /* out */
++ brcm,pull = <0>; /* none */
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&spi0>;
++ __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ pitft: pitft@0{
++ compatible = "ilitek,ili9340";
++ reg = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pitft_pins>;
++
++ spi-max-frequency = <32000000>;
++ rotate = <90>;
++ fps = <25>;
++ bgr;
++ buswidth = <8>;
++ dc-gpios = <&gpio 25 0>;
++ debug = <0>;
++ };
++
++ };
++ };
++
++ __overrides__ {
++ speed = <&pitft>,"spi-max-frequency:0";
++ rotate = <&pitft>,"rotate:0";
++ fps = <&pitft>,"fps:0";
++ debug = <&pitft>,"debug:0";
++ };
++};
diff --git a/target/linux/brcm2708/patches-4.4/0308-BCM270X_DT-Sound-DT-adjustments-for-Dynamic-DT.patch b/target/linux/brcm2708/patches-4.4/0308-BCM270X_DT-Sound-DT-adjustments-for-Dynamic-DT.patch
new file mode 100644
index 0000000000..d89bdcf412
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0308-BCM270X_DT-Sound-DT-adjustments-for-Dynamic-DT.patch
@@ -0,0 +1,578 @@
+From 7ad6d43eb9631ca8f4bb51f920b6fd2664d1b214 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Tue, 26 Apr 2016 10:44:59 +0100
+Subject: [PATCH 308/381] BCM270X_DT: Sound DT adjustments for Dynamic DT
+
+There are a number of issues when loading and unloading overlays for
+sound cards:
+1) The "sound" and "audio" nodes must be children of a bus node, such
+ as "/soc", otherwise the DT changes don't result in platform devices
+ being created and deleted.
+2) The "/sound" node must have a "disabled" status property, otherwise
+ setting the status to "okay" won't be detected.
+3) ALSA doesn't like having components unloaded under its feet, and it
+ is easy to deadlock or crash. Ordering the overlay fragments so that
+ the sound card appears last avoids this problem.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/bcm2708_common.dtsi | 23 +++++++++---------
+ .../dts/overlays/akkordion-iqdacplus-overlay.dts | 28 +++++++++++-----------
+ .../boot/dts/overlays/boomberry-dac-overlay.dts | 22 ++++++++---------
+ .../boot/dts/overlays/boomberry-digi-overlay.dts | 20 ++++++++--------
+ .../boot/dts/overlays/hifiberry-amp-overlay.dts | 20 ++++++++--------
+ .../boot/dts/overlays/hifiberry-dac-overlay.dts | 22 ++++++++---------
+ .../dts/overlays/hifiberry-dacplus-overlay.dts | 22 ++++++++---------
+ .../boot/dts/overlays/hifiberry-digi-overlay.dts | 20 ++++++++--------
+ arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts | 20 ++++++++--------
+ .../boot/dts/overlays/iqaudio-dacplus-overlay.dts | 22 ++++++++---------
+ arch/arm/boot/dts/overlays/raspidac3-overlay.dts | 20 ++++++++--------
+ arch/arm/boot/dts/overlays/rpi-dac-overlay.dts | 22 ++++++++---------
+ arch/arm/boot/dts/overlays/rpi-proto-overlay.dts | 20 ++++++++--------
+ 13 files changed, 141 insertions(+), 140 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2708_common.dtsi
++++ b/arch/arm/boot/dts/bcm2708_common.dtsi
+@@ -34,17 +34,6 @@
+ clocks = &clocks;
+ };
+
+- /* Onboard audio */
+- audio: audio {
+- compatible = "brcm,bcm2835-audio";
+- brcm,pwm-channels = <8>;
+- status = "disabled";
+- };
+-
+- /* External sound card */
+- sound: sound {
+- };
+-
+ soc: soc {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+@@ -313,6 +302,18 @@
+ compatible = "brcm,bcm2835-thermal";
+ firmware = <&firmware>;
+ };
++
++ /* Onboard audio */
++ audio: audio {
++ compatible = "brcm,bcm2835-audio";
++ brcm,pwm-channels = <8>;
++ status = "disabled";
++ };
++
++ /* External sound card */
++ sound: sound {
++ status = "disabled";
++ };
+ };
+
+ clocks: clocks {
+--- a/arch/arm/boot/dts/overlays/akkordion-iqdacplus-overlay.dts
++++ b/arch/arm/boot/dts/overlays/akkordion-iqdacplus-overlay.dts
+@@ -6,25 +6,13 @@
+ compatible = "brcm,bcm2708";
+
+ fragment@0 {
+- target = <&sound>;
+- frag0: __overlay__ {
+- compatible = "iqaudio,iqaudio-dac";
+- card_name = "Akkordion";
+- dai_name = "IQaudIO DAC";
+- dai_stream_name = "IQaudIO DAC HiFi";
+- i2s-controller = <&i2s>;
+- status = "okay";
+- };
+- };
+-
+- fragment@1 {
+ target = <&i2s>;
+ __overlay__ {
+ status = "okay";
+ };
+ };
+
+- fragment@2 {
++ fragment@1 {
+ target = <&i2c1>;
+ __overlay__ {
+ #address-cells = <1>;
+@@ -40,7 +28,19 @@
+ };
+ };
+
++ fragment@2 {
++ target = <&sound>;
++ frag2: __overlay__ {
++ compatible = "iqaudio,iqaudio-dac";
++ card_name = "Akkordion";
++ dai_name = "IQaudIO DAC";
++ dai_stream_name = "IQaudIO DAC HiFi";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
++
+ __overrides__ {
+- 24db_digital_gain = <&frag0>,"iqaudio,24db_digital_gain?";
++ 24db_digital_gain = <&frag2>,"iqaudio,24db_digital_gain?";
+ };
+ };
+--- a/arch/arm/boot/dts/overlays/boomberry-dac-overlay.dts
++++ b/arch/arm/boot/dts/overlays/boomberry-dac-overlay.dts
+@@ -6,22 +6,13 @@
+ compatible = "brcm,bcm2708";
+
+ fragment@0 {
+- target = <&sound>;
+- frag0: __overlay__ {
+- compatible = "boomberry,boomberry-dac";
+- i2s-controller = <&i2s>;
+- status = "okay";
+- };
+- };
+-
+- fragment@1 {
+ target = <&i2s>;
+ __overlay__ {
+ status = "okay";
+ };
+ };
+
+- fragment@2 {
++ fragment@1 {
+ target = <&i2c1>;
+ __overlay__ {
+ #address-cells = <1>;
+@@ -37,7 +28,16 @@
+ };
+ };
+
++ fragment@2 {
++ target = <&sound>;
++ frag2: __overlay__ {
++ compatible = "boomberry,boomberry-dac";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
++
+ __overrides__ {
+- 24db_digital_gain = <&frag0>,"boomberry,24db_digital_gain?";
++ 24db_digital_gain = <&frag2>,"boomberry,24db_digital_gain?";
+ };
+ };
+--- a/arch/arm/boot/dts/overlays/boomberry-digi-overlay.dts
++++ b/arch/arm/boot/dts/overlays/boomberry-digi-overlay.dts
+@@ -6,22 +6,13 @@
+ compatible = "brcm,bcm2708";
+
+ fragment@0 {
+- target = <&sound>;
+- __overlay__ {
+- compatible = "boomberry,boomberry-digi";
+- i2s-controller = <&i2s>;
+- status = "okay";
+- };
+- };
+-
+- fragment@1 {
+ target = <&i2s>;
+ __overlay__ {
+ status = "okay";
+ };
+ };
+
+- fragment@2 {
++ fragment@1 {
+ target = <&i2c1>;
+ __overlay__ {
+ #address-cells = <1>;
+@@ -36,4 +27,13 @@
+ };
+ };
+ };
++
++ fragment@2 {
++ target = <&sound>;
++ __overlay__ {
++ compatible = "boomberry,boomberry-digi";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
+ };
+--- a/arch/arm/boot/dts/overlays/hifiberry-amp-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hifiberry-amp-overlay.dts
+@@ -6,22 +6,13 @@
+ compatible = "brcm,bcm2708";
+
+ fragment@0 {
+- target = <&sound>;
+- __overlay__ {
+- compatible = "hifiberry,hifiberry-amp";
+- i2s-controller = <&i2s>;
+- status = "okay";
+- };
+- };
+-
+- fragment@1 {
+ target = <&i2s>;
+ __overlay__ {
+ status = "okay";
+ };
+ };
+
+- fragment@2 {
++ fragment@1 {
+ target = <&i2c1>;
+ __overlay__ {
+ #address-cells = <1>;
+@@ -36,4 +27,13 @@
+ };
+ };
+ };
++
++ fragment@2 {
++ target = <&sound>;
++ __overlay__ {
++ compatible = "hifiberry,hifiberry-amp";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
+ };
+--- a/arch/arm/boot/dts/overlays/hifiberry-dac-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hifiberry-dac-overlay.dts
+@@ -6,23 +6,14 @@
+ compatible = "brcm,bcm2708";
+
+ fragment@0 {
+- target = <&sound>;
+- __overlay__ {
+- compatible = "hifiberry,hifiberry-dac";
+- i2s-controller = <&i2s>;
+- status = "okay";
+- };
+- };
+-
+- fragment@1 {
+ target = <&i2s>;
+ __overlay__ {
+ status = "okay";
+ };
+ };
+
+- fragment@2 {
+- target-path = "/";
++ fragment@1 {
++ target = <&soc>;
+ __overlay__ {
+ pcm5102a-codec {
+ #sound-dai-cells = <0>;
+@@ -31,4 +22,13 @@
+ };
+ };
+ };
++
++ fragment@2 {
++ target = <&sound>;
++ __overlay__ {
++ compatible = "hifiberry,hifiberry-dac";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
+ };
+--- a/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
+@@ -16,22 +16,13 @@
+ };
+
+ fragment@1 {
+- target = <&sound>;
+- frag1: __overlay__ {
+- compatible = "hifiberry,hifiberry-dacplus";
+- i2s-controller = <&i2s>;
+- status = "okay";
+- };
+- };
+-
+- fragment@2 {
+ target = <&i2s>;
+ __overlay__ {
+ status = "okay";
+ };
+ };
+
+- fragment@3 {
++ fragment@2 {
+ target = <&i2c1>;
+ __overlay__ {
+ #address-cells = <1>;
+@@ -48,7 +39,16 @@
+ };
+ };
+
++ fragment@3 {
++ target = <&sound>;
++ frag3: __overlay__ {
++ compatible = "hifiberry,hifiberry-dacplus";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
++
+ __overrides__ {
+- 24db_digital_gain = <&frag1>,"hifiberry,24db_digital_gain?";
++ 24db_digital_gain = <&frag3>,"hifiberry,24db_digital_gain?";
+ };
+ };
+--- a/arch/arm/boot/dts/overlays/hifiberry-digi-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hifiberry-digi-overlay.dts
+@@ -6,22 +6,13 @@
+ compatible = "brcm,bcm2708";
+
+ fragment@0 {
+- target = <&sound>;
+- __overlay__ {
+- compatible = "hifiberry,hifiberry-digi";
+- i2s-controller = <&i2s>;
+- status = "okay";
+- };
+- };
+-
+- fragment@1 {
+ target = <&i2s>;
+ __overlay__ {
+ status = "okay";
+ };
+ };
+
+- fragment@2 {
++ fragment@1 {
+ target = <&i2c1>;
+ __overlay__ {
+ #address-cells = <1>;
+@@ -36,4 +27,13 @@
+ };
+ };
+ };
++
++ fragment@2 {
++ target = <&sound>;
++ __overlay__ {
++ compatible = "hifiberry,hifiberry-digi";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
+ };
+--- a/arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts
++++ b/arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts
+@@ -6,22 +6,13 @@
+ compatible = "brcm,bcm2708";
+
+ fragment@0 {
+- target = <&sound>;
+- __overlay__ {
+- compatible = "iqaudio,iqaudio-dac";
+- i2s-controller = <&i2s>;
+- status = "okay";
+- };
+- };
+-
+- fragment@1 {
+ target = <&i2s>;
+ __overlay__ {
+ status = "okay";
+ };
+ };
+
+- fragment@2 {
++ fragment@1 {
+ target = <&i2c1>;
+ __overlay__ {
+ #address-cells = <1>;
+@@ -36,4 +27,13 @@
+ };
+ };
+ };
++
++ fragment@2 {
++ target = <&sound>;
++ __overlay__ {
++ compatible = "iqaudio,iqaudio-dac";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
+ };
+--- a/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts
++++ b/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts
+@@ -6,22 +6,13 @@
+ compatible = "brcm,bcm2708";
+
+ fragment@0 {
+- target = <&sound>;
+- frag0: __overlay__ {
+- compatible = "iqaudio,iqaudio-dac";
+- i2s-controller = <&i2s>;
+- status = "okay";
+- };
+- };
+-
+- fragment@1 {
+ target = <&i2s>;
+ __overlay__ {
+ status = "okay";
+ };
+ };
+
+- fragment@2 {
++ fragment@1 {
+ target = <&i2c1>;
+ __overlay__ {
+ #address-cells = <1>;
+@@ -37,7 +28,16 @@
+ };
+ };
+
++ fragment@2 {
++ target = <&sound>;
++ frag2: __overlay__ {
++ compatible = "iqaudio,iqaudio-dac";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
++
+ __overrides__ {
+- 24db_digital_gain = <&frag0>,"iqaudio,24db_digital_gain?";
++ 24db_digital_gain = <&frag2>,"iqaudio,24db_digital_gain?";
+ };
+ };
+--- a/arch/arm/boot/dts/overlays/raspidac3-overlay.dts
++++ b/arch/arm/boot/dts/overlays/raspidac3-overlay.dts
+@@ -6,22 +6,13 @@
+ compatible = "brcm,bcm2708";
+
+ fragment@0 {
+- target = <&sound>;
+- __overlay__ {
+- compatible = "jg,raspidacv3";
+- i2s-controller = <&i2s>;
+- status = "okay";
+- };
+- };
+-
+- fragment@1 {
+ target = <&i2s>;
+ __overlay__ {
+ status = "okay";
+ };
+ };
+
+- fragment@2 {
++ fragment@1 {
+ target = <&i2c1>;
+ __overlay__ {
+ #address-cells = <1>;
+@@ -42,4 +33,13 @@
+ };
+ };
+ };
++
++ fragment@2 {
++ target = <&sound>;
++ __overlay__ {
++ compatible = "jg,raspidacv3";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
+ };
+--- a/arch/arm/boot/dts/overlays/rpi-dac-overlay.dts
++++ b/arch/arm/boot/dts/overlays/rpi-dac-overlay.dts
+@@ -6,23 +6,14 @@
+ compatible = "brcm,bcm2708";
+
+ fragment@0 {
+- target = <&sound>;
+- __overlay__ {
+- compatible = "rpi,rpi-dac";
+- i2s-controller = <&i2s>;
+- status = "okay";
+- };
+- };
+-
+- fragment@1 {
+ target = <&i2s>;
+ __overlay__ {
+ status = "okay";
+ };
+ };
+
+- fragment@2 {
+- target-path = "/";
++ fragment@1 {
++ target = <&soc>;
+ __overlay__ {
+ pcm1794a-codec {
+ #sound-dai-cells = <0>;
+@@ -31,4 +22,13 @@
+ };
+ };
+ };
++
++ fragment@2 {
++ target = <&sound>;
++ __overlay__ {
++ compatible = "rpi,rpi-dac";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
+ };
+--- a/arch/arm/boot/dts/overlays/rpi-proto-overlay.dts
++++ b/arch/arm/boot/dts/overlays/rpi-proto-overlay.dts
+@@ -6,22 +6,13 @@
+ compatible = "brcm,bcm2708";
+
+ fragment@0 {
+- target = <&sound>;
+- __overlay__ {
+- compatible = "rpi,rpi-proto";
+- i2s-controller = <&i2s>;
+- status = "okay";
+- };
+- };
+-
+- fragment@1 {
+ target = <&i2s>;
+ __overlay__ {
+ status = "okay";
+ };
+ };
+
+- fragment@2 {
++ fragment@1 {
+ target = <&i2c1>;
+ __overlay__ {
+ #address-cells = <1>;
+@@ -36,4 +27,13 @@
+ };
+ };
+ };
++
++ fragment@2 {
++ target = <&sound>;
++ __overlay__ {
++ compatible = "rpi,rpi-proto";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
+ };
diff --git a/target/linux/brcm2708/patches-4.4/0309-BCM270X_DT-Fix-codec-use-in-hifiberry-dac-overlay.patch b/target/linux/brcm2708/patches-4.4/0309-BCM270X_DT-Fix-codec-use-in-hifiberry-dac-overlay.patch
new file mode 100644
index 0000000000..7e81211fc8
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0309-BCM270X_DT-Fix-codec-use-in-hifiberry-dac-overlay.patch
@@ -0,0 +1,21 @@
+From b2be61827d995cd83f5453f3be0967e954095906 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Wed, 27 Apr 2016 12:01:41 +0100
+Subject: [PATCH 309/381] BCM270X_DT: Fix codec use in hifiberry-dac overlay
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/overlays/hifiberry-dac-overlay.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/hifiberry-dac-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hifiberry-dac-overlay.dts
+@@ -13,7 +13,7 @@
+ };
+
+ fragment@1 {
+- target = <&soc>;
++ target-path = "/";
+ __overlay__ {
+ pcm5102a-codec {
+ #sound-dai-cells = <0>;
diff --git a/target/linux/brcm2708/patches-4.4/0312-Revert-bcm2835-log-which-channel-map-is-set.patch b/target/linux/brcm2708/patches-4.4/0312-Revert-bcm2835-log-which-channel-map-is-set.patch
new file mode 100644
index 0000000000..ca37addd1a
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0312-Revert-bcm2835-log-which-channel-map-is-set.patch
@@ -0,0 +1,33 @@
+From 6b600a159a7204835e8f86d1fe7554c4fd2e088f Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Fri, 29 Apr 2016 17:27:33 +0100
+Subject: [PATCH 312/381] Revert "bcm2835: log which channel map is set"
+
+This reverts commit cd560b8658868d9652ab31754e02f86daf6831ba.
+---
+ sound/arm/bcm2835-vchiq.c | 5 -----
+ 1 file changed, 5 deletions(-)
+
+--- a/sound/arm/bcm2835-vchiq.c
++++ b/sound/arm/bcm2835-vchiq.c
+@@ -596,11 +596,8 @@ int bcm2835_audio_set_params(bcm2835_als
+ instance->result = -1;
+
+ if (alsa_stream->chip->cea_chmap >= 0) {
+- LOG_INFO("Using application requested channel map: %d\n",
+- alsa_stream->chip->cea_chmap);
+ chmap_value = (unsigned)alsa_stream->chip->cea_chmap << 24;
+ } else {
+- LOG_INFO("Using fallback channel map.\n");
+ /* fallback layouts for applications which do not use chmap API */
+ chmap_value = 0x00;
+ switch (channels) {
+@@ -617,8 +614,6 @@ int bcm2835_audio_set_params(bcm2835_als
+ for (i = 0; i < 8; i++)
+ chmap_value |= alsa_stream->chip->map_channels[i] << (i * 3);
+
+- LOG_INFO("Requesting AUDS channel map: 0x%lx\n", (long)chmap_value);
+-
+ m.type = VC_AUDIO_MSG_TYPE_CONFIG;
+ m.u.config.channels = channels;
+ m.u.config.samplerate = samplerate;
diff --git a/target/linux/brcm2708/patches-4.4/0313-Revert-bcm2835-add-fallback-channel-layouts-if-chann.patch b/target/linux/brcm2708/patches-4.4/0313-Revert-bcm2835-add-fallback-channel-layouts-if-chann.patch
new file mode 100644
index 0000000000..426b6b19a8
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0313-Revert-bcm2835-add-fallback-channel-layouts-if-chann.patch
@@ -0,0 +1,31 @@
+From 24d1da89c980e9561a823c065ef37ca25e13a48c Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Fri, 29 Apr 2016 17:27:35 +0100
+Subject: [PATCH 313/381] Revert "bcm2835: add fallback channel layouts if
+ channel map API is not used"
+
+This reverts commit ceacfff9f86f89826dbc8a6df667f485894327d1.
+---
+ sound/arm/bcm2835-vchiq.c | 11 +----------
+ 1 file changed, 1 insertion(+), 10 deletions(-)
+
+--- a/sound/arm/bcm2835-vchiq.c
++++ b/sound/arm/bcm2835-vchiq.c
+@@ -598,16 +598,7 @@ int bcm2835_audio_set_params(bcm2835_als
+ if (alsa_stream->chip->cea_chmap >= 0) {
+ chmap_value = (unsigned)alsa_stream->chip->cea_chmap << 24;
+ } else {
+- /* fallback layouts for applications which do not use chmap API */
+- chmap_value = 0x00;
+- switch (channels) {
+- case 3: chmap_value = 0x01; break;
+- case 4: chmap_value = 0x03; break;
+- case 5: chmap_value = 0x07; break;
+- case 6: chmap_value = 0x0b; break;
+- case 7: chmap_value = 0x0f; break;
+- case 8: chmap_value = 0x13; break;
+- }
++ chmap_value = 0; /* force stereo */
+ for (i = 0; i < 8; i++)
+ alsa_stream->chip->map_channels[i] = i;
+ }
diff --git a/target/linux/brcm2708/patches-4.4/0314-Revert-bcm2835-do-not-require-substream-for-accessin.patch b/target/linux/brcm2708/patches-4.4/0314-Revert-bcm2835-do-not-require-substream-for-accessin.patch
new file mode 100644
index 0000000000..e20f991da0
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0314-Revert-bcm2835-do-not-require-substream-for-accessin.patch
@@ -0,0 +1,51 @@
+From a557a6f30f553f24626a409333cb281405ef4086 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Fri, 29 Apr 2016 17:27:36 +0100
+Subject: [PATCH 314/381] Revert "bcm2835: do not require substream for
+ accessing chmap ctl"
+
+This reverts commit a05b4815196018c329ea98c24205bc6fa9c097e0.
+---
+ sound/arm/bcm2835-ctl.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+--- a/sound/arm/bcm2835-ctl.c
++++ b/sound/arm/bcm2835-ctl.c
+@@ -489,6 +489,8 @@ static int snd_bcm2835_chmap_ctl_get(str
+ {
+ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+ bcm2835_chip_t *chip = info->private_data;
++ unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
++ struct snd_pcm_substream *substream = snd_pcm_chmap_substream(info, idx);
+ struct cea_channel_speaker_allocation *ch = NULL;
+ int res = 0;
+ int cur = 0;
+@@ -497,6 +499,11 @@ static int snd_bcm2835_chmap_ctl_get(str
+ if (mutex_lock_interruptible(&chip->audio_mutex))
+ return -EINTR;
+
++ if (!substream || !substream->runtime) {
++ res = -ENODEV;
++ goto unlock;
++ }
++
+ for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
+ if (channel_allocations[i].ca_index == chip->cea_chmap)
+ ch = &channel_allocations[i];
+@@ -514,6 +521,7 @@ static int snd_bcm2835_chmap_ctl_get(str
+ while (cur < 8)
+ ucontrol->value.integer.value[cur++] = SNDRV_CHMAP_NA;
+
++unlock:
+ mutex_unlock(&chip->audio_mutex);
+ return res;
+ }
+@@ -533,7 +541,7 @@ static int snd_bcm2835_chmap_ctl_put(str
+ return -EINTR;
+
+ if (!substream || !substream->runtime) {
+- /* ignore and return success for the sake of alsactl */
++ res = -ENODEV;
+ goto unlock;
+ }
+
diff --git a/target/linux/brcm2708/patches-4.4/0315-Revert-bcm2835-interpolate-audio-delay.patch b/target/linux/brcm2708/patches-4.4/0315-Revert-bcm2835-interpolate-audio-delay.patch
new file mode 100644
index 0000000000..4ab8274f82
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0315-Revert-bcm2835-interpolate-audio-delay.patch
@@ -0,0 +1,70 @@
+From 336129ed3ae12518df30c332a500ffe1739af4df Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Fri, 29 Apr 2016 17:27:37 +0100
+Subject: [PATCH 315/381] Revert "bcm2835: interpolate audio delay"
+
+This reverts commit 83eca613d0eddd2c8299f114b8fe573ccaffdefc.
+---
+ sound/arm/bcm2835-pcm.c | 12 +-----------
+ sound/arm/bcm2835.h | 1 -
+ 2 files changed, 1 insertion(+), 12 deletions(-)
+
+--- a/sound/arm/bcm2835-pcm.c
++++ b/sound/arm/bcm2835-pcm.c
+@@ -25,7 +25,7 @@
+ /* hardware definition */
+ static struct snd_pcm_hardware snd_bcm2835_playback_hw = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+- SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BATCH),
++ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
+ .rate_min = 8000,
+@@ -99,8 +99,6 @@ static irqreturn_t bcm2835_playback_fifo
+ alsa_stream->pos %= alsa_stream->buffer_size;
+ }
+
+- alsa_stream->interpolate_start = ktime_get_ns();
+-
+ if (alsa_stream->substream) {
+ if (new_period)
+ snd_pcm_period_elapsed(alsa_stream->substream);
+@@ -401,7 +399,6 @@ static int snd_bcm2835_pcm_prepare(struc
+ alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
+ alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
+ alsa_stream->pos = 0;
+- alsa_stream->interpolate_start = ktime_get_ns();
+
+ audio_debug("buffer_size=%d, period_size=%d pos=%d frame_bits=%d\n",
+ alsa_stream->buffer_size, alsa_stream->period_size,
+@@ -498,7 +495,6 @@ snd_bcm2835_pcm_pointer(struct snd_pcm_s
+ {
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
+- u64 now = ktime_get_ns();
+
+ audio_info(" .. IN\n");
+
+@@ -507,12 +503,6 @@ snd_bcm2835_pcm_pointer(struct snd_pcm_s
+ frames_to_bytes(runtime, runtime->control->appl_ptr),
+ alsa_stream->pos);
+
+- /* Give userspace better delay reporting by interpolating between GPU
+- * notifications, assuming audio speed is close enough to the clock
+- * used for ktime */
+- if (alsa_stream->interpolate_start && alsa_stream->interpolate_start < now)
+- runtime->delay = -(int)div_u64((now - alsa_stream->interpolate_start) * runtime->rate, 1000000000);
+-
+ audio_info(" .. OUT\n");
+ return snd_pcm_indirect_playback_pointer(substream,
+ &alsa_stream->pcm_indirect,
+--- a/sound/arm/bcm2835.h
++++ b/sound/arm/bcm2835.h
+@@ -137,7 +137,6 @@ typedef struct bcm2835_alsa_stream {
+ unsigned int pos;
+ unsigned int buffer_size;
+ unsigned int period_size;
+- u64 interpolate_start;
+
+ uint32_t enable_fifo_irq;
+ irq_handler_t fifo_irq_handler;
diff --git a/target/linux/brcm2708/patches-4.4/0316-Revert-bcm2835-only-allow-stereo-if-analogue-jack-is.patch b/target/linux/brcm2708/patches-4.4/0316-Revert-bcm2835-only-allow-stereo-if-analogue-jack-is.patch
new file mode 100644
index 0000000000..c1adf0794f
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0316-Revert-bcm2835-only-allow-stereo-if-analogue-jack-is.patch
@@ -0,0 +1,49 @@
+From 9d56f11061a9d2598dd0c7a20886e3d5f76fa7a0 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Fri, 29 Apr 2016 17:28:06 +0100
+Subject: [PATCH 316/381] Revert "bcm2835: only allow stereo if analogue jack
+ is selected"
+
+This reverts commit 5f7049894f47b3836838cd68e29ee883179c80b3.
+---
+ sound/arm/bcm2835-ctl.c | 12 ------------
+ 1 file changed, 12 deletions(-)
+
+--- a/sound/arm/bcm2835-ctl.c
++++ b/sound/arm/bcm2835-ctl.c
+@@ -423,16 +423,9 @@ static struct cea_channel_speaker_alloca
+ { .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } },
+ };
+
+-static int uses_analogue(bcm2835_chip_t *chip)
+-{
+- return chip->dest == 1;
+-}
+-
+ static int snd_bcm2835_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag,
+ unsigned int size, unsigned int __user *tlv)
+ {
+- struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+- bcm2835_chip_t *chip = info->private_data;
+ unsigned int __user *dst;
+ int count = 0;
+ int i;
+@@ -449,9 +442,6 @@ static int snd_bcm2835_chmap_ctl_tlv(str
+ int chs_bytes;
+ int c;
+
+- if (i > 0 && uses_analogue(chip))
+- break;
+-
+ for (c = 0; c < 8; c++) {
+ if (ch->speakers[c])
+ num_chs++;
+@@ -562,8 +552,6 @@ static int snd_bcm2835_chmap_ctl_put(str
+ int matches = 1;
+ int cur = 0;
+ int x;
+- if (i > 0 && uses_analogue(chip))
+- break;
+ memset(remap, 0, sizeof(remap));
+ for (x = 0; x < substream->runtime->channels; x++) {
+ int sp = ucontrol->value.integer.value[x];
diff --git a/target/linux/brcm2708/patches-4.4/0317-Revert-bcm2835-always-use-2-4-8-channels-for-multich.patch b/target/linux/brcm2708/patches-4.4/0317-Revert-bcm2835-always-use-2-4-8-channels-for-multich.patch
new file mode 100644
index 0000000000..bdd706eaf1
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0317-Revert-bcm2835-always-use-2-4-8-channels-for-multich.patch
@@ -0,0 +1,135 @@
+From 6a35e00dde80fc9c6007d8cec6a1113aafdabd1c Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Fri, 29 Apr 2016 17:28:08 +0100
+Subject: [PATCH 317/381] Revert "bcm2835: always use 2/4/8 channels for
+ multichannel layouts"
+
+This reverts commit 06931f74092d86087144f070b06a4444df8b444b.
+---
+ sound/arm/bcm2835-ctl.c | 89 ++++++++++++++++++++++++-------------------------
+ 1 file changed, 44 insertions(+), 45 deletions(-)
+
+--- a/sound/arm/bcm2835-ctl.c
++++ b/sound/arm/bcm2835-ctl.c
+@@ -349,7 +349,6 @@ struct cea_channel_speaker_allocation {
+ #define FRW SNDRV_CHMAP_FRW
+ #define TC SNDRV_CHMAP_TC
+ #define FCH SNDRV_CHMAP_TFC
+-#define NA SNDRV_CHMAP_NA
+
+ /*
+ * CEA-861 channel maps
+@@ -357,69 +356,69 @@ struct cea_channel_speaker_allocation {
+ * Stolen from sound/pci/hda/patch_hdmi.c
+ * (unlike the source, this uses SNDRV_* constants directly, as by the
+ * map_tables array in patch_hdmi.c)
+- * Entries which do not have a physical output channel use 0. Entries which
+- * require userspace to output silence use NA (SNDRV_CHMAP_NA).
++ * Unknown entries use 0, which unfortunately is SNDRV_CHMAP_UNKNOWN instead
++ * of SNDRV_CHMAP_NA.
+ */
+ static struct cea_channel_speaker_allocation channel_allocations[] = {
+ /* channel: 7 6 5 4 3 2 1 0 */
+ { .ca_index = 0x00, .speakers = { 0, 0, 0, 0, 0, 0, FR, FL } },
+ /* 2.1 */
+-{ .ca_index = 0x01, .speakers = { 0, 0, 0, 0, NA, LFE, FR, FL } },
++{ .ca_index = 0x01, .speakers = { 0, 0, 0, 0, 0, LFE, FR, FL } },
+ /* Dolby Surround */
+-{ .ca_index = 0x02, .speakers = { 0, 0, 0, 0, FC, NA, FR, FL } },
++{ .ca_index = 0x02, .speakers = { 0, 0, 0, 0, FC, 0, FR, FL } },
+ /* surround40 */
+-{ .ca_index = 0x08, .speakers = { NA, NA, RR, RL, NA, NA, FR, FL } },
++{ .ca_index = 0x08, .speakers = { 0, 0, RR, RL, 0, 0, FR, FL } },
+ /* surround41 */
+-{ .ca_index = 0x09, .speakers = { NA, NA, RR, RL, NA, LFE, FR, FL } },
++{ .ca_index = 0x09, .speakers = { 0, 0, RR, RL, 0, LFE, FR, FL } },
+ /* surround50 */
+-{ .ca_index = 0x0a, .speakers = { NA, NA, RR, RL, FC, NA, FR, FL } },
++{ .ca_index = 0x0a, .speakers = { 0, 0, RR, RL, FC, 0, FR, FL } },
+ /* surround51 */
+-{ .ca_index = 0x0b, .speakers = { NA, NA, RR, RL, FC, LFE, FR, FL } },
++{ .ca_index = 0x0b, .speakers = { 0, 0, RR, RL, FC, LFE, FR, FL } },
+ /* 6.1 */
+-{ .ca_index = 0x0f, .speakers = { NA, RC, RR, RL, FC, LFE, FR, FL } },
++{ .ca_index = 0x0f, .speakers = { 0, RC, RR, RL, FC, LFE, FR, FL } },
+ /* surround71 */
+ { .ca_index = 0x13, .speakers = { RRC, RLC, RR, RL, FC, LFE, FR, FL } },
+
+-{ .ca_index = 0x03, .speakers = { NA, NA, NA, NA, FC, LFE, FR, FL } },
+-{ .ca_index = 0x04, .speakers = { NA, NA, NA, RC, NA, NA, FR, FL } },
+-{ .ca_index = 0x05, .speakers = { NA, NA, NA, RC, NA, LFE, FR, FL } },
+-{ .ca_index = 0x06, .speakers = { NA, NA, NA, RC, FC, NA, FR, FL } },
+-{ .ca_index = 0x07, .speakers = { NA, NA, NA, RC, FC, LFE, FR, FL } },
+-{ .ca_index = 0x0c, .speakers = { NA, RC, RR, RL, NA, NA, FR, FL } },
+-{ .ca_index = 0x0d, .speakers = { NA, RC, RR, RL, NA, LFE, FR, FL } },
+-{ .ca_index = 0x0e, .speakers = { NA, RC, RR, RL, FC, NA, FR, FL } },
+-{ .ca_index = 0x10, .speakers = { RRC, RLC, RR, RL, NA, NA, FR, FL } },
+-{ .ca_index = 0x11, .speakers = { RRC, RLC, RR, RL, NA, LFE, FR, FL } },
+-{ .ca_index = 0x12, .speakers = { RRC, RLC, RR, RL, FC, NA, FR, FL } },
+-{ .ca_index = 0x14, .speakers = { FRC, FLC, NA, NA, NA, NA, FR, FL } },
+-{ .ca_index = 0x15, .speakers = { FRC, FLC, NA, NA, NA, LFE, FR, FL } },
+-{ .ca_index = 0x16, .speakers = { FRC, FLC, NA, NA, FC, NA, FR, FL } },
+-{ .ca_index = 0x17, .speakers = { FRC, FLC, NA, NA, FC, LFE, FR, FL } },
+-{ .ca_index = 0x18, .speakers = { FRC, FLC, NA, RC, NA, NA, FR, FL } },
+-{ .ca_index = 0x19, .speakers = { FRC, FLC, NA, RC, NA, LFE, FR, FL } },
+-{ .ca_index = 0x1a, .speakers = { FRC, FLC, NA, RC, FC, NA, FR, FL } },
+-{ .ca_index = 0x1b, .speakers = { FRC, FLC, NA, RC, FC, LFE, FR, FL } },
+-{ .ca_index = 0x1c, .speakers = { FRC, FLC, RR, RL, NA, NA, FR, FL } },
+-{ .ca_index = 0x1d, .speakers = { FRC, FLC, RR, RL, NA, LFE, FR, FL } },
+-{ .ca_index = 0x1e, .speakers = { FRC, FLC, RR, RL, FC, NA, FR, FL } },
++{ .ca_index = 0x03, .speakers = { 0, 0, 0, 0, FC, LFE, FR, FL } },
++{ .ca_index = 0x04, .speakers = { 0, 0, 0, RC, 0, 0, FR, FL } },
++{ .ca_index = 0x05, .speakers = { 0, 0, 0, RC, 0, LFE, FR, FL } },
++{ .ca_index = 0x06, .speakers = { 0, 0, 0, RC, FC, 0, FR, FL } },
++{ .ca_index = 0x07, .speakers = { 0, 0, 0, RC, FC, LFE, FR, FL } },
++{ .ca_index = 0x0c, .speakers = { 0, RC, RR, RL, 0, 0, FR, FL } },
++{ .ca_index = 0x0d, .speakers = { 0, RC, RR, RL, 0, LFE, FR, FL } },
++{ .ca_index = 0x0e, .speakers = { 0, RC, RR, RL, FC, 0, FR, FL } },
++{ .ca_index = 0x10, .speakers = { RRC, RLC, RR, RL, 0, 0, FR, FL } },
++{ .ca_index = 0x11, .speakers = { RRC, RLC, RR, RL, 0, LFE, FR, FL } },
++{ .ca_index = 0x12, .speakers = { RRC, RLC, RR, RL, FC, 0, FR, FL } },
++{ .ca_index = 0x14, .speakers = { FRC, FLC, 0, 0, 0, 0, FR, FL } },
++{ .ca_index = 0x15, .speakers = { FRC, FLC, 0, 0, 0, LFE, FR, FL } },
++{ .ca_index = 0x16, .speakers = { FRC, FLC, 0, 0, FC, 0, FR, FL } },
++{ .ca_index = 0x17, .speakers = { FRC, FLC, 0, 0, FC, LFE, FR, FL } },
++{ .ca_index = 0x18, .speakers = { FRC, FLC, 0, RC, 0, 0, FR, FL } },
++{ .ca_index = 0x19, .speakers = { FRC, FLC, 0, RC, 0, LFE, FR, FL } },
++{ .ca_index = 0x1a, .speakers = { FRC, FLC, 0, RC, FC, 0, FR, FL } },
++{ .ca_index = 0x1b, .speakers = { FRC, FLC, 0, RC, FC, LFE, FR, FL } },
++{ .ca_index = 0x1c, .speakers = { FRC, FLC, RR, RL, 0, 0, FR, FL } },
++{ .ca_index = 0x1d, .speakers = { FRC, FLC, RR, RL, 0, LFE, FR, FL } },
++{ .ca_index = 0x1e, .speakers = { FRC, FLC, RR, RL, FC, 0, FR, FL } },
+ { .ca_index = 0x1f, .speakers = { FRC, FLC, RR, RL, FC, LFE, FR, FL } },
+-{ .ca_index = 0x20, .speakers = { NA, FCH, RR, RL, FC, NA, FR, FL } },
+-{ .ca_index = 0x21, .speakers = { NA, FCH, RR, RL, FC, LFE, FR, FL } },
+-{ .ca_index = 0x22, .speakers = { TC, NA, RR, RL, FC, NA, FR, FL } },
+-{ .ca_index = 0x23, .speakers = { TC, NA, RR, RL, FC, LFE, FR, FL } },
+-{ .ca_index = 0x24, .speakers = { FRH, FLH, RR, RL, NA, NA, FR, FL } },
+-{ .ca_index = 0x25, .speakers = { FRH, FLH, RR, RL, NA, LFE, FR, FL } },
+-{ .ca_index = 0x26, .speakers = { FRW, FLW, RR, RL, NA, NA, FR, FL } },
+-{ .ca_index = 0x27, .speakers = { FRW, FLW, RR, RL, NA, LFE, FR, FL } },
+-{ .ca_index = 0x28, .speakers = { TC, RC, RR, RL, FC, NA, FR, FL } },
++{ .ca_index = 0x20, .speakers = { 0, FCH, RR, RL, FC, 0, FR, FL } },
++{ .ca_index = 0x21, .speakers = { 0, FCH, RR, RL, FC, LFE, FR, FL } },
++{ .ca_index = 0x22, .speakers = { TC, 0, RR, RL, FC, 0, FR, FL } },
++{ .ca_index = 0x23, .speakers = { TC, 0, RR, RL, FC, LFE, FR, FL } },
++{ .ca_index = 0x24, .speakers = { FRH, FLH, RR, RL, 0, 0, FR, FL } },
++{ .ca_index = 0x25, .speakers = { FRH, FLH, RR, RL, 0, LFE, FR, FL } },
++{ .ca_index = 0x26, .speakers = { FRW, FLW, RR, RL, 0, 0, FR, FL } },
++{ .ca_index = 0x27, .speakers = { FRW, FLW, RR, RL, 0, LFE, FR, FL } },
++{ .ca_index = 0x28, .speakers = { TC, RC, RR, RL, FC, 0, FR, FL } },
+ { .ca_index = 0x29, .speakers = { TC, RC, RR, RL, FC, LFE, FR, FL } },
+-{ .ca_index = 0x2a, .speakers = { FCH, RC, RR, RL, FC, NA, FR, FL } },
++{ .ca_index = 0x2a, .speakers = { FCH, RC, RR, RL, FC, 0, FR, FL } },
+ { .ca_index = 0x2b, .speakers = { FCH, RC, RR, RL, FC, LFE, FR, FL } },
+-{ .ca_index = 0x2c, .speakers = { TC, FCH, RR, RL, FC, NA, FR, FL } },
++{ .ca_index = 0x2c, .speakers = { TC, FCH, RR, RL, FC, 0, FR, FL } },
+ { .ca_index = 0x2d, .speakers = { TC, FCH, RR, RL, FC, LFE, FR, FL } },
+-{ .ca_index = 0x2e, .speakers = { FRH, FLH, RR, RL, FC, NA, FR, FL } },
++{ .ca_index = 0x2e, .speakers = { FRH, FLH, RR, RL, FC, 0, FR, FL } },
+ { .ca_index = 0x2f, .speakers = { FRH, FLH, RR, RL, FC, LFE, FR, FL } },
+-{ .ca_index = 0x30, .speakers = { FRW, FLW, RR, RL, FC, NA, FR, FL } },
++{ .ca_index = 0x30, .speakers = { FRW, FLW, RR, RL, FC, 0, FR, FL } },
+ { .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } },
+ };
+
diff --git a/target/linux/brcm2708/patches-4.4/0318-Revert-bcm2835-implement-channel-map-API.patch b/target/linux/brcm2708/patches-4.4/0318-Revert-bcm2835-implement-channel-map-API.patch
new file mode 100644
index 0000000000..d59090c80a
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0318-Revert-bcm2835-implement-channel-map-API.patch
@@ -0,0 +1,496 @@
+From 54dc243ad6ea802967fd4efdb4f75facc19fa950 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Fri, 29 Apr 2016 17:29:03 +0100
+Subject: [PATCH 318/381] Revert "bcm2835: implement channel map API"
+
+This reverts commit 5efba3f8c180c39609a8d40033ef92046ef0de75.
+---
+ sound/arm/bcm2835-ctl.c | 299 ----------------------------------------------
+ sound/arm/bcm2835-pcm.c | 69 ++---------
+ sound/arm/bcm2835-vchiq.c | 13 --
+ sound/arm/bcm2835.h | 4 -
+ 4 files changed, 7 insertions(+), 378 deletions(-)
+
+--- a/sound/arm/bcm2835-ctl.c
++++ b/sound/arm/bcm2835-ctl.c
+@@ -327,304 +327,6 @@ static struct snd_kcontrol_new snd_bcm28
+ },
+ };
+
+-struct cea_channel_speaker_allocation {
+- int ca_index;
+- int speakers[8];
+-};
+-
+-#define FL SNDRV_CHMAP_FL
+-#define FR SNDRV_CHMAP_FR
+-#define RL SNDRV_CHMAP_RL
+-#define RR SNDRV_CHMAP_RR
+-#define LFE SNDRV_CHMAP_LFE
+-#define FC SNDRV_CHMAP_FC
+-#define RLC SNDRV_CHMAP_RLC
+-#define RRC SNDRV_CHMAP_RRC
+-#define RC SNDRV_CHMAP_RC
+-#define FLC SNDRV_CHMAP_FLC
+-#define FRC SNDRV_CHMAP_FRC
+-#define FLH SNDRV_CHMAP_TFL
+-#define FRH SNDRV_CHMAP_TFR
+-#define FLW SNDRV_CHMAP_FLW
+-#define FRW SNDRV_CHMAP_FRW
+-#define TC SNDRV_CHMAP_TC
+-#define FCH SNDRV_CHMAP_TFC
+-
+-/*
+- * CEA-861 channel maps
+- *
+- * Stolen from sound/pci/hda/patch_hdmi.c
+- * (unlike the source, this uses SNDRV_* constants directly, as by the
+- * map_tables array in patch_hdmi.c)
+- * Unknown entries use 0, which unfortunately is SNDRV_CHMAP_UNKNOWN instead
+- * of SNDRV_CHMAP_NA.
+- */
+-static struct cea_channel_speaker_allocation channel_allocations[] = {
+-/* channel: 7 6 5 4 3 2 1 0 */
+-{ .ca_index = 0x00, .speakers = { 0, 0, 0, 0, 0, 0, FR, FL } },
+- /* 2.1 */
+-{ .ca_index = 0x01, .speakers = { 0, 0, 0, 0, 0, LFE, FR, FL } },
+- /* Dolby Surround */
+-{ .ca_index = 0x02, .speakers = { 0, 0, 0, 0, FC, 0, FR, FL } },
+- /* surround40 */
+-{ .ca_index = 0x08, .speakers = { 0, 0, RR, RL, 0, 0, FR, FL } },
+- /* surround41 */
+-{ .ca_index = 0x09, .speakers = { 0, 0, RR, RL, 0, LFE, FR, FL } },
+- /* surround50 */
+-{ .ca_index = 0x0a, .speakers = { 0, 0, RR, RL, FC, 0, FR, FL } },
+- /* surround51 */
+-{ .ca_index = 0x0b, .speakers = { 0, 0, RR, RL, FC, LFE, FR, FL } },
+- /* 6.1 */
+-{ .ca_index = 0x0f, .speakers = { 0, RC, RR, RL, FC, LFE, FR, FL } },
+- /* surround71 */
+-{ .ca_index = 0x13, .speakers = { RRC, RLC, RR, RL, FC, LFE, FR, FL } },
+-
+-{ .ca_index = 0x03, .speakers = { 0, 0, 0, 0, FC, LFE, FR, FL } },
+-{ .ca_index = 0x04, .speakers = { 0, 0, 0, RC, 0, 0, FR, FL } },
+-{ .ca_index = 0x05, .speakers = { 0, 0, 0, RC, 0, LFE, FR, FL } },
+-{ .ca_index = 0x06, .speakers = { 0, 0, 0, RC, FC, 0, FR, FL } },
+-{ .ca_index = 0x07, .speakers = { 0, 0, 0, RC, FC, LFE, FR, FL } },
+-{ .ca_index = 0x0c, .speakers = { 0, RC, RR, RL, 0, 0, FR, FL } },
+-{ .ca_index = 0x0d, .speakers = { 0, RC, RR, RL, 0, LFE, FR, FL } },
+-{ .ca_index = 0x0e, .speakers = { 0, RC, RR, RL, FC, 0, FR, FL } },
+-{ .ca_index = 0x10, .speakers = { RRC, RLC, RR, RL, 0, 0, FR, FL } },
+-{ .ca_index = 0x11, .speakers = { RRC, RLC, RR, RL, 0, LFE, FR, FL } },
+-{ .ca_index = 0x12, .speakers = { RRC, RLC, RR, RL, FC, 0, FR, FL } },
+-{ .ca_index = 0x14, .speakers = { FRC, FLC, 0, 0, 0, 0, FR, FL } },
+-{ .ca_index = 0x15, .speakers = { FRC, FLC, 0, 0, 0, LFE, FR, FL } },
+-{ .ca_index = 0x16, .speakers = { FRC, FLC, 0, 0, FC, 0, FR, FL } },
+-{ .ca_index = 0x17, .speakers = { FRC, FLC, 0, 0, FC, LFE, FR, FL } },
+-{ .ca_index = 0x18, .speakers = { FRC, FLC, 0, RC, 0, 0, FR, FL } },
+-{ .ca_index = 0x19, .speakers = { FRC, FLC, 0, RC, 0, LFE, FR, FL } },
+-{ .ca_index = 0x1a, .speakers = { FRC, FLC, 0, RC, FC, 0, FR, FL } },
+-{ .ca_index = 0x1b, .speakers = { FRC, FLC, 0, RC, FC, LFE, FR, FL } },
+-{ .ca_index = 0x1c, .speakers = { FRC, FLC, RR, RL, 0, 0, FR, FL } },
+-{ .ca_index = 0x1d, .speakers = { FRC, FLC, RR, RL, 0, LFE, FR, FL } },
+-{ .ca_index = 0x1e, .speakers = { FRC, FLC, RR, RL, FC, 0, FR, FL } },
+-{ .ca_index = 0x1f, .speakers = { FRC, FLC, RR, RL, FC, LFE, FR, FL } },
+-{ .ca_index = 0x20, .speakers = { 0, FCH, RR, RL, FC, 0, FR, FL } },
+-{ .ca_index = 0x21, .speakers = { 0, FCH, RR, RL, FC, LFE, FR, FL } },
+-{ .ca_index = 0x22, .speakers = { TC, 0, RR, RL, FC, 0, FR, FL } },
+-{ .ca_index = 0x23, .speakers = { TC, 0, RR, RL, FC, LFE, FR, FL } },
+-{ .ca_index = 0x24, .speakers = { FRH, FLH, RR, RL, 0, 0, FR, FL } },
+-{ .ca_index = 0x25, .speakers = { FRH, FLH, RR, RL, 0, LFE, FR, FL } },
+-{ .ca_index = 0x26, .speakers = { FRW, FLW, RR, RL, 0, 0, FR, FL } },
+-{ .ca_index = 0x27, .speakers = { FRW, FLW, RR, RL, 0, LFE, FR, FL } },
+-{ .ca_index = 0x28, .speakers = { TC, RC, RR, RL, FC, 0, FR, FL } },
+-{ .ca_index = 0x29, .speakers = { TC, RC, RR, RL, FC, LFE, FR, FL } },
+-{ .ca_index = 0x2a, .speakers = { FCH, RC, RR, RL, FC, 0, FR, FL } },
+-{ .ca_index = 0x2b, .speakers = { FCH, RC, RR, RL, FC, LFE, FR, FL } },
+-{ .ca_index = 0x2c, .speakers = { TC, FCH, RR, RL, FC, 0, FR, FL } },
+-{ .ca_index = 0x2d, .speakers = { TC, FCH, RR, RL, FC, LFE, FR, FL } },
+-{ .ca_index = 0x2e, .speakers = { FRH, FLH, RR, RL, FC, 0, FR, FL } },
+-{ .ca_index = 0x2f, .speakers = { FRH, FLH, RR, RL, FC, LFE, FR, FL } },
+-{ .ca_index = 0x30, .speakers = { FRW, FLW, RR, RL, FC, 0, FR, FL } },
+-{ .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } },
+-};
+-
+-static int snd_bcm2835_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag,
+- unsigned int size, unsigned int __user *tlv)
+-{
+- unsigned int __user *dst;
+- int count = 0;
+- int i;
+-
+- if (size < 8)
+- return -ENOMEM;
+- if (put_user(SNDRV_CTL_TLVT_CONTAINER, tlv))
+- return -EFAULT;
+- size -= 8;
+- dst = tlv + 2;
+- for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
+- struct cea_channel_speaker_allocation *ch = &channel_allocations[i];
+- int num_chs = 0;
+- int chs_bytes;
+- int c;
+-
+- for (c = 0; c < 8; c++) {
+- if (ch->speakers[c])
+- num_chs++;
+- }
+-
+- chs_bytes = num_chs * 4;
+- if (size < 8)
+- return -ENOMEM;
+- if (put_user(SNDRV_CTL_TLVT_CHMAP_FIXED, dst) ||
+- put_user(chs_bytes, dst + 1))
+- return -EFAULT;
+- dst += 2;
+- size -= 8;
+- count += 8;
+- if (size < chs_bytes)
+- return -ENOMEM;
+- size -= chs_bytes;
+- count += chs_bytes;
+- for (c = 0; c < 8; c++) {
+- int sp = ch->speakers[7 - c];
+- if (sp) {
+- if (put_user(sp, dst))
+- return -EFAULT;
+- dst++;
+- }
+- }
+- }
+- if (put_user(count, tlv + 1))
+- return -EFAULT;
+- return 0;
+-}
+-
+-static int snd_bcm2835_chmap_ctl_get(struct snd_kcontrol *kcontrol,
+- struct snd_ctl_elem_value *ucontrol)
+-{
+- struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+- bcm2835_chip_t *chip = info->private_data;
+- unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+- struct snd_pcm_substream *substream = snd_pcm_chmap_substream(info, idx);
+- struct cea_channel_speaker_allocation *ch = NULL;
+- int res = 0;
+- int cur = 0;
+- int i;
+-
+- if (mutex_lock_interruptible(&chip->audio_mutex))
+- return -EINTR;
+-
+- if (!substream || !substream->runtime) {
+- res = -ENODEV;
+- goto unlock;
+- }
+-
+- for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
+- if (channel_allocations[i].ca_index == chip->cea_chmap)
+- ch = &channel_allocations[i];
+- }
+-
+- /* If no layout was set yet, return a dummy. Apparently the userspace
+- * API will be confused if we don't. */
+- if (!ch)
+- ch = &channel_allocations[0];
+-
+- for (i = 0; i < 8; i++) {
+- if (ch->speakers[7 - i])
+- ucontrol->value.integer.value[cur++] = ch->speakers[7 - i];
+- }
+- while (cur < 8)
+- ucontrol->value.integer.value[cur++] = SNDRV_CHMAP_NA;
+-
+-unlock:
+- mutex_unlock(&chip->audio_mutex);
+- return res;
+-}
+-
+-static int snd_bcm2835_chmap_ctl_put(struct snd_kcontrol *kcontrol,
+- struct snd_ctl_elem_value *ucontrol)
+-{
+- struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+- bcm2835_chip_t *chip = info->private_data;
+- unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+- struct snd_pcm_substream *substream = snd_pcm_chmap_substream(info, idx);
+- int i, prepared = 0, cea_chmap = -1;
+- int res = 0;
+- int remap[8];
+-
+- if (mutex_lock_interruptible(&chip->audio_mutex))
+- return -EINTR;
+-
+- if (!substream || !substream->runtime) {
+- res = -ENODEV;
+- goto unlock;
+- }
+-
+- switch (substream->runtime->status->state) {
+- case SNDRV_PCM_STATE_OPEN:
+- case SNDRV_PCM_STATE_SETUP:
+- break;
+- case SNDRV_PCM_STATE_PREPARED:
+- prepared = 1;
+- break;
+- default:
+- res = -EBUSY;
+- goto unlock;
+- }
+-
+- for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
+- struct cea_channel_speaker_allocation *ch = &channel_allocations[i];
+- int matches = 1;
+- int cur = 0;
+- int x;
+- memset(remap, 0, sizeof(remap));
+- for (x = 0; x < substream->runtime->channels; x++) {
+- int sp = ucontrol->value.integer.value[x];
+- while (cur < 8 && !ch->speakers[7 - cur])
+- cur++;
+- if (cur >= 8) {
+- /* user has more channels than ch */
+- matches = 0;
+- break;
+- }
+- if (ch->speakers[7 - cur] != sp) {
+- matches = 0;
+- break;
+- }
+- remap[x] = cur;
+- cur++;
+- }
+- for (x = cur; x < 8; x++) {
+- if (ch->speakers[7 - x]) {
+- /* ch has more channels than user */
+- matches = 0;
+- break;
+- }
+- }
+- if (matches) {
+- cea_chmap = ch->ca_index;
+- break;
+- }
+- }
+-
+- if (cea_chmap < 0) {
+- res = -EINVAL;
+- goto unlock;
+- }
+-
+- /* don't change the layout if another substream is active */
+- if (chip->opened != (1 << substream->number) && chip->cea_chmap != cea_chmap) {
+- res = -EBUSY; /* unsure whether this is a good error code */
+- goto unlock;
+- }
+-
+- chip->cea_chmap = cea_chmap;
+- for (i = 0; i < 8; i++)
+- chip->map_channels[i] = remap[i];
+- if (prepared)
+- snd_bcm2835_pcm_prepare_again(substream);
+-
+-unlock:
+- mutex_unlock(&chip->audio_mutex);
+- return res;
+-}
+-
+-static int snd_bcm2835_add_chmap_ctl(bcm2835_chip_t * chip)
+-{
+- struct snd_pcm_chmap *chmap;
+- struct snd_kcontrol *kctl;
+- int err, i;
+-
+- err = snd_pcm_add_chmap_ctls(chip->pcm,
+- SNDRV_PCM_STREAM_PLAYBACK,
+- NULL, 8, 0, &chmap);
+- if (err < 0)
+- return err;
+- /* override handlers */
+- chmap->private_data = chip;
+- kctl = chmap->kctl;
+- for (i = 0; i < kctl->count; i++)
+- kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
+- kctl->get = snd_bcm2835_chmap_ctl_get;
+- kctl->put = snd_bcm2835_chmap_ctl_put;
+- kctl->tlv.c = snd_bcm2835_chmap_ctl_tlv;
+- return 0;
+-}
+-
+ int snd_bcm2835_new_ctl(bcm2835_chip_t * chip)
+ {
+ int err;
+@@ -638,7 +340,6 @@ int snd_bcm2835_new_ctl(bcm2835_chip_t *
+ if (err < 0)
+ return err;
+ }
+- snd_bcm2835_add_chmap_ctl(chip);
+ for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_spdif); idx++) {
+ err = snd_ctl_add(chip->card,
+ snd_ctl_new1(&snd_bcm2835_spdif[idx], chip));
+--- a/sound/arm/bcm2835-pcm.c
++++ b/sound/arm/bcm2835-pcm.c
+@@ -19,9 +19,6 @@
+
+ #include "bcm2835.h"
+
+-/* The hardware can not do much more num_channels*samplerate then this value */
+-#define MAX_COMBINED_RATE 768000
+-
+ /* hardware definition */
+ static struct snd_pcm_hardware snd_bcm2835_playback_hw = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+@@ -110,31 +107,6 @@ static irqreturn_t bcm2835_playback_fifo
+ return IRQ_HANDLED;
+ }
+
+-
+-static int rate_hw_constraint_rate(struct snd_pcm_hw_params *params,
+- struct snd_pcm_hw_rule *rule)
+-{
+- struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+- struct snd_interval rates = {
+- .min = 8000,
+- .max = min(192000u, MAX_COMBINED_RATE / max(channels->min, 1u)),
+- };
+- struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+- return snd_interval_refine(rate, &rates);
+-}
+-
+-static int rate_hw_constraint_channels(struct snd_pcm_hw_params *params,
+- struct snd_pcm_hw_rule *rule)
+-{
+- struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+- struct snd_interval channels_interval = {
+- .min = 1,
+- .max = min(8u, MAX_COMBINED_RATE / max(rate->min, 1u)),
+- };
+- struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+- return snd_interval_refine(channels, &channels_interval);
+-}
+-
+ /* open callback */
+ static int snd_bcm2835_playback_open_generic(
+ struct snd_pcm_substream *substream, int spdif)
+@@ -216,24 +188,8 @@ static int snd_bcm2835_playback_open_gen
+ snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+ 16);
+
+- /* When playing PCM, pretend that we support the full range of channels
+- * and sample rates. The GPU can't output it, but is able to resample
+- * the data to a rate the hardware can handle it. This won't work with
+- * compressed data; the resampler would just destroy it. */
+- if (spdif) {
+- err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+- rate_hw_constraint_rate, NULL,
+- SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+- err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+- rate_hw_constraint_channels, NULL,
+- SNDRV_PCM_HW_PARAM_RATE, -1);
+- }
+-
+ chip->alsa_stream[idx] = alsa_stream;
+
+- if (!chip->opened)
+- chip->cea_chmap = -1;
+-
+ chip->opened |= (1 << idx);
+ alsa_stream->open = 1;
+ alsa_stream->draining = 1;
+@@ -344,7 +300,8 @@ static int snd_bcm2835_pcm_hw_free(struc
+ return snd_pcm_lib_free_pages(substream);
+ }
+
+-int snd_bcm2835_pcm_prepare_again(struct snd_pcm_substream *substream)
++/* prepare callback */
++static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
+ {
+ bcm2835_chip_t *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+@@ -352,6 +309,11 @@ int snd_bcm2835_pcm_prepare_again(struct
+ int channels;
+ int err;
+
++ audio_info(" .. IN\n");
++
++ if (mutex_lock_interruptible(&chip->audio_mutex))
++ return -EINTR;
++
+ /* notify the vchiq that it should enter spdif passthrough mode by
+ * setting channels=0 (see
+ * https://github.com/raspberrypi/linux/issues/528) */
+@@ -367,23 +329,6 @@ int snd_bcm2835_pcm_prepare_again(struct
+ audio_error(" error setting hw params\n");
+ }
+
+- return err;
+-}
+-
+-/* prepare callback */
+-static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
+-{
+- bcm2835_chip_t *chip = snd_pcm_substream_chip(substream);
+- struct snd_pcm_runtime *runtime = substream->runtime;
+- bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
+-
+- audio_info(" .. IN\n");
+-
+- if (mutex_lock_interruptible(&chip->audio_mutex))
+- return -EINTR;
+-
+- snd_bcm2835_pcm_prepare_again(substream);
+-
+ bcm2835_audio_setup(alsa_stream);
+
+ /* in preparation of the stream, set the controls (volume level) of the stream */
+--- a/sound/arm/bcm2835-vchiq.c
++++ b/sound/arm/bcm2835-vchiq.c
+@@ -570,8 +570,6 @@ int bcm2835_audio_set_params(bcm2835_als
+ VC_AUDIO_MSG_T m;
+ AUDIO_INSTANCE_T *instance = alsa_stream->instance;
+ int32_t success;
+- uint32_t chmap_value;
+- int i;
+ int ret;
+ LOG_DBG(" .. IN\n");
+
+@@ -595,21 +593,10 @@ int bcm2835_audio_set_params(bcm2835_als
+
+ instance->result = -1;
+
+- if (alsa_stream->chip->cea_chmap >= 0) {
+- chmap_value = (unsigned)alsa_stream->chip->cea_chmap << 24;
+- } else {
+- chmap_value = 0; /* force stereo */
+- for (i = 0; i < 8; i++)
+- alsa_stream->chip->map_channels[i] = i;
+- }
+- for (i = 0; i < 8; i++)
+- chmap_value |= alsa_stream->chip->map_channels[i] << (i * 3);
+-
+ m.type = VC_AUDIO_MSG_TYPE_CONFIG;
+ m.u.config.channels = channels;
+ m.u.config.samplerate = samplerate;
+ m.u.config.bps = bps;
+- m.u.config.channelmap = chmap_value;
+
+ /* Create the message available completion */
+ init_completion(&instance->msg_avail_comp);
+--- a/sound/arm/bcm2835.h
++++ b/sound/arm/bcm2835.h
+@@ -107,8 +107,6 @@ typedef struct bcm2835_chip {
+ int old_volume; /* stores the volume value whist muted */
+ int dest;
+ int mute;
+- int cea_chmap; /* currently requested Audio InfoFrame Data Byte 4 */
+- int map_channels[8];
+
+ unsigned int opened;
+ unsigned int spdif_status;
+@@ -151,8 +149,6 @@ int snd_bcm2835_new_ctl(bcm2835_chip_t *
+ int snd_bcm2835_new_pcm(bcm2835_chip_t * chip);
+ int snd_bcm2835_new_spdif_pcm(bcm2835_chip_t * chip);
+
+-int snd_bcm2835_pcm_prepare_again(struct snd_pcm_substream *substream);
+-
+ int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream);
+ int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream);
+ int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
diff --git a/target/linux/brcm2708/patches-4.4/0319-Revert-bcm2835-extend-allowed-range-of-channels-and-.patch b/target/linux/brcm2708/patches-4.4/0319-Revert-bcm2835-extend-allowed-range-of-channels-and-.patch
new file mode 100644
index 0000000000..62237d364d
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0319-Revert-bcm2835-extend-allowed-range-of-channels-and-.patch
@@ -0,0 +1,37 @@
+From cc475d93be9bf38826d0e091172816c29996fa4c Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Fri, 29 Apr 2016 17:30:00 +0100
+Subject: [PATCH 319/381] Revert "bcm2835: extend allowed range of channels and
+ samplerates"
+
+This reverts commit 688a5f0daa45e0a51b324707768d472e1d715c13.
+---
+ sound/arm/bcm2835-pcm.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/sound/arm/bcm2835-pcm.c
++++ b/sound/arm/bcm2835-pcm.c
+@@ -26,9 +26,9 @@ static struct snd_pcm_hardware snd_bcm28
+ .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
+ .rate_min = 8000,
+- .rate_max = 192000,
++ .rate_max = 48000,
+ .channels_min = 1,
+- .channels_max = 8,
++ .channels_max = 2,
+ .buffer_bytes_max = 128 * 1024,
+ .period_bytes_min = 1 * 1024,
+ .period_bytes_max = 128 * 1024,
+@@ -43,9 +43,9 @@ static struct snd_pcm_hardware snd_bcm28
+ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000,
+ .rate_min = 44100,
+- .rate_max = 192000,
++ .rate_max = 48000,
+ .channels_min = 2,
+- .channels_max = 8,
++ .channels_max = 2,
+ .buffer_bytes_max = 128 * 1024,
+ .period_bytes_min = 1 * 1024,
+ .period_bytes_max = 128 * 1024,
diff --git a/target/linux/brcm2708/patches-4.4/0320-videobuf2-v4l2-Verify-planes-array-in-buffer-dequeue.patch b/target/linux/brcm2708/patches-4.4/0320-videobuf2-v4l2-Verify-planes-array-in-buffer-dequeue.patch
new file mode 100644
index 0000000000..9ff50aa6a5
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0320-videobuf2-v4l2-Verify-planes-array-in-buffer-dequeue.patch
@@ -0,0 +1,53 @@
+From 2d8ae9f2f45a2f5b777088cbab6e5ea15744d1d5 Mon Sep 17 00:00:00 2001
+From: Sakari Ailus <sakari.ailus@linux.intel.com>
+Date: Sun, 3 Apr 2016 16:31:03 -0300
+Subject: [PATCH 320/381] videobuf2-v4l2: Verify planes array in buffer
+ dequeueing
+
+commit 2c1f6951a8a82e6de0d82b1158b5e493fc6c54ab upstream.
+
+When a buffer is being dequeued using VIDIOC_DQBUF IOCTL, the exact buffer
+which will be dequeued is not known until the buffer has been removed from
+the queue. The number of planes is specific to a buffer, not to the queue.
+
+This does lead to the situation where multi-plane buffers may be requested
+and queued with n planes, but VIDIOC_DQBUF IOCTL may be passed an argument
+struct with fewer planes.
+
+__fill_v4l2_buffer() however uses the number of planes from the dequeued
+videobuf2 buffer, overwriting kernel memory (the m.planes array allocated
+in video_usercopy() in v4l2-ioctl.c) if the user provided fewer
+planes than the dequeued buffer had. Oops!
+
+Fixes: b0e0e1f83de3 ("[media] media: videobuf2: Prepare to divide videobuf2")
+
+Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/videobuf2-v4l2.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/media/v4l2-core/videobuf2-v4l2.c
++++ b/drivers/media/v4l2-core/videobuf2-v4l2.c
+@@ -67,6 +67,11 @@ static int __verify_planes_array(struct
+ return 0;
+ }
+
++static int __verify_planes_array_core(struct vb2_buffer *vb, const void *pb)
++{
++ return __verify_planes_array(vb, pb);
++}
++
+ /**
+ * __verify_length() - Verify that the bytesused value for each plane fits in
+ * the plane length and that the data offset doesn't exceed the bytesused value.
+@@ -432,6 +437,7 @@ static int __fill_vb2_buffer(struct vb2_
+ }
+
+ static const struct vb2_buf_ops v4l2_buf_ops = {
++ .verify_planes_array = __verify_planes_array_core,
+ .fill_user_buffer = __fill_v4l2_buffer,
+ .fill_vb2_buffer = __fill_vb2_buffer,
+ .set_timestamp = __set_timestamp,
diff --git a/target/linux/brcm2708/patches-4.4/0321-pinctrl-bcm2835-Return-pins-to-inputs-when-freed.patch b/target/linux/brcm2708/patches-4.4/0321-pinctrl-bcm2835-Return-pins-to-inputs-when-freed.patch
new file mode 100644
index 0000000000..cf1c106b70
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0321-pinctrl-bcm2835-Return-pins-to-inputs-when-freed.patch
@@ -0,0 +1,40 @@
+From 2e4f06a9b7276db1e2dafe33564ad5115f63a210 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 6 May 2016 12:32:47 +0100
+Subject: [PATCH 321/381] pinctrl-bcm2835: Return pins to inputs when freed
+
+When dynamically unloading overlays, it is important that freed pins are
+restored to being inputs to prevent functions from being enabled in
+multiple places at once.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/pinctrl/bcm/pinctrl-bcm2835.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
++++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+@@ -831,6 +831,15 @@ static const struct pinctrl_ops bcm2835_
+ .dt_free_map = bcm2835_pctl_dt_free_map,
+ };
+
++static void bcm2835_pmx_free(struct pinctrl_dev *pctldev,
++ unsigned offset)
++{
++ struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
++
++ /* disable by setting to GPIO_IN */
++ bcm2835_pinctrl_fsel_set(pc, offset, BCM2835_FSEL_GPIO_IN);
++}
++
+ static int bcm2835_pmx_get_functions_count(struct pinctrl_dev *pctldev)
+ {
+ return BCM2835_FSEL_COUNT;
+@@ -890,6 +899,7 @@ static int bcm2835_pmx_gpio_set_directio
+ }
+
+ static const struct pinmux_ops bcm2835_pmx_ops = {
++ .free = bcm2835_pmx_free,
+ .get_functions_count = bcm2835_pmx_get_functions_count,
+ .get_function_name = bcm2835_pmx_get_function_name,
+ .get_function_groups = bcm2835_pmx_get_function_groups,
diff --git a/target/linux/brcm2708/patches-4.4/0322-BCM270X_DT-i2c0-bcm2708-pin-group-params.patch b/target/linux/brcm2708/patches-4.4/0322-BCM270X_DT-i2c0-bcm2708-pin-group-params.patch
new file mode 100644
index 0000000000..7112ee625a
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0322-BCM270X_DT-i2c0-bcm2708-pin-group-params.patch
@@ -0,0 +1,99 @@
+From c451203424a277e522ea5227cefa84658615f442 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 6 May 2016 12:53:16 +0100
+Subject: [PATCH 322/381] BCM270X_DT: i2c0-bcm2708 - pin group params
+
+Add parameters to set pin groups as a unit, setting the pin function
+appropriately. The parameters are:
+ pins_0_1
+ pins_28_29
+ pins_44_45
+ pins_46_47
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/overlays/README | 11 ++++--
+ .../arm/boot/dts/overlays/i2c0-bcm2708-overlay.dts | 43 +++++++++++++++++-----
+ 2 files changed, 42 insertions(+), 12 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -449,10 +449,15 @@ Params: ds1307 Select t
+
+
+ Name: i2c0-bcm2708
+-Info: Enable the i2c_bcm2708 driver for the i2c0 bus
++Info: Enable the i2c_bcm2708 driver for the i2c0 bus. Not all pin combinations
++ are usable on all platforms.
+ Load: dtoverlay=i2c0-bcm2708,<param>=<val>
+-Params: sda0_pin GPIO pin for SDA0 (0, 28 [or 44] - default 0)
+- scl0_pin GPIO pin for SCL0 (1, 29 [or 45] - default 1)
++Params: sda0_pin GPIO pin for SDA0 (deprecated - use pins_*)
++ scl0_pin GPIO pin for SCL0 (deprecated - use pins_*)
++ pins_0_1 Use pins 0 and 1 (default)
++ pins_28_29 Use pins 28 and 29
++ pins_44_45 Use pins 44 and 45
++ pins_46_47 Use pins 46 and 47
+
+
+ Name: i2c1-bcm2708
+--- a/arch/arm/boot/dts/overlays/i2c0-bcm2708-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c0-bcm2708-overlay.dts
+@@ -14,23 +14,48 @@
+ fragment@0 {
+ target = <&i2c0>;
+ __overlay__ {
+- pinctrl-0 = <&i2c0_pins>;
+ status = "okay";
+ };
+ };
+
+ fragment@1 {
+- target = <&gpio>;
+- __overlay__ {
+- i2c0_pins: i2c0 {
+- brcm,pins = <0 1>;
+- brcm,function = <4>; /* alt0 */
+- };
++ target = <&i2c0_pins>;
++ frag1: __overlay__ {
++ brcm,pins = <0 1>;
++ brcm,function = <4>; /* alt0 */
++ };
++ };
++
++ fragment@2 {
++ target = <&i2c0_pins>;
++ __dormant__ {
++ brcm,pins = <28 29>;
++ brcm,function = <4>; /* alt0 */
++ };
++ };
++
++ fragment@3 {
++ target = <&i2c0_pins>;
++ __dormant__ {
++ brcm,pins = <44 45>;
++ brcm,function = <5>; /* alt1 */
++ };
++ };
++
++ fragment@4 {
++ target = <&i2c0_pins>;
++ __dormant__ {
++ brcm,pins = <46 47>;
++ brcm,function = <4>; /* alt0 */
+ };
+ };
+
+ __overrides__ {
+- sda0_pin = <&i2c0_pins>,"brcm,pins:0";
+- scl0_pin = <&i2c0_pins>,"brcm,pins:4";
++ sda0_pin = <&frag1>,"brcm,pins:0";
++ scl0_pin = <&frag1>,"brcm,pins:4";
++ pins_0_1 = <0>,"+1-2-3-4";
++ pins_28_29 = <0>,"-1+2-3-4";
++ pins_44_45 = <0>,"-1-2+3-4";
++ pins_46_47 = <0>,"-1-2-3+4";
+ };
+ };
diff --git a/target/linux/brcm2708/patches-4.4/0323-config-Add-CONFIG_DRM_LOAD_EDID_FIRMWARE.patch b/target/linux/brcm2708/patches-4.4/0323-config-Add-CONFIG_DRM_LOAD_EDID_FIRMWARE.patch
new file mode 100644
index 0000000000..f844d499d0
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0323-config-Add-CONFIG_DRM_LOAD_EDID_FIRMWARE.patch
@@ -0,0 +1,30 @@
+From 616ba69b10a0c52f241575727c1f0d04ea9e9113 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Fri, 6 May 2016 12:40:37 +0100
+Subject: [PATCH 323/381] config: Add CONFIG_DRM_LOAD_EDID_FIRMWARE
+
+---
+ arch/arm/configs/bcm2709_defconfig | 1 +
+ arch/arm/configs/bcmrpi_defconfig | 1 +
+ 2 files changed, 2 insertions(+)
+
+--- a/arch/arm/configs/bcm2709_defconfig
++++ b/arch/arm/configs/bcm2709_defconfig
+@@ -815,6 +815,7 @@ CONFIG_VIDEO_TW9906=m
+ CONFIG_VIDEO_OV7640=m
+ CONFIG_VIDEO_MT9V011=m
+ CONFIG_DRM=m
++CONFIG_DRM_LOAD_EDID_FIRMWARE=y
+ CONFIG_DRM_UDL=m
+ CONFIG_DRM_VC4=m
+ CONFIG_FB=y
+--- a/arch/arm/configs/bcmrpi_defconfig
++++ b/arch/arm/configs/bcmrpi_defconfig
+@@ -807,6 +807,7 @@ CONFIG_VIDEO_TW9906=m
+ CONFIG_VIDEO_OV7640=m
+ CONFIG_VIDEO_MT9V011=m
+ CONFIG_DRM=m
++CONFIG_DRM_LOAD_EDID_FIRMWARE=y
+ CONFIG_DRM_UDL=m
+ CONFIG_DRM_VC4=m
+ CONFIG_FB=y
diff --git a/target/linux/brcm2708/patches-4.4/0324-Revert-rpi-update-vc_vchi_audioserv_defs.h.patch b/target/linux/brcm2708/patches-4.4/0324-Revert-rpi-update-vc_vchi_audioserv_defs.h.patch
new file mode 100644
index 0000000000..cf2780b2f1
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0324-Revert-rpi-update-vc_vchi_audioserv_defs.h.patch
@@ -0,0 +1,63 @@
+From f4187433a0b4592ae6df10d9080aec70270ad147 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Fri, 6 May 2016 17:18:57 +0100
+Subject: [PATCH 324/381] Revert "rpi: update vc_vchi_audioserv_defs.h"
+
+This reverts commit 64fa9f963dffab0145f7960a593422064bb0aa8d.
+---
+ sound/arm/vc_vchi_audioserv_defs.h | 13 ++-----------
+ 1 file changed, 2 insertions(+), 11 deletions(-)
+
+--- a/sound/arm/vc_vchi_audioserv_defs.h
++++ b/sound/arm/vc_vchi_audioserv_defs.h
+@@ -16,7 +16,7 @@
+ #define _VC_AUDIO_DEFS_H_
+
+ #define VC_AUDIOSERV_MIN_VER 1
+-#define VC_AUDIOSERV_VER 3
++#define VC_AUDIOSERV_VER 2
+
+ // FourCC code used for VCHI connection
+ #define VC_AUDIO_SERVER_NAME MAKE_FOURCC("AUDS")
+@@ -36,7 +36,6 @@ typedef enum {
+ VC_AUDIO_MSG_TYPE_START, // Configure audio
+ VC_AUDIO_MSG_TYPE_STOP, // Configure audio
+ VC_AUDIO_MSG_TYPE_WRITE, // Configure audio
+- VC_AUDIO_MSG_TYPE_LATENCY, // request latency in cycles
+ VC_AUDIO_MSG_TYPE_MAX
+ } VC_AUDIO_MSG_TYPE;
+
+@@ -45,7 +44,6 @@ typedef struct {
+ uint32_t channels;
+ uint32_t samplerate;
+ uint32_t bps;
+- uint32_t channelmap;
+
+ } VC_AUDIO_CONFIG_T;
+
+@@ -86,12 +84,6 @@ typedef struct {
+ uint16_t max_packet;
+ } VC_AUDIO_WRITE_T;
+
+-// query latency in samples of sink
+-typedef struct
+-{
+- uint32_t dummy;
+-} VC_AUDIO_LATENCY_T;
+-
+ // Generic result for a request (VC->HOST)
+ typedef struct {
+ int32_t success; // Success value
+@@ -116,10 +108,9 @@ typedef struct {
+ VC_AUDIO_START_T start;
+ VC_AUDIO_STOP_T stop;
+ VC_AUDIO_WRITE_T write;
+- VC_AUDIO_LATENCY_T latency;
+ VC_AUDIO_RESULT_T result;
+ VC_AUDIO_COMPLETE_T complete;
+ } u;
+ } VC_AUDIO_MSG_T;
+
+-#endif // _VC_AUDIO_DEFS_H_
+\ No newline at end of file
++#endif // _VC_AUDIO_DEFS_H_
diff --git a/target/linux/brcm2708/patches-4.4/0325-Revert-config-Add-CONFIG_DRM_LOAD_EDID_FIRMWARE.patch b/target/linux/brcm2708/patches-4.4/0325-Revert-config-Add-CONFIG_DRM_LOAD_EDID_FIRMWARE.patch
new file mode 100644
index 0000000000..416a625482
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0325-Revert-config-Add-CONFIG_DRM_LOAD_EDID_FIRMWARE.patch
@@ -0,0 +1,31 @@
+From 2faa3a4eb01cdd6c372c235900139a96ed5e81f7 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Fri, 6 May 2016 17:21:58 +0100
+Subject: [PATCH 325/381] Revert "config: Add CONFIG_DRM_LOAD_EDID_FIRMWARE"
+
+This reverts commit 417aed4cb35a479e001c8389fd8d97c3ea612999.
+---
+ arch/arm/configs/bcm2709_defconfig | 1 -
+ arch/arm/configs/bcmrpi_defconfig | 1 -
+ 2 files changed, 2 deletions(-)
+
+--- a/arch/arm/configs/bcm2709_defconfig
++++ b/arch/arm/configs/bcm2709_defconfig
+@@ -815,7 +815,6 @@ CONFIG_VIDEO_TW9906=m
+ CONFIG_VIDEO_OV7640=m
+ CONFIG_VIDEO_MT9V011=m
+ CONFIG_DRM=m
+-CONFIG_DRM_LOAD_EDID_FIRMWARE=y
+ CONFIG_DRM_UDL=m
+ CONFIG_DRM_VC4=m
+ CONFIG_FB=y
+--- a/arch/arm/configs/bcmrpi_defconfig
++++ b/arch/arm/configs/bcmrpi_defconfig
+@@ -807,7 +807,6 @@ CONFIG_VIDEO_TW9906=m
+ CONFIG_VIDEO_OV7640=m
+ CONFIG_VIDEO_MT9V011=m
+ CONFIG_DRM=m
+-CONFIG_DRM_LOAD_EDID_FIRMWARE=y
+ CONFIG_DRM_UDL=m
+ CONFIG_DRM_VC4=m
+ CONFIG_FB=y
diff --git a/target/linux/brcm2708/patches-4.4/0326-ARM-adau1977-adc-Add-basic-machine-driver-for-adau19.patch b/target/linux/brcm2708/patches-4.4/0326-ARM-adau1977-adc-Add-basic-machine-driver-for-adau19.patch
new file mode 100644
index 0000000000..513db1bb64
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0326-ARM-adau1977-adc-Add-basic-machine-driver-for-adau19.patch
@@ -0,0 +1,285 @@
+From 347d4cf757e6f093860048fe69737c29f5adcd0f Mon Sep 17 00:00:00 2001
+From: Andrey Grodzovsky <andrey2805@gmail.com>
+Date: Tue, 3 May 2016 22:10:59 -0400
+Subject: [PATCH 326/381] ARM: adau1977-adc: Add basic machine driver for
+ adau1977 codec driver.
+
+This commit adds basic support for the codec usage including: Device tree overlay,
+binding I2S bus and setting I2S mode, clock source and frequency setting according
+to spec.
+
+Signed-off-by: Andrey Grodzovsky <andrey2805@gmail.com>
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 7 ++
+ .../arm/boot/dts/overlays/adau1977-adc-overlay.dts | 53 +++++++++
+ arch/arm/configs/bcm2709_defconfig | 1 +
+ arch/arm/configs/bcmrpi_defconfig | 1 +
+ sound/soc/bcm/Kconfig | 7 ++
+ sound/soc/bcm/Makefile | 2 +
+ sound/soc/bcm/adau1977-adc.c | 125 +++++++++++++++++++++
+ 8 files changed, 197 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/adau1977-adc-overlay.dts
+ create mode 100644 sound/soc/bcm/adau1977-adc.c
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -12,6 +12,7 @@ ifeq ($(CONFIG_ARCH_BCM2835),y)
+ RPI_DT_OVERLAYS=y
+ endif
+
++dtbo-$(RPI_DT_OVERLAYS) += adau1977-adc.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += ads7846.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += akkordion-iqdacplus.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += at86rf233.dtbo
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -161,6 +161,13 @@ Params:
+ and the other i2c baudrate parameters.
+
+
++Name: adau1977-adc
++Info: Overlay for activation of ADAU1977 ADC codec over I2C for control
++ and I2S for data.
++Load: dtoverlay=adau1977-adc
++Params: <None>
++
++
+ Name: ads7846
+ Info: ADS7846 Touch controller
+ Load: dtoverlay=ads7846,<param>=<val>
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/adau1977-adc-overlay.dts
+@@ -0,0 +1,53 @@
++// Definitions for ADAU1977 ADC
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&soc>;
++
++ __overlay__ {
++ codec_supply: fixedregulator@0 {
++ compatible = "regulator-fixed";
++ regulator-name = "AVDD";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&i2c>;
++
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ adau1977: codec@11 {
++ compatible = "adi,adau1977";
++ reg = <0x11>;
++ reset-gpios = <&gpio 5 0>;
++ AVDD-supply = <&codec_supply>;
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&i2s>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@3 {
++ target = <&sound>;
++ __overlay__ {
++ compatible = "adi,adau1977-adc";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
++};
+--- a/arch/arm/configs/bcm2709_defconfig
++++ b/arch/arm/configs/bcm2709_defconfig
+@@ -861,6 +861,7 @@ CONFIG_SND_BCM2708_SOC_BOOMBERRY_DAC=m
+ CONFIG_SND_BCM2708_SOC_BOOMBERRY_DIGI=m
+ CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m
+ CONFIG_SND_BCM2708_SOC_RASPIDAC3=m
++CONFIG_SND_BCM2708_SOC_ADAU1977_ADC=m
+ CONFIG_SND_SOC_ADAU1701=m
+ CONFIG_SND_SOC_WM8804_I2C=m
+ CONFIG_SND_SIMPLE_CARD=m
+--- a/arch/arm/configs/bcmrpi_defconfig
++++ b/arch/arm/configs/bcmrpi_defconfig
+@@ -853,6 +853,7 @@ CONFIG_SND_BCM2708_SOC_BOOMBERRY_DAC=m
+ CONFIG_SND_BCM2708_SOC_BOOMBERRY_DIGI=m
+ CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m
+ CONFIG_SND_BCM2708_SOC_RASPIDAC3=m
++CONFIG_SND_BCM2708_SOC_ADAU1977_ADC=m
+ CONFIG_SND_SOC_ADAU1701=m
+ CONFIG_SND_SOC_WM8804_I2C=m
+ CONFIG_SND_SIMPLE_CARD=m
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -78,3 +78,10 @@ config SND_BCM2708_SOC_RASPIDAC3
+ select SND_SOC_TPA6130A2
+ help
+ Say Y or M if you want to add support for RaspiDAC Rev.3x.
++
++config SND_BCM2708_SOC_ADAU1977_ADC
++ tristate "Support for ADAU1977 ADC"
++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
++ select SND_SOC_ADAU1977_I2C
++ help
++ Say Y or M if you want to add support for ADAU1977 ADC.
+--- a/sound/soc/bcm/Makefile
++++ b/sound/soc/bcm/Makefile
+@@ -4,6 +4,7 @@ snd-soc-bcm2835-i2s-objs := bcm2835-i2s.
+ obj-$(CONFIG_SND_BCM2835_SOC_I2S) += snd-soc-bcm2835-i2s.o
+
+ # BCM2708 Machine Support
++snd-soc-adau1977-adc-objs := adau1977-adc.o
+ snd-soc-hifiberry-dac-objs := hifiberry_dac.o
+ snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
+ snd-soc-hifiberry-digi-objs := hifiberry_digi.o
+@@ -15,6 +16,7 @@ snd-soc-rpi-proto-objs := rpi-proto.o
+ snd-soc-iqaudio-dac-objs := iqaudio-dac.o
+ snd-soc-raspidac3-objs := raspidac3.o
+
++obj-$(CONFIG_SND_BCM2708_SOC_ADAU1977_ADC) += snd-soc-adau1977-adc.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o
+--- /dev/null
++++ b/sound/soc/bcm/adau1977-adc.c
+@@ -0,0 +1,125 @@
++/*
++ * ASoC Driver for ADAU1977 ADC
++ *
++ * Author: Andrey Grodzovsky <andrey2805@gmail.com>
++ * Copyright 2016
++ *
++ * This file is based on hifibery_dac driver by Florian Meier.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/jack.h>
++
++enum adau1977_clk_id {
++ ADAU1977_SYSCLK,
++};
++
++enum adau1977_sysclk_src {
++ ADAU1977_SYSCLK_SRC_MCLK,
++ ADAU1977_SYSCLK_SRC_LRCLK,
++};
++
++static int eval_adau1977_init(struct snd_soc_pcm_runtime *rtd)
++{
++ int ret;
++ struct snd_soc_dai *codec_dai = rtd->codec_dai;
++
++ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0, 0, 0, 0);
++ if (ret < 0)
++ return ret;
++
++ return snd_soc_codec_set_sysclk(rtd->codec, ADAU1977_SYSCLK,
++ ADAU1977_SYSCLK_SRC_MCLK, 11289600, SND_SOC_CLOCK_IN);
++}
++
++static struct snd_soc_dai_link snd_rpi_adau1977_dai[] = {
++ {
++ .name = "adau1977",
++ .stream_name = "ADAU1977",
++ .cpu_dai_name = "bcm2708-i2s.0",
++ .codec_dai_name = "adau1977-hifi",
++ .platform_name = "bcm2708-i2s.0",
++ .codec_name = "adau1977.1-0011",
++ .init = eval_adau1977_init,
++ .dai_fmt = SND_SOC_DAIFMT_I2S |
++ SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBM_CFM,
++ },
++};
++
++/* audio machine driver */
++static struct snd_soc_card snd_adau1977_adc = {
++ .name = "snd_rpi_adau1977_adc",
++ .owner = THIS_MODULE,
++ .dai_link = snd_rpi_adau1977_dai,
++ .num_links = ARRAY_SIZE(snd_rpi_adau1977_dai),
++};
++
++static int snd_adau1977_adc_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++
++ snd_adau1977_adc.dev = &pdev->dev;
++ if (pdev->dev.of_node) {
++ struct device_node *i2s_node;
++ struct snd_soc_dai_link *dai = &snd_rpi_adau1977_dai[0];
++ i2s_node = of_parse_phandle(pdev->dev.of_node,
++ "i2s-controller", 0);
++
++ if (i2s_node) {
++ dai->cpu_dai_name = NULL;
++ dai->cpu_of_node = i2s_node;
++ dai->platform_name = NULL;
++ dai->platform_of_node = i2s_node;
++ }
++ }
++
++ ret = snd_soc_register_card(&snd_adau1977_adc);
++ if (ret)
++ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret);
++
++ return ret;
++}
++
++static int snd_adau1977_adc_remove(struct platform_device *pdev)
++{
++ return snd_soc_unregister_card(&snd_adau1977_adc);
++}
++
++static const struct of_device_id snd_adau1977_adc_of_match[] = {
++ { .compatible = "adi,adau1977-adc", },
++ {},
++};
++
++MODULE_DEVICE_TABLE(of, snd_adau1977_adc_of_match);
++
++static struct platform_driver snd_adau1977_adc_driver = {
++ .driver = {
++ .name = "snd-adau1977-adc",
++ .owner = THIS_MODULE,
++ .of_match_table = snd_adau1977_adc_of_match,
++ },
++ .probe = snd_adau1977_adc_probe,
++ .remove = snd_adau1977_adc_remove,
++};
++
++module_platform_driver(snd_adau1977_adc_driver);
++
++MODULE_AUTHOR("Andrey Grodzovsky <andrey2805@gmail.com>");
++MODULE_DESCRIPTION("ASoC Driver for ADAU1977 ADC");
++MODULE_LICENSE("GPL v2");
diff --git a/target/linux/brcm2708/patches-4.4/0327-Allow-up-to-24dB-digital-gain-to-be-applied-when-usi.patch b/target/linux/brcm2708/patches-4.4/0327-Allow-up-to-24dB-digital-gain-to-be-applied-when-usi.patch
new file mode 100644
index 0000000000..daea4dbc3f
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0327-Allow-up-to-24dB-digital-gain-to-be-applied-when-usi.patch
@@ -0,0 +1,60 @@
+From ba4e2749004660d573c0d62f6fec876cd152bd3e Mon Sep 17 00:00:00 2001
+From: DigitalDreamtime <clive.messer@digitaldreamtime.co.uk>
+Date: Fri, 6 May 2016 09:42:55 +0100
+Subject: [PATCH 327/381] Allow up to 24dB digital gain to be applied when
+ using IQAudIO DAC
+
+24db_digital_gain DT param can be used to specify that PCM512x
+codec "Digital" volume control should not be limited to 0dB gain,
+and if specified will allow the full 24dB gain.
+
+Signed-off-by: DigitalDreamtime <clive.messer@digitaldreamtime.co.uk>
+---
+ arch/arm/boot/dts/overlays/README | 17 +++++++++++++++--
+ arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts | 6 +++++-
+ 2 files changed, 20 insertions(+), 3 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -490,8 +490,21 @@ Params: <None>
+
+ Name: iqaudio-dac
+ Info: Configures the IQaudio DAC audio card
+-Load: dtoverlay=iqaudio-dac
+-Params: <None>
++Load: dtoverlay=iqaudio-dac,<param>
++Params: 24db_digital_gain Allow gain to be applied via the PCM512x codec
++ Digital volume control. Enable with
++ "dtoverlay=iqaudio-dac,24db_digital_gain"
++ (The default behaviour is that the Digital
++ volume control is limited to a maximum of
++ 0dB. ie. it can attenuate but not provide
++ gain. For most users, this will be desired
++ as it will prevent clipping. By appending
++ the 24db_digital_gain parameter, the Digital
++ volume control will allow up to 24dB of
++ gain. If this parameter is enabled, it is the
++ responsibility of the user to ensure that
++ the Digital volume control is set to a value
++ that does not result in clipping/distortion!)
+
+
+ Name: iqaudio-dacplus
+--- a/arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts
++++ b/arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts
+@@ -30,10 +30,14 @@
+
+ fragment@2 {
+ target = <&sound>;
+- __overlay__ {
++ frag2: __overlay__ {
+ compatible = "iqaudio,iqaudio-dac";
+ i2s-controller = <&i2s>;
+ status = "okay";
+ };
+ };
++
++ __overrides__ {
++ 24db_digital_gain = <&frag2>,"iqaudio,24db_digital_gain?";
++ };
+ };
diff --git a/target/linux/brcm2708/patches-4.4/0328-config-Add-CONFIG_DRM_LOAD_EDID_FIRMWARE.patch b/target/linux/brcm2708/patches-4.4/0328-config-Add-CONFIG_DRM_LOAD_EDID_FIRMWARE.patch
new file mode 100644
index 0000000000..0dce6cc476
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0328-config-Add-CONFIG_DRM_LOAD_EDID_FIRMWARE.patch
@@ -0,0 +1,30 @@
+From dd29bbd2aae28fb176221d740cca0aacabae3842 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Fri, 6 May 2016 12:40:37 +0100
+Subject: [PATCH 328/381] config: Add CONFIG_DRM_LOAD_EDID_FIRMWARE
+
+---
+ arch/arm/configs/bcm2709_defconfig | 1 +
+ arch/arm/configs/bcmrpi_defconfig | 1 +
+ 2 files changed, 2 insertions(+)
+
+--- a/arch/arm/configs/bcm2709_defconfig
++++ b/arch/arm/configs/bcm2709_defconfig
+@@ -815,6 +815,7 @@ CONFIG_VIDEO_TW9906=m
+ CONFIG_VIDEO_OV7640=m
+ CONFIG_VIDEO_MT9V011=m
+ CONFIG_DRM=m
++CONFIG_DRM_LOAD_EDID_FIRMWARE=y
+ CONFIG_DRM_UDL=m
+ CONFIG_DRM_VC4=m
+ CONFIG_FB=y
+--- a/arch/arm/configs/bcmrpi_defconfig
++++ b/arch/arm/configs/bcmrpi_defconfig
+@@ -807,6 +807,7 @@ CONFIG_VIDEO_TW9906=m
+ CONFIG_VIDEO_OV7640=m
+ CONFIG_VIDEO_MT9V011=m
+ CONFIG_DRM=m
++CONFIG_DRM_LOAD_EDID_FIRMWARE=y
+ CONFIG_DRM_UDL=m
+ CONFIG_DRM_VC4=m
+ CONFIG_FB=y
diff --git a/target/linux/brcm2708/patches-4.4/0329-BCM270X_DT-Move-vc4-node-contents-to-bcm2708_common..patch b/target/linux/brcm2708/patches-4.4/0329-BCM270X_DT-Move-vc4-node-contents-to-bcm2708_common..patch
new file mode 100644
index 0000000000..e1c0253edd
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0329-BCM270X_DT-Move-vc4-node-contents-to-bcm2708_common..patch
@@ -0,0 +1,325 @@
+From 4cb8cf8c6ce47b652c93bae2b4b480bd7ea7f940 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Fri, 6 May 2016 11:48:35 -0700
+Subject: [PATCH 329/381] BCM270X_DT: Move vc4 node contents to
+ bcm2708_common.dtsi.
+
+This should clarify what's going on with the overlay: The hardware is
+always present, we're just enabling the DT node so that the vc4 driver
+probes.
+
+The interrupts are left in the overlay, because the firmware doesn't
+check node status before masking out the vc4 interrupts.
+
+By having the nodes in the common file, we'll be able to correctly
+connect the HDMI HPD GPIO so that we can detect whether an HDMI
+monitor is connected.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ arch/arm/boot/dts/bcm2708_common.dtsi | 51 +++++++
+ arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts | 160 ++++++++++-----------
+ 2 files changed, 129 insertions(+), 82 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2708_common.dtsi
++++ b/arch/arm/boot/dts/bcm2708_common.dtsi
+@@ -1,4 +1,7 @@
++#include "dt-bindings/clock/bcm2835.h"
+ #include <dt-bindings/clock/bcm2835-aux.h>
++#include "dt-bindings/power/raspberrypi-power.h"
++#include "dt-bindings/gpio/gpio.h"
+ #include "skeleton.dtsi"
+
+ / {
+@@ -170,6 +173,18 @@
+ status = "disabled";
+ };
+
++ pixelvalve0: pixelvalve@7e206000 {
++ compatible = "brcm,bcm2835-pixelvalve0";
++ reg = <0x7e206000 0x100>;
++ status = "disabled";
++ };
++
++ pixelvalve1: pixelvalve@7e207000 {
++ compatible = "brcm,bcm2835-pixelvalve1";
++ reg = <0x7e207000 0x100>;
++ status = "disabled";
++ };
++
+ pwm: pwm@7e20c000 {
+ compatible = "brcm,bcm2835-pwm";
+ reg = <0x7e20c000 0x28>;
+@@ -227,6 +242,12 @@
+ status = "disabled";
+ };
+
++ hvs: hvs@7e400000 {
++ compatible = "brcm,bcm2835-hvs";
++ reg = <0x7e400000 0x6000>;
++ status = "disabled";
++ };
++
+ i2c1: i2c@7e804000 {
+ compatible = "brcm,bcm2708-i2c";
+ reg = <0x7e804000 0x1000>;
+@@ -261,6 +282,25 @@
+ status = "disabled";
+ };
+
++ pixelvalve2: pixelvalve@7e807000 {
++ compatible = "brcm,bcm2835-pixelvalve2";
++ reg = <0x7e807000 0x100>;
++ status = "disabled";
++ };
++
++ hdmi: hdmi@7e902000 {
++ compatible = "brcm,bcm2835-hdmi";
++ reg = <0x7e902000 0x600>,
++ <0x7e808000 0x100>;
++ ddc = <&i2c2>;
++ hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>;
++ clocks = <&cprman BCM2835_PLLH_PIX>,
++ <&cprman BCM2835_CLOCK_HSM>;
++ clock-names = "pixel", "hdmi";
++ power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
++ status = "disabled";
++ };
++
+ usb: usb@7e980000 {
+ compatible = "brcm,bcm2708-usb";
+ reg = <0x7e980000 0x10000>,
+@@ -269,6 +309,12 @@
+ <1 9>;
+ };
+
++ v3d: v3d@7ec00000 {
++ compatible = "brcm,vc4-v3d";
++ reg = <0x7ec00000 0x1000>;
++ status = "disabled";
++ };
++
+ firmware: firmware {
+ compatible = "raspberrypi,bcm2835-firmware";
+ mboxes = <&mailbox>;
+@@ -303,6 +349,11 @@
+ firmware = <&firmware>;
+ };
+
++ gpu: gpu {
++ compatible = "brcm,bcm2835-vc4";
++ status = "disabled";
++ };
++
+ /* Onboard audio */
+ audio: audio {
+ compatible = "brcm,bcm2835-audio";
+--- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts
++++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts
+@@ -5,129 +5,125 @@
+ /dts-v1/;
+ /plugin/;
+
+-#include "dt-bindings/clock/bcm2835.h"
+-#include "dt-bindings/power/raspberrypi-power.h"
+-#include "dt-bindings/gpio/gpio.h"
+-
+ / {
+ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
+
+ fragment@0 {
++ target-path = "/chosen";
++ __overlay__ {
++ bootargs = "cma=256M@256M";
++ };
++ };
++
++ fragment@1 {
++ target-path = "/chosen";
++ __dormant__ {
++ bootargs = "cma=192M@256M";
++ };
++ };
++
++ fragment@2 {
++ target-path = "/chosen";
++ __dormant__ {
++ bootargs = "cma=128M@128M";
++ };
++ };
++
++ fragment@3 {
++ target-path = "/chosen";
++ __dormant__ {
++ bootargs = "cma=96M@128M";
++ };
++ };
++
++ fragment@4 {
++ target-path = "/chosen";
++ __dormant__ {
++ bootargs = "cma=64M@64M";
++ };
++ };
++
++ fragment@5 {
+ target = <&i2c2>;
+ __overlay__ {
+ status = "okay";
+ };
+ };
+
+- fragment@1 {
++ fragment@6 {
+ target = <&cprman>;
+ __overlay__ {
+ status = "okay";
+ };
+ };
+
+- fragment@2 {
++ fragment@7 {
+ target = <&fb>;
+ __overlay__ {
+ status = "disabled";
+ };
+ };
+
+- fragment@3 {
+- target = <&soc>;
++ fragment@8 {
++ target = <&pixelvalve0>;
+ __overlay__ {
+- #address-cells = <1>;
+- #size-cells = <1>;
++ interrupts = <2 13>; /* pwa0 */
++ status = "okay";
++ };
++ };
+
+- pixelvalve@7e206000 {
+- compatible = "brcm,bcm2835-pixelvalve0";
+- reg = <0x7e206000 0x100>;
+- interrupts = <2 13>; /* pwa0 */
+- };
+-
+- pixelvalve@7e207000 {
+- compatible = "brcm,bcm2835-pixelvalve1";
+- reg = <0x7e207000 0x100>;
+- interrupts = <2 14>; /* pwa1 */
+- };
+-
+- hvs@7e400000 {
+- compatible = "brcm,bcm2835-hvs";
+- reg = <0x7e400000 0x6000>;
+- interrupts = <2 1>;
+- };
+-
+- pixelvalve@7e807000 {
+- compatible = "brcm,bcm2835-pixelvalve2";
+- reg = <0x7e807000 0x100>;
+- interrupts = <2 10>; /* pixelvalve */
+- };
+-
+- hdmi@7e902000 {
+- compatible = "brcm,bcm2835-hdmi";
+- reg = <0x7e902000 0x600>,
+- <0x7e808000 0x100>;
+- interrupts = <2 8>, <2 9>;
+- ddc = <&i2c2>;
+- hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>;
+- clocks = <&cprman BCM2835_PLLH_PIX>,
+- <&cprman BCM2835_CLOCK_HSM>;
+- clock-names = "pixel", "hdmi";
+- power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
+- };
+-
+- v3d@7ec00000 {
+- compatible = "brcm,vc4-v3d";
+- reg = <0x7ec00000 0x1000>;
+- interrupts = <1 10>;
+- };
+-
+- gpu@7e4c0000 {
+- compatible = "brcm,bcm2835-vc4";
+- };
++ fragment@9 {
++ target = <&pixelvalve1>;
++ __overlay__ {
++ interrupts = <2 14>; /* pwa1 */
++ status = "okay";
+ };
+ };
+
+- fragment@4 {
+- target-path = "/chosen";
+- __overlay__ {
+- bootargs = "cma=256M@256M";
++ fragment@10 {
++ target = <&pixelvalve2>;
++ __overlay__ {
++ interrupts = <2 10>; /* pixelvalve */
++ status = "okay";
+ };
+ };
+
+- fragment@5 {
+- target-path = "/chosen";
+- __dormant__ {
+- bootargs = "cma=192M@256M";
++ fragment@11 {
++ target = <&hvs>;
++ __overlay__ {
++ interrupts = <2 1>;
++ status = "okay";
+ };
+ };
+
+- fragment@6 {
+- target-path = "/chosen";
+- __dormant__ {
+- bootargs = "cma=128M@128M";
++ fragment@12 {
++ target = <&hdmi>;
++ __overlay__ {
++ interrupts = <2 8>, <2 9>;
++ status = "okay";
+ };
+ };
+
+- fragment@7 {
+- target-path = "/chosen";
+- __dormant__ {
+- bootargs = "cma=96M@128M";
++ fragment@13 {
++ target = <&v3d>;
++ __overlay__ {
++ interrupts = <1 10>;
++ status = "okay";
+ };
+ };
+
+- fragment@8 {
+- target-path = "/chosen";
+- __dormant__ {
+- bootargs = "cma=64M@64M";
++ fragment@14 {
++ target = <&gpu>;
++ __overlay__ {
++ status = "okay";
+ };
+ };
+
+ __overrides__ {
+- cma-256 = <0>,"+4-5-6-7-8";
+- cma-192 = <0>,"-4+5-6-7-8";
+- cma-128 = <0>,"-4-5+6-7-8";
+- cma-96 = <0>,"-4-5-6+7-8";
+- cma-64 = <0>,"-4-5-6-7+8";
++ cma-256 = <0>,"+0-1-2-3-4";
++ cma-192 = <0>,"-0+1-2-3-4";
++ cma-128 = <0>,"-0-1+2-3-4";
++ cma-96 = <0>,"-0-1-2+3-4";
++ cma-64 = <0>,"-0-1-2-3+4";
+ };
+ };
diff --git a/target/linux/brcm2708/patches-4.4/0330-BCM270X_DT-Set-correct-HDMI-HPD-GPIO-levels-for-vari.patch b/target/linux/brcm2708/patches-4.4/0330-BCM270X_DT-Set-correct-HDMI-HPD-GPIO-levels-for-vari.patch
new file mode 100644
index 0000000000..64a0f6a842
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0330-BCM270X_DT-Set-correct-HDMI-HPD-GPIO-levels-for-vari.patch
@@ -0,0 +1,69 @@
+From 018d3d118011d7022f336f3b0d0db5aef5cbb31d Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Fri, 6 May 2016 12:42:26 -0700
+Subject: [PATCH 330/381] BCM270X_DT: Set correct HDMI HPD GPIO levels for
+ various boards.
+
+The CM is left out, because I haven't found a source for how the CM's
+HPD is connected.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 4 ++++
+ arch/arm/boot/dts/bcm2708-rpi-b.dts | 4 ++++
+ arch/arm/boot/dts/bcm2709-rpi-2-b.dts | 4 ++++
+ arch/arm/boot/dts/bcm2710-rpi-3-b.dts | 4 ++++
+ 4 files changed, 16 insertions(+)
+
+--- a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
++++ b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
+@@ -116,6 +116,10 @@
+ };
+ };
+
++&hdmi {
++ hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
++};
++
+ / {
+ __overrides__ {
+ uart0 = <&uart0>,"status";
+--- a/arch/arm/boot/dts/bcm2708-rpi-b.dts
++++ b/arch/arm/boot/dts/bcm2708-rpi-b.dts
+@@ -110,6 +110,10 @@
+ };
+ };
+
++&hdmi {
++ hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>;
++};
++
+ / {
+ __overrides__ {
+ uart0 = <&uart0>,"status";
+--- a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts
++++ b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts
+@@ -116,6 +116,10 @@
+ };
+ };
+
++&hdmi {
++ hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
++};
++
+ / {
+ __overrides__ {
+ uart0 = <&uart0>,"status";
+--- a/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
++++ b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
+@@ -161,6 +161,10 @@
+ };
+ };
+
++&hdmi {
++ hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
++};
++
+ / {
+ chosen {
+ bootargs = "8250.nr_uarts=1";
diff --git a/target/linux/brcm2708/patches-4.4/0331-Revert-drm-vc4-Force-HDMI-to-connected.patch b/target/linux/brcm2708/patches-4.4/0331-Revert-drm-vc4-Force-HDMI-to-connected.patch
new file mode 100644
index 0000000000..ab6ab62fe1
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0331-Revert-drm-vc4-Force-HDMI-to-connected.patch
@@ -0,0 +1,26 @@
+From 98d4a368d5cfb455ed91cf4dbdef16be4fc25349 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Fri, 6 May 2016 12:43:25 -0700
+Subject: [PATCH 331/381] Revert "drm/vc4: Force HDMI to connected."
+
+Now that we have the HDMI HPD GPIOs correctly identified in the DT, we
+should be able to successfully detect HDMI.
+
+This reverts commit fbec01e2d17b924d91850e17eeecf975e74c9ebf.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_hdmi.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
+@@ -166,8 +166,6 @@ vc4_hdmi_connector_detect(struct drm_con
+ struct drm_device *dev = connector->dev;
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+
+- return connector_status_connected;
+-
+ if (vc4->hdmi->hpd_gpio) {
+ if (gpio_get_value_cansleep(vc4->hdmi->hpd_gpio) ^
+ vc4->hdmi->hpd_active_low)
diff --git a/target/linux/brcm2708/patches-4.4/0332-BCM270X-Include-DRM_PANEL_SIMPLE-in-the-defconfigs.patch b/target/linux/brcm2708/patches-4.4/0332-BCM270X-Include-DRM_PANEL_SIMPLE-in-the-defconfigs.patch
new file mode 100644
index 0000000000..00ec518e30
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0332-BCM270X-Include-DRM_PANEL_SIMPLE-in-the-defconfigs.patch
@@ -0,0 +1,33 @@
+From 57a400e810c8486b4e80392fffb1faedf0cdb447 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Fri, 6 May 2016 12:59:27 -0700
+Subject: [PATCH 332/381] BCM270X: Include DRM_PANEL_SIMPLE in the defconfigs.
+
+This is going to be required for the Adafruit DPI panel support.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ arch/arm/configs/bcm2709_defconfig | 1 +
+ arch/arm/configs/bcmrpi_defconfig | 1 +
+ 2 files changed, 2 insertions(+)
+
+--- a/arch/arm/configs/bcm2709_defconfig
++++ b/arch/arm/configs/bcm2709_defconfig
+@@ -817,6 +817,7 @@ CONFIG_VIDEO_MT9V011=m
+ CONFIG_DRM=m
+ CONFIG_DRM_LOAD_EDID_FIRMWARE=y
+ CONFIG_DRM_UDL=m
++CONFIG_DRM_PANEL_SIMPLE=m
+ CONFIG_DRM_VC4=m
+ CONFIG_FB=y
+ CONFIG_FB_BCM2708=y
+--- a/arch/arm/configs/bcmrpi_defconfig
++++ b/arch/arm/configs/bcmrpi_defconfig
+@@ -809,6 +809,7 @@ CONFIG_VIDEO_MT9V011=m
+ CONFIG_DRM=m
+ CONFIG_DRM_LOAD_EDID_FIRMWARE=y
+ CONFIG_DRM_UDL=m
++CONFIG_DRM_PANEL_SIMPLE=m
+ CONFIG_DRM_VC4=m
+ CONFIG_FB=y
+ CONFIG_FB_BCM2708=y
diff --git a/target/linux/brcm2708/patches-4.4/0333-drm-Add-an-encoder-and-connector-type-enum-for-DPI.patch b/target/linux/brcm2708/patches-4.4/0333-drm-Add-an-encoder-and-connector-type-enum-for-DPI.patch
new file mode 100644
index 0000000000..599bfe7fb9
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0333-drm-Add-an-encoder-and-connector-type-enum-for-DPI.patch
@@ -0,0 +1,64 @@
+From 5022d46f5e7a63c305c1259e806f0ebf2ba5527e Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Fri, 18 Mar 2016 12:34:59 -0700
+Subject: [PATCH 333/381] drm: Add an encoder and connector type enum for DPI.
+
+Right now exynos is exposing DPI as a TMDS encoder and VGA connector,
+which seems rather misleading. This isn't just an internal detail,
+since xrandr actually exposes "VGA" as the output name. Define some
+new enums so that vc4's DPI can have a more informative name.
+
+I considered other names for the connector as well. For VC4, the
+Adafruit DPI kippah takes the 28 GPIO pins and routes them to a
+standard-ish 40-pin FPC connector, but "40-pin FPC" doesn't uniquely
+identify an ordering of pins (apparently some other orderings exist),
+doesn't explain things as well for the user (who, if anything, knows
+their product is a DPI kippah/panel combo), and actually doesn't have
+to exist (one could connect the 28 GPIOs directly to something else).
+Simply "DPI" seems like a good compromise name to distinguish from the
+HDMI, DSI, and TV connectors .
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
+(cherry picked from commit 0b27c02a7f1c697694f2ad6d6517e7dbf9ecfa39)
+---
+ drivers/gpu/drm/drm_crtc.c | 2 ++
+ include/uapi/drm/drm_mode.h | 2 ++
+ 2 files changed, 4 insertions(+)
+
+--- a/drivers/gpu/drm/drm_crtc.c
++++ b/drivers/gpu/drm/drm_crtc.c
+@@ -168,6 +168,7 @@ static struct drm_conn_prop_enum_list dr
+ { DRM_MODE_CONNECTOR_eDP, "eDP" },
+ { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" },
+ { DRM_MODE_CONNECTOR_DSI, "DSI" },
++ { DRM_MODE_CONNECTOR_DPI, "DPI" },
+ };
+
+ static const struct drm_prop_enum_list drm_encoder_enum_list[] = {
+@@ -179,6 +180,7 @@ static const struct drm_prop_enum_list d
+ { DRM_MODE_ENCODER_VIRTUAL, "Virtual" },
+ { DRM_MODE_ENCODER_DSI, "DSI" },
+ { DRM_MODE_ENCODER_DPMST, "DP MST" },
++ { DRM_MODE_ENCODER_DPI, "DPI" },
+ };
+
+ static const struct drm_prop_enum_list drm_subpixel_enum_list[] = {
+--- a/include/uapi/drm/drm_mode.h
++++ b/include/uapi/drm/drm_mode.h
+@@ -202,6 +202,7 @@ struct drm_mode_get_plane_res {
+ #define DRM_MODE_ENCODER_VIRTUAL 5
+ #define DRM_MODE_ENCODER_DSI 6
+ #define DRM_MODE_ENCODER_DPMST 7
++#define DRM_MODE_ENCODER_DPI 8
+
+ struct drm_mode_get_encoder {
+ __u32 encoder_id;
+@@ -241,6 +242,7 @@ struct drm_mode_get_encoder {
+ #define DRM_MODE_CONNECTOR_eDP 14
+ #define DRM_MODE_CONNECTOR_VIRTUAL 15
+ #define DRM_MODE_CONNECTOR_DSI 16
++#define DRM_MODE_CONNECTOR_DPI 17
+
+ struct drm_mode_get_connector {
+
diff --git a/target/linux/brcm2708/patches-4.4/0334-dt-bindings-Add-binding-docs-for-V3D.patch b/target/linux/brcm2708/patches-4.4/0334-dt-bindings-Add-binding-docs-for-V3D.patch
new file mode 100644
index 0000000000..2725626792
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0334-dt-bindings-Add-binding-docs-for-V3D.patch
@@ -0,0 +1,42 @@
+From 7f900beff9a3733ab171272212cb9e28e6b0629b Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Fri, 4 Mar 2016 12:32:06 -0800
+Subject: [PATCH 334/381] dt-bindings: Add binding docs for V3D.
+
+This was missed in the upstreaming process.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Acked-by: Stephen Warren <swarren@wwwdotorg.org>
+(cherry picked from commit 4653f22e9ab08b2b7178b7262a9326eb777e0266)
+---
+ Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt
++++ b/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt
+@@ -35,6 +35,12 @@ Optional properties for HDMI:
+ as an interrupt/status bit in the HDMI controller
+ itself). See bindings/pinctrl/brcm,bcm2835-gpio.txt
+
++Required properties for V3D:
++- compatible: Should be "brcm,bcm2835-v3d"
++- reg: Physical base address and length of the V3D's registers
++- interrupts: The interrupt number
++ See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt
++
+ Example:
+ pixelvalve@7e807000 {
+ compatible = "brcm,bcm2835-pixelvalve2";
+@@ -60,6 +66,12 @@ hdmi: hdmi@7e902000 {
+ clock-names = "pixel", "hdmi";
+ };
+
++v3d: v3d@7ec00000 {
++ compatible = "brcm,bcm2835-v3d";
++ reg = <0x7ec00000 0x1000>;
++ interrupts = <1 10>;
++};
++
+ vc4: gpu {
+ compatible = "brcm,bcm2835-vc4";
+ };
diff --git a/target/linux/brcm2708/patches-4.4/0335-drm-vc4-Add-DPI-driver.patch b/target/linux/brcm2708/patches-4.4/0335-drm-vc4-Add-DPI-driver.patch
new file mode 100644
index 0000000000..3b37fcf2a5
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0335-drm-vc4-Add-DPI-driver.patch
@@ -0,0 +1,673 @@
+From f12e336d29983c2f56da38810600b6f57cc62371 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Wed, 10 Feb 2016 11:42:32 -0800
+Subject: [PATCH 335/381] drm/vc4: Add DPI driver
+
+The DPI interface involves taking a ton of our GPIOs to be used as
+outputs, and routing display signals over them in parallel.
+
+v2: Use display_info.bus_formats[] to replace our custom DT
+ properties.
+v3: Rebase on V3D documentation changes.
+v4: Fix rebase detritus from V3D documentation changes.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Acked-by: Rob Herring <robh@kernel.org>
+(cherry picked from commit 08302c35b59d306ff37b996e56fb2a488c1d2c2e)
+---
+ .../devicetree/bindings/display/brcm,bcm-vc4.txt | 36 ++
+ drivers/gpu/drm/vc4/Kconfig | 1 +
+ drivers/gpu/drm/vc4/Makefile | 1 +
+ drivers/gpu/drm/vc4/vc4_debugfs.c | 1 +
+ drivers/gpu/drm/vc4/vc4_dpi.c | 520 +++++++++++++++++++++
+ drivers/gpu/drm/vc4/vc4_drv.c | 1 +
+ drivers/gpu/drm/vc4/vc4_drv.h | 5 +
+ 7 files changed, 565 insertions(+)
+ create mode 100644 drivers/gpu/drm/vc4/vc4_dpi.c
+
+--- a/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt
++++ b/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt
+@@ -35,12 +35,22 @@ Optional properties for HDMI:
+ as an interrupt/status bit in the HDMI controller
+ itself). See bindings/pinctrl/brcm,bcm2835-gpio.txt
+
++Required properties for DPI:
++- compatible: Should be "brcm,bcm2835-dpi"
++- reg: Physical base address and length of the registers
++- clocks: a) core: The core clock the unit runs on
++ b) pixel: The pixel clock that feeds the pixelvalve
++- port: Port node with a single endpoint connecting to the panel
++ device, as defined in [1]
++
+ Required properties for V3D:
+ - compatible: Should be "brcm,bcm2835-v3d"
+ - reg: Physical base address and length of the V3D's registers
+ - interrupts: The interrupt number
+ See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt
+
++[1] Documentation/devicetree/bindings/media/video-interfaces.txt
++
+ Example:
+ pixelvalve@7e807000 {
+ compatible = "brcm,bcm2835-pixelvalve2";
+@@ -66,6 +76,22 @@ hdmi: hdmi@7e902000 {
+ clock-names = "pixel", "hdmi";
+ };
+
++dpi: dpi@7e208000 {
++ compatible = "brcm,bcm2835-dpi";
++ reg = <0x7e208000 0x8c>;
++ clocks = <&clocks BCM2835_CLOCK_VPU>,
++ <&clocks BCM2835_CLOCK_DPI>;
++ clock-names = "core", "pixel";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port {
++ dpi_out: endpoint@0 {
++ remote-endpoint = <&panel_in>;
++ };
++ };
++};
++
+ v3d: v3d@7ec00000 {
+ compatible = "brcm,bcm2835-v3d";
+ reg = <0x7ec00000 0x1000>;
+@@ -75,3 +101,13 @@ v3d: v3d@7ec00000 {
+ vc4: gpu {
+ compatible = "brcm,bcm2835-vc4";
+ };
++
++panel: panel {
++ compatible = "ontat,yx700wv03", "simple-panel";
++
++ port {
++ panel_in: endpoint {
++ remote-endpoint = <&dpi_out>;
++ };
++ };
++};
+--- a/drivers/gpu/drm/vc4/Kconfig
++++ b/drivers/gpu/drm/vc4/Kconfig
+@@ -5,6 +5,7 @@ config DRM_VC4
+ select DRM_KMS_HELPER
+ select DRM_KMS_CMA_HELPER
+ select DRM_GEM_CMA_HELPER
++ select DRM_PANEL
+ help
+ Choose this option if you have a system that has a Broadcom
+ VC4 GPU, such as the Raspberry Pi or other BCM2708/BCM2835.
+--- a/drivers/gpu/drm/vc4/Makefile
++++ b/drivers/gpu/drm/vc4/Makefile
+@@ -7,6 +7,7 @@ vc4-y := \
+ vc4_bo.o \
+ vc4_crtc.o \
+ vc4_drv.o \
++ vc4_dpi.o \
+ vc4_kms.o \
+ vc4_gem.o \
+ vc4_hdmi.o \
+--- a/drivers/gpu/drm/vc4/vc4_debugfs.c
++++ b/drivers/gpu/drm/vc4/vc4_debugfs.c
+@@ -17,6 +17,7 @@
+
+ static const struct drm_info_list vc4_debugfs_list[] = {
+ {"bo_stats", vc4_bo_stats_debugfs, 0},
++ {"dpi_regs", vc4_dpi_debugfs_regs, 0},
+ {"gem_exec", vc4_gem_exec_debugfs, 0},
+ {"hdmi_regs", vc4_hdmi_debugfs_regs, 0},
+ {"hvs_regs", vc4_hvs_debugfs_regs, 0},
+--- /dev/null
++++ b/drivers/gpu/drm/vc4/vc4_dpi.c
+@@ -0,0 +1,520 @@
++/*
++ * Copyright (C) 2016 Broadcom Limited
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published by
++ * the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++/**
++ * DOC: VC4 DPI module
++ *
++ * The VC4 DPI hardware supports MIPI DPI type 4 and Nokia ViSSI
++ * signals, which are routed out to GPIO0-27 with the ALT2 function.
++ */
++
++#include "drm_atomic_helper.h"
++#include "drm_crtc_helper.h"
++#include "drm_edid.h"
++#include "drm_panel.h"
++#include "linux/clk.h"
++#include "linux/component.h"
++#include "linux/of_graph.h"
++#include "linux/of_platform.h"
++#include "vc4_drv.h"
++#include "vc4_regs.h"
++
++#define DPI_C 0x00
++# define DPI_OUTPUT_ENABLE_MODE BIT(16)
++
++/* The order field takes the incoming 24 bit RGB from the pixel valve
++ * and shuffles the 3 channels.
++ */
++# define DPI_ORDER_MASK VC4_MASK(15, 14)
++# define DPI_ORDER_SHIFT 14
++# define DPI_ORDER_RGB 0
++# define DPI_ORDER_BGR 1
++# define DPI_ORDER_GRB 2
++# define DPI_ORDER_BRG 3
++
++/* The format field takes the ORDER-shuffled pixel valve data and
++ * formats it onto the output lines.
++ */
++# define DPI_FORMAT_MASK VC4_MASK(13, 11)
++# define DPI_FORMAT_SHIFT 11
++/* This define is named in the hardware, but actually just outputs 0. */
++# define DPI_FORMAT_9BIT_666_RGB 0
++/* Outputs 00000000rrrrrggggggbbbbb */
++# define DPI_FORMAT_16BIT_565_RGB_1 1
++/* Outputs 000rrrrr00gggggg000bbbbb */
++# define DPI_FORMAT_16BIT_565_RGB_2 2
++/* Outputs 00rrrrr000gggggg00bbbbb0 */
++# define DPI_FORMAT_16BIT_565_RGB_3 3
++/* Outputs 000000rrrrrrggggggbbbbbb */
++# define DPI_FORMAT_18BIT_666_RGB_1 4
++/* Outputs 00rrrrrr00gggggg00bbbbbb */
++# define DPI_FORMAT_18BIT_666_RGB_2 5
++/* Outputs rrrrrrrrggggggggbbbbbbbb */
++# define DPI_FORMAT_24BIT_888_RGB 6
++
++/* Reverses the polarity of the corresponding signal */
++# define DPI_PIXEL_CLK_INVERT BIT(10)
++# define DPI_HSYNC_INVERT BIT(9)
++# define DPI_VSYNC_INVERT BIT(8)
++# define DPI_OUTPUT_ENABLE_INVERT BIT(7)
++
++/* Outputs the signal the falling clock edge instead of rising. */
++# define DPI_HSYNC_NEGATE BIT(6)
++# define DPI_VSYNC_NEGATE BIT(5)
++# define DPI_OUTPUT_ENABLE_NEGATE BIT(4)
++
++/* Disables the signal */
++# define DPI_HSYNC_DISABLE BIT(3)
++# define DPI_VSYNC_DISABLE BIT(2)
++# define DPI_OUTPUT_ENABLE_DISABLE BIT(1)
++
++/* Power gate to the device, full reset at 0 -> 1 transition */
++# define DPI_ENABLE BIT(0)
++
++/* All other registers besides DPI_C return the ID */
++#define DPI_ID 0x04
++# define DPI_ID_VALUE 0x00647069
++
++/* General DPI hardware state. */
++struct vc4_dpi {
++ struct platform_device *pdev;
++
++ struct drm_encoder *encoder;
++ struct drm_connector *connector;
++ struct drm_panel *panel;
++
++ void __iomem *regs;
++
++ struct clk *pixel_clock;
++ struct clk *core_clock;
++};
++
++#define DPI_READ(offset) readl(dpi->regs + (offset))
++#define DPI_WRITE(offset, val) writel(val, dpi->regs + (offset))
++
++/* VC4 DPI encoder KMS struct */
++struct vc4_dpi_encoder {
++ struct vc4_encoder base;
++ struct vc4_dpi *dpi;
++};
++
++static inline struct vc4_dpi_encoder *
++to_vc4_dpi_encoder(struct drm_encoder *encoder)
++{
++ return container_of(encoder, struct vc4_dpi_encoder, base.base);
++}
++
++/* VC4 DPI connector KMS struct */
++struct vc4_dpi_connector {
++ struct drm_connector base;
++ struct vc4_dpi *dpi;
++
++ /* Since the connector is attached to just the one encoder,
++ * this is the reference to it so we can do the best_encoder()
++ * hook.
++ */
++ struct drm_encoder *encoder;
++};
++
++static inline struct vc4_dpi_connector *
++to_vc4_dpi_connector(struct drm_connector *connector)
++{
++ return container_of(connector, struct vc4_dpi_connector, base);
++}
++
++#define DPI_REG(reg) { reg, #reg }
++static const struct {
++ u32 reg;
++ const char *name;
++} dpi_regs[] = {
++ DPI_REG(DPI_C),
++ DPI_REG(DPI_ID),
++};
++
++static void vc4_dpi_dump_regs(struct vc4_dpi *dpi)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(dpi_regs); i++) {
++ DRM_INFO("0x%04x (%s): 0x%08x\n",
++ dpi_regs[i].reg, dpi_regs[i].name,
++ DPI_READ(dpi_regs[i].reg));
++ }
++}
++
++#ifdef CONFIG_DEBUG_FS
++int vc4_dpi_debugfs_regs(struct seq_file *m, void *unused)
++{
++ struct drm_info_node *node = (struct drm_info_node *)m->private;
++ struct drm_device *dev = node->minor->dev;
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ struct vc4_dpi *dpi = vc4->dpi;
++ int i;
++
++ if (!dpi)
++ return 0;
++
++ for (i = 0; i < ARRAY_SIZE(dpi_regs); i++) {
++ seq_printf(m, "%s (0x%04x): 0x%08x\n",
++ dpi_regs[i].name, dpi_regs[i].reg,
++ DPI_READ(dpi_regs[i].reg));
++ }
++
++ return 0;
++}
++#endif
++
++static enum drm_connector_status
++vc4_dpi_connector_detect(struct drm_connector *connector, bool force)
++{
++ struct vc4_dpi_connector *vc4_connector =
++ to_vc4_dpi_connector(connector);
++ struct vc4_dpi *dpi = vc4_connector->dpi;
++
++ if (dpi->panel)
++ return connector_status_connected;
++ else
++ return connector_status_disconnected;
++}
++
++static void vc4_dpi_connector_destroy(struct drm_connector *connector)
++{
++ drm_connector_unregister(connector);
++ drm_connector_cleanup(connector);
++}
++
++static int vc4_dpi_connector_get_modes(struct drm_connector *connector)
++{
++ struct vc4_dpi_connector *vc4_connector =
++ to_vc4_dpi_connector(connector);
++ struct vc4_dpi *dpi = vc4_connector->dpi;
++
++ if (dpi->panel)
++ return drm_panel_get_modes(dpi->panel);
++
++ return 0;
++}
++
++static struct drm_encoder *
++vc4_dpi_connector_best_encoder(struct drm_connector *connector)
++{
++ struct vc4_dpi_connector *dpi_connector =
++ to_vc4_dpi_connector(connector);
++ return dpi_connector->encoder;
++}
++
++static const struct drm_connector_funcs vc4_dpi_connector_funcs = {
++ .dpms = drm_atomic_helper_connector_dpms,
++ .detect = vc4_dpi_connector_detect,
++ .fill_modes = drm_helper_probe_single_connector_modes,
++ .destroy = vc4_dpi_connector_destroy,
++ .reset = drm_atomic_helper_connector_reset,
++ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
++ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
++};
++
++static const struct drm_connector_helper_funcs vc4_dpi_connector_helper_funcs = {
++ .get_modes = vc4_dpi_connector_get_modes,
++ .best_encoder = vc4_dpi_connector_best_encoder,
++};
++
++static struct drm_connector *vc4_dpi_connector_init(struct drm_device *dev,
++ struct vc4_dpi *dpi)
++{
++ struct drm_connector *connector = NULL;
++ struct vc4_dpi_connector *dpi_connector;
++ int ret = 0;
++
++ dpi_connector = devm_kzalloc(dev->dev, sizeof(*dpi_connector),
++ GFP_KERNEL);
++ if (!dpi_connector) {
++ ret = -ENOMEM;
++ goto fail;
++ }
++ connector = &dpi_connector->base;
++
++ dpi_connector->encoder = dpi->encoder;
++ dpi_connector->dpi = dpi;
++
++ drm_connector_init(dev, connector, &vc4_dpi_connector_funcs,
++ DRM_MODE_CONNECTOR_DPI);
++ drm_connector_helper_add(connector, &vc4_dpi_connector_helper_funcs);
++
++ connector->polled = 0;
++ connector->interlace_allowed = 0;
++ connector->doublescan_allowed = 0;
++
++ drm_mode_connector_attach_encoder(connector, dpi->encoder);
++
++ return connector;
++
++ fail:
++ if (connector)
++ vc4_dpi_connector_destroy(connector);
++
++ return ERR_PTR(ret);
++}
++
++static const struct drm_encoder_funcs vc4_dpi_encoder_funcs = {
++ .destroy = drm_encoder_cleanup,
++};
++
++static void vc4_dpi_encoder_disable(struct drm_encoder *encoder)
++{
++ struct vc4_dpi_encoder *vc4_encoder = to_vc4_dpi_encoder(encoder);
++ struct vc4_dpi *dpi = vc4_encoder->dpi;
++
++ drm_panel_disable(dpi->panel);
++
++ clk_disable_unprepare(dpi->pixel_clock);
++
++ drm_panel_unprepare(dpi->panel);
++}
++
++static void vc4_dpi_encoder_enable(struct drm_encoder *encoder)
++{
++ struct drm_display_mode *mode = &encoder->crtc->mode;
++ struct vc4_dpi_encoder *vc4_encoder = to_vc4_dpi_encoder(encoder);
++ struct vc4_dpi *dpi = vc4_encoder->dpi;
++ u32 dpi_c = DPI_ENABLE | DPI_OUTPUT_ENABLE_MODE;
++ int ret;
++
++ ret = drm_panel_prepare(dpi->panel);
++ if (ret) {
++ DRM_ERROR("Panel failed to prepare\n");
++ return;
++ }
++
++ if (dpi->connector->display_info.num_bus_formats) {
++ u32 bus_format = dpi->connector->display_info.bus_formats[0];
++
++ switch (bus_format) {
++ case MEDIA_BUS_FMT_RGB888_1X24:
++ dpi_c |= VC4_SET_FIELD(DPI_FORMAT_24BIT_888_RGB,
++ DPI_FORMAT);
++ break;
++ case MEDIA_BUS_FMT_BGR888_1X24:
++ dpi_c |= VC4_SET_FIELD(DPI_FORMAT_24BIT_888_RGB,
++ DPI_FORMAT);
++ dpi_c |= VC4_SET_FIELD(DPI_ORDER_BGR, DPI_ORDER);
++ break;
++ case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
++ dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_2,
++ DPI_FORMAT);
++ break;
++ case MEDIA_BUS_FMT_RGB666_1X18:
++ dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_1,
++ DPI_FORMAT);
++ break;
++ case MEDIA_BUS_FMT_RGB565_1X16:
++ dpi_c |= VC4_SET_FIELD(DPI_FORMAT_16BIT_565_RGB_3,
++ DPI_FORMAT);
++ break;
++ default:
++ DRM_ERROR("Unknown media bus format %d\n", bus_format);
++ break;
++ }
++ }
++
++ if (mode->flags & DRM_MODE_FLAG_NHSYNC)
++ dpi_c |= DPI_HSYNC_INVERT;
++ else if (!(mode->flags & DRM_MODE_FLAG_PHSYNC))
++ dpi_c |= DPI_HSYNC_DISABLE;
++
++ if (mode->flags & DRM_MODE_FLAG_NVSYNC)
++ dpi_c |= DPI_VSYNC_INVERT;
++ else if (!(mode->flags & DRM_MODE_FLAG_PVSYNC))
++ dpi_c |= DPI_VSYNC_DISABLE;
++
++ DPI_WRITE(DPI_C, dpi_c);
++
++ ret = clk_set_rate(dpi->pixel_clock, mode->clock * 1000);
++ if (ret)
++ DRM_ERROR("Failed to set clock rate: %d\n", ret);
++
++ ret = clk_prepare_enable(dpi->pixel_clock);
++ if (ret)
++ DRM_ERROR("Failed to set clock rate: %d\n", ret);
++
++ ret = drm_panel_enable(dpi->panel);
++ if (ret) {
++ DRM_ERROR("Panel failed to enable\n");
++ drm_panel_unprepare(dpi->panel);
++ return;
++ }
++}
++
++static const struct drm_encoder_helper_funcs vc4_dpi_encoder_helper_funcs = {
++ .disable = vc4_dpi_encoder_disable,
++ .enable = vc4_dpi_encoder_enable,
++};
++
++static const struct of_device_id vc4_dpi_dt_match[] = {
++ { .compatible = "brcm,bcm2835-dpi", .data = NULL },
++ {}
++};
++
++/* Walks the OF graph to find the panel node and then asks DRM to look
++ * up the panel.
++ */
++static struct drm_panel *vc4_dpi_get_panel(struct device *dev)
++{
++ struct device_node *endpoint, *panel_node;
++ struct device_node *np = dev->of_node;
++ struct drm_panel *panel;
++
++ endpoint = of_graph_get_next_endpoint(np, NULL);
++ if (!endpoint) {
++ dev_err(dev, "no endpoint to fetch DPI panel\n");
++ return NULL;
++ }
++
++ /* don't proceed if we have an endpoint but no panel_node tied to it */
++ panel_node = of_graph_get_remote_port_parent(endpoint);
++ of_node_put(endpoint);
++ if (!panel_node) {
++ dev_err(dev, "no valid panel node\n");
++ return NULL;
++ }
++
++ panel = of_drm_find_panel(panel_node);
++ of_node_put(panel_node);
++
++ return panel;
++}
++
++static int vc4_dpi_bind(struct device *dev, struct device *master, void *data)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ struct drm_device *drm = dev_get_drvdata(master);
++ struct vc4_dev *vc4 = to_vc4_dev(drm);
++ struct vc4_dpi *dpi;
++ struct vc4_dpi_encoder *vc4_dpi_encoder;
++ int ret;
++
++ dpi = devm_kzalloc(dev, sizeof(*dpi), GFP_KERNEL);
++ if (!dpi)
++ return -ENOMEM;
++
++ vc4_dpi_encoder = devm_kzalloc(dev, sizeof(*vc4_dpi_encoder),
++ GFP_KERNEL);
++ if (!vc4_dpi_encoder)
++ return -ENOMEM;
++ vc4_dpi_encoder->base.type = VC4_ENCODER_TYPE_DPI;
++ vc4_dpi_encoder->dpi = dpi;
++ dpi->encoder = &vc4_dpi_encoder->base.base;
++
++ dpi->pdev = pdev;
++ dpi->regs = vc4_ioremap_regs(pdev, 0);
++ if (IS_ERR(dpi->regs))
++ return PTR_ERR(dpi->regs);
++
++ vc4_dpi_dump_regs(dpi);
++
++ if (DPI_READ(DPI_ID) != DPI_ID_VALUE) {
++ dev_err(dev, "Port returned 0x%08x for ID instead of 0x%08x\n",
++ DPI_READ(DPI_ID), DPI_ID_VALUE);
++ return -ENODEV;
++ }
++
++ dpi->core_clock = devm_clk_get(dev, "core");
++ if (IS_ERR(dpi->core_clock)) {
++ ret = PTR_ERR(dpi->core_clock);
++ if (ret != -EPROBE_DEFER)
++ DRM_ERROR("Failed to get core clock: %d\n", ret);
++ return ret;
++ }
++ dpi->pixel_clock = devm_clk_get(dev, "pixel");
++ if (IS_ERR(dpi->pixel_clock)) {
++ ret = PTR_ERR(dpi->pixel_clock);
++ if (ret != -EPROBE_DEFER)
++ DRM_ERROR("Failed to get pixel clock: %d\n", ret);
++ return ret;
++ }
++
++ ret = clk_prepare_enable(dpi->core_clock);
++ if (ret)
++ DRM_ERROR("Failed to turn on core clock: %d\n", ret);
++
++ dpi->panel = vc4_dpi_get_panel(dev);
++
++ drm_encoder_init(drm, dpi->encoder, &vc4_dpi_encoder_funcs,
++ DRM_MODE_ENCODER_DPI);
++ drm_encoder_helper_add(dpi->encoder, &vc4_dpi_encoder_helper_funcs);
++
++ dpi->connector = vc4_dpi_connector_init(drm, dpi);
++ if (IS_ERR(dpi->connector)) {
++ ret = PTR_ERR(dpi->connector);
++ goto err_destroy_encoder;
++ }
++
++ if (dpi->panel)
++ drm_panel_attach(dpi->panel, dpi->connector);
++
++ dev_set_drvdata(dev, dpi);
++
++ vc4->dpi = dpi;
++
++ return 0;
++
++err_destroy_encoder:
++ drm_encoder_cleanup(dpi->encoder);
++ clk_disable_unprepare(dpi->core_clock);
++ return ret;
++}
++
++static void vc4_dpi_unbind(struct device *dev, struct device *master,
++ void *data)
++{
++ struct drm_device *drm = dev_get_drvdata(master);
++ struct vc4_dev *vc4 = to_vc4_dev(drm);
++ struct vc4_dpi *dpi = dev_get_drvdata(dev);
++
++ if (dpi->panel)
++ drm_panel_detach(dpi->panel);
++
++ vc4_dpi_connector_destroy(dpi->connector);
++ drm_encoder_cleanup(dpi->encoder);
++
++ clk_disable_unprepare(dpi->core_clock);
++
++ vc4->dpi = NULL;
++}
++
++static const struct component_ops vc4_dpi_ops = {
++ .bind = vc4_dpi_bind,
++ .unbind = vc4_dpi_unbind,
++};
++
++static int vc4_dpi_dev_probe(struct platform_device *pdev)
++{
++ return component_add(&pdev->dev, &vc4_dpi_ops);
++}
++
++static int vc4_dpi_dev_remove(struct platform_device *pdev)
++{
++ component_del(&pdev->dev, &vc4_dpi_ops);
++ return 0;
++}
++
++struct platform_driver vc4_dpi_driver = {
++ .probe = vc4_dpi_dev_probe,
++ .remove = vc4_dpi_dev_remove,
++ .driver = {
++ .name = "vc4_dpi",
++ .of_match_table = vc4_dpi_dt_match,
++ },
++};
+--- a/drivers/gpu/drm/vc4/vc4_drv.c
++++ b/drivers/gpu/drm/vc4/vc4_drv.c
+@@ -259,6 +259,7 @@ static const struct component_master_ops
+
+ static struct platform_driver *const component_drivers[] = {
+ &vc4_hdmi_driver,
++ &vc4_dpi_driver,
+ &vc4_crtc_driver,
+ &vc4_hvs_driver,
+ &vc4_v3d_driver,
+--- a/drivers/gpu/drm/vc4/vc4_drv.h
++++ b/drivers/gpu/drm/vc4/vc4_drv.h
+@@ -16,6 +16,7 @@ struct vc4_dev {
+ struct vc4_hvs *hvs;
+ struct vc4_crtc *crtc[3];
+ struct vc4_v3d *v3d;
++ struct vc4_dpi *dpi;
+
+ struct drm_fbdev_cma *fbdev;
+ struct rpi_firmware *firmware;
+@@ -418,6 +419,10 @@ void vc4_debugfs_cleanup(struct drm_mino
+ /* vc4_drv.c */
+ void __iomem *vc4_ioremap_regs(struct platform_device *dev, int index);
+
++/* vc4_dpi.c */
++extern struct platform_driver vc4_dpi_driver;
++int vc4_dpi_debugfs_regs(struct seq_file *m, void *unused);
++
+ /* vc4_gem.c */
+ void vc4_gem_init(struct drm_device *dev);
+ void vc4_gem_destroy(struct drm_device *dev);
diff --git a/target/linux/brcm2708/patches-4.4/0336-drm-vc4-Fix-NULL-deref-in-HDMI-init-error-path.patch b/target/linux/brcm2708/patches-4.4/0336-drm-vc4-Fix-NULL-deref-in-HDMI-init-error-path.patch
new file mode 100644
index 0000000000..4a83889ff1
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0336-drm-vc4-Fix-NULL-deref-in-HDMI-init-error-path.patch
@@ -0,0 +1,25 @@
+From 00dc0773c1af03a24f76c53223ab0c3d1fc7debb Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 4 Apr 2016 14:25:59 -0700
+Subject: [PATCH 336/381] drm/vc4: Fix NULL deref in HDMI init error path
+
+If you make it here other than through err_destroy_encoder, vc4->hdmi
+is still NULL.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+(cherry picked from commit 5883980313af70aec0ceebaef6ef0709726e5e63)
+---
+ drivers/gpu/drm/vc4/vc4_hdmi.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
+@@ -573,7 +573,7 @@ err_unprepare_hsm:
+ err_unprepare_pix:
+ clk_disable_unprepare(hdmi->pixel_clock);
+ err_put_i2c:
+- put_device(&vc4->hdmi->ddc->dev);
++ put_device(&hdmi->ddc->dev);
+
+ return ret;
+ }
diff --git a/target/linux/brcm2708/patches-4.4/0337-drm-vc4-Kick-out-the-simplefb-framebuffer-before-we-.patch b/target/linux/brcm2708/patches-4.4/0337-drm-vc4-Kick-out-the-simplefb-framebuffer-before-we-.patch
new file mode 100644
index 0000000000..6e4080dd12
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0337-drm-vc4-Kick-out-the-simplefb-framebuffer-before-we-.patch
@@ -0,0 +1,53 @@
+From b7f009c01e2e55df7286a7de67f41846dc2536a6 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Tue, 19 Apr 2016 13:24:14 -0700
+Subject: [PATCH 337/381] drm/vc4: Kick out the simplefb framebuffer before we
+ set up KMS.
+
+If we don't, then simplefb stays loaded on /dev/fb0 even though
+scanout isn't happening from simplefb's memory area any more, and you
+end up with no console.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Acked-by: Dave Airlie <airlied@redhat.com>
+(cherry picked from commit b3a15f6d55fb584dd4d8baac5d1b6a398720620c)
+---
+ drivers/gpu/drm/vc4/vc4_drv.c | 20 ++++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_drv.c
++++ b/drivers/gpu/drm/vc4/vc4_drv.c
+@@ -164,6 +164,24 @@ static void vc4_match_add_drivers(struct
+ }
+ }
+
++static void vc4_kick_out_firmware_fb(void)
++{
++ struct apertures_struct *ap;
++
++ ap = alloc_apertures(1);
++ if (!ap)
++ return;
++
++ /* Since VC4 is a UMA device, the simplefb node may have been
++ * located anywhere in memory.
++ */
++ ap->ranges[0].base = 0;
++ ap->ranges[0].size = ~0;
++
++ remove_conflicting_framebuffers(ap, "vc4drmfb", false);
++ kfree(ap);
++}
++
+ static int vc4_drm_bind(struct device *dev)
+ {
+ struct platform_device *pdev = to_platform_device(dev);
+@@ -208,6 +226,8 @@ static int vc4_drm_bind(struct device *d
+ if (ret)
+ goto gem_destroy;
+
++ vc4_kick_out_firmware_fb();
++
+ ret = drm_dev_register(drm, 0);
+ if (ret < 0)
+ goto unbind_all;
diff --git a/target/linux/brcm2708/patches-4.4/0338-drm-vc4-Rename-async-to-nonblock.patch b/target/linux/brcm2708/patches-4.4/0338-drm-vc4-Rename-async-to-nonblock.patch
new file mode 100644
index 0000000000..aab21bdd32
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0338-drm-vc4-Rename-async-to-nonblock.patch
@@ -0,0 +1,45 @@
+From cc94958e3c07a50d65b45ea654fa498ef4d4b493 Mon Sep 17 00:00:00 2001
+From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
+Date: Tue, 26 Apr 2016 16:11:44 +0200
+Subject: [PATCH 338/381] drm/vc4: Rename async to nonblock.
+
+The async name is deprecated and should be changed to nonblocking.
+
+Cc: Eric Anholt <eric@anholt.net>
+Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
+Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
+Link: http://patchwork.freedesktop.org/patch/msgid/1461679905-30177-12-git-send-email-maarten.lankhorst@linux.intel.com
+(cherry picked from commit eb63961ba52ba545f5b7ebeeeefe1c98704e1a79)
+---
+ drivers/gpu/drm/vc4/vc4_kms.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_kms.c
+@@ -93,7 +93,7 @@ static struct vc4_commit *commit_init(st
+ * vc4_atomic_commit - commit validated state object
+ * @dev: DRM device
+ * @state: the driver state object
+- * @async: asynchronous commit
++ * @nonblock: nonblocking commit
+ *
+ * This function commits a with drm_atomic_helper_check() pre-validated state
+ * object. This can still fail when e.g. the framebuffer reservation fails. For
+@@ -104,7 +104,7 @@ static struct vc4_commit *commit_init(st
+ */
+ static int vc4_atomic_commit(struct drm_device *dev,
+ struct drm_atomic_state *state,
+- bool async)
++ bool nonblock)
+ {
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ int ret;
+@@ -170,7 +170,7 @@ static int vc4_atomic_commit(struct drm_
+ * current layout.
+ */
+
+- if (async) {
++ if (nonblock) {
+ vc4_queue_seqno_cb(dev, &c->cb, wait_seqno,
+ vc4_atomic_complete_commit_seqno_cb);
+ } else {
diff --git a/target/linux/brcm2708/patches-4.4/0339-drm-vc4-Add-support-for-gamma-ramps.patch b/target/linux/brcm2708/patches-4.4/0339-drm-vc4-Add-support-for-gamma-ramps.patch
new file mode 100644
index 0000000000..af9effe82e
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0339-drm-vc4-Add-support-for-gamma-ramps.patch
@@ -0,0 +1,137 @@
+From 6d1609ef815189095a8e44feb38e2c128c3736a5 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Thu, 31 Mar 2016 18:38:20 -0700
+Subject: [PATCH 339/381] drm/vc4: Add support for gamma ramps.
+
+We could possibly save a bit of power by not requesting gamma
+conversion when the ramp happens to be 1:1, but at least if all the
+CRTCs are off the SRAM will be disabled.
+
+This should fix brightness sliders in a lot of fullscreen games.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+(cherry picked from commit e582b6c7e7f9d0b1e30e8017e4082d3a9ede3310)
+---
+ drivers/gpu/drm/vc4/vc4_crtc.c | 58 ++++++++++++++++++++++++++++++++++++++++++
+ drivers/gpu/drm/vc4/vc4_regs.h | 6 +++++
+ 2 files changed, 64 insertions(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_crtc.c
++++ b/drivers/gpu/drm/vc4/vc4_crtc.c
+@@ -49,6 +49,10 @@ struct vc4_crtc {
+ /* Which HVS channel we're using for our CRTC. */
+ int channel;
+
++ u8 lut_r[256];
++ u8 lut_g[256];
++ u8 lut_b[256];
++
+ struct drm_pending_vblank_event *event;
+ };
+
+@@ -147,6 +151,46 @@ static void vc4_crtc_destroy(struct drm_
+ drm_crtc_cleanup(crtc);
+ }
+
++static void
++vc4_crtc_lut_load(struct drm_crtc *crtc)
++{
++ struct drm_device *dev = crtc->dev;
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
++ u32 i;
++
++ /* The LUT memory is laid out with each HVS channel in order,
++ * each of which takes 256 writes for R, 256 for G, then 256
++ * for B.
++ */
++ HVS_WRITE(SCALER_GAMADDR,
++ SCALER_GAMADDR_AUTOINC |
++ (vc4_crtc->channel * 3 * crtc->gamma_size));
++
++ for (i = 0; i < crtc->gamma_size; i++)
++ HVS_WRITE(SCALER_GAMDATA, vc4_crtc->lut_r[i]);
++ for (i = 0; i < crtc->gamma_size; i++)
++ HVS_WRITE(SCALER_GAMDATA, vc4_crtc->lut_g[i]);
++ for (i = 0; i < crtc->gamma_size; i++)
++ HVS_WRITE(SCALER_GAMDATA, vc4_crtc->lut_b[i]);
++}
++
++static void
++vc4_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
++ uint32_t start, uint32_t size)
++{
++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
++ u32 i;
++
++ for (i = start; i < start + size; i++) {
++ vc4_crtc->lut_r[i] = r[i] >> 8;
++ vc4_crtc->lut_g[i] = g[i] >> 8;
++ vc4_crtc->lut_b[i] = b[i] >> 8;
++ }
++
++ vc4_crtc_lut_load(crtc);
++}
++
+ static u32 vc4_get_fifo_full_level(u32 format)
+ {
+ static const u32 fifo_len_bytes = 64;
+@@ -260,8 +304,14 @@ static void vc4_crtc_mode_set_nofb(struc
+
+ HVS_WRITE(SCALER_DISPBKGNDX(vc4_crtc->channel),
+ SCALER_DISPBKGND_AUTOHS |
++ SCALER_DISPBKGND_GAMMA |
+ (interlace ? SCALER_DISPBKGND_INTERLACE : 0));
+
++ /* Reload the LUT, since the SRAMs would have been disabled if
++ * all CRTCs had SCALER_DISPBKGND_GAMMA unset at once.
++ */
++ vc4_crtc_lut_load(crtc);
++
+ if (debug_dump_regs) {
+ DRM_INFO("CRTC %d regs after:\n", drm_crtc_index(crtc));
+ vc4_crtc_dump_regs(vc4_crtc);
+@@ -613,6 +663,7 @@ static const struct drm_crtc_funcs vc4_c
+ .reset = drm_atomic_helper_crtc_reset,
+ .atomic_duplicate_state = vc4_crtc_duplicate_state,
+ .atomic_destroy_state = vc4_crtc_destroy_state,
++ .gamma_set = vc4_crtc_gamma_set,
+ };
+
+ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
+@@ -731,6 +782,7 @@ static int vc4_crtc_bind(struct device *
+ primary_plane->crtc = crtc;
+ vc4->crtc[drm_crtc_index(crtc)] = vc4_crtc;
+ vc4_crtc->channel = vc4_crtc->data->hvs_channel;
++ drm_mode_crtc_set_gamma_size(crtc, ARRAY_SIZE(vc4_crtc->lut_r));
+
+ /* Set up some arbitrary number of planes. We're not limited
+ * by a set number of physical registers, just the space in
+@@ -771,6 +823,12 @@ static int vc4_crtc_bind(struct device *
+
+ vc4_set_crtc_possible_masks(drm, crtc);
+
++ for (i = 0; i < crtc->gamma_size; i++) {
++ vc4_crtc->lut_r[i] = i;
++ vc4_crtc->lut_g[i] = i;
++ vc4_crtc->lut_b[i] = i;
++ }
++
+ platform_set_drvdata(pdev, vc4_crtc);
+
+ return 0;
+--- a/drivers/gpu/drm/vc4/vc4_regs.h
++++ b/drivers/gpu/drm/vc4/vc4_regs.h
+@@ -390,6 +390,12 @@
+ #define SCALER_DISPBASE2 0x0000006c
+ #define SCALER_DISPALPHA2 0x00000070
+ #define SCALER_GAMADDR 0x00000078
++# define SCALER_GAMADDR_AUTOINC BIT(31)
++/* Enables all gamma ramp SRAMs, not just those of CRTCs with gamma
++ * enabled.
++ */
++# define SCALER_GAMADDR_SRAMENB BIT(30)
++
+ #define SCALER_GAMDATA 0x000000e0
+ #define SCALER_DLIST_START 0x00002000
+ #define SCALER_DLIST_SIZE 0x00004000
diff --git a/target/linux/brcm2708/patches-4.4/0340-drm-vc4-Add-missing-render-node-support.patch b/target/linux/brcm2708/patches-4.4/0340-drm-vc4-Add-missing-render-node-support.patch
new file mode 100644
index 0000000000..c2a7d823c1
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0340-drm-vc4-Add-missing-render-node-support.patch
@@ -0,0 +1,26 @@
+From af5a17532c46fe8035fea72ba7d9409b7c9795f9 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Thu, 14 Apr 2016 23:16:05 -0700
+Subject: [PATCH 340/381] drm/vc4: Add missing render node support
+
+There shouldn't be any other driver support necessary, since none of
+the driver-specific ioctls ever required auth, and none of them deal
+with modesetting.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
+(cherry picked from commit 0cd3e27476620176c19e346f82576c6e139b85a9)
+---
+ drivers/gpu/drm/vc4/vc4_drv.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_drv.c
++++ b/drivers/gpu/drm/vc4/vc4_drv.c
+@@ -90,6 +90,7 @@ static struct drm_driver vc4_drm_driver
+ DRIVER_ATOMIC |
+ DRIVER_GEM |
+ DRIVER_HAVE_IRQ |
++ DRIVER_RENDER |
+ DRIVER_PRIME),
+ .lastclose = vc4_lastclose,
+ .preclose = vc4_drm_preclose,
diff --git a/target/linux/brcm2708/patches-4.4/0341-drm-panel-simple-Add-the-7-DPI-panel-from-Adafruit.patch b/target/linux/brcm2708/patches-4.4/0341-drm-panel-simple-Add-the-7-DPI-panel-from-Adafruit.patch
new file mode 100644
index 0000000000..c8e261b18d
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0341-drm-panel-simple-Add-the-7-DPI-panel-from-Adafruit.patch
@@ -0,0 +1,86 @@
+From 33b3868f0ec0b813153b977b08087fa4e4d5a5d3 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Thu, 24 Mar 2016 17:23:48 -0700
+Subject: [PATCH 341/381] drm/panel: simple: Add the 7" DPI panel from Adafruit
+
+This is a basic TFT panel with a 40-pin FPC connector on it. The
+specification doesn't define timings, but the Adafruit instructions
+were setting up 800x480 CVT.
+
+v2: Add .bus_format and vsync/hsync flags.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Acked-by: Rob Herring <robh@kernel.org>
+[treding@nvidia.com: keep entries properly sorted]
+Signed-off-by: Thierry Reding <treding@nvidia.com>
+
+(cherry picked from commit 8070fdbd024727c752f815b18e5339c681a01bbe)
+---
+ .../bindings/display/panel/ontat,yx700wv03.txt | 7 ++++
+ drivers/gpu/drm/panel/panel-simple.c | 37 ++++++++++++++++++++++
+ 2 files changed, 44 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/display/panel/ontat,yx700wv03.txt
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/display/panel/ontat,yx700wv03.txt
+@@ -0,0 +1,7 @@
++On Tat Industrial Company 7" DPI TFT panel.
++
++Required properties:
++- compatible: should be "ontat,yx700wv03"
++
++This binding is compatible with the simple-panel binding, which is specified
++in simple-panel.txt in this directory.
+--- a/drivers/gpu/drm/panel/panel-simple.c
++++ b/drivers/gpu/drm/panel/panel-simple.c
+@@ -1003,6 +1003,40 @@ static const struct panel_desc okaya_rs8
+ .bus_format = MEDIA_BUS_FMT_RGB666_1X18,
+ };
+
++/*
++ * 800x480 CVT. The panel appears to be quite accepting, at least as far as
++ * pixel clocks, but this is the timing that was being used in the Adafruit
++ * installation instructions.
++ */
++static const struct drm_display_mode ontat_yx700wv03_mode = {
++ .clock = 29500,
++ .hdisplay = 800,
++ .hsync_start = 824,
++ .hsync_end = 896,
++ .htotal = 992,
++ .vdisplay = 480,
++ .vsync_start = 483,
++ .vsync_end = 493,
++ .vtotal = 500,
++ .vrefresh = 60,
++ .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
++};
++
++/*
++ * Specification at:
++ * https://www.adafruit.com/images/product-files/2406/c3163.pdf
++ */
++static const struct panel_desc ontat_yx700wv03 = {
++ .modes = &ontat_yx700wv03_mode,
++ .num_modes = 1,
++ .bpc = 8,
++ .size = {
++ .width = 154,
++ .height = 83,
++ },
++ .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
++};
++
+ static const struct drm_display_mode ortustech_com43h4m85ulc_mode = {
+ .clock = 25000,
+ .hdisplay = 480,
+@@ -1179,6 +1213,9 @@ static const struct of_device_id platfor
+ .compatible = "okaya,rs800480t-7x0gp",
+ .data = &okaya_rs800480t_7x0gp,
+ }, {
++ .compatible = "ontat,yx700wv03",
++ .data = &ontat_yx700wv03,
++ }, {
+ .compatible = "ortustech,com43h4m85ulc",
+ .data = &ortustech_com43h4m85ulc,
+ }, {
diff --git a/target/linux/brcm2708/patches-4.4/0342-BCM270X_DT-Add-the-disabled-by-default-DPI-device-no.patch b/target/linux/brcm2708/patches-4.4/0342-BCM270X_DT-Add-the-disabled-by-default-DPI-device-no.patch
new file mode 100644
index 0000000000..c5dd2e7e28
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0342-BCM270X_DT-Add-the-disabled-by-default-DPI-device-no.patch
@@ -0,0 +1,34 @@
+From 48c22040d540d47c1dd4496a9587b0f3139fc8f0 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Fri, 6 May 2016 13:18:09 -0700
+Subject: [PATCH 342/381] BCM270X_DT: Add the disabled-by-default DPI device
+ node.
+
+This will be enabled and connected to a particular panel by DT
+overlays.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ arch/arm/boot/dts/bcm2708_common.dtsi | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+--- a/arch/arm/boot/dts/bcm2708_common.dtsi
++++ b/arch/arm/boot/dts/bcm2708_common.dtsi
+@@ -179,6 +179,17 @@
+ status = "disabled";
+ };
+
++ dpi: dpi@7e208000 {
++ compatible = "brcm,bcm2835-dpi";
++ reg = <0x7e208000 0x8c>;
++ clocks = <&cprman BCM2835_CLOCK_VPU>,
++ <&cprman BCM2835_CLOCK_DPI>;
++ clock-names = "core", "pixel";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
+ pixelvalve1: pixelvalve@7e207000 {
+ compatible = "brcm,bcm2835-pixelvalve1";
+ reg = <0x7e207000 0x100>;
diff --git a/target/linux/brcm2708/patches-4.4/0343-drm-vc4-Fix-get_vblank_counter-with-proper-no-op-for.patch b/target/linux/brcm2708/patches-4.4/0343-drm-vc4-Fix-get_vblank_counter-with-proper-no-op-for.patch
new file mode 100644
index 0000000000..30bfb081c8
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0343-drm-vc4-Fix-get_vblank_counter-with-proper-no-op-for.patch
@@ -0,0 +1,31 @@
+From cc64a36830bcae96e5df48d69f69057a8df539f2 Mon Sep 17 00:00:00 2001
+From: Mario Kleiner <mario.kleiner.de@gmail.com>
+Date: Fri, 6 May 2016 19:26:05 +0200
+Subject: [PATCH 343/381] drm/vc4: Fix get_vblank_counter with proper no-op for
+ Linux 4.4+
+
+get_vblank_counter hooked up to drm_vblank_count() which alway was
+non-sensical but didn't hurt in the past. Since Linux 4.4 it
+triggers a WARN_ON_ONCE in drm_update_vblank_count on first vblank
+irq disable, so fix it by hooking to drm_vblank_no_hw_counter().
+
+Tested against Raspian kernel 4.4.8 tree on RPi 2B.
+
+Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
+Cc: Eric Anholt <eric@anholt.net>
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_drv.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_drv.c
++++ b/drivers/gpu/drm/vc4/vc4_drv.c
+@@ -102,7 +102,7 @@ static struct drm_driver vc4_drm_driver
+
+ .enable_vblank = vc4_enable_vblank,
+ .disable_vblank = vc4_disable_vblank,
+- .get_vblank_counter = drm_vblank_count,
++ .get_vblank_counter = drm_vblank_no_hw_counter,
+
+ #if defined(CONFIG_DEBUG_FS)
+ .debugfs_init = vc4_debugfs_init,
diff --git a/target/linux/brcm2708/patches-4.4/0344-drm-vc4-Fix-drm_vblank_put-get-imbalance-in-page-fli.patch b/target/linux/brcm2708/patches-4.4/0344-drm-vc4-Fix-drm_vblank_put-get-imbalance-in-page-fli.patch
new file mode 100644
index 0000000000..791f5c3160
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0344-drm-vc4-Fix-drm_vblank_put-get-imbalance-in-page-fli.patch
@@ -0,0 +1,48 @@
+From c4f773a1aa2d372d152138952cf7058ce93f8952 Mon Sep 17 00:00:00 2001
+From: Mario Kleiner <mario.kleiner.de@gmail.com>
+Date: Fri, 6 May 2016 19:26:06 +0200
+Subject: [PATCH 344/381] drm/vc4: Fix drm_vblank_put/get imbalance in page
+ flip path.
+
+The async page flip path was missing drm_crtc_vblank_get/put
+completely. The sync flip path was missing a vblank put, so async
+flips only reported proper pageflip completion events by chance,
+and vblank irq's never turned off after a first vsync'ed page flip
+until system reboot.
+
+Tested against Raspian kernel 4.4.8 tree on RPi 2B.
+
+Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
+Cc: Eric Anholt <eric@anholt.net>
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_crtc.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_crtc.c
++++ b/drivers/gpu/drm/vc4/vc4_crtc.c
+@@ -506,6 +506,7 @@ static void vc4_crtc_handle_page_flip(st
+ if (vc4_crtc->event) {
+ drm_crtc_send_vblank_event(crtc, vc4_crtc->event);
+ vc4_crtc->event = NULL;
++ drm_crtc_vblank_put(crtc);
+ }
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ }
+@@ -556,6 +557,7 @@ vc4_async_page_flip_complete(struct vc4_
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ }
+
++ drm_crtc_vblank_put(crtc);
+ drm_framebuffer_unreference(flip_state->fb);
+ kfree(flip_state);
+
+@@ -598,6 +600,8 @@ static int vc4_async_page_flip(struct dr
+ return ret;
+ }
+
++ WARN_ON(drm_crtc_vblank_get(crtc) != 0);
++
+ /* Immediately update the plane's legacy fb pointer, so that later
+ * modeset prep sees the state that will be present when the semaphore
+ * is released.
diff --git a/target/linux/brcm2708/patches-4.4/0345-BCM270X_DT-Add-umbrella-I2C-Mux-overlay-i2c-mux.patch b/target/linux/brcm2708/patches-4.4/0345-BCM270X_DT-Add-umbrella-I2C-Mux-overlay-i2c-mux.patch
new file mode 100644
index 0000000000..ea5aecc932
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0345-BCM270X_DT-Add-umbrella-I2C-Mux-overlay-i2c-mux.patch
@@ -0,0 +1,269 @@
+From eaa6e5f8a581aa8c71c245ecfc882819c7090a06 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Wed, 11 May 2016 15:38:04 +0100
+Subject: [PATCH 345/381] BCM270X_DT: Add umbrella I2C Mux overlay i2c-mux
+
+This overlay supports a range of I2C multiplexers - PCA9542 (2 ports),
+PCA9545 (4 ports) and PCA9548 (8 ports).
+
+Also remove the dedicated i2c-mux-9548a overlays since it is no longer
+needed.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/overlays/Makefile | 2 +-
+ arch/arm/boot/dts/overlays/README | 17 ++-
+ arch/arm/boot/dts/overlays/i2c-mux-overlay.dts | 138 +++++++++++++++++++++
+ .../boot/dts/overlays/i2c-mux-pca9548a-overlay.dts | 67 ----------
+ 4 files changed, 152 insertions(+), 72 deletions(-)
+ create mode 100644 arch/arm/boot/dts/overlays/i2c-mux-overlay.dts
+ delete mode 100644 arch/arm/boot/dts/overlays/i2c-mux-pca9548a-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -34,7 +34,7 @@ dtbo-$(RPI_DT_OVERLAYS) += hy28a.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += hy28b.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += i2c-rtc.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += i2c-gpio.dtbo
+-dtbo-$(RPI_DT_OVERLAYS) += i2c-mux-pca9548a.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += i2c-mux.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += i2c-pwm-pca9685a.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += i2c0-bcm2708.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += i2c1-bcm2708.dtbo
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -421,10 +421,19 @@ Params: i2c_gpio_sda GPIO use
+ (default "2" = ~100kHz)
+
+
+-Name: i2c-mux-pca9548a
+-Info: Adds support for an NXP PCA9548A I2C multiplexer on i2c_arm
+-Load: dtoverlay=i2c-mux-pca9548a,<param>=<val>
+-Params: addr I2C address of PCA9548A (default 0x70)
++Name: i2c-mux
++Info: Adds support for a number of I2C bus multiplexers on i2c_arm
++Load: dtoverlay=i2c-mux,<param>=<val>
++Params: pca9542 Select the NXP PCA9542 device
++
++ pca9545 Select the NXP PCA9545 device
++
++ pca9548 Select the NXP PCA9548 device
++
++ addr Change I2C address of the device (default 0x70)
++
++
++[ The i2c-mux-pca9548a overlay has been deleted. See i2c-mux. ]
+
+
+ Name: i2c-pwm-pca9685a
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/i2c-mux-overlay.dts
+@@ -0,0 +1,138 @@
++// Umbrella I2C Mux overlay
++
++/dts-v1/;
++/plugin/;
++
++/{
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&i2c_arm>;
++ __dormant__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ pca9542: mux@70 {
++ compatible = "nxp,pca9542";
++ reg = <0x70>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ i2c@0 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0>;
++ };
++ i2c@1 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <1>;
++ };
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&i2c_arm>;
++ __dormant__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ pca9545: mux@70 {
++ compatible = "nxp,pca9545";
++ reg = <0x70>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ i2c@0 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0>;
++ };
++ i2c@1 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <1>;
++ };
++ i2c@2 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <2>;
++ };
++ i2c@3 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <3>;
++ };
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&i2c_arm>;
++ __dormant__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ pca9548: mux@70 {
++ compatible = "nxp,pca9548";
++ reg = <0x70>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ i2c@0 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0>;
++ };
++ i2c@1 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <1>;
++ };
++ i2c@2 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <2>;
++ };
++ i2c@3 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <3>;
++ };
++ i2c@4 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <4>;
++ };
++ i2c@5 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <5>;
++ };
++ i2c@6 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <6>;
++ };
++ i2c@7 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <7>;
++ };
++ };
++ };
++ };
++
++ __overrides__ {
++ pca9542 = <0>, "+0";
++ pca9545 = <0>, "+1";
++ pca9548 = <0>, "+2";
++
++ addr = <&pca9545>,"reg:0",
++ <&pca9548>,"reg:0";
++ };
++};
+--- a/arch/arm/boot/dts/overlays/i2c-mux-pca9548a-overlay.dts
++++ /dev/null
+@@ -1,67 +0,0 @@
+-// Definitions for NXP PCA9548A I2C mux on ARM I2C bus.
+-/dts-v1/;
+-/plugin/;
+-
+-/{
+- compatible = "brcm,bcm2708";
+-
+- fragment@0 {
+- target = <&i2c_arm>;
+- __overlay__ {
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "okay";
+-
+- i2cmux: mux@70 {
+- compatible = "nxp,pca9548";
+- reg = <0x70>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+-
+- i2c@0 {
+- #address-cells = <1>;
+- #size-cells = <0>;
+- reg = <0>;
+- };
+- i2c@1 {
+- #address-cells = <1>;
+- #size-cells = <0>;
+- reg = <1>;
+- };
+- i2c@2 {
+- #address-cells = <1>;
+- #size-cells = <0>;
+- reg = <2>;
+- };
+- i2c@3 {
+- #address-cells = <1>;
+- #size-cells = <0>;
+- reg = <3>;
+- };
+- i2c@4 {
+- #address-cells = <1>;
+- #size-cells = <0>;
+- reg = <4>;
+- };
+- i2c@5 {
+- #address-cells = <1>;
+- #size-cells = <0>;
+- reg = <5>;
+- };
+- i2c@6 {
+- #address-cells = <1>;
+- #size-cells = <0>;
+- reg = <6>;
+- };
+- i2c@7 {
+- #address-cells = <1>;
+- #size-cells = <0>;
+- reg = <7>;
+- };
+- };
+- };
+- };
+- __overrides__ {
+- addr = <&i2cmux>,"reg:0";
+- };
+-};
diff --git a/target/linux/brcm2708/patches-4.4/0346-BCM270X_DT-Include-address-override-for-pca9542.patch b/target/linux/brcm2708/patches-4.4/0346-BCM270X_DT-Include-address-override-for-pca9542.patch
new file mode 100644
index 0000000000..80d17ab7dc
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0346-BCM270X_DT-Include-address-override-for-pca9542.patch
@@ -0,0 +1,24 @@
+From 8753ff77e0c42682d80135d8c3519b7a5772bd9e Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Thu, 12 May 2016 08:52:06 +0100
+Subject: [PATCH 346/381] BCM270X_DT: Include address override for pca9542
+
+Omitted from "BCM270X_DT: Add umbrella I2C Mux overlay i2c-mux".
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/overlays/i2c-mux-overlay.dts | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/i2c-mux-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c-mux-overlay.dts
+@@ -132,7 +132,8 @@
+ pca9545 = <0>, "+1";
+ pca9548 = <0>, "+2";
+
+- addr = <&pca9545>,"reg:0",
++ addr = <&pca9542>,"reg:0",
++ <&pca9545>,"reg:0",
+ <&pca9548>,"reg:0";
+ };
+ };
diff --git a/target/linux/brcm2708/patches-4.4/0347-BCM270X_DT-Fix-the-tinylcd35-overlay-RTC-support.patch b/target/linux/brcm2708/patches-4.4/0347-BCM270X_DT-Fix-the-tinylcd35-overlay-RTC-support.patch
new file mode 100644
index 0000000000..968ef94274
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0347-BCM270X_DT-Fix-the-tinylcd35-overlay-RTC-support.patch
@@ -0,0 +1,68 @@
+From 3f11e310d0e877d26958afe83975a5157e500ebe Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Thu, 12 May 2016 09:04:20 +0100
+Subject: [PATCH 347/381] BCM270X_DT: Fix the tinylcd35 overlay RTC support
+
+Now that overlay parameters are applied before the merge (a requirement
+for kernel runtime overlays) it is illegal for parameters/overrides to
+target nodes in the base DTB. Solve the problem of only enabling I2C
+when an RTC option is used by making the RTC fragments conditional,
+and including the required status="okay" within the fragments.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/overlays/tinylcd35-overlay.dts | 18 ++++++++++--------
+ 1 file changed, 10 insertions(+), 8 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/tinylcd35-overlay.dts
++++ b/arch/arm/boot/dts/overlays/tinylcd35-overlay.dts
+@@ -132,28 +132,32 @@
+
+ fragment@5 {
+ target = <&i2c1>;
+- __overlay__ {
++ __dormant__ {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
++ status = "okay";
++
+ pcf8563: pcf8563@51 {
+ compatible = "nxp,pcf8563";
+ reg = <0x51>;
+- status = "disabled";
++ status = "okay";
+ };
+ };
+ };
+
+ fragment@6 {
+ target = <&i2c1>;
+- __overlay__ {
++ __dormant__ {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
++ status = "okay";
++
+ ds1307: ds1307@68 {
+ compatible = "maxim,ds1307";
+ reg = <0x68>;
+- status = "disabled";
++ status = "okay";
+ };
+ };
+ };
+@@ -213,10 +217,8 @@
+ <&tinylcd35_ts>,"interrupts:0",
+ <&tinylcd35_ts>,"pendown-gpio:4";
+ xohms = <&tinylcd35_ts>,"ti,x-plate-ohms;0";
+- rtc-pcf = <&i2c1>,"status",
+- <&pcf8563>,"status";
+- rtc-ds = <&i2c1>,"status",
+- <&ds1307>,"status";
++ rtc-pcf = <0>,"=5";
++ rtc-ds = <0>,"=6";
+ keypad = <&keypad>,"status";
+ };
+ };
diff --git a/target/linux/brcm2708/patches-4.4/0348-clk-Allow-clocks-to-be-marked-as-CRITICAL.patch b/target/linux/brcm2708/patches-4.4/0348-clk-Allow-clocks-to-be-marked-as-CRITICAL.patch
new file mode 100644
index 0000000000..bebfc5e860
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0348-clk-Allow-clocks-to-be-marked-as-CRITICAL.patch
@@ -0,0 +1,43 @@
+From ac9a9b1fcf3b0255aebc8e7f4b809f15556d9640 Mon Sep 17 00:00:00 2001
+From: Lee Jones <lee.jones@linaro.org>
+Date: Thu, 11 Feb 2016 13:19:09 -0800
+Subject: [PATCH 348/381] clk: Allow clocks to be marked as CRITICAL
+
+Critical clocks are those which must not be gated, else undefined
+or catastrophic failure would occur. Here we have chosen to
+ensure the prepare/enable counts are correctly incremented, so as
+not to confuse users with enabled clocks with no visible users.
+
+Signed-off-by: Lee Jones <lee.jones@linaro.org>
+Signed-off-by: Michael Turquette <mturquette@baylibre.com>
+Link: lkml.kernel.org/r/1455225554-13267-2-git-send-email-mturquette@baylibre.com
+(cherry picked from commit 32b9b10961860860268961d9aad0c56a73018c37)
+---
+ drivers/clk/clk.c | 5 +++++
+ include/linux/clk-provider.h | 1 +
+ 2 files changed, 6 insertions(+)
+
+--- a/drivers/clk/clk.c
++++ b/drivers/clk/clk.c
+@@ -2466,6 +2466,11 @@ static int __clk_init(struct device *dev
+ if (core->ops->init)
+ core->ops->init(core->hw);
+
++ if (core->flags & CLK_IS_CRITICAL) {
++ clk_core_prepare(core);
++ clk_core_enable(core);
++ }
++
+ kref_init(&core->ref);
+ out:
+ clk_prepare_unlock();
+--- a/include/linux/clk-provider.h
++++ b/include/linux/clk-provider.h
+@@ -31,6 +31,7 @@
+ #define CLK_SET_RATE_NO_REPARENT BIT(7) /* don't re-parent on rate change */
+ #define CLK_GET_ACCURACY_NOCACHE BIT(8) /* do not use the cached clk accuracy */
+ #define CLK_RECALC_NEW_RATES BIT(9) /* recalc rates after notifications */
++#define CLK_IS_CRITICAL BIT(11) /* do not gate, ever */
+
+ struct clk;
+ struct clk_hw;
diff --git a/target/linux/brcm2708/patches-4.4/0349-clk-bcm2835-Mark-the-VPU-clock-as-critical.patch b/target/linux/brcm2708/patches-4.4/0349-clk-bcm2835-Mark-the-VPU-clock-as-critical.patch
new file mode 100644
index 0000000000..95bcb497f5
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0349-clk-bcm2835-Mark-the-VPU-clock-as-critical.patch
@@ -0,0 +1,46 @@
+From 0488240a92abe6fc9fa6f3a3058849b17af2d3e5 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Tue, 26 Apr 2016 11:44:59 -0700
+Subject: [PATCH 349/381] clk: bcm2835: Mark the VPU clock as critical
+
+The VPU clock is also the clock for our AXI bus, so we really can't
+disable it. This might have happened during boot if, for example,
+uart1 (aux_uart clock) probed and was then disabled before the other
+consumers of the VPU clock had probed.
+
+v2: Rewrite to use a .flags in bcm2835_clock_data, since other clocks
+ will need this too.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/clk/bcm/clk-bcm2835.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -446,6 +446,8 @@ struct bcm2835_clock_data {
+ /* Number of fractional bits in the divider */
+ u32 frac_bits;
+
++ u32 flags;
++
+ bool is_vpu_clock;
+ bool is_mash_clock;
+ };
+@@ -1246,7 +1248,7 @@ static struct clk *bcm2835_register_cloc
+ init.parent_names = parents;
+ init.num_parents = data->num_mux_parents;
+ init.name = data->name;
+- init.flags = CLK_IGNORE_UNUSED;
++ init.flags = data->flags | CLK_IGNORE_UNUSED;
+
+ if (data->is_vpu_clock) {
+ init.ops = &bcm2835_vpu_clock_clk_ops;
+@@ -1665,6 +1667,7 @@ static const struct bcm2835_clk_desc clk
+ .div_reg = CM_VPUDIV,
+ .int_bits = 12,
+ .frac_bits = 8,
++ .flags = CLK_IS_CRITICAL,
+ .is_vpu_clock = true),
+
+ /* clocks with per parent mux */
diff --git a/target/linux/brcm2708/patches-4.4/0350-clk-bcm2835-Mark-GPIO-clocks-enabled-at-boot-as-crit.patch b/target/linux/brcm2708/patches-4.4/0350-clk-bcm2835-Mark-GPIO-clocks-enabled-at-boot-as-crit.patch
new file mode 100644
index 0000000000..01c1c1b64e
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0350-clk-bcm2835-Mark-GPIO-clocks-enabled-at-boot-as-crit.patch
@@ -0,0 +1,55 @@
+From edb0177945936b14fe58662743f9e9d4eeba4b73 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 9 May 2016 17:28:18 -0700
+Subject: [PATCH 350/381] clk: bcm2835: Mark GPIO clocks enabled at boot as
+ critical.
+
+These divide off of PLLD_PER and are used for the ethernet and wifi
+PHYs source PLLs. Neither of them is currently represented by a phy
+device that would grab the clock for us.
+
+This keeps other drivers from killing the networking PHYs when they
+disable their own clocks and trigger PLLD_PER's refcount going to 0.
+
+v2: Skip marking as critical if they aren't on at boot.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/clk/bcm/clk-bcm2835.c | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -1250,6 +1250,15 @@ static struct clk *bcm2835_register_cloc
+ init.name = data->name;
+ init.flags = data->flags | CLK_IGNORE_UNUSED;
+
++ /*
++ * Some GPIO clocks for ethernet/wifi PLLs are marked as
++ * critical (since some platforms use them), but if the
++ * firmware didn't have them turned on then they clearly
++ * aren't actually critical.
++ */
++ if ((cprman_read(cprman, data->ctl_reg) & CM_ENABLE) == 0)
++ init.flags &= ~CLK_IS_CRITICAL;
++
+ if (data->is_vpu_clock) {
+ init.ops = &bcm2835_vpu_clock_clk_ops;
+ } else {
+@@ -1724,13 +1733,15 @@ static const struct bcm2835_clk_desc clk
+ .div_reg = CM_GP1DIV,
+ .int_bits = 12,
+ .frac_bits = 12,
++ .flags = CLK_IS_CRITICAL,
+ .is_mash_clock = true),
+ [BCM2835_CLOCK_GP2] = REGISTER_PER_CLK(
+ .name = "gp2",
+ .ctl_reg = CM_GP2CTL,
+ .div_reg = CM_GP2DIV,
+ .int_bits = 12,
+- .frac_bits = 12),
++ .frac_bits = 12,
++ .flags = CLK_IS_CRITICAL),
+
+ /* HDMI state machine */
+ [BCM2835_CLOCK_HSM] = REGISTER_PER_CLK(
diff --git a/target/linux/brcm2708/patches-4.4/0351-clk-bcm2835-Skip-PLLC-clocks-when-deciding-on-a-new-.patch b/target/linux/brcm2708/patches-4.4/0351-clk-bcm2835-Skip-PLLC-clocks-when-deciding-on-a-new-.patch
new file mode 100644
index 0000000000..d8c80918e4
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0351-clk-bcm2835-Skip-PLLC-clocks-when-deciding-on-a-new-.patch
@@ -0,0 +1,71 @@
+From 4ef6b916c3004783aeeabfcd9889bca046d944bf Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Tue, 26 Apr 2016 12:39:45 -0700
+Subject: [PATCH 351/381] clk: bcm2835: Skip PLLC clocks when deciding on a new
+ clock parent
+
+If the firmware had set up a clock to source from PLLC, go along with
+it. But if we're looking for a new parent, we don't want to switch it
+to PLLC because the firmware will force PLLC (and thus the AXI bus
+clock) to different frequencies during over-temp/under-voltage,
+without notification to Linux.
+
+On my system, this moves the Linux-enabled HDMI state machine and DSI1
+escape clock over to plld_per from pllc_per. EMMC still ends up on
+pllc_per, because the firmware had set it up to use that.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Fixes: 41691b8862e2 ("clk: bcm2835: Add support for programming the audio domain clocks")
+---
+ drivers/clk/bcm/clk-bcm2835.c | 23 +++++++++++++++++++++++
+ 1 file changed, 23 insertions(+)
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -1024,16 +1024,28 @@ static int bcm2835_clock_set_rate(struct
+ return 0;
+ }
+
++static bool
++bcm2835_clk_is_pllc(struct clk_hw *hw)
++{
++ if (!hw)
++ return false;
++
++ return strncmp(clk_hw_get_name(hw), "pllc", 4) == 0;
++}
++
+ static int bcm2835_clock_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+ {
+ struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+ struct clk_hw *parent, *best_parent = NULL;
++ bool current_parent_is_pllc;
+ unsigned long rate, best_rate = 0;
+ unsigned long prate, best_prate = 0;
+ size_t i;
+ u32 div;
+
++ current_parent_is_pllc = bcm2835_clk_is_pllc(clk_hw_get_parent(hw));
++
+ /*
+ * Select parent clock that results in the closest but lower rate
+ */
+@@ -1041,6 +1053,17 @@ static int bcm2835_clock_determine_rate(
+ parent = clk_hw_get_parent_by_index(hw, i);
+ if (!parent)
+ continue;
++
++ /*
++ * Don't choose a PLLC-derived clock as our parent
++ * unless it had been manually set that way. PLLC's
++ * frequency gets adjusted by the firmware due to
++ * over-temp or under-voltage conditions, without
++ * prior notification to our clock consumer.
++ */
++ if (bcm2835_clk_is_pllc(parent) && !current_parent_is_pllc)
++ continue;
++
+ prate = clk_hw_get_rate(parent);
+ div = bcm2835_clock_choose_div(hw, req->rate, prate, true);
+ rate = bcm2835_clock_rate_from_divisor(clock, prate, div);
diff --git a/target/linux/brcm2708/patches-4.4/0352-mmc-Add-MMC_QUIRK_ERASE_BROKEN-for-some-cards.patch b/target/linux/brcm2708/patches-4.4/0352-mmc-Add-MMC_QUIRK_ERASE_BROKEN-for-some-cards.patch
new file mode 100644
index 0000000000..8a93b09371
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0352-mmc-Add-MMC_QUIRK_ERASE_BROKEN-for-some-cards.patch
@@ -0,0 +1,56 @@
+From 8479891a91161b13f8d63b7d8aa6614cb03e3442 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Wed, 11 May 2016 12:50:33 +0100
+Subject: [PATCH 352/381] mmc: Add MMC_QUIRK_ERASE_BROKEN for some cards
+
+Some SD cards have been found that corrupt data when small blocks
+are erased. Add a quirk to indicate that ERASE should not be used,
+and set it for cards of that type.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/mmc/card/block.c | 7 +++++++
+ drivers/mmc/core/core.c | 3 ++-
+ include/linux/mmc/card.h | 3 +++
+ 3 files changed, 12 insertions(+), 1 deletion(-)
+
+--- a/drivers/mmc/card/block.c
++++ b/drivers/mmc/card/block.c
+@@ -2552,6 +2552,13 @@ static const struct mmc_fixup blk_fixups
+ MMC_FIXUP("V10016", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc,
+ MMC_QUIRK_TRIM_BROKEN),
+
++ /*
++ * On some Kingston SD cards, multiple erases of less than 64
++ * sectors can cause corruption.
++ */
++ MMC_FIXUP("SD16G", 0x41, 0x3432, add_quirk_mmc,
++ MMC_QUIRK_ERASE_BROKEN),
++
+ END_FIXUP
+ };
+
+--- a/drivers/mmc/core/core.c
++++ b/drivers/mmc/core/core.c
+@@ -2253,7 +2253,8 @@ EXPORT_SYMBOL(mmc_erase);
+ int mmc_can_erase(struct mmc_card *card)
+ {
+ if ((card->host->caps & MMC_CAP_ERASE) &&
+- (card->csd.cmdclass & CCC_ERASE) && card->erase_size)
++ (card->csd.cmdclass & CCC_ERASE) && card->erase_size &&
++ !(card->quirks & MMC_QUIRK_ERASE_BROKEN))
+ return 1;
+ return 0;
+ }
+--- a/include/linux/mmc/card.h
++++ b/include/linux/mmc/card.h
+@@ -281,6 +281,9 @@ struct mmc_card {
+ #define MMC_QUIRK_TRIM_BROKEN (1<<12) /* Skip trim */
+
+
++#define MMC_QUIRK_ERASE_BROKEN (1<<31) /* Skip erase */
++
++
+ unsigned int erase_size; /* erase size in sectors */
+ unsigned int erase_shift; /* if erase unit is power 2 */
+ unsigned int pref_erase; /* in sectors */
diff --git a/target/linux/brcm2708/patches-4.4/0353-New-AudioInjector.net-Pi-soundcard-with-low-jitter-a.patch b/target/linux/brcm2708/patches-4.4/0353-New-AudioInjector.net-Pi-soundcard-with-low-jitter-a.patch
new file mode 100644
index 0000000000..124b814c4c
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0353-New-AudioInjector.net-Pi-soundcard-with-low-jitter-a.patch
@@ -0,0 +1,284 @@
+From 5b48080842ef9333050cf1743e89f8f780cd95d4 Mon Sep 17 00:00:00 2001
+From: Matt Flax <flatmax@flatmax.org>
+Date: Mon, 16 May 2016 21:36:31 +1000
+Subject: [PATCH 353/381] New AudioInjector.net Pi soundcard with low jitter
+ audio in and out.
+
+Contains the sound/soc/bcm ALSA machine driver and necessary alterations to the Kconfig and Makefile.
+Adds the dts overlay and updates the Makefile and README.
+Updates the relevant defconfig files to enable building for the Raspberry Pi.
+Thanks to Phil Elwell (pelwell) for the review, simple-card concepts and discussion. Thanks to Clive Messer for overlay naming suggestions.
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 6 +
+ .../audioinjector-wm8731-audio-overlay.dts | 39 ++++++
+ arch/arm/configs/bcm2709_defconfig | 1 +
+ arch/arm/configs/bcmrpi_defconfig | 1 +
+ sound/soc/bcm/Kconfig | 7 +
+ sound/soc/bcm/Makefile | 3 +
+ sound/soc/bcm/audioinjector-pi-soundcard.c | 142 +++++++++++++++++++++
+ 8 files changed, 200 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/audioinjector-wm8731-audio-overlay.dts
+ create mode 100644 sound/soc/bcm/audioinjector-pi-soundcard.c
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -16,6 +16,7 @@ dtbo-$(RPI_DT_OVERLAYS) += adau1977-adc.
+ dtbo-$(RPI_DT_OVERLAYS) += ads7846.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += akkordion-iqdacplus.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += at86rf233.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += audioinjector-wm8731-audio.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += bmp085_i2c-sensor.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += boomberry-dac.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += boomberry-digi.dtbo
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -225,6 +225,12 @@ Params: interrupt GPIO use
+ arrays (0=+0pF, 15=+4.5pF, default 15)
+
+
++Name: audioinjector-wm8731-audio
++Info: Configures the audioinjector.net audio add on soundcard
++Load: dtoverlay=audioinjector-wm8731-audio
++Params: <None>
++
++
+ Name: bmp085_i2c-sensor
+ Info: Configures the BMP085/BMP180 digital barometric pressure and temperature
+ sensors from Bosch Sensortec
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/audioinjector-wm8731-audio-overlay.dts
+@@ -0,0 +1,39 @@
++// Definitions for audioinjector.net audio add on soundcard
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&i2s>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ wm8731@1a {
++ #sound-dai-cells = <0>;
++ compatible = "wlf,wm8731";
++ reg = <0x1a>;
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&sound>;
++ __overlay__ {
++ compatible = "ai,audioinjector-pi-soundcard";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
++};
+--- a/arch/arm/configs/bcm2709_defconfig
++++ b/arch/arm/configs/bcm2709_defconfig
+@@ -863,6 +863,7 @@ CONFIG_SND_BCM2708_SOC_BOOMBERRY_DAC=m
+ CONFIG_SND_BCM2708_SOC_BOOMBERRY_DIGI=m
+ CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m
+ CONFIG_SND_BCM2708_SOC_RASPIDAC3=m
++CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD=m
+ CONFIG_SND_BCM2708_SOC_ADAU1977_ADC=m
+ CONFIG_SND_SOC_ADAU1701=m
+ CONFIG_SND_SOC_WM8804_I2C=m
+--- a/arch/arm/configs/bcmrpi_defconfig
++++ b/arch/arm/configs/bcmrpi_defconfig
+@@ -855,6 +855,7 @@ CONFIG_SND_BCM2708_SOC_BOOMBERRY_DAC=m
+ CONFIG_SND_BCM2708_SOC_BOOMBERRY_DIGI=m
+ CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m
+ CONFIG_SND_BCM2708_SOC_RASPIDAC3=m
++CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD=m
+ CONFIG_SND_BCM2708_SOC_ADAU1977_ADC=m
+ CONFIG_SND_SOC_ADAU1701=m
+ CONFIG_SND_SOC_WM8804_I2C=m
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -85,3 +85,10 @@ config SND_BCM2708_SOC_ADAU1977_ADC
+ select SND_SOC_ADAU1977_I2C
+ help
+ Say Y or M if you want to add support for ADAU1977 ADC.
++
++config SND_AUDIOINJECTOR_PI_SOUNDCARD
++ tristate "Support for audioinjector.net Pi add on soundcard"
++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
++ select SND_SOC_WM8731
++ help
++ Say Y or M if you want to add support for audioinjector.net Pi Hat
+--- a/sound/soc/bcm/Makefile
++++ b/sound/soc/bcm/Makefile
+@@ -15,6 +15,7 @@ snd-soc-rpi-dac-objs := rpi-dac.o
+ snd-soc-rpi-proto-objs := rpi-proto.o
+ snd-soc-iqaudio-dac-objs := iqaudio-dac.o
+ snd-soc-raspidac3-objs := raspidac3.o
++snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o
+
+ obj-$(CONFIG_SND_BCM2708_SOC_ADAU1977_ADC) += snd-soc-adau1977-adc.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o
+@@ -27,3 +28,5 @@ obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) +=
+ obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
+ obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
+ obj-$(CONFIG_SND_BCM2708_SOC_RASPIDAC3) += snd-soc-raspidac3.o
++obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD) += snd-soc-audioinjector-pi-soundcard.o
++
+--- /dev/null
++++ b/sound/soc/bcm/audioinjector-pi-soundcard.c
+@@ -0,0 +1,142 @@
++/*
++ * ASoC Driver for AudioInjector Pi add on soundcard
++ *
++ * Created on: 13-May-2016
++ * Author: flatmax@flatmax.org
++ * based on code by Cliff Cai <Cliff.Cai@analog.com> for the ssm2602 machine blackfin.
++ * with help from Lars-Peter Clausen for simplifying the original code to use the dai_fmt field.
++ * i2s_node code taken from the other sound/soc/bcm machine drivers.
++ *
++ * Copyright (C) 2016 Flatmax Pty. Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++#include <linux/module.h>
++#include <linux/types.h>
++
++#include <sound/core.h>
++#include <sound/soc.h>
++#include <sound/pcm_params.h>
++#include <sound/control.h>
++
++#include "../codecs/wm8731.h"
++
++static int audioinjector_pi_soundcard_dai_init(struct snd_soc_pcm_runtime *rtd)
++{
++ struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
++
++ // not connected
++ snd_soc_dapm_nc_pin(dapm, "Mic Bias");
++ snd_soc_dapm_nc_pin(dapm, "MICIN");
++ snd_soc_dapm_nc_pin(dapm, "RHPOUT");
++ snd_soc_dapm_nc_pin(dapm, "LHPOUT");
++
++ return snd_soc_dai_set_sysclk(rtd->codec_dai, WM8731_SYSCLK_XTAL, 12000000, SND_SOC_CLOCK_IN);
++}
++
++static struct snd_soc_dai_link audioinjector_pi_soundcard_dai[] = {
++ {
++ .name = "AudioInjector audio",
++ .stream_name = "AudioInjector audio",
++ .cpu_dai_name = "bcm2708-i2s.0",
++ .codec_dai_name = "wm8731-hifi",
++ .platform_name = "bcm2835-i2s.0",
++ .codec_name = "wm8731.1-001a",
++ .init = audioinjector_pi_soundcard_dai_init,
++ .dai_fmt = SND_SOC_DAIFMT_CBM_CFM|SND_SOC_DAIFMT_I2S|SND_SOC_DAIFMT_NB_NF,
++ },
++};
++
++static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
++ SND_SOC_DAPM_SPK("Ext Spk", NULL),
++ SND_SOC_DAPM_LINE("Line In Jacks", NULL),
++};
++
++/* Corgi machine connections to the codec pins */
++static const struct snd_soc_dapm_route audioinjector_audio_map[] = {
++ /* speaker connected to LOUT, ROUT */
++ {"Ext Spk", NULL, "ROUT"},
++ {"Ext Spk", NULL, "LOUT"},
++
++ /* line inputs */
++ {"Line In Jacks", NULL, "Line Input"},
++};
++
++static struct snd_soc_card snd_soc_audioinjector = {
++ .name = "audioinjector-pi-soundcard",
++ .dai_link = audioinjector_pi_soundcard_dai,
++ .num_links = 1,
++
++ .dapm_widgets = wm8731_dapm_widgets,
++ .num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets),
++ .dapm_routes = audioinjector_audio_map,
++ .num_dapm_routes = ARRAY_SIZE(audioinjector_audio_map),
++};
++
++static int audioinjector_pi_soundcard_probe(struct platform_device *pdev)
++{
++ struct snd_soc_card *card = &snd_soc_audioinjector;
++ int ret;
++
++ card->dev = &pdev->dev;
++
++ if (pdev->dev.of_node) {
++ struct snd_soc_dai_link *dai = &audioinjector_pi_soundcard_dai[0];
++ struct device_node *i2s_node = of_parse_phandle(pdev->dev.of_node,
++ "i2s-controller", 0);
++
++ if (i2s_node) {
++ dai->cpu_dai_name = NULL;
++ dai->cpu_of_node = i2s_node;
++ dai->platform_name = NULL;
++ dai->platform_of_node = i2s_node;
++ } else
++ if (!dai->cpu_of_node) {
++ dev_err(&pdev->dev, "Property 'i2s-controller' missing or invalid\n");
++ return -EINVAL;
++ }
++ }
++
++ if ((ret = snd_soc_register_card(card))) {
++ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
++ }
++ return ret;
++}
++
++static int audioinjector_pi_soundcard_remove(struct platform_device *pdev)
++{
++ struct snd_soc_card *card = platform_get_drvdata(pdev);
++ return snd_soc_unregister_card(card);
++
++}
++
++static const struct of_device_id audioinjector_pi_soundcard_of_match[] = {
++ { .compatible = "ai,audioinjector-pi-soundcard", },
++ {},
++};
++MODULE_DEVICE_TABLE(of, audioinjector_pi_soundcard_of_match);
++
++static struct platform_driver audioinjector_pi_soundcard_driver = {
++ .driver = {
++ .name = "audioinjector-audio",
++ .owner = THIS_MODULE,
++ .of_match_table = audioinjector_pi_soundcard_of_match,
++ },
++ .probe = audioinjector_pi_soundcard_probe,
++ .remove = audioinjector_pi_soundcard_remove,
++};
++
++module_platform_driver(audioinjector_pi_soundcard_driver);
++MODULE_AUTHOR("Matt Flax <flatmax@flatmax.org>");
++MODULE_DESCRIPTION("AudioInjector.net Pi Soundcard");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:audioinjector-pi-soundcard");
++
diff --git a/target/linux/brcm2708/patches-4.4/0354-mmc-Apply-QUIRK_BROKEN_ERASE-to-other-capacities.patch b/target/linux/brcm2708/patches-4.4/0354-mmc-Apply-QUIRK_BROKEN_ERASE-to-other-capacities.patch
new file mode 100644
index 0000000000..b1a9e93b9e
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0354-mmc-Apply-QUIRK_BROKEN_ERASE-to-other-capacities.patch
@@ -0,0 +1,23 @@
+From 369e26e925e1075fb57c0b04dde7a77fa7cdeb86 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Thu, 19 May 2016 14:40:28 +0100
+Subject: [PATCH 354/381] mmc: Apply QUIRK_BROKEN_ERASE to other capacities
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/mmc/card/block.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/mmc/card/block.c
++++ b/drivers/mmc/card/block.c
+@@ -2558,6 +2558,10 @@ static const struct mmc_fixup blk_fixups
+ */
+ MMC_FIXUP("SD16G", 0x41, 0x3432, add_quirk_mmc,
+ MMC_QUIRK_ERASE_BROKEN),
++ MMC_FIXUP("SD32G", 0x41, 0x3432, add_quirk_mmc,
++ MMC_QUIRK_ERASE_BROKEN),
++ MMC_FIXUP("SD64G", 0x41, 0x3432, add_quirk_mmc,
++ MMC_QUIRK_ERASE_BROKEN),
+
+ END_FIXUP
+ };
diff --git a/target/linux/brcm2708/patches-4.4/0356-mmc-Add-card_quirks-module-parameter-log-quirks.patch b/target/linux/brcm2708/patches-4.4/0356-mmc-Add-card_quirks-module-parameter-log-quirks.patch
new file mode 100644
index 0000000000..0a3cabec19
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0356-mmc-Add-card_quirks-module-parameter-log-quirks.patch
@@ -0,0 +1,76 @@
+From 07d3cfeff2b06f834132d3593740485c673fbe7d Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 20 May 2016 10:11:43 +0100
+Subject: [PATCH 356/381] mmc: Add card_quirks module parameter, log quirks
+
+Use mmc_block.card_quirks to override the quirks for all SD or MMC
+cards. The value is a bitfield using the bit positions defined in
+include/linux/mmc/card.h. If the module parameter is placed in the
+kernel command line (or bootargs) stored on the card then, assuming the
+device only has one SD card interface, the override effectively becomes
+card-specific.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/mmc/card/block.c | 28 +++++++++++++++++++++++++---
+ 1 file changed, 25 insertions(+), 3 deletions(-)
+
+--- a/drivers/mmc/card/block.c
++++ b/drivers/mmc/card/block.c
+@@ -137,6 +137,13 @@ enum {
+ module_param(perdev_minors, int, 0444);
+ MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device");
+
++/*
++ * Allow quirks to be overridden for the current card
++ */
++static char *card_quirks;
++module_param(card_quirks, charp, 0644);
++MODULE_PARM_DESC(card_quirks, "Force the use of the indicated quirks (a bitfield)");
++
+ static inline int mmc_blk_part_switch(struct mmc_card *card,
+ struct mmc_blk_data *md);
+ static int get_card_status(struct mmc_card *card, u32 *status, int retries);
+@@ -2570,6 +2577,7 @@ static int mmc_blk_probe(struct mmc_card
+ {
+ struct mmc_blk_data *md, *part_md;
+ char cap_str[10];
++ char quirk_str[24];
+
+ /*
+ * Check that the card supports the command class(es) we need.
+@@ -2577,7 +2585,16 @@ static int mmc_blk_probe(struct mmc_card
+ if (!(card->csd.cmdclass & CCC_BLOCK_READ))
+ return -ENODEV;
+
+- mmc_fixup_device(card, blk_fixups);
++ if (card_quirks) {
++ unsigned long quirks;
++ if (kstrtoul(card_quirks, 0, &quirks) == 0)
++ card->quirks = (unsigned int)quirks;
++ else
++ pr_err("mmc_block: Invalid card_quirks parameter '%s'\n",
++ card_quirks);
++ }
++ else
++ mmc_fixup_device(card, blk_fixups);
+
+ md = mmc_blk_alloc(card);
+ if (IS_ERR(md))
+@@ -2585,9 +2602,14 @@ static int mmc_blk_probe(struct mmc_card
+
+ string_get_size((u64)get_capacity(md->disk), 512, STRING_UNITS_2,
+ cap_str, sizeof(cap_str));
+- pr_info("%s: %s %s %s %s\n",
++ if (card->quirks)
++ snprintf(quirk_str, sizeof(quirk_str),
++ " (quirks 0x%08x)", card->quirks);
++ else
++ quirk_str[0] = '\0';
++ pr_info("%s: %s %s %s%s%s\n",
+ md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
+- cap_str, md->read_only ? "(ro)" : "");
++ cap_str, md->read_only ? " (ro)" : "", quirk_str);
+
+ if (mmc_blk_alloc_parts(card, md))
+ goto out;
diff --git a/target/linux/brcm2708/patches-4.4/0357-rtc-ds1307-ensure-that-any-pending-alarm-is-cleared-.patch b/target/linux/brcm2708/patches-4.4/0357-rtc-ds1307-ensure-that-any-pending-alarm-is-cleared-.patch
new file mode 100644
index 0000000000..ca2e4d3310
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0357-rtc-ds1307-ensure-that-any-pending-alarm-is-cleared-.patch
@@ -0,0 +1,58 @@
+From 0d311e4c6e701192c62668665ae1ba25d2219f28 Mon Sep 17 00:00:00 2001
+From: Nicolas Boullis <nboullis@debian.org>
+Date: Sun, 10 Apr 2016 13:23:05 +0200
+Subject: [PATCH 357/381] rtc: ds1307: ensure that any pending alarm is cleared
+ before a new alarm is enabled
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+If a previously-set alarm was disabled and then triggered, it may still
+be pending when a new alarm is configured.
+
+Then, if the alarm is enabled before the pending alarm is cleared, then
+an interrupt is immediately raised.
+
+Unfortunately, when the alarm is cleared and enabled during the same I²C
+block write, the chip (at least the DS1339 I have) considers that the
+alarm is enabled before it is cleared, and raises an interrupt.
+
+This patch ensures that the pending alarm is cleared before the alarm is
+enabled.
+
+Signed-off-by: Nicolas Boullis <nboullis@debian.org>
+Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
+---
+ drivers/rtc/rtc-ds1307.c | 13 ++++++++-----
+ 1 file changed, 8 insertions(+), 5 deletions(-)
+
+--- a/drivers/rtc/rtc-ds1307.c
++++ b/drivers/rtc/rtc-ds1307.c
+@@ -540,12 +540,8 @@ static int ds1337_set_alarm(struct devic
+ buf[5] = 0;
+ buf[6] = 0;
+
+- /* optionally enable ALARM1 */
++ /* disable alarms */
+ buf[7] = control & ~(DS1337_BIT_A1IE | DS1337_BIT_A2IE);
+- if (t->enabled) {
+- dev_dbg(dev, "alarm IRQ armed\n");
+- buf[7] |= DS1337_BIT_A1IE; /* only ALARM1 is used */
+- }
+ buf[8] = status & ~(DS1337_BIT_A1I | DS1337_BIT_A2I);
+
+ ret = ds1307->write_block_data(client,
+@@ -555,6 +551,13 @@ static int ds1337_set_alarm(struct devic
+ return ret;
+ }
+
++ /* optionally enable ALARM1 */
++ if (t->enabled) {
++ dev_dbg(dev, "alarm IRQ armed\n");
++ buf[7] |= DS1337_BIT_A1IE; /* only ALARM1 is used */
++ i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, buf[7]);
++ }
++
+ return 0;
+ }
+
diff --git a/target/linux/brcm2708/patches-4.4/0358-Revert-Revert-drm-vc4-Force-HDMI-to-connected.patch b/target/linux/brcm2708/patches-4.4/0358-Revert-Revert-drm-vc4-Force-HDMI-to-connected.patch
new file mode 100644
index 0000000000..925f7ebca0
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0358-Revert-Revert-drm-vc4-Force-HDMI-to-connected.patch
@@ -0,0 +1,27 @@
+From 303764f1b3db23d37614ab2f8d7ede9b7aa3b5e3 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Mon, 23 May 2016 17:06:08 +0100
+Subject: [PATCH 358/381] Revert "Revert "drm/vc4: Force HDMI to connected.""
+
+This reverts commit 7da44d06540b4a191ecc74e943f3203577fce0df.
+
+This breaks the driver on Pi3 as hotplug is implemented through a
+gpio expander owned by the GPU.
+
+We need to extend the virtual gpio driver to support this, but for
+now assume hotplug is always enabled.
+---
+ drivers/gpu/drm/vc4/vc4_hdmi.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
+@@ -166,6 +166,8 @@ vc4_hdmi_connector_detect(struct drm_con
+ struct drm_device *dev = connector->dev;
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+
++ return connector_status_connected;
++
+ if (vc4->hdmi->hpd_gpio) {
+ if (gpio_get_value_cansleep(vc4->hdmi->hpd_gpio) ^
+ vc4->hdmi->hpd_active_low)
diff --git a/target/linux/brcm2708/patches-4.4/0359-config-Add-NF_MATCH_RPFILTER.patch b/target/linux/brcm2708/patches-4.4/0359-config-Add-NF_MATCH_RPFILTER.patch
new file mode 100644
index 0000000000..2acfbdb74c
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0359-config-Add-NF_MATCH_RPFILTER.patch
@@ -0,0 +1,46 @@
+From 8fe9292801e175098e94b3d7d05077a8d0101aa1 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Mon, 23 May 2016 18:22:52 +0100
+Subject: [PATCH 359/381] config: Add NF_MATCH_RPFILTER
+
+---
+ arch/arm/configs/bcm2709_defconfig | 2 ++
+ arch/arm/configs/bcmrpi_defconfig | 2 ++
+ 2 files changed, 4 insertions(+)
+
+--- a/arch/arm/configs/bcm2709_defconfig
++++ b/arch/arm/configs/bcm2709_defconfig
+@@ -223,6 +223,7 @@ CONFIG_NF_CONNTRACK_IPV4=m
+ CONFIG_IP_NF_IPTABLES=m
+ CONFIG_IP_NF_MATCH_AH=m
+ CONFIG_IP_NF_MATCH_ECN=m
++CONFIG_IP_NF_MATCH_RPFILTER=m
+ CONFIG_IP_NF_MATCH_TTL=m
+ CONFIG_IP_NF_FILTER=m
+ CONFIG_IP_NF_TARGET_REJECT=m
+@@ -247,6 +248,7 @@ CONFIG_IP6_NF_MATCH_OPTS=m
+ CONFIG_IP6_NF_MATCH_HL=m
+ CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+ CONFIG_IP6_NF_MATCH_MH=m
++CONFIG_IP6_NF_MATCH_RPFILTER=m
+ CONFIG_IP6_NF_MATCH_RT=m
+ CONFIG_IP6_NF_TARGET_HL=m
+ CONFIG_IP6_NF_FILTER=m
+--- a/arch/arm/configs/bcmrpi_defconfig
++++ b/arch/arm/configs/bcmrpi_defconfig
+@@ -216,6 +216,7 @@ CONFIG_NF_CONNTRACK_IPV4=m
+ CONFIG_IP_NF_IPTABLES=m
+ CONFIG_IP_NF_MATCH_AH=m
+ CONFIG_IP_NF_MATCH_ECN=m
++CONFIG_IP_NF_MATCH_RPFILTER=m
+ CONFIG_IP_NF_MATCH_TTL=m
+ CONFIG_IP_NF_FILTER=m
+ CONFIG_IP_NF_TARGET_REJECT=m
+@@ -240,6 +241,7 @@ CONFIG_IP6_NF_MATCH_OPTS=m
+ CONFIG_IP6_NF_MATCH_HL=m
+ CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+ CONFIG_IP6_NF_MATCH_MH=m
++CONFIG_IP6_NF_MATCH_RPFILTER=m
+ CONFIG_IP6_NF_MATCH_RT=m
+ CONFIG_IP6_NF_TARGET_HL=m
+ CONFIG_IP6_NF_FILTER=m
diff --git a/target/linux/brcm2708/patches-4.4/0360-Added-Overlay-for-Microchip-MCP23017-I2C-gpio-expand.patch b/target/linux/brcm2708/patches-4.4/0360-Added-Overlay-for-Microchip-MCP23017-I2C-gpio-expand.patch
new file mode 100644
index 0000000000..1df34d0ae1
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0360-Added-Overlay-for-Microchip-MCP23017-I2C-gpio-expand.patch
@@ -0,0 +1,87 @@
+From 55e8faa999c9bf3ae4a3fb75faf5e991167c42ba Mon Sep 17 00:00:00 2001
+From: Michael Kaplan <m.kaplan@evva.com>
+Date: Tue, 24 May 2016 10:19:08 +0200
+Subject: [PATCH 360/381] Added Overlay for Microchip MCP23017 I2C gpio
+ expander
+
+---
+ arch/arm/boot/dts/overlays/README | 9 +++++
+ arch/arm/boot/dts/overlays/mcp23017-overlay.dts | 54 +++++++++++++++++++++++++
+ 2 files changed, 63 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/mcp23017-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -567,6 +567,15 @@ Params: gpio_out_pin GPIO for
+ (default "off")
+
+
++Name: mcp23017
++Info: Configures the MCP23017 I2C port expander
++Load: dtoverlay=mcp23017,<param>=<val>
++Params: gpiopin Gpio pin connected to the INTA output of the
++ MCP23017 (default: 4)
++
++ addr I2C address of the MCP23017 (default: 0x20)
++
++
+ Name: mcp2515-can0
+ Info: Configures the MCP2515 CAN controller on spi0.0
+ Load: dtoverlay=mcp2515-can0,<param>=<val>
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/mcp23017-overlay.dts
+@@ -0,0 +1,54 @@
++// Definitions for MCP23017 Gpio Extender from Microchip Semiconductor
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++
++ fragment@0 {
++ target = <&i2c1>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ mcp23017_pins: mcp23017_pins {
++ brcm,pins = <4>;
++ brcm,function = <0>;
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ mcp23017: mcp@20 {
++ compatible = "microchip,mcp23017";
++ reg = <0x20>;
++ gpio-controller;
++ #gpio-cells = <2>;
++ #interrupt-cells=<2>;
++ interrupt-parent = <&gpio>;
++ interrupts = <4 2>;
++ interrupt-controller;
++ microchip,irq-mirror;
++
++ status = "okay";
++ };
++ };
++ };
++
++ __overrides__ {
++ gpiopin = <&mcp23017_pins>,"brcm,pins:0",
++ <&mcp23017>,"interrupts:0";
++ addr = <&mcp23017>,"reg:0";
++ };
++};
++
diff --git a/target/linux/brcm2708/patches-4.4/0361-bcm2835-camera-Fix-max-min-error-when-looping-over-c.patch b/target/linux/brcm2708/patches-4.4/0361-bcm2835-camera-Fix-max-min-error-when-looping-over-c.patch
new file mode 100644
index 0000000000..581e64c7b3
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0361-bcm2835-camera-Fix-max-min-error-when-looping-over-c.patch
@@ -0,0 +1,24 @@
+From 1b3640fb2ba49dcf0ece68e61e97be6bde0c2e5a Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Tue, 24 May 2016 16:20:09 +0100
+Subject: [PATCH 361/381] bcm2835-camera: Fix max/min error when looping over
+ cameras/resolutions
+
+See: https://github.com/raspberrypi/linux/issues/1447#issuecomment-221303506
+---
+ drivers/media/platform/bcm2835/bcm2835-camera.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/media/platform/bcm2835/bcm2835-camera.c
++++ b/drivers/media/platform/bcm2835/bcm2835-camera.c
+@@ -1530,8 +1530,8 @@ static int get_num_cameras(struct vchiq_
+ }
+ for (i = 0;
+ i < (cam_info.num_cameras > num_resolutions ?
+- cam_info.num_cameras :
+- num_resolutions);
++ num_resolutions :
++ cam_info.num_cameras);
+ i++) {
+ resolutions[i][0] = cam_info.cameras[i].max_width;
+ resolutions[i][1] = cam_info.cameras[i].max_height;
diff --git a/target/linux/brcm2708/patches-4.4/0362-Change-BoomBerry-name-to-JustBoom-in-all-locations-d.patch b/target/linux/brcm2708/patches-4.4/0362-Change-BoomBerry-name-to-JustBoom-in-all-locations-d.patch
new file mode 100644
index 0000000000..f322429078
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0362-Change-BoomBerry-name-to-JustBoom-in-all-locations-d.patch
@@ -0,0 +1,1139 @@
+From 472fd91e090c8417770687a393f252f834d26ac5 Mon Sep 17 00:00:00 2001
+From: Aaron Shaw <shawaj@gmail.com>
+Date: Thu, 26 May 2016 23:37:11 +0100
+Subject: [PATCH 362/381] Change BoomBerry name to JustBoom in all locations
+ due to legal challenge
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 4 +-
+ arch/arm/boot/dts/overlays/README | 52 ++---
+ .../boot/dts/overlays/boomberry-dac-overlay.dts | 43 -----
+ .../boot/dts/overlays/boomberry-digi-overlay.dts | 39 ----
+ .../arm/boot/dts/overlays/justboom-dac-overlay.dts | 43 +++++
+ .../boot/dts/overlays/justboom-digi-overlay.dts | 39 ++++
+ arch/arm/configs/bcm2709_defconfig | 4 +-
+ arch/arm/configs/bcmrpi_defconfig | 4 +-
+ sound/soc/bcm/Kconfig | 12 +-
+ sound/soc/bcm/Makefile | 8 +-
+ sound/soc/bcm/boomberry-dac.c | 162 ----------------
+ sound/soc/bcm/boomberry-digi.c | 215 ---------------------
+ sound/soc/bcm/justboom-dac.c | 162 ++++++++++++++++
+ sound/soc/bcm/justboom-digi.c | 215 +++++++++++++++++++++
+ 14 files changed, 501 insertions(+), 501 deletions(-)
+ delete mode 100644 arch/arm/boot/dts/overlays/boomberry-dac-overlay.dts
+ delete mode 100644 arch/arm/boot/dts/overlays/boomberry-digi-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/justboom-dac-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/justboom-digi-overlay.dts
+ delete mode 100644 sound/soc/bcm/boomberry-dac.c
+ delete mode 100644 sound/soc/bcm/boomberry-digi.c
+ create mode 100644 sound/soc/bcm/justboom-dac.c
+ create mode 100644 sound/soc/bcm/justboom-digi.c
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -18,8 +18,6 @@ dtbo-$(RPI_DT_OVERLAYS) += akkordion-iqd
+ dtbo-$(RPI_DT_OVERLAYS) += at86rf233.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += audioinjector-wm8731-audio.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += bmp085_i2c-sensor.dtbo
+-dtbo-$(RPI_DT_OVERLAYS) += boomberry-dac.dtbo
+-dtbo-$(RPI_DT_OVERLAYS) += boomberry-digi.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += dpi24.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += dwc2.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += dwc-otg.dtbo
+@@ -43,6 +41,8 @@ dtbo-$(RPI_DT_OVERLAYS) += i2s-gpio28-31
+ dtbo-$(RPI_DT_OVERLAYS) += i2s-mmap.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += iqaudio-dac.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += iqaudio-dacplus.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += justboom-dac.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += justboom-digi.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += lirc-rpi.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += mcp2515-can0.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += mcp2515-can1.dtbo
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -238,32 +238,6 @@ Load: dtoverlay=bmp085_i2c-sensor
+ Params: <None>
+
+
+-Name: boomberry-dac
+-Info: Configures the BoomBerry DAC HAT, Amp HAT, DAC Zero and Amp Zero audio
+- cards
+-Load: dtoverlay=boomberry-dac,<param>=<val>
+-Params: 24db_digital_gain Allow gain to be applied via the PCM512x codec
+- Digital volume control. Enable with
+- "dtoverlay=boomberry-dac,24db_digital_gain"
+- (The default behaviour is that the Digital
+- volume control is limited to a maximum of
+- 0dB. ie. it can attenuate but not provide
+- gain. For most users, this will be desired
+- as it will prevent clipping. By appending
+- the 24dB_digital_gain parameter, the Digital
+- volume control will allow up to 24dB of
+- gain. If this parameter is enabled, it is the
+- responsibility of the user to ensure that
+- the Digital volume control is set to a value
+- that does not result in clipping/distortion!)
+-
+-
+-Name: boomberry-digi
+-Info: Configures the BoomBerry Digi HAT and Digi Zero audio cards
+-Load: dtoverlay=boomberry-digi
+-Params: <None>
+-
+-
+ Name: dht11
+ Info: Overlay for the DHT11/DHT21/DHT22 humidity/temperature sensors
+ Also sometimes found with the part number(s) AM230x.
+@@ -541,6 +515,32 @@ Params: 24db_digital_gain Allow ga
+ that does not result in clipping/distortion!)
+
+
++Name: justboom-dac
++Info: Configures the JustBoom DAC HAT, Amp HAT, DAC Zero and Amp Zero audio
++ cards
++Load: dtoverlay=justboom-dac,<param>=<val>
++Params: 24db_digital_gain Allow gain to be applied via the PCM512x codec
++ Digital volume control. Enable with
++ "dtoverlay=justboom-dac,24db_digital_gain"
++ (The default behaviour is that the Digital
++ volume control is limited to a maximum of
++ 0dB. ie. it can attenuate but not provide
++ gain. For most users, this will be desired
++ as it will prevent clipping. By appending
++ the 24dB_digital_gain parameter, the Digital
++ volume control will allow up to 24dB of
++ gain. If this parameter is enabled, it is the
++ responsibility of the user to ensure that
++ the Digital volume control is set to a value
++ that does not result in clipping/distortion!)
++
++
++Name: justboom-digi
++Info: Configures the JustBoom Digi HAT and Digi Zero audio cards
++Load: dtoverlay=justboom-digi
++Params: <None>
++
++
+ Name: lirc-rpi
+ Info: Configures lirc-rpi (Linux Infrared Remote Control for Raspberry Pi)
+ Consult the module documentation for more details.
+--- a/arch/arm/boot/dts/overlays/boomberry-dac-overlay.dts
++++ /dev/null
+@@ -1,43 +0,0 @@
+-// Definitions for BoomBerry DAC
+-/dts-v1/;
+-/plugin/;
+-
+-/ {
+- compatible = "brcm,bcm2708";
+-
+- fragment@0 {
+- target = <&i2s>;
+- __overlay__ {
+- status = "okay";
+- };
+- };
+-
+- fragment@1 {
+- target = <&i2c1>;
+- __overlay__ {
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "okay";
+-
+- pcm5122@4d {
+- #sound-dai-cells = <0>;
+- compatible = "ti,pcm5122";
+- reg = <0x4d>;
+- status = "okay";
+- };
+- };
+- };
+-
+- fragment@2 {
+- target = <&sound>;
+- frag2: __overlay__ {
+- compatible = "boomberry,boomberry-dac";
+- i2s-controller = <&i2s>;
+- status = "okay";
+- };
+- };
+-
+- __overrides__ {
+- 24db_digital_gain = <&frag2>,"boomberry,24db_digital_gain?";
+- };
+-};
+--- a/arch/arm/boot/dts/overlays/boomberry-digi-overlay.dts
++++ /dev/null
+@@ -1,39 +0,0 @@
+-// Definitions for BoomBerry Digi
+-/dts-v1/;
+-/plugin/;
+-
+-/ {
+- compatible = "brcm,bcm2708";
+-
+- fragment@0 {
+- target = <&i2s>;
+- __overlay__ {
+- status = "okay";
+- };
+- };
+-
+- fragment@1 {
+- target = <&i2c1>;
+- __overlay__ {
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "okay";
+-
+- wm8804@3b {
+- #sound-dai-cells = <0>;
+- compatible = "wlf,wm8804";
+- reg = <0x3b>;
+- status = "okay";
+- };
+- };
+- };
+-
+- fragment@2 {
+- target = <&sound>;
+- __overlay__ {
+- compatible = "boomberry,boomberry-digi";
+- i2s-controller = <&i2s>;
+- status = "okay";
+- };
+- };
+-};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/justboom-dac-overlay.dts
+@@ -0,0 +1,43 @@
++// Definitions for JustBoom DAC
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&i2s>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ pcm5122@4d {
++ #sound-dai-cells = <0>;
++ compatible = "ti,pcm5122";
++ reg = <0x4d>;
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&sound>;
++ frag2: __overlay__ {
++ compatible = "justboom,justboom-dac";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
++
++ __overrides__ {
++ 24db_digital_gain = <&frag2>,"justboom,24db_digital_gain?";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/justboom-digi-overlay.dts
+@@ -0,0 +1,39 @@
++// Definitions for JustBoom Digi
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&i2s>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ wm8804@3b {
++ #sound-dai-cells = <0>;
++ compatible = "wlf,wm8804";
++ reg = <0x3b>;
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&sound>;
++ __overlay__ {
++ compatible = "justboom,justboom-digi";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
++};
+--- a/arch/arm/configs/bcm2709_defconfig
++++ b/arch/arm/configs/bcm2709_defconfig
+@@ -861,8 +861,8 @@ CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI=m
+ CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP=m
+ CONFIG_SND_BCM2708_SOC_RPI_DAC=m
+ CONFIG_SND_BCM2708_SOC_RPI_PROTO=m
+-CONFIG_SND_BCM2708_SOC_BOOMBERRY_DAC=m
+-CONFIG_SND_BCM2708_SOC_BOOMBERRY_DIGI=m
++CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC=m
++CONFIG_SND_BCM2708_SOC_JUSTBOOM_DIGI=m
+ CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m
+ CONFIG_SND_BCM2708_SOC_RASPIDAC3=m
+ CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD=m
+--- a/arch/arm/configs/bcmrpi_defconfig
++++ b/arch/arm/configs/bcmrpi_defconfig
+@@ -853,8 +853,8 @@ CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI=m
+ CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP=m
+ CONFIG_SND_BCM2708_SOC_RPI_DAC=m
+ CONFIG_SND_BCM2708_SOC_RPI_PROTO=m
+-CONFIG_SND_BCM2708_SOC_BOOMBERRY_DAC=m
+-CONFIG_SND_BCM2708_SOC_BOOMBERRY_DIGI=m
++CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC=m
++CONFIG_SND_BCM2708_SOC_JUSTBOOM_DIGI=m
+ CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m
+ CONFIG_SND_BCM2708_SOC_RASPIDAC3=m
+ CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD=m
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -50,19 +50,19 @@ config SND_BCM2708_SOC_RPI_PROTO
+ help
+ Say Y or M if you want to add support for Audio Codec Board PROTO (WM8731).
+
+-config SND_BCM2708_SOC_BOOMBERRY_DAC
+- tristate "Support for BoomBerry DAC"
++config SND_BCM2708_SOC_JUSTBOOM_DAC
++ tristate "Support for JustBoom DAC"
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+ select SND_SOC_PCM512x
+ help
+- Say Y or M if you want to add support for BoomBerry DAC.
++ Say Y or M if you want to add support for JustBoom DAC.
+
+-config SND_BCM2708_SOC_BOOMBERRY_DIGI
+- tristate "Support for BoomBerry Digi"
++config SND_BCM2708_SOC_JUSTBOOM_DIGI
++ tristate "Support for JustBoom Digi"
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+ select SND_SOC_WM8804
+ help
+- Say Y or M if you want to add support for BoomBerry Digi.
++ Say Y or M if you want to add support for JustBoom Digi.
+
+ config SND_BCM2708_SOC_IQAUDIO_DAC
+ tristate "Support for IQaudIO-DAC"
+--- a/sound/soc/bcm/Makefile
++++ b/sound/soc/bcm/Makefile
+@@ -9,8 +9,8 @@ snd-soc-hifiberry-dac-objs := hifiberry_
+ snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
+ snd-soc-hifiberry-digi-objs := hifiberry_digi.o
+ snd-soc-hifiberry-amp-objs := hifiberry_amp.o
+-snd-soc-boomberry-dac-objs := boomberry-dac.o
+-snd-soc-boomberry-digi-objs := boomberry-digi.o
++snd-soc-justboom-dac-objs := justboom-dac.o
++snd-soc-justboom-digi-objs := justboom-digi.o
+ snd-soc-rpi-dac-objs := rpi-dac.o
+ snd-soc-rpi-proto-objs := rpi-proto.o
+ snd-soc-iqaudio-dac-objs := iqaudio-dac.o
+@@ -22,8 +22,8 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_D
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o
+-obj-$(CONFIG_SND_BCM2708_SOC_BOOMBERRY_DAC) += snd-soc-boomberry-dac.o
+-obj-$(CONFIG_SND_BCM2708_SOC_BOOMBERRY_DIGI) += snd-soc-boomberry-digi.o
++obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o
++obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DIGI) += snd-soc-justboom-digi.o
+ obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o
+ obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
+ obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
+--- a/sound/soc/bcm/boomberry-dac.c
++++ /dev/null
+@@ -1,162 +0,0 @@
+-/*
+- * ASoC Driver for BoomBerry DAC Raspberry Pi HAT Sound Card
+- *
+- * Author: Milan Neskovic
+- * Copyright 2016
+- * based on code by Daniel Matuschek <info@crazy-audio.com>
+- * based on code by Florian Meier <florian.meier@koalo.de>
+- *
+- * This program is free software; you can redistribute it and/or
+- * modify it under the terms of the GNU General Public License
+- * version 2 as published by the Free Software Foundation.
+- *
+- * This program is distributed in the hope that it will be useful, but
+- * WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- * General Public License for more details.
+- */
+-
+-#include <linux/module.h>
+-#include <linux/platform_device.h>
+-
+-#include <sound/core.h>
+-#include <sound/pcm.h>
+-#include <sound/pcm_params.h>
+-#include <sound/soc.h>
+-#include <sound/jack.h>
+-
+-#include "../codecs/pcm512x.h"
+-
+-static bool digital_gain_0db_limit = true;
+-
+-static int snd_rpi_boomberry_dac_init(struct snd_soc_pcm_runtime *rtd)
+-{
+- struct snd_soc_codec *codec = rtd->codec;
+- snd_soc_update_bits(codec, PCM512x_GPIO_EN, 0x08, 0x08);
+- snd_soc_update_bits(codec, PCM512x_GPIO_OUTPUT_4, 0xf, 0x02);
+- snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08,0x08);
+-
+- if (digital_gain_0db_limit)
+- {
+- int ret;
+- struct snd_soc_card *card = rtd->card;
+-
+- ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207);
+- if (ret < 0)
+- dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
+- }
+-
+- return 0;
+-}
+-
+-static int snd_rpi_boomberry_dac_hw_params(struct snd_pcm_substream *substream,
+- struct snd_pcm_hw_params *params)
+-{
+- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+- /*return snd_soc_dai_set_bclk_ratio(cpu_dai, 64);*/
+- unsigned int sample_bits =
+- snd_pcm_format_physical_width(params_format(params));
+- return snd_soc_dai_set_bclk_ratio(cpu_dai, sample_bits * 2);
+-}
+-
+-static int snd_rpi_boomberry_dac_startup(struct snd_pcm_substream *substream) {
+- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+- struct snd_soc_codec *codec = rtd->codec;
+- snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08,0x08);
+- return 0;
+-}
+-
+-static void snd_rpi_boomberry_dac_shutdown(struct snd_pcm_substream *substream) {
+- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+- struct snd_soc_codec *codec = rtd->codec;
+- snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08,0x00);
+-}
+-
+-/* machine stream operations */
+-static struct snd_soc_ops snd_rpi_boomberry_dac_ops = {
+- .hw_params = snd_rpi_boomberry_dac_hw_params,
+- .startup = snd_rpi_boomberry_dac_startup,
+- .shutdown = snd_rpi_boomberry_dac_shutdown,
+-};
+-
+-static struct snd_soc_dai_link snd_rpi_boomberry_dac_dai[] = {
+-{
+- .name = "BoomBerry DAC",
+- .stream_name = "BoomBerry DAC HiFi",
+- .cpu_dai_name = "bcm2708-i2s.0",
+- .codec_dai_name = "pcm512x-hifi",
+- .platform_name = "bcm2708-i2s.0",
+- .codec_name = "pcm512x.1-004d",
+- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+- SND_SOC_DAIFMT_CBS_CFS,
+- .ops = &snd_rpi_boomberry_dac_ops,
+- .init = snd_rpi_boomberry_dac_init,
+-},
+-};
+-
+-/* audio machine driver */
+-static struct snd_soc_card snd_rpi_boomberry_dac = {
+- .name = "snd_rpi_boomberry_dac",
+- .owner = THIS_MODULE,
+- .dai_link = snd_rpi_boomberry_dac_dai,
+- .num_links = ARRAY_SIZE(snd_rpi_boomberry_dac_dai),
+-};
+-
+-static int snd_rpi_boomberry_dac_probe(struct platform_device *pdev)
+-{
+- int ret = 0;
+-
+- snd_rpi_boomberry_dac.dev = &pdev->dev;
+-
+- if (pdev->dev.of_node) {
+- struct device_node *i2s_node;
+- struct snd_soc_dai_link *dai = &snd_rpi_boomberry_dac_dai[0];
+- i2s_node = of_parse_phandle(pdev->dev.of_node,
+- "i2s-controller", 0);
+-
+- if (i2s_node) {
+- dai->cpu_dai_name = NULL;
+- dai->cpu_of_node = i2s_node;
+- dai->platform_name = NULL;
+- dai->platform_of_node = i2s_node;
+- }
+-
+- digital_gain_0db_limit = !of_property_read_bool(
+- pdev->dev.of_node, "boomberry,24db_digital_gain");
+- }
+-
+- ret = snd_soc_register_card(&snd_rpi_boomberry_dac);
+- if (ret)
+- dev_err(&pdev->dev,
+- "snd_soc_register_card() failed: %d\n", ret);
+-
+- return ret;
+-}
+-
+-static int snd_rpi_boomberry_dac_remove(struct platform_device *pdev)
+-{
+- return snd_soc_unregister_card(&snd_rpi_boomberry_dac);
+-}
+-
+-static const struct of_device_id snd_rpi_boomberry_dac_of_match[] = {
+- { .compatible = "boomberry,boomberry-dac", },
+- {},
+-};
+-MODULE_DEVICE_TABLE(of, snd_rpi_boomberry_dac_of_match);
+-
+-static struct platform_driver snd_rpi_boomberry_dac_driver = {
+- .driver = {
+- .name = "snd-rpi-boomberry-dac",
+- .owner = THIS_MODULE,
+- .of_match_table = snd_rpi_boomberry_dac_of_match,
+- },
+- .probe = snd_rpi_boomberry_dac_probe,
+- .remove = snd_rpi_boomberry_dac_remove,
+-};
+-
+-module_platform_driver(snd_rpi_boomberry_dac_driver);
+-
+-MODULE_AUTHOR("Milan Neskovic <info@boomberry.co>");
+-MODULE_DESCRIPTION("ASoC Driver for BoomBerry PI DAC HAT Sound Card");
+-MODULE_LICENSE("GPL v2");
+--- a/sound/soc/bcm/boomberry-digi.c
++++ /dev/null
+@@ -1,215 +0,0 @@
+-/*
+- * ASoC Driver for BoomBerry Raspberry Pi Digi HAT Sound Card
+- *
+- * Author: Milan Neskovic
+- * Copyright 2016
+- * based on code by Daniel Matuschek <info@crazy-audio.com>
+- * based on code by Florian Meier <florian.meier@koalo.de>
+- *
+- * This program is free software; you can redistribute it and/or
+- * modify it under the terms of the GNU General Public License
+- * version 2 as published by the Free Software Foundation.
+- *
+- * This program is distributed in the hope that it will be useful, but
+- * WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- * General Public License for more details.
+- */
+-
+-#include <linux/module.h>
+-#include <linux/platform_device.h>
+-
+-#include <sound/core.h>
+-#include <sound/pcm.h>
+-#include <sound/pcm_params.h>
+-#include <sound/soc.h>
+-#include <sound/jack.h>
+-
+-#include "../codecs/wm8804.h"
+-
+-static int snd_rpi_boomberry_digi_init(struct snd_soc_pcm_runtime *rtd)
+-{
+- struct snd_soc_codec *codec = rtd->codec;
+-
+- /* enable TX output */
+- snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, 0x0);
+-
+- return 0;
+-}
+-
+-static int snd_rpi_boomberry_digi_startup(struct snd_pcm_substream *substream) {
+- /* turn on digital output */
+- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+- struct snd_soc_codec *codec = rtd->codec;
+- snd_soc_update_bits(codec, WM8804_PWRDN, 0x3c, 0x00);
+- return 0;
+-}
+-
+-static void snd_rpi_boomberry_digi_shutdown(struct snd_pcm_substream *substream) {
+- /* turn off output */
+- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+- struct snd_soc_codec *codec = rtd->codec;
+- snd_soc_update_bits(codec, WM8804_PWRDN, 0x3c, 0x3c);
+-}
+-
+-static int snd_rpi_boomberry_digi_hw_params(struct snd_pcm_substream *substream,
+- struct snd_pcm_hw_params *params)
+-{
+- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+- struct snd_soc_dai *codec_dai = rtd->codec_dai;
+- struct snd_soc_codec *codec = rtd->codec;
+- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+-
+- int sysclk = 27000000; /* This is fixed on this board */
+-
+- long mclk_freq=0;
+- int mclk_div=1;
+- int sampling_freq=1;
+-
+- int ret;
+-
+- int samplerate = params_rate(params);
+-
+- if (samplerate<=96000) {
+- mclk_freq=samplerate*256;
+- mclk_div=WM8804_MCLKDIV_256FS;
+- } else {
+- mclk_freq=samplerate*128;
+- mclk_div=WM8804_MCLKDIV_128FS;
+- }
+-
+- switch (samplerate) {
+- case 32000:
+- sampling_freq=0x03;
+- break;
+- case 44100:
+- sampling_freq=0x00;
+- break;
+- case 48000:
+- sampling_freq=0x02;
+- break;
+- case 88200:
+- sampling_freq=0x08;
+- break;
+- case 96000:
+- sampling_freq=0x0a;
+- break;
+- case 176400:
+- sampling_freq=0x0c;
+- break;
+- case 192000:
+- sampling_freq=0x0e;
+- break;
+- default:
+- dev_err(codec->dev,
+- "Failed to set WM8804 SYSCLK, unsupported samplerate %d\n",
+- samplerate);
+- }
+-
+- snd_soc_dai_set_clkdiv(codec_dai, WM8804_MCLK_DIV, mclk_div);
+- snd_soc_dai_set_pll(codec_dai, 0, 0, sysclk, mclk_freq);
+-
+- ret = snd_soc_dai_set_sysclk(codec_dai, WM8804_TX_CLKSRC_PLL,
+- sysclk, SND_SOC_CLOCK_OUT);
+- if (ret < 0) {
+- dev_err(codec->dev,
+- "Failed to set WM8804 SYSCLK: %d\n", ret);
+- return ret;
+- }
+-
+- /* Enable TX output */
+- snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, 0x0);
+-
+- /* Power on */
+- snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0);
+-
+- /* set sampling frequency status bits */
+- snd_soc_update_bits(codec, WM8804_SPDTX4, 0x0f, sampling_freq);
+-
+- return snd_soc_dai_set_bclk_ratio(cpu_dai,64);
+-}
+-
+-/* machine stream operations */
+-static struct snd_soc_ops snd_rpi_boomberry_digi_ops = {
+- .hw_params = snd_rpi_boomberry_digi_hw_params,
+- .startup = snd_rpi_boomberry_digi_startup,
+- .shutdown = snd_rpi_boomberry_digi_shutdown,
+-};
+-
+-static struct snd_soc_dai_link snd_rpi_boomberry_digi_dai[] = {
+-{
+- .name = "BoomBerry Digi",
+- .stream_name = "BoomBerry Digi HiFi",
+- .cpu_dai_name = "bcm2708-i2s.0",
+- .codec_dai_name = "wm8804-spdif",
+- .platform_name = "bcm2708-i2s.0",
+- .codec_name = "wm8804.1-003b",
+- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+- SND_SOC_DAIFMT_CBM_CFM,
+- .ops = &snd_rpi_boomberry_digi_ops,
+- .init = snd_rpi_boomberry_digi_init,
+-},
+-};
+-
+-/* audio machine driver */
+-static struct snd_soc_card snd_rpi_boomberry_digi = {
+- .name = "snd_rpi_boomberry_digi",
+- .owner = THIS_MODULE,
+- .dai_link = snd_rpi_boomberry_digi_dai,
+- .num_links = ARRAY_SIZE(snd_rpi_boomberry_digi_dai),
+-};
+-
+-static int snd_rpi_boomberry_digi_probe(struct platform_device *pdev)
+-{
+- int ret = 0;
+-
+- snd_rpi_boomberry_digi.dev = &pdev->dev;
+-
+- if (pdev->dev.of_node) {
+- struct device_node *i2s_node;
+- struct snd_soc_dai_link *dai = &snd_rpi_boomberry_digi_dai[0];
+- i2s_node = of_parse_phandle(pdev->dev.of_node,
+- "i2s-controller", 0);
+-
+- if (i2s_node) {
+- dai->cpu_dai_name = NULL;
+- dai->cpu_of_node = i2s_node;
+- dai->platform_name = NULL;
+- dai->platform_of_node = i2s_node;
+- }
+- }
+-
+- ret = snd_soc_register_card(&snd_rpi_boomberry_digi);
+- if (ret)
+- dev_err(&pdev->dev,
+- "snd_soc_register_card() failed: %d\n", ret);
+-
+- return ret;
+-}
+-
+-static int snd_rpi_boomberry_digi_remove(struct platform_device *pdev)
+-{
+- return snd_soc_unregister_card(&snd_rpi_boomberry_digi);
+-}
+-
+-static const struct of_device_id snd_rpi_boomberry_digi_of_match[] = {
+- { .compatible = "boomberry,boomberry-digi", },
+- {},
+-};
+-MODULE_DEVICE_TABLE(of, snd_rpi_boomberry_digi_of_match);
+-
+-static struct platform_driver snd_rpi_boomberry_digi_driver = {
+- .driver = {
+- .name = "snd-rpi-boomberry-digi",
+- .owner = THIS_MODULE,
+- .of_match_table = snd_rpi_boomberry_digi_of_match,
+- },
+- .probe = snd_rpi_boomberry_digi_probe,
+- .remove = snd_rpi_boomberry_digi_remove,
+-};
+-
+-module_platform_driver(snd_rpi_boomberry_digi_driver);
+-
+-MODULE_AUTHOR("Milan Neskovic <info@boomberry.co>");
+-MODULE_DESCRIPTION("ASoC Driver for BoomBerry PI Digi HAT Sound Card");
+-MODULE_LICENSE("GPL v2");
+--- /dev/null
++++ b/sound/soc/bcm/justboom-dac.c
+@@ -0,0 +1,162 @@
++/*
++ * ASoC Driver for JustBoom DAC Raspberry Pi HAT Sound Card
++ *
++ * Author: Milan Neskovic
++ * Copyright 2016
++ * based on code by Daniel Matuschek <info@crazy-audio.com>
++ * based on code by Florian Meier <florian.meier@koalo.de>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/jack.h>
++
++#include "../codecs/pcm512x.h"
++
++static bool digital_gain_0db_limit = true;
++
++static int snd_rpi_justboom_dac_init(struct snd_soc_pcm_runtime *rtd)
++{
++ struct snd_soc_codec *codec = rtd->codec;
++ snd_soc_update_bits(codec, PCM512x_GPIO_EN, 0x08, 0x08);
++ snd_soc_update_bits(codec, PCM512x_GPIO_OUTPUT_4, 0xf, 0x02);
++ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08,0x08);
++
++ if (digital_gain_0db_limit)
++ {
++ int ret;
++ struct snd_soc_card *card = rtd->card;
++
++ ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207);
++ if (ret < 0)
++ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
++ }
++
++ return 0;
++}
++
++static int snd_rpi_justboom_dac_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
++ /*return snd_soc_dai_set_bclk_ratio(cpu_dai, 64);*/
++ unsigned int sample_bits =
++ snd_pcm_format_physical_width(params_format(params));
++ return snd_soc_dai_set_bclk_ratio(cpu_dai, sample_bits * 2);
++}
++
++static int snd_rpi_justboom_dac_startup(struct snd_pcm_substream *substream) {
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_codec *codec = rtd->codec;
++ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08,0x08);
++ return 0;
++}
++
++static void snd_rpi_justboom_dac_shutdown(struct snd_pcm_substream *substream) {
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_codec *codec = rtd->codec;
++ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08,0x00);
++}
++
++/* machine stream operations */
++static struct snd_soc_ops snd_rpi_justboom_dac_ops = {
++ .hw_params = snd_rpi_justboom_dac_hw_params,
++ .startup = snd_rpi_justboom_dac_startup,
++ .shutdown = snd_rpi_justboom_dac_shutdown,
++};
++
++static struct snd_soc_dai_link snd_rpi_justboom_dac_dai[] = {
++{
++ .name = "JustBoom DAC",
++ .stream_name = "JustBoom DAC HiFi",
++ .cpu_dai_name = "bcm2708-i2s.0",
++ .codec_dai_name = "pcm512x-hifi",
++ .platform_name = "bcm2708-i2s.0",
++ .codec_name = "pcm512x.1-004d",
++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBS_CFS,
++ .ops = &snd_rpi_justboom_dac_ops,
++ .init = snd_rpi_justboom_dac_init,
++},
++};
++
++/* audio machine driver */
++static struct snd_soc_card snd_rpi_justboom_dac = {
++ .name = "snd_rpi_justboom_dac",
++ .owner = THIS_MODULE,
++ .dai_link = snd_rpi_justboom_dac_dai,
++ .num_links = ARRAY_SIZE(snd_rpi_justboom_dac_dai),
++};
++
++static int snd_rpi_justboom_dac_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++
++ snd_rpi_justboom_dac.dev = &pdev->dev;
++
++ if (pdev->dev.of_node) {
++ struct device_node *i2s_node;
++ struct snd_soc_dai_link *dai = &snd_rpi_justboom_dac_dai[0];
++ i2s_node = of_parse_phandle(pdev->dev.of_node,
++ "i2s-controller", 0);
++
++ if (i2s_node) {
++ dai->cpu_dai_name = NULL;
++ dai->cpu_of_node = i2s_node;
++ dai->platform_name = NULL;
++ dai->platform_of_node = i2s_node;
++ }
++
++ digital_gain_0db_limit = !of_property_read_bool(
++ pdev->dev.of_node, "justboom,24db_digital_gain");
++ }
++
++ ret = snd_soc_register_card(&snd_rpi_justboom_dac);
++ if (ret)
++ dev_err(&pdev->dev,
++ "snd_soc_register_card() failed: %d\n", ret);
++
++ return ret;
++}
++
++static int snd_rpi_justboom_dac_remove(struct platform_device *pdev)
++{
++ return snd_soc_unregister_card(&snd_rpi_justboom_dac);
++}
++
++static const struct of_device_id snd_rpi_justboom_dac_of_match[] = {
++ { .compatible = "justboom,justboom-dac", },
++ {},
++};
++MODULE_DEVICE_TABLE(of, snd_rpi_justboom_dac_of_match);
++
++static struct platform_driver snd_rpi_justboom_dac_driver = {
++ .driver = {
++ .name = "snd-rpi-justboom-dac",
++ .owner = THIS_MODULE,
++ .of_match_table = snd_rpi_justboom_dac_of_match,
++ },
++ .probe = snd_rpi_justboom_dac_probe,
++ .remove = snd_rpi_justboom_dac_remove,
++};
++
++module_platform_driver(snd_rpi_justboom_dac_driver);
++
++MODULE_AUTHOR("Milan Neskovic <info@justboom.co>");
++MODULE_DESCRIPTION("ASoC Driver for JustBoom PI DAC HAT Sound Card");
++MODULE_LICENSE("GPL v2");
+--- /dev/null
++++ b/sound/soc/bcm/justboom-digi.c
+@@ -0,0 +1,215 @@
++/*
++ * ASoC Driver for JustBoom Raspberry Pi Digi HAT Sound Card
++ *
++ * Author: Milan Neskovic
++ * Copyright 2016
++ * based on code by Daniel Matuschek <info@crazy-audio.com>
++ * based on code by Florian Meier <florian.meier@koalo.de>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/jack.h>
++
++#include "../codecs/wm8804.h"
++
++static int snd_rpi_justboom_digi_init(struct snd_soc_pcm_runtime *rtd)
++{
++ struct snd_soc_codec *codec = rtd->codec;
++
++ /* enable TX output */
++ snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, 0x0);
++
++ return 0;
++}
++
++static int snd_rpi_justboom_digi_startup(struct snd_pcm_substream *substream) {
++ /* turn on digital output */
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_codec *codec = rtd->codec;
++ snd_soc_update_bits(codec, WM8804_PWRDN, 0x3c, 0x00);
++ return 0;
++}
++
++static void snd_rpi_justboom_digi_shutdown(struct snd_pcm_substream *substream) {
++ /* turn off output */
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_codec *codec = rtd->codec;
++ snd_soc_update_bits(codec, WM8804_PWRDN, 0x3c, 0x3c);
++}
++
++static int snd_rpi_justboom_digi_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_dai *codec_dai = rtd->codec_dai;
++ struct snd_soc_codec *codec = rtd->codec;
++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
++
++ int sysclk = 27000000; /* This is fixed on this board */
++
++ long mclk_freq=0;
++ int mclk_div=1;
++ int sampling_freq=1;
++
++ int ret;
++
++ int samplerate = params_rate(params);
++
++ if (samplerate<=96000) {
++ mclk_freq=samplerate*256;
++ mclk_div=WM8804_MCLKDIV_256FS;
++ } else {
++ mclk_freq=samplerate*128;
++ mclk_div=WM8804_MCLKDIV_128FS;
++ }
++
++ switch (samplerate) {
++ case 32000:
++ sampling_freq=0x03;
++ break;
++ case 44100:
++ sampling_freq=0x00;
++ break;
++ case 48000:
++ sampling_freq=0x02;
++ break;
++ case 88200:
++ sampling_freq=0x08;
++ break;
++ case 96000:
++ sampling_freq=0x0a;
++ break;
++ case 176400:
++ sampling_freq=0x0c;
++ break;
++ case 192000:
++ sampling_freq=0x0e;
++ break;
++ default:
++ dev_err(codec->dev,
++ "Failed to set WM8804 SYSCLK, unsupported samplerate %d\n",
++ samplerate);
++ }
++
++ snd_soc_dai_set_clkdiv(codec_dai, WM8804_MCLK_DIV, mclk_div);
++ snd_soc_dai_set_pll(codec_dai, 0, 0, sysclk, mclk_freq);
++
++ ret = snd_soc_dai_set_sysclk(codec_dai, WM8804_TX_CLKSRC_PLL,
++ sysclk, SND_SOC_CLOCK_OUT);
++ if (ret < 0) {
++ dev_err(codec->dev,
++ "Failed to set WM8804 SYSCLK: %d\n", ret);
++ return ret;
++ }
++
++ /* Enable TX output */
++ snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, 0x0);
++
++ /* Power on */
++ snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0);
++
++ /* set sampling frequency status bits */
++ snd_soc_update_bits(codec, WM8804_SPDTX4, 0x0f, sampling_freq);
++
++ return snd_soc_dai_set_bclk_ratio(cpu_dai,64);
++}
++
++/* machine stream operations */
++static struct snd_soc_ops snd_rpi_justboom_digi_ops = {
++ .hw_params = snd_rpi_justboom_digi_hw_params,
++ .startup = snd_rpi_justboom_digi_startup,
++ .shutdown = snd_rpi_justboom_digi_shutdown,
++};
++
++static struct snd_soc_dai_link snd_rpi_justboom_digi_dai[] = {
++{
++ .name = "JustBoom Digi",
++ .stream_name = "JustBoom Digi HiFi",
++ .cpu_dai_name = "bcm2708-i2s.0",
++ .codec_dai_name = "wm8804-spdif",
++ .platform_name = "bcm2708-i2s.0",
++ .codec_name = "wm8804.1-003b",
++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBM_CFM,
++ .ops = &snd_rpi_justboom_digi_ops,
++ .init = snd_rpi_justboom_digi_init,
++},
++};
++
++/* audio machine driver */
++static struct snd_soc_card snd_rpi_justboom_digi = {
++ .name = "snd_rpi_justboom_digi",
++ .owner = THIS_MODULE,
++ .dai_link = snd_rpi_justboom_digi_dai,
++ .num_links = ARRAY_SIZE(snd_rpi_justboom_digi_dai),
++};
++
++static int snd_rpi_justboom_digi_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++
++ snd_rpi_justboom_digi.dev = &pdev->dev;
++
++ if (pdev->dev.of_node) {
++ struct device_node *i2s_node;
++ struct snd_soc_dai_link *dai = &snd_rpi_justboom_digi_dai[0];
++ i2s_node = of_parse_phandle(pdev->dev.of_node,
++ "i2s-controller", 0);
++
++ if (i2s_node) {
++ dai->cpu_dai_name = NULL;
++ dai->cpu_of_node = i2s_node;
++ dai->platform_name = NULL;
++ dai->platform_of_node = i2s_node;
++ }
++ }
++
++ ret = snd_soc_register_card(&snd_rpi_justboom_digi);
++ if (ret)
++ dev_err(&pdev->dev,
++ "snd_soc_register_card() failed: %d\n", ret);
++
++ return ret;
++}
++
++static int snd_rpi_justboom_digi_remove(struct platform_device *pdev)
++{
++ return snd_soc_unregister_card(&snd_rpi_justboom_digi);
++}
++
++static const struct of_device_id snd_rpi_justboom_digi_of_match[] = {
++ { .compatible = "justboom,justboom-digi", },
++ {},
++};
++MODULE_DEVICE_TABLE(of, snd_rpi_justboom_digi_of_match);
++
++static struct platform_driver snd_rpi_justboom_digi_driver = {
++ .driver = {
++ .name = "snd-rpi-justboom-digi",
++ .owner = THIS_MODULE,
++ .of_match_table = snd_rpi_justboom_digi_of_match,
++ },
++ .probe = snd_rpi_justboom_digi_probe,
++ .remove = snd_rpi_justboom_digi_remove,
++};
++
++module_platform_driver(snd_rpi_justboom_digi_driver);
++
++MODULE_AUTHOR("Milan Neskovic <info@justboom.co>");
++MODULE_DESCRIPTION("ASoC Driver for JustBoom PI Digi HAT Sound Card");
++MODULE_LICENSE("GPL v2");
diff --git a/target/linux/brcm2708/patches-4.4/0363-Add-dt-param-to-force-HiFiBerry-DAC-Pro-into-slave-m.patch b/target/linux/brcm2708/patches-4.4/0363-Add-dt-param-to-force-HiFiBerry-DAC-Pro-into-slave-m.patch
new file mode 100644
index 0000000000..fdea9a0823
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0363-Add-dt-param-to-force-HiFiBerry-DAC-Pro-into-slave-m.patch
@@ -0,0 +1,83 @@
+From 0975e732daee077f1b50d3869a37fb07b255f78a Mon Sep 17 00:00:00 2001
+From: DigitalDreamtime <clive.messer@digitaldreamtime.co.uk>
+Date: Sun, 29 May 2016 05:22:29 +0100
+Subject: [PATCH 363/381] Add dt param to force HiFiBerry DAC+ Pro into slave
+ mode
+
+"dtoverlay=hifiberry-dacplus,slave"
+
+Add 'slave' param to use HiFiBerry DAC+ Pro in slave mode,
+with Pi as master for bit and frame clock.
+
+Signed-off-by: DigitalDreamtime <clive.messer@digitaldreamtime.co.uk>
+---
+ arch/arm/boot/dts/overlays/README | 2 ++
+ arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts | 6 ++++--
+ sound/soc/bcm/hifiberry_dacplus.c | 10 ++++++++--
+ 3 files changed, 14 insertions(+), 4 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -344,6 +344,8 @@ Params: 24db_digital_gain Allow ga
+ responsibility of the user to ensure that
+ the Digital volume control is set to a value
+ that does not result in clipping/distortion!)
++ slave Force DAC+ Pro into slave mode, using Pi as
++ master for bit clock and frame clock.
+
+
+ Name: hifiberry-digi
+--- a/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
+@@ -41,7 +41,7 @@
+
+ fragment@3 {
+ target = <&sound>;
+- frag3: __overlay__ {
++ hifiberry_dacplus: __overlay__ {
+ compatible = "hifiberry,hifiberry-dacplus";
+ i2s-controller = <&i2s>;
+ status = "okay";
+@@ -49,6 +49,8 @@
+ };
+
+ __overrides__ {
+- 24db_digital_gain = <&frag3>,"hifiberry,24db_digital_gain?";
++ 24db_digital_gain =
++ <&hifiberry_dacplus>,"hifiberry,24db_digital_gain?";
++ slave = <&hifiberry_dacplus>,"hifiberry-dacplus,slave?";
+ };
+ };
+--- a/sound/soc/bcm/hifiberry_dacplus.c
++++ b/sound/soc/bcm/hifiberry_dacplus.c
+@@ -47,6 +47,7 @@ struct pcm512x_priv {
+ /* Clock rate of CLK48EN attached to GPIO3 pin */
+ #define CLK_48EN_RATE 24576000UL
+
++static bool slave;
+ static bool snd_rpi_hifiberry_is_dacpro;
+ static bool digital_gain_0db_limit = true;
+
+@@ -145,8 +146,11 @@ static int snd_rpi_hifiberry_dacplus_ini
+ struct snd_soc_codec *codec = rtd->codec;
+ struct pcm512x_priv *priv;
+
+- snd_rpi_hifiberry_is_dacpro
+- = snd_rpi_hifiberry_dacplus_is_pro_card(codec);
++ if (slave)
++ snd_rpi_hifiberry_is_dacpro = false;
++ else
++ snd_rpi_hifiberry_is_dacpro =
++ snd_rpi_hifiberry_dacplus_is_pro_card(codec);
+
+ if (snd_rpi_hifiberry_is_dacpro) {
+ struct snd_soc_dai_link *dai = rtd->dai_link;
+@@ -314,6 +318,8 @@ static int snd_rpi_hifiberry_dacplus_pro
+
+ digital_gain_0db_limit = !of_property_read_bool(
+ pdev->dev.of_node, "hifiberry,24db_digital_gain");
++ slave = of_property_read_bool(pdev->dev.of_node,
++ "hifiberry-dacplus,slave");
+ }
+
+ ret = snd_soc_register_card(&snd_rpi_hifiberry_dacplus);
diff --git a/target/linux/brcm2708/patches-4.4/0364-simple-add-sound-dai-cells-to-I2S-def.patch b/target/linux/brcm2708/patches-4.4/0364-simple-add-sound-dai-cells-to-I2S-def.patch
new file mode 100644
index 0000000000..0fba9b8cfe
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0364-simple-add-sound-dai-cells-to-I2S-def.patch
@@ -0,0 +1,33 @@
+From 14c2692d882e4438940a4fcf6f3c70e17e97633e Mon Sep 17 00:00:00 2001
+From: DigitalDreamtime <clive.messer@digitaldreamtime.co.uk>
+Date: Thu, 19 May 2016 00:00:00 +0100
+Subject: [PATCH 364/381] simple: add sound-dai-cells to I2S def
+
+Add '#sound-dai-cells = <0>;' to the I2S definition in
+bcm2708_common.dtsi
+
+Not having it specified, whilst not causing an issue right now with
+rpi-4.4.y, is going to cause an issue going forward with the use of
+simple-card driver. So it doesn't fall through the cracks, patch it
+in now.
+
+Hopefully Martin has taken care of getting a patch submitted for the
+upstream Pi dts, as it was he who first run into the issue with the
+current upstream kernel....
+https://github.com/msperl/linux-rpi/issues/3#issue-154916615
+
+Signed-off-by: DigitalDreamtime <clive.messer@digitaldreamtime.co.uk>
+---
+ arch/arm/boot/dts/bcm2708_common.dtsi | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/arm/boot/dts/bcm2708_common.dtsi
++++ b/arch/arm/boot/dts/bcm2708_common.dtsi
+@@ -137,6 +137,7 @@
+
+ i2s: i2s@7e203000 {
+ compatible = "brcm,bcm2835-i2s";
++ #sound-dai-cells = <0>;
+ reg = <0x7e203000 0x24>,
+ <0x7e101098 0x08>;
+
diff --git a/target/linux/brcm2708/patches-4.4/0365-BCM2835-V4L2-Increase-minimum-resolution-to-32x32.patch b/target/linux/brcm2708/patches-4.4/0365-BCM2835-V4L2-Increase-minimum-resolution-to-32x32.patch
new file mode 100644
index 0000000000..b446d03d71
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0365-BCM2835-V4L2-Increase-minimum-resolution-to-32x32.patch
@@ -0,0 +1,31 @@
+From 5369ea497f871c261a8ceb49508999160fdd3fc7 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <6by9@users.noreply.github.com>
+Date: Tue, 31 May 2016 10:38:31 +0100
+Subject: [PATCH 365/381] BCM2835-V4L2: Increase minimum resolution to 32x32
+
+https://github.com/raspberrypi/linux/issues/1498 showed
+up that 16x16 is failing to work on the GPU for some reason.
+
+GPU bug being tracked on
+https://github.com/raspberrypi/firmware/issues/607
+Workaround here by increasing minimum resolution via V4L2
+to 32x32.
+
+Signed-off-by: Dave Stevenson <6by9@users.noreply.github.com>
+---
+ drivers/media/platform/bcm2835/bcm2835-camera.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/media/platform/bcm2835/bcm2835-camera.c
++++ b/drivers/media/platform/bcm2835/bcm2835-camera.c
+@@ -36,8 +36,8 @@
+
+ #define BM2835_MMAL_VERSION "0.0.2"
+ #define BM2835_MMAL_MODULE_NAME "bcm2835-v4l2"
+-#define MIN_WIDTH 16
+-#define MIN_HEIGHT 16
++#define MIN_WIDTH 32
++#define MIN_HEIGHT 32
+ #define MIN_BUFFER_SIZE (80*1024)
+
+ #define MAX_VIDEO_MODE_WIDTH 1280
diff --git a/target/linux/brcm2708/patches-4.4/0366-config-Add-support-for-Logitech-Rumblepad.patch b/target/linux/brcm2708/patches-4.4/0366-config-Add-support-for-Logitech-Rumblepad.patch
new file mode 100644
index 0000000000..86af233496
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0366-config-Add-support-for-Logitech-Rumblepad.patch
@@ -0,0 +1,36 @@
+From 881972c61d00aa1b949e75eca9643c8f98b99b45 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Fri, 27 May 2016 18:23:51 +0100
+Subject: [PATCH 366/381] config: Add support for Logitech Rumblepad
+
+---
+ arch/arm/configs/bcm2709_defconfig | 4 ++++
+ arch/arm/configs/bcmrpi_defconfig | 4 ++++
+ 2 files changed, 8 insertions(+)
+
+--- a/arch/arm/configs/bcm2709_defconfig
++++ b/arch/arm/configs/bcm2709_defconfig
+@@ -896,6 +896,10 @@ CONFIG_HID_TWINHAN=m
+ CONFIG_HID_KENSINGTON=m
+ CONFIG_HID_LCPOWER=m
+ CONFIG_HID_LOGITECH=m
++CONFIG_HID_LOGITECH_DJ=m
++CONFIG_LOGITECH_FF=y
++CONFIG_LOGIRUMBLEPAD2_FF=y
++CONFIG_LOGIG940_FF=y
+ CONFIG_HID_MAGICMOUSE=m
+ CONFIG_HID_MICROSOFT=m
+ CONFIG_HID_MONTEREY=m
+--- a/arch/arm/configs/bcmrpi_defconfig
++++ b/arch/arm/configs/bcmrpi_defconfig
+@@ -888,6 +888,10 @@ CONFIG_HID_TWINHAN=m
+ CONFIG_HID_KENSINGTON=m
+ CONFIG_HID_LCPOWER=m
+ CONFIG_HID_LOGITECH=m
++CONFIG_HID_LOGITECH_DJ=m
++CONFIG_LOGITECH_FF=y
++CONFIG_LOGIRUMBLEPAD2_FF=y
++CONFIG_LOGIG940_FF=y
+ CONFIG_HID_MAGICMOUSE=m
+ CONFIG_HID_MICROSOFT=m
+ CONFIG_HID_MONTEREY=m
diff --git a/target/linux/brcm2708/patches-4.4/0367-New-driver-for-RRA-DigiDAC1-soundcard-using-WM8741-W.patch b/target/linux/brcm2708/patches-4.4/0367-New-driver-for-RRA-DigiDAC1-soundcard-using-WM8741-W.patch
new file mode 100644
index 0000000000..2b700dd705
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0367-New-driver-for-RRA-DigiDAC1-soundcard-using-WM8741-W.patch
@@ -0,0 +1,603 @@
+From 3fb73fd6dd7fc8bb8d2b282de1856967d7af0099 Mon Sep 17 00:00:00 2001
+From: escalator2015 <jmtasende@gmail.com>
+Date: Tue, 24 May 2016 16:20:09 +0100
+Subject: [PATCH 367/381] New driver for RRA DigiDAC1 soundcard using WM8741 +
+ WM8804
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 6 +
+ .../overlays/rra-digidac1-wm8741-audio-overlay.dts | 81 ++++
+ arch/arm/configs/bcm2709_defconfig | 1 +
+ arch/arm/configs/bcmrpi_defconfig | 1 +
+ sound/soc/bcm/Kconfig | 8 +
+ sound/soc/bcm/Makefile | 2 +
+ sound/soc/bcm/digidac1-soundcard.c | 422 +++++++++++++++++++++
+ 8 files changed, 522 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/rra-digidac1-wm8741-audio-overlay.dts
+ create mode 100644 sound/soc/bcm/digidac1-soundcard.c
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -67,6 +67,7 @@ dtbo-$(RPI_DT_OVERLAYS) += rpi-display.d
+ dtbo-$(RPI_DT_OVERLAYS) += rpi-ft5406.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += rpi-proto.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += rpi-sense.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += rra-digidac1-wm8741-audio.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += sdhost.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += sdio.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += sdio-1bit.dtbo
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -842,6 +842,12 @@ Load: dtoverlay=rpi-sense
+ Params: <None>
+
+
++Name: rra-digidac1-wm8741-audio
++Info: Configures the Red Rocks Audio DigiDAC1 soundcard
++Load: dtoverlay=rra-digidac1-wm8741-audio
++Params: <None>
++
++
+ Name: sdhost
+ Info: Selects the bcm2835-sdhost SD/MMC driver, optionally with overclock.
+ N.B. This overlay is designed for situations where the mmc driver is
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/rra-digidac1-wm8741-audio-overlay.dts
+@@ -0,0 +1,81 @@
++// Definitions for RRA DigiDAC1 Audio card
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target-path = "/";
++ __overlay__ {
++ aliases {
++ ldo0 = &ldo0;
++ ldo1 = &ldo1;
++ };
++ };
++ };
++
++ fragment@1 {
++ target-path = "/soc";
++ __overlay__ {
++
++ ldo1: ldo1 {
++ compatible = "regulator-fixed";
++ regulator-name = "DC_5V";
++ regulator-min-microvolt = <5000000>;
++ regulator-max-microvolt = <5000000>;
++ regulator-always-on;
++ };
++
++ ldo0: ldo0 {
++ compatible = "regulator-fixed";
++ regulator-name = "DC_3V3";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-always-on;
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&i2s>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@3 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ wm8804@3b {
++ #sound-dai-cells = <0>;
++ compatible = "wlf,wm8804";
++ reg = <0x3b>;
++ status = "okay";
++ PVDD-supply = <&ldo0>;
++ DVDD-supply = <&ldo0>;
++ };
++
++ wm8742: wm8741@1a {
++ compatible = "wlf,wm8741";
++ reg = <0x1a>;
++ status = "okay";
++ AVDD-supply = <&ldo1>;
++ DVDD-supply = <&ldo0>;
++ };
++ };
++ };
++
++ fragment@4 {
++ target = <&sound>;
++ __overlay__ {
++ compatible = "rra,digidac1-soundcard";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
++};
+--- a/arch/arm/configs/bcm2709_defconfig
++++ b/arch/arm/configs/bcm2709_defconfig
+@@ -866,6 +866,7 @@ CONFIG_SND_BCM2708_SOC_JUSTBOOM_DIGI=m
+ CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m
+ CONFIG_SND_BCM2708_SOC_RASPIDAC3=m
+ CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD=m
++CONFIG_SND_DIGIDAC1_SOUNDCARD=m
+ CONFIG_SND_BCM2708_SOC_ADAU1977_ADC=m
+ CONFIG_SND_SOC_ADAU1701=m
+ CONFIG_SND_SOC_WM8804_I2C=m
+--- a/arch/arm/configs/bcmrpi_defconfig
++++ b/arch/arm/configs/bcmrpi_defconfig
+@@ -858,6 +858,7 @@ CONFIG_SND_BCM2708_SOC_JUSTBOOM_DIGI=m
+ CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m
+ CONFIG_SND_BCM2708_SOC_RASPIDAC3=m
+ CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD=m
++CONFIG_SND_DIGIDAC1_SOUNDCARD=m
+ CONFIG_SND_BCM2708_SOC_ADAU1977_ADC=m
+ CONFIG_SND_SOC_ADAU1701=m
+ CONFIG_SND_SOC_WM8804_I2C=m
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -92,3 +92,11 @@ config SND_AUDIOINJECTOR_PI_SOUNDCARD
+ select SND_SOC_WM8731
+ help
+ Say Y or M if you want to add support for audioinjector.net Pi Hat
++
++config SND_DIGIDAC1_SOUNDCARD
++ tristate "Support for Red Rocks Audio DigiDAC1"
++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
++ select SND_SOC_WM8804
++ select SND_SOC_WM8741
++ help
++ Say Y or M if you want to add support for Red Rocks Audio DigiDAC1 board.
+--- a/sound/soc/bcm/Makefile
++++ b/sound/soc/bcm/Makefile
+@@ -16,6 +16,7 @@ snd-soc-rpi-proto-objs := rpi-proto.o
+ snd-soc-iqaudio-dac-objs := iqaudio-dac.o
+ snd-soc-raspidac3-objs := raspidac3.o
+ snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o
++snd-soc-digidac1-soundcard-objs := digidac1-soundcard.o
+
+ obj-$(CONFIG_SND_BCM2708_SOC_ADAU1977_ADC) += snd-soc-adau1977-adc.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o
+@@ -29,4 +30,5 @@ obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO)
+ obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
+ obj-$(CONFIG_SND_BCM2708_SOC_RASPIDAC3) += snd-soc-raspidac3.o
+ obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD) += snd-soc-audioinjector-pi-soundcard.o
++obj-$(CONFIG_SND_DIGIDAC1_SOUNDCARD) += snd-soc-digidac1-soundcard.o
+
+--- /dev/null
++++ b/sound/soc/bcm/digidac1-soundcard.c
+@@ -0,0 +1,422 @@
++/*
++ * ASoC Driver for RRA DigiDAC1
++ * Copyright 2016
++ * Author: José M. Tasende <vintage@redrocksaudio.es>
++ * based on the HifiBerry DAC driver by Florian Meier <florian.meier@koalo.de>
++ * and the Wolfson card driver by Nikesh Oswal, <Nikesh.Oswal@wolfsonmicro.com>
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/i2c.h>
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/jack.h>
++#include <sound/soc-dapm.h>
++#include <sound/tlv.h>
++#include <linux/regulator/consumer.h>
++
++#include "../codecs/wm8804.h"
++#include "../codecs/wm8741.h"
++
++#define WM8741_NUM_SUPPLIES 2
++
++/* codec private data */
++struct wm8741_priv {
++ struct wm8741_platform_data pdata;
++ struct regmap *regmap;
++ struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES];
++ unsigned int sysclk;
++ const struct snd_pcm_hw_constraint_list *sysclk_constraints;
++};
++
++static int samplerate = 44100;
++
++/* New Alsa Controls not exposed by original wm8741 codec driver */
++/* in actual driver the att. adjustment is wrong because */
++/* this DAC has a coarse attenuation register with 4dB steps */
++/* and a fine level register with 0.125dB steps */
++/* each register has 32 steps so combining both we have 1024 steps */
++/* of 0.125 dB. */
++/* The original level controls from driver are removed at startup */
++/* and replaced by the corrected ones. */
++/* The same wm8741 driver can be used for wm8741 and wm8742 devices */
++
++static const DECLARE_TLV_DB_SCALE(dac_tlv_fine, 0, 13, 0);
++static const DECLARE_TLV_DB_SCALE(dac_tlv_coarse, -12700, 400, 1);
++static const char *w8741_dither[4] = {"Off", "RPDF", "TPDF", "HPDF"};
++static const char *w8741_filter[5] = {
++ "Type 1", "Type 2", "Type 3", "Type 4", "Type 5"};
++static const char *w8741_switch[2] = {"Off", "On"};
++static const struct soc_enum w8741_enum[] = {
++SOC_ENUM_SINGLE(WM8741_MODE_CONTROL_2, 0, 4, w8741_dither),/* dithering type */
++SOC_ENUM_SINGLE(WM8741_FILTER_CONTROL, 0, 5, w8741_filter),/* filter type */
++SOC_ENUM_SINGLE(WM8741_FORMAT_CONTROL, 6, 2, w8741_switch),/* phase invert */
++SOC_ENUM_SINGLE(WM8741_VOLUME_CONTROL, 0, 2, w8741_switch),/* volume ramp */
++SOC_ENUM_SINGLE(WM8741_VOLUME_CONTROL, 3, 2, w8741_switch),/* soft mute */
++};
++
++static const struct snd_kcontrol_new w8741_snd_controls_stereo[] = {
++SOC_DOUBLE_R_TLV("DAC Fine Playback Volume", WM8741_DACLLSB_ATTENUATION,
++ WM8741_DACRLSB_ATTENUATION, 0, 31, 1, dac_tlv_fine),
++SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8741_DACLMSB_ATTENUATION,
++ WM8741_DACRMSB_ATTENUATION, 0, 31, 1, dac_tlv_coarse),
++SOC_ENUM("DAC Dither", w8741_enum[0]),
++SOC_ENUM("DAC Digital Filter", w8741_enum[1]),
++SOC_ENUM("DAC Phase Invert", w8741_enum[2]),
++SOC_ENUM("DAC Volume Ramp", w8741_enum[3]),
++SOC_ENUM("DAC Soft Mute", w8741_enum[4]),
++};
++
++static const struct snd_kcontrol_new w8741_snd_controls_mono_left[] = {
++SOC_SINGLE_TLV("DAC Fine Playback Volume", WM8741_DACLLSB_ATTENUATION,
++ 0, 31, 0, dac_tlv_fine),
++SOC_SINGLE_TLV("Digital Playback Volume", WM8741_DACLMSB_ATTENUATION,
++ 0, 31, 1, dac_tlv_coarse),
++SOC_ENUM("DAC Dither", w8741_enum[0]),
++SOC_ENUM("DAC Digital Filter", w8741_enum[1]),
++SOC_ENUM("DAC Phase Invert", w8741_enum[2]),
++SOC_ENUM("DAC Volume Ramp", w8741_enum[3]),
++SOC_ENUM("DAC Soft Mute", w8741_enum[4]),
++};
++
++static const struct snd_kcontrol_new w8741_snd_controls_mono_right[] = {
++SOC_SINGLE_TLV("DAC Fine Playback Volume", WM8741_DACRLSB_ATTENUATION,
++ 0, 31, 0, dac_tlv_fine),
++SOC_SINGLE_TLV("Digital Playback Volume", WM8741_DACRMSB_ATTENUATION,
++ 0, 31, 1, dac_tlv_coarse),
++SOC_ENUM("DAC Dither", w8741_enum[0]),
++SOC_ENUM("DAC Digital Filter", w8741_enum[1]),
++SOC_ENUM("DAC Phase Invert", w8741_enum[2]),
++SOC_ENUM("DAC Volume Ramp", w8741_enum[3]),
++SOC_ENUM("DAC Soft Mute", w8741_enum[4]),
++};
++
++static int w8741_add_controls(struct snd_soc_codec *codec)
++{
++ struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
++
++ switch (wm8741->pdata.diff_mode) {
++ case WM8741_DIFF_MODE_STEREO:
++ case WM8741_DIFF_MODE_STEREO_REVERSED:
++ snd_soc_add_codec_controls(codec,
++ w8741_snd_controls_stereo,
++ ARRAY_SIZE(w8741_snd_controls_stereo));
++ break;
++ case WM8741_DIFF_MODE_MONO_LEFT:
++ snd_soc_add_codec_controls(codec,
++ w8741_snd_controls_mono_left,
++ ARRAY_SIZE(w8741_snd_controls_mono_left));
++ break;
++ case WM8741_DIFF_MODE_MONO_RIGHT:
++ snd_soc_add_codec_controls(codec,
++ w8741_snd_controls_mono_right,
++ ARRAY_SIZE(w8741_snd_controls_mono_right));
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static int digidac1_soundcard_init(struct snd_soc_pcm_runtime *rtd)
++{
++ struct snd_soc_codec *codec = rtd->codec;
++ struct snd_soc_card *card = rtd->card;
++ struct snd_soc_pcm_runtime *wm8741_rtd;
++ struct snd_soc_codec *wm8741_codec;
++ struct snd_card *sound_card = card->snd_card;
++ struct snd_kcontrol *kctl;
++ int ret;
++
++ wm8741_rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name);
++ if (!wm8741_rtd) {
++ dev_warn(card->dev, "digidac1_soundcard_init: couldn't get wm8741 rtd\n");
++ return -EFAULT;
++ }
++ wm8741_codec = wm8741_rtd->codec;
++ ret = w8741_add_controls(wm8741_codec);
++ if (ret < 0)
++ dev_warn(card->dev, "Failed to add new wm8741 controls: %d\n",
++ ret);
++
++ /* enable TX output */
++ snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, 0x0);
++
++ kctl = snd_soc_card_get_kcontrol(card,
++ "Playback Volume");
++ if (kctl) {
++ kctl->vd[0].access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
++ snd_ctl_remove(sound_card, kctl);
++ }
++ kctl = snd_soc_card_get_kcontrol(card,
++ "Fine Playback Volume");
++ if (kctl) {
++ kctl->vd[0].access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
++ snd_ctl_remove(sound_card, kctl);
++ }
++ return 0;
++}
++
++static int digidac1_soundcard_startup(struct snd_pcm_substream *substream)
++{
++ /* turn on wm8804 digital output */
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_codec *codec = rtd->codec;
++ struct snd_soc_card *card = rtd->card;
++ struct snd_soc_pcm_runtime *wm8741_rtd;
++ struct snd_soc_codec *wm8741_codec;
++
++ snd_soc_update_bits(codec, WM8804_PWRDN, 0x3c, 0x00);
++ wm8741_rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name);
++ if (!wm8741_rtd) {
++ dev_warn(card->dev, "digidac1_soundcard_startup: couldn't get WM8741 rtd\n");
++ return -EFAULT;
++ }
++ wm8741_codec = wm8741_rtd->codec;
++
++ /* latch wm8741 level */
++ snd_soc_update_bits(wm8741_codec, WM8741_DACLLSB_ATTENUATION,
++ WM8741_UPDATELL, WM8741_UPDATELL);
++ snd_soc_update_bits(wm8741_codec, WM8741_DACLMSB_ATTENUATION,
++ WM8741_UPDATELM, WM8741_UPDATELM);
++ snd_soc_update_bits(wm8741_codec, WM8741_DACRLSB_ATTENUATION,
++ WM8741_UPDATERL, WM8741_UPDATERL);
++ snd_soc_update_bits(wm8741_codec, WM8741_DACRMSB_ATTENUATION,
++ WM8741_UPDATERM, WM8741_UPDATERM);
++
++ return 0;
++}
++
++static void digidac1_soundcard_shutdown(struct snd_pcm_substream *substream)
++{
++ /* turn off wm8804 digital output */
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_codec *codec = rtd->codec;
++
++ snd_soc_update_bits(codec, WM8804_PWRDN, 0x3c, 0x3c);
++}
++
++static int digidac1_soundcard_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_dai *codec_dai = rtd->codec_dai;
++ struct snd_soc_codec *codec = rtd->codec;
++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
++ struct snd_soc_card *card = rtd->card;
++ struct snd_soc_pcm_runtime *wm8741_rtd;
++ struct snd_soc_codec *wm8741_codec;
++
++ int sysclk = 27000000;
++ long mclk_freq = 0;
++ int mclk_div = 1;
++ int sampling_freq = 1;
++ int ret;
++
++ wm8741_rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name);
++ if (!wm8741_rtd) {
++ dev_warn(card->dev, "digidac1_soundcard_hw_params: couldn't get WM8741 rtd\n");
++ return -EFAULT;
++ }
++ wm8741_codec = wm8741_rtd->codec;
++ samplerate = params_rate(params);
++
++ if (samplerate <= 96000) {
++ mclk_freq = samplerate*256;
++ mclk_div = WM8804_MCLKDIV_256FS;
++ } else {
++ mclk_freq = samplerate*128;
++ mclk_div = WM8804_MCLKDIV_128FS;
++ }
++
++ switch (samplerate) {
++ case 32000:
++ sampling_freq = 0x03;
++ break;
++ case 44100:
++ sampling_freq = 0x00;
++ break;
++ case 48000:
++ sampling_freq = 0x02;
++ break;
++ case 88200:
++ sampling_freq = 0x08;
++ break;
++ case 96000:
++ sampling_freq = 0x0a;
++ break;
++ case 176400:
++ sampling_freq = 0x0c;
++ break;
++ case 192000:
++ sampling_freq = 0x0e;
++ break;
++ default:
++ dev_err(codec->dev,
++ "Failed to set WM8804 SYSCLK, unsupported samplerate %d\n",
++ samplerate);
++ }
++
++ snd_soc_dai_set_clkdiv(codec_dai, WM8804_MCLK_DIV, mclk_div);
++ snd_soc_dai_set_pll(codec_dai, 0, 0, sysclk, mclk_freq);
++
++ ret = snd_soc_dai_set_sysclk(codec_dai, WM8804_TX_CLKSRC_PLL,
++ sysclk, SND_SOC_CLOCK_OUT);
++ if (ret < 0) {
++ dev_err(codec->dev,
++ "Failed to set WM8804 SYSCLK: %d\n", ret);
++ return ret;
++ }
++ /* Enable wm8804 TX output */
++ snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, 0x0);
++
++ /* wm8804 Power on */
++ snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0);
++
++ /* wm8804 set sampling frequency status bits */
++ snd_soc_update_bits(codec, WM8804_SPDTX4, 0x0f, sampling_freq);
++
++ /* Now update wm8741 registers for the correct oversampling */
++ if (samplerate <= 48000)
++ snd_soc_update_bits(wm8741_codec, WM8741_MODE_CONTROL_1,
++ WM8741_OSR_MASK, 0x00);
++ else if (samplerate <= 96000)
++ snd_soc_update_bits(wm8741_codec, WM8741_MODE_CONTROL_1,
++ WM8741_OSR_MASK, 0x20);
++ else
++ snd_soc_update_bits(wm8741_codec, WM8741_MODE_CONTROL_1,
++ WM8741_OSR_MASK, 0x40);
++
++ /* wm8741 bit size */
++ switch (params_width(params)) {
++ case 16:
++ snd_soc_update_bits(wm8741_codec, WM8741_FORMAT_CONTROL,
++ WM8741_IWL_MASK, 0x00);
++ break;
++ case 20:
++ snd_soc_update_bits(wm8741_codec, WM8741_FORMAT_CONTROL,
++ WM8741_IWL_MASK, 0x01);
++ break;
++ case 24:
++ snd_soc_update_bits(wm8741_codec, WM8741_FORMAT_CONTROL,
++ WM8741_IWL_MASK, 0x02);
++ break;
++ case 32:
++ snd_soc_update_bits(wm8741_codec, WM8741_FORMAT_CONTROL,
++ WM8741_IWL_MASK, 0x03);
++ break;
++ default:
++ dev_dbg(codec->dev, "wm8741_hw_params: Unsupported bit size param = %d",
++ params_width(params));
++ return -EINVAL;
++ }
++
++ return snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
++}
++/* machine stream operations */
++static struct snd_soc_ops digidac1_soundcard_ops = {
++ .hw_params = digidac1_soundcard_hw_params,
++ .startup = digidac1_soundcard_startup,
++ .shutdown = digidac1_soundcard_shutdown,
++};
++
++static struct snd_soc_dai_link digidac1_soundcard_dai[] = {
++ {
++ .name = "RRA DigiDAC1",
++ .stream_name = "RRA DigiDAC1 HiFi",
++ .cpu_dai_name = "bcm2708-i2s.0",
++ .codec_dai_name = "wm8804-spdif",
++ .platform_name = "bcm2708-i2s.0",
++ .codec_name = "wm8804.1-003b",
++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBM_CFM,
++ .ops = &digidac1_soundcard_ops,
++ .init = digidac1_soundcard_init,
++ },
++ {
++ .name = "RRA DigiDAC11",
++ .stream_name = "RRA DigiDAC11 HiFi",
++ .cpu_dai_name = "wm8804-spdif",
++ .codec_dai_name = "wm8741",
++ .codec_name = "wm8741.1-001a",
++ .dai_fmt = SND_SOC_DAIFMT_I2S
++ | SND_SOC_DAIFMT_NB_NF
++ | SND_SOC_DAIFMT_CBS_CFS,
++ },
++};
++
++/* audio machine driver */
++static struct snd_soc_card digidac1_soundcard = {
++ .name = "digidac1-soundcard",
++ .owner = THIS_MODULE,
++ .dai_link = digidac1_soundcard_dai,
++ .num_links = ARRAY_SIZE(digidac1_soundcard_dai),
++};
++
++static int digidac1_soundcard_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++
++ digidac1_soundcard.dev = &pdev->dev;
++
++ if (pdev->dev.of_node) {
++ struct device_node *i2s_node;
++ struct snd_soc_dai_link *dai = &digidac1_soundcard_dai[0];
++
++ i2s_node = of_parse_phandle(pdev->dev.of_node,
++ "i2s-controller", 0);
++
++ if (i2s_node) {
++ dai->cpu_dai_name = NULL;
++ dai->cpu_of_node = i2s_node;
++ dai->platform_name = NULL;
++ dai->platform_of_node = i2s_node;
++ }
++ }
++
++ ret = snd_soc_register_card(&digidac1_soundcard);
++ if (ret)
++ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
++ ret);
++
++ return ret;
++}
++
++static int digidac1_soundcard_remove(struct platform_device *pdev)
++{
++ return snd_soc_unregister_card(&digidac1_soundcard);
++}
++
++static const struct of_device_id digidac1_soundcard_of_match[] = {
++ { .compatible = "rra,digidac1-soundcard", },
++ {},
++};
++MODULE_DEVICE_TABLE(of, digidac1_soundcard_of_match);
++
++static struct platform_driver digidac1_soundcard_driver = {
++ .driver = {
++ .name = "digidac1-audio",
++ .owner = THIS_MODULE,
++ .of_match_table = digidac1_soundcard_of_match,
++ },
++ .probe = digidac1_soundcard_probe,
++ .remove = digidac1_soundcard_remove,
++};
++
++module_platform_driver(digidac1_soundcard_driver);
++
++MODULE_AUTHOR("José M. Tasende <vintage@redrocksaudio.es>");
++MODULE_DESCRIPTION("ASoC Driver for RRA DigiDAC1");
++MODULE_LICENSE("GPL v2");
diff --git a/target/linux/brcm2708/patches-4.4/0368-BCM2835-V4L2-Correct-handling-for-BGR24-vs-RGB24.patch b/target/linux/brcm2708/patches-4.4/0368-BCM2835-V4L2-Correct-handling-for-BGR24-vs-RGB24.patch
new file mode 100644
index 0000000000..11721597a8
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0368-BCM2835-V4L2-Correct-handling-for-BGR24-vs-RGB24.patch
@@ -0,0 +1,170 @@
+From 34193c64b66da53cf36bec310fc4b660912847e1 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <6by9@users.noreply.github.com>
+Date: Wed, 25 May 2016 23:25:36 +0100
+Subject: [PATCH 368/381] BCM2835-V4L2: Correct handling for BGR24 vs RGB24.
+
+There was a bug in the GPU firmware that had reversed these
+two formats.
+Detect the old firmware, and reverse the formats if necessary.
+
+Signed-off-by: Dave Stevenson <6by9@users.noreply.github.com>
+---
+ drivers/media/platform/bcm2835/bcm2835-camera.c | 69 ++++++++++++++++++-------
+ drivers/media/platform/bcm2835/bcm2835-camera.h | 1 +
+ 2 files changed, 52 insertions(+), 18 deletions(-)
+
+--- a/drivers/media/platform/bcm2835/bcm2835-camera.c
++++ b/drivers/media/platform/bcm2835/bcm2835-camera.c
+@@ -115,7 +115,7 @@ static struct mmal_fmt formats[] = {
+ .name = "RGB24 (LE)",
+ .fourcc = V4L2_PIX_FMT_RGB24,
+ .flags = 0,
+- .mmal = MMAL_ENCODING_BGR24,
++ .mmal = MMAL_ENCODING_RGB24,
+ .depth = 24,
+ .mmal_component = MMAL_COMPONENT_CAMERA,
+ .ybbp = 3,
+@@ -187,7 +187,7 @@ static struct mmal_fmt formats[] = {
+ .name = "RGB24 (BE)",
+ .fourcc = V4L2_PIX_FMT_BGR24,
+ .flags = 0,
+- .mmal = MMAL_ENCODING_RGB24,
++ .mmal = MMAL_ENCODING_BGR24,
+ .depth = 24,
+ .mmal_component = MMAL_COMPONENT_CAMERA,
+ .ybbp = 3,
+@@ -1059,6 +1059,13 @@ static int mmal_setup_components(struct
+ else
+ camera_port->format.encoding = mfmt->mmal;
+
++ if (dev->rgb_bgr_swapped) {
++ if (camera_port->format.encoding == MMAL_ENCODING_RGB24)
++ camera_port->format.encoding = MMAL_ENCODING_BGR24;
++ else if (camera_port->format.encoding == MMAL_ENCODING_BGR24)
++ camera_port->format.encoding = MMAL_ENCODING_RGB24;
++ }
++
+ camera_port->format.encoding_variant = 0;
+ camera_port->es.video.width = f->fmt.pix.width;
+ camera_port->es.video.height = f->fmt.pix.height;
+@@ -1569,12 +1576,17 @@ static int set_camera_parameters(struct
+ return ret;
+ }
+
++#define MAX_SUPPORTED_ENCODINGS 20
++
+ /* MMAL instance and component init */
+ static int __init mmal_init(struct bm2835_mmal_dev *dev)
+ {
+ int ret;
+ struct mmal_es_format *format;
+ u32 bool_true = 1;
++ u32 supported_encodings[MAX_SUPPORTED_ENCODINGS];
++ int param_size;
++ struct vchiq_mmal_component *camera;
+
+ ret = vchiq_mmal_init(&dev->instance);
+ if (ret < 0)
+@@ -1586,21 +1598,48 @@ static int __init mmal_init(struct bm283
+ if (ret < 0)
+ goto unreg_mmal;
+
+- if (dev->component[MMAL_COMPONENT_CAMERA]->outputs <
+- MMAL_CAMERA_PORT_COUNT) {
++ camera = dev->component[MMAL_COMPONENT_CAMERA];
++ if (camera->outputs < MMAL_CAMERA_PORT_COUNT) {
+ ret = -EINVAL;
+ goto unreg_camera;
+ }
+
+ ret = set_camera_parameters(dev->instance,
+- dev->component[MMAL_COMPONENT_CAMERA],
++ camera,
+ dev);
+ if (ret < 0)
+ goto unreg_camera;
+
+- format =
+- &dev->component[MMAL_COMPONENT_CAMERA]->
+- output[MMAL_CAMERA_PORT_PREVIEW].format;
++ /* There was an error in the firmware that meant the camera component
++ * produced BGR instead of RGB.
++ * This is now fixed, but in order to support the old firmwares, we
++ * have to check.
++ */
++ dev->rgb_bgr_swapped = true;
++ param_size = sizeof(supported_encodings);
++ ret = vchiq_mmal_port_parameter_get(dev->instance,
++ &camera->output[MMAL_CAMERA_PORT_CAPTURE],
++ MMAL_PARAMETER_SUPPORTED_ENCODINGS,
++ &supported_encodings,
++ &param_size);
++ if (ret == 0) {
++ int i;
++
++ for (i = 0; i < param_size/sizeof(u32); i++) {
++ if (supported_encodings[i] == MMAL_ENCODING_BGR24) {
++ /* Found BGR24 first - old firmware. */
++ break;
++ }
++ if (supported_encodings[i] == MMAL_ENCODING_RGB24) {
++ /* Found RGB24 first
++ * new firmware, so use RGB24.
++ */
++ dev->rgb_bgr_swapped = false;
++ break;
++ }
++ }
++ }
++ format = &camera->output[MMAL_CAMERA_PORT_PREVIEW].format;
+
+ format->encoding = MMAL_ENCODING_OPAQUE;
+ format->encoding_variant = MMAL_ENCODING_I420;
+@@ -1614,9 +1653,7 @@ static int __init mmal_init(struct bm283
+ format->es->video.frame_rate.num = 0; /* Rely on fps_range */
+ format->es->video.frame_rate.den = 1;
+
+- format =
+- &dev->component[MMAL_COMPONENT_CAMERA]->
+- output[MMAL_CAMERA_PORT_VIDEO].format;
++ format = &camera->output[MMAL_CAMERA_PORT_VIDEO].format;
+
+ format->encoding = MMAL_ENCODING_OPAQUE;
+ format->encoding_variant = MMAL_ENCODING_I420;
+@@ -1631,14 +1668,11 @@ static int __init mmal_init(struct bm283
+ format->es->video.frame_rate.den = 1;
+
+ vchiq_mmal_port_parameter_set(dev->instance,
+- &dev->component[MMAL_COMPONENT_CAMERA]->
+- output[MMAL_CAMERA_PORT_VIDEO],
++ &camera->output[MMAL_CAMERA_PORT_VIDEO],
+ MMAL_PARAMETER_NO_IMAGE_PADDING,
+ &bool_true, sizeof(bool_true));
+
+- format =
+- &dev->component[MMAL_COMPONENT_CAMERA]->
+- output[MMAL_CAMERA_PORT_CAPTURE].format;
++ format = &camera->output[MMAL_CAMERA_PORT_CAPTURE].format;
+
+ format->encoding = MMAL_ENCODING_OPAQUE;
+
+@@ -1660,8 +1694,7 @@ static int __init mmal_init(struct bm283
+ dev->capture.enc_level = V4L2_MPEG_VIDEO_H264_LEVEL_4_0;
+
+ vchiq_mmal_port_parameter_set(dev->instance,
+- &dev->component[MMAL_COMPONENT_CAMERA]->
+- output[MMAL_CAMERA_PORT_CAPTURE],
++ &camera->output[MMAL_CAMERA_PORT_CAPTURE],
+ MMAL_PARAMETER_NO_IMAGE_PADDING,
+ &bool_true, sizeof(bool_true));
+
+--- a/drivers/media/platform/bcm2835/bcm2835-camera.h
++++ b/drivers/media/platform/bcm2835/bcm2835-camera.h
+@@ -109,6 +109,7 @@ struct bm2835_mmal_dev {
+ unsigned int camera_num;
+ unsigned int max_width;
+ unsigned int max_height;
++ unsigned int rgb_bgr_swapped;
+ };
+
+ int bm2835_mmal_init_controls(
diff --git a/target/linux/brcm2708/patches-4.4/0369-BCM270X_DT-Add-mcp23017-to-the-overlay-Makefile.patch b/target/linux/brcm2708/patches-4.4/0369-BCM270X_DT-Add-mcp23017-to-the-overlay-Makefile.patch
new file mode 100644
index 0000000000..f1931f6ad0
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0369-BCM270X_DT-Add-mcp23017-to-the-overlay-Makefile.patch
@@ -0,0 +1,20 @@
+From a71a54f2a42f4df6bf5094ed3df019b8813d2426 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 3 Jun 2016 22:21:47 +0100
+Subject: [PATCH 369/381] BCM270X_DT: Add mcp23017 to the overlay Makefile
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -44,6 +44,7 @@ dtbo-$(RPI_DT_OVERLAYS) += iqaudio-dacpl
+ dtbo-$(RPI_DT_OVERLAYS) += justboom-dac.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += justboom-digi.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += lirc-rpi.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += mcp23017.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += mcp2515-can0.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += mcp2515-can1.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += mmc.dtbo
diff --git a/target/linux/brcm2708/patches-4.4/0370-BCM270X_DT-Sort-entries-to-placate-check-script.patch b/target/linux/brcm2708/patches-4.4/0370-BCM270X_DT-Sort-entries-to-placate-check-script.patch
new file mode 100644
index 0000000000..a46ccef621
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0370-BCM270X_DT-Sort-entries-to-placate-check-script.patch
@@ -0,0 +1,56 @@
+From 30c48dc447e8c678fd7db6bdc0b09c46bf18c155 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 3 Jun 2016 23:01:01 +0100
+Subject: [PATCH 370/381] BCM270X_DT: Sort entries to placate check script
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/overlays/Makefile | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -18,10 +18,10 @@ dtbo-$(RPI_DT_OVERLAYS) += akkordion-iqd
+ dtbo-$(RPI_DT_OVERLAYS) += at86rf233.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += audioinjector-wm8731-audio.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += bmp085_i2c-sensor.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += dht11.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += dpi24.dtbo
+-dtbo-$(RPI_DT_OVERLAYS) += dwc2.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += dwc-otg.dtbo
+-dtbo-$(RPI_DT_OVERLAYS) += dht11.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += dwc2.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += enc28j60.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += gpio-ir.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += gpio-poweroff.dtbo
+@@ -31,10 +31,10 @@ dtbo-$(RPI_DT_OVERLAYS) += hifiberry-dac
+ dtbo-$(RPI_DT_OVERLAYS) += hifiberry-digi.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += hy28a.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += hy28b.dtbo
+-dtbo-$(RPI_DT_OVERLAYS) += i2c-rtc.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += i2c-gpio.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += i2c-mux.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += i2c-pwm-pca9685a.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += i2c-rtc.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += i2c0-bcm2708.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += i2c1-bcm2708.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += i2s-gpio28-31.dtbo
+@@ -73,16 +73,16 @@ dtbo-$(RPI_DT_OVERLAYS) += sdhost.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += sdio.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += sdio-1bit.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += sdtweak.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += smi.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += smi-dev.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += smi-nand.dtbo
+-dtbo-$(RPI_DT_OVERLAYS) += smi.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += spi-gpio35-39.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += spi1-1cs.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += spi1-2cs.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += spi1-3cs.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += spi2-1cs.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += spi2-2cs.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += spi2-3cs.dtbo
+-dtbo-$(RPI_DT_OVERLAYS) += spi-gpio35-39.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += tinylcd35.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += uart1.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += vc4-kms-v3d.dtbo
diff --git a/target/linux/brcm2708/patches-4.4/0371-gpio-ir-overlay-gpio_pin-shouldn-t-change-pull-setti.patch b/target/linux/brcm2708/patches-4.4/0371-gpio-ir-overlay-gpio_pin-shouldn-t-change-pull-setti.patch
new file mode 100644
index 0000000000..d7748abf4f
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0371-gpio-ir-overlay-gpio_pin-shouldn-t-change-pull-setti.patch
@@ -0,0 +1,23 @@
+From 20ef0358f5d9c9a63ee3a62301a366315c503bd1 Mon Sep 17 00:00:00 2001
+From: Matthias Reichl <hias@horus.com>
+Date: Sat, 4 Jun 2016 11:30:48 +0200
+Subject: [PATCH 371/381] gpio-ir overlay: gpio_pin shouldn't change pull
+ setting
+
+Signed-off-by: Matthias Reichl <hias@horus.com>
+---
+ arch/arm/boot/dts/overlays/gpio-ir-overlay.dts | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/gpio-ir-overlay.dts
++++ b/arch/arm/boot/dts/overlays/gpio-ir-overlay.dts
+@@ -36,8 +36,7 @@
+ __overrides__ {
+ // parameters
+ gpio_pin = <&gpio_ir>,"gpios:4",
+- <&gpio_ir_pins>,"brcm,pins:0",
+- <&gpio_ir_pins>,"brcm,pull:0"; // pin number
++ <&gpio_ir_pins>,"brcm,pins:0"; // pin number
+ gpio_pull = <&gpio_ir_pins>,"brcm,pull:0"; // pull-up/down state
+
+ rc-map-name = <&gpio_ir>,"linux,rc-map-name"; // default rc map
diff --git a/target/linux/brcm2708/patches-4.4/0372-media-rc-core-define-a-default-timeout-for-drivers.patch b/target/linux/brcm2708/patches-4.4/0372-media-rc-core-define-a-default-timeout-for-drivers.patch
new file mode 100644
index 0000000000..0264c13dad
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0372-media-rc-core-define-a-default-timeout-for-drivers.patch
@@ -0,0 +1,25 @@
+From 3abeeb47bad351f535efdf176cd623ac8ff7cfe3 Mon Sep 17 00:00:00 2001
+From: Eric Nelson <eric@nelint.com>
+Date: Sat, 3 Oct 2015 08:18:50 -0700
+Subject: [PATCH 372/381] [media] rc-core: define a default timeout for drivers
+
+A default timeout value of 125 ms should work for all decoders.
+
+Declare a constant to help standardize its' use.
+
+Signed-off-by: Eric Nelson <eric@nelint.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+---
+ include/media/rc-core.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/include/media/rc-core.h
++++ b/include/media/rc-core.h
+@@ -239,6 +239,7 @@ static inline void init_ir_raw_event(str
+ memset(ev, 0, sizeof(*ev));
+ }
+
++#define IR_DEFAULT_TIMEOUT MS_TO_NS(125)
+ #define IR_MAX_DURATION 500000000 /* 500 ms */
+ #define US_TO_NS(usec) ((usec) * 1000)
+ #define MS_TO_US(msec) ((msec) * 1000)
diff --git a/target/linux/brcm2708/patches-4.4/0373-media-rc-gpio-ir-recv-add-timeout-on-idle.patch b/target/linux/brcm2708/patches-4.4/0373-media-rc-gpio-ir-recv-add-timeout-on-idle.patch
new file mode 100644
index 0000000000..db1484b0ac
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0373-media-rc-gpio-ir-recv-add-timeout-on-idle.patch
@@ -0,0 +1,91 @@
+From 1940010ff839276f53494bafc2e709117d70f590 Mon Sep 17 00:00:00 2001
+From: Eric Nelson <eric@nelint.com>
+Date: Wed, 23 Sep 2015 11:07:08 -0300
+Subject: [PATCH 373/381] [media] rc: gpio-ir-recv: add timeout on idle
+
+Many decoders require a trailing space (period without IR illumination)
+to be delivered before completing a decode.
+
+Since the gpio-ir-recv driver only delivers events on gpio transitions,
+a single IR symbol (caused by a quick touch on an IR remote) will not
+be properly decoded without the use of a timer to flush the tail end
+state of the IR receiver.
+
+This patch initializes and uses a timer and the timeout field of rcdev
+to complete the stream and allow decode.
+
+The timeout can be overridden through the use of the LIRC_SET_REC_TIMEOUT
+ioctl.
+
+Signed-off-by: Eric Nelson <eric@nelint.com>
+Acked-by: Sean Young <sean@mess.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+---
+ drivers/media/rc/gpio-ir-recv.c | 22 ++++++++++++++++++++++
+ 1 file changed, 22 insertions(+)
+
+--- a/drivers/media/rc/gpio-ir-recv.c
++++ b/drivers/media/rc/gpio-ir-recv.c
+@@ -30,6 +30,7 @@ struct gpio_rc_dev {
+ struct rc_dev *rcdev;
+ int gpio_nr;
+ bool active_low;
++ struct timer_list flush_timer;
+ };
+
+ #ifdef CONFIG_OF
+@@ -93,12 +94,26 @@ static irqreturn_t gpio_ir_recv_irq(int
+ if (rc < 0)
+ goto err_get_value;
+
++ mod_timer(&gpio_dev->flush_timer,
++ jiffies + nsecs_to_jiffies(gpio_dev->rcdev->timeout));
++
+ ir_raw_event_handle(gpio_dev->rcdev);
+
+ err_get_value:
+ return IRQ_HANDLED;
+ }
+
++static void flush_timer(unsigned long arg)
++{
++ struct gpio_rc_dev *gpio_dev = (struct gpio_rc_dev *)arg;
++ DEFINE_IR_RAW_EVENT(ev);
++
++ ev.timeout = true;
++ ev.duration = gpio_dev->rcdev->timeout;
++ ir_raw_event_store(gpio_dev->rcdev, &ev);
++ ir_raw_event_handle(gpio_dev->rcdev);
++}
++
+ static int gpio_ir_recv_probe(struct platform_device *pdev)
+ {
+ struct gpio_rc_dev *gpio_dev;
+@@ -144,6 +159,9 @@ static int gpio_ir_recv_probe(struct pla
+ rcdev->input_id.version = 0x0100;
+ rcdev->dev.parent = &pdev->dev;
+ rcdev->driver_name = GPIO_IR_DRIVER_NAME;
++ rcdev->min_timeout = 0;
++ rcdev->timeout = IR_DEFAULT_TIMEOUT;
++ rcdev->max_timeout = 10 * IR_DEFAULT_TIMEOUT;
+ if (pdata->allowed_protos)
+ rcdev->allowed_protocols = pdata->allowed_protos;
+ else
+@@ -154,6 +172,9 @@ static int gpio_ir_recv_probe(struct pla
+ gpio_dev->gpio_nr = pdata->gpio_nr;
+ gpio_dev->active_low = pdata->active_low;
+
++ setup_timer(&gpio_dev->flush_timer, flush_timer,
++ (unsigned long)gpio_dev);
++
+ rc = gpio_request(pdata->gpio_nr, "gpio-ir-recv");
+ if (rc < 0)
+ goto err_gpio_request;
+@@ -196,6 +217,7 @@ static int gpio_ir_recv_remove(struct pl
+ struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
+
+ free_irq(gpio_to_irq(gpio_dev->gpio_nr), gpio_dev);
++ del_timer_sync(&gpio_dev->flush_timer);
+ rc_unregister_device(gpio_dev->rcdev);
+ gpio_free(gpio_dev->gpio_nr);
+ kfree(gpio_dev);
diff --git a/target/linux/brcm2708/patches-4.4/0374-smsir.h-remove-a-now-duplicated-definition-IR_DEFAUL.patch b/target/linux/brcm2708/patches-4.4/0374-smsir.h-remove-a-now-duplicated-definition-IR_DEFAUL.patch
new file mode 100644
index 0000000000..62dc60cc0e
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0374-smsir.h-remove-a-now-duplicated-definition-IR_DEFAUL.patch
@@ -0,0 +1,24 @@
+From 0208831d16535a040ffdce0afeeccd13253c2b02 Mon Sep 17 00:00:00 2001
+From: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+Date: Thu, 19 Nov 2015 11:41:36 -0200
+Subject: [PATCH 374/381] smsir.h: remove a now duplicated definition
+ (IR_DEFAULT_TIMEOUT)
+
+This macro is now part of the core. Remove from Siano driver.
+
+Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+---
+ drivers/media/common/siano/smsir.h | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/drivers/media/common/siano/smsir.h
++++ b/drivers/media/common/siano/smsir.h
+@@ -30,8 +30,6 @@ along with this program. If not, see <h
+ #include <linux/input.h>
+ #include <media/rc-core.h>
+
+-#define IR_DEFAULT_TIMEOUT 100
+-
+ struct smscore_device_t;
+
+ struct ir_t {
diff --git a/target/linux/brcm2708/patches-4.4/0375-Implement-a-wakeup-source-option-for-the-i2c-rtc-Dev.patch b/target/linux/brcm2708/patches-4.4/0375-Implement-a-wakeup-source-option-for-the-i2c-rtc-Dev.patch
new file mode 100644
index 0000000000..f12a50f54f
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0375-Implement-a-wakeup-source-option-for-the-i2c-rtc-Dev.patch
@@ -0,0 +1,36 @@
+From 5286423195daead727d1a76c9b16d75d7d34e915 Mon Sep 17 00:00:00 2001
+From: Nicolas Boullis <nboullis@debian.org>
+Date: Sat, 4 Jun 2016 00:57:06 +0200
+Subject: [PATCH 375/381] Implement a "wakeup-source" option for the i2c-rtc
+ DeviceTree overlay.
+
+See: https://github.com/raspberrypi/linux/pull/1511
+---
+ arch/arm/boot/dts/overlays/README | 3 +++
+ arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts | 4 ++++
+ 2 files changed, 7 insertions(+)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -445,6 +445,9 @@ Params: ds1307 Select t
+
+ trickle-resistor-ohms Resistor value for trickle charge (DS1339-only)
+
++ wakeup-source Specify that the RTC can be used as a wakeup
++ source
++
+
+ Name: i2c0-bcm2708
+ Info: Enable the i2c_bcm2708 driver for the i2c0 bus. Not all pin combinations
+--- a/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
+@@ -65,5 +65,9 @@
+ pcf8523 = <&pcf8523>,"status";
+ pcf8563 = <&pcf8563>,"status";
+ trickle-resistor-ohms = <&ds1339>,"trickle-resistor-ohms:0";
++ wakeup-source = <&ds1339>,"wakeup-source?",
++ <&ds3231>,"wakeup-source?",
++ <&mcp7940x>,"wakeup-source?",
++ <&mcp7941x>,"wakeup-source?";
+ };
+ };
diff --git a/target/linux/brcm2708/patches-4.4/0376-BCM270X_DT-Fix-rpi-dac-overlay.patch b/target/linux/brcm2708/patches-4.4/0376-BCM270X_DT-Fix-rpi-dac-overlay.patch
new file mode 100644
index 0000000000..1dd6c4ce63
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0376-BCM270X_DT-Fix-rpi-dac-overlay.patch
@@ -0,0 +1,34 @@
+From 0978d55c391b3698dbecfd927378dc24c57eaa07 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 3 Jun 2016 21:56:40 +0100
+Subject: [PATCH 376/381] BCM270X_DT: Fix rpi-dac overlay
+
+The rpi-dac overlay is almost identical to the hifiberry-dac overlay -
+the codec used is different but it also doesn't sit on the I2C bus. As
+a result, when the overlays were modified for dynamic loading and it
+was discovered that the hifiberry-dac overlay didn't work any more, the
+the rpi-dac overlay was also broken.
+
+The failure was caused by the fact that outside a bus, device names are
+constructed from the concatenation of the path elements leading to it,
+so moving the codec instantiation inside /soc caused the device name
+to get a "soc" added, breaking ALSA's naming.
+
+See: http://forum.kodi.tv/showthread.php?tid=269814&pid=2349776#pid2349776
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/overlays/rpi-dac-overlay.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/rpi-dac-overlay.dts
++++ b/arch/arm/boot/dts/overlays/rpi-dac-overlay.dts
+@@ -13,7 +13,7 @@
+ };
+
+ fragment@1 {
+- target = <&soc>;
++ target-path = "/";
+ __overlay__ {
+ pcm1794a-codec {
+ #sound-dai-cells = <0>;
diff --git a/target/linux/brcm2708/patches-4.4/0377-BCM270X_DT-Make-i2c-gpio-usable-by-other-overlays.patch b/target/linux/brcm2708/patches-4.4/0377-BCM270X_DT-Make-i2c-gpio-usable-by-other-overlays.patch
new file mode 100644
index 0000000000..d0124fac27
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0377-BCM270X_DT-Make-i2c-gpio-usable-by-other-overlays.patch
@@ -0,0 +1,37 @@
+From 432f47525a7916c723a80679b608f9bc0b4375b0 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 6 Jun 2016 09:23:37 +0100
+Subject: [PATCH 377/381] BCM270X_DT: Make i2c-gpio usable by other overlays
+
+Modify the i2c-gpio overlay to export symbol i2c-gpio for use by other
+overlays. Export the alias as well for good measure.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+--- a/arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts
+@@ -19,6 +19,21 @@
+ };
+ };
+ };
++
++ fragment@1 {
++ target-path = "/aliases";
++ __overlay__ {
++ i2c_gpio = "/i2c@0";
++ };
++ };
++
++ fragment@2 {
++ target-path = "/__symbols__";
++ __overlay__ {
++ i2c_gpio = "/i2c@0";
++ };
++ };
++
+ __overrides__ {
+ i2c_gpio_sda = <&i2c_gpio>,"gpios:4";
+ i2c_gpio_scl = <&i2c_gpio>,"gpios:16";
diff --git a/target/linux/brcm2708/patches-4.4/0381-Add-ads1015-overlay.patch b/target/linux/brcm2708/patches-4.4/0381-Add-ads1015-overlay.patch
new file mode 100644
index 0000000000..f51c65eb11
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0381-Add-ads1015-overlay.patch
@@ -0,0 +1,155 @@
+From 11e5c941ff3d09701e57d26b068f634fae29265c Mon Sep 17 00:00:00 2001
+From: Erik Sejr <erik@eriks.ssimicro.com>
+Date: Tue, 7 Jun 2016 20:58:17 -0400
+Subject: [PATCH 381/381] Add ads1015 overlay
+
+See: https://github.com/raspberrypi/linux/pull/1520
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 22 ++++++
+ arch/arm/boot/dts/overlays/ads1015-overlay.dts | 98 ++++++++++++++++++++++++++
+ 3 files changed, 121 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/ads1015-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -13,6 +13,7 @@ ifeq ($(CONFIG_ARCH_BCM2835),y)
+ endif
+
+ dtbo-$(RPI_DT_OVERLAYS) += adau1977-adc.dtbo
++dtbo-$(RPI_DT_OVERLAYS) += ads1015.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += ads7846.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += akkordion-iqdacplus.dtbo
+ dtbo-$(RPI_DT_OVERLAYS) += at86rf233.dtbo
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -168,6 +168,28 @@ Load: dtoverlay=adau1977-adc
+ Params: <None>
+
+
++Name: ads1015
++Info: Overlay for activation of Texas Instruments ADS1015 ADC over I2C
++Load: dtoverlay=ads1015,<param>=<val>
++Params: addr I2C bus address of device. Set based on how the
++ addr pin is wired. (default=0x48 assumes addr
++ is pulled to GND)
++ cha_enable Enable virtual channel a. (default=true)
++ cha_cfg Set the configuration for virtual channel a.
++ (default=4 configures this channel for the
++ voltage at A0 with respect to GND)
++ cha_datarate Set the datarate (samples/sec) for this channel.
++ (default=4 sets 1600 sps)
++ cha_gain Set the gain of the Programmable Gain
++ Amplifier for this channel. (default=2 sets the
++ full scale of the channel to 2.048 Volts)
++
++ Channel (ch) parameters can be set for each enabled channel.
++ A maximum of 4 channels can be enabled (letters a thru d).
++ For more information refer to the device datasheet at:
++ http://www.ti.com/lit/ds/symlink/ads1015.pdf
++
++
+ Name: ads7846
+ Info: ADS7846 Touch controller
+ Load: dtoverlay=ads7846,<param>=<val>
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/ads1015-overlay.dts
+@@ -0,0 +1,98 @@
++/*
++ * 2016 - Erik Sejr
++ */
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++ /* ----------- ADS1015 ------------ */
++ fragment@0 {
++ target = <&i2c_arm>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++ ads1015: ads1015 {
++ compatible = "ti,ads1015";
++ status = "okay";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0x48>;
++ };
++ };
++ };
++
++ fragment@1 {
++ target-path = "i2c_arm/ads1015";
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ channel_a: channel_a {
++ reg = <4>;
++ ti,gain = <2>;
++ ti,datarate = <4>;
++ };
++ };
++ };
++
++ fragment@2 {
++ target-path = "i2c_arm/ads1015";
++ __dormant__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ channel_b: channel_b {
++ reg = <5>;
++ ti,gain = <2>;
++ ti,datarate = <4>;
++ };
++ };
++ };
++
++ fragment@3 {
++ target-path = "i2c_arm/ads1015";
++ __dormant__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ channel_c: channel_c {
++ reg = <6>;
++ ti,gain = <2>;
++ ti,datarate = <4>;
++ };
++ };
++ };
++
++ fragment@4 {
++ target-path = "i2c_arm/ads1015";
++ __dormant__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ channel_d: channel_d {
++ reg = <7>;
++ ti,gain = <2>;
++ ti,datarate = <4>;
++ };
++ };
++ };
++
++ __overrides__ {
++ addr = <&ads1015>,"reg:0";
++ cha_enable = <0>,"=1";
++ cha_cfg = <&channel_a>,"reg:0";
++ cha_gain = <&channel_a>,"ti,gain:0";
++ cha_datarate = <&channel_a>,"ti,datarate:0";
++ chb_enable = <0>,"=2";
++ chb_cfg = <&channel_b>,"reg:0";
++ chb_gain = <&channel_b>,"ti,gain:0";
++ chb_datarate = <&channel_b>,"ti,datarate:0";
++ chc_enable = <0>,"=3";
++ chc_cfg = <&channel_c>,"reg:0";
++ chc_gain = <&channel_c>,"ti,gain:0";
++ chc_datarate = <&channel_c>,"ti,datarate:0";
++ chd_enable = <0>,"=4";
++ chd_cfg = <&channel_d>,"reg:0";
++ chd_gain = <&channel_d>,"ti,gain:0";
++ chd_datarate = <&channel_d>,"ti,datarate:0";
++ };
++
++};
diff --git a/target/linux/brcm2708/patches-4.4/1001-smsc95xx-disable-hw-csum.patch b/target/linux/brcm2708/patches-4.4/1001-smsc95xx-disable-hw-csum.patch
deleted file mode 100644
index eff1f0049c..0000000000
--- a/target/linux/brcm2708/patches-4.4/1001-smsc95xx-disable-hw-csum.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- a/drivers/net/usb/smsc95xx.c
-+++ b/drivers/net/usb/smsc95xx.c
-@@ -42,7 +42,7 @@
- #define LAN95XX_EEPROM_MAGIC (0x9500)
- #define EEPROM_MAC_OFFSET (0x01)
- #define DEFAULT_TX_CSUM_ENABLE (true)
--#define DEFAULT_RX_CSUM_ENABLE (true)
-+#define DEFAULT_RX_CSUM_ENABLE (false)
- #define SMSC95XX_INTERNAL_PHY_ID (1)
- #define SMSC95XX_TX_OVERHEAD (8)
- #define SMSC95XX_TX_OVERHEAD_CSUM (12)
diff --git a/target/linux/cns3xxx/patches-4.4/033-CNS3xxx-Fix-PCI-cns3xxx_write_config.patch b/target/linux/cns3xxx/patches-4.4/033-CNS3xxx-Fix-PCI-cns3xxx_write_config.patch
deleted file mode 100644
index 3f5ab06ba5..0000000000
--- a/target/linux/cns3xxx/patches-4.4/033-CNS3xxx-Fix-PCI-cns3xxx_write_config.patch
+++ /dev/null
@@ -1,19 +0,0 @@
---- a/arch/arm/mach-cns3xxx/pcie.c
-+++ b/arch/arm/mach-cns3xxx/pcie.c
-@@ -220,13 +220,13 @@ static void cns3xxx_write_config(struct
- u32 mask = (0x1ull << (size * 8)) - 1;
- int shift = (where % 4) * 8;
-
-- v = readl_relaxed(base + (where & 0xffc));
-+ v = readl_relaxed(base);
-
- v &= ~(mask << shift);
- v |= (val & mask) << shift;
-
-- writel_relaxed(v, base + (where & 0xffc));
-- readl_relaxed(base + (where & 0xffc));
-+ writel_relaxed(v, base);
-+ readl_relaxed(base);
- }
-
- static void __init cns3xxx_pcie_hw_init(struct cns3xxx_pcie *cnspci)
diff --git a/target/linux/cns3xxx/patches-4.4/075-spi_support.patch b/target/linux/cns3xxx/patches-4.4/075-spi_support.patch
index e539d1e16c..9011073c51 100644
--- a/target/linux/cns3xxx/patches-4.4/075-spi_support.patch
+++ b/target/linux/cns3xxx/patches-4.4/075-spi_support.patch
@@ -26,7 +26,7 @@
obj-$(CONFIG_SPI_DLN2) += spi-dln2.o
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
-@@ -698,6 +698,10 @@ struct spi_transfer {
+@@ -703,6 +703,10 @@ struct spi_transfer {
u32 speed_hz;
struct list_head transfer_list;
diff --git a/target/linux/cns3xxx/patches-4.4/130-Extend-PCIE_BUS_PEER2PEER-to-set-MRSS-128-to-fix-CNS3xxx-BM-DMA..patch b/target/linux/cns3xxx/patches-4.4/130-Extend-PCIE_BUS_PEER2PEER-to-set-MRSS-128-to-fix-CNS3xxx-BM-DMA..patch
index 208c80a791..96f20a494a 100644
--- a/target/linux/cns3xxx/patches-4.4/130-Extend-PCIE_BUS_PEER2PEER-to-set-MRSS-128-to-fix-CNS3xxx-BM-DMA..patch
+++ b/target/linux/cns3xxx/patches-4.4/130-Extend-PCIE_BUS_PEER2PEER-to-set-MRSS-128-to-fix-CNS3xxx-BM-DMA..patch
@@ -1,6 +1,6 @@
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
-@@ -1924,7 +1924,8 @@ static void pcie_write_mrrs(struct pci_d
+@@ -1938,7 +1938,8 @@ static void pcie_write_mrrs(struct pci_d
/* In the "safe" case, do not configure the MRRS. There appear to be
* issues with setting MRRS to 0 on a number of devices.
*/
@@ -12,7 +12,7 @@
/* For Max performance, the MRRS must be set to the largest supported
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
-@@ -756,7 +756,7 @@ enum pcie_bus_config_types {
+@@ -757,7 +757,7 @@ enum pcie_bus_config_types {
PCIE_BUS_DEFAULT, /* ensure MPS matches upstream bridge */
PCIE_BUS_SAFE, /* use largest MPS boot-time devices support */
PCIE_BUS_PERFORMANCE, /* use MPS and MRRS for best performance */
diff --git a/target/linux/generic/config-4.4 b/target/linux/generic/config-4.4
index ed7ae3ee15..456a4ab01e 100644
--- a/target/linux/generic/config-4.4
+++ b/target/linux/generic/config-4.4
@@ -1594,6 +1594,7 @@ CONFIG_INPUT_MISC=y
# CONFIG_INPUT_MOUSE is not set
# CONFIG_INPUT_MOUSEDEV is not set
# CONFIG_INPUT_MPU3050 is not set
+# CONFIG_INPUT_PALMAS_PWRBUTTON is not set
# CONFIG_INPUT_PCF8574 is not set
# CONFIG_INPUT_PCSPKR is not set
# CONFIG_INPUT_POLLDEV is not set
@@ -1604,6 +1605,10 @@ CONFIG_INPUT_MISC=y
# CONFIG_INPUT_SPARSEKMAP is not set
# CONFIG_INPUT_TABLET is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_TPS65218_PWRBUTTON is not set
+# CONFIG_INPUT_TWL4030_PWRBUTTON is not set
+# CONFIG_INPUT_TWL4030_VIBRA is not set
+# CONFIG_INPUT_TWL6040_VIBRA is not set
# CONFIG_INPUT_UINPUT is not set
# CONFIG_INPUT_WISTRON_BTNS is not set
# CONFIG_INPUT_YEALINK is not set
@@ -1824,6 +1829,7 @@ CONFIG_KERNFS=y
# CONFIG_KEYBOARD_SUNKBD is not set
# CONFIG_KEYBOARD_TCA6416 is not set
# CONFIG_KEYBOARD_TCA8418 is not set
+# CONFIG_KEYBOARD_TWL4030 is not set
# CONFIG_KEYBOARD_XTKBD is not set
# CONFIG_KEYS is not set
# CONFIG_KGDB is not set
@@ -4192,6 +4198,7 @@ CONFIG_TMPFS_XATTR=y
# CONFIG_TRACE_ENUM_MAP_FILE is not set
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_TRACE_SINK is not set
+# CONFIG_TRACING_EVENTS_GPIO is not set
CONFIG_TRACING_SUPPORT=y
CONFIG_TRAD_SIGNALS=y
# CONFIG_TRANSPARENT_HUGEPAGE is not set
@@ -4208,6 +4215,7 @@ CONFIG_TTY=y
# CONFIG_TUN is not set
# CONFIG_TUN_VNET_CROSS_LE is not set
# CONFIG_TWL4030_CORE is not set
+# CONFIG_TWL4030_MADC is not set
# CONFIG_TWL6030_GPADC is not set
# CONFIG_TWL6040_CORE is not set
# CONFIG_TYPHOON is not set
diff --git a/target/linux/generic/files/include/linux/ath9k_platform.h b/target/linux/generic/files/include/linux/ath9k_platform.h
index e543a64060..2c19f3b494 100644
--- a/target/linux/generic/files/include/linux/ath9k_platform.h
+++ b/target/linux/generic/files/include/linux/ath9k_platform.h
@@ -31,6 +31,10 @@ struct ath9k_platform_data {
u32 gpio_mask;
u32 gpio_val;
+ u32 bt_active_pin;
+ u32 bt_priority_pin;
+ u32 wlan_active_pin;
+
bool endian_check;
bool is_clk_25mhz;
bool tx_gain_buffalo;
diff --git a/target/linux/generic/patches-3.18/660-fq_codel_defaults.patch b/target/linux/generic/patches-3.18/660-fq_codel_defaults.patch
index 8c99e62cec..e0f73dedb9 100644
--- a/target/linux/generic/patches-3.18/660-fq_codel_defaults.patch
+++ b/target/linux/generic/patches-3.18/660-fq_codel_defaults.patch
@@ -1,11 +1,13 @@
--- a/net/sched/sch_fq_codel.c
+++ b/net/sched/sch_fq_codel.c
-@@ -387,7 +387,7 @@ static int fq_codel_init(struct Qdisc *s
+@@ -387,8 +387,8 @@ static int fq_codel_init(struct Qdisc *s
struct fq_codel_sched_data *q = qdisc_priv(sch);
int i;
- sch->limit = 10*1024;
+- q->flows_cnt = 1024;
+ sch->limit = 1024;
- q->flows_cnt = 1024;
++ q->flows_cnt = 128;
q->quantum = psched_mtu(qdisc_dev(sch));
q->perturbation = prandom_u32();
+ INIT_LIST_HEAD(&q->new_flows);
diff --git a/target/linux/generic/patches-4.1/660-fq_codel_defaults.patch b/target/linux/generic/patches-4.1/660-fq_codel_defaults.patch
index 8c99e62cec..e0f73dedb9 100644
--- a/target/linux/generic/patches-4.1/660-fq_codel_defaults.patch
+++ b/target/linux/generic/patches-4.1/660-fq_codel_defaults.patch
@@ -1,11 +1,13 @@
--- a/net/sched/sch_fq_codel.c
+++ b/net/sched/sch_fq_codel.c
-@@ -387,7 +387,7 @@ static int fq_codel_init(struct Qdisc *s
+@@ -387,8 +387,8 @@ static int fq_codel_init(struct Qdisc *s
struct fq_codel_sched_data *q = qdisc_priv(sch);
int i;
- sch->limit = 10*1024;
+- q->flows_cnt = 1024;
+ sch->limit = 1024;
- q->flows_cnt = 1024;
++ q->flows_cnt = 128;
q->quantum = psched_mtu(qdisc_dev(sch));
q->perturbation = prandom_u32();
+ INIT_LIST_HEAD(&q->new_flows);
diff --git a/target/linux/generic/patches-4.4/032-fq_codel-add-batch-ability-to-fq_codel_drop.patch b/target/linux/generic/patches-4.4/032-fq_codel-add-batch-ability-to-fq_codel_drop.patch
new file mode 100644
index 0000000000..d1390348cb
--- /dev/null
+++ b/target/linux/generic/patches-4.4/032-fq_codel-add-batch-ability-to-fq_codel_drop.patch
@@ -0,0 +1,189 @@
+From: Eric Dumazet <edumazet@google.com>
+Date: Sun, 1 May 2016 16:47:26 -0700
+Subject: [PATCH] fq_codel: add batch ability to fq_codel_drop()
+
+In presence of inelastic flows and stress, we can call
+fq_codel_drop() for every packet entering fq_codel qdisc.
+
+fq_codel_drop() is quite expensive, as it does a linear scan
+of 4 KB of memory to find a fat flow.
+Once found, it drops the oldest packet of this flow.
+
+Instead of dropping a single packet, try to drop 50% of the backlog
+of this fat flow, with a configurable limit of 64 packets per round.
+
+TCA_FQ_CODEL_DROP_BATCH_SIZE is the new attribute to make this
+limit configurable.
+
+With this strategy the 4 KB search is amortized to a single cache line
+per drop [1], so fq_codel_drop() no longer appears at the top of kernel
+profile in presence of few inelastic flows.
+
+[1] Assuming a 64byte cache line, and 1024 buckets
+
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Reported-by: Dave Taht <dave.taht@gmail.com>
+Cc: Jonathan Morton <chromatix99@gmail.com>
+Acked-by: Jesper Dangaard Brouer <brouer@redhat.com>
+Acked-by: Dave Taht
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/include/uapi/linux/pkt_sched.h
++++ b/include/uapi/linux/pkt_sched.h
+@@ -711,6 +711,7 @@ enum {
+ TCA_FQ_CODEL_FLOWS,
+ TCA_FQ_CODEL_QUANTUM,
+ TCA_FQ_CODEL_CE_THRESHOLD,
++ TCA_FQ_CODEL_DROP_BATCH_SIZE,
+ __TCA_FQ_CODEL_MAX
+ };
+
+--- a/net/sched/sch_fq_codel.c
++++ b/net/sched/sch_fq_codel.c
+@@ -57,6 +57,7 @@ struct fq_codel_sched_data {
+ u32 flows_cnt; /* number of flows */
+ u32 perturbation; /* hash perturbation */
+ u32 quantum; /* psched_mtu(qdisc_dev(sch)); */
++ u32 drop_batch_size;
+ struct codel_params cparams;
+ struct codel_stats cstats;
+ u32 drop_overlimit;
+@@ -133,17 +134,20 @@ static inline void flow_queue_add(struct
+ skb->next = NULL;
+ }
+
+-static unsigned int fq_codel_drop(struct Qdisc *sch)
++static unsigned int fq_codel_drop(struct Qdisc *sch, unsigned int max_packets)
+ {
+ struct fq_codel_sched_data *q = qdisc_priv(sch);
+ struct sk_buff *skb;
+ unsigned int maxbacklog = 0, idx = 0, i, len;
+ struct fq_codel_flow *flow;
++ unsigned int threshold;
+
+- /* Queue is full! Find the fat flow and drop packet from it.
++ /* Queue is full! Find the fat flow and drop packet(s) from it.
+ * This might sound expensive, but with 1024 flows, we scan
+ * 4KB of memory, and we dont need to handle a complex tree
+ * in fast path (packet queue/enqueue) with many cache misses.
++ * In stress mode, we'll try to drop 64 packets from the flow,
++ * amortizing this linear lookup to one cache line per drop.
+ */
+ for (i = 0; i < q->flows_cnt; i++) {
+ if (q->backlogs[i] > maxbacklog) {
+@@ -151,15 +155,24 @@ static unsigned int fq_codel_drop(struct
+ idx = i;
+ }
+ }
++
++ /* Our goal is to drop half of this fat flow backlog */
++ threshold = maxbacklog >> 1;
++
+ flow = &q->flows[idx];
+- skb = dequeue_head(flow);
+- len = qdisc_pkt_len(skb);
++ len = 0;
++ i = 0;
++ do {
++ skb = dequeue_head(flow);
++ len += qdisc_pkt_len(skb);
++ kfree_skb(skb);
++ } while (++i < max_packets && len < threshold);
++
++ flow->dropped += i;
+ q->backlogs[idx] -= len;
+- sch->q.qlen--;
+- qdisc_qstats_drop(sch);
+- qdisc_qstats_backlog_dec(sch, skb);
+- kfree_skb(skb);
+- flow->dropped++;
++ sch->qstats.drops += i;
++ sch->qstats.backlog -= len;
++ sch->q.qlen -= i;
+ return idx;
+ }
+
+@@ -168,14 +181,14 @@ static unsigned int fq_codel_qdisc_drop(
+ unsigned int prev_backlog;
+
+ prev_backlog = sch->qstats.backlog;
+- fq_codel_drop(sch);
++ fq_codel_drop(sch, 1U);
+ return prev_backlog - sch->qstats.backlog;
+ }
+
+ static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch)
+ {
+ struct fq_codel_sched_data *q = qdisc_priv(sch);
+- unsigned int idx, prev_backlog;
++ unsigned int idx, prev_backlog, prev_qlen;
+ struct fq_codel_flow *flow;
+ int uninitialized_var(ret);
+
+@@ -204,16 +217,22 @@ static int fq_codel_enqueue(struct sk_bu
+ return NET_XMIT_SUCCESS;
+
+ prev_backlog = sch->qstats.backlog;
+- q->drop_overlimit++;
+- /* Return Congestion Notification only if we dropped a packet
+- * from this flow.
++ prev_qlen = sch->q.qlen;
++
++ /* fq_codel_drop() is quite expensive, as it performs a linear search
++ * in q->backlogs[] to find a fat flow.
++ * So instead of dropping a single packet, drop half of its backlog
++ * with a 64 packets limit to not add a too big cpu spike here.
+ */
+- if (fq_codel_drop(sch) == idx)
+- return NET_XMIT_CN;
++ ret = fq_codel_drop(sch, q->drop_batch_size);
++
++ q->drop_overlimit += prev_qlen - sch->q.qlen;
+
+- /* As we dropped a packet, better let upper stack know this */
+- qdisc_tree_reduce_backlog(sch, 1, prev_backlog - sch->qstats.backlog);
+- return NET_XMIT_SUCCESS;
++ /* As we dropped packet(s), better let upper stack know this */
++ qdisc_tree_reduce_backlog(sch, prev_qlen - sch->q.qlen,
++ prev_backlog - sch->qstats.backlog);
++
++ return ret == idx ? NET_XMIT_CN : NET_XMIT_SUCCESS;
+ }
+
+ /* This is the specific function called from codel_dequeue()
+@@ -323,6 +342,7 @@ static const struct nla_policy fq_codel_
+ [TCA_FQ_CODEL_FLOWS] = { .type = NLA_U32 },
+ [TCA_FQ_CODEL_QUANTUM] = { .type = NLA_U32 },
+ [TCA_FQ_CODEL_CE_THRESHOLD] = { .type = NLA_U32 },
++ [TCA_FQ_CODEL_DROP_BATCH_SIZE] = { .type = NLA_U32 },
+ };
+
+ static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt)
+@@ -374,6 +394,9 @@ static int fq_codel_change(struct Qdisc
+ if (tb[TCA_FQ_CODEL_QUANTUM])
+ q->quantum = max(256U, nla_get_u32(tb[TCA_FQ_CODEL_QUANTUM]));
+
++ if (tb[TCA_FQ_CODEL_DROP_BATCH_SIZE])
++ q->drop_batch_size = min(1U, nla_get_u32(tb[TCA_FQ_CODEL_DROP_BATCH_SIZE]));
++
+ while (sch->q.qlen > sch->limit) {
+ struct sk_buff *skb = fq_codel_dequeue(sch);
+
+@@ -419,6 +442,7 @@ static int fq_codel_init(struct Qdisc *s
+
+ sch->limit = 10*1024;
+ q->flows_cnt = 1024;
++ q->drop_batch_size = 64;
+ q->quantum = psched_mtu(qdisc_dev(sch));
+ q->perturbation = prandom_u32();
+ INIT_LIST_HEAD(&q->new_flows);
+@@ -476,6 +500,8 @@ static int fq_codel_dump(struct Qdisc *s
+ q->cparams.ecn) ||
+ nla_put_u32(skb, TCA_FQ_CODEL_QUANTUM,
+ q->quantum) ||
++ nla_put_u32(skb, TCA_FQ_CODEL_DROP_BATCH_SIZE,
++ q->drop_batch_size) ||
+ nla_put_u32(skb, TCA_FQ_CODEL_FLOWS,
+ q->flows_cnt))
+ goto nla_put_failure;
diff --git a/target/linux/generic/patches-4.4/045-mtd-devices-m25p80-add-support-for-mmap-read-request.patch b/target/linux/generic/patches-4.4/045-mtd-devices-m25p80-add-support-for-mmap-read-request.patch
index ee85f448ff..c4c7e6e01d 100644
--- a/target/linux/generic/patches-4.4/045-mtd-devices-m25p80-add-support-for-mmap-read-request.patch
+++ b/target/linux/generic/patches-4.4/045-mtd-devices-m25p80-add-support-for-mmap-read-request.patch
@@ -15,7 +15,7 @@ Signed-off-by: Brian Norris <computersforpeace@gmail.com>
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
-@@ -131,6 +131,28 @@ static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
+@@ -131,6 +131,28 @@ static int m25p80_read(struct spi_nor *n
/* convert the dummy cycles to the number of bytes */
dummy /= 8;
diff --git a/target/linux/generic/patches-4.4/081-spi-bcm53xx-add-spi_flash_read-callback-for-MMIO-bas.patch b/target/linux/generic/patches-4.4/081-spi-bcm53xx-add-spi_flash_read-callback-for-MMIO-bas.patch
index 5f131e76d3..730f41e4a5 100644
--- a/target/linux/generic/patches-4.4/081-spi-bcm53xx-add-spi_flash_read-callback-for-MMIO-bas.patch
+++ b/target/linux/generic/patches-4.4/081-spi-bcm53xx-add-spi_flash_read-callback-for-MMIO-bas.patch
@@ -34,7 +34,7 @@ Signed-off-by: Mark Brown <broonie@kernel.org>
};
static inline u32 bcm53xxspi_read(struct bcm53xxspi *b53spi, u16 offset)
-@@ -32,6 +35,50 @@ static inline void bcm53xxspi_write(struct bcm53xxspi *b53spi, u16 offset,
+@@ -32,6 +35,50 @@ static inline void bcm53xxspi_write(stru
bcma_write32(b53spi->core, offset, value);
}
@@ -85,7 +85,7 @@ Signed-off-by: Mark Brown <broonie@kernel.org>
static inline unsigned int bcm53xxspi_calc_timeout(size_t len)
{
/* Do some magic calculation based on length and buad. Add 10% and 1. */
-@@ -176,6 +223,8 @@ static int bcm53xxspi_transfer_one(struct spi_master *master,
+@@ -176,6 +223,8 @@ static int bcm53xxspi_transfer_one(struc
u8 *buf;
size_t left;
@@ -94,7 +94,7 @@ Signed-off-by: Mark Brown <broonie@kernel.org>
if (t->tx_buf) {
buf = (u8 *)t->tx_buf;
left = t->len;
-@@ -206,6 +255,22 @@ static int bcm53xxspi_transfer_one(struct spi_master *master,
+@@ -206,6 +255,22 @@ static int bcm53xxspi_transfer_one(struc
return 0;
}
@@ -117,7 +117,7 @@ Signed-off-by: Mark Brown <broonie@kernel.org>
/**************************************************
* BCMA
**************************************************/
-@@ -222,6 +287,7 @@ MODULE_DEVICE_TABLE(bcma, bcm53xxspi_bcma_tbl);
+@@ -222,6 +287,7 @@ MODULE_DEVICE_TABLE(bcma, bcm53xxspi_bcm
static int bcm53xxspi_bcma_probe(struct bcma_device *core)
{
@@ -125,7 +125,7 @@ Signed-off-by: Mark Brown <broonie@kernel.org>
struct bcm53xxspi *b53spi;
struct spi_master *master;
int err;
-@@ -231,7 +297,7 @@ static int bcm53xxspi_bcma_probe(struct bcma_device *core)
+@@ -231,7 +297,7 @@ static int bcm53xxspi_bcma_probe(struct
return -ENOTSUPP;
}
@@ -134,7 +134,7 @@ Signed-off-by: Mark Brown <broonie@kernel.org>
if (!master)
return -ENOMEM;
-@@ -239,11 +305,19 @@ static int bcm53xxspi_bcma_probe(struct bcma_device *core)
+@@ -239,11 +305,19 @@ static int bcm53xxspi_bcma_probe(struct
b53spi->master = master;
b53spi->core = core;
diff --git a/target/linux/generic/patches-4.4/101-MIPS-fix-cache-flushing-for-highmem-pages.patch b/target/linux/generic/patches-4.4/101-MIPS-fix-cache-flushing-for-highmem-pages.patch
index 237f0e500c..e4ac2cd583 100644
--- a/target/linux/generic/patches-4.4/101-MIPS-fix-cache-flushing-for-highmem-pages.patch
+++ b/target/linux/generic/patches-4.4/101-MIPS-fix-cache-flushing-for-highmem-pages.patch
@@ -15,87 +15,17 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/arch/mips/mm/cache.c
+++ b/arch/mips/mm/cache.c
-@@ -14,6 +14,7 @@
- #include <linux/sched.h>
- #include <linux/syscalls.h>
- #include <linux/mm.h>
-+#include <linux/highmem.h>
-
- #include <asm/cacheflush.h>
- #include <asm/processor.h>
-@@ -78,18 +79,29 @@ SYSCALL_DEFINE3(cacheflush, unsigned lon
- return 0;
- }
-
-+static void
-+flush_highmem_page(struct page *page)
-+{
-+ void *addr = kmap_atomic(page);
-+ flush_data_cache_page((unsigned long)addr);
-+ kunmap_atomic(addr);
-+}
-+
- void __flush_dcache_page(struct page *page)
- {
- struct address_space *mapping = page_mapping(page);
- unsigned long addr;
-
-- if (PageHighMem(page))
-- return;
- if (mapping && !mapping_mapped(mapping)) {
- SetPageDcacheDirty(page);
- return;
- }
-
-+ if (PageHighMem(page)) {
-+ flush_highmem_page(page);
-+ return;
-+ }
-+
- /*
- * We could delay the flush for the !page_mapping case too. But that
- * case is for exec env/arg pages and those are %99 certainly going to
-@@ -105,6 +117,11 @@ void __flush_anon_page(struct page *page
+@@ -111,6 +111,13 @@ void __flush_anon_page(struct page *page
{
unsigned long addr = (unsigned long) page_address(page);
+ if (PageHighMem(page)) {
-+ flush_highmem_page(page);
++ addr = (unsigned long)kmap_atomic(page);
++ flush_data_cache_page(addr);
++ __kunmap_atomic((void *)addr);
+ return;
+ }
+
if (pages_do_alias(addr, vmaddr)) {
if (page_mapped(page) && !Page_dcache_dirty(page)) {
void *kaddr;
-@@ -123,8 +140,10 @@ void __flush_icache_page(struct vm_area_
- {
- unsigned long addr;
-
-- if (PageHighMem(page))
-+ if (PageHighMem(page)) {
-+ flush_highmem_page(page);
- return;
-+ }
-
- addr = (unsigned long) page_address(page);
- flush_data_cache_page(addr);
-@@ -142,12 +161,17 @@ void __update_cache(struct vm_area_struc
- if (unlikely(!pfn_valid(pfn)))
- return;
- page = pfn_to_page(pfn);
-- if (page_mapping(page) && Page_dcache_dirty(page)) {
-+ if (!Page_dcache_dirty(page) || !page_mapping(page))
-+ return;
-+
-+ if (PageHighMem(page)) {
-+ flush_highmem_page(page);
-+ } else {
- addr = (unsigned long) page_address(page);
- if (exec || pages_do_alias(addr, address & PAGE_MASK))
- flush_data_cache_page(addr);
-- ClearPageDcacheDirty(page);
- }
-+ ClearPageDcacheDirty(page);
- }
-
- unsigned long _page_cachable_default;
diff --git a/target/linux/generic/patches-4.4/206-mips-disable-vdso.patch b/target/linux/generic/patches-4.4/206-mips-disable-vdso.patch
index 1abe78f141..51b1d041bf 100644
--- a/target/linux/generic/patches-4.4/206-mips-disable-vdso.patch
+++ b/target/linux/generic/patches-4.4/206-mips-disable-vdso.patch
@@ -4,7 +4,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/arch/mips/vdso/Makefile
+++ b/arch/mips/vdso/Makefile
-@@ -26,11 +26,11 @@ aflags-vdso := $(ccflags-vdso) \
+@@ -28,11 +28,11 @@ aflags-vdso := $(ccflags-vdso) \
# the comments on that file.
#
ifndef CONFIG_CPU_MIPSR6
diff --git a/target/linux/generic/patches-4.4/207-mips-vdso-dbg-rebuild-after-genvdso.patch b/target/linux/generic/patches-4.4/207-mips-vdso-dbg-rebuild-after-genvdso.patch
index 2a36f2a7a0..7dbde1d974 100644
--- a/target/linux/generic/patches-4.4/207-mips-vdso-dbg-rebuild-after-genvdso.patch
+++ b/target/linux/generic/patches-4.4/207-mips-vdso-dbg-rebuild-after-genvdso.patch
@@ -1,8 +1,6 @@
-Index: linux-4.4.9/arch/mips/vdso/Makefile
-===================================================================
---- linux-4.4.9.orig/arch/mips/vdso/Makefile
-+++ linux-4.4.9/arch/mips/vdso/Makefile
-@@ -75,7 +75,7 @@ $(obj-vdso): KBUILD_AFLAGS := $(aflags-v
+--- a/arch/mips/vdso/Makefile
++++ b/arch/mips/vdso/Makefile
+@@ -77,7 +77,7 @@ $(obj-vdso): KBUILD_AFLAGS := $(aflags-v
$(obj)/vdso.lds: KBUILD_CPPFLAGS := $(native-abi)
@@ -11,12 +9,21 @@ Index: linux-4.4.9/arch/mips/vdso/Makefile
$(call if_changed,vdsold)
$(obj)/vdso-image.c: $(obj)/vdso.so.dbg $(obj)/genvdso FORCE
-@@ -109,7 +109,7 @@ $(obj)/vdso-o32.lds: KBUILD_CPPFLAGS :=
+@@ -111,7 +111,7 @@ $(obj)/vdso-o32.lds: KBUILD_CPPFLAGS :=
$(obj)/vdso-o32.lds: $(src)/vdso.lds.S FORCE
- $(call if_changed_dep,cpp_lds_S)
-
+ $(call if_changed_dep,cpp_lds_S)
+
-$(obj)/vdso-o32.so.dbg: $(obj)/vdso-o32.lds $(obj-vdso-o32) FORCE
+$(obj)/vdso-o32.so.dbg: $(obj)/vdso-o32.lds $(obj-vdso-o32) $(obj)/genvdso FORCE
- $(call if_changed,vdsold)
-
+ $(call if_changed,vdsold)
+
$(obj)/vdso-o32-image.c: VDSO_NAME := o32
+@@ -147,7 +147,7 @@ $(obj)/vdso-n32.lds: KBUILD_CPPFLAGS :=
+ $(obj)/vdso-n32.lds: $(src)/vdso.lds.S FORCE
+ $(call if_changed_dep,cpp_lds_S)
+
+-$(obj)/vdso-n32.so.dbg: $(obj)/vdso-n32.lds $(obj-vdso-n32) FORCE
++$(obj)/vdso-n32.so.dbg: $(obj)/vdso-n32.lds $(obj-vdso-n32) $(obj)/genvdso FORCE
+ $(call if_changed,vdsold)
+
+ $(obj)/vdso-n32-image.c: VDSO_NAME := n32
diff --git a/target/linux/generic/patches-4.4/271-uapi-libc-compat.h-do-not-rely-on-__GLIBC__.patch b/target/linux/generic/patches-4.4/271-uapi-libc-compat.h-do-not-rely-on-__GLIBC__.patch
index 61d3873c01..b8e6a3a882 100644
--- a/target/linux/generic/patches-4.4/271-uapi-libc-compat.h-do-not-rely-on-__GLIBC__.patch
+++ b/target/linux/generic/patches-4.4/271-uapi-libc-compat.h-do-not-rely-on-__GLIBC__.patch
@@ -26,6 +26,19 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+/* We have included libc headers... */
+#if !defined(__KERNEL__)
+-/* Coordinate with glibc net/if.h header. */
++/* Coordinate with libc net/if.h header. */
+ #if defined(_NET_IF_H)
+
+-/* GLIBC headers included first so don't define anything
++/* LIBC headers included first so don't define anything
+ * that would already be defined. */
+
+ #define __UAPI_DEF_IF_IFCONF 0
+@@ -85,10 +85,10 @@
+
+ #endif /* _NET_IF_H */
+
-/* Coordinate with glibc netinet/in.h header. */
+/* Coordinate with libc netinet/in.h header. */
#if defined(_NETINET_IN_H)
@@ -35,7 +48,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
* that would already be defined. */
#define __UAPI_DEF_IN_ADDR 0
#define __UAPI_DEF_IN_IPPROTO 0
-@@ -68,7 +68,7 @@
+@@ -102,7 +102,7 @@
* if the glibc code didn't define them. This guard matches
* the guard in glibc/inet/netinet/in.h which defines the
* additional in6_addr macros e.g. s6_addr16, and s6_addr32. */
@@ -44,7 +57,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
#define __UAPI_DEF_IN6_ADDR_ALT 0
#else
#define __UAPI_DEF_IN6_ADDR_ALT 1
-@@ -83,7 +83,7 @@
+@@ -117,7 +117,7 @@
#else
/* Linux headers included first, and we must define everything
@@ -53,7 +66,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
* __UAPI_DEF_* defines and adjust appropriately. */
#define __UAPI_DEF_IN_ADDR 1
#define __UAPI_DEF_IN_IPPROTO 1
-@@ -93,7 +93,7 @@
+@@ -127,7 +127,7 @@
#define __UAPI_DEF_IN_CLASS 1
#define __UAPI_DEF_IN6_ADDR 1
@@ -62,16 +75,16 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
* coordinate. */
#define __UAPI_DEF_IN6_ADDR_ALT 1
#define __UAPI_DEF_SOCKADDR_IN6 1
-@@ -115,7 +115,7 @@
+@@ -149,7 +149,7 @@
/* If we did not see any headers from any supported C libraries,
* or we are being included in the kernel, then define everything
* that we need. */
-#else /* !defined(__GLIBC__) */
+#else /* defined(__KERNEL__) */
- /* Definitions for in.h */
- #define __UAPI_DEF_IN_ADDR 1
-@@ -138,6 +138,6 @@
+ /* Definitions for if.h */
+ #define __UAPI_DEF_IF_IFCONF 1
+@@ -182,6 +182,6 @@
/* Definitions for xattr.h */
#define __UAPI_DEF_XATTR 1
diff --git a/target/linux/generic/patches-4.4/272-uapi-if_ether.h-prevent-redefinition-of-struct-ethhd.patch b/target/linux/generic/patches-4.4/272-uapi-if_ether.h-prevent-redefinition-of-struct-ethhd.patch
index ff7677f760..9065369040 100644
--- a/target/linux/generic/patches-4.4/272-uapi-if_ether.h-prevent-redefinition-of-struct-ethhd.patch
+++ b/target/linux/generic/patches-4.4/272-uapi-if_ether.h-prevent-redefinition-of-struct-ethhd.patch
@@ -40,9 +40,9 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
#endif /* _UAPI_LINUX_IF_ETHER_H */
--- a/include/uapi/linux/libc-compat.h
+++ b/include/uapi/linux/libc-compat.h
-@@ -51,6 +51,14 @@
- /* We have included libc headers... */
- #if !defined(__KERNEL__)
+@@ -85,6 +85,14 @@
+
+ #endif /* _NET_IF_H */
+/* musl defines the ethhdr struct itself in its netinet/if_ether.h.
+ * Glibc just includes the kernel header and uses a different guard. */
@@ -55,9 +55,9 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
/* Coordinate with libc netinet/in.h header. */
#if defined(_NETINET_IN_H)
-@@ -117,6 +125,9 @@
- * that we need. */
- #else /* defined(__KERNEL__) */
+@@ -161,6 +169,9 @@
+ /* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */
+ #define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1
+/* Definitions for if_ether.h */
+#define __UAPI_DEF_ETHHDR 1
diff --git a/target/linux/generic/patches-4.4/465-m25p80-mx-disable-software-protection.patch b/target/linux/generic/patches-4.4/465-m25p80-mx-disable-software-protection.patch
new file mode 100644
index 0000000000..cc2103b2e8
--- /dev/null
+++ b/target/linux/generic/patches-4.4/465-m25p80-mx-disable-software-protection.patch
@@ -0,0 +1,14 @@
+Disable software protection bits for Macronix flashes.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1156,6 +1156,7 @@ int spi_nor_scan(struct spi_nor *nor, co
+
+ if (JEDEC_MFR(info) == SNOR_MFR_ATMEL ||
+ JEDEC_MFR(info) == SNOR_MFR_INTEL ||
++ JEDEC_MFR(info) == SNOR_MFR_MACRONIX ||
+ JEDEC_MFR(info) == SNOR_MFR_SST) {
+ write_enable(nor);
+ write_sr(nor, 0);
diff --git a/target/linux/generic/patches-4.4/494-mtd-ubi-add-EOF-marker-support.patch b/target/linux/generic/patches-4.4/494-mtd-ubi-add-EOF-marker-support.patch
index 14fae764fe..dd5ee306ef 100644
--- a/target/linux/generic/patches-4.4/494-mtd-ubi-add-EOF-marker-support.patch
+++ b/target/linux/generic/patches-4.4/494-mtd-ubi-add-EOF-marker-support.patch
@@ -41,7 +41,7 @@
break;
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
-@@ -739,6 +739,7 @@ struct ubi_attach_info {
+@@ -741,6 +741,7 @@ struct ubi_attach_info {
int mean_ec;
uint64_t ec_sum;
int ec_count;
diff --git a/target/linux/generic/patches-4.4/506-yaffs2-using-new-follow_link-and-put_link.patch b/target/linux/generic/patches-4.4/506-yaffs2-using-new-follow_link-and-put_link.patch
new file mode 100644
index 0000000000..60c4e378e0
--- /dev/null
+++ b/target/linux/generic/patches-4.4/506-yaffs2-using-new-follow_link-and-put_link.patch
@@ -0,0 +1,47 @@
+From d4eb3ab036f8c37c5bc5f45ad0fa4dc34b7228c8 Mon Sep 17 00:00:00 2001
+From: Kevin Hao <kexin.hao@windriver.com>
+Date: Wed, 24 Feb 2016 14:37:13 +0800
+Subject: [PATCH 3/3] yaffs2: using new ->follow_link() and ->put_link()
+ calling conventions
+
+As what we did in commit 680baacbca69 ("new ->follow_link() and
+->put_link() calling conventions").
+
+Signed-off-by: Kevin Hao <kexin.hao@windriver.com>
+Signed-off-by: Bruce Ashfield <bruce.ashfield@windriver.com>
+---
+ fs/yaffs2/yaffs_vfs.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/fs/yaffs2/yaffs_vfs.c
++++ b/fs/yaffs2/yaffs_vfs.c
+@@ -1060,7 +1060,7 @@ static int yaffs_readlink(struct dentry
+ }
+
+ #if (YAFFS_NEW_FOLLOW_LINK == 1)
+-static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
++static const char *yaffs_follow_link(struct dentry *dentry, void **cookie)
+ {
+ void *ret;
+ #else
+@@ -1082,7 +1082,7 @@ static int yaffs_follow_link(struct dent
+ goto out;
+ }
+ #if (YAFFS_NEW_FOLLOW_LINK == 1)
+- nd_set_link(nd, alias);
++ *cookie = alias;
+ ret = alias;
+ out:
+ if (ret_int)
+@@ -1114,9 +1114,9 @@ static void yaffs_put_inode(struct inode
+ #endif
+
+ #if (YAFFS_NEW_FOLLOW_LINK == 1)
+-void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias)
++void yaffs_put_link(struct inode *inode, void *cookie)
+ {
+- kfree(alias);
++ kfree(cookie);
+ }
+ #endif
+
diff --git a/target/linux/generic/patches-4.4/630-packet_socket_type.patch b/target/linux/generic/patches-4.4/630-packet_socket_type.patch
index d2f6d7bc16..a7ffccc2a6 100644
--- a/target/linux/generic/patches-4.4/630-packet_socket_type.patch
+++ b/target/linux/generic/patches-4.4/630-packet_socket_type.patch
@@ -51,7 +51,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
goto out;
if (!net_eq(dev_net(dev), sock_net(sk)))
-@@ -1982,12 +1984,12 @@ static int packet_rcv(struct sk_buff *sk
+@@ -1986,12 +1988,12 @@ static int packet_rcv(struct sk_buff *sk
int skb_len = skb->len;
unsigned int snaplen, res;
@@ -67,7 +67,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
if (!net_eq(dev_net(dev), sock_net(sk)))
goto drop;
-@@ -2107,12 +2109,12 @@ static int tpacket_rcv(struct sk_buff *s
+@@ -2111,12 +2113,12 @@ static int tpacket_rcv(struct sk_buff *s
BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h2)) != 32);
BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h3)) != 48);
@@ -83,7 +83,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
if (!net_eq(dev_net(dev), sock_net(sk)))
goto drop;
-@@ -3097,6 +3099,7 @@ static int packet_create(struct net *net
+@@ -3092,6 +3094,7 @@ static int packet_create(struct net *net
mutex_init(&po->pg_vec_lock);
po->rollover = NULL;
po->prot_hook.func = packet_rcv;
@@ -91,7 +91,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
if (sock->type == SOCK_PACKET)
po->prot_hook.func = packet_rcv_spkt;
-@@ -3712,6 +3715,16 @@ packet_setsockopt(struct socket *sock, i
+@@ -3708,6 +3711,16 @@ packet_setsockopt(struct socket *sock, i
po->xmit = val ? packet_direct_xmit : dev_queue_xmit;
return 0;
}
@@ -108,7 +108,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
default:
return -ENOPROTOOPT;
}
-@@ -3764,6 +3777,13 @@ static int packet_getsockopt(struct sock
+@@ -3760,6 +3773,13 @@ static int packet_getsockopt(struct sock
case PACKET_VNET_HDR:
val = po->has_vnet_hdr;
break;
diff --git a/target/linux/generic/patches-4.4/642-bridge_port_isolate.patch b/target/linux/generic/patches-4.4/642-bridge_port_isolate.patch
index 6656bbe630..3ece047317 100644
--- a/target/linux/generic/patches-4.4/642-bridge_port_isolate.patch
+++ b/target/linux/generic/patches-4.4/642-bridge_port_isolate.patch
@@ -11,8 +11,8 @@ Isolating individual bridge ports
#define BR_PROXYARP_WIFI BIT(10)
+#define BR_ISOLATE_MODE BIT(11)
- /* values as per ieee8021QBridgeFdbAgingTime */
- #define BR_MIN_AGEING_TIME (10 * HZ)
+ #define BR_DEFAULT_AGEING_TIME (300 * HZ)
+
--- a/net/bridge/br_sysfs_if.c
+++ b/net/bridge/br_sysfs_if.c
@@ -173,6 +173,22 @@ BRPORT_ATTR_FLAG(unicast_flood, BR_FLOOD
@@ -24,7 +24,7 @@ Isolating individual bridge ports
+ int isolate_mode = (p->flags & BR_ISOLATE_MODE) ? 1 : 0;
+ return sprintf(buf, "%d\n", isolate_mode);
+}
-+static ssize_t store_isolate_mode(struct net_bridge_port *p, unsigned long v)
++static int store_isolate_mode(struct net_bridge_port *p, unsigned long v)
+{
+ if (v)
+ p->flags |= BR_ISOLATE_MODE;
diff --git a/target/linux/generic/patches-4.4/645-bridge_multicast_to_unicast.patch b/target/linux/generic/patches-4.4/645-bridge_multicast_to_unicast.patch
index 97a46fd334..bab091262c 100644
--- a/target/linux/generic/patches-4.4/645-bridge_multicast_to_unicast.patch
+++ b/target/linux/generic/patches-4.4/645-bridge_multicast_to_unicast.patch
@@ -11,8 +11,8 @@ Implement optinal multicast->unicast conversion for igmp snooping
#define BR_ISOLATE_MODE BIT(11)
+#define BR_MULTICAST_TO_UCAST BIT(12)
- /* values as per ieee8021QBridgeFdbAgingTime */
- #define BR_MIN_AGEING_TIME (10 * HZ)
+ #define BR_DEFAULT_AGEING_TIME (300 * HZ)
+
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -42,12 +42,13 @@ static void br_multicast_add_router(stru
@@ -172,7 +172,7 @@ Implement optinal multicast->unicast conversion for igmp snooping
if (!err)
break;
}
-@@ -1422,7 +1448,8 @@ br_multicast_leave_group(struct net_brid
+@@ -1424,7 +1450,8 @@ br_multicast_leave_group(struct net_brid
struct net_bridge_port *port,
struct br_ip *group,
struct bridge_mcast_other_query *other_query,
@@ -182,7 +182,7 @@ Implement optinal multicast->unicast conversion for igmp snooping
{
struct net_bridge_mdb_htable *mdb;
struct net_bridge_mdb_entry *mp;
-@@ -1446,7 +1473,7 @@ br_multicast_leave_group(struct net_brid
+@@ -1448,7 +1475,7 @@ br_multicast_leave_group(struct net_brid
for (pp = &mp->ports;
(p = mlock_dereference(*pp, br)) != NULL;
pp = &p->next) {
@@ -191,7 +191,7 @@ Implement optinal multicast->unicast conversion for igmp snooping
continue;
rcu_assign_pointer(*pp, p->next);
-@@ -1509,7 +1536,7 @@ br_multicast_leave_group(struct net_brid
+@@ -1511,7 +1538,7 @@ br_multicast_leave_group(struct net_brid
for (p = mlock_dereference(mp->ports, br);
p != NULL;
p = mlock_dereference(p->next, br)) {
@@ -200,7 +200,7 @@ Implement optinal multicast->unicast conversion for igmp snooping
continue;
if (!hlist_unhashed(&p->mglist) &&
-@@ -1527,8 +1554,8 @@ out:
+@@ -1529,8 +1556,8 @@ out:
static void br_ip4_multicast_leave_group(struct net_bridge *br,
struct net_bridge_port *port,
@@ -211,7 +211,7 @@ Implement optinal multicast->unicast conversion for igmp snooping
{
struct br_ip br_group;
struct bridge_mcast_own_query *own_query;
-@@ -1543,14 +1570,14 @@ static void br_ip4_multicast_leave_group
+@@ -1545,14 +1572,14 @@ static void br_ip4_multicast_leave_group
br_group.vid = vid;
br_multicast_leave_group(br, port, &br_group, &br->ip4_other_query,
@@ -228,7 +228,7 @@ Implement optinal multicast->unicast conversion for igmp snooping
{
struct br_ip br_group;
struct bridge_mcast_own_query *own_query;
-@@ -1565,7 +1592,7 @@ static void br_ip6_multicast_leave_group
+@@ -1567,7 +1594,7 @@ static void br_ip6_multicast_leave_group
br_group.vid = vid;
br_multicast_leave_group(br, port, &br_group, &br->ip6_other_query,
@@ -237,7 +237,7 @@ Implement optinal multicast->unicast conversion for igmp snooping
}
#endif
-@@ -1574,6 +1601,7 @@ static int br_multicast_ipv4_rcv(struct
+@@ -1576,6 +1603,7 @@ static int br_multicast_ipv4_rcv(struct
struct sk_buff *skb,
u16 vid)
{
@@ -245,7 +245,7 @@ Implement optinal multicast->unicast conversion for igmp snooping
struct sk_buff *skb_trimmed = NULL;
struct igmphdr *ih;
int err;
-@@ -1590,12 +1618,13 @@ static int br_multicast_ipv4_rcv(struct
+@@ -1592,12 +1620,13 @@ static int br_multicast_ipv4_rcv(struct
BR_INPUT_SKB_CB(skb)->igmp = 1;
ih = igmp_hdr(skb);
@@ -260,7 +260,7 @@ Implement optinal multicast->unicast conversion for igmp snooping
break;
case IGMPV3_HOST_MEMBERSHIP_REPORT:
err = br_ip4_multicast_igmp3_report(br, port, skb_trimmed, vid);
-@@ -1604,7 +1633,7 @@ static int br_multicast_ipv4_rcv(struct
+@@ -1606,7 +1635,7 @@ static int br_multicast_ipv4_rcv(struct
err = br_ip4_multicast_query(br, port, skb_trimmed, vid);
break;
case IGMP_HOST_LEAVE_MESSAGE:
@@ -269,7 +269,7 @@ Implement optinal multicast->unicast conversion for igmp snooping
break;
}
-@@ -1620,6 +1649,7 @@ static int br_multicast_ipv6_rcv(struct
+@@ -1622,6 +1651,7 @@ static int br_multicast_ipv6_rcv(struct
struct sk_buff *skb,
u16 vid)
{
@@ -277,7 +277,7 @@ Implement optinal multicast->unicast conversion for igmp snooping
struct sk_buff *skb_trimmed = NULL;
struct mld_msg *mld;
int err;
-@@ -1639,8 +1669,9 @@ static int br_multicast_ipv6_rcv(struct
+@@ -1641,8 +1671,9 @@ static int br_multicast_ipv6_rcv(struct
switch (mld->mld_type) {
case ICMPV6_MGM_REPORT:
@@ -288,7 +288,7 @@ Implement optinal multicast->unicast conversion for igmp snooping
break;
case ICMPV6_MLD2_REPORT:
err = br_ip6_multicast_mld2_report(br, port, skb_trimmed, vid);
-@@ -1649,7 +1680,8 @@ static int br_multicast_ipv6_rcv(struct
+@@ -1651,7 +1682,8 @@ static int br_multicast_ipv6_rcv(struct
err = br_ip6_multicast_query(br, port, skb_trimmed, vid);
break;
case ICMPV6_MGM_REDUCTION:
@@ -300,17 +300,17 @@ Implement optinal multicast->unicast conversion for igmp snooping
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
-@@ -158,6 +158,9 @@ struct net_bridge_port_group {
+@@ -157,7 +157,9 @@ struct net_bridge_port_group {
+ struct rcu_head rcu;
struct timer_list timer;
struct br_ip addr;
- unsigned char state;
-+
+ unsigned char eth_addr[ETH_ALEN];
+ unsigned char state;
+ bool unicast;
};
struct net_bridge_mdb_entry
-@@ -554,7 +557,8 @@ void br_multicast_free_pg(struct rcu_hea
+@@ -554,7 +556,8 @@ void br_multicast_free_pg(struct rcu_hea
struct net_bridge_port_group *
br_multicast_new_port_group(struct net_bridge_port *port, struct br_ip *group,
struct net_bridge_port_group __rcu *next,
diff --git a/target/linux/generic/patches-4.4/655-increase_skb_pad.patch b/target/linux/generic/patches-4.4/655-increase_skb_pad.patch
index e46e4709c1..ad95d4c67e 100644
--- a/target/linux/generic/patches-4.4/655-increase_skb_pad.patch
+++ b/target/linux/generic/patches-4.4/655-increase_skb_pad.patch
@@ -1,6 +1,6 @@
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
-@@ -2155,7 +2155,7 @@ static inline int pskb_network_may_pull(
+@@ -2179,7 +2179,7 @@ static inline int pskb_network_may_pull(
* NET_IP_ALIGN(2) + ethernet_header(14) + IP_header(20/40) + ports(8)
*/
#ifndef NET_SKB_PAD
diff --git a/target/linux/generic/patches-4.4/656-skb_reduce_truesize-helper.patch b/target/linux/generic/patches-4.4/656-skb_reduce_truesize-helper.patch
deleted file mode 100644
index 341a31b137..0000000000
--- a/target/linux/generic/patches-4.4/656-skb_reduce_truesize-helper.patch
+++ /dev/null
@@ -1,41 +0,0 @@
-From 4593a806e31119c5bd3faa00c7210ad862d515af Mon Sep 17 00:00:00 2001
-From: Dave Taht <dave.taht@bufferbloat.net>
-Date: Mon, 31 Dec 2012 10:02:21 -0800
-Subject: [PATCH 3/7] skb_reduce_truesize: helper function for shrinking skbs
- whenever needed
-
-On embedded devices in particular, large queues of small packets from the rx
-path with a large truesize can exist. Reducing their size can reduce
-memory pressure. skb_reduce_truesize is a helper function for doing this,
-when needed.
----
- include/linux/skbuff.h | 18 ++++++++++++++++++
- 1 file changed, 18 insertions(+)
-
---- a/include/linux/skbuff.h
-+++ b/include/linux/skbuff.h
-@@ -2200,6 +2200,24 @@ static inline void pskb_trim_unique(stru
- BUG_ON(err);
- }
-
-+/*
-+ * Caller wants to reduce memory needs before queueing skb
-+ * The (expensive) copy should not be be done in fast path.
-+ */
-+static inline struct sk_buff *skb_reduce_truesize(struct sk_buff *skb)
-+{
-+ if (skb->truesize > 2 * SKB_TRUESIZE(skb->len)) {
-+ struct sk_buff *nskb;
-+ nskb = skb_copy_expand(skb, skb_headroom(skb), 0,
-+ GFP_ATOMIC | __GFP_NOWARN);
-+ if (nskb) {
-+ __kfree_skb(skb);
-+ skb = nskb;
-+ }
-+ }
-+ return skb;
-+}
-+
- /**
- * skb_orphan - orphan a buffer
- * @skb: buffer to orphan
diff --git a/target/linux/generic/patches-4.4/657-qdisc_reduce_truesize.patch b/target/linux/generic/patches-4.4/657-qdisc_reduce_truesize.patch
deleted file mode 100644
index d9f5b4fb63..0000000000
--- a/target/linux/generic/patches-4.4/657-qdisc_reduce_truesize.patch
+++ /dev/null
@@ -1,63 +0,0 @@
-From bc9fec2f87d57bdbff30d296605e24504513f65c Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Dave=20T=C3=A4ht?= <dave.taht@bufferbloat.net>
-Date: Mon, 17 Sep 2012 19:20:22 -0700
-Subject: [PATCH 4/7] net: add skb_reduce_truesize support to common qdiscs
-
-Reduce skb size under load when queues begin to fill on the
-commont qdiscs.
----
- net/sched/sch_codel.c | 2 ++
- net/sched/sch_fifo.c | 12 ++++++++----
- net/sched/sch_fq_codel.c | 2 ++
- 3 files changed, 12 insertions(+), 4 deletions(-)
-
---- a/net/sched/sch_codel.c
-+++ b/net/sched/sch_codel.c
-@@ -96,6 +96,8 @@ static int codel_qdisc_enqueue(struct sk
- struct codel_sched_data *q;
-
- if (likely(qdisc_qlen(sch) < sch->limit)) {
-+ if(qdisc_qlen(sch) > 128)
-+ skb = skb_reduce_truesize(skb);
- codel_set_enqueue_time(skb);
- return qdisc_enqueue_tail(skb, sch);
- }
---- a/net/sched/sch_fifo.c
-+++ b/net/sched/sch_fifo.c
-@@ -29,17 +29,21 @@ static int bfifo_enqueue(struct sk_buff
-
- static int pfifo_enqueue(struct sk_buff *skb, struct Qdisc *sch)
- {
-- if (likely(skb_queue_len(&sch->q) < sch->limit))
-+ if (likely(skb_queue_len(&sch->q) < sch->limit)) {
-+ if (skb_queue_len(&sch->q) > 128)
-+ skb = skb_reduce_truesize(skb);
- return qdisc_enqueue_tail(skb, sch);
--
-+ }
- return qdisc_reshape_fail(skb, sch);
- }
-
- static int pfifo_tail_enqueue(struct sk_buff *skb, struct Qdisc *sch)
- {
-- if (likely(skb_queue_len(&sch->q) < sch->limit))
-+ if (likely(skb_queue_len(&sch->q) < sch->limit)) {
-+ if (skb_queue_len(&sch->q) > 128)
-+ skb = skb_reduce_truesize(skb);
- return qdisc_enqueue_tail(skb, sch);
--
-+ }
- /* queue full, remove one skb to fulfill the limit */
- __qdisc_queue_drop_head(sch, &sch->q);
- qdisc_qstats_drop(sch);
---- a/net/sched/sch_fq_codel.c
-+++ b/net/sched/sch_fq_codel.c
-@@ -187,6 +187,8 @@ static int fq_codel_enqueue(struct sk_bu
- return ret;
- }
- idx--;
-+ if (sch->q.qlen > 128)
-+ skb = skb_reduce_truesize(skb);
-
- codel_set_enqueue_time(skb);
- flow = &q->flows[idx];
diff --git a/target/linux/generic/patches-4.4/660-fq_codel_defaults.patch b/target/linux/generic/patches-4.4/660-fq_codel_defaults.patch
index cf4ff6fb18..bbf281009d 100644
--- a/target/linux/generic/patches-4.4/660-fq_codel_defaults.patch
+++ b/target/linux/generic/patches-4.4/660-fq_codel_defaults.patch
@@ -1,11 +1,13 @@
--- a/net/sched/sch_fq_codel.c
+++ b/net/sched/sch_fq_codel.c
-@@ -412,7 +412,7 @@ static int fq_codel_init(struct Qdisc *s
+@@ -440,8 +440,8 @@ static int fq_codel_init(struct Qdisc *s
struct fq_codel_sched_data *q = qdisc_priv(sch);
int i;
- sch->limit = 10*1024;
+- q->flows_cnt = 1024;
+ sch->limit = 1024;
- q->flows_cnt = 1024;
++ q->flows_cnt = 128;
+ q->drop_batch_size = 64;
q->quantum = psched_mtu(qdisc_dev(sch));
q->perturbation = prandom_u32();
diff --git a/target/linux/generic/patches-4.4/661-fq_codel_keep_dropped_stats.patch b/target/linux/generic/patches-4.4/661-fq_codel_keep_dropped_stats.patch
index 0efc61b1b0..cb3bb2f28d 100644
--- a/target/linux/generic/patches-4.4/661-fq_codel_keep_dropped_stats.patch
+++ b/target/linux/generic/patches-4.4/661-fq_codel_keep_dropped_stats.patch
@@ -1,6 +1,6 @@
--- a/net/sched/sch_fq_codel.c
+++ b/net/sched/sch_fq_codel.c
-@@ -200,7 +200,6 @@ static int fq_codel_enqueue(struct sk_bu
+@@ -211,7 +211,6 @@ static int fq_codel_enqueue(struct sk_bu
list_add_tail(&flow->flowchain, &q->new_flows);
q->new_flow_count++;
flow->deficit = q->quantum;
diff --git a/target/linux/generic/patches-4.4/662-use_fq_codel_by_default.patch b/target/linux/generic/patches-4.4/662-use_fq_codel_by_default.patch
index d3aeb9256f..a1ade521b6 100644
--- a/target/linux/generic/patches-4.4/662-use_fq_codel_by_default.patch
+++ b/target/linux/generic/patches-4.4/662-use_fq_codel_by_default.patch
@@ -13,7 +13,7 @@
device, it has to decide which ones to send first, which ones to
--- a/net/sched/sch_fq_codel.c
+++ b/net/sched/sch_fq_codel.c
-@@ -623,7 +623,7 @@ static const struct Qdisc_class_ops fq_c
+@@ -654,7 +654,7 @@ static const struct Qdisc_class_ops fq_c
.walk = fq_codel_walk,
};
@@ -22,7 +22,7 @@
.cl_ops = &fq_codel_class_ops,
.id = "fq_codel",
.priv_size = sizeof(struct fq_codel_sched_data),
-@@ -639,6 +639,7 @@ static struct Qdisc_ops fq_codel_qdisc_o
+@@ -670,6 +670,7 @@ static struct Qdisc_ops fq_codel_qdisc_o
.dump_stats = fq_codel_dump_stats,
.owner = THIS_MODULE,
};
@@ -42,7 +42,16 @@
struct Qdisc_class_common {
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
-@@ -728,7 +728,7 @@ static void attach_one_default_qdisc(str
+@@ -31,7 +31,7 @@
+ #include <net/dst.h>
+
+ /* Qdisc to use by default */
+-const struct Qdisc_ops *default_qdisc_ops = &pfifo_fast_ops;
++const struct Qdisc_ops *default_qdisc_ops = &fq_codel_qdisc_ops;
+ EXPORT_SYMBOL(default_qdisc_ops);
+
+ /* Main transmission queue. */
+@@ -731,7 +731,7 @@ static void attach_one_default_qdisc(str
void *_unused)
{
struct Qdisc *qdisc;
@@ -73,3 +82,14 @@
TC_H_MAKE(TC_H_MAJ(sch->handle),
TC_H_MIN(i + 1)));
if (qdisc == NULL) {
+--- a/net/sched/sch_api.c
++++ b/net/sched/sch_api.c
+@@ -1948,7 +1948,7 @@ static int __init pktsched_init(void)
+ return err;
+ }
+
+- register_qdisc(&pfifo_fast_ops);
++ register_qdisc(&fq_codel_qdisc_ops);
+ register_qdisc(&pfifo_qdisc_ops);
+ register_qdisc(&bfifo_qdisc_ops);
+ register_qdisc(&pfifo_head_drop_qdisc_ops);
diff --git a/target/linux/generic/patches-4.4/663-remove_pfifo_fast.patch b/target/linux/generic/patches-4.4/663-remove_pfifo_fast.patch
index d28835b9c6..6f72b19358 100644
--- a/target/linux/generic/patches-4.4/663-remove_pfifo_fast.patch
+++ b/target/linux/generic/patches-4.4/663-remove_pfifo_fast.patch
@@ -1,6 +1,6 @@
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
-@@ -435,139 +435,6 @@ struct Qdisc_ops noqueue_qdisc_ops __rea
+@@ -438,139 +438,6 @@ struct Qdisc_ops noqueue_qdisc_ops __rea
.owner = THIS_MODULE,
};
diff --git a/target/linux/generic/patches-4.4/664-codel_fix_3_12.patch b/target/linux/generic/patches-4.4/664-codel_fix_3_12.patch
deleted file mode 100644
index 4d4ca250f1..0000000000
--- a/target/linux/generic/patches-4.4/664-codel_fix_3_12.patch
+++ /dev/null
@@ -1,22 +0,0 @@
---- a/net/sched/sch_api.c
-+++ b/net/sched/sch_api.c
-@@ -1946,7 +1946,7 @@ static int __init pktsched_init(void)
- return err;
- }
-
-- register_qdisc(&pfifo_fast_ops);
-+ register_qdisc(&fq_codel_qdisc_ops);
- register_qdisc(&pfifo_qdisc_ops);
- register_qdisc(&bfifo_qdisc_ops);
- register_qdisc(&pfifo_head_drop_qdisc_ops);
---- a/net/sched/sch_generic.c
-+++ b/net/sched/sch_generic.c
-@@ -31,7 +31,7 @@
- #include <net/dst.h>
-
- /* Qdisc to use by default */
--const struct Qdisc_ops *default_qdisc_ops = &pfifo_fast_ops;
-+const struct Qdisc_ops *default_qdisc_ops = &fq_codel_qdisc_ops;
- EXPORT_SYMBOL(default_qdisc_ops);
-
- /* Main transmission queue. */
diff --git a/target/linux/generic/patches-4.4/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch b/target/linux/generic/patches-4.4/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch
index d511520dea..657804a277 100644
--- a/target/linux/generic/patches-4.4/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch
+++ b/target/linux/generic/patches-4.4/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch
@@ -295,15 +295,15 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
__skb_tunnel_rx(skb, t->dev, t->net);
-@@ -1179,6 +1316,7 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, str
+@@ -1224,6 +1361,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, str
__u32 mtu;
u8 tproto;
int err;
+ struct __ip6_tnl_fmr *fmr;
tproto = ACCESS_ONCE(t->parms.proto);
- if (tproto != IPPROTO_IPIP && tproto != 0)
-@@ -1198,6 +1336,18 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, str
+ if ((tproto != IPPROTO_IPV6 && tproto != 0) ||
+@@ -1254,6 +1392,18 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, str
if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
fl6.flowi6_mark = skb->mark;
@@ -321,8 +321,8 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
+
err = ip6_tnl_xmit2(skb, dev, dsfield, &fl6, encap_limit, &mtu);
if (err != 0) {
- /* XXX: send ICMP error even if DF is not set. */
-@@ -1366,6 +1516,14 @@ ip6_tnl_change(struct ip6_tnl *t, const
+ if (err == -EMSGSIZE)
+@@ -1368,6 +1518,14 @@ ip6_tnl_change(struct ip6_tnl *t, const
t->parms.flowinfo = p->flowinfo;
t->parms.link = p->link;
t->parms.proto = p->proto;
@@ -337,7 +337,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
ip6_tnl_dst_reset(t);
ip6_tnl_link_config(t);
return 0;
-@@ -1404,6 +1562,7 @@ ip6_tnl_parm_from_user(struct __ip6_tnl_
+@@ -1406,6 +1564,7 @@ ip6_tnl_parm_from_user(struct __ip6_tnl_
p->flowinfo = u->flowinfo;
p->link = u->link;
p->proto = u->proto;
@@ -345,7 +345,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
memcpy(p->name, u->name, sizeof(u->name));
}
-@@ -1699,6 +1858,15 @@ static int ip6_tnl_validate(struct nlatt
+@@ -1701,6 +1860,15 @@ static int ip6_tnl_validate(struct nlatt
return 0;
}
@@ -361,7 +361,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
static void ip6_tnl_netlink_parms(struct nlattr *data[],
struct __ip6_tnl_parm *parms)
{
-@@ -1730,6 +1898,46 @@ static void ip6_tnl_netlink_parms(struct
+@@ -1732,6 +1900,46 @@ static void ip6_tnl_netlink_parms(struct
if (data[IFLA_IPTUN_PROTO])
parms->proto = nla_get_u8(data[IFLA_IPTUN_PROTO]);
@@ -408,7 +408,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
}
static int ip6_tnl_newlink(struct net *src_net, struct net_device *dev,
-@@ -1782,6 +1990,12 @@ static void ip6_tnl_dellink(struct net_d
+@@ -1784,6 +1992,12 @@ static void ip6_tnl_dellink(struct net_d
static size_t ip6_tnl_get_size(const struct net_device *dev)
{
@@ -421,7 +421,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
return
/* IFLA_IPTUN_LINK */
nla_total_size(4) +
-@@ -1799,6 +2013,24 @@ static size_t ip6_tnl_get_size(const str
+@@ -1801,6 +2015,24 @@ static size_t ip6_tnl_get_size(const str
nla_total_size(4) +
/* IFLA_IPTUN_PROTO */
nla_total_size(1) +
@@ -446,7 +446,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
0;
}
-@@ -1806,6 +2038,9 @@ static int ip6_tnl_fill_info(struct sk_b
+@@ -1808,6 +2040,9 @@ static int ip6_tnl_fill_info(struct sk_b
{
struct ip6_tnl *tunnel = netdev_priv(dev);
struct __ip6_tnl_parm *parm = &tunnel->parms;
@@ -456,7 +456,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) ||
nla_put_in6_addr(skb, IFLA_IPTUN_LOCAL, &parm->laddr) ||
-@@ -1814,8 +2049,27 @@ static int ip6_tnl_fill_info(struct sk_b
+@@ -1816,8 +2051,27 @@ static int ip6_tnl_fill_info(struct sk_b
nla_put_u8(skb, IFLA_IPTUN_ENCAP_LIMIT, parm->encap_limit) ||
nla_put_be32(skb, IFLA_IPTUN_FLOWINFO, parm->flowinfo) ||
nla_put_u32(skb, IFLA_IPTUN_FLAGS, parm->flags) ||
@@ -485,7 +485,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
return 0;
nla_put_failure:
-@@ -1839,6 +2093,7 @@ static const struct nla_policy ip6_tnl_p
+@@ -1841,6 +2095,7 @@ static const struct nla_policy ip6_tnl_p
[IFLA_IPTUN_FLOWINFO] = { .type = NLA_U32 },
[IFLA_IPTUN_FLAGS] = { .type = NLA_U32 },
[IFLA_IPTUN_PROTO] = { .type = NLA_U8 },
diff --git a/target/linux/generic/patches-4.4/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch b/target/linux/generic/patches-4.4/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch
index be5cf505cc..33c0a0f1b6 100644
--- a/target/linux/generic/patches-4.4/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch
+++ b/target/linux/generic/patches-4.4/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch
@@ -143,7 +143,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
static const struct rt6_info ip6_blk_hole_entry_template = {
.dst = {
.__refcnt = ATOMIC_INIT(1),
-@@ -1883,6 +1900,11 @@ static struct rt6_info *ip6_route_info_c
+@@ -1885,6 +1902,11 @@ static struct rt6_info *ip6_route_info_c
rt->dst.output = ip6_pkt_prohibit_out;
rt->dst.input = ip6_pkt_prohibit;
break;
@@ -155,7 +155,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
case RTN_THROW:
case RTN_UNREACHABLE:
default:
-@@ -2484,6 +2506,17 @@ static int ip6_pkt_prohibit_out(struct n
+@@ -2486,6 +2508,17 @@ static int ip6_pkt_prohibit_out(struct n
return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
}
@@ -173,7 +173,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
/*
* Allocate a dst for local (unicast / anycast) address.
*/
-@@ -2726,7 +2759,8 @@ static int rtm_to_fib6_config(struct sk_
+@@ -2728,7 +2761,8 @@ static int rtm_to_fib6_config(struct sk_
if (rtm->rtm_type == RTN_UNREACHABLE ||
rtm->rtm_type == RTN_BLACKHOLE ||
rtm->rtm_type == RTN_PROHIBIT ||
@@ -183,7 +183,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
cfg->fc_flags |= RTF_REJECT;
if (rtm->rtm_type == RTN_LOCAL)
-@@ -3085,6 +3119,9 @@ static int rt6_fill_node(struct net *net
+@@ -3087,6 +3121,9 @@ static int rt6_fill_node(struct net *net
case -EACCES:
rtm->rtm_type = RTN_PROHIBIT;
break;
@@ -193,7 +193,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
case -EAGAIN:
rtm->rtm_type = RTN_THROW;
break;
-@@ -3358,6 +3395,8 @@ static int ip6_route_dev_notify(struct n
+@@ -3360,6 +3397,8 @@ static int ip6_route_dev_notify(struct n
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
net->ipv6.ip6_prohibit_entry->dst.dev = dev;
net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
@@ -202,7 +202,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
#endif
-@@ -3574,6 +3613,17 @@ static int __net_init ip6_route_net_init
+@@ -3576,6 +3615,17 @@ static int __net_init ip6_route_net_init
net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
ip6_template_metrics, true);
@@ -220,7 +220,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
#endif
net->ipv6.sysctl.flush_delay = 0;
-@@ -3592,6 +3642,8 @@ out:
+@@ -3594,6 +3644,8 @@ out:
return ret;
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
@@ -229,7 +229,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
out_ip6_prohibit_entry:
kfree(net->ipv6.ip6_prohibit_entry);
out_ip6_null_entry:
-@@ -3609,6 +3661,7 @@ static void __net_exit ip6_route_net_exi
+@@ -3611,6 +3663,7 @@ static void __net_exit ip6_route_net_exi
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
kfree(net->ipv6.ip6_prohibit_entry);
kfree(net->ipv6.ip6_blk_hole_entry);
@@ -237,7 +237,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
#endif
dst_entries_destroy(&net->ipv6.ip6_dst_ops);
}
-@@ -3706,6 +3759,9 @@ int __init ip6_route_init(void)
+@@ -3708,6 +3761,9 @@ int __init ip6_route_init(void)
init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
diff --git a/target/linux/generic/patches-4.4/721-phy_packets.patch b/target/linux/generic/patches-4.4/721-phy_packets.patch
index 04bafcdfdc..e232c0f563 100644
--- a/target/linux/generic/patches-4.4/721-phy_packets.patch
+++ b/target/linux/generic/patches-4.4/721-phy_packets.patch
@@ -1,6 +1,6 @@
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
-@@ -1297,6 +1297,7 @@ enum netdev_priv_flags {
+@@ -1298,6 +1298,7 @@ enum netdev_priv_flags {
IFF_NO_QUEUE = 1<<21,
IFF_OPENVSWITCH = 1<<22,
IFF_L3MDEV_SLAVE = 1<<23,
@@ -8,7 +8,7 @@
};
#define IFF_802_1Q_VLAN IFF_802_1Q_VLAN
-@@ -1323,6 +1324,7 @@ enum netdev_priv_flags {
+@@ -1324,6 +1325,7 @@ enum netdev_priv_flags {
#define IFF_NO_QUEUE IFF_NO_QUEUE
#define IFF_OPENVSWITCH IFF_OPENVSWITCH
#define IFF_L3MDEV_SLAVE IFF_L3MDEV_SLAVE
@@ -41,7 +41,7 @@
*/
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
-@@ -2186,6 +2186,10 @@ static inline int pskb_trim(struct sk_bu
+@@ -2210,6 +2210,10 @@ static inline int pskb_trim(struct sk_bu
return (len < skb->len) ? __pskb_trim(skb, len) : 0;
}
@@ -52,7 +52,7 @@
/**
* pskb_trim_unique - remove end from a paged unique (not cloned) buffer
* @skb: buffer to alter
-@@ -2308,16 +2312,6 @@ static inline struct sk_buff *dev_alloc_
+@@ -2314,16 +2318,6 @@ static inline struct sk_buff *dev_alloc_
}
diff --git a/target/linux/generic/patches-4.4/903-debloat_direct_io.patch b/target/linux/generic/patches-4.4/903-debloat_direct_io.patch
index ee85c40b62..460da1dbe0 100644
--- a/target/linux/generic/patches-4.4/903-debloat_direct_io.patch
+++ b/target/linux/generic/patches-4.4/903-debloat_direct_io.patch
@@ -26,7 +26,7 @@
endif
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
-@@ -2681,6 +2681,7 @@ enum {
+@@ -2691,6 +2691,7 @@ enum {
DIO_SKIP_DIO_COUNT = 0x08,
};
@@ -34,7 +34,7 @@
void dio_end_io(struct bio *bio, int error);
ssize_t __blockdev_direct_IO(struct kiocb *iocb, struct inode *inode,
-@@ -2688,6 +2689,18 @@ ssize_t __blockdev_direct_IO(struct kioc
+@@ -2698,6 +2699,18 @@ ssize_t __blockdev_direct_IO(struct kioc
loff_t offset, get_block_t get_block,
dio_iodone_t end_io, dio_submit_t submit_io,
int flags);
diff --git a/target/linux/generic/patches-4.4/997-device_tree_cmdline.patch b/target/linux/generic/patches-4.4/997-device_tree_cmdline.patch
deleted file mode 100644
index 566648fcc5..0000000000
--- a/target/linux/generic/patches-4.4/997-device_tree_cmdline.patch
+++ /dev/null
@@ -1,24 +0,0 @@
---- a/drivers/of/fdt.c
-+++ b/drivers/of/fdt.c
-@@ -956,6 +956,9 @@ int __init early_init_dt_scan_chosen(uns
- p = of_get_flat_dt_prop(node, "bootargs", &l);
- if (p != NULL && l > 0)
- strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE));
-+ p = of_get_flat_dt_prop(node, "bootargs-append", &l);
-+ if (p != NULL && l > 0)
-+ strlcat(data, p, min_t(int, strlen(data) + (int)l, COMMAND_LINE_SIZE));
-
- /*
- * CONFIG_CMDLINE is meant to be a default in case nothing else
---- a/arch/mips/kernel/prom.c
-+++ b/arch/mips/kernel/prom.c
-@@ -51,6 +51,9 @@ void * __init early_init_dt_alloc_memory
-
- void __init __dt_setup_arch(void *bph)
- {
-+ if (boot_command_line[0] == '\0')
-+ strcpy(boot_command_line, arcs_cmdline);
-+
- if (!early_init_dt_scan(bph))
- return;
-
diff --git a/target/linux/ixp4xx/Makefile b/target/linux/ixp4xx/Makefile
index c1874faf00..34c81ffe78 100644
--- a/target/linux/ixp4xx/Makefile
+++ b/target/linux/ixp4xx/Makefile
@@ -13,7 +13,7 @@ FEATURES:=squashfs
MAINTAINER:=Imre Kaloz <kaloz@openwrt.org>
SUBTARGETS=generic harddisk
-KERNEL_PATCHVER:=3.18
+KERNEL_PATCHVER:=4.4
include $(INCLUDE_DIR)/target.mk
diff --git a/target/linux/ixp4xx/config-4.4 b/target/linux/ixp4xx/config-4.4
new file mode 100644
index 0000000000..1929f85b1f
--- /dev/null
+++ b/target/linux/ixp4xx/config-4.4
@@ -0,0 +1,251 @@
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_ARCH_ADI_COYOTE is not set
+CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
+CONFIG_ARCH_HAS_DMA_SET_COHERENT_MASK=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_IXCDP1100=y
+CONFIG_ARCH_IXDP425=y
+CONFIG_ARCH_IXDP4XX=y
+CONFIG_ARCH_IXP4XX=y
+CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
+CONFIG_ARCH_NR_GPIO=0
+# CONFIG_ARCH_PRPMC1100 is not set
+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_BIG_ENDIAN=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_CPU_SUSPEND is not set
+CONFIG_ARM_L1_CACHE_SHIFT=5
+CONFIG_ARM_PATCH_PHYS_VIRT=y
+# CONFIG_ARM_THUMB is not set
+CONFIG_ATAGS=y
+CONFIG_BOUNCE=y
+# CONFIG_CACHE_L2X0 is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_CLKSRC_MMIO=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_CMDLINE="root=/dev/mtdblock2 rootfstype=squashfs,jffs2 noinitrd console=ttyS0,115200"
+CONFIG_CMDLINE_FROM_BOOTLOADER=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_BIG_ENDIAN=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+CONFIG_CPU_ENDIAN_BE32=y
+# CONFIG_CPU_ENDIAN_BE8 is not set
+CONFIG_CPU_IXP43X=y
+CONFIG_CPU_IXP46X=y
+CONFIG_CPU_PABRT_LEGACY=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_USE_DOMAINS=y
+CONFIG_CPU_XSCALE=y
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_LL_INCLUDE="debug/8250.S"
+CONFIG_DEBUG_UART_8250=y
+# CONFIG_DEBUG_UART_8250_FLOW_CONTROL is not set
+CONFIG_DEBUG_UART_8250_SHIFT=2
+# CONFIG_DEBUG_UART_8250_WORD is not set
+CONFIG_DEBUG_UART_PHYS=0xc8000003
+CONFIG_DEBUG_UART_VIRT=0xfef00003
+# CONFIG_DEBUG_USER is not set
+CONFIG_DMABOUNCE=y
+CONFIG_DNOTIFY=y
+CONFIG_EEPROM_AT24=y
+CONFIG_FRAME_POINTER=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_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_GW_I2C_PLD=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_AUDITSYSCALL=y
+# 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_SECCOMP_FILTER=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_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_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_HAVE_IDE=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_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_HWMON=y
+CONFIG_HWMON_VID=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_IXP4XX=y
+CONFIG_HZ_FIXED=0
+CONFIG_HZ_PERIODIC=y
+CONFIG_I2C=y
+CONFIG_I2C_ALGOBIT=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_GPIO=y
+# CONFIG_I2C_IOP3XX is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_IOMMU_HELPER=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_WORK=y
+# CONFIG_IWMMXT is not set
+CONFIG_IXP4XX_ETH=y
+# CONFIG_IXP4XX_INDIRECT_PCI is not set
+CONFIG_IXP4XX_NPE=y
+CONFIG_IXP4XX_QMGR=y
+CONFIG_IXP4XX_WATCHDOG=y
+CONFIG_LEDS_FSG=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_LATCH=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_LZ4_COMPRESS is not set
+# CONFIG_LZ4_DECOMPRESS is not set
+CONFIG_MACH_AP1000=y
+CONFIG_MACH_AP42X=y
+# CONFIG_MACH_ARCOM_VULCAN is not set
+CONFIG_MACH_AVILA=y
+CONFIG_MACH_CAMBRIA=y
+CONFIG_MACH_COMPEXWP18=y
+# CONFIG_MACH_DEVIXP is not set
+CONFIG_MACH_DSMG600=y
+CONFIG_MACH_FSG=y
+CONFIG_MACH_GATEWAY7001=y
+# CONFIG_MACH_GORAMO_MLR is not set
+# CONFIG_MACH_GTWX5715 is not set
+# CONFIG_MACH_IXDP465 is not set
+CONFIG_MACH_IXDPG425=y
+# CONFIG_MACH_KIXRP435 is not set
+CONFIG_MACH_LOFT=y
+CONFIG_MACH_MI424WR=y
+# CONFIG_MACH_MIC256 is not set
+# CONFIG_MACH_MICCPT is not set
+CONFIG_MACH_NAS100D=y
+CONFIG_MACH_NSLU2=y
+CONFIG_MACH_PRONGHORN=y
+CONFIG_MACH_PRONGHORNMETRO=y
+CONFIG_MACH_SIDEWINDER=y
+CONFIG_MACH_TW2662=y
+CONFIG_MACH_TW5334=y
+CONFIG_MACH_USR8200=y
+CONFIG_MACH_WG302V1=y
+CONFIG_MACH_WG302V2=y
+CONFIG_MACH_WRT300NV2=y
+CONFIG_MDIO_BOARDINFO=y
+CONFIG_MIGHT_HAVE_PCI=y
+CONFIG_MODULES_USE_ELF_REL=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+# CONFIG_MTD_CFI_GEOMETRY is not set
+CONFIG_MTD_IXP4XX=y
+CONFIG_MTD_OTP=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEED_KUSER_HELPERS=y
+CONFIG_NEED_MACH_IO_H=y
+CONFIG_NEED_PER_CPU_KM=y
+CONFIG_NET_PTP_CLASSIFY=y
+CONFIG_NET_VENDOR_XSCALE=y
+CONFIG_NO_BOOTMEM=y
+# CONFIG_OF is not set
+CONFIG_OLD_SIGACTION=y
+CONFIG_OLD_SIGSUSPEND3=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PCI=y
+# CONFIG_PCI_DOMAINS_GENERIC is not set
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PGTABLE_LEVELS=2
+CONFIG_PHYLIB=y
+# CONFIG_RCU_EXPEDITE_BOOT is not set
+# CONFIG_RCU_STALL_COMMON is not set
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_DS1672=y
+CONFIG_RTC_DRV_ISL1208=y
+CONFIG_RTC_DRV_PCF8563=y
+CONFIG_RTC_DRV_X1205=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_SCHED_HRTICK=y
+# CONFIG_SCSI_DMA is not set
+CONFIG_SENSORS_AD7418=y
+CONFIG_SENSORS_GSC=y
+CONFIG_SENSORS_MAX6650=y
+CONFIG_SENSORS_W83781D=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SPLIT_PTLOCK_CPUS=999999
+CONFIG_SRCU=y
+CONFIG_SWIOTLB=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_UID16=y
+CONFIG_UNCOMPRESS_INCLUDE="mach/uncompress.h"
+CONFIG_USB_EHCI_BIG_ENDIAN_DESC=y
+CONFIG_USB_EHCI_BIG_ENDIAN_MMIO=y
+CONFIG_USB_SUPPORT=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_BCJ=y
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_ZBOOT_ROM_TEXT=0x0
diff --git a/target/linux/ixp4xx/patches-4.4/001-arm-ixp4xx-set-cohorent_dma_mask-for-ethernet-platfo.patch b/target/linux/ixp4xx/patches-4.4/001-arm-ixp4xx-set-cohorent_dma_mask-for-ethernet-platfo.patch
new file mode 100644
index 0000000000..3ca3eb76a6
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/001-arm-ixp4xx-set-cohorent_dma_mask-for-ethernet-platfo.patch
@@ -0,0 +1,136 @@
+From 7113f56b683c5123df5c20724ac813cee66fa21a Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Mon, 1 Jul 2013 16:49:05 +0200
+Subject: [PATCH 1/2] arm: ixp4xx: set cohorent_dma_mask for ethernet platform
+ devices
+
+ARM requires the cohorent_dma_mask set, so set it for the platform
+devices so that the ethernet driver has access to it.
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ arch/arm/mach-ixp4xx/fsg-setup.c | 2 ++
+ arch/arm/mach-ixp4xx/goramo_mlr.c | 2 ++
+ arch/arm/mach-ixp4xx/ixdp425-setup.c | 3 +++
+ arch/arm/mach-ixp4xx/nas100d-setup.c | 1 +
+ arch/arm/mach-ixp4xx/nslu2-setup.c | 1 +
+ arch/arm/mach-ixp4xx/omixp-setup.c | 3 +++
+ arch/arm/mach-ixp4xx/vulcan-setup.c | 2 ++
+ 7 files changed, 14 insertions(+)
+
+--- a/arch/arm/mach-ixp4xx/fsg-setup.c
++++ b/arch/arm/mach-ixp4xx/fsg-setup.c
+@@ -142,12 +142,14 @@ static struct platform_device fsg_eth[]
+ .id = IXP4XX_ETH_NPEB,
+ .dev = {
+ .platform_data = fsg_plat_eth,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ }, {
+ .name = "ixp4xx_eth",
+ .id = IXP4XX_ETH_NPEC,
+ .dev = {
+ .platform_data = fsg_plat_eth + 1,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ }
+ };
+--- a/arch/arm/mach-ixp4xx/goramo_mlr.c
++++ b/arch/arm/mach-ixp4xx/goramo_mlr.c
+@@ -295,10 +295,12 @@ static struct platform_device device_eth
+ .name = "ixp4xx_eth",
+ .id = IXP4XX_ETH_NPEB,
+ .dev.platform_data = eth_plat,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
+ }, {
+ .name = "ixp4xx_eth",
+ .id = IXP4XX_ETH_NPEC,
+ .dev.platform_data = eth_plat + 1,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
+ }
+ };
+
+--- a/arch/arm/mach-ixp4xx/ixdp425-setup.c
++++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c
+@@ -20,6 +20,7 @@
+ #include <linux/mtd/nand.h>
+ #include <linux/mtd/partitions.h>
+ #include <linux/delay.h>
++#include <linux/dma-mapping.h>
+ #include <linux/gpio.h>
+ #include <asm/types.h>
+ #include <asm/setup.h>
+@@ -196,10 +197,12 @@ static struct platform_device ixdp425_et
+ .name = "ixp4xx_eth",
+ .id = IXP4XX_ETH_NPEB,
+ .dev.platform_data = ixdp425_plat_eth,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
+ }, {
+ .name = "ixp4xx_eth",
+ .id = IXP4XX_ETH_NPEC,
+ .dev.platform_data = ixdp425_plat_eth + 1,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
+ }
+ };
+
+--- a/arch/arm/mach-ixp4xx/nas100d-setup.c
++++ b/arch/arm/mach-ixp4xx/nas100d-setup.c
+@@ -170,6 +170,7 @@ static struct platform_device nas100d_et
+ .name = "ixp4xx_eth",
+ .id = IXP4XX_ETH_NPEB,
+ .dev.platform_data = nas100d_plat_eth,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
+ }
+ };
+
+--- a/arch/arm/mach-ixp4xx/nslu2-setup.c
++++ b/arch/arm/mach-ixp4xx/nslu2-setup.c
+@@ -182,6 +182,7 @@ static struct platform_device nslu2_eth[
+ .name = "ixp4xx_eth",
+ .id = IXP4XX_ETH_NPEB,
+ .dev.platform_data = nslu2_plat_eth,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
+ }
+ };
+
+--- a/arch/arm/mach-ixp4xx/omixp-setup.c
++++ b/arch/arm/mach-ixp4xx/omixp-setup.c
+@@ -17,6 +17,7 @@
+ #include <linux/serial_8250.h>
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
++#include <linux/dma-mapping.h>
+ #include <linux/leds.h>
+
+ #include <asm/setup.h>
+@@ -188,10 +189,12 @@ static struct platform_device ixdp425_et
+ .name = "ixp4xx_eth",
+ .id = IXP4XX_ETH_NPEB,
+ .dev.platform_data = ixdp425_plat_eth,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
+ }, {
+ .name = "ixp4xx_eth",
+ .id = IXP4XX_ETH_NPEC,
+ .dev.platform_data = ixdp425_plat_eth + 1,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ };
+
+--- a/arch/arm/mach-ixp4xx/vulcan-setup.c
++++ b/arch/arm/mach-ixp4xx/vulcan-setup.c
+@@ -139,6 +139,7 @@ static struct platform_device vulcan_eth
+ .id = IXP4XX_ETH_NPEB,
+ .dev = {
+ .platform_data = &vulcan_plat_eth[0],
++ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ },
+ [1] = {
+@@ -146,6 +147,7 @@ static struct platform_device vulcan_eth
+ .id = IXP4XX_ETH_NPEC,
+ .dev = {
+ .platform_data = &vulcan_plat_eth[1],
++ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ },
+ };
diff --git a/target/linux/ixp4xx/patches-4.4/002-ixp4xx_eth-use-parent-device-for-dma-allocations.patch b/target/linux/ixp4xx/patches-4.4/002-ixp4xx_eth-use-parent-device-for-dma-allocations.patch
new file mode 100644
index 0000000000..ceaf21b32c
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/002-ixp4xx_eth-use-parent-device-for-dma-allocations.patch
@@ -0,0 +1,95 @@
+From 1d67040af0144c549f4db8144d2ccc253ff8639c Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Mon, 1 Jul 2013 16:39:28 +0200
+Subject: [PATCH 2/2] net: ixp4xx_eth: use parent device for dma allocations
+
+Now that the platfomr device provides a dma_cohorent_mask, use it for
+dma operations.
+
+This fixes ethernet on ixp4xx which was broken since 3.7.
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ drivers/net/ethernet/xscale/ixp4xx_eth.c | 23 ++++++++++++-----------
+ 1 file changed, 12 insertions(+), 11 deletions(-)
+
+--- a/drivers/net/ethernet/xscale/ixp4xx_eth.c
++++ b/drivers/net/ethernet/xscale/ixp4xx_eth.c
+@@ -657,10 +657,10 @@ static inline void queue_put_desc(unsign
+ static inline void dma_unmap_tx(struct port *port, struct desc *desc)
+ {
+ #ifdef __ARMEB__
+- dma_unmap_single(&port->netdev->dev, desc->data,
++ dma_unmap_single(port->netdev->dev.parent, desc->data,
+ desc->buf_len, DMA_TO_DEVICE);
+ #else
+- dma_unmap_single(&port->netdev->dev, desc->data & ~3,
++ dma_unmap_single(port->netdev->dev.parent, desc->data & ~3,
+ ALIGN((desc->data & 3) + desc->buf_len, 4),
+ DMA_TO_DEVICE);
+ #endif
+@@ -727,9 +727,9 @@ static int eth_poll(struct napi_struct *
+
+ #ifdef __ARMEB__
+ if ((skb = netdev_alloc_skb(dev, RX_BUFF_SIZE))) {
+- phys = dma_map_single(&dev->dev, skb->data,
++ phys = dma_map_single(dev->dev.parent, skb->data,
+ RX_BUFF_SIZE, DMA_FROM_DEVICE);
+- if (dma_mapping_error(&dev->dev, phys)) {
++ if (dma_mapping_error(dev->dev.parent, phys)) {
+ dev_kfree_skb(skb);
+ skb = NULL;
+ }
+@@ -752,10 +752,11 @@ static int eth_poll(struct napi_struct *
+ #ifdef __ARMEB__
+ temp = skb;
+ skb = port->rx_buff_tab[n];
+- dma_unmap_single(&dev->dev, desc->data - NET_IP_ALIGN,
++ dma_unmap_single(dev->dev.parent, desc->data - NET_IP_ALIGN,
+ RX_BUFF_SIZE, DMA_FROM_DEVICE);
+ #else
+- dma_sync_single_for_cpu(&dev->dev, desc->data - NET_IP_ALIGN,
++ dma_sync_single_for_cpu(dev->dev.parent,
++ desc->data - NET_IP_ALIGN,
+ RX_BUFF_SIZE, DMA_FROM_DEVICE);
+ memcpy_swab32((u32 *)skb->data, (u32 *)port->rx_buff_tab[n],
+ ALIGN(NET_IP_ALIGN + desc->pkt_len, 4) / 4);
+@@ -874,7 +875,7 @@ static int eth_xmit(struct sk_buff *skb,
+ memcpy_swab32(mem, (u32 *)((int)skb->data & ~3), bytes / 4);
+ #endif
+
+- phys = dma_map_single(&dev->dev, mem, bytes, DMA_TO_DEVICE);
++ phys = dma_map_single(dev->dev.parent, mem, bytes, DMA_TO_DEVICE);
+ if (dma_mapping_error(&dev->dev, phys)) {
+ dev_kfree_skb(skb);
+ #ifndef __ARMEB__
+@@ -1124,7 +1125,7 @@ static int init_queues(struct port *port
+ int i;
+
+ if (!ports_open) {
+- dma_pool = dma_pool_create(DRV_NAME, &port->netdev->dev,
++ dma_pool = dma_pool_create(DRV_NAME, port->netdev->dev.parent,
+ POOL_ALLOC_SIZE, 32, 0);
+ if (!dma_pool)
+ return -ENOMEM;
+@@ -1152,9 +1153,9 @@ static int init_queues(struct port *port
+ data = buff;
+ #endif
+ desc->buf_len = MAX_MRU;
+- desc->data = dma_map_single(&port->netdev->dev, data,
++ desc->data = dma_map_single(port->netdev->dev.parent, data,
+ RX_BUFF_SIZE, DMA_FROM_DEVICE);
+- if (dma_mapping_error(&port->netdev->dev, desc->data)) {
++ if (dma_mapping_error(port->netdev->dev.parent, desc->data)) {
+ free_buffer(buff);
+ return -EIO;
+ }
+@@ -1174,7 +1175,7 @@ static void destroy_queues(struct port *
+ struct desc *desc = rx_desc_ptr(port, i);
+ buffer_t *buff = port->rx_buff_tab[i];
+ if (buff) {
+- dma_unmap_single(&port->netdev->dev,
++ dma_unmap_single(port->netdev->dev.parent,
+ desc->data - NET_IP_ALIGN,
+ RX_BUFF_SIZE, DMA_FROM_DEVICE);
+ free_buffer(buff);
diff --git a/target/linux/ixp4xx/patches-4.4/020-gateworks_i2c_pld.patch b/target/linux/ixp4xx/patches-4.4/020-gateworks_i2c_pld.patch
new file mode 100644
index 0000000000..b096387961
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/020-gateworks_i2c_pld.patch
@@ -0,0 +1,424 @@
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -696,6 +696,14 @@ config GPIO_SX150X
+ 8 bits: sx1508q
+ 16 bits: sx1509q
+
++config GPIO_GW_I2C_PLD
++ tristate "Gateworks I2C PLD GPIO Expander"
++ depends on I2C
++ help
++ Say yes here to provide access to the Gateworks I2C PLD GPIO
++ Expander. This is used at least on the GW2358-4.
++
++
+ endmenu
+
+ menu "MFD GPIO expanders"
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -40,6 +40,7 @@ obj-$(CONFIG_GPIO_ETRAXFS) += gpio-etrax
+ obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o
+ obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
+ obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o
++obj-$(CONFIG_GPIO_GW_I2C_PLD) += gw_i2c_pld.o
+ obj-$(CONFIG_GPIO_ICH) += gpio-ich.o
+ obj-$(CONFIG_GPIO_IOP) += gpio-iop.o
+ obj-$(CONFIG_GPIO_IT87) += gpio-it87.o
+--- /dev/null
++++ b/drivers/gpio/gw_i2c_pld.c
+@@ -0,0 +1,371 @@
++/*
++ * Gateworks I2C PLD GPIO expander
++ *
++ * Copyright (C) 2009 Gateworks Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/hardirq.h>
++#include <linux/i2c.h>
++#include <linux/i2c/gw_i2c_pld.h>
++#include <linux/module.h>
++#include <linux/export.h>
++#include <asm/gpio.h>
++#include <mach/hardware.h>
++
++static const struct i2c_device_id gw_i2c_pld_id[] = {
++ { "gw_i2c_pld", 8 },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, gw_i2c_pld_id);
++
++/*
++ * The Gateworks I2C PLD chip only expose one read and one
++ * write register. Writing a "one" bit (to match the reset state) lets
++ * that pin be used as an input. It is an open-drain model.
++ */
++
++struct gw_i2c_pld {
++ struct gpio_chip chip;
++ struct i2c_client *client;
++ unsigned out; /* software latch */
++};
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ * The Gateworks I2C PLD chip does not properly send the acknowledge bit
++ * thus we cannot use standard i2c_smbus functions. We have recreated
++ * our own here, but we still use the rt_mutex_lock to lock the i2c_bus
++ * as the device still exists on the I2C bus.
++*/
++
++#define PLD_SCL_GPIO 6
++#define PLD_SDA_GPIO 7
++
++#define SCL_LO() gpio_line_set(PLD_SCL_GPIO, IXP4XX_GPIO_LOW)
++#define SCL_HI() gpio_line_set(PLD_SCL_GPIO, IXP4XX_GPIO_HIGH)
++#define SCL_EN() gpio_line_config(PLD_SCL_GPIO, IXP4XX_GPIO_OUT)
++#define SDA_LO() gpio_line_set(PLD_SDA_GPIO, IXP4XX_GPIO_LOW)
++#define SDA_HI() gpio_line_set(PLD_SDA_GPIO, IXP4XX_GPIO_HIGH)
++#define SDA_EN() gpio_line_config(PLD_SDA_GPIO, IXP4XX_GPIO_OUT)
++#define SDA_DIS() gpio_line_config(PLD_SDA_GPIO, IXP4XX_GPIO_IN)
++#define SDA_IN(x) gpio_line_get(PLD_SDA_GPIO, &x);
++
++static int i2c_pld_write_byte(int address, int byte)
++{
++ int i;
++
++ address = (address << 1) & ~0x1;
++
++ SDA_HI();
++ SDA_EN();
++ SCL_EN();
++ SCL_HI();
++ SDA_LO();
++ SCL_LO();
++
++ for (i = 7; i >= 0; i--)
++ {
++ if (address & (1 << i))
++ SDA_HI();
++ else
++ SDA_LO();
++
++ SCL_HI();
++ SCL_LO();
++ }
++
++ SDA_DIS();
++ SCL_HI();
++ SDA_IN(i);
++ SCL_LO();
++ SDA_EN();
++
++ for (i = 7; i >= 0; i--)
++ {
++ if (byte & (1 << i))
++ SDA_HI();
++ else
++ SDA_LO();
++ SCL_HI();
++ SCL_LO();
++ }
++
++ SDA_DIS();
++ SCL_HI();
++ SDA_IN(i);
++ SCL_LO();
++
++ SDA_HI();
++ SDA_EN();
++
++ SDA_LO();
++ SCL_HI();
++ SDA_HI();
++ SCL_LO();
++ SCL_HI();
++
++ return 0;
++}
++
++static unsigned int i2c_pld_read_byte(int address)
++{
++ int i = 0, byte = 0;
++ int bit;
++
++ address = (address << 1) | 0x1;
++
++ SDA_HI();
++ SDA_EN();
++ SCL_EN();
++ SCL_HI();
++ SDA_LO();
++ SCL_LO();
++
++ for (i = 7; i >= 0; i--)
++ {
++ if (address & (1 << i))
++ SDA_HI();
++ else
++ SDA_LO();
++
++ SCL_HI();
++ SCL_LO();
++ }
++
++ SDA_DIS();
++ SCL_HI();
++ SDA_IN(i);
++ SCL_LO();
++ SDA_EN();
++
++ SDA_DIS();
++ for (i = 7; i >= 0; i--)
++ {
++ SCL_HI();
++ SDA_IN(bit);
++ byte |= bit << i;
++ SCL_LO();
++ }
++
++ SDA_LO();
++ SCL_HI();
++ SDA_HI();
++ SCL_LO();
++ SCL_HI();
++
++ return byte;
++}
++
++
++static int gw_i2c_pld_input8(struct gpio_chip *chip, unsigned offset)
++{
++ int ret;
++ struct gw_i2c_pld *gpio = container_of(chip, struct gw_i2c_pld, chip);
++ struct i2c_adapter *adap = gpio->client->adapter;
++
++ if (in_atomic() || irqs_disabled()) {
++ ret = rt_mutex_trylock(&adap->bus_lock);
++ if (!ret)
++ /* I2C activity is ongoing. */
++ return -EAGAIN;
++ } else {
++ rt_mutex_lock(&adap->bus_lock);
++ }
++
++ gpio->out |= (1 << offset);
++
++ ret = i2c_pld_write_byte(gpio->client->addr, gpio->out);
++
++ rt_mutex_unlock(&adap->bus_lock);
++
++ return ret;
++}
++
++static int gw_i2c_pld_get8(struct gpio_chip *chip, unsigned offset)
++{
++ int ret;
++ s32 value;
++ struct gw_i2c_pld *gpio = container_of(chip, struct gw_i2c_pld, chip);
++ struct i2c_adapter *adap = gpio->client->adapter;
++
++ if (in_atomic() || irqs_disabled()) {
++ ret = rt_mutex_trylock(&adap->bus_lock);
++ if (!ret)
++ /* I2C activity is ongoing. */
++ return -EAGAIN;
++ } else {
++ rt_mutex_lock(&adap->bus_lock);
++ }
++
++ value = i2c_pld_read_byte(gpio->client->addr);
++
++ rt_mutex_unlock(&adap->bus_lock);
++
++ return (value < 0) ? 0 : (value & (1 << offset));
++}
++
++static int gw_i2c_pld_output8(struct gpio_chip *chip, unsigned offset, int value)
++{
++ int ret;
++
++ struct gw_i2c_pld *gpio = container_of(chip, struct gw_i2c_pld, chip);
++ struct i2c_adapter *adap = gpio->client->adapter;
++
++ unsigned bit = 1 << offset;
++
++ if (in_atomic() || irqs_disabled()) {
++ ret = rt_mutex_trylock(&adap->bus_lock);
++ if (!ret)
++ /* I2C activity is ongoing. */
++ return -EAGAIN;
++ } else {
++ rt_mutex_lock(&adap->bus_lock);
++ }
++
++
++ if (value)
++ gpio->out |= bit;
++ else
++ gpio->out &= ~bit;
++
++ ret = i2c_pld_write_byte(gpio->client->addr, gpio->out);
++
++ rt_mutex_unlock(&adap->bus_lock);
++
++ return ret;
++}
++
++static void gw_i2c_pld_set8(struct gpio_chip *chip, unsigned offset, int value)
++{
++ gw_i2c_pld_output8(chip, offset, value);
++}
++
++/*-------------------------------------------------------------------------*/
++
++static int gw_i2c_pld_probe(struct i2c_client *client,
++ const struct i2c_device_id *id)
++{
++ struct gw_i2c_pld_platform_data *pdata;
++ struct gw_i2c_pld *gpio;
++ int status;
++
++ pdata = client->dev.platform_data;
++ if (!pdata)
++ return -ENODEV;
++
++ /* Allocate, initialize, and register this gpio_chip. */
++ gpio = kzalloc(sizeof *gpio, GFP_KERNEL);
++ if (!gpio)
++ return -ENOMEM;
++
++ gpio->chip.base = pdata->gpio_base;
++ gpio->chip.can_sleep = 1;
++ gpio->chip.dev = &client->dev;
++ gpio->chip.owner = THIS_MODULE;
++
++ gpio->chip.ngpio = pdata->nr_gpio;
++ gpio->chip.direction_input = gw_i2c_pld_input8;
++ gpio->chip.get = gw_i2c_pld_get8;
++ gpio->chip.direction_output = gw_i2c_pld_output8;
++ gpio->chip.set = gw_i2c_pld_set8;
++
++ gpio->chip.label = client->name;
++
++ gpio->client = client;
++ i2c_set_clientdata(client, gpio);
++
++ gpio->out = 0xFF;
++
++ status = gpiochip_add(&gpio->chip);
++ if (status < 0)
++ goto fail;
++
++ dev_info(&client->dev, "gpios %d..%d on a %s%s\n",
++ gpio->chip.base,
++ gpio->chip.base + gpio->chip.ngpio - 1,
++ client->name,
++ client->irq ? " (irq ignored)" : "");
++
++ /* Let platform code set up the GPIOs and their users.
++ * Now is the first time anyone could use them.
++ */
++ if (pdata->setup) {
++ status = pdata->setup(client,
++ gpio->chip.base, gpio->chip.ngpio,
++ pdata->context);
++ if (status < 0)
++ dev_warn(&client->dev, "setup --> %d\n", status);
++ }
++
++ return 0;
++
++fail:
++ dev_dbg(&client->dev, "probe error %d for '%s'\n",
++ status, client->name);
++ kfree(gpio);
++ return status;
++}
++
++static int gw_i2c_pld_remove(struct i2c_client *client)
++{
++ struct gw_i2c_pld_platform_data *pdata = client->dev.platform_data;
++ struct gw_i2c_pld *gpio = i2c_get_clientdata(client);
++ int status = 0;
++
++ if (pdata->teardown) {
++ status = pdata->teardown(client,
++ gpio->chip.base, gpio->chip.ngpio,
++ pdata->context);
++ if (status < 0) {
++ dev_err(&client->dev, "%s --> %d\n",
++ "teardown", status);
++ return status;
++ }
++ }
++
++ gpiochip_remove(&gpio->chip);
++ kfree(gpio);
++ return 0;
++}
++
++static struct i2c_driver gw_i2c_pld_driver = {
++ .driver = {
++ .name = "gw_i2c_pld",
++ .owner = THIS_MODULE,
++ },
++ .probe = gw_i2c_pld_probe,
++ .remove = gw_i2c_pld_remove,
++ .id_table = gw_i2c_pld_id,
++};
++
++static int __init gw_i2c_pld_init(void)
++{
++ return i2c_add_driver(&gw_i2c_pld_driver);
++}
++module_init(gw_i2c_pld_init);
++
++static void __exit gw_i2c_pld_exit(void)
++{
++ i2c_del_driver(&gw_i2c_pld_driver);
++}
++module_exit(gw_i2c_pld_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Chris Lang");
+--- /dev/null
++++ b/include/linux/i2c/gw_i2c_pld.h
+@@ -0,0 +1,20 @@
++#ifndef __LINUX_GW_I2C_PLD_H
++#define __LINUX_GW_I2C_PLD_H
++
++/**
++ * The Gateworks I2C PLD Implements an additional 8 bits of GPIO through the PLD
++ */
++
++struct gw_i2c_pld_platform_data {
++ unsigned gpio_base;
++ unsigned nr_gpio;
++ int (*setup)(struct i2c_client *client,
++ int gpio, unsigned ngpio,
++ void *context);
++ int (*teardown)(struct i2c_client *client,
++ int gpio, unsigned ngpio,
++ void *context);
++ void *context;
++};
++
++#endif /* __LINUX_GW_I2C_PLD_H */
diff --git a/target/linux/ixp4xx/patches-4.4/030-gpio_line_config.patch b/target/linux/ixp4xx/patches-4.4/030-gpio_line_config.patch
new file mode 100644
index 0000000000..0e51793273
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/030-gpio_line_config.patch
@@ -0,0 +1,73 @@
+--- a/arch/arm/mach-ixp4xx/common.c
++++ b/arch/arm/mach-ixp4xx/common.c
+@@ -93,22 +93,7 @@ void __init ixp4xx_map_io(void)
+ /*
+ * GPIO-functions
+ */
+-/*
+- * The following converted to the real HW bits the gpio_line_config
+- */
+-/* GPIO pin types */
+-#define IXP4XX_GPIO_OUT 0x1
+-#define IXP4XX_GPIO_IN 0x2
+-
+-/* GPIO signal types */
+-#define IXP4XX_GPIO_LOW 0
+-#define IXP4XX_GPIO_HIGH 1
+-
+-/* GPIO Clocks */
+-#define IXP4XX_GPIO_CLK_0 14
+-#define IXP4XX_GPIO_CLK_1 15
+-
+-static void gpio_line_config(u8 line, u32 direction)
++void gpio_line_config(u8 line, u32 direction)
+ {
+ if (direction == IXP4XX_GPIO_IN)
+ *IXP4XX_GPIO_GPOER |= (1 << line);
+@@ -116,17 +101,17 @@ static void gpio_line_config(u8 line, u3
+ *IXP4XX_GPIO_GPOER &= ~(1 << line);
+ }
+
+-static void gpio_line_get(u8 line, int *value)
++void gpio_line_get(u8 line, int *value)
+ {
+ *value = (*IXP4XX_GPIO_GPINR >> line) & 0x1;
+ }
+
+-static void gpio_line_set(u8 line, int value)
++void gpio_line_set(u8 line, int value)
+ {
+- if (value == IXP4XX_GPIO_HIGH)
+- *IXP4XX_GPIO_GPOUTR |= (1 << line);
+- else if (value == IXP4XX_GPIO_LOW)
++ if (value == IXP4XX_GPIO_LOW)
+ *IXP4XX_GPIO_GPOUTR &= ~(1 << line);
++ else
++ *IXP4XX_GPIO_GPOUTR |= (1 << line);
+ }
+
+ /*************************************************************************
+--- a/arch/arm/mach-ixp4xx/include/mach/platform.h
++++ b/arch/arm/mach-ixp4xx/include/mach/platform.h
+@@ -131,5 +131,21 @@ struct pci_sys_data;
+ extern int ixp4xx_setup(int nr, struct pci_sys_data *sys);
+ extern struct pci_ops ixp4xx_ops;
+
++/* GPIO pin types */
++#define IXP4XX_GPIO_OUT 0x1
++#define IXP4XX_GPIO_IN 0x2
++
++/* GPIO signal types */
++#define IXP4XX_GPIO_LOW 0
++#define IXP4XX_GPIO_HIGH 1
++
++/* GPIO Clocks */
++#define IXP4XX_GPIO_CLK_0 14
++#define IXP4XX_GPIO_CLK_1 15
++
++void gpio_line_config(u8 line, u32 direction);
++void gpio_line_get(u8 line, int *value);
++void gpio_line_set(u8 line, int value);
++
+ #endif // __ASSEMBLY__
+
diff --git a/target/linux/ixp4xx/patches-4.4/090-increase_entropy_pools.patch b/target/linux/ixp4xx/patches-4.4/090-increase_entropy_pools.patch
new file mode 100644
index 0000000000..3eea75b519
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/090-increase_entropy_pools.patch
@@ -0,0 +1,17 @@
+--- a/drivers/char/random.c
++++ b/drivers/char/random.c
+@@ -275,11 +275,11 @@
+ /*
+ * Configuration information
+ */
+-#define INPUT_POOL_SHIFT 12
++#define INPUT_POOL_SHIFT 13
+ #define INPUT_POOL_WORDS (1 << (INPUT_POOL_SHIFT-5))
+-#define OUTPUT_POOL_SHIFT 10
++#define OUTPUT_POOL_SHIFT 11
+ #define OUTPUT_POOL_WORDS (1 << (OUTPUT_POOL_SHIFT-5))
+-#define SEC_XFER_SIZE 512
++#define SEC_XFER_SIZE 1024
+ #define EXTRACT_SIZE 10
+
+ #define DEBUG_RANDOM_BOOT 0
diff --git a/target/linux/ixp4xx/patches-4.4/100-wg302v2_gateway7001_mac_plat_info.patch b/target/linux/ixp4xx/patches-4.4/100-wg302v2_gateway7001_mac_plat_info.patch
new file mode 100644
index 0000000000..317103fdab
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/100-wg302v2_gateway7001_mac_plat_info.patch
@@ -0,0 +1,78 @@
+--- a/arch/arm/mach-ixp4xx/gateway7001-setup.c
++++ b/arch/arm/mach-ixp4xx/gateway7001-setup.c
+@@ -17,6 +17,7 @@
+ #include <linux/serial.h>
+ #include <linux/tty.h>
+ #include <linux/serial_8250.h>
++#include <linux/dma-mapping.h>
+
+ #include <asm/types.h>
+ #include <asm/setup.h>
+@@ -75,9 +76,37 @@ static struct platform_device gateway700
+ .resource = &gateway7001_uart_resource,
+ };
+
++static struct eth_plat_info gateway7001_plat_eth[] = {
++ {
++ .phy = 1,
++ .rxq = 3,
++ .txreadyq = 20,
++ }, {
++ .phy = 2,
++ .rxq = 4,
++ .txreadyq = 21,
++ }
++};
++
++static struct platform_device gateway7001_eth[] = {
++ {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEB,
++ .dev.platform_data = gateway7001_plat_eth,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++ }, {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEC,
++ .dev.platform_data = gateway7001_plat_eth + 1,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++ }
++};
++
+ static struct platform_device *gateway7001_devices[] __initdata = {
+ &gateway7001_flash,
+- &gateway7001_uart
++ &gateway7001_uart,
++ &gateway7001_eth[0],
++ &gateway7001_eth[1],
+ };
+
+ static void __init gateway7001_init(void)
+--- a/arch/arm/mach-ixp4xx/wg302v2-setup.c
++++ b/arch/arm/mach-ixp4xx/wg302v2-setup.c
+@@ -76,9 +76,26 @@ static struct platform_device wg302v2_ua
+ .resource = &wg302v2_uart_resource,
+ };
+
++static struct eth_plat_info wg302v2_plat_eth[] = {
++ {
++ .phy = 8,
++ .rxq = 3,
++ .txreadyq = 20,
++ }
++};
++
++static struct platform_device wg302v2_eth[] = {
++ {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEB,
++ .dev.platform_data = wg302v2_plat_eth,
++ }
++};
++
+ static struct platform_device *wg302v2_devices[] __initdata = {
+ &wg302v2_flash,
+ &wg302v2_uart,
++ &wg302v2_eth[0],
+ };
+
+ static void __init wg302v2_init(void)
diff --git a/target/linux/ixp4xx/patches-4.4/105-wg302v1_support.patch b/target/linux/ixp4xx/patches-4.4/105-wg302v1_support.patch
new file mode 100644
index 0000000000..8793549c64
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/105-wg302v1_support.patch
@@ -0,0 +1,261 @@
+--- a/arch/arm/configs/ixp4xx_defconfig
++++ b/arch/arm/configs/ixp4xx_defconfig
+@@ -13,6 +13,7 @@ CONFIG_MACH_AVILA=y
+ CONFIG_MACH_LOFT=y
+ CONFIG_ARCH_ADI_COYOTE=y
+ CONFIG_MACH_GATEWAY7001=y
++CONFIG_MACH_WG302V1=y
+ CONFIG_MACH_WG302V2=y
+ CONFIG_ARCH_IXDP425=y
+ CONFIG_MACH_IXDPG425=y
+--- a/arch/arm/mach-ixp4xx/Kconfig
++++ b/arch/arm/mach-ixp4xx/Kconfig
+@@ -45,6 +45,14 @@ config MACH_GATEWAY7001
+ 7001 Access Point. For more information on this platform,
+ see http://openwrt.org
+
++config MACH_WG302V1
++ bool "Netgear WG302 v1 / WAG302 v1"
++ select PCI
++ help
++ Say 'Y' here if you want your kernel to support Netgear's
++ WG302 v1 or WAG302 v1 Access Points. For more information
++ on this platform, see http://openwrt.org
++
+ config MACH_WG302V2
+ bool "Netgear WG302 v2 / WAG302 v2"
+ select PCI
+--- a/arch/arm/mach-ixp4xx/Makefile
++++ b/arch/arm/mach-ixp4xx/Makefile
+@@ -15,6 +15,7 @@ obj-pci-$(CONFIG_MACH_NSLU2) += nslu2-p
+ obj-pci-$(CONFIG_MACH_NAS100D) += nas100d-pci.o
+ obj-pci-$(CONFIG_MACH_DSMG600) += dsmg600-pci.o
+ obj-pci-$(CONFIG_MACH_GATEWAY7001) += gateway7001-pci.o
++obj-pci-$(CONFIG_MACH_WG302V1) += wg302v1-pci.o
+ obj-pci-$(CONFIG_MACH_WG302V2) += wg302v2-pci.o
+ obj-pci-$(CONFIG_MACH_FSG) += fsg-pci.o
+ obj-pci-$(CONFIG_MACH_ARCOM_VULCAN) += vulcan-pci.o
+@@ -33,6 +34,7 @@ obj-$(CONFIG_MACH_NSLU2) += nslu2-setup.
+ obj-$(CONFIG_MACH_NAS100D) += nas100d-setup.o
+ obj-$(CONFIG_MACH_DSMG600) += dsmg600-setup.o
+ obj-$(CONFIG_MACH_GATEWAY7001) += gateway7001-setup.o
++obj-$(CONFIG_MACH_WG302V1) += wg302v1-setup.o
+ obj-$(CONFIG_MACH_WG302V2) += wg302v2-setup.o
+ obj-$(CONFIG_MACH_FSG) += fsg-setup.o
+ obj-$(CONFIG_MACH_GORAMO_MLR) += goramo_mlr.o
+--- /dev/null
++++ b/arch/arm/mach-ixp4xx/wg302v1-pci.c
+@@ -0,0 +1,63 @@
++/*
++ * arch/arch/mach-ixp4xx/wg302v1-pci.c
++ *
++ * PCI setup routines for the Netgear WG302 v1 and WAG302 v1
++ *
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * based on coyote-pci.c:
++ * Copyright (C) 2002 Jungo Software Technologies.
++ * Copyright (C) 2003 MontaVista Software, Inc.
++ *
++ * Maintainer: Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/irq.h>
++
++#include <asm/mach-types.h>
++#include <mach/hardware.h>
++
++#include <asm/mach/pci.h>
++
++void __init wg302v1_pci_preinit(void)
++{
++ irq_set_irq_type(IRQ_IXP4XX_GPIO8, IRQ_TYPE_LEVEL_LOW);
++ irq_set_irq_type(IRQ_IXP4XX_GPIO10, IRQ_TYPE_LEVEL_LOW);
++
++ ixp4xx_pci_preinit();
++}
++
++static int __init wg302v1_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
++{
++ if (slot == 1)
++ return IRQ_IXP4XX_GPIO8;
++ else if (slot == 2)
++ return IRQ_IXP4XX_GPIO10;
++ else
++ return -1;
++}
++
++struct hw_pci wg302v1_pci __initdata = {
++ .nr_controllers = 1,
++ .preinit = wg302v1_pci_preinit,
++ .ops = &ixp4xx_ops,
++ .setup = ixp4xx_setup,
++ .map_irq = wg302v1_map_irq,
++};
++
++int __init wg302v1_pci_init(void)
++{
++ if (machine_is_wg302v1())
++ pci_common_init(&wg302v1_pci);
++ return 0;
++}
++
++subsys_initcall(wg302v1_pci_init);
+--- /dev/null
++++ b/arch/arm/mach-ixp4xx/wg302v1-setup.c
+@@ -0,0 +1,147 @@
++/*
++ * arch/arm/mach-ixp4xx/wg302v1-setup.c
++ *
++ * Board setup for the Netgear WG302 v1 and WAG302 v1
++ *
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * based on coyote-setup.c:
++ * Copyright (C) 2003-2005 MontaVista Software, Inc.
++ *
++ * Author: Imre Kaloz <kaloz@openwrt.org>
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/device.h>
++#include <linux/serial.h>
++#include <linux/tty.h>
++#include <linux/serial_8250.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++#include <linux/memory.h>
++#include <linux/dma-mapping.h>
++
++#include <asm/setup.h>
++#include <mach/hardware.h>
++#include <asm/irq.h>
++#include <asm/mach-types.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/flash.h>
++
++static struct flash_platform_data wg302v1_flash_data = {
++ .map_name = "cfi_probe",
++ .width = 2,
++};
++
++static struct resource wg302v1_flash_resource = {
++ .flags = IORESOURCE_MEM,
++};
++
++static struct platform_device wg302v1_flash = {
++ .name = "IXP4XX-Flash",
++ .id = 0,
++ .dev = {
++ .platform_data = &wg302v1_flash_data,
++ },
++ .num_resources = 1,
++ .resource = &wg302v1_flash_resource,
++};
++
++static struct resource wg302v1_uart_resources[] = {
++ {
++ .start = IXP4XX_UART1_BASE_PHYS,
++ .end = IXP4XX_UART1_BASE_PHYS + 0x0fff,
++ .flags = IORESOURCE_MEM,
++ },
++ {
++ .start = IXP4XX_UART2_BASE_PHYS,
++ .end = IXP4XX_UART2_BASE_PHYS + 0x0fff,
++ .flags = IORESOURCE_MEM,
++ }
++};
++
++static struct plat_serial8250_port wg302v1_uart_data[] = {
++ {
++ .mapbase = IXP4XX_UART1_BASE_PHYS,
++ .membase = (char *)IXP4XX_UART1_BASE_VIRT + REG_OFFSET,
++ .irq = IRQ_IXP4XX_UART1,
++ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
++ .iotype = UPIO_MEM,
++ .regshift = 2,
++ .uartclk = IXP4XX_UART_XTAL,
++ },
++ {
++ .mapbase = IXP4XX_UART2_BASE_PHYS,
++ .membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
++ .irq = IRQ_IXP4XX_UART2,
++ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
++ .iotype = UPIO_MEM,
++ .regshift = 2,
++ .uartclk = IXP4XX_UART_XTAL,
++ },
++ { },
++};
++
++static struct platform_device wg302v1_uart = {
++ .name = "serial8250",
++ .id = PLAT8250_DEV_PLATFORM,
++ .dev = {
++ .platform_data = wg302v1_uart_data,
++ },
++ .num_resources = 2,
++ .resource = wg302v1_uart_resources,
++};
++
++static struct eth_plat_info wg302v1_plat_eth[] = {
++ {
++ .phy = 30,
++ .rxq = 3,
++ .txreadyq = 20,
++ }
++};
++
++static struct platform_device wg302v1_eth[] = {
++ {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEB,
++ .dev.platform_data = wg302v1_plat_eth,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++ }
++};
++
++static struct platform_device *wg302v1_devices[] __initdata = {
++ &wg302v1_flash,
++ &wg302v1_uart,
++ &wg302v1_eth[0],
++};
++
++static void __init wg302v1_init(void)
++{
++ ixp4xx_sys_init();
++
++ wg302v1_flash_resource.start = IXP4XX_EXP_BUS_BASE(0);
++ wg302v1_flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + SZ_32M - 1;
++
++ *IXP4XX_EXP_CS0 |= IXP4XX_FLASH_WRITABLE;
++ *IXP4XX_EXP_CS1 = *IXP4XX_EXP_CS0;
++
++ platform_add_devices(wg302v1_devices, ARRAY_SIZE(wg302v1_devices));
++}
++
++#ifdef CONFIG_MACH_WG302V1
++MACHINE_START(WG302V1, "Netgear WG302 v1 / WAG302 v1")
++ /* Maintainer: Imre Kaloz <kaloz@openwrt.org> */
++ .fixup = wg302v1_fixup,
++ .map_io = ixp4xx_map_io,
++ .init_irq = ixp4xx_init_irq,
++ .init_time = ixp4xx_timer_init,
++ .atag_offset = 0x0100,
++ .init_machine = wg302v1_init,
++#if defined(CONFIG_PCI)
++ .dma_zone_size = SZ_64M,
++#endif
++ .restart = ixp4xx_restart,
++MACHINE_END
++#endif
diff --git a/target/linux/ixp4xx/patches-4.4/110-pronghorn_series_support.patch b/target/linux/ixp4xx/patches-4.4/110-pronghorn_series_support.patch
new file mode 100644
index 0000000000..d1fdfcba49
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/110-pronghorn_series_support.patch
@@ -0,0 +1,393 @@
+--- a/arch/arm/configs/ixp4xx_defconfig
++++ b/arch/arm/configs/ixp4xx_defconfig
+@@ -15,6 +15,8 @@ CONFIG_ARCH_ADI_COYOTE=y
+ CONFIG_MACH_GATEWAY7001=y
+ CONFIG_MACH_WG302V1=y
+ CONFIG_MACH_WG302V2=y
++CONFIG_MACH_PRONGHORN=y
++CONFIG_MACH_PRONGHORNMETRO=y
+ CONFIG_ARCH_IXDP425=y
+ CONFIG_MACH_IXDPG425=y
+ CONFIG_MACH_IXDP465=y
+--- a/arch/arm/mach-ixp4xx/Kconfig
++++ b/arch/arm/mach-ixp4xx/Kconfig
+@@ -61,6 +61,22 @@ config MACH_WG302V2
+ WG302 v2 or WAG302 v2 Access Points. For more information
+ on this platform, see http://openwrt.org
+
++config MACH_PRONGHORN
++ bool "ADI Pronghorn series"
++ select PCI
++ help
++ Say 'Y' here if you want your kernel to support the ADI
++ Engineering Pronghorn series. For more
++ information on this platform, see http://www.adiengineering.com
++
++#
++# There're only minimal differences kernel-wise between the Pronghorn and
++# Pronghorn Metro boards - they use different chip selects to drive the
++# CF slot connected to the expansion bus, so we just enable them together.
++#
++config MACH_PRONGHORNMETRO
++ def_bool MACH_PRONGHORN
++
+ config ARCH_IXDP425
+ bool "IXDP425"
+ help
+--- a/arch/arm/mach-ixp4xx/Makefile
++++ b/arch/arm/mach-ixp4xx/Makefile
+@@ -19,6 +19,7 @@ obj-pci-$(CONFIG_MACH_WG302V1) += wg302
+ obj-pci-$(CONFIG_MACH_WG302V2) += wg302v2-pci.o
+ obj-pci-$(CONFIG_MACH_FSG) += fsg-pci.o
+ obj-pci-$(CONFIG_MACH_ARCOM_VULCAN) += vulcan-pci.o
++obj-pci-$(CONFIG_MACH_PRONGHORN) += pronghorn-pci.o
+
+ obj-y += common.o
+
+@@ -39,6 +40,7 @@ obj-$(CONFIG_MACH_WG302V2) += wg302v2-se
+ obj-$(CONFIG_MACH_FSG) += fsg-setup.o
+ obj-$(CONFIG_MACH_GORAMO_MLR) += goramo_mlr.o
+ obj-$(CONFIG_MACH_ARCOM_VULCAN) += vulcan-setup.o
++obj-$(CONFIG_MACH_PRONGHORN) += pronghorn-setup.o
+
+ obj-$(CONFIG_PCI) += $(obj-pci-$(CONFIG_PCI)) common-pci.o
+ obj-$(CONFIG_IXP4XX_QMGR) += ixp4xx_qmgr.o
+--- a/arch/arm/mach-ixp4xx/include/mach/uncompress.h
++++ b/arch/arm/mach-ixp4xx/include/mach/uncompress.h
+@@ -42,7 +42,8 @@ static __inline__ void __arch_decomp_set
+ */
+ if (machine_is_adi_coyote() || machine_is_gtwx5715() ||
+ machine_is_gateway7001() || machine_is_wg302v2() ||
+- machine_is_devixp() || machine_is_miccpt() || machine_is_mic256())
++ machine_is_devixp() || machine_is_miccpt() || machine_is_mic256() ||
++ machine_is_pronghorn() || machine_is_pronghorn_metro())
+ uart_base = (volatile u32*) IXP4XX_UART2_BASE_PHYS;
+ else
+ uart_base = (volatile u32*) IXP4XX_UART1_BASE_PHYS;
+--- /dev/null
++++ b/arch/arm/mach-ixp4xx/pronghorn-pci.c
+@@ -0,0 +1,69 @@
++/*
++ * arch/arch/mach-ixp4xx/pronghorn-pci.c
++ *
++ * PCI setup routines for ADI Engineering Pronghorn series
++ *
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * based on coyote-pci.c:
++ * Copyright (C) 2002 Jungo Software Technologies.
++ * Copyright (C) 2003 MontaVista Softwrae, Inc.
++ *
++ * Maintainer: Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/irq.h>
++
++#include <asm/mach-types.h>
++#include <mach/hardware.h>
++
++#include <asm/mach/pci.h>
++
++void __init pronghorn_pci_preinit(void)
++{
++ irq_set_irq_type(IRQ_IXP4XX_GPIO4, IRQ_TYPE_LEVEL_LOW);
++ irq_set_irq_type(IRQ_IXP4XX_GPIO6, IRQ_TYPE_LEVEL_LOW);
++ irq_set_irq_type(IRQ_IXP4XX_GPIO11, IRQ_TYPE_LEVEL_LOW);
++ irq_set_irq_type(IRQ_IXP4XX_GPIO1, IRQ_TYPE_LEVEL_LOW);
++
++ ixp4xx_pci_preinit();
++}
++
++static int __init pronghorn_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
++{
++ if (slot == 13)
++ return IRQ_IXP4XX_GPIO4;
++ else if (slot == 14)
++ return IRQ_IXP4XX_GPIO6;
++ else if (slot == 15)
++ return IRQ_IXP4XX_GPIO11;
++ else if (slot == 16)
++ return IRQ_IXP4XX_GPIO1;
++ else
++ return -1;
++}
++
++struct hw_pci pronghorn_pci __initdata = {
++ .nr_controllers = 1,
++ .preinit = pronghorn_pci_preinit,
++ .ops = &ixp4xx_ops,
++ .setup = ixp4xx_setup,
++ .map_irq = pronghorn_map_irq,
++};
++
++int __init pronghorn_pci_init(void)
++{
++ if (machine_is_pronghorn() || machine_is_pronghorn_metro())
++ pci_common_init(&pronghorn_pci);
++ return 0;
++}
++
++subsys_initcall(pronghorn_pci_init);
+--- /dev/null
++++ b/arch/arm/mach-ixp4xx/pronghorn-setup.c
+@@ -0,0 +1,252 @@
++/*
++ * arch/arm/mach-ixp4xx/pronghorn-setup.c
++ *
++ * Board setup for the ADI Engineering Pronghorn series
++ *
++ * Copyright (C) 2008 Imre Kaloz <Kaloz@openwrt.org>
++ *
++ * based on coyote-setup.c:
++ * Copyright (C) 2003-2005 MontaVista Software, Inc.
++ *
++ * Author: Imre Kaloz <Kaloz@openwrt.org>
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/device.h>
++#include <linux/serial.h>
++#include <linux/tty.h>
++#include <linux/serial_8250.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++#include <linux/memory.h>
++#include <linux/i2c-gpio.h>
++#include <linux/leds.h>
++#include <linux/dma-mapping.h>
++
++#include <asm/setup.h>
++#include <mach/hardware.h>
++#include <asm/irq.h>
++#include <asm/mach-types.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/flash.h>
++
++static struct flash_platform_data pronghorn_flash_data = {
++ .map_name = "cfi_probe",
++ .width = 2,
++};
++
++static struct resource pronghorn_flash_resource = {
++ .flags = IORESOURCE_MEM,
++};
++
++static struct platform_device pronghorn_flash = {
++ .name = "IXP4XX-Flash",
++ .id = 0,
++ .dev = {
++ .platform_data = &pronghorn_flash_data,
++ },
++ .num_resources = 1,
++ .resource = &pronghorn_flash_resource,
++};
++
++static struct resource pronghorn_uart_resources [] = {
++ {
++ .start = IXP4XX_UART1_BASE_PHYS,
++ .end = IXP4XX_UART1_BASE_PHYS + 0x0fff,
++ .flags = IORESOURCE_MEM
++ },
++ {
++ .start = IXP4XX_UART2_BASE_PHYS,
++ .end = IXP4XX_UART2_BASE_PHYS + 0x0fff,
++ .flags = IORESOURCE_MEM
++ }
++};
++
++static struct plat_serial8250_port pronghorn_uart_data[] = {
++ {
++ .mapbase = IXP4XX_UART1_BASE_PHYS,
++ .membase = (char *)IXP4XX_UART1_BASE_VIRT + REG_OFFSET,
++ .irq = IRQ_IXP4XX_UART1,
++ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
++ .iotype = UPIO_MEM,
++ .regshift = 2,
++ .uartclk = IXP4XX_UART_XTAL,
++ },
++ {
++ .mapbase = IXP4XX_UART2_BASE_PHYS,
++ .membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
++ .irq = IRQ_IXP4XX_UART2,
++ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
++ .iotype = UPIO_MEM,
++ .regshift = 2,
++ .uartclk = IXP4XX_UART_XTAL,
++ },
++ { },
++};
++
++static struct platform_device pronghorn_uart = {
++ .name = "serial8250",
++ .id = PLAT8250_DEV_PLATFORM,
++ .dev = {
++ .platform_data = pronghorn_uart_data,
++ },
++ .num_resources = 2,
++ .resource = pronghorn_uart_resources,
++};
++
++static struct i2c_gpio_platform_data pronghorn_i2c_gpio_data = {
++ .sda_pin = 9,
++ .scl_pin = 10,
++};
++
++static struct platform_device pronghorn_i2c_gpio = {
++ .name = "i2c-gpio",
++ .id = 0,
++ .dev = {
++ .platform_data = &pronghorn_i2c_gpio_data,
++ },
++};
++
++static struct gpio_led pronghorn_led_pin[] = {
++ {
++ .name = "pronghorn:green:status",
++ .gpio = 7,
++ }
++};
++
++static struct gpio_led_platform_data pronghorn_led_data = {
++ .num_leds = 1,
++ .leds = pronghorn_led_pin,
++};
++
++static struct platform_device pronghorn_led = {
++ .name = "leds-gpio",
++ .id = -1,
++ .dev.platform_data = &pronghorn_led_data,
++};
++
++static struct resource pronghorn_pata_resources[] = {
++ {
++ .flags = IORESOURCE_MEM
++ },
++ {
++ .flags = IORESOURCE_MEM,
++ },
++ {
++ .name = "intrq",
++ .start = IRQ_IXP4XX_GPIO0,
++ .end = IRQ_IXP4XX_GPIO0,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct ixp4xx_pata_data pronghorn_pata_data = {
++ .cs0_bits = 0xbfff0043,
++ .cs1_bits = 0xbfff0043,
++};
++
++static struct platform_device pronghorn_pata = {
++ .name = "pata_ixp4xx_cf",
++ .id = 0,
++ .dev.platform_data = &pronghorn_pata_data,
++ .num_resources = ARRAY_SIZE(pronghorn_pata_resources),
++ .resource = pronghorn_pata_resources,
++};
++
++static struct eth_plat_info pronghorn_plat_eth[] = {
++ {
++ .phy = 0,
++ .rxq = 3,
++ .txreadyq = 20,
++ }, {
++ .phy = 1,
++ .rxq = 4,
++ .txreadyq = 21,
++ }
++};
++
++static struct platform_device pronghorn_eth[] = {
++ {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEB,
++ .dev.platform_data = pronghorn_plat_eth,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++ }, {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEC,
++ .dev.platform_data = pronghorn_plat_eth + 1,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++ }
++};
++
++static struct platform_device *pronghorn_devices[] __initdata = {
++ &pronghorn_flash,
++ &pronghorn_uart,
++ &pronghorn_led,
++ &pronghorn_eth[0],
++ &pronghorn_eth[1],
++};
++
++static void __init pronghorn_init(void)
++{
++ ixp4xx_sys_init();
++
++ pronghorn_flash_resource.start = IXP4XX_EXP_BUS_BASE(0);
++ pronghorn_flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + SZ_32M - 1;
++
++ *IXP4XX_EXP_CS0 |= IXP4XX_FLASH_WRITABLE;
++ *IXP4XX_EXP_CS1 = *IXP4XX_EXP_CS0;
++
++ platform_add_devices(pronghorn_devices, ARRAY_SIZE(pronghorn_devices));
++
++ if (machine_is_pronghorn()) {
++ pronghorn_pata_resources[0].start = IXP4XX_EXP_BUS_BASE(2);
++ pronghorn_pata_resources[0].end = IXP4XX_EXP_BUS_END(2);
++
++ pronghorn_pata_resources[1].start = IXP4XX_EXP_BUS_BASE(3);
++ pronghorn_pata_resources[1].end = IXP4XX_EXP_BUS_END(3);
++
++ pronghorn_pata_data.cs0_cfg = IXP4XX_EXP_CS2;
++ pronghorn_pata_data.cs1_cfg = IXP4XX_EXP_CS3;
++ } else {
++ pronghorn_pata_resources[0].start = IXP4XX_EXP_BUS_BASE(3);
++ pronghorn_pata_resources[0].end = IXP4XX_EXP_BUS_END(3);
++
++ pronghorn_pata_resources[1].start = IXP4XX_EXP_BUS_BASE(4);
++ pronghorn_pata_resources[1].end = IXP4XX_EXP_BUS_END(4);
++
++ pronghorn_pata_data.cs0_cfg = IXP4XX_EXP_CS3;
++ pronghorn_pata_data.cs1_cfg = IXP4XX_EXP_CS4;
++
++ platform_device_register(&pronghorn_i2c_gpio);
++ }
++
++ platform_device_register(&pronghorn_pata);
++}
++
++MACHINE_START(PRONGHORN, "ADI Engineering Pronghorn")
++ /* Maintainer: Imre Kaloz <kaloz@openwrt.org> */
++ .map_io = ixp4xx_map_io,
++ .init_irq = ixp4xx_init_irq,
++ .init_time = ixp4xx_timer_init,
++ .atag_offset = 0x0100,
++ .init_machine = pronghorn_init,
++#if defined(CONFIG_PCI)
++ .dma_zone_size = SZ_64M,
++#endif
++ .restart = ixp4xx_restart,
++MACHINE_END
++
++MACHINE_START(PRONGHORNMETRO, "ADI Engineering Pronghorn Metro")
++ /* Maintainer: Imre Kaloz <kaloz@openwrt.org> */
++ .map_io = ixp4xx_map_io,
++ .init_irq = ixp4xx_init_irq,
++ .init_time = ixp4xx_timer_init,
++ .atag_offset = 0x0100,
++ .init_machine = pronghorn_init,
++#if defined(CONFIG_PCI)
++ .dma_zone_size = SZ_64M,
++#endif
++ .restart = ixp4xx_restart,
++MACHINE_END
diff --git a/target/linux/ixp4xx/patches-4.4/111-pronghorn_swap_uarts.patch b/target/linux/ixp4xx/patches-4.4/111-pronghorn_swap_uarts.patch
new file mode 100644
index 0000000000..ed9f7a785d
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/111-pronghorn_swap_uarts.patch
@@ -0,0 +1,44 @@
+--- a/arch/arm/mach-ixp4xx/pronghorn-setup.c
++++ b/arch/arm/mach-ixp4xx/pronghorn-setup.c
+@@ -52,31 +52,31 @@ static struct platform_device pronghorn_
+
+ static struct resource pronghorn_uart_resources [] = {
+ {
+- .start = IXP4XX_UART1_BASE_PHYS,
+- .end = IXP4XX_UART1_BASE_PHYS + 0x0fff,
++ .start = IXP4XX_UART2_BASE_PHYS,
++ .end = IXP4XX_UART2_BASE_PHYS + 0x0fff,
+ .flags = IORESOURCE_MEM
+ },
+ {
+- .start = IXP4XX_UART2_BASE_PHYS,
+- .end = IXP4XX_UART2_BASE_PHYS + 0x0fff,
++ .start = IXP4XX_UART1_BASE_PHYS,
++ .end = IXP4XX_UART1_BASE_PHYS + 0x0fff,
+ .flags = IORESOURCE_MEM
+ }
+ };
+
+ static struct plat_serial8250_port pronghorn_uart_data[] = {
+ {
+- .mapbase = IXP4XX_UART1_BASE_PHYS,
+- .membase = (char *)IXP4XX_UART1_BASE_VIRT + REG_OFFSET,
+- .irq = IRQ_IXP4XX_UART1,
++ .mapbase = IXP4XX_UART2_BASE_PHYS,
++ .membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
++ .irq = IRQ_IXP4XX_UART2,
+ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+ .iotype = UPIO_MEM,
+ .regshift = 2,
+ .uartclk = IXP4XX_UART_XTAL,
+ },
+ {
+- .mapbase = IXP4XX_UART2_BASE_PHYS,
+- .membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
+- .irq = IRQ_IXP4XX_UART2,
++ .mapbase = IXP4XX_UART1_BASE_PHYS,
++ .membase = (char *)IXP4XX_UART1_BASE_VIRT + REG_OFFSET,
++ .irq = IRQ_IXP4XX_UART1,
+ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+ .iotype = UPIO_MEM,
+ .regshift = 2,
diff --git a/target/linux/ixp4xx/patches-4.4/115-sidewinder_support.patch b/target/linux/ixp4xx/patches-4.4/115-sidewinder_support.patch
new file mode 100644
index 0000000000..20adbb5c04
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/115-sidewinder_support.patch
@@ -0,0 +1,286 @@
+From 95dac4a842a3c66f69f949b48f9075e16275f77b Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Sun, 30 Jun 2013 15:48:47 +0200
+Subject: [PATCH 07/36] 115-sidewinder_support.patch
+
+---
+ arch/arm/mach-ixp4xx/Kconfig | 10 +-
+ arch/arm/mach-ixp4xx/Makefile | 2 +
+ arch/arm/mach-ixp4xx/sidewinder-pci.c | 68 ++++++++++++++
+ arch/arm/mach-ixp4xx/sidewinder-setup.c | 151 +++++++++++++++++++++++++++++++
+ 4 files changed, 230 insertions(+), 1 deletion(-)
+ create mode 100644 arch/arm/mach-ixp4xx/sidewinder-pci.c
+ create mode 100644 arch/arm/mach-ixp4xx/sidewinder-setup.c
+
+--- a/arch/arm/mach-ixp4xx/Kconfig
++++ b/arch/arm/mach-ixp4xx/Kconfig
+@@ -77,6 +77,14 @@ config MACH_PRONGHORN
+ config MACH_PRONGHORNMETRO
+ def_bool MACH_PRONGHORN
+
++config MACH_SIDEWINDER
++ bool "ADI Sidewinder"
++ select PCI
++ help
++ Say 'Y' here if you want your kernel to support the ADI
++ Engineering Sidewinder board. For more information on this
++ platform, see http://www.adiengineering.com
++
+ config ARCH_IXDP425
+ bool "IXDP425"
+ help
+@@ -173,7 +181,7 @@ config MACH_ARCOM_VULCAN
+ #
+ config CPU_IXP46X
+ bool
+- depends on MACH_IXDP465
++ depends on MACH_IXDP465 || MACH_SIDEWINDER
+ default y
+
+ config CPU_IXP43X
+--- a/arch/arm/mach-ixp4xx/Makefile
++++ b/arch/arm/mach-ixp4xx/Makefile
+@@ -20,6 +20,7 @@ obj-pci-$(CONFIG_MACH_WG302V2) += wg302
+ obj-pci-$(CONFIG_MACH_FSG) += fsg-pci.o
+ obj-pci-$(CONFIG_MACH_ARCOM_VULCAN) += vulcan-pci.o
+ obj-pci-$(CONFIG_MACH_PRONGHORN) += pronghorn-pci.o
++obj-pci-$(CONFIG_MACH_SIDEWINDER) += sidewinder-pci.o
+
+ obj-y += common.o
+
+@@ -41,6 +42,7 @@ obj-$(CONFIG_MACH_FSG) += fsg-setup.o
+ obj-$(CONFIG_MACH_GORAMO_MLR) += goramo_mlr.o
+ obj-$(CONFIG_MACH_ARCOM_VULCAN) += vulcan-setup.o
+ obj-$(CONFIG_MACH_PRONGHORN) += pronghorn-setup.o
++obj-$(CONFIG_MACH_SIDEWINDER) += sidewinder-setup.o
+
+ obj-$(CONFIG_PCI) += $(obj-pci-$(CONFIG_PCI)) common-pci.o
+ obj-$(CONFIG_IXP4XX_QMGR) += ixp4xx_qmgr.o
+--- /dev/null
++++ b/arch/arm/mach-ixp4xx/sidewinder-pci.c
+@@ -0,0 +1,67 @@
++/*
++ * arch/arch/mach-ixp4xx/pronghornmetro-pci.c
++ *
++ * PCI setup routines for ADI Engineering Sidewinder
++ *
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * based on coyote-pci.c:
++ * Copyright (C) 2002 Jungo Software Technologies.
++ * Copyright (C) 2003 MontaVista Softwrae, Inc.
++ *
++ * Maintainer: Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/irq.h>
++
++#include <asm/mach-types.h>
++#include <mach/hardware.h>
++#include <asm/irq.h>
++
++#include <asm/mach/pci.h>
++
++void __init sidewinder_pci_preinit(void)
++{
++ irq_set_irq_type(IRQ_IXP4XX_GPIO11, IRQ_TYPE_LEVEL_LOW);
++ irq_set_irq_type(IRQ_IXP4XX_GPIO10, IRQ_TYPE_LEVEL_LOW);
++ irq_set_irq_type(IRQ_IXP4XX_GPIO9, IRQ_TYPE_LEVEL_LOW);
++
++ ixp4xx_pci_preinit();
++}
++
++static int __init sidewinder_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
++{
++ if (slot == 1)
++ return IRQ_IXP4XX_GPIO11;
++ else if (slot == 2)
++ return IRQ_IXP4XX_GPIO10;
++ else if (slot == 3)
++ return IRQ_IXP4XX_GPIO9;
++ else
++ return -1;
++}
++
++struct hw_pci sidewinder_pci __initdata = {
++ .nr_controllers = 1,
++ .preinit = sidewinder_pci_preinit,
++ .ops = &ixp4xx_ops,
++ .setup = ixp4xx_setup,
++ .map_irq = sidewinder_map_irq,
++};
++
++int __init sidewinder_pci_init(void)
++{
++ if (machine_is_sidewinder())
++ pci_common_init(&sidewinder_pci);
++ return 0;
++}
++
++subsys_initcall(sidewinder_pci_init);
+--- /dev/null
++++ b/arch/arm/mach-ixp4xx/sidewinder-setup.c
+@@ -0,0 +1,155 @@
++/*
++ * arch/arm/mach-ixp4xx/sidewinder-setup.c
++ *
++ * Board setup for the ADI Engineering Sidewinder
++ *
++ * Copyright (C) 2008 Imre Kaloz <Kaloz@openwrt.org>
++ *
++ * based on coyote-setup.c:
++ * Copyright (C) 2003-2005 MontaVista Software, Inc.
++ *
++ * Author: Imre Kaloz <Kaloz@openwrt.org>
++ */
++
++#include <linux/kernel.h>
++#include <linux/serial.h>
++#include <linux/serial_8250.h>
++#include <linux/dma-mapping.h>
++
++#include <asm/mach-types.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/flash.h>
++
++static struct flash_platform_data sidewinder_flash_data = {
++ .map_name = "cfi_probe",
++ .width = 2,
++};
++
++static struct resource sidewinder_flash_resource = {
++ .flags = IORESOURCE_MEM,
++};
++
++static struct platform_device sidewinder_flash = {
++ .name = "IXP4XX-Flash",
++ .id = 0,
++ .dev = {
++ .platform_data = &sidewinder_flash_data,
++ },
++ .num_resources = 1,
++ .resource = &sidewinder_flash_resource,
++};
++
++static struct resource sidewinder_uart_resources[] = {
++ {
++ .start = IXP4XX_UART1_BASE_PHYS,
++ .end = IXP4XX_UART1_BASE_PHYS + 0x0fff,
++ .flags = IORESOURCE_MEM,
++ },
++ {
++ .start = IXP4XX_UART2_BASE_PHYS,
++ .end = IXP4XX_UART2_BASE_PHYS + 0x0fff,
++ .flags = IORESOURCE_MEM,
++ }
++};
++
++static struct plat_serial8250_port sidewinder_uart_data[] = {
++ {
++ .mapbase = IXP4XX_UART1_BASE_PHYS,
++ .membase = (char *)IXP4XX_UART1_BASE_VIRT + REG_OFFSET,
++ .irq = IRQ_IXP4XX_UART1,
++ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
++ .iotype = UPIO_MEM,
++ .regshift = 2,
++ .uartclk = IXP4XX_UART_XTAL,
++ },
++ {
++ .mapbase = IXP4XX_UART2_BASE_PHYS,
++ .membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
++ .irq = IRQ_IXP4XX_UART2,
++ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
++ .iotype = UPIO_MEM,
++ .regshift = 2,
++ .uartclk = IXP4XX_UART_XTAL,
++ },
++ { },
++};
++
++static struct platform_device sidewinder_uart = {
++ .name = "serial8250",
++ .id = PLAT8250_DEV_PLATFORM,
++ .dev = {
++ .platform_data = sidewinder_uart_data,
++ },
++ .num_resources = ARRAY_SIZE(sidewinder_uart_resources),
++ .resource = sidewinder_uart_resources,
++};
++
++static struct eth_plat_info sidewinder_plat_eth[] = {
++ {
++ .phy = 5,
++ .rxq = 3,
++ .txreadyq = 20,
++ }, {
++ .phy = IXP4XX_ETH_PHY_MAX_ADDR,
++ .phy_mask = 0x1e,
++ .rxq = 4,
++ .txreadyq = 21,
++ }, {
++ .phy = 31,
++ .rxq = 2,
++ .txreadyq = 19,
++ }
++};
++
++static struct platform_device sidewinder_eth[] = {
++ {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEB,
++ .dev.platform_data = sidewinder_plat_eth,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++ }, {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEC,
++ .dev.platform_data = sidewinder_plat_eth + 1,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++ }, {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEA,
++ .dev.platform_data = sidewinder_plat_eth + 2,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++ }
++};
++
++static struct platform_device *sidewinder_devices[] __initdata = {
++ &sidewinder_flash,
++ &sidewinder_uart,
++ &sidewinder_eth[0],
++ &sidewinder_eth[1],
++ &sidewinder_eth[2],
++};
++
++static void __init sidewinder_init(void)
++{
++ ixp4xx_sys_init();
++
++ sidewinder_flash_resource.start = IXP4XX_EXP_BUS_BASE(0);
++ sidewinder_flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + SZ_64M - 1;
++
++ *IXP4XX_EXP_CS0 |= IXP4XX_FLASH_WRITABLE;
++ *IXP4XX_EXP_CS1 = *IXP4XX_EXP_CS0;
++
++ platform_add_devices(sidewinder_devices, ARRAY_SIZE(sidewinder_devices));
++}
++
++MACHINE_START(SIDEWINDER, "ADI Engineering Sidewinder")
++ /* Maintainer: Imre Kaloz <kaloz@openwrt.org> */
++ .map_io = ixp4xx_map_io,
++ .init_irq = ixp4xx_init_irq,
++ .init_time = ixp4xx_timer_init,
++ .atag_offset = 0x0100,
++ .init_machine = sidewinder_init,
++#if defined(CONFIG_PCI)
++ .dma_zone_size = SZ_64M,
++#endif
++ .restart = ixp4xx_restart,
++MACHINE_END
diff --git a/target/linux/ixp4xx/patches-4.4/116-sidewinder_fis_location.patch b/target/linux/ixp4xx/patches-4.4/116-sidewinder_fis_location.patch
new file mode 100644
index 0000000000..7d633f7135
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/116-sidewinder_fis_location.patch
@@ -0,0 +1,30 @@
+--- a/drivers/mtd/redboot.c
++++ b/drivers/mtd/redboot.c
+@@ -30,6 +30,8 @@
+ #include <linux/mtd/partitions.h>
+ #include <linux/module.h>
+
++#include <asm/mach-types.h>
++
+ struct fis_image_desc {
+ unsigned char name[16]; // Null terminated name
+ uint32_t flash_base; // Address within FLASH of image
+@@ -47,7 +49,8 @@ struct fis_list {
+ struct fis_list *next;
+ };
+
+-static int directory = CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK;
++int directory = CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK;
++
+ module_param(directory, int, 0);
+
+ static inline int redboot_checksum(struct fis_image_desc *img)
+@@ -75,6 +78,8 @@ static int parse_redboot_partitions(stru
+ #ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
+ static char nullstring[] = "unallocated";
+ #endif
++ if (machine_is_sidewinder())
++ directory = -5;
+
+ if ( directory < 0 ) {
+ offset = master->size + directory * master->erasesize;
diff --git a/target/linux/ixp4xx/patches-4.4/120-compex_support.patch b/target/linux/ixp4xx/patches-4.4/120-compex_support.patch
new file mode 100644
index 0000000000..2abc159f04
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/120-compex_support.patch
@@ -0,0 +1,199 @@
+From 24025a2dcf1248079dd3019fac6ed955252d277f Mon Sep 17 00:00:00 2001
+From: Imre Kaloz <kaloz@openwrt.org>
+Date: Mon, 14 Jul 2008 21:56:34 +0200
+Subject: [PATCH] Add support for the Compex WP18 / NP18A boards
+
+Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
+---
+
+--- a/arch/arm/mach-ixp4xx/Kconfig
++++ b/arch/arm/mach-ixp4xx/Kconfig
+@@ -85,6 +85,14 @@ config MACH_SIDEWINDER
+ Engineering Sidewinder board. For more information on this
+ platform, see http://www.adiengineering.com
+
++config MACH_COMPEXWP18
++ bool "Compex WP18 / NP18A"
++ select PCI
++ help
++ Say 'Y' here if you want your kernel to support Compex'
++ WP18 or NP18A boards. For more information on this
++ platform, see http://www.compex.com.sg/home/OEM/product_ap.htm
++
+ config ARCH_IXDP425
+ bool "IXDP425"
+ help
+--- a/arch/arm/mach-ixp4xx/Makefile
++++ b/arch/arm/mach-ixp4xx/Makefile
+@@ -21,6 +21,7 @@ obj-pci-$(CONFIG_MACH_FSG) += fsg-pci.o
+ obj-pci-$(CONFIG_MACH_ARCOM_VULCAN) += vulcan-pci.o
+ obj-pci-$(CONFIG_MACH_PRONGHORN) += pronghorn-pci.o
+ obj-pci-$(CONFIG_MACH_SIDEWINDER) += sidewinder-pci.o
++obj-pci-$(CONFIG_MACH_COMPEXWP18) += ixdp425-pci.o
+
+ obj-y += common.o
+
+@@ -43,6 +44,7 @@ obj-$(CONFIG_MACH_GORAMO_MLR) += goramo_
+ obj-$(CONFIG_MACH_ARCOM_VULCAN) += vulcan-setup.o
+ obj-$(CONFIG_MACH_PRONGHORN) += pronghorn-setup.o
+ obj-$(CONFIG_MACH_SIDEWINDER) += sidewinder-setup.o
++obj-$(CONFIG_MACH_COMPEXWP18) += compex42x-setup.o
+
+ obj-$(CONFIG_PCI) += $(obj-pci-$(CONFIG_PCI)) common-pci.o
+ obj-$(CONFIG_IXP4XX_QMGR) += ixp4xx_qmgr.o
+--- /dev/null
++++ b/arch/arm/mach-ixp4xx/compex42x-setup.c
+@@ -0,0 +1,141 @@
++/*
++ * arch/arm/mach-ixp4xx/compex-setup.c
++ *
++ * Compex WP18 / NP18A board-setup
++ *
++ * Copyright (C) 2008 Imre Kaloz <Kaloz@openwrt.org>
++ *
++ * based on coyote-setup.c:
++ * Copyright (C) 2003-2005 MontaVista Software, Inc.
++ *
++ * Author: Imre Kaloz <Kaloz@openwrt.org>
++ */
++
++#include <linux/kernel.h>
++#include <linux/serial.h>
++#include <linux/serial_8250.h>
++#include <linux/dma-mapping.h>
++
++#include <asm/mach-types.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/flash.h>
++
++static struct flash_platform_data compex42x_flash_data = {
++ .map_name = "cfi_probe",
++ .width = 2,
++};
++
++static struct resource compex42x_flash_resource = {
++ .flags = IORESOURCE_MEM,
++};
++
++static struct platform_device compex42x_flash = {
++ .name = "IXP4XX-Flash",
++ .id = 0,
++ .dev = {
++ .platform_data = &compex42x_flash_data,
++ },
++ .num_resources = 1,
++ .resource = &compex42x_flash_resource,
++};
++
++static struct resource compex42x_uart_resources[] = {
++ {
++ .start = IXP4XX_UART1_BASE_PHYS,
++ .end = IXP4XX_UART1_BASE_PHYS + 0x0fff,
++ .flags = IORESOURCE_MEM
++ },
++ {
++ .start = IXP4XX_UART2_BASE_PHYS,
++ .end = IXP4XX_UART2_BASE_PHYS + 0x0fff,
++ .flags = IORESOURCE_MEM
++ }
++};
++
++static struct plat_serial8250_port compex42x_uart_data[] = {
++ {
++ .mapbase = IXP4XX_UART1_BASE_PHYS,
++ .membase = (char *)IXP4XX_UART1_BASE_VIRT + REG_OFFSET,
++ .irq = IRQ_IXP4XX_UART1,
++ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
++ .iotype = UPIO_MEM,
++ .regshift = 2,
++ .uartclk = IXP4XX_UART_XTAL,
++ },
++ {
++ .mapbase = IXP4XX_UART2_BASE_PHYS,
++ .membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
++ .irq = IRQ_IXP4XX_UART2,
++ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
++ .iotype = UPIO_MEM,
++ .regshift = 2,
++ .uartclk = IXP4XX_UART_XTAL,
++ },
++ { },
++};
++
++static struct platform_device compex42x_uart = {
++ .name = "serial8250",
++ .id = PLAT8250_DEV_PLATFORM,
++ .dev.platform_data = compex42x_uart_data,
++ .num_resources = 2,
++ .resource = compex42x_uart_resources,
++};
++
++static struct eth_plat_info compex42x_plat_eth[] = {
++ {
++ .phy = IXP4XX_ETH_PHY_MAX_ADDR,
++ .phy_mask = 0xf0000,
++ .rxq = 3,
++ .txreadyq = 20,
++ }, {
++ .phy = 3,
++ .rxq = 4,
++ .txreadyq = 21,
++ }
++};
++
++static struct platform_device compex42x_eth[] = {
++ {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEB,
++ .dev.platform_data = compex42x_plat_eth,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++ }, {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEC,
++ .dev.platform_data = compex42x_plat_eth + 1,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++ }
++};
++
++static struct platform_device *compex42x_devices[] __initdata = {
++ &compex42x_flash,
++ &compex42x_uart,
++ &compex42x_eth[0],
++ &compex42x_eth[1],
++};
++
++static void __init compex42x_init(void)
++{
++ ixp4xx_sys_init();
++
++ compex42x_flash_resource.start = IXP4XX_EXP_BUS_BASE(0);
++ compex42x_flash_resource.end =
++ IXP4XX_EXP_BUS_BASE(0) + SZ_32M - 1;
++
++ platform_add_devices(compex42x_devices, ARRAY_SIZE(compex42x_devices));
++}
++
++MACHINE_START(COMPEXWP18, "Compex WP18 / NP18A")
++ /* Maintainer: Imre Kaloz <Kaloz@openwrt.org> */
++ .map_io = ixp4xx_map_io,
++ .init_irq = ixp4xx_init_irq,
++ .init_time = ixp4xx_timer_init,
++ .atag_offset = 0x0100,
++ .init_machine = compex42x_init,
++#if defined(CONFIG_PCI)
++ .dma_zone_size = SZ_64M,
++#endif
++ .restart = ixp4xx_restart,
++MACHINE_END
+--- a/arch/arm/mach-ixp4xx/ixdp425-pci.c
++++ b/arch/arm/mach-ixp4xx/ixdp425-pci.c
+@@ -69,7 +69,8 @@ struct hw_pci ixdp425_pci __initdata = {
+ int __init ixdp425_pci_init(void)
+ {
+ if (machine_is_ixdp425() || machine_is_ixcdp1100() ||
+- machine_is_ixdp465() || machine_is_kixrp435())
++ machine_is_ixdp465() || machine_is_kixrp435() ||
++ machine_is_compex42x())
+ pci_common_init(&ixdp425_pci);
+ return 0;
+ }
diff --git a/target/linux/ixp4xx/patches-4.4/130-wrt300nv2_support.patch b/target/linux/ixp4xx/patches-4.4/130-wrt300nv2_support.patch
new file mode 100644
index 0000000000..49359be447
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/130-wrt300nv2_support.patch
@@ -0,0 +1,227 @@
+--- a/arch/arm/mach-ixp4xx/Kconfig
++++ b/arch/arm/mach-ixp4xx/Kconfig
+@@ -93,6 +93,14 @@ config MACH_COMPEXWP18
+ WP18 or NP18A boards. For more information on this
+ platform, see http://www.compex.com.sg/home/OEM/product_ap.htm
+
++config MACH_WRT300NV2
++ bool "Linksys WRT300N v2"
++ select PCI
++ help
++ Say 'Y' here if you want your kernel to support Linksys'
++ WRT300N v2 router. For more information on this
++ platform, see http://openwrt.org
++
+ config ARCH_IXDP425
+ bool "IXDP425"
+ help
+--- a/arch/arm/mach-ixp4xx/Makefile
++++ b/arch/arm/mach-ixp4xx/Makefile
+@@ -22,6 +22,7 @@ obj-pci-$(CONFIG_MACH_ARCOM_VULCAN) += v
+ obj-pci-$(CONFIG_MACH_PRONGHORN) += pronghorn-pci.o
+ obj-pci-$(CONFIG_MACH_SIDEWINDER) += sidewinder-pci.o
+ obj-pci-$(CONFIG_MACH_COMPEXWP18) += ixdp425-pci.o
++obj-pci-$(CONFIG_MACH_WRT300NV2) += wrt300nv2-pci.o
+
+ obj-y += common.o
+
+@@ -45,6 +46,7 @@ obj-$(CONFIG_MACH_ARCOM_VULCAN) += vulca
+ obj-$(CONFIG_MACH_PRONGHORN) += pronghorn-setup.o
+ obj-$(CONFIG_MACH_SIDEWINDER) += sidewinder-setup.o
+ obj-$(CONFIG_MACH_COMPEXWP18) += compex42x-setup.o
++obj-$(CONFIG_MACH_WRT300NV2) += wrt300nv2-setup.o
+
+ obj-$(CONFIG_PCI) += $(obj-pci-$(CONFIG_PCI)) common-pci.o
+ obj-$(CONFIG_IXP4XX_QMGR) += ixp4xx_qmgr.o
+--- a/arch/arm/mach-ixp4xx/include/mach/uncompress.h
++++ b/arch/arm/mach-ixp4xx/include/mach/uncompress.h
+@@ -43,7 +43,8 @@ static __inline__ void __arch_decomp_set
+ if (machine_is_adi_coyote() || machine_is_gtwx5715() ||
+ machine_is_gateway7001() || machine_is_wg302v2() ||
+ machine_is_devixp() || machine_is_miccpt() || machine_is_mic256() ||
+- machine_is_pronghorn() || machine_is_pronghorn_metro())
++ machine_is_pronghorn() || machine_is_pronghorn_metro() ||
++ machine_is_wrt300nv2())
+ uart_base = (volatile u32*) IXP4XX_UART2_BASE_PHYS;
+ else
+ uart_base = (volatile u32*) IXP4XX_UART1_BASE_PHYS;
+--- /dev/null
++++ b/arch/arm/mach-ixp4xx/wrt300nv2-pci.c
+@@ -0,0 +1,64 @@
++/*
++ * arch/arch/mach-ixp4xx/wrt300nv2-pci.c
++ *
++ * PCI setup routines for Linksys WRT300N v2
++ *
++ * Copyright (C) 2007 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * based on coyote-pci.c:
++ * Copyright (C) 2002 Jungo Software Technologies.
++ * Copyright (C) 2003 MontaVista Softwrae, Inc.
++ *
++ * Maintainer: Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/irq.h>
++
++#include <asm/mach-types.h>
++#include <mach/hardware.h>
++#include <asm/irq.h>
++
++#include <asm/mach/pci.h>
++
++extern void ixp4xx_pci_preinit(void);
++extern int ixp4xx_setup(int nr, struct pci_sys_data *sys);
++extern struct pci_bus *ixp4xx_scan_bus(int nr, struct pci_sys_data *sys);
++
++void __init wrt300nv2_pci_preinit(void)
++{
++ irq_set_irq_type(IRQ_IXP4XX_GPIO8, IRQ_TYPE_LEVEL_LOW);
++
++ ixp4xx_pci_preinit();
++}
++
++static int __init wrt300nv2_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
++{
++ if (slot == 1)
++ return IRQ_IXP4XX_GPIO8;
++ else return -1;
++}
++
++struct hw_pci wrt300nv2_pci __initdata = {
++ .nr_controllers = 1,
++ .preinit = wrt300nv2_pci_preinit,
++ .ops = &ixp4xx_ops,
++ .setup = ixp4xx_setup,
++ .map_irq = wrt300nv2_map_irq,
++};
++
++int __init wrt300nv2_pci_init(void)
++{
++ if (machine_is_wrt300nv2())
++ pci_common_init(&wrt300nv2_pci);
++ return 0;
++}
++
++subsys_initcall(wrt300nv2_pci_init);
+--- /dev/null
++++ b/arch/arm/mach-ixp4xx/wrt300nv2-setup.c
+@@ -0,0 +1,110 @@
++/*
++ * arch/arm/mach-ixp4xx/wrt300nv2-setup.c
++ *
++ * Board setup for the Linksys WRT300N v2
++ *
++ * Copyright (C) 2007 Imre Kaloz <Kaloz@openwrt.org>
++ *
++ * based on coyote-setup.c:
++ * Copyright (C) 2003-2005 MontaVista Software, Inc.
++ *
++ * Author: Imre Kaloz <Kaloz@openwrt.org>
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/device.h>
++#include <linux/serial.h>
++#include <linux/tty.h>
++#include <linux/serial_8250.h>
++#include <linux/slab.h>
++
++#include <asm/types.h>
++#include <asm/setup.h>
++#include <asm/memory.h>
++#include <mach/hardware.h>
++#include <asm/irq.h>
++#include <asm/mach-types.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/flash.h>
++
++static struct flash_platform_data wrt300nv2_flash_data = {
++ .map_name = "cfi_probe",
++ .width = 2,
++};
++
++static struct resource wrt300nv2_flash_resource = {
++ .flags = IORESOURCE_MEM,
++};
++
++static struct platform_device wrt300nv2_flash = {
++ .name = "IXP4XX-Flash",
++ .id = 0,
++ .dev = {
++ .platform_data = &wrt300nv2_flash_data,
++ },
++ .num_resources = 1,
++ .resource = &wrt300nv2_flash_resource,
++};
++
++static struct resource wrt300nv2_uart_resource = {
++ .start = IXP4XX_UART2_BASE_PHYS,
++ .end = IXP4XX_UART2_BASE_PHYS + 0x0fff,
++ .flags = IORESOURCE_MEM,
++};
++
++static struct plat_serial8250_port wrt300nv2_uart_data[] = {
++ {
++ .mapbase = IXP4XX_UART2_BASE_PHYS,
++ .membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
++ .irq = IRQ_IXP4XX_UART2,
++ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
++ .iotype = UPIO_MEM,
++ .regshift = 2,
++ .uartclk = IXP4XX_UART_XTAL,
++ },
++ { },
++};
++
++static struct platform_device wrt300nv2_uart = {
++ .name = "serial8250",
++ .id = PLAT8250_DEV_PLATFORM,
++ .dev = {
++ .platform_data = wrt300nv2_uart_data,
++ },
++ .num_resources = 1,
++ .resource = &wrt300nv2_uart_resource,
++};
++
++static struct platform_device *wrt300nv2_devices[] __initdata = {
++ &wrt300nv2_flash,
++ &wrt300nv2_uart
++};
++
++static void __init wrt300nv2_init(void)
++{
++ ixp4xx_sys_init();
++
++ wrt300nv2_flash_resource.start = IXP4XX_EXP_BUS_BASE(0);
++ wrt300nv2_flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + SZ_32M - 1;
++
++ *IXP4XX_EXP_CS0 |= IXP4XX_FLASH_WRITABLE;
++ *IXP4XX_EXP_CS1 = *IXP4XX_EXP_CS0;
++
++ platform_add_devices(wrt300nv2_devices, ARRAY_SIZE(wrt300nv2_devices));
++}
++
++#ifdef CONFIG_MACH_WRT300NV2
++MACHINE_START(WRT300NV2, "Linksys WRT300N v2")
++ /* Maintainer: Imre Kaloz <kaloz@openwrt.org> */
++ .map_io = ixp4xx_map_io,
++ .init_irq = ixp4xx_init_irq,
++ .init_time = ixp4xx_timer_init,
++ .atag_offset = 0x0100,
++ .init_machine = wrt300nv2_init,
++#if defined(CONFIG_PCI)
++ .dma_zone_size = SZ_64M,
++#endif
++ .restart = ixp4xx_restart,
++MACHINE_END
++#endif
diff --git a/target/linux/ixp4xx/patches-4.4/131-wrt300nv2_mac_plat_info.patch b/target/linux/ixp4xx/patches-4.4/131-wrt300nv2_mac_plat_info.patch
new file mode 100644
index 0000000000..5debbf1072
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/131-wrt300nv2_mac_plat_info.patch
@@ -0,0 +1,42 @@
+--- a/arch/arm/mach-ixp4xx/wrt300nv2-setup.c
++++ b/arch/arm/mach-ixp4xx/wrt300nv2-setup.c
+@@ -76,9 +76,38 @@ static struct platform_device wrt300nv2_
+ .resource = &wrt300nv2_uart_resource,
+ };
+
++/* Built-in 10/100 Ethernet MAC interfaces */
++static struct eth_plat_info wrt300nv2_plat_eth[] = {
++ {
++ .phy = -1,
++ .rxq = 3,
++ .txreadyq = 20,
++ }, {
++ .phy = 1,
++ .rxq = 4,
++ .txreadyq = 21,
++ }
++};
++
++static struct platform_device wrt300nv2_eth[] = {
++ {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEB,
++ .dev.platform_data = wrt300nv2_plat_eth,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++ }, {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEC,
++ .dev.platform_data = wrt300nv2_plat_eth + 1,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++ }
++};
++
+ static struct platform_device *wrt300nv2_devices[] __initdata = {
+ &wrt300nv2_flash,
+- &wrt300nv2_uart
++ &wrt300nv2_uart,
++ &wrt300nv2_eth[0],
++ &wrt300nv2_eth[1],
+ };
+
+ static void __init wrt300nv2_init(void)
diff --git a/target/linux/ixp4xx/patches-4.4/132-wrt300nv2_mac_fix.patch b/target/linux/ixp4xx/patches-4.4/132-wrt300nv2_mac_fix.patch
new file mode 100644
index 0000000000..99db2673d0
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/132-wrt300nv2_mac_fix.patch
@@ -0,0 +1,72 @@
+--- a/arch/arm/mach-ixp4xx/wrt300nv2-setup.c
++++ b/arch/arm/mach-ixp4xx/wrt300nv2-setup.c
+@@ -3,6 +3,7 @@
+ *
+ * Board setup for the Linksys WRT300N v2
+ *
++ * Copyright (C) 2010 Alexandros C. Couloumbis <alex@ozo.com>
+ * Copyright (C) 2007 Imre Kaloz <Kaloz@openwrt.org>
+ *
+ * based on coyote-setup.c:
+@@ -18,6 +19,7 @@
+ #include <linux/tty.h>
+ #include <linux/serial_8250.h>
+ #include <linux/slab.h>
++#include <linux/etherdevice.h>
+
+ #include <asm/types.h>
+ #include <asm/setup.h>
+@@ -79,7 +81,8 @@ static struct platform_device wrt300nv2_
+ /* Built-in 10/100 Ethernet MAC interfaces */
+ static struct eth_plat_info wrt300nv2_plat_eth[] = {
+ {
+- .phy = -1,
++ .phy = IXP4XX_ETH_PHY_MAX_ADDR,
++ .phy_mask = 0x0F0000,
+ .rxq = 3,
+ .txreadyq = 20,
+ }, {
+@@ -112,6 +115,10 @@ static struct platform_device *wrt300nv2
+
+ static void __init wrt300nv2_init(void)
+ {
++ uint8_t __iomem *f;
++ int offset = 0;
++ int i;
++
+ ixp4xx_sys_init();
+
+ wrt300nv2_flash_resource.start = IXP4XX_EXP_BUS_BASE(0);
+@@ -121,6 +128,32 @@ static void __init wrt300nv2_init(void)
+ *IXP4XX_EXP_CS1 = *IXP4XX_EXP_CS0;
+
+ platform_add_devices(wrt300nv2_devices, ARRAY_SIZE(wrt300nv2_devices));
++
++ f = ioremap(IXP4XX_EXP_BUS_BASE(0), 0x60000);
++
++ if (f) {
++ for (i = 0; i < 6; i++) {
++#ifdef __ARMEB__
++ wrt300nv2_plat_eth[0].hwaddr[i] = readb(f + 0x5FFA0 + i);
++ if (i == 5)
++ offset = 1;
++ wrt300nv2_plat_eth[1].hwaddr[i] = (wrt300nv2_plat_eth[0].hwaddr[i] + offset);
++#else
++ wrt300nv2_plat_eth[0].hwaddr[i] = readb(f + 0x5FFA0 + (i^3));
++ if (i == 5)
++ offset = 1;
++ wrt300nv2_plat_eth[1].hwaddr[i] = (wrt300nv2_plat_eth[0].hwaddr[i] + offset);
++#endif
++ }
++ iounmap(f);
++ }
++
++ if (!(is_valid_ether_addr(wrt300nv2_plat_eth[0].hwaddr)))
++ random_ether_addr(wrt300nv2_plat_eth[0].hwaddr);
++ if (!(is_valid_ether_addr(wrt300nv2_plat_eth[1].hwaddr))) {
++ memcpy(wrt300nv2_plat_eth[1].hwaddr, wrt300nv2_plat_eth[0].hwaddr, ETH_ALEN);
++ wrt300nv2_plat_eth[1].hwaddr[5] = (wrt300nv2_plat_eth[0].hwaddr[5] + 1);
++ }
+ }
+
+ #ifdef CONFIG_MACH_WRT300NV2
diff --git a/target/linux/ixp4xx/patches-4.4/150-lanready_ap1000_support.patch b/target/linux/ixp4xx/patches-4.4/150-lanready_ap1000_support.patch
new file mode 100644
index 0000000000..ad09efdc2d
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/150-lanready_ap1000_support.patch
@@ -0,0 +1,203 @@
+--- a/arch/arm/mach-ixp4xx/Kconfig
++++ b/arch/arm/mach-ixp4xx/Kconfig
+@@ -101,6 +101,14 @@ config MACH_WRT300NV2
+ WRT300N v2 router. For more information on this
+ platform, see http://openwrt.org
+
++config MACH_AP1000
++ bool "Lanready AP-1000"
++ select PCI
++ help
++ Say 'Y' here if you want your kernel to support Lanready's
++ AP1000 board. For more information on this
++ platform, see http://openwrt.org
++
+ config ARCH_IXDP425
+ bool "IXDP425"
+ help
+--- a/arch/arm/mach-ixp4xx/Makefile
++++ b/arch/arm/mach-ixp4xx/Makefile
+@@ -23,6 +23,7 @@ obj-pci-$(CONFIG_MACH_PRONGHORN) += pron
+ obj-pci-$(CONFIG_MACH_SIDEWINDER) += sidewinder-pci.o
+ obj-pci-$(CONFIG_MACH_COMPEXWP18) += ixdp425-pci.o
+ obj-pci-$(CONFIG_MACH_WRT300NV2) += wrt300nv2-pci.o
++obj-pci-$(CONFIG_MACH_AP1000) += ixdp425-pci.o
+
+ obj-y += common.o
+
+@@ -47,6 +48,7 @@ obj-$(CONFIG_MACH_PRONGHORN) += pronghor
+ obj-$(CONFIG_MACH_SIDEWINDER) += sidewinder-setup.o
+ obj-$(CONFIG_MACH_COMPEXWP18) += compex42x-setup.o
+ obj-$(CONFIG_MACH_WRT300NV2) += wrt300nv2-setup.o
++obj-$(CONFIG_MACH_AP1000) += ap1000-setup.o
+
+ obj-$(CONFIG_PCI) += $(obj-pci-$(CONFIG_PCI)) common-pci.o
+ obj-$(CONFIG_IXP4XX_QMGR) += ixp4xx_qmgr.o
+--- /dev/null
++++ b/arch/arm/mach-ixp4xx/ap1000-setup.c
+@@ -0,0 +1,154 @@
++/*
++ * arch/arm/mach-ixp4xx/ap1000-setup.c
++ *
++ * Lanready AP-1000
++ *
++ * Copyright (C) 2007 Imre Kaloz <Kaloz@openwrt.org>
++ *
++ * based on ixdp425-setup.c:
++ * Copyright (C) 2003-2005 MontaVista Software, Inc.
++ *
++ * Author: Imre Kaloz <Kaloz@openwrt.org>
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/device.h>
++#include <linux/serial.h>
++#include <linux/tty.h>
++#include <linux/serial_8250.h>
++#include <linux/slab.h>
++#include <linux/dma-mapping.h>
++
++#include <asm/types.h>
++#include <asm/setup.h>
++#include <asm/memory.h>
++#include <mach/hardware.h>
++#include <asm/mach-types.h>
++#include <asm/irq.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/flash.h>
++
++static struct flash_platform_data ap1000_flash_data = {
++ .map_name = "cfi_probe",
++ .width = 2,
++};
++
++static struct resource ap1000_flash_resource = {
++ .flags = IORESOURCE_MEM,
++};
++
++static struct platform_device ap1000_flash = {
++ .name = "IXP4XX-Flash",
++ .id = 0,
++ .dev = {
++ .platform_data = &ap1000_flash_data,
++ },
++ .num_resources = 1,
++ .resource = &ap1000_flash_resource,
++};
++
++static struct resource ap1000_uart_resources[] = {
++ {
++ .start = IXP4XX_UART1_BASE_PHYS,
++ .end = IXP4XX_UART1_BASE_PHYS + 0x0fff,
++ .flags = IORESOURCE_MEM
++ },
++ {
++ .start = IXP4XX_UART2_BASE_PHYS,
++ .end = IXP4XX_UART2_BASE_PHYS + 0x0fff,
++ .flags = IORESOURCE_MEM
++ }
++};
++
++static struct plat_serial8250_port ap1000_uart_data[] = {
++ {
++ .mapbase = IXP4XX_UART1_BASE_PHYS,
++ .membase = (char *)IXP4XX_UART1_BASE_VIRT + REG_OFFSET,
++ .irq = IRQ_IXP4XX_UART1,
++ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
++ .iotype = UPIO_MEM,
++ .regshift = 2,
++ .uartclk = IXP4XX_UART_XTAL,
++ },
++ {
++ .mapbase = IXP4XX_UART2_BASE_PHYS,
++ .membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
++ .irq = IRQ_IXP4XX_UART2,
++ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
++ .iotype = UPIO_MEM,
++ .regshift = 2,
++ .uartclk = IXP4XX_UART_XTAL,
++ },
++ { },
++};
++
++static struct platform_device ap1000_uart = {
++ .name = "serial8250",
++ .id = PLAT8250_DEV_PLATFORM,
++ .dev.platform_data = ap1000_uart_data,
++ .num_resources = 2,
++ .resource = ap1000_uart_resources
++};
++
++static struct platform_device *ap1000_devices[] __initdata = {
++ &ap1000_flash,
++ &ap1000_uart
++};
++
++static char ap1000_mem_fixup[] __initdata = "mem=64M ";
++
++static void __init ap1000_fixup(struct machine_desc *desc,
++ struct tag *tags, char **cmdline, struct meminfo *mi)
++
++{
++ struct tag *t = tags;
++ char *p = *cmdline;
++
++ /* Find the end of the tags table, taking note of any cmdline tag. */
++ for (; t->hdr.size; t = tag_next(t)) {
++ if (t->hdr.tag == ATAG_CMDLINE) {
++ p = t->u.cmdline.cmdline;
++ }
++ }
++
++ /* Overwrite the end of the table with a new cmdline tag. */
++ t->hdr.tag = ATAG_CMDLINE;
++ t->hdr.size = (sizeof (struct tag_header) +
++ strlen(ap1000_mem_fixup) + strlen(p) + 1 + 4) >> 2;
++ strlcpy(t->u.cmdline.cmdline, ap1000_mem_fixup, COMMAND_LINE_SIZE);
++ strlcpy(t->u.cmdline.cmdline + strlen(ap1000_mem_fixup), p,
++ COMMAND_LINE_SIZE - strlen(ap1000_mem_fixup));
++
++ /* Terminate the table. */
++ t = tag_next(t);
++ t->hdr.tag = ATAG_NONE;
++ t->hdr.size = 0;
++}
++
++static void __init ap1000_init(void)
++{
++ ixp4xx_sys_init();
++
++ ap1000_flash_resource.start = IXP4XX_EXP_BUS_BASE(0);
++ ap1000_flash_resource.end =
++ IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1;
++
++ platform_add_devices(ap1000_devices, ARRAY_SIZE(ap1000_devices));
++}
++
++#ifdef CONFIG_MACH_AP1000
++MACHINE_START(AP1000, "Lanready AP-1000")
++ /* Maintainer: Imre Kaloz <Kaloz@openwrt.org> */
++ .fixup = ap1000_fixup,
++ .map_io = ixp4xx_map_io,
++ .init_irq = ixp4xx_init_irq,
++ .init_time = ixp4xx_timer_init,
++ .atag_offset = 0x0100,
++ .init_machine = ap1000_init,
++#if defined(CONFIG_PCI)
++ .dma_zone_size = SZ_64M,
++#endif
++ .restart = ixp4xx_restart,
++MACHINE_END
++#endif
+--- a/arch/arm/mach-ixp4xx/ixdp425-pci.c
++++ b/arch/arm/mach-ixp4xx/ixdp425-pci.c
+@@ -70,7 +70,7 @@ int __init ixdp425_pci_init(void)
+ {
+ if (machine_is_ixdp425() || machine_is_ixcdp1100() ||
+ machine_is_ixdp465() || machine_is_kixrp435() ||
+- machine_is_compex42x())
++ machine_is_compex42x() || machine_is_ap1000())
+ pci_common_init(&ixdp425_pci);
+ return 0;
+ }
diff --git a/target/linux/ixp4xx/patches-4.4/151-lanready_ap1000_mac_plat_info.patch b/target/linux/ixp4xx/patches-4.4/151-lanready_ap1000_mac_plat_info.patch
new file mode 100644
index 0000000000..2079589a71
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/151-lanready_ap1000_mac_plat_info.patch
@@ -0,0 +1,51 @@
+--- a/arch/arm/mach-ixp4xx/ap1000-setup.c
++++ b/arch/arm/mach-ixp4xx/ap1000-setup.c
+@@ -91,15 +91,45 @@ static struct platform_device ap1000_uar
+ .resource = ap1000_uart_resources
+ };
+
++/* Built-in 10/100 Ethernet MAC interfaces */
++static struct eth_plat_info ap1000_plat_eth[] = {
++ {
++ .phy = IXP4XX_ETH_PHY_MAX_ADDR,
++ .phy_mask = 0x1e,
++ .rxq = 3,
++ .txreadyq = 20,
++ }, {
++ .phy = 5,
++ .rxq = 4,
++ .txreadyq = 21,
++ }
++};
++
++static struct platform_device ap1000_eth[] = {
++ {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEB,
++ .dev.platform_data = ap1000_plat_eth,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++ }, {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEC,
++ .dev.platform_data = ap1000_plat_eth + 1,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++ }
++};
++
+ static struct platform_device *ap1000_devices[] __initdata = {
+ &ap1000_flash,
+- &ap1000_uart
++ &ap1000_uart,
++ &ap1000_eth[0],
++ &ap1000_eth[1],
+ };
+
+ static char ap1000_mem_fixup[] __initdata = "mem=64M ";
+
+-static void __init ap1000_fixup(struct machine_desc *desc,
+- struct tag *tags, char **cmdline, struct meminfo *mi)
++static void __init ap1000_fixup(struct tag *tags, char **cmdline,
++ struct meminfo *mi)
+
+ {
+ struct tag *t = tags;
diff --git a/target/linux/ixp4xx/patches-4.4/160-delayed_uart_io.patch b/target/linux/ixp4xx/patches-4.4/160-delayed_uart_io.patch
new file mode 100644
index 0000000000..2bcc801b14
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/160-delayed_uart_io.patch
@@ -0,0 +1,133 @@
+--- a/drivers/tty/serial/8250/8250_core.c
++++ b/drivers/tty/serial/8250/8250_core.c
+@@ -825,6 +825,7 @@ static int serial8250_probe(struct platf
+ uart.port.set_termios = p->set_termios;
+ uart.port.pm = p->pm;
+ uart.port.dev = &dev->dev;
++ uart.port.rw_delay = p->rw_delay;
+ uart.port.irqflags |= irqflag;
+ ret = serial8250_register_8250_port(&uart);
+ if (ret < 0) {
+@@ -981,6 +982,7 @@ int serial8250_register_8250_port(struct
+ uart->bugs = up->bugs;
+ uart->port.mapbase = up->port.mapbase;
+ uart->port.mapsize = up->port.mapsize;
++ uart->port.rw_delay = up->port.rw_delay;
+ uart->port.private_data = up->port.private_data;
+ uart->tx_loadsz = up->tx_loadsz;
+ uart->capabilities = up->capabilities;
+--- a/drivers/tty/serial/serial_core.c
++++ b/drivers/tty/serial/serial_core.c
+@@ -2185,6 +2185,7 @@ uart_report_port(struct uart_driver *drv
+ snprintf(address, sizeof(address),
+ "I/O 0x%lx offset 0x%x", port->iobase, port->hub6);
+ break;
++ case UPIO_MEM_DELAY:
+ case UPIO_MEM:
+ case UPIO_MEM32:
+ case UPIO_MEM32BE:
+@@ -2830,6 +2831,7 @@ int uart_match_port(struct uart_port *po
+ case UPIO_HUB6:
+ return (port1->iobase == port2->iobase) &&
+ (port1->hub6 == port2->hub6);
++ case UPIO_MEM_DELAY:
+ case UPIO_MEM:
+ case UPIO_MEM32:
+ case UPIO_MEM32BE:
+--- a/include/linux/serial_8250.h
++++ b/include/linux/serial_8250.h
+@@ -28,6 +28,7 @@ struct plat_serial8250_port {
+ void *private_data;
+ unsigned char regshift; /* register shift */
+ unsigned char iotype; /* UPIO_* */
++ unsigned int rw_delay; /* udelay for slower busses IXP4XX Expansion Bus */
+ unsigned char hub6;
+ upf_t flags; /* UPF_* flags */
+ unsigned int type; /* If UPF_FIXED_TYPE */
+--- a/include/linux/serial_core.h
++++ b/include/linux/serial_core.h
+@@ -150,6 +150,7 @@ struct uart_port {
+ #define UPIO_AU (SERIAL_IO_AU) /* Au1x00 and RT288x type IO */
+ #define UPIO_TSI (SERIAL_IO_TSI) /* Tsi108/109 type IO */
+ #define UPIO_MEM32BE (SERIAL_IO_MEM32BE) /* 32b big endian */
++#define UPIO_MEM_DELAY (SERIAL_IO_MEM_DELAY)
+
+ unsigned int read_status_mask; /* driver specific */
+ unsigned int ignore_status_mask; /* driver specific */
+@@ -231,6 +232,7 @@ struct uart_port {
+ int hw_stopped; /* sw-assisted CTS flow state */
+ unsigned int mctrl; /* current modem ctrl settings */
+ unsigned int timeout; /* character-based timeout */
++ unsigned int rw_delay; /* udelay for slow busses, IXP4XX Expansion Bus */
+ unsigned int type; /* port type */
+ const struct uart_ops *ops;
+ unsigned int custom_divisor;
+--- a/include/uapi/linux/serial.h
++++ b/include/uapi/linux/serial.h
+@@ -69,6 +69,7 @@ struct serial_struct {
+ #define SERIAL_IO_AU 4
+ #define SERIAL_IO_TSI 5
+ #define SERIAL_IO_MEM32BE 6
++#define SERIAL_IO_MEM_DELAY 7
+
+ #define UART_CLEAR_FIFO 0x01
+ #define UART_USE_FIFO 0x02
+--- a/drivers/tty/serial/8250/8250_port.c
++++ b/drivers/tty/serial/8250/8250_port.c
+@@ -368,6 +368,20 @@ static void mem_serial_out(struct uart_p
+ writeb(value, p->membase + offset);
+ }
+
++static unsigned int memdelay_serial_in(struct uart_port *p, int offset)
++{
++ struct uart_8250_port *up = (struct uart_8250_port *)p;
++ udelay(up->port.rw_delay);
++ return mem_serial_in(p, offset);
++}
++
++static void memdelay_serial_out(struct uart_port *p, int offset, int value)
++{
++ struct uart_8250_port *up = (struct uart_8250_port *)p;
++ udelay(up->port.rw_delay);
++ mem_serial_out(p, offset, value);
++}
++
+ static void mem32_serial_out(struct uart_port *p, int offset, int value)
+ {
+ offset = offset << p->regshift;
+@@ -435,6 +449,11 @@ static void set_io_from_upio(struct uart
+ p->serial_out = mem32be_serial_out;
+ break;
+
++ case UPIO_MEM_DELAY:
++ p->serial_in = memdelay_serial_in;
++ p->serial_out = memdelay_serial_out;
++ break;
++
+ #ifdef CONFIG_SERIAL_8250_RT288X
+ case UPIO_AU:
+ p->serial_in = au_serial_in;
+@@ -461,6 +480,7 @@ serial_port_out_sync(struct uart_port *p
+ case UPIO_MEM:
+ case UPIO_MEM32:
+ case UPIO_MEM32BE:
++ case UPIO_MEM_DELAY:
+ case UPIO_AU:
+ p->serial_out(p, offset, value);
+ p->serial_in(p, UART_LCR); /* safe, no side-effects */
+@@ -2457,6 +2477,7 @@ static int serial8250_request_std_resour
+ case UPIO_MEM32:
+ case UPIO_MEM32BE:
+ case UPIO_MEM:
++ case UPIO_MEM_DELAY:
+ if (!port->mapbase)
+ break;
+
+@@ -2494,6 +2515,7 @@ static void serial8250_release_std_resou
+ case UPIO_MEM32:
+ case UPIO_MEM32BE:
+ case UPIO_MEM:
++ case UPIO_MEM_DELAY:
+ if (!port->mapbase)
+ break;
+
diff --git a/target/linux/ixp4xx/patches-4.4/162-wg302v1_mem_fixup.patch b/target/linux/ixp4xx/patches-4.4/162-wg302v1_mem_fixup.patch
new file mode 100644
index 0000000000..75212bc2e7
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/162-wg302v1_mem_fixup.patch
@@ -0,0 +1,38 @@
+--- a/arch/arm/mach-ixp4xx/wg302v1-setup.c
++++ b/arch/arm/mach-ixp4xx/wg302v1-setup.c
+@@ -117,6 +117,35 @@ static struct platform_device *wg302v1_d
+ &wg302v1_eth[0],
+ };
+
++static char wg302v1_mem_fixup[] __initdata = " mem=32M";
++
++static void __init wg302v1_fixup(struct tag *tags, char **cmdline,
++ struct meminfo *mi)
++{
++ struct tag *t = tags;
++ char *p = *cmdline;
++ size_t fixlen, cmdlen;
++
++ /* Find the end of the tags table, taking note of any cmdline tag. */
++ for (; t->hdr.size; t = tag_next(t)) {
++ if (t->hdr.tag == ATAG_CMDLINE) {
++ p = t->u.cmdline.cmdline;
++ }
++ }
++
++ fixlen = strlen(wg302v1_mem_fixup);
++ cmdlen = strlen(p);
++ if (fixlen + cmdlen >= COMMAND_LINE_SIZE)
++ return;
++
++ /* append the fixup to the cmdline */
++ memmove(p + cmdlen, wg302v1_mem_fixup, fixlen + 1);
++
++ /* Adjust the size of the atag if there was one */
++ if (t->hdr.size)
++ t->hdr.size += fixlen;
++}
++
+ static void __init wg302v1_init(void)
+ {
+ ixp4xx_sys_init();
diff --git a/target/linux/ixp4xx/patches-4.4/170-ixdpg425_mac_plat_info.patch b/target/linux/ixp4xx/patches-4.4/170-ixdpg425_mac_plat_info.patch
new file mode 100644
index 0000000000..f7090cd1b4
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/170-ixdpg425_mac_plat_info.patch
@@ -0,0 +1,51 @@
+--- a/arch/arm/mach-ixp4xx/coyote-setup.c
++++ b/arch/arm/mach-ixp4xx/coyote-setup.c
+@@ -14,6 +14,7 @@
+ #include <linux/serial.h>
+ #include <linux/tty.h>
+ #include <linux/serial_8250.h>
++#include <linux/dma-mapping.h>
+
+ #include <asm/types.h>
+ #include <asm/setup.h>
+@@ -81,9 +82,39 @@ static struct platform_device coyote_uar
+ .resource = &coyote_uart_resource,
+ };
+
++/* Built-in 10/100 Ethernet MAC interfaces */
++static struct eth_plat_info ixdpg425_plat_eth[] = {
++ {
++ .phy = 5,
++ .rxq = 3,
++ .txreadyq = 20,
++ }, {
++ .phy = 4,
++ .rxq = 4,
++ .txreadyq = 21,
++ }
++};
++
++static struct platform_device ixdpg425_eth[] = {
++ {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEB,
++ .dev.platform_data = ixdpg425_plat_eth,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++ }, {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEC,
++ .dev.platform_data = ixdpg425_plat_eth + 1,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++ }
++};
++
++
+ static struct platform_device *coyote_devices[] __initdata = {
+ &coyote_flash,
+- &coyote_uart
++ &coyote_uart,
++ &ixdpg425_eth[0],
++ &ixdpg425_eth[1],
+ };
+
+ static void __init coyote_init(void)
diff --git a/target/linux/ixp4xx/patches-4.4/175-avila_hss_audio_support.patch b/target/linux/ixp4xx/patches-4.4/175-avila_hss_audio_support.patch
new file mode 100644
index 0000000000..72ccc00f30
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/175-avila_hss_audio_support.patch
@@ -0,0 +1,2093 @@
+--- a/sound/soc/Kconfig
++++ b/sound/soc/Kconfig
+@@ -46,6 +46,7 @@ source "sound/soc/cirrus/Kconfig"
+ source "sound/soc/davinci/Kconfig"
+ source "sound/soc/dwc/Kconfig"
+ source "sound/soc/fsl/Kconfig"
++source "sound/soc/gw-avila/Kconfig"
+ source "sound/soc/jz4740/Kconfig"
+ source "sound/soc/nuc900/Kconfig"
+ source "sound/soc/omap/Kconfig"
+--- a/sound/soc/Makefile
++++ b/sound/soc/Makefile
+@@ -26,6 +26,7 @@ obj-$(CONFIG_SND_SOC) += cirrus/
+ obj-$(CONFIG_SND_SOC) += davinci/
+ obj-$(CONFIG_SND_SOC) += dwc/
+ obj-$(CONFIG_SND_SOC) += fsl/
++obj-$(CONFIG_SND_SOC) += gw-avila/
+ obj-$(CONFIG_SND_SOC) += jz4740/
+ obj-$(CONFIG_SND_SOC) += intel/
+ obj-$(CONFIG_SND_SOC) += mediatek/
+--- /dev/null
++++ b/sound/soc/gw-avila/Kconfig
+@@ -0,0 +1,17 @@
++config SND_GW_AVILA_SOC_PCM
++ tristate
++
++config SND_GW_AVILA_SOC_HSS
++ tristate
++
++config SND_GW_AVILA_SOC
++ tristate "SoC Audio for the Gateworks AVILA Family"
++ depends on ARCH_IXP4XX && SND_SOC
++ select SND_GW_AVILA_SOC_PCM
++ select SND_GW_AVILA_SOC_HSS
++ select SND_SOC_TLV320AIC3X
++ help
++ Say Y or M if you want to add support for codecs attached to
++ the Gateworks HSS interface. You will also need
++ to select the audio interfaces to support below.
++
+--- /dev/null
++++ b/sound/soc/gw-avila/Makefile
+@@ -0,0 +1,8 @@
++# Gateworks Avila HSS Platform Support
++snd-soc-gw-avila-objs := gw-avila.o ixp4xx_hss.o
++snd-soc-gw-avila-pcm-objs := gw-avila-pcm.o
++snd-soc-gw-avila-hss-objs := gw-avila-hss.o
++
++obj-$(CONFIG_SND_GW_AVILA_SOC) += snd-soc-gw-avila.o
++obj-$(CONFIG_SND_GW_AVILA_SOC_PCM) += snd-soc-gw-avila-pcm.o
++obj-$(CONFIG_SND_GW_AVILA_SOC_HSS) += snd-soc-gw-avila-hss.o
+--- /dev/null
++++ b/sound/soc/gw-avila/gw-avila-hss.c
+@@ -0,0 +1,103 @@
++/*
++ * gw-avila-hss.c -- HSS Audio Support for Gateworks Avila
++ *
++ * Author: Chris Lang <clang@gateworks.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/interrupt.h>
++#include <linux/wait.h>
++#include <linux/delay.h>
++
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/ac97_codec.h>
++#include <sound/initval.h>
++#include <sound/soc.h>
++
++#include <asm/irq.h>
++#include <linux/mutex.h>
++#include <linux/gpio.h>
++
++#include "ixp4xx_hss.h"
++#include "gw-avila-hss.h"
++
++#define gw_avila_hss_suspend NULL
++#define gw_avila_hss_resume NULL
++
++struct snd_soc_dai_driver gw_avila_hss_dai = {
++ .playback = {
++ .channels_min = 2,
++ .channels_max = 2,
++ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
++ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
++ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
++ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
++ SNDRV_PCM_RATE_KNOT),
++ .formats = SNDRV_PCM_FMTBIT_S16_LE, },
++ .capture = {
++ .channels_min = 2,
++ .channels_max = 2,
++ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
++ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
++ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
++ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
++ SNDRV_PCM_RATE_KNOT),
++ .formats = SNDRV_PCM_FMTBIT_S16_LE, },
++};
++
++static const struct snd_soc_component_driver gw_avila_hss_component = {
++ .name = "gw_avila_hss",
++};
++
++static int gw_avila_hss_probe(struct platform_device *pdev)
++{
++ int port = (pdev->id < 2) ? 0 : 1;
++ int channel = (pdev->id % 2);
++
++ hss_handle[pdev->id] = hss_init(port, channel);
++ if (!hss_handle[pdev->id]) {
++ return -ENODEV;
++ }
++
++ return snd_soc_register_component(&pdev->dev, &gw_avila_hss_component,
++ &gw_avila_hss_dai, 1);
++}
++
++static int gw_avila_hss_remove(struct platform_device *pdev)
++{
++ snd_soc_unregister_component(&pdev->dev);
++
++ return 0;
++}
++
++static struct platform_driver gw_avila_hss_driver = {
++ .probe = gw_avila_hss_probe,
++ .remove = gw_avila_hss_remove,
++ .driver = {
++ .name = "gw_avila_hss",
++ .owner = THIS_MODULE,
++ }
++};
++
++static int __init gw_avila_hss_init(void)
++{
++ return platform_driver_register(&gw_avila_hss_driver);
++}
++module_init(gw_avila_hss_init);
++
++static void __exit gw_avila_hss_exit(void)
++{
++ platform_driver_unregister(&gw_avila_hss_driver);
++}
++module_exit(gw_avila_hss_exit);
++
++MODULE_AUTHOR("Chris Lang");
++MODULE_DESCRIPTION("HSS Audio Driver for Gateworks Avila");
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ b/sound/soc/gw-avila/gw-avila-hss.h
+@@ -0,0 +1,12 @@
++/*
++ * Author: Chris Lang <clang@gateworks.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#ifndef _GW_AVILA_HSS_H
++#define _GW_AVILA_HSS_H
++
++#endif
+--- /dev/null
++++ b/sound/soc/gw-avila/gw-avila-pcm.c
+@@ -0,0 +1,327 @@
++/*
++ * ALSA PCM interface for the TI DAVINCI processor
++ *
++ * Author: Chris Lang, <clang@gateworks.com>
++ * Copyright: (C) 2009 Gateworks Corporation
++ *
++ * Based On: davinci-evm.c, Author: Vladimir Barinov, <vbarinov@ru.mvista.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/dma-mapping.h>
++
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++
++#include <asm/dma.h>
++
++#include "gw-avila-pcm.h"
++#include "gw-avila-hss.h"
++#include "ixp4xx_hss.h"
++
++#define GW_AVILA_PCM_DEBUG 0
++#if GW_AVILA_PCM_DEBUG
++#define DPRINTK(x...) printk(KERN_DEBUG x)
++#else
++#define DPRINTK(x...)
++#endif
++
++static struct snd_pcm_hardware gw_avila_pcm_hardware = {
++ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
++ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
++/* SNDRV_PCM_INFO_PAUSE),*/
++ .formats = (SNDRV_PCM_FMTBIT_S16_LE),
++ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
++ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
++ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
++ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
++ SNDRV_PCM_RATE_KNOT),
++ .rate_min = 8000,
++ .rate_max = 8000,
++ .channels_min = 2,
++ .channels_max = 2,
++ .buffer_bytes_max = 64 * 1024, // All of the lines below may need to be changed
++ .period_bytes_min = 128,
++ .period_bytes_max = 4 * 1024,
++ .periods_min = 16,
++ .periods_max = 32,
++ .fifo_size = 0,
++};
++
++struct gw_avila_runtime_data {
++ spinlock_t lock;
++ int period; /* current DMA period */
++ int master_lch; /* Master DMA channel */
++ int slave_lch; /* Slave DMA channel */
++ struct gw_avila_pcm_dma_params *params; /* DMA params */
++};
++
++static void gw_avila_dma_irq(void *data)
++{
++ struct snd_pcm_substream *substream = data;
++ snd_pcm_period_elapsed(substream);
++}
++
++static int gw_avila_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
++{
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ struct hss_device *hdev = runtime->private_data;
++ int ret = 0;
++
++ switch (cmd) {
++ case SNDRV_PCM_TRIGGER_START:
++ case SNDRV_PCM_TRIGGER_RESUME:
++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
++ hss_tx_start(hdev);
++ else
++ hss_rx_start(hdev);
++ break;
++ case SNDRV_PCM_TRIGGER_STOP:
++ case SNDRV_PCM_TRIGGER_SUSPEND:
++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
++ hss_tx_stop(hdev);
++ else
++ hss_rx_stop(hdev);
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
++ return ret;
++}
++
++static int gw_avila_pcm_prepare(struct snd_pcm_substream *substream)
++{
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ struct hss_device *hdev = runtime->private_data;
++
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
++ hss_set_tx_callback(hdev, gw_avila_dma_irq, substream);
++ hss_config_tx_dma(hdev, runtime->dma_area, runtime->buffer_size, runtime->period_size);
++ } else {
++ hss_set_rx_callback(hdev, gw_avila_dma_irq, substream);
++ hss_config_rx_dma(hdev, runtime->dma_area, runtime->buffer_size, runtime->period_size);
++ }
++
++ return 0;
++}
++
++static snd_pcm_uframes_t
++gw_avila_pcm_pointer(struct snd_pcm_substream *substream)
++{
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ struct hss_device *hdev = runtime->private_data;
++
++ unsigned int curr = 0;
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
++ curr = hss_curr_offset_tx(hdev);
++ else
++ curr = hss_curr_offset_rx(hdev);
++ return curr;
++}
++
++static int gw_avila_pcm_open(struct snd_pcm_substream *substream)
++{
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
++
++ snd_soc_set_runtime_hwparams(substream, &gw_avila_pcm_hardware);
++
++ if (hss_handle[cpu_dai->id] != NULL)
++ runtime->private_data = hss_handle[cpu_dai->id];
++ else {
++ pr_err("hss_handle is NULL\n");
++ return -1;
++ }
++
++ hss_chan_open(hss_handle[cpu_dai->id]);
++
++ return 0;
++}
++
++static int gw_avila_pcm_close(struct snd_pcm_substream *substream)
++{
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ struct hss_device *hdev = runtime->private_data;
++
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
++ memset(hdev->tx_buf, 0, runtime->buffer_size);
++ } else
++ memset(hdev->rx_buf, 0, runtime->buffer_size);
++
++ hss_chan_close(hdev);
++
++ return 0;
++}
++
++static int gw_avila_pcm_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *hw_params)
++{
++ return snd_pcm_lib_malloc_pages(substream,
++ params_buffer_bytes(hw_params));
++}
++
++static int gw_avila_pcm_hw_free(struct snd_pcm_substream *substream)
++{
++ struct snd_pcm_runtime *runtime = substream->runtime;
++
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
++ memset(runtime->dma_area, 0, runtime->buffer_size);
++
++ return snd_pcm_lib_free_pages(substream);
++}
++
++static int gw_avila_pcm_mmap(struct snd_pcm_substream *substream,
++ struct vm_area_struct *vma)
++{
++ struct snd_pcm_runtime *runtime = substream->runtime;
++
++ return dma_mmap_writecombine(substream->pcm->card->dev, vma,
++ runtime->dma_area,
++ runtime->dma_addr,
++ runtime->dma_bytes);
++}
++
++struct snd_pcm_ops gw_avila_pcm_ops = {
++ .open = gw_avila_pcm_open,
++ .close = gw_avila_pcm_close,
++ .ioctl = snd_pcm_lib_ioctl,
++ .hw_params = gw_avila_pcm_hw_params,
++ .hw_free = gw_avila_pcm_hw_free,
++ .prepare = gw_avila_pcm_prepare,
++ .trigger = gw_avila_pcm_trigger,
++ .pointer = gw_avila_pcm_pointer,
++ .mmap = gw_avila_pcm_mmap,
++};
++
++static int gw_avila_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
++{
++ struct snd_pcm_substream *substream = pcm->streams[stream].substream;
++ struct snd_dma_buffer *buf = &substream->dma_buffer;
++ size_t size = gw_avila_pcm_hardware.buffer_bytes_max;
++
++ buf->dev.type = SNDRV_DMA_TYPE_DEV;
++ buf->dev.dev = pcm->card->dev;
++ buf->private_data = NULL;
++
++ buf->area = dma_alloc_coherent(pcm->card->dev, size,
++ &buf->addr, GFP_KERNEL);
++
++ if (!buf->area) {
++ return -ENOMEM;
++ }
++
++ memset(buf->area, 0xff, size);
++
++ DPRINTK("preallocate_dma_buffer: area=%p, addr=%p, size=%d\n",
++ (void *) buf->area, (void *) buf->addr, size);
++
++ buf->bytes = size;
++
++ return 0;
++}
++
++static void gw_avila_pcm_free(struct snd_pcm *pcm)
++{
++ struct snd_pcm_substream *substream;
++ struct snd_dma_buffer *buf;
++ int stream;
++
++ for (stream = 0; stream < 2; stream++) {
++ substream = pcm->streams[stream].substream;
++ if (!substream)
++ continue;
++
++ buf = &substream->dma_buffer;
++ if (!buf->area)
++ continue;
++
++ dma_free_coherent(NULL, buf->bytes, buf->area, 0);
++ buf->area = NULL;
++ }
++}
++
++static u64 gw_avila_pcm_dmamask = 0xFFFFFFFF;
++
++static int gw_avila_pcm_new(struct snd_soc_pcm_runtime *rtd)
++{
++ struct snd_card *card = rtd->card->snd_card;
++ struct snd_pcm *pcm = rtd->pcm;
++ struct snd_soc_dai *dai = rtd->codec_dai;
++ int ret;
++
++ if (!card->dev->dma_mask)
++ card->dev->dma_mask = &gw_avila_pcm_dmamask;
++ if (!card->dev->coherent_dma_mask)
++ card->dev->coherent_dma_mask = 0xFFFFFFFF;
++
++ if (dai->driver->playback.channels_min) {
++ ret = gw_avila_pcm_preallocate_dma_buffer(pcm,
++ SNDRV_PCM_STREAM_PLAYBACK);
++ if (ret)
++ return ret;
++ }
++
++ if (dai->driver->capture.channels_min) {
++ ret = gw_avila_pcm_preallocate_dma_buffer(pcm,
++ SNDRV_PCM_STREAM_CAPTURE);
++ if (ret)
++ return ret;
++ }
++
++ return 0;
++}
++
++struct snd_soc_platform_driver gw_avila_soc_platform = {
++ .ops = &gw_avila_pcm_ops,
++ .pcm_new = gw_avila_pcm_new,
++ .pcm_free = gw_avila_pcm_free,
++};
++
++static int gw_avila_pcm_platform_probe(struct platform_device *pdev)
++{
++ return snd_soc_register_platform(&pdev->dev, &gw_avila_soc_platform);
++}
++
++static int gw_avila_pcm_platform_remove(struct platform_device *pdev)
++{
++ snd_soc_unregister_platform(&pdev->dev);
++ return 0;
++}
++
++static struct platform_driver gw_avila_pcm_driver = {
++ .driver = {
++ .name = "gw_avila-audio",
++ .owner = THIS_MODULE,
++ },
++ .probe = gw_avila_pcm_platform_probe,
++ .remove = gw_avila_pcm_platform_remove,
++};
++
++static int __init gw_avila_soc_platform_init(void)
++{
++ return platform_driver_register(&gw_avila_pcm_driver);
++}
++module_init(gw_avila_soc_platform_init);
++
++static void __exit gw_avila_soc_platform_exit(void)
++{
++ platform_driver_unregister(&gw_avila_pcm_driver);
++}
++module_exit(gw_avila_soc_platform_exit);
++
++MODULE_AUTHOR("Chris Lang");
++MODULE_DESCRIPTION("Gateworks Avila PCM DMA module");
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ b/sound/soc/gw-avila/gw-avila-pcm.h
+@@ -0,0 +1,32 @@
++/*
++ * ALSA PCM interface for the Gateworks Avila platform
++ *
++ * Author: Chris Lang, <clang@gateworks.com>
++ * Copyright: (C) 2009 Gateworks Corporation
++ *
++ * Based On: davinci-evm.c, Author: Vladimir Barinov, <vbarinov@ru.mvista.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#ifndef _GW_AVILA_PCM_H
++#define _GW_AVILA_PCM_H
++
++#if 0
++struct gw_avila_pcm_dma_params {
++ char *name; /* stream identifier */
++ int channel; /* sync dma channel ID */
++ dma_addr_t dma_addr; /* device physical address for DMA */
++ unsigned int data_type; /* xfer data type */
++};
++
++struct gw_avila_snd_platform_data {
++ int tx_dma_ch; // XXX Do we need this?
++ int rx_dma_ch; // XXX Do we need this
++};
++extern struct snd_soc_platform gw_avila_soc_platform[];
++#endif
++
++#endif
+--- /dev/null
++++ b/sound/soc/gw-avila/gw-avila.c
+@@ -0,0 +1,244 @@
++/*
++ * File: sound/soc/gw-avila/gw_avila.c
++ * Author: Chris Lang <clang@gateworks.com>
++ *
++ * Created: Tue June 06 2008
++ * Description: Board driver for Gateworks Avila
++ *
++ * Modified:
++ * Copyright 2009 Gateworks Corporation
++ *
++ * Bugs: What Bugs?
++ *
++ * 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, see the file COPYING, or write
++ * to the Free Software Foundation, Inc.,
++ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/device.h>
++#include <asm/dma.h>
++#include <linux/platform_device.h>
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/soc.h>
++#include <linux/slab.h>
++#include <linux/gpio.h>
++
++#include "ixp4xx_hss.h"
++#include "gw-avila-hss.h"
++#include "gw-avila-pcm.h"
++
++#define CODEC_FREQ 33333000
++
++static int gw_avila_board_startup(struct snd_pcm_substream *substream)
++{
++ pr_debug("%s enter\n", __func__);
++ return 0;
++}
++
++static int gw_avila_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_dai *codec_dai = rtd->codec_dai;
++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
++
++ int ret = 0;
++
++ /* set codec DAI configuration */
++ if (cpu_dai->id % 2) {
++ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBS_CFS);
++ snd_soc_dai_set_tdm_slot(codec_dai, 0, 0, 1, 32);
++ } else {
++ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBM_CFM);
++ snd_soc_dai_set_tdm_slot(codec_dai, 0, 0, 0, 32);
++ }
++
++ if (ret < 0)
++ return ret;
++
++ /* set the codec system clock */
++ ret = snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_FREQ, SND_SOC_CLOCK_OUT);
++ if (ret < 0)
++ return ret;
++
++ return 0;
++}
++
++static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
++ SND_SOC_DAPM_HP("Headphone Jack", NULL),
++ SND_SOC_DAPM_LINE("Line Out", NULL),
++ SND_SOC_DAPM_LINE("Line In", NULL),
++};
++
++static const struct snd_soc_dapm_route audio_map[] = {
++ {"Headphone Jack", NULL, "HPLOUT"},
++ {"Headphone Jack", NULL, "HPROUT"},
++
++ /* Line Out connected to LLOUT, RLOUT */
++ {"Line Out", NULL, "LLOUT"},
++ {"Line Out", NULL, "RLOUT"},
++
++ /* Line In connected to (LINE1L | LINE2L), (LINE1R | LINE2R) */
++ {"LINE1L", NULL, "Line In"},
++ {"LINE1R", NULL, "Line In"},
++};
++
++/* Logic for a aic3x as connected on a davinci-evm */
++static int avila_aic3x_init(struct snd_soc_pcm_runtime *rtd)
++{
++ struct snd_soc_codec *codec = rtd->codec;
++ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
++
++ /* Add davinci-evm specific widgets */
++ snd_soc_dapm_new_controls(dapm, aic3x_dapm_widgets,
++ ARRAY_SIZE(aic3x_dapm_widgets));
++
++ /* Set up davinci-evm specific audio path audio_map */
++ snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
++
++ /* not connected */
++ snd_soc_dapm_disable_pin(dapm, "MONO_LOUT");
++ //snd_soc_dapm_disable_pin(dapm, "HPLCOM");
++ //snd_soc_dapm_disable_pin(dapm, "HPRCOM");
++ snd_soc_dapm_disable_pin(dapm, "MIC3L");
++ snd_soc_dapm_disable_pin(dapm, "MIC3R");
++ snd_soc_dapm_disable_pin(dapm, "LINE2L");
++ snd_soc_dapm_disable_pin(dapm, "LINE2R");
++
++ /* always connected */
++ snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
++ snd_soc_dapm_enable_pin(dapm, "Line Out");
++ snd_soc_dapm_enable_pin(dapm, "Line In");
++
++ snd_soc_dapm_sync(dapm);
++
++ return 0;
++}
++
++static struct snd_soc_ops gw_avila_board_ops = {
++ .startup = gw_avila_board_startup,
++ .hw_params = gw_avila_hw_params,
++};
++
++static struct snd_soc_dai_link gw_avila_board_dai[] = {
++ {
++ .name = "HSS-0",
++ .stream_name = "HSS-0",
++ .cpu_dai_name = "gw_avila_hss.0",
++ .codec_dai_name = "tlv320aic3x-hifi",
++ .codec_name = "tlv320aic3x-codec.0-001b",
++ .platform_name = "gw_avila-audio.0",
++ .init = avila_aic3x_init,
++ .ops = &gw_avila_board_ops,
++ },{
++ .name = "HSS-1",
++ .stream_name = "HSS-1",
++ .cpu_dai_name = "gw_avila_hss.1",
++ .codec_dai_name = "tlv320aic3x-hifi",
++ .codec_name = "tlv320aic3x-codec.0-001a",
++ .platform_name = "gw_avila-audio.1",
++ .init = avila_aic3x_init,
++ .ops = &gw_avila_board_ops,
++ },{
++ .name = "HSS-2",
++ .stream_name = "HSS-2",
++ .cpu_dai_name = "gw_avila_hss.2",
++ .codec_dai_name = "tlv320aic3x-hifi",
++ .codec_name = "tlv320aic3x-codec.0-0019",
++ .platform_name = "gw_avila-audio.2",
++ .init = avila_aic3x_init,
++ .ops = &gw_avila_board_ops,
++ },{
++ .name = "HSS-3",
++ .stream_name = "HSS-3",
++ .cpu_dai_name = "gw_avila_hss.3",
++ .codec_dai_name = "tlv320aic3x-hifi",
++ .codec_name = "tlv320aic3x-codec.0-0018",
++ .platform_name = "gw_avila-audio.3",
++ .init = avila_aic3x_init,
++ .ops = &gw_avila_board_ops,
++ },
++};
++
++static struct snd_soc_card gw_avila_board[] = {
++ {
++ .name = "gw_avila-board.0",
++ .owner = THIS_MODULE,
++ .dai_link = &gw_avila_board_dai[0],
++ .num_links = 1,
++ },{
++ .name = "gw_avila-board.1",
++ .owner = THIS_MODULE,
++ .dai_link = &gw_avila_board_dai[1],
++ .num_links = 1,
++ },{
++ .name = "gw_avila-board.2",
++ .owner = THIS_MODULE,
++ .dai_link = &gw_avila_board_dai[2],
++ .num_links = 1,
++ },{
++ .name = "gw_avila-board.3",
++ .owner = THIS_MODULE,
++ .dai_link = &gw_avila_board_dai[3],
++ .num_links = 1,
++ }
++};
++
++static struct platform_device *gw_avila_board_snd_device[4];
++
++static int __init gw_avila_board_init(void)
++{
++ int ret;
++ struct port *port;
++ int i;
++
++ if ((hss_port[0] = kzalloc(sizeof(*port), GFP_KERNEL)) == NULL)
++ return -ENOMEM;
++
++ if ((hss_port[1] = kzalloc(sizeof(*port), GFP_KERNEL)) == NULL)
++ return -ENOMEM;
++
++ for (i = 0; i < 4; i++) {
++ gw_avila_board_snd_device[i] = platform_device_alloc("soc-audio", i);
++ if (!gw_avila_board_snd_device[i]) {
++ return -ENOMEM;
++ }
++
++ platform_set_drvdata(gw_avila_board_snd_device[i], &gw_avila_board[i]);
++ ret = platform_device_add(gw_avila_board_snd_device[i]);
++
++ if (ret) {
++ platform_device_put(gw_avila_board_snd_device[i]);
++ }
++ }
++ return ret;
++}
++
++static void __exit gw_avila_board_exit(void)
++{
++ int i;
++ for (i = 0; i < 4; i++)
++ platform_device_unregister(gw_avila_board_snd_device[i]);
++}
++
++module_init(gw_avila_board_init);
++module_exit(gw_avila_board_exit);
++
++/* Module information */
++MODULE_AUTHOR("Chris Lang");
++MODULE_DESCRIPTION("ALSA SoC HSS Audio gw_avila board");
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ b/sound/soc/gw-avila/ixp4xx_hss.c
+@@ -0,0 +1,902 @@
++/*
++ * Intel IXP4xx HSS (synchronous serial port) driver for Linux
++ *
++ * Copyright (C) 2009 Chris Lang <clang@gateworks.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of version 2 of the GNU General Public License
++ * as published by the Free Software Foundation.
++ */
++
++#include <linux/module.h>
++#include <linux/bitops.h>
++#include <linux/cdev.h>
++#include <linux/dma-mapping.h>
++#include <linux/dmapool.h>
++#include <linux/fs.h>
++#include <linux/io.h>
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++#include <linux/poll.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++
++#include <mach/npe.h>
++#include <mach/qmgr.h>
++
++#include "ixp4xx_hss.h"
++
++/*****************************************************************************
++ * global variables
++ ****************************************************************************/
++
++void hss_chan_read(unsigned long data);
++static char lock_init = 0;
++static spinlock_t npe_lock;
++static struct npe *npe;
++
++static const struct {
++ int tx, txdone, rx, rxfree, chan;
++}queue_ids[2] = {{HSS0_PKT_TX0_QUEUE, HSS0_PKT_TXDONE_QUEUE, HSS0_PKT_RX_QUEUE,
++ HSS0_PKT_RXFREE0_QUEUE, HSS0_CHL_RXTRIG_QUEUE},
++ {HSS1_PKT_TX0_QUEUE, HSS1_PKT_TXDONE_QUEUE, HSS1_PKT_RX_QUEUE,
++ HSS1_PKT_RXFREE0_QUEUE, HSS1_CHL_RXTRIG_QUEUE},
++};
++
++struct port *hss_port[2];
++struct hss_device *hss_handle[32];
++EXPORT_SYMBOL(hss_handle);
++
++/*****************************************************************************
++ * utility functions
++ ****************************************************************************/
++
++#ifndef __ARMEB__
++static inline void memcpy_swab32(u32 *dest, u32 *src, int cnt)
++{
++ int i;
++ for (i = 0; i < cnt; i++)
++ dest[i] = swab32(src[i]);
++}
++#endif
++
++static inline unsigned int sub_offset(unsigned int a, unsigned int b,
++ unsigned int modulo)
++{
++ return (modulo /* make sure the result >= 0 */ + a - b) % modulo;
++}
++
++/*****************************************************************************
++ * HSS access
++ ****************************************************************************/
++
++static void hss_config_load(struct port *port)
++{
++ struct msg msg;
++
++ do {
++ memset(&msg, 0, sizeof(msg));
++ msg.cmd = PORT_CONFIG_LOAD;
++ msg.hss_port = port->id;
++ if (npe_send_message(npe, &msg, "HSS_LOAD_CONFIG"))
++ break;
++ if (npe_recv_message(npe, &msg, "HSS_LOAD_CONFIG"))
++ break;
++
++ /* HSS_LOAD_CONFIG for port #1 returns port_id = #4 */
++ if (msg.cmd != PORT_CONFIG_LOAD || msg.data32)
++ break;
++
++ /* HDLC may stop working without this */
++ npe_recv_message(npe, &msg, "FLUSH_IT");
++ return;
++ } while (0);
++
++ printk(KERN_CRIT "HSS-%i: unable to reload HSS configuration\n",
++ port->id);
++ BUG();
++}
++
++static void hss_config_set_pcr(struct port *port)
++{
++ struct msg msg;
++
++ do {
++ memset(&msg, 0, sizeof(msg));
++ msg.cmd = PORT_CONFIG_WRITE;
++ msg.hss_port = port->id;
++ msg.index = HSS_CONFIG_TX_PCR;
++#if 0
++ msg.data32 = PCR_FRM_SYNC_RISINGEDGE | PCR_MSB_ENDIAN |
++ PCR_TX_DATA_ENABLE | PCR_TX_UNASS_HIGH_IMP | PCR_TX_V56K_HIGH_IMP | PCR_TX_FB_HIGH_IMP;
++#else
++ msg.data32 = PCR_FRM_SYNC_RISINGEDGE | PCR_MSB_ENDIAN |
++ PCR_TX_DATA_ENABLE | PCR_TX_FB_HIGH_IMP | PCR_DCLK_EDGE_RISING;
++#endif
++ if (port->frame_size % 8 == 0)
++ msg.data32 |= PCR_SOF_NO_FBIT;
++
++ if (npe_send_message(npe, &msg, "HSS_SET_TX_PCR"))
++ break;
++
++ msg.index = HSS_CONFIG_RX_PCR;
++ msg.data32 &= ~ (PCR_DCLK_EDGE_RISING | PCR_FCLK_EDGE_RISING | PCR_TX_DATA_ENABLE);
++
++ if (npe_send_message(npe, &msg, "HSS_SET_RX_PCR"))
++ break;
++ return;
++ } while (0);
++
++ printk(KERN_CRIT "HSS-%i: unable to set HSS PCR registers\n", port->id);
++ BUG();
++}
++
++static void hss_config_set_core(struct port *port)
++{
++ struct msg msg;
++
++ memset(&msg, 0, sizeof(msg));
++ msg.cmd = PORT_CONFIG_WRITE;
++ msg.hss_port = port->id;
++ msg.index = HSS_CONFIG_CORE_CR;
++#if 0
++ msg.data32 = 0 | CCR_LOOPBACK |
++ (port->id ? CCR_SECOND_HSS : 0);
++#else
++ msg.data32 = 0 |
++ (port->id ? CCR_SECOND_HSS : 0);
++#endif
++ if (npe_send_message(npe, &msg, "HSS_SET_CORE_CR")) {
++ printk(KERN_CRIT "HSS-%i: unable to set HSS core control"
++ " register\n", port->id);
++ BUG();
++ }
++}
++
++static void hss_config_set_line(struct port *port)
++{
++ struct msg msg;
++
++ hss_config_set_pcr(port);
++ hss_config_set_core(port);
++
++ memset(&msg, 0, sizeof(msg));
++ msg.cmd = PORT_CONFIG_WRITE;
++ msg.hss_port = port->id;
++ msg.index = HSS_CONFIG_CLOCK_CR;
++ msg.data32 = CLK42X_SPEED_8192KHZ /* FIXME */;
++ if (npe_send_message(npe, &msg, "HSS_SET_CLOCK_CR")) {
++ printk(KERN_CRIT "HSS-%i: unable to set HSS clock control"
++ " register\n", port->id);
++ BUG();
++ }
++}
++
++static void hss_config_set_rx_frame(struct port *port)
++{
++ struct msg msg;
++
++ memset(&msg, 0, sizeof(msg));
++ msg.cmd = PORT_CONFIG_WRITE;
++ msg.hss_port = port->id;
++ msg.index = HSS_CONFIG_RX_FCR;
++ msg.data16a = port->frame_sync_offset;
++ msg.data16b = port->frame_size - 1;
++ if (npe_send_message(npe, &msg, "HSS_SET_RX_FCR")) {
++ printk(KERN_CRIT "HSS-%i: unable to set HSS RX frame size"
++ " and offset\n", port->id);
++ BUG();
++ }
++}
++
++static void hss_config_set_frame(struct port *port)
++{
++ struct msg msg;
++
++ memset(&msg, 0, sizeof(msg));
++ msg.cmd = PORT_CONFIG_WRITE;
++ msg.hss_port = port->id;
++ msg.index = HSS_CONFIG_TX_FCR;
++ msg.data16a = TX_FRAME_SYNC_OFFSET;
++ msg.data16b = port->frame_size - 1;
++ if (npe_send_message(npe, &msg, "HSS_SET_TX_FCR")) {
++ printk(KERN_CRIT "HSS-%i: unable to set HSS TX frame size"
++ " and offset\n", port->id);
++ BUG();
++ }
++ hss_config_set_rx_frame(port);
++}
++
++static void hss_config_set_lut(struct port *port)
++{
++ struct msg msg;
++ int chan_count = 32;
++
++ memset(&msg, 0, sizeof(msg));
++ msg.cmd = PORT_CONFIG_WRITE;
++ msg.hss_port = port->id;
++
++ msg.index = HSS_CONFIG_TX_LUT;
++ msg.data32 = 0xffffffff;
++ npe_send_message(npe, &msg, "HSS_SET_TX_LUT");
++ msg.index += 4;
++ npe_send_message(npe, &msg, "HSS_SET_TX_LUT");
++ msg.data32 = 0x0;
++ msg.index += 4;
++ npe_send_message(npe, &msg, "HSS_SET_TX_LUT");
++ msg.index += 4;
++ npe_send_message(npe, &msg, "HSS_SET_TX_LUT");
++ msg.index += 4;
++ npe_send_message(npe, &msg, "HSS_SET_TX_LUT");
++ msg.index += 4;
++ npe_send_message(npe, &msg, "HSS_SET_TX_LUT");
++ msg.index += 4;
++ npe_send_message(npe, &msg, "HSS_SET_TX_LUT");
++ msg.index += 4;
++ npe_send_message(npe, &msg, "HSS_SET_TX_LUT");
++
++ msg.index = HSS_CONFIG_RX_LUT;
++ msg.data32 = 0xffffffff;
++ npe_send_message(npe, &msg, "HSS_SET_RX_LUT");
++ msg.index += 4;
++ npe_send_message(npe, &msg, "HSS_SET_RX_LUT");
++ msg.data32 = 0x0;
++ msg.index += 4;
++ npe_send_message(npe, &msg, "HSS_SET_RX_LUT");
++ msg.index += 4;
++ npe_send_message(npe, &msg, "HSS_SET_RX_LUT");
++ msg.index += 4;
++ npe_send_message(npe, &msg, "HSS_SET_RX_LUT");
++ msg.index += 4;
++ npe_send_message(npe, &msg, "HSS_SET_RX_LUT");
++ msg.index += 4;
++ npe_send_message(npe, &msg, "HSS_SET_RX_LUT");
++ msg.index += 4;
++ npe_send_message(npe, &msg, "HSS_SET_RX_LUT");
++
++ hss_config_set_frame(port);
++
++ memset(&msg, 0, sizeof(msg));
++ msg.cmd = CHAN_NUM_CHANS_WRITE;
++ msg.hss_port = port->id;
++ msg.data8a = chan_count;
++ if (npe_send_message(npe, &msg, "CHAN_NUM_CHANS_WRITE")) {
++ printk(KERN_CRIT "HSS-%i: unable to set HSS channel count\n",
++ port->id);
++ BUG();
++ }
++}
++
++static u32 hss_config_get_status(struct port *port)
++{
++ struct msg msg;
++
++ do {
++ memset(&msg, 0, sizeof(msg));
++ msg.cmd = PORT_ERROR_READ;
++ msg.hss_port = port->id;
++ if (npe_send_message(npe, &msg, "PORT_ERROR_READ"))
++ break;
++ if (npe_recv_message(npe, &msg, "PORT_ERROR_READ"))
++ break;
++
++ return msg.data32;
++ } while (0);
++
++ printk(KERN_CRIT "HSS-%i: unable to read HSS status\n", port->id);
++ BUG();
++}
++
++static void hss_config_start_chan(struct port *port)
++{
++ struct msg msg;
++
++ port->chan_last_tx = 0;
++ port->chan_last_rx = 0;
++
++ do {
++ memset(&msg, 0, sizeof(msg));
++ msg.cmd = CHAN_RX_BUF_ADDR_WRITE;
++ msg.hss_port = port->id;
++ msg.data32 = port->chan_rx_buf_phys;
++ if (npe_send_message(npe, &msg, "CHAN_RX_BUF_ADDR_WRITE"))
++ break;
++
++ memset(&msg, 0, sizeof(msg));
++ msg.cmd = CHAN_TX_BUF_ADDR_WRITE;
++ msg.hss_port = port->id;
++ msg.data32 = port->chan_tx_pointers_phys;
++ if (npe_send_message(npe, &msg, "CHAN_TX_BUF_ADDR_WRITE"))
++ break;
++
++ memset(&msg, 0, sizeof(msg));
++ msg.cmd = CHAN_FLOW_ENABLE;
++ msg.hss_port = port->id;
++ if (npe_send_message(npe, &msg, "CHAN_FLOW_ENABLE"))
++ break;
++ port->chan_started = 1;
++ return;
++ } while (0);
++
++ printk(KERN_CRIT "HSS-%i: unable to start channelized flow\n",
++ port->id);
++ BUG();
++}
++
++static void hss_config_stop_chan(struct port *port)
++{
++ struct msg msg;
++
++ if (!port->chan_started)
++ return;
++
++ memset(&msg, 0, sizeof(msg));
++ msg.cmd = CHAN_FLOW_DISABLE;
++ msg.hss_port = port->id;
++ if (npe_send_message(npe, &msg, "CHAN_FLOW_DISABLE")) {
++ printk(KERN_CRIT "HSS-%i: unable to stop channelized flow\n",
++ port->id);
++ BUG();
++ }
++ hss_config_get_status(port); /* make sure it's halted */
++ port->chan_started = 0;
++}
++
++static int hss_config_load_firmware(struct port *port)
++{
++ struct msg msg;
++
++ if (port->initialized)
++ return 0;
++
++ if (!npe_running(npe)) {
++ int err;
++ if ((err = npe_load_firmware(npe, "NPE-A-HSS",
++ port->dev)))
++ return err;
++ }
++
++ do {
++ /* HSS main configuration */
++ hss_config_set_line(port);
++
++ hss_config_set_frame(port);
++
++ /* Channelized operation settings */
++ memset(&msg, 0, sizeof(msg));
++ msg.cmd = CHAN_TX_BLK_CFG_WRITE;
++ msg.hss_port = port->id;
++ msg.data8b = (CHAN_TX_LIST_FRAMES & ~7) / 2;
++ msg.data8a = msg.data8b / 4;
++ msg.data8d = CHAN_TX_LIST_FRAMES - msg.data8b;
++ msg.data8c = msg.data8d / 4;
++ if (npe_send_message(npe, &msg, "CHAN_TX_BLK_CFG_WRITE"))
++ break;
++
++ memset(&msg, 0, sizeof(msg));
++ msg.cmd = CHAN_RX_BUF_CFG_WRITE;
++ msg.hss_port = port->id;
++ msg.data8a = CHAN_RX_TRIGGER / 8;
++ msg.data8b = CHAN_RX_FRAMES;
++ if (npe_send_message(npe, &msg, "CHAN_RX_BUF_CFG_WRITE"))
++ break;
++
++ memset(&msg, 0, sizeof(msg));
++ msg.cmd = CHAN_TX_BUF_SIZE_WRITE;
++ msg.hss_port = port->id;
++ msg.data8a = CHAN_TX_LISTS;
++ if (npe_send_message(npe, &msg, "CHAN_TX_BUF_SIZE_WRITE"))
++ break;
++
++ port->initialized = 1;
++ return 0;
++ } while (0);
++
++ printk(KERN_CRIT "HSS-%i: unable to start HSS operation\n", port->id);
++ BUG();
++}
++
++void hss_chan_irq(void *pdev)
++{
++ struct port *port = pdev;
++
++ qmgr_disable_irq(queue_ids[port->id].chan);
++
++ tasklet_hi_schedule(&port->task);
++}
++
++
++int hss_prepare_chan(struct port *port)
++{
++ int err, i, j;
++ u32 *temp;
++ u32 temp2;
++ u8 *temp3;
++
++ if (port->initialized)
++ return 0;
++
++ if ((err = hss_config_load_firmware(port)))
++ return err;
++
++ if ((err = qmgr_request_queue(queue_ids[port->id].chan,
++ CHAN_QUEUE_LEN, 0, 0, "%s:hss", "hss")))
++ return err;
++
++ port->chan_tx_buf = dma_alloc_coherent(port->dev, chan_tx_buf_len(port), &port->chan_tx_buf_phys, GFP_DMA);
++ memset(port->chan_tx_buf, 0, chan_tx_buf_len(port));
++
++ port->chan_tx_pointers = dma_alloc_coherent(port->dev, chan_tx_buf_len(port) / CHAN_TX_LIST_FRAMES * 4, &port->chan_tx_pointers_phys, GFP_DMA);
++
++ temp3 = port->chan_tx_buf;
++ for (i = 0; i < CHAN_TX_LISTS; i++) {
++ for (j = 0; j < 8; j++) {
++ port->tx_lists[i][j] = temp3;
++ temp3 += CHAN_TX_LIST_FRAMES * 4;
++ }
++ }
++
++ temp = port->chan_tx_pointers;
++ temp2 = port->chan_tx_buf_phys;
++ for (i = 0; i < CHAN_TX_LISTS; i++)
++ {
++ for (j = 0; j < 32; j++)
++ {
++ *temp = temp2;
++ temp2 += CHAN_TX_LIST_FRAMES;
++ temp++;
++ }
++ }
++
++ port->chan_rx_buf = dma_alloc_coherent(port->dev, chan_rx_buf_len(port), &port->chan_rx_buf_phys, GFP_DMA);
++
++ for (i = 0; i < 8; i++) {
++ temp3 = port->chan_rx_buf + (i * 4 * 128);
++ for (j = 0; j < 8; j++) {
++ port->rx_frames[i][j] = temp3;
++ temp3 += CHAN_RX_TRIGGER;
++ }
++ }
++
++ qmgr_set_irq(queue_ids[port->id].chan, QUEUE_IRQ_SRC_NOT_EMPTY,
++ hss_chan_irq, port);
++
++ return 0;
++
++}
++
++int hss_tx_start(struct hss_device *hdev)
++{
++ unsigned long flags;
++ struct port *port = hdev->port;
++
++ hdev->tx_loc = 0;
++ hdev->tx_frame = 0;
++
++ set_bit((1 << hdev->id), &port->chan_tx_bitmap);
++
++ if (!port->chan_started)
++ {
++ qmgr_enable_irq(queue_ids[port->id].chan);
++ spin_lock_irqsave(&npe_lock, flags);
++ hss_config_start_chan(port);
++ spin_unlock_irqrestore(&npe_lock, flags);
++ hss_chan_irq(port);
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL(hss_tx_start);
++
++int hss_rx_start(struct hss_device *hdev)
++{
++ unsigned long flags;
++ struct port *port = hdev->port;
++
++ hdev->rx_loc = 0;
++ hdev->rx_frame = 0;
++
++ set_bit((1 << hdev->id), &port->chan_rx_bitmap);
++
++ if (!port->chan_started)
++ {
++ qmgr_enable_irq(queue_ids[port->id].chan);
++ spin_lock_irqsave(&npe_lock, flags);
++ hss_config_start_chan(port);
++ spin_unlock_irqrestore(&npe_lock, flags);
++ hss_chan_irq(port);
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL(hss_rx_start);
++
++int hss_tx_stop(struct hss_device *hdev)
++{
++ struct port *port = hdev->port;
++
++ clear_bit((1 << hdev->id), &port->chan_tx_bitmap);
++
++ return 0;
++}
++EXPORT_SYMBOL(hss_tx_stop);
++
++int hss_rx_stop(struct hss_device *hdev)
++{
++ struct port *port = hdev->port;
++
++ clear_bit((1 << hdev->id), &port->chan_rx_bitmap);
++
++ return 0;
++}
++EXPORT_SYMBOL(hss_rx_stop);
++
++int hss_chan_open(struct hss_device *hdev)
++{
++ struct port *port = hdev->port;
++ int i, err = 0;
++
++ if (port->chan_open)
++ return 0;
++
++ if (port->mode == MODE_HDLC) {
++ err = -ENOSYS;
++ goto out;
++ }
++
++ if (port->mode == MODE_G704 && port->channels[0] == hdev->id) {
++ err = -EBUSY; /* channel #0 is used for G.704 signaling */
++ goto out;
++ }
++
++ for (i = MAX_CHANNELS; i > port->frame_size / 8; i--)
++ if (port->channels[i - 1] == hdev->id) {
++ err = -ECHRNG; /* frame too short */
++ goto out;
++ }
++
++ hdev->rx_loc = hdev->tx_loc = 0;
++ hdev->rx_frame = hdev->tx_frame = 0;
++
++ //clear_bit((1 << hdev->id), &port->chan_rx_bitmap);
++ //clear_bit((1 << hdev->id), &port->chan_tx_bitmap);
++
++ if (!port->initialized) {
++ hss_prepare_chan(port);
++
++ hss_config_stop_chan(port);
++ hdev->open_count++;
++ port->chan_open_count++;
++
++ hss_config_set_lut(port);
++ hss_config_load(port);
++
++ }
++ port->chan_open = 1;
++
++out:
++ return err;
++}
++EXPORT_SYMBOL(hss_chan_open);
++
++int hss_chan_close(struct hss_device *hdev)
++{
++ return 0;
++}
++EXPORT_SYMBOL(hss_chan_close);
++
++void hss_chan_read(unsigned long data)
++{
++ struct port *port = (void *)data;
++ struct hss_device *hdev;
++ u8 *hw_buf, *save_buf;
++ u8 *buf;
++ u32 v;
++ unsigned int tx_list, rx_frame;
++ int i, j, channel;
++ u8 more_work = 0;
++
++/*
++ My Data in the hardware buffer is scattered by channels into 4 trunks
++ as follows for rx
++
++ channel 0 channel 1 channel 2 channel 3
++Trunk 1 = 0 -> 127 128 -> 255 256 -> 383 384 -> 512
++Trunk 2 = 513 -> 639 640 -> 768 769 -> 895 896 -> 1023
++Trunk 3 = 1024 -> 1151 1152 -> 1207 1208 -> 1407 1408 -> 1535
++Trunk 4 = 1535 -> 1663 1664 -> 1791 1792 -> 1920 1921 -> 2047
++
++ I will get CHAN_RX_TRIGGER worth of bytes out of each channel on each trunk
++ with each IRQ
++
++ For TX Data, it is split into 8 lists with each list containing 16 bytes per
++ channel
++
++Trunk 1 = 0 -> 16 17 -> 32 33 -> 48 49 -> 64
++Trunk 2 = 65 -> 80 81 -> 96 97 -> 112 113 -> 128
++Trunk 3 = 129 -> 144 145 -> 160 161 -> 176 177 -> 192
++Trunk 4 = 193 -> 208 209 -> 224 225 -> 240 241 -> 256
++
++*/
++
++
++ while ((v = qmgr_get_entry(queue_ids[port->id].chan)))
++ {
++ tx_list = (v >> 8) & 0xFF;
++ rx_frame = v & 0xFF;
++
++ if (tx_list == 7)
++ tx_list = 0;
++ else
++ tx_list++;
++ for (channel = 0; channel < 8; channel++) {
++
++ hdev = port->chan_devices[channel];
++ if (!hdev)
++ continue;
++
++ if (test_bit(1 << channel, &port->chan_tx_bitmap)) {
++ buf = (u8 *)hdev->tx_buf + hdev->tx_loc;
++#if 0
++ hw_buf = (u8 *)port->chan_tx_buf;
++ hw_buf += (tx_list * CHAN_TX_LIST_FRAMES * 32);
++ hw_buf += (4 * CHAN_TX_LIST_FRAMES * channel);
++ save_buf = hw_buf;
++#else
++ save_buf = port->tx_lists[tx_list][channel];
++#endif
++ for (i = 0; i < CHAN_TX_LIST_FRAMES; i++) {
++ hw_buf = save_buf + i;
++ for (j = 0; j < 4; j++) {
++ *hw_buf = *(buf++);
++ hw_buf += CHAN_TX_LIST_FRAMES;
++ }
++
++ hdev->tx_loc += 4;
++ hdev->tx_frame++;
++ if (hdev->tx_loc >= hdev->tx_buffer_size) {
++ hdev->tx_loc = 0;
++ buf = (u8 *)hdev->tx_buf;
++ }
++ }
++ } else {
++#if 0
++ hw_buf = (u8 *)port->chan_tx_buf;
++ hw_buf += (tx_list * CHAN_TX_LIST_FRAMES * 32);
++ hw_buf += (4 * CHAN_TX_LIST_FRAMES * channel);
++#else
++ hw_buf = port->tx_lists[tx_list][channel];
++#endif
++ memset(hw_buf, 0, 64);
++ }
++
++ if (hdev->tx_frame >= hdev->tx_period_size && test_bit(1 << channel, &port->chan_tx_bitmap))
++ {
++ hdev->tx_frame %= hdev->tx_period_size;
++ if (hdev->tx_callback)
++ hdev->tx_callback(hdev->tx_data);
++ more_work = 1;
++ }
++
++ if (test_bit(1 << channel, &port->chan_rx_bitmap)) {
++ buf = (u8 *)hdev->rx_buf + hdev->rx_loc;
++#if 0
++ hw_buf = (u8 *)port->chan_rx_buf;
++ hw_buf += (4 * CHAN_RX_FRAMES * channel);
++ hw_buf += rx_frame;
++ save_buf = hw_buf;
++#else
++ save_buf = port->rx_frames[channel][rx_frame >> 4];
++#endif
++ for (i = 0; i < CHAN_RX_TRIGGER; i++) {
++ hw_buf = save_buf + i;
++ for (j = 0; j < 4; j++) {
++ *(buf++) = *hw_buf;
++ hw_buf += CHAN_RX_FRAMES;
++ }
++ hdev->rx_loc += 4;
++ hdev->rx_frame++;
++ if (hdev->rx_loc >= hdev->rx_buffer_size) {
++ hdev->rx_loc = 0;
++ buf = (u8 *)hdev->rx_buf;
++ }
++ }
++ }
++
++ if (hdev->rx_frame >= hdev->rx_period_size && test_bit(1 << channel, &port->chan_rx_bitmap))
++ {
++ hdev->rx_frame %= hdev->rx_period_size;
++ if (hdev->rx_callback)
++ hdev->rx_callback(hdev->rx_data);
++ more_work = 1;
++ }
++ }
++#if 0
++ if (more_work)
++ {
++ tasklet_hi_schedule(&port->task);
++ return;
++ }
++#endif
++ }
++
++ qmgr_enable_irq(queue_ids[port->id].chan);
++
++ return;
++
++}
++
++struct hss_device *hss_chan_create(struct port *port, unsigned int channel)
++{
++ struct hss_device *chan_dev;
++ unsigned long flags;
++
++ chan_dev = kzalloc(sizeof(struct hss_device), GFP_KERNEL);
++
++ spin_lock_irqsave(&npe_lock, flags);
++
++ chan_dev->id = channel;
++ chan_dev->port = port;
++
++ port->channels[channel] = channel;
++
++ port->chan_devices[channel] = chan_dev;
++
++ spin_unlock_irqrestore(&npe_lock, flags);
++
++ return chan_dev;
++}
++
++/*****************************************************************************
++ * initialization
++ ****************************************************************************/
++
++static struct platform_device gw_avila_hss_device_0 = {
++ .name = "ixp4xx_hss",
++ .id = 0,
++};
++
++static struct platform_device gw_avila_hss_device_1 = {
++ .name = "ixp4xx_hss",
++ .id = 1,
++};
++
++static struct platform_device *gw_avila_hss_port_0;
++static struct platform_device *gw_avila_hss_port_1;
++static u64 hss_dmamask = 0xFFFFFFFF;
++
++struct hss_device *hss_init(int id, int channel)
++{
++ struct port *port = hss_port[id];
++ struct hss_device *hdev;
++ int ret;
++
++ if (!lock_init)
++ {
++ spin_lock_init(&npe_lock);
++ lock_init = 1;
++ npe = npe_request(0);
++ }
++
++ if (!port->init) {
++ if (id == 0) {
++ gw_avila_hss_port_0 = platform_device_alloc("hss-port", 0);
++
++ platform_set_drvdata(gw_avila_hss_port_0, &gw_avila_hss_device_0);
++ port->dev = &gw_avila_hss_port_0->dev;
++
++ if (!port->dev->dma_mask)
++ port->dev->dma_mask = &hss_dmamask;
++ if (!port->dev->coherent_dma_mask)
++ port->dev->coherent_dma_mask = 0xFFFFFFFF;
++
++ ret = platform_device_add(gw_avila_hss_port_0);
++
++ if (ret)
++ platform_device_put(gw_avila_hss_port_0);
++
++ tasklet_init(&port->task, hss_chan_read, (unsigned long) port);
++ }
++ else
++ {
++ gw_avila_hss_port_1 = platform_device_alloc("hss-port", 1);
++
++ platform_set_drvdata(gw_avila_hss_port_1, &gw_avila_hss_device_1);
++ port->dev = &gw_avila_hss_port_1->dev;
++
++ if (!port->dev->dma_mask)
++ port->dev->dma_mask = &hss_dmamask;
++ if (!port->dev->coherent_dma_mask)
++ port->dev->coherent_dma_mask = 0xFFFFFFFF;
++
++ ret = platform_device_add(gw_avila_hss_port_1);
++
++ if (ret)
++ platform_device_put(gw_avila_hss_port_1);
++
++ tasklet_init(&port->task, hss_chan_read, (unsigned long) port);
++ }
++
++ port->init = 1;
++ port->id = id;
++ port->clock_type = CLOCK_EXT;
++ port->clock_rate = 8192000;
++ port->frame_size = 256; /* E1 */
++ port->mode = MODE_RAW;
++ port->next_rx_frame = 0;
++ memset(port->channels, CHANNEL_UNUSED, sizeof(port->channels));
++ }
++
++ hdev = hss_chan_create(port, channel);
++
++ return hdev;
++}
++EXPORT_SYMBOL(hss_init);
++
++int hss_set_tx_callback(struct hss_device *hdev, void (*tx_callback)(void *), void *tx_data)
++{
++ BUG_ON(tx_callback == NULL);
++ hdev->tx_callback = tx_callback;
++ hdev->tx_data = tx_data;
++
++ return 0;
++}
++EXPORT_SYMBOL(hss_set_tx_callback);
++
++int hss_set_rx_callback(struct hss_device *hdev, void (*rx_callback)(void *), void *rx_data)
++{
++ BUG_ON(rx_callback == NULL);
++ hdev->rx_callback = rx_callback;
++ hdev->rx_data = rx_data;
++
++ return 0;
++}
++EXPORT_SYMBOL(hss_set_rx_callback);
++
++int hss_config_rx_dma(struct hss_device *hdev, void *buf, size_t buffer_size, size_t period_size)
++{
++ /*
++ * Period Size and Buffer Size are in Frames which are u32
++ * We convert the u32 *buf to u8 in order to make channel reads
++ * and rx_loc easier
++ */
++
++ hdev->rx_buf = (u8 *)buf;
++ hdev->rx_buffer_size = buffer_size << 2;
++ hdev->rx_period_size = period_size;
++
++ return 0;
++}
++EXPORT_SYMBOL(hss_config_rx_dma);
++
++int hss_config_tx_dma(struct hss_device *hdev, void *buf, size_t buffer_size, size_t period_size)
++{
++ /*
++ * Period Size and Buffer Size are in Frames which are u32
++ * We convert the u32 *buf to u8 in order to make channel reads
++ * and rx_loc easier
++ */
++
++ hdev->tx_buf = (u8 *)buf;
++ hdev->tx_buffer_size = buffer_size << 2;
++ hdev->tx_period_size = period_size;
++
++ return 0;
++}
++EXPORT_SYMBOL(hss_config_tx_dma);
++
++unsigned long hss_curr_offset_rx(struct hss_device *hdev)
++{
++ return hdev->rx_loc >> 2;
++}
++EXPORT_SYMBOL(hss_curr_offset_rx);
++
++unsigned long hss_curr_offset_tx(struct hss_device *hdev)
++{
++ return hdev->tx_loc >> 2;
++}
++EXPORT_SYMBOL(hss_curr_offset_tx);
++
++MODULE_AUTHOR("Chris Lang");
++MODULE_DESCRIPTION("Intel IXP4xx HSS Audio driver");
++MODULE_LICENSE("GPL v2");
+--- /dev/null
++++ b/sound/soc/gw-avila/ixp4xx_hss.h
+@@ -0,0 +1,401 @@
++/*
++ *
++ *
++ * Copyright (C) 2009 Gateworks Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of version 2 of the GNU General Public License
++ * as published by the Free Software Foundation.
++ */
++
++#include <linux/types.h>
++#include <linux/bitops.h>
++#include <linux/dma-mapping.h>
++#include <linux/dmapool.h>
++#include <linux/fs.h>
++#include <linux/io.h>
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++#include <linux/poll.h>
++#include <mach/npe.h>
++#include <mach/qmgr.h>
++#include <linux/interrupt.h>
++
++//#include <linux/hdlc.h> XXX We aren't HDLC
++
++#define DEBUG_QUEUES 0
++#define DEBUG_DESC 0
++#define DEBUG_RX 0
++#define DEBUG_TX 0
++#define DEBUG_PKT_BYTES 0
++#define DEBUG_CLOSE 0
++#define DEBUG_FRAMER 0
++
++#define DRV_NAME "ixp4xx_hss"
++
++#define PKT_EXTRA_FLAGS 0 /* orig 1 */
++#define TX_FRAME_SYNC_OFFSET 0 /* channelized */
++#define PKT_NUM_PIPES 1 /* 1, 2 or 4 */
++#define PKT_PIPE_FIFO_SIZEW 4 /* total 4 dwords per HSS */
++
++#define RX_DESCS 512 /* also length of all RX queues */
++#define TX_DESCS 512 /* also length of all TX queues */
++
++//#define POOL_ALLOC_SIZE (sizeof(struct desc) * (RX_DESCS + TX_DESCS))
++#define RX_SIZE (HDLC_MAX_MRU + 4) /* NPE needs more space */
++#define MAX_CLOSE_WAIT 1000 /* microseconds */
++#define HSS_COUNT 2
++#define MIN_FRAME_SIZE 16 /* bits */
++#define MAX_FRAME_SIZE 257 /* 256 bits + framing bit */
++#define MAX_CHANNELS (MAX_FRAME_SIZE / 8)
++#define MAX_CHAN_DEVICES 32
++#define CHANNEL_HDLC 0xFE
++#define CHANNEL_UNUSED 0xFF
++
++#define NAPI_WEIGHT 16
++#define CHAN_RX_TRIGGER 16 /* 8 RX frames = 1 ms @ E1 */
++#define CHAN_RX_FRAMES 128
++#define CHAN_RX_TRUNKS 1
++#define MAX_CHAN_RX_BAD_SYNC (CHAN_RX_TRIGGER / 2 /* pairs */ - 3)
++
++#define CHAN_TX_LIST_FRAMES CHAN_RX_TRIGGER /* bytes/channel per list, 16 - 48 */
++#define CHAN_TX_LISTS 8
++#define CHAN_TX_TRUNKS CHAN_RX_TRUNKS
++#define CHAN_TX_FRAMES (CHAN_TX_LIST_FRAMES * CHAN_TX_LISTS)
++
++#define CHAN_QUEUE_LEN 32 /* minimum possible */
++
++#define chan_rx_buf_len(port) (port->frame_size / 8 * CHAN_RX_FRAMES * CHAN_RX_TRUNKS)
++#define chan_tx_buf_len(port) (port->frame_size / 8 * CHAN_TX_FRAMES * CHAN_TX_TRUNKS)
++
++/* Queue IDs */
++#define HSS0_CHL_RXTRIG_QUEUE 12 /* orig size = 32 dwords */
++#define HSS0_PKT_RX_QUEUE 13 /* orig size = 32 dwords */
++#define HSS0_PKT_TX0_QUEUE 14 /* orig size = 16 dwords */
++#define HSS0_PKT_TX1_QUEUE 15
++#define HSS0_PKT_TX2_QUEUE 16
++#define HSS0_PKT_TX3_QUEUE 17
++#define HSS0_PKT_RXFREE0_QUEUE 18 /* orig size = 16 dwords */
++#define HSS0_PKT_RXFREE1_QUEUE 19
++#define HSS0_PKT_RXFREE2_QUEUE 20
++#define HSS0_PKT_RXFREE3_QUEUE 21
++#define HSS0_PKT_TXDONE_QUEUE 22 /* orig size = 64 dwords */
++
++#define HSS1_CHL_RXTRIG_QUEUE 10
++#define HSS1_PKT_RX_QUEUE 0
++#define HSS1_PKT_TX0_QUEUE 5
++#define HSS1_PKT_TX1_QUEUE 6
++#define HSS1_PKT_TX2_QUEUE 7
++#define HSS1_PKT_TX3_QUEUE 8
++#define HSS1_PKT_RXFREE0_QUEUE 1
++#define HSS1_PKT_RXFREE1_QUEUE 2
++#define HSS1_PKT_RXFREE2_QUEUE 3
++#define HSS1_PKT_RXFREE3_QUEUE 4
++#define HSS1_PKT_TXDONE_QUEUE 9
++
++#define NPE_PKT_MODE_HDLC 0
++#define NPE_PKT_MODE_RAW 1
++#define NPE_PKT_MODE_56KMODE 2
++#define NPE_PKT_MODE_56KENDIAN_MSB 4
++
++/* PKT_PIPE_HDLC_CFG_WRITE flags */
++#define PKT_HDLC_IDLE_ONES 0x1 /* default = flags */
++#define PKT_HDLC_CRC_32 0x2 /* default = CRC-16 */
++#define PKT_HDLC_MSB_ENDIAN 0x4 /* default = LE */
++
++
++/* hss_config, PCRs */
++/* Frame sync sampling, default = active low */
++#define PCR_FRM_SYNC_ACTIVE_HIGH 0x40000000
++#define PCR_FRM_SYNC_FALLINGEDGE 0x80000000
++#define PCR_FRM_SYNC_RISINGEDGE 0xC0000000
++
++/* Frame sync pin: input (default) or output generated off a given clk edge */
++#define PCR_FRM_SYNC_OUTPUT_FALLING 0x20000000
++#define PCR_FRM_SYNC_OUTPUT_RISING 0x30000000
++
++/* Frame and data clock sampling on edge, default = falling */
++#define PCR_FCLK_EDGE_RISING 0x08000000
++#define PCR_DCLK_EDGE_RISING 0x04000000
++
++/* Clock direction, default = input */
++#define PCR_SYNC_CLK_DIR_OUTPUT 0x02000000
++
++/* Generate/Receive frame pulses, default = enabled */
++#define PCR_FRM_PULSE_DISABLED 0x01000000
++
++ /* Data rate is full (default) or half the configured clk speed */
++#define PCR_HALF_CLK_RATE 0x00200000
++
++/* Invert data between NPE and HSS FIFOs? (default = no) */
++#define PCR_DATA_POLARITY_INVERT 0x00100000
++
++/* TX/RX endianness, default = LSB */
++#define PCR_MSB_ENDIAN 0x00080000
++
++/* Normal (default) / open drain mode (TX only) */
++#define PCR_TX_PINS_OPEN_DRAIN 0x00040000
++
++/* No framing bit transmitted and expected on RX? (default = framing bit) */
++#define PCR_SOF_NO_FBIT 0x00020000
++
++/* Drive data pins? */
++#define PCR_TX_DATA_ENABLE 0x00010000
++
++/* Voice 56k type: drive the data pins low (default), high, high Z */
++#define PCR_TX_V56K_HIGH 0x00002000
++#define PCR_TX_V56K_HIGH_IMP 0x00004000
++
++/* Unassigned type: drive the data pins low (default), high, high Z */
++#define PCR_TX_UNASS_HIGH 0x00000800
++#define PCR_TX_UNASS_HIGH_IMP 0x00001000
++
++/* T1 @ 1.544MHz only: Fbit dictated in FIFO (default) or high Z */
++#define PCR_TX_FB_HIGH_IMP 0x00000400
++
++/* 56k data endiannes - which bit unused: high (default) or low */
++#define PCR_TX_56KE_BIT_0_UNUSED 0x00000200
++
++/* 56k data transmission type: 32/8 bit data (default) or 56K data */
++#define PCR_TX_56KS_56K_DATA 0x00000100
++
++/* hss_config, cCR */
++/* Number of packetized clients, default = 1 */
++#define CCR_NPE_HFIFO_2_HDLC 0x04000000
++#define CCR_NPE_HFIFO_3_OR_4HDLC 0x08000000
++
++/* default = no loopback */
++#define CCR_LOOPBACK 0x02000000
++
++/* HSS number, default = 0 (first) */
++#define CCR_SECOND_HSS 0x01000000
++
++
++/* hss_config, clkCR: main:10, num:10, denom:12 */
++#define CLK42X_SPEED_EXP ((0x3FF << 22) | ( 2 << 12) | 15) /*65 KHz*/
++
++#define CLK42X_SPEED_512KHZ (( 130 << 22) | ( 2 << 12) | 15)
++#define CLK42X_SPEED_1536KHZ (( 43 << 22) | ( 18 << 12) | 47)
++#define CLK42X_SPEED_1544KHZ (( 43 << 22) | ( 33 << 12) | 192)
++#define CLK42X_SPEED_2048KHZ (( 32 << 22) | ( 34 << 12) | 63)
++#define CLK42X_SPEED_4096KHZ (( 16 << 22) | ( 34 << 12) | 127)
++#define CLK42X_SPEED_8192KHZ (( 8 << 22) | ( 34 << 12) | 255)
++
++#define CLK46X_SPEED_512KHZ (( 130 << 22) | ( 24 << 12) | 127)
++#define CLK46X_SPEED_1536KHZ (( 43 << 22) | (152 << 12) | 383)
++#define CLK46X_SPEED_1544KHZ (( 43 << 22) | ( 66 << 12) | 385)
++#define CLK46X_SPEED_2048KHZ (( 32 << 22) | (280 << 12) | 511)
++#define CLK46X_SPEED_4096KHZ (( 16 << 22) | (280 << 12) | 1023)
++#define CLK46X_SPEED_8192KHZ (( 8 << 22) | (280 << 12) | 2047)
++
++
++/* hss_config, LUT entries */
++#define TDMMAP_UNASSIGNED 0
++#define TDMMAP_HDLC 1 /* HDLC - packetized */
++#define TDMMAP_VOICE56K 2 /* Voice56K - 7-bit channelized */
++#define TDMMAP_VOICE64K 3 /* Voice64K - 8-bit channelized */
++
++/* offsets into HSS config */
++#define HSS_CONFIG_TX_PCR 0x00 /* port configuration registers */
++#define HSS_CONFIG_RX_PCR 0x04
++#define HSS_CONFIG_CORE_CR 0x08 /* loopback control, HSS# */
++#define HSS_CONFIG_CLOCK_CR 0x0C /* clock generator control */
++#define HSS_CONFIG_TX_FCR 0x10 /* frame configuration registers */
++#define HSS_CONFIG_RX_FCR 0x14
++#define HSS_CONFIG_TX_LUT 0x18 /* channel look-up tables */
++#define HSS_CONFIG_RX_LUT 0x38
++
++
++/* NPE command codes */
++/* writes the ConfigWord value to the location specified by offset */
++#define PORT_CONFIG_WRITE 0x40
++
++/* triggers the NPE to load the contents of the configuration table */
++#define PORT_CONFIG_LOAD 0x41
++
++/* triggers the NPE to return an HssErrorReadResponse message */
++#define PORT_ERROR_READ 0x42
++
++/* reset NPE internal status and enable the HssChannelized operation */
++#define CHAN_FLOW_ENABLE 0x43
++#define CHAN_FLOW_DISABLE 0x44
++#define CHAN_IDLE_PATTERN_WRITE 0x45
++#define CHAN_NUM_CHANS_WRITE 0x46
++#define CHAN_RX_BUF_ADDR_WRITE 0x47
++#define CHAN_RX_BUF_CFG_WRITE 0x48
++#define CHAN_TX_BLK_CFG_WRITE 0x49
++#define CHAN_TX_BUF_ADDR_WRITE 0x4A
++#define CHAN_TX_BUF_SIZE_WRITE 0x4B
++#define CHAN_TSLOTSWITCH_ENABLE 0x4C
++#define CHAN_TSLOTSWITCH_DISABLE 0x4D
++
++/* downloads the gainWord value for a timeslot switching channel associated
++ with bypassNum */
++#define CHAN_TSLOTSWITCH_GCT_DOWNLOAD 0x4E
++
++/* triggers the NPE to reset internal status and enable the HssPacketized
++ operation for the flow specified by pPipe */
++#define PKT_PIPE_FLOW_ENABLE 0x50
++#define PKT_PIPE_FLOW_DISABLE 0x51
++#define PKT_NUM_PIPES_WRITE 0x52
++#define PKT_PIPE_FIFO_SIZEW_WRITE 0x53
++#define PKT_PIPE_HDLC_CFG_WRITE 0x54
++#define PKT_PIPE_IDLE_PATTERN_WRITE 0x55
++#define PKT_PIPE_RX_SIZE_WRITE 0x56
++#define PKT_PIPE_MODE_WRITE 0x57
++
++/* HDLC packet status values - desc->status */
++#define ERR_SHUTDOWN 1 /* stop or shutdown occurrance */
++#define ERR_HDLC_ALIGN 2 /* HDLC alignment error */
++#define ERR_HDLC_FCS 3 /* HDLC Frame Check Sum error */
++#define ERR_RXFREE_Q_EMPTY 4 /* RX-free queue became empty while receiving
++ this packet (if buf_len < pkt_len) */
++#define ERR_HDLC_TOO_LONG 5 /* HDLC frame size too long */
++#define ERR_HDLC_ABORT 6 /* abort sequence received */
++#define ERR_DISCONNECTING 7 /* disconnect is in progress */
++
++#define CLOCK_EXT 0
++#define CLOCK_INT 1
++
++enum mode {MODE_HDLC = 0, MODE_RAW, MODE_G704};
++enum rx_tx_bit {
++ TX_BIT = 0,
++ RX_BIT = 1
++};
++enum chan_bit {
++ CHAN_0 = (1 << 0),
++ CHAN_1 = (1 << 1),
++ CHAN_2 = (1 << 2),
++ CHAN_3 = (1 << 3),
++ CHAN_4 = (1 << 4),
++ CHAN_5 = (1 << 5),
++ CHAN_6 = (1 << 6),
++ CHAN_7 = (1 << 7),
++ CHAN_8 = (1 << 8),
++ CHAN_9 = (1 << 9),
++ CHAN_10 = (1 << 10),
++ CHAN_11 = (1 << 11),
++ CHAN_12 = (1 << 12),
++ CHAN_13 = (1 << 13),
++ CHAN_14 = (1 << 14),
++ CHAN_15 = (1 << 15)
++};
++
++enum alignment { NOT_ALIGNED = 0, EVEN_FIRST, ODD_FIRST };
++
++#ifdef __ARMEB__
++typedef struct sk_buff buffer_t;
++#define free_buffer dev_kfree_skb
++#define free_buffer_irq dev_kfree_skb_irq
++#else
++typedef void buffer_t;
++#define free_buffer kfree
++#define free_buffer_irq kfree
++#endif
++
++struct hss_device {
++ struct port *port;
++ unsigned int open_count, excl_open;
++ unsigned long tx_loc, rx_loc; /* bytes */
++ unsigned long tx_frame, rx_frame; /* Frames */
++ u8 id, chan_count;
++ u8 log_channels[MAX_CHANNELS];
++
++ u8 *rx_buf;
++ u8 *tx_buf;
++
++ size_t rx_buffer_size;
++ size_t rx_period_size;
++ size_t tx_buffer_size;
++ size_t tx_period_size;
++
++ void (*rx_callback)(void *data);
++ void *rx_data;
++ void (*tx_callback)(void *data);
++ void *tx_data;
++ void *private_data;
++};
++
++extern struct hss_device *hss_handle[32];
++extern struct port *hss_port[2];
++
++struct port {
++ unsigned char init;
++
++ struct device *dev;
++
++ struct tasklet_struct task;
++ unsigned int id;
++ unsigned long chan_rx_bitmap;
++ unsigned long chan_tx_bitmap;
++ unsigned char chan_open;
++
++ /* the following fields must be protected by npe_lock */
++ enum mode mode;
++ unsigned int clock_type, clock_rate, loopback;
++ unsigned int frame_size, frame_sync_offset;
++ unsigned int next_rx_frame;
++
++ struct hss_device *chan_devices[MAX_CHAN_DEVICES];
++ u32 chan_tx_buf_phys, chan_rx_buf_phys;
++ u32 chan_tx_pointers_phys;
++ u32 *chan_tx_pointers;
++ u8 *chan_rx_buf;
++ u8 *chan_tx_buf;
++ u8 *tx_lists[CHAN_TX_LISTS][8];
++ u8 *rx_frames[8][CHAN_TX_LISTS];
++ unsigned int chan_open_count, hdlc_open;
++ unsigned int chan_started, initialized, just_set_offset;
++ unsigned int chan_last_rx, chan_last_tx;
++
++ /* assigned channels, may be invalid with given frame length or mode */
++ u8 channels[MAX_CHANNELS];
++ int msg_count;
++};
++
++/* NPE message structure */
++struct msg {
++#ifdef __ARMEB__
++ u8 cmd, unused, hss_port, index;
++ union {
++ struct { u8 data8a, data8b, data8c, data8d; };
++ struct { u16 data16a, data16b; };
++ struct { u32 data32; };
++ };
++#else
++ u8 index, hss_port, unused, cmd;
++ union {
++ struct { u8 data8d, data8c, data8b, data8a; };
++ struct { u16 data16b, data16a; };
++ struct { u32 data32; };
++ };
++#endif
++};
++
++#define rx_desc_phys(port, n) ((port)->desc_tab_phys + \
++ (n) * sizeof(struct desc))
++#define rx_desc_ptr(port, n) (&(port)->desc_tab[n])
++
++#define tx_desc_phys(port, n) ((port)->desc_tab_phys + \
++ ((n) + RX_DESCS) * sizeof(struct desc))
++#define tx_desc_ptr(port, n) (&(port)->desc_tab[(n) + RX_DESCS])
++
++int hss_prepare_chan(struct port *port);
++void hss_chan_stop(struct port *port);
++
++struct hss_device *hss_init(int id, int channel);
++int hss_chan_open(struct hss_device *hdev);
++int hss_chan_close(struct hss_device *hdev);
++
++int hss_set_tx_callback(struct hss_device *hdev, void (*tx_callback)(void *), void *tx_data);
++int hss_set_rx_callback(struct hss_device *hdev, void (*rx_callback)(void *), void *rx_data);
++int hss_tx_start(struct hss_device *hdev);
++int hss_tx_stop(struct hss_device *hdev);
++int hss_rx_start(struct hss_device *hdev);
++int hss_rx_stop(struct hss_device *hdev);
++
++int hss_config_rx_dma(struct hss_device *hdev, void *buf, size_t buffer_size, size_t period_size);
++int hss_config_tx_dma(struct hss_device *hdev, void *buf, size_t buffer_size, size_t period_size);
++unsigned long hss_curr_offset_rx(struct hss_device *hdev);
++unsigned long hss_curr_offset_tx(struct hss_device *hdev);
++
diff --git a/target/linux/ixp4xx/patches-4.4/180-tw5334_support.patch b/target/linux/ixp4xx/patches-4.4/180-tw5334_support.patch
new file mode 100644
index 0000000000..b56fbb732d
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/180-tw5334_support.patch
@@ -0,0 +1,287 @@
+--- a/arch/arm/mach-ixp4xx/Kconfig
++++ b/arch/arm/mach-ixp4xx/Kconfig
+@@ -160,6 +160,14 @@ config ARCH_PRPMC1100
+ PrPCM1100 Processor Mezanine Module. For more information on
+ this platform, see <file:Documentation/arm/IXP4xx>.
+
++config MACH_TW5334
++ bool "Titan Wireless TW-533-4"
++ select PCI
++ help
++ Say 'Y' here if you want your kernel to support the Titan
++ Wireless TW533-4. For more information on this platform,
++ see http://openwrt.org
++
+ config MACH_NAS100D
+ bool
+ prompt "NAS100D"
+--- a/arch/arm/mach-ixp4xx/Makefile
++++ b/arch/arm/mach-ixp4xx/Makefile
+@@ -24,6 +24,7 @@ obj-pci-$(CONFIG_MACH_SIDEWINDER) += sid
+ obj-pci-$(CONFIG_MACH_COMPEXWP18) += ixdp425-pci.o
+ obj-pci-$(CONFIG_MACH_WRT300NV2) += wrt300nv2-pci.o
+ obj-pci-$(CONFIG_MACH_AP1000) += ixdp425-pci.o
++obj-pci-$(CONFIG_MACH_TW5334) += tw5334-pci.o
+
+ obj-y += common.o
+
+@@ -49,6 +50,7 @@ obj-$(CONFIG_MACH_SIDEWINDER) += sidewin
+ obj-$(CONFIG_MACH_COMPEXWP18) += compex42x-setup.o
+ obj-$(CONFIG_MACH_WRT300NV2) += wrt300nv2-setup.o
+ obj-$(CONFIG_MACH_AP1000) += ap1000-setup.o
++obj-$(CONFIG_MACH_TW5334) += tw5334-setup.o
+
+ obj-$(CONFIG_PCI) += $(obj-pci-$(CONFIG_PCI)) common-pci.o
+ obj-$(CONFIG_IXP4XX_QMGR) += ixp4xx_qmgr.o
+--- a/arch/arm/mach-ixp4xx/include/mach/uncompress.h
++++ b/arch/arm/mach-ixp4xx/include/mach/uncompress.h
+@@ -44,7 +44,7 @@ static __inline__ void __arch_decomp_set
+ machine_is_gateway7001() || machine_is_wg302v2() ||
+ machine_is_devixp() || machine_is_miccpt() || machine_is_mic256() ||
+ machine_is_pronghorn() || machine_is_pronghorn_metro() ||
+- machine_is_wrt300nv2())
++ machine_is_wrt300nv2() || machine_is_tw5334())
+ uart_base = (volatile u32*) IXP4XX_UART2_BASE_PHYS;
+ else
+ uart_base = (volatile u32*) IXP4XX_UART1_BASE_PHYS;
+--- /dev/null
++++ b/arch/arm/mach-ixp4xx/tw5334-pci.c
+@@ -0,0 +1,68 @@
++/*
++ * arch/arch/mach-ixp4xx/tw5334-pci.c
++ *
++ * PCI setup routines for the Titan Wireless TW-533-4
++ *
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * based on coyote-pci.c:
++ * Copyright (C) 2002 Jungo Software Technologies.
++ * Copyright (C) 2003 MontaVista Softwrae, Inc.
++ *
++ * Maintainer: Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/irq.h>
++
++#include <asm/mach-types.h>
++#include <mach/hardware.h>
++
++#include <asm/mach/pci.h>
++
++void __init tw5334_pci_preinit(void)
++{
++ irq_set_irq_type(IRQ_IXP4XX_GPIO6, IRQ_TYPE_LEVEL_LOW);
++ irq_set_irq_type(IRQ_IXP4XX_GPIO2, IRQ_TYPE_LEVEL_LOW);
++ irq_set_irq_type(IRQ_IXP4XX_GPIO1, IRQ_TYPE_LEVEL_LOW);
++ irq_set_irq_type(IRQ_IXP4XX_GPIO0, IRQ_TYPE_LEVEL_LOW);
++
++ ixp4xx_pci_preinit();
++}
++
++static int __init tw5334_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
++{
++ if (slot == 12)
++ return IRQ_IXP4XX_GPIO6;
++ else if (slot == 13)
++ return IRQ_IXP4XX_GPIO2;
++ else if (slot == 14)
++ return IRQ_IXP4XX_GPIO1;
++ else if (slot == 15)
++ return IRQ_IXP4XX_GPIO0;
++ else return -1;
++}
++
++struct hw_pci tw5334_pci __initdata = {
++ .nr_controllers = 1,
++ .preinit = tw5334_pci_preinit,
++ .ops = &ixp4xx_ops,
++ .setup = ixp4xx_setup,
++ .map_irq = tw5334_map_irq,
++};
++
++int __init tw5334_pci_init(void)
++{
++ if (machine_is_tw5334())
++ pci_common_init(&tw5334_pci);
++ return 0;
++}
++
++subsys_initcall(tw5334_pci_init);
+--- /dev/null
++++ b/arch/arm/mach-ixp4xx/tw5334-setup.c
+@@ -0,0 +1,167 @@
++/*
++ * arch/arm/mach-ixp4xx/tw5334-setup.c
++ *
++ * Board setup for the Titan Wireless TW-533-4
++ *
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * based on coyote-setup.c:
++ * Copyright (C) 2003-2005 MontaVista Software, Inc.
++ *
++ * Author: Imre Kaloz <Kaloz@openwrt.org>
++ */
++
++#include <linux/if_ether.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/device.h>
++#include <linux/serial.h>
++#include <linux/tty.h>
++#include <linux/serial_8250.h>
++#include <linux/slab.h>
++
++#include <asm/types.h>
++#include <asm/setup.h>
++#include <asm/memory.h>
++#include <mach/hardware.h>
++#include <asm/irq.h>
++#include <asm/mach-types.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/flash.h>
++
++static struct flash_platform_data tw5334_flash_data = {
++ .map_name = "cfi_probe",
++ .width = 2,
++};
++
++static struct resource tw5334_flash_resource = {
++ .flags = IORESOURCE_MEM,
++};
++
++static struct platform_device tw5334_flash = {
++ .name = "IXP4XX-Flash",
++ .id = 0,
++ .dev = {
++ .platform_data = &tw5334_flash_data,
++ },
++ .num_resources = 1,
++ .resource = &tw5334_flash_resource,
++};
++
++static struct resource tw5334_uart_resource = {
++ .start = IXP4XX_UART2_BASE_PHYS,
++ .end = IXP4XX_UART2_BASE_PHYS + 0x0fff,
++ .flags = IORESOURCE_MEM,
++};
++
++static struct plat_serial8250_port tw5334_uart_data[] = {
++ {
++ .mapbase = IXP4XX_UART2_BASE_PHYS,
++ .membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
++ .irq = IRQ_IXP4XX_UART2,
++ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
++ .iotype = UPIO_MEM,
++ .regshift = 2,
++ .uartclk = IXP4XX_UART_XTAL,
++ },
++ { },
++};
++
++static struct platform_device tw5334_uart = {
++ .name = "serial8250",
++ .id = PLAT8250_DEV_PLATFORM,
++ .dev = {
++ .platform_data = tw5334_uart_data,
++ },
++ .num_resources = 1,
++ .resource = &tw5334_uart_resource,
++};
++
++/* Built-in 10/100 Ethernet MAC interfaces */
++static struct eth_plat_info tw5334_plat_eth[] = {
++ {
++ .phy = 0,
++ .rxq = 3,
++ .txreadyq = 20,
++ }, {
++ .phy = 1,
++ .rxq = 4,
++ .txreadyq = 21,
++ }
++};
++
++static struct platform_device tw5334_eth[] = {
++ {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEB,
++ .dev.platform_data = tw5334_plat_eth,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++ }, {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEC,
++ .dev.platform_data = tw5334_plat_eth + 1,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++ }
++};
++
++static struct platform_device *tw5334_devices[] __initdata = {
++ &tw5334_flash,
++ &tw5334_uart,
++ &tw5334_eth[0],
++ &tw5334_eth[1],
++};
++
++static void __init tw5334_init(void)
++{
++ uint8_t __iomem *f;
++ int i;
++
++ ixp4xx_sys_init();
++
++ tw5334_flash_resource.start = IXP4XX_EXP_BUS_BASE(0);
++ tw5334_flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + SZ_32M - 1;
++
++ *IXP4XX_EXP_CS0 |= IXP4XX_FLASH_WRITABLE;
++ *IXP4XX_EXP_CS1 = *IXP4XX_EXP_CS0;
++
++ platform_add_devices(tw5334_devices, ARRAY_SIZE(tw5334_devices));
++
++ /*
++ * Map in a portion of the flash and read the MAC addresses.
++ * Since it is stored in BE in the flash itself, we need to
++ * byteswap it if we're in LE mode.
++ */
++ f = ioremap(IXP4XX_EXP_BUS_BASE(0), 0x1000000);
++ if (f) {
++ for (i = 0; i < 6; i++) {
++#ifdef __ARMEB__
++ tw5334_plat_eth[0].hwaddr[i] = readb(f + 0xFC0422 + i);
++ tw5334_plat_eth[1].hwaddr[i] = readb(f + 0xFC043B + i);
++#else
++ tw5334_plat_eth[0].hwaddr[i] = readb(f + 0xFC0422 + (i^3));
++ tw5334_plat_eth[1].hwaddr[i] = readb(f + 0xFC043B + (i^3));
++#endif
++ }
++ iounmap(f);
++ }
++
++ printk(KERN_INFO "TW-533-4: Using MAC address %pM for port 0\n",
++ tw5334_plat_eth[0].hwaddr);
++ printk(KERN_INFO "TW-533-4: Using MAC address %pM for port 1\n",
++ tw5334_plat_eth[1].hwaddr);
++}
++
++#ifdef CONFIG_MACH_TW5334
++MACHINE_START(TW5334, "Titan Wireless TW-533-4")
++ /* Maintainer: Imre Kaloz <kaloz@openwrt.org> */
++ .map_io = ixp4xx_map_io,
++ .init_irq = ixp4xx_init_irq,
++ .init_time = ixp4xx_timer_init,
++ .atag_offset = 0x0100,
++ .init_machine = tw5334_init,
++#if defined(CONFIG_PCI)
++ .dma_zone_size = SZ_64M,
++#endif
++ .restart = ixp4xx_restart,
++MACHINE_END
++#endif
diff --git a/target/linux/ixp4xx/patches-4.4/185-mi424wr_support.patch b/target/linux/ixp4xx/patches-4.4/185-mi424wr_support.patch
new file mode 100644
index 0000000000..81713b3cfe
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/185-mi424wr_support.patch
@@ -0,0 +1,507 @@
+--- a/arch/arm/configs/ixp4xx_defconfig
++++ b/arch/arm/configs/ixp4xx_defconfig
+@@ -26,6 +26,7 @@ CONFIG_MACH_NAS100D=y
+ CONFIG_MACH_DSMG600=y
+ CONFIG_MACH_FSG=y
+ CONFIG_MACH_GTWX5715=y
++CONFIG_MACH_MI424WR=y
+ CONFIG_IXP4XX_QMGR=y
+ CONFIG_IXP4XX_NPE=y
+ # CONFIG_ARM_THUMB is not set
+--- a/arch/arm/mach-ixp4xx/Kconfig
++++ b/arch/arm/mach-ixp4xx/Kconfig
+@@ -258,6 +258,13 @@ config MACH_MIC256
+ Say 'Y' here if you want your kernel to support the MIC256
+ board from OMICRON electronics GmbH.
+
++config MACH_MI424WR
++ bool "Actiontec MI424WR"
++ depends on ARCH_IXP4XX
++ select PCI
++ help
++ Add support for the Actiontec MI424-WR.
++
+ comment "IXP4xx Options"
+
+ config IXP4XX_INDIRECT_PCI
+--- a/arch/arm/mach-ixp4xx/Makefile
++++ b/arch/arm/mach-ixp4xx/Makefile
+@@ -25,6 +25,7 @@ obj-pci-$(CONFIG_MACH_COMPEXWP18) += ixd
+ obj-pci-$(CONFIG_MACH_WRT300NV2) += wrt300nv2-pci.o
+ obj-pci-$(CONFIG_MACH_AP1000) += ixdp425-pci.o
+ obj-pci-$(CONFIG_MACH_TW5334) += tw5334-pci.o
++obj-pci-$(CONFIG_MACH_MI424WR) += mi424wr-pci.o
+
+ obj-y += common.o
+
+@@ -51,6 +52,7 @@ obj-$(CONFIG_MACH_COMPEXWP18) += compex4
+ obj-$(CONFIG_MACH_WRT300NV2) += wrt300nv2-setup.o
+ obj-$(CONFIG_MACH_AP1000) += ap1000-setup.o
+ obj-$(CONFIG_MACH_TW5334) += tw5334-setup.o
++obj-$(CONFIG_MACH_MI424WR) += mi424wr-setup.o
+
+ obj-$(CONFIG_PCI) += $(obj-pci-$(CONFIG_PCI)) common-pci.o
+ obj-$(CONFIG_IXP4XX_QMGR) += ixp4xx_qmgr.o
+--- /dev/null
++++ b/arch/arm/mach-ixp4xx/mi424wr-pci.c
+@@ -0,0 +1,70 @@
++/*
++ * arch/arm/mach-ixp4xx/mi424wr-pci.c
++ *
++ * Actiontec MI424WR board-level PCI initialization
++ *
++ * Copyright (C) 2008 Jose Vasconcellos
++ *
++ * Maintainer: Jose Vasconcellos <jvasco@verizon.net>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/irq.h>
++
++#include <asm/mach-types.h>
++#include <asm/mach/pci.h>
++
++/* PCI controller GPIO to IRQ pin mappings
++ * This information was obtained from Actiontec's GPL release.
++ *
++ * INTA INTB
++ * SLOT 13 8 6
++ * SLOT 14 7 8
++ * SLOT 15 6 7
++ */
++
++void __init mi424wr_pci_preinit(void)
++{
++ irq_set_irq_type(IRQ_IXP4XX_GPIO6, IRQ_TYPE_LEVEL_LOW);
++ irq_set_irq_type(IRQ_IXP4XX_GPIO7, IRQ_TYPE_LEVEL_LOW);
++ irq_set_irq_type(IRQ_IXP4XX_GPIO8, IRQ_TYPE_LEVEL_LOW);
++
++ ixp4xx_pci_preinit();
++}
++
++static int __init mi424wr_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
++{
++ if (slot == 13)
++ return IRQ_IXP4XX_GPIO8;
++ if (slot == 14)
++ return IRQ_IXP4XX_GPIO7;
++ if (slot == 15)
++ return IRQ_IXP4XX_GPIO6;
++
++ return -1;
++}
++
++struct hw_pci mi424wr_pci __initdata = {
++ .nr_controllers = 1,
++ .preinit = mi424wr_pci_preinit,
++ .ops = &ixp4xx_ops,
++ .setup = ixp4xx_setup,
++ .map_irq = mi424wr_map_irq,
++};
++
++int __init mi424wr_pci_init(void)
++{
++ if (machine_is_mi424wr())
++ pci_common_init(&mi424wr_pci);
++ return 0;
++}
++
++subsys_initcall(mi424wr_pci_init);
++
+--- /dev/null
++++ b/arch/arm/mach-ixp4xx/mi424wr-setup.c
+@@ -0,0 +1,387 @@
++/*
++ * arch/arm/mach-ixp4xx/mi424wr-setup.c
++ *
++ * Actiontec MI424-WR board setup
++ * Copyright (c) 2008 Jose Vasconcellos
++ *
++ * Based on Gemtek GTWX5715 by
++ * Copyright (C) 2004 George T. Joseph
++ * Derived from Coyote
++ *
++ * 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/device.h>
++#include <linux/serial.h>
++#include <linux/serial_8250.h>
++#include <linux/types.h>
++#include <linux/memory.h>
++#include <linux/leds.h>
++#include <linux/spi/spi_gpio_old.h>
++#include <linux/dma-mapping.h>
++
++#include <asm/setup.h>
++#include <asm/system_info.h>
++#include <asm/irq.h>
++#include <asm/io.h>
++#include <asm/mach-types.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/flash.h>
++
++/*
++ * GPIO 2,3,4 and 9 are hard wired to the Micrel/Kendin KS8995M Switch
++ * and operate as an SPI type interface. The details of the interface
++ * are available on Kendin/Micrel's web site.
++ */
++
++#define MI424WR_KSSPI_SELECT 9
++#define MI424WR_KSSPI_TXD 4
++#define MI424WR_KSSPI_CLOCK 2
++#define MI424WR_KSSPI_RXD 3
++
++/*
++ * The "reset" button is wired to GPIO 10.
++ * The GPIO is brought "low" when the button is pushed.
++ */
++
++#define MI424WR_BUTTON_GPIO 10
++#define MI424WR_BUTTON_IRQ IRQ_IXP4XX_GPIO10
++
++#define MI424WR_MOCA_WAN_LED 11
++
++/* Latch on CS1 - taken from Actiontec's 2.4 source code
++ *
++ * default latch value
++ * 0 - power alarm led (red) 0 (off)
++ * 1 - power led (green) 0 (off)
++ * 2 - wireless led (green) 1 (off)
++ * 3 - no internet led (red) 0 (off)
++ * 4 - internet ok led (green) 0 (off)
++ * 5 - moca LAN 0 (off)
++ * 6 - WAN alarm led (red) 0 (off)
++ * 7 - PCI reset 1 (not reset)
++ * 8 - IP phone 1 led (green) 1 (off)
++ * 9 - IP phone 2 led (green) 1 (off)
++ * 10 - VOIP ready led (green) 1 (off)
++ * 11 - PSTN relay 1 control 0 (PSTN)
++ * 12 - PSTN relay 1 control 0 (PSTN)
++ * 13 - N/A
++ * 14 - N/A
++ * 15 - N/A
++ */
++
++#define MI424WR_LATCH_MASK 0x04
++#define MI424WR_LATCH_DEFAULT 0x1f86
++
++#define MI424WR_LATCH_ALARM_LED 0x00
++#define MI424WR_LATCH_POWER_LED 0x01
++#define MI424WR_LATCH_WIRELESS_LED 0x02
++#define MI424WR_LATCH_INET_DOWN_LED 0x03
++#define MI424WR_LATCH_INET_OK_LED 0x04
++#define MI424WR_LATCH_MOCA_LAN_LED 0x05
++#define MI424WR_LATCH_WAN_ALARM_LED 0x06
++#define MI424WR_LATCH_PCI_RESET 0x07
++#define MI424WR_LATCH_PHONE1_LED 0x08
++#define MI424WR_LATCH_PHONE2_LED 0x09
++#define MI424WR_LATCH_VOIP_LED 0x10
++#define MI424WR_LATCH_PSTN_RELAY1 0x11
++#define MI424WR_LATCH_PSTN_RELAY2 0x12
++
++/* initialize CS1 to default timings, Intel style, 16-bit bus */
++#define MI424WR_CS1_CONFIG 0x80000002
++
++/* Define both UARTs but they are not easily accessible.
++ */
++
++static struct resource mi424wr_uart_resources[] = {
++ {
++ .start = IXP4XX_UART1_BASE_PHYS,
++ .end = IXP4XX_UART1_BASE_PHYS + 0x0fff,
++ .flags = IORESOURCE_MEM,
++ },
++ {
++ .start = IXP4XX_UART2_BASE_PHYS,
++ .end = IXP4XX_UART2_BASE_PHYS + 0x0fff,
++ .flags = IORESOURCE_MEM,
++ }
++};
++
++
++static struct plat_serial8250_port mi424wr_uart_platform_data[] = {
++ {
++ .mapbase = IXP4XX_UART1_BASE_PHYS,
++ .membase = (char *)IXP4XX_UART1_BASE_VIRT + REG_OFFSET,
++ .irq = IRQ_IXP4XX_UART1,
++ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
++ .iotype = UPIO_MEM,
++ .regshift = 2,
++ .uartclk = IXP4XX_UART_XTAL,
++ },
++ {
++ .mapbase = IXP4XX_UART2_BASE_PHYS,
++ .membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
++ .irq = IRQ_IXP4XX_UART2,
++ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
++ .iotype = UPIO_MEM,
++ .regshift = 2,
++ .uartclk = IXP4XX_UART_XTAL,
++ },
++ { },
++};
++
++static struct platform_device mi424wr_uart_device = {
++ .name = "serial8250",
++ .id = PLAT8250_DEV_PLATFORM,
++ .dev.platform_data = mi424wr_uart_platform_data,
++ .num_resources = ARRAY_SIZE(mi424wr_uart_resources),
++ .resource = mi424wr_uart_resources,
++};
++
++static struct flash_platform_data mi424wr_flash_data = {
++ .map_name = "cfi_probe",
++ .width = 2,
++};
++
++static struct resource mi424wr_flash_resource = {
++ .flags = IORESOURCE_MEM,
++};
++
++static struct platform_device mi424wr_flash = {
++ .name = "IXP4XX-Flash",
++ .id = 0,
++ .dev.platform_data = &mi424wr_flash_data,
++ .num_resources = 1,
++ .resource = &mi424wr_flash_resource,
++};
++
++static int mi424wr_spi_boardinfo_setup(struct spi_board_info *bi,
++ struct spi_master *master, void *data)
++{
++
++ strlcpy(bi->modalias, "spi-ks8995", sizeof(bi->modalias));
++
++ bi->max_speed_hz = 5000000 /* Hz */;
++ bi->bus_num = master->bus_num;
++ bi->mode = SPI_MODE_0;
++
++ return 0;
++}
++
++static struct spi_gpio_platform_data mi424wr_spi_bus_data = {
++ .pin_cs = MI424WR_KSSPI_SELECT,
++ .pin_clk = MI424WR_KSSPI_CLOCK,
++ .pin_miso = MI424WR_KSSPI_RXD,
++ .pin_mosi = MI424WR_KSSPI_TXD,
++ .cs_activelow = 1,
++ .no_spi_delay = 1,
++ .boardinfo_setup = mi424wr_spi_boardinfo_setup,
++};
++
++static struct gpio_led mi424wr_gpio_led[] = {
++ {
++ .name = "moca-wan", /* green led */
++ .gpio = MI424WR_MOCA_WAN_LED,
++ .active_low = 0,
++ }
++};
++
++static struct gpio_led_platform_data mi424wr_gpio_leds_data = {
++ .num_leds = 1,
++ .leds = mi424wr_gpio_led,
++};
++
++static struct platform_device mi424wr_gpio_leds = {
++ .name = "leds-gpio",
++ .id = -1,
++ .dev.platform_data = &mi424wr_gpio_leds_data,
++};
++
++static uint16_t latch_value = MI424WR_LATCH_DEFAULT;
++static uint16_t __iomem *iobase;
++
++static void mi424wr_latch_set_led(u8 bit, enum led_brightness value)
++{
++
++ if (((MI424WR_LATCH_MASK >> bit) & 1) ^ (value == LED_OFF))
++ latch_value &= ~(0x1 << bit);
++ else
++ latch_value |= (0x1 << bit);
++
++ __raw_writew(latch_value, iobase);
++
++}
++
++static struct latch_led mi424wr_latch_led[] = {
++ {
++ .name = "power-alarm",
++ .bit = MI424WR_LATCH_ALARM_LED,
++ },
++ {
++ .name = "power-ok",
++ .bit = MI424WR_LATCH_POWER_LED,
++ },
++ {
++ .name = "wireless", /* green led */
++ .bit = MI424WR_LATCH_WIRELESS_LED,
++ },
++ {
++ .name = "inet-down", /* red led */
++ .bit = MI424WR_LATCH_INET_DOWN_LED,
++ },
++ {
++ .name = "inet-up", /* green led */
++ .bit = MI424WR_LATCH_INET_OK_LED,
++ },
++ {
++ .name = "moca-lan", /* green led */
++ .bit = MI424WR_LATCH_MOCA_LAN_LED,
++ },
++ {
++ .name = "wan-alarm", /* red led */
++ .bit = MI424WR_LATCH_WAN_ALARM_LED,
++ }
++};
++
++static struct latch_led_platform_data mi424wr_latch_leds_data = {
++ .num_leds = ARRAY_SIZE(mi424wr_latch_led),
++ .mem = 0x51000000,
++ .leds = mi424wr_latch_led,
++ .set_led = mi424wr_latch_set_led,
++};
++
++static struct platform_device mi424wr_latch_leds = {
++ .name = "leds-latch",
++ .id = -1,
++ .dev.platform_data = &mi424wr_latch_leds_data,
++};
++
++static struct platform_device mi424wr_spi_bus = {
++ .name = "spi-gpio",
++ .id = 0,
++ .dev.platform_data = &mi424wr_spi_bus_data,
++};
++
++static struct eth_plat_info mi424wr_wan_data = {
++ .phy = 17, /* KS8721 */
++ .rxq = 3,
++ .txreadyq = 20,
++};
++
++static struct eth_plat_info mi424wr_lan_data = {
++ .phy = IXP4XX_ETH_PHY_MAX_ADDR,
++ .phy_mask = 0x1e, /* ports 1-4 of the KS8995 switch */
++ .rxq = 4,
++ .txreadyq = 21,
++};
++
++static struct platform_device mi424wr_npe_devices[] = {
++ {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEC,
++ .dev.platform_data = &mi424wr_lan_data,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++ }, {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEB,
++ .dev.platform_data = &mi424wr_wan_data,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++ }
++};
++
++static struct eth_plat_info mi424wr_wanD_data = {
++ .phy = 5,
++ .rxq = 4,
++ .txreadyq = 21,
++};
++
++static struct eth_plat_info mi424wr_lanD_data = {
++ .phy = IXP4XX_ETH_PHY_MAX_ADDR,
++ .phy_mask = 0x1e, /* ports 1-4 of the KS8995 switch */
++ .rxq = 3,
++ .txreadyq = 20,
++};
++
++static struct platform_device mi424wr_npeD_devices[] = {
++ {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEB,
++ .dev.platform_data = &mi424wr_lanD_data,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++ }, {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEC,
++ .dev.platform_data = &mi424wr_wanD_data,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++ }
++};
++
++static struct platform_device *mi424wr_devices[] __initdata = {
++ &mi424wr_uart_device,
++ &mi424wr_flash,
++ &mi424wr_gpio_leds,
++ &mi424wr_latch_leds,
++ &mi424wr_spi_bus,
++};
++
++static void __init mi424wr_init(void)
++{
++ ixp4xx_sys_init();
++
++ mi424wr_flash_resource.start = IXP4XX_EXP_BUS_BASE(0);
++ mi424wr_flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + SZ_8M - 1;
++
++ *IXP4XX_EXP_CS0 |= IXP4XX_FLASH_WRITABLE;
++ *IXP4XX_EXP_CS1 = MI424WR_CS1_CONFIG;
++
++ /* configure button as input
++ */
++ gpio_line_config(MI424WR_BUTTON_GPIO, IXP4XX_GPIO_IN);
++
++ /* Initialize LEDs and enables PCI bus.
++ */
++ iobase = ioremap_nocache(IXP4XX_EXP_BUS_BASE(1), 0x1000);
++ __raw_writew(latch_value, iobase);
++
++ platform_add_devices(mi424wr_devices, ARRAY_SIZE(mi424wr_devices));
++
++ /* Need to figure out how to detect revD.
++ * Look for a revision argument sent by redboot.
++ */
++#define revD 4
++ if (system_rev == revD) {
++ platform_device_register(&mi424wr_npeD_devices[0]);
++ platform_device_register(&mi424wr_npeD_devices[1]);
++ } else {
++ platform_device_register(&mi424wr_npe_devices[0]);
++ platform_device_register(&mi424wr_npe_devices[1]);
++ }
++}
++
++
++MACHINE_START(MI424WR, "Actiontec MI424WR")
++ /* Maintainer: Jose Vasconcellos */
++ .map_io = ixp4xx_map_io,
++ .init_irq = ixp4xx_init_irq,
++ .init_time = ixp4xx_timer_init,
++ .atag_offset = 0x0100,
++ .init_machine = mi424wr_init,
++#if defined(CONFIG_PCI)
++ .dma_zone_size = SZ_64M,
++#endif
++ .restart = ixp4xx_restart,
++MACHINE_END
++
diff --git a/target/linux/ixp4xx/patches-4.4/190-cambria_support.patch b/target/linux/ixp4xx/patches-4.4/190-cambria_support.patch
new file mode 100644
index 0000000000..d6787f4e99
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/190-cambria_support.patch
@@ -0,0 +1,1131 @@
+--- a/arch/arm/mach-ixp4xx/Kconfig
++++ b/arch/arm/mach-ixp4xx/Kconfig
+@@ -21,6 +21,14 @@ config MACH_AVILA
+ Avila Network Platform. For more information on this platform,
+ see <file:Documentation/arm/IXP4xx>.
+
++config MACH_CAMBRIA
++ bool "Cambria"
++ select PCI
++ help
++ Say 'Y' here if you want your kernel to support the Gateworks
++ Cambria series. For more information on this platform,
++ see <file:Documentation/arm/IXP4xx>.
++
+ config MACH_LOFT
+ bool "Loft"
+ depends on MACH_AVILA
+@@ -218,7 +226,7 @@ config CPU_IXP46X
+
+ config CPU_IXP43X
+ bool
+- depends on MACH_KIXRP435
++ depends on MACH_KIXRP435 || MACH_CAMBRIA
+ default y
+
+ config MACH_GTWX5715
+--- a/arch/arm/mach-ixp4xx/Makefile
++++ b/arch/arm/mach-ixp4xx/Makefile
+@@ -7,6 +7,7 @@ obj-pci-n :=
+
+ obj-pci-$(CONFIG_ARCH_IXDP4XX) += ixdp425-pci.o
+ obj-pci-$(CONFIG_MACH_AVILA) += avila-pci.o
++obj-pci-$(CONFIG_MACH_CAMBRIA) += cambria-pci.o
+ obj-pci-$(CONFIG_MACH_IXDPG425) += ixdpg425-pci.o
+ obj-pci-$(CONFIG_ARCH_ADI_COYOTE) += coyote-pci.o
+ obj-pci-$(CONFIG_MACH_GTWX5715) += gtwx5715-pci.o
+@@ -31,6 +32,7 @@ obj-y += common.o
+
+ obj-$(CONFIG_ARCH_IXDP4XX) += ixdp425-setup.o
+ obj-$(CONFIG_MACH_AVILA) += avila-setup.o
++obj-$(CONFIG_MACH_CAMBRIA) += cambria-setup.o
+ obj-$(CONFIG_MACH_IXDPG425) += coyote-setup.o
+ obj-$(CONFIG_ARCH_ADI_COYOTE) += coyote-setup.o
+ obj-$(CONFIG_MACH_GTWX5715) += gtwx5715-setup.o
+--- /dev/null
++++ b/arch/arm/mach-ixp4xx/cambria-pci.c
+@@ -0,0 +1,78 @@
++/*
++ * arch/arch/mach-ixp4xx/cambria-pci.c
++ *
++ * PCI setup routines for Gateworks Cambria series
++ *
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * based on coyote-pci.c:
++ * Copyright (C) 2002 Jungo Software Technologies.
++ * Copyright (C) 2003 MontaVista Softwrae, Inc.
++ *
++ * Maintainer: Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/irq.h>
++
++#include <asm/mach-types.h>
++#include <mach/hardware.h>
++#include <asm/irq.h>
++
++#include <asm/mach/pci.h>
++
++extern void ixp4xx_pci_preinit(void);
++extern int ixp4xx_setup(int nr, struct pci_sys_data *sys);
++extern struct pci_bus *ixp4xx_scan_bus(int nr, struct pci_sys_data *sys);
++
++void __init cambria_pci_preinit(void)
++{
++ irq_set_irq_type(IRQ_IXP4XX_GPIO11, IRQ_TYPE_LEVEL_LOW);
++ irq_set_irq_type(IRQ_IXP4XX_GPIO10, IRQ_TYPE_LEVEL_LOW);
++ irq_set_irq_type(IRQ_IXP4XX_GPIO9, IRQ_TYPE_LEVEL_LOW);
++ irq_set_irq_type(IRQ_IXP4XX_GPIO8, IRQ_TYPE_LEVEL_LOW);
++
++ ixp4xx_pci_preinit();
++}
++
++static int __init cambria_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
++{
++ if (slot == 1)
++ return IRQ_IXP4XX_GPIO11;
++ else if (slot == 2)
++ return IRQ_IXP4XX_GPIO10;
++ else if (slot == 3)
++ return IRQ_IXP4XX_GPIO9;
++ else if (slot == 4)
++ return IRQ_IXP4XX_GPIO8;
++ else if (slot == 6)
++ return IRQ_IXP4XX_GPIO10;
++ else if (slot == 15)
++ return IRQ_IXP4XX_GPIO8;
++
++ else return -1;
++}
++
++struct hw_pci cambria_pci __initdata = {
++ .nr_controllers = 1,
++ .preinit = cambria_pci_preinit,
++ .ops = &ixp4xx_ops,
++ .setup = ixp4xx_setup,
++ .map_irq = cambria_map_irq,
++};
++
++int __init cambria_pci_init(void)
++{
++ if (machine_is_cambria())
++ pci_common_init(&cambria_pci);
++ return 0;
++}
++
++subsys_initcall(cambria_pci_init);
+--- /dev/null
++++ b/arch/arm/mach-ixp4xx/cambria-setup.c
+@@ -0,0 +1,1003 @@
++/*
++ * arch/arm/mach-ixp4xx/cambria-setup.c
++ *
++ * Board setup for the Gateworks Cambria series
++ *
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ * Copyright (C) 2012 Gateworks Corporation <support@gateworks.com>
++ *
++ * based on coyote-setup.c:
++ * Copyright (C) 2003-2005 MontaVista Software, Inc.
++ *
++ * Author: Imre Kaloz <kaloz@openwrt.org>
++ * Tim Harvey <tharvey@gateworks.com>
++ */
++
++#include <linux/device.h>
++#include <linux/gpio_keys.h>
++#include <linux/gpio.h>
++#include <linux/i2c.h>
++#include <linux/i2c-gpio.h>
++#include <linux/platform_data/at24.h>
++#include <linux/i2c/gw_i2c_pld.h>
++#include <linux/platform_data/pca953x.h>
++#include <linux/if_ether.h>
++#include <linux/init.h>
++#include <linux/input.h>
++#include <linux/kernel.h>
++#include <linux/leds.h>
++#include <linux/memory.h>
++#include <linux/netdevice.h>
++#include <linux/serial.h>
++#include <linux/serial_8250.h>
++#include <linux/slab.h>
++#include <linux/socket.h>
++#include <linux/types.h>
++#include <linux/tty.h>
++#include <linux/irq.h>
++#include <linux/usb/ehci_pdriver.h>
++
++#include <mach/hardware.h>
++#include <asm/irq.h>
++#include <asm/mach-types.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/flash.h>
++#include <asm/setup.h>
++
++#define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x)
++
++struct cambria_board_info {
++ unsigned char *model;
++ void (*setup)(void);
++};
++
++static struct cambria_board_info *cambria_info __initdata;
++
++static struct flash_platform_data cambria_flash_data = {
++ .map_name = "cfi_probe",
++ .width = 2,
++};
++
++static struct resource cambria_flash_resource = {
++ .flags = IORESOURCE_MEM,
++};
++
++static struct platform_device cambria_flash = {
++ .name = "IXP4XX-Flash",
++ .id = 0,
++ .dev = {
++ .platform_data = &cambria_flash_data,
++ },
++ .num_resources = 1,
++ .resource = &cambria_flash_resource,
++};
++
++static struct i2c_gpio_platform_data cambria_i2c_gpio_data = {
++ .sda_pin = 7,
++ .scl_pin = 6,
++};
++
++static struct platform_device cambria_i2c_gpio = {
++ .name = "i2c-gpio",
++ .id = 0,
++ .dev = {
++ .platform_data = &cambria_i2c_gpio_data,
++ },
++};
++
++#ifdef SFP_SERIALID
++static struct i2c_gpio_platform_data cambria_i2c_gpio_sfpa_data = {
++ .sda_pin = 113,
++ .scl_pin = 112,
++ .sda_is_open_drain = 0,
++ .scl_is_open_drain = 0,
++};
++
++static struct platform_device cambria_i2c_gpio_sfpa = {
++ .name = "i2c-gpio",
++ .id = 1,
++ .dev = {
++ .platform_data = &cambria_i2c_gpio_sfpa_data,
++ },
++};
++
++static struct i2c_gpio_platform_data cambria_i2c_gpio_sfpb_data = {
++ .sda_pin = 115,
++ .scl_pin = 114,
++ .sda_is_open_drain = 0,
++ .scl_is_open_drain = 0,
++};
++
++static struct platform_device cambria_i2c_gpio_sfpb = {
++ .name = "i2c-gpio",
++ .id = 2,
++ .dev = {
++ .platform_data = &cambria_i2c_gpio_sfpb_data,
++ },
++};
++#endif // #ifdef SFP_SERIALID
++
++static struct eth_plat_info cambria_npec_data = {
++ .phy = 1,
++ .rxq = 4,
++ .txreadyq = 21,
++};
++
++static struct eth_plat_info cambria_npea_data = {
++ .phy = 2,
++ .rxq = 2,
++ .txreadyq = 19,
++};
++
++static struct platform_device cambria_npec_device = {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEC,
++ .dev.platform_data = &cambria_npec_data,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++};
++
++static struct platform_device cambria_npea_device = {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEA,
++ .dev.platform_data = &cambria_npea_data,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++};
++
++static struct resource cambria_uart_resource = {
++ .start = IXP4XX_UART1_BASE_PHYS,
++ .end = IXP4XX_UART1_BASE_PHYS + 0x0fff,
++ .flags = IORESOURCE_MEM,
++};
++
++static struct plat_serial8250_port cambria_uart_data[] = {
++ {
++ .mapbase = IXP4XX_UART1_BASE_PHYS,
++ .membase = (char *)IXP4XX_UART1_BASE_VIRT + REG_OFFSET,
++ .irq = IRQ_IXP4XX_UART1,
++ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
++ .iotype = UPIO_MEM,
++ .regshift = 2,
++ .uartclk = IXP4XX_UART_XTAL,
++ },
++ { },
++};
++
++static struct platform_device cambria_uart = {
++ .name = "serial8250",
++ .id = PLAT8250_DEV_PLATFORM,
++ .dev = {
++ .platform_data = cambria_uart_data,
++ },
++ .num_resources = 1,
++ .resource = &cambria_uart_resource,
++};
++
++static struct resource cambria_optional_uart_resources[] = {
++ {
++ .start = 0x52000000,
++ .end = 0x52000fff,
++ .flags = IORESOURCE_MEM
++ },
++ {
++ .start = 0x53000000,
++ .end = 0x53000fff,
++ .flags = IORESOURCE_MEM
++ },
++ {
++ .start = 0x52000000,
++ .end = 0x52000fff,
++ .flags = IORESOURCE_MEM
++ },
++ {
++ .start = 0x52000000,
++ .end = 0x52000fff,
++ .flags = IORESOURCE_MEM
++ },
++ {
++ .start = 0x52000000,
++ .end = 0x52000fff,
++ .flags = IORESOURCE_MEM
++ },
++ {
++ .start = 0x52000000,
++ .end = 0x52000fff,
++ .flags = IORESOURCE_MEM
++ },
++ {
++ .start = 0x52000000,
++ .end = 0x52000fff,
++ .flags = IORESOURCE_MEM
++ },
++ {
++ .start = 0x53000000,
++ .end = 0x53000fff,
++ .flags = IORESOURCE_MEM
++ }
++};
++
++static struct plat_serial8250_port cambria_optional_uart_data[] = {
++ {
++ .flags = UPF_BOOT_AUTOCONF,
++ .iotype = UPIO_MEM_DELAY,
++ .regshift = 0,
++ .uartclk = 1843200,
++ .rw_delay = 10,
++ },
++ {
++ .flags = UPF_BOOT_AUTOCONF,
++ .iotype = UPIO_MEM_DELAY,
++ .regshift = 0,
++ .uartclk = 1843200,
++ .rw_delay = 10,
++ },
++ {
++ .flags = UPF_BOOT_AUTOCONF,
++ .iotype = UPIO_MEM,
++ .regshift = 0,
++ .uartclk = 18432000,
++ },
++ {
++ .flags = UPF_BOOT_AUTOCONF,
++ .iotype = UPIO_MEM,
++ .regshift = 0,
++ .uartclk = 18432000,
++ },
++ {
++ .flags = UPF_BOOT_AUTOCONF,
++ .iotype = UPIO_MEM,
++ .regshift = 0,
++ .uartclk = 18432000,
++ },
++ {
++ .flags = UPF_BOOT_AUTOCONF,
++ .iotype = UPIO_MEM,
++ .regshift = 0,
++ .uartclk = 18432000,
++ },
++ {
++ .flags = UPF_BOOT_AUTOCONF,
++ .iotype = UPIO_MEM,
++ .regshift = 0,
++ .uartclk = 18432000,
++ },
++ { },
++};
++
++static struct platform_device cambria_optional_uart = {
++ .name = "serial8250",
++ .id = PLAT8250_DEV_PLATFORM1,
++ .dev.platform_data = cambria_optional_uart_data,
++ .num_resources = 2,
++ .resource = cambria_optional_uart_resources,
++};
++
++static struct resource cambria_pata_resources[] = {
++ {
++ .flags = IORESOURCE_MEM
++ },
++ {
++ .flags = IORESOURCE_MEM,
++ },
++ {
++ .name = "intrq",
++ .start = IRQ_IXP4XX_GPIO12,
++ .end = IRQ_IXP4XX_GPIO12,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct ixp4xx_pata_data cambria_pata_data = {
++ .cs0_bits = 0xbfff3c03,
++ .cs1_bits = 0xbfff3c03,
++};
++
++static struct platform_device cambria_pata = {
++ .name = "pata_ixp4xx_cf",
++ .id = 0,
++ .dev.platform_data = &cambria_pata_data,
++ .num_resources = ARRAY_SIZE(cambria_pata_resources),
++ .resource = cambria_pata_resources,
++};
++
++static struct gpio_led cambria_gpio_leds[] = {
++ {
++ .name = "user",
++ .gpio = 5,
++ .active_low = 1,
++ },
++ {
++ .name = "user2",
++ .gpio = 0,
++ .active_low = 1,
++ },
++ {
++ .name = "user3",
++ .gpio = 0,
++ .active_low = 1,
++ },
++ {
++ .name = "user4",
++ .gpio = 0,
++ .active_low = 1,
++ }
++};
++
++static struct gpio_led_platform_data cambria_gpio_leds_data = {
++ .num_leds = 1,
++ .leds = cambria_gpio_leds,
++};
++
++static struct platform_device cambria_gpio_leds_device = {
++ .name = "leds-gpio",
++ .id = -1,
++ .dev.platform_data = &cambria_gpio_leds_data,
++};
++
++static struct resource cambria_gpio_resources[] = {
++ {
++ .name = "gpio",
++ .flags = 0,
++ },
++};
++
++static struct gpio cambria_gpios_gw2350[] = {
++ // ARM GPIO
++#if 0 // configured from bootloader
++ { 0, GPIOF_IN, "ARM_DIO0" },
++ { 1, GPIOF_IN, "ARM_DIO1" },
++ { 2, GPIOF_IN, "ARM_DIO2" },
++ { 3, GPIOF_IN, "ARM_DIO3" },
++ { 4, GPIOF_IN, "ARM_DIO4" },
++ { 5, GPIOF_IN, "ARM_DIO5" },
++ { 12, GPIOF_OUT_INIT_HIGH, "WDOGEN#" },
++#endif
++ { 8, GPIOF_IN, "ARM_DIO8" },
++ { 9, GPIOF_IN, "ARM_DIO9" },
++};
++
++static struct gpio cambria_gpios_gw2358[] = {
++ // ARM GPIO
++#if 0 // configured from bootloader
++ { 0, GPIOF_IN, "*VINLOW#" },
++ { 2, GPIOF_IN, "*GPS_PPS" },
++ { 3, GPIOF_IN, "*GPS_IRQ#" },
++ { 4, GPIOF_IN, "*RS485_IRQ#" },
++ { 5, GPIOF_IN, "*SER_EN#" },
++ { 14, GPIOF_OUT_INIT_HIGH, "*WDOGEN#" },
++#endif
++};
++
++static struct gpio cambria_gpios_gw2359[] = {
++ // ARM GPIO
++#if 0 // configured from bootloader
++ { 0, GPIOF_IN, "*PCA_IRQ#" },
++ { 1, GPIOF_IN, "ARM_DIO1" },
++ { 2, GPIOF_IN, "ARM_DIO2" },
++ { 3, GPIOF_IN, "ARM_DIO3" },
++ { 4, GPIOF_IN, "ARM_DIO4" },
++ { 5, GPIOF_IN, "ARM_DIO5" },
++ { 8, GPIOF_OUT_INIT_HIGH, "*WDOGEN#" },
++#endif
++ { 11, GPIOF_OUT_INIT_HIGH, "*SER_EN" }, // console serial enable
++ { 12, GPIOF_IN, "*GSC_IRQ#" },
++ { 13, GPIOF_OUT_INIT_HIGH, "*PCIE_RST#"},
++ // GSC GPIO
++#if !(IS_ENABLED(CONFIG_KEYBOARD_GPIO_POLLED))
++ {100, GPIOF_IN, "*USER_PB#" },
++#endif
++ {103, GPIOF_OUT_INIT_HIGH, "*5V_EN" }, // 5V aux supply enable
++ {108, GPIOF_IN, "*SMUXDA0" },
++ {109, GPIOF_IN, "*SMUXDA1" },
++ {110, GPIOF_IN, "*SMUXDA2" },
++ {111, GPIOF_IN, "*SMUXDB0" },
++ {112, GPIOF_IN, "*SMUXDB1" },
++ {113, GPIOF_IN, "*SMUXDB2" },
++ // PCA GPIO
++ {118, GPIOF_IN, "*USIM2_DET#"}, // USIM2 Detect
++ {120, GPIOF_OUT_INIT_LOW, "*USB1_PCI_SEL"}, // USB1 Select (1=PCI, 0=FP)
++ {121, GPIOF_OUT_INIT_LOW, "*USB2_PCI_SEL"}, // USB2 Select (1=PCI, 0=FP)
++ {122, GPIOF_IN, "*USIM1_DET#"}, // USIM1 Detect
++ {123, GPIOF_OUT_INIT_HIGH, "*COM1_DTR#" }, // J21/J10
++ {124, GPIOF_IN, "*COM1_DSR#" }, // J21/J10
++ {127, GPIOF_IN, "PCA_DIO0" },
++ {128, GPIOF_IN, "PCA_DIO1" },
++ {129, GPIOF_IN, "PCA_DIO2" },
++ {130, GPIOF_IN, "PCA_DIO3" },
++ {131, GPIOF_IN, "PCA_DIO4" },
++};
++
++static struct gpio cambria_gpios_gw2360[] = {
++ // ARM GPIO
++ { 0, GPIOF_IN, "*PCA_IRQ#" },
++ { 11, GPIOF_OUT_INIT_LOW, "*SER0_EN#" },
++ { 12, GPIOF_IN, "*GSC_IRQ#" },
++ { 13, GPIOF_OUT_INIT_HIGH, "*PCIE_RST#"},
++ // GSC GPIO
++#if !(IS_ENABLED(CONFIG_KEYBOARD_GPIO_POLLED))
++ {100, GPIOF_IN, "*USER_PB#" },
++#endif
++ {108, GPIOF_OUT_INIT_LOW, "*ENET1_EN#" }, // ENET1 TX Enable
++ {109, GPIOF_IN, "*ENET1_PRES#" }, // ENET1 Detect (0=SFP present)
++ {110, GPIOF_OUT_INIT_LOW, "*ENET2_EN#" }, // ENET2 TX Enable
++ {111, GPIOF_IN, "*ENET2_PRES#"}, // ENET2 Detect (0=SFP present)
++ // PCA GPIO
++ {116, GPIOF_OUT_INIT_HIGH, "*USIM2_LOC"}, // USIM2 Select (1=Loc, 0=Rem)
++ {117, GPIOF_IN, "*USIM2_DET_LOC#" },// USIM2 Detect (Local Slot)
++ {118, GPIOF_IN, "*USIM2_DET_REM#" },// USIM2 Detect (Remote Slot)
++ {120, GPIOF_OUT_INIT_LOW, "*USB1_PCI_SEL"}, // USB1 Select (1=PCIe1, 0=J1)
++ {121, GPIOF_OUT_INIT_LOW, "*USB2_PCI_SEL"}, // USB2 Select (1=PCIe2, 0=J1)
++ {122, GPIOF_IN, "*USIM1_DET#"}, // USIM1 Detect
++ {127, GPIOF_IN, "DIO0" },
++ {128, GPIOF_IN, "DIO1" },
++ {129, GPIOF_IN, "DIO2" },
++ {130, GPIOF_IN, "DIO3" },
++ {131, GPIOF_IN, "DIO4" },
++};
++
++static struct latch_led cambria_latch_leds[] = {
++ {
++ .name = "ledA", /* green led */
++ .bit = 0,
++ },
++ {
++ .name = "ledB", /* green led */
++ .bit = 1,
++ },
++ {
++ .name = "ledC", /* green led */
++ .bit = 2,
++ },
++ {
++ .name = "ledD", /* green led */
++ .bit = 3,
++ },
++ {
++ .name = "ledE", /* green led */
++ .bit = 4,
++ },
++ {
++ .name = "ledF", /* green led */
++ .bit = 5,
++ },
++ {
++ .name = "ledG", /* green led */
++ .bit = 6,
++ },
++ {
++ .name = "ledH", /* green led */
++ .bit = 7,
++ }
++};
++
++static struct latch_led_platform_data cambria_latch_leds_data = {
++ .num_leds = 8,
++ .leds = cambria_latch_leds,
++ .mem = 0x53F40000,
++};
++
++static struct platform_device cambria_latch_leds_device = {
++ .name = "leds-latch",
++ .id = -1,
++ .dev.platform_data = &cambria_latch_leds_data,
++};
++
++static struct resource cambria_usb0_resources[] = {
++ {
++ .start = 0xCD000000,
++ .end = 0xCD000300,
++ .flags = IORESOURCE_MEM,
++ },
++ {
++ .start = 32,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct resource cambria_usb1_resources[] = {
++ {
++ .start = 0xCE000000,
++ .end = 0xCE000300,
++ .flags = IORESOURCE_MEM,
++ },
++ {
++ .start = 33,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static u64 ehci_dma_mask = ~(u32)0;
++
++static struct usb_ehci_pdata cambria_usb_pdata = {
++ .big_endian_desc = 1,
++ .big_endian_mmio = 1,
++ .has_tt = 1,
++ .caps_offset = 0x100,
++};
++
++static struct platform_device cambria_usb0_device = {
++ .name = "ehci-platform",
++ .id = 0,
++ .resource = cambria_usb0_resources,
++ .num_resources = ARRAY_SIZE(cambria_usb0_resources),
++ .dev = {
++ .dma_mask = &ehci_dma_mask,
++ .coherent_dma_mask = 0xffffffff,
++ .platform_data = &cambria_usb_pdata,
++ },
++};
++
++static struct platform_device cambria_usb1_device = {
++ .name = "ehci-platform",
++ .id = 1,
++ .resource = cambria_usb1_resources,
++ .num_resources = ARRAY_SIZE(cambria_usb1_resources),
++ .dev = {
++ .dma_mask = &ehci_dma_mask,
++ .coherent_dma_mask = 0xffffffff,
++ .platform_data = &cambria_usb_pdata,
++ },
++};
++
++static struct gw_i2c_pld_platform_data gw_i2c_pld_data0 = {
++ .gpio_base = 16,
++ .nr_gpio = 8,
++};
++
++static struct gw_i2c_pld_platform_data gw_i2c_pld_data1 = {
++ .gpio_base = 24,
++ .nr_gpio = 2,
++};
++
++
++static struct gpio_keys_button cambria_gpio_buttons[] = {
++ {
++ .desc = "user",
++ .type = EV_KEY,
++ .code = BTN_0,
++ .debounce_interval = 6,
++ .gpio = 25,
++ }
++};
++
++static struct gpio_keys_platform_data cambria_gpio_buttons_data = {
++ .poll_interval = 500,
++ .nbuttons = 1,
++ .buttons = cambria_gpio_buttons,
++};
++
++static struct platform_device cambria_gpio_buttons_device = {
++ .name = "gpio-keys-polled",
++ .id = -1,
++ .dev.platform_data = &cambria_gpio_buttons_data,
++};
++
++static struct platform_device *cambria_devices[] __initdata = {
++ &cambria_i2c_gpio,
++ &cambria_flash,
++ &cambria_uart,
++};
++
++static int cambria_register_gpio(struct gpio *array, size_t num)
++{
++ int i, err, ret;
++
++ ret = 0;
++ for (i = 0; i < num; i++, array++) {
++ const char *label = array->label;
++ if (label[0] == '*')
++ label++;
++ err = gpio_request_one(array->gpio, array->flags, label);
++ if (err)
++ ret = err;
++ else {
++ err = gpio_export(array->gpio, array->label[0] != '*');
++ }
++ }
++ return ret;
++}
++
++static void __init cambria_gw23xx_setup(void)
++{
++ cambria_gpio_resources[0].start = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) |\
++ (1 << 5) | (1 << 8) | (1 << 9) | (1 << 12);
++ cambria_gpio_resources[0].end = cambria_gpio_resources[0].start;
++
++ platform_device_register(&cambria_npec_device);
++ platform_device_register(&cambria_npea_device);
++}
++
++static void __init cambria_gw2350_setup(void)
++{
++ *IXP4XX_EXP_CS2 = 0xBFFF3C43;
++ irq_set_irq_type(IRQ_IXP4XX_GPIO3, IRQ_TYPE_EDGE_RISING);
++ cambria_optional_uart_data[0].mapbase = 0x52FF0000;
++ cambria_optional_uart_data[0].membase = (void __iomem *)ioremap(0x52FF0000, 0x0fff);
++ cambria_optional_uart_data[0].irq = IRQ_IXP4XX_GPIO3;
++
++ *IXP4XX_EXP_CS3 = 0xBFFF3C43;
++ irq_set_irq_type(IRQ_IXP4XX_GPIO4, IRQ_TYPE_EDGE_RISING);
++ cambria_optional_uart_data[1].mapbase = 0x53FF0000;
++ cambria_optional_uart_data[1].membase = (void __iomem *)ioremap(0x53FF0000, 0x0fff);
++ cambria_optional_uart_data[1].irq = IRQ_IXP4XX_GPIO4;
++
++ cambria_gpio_resources[0].start = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) |\
++ (1 << 5) | (1 << 8) | (1 << 9) | (1 << 12);
++ cambria_gpio_resources[0].end = cambria_gpio_resources[0].start;
++
++ platform_device_register(&cambria_optional_uart);
++ platform_device_register(&cambria_npec_device);
++ platform_device_register(&cambria_npea_device);
++
++ platform_device_register(&cambria_usb0_device);
++ platform_device_register(&cambria_usb1_device);
++
++ platform_device_register(&cambria_gpio_leds_device);
++
++ /* gpio config (/sys/class/gpio) */
++ cambria_register_gpio(ARRAY_AND_SIZE(cambria_gpios_gw2350));
++}
++
++static void __init cambria_gw2358_setup(void)
++{
++ *IXP4XX_EXP_CS3 = 0xBFFF3C43; // bit0 = 16bit vs 8bit bus
++ irq_set_irq_type(IRQ_IXP4XX_GPIO3, IRQ_TYPE_EDGE_RISING);
++ cambria_optional_uart_data[0].mapbase = 0x53FC0000;
++ cambria_optional_uart_data[0].membase = (void __iomem *)ioremap(0x53FC0000, 0x0fff);
++ cambria_optional_uart_data[0].irq = IRQ_IXP4XX_GPIO3;
++
++ irq_set_irq_type(IRQ_IXP4XX_GPIO4, IRQ_TYPE_EDGE_RISING);
++ cambria_optional_uart_data[1].mapbase = 0x53F80000;
++ cambria_optional_uart_data[1].membase = (void __iomem *)ioremap(0x53F80000, 0x0fff);
++ cambria_optional_uart_data[1].irq = IRQ_IXP4XX_GPIO4;
++
++ cambria_gpio_resources[0].start = (1 << 14) | (1 << 16) | (1 << 17) | (1 << 18) |\
++ (1 << 19) | (1 << 20) | (1 << 24) | (1 << 25);
++ cambria_gpio_resources[0].end = cambria_gpio_resources[0].start;
++
++ platform_device_register(&cambria_optional_uart);
++
++ platform_device_register(&cambria_npec_device);
++ platform_device_register(&cambria_npea_device);
++
++ platform_device_register(&cambria_usb0_device);
++ platform_device_register(&cambria_usb1_device);
++
++ platform_device_register(&cambria_pata);
++
++ cambria_gpio_leds[0].gpio = 24;
++ platform_device_register(&cambria_gpio_leds_device);
++
++ platform_device_register(&cambria_latch_leds_device);
++
++ platform_device_register(&cambria_gpio_buttons_device);
++
++ /* gpio config (/sys/class/gpio) */
++ cambria_register_gpio(ARRAY_AND_SIZE(cambria_gpios_gw2358));
++}
++
++static void __init cambria_gw2359_setup(void)
++{
++#if defined(CONFIG_MVSWITCH_PHY) || defined(CONFIG_MVSWITCH_PHY_MODULE)
++ /* The mvswitch driver has some hard-coded values which could
++ * easily be turned into a platform resource if needed. For now they
++ * match our hardware configuration:
++ * MV_BASE 0x10 - phy base address
++ * MV_WANPORT 0 - Port0 (ENET2) is WAN (SFP module)
++ * MV_CPUPORT 5 - Port5 is CPU NPEA (eth1)
++ *
++ * The mvswitch driver registers a fixup which forces a driver match
++ * if phy_addr matches MV_BASE
++ *
++ * Two static defautl VLAN's are created: WAN port in 1, and all other ports
++ * in the other.
++ */
++ cambria_npea_data.phy = 0x10; // mvswitch driver catches this
++#else
++ // Switch Port5 to CPU is MII<->MII (no PHY) - this disables the genphy driver
++ cambria_npea_data.phy = IXP4XX_ETH_PHY_MAX_ADDR;
++ // CPU NPE-C is in bridge bypass mode to Port4 PHY@0x14
++ cambria_npec_data.phy = 0x14;
++#endif
++ platform_device_register(&cambria_npec_device);
++ platform_device_register(&cambria_npea_device);
++
++ platform_device_register(&cambria_usb0_device);
++ platform_device_register(&cambria_usb1_device);
++
++ cambria_gpio_leds_data.num_leds = 3;
++ cambria_gpio_leds[0].name = "user1";
++ cambria_gpio_leds[0].gpio = 125; // PNLLED1#
++ cambria_gpio_leds[1].gpio = 126; // PNLLED3#
++ cambria_gpio_leds[2].gpio = 119; // PNLLED4#
++ platform_device_register(&cambria_gpio_leds_device);
++
++#if (IS_ENABLED(CONFIG_KEYBOARD_GPIO_POLLED))
++ cambria_gpio_buttons[0].gpio = 100;
++ platform_device_register(&cambria_gpio_buttons_device);
++#endif
++
++ /* gpio config (/sys/class/gpio) */
++ cambria_register_gpio(ARRAY_AND_SIZE(cambria_gpios_gw2359));
++}
++
++static void __init cambria_gw2360_setup(void)
++{
++ /* The GW2360 has 8 UARTs in addition to the 1 IXP4xxx UART.
++ * The chip-selects are expanded via a 3-to-8 decoder and CS2
++ * and they are 8bit devices
++ */
++ *IXP4XX_EXP_CS2 = 0xBFFF3C43;
++ cambria_optional_uart_data[0].mapbase = 0x52000000;
++ cambria_optional_uart_data[0].membase = (void __iomem *)ioremap(0x52000000, 0x0fff);
++ cambria_optional_uart_data[0].uartclk = 18432000;
++ cambria_optional_uart_data[0].iotype = UPIO_MEM;
++ cambria_optional_uart_data[0].irq = IRQ_IXP4XX_GPIO2;
++ irq_set_irq_type(IRQ_IXP4XX_GPIO2, IRQ_TYPE_EDGE_RISING);
++
++ cambria_optional_uart_data[1].mapbase = 0x52000008;
++ cambria_optional_uart_data[1].membase = (void __iomem *)ioremap(0x52000008, 0x0fff);
++ cambria_optional_uart_data[1].uartclk = 18432000;
++ cambria_optional_uart_data[1].iotype = UPIO_MEM;
++ cambria_optional_uart_data[1].irq = IRQ_IXP4XX_GPIO3;
++ irq_set_irq_type(IRQ_IXP4XX_GPIO3, IRQ_TYPE_EDGE_RISING);
++
++ cambria_optional_uart_data[2].mapbase = 0x52000010;
++ cambria_optional_uart_data[2].membase = (void __iomem *)ioremap(0x52000010, 0x0fff);
++ cambria_optional_uart_data[2].uartclk = 18432000;
++ cambria_optional_uart_data[2].iotype = UPIO_MEM;
++ cambria_optional_uart_data[2].irq = IRQ_IXP4XX_GPIO4;
++ irq_set_irq_type(IRQ_IXP4XX_GPIO4, IRQ_TYPE_EDGE_RISING);
++
++ cambria_optional_uart_data[3].mapbase = 0x52000018;
++ cambria_optional_uart_data[3].membase = (void __iomem *)ioremap(0x52000018, 0x0fff);
++ cambria_optional_uart_data[3].uartclk = 18432000;
++ cambria_optional_uart_data[3].iotype = UPIO_MEM;
++ cambria_optional_uart_data[3].irq = IRQ_IXP4XX_GPIO5;
++ irq_set_irq_type(IRQ_IXP4XX_GPIO5, IRQ_TYPE_EDGE_RISING);
++
++ cambria_optional_uart_data[4].mapbase = 0x52000020;
++ cambria_optional_uart_data[4].membase = (void __iomem *)ioremap(0x52000020, 0x0fff);
++ cambria_optional_uart_data[4].uartclk = 18432000;
++ cambria_optional_uart_data[4].iotype = UPIO_MEM;
++ cambria_optional_uart_data[4].irq = IRQ_IXP4XX_GPIO8;
++ irq_set_irq_type(IRQ_IXP4XX_GPIO8, IRQ_TYPE_EDGE_RISING);
++
++ cambria_optional_uart_data[5].mapbase = 0x52000028;
++ cambria_optional_uart_data[5].membase = (void __iomem *)ioremap(0x52000028, 0x0fff);
++ cambria_optional_uart_data[5].uartclk = 18432000;
++ cambria_optional_uart_data[5].iotype = UPIO_MEM;
++ cambria_optional_uart_data[5].irq = IRQ_IXP4XX_GPIO9;
++ irq_set_irq_type(IRQ_IXP4XX_GPIO9, IRQ_TYPE_EDGE_RISING);
++
++ cambria_optional_uart_data[6].mapbase = 0x52000030;
++ cambria_optional_uart_data[6].membase = (void __iomem *)ioremap(0x52000030, 0x0fff);
++ cambria_optional_uart_data[6].uartclk = 18432000;
++ cambria_optional_uart_data[6].iotype = UPIO_MEM;
++ cambria_optional_uart_data[6].irq = IRQ_IXP4XX_GPIO10;
++ irq_set_irq_type(IRQ_IXP4XX_GPIO10, IRQ_TYPE_EDGE_RISING);
++
++ cambria_optional_uart.num_resources = 7,
++ platform_device_register(&cambria_optional_uart);
++
++#if defined(CONFIG_MVSWITCH_PHY) || defined(CONFIG_MVSWITCH_PHY_MODULE)
++ /* The mvswitch driver has some hard-coded values which could
++ * easily be turned into a platform resource if needed. For now they
++ * match our hardware configuration:
++ * MV_BASE 0x10 - phy base address
++ * MV_WANPORT 0 - Port0 (ENET2) is WAN (SFP module)
++ * MV_CPUPORT 5 - Port5 is CPU NPEA (eth1)
++ *
++ * The mvswitch driver registers a fixup which forces a driver match
++ * if phy_addr matches MV_BASE
++ *
++ * Two static defautl VLAN's are created: WAN port in 1, and all other ports
++ * in the other.
++ */
++ cambria_npea_data.phy = 0x10; // mvswitch driver catches this
++#else
++ // Switch Port5 to CPU is MII<->MII (no PHY) - this disables the generic PHY driver
++ cambria_npea_data.phy = IXP4XX_ETH_PHY_MAX_ADDR;
++#endif
++
++ // disable genphy autonegotiation on NPE-C PHY (eth1) as its 100BaseFX
++ //cambria_npec_data.noautoneg = 1; // disable autoneg
++ cambria_npec_data.speed_10 = 0; // 100mbps
++ cambria_npec_data.half_duplex = 0; // full-duplex
++ platform_device_register(&cambria_npec_device);
++ platform_device_register(&cambria_npea_device);
++
++ platform_device_register(&cambria_usb0_device);
++ platform_device_register(&cambria_usb1_device);
++
++ cambria_gpio_leds_data.num_leds = 3;
++ cambria_gpio_leds[0].name = "user1";
++ cambria_gpio_leds[0].gpio = 125;
++ cambria_gpio_leds[1].gpio = 126;
++ cambria_gpio_leds[2].gpio = 119;
++ platform_device_register(&cambria_gpio_leds_device);
++
++#if (IS_ENABLED(CONFIG_KEYBOARD_GPIO_POLLED))
++ cambria_gpio_buttons[0].gpio = 100;
++ platform_device_register(&cambria_gpio_buttons_device);
++#endif
++
++#ifdef SFP_SERIALID
++ /* the SFP modules each have an i2c bus for serial ident via GSC GPIO
++ * To use these the i2c-gpio driver must be changed to use the _cansleep
++ * varients of gpio_get_value/gpio_set_value (I don't know why it doesn't
++ * use that anyway as it doesn't operate in an IRQ context).
++ * Additionally the i2c-gpio module must set the gpio to output-high prior
++ * to changing direction to an input to enable internal Pullups
++ */
++ platform_device_register(&cambria_i2c_gpio_sfpa);
++ platform_device_register(&cambria_i2c_gpio_sfpb);
++#endif
++
++ /* gpio config (/sys/class/gpio) */
++ cambria_register_gpio(ARRAY_AND_SIZE(cambria_gpios_gw2360));
++}
++
++static struct cambria_board_info cambria_boards[] __initdata = {
++ {
++ .model = "GW2350",
++ .setup = cambria_gw2350_setup,
++ }, {
++ .model = "GW2351",
++ .setup = cambria_gw2350_setup,
++ }, {
++ .model = "GW2358",
++ .setup = cambria_gw2358_setup,
++ }, {
++ .model = "GW2359",
++ .setup = cambria_gw2359_setup,
++ }, {
++ .model = "GW2360",
++ .setup = cambria_gw2360_setup,
++ }, {
++ .model = "GW2371",
++ .setup = cambria_gw2358_setup,
++ }
++};
++
++static struct cambria_board_info * __init cambria_find_board_info(char *model)
++{
++ int i;
++ model[6] = '\0';
++
++ for (i = 0; i < ARRAY_SIZE(cambria_boards); i++) {
++ struct cambria_board_info *info = &cambria_boards[i];
++ if (strcmp(info->model, model) == 0)
++ return info;
++ }
++
++ return NULL;
++}
++
++static struct memory_accessor *at24_mem_acc;
++
++static void at24_setup(struct memory_accessor *mem_acc, void *context)
++{
++ char mac_addr[ETH_ALEN];
++ char model[7];
++
++ at24_mem_acc = mem_acc;
++
++ /* Read MAC addresses */
++ if (at24_mem_acc->read(at24_mem_acc, mac_addr, 0x0, 6) == 6) {
++ memcpy(&cambria_npec_data.hwaddr, mac_addr, ETH_ALEN);
++ }
++ if (at24_mem_acc->read(at24_mem_acc, mac_addr, 0x6, 6) == 6) {
++ memcpy(&cambria_npea_data.hwaddr, mac_addr, ETH_ALEN);
++ }
++
++ /* Read the first 6 bytes of the model number */
++ if (at24_mem_acc->read(at24_mem_acc, model, 0x20, 6) == 6) {
++ cambria_info = cambria_find_board_info(model);
++ }
++
++}
++
++static struct at24_platform_data cambria_eeprom_info = {
++ .byte_len = 1024,
++ .page_size = 16,
++ .flags = AT24_FLAG_READONLY,
++ .setup = at24_setup,
++};
++
++static struct pca953x_platform_data cambria_pca_data = {
++ .gpio_base = 100,
++ .irq_base = -1,
++};
++
++static struct pca953x_platform_data cambria_pca2_data = {
++ .gpio_base = 116,
++ .irq_base = -1,
++};
++
++static struct i2c_board_info __initdata cambria_i2c_board_info[] = {
++ {
++ I2C_BOARD_INFO("pca9555", 0x23),
++ .platform_data = &cambria_pca_data,
++ },
++ {
++ I2C_BOARD_INFO("pca9555", 0x27),
++ .platform_data = &cambria_pca2_data,
++ },
++ {
++ I2C_BOARD_INFO("ds1672", 0x68),
++ },
++ {
++ I2C_BOARD_INFO("gsp", 0x29),
++ },
++ {
++ I2C_BOARD_INFO("ad7418", 0x28),
++ },
++ {
++ I2C_BOARD_INFO("24c08", 0x51),
++ .platform_data = &cambria_eeprom_info
++ },
++ {
++ I2C_BOARD_INFO("gw_i2c_pld", 0x56),
++ .platform_data = &gw_i2c_pld_data0,
++ },
++ {
++ I2C_BOARD_INFO("gw_i2c_pld", 0x57),
++ .platform_data = &gw_i2c_pld_data1,
++ },
++};
++
++static void __init cambria_init(void)
++{
++ ixp4xx_sys_init();
++
++ cambria_flash_resource.start = IXP4XX_EXP_BUS_BASE(0);
++ cambria_flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + SZ_32M - 1;
++
++ *IXP4XX_EXP_CS0 |= IXP4XX_FLASH_WRITABLE; // make sure window is writable
++ *IXP4XX_EXP_CS1 = *IXP4XX_EXP_CS0;
++
++ platform_add_devices(ARRAY_AND_SIZE(cambria_devices));
++
++ cambria_pata_resources[0].start = 0x53e00000;
++ cambria_pata_resources[0].end = 0x53e3ffff;
++
++ cambria_pata_resources[1].start = 0x53e40000;
++ cambria_pata_resources[1].end = 0x53e7ffff;
++
++ cambria_pata_data.cs0_cfg = IXP4XX_EXP_CS3;
++ cambria_pata_data.cs1_cfg = IXP4XX_EXP_CS3;
++
++ i2c_register_board_info(0, ARRAY_AND_SIZE(cambria_i2c_board_info));
++}
++
++static int __init cambria_model_setup(void)
++{
++ if (!machine_is_cambria())
++ return 0;
++
++ if (cambria_info) {
++ printk(KERN_DEBUG "Running on Gateworks Cambria %s\n",
++ cambria_info->model);
++ cambria_info->setup();
++ } else {
++ printk(KERN_INFO "Unknown/missing Cambria model number"
++ " -- defaults will be used\n");
++ cambria_gw23xx_setup();
++ }
++
++ return 0;
++}
++late_initcall(cambria_model_setup);
++
++MACHINE_START(CAMBRIA, "Gateworks Cambria series")
++ /* Maintainer: Imre Kaloz <kaloz@openwrt.org> */
++ .map_io = ixp4xx_map_io,
++ .init_irq = ixp4xx_init_irq,
++ .init_time = ixp4xx_timer_init,
++ .atag_offset = 0x0100,
++ .init_machine = cambria_init,
++#if defined(CONFIG_PCI)
++ .dma_zone_size = SZ_64M,
++#endif
++ .restart = ixp4xx_restart,
++MACHINE_END
diff --git a/target/linux/ixp4xx/patches-4.4/201-npe_driver_print_license_location.patch b/target/linux/ixp4xx/patches-4.4/201-npe_driver_print_license_location.patch
new file mode 100644
index 0000000000..f46b9c61bf
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/201-npe_driver_print_license_location.patch
@@ -0,0 +1,11 @@
+--- a/arch/arm/mach-ixp4xx/ixp4xx_npe.c
++++ b/arch/arm/mach-ixp4xx/ixp4xx_npe.c
+@@ -586,6 +586,8 @@ int npe_load_firmware(struct npe *npe, c
+ npe_reset(npe);
+ #endif
+
++ print_npe(KERN_INFO, npe, "firmware's license can be found in /usr/share/doc/LICENSE.IPL\n");
++
+ print_npe(KERN_INFO, npe, "firmware functionality 0x%X, "
+ "revision 0x%X:%X\n", (image->id >> 16) & 0xFF,
+ (image->id >> 8) & 0xFF, image->id & 0xFF);
diff --git a/target/linux/ixp4xx/patches-4.4/203-npe_driver_mask_phy_features.patch b/target/linux/ixp4xx/patches-4.4/203-npe_driver_mask_phy_features.patch
new file mode 100644
index 0000000000..359873d7d9
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/203-npe_driver_mask_phy_features.patch
@@ -0,0 +1,13 @@
+--- a/drivers/net/ethernet/xscale/ixp4xx_eth.c
++++ b/drivers/net/ethernet/xscale/ixp4xx_eth.c
+@@ -1474,6 +1474,10 @@ static int eth_init_one(struct platform_
+ goto err_free_mem;
+ }
+
++ /* mask with MAC supported features */
++ port->phydev->supported &= PHY_BASIC_FEATURES;
++ port->phydev->advertising = port->phydev->supported;
++
+ port->phydev->irq = PHY_POLL;
+
+ if ((err = register_netdev(dev)))
diff --git a/target/linux/ixp4xx/patches-4.4/205-npe_driver_separate_phy_functions.patch b/target/linux/ixp4xx/patches-4.4/205-npe_driver_separate_phy_functions.patch
new file mode 100644
index 0000000000..6d1eb7bfbb
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/205-npe_driver_separate_phy_functions.patch
@@ -0,0 +1,131 @@
+From e3eab80fb5d0a7d7fdb0f2f231b27161d5ec3804 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Sun, 30 Jun 2013 15:52:53 +0200
+Subject: [PATCH 23/36] 205-npe_driver_separate_phy_functions.patch
+
+---
+ drivers/net/ethernet/xscale/ixp4xx_eth.c | 70 ++++++++++++++++++++++--------
+ 1 file changed, 51 insertions(+), 19 deletions(-)
+
+--- a/drivers/net/ethernet/xscale/ixp4xx_eth.c
++++ b/drivers/net/ethernet/xscale/ixp4xx_eth.c
+@@ -589,6 +589,51 @@ static void ixp4xx_adjust_link(struct ne
+ dev->name, port->speed, port->duplex ? "full" : "half");
+ }
+
++static int ixp4xx_phy_connect(struct net_device *dev)
++{
++ struct port *port = netdev_priv(dev);
++ struct eth_plat_info *plat = port->plat;
++ char phy_id[MII_BUS_ID_SIZE + 3];
++
++ snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT,
++ mdio_bus->id, plat->phy);
++ port->phydev = phy_connect(dev, phy_id, &ixp4xx_adjust_link,
++ PHY_INTERFACE_MODE_MII);
++ if (IS_ERR(port->phydev)) {
++ printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
++ return PTR_ERR(port->phydev);
++ }
++
++ /* mask with MAC supported features */
++ port->phydev->supported &= PHY_BASIC_FEATURES;
++ port->phydev->advertising = port->phydev->supported;
++
++ port->phydev->irq = PHY_POLL;
++
++ return 0;
++}
++
++static void ixp4xx_phy_disconnect(struct net_device *dev)
++{
++ struct port *port = netdev_priv(dev);
++
++ phy_disconnect(port->phydev);
++}
++
++static void ixp4xx_phy_start(struct net_device *dev)
++{
++ struct port *port = netdev_priv(dev);
++
++ port->speed = 0; /* force "link up" message */
++ phy_start(port->phydev);
++}
++
++static void ixp4xx_phy_stop(struct net_device *dev)
++{
++ struct port *port = netdev_priv(dev);
++
++ phy_stop(port->phydev);
++}
+
+ static inline void debug_pkt(struct net_device *dev, const char *func,
+ u8 *data, int len)
+@@ -1259,8 +1304,7 @@ static int eth_open(struct net_device *d
+ return err;
+ }
+
+- port->speed = 0; /* force "link up" message */
+- phy_start(port->phydev);
++ ixp4xx_phy_start(dev);
+
+ for (i = 0; i < ETH_ALEN; i++)
+ __raw_writel(dev->dev_addr[i], &port->regs->hw_addr[i]);
+@@ -1381,7 +1425,7 @@ static int eth_close(struct net_device *
+ printk(KERN_CRIT "%s: unable to disable loopback\n",
+ dev->name);
+
+- phy_stop(port->phydev);
++ ixp4xx_phy_stop(dev);
+
+ if (!ports_open)
+ qmgr_disable_irq(TXDONE_QUEUE);
+@@ -1407,7 +1451,6 @@ static int eth_init_one(struct platform_
+ struct net_device *dev;
+ struct eth_plat_info *plat = dev_get_platdata(&pdev->dev);
+ u32 regs_phys;
+- char phy_id[MII_BUS_ID_SIZE + 3];
+ int err;
+
+ if (!(dev = alloc_etherdev(sizeof(struct port))))
+@@ -1465,20 +1508,9 @@ static int eth_init_one(struct platform_
+ __raw_writel(DEFAULT_CORE_CNTRL, &port->regs->core_control);
+ udelay(50);
+
+- snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT,
+- mdio_bus->id, plat->phy);
+- port->phydev = phy_connect(dev, phy_id, &ixp4xx_adjust_link,
+- PHY_INTERFACE_MODE_MII);
+- if (IS_ERR(port->phydev)) {
+- err = PTR_ERR(port->phydev);
++ err = ixp4xx_phy_connect(dev);
++ if (err)
+ goto err_free_mem;
+- }
+-
+- /* mask with MAC supported features */
+- port->phydev->supported &= PHY_BASIC_FEATURES;
+- port->phydev->advertising = port->phydev->supported;
+-
+- port->phydev->irq = PHY_POLL;
+
+ if ((err = register_netdev(dev)))
+ goto err_phy_dis;
+@@ -1489,7 +1521,7 @@ static int eth_init_one(struct platform_
+ return 0;
+
+ err_phy_dis:
+- phy_disconnect(port->phydev);
++ ixp4xx_phy_disconnect(dev);
+ err_free_mem:
+ npe_port_tab[NPE_ID(port->id)] = NULL;
+ release_resource(port->mem_res);
+@@ -1506,7 +1538,7 @@ static int eth_remove_one(struct platfor
+ struct port *port = netdev_priv(dev);
+
+ unregister_netdev(dev);
+- phy_disconnect(port->phydev);
++ ixp4xx_phy_disconnect(dev);
+ npe_port_tab[NPE_ID(port->id)] = NULL;
+ npe_release(port->npe);
+ release_resource(port->mem_res);
diff --git a/target/linux/ixp4xx/patches-4.4/206-npe_driver_add_update_link_function.patch b/target/linux/ixp4xx/patches-4.4/206-npe_driver_add_update_link_function.patch
new file mode 100644
index 0000000000..f1a77078c4
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/206-npe_driver_add_update_link_function.patch
@@ -0,0 +1,98 @@
+--- a/drivers/net/ethernet/xscale/ixp4xx_eth.c
++++ b/drivers/net/ethernet/xscale/ixp4xx_eth.c
+@@ -177,7 +177,7 @@ struct port {
+ struct desc *desc_tab; /* coherent */
+ u32 desc_tab_phys;
+ int id; /* logical port ID */
+- int speed, duplex;
++ int link, speed, duplex;
+ u8 firmware[4];
+ int hwts_tx_en;
+ int hwts_rx_en;
+@@ -558,37 +558,52 @@ static void ixp4xx_mdio_remove(void)
+ mdiobus_free(mdio_bus);
+ }
+
+-
+-static void ixp4xx_adjust_link(struct net_device *dev)
++static void ixp4xx_update_link(struct net_device *dev)
+ {
+ struct port *port = netdev_priv(dev);
+- struct phy_device *phydev = port->phydev;
+
+- if (!phydev->link) {
+- if (port->speed) {
+- port->speed = 0;
+- printk(KERN_INFO "%s: link down\n", dev->name);
+- }
++ if (!port->link) {
++ netif_carrier_off(dev);
++ printk(KERN_INFO "%s: link down\n", dev->name);
+ return;
+ }
+
+- if (port->speed == phydev->speed && port->duplex == phydev->duplex)
+- return;
+-
+- port->speed = phydev->speed;
+- port->duplex = phydev->duplex;
+-
+- if (port->duplex)
++ if (port->duplex == DUPLEX_FULL)
+ __raw_writel(DEFAULT_TX_CNTRL0 & ~TX_CNTRL0_HALFDUPLEX,
+ &port->regs->tx_control[0]);
+ else
+ __raw_writel(DEFAULT_TX_CNTRL0 | TX_CNTRL0_HALFDUPLEX,
+ &port->regs->tx_control[0]);
+
++ netif_carrier_on(dev);
+ printk(KERN_INFO "%s: link up, speed %u Mb/s, %s duplex\n",
+ dev->name, port->speed, port->duplex ? "full" : "half");
+ }
+
++static void ixp4xx_adjust_link(struct net_device *dev)
++{
++ struct port *port = netdev_priv(dev);
++ struct phy_device *phydev = port->phydev;
++ int status_change = 0;
++
++ if (phydev->link) {
++ if (port->duplex != phydev->duplex
++ || port->speed != phydev->speed) {
++ status_change = 1;
++ }
++ }
++
++ if (phydev->link != port->link)
++ status_change = 1;
++
++ port->link = phydev->link;
++ port->speed = phydev->speed;
++ port->duplex = phydev->duplex;
++
++ if (status_change)
++ ixp4xx_update_link(dev);
++}
++
+ static int ixp4xx_phy_connect(struct net_device *dev)
+ {
+ struct port *port = netdev_priv(dev);
+@@ -624,7 +639,6 @@ static void ixp4xx_phy_start(struct net_
+ {
+ struct port *port = netdev_priv(dev);
+
+- port->speed = 0; /* force "link up" message */
+ phy_start(port->phydev);
+ }
+
+@@ -1515,6 +1529,10 @@ static int eth_init_one(struct platform_
+ if ((err = register_netdev(dev)))
+ goto err_phy_dis;
+
++ port->link = 0;
++ port->speed = 0;
++ port->duplex = -1;
++
+ printk(KERN_INFO "%s: MII PHY %i on %s\n", dev->name, plat->phy,
+ npe_name(port->npe));
+
diff --git a/target/linux/ixp4xx/patches-4.4/207-npe_driver_multiphy_support.patch b/target/linux/ixp4xx/patches-4.4/207-npe_driver_multiphy_support.patch
new file mode 100644
index 0000000000..207ccc533a
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/207-npe_driver_multiphy_support.patch
@@ -0,0 +1,145 @@
+TODO: take care of additional PHYs through the PHY abstraction layer
+
+--- a/arch/arm/mach-ixp4xx/include/mach/platform.h
++++ b/arch/arm/mach-ixp4xx/include/mach/platform.h
+@@ -95,12 +95,23 @@ struct ixp4xx_pata_data {
+ #define IXP4XX_ETH_NPEB 0x10
+ #define IXP4XX_ETH_NPEC 0x20
+
++#define IXP4XX_ETH_PHY_MAX_ADDR 32
++
+ /* Information about built-in Ethernet MAC interfaces */
+ struct eth_plat_info {
+ u8 phy; /* MII PHY ID, 0 - 31 */
+ u8 rxq; /* configurable, currently 0 - 31 only */
+ u8 txreadyq;
+ u8 hwaddr[6];
++
++ u32 phy_mask;
++#if 0
++ int speed;
++ int duplex;
++#else
++ int speed_10;
++ int half_duplex;
++#endif
+ };
+
+ /* Information about built-in HSS (synchronous serial) interfaces */
+--- a/drivers/net/ethernet/xscale/ixp4xx_eth.c
++++ b/drivers/net/ethernet/xscale/ixp4xx_eth.c
+@@ -610,6 +610,37 @@ static int ixp4xx_phy_connect(struct net
+ struct eth_plat_info *plat = port->plat;
+ char phy_id[MII_BUS_ID_SIZE + 3];
+
++ if (plat->phy == IXP4XX_ETH_PHY_MAX_ADDR) {
++#if 0
++ switch (plat->speed) {
++ case SPEED_10:
++ case SPEED_100:
++ break;
++ default:
++ printk(KERN_ERR "%s: invalid speed (%d)\n",
++ dev->name, plat->speed);
++ return -EINVAL;
++ }
++
++ switch (plat->duplex) {
++ case DUPLEX_HALF:
++ case DUPLEX_FULL:
++ break;
++ default:
++ printk(KERN_ERR "%s: invalid duplex mode (%d)\n",
++ dev->name, plat->duplex);
++ return -EINVAL;
++ }
++ port->speed = plat->speed;
++ port->duplex = plat->duplex;
++#else
++ port->speed = plat->speed_10 ? SPEED_10 : SPEED_100;
++ port->duplex = plat->half_duplex ? DUPLEX_HALF : DUPLEX_FULL;
++#endif
++
++ return 0;
++ }
++
+ snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT,
+ mdio_bus->id, plat->phy);
+ port->phydev = phy_connect(dev, phy_id, &ixp4xx_adjust_link,
+@@ -632,21 +663,32 @@ static void ixp4xx_phy_disconnect(struct
+ {
+ struct port *port = netdev_priv(dev);
+
+- phy_disconnect(port->phydev);
++ if (port->phydev)
++ phy_disconnect(port->phydev);
+ }
+
+ static void ixp4xx_phy_start(struct net_device *dev)
+ {
+ struct port *port = netdev_priv(dev);
+
+- phy_start(port->phydev);
++ if (port->phydev) {
++ phy_start(port->phydev);
++ } else {
++ port->link = 1;
++ ixp4xx_update_link(dev);
++ }
+ }
+
+ static void ixp4xx_phy_stop(struct net_device *dev)
+ {
+ struct port *port = netdev_priv(dev);
+
+- phy_stop(port->phydev);
++ if (port->phydev) {
++ phy_stop(port->phydev);
++ } else {
++ port->link = 0;
++ ixp4xx_update_link(dev);
++ }
+ }
+
+ static inline void debug_pkt(struct net_device *dev, const char *func,
+@@ -1048,6 +1090,9 @@ static int eth_ioctl(struct net_device *
+ return hwtstamp_get(dev, req);
+ }
+
++ if (!port->phydev)
++ return -EOPNOTSUPP;
++
+ return phy_mii_ioctl(port->phydev, req, cmd);
+ }
+
+@@ -1068,18 +1113,30 @@ static void ixp4xx_get_drvinfo(struct ne
+ static int ixp4xx_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+ {
+ struct port *port = netdev_priv(dev);
++
++ if (!port->phydev)
++ return -EOPNOTSUPP;
++
+ return phy_ethtool_gset(port->phydev, cmd);
+ }
+
+ static int ixp4xx_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+ {
+ struct port *port = netdev_priv(dev);
++
++ if (!port->phydev)
++ return -EOPNOTSUPP;
++
+ return phy_ethtool_sset(port->phydev, cmd);
+ }
+
+ static int ixp4xx_nway_reset(struct net_device *dev)
+ {
+ struct port *port = netdev_priv(dev);
++
++ if (!port->phydev)
++ return -EOPNOTSUPP;
++
+ return phy_start_aneg(port->phydev);
+ }
+
diff --git a/target/linux/ixp4xx/patches-4.4/295-latch_led_driver.patch b/target/linux/ixp4xx/patches-4.4/295-latch_led_driver.patch
new file mode 100644
index 0000000000..a2f846373b
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/295-latch_led_driver.patch
@@ -0,0 +1,201 @@
+--- a/drivers/leds/Kconfig
++++ b/drivers/leds/Kconfig
+@@ -296,6 +296,12 @@ config LEDS_LP8860
+ on the LP8860 4 channel LED driver using the I2C communication
+ bus.
+
++config LEDS_LATCH
++ tristate "LED Support for Memory Latched LEDs"
++ depends on LEDS_CLASS
++ help
++ -- To Do --
++
+ config LEDS_CLEVO_MAIL
+ tristate "Mail LED on Clevo notebook"
+ depends on LEDS_CLASS
+--- a/drivers/leds/Makefile
++++ b/drivers/leds/Makefile
+@@ -25,6 +25,7 @@ obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunf
+ obj-$(CONFIG_LEDS_PCA9532) += leds-pca9532.o
+ obj-$(CONFIG_LEDS_GPIO_REGISTER) += leds-gpio-register.o
+ obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o
++obj-$(CONFIG_LEDS_LATCH) += leds-latch.o
+ obj-$(CONFIG_LEDS_LP3944) += leds-lp3944.o
+ obj-$(CONFIG_LEDS_LP55XX_COMMON) += leds-lp55xx-common.o
+ obj-$(CONFIG_LEDS_LP5521) += leds-lp5521.o
+--- /dev/null
++++ b/drivers/leds/leds-latch.c
+@@ -0,0 +1,152 @@
++/*
++ * LEDs driver for Memory Latched Devices
++ *
++ * Copyright (C) 2008 Gateworks Corp.
++ * Chris Lang <clang@gateworks.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/leds.h>
++#include <linux/workqueue.h>
++#include <asm/io.h>
++#include <linux/spinlock.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/export.h>
++
++static unsigned int mem_keep = 0xFF;
++static spinlock_t mem_lock;
++static unsigned char *iobase;
++
++struct latch_led_data {
++ struct led_classdev cdev;
++ struct work_struct work;
++ u8 new_level;
++ u8 bit;
++ void (*set_led)(u8 bit, enum led_brightness value);
++};
++
++static void latch_set_led(u8 bit, enum led_brightness value)
++{
++ if (value == LED_OFF)
++ mem_keep |= (0x1 << bit);
++ else
++ mem_keep &= ~(0x1 << bit);
++
++ writeb(mem_keep, iobase);
++}
++
++static void latch_led_set(struct led_classdev *led_cdev,
++ enum led_brightness value)
++{
++ struct latch_led_data *led_dat =
++ container_of(led_cdev, struct latch_led_data, cdev);
++
++ raw_spin_lock(mem_lock);
++
++ led_dat->set_led(led_dat->bit, value);
++
++ raw_spin_unlock(mem_lock);
++}
++
++static int latch_led_probe(struct platform_device *pdev)
++{
++ struct latch_led_platform_data *pdata = pdev->dev.platform_data;
++ struct latch_led *cur_led;
++ struct latch_led_data *leds_data, *led_dat;
++ int i, ret = 0;
++
++ if (!pdata)
++ return -EBUSY;
++
++ leds_data = kzalloc(sizeof(struct latch_led_data) * pdata->num_leds,
++ GFP_KERNEL);
++ if (!leds_data)
++ return -ENOMEM;
++
++ for (i = 0; i < pdata->num_leds; i++) {
++ cur_led = &pdata->leds[i];
++ led_dat = &leds_data[i];
++
++ led_dat->cdev.name = cur_led->name;
++ led_dat->cdev.default_trigger = cur_led->default_trigger;
++ led_dat->cdev.brightness_set = latch_led_set;
++ led_dat->cdev.brightness = LED_OFF;
++ led_dat->bit = cur_led->bit;
++ led_dat->set_led = pdata->set_led ? pdata->set_led : latch_set_led;
++
++ ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
++ if (ret < 0) {
++ goto err;
++ }
++ }
++
++ if (!pdata->set_led) {
++ iobase = ioremap_nocache(pdata->mem, 0x1000);
++ writeb(0xFF, iobase);
++ }
++ platform_set_drvdata(pdev, leds_data);
++
++ return 0;
++
++err:
++ if (i > 0) {
++ for (i = i - 1; i >= 0; i--) {
++ led_classdev_unregister(&leds_data[i].cdev);
++ }
++ }
++
++ kfree(leds_data);
++
++ return ret;
++}
++
++static int latch_led_remove(struct platform_device *pdev)
++{
++ int i;
++ struct latch_led_platform_data *pdata = pdev->dev.platform_data;
++ struct latch_led_data *leds_data;
++
++ leds_data = platform_get_drvdata(pdev);
++
++ for (i = 0; i < pdata->num_leds; i++) {
++ led_classdev_unregister(&leds_data[i].cdev);
++ cancel_work_sync(&leds_data[i].work);
++ }
++
++ kfree(leds_data);
++
++ return 0;
++}
++
++static struct platform_driver latch_led_driver = {
++ .probe = latch_led_probe,
++ .remove = latch_led_remove,
++ .driver = {
++ .name = "leds-latch",
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init latch_led_init(void)
++{
++ return platform_driver_register(&latch_led_driver);
++}
++
++static void __exit latch_led_exit(void)
++{
++ platform_driver_unregister(&latch_led_driver);
++}
++
++module_init(latch_led_init);
++module_exit(latch_led_exit);
++
++MODULE_AUTHOR("Chris Lang <clang@gateworks.com>");
++MODULE_DESCRIPTION("Latch LED driver");
+--- a/include/linux/leds.h
++++ b/include/linux/leds.h
+@@ -376,4 +376,18 @@ static inline void ledtrig_cpu(enum cpu_
+ }
+ #endif
+
++/* For the leds-latch driver */
++struct latch_led {
++ const char *name;
++ char *default_trigger;
++ unsigned bit;
++};
++
++struct latch_led_platform_data {
++ int num_leds;
++ u32 mem;
++ struct latch_led *leds;
++ void (*set_led)(u8 bit, enum led_brightness value);
++};
++
+ #endif /* __LINUX_LEDS_H_INCLUDED */
diff --git a/target/linux/ixp4xx/patches-4.4/300-avila_support.patch b/target/linux/ixp4xx/patches-4.4/300-avila_support.patch
new file mode 100644
index 0000000000..d2dafaa5cd
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/300-avila_support.patch
@@ -0,0 +1,726 @@
+--- a/arch/arm/mach-ixp4xx/avila-pci.c
++++ b/arch/arm/mach-ixp4xx/avila-pci.c
+@@ -27,8 +27,8 @@
+ #include <mach/hardware.h>
+ #include <asm/mach-types.h>
+
+-#define AVILA_MAX_DEV 4
+-#define LOFT_MAX_DEV 6
++#define AVILA_MAX_DEV 6
++
+ #define IRQ_LINES 4
+
+ /* PCI controller GPIO to IRQ pin mappings */
+@@ -55,10 +55,8 @@ static int __init avila_map_irq(const st
+ IXP4XX_GPIO_IRQ(INTD)
+ };
+
+- if (slot >= 1 &&
+- slot <= (machine_is_loft() ? LOFT_MAX_DEV : AVILA_MAX_DEV) &&
+- pin >= 1 && pin <= IRQ_LINES)
+- return pci_irq_table[(slot + pin - 2) % 4];
++ if (slot >= 1 && slot <= AVILA_MAX_DEV && pin >= 1 && pin <= IRQ_LINES)
++ return pci_irq_table[(slot + pin - 2) % IRQ_LINES];
+
+ return -1;
+ }
+--- a/arch/arm/mach-ixp4xx/avila-setup.c
++++ b/arch/arm/mach-ixp4xx/avila-setup.c
+@@ -14,9 +14,16 @@
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+ #include <linux/device.h>
++#include <linux/if_ether.h>
++#include <linux/socket.h>
++#include <linux/netdevice.h>
+ #include <linux/serial.h>
+ #include <linux/tty.h>
+ #include <linux/serial_8250.h>
++#include <linux/i2c.h>
++#include <linux/platform_data/at24.h>
++#include <linux/leds.h>
++#include <linux/platform_data/pca953x.h>
+ #include <linux/i2c-gpio.h>
+ #include <asm/types.h>
+ #include <asm/setup.h>
+@@ -26,10 +33,25 @@
+ #include <asm/irq.h>
+ #include <asm/mach/arch.h>
+ #include <asm/mach/flash.h>
++#include <linux/irq.h>
+
+ #define AVILA_SDA_PIN 7
+ #define AVILA_SCL_PIN 6
+
++/* User LEDs */
++#define AVILA_GW23XX_LED_USER_GPIO 3
++#define AVILA_GW23X7_LED_USER_GPIO 4
++
++/* gpio mask used by platform device */
++#define AVILA_GPIO_MASK (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9)
++
++struct avila_board_info {
++ unsigned char *model;
++ void (*setup)(void);
++};
++
++static struct avila_board_info *avila_info __initdata;
++
+ static struct flash_platform_data avila_flash_data = {
+ .map_name = "cfi_probe",
+ .width = 2,
+@@ -105,14 +127,69 @@ static struct platform_device avila_uart
+ .resource = avila_uart_resources
+ };
+
+-static struct resource avila_pata_resources[] = {
++static struct resource avila_optional_uart_resources[] = {
+ {
+- .flags = IORESOURCE_MEM
+- },
++ .start = 0x54000000,
++ .end = 0x54000fff,
++ .flags = IORESOURCE_MEM
++ },{
++ .start = 0x55000000,
++ .end = 0x55000fff,
++ .flags = IORESOURCE_MEM
++ },{
++ .start = 0x56000000,
++ .end = 0x56000fff,
++ .flags = IORESOURCE_MEM
++ },{
++ .start = 0x57000000,
++ .end = 0x57000fff,
++ .flags = IORESOURCE_MEM
++ }
++};
++
++static struct plat_serial8250_port avila_optional_uart_data[] = {
+ {
+- .flags = IORESOURCE_MEM,
++ .flags = UPF_BOOT_AUTOCONF,
++ .iotype = UPIO_MEM,
++ .regshift = 0,
++ .uartclk = 18432000,
++ .rw_delay = 2,
++ },{
++ .flags = UPF_BOOT_AUTOCONF,
++ .iotype = UPIO_MEM,
++ .regshift = 0,
++ .uartclk = 18432000,
++ .rw_delay = 2,
++ },{
++ .flags = UPF_BOOT_AUTOCONF,
++ .iotype = UPIO_MEM,
++ .regshift = 0,
++ .uartclk = 18432000,
++ .rw_delay = 2,
++ },{
++ .flags = UPF_BOOT_AUTOCONF,
++ .iotype = UPIO_MEM,
++ .regshift = 0,
++ .uartclk = 18432000,
++ .rw_delay = 2,
+ },
++ { }
++};
++
++static struct platform_device avila_optional_uart = {
++ .name = "serial8250",
++ .id = PLAT8250_DEV_PLATFORM1,
++ .dev.platform_data = avila_optional_uart_data,
++ .num_resources = 4,
++ .resource = avila_optional_uart_resources,
++};
++
++static struct resource avila_pata_resources[] = {
+ {
++ .flags = IORESOURCE_MEM
++ },{
++ .flags = IORESOURCE_MEM,
++ },{
+ .name = "intrq",
+ .start = IRQ_IXP4XX_GPIO12,
+ .end = IRQ_IXP4XX_GPIO12,
+@@ -133,21 +210,237 @@ static struct platform_device avila_pata
+ .resource = avila_pata_resources,
+ };
+
++/* Built-in 10/100 Ethernet MAC interfaces */
++static struct eth_plat_info avila_npeb_data = {
++ .phy = 0,
++ .rxq = 3,
++ .txreadyq = 20,
++};
++
++static struct eth_plat_info avila_npec_data = {
++ .phy = 1,
++ .rxq = 4,
++ .txreadyq = 21,
++};
++
++static struct platform_device avila_npeb_device = {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEB,
++ .dev.platform_data = &avila_npeb_data,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++};
++
++static struct platform_device avila_npec_device = {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEC,
++ .dev.platform_data = &avila_npec_data,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++};
++
++static struct gpio_led avila_gpio_leds[] = {
++ {
++ .name = "user", /* green led */
++ .gpio = AVILA_GW23XX_LED_USER_GPIO,
++ .active_low = 1,
++ },
++ {
++ .name = "radio1", /* green led */
++ .gpio = 104,
++ .active_low = 1,
++ },
++ {
++ .name = "radio2", /* green led */
++ .gpio = 105,
++ .active_low = 1,
++ },
++ {
++ .name = "radio3", /* green led */
++ .gpio = 106,
++ .active_low = 1,
++ },
++ {
++ .name = "radio4", /* green led */
++ .gpio = 107,
++ .active_low = 1,
++ },
++
++};
++
++static struct gpio_led_platform_data avila_gpio_leds_data = {
++ .num_leds = 1,
++ .leds = avila_gpio_leds,
++};
++
++static struct platform_device avila_gpio_leds_device = {
++ .name = "leds-gpio",
++ .id = -1,
++ .dev.platform_data = &avila_gpio_leds_data,
++};
++
++static struct latch_led avila_latch_leds[] = {
++ {
++ .name = "led0", /* green led */
++ .bit = 0,
++ },
++ {
++ .name = "led1", /* green led */
++ .bit = 1,
++ },
++ {
++ .name = "led2", /* green led */
++ .bit = 2,
++ },
++ {
++ .name = "led3", /* green led */
++ .bit = 3,
++ },
++ {
++ .name = "led4", /* green led */
++ .bit = 4,
++ },
++ {
++ .name = "led5", /* green led */
++ .bit = 5,
++ },
++ {
++ .name = "led6", /* green led */
++ .bit = 6,
++ },
++ {
++ .name = "led7", /* green led */
++ .bit = 7,
++ }
++};
++
++static struct latch_led_platform_data avila_latch_leds_data = {
++ .num_leds = 8,
++ .leds = avila_latch_leds,
++ .mem = 0x51000000,
++};
++
++static struct platform_device avila_latch_leds_device = {
++ .name = "leds-latch",
++ .id = -1,
++ .dev.platform_data = &avila_latch_leds_data,
++};
++
+ static struct platform_device *avila_devices[] __initdata = {
+ &avila_i2c_gpio,
+- &avila_flash,
+ &avila_uart
+ };
+
+-static void __init avila_init(void)
++/*
++ * Audio Devices
++ */
++
++static struct platform_device avila_hss_device[] = {
++ {
++ .name = "gw_avila_hss",
++ .id = 0,
++ },{
++ .name = "gw_avila_hss",
++ .id = 1,
++ },{
++ .name = "gw_avila_hss",
++ .id = 2,
++ },{
++ .name = "gw_avila_hss",
++ .id = 3,
++ },
++};
++
++static struct platform_device avila_pcm_device[] = {
++ {
++ .name = "gw_avila-audio",
++ .id = 0,
++ },{
++ .name = "gw_avila-audio",
++ .id = 1,
++ },{
++ .name = "gw_avila-audio",
++ .id = 2,
++ },{
++ .name = "gw_avila-audio",
++ .id = 3,
++ }
++};
++
++static void setup_audio_devices(void) {
++ platform_device_register(&avila_hss_device[0]);
++ platform_device_register(&avila_hss_device[1]);
++ platform_device_register(&avila_hss_device[2]);
++ platform_device_register(&avila_hss_device[3]);
++
++ platform_device_register(&avila_pcm_device[0]);
++ platform_device_register(&avila_pcm_device[1]);
++ platform_device_register(&avila_pcm_device[2]);
++ platform_device_register(&avila_pcm_device[3]);
++}
++
++static void __init avila_gw23xx_setup(void)
+ {
+- ixp4xx_sys_init();
++ platform_device_register(&avila_npeb_device);
++ platform_device_register(&avila_npec_device);
+
+- avila_flash_resource.start = IXP4XX_EXP_BUS_BASE(0);
+- avila_flash_resource.end =
+- IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1;
++ platform_device_register(&avila_gpio_leds_device);
++}
+
+- platform_add_devices(avila_devices, ARRAY_SIZE(avila_devices));
++static void __init avila_gw2342_setup(void)
++{
++ platform_device_register(&avila_npeb_device);
++ platform_device_register(&avila_npec_device);
++
++ platform_device_register(&avila_gpio_leds_device);
++
++ avila_pata_resources[0].start = IXP4XX_EXP_BUS_BASE(1);
++ avila_pata_resources[0].end = IXP4XX_EXP_BUS_END(1);
++
++ avila_pata_resources[1].start = IXP4XX_EXP_BUS_BASE(2);
++ avila_pata_resources[1].end = IXP4XX_EXP_BUS_END(2);
++
++ avila_pata_data.cs0_cfg = IXP4XX_EXP_CS1;
++ avila_pata_data.cs1_cfg = IXP4XX_EXP_CS2;
++
++ platform_device_register(&avila_pata);
++}
++
++static void __init avila_gw2345_setup(void)
++{
++ avila_npeb_data.phy = IXP4XX_ETH_PHY_MAX_ADDR;
++ avila_npeb_data.phy_mask = 0x1e; /* ports 1-4 of the KS8995 switch */
++ platform_device_register(&avila_npeb_device);
++
++ avila_npec_data.phy = 5; /* port 5 of the KS8995 switch */
++ platform_device_register(&avila_npec_device);
++
++ platform_device_register(&avila_gpio_leds_device);
++
++ avila_pata_resources[0].start = IXP4XX_EXP_BUS_BASE(1);
++ avila_pata_resources[0].end = IXP4XX_EXP_BUS_END(1);
++
++ avila_pata_resources[1].start = IXP4XX_EXP_BUS_BASE(2);
++ avila_pata_resources[1].end = IXP4XX_EXP_BUS_END(2);
++
++ avila_pata_data.cs0_cfg = IXP4XX_EXP_CS1;
++ avila_pata_data.cs1_cfg = IXP4XX_EXP_CS2;
++
++ platform_device_register(&avila_pata);
++}
++
++static void __init avila_gw2347_setup(void)
++{
++ platform_device_register(&avila_npeb_device);
++
++ avila_gpio_leds[0].gpio = AVILA_GW23X7_LED_USER_GPIO;
++ platform_device_register(&avila_gpio_leds_device);
++}
++
++static void __init avila_gw2348_setup(void)
++{
++ platform_device_register(&avila_npeb_device);
++ platform_device_register(&avila_npec_device);
++
++ platform_device_register(&avila_gpio_leds_device);
+
+ avila_pata_resources[0].start = IXP4XX_EXP_BUS_BASE(1);
+ avila_pata_resources[0].end = IXP4XX_EXP_BUS_END(1);
+@@ -159,8 +452,335 @@ static void __init avila_init(void)
+ avila_pata_data.cs1_cfg = IXP4XX_EXP_CS2;
+
+ platform_device_register(&avila_pata);
++}
++
++static void __init avila_gw2353_setup(void)
++{
++ platform_device_register(&avila_npeb_device);
++ platform_device_register(&avila_gpio_leds_device);
++}
++
++static void __init avila_gw2355_setup(void)
++{
++ avila_npeb_data.phy = IXP4XX_ETH_PHY_MAX_ADDR;
++ avila_npeb_data.phy_mask = 0x1e; /* ports 1-4 of the KS8995 switch */
++ platform_device_register(&avila_npeb_device);
++
++ avila_npec_data.phy = 16;
++ platform_device_register(&avila_npec_device);
++
++ avila_gpio_leds[0].gpio = AVILA_GW23X7_LED_USER_GPIO;
++ platform_device_register(&avila_gpio_leds_device);
++
++ *IXP4XX_EXP_CS4 |= 0xbfff3c03;
++ avila_latch_leds[0].name = "RXD";
++ avila_latch_leds[1].name = "TXD";
++ avila_latch_leds[2].name = "POL";
++ avila_latch_leds[3].name = "LNK";
++ avila_latch_leds[4].name = "ERR";
++ avila_latch_leds_data.num_leds = 5;
++ avila_latch_leds_data.mem = 0x54000000;
++ platform_device_register(&avila_latch_leds_device);
++
++ avila_pata_resources[0].start = IXP4XX_EXP_BUS_BASE(1);
++ avila_pata_resources[0].end = IXP4XX_EXP_BUS_END(1);
++
++ avila_pata_resources[1].start = IXP4XX_EXP_BUS_BASE(2);
++ avila_pata_resources[1].end = IXP4XX_EXP_BUS_END(2);
++
++ avila_pata_data.cs0_cfg = IXP4XX_EXP_CS1;
++ avila_pata_data.cs1_cfg = IXP4XX_EXP_CS2;
++
++ platform_device_register(&avila_pata);
++}
++
++static void __init avila_gw2357_setup(void)
++{
++ platform_device_register(&avila_npeb_device);
++
++ avila_gpio_leds[0].gpio = AVILA_GW23X7_LED_USER_GPIO;
++ platform_device_register(&avila_gpio_leds_device);
++
++ *IXP4XX_EXP_CS1 |= 0xbfff3c03;
++ platform_device_register(&avila_latch_leds_device);
++}
++
++static void __init avila_gw2365_setup(void)
++{
++ avila_flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + SZ_32M - 1;
++
++ *IXP4XX_EXP_CS4 = 0xBFFF3C43;
++ irq_set_irq_type(IRQ_IXP4XX_GPIO0, IRQ_TYPE_EDGE_RISING);
++ avila_optional_uart_data[0].mapbase = 0x54000000;
++ avila_optional_uart_data[0].membase = (void __iomem *)ioremap(0x54000000, 0x0fff);
++ avila_optional_uart_data[0].irq = IRQ_IXP4XX_GPIO0;
++
++ *IXP4XX_EXP_CS5 = 0xBFFF3C43;
++ irq_set_irq_type(IRQ_IXP4XX_GPIO1, IRQ_TYPE_EDGE_RISING);
++ avila_optional_uart_data[1].mapbase = 0x55000000;
++ avila_optional_uart_data[1].membase = (void __iomem *)ioremap(0x55000000, 0x0fff);
++ avila_optional_uart_data[1].irq = IRQ_IXP4XX_GPIO1;
++
++ *IXP4XX_EXP_CS6 = 0xBFFF3C43;
++ irq_set_irq_type(IRQ_IXP4XX_GPIO2, IRQ_TYPE_EDGE_RISING);
++ avila_optional_uart_data[2].mapbase = 0x56000000;
++ avila_optional_uart_data[2].membase = (void __iomem *)ioremap(0x56000000, 0x0fff);
++ avila_optional_uart_data[2].irq = IRQ_IXP4XX_GPIO2;
++
++ *IXP4XX_EXP_CS7 = 0xBFFF3C43;
++ irq_set_irq_type(IRQ_IXP4XX_GPIO3, IRQ_TYPE_EDGE_RISING);
++ avila_optional_uart_data[3].mapbase = 0x57000000;
++ avila_optional_uart_data[3].membase = (void __iomem *)ioremap(0x57000000, 0x0fff);
++ avila_optional_uart_data[3].irq = IRQ_IXP4XX_GPIO3;
++
++ platform_device_register(&avila_optional_uart);
++
++ avila_npeb_data.phy = 1;
++ platform_device_register(&avila_npeb_device);
++
++ avila_npec_data.phy = 2;
++ platform_device_register(&avila_npec_device);
++
++ avila_pata_resources[0].start = IXP4XX_EXP_BUS_BASE(2);
++ avila_pata_resources[0].end = IXP4XX_EXP_BUS_END(2);
++
++ avila_pata_resources[1].start = IXP4XX_EXP_BUS_BASE(3);
++ avila_pata_resources[1].end = IXP4XX_EXP_BUS_END(3);
++
++ avila_pata_data.cs0_cfg = IXP4XX_EXP_CS2;
++ avila_pata_data.cs1_cfg = IXP4XX_EXP_CS3;
++
++ platform_device_register(&avila_pata);
++
++ avila_gpio_leds[0].gpio = 109;
++ avila_gpio_leds_data.num_leds = 5;
++ platform_device_register(&avila_gpio_leds_device);
++
++ setup_audio_devices();
++}
++
++static void __init avila_gw2369_setup(void)
++{
++ avila_flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + SZ_32M - 1;
++
++ avila_npeb_data.phy = 1;
++ platform_device_register(&avila_npeb_device);
++
++ avila_npec_data.phy = 2;
++ platform_device_register(&avila_npec_device);
++
++ setup_audio_devices();
++}
++
++static void __init avila_gw2370_setup(void)
++{
++ avila_flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + SZ_32M - 1;
++
++ avila_npeb_data.phy = 5;
++ platform_device_register(&avila_npeb_device);
++
++ avila_npec_data.phy = IXP4XX_ETH_PHY_MAX_ADDR;
++ avila_npec_data.phy_mask = 0x1e; /* ports 1-4 of the KS8995 switch */
++ platform_device_register(&avila_npec_device);
++
++ *IXP4XX_EXP_CS2 = 0xBFFF3C43;
++ irq_set_irq_type(IRQ_IXP4XX_GPIO2, IRQ_TYPE_EDGE_RISING);
++ avila_optional_uart_data[0].mapbase = 0x52000000;
++ avila_optional_uart_data[0].membase = (void __iomem *)ioremap(0x52000000, 0x0fff);
++ avila_optional_uart_data[0].irq = IRQ_IXP4XX_GPIO2;
++
++ *IXP4XX_EXP_CS3 = 0xBFFF3C43;
++ irq_set_irq_type(IRQ_IXP4XX_GPIO3, IRQ_TYPE_EDGE_RISING);
++ avila_optional_uart_data[1].mapbase = 0x53000000;
++ avila_optional_uart_data[1].membase = (void __iomem *)ioremap(0x53000000, 0x0fff);
++ avila_optional_uart_data[1].irq = IRQ_IXP4XX_GPIO3;
++
++ avila_optional_uart.num_resources = 2;
++
++ platform_device_register(&avila_optional_uart);
++
++ avila_gpio_leds[0].gpio = 101;
++ platform_device_register(&avila_gpio_leds_device);
++
++ setup_audio_devices();
++}
++
++static void __init avila_gw2375_setup(void)
++{
++ avila_npeb_data.phy = 1;
++ platform_device_register(&avila_npeb_device);
++
++ avila_npec_data.phy = 2;
++ platform_device_register(&avila_npec_device);
++
++ *IXP4XX_EXP_CS2 = 0xBFFF3C43;
++ irq_set_irq_type(IRQ_IXP4XX_GPIO10, IRQ_TYPE_EDGE_RISING);
++ avila_optional_uart_data[0].mapbase = 0x52000000;
++ avila_optional_uart_data[0].membase = (void __iomem *)ioremap(0x52000000, 0x0fff);
++ avila_optional_uart_data[0].irq = IRQ_IXP4XX_GPIO10;
++
++ avila_optional_uart.num_resources = 1;
++
++ platform_device_register(&avila_optional_uart);
++
++ setup_audio_devices();
++}
++
++
++static struct avila_board_info avila_boards[] __initdata = {
++ {
++ .model = "GW2342",
++ .setup = avila_gw2342_setup,
++ }, {
++ .model = "GW2345",
++ .setup = avila_gw2345_setup,
++ }, {
++ .model = "GW2347",
++ .setup = avila_gw2347_setup,
++ }, {
++ .model = "GW2348",
++ .setup = avila_gw2348_setup,
++ }, {
++ .model = "GW2353",
++ .setup = avila_gw2353_setup,
++ }, {
++ .model = "GW2355",
++ .setup = avila_gw2355_setup,
++ }, {
++ .model = "GW2357",
++ .setup = avila_gw2357_setup,
++ }, {
++ .model = "GW2365",
++ .setup = avila_gw2365_setup,
++ }, {
++ .model = "GW2369",
++ .setup = avila_gw2369_setup,
++ }, {
++ .model = "GW2370",
++ .setup = avila_gw2370_setup,
++ }, {
++ .model = "GW2373",
++ .setup = avila_gw2369_setup,
++ }, {
++ .model = "GW2375",
++ .setup = avila_gw2375_setup,
++ }
++};
++
++static struct avila_board_info * __init avila_find_board_info(char *model)
++{
++ int i;
++ model[6] = '\0';
++
++ for (i = 0; i < ARRAY_SIZE(avila_boards); i++) {
++ struct avila_board_info *info = &avila_boards[i];
++ if (strcmp(info->model, model) == 0)
++ return info;
++ }
++
++ return NULL;
++}
++
++static struct memory_accessor *at24_mem_acc;
++
++static void at24_setup(struct memory_accessor *mem_acc, void *context)
++{
++ char mac_addr[ETH_ALEN];
++ char model[7];
++
++ at24_mem_acc = mem_acc;
++
++ /* Read MAC addresses */
++ if (at24_mem_acc->read(at24_mem_acc, mac_addr, 0x0, 6) == 6) {
++ memcpy(&avila_npeb_data.hwaddr, mac_addr, ETH_ALEN);
++ }
++ if (at24_mem_acc->read(at24_mem_acc, mac_addr, 0x6, 6) == 6) {
++ memcpy(&avila_npec_data.hwaddr, mac_addr, ETH_ALEN);
++ }
++
++ /* Read the first 6 bytes of the model number */
++ if (at24_mem_acc->read(at24_mem_acc, model, 0x20, 6) == 6) {
++ avila_info = avila_find_board_info(model);
++ }
++
++}
++
++static struct at24_platform_data avila_eeprom_info = {
++ .byte_len = 1024,
++ .page_size = 16,
++// .flags = AT24_FLAG_READONLY,
++ .setup = at24_setup,
++};
++
++static struct pca953x_platform_data avila_pca_data = {
++ .gpio_base = 100,
++};
++
++static struct i2c_board_info __initdata avila_i2c_board_info[] = {
++ {
++ I2C_BOARD_INFO("ds1672", 0x68),
++ },
++ {
++ I2C_BOARD_INFO("gsp", 0x29),
++ },
++ {
++ I2C_BOARD_INFO("pca9555", 0x23),
++ .platform_data = &avila_pca_data,
++ },
++ {
++ I2C_BOARD_INFO("ad7418", 0x28),
++ },
++ {
++ I2C_BOARD_INFO("24c08", 0x51),
++ .platform_data = &avila_eeprom_info
++ },
++ {
++ I2C_BOARD_INFO("tlv320aic33", 0x1b),
++ },
++ {
++ I2C_BOARD_INFO("tlv320aic33", 0x1a),
++ },
++ {
++ I2C_BOARD_INFO("tlv320aic33", 0x19),
++ },
++ {
++ I2C_BOARD_INFO("tlv320aic33", 0x18),
++ },
++};
++
++static void __init avila_init(void)
++{
++ ixp4xx_sys_init();
++
++ platform_add_devices(avila_devices, ARRAY_SIZE(avila_devices));
++
++ i2c_register_board_info(0, avila_i2c_board_info,
++ ARRAY_SIZE(avila_i2c_board_info));
++}
++
++static int __init avila_model_setup(void)
++{
++ if (!machine_is_avila())
++ return 0;
++
++ /* default 16MB flash */
++ avila_flash_resource.start = IXP4XX_EXP_BUS_BASE(0);
++ avila_flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + SZ_16M - 1;
++
++ if (avila_info) {
++ printk(KERN_DEBUG "Running on Gateworks Avila %s\n",
++ avila_info->model);
++ avila_info->setup();
++ } else {
++ printk(KERN_INFO "Unknown/missing Avila model number"
++ " -- defaults will be used\n");
++ avila_gw23xx_setup();
++ }
++ platform_device_register(&avila_flash);
+
++ return 0;
+ }
++late_initcall(avila_model_setup);
+
+ MACHINE_START(AVILA, "Gateworks Avila Network Platform")
+ /* Maintainer: Deepak Saxena <dsaxena@plexity.net> */
diff --git a/target/linux/ixp4xx/patches-4.4/304-ixp4xx_eth_jumboframe.patch b/target/linux/ixp4xx/patches-4.4/304-ixp4xx_eth_jumboframe.patch
new file mode 100644
index 0000000000..b16086bbc4
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/304-ixp4xx_eth_jumboframe.patch
@@ -0,0 +1,80 @@
+--- a/drivers/net/ethernet/xscale/ixp4xx_eth.c
++++ b/drivers/net/ethernet/xscale/ixp4xx_eth.c
+@@ -57,7 +57,7 @@
+
+ #define POOL_ALLOC_SIZE (sizeof(struct desc) * (RX_DESCS + TX_DESCS))
+ #define REGS_SIZE 0x1000
+-#define MAX_MRU 1536 /* 0x600 */
++#define MAX_MRU (14320 - ETH_HLEN - ETH_FCS_LEN)
+ #define RX_BUFF_SIZE ALIGN((NET_IP_ALIGN) + MAX_MRU, 4)
+
+ #define NAPI_WEIGHT 16
+@@ -1315,6 +1315,32 @@ static void destroy_queues(struct port *
+ }
+ }
+
++static int eth_do_change_mtu(struct net_device *dev, int mtu)
++{
++ struct port *port;
++ struct msg msg;
++ /* adjust for ethernet headers */
++ int framesize = mtu + ETH_HLEN + ETH_FCS_LEN;
++
++ port = netdev_priv(dev);
++
++ memset(&msg, 0, sizeof(msg));
++ msg.cmd = NPE_SETMAXFRAMELENGTHS;
++ msg.eth_id = port->id;
++
++ /* max rx/tx 64 byte blocks */
++ msg.byte2 = ((framesize + 63) / 64) << 8;
++ msg.byte3 = ((framesize + 63) / 64) << 8;
++
++ msg.byte4 = msg.byte6 = framesize >> 8;
++ msg.byte5 = msg.byte7 = framesize & 0xff;
++
++ if (npe_send_recv_message(port->npe, &msg, "ETH_SET_MAX_FRAME_LENGTH"))
++ return -EIO;
++
++ return 0;
++}
++
+ static int eth_open(struct net_device *dev)
+ {
+ struct port *port = netdev_priv(dev);
+@@ -1366,6 +1392,8 @@ static int eth_open(struct net_device *d
+ if (npe_send_recv_message(port->npe, &msg, "ETH_SET_FIREWALL_MODE"))
+ return -EIO;
+
++ eth_do_change_mtu(dev, dev->mtu);
++
+ if ((err = request_queues(port)) != 0)
+ return err;
+
+@@ -1505,7 +1533,26 @@ static int eth_close(struct net_device *
+ return 0;
+ }
+
++static int ixp_eth_change_mtu(struct net_device *dev, int mtu)
++{
++ int ret;
++
++ if (mtu > MAX_MRU)
++ return -EINVAL;
++
++ if (dev->flags & IFF_UP) {
++ ret = eth_do_change_mtu(dev, mtu);
++ if (ret < 0)
++ return ret;
++ }
++
++ dev->mtu = mtu;
++
++ return 0;
++}
++
+ static const struct net_device_ops ixp4xx_netdev_ops = {
++ .ndo_change_mtu = ixp_eth_change_mtu,
+ .ndo_open = eth_open,
+ .ndo_stop = eth_close,
+ .ndo_start_xmit = eth_xmit,
diff --git a/target/linux/ixp4xx/patches-4.4/310-gtwx5717_spi_bus.patch b/target/linux/ixp4xx/patches-4.4/310-gtwx5717_spi_bus.patch
new file mode 100644
index 0000000000..080b96ac86
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/310-gtwx5717_spi_bus.patch
@@ -0,0 +1,52 @@
+--- a/arch/arm/mach-ixp4xx/gtwx5715-setup.c
++++ b/arch/arm/mach-ixp4xx/gtwx5715-setup.c
+@@ -27,6 +27,7 @@
+ #include <linux/serial.h>
+ #include <linux/tty.h>
+ #include <linux/serial_8250.h>
++#include <linux/spi/spi_gpio_old.h>
+ #include <asm/types.h>
+ #include <asm/setup.h>
+ #include <asm/memory.h>
+@@ -146,9 +147,41 @@ static struct platform_device gtwx5715_f
+ .resource = &gtwx5715_flash_resource,
+ };
+
++static int gtwx5715_spi_boardinfo_setup(struct spi_board_info *bi,
++ struct spi_master *master, void *data)
++{
++
++ strlcpy(bi->modalias, "spi-ks8995", sizeof(bi->modalias));
++
++ bi->max_speed_hz = 5000000 /* Hz */;
++ bi->bus_num = master->bus_num;
++ bi->mode = SPI_MODE_0;
++
++ return 0;
++}
++
++static struct spi_gpio_platform_data gtwx5715_spi_bus_data = {
++ .pin_cs = GTWX5715_KSSPI_SELECT,
++ .pin_clk = GTWX5715_KSSPI_CLOCK,
++ .pin_miso = GTWX5715_KSSPI_RXD,
++ .pin_mosi = GTWX5715_KSSPI_TXD,
++ .cs_activelow = 1,
++ .no_spi_delay = 1,
++ .boardinfo_setup = gtwx5715_spi_boardinfo_setup,
++};
++
++static struct platform_device gtwx5715_spi_bus = {
++ .name = "spi-gpio",
++ .id = 0,
++ .dev = {
++ .platform_data = &gtwx5715_spi_bus_data,
++ },
++};
++
+ static struct platform_device *gtwx5715_devices[] __initdata = {
+ &gtwx5715_uart_device,
+ &gtwx5715_flash,
++ &gtwx5715_spi_bus,
+ };
+
+ static void __init gtwx5715_init(void)
diff --git a/target/linux/ixp4xx/patches-4.4/311-gtwx5717_mac_plat_info.patch b/target/linux/ixp4xx/patches-4.4/311-gtwx5717_mac_plat_info.patch
new file mode 100644
index 0000000000..aa7a9e05a0
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/311-gtwx5717_mac_plat_info.patch
@@ -0,0 +1,50 @@
+--- a/arch/arm/mach-ixp4xx/gtwx5715-setup.c
++++ b/arch/arm/mach-ixp4xx/gtwx5715-setup.c
+@@ -28,6 +28,7 @@
+ #include <linux/tty.h>
+ #include <linux/serial_8250.h>
+ #include <linux/spi/spi_gpio_old.h>
++#include <linux/dma-mapping.h>
+ #include <asm/types.h>
+ #include <asm/setup.h>
+ #include <asm/memory.h>
+@@ -178,10 +179,39 @@ static struct platform_device gtwx5715_s
+ },
+ };
+
++static struct eth_plat_info gtwx5715_npeb_data = {
++ .phy = IXP4XX_ETH_PHY_MAX_ADDR,
++ .phy_mask = 0x1e, /* ports 1-4 of the KS8995 switch */
++ .rxq = 3,
++ .txreadyq = 20,
++};
++
++static struct eth_plat_info gtwx5715_npec_data = {
++ .phy = 5, /* port 5 of the KS8995 switch */
++ .rxq = 4,
++ .txreadyq = 21,
++};
++
++static struct platform_device gtwx5715_npeb_device = {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEB,
++ .dev.platform_data = &gtwx5715_npeb_data,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++};
++
++static struct platform_device gtwx5715_npec_device = {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEC,
++ .dev.platform_data = &gtwx5715_npec_data,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++};
++
+ static struct platform_device *gtwx5715_devices[] __initdata = {
+ &gtwx5715_uart_device,
+ &gtwx5715_flash,
+ &gtwx5715_spi_bus,
++ &gtwx5715_npeb_device,
++ &gtwx5715_npec_device,
+ };
+
+ static void __init gtwx5715_init(void)
diff --git a/target/linux/ixp4xx/patches-4.4/312-ixp4xx_pata_optimization.patch b/target/linux/ixp4xx/patches-4.4/312-ixp4xx_pata_optimization.patch
new file mode 100644
index 0000000000..59c2837f0c
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/312-ixp4xx_pata_optimization.patch
@@ -0,0 +1,137 @@
+--- a/drivers/ata/pata_ixp4xx_cf.c
++++ b/drivers/ata/pata_ixp4xx_cf.c
+@@ -24,16 +24,58 @@
+ #include <scsi/scsi_host.h>
+
+ #define DRV_NAME "pata_ixp4xx_cf"
+-#define DRV_VERSION "0.2"
++#define DRV_VERSION "0.3"
+
+ static int ixp4xx_set_mode(struct ata_link *link, struct ata_device **error)
+ {
++ struct ixp4xx_pata_data *data = link->ap->host->dev->platform_data;
++ unsigned int pio_mask;
+ struct ata_device *dev;
+
+ ata_for_each_dev(dev, link, ENABLED) {
+- ata_dev_info(dev, "configured for PIO0\n");
+- dev->pio_mode = XFER_PIO_0;
+- dev->xfer_mode = XFER_PIO_0;
++ if (dev->id[ATA_ID_FIELD_VALID] & (1 << 1)) {
++ pio_mask = dev->id[ATA_ID_PIO_MODES] & 0x03;
++ if (pio_mask & (1 << 1)) {
++ pio_mask = 4;
++ } else {
++ pio_mask = 3;
++ }
++ } else {
++ pio_mask = (dev->id[ATA_ID_OLD_PIO_MODES] >> 8);
++ }
++
++ switch (pio_mask){
++ case 0:
++ ata_dev_printk(dev, KERN_INFO, "configured for PIO0\n");
++ dev->pio_mode = XFER_PIO_0;
++ dev->xfer_mode = XFER_PIO_0;
++ *data->cs0_cfg = 0x8a473c03;
++ break;
++ case 1:
++ ata_dev_printk(dev, KERN_INFO, "configured for PIO1\n");
++ dev->pio_mode = XFER_PIO_1;
++ dev->xfer_mode = XFER_PIO_1;
++ *data->cs0_cfg = 0x86433c03;
++ break;
++ case 2:
++ ata_dev_printk(dev, KERN_INFO, "configured for PIO2\n");
++ dev->pio_mode = XFER_PIO_2;
++ dev->xfer_mode = XFER_PIO_2;
++ *data->cs0_cfg = 0x82413c03;
++ break;
++ case 3:
++ ata_dev_printk(dev, KERN_INFO, "configured for PIO3\n");
++ dev->pio_mode = XFER_PIO_3;
++ dev->xfer_mode = XFER_PIO_3;
++ *data->cs0_cfg = 0x80823c03;
++ break;
++ case 4:
++ ata_dev_printk(dev, KERN_INFO, "configured for PIO4\n");
++ dev->pio_mode = XFER_PIO_4;
++ dev->xfer_mode = XFER_PIO_4;
++ *data->cs0_cfg = 0x80403c03;
++ break;
++ }
+ dev->xfer_shift = ATA_SHIFT_PIO;
+ dev->flags |= ATA_DFLAG_PIO;
+ }
+@@ -46,6 +88,7 @@ static unsigned int ixp4xx_mmio_data_xfe
+ unsigned int i;
+ unsigned int words = buflen >> 1;
+ u16 *buf16 = (u16 *) buf;
++ unsigned int pio_mask;
+ struct ata_port *ap = dev->link->ap;
+ void __iomem *mmio = ap->ioaddr.data_addr;
+ struct ixp4xx_pata_data *data = dev_get_platdata(ap->host->dev);
+@@ -53,8 +96,34 @@ static unsigned int ixp4xx_mmio_data_xfe
+ /* set the expansion bus in 16bit mode and restore
+ * 8 bit mode after the transaction.
+ */
+- *data->cs0_cfg &= ~(0x01);
+- udelay(100);
++ if (dev->id[ATA_ID_FIELD_VALID] & (1 << 1)){
++ pio_mask = dev->id[ATA_ID_PIO_MODES] & 0x03;
++ if (pio_mask & (1 << 1)){
++ pio_mask = 4;
++ }else{
++ pio_mask = 3;
++ }
++ }else{
++ pio_mask = (dev->id[ATA_ID_OLD_PIO_MODES] >> 8);
++ }
++ switch (pio_mask){
++ case 0:
++ *data->cs0_cfg = 0xa9643c42;
++ break;
++ case 1:
++ *data->cs0_cfg = 0x85033c42;
++ break;
++ case 2:
++ *data->cs0_cfg = 0x80b23c42;
++ break;
++ case 3:
++ *data->cs0_cfg = 0x80823c42;
++ break;
++ case 4:
++ *data->cs0_cfg = 0x80403c42;
++ break;
++ }
++ udelay(5);
+
+ /* Transfer multiple of 2 bytes */
+ if (rw == READ)
+@@ -79,8 +148,24 @@ static unsigned int ixp4xx_mmio_data_xfe
+ words++;
+ }
+
+- udelay(100);
+- *data->cs0_cfg |= 0x01;
++ udelay(5);
++ switch (pio_mask){
++ case 0:
++ *data->cs0_cfg = 0x8a473c03;
++ break;
++ case 1:
++ *data->cs0_cfg = 0x86433c03;
++ break;
++ case 2:
++ *data->cs0_cfg = 0x82413c03;
++ break;
++ case 3:
++ *data->cs0_cfg = 0x80823c03;
++ break;
++ case 4:
++ *data->cs0_cfg = 0x80403c03;
++ break;
++ }
+
+ return words << 1;
+ }
diff --git a/target/linux/ixp4xx/patches-4.4/500-usr8200_support.patch b/target/linux/ixp4xx/patches-4.4/500-usr8200_support.patch
new file mode 100644
index 0000000000..fb7f03ee1a
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/500-usr8200_support.patch
@@ -0,0 +1,347 @@
+--- a/arch/arm/mach-ixp4xx/Kconfig
++++ b/arch/arm/mach-ixp4xx/Kconfig
+@@ -93,6 +93,14 @@ config MACH_SIDEWINDER
+ Engineering Sidewinder board. For more information on this
+ platform, see http://www.adiengineering.com
+
++config MACH_USR8200
++ bool "USRobotics USR8200"
++ select PCI
++ help
++ Say 'Y' here if you want your kernel to support the USRobotics
++ USR8200 router board. For more information on this platform, see
++ http://openwrt.org
++
+ config MACH_COMPEXWP18
+ bool "Compex WP18 / NP18A"
+ select PCI
+--- a/arch/arm/mach-ixp4xx/Makefile
++++ b/arch/arm/mach-ixp4xx/Makefile
+@@ -27,6 +27,7 @@ obj-pci-$(CONFIG_MACH_WRT300NV2) += wrt
+ obj-pci-$(CONFIG_MACH_AP1000) += ixdp425-pci.o
+ obj-pci-$(CONFIG_MACH_TW5334) += tw5334-pci.o
+ obj-pci-$(CONFIG_MACH_MI424WR) += mi424wr-pci.o
++obj-pci-$(CONFIG_MACH_USR8200) += usr8200-pci.o
+
+ obj-y += common.o
+
+@@ -55,6 +56,7 @@ obj-$(CONFIG_MACH_WRT300NV2) += wrt300nv
+ obj-$(CONFIG_MACH_AP1000) += ap1000-setup.o
+ obj-$(CONFIG_MACH_TW5334) += tw5334-setup.o
+ obj-$(CONFIG_MACH_MI424WR) += mi424wr-setup.o
++obj-$(CONFIG_MACH_USR8200) += usr8200-setup.o
+
+ obj-$(CONFIG_PCI) += $(obj-pci-$(CONFIG_PCI)) common-pci.o
+ obj-$(CONFIG_IXP4XX_QMGR) += ixp4xx_qmgr.o
+--- a/arch/arm/mach-ixp4xx/include/mach/uncompress.h
++++ b/arch/arm/mach-ixp4xx/include/mach/uncompress.h
+@@ -44,7 +44,8 @@ static __inline__ void __arch_decomp_set
+ machine_is_gateway7001() || machine_is_wg302v2() ||
+ machine_is_devixp() || machine_is_miccpt() || machine_is_mic256() ||
+ machine_is_pronghorn() || machine_is_pronghorn_metro() ||
+- machine_is_wrt300nv2() || machine_is_tw5334())
++ machine_is_wrt300nv2() || machine_is_tw5334() ||
++ machine_is_usr8200())
+ uart_base = (volatile u32*) IXP4XX_UART2_BASE_PHYS;
+ else
+ uart_base = (volatile u32*) IXP4XX_UART1_BASE_PHYS;
+--- /dev/null
++++ b/arch/arm/mach-ixp4xx/usr8200-pci.c
+@@ -0,0 +1,77 @@
++/*
++ * arch/arch/mach-ixp4xx/usr8200-pci.c
++ *
++ * PCI setup routines for USRobotics USR8200
++ *
++ * Copyright (C) 2008 Peter Denison <openwrt@marshadder.org>
++ *
++ * based on pronghorn-pci.c
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ * based on coyote-pci.c:
++ * Copyright (C) 2002 Jungo Software Technologies.
++ * Copyright (C) 2003 MontaVista Softwrae, Inc.
++ *
++ * Maintainer: Peter Denison <openwrt@marshadder.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/irq.h>
++
++#include <asm/mach-types.h>
++#include <mach/hardware.h>
++
++#include <asm/mach/pci.h>
++
++void __init usr8200_pci_preinit(void)
++{
++ irq_set_irq_type(IRQ_IXP4XX_GPIO7, IRQ_TYPE_LEVEL_LOW);
++ irq_set_irq_type(IRQ_IXP4XX_GPIO8, IRQ_TYPE_LEVEL_LOW);
++ irq_set_irq_type(IRQ_IXP4XX_GPIO9, IRQ_TYPE_LEVEL_LOW);
++ irq_set_irq_type(IRQ_IXP4XX_GPIO10, IRQ_TYPE_LEVEL_LOW);
++ irq_set_irq_type(IRQ_IXP4XX_GPIO11, IRQ_TYPE_LEVEL_LOW);
++
++ ixp4xx_pci_preinit();
++}
++
++static int __init usr8200_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
++{
++ if (slot == 14)
++ return IRQ_IXP4XX_GPIO7;
++ else if (slot == 15)
++ return IRQ_IXP4XX_GPIO8;
++ else if (slot == 16) {
++ if (pin == 1)
++ return IRQ_IXP4XX_GPIO11;
++ else if (pin == 2)
++ return IRQ_IXP4XX_GPIO10;
++ else if (pin == 3)
++ return IRQ_IXP4XX_GPIO9;
++ else
++ return -1;
++ } else
++ return -1;
++}
++
++struct hw_pci usr8200_pci __initdata = {
++ .nr_controllers = 1,
++ .preinit = usr8200_pci_preinit,
++ .ops = &ixp4xx_ops,
++ .setup = ixp4xx_setup,
++ .map_irq = usr8200_map_irq,
++};
++
++int __init usr8200_pci_init(void)
++{
++ if (machine_is_usr8200())
++ pci_common_init(&usr8200_pci);
++ return 0;
++}
++
++subsys_initcall(usr8200_pci_init);
+--- /dev/null
++++ b/arch/arm/mach-ixp4xx/usr8200-setup.c
+@@ -0,0 +1,217 @@
++/*
++ * arch/arm/mach-ixp4xx/usr8200-setup.c
++ *
++ * Board setup for the USRobotics USR8200
++ *
++ * Copyright (C) 2008 Peter Denison <openwrt@marshadder.org>
++ *
++ * based on pronghorn-setup.c:
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ * based on coyote-setup.c:
++ * Copyright (C) 2003-2005 MontaVista Software, Inc.
++ *
++ * Author: Peter Denison <openwrt@marshadder.org>
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/device.h>
++#include <linux/serial.h>
++#include <linux/tty.h>
++#include <linux/serial_8250.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++#include <linux/memory.h>
++#include <linux/i2c-gpio.h>
++#include <linux/leds.h>
++#include <linux/dma-mapping.h>
++
++#include <asm/setup.h>
++#include <mach/hardware.h>
++#include <asm/irq.h>
++#include <asm/mach-types.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/flash.h>
++
++static struct flash_platform_data usr8200_flash_data = {
++ .map_name = "cfi_probe",
++ .width = 2,
++};
++
++static struct resource usr8200_flash_resource = {
++ .flags = IORESOURCE_MEM,
++};
++
++static struct platform_device usr8200_flash = {
++ .name = "IXP4XX-Flash",
++ .id = 0,
++ .dev = {
++ .platform_data = &usr8200_flash_data,
++ },
++ .num_resources = 1,
++ .resource = &usr8200_flash_resource,
++};
++
++static struct resource usr8200_uart_resources [] = {
++ {
++ .start = IXP4XX_UART2_BASE_PHYS,
++ .end = IXP4XX_UART2_BASE_PHYS + 0x0fff,
++ .flags = IORESOURCE_MEM
++ },
++ {
++ .start = IXP4XX_UART1_BASE_PHYS,
++ .end = IXP4XX_UART1_BASE_PHYS + 0x0fff,
++ .flags = IORESOURCE_MEM
++ }
++};
++
++static struct plat_serial8250_port usr8200_uart_data[] = {
++ {
++ .mapbase = IXP4XX_UART2_BASE_PHYS,
++ .membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
++ .irq = IRQ_IXP4XX_UART2,
++ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
++ .iotype = UPIO_MEM,
++ .regshift = 2,
++ .uartclk = IXP4XX_UART_XTAL,
++ },
++ {
++ .mapbase = IXP4XX_UART1_BASE_PHYS,
++ .membase = (char *)IXP4XX_UART1_BASE_VIRT + REG_OFFSET,
++ .irq = IRQ_IXP4XX_UART1,
++ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
++ .iotype = UPIO_MEM,
++ .regshift = 2,
++ .uartclk = IXP4XX_UART_XTAL,
++ },
++ { },
++};
++
++static struct platform_device usr8200_uart = {
++ .name = "serial8250",
++ .id = PLAT8250_DEV_PLATFORM,
++ .dev = {
++ .platform_data = usr8200_uart_data,
++ },
++ .num_resources = 2,
++ .resource = usr8200_uart_resources,
++};
++
++static struct gpio_led usr8200_led_pin[] = {
++ {
++ .name = "usr8200:usb1",
++ .gpio = 0,
++ .active_low = 1,
++ },
++ {
++ .name = "usr8200:usb2",
++ .gpio = 1,
++ .active_low = 1,
++ },
++ {
++ .name = "usr8200:ieee1394",
++ .gpio = 2,
++ .active_low = 1,
++ },
++ {
++ .name = "usr8200:internal",
++ .gpio = 3,
++ .active_low = 1,
++ },
++ {
++ .name = "usr8200:power",
++ .gpio = 14,
++ }
++};
++
++static struct gpio_led_platform_data usr8200_led_data = {
++ .num_leds = ARRAY_SIZE(usr8200_led_pin),
++ .leds = usr8200_led_pin,
++};
++
++static struct platform_device usr8200_led = {
++ .name = "leds-gpio",
++ .id = -1,
++ .dev.platform_data = &usr8200_led_data,
++};
++
++static struct eth_plat_info usr8200_plat_eth[] = {
++ { /* NPEC - LAN with Marvell 88E6060 switch */
++ .phy = IXP4XX_ETH_PHY_MAX_ADDR,
++ .phy_mask = 0x0F0000,
++ .rxq = 4,
++ .txreadyq = 21,
++ }, { /* NPEB - WAN */
++ .phy = 9,
++ .rxq = 3,
++ .txreadyq = 20,
++ }
++};
++
++static struct platform_device usr8200_eth[] = {
++ {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEC,
++ .dev.platform_data = usr8200_plat_eth,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++ }, {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEB,
++ .dev.platform_data = usr8200_plat_eth + 1,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++ }
++};
++
++static struct resource usr8200_rtc_resources = {
++ .flags = IORESOURCE_MEM
++};
++
++static struct platform_device usr8200_rtc = {
++ .name = "rtc7301",
++ .id = 0,
++ .num_resources = 1,
++ .resource = &usr8200_rtc_resources,
++};
++
++static struct platform_device *usr8200_devices[] __initdata = {
++ &usr8200_flash,
++ &usr8200_uart,
++ &usr8200_led,
++ &usr8200_eth[0],
++ &usr8200_eth[1],
++ &usr8200_rtc,
++};
++
++static void __init usr8200_init(void)
++{
++ ixp4xx_sys_init();
++
++ usr8200_flash_resource.start = IXP4XX_EXP_BUS_BASE(0);
++ usr8200_flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + SZ_16M - 1;
++
++ usr8200_rtc_resources.start = IXP4XX_EXP_BUS_BASE(2);
++ usr8200_rtc_resources.end = IXP4XX_EXP_BUS_BASE(2) + 0x01ff;
++
++ *IXP4XX_EXP_CS0 |= IXP4XX_FLASH_WRITABLE;
++ *IXP4XX_EXP_CS2 = 0x3fff000 | IXP4XX_EXP_BUS_SIZE(0) | IXP4XX_EXP_BUS_WR_EN |
++ IXP4XX_EXP_BUS_CS_EN | IXP4XX_EXP_BUS_BYTE_EN;
++ *IXP4XX_GPIO_GPCLKR = 0x01100000;
++
++ /* configure button as input */
++ gpio_line_config(12, IXP4XX_GPIO_IN);
++
++ platform_add_devices(usr8200_devices, ARRAY_SIZE(usr8200_devices));
++}
++
++MACHINE_START(USR8200, "USRobotics USR8200")
++ /* Maintainer: Peter Denison <openwrt@marshadder.org> */
++ .map_io = ixp4xx_map_io,
++ .init_irq = ixp4xx_init_irq,
++ .init_time = ixp4xx_timer_init,
++ .atag_offset = 0x0100,
++ .init_machine = usr8200_init,
++#if defined(CONFIG_PCI)
++ .dma_zone_size = SZ_64M,
++#endif
++ .restart = ixp4xx_restart,
++MACHINE_END
diff --git a/target/linux/ixp4xx/patches-4.4/520-tw2662_support.patch b/target/linux/ixp4xx/patches-4.4/520-tw2662_support.patch
new file mode 100644
index 0000000000..7cea61f2aa
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/520-tw2662_support.patch
@@ -0,0 +1,317 @@
+--- a/arch/arm/mach-ixp4xx/Kconfig
++++ b/arch/arm/mach-ixp4xx/Kconfig
+@@ -176,6 +176,15 @@ config ARCH_PRPMC1100
+ PrPCM1100 Processor Mezanine Module. For more information on
+ this platform, see <file:Documentation/arm/IXP4xx>.
+
++config MACH_TW2662
++ bool "Titan Wireless TW-266-2"
++ select PCI
++ help
++ Say 'Y' here if you want your kernel to support the Titan
++ Wireless TW266-2. For more information on this platform,
++ see http://openwrt.org
++
++
+ config MACH_TW5334
+ bool "Titan Wireless TW-533-4"
+ select PCI
+--- a/arch/arm/mach-ixp4xx/Makefile
++++ b/arch/arm/mach-ixp4xx/Makefile
+@@ -25,6 +25,7 @@ obj-pci-$(CONFIG_MACH_SIDEWINDER) += sid
+ obj-pci-$(CONFIG_MACH_COMPEXWP18) += ixdp425-pci.o
+ obj-pci-$(CONFIG_MACH_WRT300NV2) += wrt300nv2-pci.o
+ obj-pci-$(CONFIG_MACH_AP1000) += ixdp425-pci.o
++obj-pci-$(CONFIG_MACH_TW2662) += tw2662-pci.o
+ obj-pci-$(CONFIG_MACH_TW5334) += tw5334-pci.o
+ obj-pci-$(CONFIG_MACH_MI424WR) += mi424wr-pci.o
+ obj-pci-$(CONFIG_MACH_USR8200) += usr8200-pci.o
+@@ -54,6 +55,7 @@ obj-$(CONFIG_MACH_SIDEWINDER) += sidewin
+ obj-$(CONFIG_MACH_COMPEXWP18) += compex42x-setup.o
+ obj-$(CONFIG_MACH_WRT300NV2) += wrt300nv2-setup.o
+ obj-$(CONFIG_MACH_AP1000) += ap1000-setup.o
++obj-$(CONFIG_MACH_TW2662) += tw2662-setup.o
+ obj-$(CONFIG_MACH_TW5334) += tw5334-setup.o
+ obj-$(CONFIG_MACH_MI424WR) += mi424wr-setup.o
+ obj-$(CONFIG_MACH_USR8200) += usr8200-setup.o
+--- a/arch/arm/mach-ixp4xx/include/mach/uncompress.h
++++ b/arch/arm/mach-ixp4xx/include/mach/uncompress.h
+@@ -45,7 +45,7 @@ static __inline__ void __arch_decomp_set
+ machine_is_devixp() || machine_is_miccpt() || machine_is_mic256() ||
+ machine_is_pronghorn() || machine_is_pronghorn_metro() ||
+ machine_is_wrt300nv2() || machine_is_tw5334() ||
+- machine_is_usr8200())
++ machine_is_usr8200() || machine_is_tw2662())
+ uart_base = (volatile u32*) IXP4XX_UART2_BASE_PHYS;
+ else
+ uart_base = (volatile u32*) IXP4XX_UART1_BASE_PHYS;
+--- /dev/null
++++ b/arch/arm/mach-ixp4xx/tw2662-pci.c
+@@ -0,0 +1,67 @@
++/*
++ * arch/arm/mach-ixp4xx/tw2662-pci.c
++ *
++ * PCI setup routines for Tiran Wireless TW-266-2 platform
++ *
++ * Copyright (C) 2002 Jungo Software Technologies.
++ * Copyright (C) 2003 MontaVista Softwrae, Inc.
++ * Copyright (C) 2010 Alexandros C. Couloumbis <alex@ozo.com>
++ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * Maintainer: Deepak Saxena <dsaxena@mvista.com>
++ * Maintainer: Alexandros C. Couloumbis <alex@ozo.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/irq.h>
++#include <asm/mach-types.h>
++#include <mach/hardware.h>
++#include <asm/irq.h>
++#include <asm/mach/pci.h>
++
++#define SLOT0_DEVID 1
++#define SLOT1_DEVID 3
++
++/* PCI controller GPIO to IRQ pin mappings */
++#define SLOT0_INTA 11
++#define SLOT1_INTA 9
++
++void __init tw2662_pci_preinit(void)
++{
++ irq_set_irq_type(IXP4XX_GPIO_IRQ(SLOT0_INTA), IRQ_TYPE_LEVEL_LOW);
++ irq_set_irq_type(IXP4XX_GPIO_IRQ(SLOT1_INTA), IRQ_TYPE_LEVEL_LOW);
++ ixp4xx_pci_preinit();
++}
++
++static int __init tw2662_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
++{
++ if (slot == SLOT0_DEVID)
++ return IXP4XX_GPIO_IRQ(SLOT0_INTA);
++ else if (slot == SLOT1_DEVID)
++ return IXP4XX_GPIO_IRQ(SLOT1_INTA);
++ else return -1;
++}
++
++struct hw_pci tw2662_pci __initdata = {
++ .nr_controllers = 1,
++ .preinit = tw2662_pci_preinit,
++ .ops = &ixp4xx_ops,
++ .setup = ixp4xx_setup,
++ .map_irq = tw2662_map_irq,
++};
++
++int __init tw2662_pci_init(void)
++{
++ if (machine_is_tw2662())
++ pci_common_init(&tw2662_pci);
++ return 0;
++}
++
++subsys_initcall(tw2662_pci_init);
+--- /dev/null
++++ b/arch/arm/mach-ixp4xx/tw2662-setup.c
+@@ -0,0 +1,197 @@
++/*
++ * arch/arm/mach-ixp4xx/tw2662-setup.c
++ *
++ * Titan Wireless TW-266-2
++ *
++ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2010 Alexandros C. Couloumbis <alex@ozo.com>
++ *
++ * based on ap1000-setup.c:
++ * Author: Imre Kaloz <Kaloz@openwrt.org>
++ */
++
++#include <linux/if_ether.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/device.h>
++#include <linux/serial.h>
++#include <linux/tty.h>
++#include <linux/serial_8250.h>
++#include <linux/slab.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/platform_device.h>
++
++#include <asm/io.h>
++#include <asm/types.h>
++#include <asm/setup.h>
++#include <asm/memory.h>
++#include <mach/hardware.h>
++#include <asm/mach-types.h>
++#include <asm/irq.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/flash.h>
++
++/* gpio mask used by platform device */
++#define TW2662_GPIO_MASK (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7)
++
++static struct flash_platform_data tw2662_flash_data = {
++ .map_name = "cfi_probe",
++ .width = 2,
++};
++
++static struct resource tw2662_flash_resource = {
++ .flags = IORESOURCE_MEM,
++};
++
++static struct platform_device tw2662_flash = {
++ .name = "IXP4XX-Flash",
++ .id = 0,
++ .dev = {
++ .platform_data = &tw2662_flash_data,
++ },
++ .num_resources = 1,
++ .resource = &tw2662_flash_resource,
++};
++
++static struct resource tw2662_uart_resources[] = {
++ {
++ .start = IXP4XX_UART1_BASE_PHYS,
++ .end = IXP4XX_UART1_BASE_PHYS + 0x0fff,
++ .flags = IORESOURCE_MEM
++ },
++ {
++ .start = IXP4XX_UART2_BASE_PHYS,
++ .end = IXP4XX_UART2_BASE_PHYS + 0x0fff,
++ .flags = IORESOURCE_MEM
++ }
++};
++
++static struct plat_serial8250_port tw2662_uart_data[] = {
++ {
++ .mapbase = IXP4XX_UART1_BASE_PHYS,
++ .membase = (char *)IXP4XX_UART1_BASE_VIRT + REG_OFFSET,
++ .irq = IRQ_IXP4XX_UART1,
++ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
++ .iotype = UPIO_MEM,
++ .regshift = 2,
++ .uartclk = IXP4XX_UART_XTAL,
++ },
++ {
++ .mapbase = IXP4XX_UART2_BASE_PHYS,
++ .membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
++ .irq = IRQ_IXP4XX_UART2,
++ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
++ .iotype = UPIO_MEM,
++ .regshift = 2,
++ .uartclk = IXP4XX_UART_XTAL,
++ },
++ { },
++};
++
++static struct platform_device tw2662_uart = {
++ .name = "serial8250",
++ .id = PLAT8250_DEV_PLATFORM,
++ .dev.platform_data = tw2662_uart_data,
++ .num_resources = 2,
++ .resource = tw2662_uart_resources
++};
++
++/* Built-in 10/100 Ethernet MAC interfaces */
++static struct eth_plat_info tw2662_plat_eth[] = {
++ {
++ .phy = 3,
++ .rxq = 3,
++ .txreadyq = 20,
++ }, {
++ .phy = 1,
++ .rxq = 4,
++ .txreadyq = 21,
++ }
++};
++
++static struct platform_device tw2662_eth[] = {
++ {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEB,
++ .dev.platform_data = tw2662_plat_eth,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++ }, {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEC,
++ .dev.platform_data = tw2662_plat_eth + 1,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++ }
++};
++
++
++static struct platform_device *tw2662_devices[] __initdata = {
++ &tw2662_flash,
++ &tw2662_uart,
++ &tw2662_eth[0],
++ &tw2662_eth[1],
++};
++
++static char tw2662_mem_fixup[] __initdata = "mem=64M ";
++
++static void __init tw2662_fixup(struct tag *tags, char **cmdline,
++ struct meminfo *mi)
++{
++ struct tag *t = tags;
++ char *p = *cmdline;
++
++ /* Find the end of the tags table, taking note of any cmdline tag. */
++ for (; t->hdr.size; t = tag_next(t)) {
++ if (t->hdr.tag == ATAG_CMDLINE) {
++ p = t->u.cmdline.cmdline;
++ }
++ }
++
++ /* Overwrite the end of the table with a new cmdline tag. */
++ t->hdr.tag = ATAG_CMDLINE;
++ t->hdr.size = (sizeof (struct tag_header) +
++ strlen(tw2662_mem_fixup) + strlen(p) + 1 + 4) >> 2;
++ strlcpy(t->u.cmdline.cmdline, tw2662_mem_fixup, COMMAND_LINE_SIZE);
++ strlcpy(t->u.cmdline.cmdline + strlen(tw2662_mem_fixup), p,
++ COMMAND_LINE_SIZE - strlen(tw2662_mem_fixup));
++
++ /* Terminate the table. */
++ t = tag_next(t);
++ t->hdr.tag = ATAG_NONE;
++ t->hdr.size = 0;
++}
++
++static void __init tw2662_init(void)
++{
++ ixp4xx_sys_init();
++
++ tw2662_flash_resource.start = IXP4XX_EXP_BUS_BASE(0);
++ tw2662_flash_resource.end =
++ IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1;
++
++ platform_add_devices(tw2662_devices, ARRAY_SIZE(tw2662_devices));
++
++ if (!(is_valid_ether_addr(tw2662_plat_eth[0].hwaddr)))
++ random_ether_addr(tw2662_plat_eth[0].hwaddr);
++ if (!(is_valid_ether_addr(tw2662_plat_eth[1].hwaddr))) {
++ memcpy(tw2662_plat_eth[1].hwaddr, tw2662_plat_eth[0].hwaddr, ETH_ALEN);
++ tw2662_plat_eth[1].hwaddr[5] = (tw2662_plat_eth[0].hwaddr[5] + 1);
++ }
++
++}
++
++#ifdef CONFIG_MACH_TW2662
++MACHINE_START(TW2662, "Titan Wireless TW-266-2")
++ /* Maintainer: Alexandros C. Couloumbis <alex@ozo.com> */
++ .fixup = tw2662_fixup,
++ .map_io = ixp4xx_map_io,
++ .init_irq = ixp4xx_init_irq,
++ .init_time = ixp4xx_timer_init,
++ .atag_offset = 0x0100,
++ .init_machine = tw2662_init,
++#if defined(CONFIG_PCI)
++ .dma_zone_size = SZ_64M,
++#endif
++ .restart = ixp4xx_restart,
++MACHINE_END
++#endif
diff --git a/target/linux/ixp4xx/patches-4.4/530-ap42x_support.patch b/target/linux/ixp4xx/patches-4.4/530-ap42x_support.patch
new file mode 100644
index 0000000000..1afbe3d61e
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/530-ap42x_support.patch
@@ -0,0 +1,282 @@
+--- a/arch/arm/mach-ixp4xx/Kconfig
++++ b/arch/arm/mach-ixp4xx/Kconfig
+@@ -4,6 +4,14 @@ menu "Intel IXP4xx Implementation Option
+
+ comment "IXP4xx Platforms"
+
++config MACH_AP42X
++ bool "Tonze AP-422/425"
++ select PCI
++ help
++ Say 'Y' here if you want your kernel to support Tonze's
++ AP-422/425 boards. For more information on this platform,
++ see http://tonze.com.tw
++
+ config MACH_NSLU2
+ bool
+ prompt "Linksys NSLU2"
+--- a/arch/arm/mach-ixp4xx/Makefile
++++ b/arch/arm/mach-ixp4xx/Makefile
+@@ -5,6 +5,7 @@
+ obj-pci-y :=
+ obj-pci-n :=
+
++obj-pci-$(CONFIG_MACH_AP42X) += ap42x-pci.o
+ obj-pci-$(CONFIG_ARCH_IXDP4XX) += ixdp425-pci.o
+ obj-pci-$(CONFIG_MACH_AVILA) += avila-pci.o
+ obj-pci-$(CONFIG_MACH_CAMBRIA) += cambria-pci.o
+@@ -32,6 +33,7 @@ obj-pci-$(CONFIG_MACH_USR8200) += usr82
+
+ obj-y += common.o
+
++obj-$(CONFIG_MACH_AP42X) += ap42x-setup.o
+ obj-$(CONFIG_ARCH_IXDP4XX) += ixdp425-setup.o
+ obj-$(CONFIG_MACH_AVILA) += avila-setup.o
+ obj-$(CONFIG_MACH_CAMBRIA) += cambria-setup.o
+--- /dev/null
++++ b/arch/arm/mach-ixp4xx/ap42x-pci.c
+@@ -0,0 +1,63 @@
++/*
++ * arch/arch/mach-ixp4xx/ap42x-pci.c
++ *
++ * PCI setup routines for Tonze AP-422/425
++ *
++ * Copyright (C) 2012 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * based on coyote-pci.c:
++ * Copyright (C) 2002 Jungo Software Technologies.
++ * Copyright (C) 2003 MontaVista Softwrae, Inc.
++ *
++ * Maintainer: Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/irq.h>
++
++#include <asm/mach-types.h>
++#include <mach/hardware.h>
++
++#include <asm/mach/pci.h>
++
++void __init ap42x_pci_preinit(void)
++{
++ irq_set_irq_type(IRQ_IXP4XX_GPIO10, IRQ_TYPE_LEVEL_LOW);
++ irq_set_irq_type(IRQ_IXP4XX_GPIO11, IRQ_TYPE_LEVEL_LOW);
++
++ ixp4xx_pci_preinit();
++}
++
++static int __init ap42x_map_irq(const struct pci_dev *dev, u8 slot,
++ u8 pin)
++{
++ if (slot == 1)
++ return IRQ_IXP4XX_GPIO11;
++ else if (slot == 2)
++ return IRQ_IXP4XX_GPIO10;
++ else return -1;
++}
++
++struct hw_pci ap42x_pci __initdata = {
++ .nr_controllers = 1,
++ .preinit = ap42x_pci_preinit,
++ .ops = &ixp4xx_ops,
++ .setup = ixp4xx_setup,
++ .map_irq = ap42x_map_irq,
++};
++
++int __init ap42x_pci_init(void)
++{
++ if (machine_is_ap42x())
++ pci_common_init(&ap42x_pci);
++ return 0;
++}
++
++subsys_initcall(ap42x_pci_init);
+--- /dev/null
++++ b/arch/arm/mach-ixp4xx/ap42x-setup.c
+@@ -0,0 +1,166 @@
++/*
++ * arch/arm/mach-ixp4xx/ap42x-setup.c
++ *
++ * Board setup for the Tonze AP-42x boards
++ *
++ * Copyright (C) 2012 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * based on coyote-setup.c:
++ * Copyright (C) 2003-2005 MontaVista Software, Inc.
++ *
++ * Author: Imre Kaloz <Kaloz@openwrt.org>
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/device.h>
++#include <linux/serial.h>
++#include <linux/tty.h>
++#include <linux/serial_8250.h>
++#include <linux/mtd/physmap.h>
++#include <linux/dma-mapping.h>
++
++#include <asm/types.h>
++#include <asm/setup.h>
++#include <asm/memory.h>
++#include <mach/hardware.h>
++#include <asm/irq.h>
++#include <asm/mach-types.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/flash.h>
++
++static struct mtd_partition ap42x_flash_partitions[] = {
++ {
++ .name = "RedBoot",
++ .offset = 0x00000000,
++ .size = 0x00080000,
++ }, {
++ .name = "linux",
++ .offset = 0x00080000,
++ .size = 0x00100000,
++ }, {
++ .name = "rootfs",
++ .offset = 0x00180000,
++ .size = 0x00660000,
++ }, {
++ .name = "FIS directory",
++ .offset = 0x007f8000,
++ .size = 0x00007000,
++ }, {
++ .name = "RedBoot config",
++ .offset = 0x007ff000,
++ .size = 0x00001000,
++ },
++};
++
++static struct physmap_flash_data ap42x_flash_data = {
++ .width = 2,
++ .parts = ap42x_flash_partitions,
++ .nr_parts = ARRAY_SIZE(ap42x_flash_partitions),
++};
++
++static struct resource ap42x_flash_resource = {
++ .flags = IORESOURCE_MEM,
++ .start = IXP4XX_EXP_BUS_BASE_PHYS,
++ .end = IXP4XX_EXP_BUS_BASE_PHYS + SZ_8M - 1,
++};
++
++static struct platform_device ap42x_flash = {
++ .name = "physmap-flash",
++ .id = 0,
++ .dev = {
++ .platform_data = &ap42x_flash_data,
++ },
++ .num_resources = 1,
++ .resource = &ap42x_flash_resource,
++};
++
++static struct resource ap42x_uart_resource = {
++ .start = IXP4XX_UART2_BASE_PHYS,
++ .end = IXP4XX_UART2_BASE_PHYS + 0x0fff,
++ .flags = IORESOURCE_MEM,
++};
++
++static struct plat_serial8250_port ap42x_uart_data[] = {
++ {
++ .mapbase = IXP4XX_UART2_BASE_PHYS,
++ .membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
++ .irq = IRQ_IXP4XX_UART2,
++ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
++ .iotype = UPIO_MEM,
++ .regshift = 2,
++ .uartclk = IXP4XX_UART_XTAL,
++ },
++ { },
++};
++
++static struct platform_device ap42x_uart = {
++ .name = "serial8250",
++ .id = PLAT8250_DEV_PLATFORM,
++ .dev = {
++ .platform_data = ap42x_uart_data,
++ },
++ .num_resources = 1,
++ .resource = &ap42x_uart_resource,
++};
++
++static struct eth_plat_info ap42x_plat_eth[] = {
++ {
++ .phy = 2,
++ .rxq = 3,
++ .txreadyq = 20,
++ }, {
++ .phy = 1,
++ .rxq = 4,
++ .txreadyq = 21,
++ }
++};
++
++static struct platform_device ap42x_eth[] = {
++ {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEB,
++ .dev.platform_data = ap42x_plat_eth,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++ }, {
++ .name = "ixp4xx_eth",
++ .id = IXP4XX_ETH_NPEC,
++ .dev.platform_data = ap42x_plat_eth + 1,
++ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
++ }
++};
++
++static struct platform_device *ap42x_devices[] __initdata = {
++ &ap42x_flash,
++ &ap42x_uart,
++ &ap42x_eth[0],
++ &ap42x_eth[1],
++};
++
++static void __init ap42x_init(void)
++{
++ ixp4xx_sys_init();
++
++ ap42x_flash_resource.start = IXP4XX_EXP_BUS_BASE(0);
++ ap42x_flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + SZ_32M - 1;
++
++ *IXP4XX_EXP_CS0 |= IXP4XX_FLASH_WRITABLE;
++ *IXP4XX_EXP_CS1 = *IXP4XX_EXP_CS0;
++
++ platform_add_devices(ap42x_devices, ARRAY_SIZE(ap42x_devices));
++}
++
++#ifdef CONFIG_MACH_AP42X
++MACHINE_START(AP42X, "Tonze AP-422/425")
++ /* Maintainer: Imre Kaloz <kaloz@openwrt.org> */
++ .map_io = ixp4xx_map_io,
++ .init_irq = ixp4xx_init_irq,
++ .init_time = ixp4xx_timer_init,
++ .atag_offset = 0x100,
++ .init_machine = ap42x_init,
++#if defined(CONFIG_PCI)
++ .dma_zone_size = SZ_64M,
++#endif
++ .restart = ixp4xx_restart,
++MACHINE_END
++#endif
+--- a/arch/arm/mach-ixp4xx/include/mach/uncompress.h
++++ b/arch/arm/mach-ixp4xx/include/mach/uncompress.h
+@@ -45,7 +45,8 @@ static __inline__ void __arch_decomp_set
+ machine_is_devixp() || machine_is_miccpt() || machine_is_mic256() ||
+ machine_is_pronghorn() || machine_is_pronghorn_metro() ||
+ machine_is_wrt300nv2() || machine_is_tw5334() ||
+- machine_is_usr8200() || machine_is_tw2662())
++ machine_is_usr8200() || machine_is_tw2662() ||
++ machine_is_ap42x())
+ uart_base = (volatile u32*) IXP4XX_UART2_BASE_PHYS;
+ else
+ uart_base = (volatile u32*) IXP4XX_UART1_BASE_PHYS;
diff --git a/target/linux/ixp4xx/patches-4.4/600-skb_avoid_dmabounce.patch b/target/linux/ixp4xx/patches-4.4/600-skb_avoid_dmabounce.patch
new file mode 100644
index 0000000000..e080e600f9
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/600-skb_avoid_dmabounce.patch
@@ -0,0 +1,23 @@
+--- a/net/core/skbuff.c
++++ b/net/core/skbuff.c
+@@ -214,6 +214,9 @@ struct sk_buff *__alloc_skb(unsigned int
+
+ if (sk_memalloc_socks() && (flags & SKB_ALLOC_RX))
+ gfp_mask |= __GFP_MEMALLOC;
++#ifdef CONFIG_ARCH_IXP4XX
++ gfp_mask |= GFP_DMA;
++#endif
+
+ /* Get the HEAD */
+ skb = kmem_cache_alloc_node(cache, gfp_mask & ~__GFP_DMA, node);
+@@ -1146,6 +1149,10 @@ int pskb_expand_head(struct sk_buff *skb
+ if (skb_shared(skb))
+ BUG();
+
++#ifdef CONFIG_ARCH_IXP4XX
++ gfp_mask |= GFP_DMA;
++#endif
++
+ size = SKB_DATA_ALIGN(size);
+
+ if (skb_pfmemalloc(skb))
diff --git a/target/linux/ixp4xx/patches-4.4/900-ixp4xx-crypto-include-module.h.patch b/target/linux/ixp4xx/patches-4.4/900-ixp4xx-crypto-include-module.h.patch
new file mode 100644
index 0000000000..24c93dc741
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/900-ixp4xx-crypto-include-module.h.patch
@@ -0,0 +1,10 @@
+--- a/drivers/crypto/ixp4xx_crypto.c
++++ b/drivers/crypto/ixp4xx_crypto.c
+@@ -14,6 +14,7 @@
+ #include <linux/dmapool.h>
+ #include <linux/crypto.h>
+ #include <linux/kernel.h>
++#include <linux/module.h>
+ #include <linux/rtnetlink.h>
+ #include <linux/interrupt.h>
+ #include <linux/spinlock.h>
diff --git a/target/linux/ixp4xx/patches-4.4/910-ixp4xx-nr_irq_lines.patch b/target/linux/ixp4xx/patches-4.4/910-ixp4xx-nr_irq_lines.patch
new file mode 100644
index 0000000000..06e09f469d
--- /dev/null
+++ b/target/linux/ixp4xx/patches-4.4/910-ixp4xx-nr_irq_lines.patch
@@ -0,0 +1,22 @@
+--- a/arch/arm/mach-ixp4xx/ixdp425-pci.c
++++ b/arch/arm/mach-ixp4xx/ixdp425-pci.c
+@@ -53,7 +53,7 @@ static int __init ixdp425_map_irq(const
+ };
+
+ if (slot >= 1 && slot <= MAX_DEV && pin >= 1 && pin <= IRQ_LINES)
+- return pci_irq_table[(slot + pin - 2) % 4];
++ return pci_irq_table[(slot + pin - 2) % IRQ_LINES];
+
+ return -1;
+ }
+--- a/arch/arm/mach-ixp4xx/miccpt-pci.c
++++ b/arch/arm/mach-ixp4xx/miccpt-pci.c
+@@ -54,7 +54,7 @@ static int __init miccpt_map_irq(const s
+ };
+
+ if (slot >= 1 && slot <= MAX_DEV && pin >= 1 && pin <= IRQ_LINES)
+- return pci_irq_table[(slot + pin - 2) % 4];
++ return pci_irq_table[(slot + pin - 2) % IRQ_LINES];
+
+ return -1;
+ }
diff --git a/target/linux/lantiq/dts/DGN3500.dtsi b/target/linux/lantiq/dts/DGN3500.dtsi
index 89a773791f..7854007e01 100644
--- a/target/linux/lantiq/dts/DGN3500.dtsi
+++ b/target/linux/lantiq/dts/DGN3500.dtsi
@@ -2,7 +2,7 @@
/ {
chosen {
- bootargs-append = "root= console=ttyLTQ0,115200";
+ bootargs = "root= console=ttyLTQ0,115200";
leds {
boot = &power_green;
diff --git a/target/linux/lantiq/patches-4.4/0001-MIPS-lantiq-add-pcie-driver.patch b/target/linux/lantiq/patches-4.4/0001-MIPS-lantiq-add-pcie-driver.patch
index afe32c29f4..f417b3ef0f 100644
--- a/target/linux/lantiq/patches-4.4/0001-MIPS-lantiq-add-pcie-driver.patch
+++ b/target/linux/lantiq/patches-4.4/0001-MIPS-lantiq-add-pcie-driver.patch
@@ -5495,7 +5495,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
(transaction layer end-to-end CRC checking).
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
-@@ -1229,6 +1229,8 @@ void pci_walk_bus(struct pci_bus *top, i
+@@ -1212,6 +1212,8 @@ void pci_walk_bus(struct pci_bus *top, i
void *userdata);
int pci_cfg_space_size(struct pci_dev *dev);
unsigned char pci_bus_max_busnr(struct pci_bus *bus);
diff --git a/target/linux/lantiq/patches-4.4/0022-MTD-m25p80-allow-loading-mtd-name-from-OF.patch b/target/linux/lantiq/patches-4.4/0022-MTD-m25p80-allow-loading-mtd-name-from-OF.patch
index 25f3fff213..57ef32d445 100644
--- a/target/linux/lantiq/patches-4.4/0022-MTD-m25p80-allow-loading-mtd-name-from-OF.patch
+++ b/target/linux/lantiq/patches-4.4/0022-MTD-m25p80-allow-loading-mtd-name-from-OF.patch
@@ -22,7 +22,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
-@@ -182,6 +183,10 @@ static int m25p_probe(struct spi_device
+@@ -204,6 +205,10 @@ static int m25p_probe(struct spi_device
enum read_mode mode = SPI_NOR_NORMAL;
char *flash_name = NULL;
int ret;
@@ -33,7 +33,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
data = dev_get_platdata(&spi->dev);
-@@ -212,6 +217,8 @@ static int m25p_probe(struct spi_device
+@@ -234,6 +239,8 @@ static int m25p_probe(struct spi_device
if (data && data->name)
nor->mtd.name = data->name;
diff --git a/target/linux/mediatek/Makefile b/target/linux/mediatek/Makefile
index 0415d245ec..17deab16a3 100644
--- a/target/linux/mediatek/Makefile
+++ b/target/linux/mediatek/Makefile
@@ -5,9 +5,9 @@ include $(TOPDIR)/rules.mk
ARCH:=arm
BOARD:=mediatek
BOARDNAME:=Mediatek Ralink ARM
-FEATURES:=squashfs
+FEATURES:=squashfs jffs2
CPU_TYPE:=cortex-a7
-MAINTAINER:=John Crispin <blogic@openwrt.org>
+MAINTAINER:=John Crispin <john@phrozen.org>
KERNEL_PATCHVER:=4.4
diff --git a/target/linux/mediatek/base-files/etc/board.d/02_network b/target/linux/mediatek/base-files/etc/board.d/02_network
index b936d0e150..1d1b5c021a 100755
--- a/target/linux/mediatek/base-files/etc/board.d/02_network
+++ b/target/linux/mediatek/base-files/etc/board.d/02_network
@@ -10,6 +10,8 @@ mediatek_setup_interfaces()
local board="$1"
case $board in
+ eMMC | \
+ NAND | \
mt7623_evb)
ucidef_set_interfaces_lan_wan "eth0" "eth1"
ucidef_add_switch "switch0" \
diff --git a/target/linux/mediatek/config-4.4 b/target/linux/mediatek/config-4.4
index cd8b915fd6..b20ae5d6a9 100644
--- a/target/linux/mediatek/config-4.4
+++ b/target/linux/mediatek/config-4.4
@@ -59,7 +59,7 @@ CONFIG_CLKSRC_MMIO=y
CONFIG_CLKSRC_OF=y
CONFIG_CLKSRC_PROBE=y
CONFIG_CLONE_BACKWARDS=y
-CONFIG_CMDLINE="earlyprintk console=ttyS0,115200 block2mtd.block2mtd=/dev/mmcblk0,65536,eMMC,5 mtdparts=eMMC:256k(mbr)ro,512k(uboot)ro,256k(config)ro,256k(factory)ro,32M(kernel),32M(recovery),1024M(rootfs),2048M(usrdata),-(bmtpool)"
+CONFIG_CMDLINE="earlyprintk console=ttyS0,115200 block2mtd.block2mtd=/dev/mmcblk0,65536,eMMC,5 mtdparts=eMMC:256k(mbr)ro,512k(uboot)ro,256k(config)ro,256k(factory)ro,32M(kernel),32M(recovery),1024M(rootfs),2048M(usrdata),-(bmtpool) rootfstype=squashfs,jffs2"
CONFIG_CMDLINE_FORCE=y
CONFIG_COMMON_CLK=y
CONFIG_COMMON_CLK_MEDIATEK=y
@@ -296,9 +296,10 @@ CONFIG_MODULES_USE_ELF_REL=y
CONFIG_MTD_BLOCK2MTD=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_M25P80=y
+CONFIG_MTD_MT81xx_NOR=y
CONFIG_MTD_NAND=y
CONFIG_MTD_NAND_ECC=y
-CONFIG_MTD_NAND_MTKSDG1=y
+CONFIG_MTD_NAND_MTK=y
CONFIG_MTD_SPI_NOR=y
CONFIG_MTK_INFRACFG=y
CONFIG_MTK_PMIC_WRAP=y
@@ -406,6 +407,10 @@ CONFIG_PREEMPT_COUNT=y
# CONFIG_PREEMPT_NONE is not set
CONFIG_PREEMPT_RCU=y
CONFIG_PRINTK_TIME=y
+CONFIG_PWM=y
+CONFIG_PWM_MEDIATEK=y
+# CONFIG_PWM_MTK_DISP is not set
+CONFIG_PWM_SYSFS=y
CONFIG_RATIONAL=y
CONFIG_RCU_CPU_STALL_TIMEOUT=21
# CONFIG_RCU_EXPERT is not set
diff --git a/target/linux/mediatek/files/arch/arm/boot/dts/_mt7623.dtsi b/target/linux/mediatek/files/arch/arm/boot/dts/_mt7623.dtsi
new file mode 100644
index 0000000000..4afcc75096
--- /dev/null
+++ b/target/linux/mediatek/files/arch/arm/boot/dts/_mt7623.dtsi
@@ -0,0 +1,615 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: John Crispin <blogic@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/clock/mt2701-clk.h>
+#include <dt-bindings/power/mt2701-power.h>
+#include <dt-bindings/phy/phy.h>
+#include <dt-bindings/reset-controller/mt2701-resets.h>
+#include <dt-bindings/pinctrl/mt7623-pinfunc.h>
+#include "skeleton64.dtsi"
+
+
+/ {
+ compatible = "mediatek,mt7623";
+ interrupt-parent = <&sysirq>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ enable-method = "mediatek,mt6589-smp";
+
+ cpu0: cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x0>;
+ clocks = <&infracfg CLK_INFRA_CPUSEL>,
+ <&apmixedsys CLK_APMIXED_MAINPLL>;
+ clock-names = "cpu", "intermediate";
+ operating-points = <
+ 598000 1150000
+ 747500 1150000
+ 1040000 1150000
+ 1196000 1200000
+ 1300000 1300000
+ >;
+ };
+ cpu1: cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x1>;
+ clocks = <&infracfg CLK_INFRA_CPUSEL>,
+ <&apmixedsys CLK_APMIXED_MAINPLL>;
+ clock-names = "cpu", "intermediate";
+ operating-points = <
+ 598000 1150000
+ 747500 1150000
+ 1040000 1150000
+ 1196000 1200000
+ 1300000 1300000
+ >;
+ };
+ cpu2: cpu@2 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x2>;
+ clocks = <&infracfg CLK_INFRA_CPUSEL>,
+ <&apmixedsys CLK_APMIXED_MAINPLL>;
+ clock-names = "cpu", "intermediate";
+ operating-points = <
+ 598000 1150000
+ 747500 1150000
+ 1040000 1150000
+ 1196000 1200000
+ 1300000 1300000
+ >;
+ };
+ cpu3: cpu@3 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x3>;
+ clocks = <&infracfg CLK_INFRA_CPUSEL>,
+ <&apmixedsys CLK_APMIXED_MAINPLL>;
+ clock-names = "cpu", "intermediate";
+ operating-points = <
+ 598000 1150000
+ 747500 1150000
+ 1040000 1150000
+ 1196000 1200000
+ 1300000 1300000
+ >;
+ };
+ };
+
+ system_clk: dummy13m {
+ compatible = "fixed-clock";
+ clock-frequency = <13000000>;
+ #clock-cells = <0>;
+ };
+
+ rtc_clk: dummy32k {
+ compatible = "fixed-clock";
+ clock-frequency = <32000>;
+ #clock-cells = <0>;
+ clock-output-names = "clk32k";
+ };
+
+ clk26m: dummy26m {
+ compatible = "fixed-clock";
+ clock-frequency = <26000000>;
+ #clock-cells = <0>;
+ clock-output-names = "clk26m";
+ };
+
+ timer {
+ compatible = "arm,armv7-timer";
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
+ <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
+ <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
+ <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+ clock-frequency = <13000000>;
+ arm,cpu-registers-not-fw-configured;
+ };
+
+ topckgen: power-controller@10000000 {
+ compatible = "mediatek,mt7623-topckgen",
+ "mediatek,mt2701-topckgen",
+ "syscon";
+ reg = <0 0x10000000 0 0x1000>;
+ #clock-cells = <1>;
+ };
+
+ infracfg: power-controller@10001000 {
+ compatible = "mediatek,mt7623-infracfg",
+ "mediatek,mt2701-infracfg",
+ "syscon";
+ reg = <0 0x10001000 0 0x1000>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+ pericfg: pericfg@10003000 {
+ compatible = "mediatek,mt7623-pericfg",
+ "mediatek,mt2701-pericfg",
+ "syscon";
+ reg = <0 0x10003000 0 0x1000>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+ pio: pinctrl@10005000 {
+ compatible = "mediatek,mt7623-pinctrl";
+ reg = <0 0x1000b000 0 0x1000>;
+ mediatek,pctl-regmap = <&syscfg_pctl_a>;
+ pins-are-numbered;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ interrupt-parent = <&gic>;
+ #interrupt-cells = <2>;
+ interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ syscfg_pctl_a: syscfg@10005000 {
+ compatible = "mediatek,mt7623-pctl-a-syscfg", "syscon";
+ reg = <0 0x10005000 0 0x1000>;
+ };
+
+ scpsys: scpsys@10006000 {
+ #power-domain-cells = <1>;
+ compatible = "mediatek,mt7623-scpsys",
+ "mediatek,mt2701-scpsys";
+ reg = <0 0x10006000 0 0x1000>;
+ infracfg = <&infracfg>;
+ clocks = <&clk26m>,
+ <&topckgen CLK_TOP_MM_SEL>;
+ clock-names = "mfg", "mm";
+ };
+
+ watchdog: watchdog@10007000 {
+ compatible = "mediatek,mt7623-wdt",
+ "mediatek,mt6589-wdt";
+ reg = <0 0x10007000 0 0x100>;
+ };
+
+ timer: timer@10008000 {
+ compatible = "mediatek,mt7623-timer",
+ "mediatek,mt6577-timer";
+ reg = <0 0x10008000 0 0x80>;
+ interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&system_clk>, <&rtc_clk>;
+ clock-names = "system-clk", "rtc-clk";
+ };
+
+ pwrap: pwrap@1000d000 {
+ compatible = "mediatek,mt7623-pwrap",
+ "mediatek,mt2701-pwrap";
+ reg = <0 0x1000d000 0 0x1000>;
+ reg-names = "pwrap";
+ interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>;
+ resets = <&infracfg MT2701_INFRA_PMIC_WRAP_RST>;
+ reset-names = "pwrap";
+ clocks = <&infracfg CLK_INFRA_PMICSPI>,
+ <&infracfg CLK_INFRA_PMICWRAP>;
+ clock-names = "spi", "wrap";
+ };
+
+ sysirq: interrupt-controller@10200100 {
+ compatible = "mediatek,mt7623-sysirq",
+ "mediatek,mt6577-sysirq";
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ interrupt-parent = <&gic>;
+ reg = <0 0x10200100 0 0x1c>;
+ };
+
+ apmixedsys: apmixedsys@10209000 {
+ compatible = "mediatek,mt7623-apmixedsys",
+ "mediatek,mt2701-apmixedsys";
+ reg = <0 0x10209000 0 0x1000>;
+ #clock-cells = <1>;
+ };
+
+ gic: interrupt-controller@10211000 {
+ compatible = "arm,cortex-a7-gic";
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ interrupt-parent = <&gic>;
+ reg = <0 0x10211000 0 0x1000>,
+ <0 0x10212000 0 0x1000>,
+ <0 0x10214000 0 0x2000>,
+ <0 0x10216000 0 0x2000>;
+ };
+
+ i2c0: i2c@11007000 {
+ compatible = "mediatek,mt7623-i2c",
+ "mediatek,mt6577-i2c";
+ reg = <0 0x11007000 0 0x70>,
+ <0 0x11000200 0 0x80>;
+ interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_LOW>;
+ clock-div = <16>;
+ clocks = <&pericfg CLK_PERI_I2C0>,
+ <&pericfg CLK_PERI_AP_DMA>;
+ clock-names = "main", "dma";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c1: i2c@11008000 {
+ compatible = "mediatek,mt7623-i2c",
+ "mediatek,mt6577-i2c";
+ reg = <0 0x11008000 0 0x70>,
+ <0 0x11000280 0 0x80>;
+ interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_LOW>;
+ clock-div = <16>;
+ clocks = <&pericfg CLK_PERI_I2C1>,
+ <&pericfg CLK_PERI_AP_DMA>;
+ clock-names = "main", "dma";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c2: i2c@11009000 {
+ compatible = "mediatek,mt7623-i2c",
+ "mediatek,mt6577-i2c";
+ reg = <0 0x11009000 0 0x70>,
+ <0 0x11000300 0 0x80>;
+ interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_LOW>;
+ clock-div = <16>;
+ clocks = <&pericfg CLK_PERI_I2C2>,
+ <&pericfg CLK_PERI_AP_DMA>;
+ clock-names = "main", "dma";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ uart0: serial@11002000 {
+ compatible = "mediatek,mt7623-uart",
+ "mediatek,mt6577-uart";
+ reg = <0 0x11002000 0 0x400>;
+ interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&pericfg CLK_PERI_UART0_SEL>,
+ <&pericfg CLK_PERI_UART0>;
+ clock-names = "baud", "bus";
+ status = "disabled";
+ };
+
+ uart1: serial@11003000 {
+ compatible = "mediatek,mt7623-uart",
+ "mediatek,mt6577-uart";
+ reg = <0 0x11003000 0 0x400>;
+ interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&pericfg CLK_PERI_UART1_SEL>,
+ <&pericfg CLK_PERI_UART1>;
+ clock-names = "baud", "bus";
+ status = "disabled";
+ };
+
+ uart2: serial@11004000 {
+ compatible = "mediatek,mt7623-uart",
+ "mediatek,mt6577-uart";
+ reg = <0 0x11004000 0 0x400>;
+ interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&pericfg CLK_PERI_UART2_SEL>,
+ <&pericfg CLK_PERI_UART2>;
+ clock-names = "baud", "bus";
+ status = "disabled";
+ };
+
+ uart3: serial@11005000 {
+ compatible = "mediatek,mt7623-uart",
+ "mediatek,mt6577-uart";
+ reg = <0 0x11005000 0 0x400>;
+ interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&pericfg CLK_PERI_UART3_SEL>,
+ <&pericfg CLK_PERI_UART3>;
+ clock-names = "baud", "bus";
+ status = "disabled";
+ };
+
+ pwm: pwm@11006000 {
+ compatible = "mediatek,mt7623-pwm";
+
+ reg = <0 0x11006000 0 0x1000>;
+
+ resets = <&pericfg MT2701_PERI_PWM_SW_RST>;
+ reset-names = "pwm";
+
+ #pwm-cells = <2>;
+ clocks = <&topckgen CLK_TOP_PWM_SEL>,
+ <&pericfg CLK_PERI_PWM>,
+ <&pericfg CLK_PERI_PWM1>,
+ <&pericfg CLK_PERI_PWM2>,
+ <&pericfg CLK_PERI_PWM3>,
+ <&pericfg CLK_PERI_PWM4>,
+ <&pericfg CLK_PERI_PWM5>;
+ clock-names = "top", "main", "pwm1", "pwm2",
+ "pwm3", "pwm4", "pwm5";
+
+ status = "disabled";
+ };
+
+ spi: spi@1100a000 {
+ compatible = "mediatek,mt7623-spi", "mediatek,mt6589-spi";
+ reg = <0 0x1100a000 0 0x1000>;
+ interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&pericfg CLK_PERI_SPI0>;
+ clock-names = "main";
+
+ status = "disabled";
+ };
+
+ nandc: nfi@1100d000 {
+ compatible = "mediatek,mt2701-nfc";
+ reg = <0 0x1100d000 0 0x1000>;
+ power-domains = <&scpsys MT2701_POWER_DOMAIN_IFR_MSC>;
+ interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&pericfg CLK_PERI_NFI>,
+ <&pericfg CLK_PERI_NFI_PAD>;
+ clock-names = "nfi_clk", "pad_clk";
+ status = "disabled";
+ ecc-engine = <&bch>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ bch: ecc@1100e000 {
+ compatible = "mediatek,mt2701-ecc";
+ reg = <0 0x1100e000 0 0x1000>;
+ interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&pericfg CLK_PERI_NFI_ECC>;
+ clock-names = "nfiecc_clk";
+ status = "disabled";
+ };
+
+ mmc0: mmc@11230000 {
+ compatible = "mediatek,mt7623-mmc",
+ "mediatek,mt8135-mmc";
+ reg = <0 0x11230000 0 0x1000>;
+ interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&pericfg CLK_PERI_MSDC30_0>,
+ <&topckgen CLK_TOP_MSDC30_0_SEL>;
+ clock-names = "source", "hclk";
+ status = "disabled";
+ };
+
+ mmc1: mmc@11240000 {
+ compatible = "mediatek,mt7623-mmc",
+ "mediatek,mt8135-mmc";
+ reg = <0 0x11240000 0 0x1000>;
+ interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&pericfg CLK_PERI_MSDC30_1>,
+ <&topckgen CLK_TOP_MSDC30_1_SEL>;
+ clock-names = "source", "hclk";
+ status = "disabled";
+ };
+
+ usb1: usb@1a1c0000 {
+ compatible = "mediatek,mt2701-xhci",
+ "mediatek,mt8173-xhci";
+ reg = <0 0x1a1c0000 0 0x1000>,
+ <0 0x1a1c4700 0 0x0100>;
+ interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&hifsys CLK_HIFSYS_USB0PHY>,
+ <&topckgen CLK_TOP_ETHIF_SEL>;
+ clock-names = "sys_ck", "ethif";
+ power-domains = <&scpsys MT2701_POWER_DOMAIN_HIF>;
+ phys = <&phy_port0 PHY_TYPE_USB3>;
+ status = "disabled";
+ };
+
+ u3phy1: usb-phy@1a1c4000 {
+ compatible = "mediatek,mt2701-u3phy",
+ "mediatek,mt8173-u3phy";
+ reg = <0 0x1a1c4000 0 0x0700>;
+ clocks = <&clk26m>;
+ clock-names = "u3phya_ref";
+ #phy-cells = <1>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+ status = "disabled";
+
+ phy_port0: phy_port0: port@1a1c4800 {
+ reg = <0 0x1a1c4800 0 0x800>;
+ #phy-cells = <1>;
+ status = "okay";
+ };
+ };
+
+ usb2: usb@1a240000 {
+ compatible = "mediatek,mt2701-xhci",
+ "mediatek,mt8173-xhci";
+ reg = <0 0x1a240000 0 0x1000>,
+ <0 0x1a244700 0 0x0100>;
+ interrupts = <GIC_SPI 197 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&hifsys CLK_HIFSYS_USB1PHY>,
+ <&topckgen CLK_TOP_ETHIF_SEL>;
+ clock-names = "sys_ck", "ethif";
+ power-domains = <&scpsys MT2701_POWER_DOMAIN_HIF>;
+ phys = <&u3phy2 0>;
+ status = "disabled";
+ };
+
+ u3phy2: usb-phy@1a244000 {
+ compatible = "mediatek,mt2701-u3phy",
+ "mediatek,mt8173-u3phy";
+ reg = <0 0x1a244000 0 0x0700>,
+ <0 0x1a244800 0 0x0800>;
+ clocks = <&clk26m>;
+ clock-names = "u3phya_ref";
+ #phy-cells = <1>;
+ status = "disabled";
+ };
+
+ hifsys: clock-controller@1a000000 {
+ compatible = "mediatek,mt7623-hifsys",
+ "mediatek,mt2701-hifsys",
+ "syscon";
+ reg = <0 0x1a000000 0 0x1000>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+ pcie: pcie@1a140000 {
+ compatible = "mediatek,mt7623-pcie";
+ device_type = "pci";
+ reg = <0 0x1a140000 0 0x8000>, /* PCI-Express registers */
+ <0 0x1a149000 0 0x1000>, /* PCI-Express PHY0 */
+ <0 0x1a14a000 0 0x1000>, /* PCI-Express PHY1 */
+ <0 0x1a244000 0 0x1000>; /* PCI-Express PHY2 */
+ reg-names = "pcie", "pcie phy0", "pcie phy1", "pcie phy2";
+ interrupts = <GIC_SPI 193 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 194 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 195 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-names = "pcie0", "pcie1", "pcie2";
+ clocks = <&topckgen CLK_TOP_ETHIF_SEL>;
+ clock-names = "pcie";
+ power-domains = <&scpsys MT2701_POWER_DOMAIN_HIF>;
+ resets = <&hifsys MT2701_HIFSYS_PCIE0_RST>,
+ <&hifsys MT2701_HIFSYS_PCIE1_RST>,
+ <&hifsys MT2701_HIFSYS_PCIE2_RST>;
+ reset-names = "pcie0", "pcie1", "pcie2";
+
+ mediatek,hifsys = <&hifsys>;
+
+ bus-range = <0x00 0xff>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+
+ ranges = <0x81000000 0 0x1a160000 0 0x1a160000 0 0x00010000 /* io space */
+ 0x83000000 0 0x60000000 0 0x60000000 0 0x10000000>; /* pci memory */
+
+ status = "disabled";
+
+ pcie@1,0 {
+ device_type = "pci";
+ reg = <0x0800 0 0 0 0>;
+
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges;
+ };
+
+ pcie@2,0{
+ device_type = "pci";
+ reg = <0x1000 0 0 0 0>;
+
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges;
+ };
+
+ pcie@3,0{
+ device_type = "pci";
+ reg = <0x1800 0 0 0 0>;
+
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges;
+ };
+ };
+
+ ethsys: syscon@1b000000 {
+ compatible = "mediatek,mt2701-ethsys", "syscon";
+ reg = <0 0x1b000000 0 0x1000>;
+ #reset-cells = <1>;
+ #clock-cells = <1>;
+ };
+
+ eth: ethernet@1b100000 {
+ compatible = "mediatek,mt7623-eth";
+ reg = <0 0x1b100000 0 0x20000>;
+
+ clocks = <&topckgen CLK_TOP_ETHIF_SEL>,
+ <&ethsys CLK_ETHSYS_ESW>,
+ <&ethsys CLK_ETHSYS_GP2>,
+ <&ethsys CLK_ETHSYS_GP1>;
+ clock-names = "ethif", "esw", "gp2", "gp1";
+ interrupts = <GIC_SPI 200 IRQ_TYPE_LEVEL_LOW
+ GIC_SPI 199 IRQ_TYPE_LEVEL_LOW
+ GIC_SPI 198 IRQ_TYPE_LEVEL_LOW>;
+ power-domains = <&scpsys MT2701_POWER_DOMAIN_ETH>;
+
+ resets = <&ethsys 6>;
+ reset-names = "eth";
+
+ mediatek,ethsys = <&ethsys>;
+ mediatek,pctl = <&syscfg_pctl_a>;
+
+ mediatek,switch = <&gsw>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ status = "disabled";
+
+ gmac1: mac@0 {
+ compatible = "mediatek,eth-mac";
+ reg = <0>;
+
+ status = "disabled";
+
+ phy-mode = "rgmii";
+
+ fixed-link {
+ speed = <1000>;
+ full-duplex;
+ pause;
+ };
+ };
+
+ gmac2: mac@1 {
+ compatible = "mediatek,eth-mac";
+ reg = <1>;
+
+ status = "disabled";
+ };
+
+ mdio-bus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ phy5: ethernet-phy@5 {
+ reg = <5>;
+ phy-mode = "rgmii-rxid";
+ };
+
+ phy1f: ethernet-phy@1f {
+ reg = <0x1f>;
+ phy-mode = "rgmii";
+ };
+ };
+ };
+
+ gsw: switch@1b100000 {
+ compatible = "mediatek,mt7623-gsw";
+ interrupt-parent = <&pio>;
+ interrupts = <168 IRQ_TYPE_EDGE_RISING>;
+ resets = <&ethsys 2>;
+ reset-names = "eth";
+ clocks = <&apmixedsys CLK_APMIXED_TRGPLL>;
+ clock-names = "trgpll";
+ mt7530-supply = <&mt6323_vpa_reg>;
+ mediatek,pctl-regmap = <&syscfg_pctl_a>;
+ mediatek,ethsys = <&ethsys>;
+ status = "disabled";
+ };
+};
diff --git a/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-NAND.dts b/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-NAND.dts
index d25e46ebae..43551f7a07 100644
--- a/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-NAND.dts
+++ b/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-NAND.dts
@@ -14,11 +14,11 @@
/dts-v1/;
-#include "mt7623.dtsi"
+#include "_mt7623.dtsi"
#include <dt-bindings/gpio/gpio.h>
/ {
- model = "MediaTek MT7623 evaluation board";
+ model = "MediaTek MT7623 NAND evaluation board";
compatible = "mediatek,mt7623-evb", "mediatek,mt7623";
chosen {
@@ -341,6 +341,16 @@
output-low;
};
};
+
+ pwm_pins: pwm {
+ pins_pwm1 {
+ pinmux = <MT7623_PIN_204_PWM1_FUNC_PWM1>;
+ };
+
+ pins_pwm2 {
+ pinmux = <MT7623_PIN_205_PWM2_FUNC_PWM2>;
+ };
+ };
};
&nandc {
@@ -416,6 +426,14 @@
&gmac2 {
mac-address = [00 11 22 33 44 55];
status = "okay";
+
+ phy-mode = "rgmii";
+
+ fixed-link {
+ speed = <1000>;
+ full-duplex;
+ pause;
+ };
};
&gsw {
@@ -424,3 +442,9 @@
mediatek,reset-pin = <&pio 15 0>;
status = "okay";
};
+
+&pwm {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm_pins>;
+ status = "okay";
+};
diff --git a/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-eMMC.dts b/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-eMMC.dts
index 2b75b44541..630240c730 100644
--- a/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-eMMC.dts
+++ b/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-eMMC.dts
@@ -14,7 +14,7 @@
/dts-v1/;
-#include "mt7623.dtsi"
+#include "_mt7623.dtsi"
#include <dt-bindings/gpio/gpio.h>
/ {
@@ -436,6 +436,16 @@
output-low;
};
};
+
+ pwm_pins: pwm {
+ pins_pwm1 {
+ pinmux = <MT7623_PIN_204_PWM1_FUNC_PWM1>;
+ };
+
+ pins_pwm2 {
+ pinmux = <MT7623_PIN_205_PWM2_FUNC_PWM2>;
+ };
+ };
};
&usb1 {
@@ -464,6 +474,7 @@
&gmac2 {
mac-address = [00 11 22 33 44 55];
status = "okay";
+ phy-handle = <&phy5>;
};
&gsw {
@@ -472,3 +483,9 @@
mediatek,reset-pin = <&pio 15 0>;
status = "okay";
};
+
+&pwm {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm_pins>;
+ status = "okay";
+};
diff --git a/target/linux/mediatek/image/Makefile b/target/linux/mediatek/image/Makefile
index 7169907142..b88d2dce2f 100644
--- a/target/linux/mediatek/image/Makefile
+++ b/target/linux/mediatek/image/Makefile
@@ -17,7 +17,7 @@ ifneq ($(CONFIG_TARGET_ROOTFS_INITRAMFS),)
endif
mkdir -p "$(KDIR_TMP)/sysupgrade-$(1)/"
echo "BOARD=$(1)" > "$(KDIR_TMP)/sysupgrade-$(1)/CONTROL"
- $(CP) "$(KDIR)/root.squashfs" "$(KDIR_TMP)/sysupgrade-$(1)/root"
+ $(CP) "$(KDIR)/root.$(2)" "$(KDIR_TMP)/sysupgrade-$(1)/root"
$(CP) "$(KDIR)/uImage-$(1)" "$(KDIR_TMP)/sysupgrade-$(1)/kernel"
(cd "$(KDIR_TMP)"; $(TAR) cvf \
"$(BIN_DIR)/$(IMG_PREFIX)-$(1)-sysupgrade.tar" sysupgrade-$(1) \
@@ -29,8 +29,13 @@ define Image/Build/squashfs
$(call prepare_generic_squashfs,$(KDIR)/root.squashfs)
$(CP) $(KDIR)/root.squashfs $(BIN_DIR)/$(IMG_PREFIX)-root.squashfs
- $(call Image/Build/SysupgradeCombined,eMMC)
- $(call Image/Build/SysupgradeCombined,NAND)
+ $(call Image/Build/SysupgradeCombined,eMMC,squashfs)
+endef
+
+define Image/Build/jffs2-128k
+ $(CP) $(KDIR)/root.jffs2-128k $(BIN_DIR)/$(IMG_PREFIX)-root.jffs2
+
+ $(call Image/Build/SysupgradeCombined,NAND,jffs2-128k)
endef
define Image/Build
diff --git a/target/linux/mediatek/patches-4.4/0001-NET-multi-phy-support.patch b/target/linux/mediatek/patches-4.4/0001-NET-multi-phy-support.patch
index 32b574992f..4b75613979 100644
--- a/target/linux/mediatek/patches-4.4/0001-NET-multi-phy-support.patch
+++ b/target/linux/mediatek/patches-4.4/0001-NET-multi-phy-support.patch
@@ -1,7 +1,7 @@
-From c30a296646a42302065ba452abe95b0b4b550883 Mon Sep 17 00:00:00 2001
+From 1e021917e634b173d466bf0dd3d2ae84e51a77ff Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 27 Jul 2014 09:38:50 +0100
-Subject: [PATCH 01/91] NET: multi phy support
+Subject: [PATCH 001/102] NET: multi phy support
Signed-off-by: John Crispin <blogic@openwrt.org>
---
@@ -9,11 +9,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
include/linux/phy.h | 1 +
2 files changed, 7 insertions(+), 3 deletions(-)
-diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
-index 47cd306..f69d12f 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
-@@ -844,7 +844,8 @@ void phy_state_machine(struct work_struct *work)
+@@ -888,7 +888,8 @@ void phy_state_machine(struct work_struc
/* If the link is down, give up on negotiation for now */
if (!phydev->link) {
phydev->state = PHY_NOLINK;
@@ -23,7 +21,7 @@ index 47cd306..f69d12f 100644
phydev->adjust_link(phydev->attached_dev);
break;
}
-@@ -927,7 +928,8 @@ void phy_state_machine(struct work_struct *work)
+@@ -971,7 +972,8 @@ void phy_state_machine(struct work_struc
netif_carrier_on(phydev->attached_dev);
} else {
phydev->state = PHY_NOLINK;
@@ -33,7 +31,7 @@ index 47cd306..f69d12f 100644
}
phydev->adjust_link(phydev->attached_dev);
-@@ -939,7 +941,8 @@ void phy_state_machine(struct work_struct *work)
+@@ -983,7 +985,8 @@ void phy_state_machine(struct work_struc
case PHY_HALTED:
if (phydev->link) {
phydev->link = 0;
@@ -43,8 +41,6 @@ index 47cd306..f69d12f 100644
phydev->adjust_link(phydev->attached_dev);
do_suspend = true;
}
-diff --git a/include/linux/phy.h b/include/linux/phy.h
-index 05fde31..276ab8a 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -377,6 +377,7 @@ struct phy_device {
@@ -55,6 +51,3 @@ index 05fde31..276ab8a 100644
enum phy_state state;
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0002-soc-mediatek-Separate-scpsys-driver-common-code.patch b/target/linux/mediatek/patches-4.4/0002-soc-mediatek-Separate-scpsys-driver-common-code.patch
index 389a09ea8c..194e66970e 100644
--- a/target/linux/mediatek/patches-4.4/0002-soc-mediatek-Separate-scpsys-driver-common-code.patch
+++ b/target/linux/mediatek/patches-4.4/0002-soc-mediatek-Separate-scpsys-driver-common-code.patch
@@ -1,7 +1,7 @@
-From 2c93328ed05061a50e3bd4111379dbcf6946d3ac Mon Sep 17 00:00:00 2001
+From 1892fcf687116720d07135c83d489a23ec56a166 Mon Sep 17 00:00:00 2001
From: James Liao <jamesjj.liao@mediatek.com>
Date: Wed, 30 Dec 2015 14:41:43 +0800
-Subject: [PATCH 02/91] soc: mediatek: Separate scpsys driver common code
+Subject: [PATCH 002/102] soc: mediatek: Separate scpsys driver common code
Separate scpsys driver common code to mtk-scpsys.c, and move MT8173
platform code to mtk-scpsys-mt8173.c.
@@ -17,8 +17,6 @@ Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
create mode 100644 drivers/soc/mediatek/mtk-scpsys-mt8173.c
create mode 100644 drivers/soc/mediatek/mtk-scpsys.h
-diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig
-index 0a4ea80..eca6fb7 100644
--- a/drivers/soc/mediatek/Kconfig
+++ b/drivers/soc/mediatek/Kconfig
@@ -22,11 +22,20 @@ config MTK_PMIC_WRAP
@@ -44,8 +42,6 @@ index 0a4ea80..eca6fb7 100644
+ driver.
+ The System Control Processor System (SCPSYS) has several power
+ management related tasks in the system.
-diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile
-index 12998b0..3b22baa 100644
--- a/drivers/soc/mediatek/Makefile
+++ b/drivers/soc/mediatek/Makefile
@@ -1,3 +1,4 @@
@@ -53,9 +49,6 @@ index 12998b0..3b22baa 100644
obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o
obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o
+obj-$(CONFIG_MTK_SCPSYS_MT8173) += mtk-scpsys-mt8173.o
-diff --git a/drivers/soc/mediatek/mtk-scpsys-mt8173.c b/drivers/soc/mediatek/mtk-scpsys-mt8173.c
-new file mode 100644
-index 0000000..3c7b569
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-scpsys-mt8173.c
@@ -0,0 +1,179 @@
@@ -238,8 +231,6 @@ index 0000000..3c7b569
+};
+
+module_platform_driver_probe(scpsys_drv, scpsys_probe);
-diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
-index 4d4203c..a0943c5 100644
--- a/drivers/soc/mediatek/mtk-scpsys.c
+++ b/drivers/soc/mediatek/mtk-scpsys.c
@@ -11,28 +11,14 @@
@@ -257,7 +248,7 @@ index 4d4203c..a0943c5 100644
-#include <linux/regmap.h>
#include <linux/soc/mediatek/infracfg.h>
-#include <dt-bindings/power/mt8173-power.h>
--
+
-#define SPM_VDE_PWR_CON 0x0210
-#define SPM_MFG_PWR_CON 0x0214
-#define SPM_VEN_PWR_CON 0x0230
@@ -268,7 +259,6 @@ index 4d4203c..a0943c5 100644
-#define SPM_MFG_2D_PWR_CON 0x02c0
-#define SPM_MFG_ASYNC_PWR_CON 0x02c4
-#define SPM_USB_PWR_CON 0x02cc
-+
+#include "mtk-scpsys.h"
+
#define SPM_PWR_STATUS 0x060c
@@ -428,7 +418,7 @@ index 4d4203c..a0943c5 100644
static int scpsys_domain_is_on(struct scp_domain *scpd)
{
struct scp *scp = scpd->scp;
-@@ -398,63 +237,89 @@ static bool scpsys_active_wakeup(struct device *dev)
+@@ -398,63 +237,89 @@ static bool scpsys_active_wakeup(struct
return scpd->active_wakeup;
}
@@ -518,13 +508,13 @@ index 4d4203c..a0943c5 100644
+ return ERR_PTR(-ENOMEM);
+
+ pd_data = &scp->pd_data;
-+
+
+- for (i = 0; i < NUM_DOMAINS; i++) {
+ pd_data->domains = devm_kzalloc(&pdev->dev,
+ sizeof(*pd_data->domains) * num, GFP_KERNEL);
+ if (!pd_data->domains)
+ return ERR_PTR(-ENOMEM);
-
-- for (i = 0; i < NUM_DOMAINS; i++) {
++
+ pd_data->num_domains = num;
+
+ init_clks(pdev, clk);
@@ -549,7 +539,7 @@ index 4d4203c..a0943c5 100644
pd_data->domains[i] = genpd;
scpd->scp = scp;
-@@ -464,13 +329,25 @@ static int __init scpsys_probe(struct platform_device *pdev)
+@@ -464,13 +329,25 @@ static int __init scpsys_probe(struct pl
scpd->sram_pdn_ack_bits = data->sram_pdn_ack_bits;
scpd->bus_prot_mask = data->bus_prot_mask;
scpd->active_wakeup = data->active_wakeup;
@@ -577,7 +567,7 @@ index 4d4203c..a0943c5 100644
/*
* Initially turn on all domains to make the domains usable
-@@ -489,37 +366,9 @@ static int __init scpsys_probe(struct platform_device *pdev)
+@@ -489,37 +366,9 @@ static int __init scpsys_probe(struct pl
* valid.
*/
@@ -616,9 +606,6 @@ index 4d4203c..a0943c5 100644
-};
-
-module_platform_driver_probe(scpsys_drv, scpsys_probe);
-diff --git a/drivers/soc/mediatek/mtk-scpsys.h b/drivers/soc/mediatek/mtk-scpsys.h
-new file mode 100644
-index 0000000..466728d
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-scpsys.h
@@ -0,0 +1,54 @@
@@ -676,6 +663,3 @@ index 0000000..466728d
+ struct scp *scp, int num);
+
+#endif /* __DRV_SOC_MTK_H */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0003-soc-mediatek-Init-MT8173-scpsys-driver-earlier.patch b/target/linux/mediatek/patches-4.4/0003-soc-mediatek-Init-MT8173-scpsys-driver-earlier.patch
index c1eabc1716..46af96450b 100644
--- a/target/linux/mediatek/patches-4.4/0003-soc-mediatek-Init-MT8173-scpsys-driver-earlier.patch
+++ b/target/linux/mediatek/patches-4.4/0003-soc-mediatek-Init-MT8173-scpsys-driver-earlier.patch
@@ -1,7 +1,7 @@
-From c359272f86805259c5801385d60fdeea9d629cf9 Mon Sep 17 00:00:00 2001
+From 6f87948c3a58f02f6a64eadda719317016739d5e Mon Sep 17 00:00:00 2001
From: James Liao <jamesjj.liao@mediatek.com>
Date: Wed, 30 Dec 2015 14:41:44 +0800
-Subject: [PATCH 03/91] soc: mediatek: Init MT8173 scpsys driver earlier
+Subject: [PATCH 003/102] soc: mediatek: Init MT8173 scpsys driver earlier
Some power domain comsumers may init before module_init.
So the power domain provider (scpsys) need to be initialized
@@ -12,11 +12,9 @@ Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
drivers/soc/mediatek/mtk-scpsys-mt8173.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
-diff --git a/drivers/soc/mediatek/mtk-scpsys-mt8173.c b/drivers/soc/mediatek/mtk-scpsys-mt8173.c
-index 3c7b569..827e696 100644
--- a/drivers/soc/mediatek/mtk-scpsys-mt8173.c
+++ b/drivers/soc/mediatek/mtk-scpsys-mt8173.c
-@@ -176,4 +176,15 @@ static struct platform_driver scpsys_drv = {
+@@ -176,4 +176,15 @@ static struct platform_driver scpsys_drv
},
};
@@ -33,6 +31,3 @@ index 3c7b569..827e696 100644
+
+subsys_initcall(scpsys_drv_init);
+module_exit(scpsys_drv_exit);
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0004-soc-mediatek-Add-MT2701-power-dt-bindings.patch b/target/linux/mediatek/patches-4.4/0004-soc-mediatek-Add-MT2701-power-dt-bindings.patch
index 42980394fa..132d6c89c8 100644
--- a/target/linux/mediatek/patches-4.4/0004-soc-mediatek-Add-MT2701-power-dt-bindings.patch
+++ b/target/linux/mediatek/patches-4.4/0004-soc-mediatek-Add-MT2701-power-dt-bindings.patch
@@ -1,7 +1,7 @@
-From f371844374fff273f817d6c43f679606417af59e Mon Sep 17 00:00:00 2001
+From 7c5b29de78f1b15c5bde40a6ca4510fc09588457 Mon Sep 17 00:00:00 2001
From: Shunli Wang <shunli.wang@mediatek.com>
Date: Wed, 30 Dec 2015 14:41:45 +0800
-Subject: [PATCH 04/91] soc: mediatek: Add MT2701 power dt-bindings
+Subject: [PATCH 004/102] soc: mediatek: Add MT2701 power dt-bindings
Add power dt-bindings for MT2701.
@@ -12,9 +12,6 @@ Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
1 file changed, 27 insertions(+)
create mode 100644 include/dt-bindings/power/mt2701-power.h
-diff --git a/include/dt-bindings/power/mt2701-power.h b/include/dt-bindings/power/mt2701-power.h
-new file mode 100644
-index 0000000..64cc826
--- /dev/null
+++ b/include/dt-bindings/power/mt2701-power.h
@@ -0,0 +1,27 @@
@@ -45,6 +42,3 @@ index 0000000..64cc826
+#define MT2701_POWER_DOMAIN_IFR_MSC 8
+
+#endif /* _DT_BINDINGS_POWER_MT2701_POWER_H */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0005-soc-mediatek-Add-MT2701-MT7623-scpsys-driver.patch b/target/linux/mediatek/patches-4.4/0005-soc-mediatek-Add-MT2701-MT7623-scpsys-driver.patch
index 158d6d0b2b..2f2337a8e3 100644
--- a/target/linux/mediatek/patches-4.4/0005-soc-mediatek-Add-MT2701-MT7623-scpsys-driver.patch
+++ b/target/linux/mediatek/patches-4.4/0005-soc-mediatek-Add-MT2701-MT7623-scpsys-driver.patch
@@ -1,7 +1,7 @@
-From c6711565985f359d7d3c05f01f081e4c216902de Mon Sep 17 00:00:00 2001
+From 8aa49d107d8a22fd6cbf37174614baf32d0976e2 Mon Sep 17 00:00:00 2001
From: Shunli Wang <shunli.wang@mediatek.com>
Date: Wed, 30 Dec 2015 14:41:46 +0800
-Subject: [PATCH 05/91] soc: mediatek: Add MT2701/MT7623 scpsys driver
+Subject: [PATCH 005/102] soc: mediatek: Add MT2701/MT7623 scpsys driver
Add scpsys driver for MT2701 and MT7623.
@@ -14,8 +14,6 @@ Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
3 files changed, 173 insertions(+)
create mode 100644 drivers/soc/mediatek/mtk-scpsys-mt2701.c
-diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig
-index eca6fb7..92cf838 100644
--- a/drivers/soc/mediatek/Kconfig
+++ b/drivers/soc/mediatek/Kconfig
@@ -39,3 +39,14 @@ config MTK_SCPSYS_MT8173
@@ -33,18 +31,13 @@ index eca6fb7..92cf838 100644
+ domain driver.
+ The System Control Processor System (SCPSYS) has several power
+ management related tasks in the system.
-diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile
-index 3b22baa..822986d 100644
--- a/drivers/soc/mediatek/Makefile
+++ b/drivers/soc/mediatek/Makefile
-@@ -2,3 +2,4 @@ obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o
+@@ -2,3 +2,4 @@ obj-$(CONFIG_MTK_INFRACFG) += mtk-infrac
obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o
obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o
obj-$(CONFIG_MTK_SCPSYS_MT8173) += mtk-scpsys-mt8173.o
+obj-$(CONFIG_MTK_SCPSYS_MT2701) += mtk-scpsys-mt2701.o
-diff --git a/drivers/soc/mediatek/mtk-scpsys-mt2701.c b/drivers/soc/mediatek/mtk-scpsys-mt2701.c
-new file mode 100644
-index 0000000..339d5b8
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-scpsys-mt2701.c
@@ -0,0 +1,161 @@
@@ -209,6 +202,3 @@ index 0000000..339d5b8
+
+MODULE_DESCRIPTION("MediaTek MT2701 scpsys driver");
+MODULE_LICENSE("GPL v2");
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0006-clk-mediatek-Refine-the-makefile-to-support-multiple.patch b/target/linux/mediatek/patches-4.4/0006-clk-mediatek-Refine-the-makefile-to-support-multiple.patch
index 62b825555d..d4bac233b9 100644
--- a/target/linux/mediatek/patches-4.4/0006-clk-mediatek-Refine-the-makefile-to-support-multiple.patch
+++ b/target/linux/mediatek/patches-4.4/0006-clk-mediatek-Refine-the-makefile-to-support-multiple.patch
@@ -1,8 +1,8 @@
-From 0c39bcd17fa6ce723f56ad3756b4bb36c4690342 Mon Sep 17 00:00:00 2001
+From 69d4e250847f82a5896c41bcb5f1e793c5a8fbac Mon Sep 17 00:00:00 2001
From: James Liao <jamesjj.liao@mediatek.com>
Date: Tue, 5 Jan 2016 14:30:17 +0800
-Subject: [PATCH 06/91] clk: mediatek: Refine the makefile to support multiple
- clock drivers
+Subject: [PATCH 006/102] clk: mediatek: Refine the makefile to support
+ multiple clock drivers
Add a Kconfig to define clock configuration for each SoC, and
modify the Makefile to build drivers that only selected in config.
@@ -16,8 +16,6 @@ Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
3 files changed, 27 insertions(+), 3 deletions(-)
create mode 100644 drivers/clk/mediatek/Kconfig
-diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
-index c3e3a02..b7a37dc 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -198,3 +198,4 @@ source "drivers/clk/mvebu/Kconfig"
@@ -25,9 +23,6 @@ index c3e3a02..b7a37dc 100644
source "drivers/clk/samsung/Kconfig"
source "drivers/clk/tegra/Kconfig"
+source "drivers/clk/mediatek/Kconfig"
-diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
-new file mode 100644
-index 0000000..dc224e6
--- /dev/null
+++ b/drivers/clk/mediatek/Kconfig
@@ -0,0 +1,23 @@
@@ -54,8 +49,6 @@ index 0000000..dc224e6
+ default ARCH_MEDIATEK
+ ---help---
+ This driver supports Mediatek MT8173 clocks.
-diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
-index 95fdfac..32e7222 100644
--- a/drivers/clk/mediatek/Makefile
+++ b/drivers/clk/mediatek/Makefile
@@ -1,4 +1,4 @@
@@ -66,6 +59,3 @@ index 95fdfac..32e7222 100644
-obj-y += clk-mt8173.o
+obj-$(CONFIG_COMMON_CLK_MT8135) += clk-mt8135.o
+obj-$(CONFIG_COMMON_CLK_MT8173) += clk-mt8173.o
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0007-dt-bindings-ARM-Mediatek-Document-bindings-for-MT270.patch b/target/linux/mediatek/patches-4.4/0007-dt-bindings-ARM-Mediatek-Document-bindings-for-MT270.patch
index 5c24ef8a0e..fd21c0b788 100644
--- a/target/linux/mediatek/patches-4.4/0007-dt-bindings-ARM-Mediatek-Document-bindings-for-MT270.patch
+++ b/target/linux/mediatek/patches-4.4/0007-dt-bindings-ARM-Mediatek-Document-bindings-for-MT270.patch
@@ -1,7 +1,7 @@
-From d7e96f87f66c571e9f4171ecd89c656fbd2de89b Mon Sep 17 00:00:00 2001
+From 7c98b20fa68a2a64bca69822eb7be4fa9b668fab Mon Sep 17 00:00:00 2001
From: James Liao <jamesjj.liao@mediatek.com>
Date: Tue, 5 Jan 2016 14:30:18 +0800
-Subject: [PATCH 07/91] dt-bindings: ARM: Mediatek: Document bindings for
+Subject: [PATCH 007/102] dt-bindings: ARM: Mediatek: Document bindings for
MT2701
This patch adds the binding documentation for apmixedsys, bdpsys,
@@ -25,11 +25,9 @@ Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
create mode 100644 Documentation/devicetree/bindings/arm/mediatek/mediatek,ethsys.txt
create mode 100644 Documentation/devicetree/bindings/arm/mediatek/mediatek,hifsys.txt
-diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,apmixedsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,apmixedsys.txt
-index 936166f..a701e19 100644
--- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,apmixedsys.txt
+++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,apmixedsys.txt
-@@ -6,6 +6,7 @@ The Mediatek apmixedsys controller provides the PLLs to the system.
+@@ -6,6 +6,7 @@ The Mediatek apmixedsys controller provi
Required Properties:
- compatible: Should be:
@@ -37,9 +35,6 @@ index 936166f..a701e19 100644
- "mediatek,mt8135-apmixedsys"
- "mediatek,mt8173-apmixedsys"
- #clock-cells: Must be 1
-diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,bdpsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,bdpsys.txt
-new file mode 100644
-index 0000000..4137196
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,bdpsys.txt
@@ -0,0 +1,22 @@
@@ -65,9 +60,6 @@ index 0000000..4137196
+ reg = <0 0x1c000000 0 0x1000>;
+ #clock-cells = <1>;
+};
-diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,ethsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,ethsys.txt
-new file mode 100644
-index 0000000..768f3a5
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,ethsys.txt
@@ -0,0 +1,22 @@
@@ -93,9 +85,6 @@ index 0000000..768f3a5
+ reg = <0 0x1b000000 0 0x1000>;
+ #clock-cells = <1>;
+};
-diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,hifsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,hifsys.txt
-new file mode 100644
-index 0000000..b7a39b6
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,hifsys.txt
@@ -0,0 +1,22 @@
@@ -121,11 +110,9 @@ index 0000000..b7a39b6
+ reg = <0 0x1a000000 0 0x1000>;
+ #clock-cells = <1>;
+};
-diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,imgsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,imgsys.txt
-index b1f2ce1..9bda7f7 100644
--- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,imgsys.txt
+++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,imgsys.txt
-@@ -6,6 +6,7 @@ The Mediatek imgsys controller provides various clocks to the system.
+@@ -6,6 +6,7 @@ The Mediatek imgsys controller provides
Required Properties:
- compatible: Should be:
@@ -133,8 +120,6 @@ index b1f2ce1..9bda7f7 100644
- "mediatek,mt8173-imgsys", "syscon"
- #clock-cells: Must be 1
-diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.txt
-index f6cd3e4..2f11a69 100644
--- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.txt
+++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.txt
@@ -7,6 +7,7 @@ outputs to the system.
@@ -145,11 +130,9 @@ index f6cd3e4..2f11a69 100644
- "mediatek,mt8135-infracfg", "syscon"
- "mediatek,mt8173-infracfg", "syscon"
- #clock-cells: Must be 1
-diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.txt
-index 4385946..c9d9d43 100644
--- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.txt
+++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.txt
-@@ -6,6 +6,7 @@ The Mediatek mmsys controller provides various clocks to the system.
+@@ -6,6 +6,7 @@ The Mediatek mmsys controller provides v
Required Properties:
- compatible: Should be:
@@ -157,8 +140,6 @@ index 4385946..c9d9d43 100644
- "mediatek,mt8173-mmsys", "syscon"
- #clock-cells: Must be 1
-diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.txt
-index f25b854..d3454cd 100644
--- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.txt
+++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.txt
@@ -7,6 +7,7 @@ outputs to the system.
@@ -169,11 +150,9 @@ index f25b854..d3454cd 100644
- "mediatek,mt8135-pericfg", "syscon"
- "mediatek,mt8173-pericfg", "syscon"
- #clock-cells: Must be 1
-diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,topckgen.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,topckgen.txt
-index f9e9179..602e5bc 100644
--- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,topckgen.txt
+++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,topckgen.txt
-@@ -6,6 +6,7 @@ The Mediatek topckgen controller provides various clocks to the system.
+@@ -6,6 +6,7 @@ The Mediatek topckgen controller provide
Required Properties:
- compatible: Should be:
@@ -181,11 +160,9 @@ index f9e9179..602e5bc 100644
- "mediatek,mt8135-topckgen"
- "mediatek,mt8173-topckgen"
- #clock-cells: Must be 1
-diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,vdecsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,vdecsys.txt
-index 1faacf1..f5b1e7d 100644
--- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,vdecsys.txt
+++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,vdecsys.txt
-@@ -6,6 +6,7 @@ The Mediatek vdecsys controller provides various clocks to the system.
+@@ -6,6 +6,7 @@ The Mediatek vdecsys controller provides
Required Properties:
- compatible: Should be:
@@ -193,6 +170,3 @@ index 1faacf1..f5b1e7d 100644
- "mediatek,mt8173-vdecsys", "syscon"
- #clock-cells: Must be 1
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0008-clk-mediatek-Add-dt-bindings-for-MT2701-clocks.patch b/target/linux/mediatek/patches-4.4/0008-clk-mediatek-Add-dt-bindings-for-MT2701-clocks.patch
index 057eb44fa7..422a5bec3a 100644
--- a/target/linux/mediatek/patches-4.4/0008-clk-mediatek-Add-dt-bindings-for-MT2701-clocks.patch
+++ b/target/linux/mediatek/patches-4.4/0008-clk-mediatek-Add-dt-bindings-for-MT2701-clocks.patch
@@ -1,7 +1,7 @@
-From 2fcbc15da2f13164e0851b9c7fae290249f0b44d Mon Sep 17 00:00:00 2001
+From 190696e3995be38fa01490e4ab88ea2c859829c9 Mon Sep 17 00:00:00 2001
From: Shunli Wang <shunli.wang@mediatek.com>
Date: Tue, 5 Jan 2016 14:30:19 +0800
-Subject: [PATCH 08/91] clk: mediatek: Add dt-bindings for MT2701 clocks
+Subject: [PATCH 008/102] clk: mediatek: Add dt-bindings for MT2701 clocks
Add MT2701 clock dt-bindings, include topckgen, apmixedsys,
infracfg, pericfg and subsystem clocks.
@@ -13,9 +13,6 @@ Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
1 file changed, 481 insertions(+)
create mode 100644 include/dt-bindings/clock/mt2701-clk.h
-diff --git a/include/dt-bindings/clock/mt2701-clk.h b/include/dt-bindings/clock/mt2701-clk.h
-new file mode 100644
-index 0000000..50972d1
--- /dev/null
+++ b/include/dt-bindings/clock/mt2701-clk.h
@@ -0,0 +1,481 @@
@@ -500,6 +497,3 @@ index 0000000..50972d1
+#define CLK_BDP_NR 50
+
+#endif /* _DT_BINDINGS_CLK_MT2701_H */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0009-clk-mediatek-Add-MT2701-clock-support.patch b/target/linux/mediatek/patches-4.4/0009-clk-mediatek-Add-MT2701-clock-support.patch
index b29285e864..6f8f68a300 100644
--- a/target/linux/mediatek/patches-4.4/0009-clk-mediatek-Add-MT2701-clock-support.patch
+++ b/target/linux/mediatek/patches-4.4/0009-clk-mediatek-Add-MT2701-clock-support.patch
@@ -1,7 +1,7 @@
-From f2c07eaa2df52f9acac9ffc3457d3d81079dd723 Mon Sep 17 00:00:00 2001
+From a4c507d052390b42d7e8c59241e3c336796f730f Mon Sep 17 00:00:00 2001
From: Shunli Wang <shunli.wang@mediatek.com>
Date: Tue, 5 Jan 2016 14:30:20 +0800
-Subject: [PATCH 09/91] clk: mediatek: Add MT2701 clock support
+Subject: [PATCH 009/102] clk: mediatek: Add MT2701 clock support
Add MT2701 clock support, include topckgen, apmixedsys,
infracfg, pericfg and subsystem clocks.
@@ -19,8 +19,6 @@ Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
7 files changed, 1334 insertions(+), 3 deletions(-)
create mode 100644 drivers/clk/mediatek/clk-mt2701.c
-diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
-index dc224e6..6c7cdc0 100644
--- a/drivers/clk/mediatek/Kconfig
+++ b/drivers/clk/mediatek/Kconfig
@@ -6,6 +6,14 @@ config COMMON_CLK_MEDIATEK
@@ -38,8 +36,6 @@ index dc224e6..6c7cdc0 100644
config COMMON_CLK_MT8135
bool "Clock driver for Mediatek MT8135"
depends on COMMON_CLK
-diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
-index 32e7222..5b2b91b 100644
--- a/drivers/clk/mediatek/Makefile
+++ b/drivers/clk/mediatek/Makefile
@@ -1,4 +1,5 @@
@@ -48,11 +44,9 @@ index 32e7222..5b2b91b 100644
+obj-$(CONFIG_COMMON_CLK_MT2701) += clk-mt2701.o
obj-$(CONFIG_COMMON_CLK_MT8135) += clk-mt8135.o
obj-$(CONFIG_COMMON_CLK_MT8173) += clk-mt8173.o
-diff --git a/drivers/clk/mediatek/clk-gate.c b/drivers/clk/mediatek/clk-gate.c
-index 576bdb7..38badb4 100644
--- a/drivers/clk/mediatek/clk-gate.c
+++ b/drivers/clk/mediatek/clk-gate.c
-@@ -61,6 +61,26 @@ static void mtk_cg_clr_bit(struct clk_hw *hw)
+@@ -61,6 +61,26 @@ static void mtk_cg_clr_bit(struct clk_hw
regmap_write(cg->regmap, cg->clr_ofs, BIT(cg->bit));
}
@@ -79,7 +73,7 @@ index 576bdb7..38badb4 100644
static int mtk_cg_enable(struct clk_hw *hw)
{
mtk_cg_clr_bit(hw);
-@@ -85,6 +105,30 @@ static void mtk_cg_disable_inv(struct clk_hw *hw)
+@@ -85,6 +105,30 @@ static void mtk_cg_disable_inv(struct cl
mtk_cg_clr_bit(hw);
}
@@ -110,7 +104,7 @@ index 576bdb7..38badb4 100644
const struct clk_ops mtk_clk_gate_ops_setclr = {
.is_enabled = mtk_cg_bit_is_cleared,
.enable = mtk_cg_enable,
-@@ -97,6 +141,18 @@ const struct clk_ops mtk_clk_gate_ops_setclr_inv = {
+@@ -97,6 +141,18 @@ const struct clk_ops mtk_clk_gate_ops_se
.disable = mtk_cg_disable_inv,
};
@@ -129,11 +123,9 @@ index 576bdb7..38badb4 100644
struct clk * __init mtk_clk_register_gate(
const char *name,
const char *parent_name,
-diff --git a/drivers/clk/mediatek/clk-gate.h b/drivers/clk/mediatek/clk-gate.h
-index 11e25c9..7f7ef34 100644
--- a/drivers/clk/mediatek/clk-gate.h
+++ b/drivers/clk/mediatek/clk-gate.h
-@@ -36,6 +36,8 @@ static inline struct mtk_clk_gate *to_clk_gate(struct clk_hw *hw)
+@@ -36,6 +36,8 @@ static inline struct mtk_clk_gate *to_cl
extern const struct clk_ops mtk_clk_gate_ops_setclr;
extern const struct clk_ops mtk_clk_gate_ops_setclr_inv;
@@ -142,9 +134,6 @@ index 11e25c9..7f7ef34 100644
struct clk *mtk_clk_register_gate(
const char *name,
-diff --git a/drivers/clk/mediatek/clk-mt2701.c b/drivers/clk/mediatek/clk-mt2701.c
-new file mode 100644
-index 0000000..2f521f4
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt2701.c
@@ -0,0 +1,1210 @@
@@ -1358,11 +1347,9 @@ index 0000000..2f521f4
+}
+CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt2701-apmixedsys",
+ mtk_apmixedsys_init);
-diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c
-index cf08db6..be19a41 100644
--- a/drivers/clk/mediatek/clk-mtk.c
+++ b/drivers/clk/mediatek/clk-mtk.c
-@@ -242,3 +242,28 @@ void __init mtk_clk_register_composites(const struct mtk_composite *mcs,
+@@ -242,3 +242,28 @@ void __init mtk_clk_register_composites(
clk_data->clks[mc->id] = clk;
}
}
@@ -1391,8 +1378,6 @@ index cf08db6..be19a41 100644
+ clk_data->clks[mcd->id] = clk;
+ }
+}
-diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h
-index 32d2e45..60701e8 100644
--- a/drivers/clk/mediatek/clk-mtk.h
+++ b/drivers/clk/mediatek/clk-mtk.h
@@ -110,7 +110,8 @@ struct mtk_composite {
@@ -1444,6 +1429,3 @@ index 32d2e45..60701e8 100644
struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num);
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0010-reset-mediatek-mt2701-reset-controller-dt-binding-fi.patch b/target/linux/mediatek/patches-4.4/0010-reset-mediatek-mt2701-reset-controller-dt-binding-fi.patch
index 8f5db79c76..b5b10e7b0b 100644
--- a/target/linux/mediatek/patches-4.4/0010-reset-mediatek-mt2701-reset-controller-dt-binding-fi.patch
+++ b/target/linux/mediatek/patches-4.4/0010-reset-mediatek-mt2701-reset-controller-dt-binding-fi.patch
@@ -1,7 +1,7 @@
-From 8d134cbe750b59d15c591622d81e2e9daa09f0c4 Mon Sep 17 00:00:00 2001
+From 8bf0f2a1e8ff082de3f650211abd985ef68abe1b Mon Sep 17 00:00:00 2001
From: Shunli Wang <shunli.wang@mediatek.com>
Date: Tue, 5 Jan 2016 14:30:21 +0800
-Subject: [PATCH 10/91] reset: mediatek: mt2701 reset controller dt-binding
+Subject: [PATCH 010/102] reset: mediatek: mt2701 reset controller dt-binding
file
Dt-binding file about reset controller is used to provide
@@ -14,9 +14,6 @@ Signed-off-by: Shunli Wang <shunli.wang@mediatek.com>
1 file changed, 74 insertions(+)
create mode 100644 include/dt-bindings/reset-controller/mt2701-resets.h
-diff --git a/include/dt-bindings/reset-controller/mt2701-resets.h b/include/dt-bindings/reset-controller/mt2701-resets.h
-new file mode 100644
-index 0000000..00efeb0
--- /dev/null
+++ b/include/dt-bindings/reset-controller/mt2701-resets.h
@@ -0,0 +1,74 @@
@@ -94,6 +91,3 @@ index 0000000..00efeb0
+#define MT2701_TOPRGU_BDP_DISP_RST 13
+
+#endif /* _DT_BINDINGS_RESET_CONTROLLER_MT2701 */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0011-reset-mediatek-mt2701-reset-driver.patch b/target/linux/mediatek/patches-4.4/0011-reset-mediatek-mt2701-reset-driver.patch
index bbb123e575..18d4fbf252 100644
--- a/target/linux/mediatek/patches-4.4/0011-reset-mediatek-mt2701-reset-driver.patch
+++ b/target/linux/mediatek/patches-4.4/0011-reset-mediatek-mt2701-reset-driver.patch
@@ -1,7 +1,7 @@
-From b86d3303db25a8296e4c3de46ee1470f60f71b0c Mon Sep 17 00:00:00 2001
+From 3ba0020ea70ffb5503eff1823be7fa5ceda38286 Mon Sep 17 00:00:00 2001
From: Shunli Wang <shunli.wang@mediatek.com>
Date: Tue, 5 Jan 2016 14:30:22 +0800
-Subject: [PATCH 11/91] reset: mediatek: mt2701 reset driver
+Subject: [PATCH 011/102] reset: mediatek: mt2701 reset driver
In infrasys and perifsys, there are many reset
control bits for kinds of modules. These bits are
@@ -14,11 +14,9 @@ Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
drivers/clk/mediatek/clk-mt2701.c | 4 ++++
1 file changed, 4 insertions(+)
-diff --git a/drivers/clk/mediatek/clk-mt2701.c b/drivers/clk/mediatek/clk-mt2701.c
-index 2f521f4..39472e4 100644
--- a/drivers/clk/mediatek/clk-mt2701.c
+++ b/drivers/clk/mediatek/clk-mt2701.c
-@@ -665,6 +665,8 @@ static void __init mtk_infrasys_init(struct device_node *node)
+@@ -665,6 +665,8 @@ static void __init mtk_infrasys_init(str
if (r)
pr_err("%s(): could not register clock provider: %d\n",
__func__, r);
@@ -27,7 +25,7 @@ index 2f521f4..39472e4 100644
}
CLK_OF_DECLARE(mtk_infrasys, "mediatek,mt2701-infracfg", mtk_infrasys_init);
-@@ -782,6 +784,8 @@ static void __init mtk_pericfg_init(struct device_node *node)
+@@ -782,6 +784,8 @@ static void __init mtk_pericfg_init(stru
if (r)
pr_err("%s(): could not register clock provider: %d\n",
__func__, r);
@@ -36,6 +34,3 @@ index 2f521f4..39472e4 100644
}
CLK_OF_DECLARE(mtk_pericfg, "mediatek,mt2701-pericfg", mtk_pericfg_init);
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0012-ARM-mediatek-Add-MT2701-config-options-for-mediatek-.patch b/target/linux/mediatek/patches-4.4/0012-ARM-mediatek-Add-MT2701-config-options-for-mediatek-.patch
index 0e532ffcbf..479334a92d 100644
--- a/target/linux/mediatek/patches-4.4/0012-ARM-mediatek-Add-MT2701-config-options-for-mediatek-.patch
+++ b/target/linux/mediatek/patches-4.4/0012-ARM-mediatek-Add-MT2701-config-options-for-mediatek-.patch
@@ -1,8 +1,8 @@
-From 3b5df542d52b13a1b20d25311fa4c4029a3b83af Mon Sep 17 00:00:00 2001
+From 32fa899c6ab79953e4f470fb23c38bcc40edc5c8 Mon Sep 17 00:00:00 2001
From: Erin Lo <erin.lo@mediatek.com>
Date: Mon, 28 Dec 2015 15:09:02 +0800
-Subject: [PATCH 12/91] ARM: mediatek: Add MT2701 config options for mediatek
- SoCs.
+Subject: [PATCH 012/102] ARM: mediatek: Add MT2701 config options for
+ mediatek SoCs.
The upcoming MTK pinctrl driver have a big pin table for each SoC
and we don't want to bloat the kernel binary if we don't need it.
@@ -14,8 +14,6 @@ Acked-by: Linus Walleij <linus.walleij@linaro.org>
arch/arm/mach-mediatek/Kconfig | 4 ++++
1 file changed, 4 insertions(+)
-diff --git a/arch/arm/mach-mediatek/Kconfig b/arch/arm/mach-mediatek/Kconfig
-index aeece17..37dd438 100644
--- a/arch/arm/mach-mediatek/Kconfig
+++ b/arch/arm/mach-mediatek/Kconfig
@@ -9,6 +9,10 @@ menuconfig ARCH_MEDIATEK
@@ -29,6 +27,3 @@ index aeece17..37dd438 100644
config MACH_MT6589
bool "MediaTek MT6589 SoCs support"
default ARCH_MEDIATEK
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0013-dt-bindings-mediatek-Modify-pinctrl-bindings-for-mt2.patch b/target/linux/mediatek/patches-4.4/0013-dt-bindings-mediatek-Modify-pinctrl-bindings-for-mt2.patch
index ba3bd08806..af1ad668f5 100644
--- a/target/linux/mediatek/patches-4.4/0013-dt-bindings-mediatek-Modify-pinctrl-bindings-for-mt2.patch
+++ b/target/linux/mediatek/patches-4.4/0013-dt-bindings-mediatek-Modify-pinctrl-bindings-for-mt2.patch
@@ -1,7 +1,7 @@
-From 1a254735cad9db5c8605c972b0f16b3929dc0d6e Mon Sep 17 00:00:00 2001
+From afcbed6f51e8c3a9195952b27c8aad047c314ed0 Mon Sep 17 00:00:00 2001
From: Biao Huang <biao.huang@mediatek.com>
Date: Mon, 28 Dec 2015 15:09:03 +0800
-Subject: [PATCH 13/91] dt-bindings: mediatek: Modify pinctrl bindings for
+Subject: [PATCH 013/102] dt-bindings: mediatek: Modify pinctrl bindings for
mt2701
Signed-off-by: Biao Huang <biao.huang@mediatek.com>
@@ -11,11 +11,9 @@ Reviewed-by: Mathias Brugger <matthias.bgg@gmail.com>
Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
-diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt
-index 0480bc3..9ffb0b2 100644
--- a/Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt
-@@ -4,10 +4,11 @@ The Mediatek's Pin controller is used to control SoC pins.
+@@ -4,10 +4,11 @@ The Mediatek's Pin controller is used to
Required properties:
- compatible: value should be one of the following.
@@ -31,6 +29,3 @@ index 0480bc3..9ffb0b2 100644
- pins-are-numbered: Specify the subnodes are using numbered pinmux to
specify pins.
- gpio-controller : Marks the device node as a gpio controller.
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0014-pinctrl-dt-bindings-Add-pinfunc-header-file-for-mt27.patch b/target/linux/mediatek/patches-4.4/0014-pinctrl-dt-bindings-Add-pinfunc-header-file-for-mt27.patch
index d898f3c06f..0df6d186ba 100644
--- a/target/linux/mediatek/patches-4.4/0014-pinctrl-dt-bindings-Add-pinfunc-header-file-for-mt27.patch
+++ b/target/linux/mediatek/patches-4.4/0014-pinctrl-dt-bindings-Add-pinfunc-header-file-for-mt27.patch
@@ -1,7 +1,7 @@
-From 416720ba33d4fd7d3166c17be7c13651cc08d408 Mon Sep 17 00:00:00 2001
+From 124894a4d1635915ff95c447767677b60fd27e9c Mon Sep 17 00:00:00 2001
From: Biao Huang <biao.huang@mediatek.com>
Date: Mon, 28 Dec 2015 15:09:04 +0800
-Subject: [PATCH 14/91] pinctrl: dt bindings: Add pinfunc header file for
+Subject: [PATCH 014/102] pinctrl: dt bindings: Add pinfunc header file for
mt2701
Add pinfunc header file, mt2701 related dts will include it
@@ -21,9 +21,6 @@ Acked-by: Linus Walleij <linus.walleij@linaro.org>
create mode 100644 drivers/pinctrl/mediatek/pinctrl-mt2701.c
create mode 100644 drivers/pinctrl/mediatek/pinctrl-mtk-mt2701.h
-diff --git a/arch/arm/boot/dts/mt2701-pinfunc.h b/arch/arm/boot/dts/mt2701-pinfunc.h
-new file mode 100644
-index 0000000..e24ebc8
--- /dev/null
+++ b/arch/arm/boot/dts/mt2701-pinfunc.h
@@ -0,0 +1,735 @@
@@ -762,8 +759,6 @@ index 0000000..e24ebc8
+#define MT2701_PIN_278_JTAG_RESET__FUNC_JTAG_RESET (MTK_PIN_NO(278) | 1)
+
+#endif /* __DTS_MT2701_PINFUNC_H */
-diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig
-index 02f6f92..13e9939 100644
--- a/drivers/pinctrl/mediatek/Kconfig
+++ b/drivers/pinctrl/mediatek/Kconfig
@@ -9,6 +9,12 @@ config PINCTRL_MTK_COMMON
@@ -779,8 +774,6 @@ index 02f6f92..13e9939 100644
config PINCTRL_MT8135
bool "Mediatek MT8135 pin control" if COMPILE_TEST && !MACH_MT8135
depends on OF
-diff --git a/drivers/pinctrl/mediatek/Makefile b/drivers/pinctrl/mediatek/Makefile
-index eb923d6..da30314 100644
--- a/drivers/pinctrl/mediatek/Makefile
+++ b/drivers/pinctrl/mediatek/Makefile
@@ -2,6 +2,7 @@
@@ -791,9 +784,6 @@ index eb923d6..da30314 100644
obj-$(CONFIG_PINCTRL_MT8135) += pinctrl-mt8135.o
obj-$(CONFIG_PINCTRL_MT8127) += pinctrl-mt8127.o
obj-$(CONFIG_PINCTRL_MT8173) += pinctrl-mt8173.o
-diff --git a/drivers/pinctrl/mediatek/pinctrl-mt2701.c b/drivers/pinctrl/mediatek/pinctrl-mt2701.c
-new file mode 100644
-index 0000000..4861b5d
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mt2701.c
@@ -0,0 +1,586 @@
@@ -1383,8 +1373,6 @@ index 0000000..4861b5d
+}
+
+arch_initcall(mtk_pinctrl_init);
-diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
-index 5c71727..05ba7a8 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
@@ -47,6 +47,8 @@
@@ -1396,7 +1384,7 @@ index 5c71727..05ba7a8 100644
};
/*
-@@ -81,6 +83,9 @@ static int mtk_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
+@@ -81,6 +83,9 @@ static int mtk_pmx_gpio_set_direction(st
reg_addr = mtk_get_port(pctl, offset) + pctl->devdata->dir_offset;
bit = BIT(offset & 0xf);
@@ -1406,7 +1394,7 @@ index 5c71727..05ba7a8 100644
if (input)
/* Different SoC has different alignment offset. */
reg_addr = CLR_ADDR(reg_addr, pctl);
-@@ -347,6 +352,7 @@ static int mtk_pconf_parse_conf(struct pinctrl_dev *pctldev,
+@@ -347,6 +352,7 @@ static int mtk_pconf_parse_conf(struct p
ret = mtk_pconf_set_pull_select(pctl, pin, true, false, arg);
break;
case PIN_CONFIG_INPUT_ENABLE:
@@ -1414,7 +1402,7 @@ index 5c71727..05ba7a8 100644
ret = mtk_pconf_set_ies_smt(pctl, pin, arg, param);
break;
case PIN_CONFIG_OUTPUT:
-@@ -354,6 +360,7 @@ static int mtk_pconf_parse_conf(struct pinctrl_dev *pctldev,
+@@ -354,6 +360,7 @@ static int mtk_pconf_parse_conf(struct p
ret = mtk_pmx_gpio_set_direction(pctldev, NULL, pin, false);
break;
case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
@@ -1422,7 +1410,7 @@ index 5c71727..05ba7a8 100644
ret = mtk_pconf_set_ies_smt(pctl, pin, arg, param);
break;
case PIN_CONFIG_DRIVE_STRENGTH:
-@@ -667,9 +674,14 @@ static int mtk_pmx_set_mode(struct pinctrl_dev *pctldev,
+@@ -667,9 +674,14 @@ static int mtk_pmx_set_mode(struct pinct
unsigned int mask = (1L << GPIO_MODE_BITS) - 1;
struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
@@ -1437,7 +1425,7 @@ index 5c71727..05ba7a8 100644
bit = pin % MAX_GPIO_MODE_PER_REG;
mask <<= (GPIO_MODE_BITS * bit);
val = (mode << (GPIO_MODE_BITS * bit));
-@@ -746,6 +758,10 @@ static int mtk_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+@@ -746,6 +758,10 @@ static int mtk_gpio_get_direction(struct
reg_addr = mtk_get_port(pctl, offset) + pctl->devdata->dir_offset;
bit = BIT(offset & 0xf);
@@ -1448,8 +1436,6 @@ index 5c71727..05ba7a8 100644
regmap_read(pctl->regmap1, reg_addr, &read_val);
return !(read_val & bit);
}
-diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.h b/drivers/pinctrl/mediatek/pinctrl-mtk-common.h
-index 55a5343..8543bc4 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.h
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.h
@@ -209,7 +209,14 @@ struct mtk_eint_offsets {
@@ -1478,9 +1464,6 @@ index 55a5343..8543bc4 100644
unsigned int dir_offset;
unsigned int ies_offset;
unsigned int smt_offset;
-diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-mt2701.h b/drivers/pinctrl/mediatek/pinctrl-mtk-mt2701.h
-new file mode 100644
-index 0000000..f906420
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-mt2701.h
@@ -0,0 +1,2323 @@
@@ -3807,6 +3790,3 @@ index 0000000..f906420
+};
+
+#endif /* __PINCTRL_MTK_MT2701_H */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0015-dt-bindings-mediatek-Modify-pinctrl-bindings-for-mt7.patch b/target/linux/mediatek/patches-4.4/0015-dt-bindings-mediatek-Modify-pinctrl-bindings-for-mt7.patch
index d1e231eb72..fcd39c487d 100644
--- a/target/linux/mediatek/patches-4.4/0015-dt-bindings-mediatek-Modify-pinctrl-bindings-for-mt7.patch
+++ b/target/linux/mediatek/patches-4.4/0015-dt-bindings-mediatek-Modify-pinctrl-bindings-for-mt7.patch
@@ -1,7 +1,7 @@
-From ddc72b659b3642d0496dee4e1ee39416ca008053 Mon Sep 17 00:00:00 2001
+From 3800e5c33e5becbb56c6694008d1f3435fd78707 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Thu, 7 Jan 2016 23:42:06 +0100
-Subject: [PATCH 15/91] dt-bindings: mediatek: Modify pinctrl bindings for
+Subject: [PATCH 015/102] dt-bindings: mediatek: Modify pinctrl bindings for
mt7623
Signed-off-by: John Crispin <blogic@openwrt.org>
@@ -11,8 +11,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
2 files changed, 522 insertions(+)
create mode 100644 include/dt-bindings/pinctrl/mt7623-pinfunc.h
-diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt
-index 9ffb0b2..17631d0 100644
--- a/Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt
@@ -6,6 +6,7 @@ Required properties:
@@ -23,9 +21,6 @@ index 9ffb0b2..17631d0 100644
"mediatek,mt8127-pinctrl", compatible with mt8127 pinctrl.
"mediatek,mt8135-pinctrl", compatible with mt8135 pinctrl.
"mediatek,mt8173-pinctrl", compatible with mt8173 pinctrl.
-diff --git a/include/dt-bindings/pinctrl/mt7623-pinfunc.h b/include/dt-bindings/pinctrl/mt7623-pinfunc.h
-new file mode 100644
-index 0000000..891b173
--- /dev/null
+++ b/include/dt-bindings/pinctrl/mt7623-pinfunc.h
@@ -0,0 +1,521 @@
@@ -550,6 +545,3 @@ index 0000000..891b173
+
+#endif /* __DTS_MT7623_PINFUNC_H */
+
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0016-pinctrl-dt-bindings-Add-pinctrl-file-for-mt7623.patch b/target/linux/mediatek/patches-4.4/0016-pinctrl-dt-bindings-Add-pinctrl-file-for-mt7623.patch
index cf09ae5da0..3428fce39c 100644
--- a/target/linux/mediatek/patches-4.4/0016-pinctrl-dt-bindings-Add-pinctrl-file-for-mt7623.patch
+++ b/target/linux/mediatek/patches-4.4/0016-pinctrl-dt-bindings-Add-pinctrl-file-for-mt7623.patch
@@ -1,7 +1,7 @@
-From 1255eaacd6cc9d1fa6bb33185380efed22008baf Mon Sep 17 00:00:00 2001
+From 641ccb565a934ffaa30b828f2361e6f57325c70a Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sat, 27 Jun 2015 13:13:05 +0200
-Subject: [PATCH 16/91] pinctrl: dt bindings: Add pinctrl file for mt7623
+Subject: [PATCH 016/102] pinctrl: dt bindings: Add pinctrl file for mt7623
Add the driver and header files required to make pinctrl work on MediaTek
MT7623.
@@ -17,8 +17,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
create mode 100644 drivers/pinctrl/mediatek/pinctrl-mt7623.c
create mode 100644 drivers/pinctrl/mediatek/pinctrl-mtk-mt7623.h
-diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig
-index 13e9939..78654a8 100644
--- a/drivers/pinctrl/mediatek/Kconfig
+++ b/drivers/pinctrl/mediatek/Kconfig
@@ -15,6 +15,12 @@ config PINCTRL_MT2701
@@ -34,11 +32,9 @@ index 13e9939..78654a8 100644
config PINCTRL_MT8135
bool "Mediatek MT8135 pin control" if COMPILE_TEST && !MACH_MT8135
depends on OF
-diff --git a/drivers/pinctrl/mediatek/Makefile b/drivers/pinctrl/mediatek/Makefile
-index da30314..1be2f3f 100644
--- a/drivers/pinctrl/mediatek/Makefile
+++ b/drivers/pinctrl/mediatek/Makefile
-@@ -3,6 +3,7 @@ obj-$(CONFIG_PINCTRL_MTK_COMMON) += pinctrl-mtk-common.o
+@@ -3,6 +3,7 @@ obj-$(CONFIG_PINCTRL_MTK_COMMON) += pinc
# SoC Drivers
obj-$(CONFIG_PINCTRL_MT2701) += pinctrl-mt2701.o
@@ -46,9 +42,6 @@ index da30314..1be2f3f 100644
obj-$(CONFIG_PINCTRL_MT8135) += pinctrl-mt8135.o
obj-$(CONFIG_PINCTRL_MT8127) += pinctrl-mt8127.o
obj-$(CONFIG_PINCTRL_MT8173) += pinctrl-mt8173.o
-diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7623.c b/drivers/pinctrl/mediatek/pinctrl-mt7623.c
-new file mode 100644
-index 0000000..bf0d05b
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mt7623.c
@@ -0,0 +1,380 @@
@@ -432,9 +425,6 @@ index 0000000..bf0d05b
+}
+
+arch_initcall(mtk_pinctrl_init);
-diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-mt7623.h b/drivers/pinctrl/mediatek/pinctrl-mtk-mt7623.h
-new file mode 100644
-index 0000000..fb63c01
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-mt7623.h
@@ -0,0 +1,1937 @@
@@ -2375,8 +2365,6 @@ index 0000000..fb63c01
+};
+
+#endif /* __PINCTRL_MTK_MT7623_H */
-diff --git a/include/dt-bindings/pinctrl/mt7623-pinfunc.h b/include/dt-bindings/pinctrl/mt7623-pinfunc.h
-index 891b173..eeb2380 100644
--- a/include/dt-bindings/pinctrl/mt7623-pinfunc.h
+++ b/include/dt-bindings/pinctrl/mt7623-pinfunc.h
@@ -505,6 +505,9 @@
@@ -2389,6 +2377,3 @@ index 891b173..eeb2380 100644
#define MT7623_PIN_274_G2_RXDV_FUNC_GPIO274 (MTK_PIN_NO(274) | 0)
#define MT7623_PIN_274_G2_RXDV_FUNC_G2_RXDV (MTK_PIN_NO(274) | 1)
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0017-clk-add-hifsys-reset.patch b/target/linux/mediatek/patches-4.4/0017-clk-add-hifsys-reset.patch
index 0b1b59be9c..d7d151cedb 100644
--- a/target/linux/mediatek/patches-4.4/0017-clk-add-hifsys-reset.patch
+++ b/target/linux/mediatek/patches-4.4/0017-clk-add-hifsys-reset.patch
@@ -1,7 +1,7 @@
-From 294cf90337d70ad74edf147180bbeef837298bd0 Mon Sep 17 00:00:00 2001
+From f7121d2b19ddad33a09408a2c5923bfd95da8533 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Wed, 6 Jan 2016 20:06:49 +0100
-Subject: [PATCH 17/91] clk: add hifsys reset
+Subject: [PATCH 017/102] clk: add hifsys reset
Hi,
@@ -18,11 +18,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
include/dt-bindings/reset-controller/mt2701-resets.h | 9 +++++++++
2 files changed, 11 insertions(+)
-diff --git a/drivers/clk/mediatek/clk-mt2701.c b/drivers/clk/mediatek/clk-mt2701.c
-index 39472e4..0e40bb8 100644
--- a/drivers/clk/mediatek/clk-mt2701.c
+++ b/drivers/clk/mediatek/clk-mt2701.c
-@@ -1000,6 +1000,8 @@ static void __init mtk_hifsys_init(struct device_node *node)
+@@ -1000,6 +1000,8 @@ static void __init mtk_hifsys_init(struc
if (r)
pr_err("%s(): could not register clock provider: %d\n",
__func__, r);
@@ -31,8 +29,6 @@ index 39472e4..0e40bb8 100644
}
CLK_OF_DECLARE(mtk_hifsys, "mediatek,mt2701-hifsys", mtk_hifsys_init);
-diff --git a/include/dt-bindings/reset-controller/mt2701-resets.h b/include/dt-bindings/reset-controller/mt2701-resets.h
-index 00efeb0..aaf0305 100644
--- a/include/dt-bindings/reset-controller/mt2701-resets.h
+++ b/include/dt-bindings/reset-controller/mt2701-resets.h
@@ -71,4 +71,13 @@
@@ -49,6 +45,3 @@ index 00efeb0..aaf0305 100644
+#define MT2701_HIFSYS_PCIE2_RST 26
+
#endif /* _DT_BINDINGS_RESET_CONTROLLER_MT2701 */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0018-dt-bindings-Add-a-binding-for-Mediatek-xHCI-host-con.patch b/target/linux/mediatek/patches-4.4/0018-dt-bindings-Add-a-binding-for-Mediatek-xHCI-host-con.patch
index d011bf344d..9c178f2918 100644
--- a/target/linux/mediatek/patches-4.4/0018-dt-bindings-Add-a-binding-for-Mediatek-xHCI-host-con.patch
+++ b/target/linux/mediatek/patches-4.4/0018-dt-bindings-Add-a-binding-for-Mediatek-xHCI-host-con.patch
@@ -1,7 +1,7 @@
-From 84d37aeef94deae3ce87e677f6016a5d980429e8 Mon Sep 17 00:00:00 2001
+From ba126a519da8a036dae0032e9d5a89e47570e5fb Mon Sep 17 00:00:00 2001
From: "chunfeng.yun@mediatek.com" <chunfeng.yun@mediatek.com>
Date: Tue, 17 Nov 2015 17:18:39 +0800
-Subject: [PATCH 18/91] dt-bindings: Add a binding for Mediatek xHCI host
+Subject: [PATCH 018/102] dt-bindings: Add a binding for Mediatek xHCI host
controller
add a DT binding documentation of xHCI host controller for the
@@ -13,9 +13,6 @@ Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
1 file changed, 51 insertions(+)
create mode 100644 Documentation/devicetree/bindings/usb/mt8173-xhci.txt
-diff --git a/Documentation/devicetree/bindings/usb/mt8173-xhci.txt b/Documentation/devicetree/bindings/usb/mt8173-xhci.txt
-new file mode 100644
-index 0000000..a78f20b
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/mt8173-xhci.txt
@@ -0,0 +1,51 @@
@@ -70,6 +67,3 @@ index 0000000..a78f20b
+ mediatek,syscon-wakeup = <&pericfg>;
+ mediatek,wakeup-src = <1>;
+};
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0019-xhci-mediatek-support-MTK-xHCI-host-controller.patch b/target/linux/mediatek/patches-4.4/0019-xhci-mediatek-support-MTK-xHCI-host-controller.patch
index 603abe0704..f344be6fdd 100644
--- a/target/linux/mediatek/patches-4.4/0019-xhci-mediatek-support-MTK-xHCI-host-controller.patch
+++ b/target/linux/mediatek/patches-4.4/0019-xhci-mediatek-support-MTK-xHCI-host-controller.patch
@@ -1,7 +1,7 @@
-From 651d8fff94718c7e48b8a40d7774878eb8ed62ee Mon Sep 17 00:00:00 2001
+From 8b8185586a13ebbd760e80bbe5f22f9417b50fd2 Mon Sep 17 00:00:00 2001
From: "chunfeng.yun@mediatek.com" <chunfeng.yun@mediatek.com>
Date: Tue, 17 Nov 2015 17:18:40 +0800
-Subject: [PATCH 19/91] xhci: mediatek: support MTK xHCI host controller
+Subject: [PATCH 019/102] xhci: mediatek: support MTK xHCI host controller
There some vendor quirks for MTK xhci host controller:
1. It defines some extra SW scheduling parameters for HW
@@ -31,8 +31,6 @@ Reviewed-by: Daniel Thompson <daniel.thompson@linaro.org>
create mode 100644 drivers/usb/host/xhci-mtk.c
create mode 100644 drivers/usb/host/xhci-mtk.h
-diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
-index 3bb0887..daa563f 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -41,6 +41,15 @@ config USB_XHCI_PLATFORM
@@ -51,8 +49,6 @@ index 3bb0887..daa563f 100644
config USB_XHCI_MVEBU
tristate "xHCI support for Marvell Armada 375/38x"
select USB_XHCI_PLATFORM
-diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
-index e7558ab..65a06b4 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -13,6 +13,9 @@ fhci-$(CONFIG_FHCI_DEBUG) += fhci-dbg.o
@@ -73,9 +69,6 @@ index e7558ab..65a06b4 100644
obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o
obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o
obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
-diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
-new file mode 100644
-index 0000000..c30de7c
--- /dev/null
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -0,0 +1,415 @@
@@ -494,9 +487,6 @@ index 0000000..c30de7c
+ }
+}
+EXPORT_SYMBOL_GPL(xhci_mtk_drop_ep_quirk);
-diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c
-new file mode 100644
-index 0000000..c9ab6a4
--- /dev/null
+++ b/drivers/usb/host/xhci-mtk.c
@@ -0,0 +1,763 @@
@@ -1263,9 +1253,6 @@ index 0000000..c9ab6a4
+MODULE_AUTHOR("Chunfeng Yun <chunfeng.yun@mediatek.com>");
+MODULE_DESCRIPTION("MediaTek xHCI Host Controller Driver");
+MODULE_LICENSE("GPL v2");
-diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h
-new file mode 100644
-index 0000000..7da677c
--- /dev/null
+++ b/drivers/usb/host/xhci-mtk.h
@@ -0,0 +1,162 @@
@@ -1431,8 +1418,6 @@ index 0000000..7da677c
+#endif
+
+#endif /* _XHCI_MTK_H_ */
-diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
-index eeaa6c6..f1c21c4 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -68,6 +68,7 @@
@@ -1443,7 +1428,7 @@ index eeaa6c6..f1c21c4 100644
/*
* Returns zero if the TRB isn't in this segment, otherwise it returns the DMA
-@@ -3075,17 +3076,22 @@ static u32 xhci_td_remainder(struct xhci_hcd *xhci, int transferred,
+@@ -3065,17 +3066,22 @@ static u32 xhci_td_remainder(struct xhci
{
u32 maxp, total_packet_count;
@@ -1470,7 +1455,7 @@ index eeaa6c6..f1c21c4 100644
/* Queueing functions don't count the current TRB into transferred */
return (total_packet_count - ((transferred + trb_buff_len) / maxp));
}
-@@ -3473,7 +3479,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
+@@ -3463,7 +3469,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *
field |= 0x1;
/* xHCI 1.0/1.1 6.4.1.2.1: Transfer Type field */
@@ -1479,8 +1464,6 @@ index eeaa6c6..f1c21c4 100644
if (urb->transfer_buffer_length > 0) {
if (setup->bRequestType & USB_DIR_IN)
field |= TRB_TX_TYPE(TRB_DATA_IN);
-diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
-index 3f91270..15fedb2 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -31,6 +31,7 @@
@@ -1491,7 +1474,7 @@ index 3f91270..15fedb2 100644
#define DRIVER_AUTHOR "Sarah Sharp"
#define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver"
-@@ -634,7 +635,11 @@ int xhci_run(struct usb_hcd *hcd)
+@@ -635,7 +636,11 @@ int xhci_run(struct usb_hcd *hcd)
"// Set the interrupt modulation register");
temp = readl(&xhci->ir_set->irq_control);
temp &= ~ER_IRQ_INTERVAL_MASK;
@@ -1504,7 +1487,7 @@ index 3f91270..15fedb2 100644
writel(temp, &xhci->ir_set->irq_control);
/* Set the HCD state before we enable the irqs */
-@@ -1698,6 +1703,9 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
+@@ -1701,6 +1706,9 @@ int xhci_drop_endpoint(struct usb_hcd *h
xhci_endpoint_zero(xhci, xhci->devs[udev->slot_id], ep);
@@ -1514,7 +1497,7 @@ index 3f91270..15fedb2 100644
xhci_dbg(xhci, "drop ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x\n",
(unsigned int) ep->desc.bEndpointAddress,
udev->slot_id,
-@@ -1793,6 +1801,15 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
+@@ -1796,6 +1804,15 @@ int xhci_add_endpoint(struct usb_hcd *hc
return -ENOMEM;
}
@@ -1530,11 +1513,9 @@ index 3f91270..15fedb2 100644
ctrl_ctx->add_flags |= cpu_to_le32(added_ctxs);
new_add_flags = le32_to_cpu(ctrl_ctx->add_flags);
-diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
-index 0b94512..40cf36e 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
-@@ -1630,6 +1630,7 @@ struct xhci_hcd {
+@@ -1631,6 +1631,7 @@ struct xhci_hcd {
/* For controllers with a broken beyond repair streams implementation */
#define XHCI_BROKEN_STREAMS (1 << 19)
#define XHCI_PME_STUCK_QUIRK (1 << 20)
@@ -1542,6 +1523,3 @@ index 0b94512..40cf36e 100644
unsigned int num_active_eps;
unsigned int limit_active_eps;
/* There are two roothubs to keep track of bus suspend info for */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0020-arm64-dts-mediatek-add-xHCI-usb-phy-for-mt8173.patch b/target/linux/mediatek/patches-4.4/0020-arm64-dts-mediatek-add-xHCI-usb-phy-for-mt8173.patch
index c5bfd0f0e1..50c03ee892 100644
--- a/target/linux/mediatek/patches-4.4/0020-arm64-dts-mediatek-add-xHCI-usb-phy-for-mt8173.patch
+++ b/target/linux/mediatek/patches-4.4/0020-arm64-dts-mediatek-add-xHCI-usb-phy-for-mt8173.patch
@@ -1,7 +1,7 @@
-From 31a22fbd0d3b187be61c4c5d22b19c95abb327c3 Mon Sep 17 00:00:00 2001
+From 645465d4c6dd46c5e6c9ac25cd42608b4201fde0 Mon Sep 17 00:00:00 2001
From: "chunfeng.yun@mediatek.com" <chunfeng.yun@mediatek.com>
Date: Tue, 17 Nov 2015 17:18:41 +0800
-Subject: [PATCH 20/91] arm64: dts: mediatek: add xHCI & usb phy for mt8173
+Subject: [PATCH 020/102] arm64: dts: mediatek: add xHCI & usb phy for mt8173
add xHCI and phy drivers for MT8173-EVB
@@ -11,8 +11,6 @@ Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
arch/arm64/boot/dts/mediatek/mt8173.dtsi | 42 +++++++++++++++++++++++++++
2 files changed, 58 insertions(+)
-diff --git a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
-index 811cb76..9b1482a 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
+++ b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
@@ -13,6 +13,7 @@
@@ -49,8 +47,6 @@ index 811cb76..9b1482a 100644
+ vbus-supply = <&usb_p1_vbus>;
+ mediatek,wakeup-src = <1>;
+};
-diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
-index 4dd5f93..c1fd275 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
@@ -14,6 +14,7 @@
@@ -109,6 +105,3 @@ index 4dd5f93..c1fd275 100644
mmsys: clock-controller@14000000 {
compatible = "mediatek,mt8173-mmsys", "syscon";
reg = <0 0x14000000 0 0x1000>;
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0021-Document-DT-Add-bindings-for-mediatek-MT7623-SoC-Pla.patch b/target/linux/mediatek/patches-4.4/0021-Document-DT-Add-bindings-for-mediatek-MT7623-SoC-Pla.patch
index 470da141e8..223c2263f3 100644
--- a/target/linux/mediatek/patches-4.4/0021-Document-DT-Add-bindings-for-mediatek-MT7623-SoC-Pla.patch
+++ b/target/linux/mediatek/patches-4.4/0021-Document-DT-Add-bindings-for-mediatek-MT7623-SoC-Pla.patch
@@ -1,7 +1,7 @@
-From 162deec293400cb132161606629654acaec7cb4b Mon Sep 17 00:00:00 2001
+From e111a35542ac14712026fe1a55236f76c7fc9048 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Tue, 5 Jan 2016 12:13:54 +0100
-Subject: [PATCH 21/91] Document: DT: Add bindings for mediatek MT7623 SoC
+Subject: [PATCH 021/102] Document: DT: Add bindings for mediatek MT7623 SoC
Platform
This adds a DT binding documentation for the MT7623 SoC from Mediatek.
@@ -13,8 +13,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt | 1 +
3 files changed, 6 insertions(+)
-diff --git a/Documentation/devicetree/bindings/arm/mediatek.txt b/Documentation/devicetree/bindings/arm/mediatek.txt
-index 618a9199..40e9d32 100644
--- a/Documentation/devicetree/bindings/arm/mediatek.txt
+++ b/Documentation/devicetree/bindings/arm/mediatek.txt
@@ -10,6 +10,7 @@ compatible: Must contain one of
@@ -35,8 +33,6 @@ index 618a9199..40e9d32 100644
- MTK mt8127 tablet moose EVB:
Required root node properties:
- compatible = "mediatek,mt8127-moose", "mediatek,mt8127";
-diff --git a/Documentation/devicetree/bindings/serial/mtk-uart.txt b/Documentation/devicetree/bindings/serial/mtk-uart.txt
-index 2d47add..474f0cf 100644
--- a/Documentation/devicetree/bindings/serial/mtk-uart.txt
+++ b/Documentation/devicetree/bindings/serial/mtk-uart.txt
@@ -2,6 +2,7 @@
@@ -47,8 +43,6 @@ index 2d47add..474f0cf 100644
* "mediatek,mt8135-uart" for MT8135 compatible UARTS
* "mediatek,mt8127-uart" for MT8127 compatible UARTS
* "mediatek,mt8173-uart" for MT8173 compatible UARTS
-diff --git a/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt b/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt
-index 64083bc..6bacda1b3 100644
--- a/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt
+++ b/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt
@@ -5,6 +5,7 @@ Required properties:
@@ -59,6 +53,3 @@ index 64083bc..6bacda1b3 100644
* "mediatek,mt8127-timer" for MT8127 compatible timers
* "mediatek,mt8135-timer" for MT8135 compatible timers
* "mediatek,mt8173-timer" for MT8173 compatible timers
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0022-soc-mediatek-add-compat-string-for-mt7623-to-scpsys.patch b/target/linux/mediatek/patches-4.4/0022-soc-mediatek-add-compat-string-for-mt7623-to-scpsys.patch
index 5ae71d73db..453b61288a 100644
--- a/target/linux/mediatek/patches-4.4/0022-soc-mediatek-add-compat-string-for-mt7623-to-scpsys.patch
+++ b/target/linux/mediatek/patches-4.4/0022-soc-mediatek-add-compat-string-for-mt7623-to-scpsys.patch
@@ -1,18 +1,17 @@
-From fa5d94d6b4b314f751b1c32bb5a87a80b866d05e Mon Sep 17 00:00:00 2001
+From f232c3b36355974bf3442de3a4726d2e499ed3fe Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Tue, 5 Jan 2016 16:52:31 +0100
-Subject: [PATCH 22/91] soc: mediatek: add compat string for mt7623 to scpsys
+Subject: [PATCH 022/102] soc: mediatek: add compat string for mt7623 to
+ scpsys
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/soc/mediatek/mtk-scpsys-mt2701.c | 2 ++
1 file changed, 2 insertions(+)
-diff --git a/drivers/soc/mediatek/mtk-scpsys-mt2701.c b/drivers/soc/mediatek/mtk-scpsys-mt2701.c
-index 339d5b8..3a31946 100644
--- a/drivers/soc/mediatek/mtk-scpsys-mt2701.c
+++ b/drivers/soc/mediatek/mtk-scpsys-mt2701.c
-@@ -136,6 +136,8 @@ static const struct of_device_id of_scpsys_match_tbl[] = {
+@@ -136,6 +136,8 @@ static const struct of_device_id of_scps
{
.compatible = "mediatek,mt2701-scpsys",
}, {
@@ -21,6 +20,3 @@ index 339d5b8..3a31946 100644
/* sentinel */
}
};
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0023-ARM-dts-mediatek-add-MT7623-basic-support.patch b/target/linux/mediatek/patches-4.4/0023-ARM-dts-mediatek-add-MT7623-basic-support.patch
index edc20b7855..5be3b27eb2 100644
--- a/target/linux/mediatek/patches-4.4/0023-ARM-dts-mediatek-add-MT7623-basic-support.patch
+++ b/target/linux/mediatek/patches-4.4/0023-ARM-dts-mediatek-add-MT7623-basic-support.patch
@@ -1,23 +1,21 @@
-From 83ef9fb21a896ac03c3a78bc3ae0b21f3b0a43a3 Mon Sep 17 00:00:00 2001
+From 51d5ca9e151eb323bd965e72ad1e1dc93fcf7b13 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Tue, 5 Jan 2016 12:16:17 +0100
-Subject: [PATCH 23/91] ARM: dts: mediatek: add MT7623 basic support
+Subject: [PATCH 023/102] ARM: dts: mediatek: add MT7623 basic support
This adds basic chip support for Mediatek MT7623.
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/arm/boot/dts/Makefile | 1 +
- arch/arm/boot/dts/mt7623-evb.dts | 474 +++++++++++++++++++++++++++++
- arch/arm/boot/dts/mt7623.dtsi | 593 +++++++++++++++++++++++++++++++++++++
+ arch/arm/boot/dts/mt7623-evb.dts | 421 ++++++++++++++++++++++++++
+ arch/arm/boot/dts/mt7623.dtsi | 601 +++++++++++++++++++++++++++++++++++++
arch/arm/mach-mediatek/Kconfig | 4 +
arch/arm/mach-mediatek/mediatek.c | 1 +
- 5 files changed, 1073 insertions(+)
+ 5 files changed, 1028 insertions(+)
create mode 100644 arch/arm/boot/dts/mt7623-evb.dts
create mode 100644 arch/arm/boot/dts/mt7623.dtsi
-diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
-index 30bbc37..2bce370 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -774,6 +774,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \
@@ -28,12 +26,9 @@ index 30bbc37..2bce370 100644
mt8127-moose.dtb \
mt8135-evbp1.dtb
dtb-$(CONFIG_ARCH_ZX) += zx296702-ad1.dtb
-diff --git a/arch/arm/boot/dts/mt7623-evb.dts b/arch/arm/boot/dts/mt7623-evb.dts
-new file mode 100644
-index 0000000..70b92a4
--- /dev/null
+++ b/arch/arm/boot/dts/mt7623-evb.dts
-@@ -0,0 +1,474 @@
+@@ -0,0 +1,421 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: John Crispin <blogic@openwrt.org>
@@ -323,127 +318,32 @@ index 0000000..70b92a4
+ status = "okay";
+};
+
-+&mmc0 {
-+ status = "okay";
-+ pinctrl-names = "default", "state_uhs";
-+ pinctrl-0 = <&mmc0_pins_default>;
-+ pinctrl-1 = <&mmc0_pins_uhs>;
-+ bus-width = <8>;
-+ max-frequency = <50000000>;
-+ cap-mmc-highspeed;
-+ vmmc-supply = <&mt6323_vemc3v3_reg>;
-+ vqmmc-supply = <&mt6323_vio18_reg>;
-+ non-removable;
-+};
-+
-+&mmc1 {
-+ status = "okay";
-+ pinctrl-names = "default", "state_uhs";
-+ pinctrl-0 = <&mmc1_pins_default>;
-+ pinctrl-1 = <&mmc1_pins_uhs>;
-+ bus-width = <4>;
-+ max-frequency = <50000000>;
-+ cap-sd-highspeed;
-+ sd-uhs-sdr25;
-+// cd-gpios = <&pio 132 0>;
-+ vmmc-supply = <&mt6323_vmch_reg>;
-+ vqmmc-supply = <&mt6323_vmc_reg>;
-+};
-+
+&pio {
-+ mmc0_pins_default: mmc0default {
-+ pins_cmd_dat {
-+ pinmux = <MT7623_PIN_111_MSDC0_DAT7_FUNC_MSDC0_DAT7>,
-+ <MT7623_PIN_112_MSDC0_DAT6_FUNC_MSDC0_DAT6>,
-+ <MT7623_PIN_113_MSDC0_DAT5_FUNC_MSDC0_DAT5>,
-+ <MT7623_PIN_114_MSDC0_DAT4_FUNC_MSDC0_DAT4>,
-+ <MT7623_PIN_118_MSDC0_DAT3_FUNC_MSDC0_DAT3>,
-+ <MT7623_PIN_119_MSDC0_DAT2_FUNC_MSDC0_DAT2>,
-+ <MT7623_PIN_120_MSDC0_DAT1_FUNC_MSDC0_DAT1>,
-+ <MT7623_PIN_121_MSDC0_DAT0_FUNC_MSDC0_DAT0>,
-+ <MT7623_PIN_116_MSDC0_CMD_FUNC_MSDC0_CMD>;
-+ input-enable;
-+ bias-pull-up;
-+ };
-+
-+ pins_clk {
-+ pinmux = <MT7623_PIN_117_MSDC0_CLK_FUNC_MSDC0_CLK>;
-+ bias-pull-down;
-+ };
-+
-+ pins_rst {
-+ pinmux = <MT7623_PIN_115_MSDC0_RSTB_FUNC_MSDC0_RSTB>;
-+ bias-pull-up;
++ nand_pins_default: nanddefault {
++ pins_dat {
++ pinmux = <MT7623_PIN_111_MSDC0_DAT7_FUNC_NLD7>,
++ <MT7623_PIN_112_MSDC0_DAT6_FUNC_NLD6>,
++ <MT7623_PIN_114_MSDC0_DAT4_FUNC_NLD4>,
++ <MT7623_PIN_118_MSDC0_DAT3_FUNC_NLD3>,
++ <MT7623_PIN_121_MSDC0_DAT0_FUNC_NLD0>,
++ <MT7623_PIN_120_MSDC0_DAT1_FUNC_NLD1>,
++ <MT7623_PIN_113_MSDC0_DAT5_FUNC_NLD5>,
++ <MT7623_PIN_115_MSDC0_RSTB_FUNC_NLD8>,
++ <MT7623_PIN_119_MSDC0_DAT2_FUNC_NLD2>;
++ input-enable;
++ drive-strength = <MTK_DRIVE_8mA>;
++ bias-pull-up;
+ };
-+ };
+
-+ mmc0_pins_uhs: mmc0 {
-+ pins_cmd_dat {
-+ pinmux = <MT7623_PIN_111_MSDC0_DAT7_FUNC_MSDC0_DAT7>,
-+ <MT7623_PIN_112_MSDC0_DAT6_FUNC_MSDC0_DAT6>,
-+ <MT7623_PIN_113_MSDC0_DAT5_FUNC_MSDC0_DAT5>,
-+ <MT7623_PIN_114_MSDC0_DAT4_FUNC_MSDC0_DAT4>,
-+ <MT7623_PIN_118_MSDC0_DAT3_FUNC_MSDC0_DAT3>,
-+ <MT7623_PIN_119_MSDC0_DAT2_FUNC_MSDC0_DAT2>,
-+ <MT7623_PIN_120_MSDC0_DAT1_FUNC_MSDC0_DAT1>,
-+ <MT7623_PIN_121_MSDC0_DAT0_FUNC_MSDC0_DAT0>,
-+ <MT7623_PIN_116_MSDC0_CMD_FUNC_MSDC0_CMD>;
-+ input-enable;
-+ drive-strength = <MTK_DRIVE_2mA>;
-+ bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
-+ };
-+
-+ pins_clk {
-+ pinmux = <MT7623_PIN_117_MSDC0_CLK_FUNC_MSDC0_CLK>;
-+ drive-strength = <MTK_DRIVE_2mA>;
-+ bias-pull-down = <MTK_PUPD_SET_R1R0_01>;
-+ };
-+
-+ pins_rst {
-+ pinmux = <MT7623_PIN_115_MSDC0_RSTB_FUNC_MSDC0_RSTB>;
-+ bias-pull-up;
-+ };
-+ };
-+
-+ mmc1_pins_default: mmc1default {
-+ pins_cmd_dat {
-+ pinmux = <MT7623_PIN_107_MSDC1_DAT0_FUNC_MSDC1_DAT0>,
-+ <MT7623_PIN_108_MSDC1_DAT1_FUNC_MSDC1_DAT1>,
-+ <MT7623_PIN_109_MSDC1_DAT2_FUNC_MSDC1_DAT2>,
-+ <MT7623_PIN_110_MSDC1_DAT3_FUNC_MSDC1_DAT3>,
-+ <MT7623_PIN_105_MSDC1_CMD_FUNC_MSDC1_CMD>;
-+ input-enable;
-+ drive-strength = <MTK_DRIVE_4mA>;
++ pins_we {
++ pinmux = <MT7623_PIN_117_MSDC0_CLK_FUNC_NWEB>;
++ drive-strength = <MTK_DRIVE_8mA>;
+ bias-pull-up = <MTK_PUPD_SET_R1R0_10>;
+ };
+
-+ pins_clk {
-+ pinmux = <MT7623_PIN_106_MSDC1_CLK_FUNC_MSDC1_CLK>;
-+ bias-pull-down;
-+ drive-strength = <MTK_DRIVE_4mA>;
-+ };
-+
-+// pins_insert {
-+// pinmux = <MT8173_PIN_132_I2S0_DATA1_FUNC_GPIO132>;
-+// bias-pull-up;
-+// };
-+ };
-+
-+ mmc1_pins_uhs: mmc1 {
-+ pins_cmd_dat {
-+ pinmux = <MT7623_PIN_107_MSDC1_DAT0_FUNC_MSDC1_DAT0>,
-+ <MT7623_PIN_108_MSDC1_DAT1_FUNC_MSDC1_DAT1>,
-+ <MT7623_PIN_109_MSDC1_DAT2_FUNC_MSDC1_DAT2>,
-+ <MT7623_PIN_110_MSDC1_DAT3_FUNC_MSDC1_DAT3>,
-+ <MT7623_PIN_105_MSDC1_CMD_FUNC_MSDC1_CMD>;
-+ input-enable;
-+ drive-strength = <MTK_DRIVE_4mA>;
-+ bias-pull-up = <MTK_PUPD_SET_R1R0_10>;
-+ };
-+
-+ pins_clk {
-+ pinmux = <MT7623_PIN_106_MSDC1_CLK_FUNC_MSDC1_CLK>;
-+ drive-strength = <MTK_DRIVE_4mA>;
++ pins_ale {
++ pinmux = <MT7623_PIN_116_MSDC0_CMD_FUNC_NALE>;
++ drive-strength = <MTK_DRIVE_8mA>;
+ bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+ };
+ };
@@ -474,6 +374,48 @@ index 0000000..70b92a4
+ };
+};
+
++&nandc {
++ status = "okay";
++ pinctrl-names = "default";
++ pinctrl-0 = <&nand_pins_default>;
++ nand@0 {
++ reg = <0>;
++ partitions {
++ compatible = "fixed-partitions";
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ partition@C0000 {
++ label = "uboot-env";
++ reg = <0xC0000 0x40000>;
++ };
++
++ partition@100000 {
++ label = "factory";
++ reg = <0x100000 0x40000>;
++ };
++
++ partition@140000 {
++ label = "kernel";
++ reg = <0x140000 0x2000000>;
++ };
++
++ partition@2140000 {
++ label = "recovery";
++ reg = <0x2140000 0x2000000>;
++ };
++
++ partition@4140000 {
++ label = "rootfs";
++ reg = <0x4140000 0x1000000>;
++ };
++ };
++ };
++};
++&bch {
++ status = "okay";
++};
++
+&usb1 {
+ vusb33-supply = <&mt6323_vusb_reg>;
+ vbus-supply = <&usb_p1_vbus>;
@@ -508,12 +450,9 @@ index 0000000..70b92a4
+ mediatek,reset-pin = <&pio 15 0>;
+ status = "okay";
+};
-diff --git a/arch/arm/boot/dts/mt7623.dtsi b/arch/arm/boot/dts/mt7623.dtsi
-new file mode 100644
-index 0000000..80c1ab8
--- /dev/null
+++ b/arch/arm/boot/dts/mt7623.dtsi
-@@ -0,0 +1,593 @@
+@@ -0,0 +1,601 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: John Crispin <blogic@openwrt.org>
@@ -854,6 +793,7 @@ index 0000000..80c1ab8
+ compatible = "mediatek,mt2701-nfc";
+ reg = <0 0x1100d000 0 0x1000>;
+ interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_LOW>;
++ power-domains = <&scpsys MT2701_POWER_DOMAIN_IFR_MSC>;
+ clocks = <&pericfg CLK_PERI_NFI>,
+ <&pericfg CLK_PERI_NFI_PAD>;
+ clock-names = "nfi_clk", "pad_clk";
@@ -1073,8 +1013,15 @@ index 0000000..80c1ab8
+ compatible = "mediatek,eth-mac";
+ reg = <1>;
+
-+ phy-handle = <&phy5>;
+ status = "disabled";
++
++ phy-mode = "rgmii";
++
++ fixed-link {
++ speed = <1000>;
++ full-duplex;
++ pause;
++ };
+ };
+
+ mdio-bus {
@@ -1107,8 +1054,6 @@ index 0000000..80c1ab8
+ status = "disabled";
+ };
+};
-diff --git a/arch/arm/mach-mediatek/Kconfig b/arch/arm/mach-mediatek/Kconfig
-index 37dd438..7fb605e 100644
--- a/arch/arm/mach-mediatek/Kconfig
+++ b/arch/arm/mach-mediatek/Kconfig
@@ -21,6 +21,10 @@ config MACH_MT6592
@@ -1122,11 +1067,9 @@ index 37dd438..7fb605e 100644
config MACH_MT8127
bool "MediaTek MT8127 SoCs support"
default ARCH_MEDIATEK
-diff --git a/arch/arm/mach-mediatek/mediatek.c b/arch/arm/mach-mediatek/mediatek.c
-index d019a08..bcfca37 100644
--- a/arch/arm/mach-mediatek/mediatek.c
+++ b/arch/arm/mach-mediatek/mediatek.c
-@@ -46,6 +46,7 @@ static void __init mediatek_timer_init(void)
+@@ -46,6 +46,7 @@ static void __init mediatek_timer_init(v
static const char * const mediatek_board_dt_compat[] = {
"mediatek,mt6589",
"mediatek,mt6592",
@@ -1134,6 +1077,3 @@ index d019a08..bcfca37 100644
"mediatek,mt8127",
"mediatek,mt8135",
NULL,
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0024-dt-bindings-add-MediaTek-PCIe-binding-documentation.patch b/target/linux/mediatek/patches-4.4/0024-dt-bindings-add-MediaTek-PCIe-binding-documentation.patch
index 4874373ad5..d6fe977793 100644
--- a/target/linux/mediatek/patches-4.4/0024-dt-bindings-add-MediaTek-PCIe-binding-documentation.patch
+++ b/target/linux/mediatek/patches-4.4/0024-dt-bindings-add-MediaTek-PCIe-binding-documentation.patch
@@ -1,7 +1,7 @@
-From 427a938858630fe4cec1b3829624676a4106d236 Mon Sep 17 00:00:00 2001
+From 05be818061b9f2a0fa5ad0cde6881917ff14a2f2 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Wed, 6 Jan 2016 21:55:10 +0100
-Subject: [PATCH 24/91] dt-bindings: add MediaTek PCIe binding documentation
+Subject: [PATCH 024/102] dt-bindings: add MediaTek PCIe binding documentation
Signed-off-by: John Crispin <blogic@openwrt.org>
---
@@ -9,9 +9,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
1 file changed, 140 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pci/mediatek-pcie.txt
-diff --git a/Documentation/devicetree/bindings/pci/mediatek-pcie.txt b/Documentation/devicetree/bindings/pci/mediatek-pcie.txt
-new file mode 100644
-index 0000000..8fea3ed
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/mediatek-pcie.txt
@@ -0,0 +1,140 @@
@@ -155,6 +152,3 @@ index 0000000..8fea3ed
+ status = "okay";
+ };
+ };
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0025-PCI-mediatek-add-support-for-PCIe-found-on-MT7623-MT.patch b/target/linux/mediatek/patches-4.4/0025-PCI-mediatek-add-support-for-PCIe-found-on-MT7623-MT.patch
index a6534b6643..bcb109d6a9 100644
--- a/target/linux/mediatek/patches-4.4/0025-PCI-mediatek-add-support-for-PCIe-found-on-MT7623-MT.patch
+++ b/target/linux/mediatek/patches-4.4/0025-PCI-mediatek-add-support-for-PCIe-found-on-MT7623-MT.patch
@@ -1,7 +1,7 @@
-From 5571cc63036daf0e0a05f07b0137fee86d58acb0 Mon Sep 17 00:00:00 2001
+From 8ab1d4e0a9a68e03f472dee1c036a01d0198c20c Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Tue, 5 Jan 2016 20:20:04 +0100
-Subject: [PATCH 25/91] PCI: mediatek: add support for PCIe found on
+Subject: [PATCH 025/102] PCI: mediatek: add support for PCIe found on
MT7623/MT2701
Add PCIe controller support on MediaTek MT2701/MT7623. The driver supports
@@ -17,8 +17,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
4 files changed, 654 insertions(+)
create mode 100644 drivers/pci/host/pcie-mediatek.c
-diff --git a/arch/arm/mach-mediatek/Kconfig b/arch/arm/mach-mediatek/Kconfig
-index 7fb605e..a7fef77 100644
--- a/arch/arm/mach-mediatek/Kconfig
+++ b/arch/arm/mach-mediatek/Kconfig
@@ -24,6 +24,7 @@ config MACH_MT6592
@@ -29,11 +27,9 @@ index 7fb605e..a7fef77 100644
config MACH_MT8127
bool "MediaTek MT8127 SoCs support"
-diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
-index f131ba9..912f0e1 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
-@@ -172,4 +172,15 @@ config PCI_HISI
+@@ -173,4 +173,15 @@ config PCI_HISI
help
Say Y here if you want PCIe controller support on HiSilicon HIP05 SoC
@@ -49,18 +45,13 @@ index f131ba9..912f0e1 100644
+ PCIe include one Host/PCI bridge and 3 PCIe MAC.
+
endmenu
-diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
-index 9d4d3c6..3b53374 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
-@@ -20,3 +20,4 @@ obj-$(CONFIG_PCIE_IPROC_BCMA) += pcie-iproc-bcma.o
+@@ -20,3 +20,4 @@ obj-$(CONFIG_PCIE_IPROC_BCMA) += pcie-ip
obj-$(CONFIG_PCIE_ALTERA) += pcie-altera.o
obj-$(CONFIG_PCIE_ALTERA_MSI) += pcie-altera-msi.o
obj-$(CONFIG_PCI_HISI) += pcie-hisi.o
+obj-$(CONFIG_PCIE_MTK) += pcie-mediatek.o
-diff --git a/drivers/pci/host/pcie-mediatek.c b/drivers/pci/host/pcie-mediatek.c
-new file mode 100644
-index 0000000..ef03952
--- /dev/null
+++ b/drivers/pci/host/pcie-mediatek.c
@@ -0,0 +1,641 @@
@@ -705,6 +696,3 @@ index 0000000..ef03952
+}
+
+module_init(mtk_pcie_init);
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0026-scpsys-various-fixes.patch b/target/linux/mediatek/patches-4.4/0026-scpsys-various-fixes.patch
index 7f64c518a1..7ec3033463 100644
--- a/target/linux/mediatek/patches-4.4/0026-scpsys-various-fixes.patch
+++ b/target/linux/mediatek/patches-4.4/0026-scpsys-various-fixes.patch
@@ -1,7 +1,7 @@
-From a366216a08408949eca2d7823273da6826d3c483 Mon Sep 17 00:00:00 2001
+From 59aafd667d2880c90776931b6102b8252214d93c Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 21 Feb 2016 13:52:12 +0100
-Subject: [PATCH 26/91] scpsys: various fixes
+Subject: [PATCH 026/102] scpsys: various fixes
---
drivers/clk/mediatek/clk-mt2701.c | 2 ++
@@ -9,11 +9,9 @@ Subject: [PATCH 26/91] scpsys: various fixes
include/dt-bindings/power/mt2701-power.h | 4 ++--
3 files changed, 4 insertions(+), 10 deletions(-)
-diff --git a/drivers/clk/mediatek/clk-mt2701.c b/drivers/clk/mediatek/clk-mt2701.c
-index 0e40bb8..812b347 100644
--- a/drivers/clk/mediatek/clk-mt2701.c
+++ b/drivers/clk/mediatek/clk-mt2701.c
-@@ -1043,6 +1043,8 @@ static void __init mtk_ethsys_init(struct device_node *node)
+@@ -1043,6 +1043,8 @@ static void __init mtk_ethsys_init(struc
if (r)
pr_err("%s(): could not register clock provider: %d\n",
__func__, r);
@@ -22,11 +20,9 @@ index 0e40bb8..812b347 100644
}
CLK_OF_DECLARE(mtk_ethsys, "mediatek,mt2701-ethsys", mtk_ethsys_init);
-diff --git a/drivers/soc/mediatek/mtk-scpsys-mt2701.c b/drivers/soc/mediatek/mtk-scpsys-mt2701.c
-index 3a31946..19489bc 100644
--- a/drivers/soc/mediatek/mtk-scpsys-mt2701.c
+++ b/drivers/soc/mediatek/mtk-scpsys-mt2701.c
-@@ -61,14 +61,6 @@ static const struct scp_domain_data scp_domain_data[] = {
+@@ -61,14 +61,6 @@ static const struct scp_domain_data scp_
.bus_prot_mask = MT2701_TOP_AXI_PROT_EN_DISP,
.active_wakeup = true,
},
@@ -41,8 +37,6 @@ index 3a31946..19489bc 100644
[MT2701_POWER_DOMAIN_VDEC] = {
.name = "vdec",
.sta_mask = VDE_PWR_STA_MASK,
-diff --git a/include/dt-bindings/power/mt2701-power.h b/include/dt-bindings/power/mt2701-power.h
-index 64cc826..c168597 100644
--- a/include/dt-bindings/power/mt2701-power.h
+++ b/include/dt-bindings/power/mt2701-power.h
@@ -16,12 +16,12 @@
@@ -60,6 +54,3 @@ index 64cc826..c168597 100644
+#define MT2701_POWER_DOMAIN_IFR_MSC 2
#endif /* _DT_BINDINGS_POWER_MT2701_POWER_H */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0027-soc-mediatek-PMIC-wrap-Clear-the-vldclr-if-state-mac.patch b/target/linux/mediatek/patches-4.4/0027-soc-mediatek-PMIC-wrap-Clear-the-vldclr-if-state-mac.patch
index dfd274b1e2..964373bf49 100644
--- a/target/linux/mediatek/patches-4.4/0027-soc-mediatek-PMIC-wrap-Clear-the-vldclr-if-state-mac.patch
+++ b/target/linux/mediatek/patches-4.4/0027-soc-mediatek-PMIC-wrap-Clear-the-vldclr-if-state-mac.patch
@@ -1,7 +1,7 @@
-From 4d02177361d13355d98a38830c69bb9add3c109c Mon Sep 17 00:00:00 2001
+From 55231d8299d3dccde8588ed2e86c2bc0ef2e12ce Mon Sep 17 00:00:00 2001
From: Henry Chen <henryc.chen@mediatek.com>
Date: Mon, 4 Jan 2016 20:02:52 +0800
-Subject: [PATCH 27/91] soc: mediatek: PMIC wrap: Clear the vldclr if state
+Subject: [PATCH 027/102] soc: mediatek: PMIC wrap: Clear the vldclr if state
machine stay on FSM_VLDCLR state.
Sometimes PMIC is too busy to send data in time to cause pmic wrap timeout,
@@ -20,11 +20,9 @@ Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
drivers/soc/mediatek/mtk-pmic-wrap.c | 22 ++++++++++++++++++++--
1 file changed, 20 insertions(+), 2 deletions(-)
-diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
-index 105597a..696071b 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
-@@ -412,6 +412,20 @@ static bool pwrap_is_fsm_vldclr(struct pmic_wrapper *wrp)
+@@ -412,6 +412,20 @@ static bool pwrap_is_fsm_vldclr(struct p
return PWRAP_GET_WACS_FSM(val) == PWRAP_WACS_FSM_WFVLDCLR;
}
@@ -45,7 +43,7 @@ index 105597a..696071b 100644
static bool pwrap_is_sync_idle(struct pmic_wrapper *wrp)
{
return pwrap_readl(wrp, PWRAP_WACS2_RDATA) & PWRAP_STATE_SYNC_IDLE0;
-@@ -445,8 +459,10 @@ static int pwrap_write(struct pmic_wrapper *wrp, u32 adr, u32 wdata)
+@@ -445,8 +459,10 @@ static int pwrap_write(struct pmic_wrapp
int ret;
ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle);
@@ -57,7 +55,7 @@ index 105597a..696071b 100644
pwrap_writel(wrp, (1 << 31) | ((adr >> 1) << 16) | wdata,
PWRAP_WACS2_CMD);
-@@ -459,8 +475,10 @@ static int pwrap_read(struct pmic_wrapper *wrp, u32 adr, u32 *rdata)
+@@ -459,8 +475,10 @@ static int pwrap_read(struct pmic_wrappe
int ret;
ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle);
@@ -69,6 +67,3 @@ index 105597a..696071b 100644
pwrap_writel(wrp, (adr >> 1) << 16, PWRAP_WACS2_CMD);
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0028-ARM-mediatek-add-MT7623-smp-bringup-code.patch b/target/linux/mediatek/patches-4.4/0028-ARM-mediatek-add-MT7623-smp-bringup-code.patch
index 8c22fd9a26..4aacd26a1f 100644
--- a/target/linux/mediatek/patches-4.4/0028-ARM-mediatek-add-MT7623-smp-bringup-code.patch
+++ b/target/linux/mediatek/patches-4.4/0028-ARM-mediatek-add-MT7623-smp-bringup-code.patch
@@ -1,7 +1,7 @@
-From e4a5c39f75a11ecb78d1243b19b929af54f888fa Mon Sep 17 00:00:00 2001
+From d088a94afc768683a881b627b6737442158e7db6 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Tue, 5 Jan 2016 17:24:28 +0100
-Subject: [PATCH 28/91] ARM: mediatek: add MT7623 smp bringup code
+Subject: [PATCH 028/102] ARM: mediatek: add MT7623 smp bringup code
Add support for booting secondary CPUs on MT7623.
@@ -11,11 +11,9 @@ Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
arch/arm/mach-mediatek/platsmp.c | 7 +++++++
1 file changed, 7 insertions(+)
-diff --git a/arch/arm/mach-mediatek/platsmp.c b/arch/arm/mach-mediatek/platsmp.c
-index 8141f3f..8151400 100644
--- a/arch/arm/mach-mediatek/platsmp.c
+++ b/arch/arm/mach-mediatek/platsmp.c
-@@ -44,6 +44,12 @@ static const struct mtk_smp_boot_info mtk_mt6589_boot = {
+@@ -44,6 +44,12 @@ static const struct mtk_smp_boot_info mt
{ 0x38, 0x3c, 0x40 },
};
@@ -28,7 +26,7 @@ index 8141f3f..8151400 100644
static const struct of_device_id mtk_tz_smp_boot_infos[] __initconst = {
{ .compatible = "mediatek,mt8135", .data = &mtk_mt8135_tz_boot },
{ .compatible = "mediatek,mt8127", .data = &mtk_mt8135_tz_boot },
-@@ -51,6 +57,7 @@ static const struct of_device_id mtk_tz_smp_boot_infos[] __initconst = {
+@@ -51,6 +57,7 @@ static const struct of_device_id mtk_tz_
static const struct of_device_id mtk_smp_boot_infos[] __initconst = {
{ .compatible = "mediatek,mt6589", .data = &mtk_mt6589_boot },
@@ -36,6 +34,3 @@ index 8141f3f..8151400 100644
};
static void __iomem *mtk_smp_base;
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0029-soc-mediatek-PMIC-wrap-clear-the-STAUPD_TRIG-bit-of-.patch b/target/linux/mediatek/patches-4.4/0029-soc-mediatek-PMIC-wrap-clear-the-STAUPD_TRIG-bit-of-.patch
index 6ad960ec42..eb936a789b 100644
--- a/target/linux/mediatek/patches-4.4/0029-soc-mediatek-PMIC-wrap-clear-the-STAUPD_TRIG-bit-of-.patch
+++ b/target/linux/mediatek/patches-4.4/0029-soc-mediatek-PMIC-wrap-clear-the-STAUPD_TRIG-bit-of-.patch
@@ -1,8 +1,8 @@
-From b4a6293df00036129d26a7f06bfb220ba5a73c42 Mon Sep 17 00:00:00 2001
+From b92861fbc79b3a7a9bc1c51e2dbfa2c191cc27ea Mon Sep 17 00:00:00 2001
From: Henry Chen <henryc.chen@mediatek.com>
Date: Thu, 21 Jan 2016 19:04:00 +0800
-Subject: [PATCH 29/91] soc: mediatek: PMIC wrap: clear the STAUPD_TRIG bit of
- WDT_SRC_EN
+Subject: [PATCH 029/102] soc: mediatek: PMIC wrap: clear the STAUPD_TRIG bit
+ of WDT_SRC_EN
Since STAUPD interrupts aren't handled on mt8173, disable watchdog timeout
monitor of STAUPD to avoid WDT_INT triggered by STAUPD.
@@ -14,8 +14,6 @@ Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
drivers/soc/mediatek/mtk-pmic-wrap.c | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
-diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
-index 696071b..0d9b19a 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -60,6 +60,15 @@
@@ -34,7 +32,7 @@ index 696071b..0d9b19a 100644
/* macro for slave device wrapper registers */
#define PWRAP_DEW_BASE 0xbc00
#define PWRAP_DEW_EVENT_OUT_EN (PWRAP_DEW_BASE + 0x0)
-@@ -822,7 +831,7 @@ MODULE_DEVICE_TABLE(of, of_pwrap_match_tbl);
+@@ -822,7 +831,7 @@ MODULE_DEVICE_TABLE(of, of_pwrap_match_t
static int pwrap_probe(struct platform_device *pdev)
{
@@ -43,7 +41,7 @@ index 696071b..0d9b19a 100644
struct pmic_wrapper *wrp;
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *of_id =
-@@ -912,7 +921,13 @@ static int pwrap_probe(struct platform_device *pdev)
+@@ -912,7 +921,13 @@ static int pwrap_probe(struct platform_d
/* Initialize watchdog, may not be done by the bootloader */
pwrap_writel(wrp, 0xf, PWRAP_WDT_UNIT);
@@ -58,6 +56,3 @@ index 696071b..0d9b19a 100644
pwrap_writel(wrp, 0x1, PWRAP_TIMER_EN);
pwrap_writel(wrp, ~((1 << 31) | (1 << 1)), PWRAP_INT_EN);
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0030-ARM-mediatek-add-mt2701-smp-bringup-code.patch b/target/linux/mediatek/patches-4.4/0030-ARM-mediatek-add-mt2701-smp-bringup-code.patch
index 61fa475046..790ccca1ff 100644
--- a/target/linux/mediatek/patches-4.4/0030-ARM-mediatek-add-mt2701-smp-bringup-code.patch
+++ b/target/linux/mediatek/patches-4.4/0030-ARM-mediatek-add-mt2701-smp-bringup-code.patch
@@ -1,7 +1,7 @@
-From 0befbd007b72ba2b14c65558d3bb72ea885496f6 Mon Sep 17 00:00:00 2001
+From f88ec31c6ba3a006d0be87ff1d99145f8cc85bee Mon Sep 17 00:00:00 2001
From: Louis Yu <louis.yu@mediatek.com>
Date: Thu, 7 Jan 2016 20:09:43 +0800
-Subject: [PATCH 30/91] ARM: mediatek: add mt2701 smp bringup code
+Subject: [PATCH 030/102] ARM: mediatek: add mt2701 smp bringup code
Add support for booting secondary CPUs on mt2701.
@@ -11,11 +11,9 @@ Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
arch/arm/mach-mediatek/platsmp.c | 1 +
1 file changed, 1 insertion(+)
-diff --git a/arch/arm/mach-mediatek/platsmp.c b/arch/arm/mach-mediatek/platsmp.c
-index 8151400..2078f92d5 100644
--- a/arch/arm/mach-mediatek/platsmp.c
+++ b/arch/arm/mach-mediatek/platsmp.c
-@@ -53,6 +53,7 @@ static const struct mtk_smp_boot_info mtk_mt7623_boot = {
+@@ -53,6 +53,7 @@ static const struct mtk_smp_boot_info mt
static const struct of_device_id mtk_tz_smp_boot_infos[] __initconst = {
{ .compatible = "mediatek,mt8135", .data = &mtk_mt8135_tz_boot },
{ .compatible = "mediatek,mt8127", .data = &mtk_mt8135_tz_boot },
@@ -23,6 +21,3 @@ index 8151400..2078f92d5 100644
};
static const struct of_device_id mtk_smp_boot_infos[] __initconst = {
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0031-dt-bindings-ARM-Mediatek-add-MT2701-7623-string-to-t.patch b/target/linux/mediatek/patches-4.4/0031-dt-bindings-ARM-Mediatek-add-MT2701-7623-string-to-t.patch
index dd20cca520..186b2f4e34 100644
--- a/target/linux/mediatek/patches-4.4/0031-dt-bindings-ARM-Mediatek-add-MT2701-7623-string-to-t.patch
+++ b/target/linux/mediatek/patches-4.4/0031-dt-bindings-ARM-Mediatek-add-MT2701-7623-string-to-t.patch
@@ -1,8 +1,8 @@
-From 9367fb14e1be8dd174f8d63ec83f7ee2d90ae733 Mon Sep 17 00:00:00 2001
+From 15f4d895578f02cbaed10b0f5f6853b873aba10b Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Wed, 20 Jan 2016 13:12:19 +0100
-Subject: [PATCH 31/91] dt-bindings: ARM: Mediatek: add MT2701/7623 string to
- the PMIC wrapper doc
+Subject: [PATCH 031/102] dt-bindings: ARM: Mediatek: add MT2701/7623 string
+ to the PMIC wrapper doc
Signed-off-by: John Crispin <blogic@openwrt.org>
Acked-by: Rob Herring <robh@kernel.org>
@@ -11,8 +11,6 @@ Cc: devicetree@vger.kernel.org
Documentation/devicetree/bindings/soc/mediatek/pwrap.txt | 1 +
1 file changed, 1 insertion(+)
-diff --git a/Documentation/devicetree/bindings/soc/mediatek/pwrap.txt b/Documentation/devicetree/bindings/soc/mediatek/pwrap.txt
-index ddeb5b6..107700d 100644
--- a/Documentation/devicetree/bindings/soc/mediatek/pwrap.txt
+++ b/Documentation/devicetree/bindings/soc/mediatek/pwrap.txt
@@ -18,6 +18,7 @@ IP Pairing
@@ -23,6 +21,3 @@ index ddeb5b6..107700d 100644
"mediatek,mt8135-pwrap" for MT8135 SoCs
"mediatek,mt8173-pwrap" for MT8173 SoCs
- interrupts: IRQ for pwrap in SOC
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0032-soc-mediatek-PMIC-wrap-don-t-duplicate-the-wrapper-d.patch b/target/linux/mediatek/patches-4.4/0032-soc-mediatek-PMIC-wrap-don-t-duplicate-the-wrapper-d.patch
index e350f445f2..8092e96d71 100644
--- a/target/linux/mediatek/patches-4.4/0032-soc-mediatek-PMIC-wrap-don-t-duplicate-the-wrapper-d.patch
+++ b/target/linux/mediatek/patches-4.4/0032-soc-mediatek-PMIC-wrap-don-t-duplicate-the-wrapper-d.patch
@@ -1,8 +1,8 @@
-From 7b7d59b4219c30e1b9601300348f1431fdab7081 Mon Sep 17 00:00:00 2001
+From 64e8091be39c3f0a7bf4651bd2045b8c86429d55 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Wed, 20 Jan 2016 06:42:01 +0100
-Subject: [PATCH 32/91] soc: mediatek: PMIC wrap: don't duplicate the wrapper
- data
+Subject: [PATCH 032/102] soc: mediatek: PMIC wrap: don't duplicate the
+ wrapper data
As we add support for more devices struct pmic_wrapper_type will grow and
we do not really want to start duplicating all the elements in
@@ -13,8 +13,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
drivers/soc/mediatek/mtk-pmic-wrap.c | 22 ++++++++--------------
1 file changed, 8 insertions(+), 14 deletions(-)
-diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
-index 0d9b19a..340c4b5 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -376,9 +376,7 @@ struct pmic_wrapper {
@@ -55,7 +53,7 @@ index 0d9b19a..340c4b5 100644
}
static bool pwrap_is_fsm_idle(struct pmic_wrapper *wrp)
-@@ -697,7 +695,7 @@ static int pwrap_init(struct pmic_wrapper *wrp)
+@@ -697,7 +695,7 @@ static int pwrap_init(struct pmic_wrappe
pwrap_writel(wrp, 1, PWRAP_WRAP_EN);
@@ -64,7 +62,7 @@ index 0d9b19a..340c4b5 100644
pwrap_writel(wrp, 1, PWRAP_WACS2_EN);
-@@ -742,7 +740,7 @@ static int pwrap_init(struct pmic_wrapper *wrp)
+@@ -742,7 +740,7 @@ static int pwrap_init(struct pmic_wrappe
pwrap_writel(wrp, 0x1, PWRAP_CRC_EN);
pwrap_writel(wrp, 0x0, PWRAP_SIG_MODE);
pwrap_writel(wrp, PWRAP_DEW_CRC_VAL, PWRAP_SIG_ADR);
@@ -73,7 +71,7 @@ index 0d9b19a..340c4b5 100644
if (pwrap_is_mt8135(wrp))
pwrap_writel(wrp, 0x7, PWRAP_RRARB_EN);
-@@ -836,7 +834,6 @@ static int pwrap_probe(struct platform_device *pdev)
+@@ -836,7 +834,6 @@ static int pwrap_probe(struct platform_d
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *of_id =
of_match_device(of_pwrap_match_tbl, &pdev->dev);
@@ -81,7 +79,7 @@ index 0d9b19a..340c4b5 100644
struct resource *res;
wrp = devm_kzalloc(&pdev->dev, sizeof(*wrp), GFP_KERNEL);
-@@ -845,10 +842,7 @@ static int pwrap_probe(struct platform_device *pdev)
+@@ -845,10 +842,7 @@ static int pwrap_probe(struct platform_d
platform_set_drvdata(pdev, wrp);
@@ -93,6 +91,3 @@ index 0d9b19a..340c4b5 100644
wrp->dev = &pdev->dev;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwrap");
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0033-soc-mediatek-PMIC-wrap-add-wrapper-callbacks-for-ini.patch b/target/linux/mediatek/patches-4.4/0033-soc-mediatek-PMIC-wrap-add-wrapper-callbacks-for-ini.patch
index 9b37004c46..9368a85f82 100644
--- a/target/linux/mediatek/patches-4.4/0033-soc-mediatek-PMIC-wrap-add-wrapper-callbacks-for-ini.patch
+++ b/target/linux/mediatek/patches-4.4/0033-soc-mediatek-PMIC-wrap-add-wrapper-callbacks-for-ini.patch
@@ -1,7 +1,7 @@
-From 35d879d80437cc6ed811538903e115dbcda777ac Mon Sep 17 00:00:00 2001
+From 756b919b7874cc241a276b4fc5bbec5b3fb4bca8 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Wed, 20 Jan 2016 05:27:17 +0100
-Subject: [PATCH 33/91] soc: mediatek: PMIC wrap: add wrapper callbacks for
+Subject: [PATCH 033/102] soc: mediatek: PMIC wrap: add wrapper callbacks for
init_reg_clock
Split init_reg_clock up into SoC specific callbacks. The patch also
@@ -12,8 +12,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
drivers/soc/mediatek/mtk-pmic-wrap.c | 70 ++++++++++++++++++----------------
1 file changed, 38 insertions(+), 32 deletions(-)
-diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
-index 340c4b5..b22b664 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -354,24 +354,6 @@ enum pwrap_type {
@@ -55,7 +53,7 @@ index 340c4b5..b22b664 100644
static inline int pwrap_is_mt8135(struct pmic_wrapper *wrp)
{
return wrp->master->type == PWRAP_MT8135;
-@@ -578,20 +567,23 @@ static int pwrap_init_sidly(struct pmic_wrapper *wrp)
+@@ -578,20 +567,23 @@ static int pwrap_init_sidly(struct pmic_
return 0;
}
@@ -92,7 +90,7 @@ index 340c4b5..b22b664 100644
return 0;
}
-@@ -699,7 +691,7 @@ static int pwrap_init(struct pmic_wrapper *wrp)
+@@ -699,7 +691,7 @@ static int pwrap_init(struct pmic_wrappe
pwrap_writel(wrp, 1, PWRAP_WACS2_EN);
@@ -101,7 +99,7 @@ index 340c4b5..b22b664 100644
if (ret)
return ret;
-@@ -814,6 +806,20 @@ static const struct regmap_config pwrap_regmap_config = {
+@@ -814,6 +806,20 @@ static const struct regmap_config pwrap_
.max_register = 0xffff,
};
@@ -122,6 +120,3 @@ index 340c4b5..b22b664 100644
static struct of_device_id of_pwrap_match_tbl[] = {
{
.compatible = "mediatek,mt8135-pwrap",
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0034-soc-mediatek-PMIC-wrap-split-SoC-specific-init-into-.patch b/target/linux/mediatek/patches-4.4/0034-soc-mediatek-PMIC-wrap-split-SoC-specific-init-into-.patch
index cb90f1e82f..6d9c99a695 100644
--- a/target/linux/mediatek/patches-4.4/0034-soc-mediatek-PMIC-wrap-split-SoC-specific-init-into-.patch
+++ b/target/linux/mediatek/patches-4.4/0034-soc-mediatek-PMIC-wrap-split-SoC-specific-init-into-.patch
@@ -1,8 +1,8 @@
-From d82889cec95358b917fcf29fc3214980deb138b9 Mon Sep 17 00:00:00 2001
+From a1bbd630710d5da89a9c347c84d7badd30e7e68a Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Wed, 20 Jan 2016 10:12:00 +0100
-Subject: [PATCH 34/91] soc: mediatek: PMIC wrap: split SoC specific init into
- callback
+Subject: [PATCH 034/102] soc: mediatek: PMIC wrap: split SoC specific init
+ into callback
This patch moves the SoC specific wrapper init code into separate callback
to avoid pwrap_init() getting too large. This is done by adding a new
@@ -16,8 +16,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
drivers/soc/mediatek/mtk-pmic-wrap.c | 67 +++++++++++++++++++++-------------
1 file changed, 42 insertions(+), 25 deletions(-)
-diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
-index b22b664..22c89e9 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -372,6 +372,7 @@ struct pmic_wrapper_type {
@@ -28,7 +26,7 @@ index b22b664..22c89e9 100644
};
static inline int pwrap_is_mt8135(struct pmic_wrapper *wrp)
-@@ -665,6 +666,41 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
+@@ -665,6 +666,41 @@ static int pwrap_init_cipher(struct pmic
return 0;
}
@@ -70,7 +68,7 @@ index b22b664..22c89e9 100644
static int pwrap_init(struct pmic_wrapper *wrp)
{
int ret;
-@@ -743,31 +779,10 @@ static int pwrap_init(struct pmic_wrapper *wrp)
+@@ -743,31 +779,10 @@ static int pwrap_init(struct pmic_wrappe
pwrap_writel(wrp, 0x5, PWRAP_STAUPD_PRD);
pwrap_writel(wrp, 0xff, PWRAP_STAUPD_GRPEN);
@@ -106,7 +104,7 @@ index b22b664..22c89e9 100644
}
/* Setup the init done registers */
-@@ -811,6 +826,7 @@ static struct pmic_wrapper_type pwrap_mt8135 = {
+@@ -811,6 +826,7 @@ static struct pmic_wrapper_type pwrap_mt
.type = PWRAP_MT8135,
.arb_en_all = 0x1ff,
.init_reg_clock = pwrap_mt8135_init_reg_clock,
@@ -114,7 +112,7 @@ index b22b664..22c89e9 100644
};
static struct pmic_wrapper_type pwrap_mt8173 = {
-@@ -818,6 +834,7 @@ static struct pmic_wrapper_type pwrap_mt8173 = {
+@@ -818,6 +834,7 @@ static struct pmic_wrapper_type pwrap_mt
.type = PWRAP_MT8173,
.arb_en_all = 0x3f,
.init_reg_clock = pwrap_mt8173_init_reg_clock,
@@ -122,6 +120,3 @@ index b22b664..22c89e9 100644
};
static struct of_device_id of_pwrap_match_tbl[] = {
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0035-soc-mediatek-PMIC-wrap-WRAP_INT_EN-needs-a-different.patch b/target/linux/mediatek/patches-4.4/0035-soc-mediatek-PMIC-wrap-WRAP_INT_EN-needs-a-different.patch
index 7a27a6c493..42fbe2e1ca 100644
--- a/target/linux/mediatek/patches-4.4/0035-soc-mediatek-PMIC-wrap-WRAP_INT_EN-needs-a-different.patch
+++ b/target/linux/mediatek/patches-4.4/0035-soc-mediatek-PMIC-wrap-WRAP_INT_EN-needs-a-different.patch
@@ -1,7 +1,7 @@
-From 613acba0068461948e6b5283df03d7c1e1583a40 Mon Sep 17 00:00:00 2001
+From 274fd9ba57170de88bbdf522cbd6c290c2e51fb8 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Wed, 20 Jan 2016 10:14:39 +0100
-Subject: [PATCH 35/91] soc: mediatek: PMIC wrap: WRAP_INT_EN needs a
+Subject: [PATCH 035/102] soc: mediatek: PMIC wrap: WRAP_INT_EN needs a
different bitmask for MT2701/7623
MT2701 and MT7623 use a different bitmask for PWRAP_INT_EN.
@@ -11,8 +11,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
drivers/soc/mediatek/mtk-pmic-wrap.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
-diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
-index 22c89e9..9df1135 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -371,6 +371,7 @@ struct pmic_wrapper_type {
@@ -23,7 +21,7 @@ index 22c89e9..9df1135 100644
int (*init_reg_clock)(struct pmic_wrapper *wrp);
int (*init_soc_specific)(struct pmic_wrapper *wrp);
};
-@@ -825,6 +826,7 @@ static struct pmic_wrapper_type pwrap_mt8135 = {
+@@ -825,6 +826,7 @@ static struct pmic_wrapper_type pwrap_mt
.regs = mt8135_regs,
.type = PWRAP_MT8135,
.arb_en_all = 0x1ff,
@@ -31,7 +29,7 @@ index 22c89e9..9df1135 100644
.init_reg_clock = pwrap_mt8135_init_reg_clock,
.init_soc_specific = pwrap_mt8135_init_soc_specific,
};
-@@ -833,6 +835,7 @@ static struct pmic_wrapper_type pwrap_mt8173 = {
+@@ -833,6 +835,7 @@ static struct pmic_wrapper_type pwrap_mt
.regs = mt8173_regs,
.type = PWRAP_MT8173,
.arb_en_all = 0x3f,
@@ -39,7 +37,7 @@ index 22c89e9..9df1135 100644
.init_reg_clock = pwrap_mt8173_init_reg_clock,
.init_soc_specific = pwrap_mt8173_init_soc_specific,
};
-@@ -946,7 +949,7 @@ static int pwrap_probe(struct platform_device *pdev)
+@@ -946,7 +949,7 @@ static int pwrap_probe(struct platform_d
PWRAP_WDT_SRC_MASK_NO_STAUPD : PWRAP_WDT_SRC_MASK_ALL;
pwrap_writel(wrp, wdt_src, PWRAP_WDT_SRC_EN);
pwrap_writel(wrp, 0x1, PWRAP_TIMER_EN);
@@ -48,6 +46,3 @@ index 22c89e9..9df1135 100644
irq = platform_get_irq(pdev, 0);
ret = devm_request_irq(wrp->dev, irq, pwrap_interrupt, IRQF_TRIGGER_HIGH,
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0036-soc-mediatek-PMIC-wrap-SPI_WRITE-needs-a-different-b.patch b/target/linux/mediatek/patches-4.4/0036-soc-mediatek-PMIC-wrap-SPI_WRITE-needs-a-different-b.patch
index f88981c31e..a80bd731d9 100644
--- a/target/linux/mediatek/patches-4.4/0036-soc-mediatek-PMIC-wrap-SPI_WRITE-needs-a-different-b.patch
+++ b/target/linux/mediatek/patches-4.4/0036-soc-mediatek-PMIC-wrap-SPI_WRITE-needs-a-different-b.patch
@@ -1,8 +1,8 @@
-From 1186088ab86b7286e1920dcbfbbbf2627a0daeda Mon Sep 17 00:00:00 2001
+From 511e697282c6425950b95373ac8dc59a42fd2485 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Wed, 20 Jan 2016 10:21:42 +0100
-Subject: [PATCH 36/91] soc: mediatek: PMIC wrap: SPI_WRITE needs a different
- bitmask for MT2701/7623
+Subject: [PATCH 036/102] soc: mediatek: PMIC wrap: SPI_WRITE needs a
+ different bitmask for MT2701/7623
Different SoCs will use different bitmask for the SPI_WRITE command. This
patch defines the bitmask in the pmic_wrapper_type struct. This allows us
@@ -13,8 +13,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
drivers/soc/mediatek/mtk-pmic-wrap.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
-diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
-index 9df1135..8ce1bad 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -372,6 +372,7 @@ struct pmic_wrapper_type {
@@ -25,7 +23,7 @@ index 9df1135..8ce1bad 100644
int (*init_reg_clock)(struct pmic_wrapper *wrp);
int (*init_soc_specific)(struct pmic_wrapper *wrp);
};
-@@ -511,15 +512,15 @@ static int pwrap_reset_spislave(struct pmic_wrapper *wrp)
+@@ -511,15 +512,15 @@ static int pwrap_reset_spislave(struct p
pwrap_writel(wrp, 1, PWRAP_MAN_EN);
pwrap_writel(wrp, 0, PWRAP_DIO_EN);
@@ -45,7 +43,7 @@ index 9df1135..8ce1bad 100644
PWRAP_MAN_CMD);
ret = pwrap_wait_for_state(wrp, pwrap_is_sync_idle);
-@@ -827,6 +828,7 @@ static struct pmic_wrapper_type pwrap_mt8135 = {
+@@ -827,6 +828,7 @@ static struct pmic_wrapper_type pwrap_mt
.type = PWRAP_MT8135,
.arb_en_all = 0x1ff,
.int_en_all = ~(BIT(31) | BIT(1)),
@@ -53,7 +51,7 @@ index 9df1135..8ce1bad 100644
.init_reg_clock = pwrap_mt8135_init_reg_clock,
.init_soc_specific = pwrap_mt8135_init_soc_specific,
};
-@@ -836,6 +838,7 @@ static struct pmic_wrapper_type pwrap_mt8173 = {
+@@ -836,6 +838,7 @@ static struct pmic_wrapper_type pwrap_mt
.type = PWRAP_MT8173,
.arb_en_all = 0x3f,
.int_en_all = ~(BIT(31) | BIT(1)),
@@ -61,6 +59,3 @@ index 9df1135..8ce1bad 100644
.init_reg_clock = pwrap_mt8173_init_reg_clock,
.init_soc_specific = pwrap_mt8173_init_soc_specific,
};
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0037-soc-mediatek-PMIC-wrap-move-wdt_src-into-the-pmic_wr.patch b/target/linux/mediatek/patches-4.4/0037-soc-mediatek-PMIC-wrap-move-wdt_src-into-the-pmic_wr.patch
index cccbe1034f..1e2c587605 100644
--- a/target/linux/mediatek/patches-4.4/0037-soc-mediatek-PMIC-wrap-move-wdt_src-into-the-pmic_wr.patch
+++ b/target/linux/mediatek/patches-4.4/0037-soc-mediatek-PMIC-wrap-move-wdt_src-into-the-pmic_wr.patch
@@ -1,7 +1,7 @@
-From 95f72db32afd545b88eaa04802736f1f84242a9f Mon Sep 17 00:00:00 2001
+From 6aecbc79322efd3068c6140f74a68654fbe5b5f6 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Wed, 20 Jan 2016 10:48:35 +0100
-Subject: [PATCH 37/91] soc: mediatek: PMIC wrap: move wdt_src into the
+Subject: [PATCH 037/102] soc: mediatek: PMIC wrap: move wdt_src into the
pmic_wrapper_type struct
Different SoCs will use different bitmask for the wdt_src. This patch
@@ -13,8 +13,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
drivers/soc/mediatek/mtk-pmic-wrap.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
-diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
-index 8ce1bad..aa54df3 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -373,6 +373,7 @@ struct pmic_wrapper_type {
@@ -25,7 +23,7 @@ index 8ce1bad..aa54df3 100644
int (*init_reg_clock)(struct pmic_wrapper *wrp);
int (*init_soc_specific)(struct pmic_wrapper *wrp);
};
-@@ -829,6 +830,7 @@ static struct pmic_wrapper_type pwrap_mt8135 = {
+@@ -829,6 +830,7 @@ static struct pmic_wrapper_type pwrap_mt
.arb_en_all = 0x1ff,
.int_en_all = ~(BIT(31) | BIT(1)),
.spi_w = PWRAP_MAN_CMD_SPI_WRITE,
@@ -33,7 +31,7 @@ index 8ce1bad..aa54df3 100644
.init_reg_clock = pwrap_mt8135_init_reg_clock,
.init_soc_specific = pwrap_mt8135_init_soc_specific,
};
-@@ -839,6 +841,7 @@ static struct pmic_wrapper_type pwrap_mt8173 = {
+@@ -839,6 +841,7 @@ static struct pmic_wrapper_type pwrap_mt
.arb_en_all = 0x3f,
.int_en_all = ~(BIT(31) | BIT(1)),
.spi_w = PWRAP_MAN_CMD_SPI_WRITE,
@@ -41,7 +39,7 @@ index 8ce1bad..aa54df3 100644
.init_reg_clock = pwrap_mt8173_init_reg_clock,
.init_soc_specific = pwrap_mt8173_init_soc_specific,
};
-@@ -858,7 +861,7 @@ MODULE_DEVICE_TABLE(of, of_pwrap_match_tbl);
+@@ -858,7 +861,7 @@ MODULE_DEVICE_TABLE(of, of_pwrap_match_t
static int pwrap_probe(struct platform_device *pdev)
{
@@ -50,7 +48,7 @@ index 8ce1bad..aa54df3 100644
struct pmic_wrapper *wrp;
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *of_id =
-@@ -948,9 +951,7 @@ static int pwrap_probe(struct platform_device *pdev)
+@@ -948,9 +951,7 @@ static int pwrap_probe(struct platform_d
* Since STAUPD was not used on mt8173 platform,
* so STAUPD of WDT_SRC which should be turned off
*/
@@ -61,6 +59,3 @@ index 8ce1bad..aa54df3 100644
pwrap_writel(wrp, 0x1, PWRAP_TIMER_EN);
pwrap_writel(wrp, wrp->master->int_en_all, PWRAP_INT_EN);
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0038-soc-mediatek-PMIC-wrap-remove-pwrap_is_mt8135-and-pw.patch b/target/linux/mediatek/patches-4.4/0038-soc-mediatek-PMIC-wrap-remove-pwrap_is_mt8135-and-pw.patch
index 7f8a2930a5..001793f585 100644
--- a/target/linux/mediatek/patches-4.4/0038-soc-mediatek-PMIC-wrap-remove-pwrap_is_mt8135-and-pw.patch
+++ b/target/linux/mediatek/patches-4.4/0038-soc-mediatek-PMIC-wrap-remove-pwrap_is_mt8135-and-pw.patch
@@ -1,8 +1,8 @@
-From bb19fd13b1ed629873ea144b22c4764aa4baa5ef Mon Sep 17 00:00:00 2001
+From da09b34ad22e8f065a02af114668f7d86357244a Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Wed, 20 Jan 2016 10:54:18 +0100
-Subject: [PATCH 38/91] soc: mediatek: PMIC wrap: remove pwrap_is_mt8135() and
- pwrap_is_mt8173()
+Subject: [PATCH 038/102] soc: mediatek: PMIC wrap: remove pwrap_is_mt8135()
+ and pwrap_is_mt8173()
With more SoCs being added the list of helper functions like these would
grow. To mitigate this problem we remove the existing helpers and change
@@ -18,8 +18,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
drivers/soc/mediatek/mtk-pmic-wrap.c | 28 ++++++++++++----------------
1 file changed, 12 insertions(+), 16 deletions(-)
-diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
-index aa54df3..a2bacda 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -374,20 +374,11 @@ struct pmic_wrapper_type {
@@ -44,7 +42,7 @@ index aa54df3..a2bacda 100644
static u32 pwrap_readl(struct pmic_wrapper *wrp, enum pwrap_regs reg)
{
return readl(wrp->base + wrp->master->regs[reg]);
-@@ -619,11 +610,14 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
+@@ -619,11 +610,14 @@ static int pwrap_init_cipher(struct pmic
pwrap_writel(wrp, 0x1, PWRAP_CIPHER_KEY_SEL);
pwrap_writel(wrp, 0x2, PWRAP_CIPHER_IV_SEL);
@@ -61,7 +59,7 @@ index aa54df3..a2bacda 100644
}
/* Config cipher mode @PMIC */
-@@ -713,7 +707,7 @@ static int pwrap_init(struct pmic_wrapper *wrp)
+@@ -713,7 +707,7 @@ static int pwrap_init(struct pmic_wrappe
if (wrp->rstc_bridge)
reset_control_reset(wrp->rstc_bridge);
@@ -70,7 +68,7 @@ index aa54df3..a2bacda 100644
/* Enable DCM */
pwrap_writel(wrp, 3, PWRAP_DCM_EN);
pwrap_writel(wrp, 0, PWRAP_DCM_DBC_PRD);
-@@ -773,7 +767,7 @@ static int pwrap_init(struct pmic_wrapper *wrp)
+@@ -773,7 +767,7 @@ static int pwrap_init(struct pmic_wrappe
pwrap_writel(wrp, PWRAP_DEW_CRC_VAL, PWRAP_SIG_ADR);
pwrap_writel(wrp, wrp->master->arb_en_all, PWRAP_HIPRIO_ARB_EN);
@@ -79,7 +77,7 @@ index aa54df3..a2bacda 100644
pwrap_writel(wrp, 0x7, PWRAP_RRARB_EN);
pwrap_writel(wrp, 0x1, PWRAP_WACS0_EN);
-@@ -793,7 +787,7 @@ static int pwrap_init(struct pmic_wrapper *wrp)
+@@ -793,7 +787,7 @@ static int pwrap_init(struct pmic_wrappe
pwrap_writel(wrp, 1, PWRAP_INIT_DONE0);
pwrap_writel(wrp, 1, PWRAP_INIT_DONE1);
@@ -88,7 +86,7 @@ index aa54df3..a2bacda 100644
writel(1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_INIT_DONE3);
writel(1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_INIT_DONE4);
}
-@@ -831,6 +825,7 @@ static struct pmic_wrapper_type pwrap_mt8135 = {
+@@ -831,6 +825,7 @@ static struct pmic_wrapper_type pwrap_mt
.int_en_all = ~(BIT(31) | BIT(1)),
.spi_w = PWRAP_MAN_CMD_SPI_WRITE,
.wdt_src = PWRAP_WDT_SRC_MASK_ALL,
@@ -96,7 +94,7 @@ index aa54df3..a2bacda 100644
.init_reg_clock = pwrap_mt8135_init_reg_clock,
.init_soc_specific = pwrap_mt8135_init_soc_specific,
};
-@@ -842,6 +837,7 @@ static struct pmic_wrapper_type pwrap_mt8173 = {
+@@ -842,6 +837,7 @@ static struct pmic_wrapper_type pwrap_mt
.int_en_all = ~(BIT(31) | BIT(1)),
.spi_w = PWRAP_MAN_CMD_SPI_WRITE,
.wdt_src = PWRAP_WDT_SRC_MASK_NO_STAUPD,
@@ -104,7 +102,7 @@ index aa54df3..a2bacda 100644
.init_reg_clock = pwrap_mt8173_init_reg_clock,
.init_soc_specific = pwrap_mt8173_init_soc_specific,
};
-@@ -889,7 +885,7 @@ static int pwrap_probe(struct platform_device *pdev)
+@@ -889,7 +885,7 @@ static int pwrap_probe(struct platform_d
return ret;
}
@@ -113,6 +111,3 @@ index aa54df3..a2bacda 100644
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"pwrap-bridge");
wrp->bridge_base = devm_ioremap_resource(wrp->dev, res);
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0039-soc-mediatek-PMIC-wrap-add-a-slave-specific-struct.patch b/target/linux/mediatek/patches-4.4/0039-soc-mediatek-PMIC-wrap-add-a-slave-specific-struct.patch
index 5fb66dbb5c..dea271af66 100644
--- a/target/linux/mediatek/patches-4.4/0039-soc-mediatek-PMIC-wrap-add-a-slave-specific-struct.patch
+++ b/target/linux/mediatek/patches-4.4/0039-soc-mediatek-PMIC-wrap-add-a-slave-specific-struct.patch
@@ -1,7 +1,8 @@
-From daa4d054bb0557799c8b324d7aa5f0a3a4a7b078 Mon Sep 17 00:00:00 2001
+From 21bdcd324f769545b1765fe391d939a1edd07cbb Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Wed, 20 Jan 2016 09:55:08 +0100
-Subject: [PATCH 39/91] soc: mediatek: PMIC wrap: add a slave specific struct
+Subject: [PATCH 039/102] soc: mediatek: PMIC wrap: add a slave specific
+ struct
This patch adds a new struct pwrap_slv_type that we use to store the slave
specific data. The patch adds 2 new helper functions to access the dew
@@ -12,8 +13,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
drivers/soc/mediatek/mtk-pmic-wrap.c | 159 ++++++++++++++++++++++++----------
1 file changed, 112 insertions(+), 47 deletions(-)
-diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
-index a2bacda..bcc841e 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -69,33 +69,54 @@
@@ -125,7 +124,7 @@ index a2bacda..bcc841e 100644
struct clk *clk_spi;
struct clk *clk_wrap;
struct reset_control *rstc;
-@@ -544,7 +575,8 @@ static int pwrap_init_sidly(struct pmic_wrapper *wrp)
+@@ -544,7 +575,8 @@ static int pwrap_init_sidly(struct pmic_
for (i = 0; i < 4; i++) {
pwrap_writel(wrp, i, PWRAP_SIDLY);
@@ -135,7 +134,7 @@ index a2bacda..bcc841e 100644
if (rdata == PWRAP_DEW_READ_TEST_VAL) {
dev_dbg(wrp->dev, "[Read Test] pass, SIDLY=%x\n", i);
pass |= 1 << i;
-@@ -593,7 +625,8 @@ static bool pwrap_is_pmic_cipher_ready(struct pmic_wrapper *wrp)
+@@ -593,7 +625,8 @@ static bool pwrap_is_pmic_cipher_ready(s
u32 rdata;
int ret;
@@ -145,7 +144,7 @@ index a2bacda..bcc841e 100644
if (ret)
return 0;
-@@ -621,12 +654,12 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
+@@ -621,12 +654,12 @@ static int pwrap_init_cipher(struct pmic
}
/* Config cipher mode @PMIC */
@@ -164,7 +163,7 @@ index a2bacda..bcc841e 100644
/* wait for cipher data ready@AP */
ret = pwrap_wait_for_state(wrp, pwrap_is_cipher_ready);
-@@ -643,7 +676,7 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
+@@ -643,7 +676,7 @@ static int pwrap_init_cipher(struct pmic
}
/* wait for cipher mode idle */
@@ -173,7 +172,7 @@ index a2bacda..bcc841e 100644
ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle_and_sync_idle);
if (ret) {
dev_err(wrp->dev, "cipher mode idle fail, ret=%d\n", ret);
-@@ -653,9 +686,11 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
+@@ -653,9 +686,11 @@ static int pwrap_init_cipher(struct pmic
pwrap_writel(wrp, 1, PWRAP_CIPHER_MODE);
/* Write Test */
@@ -188,7 +187,7 @@ index a2bacda..bcc841e 100644
dev_err(wrp->dev, "rdata=0x%04X\n", rdata);
return -EFAULT;
}
-@@ -677,8 +712,10 @@ static int pwrap_mt8135_init_soc_specific(struct pmic_wrapper *wrp)
+@@ -677,8 +712,10 @@ static int pwrap_mt8135_init_soc_specifi
writel(0x7ff, wrp->bridge_base + PWRAP_MT8135_BRIDGE_INT_EN);
/* enable PMIC event out and sources */
@@ -201,7 +200,7 @@ index a2bacda..bcc841e 100644
dev_err(wrp->dev, "enable dewrap fail\n");
return -EFAULT;
}
-@@ -689,8 +726,10 @@ static int pwrap_mt8135_init_soc_specific(struct pmic_wrapper *wrp)
+@@ -689,8 +726,10 @@ static int pwrap_mt8135_init_soc_specifi
static int pwrap_mt8173_init_soc_specific(struct pmic_wrapper *wrp)
{
/* PMIC_DEWRAP enables */
@@ -214,7 +213,7 @@ index a2bacda..bcc841e 100644
dev_err(wrp->dev, "enable dewrap fail\n");
return -EFAULT;
}
-@@ -734,7 +773,7 @@ static int pwrap_init(struct pmic_wrapper *wrp)
+@@ -734,7 +773,7 @@ static int pwrap_init(struct pmic_wrappe
return ret;
/* Enable dual IO mode */
@@ -223,7 +222,7 @@ index a2bacda..bcc841e 100644
/* Check IDLE & INIT_DONE in advance */
ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle_and_sync_idle);
-@@ -746,7 +785,7 @@ static int pwrap_init(struct pmic_wrapper *wrp)
+@@ -746,7 +785,7 @@ static int pwrap_init(struct pmic_wrappe
pwrap_writel(wrp, 1, PWRAP_DIO_EN);
/* Read Test */
@@ -232,7 +231,7 @@ index a2bacda..bcc841e 100644
if (rdata != PWRAP_DEW_READ_TEST_VAL) {
dev_err(wrp->dev, "Read test failed after switch to DIO mode: 0x%04x != 0x%04x\n",
PWRAP_DEW_READ_TEST_VAL, rdata);
-@@ -759,12 +798,13 @@ static int pwrap_init(struct pmic_wrapper *wrp)
+@@ -759,12 +798,13 @@ static int pwrap_init(struct pmic_wrappe
return ret;
/* Signature checking - using CRC */
@@ -248,7 +247,7 @@ index a2bacda..bcc841e 100644
pwrap_writel(wrp, wrp->master->arb_en_all, PWRAP_HIPRIO_ARB_EN);
if (wrp->master->type == PWRAP_MT8135)
-@@ -818,6 +858,21 @@ static const struct regmap_config pwrap_regmap_config = {
+@@ -818,6 +858,21 @@ static const struct regmap_config pwrap_
.max_register = 0xffff,
};
@@ -270,7 +269,7 @@ index a2bacda..bcc841e 100644
static struct pmic_wrapper_type pwrap_mt8135 = {
.regs = mt8135_regs,
.type = PWRAP_MT8135,
-@@ -862,8 +917,17 @@ static int pwrap_probe(struct platform_device *pdev)
+@@ -862,8 +917,17 @@ static int pwrap_probe(struct platform_d
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *of_id =
of_match_device(of_pwrap_match_tbl, &pdev->dev);
@@ -288,7 +287,7 @@ index a2bacda..bcc841e 100644
wrp = devm_kzalloc(&pdev->dev, sizeof(*wrp), GFP_KERNEL);
if (!wrp)
return -ENOMEM;
-@@ -871,6 +935,7 @@ static int pwrap_probe(struct platform_device *pdev)
+@@ -871,6 +935,7 @@ static int pwrap_probe(struct platform_d
platform_set_drvdata(pdev, wrp);
wrp->master = of_id->data;
@@ -296,6 +295,3 @@ index a2bacda..bcc841e 100644
wrp->dev = &pdev->dev;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwrap");
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0040-soc-mediatek-PMIC-wrap-add-mt6323-slave-support.patch b/target/linux/mediatek/patches-4.4/0040-soc-mediatek-PMIC-wrap-add-mt6323-slave-support.patch
index 509ba3346c..51f06288fb 100644
--- a/target/linux/mediatek/patches-4.4/0040-soc-mediatek-PMIC-wrap-add-mt6323-slave-support.patch
+++ b/target/linux/mediatek/patches-4.4/0040-soc-mediatek-PMIC-wrap-add-mt6323-slave-support.patch
@@ -1,7 +1,7 @@
-From 15143b59a26a06e890e2ba3c9944b3f751ce39bd Mon Sep 17 00:00:00 2001
+From 4418ba9a0bb105f00259d10ceb16f9e27199e9b0 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Wed, 20 Jan 2016 11:40:43 +0100
-Subject: [PATCH 40/91] soc: mediatek: PMIC wrap: add mt6323 slave support
+Subject: [PATCH 040/102] soc: mediatek: PMIC wrap: add mt6323 slave support
Add support for MT6323 slaves. This PMIC can be found on MT2701 and MT7623
EVB. The only function that we need to touch is pwrap_init_cipher().
@@ -11,8 +11,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
drivers/soc/mediatek/mtk-pmic-wrap.c | 43 ++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
-diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
-index bcc841e..0e4ebb8 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -93,6 +93,27 @@ enum dew_regs {
@@ -51,7 +49,7 @@ index bcc841e..0e4ebb8 100644
PMIC_MT6397,
};
-@@ -661,6 +683,19 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
+@@ -661,6 +683,19 @@ static int pwrap_init_cipher(struct pmic
pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_LOAD], 0x1);
pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_START], 0x1);
@@ -71,7 +69,7 @@ index bcc841e..0e4ebb8 100644
/* wait for cipher data ready@AP */
ret = pwrap_wait_for_state(wrp, pwrap_is_cipher_ready);
if (ret) {
-@@ -858,6 +893,11 @@ static const struct regmap_config pwrap_regmap_config = {
+@@ -858,6 +893,11 @@ static const struct regmap_config pwrap_
.max_register = 0xffff,
};
@@ -83,7 +81,7 @@ index bcc841e..0e4ebb8 100644
static const struct pwrap_slv_type pmic_mt6397 = {
.dew_regs = mt6397_regs,
.type = PMIC_MT6397,
-@@ -865,6 +905,9 @@ static const struct pwrap_slv_type pmic_mt6397 = {
+@@ -865,6 +905,9 @@ static const struct pwrap_slv_type pmic_
static const struct of_device_id of_slave_match_tbl[] = {
{
@@ -93,6 +91,3 @@ index bcc841e..0e4ebb8 100644
.compatible = "mediatek,mt6397",
.data = &pmic_mt6397,
}, {
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0041-soc-mediatek-PMIC-wrap-add-MT2701-7623-support.patch b/target/linux/mediatek/patches-4.4/0041-soc-mediatek-PMIC-wrap-add-MT2701-7623-support.patch
index b575405ab6..a50a34af6a 100644
--- a/target/linux/mediatek/patches-4.4/0041-soc-mediatek-PMIC-wrap-add-MT2701-7623-support.patch
+++ b/target/linux/mediatek/patches-4.4/0041-soc-mediatek-PMIC-wrap-add-MT2701-7623-support.patch
@@ -1,7 +1,7 @@
-From 2f5df30a7b913069c8fce22dc702e0d7c76ef361 Mon Sep 17 00:00:00 2001
+From 7736d97fe2c6c71c9009a1b45a94de06bfc94a37 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Wed, 20 Jan 2016 12:09:14 +0100
-Subject: [PATCH 41/91] soc: mediatek: PMIC wrap: add MT2701/7623 support
+Subject: [PATCH 041/102] soc: mediatek: PMIC wrap: add MT2701/7623 support
Add the registers, callbacks and data structures required to make the
wrapper work on MT2701 and MT7623.
@@ -11,8 +11,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
drivers/soc/mediatek/mtk-pmic-wrap.c | 154 ++++++++++++++++++++++++++++++++++
1 file changed, 154 insertions(+)
-diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
-index 0e4ebb8..3c3e56d 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -52,6 +52,7 @@
@@ -138,7 +136,7 @@ index 0e4ebb8..3c3e56d 100644
PWRAP_MT8135,
PWRAP_MT8173,
};
-@@ -637,6 +732,31 @@ static int pwrap_mt8173_init_reg_clock(struct pmic_wrapper *wrp)
+@@ -637,6 +732,31 @@ static int pwrap_mt8173_init_reg_clock(s
return 0;
}
@@ -170,7 +168,7 @@ index 0e4ebb8..3c3e56d 100644
static bool pwrap_is_cipher_ready(struct pmic_wrapper *wrp)
{
return pwrap_readl(wrp, PWRAP_CIPHER_RDY) & 1;
-@@ -670,6 +790,7 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
+@@ -670,6 +790,7 @@ static int pwrap_init_cipher(struct pmic
pwrap_writel(wrp, 1, PWRAP_CIPHER_LOAD);
pwrap_writel(wrp, 1, PWRAP_CIPHER_START);
break;
@@ -178,7 +176,7 @@ index 0e4ebb8..3c3e56d 100644
case PWRAP_MT8173:
pwrap_writel(wrp, 1, PWRAP_CIPHER_EN);
break;
-@@ -772,6 +893,24 @@ static int pwrap_mt8173_init_soc_specific(struct pmic_wrapper *wrp)
+@@ -772,6 +893,24 @@ static int pwrap_mt8173_init_soc_specifi
return 0;
}
@@ -203,7 +201,7 @@ index 0e4ebb8..3c3e56d 100644
static int pwrap_init(struct pmic_wrapper *wrp)
{
int ret;
-@@ -916,6 +1055,18 @@ static const struct of_device_id of_slave_match_tbl[] = {
+@@ -916,6 +1055,18 @@ static const struct of_device_id of_slav
};
MODULE_DEVICE_TABLE(of, of_slave_match_tbl);
@@ -222,7 +220,7 @@ index 0e4ebb8..3c3e56d 100644
static struct pmic_wrapper_type pwrap_mt8135 = {
.regs = mt8135_regs,
.type = PWRAP_MT8135,
-@@ -942,6 +1093,9 @@ static struct pmic_wrapper_type pwrap_mt8173 = {
+@@ -942,6 +1093,9 @@ static struct pmic_wrapper_type pwrap_mt
static struct of_device_id of_pwrap_match_tbl[] = {
{
@@ -232,6 +230,3 @@ index 0e4ebb8..3c3e56d 100644
.compatible = "mediatek,mt8135-pwrap",
.data = &pwrap_mt8135,
}, {
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0042-dt-bindings-mfd-Add-bindings-for-the-MediaTek-MT6323.patch b/target/linux/mediatek/patches-4.4/0042-dt-bindings-mfd-Add-bindings-for-the-MediaTek-MT6323.patch
index ffb0580c3e..701ee67bad 100644
--- a/target/linux/mediatek/patches-4.4/0042-dt-bindings-mfd-Add-bindings-for-the-MediaTek-MT6323.patch
+++ b/target/linux/mediatek/patches-4.4/0042-dt-bindings-mfd-Add-bindings-for-the-MediaTek-MT6323.patch
@@ -1,8 +1,8 @@
-From edc6e6a2f10f7b7fc94dc6147c86520e5a439d16 Mon Sep 17 00:00:00 2001
+From c14dc2993a272c706650502ec579ceabe5f2355e Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 10 Jan 2016 17:12:37 +0100
-Subject: [PATCH 42/91] dt-bindings: mfd: Add bindings for the MediaTek MT6323
- PMIC
+Subject: [PATCH 042/102] dt-bindings: mfd: Add bindings for the MediaTek
+ MT6323 PMIC
Signed-off-by: John Crispin <blogic@openwrt.org>
Acked-by: Rob Herring <robh@kernel.org>
@@ -11,8 +11,6 @@ Cc: devicetree@vger.kernel.org
Documentation/devicetree/bindings/mfd/mt6397.txt | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
-diff --git a/Documentation/devicetree/bindings/mfd/mt6397.txt b/Documentation/devicetree/bindings/mfd/mt6397.txt
-index 15043e6..949c85f 100644
--- a/Documentation/devicetree/bindings/mfd/mt6397.txt
+++ b/Documentation/devicetree/bindings/mfd/mt6397.txt
@@ -1,6 +1,6 @@
@@ -24,7 +22,7 @@ index 15043e6..949c85f 100644
- Regulator
- RTC
- Audio codec
-@@ -8,14 +8,14 @@ MT6397 is a multifunction device with the following sub modules:
+@@ -8,14 +8,14 @@ MT6397 is a multifunction device with th
- Clock
It is interfaced to host controller using SPI interface by a proprietary hardware
@@ -50,6 +48,3 @@ index 15043e6..949c85f 100644
- codec
Required properties:
- compatible: "mediatek,mt6397-codec"
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0043-mfd-mt6397-int_con-and-int_status-may-vary-in-locati.patch b/target/linux/mediatek/patches-4.4/0043-mfd-mt6397-int_con-and-int_status-may-vary-in-locati.patch
index 16be0ba09a..6b433b0dfa 100644
--- a/target/linux/mediatek/patches-4.4/0043-mfd-mt6397-int_con-and-int_status-may-vary-in-locati.patch
+++ b/target/linux/mediatek/patches-4.4/0043-mfd-mt6397-int_con-and-int_status-may-vary-in-locati.patch
@@ -1,7 +1,7 @@
-From f97549172878651725a719a4fc4b610613fe5843 Mon Sep 17 00:00:00 2001
+From 8269ed007349714e9ef0e3408a68159d763145dd Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Fri, 8 Jan 2016 08:33:17 +0100
-Subject: [PATCH 43/91] mfd: mt6397: int_con and int_status may vary in
+Subject: [PATCH 043/102] mfd: mt6397: int_con and int_status may vary in
location
MT6323 has the INT_CON and INT_STATUS located at a different position.
@@ -13,11 +13,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
include/linux/mfd/mt6397/core.h | 2 ++
2 files changed, 19 insertions(+), 10 deletions(-)
-diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c
-index 1749c1c..75ad0fe 100644
--- a/drivers/mfd/mt6397-core.c
+++ b/drivers/mfd/mt6397-core.c
-@@ -69,8 +69,10 @@ static void mt6397_irq_sync_unlock(struct irq_data *data)
+@@ -69,8 +69,10 @@ static void mt6397_irq_sync_unlock(struc
{
struct mt6397_chip *mt6397 = irq_data_get_irq_chip_data(data);
@@ -30,7 +28,7 @@ index 1749c1c..75ad0fe 100644
mutex_unlock(&mt6397->irqlock);
}
-@@ -147,8 +149,8 @@ static irqreturn_t mt6397_irq_thread(int irq, void *data)
+@@ -147,8 +149,8 @@ static irqreturn_t mt6397_irq_thread(int
{
struct mt6397_chip *mt6397 = data;
@@ -41,7 +39,7 @@ index 1749c1c..75ad0fe 100644
return IRQ_HANDLED;
}
-@@ -177,8 +179,8 @@ static int mt6397_irq_init(struct mt6397_chip *mt6397)
+@@ -177,8 +179,8 @@ static int mt6397_irq_init(struct mt6397
mutex_init(&mt6397->irqlock);
/* Mask all interrupt sources */
@@ -52,7 +50,7 @@ index 1749c1c..75ad0fe 100644
mt6397->irq_domain = irq_domain_add_linear(mt6397->dev->of_node,
MT6397_IRQ_NR, &mt6397_irq_domain_ops, mt6397);
-@@ -203,8 +205,8 @@ static int mt6397_irq_suspend(struct device *dev)
+@@ -203,8 +205,8 @@ static int mt6397_irq_suspend(struct dev
{
struct mt6397_chip *chip = dev_get_drvdata(dev);
@@ -63,7 +61,7 @@ index 1749c1c..75ad0fe 100644
enable_irq_wake(chip->irq);
-@@ -215,8 +217,8 @@ static int mt6397_irq_resume(struct device *dev)
+@@ -215,8 +217,8 @@ static int mt6397_irq_resume(struct devi
{
struct mt6397_chip *chip = dev_get_drvdata(dev);
@@ -74,7 +72,7 @@ index 1749c1c..75ad0fe 100644
disable_irq_wake(chip->irq);
-@@ -237,6 +239,11 @@ static int mt6397_probe(struct platform_device *pdev)
+@@ -237,6 +239,11 @@ static int mt6397_probe(struct platform_
return -ENOMEM;
mt6397->dev = &pdev->dev;
@@ -86,8 +84,6 @@ index 1749c1c..75ad0fe 100644
/*
* mt6397 MFD is child device of soc pmic wrapper.
* Regmap is set from its parent.
-diff --git a/include/linux/mfd/mt6397/core.h b/include/linux/mfd/mt6397/core.h
-index 45b8e8a..d678f52 100644
--- a/include/linux/mfd/mt6397/core.h
+++ b/include/linux/mfd/mt6397/core.h
@@ -60,6 +60,8 @@ struct mt6397_chip {
@@ -99,6 +95,3 @@ index 45b8e8a..d678f52 100644
};
#endif /* __MFD_MT6397_CORE_H__ */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0044-mfd-mt6397-add-support-for-different-Slave-types.patch b/target/linux/mediatek/patches-4.4/0044-mfd-mt6397-add-support-for-different-Slave-types.patch
index cd69ac0065..bae05fb51b 100644
--- a/target/linux/mediatek/patches-4.4/0044-mfd-mt6397-add-support-for-different-Slave-types.patch
+++ b/target/linux/mediatek/patches-4.4/0044-mfd-mt6397-add-support-for-different-Slave-types.patch
@@ -1,15 +1,13 @@
-From 5fbdf1ebc267561781ce812793cd35e63fa39614 Mon Sep 17 00:00:00 2001
+From c6c447480e51301faa2254c7316ab075e20c4b0c Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Fri, 8 Jan 2016 08:41:52 +0100
-Subject: [PATCH 44/91] mfd: mt6397: add support for different Slave types
+Subject: [PATCH 044/102] mfd: mt6397: add support for different Slave types
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/mfd/mt6397-core.c | 58 ++++++++++++++++++++++++++++++++-------------
1 file changed, 41 insertions(+), 17 deletions(-)
-diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c
-index 75ad0fe..aa91606 100644
--- a/drivers/mfd/mt6397-core.c
+++ b/drivers/mfd/mt6397-core.c
@@ -24,6 +24,9 @@
@@ -22,7 +20,7 @@ index 75ad0fe..aa91606 100644
static const struct resource mt6397_rtc_resources[] = {
{
.start = MT6397_RTC_BASE,
-@@ -232,39 +235,60 @@ static SIMPLE_DEV_PM_OPS(mt6397_pm_ops, mt6397_irq_suspend,
+@@ -232,39 +235,60 @@ static SIMPLE_DEV_PM_OPS(mt6397_pm_ops,
static int mt6397_probe(struct platform_device *pdev)
{
int ret;
@@ -100,6 +98,3 @@ index 75ad0fe..aa91606 100644
return ret;
}
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0045-mfd-mt6397-add-MT6323-support-to-MT6397-driver.patch b/target/linux/mediatek/patches-4.4/0045-mfd-mt6397-add-MT6323-support-to-MT6397-driver.patch
index 0f398cddde..d673a0a096 100644
--- a/target/linux/mediatek/patches-4.4/0045-mfd-mt6397-add-MT6323-support-to-MT6397-driver.patch
+++ b/target/linux/mediatek/patches-4.4/0045-mfd-mt6397-add-MT6323-support-to-MT6397-driver.patch
@@ -1,7 +1,7 @@
-From 2a1c7879d8c3eac4313abc011adbefbc50fd5f92 Mon Sep 17 00:00:00 2001
+From 0ae7153c9f00361c3e6dac9da0c2d994557953f5 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Fri, 8 Jan 2016 04:09:43 +0100
-Subject: [PATCH 45/91] mfd: mt6397: add MT6323 support to MT6397 driver
+Subject: [PATCH 045/102] mfd: mt6397: add MT6323 support to MT6397 driver
Signed-off-by: John Crispin <blogic@openwrt.org>
---
@@ -12,8 +12,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
create mode 100644 include/linux/mfd/mt6323/core.h
create mode 100644 include/linux/mfd/mt6323/registers.h
-diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c
-index aa91606..8234cd3 100644
--- a/drivers/mfd/mt6397-core.c
+++ b/drivers/mfd/mt6397-core.c
@@ -19,11 +19,14 @@
@@ -31,7 +29,7 @@ index aa91606..8234cd3 100644
#define MT6391_CID_CODE 0x91
#define MT6397_CID_CODE 0x97
-@@ -40,6 +43,13 @@ static const struct resource mt6397_rtc_resources[] = {
+@@ -40,6 +43,13 @@ static const struct resource mt6397_rtc_
},
};
@@ -45,7 +43,7 @@ index aa91606..8234cd3 100644
static const struct mfd_cell mt6397_devs[] = {
{
.name = "mt6397-rtc",
-@@ -261,6 +271,15 @@ static int mt6397_probe(struct platform_device *pdev)
+@@ -261,6 +271,15 @@ static int mt6397_probe(struct platform_
}
switch (id & 0xff) {
@@ -61,7 +59,7 @@ index aa91606..8234cd3 100644
case MT6397_CID_CODE:
case MT6391_CID_CODE:
pmic->int_con[0] = MT6397_INT_CON0;
-@@ -302,6 +321,7 @@ static int mt6397_remove(struct platform_device *pdev)
+@@ -302,6 +321,7 @@ static int mt6397_remove(struct platform
static const struct of_device_id mt6397_of_match[] = {
{ .compatible = "mediatek,mt6397" },
@@ -69,9 +67,6 @@ index aa91606..8234cd3 100644
{ }
};
MODULE_DEVICE_TABLE(of, mt6397_of_match);
-diff --git a/include/linux/mfd/mt6323/core.h b/include/linux/mfd/mt6323/core.h
-new file mode 100644
-index 0000000..06d0ec3
--- /dev/null
+++ b/include/linux/mfd/mt6323/core.h
@@ -0,0 +1,36 @@
@@ -111,9 +106,6 @@ index 0000000..06d0ec3
+};
+
+#endif /* __MFD_MT6323_CORE_H__ */
-diff --git a/include/linux/mfd/mt6323/registers.h b/include/linux/mfd/mt6323/registers.h
-new file mode 100644
-index 0000000..160f3c0
--- /dev/null
+++ b/include/linux/mfd/mt6323/registers.h
@@ -0,0 +1,408 @@
@@ -525,6 +517,3 @@ index 0000000..160f3c0
+#define MT6323_ACCDET_CON16 0x079A
+
+#endif /* __MFD_MT6323_REGISTERS_H__ */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0046-regulator-Add-document-for-MT6323-regulator.patch b/target/linux/mediatek/patches-4.4/0046-regulator-Add-document-for-MT6323-regulator.patch
index d389e4b47d..d70631483a 100644
--- a/target/linux/mediatek/patches-4.4/0046-regulator-Add-document-for-MT6323-regulator.patch
+++ b/target/linux/mediatek/patches-4.4/0046-regulator-Add-document-for-MT6323-regulator.patch
@@ -1,7 +1,7 @@
-From 34177561c62ed881c862f9ece652ca1ca5994796 Mon Sep 17 00:00:00 2001
+From f536a600e0e20fd57475415ce5b3d909441d53b6 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 10 Jan 2016 17:31:46 +0100
-Subject: [PATCH 46/91] regulator: Add document for MT6323 regulator
+Subject: [PATCH 046/102] regulator: Add document for MT6323 regulator
Signed-off-by: John Crispin <blogic@openwrt.org>
Cc: devicetree@vger.kernel.org
@@ -10,9 +10,6 @@ Cc: devicetree@vger.kernel.org
1 file changed, 239 insertions(+)
create mode 100644 Documentation/devicetree/bindings/regulator/mt6323-regulator.txt
-diff --git a/Documentation/devicetree/bindings/regulator/mt6323-regulator.txt b/Documentation/devicetree/bindings/regulator/mt6323-regulator.txt
-new file mode 100644
-index 0000000..9fd95e7
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/mt6323-regulator.txt
@@ -0,0 +1,239 @@
@@ -255,6 +252,3 @@ index 0000000..9fd95e7
+ };
+ };
+ };
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0047-regulator-mt6323-Add-support-for-MT6323-regulator.patch b/target/linux/mediatek/patches-4.4/0047-regulator-mt6323-Add-support-for-MT6323-regulator.patch
index 170fcee452..6456c27dce 100644
--- a/target/linux/mediatek/patches-4.4/0047-regulator-mt6323-Add-support-for-MT6323-regulator.patch
+++ b/target/linux/mediatek/patches-4.4/0047-regulator-mt6323-Add-support-for-MT6323-regulator.patch
@@ -1,7 +1,7 @@
-From 2a33aa927dece6ac6d10caff48897c8ac6a66c1b Mon Sep 17 00:00:00 2001
+From 94c08223cd696d872cda7d9aa4e817956d0a0b84 Mon Sep 17 00:00:00 2001
From: Chen Zhong <chen.zhong@mediatek.com>
Date: Fri, 8 Jan 2016 04:17:37 +0100
-Subject: [PATCH 47/91] regulator: mt6323: Add support for MT6323 regulator
+Subject: [PATCH 047/102] regulator: mt6323: Add support for MT6323 regulator
The MT6323 is a regulator found on boards based on MediaTek MT7623 and
probably other SoCs. It is a so called pmic and connects as a slave to
@@ -18,11 +18,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
create mode 100644 drivers/regulator/mt6323-regulator.c
create mode 100644 include/linux/regulator/mt6323-regulator.h
-diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
-index 8df0b0e..4aec931 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
-@@ -452,6 +452,15 @@ config REGULATOR_MT6311
+@@ -453,6 +453,15 @@ config REGULATOR_MT6311
This driver supports the control of different power rails of device
through regulator interface.
@@ -38,11 +36,9 @@ index 8df0b0e..4aec931 100644
config REGULATOR_MT6397
tristate "MediaTek MT6397 PMIC"
depends on MFD_MT6397
-diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
-index 0f81749..b42a84e 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
-@@ -60,6 +60,7 @@ obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
+@@ -60,6 +60,7 @@ obj-$(CONFIG_REGULATOR_MC13783) += mc137
obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o
obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o
@@ -50,9 +46,6 @@ index 0f81749..b42a84e 100644
obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o
-diff --git a/drivers/regulator/mt6323-regulator.c b/drivers/regulator/mt6323-regulator.c
-new file mode 100644
-index 0000000..28ebbda
--- /dev/null
+++ b/drivers/regulator/mt6323-regulator.c
@@ -0,0 +1,432 @@
@@ -488,9 +481,6 @@ index 0000000..28ebbda
+MODULE_AUTHOR("Chen Zhong <chen.zhong@mediatek.com>");
+MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6397 PMIC");
+MODULE_LICENSE("GPL v2");
-diff --git a/include/linux/regulator/mt6323-regulator.h b/include/linux/regulator/mt6323-regulator.h
-new file mode 100644
-index 0000000..67011cd
--- /dev/null
+++ b/include/linux/regulator/mt6323-regulator.h
@@ -0,0 +1,52 @@
@@ -546,6 +536,3 @@ index 0000000..67011cd
+#define MT6323_MAX_REGULATOR MT6323_ID_RG_MAX
+
+#endif /* __LINUX_REGULATOR_MT6323_H */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0048-net-next-mediatek-document-MediaTek-SoC-ethernet-bin.patch b/target/linux/mediatek/patches-4.4/0048-net-next-mediatek-document-MediaTek-SoC-ethernet-bin.patch
index dd4ee9dac3..7d1e7422ea 100644
--- a/target/linux/mediatek/patches-4.4/0048-net-next-mediatek-document-MediaTek-SoC-ethernet-bin.patch
+++ b/target/linux/mediatek/patches-4.4/0048-net-next-mediatek-document-MediaTek-SoC-ethernet-bin.patch
@@ -1,7 +1,7 @@
-From caa2186644606dad07a603905ebabb8068828ebf Mon Sep 17 00:00:00 2001
+From 6efc8d9081b70dcf71d7e8efd7b51d48ee2541be Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Wed, 2 Mar 2016 07:18:52 +0100
-Subject: [PATCH 48/91] net-next: mediatek: document MediaTek SoC ethernet
+Subject: [PATCH 048/102] net-next: mediatek: document MediaTek SoC ethernet
binding
This adds the binding documentation for the MediaTek Ethernet
@@ -15,9 +15,6 @@ Cc: devicetree@vger.kernel.org
1 file changed, 77 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/mediatek-net.txt
-diff --git a/Documentation/devicetree/bindings/net/mediatek-net.txt b/Documentation/devicetree/bindings/net/mediatek-net.txt
-new file mode 100644
-index 0000000..5ca7929
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/mediatek-net.txt
@@ -0,0 +1,77 @@
@@ -98,6 +95,3 @@ index 0000000..5ca7929
+ };
+ };
+};
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0049-net-next-mediatek-add-support-for-MT7623-ethernet.patch b/target/linux/mediatek/patches-4.4/0049-net-next-mediatek-add-support-for-MT7623-ethernet.patch
index 5e12344785..85aa93d475 100644
--- a/target/linux/mediatek/patches-4.4/0049-net-next-mediatek-add-support-for-MT7623-ethernet.patch
+++ b/target/linux/mediatek/patches-4.4/0049-net-next-mediatek-add-support-for-MT7623-ethernet.patch
@@ -1,7 +1,7 @@
-From 412449bacdb46b548fd08af19148019e2e979294 Mon Sep 17 00:00:00 2001
+From 8cc84aa65121135d7b120ce71b4f10f81230c818 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Wed, 2 Mar 2016 04:27:10 +0100
-Subject: [PATCH 49/91] net-next: mediatek: add support for MT7623 ethernet
+Subject: [PATCH 049/102] net-next: mediatek: add support for MT7623 ethernet
Add ethernet support for MediaTek SoCs from the MT7623 family. These have
dual GMAC. Depending on the exact version, there might be a built-in
@@ -26,9 +26,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
create mode 100644 drivers/net/ethernet/mediatek/mtk_eth_soc.c
create mode 100644 drivers/net/ethernet/mediatek/mtk_eth_soc.h
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-new file mode 100644
-index 0000000..ba3afa5
--- /dev/null
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -0,0 +1,1807 @@
@@ -1839,9 +1836,6 @@ index 0000000..ba3afa5
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
+MODULE_DESCRIPTION("Ethernet driver for MediaTek SoC");
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-new file mode 100644
-index 0000000..48a5292
--- /dev/null
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -0,0 +1,421 @@
@@ -2266,6 +2260,3 @@ index 0000000..48a5292
+u32 mtk_r32(struct mtk_eth *eth, unsigned reg);
+
+#endif /* MTK_ETH_H */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0050-net-next-mediatek-add-Kconfig-and-Makefile.patch b/target/linux/mediatek/patches-4.4/0050-net-next-mediatek-add-Kconfig-and-Makefile.patch
index 506e3e4076..0c7a89e622 100644
--- a/target/linux/mediatek/patches-4.4/0050-net-next-mediatek-add-Kconfig-and-Makefile.patch
+++ b/target/linux/mediatek/patches-4.4/0050-net-next-mediatek-add-Kconfig-and-Makefile.patch
@@ -1,7 +1,7 @@
-From 8bc8e78ddec2c93d7fe3487dfdfeedd382e3b96f Mon Sep 17 00:00:00 2001
+From 31e907e5c3c2fc1c94d005bfccdd4a32b5a05f82 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Wed, 2 Mar 2016 04:32:43 +0100
-Subject: [PATCH 50/91] net-next: mediatek: add Kconfig and Makefile
+Subject: [PATCH 050/102] net-next: mediatek: add Kconfig and Makefile
This patch adds the Makefile and Kconfig required to make the driver build.
@@ -15,8 +15,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
create mode 100644 drivers/net/ethernet/mediatek/Kconfig
create mode 100644 drivers/net/ethernet/mediatek/Makefile
-diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
-index 31c5e47..cd28b95 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -106,6 +106,7 @@ config LANTIQ_ETOP
@@ -27,8 +25,6 @@ index 31c5e47..cd28b95 100644
source "drivers/net/ethernet/mellanox/Kconfig"
source "drivers/net/ethernet/micrel/Kconfig"
source "drivers/net/ethernet/microchip/Kconfig"
-diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
-index 071f84e..c62191f 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_JME) += jme.o
@@ -39,9 +35,6 @@ index 071f84e..c62191f 100644
obj-$(CONFIG_NET_VENDOR_MELLANOX) += mellanox/
obj-$(CONFIG_NET_VENDOR_MICREL) += micrel/
obj-$(CONFIG_NET_VENDOR_MICROCHIP) += microchip/
-diff --git a/drivers/net/ethernet/mediatek/Kconfig b/drivers/net/ethernet/mediatek/Kconfig
-new file mode 100644
-index 0000000..b0229f4
--- /dev/null
+++ b/drivers/net/ethernet/mediatek/Kconfig
@@ -0,0 +1,17 @@
@@ -62,9 +55,6 @@ index 0000000..b0229f4
+ MediaTek MT2701/MT7623 chipset family.
+
+endif #NET_VENDOR_MEDIATEK
-diff --git a/drivers/net/ethernet/mediatek/Makefile b/drivers/net/ethernet/mediatek/Makefile
-new file mode 100644
-index 0000000..aa3f1c8
--- /dev/null
+++ b/drivers/net/ethernet/mediatek/Makefile
@@ -0,0 +1,5 @@
@@ -73,6 +63,3 @@ index 0000000..aa3f1c8
+#
+
+obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth_soc.o
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0051-net-next-mediatek-add-an-entry-to-MAINTAINERS.patch b/target/linux/mediatek/patches-4.4/0051-net-next-mediatek-add-an-entry-to-MAINTAINERS.patch
index 4ceb356a08..0fc9b373e5 100644
--- a/target/linux/mediatek/patches-4.4/0051-net-next-mediatek-add-an-entry-to-MAINTAINERS.patch
+++ b/target/linux/mediatek/patches-4.4/0051-net-next-mediatek-add-an-entry-to-MAINTAINERS.patch
@@ -1,7 +1,7 @@
-From d9b93fb0d4021694a2b7e47981cd9de67e83aa05 Mon Sep 17 00:00:00 2001
+From 514e4ce65a5f1b5bfa3cbca153f672844f093f0e Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Wed, 2 Mar 2016 04:34:04 +0100
-Subject: [PATCH 51/91] net-next: mediatek: add an entry to MAINTAINERS
+Subject: [PATCH 051/102] net-next: mediatek: add an entry to MAINTAINERS
Add myself and Felix as the Maintainers for the MediaTek ethernet driver.
@@ -11,11 +11,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
MAINTAINERS | 7 +++++++
1 file changed, 7 insertions(+)
-diff --git a/MAINTAINERS b/MAINTAINERS
-index 156e1d3..7737042 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
-@@ -6908,6 +6908,13 @@ F: include/uapi/linux/meye.h
+@@ -6907,6 +6907,13 @@ F: include/uapi/linux/meye.h
F: include/uapi/linux/ivtv*
F: include/uapi/linux/uvcvideo.h
@@ -29,6 +27,3 @@ index 156e1d3..7737042 100644
MEDIATEK MT7601U WIRELESS LAN DRIVER
M: Jakub Kicinski <kubakici@wp.pl>
L: linux-wireless@vger.kernel.org
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0052-clk-dont-disable-unused-clocks.patch b/target/linux/mediatek/patches-4.4/0052-clk-dont-disable-unused-clocks.patch
new file mode 100644
index 0000000000..87e4a54ed3
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0052-clk-dont-disable-unused-clocks.patch
@@ -0,0 +1,21 @@
+From 5238c5d1d38661955ed3b52f45c46e00bfc9eb6e Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Thu, 7 Apr 2016 07:18:35 +0200
+Subject: [PATCH 052/102] clk: dont disable unused clocks
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/clk/clk.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/clk/clk.c
++++ b/drivers/clk/clk.c
+@@ -233,7 +233,7 @@ unlock_out:
+ clk_enable_unlock(flags);
+ }
+
+-static bool clk_ignore_unused;
++static bool clk_ignore_unused = true;
+ static int __init clk_ignore_unused_setup(char *__unused)
+ {
+ clk_ignore_unused = true;
diff --git a/target/linux/mediatek/patches-4.4/0052-mtd-nand-add-an-mtd_to_nand-helper.patch b/target/linux/mediatek/patches-4.4/0052-mtd-nand-add-an-mtd_to_nand-helper.patch
deleted file mode 100644
index 83e725a5cc..0000000000
--- a/target/linux/mediatek/patches-4.4/0052-mtd-nand-add-an-mtd_to_nand-helper.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-From 69a0df9dd942799651a7ec06b3cfe7fc43b2e32a Mon Sep 17 00:00:00 2001
-From: Boris BREZILLON <boris.brezillon@free-electrons.com>
-Date: Mon, 16 Nov 2015 14:37:35 +0100
-Subject: [PATCH 52/91] mtd: nand: add an mtd_to_nand() helper
-
-Some drivers are retrieving the nand_chip pointer using the container_of
-macro on a struct wrapping both the nand_chip and the mtd_info struct while
-the standard way of retrieving this pointer is through mtd->priv.
-Provide an helper to do that.
-
-Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
-Signed-off-by: Brian Norris <computersforpeace@gmail.com>
----
- include/linux/mtd/nand.h | 5 +++++
- 1 file changed, 5 insertions(+)
-
-diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
-index 5a9d1d4..a4839b3 100644
---- a/include/linux/mtd/nand.h
-+++ b/include/linux/mtd/nand.h
-@@ -719,6 +719,11 @@ struct nand_chip {
- void *priv;
- };
-
-+static inline struct nand_chip *mtd_to_nand(struct mtd_info *mtd)
-+{
-+ return mtd->priv;
-+}
-+
- /*
- * NAND Flash Manufacturer ID Codes
- */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0053-clk-mediatek-enable-critical-clocks.patch b/target/linux/mediatek/patches-4.4/0053-clk-mediatek-enable-critical-clocks.patch
new file mode 100644
index 0000000000..39939001f1
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0053-clk-mediatek-enable-critical-clocks.patch
@@ -0,0 +1,69 @@
+From c8fd103d6c07af5db47f061b70759b7c69169656 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Thu, 31 Mar 2016 06:46:51 +0200
+Subject: [PATCH 053/102] clk: mediatek: enable critical clocks
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/clk/mediatek/clk-mt2701.c | 22 ++++++++++++++++++++--
+ 1 file changed, 20 insertions(+), 2 deletions(-)
+
+--- a/drivers/clk/mediatek/clk-mt2701.c
++++ b/drivers/clk/mediatek/clk-mt2701.c
+@@ -573,6 +573,20 @@ static const struct mtk_gate top_clks[]
+ GATE_TOP_AUD(CLK_TOP_AUD_I2S6_MCLK, "aud_i2s6_mclk", "aud_k6_src_div", 28),
+ };
+
++static struct clk_onecell_data *mt7623_top_clk_data __initdata;
++static struct clk_onecell_data *mt7623_pll_clk_data __initdata;
++
++static void __init mtk_clk_enable_critical(void)
++{
++ if (!mt7623_top_clk_data || !mt7623_pll_clk_data)
++ return;
++
++ clk_prepare_enable(mt7623_pll_clk_data->clks[CLK_APMIXED_ARMPLL]);
++ clk_prepare_enable(mt7623_top_clk_data->clks[CLK_TOP_MEM_SEL]);
++ clk_prepare_enable(mt7623_top_clk_data->clks[CLK_TOP_DDRPHYCFG_SEL]);
++ clk_prepare_enable(mt7623_top_clk_data->clks[CLK_TOP_RTC_SEL]);
++}
++
+ static void __init mtk_topckgen_init(struct device_node *node)
+ {
+ struct clk_onecell_data *clk_data;
+@@ -585,7 +599,7 @@ static void __init mtk_topckgen_init(str
+ return;
+ }
+
+- clk_data = mtk_alloc_clk_data(CLK_TOP_NR);
++ mt7623_top_clk_data = clk_data = mtk_alloc_clk_data(CLK_TOP_NR);
+
+ mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks),
+ clk_data);
+@@ -606,6 +620,8 @@ static void __init mtk_topckgen_init(str
+ if (r)
+ pr_err("%s(): could not register clock provider: %d\n",
+ __func__, r);
++
++ mtk_clk_enable_critical();
+ }
+ CLK_OF_DECLARE(mtk_topckgen, "mediatek,mt2701-topckgen", mtk_topckgen_init);
+
+@@ -1202,7 +1218,7 @@ static void __init mtk_apmixedsys_init(s
+ struct clk_onecell_data *clk_data;
+ int r;
+
+- clk_data = mtk_alloc_clk_data(ARRAY_SIZE(apmixed_plls));
++ mt7623_pll_clk_data = clk_data = mtk_alloc_clk_data(ARRAY_SIZE(apmixed_plls));
+ if (!clk_data)
+ return;
+
+@@ -1213,6 +1229,8 @@ static void __init mtk_apmixedsys_init(s
+ if (r)
+ pr_err("%s(): could not register clock provider: %d\n",
+ __func__, r);
++
++ mtk_clk_enable_critical();
+ }
+ CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt2701-apmixedsys",
+ mtk_apmixedsys_init);
diff --git a/target/linux/mediatek/patches-4.4/0053-mtd-nand-add-nand_to_mtd-helper.patch b/target/linux/mediatek/patches-4.4/0053-mtd-nand-add-nand_to_mtd-helper.patch
deleted file mode 100644
index b103c5b539..0000000000
--- a/target/linux/mediatek/patches-4.4/0053-mtd-nand-add-nand_to_mtd-helper.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-From 833645b92150d74642829c24c0ca1fbbdeccfb5c Mon Sep 17 00:00:00 2001
-From: Boris BREZILLON <boris.brezillon@free-electrons.com>
-Date: Tue, 1 Dec 2015 12:03:07 +0100
-Subject: [PATCH 53/91] mtd: nand: add nand_to_mtd() helper
-
-Add a new helper to retrieve the MTD device attached to a NAND chip.
-
-Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
-Signed-off-by: Brian Norris <computersforpeace@gmail.com>
----
- include/linux/mtd/nand.h | 5 +++++
- 1 file changed, 5 insertions(+)
-
-diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
-index a4839b3..c75424f 100644
---- a/include/linux/mtd/nand.h
-+++ b/include/linux/mtd/nand.h
-@@ -724,6 +724,11 @@ static inline struct nand_chip *mtd_to_nand(struct mtd_info *mtd)
- return mtd->priv;
- }
-
-+static inline struct mtd_info *nand_to_mtd(struct nand_chip *chip)
-+{
-+ return &chip->mtd;
-+}
-+
- /*
- * NAND Flash Manufacturer ID Codes
- */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0054-clk-mediatek-Export-CPU-mux-clocks-for-CPU-frequency.patch b/target/linux/mediatek/patches-4.4/0054-clk-mediatek-Export-CPU-mux-clocks-for-CPU-frequency.patch
new file mode 100644
index 0000000000..d5af5f0c82
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0054-clk-mediatek-Export-CPU-mux-clocks-for-CPU-frequency.patch
@@ -0,0 +1,287 @@
+From 1387d4f0ebf4b48c09f2ea0d27a02936c3fa0010 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Thu, 31 Mar 2016 02:26:37 +0200
+Subject: [PATCH 054/102] clk: mediatek: Export CPU mux clocks for CPU
+ frequency control
+
+This patch adds CPU mux clocks which are used by Mediatek cpufreq driver
+for intermediate clock source switching.
+
+Signed-off-by: Pi-Cheng Chen <pi-cheng.chen@linaro.org>
+---
+ drivers/clk/mediatek/Makefile | 2 +-
+ drivers/clk/mediatek/clk-cpumux.c | 127 ++++++++++++++++++++++++++++++++
+ drivers/clk/mediatek/clk-cpumux.h | 22 ++++++
+ drivers/clk/mediatek/clk-mt2701.c | 8 ++
+ drivers/clk/mediatek/clk-mt8173.c | 23 ++++++
+ include/dt-bindings/clock/mt2701-clk.h | 3 +-
+ include/dt-bindings/clock/mt8173-clk.h | 4 +-
+ 7 files changed, 186 insertions(+), 3 deletions(-)
+ create mode 100644 drivers/clk/mediatek/clk-cpumux.c
+ create mode 100644 drivers/clk/mediatek/clk-cpumux.h
+
+--- a/drivers/clk/mediatek/Makefile
++++ b/drivers/clk/mediatek/Makefile
+@@ -1,4 +1,4 @@
+-obj-$(CONFIG_COMMON_CLK_MEDIATEK) += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.o
++obj-$(CONFIG_COMMON_CLK_MEDIATEK) += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.o clk-cpumux.o
+ obj-$(CONFIG_RESET_CONTROLLER) += reset.o
+ obj-$(CONFIG_COMMON_CLK_MT2701) += clk-mt2701.o
+ obj-$(CONFIG_COMMON_CLK_MT8135) += clk-mt8135.o
+--- /dev/null
++++ b/drivers/clk/mediatek/clk-cpumux.c
+@@ -0,0 +1,127 @@
++/*
++ * Copyright (c) 2015 Linaro Ltd.
++ * Author: Pi-Cheng Chen <pi-cheng.chen@linaro.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/clk-provider.h>
++#include <linux/mfd/syscon.h>
++#include <linux/slab.h>
++
++#include "clk-mtk.h"
++#include "clk-cpumux.h"
++
++struct mtk_clk_cpumux {
++ struct clk_hw hw;
++ struct regmap *regmap;
++ u32 reg;
++ u32 mask;
++ u8 shift;
++};
++
++static inline struct mtk_clk_cpumux *to_clk_mux(struct clk_hw *_hw)
++{
++ return container_of(_hw, struct mtk_clk_cpumux, hw);
++}
++
++static u8 clk_cpumux_get_parent(struct clk_hw *hw)
++{
++ struct mtk_clk_cpumux *mux = to_clk_mux(hw);
++ int num_parents = clk_hw_get_num_parents(hw);
++ unsigned int val;
++
++ regmap_read(mux->regmap, mux->reg, &val);
++
++ val >>= mux->shift;
++ val &= mux->mask;
++
++ if (val >= num_parents)
++ return -EINVAL;
++
++ return val;
++}
++
++static int clk_cpumux_set_parent(struct clk_hw *hw, u8 index)
++{
++ struct mtk_clk_cpumux *mux = to_clk_mux(hw);
++ u32 mask, val;
++
++ val = index << mux->shift;
++ mask = mux->mask << mux->shift;
++
++ return regmap_update_bits(mux->regmap, mux->reg, mask, val);
++}
++
++static const struct clk_ops clk_cpumux_ops = {
++ .get_parent = clk_cpumux_get_parent,
++ .set_parent = clk_cpumux_set_parent,
++};
++
++static struct clk __init *mtk_clk_register_cpumux(const struct mtk_composite *mux,
++ struct regmap *regmap)
++{
++ struct mtk_clk_cpumux *cpumux;
++ struct clk *clk;
++ struct clk_init_data init;
++
++ cpumux = kzalloc(sizeof(*cpumux), GFP_KERNEL);
++ if (!cpumux)
++ return ERR_PTR(-ENOMEM);
++
++ init.name = mux->name;
++ init.ops = &clk_cpumux_ops;
++ init.parent_names = mux->parent_names;
++ init.num_parents = mux->num_parents;
++ init.flags = mux->flags;
++
++ cpumux->reg = mux->mux_reg;
++ cpumux->shift = mux->mux_shift;
++ cpumux->mask = BIT(mux->mux_width) - 1;
++ cpumux->regmap = regmap;
++ cpumux->hw.init = &init;
++
++ clk = clk_register(NULL, &cpumux->hw);
++ if (IS_ERR(clk))
++ kfree(cpumux);
++
++ return clk;
++}
++
++int __init mtk_clk_register_cpumuxes(struct device_node *node,
++ const struct mtk_composite *clks, int num,
++ struct clk_onecell_data *clk_data)
++{
++ int i;
++ struct clk *clk;
++ struct regmap *regmap;
++
++ regmap = syscon_node_to_regmap(node);
++ if (IS_ERR(regmap)) {
++ pr_err("Cannot find regmap for %s: %ld\n", node->full_name,
++ PTR_ERR(regmap));
++ return PTR_ERR(regmap);
++ }
++
++ for (i = 0; i < num; i++) {
++ const struct mtk_composite *mux = &clks[i];
++
++ clk = mtk_clk_register_cpumux(mux, regmap);
++ if (IS_ERR(clk)) {
++ pr_err("Failed to register clk %s: %ld\n",
++ mux->name, PTR_ERR(clk));
++ continue;
++ }
++
++ clk_data->clks[mux->id] = clk;
++ }
++
++ return 0;
++}
+--- /dev/null
++++ b/drivers/clk/mediatek/clk-cpumux.h
+@@ -0,0 +1,22 @@
++/*
++ * Copyright (c) 2015 Linaro Ltd.
++ * Author: Pi-Cheng Chen <pi-cheng.chen@linaro.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef __DRV_CLK_CPUMUX_H
++#define __DRV_CLK_CPUMUX_H
++
++int mtk_clk_register_cpumuxes(struct device_node *node,
++ const struct mtk_composite *clks, int num,
++ struct clk_onecell_data *clk_data);
++
++#endif /* __DRV_CLK_CPUMUX_H */
+--- a/drivers/clk/mediatek/clk-mt2701.c
++++ b/drivers/clk/mediatek/clk-mt2701.c
+@@ -18,6 +18,7 @@
+
+ #include "clk-mtk.h"
+ #include "clk-gate.h"
++#include "clk-cpumux.h"
+
+ #include <dt-bindings/clock/mt2701-clk.h>
+
+@@ -465,6 +466,10 @@ static const char * const cpu_parents[]
+ "mmpll"
+ };
+
++static const struct mtk_composite cpu_muxes[] __initconst = {
++ MUX(CLK_INFRA_CPUSEL, "infra_cpu_sel", cpu_parents, 0x0000, 2, 2),
++};
++
+ static const struct mtk_composite top_muxes[] __initconst = {
+ MUX_GATE(CLK_TOP_AXI_SEL, "axi_sel", axi_parents,
+ 0x0040, 0, 3, INVALID_MUX_GATE_BIT),
+@@ -677,6 +682,9 @@ static void __init mtk_infrasys_init(str
+ mtk_clk_register_factors(infra_fixed_divs, ARRAY_SIZE(infra_fixed_divs),
+ clk_data);
+
++ mtk_clk_register_cpumuxes(node, cpu_muxes, ARRAY_SIZE(cpu_muxes),
++ clk_data);
++
+ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+ if (r)
+ pr_err("%s(): could not register clock provider: %d\n",
+--- a/drivers/clk/mediatek/clk-mt8173.c
++++ b/drivers/clk/mediatek/clk-mt8173.c
+@@ -18,6 +18,7 @@
+
+ #include "clk-mtk.h"
+ #include "clk-gate.h"
++#include "clk-cpumux.h"
+
+ #include <dt-bindings/clock/mt8173-clk.h>
+
+@@ -526,6 +527,25 @@ static const char * const i2s3_b_ck_pare
+ "apll2_div5"
+ };
+
++static const char * const ca53_parents[] __initconst = {
++ "clk26m",
++ "armca7pll",
++ "mainpll",
++ "univpll"
++};
++
++static const char * const ca57_parents[] __initconst = {
++ "clk26m",
++ "armca15pll",
++ "mainpll",
++ "univpll"
++};
++
++static const struct mtk_composite cpu_muxes[] __initconst = {
++ MUX(CLK_INFRA_CA53SEL, "infra_ca53_sel", ca53_parents, 0x0000, 0, 2),
++ MUX(CLK_INFRA_CA57SEL, "infra_ca57_sel", ca57_parents, 0x0000, 2, 2),
++};
++
+ static const struct mtk_composite top_muxes[] __initconst = {
+ /* CLK_CFG_0 */
+ MUX(CLK_TOP_AXI_SEL, "axi_sel", axi_parents, 0x0040, 0, 3),
+@@ -945,6 +965,9 @@ static void __init mtk_infrasys_init(str
+ clk_data);
+ mtk_clk_register_factors(infra_divs, ARRAY_SIZE(infra_divs), clk_data);
+
++ mtk_clk_register_cpumuxes(node, cpu_muxes, ARRAY_SIZE(cpu_muxes),
++ clk_data);
++
+ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+ if (r)
+ pr_err("%s(): could not register clock provider: %d\n",
+--- a/include/dt-bindings/clock/mt2701-clk.h
++++ b/include/dt-bindings/clock/mt2701-clk.h
+@@ -217,7 +217,8 @@
+ #define CLK_INFRA_PMICWRAP 17
+ #define CLK_INFRA_DDCCI 18
+ #define CLK_INFRA_CLK_13M 19
+-#define CLK_INFRA_NR 20
++#define CLK_INFRA_CPUSEL 20
++#define CLK_INFRA_NR 21
+
+ /* PERICFG */
+
+--- a/include/dt-bindings/clock/mt8173-clk.h
++++ b/include/dt-bindings/clock/mt8173-clk.h
+@@ -192,7 +192,9 @@
+ #define CLK_INFRA_PMICSPI 10
+ #define CLK_INFRA_PMICWRAP 11
+ #define CLK_INFRA_CLK_13M 12
+-#define CLK_INFRA_NR_CLK 13
++#define CLK_INFRA_CA53SEL 13
++#define CLK_INFRA_CA57SEL 14
++#define CLK_INFRA_NR_CLK 15
+
+ /* PERI_SYS */
+
diff --git a/target/linux/mediatek/patches-4.4/0054-mtd-nand-add-helpers-to-access-priv.patch b/target/linux/mediatek/patches-4.4/0054-mtd-nand-add-helpers-to-access-priv.patch
deleted file mode 100644
index 8e32d5f919..0000000000
--- a/target/linux/mediatek/patches-4.4/0054-mtd-nand-add-helpers-to-access-priv.patch
+++ /dev/null
@@ -1,39 +0,0 @@
-From af8437ee10a6304da30ca479480102b464b39c82 Mon Sep 17 00:00:00 2001
-From: Boris BREZILLON <boris.brezillon@free-electrons.com>
-Date: Thu, 10 Dec 2015 09:00:39 +0100
-Subject: [PATCH 54/91] mtd: nand: add helpers to access ->priv
-
-Add two helpers to access the field reserved for private controller data.
-This makes it clearer what this field is reserved for and ease future
-refactoring.
-
-Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
-Signed-off-by: Brian Norris <computersforpeace@gmail.com>
----
- include/linux/mtd/nand.h | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
-diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
-index c75424f..345f864 100644
---- a/include/linux/mtd/nand.h
-+++ b/include/linux/mtd/nand.h
-@@ -729,6 +729,16 @@ static inline struct mtd_info *nand_to_mtd(struct nand_chip *chip)
- return &chip->mtd;
- }
-
-+static inline void *nand_get_controller_data(struct nand_chip *chip)
-+{
-+ return chip->priv;
-+}
-+
-+static inline void nand_set_controller_data(struct nand_chip *chip, void *priv)
-+{
-+ chip->priv = priv;
-+}
-+
- /*
- * NAND Flash Manufacturer ID Codes
- */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0055-cpufreq-mediatek-add-driver.patch b/target/linux/mediatek/patches-4.4/0055-cpufreq-mediatek-add-driver.patch
new file mode 100644
index 0000000000..8b476361ff
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0055-cpufreq-mediatek-add-driver.patch
@@ -0,0 +1,433 @@
+From 60f4e41b367bdb29530468c91c1e613b17a37755 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Wed, 30 Mar 2016 23:48:53 +0200
+Subject: [PATCH 055/102] cpufreq: mediatek: add driver
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/cpufreq/Kconfig.arm | 9 +
+ drivers/cpufreq/Makefile | 1 +
+ drivers/cpufreq/mt7623-cpufreq.c | 389 ++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 399 insertions(+)
+ create mode 100644 drivers/cpufreq/mt7623-cpufreq.c
+
+--- a/drivers/cpufreq/Kconfig.arm
++++ b/drivers/cpufreq/Kconfig.arm
+@@ -81,6 +81,15 @@ config ARM_KIRKWOOD_CPUFREQ
+ This adds the CPUFreq driver for Marvell Kirkwood
+ SoCs.
+
++config ARM_MT7623_CPUFREQ
++ bool "Mediatek MT7623 CPUFreq support"
++ depends on ARCH_MEDIATEK && REGULATOR
++ depends on ARM || (ARM_CPU_TOPOLOGY && COMPILE_TEST)
++ depends on !CPU_THERMAL || THERMAL=y
++ select PM_OPP
++ help
++ This adds the CPUFreq driver support for Mediatek MT7623 SoC.
++
+ config ARM_MT8173_CPUFREQ
+ bool "Mediatek MT8173 CPUFreq support"
+ depends on ARCH_MEDIATEK && REGULATOR
+--- a/drivers/cpufreq/Makefile
++++ b/drivers/cpufreq/Makefile
+@@ -57,6 +57,7 @@ obj-$(CONFIG_ARM_HISI_ACPU_CPUFREQ) += h
+ obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o
+ obj-$(CONFIG_ARM_INTEGRATOR) += integrator-cpufreq.o
+ obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += kirkwood-cpufreq.o
++obj-$(CONFIG_ARM_MT7623_CPUFREQ) += mt7623-cpufreq.o
+ obj-$(CONFIG_ARM_MT8173_CPUFREQ) += mt8173-cpufreq.o
+ obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o
+ obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2xx-cpufreq.o
+--- /dev/null
++++ b/drivers/cpufreq/mt7623-cpufreq.c
+@@ -0,0 +1,389 @@
++/*
++ * Copyright (c) 2015 Linaro Ltd.
++ * Author: Pi-Cheng Chen <pi-cheng.chen@linaro.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/clk.h>
++#include <linux/cpu.h>
++#include <linux/cpu_cooling.h>
++#include <linux/cpufreq.h>
++#include <linux/cpumask.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/pm_opp.h>
++#include <linux/regulator/consumer.h>
++#include <linux/slab.h>
++#include <linux/thermal.h>
++
++#define VOLT_TOL (10000)
++
++/*
++ * When scaling the clock frequency of a CPU clock domain, the clock source
++ * needs to be switched to another stable PLL clock temporarily until
++ * the original PLL becomes stable at target frequency.
++ */
++struct mtk_cpu_dvfs_info {
++ struct device *cpu_dev;
++ struct regulator *proc_reg;
++ struct clk *cpu_clk;
++ struct clk *inter_clk;
++ struct thermal_cooling_device *cdev;
++ int intermediate_voltage;
++};
++
++static int mtk_cpufreq_set_voltage(struct mtk_cpu_dvfs_info *info, int vproc)
++{
++ return regulator_set_voltage(info->proc_reg, vproc,
++ vproc + VOLT_TOL);
++}
++
++static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
++ unsigned int index)
++{
++ struct cpufreq_frequency_table *freq_table = policy->freq_table;
++ struct clk *cpu_clk = policy->clk;
++ struct clk *armpll = clk_get_parent(cpu_clk);
++ struct mtk_cpu_dvfs_info *info = policy->driver_data;
++ struct device *cpu_dev = info->cpu_dev;
++ struct dev_pm_opp *opp;
++ long freq_hz, old_freq_hz;
++ int vproc, old_vproc, inter_vproc, target_vproc, ret;
++
++ inter_vproc = info->intermediate_voltage;
++
++ old_freq_hz = clk_get_rate(cpu_clk);
++ old_vproc = regulator_get_voltage(info->proc_reg);
++
++ freq_hz = freq_table[index].frequency * 1000;
++
++ rcu_read_lock();
++ opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
++ if (IS_ERR(opp)) {
++ rcu_read_unlock();
++ pr_err("cpu%d: failed to find OPP for %ld\n",
++ policy->cpu, freq_hz);
++ return PTR_ERR(opp);
++ }
++ vproc = dev_pm_opp_get_voltage(opp);
++ rcu_read_unlock();
++
++ /*
++ * If the new voltage or the intermediate voltage is higher than the
++ * current voltage, scale up voltage first.
++ */
++ target_vproc = (inter_vproc > vproc) ? inter_vproc : vproc;
++ if (old_vproc < target_vproc) {
++ ret = mtk_cpufreq_set_voltage(info, target_vproc);
++ if (ret) {
++ pr_err("cpu%d: failed to scale up voltage!\n",
++ policy->cpu);
++ mtk_cpufreq_set_voltage(info, old_vproc);
++ return ret;
++ }
++ }
++
++ /* Reparent the CPU clock to intermediate clock. */
++ ret = clk_set_parent(cpu_clk, info->inter_clk);
++ if (ret) {
++ pr_err("cpu%d: failed to re-parent cpu clock!\n",
++ policy->cpu);
++ mtk_cpufreq_set_voltage(info, old_vproc);
++ WARN_ON(1);
++ return ret;
++ }
++
++ /* Set the original PLL to target rate. */
++ ret = clk_set_rate(armpll, freq_hz);
++ if (ret) {
++ pr_err("cpu%d: failed to scale cpu clock rate!\n",
++ policy->cpu);
++ clk_set_parent(cpu_clk, armpll);
++ mtk_cpufreq_set_voltage(info, old_vproc);
++ return ret;
++ }
++
++ /* Set parent of CPU clock back to the original PLL. */
++ ret = clk_set_parent(cpu_clk, armpll);
++ if (ret) {
++ pr_err("cpu%d: failed to re-parent cpu clock!\n",
++ policy->cpu);
++ mtk_cpufreq_set_voltage(info, inter_vproc);
++ WARN_ON(1);
++ return ret;
++ }
++
++ /*
++ * If the new voltage is lower than the intermediate voltage or the
++ * original voltage, scale down to the new voltage.
++ */
++ if (vproc < inter_vproc || vproc < old_vproc) {
++ ret = mtk_cpufreq_set_voltage(info, vproc);
++ if (ret) {
++ pr_err("cpu%d: failed to scale down voltage!\n",
++ policy->cpu);
++ clk_set_parent(cpu_clk, info->inter_clk);
++ clk_set_rate(armpll, old_freq_hz);
++ clk_set_parent(cpu_clk, armpll);
++ return ret;
++ }
++ }
++
++ return 0;
++}
++
++static void mtk_cpufreq_ready(struct cpufreq_policy *policy)
++{
++ struct mtk_cpu_dvfs_info *info = policy->driver_data;
++ struct device_node *np = of_node_get(info->cpu_dev->of_node);
++
++ if (WARN_ON(!np))
++ return;
++
++ if (of_find_property(np, "#cooling-cells", NULL)) {
++ info->cdev = of_cpufreq_cooling_register(np,
++ policy->related_cpus);
++
++ if (IS_ERR(info->cdev)) {
++ dev_err(info->cpu_dev,
++ "running cpufreq without cooling device: %ld\n",
++ PTR_ERR(info->cdev));
++
++ info->cdev = NULL;
++ }
++ }
++
++ of_node_put(np);
++}
++
++static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
++{
++ struct device *cpu_dev;
++ struct regulator *proc_reg = ERR_PTR(-ENODEV);
++ struct clk *cpu_clk = ERR_PTR(-ENODEV);
++ struct clk *inter_clk = ERR_PTR(-ENODEV);
++ struct dev_pm_opp *opp;
++ unsigned long rate;
++ int ret;
++
++ cpu_dev = get_cpu_device(cpu);
++ if (!cpu_dev) {
++ pr_err("failed to get cpu%d device\n", cpu);
++ return -ENODEV;
++ }
++
++ cpu_clk = clk_get(cpu_dev, "cpu");
++ if (IS_ERR(cpu_clk)) {
++ if (PTR_ERR(cpu_clk) == -EPROBE_DEFER)
++ pr_warn("cpu clk for cpu%d not ready, retry.\n", cpu);
++ else
++ pr_err("failed to get cpu clk for cpu%d\n", cpu);
++
++ ret = PTR_ERR(cpu_clk);
++ return ret;
++ }
++
++ inter_clk = clk_get(cpu_dev, "intermediate");
++ if (IS_ERR(inter_clk)) {
++ if (PTR_ERR(inter_clk) == -EPROBE_DEFER)
++ pr_warn("intermediate clk for cpu%d not ready, retry.\n",
++ cpu);
++ else
++ pr_err("failed to get intermediate clk for cpu%d\n",
++ cpu);
++
++ ret = PTR_ERR(inter_clk);
++ goto out_free_resources;
++ }
++
++ proc_reg = regulator_get_exclusive(cpu_dev, "proc");
++ if (IS_ERR(proc_reg)) {
++ if (PTR_ERR(proc_reg) == -EPROBE_DEFER)
++ pr_warn("proc regulator for cpu%d not ready, retry.\n",
++ cpu);
++ else
++ pr_err("failed to get proc regulator for cpu%d\n",
++ cpu);
++
++ ret = PTR_ERR(proc_reg);
++ goto out_free_resources;
++ }
++
++ ret = dev_pm_opp_of_add_table(cpu_dev);
++ if (ret) {
++ pr_warn("no OPP table for cpu%d\n", cpu);
++ goto out_free_resources;
++ }
++
++ /* Search a safe voltage for intermediate frequency. */
++ rate = clk_get_rate(inter_clk);
++ rcu_read_lock();
++ opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate);
++ if (IS_ERR(opp)) {
++ rcu_read_unlock();
++ pr_err("failed to get intermediate opp for cpu%d\n", cpu);
++ ret = PTR_ERR(opp);
++ goto out_free_opp_table;
++ }
++ info->intermediate_voltage = dev_pm_opp_get_voltage(opp);
++ rcu_read_unlock();
++
++ info->cpu_dev = cpu_dev;
++ info->proc_reg = proc_reg;
++ info->cpu_clk = cpu_clk;
++ info->inter_clk = inter_clk;
++
++ return 0;
++
++out_free_opp_table:
++ dev_pm_opp_of_remove_table(cpu_dev);
++
++out_free_resources:
++ if (!IS_ERR(proc_reg))
++ regulator_put(proc_reg);
++ if (!IS_ERR(cpu_clk))
++ clk_put(cpu_clk);
++ if (!IS_ERR(inter_clk))
++ clk_put(inter_clk);
++
++ return ret;
++}
++
++static void mtk_cpu_dvfs_info_release(struct mtk_cpu_dvfs_info *info)
++{
++ if (!IS_ERR(info->proc_reg))
++ regulator_put(info->proc_reg);
++ if (!IS_ERR(info->cpu_clk))
++ clk_put(info->cpu_clk);
++ if (!IS_ERR(info->inter_clk))
++ clk_put(info->inter_clk);
++
++ dev_pm_opp_of_remove_table(info->cpu_dev);
++}
++
++static int mtk_cpufreq_init(struct cpufreq_policy *policy)
++{
++ struct mtk_cpu_dvfs_info *info;
++ struct cpufreq_frequency_table *freq_table;
++ int ret;
++
++ info = kzalloc(sizeof(*info), GFP_KERNEL);
++ if (!info)
++ return -ENOMEM;
++
++ ret = mtk_cpu_dvfs_info_init(info, policy->cpu);
++ if (ret) {
++ pr_err("%s failed to initialize dvfs info for cpu%d\n",
++ __func__, policy->cpu);
++ goto out_free_dvfs_info;
++ }
++
++ ret = dev_pm_opp_init_cpufreq_table(info->cpu_dev, &freq_table);
++ if (ret) {
++ pr_err("failed to init cpufreq table for cpu%d: %d\n",
++ policy->cpu, ret);
++ goto out_release_dvfs_info;
++ }
++
++ ret = cpufreq_table_validate_and_show(policy, freq_table);
++ if (ret) {
++ pr_err("%s: invalid frequency table: %d\n", __func__, ret);
++ goto out_free_cpufreq_table;
++ }
++
++ /* CPUs in the same cluster share a clock and power domain. */
++ cpumask_setall(policy->cpus);
++ policy->driver_data = info;
++ policy->clk = info->cpu_clk;
++
++ return 0;
++
++out_free_cpufreq_table:
++ dev_pm_opp_free_cpufreq_table(info->cpu_dev, &freq_table);
++
++out_release_dvfs_info:
++ mtk_cpu_dvfs_info_release(info);
++
++out_free_dvfs_info:
++ kfree(info);
++
++ return ret;
++}
++
++static int mtk_cpufreq_exit(struct cpufreq_policy *policy)
++{
++ struct mtk_cpu_dvfs_info *info = policy->driver_data;
++
++ cpufreq_cooling_unregister(info->cdev);
++ dev_pm_opp_free_cpufreq_table(info->cpu_dev, &policy->freq_table);
++ mtk_cpu_dvfs_info_release(info);
++ kfree(info);
++
++ return 0;
++}
++
++static struct cpufreq_driver mt7623_cpufreq_driver = {
++ .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
++ .verify = cpufreq_generic_frequency_table_verify,
++ .target_index = mtk_cpufreq_set_target,
++ .get = cpufreq_generic_get,
++ .init = mtk_cpufreq_init,
++ .exit = mtk_cpufreq_exit,
++ .ready = mtk_cpufreq_ready,
++ .name = "mtk-cpufreq",
++ .attr = cpufreq_generic_attr,
++};
++
++static int mt7623_cpufreq_probe(struct platform_device *pdev)
++{
++ int ret;
++
++ ret = cpufreq_register_driver(&mt7623_cpufreq_driver);
++ if (ret)
++ pr_err("failed to register mtk cpufreq driver\n");
++
++ return ret;
++}
++
++static struct platform_driver mt7623_cpufreq_platdrv = {
++ .driver = {
++ .name = "mt7623-cpufreq",
++ },
++ .probe = mt7623_cpufreq_probe,
++};
++
++static int mt7623_cpufreq_driver_init(void)
++{
++ struct platform_device *pdev;
++ int err;
++
++ if (!of_machine_is_compatible("mediatek,mt7623"))
++ return -ENODEV;
++
++ err = platform_driver_register(&mt7623_cpufreq_platdrv);
++ if (err)
++ return err;
++
++ /*
++ * Since there's no place to hold device registration code and no
++ * device tree based way to match cpufreq driver yet, both the driver
++ * and the device registration codes are put here to handle defer
++ * probing.
++ */
++ pdev = platform_device_register_simple("mt7623-cpufreq", -1, NULL, 0);
++ if (IS_ERR(pdev)) {
++ pr_err("failed to register mtk-cpufreq platform device\n");
++ return PTR_ERR(pdev);
++ }
++
++ return 0;
++}
++device_initcall(mt7623_cpufreq_driver_init);
diff --git a/target/linux/mediatek/patches-4.4/0055-mtd-nand-embed-an-mtd_info-structure-into-nand_chip.patch b/target/linux/mediatek/patches-4.4/0055-mtd-nand-embed-an-mtd_info-structure-into-nand_chip.patch
deleted file mode 100644
index 0decc646f0..0000000000
--- a/target/linux/mediatek/patches-4.4/0055-mtd-nand-embed-an-mtd_info-structure-into-nand_chip.patch
+++ /dev/null
@@ -1,42 +0,0 @@
-From f18fcf4468ffdce17747f3d331f998a7e9264142 Mon Sep 17 00:00:00 2001
-From: Boris BREZILLON <boris.brezillon@free-electrons.com>
-Date: Tue, 1 Dec 2015 12:03:06 +0100
-Subject: [PATCH 55/91] mtd: nand: embed an mtd_info structure into nand_chip
-
-Currently all NAND controller drivers are providing both the mtd_info and
-nand_chip struct and then let the NAND subsystem to initialize a few
-things before registering the mtd instance to the MTD layer.
-Embed an mtd_info field into nand_chip to add some consistency to all NAND
-controller drivers.
-This change will also help factorizing boilerplate code copied in all NAND
-drivers.
-
-Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
-Signed-off-by: Brian Norris <computersforpeace@gmail.com>
----
- include/linux/mtd/nand.h | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
-index 345f864..1ded588 100644
---- a/include/linux/mtd/nand.h
-+++ b/include/linux/mtd/nand.h
-@@ -540,6 +540,7 @@ struct nand_buffers {
-
- /**
- * struct nand_chip - NAND Private Flash Chip Data
-+ * @mtd: MTD device registered to the MTD framework
- * @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the
- * flash device
- * @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the
-@@ -640,6 +641,7 @@ struct nand_buffers {
- */
-
- struct nand_chip {
-+ struct mtd_info mtd;
- void __iomem *IO_ADDR_R;
- void __iomem *IO_ADDR_W;
-
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0056-arm-mediatek-make-a7-timer-work-Signed-off-by-John-C.patch b/target/linux/mediatek/patches-4.4/0056-arm-mediatek-make-a7-timer-work-Signed-off-by-John-C.patch
new file mode 100644
index 0000000000..fe81b47290
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0056-arm-mediatek-make-a7-timer-work-Signed-off-by-John-C.patch
@@ -0,0 +1,31 @@
+From f8cda0bc698706413b5dd6fde827f9a2601ac61b Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Thu, 31 Mar 2016 06:07:01 +0200
+Subject: [PATCH 056/102] arm: mediatek: make a7 timer work Signed-off-by:
+ John Crispin <blogic@openwrt.org>
+
+---
+ arch/arm/mach-mediatek/Kconfig | 1 +
+ arch/arm/mach-mediatek/mediatek.c | 1 +
+ 2 files changed, 2 insertions(+)
+
+--- a/arch/arm/mach-mediatek/Kconfig
++++ b/arch/arm/mach-mediatek/Kconfig
+@@ -24,6 +24,7 @@ config MACH_MT6592
+ config MACH_MT7623
+ bool "MediaTek MT7623 SoCs support"
+ default ARCH_MEDIATEK
++ select HAVE_ARM_ARCH_TIMER
+ select MIGHT_HAVE_PCI
+
+ config MACH_MT8127
+--- a/arch/arm/mach-mediatek/mediatek.c
++++ b/arch/arm/mach-mediatek/mediatek.c
+@@ -29,6 +29,7 @@ static void __init mediatek_timer_init(v
+ void __iomem *gpt_base;
+
+ if (of_machine_is_compatible("mediatek,mt6589") ||
++ of_machine_is_compatible("mediatek,mt7623") ||
+ of_machine_is_compatible("mediatek,mt8135") ||
+ of_machine_is_compatible("mediatek,mt8127")) {
+ /* turn on GPT6 which ungates arch timer clocks */
diff --git a/target/linux/mediatek/patches-4.4/0056-mtd-add-get-set-of_node-flash_node-helpers.patch b/target/linux/mediatek/patches-4.4/0056-mtd-add-get-set-of_node-flash_node-helpers.patch
deleted file mode 100644
index 02066f88b9..0000000000
--- a/target/linux/mediatek/patches-4.4/0056-mtd-add-get-set-of_node-flash_node-helpers.patch
+++ /dev/null
@@ -1,87 +0,0 @@
-From 59d8570d4b61af8544fc295d5e83ab7c28294bb8 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Tue, 22 Mar 2016 03:52:07 +0100
-Subject: [PATCH 56/91] mtd: add get/set of_node/flash_node helpers
-
-We are going to begin using the mtd->dev.of_node field for MTD device
-nodes, so let's add helpers for it. Also, we'll be making some
-conversions on spi_nor (and nand_chip eventually) too, so get that ready
-with their own helpers.
-
-Signed-off-by: Brian Norris <computersforpeace@gmail.com>
-Reviewed-by: Boris Brezillon <boris.brezillon@free-electrons.com>
----
- include/linux/mtd/mtd.h | 11 +++++++++++
- include/linux/mtd/nand.h | 11 +++++++++++
- include/linux/mtd/spi-nor.h | 11 +++++++++++
- 3 files changed, 33 insertions(+)
-
-diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
-index f17fa75..cc84923 100644
---- a/include/linux/mtd/mtd.h
-+++ b/include/linux/mtd/mtd.h
-@@ -254,6 +254,17 @@ struct mtd_info {
- int usecount;
- };
-
-+static inline void mtd_set_of_node(struct mtd_info *mtd,
-+ struct device_node *np)
-+{
-+ mtd->dev.of_node = np;
-+}
-+
-+static inline struct device_node *mtd_get_of_node(struct mtd_info *mtd)
-+{
-+ return mtd->dev.of_node;
-+}
-+
- int mtd_erase(struct mtd_info *mtd, struct erase_info *instr);
- int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
- void **virt, resource_size_t *phys);
-diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
-index 1ded588..3c34ca4 100644
---- a/include/linux/mtd/nand.h
-+++ b/include/linux/mtd/nand.h
-@@ -741,6 +741,17 @@ static inline void nand_set_controller_data(struct nand_chip *chip, void *priv)
- chip->priv = priv;
- }
-
-+static inline void nand_set_flash_node(struct nand_chip *chip,
-+ struct device_node *np)
-+{
-+ chip->flash_node = np;
-+}
-+
-+static inline struct device_node *nand_get_flash_node(struct nand_chip *chip)
-+{
-+ return chip->flash_node;
-+}
-+
- /*
- * NAND Flash Manufacturer ID Codes
- */
-diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
-index c8723b6..6d991df 100644
---- a/include/linux/mtd/spi-nor.h
-+++ b/include/linux/mtd/spi-nor.h
-@@ -185,6 +185,17 @@ struct spi_nor {
- void *priv;
- };
-
-+static inline void spi_nor_set_flash_node(struct spi_nor *nor,
-+ struct device_node *np)
-+{
-+ nor->flash_node = np;
-+}
-+
-+static inline struct device_node *spi_nor_get_flash_node(struct spi_nor *nor)
-+{
-+ return nor->flash_node;
-+}
-+
- /**
- * spi_nor_scan() - scan the SPI NOR
- * @nor: the spi_nor structure
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0057-mtd-mediatek-device-tree-docs-for-MTK-Smart-Device-G.patch b/target/linux/mediatek/patches-4.4/0057-mtd-mediatek-device-tree-docs-for-MTK-Smart-Device-G.patch
deleted file mode 100644
index edeeb96850..0000000000
--- a/target/linux/mediatek/patches-4.4/0057-mtd-mediatek-device-tree-docs-for-MTK-Smart-Device-G.patch
+++ /dev/null
@@ -1,64 +0,0 @@
-From 0fe612b501f1d56d76b2858d2ae779c1e766d064 Mon Sep 17 00:00:00 2001
-From: Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
-Date: Wed, 2 Mar 2016 12:00:11 -0500
-Subject: [PATCH 57/91] mtd: mediatek: device tree docs for MTK Smart Device
- Gen1 NAND
-
-This patch adds documentation support for Smart Device Gen1 type of
-NAND controllers.
-
-Mediatek's SoC 2701 is one of the SoCs that implements this controller.
-
-Signed-off-by: Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
----
- .../devicetree/bindings/mtd/mtksdg1-nand.txt | 38 ++++++++++++++++++++
- 1 file changed, 38 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/mtd/mtksdg1-nand.txt
-
-diff --git a/Documentation/devicetree/bindings/mtd/mtksdg1-nand.txt b/Documentation/devicetree/bindings/mtd/mtksdg1-nand.txt
-new file mode 100644
-index 0000000..129d17b
---- /dev/null
-+++ b/Documentation/devicetree/bindings/mtd/mtksdg1-nand.txt
-@@ -0,0 +1,38 @@
-+MTK Smart Device SoCs NAND controller DT binding
-+
-+Required properties:
-+- compatible: Should be "mediatek,mt2701-nfc".
-+- reg: The first contains base physical address and size of
-+ NAND controller's registers. The second contains base
-+ physical address and size of NAND ECC engine.
-+- interrupts: the NFC NFI interrupt, and the NFC ECC interrupt
-+- clocks: NAND controller clocks.
-+- clock-names: NAND controller clocks internal name.
-+- vmch-supply: NAND power supply.
-+- #address-cells: Partition address, should be set 1.
-+- #size-cells: Partition size, should be set 1.
-+
-+Optional properties:
-+
-+nand-on-flash-bbt: Use a flash based bad block table.
-+
-+Optional subnodes:
-+- Partitions, see Documentation/devicetree/bindings/mtd/partition.txt
-+
-+Example:
-+
-+ nand: nand@1100d000 {
-+ compatible = "mediatek,mt2701-nfc";
-+ reg = <0 0x1100d000 0 0x1000>, <0 0x1100e000 0 0x1000>;
-+ interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_LOW>,
-+ <GIC_SPI 55 IRQ_TYPE_LEVEL_LOW>;
-+ clocks = <&pericfg CLK_PERI_NFI>, <&pericfg CLK_PERI_NFI_ECC>,
-+ <&pericfg CLK_PERI_NFI_PAD>;
-+ clock-names = "nfi_ck", "nfi_ecc_ck", "nfi_pad_ck";
-+ vmch-supply = <&mt6323_vmch_reg>;
-+ status = "disabled";
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+
-+ ...
-+ };
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0057-net-mediatek-checking-for-IS_ERR-instead-of-NULL.patch b/target/linux/mediatek/patches-4.4/0057-net-mediatek-checking-for-IS_ERR-instead-of-NULL.patch
new file mode 100644
index 0000000000..f00e9682bc
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0057-net-mediatek-checking-for-IS_ERR-instead-of-NULL.patch
@@ -0,0 +1,27 @@
+From b9f9b937dd12dc57bd54a6c89b18eb40d4508424 Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <dan.carpenter@oracle.com>
+Date: Tue, 15 Mar 2016 10:18:49 +0300
+Subject: [PATCH 057/102] net: mediatek: checking for IS_ERR() instead of NULL
+
+of_phy_connect() returns NULL on error, it never returns error pointers.
+
+Fixes: 656e705243fd ('net-next: mediatek: add support for MT7623 ethernet')
+Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -186,9 +186,9 @@ static int mtk_phy_connect_node(struct m
+
+ phydev = of_phy_connect(eth->netdev[mac->id], phy_node,
+ mtk_phy_link_adjust, 0, phy_mode);
+- if (IS_ERR(phydev)) {
++ if (!phydev) {
+ dev_err(eth->dev, "could not connect to PHY\n");
+- return PTR_ERR(phydev);
++ return -ENODEV;
+ }
+
+ dev_info(eth->dev,
diff --git a/target/linux/mediatek/patches-4.4/0058-mtd-mediatek-driver-for-MTK-Smart-Device-Gen1-NAND.patch b/target/linux/mediatek/patches-4.4/0058-mtd-mediatek-driver-for-MTK-Smart-Device-Gen1-NAND.patch
deleted file mode 100644
index c868fa49b9..0000000000
--- a/target/linux/mediatek/patches-4.4/0058-mtd-mediatek-driver-for-MTK-Smart-Device-Gen1-NAND.patch
+++ /dev/null
@@ -1,1798 +0,0 @@
-From 24db36ad20239841b897efb41442841ebf5d2f78 Mon Sep 17 00:00:00 2001
-From: Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
-Date: Wed, 2 Mar 2016 12:00:12 -0500
-Subject: [PATCH 58/91] mtd: mediatek: driver for MTK Smart Device Gen1 NAND
-
-This patch adds support for mediatek's SDG1 NFC nand controller
-embedded in SoC 2701.
-
-UBIFS support has been successfully tested.
-
-Signed-off-by: Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
----
- drivers/mtd/nand/Kconfig | 6 +
- drivers/mtd/nand/Makefile | 1 +
- drivers/mtd/nand/mtksdg1_nand.c | 1535 +++++++++++++++++++++++++++++++++++
- drivers/mtd/nand/mtksdg1_nand_ecc.h | 75 ++
- drivers/mtd/nand/mtksdg1_nand_nfi.h | 119 +++
- 5 files changed, 1736 insertions(+)
- create mode 100644 drivers/mtd/nand/mtksdg1_nand.c
- create mode 100644 drivers/mtd/nand/mtksdg1_nand_ecc.h
- create mode 100644 drivers/mtd/nand/mtksdg1_nand_nfi.h
-
-diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
-index 2896640..5ec072a 100644
---- a/drivers/mtd/nand/Kconfig
-+++ b/drivers/mtd/nand/Kconfig
-@@ -546,4 +546,10 @@ config MTD_NAND_HISI504
- help
- Enables support for NAND controller on Hisilicon SoC Hip04.
-
-+config MTD_NAND_MTKSDG1
-+ tristate "Support for NAND controller on MTK Smart Device SoCs"
-+ depends on HAS_DMA
-+ help
-+ Enables support for NAND controller on MTK Smart Device SoCs.
-+
- endif # MTD_NAND
-diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
-index 2c7f014..2a2620c 100644
---- a/drivers/mtd/nand/Makefile
-+++ b/drivers/mtd/nand/Makefile
-@@ -55,5 +55,6 @@ obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/
- obj-$(CONFIG_MTD_NAND_SUNXI) += sunxi_nand.o
- obj-$(CONFIG_MTD_NAND_HISI504) += hisi504_nand.o
- obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand/
-+obj-$(CONFIG_MTD_NAND_MTKSDG1) += mtksdg1_nand.o
-
- nand-objs := nand_base.o nand_bbt.o nand_timings.o
-diff --git a/drivers/mtd/nand/mtksdg1_nand.c b/drivers/mtd/nand/mtksdg1_nand.c
-new file mode 100644
-index 0000000..55dd17d
---- /dev/null
-+++ b/drivers/mtd/nand/mtksdg1_nand.c
-@@ -0,0 +1,1535 @@
-+/*
-+ * MTK smart device NAND Flash controller driver.
-+ * Copyright (C) 2015-2016 MediaTek Inc.
-+ * Authors: Xiaolei Li <xiaolei.li@mediatek.com>
-+ * Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#include <linux/platform_device.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/interrupt.h>
-+#include <linux/of_mtd.h>
-+#include <linux/delay.h>
-+#include <linux/clk.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/mtd/nand.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/module.h>
-+
-+#include "mtksdg1_nand_nfi.h"
-+#include "mtksdg1_nand_ecc.h"
-+
-+#define MTK_IRQ_ECC "mtksdg1-nand-ecc"
-+#define MTK_IRQ_NFI "mtksdg1-nand-nfi"
-+#define MTK_NAME "mtksdg1-nand"
-+
-+#define KB(x) ((x) * 1024UL)
-+#define MB(x) (KB(x) * 1024UL)
-+
-+#define SECTOR_SHIFT (10)
-+#define SECTOR_SIZE (1UL << SECTOR_SHIFT)
-+#define BYTES_TO_SECTORS(x) ((x) >> SECTOR_SHIFT)
-+#define SECTORS_TO_BYTES(x) ((x) << SECTOR_SHIFT)
-+
-+#define MTK_TIMEOUT (500)
-+#define MTK_RESET_TIMEOUT (1 * HZ)
-+
-+#define MTK_ECC_PARITY_BITS (14)
-+#define MTK_NAND_MAX_CHIP (2)
-+
-+#define MTK_OOB_ON (1)
-+#define MTK_OOB_OFF (0)
-+
-+/* raw accesses do not use ECC (ecc = !raw) */
-+#define MTK_ECC_OFF (1)
-+#define MTK_ECC_ON (0)
-+
-+struct mtk_nfc_clk {
-+ struct clk *nfiecc_clk;
-+ struct clk *nfi_clk;
-+ struct clk *pad_clk;
-+};
-+
-+struct mtk_nfc_saved_reg {
-+ struct {
-+ u32 enccnfg;
-+ u32 deccnfg;
-+ } ecc;
-+ struct {
-+ u32 emp_thresh;
-+ u16 pagefmt;
-+ u32 acccon;
-+ u16 cnrnb;
-+ u16 csel;
-+ } nfi;
-+};
-+
-+struct mtk_nfc_host {
-+ struct mtk_nfc_clk clk;
-+ struct nand_chip chip;
-+ struct device *dev;
-+
-+ struct {
-+ struct completion complete;
-+ void __iomem *base;
-+ } nfi;
-+
-+ struct {
-+ struct completion complete;
-+ void __iomem *base;
-+ u32 dec_sec;
-+ } ecc;
-+
-+ u32 fdm_reg[MTKSDG1_NFI_FDM_REG_SIZE / sizeof(u32)];
-+ bool switch_oob;
-+ u32 row_nob;
-+ u8 *buffer;
-+
-+#ifdef CONFIG_PM_SLEEP
-+ struct mtk_nfc_saved_reg saved_reg;
-+#endif
-+};
-+
-+static struct nand_ecclayout nand_2k_64 = {
-+ .oobfree = { {0, 16} },
-+};
-+
-+static struct nand_ecclayout nand_4k_128 = {
-+ .oobfree = { {0, 32} },
-+};
-+
-+/* NFI register access */
-+static inline void mtk_nfi_writel(struct mtk_nfc_host *host, u32 val, u32 reg)
-+{
-+ writel(val, host->nfi.base + reg);
-+}
-+static inline void mtk_nfi_writew(struct mtk_nfc_host *host, u16 val, u32 reg)
-+{
-+ writew(val, host->nfi.base + reg);
-+}
-+static inline u32 mtk_nfi_readl(struct mtk_nfc_host *host, u32 reg)
-+{
-+ return readl_relaxed(host->nfi.base + reg);
-+}
-+static inline u16 mtk_nfi_readw(struct mtk_nfc_host *host, u32 reg)
-+{
-+ return readw_relaxed(host->nfi.base + reg);
-+}
-+static inline u8 mtk_nfi_readb(struct mtk_nfc_host *host, u32 reg)
-+{
-+ return readb_relaxed(host->nfi.base + reg);
-+}
-+
-+/* ECC register access */
-+static inline void mtk_ecc_writel(struct mtk_nfc_host *host, u32 val, u32 reg)
-+{
-+ writel(val, host->ecc.base + reg);
-+}
-+static inline void mtk_ecc_writew(struct mtk_nfc_host *host, u16 val, u32 reg)
-+{
-+ writew(val, host->ecc.base + reg);
-+}
-+static inline u32 mtk_ecc_readl(struct mtk_nfc_host *host, u32 reg)
-+{
-+ return readl_relaxed(host->ecc.base + reg);
-+}
-+static inline u16 mtk_ecc_readw(struct mtk_nfc_host *host, u32 reg)
-+{
-+ return readw_relaxed(host->ecc.base + reg);
-+}
-+
-+static void mtk_nfc_hw_reset(struct mtk_nfc_host *host)
-+{
-+ unsigned long timeout = MTK_RESET_TIMEOUT;
-+ struct device *dev = host->dev;
-+ u32 val;
-+
-+ /* reset the state machine, data fifo and fdm data */
-+ mtk_nfi_writel(host, CON_FIFO_FLUSH | CON_NFI_RST, MTKSDG1_NFI_CON);
-+ timeout += jiffies;
-+ do {
-+ val = mtk_nfi_readl(host, MTKSDG1_NFI_MASTER_STA);
-+ val &= MASTER_STA_MASK;
-+ if (!val)
-+ return;
-+ usleep_range(50, 100);
-+
-+ } while (time_before(jiffies, timeout));
-+
-+ dev_warn(dev, "nfi master active after in reset [0x%x] = 0x%x\n",
-+ MTKSDG1_NFI_MASTER_STA, val);
-+};
-+
-+static int mtk_nfc_set_command(struct mtk_nfc_host *host, u8 command)
-+{
-+ unsigned long timeout = msecs_to_jiffies(MTK_TIMEOUT);
-+ struct device *dev = host->dev;
-+ u32 val;
-+
-+ mtk_nfi_writel(host, command, MTKSDG1_NFI_CMD);
-+
-+ /* wait for the NFI core to enter command mode */
-+ timeout += jiffies;
-+ do {
-+ val = mtk_nfi_readl(host, MTKSDG1_NFI_STA);
-+ val &= STA_CMD;
-+ if (!val)
-+ return 0;
-+ cpu_relax();
-+
-+ } while (time_before(jiffies, timeout));
-+ dev_warn(dev, "nfi core timed out entering command mode\n");
-+
-+ return -EIO;
-+}
-+
-+static int mtk_nfc_set_address(struct mtk_nfc_host *host, u32 column, u32 row,
-+ u8 colnob, u8 row_nob)
-+{
-+ unsigned long timeout = msecs_to_jiffies(MTK_TIMEOUT);
-+ struct device *dev = host->dev;
-+ u32 addr_nob, val;
-+
-+ addr_nob = colnob | (row_nob << ADDR_ROW_NOB_SHIFT);
-+ mtk_nfi_writel(host, column, MTKSDG1_NFI_COLADDR);
-+ mtk_nfi_writel(host, row, MTKSDG1_NFI_ROWADDR);
-+ mtk_nfi_writel(host, addr_nob, MTKSDG1_NFI_ADDRNOB);
-+
-+ /* wait for the NFI core to enter address mode */
-+ timeout += jiffies;
-+ do {
-+ val = mtk_nfi_readl(host, MTKSDG1_NFI_STA);
-+ val &= STA_ADDR;
-+ if (!val)
-+ return 0;
-+ cpu_relax();
-+
-+ } while (time_before(jiffies, timeout));
-+
-+ dev_warn(dev, "nfi core timed out entering address mode\n");
-+
-+ return -EIO;
-+}
-+
-+static inline void mtk_ecc_encoder_idle(struct mtk_nfc_host *host)
-+{
-+ unsigned long timeout = msecs_to_jiffies(MTK_TIMEOUT);
-+ struct device *dev = host->dev;
-+ u32 val;
-+
-+ timeout += jiffies;
-+ do {
-+ val = mtk_ecc_readl(host, MTKSDG1_ECC_ENCIDLE);
-+ val &= ENC_IDLE;
-+ if (val)
-+ return;
-+ cpu_relax();
-+
-+ } while (time_before(jiffies, timeout));
-+
-+ dev_warn(dev, "hw init ecc encoder not idle\n");
-+}
-+
-+static inline void mtk_ecc_decoder_idle(struct mtk_nfc_host *host)
-+{
-+ unsigned long timeout = msecs_to_jiffies(MTK_TIMEOUT);
-+ struct device *dev = host->dev;
-+ u32 val;
-+
-+ timeout += jiffies;
-+ do {
-+ val = mtk_ecc_readw(host, MTKSDG1_ECC_DECIDLE);
-+ val &= DEC_IDLE;
-+ if (val)
-+ return;
-+ cpu_relax();
-+
-+ } while (time_before(jiffies, timeout));
-+
-+ dev_warn(dev, "hw init ecc decoder not idle\n");
-+}
-+
-+static int mtk_nfc_transfer_done(struct mtk_nfc_host *host, u32 sectors)
-+{
-+ unsigned long timeout = msecs_to_jiffies(MTK_TIMEOUT);
-+ u32 cnt;
-+
-+ /* wait for the sector count */
-+ timeout += jiffies;
-+ do {
-+ cnt = mtk_nfi_readl(host, MTKSDG1_NFI_ADDRCNTR);
-+ cnt &= CNTR_MASK;
-+ if (cnt >= sectors)
-+ return 0;
-+ cpu_relax();
-+
-+ } while (time_before(jiffies, timeout));
-+
-+ return -EIO;
-+}
-+
-+static int mtk_nfc_subpage_done(struct mtk_nfc_host *host, int sectors)
-+{
-+ unsigned long timeout = msecs_to_jiffies(MTK_TIMEOUT);
-+ u32 val;
-+
-+ timeout += jiffies;
-+ do {
-+ val = mtk_nfi_readl(host, MTKSDG1_NFI_BYTELEN);
-+ val &= CNTR_MASK;
-+ if (val >= sectors)
-+ return 0;
-+ cpu_relax();
-+
-+ } while (time_before(jiffies, timeout));
-+
-+ return -EIO;
-+}
-+
-+static inline int mtk_nfc_data_ready(struct mtk_nfc_host *host)
-+{
-+ unsigned long timeout = msecs_to_jiffies(MTK_TIMEOUT);
-+ u8 val;
-+
-+ timeout += jiffies;
-+ do {
-+ val = mtk_nfi_readw(host, MTKSDG1_NFI_PIO_DIRDY);
-+ val &= PIO_DI_RDY;
-+ if (val)
-+ return 0;
-+ cpu_relax();
-+
-+ } while (time_before(jiffies, timeout));
-+
-+ /* data _MUST_ not be accessed */
-+ return -EIO;
-+}
-+
-+static int mtk_nfc_hw_runtime_config(struct mtd_info *mtd)
-+{
-+ struct nand_chip *chip = mtd_to_nand(mtd);
-+ struct mtk_nfc_host *host = nand_get_controller_data(chip);
-+ struct device *dev = host->dev;
-+ u32 dec_size, enc_size;
-+ u32 ecc_bit, ecc_level;
-+ u32 spare, fmt;
-+ u32 reg;
-+
-+ host->row_nob = 1;
-+ if (chip->chipsize > MB(32))
-+ host->row_nob = chip->chipsize > MB(128) ? 3 : 2;
-+
-+ spare = mtd->oobsize / BYTES_TO_SECTORS(mtd->writesize);
-+ switch (spare) {
-+ case 16:
-+ ecc_bit = ECC_CNFG_4BIT;
-+ ecc_level = 4;
-+ break;
-+ case 32:
-+ ecc_bit = ECC_CNFG_12BIT;
-+ ecc_level = 12;
-+ break;
-+ default:
-+ dev_err(dev, "invalid spare size per sector: %d\n", spare);
-+ return -EINVAL;
-+ }
-+
-+ chip->ecc.strength = ecc_level;
-+ chip->ecc.size = SECTOR_SIZE;
-+
-+ switch (mtd->writesize) {
-+ case KB(2):
-+ fmt = PAGEFMT_512_2K;
-+ chip->ecc.layout = &nand_2k_64;
-+ break;
-+ case KB(4):
-+ fmt = PAGEFMT_2K_4K;
-+ chip->ecc.layout = &nand_4k_128;
-+ break;
-+ case KB(8):
-+ fmt = PAGEFMT_4K_8K;
-+ break;
-+ default:
-+ dev_err(dev, "invalid page size: %d\n", mtd->writesize);
-+ return -EINVAL;
-+ }
-+
-+ /* configure PAGE FMT */
-+ reg = fmt;
-+ reg |= PAGEFMT_SPARE_16 << PAGEFMT_SPARE_SHIFT;
-+ reg |= MTKSDG1_NFI_FDM_REG_SIZE << PAGEFMT_FDM_SHIFT;
-+ reg |= MTKSDG1_NFI_FDM_REG_SIZE << PAGEFMT_FDM_ECC_SHIFT;
-+ mtk_nfi_writew(host, reg, MTKSDG1_NFI_PAGEFMT);
-+
-+ /* configure ECC encoder (in bits) */
-+ enc_size = (SECTOR_SIZE + MTKSDG1_NFI_FDM_REG_SIZE) << 3;
-+ reg = ecc_bit | ECC_NFI_MODE | (enc_size << ECC_MS_SHIFT);
-+ mtk_ecc_writel(host, reg, MTKSDG1_ECC_ENCCNFG);
-+
-+ /* configure ECC decoder (inbits) */
-+ dec_size = enc_size + ecc_level * MTK_ECC_PARITY_BITS;
-+ reg = ecc_bit | ECC_NFI_MODE | (dec_size << ECC_MS_SHIFT);
-+ reg |= (DEC_CNFG_CORRECT | DEC_EMPTY_EN);
-+ mtk_ecc_writel(host, reg, MTKSDG1_ECC_DECCNFG);
-+
-+ return 0;
-+}
-+
-+static void mtk_nfc_device_reset(struct mtk_nfc_host *host)
-+{
-+ unsigned long timeout = msecs_to_jiffies(MTK_TIMEOUT);
-+ struct device *dev = host->dev;
-+ u16 chip;
-+ int rc;
-+
-+ mtk_nfc_hw_reset(host);
-+
-+ /* enable reset done interrupt */
-+ mtk_nfi_writew(host, INTR_RST_DONE_EN, MTKSDG1_NFI_INTR_EN);
-+
-+ /* configure FSM for reset operation */
-+ mtk_nfi_writew(host, CNFG_OP_RESET, MTKSDG1_NFI_CNFG);
-+
-+ init_completion(&host->nfi.complete);
-+
-+ mtk_nfc_set_command(host, NAND_CMD_RESET);
-+ rc = wait_for_completion_timeout(&host->nfi.complete, timeout);
-+ if (!rc) {
-+ chip = mtk_nfi_readw(host, MTKSDG1_NFI_CSEL);
-+ dev_err(dev, "device(%d) reset timeout\n", chip);
-+ }
-+}
-+
-+static void mtk_nfc_select_chip(struct mtd_info *mtd, int chip)
-+{
-+ struct nand_chip *nand = mtd_to_nand(mtd);
-+ struct mtk_nfc_host *host = nand_get_controller_data(nand);
-+
-+ if (chip < 0)
-+ return;
-+
-+ mtk_nfi_writel(host, chip, MTKSDG1_NFI_CSEL);
-+}
-+
-+static inline bool mtk_nfc_cmd_supported(unsigned command)
-+{
-+ switch (command) {
-+ case NAND_CMD_RESET:
-+ case NAND_CMD_READID:
-+ case NAND_CMD_STATUS:
-+ case NAND_CMD_READOOB:
-+ case NAND_CMD_ERASE1:
-+ case NAND_CMD_ERASE2:
-+ case NAND_CMD_SEQIN:
-+ case NAND_CMD_PAGEPROG:
-+ case NAND_CMD_CACHEDPROG:
-+ case NAND_CMD_READ0:
-+ return true;
-+ default:
-+ return false;
-+ }
-+}
-+
-+static void mtk_nfc_cmdfunc(struct mtd_info *mtd, unsigned command, int column,
-+ int page_addr)
-+{
-+ struct mtk_nfc_host *host = nand_get_controller_data(mtd_to_nand(mtd));
-+ unsigned long const cmd_timeout = msecs_to_jiffies(MTK_TIMEOUT);
-+ struct completion *p = &host->nfi.complete;
-+ u32 val;
-+ int rc;
-+
-+ if (mtk_nfc_cmd_supported(command))
-+ mtk_nfc_hw_reset(host);
-+
-+ switch (command) {
-+ case NAND_CMD_RESET:
-+ mtk_nfc_device_reset(host);
-+ break;
-+ case NAND_CMD_READID:
-+ val = CNFG_READ_EN | CNFG_BYTE_RW | CNFG_OP_SRD;
-+ mtk_nfi_writew(host, val, MTKSDG1_NFI_CNFG);
-+ mtk_nfc_set_command(host, NAND_CMD_READID);
-+ mtk_nfc_set_address(host, column, 0, 1, 0);
-+ mtk_nfi_writel(host, CON_SRD, MTKSDG1_NFI_CON);
-+ break;
-+ case NAND_CMD_STATUS:
-+ val = CNFG_READ_EN | CNFG_BYTE_RW | CNFG_OP_SRD;
-+ mtk_nfi_writew(host, val, MTKSDG1_NFI_CNFG);
-+ mtk_nfc_set_command(host, NAND_CMD_STATUS);
-+ mtk_nfi_writel(host, CON_SRD, MTKSDG1_NFI_CON);
-+ break;
-+ case NAND_CMD_READOOB:
-+ val = CNFG_READ_EN | CNFG_BYTE_RW | CNFG_OP_READ;
-+ mtk_nfi_writew(host, val, MTKSDG1_NFI_CNFG);
-+ mtk_nfc_set_command(host, NAND_CMD_READ0);
-+ column += mtd->writesize;
-+ mtk_nfc_set_address(host, column, page_addr, 2, host->row_nob);
-+ val = CON_BRD | (1 << CON_SEC_SHIFT);
-+ mtk_nfi_writel(host, val, MTKSDG1_NFI_CON);
-+ break;
-+ case NAND_CMD_ERASE1:
-+ mtk_nfi_writew(host, INTR_ERS_DONE_EN, MTKSDG1_NFI_INTR_EN);
-+ mtk_nfi_writew(host, CNFG_OP_ERASE, MTKSDG1_NFI_CNFG);
-+ mtk_nfc_set_command(host, NAND_CMD_ERASE1);
-+ mtk_nfc_set_address(host, 0, page_addr, 0, host->row_nob);
-+ break;
-+ case NAND_CMD_ERASE2:
-+ init_completion(p);
-+ mtk_nfc_set_command(host, NAND_CMD_ERASE2);
-+ rc = wait_for_completion_timeout(p, cmd_timeout);
-+ if (!rc)
-+ dev_err(host->dev, "erase command timeout\n");
-+ break;
-+ case NAND_CMD_SEQIN:
-+ mtk_nfi_writew(host, CNFG_OP_PRGM, MTKSDG1_NFI_CNFG);
-+ mtk_nfc_set_command(host, NAND_CMD_SEQIN);
-+ mtk_nfc_set_address(host, column, page_addr, 2, host->row_nob);
-+ break;
-+ case NAND_CMD_PAGEPROG:
-+ case NAND_CMD_CACHEDPROG:
-+ mtk_nfi_writew(host, INTR_BUSY_RT_EN, MTKSDG1_NFI_INTR_EN);
-+ init_completion(p);
-+ mtk_nfc_set_command(host, command);
-+ rc = wait_for_completion_timeout(p, cmd_timeout);
-+ if (!rc)
-+ dev_err(host->dev, "pageprogr command timeout\n");
-+ break;
-+ case NAND_CMD_READ0:
-+ val = CNFG_OP_READ | CNFG_READ_EN;
-+ mtk_nfi_writew(host, val, MTKSDG1_NFI_CNFG);
-+ mtk_nfc_set_command(host, NAND_CMD_READ0);
-+ break;
-+ default:
-+ dev_warn(host->dev, "command 0x%x not supported\n", command);
-+ break;
-+ }
-+}
-+
-+static uint8_t mtk_nfc_read_byte(struct mtd_info *mtd)
-+{
-+ struct nand_chip *chip = mtd_to_nand(mtd);
-+ struct mtk_nfc_host *host = nand_get_controller_data(chip);
-+ int rc;
-+
-+ rc = mtk_nfc_data_ready(host);
-+ if (rc < 0) {
-+ dev_err(host->dev, "data not ready\n");
-+ return NAND_STATUS_FAIL;
-+ }
-+
-+ return mtk_nfi_readb(host, MTKSDG1_NFI_DATAR);
-+}
-+
-+static void mtk_nfc_write_fdm(struct nand_chip *chip, u32 sectors)
-+{
-+ struct mtk_nfc_host *host = nand_get_controller_data(chip);
-+ u8 *src, *dst;
-+ int i, j, reg;
-+
-+ for (i = 0; i < sectors ; i++) {
-+ /* read FDM from OOB into private area */
-+ src = chip->oob_poi + i * MTKSDG1_NFI_FDM_REG_SIZE;
-+ dst = (u8 *)host->fdm_reg;
-+ memcpy(dst, src, MTKSDG1_NFI_FDM_REG_SIZE);
-+
-+ /* write FDM to registers */
-+ for (j = 0; j < ARRAY_SIZE(host->fdm_reg); j++) {
-+ reg = MTKSDG1_NFI_FDM0L + i * MTKSDG1_NFI_FDM_REG_SIZE;
-+ reg += j * sizeof(host->fdm_reg[0]);
-+ mtk_nfi_writel(host, host->fdm_reg[j], reg);
-+ }
-+ }
-+}
-+
-+static int mtk_nfc_write_page(struct mtd_info *mtd,
-+ struct nand_chip *chip, const uint8_t *buf,
-+ int oob_on, int page, int raw)
-+{
-+
-+ struct mtk_nfc_host *host = nand_get_controller_data(chip);
-+ struct completion *nfi = &host->nfi.complete;
-+ struct device *dev = host->dev;
-+ const bool use_ecc = !raw;
-+ void *q = (void *) buf;
-+ dma_addr_t dma_addr;
-+ size_t dmasize;
-+ u32 reg;
-+ int ret;
-+
-+ dmasize = mtd->writesize + (raw ? mtd->oobsize : 0);
-+
-+ dma_addr = dma_map_single(dev, q, dmasize, DMA_TO_DEVICE);
-+ if (dma_mapping_error(host->dev, dma_addr)) {
-+ dev_err(host->dev, "dma mapping error\n");
-+ return -EINVAL;
-+ }
-+
-+ reg = mtk_nfi_readw(host, MTKSDG1_NFI_CNFG);
-+ reg |= CNFG_AHB | CNFG_DMA_BURST_EN;
-+ if (use_ecc) {
-+ /**
-+ * OOB will be generated
-+ * - FDM: from register
-+ * - ECC: from HW
-+ */
-+ reg |= CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN;
-+ mtk_nfi_writew(host, reg, MTKSDG1_NFI_CNFG);
-+
-+ mtk_ecc_encoder_idle(host);
-+ mtk_ecc_writew(host, ENC_EN, MTKSDG1_ECC_ENCCON);
-+
-+ /* write OOB into the FDM registers (OOB area in MTK NAND) */
-+ if (oob_on)
-+ mtk_nfc_write_fdm(chip, chip->ecc.steps);
-+ } else {
-+ /* OOB is part of the DMA transfer */
-+ mtk_nfi_writew(host, reg, MTKSDG1_NFI_CNFG);
-+ }
-+
-+ mtk_nfi_writel(host, chip->ecc.steps << CON_SEC_SHIFT, MTKSDG1_NFI_CON);
-+ mtk_nfi_writel(host, lower_32_bits(dma_addr), MTKSDG1_NFI_STRADDR);
-+ mtk_nfi_writew(host, INTR_AHB_DONE_EN, MTKSDG1_NFI_INTR_EN);
-+
-+ init_completion(nfi);
-+
-+ /* start DMA */
-+ reg = mtk_nfi_readl(host, MTKSDG1_NFI_CON) | CON_BWR;
-+ mtk_nfi_writel(host, reg, MTKSDG1_NFI_CON);
-+
-+ ret = wait_for_completion_timeout(nfi, msecs_to_jiffies(MTK_TIMEOUT));
-+ if (!ret) {
-+ dev_err(dev, "program ahb done timeout\n");
-+ mtk_nfi_writew(host, 0, MTKSDG1_NFI_INTR_EN);
-+ ret = -ETIMEDOUT;
-+ goto timeout;
-+ }
-+
-+ ret = mtk_nfc_transfer_done(host, chip->ecc.steps);
-+ if (ret < 0)
-+ dev_err(dev, "hwecc write timeout\n");
-+timeout:
-+ dma_unmap_single(host->dev, dma_addr, dmasize, DMA_TO_DEVICE);
-+
-+ if (use_ecc) {
-+ mtk_ecc_encoder_idle(host);
-+ mtk_ecc_writew(host, ENC_DE, MTKSDG1_ECC_ENCCON);
-+ }
-+
-+ mtk_nfi_writel(host, 0, MTKSDG1_NFI_CON);
-+
-+ return ret;
-+}
-+
-+static int mtk_nfc_write_page_hwecc(struct mtd_info *mtd,
-+ struct nand_chip *chip, const uint8_t *buf,
-+ int oob_on, int page)
-+{
-+ return mtk_nfc_write_page(mtd, chip, buf, oob_on, page, MTK_ECC_ON);
-+}
-+
-+static int mtk_nfc_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-+ const uint8_t *buf, int oob_on, int pg)
-+{
-+ struct mtk_nfc_host *host = nand_get_controller_data(chip);
-+ uint8_t *src, *dst;
-+ size_t len;
-+ u32 i;
-+
-+ memset(host->buffer, 0xff, mtd->writesize + mtd->oobsize);
-+
-+ /* MTK internal 4KB page data layout:
-+ * ----------------------------------
-+ * PAGE = 4KB, SECTOR = 1KB, OOB=128B
-+ * page = sector_oob1 + sector_oob2 + sector_oob3 + sector_oob4
-+ * sector_oob = data (1KB) + FDM (8B) + ECC parity (21B) + free (3B)
-+ *
-+ */
-+ len = SECTOR_SIZE + mtd->oobsize / chip->ecc.steps;
-+
-+ for (i = 0; i < chip->ecc.steps; i++) {
-+
-+ if (buf) {
-+ src = (uint8_t *) buf + i * SECTOR_SIZE;
-+ dst = host->buffer + i * len;
-+ memcpy(dst, src, SECTOR_SIZE);
-+ }
-+
-+ if (oob_on) {
-+ src = chip->oob_poi + i * MTKSDG1_NFI_FDM_REG_SIZE;
-+ dst = host->buffer + i * len + SECTOR_SIZE;
-+ memcpy(dst, src, MTKSDG1_NFI_FDM_REG_SIZE);
-+ }
-+ }
-+
-+ return mtk_nfc_write_page(mtd, chip, host->buffer, MTK_OOB_OFF, pg,
-+ MTK_ECC_OFF);
-+}
-+
-+static int mtk_nfc_sector_encode(struct nand_chip *chip, u8 *data)
-+{
-+ struct mtk_nfc_host *host = nand_get_controller_data(chip);
-+ struct completion *ecc = &host->ecc.complete;
-+ u32 reg, parity_bytes, i;
-+ dma_addr_t dma_addr;
-+ u32 *parity_region;
-+ int rc, ret = 0;
-+ size_t dmasize;
-+
-+ dmasize = SECTOR_SIZE + MTKSDG1_NFI_FDM_REG_SIZE;
-+ dma_addr = dma_map_single(host->dev, data, dmasize, DMA_TO_DEVICE);
-+ if (dma_mapping_error(host->dev, dma_addr)) {
-+ dev_err(host->dev, "dma mapping error\n");
-+ return -EINVAL;
-+ }
-+
-+ /* enable the encoder in DMA mode to calculate the ECC bytes */
-+ reg = mtk_ecc_readl(host, MTKSDG1_ECC_ENCCNFG);
-+ reg &= (~ECC_ENC_MODE_MASK);
-+ reg |= ECC_DMA_MODE;
-+ mtk_ecc_writel(host, reg, MTKSDG1_ECC_ENCCNFG);
-+
-+ mtk_ecc_writel(host, ENC_IRQEN, MTKSDG1_ECC_ENCIRQ_EN);
-+ mtk_ecc_writel(host, lower_32_bits(dma_addr), MTKSDG1_ECC_ENCDIADDR);
-+
-+ init_completion(ecc);
-+ mtk_ecc_writew(host, ENC_EN, MTKSDG1_ECC_ENCCON);
-+
-+ rc = wait_for_completion_timeout(ecc, msecs_to_jiffies(MTK_TIMEOUT));
-+ if (!rc) {
-+ dev_err(host->dev, "ecc encode done timeout\n");
-+ mtk_ecc_writel(host, 0, MTKSDG1_ECC_ENCIRQ_EN);
-+ ret = -ETIMEDOUT;
-+ goto timeout;
-+ }
-+
-+ mtk_ecc_encoder_idle(host);
-+
-+ /**
-+ * Program ECC bytes to OOB
-+ * per sector oob = FDM + ECC + SPARE
-+ */
-+
-+ parity_region = (u32 *) (data + SECTOR_SIZE + MTKSDG1_NFI_FDM_REG_SIZE);
-+ parity_bytes = (chip->ecc.strength * MTK_ECC_PARITY_BITS + 7) >> 3;
-+
-+ /* write the parity bytes generated by the ECC back to the OOB region */
-+ for (i = 0; i < parity_bytes; i += sizeof(u32))
-+ *parity_region++ = mtk_ecc_readl(host, MTKSDG1_ECC_ENCPAR0 + i);
-+
-+timeout:
-+
-+ dma_unmap_single(host->dev, dma_addr, dmasize, DMA_TO_DEVICE);
-+
-+ mtk_ecc_writew(host, 0, MTKSDG1_ECC_ENCCON);
-+ reg = mtk_ecc_readl(host, MTKSDG1_ECC_ENCCNFG);
-+ reg &= (~ECC_ENC_MODE_MASK);
-+ reg |= ECC_NFI_MODE;
-+ mtk_ecc_writel(host, reg, MTKSDG1_ECC_ENCCNFG);
-+
-+ return ret;
-+}
-+
-+static int mtk_nfc_write_subpage_hwecc(struct mtd_info *mtd,
-+ struct nand_chip *chip, uint32_t offset, uint32_t data_len,
-+ const uint8_t *buf, int oob_on, int pg)
-+{
-+ struct mtk_nfc_host *host = nand_get_controller_data(chip);
-+ uint8_t *src, *dst;
-+ u32 start, end;
-+ size_t len;
-+ int i, ret;
-+
-+ start = BYTES_TO_SECTORS(offset);
-+ end = BYTES_TO_SECTORS(offset + data_len + SECTOR_SIZE - 1);
-+
-+ len = SECTOR_SIZE + mtd->oobsize / chip->ecc.steps;
-+
-+ memset(host->buffer, 0xff, mtd->writesize + mtd->oobsize);
-+ for (i = 0; i < chip->ecc.steps; i++) {
-+
-+ /* write data */
-+ src = (uint8_t *) buf + i * SECTOR_SIZE;
-+ dst = host->buffer + i * len;
-+ memcpy(dst, src, SECTOR_SIZE);
-+
-+ if (i < start)
-+ continue;
-+
-+ if (i >= end)
-+ continue;
-+
-+ /* write fdm */
-+ if (oob_on) {
-+ src = chip->oob_poi + i * MTKSDG1_NFI_FDM_REG_SIZE;
-+ dst = host->buffer + i * len + SECTOR_SIZE;
-+ memcpy(dst, src, MTKSDG1_NFI_FDM_REG_SIZE);
-+ }
-+
-+ /* point to the start of data */
-+ src = host->buffer + i * len;
-+
-+ /* program the CRC back to the OOB */
-+ ret = mtk_nfc_sector_encode(chip, src);
-+ if (ret < 0)
-+ return ret;
-+ }
-+
-+ /* use the data in the private buffer (now with FDM and CRC) to perform
-+ * a raw write
-+ */
-+ src = host->buffer;
-+ return mtk_nfc_write_page(mtd, chip, src, MTK_OOB_OFF, pg, MTK_ECC_OFF);
-+}
-+
-+static int mtk_nfc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
-+ int page)
-+{
-+ u8 *buf = chip->buffers->databuf;
-+ int ret;
-+
-+ memset(buf, 0xff, mtd->writesize);
-+ chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
-+ ret = mtk_nfc_write_page_hwecc(mtd, chip, buf, MTK_OOB_ON, page);
-+ if (ret < 0)
-+ return -EIO;
-+
-+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
-+ ret = chip->waitfunc(mtd, chip);
-+
-+ return ret & NAND_STATUS_FAIL ? -EIO : 0;
-+}
-+
-+static int mtk_nfc_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
-+ int page)
-+{
-+ int ret;
-+
-+ chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
-+ ret = mtk_nfc_write_page_raw(mtd, chip, NULL, MTK_OOB_ON, page);
-+ if (ret < 0)
-+ return -EIO;
-+
-+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
-+ ret = chip->waitfunc(mtd, chip);
-+
-+ return ret & NAND_STATUS_FAIL ? -EIO : 0;
-+}
-+
-+static int mtk_nfc_ecc_check(struct mtd_info *mtd, struct nand_chip *chip,
-+ u32 sectors)
-+{
-+ struct mtk_nfc_host *host = nand_get_controller_data(chip);
-+ u32 offset, i, err, max_bitflip;
-+
-+ max_bitflip = 0;
-+
-+ for (i = 0; i < sectors; i++) {
-+ offset = (i >> 2) << 2;
-+ err = mtk_ecc_readl(host, MTKSDG1_ECC_DECENUM0 + offset);
-+ err = err >> ((i % 4) * 8);
-+ err &= ERR_MASK;
-+ if (err == ERR_MASK) {
-+ /* uncorrectable errors */
-+ mtd->ecc_stats.failed++;
-+ continue;
-+ }
-+
-+ mtd->ecc_stats.corrected += err;
-+ max_bitflip = max_t(u32, max_bitflip, err);
-+ }
-+
-+ return max_bitflip;
-+}
-+
-+static void mtk_nfc_read_fdm(struct nand_chip *chip, u32 sectors)
-+{
-+ struct mtk_nfc_host *host = nand_get_controller_data(chip);
-+ int i, j, reg;
-+ u8 *dst, *src;
-+
-+ for (i = 0; i < sectors; i++) {
-+ /* read FDM register into host memory */
-+ for (j = 0; j < ARRAY_SIZE(host->fdm_reg); j++) {
-+ reg = MTKSDG1_NFI_FDM0L + i * MTKSDG1_NFI_FDM_REG_SIZE;
-+ reg += j * sizeof(host->fdm_reg[0]);
-+ host->fdm_reg[j] = mtk_nfi_readl(host, reg);
-+ }
-+
-+ /* copy FDM register from host to OOB */
-+ src = (u8 *)host->fdm_reg;
-+ dst = chip->oob_poi + i * MTKSDG1_NFI_FDM_REG_SIZE;
-+ memcpy(dst, src, MTKSDG1_NFI_FDM_REG_SIZE);
-+ }
-+}
-+
-+static int mtk_nfc_update_oob(struct mtd_info *mtd, struct nand_chip *chip,
-+ u8 *buf, u32 sectors)
-+{
-+ struct mtk_nfc_host *host = nand_get_controller_data(chip);
-+ int i, bitflips = 0;
-+
-+ /* if the page is empty, no bitflips and clear data and oob */
-+ if (mtk_nfi_readl(host, MTKSDG1_NFI_STA) & STA_EMP_PAGE) {
-+ memset(buf, 0xff, SECTORS_TO_BYTES(sectors));
-+
-+ /* empty page: update OOB with 0xFF */
-+ for (i = 0; i < sectors; i++) {
-+ memset(chip->oob_poi + i * MTKSDG1_NFI_FDM_REG_SIZE,
-+ 0xff, MTKSDG1_NFI_FDM_REG_SIZE);
-+ }
-+ } else {
-+ /* update OOB with HW info */
-+ mtk_nfc_read_fdm(chip, sectors);
-+
-+ /* return the bitflips */
-+ bitflips = mtk_nfc_ecc_check(mtd, chip, sectors);
-+ }
-+
-+ return bitflips;
-+}
-+
-+static int mtk_nfc_block_markbad(struct mtd_info *mtd, loff_t ofs)
-+{
-+ struct nand_chip *chip = mtd_to_nand(mtd);
-+ u8 *buf = chip->buffers->databuf;
-+ int rc, i, pg;
-+
-+ /* block_markbad writes 0x00 at data and OOB */
-+ memset(buf, 0x00, mtd->writesize + mtd->oobsize);
-+
-+ /* Write to first/last page(s) if necessary */
-+ if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
-+ ofs += mtd->erasesize - mtd->writesize;
-+
-+ i = 0;
-+ do {
-+ pg = (int)(ofs >> chip->page_shift);
-+
-+ /**
-+ * write 0x00 to DATA & OOB in flash
-+ * No need to reorganize the page since it is all 0x00
-+ */
-+ chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, pg);
-+ rc = mtk_nfc_write_page(mtd, chip, buf, MTK_OOB_OFF, pg,
-+ MTK_ECC_OFF);
-+ if (rc < 0)
-+ return rc;
-+
-+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
-+ rc = chip->waitfunc(mtd, chip);
-+ rc = rc & NAND_STATUS_FAIL ? -EIO : 0;
-+ if (rc < 0)
-+ return rc;
-+
-+ ofs += mtd->writesize;
-+ i++;
-+
-+ } while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);
-+
-+ return 0;
-+}
-+
-+static int mtk_nfc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
-+ uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi,
-+ int page, int raw)
-+{
-+ struct mtk_nfc_host *host = nand_get_controller_data(chip);
-+ unsigned long timeout = msecs_to_jiffies(MTK_TIMEOUT);
-+ u32 reg, column, spare, sectors, start, end;
-+ struct completion *nfi, *ecc;
-+ const bool use_ecc = !raw;
-+ int bitflips = -EIO;
-+ dma_addr_t dma_addr;
-+ size_t len;
-+ u8 *buf;
-+ int rc;
-+
-+ nfi = &host->nfi.complete;
-+ ecc = &host->ecc.complete;
-+
-+ start = BYTES_TO_SECTORS(data_offs);
-+ end = BYTES_TO_SECTORS(data_offs + readlen + SECTOR_SIZE - 1);
-+ sectors = end - start;
-+
-+ spare = mtd->oobsize / chip->ecc.steps;
-+ column = start * (SECTOR_SIZE + spare);
-+
-+ len = SECTORS_TO_BYTES(sectors) + (raw ? sectors * spare : 0);
-+ buf = bufpoi + SECTORS_TO_BYTES(start);
-+
-+ /* map the device memory */
-+ dma_addr = dma_map_single(host->dev, buf, len, DMA_FROM_DEVICE);
-+ if (dma_mapping_error(host->dev, dma_addr)) {
-+ dev_err(host->dev, "dma mapping error\n");
-+ return -EINVAL;
-+ }
-+
-+ /* configure the transfer */
-+ reg = mtk_nfi_readw(host, MTKSDG1_NFI_CNFG);
-+ reg |= CNFG_DMA_BURST_EN | CNFG_AHB;
-+ if (use_ecc) {
-+ reg |= CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN;
-+ mtk_nfi_writew(host, reg, MTKSDG1_NFI_CNFG);
-+
-+ /* enable encoder */
-+ mtk_ecc_decoder_idle(host);
-+ mtk_ecc_writel(host, DEC_EN, MTKSDG1_ECC_DECCON);
-+ } else
-+ mtk_nfi_writew(host, reg, MTKSDG1_NFI_CNFG);
-+
-+ mtk_nfi_writel(host, sectors << CON_SEC_SHIFT, MTKSDG1_NFI_CON);
-+ mtk_nfi_writew(host, INTR_BUSY_RT_EN, MTKSDG1_NFI_INTR_EN);
-+
-+ init_completion(nfi);
-+
-+ mtk_nfc_set_address(host, column, page, 2, host->row_nob);
-+ mtk_nfc_set_command(host, NAND_CMD_READSTART);
-+ rc = wait_for_completion_timeout(nfi, timeout);
-+ if (!rc) {
-+ dev_err(host->dev, "read busy return timeout\n");
-+ goto error;
-+ }
-+
-+ mtk_nfi_writew(host, INTR_AHB_DONE_EN, MTKSDG1_NFI_INTR_EN);
-+ mtk_nfi_writel(host, lower_32_bits(dma_addr), MTKSDG1_NFI_STRADDR);
-+
-+ if (use_ecc) {
-+ /* program ECC with sector count */
-+ host->ecc.dec_sec = sectors;
-+ init_completion(ecc);
-+ mtk_ecc_writew(host, DEC_IRQEN, MTKSDG1_ECC_DECIRQ_EN);
-+ }
-+
-+ init_completion(nfi);
-+
-+ /* start DMA */
-+ reg = mtk_nfi_readl(host, MTKSDG1_NFI_CON) | CON_BRD;
-+ mtk_nfi_writel(host, reg, MTKSDG1_NFI_CON);
-+
-+ rc = wait_for_completion_timeout(nfi, timeout);
-+ if (!rc)
-+ dev_warn(host->dev, "read ahb/dma done timeout\n");
-+
-+ /* DMA interrupt didn't trigger, check page done just in case */
-+ rc = mtk_nfc_subpage_done(host, sectors);
-+ if (rc < 0) {
-+ dev_err(host->dev, "subpage done timeout\n");
-+ goto error;
-+ }
-+
-+ /* raw transfer successful */
-+ bitflips = 0;
-+
-+ if (use_ecc) {
-+ rc = wait_for_completion_timeout(ecc, timeout);
-+ if (!rc) {
-+ dev_err(host->dev, "ecc decode timeout\n");
-+ host->ecc.dec_sec = 0;
-+ bitflips = -ETIMEDOUT;
-+ goto error;
-+ }
-+ bitflips = mtk_nfc_update_oob(mtd, chip, buf, sectors);
-+ }
-+
-+error:
-+ dma_unmap_single(host->dev, dma_addr, len, DMA_FROM_DEVICE);
-+
-+ if (use_ecc) {
-+ /* make sure the ECC dec irq is disabled */
-+ mtk_ecc_writew(host, 0, MTKSDG1_ECC_DECIRQ_EN);
-+ mtk_ecc_decoder_idle(host);
-+
-+ /* disable ECC dec */
-+ mtk_ecc_writew(host, 0, MTKSDG1_ECC_DECCON);
-+ }
-+
-+ mtk_nfi_writel(host, 0, MTKSDG1_NFI_CON);
-+
-+ return bitflips;
-+}
-+
-+static int mtk_nfc_read_subpage_hwecc(struct mtd_info *mtd,
-+ struct nand_chip *chip, uint32_t data_offs,
-+ uint32_t readlen, uint8_t *bufpoi, int page)
-+{
-+ return mtk_nfc_read_subpage(mtd, chip, data_offs, readlen,
-+ bufpoi, page, MTK_ECC_ON);
-+}
-+
-+static int mtk_nfc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
-+ uint8_t *buf, int oob_on, int page)
-+{
-+ return mtk_nfc_read_subpage_hwecc(mtd, chip, 0, mtd->writesize,
-+ buf, page);
-+}
-+
-+static int mtk_nfc_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-+ uint8_t *buf, int oob_on, int page)
-+{
-+ struct mtk_nfc_host *host = nand_get_controller_data(chip);
-+ uint8_t *src, *dst;
-+ int i, ret;
-+ size_t len;
-+
-+ dst = host->buffer;
-+ memset(dst, 0xff, mtd->writesize + mtd->oobsize);
-+ ret = mtk_nfc_read_subpage(mtd, chip, 0, mtd->writesize, dst, page, 1);
-+ if (ret < 0)
-+ return ret;
-+
-+ len = SECTOR_SIZE + mtd->oobsize / chip->ecc.steps;
-+
-+ /* copy to the output buffer */
-+ for (i = 0; i < chip->ecc.steps; i++) {
-+
-+ /* copy sector data */
-+ if (buf) {
-+ src = host->buffer + i * len;
-+ dst = buf + i * SECTOR_SIZE;
-+ memcpy(dst, src, SECTOR_SIZE);
-+ }
-+
-+ /* copy FDM data to OOB */
-+ if (oob_on) {
-+ src = host->buffer + i * len + SECTOR_SIZE;
-+ dst = chip->oob_poi + i * MTKSDG1_NFI_FDM_REG_SIZE;
-+ memcpy(dst, src, MTKSDG1_NFI_FDM_REG_SIZE);
-+ }
-+ }
-+
-+ return ret;
-+}
-+
-+static void mtk_nfc_switch_oob(struct mtd_info *mtd, struct nand_chip *chip,
-+ uint8_t *buf)
-+{
-+ struct mtk_nfc_host *host = nand_get_controller_data(chip);
-+ size_t spare;
-+ u32 sectors;
-+ u8 *bufpoi;
-+ int len;
-+
-+ spare = mtd->oobsize / chip->ecc.steps;
-+ sectors = mtd->writesize / (SECTOR_SIZE + spare);
-+
-+ /**
-+ * MTK: DATA+oob1, DATA+oob2, DATA+oob3 ...
-+ * LNX: DATA+OOB
-+ */
-+ /* point to the last oob_i from the NAND device*/
-+ bufpoi = buf + mtd->writesize - (sectors * spare);
-+ len = sizeof(host->fdm_reg);
-+
-+ /* copy NAND oob to private area */
-+ memcpy(host->fdm_reg, bufpoi, len);
-+
-+ /* copy oob_poi to NAND */
-+ memcpy(bufpoi, chip->oob_poi, len);
-+
-+ /* copy NAND oob to oob_poi */
-+ memcpy(chip->oob_poi, host->fdm_reg, sizeof(host->fdm_reg));
-+ memset(host->fdm_reg, 0x00, len);
-+}
-+
-+static int mtk_nfc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
-+ int page)
-+{
-+ struct mtk_nfc_host *host = nand_get_controller_data(chip);
-+ u8 *buf = chip->buffers->databuf;
-+ struct mtd_ecc_stats stats;
-+ int ret;
-+
-+ stats = mtd->ecc_stats;
-+
-+ memset(buf, 0xff, mtd->writesize);
-+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
-+
-+ ret = mtk_nfc_read_page_hwecc(mtd, chip, buf, 1, page);
-+
-+ if (host->switch_oob)
-+ mtk_nfc_switch_oob(mtd, chip, buf);
-+
-+ if (ret < mtd->bitflip_threshold)
-+ mtd->ecc_stats.corrected = stats.corrected;
-+
-+ return ret;
-+}
-+
-+static int mtk_nfc_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
-+ int page)
-+{
-+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
-+
-+ return mtk_nfc_read_page_raw(mtd, chip, NULL, MTK_OOB_ON, page);
-+}
-+
-+static inline void mtk_nfc_hw_init(struct mtk_nfc_host *host)
-+{
-+ mtk_nfi_writel(host, 0x10804211, MTKSDG1_NFI_ACCCON);
-+ mtk_nfi_writew(host, 0xf1, MTKSDG1_NFI_CNRNB);
-+ mtk_nfc_hw_reset(host);
-+
-+ /* clear interrupt */
-+ mtk_nfi_readl(host, MTKSDG1_NFI_INTR_STA);
-+ mtk_nfi_writel(host, 0, MTKSDG1_NFI_INTR_EN);
-+
-+ /* ECC encoder init */
-+ mtk_ecc_encoder_idle(host);
-+ mtk_ecc_writew(host, ENC_DE, MTKSDG1_ECC_ENCCON);
-+
-+ /* ECC decoder init */
-+ mtk_ecc_decoder_idle(host);
-+ mtk_ecc_writel(host, DEC_DE, MTKSDG1_ECC_DECCON);
-+}
-+
-+static irqreturn_t mtk_nfi_irq(int irq, void *devid)
-+{
-+ struct mtk_nfc_host *host = devid;
-+ u16 sta, ien;
-+
-+ sta = mtk_nfi_readw(host, MTKSDG1_NFI_INTR_STA);
-+ ien = mtk_nfi_readw(host, MTKSDG1_NFI_INTR_EN);
-+
-+ if (!(sta & ien))
-+ return IRQ_NONE;
-+
-+ mtk_nfi_writew(host, ~sta & ien, MTKSDG1_NFI_INTR_EN);
-+ complete(&host->nfi.complete);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static irqreturn_t mtk_ecc_irq(int irq, void *devid)
-+{
-+ struct mtk_nfc_host *host = devid;
-+ u32 reg_val, mask;
-+
-+ reg_val = mtk_ecc_readw(host, MTKSDG1_ECC_DECIRQ_STA);
-+ if (reg_val & DEC_IRQEN) {
-+ if (host->ecc.dec_sec) {
-+ mask = 1 << (host->ecc.dec_sec - 1);
-+ reg_val = mtk_ecc_readw(host, MTKSDG1_ECC_DECDONE);
-+ if (mask & reg_val) {
-+ host->ecc.dec_sec = 0;
-+ complete(&host->ecc.complete);
-+ mtk_ecc_writew(host, 0, MTKSDG1_ECC_DECIRQ_EN);
-+ }
-+ } else
-+ dev_warn(host->dev, "spurious DEC_IRQ\n");
-+
-+ return IRQ_HANDLED;
-+ }
-+
-+ reg_val = mtk_ecc_readl(host, MTKSDG1_ECC_ENCIRQ_STA);
-+ if (reg_val & ENC_IRQEN) {
-+ complete(&host->ecc.complete);
-+ mtk_ecc_writel(host, 0, MTKSDG1_ECC_ENCIRQ_EN);
-+
-+ return IRQ_HANDLED;
-+ }
-+
-+ return IRQ_NONE;
-+}
-+
-+static int mtk_nfc_enable_clk(struct device *dev, struct mtk_nfc_clk *clk)
-+{
-+ int ret;
-+
-+ ret = clk_prepare_enable(clk->nfi_clk);
-+ if (ret) {
-+ dev_err(dev, "failed to enable nfi clk\n");
-+ return ret;
-+ }
-+
-+ ret = clk_prepare_enable(clk->nfiecc_clk);
-+ if (ret) {
-+ dev_err(dev, "failed to enable nfiecc clk\n");
-+ goto out_nfiecc_clk_disable;
-+ }
-+
-+ ret = clk_prepare_enable(clk->pad_clk);
-+ if (ret) {
-+ dev_err(dev, "failed to enable pad clk\n");
-+ goto out_pad_clk_disable;
-+ }
-+
-+ return 0;
-+
-+out_pad_clk_disable:
-+ clk_disable_unprepare(clk->nfiecc_clk);
-+
-+out_nfiecc_clk_disable:
-+ clk_disable_unprepare(clk->nfi_clk);
-+
-+ return ret;
-+}
-+
-+static void mtk_nfc_disable_clk(struct mtk_nfc_clk *clk)
-+{
-+ clk_disable_unprepare(clk->nfi_clk);
-+ clk_disable_unprepare(clk->nfiecc_clk);
-+ clk_disable_unprepare(clk->pad_clk);
-+}
-+
-+static int mtk_nfc_probe(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ struct device_node *np = dev->of_node;
-+ struct mtk_nfc_host *host;
-+ struct nand_chip *chip;
-+ struct mtd_info *mtd;
-+ struct resource *res;
-+ int ret, irq;
-+ size_t len;
-+
-+ host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
-+ if (!host)
-+ return -ENOMEM;
-+
-+ chip = &host->chip;
-+ mtd = nand_to_mtd(chip);
-+ host->dev = dev;
-+
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ host->nfi.base = devm_ioremap_resource(dev, res);
-+ if (IS_ERR(host->nfi.base)) {
-+ ret = PTR_ERR(host->nfi.base);
-+ dev_err(dev, "no nfi base\n");
-+ return ret;
-+ }
-+
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-+ host->ecc.base = devm_ioremap_resource(dev, res);
-+ if (IS_ERR(host->ecc.base)) {
-+ ret = PTR_ERR(host->ecc.base);
-+ dev_err(dev, "no ecc base\n");
-+ return ret;
-+ }
-+
-+ host->clk.nfi_clk = devm_clk_get(dev, "nfi_clk");
-+ if (IS_ERR(host->clk.nfi_clk)) {
-+ dev_err(dev, "no clk\n");
-+ ret = PTR_ERR(host->clk.nfi_clk);
-+ return ret;
-+ }
-+
-+ host->clk.nfiecc_clk = devm_clk_get(dev, "nfiecc_clk");
-+ if (IS_ERR(host->clk.nfiecc_clk)) {
-+ dev_err(dev, "no ecc clk\n");
-+ ret = PTR_ERR(host->clk.nfiecc_clk);
-+ return ret;
-+ }
-+
-+ host->clk.pad_clk = devm_clk_get(dev, "pad_clk");
-+ if (IS_ERR(host->clk.pad_clk)) {
-+ dev_err(dev, "no pad clk\n");
-+ ret = PTR_ERR(host->clk.pad_clk);
-+ return ret;
-+ }
-+
-+ ret = mtk_nfc_enable_clk(dev, &host->clk);
-+ if (ret)
-+ return ret;
-+
-+ irq = platform_get_irq(pdev, 0);
-+ if (irq < 0) {
-+ dev_err(dev, "no nfi irq resource\n");
-+ ret = -EINVAL;
-+ goto clk_disable;
-+ }
-+
-+ ret = devm_request_irq(dev, irq, mtk_nfi_irq, 0x0, MTK_IRQ_NFI, host);
-+ if (ret) {
-+ dev_err(dev, "failed to request nfi irq\n");
-+ goto clk_disable;
-+ }
-+
-+ irq = platform_get_irq(pdev, 1);
-+ if (irq < 0) {
-+ dev_err(dev, "no ecc irq resource\n");
-+ ret = -EINVAL;
-+ goto clk_disable;
-+ }
-+
-+ ret = devm_request_irq(dev, irq, mtk_ecc_irq, 0x0, MTK_IRQ_ECC, host);
-+ if (ret) {
-+ dev_err(dev, "failed to request ecc irq\n");
-+ goto clk_disable;
-+ }
-+
-+ ret = dma_set_mask(dev, DMA_BIT_MASK(32));
-+ if (ret) {
-+ dev_err(dev, "failed to set dma mask\n");
-+ goto clk_disable;
-+ }
-+
-+ platform_set_drvdata(pdev, host);
-+
-+ mtd_set_of_node(mtd, np);
-+ mtd->owner = THIS_MODULE;
-+ mtd->dev.parent = dev;
-+ mtd->name = MTK_NAME;
-+
-+ nand_set_controller_data(chip, host);
-+ chip->options |= NAND_USE_BOUNCE_BUFFER | NAND_SUBPAGE_READ;
-+ chip->block_markbad = mtk_nfc_block_markbad;
-+ chip->select_chip = mtk_nfc_select_chip;
-+ chip->read_byte = mtk_nfc_read_byte;
-+ chip->cmdfunc = mtk_nfc_cmdfunc;
-+ chip->ecc.mode = NAND_ECC_HW;
-+ chip->ecc.write_subpage = mtk_nfc_write_subpage_hwecc;
-+ chip->ecc.write_page_raw = mtk_nfc_write_page_raw;
-+ chip->ecc.write_page = mtk_nfc_write_page_hwecc;
-+ chip->ecc.write_oob_raw = mtk_nfc_write_oob_raw;
-+ chip->ecc.write_oob = mtk_nfc_write_oob;
-+ chip->ecc.read_subpage = mtk_nfc_read_subpage_hwecc;
-+ chip->ecc.read_page_raw = mtk_nfc_read_page_raw;
-+ chip->ecc.read_oob_raw = mtk_nfc_read_oob_raw;
-+ chip->ecc.read_page = mtk_nfc_read_page_hwecc;
-+ chip->ecc.read_oob = mtk_nfc_read_oob;
-+
-+ mtk_nfc_hw_init(host);
-+
-+ ret = nand_scan_ident(mtd, MTK_NAND_MAX_CHIP, NULL);
-+ if (ret) {
-+ ret = -ENODEV;
-+ goto clk_disable;
-+ }
-+
-+ ret = mtk_nfc_hw_runtime_config(mtd);
-+ if (ret < 0) {
-+ dev_err(dev, "nand device not supported\n");
-+ goto clk_disable;
-+ }
-+
-+ len = mtd->writesize + mtd->oobsize;
-+ host->buffer = devm_kzalloc(dev, len, GFP_KERNEL);
-+ if (!host->buffer) {
-+ ret = -ENOMEM;
-+ goto clk_disable;
-+ }
-+
-+ /* required to create bbt table if not present */
-+ host->switch_oob = true;
-+ ret = nand_scan_tail(mtd);
-+ if (ret) {
-+ ret = -ENODEV;
-+ goto clk_disable;
-+ }
-+ host->switch_oob = false;
-+
-+ ret = mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
-+ if (ret) {
-+ dev_err(dev, "mtd parse partition error\n");
-+ goto nand_free;
-+ }
-+
-+ return 0;
-+
-+nand_free:
-+ nand_release(mtd);
-+
-+clk_disable:
-+ mtk_nfc_disable_clk(&host->clk);
-+
-+ return ret;
-+}
-+
-+static int mtk_nfc_remove(struct platform_device *pdev)
-+{
-+ struct mtk_nfc_host *host = platform_get_drvdata(pdev);
-+ struct mtd_info *mtd = nand_to_mtd(&host->chip);
-+
-+ nand_release(mtd);
-+ mtk_nfc_disable_clk(&host->clk);
-+
-+ return 0;
-+}
-+
-+#ifdef CONFIG_PM_SLEEP
-+static int mtk_nfc_suspend(struct device *dev)
-+{
-+ struct mtk_nfc_host *host = dev_get_drvdata(dev);
-+ struct mtk_nfc_saved_reg *reg = &host->saved_reg;
-+
-+ reg->nfi.emp_thresh = mtk_nfi_readl(host, MTKSDG1_NFI_EMPTY_THRESH);
-+ reg->ecc.enccnfg = mtk_ecc_readl(host, MTKSDG1_ECC_ENCCNFG);
-+ reg->ecc.deccnfg = mtk_ecc_readl(host, MTKSDG1_ECC_DECCNFG);
-+ reg->nfi.pagefmt = mtk_nfi_readw(host, MTKSDG1_NFI_PAGEFMT);
-+ reg->nfi.acccon = mtk_nfi_readl(host, MTKSDG1_NFI_ACCCON);
-+ reg->nfi.cnrnb = mtk_nfi_readw(host, MTKSDG1_NFI_CNRNB);
-+ reg->nfi.csel = mtk_nfi_readw(host, MTKSDG1_NFI_CSEL);
-+
-+ mtk_nfc_disable_clk(&host->clk);
-+
-+ return 0;
-+}
-+
-+static int mtk_nfc_resume(struct device *dev)
-+{
-+ struct mtk_nfc_host *host = dev_get_drvdata(dev);
-+ struct mtk_nfc_saved_reg *reg = &host->saved_reg;
-+ struct nand_chip *chip = &host->chip;
-+ struct mtd_info *mtd = nand_to_mtd(chip);
-+ int ret;
-+ u32 i;
-+
-+ udelay(200);
-+
-+ ret = mtk_nfc_enable_clk(dev, &host->clk);
-+ if (ret)
-+ return ret;
-+
-+ for (i = 0; i < chip->numchips; i++) {
-+ chip->select_chip(mtd, i);
-+ chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
-+ }
-+
-+ mtk_nfi_writel(host, reg->nfi.emp_thresh, MTKSDG1_NFI_EMPTY_THRESH);
-+ mtk_nfi_writew(host, reg->nfi.pagefmt, MTKSDG1_NFI_PAGEFMT);
-+ mtk_ecc_writel(host, reg->ecc.enccnfg, MTKSDG1_ECC_ENCCNFG);
-+ mtk_ecc_writel(host, reg->ecc.deccnfg, MTKSDG1_ECC_DECCNFG);
-+ mtk_nfi_writel(host, reg->nfi.acccon, MTKSDG1_NFI_ACCCON);
-+ mtk_nfi_writew(host, reg->nfi.cnrnb, MTKSDG1_NFI_CNRNB);
-+ mtk_nfi_writew(host, reg->nfi.csel, MTKSDG1_NFI_CSEL);
-+
-+ return 0;
-+}
-+
-+static SIMPLE_DEV_PM_OPS(mtk_nfc_pm_ops, mtk_nfc_suspend, mtk_nfc_resume);
-+#endif
-+
-+static const struct of_device_id mtk_nfc_id_table[] = {
-+ { .compatible = "mediatek,mt2701-nfc" },
-+ {}
-+};
-+MODULE_DEVICE_TABLE(of, mtk_nfc_id_table);
-+
-+static struct platform_driver mtk_nfc_driver = {
-+ .probe = mtk_nfc_probe,
-+ .remove = mtk_nfc_remove,
-+ .driver = {
-+ .name = MTK_NAME,
-+ .of_match_table = mtk_nfc_id_table,
-+#ifdef CONFIG_PM_SLEEP
-+ .pm = &mtk_nfc_pm_ops,
-+#endif
-+ },
-+};
-+
-+module_platform_driver(mtk_nfc_driver);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Xiaolei Li <xiaolei.li@mediatek.com>");
-+MODULE_DESCRIPTION("MTK Nand Flash Controller Driver");
-+
-diff --git a/drivers/mtd/nand/mtksdg1_nand_ecc.h b/drivers/mtd/nand/mtksdg1_nand_ecc.h
-new file mode 100644
-index 0000000..d90b196
---- /dev/null
-+++ b/drivers/mtd/nand/mtksdg1_nand_ecc.h
-@@ -0,0 +1,75 @@
-+/*
-+ * MTK smart device ECC engine register.
-+ * Copyright (C) 2015-2016 MediaTek Inc.
-+ * Author: Xiaolei.Li <xiaolei.li@mediatek.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#ifndef MTKSDG1_NAND_ECC_H
-+#define MTKSDG1_NAND_ECC_H
-+
-+/* ECC engine register definition */
-+#define MTKSDG1_ECC_ENCCON (0x00)
-+#define ENC_EN (1)
-+#define ENC_DE (0)
-+
-+#define MTKSDG1_ECC_ENCCNFG (0x04)
-+#define ECC_CNFG_4BIT (0)
-+#define ECC_CNFG_12BIT (4)
-+#define ECC_NFI_MODE BIT(5)
-+#define ECC_DMA_MODE (0)
-+#define ECC_ENC_MODE_MASK (0x3 << 5)
-+#define ECC_MS_SHIFT (16)
-+
-+#define MTKSDG1_ECC_ENCDIADDR (0x08)
-+
-+#define MTKSDG1_ECC_ENCIDLE (0x0C)
-+#define ENC_IDLE BIT(0)
-+
-+#define MTKSDG1_ECC_ENCPAR0 (0x10)
-+#define MTKSDG1_ECC_ENCSTA (0x7C)
-+
-+#define MTKSDG1_ECC_ENCIRQ_EN (0x80)
-+#define ENC_IRQEN BIT(0)
-+
-+#define MTKSDG1_ECC_ENCIRQ_STA (0x84)
-+
-+#define MTKSDG1_ECC_DECCON (0x100)
-+#define DEC_EN (1)
-+#define DEC_DE (0)
-+
-+#define MTKSDG1_ECC_DECCNFG (0x104)
-+#define DEC_EMPTY_EN BIT(31)
-+#define DEC_CNFG_FER (0x1 << 12)
-+#define DEC_CNFG_EL (0x2 << 12)
-+#define DEC_CNFG_CORRECT (0x3 << 12)
-+
-+#define MTKSDG1_ECC_DECIDLE (0x10C)
-+#define DEC_IDLE BIT(0)
-+
-+#define MTKSDG1_ECC_DECFER (0x110)
-+
-+#define MTKSDG1_ECC_DECENUM0 (0x114)
-+#define ERR_MASK (0x3f)
-+
-+#define MTKSDG1_ECC_DECDONE (0x124)
-+
-+#define MTKSDG1_ECC_DECEL0 (0x128)
-+
-+#define MTKSDG1_ECC_DECIRQ_EN (0x200)
-+#define DEC_IRQEN BIT(0)
-+
-+#define MTKSDG1_ECC_DECIRQ_STA (0x204)
-+
-+#define MTKSDG1_ECC_DECFSM (0x208)
-+#define DECFSM_MASK (0x7f0f0f0f)
-+#define DECFSM_IDLE (0x01010101)
-+#endif
-diff --git a/drivers/mtd/nand/mtksdg1_nand_nfi.h b/drivers/mtd/nand/mtksdg1_nand_nfi.h
-new file mode 100644
-index 0000000..a9aa6f6
---- /dev/null
-+++ b/drivers/mtd/nand/mtksdg1_nand_nfi.h
-@@ -0,0 +1,119 @@
-+/*
-+ * MTK smart device NAND Flash controller register.
-+ * Copyright (C) 2015-2016 MediaTek Inc.
-+ * Author: Xiaolei.Li <xiaolei.li@mediatek.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#ifndef MTKSDG1_NAND_NFI_H
-+#define MTKSDG1_NAND_NFI_H
-+
-+/* NAND controller register definition */
-+#define MTKSDG1_NFI_CNFG (0x00)
-+#define CNFG_AHB BIT(0)
-+#define CNFG_READ_EN BIT(1)
-+#define CNFG_DMA_BURST_EN BIT(2)
-+#define CNFG_BYTE_RW BIT(6)
-+#define CNFG_HW_ECC_EN BIT(8)
-+#define CNFG_AUTO_FMT_EN BIT(9)
-+#define CNFG_OP_IDLE (0 << 12)
-+#define CNFG_OP_READ (1 << 12)
-+#define CNFG_OP_SRD (2 << 12)
-+#define CNFG_OP_PRGM (3 << 12)
-+#define CNFG_OP_ERASE (4 << 12)
-+#define CNFG_OP_RESET (5 << 12)
-+#define CNFG_OP_CUST (6 << 12)
-+
-+#define MTKSDG1_NFI_PAGEFMT (0x04)
-+#define PAGEFMT_FDM_ECC_SHIFT (12)
-+#define PAGEFMT_FDM_SHIFT (8)
-+#define PAGEFMT_SPARE_16 (0)
-+#define PAGEFMT_SPARE_32 (4)
-+#define PAGEFMT_SPARE_SHIFT (4)
-+#define PAGEFMT_SEC_SEL_512 BIT(2)
-+#define PAGEFMT_512_2K (0)
-+#define PAGEFMT_2K_4K (1)
-+#define PAGEFMT_4K_8K (2)
-+
-+/* NFI control */
-+#define MTKSDG1_NFI_CON (0x08)
-+#define CON_FIFO_FLUSH BIT(0)
-+#define CON_NFI_RST BIT(1)
-+#define CON_SRD BIT(4) /* single read */
-+#define CON_BRD BIT(8) /* burst read */
-+#define CON_BWR BIT(9) /* burst write */
-+#define CON_SEC_SHIFT (12)
-+
-+/* Timming control register */
-+#define MTKSDG1_NFI_ACCCON (0x0C)
-+
-+#define MTKSDG1_NFI_INTR_EN (0x10)
-+#define INTR_RD_DONE_EN BIT(0)
-+#define INTR_WR_DONE_EN BIT(1)
-+#define INTR_RST_DONE_EN BIT(2)
-+#define INTR_ERS_DONE_EN BIT(3)
-+#define INTR_BUSY_RT_EN BIT(4)
-+#define INTR_AHB_DONE_EN BIT(6)
-+
-+#define MTKSDG1_NFI_INTR_STA (0x14)
-+
-+#define MTKSDG1_NFI_CMD (0x20)
-+
-+#define MTKSDG1_NFI_ADDRNOB (0x30)
-+#define ADDR_ROW_NOB_SHIFT (4)
-+
-+#define MTKSDG1_NFI_COLADDR (0x34)
-+#define MTKSDG1_NFI_ROWADDR (0x38)
-+#define MTKSDG1_NFI_STRDATA (0x40)
-+#define MTKSDG1_NFI_CNRNB (0x44)
-+#define MTKSDG1_NFI_DATAW (0x50)
-+#define MTKSDG1_NFI_DATAR (0x54)
-+#define MTKSDG1_NFI_PIO_DIRDY (0x58)
-+#define PIO_DI_RDY (0x01)
-+
-+/* NFI state*/
-+#define MTKSDG1_NFI_STA (0x60)
-+#define STA_CMD BIT(0)
-+#define STA_ADDR BIT(1)
-+#define STA_DATAR BIT(2)
-+#define STA_DATAW BIT(3)
-+#define STA_EMP_PAGE BIT(12)
-+
-+#define MTKSDG1_NFI_FIFOSTA (0x64)
-+
-+#define MTKSDG1_NFI_ADDRCNTR (0x70)
-+#define CNTR_MASK GENMASK(16, 12)
-+
-+#define MTKSDG1_NFI_STRADDR (0x80)
-+#define MTKSDG1_NFI_BYTELEN (0x84)
-+#define MTKSDG1_NFI_CSEL (0x90)
-+#define MTKSDG1_NFI_IOCON (0x94)
-+
-+/* FDM data for sector: FDM0[L,H] - FDMF[L,H] */
-+#define MTKSDG1_NFI_FDM_MAX_SEC (0x10)
-+#define MTKSDG1_NFI_FDM_REG_SIZE (8)
-+#define MTKSDG1_NFI_FDM0L (0xA0)
-+#define MTKSDG1_NFI_FDM0M (0xA4)
-+
-+
-+#define MTKSDG1_NFI_FIFODATA0 (0x190)
-+#define MTKSDG1_NFI_DEBUG_CON1 (0x220)
-+#define MTKSDG1_NFI_MASTER_STA (0x224)
-+#define MASTER_STA_MASK (0x0FFF)
-+
-+#define MTKSDG1_NFI_RANDOM_CNFG (0x238)
-+#define MTKSDG1_NFI_EMPTY_THRESH (0x23C)
-+#define MTKSDG1_NFI_NAND_TYPE (0x240)
-+#define MTKSDG1_NFI_ACCCON1 (0x244)
-+#define MTKSDG1_NFI_DELAY_CTRL (0x248)
-+
-+#endif
-+
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0058-net-mediatek-unlock-on-error-in-mtk_tx_map.patch b/target/linux/mediatek/patches-4.4/0058-net-mediatek-unlock-on-error-in-mtk_tx_map.patch
new file mode 100644
index 0000000000..a3f861b72c
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0058-net-mediatek-unlock-on-error-in-mtk_tx_map.patch
@@ -0,0 +1,24 @@
+From 6c12340c0c307d18b8d6120f64a8275b6d4d3e67 Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <dan.carpenter@oracle.com>
+Date: Tue, 15 Mar 2016 10:19:04 +0300
+Subject: [PATCH 058/102] net: mediatek: unlock on error in mtk_tx_map()
+
+There was a missing unlock on the error path.
+
+Fixes: 656e705243fd ('net-next: mediatek: add support for MT7623 ethernet')
+Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -661,6 +661,8 @@ err_dma:
+ itxd = mtk_qdma_phys_to_virt(ring, itxd->txd2);
+ } while (itxd != txd);
+
++ spin_unlock_irqrestore(&eth->page_lock, flags);
++
+ return -ENOMEM;
+ }
+
diff --git a/target/linux/mediatek/patches-4.4/0059-mtd-nand-backport-fixes.patch b/target/linux/mediatek/patches-4.4/0059-mtd-nand-backport-fixes.patch
deleted file mode 100644
index 074346a6ff..0000000000
--- a/target/linux/mediatek/patches-4.4/0059-mtd-nand-backport-fixes.patch
+++ /dev/null
@@ -1,46 +0,0 @@
-From 96bddff914c0cee1b16d809220e84b470b433122 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Thu, 31 Mar 2016 02:28:08 +0200
-Subject: [PATCH 59/91] mtd: nand: backport fixes
-
----
- drivers/mtd/nand/mtksdg1_nand.c | 9 ++++++++-
- 1 file changed, 8 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/mtd/nand/mtksdg1_nand.c b/drivers/mtd/nand/mtksdg1_nand.c
-index 55dd17d..f92b949 100644
---- a/drivers/mtd/nand/mtksdg1_nand.c
-+++ b/drivers/mtd/nand/mtksdg1_nand.c
-@@ -107,6 +107,9 @@ static struct nand_ecclayout nand_4k_128 = {
- .oobfree = { {0, 32} },
- };
-
-+static const char * const part_probes[] = {
-+ "cmdlinepart", "RedBoot", "ofpart", NULL };
-+
- /* NFI register access */
- static inline void mtk_nfi_writel(struct mtk_nfc_host *host, u32 val, u32 reg)
- {
-@@ -1298,6 +1301,7 @@ static int mtk_nfc_probe(struct platform_device *pdev)
-
- chip = &host->chip;
- mtd = nand_to_mtd(chip);
-+ mtd->priv = chip;
- host->dev = dev;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-@@ -1428,7 +1432,10 @@ static int mtk_nfc_probe(struct platform_device *pdev)
- }
- host->switch_oob = false;
-
-- ret = mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
-+ ret = mtd_device_parse_register(mtd, part_probes,
-+ &(struct mtd_part_parser_data) {
-+ .of_node = pdev->dev.of_node,
-+ }, NULL, 0);
- if (ret) {
- dev_err(dev, "mtd parse partition error\n");
- goto nand_free;
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0059-net-mediatek-use-dma_addr_t-correctly.patch b/target/linux/mediatek/patches-4.4/0059-net-mediatek-use-dma_addr_t-correctly.patch
new file mode 100644
index 0000000000..0dd5f2d29d
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0059-net-mediatek-use-dma_addr_t-correctly.patch
@@ -0,0 +1,30 @@
+From a572747434b6153e75812c5466c0557e5ed69284 Mon Sep 17 00:00:00 2001
+From: Arnd Bergmann <arnd@arndb.de>
+Date: Mon, 14 Mar 2016 15:07:10 +0100
+Subject: [PATCH 059/102] net: mediatek: use dma_addr_t correctly
+
+dma_alloc_coherent() expects a dma_addr_t pointer as its argument,
+not an 'unsigned int', and gcc correctly warns about broken
+code in the mtk_init_fq_dma function:
+
+drivers/net/ethernet/mediatek/mtk_eth_soc.c: In function 'mtk_init_fq_dma':
+drivers/net/ethernet/mediatek/mtk_eth_soc.c:463:13: error: passing argument 3 of 'dma_alloc_coherent' from incompatible pointer type [-Werror=incompatible-pointer-types]
+
+This changes the type of the local variable to dma_addr_t.
+
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -453,7 +453,7 @@ static inline void mtk_rx_get_desc(struc
+ /* the qdma core needs scratch memory to be setup */
+ static int mtk_init_fq_dma(struct mtk_eth *eth)
+ {
+- unsigned int phy_ring_head, phy_ring_tail;
++ dma_addr_t phy_ring_head, phy_ring_tail;
+ int cnt = MTK_DMA_SIZE;
+ dma_addr_t dma_addr;
+ int i;
diff --git a/target/linux/mediatek/patches-4.4/0060-clk-dont-disable-unused-clocks.patch b/target/linux/mediatek/patches-4.4/0060-clk-dont-disable-unused-clocks.patch
deleted file mode 100644
index ef425225f2..0000000000
--- a/target/linux/mediatek/patches-4.4/0060-clk-dont-disable-unused-clocks.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-From cbcbd319d905cdcf4a71003b5634137fee03855b Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Thu, 7 Apr 2016 07:18:35 +0200
-Subject: [PATCH 60/91] clk: dont disable unused clocks
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/clk/clk.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
-index f13c3f4..5e9ddae 100644
---- a/drivers/clk/clk.c
-+++ b/drivers/clk/clk.c
-@@ -233,7 +233,7 @@ unlock_out:
- clk_enable_unlock(flags);
- }
-
--static bool clk_ignore_unused;
-+static bool clk_ignore_unused = true;
- static int __init clk_ignore_unused_setup(char *__unused)
- {
- clk_ignore_unused = true;
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0060-net-mediatek-remove-incorrect-dma_mask-assignment.patch b/target/linux/mediatek/patches-4.4/0060-net-mediatek-remove-incorrect-dma_mask-assignment.patch
new file mode 100644
index 0000000000..d1df7327b1
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0060-net-mediatek-remove-incorrect-dma_mask-assignment.patch
@@ -0,0 +1,31 @@
+From 8473af12d5aa34613070447d6fd8f785f31301de Mon Sep 17 00:00:00 2001
+From: Arnd Bergmann <arnd@arndb.de>
+Date: Mon, 14 Mar 2016 15:07:11 +0100
+Subject: [PATCH 060/102] net: mediatek: remove incorrect dma_mask assignment
+
+Device drivers should not mess with the DMA mask directly,
+but instead call dma_set_mask() etc if needed.
+
+In case of the mtk_eth_soc driver, the mask already gets set
+correctly when the device is created, and setting it again
+is against the documented API.
+
+This removes the incorrect setting.
+
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -1678,9 +1678,6 @@ static int mtk_probe(struct platform_dev
+ struct mtk_eth *eth;
+ int err;
+
+- pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+- pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+-
+ device_reset(&pdev->dev);
+
+ match = of_match_device(of_mtk_match, &pdev->dev);
diff --git a/target/linux/mediatek/patches-4.4/0061-clk-mediatek-enable-critical-clocks.patch b/target/linux/mediatek/patches-4.4/0061-clk-mediatek-enable-critical-clocks.patch
deleted file mode 100644
index b075a7465e..0000000000
--- a/target/linux/mediatek/patches-4.4/0061-clk-mediatek-enable-critical-clocks.patch
+++ /dev/null
@@ -1,74 +0,0 @@
-From 6610fdbea393a4a8ed956b2aaf7012bea3a5069e Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Thu, 31 Mar 2016 06:46:51 +0200
-Subject: [PATCH 61/91] clk: mediatek: enable critical clocks
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/clk/mediatek/clk-mt2701.c | 22 ++++++++++++++++++++--
- 1 file changed, 20 insertions(+), 2 deletions(-)
-
-diff --git a/drivers/clk/mediatek/clk-mt2701.c b/drivers/clk/mediatek/clk-mt2701.c
-index 812b347..1634288 100644
---- a/drivers/clk/mediatek/clk-mt2701.c
-+++ b/drivers/clk/mediatek/clk-mt2701.c
-@@ -573,6 +573,20 @@ static const struct mtk_gate top_clks[] __initconst = {
- GATE_TOP_AUD(CLK_TOP_AUD_I2S6_MCLK, "aud_i2s6_mclk", "aud_k6_src_div", 28),
- };
-
-+static struct clk_onecell_data *mt7623_top_clk_data __initdata;
-+static struct clk_onecell_data *mt7623_pll_clk_data __initdata;
-+
-+static void __init mtk_clk_enable_critical(void)
-+{
-+ if (!mt7623_top_clk_data || !mt7623_pll_clk_data)
-+ return;
-+
-+ clk_prepare_enable(mt7623_pll_clk_data->clks[CLK_APMIXED_ARMPLL]);
-+ clk_prepare_enable(mt7623_top_clk_data->clks[CLK_TOP_MEM_SEL]);
-+ clk_prepare_enable(mt7623_top_clk_data->clks[CLK_TOP_DDRPHYCFG_SEL]);
-+ clk_prepare_enable(mt7623_top_clk_data->clks[CLK_TOP_RTC_SEL]);
-+}
-+
- static void __init mtk_topckgen_init(struct device_node *node)
- {
- struct clk_onecell_data *clk_data;
-@@ -585,7 +599,7 @@ static void __init mtk_topckgen_init(struct device_node *node)
- return;
- }
-
-- clk_data = mtk_alloc_clk_data(CLK_TOP_NR);
-+ mt7623_top_clk_data = clk_data = mtk_alloc_clk_data(CLK_TOP_NR);
-
- mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks),
- clk_data);
-@@ -606,6 +620,8 @@ static void __init mtk_topckgen_init(struct device_node *node)
- if (r)
- pr_err("%s(): could not register clock provider: %d\n",
- __func__, r);
-+
-+ mtk_clk_enable_critical();
- }
- CLK_OF_DECLARE(mtk_topckgen, "mediatek,mt2701-topckgen", mtk_topckgen_init);
-
-@@ -1202,7 +1218,7 @@ static void __init mtk_apmixedsys_init(struct device_node *node)
- struct clk_onecell_data *clk_data;
- int r;
-
-- clk_data = mtk_alloc_clk_data(ARRAY_SIZE(apmixed_plls));
-+ mt7623_pll_clk_data = clk_data = mtk_alloc_clk_data(ARRAY_SIZE(apmixed_plls));
- if (!clk_data)
- return;
-
-@@ -1213,6 +1229,8 @@ static void __init mtk_apmixedsys_init(struct device_node *node)
- if (r)
- pr_err("%s(): could not register clock provider: %d\n",
- __func__, r);
-+
-+ mtk_clk_enable_critical();
- }
- CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt2701-apmixedsys",
- mtk_apmixedsys_init);
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0061-net-mediatek-check-device_reset-return-code.patch b/target/linux/mediatek/patches-4.4/0061-net-mediatek-check-device_reset-return-code.patch
new file mode 100644
index 0000000000..ebc6d9b361
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0061-net-mediatek-check-device_reset-return-code.patch
@@ -0,0 +1,33 @@
+From 99159791184752ece724b741f9fa6334fdc67123 Mon Sep 17 00:00:00 2001
+From: Arnd Bergmann <arnd@arndb.de>
+Date: Mon, 14 Mar 2016 15:07:12 +0100
+Subject: [PATCH 061/102] net: mediatek: check device_reset return code
+
+The device_reset() function may fail, so we have to check
+its return value, e.g. to make deferred probing work correctly.
+gcc warns about it because of the warn_unused_result attribute:
+
+drivers/net/ethernet/mediatek/mtk_eth_soc.c: In function 'mtk_probe':
+drivers/net/ethernet/mediatek/mtk_eth_soc.c:1679:2: error: ignoring return value of 'device_reset', declared with attribute warn_unused_result [-Werror=unused-result]
+
+This adds the trivial error check to propagate the return value
+to the generic platform device probe code.
+
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -1678,7 +1678,9 @@ static int mtk_probe(struct platform_dev
+ struct mtk_eth *eth;
+ int err;
+
+- device_reset(&pdev->dev);
++ err = device_reset(&pdev->dev);
++ if (err)
++ return err;
+
+ match = of_match_device(of_mtk_match, &pdev->dev);
+ soc = (struct mtk_soc_data *)match->data;
diff --git a/target/linux/mediatek/patches-4.4/0062-clk-mediatek-Export-CPU-mux-clocks-for-CPU-frequency.patch b/target/linux/mediatek/patches-4.4/0062-clk-mediatek-Export-CPU-mux-clocks-for-CPU-frequency.patch
deleted file mode 100644
index d30f2dd48c..0000000000
--- a/target/linux/mediatek/patches-4.4/0062-clk-mediatek-Export-CPU-mux-clocks-for-CPU-frequency.patch
+++ /dev/null
@@ -1,306 +0,0 @@
-From 2ed6efcef399d15910ff60eef72b4cf8e5265c47 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Thu, 31 Mar 2016 02:26:37 +0200
-Subject: [PATCH 62/91] clk: mediatek: Export CPU mux clocks for CPU frequency
- control
-
-This patch adds CPU mux clocks which are used by Mediatek cpufreq driver
-for intermediate clock source switching.
-
-Signed-off-by: Pi-Cheng Chen <pi-cheng.chen@linaro.org>
----
- drivers/clk/mediatek/Makefile | 2 +-
- drivers/clk/mediatek/clk-cpumux.c | 127 ++++++++++++++++++++++++++++++++
- drivers/clk/mediatek/clk-cpumux.h | 22 ++++++
- drivers/clk/mediatek/clk-mt2701.c | 8 ++
- drivers/clk/mediatek/clk-mt8173.c | 23 ++++++
- include/dt-bindings/clock/mt2701-clk.h | 3 +-
- include/dt-bindings/clock/mt8173-clk.h | 4 +-
- 7 files changed, 186 insertions(+), 3 deletions(-)
- create mode 100644 drivers/clk/mediatek/clk-cpumux.c
- create mode 100644 drivers/clk/mediatek/clk-cpumux.h
-
-diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
-index 5b2b91b..76bfab6 100644
---- a/drivers/clk/mediatek/Makefile
-+++ b/drivers/clk/mediatek/Makefile
-@@ -1,4 +1,4 @@
--obj-$(CONFIG_COMMON_CLK_MEDIATEK) += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.o
-+obj-$(CONFIG_COMMON_CLK_MEDIATEK) += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.o clk-cpumux.o
- obj-$(CONFIG_RESET_CONTROLLER) += reset.o
- obj-$(CONFIG_COMMON_CLK_MT2701) += clk-mt2701.o
- obj-$(CONFIG_COMMON_CLK_MT8135) += clk-mt8135.o
-diff --git a/drivers/clk/mediatek/clk-cpumux.c b/drivers/clk/mediatek/clk-cpumux.c
-new file mode 100644
-index 0000000..91b5238
---- /dev/null
-+++ b/drivers/clk/mediatek/clk-cpumux.c
-@@ -0,0 +1,127 @@
-+/*
-+ * Copyright (c) 2015 Linaro Ltd.
-+ * Author: Pi-Cheng Chen <pi-cheng.chen@linaro.org>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#include <linux/clk-provider.h>
-+#include <linux/mfd/syscon.h>
-+#include <linux/slab.h>
-+
-+#include "clk-mtk.h"
-+#include "clk-cpumux.h"
-+
-+struct mtk_clk_cpumux {
-+ struct clk_hw hw;
-+ struct regmap *regmap;
-+ u32 reg;
-+ u32 mask;
-+ u8 shift;
-+};
-+
-+static inline struct mtk_clk_cpumux *to_clk_mux(struct clk_hw *_hw)
-+{
-+ return container_of(_hw, struct mtk_clk_cpumux, hw);
-+}
-+
-+static u8 clk_cpumux_get_parent(struct clk_hw *hw)
-+{
-+ struct mtk_clk_cpumux *mux = to_clk_mux(hw);
-+ int num_parents = clk_hw_get_num_parents(hw);
-+ unsigned int val;
-+
-+ regmap_read(mux->regmap, mux->reg, &val);
-+
-+ val >>= mux->shift;
-+ val &= mux->mask;
-+
-+ if (val >= num_parents)
-+ return -EINVAL;
-+
-+ return val;
-+}
-+
-+static int clk_cpumux_set_parent(struct clk_hw *hw, u8 index)
-+{
-+ struct mtk_clk_cpumux *mux = to_clk_mux(hw);
-+ u32 mask, val;
-+
-+ val = index << mux->shift;
-+ mask = mux->mask << mux->shift;
-+
-+ return regmap_update_bits(mux->regmap, mux->reg, mask, val);
-+}
-+
-+static const struct clk_ops clk_cpumux_ops = {
-+ .get_parent = clk_cpumux_get_parent,
-+ .set_parent = clk_cpumux_set_parent,
-+};
-+
-+static struct clk __init *mtk_clk_register_cpumux(const struct mtk_composite *mux,
-+ struct regmap *regmap)
-+{
-+ struct mtk_clk_cpumux *cpumux;
-+ struct clk *clk;
-+ struct clk_init_data init;
-+
-+ cpumux = kzalloc(sizeof(*cpumux), GFP_KERNEL);
-+ if (!cpumux)
-+ return ERR_PTR(-ENOMEM);
-+
-+ init.name = mux->name;
-+ init.ops = &clk_cpumux_ops;
-+ init.parent_names = mux->parent_names;
-+ init.num_parents = mux->num_parents;
-+ init.flags = mux->flags;
-+
-+ cpumux->reg = mux->mux_reg;
-+ cpumux->shift = mux->mux_shift;
-+ cpumux->mask = BIT(mux->mux_width) - 1;
-+ cpumux->regmap = regmap;
-+ cpumux->hw.init = &init;
-+
-+ clk = clk_register(NULL, &cpumux->hw);
-+ if (IS_ERR(clk))
-+ kfree(cpumux);
-+
-+ return clk;
-+}
-+
-+int __init mtk_clk_register_cpumuxes(struct device_node *node,
-+ const struct mtk_composite *clks, int num,
-+ struct clk_onecell_data *clk_data)
-+{
-+ int i;
-+ struct clk *clk;
-+ struct regmap *regmap;
-+
-+ regmap = syscon_node_to_regmap(node);
-+ if (IS_ERR(regmap)) {
-+ pr_err("Cannot find regmap for %s: %ld\n", node->full_name,
-+ PTR_ERR(regmap));
-+ return PTR_ERR(regmap);
-+ }
-+
-+ for (i = 0; i < num; i++) {
-+ const struct mtk_composite *mux = &clks[i];
-+
-+ clk = mtk_clk_register_cpumux(mux, regmap);
-+ if (IS_ERR(clk)) {
-+ pr_err("Failed to register clk %s: %ld\n",
-+ mux->name, PTR_ERR(clk));
-+ continue;
-+ }
-+
-+ clk_data->clks[mux->id] = clk;
-+ }
-+
-+ return 0;
-+}
-diff --git a/drivers/clk/mediatek/clk-cpumux.h b/drivers/clk/mediatek/clk-cpumux.h
-new file mode 100644
-index 0000000..52c769f
---- /dev/null
-+++ b/drivers/clk/mediatek/clk-cpumux.h
-@@ -0,0 +1,22 @@
-+/*
-+ * Copyright (c) 2015 Linaro Ltd.
-+ * Author: Pi-Cheng Chen <pi-cheng.chen@linaro.org>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#ifndef __DRV_CLK_CPUMUX_H
-+#define __DRV_CLK_CPUMUX_H
-+
-+int mtk_clk_register_cpumuxes(struct device_node *node,
-+ const struct mtk_composite *clks, int num,
-+ struct clk_onecell_data *clk_data);
-+
-+#endif /* __DRV_CLK_CPUMUX_H */
-diff --git a/drivers/clk/mediatek/clk-mt2701.c b/drivers/clk/mediatek/clk-mt2701.c
-index 1634288..5c37fcb 100644
---- a/drivers/clk/mediatek/clk-mt2701.c
-+++ b/drivers/clk/mediatek/clk-mt2701.c
-@@ -18,6 +18,7 @@
-
- #include "clk-mtk.h"
- #include "clk-gate.h"
-+#include "clk-cpumux.h"
-
- #include <dt-bindings/clock/mt2701-clk.h>
-
-@@ -465,6 +466,10 @@ static const char * const cpu_parents[] __initconst = {
- "mmpll"
- };
-
-+static const struct mtk_composite cpu_muxes[] __initconst = {
-+ MUX(CLK_INFRA_CPUSEL, "infra_cpu_sel", cpu_parents, 0x0000, 2, 2),
-+};
-+
- static const struct mtk_composite top_muxes[] __initconst = {
- MUX_GATE(CLK_TOP_AXI_SEL, "axi_sel", axi_parents,
- 0x0040, 0, 3, INVALID_MUX_GATE_BIT),
-@@ -677,6 +682,9 @@ static void __init mtk_infrasys_init(struct device_node *node)
- mtk_clk_register_factors(infra_fixed_divs, ARRAY_SIZE(infra_fixed_divs),
- clk_data);
-
-+ mtk_clk_register_cpumuxes(node, cpu_muxes, ARRAY_SIZE(cpu_muxes),
-+ clk_data);
-+
- r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
- if (r)
- pr_err("%s(): could not register clock provider: %d\n",
-diff --git a/drivers/clk/mediatek/clk-mt8173.c b/drivers/clk/mediatek/clk-mt8173.c
-index 227e356..b82c0e2 100644
---- a/drivers/clk/mediatek/clk-mt8173.c
-+++ b/drivers/clk/mediatek/clk-mt8173.c
-@@ -18,6 +18,7 @@
-
- #include "clk-mtk.h"
- #include "clk-gate.h"
-+#include "clk-cpumux.h"
-
- #include <dt-bindings/clock/mt8173-clk.h>
-
-@@ -526,6 +527,25 @@ static const char * const i2s3_b_ck_parents[] __initconst = {
- "apll2_div5"
- };
-
-+static const char * const ca53_parents[] __initconst = {
-+ "clk26m",
-+ "armca7pll",
-+ "mainpll",
-+ "univpll"
-+};
-+
-+static const char * const ca57_parents[] __initconst = {
-+ "clk26m",
-+ "armca15pll",
-+ "mainpll",
-+ "univpll"
-+};
-+
-+static const struct mtk_composite cpu_muxes[] __initconst = {
-+ MUX(CLK_INFRA_CA53SEL, "infra_ca53_sel", ca53_parents, 0x0000, 0, 2),
-+ MUX(CLK_INFRA_CA57SEL, "infra_ca57_sel", ca57_parents, 0x0000, 2, 2),
-+};
-+
- static const struct mtk_composite top_muxes[] __initconst = {
- /* CLK_CFG_0 */
- MUX(CLK_TOP_AXI_SEL, "axi_sel", axi_parents, 0x0040, 0, 3),
-@@ -945,6 +965,9 @@ static void __init mtk_infrasys_init(struct device_node *node)
- clk_data);
- mtk_clk_register_factors(infra_divs, ARRAY_SIZE(infra_divs), clk_data);
-
-+ mtk_clk_register_cpumuxes(node, cpu_muxes, ARRAY_SIZE(cpu_muxes),
-+ clk_data);
-+
- r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
- if (r)
- pr_err("%s(): could not register clock provider: %d\n",
-diff --git a/include/dt-bindings/clock/mt2701-clk.h b/include/dt-bindings/clock/mt2701-clk.h
-index 50972d1..a6c63b8 100644
---- a/include/dt-bindings/clock/mt2701-clk.h
-+++ b/include/dt-bindings/clock/mt2701-clk.h
-@@ -217,7 +217,8 @@
- #define CLK_INFRA_PMICWRAP 17
- #define CLK_INFRA_DDCCI 18
- #define CLK_INFRA_CLK_13M 19
--#define CLK_INFRA_NR 20
-+#define CLK_INFRA_CPUSEL 20
-+#define CLK_INFRA_NR 21
-
- /* PERICFG */
-
-diff --git a/include/dt-bindings/clock/mt8173-clk.h b/include/dt-bindings/clock/mt8173-clk.h
-index 7956ba1..c82ed7c 100644
---- a/include/dt-bindings/clock/mt8173-clk.h
-+++ b/include/dt-bindings/clock/mt8173-clk.h
-@@ -192,7 +192,9 @@
- #define CLK_INFRA_PMICSPI 10
- #define CLK_INFRA_PMICWRAP 11
- #define CLK_INFRA_CLK_13M 12
--#define CLK_INFRA_NR_CLK 13
-+#define CLK_INFRA_CA53SEL 13
-+#define CLK_INFRA_CA57SEL 14
-+#define CLK_INFRA_NR_CLK 15
-
- /* PERI_SYS */
-
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0062-net-mediatek-watchdog_timeo-was-not-set.patch b/target/linux/mediatek/patches-4.4/0062-net-mediatek-watchdog_timeo-was-not-set.patch
new file mode 100644
index 0000000000..ca2e791a37
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0062-net-mediatek-watchdog_timeo-was-not-set.patch
@@ -0,0 +1,23 @@
+From 387257cbd6f3f92de71e2f578d3a9414d0dada27 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Wed, 30 Mar 2016 03:18:17 +0200
+Subject: [PATCH 062/102] net: mediatek: watchdog_timeo was not set
+
+The original commit failed to set watchdog_timeo. This patch sets
+watchdog_timeo to HZ.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -1645,6 +1645,7 @@ static int mtk_add_mac(struct mtk_eth *e
+ mac->hw_stats->reg_offset = id * MTK_STAT_OFFSET;
+
+ SET_NETDEV_DEV(eth->netdev[id], eth->dev);
++ eth->netdev[id]->watchdog_timeo = HZ;
+ eth->netdev[id]->netdev_ops = &mtk_netdev_ops;
+ eth->netdev[id]->base_addr = (unsigned long)eth->base;
+ eth->netdev[id]->vlan_features = MTK_HW_FEATURES &
diff --git a/target/linux/mediatek/patches-4.4/0063-cpufreq-mediatek-add-driver.patch b/target/linux/mediatek/patches-4.4/0063-cpufreq-mediatek-add-driver.patch
deleted file mode 100644
index cf80540913..0000000000
--- a/target/linux/mediatek/patches-4.4/0063-cpufreq-mediatek-add-driver.patch
+++ /dev/null
@@ -1,443 +0,0 @@
-From 668d2c777a41440daa55435c2a217e61c23e4a30 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Wed, 30 Mar 2016 23:48:53 +0200
-Subject: [PATCH 63/91] cpufreq: mediatek: add driver
-
-Signed-off-by: John Crispin <john@phrozen.org>
----
- drivers/cpufreq/Kconfig.arm | 9 +
- drivers/cpufreq/Makefile | 1 +
- drivers/cpufreq/mt7623-cpufreq.c | 389 ++++++++++++++++++++++++++++++++++++++
- 3 files changed, 399 insertions(+)
- create mode 100644 drivers/cpufreq/mt7623-cpufreq.c
-
-diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
-index b1f8a73..baf945e 100644
---- a/drivers/cpufreq/Kconfig.arm
-+++ b/drivers/cpufreq/Kconfig.arm
-@@ -81,6 +81,15 @@ config ARM_KIRKWOOD_CPUFREQ
- This adds the CPUFreq driver for Marvell Kirkwood
- SoCs.
-
-+config ARM_MT7623_CPUFREQ
-+ bool "Mediatek MT7623 CPUFreq support"
-+ depends on ARCH_MEDIATEK && REGULATOR
-+ depends on ARM || (ARM_CPU_TOPOLOGY && COMPILE_TEST)
-+ depends on !CPU_THERMAL || THERMAL=y
-+ select PM_OPP
-+ help
-+ This adds the CPUFreq driver support for Mediatek MT7623 SoC.
-+
- config ARM_MT8173_CPUFREQ
- bool "Mediatek MT8173 CPUFreq support"
- depends on ARCH_MEDIATEK && REGULATOR
-diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
-index c0af1a1..e198752 100644
---- a/drivers/cpufreq/Makefile
-+++ b/drivers/cpufreq/Makefile
-@@ -57,6 +57,7 @@ obj-$(CONFIG_ARM_HISI_ACPU_CPUFREQ) += hisi-acpu-cpufreq.o
- obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o
- obj-$(CONFIG_ARM_INTEGRATOR) += integrator-cpufreq.o
- obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += kirkwood-cpufreq.o
-+obj-$(CONFIG_ARM_MT7623_CPUFREQ) += mt7623-cpufreq.o
- obj-$(CONFIG_ARM_MT8173_CPUFREQ) += mt8173-cpufreq.o
- obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o
- obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2xx-cpufreq.o
-diff --git a/drivers/cpufreq/mt7623-cpufreq.c b/drivers/cpufreq/mt7623-cpufreq.c
-new file mode 100644
-index 0000000..8d154ce
---- /dev/null
-+++ b/drivers/cpufreq/mt7623-cpufreq.c
-@@ -0,0 +1,389 @@
-+/*
-+ * Copyright (c) 2015 Linaro Ltd.
-+ * Author: Pi-Cheng Chen <pi-cheng.chen@linaro.org>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#include <linux/clk.h>
-+#include <linux/cpu.h>
-+#include <linux/cpu_cooling.h>
-+#include <linux/cpufreq.h>
-+#include <linux/cpumask.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <linux/pm_opp.h>
-+#include <linux/regulator/consumer.h>
-+#include <linux/slab.h>
-+#include <linux/thermal.h>
-+
-+#define VOLT_TOL (10000)
-+
-+/*
-+ * When scaling the clock frequency of a CPU clock domain, the clock source
-+ * needs to be switched to another stable PLL clock temporarily until
-+ * the original PLL becomes stable at target frequency.
-+ */
-+struct mtk_cpu_dvfs_info {
-+ struct device *cpu_dev;
-+ struct regulator *proc_reg;
-+ struct clk *cpu_clk;
-+ struct clk *inter_clk;
-+ struct thermal_cooling_device *cdev;
-+ int intermediate_voltage;
-+};
-+
-+static int mtk_cpufreq_set_voltage(struct mtk_cpu_dvfs_info *info, int vproc)
-+{
-+ return regulator_set_voltage(info->proc_reg, vproc,
-+ vproc + VOLT_TOL);
-+}
-+
-+static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
-+ unsigned int index)
-+{
-+ struct cpufreq_frequency_table *freq_table = policy->freq_table;
-+ struct clk *cpu_clk = policy->clk;
-+ struct clk *armpll = clk_get_parent(cpu_clk);
-+ struct mtk_cpu_dvfs_info *info = policy->driver_data;
-+ struct device *cpu_dev = info->cpu_dev;
-+ struct dev_pm_opp *opp;
-+ long freq_hz, old_freq_hz;
-+ int vproc, old_vproc, inter_vproc, target_vproc, ret;
-+
-+ inter_vproc = info->intermediate_voltage;
-+
-+ old_freq_hz = clk_get_rate(cpu_clk);
-+ old_vproc = regulator_get_voltage(info->proc_reg);
-+
-+ freq_hz = freq_table[index].frequency * 1000;
-+
-+ rcu_read_lock();
-+ opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
-+ if (IS_ERR(opp)) {
-+ rcu_read_unlock();
-+ pr_err("cpu%d: failed to find OPP for %ld\n",
-+ policy->cpu, freq_hz);
-+ return PTR_ERR(opp);
-+ }
-+ vproc = dev_pm_opp_get_voltage(opp);
-+ rcu_read_unlock();
-+
-+ /*
-+ * If the new voltage or the intermediate voltage is higher than the
-+ * current voltage, scale up voltage first.
-+ */
-+ target_vproc = (inter_vproc > vproc) ? inter_vproc : vproc;
-+ if (old_vproc < target_vproc) {
-+ ret = mtk_cpufreq_set_voltage(info, target_vproc);
-+ if (ret) {
-+ pr_err("cpu%d: failed to scale up voltage!\n",
-+ policy->cpu);
-+ mtk_cpufreq_set_voltage(info, old_vproc);
-+ return ret;
-+ }
-+ }
-+
-+ /* Reparent the CPU clock to intermediate clock. */
-+ ret = clk_set_parent(cpu_clk, info->inter_clk);
-+ if (ret) {
-+ pr_err("cpu%d: failed to re-parent cpu clock!\n",
-+ policy->cpu);
-+ mtk_cpufreq_set_voltage(info, old_vproc);
-+ WARN_ON(1);
-+ return ret;
-+ }
-+
-+ /* Set the original PLL to target rate. */
-+ ret = clk_set_rate(armpll, freq_hz);
-+ if (ret) {
-+ pr_err("cpu%d: failed to scale cpu clock rate!\n",
-+ policy->cpu);
-+ clk_set_parent(cpu_clk, armpll);
-+ mtk_cpufreq_set_voltage(info, old_vproc);
-+ return ret;
-+ }
-+
-+ /* Set parent of CPU clock back to the original PLL. */
-+ ret = clk_set_parent(cpu_clk, armpll);
-+ if (ret) {
-+ pr_err("cpu%d: failed to re-parent cpu clock!\n",
-+ policy->cpu);
-+ mtk_cpufreq_set_voltage(info, inter_vproc);
-+ WARN_ON(1);
-+ return ret;
-+ }
-+
-+ /*
-+ * If the new voltage is lower than the intermediate voltage or the
-+ * original voltage, scale down to the new voltage.
-+ */
-+ if (vproc < inter_vproc || vproc < old_vproc) {
-+ ret = mtk_cpufreq_set_voltage(info, vproc);
-+ if (ret) {
-+ pr_err("cpu%d: failed to scale down voltage!\n",
-+ policy->cpu);
-+ clk_set_parent(cpu_clk, info->inter_clk);
-+ clk_set_rate(armpll, old_freq_hz);
-+ clk_set_parent(cpu_clk, armpll);
-+ return ret;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static void mtk_cpufreq_ready(struct cpufreq_policy *policy)
-+{
-+ struct mtk_cpu_dvfs_info *info = policy->driver_data;
-+ struct device_node *np = of_node_get(info->cpu_dev->of_node);
-+
-+ if (WARN_ON(!np))
-+ return;
-+
-+ if (of_find_property(np, "#cooling-cells", NULL)) {
-+ info->cdev = of_cpufreq_cooling_register(np,
-+ policy->related_cpus);
-+
-+ if (IS_ERR(info->cdev)) {
-+ dev_err(info->cpu_dev,
-+ "running cpufreq without cooling device: %ld\n",
-+ PTR_ERR(info->cdev));
-+
-+ info->cdev = NULL;
-+ }
-+ }
-+
-+ of_node_put(np);
-+}
-+
-+static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
-+{
-+ struct device *cpu_dev;
-+ struct regulator *proc_reg = ERR_PTR(-ENODEV);
-+ struct clk *cpu_clk = ERR_PTR(-ENODEV);
-+ struct clk *inter_clk = ERR_PTR(-ENODEV);
-+ struct dev_pm_opp *opp;
-+ unsigned long rate;
-+ int ret;
-+
-+ cpu_dev = get_cpu_device(cpu);
-+ if (!cpu_dev) {
-+ pr_err("failed to get cpu%d device\n", cpu);
-+ return -ENODEV;
-+ }
-+
-+ cpu_clk = clk_get(cpu_dev, "cpu");
-+ if (IS_ERR(cpu_clk)) {
-+ if (PTR_ERR(cpu_clk) == -EPROBE_DEFER)
-+ pr_warn("cpu clk for cpu%d not ready, retry.\n", cpu);
-+ else
-+ pr_err("failed to get cpu clk for cpu%d\n", cpu);
-+
-+ ret = PTR_ERR(cpu_clk);
-+ return ret;
-+ }
-+
-+ inter_clk = clk_get(cpu_dev, "intermediate");
-+ if (IS_ERR(inter_clk)) {
-+ if (PTR_ERR(inter_clk) == -EPROBE_DEFER)
-+ pr_warn("intermediate clk for cpu%d not ready, retry.\n",
-+ cpu);
-+ else
-+ pr_err("failed to get intermediate clk for cpu%d\n",
-+ cpu);
-+
-+ ret = PTR_ERR(inter_clk);
-+ goto out_free_resources;
-+ }
-+
-+ proc_reg = regulator_get_exclusive(cpu_dev, "proc");
-+ if (IS_ERR(proc_reg)) {
-+ if (PTR_ERR(proc_reg) == -EPROBE_DEFER)
-+ pr_warn("proc regulator for cpu%d not ready, retry.\n",
-+ cpu);
-+ else
-+ pr_err("failed to get proc regulator for cpu%d\n",
-+ cpu);
-+
-+ ret = PTR_ERR(proc_reg);
-+ goto out_free_resources;
-+ }
-+
-+ ret = dev_pm_opp_of_add_table(cpu_dev);
-+ if (ret) {
-+ pr_warn("no OPP table for cpu%d\n", cpu);
-+ goto out_free_resources;
-+ }
-+
-+ /* Search a safe voltage for intermediate frequency. */
-+ rate = clk_get_rate(inter_clk);
-+ rcu_read_lock();
-+ opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate);
-+ if (IS_ERR(opp)) {
-+ rcu_read_unlock();
-+ pr_err("failed to get intermediate opp for cpu%d\n", cpu);
-+ ret = PTR_ERR(opp);
-+ goto out_free_opp_table;
-+ }
-+ info->intermediate_voltage = dev_pm_opp_get_voltage(opp);
-+ rcu_read_unlock();
-+
-+ info->cpu_dev = cpu_dev;
-+ info->proc_reg = proc_reg;
-+ info->cpu_clk = cpu_clk;
-+ info->inter_clk = inter_clk;
-+
-+ return 0;
-+
-+out_free_opp_table:
-+ dev_pm_opp_of_remove_table(cpu_dev);
-+
-+out_free_resources:
-+ if (!IS_ERR(proc_reg))
-+ regulator_put(proc_reg);
-+ if (!IS_ERR(cpu_clk))
-+ clk_put(cpu_clk);
-+ if (!IS_ERR(inter_clk))
-+ clk_put(inter_clk);
-+
-+ return ret;
-+}
-+
-+static void mtk_cpu_dvfs_info_release(struct mtk_cpu_dvfs_info *info)
-+{
-+ if (!IS_ERR(info->proc_reg))
-+ regulator_put(info->proc_reg);
-+ if (!IS_ERR(info->cpu_clk))
-+ clk_put(info->cpu_clk);
-+ if (!IS_ERR(info->inter_clk))
-+ clk_put(info->inter_clk);
-+
-+ dev_pm_opp_of_remove_table(info->cpu_dev);
-+}
-+
-+static int mtk_cpufreq_init(struct cpufreq_policy *policy)
-+{
-+ struct mtk_cpu_dvfs_info *info;
-+ struct cpufreq_frequency_table *freq_table;
-+ int ret;
-+
-+ info = kzalloc(sizeof(*info), GFP_KERNEL);
-+ if (!info)
-+ return -ENOMEM;
-+
-+ ret = mtk_cpu_dvfs_info_init(info, policy->cpu);
-+ if (ret) {
-+ pr_err("%s failed to initialize dvfs info for cpu%d\n",
-+ __func__, policy->cpu);
-+ goto out_free_dvfs_info;
-+ }
-+
-+ ret = dev_pm_opp_init_cpufreq_table(info->cpu_dev, &freq_table);
-+ if (ret) {
-+ pr_err("failed to init cpufreq table for cpu%d: %d\n",
-+ policy->cpu, ret);
-+ goto out_release_dvfs_info;
-+ }
-+
-+ ret = cpufreq_table_validate_and_show(policy, freq_table);
-+ if (ret) {
-+ pr_err("%s: invalid frequency table: %d\n", __func__, ret);
-+ goto out_free_cpufreq_table;
-+ }
-+
-+ /* CPUs in the same cluster share a clock and power domain. */
-+ cpumask_setall(policy->cpus);
-+ policy->driver_data = info;
-+ policy->clk = info->cpu_clk;
-+
-+ return 0;
-+
-+out_free_cpufreq_table:
-+ dev_pm_opp_free_cpufreq_table(info->cpu_dev, &freq_table);
-+
-+out_release_dvfs_info:
-+ mtk_cpu_dvfs_info_release(info);
-+
-+out_free_dvfs_info:
-+ kfree(info);
-+
-+ return ret;
-+}
-+
-+static int mtk_cpufreq_exit(struct cpufreq_policy *policy)
-+{
-+ struct mtk_cpu_dvfs_info *info = policy->driver_data;
-+
-+ cpufreq_cooling_unregister(info->cdev);
-+ dev_pm_opp_free_cpufreq_table(info->cpu_dev, &policy->freq_table);
-+ mtk_cpu_dvfs_info_release(info);
-+ kfree(info);
-+
-+ return 0;
-+}
-+
-+static struct cpufreq_driver mt7623_cpufreq_driver = {
-+ .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
-+ .verify = cpufreq_generic_frequency_table_verify,
-+ .target_index = mtk_cpufreq_set_target,
-+ .get = cpufreq_generic_get,
-+ .init = mtk_cpufreq_init,
-+ .exit = mtk_cpufreq_exit,
-+ .ready = mtk_cpufreq_ready,
-+ .name = "mtk-cpufreq",
-+ .attr = cpufreq_generic_attr,
-+};
-+
-+static int mt7623_cpufreq_probe(struct platform_device *pdev)
-+{
-+ int ret;
-+
-+ ret = cpufreq_register_driver(&mt7623_cpufreq_driver);
-+ if (ret)
-+ pr_err("failed to register mtk cpufreq driver\n");
-+
-+ return ret;
-+}
-+
-+static struct platform_driver mt7623_cpufreq_platdrv = {
-+ .driver = {
-+ .name = "mt7623-cpufreq",
-+ },
-+ .probe = mt7623_cpufreq_probe,
-+};
-+
-+static int mt7623_cpufreq_driver_init(void)
-+{
-+ struct platform_device *pdev;
-+ int err;
-+
-+ if (!of_machine_is_compatible("mediatek,mt7623"))
-+ return -ENODEV;
-+
-+ err = platform_driver_register(&mt7623_cpufreq_platdrv);
-+ if (err)
-+ return err;
-+
-+ /*
-+ * Since there's no place to hold device registration code and no
-+ * device tree based way to match cpufreq driver yet, both the driver
-+ * and the device registration codes are put here to handle defer
-+ * probing.
-+ */
-+ pdev = platform_device_register_simple("mt7623-cpufreq", -1, NULL, 0);
-+ if (IS_ERR(pdev)) {
-+ pr_err("failed to register mtk-cpufreq platform device\n");
-+ return PTR_ERR(pdev);
-+ }
-+
-+ return 0;
-+}
-+device_initcall(mt7623_cpufreq_driver_init);
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0063-net-mediatek-mtk_cal_txd_req-returns-bad-value.patch b/target/linux/mediatek/patches-4.4/0063-net-mediatek-mtk_cal_txd_req-returns-bad-value.patch
new file mode 100644
index 0000000000..a81f165980
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0063-net-mediatek-mtk_cal_txd_req-returns-bad-value.patch
@@ -0,0 +1,25 @@
+From d8f3e96943334c91ecc0827ed0d3232068c389e6 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Tue, 22 Mar 2016 04:42:27 +0100
+Subject: [PATCH 063/102] net: mediatek: mtk_cal_txd_req() returns bad value
+
+The code used to also support the PDMA engine, which had 2 packet pointers
+per descriptor. Because of this we have to divide the result by 2 and round
+it up. This is no longer needed as the code only supports QDMA.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -681,7 +681,7 @@ static inline int mtk_cal_txd_req(struct
+ nfrags += skb_shinfo(skb)->nr_frags;
+ }
+
+- return DIV_ROUND_UP(nfrags, 2);
++ return nfrags;
+ }
+
+ static int mtk_start_xmit(struct sk_buff *skb, struct net_device *dev)
diff --git a/target/linux/mediatek/patches-4.4/0064-arm-mediatek-make-a7-timer-work.patch b/target/linux/mediatek/patches-4.4/0064-arm-mediatek-make-a7-timer-work.patch
deleted file mode 100644
index bd3bf31c2c..0000000000
--- a/target/linux/mediatek/patches-4.4/0064-arm-mediatek-make-a7-timer-work.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-From 6eeadfb48dc5e73dae115fc0be9416e3d5fed84d Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Thu, 31 Mar 2016 06:07:01 +0200
-Subject: [PATCH 64/91] arm: mediatek: make a7 timer work Signed-off-by: John
- Crispin <blogic@openwrt.org>
-
----
- arch/arm/mach-mediatek/Kconfig | 1 +
- arch/arm/mach-mediatek/mediatek.c | 1 +
- 2 files changed, 2 insertions(+)
-
-diff --git a/arch/arm/mach-mediatek/Kconfig b/arch/arm/mach-mediatek/Kconfig
-index a7fef77..2c05bc31 100644
---- a/arch/arm/mach-mediatek/Kconfig
-+++ b/arch/arm/mach-mediatek/Kconfig
-@@ -24,6 +24,7 @@ config MACH_MT6592
- config MACH_MT7623
- bool "MediaTek MT7623 SoCs support"
- default ARCH_MEDIATEK
-+ select HAVE_ARM_ARCH_TIMER
- select MIGHT_HAVE_PCI
-
- config MACH_MT8127
-diff --git a/arch/arm/mach-mediatek/mediatek.c b/arch/arm/mach-mediatek/mediatek.c
-index bcfca37..7553a8c 100644
---- a/arch/arm/mach-mediatek/mediatek.c
-+++ b/arch/arm/mach-mediatek/mediatek.c
-@@ -29,6 +29,7 @@ static void __init mediatek_timer_init(void)
- void __iomem *gpt_base;
-
- if (of_machine_is_compatible("mediatek,mt6589") ||
-+ of_machine_is_compatible("mediatek,mt7623") ||
- of_machine_is_compatible("mediatek,mt8135") ||
- of_machine_is_compatible("mediatek,mt8127")) {
- /* turn on GPT6 which ungates arch timer clocks */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0064-net-mediatek-remove-superflous-reset-call.patch b/target/linux/mediatek/patches-4.4/0064-net-mediatek-remove-superflous-reset-call.patch
new file mode 100644
index 0000000000..434a6e38ed
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0064-net-mediatek-remove-superflous-reset-call.patch
@@ -0,0 +1,26 @@
+From 2597d2cedba62b2a3fdca9c044187705f98a0372 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Fri, 25 Mar 2016 04:24:27 +0100
+Subject: [PATCH 064/102] net: mediatek: remove superflous reset call
+
+HW reset is triggered int he mtk_hw_init() function. There is no need to
+reset the core during probe.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 ----
+ 1 file changed, 4 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -1679,10 +1679,6 @@ static int mtk_probe(struct platform_dev
+ struct mtk_eth *eth;
+ int err;
+
+- err = device_reset(&pdev->dev);
+- if (err)
+- return err;
+-
+ match = of_match_device(of_mtk_match, &pdev->dev);
+ soc = (struct mtk_soc_data *)match->data;
+
diff --git a/target/linux/mediatek/patches-4.4/0065-net-mediatek-checking-for-IS_ERR-instead-of-NULL.patch b/target/linux/mediatek/patches-4.4/0065-net-mediatek-checking-for-IS_ERR-instead-of-NULL.patch
deleted file mode 100644
index 124818ae4d..0000000000
--- a/target/linux/mediatek/patches-4.4/0065-net-mediatek-checking-for-IS_ERR-instead-of-NULL.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-From 0b88e5873b97ab20566b51134123fda7050d4d08 Mon Sep 17 00:00:00 2001
-From: Dan Carpenter <dan.carpenter@oracle.com>
-Date: Tue, 15 Mar 2016 10:18:49 +0300
-Subject: [PATCH 65/91] net: mediatek: checking for IS_ERR() instead of NULL
-
-of_phy_connect() returns NULL on error, it never returns error pointers.
-
-Fixes: 656e705243fd ('net-next: mediatek: add support for MT7623 ethernet')
-Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index ba3afa5..9759fe5 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -186,9 +186,9 @@ static int mtk_phy_connect_node(struct mtk_eth *eth, struct mtk_mac *mac,
-
- phydev = of_phy_connect(eth->netdev[mac->id], phy_node,
- mtk_phy_link_adjust, 0, phy_mode);
-- if (IS_ERR(phydev)) {
-+ if (!phydev) {
- dev_err(eth->dev, "could not connect to PHY\n");
-- return PTR_ERR(phydev);
-+ return -ENODEV;
- }
-
- dev_info(eth->dev,
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0065-net-mediatek-fix-stop-and-wakeup-of-queue.patch b/target/linux/mediatek/patches-4.4/0065-net-mediatek-fix-stop-and-wakeup-of-queue.patch
new file mode 100644
index 0000000000..1660e4204d
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0065-net-mediatek-fix-stop-and-wakeup-of-queue.patch
@@ -0,0 +1,84 @@
+From afc838dde560ab584d3fb0e4b011e4a6770dab3d Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Tue, 29 Mar 2016 16:41:07 +0200
+Subject: [PATCH 065/102] net: mediatek: fix stop and wakeup of queue
+
+The driver supports 2 MACs. Both run on the same DMA ring. If we go
+above/below the TX rings thershold value, we always need to wake/stop
+the queu of both devices. Not doing to can cause TX stalls and packet
+drops on one of the devices.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 37 +++++++++++++++++++--------
+ 1 file changed, 27 insertions(+), 10 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -684,6 +684,28 @@ static inline int mtk_cal_txd_req(struct
+ return nfrags;
+ }
+
++static void mtk_wake_queue(struct mtk_eth *eth)
++{
++ int i;
++
++ for (i = 0; i < MTK_MAC_COUNT; i++) {
++ if (!eth->netdev[i])
++ continue;
++ netif_wake_queue(eth->netdev[i]);
++ }
++}
++
++static void mtk_stop_queue(struct mtk_eth *eth)
++{
++ int i;
++
++ for (i = 0; i < MTK_MAC_COUNT; i++) {
++ if (!eth->netdev[i])
++ continue;
++ netif_stop_queue(eth->netdev[i]);
++ }
++}
++
+ static int mtk_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
+ struct mtk_mac *mac = netdev_priv(dev);
+@@ -695,7 +717,7 @@ static int mtk_start_xmit(struct sk_buff
+
+ tx_num = mtk_cal_txd_req(skb);
+ if (unlikely(atomic_read(&ring->free_count) <= tx_num)) {
+- netif_stop_queue(dev);
++ mtk_stop_queue(eth);
+ netif_err(eth, tx_queued, dev,
+ "Tx Ring full when queue awake!\n");
+ return NETDEV_TX_BUSY;
+@@ -720,10 +742,10 @@ static int mtk_start_xmit(struct sk_buff
+ goto drop;
+
+ if (unlikely(atomic_read(&ring->free_count) <= ring->thresh)) {
+- netif_stop_queue(dev);
++ mtk_stop_queue(eth);
+ if (unlikely(atomic_read(&ring->free_count) >
+ ring->thresh))
+- netif_wake_queue(dev);
++ mtk_wake_queue(eth);
+ }
+
+ return NETDEV_TX_OK;
+@@ -897,13 +919,8 @@ static int mtk_poll_tx(struct mtk_eth *e
+ if (!total)
+ return 0;
+
+- for (i = 0; i < MTK_MAC_COUNT; i++) {
+- if (!eth->netdev[i] ||
+- unlikely(!netif_queue_stopped(eth->netdev[i])))
+- continue;
+- if (atomic_read(&ring->free_count) > ring->thresh)
+- netif_wake_queue(eth->netdev[i]);
+- }
++ if (atomic_read(&ring->free_count) > ring->thresh)
++ mtk_wake_queue(eth);
+
+ return total;
+ }
diff --git a/target/linux/mediatek/patches-4.4/0066-net-mediatek-fix-mtk_pending_work.patch b/target/linux/mediatek/patches-4.4/0066-net-mediatek-fix-mtk_pending_work.patch
new file mode 100644
index 0000000000..b233578106
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0066-net-mediatek-fix-mtk_pending_work.patch
@@ -0,0 +1,58 @@
+From e2cc73e6ddb0cc39b8f58654a449651a621916a9 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Tue, 29 Mar 2016 17:00:47 +0200
+Subject: [PATCH 066/102] net: mediatek: fix mtk_pending_work
+
+The driver supports 2 MACs. Both run on the same DMA ring. If we hit a TX
+timeout we need to stop both netdevs before retarting them again. If we
+dont do thsi, mtk_stop() wont shutdown DMA and the consecutive call to
+mtk_open() wont restart DMA and enable IRQs.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 30 +++++++++++++++++++--------
+ 1 file changed, 21 insertions(+), 9 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -1430,19 +1430,31 @@ static int mtk_do_ioctl(struct net_devic
+
+ static void mtk_pending_work(struct work_struct *work)
+ {
+- struct mtk_mac *mac = container_of(work, struct mtk_mac, pending_work);
+- struct mtk_eth *eth = mac->hw;
+- struct net_device *dev = eth->netdev[mac->id];
+- int err;
++ struct mtk_eth *eth = container_of(work, struct mtk_eth, pending_work);
++ int err, i;
++ unsigned long restart = 0;
+
+ rtnl_lock();
+- mtk_stop(dev);
+
+- err = mtk_open(dev);
+- if (err) {
+- netif_alert(eth, ifup, dev,
++ /* stop all devices to make sure that dma is properly shut down */
++ for (i = 0; i < MTK_MAC_COUNT; i++) {
++ if (!netif_oper_up(eth->netdev[i]))
++ continue;
++ mtk_stop(eth->netdev[i]);
++ __set_bit(i, &restart);
++ }
++
++
++ /* restart DMA and enable IRQs */
++ for (i = 0; i < MTK_MAC_COUNT; i++) {
++ if (!test_bit(i, &restart))
++ continue;
++ err = mtk_open(eth->netdev[i]);
++ if (err) {
++ netif_alert(eth, ifup, eth->netdev[i],
+ "Driver up/down cycle failed, closing device.\n");
+- dev_close(dev);
++ dev_close(eth->netdev[i]);
++ }
+ }
+ rtnl_unlock();
+ }
diff --git a/target/linux/mediatek/patches-4.4/0066-net-mediatek-unlock-on-error-in-mtk_tx_map.patch b/target/linux/mediatek/patches-4.4/0066-net-mediatek-unlock-on-error-in-mtk_tx_map.patch
deleted file mode 100644
index 75f09d54ed..0000000000
--- a/target/linux/mediatek/patches-4.4/0066-net-mediatek-unlock-on-error-in-mtk_tx_map.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-From 489994e9cb0d9f762c31e2af9205188ae8f3b013 Mon Sep 17 00:00:00 2001
-From: Dan Carpenter <dan.carpenter@oracle.com>
-Date: Tue, 15 Mar 2016 10:19:04 +0300
-Subject: [PATCH 66/91] net: mediatek: unlock on error in mtk_tx_map()
-
-There was a missing unlock on the error path.
-
-Fixes: 656e705243fd ('net-next: mediatek: add support for MT7623 ethernet')
-Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 9759fe5..c2c2e206 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -661,6 +661,8 @@ err_dma:
- itxd = mtk_qdma_phys_to_virt(ring, itxd->txd2);
- } while (itxd != txd);
-
-+ spin_unlock_irqrestore(&eth->page_lock, flags);
-+
- return -ENOMEM;
- }
-
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0067-net-mediatek-fix-TX-locking.patch b/target/linux/mediatek/patches-4.4/0067-net-mediatek-fix-TX-locking.patch
new file mode 100644
index 0000000000..d750de6af1
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0067-net-mediatek-fix-TX-locking.patch
@@ -0,0 +1,93 @@
+From 6f152b2bdb295d86beb746494ef6fddf17986f8e Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Tue, 29 Mar 2016 17:20:01 +0200
+Subject: [PATCH 067/102] net: mediatek: fix TX locking
+
+Inside the TX path there is a lock inside the tx_map function. This is
+however too late. The patch moves the lock to the start of the xmit
+function right before the free count check of the DMA ring happens.
+If we do not do this, the code becomes racy leading to TX stalls and
+dropped packets. This happens as there are 2 netdevs running on the
+same physical DMA ring.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 20 ++++++++++----------
+ 1 file changed, 10 insertions(+), 10 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -536,7 +536,6 @@ static int mtk_tx_map(struct sk_buff *sk
+ struct mtk_eth *eth = mac->hw;
+ struct mtk_tx_dma *itxd, *txd;
+ struct mtk_tx_buf *tx_buf;
+- unsigned long flags;
+ dma_addr_t mapped_addr;
+ unsigned int nr_frags;
+ int i, n_desc = 1;
+@@ -568,11 +567,6 @@ static int mtk_tx_map(struct sk_buff *sk
+ if (unlikely(dma_mapping_error(&dev->dev, mapped_addr)))
+ return -ENOMEM;
+
+- /* normally we can rely on the stack not calling this more than once,
+- * however we have 2 queues running ont he same ring so we need to lock
+- * the ring access
+- */
+- spin_lock_irqsave(&eth->page_lock, flags);
+ WRITE_ONCE(itxd->txd1, mapped_addr);
+ tx_buf->flags |= MTK_TX_FLAGS_SINGLE0;
+ dma_unmap_addr_set(tx_buf, dma_addr0, mapped_addr);
+@@ -632,8 +626,6 @@ static int mtk_tx_map(struct sk_buff *sk
+ WRITE_ONCE(itxd->txd3, (TX_DMA_SWC | TX_DMA_PLEN0(skb_headlen(skb)) |
+ (!nr_frags * TX_DMA_LS0)));
+
+- spin_unlock_irqrestore(&eth->page_lock, flags);
+-
+ netdev_sent_queue(dev, skb->len);
+ skb_tx_timestamp(skb);
+
+@@ -661,8 +653,6 @@ err_dma:
+ itxd = mtk_qdma_phys_to_virt(ring, itxd->txd2);
+ } while (itxd != txd);
+
+- spin_unlock_irqrestore(&eth->page_lock, flags);
+-
+ return -ENOMEM;
+ }
+
+@@ -712,14 +702,22 @@ static int mtk_start_xmit(struct sk_buff
+ struct mtk_eth *eth = mac->hw;
+ struct mtk_tx_ring *ring = &eth->tx_ring;
+ struct net_device_stats *stats = &dev->stats;
++ unsigned long flags;
+ bool gso = false;
+ int tx_num;
+
++ /* normally we can rely on the stack not calling this more than once,
++ * however we have 2 queues running ont he same ring so we need to lock
++ * the ring access
++ */
++ spin_lock_irqsave(&eth->page_lock, flags);
++
+ tx_num = mtk_cal_txd_req(skb);
+ if (unlikely(atomic_read(&ring->free_count) <= tx_num)) {
+ mtk_stop_queue(eth);
+ netif_err(eth, tx_queued, dev,
+ "Tx Ring full when queue awake!\n");
++ spin_unlock_irqrestore(&eth->page_lock, flags);
+ return NETDEV_TX_BUSY;
+ }
+
+@@ -747,10 +745,12 @@ static int mtk_start_xmit(struct sk_buff
+ ring->thresh))
+ mtk_wake_queue(eth);
+ }
++ spin_unlock_irqrestore(&eth->page_lock, flags);
+
+ return NETDEV_TX_OK;
+
+ drop:
++ spin_unlock_irqrestore(&eth->page_lock, flags);
+ stats->tx_dropped++;
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
diff --git a/target/linux/mediatek/patches-4.4/0067-net-mediatek-use-dma_addr_t-correctly.patch b/target/linux/mediatek/patches-4.4/0067-net-mediatek-use-dma_addr_t-correctly.patch
deleted file mode 100644
index e86bc22544..0000000000
--- a/target/linux/mediatek/patches-4.4/0067-net-mediatek-use-dma_addr_t-correctly.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-From ac345476b98f3856bbf3938e114d4be799f8bd69 Mon Sep 17 00:00:00 2001
-From: Arnd Bergmann <arnd@arndb.de>
-Date: Mon, 14 Mar 2016 15:07:10 +0100
-Subject: [PATCH 67/91] net: mediatek: use dma_addr_t correctly
-
-dma_alloc_coherent() expects a dma_addr_t pointer as its argument,
-not an 'unsigned int', and gcc correctly warns about broken
-code in the mtk_init_fq_dma function:
-
-drivers/net/ethernet/mediatek/mtk_eth_soc.c: In function 'mtk_init_fq_dma':
-drivers/net/ethernet/mediatek/mtk_eth_soc.c:463:13: error: passing argument 3 of 'dma_alloc_coherent' from incompatible pointer type [-Werror=incompatible-pointer-types]
-
-This changes the type of the local variable to dma_addr_t.
-
-Signed-off-by: Arnd Bergmann <arnd@arndb.de>
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index c2c2e206..a005bc4 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -453,7 +453,7 @@ static inline void mtk_rx_get_desc(struct mtk_rx_dma *rxd,
- /* the qdma core needs scratch memory to be setup */
- static int mtk_init_fq_dma(struct mtk_eth *eth)
- {
-- unsigned int phy_ring_head, phy_ring_tail;
-+ dma_addr_t phy_ring_head, phy_ring_tail;
- int cnt = MTK_DMA_SIZE;
- dma_addr_t dma_addr;
- int i;
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0068-net-mediatek-move-the-pending_work-struct-to-the-dev.patch b/target/linux/mediatek/patches-4.4/0068-net-mediatek-move-the-pending_work-struct-to-the-dev.patch
new file mode 100644
index 0000000000..497309144c
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0068-net-mediatek-move-the-pending_work-struct-to-the-dev.patch
@@ -0,0 +1,102 @@
+From 29bc7a1e374425937b5dd2f316dbeef343d4c68a Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Tue, 29 Mar 2016 17:24:24 +0200
+Subject: [PATCH 068/102] net: mediatek: move the pending_work struct to the
+ device generic struct
+
+The worker always touches both netdevs. It is ethernet core and not MAC
+specific. We only need one worker, which belongs into the ethernets core struct.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 10 ++++------
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h | 4 ++--
+ 2 files changed, 6 insertions(+), 8 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -1193,7 +1193,7 @@ static void mtk_tx_timeout(struct net_de
+ eth->netdev[mac->id]->stats.tx_errors++;
+ netif_err(eth, tx_err, dev,
+ "transmit timed out\n");
+- schedule_work(&mac->pending_work);
++ schedule_work(&eth->pending_work);
+ }
+
+ static irqreturn_t mtk_handle_irq(int irq, void *_eth)
+@@ -1438,7 +1438,7 @@ static void mtk_pending_work(struct work
+
+ /* stop all devices to make sure that dma is properly shut down */
+ for (i = 0; i < MTK_MAC_COUNT; i++) {
+- if (!netif_oper_up(eth->netdev[i]))
++ if (!eth->netdev[i])
+ continue;
+ mtk_stop(eth->netdev[i]);
+ __set_bit(i, &restart);
+@@ -1464,15 +1464,13 @@ static int mtk_cleanup(struct mtk_eth *e
+ int i;
+
+ for (i = 0; i < MTK_MAC_COUNT; i++) {
+- struct mtk_mac *mac = netdev_priv(eth->netdev[i]);
+-
+ if (!eth->netdev[i])
+ continue;
+
+ unregister_netdev(eth->netdev[i]);
+ free_netdev(eth->netdev[i]);
+- cancel_work_sync(&mac->pending_work);
+ }
++ cancel_work_sync(&eth->pending_work);
+
+ return 0;
+ }
+@@ -1660,7 +1658,6 @@ static int mtk_add_mac(struct mtk_eth *e
+ mac->id = id;
+ mac->hw = eth;
+ mac->of_node = np;
+- INIT_WORK(&mac->pending_work, mtk_pending_work);
+
+ mac->hw_stats = devm_kzalloc(eth->dev,
+ sizeof(*mac->hw_stats),
+@@ -1762,6 +1759,7 @@ static int mtk_probe(struct platform_dev
+
+ eth->dev = &pdev->dev;
+ eth->msg_enable = netif_msg_init(mtk_msg_level, MTK_DEFAULT_MSG_ENABLE);
++ INIT_WORK(&eth->pending_work, mtk_pending_work);
+
+ err = mtk_hw_init(eth);
+ if (err)
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -363,6 +363,7 @@ struct mtk_rx_ring {
+ * @clk_gp1: The gmac1 clock
+ * @clk_gp2: The gmac2 clock
+ * @mii_bus: If there is a bus we need to create an instance for it
++ * @pending_work: The workqueue used to reset the dma ring
+ */
+
+ struct mtk_eth {
+@@ -389,6 +390,7 @@ struct mtk_eth {
+ struct clk *clk_gp1;
+ struct clk *clk_gp2;
+ struct mii_bus *mii_bus;
++ struct work_struct pending_work;
+ };
+
+ /* struct mtk_mac - the structure that holds the info about the MACs of the
+@@ -398,7 +400,6 @@ struct mtk_eth {
+ * @hw: Backpointer to our main datastruture
+ * @hw_stats: Packet statistics counter
+ * @phy_dev: The attached PHY if available
+- * @pending_work: The workqueue used to reset the dma ring
+ */
+ struct mtk_mac {
+ int id;
+@@ -406,7 +407,6 @@ struct mtk_mac {
+ struct mtk_eth *hw;
+ struct mtk_hw_stats *hw_stats;
+ struct phy_device *phy_dev;
+- struct work_struct pending_work;
+ };
+
+ /* the struct describing the SoC. these are declared in the soc_xyz.c files */
diff --git a/target/linux/mediatek/patches-4.4/0068-net-mediatek-remove-incorrect-dma_mask-assignment.patch b/target/linux/mediatek/patches-4.4/0068-net-mediatek-remove-incorrect-dma_mask-assignment.patch
deleted file mode 100644
index 262e5c17ba..0000000000
--- a/target/linux/mediatek/patches-4.4/0068-net-mediatek-remove-incorrect-dma_mask-assignment.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From 8b6bb80616460eda2e70e358c5fb70c0f4d4d02f Mon Sep 17 00:00:00 2001
-From: Arnd Bergmann <arnd@arndb.de>
-Date: Mon, 14 Mar 2016 15:07:11 +0100
-Subject: [PATCH 68/91] net: mediatek: remove incorrect dma_mask assignment
-
-Device drivers should not mess with the DMA mask directly,
-but instead call dma_set_mask() etc if needed.
-
-In case of the mtk_eth_soc driver, the mask already gets set
-correctly when the device is created, and setting it again
-is against the documented API.
-
-This removes the incorrect setting.
-
-Signed-off-by: Arnd Bergmann <arnd@arndb.de>
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 3 ---
- 1 file changed, 3 deletions(-)
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index a005bc4..fcd4ed7 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -1678,9 +1678,6 @@ static int mtk_probe(struct platform_device *pdev)
- struct mtk_eth *eth;
- int err;
-
-- pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
-- pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
--
- device_reset(&pdev->dev);
-
- match = of_match_device(of_mtk_match, &pdev->dev);
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0069-net-mediatek-check-device_reset-return-code.patch b/target/linux/mediatek/patches-4.4/0069-net-mediatek-check-device_reset-return-code.patch
deleted file mode 100644
index 30ead3800c..0000000000
--- a/target/linux/mediatek/patches-4.4/0069-net-mediatek-check-device_reset-return-code.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-From cd7ea7dae994beea798115f4c34c96f45cc028d1 Mon Sep 17 00:00:00 2001
-From: Arnd Bergmann <arnd@arndb.de>
-Date: Mon, 14 Mar 2016 15:07:12 +0100
-Subject: [PATCH 69/91] net: mediatek: check device_reset return code
-
-The device_reset() function may fail, so we have to check
-its return value, e.g. to make deferred probing work correctly.
-gcc warns about it because of the warn_unused_result attribute:
-
-drivers/net/ethernet/mediatek/mtk_eth_soc.c: In function 'mtk_probe':
-drivers/net/ethernet/mediatek/mtk_eth_soc.c:1679:2: error: ignoring return value of 'device_reset', declared with attribute warn_unused_result [-Werror=unused-result]
-
-This adds the trivial error check to propagate the return value
-to the generic platform device probe code.
-
-Signed-off-by: Arnd Bergmann <arnd@arndb.de>
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index fcd4ed7..7f2126b 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -1678,7 +1678,9 @@ static int mtk_probe(struct platform_device *pdev)
- struct mtk_eth *eth;
- int err;
-
-- device_reset(&pdev->dev);
-+ err = device_reset(&pdev->dev);
-+ if (err)
-+ return err;
-
- match = of_match_device(of_mtk_match, &pdev->dev);
- soc = (struct mtk_soc_data *)match->data;
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0069-net-mediatek-do-not-set-the-QID-field-in-the-TX-DMA-.patch b/target/linux/mediatek/patches-4.4/0069-net-mediatek-do-not-set-the-QID-field-in-the-TX-DMA-.patch
new file mode 100644
index 0000000000..72f96e2174
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0069-net-mediatek-do-not-set-the-QID-field-in-the-TX-DMA-.patch
@@ -0,0 +1,32 @@
+From 4742349c1595d38b3e3b463e66cf21af4217c869 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Thu, 7 Apr 2016 17:36:23 +0200
+Subject: [PATCH 069/102] net: mediatek: do not set the QID field in the TX
+ DMA descriptors
+
+The QID field gets set to the mac id. This made the DMA linked list queue
+the traffic of each MAC on a different internal queue. However during long
+term testing we found that this will cause traffic stalls as the multi
+queue setup requires a more complete initialisation which is not part of
+the upstream driver yet.
+
+This patch removes the code setting the QID field, resulting in all
+traffic ending up in queue 0 which works without any special setup.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -603,8 +603,7 @@ static int mtk_tx_map(struct sk_buff *sk
+ WRITE_ONCE(txd->txd1, mapped_addr);
+ WRITE_ONCE(txd->txd3, (TX_DMA_SWC |
+ TX_DMA_PLEN0(frag_map_size) |
+- last_frag * TX_DMA_LS0) |
+- mac->id);
++ last_frag * TX_DMA_LS0));
+ WRITE_ONCE(txd->txd4, 0);
+
+ tx_buf->skb = (struct sk_buff *)MTK_DMA_DUMMY_DESC;
diff --git a/target/linux/mediatek/patches-4.4/0070-net-mediatek-update-the-IRQ-part-of-the-binding-docu.patch b/target/linux/mediatek/patches-4.4/0070-net-mediatek-update-the-IRQ-part-of-the-binding-docu.patch
new file mode 100644
index 0000000000..efc59c06f2
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0070-net-mediatek-update-the-IRQ-part-of-the-binding-docu.patch
@@ -0,0 +1,41 @@
+From 297ef52cd21e28da671996d7b4f39f268d2d0ec1 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Tue, 29 Mar 2016 14:32:07 +0200
+Subject: [PATCH 070/102] net: mediatek: update the IRQ part of the binding
+ document
+
+The current binding document only describes a single interrupt. Update the
+document by adding the 2 other interrupts.
+
+The driver currently only uses a single interrupt. The HW is however able
+to using IRQ grouping to split TX and RX onto separate GIC irqs.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+ Acked-by: Rob Herring <robh@kernel.org>
+---
+ Documentation/devicetree/bindings/net/mediatek-net.txt | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/Documentation/devicetree/bindings/net/mediatek-net.txt
++++ b/Documentation/devicetree/bindings/net/mediatek-net.txt
+@@ -9,7 +9,8 @@ have dual GMAC each represented by a chi
+ Required properties:
+ - compatible: Should be "mediatek,mt7623-eth"
+ - reg: Address and length of the register set for the device
+-- interrupts: Should contain the frame engines interrupt
++- interrupts: Should contain the three frame engines interrupts in numeric
++ order. These are fe_int0, fe_int1 and fe_int2.
+ - clocks: the clock used by the core
+ - clock-names: the names of the clock listed in the clocks property. These are
+ "ethif", "esw", "gp2", "gp1"
+@@ -42,7 +43,9 @@ eth: ethernet@1b100000 {
+ <&ethsys CLK_ETHSYS_GP2>,
+ <&ethsys CLK_ETHSYS_GP1>;
+ clock-names = "ethif", "esw", "gp2", "gp1";
+- interrupts = <GIC_SPI 200 IRQ_TYPE_LEVEL_LOW>;
++ interrupts = <GIC_SPI 200 IRQ_TYPE_LEVEL_LOW
++ GIC_SPI 199 IRQ_TYPE_LEVEL_LOW
++ GIC_SPI 198 IRQ_TYPE_LEVEL_LOW>;
+ power-domains = <&scpsys MT2701_POWER_DOMAIN_ETH>;
+ resets = <&ethsys MT2701_ETHSYS_ETH_RST>;
+ reset-names = "eth";
diff --git a/target/linux/mediatek/patches-4.4/0070-net-mediatek-watchdog_timeo-was-not-set.patch b/target/linux/mediatek/patches-4.4/0070-net-mediatek-watchdog_timeo-was-not-set.patch
deleted file mode 100644
index a4c5e9ffd6..0000000000
--- a/target/linux/mediatek/patches-4.4/0070-net-mediatek-watchdog_timeo-was-not-set.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From 5fac03871435c52f7f9b7f34aefb2774089d32f9 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Wed, 30 Mar 2016 03:18:17 +0200
-Subject: [PATCH 70/91] net: mediatek: watchdog_timeo was not set
-
-The original commit failed to set watchdog_timeo. This patch sets
-watchdog_timeo to HZ.
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 7f2126b..7e6d2e2 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -1645,6 +1645,7 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
- mac->hw_stats->reg_offset = id * MTK_STAT_OFFSET;
-
- SET_NETDEV_DEV(eth->netdev[id], eth->dev);
-+ eth->netdev[id]->watchdog_timeo = HZ;
- eth->netdev[id]->netdev_ops = &mtk_netdev_ops;
- eth->netdev[id]->base_addr = (unsigned long)eth->base;
- eth->netdev[id]->vlan_features = MTK_HW_FEATURES &
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0071-net-mediatek-mtk_cal_txd_req-returns-bad-value.patch b/target/linux/mediatek/patches-4.4/0071-net-mediatek-mtk_cal_txd_req-returns-bad-value.patch
deleted file mode 100644
index c18fa0c996..0000000000
--- a/target/linux/mediatek/patches-4.4/0071-net-mediatek-mtk_cal_txd_req-returns-bad-value.patch
+++ /dev/null
@@ -1,30 +0,0 @@
-From ca0d5851de3763fe309d3083693f1a438c6e98c9 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Tue, 22 Mar 2016 04:42:27 +0100
-Subject: [PATCH 71/91] net: mediatek: mtk_cal_txd_req() returns bad value
-
-The code used to also support the PDMA engine, which had 2 packet pointers
-per descriptor. Because of this we have to divide the result by 2 and round
-it up. This is no longer needed as the code only supports QDMA.
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 7e6d2e2..4d8d0a3 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -681,7 +681,7 @@ static inline int mtk_cal_txd_req(struct sk_buff *skb)
- nfrags += skb_shinfo(skb)->nr_frags;
- }
-
-- return DIV_ROUND_UP(nfrags, 2);
-+ return nfrags;
- }
-
- static int mtk_start_xmit(struct sk_buff *skb, struct net_device *dev)
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0071-pwm-add-pwm-mediatek.patch b/target/linux/mediatek/patches-4.4/0071-pwm-add-pwm-mediatek.patch
new file mode 100644
index 0000000000..8ca6c491e9
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0071-pwm-add-pwm-mediatek.patch
@@ -0,0 +1,337 @@
+From 6f5941c93bdf7649f392f1263b9068d360ceab4d Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Fri, 6 May 2016 02:55:48 +0200
+Subject: [PATCH 071/102] pwm: add pwm-mediatek
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ arch/arm/boot/dts/mt7623-evb.dts | 17 +++
+ arch/arm/boot/dts/mt7623.dtsi | 22 ++++
+ drivers/pwm/Kconfig | 9 ++
+ drivers/pwm/Makefile | 1 +
+ drivers/pwm/pwm-mediatek.c | 230 ++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 279 insertions(+)
+ create mode 100644 drivers/pwm/pwm-mediatek.c
+
+--- a/arch/arm/boot/dts/mt7623-evb.dts
++++ b/arch/arm/boot/dts/mt7623-evb.dts
+@@ -341,6 +341,17 @@
+ output-low;
+ };
+ };
++
++ pwm_pins: pwm {
++ pins_pwm1 {
++ pinmux = <MT7623_PIN_204_PWM1_FUNC_PWM1>;
++ };
++
++ pins_pwm2 {
++ pinmux = <MT7623_PIN_205_PWM2_FUNC_PWM2>;
++ };
++ };
++
+ };
+
+ &nandc {
+@@ -419,3 +430,9 @@
+ mediatek,reset-pin = <&pio 15 0>;
+ status = "okay";
+ };
++
++&pwm {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pwm_pins>;
++ status = "okay";
++};
+--- a/arch/arm/boot/dts/mt7623.dtsi
++++ b/arch/arm/boot/dts/mt7623.dtsi
+@@ -324,6 +324,28 @@
+ status = "disabled";
+ };
+
++ pwm: pwm@11006000 {
++ compatible = "mediatek,mt7623-pwm";
++
++ reg = <0 0x11006000 0 0x1000>;
++
++ resets = <&pericfg MT2701_PERI_PWM_SW_RST>;
++ reset-names = "pwm";
++
++ #pwm-cells = <2>;
++ clocks = <&topckgen CLK_TOP_PWM_SEL>,
++ <&pericfg CLK_PERI_PWM>,
++ <&pericfg CLK_PERI_PWM1>,
++ <&pericfg CLK_PERI_PWM2>,
++ <&pericfg CLK_PERI_PWM3>,
++ <&pericfg CLK_PERI_PWM4>,
++ <&pericfg CLK_PERI_PWM5>;
++ clock-names = "top", "main", "pwm1", "pwm2",
++ "pwm3", "pwm4", "pwm5";
++
++ status = "disabled";
++ };
++
+ spi: spi@1100a000 {
+ compatible = "mediatek,mt7623-spi", "mediatek,mt6589-spi";
+ reg = <0 0x1100a000 0 0x1000>;
+--- a/drivers/pwm/Kconfig
++++ b/drivers/pwm/Kconfig
+@@ -260,6 +260,15 @@ config PWM_MTK_DISP
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-mtk-disp.
+
++config PWM_MEDIATEK
++ tristate "MediaTek PWM support"
++ depends on ARCH_MEDIATEK || COMPILE_TEST
++ help
++ Generic PWM framework driver for Mediatek ARM SoC.
++
++ To compile this driver as a module, choose M here: the module
++ will be called pwm-mxs.
++
+ config PWM_MXS
+ tristate "Freescale MXS PWM support"
+ depends on ARCH_MXS && OF
+--- a/drivers/pwm/Makefile
++++ b/drivers/pwm/Makefile
+@@ -22,6 +22,7 @@ obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx
+ obj-$(CONFIG_PWM_LPSS) += pwm-lpss.o
+ obj-$(CONFIG_PWM_LPSS_PCI) += pwm-lpss-pci.o
+ obj-$(CONFIG_PWM_LPSS_PLATFORM) += pwm-lpss-platform.o
++obj-$(CONFIG_PWM_MEDIATEK) += pwm-mediatek.o
+ obj-$(CONFIG_PWM_MTK_DISP) += pwm-mtk-disp.o
+ obj-$(CONFIG_PWM_MXS) += pwm-mxs.o
+ obj-$(CONFIG_PWM_PCA9685) += pwm-pca9685.o
+--- /dev/null
++++ b/drivers/pwm/pwm-mediatek.c
+@@ -0,0 +1,230 @@
++/*
++ * Mediatek Pulse Width Modulator driver
++ *
++ * Copyright (C) 2015 John Crispin <blogic@openwrt.org>
++ *
++ * This file is licensed under the terms of the GNU General Public
++ * License version 2. This program is licensed "as is" without any
++ * warranty of any kind, whether express or implied.
++ */
++
++#include <linux/err.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/clk.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/pwm.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++
++#define NUM_PWM 5
++
++/* PWM registers and bits definitions */
++#define PWMCON 0x00
++#define PWMHDUR 0x04
++#define PWMLDUR 0x08
++#define PWMGDUR 0x0c
++#define PWMWAVENUM 0x28
++#define PWMDWIDTH 0x2c
++#define PWMTHRES 0x30
++
++/**
++ * struct mtk_pwm_chip - struct representing pwm chip
++ *
++ * @mmio_base: base address of pwm chip
++ * @chip: linux pwm chip representation
++ */
++struct mtk_pwm_chip {
++ void __iomem *mmio_base;
++ struct pwm_chip chip;
++ struct clk *clk_top;
++ struct clk *clk_main;
++ struct clk *clk_pwm[NUM_PWM];
++};
++
++static inline struct mtk_pwm_chip *to_mtk_pwm_chip(struct pwm_chip *chip)
++{
++ return container_of(chip, struct mtk_pwm_chip, chip);
++}
++
++static inline u32 mtk_pwm_readl(struct mtk_pwm_chip *chip, unsigned int num,
++ unsigned long offset)
++{
++ return ioread32(chip->mmio_base + 0x10 + (num * 0x40) + offset);
++}
++
++static inline void mtk_pwm_writel(struct mtk_pwm_chip *chip,
++ unsigned int num, unsigned long offset,
++ unsigned long val)
++{
++ iowrite32(val, chip->mmio_base + 0x10 + (num * 0x40) + offset);
++}
++
++static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
++ int duty_ns, int period_ns)
++{
++ struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
++ u32 resolution = 100 / 4;
++ u32 clkdiv = 0;
++
++ resolution = 1000000000 / (clk_get_rate(pc->clk_pwm[pwm->hwpwm]));
++
++ while (period_ns / resolution > 8191) {
++ clkdiv++;
++ resolution *= 2;
++ }
++
++ if (clkdiv > 7)
++ return -1;
++
++ mtk_pwm_writel(pc, pwm->hwpwm, PWMCON, BIT(15) | BIT(3) | clkdiv);
++ mtk_pwm_writel(pc, pwm->hwpwm, PWMDWIDTH, period_ns / resolution);
++ mtk_pwm_writel(pc, pwm->hwpwm, PWMTHRES, duty_ns / resolution);
++ return 0;
++}
++
++static int mtk_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
++{
++ struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
++ u32 val;
++ int ret;
++
++ ret = clk_prepare(pc->clk_pwm[pwm->hwpwm]);
++ if (ret < 0)
++ return ret;
++
++ val = ioread32(pc->mmio_base);
++ val |= BIT(pwm->hwpwm);
++ iowrite32(val, pc->mmio_base);
++
++ return 0;
++}
++
++static void mtk_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
++{
++ struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
++ u32 val;
++
++ val = ioread32(pc->mmio_base);
++ val &= ~BIT(pwm->hwpwm);
++ iowrite32(val, pc->mmio_base);
++ clk_unprepare(pc->clk_pwm[pwm->hwpwm]);
++}
++
++static const struct pwm_ops mtk_pwm_ops = {
++ .config = mtk_pwm_config,
++ .enable = mtk_pwm_enable,
++ .disable = mtk_pwm_disable,
++ .owner = THIS_MODULE,
++};
++
++static int mtk_pwm_probe(struct platform_device *pdev)
++{
++ struct mtk_pwm_chip *pc;
++ struct resource *r;
++ int ret;
++
++ pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
++ if (!pc)
++ return -ENOMEM;
++
++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ pc->mmio_base = devm_ioremap_resource(&pdev->dev, r);
++ if (IS_ERR(pc->mmio_base))
++ return PTR_ERR(pc->mmio_base);
++
++ pc->clk_main = devm_clk_get(&pdev->dev, "main");
++ if (IS_ERR(pc->clk_main))
++ return PTR_ERR(pc->clk_main);
++
++ pc->clk_top = devm_clk_get(&pdev->dev, "top");
++ if (IS_ERR(pc->clk_top))
++ return PTR_ERR(pc->clk_top);
++
++ pc->clk_pwm[0] = devm_clk_get(&pdev->dev, "pwm1");
++ if (IS_ERR(pc->clk_pwm[0]))
++ return PTR_ERR(pc->clk_pwm[0]);
++
++ pc->clk_pwm[1] = devm_clk_get(&pdev->dev, "pwm2");
++ if (IS_ERR(pc->clk_pwm[1]))
++ return PTR_ERR(pc->clk_pwm[1]);
++
++ pc->clk_pwm[2] = devm_clk_get(&pdev->dev, "pwm3");
++ if (IS_ERR(pc->clk_pwm[2]))
++ return PTR_ERR(pc->clk_pwm[2]);
++
++ pc->clk_pwm[3] = devm_clk_get(&pdev->dev, "pwm4");
++ if (IS_ERR(pc->clk_pwm[3]))
++ return PTR_ERR(pc->clk_pwm[3]);
++
++ pc->clk_pwm[4] = devm_clk_get(&pdev->dev, "pwm5");
++ if (IS_ERR(pc->clk_pwm[4]))
++ return PTR_ERR(pc->clk_pwm[4]);
++
++ ret = clk_prepare(pc->clk_top);
++ if (ret < 0)
++ return ret;
++
++ ret = clk_prepare(pc->clk_main);
++ if (ret < 0)
++ goto disable_clk_top;
++
++ platform_set_drvdata(pdev, pc);
++
++ pc->chip.dev = &pdev->dev;
++ pc->chip.ops = &mtk_pwm_ops;
++ pc->chip.base = -1;
++ pc->chip.npwm = NUM_PWM;
++
++ ret = pwmchip_add(&pc->chip);
++ if (ret < 0) {
++ dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
++ goto disable_clk_main;
++ }
++
++ return 0;
++
++disable_clk_main:
++ clk_unprepare(pc->clk_main);
++disable_clk_top:
++ clk_unprepare(pc->clk_top);
++
++ return ret;
++}
++
++static int mtk_pwm_remove(struct platform_device *pdev)
++{
++ struct mtk_pwm_chip *pc = platform_get_drvdata(pdev);
++ int i;
++
++ for (i = 0; i < NUM_PWM; i++)
++ pwm_disable(&pc->chip.pwms[i]);
++
++ return pwmchip_remove(&pc->chip);
++}
++
++static const struct of_device_id mtk_pwm_of_match[] = {
++ { .compatible = "mediatek,mt7623-pwm" },
++ { }
++};
++
++MODULE_DEVICE_TABLE(of, mtk_pwm_of_match);
++
++static struct platform_driver mtk_pwm_driver = {
++ .driver = {
++ .name = "mtk-pwm",
++ .owner = THIS_MODULE,
++ .of_match_table = mtk_pwm_of_match,
++ },
++ .probe = mtk_pwm_probe,
++ .remove = mtk_pwm_remove,
++};
++
++module_platform_driver(mtk_pwm_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
++MODULE_ALIAS("platform:mtk-pwm");
diff --git a/target/linux/mediatek/patches-4.4/0072-mtd-backport-v4.7-0day-patches-from-Boris.patch b/target/linux/mediatek/patches-4.4/0072-mtd-backport-v4.7-0day-patches-from-Boris.patch
new file mode 100644
index 0000000000..ccbf8d0fb2
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0072-mtd-backport-v4.7-0day-patches-from-Boris.patch
@@ -0,0 +1,5489 @@
+From a369af5149e6eb442b22ce89b564dd7a76e03638 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Tue, 26 Apr 2016 19:05:01 +0200
+Subject: [PATCH 072/102] mtd: backport v4.7-0day patches from Boris
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/mtd/Kconfig | 4 +-
+ drivers/mtd/cmdlinepart.c | 3 +-
+ drivers/mtd/devices/m25p80.c | 44 +--
+ drivers/mtd/maps/physmap_of.c | 6 +-
+ drivers/mtd/mtdchar.c | 123 ++++++--
+ drivers/mtd/mtdconcat.c | 2 +-
+ drivers/mtd/mtdcore.c | 428 ++++++++++++++++++++++++--
+ drivers/mtd/mtdcore.h | 7 +-
+ drivers/mtd/mtdpart.c | 161 ++++++----
+ drivers/mtd/mtdswap.c | 24 +-
+ drivers/mtd/nand/Kconfig | 21 +-
+ drivers/mtd/nand/Makefile | 2 +
+ drivers/mtd/nand/nand_base.c | 571 +++++++++++++++++++----------------
+ drivers/mtd/nand/nand_bbt.c | 34 +--
+ drivers/mtd/nand/nand_bch.c | 52 ++--
+ drivers/mtd/nand/nand_ecc.c | 6 +-
+ drivers/mtd/nand/nand_ids.c | 4 +-
+ drivers/mtd/nand/nandsim.c | 43 +--
+ drivers/mtd/ofpart.c | 53 ++--
+ drivers/mtd/spi-nor/Kconfig | 10 +-
+ drivers/mtd/spi-nor/Makefile | 1 +
+ drivers/mtd/spi-nor/mtk-quadspi.c | 485 +++++++++++++++++++++++++++++
+ drivers/mtd/spi-nor/spi-nor.c | 321 +++++++++++++-------
+ drivers/mtd/tests/mtd_nandecctest.c | 2 +-
+ drivers/mtd/tests/oobtest.c | 49 ++-
+ drivers/mtd/tests/pagetest.c | 3 +-
+ drivers/mtd/ubi/cdev.c | 4 +-
+ drivers/mtd/ubi/misc.c | 49 +++
+ drivers/mtd/ubi/ubi.h | 16 +-
+ drivers/mtd/ubi/upd.c | 2 +-
+ drivers/mtd/ubi/wl.c | 21 +-
+ include/linux/mtd/bbm.h | 1 -
+ include/linux/mtd/fsmc.h | 18 --
+ include/linux/mtd/inftl.h | 1 -
+ include/linux/mtd/map.h | 9 +-
+ include/linux/mtd/mtd.h | 80 ++++-
+ include/linux/mtd/nand.h | 94 ++++--
+ include/linux/mtd/nand_bch.h | 10 +-
+ include/linux/mtd/nftl.h | 1 -
+ include/linux/mtd/onenand.h | 2 -
+ include/linux/mtd/partitions.h | 27 +-
+ include/linux/mtd/sh_flctl.h | 4 +-
+ include/linux/mtd/sharpsl.h | 2 +-
+ include/linux/mtd/spi-nor.h | 23 +-
+ include/uapi/mtd/mtd-abi.h | 2 +-
+ 45 files changed, 2077 insertions(+), 748 deletions(-)
+ create mode 100644 drivers/mtd/spi-nor/mtk-quadspi.c
+
+--- a/drivers/mtd/Kconfig
++++ b/drivers/mtd/Kconfig
+@@ -131,7 +131,7 @@ config MTD_CMDLINE_PARTS
+
+ config MTD_AFS_PARTS
+ tristate "ARM Firmware Suite partition parsing"
+- depends on ARM
++ depends on (ARM || ARM64)
+ ---help---
+ The ARM Firmware Suite allows the user to divide flash devices into
+ multiple 'images'. Each such image has a header containing its name
+@@ -161,7 +161,7 @@ config MTD_AR7_PARTS
+
+ config MTD_BCM63XX_PARTS
+ tristate "BCM63XX CFE partitioning support"
+- depends on BCM63XX
++ depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST
+ select CRC32
+ help
+ This provides partions parsing for BCM63xx devices with CFE
+--- a/drivers/mtd/cmdlinepart.c
++++ b/drivers/mtd/cmdlinepart.c
+@@ -304,7 +304,7 @@ static int mtdpart_setup_real(char *s)
+ * the first one in the chain if a NULL mtd_id is passed in.
+ */
+ static int parse_cmdline_partitions(struct mtd_info *master,
+- struct mtd_partition **pparts,
++ const struct mtd_partition **pparts,
+ struct mtd_part_parser_data *data)
+ {
+ unsigned long long offset;
+@@ -382,7 +382,6 @@ static int __init mtdpart_setup(char *s)
+ __setup("mtdparts=", mtdpart_setup);
+
+ static struct mtd_part_parser cmdline_parser = {
+- .owner = THIS_MODULE,
+ .parse_fn = parse_cmdline_partitions,
+ .name = "cmdlinepart",
+ };
+--- a/drivers/mtd/devices/m25p80.c
++++ b/drivers/mtd/devices/m25p80.c
+@@ -174,22 +174,6 @@ static int m25p80_read(struct spi_nor *n
+ return 0;
+ }
+
+-static int m25p80_erase(struct spi_nor *nor, loff_t offset)
+-{
+- struct m25p *flash = nor->priv;
+-
+- dev_dbg(nor->dev, "%dKiB at 0x%08x\n",
+- flash->spi_nor.mtd.erasesize / 1024, (u32)offset);
+-
+- /* Set up command buffer. */
+- flash->command[0] = nor->erase_opcode;
+- m25p_addr2cmd(nor, offset, flash->command);
+-
+- spi_write(flash->spi, flash->command, m25p_cmdsz(nor));
+-
+- return 0;
+-}
+-
+ /*
+ * board specific setup should have ensured the SPI clock used here
+ * matches what the READ command supports, at least until this driver
+@@ -197,12 +181,11 @@ static int m25p80_erase(struct spi_nor *
+ */
+ static int m25p_probe(struct spi_device *spi)
+ {
+- struct mtd_part_parser_data ppdata;
+ struct flash_platform_data *data;
+ struct m25p *flash;
+ struct spi_nor *nor;
+ enum read_mode mode = SPI_NOR_NORMAL;
+- char *flash_name = NULL;
++ char *flash_name;
+ int ret;
+
+ data = dev_get_platdata(&spi->dev);
+@@ -216,12 +199,11 @@ static int m25p_probe(struct spi_device
+ /* install the hooks */
+ nor->read = m25p80_read;
+ nor->write = m25p80_write;
+- nor->erase = m25p80_erase;
+ nor->write_reg = m25p80_write_reg;
+ nor->read_reg = m25p80_read_reg;
+
+ nor->dev = &spi->dev;
+- nor->flash_node = spi->dev.of_node;
++ spi_nor_set_flash_node(nor, spi->dev.of_node);
+ nor->priv = flash;
+
+ spi_set_drvdata(spi, flash);
+@@ -242,6 +224,8 @@ static int m25p_probe(struct spi_device
+ */
+ if (data && data->type)
+ flash_name = data->type;
++ else if (!strcmp(spi->modalias, "spi-nor"))
++ flash_name = NULL; /* auto-detect */
+ else
+ flash_name = spi->modalias;
+
+@@ -249,11 +233,8 @@ static int m25p_probe(struct spi_device
+ if (ret)
+ return ret;
+
+- ppdata.of_node = spi->dev.of_node;
+-
+- return mtd_device_parse_register(&nor->mtd, NULL, &ppdata,
+- data ? data->parts : NULL,
+- data ? data->nr_parts : 0);
++ return mtd_device_register(&nor->mtd, data ? data->parts : NULL,
++ data ? data->nr_parts : 0);
+ }
+
+
+@@ -279,14 +260,21 @@ static int m25p_remove(struct spi_device
+ */
+ static const struct spi_device_id m25p_ids[] = {
+ /*
++ * Allow non-DT platform devices to bind to the "spi-nor" modalias, and
++ * hack around the fact that the SPI core does not provide uevent
++ * matching for .of_match_table
++ */
++ {"spi-nor"},
++
++ /*
+ * Entries not used in DTs that should be safe to drop after replacing
+- * them with "nor-jedec" in platform data.
++ * them with "spi-nor" in platform data.
+ */
+ {"s25sl064a"}, {"w25x16"}, {"m25p10"}, {"m25px64"},
+
+ /*
+- * Entries that were used in DTs without "nor-jedec" fallback and should
+- * be kept for backward compatibility.
++ * Entries that were used in DTs without "jedec,spi-nor" fallback and
++ * should be kept for backward compatibility.
+ */
+ {"at25df321a"}, {"at25df641"}, {"at26df081a"},
+ {"mr25h256"},
+--- a/drivers/mtd/maps/physmap_of.c
++++ b/drivers/mtd/maps/physmap_of.c
+@@ -128,7 +128,6 @@ static int of_flash_probe(struct platfor
+ int reg_tuple_size;
+ struct mtd_info **mtd_list = NULL;
+ resource_size_t res_size;
+- struct mtd_part_parser_data ppdata;
+ bool map_indirect;
+ const char *mtd_name = NULL;
+
+@@ -272,8 +271,9 @@ static int of_flash_probe(struct platfor
+ if (err)
+ goto err_out;
+
+- ppdata.of_node = dp;
+- mtd_device_parse_register(info->cmtd, part_probe_types_def, &ppdata,
++ info->cmtd->dev.parent = &dev->dev;
++ mtd_set_of_node(info->cmtd, dp);
++ mtd_device_parse_register(info->cmtd, part_probe_types_def, NULL,
+ NULL, 0);
+
+ kfree(mtd_list);
+--- a/drivers/mtd/mtdchar.c
++++ b/drivers/mtd/mtdchar.c
+@@ -465,38 +465,111 @@ static int mtdchar_readoob(struct file *
+ }
+
+ /*
+- * Copies (and truncates, if necessary) data from the larger struct,
+- * nand_ecclayout, to the smaller, deprecated layout struct,
+- * nand_ecclayout_user. This is necessary only to support the deprecated
+- * API ioctl ECCGETLAYOUT while allowing all new functionality to use
+- * nand_ecclayout flexibly (i.e. the struct may change size in new
+- * releases without requiring major rewrites).
++ * Copies (and truncates, if necessary) OOB layout information to the
++ * deprecated layout struct, nand_ecclayout_user. This is necessary only to
++ * support the deprecated API ioctl ECCGETLAYOUT while allowing all new
++ * functionality to use mtd_ooblayout_ops flexibly (i.e. mtd_ooblayout_ops
++ * can describe any kind of OOB layout with almost zero overhead from a
++ * memory usage point of view).
+ */
+-static int shrink_ecclayout(const struct nand_ecclayout *from,
+- struct nand_ecclayout_user *to)
++static int shrink_ecclayout(struct mtd_info *mtd,
++ struct nand_ecclayout_user *to)
+ {
+- int i;
++ struct mtd_oob_region oobregion;
++ int i, section = 0, ret;
+
+- if (!from || !to)
++ if (!mtd || !to)
+ return -EINVAL;
+
+ memset(to, 0, sizeof(*to));
+
+- to->eccbytes = min((int)from->eccbytes, MTD_MAX_ECCPOS_ENTRIES);
+- for (i = 0; i < to->eccbytes; i++)
+- to->eccpos[i] = from->eccpos[i];
++ to->eccbytes = 0;
++ for (i = 0; i < MTD_MAX_ECCPOS_ENTRIES;) {
++ u32 eccpos;
++
++ ret = mtd_ooblayout_ecc(mtd, section, &oobregion);
++ if (ret < 0) {
++ if (ret != -ERANGE)
++ return ret;
++
++ break;
++ }
++
++ eccpos = oobregion.offset;
++ for (; i < MTD_MAX_ECCPOS_ENTRIES &&
++ eccpos < oobregion.offset + oobregion.length; i++) {
++ to->eccpos[i] = eccpos++;
++ to->eccbytes++;
++ }
++ }
+
+ for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES; i++) {
+- if (from->oobfree[i].length == 0 &&
+- from->oobfree[i].offset == 0)
++ ret = mtd_ooblayout_free(mtd, i, &oobregion);
++ if (ret < 0) {
++ if (ret != -ERANGE)
++ return ret;
++
+ break;
+- to->oobavail += from->oobfree[i].length;
+- to->oobfree[i] = from->oobfree[i];
++ }
++
++ to->oobfree[i].offset = oobregion.offset;
++ to->oobfree[i].length = oobregion.length;
++ to->oobavail += to->oobfree[i].length;
+ }
+
+ return 0;
+ }
+
++static int get_oobinfo(struct mtd_info *mtd, struct nand_oobinfo *to)
++{
++ struct mtd_oob_region oobregion;
++ int i, section = 0, ret;
++
++ if (!mtd || !to)
++ return -EINVAL;
++
++ memset(to, 0, sizeof(*to));
++
++ to->eccbytes = 0;
++ for (i = 0; i < ARRAY_SIZE(to->eccpos);) {
++ u32 eccpos;
++
++ ret = mtd_ooblayout_ecc(mtd, section, &oobregion);
++ if (ret < 0) {
++ if (ret != -ERANGE)
++ return ret;
++
++ break;
++ }
++
++ if (oobregion.length + i > ARRAY_SIZE(to->eccpos))
++ return -EINVAL;
++
++ eccpos = oobregion.offset;
++ for (; eccpos < oobregion.offset + oobregion.length; i++) {
++ to->eccpos[i] = eccpos++;
++ to->eccbytes++;
++ }
++ }
++
++ for (i = 0; i < 8; i++) {
++ ret = mtd_ooblayout_free(mtd, i, &oobregion);
++ if (ret < 0) {
++ if (ret != -ERANGE)
++ return ret;
++
++ break;
++ }
++
++ to->oobfree[i][0] = oobregion.offset;
++ to->oobfree[i][1] = oobregion.length;
++ }
++
++ to->useecc = MTD_NANDECC_AUTOPLACE;
++
++ return 0;
++}
++
+ static int mtdchar_blkpg_ioctl(struct mtd_info *mtd,
+ struct blkpg_ioctl_arg *arg)
+ {
+@@ -815,16 +888,12 @@ static int mtdchar_ioctl(struct file *fi
+ {
+ struct nand_oobinfo oi;
+
+- if (!mtd->ecclayout)
++ if (!mtd->ooblayout)
+ return -EOPNOTSUPP;
+- if (mtd->ecclayout->eccbytes > ARRAY_SIZE(oi.eccpos))
+- return -EINVAL;
+
+- oi.useecc = MTD_NANDECC_AUTOPLACE;
+- memcpy(&oi.eccpos, mtd->ecclayout->eccpos, sizeof(oi.eccpos));
+- memcpy(&oi.oobfree, mtd->ecclayout->oobfree,
+- sizeof(oi.oobfree));
+- oi.eccbytes = mtd->ecclayout->eccbytes;
++ ret = get_oobinfo(mtd, &oi);
++ if (ret)
++ return ret;
+
+ if (copy_to_user(argp, &oi, sizeof(struct nand_oobinfo)))
+ return -EFAULT;
+@@ -913,14 +982,14 @@ static int mtdchar_ioctl(struct file *fi
+ {
+ struct nand_ecclayout_user *usrlay;
+
+- if (!mtd->ecclayout)
++ if (!mtd->ooblayout)
+ return -EOPNOTSUPP;
+
+ usrlay = kmalloc(sizeof(*usrlay), GFP_KERNEL);
+ if (!usrlay)
+ return -ENOMEM;
+
+- shrink_ecclayout(mtd->ecclayout, usrlay);
++ shrink_ecclayout(mtd, usrlay);
+
+ if (copy_to_user(argp, usrlay, sizeof(*usrlay)))
+ ret = -EFAULT;
+--- a/drivers/mtd/mtdconcat.c
++++ b/drivers/mtd/mtdconcat.c
+@@ -777,7 +777,7 @@ struct mtd_info *mtd_concat_create(struc
+
+ }
+
+- concat->mtd.ecclayout = subdev[0]->ecclayout;
++ mtd_set_ooblayout(&concat->mtd, subdev[0]->ooblayout);
+
+ concat->num_subdev = num_devs;
+ concat->mtd.name = name;
+--- a/drivers/mtd/mtdcore.c
++++ b/drivers/mtd/mtdcore.c
+@@ -32,6 +32,7 @@
+ #include <linux/err.h>
+ #include <linux/ioctl.h>
+ #include <linux/init.h>
++#include <linux/of.h>
+ #include <linux/proc_fs.h>
+ #include <linux/idr.h>
+ #include <linux/backing-dev.h>
+@@ -446,6 +447,7 @@ int add_mtd_device(struct mtd_info *mtd)
+ mtd->dev.devt = MTD_DEVT(i);
+ dev_set_name(&mtd->dev, "mtd%d", i);
+ dev_set_drvdata(&mtd->dev, mtd);
++ of_node_get(mtd_get_of_node(mtd));
+ error = device_register(&mtd->dev);
+ if (error)
+ goto fail_added;
+@@ -477,6 +479,7 @@ int add_mtd_device(struct mtd_info *mtd)
+ return 0;
+
+ fail_added:
++ of_node_put(mtd_get_of_node(mtd));
+ idr_remove(&mtd_idr, i);
+ fail_locked:
+ mutex_unlock(&mtd_table_mutex);
+@@ -518,6 +521,7 @@ int del_mtd_device(struct mtd_info *mtd)
+ device_unregister(&mtd->dev);
+
+ idr_remove(&mtd_idr, mtd->index);
++ of_node_put(mtd_get_of_node(mtd));
+
+ module_put(THIS_MODULE);
+ ret = 0;
+@@ -529,9 +533,10 @@ out_error:
+ }
+
+ static int mtd_add_device_partitions(struct mtd_info *mtd,
+- struct mtd_partition *real_parts,
+- int nbparts)
++ struct mtd_partitions *parts)
+ {
++ const struct mtd_partition *real_parts = parts->parts;
++ int nbparts = parts->nr_parts;
+ int ret;
+
+ if (nbparts == 0 || IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) {
+@@ -600,29 +605,29 @@ int mtd_device_parse_register(struct mtd
+ const struct mtd_partition *parts,
+ int nr_parts)
+ {
++ struct mtd_partitions parsed;
+ int ret;
+- struct mtd_partition *real_parts = NULL;
+
+ mtd_set_dev_defaults(mtd);
+
+- ret = parse_mtd_partitions(mtd, types, &real_parts, parser_data);
+- if (ret <= 0 && nr_parts && parts) {
+- real_parts = kmemdup(parts, sizeof(*parts) * nr_parts,
+- GFP_KERNEL);
+- if (!real_parts)
+- ret = -ENOMEM;
+- else
+- ret = nr_parts;
+- }
+- /* Didn't come up with either parsed OR fallback partitions */
+- if (ret < 0) {
+- pr_info("mtd: failed to find partitions; one or more parsers reports errors (%d)\n",
++ memset(&parsed, 0, sizeof(parsed));
++
++ ret = parse_mtd_partitions(mtd, types, &parsed, parser_data);
++ if ((ret < 0 || parsed.nr_parts == 0) && parts && nr_parts) {
++ /* Fall back to driver-provided partitions */
++ parsed = (struct mtd_partitions){
++ .parts = parts,
++ .nr_parts = nr_parts,
++ };
++ } else if (ret < 0) {
++ /* Didn't come up with parsed OR fallback partitions */
++ pr_info("mtd: failed to find partitions; one or more parsers reports errors (%d)\n",
+ ret);
+ /* Don't abort on errors; we can still use unpartitioned MTD */
+- ret = 0;
++ memset(&parsed, 0, sizeof(parsed));
+ }
+
+- ret = mtd_add_device_partitions(mtd, real_parts, ret);
++ ret = mtd_add_device_partitions(mtd, &parsed);
+ if (ret)
+ goto out;
+
+@@ -642,7 +647,8 @@ int mtd_device_parse_register(struct mtd
+ }
+
+ out:
+- kfree(real_parts);
++ /* Cleanup any parsed partitions */
++ mtd_part_parser_cleanup(&parsed);
+ return ret;
+ }
+ EXPORT_SYMBOL_GPL(mtd_device_parse_register);
+@@ -767,7 +773,6 @@ out:
+ }
+ EXPORT_SYMBOL_GPL(get_mtd_device);
+
+-
+ int __get_mtd_device(struct mtd_info *mtd)
+ {
+ int err;
+@@ -1001,6 +1006,366 @@ int mtd_read_oob(struct mtd_info *mtd, l
+ }
+ EXPORT_SYMBOL_GPL(mtd_read_oob);
+
++/**
++ * mtd_ooblayout_ecc - Get the OOB region definition of a specific ECC section
++ * @mtd: MTD device structure
++ * @section: ECC section. Depending on the layout you may have all the ECC
++ * bytes stored in a single contiguous section, or one section
++ * per ECC chunk (and sometime several sections for a single ECC
++ * ECC chunk)
++ * @oobecc: OOB region struct filled with the appropriate ECC position
++ * information
++ *
++ * This functions return ECC section information in the OOB area. I you want
++ * to get all the ECC bytes information, then you should call
++ * mtd_ooblayout_ecc(mtd, section++, oobecc) until it returns -ERANGE.
++ *
++ * Returns zero on success, a negative error code otherwise.
++ */
++int mtd_ooblayout_ecc(struct mtd_info *mtd, int section,
++ struct mtd_oob_region *oobecc)
++{
++ memset(oobecc, 0, sizeof(*oobecc));
++
++ if (!mtd || section < 0)
++ return -EINVAL;
++
++ if (!mtd->ooblayout || !mtd->ooblayout->ecc)
++ return -ENOTSUPP;
++
++ return mtd->ooblayout->ecc(mtd, section, oobecc);
++}
++EXPORT_SYMBOL_GPL(mtd_ooblayout_ecc);
++
++/**
++ * mtd_ooblayout_free - Get the OOB region definition of a specific free
++ * section
++ * @mtd: MTD device structure
++ * @section: Free section you are interested in. Depending on the layout
++ * you may have all the free bytes stored in a single contiguous
++ * section, or one section per ECC chunk plus an extra section
++ * for the remaining bytes (or other funky layout).
++ * @oobfree: OOB region struct filled with the appropriate free position
++ * information
++ *
++ * This functions return free bytes position in the OOB area. I you want
++ * to get all the free bytes information, then you should call
++ * mtd_ooblayout_free(mtd, section++, oobfree) until it returns -ERANGE.
++ *
++ * Returns zero on success, a negative error code otherwise.
++ */
++int mtd_ooblayout_free(struct mtd_info *mtd, int section,
++ struct mtd_oob_region *oobfree)
++{
++ memset(oobfree, 0, sizeof(*oobfree));
++
++ if (!mtd || section < 0)
++ return -EINVAL;
++
++ if (!mtd->ooblayout || !mtd->ooblayout->free)
++ return -ENOTSUPP;
++
++ return mtd->ooblayout->free(mtd, section, oobfree);
++}
++EXPORT_SYMBOL_GPL(mtd_ooblayout_free);
++
++/**
++ * mtd_ooblayout_find_region - Find the region attached to a specific byte
++ * @mtd: mtd info structure
++ * @byte: the byte we are searching for
++ * @sectionp: pointer where the section id will be stored
++ * @oobregion: used to retrieve the ECC position
++ * @iter: iterator function. Should be either mtd_ooblayout_free or
++ * mtd_ooblayout_ecc depending on the region type you're searching for
++ *
++ * This functions returns the section id and oobregion information of a
++ * specific byte. For example, say you want to know where the 4th ECC byte is
++ * stored, you'll use:
++ *
++ * mtd_ooblayout_find_region(mtd, 3, &section, &oobregion, mtd_ooblayout_ecc);
++ *
++ * Returns zero on success, a negative error code otherwise.
++ */
++static int mtd_ooblayout_find_region(struct mtd_info *mtd, int byte,
++ int *sectionp, struct mtd_oob_region *oobregion,
++ int (*iter)(struct mtd_info *,
++ int section,
++ struct mtd_oob_region *oobregion))
++{
++ int pos = 0, ret, section = 0;
++
++ memset(oobregion, 0, sizeof(*oobregion));
++
++ while (1) {
++ ret = iter(mtd, section, oobregion);
++ if (ret)
++ return ret;
++
++ if (pos + oobregion->length > byte)
++ break;
++
++ pos += oobregion->length;
++ section++;
++ }
++
++ /*
++ * Adjust region info to make it start at the beginning at the
++ * 'start' ECC byte.
++ */
++ oobregion->offset += byte - pos;
++ oobregion->length -= byte - pos;
++ *sectionp = section;
++
++ return 0;
++}
++
++/**
++ * mtd_ooblayout_find_eccregion - Find the ECC region attached to a specific
++ * ECC byte
++ * @mtd: mtd info structure
++ * @eccbyte: the byte we are searching for
++ * @sectionp: pointer where the section id will be stored
++ * @oobregion: OOB region information
++ *
++ * Works like mtd_ooblayout_find_region() except it searches for a specific ECC
++ * byte.
++ *
++ * Returns zero on success, a negative error code otherwise.
++ */
++int mtd_ooblayout_find_eccregion(struct mtd_info *mtd, int eccbyte,
++ int *section,
++ struct mtd_oob_region *oobregion)
++{
++ return mtd_ooblayout_find_region(mtd, eccbyte, section, oobregion,
++ mtd_ooblayout_ecc);
++}
++EXPORT_SYMBOL_GPL(mtd_ooblayout_find_eccregion);
++
++/**
++ * mtd_ooblayout_get_bytes - Extract OOB bytes from the oob buffer
++ * @mtd: mtd info structure
++ * @buf: destination buffer to store OOB bytes
++ * @oobbuf: OOB buffer
++ * @start: first byte to retrieve
++ * @nbytes: number of bytes to retrieve
++ * @iter: section iterator
++ *
++ * Extract bytes attached to a specific category (ECC or free)
++ * from the OOB buffer and copy them into buf.
++ *
++ * Returns zero on success, a negative error code otherwise.
++ */
++static int mtd_ooblayout_get_bytes(struct mtd_info *mtd, u8 *buf,
++ const u8 *oobbuf, int start, int nbytes,
++ int (*iter)(struct mtd_info *,
++ int section,
++ struct mtd_oob_region *oobregion))
++{
++ struct mtd_oob_region oobregion = { };
++ int section = 0, ret;
++
++ ret = mtd_ooblayout_find_region(mtd, start, &section,
++ &oobregion, iter);
++
++ while (!ret) {
++ int cnt;
++
++ cnt = oobregion.length > nbytes ? nbytes : oobregion.length;
++ memcpy(buf, oobbuf + oobregion.offset, cnt);
++ buf += cnt;
++ nbytes -= cnt;
++
++ if (!nbytes)
++ break;
++
++ ret = iter(mtd, ++section, &oobregion);
++ }
++
++ return ret;
++}
++
++/**
++ * mtd_ooblayout_set_bytes - put OOB bytes into the oob buffer
++ * @mtd: mtd info structure
++ * @buf: source buffer to get OOB bytes from
++ * @oobbuf: OOB buffer
++ * @start: first OOB byte to set
++ * @nbytes: number of OOB bytes to set
++ * @iter: section iterator
++ *
++ * Fill the OOB buffer with data provided in buf. The category (ECC or free)
++ * is selected by passing the appropriate iterator.
++ *
++ * Returns zero on success, a negative error code otherwise.
++ */
++static int mtd_ooblayout_set_bytes(struct mtd_info *mtd, const u8 *buf,
++ u8 *oobbuf, int start, int nbytes,
++ int (*iter)(struct mtd_info *,
++ int section,
++ struct mtd_oob_region *oobregion))
++{
++ struct mtd_oob_region oobregion = { };
++ int section = 0, ret;
++
++ ret = mtd_ooblayout_find_region(mtd, start, &section,
++ &oobregion, iter);
++
++ while (!ret) {
++ int cnt;
++
++ cnt = oobregion.length > nbytes ? nbytes : oobregion.length;
++ memcpy(oobbuf + oobregion.offset, buf, cnt);
++ buf += cnt;
++ nbytes -= cnt;
++
++ if (!nbytes)
++ break;
++
++ ret = iter(mtd, ++section, &oobregion);
++ }
++
++ return ret;
++}
++
++/**
++ * mtd_ooblayout_count_bytes - count the number of bytes in a OOB category
++ * @mtd: mtd info structure
++ * @iter: category iterator
++ *
++ * Count the number of bytes in a given category.
++ *
++ * Returns a positive value on success, a negative error code otherwise.
++ */
++static int mtd_ooblayout_count_bytes(struct mtd_info *mtd,
++ int (*iter)(struct mtd_info *,
++ int section,
++ struct mtd_oob_region *oobregion))
++{
++ struct mtd_oob_region oobregion = { };
++ int section = 0, ret, nbytes = 0;
++
++ while (1) {
++ ret = iter(mtd, section++, &oobregion);
++ if (ret) {
++ if (ret == -ERANGE)
++ ret = nbytes;
++ break;
++ }
++
++ nbytes += oobregion.length;
++ }
++
++ return ret;
++}
++
++/**
++ * mtd_ooblayout_get_eccbytes - extract ECC bytes from the oob buffer
++ * @mtd: mtd info structure
++ * @eccbuf: destination buffer to store ECC bytes
++ * @oobbuf: OOB buffer
++ * @start: first ECC byte to retrieve
++ * @nbytes: number of ECC bytes to retrieve
++ *
++ * Works like mtd_ooblayout_get_bytes(), except it acts on ECC bytes.
++ *
++ * Returns zero on success, a negative error code otherwise.
++ */
++int mtd_ooblayout_get_eccbytes(struct mtd_info *mtd, u8 *eccbuf,
++ const u8 *oobbuf, int start, int nbytes)
++{
++ return mtd_ooblayout_get_bytes(mtd, eccbuf, oobbuf, start, nbytes,
++ mtd_ooblayout_ecc);
++}
++EXPORT_SYMBOL_GPL(mtd_ooblayout_get_eccbytes);
++
++/**
++ * mtd_ooblayout_set_eccbytes - set ECC bytes into the oob buffer
++ * @mtd: mtd info structure
++ * @eccbuf: source buffer to get ECC bytes from
++ * @oobbuf: OOB buffer
++ * @start: first ECC byte to set
++ * @nbytes: number of ECC bytes to set
++ *
++ * Works like mtd_ooblayout_set_bytes(), except it acts on ECC bytes.
++ *
++ * Returns zero on success, a negative error code otherwise.
++ */
++int mtd_ooblayout_set_eccbytes(struct mtd_info *mtd, const u8 *eccbuf,
++ u8 *oobbuf, int start, int nbytes)
++{
++ return mtd_ooblayout_set_bytes(mtd, eccbuf, oobbuf, start, nbytes,
++ mtd_ooblayout_ecc);
++}
++EXPORT_SYMBOL_GPL(mtd_ooblayout_set_eccbytes);
++
++/**
++ * mtd_ooblayout_get_databytes - extract data bytes from the oob buffer
++ * @mtd: mtd info structure
++ * @databuf: destination buffer to store ECC bytes
++ * @oobbuf: OOB buffer
++ * @start: first ECC byte to retrieve
++ * @nbytes: number of ECC bytes to retrieve
++ *
++ * Works like mtd_ooblayout_get_bytes(), except it acts on free bytes.
++ *
++ * Returns zero on success, a negative error code otherwise.
++ */
++int mtd_ooblayout_get_databytes(struct mtd_info *mtd, u8 *databuf,
++ const u8 *oobbuf, int start, int nbytes)
++{
++ return mtd_ooblayout_get_bytes(mtd, databuf, oobbuf, start, nbytes,
++ mtd_ooblayout_free);
++}
++EXPORT_SYMBOL_GPL(mtd_ooblayout_get_databytes);
++
++/**
++ * mtd_ooblayout_get_eccbytes - set data bytes into the oob buffer
++ * @mtd: mtd info structure
++ * @eccbuf: source buffer to get data bytes from
++ * @oobbuf: OOB buffer
++ * @start: first ECC byte to set
++ * @nbytes: number of ECC bytes to set
++ *
++ * Works like mtd_ooblayout_get_bytes(), except it acts on free bytes.
++ *
++ * Returns zero on success, a negative error code otherwise.
++ */
++int mtd_ooblayout_set_databytes(struct mtd_info *mtd, const u8 *databuf,
++ u8 *oobbuf, int start, int nbytes)
++{
++ return mtd_ooblayout_set_bytes(mtd, databuf, oobbuf, start, nbytes,
++ mtd_ooblayout_free);
++}
++EXPORT_SYMBOL_GPL(mtd_ooblayout_set_databytes);
++
++/**
++ * mtd_ooblayout_count_freebytes - count the number of free bytes in OOB
++ * @mtd: mtd info structure
++ *
++ * Works like mtd_ooblayout_count_bytes(), except it count free bytes.
++ *
++ * Returns zero on success, a negative error code otherwise.
++ */
++int mtd_ooblayout_count_freebytes(struct mtd_info *mtd)
++{
++ return mtd_ooblayout_count_bytes(mtd, mtd_ooblayout_free);
++}
++EXPORT_SYMBOL_GPL(mtd_ooblayout_count_freebytes);
++
++/**
++ * mtd_ooblayout_count_freebytes - count the number of ECC bytes in OOB
++ * @mtd: mtd info structure
++ *
++ * Works like mtd_ooblayout_count_bytes(), except it count ECC bytes.
++ *
++ * Returns zero on success, a negative error code otherwise.
++ */
++int mtd_ooblayout_count_eccbytes(struct mtd_info *mtd)
++{
++ return mtd_ooblayout_count_bytes(mtd, mtd_ooblayout_ecc);
++}
++EXPORT_SYMBOL_GPL(mtd_ooblayout_count_eccbytes);
++
+ /*
+ * Method to access the protection register area, present in some flash
+ * devices. The user data is one time programmable but the factory data is read
+--- a/drivers/mtd/mtdcore.h
++++ b/drivers/mtd/mtdcore.h
+@@ -10,10 +10,15 @@ int add_mtd_device(struct mtd_info *mtd)
+ int del_mtd_device(struct mtd_info *mtd);
+ int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int);
+ int del_mtd_partitions(struct mtd_info *);
++
++struct mtd_partitions;
++
+ int parse_mtd_partitions(struct mtd_info *master, const char * const *types,
+- struct mtd_partition **pparts,
++ struct mtd_partitions *pparts,
+ struct mtd_part_parser_data *data);
+
++void mtd_part_parser_cleanup(struct mtd_partitions *parts);
++
+ int __init init_mtdchar(void);
+ void __exit cleanup_mtdchar(void);
+
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -55,9 +55,12 @@ static void mtd_partition_split(struct m
+
+ /*
+ * Given a pointer to the MTD object in the mtd_part structure, we can retrieve
+- * the pointer to that structure with this macro.
++ * the pointer to that structure.
+ */
+-#define PART(x) ((struct mtd_part *)(x))
++static inline struct mtd_part *mtd_to_part(const struct mtd_info *mtd)
++{
++ return container_of(mtd, struct mtd_part, mtd);
++}
+
+
+ /*
+@@ -68,7 +71,7 @@ static void mtd_partition_split(struct m
+ static int part_read(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ struct mtd_ecc_stats stats;
+ int res;
+
+@@ -87,7 +90,7 @@ static int part_read(struct mtd_info *mt
+ static int part_point(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, void **virt, resource_size_t *phys)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+
+ return part->master->_point(part->master, from + part->offset, len,
+ retlen, virt, phys);
+@@ -95,7 +98,7 @@ static int part_point(struct mtd_info *m
+
+ static int part_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+
+ return part->master->_unpoint(part->master, from + part->offset, len);
+ }
+@@ -105,7 +108,7 @@ static unsigned long part_get_unmapped_a
+ unsigned long offset,
+ unsigned long flags)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+
+ offset += part->offset;
+ return part->master->_get_unmapped_area(part->master, len, offset,
+@@ -115,7 +118,7 @@ static unsigned long part_get_unmapped_a
+ static int part_read_oob(struct mtd_info *mtd, loff_t from,
+ struct mtd_oob_ops *ops)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ int res;
+
+ if (from >= mtd->size)
+@@ -130,10 +133,7 @@ static int part_read_oob(struct mtd_info
+ if (ops->oobbuf) {
+ size_t len, pages;
+
+- if (ops->mode == MTD_OPS_AUTO_OOB)
+- len = mtd->oobavail;
+- else
+- len = mtd->oobsize;
++ len = mtd_oobavail(mtd, ops);
+ pages = mtd_div_by_ws(mtd->size, mtd);
+ pages -= mtd_div_by_ws(from, mtd);
+ if (ops->ooboffs + ops->ooblen > pages * len)
+@@ -153,7 +153,7 @@ static int part_read_oob(struct mtd_info
+ static int part_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
+ size_t len, size_t *retlen, u_char *buf)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ return part->master->_read_user_prot_reg(part->master, from, len,
+ retlen, buf);
+ }
+@@ -161,7 +161,7 @@ static int part_read_user_prot_reg(struc
+ static int part_get_user_prot_info(struct mtd_info *mtd, size_t len,
+ size_t *retlen, struct otp_info *buf)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ return part->master->_get_user_prot_info(part->master, len, retlen,
+ buf);
+ }
+@@ -169,7 +169,7 @@ static int part_get_user_prot_info(struc
+ static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
+ size_t len, size_t *retlen, u_char *buf)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ return part->master->_read_fact_prot_reg(part->master, from, len,
+ retlen, buf);
+ }
+@@ -177,7 +177,7 @@ static int part_read_fact_prot_reg(struc
+ static int part_get_fact_prot_info(struct mtd_info *mtd, size_t len,
+ size_t *retlen, struct otp_info *buf)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ return part->master->_get_fact_prot_info(part->master, len, retlen,
+ buf);
+ }
+@@ -185,7 +185,7 @@ static int part_get_fact_prot_info(struc
+ static int part_write(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ return part->master->_write(part->master, to + part->offset, len,
+ retlen, buf);
+ }
+@@ -193,7 +193,7 @@ static int part_write(struct mtd_info *m
+ static int part_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ return part->master->_panic_write(part->master, to + part->offset, len,
+ retlen, buf);
+ }
+@@ -201,7 +201,7 @@ static int part_panic_write(struct mtd_i
+ static int part_write_oob(struct mtd_info *mtd, loff_t to,
+ struct mtd_oob_ops *ops)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+
+ if (to >= mtd->size)
+ return -EINVAL;
+@@ -213,7 +213,7 @@ static int part_write_oob(struct mtd_inf
+ static int part_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
+ size_t len, size_t *retlen, u_char *buf)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ return part->master->_write_user_prot_reg(part->master, from, len,
+ retlen, buf);
+ }
+@@ -221,21 +221,21 @@ static int part_write_user_prot_reg(stru
+ static int part_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
+ size_t len)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ return part->master->_lock_user_prot_reg(part->master, from, len);
+ }
+
+ static int part_writev(struct mtd_info *mtd, const struct kvec *vecs,
+ unsigned long count, loff_t to, size_t *retlen)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ return part->master->_writev(part->master, vecs, count,
+ to + part->offset, retlen);
+ }
+
+ static int part_erase(struct mtd_info *mtd, struct erase_info *instr)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ int ret;
+
+
+@@ -299,7 +299,7 @@ static int part_erase(struct mtd_info *m
+ void mtd_erase_callback(struct erase_info *instr)
+ {
+ if (instr->mtd->_erase == part_erase) {
+- struct mtd_part *part = PART(instr->mtd);
++ struct mtd_part *part = mtd_to_part(instr->mtd);
+ size_t wrlen = 0;
+
+ if (instr->mtd->flags & MTD_ERASE_PARTIAL) {
+@@ -330,13 +330,13 @@ EXPORT_SYMBOL_GPL(mtd_erase_callback);
+
+ static int part_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ return part->master->_lock(part->master, ofs + part->offset, len);
+ }
+
+ static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+
+ ofs += part->offset;
+ if (mtd->flags & MTD_ERASE_PARTIAL) {
+@@ -349,45 +349,45 @@ static int part_unlock(struct mtd_info *
+
+ static int part_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ return part->master->_is_locked(part->master, ofs + part->offset, len);
+ }
+
+ static void part_sync(struct mtd_info *mtd)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ part->master->_sync(part->master);
+ }
+
+ static int part_suspend(struct mtd_info *mtd)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ return part->master->_suspend(part->master);
+ }
+
+ static void part_resume(struct mtd_info *mtd)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ part->master->_resume(part->master);
+ }
+
+ static int part_block_isreserved(struct mtd_info *mtd, loff_t ofs)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ ofs += part->offset;
+ return part->master->_block_isreserved(part->master, ofs);
+ }
+
+ static int part_block_isbad(struct mtd_info *mtd, loff_t ofs)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ ofs += part->offset;
+ return part->master->_block_isbad(part->master, ofs);
+ }
+
+ static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ int res;
+
+ ofs += part->offset;
+@@ -397,6 +397,27 @@ static int part_block_markbad(struct mtd
+ return res;
+ }
+
++static int part_ooblayout_ecc(struct mtd_info *mtd, int section,
++ struct mtd_oob_region *oobregion)
++{
++ struct mtd_part *part = mtd_to_part(mtd);
++
++ return mtd_ooblayout_ecc(part->master, section, oobregion);
++}
++
++static int part_ooblayout_free(struct mtd_info *mtd, int section,
++ struct mtd_oob_region *oobregion)
++{
++ struct mtd_part *part = mtd_to_part(mtd);
++
++ return mtd_ooblayout_free(part->master, section, oobregion);
++}
++
++static const struct mtd_ooblayout_ops part_ooblayout_ops = {
++ .ecc = part_ooblayout_ecc,
++ .free = part_ooblayout_free,
++};
++
+ static inline void free_partition(struct mtd_part *p)
+ {
+ kfree(p->mtd.name);
+@@ -614,7 +635,7 @@ static struct mtd_part *allocate_partiti
+ slave->mtd.erasesize = slave->mtd.size;
+ }
+
+- slave->mtd.ecclayout = master->ecclayout;
++ mtd_set_ooblayout(&slave->mtd, &part_ooblayout_ops);
+ slave->mtd.ecc_step_size = master->ecc_step_size;
+ slave->mtd.ecc_strength = master->ecc_strength;
+ slave->mtd.bitflip_threshold = master->bitflip_threshold;
+@@ -639,7 +660,7 @@ static ssize_t mtd_partition_offset_show
+ struct device_attribute *attr, char *buf)
+ {
+ struct mtd_info *mtd = dev_get_drvdata(dev);
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ return snprintf(buf, PAGE_SIZE, "%lld\n", part->offset);
+ }
+
+@@ -677,11 +698,10 @@ int mtd_add_partition(struct mtd_info *m
+ if (length <= 0)
+ return -EINVAL;
+
++ memset(&part, 0, sizeof(part));
+ part.name = name;
+ part.size = length;
+ part.offset = offset;
+- part.mask_flags = 0;
+- part.ecclayout = NULL;
+
+ new = allocate_partition(master, &part, -1, offset);
+ if (IS_ERR(new))
+@@ -845,7 +865,7 @@ int add_mtd_partitions(struct mtd_info *
+ static DEFINE_SPINLOCK(part_parser_lock);
+ static LIST_HEAD(part_parsers);
+
+-static struct mtd_part_parser *get_partition_parser(const char *name)
++static struct mtd_part_parser *mtd_part_parser_get(const char *name)
+ {
+ struct mtd_part_parser *p, *ret = NULL;
+
+@@ -862,7 +882,20 @@ static struct mtd_part_parser *get_parti
+ return ret;
+ }
+
+-#define put_partition_parser(p) do { module_put((p)->owner); } while (0)
++static inline void mtd_part_parser_put(const struct mtd_part_parser *p)
++{
++ module_put(p->owner);
++}
++
++/*
++ * Many partition parsers just expected the core to kfree() all their data in
++ * one chunk. Do that by default.
++ */
++static void mtd_part_parser_cleanup_default(const struct mtd_partition *pparts,
++ int nr_parts)
++{
++ kfree(pparts);
++}
+
+ static struct mtd_part_parser *
+ get_partition_parser_by_type(enum mtd_parser_type type,
+@@ -874,7 +907,7 @@ get_partition_parser_by_type(enum mtd_pa
+
+ p = list_prepare_entry(start, &part_parsers, list);
+ if (start)
+- put_partition_parser(start);
++ mtd_part_parser_put(start);
+
+ list_for_each_entry_continue(p, &part_parsers, list) {
+ if (p->type == type && try_module_get(p->owner)) {
+@@ -888,13 +921,19 @@ get_partition_parser_by_type(enum mtd_pa
+ return ret;
+ }
+
+-void register_mtd_parser(struct mtd_part_parser *p)
+-{
++int __register_mtd_parser(struct mtd_part_parser *p, struct module *owner)
++ {
++ p->owner = owner;
++
++ if (!p->cleanup)
++ p->cleanup = &mtd_part_parser_cleanup_default;
++
+ spin_lock(&part_parser_lock);
+ list_add(&p->list, &part_parsers);
+ spin_unlock(&part_parser_lock);
++ return 0;
+ }
+-EXPORT_SYMBOL_GPL(register_mtd_parser);
++EXPORT_SYMBOL_GPL(__register_mtd_parser);
+
+ void deregister_mtd_parser(struct mtd_part_parser *p)
+ {
+@@ -954,7 +993,7 @@ static const char * const default_mtd_pa
+ * parse_mtd_partitions - parse MTD partitions
+ * @master: the master partition (describes whole MTD device)
+ * @types: names of partition parsers to try or %NULL
+- * @pparts: array of partitions found is returned here
++ * @pparts: info about partitions found is returned here
+ * @data: MTD partition parser-specific data
+ *
+ * This function tries to find partition on MTD device @master. It uses MTD
+@@ -966,45 +1005,42 @@ static const char * const default_mtd_pa
+ *
+ * This function may return:
+ * o a negative error code in case of failure
+- * o zero if no partitions were found
+- * o a positive number of found partitions, in which case on exit @pparts will
+- * point to an array containing this number of &struct mtd_info objects.
++ * o zero otherwise, and @pparts will describe the partitions, number of
++ * partitions, and the parser which parsed them. Caller must release
++ * resources with mtd_part_parser_cleanup() when finished with the returned
++ * data.
+ */
+ int parse_mtd_partitions(struct mtd_info *master, const char *const *types,
+- struct mtd_partition **pparts,
++ struct mtd_partitions *pparts,
+ struct mtd_part_parser_data *data)
+ {
+ struct mtd_part_parser *parser;
+ int ret, err = 0;
+ const char *const *types_of = NULL;
+
+- if (data && data->of_node) {
+- types_of = of_get_probes(data->of_node);
+- if (types_of != NULL)
+- types = types_of;
+- }
+-
+ if (!types)
+ types = default_mtd_part_types;
+
+ for ( ; *types; types++) {
+ pr_debug("%s: parsing partitions %s\n", master->name, *types);
+- parser = get_partition_parser(*types);
++ parser = mtd_part_parser_get(*types);
+ if (!parser && !request_module("%s", *types))
+- parser = get_partition_parser(*types);
++ parser = mtd_part_parser_get(*types);
+ pr_debug("%s: got parser %s\n", master->name,
+ parser ? parser->name : NULL);
+ if (!parser)
+ continue;
+- ret = (*parser->parse_fn)(master, pparts, data);
++ ret = (*parser->parse_fn)(master, &pparts->parts, data);
+ pr_debug("%s: parser %s: %i\n",
+ master->name, parser->name, ret);
+- put_partition_parser(parser);
+ if (ret > 0) {
+ printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n",
+ ret, parser->name, master->name);
+- return ret;
++ pparts->nr_parts = ret;
++ pparts->parser = parser;
++ return 0;
+ }
++ mtd_part_parser_put(parser);
+ /*
+ * Stash the first error we see; only report it if no parser
+ * succeeds
+@@ -1034,7 +1070,7 @@ int parse_mtd_partitions_by_type(struct
+ ret = (*parser->parse_fn)(master, pparts, data);
+
+ if (ret > 0) {
+- put_partition_parser(parser);
++ mtd_part_parser_put(parser);
+ printk(KERN_NOTICE
+ "%d %s partitions found on MTD device %s\n",
+ ret, parser->name, master->name);
+@@ -1048,6 +1084,22 @@ int parse_mtd_partitions_by_type(struct
+ }
+ EXPORT_SYMBOL_GPL(parse_mtd_partitions_by_type);
+
++void mtd_part_parser_cleanup(struct mtd_partitions *parts)
++{
++ const struct mtd_part_parser *parser;
++
++ if (!parts)
++ return;
++
++ parser = parts->parser;
++ if (parser) {
++ if (parser->cleanup)
++ parser->cleanup(parts->parts, parts->nr_parts);
++
++ mtd_part_parser_put(parser);
++ }
++}
++
+ int mtd_is_partition(const struct mtd_info *mtd)
+ {
+ struct mtd_part *part;
+@@ -1070,7 +1122,7 @@ struct mtd_info *mtdpart_get_master(cons
+ if (!mtd_is_partition(mtd))
+ return (struct mtd_info *)mtd;
+
+- return PART(mtd)->master;
++ return mtd_to_part(mtd)->master;
+ }
+ EXPORT_SYMBOL_GPL(mtdpart_get_master);
+
+@@ -1079,7 +1131,7 @@ uint64_t mtdpart_get_offset(const struct
+ if (!mtd_is_partition(mtd))
+ return 0;
+
+- return PART(mtd)->offset;
++ return mtd_to_part(mtd)->offset;
+ }
+ EXPORT_SYMBOL_GPL(mtdpart_get_offset);
+
+@@ -1089,6 +1141,6 @@ uint64_t mtd_get_device_size(const struc
+ if (!mtd_is_partition(mtd))
+ return mtd->size;
+
+- return PART(mtd)->master->size;
++ return mtd_to_part(mtd)->master->size;
+ }
+ EXPORT_SYMBOL_GPL(mtd_get_device_size);
+--- a/drivers/mtd/mtdswap.c
++++ b/drivers/mtd/mtdswap.c
+@@ -346,7 +346,7 @@ static int mtdswap_read_markers(struct m
+ if (mtd_can_have_bb(d->mtd) && mtd_block_isbad(d->mtd, offset))
+ return MTDSWAP_SCANNED_BAD;
+
+- ops.ooblen = 2 * d->mtd->ecclayout->oobavail;
++ ops.ooblen = 2 * d->mtd->oobavail;
+ ops.oobbuf = d->oob_buf;
+ ops.ooboffs = 0;
+ ops.datbuf = NULL;
+@@ -359,7 +359,7 @@ static int mtdswap_read_markers(struct m
+
+ data = (struct mtdswap_oobdata *)d->oob_buf;
+ data2 = (struct mtdswap_oobdata *)
+- (d->oob_buf + d->mtd->ecclayout->oobavail);
++ (d->oob_buf + d->mtd->oobavail);
+
+ if (le16_to_cpu(data->magic) == MTDSWAP_MAGIC_CLEAN) {
+ eb->erase_count = le32_to_cpu(data->count);
+@@ -933,7 +933,7 @@ static unsigned int mtdswap_eblk_passes(
+
+ ops.mode = MTD_OPS_AUTO_OOB;
+ ops.len = mtd->writesize;
+- ops.ooblen = mtd->ecclayout->oobavail;
++ ops.ooblen = mtd->oobavail;
+ ops.ooboffs = 0;
+ ops.datbuf = d->page_buf;
+ ops.oobbuf = d->oob_buf;
+@@ -945,7 +945,7 @@ static unsigned int mtdswap_eblk_passes(
+ for (i = 0; i < mtd_pages; i++) {
+ patt = mtdswap_test_patt(test + i);
+ memset(d->page_buf, patt, mtd->writesize);
+- memset(d->oob_buf, patt, mtd->ecclayout->oobavail);
++ memset(d->oob_buf, patt, mtd->oobavail);
+ ret = mtd_write_oob(mtd, pos, &ops);
+ if (ret)
+ goto error;
+@@ -964,7 +964,7 @@ static unsigned int mtdswap_eblk_passes(
+ if (p1[j] != patt)
+ goto error;
+
+- for (j = 0; j < mtd->ecclayout->oobavail; j++)
++ for (j = 0; j < mtd->oobavail; j++)
+ if (p2[j] != (unsigned char)patt)
+ goto error;
+
+@@ -1387,7 +1387,7 @@ static int mtdswap_init(struct mtdswap_d
+ if (!d->page_buf)
+ goto page_buf_fail;
+
+- d->oob_buf = kmalloc(2 * mtd->ecclayout->oobavail, GFP_KERNEL);
++ d->oob_buf = kmalloc(2 * mtd->oobavail, GFP_KERNEL);
+ if (!d->oob_buf)
+ goto oob_buf_fail;
+
+@@ -1417,7 +1417,6 @@ static void mtdswap_add_mtd(struct mtd_b
+ unsigned long part;
+ unsigned int eblocks, eavailable, bad_blocks, spare_cnt;
+ uint64_t swap_size, use_size, size_limit;
+- struct nand_ecclayout *oinfo;
+ int ret;
+
+ parts = &partitions[0];
+@@ -1447,17 +1446,10 @@ static void mtdswap_add_mtd(struct mtd_b
+ return;
+ }
+
+- oinfo = mtd->ecclayout;
+- if (!oinfo) {
+- printk(KERN_ERR "%s: mtd%d does not have OOB\n",
+- MTDSWAP_PREFIX, mtd->index);
+- return;
+- }
+-
+- if (!mtd->oobsize || oinfo->oobavail < MTDSWAP_OOBSIZE) {
++ if (!mtd->oobsize || mtd->oobavail < MTDSWAP_OOBSIZE) {
+ printk(KERN_ERR "%s: Not enough free bytes in OOB, "
+ "%d available, %zu needed.\n",
+- MTDSWAP_PREFIX, oinfo->oobavail, MTDSWAP_OOBSIZE);
++ MTDSWAP_PREFIX, mtd->oobavail, MTDSWAP_OOBSIZE);
+ return;
+ }
+
+--- a/drivers/mtd/nand/Kconfig
++++ b/drivers/mtd/nand/Kconfig
+@@ -55,7 +55,7 @@ config MTD_NAND_DENALI_PCI
+ config MTD_NAND_DENALI_DT
+ tristate "Support Denali NAND controller as a DT device"
+ select MTD_NAND_DENALI
+- depends on HAS_DMA && HAVE_CLK
++ depends on HAS_DMA && HAVE_CLK && OF
+ help
+ Enable the driver for NAND flash on platforms using a Denali NAND
+ controller as a DT device.
+@@ -74,6 +74,7 @@ config MTD_NAND_DENALI_SCRATCH_REG_ADDR
+ config MTD_NAND_GPIO
+ tristate "GPIO assisted NAND Flash driver"
+ depends on GPIOLIB || COMPILE_TEST
++ depends on HAS_IOMEM
+ help
+ This enables a NAND flash driver where control signals are
+ connected to GPIO pins, and commands and data are communicated
+@@ -310,6 +311,7 @@ config MTD_NAND_CAFE
+ config MTD_NAND_CS553X
+ tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)"
+ depends on X86_32
++ depends on !UML && HAS_IOMEM
+ help
+ The CS553x companion chips for the AMD Geode processor
+ include NAND flash controllers with built-in hardware ECC
+@@ -463,6 +465,7 @@ config MTD_NAND_MPC5121_NFC
+ config MTD_NAND_VF610_NFC
+ tristate "Support for Freescale NFC for VF610/MPC5125"
+ depends on (SOC_VF610 || COMPILE_TEST)
++ depends on HAS_IOMEM
+ help
+ Enables support for NAND Flash Controller on some Freescale
+ processors like the VF610, MPC5125, MCF54418 or Kinetis K70.
+@@ -480,7 +483,7 @@ config MTD_NAND_MXC
+
+ config MTD_NAND_SH_FLCTL
+ tristate "Support for NAND on Renesas SuperH FLCTL"
+- depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
++ depends on SUPERH || COMPILE_TEST
+ depends on HAS_IOMEM
+ depends on HAS_DMA
+ help
+@@ -519,6 +522,13 @@ config MTD_NAND_JZ4740
+ help
+ Enables support for NAND Flash on JZ4740 SoC based boards.
+
++config MTD_NAND_JZ4780
++ tristate "Support for NAND on JZ4780 SoC"
++ depends on MACH_JZ4780 && JZ4780_NEMC
++ help
++ Enables support for NAND Flash connected to the NEMC on JZ4780 SoC
++ based boards, using the BCH controller for hardware error correction.
++
+ config MTD_NAND_FSMC
+ tristate "Support for NAND on ST Micros FSMC"
+ depends on PLAT_SPEAR || ARCH_NOMADIK || ARCH_U8500 || MACH_U300
+@@ -546,4 +556,11 @@ config MTD_NAND_HISI504
+ help
+ Enables support for NAND controller on Hisilicon SoC Hip04.
+
++config MTD_NAND_QCOM
++ tristate "Support for NAND on QCOM SoCs"
++ depends on ARCH_QCOM
++ help
++ Enables support for NAND flash chips on SoCs containing the EBI2 NAND
++ controller. This controller is found on IPQ806x SoC.
++
+ endif # MTD_NAND
+--- a/drivers/mtd/nand/Makefile
++++ b/drivers/mtd/nand/Makefile
+@@ -49,11 +49,13 @@ obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mp
+ obj-$(CONFIG_MTD_NAND_VF610_NFC) += vf610_nfc.o
+ obj-$(CONFIG_MTD_NAND_RICOH) += r852.o
+ obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o
++obj-$(CONFIG_MTD_NAND_JZ4780) += jz4780_nand.o jz4780_bch.o
+ obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/
+ obj-$(CONFIG_MTD_NAND_XWAY) += xway_nand.o
+ obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/
+ obj-$(CONFIG_MTD_NAND_SUNXI) += sunxi_nand.o
+ obj-$(CONFIG_MTD_NAND_HISI504) += hisi504_nand.o
+ obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand/
++obj-$(CONFIG_MTD_NAND_QCOM) += qcom_nandc.o
+
+ nand-objs := nand_base.o nand_bbt.o nand_timings.o
+--- a/drivers/mtd/nand/nand_base.c
++++ b/drivers/mtd/nand/nand_base.c
+@@ -48,50 +48,6 @@
+ #include <linux/mtd/partitions.h>
+ #include <linux/of_mtd.h>
+
+-/* Define default oob placement schemes for large and small page devices */
+-static struct nand_ecclayout nand_oob_8 = {
+- .eccbytes = 3,
+- .eccpos = {0, 1, 2},
+- .oobfree = {
+- {.offset = 3,
+- .length = 2},
+- {.offset = 6,
+- .length = 2} }
+-};
+-
+-static struct nand_ecclayout nand_oob_16 = {
+- .eccbytes = 6,
+- .eccpos = {0, 1, 2, 3, 6, 7},
+- .oobfree = {
+- {.offset = 8,
+- . length = 8} }
+-};
+-
+-static struct nand_ecclayout nand_oob_64 = {
+- .eccbytes = 24,
+- .eccpos = {
+- 40, 41, 42, 43, 44, 45, 46, 47,
+- 48, 49, 50, 51, 52, 53, 54, 55,
+- 56, 57, 58, 59, 60, 61, 62, 63},
+- .oobfree = {
+- {.offset = 2,
+- .length = 38} }
+-};
+-
+-static struct nand_ecclayout nand_oob_128 = {
+- .eccbytes = 48,
+- .eccpos = {
+- 80, 81, 82, 83, 84, 85, 86, 87,
+- 88, 89, 90, 91, 92, 93, 94, 95,
+- 96, 97, 98, 99, 100, 101, 102, 103,
+- 104, 105, 106, 107, 108, 109, 110, 111,
+- 112, 113, 114, 115, 116, 117, 118, 119,
+- 120, 121, 122, 123, 124, 125, 126, 127},
+- .oobfree = {
+- {.offset = 2,
+- .length = 78} }
+-};
+-
+ static int nand_get_device(struct mtd_info *mtd, int new_state);
+
+ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
+@@ -103,10 +59,96 @@ static int nand_do_write_oob(struct mtd_
+ */
+ DEFINE_LED_TRIGGER(nand_led_trigger);
+
++/* Define default oob placement schemes for large and small page devices */
++static int nand_ooblayout_ecc_sp(struct mtd_info *mtd, int section,
++ struct mtd_oob_region *oobregion)
++{
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct nand_ecc_ctrl *ecc = &chip->ecc;
++
++ if (section > 1)
++ return -ERANGE;
++
++ if (!section) {
++ oobregion->offset = 0;
++ oobregion->length = 4;
++ } else {
++ oobregion->offset = 6;
++ oobregion->length = ecc->total - 4;
++ }
++
++ return 0;
++}
++
++static int nand_ooblayout_free_sp(struct mtd_info *mtd, int section,
++ struct mtd_oob_region *oobregion)
++{
++ if (section > 1)
++ return -ERANGE;
++
++ if (mtd->oobsize == 16) {
++ if (section)
++ return -ERANGE;
++
++ oobregion->length = 8;
++ oobregion->offset = 8;
++ } else {
++ oobregion->length = 2;
++ if (!section)
++ oobregion->offset = 3;
++ else
++ oobregion->offset = 6;
++ }
++
++ return 0;
++}
++
++const struct mtd_ooblayout_ops nand_ooblayout_sp_ops = {
++ .ecc = nand_ooblayout_ecc_sp,
++ .free = nand_ooblayout_free_sp,
++};
++EXPORT_SYMBOL_GPL(nand_ooblayout_sp_ops);
++
++static int nand_ooblayout_ecc_lp(struct mtd_info *mtd, int section,
++ struct mtd_oob_region *oobregion)
++{
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct nand_ecc_ctrl *ecc = &chip->ecc;
++
++ if (section)
++ return -ERANGE;
++
++ oobregion->length = ecc->total;
++ oobregion->offset = mtd->oobsize - oobregion->length;
++
++ return 0;
++}
++
++static int nand_ooblayout_free_lp(struct mtd_info *mtd, int section,
++ struct mtd_oob_region *oobregion)
++{
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct nand_ecc_ctrl *ecc = &chip->ecc;
++
++ if (section)
++ return -ERANGE;
++
++ oobregion->length = mtd->oobsize - ecc->total - 2;
++ oobregion->offset = 2;
++
++ return 0;
++}
++
++const struct mtd_ooblayout_ops nand_ooblayout_lp_ops = {
++ .ecc = nand_ooblayout_ecc_lp,
++ .free = nand_ooblayout_free_lp,
++};
++EXPORT_SYMBOL_GPL(nand_ooblayout_lp_ops);
++
+ static int check_offs_len(struct mtd_info *mtd,
+ loff_t ofs, uint64_t len)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ int ret = 0;
+
+ /* Start address must align on block boundary */
+@@ -132,7 +174,7 @@ static int check_offs_len(struct mtd_inf
+ */
+ static void nand_release_device(struct mtd_info *mtd)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ /* Release the controller and the chip */
+ spin_lock(&chip->controller->lock);
+@@ -150,7 +192,7 @@ static void nand_release_device(struct m
+ */
+ static uint8_t nand_read_byte(struct mtd_info *mtd)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ return readb(chip->IO_ADDR_R);
+ }
+
+@@ -163,7 +205,7 @@ static uint8_t nand_read_byte(struct mtd
+ */
+ static uint8_t nand_read_byte16(struct mtd_info *mtd)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ return (uint8_t) cpu_to_le16(readw(chip->IO_ADDR_R));
+ }
+
+@@ -175,7 +217,7 @@ static uint8_t nand_read_byte16(struct m
+ */
+ static u16 nand_read_word(struct mtd_info *mtd)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ return readw(chip->IO_ADDR_R);
+ }
+
+@@ -188,7 +230,7 @@ static u16 nand_read_word(struct mtd_inf
+ */
+ static void nand_select_chip(struct mtd_info *mtd, int chipnr)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ switch (chipnr) {
+ case -1:
+@@ -211,7 +253,7 @@ static void nand_select_chip(struct mtd_
+ */
+ static void nand_write_byte(struct mtd_info *mtd, uint8_t byte)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ chip->write_buf(mtd, &byte, 1);
+ }
+@@ -225,7 +267,7 @@ static void nand_write_byte(struct mtd_i
+ */
+ static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ uint16_t word = byte;
+
+ /*
+@@ -257,7 +299,7 @@ static void nand_write_byte16(struct mtd
+ */
+ static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ iowrite8_rep(chip->IO_ADDR_W, buf, len);
+ }
+@@ -272,7 +314,7 @@ static void nand_write_buf(struct mtd_in
+ */
+ static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ ioread8_rep(chip->IO_ADDR_R, buf, len);
+ }
+@@ -287,7 +329,7 @@ static void nand_read_buf(struct mtd_inf
+ */
+ static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ u16 *p = (u16 *) buf;
+
+ iowrite16_rep(chip->IO_ADDR_W, p, len >> 1);
+@@ -303,7 +345,7 @@ static void nand_write_buf16(struct mtd_
+ */
+ static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ u16 *p = (u16 *) buf;
+
+ ioread16_rep(chip->IO_ADDR_R, p, len >> 1);
+@@ -313,14 +355,13 @@ static void nand_read_buf16(struct mtd_i
+ * nand_block_bad - [DEFAULT] Read bad block marker from the chip
+ * @mtd: MTD device structure
+ * @ofs: offset from device start
+- * @getchip: 0, if the chip is already selected
+ *
+ * Check, if the block is bad.
+ */
+-static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
++static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
+ {
+- int page, chipnr, res = 0, i = 0;
+- struct nand_chip *chip = mtd->priv;
++ int page, res = 0, i = 0;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ u16 bad;
+
+ if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
+@@ -328,15 +369,6 @@ static int nand_block_bad(struct mtd_inf
+
+ page = (int)(ofs >> chip->page_shift) & chip->pagemask;
+
+- if (getchip) {
+- chipnr = (int)(ofs >> chip->chip_shift);
+-
+- nand_get_device(mtd, FL_READING);
+-
+- /* Select the NAND device */
+- chip->select_chip(mtd, chipnr);
+- }
+-
+ do {
+ if (chip->options & NAND_BUSWIDTH_16) {
+ chip->cmdfunc(mtd, NAND_CMD_READOOB,
+@@ -361,11 +393,6 @@ static int nand_block_bad(struct mtd_inf
+ i++;
+ } while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE));
+
+- if (getchip) {
+- chip->select_chip(mtd, -1);
+- nand_release_device(mtd);
+- }
+-
+ return res;
+ }
+
+@@ -380,7 +407,7 @@ static int nand_block_bad(struct mtd_inf
+ */
+ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_oob_ops ops;
+ uint8_t buf[2] = { 0, 0 };
+ int ret = 0, res, i = 0;
+@@ -430,7 +457,7 @@ static int nand_default_block_markbad(st
+ */
+ static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ int res, ret = 0;
+
+ if (!(chip->bbt_options & NAND_BBT_NO_OOB_BBM)) {
+@@ -471,7 +498,7 @@ static int nand_block_markbad_lowlevel(s
+ */
+ static int nand_check_wp(struct mtd_info *mtd)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ /* Broken xD cards report WP despite being writable */
+ if (chip->options & NAND_BROKEN_XD)
+@@ -491,7 +518,7 @@ static int nand_check_wp(struct mtd_info
+ */
+ static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ if (!chip->bbt)
+ return 0;
+@@ -503,19 +530,17 @@ static int nand_block_isreserved(struct
+ * nand_block_checkbad - [GENERIC] Check if a block is marked bad
+ * @mtd: MTD device structure
+ * @ofs: offset from device start
+- * @getchip: 0, if the chip is already selected
+ * @allowbbt: 1, if its allowed to access the bbt area
+ *
+ * Check, if the block is bad. Either by reading the bad block table or
+ * calling of the scan function.
+ */
+-static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
+- int allowbbt)
++static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int allowbbt)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ if (!chip->bbt)
+- return chip->block_bad(mtd, ofs, getchip);
++ return chip->block_bad(mtd, ofs);
+
+ /* Return info from the table */
+ return nand_isbad_bbt(mtd, ofs, allowbbt);
+@@ -531,7 +556,7 @@ static int nand_block_checkbad(struct mt
+ */
+ static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ int i;
+
+ /* Wait for the device to get ready */
+@@ -551,7 +576,7 @@ static void panic_nand_wait_ready(struct
+ */
+ void nand_wait_ready(struct mtd_info *mtd)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ unsigned long timeo = 400;
+
+ if (in_interrupt() || oops_in_progress)
+@@ -566,8 +591,8 @@ void nand_wait_ready(struct mtd_info *mt
+ cond_resched();
+ } while (time_before(jiffies, timeo));
+
+- pr_warn_ratelimited(
+- "timeout while waiting for chip to become ready\n");
++ if (!chip->dev_ready(mtd))
++ pr_warn_ratelimited("timeout while waiting for chip to become ready\n");
+ out:
+ led_trigger_event(nand_led_trigger, LED_OFF);
+ }
+@@ -582,7 +607,7 @@ EXPORT_SYMBOL_GPL(nand_wait_ready);
+ */
+ static void nand_wait_status_ready(struct mtd_info *mtd, unsigned long timeo)
+ {
+- register struct nand_chip *chip = mtd->priv;
++ register struct nand_chip *chip = mtd_to_nand(mtd);
+
+ timeo = jiffies + msecs_to_jiffies(timeo);
+ do {
+@@ -605,7 +630,7 @@ static void nand_wait_status_ready(struc
+ static void nand_command(struct mtd_info *mtd, unsigned int command,
+ int column, int page_addr)
+ {
+- register struct nand_chip *chip = mtd->priv;
++ register struct nand_chip *chip = mtd_to_nand(mtd);
+ int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE;
+
+ /* Write out the command to the device */
+@@ -708,7 +733,7 @@ static void nand_command(struct mtd_info
+ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
+ int column, int page_addr)
+ {
+- register struct nand_chip *chip = mtd->priv;
++ register struct nand_chip *chip = mtd_to_nand(mtd);
+
+ /* Emulate NAND_CMD_READOOB */
+ if (command == NAND_CMD_READOOB) {
+@@ -832,7 +857,7 @@ static void panic_nand_get_device(struct
+ static int
+ nand_get_device(struct mtd_info *mtd, int new_state)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ spinlock_t *lock = &chip->controller->lock;
+ wait_queue_head_t *wq = &chip->controller->wq;
+ DECLARE_WAITQUEUE(wait, current);
+@@ -952,7 +977,7 @@ static int __nand_unlock(struct mtd_info
+ {
+ int ret = 0;
+ int status, page;
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ /* Submit address of first page to unlock */
+ page = ofs >> chip->page_shift;
+@@ -987,7 +1012,7 @@ int nand_unlock(struct mtd_info *mtd, lo
+ {
+ int ret = 0;
+ int chipnr;
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ pr_debug("%s: start = 0x%012llx, len = %llu\n",
+ __func__, (unsigned long long)ofs, len);
+@@ -1050,7 +1075,7 @@ int nand_lock(struct mtd_info *mtd, loff
+ {
+ int ret = 0;
+ int chipnr, status, page;
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ pr_debug("%s: start = 0x%012llx, len = %llu\n",
+ __func__, (unsigned long long)ofs, len);
+@@ -1309,13 +1334,12 @@ static int nand_read_page_raw_syndrome(s
+ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf, int oob_required, int page)
+ {
+- int i, eccsize = chip->ecc.size;
++ int i, eccsize = chip->ecc.size, ret;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ uint8_t *p = buf;
+ uint8_t *ecc_calc = chip->buffers->ecccalc;
+ uint8_t *ecc_code = chip->buffers->ecccode;
+- uint32_t *eccpos = chip->ecc.layout->eccpos;
+ unsigned int max_bitflips = 0;
+
+ chip->ecc.read_page_raw(mtd, chip, buf, 1, page);
+@@ -1323,8 +1347,10 @@ static int nand_read_page_swecc(struct m
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
+ chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+
+- for (i = 0; i < chip->ecc.total; i++)
+- ecc_code[i] = chip->oob_poi[eccpos[i]];
++ ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
++ chip->ecc.total);
++ if (ret)
++ return ret;
+
+ eccsteps = chip->ecc.steps;
+ p = buf;
+@@ -1356,14 +1382,14 @@ static int nand_read_subpage(struct mtd_
+ uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi,
+ int page)
+ {
+- int start_step, end_step, num_steps;
+- uint32_t *eccpos = chip->ecc.layout->eccpos;
++ int start_step, end_step, num_steps, ret;
+ uint8_t *p;
+ int data_col_addr, i, gaps = 0;
+ int datafrag_len, eccfrag_len, aligned_len, aligned_pos;
+ int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1;
+- int index;
++ int index, section = 0;
+ unsigned int max_bitflips = 0;
++ struct mtd_oob_region oobregion = { };
+
+ /* Column address within the page aligned to ECC size (256bytes) */
+ start_step = data_offs / chip->ecc.size;
+@@ -1391,12 +1417,13 @@ static int nand_read_subpage(struct mtd_
+ * The performance is faster if we position offsets according to
+ * ecc.pos. Let's make sure that there are no gaps in ECC positions.
+ */
+- for (i = 0; i < eccfrag_len - 1; i++) {
+- if (eccpos[i + index] + 1 != eccpos[i + index + 1]) {
+- gaps = 1;
+- break;
+- }
+- }
++ ret = mtd_ooblayout_find_eccregion(mtd, index, &section, &oobregion);
++ if (ret)
++ return ret;
++
++ if (oobregion.length < eccfrag_len)
++ gaps = 1;
++
+ if (gaps) {
+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+@@ -1405,20 +1432,23 @@ static int nand_read_subpage(struct mtd_
+ * Send the command to read the particular ECC bytes take care
+ * about buswidth alignment in read_buf.
+ */
+- aligned_pos = eccpos[index] & ~(busw - 1);
++ aligned_pos = oobregion.offset & ~(busw - 1);
+ aligned_len = eccfrag_len;
+- if (eccpos[index] & (busw - 1))
++ if (oobregion.offset & (busw - 1))
+ aligned_len++;
+- if (eccpos[index + (num_steps * chip->ecc.bytes)] & (busw - 1))
++ if ((oobregion.offset + (num_steps * chip->ecc.bytes)) &
++ (busw - 1))
+ aligned_len++;
+
+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
+- mtd->writesize + aligned_pos, -1);
++ mtd->writesize + aligned_pos, -1);
+ chip->read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len);
+ }
+
+- for (i = 0; i < eccfrag_len; i++)
+- chip->buffers->ecccode[i] = chip->oob_poi[eccpos[i + index]];
++ ret = mtd_ooblayout_get_eccbytes(mtd, chip->buffers->ecccode,
++ chip->oob_poi, index, eccfrag_len);
++ if (ret)
++ return ret;
+
+ p = bufpoi + data_col_addr;
+ for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) {
+@@ -1426,6 +1456,16 @@ static int nand_read_subpage(struct mtd_
+
+ stat = chip->ecc.correct(mtd, p,
+ &chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]);
++ if (stat == -EBADMSG &&
++ (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
++ /* check for empty pages with bitflips */
++ stat = nand_check_erased_ecc_chunk(p, chip->ecc.size,
++ &chip->buffers->ecccode[i],
++ chip->ecc.bytes,
++ NULL, 0,
++ chip->ecc.strength);
++ }
++
+ if (stat < 0) {
+ mtd->ecc_stats.failed++;
+ } else {
+@@ -1449,13 +1489,12 @@ static int nand_read_subpage(struct mtd_
+ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf, int oob_required, int page)
+ {
+- int i, eccsize = chip->ecc.size;
++ int i, eccsize = chip->ecc.size, ret;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ uint8_t *p = buf;
+ uint8_t *ecc_calc = chip->buffers->ecccalc;
+ uint8_t *ecc_code = chip->buffers->ecccode;
+- uint32_t *eccpos = chip->ecc.layout->eccpos;
+ unsigned int max_bitflips = 0;
+
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+@@ -1465,8 +1504,10 @@ static int nand_read_page_hwecc(struct m
+ }
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+- for (i = 0; i < chip->ecc.total; i++)
+- ecc_code[i] = chip->oob_poi[eccpos[i]];
++ ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
++ chip->ecc.total);
++ if (ret)
++ return ret;
+
+ eccsteps = chip->ecc.steps;
+ p = buf;
+@@ -1475,6 +1516,15 @@ static int nand_read_page_hwecc(struct m
+ int stat;
+
+ stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
++ if (stat == -EBADMSG &&
++ (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
++ /* check for empty pages with bitflips */
++ stat = nand_check_erased_ecc_chunk(p, eccsize,
++ &ecc_code[i], eccbytes,
++ NULL, 0,
++ chip->ecc.strength);
++ }
++
+ if (stat < 0) {
+ mtd->ecc_stats.failed++;
+ } else {
+@@ -1502,12 +1552,11 @@ static int nand_read_page_hwecc(struct m
+ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
+ struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
+ {
+- int i, eccsize = chip->ecc.size;
++ int i, eccsize = chip->ecc.size, ret;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ uint8_t *p = buf;
+ uint8_t *ecc_code = chip->buffers->ecccode;
+- uint32_t *eccpos = chip->ecc.layout->eccpos;
+ uint8_t *ecc_calc = chip->buffers->ecccalc;
+ unsigned int max_bitflips = 0;
+
+@@ -1516,8 +1565,10 @@ static int nand_read_page_hwecc_oob_firs
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+
+- for (i = 0; i < chip->ecc.total; i++)
+- ecc_code[i] = chip->oob_poi[eccpos[i]];
++ ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
++ chip->ecc.total);
++ if (ret)
++ return ret;
+
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+ int stat;
+@@ -1527,6 +1578,15 @@ static int nand_read_page_hwecc_oob_firs
+ chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+
+ stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL);
++ if (stat == -EBADMSG &&
++ (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
++ /* check for empty pages with bitflips */
++ stat = nand_check_erased_ecc_chunk(p, eccsize,
++ &ecc_code[i], eccbytes,
++ NULL, 0,
++ chip->ecc.strength);
++ }
++
+ if (stat < 0) {
+ mtd->ecc_stats.failed++;
+ } else {
+@@ -1554,6 +1614,7 @@ static int nand_read_page_syndrome(struc
+ int i, eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
++ int eccpadbytes = eccbytes + chip->ecc.prepad + chip->ecc.postpad;
+ uint8_t *p = buf;
+ uint8_t *oob = chip->oob_poi;
+ unsigned int max_bitflips = 0;
+@@ -1573,19 +1634,29 @@ static int nand_read_page_syndrome(struc
+ chip->read_buf(mtd, oob, eccbytes);
+ stat = chip->ecc.correct(mtd, p, oob, NULL);
+
+- if (stat < 0) {
+- mtd->ecc_stats.failed++;
+- } else {
+- mtd->ecc_stats.corrected += stat;
+- max_bitflips = max_t(unsigned int, max_bitflips, stat);
+- }
+-
+ oob += eccbytes;
+
+ if (chip->ecc.postpad) {
+ chip->read_buf(mtd, oob, chip->ecc.postpad);
+ oob += chip->ecc.postpad;
+ }
++
++ if (stat == -EBADMSG &&
++ (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
++ /* check for empty pages with bitflips */
++ stat = nand_check_erased_ecc_chunk(p, chip->ecc.size,
++ oob - eccpadbytes,
++ eccpadbytes,
++ NULL, 0,
++ chip->ecc.strength);
++ }
++
++ if (stat < 0) {
++ mtd->ecc_stats.failed++;
++ } else {
++ mtd->ecc_stats.corrected += stat;
++ max_bitflips = max_t(unsigned int, max_bitflips, stat);
++ }
+ }
+
+ /* Calculate remaining oob bytes */
+@@ -1598,14 +1669,17 @@ static int nand_read_page_syndrome(struc
+
+ /**
+ * nand_transfer_oob - [INTERN] Transfer oob to client buffer
+- * @chip: nand chip structure
++ * @mtd: mtd info structure
+ * @oob: oob destination address
+ * @ops: oob ops structure
+ * @len: size of oob to transfer
+ */
+-static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
++static uint8_t *nand_transfer_oob(struct mtd_info *mtd, uint8_t *oob,
+ struct mtd_oob_ops *ops, size_t len)
+ {
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ int ret;
++
+ switch (ops->mode) {
+
+ case MTD_OPS_PLACE_OOB:
+@@ -1613,31 +1687,12 @@ static uint8_t *nand_transfer_oob(struct
+ memcpy(oob, chip->oob_poi + ops->ooboffs, len);
+ return oob + len;
+
+- case MTD_OPS_AUTO_OOB: {
+- struct nand_oobfree *free = chip->ecc.layout->oobfree;
+- uint32_t boffs = 0, roffs = ops->ooboffs;
+- size_t bytes = 0;
+-
+- for (; free->length && len; free++, len -= bytes) {
+- /* Read request not from offset 0? */
+- if (unlikely(roffs)) {
+- if (roffs >= free->length) {
+- roffs -= free->length;
+- continue;
+- }
+- boffs = free->offset + roffs;
+- bytes = min_t(size_t, len,
+- (free->length - roffs));
+- roffs = 0;
+- } else {
+- bytes = min_t(size_t, len, free->length);
+- boffs = free->offset;
+- }
+- memcpy(oob, chip->oob_poi + boffs, bytes);
+- oob += bytes;
+- }
+- return oob;
+- }
++ case MTD_OPS_AUTO_OOB:
++ ret = mtd_ooblayout_get_databytes(mtd, oob, chip->oob_poi,
++ ops->ooboffs, len);
++ BUG_ON(ret);
++ return oob + len;
++
+ default:
+ BUG();
+ }
+@@ -1655,7 +1710,7 @@ static uint8_t *nand_transfer_oob(struct
+ */
+ static int nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ pr_debug("setting READ RETRY mode %d\n", retry_mode);
+
+@@ -1680,12 +1735,11 @@ static int nand_do_read_ops(struct mtd_i
+ struct mtd_oob_ops *ops)
+ {
+ int chipnr, page, realpage, col, bytes, aligned, oob_required;
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ int ret = 0;
+ uint32_t readlen = ops->len;
+ uint32_t oobreadlen = ops->ooblen;
+- uint32_t max_oobsize = ops->mode == MTD_OPS_AUTO_OOB ?
+- mtd->oobavail : mtd->oobsize;
++ uint32_t max_oobsize = mtd_oobavail(mtd, ops);
+
+ uint8_t *bufpoi, *oob, *buf;
+ int use_bufpoi;
+@@ -1772,7 +1826,7 @@ read_retry:
+ int toread = min(oobreadlen, max_oobsize);
+
+ if (toread) {
+- oob = nand_transfer_oob(chip,
++ oob = nand_transfer_oob(mtd,
+ oob, ops, toread);
+ oobreadlen -= toread;
+ }
+@@ -2024,7 +2078,7 @@ static int nand_do_read_oob(struct mtd_i
+ struct mtd_oob_ops *ops)
+ {
+ int page, realpage, chipnr;
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_ecc_stats stats;
+ int readlen = ops->ooblen;
+ int len;
+@@ -2036,10 +2090,7 @@ static int nand_do_read_oob(struct mtd_i
+
+ stats = mtd->ecc_stats;
+
+- if (ops->mode == MTD_OPS_AUTO_OOB)
+- len = chip->ecc.layout->oobavail;
+- else
+- len = mtd->oobsize;
++ len = mtd_oobavail(mtd, ops);
+
+ if (unlikely(ops->ooboffs >= len)) {
+ pr_debug("%s: attempt to start read outside oob\n",
+@@ -2073,7 +2124,7 @@ static int nand_do_read_oob(struct mtd_i
+ break;
+
+ len = min(len, readlen);
+- buf = nand_transfer_oob(chip, buf, ops, len);
++ buf = nand_transfer_oob(mtd, buf, ops, len);
+
+ if (chip->options & NAND_NEED_READRDY) {
+ /* Apply delay or wait for ready/busy pin */
+@@ -2232,19 +2283,20 @@ static int nand_write_page_swecc(struct
+ const uint8_t *buf, int oob_required,
+ int page)
+ {
+- int i, eccsize = chip->ecc.size;
++ int i, eccsize = chip->ecc.size, ret;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ uint8_t *ecc_calc = chip->buffers->ecccalc;
+ const uint8_t *p = buf;
+- uint32_t *eccpos = chip->ecc.layout->eccpos;
+
+ /* Software ECC calculation */
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
+ chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+
+- for (i = 0; i < chip->ecc.total; i++)
+- chip->oob_poi[eccpos[i]] = ecc_calc[i];
++ ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
++ chip->ecc.total);
++ if (ret)
++ return ret;
+
+ return chip->ecc.write_page_raw(mtd, chip, buf, 1, page);
+ }
+@@ -2261,12 +2313,11 @@ static int nand_write_page_hwecc(struct
+ const uint8_t *buf, int oob_required,
+ int page)
+ {
+- int i, eccsize = chip->ecc.size;
++ int i, eccsize = chip->ecc.size, ret;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ uint8_t *ecc_calc = chip->buffers->ecccalc;
+ const uint8_t *p = buf;
+- uint32_t *eccpos = chip->ecc.layout->eccpos;
+
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+ chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+@@ -2274,8 +2325,10 @@ static int nand_write_page_hwecc(struct
+ chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+ }
+
+- for (i = 0; i < chip->ecc.total; i++)
+- chip->oob_poi[eccpos[i]] = ecc_calc[i];
++ ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
++ chip->ecc.total);
++ if (ret)
++ return ret;
+
+ chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+@@ -2303,11 +2356,10 @@ static int nand_write_subpage_hwecc(stru
+ int ecc_size = chip->ecc.size;
+ int ecc_bytes = chip->ecc.bytes;
+ int ecc_steps = chip->ecc.steps;
+- uint32_t *eccpos = chip->ecc.layout->eccpos;
+ uint32_t start_step = offset / ecc_size;
+ uint32_t end_step = (offset + data_len - 1) / ecc_size;
+ int oob_bytes = mtd->oobsize / ecc_steps;
+- int step, i;
++ int step, ret;
+
+ for (step = 0; step < ecc_steps; step++) {
+ /* configure controller for WRITE access */
+@@ -2335,8 +2387,10 @@ static int nand_write_subpage_hwecc(stru
+ /* copy calculated ECC for whole page to chip->buffer->oob */
+ /* this include masked-value(0xFF) for unwritten subpages */
+ ecc_calc = chip->buffers->ecccalc;
+- for (i = 0; i < chip->ecc.total; i++)
+- chip->oob_poi[eccpos[i]] = ecc_calc[i];
++ ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
++ chip->ecc.total);
++ if (ret)
++ return ret;
+
+ /* write OOB buffer to NAND device */
+ chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+@@ -2472,7 +2526,8 @@ static int nand_write_page(struct mtd_in
+ static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len,
+ struct mtd_oob_ops *ops)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ int ret;
+
+ /*
+ * Initialise to all 0xFF, to avoid the possibility of left over OOB
+@@ -2487,31 +2542,12 @@ static uint8_t *nand_fill_oob(struct mtd
+ memcpy(chip->oob_poi + ops->ooboffs, oob, len);
+ return oob + len;
+
+- case MTD_OPS_AUTO_OOB: {
+- struct nand_oobfree *free = chip->ecc.layout->oobfree;
+- uint32_t boffs = 0, woffs = ops->ooboffs;
+- size_t bytes = 0;
+-
+- for (; free->length && len; free++, len -= bytes) {
+- /* Write request not from offset 0? */
+- if (unlikely(woffs)) {
+- if (woffs >= free->length) {
+- woffs -= free->length;
+- continue;
+- }
+- boffs = free->offset + woffs;
+- bytes = min_t(size_t, len,
+- (free->length - woffs));
+- woffs = 0;
+- } else {
+- bytes = min_t(size_t, len, free->length);
+- boffs = free->offset;
+- }
+- memcpy(chip->oob_poi + boffs, oob, bytes);
+- oob += bytes;
+- }
+- return oob;
+- }
++ case MTD_OPS_AUTO_OOB:
++ ret = mtd_ooblayout_set_databytes(mtd, oob, chip->oob_poi,
++ ops->ooboffs, len);
++ BUG_ON(ret);
++ return oob + len;
++
+ default:
+ BUG();
+ }
+@@ -2532,12 +2568,11 @@ static int nand_do_write_ops(struct mtd_
+ struct mtd_oob_ops *ops)
+ {
+ int chipnr, realpage, page, blockmask, column;
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ uint32_t writelen = ops->len;
+
+ uint32_t oobwritelen = ops->ooblen;
+- uint32_t oobmaxlen = ops->mode == MTD_OPS_AUTO_OOB ?
+- mtd->oobavail : mtd->oobsize;
++ uint32_t oobmaxlen = mtd_oobavail(mtd, ops);
+
+ uint8_t *oob = ops->oobbuf;
+ uint8_t *buf = ops->datbuf;
+@@ -2662,7 +2697,7 @@ err_out:
+ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const uint8_t *buf)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_oob_ops ops;
+ int ret;
+
+@@ -2722,15 +2757,12 @@ static int nand_do_write_oob(struct mtd_
+ struct mtd_oob_ops *ops)
+ {
+ int chipnr, page, status, len;
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ pr_debug("%s: to = 0x%08x, len = %i\n",
+ __func__, (unsigned int)to, (int)ops->ooblen);
+
+- if (ops->mode == MTD_OPS_AUTO_OOB)
+- len = chip->ecc.layout->oobavail;
+- else
+- len = mtd->oobsize;
++ len = mtd_oobavail(mtd, ops);
+
+ /* Do not allow write past end of page */
+ if ((ops->ooboffs + ops->ooblen) > len) {
+@@ -2847,7 +2879,7 @@ out:
+ */
+ static int single_erase(struct mtd_info *mtd, int page)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ /* Send commands to erase a block */
+ chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
+ chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
+@@ -2879,7 +2911,7 @@ int nand_erase_nand(struct mtd_info *mtd
+ int allowbbt)
+ {
+ int page, status, pages_per_block, ret, chipnr;
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ loff_t len;
+
+ pr_debug("%s: start = 0x%012llx, len = %llu\n",
+@@ -2918,7 +2950,7 @@ int nand_erase_nand(struct mtd_info *mtd
+ while (len) {
+ /* Check if we have a bad block, we do not erase bad blocks! */
+ if (nand_block_checkbad(mtd, ((loff_t) page) <<
+- chip->page_shift, 0, allowbbt)) {
++ chip->page_shift, allowbbt)) {
+ pr_warn("%s: attempt to erase a bad block at page 0x%08x\n",
+ __func__, page);
+ instr->state = MTD_ERASE_FAILED;
+@@ -3005,7 +3037,20 @@ static void nand_sync(struct mtd_info *m
+ */
+ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
+ {
+- return nand_block_checkbad(mtd, offs, 1, 0);
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ int chipnr = (int)(offs >> chip->chip_shift);
++ int ret;
++
++ /* Select the NAND device */
++ nand_get_device(mtd, FL_READING);
++ chip->select_chip(mtd, chipnr);
++
++ ret = nand_block_checkbad(mtd, offs, 0);
++
++ chip->select_chip(mtd, -1);
++ nand_release_device(mtd);
++
++ return ret;
+ }
+
+ /**
+@@ -3094,7 +3139,7 @@ static int nand_suspend(struct mtd_info
+ */
+ static void nand_resume(struct mtd_info *mtd)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ if (chip->state == FL_PM_SUSPENDED)
+ nand_release_device(mtd);
+@@ -3266,7 +3311,7 @@ ext_out:
+
+ static int nand_setup_read_retry_micron(struct mtd_info *mtd, int retry_mode)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode};
+
+ return chip->onfi_set_features(mtd, chip, ONFI_FEATURE_ADDR_READ_RETRY,
+@@ -3937,10 +3982,13 @@ ident_done:
+ return type;
+ }
+
+-static int nand_dt_init(struct mtd_info *mtd, struct nand_chip *chip,
+- struct device_node *dn)
++static int nand_dt_init(struct nand_chip *chip)
+ {
+- int ecc_mode, ecc_strength, ecc_step;
++ struct device_node *dn = nand_get_flash_node(chip);
++ int ecc_mode, ecc_algo, ecc_strength, ecc_step;
++
++ if (!dn)
++ return 0;
+
+ if (of_get_nand_bus_width(dn) == 16)
+ chip->options |= NAND_BUSWIDTH_16;
+@@ -3949,6 +3997,7 @@ static int nand_dt_init(struct mtd_info
+ chip->bbt_options |= NAND_BBT_USE_FLASH;
+
+ ecc_mode = of_get_nand_ecc_mode(dn);
++ ecc_algo = of_get_nand_ecc_algo(dn);
+ ecc_strength = of_get_nand_ecc_strength(dn);
+ ecc_step = of_get_nand_ecc_step_size(dn);
+
+@@ -3961,6 +4010,9 @@ static int nand_dt_init(struct mtd_info
+ if (ecc_mode >= 0)
+ chip->ecc.mode = ecc_mode;
+
++ if (ecc_algo >= 0)
++ chip->ecc.algo = ecc_algo;
++
+ if (ecc_strength >= 0)
+ chip->ecc.strength = ecc_strength;
+
+@@ -3984,15 +4036,16 @@ int nand_scan_ident(struct mtd_info *mtd
+ struct nand_flash_dev *table)
+ {
+ int i, nand_maf_id, nand_dev_id;
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct nand_flash_dev *type;
+ int ret;
+
+- if (chip->flash_node) {
+- ret = nand_dt_init(mtd, chip, chip->flash_node);
+- if (ret)
+- return ret;
+- }
++ ret = nand_dt_init(chip);
++ if (ret)
++ return ret;
++
++ if (!mtd->name && mtd->dev.parent)
++ mtd->name = dev_name(mtd->dev.parent);
+
+ if (!mtd->name && mtd->dev.parent)
+ mtd->name = dev_name(mtd->dev.parent);
+@@ -4055,7 +4108,7 @@ EXPORT_SYMBOL(nand_scan_ident);
+ */
+ static bool nand_ecc_strength_good(struct mtd_info *mtd)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
+ int corr, ds_corr;
+
+@@ -4083,10 +4136,10 @@ static bool nand_ecc_strength_good(struc
+ */
+ int nand_scan_tail(struct mtd_info *mtd)
+ {
+- int i;
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
+ struct nand_buffers *nbuf;
++ int ret;
+
+ /* New bad blocks should be marked in OOB, flash-based BBT, or both */
+ BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) &&
+@@ -4113,19 +4166,15 @@ int nand_scan_tail(struct mtd_info *mtd)
+ /*
+ * If no default placement scheme is given, select an appropriate one.
+ */
+- if (!ecc->layout && (ecc->mode != NAND_ECC_SOFT_BCH)) {
++ if (!mtd->ooblayout && (ecc->mode != NAND_ECC_SOFT_BCH)) {
+ switch (mtd->oobsize) {
+ case 8:
+- ecc->layout = &nand_oob_8;
+- break;
+ case 16:
+- ecc->layout = &nand_oob_16;
++ mtd_set_ooblayout(mtd, &nand_ooblayout_sp_ops);
+ break;
+ case 64:
+- ecc->layout = &nand_oob_64;
+- break;
+ case 128:
+- ecc->layout = &nand_oob_128;
++ mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
+ break;
+ default:
+ pr_warn("No oob scheme defined for oobsize %d\n",
+@@ -4168,7 +4217,7 @@ int nand_scan_tail(struct mtd_info *mtd)
+ ecc->write_oob = nand_write_oob_std;
+ if (!ecc->read_subpage)
+ ecc->read_subpage = nand_read_subpage;
+- if (!ecc->write_subpage)
++ if (!ecc->write_subpage && ecc->hwctl && ecc->calculate)
+ ecc->write_subpage = nand_write_subpage_hwecc;
+
+ case NAND_ECC_HW_SYNDROME:
+@@ -4246,10 +4295,8 @@ int nand_scan_tail(struct mtd_info *mtd)
+ }
+
+ /* See nand_bch_init() for details. */
+- ecc->bytes = DIV_ROUND_UP(
+- ecc->strength * fls(8 * ecc->size), 8);
+- ecc->priv = nand_bch_init(mtd, ecc->size, ecc->bytes,
+- &ecc->layout);
++ ecc->bytes = 0;
++ ecc->priv = nand_bch_init(mtd);
+ if (!ecc->priv) {
+ pr_warn("BCH ECC initialization failed!\n");
+ BUG();
+@@ -4280,20 +4327,9 @@ int nand_scan_tail(struct mtd_info *mtd)
+ if (!ecc->write_oob_raw)
+ ecc->write_oob_raw = ecc->write_oob;
+
+- /*
+- * The number of bytes available for a client to place data into
+- * the out of band area.
+- */
+- ecc->layout->oobavail = 0;
+- for (i = 0; ecc->layout->oobfree[i].length
+- && i < ARRAY_SIZE(ecc->layout->oobfree); i++)
+- ecc->layout->oobavail += ecc->layout->oobfree[i].length;
+- mtd->oobavail = ecc->layout->oobavail;
+-
+- /* ECC sanity check: warn if it's too weak */
+- if (!nand_ecc_strength_good(mtd))
+- pr_warn("WARNING: %s: the ECC used on your system is too weak compared to the one required by the NAND chip\n",
+- mtd->name);
++ /* propagate ecc info to mtd_info */
++ mtd->ecc_strength = ecc->strength;
++ mtd->ecc_step_size = ecc->size;
+
+ /*
+ * Set the number of read / write steps for one page depending on ECC
+@@ -4306,6 +4342,21 @@ int nand_scan_tail(struct mtd_info *mtd)
+ }
+ ecc->total = ecc->steps * ecc->bytes;
+
++ /*
++ * The number of bytes available for a client to place data into
++ * the out of band area.
++ */
++ ret = mtd_ooblayout_count_freebytes(mtd);
++ if (ret < 0)
++ ret = 0;
++
++ mtd->oobavail = ret;
++
++ /* ECC sanity check: warn if it's too weak */
++ if (!nand_ecc_strength_good(mtd))
++ pr_warn("WARNING: %s: the ECC used on your system is too weak compared to the one required by the NAND chip\n",
++ mtd->name);
++
+ /* Allow subpage writes up to ecc.steps. Not possible for MLC flash */
+ if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && nand_is_slc(chip)) {
+ switch (ecc->steps) {
+@@ -4362,10 +4413,6 @@ int nand_scan_tail(struct mtd_info *mtd)
+ mtd->_block_markbad = nand_block_markbad;
+ mtd->writebufsize = mtd->writesize;
+
+- /* propagate ecc info to mtd_info */
+- mtd->ecclayout = ecc->layout;
+- mtd->ecc_strength = ecc->strength;
+- mtd->ecc_step_size = ecc->size;
+ /*
+ * Initialize bitflip_threshold to its default prior scan_bbt() call.
+ * scan_bbt() might invoke mtd_read(), thus bitflip_threshold must be
+@@ -4421,7 +4468,7 @@ EXPORT_SYMBOL(nand_scan);
+ */
+ void nand_release(struct mtd_info *mtd)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ if (chip->ecc.mode == NAND_ECC_SOFT_BCH)
+ nand_bch_free((struct nand_bch_control *)chip->ecc.priv);
+--- a/drivers/mtd/nand/nand_bbt.c
++++ b/drivers/mtd/nand/nand_bbt.c
+@@ -172,7 +172,7 @@ static int read_bbt(struct mtd_info *mtd
+ struct nand_bbt_descr *td, int offs)
+ {
+ int res, ret = 0, i, j, act = 0;
+- struct nand_chip *this = mtd->priv;
++ struct nand_chip *this = mtd_to_nand(mtd);
+ size_t retlen, len, totlen;
+ loff_t from;
+ int bits = td->options & NAND_BBT_NRBITS_MSK;
+@@ -263,7 +263,7 @@ static int read_bbt(struct mtd_info *mtd
+ */
+ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip)
+ {
+- struct nand_chip *this = mtd->priv;
++ struct nand_chip *this = mtd_to_nand(mtd);
+ int res = 0, i;
+
+ if (td->options & NAND_BBT_PERCHIP) {
+@@ -388,7 +388,7 @@ static u32 bbt_get_ver_offs(struct mtd_i
+ static void read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
+ struct nand_bbt_descr *td, struct nand_bbt_descr *md)
+ {
+- struct nand_chip *this = mtd->priv;
++ struct nand_chip *this = mtd_to_nand(mtd);
+
+ /* Read the primary version, if available */
+ if (td->options & NAND_BBT_VERSION) {
+@@ -454,7 +454,7 @@ static int scan_block_fast(struct mtd_in
+ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
+ struct nand_bbt_descr *bd, int chip)
+ {
+- struct nand_chip *this = mtd->priv;
++ struct nand_chip *this = mtd_to_nand(mtd);
+ int i, numblocks, numpages;
+ int startblock;
+ loff_t from;
+@@ -523,7 +523,7 @@ static int create_bbt(struct mtd_info *m
+ */
+ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td)
+ {
+- struct nand_chip *this = mtd->priv;
++ struct nand_chip *this = mtd_to_nand(mtd);
+ int i, chips;
+ int startblock, block, dir;
+ int scanlen = mtd->writesize + mtd->oobsize;
+@@ -618,7 +618,7 @@ static int write_bbt(struct mtd_info *mt
+ struct nand_bbt_descr *td, struct nand_bbt_descr *md,
+ int chipsel)
+ {
+- struct nand_chip *this = mtd->priv;
++ struct nand_chip *this = mtd_to_nand(mtd);
+ struct erase_info einfo;
+ int i, res, chip = 0;
+ int bits, startblock, dir, page, offs, numblocks, sft, sftmsk;
+@@ -819,7 +819,7 @@ static int write_bbt(struct mtd_info *mt
+ */
+ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
+ {
+- struct nand_chip *this = mtd->priv;
++ struct nand_chip *this = mtd_to_nand(mtd);
+
+ return create_bbt(mtd, this->buffers->databuf, bd, -1);
+ }
+@@ -838,7 +838,7 @@ static inline int nand_memory_bbt(struct
+ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd)
+ {
+ int i, chips, writeops, create, chipsel, res, res2;
+- struct nand_chip *this = mtd->priv;
++ struct nand_chip *this = mtd_to_nand(mtd);
+ struct nand_bbt_descr *td = this->bbt_td;
+ struct nand_bbt_descr *md = this->bbt_md;
+ struct nand_bbt_descr *rd, *rd2;
+@@ -962,7 +962,7 @@ static int check_create(struct mtd_info
+ */
+ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
+ {
+- struct nand_chip *this = mtd->priv;
++ struct nand_chip *this = mtd_to_nand(mtd);
+ int i, j, chips, block, nrblocks, update;
+ uint8_t oldval;
+
+@@ -1022,7 +1022,7 @@ static void mark_bbt_region(struct mtd_i
+ */
+ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)
+ {
+- struct nand_chip *this = mtd->priv;
++ struct nand_chip *this = mtd_to_nand(mtd);
+ u32 pattern_len;
+ u32 bits;
+ u32 table_size;
+@@ -1074,7 +1074,7 @@ static void verify_bbt_descr(struct mtd_
+ */
+ static int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
+ {
+- struct nand_chip *this = mtd->priv;
++ struct nand_chip *this = mtd_to_nand(mtd);
+ int len, res;
+ uint8_t *buf;
+ struct nand_bbt_descr *td = this->bbt_td;
+@@ -1147,7 +1147,7 @@ err:
+ */
+ static int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
+ {
+- struct nand_chip *this = mtd->priv;
++ struct nand_chip *this = mtd_to_nand(mtd);
+ int len, res = 0;
+ int chip, chipsel;
+ uint8_t *buf;
+@@ -1281,7 +1281,7 @@ static int nand_create_badblock_pattern(
+ */
+ int nand_default_bbt(struct mtd_info *mtd)
+ {
+- struct nand_chip *this = mtd->priv;
++ struct nand_chip *this = mtd_to_nand(mtd);
+ int ret;
+
+ /* Is a flash based bad block table requested? */
+@@ -1317,7 +1317,7 @@ int nand_default_bbt(struct mtd_info *mt
+ */
+ int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs)
+ {
+- struct nand_chip *this = mtd->priv;
++ struct nand_chip *this = mtd_to_nand(mtd);
+ int block;
+
+ block = (int)(offs >> this->bbt_erase_shift);
+@@ -1332,7 +1332,7 @@ int nand_isreserved_bbt(struct mtd_info
+ */
+ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
+ {
+- struct nand_chip *this = mtd->priv;
++ struct nand_chip *this = mtd_to_nand(mtd);
+ int block, res;
+
+ block = (int)(offs >> this->bbt_erase_shift);
+@@ -1359,7 +1359,7 @@ int nand_isbad_bbt(struct mtd_info *mtd,
+ */
+ int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs)
+ {
+- struct nand_chip *this = mtd->priv;
++ struct nand_chip *this = mtd_to_nand(mtd);
+ int block, ret = 0;
+
+ block = (int)(offs >> this->bbt_erase_shift);
+@@ -1373,5 +1373,3 @@ int nand_markbad_bbt(struct mtd_info *mt
+
+ return ret;
+ }
+-
+-EXPORT_SYMBOL(nand_scan_bbt);
+--- a/drivers/mtd/nand/nand_bch.c
++++ b/drivers/mtd/nand/nand_bch.c
+@@ -32,13 +32,11 @@
+ /**
+ * struct nand_bch_control - private NAND BCH control structure
+ * @bch: BCH control structure
+- * @ecclayout: private ecc layout for this BCH configuration
+ * @errloc: error location array
+ * @eccmask: XOR ecc mask, allows erased pages to be decoded as valid
+ */
+ struct nand_bch_control {
+ struct bch_control *bch;
+- struct nand_ecclayout ecclayout;
+ unsigned int *errloc;
+ unsigned char *eccmask;
+ };
+@@ -52,7 +50,7 @@ struct nand_bch_control {
+ int nand_bch_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
+ unsigned char *code)
+ {
+- const struct nand_chip *chip = mtd->priv;
++ const struct nand_chip *chip = mtd_to_nand(mtd);
+ struct nand_bch_control *nbc = chip->ecc.priv;
+ unsigned int i;
+
+@@ -79,7 +77,7 @@ EXPORT_SYMBOL(nand_bch_calculate_ecc);
+ int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
+ unsigned char *read_ecc, unsigned char *calc_ecc)
+ {
+- const struct nand_chip *chip = mtd->priv;
++ const struct nand_chip *chip = mtd_to_nand(mtd);
+ struct nand_bch_control *nbc = chip->ecc.priv;
+ unsigned int *errloc = nbc->errloc;
+ int i, count;
+@@ -98,7 +96,7 @@ int nand_bch_correct_data(struct mtd_inf
+ }
+ } else if (count < 0) {
+ printk(KERN_ERR "ecc unrecoverable error\n");
+- count = -1;
++ count = -EBADMSG;
+ }
+ return count;
+ }
+@@ -107,9 +105,6 @@ EXPORT_SYMBOL(nand_bch_correct_data);
+ /**
+ * nand_bch_init - [NAND Interface] Initialize NAND BCH error correction
+ * @mtd: MTD block structure
+- * @eccsize: ecc block size in bytes
+- * @eccbytes: ecc length in bytes
+- * @ecclayout: output default layout
+ *
+ * Returns:
+ * a pointer to a new NAND BCH control structure, or NULL upon failure
+@@ -123,14 +118,20 @@ EXPORT_SYMBOL(nand_bch_correct_data);
+ * @eccsize = 512 (thus, m=13 is the smallest integer such that 2^m-1 > 512*8)
+ * @eccbytes = 7 (7 bytes are required to store m*t = 13*4 = 52 bits)
+ */
+-struct nand_bch_control *
+-nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
+- struct nand_ecclayout **ecclayout)
++struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
+ {
++ struct nand_chip *nand = mtd_to_nand(mtd);
+ unsigned int m, t, eccsteps, i;
+- struct nand_ecclayout *layout;
+ struct nand_bch_control *nbc = NULL;
+ unsigned char *erased_page;
++ unsigned int eccsize = nand->ecc.size;
++ unsigned int eccbytes = nand->ecc.bytes;
++ unsigned int eccstrength = nand->ecc.strength;
++
++ if (!eccbytes && eccstrength) {
++ eccbytes = DIV_ROUND_UP(eccstrength * fls(8 * eccsize), 8);
++ nand->ecc.bytes = eccbytes;
++ }
+
+ if (!eccsize || !eccbytes) {
+ printk(KERN_WARNING "ecc parameters not supplied\n");
+@@ -158,7 +159,7 @@ nand_bch_init(struct mtd_info *mtd, unsi
+ eccsteps = mtd->writesize/eccsize;
+
+ /* if no ecc placement scheme was provided, build one */
+- if (!*ecclayout) {
++ if (!mtd->ooblayout) {
+
+ /* handle large page devices only */
+ if (mtd->oobsize < 64) {
+@@ -167,24 +168,7 @@ nand_bch_init(struct mtd_info *mtd, unsi
+ goto fail;
+ }
+
+- layout = &nbc->ecclayout;
+- layout->eccbytes = eccsteps*eccbytes;
+-
+- /* reserve 2 bytes for bad block marker */
+- if (layout->eccbytes+2 > mtd->oobsize) {
+- printk(KERN_WARNING "no suitable oob scheme available "
+- "for oobsize %d eccbytes %u\n", mtd->oobsize,
+- eccbytes);
+- goto fail;
+- }
+- /* put ecc bytes at oob tail */
+- for (i = 0; i < layout->eccbytes; i++)
+- layout->eccpos[i] = mtd->oobsize-layout->eccbytes+i;
+-
+- layout->oobfree[0].offset = 2;
+- layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes;
+-
+- *ecclayout = layout;
++ mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
+ }
+
+ /* sanity checks */
+@@ -192,7 +176,8 @@ nand_bch_init(struct mtd_info *mtd, unsi
+ printk(KERN_WARNING "eccsize %u is too large\n", eccsize);
+ goto fail;
+ }
+- if ((*ecclayout)->eccbytes != (eccsteps*eccbytes)) {
++
++ if (mtd_ooblayout_count_eccbytes(mtd) != (eccsteps*eccbytes)) {
+ printk(KERN_WARNING "invalid ecc layout\n");
+ goto fail;
+ }
+@@ -216,6 +201,9 @@ nand_bch_init(struct mtd_info *mtd, unsi
+ for (i = 0; i < eccbytes; i++)
+ nbc->eccmask[i] ^= 0xff;
+
++ if (!eccstrength)
++ nand->ecc.strength = (eccbytes * 8) / fls(8 * eccsize);
++
+ return nbc;
+ fail:
+ nand_bch_free(nbc);
+--- a/drivers/mtd/nand/nand_ecc.c
++++ b/drivers/mtd/nand/nand_ecc.c
+@@ -424,7 +424,7 @@ int nand_calculate_ecc(struct mtd_info *
+ unsigned char *code)
+ {
+ __nand_calculate_ecc(buf,
+- ((struct nand_chip *)mtd->priv)->ecc.size, code);
++ mtd_to_nand(mtd)->ecc.size, code);
+
+ return 0;
+ }
+@@ -524,7 +524,7 @@ int nand_correct_data(struct mtd_info *m
+ unsigned char *read_ecc, unsigned char *calc_ecc)
+ {
+ return __nand_correct_data(buf, read_ecc, calc_ecc,
+- ((struct nand_chip *)mtd->priv)->ecc.size);
++ mtd_to_nand(mtd)->ecc.size);
+ }
+ EXPORT_SYMBOL(nand_correct_data);
+
+--- a/drivers/mtd/nand/nand_ids.c
++++ b/drivers/mtd/nand/nand_ids.c
+@@ -50,8 +50,8 @@ struct nand_flash_dev nand_flash_ids[] =
+ SZ_16K, SZ_8K, SZ_4M, 0, 6, 1280, NAND_ECC_INFO(40, SZ_1K) },
+ {"H27UCG8T2ATR-BC 64G 3.3V 8-bit",
+ { .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} },
+- SZ_8K, SZ_8K, SZ_2M, 0, 6, 640, NAND_ECC_INFO(40, SZ_1K),
+- 4 },
++ SZ_8K, SZ_8K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640,
++ NAND_ECC_INFO(40, SZ_1K), 4 },
+
+ LEGACY_ID_NAND("NAND 4MiB 5V 8-bit", 0x6B, 4, SZ_8K, SP_OPTIONS),
+ LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS),
+--- a/drivers/mtd/nand/nandsim.c
++++ b/drivers/mtd/nand/nandsim.c
+@@ -666,8 +666,8 @@ static char *get_partition_name(int i)
+ */
+ static int init_nandsim(struct mtd_info *mtd)
+ {
+- struct nand_chip *chip = mtd->priv;
+- struct nandsim *ns = chip->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct nandsim *ns = nand_get_controller_data(chip);
+ int i, ret = 0;
+ uint64_t remains;
+ uint64_t next_offset;
+@@ -1908,7 +1908,8 @@ static void switch_state(struct nandsim
+
+ static u_char ns_nand_read_byte(struct mtd_info *mtd)
+ {
+- struct nandsim *ns = ((struct nand_chip *)mtd->priv)->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct nandsim *ns = nand_get_controller_data(chip);
+ u_char outb = 0x00;
+
+ /* Sanity and correctness checks */
+@@ -1969,7 +1970,8 @@ static u_char ns_nand_read_byte(struct m
+
+ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
+ {
+- struct nandsim *ns = ((struct nand_chip *)mtd->priv)->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct nandsim *ns = nand_get_controller_data(chip);
+
+ /* Sanity and correctness checks */
+ if (!ns->lines.ce) {
+@@ -2123,7 +2125,8 @@ static void ns_nand_write_byte(struct mt
+
+ static void ns_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int bitmask)
+ {
+- struct nandsim *ns = ((struct nand_chip *)mtd->priv)->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct nandsim *ns = nand_get_controller_data(chip);
+
+ ns->lines.cle = bitmask & NAND_CLE ? 1 : 0;
+ ns->lines.ale = bitmask & NAND_ALE ? 1 : 0;
+@@ -2141,7 +2144,7 @@ static int ns_device_ready(struct mtd_in
+
+ static uint16_t ns_nand_read_word(struct mtd_info *mtd)
+ {
+- struct nand_chip *chip = (struct nand_chip *)mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ NS_DBG("read_word\n");
+
+@@ -2150,7 +2153,8 @@ static uint16_t ns_nand_read_word(struct
+
+ static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+ {
+- struct nandsim *ns = ((struct nand_chip *)mtd->priv)->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct nandsim *ns = nand_get_controller_data(chip);
+
+ /* Check that chip is expecting data input */
+ if (!(ns->state & STATE_DATAIN_MASK)) {
+@@ -2177,7 +2181,8 @@ static void ns_nand_write_buf(struct mtd
+
+ static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+ {
+- struct nandsim *ns = ((struct nand_chip *)mtd->priv)->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct nandsim *ns = nand_get_controller_data(chip);
+
+ /* Sanity and correctness checks */
+ if (!ns->lines.ce) {
+@@ -2198,7 +2203,7 @@ static void ns_nand_read_buf(struct mtd_
+ int i;
+
+ for (i = 0; i < len; i++)
+- buf[i] = ((struct nand_chip *)mtd->priv)->read_byte(mtd);
++ buf[i] = mtd_to_nand(mtd)->read_byte(mtd);
+
+ return;
+ }
+@@ -2236,16 +2241,15 @@ static int __init ns_init_module(void)
+ }
+
+ /* Allocate and initialize mtd_info, nand_chip and nandsim structures */
+- nsmtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip)
+- + sizeof(struct nandsim), GFP_KERNEL);
+- if (!nsmtd) {
++ chip = kzalloc(sizeof(struct nand_chip) + sizeof(struct nandsim),
++ GFP_KERNEL);
++ if (!chip) {
+ NS_ERR("unable to allocate core structures.\n");
+ return -ENOMEM;
+ }
+- chip = (struct nand_chip *)(nsmtd + 1);
+- nsmtd->priv = (void *)chip;
++ nsmtd = nand_to_mtd(chip);
+ nand = (struct nandsim *)(chip + 1);
+- chip->priv = (void *)nand;
++ nand_set_controller_data(chip, (void *)nand);
+
+ /*
+ * Register simulator's callbacks.
+@@ -2257,6 +2261,7 @@ static int __init ns_init_module(void)
+ chip->read_buf = ns_nand_read_buf;
+ chip->read_word = ns_nand_read_word;
+ chip->ecc.mode = NAND_ECC_SOFT;
++ chip->ecc.algo = NAND_ECC_HAMMING;
+ /* The NAND_SKIP_BBTSCAN option is necessary for 'overridesize' */
+ /* and 'badblocks' parameters to work */
+ chip->options |= NAND_SKIP_BBTSCAN;
+@@ -2335,6 +2340,7 @@ static int __init ns_init_module(void)
+ goto error;
+ }
+ chip->ecc.mode = NAND_ECC_SOFT_BCH;
++ chip->ecc.algo = NAND_ECC_BCH;
+ chip->ecc.size = 512;
+ chip->ecc.strength = bch;
+ chip->ecc.bytes = eccbytes;
+@@ -2392,7 +2398,7 @@ err_exit:
+ for (i = 0;i < ARRAY_SIZE(nand->partitions); ++i)
+ kfree(nand->partitions[i].name);
+ error:
+- kfree(nsmtd);
++ kfree(chip);
+ free_lists();
+
+ return retval;
+@@ -2405,7 +2411,8 @@ module_init(ns_init_module);
+ */
+ static void __exit ns_cleanup_module(void)
+ {
+- struct nandsim *ns = ((struct nand_chip *)nsmtd->priv)->priv;
++ struct nand_chip *chip = mtd_to_nand(nsmtd);
++ struct nandsim *ns = nand_get_controller_data(chip);
+ int i;
+
+ nandsim_debugfs_remove(ns);
+@@ -2413,7 +2420,7 @@ static void __exit ns_cleanup_module(voi
+ nand_release(nsmtd); /* Unregister driver */
+ for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i)
+ kfree(ns->partitions[i].name);
+- kfree(nsmtd); /* Free other structures */
++ kfree(mtd_to_nand(nsmtd)); /* Free other structures */
+ free_lists();
+ }
+
+--- a/drivers/mtd/ofpart.c
++++ b/drivers/mtd/ofpart.c
+@@ -26,9 +26,10 @@ static bool node_has_compatible(struct d
+ }
+
+ static int parse_ofpart_partitions(struct mtd_info *master,
+- struct mtd_partition **pparts,
++ const struct mtd_partition **pparts,
+ struct mtd_part_parser_data *data)
+ {
++ struct mtd_partition *parts;
+ struct device_node *mtd_node;
+ struct device_node *ofpart_node;
+ const char *partname;
+@@ -37,10 +38,8 @@ static int parse_ofpart_partitions(struc
+ bool dedicated = true;
+
+
+- if (!data)
+- return 0;
+-
+- mtd_node = data->of_node;
++ /* Pull of_node from the master device node */
++ mtd_node = mtd_get_of_node(master);
+ if (!mtd_node)
+ return 0;
+
+@@ -72,8 +71,8 @@ static int parse_ofpart_partitions(struc
+ if (nr_parts == 0)
+ return 0;
+
+- *pparts = kzalloc(nr_parts * sizeof(**pparts), GFP_KERNEL);
+- if (!*pparts)
++ parts = kzalloc(nr_parts * sizeof(*parts), GFP_KERNEL);
++ if (!parts)
+ return -ENOMEM;
+
+ i = 0;
+@@ -107,19 +106,19 @@ static int parse_ofpart_partitions(struc
+ goto ofpart_fail;
+ }
+
+- (*pparts)[i].offset = of_read_number(reg, a_cells);
+- (*pparts)[i].size = of_read_number(reg + a_cells, s_cells);
++ parts[i].offset = of_read_number(reg, a_cells);
++ parts[i].size = of_read_number(reg + a_cells, s_cells);
+
+ partname = of_get_property(pp, "label", &len);
+ if (!partname)
+ partname = of_get_property(pp, "name", &len);
+- (*pparts)[i].name = partname;
++ parts[i].name = partname;
+
+ if (of_get_property(pp, "read-only", &len))
+- (*pparts)[i].mask_flags |= MTD_WRITEABLE;
++ parts[i].mask_flags |= MTD_WRITEABLE;
+
+ if (of_get_property(pp, "lock", &len))
+- (*pparts)[i].mask_flags |= MTD_POWERUP_LOCK;
++ parts[i].mask_flags |= MTD_POWERUP_LOCK;
+
+ i++;
+ }
+@@ -127,6 +126,7 @@ static int parse_ofpart_partitions(struc
+ if (!nr_parts)
+ goto ofpart_none;
+
++ *pparts = parts;
+ return nr_parts;
+
+ ofpart_fail:
+@@ -135,21 +135,20 @@ ofpart_fail:
+ ret = -EINVAL;
+ ofpart_none:
+ of_node_put(pp);
+- kfree(*pparts);
+- *pparts = NULL;
++ kfree(parts);
+ return ret;
+ }
+
+ static struct mtd_part_parser ofpart_parser = {
+- .owner = THIS_MODULE,
+ .parse_fn = parse_ofpart_partitions,
+ .name = "ofpart",
+ };
+
+ static int parse_ofoldpart_partitions(struct mtd_info *master,
+- struct mtd_partition **pparts,
++ const struct mtd_partition **pparts,
+ struct mtd_part_parser_data *data)
+ {
++ struct mtd_partition *parts;
+ struct device_node *dp;
+ int i, plen, nr_parts;
+ const struct {
+@@ -157,10 +156,8 @@ static int parse_ofoldpart_partitions(st
+ } *part;
+ const char *names;
+
+- if (!data)
+- return 0;
+-
+- dp = data->of_node;
++ /* Pull of_node from the master device node */
++ dp = mtd_get_of_node(master);
+ if (!dp)
+ return 0;
+
+@@ -173,37 +170,37 @@ static int parse_ofoldpart_partitions(st
+
+ nr_parts = plen / sizeof(part[0]);
+
+- *pparts = kzalloc(nr_parts * sizeof(*(*pparts)), GFP_KERNEL);
+- if (!*pparts)
++ parts = kzalloc(nr_parts * sizeof(*parts), GFP_KERNEL);
++ if (!parts)
+ return -ENOMEM;
+
+ names = of_get_property(dp, "partition-names", &plen);
+
+ for (i = 0; i < nr_parts; i++) {
+- (*pparts)[i].offset = be32_to_cpu(part->offset);
+- (*pparts)[i].size = be32_to_cpu(part->len) & ~1;
++ parts[i].offset = be32_to_cpu(part->offset);
++ parts[i].size = be32_to_cpu(part->len) & ~1;
+ /* bit 0 set signifies read only partition */
+ if (be32_to_cpu(part->len) & 1)
+- (*pparts)[i].mask_flags = MTD_WRITEABLE;
++ parts[i].mask_flags = MTD_WRITEABLE;
+
+ if (names && (plen > 0)) {
+ int len = strlen(names) + 1;
+
+- (*pparts)[i].name = names;
++ parts[i].name = names;
+ plen -= len;
+ names += len;
+ } else {
+- (*pparts)[i].name = "unnamed";
++ parts[i].name = "unnamed";
+ }
+
+ part++;
+ }
+
++ *pparts = parts;
+ return nr_parts;
+ }
+
+ static struct mtd_part_parser ofoldpart_parser = {
+- .owner = THIS_MODULE,
+ .parse_fn = parse_ofoldpart_partitions,
+ .name = "ofoldpart",
+ };
+--- a/drivers/mtd/spi-nor/Kconfig
++++ b/drivers/mtd/spi-nor/Kconfig
+@@ -7,6 +7,14 @@ menuconfig MTD_SPI_NOR
+
+ if MTD_SPI_NOR
+
++config MTD_MT81xx_NOR
++ tristate "Mediatek MT81xx SPI NOR flash controller"
++ depends on HAS_IOMEM
++ help
++ This enables access to SPI NOR flash, using MT81xx SPI NOR flash
++ controller. This controller does not support generic SPI BUS, it only
++ supports SPI NOR Flash.
++
+ config MTD_SPI_NOR_USE_4K_SECTORS
+ bool "Use small 4096 B erase sectors"
+ default y
+@@ -23,7 +31,7 @@ config MTD_SPI_NOR_USE_4K_SECTORS
+
+ config SPI_FSL_QUADSPI
+ tristate "Freescale Quad SPI controller"
+- depends on ARCH_MXC || COMPILE_TEST
++ depends on ARCH_MXC || SOC_LS1021A || ARCH_LAYERSCAPE || COMPILE_TEST
+ depends on HAS_IOMEM
+ help
+ This enables support for the Quad SPI controller in master mode.
+--- a/drivers/mtd/spi-nor/Makefile
++++ b/drivers/mtd/spi-nor/Makefile
+@@ -1,3 +1,4 @@
+ obj-$(CONFIG_MTD_SPI_NOR) += spi-nor.o
+ obj-$(CONFIG_SPI_FSL_QUADSPI) += fsl-quadspi.o
++obj-$(CONFIG_MTD_MT81xx_NOR) += mtk-quadspi.o
+ obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o
+--- /dev/null
++++ b/drivers/mtd/spi-nor/mtk-quadspi.c
+@@ -0,0 +1,485 @@
++/*
++ * Copyright (c) 2015 MediaTek Inc.
++ * Author: Bayi Cheng <bayi.cheng@mediatek.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/init.h>
++#include <linux/io.h>
++#include <linux/iopoll.h>
++#include <linux/ioport.h>
++#include <linux/math64.h>
++#include <linux/module.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mutex.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/pinctrl/consumer.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/mtd/spi-nor.h>
++
++#define MTK_NOR_CMD_REG 0x00
++#define MTK_NOR_CNT_REG 0x04
++#define MTK_NOR_RDSR_REG 0x08
++#define MTK_NOR_RDATA_REG 0x0c
++#define MTK_NOR_RADR0_REG 0x10
++#define MTK_NOR_RADR1_REG 0x14
++#define MTK_NOR_RADR2_REG 0x18
++#define MTK_NOR_WDATA_REG 0x1c
++#define MTK_NOR_PRGDATA0_REG 0x20
++#define MTK_NOR_PRGDATA1_REG 0x24
++#define MTK_NOR_PRGDATA2_REG 0x28
++#define MTK_NOR_PRGDATA3_REG 0x2c
++#define MTK_NOR_PRGDATA4_REG 0x30
++#define MTK_NOR_PRGDATA5_REG 0x34
++#define MTK_NOR_SHREG0_REG 0x38
++#define MTK_NOR_SHREG1_REG 0x3c
++#define MTK_NOR_SHREG2_REG 0x40
++#define MTK_NOR_SHREG3_REG 0x44
++#define MTK_NOR_SHREG4_REG 0x48
++#define MTK_NOR_SHREG5_REG 0x4c
++#define MTK_NOR_SHREG6_REG 0x50
++#define MTK_NOR_SHREG7_REG 0x54
++#define MTK_NOR_SHREG8_REG 0x58
++#define MTK_NOR_SHREG9_REG 0x5c
++#define MTK_NOR_CFG1_REG 0x60
++#define MTK_NOR_CFG2_REG 0x64
++#define MTK_NOR_CFG3_REG 0x68
++#define MTK_NOR_STATUS0_REG 0x70
++#define MTK_NOR_STATUS1_REG 0x74
++#define MTK_NOR_STATUS2_REG 0x78
++#define MTK_NOR_STATUS3_REG 0x7c
++#define MTK_NOR_FLHCFG_REG 0x84
++#define MTK_NOR_TIME_REG 0x94
++#define MTK_NOR_PP_DATA_REG 0x98
++#define MTK_NOR_PREBUF_STUS_REG 0x9c
++#define MTK_NOR_DELSEL0_REG 0xa0
++#define MTK_NOR_DELSEL1_REG 0xa4
++#define MTK_NOR_INTRSTUS_REG 0xa8
++#define MTK_NOR_INTREN_REG 0xac
++#define MTK_NOR_CHKSUM_CTL_REG 0xb8
++#define MTK_NOR_CHKSUM_REG 0xbc
++#define MTK_NOR_CMD2_REG 0xc0
++#define MTK_NOR_WRPROT_REG 0xc4
++#define MTK_NOR_RADR3_REG 0xc8
++#define MTK_NOR_DUAL_REG 0xcc
++#define MTK_NOR_DELSEL2_REG 0xd0
++#define MTK_NOR_DELSEL3_REG 0xd4
++#define MTK_NOR_DELSEL4_REG 0xd8
++
++/* commands for mtk nor controller */
++#define MTK_NOR_READ_CMD 0x0
++#define MTK_NOR_RDSR_CMD 0x2
++#define MTK_NOR_PRG_CMD 0x4
++#define MTK_NOR_WR_CMD 0x10
++#define MTK_NOR_PIO_WR_CMD 0x90
++#define MTK_NOR_WRSR_CMD 0x20
++#define MTK_NOR_PIO_READ_CMD 0x81
++#define MTK_NOR_WR_BUF_ENABLE 0x1
++#define MTK_NOR_WR_BUF_DISABLE 0x0
++#define MTK_NOR_ENABLE_SF_CMD 0x30
++#define MTK_NOR_DUAD_ADDR_EN 0x8
++#define MTK_NOR_QUAD_READ_EN 0x4
++#define MTK_NOR_DUAL_ADDR_EN 0x2
++#define MTK_NOR_DUAL_READ_EN 0x1
++#define MTK_NOR_DUAL_DISABLE 0x0
++#define MTK_NOR_FAST_READ 0x1
++
++#define SFLASH_WRBUF_SIZE 128
++
++/* Can shift up to 48 bits (6 bytes) of TX/RX */
++#define MTK_NOR_MAX_RX_TX_SHIFT 6
++/* can shift up to 56 bits (7 bytes) transfer by MTK_NOR_PRG_CMD */
++#define MTK_NOR_MAX_SHIFT 7
++
++/* Helpers for accessing the program data / shift data registers */
++#define MTK_NOR_PRG_REG(n) (MTK_NOR_PRGDATA0_REG + 4 * (n))
++#define MTK_NOR_SHREG(n) (MTK_NOR_SHREG0_REG + 4 * (n))
++
++struct mt8173_nor {
++ struct spi_nor nor;
++ struct device *dev;
++ void __iomem *base; /* nor flash base address */
++ struct clk *spi_clk;
++ struct clk *nor_clk;
++};
++
++static void mt8173_nor_set_read_mode(struct mt8173_nor *mt8173_nor)
++{
++ struct spi_nor *nor = &mt8173_nor->nor;
++
++ switch (nor->flash_read) {
++ case SPI_NOR_FAST:
++ writeb(nor->read_opcode, mt8173_nor->base +
++ MTK_NOR_PRGDATA3_REG);
++ writeb(MTK_NOR_FAST_READ, mt8173_nor->base +
++ MTK_NOR_CFG1_REG);
++ break;
++ case SPI_NOR_DUAL:
++ writeb(nor->read_opcode, mt8173_nor->base +
++ MTK_NOR_PRGDATA3_REG);
++ writeb(MTK_NOR_DUAL_READ_EN, mt8173_nor->base +
++ MTK_NOR_DUAL_REG);
++ break;
++ case SPI_NOR_QUAD:
++ writeb(nor->read_opcode, mt8173_nor->base +
++ MTK_NOR_PRGDATA4_REG);
++ writeb(MTK_NOR_QUAD_READ_EN, mt8173_nor->base +
++ MTK_NOR_DUAL_REG);
++ break;
++ default:
++ writeb(MTK_NOR_DUAL_DISABLE, mt8173_nor->base +
++ MTK_NOR_DUAL_REG);
++ break;
++ }
++}
++
++static int mt8173_nor_execute_cmd(struct mt8173_nor *mt8173_nor, u8 cmdval)
++{
++ int reg;
++ u8 val = cmdval & 0x1f;
++
++ writeb(cmdval, mt8173_nor->base + MTK_NOR_CMD_REG);
++ return readl_poll_timeout(mt8173_nor->base + MTK_NOR_CMD_REG, reg,
++ !(reg & val), 100, 10000);
++}
++
++static int mt8173_nor_do_tx_rx(struct mt8173_nor *mt8173_nor, u8 op,
++ u8 *tx, int txlen, u8 *rx, int rxlen)
++{
++ int len = 1 + txlen + rxlen;
++ int i, ret, idx;
++
++ if (len > MTK_NOR_MAX_SHIFT)
++ return -EINVAL;
++
++ writeb(len * 8, mt8173_nor->base + MTK_NOR_CNT_REG);
++
++ /* start at PRGDATA5, go down to PRGDATA0 */
++ idx = MTK_NOR_MAX_RX_TX_SHIFT - 1;
++
++ /* opcode */
++ writeb(op, mt8173_nor->base + MTK_NOR_PRG_REG(idx));
++ idx--;
++
++ /* program TX data */
++ for (i = 0; i < txlen; i++, idx--)
++ writeb(tx[i], mt8173_nor->base + MTK_NOR_PRG_REG(idx));
++
++ /* clear out rest of TX registers */
++ while (idx >= 0) {
++ writeb(0, mt8173_nor->base + MTK_NOR_PRG_REG(idx));
++ idx--;
++ }
++
++ ret = mt8173_nor_execute_cmd(mt8173_nor, MTK_NOR_PRG_CMD);
++ if (ret)
++ return ret;
++
++ /* restart at first RX byte */
++ idx = rxlen - 1;
++
++ /* read out RX data */
++ for (i = 0; i < rxlen; i++, idx--)
++ rx[i] = readb(mt8173_nor->base + MTK_NOR_SHREG(idx));
++
++ return 0;
++}
++
++/* Do a WRSR (Write Status Register) command */
++static int mt8173_nor_wr_sr(struct mt8173_nor *mt8173_nor, u8 sr)
++{
++ writeb(sr, mt8173_nor->base + MTK_NOR_PRGDATA5_REG);
++ writeb(8, mt8173_nor->base + MTK_NOR_CNT_REG);
++ return mt8173_nor_execute_cmd(mt8173_nor, MTK_NOR_WRSR_CMD);
++}
++
++static int mt8173_nor_write_buffer_enable(struct mt8173_nor *mt8173_nor)
++{
++ u8 reg;
++
++ /* the bit0 of MTK_NOR_CFG2_REG is pre-fetch buffer
++ * 0: pre-fetch buffer use for read
++ * 1: pre-fetch buffer use for page program
++ */
++ writel(MTK_NOR_WR_BUF_ENABLE, mt8173_nor->base + MTK_NOR_CFG2_REG);
++ return readb_poll_timeout(mt8173_nor->base + MTK_NOR_CFG2_REG, reg,
++ 0x01 == (reg & 0x01), 100, 10000);
++}
++
++static int mt8173_nor_write_buffer_disable(struct mt8173_nor *mt8173_nor)
++{
++ u8 reg;
++
++ writel(MTK_NOR_WR_BUF_DISABLE, mt8173_nor->base + MTK_NOR_CFG2_REG);
++ return readb_poll_timeout(mt8173_nor->base + MTK_NOR_CFG2_REG, reg,
++ MTK_NOR_WR_BUF_DISABLE == (reg & 0x1), 100,
++ 10000);
++}
++
++static void mt8173_nor_set_addr(struct mt8173_nor *mt8173_nor, u32 addr)
++{
++ int i;
++
++ for (i = 0; i < 3; i++) {
++ writeb(addr & 0xff, mt8173_nor->base + MTK_NOR_RADR0_REG + i * 4);
++ addr >>= 8;
++ }
++ /* Last register is non-contiguous */
++ writeb(addr & 0xff, mt8173_nor->base + MTK_NOR_RADR3_REG);
++}
++
++static int mt8173_nor_read(struct spi_nor *nor, loff_t from, size_t length,
++ size_t *retlen, u_char *buffer)
++{
++ int i, ret;
++ int addr = (int)from;
++ u8 *buf = (u8 *)buffer;
++ struct mt8173_nor *mt8173_nor = nor->priv;
++
++ /* set mode for fast read mode ,dual mode or quad mode */
++ mt8173_nor_set_read_mode(mt8173_nor);
++ mt8173_nor_set_addr(mt8173_nor, addr);
++
++ for (i = 0; i < length; i++, (*retlen)++) {
++ ret = mt8173_nor_execute_cmd(mt8173_nor, MTK_NOR_PIO_READ_CMD);
++ if (ret < 0)
++ return ret;
++ buf[i] = readb(mt8173_nor->base + MTK_NOR_RDATA_REG);
++ }
++ return 0;
++}
++
++static int mt8173_nor_write_single_byte(struct mt8173_nor *mt8173_nor,
++ int addr, int length, u8 *data)
++{
++ int i, ret;
++
++ mt8173_nor_set_addr(mt8173_nor, addr);
++
++ for (i = 0; i < length; i++) {
++ writeb(*data++, mt8173_nor->base + MTK_NOR_WDATA_REG);
++ ret = mt8173_nor_execute_cmd(mt8173_nor, MTK_NOR_PIO_WR_CMD);
++ if (ret < 0)
++ return ret;
++ }
++ return 0;
++}
++
++static int mt8173_nor_write_buffer(struct mt8173_nor *mt8173_nor, int addr,
++ const u8 *buf)
++{
++ int i, bufidx, data;
++
++ mt8173_nor_set_addr(mt8173_nor, addr);
++
++ bufidx = 0;
++ for (i = 0; i < SFLASH_WRBUF_SIZE; i += 4) {
++ data = buf[bufidx + 3]<<24 | buf[bufidx + 2]<<16 |
++ buf[bufidx + 1]<<8 | buf[bufidx];
++ bufidx += 4;
++ writel(data, mt8173_nor->base + MTK_NOR_PP_DATA_REG);
++ }
++ return mt8173_nor_execute_cmd(mt8173_nor, MTK_NOR_WR_CMD);
++}
++
++static void mt8173_nor_write(struct spi_nor *nor, loff_t to, size_t len,
++ size_t *retlen, const u_char *buf)
++{
++ int ret;
++ struct mt8173_nor *mt8173_nor = nor->priv;
++
++ ret = mt8173_nor_write_buffer_enable(mt8173_nor);
++ if (ret < 0)
++ dev_warn(mt8173_nor->dev, "write buffer enable failed!\n");
++
++ while (len >= SFLASH_WRBUF_SIZE) {
++ ret = mt8173_nor_write_buffer(mt8173_nor, to, buf);
++ if (ret < 0)
++ dev_err(mt8173_nor->dev, "write buffer failed!\n");
++ len -= SFLASH_WRBUF_SIZE;
++ to += SFLASH_WRBUF_SIZE;
++ buf += SFLASH_WRBUF_SIZE;
++ (*retlen) += SFLASH_WRBUF_SIZE;
++ }
++ ret = mt8173_nor_write_buffer_disable(mt8173_nor);
++ if (ret < 0)
++ dev_warn(mt8173_nor->dev, "write buffer disable failed!\n");
++
++ if (len) {
++ ret = mt8173_nor_write_single_byte(mt8173_nor, to, (int)len,
++ (u8 *)buf);
++ if (ret < 0)
++ dev_err(mt8173_nor->dev, "write single byte failed!\n");
++ (*retlen) += len;
++ }
++}
++
++static int mt8173_nor_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
++{
++ int ret;
++ struct mt8173_nor *mt8173_nor = nor->priv;
++
++ switch (opcode) {
++ case SPINOR_OP_RDSR:
++ ret = mt8173_nor_execute_cmd(mt8173_nor, MTK_NOR_RDSR_CMD);
++ if (ret < 0)
++ return ret;
++ if (len == 1)
++ *buf = readb(mt8173_nor->base + MTK_NOR_RDSR_REG);
++ else
++ dev_err(mt8173_nor->dev, "len should be 1 for read status!\n");
++ break;
++ default:
++ ret = mt8173_nor_do_tx_rx(mt8173_nor, opcode, NULL, 0, buf, len);
++ break;
++ }
++ return ret;
++}
++
++static int mt8173_nor_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
++ int len)
++{
++ int ret;
++ struct mt8173_nor *mt8173_nor = nor->priv;
++
++ switch (opcode) {
++ case SPINOR_OP_WRSR:
++ /* We only handle 1 byte */
++ ret = mt8173_nor_wr_sr(mt8173_nor, *buf);
++ break;
++ default:
++ ret = mt8173_nor_do_tx_rx(mt8173_nor, opcode, buf, len, NULL, 0);
++ if (ret)
++ dev_warn(mt8173_nor->dev, "write reg failure!\n");
++ break;
++ }
++ return ret;
++}
++
++static int mtk_nor_init(struct mt8173_nor *mt8173_nor,
++ struct device_node *flash_node)
++{
++ int ret;
++ struct spi_nor *nor;
++
++ /* initialize controller to accept commands */
++ writel(MTK_NOR_ENABLE_SF_CMD, mt8173_nor->base + MTK_NOR_WRPROT_REG);
++
++ nor = &mt8173_nor->nor;
++ nor->dev = mt8173_nor->dev;
++ nor->priv = mt8173_nor;
++ spi_nor_set_flash_node(nor, flash_node);
++
++ /* fill the hooks to spi nor */
++ nor->read = mt8173_nor_read;
++ nor->read_reg = mt8173_nor_read_reg;
++ nor->write = mt8173_nor_write;
++ nor->write_reg = mt8173_nor_write_reg;
++ nor->mtd.name = "mtk_nor";
++ /* initialized with NULL */
++ ret = spi_nor_scan(nor, NULL, SPI_NOR_DUAL);
++ if (ret)
++ return ret;
++
++ return mtd_device_register(&nor->mtd, NULL, 0);
++}
++
++static int mtk_nor_drv_probe(struct platform_device *pdev)
++{
++ struct device_node *flash_np;
++ struct resource *res;
++ int ret;
++ struct mt8173_nor *mt8173_nor;
++
++ if (!pdev->dev.of_node) {
++ dev_err(&pdev->dev, "No DT found\n");
++ return -EINVAL;
++ }
++
++ mt8173_nor = devm_kzalloc(&pdev->dev, sizeof(*mt8173_nor), GFP_KERNEL);
++ if (!mt8173_nor)
++ return -ENOMEM;
++ platform_set_drvdata(pdev, mt8173_nor);
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ mt8173_nor->base = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(mt8173_nor->base))
++ return PTR_ERR(mt8173_nor->base);
++
++ mt8173_nor->spi_clk = devm_clk_get(&pdev->dev, "spi");
++ if (IS_ERR(mt8173_nor->spi_clk))
++ return PTR_ERR(mt8173_nor->spi_clk);
++
++ mt8173_nor->nor_clk = devm_clk_get(&pdev->dev, "sf");
++ if (IS_ERR(mt8173_nor->nor_clk))
++ return PTR_ERR(mt8173_nor->nor_clk);
++
++ mt8173_nor->dev = &pdev->dev;
++ ret = clk_prepare_enable(mt8173_nor->spi_clk);
++ if (ret)
++ return ret;
++
++ ret = clk_prepare_enable(mt8173_nor->nor_clk);
++ if (ret) {
++ clk_disable_unprepare(mt8173_nor->spi_clk);
++ return ret;
++ }
++ /* only support one attached flash */
++ flash_np = of_get_next_available_child(pdev->dev.of_node, NULL);
++ if (!flash_np) {
++ dev_err(&pdev->dev, "no SPI flash device to configure\n");
++ ret = -ENODEV;
++ goto nor_free;
++ }
++ ret = mtk_nor_init(mt8173_nor, flash_np);
++
++nor_free:
++ if (ret) {
++ clk_disable_unprepare(mt8173_nor->spi_clk);
++ clk_disable_unprepare(mt8173_nor->nor_clk);
++ }
++ return ret;
++}
++
++static int mtk_nor_drv_remove(struct platform_device *pdev)
++{
++ struct mt8173_nor *mt8173_nor = platform_get_drvdata(pdev);
++
++ clk_disable_unprepare(mt8173_nor->spi_clk);
++ clk_disable_unprepare(mt8173_nor->nor_clk);
++ return 0;
++}
++
++static const struct of_device_id mtk_nor_of_ids[] = {
++ { .compatible = "mediatek,mt8173-nor"},
++ { /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, mtk_nor_of_ids);
++
++static struct platform_driver mtk_nor_driver = {
++ .probe = mtk_nor_drv_probe,
++ .remove = mtk_nor_drv_remove,
++ .driver = {
++ .name = "mtk-nor",
++ .of_match_table = mtk_nor_of_ids,
++ },
++};
++
++module_platform_driver(mtk_nor_driver);
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("MediaTek SPI NOR Flash Driver");
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -38,6 +38,7 @@
+ #define CHIP_ERASE_2MB_READY_WAIT_JIFFIES (40UL * HZ)
+
+ #define SPI_NOR_MAX_ID_LEN 6
++#define SPI_NOR_MAX_ADDR_WIDTH 4
+
+ struct flash_info {
+ char *name;
+@@ -60,14 +61,20 @@ struct flash_info {
+ u16 addr_width;
+
+ u16 flags;
+-#define SECT_4K 0x01 /* SPINOR_OP_BE_4K works uniformly */
+-#define SPI_NOR_NO_ERASE 0x02 /* No erase command needed */
+-#define SST_WRITE 0x04 /* use SST byte programming */
+-#define SPI_NOR_NO_FR 0x08 /* Can't do fastread */
+-#define SECT_4K_PMC 0x10 /* SPINOR_OP_BE_4K_PMC works uniformly */
+-#define SPI_NOR_DUAL_READ 0x20 /* Flash supports Dual Read */
+-#define SPI_NOR_QUAD_READ 0x40 /* Flash supports Quad Read */
+-#define USE_FSR 0x80 /* use flag status register */
++#define SECT_4K BIT(0) /* SPINOR_OP_BE_4K works uniformly */
++#define SPI_NOR_NO_ERASE BIT(1) /* No erase command needed */
++#define SST_WRITE BIT(2) /* use SST byte programming */
++#define SPI_NOR_NO_FR BIT(3) /* Can't do fastread */
++#define SECT_4K_PMC BIT(4) /* SPINOR_OP_BE_4K_PMC works uniformly */
++#define SPI_NOR_DUAL_READ BIT(5) /* Flash supports Dual Read */
++#define SPI_NOR_QUAD_READ BIT(6) /* Flash supports Quad Read */
++#define USE_FSR BIT(7) /* use flag status register */
++#define SPI_NOR_HAS_LOCK BIT(8) /* Flash supports lock/unlock via SR */
++#define SPI_NOR_HAS_TB BIT(9) /*
++ * Flash SR has Top/Bottom (TB) protect
++ * bit. Must be used with
++ * SPI_NOR_HAS_LOCK.
++ */
+ };
+
+ #define JEDEC_MFR(info) ((info)->id[0])
+@@ -313,6 +320,29 @@ static void spi_nor_unlock_and_unprep(st
+ }
+
+ /*
++ * Initiate the erasure of a single sector
++ */
++static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
++{
++ u8 buf[SPI_NOR_MAX_ADDR_WIDTH];
++ int i;
++
++ if (nor->erase)
++ return nor->erase(nor, addr);
++
++ /*
++ * Default implementation, if driver doesn't have a specialized HW
++ * control
++ */
++ for (i = nor->addr_width - 1; i >= 0; i--) {
++ buf[i] = addr & 0xff;
++ addr >>= 8;
++ }
++
++ return nor->write_reg(nor, nor->erase_opcode, buf, nor->addr_width);
++}
++
++/*
+ * Erase an address range on the nor chip. The address range may extend
+ * one or more erase sectors. Return an error is there is a problem erasing.
+ */
+@@ -371,10 +401,9 @@ static int spi_nor_erase(struct mtd_info
+ while (len) {
+ write_enable(nor);
+
+- if (nor->erase(nor, addr)) {
+- ret = -EIO;
++ ret = spi_nor_erase_sector(nor, addr);
++ if (ret)
+ goto erase_err;
+- }
+
+ addr += mtd->erasesize;
+ len -= mtd->erasesize;
+@@ -387,17 +416,13 @@ static int spi_nor_erase(struct mtd_info
+
+ write_disable(nor);
+
++erase_err:
+ spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE);
+
+- instr->state = MTD_ERASE_DONE;
++ instr->state = ret ? MTD_ERASE_FAILED : MTD_ERASE_DONE;
+ mtd_erase_callback(instr);
+
+ return ret;
+-
+-erase_err:
+- spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE);
+- instr->state = MTD_ERASE_FAILED;
+- return ret;
+ }
+
+ static void stm_get_locked_range(struct spi_nor *nor, u8 sr, loff_t *ofs,
+@@ -415,32 +440,58 @@ static void stm_get_locked_range(struct
+ } else {
+ pow = ((sr & mask) ^ mask) >> shift;
+ *len = mtd->size >> pow;
+- *ofs = mtd->size - *len;
++ if (nor->flags & SNOR_F_HAS_SR_TB && sr & SR_TB)
++ *ofs = 0;
++ else
++ *ofs = mtd->size - *len;
+ }
+ }
+
+ /*
+- * Return 1 if the entire region is locked, 0 otherwise
++ * Return 1 if the entire region is locked (if @locked is true) or unlocked (if
++ * @locked is false); 0 otherwise
+ */
+-static int stm_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
+- u8 sr)
++static int stm_check_lock_status_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
++ u8 sr, bool locked)
+ {
+ loff_t lock_offs;
+ uint64_t lock_len;
+
++ if (!len)
++ return 1;
++
+ stm_get_locked_range(nor, sr, &lock_offs, &lock_len);
+
+- return (ofs + len <= lock_offs + lock_len) && (ofs >= lock_offs);
++ if (locked)
++ /* Requested range is a sub-range of locked range */
++ return (ofs + len <= lock_offs + lock_len) && (ofs >= lock_offs);
++ else
++ /* Requested range does not overlap with locked range */
++ return (ofs >= lock_offs + lock_len) || (ofs + len <= lock_offs);
++}
++
++static int stm_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
++ u8 sr)
++{
++ return stm_check_lock_status_sr(nor, ofs, len, sr, true);
++}
++
++static int stm_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
++ u8 sr)
++{
++ return stm_check_lock_status_sr(nor, ofs, len, sr, false);
+ }
+
+ /*
+ * Lock a region of the flash. Compatible with ST Micro and similar flash.
+- * Supports only the block protection bits BP{0,1,2} in the status register
++ * Supports the block protection bits BP{0,1,2} in the status register
+ * (SR). Does not support these features found in newer SR bitfields:
+- * - TB: top/bottom protect - only handle TB=0 (top protect)
+ * - SEC: sector/block protect - only handle SEC=0 (block protect)
+ * - CMP: complement protect - only support CMP=0 (range is not complemented)
+ *
++ * Support for the following is provided conditionally for some flash:
++ * - TB: top/bottom protect
++ *
+ * Sample table portion for 8MB flash (Winbond w25q64fw):
+ *
+ * SEC | TB | BP2 | BP1 | BP0 | Prot Length | Protected Portion
+@@ -453,26 +504,55 @@ static int stm_is_locked_sr(struct spi_n
+ * 0 | 0 | 1 | 0 | 1 | 2 MB | Upper 1/4
+ * 0 | 0 | 1 | 1 | 0 | 4 MB | Upper 1/2
+ * X | X | 1 | 1 | 1 | 8 MB | ALL
++ * ------|-------|-------|-------|-------|---------------|-------------------
++ * 0 | 1 | 0 | 0 | 1 | 128 KB | Lower 1/64
++ * 0 | 1 | 0 | 1 | 0 | 256 KB | Lower 1/32
++ * 0 | 1 | 0 | 1 | 1 | 512 KB | Lower 1/16
++ * 0 | 1 | 1 | 0 | 0 | 1 MB | Lower 1/8
++ * 0 | 1 | 1 | 0 | 1 | 2 MB | Lower 1/4
++ * 0 | 1 | 1 | 1 | 0 | 4 MB | Lower 1/2
+ *
+ * Returns negative on errors, 0 on success.
+ */
+ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
+ {
+ struct mtd_info *mtd = &nor->mtd;
+- u8 status_old, status_new;
++ int status_old, status_new;
+ u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
+ u8 shift = ffs(mask) - 1, pow, val;
++ loff_t lock_len;
++ bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;
++ bool use_top;
++ int ret;
+
+ status_old = read_sr(nor);
++ if (status_old < 0)
++ return status_old;
+
+- /* SPI NOR always locks to the end */
+- if (ofs + len != mtd->size) {
+- /* Does combined region extend to end? */
+- if (!stm_is_locked_sr(nor, ofs + len, mtd->size - ofs - len,
+- status_old))
+- return -EINVAL;
+- len = mtd->size - ofs;
+- }
++ /* If nothing in our range is unlocked, we don't need to do anything */
++ if (stm_is_locked_sr(nor, ofs, len, status_old))
++ return 0;
++
++ /* If anything below us is unlocked, we can't use 'bottom' protection */
++ if (!stm_is_locked_sr(nor, 0, ofs, status_old))
++ can_be_bottom = false;
++
++ /* If anything above us is unlocked, we can't use 'top' protection */
++ if (!stm_is_locked_sr(nor, ofs + len, mtd->size - (ofs + len),
++ status_old))
++ can_be_top = false;
++
++ if (!can_be_bottom && !can_be_top)
++ return -EINVAL;
++
++ /* Prefer top, if both are valid */
++ use_top = can_be_top;
++
++ /* lock_len: length of region that should end up locked */
++ if (use_top)
++ lock_len = mtd->size - ofs;
++ else
++ lock_len = ofs + len;
+
+ /*
+ * Need smallest pow such that:
+@@ -483,7 +563,7 @@ static int stm_lock(struct spi_nor *nor,
+ *
+ * pow = ceil(log2(size / len)) = log2(size) - floor(log2(len))
+ */
+- pow = ilog2(mtd->size) - ilog2(len);
++ pow = ilog2(mtd->size) - ilog2(lock_len);
+ val = mask - (pow << shift);
+ if (val & ~mask)
+ return -EINVAL;
+@@ -491,14 +571,27 @@ static int stm_lock(struct spi_nor *nor,
+ if (!(val & mask))
+ return -EINVAL;
+
+- status_new = (status_old & ~mask) | val;
++ status_new = (status_old & ~mask & ~SR_TB) | val;
++
++ /* Disallow further writes if WP pin is asserted */
++ status_new |= SR_SRWD;
++
++ if (!use_top)
++ status_new |= SR_TB;
++
++ /* Don't bother if they're the same */
++ if (status_new == status_old)
++ return 0;
+
+ /* Only modify protection if it will not unlock other areas */
+- if ((status_new & mask) <= (status_old & mask))
++ if ((status_new & mask) < (status_old & mask))
+ return -EINVAL;
+
+ write_enable(nor);
+- return write_sr(nor, status_new);
++ ret = write_sr(nor, status_new);
++ if (ret)
++ return ret;
++ return spi_nor_wait_till_ready(nor);
+ }
+
+ /*
+@@ -509,17 +602,43 @@ static int stm_lock(struct spi_nor *nor,
+ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
+ {
+ struct mtd_info *mtd = &nor->mtd;
+- uint8_t status_old, status_new;
++ int status_old, status_new;
+ u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
+ u8 shift = ffs(mask) - 1, pow, val;
++ loff_t lock_len;
++ bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;
++ bool use_top;
++ int ret;
+
+ status_old = read_sr(nor);
++ if (status_old < 0)
++ return status_old;
++
++ /* If nothing in our range is locked, we don't need to do anything */
++ if (stm_is_unlocked_sr(nor, ofs, len, status_old))
++ return 0;
++
++ /* If anything below us is locked, we can't use 'top' protection */
++ if (!stm_is_unlocked_sr(nor, 0, ofs, status_old))
++ can_be_top = false;
++
++ /* If anything above us is locked, we can't use 'bottom' protection */
++ if (!stm_is_unlocked_sr(nor, ofs + len, mtd->size - (ofs + len),
++ status_old))
++ can_be_bottom = false;
+
+- /* Cannot unlock; would unlock larger region than requested */
+- if (stm_is_locked_sr(nor, ofs - mtd->erasesize, mtd->erasesize,
+- status_old))
++ if (!can_be_bottom && !can_be_top)
+ return -EINVAL;
+
++ /* Prefer top, if both are valid */
++ use_top = can_be_top;
++
++ /* lock_len: length of region that should remain locked */
++ if (use_top)
++ lock_len = mtd->size - (ofs + len);
++ else
++ lock_len = ofs;
++
+ /*
+ * Need largest pow such that:
+ *
+@@ -529,8 +648,8 @@ static int stm_unlock(struct spi_nor *no
+ *
+ * pow = floor(log2(size / len)) = log2(size) - ceil(log2(len))
+ */
+- pow = ilog2(mtd->size) - order_base_2(mtd->size - (ofs + len));
+- if (ofs + len == mtd->size) {
++ pow = ilog2(mtd->size) - order_base_2(lock_len);
++ if (lock_len == 0) {
+ val = 0; /* fully unlocked */
+ } else {
+ val = mask - (pow << shift);
+@@ -539,14 +658,28 @@ static int stm_unlock(struct spi_nor *no
+ return -EINVAL;
+ }
+
+- status_new = (status_old & ~mask) | val;
++ status_new = (status_old & ~mask & ~SR_TB) | val;
++
++ /* Don't protect status register if we're fully unlocked */
++ if (lock_len == mtd->size)
++ status_new &= ~SR_SRWD;
++
++ if (!use_top)
++ status_new |= SR_TB;
++
++ /* Don't bother if they're the same */
++ if (status_new == status_old)
++ return 0;
+
+ /* Only modify protection if it will not lock other areas */
+- if ((status_new & mask) >= (status_old & mask))
++ if ((status_new & mask) > (status_old & mask))
+ return -EINVAL;
+
+ write_enable(nor);
+- return write_sr(nor, status_new);
++ ret = write_sr(nor, status_new);
++ if (ret)
++ return ret;
++ return spi_nor_wait_till_ready(nor);
+ }
+
+ /*
+@@ -715,9 +848,9 @@ static const struct flash_info spi_nor_i
+ { "mx25l4005a", INFO(0xc22013, 0, 64 * 1024, 8, SECT_4K) },
+ { "mx25l8005", INFO(0xc22014, 0, 64 * 1024, 16, 0) },
+ { "mx25l1606e", INFO(0xc22015, 0, 64 * 1024, 32, SECT_4K) },
+- { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, 0) },
++ { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, SECT_4K) },
+ { "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) },
+- { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, 0) },
++ { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K) },
+ { "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) },
+ { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
+ { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
+@@ -732,8 +865,8 @@ static const struct flash_info spi_nor_i
+ { "n25q032a", INFO(0x20bb16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) },
+ { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) },
+ { "n25q064a", INFO(0x20bb17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) },
+- { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, SPI_NOR_QUAD_READ) },
+- { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, SPI_NOR_QUAD_READ) },
++ { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) },
++ { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) },
+ { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ) },
+ { "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
+ { "n25q512ax3", INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
+@@ -767,6 +900,7 @@ static const struct flash_info spi_nor_i
+ { "s25fl008k", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ { "s25fl016k", INFO(0xef4015, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ { "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
++ { "s25fl116k", INFO(0x014015, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ { "s25fl132k", INFO(0x014016, 0, 64 * 1024, 64, SECT_4K) },
+ { "s25fl164k", INFO(0x014017, 0, 64 * 1024, 128, SECT_4K) },
+ { "s25fl204k", INFO(0x014013, 0, 64 * 1024, 8, SECT_4K | SPI_NOR_DUAL_READ) },
+@@ -830,11 +964,23 @@ static const struct flash_info spi_nor_i
+ { "w25x16", INFO(0xef3015, 0, 64 * 1024, 32, SECT_4K) },
+ { "w25x32", INFO(0xef3016, 0, 64 * 1024, 64, SECT_4K) },
+ { "w25q32", INFO(0xef4016, 0, 64 * 1024, 64, SECT_4K) },
+- { "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
++ {
++ "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64,
++ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
++ SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
++ },
+ { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
+ { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
+- { "w25q64dw", INFO(0xef6017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+- { "w25q128fw", INFO(0xef6018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
++ {
++ "w25q64dw", INFO(0xef6017, 0, 64 * 1024, 128,
++ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
++ SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
++ },
++ {
++ "w25q128fw", INFO(0xef6018, 0, 64 * 1024, 256,
++ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
++ SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
++ },
+ { "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) },
+ { "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) },
+ { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
+@@ -857,7 +1003,7 @@ static const struct flash_info *spi_nor_
+
+ tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN);
+ if (tmp < 0) {
+- dev_dbg(nor->dev, " error %d reading JEDEC ID\n", tmp);
++ dev_dbg(nor->dev, "error %d reading JEDEC ID\n", tmp);
+ return ERR_PTR(tmp);
+ }
+
+@@ -868,7 +1014,7 @@ static const struct flash_info *spi_nor_
+ return &spi_nor_ids[tmp];
+ }
+ }
+- dev_err(nor->dev, "unrecognized JEDEC id bytes: %02x, %2x, %2x\n",
++ dev_err(nor->dev, "unrecognized JEDEC id bytes: %02x, %02x, %02x\n",
+ id[0], id[1], id[2]);
+ return ERR_PTR(-ENODEV);
+ }
+@@ -1014,6 +1160,8 @@ static int macronix_quad_enable(struct s
+ int ret, val;
+
+ val = read_sr(nor);
++ if (val < 0)
++ return val;
+ write_enable(nor);
+
+ write_sr(nor, val | SR_QUAD_EN_MX);
+@@ -1095,7 +1243,7 @@ static int set_quad_mode(struct spi_nor
+ static int spi_nor_check(struct spi_nor *nor)
+ {
+ if (!nor->dev || !nor->read || !nor->write ||
+- !nor->read_reg || !nor->write_reg || !nor->erase) {
++ !nor->read_reg || !nor->write_reg) {
+ pr_err("spi-nor: please fill all the necessary fields!\n");
+ return -EINVAL;
+ }
+@@ -1108,7 +1256,7 @@ int spi_nor_scan(struct spi_nor *nor, co
+ const struct flash_info *info = NULL;
+ struct device *dev = nor->dev;
+ struct mtd_info *mtd = &nor->mtd;
+- struct device_node *np = nor->flash_node;
++ struct device_node *np = spi_nor_get_flash_node(nor);
+ int ret;
+ int i;
+
+@@ -1158,9 +1306,11 @@ int spi_nor_scan(struct spi_nor *nor, co
+ if (JEDEC_MFR(info) == SNOR_MFR_ATMEL ||
+ JEDEC_MFR(info) == SNOR_MFR_INTEL ||
+ JEDEC_MFR(info) == SNOR_MFR_MACRONIX ||
+- JEDEC_MFR(info) == SNOR_MFR_SST) {
++ JEDEC_MFR(info) == SNOR_MFR_SST ||
++ info->flags & SPI_NOR_HAS_LOCK) {
+ write_enable(nor);
+ write_sr(nor, 0);
++ spi_nor_wait_till_ready(nor);
+ }
+
+ if (!mtd->name)
+@@ -1174,7 +1324,8 @@ int spi_nor_scan(struct spi_nor *nor, co
+ mtd->_read = spi_nor_read;
+
+ /* NOR protection support for STmicro/Micron chips and similar */
+- if (JEDEC_MFR(info) == SNOR_MFR_MICRON) {
++ if (JEDEC_MFR(info) == SNOR_MFR_MICRON ||
++ info->flags & SPI_NOR_HAS_LOCK) {
+ nor->flash_lock = stm_lock;
+ nor->flash_unlock = stm_unlock;
+ nor->flash_is_locked = stm_is_locked;
+@@ -1194,6 +1345,8 @@ int spi_nor_scan(struct spi_nor *nor, co
+
+ if (info->flags & USE_FSR)
+ nor->flags |= SNOR_F_USE_FSR;
++ if (info->flags & SPI_NOR_HAS_TB)
++ nor->flags |= SNOR_F_HAS_SR_TB;
+
+ #ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
+ /* prefer "small sector" erase if possible */
+@@ -1296,6 +1449,12 @@ int spi_nor_scan(struct spi_nor *nor, co
+ nor->addr_width = 3;
+ }
+
++ if (nor->addr_width > SPI_NOR_MAX_ADDR_WIDTH) {
++ dev_err(dev, "address width is too large: %u\n",
++ nor->addr_width);
++ return -EINVAL;
++ }
++
+ nor->read_dummy = spi_nor_read_dummy_cycles(nor);
+
+ dev_info(dev, "%s (%lld Kbytes)\n", info->name,
+--- a/drivers/mtd/tests/mtd_nandecctest.c
++++ b/drivers/mtd/tests/mtd_nandecctest.c
+@@ -187,7 +187,7 @@ static int double_bit_error_detect(void
+ __nand_calculate_ecc(error_data, size, calc_ecc);
+ ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size);
+
+- return (ret == -1) ? 0 : -EINVAL;
++ return (ret == -EBADMSG) ? 0 : -EINVAL;
+ }
+
+ static const struct nand_ecc_test nand_ecc_test[] = {
+--- a/drivers/mtd/tests/oobtest.c
++++ b/drivers/mtd/tests/oobtest.c
+@@ -215,19 +215,19 @@ static int verify_eraseblock(int ebnum)
+ pr_info("ignoring error as within bitflip_limit\n");
+ }
+
+- if (use_offset != 0 || use_len < mtd->ecclayout->oobavail) {
++ if (use_offset != 0 || use_len < mtd->oobavail) {
+ int k;
+
+ ops.mode = MTD_OPS_AUTO_OOB;
+ ops.len = 0;
+ ops.retlen = 0;
+- ops.ooblen = mtd->ecclayout->oobavail;
++ ops.ooblen = mtd->oobavail;
+ ops.oobretlen = 0;
+ ops.ooboffs = 0;
+ ops.datbuf = NULL;
+ ops.oobbuf = readbuf;
+ err = mtd_read_oob(mtd, addr, &ops);
+- if (err || ops.oobretlen != mtd->ecclayout->oobavail) {
++ if (err || ops.oobretlen != mtd->oobavail) {
+ pr_err("error: readoob failed at %#llx\n",
+ (long long)addr);
+ errcnt += 1;
+@@ -244,7 +244,7 @@ static int verify_eraseblock(int ebnum)
+ /* verify post-(use_offset + use_len) area for 0xff */
+ k = use_offset + use_len;
+ bitflips += memffshow(addr, k, readbuf + k,
+- mtd->ecclayout->oobavail - k);
++ mtd->oobavail - k);
+
+ if (bitflips > bitflip_limit) {
+ pr_err("error: verify failed at %#llx\n",
+@@ -269,8 +269,8 @@ static int verify_eraseblock_in_one_go(i
+ struct mtd_oob_ops ops;
+ int err = 0;
+ loff_t addr = (loff_t)ebnum * mtd->erasesize;
+- size_t len = mtd->ecclayout->oobavail * pgcnt;
+- size_t oobavail = mtd->ecclayout->oobavail;
++ size_t len = mtd->oobavail * pgcnt;
++ size_t oobavail = mtd->oobavail;
+ size_t bitflips;
+ int i;
+
+@@ -394,8 +394,8 @@ static int __init mtd_oobtest_init(void)
+ goto out;
+
+ use_offset = 0;
+- use_len = mtd->ecclayout->oobavail;
+- use_len_max = mtd->ecclayout->oobavail;
++ use_len = mtd->oobavail;
++ use_len_max = mtd->oobavail;
+ vary_offset = 0;
+
+ /* First test: write all OOB, read it back and verify */
+@@ -460,8 +460,8 @@ static int __init mtd_oobtest_init(void)
+
+ /* Write all eraseblocks */
+ use_offset = 0;
+- use_len = mtd->ecclayout->oobavail;
+- use_len_max = mtd->ecclayout->oobavail;
++ use_len = mtd->oobavail;
++ use_len_max = mtd->oobavail;
+ vary_offset = 1;
+ prandom_seed_state(&rnd_state, 5);
+
+@@ -471,8 +471,8 @@ static int __init mtd_oobtest_init(void)
+
+ /* Check all eraseblocks */
+ use_offset = 0;
+- use_len = mtd->ecclayout->oobavail;
+- use_len_max = mtd->ecclayout->oobavail;
++ use_len = mtd->oobavail;
++ use_len_max = mtd->oobavail;
+ vary_offset = 1;
+ prandom_seed_state(&rnd_state, 5);
+ err = verify_all_eraseblocks();
+@@ -480,8 +480,8 @@ static int __init mtd_oobtest_init(void)
+ goto out;
+
+ use_offset = 0;
+- use_len = mtd->ecclayout->oobavail;
+- use_len_max = mtd->ecclayout->oobavail;
++ use_len = mtd->oobavail;
++ use_len_max = mtd->oobavail;
+ vary_offset = 0;
+
+ /* Fourth test: try to write off end of device */
+@@ -501,7 +501,7 @@ static int __init mtd_oobtest_init(void)
+ ops.retlen = 0;
+ ops.ooblen = 1;
+ ops.oobretlen = 0;
+- ops.ooboffs = mtd->ecclayout->oobavail;
++ ops.ooboffs = mtd->oobavail;
+ ops.datbuf = NULL;
+ ops.oobbuf = writebuf;
+ pr_info("attempting to start write past end of OOB\n");
+@@ -521,7 +521,7 @@ static int __init mtd_oobtest_init(void)
+ ops.retlen = 0;
+ ops.ooblen = 1;
+ ops.oobretlen = 0;
+- ops.ooboffs = mtd->ecclayout->oobavail;
++ ops.ooboffs = mtd->oobavail;
+ ops.datbuf = NULL;
+ ops.oobbuf = readbuf;
+ pr_info("attempting to start read past end of OOB\n");
+@@ -543,7 +543,7 @@ static int __init mtd_oobtest_init(void)
+ ops.mode = MTD_OPS_AUTO_OOB;
+ ops.len = 0;
+ ops.retlen = 0;
+- ops.ooblen = mtd->ecclayout->oobavail + 1;
++ ops.ooblen = mtd->oobavail + 1;
+ ops.oobretlen = 0;
+ ops.ooboffs = 0;
+ ops.datbuf = NULL;
+@@ -563,7 +563,7 @@ static int __init mtd_oobtest_init(void)
+ ops.mode = MTD_OPS_AUTO_OOB;
+ ops.len = 0;
+ ops.retlen = 0;
+- ops.ooblen = mtd->ecclayout->oobavail + 1;
++ ops.ooblen = mtd->oobavail + 1;
+ ops.oobretlen = 0;
+ ops.ooboffs = 0;
+ ops.datbuf = NULL;
+@@ -587,7 +587,7 @@ static int __init mtd_oobtest_init(void)
+ ops.mode = MTD_OPS_AUTO_OOB;
+ ops.len = 0;
+ ops.retlen = 0;
+- ops.ooblen = mtd->ecclayout->oobavail;
++ ops.ooblen = mtd->oobavail;
+ ops.oobretlen = 0;
+ ops.ooboffs = 1;
+ ops.datbuf = NULL;
+@@ -607,7 +607,7 @@ static int __init mtd_oobtest_init(void)
+ ops.mode = MTD_OPS_AUTO_OOB;
+ ops.len = 0;
+ ops.retlen = 0;
+- ops.ooblen = mtd->ecclayout->oobavail;
++ ops.ooblen = mtd->oobavail;
+ ops.oobretlen = 0;
+ ops.ooboffs = 1;
+ ops.datbuf = NULL;
+@@ -638,7 +638,7 @@ static int __init mtd_oobtest_init(void)
+ for (i = 0; i < ebcnt - 1; ++i) {
+ int cnt = 2;
+ int pg;
+- size_t sz = mtd->ecclayout->oobavail;
++ size_t sz = mtd->oobavail;
+ if (bbt[i] || bbt[i + 1])
+ continue;
+ addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize;
+@@ -673,13 +673,12 @@ static int __init mtd_oobtest_init(void)
+ for (i = 0; i < ebcnt - 1; ++i) {
+ if (bbt[i] || bbt[i + 1])
+ continue;
+- prandom_bytes_state(&rnd_state, writebuf,
+- mtd->ecclayout->oobavail * 2);
++ prandom_bytes_state(&rnd_state, writebuf, mtd->oobavail * 2);
+ addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize;
+ ops.mode = MTD_OPS_AUTO_OOB;
+ ops.len = 0;
+ ops.retlen = 0;
+- ops.ooblen = mtd->ecclayout->oobavail * 2;
++ ops.ooblen = mtd->oobavail * 2;
+ ops.oobretlen = 0;
+ ops.ooboffs = 0;
+ ops.datbuf = NULL;
+@@ -688,7 +687,7 @@ static int __init mtd_oobtest_init(void)
+ if (err)
+ goto out;
+ if (memcmpshow(addr, readbuf, writebuf,
+- mtd->ecclayout->oobavail * 2)) {
++ mtd->oobavail * 2)) {
+ pr_err("error: verify failed at %#llx\n",
+ (long long)addr);
+ errcnt += 1;
+--- a/drivers/mtd/tests/pagetest.c
++++ b/drivers/mtd/tests/pagetest.c
+@@ -127,13 +127,12 @@ static int crosstest(void)
+ unsigned char *pp1, *pp2, *pp3, *pp4;
+
+ pr_info("crosstest\n");
+- pp1 = kmalloc(pgsize * 4, GFP_KERNEL);
++ pp1 = kzalloc(pgsize * 4, GFP_KERNEL);
+ if (!pp1)
+ return -ENOMEM;
+ pp2 = pp1 + pgsize;
+ pp3 = pp2 + pgsize;
+ pp4 = pp3 + pgsize;
+- memset(pp1, 0, pgsize * 4);
+
+ addr0 = 0;
+ for (i = 0; i < ebcnt && bbt[i]; ++i)
+--- a/drivers/mtd/ubi/cdev.c
++++ b/drivers/mtd/ubi/cdev.c
+@@ -174,9 +174,9 @@ static int vol_cdev_fsync(struct file *f
+ struct ubi_device *ubi = desc->vol->ubi;
+ struct inode *inode = file_inode(file);
+ int err;
+- mutex_lock(&inode->i_mutex);
++ inode_lock(inode);
+ err = ubi_sync(ubi->ubi_num);
+- mutex_unlock(&inode->i_mutex);
++ inode_unlock(inode);
+ return err;
+ }
+
+--- a/drivers/mtd/ubi/misc.c
++++ b/drivers/mtd/ubi/misc.c
+@@ -153,3 +153,52 @@ int ubi_check_pattern(const void *buf, u
+ return 0;
+ return 1;
+ }
++
++/* Normal UBI messages */
++void ubi_msg(const struct ubi_device *ubi, const char *fmt, ...)
++{
++ struct va_format vaf;
++ va_list args;
++
++ va_start(args, fmt);
++
++ vaf.fmt = fmt;
++ vaf.va = &args;
++
++ pr_notice(UBI_NAME_STR "%d: %pV\n", ubi->ubi_num, &vaf);
++
++ va_end(args);
++}
++
++/* UBI warning messages */
++void ubi_warn(const struct ubi_device *ubi, const char *fmt, ...)
++{
++ struct va_format vaf;
++ va_list args;
++
++ va_start(args, fmt);
++
++ vaf.fmt = fmt;
++ vaf.va = &args;
++
++ pr_warn(UBI_NAME_STR "%d warning: %ps: %pV\n",
++ ubi->ubi_num, __builtin_return_address(0), &vaf);
++
++ va_end(args);
++}
++
++/* UBI error messages */
++void ubi_err(const struct ubi_device *ubi, const char *fmt, ...)
++{
++ struct va_format vaf;
++ va_list args;
++
++ va_start(args, fmt);
++
++ vaf.fmt = fmt;
++ vaf.va = &args;
++
++ pr_err(UBI_NAME_STR "%d error: %ps: %pV\n",
++ ubi->ubi_num, __builtin_return_address(0), &vaf);
++ va_end(args);
++}
+--- a/drivers/mtd/ubi/ubi.h
++++ b/drivers/mtd/ubi/ubi.h
+@@ -49,15 +49,19 @@
+ /* UBI name used for character devices, sysfs, etc */
+ #define UBI_NAME_STR "ubi"
+
++struct ubi_device;
++
+ /* Normal UBI messages */
+-#define ubi_msg(ubi, fmt, ...) pr_notice(UBI_NAME_STR "%d: " fmt "\n", \
+- ubi->ubi_num, ##__VA_ARGS__)
++__printf(2, 3)
++void ubi_msg(const struct ubi_device *ubi, const char *fmt, ...);
++
+ /* UBI warning messages */
+-#define ubi_warn(ubi, fmt, ...) pr_warn(UBI_NAME_STR "%d warning: %s: " fmt "\n", \
+- ubi->ubi_num, __func__, ##__VA_ARGS__)
++__printf(2, 3)
++void ubi_warn(const struct ubi_device *ubi, const char *fmt, ...);
++
+ /* UBI error messages */
+-#define ubi_err(ubi, fmt, ...) pr_err(UBI_NAME_STR "%d error: %s: " fmt "\n", \
+- ubi->ubi_num, __func__, ##__VA_ARGS__)
++__printf(2, 3)
++void ubi_err(const struct ubi_device *ubi, const char *fmt, ...);
+
+ /* Background thread name pattern */
+ #define UBI_BGT_NAME_PATTERN "ubi_bgt%dd"
+--- a/drivers/mtd/ubi/wl.c
++++ b/drivers/mtd/ubi/wl.c
+@@ -628,6 +628,7 @@ static int do_sync_erase(struct ubi_devi
+ return __erase_worker(ubi, &wl_wrk);
+ }
+
++static int ensure_wear_leveling(struct ubi_device *ubi, int nested);
+ /**
+ * wear_leveling_worker - wear-leveling worker function.
+ * @ubi: UBI device description object
+@@ -649,6 +650,7 @@ static int wear_leveling_worker(struct u
+ #endif
+ struct ubi_wl_entry *e1, *e2;
+ struct ubi_vid_hdr *vid_hdr;
++ int dst_leb_clean = 0;
+
+ kfree(wrk);
+ if (shutdown)
+@@ -753,6 +755,7 @@ static int wear_leveling_worker(struct u
+
+ err = ubi_io_read_vid_hdr(ubi, e1->pnum, vid_hdr, 0);
+ if (err && err != UBI_IO_BITFLIPS) {
++ dst_leb_clean = 1;
+ if (err == UBI_IO_FF) {
+ /*
+ * We are trying to move PEB without a VID header. UBI
+@@ -798,10 +801,12 @@ static int wear_leveling_worker(struct u
+ * protection queue.
+ */
+ protect = 1;
++ dst_leb_clean = 1;
+ goto out_not_moved;
+ }
+ if (err == MOVE_RETRY) {
+ scrubbing = 1;
++ dst_leb_clean = 1;
+ goto out_not_moved;
+ }
+ if (err == MOVE_TARGET_BITFLIPS || err == MOVE_TARGET_WR_ERR ||
+@@ -827,6 +832,7 @@ static int wear_leveling_worker(struct u
+ ubi->erroneous_peb_count);
+ goto out_error;
+ }
++ dst_leb_clean = 1;
+ erroneous = 1;
+ goto out_not_moved;
+ }
+@@ -897,15 +903,24 @@ out_not_moved:
+ wl_tree_add(e1, &ubi->scrub);
+ else
+ wl_tree_add(e1, &ubi->used);
++ if (dst_leb_clean) {
++ wl_tree_add(e2, &ubi->free);
++ ubi->free_count++;
++ }
++
+ ubi_assert(!ubi->move_to_put);
+ ubi->move_from = ubi->move_to = NULL;
+ ubi->wl_scheduled = 0;
+ spin_unlock(&ubi->wl_lock);
+
+ ubi_free_vid_hdr(ubi, vid_hdr);
+- err = do_sync_erase(ubi, e2, vol_id, lnum, torture);
+- if (err)
+- goto out_ro;
++ if (dst_leb_clean) {
++ ensure_wear_leveling(ubi, 1);
++ } else {
++ err = do_sync_erase(ubi, e2, vol_id, lnum, torture);
++ if (err)
++ goto out_ro;
++ }
+
+ mutex_unlock(&ubi->move_mutex);
+ return 0;
+--- a/include/linux/mtd/bbm.h
++++ b/include/linux/mtd/bbm.h
+@@ -166,7 +166,6 @@ struct bbm_info {
+ };
+
+ /* OneNAND BBT interface */
+-extern int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd);
+ extern int onenand_default_bbt(struct mtd_info *mtd);
+
+ #endif /* __LINUX_MTD_BBM_H */
+--- a/include/linux/mtd/fsmc.h
++++ b/include/linux/mtd/fsmc.h
+@@ -103,24 +103,6 @@
+
+ #define FSMC_BUSY_WAIT_TIMEOUT (1 * HZ)
+
+-/*
+- * There are 13 bytes of ecc for every 512 byte block in FSMC version 8
+- * and it has to be read consecutively and immediately after the 512
+- * byte data block for hardware to generate the error bit offsets
+- * Managing the ecc bytes in the following way is easier. This way is
+- * similar to oobfree structure maintained already in u-boot nand driver
+- */
+-#define MAX_ECCPLACE_ENTRIES 32
+-
+-struct fsmc_nand_eccplace {
+- uint8_t offset;
+- uint8_t length;
+-};
+-
+-struct fsmc_eccplace {
+- struct fsmc_nand_eccplace eccplace[MAX_ECCPLACE_ENTRIES];
+-};
+-
+ struct fsmc_nand_timings {
+ uint8_t tclr;
+ uint8_t tar;
+--- a/include/linux/mtd/inftl.h
++++ b/include/linux/mtd/inftl.h
+@@ -44,7 +44,6 @@ struct INFTLrecord {
+ unsigned int nb_blocks; /* number of physical blocks */
+ unsigned int nb_boot_blocks; /* number of blocks used by the bios */
+ struct erase_info instr;
+- struct nand_ecclayout oobinfo;
+ };
+
+ int INFTL_mount(struct INFTLrecord *s);
+--- a/include/linux/mtd/map.h
++++ b/include/linux/mtd/map.h
+@@ -142,7 +142,9 @@
+ #endif
+
+ #ifndef map_bankwidth
++#ifdef CONFIG_MTD
+ #warning "No CONFIG_MTD_MAP_BANK_WIDTH_xx selected. No NOR chip support can work"
++#endif
+ static inline int map_bankwidth(void *map)
+ {
+ BUG();
+@@ -238,8 +240,11 @@ struct map_info {
+ If there is no cache to care about this can be set to NULL. */
+ void (*inval_cache)(struct map_info *, unsigned long, ssize_t);
+
+- /* set_vpp() must handle being reentered -- enable, enable, disable
+- must leave it enabled. */
++ /* This will be called with 1 as parameter when the first map user
++ * needs VPP, and called with 0 when the last user exits. The map
++ * core maintains a reference counter, and assumes that VPP is a
++ * global resource applying to all mapped flash chips on the system.
++ */
+ void (*set_vpp)(struct map_info *, int);
+
+ unsigned long pfow_base;
+--- a/include/linux/mtd/mtd.h
++++ b/include/linux/mtd/mtd.h
+@@ -100,17 +100,35 @@ struct mtd_oob_ops {
+
+ #define MTD_MAX_OOBFREE_ENTRIES_LARGE 32
+ #define MTD_MAX_ECCPOS_ENTRIES_LARGE 640
++/**
++ * struct mtd_oob_region - oob region definition
++ * @offset: region offset
++ * @length: region length
++ *
++ * This structure describes a region of the OOB area, and is used
++ * to retrieve ECC or free bytes sections.
++ * Each section is defined by an offset within the OOB area and a
++ * length.
++ */
++struct mtd_oob_region {
++ u32 offset;
++ u32 length;
++};
++
+ /*
+- * Internal ECC layout control structure. For historical reasons, there is a
+- * similar, smaller struct nand_ecclayout_user (in mtd-abi.h) that is retained
+- * for export to user-space via the ECCGETLAYOUT ioctl.
+- * nand_ecclayout should be expandable in the future simply by the above macros.
++ * struct mtd_ooblayout_ops - NAND OOB layout operations
++ * @ecc: function returning an ECC region in the OOB area.
++ * Should return -ERANGE if %section exceeds the total number of
++ * ECC sections.
++ * @free: function returning a free region in the OOB area.
++ * Should return -ERANGE if %section exceeds the total number of
++ * free sections.
+ */
+-struct nand_ecclayout {
+- __u32 eccbytes;
+- __u32 eccpos[MTD_MAX_ECCPOS_ENTRIES_LARGE];
+- __u32 oobavail;
+- struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES_LARGE];
++struct mtd_ooblayout_ops {
++ int (*ecc)(struct mtd_info *mtd, int section,
++ struct mtd_oob_region *oobecc);
++ int (*free)(struct mtd_info *mtd, int section,
++ struct mtd_oob_region *oobfree);
+ };
+
+ struct module; /* only needed for owner field in mtd_info */
+@@ -171,8 +189,8 @@ struct mtd_info {
+ const char *name;
+ int index;
+
+- /* ECC layout structure pointer - read only! */
+- struct nand_ecclayout *ecclayout;
++ /* OOB layout description */
++ const struct mtd_ooblayout_ops *ooblayout;
+
+ /* the ecc step size. */
+ unsigned int ecc_step_size;
+@@ -258,6 +276,46 @@ struct mtd_info {
+ int usecount;
+ };
+
++int mtd_ooblayout_ecc(struct mtd_info *mtd, int section,
++ struct mtd_oob_region *oobecc);
++int mtd_ooblayout_find_eccregion(struct mtd_info *mtd, int eccbyte,
++ int *section,
++ struct mtd_oob_region *oobregion);
++int mtd_ooblayout_get_eccbytes(struct mtd_info *mtd, u8 *eccbuf,
++ const u8 *oobbuf, int start, int nbytes);
++int mtd_ooblayout_set_eccbytes(struct mtd_info *mtd, const u8 *eccbuf,
++ u8 *oobbuf, int start, int nbytes);
++int mtd_ooblayout_free(struct mtd_info *mtd, int section,
++ struct mtd_oob_region *oobfree);
++int mtd_ooblayout_get_databytes(struct mtd_info *mtd, u8 *databuf,
++ const u8 *oobbuf, int start, int nbytes);
++int mtd_ooblayout_set_databytes(struct mtd_info *mtd, const u8 *databuf,
++ u8 *oobbuf, int start, int nbytes);
++int mtd_ooblayout_count_freebytes(struct mtd_info *mtd);
++int mtd_ooblayout_count_eccbytes(struct mtd_info *mtd);
++
++static inline void mtd_set_ooblayout(struct mtd_info *mtd,
++ const struct mtd_ooblayout_ops *ooblayout)
++{
++ mtd->ooblayout = ooblayout;
++}
++
++static inline void mtd_set_of_node(struct mtd_info *mtd,
++ struct device_node *np)
++{
++ mtd->dev.of_node = np;
++}
++
++static inline struct device_node *mtd_get_of_node(struct mtd_info *mtd)
++{
++ return mtd->dev.of_node;
++}
++
++static inline int mtd_oobavail(struct mtd_info *mtd, struct mtd_oob_ops *ops)
++{
++ return ops->mode == MTD_OPS_AUTO_OOB ? mtd->oobavail : mtd->oobsize;
++}
++
+ int mtd_erase(struct mtd_info *mtd, struct erase_info *instr);
+ int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
+ void **virt, resource_size_t *phys);
+--- a/include/linux/mtd/nand.h
++++ b/include/linux/mtd/nand.h
+@@ -119,6 +119,12 @@ typedef enum {
+ NAND_ECC_SOFT_BCH,
+ } nand_ecc_modes_t;
+
++enum nand_ecc_algo {
++ NAND_ECC_UNKNOWN,
++ NAND_ECC_HAMMING,
++ NAND_ECC_BCH,
++};
++
+ /*
+ * Constants for Hardware ECC
+ */
+@@ -129,6 +135,14 @@ typedef enum {
+ /* Enable Hardware ECC before syndrome is read back from flash */
+ #define NAND_ECC_READSYN 2
+
++/*
++ * Enable generic NAND 'page erased' check. This check is only done when
++ * ecc.correct() returns -EBADMSG.
++ * Set this flag if your implementation does not fix bitflips in erased
++ * pages and you want to rely on the default implementation.
++ */
++#define NAND_ECC_GENERIC_ERASED_CHECK BIT(0)
++
+ /* Bit mask for flags passed to do_nand_read_ecc */
+ #define NAND_GET_DEVICE 0x80
+
+@@ -160,6 +174,12 @@ typedef enum {
+ /* Device supports subpage reads */
+ #define NAND_SUBPAGE_READ 0x00001000
+
++/*
++ * Some MLC NANDs need data scrambling to limit bitflips caused by repeated
++ * patterns.
++ */
++#define NAND_NEED_SCRAMBLING 0x00002000
++
+ /* Options valid for Samsung large page devices */
+ #define NAND_SAMSUNG_LP_OPTIONS NAND_CACHEPRG
+
+@@ -276,15 +296,15 @@ struct nand_onfi_params {
+ __le16 t_r;
+ __le16 t_ccs;
+ __le16 src_sync_timing_mode;
+- __le16 src_ssync_features;
++ u8 src_ssync_features;
+ __le16 clk_pin_capacitance_typ;
+ __le16 io_pin_capacitance_typ;
+ __le16 input_pin_capacitance_typ;
+ u8 input_pin_capacitance_max;
+ u8 driver_strength_support;
+ __le16 t_int_r;
+- __le16 t_ald;
+- u8 reserved4[7];
++ __le16 t_adl;
++ u8 reserved4[8];
+
+ /* vendor */
+ __le16 vendor_revision;
+@@ -407,7 +427,7 @@ struct nand_jedec_params {
+ __le16 input_pin_capacitance_typ;
+ __le16 clk_pin_capacitance_typ;
+ u8 driver_strength_support;
+- __le16 t_ald;
++ __le16 t_adl;
+ u8 reserved4[36];
+
+ /* ECC and endurance block */
+@@ -444,6 +464,7 @@ struct nand_hw_control {
+ /**
+ * struct nand_ecc_ctrl - Control structure for ECC
+ * @mode: ECC mode
++ * @algo: ECC algorithm
+ * @steps: number of ECC steps per page
+ * @size: data bytes per ECC step
+ * @bytes: ECC bytes per step
+@@ -451,12 +472,18 @@ struct nand_hw_control {
+ * @total: total number of ECC bytes per page
+ * @prepad: padding information for syndrome based ECC generators
+ * @postpad: padding information for syndrome based ECC generators
+- * @layout: ECC layout control struct pointer
++ * @options: ECC specific options (see NAND_ECC_XXX flags defined above)
+ * @priv: pointer to private ECC control data
+ * @hwctl: function to control hardware ECC generator. Must only
+ * be provided if an hardware ECC is available
+ * @calculate: function for ECC calculation or readback from ECC hardware
+- * @correct: function for ECC correction, matching to ECC generator (sw/hw)
++ * @correct: function for ECC correction, matching to ECC generator (sw/hw).
++ * Should return a positive number representing the number of
++ * corrected bitflips, -EBADMSG if the number of bitflips exceed
++ * ECC strength, or any other error code if the error is not
++ * directly related to correction.
++ * If -EBADMSG is returned the input buffers should be left
++ * untouched.
+ * @read_page_raw: function to read a raw page without ECC. This function
+ * should hide the specific layout used by the ECC
+ * controller and always return contiguous in-band and
+@@ -487,6 +514,7 @@ struct nand_hw_control {
+ */
+ struct nand_ecc_ctrl {
+ nand_ecc_modes_t mode;
++ enum nand_ecc_algo algo;
+ int steps;
+ int size;
+ int bytes;
+@@ -494,7 +522,7 @@ struct nand_ecc_ctrl {
+ int strength;
+ int prepad;
+ int postpad;
+- struct nand_ecclayout *layout;
++ unsigned int options;
+ void *priv;
+ void (*hwctl)(struct mtd_info *mtd, int mode);
+ int (*calculate)(struct mtd_info *mtd, const uint8_t *dat,
+@@ -540,11 +568,11 @@ struct nand_buffers {
+
+ /**
+ * struct nand_chip - NAND Private Flash Chip Data
++ * @mtd: MTD device registered to the MTD framework
+ * @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the
+ * flash device
+ * @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the
+ * flash device.
+- * @flash_node: [BOARDSPECIFIC] device node describing this instance
+ * @read_byte: [REPLACEABLE] read one byte from the chip
+ * @read_word: [REPLACEABLE] read one word from the chip
+ * @write_byte: [REPLACEABLE] write a single byte to the chip on the
+@@ -640,18 +668,17 @@ struct nand_buffers {
+ */
+
+ struct nand_chip {
++ struct mtd_info mtd;
+ void __iomem *IO_ADDR_R;
+ void __iomem *IO_ADDR_W;
+
+- struct device_node *flash_node;
+-
+ uint8_t (*read_byte)(struct mtd_info *mtd);
+ u16 (*read_word)(struct mtd_info *mtd);
+ void (*write_byte)(struct mtd_info *mtd, uint8_t byte);
+ void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
+ void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
+ void (*select_chip)(struct mtd_info *mtd, int chip);
+- int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
++ int (*block_bad)(struct mtd_info *mtd, loff_t ofs);
+ int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
+ void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
+ int (*dev_ready)(struct mtd_info *mtd);
+@@ -719,6 +746,40 @@ struct nand_chip {
+ void *priv;
+ };
+
++extern const struct mtd_ooblayout_ops nand_ooblayout_sp_ops;
++extern const struct mtd_ooblayout_ops nand_ooblayout_lp_ops;
++
++static inline void nand_set_flash_node(struct nand_chip *chip,
++ struct device_node *np)
++{
++ mtd_set_of_node(&chip->mtd, np);
++}
++
++static inline struct device_node *nand_get_flash_node(struct nand_chip *chip)
++{
++ return mtd_get_of_node(&chip->mtd);
++}
++
++static inline struct nand_chip *mtd_to_nand(struct mtd_info *mtd)
++{
++ return container_of(mtd, struct nand_chip, mtd);
++}
++
++static inline struct mtd_info *nand_to_mtd(struct nand_chip *chip)
++{
++ return &chip->mtd;
++}
++
++static inline void *nand_get_controller_data(struct nand_chip *chip)
++{
++ return chip->priv;
++}
++
++static inline void nand_set_controller_data(struct nand_chip *chip, void *priv)
++{
++ chip->priv = priv;
++}
++
+ /*
+ * NAND Flash Manufacturer ID Codes
+ */
+@@ -850,7 +911,6 @@ extern int nand_do_read(struct mtd_info
+ * @chip_delay: R/B delay value in us
+ * @options: Option flags, e.g. 16bit buswidth
+ * @bbt_options: BBT option flags, e.g. NAND_BBT_USE_FLASH
+- * @ecclayout: ECC layout info structure
+ * @part_probe_types: NULL-terminated array of probe types
+ */
+ struct platform_nand_chip {
+@@ -858,7 +918,6 @@ struct platform_nand_chip {
+ int chip_offset;
+ int nr_partitions;
+ struct mtd_partition *partitions;
+- struct nand_ecclayout *ecclayout;
+ int chip_delay;
+ unsigned int options;
+ unsigned int bbt_options;
+@@ -908,15 +967,6 @@ struct platform_nand_data {
+ struct platform_nand_ctrl ctrl;
+ };
+
+-/* Some helpers to access the data structures */
+-static inline
+-struct platform_nand_chip *get_platform_nandchip(struct mtd_info *mtd)
+-{
+- struct nand_chip *chip = mtd->priv;
+-
+- return chip->priv;
+-}
+-
+ /* return the supported features. */
+ static inline int onfi_feature(struct nand_chip *chip)
+ {
+--- a/include/linux/mtd/nand_bch.h
++++ b/include/linux/mtd/nand_bch.h
+@@ -32,9 +32,7 @@ int nand_bch_correct_data(struct mtd_inf
+ /*
+ * Initialize BCH encoder/decoder
+ */
+-struct nand_bch_control *
+-nand_bch_init(struct mtd_info *mtd, unsigned int eccsize,
+- unsigned int eccbytes, struct nand_ecclayout **ecclayout);
++struct nand_bch_control *nand_bch_init(struct mtd_info *mtd);
+ /*
+ * Release BCH encoder/decoder resources
+ */
+@@ -55,12 +53,10 @@ static inline int
+ nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
+ unsigned char *read_ecc, unsigned char *calc_ecc)
+ {
+- return -1;
++ return -ENOTSUPP;
+ }
+
+-static inline struct nand_bch_control *
+-nand_bch_init(struct mtd_info *mtd, unsigned int eccsize,
+- unsigned int eccbytes, struct nand_ecclayout **ecclayout)
++static inline struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
+ {
+ return NULL;
+ }
+--- a/include/linux/mtd/nftl.h
++++ b/include/linux/mtd/nftl.h
+@@ -50,7 +50,6 @@ struct NFTLrecord {
+ unsigned int nb_blocks; /* number of physical blocks */
+ unsigned int nb_boot_blocks; /* number of blocks used by the bios */
+ struct erase_info instr;
+- struct nand_ecclayout oobinfo;
+ };
+
+ int NFTL_mount(struct NFTLrecord *s);
+--- a/include/linux/mtd/onenand.h
++++ b/include/linux/mtd/onenand.h
+@@ -80,7 +80,6 @@ struct onenand_bufferram {
+ * @page_buf: [INTERN] page main data buffer
+ * @oob_buf: [INTERN] page oob data buffer
+ * @subpagesize: [INTERN] holds the subpagesize
+- * @ecclayout: [REPLACEABLE] the default ecc placement scheme
+ * @bbm: [REPLACEABLE] pointer to Bad Block Management
+ * @priv: [OPTIONAL] pointer to private chip date
+ */
+@@ -134,7 +133,6 @@ struct onenand_chip {
+ #endif
+
+ int subpagesize;
+- struct nand_ecclayout *ecclayout;
+
+ void *bbm;
+
+--- a/include/linux/mtd/partitions.h
++++ b/include/linux/mtd/partitions.h
+@@ -42,7 +42,6 @@ struct mtd_partition {
+ uint64_t size; /* partition size */
+ uint64_t offset; /* offset within the master MTD space */
+ uint32_t mask_flags; /* master MTD flags to mask out for this partition */
+- struct nand_ecclayout *ecclayout; /* out of band layout for this partition (NAND only) */
+ };
+
+ #define MTDPART_OFS_RETAIN (-3)
+@@ -56,11 +55,9 @@ struct device_node;
+ /**
+ * struct mtd_part_parser_data - used to pass data to MTD partition parsers.
+ * @origin: for RedBoot, start address of MTD device
+- * @of_node: for OF parsers, device node containing partitioning information
+ */
+ struct mtd_part_parser_data {
+ unsigned long origin;
+- struct device_node *of_node;
+ };
+
+
+@@ -78,14 +75,34 @@ struct mtd_part_parser {
+ struct list_head list;
+ struct module *owner;
+ const char *name;
+- int (*parse_fn)(struct mtd_info *, struct mtd_partition **,
++ int (*parse_fn)(struct mtd_info *, const struct mtd_partition **,
+ struct mtd_part_parser_data *);
++ void (*cleanup)(const struct mtd_partition *pparts, int nr_parts);
+ enum mtd_parser_type type;
+ };
+
+-extern void register_mtd_parser(struct mtd_part_parser *parser);
++/* Container for passing around a set of parsed partitions */
++struct mtd_partitions {
++ const struct mtd_partition *parts;
++ int nr_parts;
++ const struct mtd_part_parser *parser;
++};
++
++extern int __register_mtd_parser(struct mtd_part_parser *parser,
++ struct module *owner);
++#define register_mtd_parser(parser) __register_mtd_parser(parser, THIS_MODULE)
++
+ extern void deregister_mtd_parser(struct mtd_part_parser *parser);
+
++/*
++ * module_mtd_part_parser() - Helper macro for MTD partition parsers that don't
++ * do anything special in module init/exit. Each driver may only use this macro
++ * once, and calling it replaces module_init() and module_exit().
++ */
++#define module_mtd_part_parser(__mtd_part_parser) \
++ module_driver(__mtd_part_parser, register_mtd_parser, \
++ deregister_mtd_parser)
++
+ int mtd_is_partition(const struct mtd_info *mtd);
+ int mtd_add_partition(struct mtd_info *master, const char *name,
+ long long offset, long long length);
+--- a/include/linux/mtd/sh_flctl.h
++++ b/include/linux/mtd/sh_flctl.h
+@@ -143,11 +143,11 @@ enum flctl_ecc_res_t {
+ struct dma_chan;
+
+ struct sh_flctl {
+- struct mtd_info mtd;
+ struct nand_chip chip;
+ struct platform_device *pdev;
+ struct dev_pm_qos_request pm_qos;
+ void __iomem *reg;
++ resource_size_t fifo;
+
+ uint8_t done_buff[2048 + 64]; /* max size 2048 + 64 */
+ int read_bytes;
+@@ -186,7 +186,7 @@ struct sh_flctl_platform_data {
+
+ static inline struct sh_flctl *mtd_to_flctl(struct mtd_info *mtdinfo)
+ {
+- return container_of(mtdinfo, struct sh_flctl, mtd);
++ return container_of(mtd_to_nand(mtdinfo), struct sh_flctl, chip);
+ }
+
+ #endif /* __SH_FLCTL_H__ */
+--- a/include/linux/mtd/sharpsl.h
++++ b/include/linux/mtd/sharpsl.h
+@@ -14,7 +14,7 @@
+
+ struct sharpsl_nand_platform_data {
+ struct nand_bbt_descr *badblock_pattern;
+- struct nand_ecclayout *ecc_layout;
++ const struct mtd_ooblayout_ops *ecc_layout;
+ struct mtd_partition *partitions;
+ unsigned int nr_partitions;
+ };
+--- a/include/uapi/mtd/mtd-abi.h
++++ b/include/uapi/mtd/mtd-abi.h
+@@ -228,7 +228,7 @@ struct nand_oobfree {
+ * complete set of ECC information. The ioctl truncates the larger internal
+ * structure to retain binary compatibility with the static declaration of the
+ * ioctl. Note that the "MTD_MAX_..._ENTRIES" macros represent the max size of
+- * the user struct, not the MAX size of the internal struct nand_ecclayout.
++ * the user struct, not the MAX size of the internal OOB layout representation.
+ */
+ struct nand_ecclayout_user {
+ __u32 eccbytes;
+--- a/fs/jffs2/wbuf.c
++++ b/fs/jffs2/wbuf.c
+@@ -1153,7 +1153,7 @@ static struct jffs2_sb_info *work_to_sb(
+ {
+ struct delayed_work *dwork;
+
+- dwork = container_of(work, struct delayed_work, work);
++ dwork = to_delayed_work(work);
+ return container_of(dwork, struct jffs2_sb_info, wbuf_dwork);
+ }
+
+@@ -1183,22 +1183,20 @@ void jffs2_dirty_trigger(struct jffs2_sb
+
+ int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
+ {
+- struct nand_ecclayout *oinfo = c->mtd->ecclayout;
+-
+ if (!c->mtd->oobsize)
+ return 0;
+
+ /* Cleanmarker is out-of-band, so inline size zero */
+ c->cleanmarker_size = 0;
+
+- if (!oinfo || oinfo->oobavail == 0) {
++ if (c->mtd->oobavail == 0) {
+ pr_err("inconsistent device description\n");
+ return -EINVAL;
+ }
+
+ jffs2_dbg(1, "using OOB on NAND\n");
+
+- c->oobavail = oinfo->oobavail;
++ c->oobavail = c->mtd->oobavail;
+
+ /* Initialise write buffer */
+ init_rwsem(&c->wbuf_sem);
+--- a/include/linux/mtd/spi-nor.h
++++ b/include/linux/mtd/spi-nor.h
+@@ -85,6 +85,7 @@
+ #define SR_BP0 BIT(2) /* Block protect 0 */
+ #define SR_BP1 BIT(3) /* Block protect 1 */
+ #define SR_BP2 BIT(4) /* Block protect 2 */
++#define SR_TB BIT(5) /* Top/Bottom protect */
+ #define SR_SRWD BIT(7) /* SR write protect */
+
+ #define SR_QUAD_EN_MX BIT(6) /* Macronix Quad I/O */
+@@ -116,6 +117,7 @@ enum spi_nor_ops {
+
+ enum spi_nor_option_flags {
+ SNOR_F_USE_FSR = BIT(0),
++ SNOR_F_HAS_SR_TB = BIT(1),
+ };
+
+ /**
+@@ -123,7 +125,6 @@ enum spi_nor_option_flags {
+ * @mtd: point to a mtd_info structure
+ * @lock: the lock for the read/write/erase/lock/unlock operations
+ * @dev: point to a spi device, or a spi nor controller device.
+- * @flash_node: point to a device node describing this flash instance.
+ * @page_size: the page size of the SPI NOR
+ * @addr_width: number of address bytes
+ * @erase_opcode: the opcode for erasing a sector
+@@ -143,7 +144,8 @@ enum spi_nor_option_flags {
+ * @read: [DRIVER-SPECIFIC] read data from the SPI NOR
+ * @write: [DRIVER-SPECIFIC] write data to the SPI NOR
+ * @erase: [DRIVER-SPECIFIC] erase a sector of the SPI NOR
+- * at the offset @offs
++ * at the offset @offs; if not provided by the driver,
++ * spi-nor will send the erase opcode via write_reg()
+ * @flash_lock: [FLASH-SPECIFIC] lock a region of the SPI NOR
+ * @flash_unlock: [FLASH-SPECIFIC] unlock a region of the SPI NOR
+ * @flash_is_locked: [FLASH-SPECIFIC] check if a region of the SPI NOR is
+@@ -154,7 +156,6 @@ struct spi_nor {
+ struct mtd_info mtd;
+ struct mutex lock;
+ struct device *dev;
+- struct device_node *flash_node;
+ u32 page_size;
+ u8 addr_width;
+ u8 erase_opcode;
+@@ -184,6 +185,17 @@ struct spi_nor {
+ void *priv;
+ };
+
++static inline void spi_nor_set_flash_node(struct spi_nor *nor,
++ struct device_node *np)
++{
++ mtd_set_of_node(&nor->mtd, np);
++}
++
++static inline struct device_node *spi_nor_get_flash_node(struct spi_nor *nor)
++{
++ return mtd_get_of_node(&nor->mtd);
++}
++
+ /**
+ * spi_nor_scan() - scan the SPI NOR
+ * @nor: the spi_nor structure
diff --git a/target/linux/mediatek/patches-4.4/0072-net-mediatek-remove-superflous-reset-call.patch b/target/linux/mediatek/patches-4.4/0072-net-mediatek-remove-superflous-reset-call.patch
deleted file mode 100644
index c2b5fdafa6..0000000000
--- a/target/linux/mediatek/patches-4.4/0072-net-mediatek-remove-superflous-reset-call.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-From 51dc0a2114c3d6e51bf2acde415fccdec031e480 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Fri, 25 Mar 2016 04:24:27 +0100
-Subject: [PATCH 72/91] net: mediatek: remove superflous reset call
-
-HW reset is triggered int he mtk_hw_init() function. There is no need to
-reset the core during probe.
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 ----
- 1 file changed, 4 deletions(-)
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 4d8d0a3..293ea59 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -1679,10 +1679,6 @@ static int mtk_probe(struct platform_device *pdev)
- struct mtk_eth *eth;
- int err;
-
-- err = device_reset(&pdev->dev);
-- if (err)
-- return err;
--
- match = of_match_device(of_mtk_match, &pdev->dev);
- soc = (struct mtk_soc_data *)match->data;
-
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0073-net-mediatek-fix-stop-and-wakeup-of-queue.patch b/target/linux/mediatek/patches-4.4/0073-net-mediatek-fix-stop-and-wakeup-of-queue.patch
deleted file mode 100644
index b14b67acf0..0000000000
--- a/target/linux/mediatek/patches-4.4/0073-net-mediatek-fix-stop-and-wakeup-of-queue.patch
+++ /dev/null
@@ -1,89 +0,0 @@
-From 868eb5a3d0217e1ecdc2f628c6dc4fcd18562a71 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Tue, 29 Mar 2016 16:41:07 +0200
-Subject: [PATCH 73/91] net: mediatek: fix stop and wakeup of queue
-
-The driver supports 2 MACs. Both run on the same DMA ring. If we go
-above/below the TX rings thershold value, we always need to wake/stop
-the queu of both devices. Not doing to can cause TX stalls and packet
-drops on one of the devices.
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 37 +++++++++++++++++++--------
- 1 file changed, 27 insertions(+), 10 deletions(-)
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 293ea59..04bdb9d 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -684,6 +684,28 @@ static inline int mtk_cal_txd_req(struct sk_buff *skb)
- return nfrags;
- }
-
-+static void mtk_wake_queue(struct mtk_eth *eth)
-+{
-+ int i;
-+
-+ for (i = 0; i < MTK_MAC_COUNT; i++) {
-+ if (!eth->netdev[i])
-+ continue;
-+ netif_wake_queue(eth->netdev[i]);
-+ }
-+}
-+
-+static void mtk_stop_queue(struct mtk_eth *eth)
-+{
-+ int i;
-+
-+ for (i = 0; i < MTK_MAC_COUNT; i++) {
-+ if (!eth->netdev[i])
-+ continue;
-+ netif_stop_queue(eth->netdev[i]);
-+ }
-+}
-+
- static int mtk_start_xmit(struct sk_buff *skb, struct net_device *dev)
- {
- struct mtk_mac *mac = netdev_priv(dev);
-@@ -695,7 +717,7 @@ static int mtk_start_xmit(struct sk_buff *skb, struct net_device *dev)
-
- tx_num = mtk_cal_txd_req(skb);
- if (unlikely(atomic_read(&ring->free_count) <= tx_num)) {
-- netif_stop_queue(dev);
-+ mtk_stop_queue(eth);
- netif_err(eth, tx_queued, dev,
- "Tx Ring full when queue awake!\n");
- return NETDEV_TX_BUSY;
-@@ -720,10 +742,10 @@ static int mtk_start_xmit(struct sk_buff *skb, struct net_device *dev)
- goto drop;
-
- if (unlikely(atomic_read(&ring->free_count) <= ring->thresh)) {
-- netif_stop_queue(dev);
-+ mtk_stop_queue(eth);
- if (unlikely(atomic_read(&ring->free_count) >
- ring->thresh))
-- netif_wake_queue(dev);
-+ mtk_wake_queue(eth);
- }
-
- return NETDEV_TX_OK;
-@@ -897,13 +919,8 @@ static int mtk_poll_tx(struct mtk_eth *eth, int budget, bool *tx_again)
- if (!total)
- return 0;
-
-- for (i = 0; i < MTK_MAC_COUNT; i++) {
-- if (!eth->netdev[i] ||
-- unlikely(!netif_queue_stopped(eth->netdev[i])))
-- continue;
-- if (atomic_read(&ring->free_count) > ring->thresh)
-- netif_wake_queue(eth->netdev[i]);
-- }
-+ if (atomic_read(&ring->free_count) > ring->thresh)
-+ mtk_wake_queue(eth);
-
- return total;
- }
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0073-of-mtd-prepare-helper-reading-NAND-ECC-algo-from-DT.patch b/target/linux/mediatek/patches-4.4/0073-of-mtd-prepare-helper-reading-NAND-ECC-algo-from-DT.patch
new file mode 100644
index 0000000000..44ab079cc0
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0073-of-mtd-prepare-helper-reading-NAND-ECC-algo-from-DT.patch
@@ -0,0 +1,91 @@
+From 410a91f6efa1c4c3c4369d1dd2c31286749dff33 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Wed, 23 Mar 2016 11:19:01 +0100
+Subject: [PATCH 073/102] of: mtd: prepare helper reading NAND ECC algo from
+ DT
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+NAND subsystem is being slightly reworked to store ECC details in
+separated fields. In future we'll want to add support for more DT
+properties as specifying every possible setup with a single
+"nand-ecc-mode" is a pretty bad idea.
+To allow this let's add a helper that will support something like
+"nand-ecc-algo" in future. Right now we use it for keeping backward
+compatibility.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
+---
+ drivers/of/of_mtd.c | 36 ++++++++++++++++++++++++++++++++++++
+ include/linux/of_mtd.h | 6 ++++++
+ 2 files changed, 42 insertions(+)
+
+--- a/drivers/of/of_mtd.c
++++ b/drivers/of/of_mtd.c
+@@ -50,6 +50,42 @@ int of_get_nand_ecc_mode(struct device_n
+ EXPORT_SYMBOL_GPL(of_get_nand_ecc_mode);
+
+ /**
++ * of_get_nand_ecc_algo - Get nand ecc algorithm for given device_node
++ * @np: Pointer to the given device_node
++ *
++ * The function gets ecc algorithm and returns its enum value, or errno in error
++ * case.
++ */
++int of_get_nand_ecc_algo(struct device_node *np)
++{
++ const char *pm;
++ int err;
++
++ /*
++ * TODO: Read ECC algo OF property and map it to enum nand_ecc_algo.
++ * It's not implemented yet as currently NAND subsystem ignores
++ * algorithm explicitly set this way. Once it's handled we should
++ * document & support new property.
++ */
++
++ /*
++ * For backward compatibility we also read "nand-ecc-mode" checking
++ * for some obsoleted values that were specifying ECC algorithm.
++ */
++ err = of_property_read_string(np, "nand-ecc-mode", &pm);
++ if (err < 0)
++ return err;
++
++ if (!strcasecmp(pm, "soft"))
++ return NAND_ECC_HAMMING;
++ else if (!strcasecmp(pm, "soft_bch"))
++ return NAND_ECC_BCH;
++
++ return -ENODEV;
++}
++EXPORT_SYMBOL_GPL(of_get_nand_ecc_algo);
++
++/**
+ * of_get_nand_ecc_step_size - Get ECC step size associated to
+ * the required ECC strength (see below).
+ * @np: Pointer to the given device_node
+--- a/include/linux/of_mtd.h
++++ b/include/linux/of_mtd.h
+@@ -13,6 +13,7 @@
+
+ #include <linux/of.h>
+ int of_get_nand_ecc_mode(struct device_node *np);
++int of_get_nand_ecc_algo(struct device_node *np);
+ int of_get_nand_ecc_step_size(struct device_node *np);
+ int of_get_nand_ecc_strength(struct device_node *np);
+ int of_get_nand_bus_width(struct device_node *np);
+@@ -24,6 +25,11 @@ static inline int of_get_nand_ecc_mode(s
+ {
+ return -ENOSYS;
+ }
++
++static inline int of_get_nand_ecc_algo(struct device_node *np)
++{
++ return -ENOSYS;
++}
+
+ static inline int of_get_nand_ecc_step_size(struct device_node *np)
+ {
diff --git a/target/linux/mediatek/patches-4.4/0074-mtd-mediatek-device-tree-docs-for-MTK-Smart-Device-G.patch b/target/linux/mediatek/patches-4.4/0074-mtd-mediatek-device-tree-docs-for-MTK-Smart-Device-G.patch
new file mode 100644
index 0000000000..5f260e3e34
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0074-mtd-mediatek-device-tree-docs-for-MTK-Smart-Device-G.patch
@@ -0,0 +1,179 @@
+From 5e1c00983efeca4522ac2e8574e3e3997d26a203 Mon Sep 17 00:00:00 2001
+From: Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
+Date: Fri, 29 Apr 2016 12:17:21 -0400
+Subject: [PATCH 074/102] mtd: mediatek: device tree docs for MTK Smart Device
+ Gen1 NAND
+
+This patch adds documentation support for Smart Device Gen1 type of
+NAND controllers.
+
+Signed-off-by: Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
+---
+ Documentation/devicetree/bindings/mtd/mtk-nand.txt | 161 ++++++++++++++++++++
+ 1 file changed, 161 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/mtd/mtk-nand.txt
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/mtd/mtk-nand.txt
+@@ -0,0 +1,161 @@
++MTK SoCs NAND FLASH controller (NFC) DT binding
++
++This file documents the device tree bindings for MTK SoCs NAND controllers.
++The functional split of the controller requires two drivers to operate:
++the nand controller interface driver and the ECC engine driver.
++
++The hardware description for both devices must be captured as device
++tree nodes.
++
++1) NFC NAND Controller Interface (NFI):
++=======================================
++
++The first part of NFC is NAND Controller Interface (NFI) HW.
++Required NFI properties:
++- compatible: Should be "mediatek,mtxxxx-nfc".
++- reg: Base physical address and size of NFI.
++- interrupts: Interrupts of NFI.
++- clocks: NFI required clocks.
++- clock-names: NFI clocks internal name.
++- status: Disabled default. Then set "okay" by platform.
++- ecc-engine: Required ECC Engine node.
++- #address-cells: NAND chip index, should be 1.
++- #size-cells: Should be 0.
++
++Example:
++
++ nandc: nfi@1100d000 {
++ compatible = "mediatek,mt2701-nfc";
++ reg = <0 0x1100d000 0 0x1000>;
++ interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_LOW>;
++ clocks = <&pericfg CLK_PERI_NFI>,
++ <&pericfg CLK_PERI_NFI_PAD>;
++ clock-names = "nfi_clk", "pad_clk";
++ status = "disabled";
++ ecc-engine = <&bch>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
++Platform related properties, should be set in {platform_name}.dts:
++- children nodes: NAND chips.
++
++Children nodes properties:
++- reg: Chip Select Signal, default 0.
++ Set as reg = <0>, <1> when need 2 CS.
++Optional:
++- nand-on-flash-bbt: Store BBT on NAND Flash.
++- nand-ecc-mode: the NAND ecc mode (check driver for supported modes)
++- nand-ecc-step-size: Number of data bytes covered by a single ECC step.
++ The controller only supports 512 and 1024.
++ For large page NANDs ther recommended value is 1024.
++- nand-ecc-strength: Number of bits to correct per ECC step.
++ The valid values that the controller supports are: 4, 6,
++ 8, 10, 12, 14, 16, 18, 20, 22, 24, 28, 32, 36, 40, 44,
++ 48, 52, 56, 60.
++ The strength should be calculated as follows:
++ E = (S - F) * 8 / 14
++ S = O / (P / Q)
++ E :nand-ecc-strength;
++ S :spare size per sector;
++ F : FDM size, should be in the range [1,8].
++ It is used to store free oob data.
++ O : oob size;
++ P : page size;
++ Q :nand-ecc-step-size
++ If the result does not match any one of the listed
++ choices above, please select the smaller valid value from
++ the list.
++ (otherwise the driver will do the clamping at runtime).
++- vmch-supply: NAND power supply.
++- pinctrl-names: Default NAND pin GPIO setting name.
++- pinctrl-0: GPIO setting node.
++
++Example:
++ &pio {
++ nand_pins_default: nanddefault {
++ pins_dat {
++ pinmux = <MT2701_PIN_111_MSDC0_DAT7__FUNC_NLD7>,
++ <MT2701_PIN_112_MSDC0_DAT6__FUNC_NLD6>,
++ <MT2701_PIN_114_MSDC0_DAT4__FUNC_NLD4>,
++ <MT2701_PIN_118_MSDC0_DAT3__FUNC_NLD3>,
++ <MT2701_PIN_121_MSDC0_DAT0__FUNC_NLD0>,
++ <MT2701_PIN_120_MSDC0_DAT1__FUNC_NLD1>,
++ <MT2701_PIN_113_MSDC0_DAT5__FUNC_NLD5>,
++ <MT2701_PIN_115_MSDC0_RSTB__FUNC_NLD8>,
++ <MT2701_PIN_119_MSDC0_DAT2__FUNC_NLD2>;
++ input-enable;
++ drive-strength = <MTK_DRIVE_8mA>;
++ bias-pull-up;
++ };
++
++ pins_we {
++ pinmux = <MT2701_PIN_117_MSDC0_CLK__FUNC_NWEB>;
++ drive-strength = <MTK_DRIVE_8mA>;
++ bias-pull-up = <MTK_PUPD_SET_R1R0_10>;
++ };
++
++ pins_ale {
++ pinmux = <MT2701_PIN_116_MSDC0_CMD__FUNC_NALE>;
++ drive-strength = <MTK_DRIVE_8mA>;
++ bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
++ };
++ };
++ };
++
++ &nandc {
++ status = "okay";
++ pinctrl-names = "default";
++ pinctrl-0 = <&nand_pins_default>;
++ nand@0 {
++ reg = <0>;
++ nand-on-flash-bbt;
++ nand-ecc-mode = "hw";
++ nand-ecc-strength = <24>;
++ nand-ecc-step-size = <1024>;
++ };
++ };
++
++NAND chip optional subnodes:
++- Partitions, see Documentation/devicetree/bindings/mtd/partition.txt
++
++Example:
++ nand@0 {
++ partitions {
++ compatible = "fixed-partitions";
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ preloader@0 {
++ label = "pl";
++ read-only;
++ reg = <0x00000000 0x00400000>;
++ };
++ android@0x00400000 {
++ label = "android";
++ reg = <0x00400000 0x12c00000>;
++ };
++ };
++ };
++
++2) ECC Engine:
++==============
++
++Required BCH properties:
++- compatible: Should be "mediatek,mtxxxx-ecc".
++- reg: Base physical address and size of ECC.
++- interrupts: Interrupts of ECC.
++- clocks: ECC required clocks.
++- clock-names: ECC clocks internal name.
++- status: Disabled default. Then set "okay" by platform.
++
++Example:
++
++ bch: ecc@1100e000 {
++ compatible = "mediatek,mt2701-ecc";
++ reg = <0 0x1100e000 0 0x1000>;
++ interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_LOW>;
++ clocks = <&pericfg CLK_PERI_NFI_ECC>;
++ clock-names = "nfiecc_clk";
++ status = "disabled";
++ };
diff --git a/target/linux/mediatek/patches-4.4/0074-net-mediatek-fix-mtk_pending_work.patch b/target/linux/mediatek/patches-4.4/0074-net-mediatek-fix-mtk_pending_work.patch
deleted file mode 100644
index 1a2ce6f873..0000000000
--- a/target/linux/mediatek/patches-4.4/0074-net-mediatek-fix-mtk_pending_work.patch
+++ /dev/null
@@ -1,63 +0,0 @@
-From 300ca8c6b5dcee2593f22d5bf8f13bb4da8c19c5 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Tue, 29 Mar 2016 17:00:47 +0200
-Subject: [PATCH 74/91] net: mediatek: fix mtk_pending_work
-
-The driver supports 2 MACs. Both run on the same DMA ring. If we hit a TX
-timeout we need to stop both netdevs before retarting them again. If we
-dont do thsi, mtk_stop() wont shutdown DMA and the consecutive call to
-mtk_open() wont restart DMA and enable IRQs.
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 30 +++++++++++++++++++--------
- 1 file changed, 21 insertions(+), 9 deletions(-)
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 04bdb9d..26eeb1a 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -1430,19 +1430,31 @@ static int mtk_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-
- static void mtk_pending_work(struct work_struct *work)
- {
-- struct mtk_mac *mac = container_of(work, struct mtk_mac, pending_work);
-- struct mtk_eth *eth = mac->hw;
-- struct net_device *dev = eth->netdev[mac->id];
-- int err;
-+ struct mtk_eth *eth = container_of(work, struct mtk_eth, pending_work);
-+ int err, i;
-+ unsigned long restart = 0;
-
- rtnl_lock();
-- mtk_stop(dev);
-
-- err = mtk_open(dev);
-- if (err) {
-- netif_alert(eth, ifup, dev,
-+ /* stop all devices to make sure that dma is properly shut down */
-+ for (i = 0; i < MTK_MAC_COUNT; i++) {
-+ if (!netif_oper_up(eth->netdev[i]))
-+ continue;
-+ mtk_stop(eth->netdev[i]);
-+ __set_bit(i, &restart);
-+ }
-+
-+
-+ /* restart DMA and enable IRQs */
-+ for (i = 0; i < MTK_MAC_COUNT; i++) {
-+ if (!test_bit(i, &restart))
-+ continue;
-+ err = mtk_open(eth->netdev[i]);
-+ if (err) {
-+ netif_alert(eth, ifup, eth->netdev[i],
- "Driver up/down cycle failed, closing device.\n");
-- dev_close(dev);
-+ dev_close(eth->netdev[i]);
-+ }
- }
- rtnl_unlock();
- }
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0075-mtd-mediatek-driver-for-MTK-Smart-Device-Gen1-NAND.patch b/target/linux/mediatek/patches-4.4/0075-mtd-mediatek-driver-for-MTK-Smart-Device-Gen1-NAND.patch
new file mode 100644
index 0000000000..e5312eb08c
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0075-mtd-mediatek-driver-for-MTK-Smart-Device-Gen1-NAND.patch
@@ -0,0 +1,2064 @@
+From de18239fc971cfc17c53320c66ae64dd5ade032d Mon Sep 17 00:00:00 2001
+From: Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
+Date: Fri, 29 Apr 2016 12:17:22 -0400
+Subject: [PATCH 075/102] mtd: mediatek: driver for MTK Smart Device Gen1 NAND
+
+This patch adds support for mediatek's SDG1 NFC nand controller
+embedded in SoC 2701
+
+Signed-off-by: Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
+---
+ drivers/mtd/nand/Kconfig | 7 +
+ drivers/mtd/nand/Makefile | 1 +
+ drivers/mtd/nand/mtk_ecc.c | 527 ++++++++++++++++
+ drivers/mtd/nand/mtk_ecc.h | 53 ++
+ drivers/mtd/nand/mtk_nand.c | 1432 +++++++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 2020 insertions(+)
+ create mode 100644 drivers/mtd/nand/mtk_ecc.c
+ create mode 100644 drivers/mtd/nand/mtk_ecc.h
+ create mode 100644 drivers/mtd/nand/mtk_nand.c
+
+--- a/drivers/mtd/nand/Kconfig
++++ b/drivers/mtd/nand/Kconfig
+@@ -563,4 +563,11 @@ config MTD_NAND_QCOM
+ Enables support for NAND flash chips on SoCs containing the EBI2 NAND
+ controller. This controller is found on IPQ806x SoC.
+
++config MTD_NAND_MTK
++ tristate "Support for NAND controller on MTK SoCs"
++ depends on HAS_DMA
++ help
++ Enables support for NAND controller on MTK SoCs.
++ This controller is found on mt27xx, mt81xx, mt65xx SoCs.
++
+ endif # MTD_NAND
+--- a/drivers/mtd/nand/Makefile
++++ b/drivers/mtd/nand/Makefile
+@@ -57,5 +57,6 @@ obj-$(CONFIG_MTD_NAND_SUNXI) += sunxi_n
+ obj-$(CONFIG_MTD_NAND_HISI504) += hisi504_nand.o
+ obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand/
+ obj-$(CONFIG_MTD_NAND_QCOM) += qcom_nandc.o
++obj-$(CONFIG_MTD_NAND_MTK) += mtk_nand.o mtk_ecc.o
+
+ nand-objs := nand_base.o nand_bbt.o nand_timings.o
+--- /dev/null
++++ b/drivers/mtd/nand/mtk_ecc.c
+@@ -0,0 +1,527 @@
++/*
++ * MTK ECC controller driver.
++ * Copyright (C) 2016 MediaTek Inc.
++ * Authors: Xiaolei Li <xiaolei.li@mediatek.com>
++ * Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/platform_device.h>
++#include <linux/dma-mapping.h>
++#include <linux/interrupt.h>
++#include <linux/clk.h>
++#include <linux/module.h>
++#include <linux/iopoll.h>
++#include <linux/of.h>
++#include <linux/of_platform.h>
++#include <linux/semaphore.h>
++
++#include "mtk_ecc.h"
++
++#define ECC_ENCCON (0x00)
++#define ENC_EN (1)
++#define ENC_DE (0)
++#define ECC_ENCCNFG (0x04)
++#define ECC_CNFG_4BIT (0)
++#define ECC_CNFG_6BIT (1)
++#define ECC_CNFG_8BIT (2)
++#define ECC_CNFG_10BIT (3)
++#define ECC_CNFG_12BIT (4)
++#define ECC_CNFG_14BIT (5)
++#define ECC_CNFG_16BIT (6)
++#define ECC_CNFG_18BIT (7)
++#define ECC_CNFG_20BIT (8)
++#define ECC_CNFG_22BIT (9)
++#define ECC_CNFG_24BIT (0xa)
++#define ECC_CNFG_28BIT (0xb)
++#define ECC_CNFG_32BIT (0xc)
++#define ECC_CNFG_36BIT (0xd)
++#define ECC_CNFG_40BIT (0xe)
++#define ECC_CNFG_44BIT (0xf)
++#define ECC_CNFG_48BIT (0x10)
++#define ECC_CNFG_52BIT (0x11)
++#define ECC_CNFG_56BIT (0x12)
++#define ECC_CNFG_60BIT (0x13)
++#define ECC_MODE_SHIFT (5)
++#define ECC_MS_SHIFT (16)
++#define ECC_ENCDIADDR (0x08)
++#define ECC_ENCIDLE (0x0C)
++#define ENC_IDLE BIT(0)
++#define ECC_ENCPAR(x) (0x10 + (x) * sizeof(u32))
++#define ECC_ENCIRQ_EN (0x80)
++#define ENC_IRQEN BIT(0)
++#define ECC_ENCIRQ_STA (0x84)
++#define ECC_DECCON (0x100)
++#define DEC_EN (1)
++#define DEC_DE (0)
++#define ECC_DECCNFG (0x104)
++#define DEC_EMPTY_EN BIT(31)
++#define DEC_CNFG_CORRECT (0x3 << 12)
++#define ECC_DECIDLE (0x10C)
++#define DEC_IDLE BIT(0)
++#define ECC_DECENUM0 (0x114)
++#define ERR_MASK (0x3f)
++#define ECC_DECDONE (0x124)
++#define ECC_DECIRQ_EN (0x200)
++#define DEC_IRQEN BIT(0)
++#define ECC_DECIRQ_STA (0x204)
++
++#define ECC_TIMEOUT (500000)
++
++#define ECC_IDLE_REG(x) ((x) == ECC_ENC ? ECC_ENCIDLE : ECC_DECIDLE)
++#define ECC_IDLE_MASK(x) ((x) == ECC_ENC ? ENC_IDLE : DEC_IDLE)
++#define ECC_IRQ_REG(x) ((x) == ECC_ENC ? ECC_ENCIRQ_EN : ECC_DECIRQ_EN)
++#define ECC_IRQ_EN(x) ((x) == ECC_ENC ? ENC_IRQEN : DEC_IRQEN)
++#define ECC_CTL_REG(x) ((x) == ECC_ENC ? ECC_ENCCON : ECC_DECCON)
++#define ECC_CODEC_ENABLE(x) ((x) == ECC_ENC ? ENC_EN : DEC_EN)
++#define ECC_CODEC_DISABLE(x) ((x) == ECC_ENC ? ENC_DE : DEC_DE)
++
++struct mtk_ecc {
++ struct device *dev;
++ void __iomem *regs;
++ struct clk *clk;
++
++ struct completion done;
++ struct semaphore sem;
++ u32 sec_mask;
++};
++
++static inline void mtk_ecc_codec_wait_idle(struct mtk_ecc *ecc,
++ enum mtk_ecc_codec codec)
++{
++ struct device *dev = ecc->dev;
++ u32 val;
++ int ret;
++
++ ret = readl_poll_timeout_atomic(ecc->regs + ECC_IDLE_REG(codec), val,
++ val & ECC_IDLE_MASK(codec),
++ 10, ECC_TIMEOUT);
++ if (ret)
++ dev_warn(dev, "%s NOT idle\n",
++ codec == ECC_ENC ? "encoder" : "decoder");
++}
++
++static irqreturn_t mtk_ecc_irq(int irq, void *id)
++{
++ struct mtk_ecc *ecc = id;
++ enum mtk_ecc_codec codec;
++ u32 dec, enc;
++
++ dec = readw(ecc->regs + ECC_DECIRQ_STA) & DEC_IRQEN;
++ if (dec) {
++ codec = ECC_DEC;
++ dec = readw(ecc->regs + ECC_DECDONE);
++ if (dec & ecc->sec_mask) {
++ ecc->sec_mask = 0;
++ complete(&ecc->done);
++ } else
++ return IRQ_HANDLED;
++ } else {
++ enc = readl(ecc->regs + ECC_ENCIRQ_STA) & ENC_IRQEN;
++ if (enc) {
++ codec = ECC_ENC;
++ complete(&ecc->done);
++ } else
++ return IRQ_NONE;
++ }
++
++ writel(0, ecc->regs + ECC_IRQ_REG(codec));
++
++ return IRQ_HANDLED;
++}
++
++static void mtk_ecc_config(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
++{
++ u32 ecc_bit = ECC_CNFG_4BIT, dec_sz, enc_sz;
++ u32 reg;
++
++ switch (config->strength) {
++ case 4:
++ ecc_bit = ECC_CNFG_4BIT;
++ break;
++ case 6:
++ ecc_bit = ECC_CNFG_6BIT;
++ break;
++ case 8:
++ ecc_bit = ECC_CNFG_8BIT;
++ break;
++ case 10:
++ ecc_bit = ECC_CNFG_10BIT;
++ break;
++ case 12:
++ ecc_bit = ECC_CNFG_12BIT;
++ break;
++ case 14:
++ ecc_bit = ECC_CNFG_14BIT;
++ break;
++ case 16:
++ ecc_bit = ECC_CNFG_16BIT;
++ break;
++ case 18:
++ ecc_bit = ECC_CNFG_18BIT;
++ break;
++ case 20:
++ ecc_bit = ECC_CNFG_20BIT;
++ break;
++ case 22:
++ ecc_bit = ECC_CNFG_22BIT;
++ break;
++ case 24:
++ ecc_bit = ECC_CNFG_24BIT;
++ break;
++ case 28:
++ ecc_bit = ECC_CNFG_28BIT;
++ break;
++ case 32:
++ ecc_bit = ECC_CNFG_32BIT;
++ break;
++ case 36:
++ ecc_bit = ECC_CNFG_36BIT;
++ break;
++ case 40:
++ ecc_bit = ECC_CNFG_40BIT;
++ break;
++ case 44:
++ ecc_bit = ECC_CNFG_44BIT;
++ break;
++ case 48:
++ ecc_bit = ECC_CNFG_48BIT;
++ break;
++ case 52:
++ ecc_bit = ECC_CNFG_52BIT;
++ break;
++ case 56:
++ ecc_bit = ECC_CNFG_56BIT;
++ break;
++ case 60:
++ ecc_bit = ECC_CNFG_60BIT;
++ break;
++ default:
++ dev_err(ecc->dev, "invalid strength %d\n", config->strength);
++ }
++
++ if (config->codec == ECC_ENC) {
++ /* configure ECC encoder (in bits) */
++ enc_sz = config->enc_len << 3;
++
++ reg = ecc_bit | (config->ecc_mode << ECC_MODE_SHIFT);
++ reg |= (enc_sz << ECC_MS_SHIFT);
++ writel(reg, ecc->regs + ECC_ENCCNFG);
++
++ if (config->ecc_mode != ECC_NFI_MODE)
++ writel(lower_32_bits(config->addr),
++ ecc->regs + ECC_ENCDIADDR);
++
++ } else {
++ /* configure ECC decoder (in bits) */
++ dec_sz = config->dec_len;
++
++ reg = ecc_bit | (config->ecc_mode << ECC_MODE_SHIFT);
++ reg |= (dec_sz << ECC_MS_SHIFT) | DEC_CNFG_CORRECT;
++ reg |= DEC_EMPTY_EN;
++ writel(reg, ecc->regs + ECC_DECCNFG);
++
++ if (config->sec_mask)
++ ecc->sec_mask = 1 << (config->sec_mask - 1);
++ }
++}
++
++void mtk_ecc_get_stats(struct mtk_ecc *ecc, struct mtk_ecc_stats *stats,
++ int sectors)
++{
++ u32 offset, i, err;
++ u32 bitflips = 0;
++
++ stats->corrected = 0;
++ stats->failed = 0;
++
++ for (i = 0; i < sectors; i++) {
++ offset = (i >> 2) << 2;
++ err = readl(ecc->regs + ECC_DECENUM0 + offset);
++ err = err >> ((i % 4) * 8);
++ err &= ERR_MASK;
++ if (err == ERR_MASK) {
++ /* uncorrectable errors */
++ stats->failed++;
++ continue;
++ }
++
++ stats->corrected += err;
++ bitflips = max_t(u32, bitflips, err);
++ }
++
++ stats->bitflips = bitflips;
++}
++EXPORT_SYMBOL(mtk_ecc_get_stats);
++
++void mtk_ecc_release(struct mtk_ecc *ecc)
++{
++ clk_disable_unprepare(ecc->clk);
++ put_device(ecc->dev);
++}
++EXPORT_SYMBOL(mtk_ecc_release);
++
++static struct mtk_ecc *mtk_ecc_get(struct device_node *np)
++{
++ struct platform_device *pdev;
++ struct mtk_ecc *ecc;
++
++ pdev = of_find_device_by_node(np);
++ if (!pdev || !platform_get_drvdata(pdev))
++ return ERR_PTR(-EPROBE_DEFER);
++
++ get_device(&pdev->dev);
++ ecc = platform_get_drvdata(pdev);
++ clk_prepare_enable(ecc->clk);
++ mtk_ecc_hw_init(ecc);
++
++ return ecc;
++}
++
++struct mtk_ecc *of_mtk_ecc_get(struct device_node *of_node)
++{
++ struct mtk_ecc *ecc = NULL;
++ struct device_node *np;
++
++ np = of_parse_phandle(of_node, "ecc-engine", 0);
++ if (np) {
++ ecc = mtk_ecc_get(np);
++ of_node_put(np);
++ }
++
++ return ecc;
++}
++EXPORT_SYMBOL(of_mtk_ecc_get);
++
++int mtk_ecc_enable(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
++{
++ enum mtk_ecc_codec codec = config->codec;
++ int ret;
++
++ ret = down_interruptible(&ecc->sem);
++ if (ret) {
++ dev_err(ecc->dev, "interrupted when attempting to lock\n");
++ return ret;
++ }
++
++ mtk_ecc_codec_wait_idle(ecc, codec);
++ mtk_ecc_config(ecc, config);
++ writew(ECC_CODEC_ENABLE(codec), ecc->regs + ECC_CTL_REG(codec));
++
++ init_completion(&ecc->done);
++ writew(ECC_IRQ_EN(codec), ecc->regs + ECC_IRQ_REG(codec));
++
++ return 0;
++}
++EXPORT_SYMBOL(mtk_ecc_enable);
++
++void mtk_ecc_disable(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
++{
++ enum mtk_ecc_codec codec = config->codec;
++
++ mtk_ecc_codec_wait_idle(ecc, codec);
++ writew(0, ecc->regs + ECC_IRQ_REG(codec));
++ writew(ECC_CODEC_DISABLE(codec), ecc->regs + ECC_CTL_REG(codec));
++ up(&ecc->sem);
++}
++EXPORT_SYMBOL(mtk_ecc_disable);
++
++int mtk_ecc_wait_irq_done(struct mtk_ecc *ecc, enum mtk_ecc_codec codec)
++{
++ int ret;
++
++ ret = wait_for_completion_timeout(&ecc->done, msecs_to_jiffies(500));
++ if (!ret) {
++ dev_err(ecc->dev, "%s timeout - interrupt did not arrive)\n",
++ (codec == ECC_ENC) ? "encoder" : "decoder");
++ return -ETIMEDOUT;
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL(mtk_ecc_wait_irq_done);
++
++int mtk_ecc_encode_non_nfi_mode(struct mtk_ecc *ecc,
++ struct mtk_ecc_config *config, u8 *data, u32 bytes)
++{
++ dma_addr_t addr;
++ u32 *p, len, i;
++ int ret = 0;
++
++ addr = dma_map_single(ecc->dev, data, bytes, DMA_TO_DEVICE);
++ ret = dma_mapping_error(ecc->dev, addr);
++ if (ret) {
++ dev_err(ecc->dev, "dma mapping error\n");
++ return -EINVAL;
++ }
++
++ config->codec = ECC_ENC;
++ config->addr = addr;
++ ret = mtk_ecc_enable(ecc, config);
++ if (ret) {
++ dma_unmap_single(ecc->dev, addr, bytes, DMA_TO_DEVICE);
++ return ret;
++ }
++
++ ret = mtk_ecc_wait_irq_done(ecc, ECC_ENC);
++ if (ret)
++ goto timeout;
++
++ mtk_ecc_codec_wait_idle(ecc, ECC_ENC);
++
++ /* Program ECC bytes to OOB: per sector oob = FDM + ECC + SPARE */
++ len = (config->strength * ECC_PARITY_BITS + 7) >> 3;
++ p = (u32 *) (data + bytes);
++
++ /* write the parity bytes generated by the ECC back to the OOB region */
++ for (i = 0; i < len; i++)
++ p[i] = readl(ecc->regs + ECC_ENCPAR(i));
++timeout:
++
++ dma_unmap_single(ecc->dev, addr, bytes, DMA_TO_DEVICE);
++ mtk_ecc_disable(ecc, config);
++
++ return ret;
++}
++EXPORT_SYMBOL(mtk_ecc_encode_non_nfi_mode);
++
++void mtk_ecc_hw_init(struct mtk_ecc *ecc)
++{
++ mtk_ecc_codec_wait_idle(ecc, ECC_ENC);
++ writew(ENC_DE, ecc->regs + ECC_ENCCON);
++
++ mtk_ecc_codec_wait_idle(ecc, ECC_DEC);
++ writel(DEC_DE, ecc->regs + ECC_DECCON);
++}
++
++void mtk_ecc_update_strength(u32 *p)
++{
++ u32 ecc[] = {4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 28, 32, 36,
++ 40, 44, 48, 52, 56, 60};
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(ecc); i++) {
++ if (*p <= ecc[i]) {
++ if (!i)
++ *p = ecc[i];
++ else if (*p != ecc[i])
++ *p = ecc[i - 1];
++ return;
++ }
++ }
++
++ *p = ecc[ARRAY_SIZE(ecc) - 1];
++}
++EXPORT_SYMBOL(mtk_ecc_update_strength);
++
++static int mtk_ecc_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct mtk_ecc *ecc;
++ struct resource *res;
++ int irq, ret;
++
++ ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL);
++ if (!ecc)
++ return -ENOMEM;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ ecc->regs = devm_ioremap_resource(dev, res);
++ if (IS_ERR(ecc->regs)) {
++ dev_err(dev, "failed to map regs: %ld\n", PTR_ERR(ecc->regs));
++ return PTR_ERR(ecc->regs);
++ }
++
++ ecc->clk = devm_clk_get(dev, NULL);
++ if (IS_ERR(ecc->clk)) {
++ dev_err(dev, "failed to get clock: %ld\n", PTR_ERR(ecc->clk));
++ return PTR_ERR(ecc->clk);
++ }
++
++ irq = platform_get_irq(pdev, 0);
++ if (irq < 0) {
++ dev_err(dev, "failed to get irq\n");
++ return -EINVAL;
++ }
++
++ ret = dma_set_mask(dev, DMA_BIT_MASK(32));
++ if (ret) {
++ dev_err(dev, "failed to set DMA mask\n");
++ return ret;
++ }
++
++ ret = devm_request_irq(dev, irq, mtk_ecc_irq, 0x0, "mtk-ecc", ecc);
++ if (ret) {
++ dev_err(dev, "failed to request irq\n");
++ return -EINVAL;
++ }
++
++ ecc->dev = dev;
++ sema_init(&ecc->sem, 1);
++ platform_set_drvdata(pdev, ecc);
++ dev_info(dev, "probed\n");
++
++ return 0;
++}
++
++#ifdef CONFIG_PM_SLEEP
++static int mtk_ecc_suspend(struct device *dev)
++{
++ struct mtk_ecc *ecc = dev_get_drvdata(dev);
++
++ clk_disable_unprepare(ecc->clk);
++
++ return 0;
++}
++
++static int mtk_ecc_resume(struct device *dev)
++{
++ struct mtk_ecc *ecc = dev_get_drvdata(dev);
++ int ret;
++
++ ret = clk_prepare_enable(ecc->clk);
++ if (ret) {
++ dev_err(dev, "failed to enable clk\n");
++ return ret;
++ }
++
++ mtk_ecc_hw_init(ecc);
++
++ return 0;
++}
++
++static SIMPLE_DEV_PM_OPS(mtk_ecc_pm_ops, mtk_ecc_suspend, mtk_ecc_resume);
++#endif
++
++static const struct of_device_id mtk_ecc_dt_match[] = {
++ { .compatible = "mediatek,mt2701-ecc" },
++ {},
++};
++
++MODULE_DEVICE_TABLE(of, mtk_ecc_dt_match);
++
++static struct platform_driver mtk_ecc_driver = {
++ .probe = mtk_ecc_probe,
++ .driver = {
++ .name = "mtk-ecc",
++ .of_match_table = of_match_ptr(mtk_ecc_dt_match),
++#ifdef CONFIG_PM_SLEEP
++ .pm = &mtk_ecc_pm_ops,
++#endif
++ },
++};
++
++module_platform_driver(mtk_ecc_driver);
++
++MODULE_AUTHOR("Xiaolei Li <xiaolei.li@mediatek.com>");
++MODULE_AUTHOR("Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>");
++MODULE_DESCRIPTION("MTK Nand ECC Driver");
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ b/drivers/mtd/nand/mtk_ecc.h
+@@ -0,0 +1,53 @@
++/*
++ * MTK SDG1 ECC controller
++ *
++ * Copyright (c) 2016 Mediatek
++ * Authors: Xiaolei Li <xiaolei.li@mediatek.com>
++ * Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#ifndef __DRIVERS_MTD_NAND_MTK_ECC_H__
++#define __DRIVERS_MTD_NAND_MTK_ECC_H__
++
++#include <linux/types.h>
++
++#define ECC_PARITY_BITS (14)
++
++enum mtk_ecc_mode {ECC_DMA_MODE = 0, ECC_NFI_MODE = 1};
++enum mtk_ecc_codec {ECC_ENC, ECC_DEC};
++
++struct device_node;
++struct mtk_ecc;
++
++struct mtk_ecc_stats {
++ u32 corrected;
++ u32 bitflips;
++ u32 failed;
++};
++
++struct mtk_ecc_config {
++ enum mtk_ecc_mode ecc_mode;
++ enum mtk_ecc_codec codec;
++ dma_addr_t addr;
++ u32 sec_mask;
++ u32 strength;
++ u32 enc_len;
++ u32 dec_len;
++};
++
++int mtk_ecc_enable(struct mtk_ecc *, struct mtk_ecc_config *);
++void mtk_ecc_disable(struct mtk_ecc *, struct mtk_ecc_config *);
++int mtk_ecc_encode_non_nfi_mode(struct mtk_ecc *, struct mtk_ecc_config *,
++ u8 *, u32);
++void mtk_ecc_get_stats(struct mtk_ecc *, struct mtk_ecc_stats *, int);
++int mtk_ecc_wait_irq_done(struct mtk_ecc *, enum mtk_ecc_codec);
++void mtk_ecc_hw_init(struct mtk_ecc *);
++void mtk_ecc_update_strength(u32 *);
++
++struct mtk_ecc *of_mtk_ecc_get(struct device_node *);
++void mtk_ecc_release(struct mtk_ecc *);
++
++#endif
+--- /dev/null
++++ b/drivers/mtd/nand/mtk_nand.c
+@@ -0,0 +1,1432 @@
++/*
++ * MTK NAND Flash controller driver.
++ * Copyright (C) 2016 MediaTek Inc.
++ * Authors: Xiaolei Li <xiaolei.li@mediatek.com>
++ * Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/platform_device.h>
++#include <linux/dma-mapping.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/clk.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/mtd.h>
++#include <linux/module.h>
++#include <linux/iopoll.h>
++#include <linux/of.h>
++#include "mtk_ecc.h"
++
++/* NAND controller register definition */
++#define NFI_CNFG (0x00)
++#define CNFG_AHB BIT(0)
++#define CNFG_READ_EN BIT(1)
++#define CNFG_DMA_BURST_EN BIT(2)
++#define CNFG_BYTE_RW BIT(6)
++#define CNFG_HW_ECC_EN BIT(8)
++#define CNFG_AUTO_FMT_EN BIT(9)
++#define CNFG_OP_CUST (6 << 12)
++#define NFI_PAGEFMT (0x04)
++#define PAGEFMT_FDM_ECC_SHIFT (12)
++#define PAGEFMT_FDM_SHIFT (8)
++#define PAGEFMT_SPARE_16 (0)
++#define PAGEFMT_SPARE_26 (1)
++#define PAGEFMT_SPARE_27 (2)
++#define PAGEFMT_SPARE_28 (3)
++#define PAGEFMT_SPARE_32 (4)
++#define PAGEFMT_SPARE_36 (5)
++#define PAGEFMT_SPARE_40 (6)
++#define PAGEFMT_SPARE_44 (7)
++#define PAGEFMT_SPARE_48 (8)
++#define PAGEFMT_SPARE_49 (9)
++#define PAGEFMT_SPARE_50 (0xa)
++#define PAGEFMT_SPARE_51 (0xb)
++#define PAGEFMT_SPARE_52 (0xc)
++#define PAGEFMT_SPARE_62 (0xd)
++#define PAGEFMT_SPARE_63 (0xe)
++#define PAGEFMT_SPARE_64 (0xf)
++#define PAGEFMT_SPARE_SHIFT (4)
++#define PAGEFMT_SEC_SEL_512 BIT(2)
++#define PAGEFMT_512_2K (0)
++#define PAGEFMT_2K_4K (1)
++#define PAGEFMT_4K_8K (2)
++#define PAGEFMT_8K_16K (3)
++/* NFI control */
++#define NFI_CON (0x08)
++#define CON_FIFO_FLUSH BIT(0)
++#define CON_NFI_RST BIT(1)
++#define CON_BRD BIT(8) /* burst read */
++#define CON_BWR BIT(9) /* burst write */
++#define CON_SEC_SHIFT (12)
++/* Timming control register */
++#define NFI_ACCCON (0x0C)
++#define NFI_INTR_EN (0x10)
++#define INTR_AHB_DONE_EN BIT(6)
++#define NFI_INTR_STA (0x14)
++#define NFI_CMD (0x20)
++#define NFI_ADDRNOB (0x30)
++#define NFI_COLADDR (0x34)
++#define NFI_ROWADDR (0x38)
++#define NFI_STRDATA (0x40)
++#define STAR_EN (1)
++#define STAR_DE (0)
++#define NFI_CNRNB (0x44)
++#define NFI_DATAW (0x50)
++#define NFI_DATAR (0x54)
++#define NFI_PIO_DIRDY (0x58)
++#define PIO_DI_RDY (0x01)
++#define NFI_STA (0x60)
++#define STA_CMD BIT(0)
++#define STA_ADDR BIT(1)
++#define STA_BUSY BIT(8)
++#define STA_EMP_PAGE BIT(12)
++#define NFI_FSM_CUSTDATA (0xe << 16)
++#define NFI_FSM_MASK (0xf << 16)
++#define NFI_ADDRCNTR (0x70)
++#define CNTR_MASK GENMASK(16, 12)
++#define NFI_STRADDR (0x80)
++#define NFI_BYTELEN (0x84)
++#define NFI_CSEL (0x90)
++#define NFI_FDML(x) (0xA0 + (x) * sizeof(u32) * 2)
++#define NFI_FDMM(x) (0xA4 + (x) * sizeof(u32) * 2)
++#define NFI_FDM_MAX_SIZE (8)
++#define NFI_MASTER_STA (0x224)
++#define MASTER_STA_MASK (0x0FFF)
++#define NFI_EMPTY_THRESH (0x23C)
++
++#define MTK_NAME "mtk-nand"
++#define KB(x) ((x) * 1024UL)
++#define MB(x) (KB(x) * 1024UL)
++
++#define MTK_TIMEOUT (500000)
++#define MTK_RESET_TIMEOUT (1000000)
++#define MTK_MAX_SECTOR (16)
++#define MTK_NAND_MAX_NSELS (2)
++
++typedef void (*bad_mark_swap)(struct mtd_info *, uint8_t *buf, int raw);
++struct mtk_nfc_bad_mark_ctl {
++ bad_mark_swap bm_swap;
++ u32 sec;
++ u32 pos;
++};
++
++/*
++ * FDM: region used to store free OOB data
++ */
++struct mtk_nfc_fdm {
++ u32 reg_size;
++ u32 ecc_size;
++};
++
++struct mtk_nfc_nand_chip {
++ struct list_head node;
++ struct nand_chip nand;
++
++ struct mtk_nfc_bad_mark_ctl bad_mark;
++ struct mtk_nfc_fdm fdm;
++ u32 spare_per_sector;
++
++ int nsels;
++ u8 sels[0];
++ /* nothing after this field */
++};
++
++struct mtk_nfc_clk {
++ struct clk *nfi_clk;
++ struct clk *pad_clk;
++};
++
++struct mtk_nfc {
++ struct nand_hw_control controller;
++ struct mtk_ecc_config ecc_cfg;
++ struct mtk_nfc_clk clk;
++ struct mtk_ecc *ecc;
++
++ struct device *dev;
++ void __iomem *regs;
++
++ struct completion done;
++ struct list_head chips;
++
++ u8 *buffer;
++};
++
++static inline struct mtk_nfc_nand_chip *to_mtk_nand(struct nand_chip *nand)
++{
++ return container_of(nand, struct mtk_nfc_nand_chip, nand);
++}
++
++static inline uint8_t *data_ptr(struct nand_chip *chip, const uint8_t *p, int i)
++{
++ return (uint8_t *) p + i * chip->ecc.size;
++}
++
++static inline uint8_t *oob_ptr(struct nand_chip *chip, int i)
++{
++ struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++ uint8_t *poi;
++
++ if (i < mtk_nand->bad_mark.sec)
++ poi = chip->oob_poi + (i + 1) * mtk_nand->fdm.reg_size;
++ else if (i == mtk_nand->bad_mark.sec)
++ poi = chip->oob_poi;
++ else
++ poi = chip->oob_poi + i * mtk_nand->fdm.reg_size;
++
++ return poi;
++}
++
++static inline int mtk_data_len(struct nand_chip *chip)
++{
++ struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++
++ return chip->ecc.size + mtk_nand->spare_per_sector;
++}
++
++static inline uint8_t *mtk_data_ptr(struct nand_chip *chip, int i)
++{
++ struct mtk_nfc *nfc = nand_get_controller_data(chip);
++
++ return nfc->buffer + i * mtk_data_len(chip);
++}
++
++static inline uint8_t *mtk_oob_ptr(struct nand_chip *chip, int i)
++{
++ struct mtk_nfc *nfc = nand_get_controller_data(chip);
++
++ return nfc->buffer + i * mtk_data_len(chip) + chip->ecc.size;
++}
++
++static inline void nfi_writel(struct mtk_nfc *nfc, u32 val, u32 reg)
++{
++ writel(val, nfc->regs + reg);
++}
++
++static inline void nfi_writew(struct mtk_nfc *nfc, u16 val, u32 reg)
++{
++ writew(val, nfc->regs + reg);
++}
++
++static inline void nfi_writeb(struct mtk_nfc *nfc, u8 val, u32 reg)
++{
++ writeb(val, nfc->regs + reg);
++}
++
++static inline u32 nfi_readl(struct mtk_nfc *nfc, u32 reg)
++{
++ return readl_relaxed(nfc->regs + reg);
++}
++
++static inline u16 nfi_readw(struct mtk_nfc *nfc, u32 reg)
++{
++ return readw_relaxed(nfc->regs + reg);
++}
++
++static inline u8 nfi_readb(struct mtk_nfc *nfc, u32 reg)
++{
++ return readb_relaxed(nfc->regs + reg);
++}
++
++static void mtk_nfc_hw_reset(struct mtk_nfc *nfc)
++{
++ struct device *dev = nfc->dev;
++ u32 val;
++ int ret;
++
++ /* reset all registers and force the NFI master to terminate */
++ nfi_writel(nfc, CON_FIFO_FLUSH | CON_NFI_RST, NFI_CON);
++
++ /* wait for the master to finish the last transaction */
++ ret = readl_poll_timeout(nfc->regs + NFI_MASTER_STA, val,
++ !(val & MASTER_STA_MASK), 50, MTK_RESET_TIMEOUT);
++ if (ret)
++ dev_warn(dev, "master active in reset [0x%x] = 0x%x\n",
++ NFI_MASTER_STA, val);
++
++ /* ensure any status register affected by the NFI master is reset */
++ nfi_writel(nfc, CON_FIFO_FLUSH | CON_NFI_RST, NFI_CON);
++ nfi_writew(nfc, STAR_DE, NFI_STRDATA);
++}
++
++static int mtk_nfc_send_command(struct mtk_nfc *nfc, u8 command)
++{
++ struct device *dev = nfc->dev;
++ u32 val;
++ int ret;
++
++ nfi_writel(nfc, command, NFI_CMD);
++
++ ret = readl_poll_timeout_atomic(nfc->regs + NFI_STA, val,
++ !(val & STA_CMD), 10, MTK_TIMEOUT);
++ if (ret) {
++ dev_warn(dev, "nfi core timed out entering command mode\n");
++ return -EIO;
++ }
++
++ return 0;
++}
++
++static int mtk_nfc_send_address(struct mtk_nfc *nfc, int addr)
++{
++ struct device *dev = nfc->dev;
++ u32 val;
++ int ret;
++
++ nfi_writel(nfc, addr, NFI_COLADDR);
++ nfi_writel(nfc, 0, NFI_ROWADDR);
++ nfi_writew(nfc, 1, NFI_ADDRNOB);
++
++ ret = readl_poll_timeout_atomic(nfc->regs + NFI_STA, val,
++ !(val & STA_ADDR), 10, MTK_TIMEOUT);
++ if (ret) {
++ dev_warn(dev, "nfi core timed out entering address mode\n");
++ return -EIO;
++ }
++
++ return 0;
++}
++
++static int mtk_nfc_hw_runtime_config(struct mtd_info *mtd)
++{
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++ struct mtk_nfc *nfc = nand_get_controller_data(chip);
++ u32 fmt, spare;
++
++ if (!mtd->writesize)
++ return 0;
++
++ spare = mtk_nand->spare_per_sector;
++
++ switch (mtd->writesize) {
++ case 512:
++ fmt = PAGEFMT_512_2K | PAGEFMT_SEC_SEL_512;
++ break;
++ case KB(2):
++ if (chip->ecc.size == 512)
++ fmt = PAGEFMT_2K_4K | PAGEFMT_SEC_SEL_512;
++ else
++ fmt = PAGEFMT_512_2K;
++ break;
++ case KB(4):
++ if (chip->ecc.size == 512)
++ fmt = PAGEFMT_4K_8K | PAGEFMT_SEC_SEL_512;
++ else
++ fmt = PAGEFMT_2K_4K;
++ break;
++ case KB(8):
++ if (chip->ecc.size == 512)
++ fmt = PAGEFMT_8K_16K | PAGEFMT_SEC_SEL_512;
++ else
++ fmt = PAGEFMT_4K_8K;
++ break;
++ case KB(16):
++ fmt = PAGEFMT_8K_16K;
++ break;
++ default:
++ dev_err(nfc->dev, "invalid page len: %d\n", mtd->writesize);
++ return -EINVAL;
++ }
++
++ /* the hardware doubles the value for this eccsize so let's halve it */
++ if (chip->ecc.size == 1024)
++ spare >>= 1;
++
++ switch (spare) {
++ case 16:
++ fmt |= (PAGEFMT_SPARE_16 << PAGEFMT_SPARE_SHIFT);
++ break;
++ case 26:
++ fmt |= (PAGEFMT_SPARE_26 << PAGEFMT_SPARE_SHIFT);
++ break;
++ case 27:
++ fmt |= (PAGEFMT_SPARE_27 << PAGEFMT_SPARE_SHIFT);
++ break;
++ case 28:
++ fmt |= (PAGEFMT_SPARE_28 << PAGEFMT_SPARE_SHIFT);
++ break;
++ case 32:
++ fmt |= (PAGEFMT_SPARE_32 << PAGEFMT_SPARE_SHIFT);
++ break;
++ case 36:
++ fmt |= (PAGEFMT_SPARE_36 << PAGEFMT_SPARE_SHIFT);
++ break;
++ case 40:
++ fmt |= (PAGEFMT_SPARE_40 << PAGEFMT_SPARE_SHIFT);
++ break;
++ case 44:
++ fmt |= (PAGEFMT_SPARE_44 << PAGEFMT_SPARE_SHIFT);
++ break;
++ case 48:
++ fmt |= (PAGEFMT_SPARE_48 << PAGEFMT_SPARE_SHIFT);
++ break;
++ case 49:
++ fmt |= (PAGEFMT_SPARE_49 << PAGEFMT_SPARE_SHIFT);
++ break;
++ case 50:
++ fmt |= (PAGEFMT_SPARE_50 << PAGEFMT_SPARE_SHIFT);
++ break;
++ case 51:
++ fmt |= (PAGEFMT_SPARE_51 << PAGEFMT_SPARE_SHIFT);
++ break;
++ case 52:
++ fmt |= (PAGEFMT_SPARE_52 << PAGEFMT_SPARE_SHIFT);
++ break;
++ case 62:
++ fmt |= (PAGEFMT_SPARE_62 << PAGEFMT_SPARE_SHIFT);
++ break;
++ case 63:
++ fmt |= (PAGEFMT_SPARE_63 << PAGEFMT_SPARE_SHIFT);
++ break;
++ case 64:
++ fmt |= (PAGEFMT_SPARE_64 << PAGEFMT_SPARE_SHIFT);
++ break;
++ default:
++ dev_err(nfc->dev, "invalid spare per sector %d\n", spare);
++ return -EINVAL;
++ }
++
++ fmt |= mtk_nand->fdm.reg_size << PAGEFMT_FDM_SHIFT;
++ fmt |= mtk_nand->fdm.ecc_size << PAGEFMT_FDM_ECC_SHIFT;
++ nfi_writew(nfc, fmt, NFI_PAGEFMT);
++
++ nfc->ecc_cfg.strength = chip->ecc.strength;
++ nfc->ecc_cfg.enc_len = chip->ecc.size + mtk_nand->fdm.ecc_size;
++ nfc->ecc_cfg.dec_len = (nfc->ecc_cfg.enc_len << 3)
++ + chip->ecc.strength * ECC_PARITY_BITS;
++
++ return 0;
++}
++
++static void mtk_nfc_select_chip(struct mtd_info *mtd, int chip)
++{
++ struct nand_chip *nand = mtd_to_nand(mtd);
++ struct mtk_nfc *nfc = nand_get_controller_data(nand);
++ struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(nand);
++
++ if (chip < 0)
++ return;
++
++ mtk_nfc_hw_runtime_config(mtd);
++
++ nfi_writel(nfc, mtk_nand->sels[chip], NFI_CSEL);
++}
++
++static int mtk_nfc_dev_ready(struct mtd_info *mtd)
++{
++ struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
++
++ if (nfi_readl(nfc, NFI_STA) & STA_BUSY)
++ return 0;
++
++ return 1;
++}
++
++static void mtk_nfc_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
++{
++ struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
++
++ if (ctrl & NAND_ALE)
++ mtk_nfc_send_address(nfc, dat);
++ else if (ctrl & NAND_CLE) {
++ mtk_nfc_hw_reset(nfc);
++
++ nfi_writew(nfc, CNFG_OP_CUST, NFI_CNFG);
++ mtk_nfc_send_command(nfc, dat);
++ }
++}
++
++static inline void mtk_nfc_wait_ioready(struct mtk_nfc *nfc)
++{
++ int rc;
++ u8 val;
++
++ rc = readb_poll_timeout_atomic(nfc->regs + NFI_PIO_DIRDY, val,
++ val & PIO_DI_RDY, 10, MTK_TIMEOUT);
++ if (rc < 0)
++ dev_err(nfc->dev, "data not ready\n");
++}
++
++static inline uint8_t mtk_nfc_read_byte(struct mtd_info *mtd)
++{
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct mtk_nfc *nfc = nand_get_controller_data(chip);
++ u32 reg;
++
++ reg = nfi_readl(nfc, NFI_STA) & NFI_FSM_MASK;
++ if (reg != NFI_FSM_CUSTDATA) {
++ reg = nfi_readw(nfc, NFI_CNFG);
++ reg |= CNFG_BYTE_RW | CNFG_READ_EN;
++ nfi_writew(nfc, reg, NFI_CNFG);
++
++ reg = (MTK_MAX_SECTOR << CON_SEC_SHIFT) | CON_BRD;
++ nfi_writel(nfc, reg, NFI_CON);
++
++ /* trigger to fetch data */
++ nfi_writew(nfc, STAR_EN, NFI_STRDATA);
++ }
++
++ mtk_nfc_wait_ioready(nfc);
++
++ return nfi_readb(nfc, NFI_DATAR);
++}
++
++static void mtk_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
++{
++ int i;
++
++ for (i = 0; i < len; i++)
++ buf[i] = mtk_nfc_read_byte(mtd);
++}
++
++static void mtk_nfc_write_byte(struct mtd_info *mtd, uint8_t byte)
++{
++ struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
++ u32 reg;
++
++ reg = nfi_readl(nfc, NFI_STA) & NFI_FSM_MASK;
++
++ if (reg != NFI_FSM_CUSTDATA) {
++ reg = nfi_readw(nfc, NFI_CNFG) | CNFG_BYTE_RW;
++ nfi_writew(nfc, reg, NFI_CNFG);
++
++ reg = MTK_MAX_SECTOR << CON_SEC_SHIFT | CON_BWR;
++ nfi_writel(nfc, reg, NFI_CON);
++
++ nfi_writew(nfc, STAR_EN, NFI_STRDATA);
++ }
++
++ mtk_nfc_wait_ioready(nfc);
++ nfi_writeb(nfc, byte, NFI_DATAW);
++}
++
++static void mtk_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
++{
++ int i;
++
++ for (i = 0; i < len; i++)
++ mtk_nfc_write_byte(mtd, buf[i]);
++}
++
++static int mtk_nfc_sector_encode(struct nand_chip *chip, u8 *data)
++{
++ struct mtk_nfc *nfc = nand_get_controller_data(chip);
++ struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++ int size = chip->ecc.size + mtk_nand->fdm.reg_size;
++
++ nfc->ecc_cfg.ecc_mode = ECC_DMA_MODE;
++ nfc->ecc_cfg.codec = ECC_ENC;
++ return mtk_ecc_encode_non_nfi_mode(nfc->ecc, &nfc->ecc_cfg, data, size);
++}
++
++static void mtk_nfc_no_bad_mark_swap(struct mtd_info *a, uint8_t *b, int c)
++{
++ /* nope */
++}
++
++static void mtk_nfc_bad_mark_swap(struct mtd_info *mtd, uint8_t *buf, int raw)
++{
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct mtk_nfc_nand_chip *nand = to_mtk_nand(chip);
++ u32 bad_pos = nand->bad_mark.pos;
++
++ if (raw)
++ bad_pos += nand->bad_mark.sec * mtk_data_len(chip);
++ else
++ bad_pos += nand->bad_mark.sec * chip->ecc.size;
++
++ swap(chip->oob_poi[0], buf[bad_pos]);
++}
++
++static int mtk_nfc_format_subpage(struct mtd_info *mtd, uint32_t offset,
++ uint32_t len, const uint8_t *buf)
++{
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++ struct mtk_nfc *nfc = nand_get_controller_data(chip);
++ struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
++ u32 start, end;
++ int i, ret;
++
++ start = offset / chip->ecc.size;
++ end = DIV_ROUND_UP(offset + len, chip->ecc.size);
++
++ memset(nfc->buffer, 0xff, mtd->writesize + mtd->oobsize);
++ for (i = 0; i < chip->ecc.steps; i++) {
++
++ memcpy(mtk_data_ptr(chip, i), data_ptr(chip, buf, i),
++ chip->ecc.size);
++
++ if (start > i || i >= end)
++ continue;
++
++ if (i == mtk_nand->bad_mark.sec)
++ mtk_nand->bad_mark.bm_swap(mtd, nfc->buffer, 1);
++
++ memcpy(mtk_oob_ptr(chip, i), oob_ptr(chip, i), fdm->reg_size);
++
++ /* program the CRC back to the OOB */
++ ret = mtk_nfc_sector_encode(chip, mtk_data_ptr(chip, i));
++ if (ret < 0)
++ return ret;
++ }
++
++ return 0;
++}
++
++static void mtk_nfc_format_page(struct mtd_info *mtd, const uint8_t *buf)
++{
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++ struct mtk_nfc *nfc = nand_get_controller_data(chip);
++ struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
++ u32 i;
++
++ memset(nfc->buffer, 0xff, mtd->writesize + mtd->oobsize);
++ for (i = 0; i < chip->ecc.steps; i++) {
++ if (buf)
++ memcpy(mtk_data_ptr(chip, i), data_ptr(chip, buf, i),
++ chip->ecc.size);
++
++ if (i == mtk_nand->bad_mark.sec)
++ mtk_nand->bad_mark.bm_swap(mtd, nfc->buffer, 1);
++
++ memcpy(mtk_oob_ptr(chip, i), oob_ptr(chip, i), fdm->reg_size);
++ }
++}
++
++static inline void mtk_nfc_read_fdm(struct nand_chip *chip, u32 start,
++ u32 sectors)
++{
++ struct mtk_nfc *nfc = nand_get_controller_data(chip);
++ u32 *p;
++ int i;
++
++ for (i = 0; i < sectors; i++) {
++ p = (u32 *) oob_ptr(chip, start + i);
++ p[0] = nfi_readl(nfc, NFI_FDML(i));
++ p[1] = nfi_readl(nfc, NFI_FDMM(i));
++ }
++}
++
++static inline void mtk_nfc_write_fdm(struct nand_chip *chip)
++{
++ struct mtk_nfc *nfc = nand_get_controller_data(chip);
++ u32 *p;
++ int i;
++
++ for (i = 0; i < chip->ecc.steps ; i++) {
++ p = (u32 *) oob_ptr(chip, i);
++ nfi_writel(nfc, p[0], NFI_FDML(i));
++ nfi_writel(nfc, p[1], NFI_FDMM(i));
++ }
++}
++
++static int mtk_nfc_do_write_page(struct mtd_info *mtd, struct nand_chip *chip,
++ const uint8_t *buf, int page, int len)
++{
++
++ struct mtk_nfc *nfc = nand_get_controller_data(chip);
++ struct device *dev = nfc->dev;
++ dma_addr_t addr;
++ u32 reg;
++ int ret;
++
++ addr = dma_map_single(dev, (void *) buf, len, DMA_TO_DEVICE);
++ ret = dma_mapping_error(nfc->dev, addr);
++ if (ret) {
++ dev_err(nfc->dev, "dma mapping error\n");
++ return -EINVAL;
++ }
++
++ reg = nfi_readw(nfc, NFI_CNFG) | CNFG_AHB | CNFG_DMA_BURST_EN;
++ nfi_writew(nfc, reg, NFI_CNFG);
++
++ nfi_writel(nfc, chip->ecc.steps << CON_SEC_SHIFT, NFI_CON);
++ nfi_writel(nfc, lower_32_bits(addr), NFI_STRADDR);
++ nfi_writew(nfc, INTR_AHB_DONE_EN, NFI_INTR_EN);
++
++ init_completion(&nfc->done);
++
++ reg = nfi_readl(nfc, NFI_CON) | CON_BWR;
++ nfi_writel(nfc, reg, NFI_CON);
++ nfi_writew(nfc, STAR_EN, NFI_STRDATA);
++
++ ret = wait_for_completion_timeout(&nfc->done, msecs_to_jiffies(500));
++ if (!ret) {
++ dev_err(dev, "program ahb done timeout\n");
++ nfi_writew(nfc, 0, NFI_INTR_EN);
++ ret = -ETIMEDOUT;
++ goto timeout;
++ }
++
++ ret = readl_poll_timeout_atomic(nfc->regs + NFI_ADDRCNTR, reg,
++ (reg & CNTR_MASK) >= chip->ecc.steps, 10, MTK_TIMEOUT);
++ if (ret)
++ dev_err(dev, "hwecc write timeout\n");
++
++timeout:
++
++ dma_unmap_single(nfc->dev, addr, len, DMA_TO_DEVICE);
++ nfi_writel(nfc, 0, NFI_CON);
++
++ return ret;
++}
++
++static int mtk_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
++ const uint8_t *buf, int page, int raw)
++{
++ struct mtk_nfc *nfc = nand_get_controller_data(chip);
++ struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++ size_t len;
++ const u8 *bufpoi;
++ u32 reg;
++ int ret;
++
++ if (!raw) {
++ /* OOB => FDM: from register, ECC: from HW */
++ reg = nfi_readw(nfc, NFI_CNFG) | CNFG_AUTO_FMT_EN;
++ nfi_writew(nfc, reg | CNFG_HW_ECC_EN, NFI_CNFG);
++
++ nfc->ecc_cfg.codec = ECC_ENC;
++ nfc->ecc_cfg.ecc_mode = ECC_NFI_MODE;
++ ret = mtk_ecc_enable(nfc->ecc, &nfc->ecc_cfg);
++ if (ret) {
++ /* clear NFI config */
++ reg = nfi_readw(nfc, NFI_CNFG);
++ reg &= ~(CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN);
++ nfi_writew(nfc, reg, NFI_CNFG);
++
++ return ret;
++ }
++
++ memcpy(nfc->buffer, buf, mtd->writesize);
++ mtk_nand->bad_mark.bm_swap(mtd, nfc->buffer, raw);
++ bufpoi = nfc->buffer;
++
++ /* write OOB into the FDM registers (OOB area in MTK NAND) */
++ mtk_nfc_write_fdm(chip);
++ } else
++ bufpoi = buf;
++
++ len = mtd->writesize + (raw ? mtd->oobsize : 0);
++ ret = mtk_nfc_do_write_page(mtd, chip, bufpoi, page, len);
++
++ if (!raw)
++ mtk_ecc_disable(nfc->ecc, &nfc->ecc_cfg);
++
++ return ret;
++}
++
++static int mtk_nfc_write_page_hwecc(struct mtd_info *mtd,
++ struct nand_chip *chip, const uint8_t *buf, int oob_on, int page)
++{
++ return mtk_nfc_write_page(mtd, chip, buf, page, 0);
++}
++
++static int mtk_nfc_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
++ const uint8_t *buf, int oob_on, int pg)
++{
++ struct mtk_nfc *nfc = nand_get_controller_data(chip);
++
++ mtk_nfc_format_page(mtd, buf);
++ return mtk_nfc_write_page(mtd, chip, nfc->buffer, pg, 1);
++}
++
++static int mtk_nfc_write_subpage_hwecc(struct mtd_info *mtd,
++ struct nand_chip *chip, uint32_t offset, uint32_t data_len,
++ const uint8_t *buf, int oob_on, int page)
++{
++ struct mtk_nfc *nfc = nand_get_controller_data(chip);
++ int ret;
++
++ ret = mtk_nfc_format_subpage(mtd, offset, data_len, buf);
++ if (ret < 0)
++ return ret;
++
++ /* use the data in the private buffer (now with FDM and CRC) */
++ return mtk_nfc_write_page(mtd, chip, nfc->buffer, page, 1);
++}
++
++static int mtk_nfc_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
++ int page)
++{
++ int ret;
++
++ chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
++
++ ret = mtk_nfc_write_page_raw(mtd, chip, NULL, 1, page);
++ if (ret < 0)
++ return -EIO;
++
++ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
++ ret = chip->waitfunc(mtd, chip);
++
++ return ret & NAND_STATUS_FAIL ? -EIO : 0;
++}
++
++static int mtk_nfc_update_ecc_stats(struct mtd_info *mtd, u8 *buf, u32 sectors)
++{
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct mtk_nfc *nfc = nand_get_controller_data(chip);
++ struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++ struct mtk_ecc_stats stats;
++ int rc, i;
++
++ rc = nfi_readl(nfc, NFI_STA) & STA_EMP_PAGE;
++ if (rc) {
++ memset(buf, 0xff, sectors * chip->ecc.size);
++ for (i = 0; i < sectors; i++)
++ memset(oob_ptr(chip, i), 0xff, mtk_nand->fdm.reg_size);
++ return 0;
++ }
++
++ mtk_ecc_get_stats(nfc->ecc, &stats, sectors);
++ mtd->ecc_stats.corrected += stats.corrected;
++ mtd->ecc_stats.failed += stats.failed;
++
++ return stats.bitflips;
++}
++
++static int mtk_nfc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
++ uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi,
++ int page, int raw)
++{
++ struct mtk_nfc *nfc = nand_get_controller_data(chip);
++ struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++ u32 spare = mtk_nand->spare_per_sector;
++ u32 column, sectors, start, end, reg;
++ dma_addr_t addr;
++ int bitflips;
++ size_t len;
++ u8 *buf;
++ int rc;
++
++ start = data_offs / chip->ecc.size;
++ end = DIV_ROUND_UP(data_offs + readlen, chip->ecc.size);
++
++ sectors = end - start;
++ column = start * (chip->ecc.size + spare);
++
++ len = sectors * chip->ecc.size + (raw ? sectors * spare : 0);
++ buf = bufpoi + start * chip->ecc.size;
++
++ if (column != 0)
++ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, column, -1);
++
++ addr = dma_map_single(nfc->dev, buf, len, DMA_FROM_DEVICE);
++ rc = dma_mapping_error(nfc->dev, addr);
++ if (rc) {
++ dev_err(nfc->dev, "dma mapping error\n");
++
++ return -EINVAL;
++ }
++
++ reg = nfi_readw(nfc, NFI_CNFG);
++ reg |= CNFG_READ_EN | CNFG_DMA_BURST_EN | CNFG_AHB;
++ if (!raw) {
++ reg |= CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN;
++ nfi_writew(nfc, reg, NFI_CNFG);
++
++ nfc->ecc_cfg.ecc_mode = ECC_NFI_MODE;
++ nfc->ecc_cfg.sec_mask = sectors;
++ nfc->ecc_cfg.codec = ECC_DEC;
++ rc = mtk_ecc_enable(nfc->ecc, &nfc->ecc_cfg);
++ if (rc) {
++ dev_err(nfc->dev, "ecc enable\n");
++ /* clear NFI_CNFG */
++ reg &= ~(CNFG_DMA_BURST_EN | CNFG_AHB | CNFG_READ_EN |
++ CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN);
++ nfi_writew(nfc, reg, NFI_CNFG);
++ dma_unmap_single(nfc->dev, addr, len, DMA_FROM_DEVICE);
++
++ return rc;
++ }
++ } else
++ nfi_writew(nfc, reg, NFI_CNFG);
++
++ nfi_writel(nfc, sectors << CON_SEC_SHIFT, NFI_CON);
++ nfi_writew(nfc, INTR_AHB_DONE_EN, NFI_INTR_EN);
++ nfi_writel(nfc, lower_32_bits(addr), NFI_STRADDR);
++
++ init_completion(&nfc->done);
++ reg = nfi_readl(nfc, NFI_CON) | CON_BRD;
++ nfi_writel(nfc, reg, NFI_CON);
++ nfi_writew(nfc, STAR_EN, NFI_STRDATA);
++
++ rc = wait_for_completion_timeout(&nfc->done, msecs_to_jiffies(500));
++ if (!rc)
++ dev_warn(nfc->dev, "read ahb/dma done timeout\n");
++
++ rc = readl_poll_timeout_atomic(nfc->regs + NFI_BYTELEN, reg,
++ (reg & CNTR_MASK) >= sectors, 10, MTK_TIMEOUT);
++ if (rc < 0) {
++ dev_err(nfc->dev, "subpage done timeout\n");
++ bitflips = -EIO;
++ } else {
++ bitflips = 0;
++ if (!raw) {
++ rc = mtk_ecc_wait_irq_done(nfc->ecc, ECC_DEC);
++ bitflips = rc < 0 ? -ETIMEDOUT :
++ mtk_nfc_update_ecc_stats(mtd, buf, sectors);
++ mtk_nfc_read_fdm(chip, start, sectors);
++ }
++ }
++
++ dma_unmap_single(nfc->dev, addr, len, DMA_FROM_DEVICE);
++
++ if (raw)
++ goto done;
++
++ mtk_ecc_disable(nfc->ecc, &nfc->ecc_cfg);
++
++ if (clamp(mtk_nand->bad_mark.sec, start, end) == mtk_nand->bad_mark.sec)
++ mtk_nand->bad_mark.bm_swap(mtd, bufpoi, raw);
++done:
++ nfi_writel(nfc, 0, NFI_CON);
++
++ return bitflips;
++}
++
++static int mtk_nfc_read_subpage_hwecc(struct mtd_info *mtd,
++ struct nand_chip *chip, uint32_t off, uint32_t len, uint8_t *p, int pg)
++{
++ return mtk_nfc_read_subpage(mtd, chip, off, len, p, pg, 0);
++}
++
++static int mtk_nfc_read_page_hwecc(struct mtd_info *mtd,
++ struct nand_chip *chip, uint8_t *p, int oob_on, int pg)
++{
++ return mtk_nfc_read_subpage(mtd, chip, 0, mtd->writesize, p, pg, 0);
++}
++
++static int mtk_nfc_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
++ uint8_t *buf, int oob_on, int page)
++{
++ struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++ struct mtk_nfc *nfc = nand_get_controller_data(chip);
++ struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
++ int i, ret;
++
++ memset(nfc->buffer, 0xff, mtd->writesize + mtd->oobsize);
++ ret = mtk_nfc_read_subpage(mtd, chip, 0, mtd->writesize, nfc->buffer,
++ page, 1);
++ if (ret < 0)
++ return ret;
++
++ for (i = 0; i < chip->ecc.steps; i++) {
++ memcpy(oob_ptr(chip, i), mtk_oob_ptr(chip, i), fdm->reg_size);
++ if (i == mtk_nand->bad_mark.sec)
++ mtk_nand->bad_mark.bm_swap(mtd, nfc->buffer, 1);
++
++ if (buf)
++ memcpy(data_ptr(chip, buf, i), mtk_data_ptr(chip, i),
++ chip->ecc.size);
++ }
++
++ return ret;
++}
++
++static int mtk_nfc_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
++ int page)
++{
++ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
++
++ return mtk_nfc_read_page_raw(mtd, chip, NULL, 1, page);
++}
++
++static inline void mtk_nfc_hw_init(struct mtk_nfc *nfc)
++{
++ nfi_writel(nfc, 0x10804211, NFI_ACCCON);
++ nfi_writew(nfc, 0xf1, NFI_CNRNB);
++ nfi_writew(nfc, PAGEFMT_8K_16K, NFI_PAGEFMT);
++
++ mtk_nfc_hw_reset(nfc);
++
++ nfi_readl(nfc, NFI_INTR_STA);
++ nfi_writel(nfc, 0, NFI_INTR_EN);
++}
++
++static irqreturn_t mtk_nfc_irq(int irq, void *id)
++{
++ struct mtk_nfc *nfc = id;
++ u16 sta, ien;
++
++ sta = nfi_readw(nfc, NFI_INTR_STA);
++ ien = nfi_readw(nfc, NFI_INTR_EN);
++
++ if (!(sta & ien))
++ return IRQ_NONE;
++
++ nfi_writew(nfc, ~sta & ien, NFI_INTR_EN);
++ complete(&nfc->done);
++
++ return IRQ_HANDLED;
++}
++
++static int mtk_nfc_enable_clk(struct device *dev, struct mtk_nfc_clk *clk)
++{
++ int ret;
++
++ ret = clk_prepare_enable(clk->nfi_clk);
++ if (ret) {
++ dev_err(dev, "failed to enable nfi clk\n");
++ return ret;
++ }
++
++ ret = clk_prepare_enable(clk->pad_clk);
++ if (ret) {
++ dev_err(dev, "failed to enable pad clk\n");
++ clk_disable_unprepare(clk->nfi_clk);
++ return ret;
++ }
++
++ return 0;
++}
++
++static void mtk_nfc_disable_clk(struct mtk_nfc_clk *clk)
++{
++ clk_disable_unprepare(clk->nfi_clk);
++ clk_disable_unprepare(clk->pad_clk);
++}
++
++static int mtk_nfc_ooblayout_free(struct mtd_info *mtd, int section,
++ struct mtd_oob_region *oob_region)
++{
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++ struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
++ u32 eccsteps;
++
++ eccsteps = mtd->writesize / chip->ecc.size;
++
++ if (section >= eccsteps)
++ return -ERANGE;
++
++ oob_region->length = fdm->reg_size - fdm->ecc_size;
++ oob_region->offset = section * fdm->reg_size + fdm->ecc_size;
++
++ return 0;
++}
++
++static int mtk_nfc_ooblayout_ecc(struct mtd_info *mtd, int section,
++ struct mtd_oob_region *oob_region)
++{
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++ u32 eccsteps;
++
++ if (section)
++ return -ERANGE;
++
++ eccsteps = mtd->writesize / chip->ecc.size;
++ oob_region->offset = mtk_nand->fdm.reg_size * eccsteps;
++ oob_region->length = mtd->oobsize - oob_region->offset;
++
++ return 0;
++}
++
++static const struct mtd_ooblayout_ops mtk_nfc_ooblayout_ops = {
++ .free = mtk_nfc_ooblayout_free,
++ .ecc = mtk_nfc_ooblayout_ecc,
++};
++
++static void mtk_nfc_set_fdm(struct mtk_nfc_fdm *fdm, struct mtd_info *mtd)
++{
++ struct nand_chip *nand = mtd_to_nand(mtd);
++ struct mtk_nfc_nand_chip *chip = to_mtk_nand(nand);
++ u32 ecc_bytes;
++
++ ecc_bytes = DIV_ROUND_UP(nand->ecc.strength * ECC_PARITY_BITS, 8);
++
++ fdm->reg_size = chip->spare_per_sector - ecc_bytes;
++ if (fdm->reg_size > NFI_FDM_MAX_SIZE)
++ fdm->reg_size = NFI_FDM_MAX_SIZE;
++
++ /* bad block mark storage */
++ fdm->ecc_size = 1;
++}
++
++static void mtk_nfc_set_bad_mark_ctl(struct mtk_nfc_bad_mark_ctl *bm_ctl,
++ struct mtd_info *mtd)
++{
++ struct nand_chip *nand = mtd_to_nand(mtd);
++
++ if (mtd->writesize == 512)
++ bm_ctl->bm_swap = mtk_nfc_no_bad_mark_swap;
++ else {
++ bm_ctl->bm_swap = mtk_nfc_bad_mark_swap;
++ bm_ctl->sec = mtd->writesize / mtk_data_len(nand);
++ bm_ctl->pos = mtd->writesize % mtk_data_len(nand);
++ }
++}
++
++static void mtk_nfc_set_spare_per_sector(u32 *sps, struct mtd_info *mtd)
++{
++ struct nand_chip *nand = mtd_to_nand(mtd);
++ u32 spare[] = {16, 26, 27, 28, 32, 36, 40, 44,
++ 48, 49, 50, 51, 52, 62, 63, 64};
++ u32 eccsteps, i;
++
++ eccsteps = mtd->writesize / nand->ecc.size;
++ *sps = mtd->oobsize / eccsteps;
++
++ if (nand->ecc.size == 1024)
++ *sps >>= 1;
++
++ for (i = 0; i < ARRAY_SIZE(spare); i++) {
++ if (*sps <= spare[i]) {
++ if (!i)
++ *sps = spare[i];
++ else if (*sps != spare[i])
++ *sps = spare[i - 1];
++ break;
++ }
++ }
++
++ if (i >= ARRAY_SIZE(spare))
++ *sps = spare[ARRAY_SIZE(spare) - 1];
++
++ if (nand->ecc.size == 1024)
++ *sps <<= 1;
++}
++
++static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
++{
++ struct nand_chip *nand = mtd_to_nand(mtd);
++ u32 spare;
++
++ /* support only ecc hw mode */
++ if (nand->ecc.mode != NAND_ECC_HW) {
++ dev_err(dev, "ecc.mode not supported\n");
++ return -EINVAL;
++ }
++
++ /* if optional DT settings are not present */
++ if (!nand->ecc.size || !nand->ecc.strength) {
++
++ /* controller only supports sizes 512 and 1024 */
++ nand->ecc.size = (mtd->writesize > 512) ? 1024 : 512;
++
++ /* get controller valid values */
++ mtk_nfc_set_spare_per_sector(&spare, mtd);
++ spare = spare - NFI_FDM_MAX_SIZE;
++ nand->ecc.strength = (spare << 3) / ECC_PARITY_BITS;
++ }
++
++ mtk_ecc_update_strength(&nand->ecc.strength);
++
++ dev_info(dev, "eccsize %d eccstrength %d\n",
++ nand->ecc.size, nand->ecc.strength);
++
++ return 0;
++}
++
++static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
++ struct device_node *np)
++{
++ struct mtk_nfc_nand_chip *chip;
++ struct nand_chip *nand;
++ struct mtd_info *mtd;
++ int nsels, len;
++ u32 tmp;
++ int ret;
++ int i;
++
++ if (!of_get_property(np, "reg", &nsels))
++ return -ENODEV;
++
++ nsels /= sizeof(u32);
++ if (!nsels || nsels > MTK_NAND_MAX_NSELS) {
++ dev_err(dev, "invalid reg property size %d\n", nsels);
++ return -EINVAL;
++ }
++
++ chip = devm_kzalloc(dev,
++ sizeof(*chip) + nsels * sizeof(u8), GFP_KERNEL);
++ if (!chip)
++ return -ENOMEM;
++
++ chip->nsels = nsels;
++ for (i = 0; i < nsels; i++) {
++ ret = of_property_read_u32_index(np, "reg", i, &tmp);
++ if (ret) {
++ dev_err(dev, "reg property failure : %d\n", ret);
++ return ret;
++ }
++ chip->sels[i] = tmp;
++ }
++
++ nand = &chip->nand;
++ nand->controller = &nfc->controller;
++
++ nand_set_flash_node(nand, np);
++ nand_set_controller_data(nand, nfc);
++
++ nand->options |= NAND_USE_BOUNCE_BUFFER | NAND_SUBPAGE_READ;
++ nand->dev_ready = mtk_nfc_dev_ready;
++ nand->select_chip = mtk_nfc_select_chip;
++ nand->write_byte = mtk_nfc_write_byte;
++ nand->write_buf = mtk_nfc_write_buf;
++ nand->read_byte = mtk_nfc_read_byte;
++ nand->read_buf = mtk_nfc_read_buf;
++ nand->cmd_ctrl = mtk_nfc_cmd_ctrl;
++
++ /* set default mode in case dt entry is missing */
++ nand->ecc.mode = NAND_ECC_HW;
++
++ nand->ecc.write_subpage = mtk_nfc_write_subpage_hwecc;
++ nand->ecc.write_page_raw = mtk_nfc_write_page_raw;
++ nand->ecc.write_page = mtk_nfc_write_page_hwecc;
++ nand->ecc.write_oob_raw = mtk_nfc_write_oob_std;
++ nand->ecc.write_oob = mtk_nfc_write_oob_std;
++
++ nand->ecc.read_subpage = mtk_nfc_read_subpage_hwecc;
++ nand->ecc.read_page_raw = mtk_nfc_read_page_raw;
++ nand->ecc.read_page = mtk_nfc_read_page_hwecc;
++ nand->ecc.read_oob_raw = mtk_nfc_read_oob_std;
++ nand->ecc.read_oob = mtk_nfc_read_oob_std;
++
++ mtd = nand_to_mtd(nand);
++ mtd->owner = THIS_MODULE;
++ mtd->dev.parent = dev;
++ mtd->name = MTK_NAME;
++ mtd_set_ooblayout(mtd, &mtk_nfc_ooblayout_ops);
++
++ mtk_nfc_hw_init(nfc);
++
++ ret = nand_scan_ident(mtd, nsels, NULL);
++ if (ret)
++ return -ENODEV;
++
++ /* store bbt magic in page, cause OOB is not protected */
++ if (nand->bbt_options & NAND_BBT_USE_FLASH)
++ nand->bbt_options |= NAND_BBT_NO_OOB;
++
++ ret = mtk_nfc_ecc_init(dev, mtd);
++ if (ret)
++ return -EINVAL;
++
++ mtk_nfc_set_spare_per_sector(&chip->spare_per_sector, mtd);
++ mtk_nfc_set_fdm(&chip->fdm, mtd);
++ mtk_nfc_set_bad_mark_ctl(&chip->bad_mark, mtd);
++
++ len = mtd->writesize + mtd->oobsize;
++ nfc->buffer = devm_kzalloc(dev, len, GFP_KERNEL);
++ if (!nfc->buffer)
++ return -ENOMEM;
++
++ ret = nand_scan_tail(mtd);
++ if (ret)
++ return -ENODEV;
++
++ ret = mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
++ if (ret) {
++ dev_err(dev, "mtd parse partition error\n");
++ nand_release(mtd);
++ return ret;
++ }
++
++ list_add_tail(&chip->node, &nfc->chips);
++
++ return 0;
++}
++
++static int mtk_nfc_nand_chips_init(struct device *dev, struct mtk_nfc *nfc)
++{
++ struct device_node *np = dev->of_node;
++ struct device_node *nand_np;
++ int ret;
++
++ for_each_child_of_node(np, nand_np) {
++ ret = mtk_nfc_nand_chip_init(dev, nfc, nand_np);
++ if (ret) {
++ of_node_put(nand_np);
++ return ret;
++ }
++ }
++
++ return 0;
++}
++
++static int mtk_nfc_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct device_node *np = dev->of_node;
++ struct mtk_nfc *nfc;
++ struct resource *res;
++ int ret, irq;
++
++ nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
++ if (!nfc)
++ return -ENOMEM;
++
++ spin_lock_init(&nfc->controller.lock);
++ init_waitqueue_head(&nfc->controller.wq);
++ INIT_LIST_HEAD(&nfc->chips);
++
++ /* probe defer if not ready */
++ nfc->ecc = of_mtk_ecc_get(np);
++ if (IS_ERR(nfc->ecc))
++ return PTR_ERR(nfc->ecc);
++ else if (!nfc->ecc)
++ return -ENODEV;
++
++ nfc->dev = dev;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ nfc->regs = devm_ioremap_resource(dev, res);
++ if (IS_ERR(nfc->regs)) {
++ ret = PTR_ERR(nfc->regs);
++ dev_err(dev, "no nfi base\n");
++ goto release_ecc;
++ }
++
++ nfc->clk.nfi_clk = devm_clk_get(dev, "nfi_clk");
++ if (IS_ERR(nfc->clk.nfi_clk)) {
++ dev_err(dev, "no clk\n");
++ ret = PTR_ERR(nfc->clk.nfi_clk);
++ goto release_ecc;
++ }
++
++ nfc->clk.pad_clk = devm_clk_get(dev, "pad_clk");
++ if (IS_ERR(nfc->clk.pad_clk)) {
++ dev_err(dev, "no pad clk\n");
++ ret = PTR_ERR(nfc->clk.pad_clk);
++ goto release_ecc;
++ }
++
++ ret = mtk_nfc_enable_clk(dev, &nfc->clk);
++ if (ret)
++ goto release_ecc;
++
++ irq = platform_get_irq(pdev, 0);
++ if (irq < 0) {
++ dev_err(dev, "no nfi irq resource\n");
++ ret = -EINVAL;
++ goto clk_disable;
++ }
++
++ ret = devm_request_irq(dev, irq, mtk_nfc_irq, 0x0, "mtk-nand", nfc);
++ if (ret) {
++ dev_err(dev, "failed to request nfi irq\n");
++ goto clk_disable;
++ }
++
++ ret = dma_set_mask(dev, DMA_BIT_MASK(32));
++ if (ret) {
++ dev_err(dev, "failed to set dma mask\n");
++ goto clk_disable;
++ }
++
++ platform_set_drvdata(pdev, nfc);
++
++ ret = mtk_nfc_nand_chips_init(dev, nfc);
++ if (ret) {
++ dev_err(dev, "failed to init nand chips\n");
++ goto clk_disable;
++ }
++
++ return 0;
++
++clk_disable:
++ mtk_nfc_disable_clk(&nfc->clk);
++
++release_ecc:
++ mtk_ecc_release(nfc->ecc);
++
++ return ret;
++}
++
++static int mtk_nfc_remove(struct platform_device *pdev)
++{
++ struct mtk_nfc *nfc = platform_get_drvdata(pdev);
++ struct mtk_nfc_nand_chip *chip;
++
++ while (!list_empty(&nfc->chips)) {
++ chip = list_first_entry(&nfc->chips, struct mtk_nfc_nand_chip,
++ node);
++ nand_release(nand_to_mtd(&chip->nand));
++ list_del(&chip->node);
++ }
++
++ mtk_ecc_release(nfc->ecc);
++ mtk_nfc_disable_clk(&nfc->clk);
++
++ return 0;
++}
++
++#ifdef CONFIG_PM_SLEEP
++static int mtk_nfc_suspend(struct device *dev)
++{
++ struct mtk_nfc *nfc = dev_get_drvdata(dev);
++
++ mtk_nfc_disable_clk(&nfc->clk);
++
++ return 0;
++}
++
++static int mtk_nfc_resume(struct device *dev)
++{
++ struct mtk_nfc *nfc = dev_get_drvdata(dev);
++ struct mtk_nfc_nand_chip *chip;
++ struct nand_chip *nand;
++ struct mtd_info *mtd;
++ int ret;
++ u32 i;
++
++ udelay(200);
++
++ ret = mtk_nfc_enable_clk(dev, &nfc->clk);
++ if (ret)
++ return ret;
++
++ mtk_nfc_hw_init(nfc);
++
++ list_for_each_entry(chip, &nfc->chips, node) {
++ nand = &chip->nand;
++ mtd = nand_to_mtd(nand);
++ for (i = 0; i < chip->nsels; i++) {
++ nand->select_chip(mtd, i);
++ nand->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
++ }
++ }
++
++ return 0;
++}
++static SIMPLE_DEV_PM_OPS(mtk_nfc_pm_ops, mtk_nfc_suspend, mtk_nfc_resume);
++#endif
++
++static const struct of_device_id mtk_nfc_id_table[] = {
++ { .compatible = "mediatek,mt2701-nfc" },
++ {}
++};
++MODULE_DEVICE_TABLE(of, mtk_nfc_id_table);
++
++static struct platform_driver mtk_nfc_driver = {
++ .probe = mtk_nfc_probe,
++ .remove = mtk_nfc_remove,
++ .driver = {
++ .name = MTK_NAME,
++ .of_match_table = mtk_nfc_id_table,
++#ifdef CONFIG_PM_SLEEP
++ .pm = &mtk_nfc_pm_ops,
++#endif
++ },
++};
++
++module_platform_driver(mtk_nfc_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Xiaolei Li <xiaolei.li@mediatek.com>");
++MODULE_AUTHOR("Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>");
++MODULE_DESCRIPTION("MTK Nand Flash Controller Driver");
diff --git a/target/linux/mediatek/patches-4.4/0075-net-mediatek-fix-TX-locking.patch b/target/linux/mediatek/patches-4.4/0075-net-mediatek-fix-TX-locking.patch
deleted file mode 100644
index 0c68499827..0000000000
--- a/target/linux/mediatek/patches-4.4/0075-net-mediatek-fix-TX-locking.patch
+++ /dev/null
@@ -1,98 +0,0 @@
-From 506c56fe0c3986c13fbca474ee91b061fbc850ca Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Tue, 29 Mar 2016 17:20:01 +0200
-Subject: [PATCH 75/91] net: mediatek: fix TX locking
-
-Inside the TX path there is a lock inside the tx_map function. This is
-however too late. The patch moves the lock to the start of the xmit
-function right before the free count check of the DMA ring happens.
-If we do not do this, the code becomes racy leading to TX stalls and
-dropped packets. This happens as there are 2 netdevs running on the
-same physical DMA ring.
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 20 ++++++++++----------
- 1 file changed, 10 insertions(+), 10 deletions(-)
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 26eeb1a..67b18f9 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -536,7 +536,6 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev,
- struct mtk_eth *eth = mac->hw;
- struct mtk_tx_dma *itxd, *txd;
- struct mtk_tx_buf *tx_buf;
-- unsigned long flags;
- dma_addr_t mapped_addr;
- unsigned int nr_frags;
- int i, n_desc = 1;
-@@ -568,11 +567,6 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev,
- if (unlikely(dma_mapping_error(&dev->dev, mapped_addr)))
- return -ENOMEM;
-
-- /* normally we can rely on the stack not calling this more than once,
-- * however we have 2 queues running ont he same ring so we need to lock
-- * the ring access
-- */
-- spin_lock_irqsave(&eth->page_lock, flags);
- WRITE_ONCE(itxd->txd1, mapped_addr);
- tx_buf->flags |= MTK_TX_FLAGS_SINGLE0;
- dma_unmap_addr_set(tx_buf, dma_addr0, mapped_addr);
-@@ -632,8 +626,6 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev,
- WRITE_ONCE(itxd->txd3, (TX_DMA_SWC | TX_DMA_PLEN0(skb_headlen(skb)) |
- (!nr_frags * TX_DMA_LS0)));
-
-- spin_unlock_irqrestore(&eth->page_lock, flags);
--
- netdev_sent_queue(dev, skb->len);
- skb_tx_timestamp(skb);
-
-@@ -661,8 +653,6 @@ err_dma:
- itxd = mtk_qdma_phys_to_virt(ring, itxd->txd2);
- } while (itxd != txd);
-
-- spin_unlock_irqrestore(&eth->page_lock, flags);
--
- return -ENOMEM;
- }
-
-@@ -712,14 +702,22 @@ static int mtk_start_xmit(struct sk_buff *skb, struct net_device *dev)
- struct mtk_eth *eth = mac->hw;
- struct mtk_tx_ring *ring = &eth->tx_ring;
- struct net_device_stats *stats = &dev->stats;
-+ unsigned long flags;
- bool gso = false;
- int tx_num;
-
-+ /* normally we can rely on the stack not calling this more than once,
-+ * however we have 2 queues running ont he same ring so we need to lock
-+ * the ring access
-+ */
-+ spin_lock_irqsave(&eth->page_lock, flags);
-+
- tx_num = mtk_cal_txd_req(skb);
- if (unlikely(atomic_read(&ring->free_count) <= tx_num)) {
- mtk_stop_queue(eth);
- netif_err(eth, tx_queued, dev,
- "Tx Ring full when queue awake!\n");
-+ spin_unlock_irqrestore(&eth->page_lock, flags);
- return NETDEV_TX_BUSY;
- }
-
-@@ -747,10 +745,12 @@ static int mtk_start_xmit(struct sk_buff *skb, struct net_device *dev)
- ring->thresh))
- mtk_wake_queue(eth);
- }
-+ spin_unlock_irqrestore(&eth->page_lock, flags);
-
- return NETDEV_TX_OK;
-
- drop:
-+ spin_unlock_irqrestore(&eth->page_lock, flags);
- stats->tx_dropped++;
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0076-mtd-nand-add-power-domains-to-the-mediatek-driver.patch b/target/linux/mediatek/patches-4.4/0076-mtd-nand-add-power-domains-to-the-mediatek-driver.patch
new file mode 100644
index 0000000000..7702246a4c
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0076-mtd-nand-add-power-domains-to-the-mediatek-driver.patch
@@ -0,0 +1,67 @@
+From 5dc0d474396e04e6c140d71f0e113eb1c03501c5 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Tue, 17 May 2016 05:44:10 +0200
+Subject: [PATCH 076/102] mtd: nand: add power domains to the mediatek driver
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/mtd/nand/mtk_nand.c | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+--- a/drivers/mtd/nand/mtk_nand.c
++++ b/drivers/mtd/nand/mtk_nand.c
+@@ -16,6 +16,7 @@
+
+ #include <linux/platform_device.h>
+ #include <linux/dma-mapping.h>
++#include <linux/pm_runtime.h>
+ #include <linux/interrupt.h>
+ #include <linux/delay.h>
+ #include <linux/clk.h>
+@@ -102,6 +103,7 @@
+ #define NFI_MASTER_STA (0x224)
+ #define MASTER_STA_MASK (0x0FFF)
+ #define NFI_EMPTY_THRESH (0x23C)
++#define NFI_ACCCON1 (0x244)
+
+ #define MTK_NAME "mtk-nand"
+ #define KB(x) ((x) * 1024UL)
+@@ -539,6 +541,8 @@ static void mtk_nfc_bad_mark_swap(struct
+ struct mtk_nfc_nand_chip *nand = to_mtk_nand(chip);
+ u32 bad_pos = nand->bad_mark.pos;
+
++ return;
++
+ if (raw)
+ bad_pos += nand->bad_mark.sec * mtk_data_len(chip);
+ else
+@@ -946,7 +950,8 @@ static int mtk_nfc_read_oob_std(struct m
+
+ static inline void mtk_nfc_hw_init(struct mtk_nfc *nfc)
+ {
+- nfi_writel(nfc, 0x10804211, NFI_ACCCON);
++ nfi_writel(nfc, 0x30c77fff, NFI_ACCCON);
++ nfi_writel(nfc, 0xC03222, NFI_ACCCON1);
+ nfi_writew(nfc, 0xf1, NFI_CNRNB);
+ nfi_writew(nfc, PAGEFMT_8K_16K, NFI_PAGEFMT);
+
+@@ -1328,6 +1333,9 @@ static int mtk_nfc_probe(struct platform
+ goto clk_disable;
+ }
+
++ pm_runtime_enable(dev);
++ pm_runtime_get_sync(dev);
++
+ platform_set_drvdata(pdev, nfc);
+
+ ret = mtk_nfc_nand_chips_init(dev, nfc);
+@@ -1362,6 +1370,9 @@ static int mtk_nfc_remove(struct platfor
+ mtk_ecc_release(nfc->ecc);
+ mtk_nfc_disable_clk(&nfc->clk);
+
++ pm_runtime_put_sync(&pdev->dev);
++ pm_runtime_disable(&pdev->dev);
++
+ return 0;
+ }
+
diff --git a/target/linux/mediatek/patches-4.4/0076-net-mediatek-move-the-pending_work-struct-to-the-dev.patch b/target/linux/mediatek/patches-4.4/0076-net-mediatek-move-the-pending_work-struct-to-the-dev.patch
deleted file mode 100644
index 4dd0d45b0e..0000000000
--- a/target/linux/mediatek/patches-4.4/0076-net-mediatek-move-the-pending_work-struct-to-the-dev.patch
+++ /dev/null
@@ -1,109 +0,0 @@
-From d42de6ec9325c29d0f59c5df74a5cbceb00ddd9d Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Tue, 29 Mar 2016 17:24:24 +0200
-Subject: [PATCH 76/91] net: mediatek: move the pending_work struct to the
- device generic struct
-
-The worker always touches both netdevs. It is ethernet core and not MAC
-specific. We only need one worker, which belongs into the ethernets core struct.
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 10 ++++------
- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 4 ++--
- 2 files changed, 6 insertions(+), 8 deletions(-)
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 67b18f9..bbcd607 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -1193,7 +1193,7 @@ static void mtk_tx_timeout(struct net_device *dev)
- eth->netdev[mac->id]->stats.tx_errors++;
- netif_err(eth, tx_err, dev,
- "transmit timed out\n");
-- schedule_work(&mac->pending_work);
-+ schedule_work(&eth->pending_work);
- }
-
- static irqreturn_t mtk_handle_irq(int irq, void *_eth)
-@@ -1438,7 +1438,7 @@ static void mtk_pending_work(struct work_struct *work)
-
- /* stop all devices to make sure that dma is properly shut down */
- for (i = 0; i < MTK_MAC_COUNT; i++) {
-- if (!netif_oper_up(eth->netdev[i]))
-+ if (!eth->netdev[i])
- continue;
- mtk_stop(eth->netdev[i]);
- __set_bit(i, &restart);
-@@ -1464,15 +1464,13 @@ static int mtk_cleanup(struct mtk_eth *eth)
- int i;
-
- for (i = 0; i < MTK_MAC_COUNT; i++) {
-- struct mtk_mac *mac = netdev_priv(eth->netdev[i]);
--
- if (!eth->netdev[i])
- continue;
-
- unregister_netdev(eth->netdev[i]);
- free_netdev(eth->netdev[i]);
-- cancel_work_sync(&mac->pending_work);
- }
-+ cancel_work_sync(&eth->pending_work);
-
- return 0;
- }
-@@ -1660,7 +1658,6 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
- mac->id = id;
- mac->hw = eth;
- mac->of_node = np;
-- INIT_WORK(&mac->pending_work, mtk_pending_work);
-
- mac->hw_stats = devm_kzalloc(eth->dev,
- sizeof(*mac->hw_stats),
-@@ -1762,6 +1759,7 @@ static int mtk_probe(struct platform_device *pdev)
-
- eth->dev = &pdev->dev;
- eth->msg_enable = netif_msg_init(mtk_msg_level, MTK_DEFAULT_MSG_ENABLE);
-+ INIT_WORK(&eth->pending_work, mtk_pending_work);
-
- err = mtk_hw_init(eth);
- if (err)
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index 48a5292..eed626d 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -363,6 +363,7 @@ struct mtk_rx_ring {
- * @clk_gp1: The gmac1 clock
- * @clk_gp2: The gmac2 clock
- * @mii_bus: If there is a bus we need to create an instance for it
-+ * @pending_work: The workqueue used to reset the dma ring
- */
-
- struct mtk_eth {
-@@ -389,6 +390,7 @@ struct mtk_eth {
- struct clk *clk_gp1;
- struct clk *clk_gp2;
- struct mii_bus *mii_bus;
-+ struct work_struct pending_work;
- };
-
- /* struct mtk_mac - the structure that holds the info about the MACs of the
-@@ -398,7 +400,6 @@ struct mtk_eth {
- * @hw: Backpointer to our main datastruture
- * @hw_stats: Packet statistics counter
- * @phy_dev: The attached PHY if available
-- * @pending_work: The workqueue used to reset the dma ring
- */
- struct mtk_mac {
- int id;
-@@ -406,7 +407,6 @@ struct mtk_mac {
- struct mtk_eth *hw;
- struct mtk_hw_stats *hw_stats;
- struct phy_device *phy_dev;
-- struct work_struct pending_work;
- };
-
- /* the struct describing the SoC. these are declared in the soc_xyz.c files */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0077-net-mediatek-do-not-set-the-QID-field-in-the-TX-DMA-.patch b/target/linux/mediatek/patches-4.4/0077-net-mediatek-do-not-set-the-QID-field-in-the-TX-DMA-.patch
deleted file mode 100644
index 1038faf5c1..0000000000
--- a/target/linux/mediatek/patches-4.4/0077-net-mediatek-do-not-set-the-QID-field-in-the-TX-DMA-.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-From 2675e2a40d78c55fc2d578ec71cc990170cacc42 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Thu, 7 Apr 2016 17:36:23 +0200
-Subject: [PATCH 77/91] net: mediatek: do not set the QID field in the TX DMA
- descriptors
-
-The QID field gets set to the mac id. This made the DMA linked list queue
-the traffic of each MAC on a different internal queue. However during long
-term testing we found that this will cause traffic stalls as the multi
-queue setup requires a more complete initialisation which is not part of
-the upstream driver yet.
-
-This patch removes the code setting the QID field, resulting in all
-traffic ending up in queue 0 which works without any special setup.
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 3 +--
- 1 file changed, 1 insertion(+), 2 deletions(-)
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index bbcd607..bab5d45 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -603,8 +603,7 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev,
- WRITE_ONCE(txd->txd1, mapped_addr);
- WRITE_ONCE(txd->txd3, (TX_DMA_SWC |
- TX_DMA_PLEN0(frag_map_size) |
-- last_frag * TX_DMA_LS0) |
-- mac->id);
-+ last_frag * TX_DMA_LS0));
- WRITE_ONCE(txd->txd4, 0);
-
- tx_buf->skb = (struct sk_buff *)MTK_DMA_DUMMY_DESC;
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0077-net-next-mediatek-use-mdiobus_free-in-favour-of-kfre.patch b/target/linux/mediatek/patches-4.4/0077-net-next-mediatek-use-mdiobus_free-in-favour-of-kfre.patch
new file mode 100644
index 0000000000..c2fe21825c
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0077-net-next-mediatek-use-mdiobus_free-in-favour-of-kfre.patch
@@ -0,0 +1,36 @@
+From b1c85818c3fb00022dc125bb62d657d3fd3cf49c Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Sat, 7 May 2016 06:31:08 +0200
+Subject: [PATCH 077/102] net-next: mediatek: use mdiobus_free() in favour of
+ kfree()
+
+The driver currently uses kfree() to clear the mii_bus. This is not the
+correct way to clear the memory and mdiobus_free() should be used instead.
+This patch fixes the two instances where this happens in the driver.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -280,7 +280,7 @@ static int mtk_mdio_init(struct mtk_eth
+ return 0;
+
+ err_free_bus:
+- kfree(eth->mii_bus);
++ mdiobus_free(eth->mii_bus);
+
+ err_put_node:
+ of_node_put(mii_np);
+@@ -295,7 +295,7 @@ static void mtk_mdio_cleanup(struct mtk_
+
+ mdiobus_unregister(eth->mii_bus);
+ of_node_put(eth->mii_bus->dev.of_node);
+- kfree(eth->mii_bus);
++ mdiobus_free(eth->mii_bus);
+ }
+
+ static inline void mtk_irq_disable(struct mtk_eth *eth, u32 mask)
diff --git a/target/linux/mediatek/patches-4.4/0078-net-mediatek-update-the-IRQ-part-of-the-binding-docu.patch b/target/linux/mediatek/patches-4.4/0078-net-mediatek-update-the-IRQ-part-of-the-binding-docu.patch
deleted file mode 100644
index 8104ef2872..0000000000
--- a/target/linux/mediatek/patches-4.4/0078-net-mediatek-update-the-IRQ-part-of-the-binding-docu.patch
+++ /dev/null
@@ -1,46 +0,0 @@
-From 289e6b23aa394126f50048f673ac266686bbf65e Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Tue, 29 Mar 2016 14:32:07 +0200
-Subject: [PATCH 78/91] net: mediatek: update the IRQ part of the binding
- document
-
-The current binding document only describes a single interrupt. Update the
-document by adding the 2 other interrupts.
-
-The driver currently only uses a single interrupt. The HW is however able
-to using IRQ grouping to split TX and RX onto separate GIC irqs.
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
- Acked-by: Rob Herring <robh@kernel.org>
----
- Documentation/devicetree/bindings/net/mediatek-net.txt | 7 +++++--
- 1 file changed, 5 insertions(+), 2 deletions(-)
-
-diff --git a/Documentation/devicetree/bindings/net/mediatek-net.txt b/Documentation/devicetree/bindings/net/mediatek-net.txt
-index 5ca7929..32eaaca 100644
---- a/Documentation/devicetree/bindings/net/mediatek-net.txt
-+++ b/Documentation/devicetree/bindings/net/mediatek-net.txt
-@@ -9,7 +9,8 @@ have dual GMAC each represented by a child node..
- Required properties:
- - compatible: Should be "mediatek,mt7623-eth"
- - reg: Address and length of the register set for the device
--- interrupts: Should contain the frame engines interrupt
-+- interrupts: Should contain the three frame engines interrupts in numeric
-+ order. These are fe_int0, fe_int1 and fe_int2.
- - clocks: the clock used by the core
- - clock-names: the names of the clock listed in the clocks property. These are
- "ethif", "esw", "gp2", "gp1"
-@@ -42,7 +43,9 @@ eth: ethernet@1b100000 {
- <&ethsys CLK_ETHSYS_GP2>,
- <&ethsys CLK_ETHSYS_GP1>;
- clock-names = "ethif", "esw", "gp2", "gp1";
-- interrupts = <GIC_SPI 200 IRQ_TYPE_LEVEL_LOW>;
-+ interrupts = <GIC_SPI 200 IRQ_TYPE_LEVEL_LOW
-+ GIC_SPI 199 IRQ_TYPE_LEVEL_LOW
-+ GIC_SPI 198 IRQ_TYPE_LEVEL_LOW>;
- power-domains = <&scpsys MT2701_POWER_DOMAIN_ETH>;
- resets = <&ethsys MT2701_ETHSYS_ETH_RST>;
- reset-names = "eth";
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0078-net-next-mediatek-fix-gigabit-and-flow-control-adver.patch b/target/linux/mediatek/patches-4.4/0078-net-next-mediatek-fix-gigabit-and-flow-control-adver.patch
new file mode 100644
index 0000000000..42adb9e786
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0078-net-next-mediatek-fix-gigabit-and-flow-control-adver.patch
@@ -0,0 +1,71 @@
+From 09313f26999e2685e0b9434374e7308e1f447e55 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Fri, 22 Apr 2016 11:05:23 +0200
+Subject: [PATCH 078/102] net-next: mediatek: fix gigabit and flow control
+ advertisement
+
+The current code will not setup the PHYs advertisement features correctly.
+Fix this and properly advertise Gigabit features and properly handle
+asymmetric pause frames.
+
+Signed-off-by: Sean Wang <keyhaede@gmail.com>
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 30 +++++++++++++++++++++++----
+ 1 file changed, 26 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -133,6 +133,8 @@ static int mtk_mdio_read(struct mii_bus
+ static void mtk_phy_link_adjust(struct net_device *dev)
+ {
+ struct mtk_mac *mac = netdev_priv(dev);
++ u16 lcl_adv = 0, rmt_adv = 0;
++ u8 flowctrl;
+ u32 mcr = MAC_MCR_MAX_RX_1536 | MAC_MCR_IPG_CFG |
+ MAC_MCR_FORCE_MODE | MAC_MCR_TX_EN |
+ MAC_MCR_RX_EN | MAC_MCR_BACKOFF_EN |
+@@ -150,11 +152,30 @@ static void mtk_phy_link_adjust(struct n
+ if (mac->phy_dev->link)
+ mcr |= MAC_MCR_FORCE_LINK;
+
+- if (mac->phy_dev->duplex)
++ if (mac->phy_dev->duplex) {
+ mcr |= MAC_MCR_FORCE_DPX;
+
+- if (mac->phy_dev->pause)
+- mcr |= MAC_MCR_FORCE_RX_FC | MAC_MCR_FORCE_TX_FC;
++ if (mac->phy_dev->pause)
++ rmt_adv = LPA_PAUSE_CAP;
++ if (mac->phy_dev->asym_pause)
++ rmt_adv |= LPA_PAUSE_ASYM;
++
++ if (mac->phy_dev->advertising & ADVERTISED_Pause)
++ lcl_adv |= ADVERTISE_PAUSE_CAP;
++ if (mac->phy_dev->advertising & ADVERTISED_Asym_Pause)
++ lcl_adv |= ADVERTISE_PAUSE_ASYM;
++
++ flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
++
++ if (flowctrl & FLOW_CTRL_TX)
++ mcr |= MAC_MCR_FORCE_TX_FC;
++ if (flowctrl & FLOW_CTRL_RX)
++ mcr |= MAC_MCR_FORCE_RX_FC;
++
++ netif_dbg(mac->hw, link, dev, "rx pause %s, tx pause %s\n",
++ flowctrl & FLOW_CTRL_RX ? "enabled" : "disabled",
++ flowctrl & FLOW_CTRL_TX ? "enabled" : "disabled");
++ }
+
+ mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id));
+
+@@ -236,7 +257,8 @@ static int mtk_phy_connect(struct mtk_ma
+ mac->phy_dev->autoneg = AUTONEG_ENABLE;
+ mac->phy_dev->speed = 0;
+ mac->phy_dev->duplex = 0;
+- mac->phy_dev->supported &= PHY_BASIC_FEATURES;
++ mac->phy_dev->supported &= PHY_GBIT_FEATURES | SUPPORTED_Pause |
++ SUPPORTED_Asym_Pause;
+ mac->phy_dev->advertising = mac->phy_dev->supported |
+ ADVERTISED_Autoneg;
+ phy_start_aneg(mac->phy_dev);
diff --git a/target/linux/mediatek/patches-4.4/0079-net-next-mediatek-add-fixed-phy-support.patch b/target/linux/mediatek/patches-4.4/0079-net-next-mediatek-add-fixed-phy-support.patch
new file mode 100644
index 0000000000..669febbdf1
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0079-net-next-mediatek-add-fixed-phy-support.patch
@@ -0,0 +1,38 @@
+From 09f0b50ae838bd6e2bbf0aa22de9f352122297de Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Fri, 22 Apr 2016 11:06:03 +0200
+Subject: [PATCH 079/102] net-next: mediatek: add fixed-phy support
+
+The MT7623 SoC has a builtin gigabit switch. If we want to use it, GMAC1
+needs to be configured using a fixed link speed and flow control settings.
+The easiest way to do this is to used the fixed-phy driver, allowing us to
+reuse the existing mdio polling code to setup the MAC.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -229,6 +229,9 @@ static int mtk_phy_connect(struct mtk_ma
+ u32 val, ge_mode;
+
+ np = of_parse_phandle(mac->of_node, "phy-handle", 0);
++ if (!np && of_phy_is_fixed_link(mac->of_node))
++ if (!of_phy_register_fixed_link(mac->of_node))
++ np = of_node_get(mac->of_node);
+ if (!np)
+ return -ENODEV;
+
+@@ -257,6 +260,9 @@ static int mtk_phy_connect(struct mtk_ma
+ mac->phy_dev->autoneg = AUTONEG_ENABLE;
+ mac->phy_dev->speed = 0;
+ mac->phy_dev->duplex = 0;
++ if (of_phy_is_fixed_link(mac->of_node))
++ mac->phy_dev->supported |= SUPPORTED_Pause |
++ SUPPORTED_Asym_Pause;
+ mac->phy_dev->supported &= PHY_GBIT_FEATURES | SUPPORTED_Pause |
+ SUPPORTED_Asym_Pause;
+ mac->phy_dev->advertising = mac->phy_dev->supported |
diff --git a/target/linux/mediatek/patches-4.4/0079-net-next-mediatek-fix-BQL-support.patch b/target/linux/mediatek/patches-4.4/0079-net-next-mediatek-fix-BQL-support.patch
deleted file mode 100644
index a4d42d324a..0000000000
--- a/target/linux/mediatek/patches-4.4/0079-net-next-mediatek-fix-BQL-support.patch
+++ /dev/null
@@ -1,89 +0,0 @@
-From f26f228f312fafc090d21036b682bd1062bb731f Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Sat, 23 Apr 2016 11:57:21 +0200
-Subject: [PATCH 79/91] net-next: mediatek: fix BQL support
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 33 ++++++++++++++++-----------
- 1 file changed, 20 insertions(+), 13 deletions(-)
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index bab5d45..9928a79 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -625,7 +625,16 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev,
- WRITE_ONCE(itxd->txd3, (TX_DMA_SWC | TX_DMA_PLEN0(skb_headlen(skb)) |
- (!nr_frags * TX_DMA_LS0)));
-
-- netdev_sent_queue(dev, skb->len);
-+ /* we have a single DMA ring so BQL needs to be updated for all devices
-+ * sitting on this ring
-+ */
-+ for (i = 0; i < MTK_MAC_COUNT; i++) {
-+ if (!eth->netdev[i])
-+ continue;
-+
-+ netdev_sent_queue(eth->netdev[i], skb->len);
-+ }
-+
- skb_tx_timestamp(skb);
-
- ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2);
-@@ -853,21 +862,18 @@ static int mtk_poll_tx(struct mtk_eth *eth, int budget, bool *tx_again)
- struct mtk_tx_dma *desc;
- struct sk_buff *skb;
- struct mtk_tx_buf *tx_buf;
-- int total = 0, done[MTK_MAX_DEVS];
-- unsigned int bytes[MTK_MAX_DEVS];
-+ int total = 0, done = 0;
-+ unsigned int bytes = 0;
- u32 cpu, dma;
- static int condition;
- int i;
-
-- memset(done, 0, sizeof(done));
-- memset(bytes, 0, sizeof(bytes));
--
- cpu = mtk_r32(eth, MTK_QTX_CRX_PTR);
- dma = mtk_r32(eth, MTK_QTX_DRX_PTR);
-
- desc = mtk_qdma_phys_to_virt(ring, cpu);
-
-- while ((cpu != dma) && budget) {
-+ while ((cpu != dma) && done < budget) {
- u32 next_cpu = desc->txd2;
- int mac;
-
-@@ -887,9 +893,8 @@ static int mtk_poll_tx(struct mtk_eth *eth, int budget, bool *tx_again)
- }
-
- if (skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC) {
-- bytes[mac] += skb->len;
-- done[mac]++;
-- budget--;
-+ bytes += skb->len;
-+ done++;
- }
- mtk_tx_unmap(eth->dev, tx_buf);
-
-@@ -902,11 +907,13 @@ static int mtk_poll_tx(struct mtk_eth *eth, int budget, bool *tx_again)
-
- mtk_w32(eth, cpu, MTK_QTX_CRX_PTR);
-
-+ /* we have a single DMA ring so BQL needs to be updated for all devices
-+ * sitting on this ring
-+ */
- for (i = 0; i < MTK_MAC_COUNT; i++) {
-- if (!eth->netdev[i] || !done[i])
-+ if (!eth->netdev[i])
- continue;
-- netdev_completed_queue(eth->netdev[i], done[i], bytes[i]);
-- total += done[i];
-+ netdev_completed_queue(eth->netdev[i], done, bytes);
- }
-
- /* read hw index again make sure no new tx packet */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0080-net-next-mediatek-fix-gigabit-and-flow-control-adver.patch b/target/linux/mediatek/patches-4.4/0080-net-next-mediatek-fix-gigabit-and-flow-control-adver.patch
deleted file mode 100644
index facbbf2937..0000000000
--- a/target/linux/mediatek/patches-4.4/0080-net-next-mediatek-fix-gigabit-and-flow-control-adver.patch
+++ /dev/null
@@ -1,59 +0,0 @@
-From 6918f290a9019425043dbedf7b39bc82a69e23a6 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Fri, 22 Apr 2016 11:05:23 +0200
-Subject: [PATCH 80/91] net-next: mediatek: fix gigabit and flow control
- advertisement
-
-The current code will not setup the PHYs advertisement features correctly.
-Fix this and properly advertise Gigabit features and properly handle
-asymmetric pause frames.
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 16 ++++++++++++++--
- 1 file changed, 14 insertions(+), 2 deletions(-)
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 9928a79..204d927 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -133,6 +133,8 @@ static int mtk_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg)
- static void mtk_phy_link_adjust(struct net_device *dev)
- {
- struct mtk_mac *mac = netdev_priv(dev);
-+ u16 lcl_adv, rmt_adv = 0;
-+ u8 flowctrl;
- u32 mcr = MAC_MCR_MAX_RX_1536 | MAC_MCR_IPG_CFG |
- MAC_MCR_FORCE_MODE | MAC_MCR_TX_EN |
- MAC_MCR_RX_EN | MAC_MCR_BACKOFF_EN |
-@@ -154,7 +156,16 @@ static void mtk_phy_link_adjust(struct net_device *dev)
- mcr |= MAC_MCR_FORCE_DPX;
-
- if (mac->phy_dev->pause)
-- mcr |= MAC_MCR_FORCE_RX_FC | MAC_MCR_FORCE_TX_FC;
-+ rmt_adv = LPA_PAUSE_CAP;
-+ if (mac->phy_dev->asym_pause)
-+ rmt_adv |= LPA_PAUSE_ASYM;
-+
-+ lcl_adv = mii_advertise_flowctrl(FLOW_CTRL_RX | FLOW_CTRL_TX);
-+ flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
-+ if (flowctrl & FLOW_CTRL_TX)
-+ mcr |= MAC_MCR_FORCE_TX_FC;
-+ if (flowctrl & FLOW_CTRL_RX)
-+ mcr |= MAC_MCR_FORCE_RX_FC;
-
- mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id));
-
-@@ -236,7 +247,8 @@ static int mtk_phy_connect(struct mtk_mac *mac)
- mac->phy_dev->autoneg = AUTONEG_ENABLE;
- mac->phy_dev->speed = 0;
- mac->phy_dev->duplex = 0;
-- mac->phy_dev->supported &= PHY_BASIC_FEATURES;
-+ mac->phy_dev->supported &= PHY_GBIT_FEATURES | SUPPORTED_Pause |
-+ ~SUPPORTED_Asym_Pause;
- mac->phy_dev->advertising = mac->phy_dev->supported |
- ADVERTISED_Autoneg;
- phy_start_aneg(mac->phy_dev);
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0080-net-next-mediatek-properly-handle-RGMII-modes.patch b/target/linux/mediatek/patches-4.4/0080-net-next-mediatek-properly-handle-RGMII-modes.patch
new file mode 100644
index 0000000000..1d176f2ece
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0080-net-next-mediatek-properly-handle-RGMII-modes.patch
@@ -0,0 +1,31 @@
+From 25eaa5d6483a5899e6bf48b47f762f05c186b4b6 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Fri, 22 Apr 2016 11:08:43 +0200
+Subject: [PATCH 080/102] net-next: mediatek: properly handle RGMII modes
+
+If an external Gigabit PHY is connected to either of the MACs we need to
+be able to tell the PHY to use a delay. Not doing so will result in heavy
+packet loss and/or data corruption when using PHYs such as the IC+ IP1001.
+We tell the PHY which MII delay mode to use via the devictree.
+
+The ethernet driver needs to be adapted to handle all 3 rgmii-*id modes
+in the same way as normal rgmii when setting up the MAC.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -236,6 +236,9 @@ static int mtk_phy_connect(struct mtk_ma
+ return -ENODEV;
+
+ switch (of_get_phy_mode(np)) {
++ case PHY_INTERFACE_MODE_RGMII_TXID:
++ case PHY_INTERFACE_MODE_RGMII_RXID:
++ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII:
+ ge_mode = 0;
+ break;
diff --git a/target/linux/mediatek/patches-4.4/0081-net-next-mediatek-add-fixed-phy-support.patch b/target/linux/mediatek/patches-4.4/0081-net-next-mediatek-add-fixed-phy-support.patch
deleted file mode 100644
index bc6349568a..0000000000
--- a/target/linux/mediatek/patches-4.4/0081-net-next-mediatek-add-fixed-phy-support.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-From b5ecc24a027dea24f3ff798f87f65dd42015b342 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Fri, 22 Apr 2016 11:06:03 +0200
-Subject: [PATCH 81/91] net-next: mediatek: add fixed-phy support
-
-The MT7623 SoC has a builtin gigabit switch. If we want to use it, GMAC1
-needs to be configured using a fixed link speed and flow control settings.
-The easiest way to do this is to used the fixed-phy driver, allowing us to
-reuse the existing mdio polling code to setup the MAC.
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 3 +++
- 1 file changed, 3 insertions(+)
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 204d927..f4d8519 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -219,6 +219,9 @@ static int mtk_phy_connect(struct mtk_mac *mac)
- u32 val, ge_mode;
-
- np = of_parse_phandle(mac->of_node, "phy-handle", 0);
-+ if (!np && of_phy_is_fixed_link(mac->of_node))
-+ if (!of_phy_register_fixed_link(mac->of_node))
-+ np = of_node_get(mac->of_node);
- if (!np)
- return -ENODEV;
-
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0081-net-next-mediatek-fix-DQL-support.patch b/target/linux/mediatek/patches-4.4/0081-net-next-mediatek-fix-DQL-support.patch
new file mode 100644
index 0000000000..f1c7290aac
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0081-net-next-mediatek-fix-DQL-support.patch
@@ -0,0 +1,92 @@
+From 81cdbda2a08375b9d5915567d2210bf2433e7332 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Sat, 23 Apr 2016 11:57:21 +0200
+Subject: [PATCH 081/102] net-next: mediatek: fix DQL support
+
+The MTK ethernet core has 2 MACs both sitting on the same DMA ring. The
+current code will assign the TX traffic of each MAC to its own DQL. This
+results in the amount of data, that DQL says is in the queue incorrect. As
+the data from multiple devices is infact enqueued. This makes any decision
+based on these value non deterministic. Fix this by tracking all TX
+traffic, regardless of the MAC it belongs to in the DQL of all devices
+using the DMA.
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 33 ++++++++++++++++-----------
+ 1 file changed, 20 insertions(+), 13 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -656,7 +656,16 @@ static int mtk_tx_map(struct sk_buff *sk
+ WRITE_ONCE(itxd->txd3, (TX_DMA_SWC | TX_DMA_PLEN0(skb_headlen(skb)) |
+ (!nr_frags * TX_DMA_LS0)));
+
+- netdev_sent_queue(dev, skb->len);
++ /* we have a single DMA ring so BQL needs to be updated for all devices
++ * sitting on this ring
++ */
++ for (i = 0; i < MTK_MAC_COUNT; i++) {
++ if (!eth->netdev[i])
++ continue;
++
++ netdev_sent_queue(eth->netdev[i], skb->len);
++ }
++
+ skb_tx_timestamp(skb);
+
+ ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2);
+@@ -884,21 +893,18 @@ static int mtk_poll_tx(struct mtk_eth *e
+ struct mtk_tx_dma *desc;
+ struct sk_buff *skb;
+ struct mtk_tx_buf *tx_buf;
+- int total = 0, done[MTK_MAX_DEVS];
+- unsigned int bytes[MTK_MAX_DEVS];
++ int total = 0, done = 0;
++ unsigned int bytes = 0;
+ u32 cpu, dma;
+ static int condition;
+ int i;
+
+- memset(done, 0, sizeof(done));
+- memset(bytes, 0, sizeof(bytes));
+-
+ cpu = mtk_r32(eth, MTK_QTX_CRX_PTR);
+ dma = mtk_r32(eth, MTK_QTX_DRX_PTR);
+
+ desc = mtk_qdma_phys_to_virt(ring, cpu);
+
+- while ((cpu != dma) && budget) {
++ while ((cpu != dma) && done < budget) {
+ u32 next_cpu = desc->txd2;
+ int mac;
+
+@@ -918,9 +924,8 @@ static int mtk_poll_tx(struct mtk_eth *e
+ }
+
+ if (skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC) {
+- bytes[mac] += skb->len;
+- done[mac]++;
+- budget--;
++ bytes += skb->len;
++ done++;
+ }
+ mtk_tx_unmap(eth->dev, tx_buf);
+
+@@ -933,11 +938,13 @@ static int mtk_poll_tx(struct mtk_eth *e
+
+ mtk_w32(eth, cpu, MTK_QTX_CRX_PTR);
+
++ /* we have a single DMA ring so BQL needs to be updated for all devices
++ * sitting on this ring
++ */
+ for (i = 0; i < MTK_MAC_COUNT; i++) {
+- if (!eth->netdev[i] || !done[i])
++ if (!eth->netdev[i])
+ continue;
+- netdev_completed_queue(eth->netdev[i], done[i], bytes[i]);
+- total += done[i];
++ netdev_completed_queue(eth->netdev[i], done, bytes);
+ }
+
+ /* read hw index again make sure no new tx packet */
diff --git a/target/linux/mediatek/patches-4.4/0082-net-next-mediatek-add-RX-delay-support.patch b/target/linux/mediatek/patches-4.4/0082-net-next-mediatek-add-RX-delay-support.patch
deleted file mode 100644
index ad49fd9352..0000000000
--- a/target/linux/mediatek/patches-4.4/0082-net-next-mediatek-add-RX-delay-support.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-From bbd92ed51c48a4586f149767841a5495cbc5a979 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Fri, 22 Apr 2016 11:08:43 +0200
-Subject: [PATCH 82/91] net-next: mediatek: add RX delay support
-
-If an external Gigabit PHY is connected to either of the MACs we need to
-tell the to use a RX delay. Not doing so will result in heavy packet loss
-and/or data corruption of RX traffic.
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index f4d8519..aa25788 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -226,6 +226,7 @@ static int mtk_phy_connect(struct mtk_mac *mac)
- return -ENODEV;
-
- switch (of_get_phy_mode(np)) {
-+ case PHY_INTERFACE_MODE_RGMII_RXID:
- case PHY_INTERFACE_MODE_RGMII:
- ge_mode = 0;
- break;
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0082-net-next-mediatek-add-missing-return-code-check.patch b/target/linux/mediatek/patches-4.4/0082-net-next-mediatek-add-missing-return-code-check.patch
new file mode 100644
index 0000000000..19cdbf0d3e
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0082-net-next-mediatek-add-missing-return-code-check.patch
@@ -0,0 +1,26 @@
+From 51ca1e9f141499fd7c95bff5401215b706656754 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Sat, 23 Apr 2016 09:06:05 +0200
+Subject: [PATCH 082/102] net-next: mediatek: add missing return code check
+
+The code fails to check if the scratch memory was properly allocated. Add
+this check and return with an error if the allocation failed.
+
+Signed-off-by: Sean Wang <keyhaede@gmail.com>
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -498,6 +498,9 @@ static int mtk_init_fq_dma(struct mtk_et
+
+ eth->scratch_head = kcalloc(cnt, MTK_QDMA_PAGE_SIZE,
+ GFP_KERNEL);
++ if (unlikely(!eth->scratch_head))
++ return -ENOMEM;
++
+ dma_addr = dma_map_single(eth->dev,
+ eth->scratch_head, cnt * MTK_QDMA_PAGE_SIZE,
+ DMA_FROM_DEVICE);
diff --git a/target/linux/mediatek/patches-4.4/0083-net-next-mediatek-add-missing-return-code-check.patch b/target/linux/mediatek/patches-4.4/0083-net-next-mediatek-add-missing-return-code-check.patch
deleted file mode 100644
index 652001ecf9..0000000000
--- a/target/linux/mediatek/patches-4.4/0083-net-next-mediatek-add-missing-return-code-check.patch
+++ /dev/null
@@ -1,30 +0,0 @@
-From d20b45f50d6b3352aa7be76eb7a28cffcfe379da Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Sat, 23 Apr 2016 09:06:05 +0200
-Subject: [PATCH 83/91] net-next: mediatek: add missing return code check
-
-The code fails to check if the scratch memory was properly allocated. Add
-this check and return with an error if the allocation failed.
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 3 +++
- 1 file changed, 3 insertions(+)
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index aa25788..e58a634 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -483,6 +483,9 @@ static int mtk_init_fq_dma(struct mtk_eth *eth)
-
- eth->scratch_head = kcalloc(cnt, MTK_QDMA_PAGE_SIZE,
- GFP_KERNEL);
-+ if (unlikely(!eth->scratch_head))
-+ return -ENOMEM;
-+
- dma_addr = dma_map_single(eth->dev,
- eth->scratch_head, cnt * MTK_QDMA_PAGE_SIZE,
- DMA_FROM_DEVICE);
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0083-net-next-mediatek-fix-missing-free-of-scratch-memory.patch b/target/linux/mediatek/patches-4.4/0083-net-next-mediatek-fix-missing-free-of-scratch-memory.patch
new file mode 100644
index 0000000000..793875faf4
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0083-net-next-mediatek-fix-missing-free-of-scratch-memory.patch
@@ -0,0 +1,92 @@
+From b48745c534ced06005d2ba57198b54a6a160b39d Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Sat, 23 Apr 2016 09:18:28 +0200
+Subject: [PATCH 083/102] net-next: mediatek: fix missing free of scratch
+ memory
+
+Scratch memory gets allocated in mtk_init_fq_dma() but the corresponding
+code to free it is missing inside mtk_dma_free() causing a memory leak.
+With this patch applied, we can run ifconfig/up/down several thousand
+times without any problems.
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 18 +++++++++++++-----
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h | 2 ++
+ 2 files changed, 15 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -484,14 +484,14 @@ static inline void mtk_rx_get_desc(struc
+ /* the qdma core needs scratch memory to be setup */
+ static int mtk_init_fq_dma(struct mtk_eth *eth)
+ {
+- dma_addr_t phy_ring_head, phy_ring_tail;
++ dma_addr_t phy_ring_tail;
+ int cnt = MTK_DMA_SIZE;
+ dma_addr_t dma_addr;
+ int i;
+
+ eth->scratch_ring = dma_alloc_coherent(eth->dev,
+ cnt * sizeof(struct mtk_tx_dma),
+- &phy_ring_head,
++ &eth->phy_scratch_ring,
+ GFP_ATOMIC | __GFP_ZERO);
+ if (unlikely(!eth->scratch_ring))
+ return -ENOMEM;
+@@ -508,19 +508,19 @@ static int mtk_init_fq_dma(struct mtk_et
+ return -ENOMEM;
+
+ memset(eth->scratch_ring, 0x0, sizeof(struct mtk_tx_dma) * cnt);
+- phy_ring_tail = phy_ring_head +
++ phy_ring_tail = eth->phy_scratch_ring +
+ (sizeof(struct mtk_tx_dma) * (cnt - 1));
+
+ for (i = 0; i < cnt; i++) {
+ eth->scratch_ring[i].txd1 =
+ (dma_addr + (i * MTK_QDMA_PAGE_SIZE));
+ if (i < cnt - 1)
+- eth->scratch_ring[i].txd2 = (phy_ring_head +
++ eth->scratch_ring[i].txd2 = (eth->phy_scratch_ring +
+ ((i + 1) * sizeof(struct mtk_tx_dma)));
+ eth->scratch_ring[i].txd3 = TX_DMA_SDL(MTK_QDMA_PAGE_SIZE);
+ }
+
+- mtk_w32(eth, phy_ring_head, MTK_QDMA_FQ_HEAD);
++ mtk_w32(eth, eth->phy_scratch_ring, MTK_QDMA_FQ_HEAD);
+ mtk_w32(eth, phy_ring_tail, MTK_QDMA_FQ_TAIL);
+ mtk_w32(eth, (cnt << 16) | cnt, MTK_QDMA_FQ_CNT);
+ mtk_w32(eth, MTK_QDMA_PAGE_SIZE << 16, MTK_QDMA_FQ_BLEN);
+@@ -1220,6 +1220,14 @@ static void mtk_dma_free(struct mtk_eth
+ for (i = 0; i < MTK_MAC_COUNT; i++)
+ if (eth->netdev[i])
+ netdev_reset_queue(eth->netdev[i]);
++ if (eth->scratch_ring) {
++ dma_free_coherent(eth->dev,
++ MTK_DMA_SIZE * sizeof(struct mtk_tx_dma),
++ eth->scratch_ring,
++ eth->phy_scratch_ring);
++ eth->scratch_ring = NULL;
++ eth->phy_scratch_ring = 0;
++ }
+ mtk_tx_clean(eth);
+ mtk_rx_clean(eth);
+ kfree(eth->scratch_head);
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -357,6 +357,7 @@ struct mtk_rx_ring {
+ * @rx_ring: Pointer to the memore holding info about the RX ring
+ * @rx_napi: The NAPI struct
+ * @scratch_ring: Newer SoCs need memory for a second HW managed TX ring
++ * @phy_scratch_ring: physical address of scratch_ring
+ * @scratch_head: The scratch memory that scratch_ring points to.
+ * @clk_ethif: The ethif clock
+ * @clk_esw: The switch clock
+@@ -384,6 +385,7 @@ struct mtk_eth {
+ struct mtk_rx_ring rx_ring;
+ struct napi_struct rx_napi;
+ struct mtk_tx_dma *scratch_ring;
++ dma_addr_t phy_scratch_ring;
+ void *scratch_head;
+ struct clk *clk_ethif;
+ struct clk *clk_esw;
diff --git a/target/linux/mediatek/patches-4.4/0084-net-next-mediatek-fix-missing-free-of-scratch-memory.patch b/target/linux/mediatek/patches-4.4/0084-net-next-mediatek-fix-missing-free-of-scratch-memory.patch
deleted file mode 100644
index 632b9a8140..0000000000
--- a/target/linux/mediatek/patches-4.4/0084-net-next-mediatek-fix-missing-free-of-scratch-memory.patch
+++ /dev/null
@@ -1,96 +0,0 @@
-From 2d22628561299e1c7d71e16262131127de3c4216 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Sat, 23 Apr 2016 09:18:28 +0200
-Subject: [PATCH 84/91] net-next: mediatek: fix missing free of scratch memory
-
-Scratch memory gets allocated in mtk_init_fq_dma() but the corresponding
-code to free it is missing inside mtk_dma_free() causing a memory leak.
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 18 +++++++++++++-----
- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 2 ++
- 2 files changed, 15 insertions(+), 5 deletions(-)
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index e58a634..06b9094 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -469,14 +469,14 @@ static inline void mtk_rx_get_desc(struct mtk_rx_dma *rxd,
- /* the qdma core needs scratch memory to be setup */
- static int mtk_init_fq_dma(struct mtk_eth *eth)
- {
-- dma_addr_t phy_ring_head, phy_ring_tail;
-+ dma_addr_t phy_ring_tail;
- int cnt = MTK_DMA_SIZE;
- dma_addr_t dma_addr;
- int i;
-
- eth->scratch_ring = dma_alloc_coherent(eth->dev,
- cnt * sizeof(struct mtk_tx_dma),
-- &phy_ring_head,
-+ &eth->phy_scratch_ring,
- GFP_ATOMIC | __GFP_ZERO);
- if (unlikely(!eth->scratch_ring))
- return -ENOMEM;
-@@ -493,19 +493,19 @@ static int mtk_init_fq_dma(struct mtk_eth *eth)
- return -ENOMEM;
-
- memset(eth->scratch_ring, 0x0, sizeof(struct mtk_tx_dma) * cnt);
-- phy_ring_tail = phy_ring_head +
-+ phy_ring_tail = eth->phy_scratch_ring +
- (sizeof(struct mtk_tx_dma) * (cnt - 1));
-
- for (i = 0; i < cnt; i++) {
- eth->scratch_ring[i].txd1 =
- (dma_addr + (i * MTK_QDMA_PAGE_SIZE));
- if (i < cnt - 1)
-- eth->scratch_ring[i].txd2 = (phy_ring_head +
-+ eth->scratch_ring[i].txd2 = (eth->phy_scratch_ring +
- ((i + 1) * sizeof(struct mtk_tx_dma)));
- eth->scratch_ring[i].txd3 = TX_DMA_SDL(MTK_QDMA_PAGE_SIZE);
- }
-
-- mtk_w32(eth, phy_ring_head, MTK_QDMA_FQ_HEAD);
-+ mtk_w32(eth, eth->phy_scratch_ring, MTK_QDMA_FQ_HEAD);
- mtk_w32(eth, phy_ring_tail, MTK_QDMA_FQ_TAIL);
- mtk_w32(eth, (cnt << 16) | cnt, MTK_QDMA_FQ_CNT);
- mtk_w32(eth, MTK_QDMA_PAGE_SIZE << 16, MTK_QDMA_FQ_BLEN);
-@@ -1205,6 +1205,14 @@ static void mtk_dma_free(struct mtk_eth *eth)
- for (i = 0; i < MTK_MAC_COUNT; i++)
- if (eth->netdev[i])
- netdev_reset_queue(eth->netdev[i]);
-+ if (eth->scratch_ring) {
-+ dma_free_coherent(eth->dev,
-+ MTK_DMA_SIZE * sizeof(struct mtk_tx_dma),
-+ eth->scratch_ring,
-+ eth->phy_scratch_ring);
-+ eth->scratch_ring = NULL;
-+ eth->phy_scratch_ring = 0;
-+ }
- mtk_tx_clean(eth);
- mtk_rx_clean(eth);
- kfree(eth->scratch_head);
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index eed626d..57f7e8a 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -357,6 +357,7 @@ struct mtk_rx_ring {
- * @rx_ring: Pointer to the memore holding info about the RX ring
- * @rx_napi: The NAPI struct
- * @scratch_ring: Newer SoCs need memory for a second HW managed TX ring
-+ * @phy_scratch_ring: physical address of scratch_ring
- * @scratch_head: The scratch memory that scratch_ring points to.
- * @clk_ethif: The ethif clock
- * @clk_esw: The switch clock
-@@ -384,6 +385,7 @@ struct mtk_eth {
- struct mtk_rx_ring rx_ring;
- struct napi_struct rx_napi;
- struct mtk_tx_dma *scratch_ring;
-+ dma_addr_t phy_scratch_ring;
- void *scratch_head;
- struct clk *clk_ethif;
- struct clk *clk_esw;
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0084-net-next-mediatek-invalid-buffer-lookup-in-mtk_tx_ma.patch b/target/linux/mediatek/patches-4.4/0084-net-next-mediatek-invalid-buffer-lookup-in-mtk_tx_ma.patch
new file mode 100644
index 0000000000..eb44af6f89
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0084-net-next-mediatek-invalid-buffer-lookup-in-mtk_tx_ma.patch
@@ -0,0 +1,27 @@
+From 1eea1536dbbbfda418751ec6f5387acb521ddb97 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Sat, 23 Apr 2016 09:25:00 +0200
+Subject: [PATCH 084/102] net-next: mediatek: invalid buffer lookup in
+ mtk_tx_map()
+
+The lookup of the tx_buffer in the error path inside mtk_tx_map() uses the
+wrong descriptor pointer. This looks like a copy & paste error. Change the
+code to use the correct pointer.
+
+Signed-off-by: Sean Wang <keyhaede@gmail.com>
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -686,7 +686,7 @@ static int mtk_tx_map(struct sk_buff *sk
+
+ err_dma:
+ do {
+- tx_buf = mtk_desc_to_tx_buf(ring, txd);
++ tx_buf = mtk_desc_to_tx_buf(ring, itxd);
+
+ /* unmap dma */
+ mtk_tx_unmap(&dev->dev, tx_buf);
diff --git a/target/linux/mediatek/patches-4.4/0085-net-next-mediatek-dropped-rx-packets-are-not-being-c.patch b/target/linux/mediatek/patches-4.4/0085-net-next-mediatek-dropped-rx-packets-are-not-being-c.patch
new file mode 100644
index 0000000000..2b2a011b3d
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0085-net-next-mediatek-dropped-rx-packets-are-not-being-c.patch
@@ -0,0 +1,34 @@
+From 98aac832925a99afee8722cdfd5a848dd6086b8f Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Sat, 23 Apr 2016 09:28:25 +0200
+Subject: [PATCH 085/102] net-next: mediatek: dropped rx packets are not being
+ counted properly
+
+There are 2 places inside mtk_poll_rx where rx_dropped is not being
+incremented properly. Fix this by adding the missing code to increment
+the counter.
+
+Signed-off-by: Sean Wang <keyhaede@gmail.com>
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -841,6 +841,7 @@ static int mtk_poll_rx(struct napi_struc
+ DMA_FROM_DEVICE);
+ if (unlikely(dma_mapping_error(&netdev->dev, dma_addr))) {
+ skb_free_frag(new_data);
++ netdev->stats.rx_dropped++;
+ goto release_desc;
+ }
+
+@@ -848,6 +849,7 @@ static int mtk_poll_rx(struct napi_struc
+ skb = build_skb(data, ring->frag_size);
+ if (unlikely(!skb)) {
+ put_page(virt_to_head_page(new_data));
++ netdev->stats.rx_dropped++;
+ goto release_desc;
+ }
+ skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN);
diff --git a/target/linux/mediatek/patches-4.4/0085-net-next-mediatek-invalid-buffer-lookup-in-mtk_tx_ma.patch b/target/linux/mediatek/patches-4.4/0085-net-next-mediatek-invalid-buffer-lookup-in-mtk_tx_ma.patch
deleted file mode 100644
index 37e14b19bc..0000000000
--- a/target/linux/mediatek/patches-4.4/0085-net-next-mediatek-invalid-buffer-lookup-in-mtk_tx_ma.patch
+++ /dev/null
@@ -1,30 +0,0 @@
-From 7ae20e15e06eed22f343a566b22dce258f7b8704 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Sat, 23 Apr 2016 09:25:00 +0200
-Subject: [PATCH 85/91] net-next: mediatek: invalid buffer lookup in
- mtk_tx_map()
-
-The lookup of the tx_buffer in the error path inside mtk_tx_map() uses the
-wrong descriptor pointer. This looks like a copy & paste error.
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 06b9094..63e1da4 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -671,7 +671,7 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev,
-
- err_dma:
- do {
-- tx_buf = mtk_desc_to_tx_buf(ring, txd);
-+ tx_buf = mtk_desc_to_tx_buf(ring, itxd);
-
- /* unmap dma */
- mtk_tx_unmap(&dev->dev, tx_buf);
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0086-net-next-mediatek-add-next-data-pointer-coherency-pr.patch b/target/linux/mediatek/patches-4.4/0086-net-next-mediatek-add-next-data-pointer-coherency-pr.patch
new file mode 100644
index 0000000000..cd4bdf8fa4
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0086-net-next-mediatek-add-next-data-pointer-coherency-pr.patch
@@ -0,0 +1,39 @@
+From 5077ac38a86023124ebbe24cd1b7ecbd0f8edaff Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Tue, 3 May 2016 03:06:59 +0200
+Subject: [PATCH 086/102] net-next: mediatek: add next data pointer coherency
+ protection
+
+The QDMA engine can fail to update the register pointing to the next TX
+descriptor if this bit does not get set in the QDMA configuration register.
+Not setting this bit can result in invalid values inside the TX rings
+registers which will causes TX stalls.
+
+Signed-off-by: Sean Wang <keyhaede@gmail.com>
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +-
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 +
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -1292,7 +1292,7 @@ static int mtk_start_dma(struct mtk_eth
+ mtk_w32(eth,
+ MTK_TX_WB_DDONE | MTK_RX_DMA_EN | MTK_TX_DMA_EN |
+ MTK_RX_2B_OFFSET | MTK_DMA_SIZE_16DWORDS |
+- MTK_RX_BT_32DWORDS,
++ MTK_RX_BT_32DWORDS | MTK_NDP_CO_PRO,
+ MTK_QDMA_GLO_CFG);
+
+ return 0;
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -91,6 +91,7 @@
+ #define MTK_QDMA_GLO_CFG 0x1A04
+ #define MTK_RX_2B_OFFSET BIT(31)
+ #define MTK_RX_BT_32DWORDS (3 << 11)
++#define MTK_NDP_CO_PRO BIT(10)
+ #define MTK_TX_WB_DDONE BIT(6)
+ #define MTK_DMA_SIZE_16DWORDS (2 << 4)
+ #define MTK_RX_DMA_BUSY BIT(3)
diff --git a/target/linux/mediatek/patches-4.4/0086-net-next-mediatek-dropped-rx-packets-are-not-being-c.patch b/target/linux/mediatek/patches-4.4/0086-net-next-mediatek-dropped-rx-packets-are-not-being-c.patch
deleted file mode 100644
index 8a38b5a5f5..0000000000
--- a/target/linux/mediatek/patches-4.4/0086-net-next-mediatek-dropped-rx-packets-are-not-being-c.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-From d74187cab7927d3496c01c97051d9c539067ad1b Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Sat, 23 Apr 2016 09:28:25 +0200
-Subject: [PATCH 86/91] net-next: mediatek: dropped rx packets are not being
- counted properly
-
-There are 2 places inside mtk_poll_rx where rx_dropped is not being
-incremented properly. Fix this by adding the missing code to increment
-the counter.
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 63e1da4..24a4179 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -826,6 +826,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
- DMA_FROM_DEVICE);
- if (unlikely(dma_mapping_error(&netdev->dev, dma_addr))) {
- skb_free_frag(new_data);
-+ netdev->stats.rx_dropped++;
- goto release_desc;
- }
-
-@@ -833,6 +834,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
- skb = build_skb(data, ring->frag_size);
- if (unlikely(!skb)) {
- put_page(virt_to_head_page(new_data));
-+ netdev->stats.rx_dropped++;
- goto release_desc;
- }
- skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN);
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0087-net-next-mediatek-add-IRQ-locking.patch b/target/linux/mediatek/patches-4.4/0087-net-next-mediatek-add-IRQ-locking.patch
deleted file mode 100644
index 7278d83285..0000000000
--- a/target/linux/mediatek/patches-4.4/0087-net-next-mediatek-add-IRQ-locking.patch
+++ /dev/null
@@ -1,74 +0,0 @@
-From 4ff9304355036d4a00bdf0e47e869fc770ba1cc5 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Wed, 20 Apr 2016 16:18:07 +0200
-Subject: [PATCH 87/91] net-next: mediatek: add IRQ locking
-
-The code that enables and disables IRQs is missing proper locking. After
-adding the IRQ separation patch and routing the putting the RX and TX IRQs
-on different cores we experienced IRQ stalls. Fix this by adding proper
-locking. We use a dedicated lock to reduce the latency if the IRQ code.
-Otherwise it might wait for bottom code to finish before reenabling or
-disabling IRQs.
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 7 +++++++
- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 +
- 2 files changed, 8 insertions(+)
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 24a4179..f86d551 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -316,22 +316,28 @@ static void mtk_mdio_cleanup(struct mtk_eth *eth)
-
- static inline void mtk_irq_disable(struct mtk_eth *eth, u32 mask)
- {
-+ unsigned long flags;
- u32 val;
-
-+ spin_lock_irqsave(&eth->irq_lock, flags);
- val = mtk_r32(eth, MTK_QDMA_INT_MASK);
- mtk_w32(eth, val & ~mask, MTK_QDMA_INT_MASK);
- /* flush write */
- mtk_r32(eth, MTK_QDMA_INT_MASK);
-+ spin_unlock_irqrestore(&eth->irq_lock, flags);
- }
-
- static inline void mtk_irq_enable(struct mtk_eth *eth, u32 mask)
- {
-+ unsigned long flags;
- u32 val;
-
-+ spin_lock_irqsave(&eth->irq_lock, flags);
- val = mtk_r32(eth, MTK_QDMA_INT_MASK);
- mtk_w32(eth, val | mask, MTK_QDMA_INT_MASK);
- /* flush write */
- mtk_r32(eth, MTK_QDMA_INT_MASK);
-+ spin_unlock_irqrestore(&eth->irq_lock, flags);
- }
-
- static int mtk_set_mac_address(struct net_device *dev, void *p)
-@@ -1752,6 +1758,7 @@ static int mtk_probe(struct platform_device *pdev)
- return -EADDRNOTAVAIL;
-
- spin_lock_init(&eth->page_lock);
-+ spin_lock_init(&eth->irq_lock);
-
- eth->ethsys = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
- "mediatek,ethsys");
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index 57f7e8a..8220275 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -372,6 +372,7 @@ struct mtk_eth {
- void __iomem *base;
- struct reset_control *rstc;
- spinlock_t page_lock;
-+ spinlock_t irq_lock;
- struct net_device dummy_dev;
- struct net_device *netdev[MTK_MAX_DEVS];
- struct mtk_mac *mac[MTK_MAX_DEVS];
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0087-net-next-mediatek-disable-all-interrupts-during-prob.patch b/target/linux/mediatek/patches-4.4/0087-net-next-mediatek-disable-all-interrupts-during-prob.patch
new file mode 100644
index 0000000000..6e809b9315
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0087-net-next-mediatek-disable-all-interrupts-during-prob.patch
@@ -0,0 +1,26 @@
+From f9a08e142fd87c72a7803203ce4ecc94806046ca Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Tue, 3 May 2016 03:14:07 +0200
+Subject: [PATCH 087/102] net-next: mediatek: disable all interrupts during
+ probe
+
+The current code only disables those IRQs that we will later use. To
+ensure that we have a predefined state, we really want to disable all IRQs.
+Change the code to disable all IRQs to achieve this.
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -1406,7 +1406,7 @@ static int __init mtk_hw_init(struct mtk
+
+ /* disable delay and normal interrupt */
+ mtk_w32(eth, 0, MTK_QDMA_DELAY_INT);
+- mtk_irq_disable(eth, MTK_TX_DONE_INT | MTK_RX_DONE_INT);
++ mtk_irq_disable(eth, ~0);
+ mtk_w32(eth, RST_GL_PSE, MTK_RST_GL);
+ mtk_w32(eth, 0, MTK_RST_GL);
+
diff --git a/target/linux/mediatek/patches-4.4/0088-net-next-mediatek-add-support-for-IRQ-grouping.patch b/target/linux/mediatek/patches-4.4/0088-net-next-mediatek-add-support-for-IRQ-grouping.patch
deleted file mode 100644
index 28183b9098..0000000000
--- a/target/linux/mediatek/patches-4.4/0088-net-next-mediatek-add-support-for-IRQ-grouping.patch
+++ /dev/null
@@ -1,401 +0,0 @@
-From 41b4500871ab5b1ef27c6fb49ffd8aac8c7e5009 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Wed, 23 Mar 2016 18:31:48 +0100
-Subject: [PATCH 88/91] net-next: mediatek: add support for IRQ grouping
-
-The ethernet core has 3 IRQs. using the IRQ grouping registers we are able
-to separate TX and RX IRQs, which allows us to service them on separate
-cores. This patch splits the irq handler into 2 separate functiosn, one for
-TX and another for RX. The TX housekeeping is split out of the NAPI handler.
-Instead we use a tasklet to handle housekeeping.
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 164 ++++++++++++++++++---------
- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 16 ++-
- 2 files changed, 124 insertions(+), 56 deletions(-)
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index f86d551..6557026 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -790,7 +790,7 @@ drop:
- }
-
- static int mtk_poll_rx(struct napi_struct *napi, int budget,
-- struct mtk_eth *eth, u32 rx_intr)
-+ struct mtk_eth *eth)
- {
- struct mtk_rx_ring *ring = &eth->rx_ring;
- int idx = ring->calc_idx;
-@@ -878,19 +878,18 @@ release_desc:
- }
-
- if (done < budget)
-- mtk_w32(eth, rx_intr, MTK_QMTK_INT_STATUS);
-+ mtk_w32(eth, MTK_RX_DONE_INT, MTK_QMTK_INT_STATUS);
-
- return done;
- }
-
--static int mtk_poll_tx(struct mtk_eth *eth, int budget, bool *tx_again)
-+static int mtk_poll_tx(struct mtk_eth *eth, int budget)
- {
- struct mtk_tx_ring *ring = &eth->tx_ring;
- struct mtk_tx_dma *desc;
- struct sk_buff *skb;
- struct mtk_tx_buf *tx_buf;
-- int total = 0, done = 0;
-- unsigned int bytes = 0;
-+ unsigned int bytes = 0, done = 0;
- u32 cpu, dma;
- static int condition;
- int i;
-@@ -944,63 +943,80 @@ static int mtk_poll_tx(struct mtk_eth *eth, int budget, bool *tx_again)
- }
-
- /* read hw index again make sure no new tx packet */
-- if (cpu != dma || cpu != mtk_r32(eth, MTK_QTX_DRX_PTR))
-- *tx_again = true;
-- else
-+ if (cpu == dma && cpu == mtk_r32(eth, MTK_QTX_DRX_PTR))
- mtk_w32(eth, MTK_TX_DONE_INT, MTK_QMTK_INT_STATUS);
-
-- if (!total)
-- return 0;
--
- if (atomic_read(&ring->free_count) > ring->thresh)
- mtk_wake_queue(eth);
-
-- return total;
-+ return done;
- }
-
--static int mtk_poll(struct napi_struct *napi, int budget)
-+static void mtk_handle_status_irq(struct mtk_eth *eth)
- {
-- struct mtk_eth *eth = container_of(napi, struct mtk_eth, rx_napi);
-- u32 status, status2, mask, tx_intr, rx_intr, status_intr;
-- int tx_done, rx_done;
-- bool tx_again = false;
--
-- status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
-- status2 = mtk_r32(eth, MTK_INT_STATUS2);
-- tx_intr = MTK_TX_DONE_INT;
-- rx_intr = MTK_RX_DONE_INT;
-- status_intr = (MTK_GDM1_AF | MTK_GDM2_AF);
-- tx_done = 0;
-- rx_done = 0;
-- tx_again = 0;
--
-- if (status & tx_intr)
-- tx_done = mtk_poll_tx(eth, budget, &tx_again);
--
-- if (status & rx_intr)
-- rx_done = mtk_poll_rx(napi, budget, eth, rx_intr);
-+ u32 status2 = mtk_r32(eth, MTK_INT_STATUS2);
-+ u32 status_intr = (MTK_GDM1_AF | MTK_GDM2_AF);
-
- if (unlikely(status2 & status_intr)) {
- mtk_stats_update(eth);
- mtk_w32(eth, status_intr, MTK_INT_STATUS2);
- }
-+}
-
-+static int mtk_napi_tx(struct napi_struct *napi, int budget)
-+{
-+ struct mtk_eth *eth = container_of(napi, struct mtk_eth, tx_napi);
-+ u32 status, mask;
-+ int tx_done = 0;
-+
-+ mtk_handle_status_irq(eth);
-+
-+ status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
-+ tx_done = mtk_poll_tx(eth, budget);
- if (unlikely(netif_msg_intr(eth))) {
- mask = mtk_r32(eth, MTK_QDMA_INT_MASK);
-- netdev_info(eth->netdev[0],
-- "done tx %d, rx %d, intr 0x%08x/0x%x\n",
-- tx_done, rx_done, status, mask);
-+ dev_info(eth->dev,
-+ "done tx %d, intr 0x%08x/0x%x\n",
-+ tx_done, status, mask);
- }
-
-- if (tx_again || rx_done == budget)
-+ if (tx_done == budget)
- return budget;
-
- status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
-- if (status & (tx_intr | rx_intr))
-+ if (status & MTK_TX_DONE_INT)
- return budget;
-
- napi_complete(napi);
-- mtk_irq_enable(eth, tx_intr | rx_intr);
-+ mtk_irq_enable(eth, MTK_TX_DONE_INT);
-+
-+ return tx_done;
-+}
-+
-+static int mtk_napi_rx(struct napi_struct *napi, int budget)
-+{
-+ struct mtk_eth *eth = container_of(napi, struct mtk_eth, rx_napi);
-+ u32 status, mask;
-+ int rx_done = 0;
-+
-+ status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
-+ rx_done = mtk_poll_rx(napi, budget, eth);
-+ if (unlikely(netif_msg_intr(eth))) {
-+ mask = mtk_r32(eth, MTK_QDMA_INT_MASK);
-+ dev_info(eth->dev,
-+ "done rx %d, intr 0x%08x/0x%x\n",
-+ rx_done, status, mask);
-+ }
-+
-+ if (rx_done == budget)
-+ return budget;
-+
-+ status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
-+ if (status & MTK_RX_DONE_INT)
-+ return budget;
-+
-+ napi_complete(napi);
-+ mtk_irq_enable(eth, MTK_RX_DONE_INT);
-
- return rx_done;
- }
-@@ -1237,22 +1253,44 @@ static void mtk_tx_timeout(struct net_device *dev)
- schedule_work(&eth->pending_work);
- }
-
--static irqreturn_t mtk_handle_irq(int irq, void *_eth)
-+static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth)
- {
- struct mtk_eth *eth = _eth;
- u32 status;
-
- status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
-+ status &= ~MTK_TX_DONE_INT;
-+
- if (unlikely(!status))
- return IRQ_NONE;
-
-- if (likely(status & (MTK_RX_DONE_INT | MTK_TX_DONE_INT))) {
-+ if (status & MTK_RX_DONE_INT) {
- if (likely(napi_schedule_prep(&eth->rx_napi)))
- __napi_schedule(&eth->rx_napi);
-- } else {
-- mtk_w32(eth, status, MTK_QMTK_INT_STATUS);
-+ mtk_irq_disable(eth, MTK_RX_DONE_INT);
-+ }
-+ mtk_w32(eth, status, MTK_QMTK_INT_STATUS);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static irqreturn_t mtk_handle_irq_tx(int irq, void *_eth)
-+{
-+ struct mtk_eth *eth = _eth;
-+ u32 status;
-+
-+ status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
-+ status &= ~MTK_RX_DONE_INT;
-+
-+ if (unlikely(!status))
-+ return IRQ_NONE;
-+
-+ if (status & MTK_TX_DONE_INT) {
-+ if (likely(napi_schedule_prep(&eth->tx_napi)))
-+ __napi_schedule(&eth->tx_napi);
-+ mtk_irq_disable(eth, MTK_TX_DONE_INT);
- }
-- mtk_irq_disable(eth, (MTK_RX_DONE_INT | MTK_TX_DONE_INT));
-+ mtk_w32(eth, status, MTK_QMTK_INT_STATUS);
-
- return IRQ_HANDLED;
- }
-@@ -1265,7 +1303,7 @@ static void mtk_poll_controller(struct net_device *dev)
- u32 int_mask = MTK_TX_DONE_INT | MTK_RX_DONE_INT;
-
- mtk_irq_disable(eth, int_mask);
-- mtk_handle_irq(dev->irq, dev);
-+ mtk_handle_irq(dev->irq[0], dev);
- mtk_irq_enable(eth, int_mask);
- }
- #endif
-@@ -1301,6 +1339,7 @@ static int mtk_open(struct net_device *dev)
- if (err)
- return err;
-
-+ napi_enable(&eth->tx_napi);
- napi_enable(&eth->rx_napi);
- mtk_irq_enable(eth, MTK_TX_DONE_INT | MTK_RX_DONE_INT);
- }
-@@ -1349,6 +1388,7 @@ static int mtk_stop(struct net_device *dev)
- return 0;
-
- mtk_irq_disable(eth, MTK_TX_DONE_INT | MTK_RX_DONE_INT);
-+ napi_disable(&eth->tx_napi);
- napi_disable(&eth->rx_napi);
-
- mtk_stop_dma(eth, MTK_QDMA_GLO_CFG);
-@@ -1386,7 +1426,11 @@ static int __init mtk_hw_init(struct mtk_eth *eth)
- /* Enable RX VLan Offloading */
- mtk_w32(eth, 1, MTK_CDMP_EG_CTRL);
-
-- err = devm_request_irq(eth->dev, eth->irq, mtk_handle_irq, 0,
-+ err = devm_request_irq(eth->dev, eth->irq[1], mtk_handle_irq_tx, 0,
-+ dev_name(eth->dev), eth);
-+ if (err)
-+ return err;
-+ err = devm_request_irq(eth->dev, eth->irq[2], mtk_handle_irq_rx, 0,
- dev_name(eth->dev), eth);
- if (err)
- return err;
-@@ -1402,7 +1446,11 @@ static int __init mtk_hw_init(struct mtk_eth *eth)
- mtk_w32(eth, 0, MTK_RST_GL);
-
- /* FE int grouping */
-- mtk_w32(eth, 0, MTK_FE_INT_GRP);
-+ mtk_w32(eth, MTK_TX_DONE_INT, MTK_PDMA_INT_GRP1);
-+ mtk_w32(eth, MTK_RX_DONE_INT, MTK_PDMA_INT_GRP2);
-+ mtk_w32(eth, MTK_TX_DONE_INT, MTK_QDMA_INT_GRP1);
-+ mtk_w32(eth, MTK_RX_DONE_INT, MTK_QDMA_INT_GRP2);
-+ mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP);
-
- for (i = 0; i < 2; i++) {
- u32 val = mtk_r32(eth, MTK_GDMA_FWD_CFG(i));
-@@ -1450,7 +1498,9 @@ static void mtk_uninit(struct net_device *dev)
- phy_disconnect(mac->phy_dev);
- mtk_mdio_cleanup(eth);
- mtk_irq_disable(eth, ~0);
-- free_irq(dev->irq, dev);
-+ free_irq(eth->irq[0], dev);
-+ free_irq(eth->irq[1], dev);
-+ free_irq(eth->irq[2], dev);
- }
-
- static int mtk_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-@@ -1725,10 +1775,10 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
- dev_err(eth->dev, "error bringing up device\n");
- goto free_netdev;
- }
-- eth->netdev[id]->irq = eth->irq;
-+ eth->netdev[id]->irq = eth->irq[0];
- netif_info(eth, probe, eth->netdev[id],
- "mediatek frame engine at 0x%08lx, irq %d\n",
-- eth->netdev[id]->base_addr, eth->netdev[id]->irq);
-+ eth->netdev[id]->base_addr, eth->irq[0]);
-
- return 0;
-
-@@ -1745,6 +1795,7 @@ static int mtk_probe(struct platform_device *pdev)
- struct mtk_soc_data *soc;
- struct mtk_eth *eth;
- int err;
-+ int i;
-
- match = of_match_device(of_mtk_match, &pdev->dev);
- soc = (struct mtk_soc_data *)match->data;
-@@ -1780,10 +1831,12 @@ static int mtk_probe(struct platform_device *pdev)
- return PTR_ERR(eth->rstc);
- }
-
-- eth->irq = platform_get_irq(pdev, 0);
-- if (eth->irq < 0) {
-- dev_err(&pdev->dev, "no IRQ resource found\n");
-- return -ENXIO;
-+ for (i = 0; i < 3; i++) {
-+ eth->irq[i] = platform_get_irq(pdev, i);
-+ if (eth->irq[i] < 0) {
-+ dev_err(&pdev->dev, "no IRQ%d resource found\n", i);
-+ return -ENXIO;
-+ }
- }
-
- eth->clk_ethif = devm_clk_get(&pdev->dev, "ethif");
-@@ -1824,7 +1877,9 @@ static int mtk_probe(struct platform_device *pdev)
- * for NAPI to work
- */
- init_dummy_netdev(&eth->dummy_dev);
-- netif_napi_add(&eth->dummy_dev, &eth->rx_napi, mtk_poll,
-+ netif_napi_add(&eth->dummy_dev, &eth->tx_napi, mtk_napi_tx,
-+ MTK_NAPI_WEIGHT);
-+ netif_napi_add(&eth->dummy_dev, &eth->rx_napi, mtk_napi_rx,
- MTK_NAPI_WEIGHT);
-
- platform_set_drvdata(pdev, eth);
-@@ -1845,6 +1900,7 @@ static int mtk_remove(struct platform_device *pdev)
- clk_disable_unprepare(eth->clk_gp1);
- clk_disable_unprepare(eth->clk_gp2);
-
-+ netif_napi_del(&eth->tx_napi);
- netif_napi_del(&eth->rx_napi);
- mtk_cleanup(eth);
- platform_set_drvdata(pdev, NULL);
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index 8220275..bf158f8 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -68,6 +68,10 @@
- /* Unicast Filter MAC Address Register - High */
- #define MTK_GDMA_MAC_ADRH(x) (0x50C + (x * 0x1000))
-
-+/* PDMA Interrupt grouping registers */
-+#define MTK_PDMA_INT_GRP1 0xa50
-+#define MTK_PDMA_INT_GRP2 0xa54
-+
- /* QDMA TX Queue Configuration Registers */
- #define MTK_QTX_CFG(x) (0x1800 + (x * 0x10))
- #define QDMA_RES_THRES 4
-@@ -124,6 +128,11 @@
- #define MTK_TX_DONE_INT (MTK_TX_DONE_INT0 | MTK_TX_DONE_INT1 | \
- MTK_TX_DONE_INT2 | MTK_TX_DONE_INT3)
-
-+/* QDMA Interrupt grouping registers */
-+#define MTK_QDMA_INT_GRP1 0x1a20
-+#define MTK_QDMA_INT_GRP2 0x1a24
-+#define MTK_RLS_DONE_INT BIT(0)
-+
- /* QDMA Interrupt Status Register */
- #define MTK_QDMA_INT_MASK 0x1A1C
-
-@@ -355,7 +364,8 @@ struct mtk_rx_ring {
- * @dma_refcnt: track how many netdevs are using the DMA engine
- * @tx_ring: Pointer to the memore holding info about the TX ring
- * @rx_ring: Pointer to the memore holding info about the RX ring
-- * @rx_napi: The NAPI struct
-+ * @tx_napi: The TX NAPI struct
-+ * @rx_napi: The RX NAPI struct
- * @scratch_ring: Newer SoCs need memory for a second HW managed TX ring
- * @phy_scratch_ring: physical address of scratch_ring
- * @scratch_head: The scratch memory that scratch_ring points to.
-@@ -376,7 +386,7 @@ struct mtk_eth {
- struct net_device dummy_dev;
- struct net_device *netdev[MTK_MAX_DEVS];
- struct mtk_mac *mac[MTK_MAX_DEVS];
-- int irq;
-+ int irq[3];
- u32 msg_enable;
- unsigned long sysclk;
- struct regmap *ethsys;
-@@ -384,6 +394,7 @@ struct mtk_eth {
- atomic_t dma_refcnt;
- struct mtk_tx_ring tx_ring;
- struct mtk_rx_ring rx_ring;
-+ struct napi_struct tx_napi;
- struct napi_struct rx_napi;
- struct mtk_tx_dma *scratch_ring;
- dma_addr_t phy_scratch_ring;
-@@ -394,6 +405,7 @@ struct mtk_eth {
- struct clk *clk_gp2;
- struct mii_bus *mii_bus;
- struct work_struct pending_work;
-+
- };
-
- /* struct mtk_mac - the structure that holds the info about the MACs of the
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0088-net-next-mediatek-fix-threshold-value.patch b/target/linux/mediatek/patches-4.4/0088-net-next-mediatek-fix-threshold-value.patch
new file mode 100644
index 0000000000..466f8731e0
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0088-net-next-mediatek-fix-threshold-value.patch
@@ -0,0 +1,30 @@
+From 34ea0f209e0759158e363039852a04b1facc3acd Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Tue, 3 May 2016 02:55:27 +0200
+Subject: [PATCH 088/102] net-next: mediatek: fix threshold value
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The logic to calculate the threshold value for stopping the TX queue is
+bad. Currently it will always use 1/2 of the rings size, which is way too
+much. Set the threshold to MAX_SKB_FRAGS. This makes sure that the queue
+is stopped when there is not enough room to accept an additional segment. 
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -1043,8 +1043,7 @@ static int mtk_tx_alloc(struct mtk_eth *
+ atomic_set(&ring->free_count, MTK_DMA_SIZE - 2);
+ ring->next_free = &ring->dma[0];
+ ring->last_free = &ring->dma[MTK_DMA_SIZE - 2];
+- ring->thresh = max((unsigned long)MTK_DMA_SIZE >> 2,
+- MAX_SKB_FRAGS);
++ ring->thresh = MAX_SKB_FRAGS;
+
+ /* make sure that all changes to the dma ring are flushed before we
+ * continue
diff --git a/target/linux/mediatek/patches-4.4/0089-net-mediatek-add-gsw-mt7530-driver.patch b/target/linux/mediatek/patches-4.4/0089-net-mediatek-add-gsw-mt7530-driver.patch
deleted file mode 100644
index f035b24e05..0000000000
--- a/target/linux/mediatek/patches-4.4/0089-net-mediatek-add-gsw-mt7530-driver.patch
+++ /dev/null
@@ -1,2380 +0,0 @@
-From 46f10e3c9c25668efb85babe9ac5e37d019c2794 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Mon, 11 Apr 2016 03:11:54 +0200
-Subject: [PATCH 89/91] net: mediatek add gsw/mt7530 driver
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/net/ethernet/mediatek/Makefile | 2 +-
- drivers/net/ethernet/mediatek/gsw_mt7620.h | 251 +++++++
- drivers/net/ethernet/mediatek/gsw_mt7623.c | 1084 +++++++++++++++++++++++++++
- drivers/net/ethernet/mediatek/mt7530.c | 808 ++++++++++++++++++++
- drivers/net/ethernet/mediatek/mt7530.h | 20 +
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 59 +-
- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 4 +
- 7 files changed, 2198 insertions(+), 30 deletions(-)
- create mode 100644 drivers/net/ethernet/mediatek/gsw_mt7620.h
- create mode 100644 drivers/net/ethernet/mediatek/gsw_mt7623.c
- create mode 100644 drivers/net/ethernet/mediatek/mt7530.c
- create mode 100644 drivers/net/ethernet/mediatek/mt7530.h
-
-diff --git a/drivers/net/ethernet/mediatek/Makefile b/drivers/net/ethernet/mediatek/Makefile
-index aa3f1c8..82001c4 100644
---- a/drivers/net/ethernet/mediatek/Makefile
-+++ b/drivers/net/ethernet/mediatek/Makefile
-@@ -2,4 +2,4 @@
- # Makefile for the Mediatek SoCs built-in ethernet macs
- #
-
--obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth_soc.o
-+obj-$(CONFIG_NET_MEDIATEK_SOC) += mt7530.o gsw_mt7623.o mtk_eth_soc.o
-diff --git a/drivers/net/ethernet/mediatek/gsw_mt7620.h b/drivers/net/ethernet/mediatek/gsw_mt7620.h
-new file mode 100644
-index 0000000..6fca8f2
---- /dev/null
-+++ b/drivers/net/ethernet/mediatek/gsw_mt7620.h
-@@ -0,0 +1,251 @@
-+/* 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; version 2 of the License
-+ *
-+ * 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.
-+ *
-+ * Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
-+ * Copyright (C) 2009-2016 Felix Fietkau <nbd@nbd.name>
-+ * Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
-+ */
-+
-+#ifndef _RALINK_GSW_MT7620_H__
-+#define _RALINK_GSW_MT7620_H__
-+
-+#define GSW_REG_PHY_TIMEOUT (5 * HZ)
-+
-+#define MT7620_GSW_REG_PIAC 0x0004
-+
-+#define GSW_NUM_VLANS 16
-+#define GSW_NUM_VIDS 4096
-+#define GSW_NUM_PORTS 7
-+#define GSW_PORT6 6
-+
-+#define GSW_MDIO_ACCESS BIT(31)
-+#define GSW_MDIO_READ BIT(19)
-+#define GSW_MDIO_WRITE BIT(18)
-+#define GSW_MDIO_START BIT(16)
-+#define GSW_MDIO_ADDR_SHIFT 20
-+#define GSW_MDIO_REG_SHIFT 25
-+
-+#define GSW_REG_PORT_PMCR(x) (0x3000 + (x * 0x100))
-+#define GSW_REG_PORT_STATUS(x) (0x3008 + (x * 0x100))
-+#define GSW_REG_SMACCR0 0x3fE4
-+#define GSW_REG_SMACCR1 0x3fE8
-+#define GSW_REG_CKGCR 0x3ff0
-+
-+#define GSW_REG_IMR 0x7008
-+#define GSW_REG_ISR 0x700c
-+#define GSW_REG_GPC1 0x7014
-+
-+#define SYSC_REG_CHIP_REV_ID 0x0c
-+#define SYSC_REG_CFG 0x10
-+#define SYSC_REG_CFG1 0x14
-+#define RST_CTRL_MCM BIT(2)
-+#define SYSC_PAD_RGMII2_MDIO 0x58
-+#define SYSC_GPIO_MODE 0x60
-+
-+#define PORT_IRQ_ST_CHG 0x7f
-+
-+#define MT7621_ESW_PHY_POLLING 0x0000
-+#define MT7620_ESW_PHY_POLLING 0x7000
-+
-+#define PMCR_IPG BIT(18)
-+#define PMCR_MAC_MODE BIT(16)
-+#define PMCR_FORCE BIT(15)
-+#define PMCR_TX_EN BIT(14)
-+#define PMCR_RX_EN BIT(13)
-+#define PMCR_BACKOFF BIT(9)
-+#define PMCR_BACKPRES BIT(8)
-+#define PMCR_RX_FC BIT(5)
-+#define PMCR_TX_FC BIT(4)
-+#define PMCR_SPEED(_x) (_x << 2)
-+#define PMCR_DUPLEX BIT(1)
-+#define PMCR_LINK BIT(0)
-+
-+#define PHY_AN_EN BIT(31)
-+#define PHY_PRE_EN BIT(30)
-+#define PMY_MDC_CONF(_x) ((_x & 0x3f) << 24)
-+
-+/* ethernet subsystem config register */
-+#define ETHSYS_SYSCFG0 0x14
-+/* ethernet subsystem clock register */
-+#define ETHSYS_CLKCFG0 0x2c
-+#define ETHSYS_TRGMII_CLK_SEL362_5 BIT(11)
-+
-+/* p5 RGMII wrapper TX clock control register */
-+#define MT7530_P5RGMIITXCR 0x7b04
-+/* p5 RGMII wrapper RX clock control register */
-+#define MT7530_P5RGMIIRXCR 0x7b00
-+/* TRGMII TDX ODT registers */
-+#define MT7530_TRGMII_TD0_ODT 0x7a54
-+#define MT7530_TRGMII_TD1_ODT 0x7a5c
-+#define MT7530_TRGMII_TD2_ODT 0x7a64
-+#define MT7530_TRGMII_TD3_ODT 0x7a6c
-+#define MT7530_TRGMII_TD4_ODT 0x7a74
-+#define MT7530_TRGMII_TD5_ODT 0x7a7c
-+/* TRGMII TCK ctrl register */
-+#define MT7530_TRGMII_TCK_CTRL 0x7a78
-+/* TRGMII Tx ctrl register */
-+#define MT7530_TRGMII_TXCTRL 0x7a40
-+/* port 6 extended control register */
-+#define MT7530_P6ECR 0x7830
-+/* IO driver control register */
-+#define MT7530_IO_DRV_CR 0x7810
-+/* top signal control register */
-+#define MT7530_TOP_SIG_CTRL 0x7808
-+/* modified hwtrap register */
-+#define MT7530_MHWTRAP 0x7804
-+/* hwtrap status register */
-+#define MT7530_HWTRAP 0x7800
-+/* status interrupt register */
-+#define MT7530_SYS_INT_STS 0x700c
-+/* system nterrupt register */
-+#define MT7530_SYS_INT_EN 0x7008
-+/* system control register */
-+#define MT7530_SYS_CTRL 0x7000
-+/* port MAC status register */
-+#define MT7530_PMSR_P(x) (0x3008 + (x * 0x100))
-+/* port MAC control register */
-+#define MT7530_PMCR_P(x) (0x3000 + (x * 0x100))
-+
-+#define MT7621_XTAL_SHIFT 6
-+#define MT7621_XTAL_MASK 0x7
-+#define MT7621_XTAL_25 6
-+#define MT7621_XTAL_40 3
-+#define MT7621_MDIO_DRV_MASK (3 << 4)
-+#define MT7621_GE1_MODE_MASK (3 << 12)
-+
-+#define TRGMII_TXCTRL_TXC_INV BIT(30)
-+#define P6ECR_INTF_MODE_RGMII BIT(1)
-+#define P5RGMIIRXCR_C_ALIGN BIT(8)
-+#define P5RGMIIRXCR_DELAY_2 BIT(1)
-+#define P5RGMIITXCR_DELAY_2 (BIT(8) | BIT(2))
-+
-+/* TOP_SIG_CTRL bits */
-+#define TOP_SIG_CTRL_NORMAL (BIT(17) | BIT(16))
-+
-+/* MHWTRAP bits */
-+#define MHWTRAP_MANUAL BIT(16)
-+#define MHWTRAP_P5_MAC_SEL BIT(13)
-+#define MHWTRAP_P6_DIS BIT(8)
-+#define MHWTRAP_P5_RGMII_MODE BIT(7)
-+#define MHWTRAP_P5_DIS BIT(6)
-+#define MHWTRAP_PHY_ACCESS BIT(5)
-+
-+/* HWTRAP bits */
-+#define HWTRAP_XTAL_SHIFT 9
-+#define HWTRAP_XTAL_MASK 0x3
-+
-+/* SYS_CTRL bits */
-+#define SYS_CTRL_SW_RST BIT(1)
-+#define SYS_CTRL_REG_RST BIT(0)
-+
-+/* PMCR bits */
-+#define PMCR_IFG_XMIT_96 BIT(18)
-+#define PMCR_MAC_MODE BIT(16)
-+#define PMCR_FORCE_MODE BIT(15)
-+#define PMCR_TX_EN BIT(14)
-+#define PMCR_RX_EN BIT(13)
-+#define PMCR_BACK_PRES_EN BIT(9)
-+#define PMCR_BACKOFF_EN BIT(8)
-+#define PMCR_TX_FC_EN BIT(5)
-+#define PMCR_RX_FC_EN BIT(4)
-+#define PMCR_FORCE_SPEED_1000 BIT(3)
-+#define PMCR_FORCE_FDX BIT(1)
-+#define PMCR_FORCE_LNK BIT(0)
-+#define PMCR_FIXED_LINK (PMCR_IFG_XMIT_96 | PMCR_MAC_MODE | \
-+ PMCR_FORCE_MODE | PMCR_TX_EN | PMCR_RX_EN | \
-+ PMCR_BACK_PRES_EN | PMCR_BACKOFF_EN | \
-+ PMCR_FORCE_SPEED_1000 | PMCR_FORCE_FDX | \
-+ PMCR_FORCE_LNK)
-+
-+#define PMCR_FIXED_LINK_FC (PMCR_FIXED_LINK | \
-+ PMCR_TX_FC_EN | PMCR_RX_FC_EN)
-+
-+/* TRGMII control registers */
-+#define GSW_INTF_MODE 0x390
-+#define GSW_TRGMII_TD0_ODT 0x354
-+#define GSW_TRGMII_TD1_ODT 0x35c
-+#define GSW_TRGMII_TD2_ODT 0x364
-+#define GSW_TRGMII_TD3_ODT 0x36c
-+#define GSW_TRGMII_TXCTL_ODT 0x374
-+#define GSW_TRGMII_TCK_ODT 0x37c
-+#define GSW_TRGMII_RCK_CTRL 0x300
-+
-+#define INTF_MODE_TRGMII BIT(1)
-+#define TRGMII_RCK_CTRL_RX_RST BIT(31)
-+
-+
-+/* possible XTAL speed */
-+#define MT7623_XTAL_40 0
-+#define MT7623_XTAL_20 1
-+#define MT7623_XTAL_25 3
-+
-+/* GPIO port control registers */
-+#define GPIO_OD33_CTRL8 0x4c0
-+#define GPIO_BIAS_CTRL 0xed0
-+#define GPIO_DRV_SEL10 0xf00
-+
-+/* on MT7620 the functio of port 4 can be software configured */
-+enum {
-+ PORT4_EPHY = 0,
-+ PORT4_EXT,
-+};
-+
-+/* struct mt7620_gsw - the structure that holds the SoC specific data
-+ * @dev: The Device struct
-+ * @base: The base address
-+ * @piac_offset: The PIAC base may change depending on SoC
-+ * @irq: The IRQ we are using
-+ * @port4: The port4 mode on MT7620
-+ * @autopoll: Is MDIO autopolling enabled
-+ * @ethsys: The ethsys register map
-+ * @pctl: The pin control register map
-+ * @clk_trgpll: The trgmii pll clock
-+ */
-+struct mt7620_gsw {
-+ struct mtk_eth *eth;
-+ struct device *dev;
-+ void __iomem *base;
-+ u32 piac_offset;
-+ int irq;
-+ int port4;
-+ unsigned long int autopoll;
-+
-+ struct regmap *ethsys;
-+ struct regmap *pctl;
-+
-+ struct clk *clk_trgpll;
-+
-+ int trgmii_force;
-+ bool wllll;
-+};
-+
-+/* switch register I/O wrappers */
-+void mtk_switch_w32(struct mt7620_gsw *gsw, u32 val, unsigned reg);
-+u32 mtk_switch_r32(struct mt7620_gsw *gsw, unsigned reg);
-+
-+/* the callback used by the driver core to bringup the switch */
-+int mtk_gsw_init(struct mtk_eth *eth);
-+
-+/* MDIO access wrappers */
-+int mt7620_mdio_write(struct mii_bus *bus, int phy_addr, int phy_reg, u16 val);
-+int mt7620_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg);
-+void mt7620_mdio_link_adjust(struct mtk_eth *eth, int port);
-+int mt7620_has_carrier(struct mtk_eth *eth);
-+void mt7620_print_link_state(struct mtk_eth *eth, int port, int link,
-+ int speed, int duplex);
-+void mt7530_mdio_w32(struct mt7620_gsw *gsw, u32 reg, u32 val);
-+u32 mt7530_mdio_r32(struct mt7620_gsw *gsw, u32 reg);
-+void mt7530_mdio_m32(struct mt7620_gsw *gsw, u32 mask, u32 set, u32 reg);
-+
-+u32 _mtk_mdio_write(struct mtk_eth *eth, u32 phy_addr,
-+ u32 phy_register, u32 write_data);
-+u32 _mtk_mdio_read(struct mtk_eth *eth, int phy_addr, int phy_reg);
-+void mt7620_handle_carrier(struct mtk_eth *eth);
-+
-+#endif
-diff --git a/drivers/net/ethernet/mediatek/gsw_mt7623.c b/drivers/net/ethernet/mediatek/gsw_mt7623.c
-new file mode 100644
-index 0000000..0c6b8a6
---- /dev/null
-+++ b/drivers/net/ethernet/mediatek/gsw_mt7623.c
-@@ -0,0 +1,1084 @@
-+/* 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; version 2 of the License
-+ *
-+ * 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.
-+ *
-+ * Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
-+ * Copyright (C) 2009-2016 Felix Fietkau <nbd@nbd.name>
-+ * Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/types.h>
-+#include <linux/platform_device.h>
-+#include <linux/of_device.h>
-+#include <linux/of_irq.h>
-+#include <linux/of_gpio.h>
-+#include <linux/of_mdio.h>
-+#include <linux/clk.h>
-+#include <linux/mfd/syscon.h>
-+#include <linux/regulator/consumer.h>
-+#include <linux/pm_runtime.h>
-+#include <linux/regmap.h>
-+#include <linux/reset.h>
-+#include <linux/mii.h>
-+#include <linux/interrupt.h>
-+#include <linux/netdevice.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/phy.h>
-+#include <linux/ethtool.h>
-+#include <linux/version.h>
-+#include <linux/atomic.h>
-+
-+#include "mtk_eth_soc.h"
-+#include "gsw_mt7620.h"
-+#include "mt7530.h"
-+
-+#define ETHSYS_CLKCFG0 0x2c
-+#define ETHSYS_TRGMII_CLK_SEL362_5 BIT(11)
-+
-+void mt7530_mdio_w32(struct mt7620_gsw *gsw, u32 reg, u32 val)
-+{
-+ _mtk_mdio_write(gsw->eth, 0x1f, 0x1f, (reg >> 6) & 0x3ff);
-+ _mtk_mdio_write(gsw->eth, 0x1f, (reg >> 2) & 0xf, val & 0xffff);
-+ _mtk_mdio_write(gsw->eth, 0x1f, 0x10, val >> 16);
-+}
-+
-+u32 mt7530_mdio_r32(struct mt7620_gsw *gsw, u32 reg)
-+{
-+ u16 high, low;
-+
-+ _mtk_mdio_write(gsw->eth, 0x1f, 0x1f, (reg >> 6) & 0x3ff);
-+ low = _mtk_mdio_read(gsw->eth, 0x1f, (reg >> 2) & 0xf);
-+ high = _mtk_mdio_read(gsw->eth, 0x1f, 0x10);
-+
-+ return (high << 16) | (low & 0xffff);
-+}
-+
-+void mt7530_mdio_m32(struct mt7620_gsw *gsw, u32 mask, u32 set, u32 reg)
-+{
-+ u32 val = mt7530_mdio_r32(gsw, reg);
-+
-+ val &= mask;
-+ val |= set;
-+ mt7530_mdio_w32(gsw, reg, val);
-+}
-+
-+void mtk_switch_w32(struct mt7620_gsw *gsw, u32 val, unsigned reg)
-+{
-+ mtk_w32(gsw->eth, val, reg + 0x10000);
-+}
-+
-+u32 mtk_switch_r32(struct mt7620_gsw *gsw, unsigned reg)
-+{
-+ return mtk_r32(gsw->eth, reg + 0x10000);
-+}
-+
-+void mtk_switch_m32(struct mt7620_gsw *gsw, u32 mask, u32 set, unsigned reg)
-+{
-+ u32 val = mtk_switch_r32(gsw, reg);
-+
-+ val &= mask;
-+ val |= set;
-+
-+ mtk_switch_w32(gsw, val, reg);
-+}
-+
-+int mt7623_gsw_config(struct mtk_eth *eth)
-+{
-+ if (eth->mii_bus && eth->mii_bus->phy_map[0x1f])
-+ mt7530_probe(eth->dev, NULL, eth->mii_bus, 1);
-+
-+ return 0;
-+}
-+
-+static irqreturn_t gsw_interrupt_mt7623(int irq, void *_eth)
-+{
-+ struct mtk_eth *eth = (struct mtk_eth *)_eth;
-+ struct mt7620_gsw *gsw = (struct mt7620_gsw *)eth->sw_priv;
-+ u32 reg, i;
-+
-+ reg = mt7530_mdio_r32(gsw, 0x700c);
-+
-+ for (i = 0; i < 5; i++)
-+ if (reg & BIT(i)) {
-+ unsigned int link;
-+
-+ link = mt7530_mdio_r32(gsw,
-+ 0x3008 + (i * 0x100)) & 0x1;
-+
-+ if (link)
-+ dev_info(gsw->dev,
-+ "port %d link up\n", i);
-+ else
-+ dev_info(gsw->dev,
-+ "port %d link down\n", i);
-+ }
-+
-+// mt7620_handle_carrier(eth);
-+ mt7530_mdio_w32(gsw, 0x700c, 0x1f);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static void wait_loop(struct mt7620_gsw *gsw)
-+{
-+ int i;
-+ int read_data;
-+
-+ for (i = 0; i < 320; i = i + 1)
-+ read_data = mtk_switch_r32(gsw, 0x610);
-+}
-+
-+static void trgmii_calibration_7623(struct mt7620_gsw *gsw)
-+{
-+
-+ unsigned int tap_a[5] = { 0, 0, 0, 0, 0 }; /* minumum delay for all correct */
-+ unsigned int tap_b[5] = { 0, 0, 0, 0, 0 }; /* maximum delay for all correct */
-+ unsigned int final_tap[5];
-+ unsigned int rxc_step_size;
-+ unsigned int rxd_step_size;
-+ unsigned int read_data;
-+ unsigned int tmp;
-+ unsigned int rd_wd;
-+ int i;
-+ unsigned int err_cnt[5];
-+ unsigned int init_toggle_data;
-+ unsigned int err_flag[5];
-+ unsigned int err_total_flag;
-+ unsigned int training_word;
-+ unsigned int rd_tap;
-+ u32 val;
-+
-+ u32 TRGMII_7623_base;
-+ u32 TRGMII_7623_RD_0;
-+ u32 TRGMII_RCK_CTRL;
-+
-+ TRGMII_7623_base = 0x300; /* 0xFB110300 */
-+ TRGMII_7623_RD_0 = TRGMII_7623_base + 0x10;
-+ TRGMII_RCK_CTRL = TRGMII_7623_base;
-+ rxd_step_size = 0x1;
-+ rxc_step_size = 0x4;
-+ init_toggle_data = 0x00000055;
-+ training_word = 0x000000AC;
-+
-+ /* RX clock gating in MT7623 */
-+ mtk_switch_m32(gsw, 0x3fffffff, 0, TRGMII_7623_base + 0x04);
-+
-+ /* Assert RX reset in MT7623 */
-+ mtk_switch_m32(gsw, 0, 0x80000000, TRGMII_7623_base + 0x00);
-+
-+ /* Set TX OE edge in MT7623 */
-+ mtk_switch_m32(gsw, 0, 0x00002000, TRGMII_7623_base + 0x78);
-+
-+ /* Disable RX clock gating in MT7623 */
-+ mtk_switch_m32(gsw, 0, 0xC0000000, TRGMII_7623_base + 0x04);
-+
-+ /* Release RX reset in MT7623 */
-+ mtk_switch_m32(gsw, 0x7fffffff, 0, TRGMII_7623_base);
-+
-+ for (i = 0; i < 5; i++)
-+ mtk_switch_m32(gsw, 0, 0x80000000, TRGMII_7623_RD_0 + i * 8);
-+
-+ pr_err("Enable Training Mode in MT7530\n");
-+ read_data = mt7530_mdio_r32(gsw, 0x7A40);
-+ read_data |= 0xC0000000;
-+ mt7530_mdio_w32(gsw, 0x7A40, read_data); /* Enable Training Mode in MT7530 */
-+ err_total_flag = 0;
-+ pr_err("Adjust RXC delay in MT7623\n");
-+ read_data = 0x0;
-+ while (err_total_flag == 0 && read_data != 0x68) {
-+ pr_err("2nd Enable EDGE CHK in MT7623\n");
-+ /* Enable EDGE CHK in MT7623 */
-+ for (i = 0; i < 5; i++)
-+ mtk_switch_m32(gsw, 0x4fffffff, 0x40000000, TRGMII_7623_RD_0 + i * 8);
-+
-+ wait_loop(gsw);
-+ err_total_flag = 1;
-+ for (i = 0; i < 5; i++) {
-+ err_cnt[i] =
-+ mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8) >> 8;
-+ err_cnt[i] &= 0x0000000f;
-+ rd_wd = mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8) >> 16;
-+ rd_wd &= 0x000000ff;
-+ val = mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8);
-+ pr_err("ERR_CNT = %d, RD_WD =%x, TRGMII_7623_RD_0=%x\n",
-+ err_cnt[i], rd_wd, val);
-+ if (err_cnt[i] != 0) {
-+ err_flag[i] = 1;
-+ } else if (rd_wd != 0x55) {
-+ err_flag[i] = 1;
-+ } else {
-+ err_flag[i] = 0;
-+ }
-+ err_total_flag = err_flag[i] & err_total_flag;
-+ }
-+
-+ pr_err("2nd Disable EDGE CHK in MT7623\n");
-+ /* Disable EDGE CHK in MT7623 */
-+ for (i = 0; i < 5; i++)
-+ mtk_switch_m32(gsw, 0x4fffffff, 0x40000000, TRGMII_7623_RD_0 + i * 8);
-+ wait_loop(gsw);
-+ pr_err("2nd Disable EDGE CHK in MT7623\n");
-+ /* Adjust RXC delay */
-+ /* RX clock gating in MT7623 */
-+ mtk_switch_m32(gsw, 0x3fffffff, 0, TRGMII_7623_base + 0x04);
-+ read_data = mtk_switch_r32(gsw, TRGMII_7623_base);
-+ if (err_total_flag == 0) {
-+ tmp = (read_data & 0x0000007f) + rxc_step_size;
-+ pr_err(" RXC delay = %d\n", tmp);
-+ read_data >>= 8;
-+ read_data &= 0xffffff80;
-+ read_data |= tmp;
-+ read_data <<= 8;
-+ read_data &= 0xffffff80;
-+ read_data |= tmp;
-+ mtk_switch_w32(gsw, read_data, TRGMII_7623_base);
-+ } else {
-+ tmp = (read_data & 0x0000007f) + 16;
-+ pr_err(" RXC delay = %d\n", tmp);
-+ read_data >>= 8;
-+ read_data &= 0xffffff80;
-+ read_data |= tmp;
-+ read_data <<= 8;
-+ read_data &= 0xffffff80;
-+ read_data |= tmp;
-+ mtk_switch_w32(gsw, read_data, TRGMII_7623_base);
-+ }
-+ read_data &= 0x000000ff;
-+
-+ /* Disable RX clock gating in MT7623 */
-+ mtk_switch_m32(gsw, 0, 0xC0000000, TRGMII_7623_base + 0x04);
-+ for (i = 0; i < 5; i++)
-+ mtk_switch_m32(gsw, 0, 0x80000000, TRGMII_7623_RD_0 + i * 8);
-+ }
-+
-+ /* Read RD_WD MT7623 */
-+ for (i = 0; i < 5; i++) {
-+ rd_tap = 0;
-+ while (err_flag[i] != 0 && rd_tap != 128) {
-+ /* Enable EDGE CHK in MT7623 */
-+ mtk_switch_m32(gsw, 0x4fffffff, 0x40000000, TRGMII_7623_RD_0 + i * 8);
-+ wait_loop(gsw);
-+
-+ read_data = mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8);
-+ err_cnt[i] = (read_data >> 8) & 0x0000000f; /* Read MT7623 Errcnt */
-+ rd_wd = (read_data >> 16) & 0x000000ff;
-+ if (err_cnt[i] != 0 || rd_wd != 0x55) {
-+ err_flag[i] = 1;
-+ } else {
-+ err_flag[i] = 0;
-+ }
-+ /* Disable EDGE CHK in MT7623 */
-+ mtk_switch_m32(gsw, 0x4fffffff, 0x40000000, TRGMII_7623_RD_0 + i * 8);
-+ wait_loop(gsw);
-+ if (err_flag[i] != 0) {
-+ rd_tap = (read_data & 0x0000007f) + rxd_step_size; /* Add RXD delay in MT7623 */
-+ read_data = (read_data & 0xffffff80) | rd_tap;
-+ mtk_switch_w32(gsw, read_data,
-+ TRGMII_7623_RD_0 + i * 8);
-+ tap_a[i] = rd_tap;
-+ } else {
-+ rd_tap = (read_data & 0x0000007f) + 48;
-+ read_data = (read_data & 0xffffff80) | rd_tap;
-+ mtk_switch_w32(gsw, read_data,
-+ TRGMII_7623_RD_0 + i * 8);
-+ }
-+
-+ }
-+ pr_err("MT7623 %dth bit Tap_a = %d\n", i, tap_a[i]);
-+ }
-+ /* pr_err("Last While Loop\n"); */
-+ for (i = 0; i < 5; i++) {
-+ while ((err_flag[i] == 0) && (rd_tap != 128)) {
-+ read_data = mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8);
-+ rd_tap = (read_data & 0x0000007f) + rxd_step_size; /* Add RXD delay in MT7623 */
-+ read_data = (read_data & 0xffffff80) | rd_tap;
-+ mtk_switch_w32(gsw, read_data, TRGMII_7623_RD_0 + i * 8);
-+ /* Enable EDGE CHK in MT7623 */
-+ val =
-+ mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8) | 0x40000000;
-+ val &= 0x4fffffff;
-+ mtk_switch_w32(gsw, val, TRGMII_7623_RD_0 + i * 8);
-+ wait_loop(gsw);
-+ read_data = mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8);
-+ err_cnt[i] = (read_data >> 8) & 0x0000000f; /* Read MT7623 Errcnt */
-+ rd_wd = (read_data >> 16) & 0x000000ff;
-+ if (err_cnt[i] != 0 || rd_wd != 0x55) {
-+ err_flag[i] = 1;
-+ } else {
-+ err_flag[i] = 0;
-+ }
-+
-+ /* Disable EDGE CHK in MT7623 */
-+ mtk_switch_m32(gsw, 0x4fffffff, 0x40000000, TRGMII_7623_RD_0 + i * 8);
-+ wait_loop(gsw);
-+
-+ }
-+
-+ tap_b[i] = rd_tap; /* -rxd_step_size; */
-+ pr_err("MT7623 %dth bit Tap_b = %d\n", i, tap_b[i]);
-+ final_tap[i] = (tap_a[i] + tap_b[i]) / 2; /* Calculate RXD delay = (TAP_A + TAP_B)/2 */
-+ read_data = (read_data & 0xffffff80) | final_tap[i];
-+ mtk_switch_w32(gsw, read_data, TRGMII_7623_RD_0 + i * 8);
-+ }
-+
-+ read_data = mt7530_mdio_r32(gsw, 0x7A40);
-+ read_data &= 0x3fffffff;
-+ mt7530_mdio_w32(gsw, 0x7A40, read_data);
-+}
-+
-+static void trgmii_calibration_7530(struct mt7620_gsw *gsw)
-+{
-+
-+ unsigned int tap_a[5] = { 0, 0, 0, 0, 0 };
-+ unsigned int tap_b[5] = { 0, 0, 0, 0, 0 };
-+ unsigned int final_tap[5];
-+ unsigned int rxc_step_size;
-+ unsigned int rxd_step_size;
-+ unsigned int read_data;
-+ unsigned int tmp = 0;
-+ int i;
-+ unsigned int err_cnt[5];
-+ unsigned int rd_wd;
-+ unsigned int init_toggle_data;
-+ unsigned int err_flag[5];
-+ unsigned int err_total_flag;
-+ unsigned int training_word;
-+ unsigned int rd_tap;
-+
-+ u32 TRGMII_7623_base;
-+ u32 TRGMII_7530_RD_0;
-+ u32 TRGMII_RCK_CTRL;
-+ u32 TRGMII_7530_base;
-+ u32 TRGMII_7530_TX_base;
-+ u32 val;
-+
-+ TRGMII_7623_base = 0x300;
-+ TRGMII_7530_base = 0x7A00;
-+ TRGMII_7530_RD_0 = TRGMII_7530_base + 0x10;
-+ TRGMII_RCK_CTRL = TRGMII_7623_base;
-+ rxd_step_size = 0x1;
-+ rxc_step_size = 0x8;
-+ init_toggle_data = 0x00000055;
-+ training_word = 0x000000AC;
-+
-+ TRGMII_7530_TX_base = TRGMII_7530_base + 0x50;
-+
-+ /* pr_err("Calibration begin ........\n"); */
-+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x40) | 0x80000000;
-+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x40);
-+ read_data = mt7530_mdio_r32(gsw, 0x7a10);
-+ /* pr_err("TRGMII_7530_RD_0 is %x\n", read_data); */
-+
-+ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base + 0x04);
-+ read_data &= 0x3fffffff;
-+ mt7530_mdio_w32(gsw, TRGMII_7530_base + 0x04, read_data); /* RX clock gating in MT7530 */
-+
-+ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base + 0x78);
-+ read_data |= 0x00002000;
-+ mt7530_mdio_w32(gsw, TRGMII_7530_base + 0x78, read_data); /* Set TX OE edge in MT7530 */
-+
-+ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base);
-+ read_data |= 0x80000000;
-+ mt7530_mdio_w32(gsw, TRGMII_7530_base, read_data); /* Assert RX reset in MT7530 */
-+
-+ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base);
-+ read_data &= 0x7fffffff;
-+ mt7530_mdio_w32(gsw, TRGMII_7530_base, read_data); /* Release RX reset in MT7530 */
-+
-+ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base + 0x04);
-+ read_data |= 0xC0000000;
-+ mt7530_mdio_w32(gsw, TRGMII_7530_base + 0x04, read_data); /* Disable RX clock gating in MT7530 */
-+
-+ /* pr_err("Enable Training Mode in MT7623\n"); */
-+ /*Enable Training Mode in MT7623 */
-+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x40) | 0x80000000;
-+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x40);
-+ if (gsw->trgmii_force == 2000) {
-+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x40) | 0xC0000000;
-+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x40);
-+ } else {
-+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x40) | 0x80000000;
-+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x40);
-+ }
-+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x078) & 0xfffff0ff;
-+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x078);
-+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x50) & 0xfffff0ff;
-+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x50);
-+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x58) & 0xfffff0ff;
-+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x58);
-+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x60) & 0xfffff0ff;
-+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x60);
-+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x68) & 0xfffff0ff;
-+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x68);
-+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x70) & 0xfffff0ff;
-+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x70);
-+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x78) & 0x00000800;
-+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x78);
-+ err_total_flag = 0;
-+ /* pr_err("Adjust RXC delay in MT7530\n"); */
-+ read_data = 0x0;
-+ while (err_total_flag == 0 && (read_data != 0x68)) {
-+ /* pr_err("2nd Enable EDGE CHK in MT7530\n"); */
-+ /* Enable EDGE CHK in MT7530 */
-+ for (i = 0; i < 5; i++) {
-+ read_data =
-+ mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8);
-+ read_data |= 0x40000000;
-+ read_data &= 0x4fffffff;
-+ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8,
-+ read_data);
-+ wait_loop(gsw);
-+ /* pr_err("2nd Disable EDGE CHK in MT7530\n"); */
-+ err_cnt[i] =
-+ mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8);
-+ /* pr_err("***** MT7530 %dth bit ERR_CNT =%x\n",i, err_cnt[i]); */
-+ /* pr_err("MT7530 %dth bit ERR_CNT =%x\n",i, err_cnt[i]); */
-+ err_cnt[i] >>= 8;
-+ err_cnt[i] &= 0x0000ff0f;
-+ rd_wd = err_cnt[i] >> 8;
-+ rd_wd &= 0x000000ff;
-+ err_cnt[i] &= 0x0000000f;
-+ /* read_data = mt7530_mdio_r32(gsw,0x7a10,&read_data); */
-+ if (err_cnt[i] != 0) {
-+ err_flag[i] = 1;
-+ } else if (rd_wd != 0x55) {
-+ err_flag[i] = 1;
-+ } else {
-+ err_flag[i] = 0;
-+ }
-+ if (i == 0) {
-+ err_total_flag = err_flag[i];
-+ } else {
-+ err_total_flag = err_flag[i] & err_total_flag;
-+ }
-+ /* Disable EDGE CHK in MT7530 */
-+ read_data =
-+ mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8);
-+ read_data |= 0x40000000;
-+ read_data &= 0x4fffffff;
-+ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8,
-+ read_data);
-+ wait_loop(gsw);
-+ }
-+ /*Adjust RXC delay */
-+ if (err_total_flag == 0) {
-+ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base);
-+ read_data |= 0x80000000;
-+ mt7530_mdio_w32(gsw, TRGMII_7530_base, read_data); /* Assert RX reset in MT7530 */
-+
-+ read_data =
-+ mt7530_mdio_r32(gsw, TRGMII_7530_base + 0x04);
-+ read_data &= 0x3fffffff;
-+ mt7530_mdio_w32(gsw, TRGMII_7530_base + 0x04, read_data); /* RX clock gating in MT7530 */
-+
-+ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base);
-+ tmp = read_data;
-+ tmp &= 0x0000007f;
-+ tmp += rxc_step_size;
-+ /* pr_err("Current rxc delay = %d\n", tmp); */
-+ read_data &= 0xffffff80;
-+ read_data |= tmp;
-+ mt7530_mdio_w32(gsw, TRGMII_7530_base, read_data);
-+ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base);
-+ /* pr_err("Current RXC delay = %x\n", read_data); */
-+
-+ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base);
-+ read_data &= 0x7fffffff;
-+ mt7530_mdio_w32(gsw, TRGMII_7530_base, read_data); /* Release RX reset in MT7530 */
-+
-+ read_data =
-+ mt7530_mdio_r32(gsw, TRGMII_7530_base + 0x04);
-+ read_data |= 0xc0000000;
-+ mt7530_mdio_w32(gsw, TRGMII_7530_base + 0x04, read_data); /* Disable RX clock gating in MT7530 */
-+ pr_err("####### MT7530 RXC delay is %d\n", tmp);
-+ }
-+ read_data = tmp;
-+ }
-+ pr_err("Finish RXC Adjustment while loop\n");
-+
-+ /* pr_err("Read RD_WD MT7530\n"); */
-+ /* Read RD_WD MT7530 */
-+ for (i = 0; i < 5; i++) {
-+ rd_tap = 0;
-+ while (err_flag[i] != 0 && rd_tap != 128) {
-+ /* Enable EDGE CHK in MT7530 */
-+ read_data =
-+ mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8);
-+ read_data |= 0x40000000;
-+ read_data &= 0x4fffffff;
-+ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8,
-+ read_data);
-+ wait_loop(gsw);
-+ err_cnt[i] = (read_data >> 8) & 0x0000000f;
-+ rd_wd = (read_data >> 16) & 0x000000ff;
-+ if (err_cnt[i] != 0 || rd_wd != 0x55) {
-+ err_flag[i] = 1;
-+ } else {
-+ err_flag[i] = 0;
-+ }
-+ if (err_flag[i] != 0) {
-+ rd_tap = (read_data & 0x0000007f) + rxd_step_size; /* Add RXD delay in MT7530 */
-+ read_data = (read_data & 0xffffff80) | rd_tap;
-+ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8,
-+ read_data);
-+ tap_a[i] = rd_tap;
-+ } else {
-+ tap_a[i] = (read_data & 0x0000007f); /* Record the min delay TAP_A */
-+ rd_tap = tap_a[i] + 0x4;
-+ read_data = (read_data & 0xffffff80) | rd_tap;
-+ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8,
-+ read_data);
-+ }
-+
-+ /* Disable EDGE CHK in MT7530 */
-+ read_data =
-+ mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8);
-+ read_data |= 0x40000000;
-+ read_data &= 0x4fffffff;
-+ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8,
-+ read_data);
-+ wait_loop(gsw);
-+
-+ }
-+ pr_err("MT7530 %dth bit Tap_a = %d\n", i, tap_a[i]);
-+ }
-+
-+ /* pr_err("Last While Loop\n"); */
-+ for (i = 0; i < 5; i++) {
-+ rd_tap = 0;
-+ while (err_flag[i] == 0 && (rd_tap != 128)) {
-+ /* Enable EDGE CHK in MT7530 */
-+ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8);
-+ read_data |= 0x40000000;
-+ read_data &= 0x4fffffff;
-+ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8,
-+ read_data);
-+ wait_loop(gsw);
-+ err_cnt[i] = (read_data >> 8) & 0x0000000f;
-+ rd_wd = (read_data >> 16) & 0x000000ff;
-+ if (err_cnt[i] != 0 || rd_wd != 0x55)
-+ err_flag[i] = 1;
-+ else
-+ err_flag[i] = 0;
-+
-+ if (err_flag[i] == 0 && (rd_tap != 128)) {
-+ /* Add RXD delay in MT7530 */
-+ rd_tap = (read_data & 0x0000007f) + rxd_step_size;
-+ read_data = (read_data & 0xffffff80) | rd_tap;
-+ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8,
-+ read_data);
-+ }
-+ /* Disable EDGE CHK in MT7530 */
-+ read_data =
-+ mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8);
-+ read_data |= 0x40000000;
-+ read_data &= 0x4fffffff;
-+ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8,
-+ read_data);
-+ wait_loop(gsw);
-+ }
-+ tap_b[i] = rd_tap; /* - rxd_step_size; */
-+ pr_err("MT7530 %dth bit Tap_b = %d\n", i, tap_b[i]);
-+ /* Calculate RXD delay = (TAP_A + TAP_B)/2 */
-+ final_tap[i] = (tap_a[i] + tap_b[i]) / 2;
-+ /* pr_err("########****** MT7530 %dth bit Final Tap = %d\n", i, final_tap[i]); */
-+
-+ read_data = (read_data & 0xffffff80) | final_tap[i];
-+ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, read_data);
-+ }
-+
-+ if (gsw->trgmii_force == 2000)
-+ mtk_switch_m32(gsw, 0x7fffffff, 0, TRGMII_7623_base + 0x40);
-+ else
-+ mtk_switch_m32(gsw, 0x3fffffff, 0, TRGMII_7623_base + 0x40);
-+
-+}
-+
-+static void mt7530_trgmii_clock_setting(struct mt7620_gsw *gsw, u32 xtal_mode)
-+{
-+
-+ u32 regValue;
-+
-+ /* TRGMII Clock */
-+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x410);
-+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x1);
-+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x404);
-+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
-+
-+ if (xtal_mode == 1) {
-+ /* 25MHz */
-+ if (gsw->trgmii_force == 2600)
-+ /* 325MHz */
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x1a00);
-+ else if (gsw->trgmii_force == 2000)
-+ /* 250MHz */
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x1400);
-+ } else if (xtal_mode == 2) {
-+ /* 40MHz */
-+ if (gsw->trgmii_force == 2600)
-+ /* 325MHz */
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x1040);
-+ else if (gsw->trgmii_force == 2000)
-+ /* 250MHz */
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x0c80);
-+ }
-+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x405);
-+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x0);
-+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x409);
-+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
-+ if (xtal_mode == 1)
-+ /* 25MHz */
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x0057);
-+ else
-+ /* 40MHz */
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x0087);
-+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x40a);
-+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
-+ if (xtal_mode == 1)
-+ /* 25MHz */
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x0057);
-+ else
-+ /* 40MHz */
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x0087);
-+
-+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x403);
-+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x1800);
-+
-+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x403);
-+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x1c00);
-+
-+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x401);
-+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0xc020);
-+
-+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x406);
-+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0xa030);
-+
-+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x406);
-+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0xa038);
-+
-+// udelay(120); /* for MT7623 bring up test */
-+
-+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x410);
-+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x3);
-+
-+ regValue = mt7530_mdio_r32(gsw, 0x7830);
-+ regValue &= 0xFFFFFFFC;
-+ regValue |= 0x00000001;
-+ mt7530_mdio_w32(gsw, 0x7830, regValue);
-+
-+ regValue = mt7530_mdio_r32(gsw, 0x7a40);
-+ regValue &= ~(0x1 << 30);
-+ regValue &= ~(0x1 << 28);
-+ mt7530_mdio_w32(gsw, 0x7a40, regValue);
-+
-+ mt7530_mdio_w32(gsw, 0x7a78, 0x55);
-+// udelay(100); /* for mt7623 bring up test */
-+
-+ mtk_switch_m32(gsw, 0x7fffffff, 0, 0x300);
-+
-+ trgmii_calibration_7623(gsw);
-+ trgmii_calibration_7530(gsw);
-+
-+ mtk_switch_m32(gsw, 0, 0x80000000, 0x300);
-+ mtk_switch_m32(gsw, 0, 0x7fffffff, 0x300);
-+
-+ /*MT7530 RXC reset */
-+ regValue = mt7530_mdio_r32(gsw, 0x7a00);
-+ regValue |= (0x1 << 31);
-+ mt7530_mdio_w32(gsw, 0x7a00, regValue);
-+ mdelay(1);
-+ regValue &= ~(0x1 << 31);
-+ mt7530_mdio_w32(gsw, 0x7a00, regValue);
-+ mdelay(100);
-+}
-+
-+static void mt7623_hw_init(struct mtk_eth *eth, struct mt7620_gsw *gsw, struct device_node *np)
-+{
-+ u32 i;
-+ u32 val;
-+ u32 xtal_mode;
-+
-+ regmap_update_bits(gsw->ethsys, ETHSYS_CLKCFG0,
-+ ETHSYS_TRGMII_CLK_SEL362_5,
-+ ETHSYS_TRGMII_CLK_SEL362_5);
-+
-+ /* reset the TRGMII core */
-+ mtk_switch_m32(gsw, 0, INTF_MODE_TRGMII, GSW_INTF_MODE);
-+ /* Assert MT7623 RXC reset */
-+ mtk_switch_m32(gsw, 0, TRGMII_RCK_CTRL_RX_RST, GSW_TRGMII_RCK_CTRL);
-+
-+ /* Hardware reset Switch */
-+ device_reset(eth->dev);
-+
-+ /* Wait for Switch Reset Completed*/
-+ for (i = 0; i < 100; i++) {
-+ mdelay(10);
-+ if (mt7530_mdio_r32(gsw, MT7530_HWTRAP))
-+ break;
-+ }
-+
-+ /* turn off all PHYs */
-+ for (i = 0; i <= 4; i++) {
-+ val = _mtk_mdio_read(gsw->eth, i, 0x0);
-+ val |= BIT(11);
-+ _mtk_mdio_write(gsw->eth, i, 0x0, val);
-+ }
-+
-+ /* reset the switch */
-+ mt7530_mdio_w32(gsw, MT7530_SYS_CTRL,
-+ SYS_CTRL_SW_RST | SYS_CTRL_REG_RST);
-+ udelay(100);
-+
-+ /* GE1, Force 1000M/FD, FC ON */
-+ mt7530_mdio_w32(gsw, MT7530_PMCR_P(6), PMCR_FIXED_LINK_FC);
-+
-+ /* GE2, Force 1000M/FD, FC ON */
-+ mt7530_mdio_w32(gsw, MT7530_PMCR_P(5), PMCR_FIXED_LINK_FC);
-+
-+ /* Enable Port 6, P5 as GMAC5, P5 disable */
-+ val = mt7530_mdio_r32(gsw, MT7530_MHWTRAP);
-+ if (gsw->eth->mac[0] &&
-+ of_phy_is_fixed_link(gsw->eth->mac[0]->of_node))
-+ /* Enable Port 6 */
-+ val &= ~MHWTRAP_P6_DIS;
-+ else
-+ /* Disable Port 6 */
-+ val |= MHWTRAP_P6_DIS;
-+ if (gsw->eth->mac[1] &&
-+ of_phy_is_fixed_link(gsw->eth->mac[1]->of_node)) {
-+ /* Enable Port 5 */
-+ val &= ~MHWTRAP_P5_DIS;
-+ /* Port 5 as PHY */
-+ val &= ~MHWTRAP_P5_MAC_SEL;
-+ } else {
-+ /* Disable Port 5 */
-+ val |= MHWTRAP_P5_DIS;
-+ /* Port 5 as GMAC */
-+ val |= MHWTRAP_P5_MAC_SEL;
-+ val |= BIT(7);
-+ mt7530_mdio_w32(gsw, MT7530_PMCR_P(5), 0x8000);
-+ }
-+ /* gphy to port 0/4 */
-+ if (gsw->wllll)
-+ val |= BIT(20);
-+ else
-+ val &= ~BIT(20);
-+
-+ /* Set MT7530 phy direct access mode**/
-+ val &= ~MHWTRAP_PHY_ACCESS;
-+ /* manual override of HW-Trap */
-+ val |= MHWTRAP_MANUAL;
-+ mt7530_mdio_w32(gsw, MT7530_MHWTRAP, val);
-+ dev_info(gsw->dev, "Setting MHWTRAP to 0x%08x\n", val);
-+
-+ val = mt7530_mdio_r32(gsw, 0x7800);
-+ val = (val >> 9) & 0x3;
-+ if (val == 0x3) {
-+ xtal_mode = 1;
-+ /* 25Mhz Xtal - do nothing */
-+ } else if (val == 0x2) {
-+ /* 40Mhz */
-+ xtal_mode = 2;
-+
-+ /* disable MT7530 core clock */
-+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x410);
-+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x0);
-+
-+ /* disable MT7530 PLL */
-+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x40d);
-+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x2020);
-+
-+ /* for MT7530 core clock = 500Mhz */
-+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x40e);
-+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x119);
-+
-+ /* enable MT7530 PLL */
-+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x40d);
-+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x2820);
-+
-+ udelay(20);
-+
-+ /* enable MT7530 core clock */
-+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x410);
-+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
-+ } else {
-+ xtal_mode = 3;
-+ /* 20Mhz Xtal - TODO */
-+ }
-+
-+ /* RGMII */
-+ _mtk_mdio_write(gsw->eth, 0, 14, 0x1);
-+
-+ /* set MT7530 central align */
-+ val = mt7530_mdio_r32(gsw, 0x7830);
-+ val &= ~1;
-+ val |= 1<<1;
-+ mt7530_mdio_w32(gsw, 0x7830, val);
-+
-+ val = mt7530_mdio_r32(gsw, 0x7a40);
-+ val &= ~(1<<30);
-+ mt7530_mdio_w32(gsw, 0x7a40, val);
-+
-+ mt7530_mdio_w32(gsw, 0x7a78, 0x855);
-+
-+ /* delay setting for 10/1000M */
-+ mt7530_mdio_w32(gsw, 0x7b00, 0x104);
-+ mt7530_mdio_w32(gsw, 0x7b04, 0x10);
-+
-+ /* lower Tx Driving */
-+ mt7530_mdio_w32(gsw, 0x7a54, 0x88);
-+ mt7530_mdio_w32(gsw, 0x7a5c, 0x88);
-+ mt7530_mdio_w32(gsw, 0x7a64, 0x88);
-+ mt7530_mdio_w32(gsw, 0x7a6c, 0x88);
-+ mt7530_mdio_w32(gsw, 0x7a74, 0x88);
-+ mt7530_mdio_w32(gsw, 0x7a7c, 0x88);
-+ mt7530_mdio_w32(gsw, 0x7810, 0x11);
-+
-+ /* Set MT7623/MT7683 TX Driving */
-+ mtk_switch_w32(gsw, 0x88, 0x354);
-+ mtk_switch_w32(gsw, 0x88, 0x35c);
-+ mtk_switch_w32(gsw, 0x88, 0x364);
-+ mtk_switch_w32(gsw, 0x88, 0x36c);
-+ mtk_switch_w32(gsw, 0x88, 0x374);
-+ mtk_switch_w32(gsw, 0x88, 0x37c);
-+
-+ /* Set GE2 driving and slew rate */
-+ regmap_write(gsw->pctl, 0xF00, 0xe00);
-+ /* set GE2 TDSEL */
-+ regmap_write(gsw->pctl, 0x4C0, 0x5);
-+ /* set GE2 TUNE */
-+ regmap_write(gsw->pctl, 0xED0, 0x0);
-+
-+ regmap_write(gsw->pctl, 0xb70, 0);
-+ regmap_write(gsw->pctl, 0x250, 0xffff);
-+ regmap_write(gsw->pctl, 0x260, 0xff);
-+ regmap_write(gsw->pctl, 0x380, 0x37);
-+ regmap_write(gsw->pctl, 0x390, 0x40);
-+
-+ mt7530_trgmii_clock_setting(gsw, xtal_mode);
-+
-+ //LANWANPartition(gsw);
-+
-+ /* disable EEE */
-+ for (i = 0; i <= 4; i++) {
-+ _mtk_mdio_write(gsw->eth, i, 13, 0x7);
-+ _mtk_mdio_write(gsw->eth, i, 14, 0x3C);
-+ _mtk_mdio_write(gsw->eth, i, 13, 0x4007);
-+ _mtk_mdio_write(gsw->eth, i, 14, 0x0);
-+
-+ /* Increase SlvDPSready time */
-+ _mtk_mdio_write(gsw->eth, i, 31, 0x52b5);
-+ _mtk_mdio_write(gsw->eth, i, 16, 0xafae);
-+ _mtk_mdio_write(gsw->eth, i, 18, 0x2f);
-+ _mtk_mdio_write(gsw->eth, i, 16, 0x8fae);
-+
-+ /* Incease post_update_timer */
-+ _mtk_mdio_write(gsw->eth, i, 31, 0x3);
-+ _mtk_mdio_write(gsw->eth, i, 17, 0x4b);
-+
-+ /* Adjust 100_mse_threshold */
-+ _mtk_mdio_write(gsw->eth, i, 13, 0x1e);
-+ _mtk_mdio_write(gsw->eth, i, 14, 0x123);
-+ _mtk_mdio_write(gsw->eth, i, 13, 0x401e);
-+ _mtk_mdio_write(gsw->eth, i, 14, 0xffff);
-+
-+ /* Disable mcc */
-+ _mtk_mdio_write(gsw->eth, i, 13, 0x1e);
-+ _mtk_mdio_write(gsw->eth, i, 14, 0xa6);
-+ _mtk_mdio_write(gsw->eth, i, 13, 0x401e);
-+ _mtk_mdio_write(gsw->eth, i, 14, 0x300);
-+
-+ /* Disable HW auto downshift*/
-+ _mtk_mdio_write(gsw->eth, i, 31, 0x1);
-+ val = _mtk_mdio_read(gsw->eth, i, 0x14);
-+ val &= ~(1<<4);
-+ _mtk_mdio_write(gsw->eth, i, 0x14, val);
-+ }
-+
-+ /* turn on all PHYs */
-+ for (i = 0; i <= 4; i++) {
-+ val = _mtk_mdio_read(gsw->eth, i, 0);
-+ val &= ~BIT(11);
-+ _mtk_mdio_write(gsw->eth, i, 0, val);
-+ }
-+
-+ /* enable irq */
-+ mt7530_mdio_m32(gsw, 0, TOP_SIG_CTRL_NORMAL, MT7530_TOP_SIG_CTRL);
-+}
-+
-+static const struct of_device_id mediatek_gsw_match[] = {
-+ { .compatible = "mediatek,mt7623-gsw" },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(of, mediatek_gsw_match);
-+
-+int mtk_gsw_init(struct mtk_eth *eth)
-+{
-+ struct device_node *np = eth->switch_np;
-+ struct platform_device *pdev = of_find_device_by_node(np);
-+ struct mt7620_gsw *gsw;
-+
-+ if (!pdev)
-+ return -ENODEV;
-+
-+ if (!of_device_is_compatible(np, mediatek_gsw_match->compatible))
-+ return -EINVAL;
-+
-+ gsw = platform_get_drvdata(pdev);
-+ if (!gsw)
-+ return -ENODEV;
-+ gsw->eth = eth;
-+ eth->sw_priv = gsw;
-+
-+ mt7623_hw_init(eth, gsw, np);
-+
-+ if (request_threaded_irq(gsw->irq, gsw_interrupt_mt7623, NULL, 0,
-+ "gsw", eth))
-+ pr_err("fail to request irq\n");
-+ mt7530_mdio_w32(gsw, 0x7008, 0x1f);
-+
-+ return 0;
-+}
-+
-+static int mt7623_gsw_probe(struct platform_device *pdev)
-+{
-+ struct device_node *np = pdev->dev.of_node;
-+ struct device_node *pctl;
-+ int reset_pin, ret;
-+ struct mt7620_gsw *gsw;
-+ struct regulator *supply;
-+
-+ gsw = devm_kzalloc(&pdev->dev, sizeof(struct mt7620_gsw), GFP_KERNEL);
-+ if (!gsw)
-+ return -ENOMEM;
-+
-+ gsw->dev = &pdev->dev;
-+ gsw->trgmii_force = 2000;
-+ gsw->irq = irq_of_parse_and_map(np, 0);
-+ if (gsw->irq < 0)
-+ return -EINVAL;
-+
-+ gsw->ethsys = syscon_regmap_lookup_by_phandle(np, "mediatek,ethsys");
-+ if (IS_ERR(gsw->ethsys))
-+ return PTR_ERR(gsw->ethsys);
-+
-+ reset_pin = of_get_named_gpio(np, "mediatek,reset-pin", 0);
-+ if (reset_pin < 0)
-+ return reset_pin;
-+
-+ pctl = of_parse_phandle(np, "mediatek,pctl-regmap", 0);
-+ if (IS_ERR(pctl))
-+ return PTR_ERR(pctl);
-+
-+ gsw->pctl = syscon_node_to_regmap(pctl);
-+ if (IS_ERR(pctl))
-+ return PTR_ERR(pctl);
-+
-+ ret = devm_gpio_request(&pdev->dev, reset_pin, "mt7530-reset");
-+ if (ret)
-+ return ret;
-+
-+ gsw->clk_trgpll = devm_clk_get(&pdev->dev, "trgpll");
-+
-+ if (IS_ERR(gsw->clk_trgpll))
-+ return -ENODEV;
-+
-+ supply = devm_regulator_get(&pdev->dev, "mt7530");
-+ if (IS_ERR(supply))
-+ return PTR_ERR(supply);
-+
-+ regulator_set_voltage(supply, 1000000, 1000000);
-+ ret = regulator_enable(supply);
-+ if (ret) {
-+ dev_err(&pdev->dev, "Failed to enable reg-7530: %d\n", ret);
-+ return ret;
-+ }
-+
-+ gsw->wllll = of_property_read_bool(np, "mediatek,wllll");
-+
-+ pm_runtime_enable(&pdev->dev);
-+ pm_runtime_get_sync(&pdev->dev);
-+
-+ ret = clk_set_rate(gsw->clk_trgpll, 500000000);
-+ if (ret)
-+ return ret;
-+
-+ regmap_write(gsw->ethsys, 0x34, 0x800000);
-+ regmap_write(gsw->ethsys, 0x34, 0x0);
-+
-+ clk_prepare_enable(gsw->clk_trgpll);
-+
-+ gpio_direction_output(reset_pin, 0);
-+ udelay(1000);
-+ gpio_set_value(reset_pin, 1);
-+ mdelay(100);
-+
-+ platform_set_drvdata(pdev, gsw);
-+
-+ return 0;
-+}
-+
-+static int mt7623_gsw_remove(struct platform_device *pdev)
-+{
-+ struct mt7620_gsw *gsw = platform_get_drvdata(pdev);
-+
-+ clk_disable_unprepare(gsw->clk_trgpll);
-+
-+ pm_runtime_put_sync(&pdev->dev);
-+ pm_runtime_disable(&pdev->dev);
-+
-+ platform_set_drvdata(pdev, NULL);
-+
-+ return 0;
-+}
-+
-+static struct platform_driver gsw_driver = {
-+ .probe = mt7623_gsw_probe,
-+ .remove = mt7623_gsw_remove,
-+ .driver = {
-+ .name = "mt7623-gsw",
-+ .owner = THIS_MODULE,
-+ .of_match_table = mediatek_gsw_match,
-+ },
-+};
-+
-+module_platform_driver(gsw_driver);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
-+MODULE_DESCRIPTION("GBit switch driver for Mediatek MT7623 SoC");
-diff --git a/drivers/net/ethernet/mediatek/mt7530.c b/drivers/net/ethernet/mediatek/mt7530.c
-new file mode 100644
-index 0000000..2e9d280
---- /dev/null
-+++ b/drivers/net/ethernet/mediatek/mt7530.c
-@@ -0,0 +1,808 @@
-+/*
-+ * 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.
-+ *
-+ * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
-+ */
-+
-+#include <linux/if.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/list.h>
-+#include <linux/if_ether.h>
-+#include <linux/skbuff.h>
-+#include <linux/netdevice.h>
-+#include <linux/netlink.h>
-+#include <linux/bitops.h>
-+#include <net/genetlink.h>
-+#include <linux/switch.h>
-+#include <linux/delay.h>
-+#include <linux/phy.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/lockdep.h>
-+#include <linux/workqueue.h>
-+#include <linux/of_device.h>
-+
-+#include "mt7530.h"
-+
-+#define MT7530_CPU_PORT 6
-+#define MT7530_NUM_PORTS 8
-+#define MT7530_NUM_VLANS 16
-+#define MT7530_MAX_VID 4095
-+#define MT7530_MIN_VID 0
-+
-+/* registers */
-+#define REG_ESW_VLAN_VTCR 0x90
-+#define REG_ESW_VLAN_VAWD1 0x94
-+#define REG_ESW_VLAN_VAWD2 0x98
-+#define REG_ESW_VLAN_VTIM(x) (0x100 + 4 * ((x) / 2))
-+
-+#define REG_ESW_VLAN_VAWD1_IVL_MAC BIT(30)
-+#define REG_ESW_VLAN_VAWD1_VTAG_EN BIT(28)
-+#define REG_ESW_VLAN_VAWD1_VALID BIT(0)
-+
-+/* vlan egress mode */
-+enum {
-+ ETAG_CTRL_UNTAG = 0,
-+ ETAG_CTRL_TAG = 2,
-+ ETAG_CTRL_SWAP = 1,
-+ ETAG_CTRL_STACK = 3,
-+};
-+
-+#define REG_ESW_PORT_PCR(x) (0x2004 | ((x) << 8))
-+#define REG_ESW_PORT_PVC(x) (0x2010 | ((x) << 8))
-+#define REG_ESW_PORT_PPBV1(x) (0x2014 | ((x) << 8))
-+
-+#define REG_HWTRAP 0x7804
-+
-+#define MIB_DESC(_s , _o, _n) \
-+ { \
-+ .size = (_s), \
-+ .offset = (_o), \
-+ .name = (_n), \
-+ }
-+
-+struct mt7xxx_mib_desc {
-+ unsigned int size;
-+ unsigned int offset;
-+ const char *name;
-+};
-+
-+#define MT7621_MIB_COUNTER_BASE 0x4000
-+#define MT7621_MIB_COUNTER_PORT_OFFSET 0x100
-+#define MT7621_STATS_TDPC 0x00
-+#define MT7621_STATS_TCRC 0x04
-+#define MT7621_STATS_TUPC 0x08
-+#define MT7621_STATS_TMPC 0x0C
-+#define MT7621_STATS_TBPC 0x10
-+#define MT7621_STATS_TCEC 0x14
-+#define MT7621_STATS_TSCEC 0x18
-+#define MT7621_STATS_TMCEC 0x1C
-+#define MT7621_STATS_TDEC 0x20
-+#define MT7621_STATS_TLCEC 0x24
-+#define MT7621_STATS_TXCEC 0x28
-+#define MT7621_STATS_TPPC 0x2C
-+#define MT7621_STATS_TL64PC 0x30
-+#define MT7621_STATS_TL65PC 0x34
-+#define MT7621_STATS_TL128PC 0x38
-+#define MT7621_STATS_TL256PC 0x3C
-+#define MT7621_STATS_TL512PC 0x40
-+#define MT7621_STATS_TL1024PC 0x44
-+#define MT7621_STATS_TOC 0x48
-+#define MT7621_STATS_RDPC 0x60
-+#define MT7621_STATS_RFPC 0x64
-+#define MT7621_STATS_RUPC 0x68
-+#define MT7621_STATS_RMPC 0x6C
-+#define MT7621_STATS_RBPC 0x70
-+#define MT7621_STATS_RAEPC 0x74
-+#define MT7621_STATS_RCEPC 0x78
-+#define MT7621_STATS_RUSPC 0x7C
-+#define MT7621_STATS_RFEPC 0x80
-+#define MT7621_STATS_ROSPC 0x84
-+#define MT7621_STATS_RJEPC 0x88
-+#define MT7621_STATS_RPPC 0x8C
-+#define MT7621_STATS_RL64PC 0x90
-+#define MT7621_STATS_RL65PC 0x94
-+#define MT7621_STATS_RL128PC 0x98
-+#define MT7621_STATS_RL256PC 0x9C
-+#define MT7621_STATS_RL512PC 0xA0
-+#define MT7621_STATS_RL1024PC 0xA4
-+#define MT7621_STATS_ROC 0xA8
-+#define MT7621_STATS_RDPC_CTRL 0xB0
-+#define MT7621_STATS_RDPC_ING 0xB4
-+#define MT7621_STATS_RDPC_ARL 0xB8
-+
-+static const struct mt7xxx_mib_desc mt7621_mibs[] = {
-+ MIB_DESC(1, MT7621_STATS_TDPC, "TxDrop"),
-+ MIB_DESC(1, MT7621_STATS_TCRC, "TxCRC"),
-+ MIB_DESC(1, MT7621_STATS_TUPC, "TxUni"),
-+ MIB_DESC(1, MT7621_STATS_TMPC, "TxMulti"),
-+ MIB_DESC(1, MT7621_STATS_TBPC, "TxBroad"),
-+ MIB_DESC(1, MT7621_STATS_TCEC, "TxCollision"),
-+ MIB_DESC(1, MT7621_STATS_TSCEC, "TxSingleCol"),
-+ MIB_DESC(1, MT7621_STATS_TMCEC, "TxMultiCol"),
-+ MIB_DESC(1, MT7621_STATS_TDEC, "TxDefer"),
-+ MIB_DESC(1, MT7621_STATS_TLCEC, "TxLateCol"),
-+ MIB_DESC(1, MT7621_STATS_TXCEC, "TxExcCol"),
-+ MIB_DESC(1, MT7621_STATS_TPPC, "TxPause"),
-+ MIB_DESC(1, MT7621_STATS_TL64PC, "Tx64Byte"),
-+ MIB_DESC(1, MT7621_STATS_TL65PC, "Tx65Byte"),
-+ MIB_DESC(1, MT7621_STATS_TL128PC, "Tx128Byte"),
-+ MIB_DESC(1, MT7621_STATS_TL256PC, "Tx256Byte"),
-+ MIB_DESC(1, MT7621_STATS_TL512PC, "Tx512Byte"),
-+ MIB_DESC(1, MT7621_STATS_TL1024PC, "Tx1024Byte"),
-+ MIB_DESC(2, MT7621_STATS_TOC, "TxByte"),
-+ MIB_DESC(1, MT7621_STATS_RDPC, "RxDrop"),
-+ MIB_DESC(1, MT7621_STATS_RFPC, "RxFiltered"),
-+ MIB_DESC(1, MT7621_STATS_RUPC, "RxUni"),
-+ MIB_DESC(1, MT7621_STATS_RMPC, "RxMulti"),
-+ MIB_DESC(1, MT7621_STATS_RBPC, "RxBroad"),
-+ MIB_DESC(1, MT7621_STATS_RAEPC, "RxAlignErr"),
-+ MIB_DESC(1, MT7621_STATS_RCEPC, "RxCRC"),
-+ MIB_DESC(1, MT7621_STATS_RUSPC, "RxUnderSize"),
-+ MIB_DESC(1, MT7621_STATS_RFEPC, "RxFragment"),
-+ MIB_DESC(1, MT7621_STATS_ROSPC, "RxOverSize"),
-+ MIB_DESC(1, MT7621_STATS_RJEPC, "RxJabber"),
-+ MIB_DESC(1, MT7621_STATS_RPPC, "RxPause"),
-+ MIB_DESC(1, MT7621_STATS_RL64PC, "Rx64Byte"),
-+ MIB_DESC(1, MT7621_STATS_RL65PC, "Rx65Byte"),
-+ MIB_DESC(1, MT7621_STATS_RL128PC, "Rx128Byte"),
-+ MIB_DESC(1, MT7621_STATS_RL256PC, "Rx256Byte"),
-+ MIB_DESC(1, MT7621_STATS_RL512PC, "Rx512Byte"),
-+ MIB_DESC(1, MT7621_STATS_RL1024PC, "Rx1024Byte"),
-+ MIB_DESC(2, MT7621_STATS_ROC, "RxByte"),
-+ MIB_DESC(1, MT7621_STATS_RDPC_CTRL, "RxCtrlDrop"),
-+ MIB_DESC(1, MT7621_STATS_RDPC_ING, "RxIngDrop"),
-+ MIB_DESC(1, MT7621_STATS_RDPC_ARL, "RxARLDrop")
-+};
-+
-+enum {
-+ /* Global attributes. */
-+ MT7530_ATTR_ENABLE_VLAN,
-+};
-+
-+struct mt7530_port_entry {
-+ u16 pvid;
-+};
-+
-+struct mt7530_vlan_entry {
-+ u16 vid;
-+ u8 member;
-+ u8 etags;
-+};
-+
-+struct mt7530_priv {
-+ void __iomem *base;
-+ struct mii_bus *bus;
-+ struct switch_dev swdev;
-+
-+ bool global_vlan_enable;
-+ struct mt7530_vlan_entry vlan_entries[MT7530_NUM_VLANS];
-+ struct mt7530_port_entry port_entries[MT7530_NUM_PORTS];
-+};
-+
-+struct mt7530_mapping {
-+ char *name;
-+ u16 pvids[MT7530_NUM_PORTS];
-+ u8 members[MT7530_NUM_VLANS];
-+ u8 etags[MT7530_NUM_VLANS];
-+ u16 vids[MT7530_NUM_VLANS];
-+} mt7530_defaults[] = {
-+ {
-+ .name = "llllw",
-+ .pvids = { 1, 1, 1, 1, 2, 1, 1 },
-+ .members = { 0, 0x6f, 0x50 },
-+ .etags = { 0, 0x40, 0x40 },
-+ .vids = { 0, 1, 2 },
-+ }, {
-+ .name = "wllll",
-+ .pvids = { 2, 1, 1, 1, 1, 1, 1 },
-+ .members = { 0, 0x7e, 0x41 },
-+ .etags = { 0, 0x40, 0x40 },
-+ .vids = { 0, 1, 2 },
-+ },
-+};
-+
-+struct mt7530_mapping*
-+mt7530_find_mapping(struct device_node *np)
-+{
-+ const char *map;
-+ int i;
-+
-+ if (of_property_read_string(np, "mediatek,portmap", &map))
-+ return NULL;
-+
-+ for (i = 0; i < ARRAY_SIZE(mt7530_defaults); i++)
-+ if (!strcmp(map, mt7530_defaults[i].name))
-+ return &mt7530_defaults[i];
-+
-+ return NULL;
-+}
-+
-+static void
-+mt7530_apply_mapping(struct mt7530_priv *mt7530, struct mt7530_mapping *map)
-+{
-+ int i = 0;
-+
-+ for (i = 0; i < MT7530_NUM_PORTS; i++)
-+ mt7530->port_entries[i].pvid = map->pvids[i];
-+
-+ for (i = 0; i < MT7530_NUM_VLANS; i++) {
-+ mt7530->vlan_entries[i].member = map->members[i];
-+ mt7530->vlan_entries[i].etags = map->etags[i];
-+ mt7530->vlan_entries[i].vid = map->vids[i];
-+ }
-+}
-+
-+static int
-+mt7530_reset_switch(struct switch_dev *dev)
-+{
-+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
-+ int i;
-+
-+ memset(eth->port_entries, 0, sizeof(eth->port_entries));
-+ memset(eth->vlan_entries, 0, sizeof(eth->vlan_entries));
-+
-+ /* set default vid of each vlan to the same number of vlan, so the vid
-+ * won't need be set explicitly.
-+ */
-+ for (i = 0; i < MT7530_NUM_VLANS; i++) {
-+ eth->vlan_entries[i].vid = i;
-+ }
-+
-+ return 0;
-+}
-+
-+static int
-+mt7530_get_vlan_enable(struct switch_dev *dev,
-+ const struct switch_attr *attr,
-+ struct switch_val *val)
-+{
-+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
-+
-+ val->value.i = eth->global_vlan_enable;
-+
-+ return 0;
-+}
-+
-+static int
-+mt7530_set_vlan_enable(struct switch_dev *dev,
-+ const struct switch_attr *attr,
-+ struct switch_val *val)
-+{
-+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
-+
-+ eth->global_vlan_enable = val->value.i != 0;
-+
-+ return 0;
-+}
-+
-+static u32
-+mt7530_r32(struct mt7530_priv *eth, u32 reg)
-+{
-+ u32 val;
-+ if (eth->bus) {
-+ u16 high, low;
-+
-+ mdiobus_write(eth->bus, 0x1f, 0x1f, (reg >> 6) & 0x3ff);
-+ low = mdiobus_read(eth->bus, 0x1f, (reg >> 2) & 0xf);
-+ high = mdiobus_read(eth->bus, 0x1f, 0x10);
-+
-+ return (high << 16) | (low & 0xffff);
-+ }
-+
-+ val = ioread32(eth->base + reg);
-+ pr_debug("MT7530 MDIO Read [%04x]=%08x\n", reg, val);
-+
-+ return val;
-+}
-+
-+static void
-+mt7530_w32(struct mt7530_priv *eth, u32 reg, u32 val)
-+{
-+ if (eth->bus) {
-+ mdiobus_write(eth->bus, 0x1f, 0x1f, (reg >> 6) & 0x3ff);
-+ mdiobus_write(eth->bus, 0x1f, (reg >> 2) & 0xf, val & 0xffff);
-+ mdiobus_write(eth->bus, 0x1f, 0x10, val >> 16);
-+ return;
-+ }
-+
-+ pr_debug("MT7530 MDIO Write[%04x]=%08x\n", reg, val);
-+ iowrite32(val, eth->base + reg);
-+}
-+
-+static void
-+mt7530_vtcr(struct mt7530_priv *eth, u32 cmd, u32 val)
-+{
-+ int i;
-+
-+ mt7530_w32(eth, REG_ESW_VLAN_VTCR, BIT(31) | (cmd << 12) | val);
-+
-+ for (i = 0; i < 20; i++) {
-+ u32 val = mt7530_r32(eth, REG_ESW_VLAN_VTCR);
-+
-+ if ((val & BIT(31)) == 0)
-+ break;
-+
-+ udelay(1000);
-+ }
-+ if (i == 20)
-+ printk("mt7530: vtcr timeout\n");
-+}
-+
-+static int
-+mt7530_get_port_pvid(struct switch_dev *dev, int port, int *val)
-+{
-+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
-+
-+ if (port >= MT7530_NUM_PORTS)
-+ return -EINVAL;
-+
-+ *val = mt7530_r32(eth, REG_ESW_PORT_PPBV1(port));
-+ *val &= 0xfff;
-+
-+ return 0;
-+}
-+
-+static int
-+mt7530_set_port_pvid(struct switch_dev *dev, int port, int pvid)
-+{
-+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
-+
-+ if (port >= MT7530_NUM_PORTS)
-+ return -EINVAL;
-+
-+ if (pvid < MT7530_MIN_VID || pvid > MT7530_MAX_VID)
-+ return -EINVAL;
-+
-+ eth->port_entries[port].pvid = pvid;
-+
-+ return 0;
-+}
-+
-+static int
-+mt7530_get_vlan_ports(struct switch_dev *dev, struct switch_val *val)
-+{
-+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
-+ u32 member;
-+ u32 etags;
-+ int i;
-+
-+ val->len = 0;
-+
-+ if (val->port_vlan < 0 || val->port_vlan >= MT7530_NUM_VLANS)
-+ return -EINVAL;
-+
-+ mt7530_vtcr(eth, 0, val->port_vlan);
-+
-+ member = mt7530_r32(eth, REG_ESW_VLAN_VAWD1);
-+ member >>= 16;
-+ member &= 0xff;
-+
-+ etags = mt7530_r32(eth, REG_ESW_VLAN_VAWD2);
-+
-+ for (i = 0; i < MT7530_NUM_PORTS; i++) {
-+ struct switch_port *p;
-+ int etag;
-+
-+ if (!(member & BIT(i)))
-+ continue;
-+
-+ p = &val->value.ports[val->len++];
-+ p->id = i;
-+
-+ etag = (etags >> (i * 2)) & 0x3;
-+
-+ if (etag == ETAG_CTRL_TAG)
-+ p->flags |= BIT(SWITCH_PORT_FLAG_TAGGED);
-+ else if (etag != ETAG_CTRL_UNTAG)
-+ printk("vlan egress tag control neither untag nor tag.\n");
-+ }
-+
-+ return 0;
-+}
-+
-+static int
-+mt7530_set_vlan_ports(struct switch_dev *dev, struct switch_val *val)
-+{
-+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
-+ u8 member = 0;
-+ u8 etags = 0;
-+ int i;
-+
-+ if (val->port_vlan < 0 || val->port_vlan >= MT7530_NUM_VLANS ||
-+ val->len > MT7530_NUM_PORTS)
-+ return -EINVAL;
-+
-+ for (i = 0; i < val->len; i++) {
-+ struct switch_port *p = &val->value.ports[i];
-+
-+ if (p->id >= MT7530_NUM_PORTS)
-+ return -EINVAL;
-+
-+ member |= BIT(p->id);
-+
-+ if (p->flags & BIT(SWITCH_PORT_FLAG_TAGGED))
-+ etags |= BIT(p->id);
-+ }
-+ eth->vlan_entries[val->port_vlan].member = member;
-+ eth->vlan_entries[val->port_vlan].etags = etags;
-+
-+ return 0;
-+}
-+
-+static int
-+mt7530_set_vid(struct switch_dev *dev, const struct switch_attr *attr,
-+ struct switch_val *val)
-+{
-+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
-+ int vlan;
-+ u16 vid;
-+
-+ vlan = val->port_vlan;
-+ vid = (u16)val->value.i;
-+
-+ if (vlan < 0 || vlan >= MT7530_NUM_VLANS)
-+ return -EINVAL;
-+
-+ if (vid < MT7530_MIN_VID || vid > MT7530_MAX_VID)
-+ return -EINVAL;
-+
-+ eth->vlan_entries[vlan].vid = vid;
-+ return 0;
-+}
-+
-+static int
-+mt7530_get_vid(struct switch_dev *dev, const struct switch_attr *attr,
-+ struct switch_val *val)
-+{
-+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
-+ u32 vid;
-+ int vlan;
-+
-+ vlan = val->port_vlan;
-+
-+ vid = mt7530_r32(eth, REG_ESW_VLAN_VTIM(vlan));
-+ if (vlan & 1)
-+ vid = vid >> 12;
-+ vid &= 0xfff;
-+
-+ val->value.i = vid;
-+ return 0;
-+}
-+
-+static int
-+mt7530_apply_config(struct switch_dev *dev)
-+{
-+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
-+ int i, j;
-+ u8 tag_ports;
-+ u8 untag_ports;
-+
-+ if (!eth->global_vlan_enable) {
-+ for (i = 0; i < MT7530_NUM_PORTS; i++)
-+ mt7530_w32(eth, REG_ESW_PORT_PCR(i), 0x00ff0000);
-+
-+ for (i = 0; i < MT7530_NUM_PORTS; i++)
-+ mt7530_w32(eth, REG_ESW_PORT_PVC(i), 0x810000c0);
-+
-+ return 0;
-+ }
-+
-+ /* set all ports as security mode */
-+ for (i = 0; i < MT7530_NUM_PORTS; i++)
-+ mt7530_w32(eth, REG_ESW_PORT_PCR(i), 0x00ff0003);
-+
-+ /* check if a port is used in tag/untag vlan egress mode */
-+ tag_ports = 0;
-+ untag_ports = 0;
-+
-+ for (i = 0; i < MT7530_NUM_VLANS; i++) {
-+ u8 member = eth->vlan_entries[i].member;
-+ u8 etags = eth->vlan_entries[i].etags;
-+
-+ if (!member)
-+ continue;
-+
-+ for (j = 0; j < MT7530_NUM_PORTS; j++) {
-+ if (!(member & BIT(j)))
-+ continue;
-+
-+ if (etags & BIT(j))
-+ tag_ports |= 1u << j;
-+ else
-+ untag_ports |= 1u << j;
-+ }
-+ }
-+
-+ /* set all untag-only ports as transparent and the rest as user port */
-+ for (i = 0; i < MT7530_NUM_PORTS; i++) {
-+ u32 pvc_mode = 0x81000000;
-+
-+ if (untag_ports & BIT(i) && !(tag_ports & BIT(i)))
-+ pvc_mode = 0x810000c0;
-+
-+ mt7530_w32(eth, REG_ESW_PORT_PVC(i), pvc_mode);
-+ }
-+
-+ for (i = 0; i < MT7530_NUM_VLANS; i++) {
-+ u16 vid = eth->vlan_entries[i].vid;
-+ u8 member = eth->vlan_entries[i].member;
-+ u8 etags = eth->vlan_entries[i].etags;
-+ u32 val;
-+
-+ /* vid of vlan */
-+ val = mt7530_r32(eth, REG_ESW_VLAN_VTIM(i));
-+ if (i % 2 == 0) {
-+ val &= 0xfff000;
-+ val |= vid;
-+ } else {
-+ val &= 0xfff;
-+ val |= (vid << 12);
-+ }
-+ mt7530_w32(eth, REG_ESW_VLAN_VTIM(i), val);
-+
-+ /* vlan port membership */
-+ if (member)
-+ mt7530_w32(eth, REG_ESW_VLAN_VAWD1, REG_ESW_VLAN_VAWD1_IVL_MAC |
-+ REG_ESW_VLAN_VAWD1_VTAG_EN | (member << 16) |
-+ REG_ESW_VLAN_VAWD1_VALID);
-+ else
-+ mt7530_w32(eth, REG_ESW_VLAN_VAWD1, 0);
-+
-+ /* egress mode */
-+ val = 0;
-+ for (j = 0; j < MT7530_NUM_PORTS; j++) {
-+ if (etags & BIT(j))
-+ val |= ETAG_CTRL_TAG << (j * 2);
-+ else
-+ val |= ETAG_CTRL_UNTAG << (j * 2);
-+ }
-+ mt7530_w32(eth, REG_ESW_VLAN_VAWD2, val);
-+
-+ /* write to vlan table */
-+ mt7530_vtcr(eth, 1, i);
-+ }
-+
-+ /* Port Default PVID */
-+ for (i = 0; i < MT7530_NUM_PORTS; i++) {
-+ u32 val;
-+ val = mt7530_r32(eth, REG_ESW_PORT_PPBV1(i));
-+ val &= ~0xfff;
-+ val |= eth->port_entries[i].pvid;
-+ mt7530_w32(eth, REG_ESW_PORT_PPBV1(i), val);
-+ }
-+
-+ return 0;
-+}
-+
-+static int
-+mt7530_get_port_link(struct switch_dev *dev, int port,
-+ struct switch_port_link *link)
-+{
-+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
-+ u32 speed, pmsr;
-+
-+ if (port < 0 || port >= MT7530_NUM_PORTS)
-+ return -EINVAL;
-+
-+ pmsr = mt7530_r32(eth, 0x3008 + (0x100 * port));
-+
-+ link->link = pmsr & 1;
-+ link->duplex = (pmsr >> 1) & 1;
-+ speed = (pmsr >> 2) & 3;
-+
-+ switch (speed) {
-+ case 0:
-+ link->speed = SWITCH_PORT_SPEED_10;
-+ break;
-+ case 1:
-+ link->speed = SWITCH_PORT_SPEED_100;
-+ break;
-+ case 2:
-+ case 3: /* forced gige speed can be 2 or 3 */
-+ link->speed = SWITCH_PORT_SPEED_1000;
-+ break;
-+ default:
-+ link->speed = SWITCH_PORT_SPEED_UNKNOWN;
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
-+static const struct switch_attr mt7530_global[] = {
-+ {
-+ .type = SWITCH_TYPE_INT,
-+ .name = "enable_vlan",
-+ .description = "VLAN mode (1:enabled)",
-+ .max = 1,
-+ .id = MT7530_ATTR_ENABLE_VLAN,
-+ .get = mt7530_get_vlan_enable,
-+ .set = mt7530_set_vlan_enable,
-+ },
-+};
-+
-+static u64 get_mib_counter(struct mt7530_priv *eth, int i, int port)
-+{
-+ unsigned int port_base;
-+ u64 t;
-+
-+ port_base = MT7621_MIB_COUNTER_BASE +
-+ MT7621_MIB_COUNTER_PORT_OFFSET * port;
-+
-+ t = mt7530_r32(eth, port_base + mt7621_mibs[i].offset);
-+ if (mt7621_mibs[i].size == 2) {
-+ u64 hi;
-+
-+ hi = mt7530_r32(eth, port_base + mt7621_mibs[i].offset + 4);
-+ t |= hi << 32;
-+ }
-+
-+ return t;
-+}
-+
-+static int mt7621_sw_get_port_mib(struct switch_dev *dev,
-+ const struct switch_attr *attr,
-+ struct switch_val *val)
-+{
-+ static char buf[4096];
-+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
-+ int i, len = 0;
-+
-+ if (val->port_vlan >= MT7530_NUM_PORTS)
-+ return -EINVAL;
-+
-+ len += snprintf(buf + len, sizeof(buf) - len,
-+ "Port %d MIB counters\n", val->port_vlan);
-+
-+ for (i = 0; i < sizeof(mt7621_mibs) / sizeof(*mt7621_mibs); ++i) {
-+ u64 counter;
-+ len += snprintf(buf + len, sizeof(buf) - len,
-+ "%-11s: ", mt7621_mibs[i].name);
-+ counter = get_mib_counter(eth, i, val->port_vlan);
-+ len += snprintf(buf + len, sizeof(buf) - len, "%llu\n",
-+ counter);
-+ }
-+
-+ val->value.s = buf;
-+ val->len = len;
-+ return 0;
-+}
-+
-+static const struct switch_attr mt7621_port[] = {
-+ {
-+ .type = SWITCH_TYPE_STRING,
-+ .name = "mib",
-+ .description = "Get MIB counters for port",
-+ .get = mt7621_sw_get_port_mib,
-+ .set = NULL,
-+ },
-+};
-+
-+static const struct switch_attr mt7530_port[] = {
-+};
-+
-+static const struct switch_attr mt7530_vlan[] = {
-+ {
-+ .type = SWITCH_TYPE_INT,
-+ .name = "vid",
-+ .description = "VLAN ID (0-4094)",
-+ .set = mt7530_set_vid,
-+ .get = mt7530_get_vid,
-+ .max = 4094,
-+ },
-+};
-+
-+static const struct switch_dev_ops mt7621_ops = {
-+ .attr_global = {
-+ .attr = mt7530_global,
-+ .n_attr = ARRAY_SIZE(mt7530_global),
-+ },
-+/* .attr_port = {
-+ .attr = mt7621_port,
-+ .n_attr = ARRAY_SIZE(mt7621_port),
-+ },*/
-+ .attr_vlan = {
-+ .attr = mt7530_vlan,
-+ .n_attr = ARRAY_SIZE(mt7530_vlan),
-+ },
-+ .get_vlan_ports = mt7530_get_vlan_ports,
-+ .set_vlan_ports = mt7530_set_vlan_ports,
-+ .get_port_pvid = mt7530_get_port_pvid,
-+ .set_port_pvid = mt7530_set_port_pvid,
-+ .get_port_link = mt7530_get_port_link,
-+ .apply_config = mt7530_apply_config,
-+ .reset_switch = mt7530_reset_switch,
-+};
-+
-+static const struct switch_dev_ops mt7530_ops = {
-+ .attr_global = {
-+ .attr = mt7530_global,
-+ .n_attr = ARRAY_SIZE(mt7530_global),
-+ },
-+ .attr_port = {
-+ .attr = mt7530_port,
-+ .n_attr = ARRAY_SIZE(mt7530_port),
-+ },
-+ .attr_vlan = {
-+ .attr = mt7530_vlan,
-+ .n_attr = ARRAY_SIZE(mt7530_vlan),
-+ },
-+ .get_vlan_ports = mt7530_get_vlan_ports,
-+ .set_vlan_ports = mt7530_set_vlan_ports,
-+ .get_port_pvid = mt7530_get_port_pvid,
-+ .set_port_pvid = mt7530_set_port_pvid,
-+ .get_port_link = mt7530_get_port_link,
-+ .apply_config = mt7530_apply_config,
-+ .reset_switch = mt7530_reset_switch,
-+};
-+
-+int
-+mt7530_probe(struct device *dev, void __iomem *base, struct mii_bus *bus, int vlan)
-+{
-+ struct switch_dev *swdev;
-+ struct mt7530_priv *mt7530;
-+ struct mt7530_mapping *map;
-+ int ret;
-+
-+ mt7530 = devm_kzalloc(dev, sizeof(struct mt7530_priv), GFP_KERNEL);
-+ if (!mt7530)
-+ return -ENOMEM;
-+
-+ mt7530->base = base;
-+ mt7530->bus = bus;
-+ mt7530->global_vlan_enable = vlan;
-+
-+ swdev = &mt7530->swdev;
-+ if (bus) {
-+ swdev->alias = "mt7530";
-+ swdev->name = "mt7530";
-+ } else if (IS_ENABLED(CONFIG_MACH_MT7623)) {
-+ swdev->alias = "mt7623";
-+ swdev->name = "mt7623";
-+ } else if (IS_ENABLED(CONFIG_SOC_MT7621)) {
-+ swdev->alias = "mt7621";
-+ swdev->name = "mt7621";
-+ } else {
-+ swdev->alias = "mt7620";
-+ swdev->name = "mt7620";
-+ }
-+ swdev->cpu_port = MT7530_CPU_PORT;
-+ swdev->ports = MT7530_NUM_PORTS;
-+ swdev->vlans = MT7530_NUM_VLANS;
-+ if (IS_ENABLED(CONFIG_SOC_MT7621) || IS_ENABLED(CONFIG_MACH_MT7623))
-+ swdev->ops = &mt7621_ops;
-+ else
-+ swdev->ops = &mt7530_ops;
-+
-+ ret = register_switch(swdev, NULL);
-+ if (ret) {
-+ dev_err(dev, "failed to register mt7530\n");
-+ return ret;
-+ }
-+
-+ mt7530_reset_switch(swdev);
-+
-+ map = mt7530_find_mapping(dev->of_node);
-+ if (map)
-+ mt7530_apply_mapping(mt7530, map);
-+ mt7530_apply_config(swdev);
-+
-+ /* magic vodoo */
-+ if (!(IS_ENABLED(CONFIG_SOC_MT7621) || IS_ENABLED(CONFIG_MACH_MT7623)) && bus && mt7530_r32(mt7530, REG_HWTRAP) != 0x1117edf) {
-+ dev_info(dev, "fixing up MHWTRAP register - bootloader probably played with it\n");
-+ mt7530_w32(mt7530, REG_HWTRAP, 0x1117edf);
-+ }
-+ dev_info(dev, "loaded %s driver\n", swdev->name);
-+
-+ return 0;
-+}
-diff --git a/drivers/net/ethernet/mediatek/mt7530.h b/drivers/net/ethernet/mediatek/mt7530.h
-new file mode 100644
-index 0000000..1fc8c62
---- /dev/null
-+++ b/drivers/net/ethernet/mediatek/mt7530.h
-@@ -0,0 +1,20 @@
-+/*
-+ * 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.
-+ *
-+ * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
-+ */
-+
-+#ifndef _MT7530_H__
-+#define _MT7530_H__
-+
-+int mt7530_probe(struct device *dev, void __iomem *base, struct mii_bus *bus, int vlan);
-+
-+#endif
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 6557026..bb62b91 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -24,6 +24,9 @@
-
- #include "mtk_eth_soc.h"
-
-+/* the callback used by the driver core to bringup the switch */
-+int mtk_gsw_init(struct mtk_eth *eth);
-+
- static int mtk_msg_level = -1;
- module_param_named(msg_level, mtk_msg_level, int, 0);
- MODULE_PARM_DESC(msg_level, "Message level (-1=defaults,0=none,...,16=all)");
-@@ -69,7 +72,7 @@ static int mtk_mdio_busy_wait(struct mtk_eth *eth)
- return 0;
- if (time_after(jiffies, t_start + PHY_IAC_TIMEOUT))
- break;
-- usleep_range(10, 20);
-+// usleep_range(10, 20);
- }
-
- dev_err(eth->dev, "mdio: MDIO timeout\n");
-@@ -1408,15 +1411,6 @@ static int __init mtk_hw_init(struct mtk_eth *eth)
- reset_control_deassert(eth->rstc);
- usleep_range(10, 20);
-
-- /* Set GE2 driving and slew rate */
-- regmap_write(eth->pctl, GPIO_DRV_SEL10, 0xa00);
--
-- /* set GE2 TDSEL */
-- regmap_write(eth->pctl, GPIO_OD33_CTRL8, 0x5);
--
-- /* set GE2 TUNE */
-- regmap_write(eth->pctl, GPIO_BIAS_CTRL, 0x0);
--
- /* GE1, Force 1000M/FD, FC ON */
- mtk_w32(eth, MAC_MCR_FIXED_LINK, MTK_MAC_MCR(0));
-
-@@ -1439,6 +1433,8 @@ static int __init mtk_hw_init(struct mtk_eth *eth)
- if (err)
- return err;
-
-+ mtk_gsw_init(eth);
-+
- /* disable delay and normal interrupt */
- mtk_w32(eth, 0, MTK_QDMA_DELAY_INT);
- mtk_irq_disable(eth, MTK_TX_DONE_INT | MTK_RX_DONE_INT);
-@@ -1466,6 +1462,8 @@ static int __init mtk_hw_init(struct mtk_eth *eth)
- mtk_w32(eth, val, MTK_GDMA_FWD_CFG(i));
- }
-
-+ mt7623_gsw_config(eth);
-+
- return 0;
- }
-
-@@ -1721,7 +1719,7 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
- {
- struct mtk_mac *mac;
- const __be32 *_id = of_get_property(np, "reg", NULL);
-- int id, err;
-+ int id;
-
- if (!_id) {
- dev_err(eth->dev, "missing mac id\n");
-@@ -1755,8 +1753,8 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
- GFP_KERNEL);
- if (!mac->hw_stats) {
- dev_err(eth->dev, "failed to allocate counter memory\n");
-- err = -ENOMEM;
-- goto free_netdev;
-+ free_netdev(eth->netdev[id]);
-+ return -ENOMEM;
- }
- spin_lock_init(&mac->hw_stats->stats_lock);
- mac->hw_stats->reg_offset = id * MTK_STAT_OFFSET;
-@@ -1770,21 +1768,9 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
- eth->netdev[id]->features |= MTK_HW_FEATURES;
- eth->netdev[id]->ethtool_ops = &mtk_ethtool_ops;
-
-- err = register_netdev(eth->netdev[id]);
-- if (err) {
-- dev_err(eth->dev, "error bringing up device\n");
-- goto free_netdev;
-- }
- eth->netdev[id]->irq = eth->irq[0];
-- netif_info(eth, probe, eth->netdev[id],
-- "mediatek frame engine at 0x%08lx, irq %d\n",
-- eth->netdev[id]->base_addr, eth->irq[0]);
-
- return 0;
--
--free_netdev:
-- free_netdev(eth->netdev[id]);
-- return err;
- }
-
- static int mtk_probe(struct platform_device *pdev)
-@@ -1852,14 +1838,13 @@ static int mtk_probe(struct platform_device *pdev)
- clk_prepare_enable(eth->clk_gp1);
- clk_prepare_enable(eth->clk_gp2);
-
-+ eth->switch_np = of_parse_phandle(pdev->dev.of_node,
-+ "mediatek,switch", 0);
-+
- eth->dev = &pdev->dev;
- eth->msg_enable = netif_msg_init(mtk_msg_level, MTK_DEFAULT_MSG_ENABLE);
- INIT_WORK(&eth->pending_work, mtk_pending_work);
-
-- err = mtk_hw_init(eth);
-- if (err)
-- return err;
--
- for_each_child_of_node(pdev->dev.of_node, mac_np) {
- if (!of_device_is_compatible(mac_np,
- "mediatek,eth-mac"))
-@@ -1873,6 +1858,22 @@ static int mtk_probe(struct platform_device *pdev)
- goto err_free_dev;
- }
-
-+ err = mtk_hw_init(eth);
-+ if (err)
-+ return err;
-+
-+ for (i = 0; i < MTK_MAX_DEVS; i++) {
-+ if (!eth->netdev[i])
-+ continue;
-+ err = register_netdev(eth->netdev[i]);
-+ if (err)
-+ dev_err(eth->dev, "error bringing up device\n");
-+ else
-+ netif_info(eth, probe, eth->netdev[i],
-+ "mediatek frame engine at 0x%08lx, irq %d\n",
-+ eth->netdev[i]->base_addr, eth->irq[0]);
-+ }
-+
- /* we run 2 devices on the same DMA ring so we need a dummy device
- * for NAPI to work
- */
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index bf158f8..5093518 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -406,6 +406,8 @@ struct mtk_eth {
- struct mii_bus *mii_bus;
- struct work_struct pending_work;
-
-+ struct device_node *switch_np;
-+ void *sw_priv;
- };
-
- /* struct mtk_mac - the structure that holds the info about the MACs of the
-@@ -433,4 +435,6 @@ void mtk_stats_update_mac(struct mtk_mac *mac);
- void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg);
- u32 mtk_r32(struct mtk_eth *eth, unsigned reg);
-
-+int mt7623_gsw_config(struct mtk_eth *eth);
-+
- #endif /* MTK_ETH_H */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0089-net-next-mediatek-increase-watchdog_timeo.patch b/target/linux/mediatek/patches-4.4/0089-net-next-mediatek-increase-watchdog_timeo.patch
new file mode 100644
index 0000000000..96928d232a
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0089-net-next-mediatek-increase-watchdog_timeo.patch
@@ -0,0 +1,26 @@
+From 2cbf3f95a49925317ef4138ceaf7f7f30f353f0f Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Tue, 3 May 2016 03:17:53 +0200
+Subject: [PATCH 089/102] net-next: mediatek: increase watchdog_timeo
+
+During stress testing, after reducing the threshold value, we have seen
+TX timeouts that were caused by the watchdog_timeo value being too low.
+Increase the value to 5 * HZ which is a value commonly used by many other
+drivers.
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -1720,7 +1720,7 @@ static int mtk_add_mac(struct mtk_eth *e
+ mac->hw_stats->reg_offset = id * MTK_STAT_OFFSET;
+
+ SET_NETDEV_DEV(eth->netdev[id], eth->dev);
+- eth->netdev[id]->watchdog_timeo = HZ;
++ eth->netdev[id]->watchdog_timeo = 5 * HZ;
+ eth->netdev[id]->netdev_ops = &mtk_netdev_ops;
+ eth->netdev[id]->base_addr = (unsigned long)eth->base;
+ eth->netdev[id]->vlan_features = MTK_HW_FEATURES &
diff --git a/target/linux/mediatek/patches-4.4/0090-net-mediatek-v4.4-backports.patch b/target/linux/mediatek/patches-4.4/0090-net-mediatek-v4.4-backports.patch
deleted file mode 100644
index f26eaeaccc..0000000000
--- a/target/linux/mediatek/patches-4.4/0090-net-mediatek-v4.4-backports.patch
+++ /dev/null
@@ -1,77 +0,0 @@
-From 7d2bdde21bc72eb41878890149f2b9d05fc3af6e Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Mon, 11 Apr 2016 06:00:23 +0200
-Subject: [PATCH 90/91] net: mediatek: v4.4 backports
-
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 23 ++++++++++++++---------
- 1 file changed, 14 insertions(+), 9 deletions(-)
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index bb62b91..5d33053 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -207,7 +207,7 @@ static int mtk_phy_connect_node(struct mtk_eth *eth, struct mtk_mac *mac,
-
- dev_info(eth->dev,
- "connected mac %d to PHY at %s [uid=%08x, driver=%s]\n",
-- mac->id, phydev_name(phydev), phydev->phy_id,
-+ mac->id, dev_name(&phydev->dev), phydev->phy_id,
- phydev->drv->name);
-
- mac->phy_dev = phydev;
-@@ -1268,9 +1268,10 @@ static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth)
- return IRQ_NONE;
-
- if (status & MTK_RX_DONE_INT) {
-- if (likely(napi_schedule_prep(&eth->rx_napi)))
-+ if (likely(napi_schedule_prep(&eth->rx_napi))) {
-+ mtk_irq_disable(eth, MTK_RX_DONE_INT);
- __napi_schedule(&eth->rx_napi);
-- mtk_irq_disable(eth, MTK_RX_DONE_INT);
-+ }
- }
- mtk_w32(eth, status, MTK_QMTK_INT_STATUS);
-
-@@ -1289,9 +1290,10 @@ static irqreturn_t mtk_handle_irq_tx(int irq, void *_eth)
- return IRQ_NONE;
-
- if (status & MTK_TX_DONE_INT) {
-- if (likely(napi_schedule_prep(&eth->tx_napi)))
-+ if (likely(napi_schedule_prep(&eth->tx_napi))) {
-+ mtk_irq_disable(eth, MTK_TX_DONE_INT);
- __napi_schedule(&eth->tx_napi);
-- mtk_irq_disable(eth, MTK_TX_DONE_INT);
-+ }
- }
- mtk_w32(eth, status, MTK_QMTK_INT_STATUS);
-
-@@ -1383,6 +1385,7 @@ static int mtk_stop(struct net_device *dev)
- struct mtk_mac *mac = netdev_priv(dev);
- struct mtk_eth *eth = mac->hw;
-
-+ netif_carrier_off(dev);
- netif_tx_disable(dev);
- phy_stop(mac->phy_dev);
-
-@@ -1582,11 +1585,13 @@ static int mtk_set_settings(struct net_device *dev,
- {
- struct mtk_mac *mac = netdev_priv(dev);
-
-- if (cmd->phy_address != mac->phy_dev->mdio.addr) {
-- mac->phy_dev = mdiobus_get_phy(mac->hw->mii_bus,
-- cmd->phy_address);
-- if (!mac->phy_dev)
-+ if (cmd->phy_address != mac->phy_dev->addr) {
-+ if (mac->hw->mii_bus->phy_map[cmd->phy_address]) {
-+ mac->phy_dev =
-+ mac->hw->mii_bus->phy_map[cmd->phy_address];
-+ } else {
- return -ENODEV;
-+ }
- }
-
- return phy_ethtool_sset(mac->phy_dev, cmd);
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0090-net-next-mediatek-fix-off-by-one-in-the-TX-ring-allo.patch b/target/linux/mediatek/patches-4.4/0090-net-next-mediatek-fix-off-by-one-in-the-TX-ring-allo.patch
new file mode 100644
index 0000000000..b6f32fc451
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0090-net-next-mediatek-fix-off-by-one-in-the-TX-ring-allo.patch
@@ -0,0 +1,36 @@
+From 94425de9ede5ef0eafbfced65140c30e7c0b6c0d Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Tue, 3 May 2016 03:01:13 +0200
+Subject: [PATCH 090/102] net-next: mediatek: fix off by one in the TX ring
+ allocation
+
+The TX ring setup has an off by one error causing it to not utilise all
+descriptors. This has the side effect that we need to reset the next
+pointer at runtime to make it work. Fix the off by one and remove the
+code fixing the ring at runtime.
+
+Signed-off-by: Sean Wang <keyhaede@gmail.com>
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -934,7 +934,6 @@ static int mtk_poll_tx(struct mtk_eth *e
+ }
+ mtk_tx_unmap(eth->dev, tx_buf);
+
+- ring->last_free->txd2 = next_cpu;
+ ring->last_free = desc;
+ atomic_inc(&ring->free_count);
+
+@@ -1042,7 +1041,7 @@ static int mtk_tx_alloc(struct mtk_eth *
+
+ atomic_set(&ring->free_count, MTK_DMA_SIZE - 2);
+ ring->next_free = &ring->dma[0];
+- ring->last_free = &ring->dma[MTK_DMA_SIZE - 2];
++ ring->last_free = &ring->dma[MTK_DMA_SIZE - 1];
+ ring->thresh = MAX_SKB_FRAGS;
+
+ /* make sure that all changes to the dma ring are flushed before we
diff --git a/target/linux/mediatek/patches-4.4/0091-net-next-mediatek-WIP.patch b/target/linux/mediatek/patches-4.4/0091-net-next-mediatek-WIP.patch
deleted file mode 100644
index b852e67470..0000000000
--- a/target/linux/mediatek/patches-4.4/0091-net-next-mediatek-WIP.patch
+++ /dev/null
@@ -1,249 +0,0 @@
-From 34e10b96d5ccb99fb78251051bc5652b09359983 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Thu, 28 Apr 2016 07:58:22 +0200
-Subject: [PATCH 91/91] net-next: mediatek WIP
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 89 ++++++++++++---------------
- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 5 +-
- 2 files changed, 44 insertions(+), 50 deletions(-)
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 5d33053..2e05920 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -326,7 +326,7 @@ static inline void mtk_irq_disable(struct mtk_eth *eth, u32 mask)
- val = mtk_r32(eth, MTK_QDMA_INT_MASK);
- mtk_w32(eth, val & ~mask, MTK_QDMA_INT_MASK);
- /* flush write */
-- mtk_r32(eth, MTK_QDMA_INT_MASK);
-+// mtk_r32(eth, MTK_QDMA_INT_MASK);
- spin_unlock_irqrestore(&eth->irq_lock, flags);
- }
-
-@@ -339,7 +339,7 @@ static inline void mtk_irq_enable(struct mtk_eth *eth, u32 mask)
- val = mtk_r32(eth, MTK_QDMA_INT_MASK);
- mtk_w32(eth, val | mask, MTK_QDMA_INT_MASK);
- /* flush write */
-- mtk_r32(eth, MTK_QDMA_INT_MASK);
-+// mtk_r32(eth, MTK_QDMA_INT_MASK);
- spin_unlock_irqrestore(&eth->irq_lock, flags);
- }
-
-@@ -710,10 +710,26 @@ static inline int mtk_cal_txd_req(struct sk_buff *skb)
- return nfrags;
- }
-
-+static int mtk_queue_stopped(struct mtk_eth *eth)
-+{
-+ int i;
-+
-+ for (i = 0; i < MTK_MAC_COUNT; i++) {
-+ if (!eth->netdev[i])
-+ continue;
-+ if (netif_queue_stopped(eth->netdev[i]))
-+ return 1;
-+ }
-+
-+ return 0;
-+}
-+
- static void mtk_wake_queue(struct mtk_eth *eth)
- {
- int i;
-
-+ printk("%s:%s[%d]w\n", __FILE__, __func__, __LINE__);
-+
- for (i = 0; i < MTK_MAC_COUNT; i++) {
- if (!eth->netdev[i])
- continue;
-@@ -725,6 +741,7 @@ static void mtk_stop_queue(struct mtk_eth *eth)
- {
- int i;
-
-+ printk("%s:%s[%d]s\n", __FILE__, __func__, __LINE__);
- for (i = 0; i < MTK_MAC_COUNT; i++) {
- if (!eth->netdev[i])
- continue;
-@@ -775,12 +792,9 @@ static int mtk_start_xmit(struct sk_buff *skb, struct net_device *dev)
- if (mtk_tx_map(skb, dev, tx_num, ring, gso) < 0)
- goto drop;
-
-- if (unlikely(atomic_read(&ring->free_count) <= ring->thresh)) {
-+ if (unlikely(atomic_read(&ring->free_count) <= ring->thresh))
- mtk_stop_queue(eth);
-- if (unlikely(atomic_read(&ring->free_count) >
-- ring->thresh))
-- mtk_wake_queue(eth);
-- }
-+
- spin_unlock_irqrestore(&eth->page_lock, flags);
-
- return NETDEV_TX_OK;
-@@ -927,7 +941,6 @@ static int mtk_poll_tx(struct mtk_eth *eth, int budget)
- }
- mtk_tx_unmap(eth->dev, tx_buf);
-
-- ring->last_free->txd2 = next_cpu;
- ring->last_free = desc;
- atomic_inc(&ring->free_count);
-
-@@ -945,11 +958,8 @@ static int mtk_poll_tx(struct mtk_eth *eth, int budget)
- netdev_completed_queue(eth->netdev[i], done, bytes);
- }
-
-- /* read hw index again make sure no new tx packet */
-- if (cpu == dma && cpu == mtk_r32(eth, MTK_QTX_DRX_PTR))
-- mtk_w32(eth, MTK_TX_DONE_INT, MTK_QMTK_INT_STATUS);
--
-- if (atomic_read(&ring->free_count) > ring->thresh)
-+ if (mtk_queue_stopped(eth) &&
-+ (atomic_read(&ring->free_count) > ring->thresh))
- mtk_wake_queue(eth);
-
- return done;
-@@ -973,10 +983,11 @@ static int mtk_napi_tx(struct napi_struct *napi, int budget)
- int tx_done = 0;
-
- mtk_handle_status_irq(eth);
--
-- status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
-+ mtk_w32(eth, MTK_TX_DONE_INT, MTK_QMTK_INT_STATUS);
- tx_done = mtk_poll_tx(eth, budget);
-+
- if (unlikely(netif_msg_intr(eth))) {
-+ status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
- mask = mtk_r32(eth, MTK_QDMA_INT_MASK);
- dev_info(eth->dev,
- "done tx %d, intr 0x%08x/0x%x\n",
-@@ -1002,9 +1013,12 @@ static int mtk_napi_rx(struct napi_struct *napi, int budget)
- u32 status, mask;
- int rx_done = 0;
-
-- status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
-+ mtk_handle_status_irq(eth);
-+ mtk_w32(eth, MTK_RX_DONE_INT, MTK_QMTK_INT_STATUS);
- rx_done = mtk_poll_rx(napi, budget, eth);
-+
- if (unlikely(netif_msg_intr(eth))) {
-+ status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
- mask = mtk_r32(eth, MTK_QDMA_INT_MASK);
- dev_info(eth->dev,
- "done rx %d, intr 0x%08x/0x%x\n",
-@@ -1052,9 +1066,8 @@ static int mtk_tx_alloc(struct mtk_eth *eth)
-
- atomic_set(&ring->free_count, MTK_DMA_SIZE - 2);
- ring->next_free = &ring->dma[0];
-- ring->last_free = &ring->dma[MTK_DMA_SIZE - 2];
-- ring->thresh = max((unsigned long)MTK_DMA_SIZE >> 2,
-- MAX_SKB_FRAGS);
-+ ring->last_free = &ring->dma[MTK_DMA_SIZE - 1];
-+ ring->thresh = MAX_SKB_FRAGS;
-
- /* make sure that all changes to the dma ring are flushed before we
- * continue
-@@ -1259,21 +1272,11 @@ static void mtk_tx_timeout(struct net_device *dev)
- static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth)
- {
- struct mtk_eth *eth = _eth;
-- u32 status;
--
-- status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
-- status &= ~MTK_TX_DONE_INT;
--
-- if (unlikely(!status))
-- return IRQ_NONE;
-
-- if (status & MTK_RX_DONE_INT) {
-- if (likely(napi_schedule_prep(&eth->rx_napi))) {
-- mtk_irq_disable(eth, MTK_RX_DONE_INT);
-- __napi_schedule(&eth->rx_napi);
-- }
-+ if (likely(napi_schedule_prep(&eth->rx_napi))) {
-+ __napi_schedule(&eth->rx_napi);
-+ mtk_irq_disable(eth, MTK_RX_DONE_INT);
- }
-- mtk_w32(eth, status, MTK_QMTK_INT_STATUS);
-
- return IRQ_HANDLED;
- }
-@@ -1281,21 +1284,11 @@ static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth)
- static irqreturn_t mtk_handle_irq_tx(int irq, void *_eth)
- {
- struct mtk_eth *eth = _eth;
-- u32 status;
--
-- status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
-- status &= ~MTK_RX_DONE_INT;
--
-- if (unlikely(!status))
-- return IRQ_NONE;
-
-- if (status & MTK_TX_DONE_INT) {
-- if (likely(napi_schedule_prep(&eth->tx_napi))) {
-- mtk_irq_disable(eth, MTK_TX_DONE_INT);
-- __napi_schedule(&eth->tx_napi);
-- }
-+ if (likely(napi_schedule_prep(&eth->tx_napi))) {
-+ __napi_schedule(&eth->tx_napi);
-+ mtk_irq_disable(eth, MTK_TX_DONE_INT);
- }
-- mtk_w32(eth, status, MTK_QMTK_INT_STATUS);
-
- return IRQ_HANDLED;
- }
-@@ -1326,7 +1319,7 @@ static int mtk_start_dma(struct mtk_eth *eth)
- mtk_w32(eth,
- MTK_TX_WB_DDONE | MTK_RX_DMA_EN | MTK_TX_DMA_EN |
- MTK_RX_2B_OFFSET | MTK_DMA_SIZE_16DWORDS |
-- MTK_RX_BT_32DWORDS,
-+ MTK_RX_BT_32DWORDS | MTK_NDP_CO_PRO,
- MTK_QDMA_GLO_CFG);
-
- return 0;
-@@ -1440,7 +1433,7 @@ static int __init mtk_hw_init(struct mtk_eth *eth)
-
- /* disable delay and normal interrupt */
- mtk_w32(eth, 0, MTK_QDMA_DELAY_INT);
-- mtk_irq_disable(eth, MTK_TX_DONE_INT | MTK_RX_DONE_INT);
-+ mtk_irq_disable(eth, ~0);
- mtk_w32(eth, RST_GL_PSE, MTK_RST_GL);
- mtk_w32(eth, 0, MTK_RST_GL);
-
-@@ -1765,7 +1758,7 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
- mac->hw_stats->reg_offset = id * MTK_STAT_OFFSET;
-
- SET_NETDEV_DEV(eth->netdev[id], eth->dev);
-- eth->netdev[id]->watchdog_timeo = HZ;
-+ eth->netdev[id]->watchdog_timeo = 4 * HZ;
- eth->netdev[id]->netdev_ops = &mtk_netdev_ops;
- eth->netdev[id]->base_addr = (unsigned long)eth->base;
- eth->netdev[id]->vlan_features = MTK_HW_FEATURES &
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index 5093518..6b22445 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -18,9 +18,9 @@
- #define MTK_QDMA_PAGE_SIZE 2048
- #define MTK_MAX_RX_LENGTH 1536
- #define MTK_TX_DMA_BUF_LEN 0x3fff
--#define MTK_DMA_SIZE 256
--#define MTK_NAPI_WEIGHT 64
- #define MTK_MAC_COUNT 2
-+#define MTK_DMA_SIZE (256 * MTK_MAC_COUNT)
-+#define MTK_NAPI_WEIGHT (64 * MTK_MAC_COUNT)
- #define MTK_RX_ETH_HLEN (VLAN_ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN)
- #define MTK_RX_HLEN (NET_SKB_PAD + MTK_RX_ETH_HLEN + NET_IP_ALIGN)
- #define MTK_DMA_DUMMY_DESC 0xffffffff
-@@ -95,6 +95,7 @@
- #define MTK_QDMA_GLO_CFG 0x1A04
- #define MTK_RX_2B_OFFSET BIT(31)
- #define MTK_RX_BT_32DWORDS (3 << 11)
-+#define MTK_NDP_CO_PRO BIT(10)
- #define MTK_TX_WB_DDONE BIT(6)
- #define MTK_DMA_SIZE_16DWORDS (2 << 4)
- #define MTK_RX_DMA_BUSY BIT(3)
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0091-net-next-mediatek-only-wake-the-queue-if-it-is-stopp.patch b/target/linux/mediatek/patches-4.4/0091-net-next-mediatek-only-wake-the-queue-if-it-is-stopp.patch
new file mode 100644
index 0000000000..257634c4c3
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0091-net-next-mediatek-only-wake-the-queue-if-it-is-stopp.patch
@@ -0,0 +1,48 @@
+From 1473b4cce85760c0202a08e6a48ec51867dc1bf7 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Tue, 3 May 2016 04:01:38 +0200
+Subject: [PATCH 091/102] net-next: mediatek: only wake the queue if it is
+ stopped
+
+The current code unconditionally wakes up the queue at the end of each
+tx_poll action. Change the code to only wake up the queues if any of
+them have actually been stopped before.
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 17 ++++++++++++++++-
+ 1 file changed, 16 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -716,6 +716,20 @@ static inline int mtk_cal_txd_req(struct
+ return nfrags;
+ }
+
++static int mtk_queue_stopped(struct mtk_eth *eth)
++{
++ int i;
++
++ for (i = 0; i < MTK_MAC_COUNT; i++) {
++ if (!eth->netdev[i])
++ continue;
++ if (netif_queue_stopped(eth->netdev[i]))
++ return 1;
++ }
++
++ return 0;
++}
++
+ static void mtk_wake_queue(struct mtk_eth *eth)
+ {
+ int i;
+@@ -960,7 +974,8 @@ static int mtk_poll_tx(struct mtk_eth *e
+ if (!total)
+ return 0;
+
+- if (atomic_read(&ring->free_count) > ring->thresh)
++ if (mtk_queue_stopped(eth) &&
++ (atomic_read(&ring->free_count) > ring->thresh))
+ mtk_wake_queue(eth);
+
+ return total;
diff --git a/target/linux/mediatek/patches-4.4/0092-net-next-mediatek-remove-superfluous-queue-wake-up-c.patch b/target/linux/mediatek/patches-4.4/0092-net-next-mediatek-remove-superfluous-queue-wake-up-c.patch
new file mode 100644
index 0000000000..fe08958b5c
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0092-net-next-mediatek-remove-superfluous-queue-wake-up-c.patch
@@ -0,0 +1,36 @@
+From 538020913db04d199ce4d7e845444880e8200b5f Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Tue, 3 May 2016 05:40:38 +0200
+Subject: [PATCH 092/102] net-next: mediatek: remove superfluous queue wake up
+ call
+
+The code checks if the queue should be stopped because we are below the
+threshold of free descriptors only to check if it should be started again.
+If we do end up in a state where we are at the threshold limit, it makes
+more sense to just stop the queue and wait for the next IRQ to trigger the
+TX housekeeping again. There is no rush in enqueuing the next packet, it
+needs to wait for all the others in the queue to be dispatched first
+anyway.
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -795,12 +795,9 @@ static int mtk_start_xmit(struct sk_buff
+ if (mtk_tx_map(skb, dev, tx_num, ring, gso) < 0)
+ goto drop;
+
+- if (unlikely(atomic_read(&ring->free_count) <= ring->thresh)) {
++ if (unlikely(atomic_read(&ring->free_count) <= ring->thresh))
+ mtk_stop_queue(eth);
+- if (unlikely(atomic_read(&ring->free_count) >
+- ring->thresh))
+- mtk_wake_queue(eth);
+- }
++
+ spin_unlock_irqrestore(&eth->page_lock, flags);
+
+ return NETDEV_TX_OK;
diff --git a/target/linux/mediatek/patches-4.4/0093-net-next-mediatek-remove-superfluous-register-reads.patch b/target/linux/mediatek/patches-4.4/0093-net-next-mediatek-remove-superfluous-register-reads.patch
new file mode 100644
index 0000000000..3ddbbc6fd6
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0093-net-next-mediatek-remove-superfluous-register-reads.patch
@@ -0,0 +1,37 @@
+From 31428406bf4b9da2a322ae947096414ff0489fb5 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Tue, 3 May 2016 03:57:01 +0200
+Subject: [PATCH 093/102] net-next: mediatek: remove superfluous register
+ reads
+
+The driver was originally written for MIPS based SoC. These required the
+IRQ mask register to be read after writing it to ensure that the content
+was actually applied. As this version only works on ARM based SoC, we can
+safely remove the 2 reads as they ware not required.
+
+Signed-off-by: Sean Wang <keyhaede@gmail.com>
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 ----
+ 1 file changed, 4 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -335,8 +335,6 @@ static inline void mtk_irq_disable(struc
+
+ val = mtk_r32(eth, MTK_QDMA_INT_MASK);
+ mtk_w32(eth, val & ~mask, MTK_QDMA_INT_MASK);
+- /* flush write */
+- mtk_r32(eth, MTK_QDMA_INT_MASK);
+ }
+
+ static inline void mtk_irq_enable(struct mtk_eth *eth, u32 mask)
+@@ -345,8 +343,6 @@ static inline void mtk_irq_enable(struct
+
+ val = mtk_r32(eth, MTK_QDMA_INT_MASK);
+ mtk_w32(eth, val | mask, MTK_QDMA_INT_MASK);
+- /* flush write */
+- mtk_r32(eth, MTK_QDMA_INT_MASK);
+ }
+
+ static int mtk_set_mac_address(struct net_device *dev, void *p)
diff --git a/target/linux/mediatek/patches-4.4/0094-net-next-mediatek-don-t-use-intermediate-variables-t.patch b/target/linux/mediatek/patches-4.4/0094-net-next-mediatek-don-t-use-intermediate-variables-t.patch
new file mode 100644
index 0000000000..983d0c2712
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0094-net-next-mediatek-don-t-use-intermediate-variables-t.patch
@@ -0,0 +1,82 @@
+From 441d87495f33fd444a2b2a16f6df07892dac3f89 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Tue, 3 May 2016 04:12:35 +0200
+Subject: [PATCH 094/102] net-next: mediatek: don't use intermediate variables
+ to store IRQ masks
+
+The code currently uses variables to store and never modify the bit masks
+of interrupts. This is legacy code from an early version of the driver
+that supported MIPS based SoCs where the IRQ bits depended on the actual
+SoC. As the bits are the same for all ARM based SoC using this driver we
+can remove the intermediate variables.
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 22 ++++++++++------------
+ 1 file changed, 10 insertions(+), 12 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -806,7 +806,7 @@ drop:
+ }
+
+ static int mtk_poll_rx(struct napi_struct *napi, int budget,
+- struct mtk_eth *eth, u32 rx_intr)
++ struct mtk_eth *eth)
+ {
+ struct mtk_rx_ring *ring = &eth->rx_ring;
+ int idx = ring->calc_idx;
+@@ -894,7 +894,7 @@ release_desc:
+ }
+
+ if (done < budget)
+- mtk_w32(eth, rx_intr, MTK_QMTK_INT_STATUS);
++ mtk_w32(eth, MTK_RX_DONE_INT, MTK_QMTK_INT_STATUS);
+
+ return done;
+ }
+@@ -977,28 +977,26 @@ static int mtk_poll_tx(struct mtk_eth *e
+ static int mtk_poll(struct napi_struct *napi, int budget)
+ {
+ struct mtk_eth *eth = container_of(napi, struct mtk_eth, rx_napi);
+- u32 status, status2, mask, tx_intr, rx_intr, status_intr;
++ u32 status, status2, mask;
+ int tx_done, rx_done;
+ bool tx_again = false;
+
+ status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
+ status2 = mtk_r32(eth, MTK_INT_STATUS2);
+- tx_intr = MTK_TX_DONE_INT;
+- rx_intr = MTK_RX_DONE_INT;
+- status_intr = (MTK_GDM1_AF | MTK_GDM2_AF);
+ tx_done = 0;
+ rx_done = 0;
+ tx_again = 0;
+
+- if (status & tx_intr)
++ if (status & MTK_TX_DONE_INT)
+ tx_done = mtk_poll_tx(eth, budget, &tx_again);
+
+- if (status & rx_intr)
+- rx_done = mtk_poll_rx(napi, budget, eth, rx_intr);
++ if (status & MTK_RX_DONE_INT)
++ rx_done = mtk_poll_rx(napi, budget, eth);
+
+- if (unlikely(status2 & status_intr)) {
++ if (unlikely(status2 & (MTK_GDM1_AF | MTK_GDM2_AF))) {
+ mtk_stats_update(eth);
+- mtk_w32(eth, status_intr, MTK_INT_STATUS2);
++ mtk_w32(eth, (MTK_GDM1_AF | MTK_GDM2_AF),
++ MTK_INT_STATUS2);
+ }
+
+ if (unlikely(netif_msg_intr(eth))) {
+@@ -1016,7 +1014,7 @@ static int mtk_poll(struct napi_struct *
+ return budget;
+
+ napi_complete(napi);
+- mtk_irq_enable(eth, tx_intr | rx_intr);
++ mtk_irq_enable(eth, MTK_RX_DONE_INT | MTK_RX_DONE_INT);
+
+ return rx_done;
+ }
diff --git a/target/linux/mediatek/patches-4.4/0095-net-next-mediatek-add-IRQ-locking.patch b/target/linux/mediatek/patches-4.4/0095-net-next-mediatek-add-IRQ-locking.patch
new file mode 100644
index 0000000000..bf27aac15c
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0095-net-next-mediatek-add-IRQ-locking.patch
@@ -0,0 +1,64 @@
+From dd08d1ac4cfc86fbea5ee207b9615922ede88ec6 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Tue, 17 May 2016 06:01:45 +0200
+Subject: [PATCH 095/102] net-next: mediatek: add IRQ locking
+
+The code that enables and disables IRQs is missing proper locking. After
+adding the IRQ separation patch and routing the putting the RX and TX IRQs
+on different cores we experienced IRQ stalls. Fix this by adding proper
+locking. We use a dedicated lock to reduce the latency if the IRQ code.
+Otherwise it might wait for bottom code to finish before reenabling or
+disabling IRQs.
+
+Signed-off-by: Sean Wang <keyhaede@gmail.com>
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 7 +++++++
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 +
+ 2 files changed, 8 insertions(+)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -331,18 +331,24 @@ static void mtk_mdio_cleanup(struct mtk_
+
+ static inline void mtk_irq_disable(struct mtk_eth *eth, u32 mask)
+ {
++ unsigned long flags;
+ u32 val;
+
++ spin_lock_irqsave(&eth->irq_lock, flags);
+ val = mtk_r32(eth, MTK_QDMA_INT_MASK);
+ mtk_w32(eth, val & ~mask, MTK_QDMA_INT_MASK);
++ spin_unlock_irqrestore(&eth->irq_lock, flags);
+ }
+
+ static inline void mtk_irq_enable(struct mtk_eth *eth, u32 mask)
+ {
++ unsigned long flags;
+ u32 val;
+
++ spin_lock_irqsave(&eth->irq_lock, flags);
+ val = mtk_r32(eth, MTK_QDMA_INT_MASK);
+ mtk_w32(eth, val | mask, MTK_QDMA_INT_MASK);
++ spin_unlock_irqrestore(&eth->irq_lock, flags);
+ }
+
+ static int mtk_set_mac_address(struct net_device *dev, void *p)
+@@ -1771,6 +1777,7 @@ static int mtk_probe(struct platform_dev
+ return -EADDRNOTAVAIL;
+
+ spin_lock_init(&eth->page_lock);
++ spin_lock_init(&eth->irq_lock);
+
+ eth->ethsys = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "mediatek,ethsys");
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -373,6 +373,7 @@ struct mtk_eth {
+ void __iomem *base;
+ struct reset_control *rstc;
+ spinlock_t page_lock;
++ spinlock_t irq_lock;
+ struct net_device dummy_dev;
+ struct net_device *netdev[MTK_MAX_DEVS];
+ struct mtk_mac *mac[MTK_MAX_DEVS];
diff --git a/target/linux/mediatek/patches-4.4/0096-net-next-mediatek-add-support-for-IRQ-grouping.patch b/target/linux/mediatek/patches-4.4/0096-net-next-mediatek-add-support-for-IRQ-grouping.patch
new file mode 100644
index 0000000000..727073ebcd
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0096-net-next-mediatek-add-support-for-IRQ-grouping.patch
@@ -0,0 +1,361 @@
+From 190df1a9dbf4d8809b7f991194ce60e47f2290a2 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Wed, 23 Mar 2016 18:31:48 +0100
+Subject: [PATCH 096/102] net-next: mediatek: add support for IRQ grouping
+
+The ethernet core has 3 IRQs. using the IRQ grouping registers we are able
+to separate TX and RX IRQs, which allows us to service them on separate
+cores. This patch splits the irq handler into 2 separate functions, one for
+TX and another for RX. The TX housekeeping is split out into its own NAPI
+handler.
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 156 +++++++++++++++++----------
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h | 15 ++-
+ 2 files changed, 111 insertions(+), 60 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -905,14 +905,13 @@ release_desc:
+ return done;
+ }
+
+-static int mtk_poll_tx(struct mtk_eth *eth, int budget, bool *tx_again)
++static int mtk_poll_tx(struct mtk_eth *eth, int budget)
+ {
+ struct mtk_tx_ring *ring = &eth->tx_ring;
+ struct mtk_tx_dma *desc;
+ struct sk_buff *skb;
+ struct mtk_tx_buf *tx_buf;
+- int total = 0, done = 0;
+- unsigned int bytes = 0;
++ unsigned int bytes = 0, done = 0;
+ u32 cpu, dma;
+ static int condition;
+ int i;
+@@ -964,63 +963,82 @@ static int mtk_poll_tx(struct mtk_eth *e
+ netdev_completed_queue(eth->netdev[i], done, bytes);
+ }
+
+- /* read hw index again make sure no new tx packet */
+- if (cpu != dma || cpu != mtk_r32(eth, MTK_QTX_DRX_PTR))
+- *tx_again = true;
+- else
+- mtk_w32(eth, MTK_TX_DONE_INT, MTK_QMTK_INT_STATUS);
+-
+- if (!total)
+- return 0;
+-
+ if (mtk_queue_stopped(eth) &&
+ (atomic_read(&ring->free_count) > ring->thresh))
+ mtk_wake_queue(eth);
+
+- return total;
++ return done;
+ }
+
+-static int mtk_poll(struct napi_struct *napi, int budget)
++static void mtk_handle_status_irq(struct mtk_eth *eth)
+ {
+- struct mtk_eth *eth = container_of(napi, struct mtk_eth, rx_napi);
+- u32 status, status2, mask;
+- int tx_done, rx_done;
+- bool tx_again = false;
+-
+- status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
+- status2 = mtk_r32(eth, MTK_INT_STATUS2);
+- tx_done = 0;
+- rx_done = 0;
+- tx_again = 0;
+-
+- if (status & MTK_TX_DONE_INT)
+- tx_done = mtk_poll_tx(eth, budget, &tx_again);
+-
+- if (status & MTK_RX_DONE_INT)
+- rx_done = mtk_poll_rx(napi, budget, eth);
++ u32 status2 = mtk_r32(eth, MTK_INT_STATUS2);
+
+ if (unlikely(status2 & (MTK_GDM1_AF | MTK_GDM2_AF))) {
+ mtk_stats_update(eth);
+ mtk_w32(eth, (MTK_GDM1_AF | MTK_GDM2_AF),
+ MTK_INT_STATUS2);
+ }
++}
++
++static int mtk_napi_tx(struct napi_struct *napi, int budget)
++{
++ struct mtk_eth *eth = container_of(napi, struct mtk_eth, tx_napi);
++ u32 status, mask;
++ int tx_done = 0;
++
++ mtk_handle_status_irq(eth);
++ mtk_w32(eth, MTK_TX_DONE_INT, MTK_QMTK_INT_STATUS);
++ tx_done = mtk_poll_tx(eth, budget);
+
+ if (unlikely(netif_msg_intr(eth))) {
++ status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
+ mask = mtk_r32(eth, MTK_QDMA_INT_MASK);
+- netdev_info(eth->netdev[0],
+- "done tx %d, rx %d, intr 0x%08x/0x%x\n",
+- tx_done, rx_done, status, mask);
++ dev_info(eth->dev,
++ "done tx %d, intr 0x%08x/0x%x\n",
++ tx_done, status, mask);
+ }
+
+- if (tx_again || rx_done == budget)
++ if (tx_done == budget)
+ return budget;
+
+ status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
+- if (status & (tx_intr | rx_intr))
++ if (status & MTK_TX_DONE_INT)
+ return budget;
+
+ napi_complete(napi);
+- mtk_irq_enable(eth, MTK_RX_DONE_INT | MTK_RX_DONE_INT);
++ mtk_irq_enable(eth, MTK_TX_DONE_INT);
++
++ return tx_done;
++}
++
++static int mtk_napi_rx(struct napi_struct *napi, int budget)
++{
++ struct mtk_eth *eth = container_of(napi, struct mtk_eth, rx_napi);
++ u32 status, mask;
++ int rx_done = 0;
++
++ mtk_handle_status_irq(eth);
++ mtk_w32(eth, MTK_RX_DONE_INT, MTK_QMTK_INT_STATUS);
++ rx_done = mtk_poll_rx(napi, budget, eth);
++
++ if (unlikely(netif_msg_intr(eth))) {
++ status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
++ mask = mtk_r32(eth, MTK_QDMA_INT_MASK);
++ dev_info(eth->dev,
++ "done rx %d, intr 0x%08x/0x%x\n",
++ rx_done, status, mask);
++ }
++
++ if (rx_done == budget)
++ return budget;
++
++ status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
++ if (status & MTK_RX_DONE_INT)
++ return budget;
++
++ napi_complete(napi);
++ mtk_irq_enable(eth, MTK_RX_DONE_INT);
+
+ return rx_done;
+ }
+@@ -1256,22 +1274,26 @@ static void mtk_tx_timeout(struct net_de
+ schedule_work(&eth->pending_work);
+ }
+
+-static irqreturn_t mtk_handle_irq(int irq, void *_eth)
++static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth)
+ {
+ struct mtk_eth *eth = _eth;
+- u32 status;
+
+- status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
+- if (unlikely(!status))
+- return IRQ_NONE;
++ if (likely(napi_schedule_prep(&eth->rx_napi))) {
++ __napi_schedule(&eth->rx_napi);
++ mtk_irq_disable(eth, MTK_RX_DONE_INT);
++ }
+
+- if (likely(status & (MTK_RX_DONE_INT | MTK_TX_DONE_INT))) {
+- if (likely(napi_schedule_prep(&eth->rx_napi)))
+- __napi_schedule(&eth->rx_napi);
+- } else {
+- mtk_w32(eth, status, MTK_QMTK_INT_STATUS);
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t mtk_handle_irq_tx(int irq, void *_eth)
++{
++ struct mtk_eth *eth = _eth;
++
++ if (likely(napi_schedule_prep(&eth->tx_napi))) {
++ __napi_schedule(&eth->tx_napi);
++ mtk_irq_disable(eth, MTK_TX_DONE_INT);
+ }
+- mtk_irq_disable(eth, (MTK_RX_DONE_INT | MTK_TX_DONE_INT));
+
+ return IRQ_HANDLED;
+ }
+@@ -1284,7 +1306,7 @@ static void mtk_poll_controller(struct n
+ u32 int_mask = MTK_TX_DONE_INT | MTK_RX_DONE_INT;
+
+ mtk_irq_disable(eth, int_mask);
+- mtk_handle_irq(dev->irq, dev);
++ mtk_handle_irq(dev->irq[0], dev);
+ mtk_irq_enable(eth, int_mask);
+ }
+ #endif
+@@ -1320,6 +1342,7 @@ static int mtk_open(struct net_device *d
+ if (err)
+ return err;
+
++ napi_enable(&eth->tx_napi);
+ napi_enable(&eth->rx_napi);
+ mtk_irq_enable(eth, MTK_TX_DONE_INT | MTK_RX_DONE_INT);
+ }
+@@ -1368,6 +1391,7 @@ static int mtk_stop(struct net_device *d
+ return 0;
+
+ mtk_irq_disable(eth, MTK_TX_DONE_INT | MTK_RX_DONE_INT);
++ napi_disable(&eth->tx_napi);
+ napi_disable(&eth->rx_napi);
+
+ mtk_stop_dma(eth, MTK_QDMA_GLO_CFG);
+@@ -1405,7 +1429,11 @@ static int __init mtk_hw_init(struct mtk
+ /* Enable RX VLan Offloading */
+ mtk_w32(eth, 1, MTK_CDMP_EG_CTRL);
+
+- err = devm_request_irq(eth->dev, eth->irq, mtk_handle_irq, 0,
++ err = devm_request_irq(eth->dev, eth->irq[1], mtk_handle_irq_tx, 0,
++ dev_name(eth->dev), eth);
++ if (err)
++ return err;
++ err = devm_request_irq(eth->dev, eth->irq[2], mtk_handle_irq_rx, 0,
+ dev_name(eth->dev), eth);
+ if (err)
+ return err;
+@@ -1421,7 +1449,11 @@ static int __init mtk_hw_init(struct mtk
+ mtk_w32(eth, 0, MTK_RST_GL);
+
+ /* FE int grouping */
+- mtk_w32(eth, 0, MTK_FE_INT_GRP);
++ mtk_w32(eth, MTK_TX_DONE_INT, MTK_PDMA_INT_GRP1);
++ mtk_w32(eth, MTK_RX_DONE_INT, MTK_PDMA_INT_GRP2);
++ mtk_w32(eth, MTK_TX_DONE_INT, MTK_QDMA_INT_GRP1);
++ mtk_w32(eth, MTK_RX_DONE_INT, MTK_QDMA_INT_GRP2);
++ mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP);
+
+ for (i = 0; i < 2; i++) {
+ u32 val = mtk_r32(eth, MTK_GDMA_FWD_CFG(i));
+@@ -1469,7 +1501,9 @@ static void mtk_uninit(struct net_device
+ phy_disconnect(mac->phy_dev);
+ mtk_mdio_cleanup(eth);
+ mtk_irq_disable(eth, ~0);
+- free_irq(dev->irq, dev);
++ free_irq(eth->irq[0], dev);
++ free_irq(eth->irq[1], dev);
++ free_irq(eth->irq[2], dev);
+ }
+
+ static int mtk_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+@@ -1744,10 +1778,10 @@ static int mtk_add_mac(struct mtk_eth *e
+ dev_err(eth->dev, "error bringing up device\n");
+ goto free_netdev;
+ }
+- eth->netdev[id]->irq = eth->irq;
++ eth->netdev[id]->irq = eth->irq[0];
+ netif_info(eth, probe, eth->netdev[id],
+ "mediatek frame engine at 0x%08lx, irq %d\n",
+- eth->netdev[id]->base_addr, eth->netdev[id]->irq);
++ eth->netdev[id]->base_addr, eth->irq[0]);
+
+ return 0;
+
+@@ -1764,6 +1798,7 @@ static int mtk_probe(struct platform_dev
+ struct mtk_soc_data *soc;
+ struct mtk_eth *eth;
+ int err;
++ int i;
+
+ match = of_match_device(of_mtk_match, &pdev->dev);
+ soc = (struct mtk_soc_data *)match->data;
+@@ -1799,10 +1834,12 @@ static int mtk_probe(struct platform_dev
+ return PTR_ERR(eth->rstc);
+ }
+
+- eth->irq = platform_get_irq(pdev, 0);
+- if (eth->irq < 0) {
+- dev_err(&pdev->dev, "no IRQ resource found\n");
+- return -ENXIO;
++ for (i = 0; i < 3; i++) {
++ eth->irq[i] = platform_get_irq(pdev, i);
++ if (eth->irq[i] < 0) {
++ dev_err(&pdev->dev, "no IRQ%d resource found\n", i);
++ return -ENXIO;
++ }
+ }
+
+ eth->clk_ethif = devm_clk_get(&pdev->dev, "ethif");
+@@ -1843,7 +1880,9 @@ static int mtk_probe(struct platform_dev
+ * for NAPI to work
+ */
+ init_dummy_netdev(&eth->dummy_dev);
+- netif_napi_add(&eth->dummy_dev, &eth->rx_napi, mtk_poll,
++ netif_napi_add(&eth->dummy_dev, &eth->tx_napi, mtk_napi_tx,
++ MTK_NAPI_WEIGHT);
++ netif_napi_add(&eth->dummy_dev, &eth->rx_napi, mtk_napi_rx,
+ MTK_NAPI_WEIGHT);
+
+ platform_set_drvdata(pdev, eth);
+@@ -1864,6 +1903,7 @@ static int mtk_remove(struct platform_de
+ clk_disable_unprepare(eth->clk_gp1);
+ clk_disable_unprepare(eth->clk_gp2);
+
++ netif_napi_del(&eth->tx_napi);
+ netif_napi_del(&eth->rx_napi);
+ mtk_cleanup(eth);
+ platform_set_drvdata(pdev, NULL);
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -68,6 +68,10 @@
+ /* Unicast Filter MAC Address Register - High */
+ #define MTK_GDMA_MAC_ADRH(x) (0x50C + (x * 0x1000))
+
++/* PDMA Interrupt grouping registers */
++#define MTK_PDMA_INT_GRP1 0xa50
++#define MTK_PDMA_INT_GRP2 0xa54
++
+ /* QDMA TX Queue Configuration Registers */
+ #define MTK_QTX_CFG(x) (0x1800 + (x * 0x10))
+ #define QDMA_RES_THRES 4
+@@ -125,6 +129,11 @@
+ #define MTK_TX_DONE_INT (MTK_TX_DONE_INT0 | MTK_TX_DONE_INT1 | \
+ MTK_TX_DONE_INT2 | MTK_TX_DONE_INT3)
+
++/* QDMA Interrupt grouping registers */
++#define MTK_QDMA_INT_GRP1 0x1a20
++#define MTK_QDMA_INT_GRP2 0x1a24
++#define MTK_RLS_DONE_INT BIT(0)
++
+ /* QDMA Interrupt Status Register */
+ #define MTK_QDMA_INT_MASK 0x1A1C
+
+@@ -356,7 +365,8 @@ struct mtk_rx_ring {
+ * @dma_refcnt: track how many netdevs are using the DMA engine
+ * @tx_ring: Pointer to the memore holding info about the TX ring
+ * @rx_ring: Pointer to the memore holding info about the RX ring
+- * @rx_napi: The NAPI struct
++ * @tx_napi: The TX NAPI struct
++ * @rx_napi: The RX NAPI struct
+ * @scratch_ring: Newer SoCs need memory for a second HW managed TX ring
+ * @phy_scratch_ring: physical address of scratch_ring
+ * @scratch_head: The scratch memory that scratch_ring points to.
+@@ -377,7 +387,7 @@ struct mtk_eth {
+ struct net_device dummy_dev;
+ struct net_device *netdev[MTK_MAX_DEVS];
+ struct mtk_mac *mac[MTK_MAX_DEVS];
+- int irq;
++ int irq[3];
+ u32 msg_enable;
+ unsigned long sysclk;
+ struct regmap *ethsys;
+@@ -385,6 +395,7 @@ struct mtk_eth {
+ atomic_t dma_refcnt;
+ struct mtk_tx_ring tx_ring;
+ struct mtk_rx_ring rx_ring;
++ struct napi_struct tx_napi;
+ struct napi_struct rx_napi;
+ struct mtk_tx_dma *scratch_ring;
+ dma_addr_t phy_scratch_ring;
diff --git a/target/linux/mediatek/patches-4.4/0098-net-next-mediatek-only-trigger-the-tx-watchdog-reset.patch b/target/linux/mediatek/patches-4.4/0098-net-next-mediatek-only-trigger-the-tx-watchdog-reset.patch
new file mode 100644
index 0000000000..cc18be53b4
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0098-net-next-mediatek-only-trigger-the-tx-watchdog-reset.patch
@@ -0,0 +1,57 @@
+From cd1343c14328a5de1a58c47b81b8a2febb31d542 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Tue, 10 May 2016 11:16:30 +0200
+Subject: [PATCH 098/102] net-next: mediatek: only trigger the tx watchdog
+ reset when all devices are stalled
+
+Signed-off-by: Sean Wang <keyhaede@gmail.com>
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 14 ++++++++++++--
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 +
+ 2 files changed, 13 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -1267,11 +1267,21 @@ static void mtk_tx_timeout(struct net_de
+ {
+ struct mtk_mac *mac = netdev_priv(dev);
+ struct mtk_eth *eth = mac->hw;
++ int i, reset = 0;
+
+ eth->netdev[mac->id]->stats.tx_errors++;
+ netif_err(eth, tx_err, dev,
+ "transmit timed out\n");
+- schedule_work(&eth->pending_work);
++
++ for (i = 0; i < MTK_MAC_COUNT; i++) {
++ if (!eth->netdev[i] ||
++ time_after(jiffies, dev_trans_start(eth->netdev[i]) +
++ MTK_WDT_TIMEOUT))
++ reset++;
++ }
++
++ if (reset == MTK_MAC_COUNT)
++ schedule_work(&eth->pending_work);
+ }
+
+ static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth)
+@@ -1765,7 +1775,7 @@ static int mtk_add_mac(struct mtk_eth *e
+ mac->hw_stats->reg_offset = id * MTK_STAT_OFFSET;
+
+ SET_NETDEV_DEV(eth->netdev[id], eth->dev);
+- eth->netdev[id]->watchdog_timeo = 5 * HZ;
++ eth->netdev[id]->watchdog_timeo = MTK_WDT_TIMEOUT;
+ eth->netdev[id]->netdev_ops = &mtk_netdev_ops;
+ eth->netdev[id]->base_addr = (unsigned long)eth->base;
+ eth->netdev[id]->vlan_features = MTK_HW_FEATURES &
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -15,6 +15,7 @@
+ #ifndef MTK_ETH_H
+ #define MTK_ETH_H
+
++#define MTK_WDT_TIMEOUT (4 * HZ)
+ #define MTK_QDMA_PAGE_SIZE 2048
+ #define MTK_MAX_RX_LENGTH 1536
+ #define MTK_TX_DMA_BUF_LEN 0x3fff
diff --git a/target/linux/mediatek/patches-4.4/0101-net-mediatek-add-gsw-mt7530-driver.patch b/target/linux/mediatek/patches-4.4/0101-net-mediatek-add-gsw-mt7530-driver.patch
new file mode 100644
index 0000000000..4d931fc0fa
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0101-net-mediatek-add-gsw-mt7530-driver.patch
@@ -0,0 +1,2360 @@
+From 6b8a7257e7bcb56782c3f8048311670fe6a80209 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 11 Apr 2016 03:11:54 +0200
+Subject: [PATCH 101/102] net: mediatek add gsw/mt7530 driver
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/net/ethernet/mediatek/Makefile | 2 +-
+ drivers/net/ethernet/mediatek/gsw_mt7620.h | 251 +++++++
+ drivers/net/ethernet/mediatek/gsw_mt7623.c | 1084 +++++++++++++++++++++++++++
+ drivers/net/ethernet/mediatek/mt7530.c | 808 ++++++++++++++++++++
+ drivers/net/ethernet/mediatek/mt7530.h | 20 +
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 59 +-
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h | 5 +
+ 7 files changed, 2199 insertions(+), 30 deletions(-)
+ create mode 100644 drivers/net/ethernet/mediatek/gsw_mt7620.h
+ create mode 100644 drivers/net/ethernet/mediatek/gsw_mt7623.c
+ create mode 100644 drivers/net/ethernet/mediatek/mt7530.c
+ create mode 100644 drivers/net/ethernet/mediatek/mt7530.h
+
+--- a/drivers/net/ethernet/mediatek/Makefile
++++ b/drivers/net/ethernet/mediatek/Makefile
+@@ -2,4 +2,4 @@
+ # Makefile for the Mediatek SoCs built-in ethernet macs
+ #
+
+-obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth_soc.o
++obj-$(CONFIG_NET_MEDIATEK_SOC) += mt7530.o gsw_mt7623.o mtk_eth_soc.o
+--- /dev/null
++++ b/drivers/net/ethernet/mediatek/gsw_mt7620.h
+@@ -0,0 +1,251 @@
++/* 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; version 2 of the License
++ *
++ * 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.
++ *
++ * Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
++ * Copyright (C) 2009-2016 Felix Fietkau <nbd@nbd.name>
++ * Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
++ */
++
++#ifndef _RALINK_GSW_MT7620_H__
++#define _RALINK_GSW_MT7620_H__
++
++#define GSW_REG_PHY_TIMEOUT (5 * HZ)
++
++#define MT7620_GSW_REG_PIAC 0x0004
++
++#define GSW_NUM_VLANS 16
++#define GSW_NUM_VIDS 4096
++#define GSW_NUM_PORTS 7
++#define GSW_PORT6 6
++
++#define GSW_MDIO_ACCESS BIT(31)
++#define GSW_MDIO_READ BIT(19)
++#define GSW_MDIO_WRITE BIT(18)
++#define GSW_MDIO_START BIT(16)
++#define GSW_MDIO_ADDR_SHIFT 20
++#define GSW_MDIO_REG_SHIFT 25
++
++#define GSW_REG_PORT_PMCR(x) (0x3000 + (x * 0x100))
++#define GSW_REG_PORT_STATUS(x) (0x3008 + (x * 0x100))
++#define GSW_REG_SMACCR0 0x3fE4
++#define GSW_REG_SMACCR1 0x3fE8
++#define GSW_REG_CKGCR 0x3ff0
++
++#define GSW_REG_IMR 0x7008
++#define GSW_REG_ISR 0x700c
++#define GSW_REG_GPC1 0x7014
++
++#define SYSC_REG_CHIP_REV_ID 0x0c
++#define SYSC_REG_CFG 0x10
++#define SYSC_REG_CFG1 0x14
++#define RST_CTRL_MCM BIT(2)
++#define SYSC_PAD_RGMII2_MDIO 0x58
++#define SYSC_GPIO_MODE 0x60
++
++#define PORT_IRQ_ST_CHG 0x7f
++
++#define MT7621_ESW_PHY_POLLING 0x0000
++#define MT7620_ESW_PHY_POLLING 0x7000
++
++#define PMCR_IPG BIT(18)
++#define PMCR_MAC_MODE BIT(16)
++#define PMCR_FORCE BIT(15)
++#define PMCR_TX_EN BIT(14)
++#define PMCR_RX_EN BIT(13)
++#define PMCR_BACKOFF BIT(9)
++#define PMCR_BACKPRES BIT(8)
++#define PMCR_RX_FC BIT(5)
++#define PMCR_TX_FC BIT(4)
++#define PMCR_SPEED(_x) (_x << 2)
++#define PMCR_DUPLEX BIT(1)
++#define PMCR_LINK BIT(0)
++
++#define PHY_AN_EN BIT(31)
++#define PHY_PRE_EN BIT(30)
++#define PMY_MDC_CONF(_x) ((_x & 0x3f) << 24)
++
++/* ethernet subsystem config register */
++#define ETHSYS_SYSCFG0 0x14
++/* ethernet subsystem clock register */
++#define ETHSYS_CLKCFG0 0x2c
++#define ETHSYS_TRGMII_CLK_SEL362_5 BIT(11)
++
++/* p5 RGMII wrapper TX clock control register */
++#define MT7530_P5RGMIITXCR 0x7b04
++/* p5 RGMII wrapper RX clock control register */
++#define MT7530_P5RGMIIRXCR 0x7b00
++/* TRGMII TDX ODT registers */
++#define MT7530_TRGMII_TD0_ODT 0x7a54
++#define MT7530_TRGMII_TD1_ODT 0x7a5c
++#define MT7530_TRGMII_TD2_ODT 0x7a64
++#define MT7530_TRGMII_TD3_ODT 0x7a6c
++#define MT7530_TRGMII_TD4_ODT 0x7a74
++#define MT7530_TRGMII_TD5_ODT 0x7a7c
++/* TRGMII TCK ctrl register */
++#define MT7530_TRGMII_TCK_CTRL 0x7a78
++/* TRGMII Tx ctrl register */
++#define MT7530_TRGMII_TXCTRL 0x7a40
++/* port 6 extended control register */
++#define MT7530_P6ECR 0x7830
++/* IO driver control register */
++#define MT7530_IO_DRV_CR 0x7810
++/* top signal control register */
++#define MT7530_TOP_SIG_CTRL 0x7808
++/* modified hwtrap register */
++#define MT7530_MHWTRAP 0x7804
++/* hwtrap status register */
++#define MT7530_HWTRAP 0x7800
++/* status interrupt register */
++#define MT7530_SYS_INT_STS 0x700c
++/* system nterrupt register */
++#define MT7530_SYS_INT_EN 0x7008
++/* system control register */
++#define MT7530_SYS_CTRL 0x7000
++/* port MAC status register */
++#define MT7530_PMSR_P(x) (0x3008 + (x * 0x100))
++/* port MAC control register */
++#define MT7530_PMCR_P(x) (0x3000 + (x * 0x100))
++
++#define MT7621_XTAL_SHIFT 6
++#define MT7621_XTAL_MASK 0x7
++#define MT7621_XTAL_25 6
++#define MT7621_XTAL_40 3
++#define MT7621_MDIO_DRV_MASK (3 << 4)
++#define MT7621_GE1_MODE_MASK (3 << 12)
++
++#define TRGMII_TXCTRL_TXC_INV BIT(30)
++#define P6ECR_INTF_MODE_RGMII BIT(1)
++#define P5RGMIIRXCR_C_ALIGN BIT(8)
++#define P5RGMIIRXCR_DELAY_2 BIT(1)
++#define P5RGMIITXCR_DELAY_2 (BIT(8) | BIT(2))
++
++/* TOP_SIG_CTRL bits */
++#define TOP_SIG_CTRL_NORMAL (BIT(17) | BIT(16))
++
++/* MHWTRAP bits */
++#define MHWTRAP_MANUAL BIT(16)
++#define MHWTRAP_P5_MAC_SEL BIT(13)
++#define MHWTRAP_P6_DIS BIT(8)
++#define MHWTRAP_P5_RGMII_MODE BIT(7)
++#define MHWTRAP_P5_DIS BIT(6)
++#define MHWTRAP_PHY_ACCESS BIT(5)
++
++/* HWTRAP bits */
++#define HWTRAP_XTAL_SHIFT 9
++#define HWTRAP_XTAL_MASK 0x3
++
++/* SYS_CTRL bits */
++#define SYS_CTRL_SW_RST BIT(1)
++#define SYS_CTRL_REG_RST BIT(0)
++
++/* PMCR bits */
++#define PMCR_IFG_XMIT_96 BIT(18)
++#define PMCR_MAC_MODE BIT(16)
++#define PMCR_FORCE_MODE BIT(15)
++#define PMCR_TX_EN BIT(14)
++#define PMCR_RX_EN BIT(13)
++#define PMCR_BACK_PRES_EN BIT(9)
++#define PMCR_BACKOFF_EN BIT(8)
++#define PMCR_TX_FC_EN BIT(5)
++#define PMCR_RX_FC_EN BIT(4)
++#define PMCR_FORCE_SPEED_1000 BIT(3)
++#define PMCR_FORCE_FDX BIT(1)
++#define PMCR_FORCE_LNK BIT(0)
++#define PMCR_FIXED_LINK (PMCR_IFG_XMIT_96 | PMCR_MAC_MODE | \
++ PMCR_FORCE_MODE | PMCR_TX_EN | PMCR_RX_EN | \
++ PMCR_BACK_PRES_EN | PMCR_BACKOFF_EN | \
++ PMCR_FORCE_SPEED_1000 | PMCR_FORCE_FDX | \
++ PMCR_FORCE_LNK)
++
++#define PMCR_FIXED_LINK_FC (PMCR_FIXED_LINK | \
++ PMCR_TX_FC_EN | PMCR_RX_FC_EN)
++
++/* TRGMII control registers */
++#define GSW_INTF_MODE 0x390
++#define GSW_TRGMII_TD0_ODT 0x354
++#define GSW_TRGMII_TD1_ODT 0x35c
++#define GSW_TRGMII_TD2_ODT 0x364
++#define GSW_TRGMII_TD3_ODT 0x36c
++#define GSW_TRGMII_TXCTL_ODT 0x374
++#define GSW_TRGMII_TCK_ODT 0x37c
++#define GSW_TRGMII_RCK_CTRL 0x300
++
++#define INTF_MODE_TRGMII BIT(1)
++#define TRGMII_RCK_CTRL_RX_RST BIT(31)
++
++
++/* possible XTAL speed */
++#define MT7623_XTAL_40 0
++#define MT7623_XTAL_20 1
++#define MT7623_XTAL_25 3
++
++/* GPIO port control registers */
++#define GPIO_OD33_CTRL8 0x4c0
++#define GPIO_BIAS_CTRL 0xed0
++#define GPIO_DRV_SEL10 0xf00
++
++/* on MT7620 the functio of port 4 can be software configured */
++enum {
++ PORT4_EPHY = 0,
++ PORT4_EXT,
++};
++
++/* struct mt7620_gsw - the structure that holds the SoC specific data
++ * @dev: The Device struct
++ * @base: The base address
++ * @piac_offset: The PIAC base may change depending on SoC
++ * @irq: The IRQ we are using
++ * @port4: The port4 mode on MT7620
++ * @autopoll: Is MDIO autopolling enabled
++ * @ethsys: The ethsys register map
++ * @pctl: The pin control register map
++ * @clk_trgpll: The trgmii pll clock
++ */
++struct mt7620_gsw {
++ struct mtk_eth *eth;
++ struct device *dev;
++ void __iomem *base;
++ u32 piac_offset;
++ int irq;
++ int port4;
++ unsigned long int autopoll;
++
++ struct regmap *ethsys;
++ struct regmap *pctl;
++
++ struct clk *clk_trgpll;
++
++ int trgmii_force;
++ bool wllll;
++};
++
++/* switch register I/O wrappers */
++void mtk_switch_w32(struct mt7620_gsw *gsw, u32 val, unsigned reg);
++u32 mtk_switch_r32(struct mt7620_gsw *gsw, unsigned reg);
++
++/* the callback used by the driver core to bringup the switch */
++int mtk_gsw_init(struct mtk_eth *eth);
++
++/* MDIO access wrappers */
++int mt7620_mdio_write(struct mii_bus *bus, int phy_addr, int phy_reg, u16 val);
++int mt7620_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg);
++void mt7620_mdio_link_adjust(struct mtk_eth *eth, int port);
++int mt7620_has_carrier(struct mtk_eth *eth);
++void mt7620_print_link_state(struct mtk_eth *eth, int port, int link,
++ int speed, int duplex);
++void mt7530_mdio_w32(struct mt7620_gsw *gsw, u32 reg, u32 val);
++u32 mt7530_mdio_r32(struct mt7620_gsw *gsw, u32 reg);
++void mt7530_mdio_m32(struct mt7620_gsw *gsw, u32 mask, u32 set, u32 reg);
++
++u32 _mtk_mdio_write(struct mtk_eth *eth, u32 phy_addr,
++ u32 phy_register, u32 write_data);
++u32 _mtk_mdio_read(struct mtk_eth *eth, int phy_addr, int phy_reg);
++void mt7620_handle_carrier(struct mtk_eth *eth);
++
++#endif
+--- /dev/null
++++ b/drivers/net/ethernet/mediatek/gsw_mt7623.c
+@@ -0,0 +1,1084 @@
++/* 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; version 2 of the License
++ *
++ * 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.
++ *
++ * Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
++ * Copyright (C) 2009-2016 Felix Fietkau <nbd@nbd.name>
++ * Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/platform_device.h>
++#include <linux/of_device.h>
++#include <linux/of_irq.h>
++#include <linux/of_gpio.h>
++#include <linux/of_mdio.h>
++#include <linux/clk.h>
++#include <linux/mfd/syscon.h>
++#include <linux/regulator/consumer.h>
++#include <linux/pm_runtime.h>
++#include <linux/regmap.h>
++#include <linux/reset.h>
++#include <linux/mii.h>
++#include <linux/interrupt.h>
++#include <linux/netdevice.h>
++#include <linux/dma-mapping.h>
++#include <linux/phy.h>
++#include <linux/ethtool.h>
++#include <linux/version.h>
++#include <linux/atomic.h>
++
++#include "mtk_eth_soc.h"
++#include "gsw_mt7620.h"
++#include "mt7530.h"
++
++#define ETHSYS_CLKCFG0 0x2c
++#define ETHSYS_TRGMII_CLK_SEL362_5 BIT(11)
++
++void mt7530_mdio_w32(struct mt7620_gsw *gsw, u32 reg, u32 val)
++{
++ _mtk_mdio_write(gsw->eth, 0x1f, 0x1f, (reg >> 6) & 0x3ff);
++ _mtk_mdio_write(gsw->eth, 0x1f, (reg >> 2) & 0xf, val & 0xffff);
++ _mtk_mdio_write(gsw->eth, 0x1f, 0x10, val >> 16);
++}
++
++u32 mt7530_mdio_r32(struct mt7620_gsw *gsw, u32 reg)
++{
++ u16 high, low;
++
++ _mtk_mdio_write(gsw->eth, 0x1f, 0x1f, (reg >> 6) & 0x3ff);
++ low = _mtk_mdio_read(gsw->eth, 0x1f, (reg >> 2) & 0xf);
++ high = _mtk_mdio_read(gsw->eth, 0x1f, 0x10);
++
++ return (high << 16) | (low & 0xffff);
++}
++
++void mt7530_mdio_m32(struct mt7620_gsw *gsw, u32 mask, u32 set, u32 reg)
++{
++ u32 val = mt7530_mdio_r32(gsw, reg);
++
++ val &= mask;
++ val |= set;
++ mt7530_mdio_w32(gsw, reg, val);
++}
++
++void mtk_switch_w32(struct mt7620_gsw *gsw, u32 val, unsigned reg)
++{
++ mtk_w32(gsw->eth, val, reg + 0x10000);
++}
++
++u32 mtk_switch_r32(struct mt7620_gsw *gsw, unsigned reg)
++{
++ return mtk_r32(gsw->eth, reg + 0x10000);
++}
++
++void mtk_switch_m32(struct mt7620_gsw *gsw, u32 mask, u32 set, unsigned reg)
++{
++ u32 val = mtk_switch_r32(gsw, reg);
++
++ val &= mask;
++ val |= set;
++
++ mtk_switch_w32(gsw, val, reg);
++}
++
++int mt7623_gsw_config(struct mtk_eth *eth)
++{
++ if (eth->mii_bus && eth->mii_bus->phy_map[0x1f])
++ mt7530_probe(eth->dev, NULL, eth->mii_bus, 1);
++
++ return 0;
++}
++
++static irqreturn_t gsw_interrupt_mt7623(int irq, void *_eth)
++{
++ struct mtk_eth *eth = (struct mtk_eth *)_eth;
++ struct mt7620_gsw *gsw = (struct mt7620_gsw *)eth->sw_priv;
++ u32 reg, i;
++
++ reg = mt7530_mdio_r32(gsw, 0x700c);
++
++ for (i = 0; i < 5; i++)
++ if (reg & BIT(i)) {
++ unsigned int link;
++
++ link = mt7530_mdio_r32(gsw,
++ 0x3008 + (i * 0x100)) & 0x1;
++
++ if (link)
++ dev_info(gsw->dev,
++ "port %d link up\n", i);
++ else
++ dev_info(gsw->dev,
++ "port %d link down\n", i);
++ }
++
++// mt7620_handle_carrier(eth);
++ mt7530_mdio_w32(gsw, 0x700c, 0x1f);
++
++ return IRQ_HANDLED;
++}
++
++static void wait_loop(struct mt7620_gsw *gsw)
++{
++ int i;
++ int read_data;
++
++ for (i = 0; i < 320; i = i + 1)
++ read_data = mtk_switch_r32(gsw, 0x610);
++}
++
++static void trgmii_calibration_7623(struct mt7620_gsw *gsw)
++{
++
++ unsigned int tap_a[5] = { 0, 0, 0, 0, 0 }; /* minumum delay for all correct */
++ unsigned int tap_b[5] = { 0, 0, 0, 0, 0 }; /* maximum delay for all correct */
++ unsigned int final_tap[5];
++ unsigned int rxc_step_size;
++ unsigned int rxd_step_size;
++ unsigned int read_data;
++ unsigned int tmp;
++ unsigned int rd_wd;
++ int i;
++ unsigned int err_cnt[5];
++ unsigned int init_toggle_data;
++ unsigned int err_flag[5];
++ unsigned int err_total_flag;
++ unsigned int training_word;
++ unsigned int rd_tap;
++ u32 val;
++
++ u32 TRGMII_7623_base;
++ u32 TRGMII_7623_RD_0;
++ u32 TRGMII_RCK_CTRL;
++
++ TRGMII_7623_base = 0x300; /* 0xFB110300 */
++ TRGMII_7623_RD_0 = TRGMII_7623_base + 0x10;
++ TRGMII_RCK_CTRL = TRGMII_7623_base;
++ rxd_step_size = 0x1;
++ rxc_step_size = 0x4;
++ init_toggle_data = 0x00000055;
++ training_word = 0x000000AC;
++
++ /* RX clock gating in MT7623 */
++ mtk_switch_m32(gsw, 0x3fffffff, 0, TRGMII_7623_base + 0x04);
++
++ /* Assert RX reset in MT7623 */
++ mtk_switch_m32(gsw, 0, 0x80000000, TRGMII_7623_base + 0x00);
++
++ /* Set TX OE edge in MT7623 */
++ mtk_switch_m32(gsw, 0, 0x00002000, TRGMII_7623_base + 0x78);
++
++ /* Disable RX clock gating in MT7623 */
++ mtk_switch_m32(gsw, 0, 0xC0000000, TRGMII_7623_base + 0x04);
++
++ /* Release RX reset in MT7623 */
++ mtk_switch_m32(gsw, 0x7fffffff, 0, TRGMII_7623_base);
++
++ for (i = 0; i < 5; i++)
++ mtk_switch_m32(gsw, 0, 0x80000000, TRGMII_7623_RD_0 + i * 8);
++
++ pr_err("Enable Training Mode in MT7530\n");
++ read_data = mt7530_mdio_r32(gsw, 0x7A40);
++ read_data |= 0xC0000000;
++ mt7530_mdio_w32(gsw, 0x7A40, read_data); /* Enable Training Mode in MT7530 */
++ err_total_flag = 0;
++ pr_err("Adjust RXC delay in MT7623\n");
++ read_data = 0x0;
++ while (err_total_flag == 0 && read_data != 0x68) {
++ pr_err("2nd Enable EDGE CHK in MT7623\n");
++ /* Enable EDGE CHK in MT7623 */
++ for (i = 0; i < 5; i++)
++ mtk_switch_m32(gsw, 0x4fffffff, 0x40000000, TRGMII_7623_RD_0 + i * 8);
++
++ wait_loop(gsw);
++ err_total_flag = 1;
++ for (i = 0; i < 5; i++) {
++ err_cnt[i] =
++ mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8) >> 8;
++ err_cnt[i] &= 0x0000000f;
++ rd_wd = mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8) >> 16;
++ rd_wd &= 0x000000ff;
++ val = mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8);
++ pr_err("ERR_CNT = %d, RD_WD =%x, TRGMII_7623_RD_0=%x\n",
++ err_cnt[i], rd_wd, val);
++ if (err_cnt[i] != 0) {
++ err_flag[i] = 1;
++ } else if (rd_wd != 0x55) {
++ err_flag[i] = 1;
++ } else {
++ err_flag[i] = 0;
++ }
++ err_total_flag = err_flag[i] & err_total_flag;
++ }
++
++ pr_err("2nd Disable EDGE CHK in MT7623\n");
++ /* Disable EDGE CHK in MT7623 */
++ for (i = 0; i < 5; i++)
++ mtk_switch_m32(gsw, 0x4fffffff, 0x40000000, TRGMII_7623_RD_0 + i * 8);
++ wait_loop(gsw);
++ pr_err("2nd Disable EDGE CHK in MT7623\n");
++ /* Adjust RXC delay */
++ /* RX clock gating in MT7623 */
++ mtk_switch_m32(gsw, 0x3fffffff, 0, TRGMII_7623_base + 0x04);
++ read_data = mtk_switch_r32(gsw, TRGMII_7623_base);
++ if (err_total_flag == 0) {
++ tmp = (read_data & 0x0000007f) + rxc_step_size;
++ pr_err(" RXC delay = %d\n", tmp);
++ read_data >>= 8;
++ read_data &= 0xffffff80;
++ read_data |= tmp;
++ read_data <<= 8;
++ read_data &= 0xffffff80;
++ read_data |= tmp;
++ mtk_switch_w32(gsw, read_data, TRGMII_7623_base);
++ } else {
++ tmp = (read_data & 0x0000007f) + 16;
++ pr_err(" RXC delay = %d\n", tmp);
++ read_data >>= 8;
++ read_data &= 0xffffff80;
++ read_data |= tmp;
++ read_data <<= 8;
++ read_data &= 0xffffff80;
++ read_data |= tmp;
++ mtk_switch_w32(gsw, read_data, TRGMII_7623_base);
++ }
++ read_data &= 0x000000ff;
++
++ /* Disable RX clock gating in MT7623 */
++ mtk_switch_m32(gsw, 0, 0xC0000000, TRGMII_7623_base + 0x04);
++ for (i = 0; i < 5; i++)
++ mtk_switch_m32(gsw, 0, 0x80000000, TRGMII_7623_RD_0 + i * 8);
++ }
++
++ /* Read RD_WD MT7623 */
++ for (i = 0; i < 5; i++) {
++ rd_tap = 0;
++ while (err_flag[i] != 0 && rd_tap != 128) {
++ /* Enable EDGE CHK in MT7623 */
++ mtk_switch_m32(gsw, 0x4fffffff, 0x40000000, TRGMII_7623_RD_0 + i * 8);
++ wait_loop(gsw);
++
++ read_data = mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8);
++ err_cnt[i] = (read_data >> 8) & 0x0000000f; /* Read MT7623 Errcnt */
++ rd_wd = (read_data >> 16) & 0x000000ff;
++ if (err_cnt[i] != 0 || rd_wd != 0x55) {
++ err_flag[i] = 1;
++ } else {
++ err_flag[i] = 0;
++ }
++ /* Disable EDGE CHK in MT7623 */
++ mtk_switch_m32(gsw, 0x4fffffff, 0x40000000, TRGMII_7623_RD_0 + i * 8);
++ wait_loop(gsw);
++ if (err_flag[i] != 0) {
++ rd_tap = (read_data & 0x0000007f) + rxd_step_size; /* Add RXD delay in MT7623 */
++ read_data = (read_data & 0xffffff80) | rd_tap;
++ mtk_switch_w32(gsw, read_data,
++ TRGMII_7623_RD_0 + i * 8);
++ tap_a[i] = rd_tap;
++ } else {
++ rd_tap = (read_data & 0x0000007f) + 48;
++ read_data = (read_data & 0xffffff80) | rd_tap;
++ mtk_switch_w32(gsw, read_data,
++ TRGMII_7623_RD_0 + i * 8);
++ }
++
++ }
++ pr_err("MT7623 %dth bit Tap_a = %d\n", i, tap_a[i]);
++ }
++ /* pr_err("Last While Loop\n"); */
++ for (i = 0; i < 5; i++) {
++ while ((err_flag[i] == 0) && (rd_tap != 128)) {
++ read_data = mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8);
++ rd_tap = (read_data & 0x0000007f) + rxd_step_size; /* Add RXD delay in MT7623 */
++ read_data = (read_data & 0xffffff80) | rd_tap;
++ mtk_switch_w32(gsw, read_data, TRGMII_7623_RD_0 + i * 8);
++ /* Enable EDGE CHK in MT7623 */
++ val =
++ mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8) | 0x40000000;
++ val &= 0x4fffffff;
++ mtk_switch_w32(gsw, val, TRGMII_7623_RD_0 + i * 8);
++ wait_loop(gsw);
++ read_data = mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8);
++ err_cnt[i] = (read_data >> 8) & 0x0000000f; /* Read MT7623 Errcnt */
++ rd_wd = (read_data >> 16) & 0x000000ff;
++ if (err_cnt[i] != 0 || rd_wd != 0x55) {
++ err_flag[i] = 1;
++ } else {
++ err_flag[i] = 0;
++ }
++
++ /* Disable EDGE CHK in MT7623 */
++ mtk_switch_m32(gsw, 0x4fffffff, 0x40000000, TRGMII_7623_RD_0 + i * 8);
++ wait_loop(gsw);
++
++ }
++
++ tap_b[i] = rd_tap; /* -rxd_step_size; */
++ pr_err("MT7623 %dth bit Tap_b = %d\n", i, tap_b[i]);
++ final_tap[i] = (tap_a[i] + tap_b[i]) / 2; /* Calculate RXD delay = (TAP_A + TAP_B)/2 */
++ read_data = (read_data & 0xffffff80) | final_tap[i];
++ mtk_switch_w32(gsw, read_data, TRGMII_7623_RD_0 + i * 8);
++ }
++
++ read_data = mt7530_mdio_r32(gsw, 0x7A40);
++ read_data &= 0x3fffffff;
++ mt7530_mdio_w32(gsw, 0x7A40, read_data);
++}
++
++static void trgmii_calibration_7530(struct mt7620_gsw *gsw)
++{
++
++ unsigned int tap_a[5] = { 0, 0, 0, 0, 0 };
++ unsigned int tap_b[5] = { 0, 0, 0, 0, 0 };
++ unsigned int final_tap[5];
++ unsigned int rxc_step_size;
++ unsigned int rxd_step_size;
++ unsigned int read_data;
++ unsigned int tmp = 0;
++ int i;
++ unsigned int err_cnt[5];
++ unsigned int rd_wd;
++ unsigned int init_toggle_data;
++ unsigned int err_flag[5];
++ unsigned int err_total_flag;
++ unsigned int training_word;
++ unsigned int rd_tap;
++
++ u32 TRGMII_7623_base;
++ u32 TRGMII_7530_RD_0;
++ u32 TRGMII_RCK_CTRL;
++ u32 TRGMII_7530_base;
++ u32 TRGMII_7530_TX_base;
++ u32 val;
++
++ TRGMII_7623_base = 0x300;
++ TRGMII_7530_base = 0x7A00;
++ TRGMII_7530_RD_0 = TRGMII_7530_base + 0x10;
++ TRGMII_RCK_CTRL = TRGMII_7623_base;
++ rxd_step_size = 0x1;
++ rxc_step_size = 0x8;
++ init_toggle_data = 0x00000055;
++ training_word = 0x000000AC;
++
++ TRGMII_7530_TX_base = TRGMII_7530_base + 0x50;
++
++ /* pr_err("Calibration begin ........\n"); */
++ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x40) | 0x80000000;
++ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x40);
++ read_data = mt7530_mdio_r32(gsw, 0x7a10);
++ /* pr_err("TRGMII_7530_RD_0 is %x\n", read_data); */
++
++ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base + 0x04);
++ read_data &= 0x3fffffff;
++ mt7530_mdio_w32(gsw, TRGMII_7530_base + 0x04, read_data); /* RX clock gating in MT7530 */
++
++ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base + 0x78);
++ read_data |= 0x00002000;
++ mt7530_mdio_w32(gsw, TRGMII_7530_base + 0x78, read_data); /* Set TX OE edge in MT7530 */
++
++ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base);
++ read_data |= 0x80000000;
++ mt7530_mdio_w32(gsw, TRGMII_7530_base, read_data); /* Assert RX reset in MT7530 */
++
++ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base);
++ read_data &= 0x7fffffff;
++ mt7530_mdio_w32(gsw, TRGMII_7530_base, read_data); /* Release RX reset in MT7530 */
++
++ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base + 0x04);
++ read_data |= 0xC0000000;
++ mt7530_mdio_w32(gsw, TRGMII_7530_base + 0x04, read_data); /* Disable RX clock gating in MT7530 */
++
++ /* pr_err("Enable Training Mode in MT7623\n"); */
++ /*Enable Training Mode in MT7623 */
++ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x40) | 0x80000000;
++ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x40);
++ if (gsw->trgmii_force == 2000) {
++ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x40) | 0xC0000000;
++ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x40);
++ } else {
++ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x40) | 0x80000000;
++ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x40);
++ }
++ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x078) & 0xfffff0ff;
++ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x078);
++ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x50) & 0xfffff0ff;
++ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x50);
++ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x58) & 0xfffff0ff;
++ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x58);
++ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x60) & 0xfffff0ff;
++ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x60);
++ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x68) & 0xfffff0ff;
++ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x68);
++ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x70) & 0xfffff0ff;
++ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x70);
++ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x78) & 0x00000800;
++ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x78);
++ err_total_flag = 0;
++ /* pr_err("Adjust RXC delay in MT7530\n"); */
++ read_data = 0x0;
++ while (err_total_flag == 0 && (read_data != 0x68)) {
++ /* pr_err("2nd Enable EDGE CHK in MT7530\n"); */
++ /* Enable EDGE CHK in MT7530 */
++ for (i = 0; i < 5; i++) {
++ read_data =
++ mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8);
++ read_data |= 0x40000000;
++ read_data &= 0x4fffffff;
++ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8,
++ read_data);
++ wait_loop(gsw);
++ /* pr_err("2nd Disable EDGE CHK in MT7530\n"); */
++ err_cnt[i] =
++ mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8);
++ /* pr_err("***** MT7530 %dth bit ERR_CNT =%x\n",i, err_cnt[i]); */
++ /* pr_err("MT7530 %dth bit ERR_CNT =%x\n",i, err_cnt[i]); */
++ err_cnt[i] >>= 8;
++ err_cnt[i] &= 0x0000ff0f;
++ rd_wd = err_cnt[i] >> 8;
++ rd_wd &= 0x000000ff;
++ err_cnt[i] &= 0x0000000f;
++ /* read_data = mt7530_mdio_r32(gsw,0x7a10,&read_data); */
++ if (err_cnt[i] != 0) {
++ err_flag[i] = 1;
++ } else if (rd_wd != 0x55) {
++ err_flag[i] = 1;
++ } else {
++ err_flag[i] = 0;
++ }
++ if (i == 0) {
++ err_total_flag = err_flag[i];
++ } else {
++ err_total_flag = err_flag[i] & err_total_flag;
++ }
++ /* Disable EDGE CHK in MT7530 */
++ read_data =
++ mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8);
++ read_data |= 0x40000000;
++ read_data &= 0x4fffffff;
++ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8,
++ read_data);
++ wait_loop(gsw);
++ }
++ /*Adjust RXC delay */
++ if (err_total_flag == 0) {
++ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base);
++ read_data |= 0x80000000;
++ mt7530_mdio_w32(gsw, TRGMII_7530_base, read_data); /* Assert RX reset in MT7530 */
++
++ read_data =
++ mt7530_mdio_r32(gsw, TRGMII_7530_base + 0x04);
++ read_data &= 0x3fffffff;
++ mt7530_mdio_w32(gsw, TRGMII_7530_base + 0x04, read_data); /* RX clock gating in MT7530 */
++
++ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base);
++ tmp = read_data;
++ tmp &= 0x0000007f;
++ tmp += rxc_step_size;
++ /* pr_err("Current rxc delay = %d\n", tmp); */
++ read_data &= 0xffffff80;
++ read_data |= tmp;
++ mt7530_mdio_w32(gsw, TRGMII_7530_base, read_data);
++ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base);
++ /* pr_err("Current RXC delay = %x\n", read_data); */
++
++ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base);
++ read_data &= 0x7fffffff;
++ mt7530_mdio_w32(gsw, TRGMII_7530_base, read_data); /* Release RX reset in MT7530 */
++
++ read_data =
++ mt7530_mdio_r32(gsw, TRGMII_7530_base + 0x04);
++ read_data |= 0xc0000000;
++ mt7530_mdio_w32(gsw, TRGMII_7530_base + 0x04, read_data); /* Disable RX clock gating in MT7530 */
++ pr_err("####### MT7530 RXC delay is %d\n", tmp);
++ }
++ read_data = tmp;
++ }
++ pr_err("Finish RXC Adjustment while loop\n");
++
++ /* pr_err("Read RD_WD MT7530\n"); */
++ /* Read RD_WD MT7530 */
++ for (i = 0; i < 5; i++) {
++ rd_tap = 0;
++ while (err_flag[i] != 0 && rd_tap != 128) {
++ /* Enable EDGE CHK in MT7530 */
++ read_data =
++ mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8);
++ read_data |= 0x40000000;
++ read_data &= 0x4fffffff;
++ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8,
++ read_data);
++ wait_loop(gsw);
++ err_cnt[i] = (read_data >> 8) & 0x0000000f;
++ rd_wd = (read_data >> 16) & 0x000000ff;
++ if (err_cnt[i] != 0 || rd_wd != 0x55) {
++ err_flag[i] = 1;
++ } else {
++ err_flag[i] = 0;
++ }
++ if (err_flag[i] != 0) {
++ rd_tap = (read_data & 0x0000007f) + rxd_step_size; /* Add RXD delay in MT7530 */
++ read_data = (read_data & 0xffffff80) | rd_tap;
++ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8,
++ read_data);
++ tap_a[i] = rd_tap;
++ } else {
++ tap_a[i] = (read_data & 0x0000007f); /* Record the min delay TAP_A */
++ rd_tap = tap_a[i] + 0x4;
++ read_data = (read_data & 0xffffff80) | rd_tap;
++ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8,
++ read_data);
++ }
++
++ /* Disable EDGE CHK in MT7530 */
++ read_data =
++ mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8);
++ read_data |= 0x40000000;
++ read_data &= 0x4fffffff;
++ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8,
++ read_data);
++ wait_loop(gsw);
++
++ }
++ pr_err("MT7530 %dth bit Tap_a = %d\n", i, tap_a[i]);
++ }
++
++ /* pr_err("Last While Loop\n"); */
++ for (i = 0; i < 5; i++) {
++ rd_tap = 0;
++ while (err_flag[i] == 0 && (rd_tap != 128)) {
++ /* Enable EDGE CHK in MT7530 */
++ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8);
++ read_data |= 0x40000000;
++ read_data &= 0x4fffffff;
++ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8,
++ read_data);
++ wait_loop(gsw);
++ err_cnt[i] = (read_data >> 8) & 0x0000000f;
++ rd_wd = (read_data >> 16) & 0x000000ff;
++ if (err_cnt[i] != 0 || rd_wd != 0x55)
++ err_flag[i] = 1;
++ else
++ err_flag[i] = 0;
++
++ if (err_flag[i] == 0 && (rd_tap != 128)) {
++ /* Add RXD delay in MT7530 */
++ rd_tap = (read_data & 0x0000007f) + rxd_step_size;
++ read_data = (read_data & 0xffffff80) | rd_tap;
++ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8,
++ read_data);
++ }
++ /* Disable EDGE CHK in MT7530 */
++ read_data =
++ mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8);
++ read_data |= 0x40000000;
++ read_data &= 0x4fffffff;
++ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8,
++ read_data);
++ wait_loop(gsw);
++ }
++ tap_b[i] = rd_tap; /* - rxd_step_size; */
++ pr_err("MT7530 %dth bit Tap_b = %d\n", i, tap_b[i]);
++ /* Calculate RXD delay = (TAP_A + TAP_B)/2 */
++ final_tap[i] = (tap_a[i] + tap_b[i]) / 2;
++ /* pr_err("########****** MT7530 %dth bit Final Tap = %d\n", i, final_tap[i]); */
++
++ read_data = (read_data & 0xffffff80) | final_tap[i];
++ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, read_data);
++ }
++
++ if (gsw->trgmii_force == 2000)
++ mtk_switch_m32(gsw, 0x7fffffff, 0, TRGMII_7623_base + 0x40);
++ else
++ mtk_switch_m32(gsw, 0x3fffffff, 0, TRGMII_7623_base + 0x40);
++
++}
++
++static void mt7530_trgmii_clock_setting(struct mt7620_gsw *gsw, u32 xtal_mode)
++{
++
++ u32 regValue;
++
++ /* TRGMII Clock */
++ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x410);
++ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x1);
++ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x404);
++ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
++
++ if (xtal_mode == 1) {
++ /* 25MHz */
++ if (gsw->trgmii_force == 2600)
++ /* 325MHz */
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x1a00);
++ else if (gsw->trgmii_force == 2000)
++ /* 250MHz */
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x1400);
++ } else if (xtal_mode == 2) {
++ /* 40MHz */
++ if (gsw->trgmii_force == 2600)
++ /* 325MHz */
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x1040);
++ else if (gsw->trgmii_force == 2000)
++ /* 250MHz */
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x0c80);
++ }
++ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x405);
++ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x0);
++ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x409);
++ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
++ if (xtal_mode == 1)
++ /* 25MHz */
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x0057);
++ else
++ /* 40MHz */
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x0087);
++ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x40a);
++ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
++ if (xtal_mode == 1)
++ /* 25MHz */
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x0057);
++ else
++ /* 40MHz */
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x0087);
++
++ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x403);
++ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x1800);
++
++ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x403);
++ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x1c00);
++
++ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x401);
++ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
++ _mtk_mdio_write(gsw->eth, 0, 14, 0xc020);
++
++ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x406);
++ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
++ _mtk_mdio_write(gsw->eth, 0, 14, 0xa030);
++
++ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x406);
++ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
++ _mtk_mdio_write(gsw->eth, 0, 14, 0xa038);
++
++// udelay(120); /* for MT7623 bring up test */
++
++ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x410);
++ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x3);
++
++ regValue = mt7530_mdio_r32(gsw, 0x7830);
++ regValue &= 0xFFFFFFFC;
++ regValue |= 0x00000001;
++ mt7530_mdio_w32(gsw, 0x7830, regValue);
++
++ regValue = mt7530_mdio_r32(gsw, 0x7a40);
++ regValue &= ~(0x1 << 30);
++ regValue &= ~(0x1 << 28);
++ mt7530_mdio_w32(gsw, 0x7a40, regValue);
++
++ mt7530_mdio_w32(gsw, 0x7a78, 0x55);
++// udelay(100); /* for mt7623 bring up test */
++
++ mtk_switch_m32(gsw, 0x7fffffff, 0, 0x300);
++
++ trgmii_calibration_7623(gsw);
++ trgmii_calibration_7530(gsw);
++
++ mtk_switch_m32(gsw, 0, 0x80000000, 0x300);
++ mtk_switch_m32(gsw, 0, 0x7fffffff, 0x300);
++
++ /*MT7530 RXC reset */
++ regValue = mt7530_mdio_r32(gsw, 0x7a00);
++ regValue |= (0x1 << 31);
++ mt7530_mdio_w32(gsw, 0x7a00, regValue);
++ mdelay(1);
++ regValue &= ~(0x1 << 31);
++ mt7530_mdio_w32(gsw, 0x7a00, regValue);
++ mdelay(100);
++}
++
++static void mt7623_hw_init(struct mtk_eth *eth, struct mt7620_gsw *gsw, struct device_node *np)
++{
++ u32 i;
++ u32 val;
++ u32 xtal_mode;
++
++ regmap_update_bits(gsw->ethsys, ETHSYS_CLKCFG0,
++ ETHSYS_TRGMII_CLK_SEL362_5,
++ ETHSYS_TRGMII_CLK_SEL362_5);
++
++ /* reset the TRGMII core */
++ mtk_switch_m32(gsw, 0, INTF_MODE_TRGMII, GSW_INTF_MODE);
++ /* Assert MT7623 RXC reset */
++ mtk_switch_m32(gsw, 0, TRGMII_RCK_CTRL_RX_RST, GSW_TRGMII_RCK_CTRL);
++
++ /* Hardware reset Switch */
++ device_reset(eth->dev);
++
++ /* Wait for Switch Reset Completed*/
++ for (i = 0; i < 100; i++) {
++ mdelay(10);
++ if (mt7530_mdio_r32(gsw, MT7530_HWTRAP))
++ break;
++ }
++
++ /* turn off all PHYs */
++ for (i = 0; i <= 4; i++) {
++ val = _mtk_mdio_read(gsw->eth, i, 0x0);
++ val |= BIT(11);
++ _mtk_mdio_write(gsw->eth, i, 0x0, val);
++ }
++
++ /* reset the switch */
++ mt7530_mdio_w32(gsw, MT7530_SYS_CTRL,
++ SYS_CTRL_SW_RST | SYS_CTRL_REG_RST);
++ udelay(100);
++
++ /* GE1, Force 1000M/FD, FC ON */
++ mt7530_mdio_w32(gsw, MT7530_PMCR_P(6), PMCR_FIXED_LINK_FC);
++
++ /* GE2, Force 1000M/FD, FC ON */
++ mt7530_mdio_w32(gsw, MT7530_PMCR_P(5), PMCR_FIXED_LINK_FC);
++
++ /* Enable Port 6, P5 as GMAC5, P5 disable */
++ val = mt7530_mdio_r32(gsw, MT7530_MHWTRAP);
++ if (gsw->eth->mac[0] &&
++ of_phy_is_fixed_link(gsw->eth->mac[0]->of_node))
++ /* Enable Port 6 */
++ val &= ~MHWTRAP_P6_DIS;
++ else
++ /* Disable Port 6 */
++ val |= MHWTRAP_P6_DIS;
++ if (gsw->eth->mac[1] &&
++ of_phy_is_fixed_link(gsw->eth->mac[1]->of_node)) {
++ /* Enable Port 5 */
++ val &= ~MHWTRAP_P5_DIS;
++ /* Port 5 as PHY */
++ val &= ~MHWTRAP_P5_MAC_SEL;
++ } else {
++ /* Disable Port 5 */
++ val |= MHWTRAP_P5_DIS;
++ /* Port 5 as GMAC */
++ val |= MHWTRAP_P5_MAC_SEL;
++ val |= BIT(7);
++ mt7530_mdio_w32(gsw, MT7530_PMCR_P(5), 0x8000);
++ }
++ /* gphy to port 0/4 */
++ if (gsw->wllll)
++ val |= BIT(20);
++ else
++ val &= ~BIT(20);
++
++ /* Set MT7530 phy direct access mode**/
++ val &= ~MHWTRAP_PHY_ACCESS;
++ /* manual override of HW-Trap */
++ val |= MHWTRAP_MANUAL;
++ mt7530_mdio_w32(gsw, MT7530_MHWTRAP, val);
++ dev_info(gsw->dev, "Setting MHWTRAP to 0x%08x\n", val);
++
++ val = mt7530_mdio_r32(gsw, 0x7800);
++ val = (val >> 9) & 0x3;
++ if (val == 0x3) {
++ xtal_mode = 1;
++ /* 25Mhz Xtal - do nothing */
++ } else if (val == 0x2) {
++ /* 40Mhz */
++ xtal_mode = 2;
++
++ /* disable MT7530 core clock */
++ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x410);
++ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x0);
++
++ /* disable MT7530 PLL */
++ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x40d);
++ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x2020);
++
++ /* for MT7530 core clock = 500Mhz */
++ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x40e);
++ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x119);
++
++ /* enable MT7530 PLL */
++ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x40d);
++ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x2820);
++
++ udelay(20);
++
++ /* enable MT7530 core clock */
++ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x410);
++ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
++ } else {
++ xtal_mode = 3;
++ /* 20Mhz Xtal - TODO */
++ }
++
++ /* RGMII */
++ _mtk_mdio_write(gsw->eth, 0, 14, 0x1);
++
++ /* set MT7530 central align */
++ val = mt7530_mdio_r32(gsw, 0x7830);
++ val &= ~1;
++ val |= 1<<1;
++ mt7530_mdio_w32(gsw, 0x7830, val);
++
++ val = mt7530_mdio_r32(gsw, 0x7a40);
++ val &= ~(1<<30);
++ mt7530_mdio_w32(gsw, 0x7a40, val);
++
++ mt7530_mdio_w32(gsw, 0x7a78, 0x855);
++
++ /* delay setting for 10/1000M */
++ mt7530_mdio_w32(gsw, 0x7b00, 0x104);
++ mt7530_mdio_w32(gsw, 0x7b04, 0x10);
++
++ /* lower Tx Driving */
++ mt7530_mdio_w32(gsw, 0x7a54, 0x88);
++ mt7530_mdio_w32(gsw, 0x7a5c, 0x88);
++ mt7530_mdio_w32(gsw, 0x7a64, 0x88);
++ mt7530_mdio_w32(gsw, 0x7a6c, 0x88);
++ mt7530_mdio_w32(gsw, 0x7a74, 0x88);
++ mt7530_mdio_w32(gsw, 0x7a7c, 0x88);
++ mt7530_mdio_w32(gsw, 0x7810, 0x11);
++
++ /* Set MT7623/MT7683 TX Driving */
++ mtk_switch_w32(gsw, 0x88, 0x354);
++ mtk_switch_w32(gsw, 0x88, 0x35c);
++ mtk_switch_w32(gsw, 0x88, 0x364);
++ mtk_switch_w32(gsw, 0x88, 0x36c);
++ mtk_switch_w32(gsw, 0x88, 0x374);
++ mtk_switch_w32(gsw, 0x88, 0x37c);
++
++ /* Set GE2 driving and slew rate */
++ regmap_write(gsw->pctl, 0xF00, 0xe00);
++ /* set GE2 TDSEL */
++ regmap_write(gsw->pctl, 0x4C0, 0x5);
++ /* set GE2 TUNE */
++ regmap_write(gsw->pctl, 0xED0, 0x0);
++
++ regmap_write(gsw->pctl, 0xb70, 0);
++ regmap_write(gsw->pctl, 0x250, 0xffff);
++ regmap_write(gsw->pctl, 0x260, 0xff);
++ regmap_write(gsw->pctl, 0x380, 0x37);
++ regmap_write(gsw->pctl, 0x390, 0x40);
++
++ mt7530_trgmii_clock_setting(gsw, xtal_mode);
++
++ //LANWANPartition(gsw);
++
++ /* disable EEE */
++ for (i = 0; i <= 4; i++) {
++ _mtk_mdio_write(gsw->eth, i, 13, 0x7);
++ _mtk_mdio_write(gsw->eth, i, 14, 0x3C);
++ _mtk_mdio_write(gsw->eth, i, 13, 0x4007);
++ _mtk_mdio_write(gsw->eth, i, 14, 0x0);
++
++ /* Increase SlvDPSready time */
++ _mtk_mdio_write(gsw->eth, i, 31, 0x52b5);
++ _mtk_mdio_write(gsw->eth, i, 16, 0xafae);
++ _mtk_mdio_write(gsw->eth, i, 18, 0x2f);
++ _mtk_mdio_write(gsw->eth, i, 16, 0x8fae);
++
++ /* Incease post_update_timer */
++ _mtk_mdio_write(gsw->eth, i, 31, 0x3);
++ _mtk_mdio_write(gsw->eth, i, 17, 0x4b);
++
++ /* Adjust 100_mse_threshold */
++ _mtk_mdio_write(gsw->eth, i, 13, 0x1e);
++ _mtk_mdio_write(gsw->eth, i, 14, 0x123);
++ _mtk_mdio_write(gsw->eth, i, 13, 0x401e);
++ _mtk_mdio_write(gsw->eth, i, 14, 0xffff);
++
++ /* Disable mcc */
++ _mtk_mdio_write(gsw->eth, i, 13, 0x1e);
++ _mtk_mdio_write(gsw->eth, i, 14, 0xa6);
++ _mtk_mdio_write(gsw->eth, i, 13, 0x401e);
++ _mtk_mdio_write(gsw->eth, i, 14, 0x300);
++
++ /* Disable HW auto downshift*/
++ _mtk_mdio_write(gsw->eth, i, 31, 0x1);
++ val = _mtk_mdio_read(gsw->eth, i, 0x14);
++ val &= ~(1<<4);
++ _mtk_mdio_write(gsw->eth, i, 0x14, val);
++ }
++
++ /* turn on all PHYs */
++ for (i = 0; i <= 4; i++) {
++ val = _mtk_mdio_read(gsw->eth, i, 0);
++ val &= ~BIT(11);
++ _mtk_mdio_write(gsw->eth, i, 0, val);
++ }
++
++ /* enable irq */
++ mt7530_mdio_m32(gsw, 0, TOP_SIG_CTRL_NORMAL, MT7530_TOP_SIG_CTRL);
++}
++
++static const struct of_device_id mediatek_gsw_match[] = {
++ { .compatible = "mediatek,mt7623-gsw" },
++ {},
++};
++MODULE_DEVICE_TABLE(of, mediatek_gsw_match);
++
++int mtk_gsw_init(struct mtk_eth *eth)
++{
++ struct device_node *np = eth->switch_np;
++ struct platform_device *pdev = of_find_device_by_node(np);
++ struct mt7620_gsw *gsw;
++
++ if (!pdev)
++ return -ENODEV;
++
++ if (!of_device_is_compatible(np, mediatek_gsw_match->compatible))
++ return -EINVAL;
++
++ gsw = platform_get_drvdata(pdev);
++ if (!gsw)
++ return -ENODEV;
++ gsw->eth = eth;
++ eth->sw_priv = gsw;
++
++ mt7623_hw_init(eth, gsw, np);
++
++ if (request_threaded_irq(gsw->irq, gsw_interrupt_mt7623, NULL, 0,
++ "gsw", eth))
++ pr_err("fail to request irq\n");
++ mt7530_mdio_w32(gsw, 0x7008, 0x1f);
++
++ return 0;
++}
++
++static int mt7623_gsw_probe(struct platform_device *pdev)
++{
++ struct device_node *np = pdev->dev.of_node;
++ struct device_node *pctl;
++ int reset_pin, ret;
++ struct mt7620_gsw *gsw;
++ struct regulator *supply;
++
++ gsw = devm_kzalloc(&pdev->dev, sizeof(struct mt7620_gsw), GFP_KERNEL);
++ if (!gsw)
++ return -ENOMEM;
++
++ gsw->dev = &pdev->dev;
++ gsw->trgmii_force = 2000;
++ gsw->irq = irq_of_parse_and_map(np, 0);
++ if (gsw->irq < 0)
++ return -EINVAL;
++
++ gsw->ethsys = syscon_regmap_lookup_by_phandle(np, "mediatek,ethsys");
++ if (IS_ERR(gsw->ethsys))
++ return PTR_ERR(gsw->ethsys);
++
++ reset_pin = of_get_named_gpio(np, "mediatek,reset-pin", 0);
++ if (reset_pin < 0)
++ return reset_pin;
++
++ pctl = of_parse_phandle(np, "mediatek,pctl-regmap", 0);
++ if (IS_ERR(pctl))
++ return PTR_ERR(pctl);
++
++ gsw->pctl = syscon_node_to_regmap(pctl);
++ if (IS_ERR(pctl))
++ return PTR_ERR(pctl);
++
++ ret = devm_gpio_request(&pdev->dev, reset_pin, "mt7530-reset");
++ if (ret)
++ return ret;
++
++ gsw->clk_trgpll = devm_clk_get(&pdev->dev, "trgpll");
++
++ if (IS_ERR(gsw->clk_trgpll))
++ return -ENODEV;
++
++ supply = devm_regulator_get(&pdev->dev, "mt7530");
++ if (IS_ERR(supply))
++ return PTR_ERR(supply);
++
++ regulator_set_voltage(supply, 1000000, 1000000);
++ ret = regulator_enable(supply);
++ if (ret) {
++ dev_err(&pdev->dev, "Failed to enable reg-7530: %d\n", ret);
++ return ret;
++ }
++
++ gsw->wllll = of_property_read_bool(np, "mediatek,wllll");
++
++ pm_runtime_enable(&pdev->dev);
++ pm_runtime_get_sync(&pdev->dev);
++
++ ret = clk_set_rate(gsw->clk_trgpll, 500000000);
++ if (ret)
++ return ret;
++
++ regmap_write(gsw->ethsys, 0x34, 0x800000);
++ regmap_write(gsw->ethsys, 0x34, 0x0);
++
++ clk_prepare_enable(gsw->clk_trgpll);
++
++ gpio_direction_output(reset_pin, 0);
++ udelay(1000);
++ gpio_set_value(reset_pin, 1);
++ mdelay(100);
++
++ platform_set_drvdata(pdev, gsw);
++
++ return 0;
++}
++
++static int mt7623_gsw_remove(struct platform_device *pdev)
++{
++ struct mt7620_gsw *gsw = platform_get_drvdata(pdev);
++
++ clk_disable_unprepare(gsw->clk_trgpll);
++
++ pm_runtime_put_sync(&pdev->dev);
++ pm_runtime_disable(&pdev->dev);
++
++ platform_set_drvdata(pdev, NULL);
++
++ return 0;
++}
++
++static struct platform_driver gsw_driver = {
++ .probe = mt7623_gsw_probe,
++ .remove = mt7623_gsw_remove,
++ .driver = {
++ .name = "mt7623-gsw",
++ .owner = THIS_MODULE,
++ .of_match_table = mediatek_gsw_match,
++ },
++};
++
++module_platform_driver(gsw_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
++MODULE_DESCRIPTION("GBit switch driver for Mediatek MT7623 SoC");
+--- /dev/null
++++ b/drivers/net/ethernet/mediatek/mt7530.c
+@@ -0,0 +1,808 @@
++/*
++ * 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.
++ *
++ * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
++ */
++
++#include <linux/if.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/if_ether.h>
++#include <linux/skbuff.h>
++#include <linux/netdevice.h>
++#include <linux/netlink.h>
++#include <linux/bitops.h>
++#include <net/genetlink.h>
++#include <linux/switch.h>
++#include <linux/delay.h>
++#include <linux/phy.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/lockdep.h>
++#include <linux/workqueue.h>
++#include <linux/of_device.h>
++
++#include "mt7530.h"
++
++#define MT7530_CPU_PORT 6
++#define MT7530_NUM_PORTS 8
++#define MT7530_NUM_VLANS 16
++#define MT7530_MAX_VID 4095
++#define MT7530_MIN_VID 0
++
++/* registers */
++#define REG_ESW_VLAN_VTCR 0x90
++#define REG_ESW_VLAN_VAWD1 0x94
++#define REG_ESW_VLAN_VAWD2 0x98
++#define REG_ESW_VLAN_VTIM(x) (0x100 + 4 * ((x) / 2))
++
++#define REG_ESW_VLAN_VAWD1_IVL_MAC BIT(30)
++#define REG_ESW_VLAN_VAWD1_VTAG_EN BIT(28)
++#define REG_ESW_VLAN_VAWD1_VALID BIT(0)
++
++/* vlan egress mode */
++enum {
++ ETAG_CTRL_UNTAG = 0,
++ ETAG_CTRL_TAG = 2,
++ ETAG_CTRL_SWAP = 1,
++ ETAG_CTRL_STACK = 3,
++};
++
++#define REG_ESW_PORT_PCR(x) (0x2004 | ((x) << 8))
++#define REG_ESW_PORT_PVC(x) (0x2010 | ((x) << 8))
++#define REG_ESW_PORT_PPBV1(x) (0x2014 | ((x) << 8))
++
++#define REG_HWTRAP 0x7804
++
++#define MIB_DESC(_s , _o, _n) \
++ { \
++ .size = (_s), \
++ .offset = (_o), \
++ .name = (_n), \
++ }
++
++struct mt7xxx_mib_desc {
++ unsigned int size;
++ unsigned int offset;
++ const char *name;
++};
++
++#define MT7621_MIB_COUNTER_BASE 0x4000
++#define MT7621_MIB_COUNTER_PORT_OFFSET 0x100
++#define MT7621_STATS_TDPC 0x00
++#define MT7621_STATS_TCRC 0x04
++#define MT7621_STATS_TUPC 0x08
++#define MT7621_STATS_TMPC 0x0C
++#define MT7621_STATS_TBPC 0x10
++#define MT7621_STATS_TCEC 0x14
++#define MT7621_STATS_TSCEC 0x18
++#define MT7621_STATS_TMCEC 0x1C
++#define MT7621_STATS_TDEC 0x20
++#define MT7621_STATS_TLCEC 0x24
++#define MT7621_STATS_TXCEC 0x28
++#define MT7621_STATS_TPPC 0x2C
++#define MT7621_STATS_TL64PC 0x30
++#define MT7621_STATS_TL65PC 0x34
++#define MT7621_STATS_TL128PC 0x38
++#define MT7621_STATS_TL256PC 0x3C
++#define MT7621_STATS_TL512PC 0x40
++#define MT7621_STATS_TL1024PC 0x44
++#define MT7621_STATS_TOC 0x48
++#define MT7621_STATS_RDPC 0x60
++#define MT7621_STATS_RFPC 0x64
++#define MT7621_STATS_RUPC 0x68
++#define MT7621_STATS_RMPC 0x6C
++#define MT7621_STATS_RBPC 0x70
++#define MT7621_STATS_RAEPC 0x74
++#define MT7621_STATS_RCEPC 0x78
++#define MT7621_STATS_RUSPC 0x7C
++#define MT7621_STATS_RFEPC 0x80
++#define MT7621_STATS_ROSPC 0x84
++#define MT7621_STATS_RJEPC 0x88
++#define MT7621_STATS_RPPC 0x8C
++#define MT7621_STATS_RL64PC 0x90
++#define MT7621_STATS_RL65PC 0x94
++#define MT7621_STATS_RL128PC 0x98
++#define MT7621_STATS_RL256PC 0x9C
++#define MT7621_STATS_RL512PC 0xA0
++#define MT7621_STATS_RL1024PC 0xA4
++#define MT7621_STATS_ROC 0xA8
++#define MT7621_STATS_RDPC_CTRL 0xB0
++#define MT7621_STATS_RDPC_ING 0xB4
++#define MT7621_STATS_RDPC_ARL 0xB8
++
++static const struct mt7xxx_mib_desc mt7621_mibs[] = {
++ MIB_DESC(1, MT7621_STATS_TDPC, "TxDrop"),
++ MIB_DESC(1, MT7621_STATS_TCRC, "TxCRC"),
++ MIB_DESC(1, MT7621_STATS_TUPC, "TxUni"),
++ MIB_DESC(1, MT7621_STATS_TMPC, "TxMulti"),
++ MIB_DESC(1, MT7621_STATS_TBPC, "TxBroad"),
++ MIB_DESC(1, MT7621_STATS_TCEC, "TxCollision"),
++ MIB_DESC(1, MT7621_STATS_TSCEC, "TxSingleCol"),
++ MIB_DESC(1, MT7621_STATS_TMCEC, "TxMultiCol"),
++ MIB_DESC(1, MT7621_STATS_TDEC, "TxDefer"),
++ MIB_DESC(1, MT7621_STATS_TLCEC, "TxLateCol"),
++ MIB_DESC(1, MT7621_STATS_TXCEC, "TxExcCol"),
++ MIB_DESC(1, MT7621_STATS_TPPC, "TxPause"),
++ MIB_DESC(1, MT7621_STATS_TL64PC, "Tx64Byte"),
++ MIB_DESC(1, MT7621_STATS_TL65PC, "Tx65Byte"),
++ MIB_DESC(1, MT7621_STATS_TL128PC, "Tx128Byte"),
++ MIB_DESC(1, MT7621_STATS_TL256PC, "Tx256Byte"),
++ MIB_DESC(1, MT7621_STATS_TL512PC, "Tx512Byte"),
++ MIB_DESC(1, MT7621_STATS_TL1024PC, "Tx1024Byte"),
++ MIB_DESC(2, MT7621_STATS_TOC, "TxByte"),
++ MIB_DESC(1, MT7621_STATS_RDPC, "RxDrop"),
++ MIB_DESC(1, MT7621_STATS_RFPC, "RxFiltered"),
++ MIB_DESC(1, MT7621_STATS_RUPC, "RxUni"),
++ MIB_DESC(1, MT7621_STATS_RMPC, "RxMulti"),
++ MIB_DESC(1, MT7621_STATS_RBPC, "RxBroad"),
++ MIB_DESC(1, MT7621_STATS_RAEPC, "RxAlignErr"),
++ MIB_DESC(1, MT7621_STATS_RCEPC, "RxCRC"),
++ MIB_DESC(1, MT7621_STATS_RUSPC, "RxUnderSize"),
++ MIB_DESC(1, MT7621_STATS_RFEPC, "RxFragment"),
++ MIB_DESC(1, MT7621_STATS_ROSPC, "RxOverSize"),
++ MIB_DESC(1, MT7621_STATS_RJEPC, "RxJabber"),
++ MIB_DESC(1, MT7621_STATS_RPPC, "RxPause"),
++ MIB_DESC(1, MT7621_STATS_RL64PC, "Rx64Byte"),
++ MIB_DESC(1, MT7621_STATS_RL65PC, "Rx65Byte"),
++ MIB_DESC(1, MT7621_STATS_RL128PC, "Rx128Byte"),
++ MIB_DESC(1, MT7621_STATS_RL256PC, "Rx256Byte"),
++ MIB_DESC(1, MT7621_STATS_RL512PC, "Rx512Byte"),
++ MIB_DESC(1, MT7621_STATS_RL1024PC, "Rx1024Byte"),
++ MIB_DESC(2, MT7621_STATS_ROC, "RxByte"),
++ MIB_DESC(1, MT7621_STATS_RDPC_CTRL, "RxCtrlDrop"),
++ MIB_DESC(1, MT7621_STATS_RDPC_ING, "RxIngDrop"),
++ MIB_DESC(1, MT7621_STATS_RDPC_ARL, "RxARLDrop")
++};
++
++enum {
++ /* Global attributes. */
++ MT7530_ATTR_ENABLE_VLAN,
++};
++
++struct mt7530_port_entry {
++ u16 pvid;
++};
++
++struct mt7530_vlan_entry {
++ u16 vid;
++ u8 member;
++ u8 etags;
++};
++
++struct mt7530_priv {
++ void __iomem *base;
++ struct mii_bus *bus;
++ struct switch_dev swdev;
++
++ bool global_vlan_enable;
++ struct mt7530_vlan_entry vlan_entries[MT7530_NUM_VLANS];
++ struct mt7530_port_entry port_entries[MT7530_NUM_PORTS];
++};
++
++struct mt7530_mapping {
++ char *name;
++ u16 pvids[MT7530_NUM_PORTS];
++ u8 members[MT7530_NUM_VLANS];
++ u8 etags[MT7530_NUM_VLANS];
++ u16 vids[MT7530_NUM_VLANS];
++} mt7530_defaults[] = {
++ {
++ .name = "llllw",
++ .pvids = { 1, 1, 1, 1, 2, 1, 1 },
++ .members = { 0, 0x6f, 0x50 },
++ .etags = { 0, 0x40, 0x40 },
++ .vids = { 0, 1, 2 },
++ }, {
++ .name = "wllll",
++ .pvids = { 2, 1, 1, 1, 1, 1, 1 },
++ .members = { 0, 0x7e, 0x41 },
++ .etags = { 0, 0x40, 0x40 },
++ .vids = { 0, 1, 2 },
++ },
++};
++
++struct mt7530_mapping*
++mt7530_find_mapping(struct device_node *np)
++{
++ const char *map;
++ int i;
++
++ if (of_property_read_string(np, "mediatek,portmap", &map))
++ return NULL;
++
++ for (i = 0; i < ARRAY_SIZE(mt7530_defaults); i++)
++ if (!strcmp(map, mt7530_defaults[i].name))
++ return &mt7530_defaults[i];
++
++ return NULL;
++}
++
++static void
++mt7530_apply_mapping(struct mt7530_priv *mt7530, struct mt7530_mapping *map)
++{
++ int i = 0;
++
++ for (i = 0; i < MT7530_NUM_PORTS; i++)
++ mt7530->port_entries[i].pvid = map->pvids[i];
++
++ for (i = 0; i < MT7530_NUM_VLANS; i++) {
++ mt7530->vlan_entries[i].member = map->members[i];
++ mt7530->vlan_entries[i].etags = map->etags[i];
++ mt7530->vlan_entries[i].vid = map->vids[i];
++ }
++}
++
++static int
++mt7530_reset_switch(struct switch_dev *dev)
++{
++ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
++ int i;
++
++ memset(eth->port_entries, 0, sizeof(eth->port_entries));
++ memset(eth->vlan_entries, 0, sizeof(eth->vlan_entries));
++
++ /* set default vid of each vlan to the same number of vlan, so the vid
++ * won't need be set explicitly.
++ */
++ for (i = 0; i < MT7530_NUM_VLANS; i++) {
++ eth->vlan_entries[i].vid = i;
++ }
++
++ return 0;
++}
++
++static int
++mt7530_get_vlan_enable(struct switch_dev *dev,
++ const struct switch_attr *attr,
++ struct switch_val *val)
++{
++ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
++
++ val->value.i = eth->global_vlan_enable;
++
++ return 0;
++}
++
++static int
++mt7530_set_vlan_enable(struct switch_dev *dev,
++ const struct switch_attr *attr,
++ struct switch_val *val)
++{
++ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
++
++ eth->global_vlan_enable = val->value.i != 0;
++
++ return 0;
++}
++
++static u32
++mt7530_r32(struct mt7530_priv *eth, u32 reg)
++{
++ u32 val;
++ if (eth->bus) {
++ u16 high, low;
++
++ mdiobus_write(eth->bus, 0x1f, 0x1f, (reg >> 6) & 0x3ff);
++ low = mdiobus_read(eth->bus, 0x1f, (reg >> 2) & 0xf);
++ high = mdiobus_read(eth->bus, 0x1f, 0x10);
++
++ return (high << 16) | (low & 0xffff);
++ }
++
++ val = ioread32(eth->base + reg);
++ pr_debug("MT7530 MDIO Read [%04x]=%08x\n", reg, val);
++
++ return val;
++}
++
++static void
++mt7530_w32(struct mt7530_priv *eth, u32 reg, u32 val)
++{
++ if (eth->bus) {
++ mdiobus_write(eth->bus, 0x1f, 0x1f, (reg >> 6) & 0x3ff);
++ mdiobus_write(eth->bus, 0x1f, (reg >> 2) & 0xf, val & 0xffff);
++ mdiobus_write(eth->bus, 0x1f, 0x10, val >> 16);
++ return;
++ }
++
++ pr_debug("MT7530 MDIO Write[%04x]=%08x\n", reg, val);
++ iowrite32(val, eth->base + reg);
++}
++
++static void
++mt7530_vtcr(struct mt7530_priv *eth, u32 cmd, u32 val)
++{
++ int i;
++
++ mt7530_w32(eth, REG_ESW_VLAN_VTCR, BIT(31) | (cmd << 12) | val);
++
++ for (i = 0; i < 20; i++) {
++ u32 val = mt7530_r32(eth, REG_ESW_VLAN_VTCR);
++
++ if ((val & BIT(31)) == 0)
++ break;
++
++ udelay(1000);
++ }
++ if (i == 20)
++ printk("mt7530: vtcr timeout\n");
++}
++
++static int
++mt7530_get_port_pvid(struct switch_dev *dev, int port, int *val)
++{
++ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
++
++ if (port >= MT7530_NUM_PORTS)
++ return -EINVAL;
++
++ *val = mt7530_r32(eth, REG_ESW_PORT_PPBV1(port));
++ *val &= 0xfff;
++
++ return 0;
++}
++
++static int
++mt7530_set_port_pvid(struct switch_dev *dev, int port, int pvid)
++{
++ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
++
++ if (port >= MT7530_NUM_PORTS)
++ return -EINVAL;
++
++ if (pvid < MT7530_MIN_VID || pvid > MT7530_MAX_VID)
++ return -EINVAL;
++
++ eth->port_entries[port].pvid = pvid;
++
++ return 0;
++}
++
++static int
++mt7530_get_vlan_ports(struct switch_dev *dev, struct switch_val *val)
++{
++ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
++ u32 member;
++ u32 etags;
++ int i;
++
++ val->len = 0;
++
++ if (val->port_vlan < 0 || val->port_vlan >= MT7530_NUM_VLANS)
++ return -EINVAL;
++
++ mt7530_vtcr(eth, 0, val->port_vlan);
++
++ member = mt7530_r32(eth, REG_ESW_VLAN_VAWD1);
++ member >>= 16;
++ member &= 0xff;
++
++ etags = mt7530_r32(eth, REG_ESW_VLAN_VAWD2);
++
++ for (i = 0; i < MT7530_NUM_PORTS; i++) {
++ struct switch_port *p;
++ int etag;
++
++ if (!(member & BIT(i)))
++ continue;
++
++ p = &val->value.ports[val->len++];
++ p->id = i;
++
++ etag = (etags >> (i * 2)) & 0x3;
++
++ if (etag == ETAG_CTRL_TAG)
++ p->flags |= BIT(SWITCH_PORT_FLAG_TAGGED);
++ else if (etag != ETAG_CTRL_UNTAG)
++ printk("vlan egress tag control neither untag nor tag.\n");
++ }
++
++ return 0;
++}
++
++static int
++mt7530_set_vlan_ports(struct switch_dev *dev, struct switch_val *val)
++{
++ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
++ u8 member = 0;
++ u8 etags = 0;
++ int i;
++
++ if (val->port_vlan < 0 || val->port_vlan >= MT7530_NUM_VLANS ||
++ val->len > MT7530_NUM_PORTS)
++ return -EINVAL;
++
++ for (i = 0; i < val->len; i++) {
++ struct switch_port *p = &val->value.ports[i];
++
++ if (p->id >= MT7530_NUM_PORTS)
++ return -EINVAL;
++
++ member |= BIT(p->id);
++
++ if (p->flags & BIT(SWITCH_PORT_FLAG_TAGGED))
++ etags |= BIT(p->id);
++ }
++ eth->vlan_entries[val->port_vlan].member = member;
++ eth->vlan_entries[val->port_vlan].etags = etags;
++
++ return 0;
++}
++
++static int
++mt7530_set_vid(struct switch_dev *dev, const struct switch_attr *attr,
++ struct switch_val *val)
++{
++ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
++ int vlan;
++ u16 vid;
++
++ vlan = val->port_vlan;
++ vid = (u16)val->value.i;
++
++ if (vlan < 0 || vlan >= MT7530_NUM_VLANS)
++ return -EINVAL;
++
++ if (vid < MT7530_MIN_VID || vid > MT7530_MAX_VID)
++ return -EINVAL;
++
++ eth->vlan_entries[vlan].vid = vid;
++ return 0;
++}
++
++static int
++mt7530_get_vid(struct switch_dev *dev, const struct switch_attr *attr,
++ struct switch_val *val)
++{
++ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
++ u32 vid;
++ int vlan;
++
++ vlan = val->port_vlan;
++
++ vid = mt7530_r32(eth, REG_ESW_VLAN_VTIM(vlan));
++ if (vlan & 1)
++ vid = vid >> 12;
++ vid &= 0xfff;
++
++ val->value.i = vid;
++ return 0;
++}
++
++static int
++mt7530_apply_config(struct switch_dev *dev)
++{
++ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
++ int i, j;
++ u8 tag_ports;
++ u8 untag_ports;
++
++ if (!eth->global_vlan_enable) {
++ for (i = 0; i < MT7530_NUM_PORTS; i++)
++ mt7530_w32(eth, REG_ESW_PORT_PCR(i), 0x00ff0000);
++
++ for (i = 0; i < MT7530_NUM_PORTS; i++)
++ mt7530_w32(eth, REG_ESW_PORT_PVC(i), 0x810000c0);
++
++ return 0;
++ }
++
++ /* set all ports as security mode */
++ for (i = 0; i < MT7530_NUM_PORTS; i++)
++ mt7530_w32(eth, REG_ESW_PORT_PCR(i), 0x00ff0003);
++
++ /* check if a port is used in tag/untag vlan egress mode */
++ tag_ports = 0;
++ untag_ports = 0;
++
++ for (i = 0; i < MT7530_NUM_VLANS; i++) {
++ u8 member = eth->vlan_entries[i].member;
++ u8 etags = eth->vlan_entries[i].etags;
++
++ if (!member)
++ continue;
++
++ for (j = 0; j < MT7530_NUM_PORTS; j++) {
++ if (!(member & BIT(j)))
++ continue;
++
++ if (etags & BIT(j))
++ tag_ports |= 1u << j;
++ else
++ untag_ports |= 1u << j;
++ }
++ }
++
++ /* set all untag-only ports as transparent and the rest as user port */
++ for (i = 0; i < MT7530_NUM_PORTS; i++) {
++ u32 pvc_mode = 0x81000000;
++
++ if (untag_ports & BIT(i) && !(tag_ports & BIT(i)))
++ pvc_mode = 0x810000c0;
++
++ mt7530_w32(eth, REG_ESW_PORT_PVC(i), pvc_mode);
++ }
++
++ for (i = 0; i < MT7530_NUM_VLANS; i++) {
++ u16 vid = eth->vlan_entries[i].vid;
++ u8 member = eth->vlan_entries[i].member;
++ u8 etags = eth->vlan_entries[i].etags;
++ u32 val;
++
++ /* vid of vlan */
++ val = mt7530_r32(eth, REG_ESW_VLAN_VTIM(i));
++ if (i % 2 == 0) {
++ val &= 0xfff000;
++ val |= vid;
++ } else {
++ val &= 0xfff;
++ val |= (vid << 12);
++ }
++ mt7530_w32(eth, REG_ESW_VLAN_VTIM(i), val);
++
++ /* vlan port membership */
++ if (member)
++ mt7530_w32(eth, REG_ESW_VLAN_VAWD1, REG_ESW_VLAN_VAWD1_IVL_MAC |
++ REG_ESW_VLAN_VAWD1_VTAG_EN | (member << 16) |
++ REG_ESW_VLAN_VAWD1_VALID);
++ else
++ mt7530_w32(eth, REG_ESW_VLAN_VAWD1, 0);
++
++ /* egress mode */
++ val = 0;
++ for (j = 0; j < MT7530_NUM_PORTS; j++) {
++ if (etags & BIT(j))
++ val |= ETAG_CTRL_TAG << (j * 2);
++ else
++ val |= ETAG_CTRL_UNTAG << (j * 2);
++ }
++ mt7530_w32(eth, REG_ESW_VLAN_VAWD2, val);
++
++ /* write to vlan table */
++ mt7530_vtcr(eth, 1, i);
++ }
++
++ /* Port Default PVID */
++ for (i = 0; i < MT7530_NUM_PORTS; i++) {
++ u32 val;
++ val = mt7530_r32(eth, REG_ESW_PORT_PPBV1(i));
++ val &= ~0xfff;
++ val |= eth->port_entries[i].pvid;
++ mt7530_w32(eth, REG_ESW_PORT_PPBV1(i), val);
++ }
++
++ return 0;
++}
++
++static int
++mt7530_get_port_link(struct switch_dev *dev, int port,
++ struct switch_port_link *link)
++{
++ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
++ u32 speed, pmsr;
++
++ if (port < 0 || port >= MT7530_NUM_PORTS)
++ return -EINVAL;
++
++ pmsr = mt7530_r32(eth, 0x3008 + (0x100 * port));
++
++ link->link = pmsr & 1;
++ link->duplex = (pmsr >> 1) & 1;
++ speed = (pmsr >> 2) & 3;
++
++ switch (speed) {
++ case 0:
++ link->speed = SWITCH_PORT_SPEED_10;
++ break;
++ case 1:
++ link->speed = SWITCH_PORT_SPEED_100;
++ break;
++ case 2:
++ case 3: /* forced gige speed can be 2 or 3 */
++ link->speed = SWITCH_PORT_SPEED_1000;
++ break;
++ default:
++ link->speed = SWITCH_PORT_SPEED_UNKNOWN;
++ break;
++ }
++
++ return 0;
++}
++
++static const struct switch_attr mt7530_global[] = {
++ {
++ .type = SWITCH_TYPE_INT,
++ .name = "enable_vlan",
++ .description = "VLAN mode (1:enabled)",
++ .max = 1,
++ .id = MT7530_ATTR_ENABLE_VLAN,
++ .get = mt7530_get_vlan_enable,
++ .set = mt7530_set_vlan_enable,
++ },
++};
++
++static u64 get_mib_counter(struct mt7530_priv *eth, int i, int port)
++{
++ unsigned int port_base;
++ u64 t;
++
++ port_base = MT7621_MIB_COUNTER_BASE +
++ MT7621_MIB_COUNTER_PORT_OFFSET * port;
++
++ t = mt7530_r32(eth, port_base + mt7621_mibs[i].offset);
++ if (mt7621_mibs[i].size == 2) {
++ u64 hi;
++
++ hi = mt7530_r32(eth, port_base + mt7621_mibs[i].offset + 4);
++ t |= hi << 32;
++ }
++
++ return t;
++}
++
++static int mt7621_sw_get_port_mib(struct switch_dev *dev,
++ const struct switch_attr *attr,
++ struct switch_val *val)
++{
++ static char buf[4096];
++ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
++ int i, len = 0;
++
++ if (val->port_vlan >= MT7530_NUM_PORTS)
++ return -EINVAL;
++
++ len += snprintf(buf + len, sizeof(buf) - len,
++ "Port %d MIB counters\n", val->port_vlan);
++
++ for (i = 0; i < sizeof(mt7621_mibs) / sizeof(*mt7621_mibs); ++i) {
++ u64 counter;
++ len += snprintf(buf + len, sizeof(buf) - len,
++ "%-11s: ", mt7621_mibs[i].name);
++ counter = get_mib_counter(eth, i, val->port_vlan);
++ len += snprintf(buf + len, sizeof(buf) - len, "%llu\n",
++ counter);
++ }
++
++ val->value.s = buf;
++ val->len = len;
++ return 0;
++}
++
++static const struct switch_attr mt7621_port[] = {
++ {
++ .type = SWITCH_TYPE_STRING,
++ .name = "mib",
++ .description = "Get MIB counters for port",
++ .get = mt7621_sw_get_port_mib,
++ .set = NULL,
++ },
++};
++
++static const struct switch_attr mt7530_port[] = {
++};
++
++static const struct switch_attr mt7530_vlan[] = {
++ {
++ .type = SWITCH_TYPE_INT,
++ .name = "vid",
++ .description = "VLAN ID (0-4094)",
++ .set = mt7530_set_vid,
++ .get = mt7530_get_vid,
++ .max = 4094,
++ },
++};
++
++static const struct switch_dev_ops mt7621_ops = {
++ .attr_global = {
++ .attr = mt7530_global,
++ .n_attr = ARRAY_SIZE(mt7530_global),
++ },
++/* .attr_port = {
++ .attr = mt7621_port,
++ .n_attr = ARRAY_SIZE(mt7621_port),
++ },*/
++ .attr_vlan = {
++ .attr = mt7530_vlan,
++ .n_attr = ARRAY_SIZE(mt7530_vlan),
++ },
++ .get_vlan_ports = mt7530_get_vlan_ports,
++ .set_vlan_ports = mt7530_set_vlan_ports,
++ .get_port_pvid = mt7530_get_port_pvid,
++ .set_port_pvid = mt7530_set_port_pvid,
++ .get_port_link = mt7530_get_port_link,
++ .apply_config = mt7530_apply_config,
++ .reset_switch = mt7530_reset_switch,
++};
++
++static const struct switch_dev_ops mt7530_ops = {
++ .attr_global = {
++ .attr = mt7530_global,
++ .n_attr = ARRAY_SIZE(mt7530_global),
++ },
++ .attr_port = {
++ .attr = mt7530_port,
++ .n_attr = ARRAY_SIZE(mt7530_port),
++ },
++ .attr_vlan = {
++ .attr = mt7530_vlan,
++ .n_attr = ARRAY_SIZE(mt7530_vlan),
++ },
++ .get_vlan_ports = mt7530_get_vlan_ports,
++ .set_vlan_ports = mt7530_set_vlan_ports,
++ .get_port_pvid = mt7530_get_port_pvid,
++ .set_port_pvid = mt7530_set_port_pvid,
++ .get_port_link = mt7530_get_port_link,
++ .apply_config = mt7530_apply_config,
++ .reset_switch = mt7530_reset_switch,
++};
++
++int
++mt7530_probe(struct device *dev, void __iomem *base, struct mii_bus *bus, int vlan)
++{
++ struct switch_dev *swdev;
++ struct mt7530_priv *mt7530;
++ struct mt7530_mapping *map;
++ int ret;
++
++ mt7530 = devm_kzalloc(dev, sizeof(struct mt7530_priv), GFP_KERNEL);
++ if (!mt7530)
++ return -ENOMEM;
++
++ mt7530->base = base;
++ mt7530->bus = bus;
++ mt7530->global_vlan_enable = vlan;
++
++ swdev = &mt7530->swdev;
++ if (bus) {
++ swdev->alias = "mt7530";
++ swdev->name = "mt7530";
++ } else if (IS_ENABLED(CONFIG_MACH_MT7623)) {
++ swdev->alias = "mt7623";
++ swdev->name = "mt7623";
++ } else if (IS_ENABLED(CONFIG_SOC_MT7621)) {
++ swdev->alias = "mt7621";
++ swdev->name = "mt7621";
++ } else {
++ swdev->alias = "mt7620";
++ swdev->name = "mt7620";
++ }
++ swdev->cpu_port = MT7530_CPU_PORT;
++ swdev->ports = MT7530_NUM_PORTS;
++ swdev->vlans = MT7530_NUM_VLANS;
++ if (IS_ENABLED(CONFIG_SOC_MT7621) || IS_ENABLED(CONFIG_MACH_MT7623))
++ swdev->ops = &mt7621_ops;
++ else
++ swdev->ops = &mt7530_ops;
++
++ ret = register_switch(swdev, NULL);
++ if (ret) {
++ dev_err(dev, "failed to register mt7530\n");
++ return ret;
++ }
++
++ mt7530_reset_switch(swdev);
++
++ map = mt7530_find_mapping(dev->of_node);
++ if (map)
++ mt7530_apply_mapping(mt7530, map);
++ mt7530_apply_config(swdev);
++
++ /* magic vodoo */
++ if (!(IS_ENABLED(CONFIG_SOC_MT7621) || IS_ENABLED(CONFIG_MACH_MT7623)) && bus && mt7530_r32(mt7530, REG_HWTRAP) != 0x1117edf) {
++ dev_info(dev, "fixing up MHWTRAP register - bootloader probably played with it\n");
++ mt7530_w32(mt7530, REG_HWTRAP, 0x1117edf);
++ }
++ dev_info(dev, "loaded %s driver\n", swdev->name);
++
++ return 0;
++}
+--- /dev/null
++++ b/drivers/net/ethernet/mediatek/mt7530.h
+@@ -0,0 +1,20 @@
++/*
++ * 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.
++ *
++ * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
++ */
++
++#ifndef _MT7530_H__
++#define _MT7530_H__
++
++int mt7530_probe(struct device *dev, void __iomem *base, struct mii_bus *bus, int vlan);
++
++#endif
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -24,6 +24,9 @@
+
+ #include "mtk_eth_soc.h"
+
++/* the callback used by the driver core to bringup the switch */
++int mtk_gsw_init(struct mtk_eth *eth);
++
+ static int mtk_msg_level = -1;
+ module_param_named(msg_level, mtk_msg_level, int, 0);
+ MODULE_PARM_DESC(msg_level, "Message level (-1=defaults,0=none,...,16=all)");
+@@ -69,7 +72,7 @@ static int mtk_mdio_busy_wait(struct mtk
+ return 0;
+ if (time_after(jiffies, t_start + PHY_IAC_TIMEOUT))
+ break;
+- usleep_range(10, 20);
++// usleep_range(10, 20);
+ }
+
+ dev_err(eth->dev, "mdio: MDIO timeout\n");
+@@ -1421,15 +1424,6 @@ static int __init mtk_hw_init(struct mtk
+ reset_control_deassert(eth->rstc);
+ usleep_range(10, 20);
+
+- /* Set GE2 driving and slew rate */
+- regmap_write(eth->pctl, GPIO_DRV_SEL10, 0xa00);
+-
+- /* set GE2 TDSEL */
+- regmap_write(eth->pctl, GPIO_OD33_CTRL8, 0x5);
+-
+- /* set GE2 TUNE */
+- regmap_write(eth->pctl, GPIO_BIAS_CTRL, 0x0);
+-
+ /* GE1, Force 1000M/FD, FC ON */
+ mtk_w32(eth, MAC_MCR_FIXED_LINK, MTK_MAC_MCR(0));
+
+@@ -1452,6 +1446,8 @@ static int __init mtk_hw_init(struct mtk
+ if (err)
+ return err;
+
++ mtk_gsw_init(eth);
++
+ /* disable delay and normal interrupt */
+ mtk_w32(eth, 0, MTK_QDMA_DELAY_INT);
+ mtk_irq_disable(eth, ~0);
+@@ -1479,6 +1475,8 @@ static int __init mtk_hw_init(struct mtk
+ mtk_w32(eth, val, MTK_GDMA_FWD_CFG(i));
+ }
+
++ mt7623_gsw_config(eth);
++
+ return 0;
+ }
+
+@@ -1734,7 +1732,7 @@ static int mtk_add_mac(struct mtk_eth *e
+ {
+ struct mtk_mac *mac;
+ const __be32 *_id = of_get_property(np, "reg", NULL);
+- int id, err;
++ int id;
+
+ if (!_id) {
+ dev_err(eth->dev, "missing mac id\n");
+@@ -1768,8 +1766,8 @@ static int mtk_add_mac(struct mtk_eth *e
+ GFP_KERNEL);
+ if (!mac->hw_stats) {
+ dev_err(eth->dev, "failed to allocate counter memory\n");
+- err = -ENOMEM;
+- goto free_netdev;
++ free_netdev(eth->netdev[id]);
++ return -ENOMEM;
+ }
+ spin_lock_init(&mac->hw_stats->stats_lock);
+ mac->hw_stats->reg_offset = id * MTK_STAT_OFFSET;
+@@ -1783,21 +1781,9 @@ static int mtk_add_mac(struct mtk_eth *e
+ eth->netdev[id]->features |= MTK_HW_FEATURES;
+ eth->netdev[id]->ethtool_ops = &mtk_ethtool_ops;
+
+- err = register_netdev(eth->netdev[id]);
+- if (err) {
+- dev_err(eth->dev, "error bringing up device\n");
+- goto free_netdev;
+- }
+ eth->netdev[id]->irq = eth->irq[0];
+- netif_info(eth, probe, eth->netdev[id],
+- "mediatek frame engine at 0x%08lx, irq %d\n",
+- eth->netdev[id]->base_addr, eth->irq[0]);
+
+ return 0;
+-
+-free_netdev:
+- free_netdev(eth->netdev[id]);
+- return err;
+ }
+
+ static int mtk_probe(struct platform_device *pdev)
+@@ -1865,14 +1851,13 @@ static int mtk_probe(struct platform_dev
+ clk_prepare_enable(eth->clk_gp1);
+ clk_prepare_enable(eth->clk_gp2);
+
++ eth->switch_np = of_parse_phandle(pdev->dev.of_node,
++ "mediatek,switch", 0);
++
+ eth->dev = &pdev->dev;
+ eth->msg_enable = netif_msg_init(mtk_msg_level, MTK_DEFAULT_MSG_ENABLE);
+ INIT_WORK(&eth->pending_work, mtk_pending_work);
+
+- err = mtk_hw_init(eth);
+- if (err)
+- return err;
+-
+ for_each_child_of_node(pdev->dev.of_node, mac_np) {
+ if (!of_device_is_compatible(mac_np,
+ "mediatek,eth-mac"))
+@@ -1886,6 +1871,22 @@ static int mtk_probe(struct platform_dev
+ goto err_free_dev;
+ }
+
++ err = mtk_hw_init(eth);
++ if (err)
++ return err;
++
++ for (i = 0; i < MTK_MAX_DEVS; i++) {
++ if (!eth->netdev[i])
++ continue;
++ err = register_netdev(eth->netdev[i]);
++ if (err)
++ dev_err(eth->dev, "error bringing up device\n");
++ else
++ netif_info(eth, probe, eth->netdev[i],
++ "mediatek frame engine at 0x%08lx, irq %d\n",
++ eth->netdev[i]->base_addr, eth->irq[0]);
++ }
++
+ /* we run 2 devices on the same DMA ring so we need a dummy device
+ * for NAPI to work
+ */
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -407,6 +407,9 @@ struct mtk_eth {
+ struct clk *clk_gp2;
+ struct mii_bus *mii_bus;
+ struct work_struct pending_work;
++
++ struct device_node *switch_np;
++ void *sw_priv;
+ };
+
+ /* struct mtk_mac - the structure that holds the info about the MACs of the
+@@ -434,4 +437,6 @@ void mtk_stats_update_mac(struct mtk_mac
+ void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg);
+ u32 mtk_r32(struct mtk_eth *eth, unsigned reg);
+
++int mt7623_gsw_config(struct mtk_eth *eth);
++
+ #endif /* MTK_ETH_H */
diff --git a/target/linux/mediatek/patches-4.4/0102-net-mediatek-v4.4-backports.patch b/target/linux/mediatek/patches-4.4/0102-net-mediatek-v4.4-backports.patch
new file mode 100644
index 0000000000..3561b4020c
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0102-net-mediatek-v4.4-backports.patch
@@ -0,0 +1,46 @@
+From c1ff5519a7fd849da5d169036d8175383f807962 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 11 Apr 2016 06:00:23 +0200
+Subject: [PATCH 102/102] net: mediatek: v4.4 backports
+
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 13 ++++++++-----
+ 1 file changed, 8 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -217,7 +217,7 @@ static int mtk_phy_connect_node(struct m
+
+ dev_info(eth->dev,
+ "connected mac %d to PHY at %s [uid=%08x, driver=%s]\n",
+- mac->id, phydev_name(phydev), phydev->phy_id,
++ mac->id, dev_name(&phydev->dev), phydev->phy_id,
+ phydev->drv->name);
+
+ mac->phy_dev = phydev;
+@@ -1396,6 +1396,7 @@ static int mtk_stop(struct net_device *d
+ struct mtk_mac *mac = netdev_priv(dev);
+ struct mtk_eth *eth = mac->hw;
+
++ netif_carrier_off(dev);
+ netif_tx_disable(dev);
+ phy_stop(mac->phy_dev);
+
+@@ -1595,11 +1596,13 @@ static int mtk_set_settings(struct net_d
+ {
+ struct mtk_mac *mac = netdev_priv(dev);
+
+- if (cmd->phy_address != mac->phy_dev->mdio.addr) {
+- mac->phy_dev = mdiobus_get_phy(mac->hw->mii_bus,
+- cmd->phy_address);
+- if (!mac->phy_dev)
++ if (cmd->phy_address != mac->phy_dev->addr) {
++ if (mac->hw->mii_bus->phy_map[cmd->phy_address]) {
++ mac->phy_dev =
++ mac->hw->mii_bus->phy_map[cmd->phy_address];
++ } else {
+ return -ENODEV;
++ }
+ }
+
+ return phy_ethtool_sset(mac->phy_dev, cmd);
diff --git a/target/linux/mediatek/patches-4.4/0200-devicetree.patch b/target/linux/mediatek/patches-4.4/0200-devicetree.patch
index 0f2ba50885..eb743c7247 100644
--- a/target/linux/mediatek/patches-4.4/0200-devicetree.patch
+++ b/target/linux/mediatek/patches-4.4/0200-devicetree.patch
@@ -1,6 +1,6 @@
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
-@@ -775,6 +775,8 @@
+@@ -775,6 +775,8 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \
mt6589-aquaris5.dtb \
mt6592-evb.dtb \
mt7623-evb.dtb \
diff --git a/target/linux/mediatek/patches-4.4/0100-block2mtd.patch b/target/linux/mediatek/patches-4.4/0201-block2mtd.patch
index 395884b730..395884b730 100644
--- a/target/linux/mediatek/patches-4.4/0100-block2mtd.patch
+++ b/target/linux/mediatek/patches-4.4/0201-block2mtd.patch
diff --git a/target/linux/mvebu/patches-4.4/001-fix_gpio_config_on_linksys_boards.patch b/target/linux/mvebu/patches-4.4/001-fix_gpio_config_on_linksys_boards.patch
deleted file mode 100644
index c92a1d73ef..0000000000
--- a/target/linux/mvebu/patches-4.4/001-fix_gpio_config_on_linksys_boards.patch
+++ /dev/null
@@ -1,58 +0,0 @@
-Some of the GPIO configs were wrong in the submitted DTS files,
-this patch fixes all affected boards.
-
-Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
-
-Cc: <stable@vger.kernel.org> # v4.1 +
----
- arch/arm/boot/dts/armada-385-linksys.dtsi | 6 +++---
- arch/arm/boot/dts/armada-xp-linksys-mamba.dts | 4 ++--
- 2 files changed, 5 insertions(+), 5 deletions(-)
-
---- a/arch/arm/boot/dts/armada-385-linksys.dtsi
-+++ b/arch/arm/boot/dts/armada-385-linksys.dtsi
-@@ -245,7 +245,7 @@
- button@2 {
- label = "Factory Reset Button";
- linux,code = <KEY_RESTART>;
-- gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
-+ gpios = <&gpio0 29 GPIO_ACTIVE_LOW>;
- };
- };
-
-@@ -260,7 +260,7 @@
- };
-
- sata {
-- gpios = <&gpio1 22 GPIO_ACTIVE_HIGH>;
-+ gpios = <&gpio1 22 GPIO_ACTIVE_LOW>;
- default-state = "off";
- };
- };
-@@ -313,7 +313,7 @@
-
- &pinctrl {
- keys_pin: keys-pin {
-- marvell,pins = "mpp24", "mpp47";
-+ marvell,pins = "mpp24", "mpp29";
- marvell,function = "gpio";
- };
-
---- a/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
-+++ b/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
-@@ -304,13 +304,13 @@
- button@1 {
- label = "WPS";
- linux,code = <KEY_WPS_BUTTON>;
-- gpios = <&gpio1 0 GPIO_ACTIVE_HIGH>;
-+ gpios = <&gpio1 0 GPIO_ACTIVE_LOW>;
- };
-
- button@2 {
- label = "Factory Reset Button";
- linux,code = <KEY_RESTART>;
-- gpios = <&gpio1 1 GPIO_ACTIVE_HIGH>;
-+ gpios = <&gpio1 1 GPIO_ACTIVE_LOW>;
- };
- };
-
diff --git a/target/linux/oxnas/patches-4.4/320-oxnas-irqchip.patch b/target/linux/oxnas/patches-4.4/320-oxnas-irqchip.patch
index 62224b63b1..37918d680b 100644
--- a/target/linux/oxnas/patches-4.4/320-oxnas-irqchip.patch
+++ b/target/linux/oxnas/patches-4.4/320-oxnas-irqchip.patch
@@ -24,7 +24,7 @@
obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
-@@ -1245,6 +1245,7 @@ IRQCHIP_DECLARE(arm1176jzf_dc_gic, "arm,
+@@ -1253,6 +1253,7 @@ IRQCHIP_DECLARE(arm1176jzf_dc_gic, "arm,
IRQCHIP_DECLARE(cortex_a15_gic, "arm,cortex-a15-gic", gic_of_init);
IRQCHIP_DECLARE(cortex_a9_gic, "arm,cortex-a9-gic", gic_of_init);
IRQCHIP_DECLARE(cortex_a7_gic, "arm,cortex-a7-gic", gic_of_init);
diff --git a/target/linux/ramips/patches-4.4/0010-MIPS-ralink-Add-a-few-missing-clocks.patch b/target/linux/ramips/patches-4.4/0010-MIPS-ralink-Add-a-few-missing-clocks.patch
new file mode 100644
index 0000000000..56bca7838b
--- /dev/null
+++ b/target/linux/ramips/patches-4.4/0010-MIPS-ralink-Add-a-few-missing-clocks.patch
@@ -0,0 +1,48 @@
+From 3b2e7c7c83873f4c073d501c2fff80518e264240 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 4 Jan 2016 20:24:00 +0100
+Subject: [PATCH] MIPS: ralink: Add a few missing clocks
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+Cc: linux-mips@linux-mips.org
+Patchwork: https://patchwork.linux-mips.org/patch/11995/
+Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
+---
+ arch/mips/ralink/mt7620.c | 3 +++
+ arch/mips/ralink/rt305x.c | 1 +
+ arch/mips/ralink/rt3883.c | 1 +
+ 3 files changed, 5 insertions(+)
+
+--- a/arch/mips/ralink/mt7620.c
++++ b/arch/mips/ralink/mt7620.c
+@@ -436,7 +436,10 @@ void __init ralink_clk_init(void)
+ ralink_clk_add("10000100.timer", periph_rate);
+ ralink_clk_add("10000120.watchdog", periph_rate);
+ ralink_clk_add("10000b00.spi", sys_rate);
++ ralink_clk_add("10000b40.spi", sys_rate);
+ ralink_clk_add("10000c00.uartlite", periph_rate);
++ ralink_clk_add("10000d00.uart1", periph_rate);
++ ralink_clk_add("10000e00.uart2", periph_rate);
+ ralink_clk_add("10180000.wmac", xtal_rate);
+
+ if (IS_ENABLED(CONFIG_USB) && is_mt76x8()) {
+--- a/arch/mips/ralink/rt305x.c
++++ b/arch/mips/ralink/rt305x.c
+@@ -201,6 +201,7 @@ void __init ralink_clk_init(void)
+ ralink_clk_add("cpu", cpu_rate);
+ ralink_clk_add("sys", sys_rate);
+ ralink_clk_add("10000b00.spi", sys_rate);
++ ralink_clk_add("10000b40.spi", sys_rate);
+ ralink_clk_add("10000100.timer", wdt_rate);
+ ralink_clk_add("10000120.watchdog", wdt_rate);
+ ralink_clk_add("10000500.uart", uart_rate);
+--- a/arch/mips/ralink/rt3883.c
++++ b/arch/mips/ralink/rt3883.c
+@@ -109,6 +109,7 @@ void __init ralink_clk_init(void)
+ ralink_clk_add("10000120.watchdog", sys_rate);
+ ralink_clk_add("10000500.uart", 40000000);
+ ralink_clk_add("10000b00.spi", sys_rate);
++ ralink_clk_add("10000b40.spi", sys_rate);
+ ralink_clk_add("10000c00.uartlite", 40000000);
+ ralink_clk_add("10100000.ethernet", sys_rate);
+ ralink_clk_add("10180000.wmac", 40000000);
diff --git a/target/linux/ramips/patches-4.4/0010-arch-mips-ralink-add-spi1-clocks.patch b/target/linux/ramips/patches-4.4/0010-arch-mips-ralink-add-spi1-clocks.patch
deleted file mode 100644
index 1c3db6b6d2..0000000000
--- a/target/linux/ramips/patches-4.4/0010-arch-mips-ralink-add-spi1-clocks.patch
+++ /dev/null
@@ -1,44 +0,0 @@
-From 39ce22c870f4503bed5e451acfcab21eba3b6239 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Sun, 27 Jul 2014 09:49:07 +0100
-Subject: [PATCH 10/53] arch: mips: ralink: add spi1 clocks
-
-based on f3bc64d6d1f21c1b92d75f233a37b75d77af6963
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- arch/mips/ralink/mt7620.c | 1 +
- arch/mips/ralink/rt305x.c | 1 +
- arch/mips/ralink/rt3883.c | 1 +
- 3 files changed, 3 insertions(+)
-
---- a/arch/mips/ralink/mt7620.c
-+++ b/arch/mips/ralink/mt7620.c
-@@ -436,6 +436,7 @@ void __init ralink_clk_init(void)
- ralink_clk_add("10000100.timer", periph_rate);
- ralink_clk_add("10000120.watchdog", periph_rate);
- ralink_clk_add("10000b00.spi", sys_rate);
-+ ralink_clk_add("10000b40.spi", sys_rate);
- ralink_clk_add("10000c00.uartlite", periph_rate);
- ralink_clk_add("10180000.wmac", xtal_rate);
-
---- a/arch/mips/ralink/rt305x.c
-+++ b/arch/mips/ralink/rt305x.c
-@@ -201,6 +201,7 @@ void __init ralink_clk_init(void)
- ralink_clk_add("cpu", cpu_rate);
- ralink_clk_add("sys", sys_rate);
- ralink_clk_add("10000b00.spi", sys_rate);
-+ ralink_clk_add("10000b40.spi", sys_rate);
- ralink_clk_add("10000100.timer", wdt_rate);
- ralink_clk_add("10000120.watchdog", wdt_rate);
- ralink_clk_add("10000500.uart", uart_rate);
---- a/arch/mips/ralink/rt3883.c
-+++ b/arch/mips/ralink/rt3883.c
-@@ -109,6 +109,7 @@ void __init ralink_clk_init(void)
- ralink_clk_add("10000120.watchdog", sys_rate);
- ralink_clk_add("10000500.uart", 40000000);
- ralink_clk_add("10000b00.spi", sys_rate);
-+ ralink_clk_add("10000b40.spi", sys_rate);
- ralink_clk_add("10000c00.uartlite", 40000000);
- ralink_clk_add("10100000.ethernet", sys_rate);
- ralink_clk_add("10180000.wmac", 40000000);
diff --git a/target/linux/ramips/patches-4.4/0013-owrt-hack-fix-mt7688-cache-issue.patch b/target/linux/ramips/patches-4.4/0013-owrt-hack-fix-mt7688-cache-issue.patch
index b094b8840e..c9bba2a9dd 100644
--- a/target/linux/ramips/patches-4.4/0013-owrt-hack-fix-mt7688-cache-issue.patch
+++ b/target/linux/ramips/patches-4.4/0013-owrt-hack-fix-mt7688-cache-issue.patch
@@ -18,7 +18,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
sparse_init();
plat_swiotlb_setup();
paging_init();
-@@ -806,6 +805,7 @@ void __init setup_arch(char **cmdline_p)
+@@ -809,6 +808,7 @@ void __init setup_arch(char **cmdline_p)
prefill_possible_map();
cpu_cache_init();
diff --git a/target/linux/ramips/patches-4.4/0022-MIPS-ralink-Fix-vendor-string-for-mt7620.patch b/target/linux/ramips/patches-4.4/0022-MIPS-ralink-Fix-vendor-string-for-mt7620.patch
new file mode 100644
index 0000000000..05017b1bff
--- /dev/null
+++ b/target/linux/ramips/patches-4.4/0022-MIPS-ralink-Fix-vendor-string-for-mt7620.patch
@@ -0,0 +1,27 @@
+From 3bca798b859c75063b3b4e65f6b019c7a4bd53ef Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 4 Jan 2016 20:23:59 +0100
+Subject: [PATCH] MIPS: ralink: Fix vendor string for mt7620
+
+Ralink was acquired by Mediatek. Represent this in the cpuinfo. It
+apparently confused people.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+Cc: linux-mips@linux-mips.org
+Patchwork: https://patchwork.linux-mips.org/patch/11994/
+Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
+---
+ arch/mips/ralink/mt7620.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/mips/ralink/mt7620.c
++++ b/arch/mips/ralink/mt7620.c
+@@ -555,7 +555,7 @@ void prom_soc_init(struct ralink_soc_inf
+ }
+
+ snprintf(soc_info->sys_type, RAMIPS_SYS_TYPE_LEN,
+- "Ralink %s ver:%u eco:%u",
++ "MediaTek %s ver:%u eco:%u",
+ name,
+ (rev >> CHIP_REV_VER_SHIFT) & CHIP_REV_VER_MASK,
+ (rev & CHIP_REV_ECO_MASK));
diff --git a/target/linux/ramips/patches-4.4/0022-arch-mips-ralink-proper-vendor-id-srtring.patch b/target/linux/ramips/patches-4.4/0022-arch-mips-ralink-proper-vendor-id-srtring.patch
deleted file mode 100644
index adadf2a9ab..0000000000
--- a/target/linux/ramips/patches-4.4/0022-arch-mips-ralink-proper-vendor-id-srtring.patch
+++ /dev/null
@@ -1,21 +0,0 @@
-From 2e5d90398aacde3e46dfd87e6f716b00a0ffcd83 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Mon, 7 Dec 2015 17:30:11 +0100
-Subject: [PATCH 22/53] arch: mips: ralink: proper vendor id srtring
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- arch/mips/ralink/mt7620.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/arch/mips/ralink/mt7620.c
-+++ b/arch/mips/ralink/mt7620.c
-@@ -553,7 +553,7 @@ void prom_soc_init(struct ralink_soc_inf
- }
-
- snprintf(soc_info->sys_type, RAMIPS_SYS_TYPE_LEN,
-- "Ralink %s ver:%u eco:%u",
-+ "MediaTek %s ver:%u eco:%u",
- name,
- (rev >> CHIP_REV_VER_SHIFT) & CHIP_REV_VER_MASK,
- (rev & CHIP_REV_ECO_MASK));
diff --git a/target/linux/ramips/patches-4.4/0033-xhci-mediatek-support-MTK-xHCI-host-controller.patch b/target/linux/ramips/patches-4.4/0033-xhci-mediatek-support-MTK-xHCI-host-controller.patch
index a00d2d7d3b..4107d49ce6 100644
--- a/target/linux/ramips/patches-4.4/0033-xhci-mediatek-support-MTK-xHCI-host-controller.patch
+++ b/target/linux/ramips/patches-4.4/0033-xhci-mediatek-support-MTK-xHCI-host-controller.patch
@@ -1466,7 +1466,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
#define DRIVER_AUTHOR "Sarah Sharp"
#define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver"
-@@ -634,7 +635,11 @@ int xhci_run(struct usb_hcd *hcd)
+@@ -635,7 +636,11 @@ int xhci_run(struct usb_hcd *hcd)
"// Set the interrupt modulation register");
temp = readl(&xhci->ir_set->irq_control);
temp &= ~ER_IRQ_INTERVAL_MASK;
@@ -1479,7 +1479,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
writel(temp, &xhci->ir_set->irq_control);
/* Set the HCD state before we enable the irqs */
-@@ -1700,6 +1705,9 @@ int xhci_drop_endpoint(struct usb_hcd *h
+@@ -1701,6 +1706,9 @@ int xhci_drop_endpoint(struct usb_hcd *h
xhci_endpoint_zero(xhci, xhci->devs[udev->slot_id], ep);
@@ -1489,7 +1489,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
xhci_dbg(xhci, "drop ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x\n",
(unsigned int) ep->desc.bEndpointAddress,
udev->slot_id,
-@@ -1795,6 +1803,15 @@ int xhci_add_endpoint(struct usb_hcd *hc
+@@ -1796,6 +1804,15 @@ int xhci_add_endpoint(struct usb_hcd *hc
return -ENOMEM;
}
@@ -1507,7 +1507,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
-@@ -1630,6 +1630,7 @@ struct xhci_hcd {
+@@ -1631,6 +1631,7 @@ struct xhci_hcd {
/* For controllers with a broken beyond repair streams implementation */
#define XHCI_BROKEN_STREAMS (1 << 19)
#define XHCI_PME_STUCK_QUIRK (1 << 20)
diff --git a/target/linux/ramips/patches-4.4/0049-watchdog-add-MT7621-support.patch b/target/linux/ramips/patches-4.4/0049-watchdog-add-MT7621-support.patch
index eba6d7a390..529a801dc5 100644
--- a/target/linux/ramips/patches-4.4/0049-watchdog-add-MT7621-support.patch
+++ b/target/linux/ramips/patches-4.4/0049-watchdog-add-MT7621-support.patch
@@ -13,7 +13,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
-@@ -1354,6 +1354,13 @@ config RALINK_WDT
+@@ -1345,6 +1345,13 @@ config RALINK_WDT
help
Hardware driver for the Ralink SoC Watchdog Timer.
diff --git a/target/linux/ramips/patches-4.4/0054-mtd-add-chunked-read-io-to-m25p80.patch b/target/linux/ramips/patches-4.4/0054-mtd-add-chunked-read-io-to-m25p80.patch
index 9821dac322..281dd5eaa4 100644
--- a/target/linux/ramips/patches-4.4/0054-mtd-add-chunked-read-io-to-m25p80.patch
+++ b/target/linux/ramips/patches-4.4/0054-mtd-add-chunked-read-io-to-m25p80.patch
@@ -1,6 +1,6 @@
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
-@@ -1008,6 +1008,66 @@ write_err:
+@@ -1009,6 +1009,66 @@ write_err:
return ret;
}
@@ -67,7 +67,7 @@
static int macronix_quad_enable(struct spi_nor *nor)
{
int ret, val;
-@@ -1229,10 +1289,12 @@ int spi_nor_scan(struct spi_nor *nor, co
+@@ -1187,10 +1247,12 @@ int spi_nor_scan(struct spi_nor *nor, co
}
/* sst nor chips use AAI word program */
@@ -82,7 +82,7 @@
if (info->flags & USE_FSR)
nor->flags |= SNOR_F_USE_FSR;
-@@ -1260,11 +1322,20 @@ int spi_nor_scan(struct spi_nor *nor, co
+@@ -1218,11 +1280,20 @@ int spi_nor_scan(struct spi_nor *nor, co
mtd->writebufsize = nor->page_size;
if (np) {
diff --git a/target/linux/ramips/patches-4.4/0065-MIPS-ralink-MT7688-pinmux-fixes.patch b/target/linux/ramips/patches-4.4/0065-MIPS-ralink-MT7688-pinmux-fixes.patch
new file mode 100644
index 0000000000..18571e6928
--- /dev/null
+++ b/target/linux/ramips/patches-4.4/0065-MIPS-ralink-MT7688-pinmux-fixes.patch
@@ -0,0 +1,166 @@
+From e906a5f67e5a3337d696ec848e9c28fc68b39aa3 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 4 Jan 2016 20:23:56 +0100
+Subject: [PATCH] MIPS: ralink: MT7688 pinmux fixes
+
+A few fixes to the pinmux data, 2 new muxes and a minor whitespace
+cleanup.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+Cc: linux-mips@linux-mips.org
+Patchwork: https://patchwork.linux-mips.org/patch/11991/
+Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
+---
+ arch/mips/ralink/mt7620.c | 80 +++++++++++++++++++++++++++++------------------
+ 1 file changed, 50 insertions(+), 30 deletions(-)
+
+--- a/arch/mips/ralink/mt7620.c
++++ b/arch/mips/ralink/mt7620.c
+@@ -107,31 +107,31 @@ static struct rt2880_pmx_group mt7620a_p
+ };
+
+ static struct rt2880_pmx_func pwm1_grp_mt7628[] = {
+- FUNC("sdcx", 3, 19, 1),
++ FUNC("sdxc d6", 3, 19, 1),
+ FUNC("utif", 2, 19, 1),
+ FUNC("gpio", 1, 19, 1),
+- FUNC("pwm", 0, 19, 1),
++ FUNC("pwm1", 0, 19, 1),
+ };
+
+ static struct rt2880_pmx_func pwm0_grp_mt7628[] = {
+- FUNC("sdcx", 3, 18, 1),
++ FUNC("sdxc d7", 3, 18, 1),
+ FUNC("utif", 2, 18, 1),
+ FUNC("gpio", 1, 18, 1),
+- FUNC("pwm", 0, 18, 1),
++ FUNC("pwm0", 0, 18, 1),
+ };
+
+ static struct rt2880_pmx_func uart2_grp_mt7628[] = {
+- FUNC("sdcx", 3, 20, 2),
++ FUNC("sdxc d5 d4", 3, 20, 2),
+ FUNC("pwm", 2, 20, 2),
+ FUNC("gpio", 1, 20, 2),
+- FUNC("uart", 0, 20, 2),
++ FUNC("uart2", 0, 20, 2),
+ };
+
+ static struct rt2880_pmx_func uart1_grp_mt7628[] = {
+- FUNC("sdcx", 3, 45, 2),
++ FUNC("sw_r", 3, 45, 2),
+ FUNC("pwm", 2, 45, 2),
+ FUNC("gpio", 1, 45, 2),
+- FUNC("uart", 0, 45, 2),
++ FUNC("uart1", 0, 45, 2),
+ };
+
+ static struct rt2880_pmx_func i2c_grp_mt7628[] = {
+@@ -143,21 +143,21 @@ static struct rt2880_pmx_func i2c_grp_mt
+
+ static struct rt2880_pmx_func refclk_grp_mt7628[] = { FUNC("reclk", 0, 36, 1) };
+ static struct rt2880_pmx_func perst_grp_mt7628[] = { FUNC("perst", 0, 37, 1) };
+-static struct rt2880_pmx_func wdt_grp_mt7628[] = { FUNC("wdt", 0, 15, 38) };
++static struct rt2880_pmx_func wdt_grp_mt7628[] = { FUNC("wdt", 0, 38, 1) };
+ static struct rt2880_pmx_func spi_grp_mt7628[] = { FUNC("spi", 0, 7, 4) };
+
+ static struct rt2880_pmx_func sd_mode_grp_mt7628[] = {
+ FUNC("jtag", 3, 22, 8),
+ FUNC("utif", 2, 22, 8),
+ FUNC("gpio", 1, 22, 8),
+- FUNC("sdcx", 0, 22, 8),
++ FUNC("sdxc", 0, 22, 8),
+ };
+
+ static struct rt2880_pmx_func uart0_grp_mt7628[] = {
+ FUNC("-", 3, 12, 2),
+ FUNC("-", 2, 12, 2),
+ FUNC("gpio", 1, 12, 2),
+- FUNC("uart", 0, 12, 2),
++ FUNC("uart0", 0, 12, 2),
+ };
+
+ static struct rt2880_pmx_func i2s_grp_mt7628[] = {
+@@ -171,7 +171,7 @@ static struct rt2880_pmx_func spi_cs1_gr
+ FUNC("-", 3, 6, 1),
+ FUNC("refclk", 2, 6, 1),
+ FUNC("gpio", 1, 6, 1),
+- FUNC("spi", 0, 6, 1),
++ FUNC("spi cs1", 0, 6, 1),
+ };
+
+ static struct rt2880_pmx_func spis_grp_mt7628[] = {
+@@ -188,28 +188,44 @@ static struct rt2880_pmx_func gpio_grp_m
+ FUNC("gpio", 0, 11, 1),
+ };
+
+-#define MT7628_GPIO_MODE_MASK 0x3
+-
+-#define MT7628_GPIO_MODE_PWM1 30
+-#define MT7628_GPIO_MODE_PWM0 28
+-#define MT7628_GPIO_MODE_UART2 26
+-#define MT7628_GPIO_MODE_UART1 24
+-#define MT7628_GPIO_MODE_I2C 20
+-#define MT7628_GPIO_MODE_REFCLK 18
+-#define MT7628_GPIO_MODE_PERST 16
+-#define MT7628_GPIO_MODE_WDT 14
+-#define MT7628_GPIO_MODE_SPI 12
+-#define MT7628_GPIO_MODE_SDMODE 10
+-#define MT7628_GPIO_MODE_UART0 8
+-#define MT7628_GPIO_MODE_I2S 6
+-#define MT7628_GPIO_MODE_CS1 4
+-#define MT7628_GPIO_MODE_SPIS 2
+-#define MT7628_GPIO_MODE_GPIO 0
++static struct rt2880_pmx_func wled_kn_grp_mt7628[] = {
++ FUNC("rsvd", 3, 35, 1),
++ FUNC("rsvd", 2, 35, 1),
++ FUNC("gpio", 1, 35, 1),
++ FUNC("wled_kn", 0, 35, 1),
++};
++
++static struct rt2880_pmx_func wled_an_grp_mt7628[] = {
++ FUNC("rsvd", 3, 35, 1),
++ FUNC("rsvd", 2, 35, 1),
++ FUNC("gpio", 1, 35, 1),
++ FUNC("wled_an", 0, 35, 1),
++};
++
++#define MT7628_GPIO_MODE_MASK 0x3
++
++#define MT7628_GPIO_MODE_WLED_KN 48
++#define MT7628_GPIO_MODE_WLED_AN 32
++#define MT7628_GPIO_MODE_PWM1 30
++#define MT7628_GPIO_MODE_PWM0 28
++#define MT7628_GPIO_MODE_UART2 26
++#define MT7628_GPIO_MODE_UART1 24
++#define MT7628_GPIO_MODE_I2C 20
++#define MT7628_GPIO_MODE_REFCLK 18
++#define MT7628_GPIO_MODE_PERST 16
++#define MT7628_GPIO_MODE_WDT 14
++#define MT7628_GPIO_MODE_SPI 12
++#define MT7628_GPIO_MODE_SDMODE 10
++#define MT7628_GPIO_MODE_UART0 8
++#define MT7628_GPIO_MODE_I2S 6
++#define MT7628_GPIO_MODE_CS1 4
++#define MT7628_GPIO_MODE_SPIS 2
++#define MT7628_GPIO_MODE_GPIO 0
+
+ static struct rt2880_pmx_group mt7628an_pinmux_data[] = {
+ GRP_G("pmw1", pwm1_grp_mt7628, MT7628_GPIO_MODE_MASK,
+ 1, MT7628_GPIO_MODE_PWM1),
+- GRP_G("pmw1", pwm0_grp_mt7628, MT7628_GPIO_MODE_MASK,
++ GRP_G("pmw0", pwm0_grp_mt7628, MT7628_GPIO_MODE_MASK,
+ 1, MT7628_GPIO_MODE_PWM0),
+ GRP_G("uart2", uart2_grp_mt7628, MT7628_GPIO_MODE_MASK,
+ 1, MT7628_GPIO_MODE_UART2),
+@@ -233,6 +249,10 @@ static struct rt2880_pmx_group mt7628an_
+ 1, MT7628_GPIO_MODE_SPIS),
+ GRP_G("gpio", gpio_grp_mt7628, MT7628_GPIO_MODE_MASK,
+ 1, MT7628_GPIO_MODE_GPIO),
++ GRP_G("wled_an", wled_an_grp_mt7628, MT7628_GPIO_MODE_MASK,
++ 1, MT7628_GPIO_MODE_WLED_AN),
++ GRP_G("wled_kn", wled_kn_grp_mt7628, MT7628_GPIO_MODE_MASK,
++ 1, MT7628_GPIO_MODE_WLED_KN),
+ { 0 }
+ };
+
diff --git a/target/linux/ramips/patches-4.4/0065-mt7688-fixes.patch b/target/linux/ramips/patches-4.4/0065-mt7688-fixes.patch
deleted file mode 100644
index b96be916e4..0000000000
--- a/target/linux/ramips/patches-4.4/0065-mt7688-fixes.patch
+++ /dev/null
@@ -1,73 +0,0 @@
---- a/arch/mips/ralink/mt7620.c
-+++ b/arch/mips/ralink/mt7620.c
-@@ -107,31 +107,31 @@ static struct rt2880_pmx_group mt7620a_p
- };
-
- static struct rt2880_pmx_func pwm1_grp_mt7628[] = {
-- FUNC("sdcx", 3, 19, 1),
-+ FUNC("sdxc", 3, 19, 1),
- FUNC("utif", 2, 19, 1),
- FUNC("gpio", 1, 19, 1),
- FUNC("pwm", 0, 19, 1),
- };
-
- static struct rt2880_pmx_func pwm0_grp_mt7628[] = {
-- FUNC("sdcx", 3, 18, 1),
-+ FUNC("sdxc", 3, 18, 1),
- FUNC("utif", 2, 18, 1),
- FUNC("gpio", 1, 18, 1),
- FUNC("pwm", 0, 18, 1),
- };
-
- static struct rt2880_pmx_func uart2_grp_mt7628[] = {
-- FUNC("sdcx", 3, 20, 2),
-+ FUNC("sdxc", 3, 20, 2),
- FUNC("pwm", 2, 20, 2),
- FUNC("gpio", 1, 20, 2),
-- FUNC("uart", 0, 20, 2),
-+ FUNC("uart2", 0, 20, 2),
- };
-
- static struct rt2880_pmx_func uart1_grp_mt7628[] = {
- FUNC("sdcx", 3, 45, 2),
- FUNC("pwm", 2, 45, 2),
- FUNC("gpio", 1, 45, 2),
-- FUNC("uart", 0, 45, 2),
-+ FUNC("uart1", 0, 45, 2),
- };
-
- static struct rt2880_pmx_func i2c_grp_mt7628[] = {
-@@ -143,21 +143,21 @@ static struct rt2880_pmx_func i2c_grp_mt
-
- static struct rt2880_pmx_func refclk_grp_mt7628[] = { FUNC("reclk", 0, 36, 1) };
- static struct rt2880_pmx_func perst_grp_mt7628[] = { FUNC("perst", 0, 37, 1) };
--static struct rt2880_pmx_func wdt_grp_mt7628[] = { FUNC("wdt", 0, 15, 38) };
-+static struct rt2880_pmx_func wdt_grp_mt7628[] = { FUNC("wdt", 0, 38, 1) };
- static struct rt2880_pmx_func spi_grp_mt7628[] = { FUNC("spi", 0, 7, 4) };
-
- static struct rt2880_pmx_func sd_mode_grp_mt7628[] = {
- FUNC("jtag", 3, 22, 8),
- FUNC("utif", 2, 22, 8),
- FUNC("gpio", 1, 22, 8),
-- FUNC("sdcx", 0, 22, 8),
-+ FUNC("sdxc", 0, 22, 8),
- };
-
- static struct rt2880_pmx_func uart0_grp_mt7628[] = {
- FUNC("-", 3, 12, 2),
- FUNC("-", 2, 12, 2),
- FUNC("gpio", 1, 12, 2),
-- FUNC("uart", 0, 12, 2),
-+ FUNC("uart0", 0, 12, 2),
- };
-
- static struct rt2880_pmx_func i2s_grp_mt7628[] = {
-@@ -438,6 +438,8 @@ void __init ralink_clk_init(void)
- ralink_clk_add("10000b00.spi", sys_rate);
- ralink_clk_add("10000b40.spi", sys_rate);
- ralink_clk_add("10000c00.uartlite", periph_rate);
-+ ralink_clk_add("10000d00.uart1", periph_rate);
-+ ralink_clk_add("10000e00.uart2", periph_rate);
- ralink_clk_add("10180000.wmac", xtal_rate);
-
- if (IS_ENABLED(CONFIG_USB) && is_mt76x8()) {
diff --git a/target/linux/ramips/patches-4.4/0080-MIPS-ralink-fix-USB-frequency-scaling.patch b/target/linux/ramips/patches-4.4/0080-MIPS-ralink-fix-USB-frequency-scaling.patch
index 0f3129e931..c7eec6ecf2 100644
--- a/target/linux/ramips/patches-4.4/0080-MIPS-ralink-fix-USB-frequency-scaling.patch
+++ b/target/linux/ramips/patches-4.4/0080-MIPS-ralink-fix-USB-frequency-scaling.patch
@@ -15,12 +15,10 @@ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/ralink/mt7620.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
-diff --git a/arch/mips/ralink/mt7620.c b/arch/mips/ralink/mt7620.c
-index dfb04fc..fc19932 100644
--- a/arch/mips/ralink/mt7620.c
+++ b/arch/mips/ralink/mt7620.c
-@@ -439,7 +439,7 @@ void __init ralink_clk_init(void)
- ralink_clk_add("10000c00.uartlite", periph_rate);
+@@ -462,7 +462,7 @@ void __init ralink_clk_init(void)
+ ralink_clk_add("10000e00.uart2", periph_rate);
ralink_clk_add("10180000.wmac", xtal_rate);
- if (IS_ENABLED(CONFIG_USB) && is_mt76x8()) {
@@ -28,6 +26,3 @@ index dfb04fc..fc19932 100644
/*
* When the CPU goes into sleep mode, the BUS clock will be
* too low for USB to function properly. Adjust the busses
---
-2.1.4
-
diff --git a/target/linux/ramips/patches-4.4/0081-MIPS-ralink-Fix-invalid-assignment-of-SoC-type.patch b/target/linux/ramips/patches-4.4/0081-MIPS-ralink-Fix-invalid-assignment-of-SoC-type.patch
new file mode 100644
index 0000000000..2c149cc9e2
--- /dev/null
+++ b/target/linux/ramips/patches-4.4/0081-MIPS-ralink-Fix-invalid-assignment-of-SoC-type.patch
@@ -0,0 +1,25 @@
+From 0af3a40f09a2a85089037a0b5b51471fa48b229e Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 4 Jan 2016 20:23:58 +0100
+Subject: [PATCH] MIPS: ralink: Fix invalid assignment of SoC type
+
+Commit 418d29c87061 ("MIPS: ralink: Unify SoC id handling") introduced
+broken code. We obviously need to assign the value.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+Cc: linux-mips@linux-mips.org
+Patchwork: https://patchwork.linux-mips.org/patch/11993/
+Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
+---
+ arch/mips/ralink/rt288x.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/mips/ralink/rt288x.c
++++ b/arch/mips/ralink/rt288x.c
+@@ -119,5 +119,5 @@ void prom_soc_init(struct ralink_soc_inf
+ soc_info->mem_size_max = RT2880_MEM_SIZE_MAX;
+
+ rt2880_pinmux_data = rt2880_pinmux_data_act;
+- ralink_soc == RT2880_SOC;
++ ralink_soc = RT2880_SOC;
+ }
diff --git a/target/linux/socfpga/config-4.4 b/target/linux/socfpga/config-4.4
index 15cac52fa8..b68bf7a9b0 100644
--- a/target/linux/socfpga/config-4.4
+++ b/target/linux/socfpga/config-4.4
@@ -416,6 +416,7 @@ CONFIG_MMC_DW_PLTFM=y
CONFIG_MODULES_TREE_LOOKUP=y
CONFIG_MODULES_USE_ELF_REL=y
CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_M25P80=y
CONFIG_MTD_SPI_NOR=y
CONFIG_MTD_UBI=y
CONFIG_MTD_UBI_BEB_LIMIT=20
@@ -621,6 +622,7 @@ CONFIG_SPARSE_IRQ=y
CONFIG_SPI=y
CONFIG_SPI_ALTERA=y
CONFIG_SPI_BITBANG=y
+CONFIG_SPI_CADENCE_QUADSPI=y
CONFIG_SPI_DESIGNWARE=y
CONFIG_SPI_DW_MMIO=y
CONFIG_SPI_MASTER=y
diff --git a/target/linux/socfpga/patches-4.4/0001-dt-bindings-gpio-altera-Fix-altr-interrupt-type-prop.patch b/target/linux/socfpga/patches-4.4/0001-dt-bindings-gpio-altera-Fix-altr-interrupt-type-prop.patch
index b89793a162..bf658eb734 100644
--- a/target/linux/socfpga/patches-4.4/0001-dt-bindings-gpio-altera-Fix-altr-interrupt-type-prop.patch
+++ b/target/linux/socfpga/patches-4.4/0001-dt-bindings-gpio-altera-Fix-altr-interrupt-type-prop.patch
@@ -1,7 +1,7 @@
-From b32732e51a774e8514f40975f2600f02ef9db0b4 Mon Sep 17 00:00:00 2001
+From 39c5b88eedd3e99c57aeaf7d7d61a830a4ef4b80 Mon Sep 17 00:00:00 2001
From: Marek Vasut <marex@denx.de>
Date: Mon, 29 Feb 2016 17:19:59 +0100
-Subject: [PATCH 1/5] dt-bindings: gpio: altera: Fix altr,interrupt-type
+Subject: [PATCH 01/33] dt-bindings: gpio: altera: Fix altr,interrupt-type
property
The altr,interrupt-trigger property is not used by the driver.
@@ -41,5 +41,5 @@ index 12f5014..826a720 100644
gpio-controller;
#interrupt-cells = <1>;
--
-2.7.0
+2.8.1
diff --git a/target/linux/socfpga/patches-4.4/0002-usb-dwc2-gadget-Repair-DSTS-register-decoding.patch b/target/linux/socfpga/patches-4.4/0002-usb-dwc2-gadget-Repair-DSTS-register-decoding.patch
index 9be3834055..2a2b2ba8c6 100644
--- a/target/linux/socfpga/patches-4.4/0002-usb-dwc2-gadget-Repair-DSTS-register-decoding.patch
+++ b/target/linux/socfpga/patches-4.4/0002-usb-dwc2-gadget-Repair-DSTS-register-decoding.patch
@@ -1,7 +1,7 @@
-From e5cbd23e4f40181c907a1abc136b17de8cb86809 Mon Sep 17 00:00:00 2001
+From f7697963e1b0fc1496709f84c00da5cb144a58a3 Mon Sep 17 00:00:00 2001
From: Marek Vasut <marex@denx.de>
Date: Thu, 17 Dec 2015 23:42:35 +0100
-Subject: [PATCH 2/5] usb: dwc2: gadget: Repair DSTS register decoding
+Subject: [PATCH 02/33] usb: dwc2: gadget: Repair DSTS register decoding
The "enumspd" field is located in register DSTS[2:1], but the code
which checks the bitfield does not shift the value accordingly. This
@@ -32,5 +32,5 @@ index 0abf73c..48e47c1 100644
case DSTS_ENUMSPD_FS48:
hsotg->gadget.speed = USB_SPEED_FULL;
--
-2.7.0
+2.8.1
diff --git a/target/linux/socfpga/patches-4.4/0003-ARM-socfpga-dts-Enable-MMC-support-at-correct-place-.patch b/target/linux/socfpga/patches-4.4/0003-ARM-socfpga-dts-Enable-MMC-support-at-correct-place-.patch
index b12de6dcf9..5dec33881e 100644
--- a/target/linux/socfpga/patches-4.4/0003-ARM-socfpga-dts-Enable-MMC-support-at-correct-place-.patch
+++ b/target/linux/socfpga/patches-4.4/0003-ARM-socfpga-dts-Enable-MMC-support-at-correct-place-.patch
@@ -1,8 +1,8 @@
-From 6b8c64eb90e5d958f32524ff2d0571b3b6ac92df Mon Sep 17 00:00:00 2001
+From 23d14e4479c925904bc7620a55c66eb8babacbb9 Mon Sep 17 00:00:00 2001
From: Marek Vasut <marex@denx.de>
Date: Mon, 21 Dec 2015 00:42:01 -0600
-Subject: [PATCH 3/5] ARM: socfpga: dts: Enable MMC support at correct place in
- the DT
+Subject: [PATCH 03/33] ARM: socfpga: dts: Enable MMC support at correct place
+ in the DT
The socfpga.dtsi explicitly enabled MMC support, but not all boards are
equiped with an MMC card. There are setups which only have QSPI NOR.
@@ -86,5 +86,5 @@ index 48bf651..b61f22f 100644
&usb1 {
--
-2.7.0
+2.8.1
diff --git a/target/linux/socfpga/patches-4.4/0004-ARM-socfpga-Add-support-for-HPS-LEDs-on-SoCKit.patch b/target/linux/socfpga/patches-4.4/0004-ARM-socfpga-Add-support-for-HPS-LEDs-on-SoCKit.patch
index 954f03e990..f3155c5b2c 100644
--- a/target/linux/socfpga/patches-4.4/0004-ARM-socfpga-Add-support-for-HPS-LEDs-on-SoCKit.patch
+++ b/target/linux/socfpga/patches-4.4/0004-ARM-socfpga-Add-support-for-HPS-LEDs-on-SoCKit.patch
@@ -1,7 +1,7 @@
-From e56e545745dc42cba743dab549d0afb1a39d14b4 Mon Sep 17 00:00:00 2001
+From 2088bf920b5ff60ab14e9fca940b4ae28e8b88d3 Mon Sep 17 00:00:00 2001
From: Marek Vasut <marex@denx.de>
Date: Mon, 22 Jun 2015 23:37:47 +0200
-Subject: [PATCH 4/5] ARM: socfpga: Add support for HPS LEDs on SoCKit
+Subject: [PATCH 04/33] ARM: socfpga: Add support for HPS LEDs on SoCKit
Add support for the blue LEDs on the SoCFPGA SoCkit board.
@@ -62,5 +62,5 @@ index b61f22f..1461690 100644
status = "okay";
};
--
-2.7.0
+2.8.1
diff --git a/target/linux/socfpga/patches-4.4/0005-ARM-socfpga-Add-support-for-HPS-KEYs-SWs-on-SoCKit.patch b/target/linux/socfpga/patches-4.4/0005-ARM-socfpga-Add-support-for-HPS-KEYs-SWs-on-SoCKit.patch
index a5e53f5d6c..8e24b6c1e1 100644
--- a/target/linux/socfpga/patches-4.4/0005-ARM-socfpga-Add-support-for-HPS-KEYs-SWs-on-SoCKit.patch
+++ b/target/linux/socfpga/patches-4.4/0005-ARM-socfpga-Add-support-for-HPS-KEYs-SWs-on-SoCKit.patch
@@ -1,7 +1,7 @@
-From a953c0800246e99c9b449bd9ec0b26682a82700c Mon Sep 17 00:00:00 2001
+From 7e990b69f2331daf7847ddb82bb5da9623f24f4f Mon Sep 17 00:00:00 2001
From: Marek Vasut <marex@denx.de>
Date: Tue, 23 Jun 2015 00:41:08 +0200
-Subject: [PATCH 5/5] ARM: socfpga: Add support for HPS KEYs/SWs on SoCKit
+Subject: [PATCH 05/33] ARM: socfpga: Add support for HPS KEYs/SWs on SoCKit
Add support for the keys and flip-switches on the SoCFPGA SoCkit board.
@@ -96,5 +96,5 @@ index 1461690..02e22f5 100644
};
--
-2.7.0
+2.8.1
diff --git a/target/linux/socfpga/patches-4.4/0006-mtd-add-get-set-of_node-flash_node-helpers.patch b/target/linux/socfpga/patches-4.4/0006-mtd-add-get-set-of_node-flash_node-helpers.patch
new file mode 100644
index 0000000000..c3415d316c
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0006-mtd-add-get-set-of_node-flash_node-helpers.patch
@@ -0,0 +1,87 @@
+From cb0416f4be60979f3fd3e99a9baff17ac9b8381f Mon Sep 17 00:00:00 2001
+From: Brian Norris <computersforpeace@gmail.com>
+Date: Fri, 30 Oct 2015 20:33:20 -0700
+Subject: [PATCH 06/33] mtd: add get/set of_node/flash_node helpers
+
+We are going to begin using the mtd->dev.of_node field for MTD device
+nodes, so let's add helpers for it. Also, we'll be making some
+conversions on spi_nor (and nand_chip eventually) too, so get that ready
+with their own helpers.
+
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+Reviewed-by: Boris Brezillon <boris.brezillon@free-electrons.com>
+---
+ include/linux/mtd/mtd.h | 11 +++++++++++
+ include/linux/mtd/nand.h | 11 +++++++++++
+ include/linux/mtd/spi-nor.h | 11 +++++++++++
+ 3 files changed, 33 insertions(+)
+
+diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
+index f17fa75..cc84923 100644
+--- a/include/linux/mtd/mtd.h
++++ b/include/linux/mtd/mtd.h
+@@ -254,6 +254,17 @@ struct mtd_info {
+ int usecount;
+ };
+
++static inline void mtd_set_of_node(struct mtd_info *mtd,
++ struct device_node *np)
++{
++ mtd->dev.of_node = np;
++}
++
++static inline struct device_node *mtd_get_of_node(struct mtd_info *mtd)
++{
++ return mtd->dev.of_node;
++}
++
+ int mtd_erase(struct mtd_info *mtd, struct erase_info *instr);
+ int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
+ void **virt, resource_size_t *phys);
+diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
+index 5a9d1d4..4f7c9b9 100644
+--- a/include/linux/mtd/nand.h
++++ b/include/linux/mtd/nand.h
+@@ -719,6 +719,17 @@ struct nand_chip {
+ void *priv;
+ };
+
++static inline void nand_set_flash_node(struct nand_chip *chip,
++ struct device_node *np)
++{
++ chip->flash_node = np;
++}
++
++static inline struct device_node *nand_get_flash_node(struct nand_chip *chip)
++{
++ return chip->flash_node;
++}
++
+ /*
+ * NAND Flash Manufacturer ID Codes
+ */
+diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
+index 12a4611..823c5381 100644
+--- a/include/linux/mtd/spi-nor.h
++++ b/include/linux/mtd/spi-nor.h
+@@ -184,6 +184,17 @@ struct spi_nor {
+ void *priv;
+ };
+
++static inline void spi_nor_set_flash_node(struct spi_nor *nor,
++ struct device_node *np)
++{
++ nor->flash_node = np;
++}
++
++static inline struct device_node *spi_nor_get_flash_node(struct spi_nor *nor)
++{
++ return nor->flash_node;
++}
++
+ /**
+ * spi_nor_scan() - scan the SPI NOR
+ * @nor: the spi_nor structure
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0007-mtd-nand-spi-nor-assign-MTD-of_node.patch b/target/linux/socfpga/patches-4.4/0007-mtd-nand-spi-nor-assign-MTD-of_node.patch
new file mode 100644
index 0000000000..c556a640a4
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0007-mtd-nand-spi-nor-assign-MTD-of_node.patch
@@ -0,0 +1,44 @@
+From 0b3e7c875f3f6ac9127b55eb99817c2f412e164e Mon Sep 17 00:00:00 2001
+From: Brian Norris <computersforpeace@gmail.com>
+Date: Fri, 30 Oct 2015 20:33:22 -0700
+Subject: [PATCH 07/33] mtd: {nand,spi-nor}: assign MTD of_node
+
+We should pass along our flash DT node to the MTD layer, so it can set
+up ofpart for us.
+
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+Reviewed-by: Boris Brezillon <boris.brezillon@free-electrons.com>
+---
+ drivers/mtd/nand/nand_base.c | 3 +++
+ drivers/mtd/spi-nor/spi-nor.c | 1 +
+ 2 files changed, 4 insertions(+)
+
+diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
+index 3ff583f..1f30656 100644
+--- a/drivers/mtd/nand/nand_base.c
++++ b/drivers/mtd/nand/nand_base.c
+@@ -3990,6 +3990,9 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
+ int ret;
+
+ if (chip->flash_node) {
++ /* MTD can automatically handle DT partitions, etc. */
++ mtd_set_of_node(mtd, chip->flash_node);
++
+ ret = nand_dt_init(mtd, chip, chip->flash_node);
+ if (ret)
+ return ret;
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index 32477c4..24ad373 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1256,6 +1256,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+ mtd->flags |= MTD_NO_ERASE;
+
+ mtd->dev.parent = dev;
++ mtd_set_of_node(mtd, np);
+ nor->page_size = info->page_size;
+ mtd->writebufsize = nor->page_size;
+
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0008-mtd-spi-nor-convert-to-spi_nor_-get-set-_flash_node.patch b/target/linux/socfpga/patches-4.4/0008-mtd-spi-nor-convert-to-spi_nor_-get-set-_flash_node.patch
new file mode 100644
index 0000000000..0f4093f424
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0008-mtd-spi-nor-convert-to-spi_nor_-get-set-_flash_node.patch
@@ -0,0 +1,91 @@
+From bf8554bc3b6b699e9c5b990f63b286b31cf7e80b Mon Sep 17 00:00:00 2001
+From: Brian Norris <computersforpeace@gmail.com>
+Date: Fri, 30 Oct 2015 20:33:24 -0700
+Subject: [PATCH 08/33] mtd: spi-nor: convert to spi_nor_{get,
+ set}_flash_node()
+
+Used semantic patch with 'make coccicheck MODE=patch COCCI=script.cocci':
+
+---8<----
+virtual patch
+
+@@
+struct spi_nor b;
+struct spi_nor *c;
+expression d;
+@@
+(
+-(b).flash_node = (d)
++spi_nor_set_flash_node(&b, d)
+|
+-(c)->flash_node = (d)
++spi_nor_set_flash_node(c, d)
+)
+---8<----
+
+And a manual conversion for the one use of spi_nor_get_flash_node().
+
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+Reviewed-by: Boris Brezillon <boris.brezillon@free-electrons.com>
+---
+ drivers/mtd/devices/m25p80.c | 2 +-
+ drivers/mtd/spi-nor/fsl-quadspi.c | 2 +-
+ drivers/mtd/spi-nor/nxp-spifi.c | 2 +-
+ drivers/mtd/spi-nor/spi-nor.c | 2 +-
+ 4 files changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
+index fe9ceb7..bc7a802 100644
+--- a/drivers/mtd/devices/m25p80.c
++++ b/drivers/mtd/devices/m25p80.c
+@@ -199,7 +199,7 @@ static int m25p_probe(struct spi_device *spi)
+ nor->read_reg = m25p80_read_reg;
+
+ nor->dev = &spi->dev;
+- nor->flash_node = spi->dev.of_node;
++ spi_nor_set_flash_node(nor, spi->dev.of_node);
+ nor->priv = flash;
+
+ spi_set_drvdata(spi, flash);
+diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c
+index 7b10ed4..8f4d920 100644
+--- a/drivers/mtd/spi-nor/fsl-quadspi.c
++++ b/drivers/mtd/spi-nor/fsl-quadspi.c
+@@ -1013,7 +1013,7 @@ static int fsl_qspi_probe(struct platform_device *pdev)
+ mtd = &nor->mtd;
+
+ nor->dev = dev;
+- nor->flash_node = np;
++ spi_nor_set_flash_node(nor, np);
+ nor->priv = q;
+
+ /* fill the hooks */
+diff --git a/drivers/mtd/spi-nor/nxp-spifi.c b/drivers/mtd/spi-nor/nxp-spifi.c
+index 9e82098..4524b28 100644
+--- a/drivers/mtd/spi-nor/nxp-spifi.c
++++ b/drivers/mtd/spi-nor/nxp-spifi.c
+@@ -330,7 +330,7 @@ static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
+ writel(ctrl, spifi->io_base + SPIFI_CTRL);
+
+ spifi->nor.dev = spifi->dev;
+- spifi->nor.flash_node = np;
++ spi_nor_set_flash_node(&spifi->nor, np);
+ spifi->nor.priv = spifi;
+ spifi->nor.read = nxp_spifi_read;
+ spifi->nor.write = nxp_spifi_write;
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index 24ad373..b76090e 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1151,7 +1151,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+ const struct flash_info *info = NULL;
+ struct device *dev = nor->dev;
+ struct mtd_info *mtd = &nor->mtd;
+- struct device_node *np = nor->flash_node;
++ struct device_node *np = spi_nor_get_flash_node(nor);
+ int ret;
+ int i;
+
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0009-mtd-spi-nor-drop-flash_node-field.patch b/target/linux/socfpga/patches-4.4/0009-mtd-spi-nor-drop-flash_node-field.patch
new file mode 100644
index 0000000000..1da6c949fb
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0009-mtd-spi-nor-drop-flash_node-field.patch
@@ -0,0 +1,64 @@
+From 1348b9e2300f66a4ffcb5b467f4c99cfb958ffca Mon Sep 17 00:00:00 2001
+From: Brian Norris <computersforpeace@gmail.com>
+Date: Fri, 30 Oct 2015 20:33:27 -0700
+Subject: [PATCH 09/33] mtd: spi-nor: drop flash_node field
+
+We can just alias to the MTD of_node.
+
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+Reviewed-by: Boris Brezillon <boris.brezillon@free-electrons.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 1 -
+ include/linux/mtd/spi-nor.h | 6 ++----
+ 2 files changed, 2 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index b76090e..3e06d5b 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1256,7 +1256,6 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+ mtd->flags |= MTD_NO_ERASE;
+
+ mtd->dev.parent = dev;
+- mtd_set_of_node(mtd, np);
+ nor->page_size = info->page_size;
+ mtd->writebufsize = nor->page_size;
+
+diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
+index 823c5381..592420b 100644
+--- a/include/linux/mtd/spi-nor.h
++++ b/include/linux/mtd/spi-nor.h
+@@ -123,7 +123,6 @@ enum spi_nor_option_flags {
+ * @mtd: point to a mtd_info structure
+ * @lock: the lock for the read/write/erase/lock/unlock operations
+ * @dev: point to a spi device, or a spi nor controller device.
+- * @flash_node: point to a device node describing this flash instance.
+ * @page_size: the page size of the SPI NOR
+ * @addr_width: number of address bytes
+ * @erase_opcode: the opcode for erasing a sector
+@@ -154,7 +153,6 @@ struct spi_nor {
+ struct mtd_info mtd;
+ struct mutex lock;
+ struct device *dev;
+- struct device_node *flash_node;
+ u32 page_size;
+ u8 addr_width;
+ u8 erase_opcode;
+@@ -187,12 +185,12 @@ struct spi_nor {
+ static inline void spi_nor_set_flash_node(struct spi_nor *nor,
+ struct device_node *np)
+ {
+- nor->flash_node = np;
++ mtd_set_of_node(&nor->mtd, np);
+ }
+
+ static inline struct device_node *spi_nor_get_flash_node(struct spi_nor *nor)
+ {
+- return nor->flash_node;
++ return mtd_get_of_node(&nor->mtd);
+ }
+
+ /**
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0010-mtd-spi-nor-remove-unnecessary-leading-space-from-db.patch b/target/linux/socfpga/patches-4.4/0010-mtd-spi-nor-remove-unnecessary-leading-space-from-db.patch
new file mode 100644
index 0000000000..19b22c5018
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0010-mtd-spi-nor-remove-unnecessary-leading-space-from-db.patch
@@ -0,0 +1,32 @@
+From f8c5645dd28440380622c2ad3744de0b55bd0bdf Mon Sep 17 00:00:00 2001
+From: Brian Norris <computersforpeace@gmail.com>
+Date: Fri, 30 Oct 2015 12:56:22 -0700
+Subject: [PATCH 10/33] mtd: spi-nor: remove unnecessary leading space from dbg
+ print
+
+As Cyrille noted [1], this line is wrong.
+
+[1] http://lists.infradead.org/pipermail/linux-mtd/2015-September/061725.html
+
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+Cc: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index 3e06d5b..107571e 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -856,7 +856,7 @@ static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
+
+ tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN);
+ if (tmp < 0) {
+- dev_dbg(nor->dev, " error %d reading JEDEC ID\n", tmp);
++ dev_dbg(nor->dev, "error %d reading JEDEC ID\n", tmp);
+ return ERR_PTR(tmp);
+ }
+
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0011-mtd-spi-nor-provide-default-erase_sector-implementat.patch b/target/linux/socfpga/patches-4.4/0011-mtd-spi-nor-provide-default-erase_sector-implementat.patch
new file mode 100644
index 0000000000..666b069451
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0011-mtd-spi-nor-provide-default-erase_sector-implementat.patch
@@ -0,0 +1,112 @@
+From 29675718c3880cbe7a8d8c6819c07dcec656c544 Mon Sep 17 00:00:00 2001
+From: Brian Norris <computersforpeace@gmail.com>
+Date: Tue, 10 Nov 2015 12:15:27 -0800
+Subject: [PATCH 11/33] mtd: spi-nor: provide default erase_sector
+ implementation
+
+Some spi-nor drivers perform sector erase by duplicating their
+write_reg() command. Let's not require that the driver fill this out,
+and provide a default instead.
+
+Tested on m25p80.c and Medatek's MT8173 SPI NOR flash driver.
+
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 37 +++++++++++++++++++++++++++++++++----
+ include/linux/mtd/spi-nor.h | 3 ++-
+ 2 files changed, 35 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index 107571e..0d2be38 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -38,6 +38,7 @@
+ #define CHIP_ERASE_2MB_READY_WAIT_JIFFIES (40UL * HZ)
+
+ #define SPI_NOR_MAX_ID_LEN 6
++#define SPI_NOR_MAX_ADDR_WIDTH 4
+
+ struct flash_info {
+ char *name;
+@@ -313,6 +314,29 @@ static void spi_nor_unlock_and_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
+ }
+
+ /*
++ * Initiate the erasure of a single sector
++ */
++static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
++{
++ u8 buf[SPI_NOR_MAX_ADDR_WIDTH];
++ int i;
++
++ if (nor->erase)
++ return nor->erase(nor, addr);
++
++ /*
++ * Default implementation, if driver doesn't have a specialized HW
++ * control
++ */
++ for (i = nor->addr_width - 1; i >= 0; i--) {
++ buf[i] = addr & 0xff;
++ addr >>= 8;
++ }
++
++ return nor->write_reg(nor, nor->erase_opcode, buf, nor->addr_width);
++}
++
++/*
+ * Erase an address range on the nor chip. The address range may extend
+ * one or more erase sectors. Return an error is there is a problem erasing.
+ */
+@@ -371,10 +395,9 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
+ while (len) {
+ write_enable(nor);
+
+- if (nor->erase(nor, addr)) {
+- ret = -EIO;
++ ret = spi_nor_erase_sector(nor, addr);
++ if (ret)
+ goto erase_err;
+- }
+
+ addr += mtd->erasesize;
+ len -= mtd->erasesize;
+@@ -1138,7 +1161,7 @@ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+ static int spi_nor_check(struct spi_nor *nor)
+ {
+ if (!nor->dev || !nor->read || !nor->write ||
+- !nor->read_reg || !nor->write_reg || !nor->erase) {
++ !nor->read_reg || !nor->write_reg) {
+ pr_err("spi-nor: please fill all the necessary fields!\n");
+ return -EINVAL;
+ }
+@@ -1338,6 +1361,12 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+ nor->addr_width = 3;
+ }
+
++ if (nor->addr_width > SPI_NOR_MAX_ADDR_WIDTH) {
++ dev_err(dev, "address width is too large: %u\n",
++ nor->addr_width);
++ return -EINVAL;
++ }
++
+ nor->read_dummy = spi_nor_read_dummy_cycles(nor);
+
+ dev_info(dev, "%s (%lld Kbytes)\n", info->name,
+diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
+index 592420b..62356d5 100644
+--- a/include/linux/mtd/spi-nor.h
++++ b/include/linux/mtd/spi-nor.h
+@@ -142,7 +142,8 @@ enum spi_nor_option_flags {
+ * @read: [DRIVER-SPECIFIC] read data from the SPI NOR
+ * @write: [DRIVER-SPECIFIC] write data to the SPI NOR
+ * @erase: [DRIVER-SPECIFIC] erase a sector of the SPI NOR
+- * at the offset @offs
++ * at the offset @offs; if not provided by the driver,
++ * spi-nor will send the erase opcode via write_reg()
+ * @flash_lock: [FLASH-SPECIFIC] lock a region of the SPI NOR
+ * @flash_unlock: [FLASH-SPECIFIC] unlock a region of the SPI NOR
+ * @flash_is_locked: [FLASH-SPECIFIC] check if a region of the SPI NOR is
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0012-mtd-spi-nor-mx25l3205d-mx25l6405d-append-SECT_4K.patch b/target/linux/socfpga/patches-4.4/0012-mtd-spi-nor-mx25l3205d-mx25l6405d-append-SECT_4K.patch
new file mode 100644
index 0000000000..720d687dff
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0012-mtd-spi-nor-mx25l3205d-mx25l6405d-append-SECT_4K.patch
@@ -0,0 +1,32 @@
+From 655585649ba3f4675b4386afc1feb22c6a880eb8 Mon Sep 17 00:00:00 2001
+From: Andreas Fenkart <afenkart@gmail.com>
+Date: Thu, 5 Nov 2015 10:04:23 +0100
+Subject: [PATCH 12/33] mtd: spi-nor: mx25l3205d/mx25l6405d: append SECT_4K
+
+according datasheet both chips can erase 4kByte sectors individually
+
+Signed-off-by: Andreas Fenkart <andreas.fenkart@dev.digitalstrom.org>
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index 0d2be38..c5bc927 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -738,9 +738,9 @@ static const struct flash_info spi_nor_ids[] = {
+ { "mx25l4005a", INFO(0xc22013, 0, 64 * 1024, 8, SECT_4K) },
+ { "mx25l8005", INFO(0xc22014, 0, 64 * 1024, 16, 0) },
+ { "mx25l1606e", INFO(0xc22015, 0, 64 * 1024, 32, SECT_4K) },
+- { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, 0) },
++ { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, SECT_4K) },
+ { "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) },
+- { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, 0) },
++ { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K) },
+ { "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) },
+ { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
+ { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0013-mtd-spi-nor-Fix-error-message-with-unrecognized-JEDE.patch b/target/linux/socfpga/patches-4.4/0013-mtd-spi-nor-Fix-error-message-with-unrecognized-JEDE.patch
new file mode 100644
index 0000000000..1fd89554b7
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0013-mtd-spi-nor-Fix-error-message-with-unrecognized-JEDE.patch
@@ -0,0 +1,35 @@
+From 14b9112f7d20455ffef7d796317e7d08c6545b41 Mon Sep 17 00:00:00 2001
+From: Ricardo Ribalda <ricardo.ribalda@gmail.com>
+Date: Mon, 30 Nov 2015 20:41:17 +0100
+Subject: [PATCH 13/33] mtd: spi-nor: Fix error message with unrecognized JEDEC
+
+The error message was:
+
+m25p80 spi32766.0: unrecognized JEDEC id bytes: 00, 0, 0
+
+The new error message:
+
+m25p80 spi32766.0: unrecognized JEDEC id bytes: 00, 00, 00
+
+Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com>
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index c5bc927..3a50eea 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -890,7 +890,7 @@ static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
+ return &spi_nor_ids[tmp];
+ }
+ }
+- dev_err(nor->dev, "unrecognized JEDEC id bytes: %02x, %2x, %2x\n",
++ dev_err(nor->dev, "unrecognized JEDEC id bytes: %02x, %02x, %02x\n",
+ id[0], id[1], id[2]);
+ return ERR_PTR(-ENODEV);
+ }
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0014-mtd-spi-nor-fix-error-handling-in-spi_nor_erase.patch b/target/linux/socfpga/patches-4.4/0014-mtd-spi-nor-fix-error-handling-in-spi_nor_erase.patch
new file mode 100644
index 0000000000..c9f48eaa5b
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0014-mtd-spi-nor-fix-error-handling-in-spi_nor_erase.patch
@@ -0,0 +1,44 @@
+From 93aa2e2f5af5b8e766fc22c3ff83a1642462025f Mon Sep 17 00:00:00 2001
+From: Heiner Kallweit <hkallweit1@gmail.com>
+Date: Tue, 17 Nov 2015 20:18:54 +0100
+Subject: [PATCH 14/33] mtd: spi-nor: fix error handling in spi_nor_erase
+
+The documenting comment of mtd_erase in mtdcore.c states:
+Device drivers are supposed to call instr->callback() whenever
+the operation completes, even if it completes with a failure.
+
+Currently the callback isn't called in case of failure. Fix this.
+
+Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 8 ++------
+ 1 file changed, 2 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index 3a50eea..43e00e2 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -410,17 +410,13 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
+
+ write_disable(nor);
+
++erase_err:
+ spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE);
+
+- instr->state = MTD_ERASE_DONE;
++ instr->state = ret ? MTD_ERASE_FAILED : MTD_ERASE_DONE;
+ mtd_erase_callback(instr);
+
+ return ret;
+-
+-erase_err:
+- spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE);
+- instr->state = MTD_ERASE_FAILED;
+- return ret;
+ }
+
+ static void stm_get_locked_range(struct spi_nor *nor, u8 sr, loff_t *ofs,
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0015-mtd-spi-nor-Check-the-return-value-from-read_sr.patch b/target/linux/socfpga/patches-4.4/0015-mtd-spi-nor-Check-the-return-value-from-read_sr.patch
new file mode 100644
index 0000000000..bfb5a97ac8
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0015-mtd-spi-nor-Check-the-return-value-from-read_sr.patch
@@ -0,0 +1,60 @@
+From 8f5f914b1b6d70d6d7455e0f89df84b3377677f9 Mon Sep 17 00:00:00 2001
+From: Fabio Estevam <fabio.estevam@freescale.com>
+Date: Fri, 20 Nov 2015 16:26:11 -0200
+Subject: [PATCH 15/33] mtd: spi-nor: Check the return value from read_sr()
+
+We should better check the return value from read_sr() and
+propagate it in the case of error.
+
+Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index 43e00e2..f8f36d4 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -478,11 +478,13 @@ static int stm_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
+ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
+ {
+ struct mtd_info *mtd = &nor->mtd;
+- u8 status_old, status_new;
++ int status_old, status_new;
+ u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
+ u8 shift = ffs(mask) - 1, pow, val;
+
+ status_old = read_sr(nor);
++ if (status_old < 0)
++ return status_old;
+
+ /* SPI NOR always locks to the end */
+ if (ofs + len != mtd->size) {
+@@ -528,11 +530,13 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
+ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
+ {
+ struct mtd_info *mtd = &nor->mtd;
+- uint8_t status_old, status_new;
++ int status_old, status_new;
+ u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
+ u8 shift = ffs(mask) - 1, pow, val;
+
+ status_old = read_sr(nor);
++ if (status_old < 0)
++ return status_old;
+
+ /* Cannot unlock; would unlock larger region than requested */
+ if (stm_is_locked_sr(nor, ofs - mtd->erasesize, mtd->erasesize,
+@@ -1032,6 +1036,8 @@ static int macronix_quad_enable(struct spi_nor *nor)
+ int ret, val;
+
+ val = read_sr(nor);
++ if (val < 0)
++ return val;
+ write_enable(nor);
+
+ write_sr(nor, val | SR_QUAD_EN_MX);
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0016-mtd-spi-nor-remove-micron_quad_enable.patch b/target/linux/socfpga/patches-4.4/0016-mtd-spi-nor-remove-micron_quad_enable.patch
new file mode 100644
index 0000000000..48ceb8ef52
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0016-mtd-spi-nor-remove-micron_quad_enable.patch
@@ -0,0 +1,110 @@
+From 246e2a5cc60e2179bf8849310b7af9eaa5c505f9 Mon Sep 17 00:00:00 2001
+From: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+Date: Fri, 8 Jan 2016 17:02:13 +0100
+Subject: [PATCH 16/33] mtd: spi-nor: remove micron_quad_enable()
+
+This patch remove the micron_quad_enable() function which force the Quad
+SPI mode. However, once this mode is enabled, the Micron memory expect ALL
+commands to use the SPI 4-4-4 protocol. Hence a failure does occur when
+calling spi_nor_wait_till_ready() right after the update of the Enhanced
+Volatile Configuration Register (EVCR) in the micron_quad_enable() as
+the SPI controller driver is not aware about the protocol change.
+
+Since there is almost no performance increase using Fast Read 4-4-4
+commands instead of Fast Read 1-1-4 commands, we rather keep on using the
+Extended SPI mode than enabling the Quad SPI mode.
+
+Let's take the example of the pretty standard use of 8 dummy cycles during
+Fast Read operations on 64KB erase sectors:
+
+Fast Read 1-1-4 requires 8 cycles for the command, then 24 cycles for the
+3byte address followed by 8 dummy clock cycles and finally 65536*2 cycles
+for the read data; so 131112 clock cycles.
+
+On the other hand the Fast Read 4-4-4 would require 2 cycles for the
+command, then 6 cycles for the 3byte address followed by 8 dummy clock
+cycles and finally 65536*2 cycles for the read data. So 131088 clock
+cycles. The theorical bandwidth increase is 0.0%.
+
+Now using Fast Read operations on 512byte pages:
+Fast Read 1-1-4 needs 8+24+8+(512*2) = 1064 clock cycles whereas Fast
+Read 4-4-4 would requires 2+6+8+(512*2) = 1040 clock cycles. Hence the
+theorical bandwidth increase is 2.3%.
+Consecutive reads for non sequential pages is not a relevant use case so
+The Quad SPI mode is not worth it.
+
+mtd_speedtest seems to confirm these figures.
+
+Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+Fixes: 548cd3ab54da ("mtd: spi-nor: Add quad I/O support for Micron SPI NOR")
+---
+ drivers/mtd/spi-nor/spi-nor.c | 46 +------------------------------------------
+ 1 file changed, 1 insertion(+), 45 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index f8f36d4..6e72e96 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1092,45 +1092,6 @@ static int spansion_quad_enable(struct spi_nor *nor)
+ return 0;
+ }
+
+-static int micron_quad_enable(struct spi_nor *nor)
+-{
+- int ret;
+- u8 val;
+-
+- ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1);
+- if (ret < 0) {
+- dev_err(nor->dev, "error %d reading EVCR\n", ret);
+- return ret;
+- }
+-
+- write_enable(nor);
+-
+- /* set EVCR, enable quad I/O */
+- nor->cmd_buf[0] = val & ~EVCR_QUAD_EN_MICRON;
+- ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, nor->cmd_buf, 1);
+- if (ret < 0) {
+- dev_err(nor->dev, "error while writing EVCR register\n");
+- return ret;
+- }
+-
+- ret = spi_nor_wait_till_ready(nor);
+- if (ret)
+- return ret;
+-
+- /* read EVCR and check it */
+- ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1);
+- if (ret < 0) {
+- dev_err(nor->dev, "error %d reading EVCR\n", ret);
+- return ret;
+- }
+- if (val & EVCR_QUAD_EN_MICRON) {
+- dev_err(nor->dev, "Micron EVCR Quad bit not clear\n");
+- return -EINVAL;
+- }
+-
+- return 0;
+-}
+-
+ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+ {
+ int status;
+@@ -1144,12 +1105,7 @@ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+ }
+ return status;
+ case SNOR_MFR_MICRON:
+- status = micron_quad_enable(nor);
+- if (status) {
+- dev_err(nor->dev, "Micron quad-read not enabled\n");
+- return -EINVAL;
+- }
+- return status;
++ return 0;
+ default:
+ status = spansion_quad_enable(nor);
+ if (status) {
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0017-mtd-spi-nor-properly-detect-the-memory-when-it-boots.patch b/target/linux/socfpga/patches-4.4/0017-mtd-spi-nor-properly-detect-the-memory-when-it-boots.patch
new file mode 100644
index 0000000000..63cd47e006
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0017-mtd-spi-nor-properly-detect-the-memory-when-it-boots.patch
@@ -0,0 +1,244 @@
+From 06883bee58d1beedef783f7f5662367736d90924 Mon Sep 17 00:00:00 2001
+From: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+Date: Fri, 8 Jan 2016 17:02:14 +0100
+Subject: [PATCH 17/33] mtd: spi-nor: properly detect the memory when it boots
+ in Quad or Dual mode
+
+The quad (or dual) mode of a spi-nor memory may be enabled at boot time by
+non-volatile bits in some setting register. Also such a mode may have
+already been enabled at early stage by some boot loader.
+
+Hence, we should not guess the spi-nor memory is always configured for the
+regular SPI 1-1-1 protocol.
+
+Micron and Macronix memories, once their Quad (or dual for Micron) mode
+enabled, no longer process the regular JEDEC Read ID (0x9f) command but
+instead reply to a new command: JEDEC Read ID Multiple I/O (0xaf).
+Besides, in Quad mode both memory manufacturers expect ALL commands to
+use the SPI 4-4-4 protocol. For Micron memories, enabling their Dual mode
+implies to use the SPI 2-2-2 protocol for ALL commands.
+
+Winbond memories, once their Quad mode enabled, expect ALL commands to use
+the SPI 4-4-4 protocol. Unlike Micron and Macronix memories, they still
+reply to the regular JEDEC Read ID (0x9f) command.
+
+Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 83 ++++++++++++++++++++++++++++++++++++++++---
+ include/linux/mtd/spi-nor.h | 50 ++++++++++++++++++++++++--
+ 2 files changed, 127 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index 6e72e96..9ad2d40 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -73,6 +73,12 @@ struct flash_info {
+
+ #define JEDEC_MFR(info) ((info)->id[0])
+
++struct read_id_config {
++ enum read_mode mode;
++ enum spi_nor_protocol proto;
++ u8 opcode;
++};
++
+ static const struct flash_info *spi_nor_match_id(const char *name);
+
+ /*
+@@ -871,11 +877,22 @@ static const struct flash_info spi_nor_ids[] = {
+ { },
+ };
+
+-static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
++static const struct flash_info *spi_nor_read_id(struct spi_nor *nor,
++ enum read_mode mode)
+ {
+- int tmp;
++ int i, tmp;
+ u8 id[SPI_NOR_MAX_ID_LEN];
+ const struct flash_info *info;
++ static const struct read_id_config configs[] = {
++ /* Winbond QPI mode */
++ {SPI_NOR_QUAD, SNOR_PROTO_4_4_4, SPINOR_OP_RDID},
++
++ /* Micron Quad mode & Macronix QPI mode */
++ {SPI_NOR_QUAD, SNOR_PROTO_4_4_4, SPINOR_OP_MIO_RDID},
++
++ /* Micron Dual mode */
++ {SPI_NOR_DUAL, SNOR_PROTO_2_2_2, SPINOR_OP_MIO_RDID}
++ };
+
+ tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN);
+ if (tmp < 0) {
+@@ -883,6 +900,58 @@ static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
+ return ERR_PTR(tmp);
+ }
+
++ /*
++ * Check whether the SPI NOR memory has already been configured (at
++ * reset or by some bootloader) to use a protocol other than SPI 1-1-1.
++ */
++ for (i = 0; i < ARRAY_SIZE(configs); ++i) {
++ int len = SPI_NOR_MAX_ID_LEN;
++ bool is_multi = false;
++
++ /*
++ * Check the latest read Manufacturer ID + Device ID (3 bytes):
++ * if they are different from both 0x000000 and 0xffffff, we
++ * assume that we succeeded in reading a valid JEDEC ID so we
++ * don't need to try other SPI protocols.
++ * Indeed when either the protocol or the op code are not valid,
++ * the SPI NOR memory should not reply to the command. Hence the
++ * SPI I/O lines remain in their default state: 1 when connected
++ * to pull-up resistors or 0 with pull-down.
++ */
++ if (!((id[0] == 0xff && id[1] == 0xff && id[2] == 0xff) ||
++ (id[0] == 0x00 && id[1] == 0x00 && id[2] == 0x00)))
++ break;
++
++ /* Only try protocols supported by the user. */
++ if (configs[i].mode != mode)
++ continue;
++
++ /* Set this protocol for all commands. */
++ nor->reg_proto = configs[i].proto;
++ nor->read_proto = configs[i].proto;
++ nor->write_proto = configs[i].proto;
++ nor->erase_proto = configs[i].proto;
++
++ /*
++ * Multiple I/O Read ID only returns the Manufacturer ID
++ * (1 byte) and the Device ID (2 bytes). So we reset the
++ * remaining bytes.
++ */
++ if (configs[i].opcode == SPINOR_OP_MIO_RDID) {
++ is_multi = true;
++ len = 3;
++ memset(id + len, 0, sizeof(id) - len);
++ }
++
++ tmp = nor->read_reg(nor, configs[i].opcode, id, len);
++ if (tmp < 0) {
++ dev_dbg(nor->dev,
++ "error %d reading JEDEC ID%s\n",
++ tmp, (is_multi ? " Multi I/O" : ""));
++ return ERR_PTR(tmp);
++ }
++ }
++
+ for (tmp = 0; tmp < ARRAY_SIZE(spi_nor_ids) - 1; tmp++) {
+ info = &spi_nor_ids[tmp];
+ if (info->id_len) {
+@@ -1140,11 +1209,17 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+ if (ret)
+ return ret;
+
++ /* Reset SPI protocol for all commands */
++ nor->erase_proto = SNOR_PROTO_1_1_1;
++ nor->read_proto = SNOR_PROTO_1_1_1;
++ nor->write_proto = SNOR_PROTO_1_1_1;
++ nor->reg_proto = SNOR_PROTO_1_1_1;
++
+ if (name)
+ info = spi_nor_match_id(name);
+ /* Try to auto-detect if chip name wasn't specified or not found */
+ if (!info)
+- info = spi_nor_read_id(nor);
++ info = spi_nor_read_id(nor, mode);
+ if (IS_ERR_OR_NULL(info))
+ return -ENOENT;
+
+@@ -1155,7 +1230,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+ if (name && info->id_len) {
+ const struct flash_info *jinfo;
+
+- jinfo = spi_nor_read_id(nor);
++ jinfo = spi_nor_read_id(nor, mode);
+ if (IS_ERR(jinfo)) {
+ return PTR_ERR(jinfo);
+ } else if (jinfo != info) {
+diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
+index 62356d5..53932c8 100644
+--- a/include/linux/mtd/spi-nor.h
++++ b/include/linux/mtd/spi-nor.h
+@@ -75,8 +75,9 @@
+ #define SPINOR_OP_BRWR 0x17 /* Bank register write */
+
+ /* Used for Micron flashes only. */
+-#define SPINOR_OP_RD_EVCR 0x65 /* Read EVCR register */
+-#define SPINOR_OP_WD_EVCR 0x61 /* Write EVCR register */
++#define SPINOR_OP_MIO_RDID 0xaf /* Multiple I/O Read JEDEC ID */
++#define SPINOR_OP_RD_EVCR 0x65 /* Read EVCR register */
++#define SPINOR_OP_WD_EVCR 0x61 /* Write EVCR register */
+
+ /* Status Register bits. */
+ #define SR_WIP BIT(0) /* Write in progress */
+@@ -105,6 +106,43 @@ enum read_mode {
+ SPI_NOR_QUAD,
+ };
+
++
++#define SNOR_PROTO_CMD_OFF 8
++#define SNOR_PROTO_CMD_MASK GENMASK(11, 8)
++#define SNOR_PROTO_CMD_TO_PROTO(cmd) \
++ (((cmd) << SNOR_PROTO_CMD_OFF) & SNOR_PROTO_CMD_MASK)
++#define SNOR_PROTO_CMD_FROM_PROTO(proto) \
++ ((((u32)(proto)) & SNOR_PROTO_CMD_MASK) >> SNOR_PROTO_CMD_OFF)
++
++#define SNOR_PROTO_ADDR_OFF 4
++#define SNOR_PROTO_ADDR_MASK GENMASK(7, 4)
++#define SNOR_PROTO_ADDR_TO_PROTO(addr) \
++ (((addr) << SNOR_PROTO_ADDR_OFF) & SNOR_PROTO_ADDR_MASK)
++#define SNOR_PROTO_ADDR_FROM_PROTO(proto) \
++ ((((u32)(proto)) & SNOR_PROTO_ADDR_MASK) >> SNOR_PROTO_ADDR_OFF)
++
++#define SNOR_PROTO_DATA_OFF 0
++#define SNOR_PROTO_DATA_MASK GENMASK(3, 0)
++#define SNOR_PROTO_DATA_TO_PROTO(data) \
++ (((data) << SNOR_PROTO_DATA_OFF) & SNOR_PROTO_DATA_MASK)
++#define SNOR_PROTO_DATA_FROM_PROTO(proto) \
++ ((((u32)(proto)) & SNOR_PROTO_DATA_MASK) >> SNOR_PROTO_DATA_OFF)
++
++#define SNOR_PROTO(cmd, addr, data) \
++ (SNOR_PROTO_CMD_TO_PROTO(cmd) | \
++ SNOR_PROTO_ADDR_TO_PROTO(addr) | \
++ SNOR_PROTO_DATA_TO_PROTO(data))
++
++enum spi_nor_protocol {
++ SNOR_PROTO_1_1_1 = SNOR_PROTO(1, 1, 1), /* SPI */
++ SNOR_PROTO_1_1_2 = SNOR_PROTO(1, 1, 2), /* Dual Output */
++ SNOR_PROTO_1_1_4 = SNOR_PROTO(1, 1, 4), /* Quad Output */
++ SNOR_PROTO_1_2_2 = SNOR_PROTO(1, 2, 2), /* Dual IO */
++ SNOR_PROTO_1_4_4 = SNOR_PROTO(1, 4, 4), /* Quad IO */
++ SNOR_PROTO_2_2_2 = SNOR_PROTO(2, 2, 2), /* Dual Command */
++ SNOR_PROTO_4_4_4 = SNOR_PROTO(4, 4, 4), /* Quad Command */
++};
++
+ #define SPI_NOR_MAX_CMD_SIZE 8
+ enum spi_nor_ops {
+ SPI_NOR_OPS_READ = 0,
+@@ -132,6 +170,10 @@ enum spi_nor_option_flags {
+ * @flash_read: the mode of the read
+ * @sst_write_second: used by the SST write operation
+ * @flags: flag options for the current SPI-NOR (SNOR_F_*)
++ * @erase_proto: the SPI protocol used by erase operations
++ * @read_proto: the SPI protocol used by read operations
++ * @write_proto: the SPI protocol used by write operations
++ * @reg_proto the SPI protocol used by read_reg/write_reg operations
+ * @cmd_buf: used by the write_reg
+ * @prepare: [OPTIONAL] do some preparations for the
+ * read/write/erase/lock/unlock operations
+@@ -160,6 +202,10 @@ struct spi_nor {
+ u8 read_opcode;
+ u8 read_dummy;
+ u8 program_opcode;
++ enum spi_nor_protocol erase_proto;
++ enum spi_nor_protocol read_proto;
++ enum spi_nor_protocol write_proto;
++ enum spi_nor_protocol reg_proto;
+ enum read_mode flash_read;
+ bool sst_write_second;
+ u32 flags;
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0018-mtd-spi-nor-select-op-codes-and-SPI-NOR-protocols-by.patch b/target/linux/socfpga/patches-4.4/0018-mtd-spi-nor-select-op-codes-and-SPI-NOR-protocols-by.patch
new file mode 100644
index 0000000000..5adef1eb80
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0018-mtd-spi-nor-select-op-codes-and-SPI-NOR-protocols-by.patch
@@ -0,0 +1,203 @@
+From a27dc343ea2de9283ca057fbcafa12a279a19b7b Mon Sep 17 00:00:00 2001
+From: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+Date: Fri, 8 Jan 2016 17:02:15 +0100
+Subject: [PATCH 18/33] mtd: spi-nor: select op codes and SPI NOR protocols by
+ manufacturer
+
+This is a transitional patch to prepare the split by Manufacturer of the
+support of Single/Dual/Quad SPI modes.
+
+Indeed every QSPI NOR manufacturer (Spansion, Micron, Macronix, Winbond)
+supports Dual or Quad SPI modes on its way. Especially the Fast Read op
+code and the SPI NOR protocols to use are not quite the same depending on
+the manufacturer.
+
+For instance Quad commands can use either the SPI 1-1-4, 1-4-4 or 4-4-4
+protocol.
+
+This is why this patch will be completed by fixes for each manufacturer.
+
+Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 110 ++++++++++++++++++++++++++++++++----------
+ include/linux/mtd/spi-nor.h | 12 +++--
+ 2 files changed, 92 insertions(+), 30 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index 9ad2d40..889af12 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1172,17 +1172,61 @@ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+ dev_err(nor->dev, "Macronix quad-read not enabled\n");
+ return -EINVAL;
+ }
+- return status;
++ /* Check whether Macronix QPI mode is enabled. */
++ if (nor->read_proto != SNOR_PROTO_4_4_4)
++ nor->read_proto = SNOR_PROTO_1_1_4;
++ break;
++
+ case SNOR_MFR_MICRON:
+- return 0;
+- default:
++ /* Check whether Micron Quad mode is enabled. */
++ if (nor->read_proto != SNOR_PROTO_4_4_4)
++ nor->read_proto = SNOR_PROTO_1_1_4;
++ break;
++
++ case SNOR_MFR_SPANSION:
+ status = spansion_quad_enable(nor);
+ if (status) {
+ dev_err(nor->dev, "Spansion quad-read not enabled\n");
+ return -EINVAL;
+ }
+- return status;
++ nor->read_proto = SNOR_PROTO_1_1_4;
++ break;
++
++ default:
++ return -EINVAL;
+ }
++
++ nor->read_opcode = SPINOR_OP_READ_1_1_4;
++ return 0;
++}
++
++static int set_dual_mode(struct spi_nor *nor, const struct flash_info *info)
++{
++ switch (JEDEC_MFR(info)) {
++ case SNOR_MFR_MICRON:
++ /* Check whether Micron Dual mode is enabled. */
++ if (nor->read_proto != SNOR_PROTO_2_2_2)
++ nor->read_proto = SNOR_PROTO_1_1_2;
++ break;
++
++ default:
++ nor->read_proto = SNOR_PROTO_1_1_2;
++ break;
++ }
++
++ nor->read_opcode = SPINOR_OP_READ_1_1_2;
++ return 0;
++}
++
++static int set_single_mode(struct spi_nor *nor, const struct flash_info *info)
++{
++ switch (JEDEC_MFR(info)) {
++ default:
++ nor->read_proto = SNOR_PROTO_1_1_1;
++ break;
++ }
++
++ return 0;
+ }
+
+ static int spi_nor_check(struct spi_nor *nor)
+@@ -1330,7 +1374,30 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+ if (info->flags & SPI_NOR_NO_FR)
+ nor->flash_read = SPI_NOR_NORMAL;
+
+- /* Quad/Dual-read mode takes precedence over fast/normal */
++ /* Default commands */
++ if (nor->flash_read == SPI_NOR_NORMAL)
++ nor->read_opcode = SPINOR_OP_READ;
++ else
++ nor->read_opcode = SPINOR_OP_READ_FAST;
++
++ nor->program_opcode = SPINOR_OP_PP;
++
++ /*
++ * Quad/Dual-read mode takes precedence over fast/normal.
++ *
++ * Manufacturer specific modes are discovered when reading the JEDEC ID
++ * and are reported by the nor->read_proto value:
++ * - SNOR_PROTO_4_4_4 is either:
++ * + Micron Quad mode enabled
++ * + Macronix/Winbond QPI mode enabled
++ * - SNOR_PROTO_2_2_2 is either:
++ * + Micron Dual mode enabled
++ *
++ * The opcodes and the protocols are updated depending on the
++ * manufacturer.
++ * The read opcode and protocol should be updated by the relevant
++ * function when entering Quad or Dual mode.
++ */
+ if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) {
+ ret = set_quad_mode(nor, info);
+ if (ret) {
+@@ -1339,30 +1406,21 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+ }
+ nor->flash_read = SPI_NOR_QUAD;
+ } else if (mode == SPI_NOR_DUAL && info->flags & SPI_NOR_DUAL_READ) {
++ ret = set_dual_mode(nor, info);
++ if (ret) {
++ dev_err(dev, "dual mode not supported\n");
++ return ret;
++ }
+ nor->flash_read = SPI_NOR_DUAL;
++ } else if (info->flags & (SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)) {
++ /* We may need to leave a Quad or Dual mode */
++ ret = set_single_mode(nor, info);
++ if (ret) {
++ dev_err(dev, "failed to switch back to single mode\n");
++ return ret;
++ }
+ }
+
+- /* Default commands */
+- switch (nor->flash_read) {
+- case SPI_NOR_QUAD:
+- nor->read_opcode = SPINOR_OP_READ_1_1_4;
+- break;
+- case SPI_NOR_DUAL:
+- nor->read_opcode = SPINOR_OP_READ_1_1_2;
+- break;
+- case SPI_NOR_FAST:
+- nor->read_opcode = SPINOR_OP_READ_FAST;
+- break;
+- case SPI_NOR_NORMAL:
+- nor->read_opcode = SPINOR_OP_READ;
+- break;
+- default:
+- dev_err(dev, "No Read opcode defined\n");
+- return -EINVAL;
+- }
+-
+- nor->program_opcode = SPINOR_OP_PP;
+-
+ if (info->addr_width)
+ nor->addr_width = info->addr_width;
+ else if (mtd->size > 0x1000000) {
+diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
+index 53932c8..89e3228 100644
+--- a/include/linux/mtd/spi-nor.h
++++ b/include/linux/mtd/spi-nor.h
+@@ -42,8 +42,10 @@
+ #define SPINOR_OP_WRSR 0x01 /* Write status register 1 byte */
+ #define SPINOR_OP_READ 0x03 /* Read data bytes (low frequency) */
+ #define SPINOR_OP_READ_FAST 0x0b /* Read data bytes (high frequency) */
+-#define SPINOR_OP_READ_1_1_2 0x3b /* Read data bytes (Dual SPI) */
+-#define SPINOR_OP_READ_1_1_4 0x6b /* Read data bytes (Quad SPI) */
++#define SPINOR_OP_READ_1_1_2 0x3b /* Read data bytes (Dual Output SPI) */
++#define SPINOR_OP_READ_1_2_2 0xbb /* Read data bytes (Dual I/O SPI) */
++#define SPINOR_OP_READ_1_1_4 0x6b /* Read data bytes (Quad Output SPI) */
++#define SPINOR_OP_READ_1_4_4 0xeb /* Read data bytes (Quad I/O SPI) */
+ #define SPINOR_OP_PP 0x02 /* Page program (up to 256 bytes) */
+ #define SPINOR_OP_BE_4K 0x20 /* Erase 4KiB block */
+ #define SPINOR_OP_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */
+@@ -57,8 +59,10 @@
+ /* 4-byte address opcodes - used on Spansion and some Macronix flashes. */
+ #define SPINOR_OP_READ4 0x13 /* Read data bytes (low frequency) */
+ #define SPINOR_OP_READ4_FAST 0x0c /* Read data bytes (high frequency) */
+-#define SPINOR_OP_READ4_1_1_2 0x3c /* Read data bytes (Dual SPI) */
+-#define SPINOR_OP_READ4_1_1_4 0x6c /* Read data bytes (Quad SPI) */
++#define SPINOR_OP_READ4_1_1_2 0x3c /* Read data bytes (Dual Output SPI) */
++#define SPINOR_OP_READ4_1_2_2 0xbc /* Read data bytes (Dual I/O SPI) */
++#define SPINOR_OP_READ4_1_1_4 0x6c /* Read data bytes (Quad Output SPI) */
++#define SPINOR_OP_READ4_1_4_4 0xec /* Read data bytes (Quad I/O SPI) */
+ #define SPINOR_OP_PP_4B 0x12 /* Page program (up to 256 bytes) */
+ #define SPINOR_OP_SE_4B 0xdc /* Sector erase (usually 64KiB) */
+
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0019-mtd-spi-nor-fix-support-of-Macronix-memories.patch b/target/linux/socfpga/patches-4.4/0019-mtd-spi-nor-fix-support-of-Macronix-memories.patch
new file mode 100644
index 0000000000..087b6715d0
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0019-mtd-spi-nor-fix-support-of-Macronix-memories.patch
@@ -0,0 +1,139 @@
+From 4e094634d1995e279f8bc5eb92463295cb894c76 Mon Sep 17 00:00:00 2001
+From: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+Date: Fri, 8 Jan 2016 17:02:16 +0100
+Subject: [PATCH 19/33] mtd: spi-nor: fix support of Macronix memories
+
+This patch fixes the support of Macronix memories. Especially we avoid
+updating the Status Register when not needed as the Quad Enable (QE) bit
+is a non-volatile bit.
+
+Also we add comments to explain why we use some Fast Read op codes rather
+than others.
+
+Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 81 ++++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 72 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index 889af12..1b1f5a6 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1107,6 +1107,11 @@ static int macronix_quad_enable(struct spi_nor *nor)
+ val = read_sr(nor);
+ if (val < 0)
+ return val;
++
++ if (likely(val & SR_QUAD_EN_MX))
++ return 0;
++ dev_warn(nor->dev, "Macronix Quad mode disabled, enable it\n");
++
+ write_enable(nor);
+
+ write_sr(nor, val | SR_QUAD_EN_MX);
+@@ -1161,21 +1166,73 @@ static int spansion_quad_enable(struct spi_nor *nor)
+ return 0;
+ }
+
++static int macronix_set_quad_mode(struct spi_nor *nor)
++{
++ int status;
++
++ /* Check whether the QPI mode is enabled. */
++ if (nor->read_proto == SNOR_PROTO_4_4_4) {
++ /*
++ * Since the QPI mode is enabled, the Quad Enabled (QE)
++ * non-volatile bit is already set.
++ * However in QPI mode, only the Fast Read 1-4-4 (0xeb)
++ * op code is supported.
++ * WARNING: we should take care about the performance
++ * enhance toggling bits P0-P7 written during the
++ * dummy/mode cycles to avoid entering the continuous
++ * read (performance enhance) mode by mistake!
++ */
++ nor->read_opcode = SPINOR_OP_READ_1_4_4;
++ return 0;
++ }
++
++ /*
++ * The QPI mode is disabled but we still need to set the QE bit:
++ * this disables the reset and write protect features and
++ * frees the associated pins so they can be used as the 3rd
++ * and 4th I/O lines required by Quad SPI commands.
++ * Also we'd rather use the Fast Read 1-1-4 (0x6b) op code than
++ * the Fast Read 1-4-4 (0xeb) op code so we don't care about
++ * entering the continuous read mode by mistake if some
++ * performance enhance toggling bits P0-P7 were written during
++ * dummy/mode cycles.
++ */
++ status = macronix_quad_enable(nor);
++ if (status) {
++ dev_err(nor->dev, "Macronix quad-read not enabled\n");
++ return status;
++ }
++ nor->read_proto = SNOR_PROTO_1_1_4;
++ nor->read_opcode = SPINOR_OP_READ_1_1_4;
++ return 0;
++}
++
++/*
++ * For both Macronix Dual and Single modes, we don't care about the value of
++ * the Quad Enabled (QE) bit since the memory still replies to Dual or Single
++ * SPI commands.
++ */
++
++static int macronix_set_dual_mode(struct spi_nor *nor)
++{
++ nor->read_proto = SNOR_PROTO_1_1_2;
++ nor->read_opcode = SPINOR_OP_READ_1_1_2;
++ return 0;
++}
++
++static int macronix_set_single_mode(struct spi_nor *nor)
++{
++ nor->read_proto = SNOR_PROTO_1_1_1;
++ return 0;
++}
++
+ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+ {
+ int status;
+
+ switch (JEDEC_MFR(info)) {
+ case SNOR_MFR_MACRONIX:
+- status = macronix_quad_enable(nor);
+- if (status) {
+- dev_err(nor->dev, "Macronix quad-read not enabled\n");
+- return -EINVAL;
+- }
+- /* Check whether Macronix QPI mode is enabled. */
+- if (nor->read_proto != SNOR_PROTO_4_4_4)
+- nor->read_proto = SNOR_PROTO_1_1_4;
+- break;
++ return macronix_set_quad_mode(nor);
+
+ case SNOR_MFR_MICRON:
+ /* Check whether Micron Quad mode is enabled. */
+@@ -1203,6 +1260,9 @@ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+ static int set_dual_mode(struct spi_nor *nor, const struct flash_info *info)
+ {
+ switch (JEDEC_MFR(info)) {
++ case SNOR_MFR_MACRONIX:
++ return macronix_set_dual_mode(nor);
++
+ case SNOR_MFR_MICRON:
+ /* Check whether Micron Dual mode is enabled. */
+ if (nor->read_proto != SNOR_PROTO_2_2_2)
+@@ -1221,6 +1281,9 @@ static int set_dual_mode(struct spi_nor *nor, const struct flash_info *info)
+ static int set_single_mode(struct spi_nor *nor, const struct flash_info *info)
+ {
+ switch (JEDEC_MFR(info)) {
++ case SNOR_MFR_MACRONIX:
++ return macronix_set_single_mode(nor);
++
+ default:
+ nor->read_proto = SNOR_PROTO_1_1_1;
+ break;
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0020-mtd-spi-nor-fix-support-of-Winbond-memories.patch b/target/linux/socfpga/patches-4.4/0020-mtd-spi-nor-fix-support-of-Winbond-memories.patch
new file mode 100644
index 0000000000..e41fd3fff7
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0020-mtd-spi-nor-fix-support-of-Winbond-memories.patch
@@ -0,0 +1,179 @@
+From 96b232d03a0c4462eacf879ed80b0cfd235e65c4 Mon Sep 17 00:00:00 2001
+From: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+Date: Fri, 8 Jan 2016 17:02:17 +0100
+Subject: [PATCH 20/33] mtd: spi-nor: fix support of Winbond memories
+
+This patch fixes the support of Winbond memories. Indeed, before
+performing any Quad SPI command, the Quad Enable (QE) non-volatile bit
+MUST be set in the Status Register 2.
+
+According to the w25q16fw datasheet from Winbond:
+"When QE=1, the /WP pin becomes IO2 and /HOLD pin becomes IO3."
+
+Quad SPI instructions requires the bidirectional IO2 and IO3 pins.
+
+Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 100 ++++++++++++++++++++++++++++++++++++++++++
+ include/linux/mtd/spi-nor.h | 6 +++
+ 2 files changed, 106 insertions(+)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index 1b1f5a6..aa7d26d 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1166,6 +1166,40 @@ static int spansion_quad_enable(struct spi_nor *nor)
+ return 0;
+ }
+
++static int winbond_quad_enable(struct spi_nor *nor)
++{
++ int ret;
++ u8 sr2;
++
++ ret = nor->read_reg(nor, SPINOR_OP_RDSR2_WINB, &sr2, 1);
++ if (ret < 0)
++ return ret;
++
++ if (likely(sr2 & SR2_QUAD_EN_WINB))
++ return 0;
++ dev_warn(nor->dev, "Winbond Quad mode disabled, enable it\n");
++
++ write_enable(nor);
++
++ sr2 |= SR2_QUAD_EN_WINB;
++ ret = nor->write_reg(nor, SPINOR_OP_WRSR2_WINB, &sr2, 1);
++ if (ret < 0)
++ return ret;
++
++ if (spi_nor_wait_till_ready(nor))
++ return -EIO;
++
++ ret = nor->read_reg(nor, SPINOR_OP_RDSR2_WINB, &sr2, 1);
++ if (ret < 0)
++ return ret;
++ if (!(sr2 & SR2_QUAD_EN_WINB)) {
++ dev_err(nor->dev, "Winbond Quad bit not set\n");
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
+ static int macronix_set_quad_mode(struct spi_nor *nor)
+ {
+ int status;
+@@ -1226,6 +1260,63 @@ static int macronix_set_single_mode(struct spi_nor *nor)
+ return 0;
+ }
+
++static int winbond_set_quad_mode(struct spi_nor *nor)
++{
++ int status;
++
++ /* Check whether the QPI mode is enabled. */
++ if (nor->read_proto == SNOR_PROTO_4_4_4) {
++ /* Since the QPI mode is enabled, the Quad Enabled (QE)
++ * non-volatile bit is already set.
++ * If the Fast Read 1-4-4 (0xeb) were used, we should
++ * take care about the value M7-M0 written during
++ * dummy/mode cycles to avoid entering the continuous
++ * read mode by mistake.
++ * Also the Fast Read 1-1-4 (0x6b) op code is not
++ * supported in QPI mode.
++ * Hence the Fast Read 1-1-1 (0x0b) op code is chosen.
++ */
++ nor->read_opcode = SPINOR_OP_READ_FAST;
++ return 0;
++ }
++
++ /*
++ * The QPI mode is disabled but we still need to set the QE bit:
++ * when QE=1, the /WP pin becomes IO2 and /HOLD pin becomes IO3.
++ * If the Fast Read 1-4-4 (0xeb) were used, we should take care
++ * about the value M7-M0 written during dummy/mode cycles to
++ * avoid entering the continuous read mode by mistake.
++ * Hence the Fast Read 1-1-4 (0x6b) op code is preferred.
++ */
++ status = winbond_quad_enable(nor);
++ if (status) {
++ dev_err(nor->dev, "Winbond quad-read nor enabled\n");
++ return status;
++ }
++ nor->read_proto = SNOR_PROTO_1_1_4;
++ nor->read_opcode = SPINOR_OP_READ_1_1_4;
++ return 0;
++}
++
++/*
++ * For both Winbond Dual and Single modes, we don't care about the value of
++ * the Quad Enabled (QE) bit since the memory still replies to Dual or Single
++ * SPI commands.
++ */
++
++static int winbond_set_dual_mode(struct spi_nor *nor)
++{
++ nor->read_proto = SNOR_PROTO_1_1_2;
++ nor->read_opcode = SPINOR_OP_READ_1_1_2;
++ return 0;
++}
++
++static int winbond_set_single_mode(struct spi_nor *nor)
++{
++ nor->read_proto = SNOR_PROTO_1_1_1;
++ return 0;
++}
++
+ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+ {
+ int status;
+@@ -1234,6 +1325,9 @@ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+ case SNOR_MFR_MACRONIX:
+ return macronix_set_quad_mode(nor);
+
++ case SNOR_MFR_WINBOND:
++ return winbond_set_quad_mode(nor);
++
+ case SNOR_MFR_MICRON:
+ /* Check whether Micron Quad mode is enabled. */
+ if (nor->read_proto != SNOR_PROTO_4_4_4)
+@@ -1263,6 +1357,9 @@ static int set_dual_mode(struct spi_nor *nor, const struct flash_info *info)
+ case SNOR_MFR_MACRONIX:
+ return macronix_set_dual_mode(nor);
+
++ case SNOR_MFR_WINBOND:
++ return winbond_set_dual_mode(nor);
++
+ case SNOR_MFR_MICRON:
+ /* Check whether Micron Dual mode is enabled. */
+ if (nor->read_proto != SNOR_PROTO_2_2_2)
+@@ -1284,6 +1381,9 @@ static int set_single_mode(struct spi_nor *nor, const struct flash_info *info)
+ case SNOR_MFR_MACRONIX:
+ return macronix_set_single_mode(nor);
+
++ case SNOR_MFR_WINBOND:
++ return winbond_set_single_mode(nor);
++
+ default:
+ nor->read_proto = SNOR_PROTO_1_1_1;
+ break;
+diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
+index 89e3228..46343f5 100644
+--- a/include/linux/mtd/spi-nor.h
++++ b/include/linux/mtd/spi-nor.h
+@@ -75,6 +75,12 @@
+ #define SPINOR_OP_EN4B 0xb7 /* Enter 4-byte mode */
+ #define SPINOR_OP_EX4B 0xe9 /* Exit 4-byte mode */
+
++/* Used for Winbond flashes only. */
++#define SPINOR_OP_RDSR2_WINB 0x35 /* Read status register 2 */
++#define SPINOR_OP_WRSR2_WINB 0x31 /* Write status register 2 */
++
++#define SR2_QUAD_EN_WINB BIT(1) /* Quad Enable bit */
++
+ /* Used for Spansion flashes only. */
+ #define SPINOR_OP_BRWR 0x17 /* Bank register write */
+
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0021-mtd-spi-nor-fix-support-of-Micron-memories.patch b/target/linux/socfpga/patches-4.4/0021-mtd-spi-nor-fix-support-of-Micron-memories.patch
new file mode 100644
index 0000000000..83d79ab90d
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0021-mtd-spi-nor-fix-support-of-Micron-memories.patch
@@ -0,0 +1,224 @@
+From 0cd0df6b3583920ab9231035e533560b58e71a50 Mon Sep 17 00:00:00 2001
+From: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+Date: Fri, 8 Jan 2016 17:02:18 +0100
+Subject: [PATCH 21/33] mtd: spi-nor: fix support of Micron memories
+
+This patch adds missing mode transitions. Indeed depending on both the
+current memory mode and the new protocol wanted by the user, we may need
+to perform a switch back to the Extended SPI mode.
+
+However when the current mode is the Quad mode and the user has asked for
+a Quad SPI protocol, we'd rather stay in Quad mode and use the Fast Read
+4-4-4 command than switch to the Extended SPI mode and use the Fast Read
+1-1-4 command.
+
+Also we'd rather stay in Dual mode than swith to the Extended SPI mode
+whenever the user has asked for Dual SPI protocol.
+
+Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 154 +++++++++++++++++++++++++++++++++++++++---
+ include/linux/mtd/spi-nor.h | 1 +
+ 2 files changed, 147 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index aa7d26d..ae2cbac 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1317,6 +1317,147 @@ static int winbond_set_single_mode(struct spi_nor *nor)
+ return 0;
+ }
+
++static int micron_set_protocol(struct spi_nor *nor, u8 mask, u8 val,
++ enum spi_nor_protocol proto)
++{
++ u8 evcr;
++ int ret;
++
++ /* Read the Enhanced Volatile Configuration Register (EVCR). */
++ ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &evcr, 1);
++ if (ret < 0) {
++ dev_err(nor->dev, "error while reading EVCR register\n");
++ return ret;
++ }
++
++ /* Check whether we need to update the protocol bits. */
++ if ((evcr & mask) == val)
++ return 0;
++
++ /* Set EVCR protocol bits. */
++ write_enable(nor);
++ evcr = (evcr & ~mask) | val;
++ ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, &evcr, 1);
++ if (ret < 0) {
++ dev_err(nor->dev, "error while writing EVCR register\n");
++ return ret;
++ }
++
++ /* Switch reg protocol now before accessing any other registers. */
++ nor->reg_proto = proto;
++
++ ret = spi_nor_wait_till_ready(nor);
++ if (ret)
++ return ret;
++
++ /* Read EVCR and check it. */
++ ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &evcr, 1);
++ if (ret < 0 || (evcr & mask) != val) {
++ dev_err(nor->dev, "Micron EVCR protocol bits not updated\n");
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static int micron_set_extended_spi_protocol(struct spi_nor *nor)
++{
++ int ret;
++
++ /* Set Quad/Dual bits to 11 to select the Extended SPI mode */
++ ret = micron_set_protocol(nor,
++ EVCR_QUAD_EN_MICRON | EVCR_DUAL_EN_MICRON,
++ EVCR_QUAD_EN_MICRON | EVCR_DUAL_EN_MICRON,
++ SNOR_PROTO_1_1_1);
++ if (ret) {
++ dev_err(nor->dev, "Failed to set Micron Extended SPI mode\n");
++ return ret;
++ }
++
++ nor->write_proto = SNOR_PROTO_1_1_1;
++ nor->erase_proto = SNOR_PROTO_1_1_1;
++ return 0;
++}
++
++static int micron_set_quad_mode(struct spi_nor *nor)
++{
++ /* Check whether the Dual SPI mode is enabled. */
++ if (unlikely(nor->read_proto == SNOR_PROTO_2_2_2)) {
++ int ret;
++
++ /*
++ * Exit Micron Dual mode and switch to the Extended SPI mode:
++ * we can change the mode safely as we write into a volatile
++ * register.
++ * Also the Quad mode is not worth it for MTD usages: it
++ * should only be relevant for eXecution In Place (XIP) usages,
++ * which are out of the scope of the spi-nor framework.
++ */
++ ret = micron_set_extended_spi_protocol(nor);
++ if (ret)
++ return ret;
++ }
++
++ /*
++ * Whatever the Quad mode is enabled or not, the
++ * Fast Read Quad Output 1-1-4 (0x6b) op code is supported.
++ */
++ if (nor->read_proto != SNOR_PROTO_4_4_4)
++ nor->read_proto = SNOR_PROTO_1_1_4;
++ nor->read_opcode = SPINOR_OP_READ_1_1_4;
++ return 0;
++}
++
++static int micron_set_dual_mode(struct spi_nor *nor)
++{
++ /* Check whether Quad mode is enabled. */
++ if (unlikely(nor->read_proto == SNOR_PROTO_4_4_4)) {
++ int ret;
++
++ /*
++ * Exit Micron Quad mode and switch to the Extended SPI mode:
++ * we can change the mode safely as we write into a volatile
++ * register.
++ * Also the Dual mode is not worth it for MTD usages: it
++ * should only be relevant for eXecution In Place (XIP) usages,
++ * which are out of the scope of the spi-nor framework.
++ */
++ ret = micron_set_extended_spi_protocol(nor);
++ if (ret)
++ return ret;
++ }
++
++ /*
++ * Whatever the Dual mode is enabled or not, the
++ * Fast Read Dual Output 1-1-2 (0x3b) op code is supported.
++ */
++ if (nor->read_proto != SNOR_PROTO_2_2_2)
++ nor->read_proto = SNOR_PROTO_1_1_2;
++ nor->read_opcode = SPINOR_OP_READ_1_1_2;
++ return 0;
++}
++
++static int micron_set_single_mode(struct spi_nor *nor)
++{
++ /* Check whether either the Dual or Quad mode is enabled. */
++ if (unlikely(nor->read_proto != SNOR_PROTO_1_1_1)) {
++ int ret;
++
++ /*
++ * Exit Micron Dual or Quad mode and switch to the Extended SPI
++ * mode: we can change the mode safely as we write into a
++ * volatile register.
++ */
++ ret = micron_set_extended_spi_protocol(nor);
++ if (ret)
++ return ret;
++
++ nor->read_proto = SNOR_PROTO_1_1_1;
++ }
++
++ return 0;
++}
++
+ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+ {
+ int status;
+@@ -1329,10 +1470,7 @@ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+ return winbond_set_quad_mode(nor);
+
+ case SNOR_MFR_MICRON:
+- /* Check whether Micron Quad mode is enabled. */
+- if (nor->read_proto != SNOR_PROTO_4_4_4)
+- nor->read_proto = SNOR_PROTO_1_1_4;
+- break;
++ return micron_set_quad_mode(nor);
+
+ case SNOR_MFR_SPANSION:
+ status = spansion_quad_enable(nor);
+@@ -1361,10 +1499,7 @@ static int set_dual_mode(struct spi_nor *nor, const struct flash_info *info)
+ return winbond_set_dual_mode(nor);
+
+ case SNOR_MFR_MICRON:
+- /* Check whether Micron Dual mode is enabled. */
+- if (nor->read_proto != SNOR_PROTO_2_2_2)
+- nor->read_proto = SNOR_PROTO_1_1_2;
+- break;
++ return micron_set_dual_mode(nor);
+
+ default:
+ nor->read_proto = SNOR_PROTO_1_1_2;
+@@ -1384,6 +1519,9 @@ static int set_single_mode(struct spi_nor *nor, const struct flash_info *info)
+ case SNOR_MFR_WINBOND:
+ return winbond_set_single_mode(nor);
+
++ case SNOR_MFR_MICRON:
++ return micron_set_single_mode(nor);
++
+ default:
+ nor->read_proto = SNOR_PROTO_1_1_1;
+ break;
+diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
+index 46343f5..d0a6f34 100644
+--- a/include/linux/mtd/spi-nor.h
++++ b/include/linux/mtd/spi-nor.h
+@@ -102,6 +102,7 @@
+
+ /* Enhanced Volatile Configuration Register bits */
+ #define EVCR_QUAD_EN_MICRON BIT(7) /* Micron Quad I/O */
++#define EVCR_DUAL_EN_MICRON BIT(6) /* Micron Dual I/O */
+
+ /* Flag Status Register bits */
+ #define FSR_READY BIT(7)
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0022-mtd-spi-nor-fix-support-of-Spansion-memories.patch b/target/linux/socfpga/patches-4.4/0022-mtd-spi-nor-fix-support-of-Spansion-memories.patch
new file mode 100644
index 0000000000..a7a8f4bbc5
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0022-mtd-spi-nor-fix-support-of-Spansion-memories.patch
@@ -0,0 +1,116 @@
+From 4774693a681539f1e890164acc2d99fede2aa35e Mon Sep 17 00:00:00 2001
+From: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+Date: Fri, 8 Jan 2016 17:02:19 +0100
+Subject: [PATCH 22/33] mtd: spi-nor: fix support of Spansion memories
+
+This patch is only a transitional one. It concludes the series of patches
+to select op codes and protocols by manufacturer.
+
+Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 53 ++++++++++++++++++++++++++++++-------------
+ 1 file changed, 37 insertions(+), 16 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index ae2cbac..8a042ab 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1458,10 +1458,35 @@ static int micron_set_single_mode(struct spi_nor *nor)
+ return 0;
+ }
+
+-static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
++static int spansion_set_quad_mode(struct spi_nor *nor)
+ {
+ int status;
+
++ status = spansion_quad_enable(nor);
++ if (status) {
++ dev_err(nor->dev, "Spansion quad-read not enabled\n");
++ return -EINVAL;
++ }
++ nor->read_proto = SNOR_PROTO_1_1_4;
++ nor->read_opcode = SPINOR_OP_READ_1_1_4;
++ return 0;
++}
++
++static int spansion_set_dual_mode(struct spi_nor *nor)
++{
++ nor->read_proto = SNOR_PROTO_1_1_2;
++ nor->read_opcode = SPINOR_OP_READ_1_1_2;
++ return 0;
++}
++
++static int spansion_set_single_mode(struct spi_nor *nor)
++{
++ nor->read_proto = SNOR_PROTO_1_1_1;
++ return 0;
++}
++
++static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
++{
+ switch (JEDEC_MFR(info)) {
+ case SNOR_MFR_MACRONIX:
+ return macronix_set_quad_mode(nor);
+@@ -1473,20 +1498,13 @@ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+ return micron_set_quad_mode(nor);
+
+ case SNOR_MFR_SPANSION:
+- status = spansion_quad_enable(nor);
+- if (status) {
+- dev_err(nor->dev, "Spansion quad-read not enabled\n");
+- return -EINVAL;
+- }
+- nor->read_proto = SNOR_PROTO_1_1_4;
+- break;
++ return spansion_set_quad_mode(nor);
+
+ default:
+- return -EINVAL;
++ break;
+ }
+
+- nor->read_opcode = SPINOR_OP_READ_1_1_4;
+- return 0;
++ return -EINVAL;
+ }
+
+ static int set_dual_mode(struct spi_nor *nor, const struct flash_info *info)
+@@ -1501,13 +1519,14 @@ static int set_dual_mode(struct spi_nor *nor, const struct flash_info *info)
+ case SNOR_MFR_MICRON:
+ return micron_set_dual_mode(nor);
+
++ case SNOR_MFR_SPANSION:
++ return spansion_set_dual_mode(nor);
++
+ default:
+- nor->read_proto = SNOR_PROTO_1_1_2;
+ break;
+ }
+
+- nor->read_opcode = SPINOR_OP_READ_1_1_2;
+- return 0;
++ return -EINVAL;
+ }
+
+ static int set_single_mode(struct spi_nor *nor, const struct flash_info *info)
+@@ -1522,12 +1541,14 @@ static int set_single_mode(struct spi_nor *nor, const struct flash_info *info)
+ case SNOR_MFR_MICRON:
+ return micron_set_single_mode(nor);
+
++ case SNOR_MFR_SPANSION:
++ return spansion_set_single_mode(nor);
++
+ default:
+- nor->read_proto = SNOR_PROTO_1_1_1;
+ break;
+ }
+
+- return 0;
++ return -EINVAL;
+ }
+
+ static int spi_nor_check(struct spi_nor *nor)
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0023-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch b/target/linux/socfpga/patches-4.4/0023-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch
new file mode 100644
index 0000000000..7153a9f171
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0023-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch
@@ -0,0 +1,264 @@
+From 16410a33d6655d6c85c8c522bc6f2cfebf7c06a4 Mon Sep 17 00:00:00 2001
+From: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+Date: Fri, 8 Jan 2016 17:02:20 +0100
+Subject: [PATCH 23/33] mtd: spi-nor: configure the number of dummy clock
+ cycles by manufacturer
+
+This is a transitional patch which let us set the number of dummy clock
+cycles by manufacturer.
+
+More patches will follow by manufacturer to actually configure the
+relevant number of dummy clock cycles following the dedicated procedure.
+
+For instance, some manufacturers like Spansion configure the number of
+dummy clock cycles to be used by Fast Read command through some
+non-volatile register. In such a case, we should avoid updating its value
+but instead read it then set the nor->read_dummy accordingly.
+
+On the other hand, some manufacturers like Micron use some volatile
+register. In this case, we'd rather update this register to use a number
+of dummy clock cycles, which is a multiple of 8.
+Indeed some drivers, like m25p80, only support writing bytes, hence
+multiples of 8 bits.
+
+Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 99 ++++++++++++++++++++++++++++++++-----------
+ 1 file changed, 74 insertions(+), 25 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index 8a042ab..ae3e9d8 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -139,24 +139,6 @@ static int read_cr(struct spi_nor *nor)
+ }
+
+ /*
+- * Dummy Cycle calculation for different type of read.
+- * It can be used to support more commands with
+- * different dummy cycle requirements.
+- */
+-static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor)
+-{
+- switch (nor->flash_read) {
+- case SPI_NOR_FAST:
+- case SPI_NOR_DUAL:
+- case SPI_NOR_QUAD:
+- return 8;
+- case SPI_NOR_NORMAL:
+- return 0;
+- }
+- return 0;
+-}
+-
+-/*
+ * Write status register 1 byte
+ * Returns negative if error occurred.
+ */
+@@ -1217,6 +1199,7 @@ static int macronix_set_quad_mode(struct spi_nor *nor)
+ * read (performance enhance) mode by mistake!
+ */
+ nor->read_opcode = SPINOR_OP_READ_1_4_4;
++ nor->read_dummy = 8;
+ return 0;
+ }
+
+@@ -1238,6 +1221,7 @@ static int macronix_set_quad_mode(struct spi_nor *nor)
+ }
+ nor->read_proto = SNOR_PROTO_1_1_4;
+ nor->read_opcode = SPINOR_OP_READ_1_1_4;
++ nor->read_dummy = 8;
+ return 0;
+ }
+
+@@ -1251,12 +1235,27 @@ static int macronix_set_dual_mode(struct spi_nor *nor)
+ {
+ nor->read_proto = SNOR_PROTO_1_1_2;
+ nor->read_opcode = SPINOR_OP_READ_1_1_2;
++ nor->read_dummy = 8;
+ return 0;
+ }
+
+ static int macronix_set_single_mode(struct spi_nor *nor)
+ {
++ u8 read_dummy;
++
++ switch (nor->read_opcode) {
++ case SPINOR_OP_READ:
++ case SPINOR_OP_READ4:
++ read_dummy = 0;
++ break;
++
++ default:
++ read_dummy = 8;
++ break;
++ }
++
+ nor->read_proto = SNOR_PROTO_1_1_1;
++ nor->read_dummy = read_dummy;
+ return 0;
+ }
+
+@@ -1277,6 +1276,7 @@ static int winbond_set_quad_mode(struct spi_nor *nor)
+ * Hence the Fast Read 1-1-1 (0x0b) op code is chosen.
+ */
+ nor->read_opcode = SPINOR_OP_READ_FAST;
++ nor->read_dummy = 8;
+ return 0;
+ }
+
+@@ -1295,6 +1295,7 @@ static int winbond_set_quad_mode(struct spi_nor *nor)
+ }
+ nor->read_proto = SNOR_PROTO_1_1_4;
+ nor->read_opcode = SPINOR_OP_READ_1_1_4;
++ nor->read_dummy = 8;
+ return 0;
+ }
+
+@@ -1308,12 +1309,27 @@ static int winbond_set_dual_mode(struct spi_nor *nor)
+ {
+ nor->read_proto = SNOR_PROTO_1_1_2;
+ nor->read_opcode = SPINOR_OP_READ_1_1_2;
++ nor->read_dummy = 8;
+ return 0;
+ }
+
+ static int winbond_set_single_mode(struct spi_nor *nor)
+ {
++ u8 read_dummy;
++
++ switch (nor->read_opcode) {
++ case SPINOR_OP_READ:
++ case SPINOR_OP_READ4:
++ read_dummy = 0;
++ break;
++
++ default:
++ read_dummy = 8;
++ break;
++ }
++
+ nor->read_proto = SNOR_PROTO_1_1_1;
++ nor->read_dummy = read_dummy;
+ return 0;
+ }
+
+@@ -1405,6 +1421,7 @@ static int micron_set_quad_mode(struct spi_nor *nor)
+ if (nor->read_proto != SNOR_PROTO_4_4_4)
+ nor->read_proto = SNOR_PROTO_1_1_4;
+ nor->read_opcode = SPINOR_OP_READ_1_1_4;
++ nor->read_dummy = 8;
+ return 0;
+ }
+
+@@ -1434,11 +1451,14 @@ static int micron_set_dual_mode(struct spi_nor *nor)
+ if (nor->read_proto != SNOR_PROTO_2_2_2)
+ nor->read_proto = SNOR_PROTO_1_1_2;
+ nor->read_opcode = SPINOR_OP_READ_1_1_2;
++ nor->read_dummy = 8;
+ return 0;
+ }
+
+ static int micron_set_single_mode(struct spi_nor *nor)
+ {
++ u8 read_dummy;
++
+ /* Check whether either the Dual or Quad mode is enabled. */
+ if (unlikely(nor->read_proto != SNOR_PROTO_1_1_1)) {
+ int ret;
+@@ -1455,6 +1475,18 @@ static int micron_set_single_mode(struct spi_nor *nor)
+ nor->read_proto = SNOR_PROTO_1_1_1;
+ }
+
++ /* Force the number of dummy cycles to 8 for Fast Read, 0 for Read. */
++ switch (nor->read_opcode) {
++ case SPINOR_OP_READ:
++ case SPINOR_OP_READ4:
++ read_dummy = 0;
++ break;
++
++ default:
++ read_dummy = 8;
++ break;
++ }
++ nor->read_dummy = read_dummy;
+ return 0;
+ }
+
+@@ -1469,6 +1501,7 @@ static int spansion_set_quad_mode(struct spi_nor *nor)
+ }
+ nor->read_proto = SNOR_PROTO_1_1_4;
+ nor->read_opcode = SPINOR_OP_READ_1_1_4;
++ nor->read_dummy = 8;
+ return 0;
+ }
+
+@@ -1476,12 +1509,27 @@ static int spansion_set_dual_mode(struct spi_nor *nor)
+ {
+ nor->read_proto = SNOR_PROTO_1_1_2;
+ nor->read_opcode = SPINOR_OP_READ_1_1_2;
++ nor->read_dummy = 8;
+ return 0;
+ }
+
+ static int spansion_set_single_mode(struct spi_nor *nor)
+ {
++ u8 read_dummy;
++
++ switch (nor->read_opcode) {
++ case SPINOR_OP_READ:
++ case SPINOR_OP_READ4:
++ read_dummy = 0;
++ break;
++
++ default:
++ read_dummy = 8;
++ break;
++ }
++
+ nor->read_proto = SNOR_PROTO_1_1_1;
++ nor->read_dummy = read_dummy;
+ return 0;
+ }
+
+@@ -1696,11 +1744,14 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+ if (info->flags & SPI_NOR_NO_FR)
+ nor->flash_read = SPI_NOR_NORMAL;
+
+- /* Default commands */
+- if (nor->flash_read == SPI_NOR_NORMAL)
++ /* Default commands and number of dummy cycles */
++ if (nor->flash_read == SPI_NOR_NORMAL) {
+ nor->read_opcode = SPINOR_OP_READ;
+- else
++ nor->read_dummy = 0;
++ } else {
+ nor->read_opcode = SPINOR_OP_READ_FAST;
++ nor->read_dummy = 8;
++ }
+
+ nor->program_opcode = SPINOR_OP_PP;
+
+@@ -1715,8 +1766,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+ * - SNOR_PROTO_2_2_2 is either:
+ * + Micron Dual mode enabled
+ *
+- * The opcodes and the protocols are updated depending on the
+- * manufacturer.
++ * The opcodes, the protocols and the number of dummy cycles are updated
++ * depending on the manufacturer.
+ * The read opcode and protocol should be updated by the relevant
+ * function when entering Quad or Dual mode.
+ */
+@@ -1780,8 +1831,6 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+ return -EINVAL;
+ }
+
+- nor->read_dummy = spi_nor_read_dummy_cycles(nor);
+-
+ dev_info(dev, "%s (%lld Kbytes)\n", info->name,
+ (long long)mtd->size >> 10);
+
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0024-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch b/target/linux/socfpga/patches-4.4/0024-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch
new file mode 100644
index 0000000000..c6bf87099a
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0024-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch
@@ -0,0 +1,159 @@
+From 77fee227b15835d03517dc34675f72e8963ae882 Mon Sep 17 00:00:00 2001
+From: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+Date: Fri, 8 Jan 2016 17:02:21 +0100
+Subject: [PATCH 24/33] mtd: spi-nor: configure the number of dummy clock
+ cycles on Micron memories
+
+The spi-nor framework currently expects all Fast Read operations to use 8
+dummy clock cycles. Especially some drivers like m25p80 can only support
+multiple of 8 dummy clock cycles.
+
+On Micron memories, the number of dummy clock cycles to be used by Fast
+Read commands can be safely set to 8 by updating the Volatile
+Configuration Register (VCR).
+
+Also the XIP bit is set at the same time when updating the VCR so the
+Continuous Read mode is disabled: this prevents us from entering it by
+mistake.
+
+Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 72 ++++++++++++++++++++++++++++++++++++++-----
+ include/linux/mtd/spi-nor.h | 2 ++
+ 2 files changed, 67 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index ae3e9d8..5232984 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1333,6 +1333,53 @@ static int winbond_set_single_mode(struct spi_nor *nor)
+ return 0;
+ }
+
++static int micron_set_dummy_cycles(struct spi_nor *nor, u8 read_dummy)
++{
++ u8 vcr, val, mask;
++ int ret;
++
++ /* Set bit3 (XIP) to disable the Continuous Read mode */
++ mask = GENMASK(7, 4) | BIT(3);
++ val = ((read_dummy << 4) | BIT(3)) & mask;
++
++ /* Read the Volatile Configuration Register (VCR). */
++ ret = nor->read_reg(nor, SPINOR_OP_RD_VCR, &vcr, 1);
++ if (ret < 0) {
++ dev_err(nor->dev, "error while reading VCR register\n");
++ return ret;
++ }
++
++ /* Check whether we need to update the number of dummy cycles. */
++ if ((vcr & mask) == val) {
++ nor->read_dummy = read_dummy;
++ return 0;
++ }
++
++ /* Update the number of dummy into the VCR. */
++ write_enable(nor);
++ vcr = (vcr & ~mask) | val;
++ ret = nor->write_reg(nor, SPINOR_OP_WR_VCR, &vcr, 1);
++ if (ret < 0) {
++ dev_err(nor->dev, "error while writing VCR register\n");
++ return ret;
++ }
++
++ ret = spi_nor_wait_till_ready(nor);
++ if (ret)
++ return ret;
++
++ /* Read VCR and check it. */
++ ret = nor->read_reg(nor, SPINOR_OP_RD_VCR, &vcr, 1);
++ if (ret < 0 || (vcr & mask) != val) {
++ dev_err(nor->dev, "Micron VCR dummy cycles not updated\n");
++ return -EINVAL;
++ }
++
++ /* Save the number of dummy cycles to use with Fast Read commands */
++ nor->read_dummy = read_dummy;
++ return 0;
++}
++
+ static int micron_set_protocol(struct spi_nor *nor, u8 mask, u8 val,
+ enum spi_nor_protocol proto)
+ {
+@@ -1417,12 +1464,15 @@ static int micron_set_quad_mode(struct spi_nor *nor)
+ /*
+ * Whatever the Quad mode is enabled or not, the
+ * Fast Read Quad Output 1-1-4 (0x6b) op code is supported.
++ * Force the number of dummy cycles to 8 and disable the Continuous Read
++ * mode to prevent some drivers from using it by mistake (m25p80).
++ * We can change these settings safely as we write into a volatile
++ * register.
+ */
+ if (nor->read_proto != SNOR_PROTO_4_4_4)
+ nor->read_proto = SNOR_PROTO_1_1_4;
+ nor->read_opcode = SPINOR_OP_READ_1_1_4;
+- nor->read_dummy = 8;
+- return 0;
++ return micron_set_dummy_cycles(nor, 8);
+ }
+
+ static int micron_set_dual_mode(struct spi_nor *nor)
+@@ -1447,12 +1497,15 @@ static int micron_set_dual_mode(struct spi_nor *nor)
+ /*
+ * Whatever the Dual mode is enabled or not, the
+ * Fast Read Dual Output 1-1-2 (0x3b) op code is supported.
++ * Force the number of dummy cycles to 8 and disable the Continuous Read
++ * mode to prevent some drivers from using it by mistake (m25p80).
++ * We can change these settings safely as we write into a volatile
++ * register.
+ */
+ if (nor->read_proto != SNOR_PROTO_2_2_2)
+ nor->read_proto = SNOR_PROTO_1_1_2;
+ nor->read_opcode = SPINOR_OP_READ_1_1_2;
+- nor->read_dummy = 8;
+- return 0;
++ return micron_set_dummy_cycles(nor, 8);
+ }
+
+ static int micron_set_single_mode(struct spi_nor *nor)
+@@ -1475,7 +1528,13 @@ static int micron_set_single_mode(struct spi_nor *nor)
+ nor->read_proto = SNOR_PROTO_1_1_1;
+ }
+
+- /* Force the number of dummy cycles to 8 for Fast Read, 0 for Read. */
++ /*
++ * Force the number of dummy cycles to 8 for Fast Read, 0 for Read
++ * and disable the Continuous Read mode to prevent some drivers from
++ * using it by mistake (m25p80).
++ * We can change these settings safely as we write into a volatile
++ * register.
++ */
+ switch (nor->read_opcode) {
+ case SPINOR_OP_READ:
+ case SPINOR_OP_READ4:
+@@ -1486,8 +1545,7 @@ static int micron_set_single_mode(struct spi_nor *nor)
+ read_dummy = 8;
+ break;
+ }
+- nor->read_dummy = read_dummy;
+- return 0;
++ return micron_set_dummy_cycles(nor, read_dummy);
+ }
+
+ static int spansion_set_quad_mode(struct spi_nor *nor)
+diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
+index d0a6f34..2dc0f8b 100644
+--- a/include/linux/mtd/spi-nor.h
++++ b/include/linux/mtd/spi-nor.h
+@@ -86,6 +86,8 @@
+
+ /* Used for Micron flashes only. */
+ #define SPINOR_OP_MIO_RDID 0xaf /* Multiple I/O Read JEDEC ID */
++#define SPINOR_OP_RD_VCR 0x85 /* Read VCR register */
++#define SPINOR_OP_WR_VCR 0x81 /* Write VCR register */
+ #define SPINOR_OP_RD_EVCR 0x65 /* Read EVCR register */
+ #define SPINOR_OP_WD_EVCR 0x61 /* Write EVCR register */
+
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0025-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch b/target/linux/socfpga/patches-4.4/0025-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch
new file mode 100644
index 0000000000..a9c3afd98d
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0025-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch
@@ -0,0 +1,237 @@
+From a714a2af12d0de527be168b821373f29f4343cb7 Mon Sep 17 00:00:00 2001
+From: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+Date: Fri, 8 Jan 2016 17:02:22 +0100
+Subject: [PATCH 25/33] mtd: spi-nor: configure the number of dummy clock
+ cycles on Macronix memories
+
+The spi-nor framework currently expects all Fast Read operations to use 8
+dummy clock cycles. Especially some drivers like m25p80 can only support
+multiple of 8 dummy clock cycles.
+
+On Macronix memories, the number of dummy clock cycles to be used by Fast
+Read commands can be safely set to 8 by updating the DC0 and DC1 volatile
+bits inside the Configuration Register.
+
+According to the mx66l1g45g datasheet from Macronix, using 8 dummy clock
+cycles should be enough to set the SPI bus clock frequency up to:
+- 133 MHz for Fast Read 1-1-1, 1-1-2, 1-1-4 and 1-2-2 commands in Single
+ Transfer Rate (STR)
+- 104 MHz for Fast Read 1-4-4 (or 4-4-4 in QPI mode) commands (STR)
+
+Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 155 +++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 147 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index 5232984..55a1d74 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1182,6 +1182,136 @@ static int winbond_quad_enable(struct spi_nor *nor)
+ return 0;
+ }
+
++static int macronix_dummy2code(u8 read_opcode, u8 read_dummy, u8 *dc)
++{
++ switch (read_opcode) {
++ case SPINOR_OP_READ:
++ case SPINOR_OP_READ4:
++ *dc = 0;
++ break;
++
++ case SPINOR_OP_READ_FAST:
++ case SPINOR_OP_READ_1_1_2:
++ case SPINOR_OP_READ_1_1_4:
++ case SPINOR_OP_READ4_FAST:
++ case SPINOR_OP_READ4_1_1_2:
++ case SPINOR_OP_READ4_1_1_4:
++ switch (read_dummy) {
++ case 6:
++ *dc = 1;
++ break;
++ case 8:
++ *dc = 0;
++ break;
++ case 10:
++ *dc = 3;
++ break;
++ default:
++ return -EINVAL;
++ }
++ break;
++
++ case SPINOR_OP_READ_1_2_2:
++ case SPINOR_OP_READ4_1_2_2:
++ switch (read_dummy) {
++ case 4:
++ *dc = 0;
++ break;
++ case 6:
++ *dc = 1;
++ break;
++ case 8:
++ *dc = 2;
++ break;
++ case 10:
++ *dc = 3;
++ default:
++ return -EINVAL;
++ }
++ break;
++
++ case SPINOR_OP_READ_1_4_4:
++ case SPINOR_OP_READ4_1_4_4:
++ switch (read_dummy) {
++ case 4:
++ *dc = 1;
++ break;
++ case 6:
++ *dc = 0;
++ break;
++ case 8:
++ *dc = 2;
++ break;
++ case 10:
++ *dc = 3;
++ default:
++ return -EINVAL;
++ }
++ break;
++
++ default:
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static int macronix_set_dummy_cycles(struct spi_nor *nor, u8 read_dummy)
++{
++ int ret, sr, cr, mask, val;
++ u16 sr_cr;
++ u8 dc;
++
++ /* Convert the number of dummy cycles into Macronix DC volatile bits */
++ ret = macronix_dummy2code(nor->read_opcode, read_dummy, &dc);
++ if (ret)
++ return ret;
++
++ mask = GENMASK(7, 6);
++ val = (dc << 6) & mask;
++
++ cr = read_cr(nor);
++ if (cr < 0) {
++ dev_err(nor->dev, "error while reading the config register\n");
++ return cr;
++ }
++
++ if ((cr & mask) == val) {
++ nor->read_dummy = read_dummy;
++ return 0;
++ }
++
++ sr = read_sr(nor);
++ if (sr < 0) {
++ dev_err(nor->dev, "error while reading the status register\n");
++ return sr;
++ }
++
++ cr = (cr & ~mask) | val;
++ sr_cr = (sr & 0xff) | ((cr & 0xff) << 8);
++ write_enable(nor);
++ ret = write_sr_cr(nor, sr_cr);
++ if (ret) {
++ dev_err(nor->dev,
++ "error while writing the SR and CR registers\n");
++ return ret;
++ }
++
++ ret = spi_nor_wait_till_ready(nor);
++ if (ret)
++ return ret;
++
++ cr = read_cr(nor);
++ if (cr < 0 || (cr & mask) != val) {
++ dev_err(nor->dev, "Macronix Dummy Cycle bits not updated\n");
++ return -EINVAL;
++ }
++
++ /* Save the number of dummy cycles to use with Fast Read commands */
++ nor->read_dummy = read_dummy;
++ return 0;
++}
++
+ static int macronix_set_quad_mode(struct spi_nor *nor)
+ {
+ int status;
+@@ -1199,8 +1329,7 @@ static int macronix_set_quad_mode(struct spi_nor *nor)
+ * read (performance enhance) mode by mistake!
+ */
+ nor->read_opcode = SPINOR_OP_READ_1_4_4;
+- nor->read_dummy = 8;
+- return 0;
++ return macronix_set_dummy_cycles(nor, 8);
+ }
+
+ /*
+@@ -1213,6 +1342,9 @@ static int macronix_set_quad_mode(struct spi_nor *nor)
+ * entering the continuous read mode by mistake if some
+ * performance enhance toggling bits P0-P7 were written during
+ * dummy/mode cycles.
++ *
++ * Use the Fast Read Quad Output 1-1-4 (0x6b) command with 8 dummy
++ * cycles (up to 133MHz for STR and 66MHz for DTR).
+ */
+ status = macronix_quad_enable(nor);
+ if (status) {
+@@ -1221,8 +1353,7 @@ static int macronix_set_quad_mode(struct spi_nor *nor)
+ }
+ nor->read_proto = SNOR_PROTO_1_1_4;
+ nor->read_opcode = SPINOR_OP_READ_1_1_4;
+- nor->read_dummy = 8;
+- return 0;
++ return macronix_set_dummy_cycles(nor, 8);
+ }
+
+ /*
+@@ -1233,16 +1364,25 @@ static int macronix_set_quad_mode(struct spi_nor *nor)
+
+ static int macronix_set_dual_mode(struct spi_nor *nor)
+ {
++ /*
++ * Use the Fast Read Dual Output 1-1-2 (0x3b) command with 8 dummy
++ * cycles (up to 133MHz for STR and 66MHz for DTR).
++ */
+ nor->read_proto = SNOR_PROTO_1_1_2;
+ nor->read_opcode = SPINOR_OP_READ_1_1_2;
+- nor->read_dummy = 8;
+- return 0;
++ return macronix_set_dummy_cycles(nor, 8);
+ }
+
+ static int macronix_set_single_mode(struct spi_nor *nor)
+ {
+ u8 read_dummy;
+
++ /*
++ * Configure 8 dummy cycles for Fast Read 1-1-1 (0x0b) command (up to
++ * 133MHz for STR and 66MHz for DTR). The Read 1-1-1 (0x03) command
++ * expects no dummy cycle.
++ * read_opcode should not be overridden here!
++ */
+ switch (nor->read_opcode) {
+ case SPINOR_OP_READ:
+ case SPINOR_OP_READ4:
+@@ -1255,8 +1395,7 @@ static int macronix_set_single_mode(struct spi_nor *nor)
+ }
+
+ nor->read_proto = SNOR_PROTO_1_1_1;
+- nor->read_dummy = read_dummy;
+- return 0;
++ return macronix_set_dummy_cycles(nor, read_dummy);
+ }
+
+ static int winbond_set_quad_mode(struct spi_nor *nor)
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0026-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch b/target/linux/socfpga/patches-4.4/0026-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch
new file mode 100644
index 0000000000..df79cdcce6
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0026-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch
@@ -0,0 +1,215 @@
+From 7b411f38f7882fdf9f5607bc75deb940a7aaa480 Mon Sep 17 00:00:00 2001
+From: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+Date: Fri, 8 Jan 2016 17:10:53 +0100
+Subject: [PATCH 26/33] mtd: spi-nor: configure the number of dummy clock
+ cycles on Spansion memories
+
+On Spansion memories, the number of dummy clock cycles to be used during
+Fast Read commands is configured through the 2bit latency code (LC). These
+bits are non-volatile inside the Configuration Register.
+
+To avoid breaking the configuration expected at reset by some bootloaders,
+we'd rather read the latency code and set the nor->read_dummy value
+accordingly than update those non-volatile bits.
+
+Since the Quad Enable non-volatile bit can be read at the same time from
+the Control Register, we now check its value to avoid some calls of the
+spansion_quad_enable() function when they are not needed.
+
+Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 159 ++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 137 insertions(+), 22 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index 55a1d74..654209a 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1687,47 +1687,162 @@ static int micron_set_single_mode(struct spi_nor *nor)
+ return micron_set_dummy_cycles(nor, read_dummy);
+ }
+
+-static int spansion_set_quad_mode(struct spi_nor *nor)
++static inline int spansion_get_config(struct spi_nor *nor,
++ bool *quad_enabled,
++ u8 *latency_code)
+ {
+- int status;
++ int cr;
+
+- status = spansion_quad_enable(nor);
+- if (status) {
+- dev_err(nor->dev, "Spansion quad-read not enabled\n");
++ cr = read_cr(nor);
++ if (cr < 0) {
++ dev_err(nor->dev,
++ "error while reading the configuration register\n");
++ return cr;
++ }
++
++ if (quad_enabled)
++ *quad_enabled = !!(cr & CR_QUAD_EN_SPAN);
++
++ if (latency_code)
++ *latency_code = (u8)((cr & GENMASK(7, 6)) >> 6);
++
++ return 0;
++}
++
++static int spansion_set_dummy_cycles(struct spi_nor *nor, u8 latency_code)
++{
++ /* SDR dummy cycles */
++ switch (nor->read_opcode) {
++ case SPINOR_OP_READ:
++ case SPINOR_OP_READ4:
++ nor->read_dummy = 0;
++ break;
++
++ case SPINOR_OP_READ_FAST:
++ case SPINOR_OP_READ_1_1_2:
++ case SPINOR_OP_READ_1_1_4:
++ case SPINOR_OP_READ4_FAST:
++ case SPINOR_OP_READ4_1_1_2:
++ case SPINOR_OP_READ4_1_1_4:
++ nor->read_dummy = (latency_code == 3) ? 0 : 8;
++ break;
++
++ case SPINOR_OP_READ_1_2_2:
++ case SPINOR_OP_READ4_1_2_2:
++ switch (latency_code) {
++ default:
++ case 0:
++ case 3:
++ nor->read_dummy = 4;
++ break;
++ case 1:
++ nor->read_dummy = 5;
++ break;
++ case 2:
++ nor->read_dummy = 6;
++ break;
++ }
++ break;
++
++
++ case SPINOR_OP_READ_1_4_4:
++ case SPINOR_OP_READ4_1_4_4:
++ switch (latency_code) {
++ default:
++ case 0:
++ case 1:
++ nor->read_dummy = 4;
++ break;
++ case 2:
++ nor->read_dummy = 5;
++ break;
++ case 3:
++ nor->read_dummy = 1;
++ break;
++ }
++
++ default:
+ return -EINVAL;
+ }
++
++ return 0;
++}
++
++static int spansion_set_quad_mode(struct spi_nor *nor)
++{
++ bool quad_enabled;
++ u8 latency_code;
++ int ret;
++
++ /*
++ * The QUAD bit of Configuration Register must be set (CR Bit1=1) for
++ * using any Quad SPI command.
++ */
++ ret = spansion_get_config(nor, &quad_enabled, &latency_code);
++ if (ret)
++ return ret;
++
++ /* The Quad mode should be enabled ... */
++ if (!quad_enabled) {
++ /* ... if not try to enable it. */
++ dev_warn(nor->dev, "Spansion Quad mode disabled, enable it\n");
++ ret = spansion_quad_enable(nor);
++ if (ret)
++ return ret;
++ }
++
++ /*
++ * Don't use the Fast Read Quad I/O (0xeb / 0xec) commands as their
++ * number of dummy cycles can not be set to a multiple of 8: some SPI
++ * controllers, especially those relying on the m25p80 driver, expect
++ * the number of dummy cycles to be a multiple of 8.
++ * Also when using a Fast Read Quad I/O command, the memory checks the
++ * value of the first mode/dummy cycles to decice whether it enters or
++ * leaves the Countinuous Read mode. We should never enter the
++ * Countinuous Read mode as the spi-nor framework doesn't support it.
++ * For all these reason, we'd rather use the Fast Read Quad Output
++ * 1-1-4 (0x6b / 0x6c) commands instead.
++ */
+ nor->read_proto = SNOR_PROTO_1_1_4;
+ nor->read_opcode = SPINOR_OP_READ_1_1_4;
+- nor->read_dummy = 8;
+- return 0;
++ return spansion_set_dummy_cycles(nor, latency_code);
+ }
+
+ static int spansion_set_dual_mode(struct spi_nor *nor)
+ {
++ u8 latency_code;
++ int ret;
++
++ /* We don't care about the quad mode status */
++ ret = spansion_get_config(nor, NULL, &latency_code);
++ if (ret)
++ return ret;
++
++ /*
++ * Don't use the Fast Read Dual I/O (0xbb / 0xbc) commands as their
++ * number of dummy cycles can not bet set to a multiple of 8: some SPI
++ * controllers, especially those relying on the m25p80 driver, expect
++ * the number of dummy cycles to be a multiple of 8.
++ * For this reason, w'd rather use the Fast Read Dual Output 1-1-2
++ * (0x3b / 0x3c) commands instead.
++ */
+ nor->read_proto = SNOR_PROTO_1_1_2;
+ nor->read_opcode = SPINOR_OP_READ_1_1_2;
+- nor->read_dummy = 8;
+- return 0;
++ return spansion_set_dummy_cycles(nor, latency_code);
+ }
+
+ static int spansion_set_single_mode(struct spi_nor *nor)
+ {
+- u8 read_dummy;
+-
+- switch (nor->read_opcode) {
+- case SPINOR_OP_READ:
+- case SPINOR_OP_READ4:
+- read_dummy = 0;
+- break;
++ u8 latency_code;
++ int ret;
+
+- default:
+- read_dummy = 8;
+- break;
+- }
++ /* We don't care about the quad mode status */
++ ret = spansion_get_config(nor, NULL, &latency_code);
++ if (ret)
++ return ret;
+
+ nor->read_proto = SNOR_PROTO_1_1_1;
+- nor->read_dummy = read_dummy;
+- return 0;
++ return spansion_set_dummy_cycles(nor, latency_code);
+ }
+
+ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0027-mtd-m25p80-add-support-of-dual-and-quad-spi-protocol.patch b/target/linux/socfpga/patches-4.4/0027-mtd-m25p80-add-support-of-dual-and-quad-spi-protocol.patch
new file mode 100644
index 0000000000..d2f5ab6e84
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0027-mtd-m25p80-add-support-of-dual-and-quad-spi-protocol.patch
@@ -0,0 +1,293 @@
+From 8b4f14b2f8ed819a6b9e371128259271e8d88841 Mon Sep 17 00:00:00 2001
+From: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+Date: Fri, 8 Jan 2016 17:10:54 +0100
+Subject: [PATCH 27/33] mtd: m25p80: add support of dual and quad spi protocols
+ to all commands
+
+Before this patch, m25p80_read() supported few SPI protocols:
+- regular SPI 1-1-1
+- SPI Dual Output 1-1-2
+- SPI Quad Output 1-1-4
+On the other hand, all other m25p80_*() hooks only supported SPI 1-1-1.
+
+However once their Quad mode enabled, Micron and Macronix spi-nor memories
+expect all commands to use the SPI 4-4-4 protocol.
+
+Also, once their Dual mode enabled, Micron spi-nor memories expect all
+commands to use the SPI-2-2-2 protocol.
+
+So this patch adds support to all currently existing SPI protocols to
+cover as many protocols as possible.
+
+Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+---
+ drivers/mtd/devices/m25p80.c | 192 ++++++++++++++++++++++++++++++++++---------
+ 1 file changed, 151 insertions(+), 41 deletions(-)
+
+diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
+index bc7a802..e3e2708 100644
+--- a/drivers/mtd/devices/m25p80.c
++++ b/drivers/mtd/devices/m25p80.c
+@@ -27,22 +27,64 @@
+ #include <linux/spi/flash.h>
+ #include <linux/mtd/spi-nor.h>
+
+-#define MAX_CMD_SIZE 6
++#define MAX_CMD_SIZE 16
+ struct m25p {
+ struct spi_device *spi;
+ struct spi_nor spi_nor;
+ u8 command[MAX_CMD_SIZE];
+ };
+
++static inline int m25p80_proto2nbits(enum spi_nor_protocol proto,
++ unsigned *code_nbits,
++ unsigned *addr_nbits,
++ unsigned *data_nbits)
++{
++ if (code_nbits)
++ *code_nbits = SNOR_PROTO_CMD_FROM_PROTO(proto);
++ if (addr_nbits)
++ *addr_nbits = SNOR_PROTO_ADDR_FROM_PROTO(proto);
++ if (data_nbits)
++ *data_nbits = SNOR_PROTO_DATA_FROM_PROTO(proto);
++
++ return 0;
++}
++
+ static int m25p80_read_reg(struct spi_nor *nor, u8 code, u8 *val, int len)
+ {
+ struct m25p *flash = nor->priv;
+ struct spi_device *spi = flash->spi;
++ unsigned code_nbits, data_nbits;
++ struct spi_transfer xfers[2];
+ int ret;
+
+- ret = spi_write_then_read(spi, &code, 1, val, len);
++ /* Check the total length of command op code and data. */
++ if (len + 1 > MAX_CMD_SIZE)
++ return -EINVAL;
++
++ /* Get transfer protocols (addr_nbits is not relevant here). */
++ ret = m25p80_proto2nbits(nor->reg_proto,
++ &code_nbits, NULL, &data_nbits);
++ if (ret < 0)
++ return ret;
++
++ /* Set up transfers. */
++ memset(xfers, 0, sizeof(xfers));
++
++ flash->command[0] = code;
++ xfers[0].len = 1;
++ xfers[0].tx_buf = flash->command;
++ xfers[0].tx_nbits = code_nbits;
++
++ xfers[1].len = len;
++ xfers[1].rx_buf = &flash->command[1];
++ xfers[1].rx_nbits = data_nbits;
++
++ /* Process command. */
++ ret = spi_sync_transfer(spi, xfers, 2);
+ if (ret < 0)
+ dev_err(&spi->dev, "error %d reading %x\n", ret, code);
++ else
++ memcpy(val, &flash->command[1], len);
+
+ return ret;
+ }
+@@ -65,12 +107,42 @@ static int m25p80_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
+ {
+ struct m25p *flash = nor->priv;
+ struct spi_device *spi = flash->spi;
++ unsigned code_nbits, data_nbits, num_xfers = 1;
++ struct spi_transfer xfers[2];
++ int ret;
++
++ /* Check the total length of command op code and data. */
++ if (buf && (len + 1 > MAX_CMD_SIZE))
++ return -EINVAL;
++
++ /* Get transfer protocols (addr_nbits is not relevant here). */
++ ret = m25p80_proto2nbits(nor->reg_proto,
++ &code_nbits, NULL, &data_nbits);
++ if (ret < 0)
++ return ret;
++
++ /* Set up transfer(s). */
++ memset(xfers, 0, sizeof(xfers));
+
+ flash->command[0] = opcode;
+- if (buf)
++ xfers[0].len = 1;
++ xfers[0].tx_buf = flash->command;
++ xfers[0].tx_nbits = code_nbits;
++
++ if (buf) {
+ memcpy(&flash->command[1], buf, len);
++ if (data_nbits == code_nbits) {
++ xfers[0].len += len;
++ } else {
++ xfers[1].len = len;
++ xfers[1].tx_buf = &flash->command[1];
++ xfers[1].tx_nbits = data_nbits;
++ num_xfers++;
++ }
++ }
+
+- return spi_write(spi, flash->command, len + 1);
++ /* Process command. */
++ return spi_sync_transfer(spi, xfers, num_xfers);
+ }
+
+ static void m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
+@@ -78,43 +150,54 @@ static void m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
+ {
+ struct m25p *flash = nor->priv;
+ struct spi_device *spi = flash->spi;
+- struct spi_transfer t[2] = {};
++ unsigned code_nbits, addr_nbits, data_nbits, num_xfers = 1;
++ struct spi_transfer xfers[3];
+ struct spi_message m;
+- int cmd_sz = m25p_cmdsz(nor);
+-
+- spi_message_init(&m);
++ int ret, cmd_sz = m25p_cmdsz(nor);
+
+ if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
+ cmd_sz = 1;
+
+- flash->command[0] = nor->program_opcode;
+- m25p_addr2cmd(nor, to, flash->command);
++ /* Get transfer protocols. */
++ ret = m25p80_proto2nbits(nor->write_proto,
++ &code_nbits, &addr_nbits, &data_nbits);
++ if (ret < 0) {
++ *retlen = 0;
++ return;
++ }
+
+- t[0].tx_buf = flash->command;
+- t[0].len = cmd_sz;
+- spi_message_add_tail(&t[0], &m);
++ /* Set up transfers. */
++ memset(xfers, 0, sizeof(xfers));
++
++ flash->command[0] = nor->program_opcode;
++ xfers[0].len = 1;
++ xfers[0].tx_buf = flash->command;
++ xfers[0].tx_nbits = code_nbits;
++
++ if (cmd_sz > 1) {
++ m25p_addr2cmd(nor, to, flash->command);
++ if (addr_nbits == code_nbits) {
++ xfers[0].len += nor->addr_width;
++ } else {
++ xfers[1].len = nor->addr_width;
++ xfers[1].tx_buf = &flash->command[1];
++ xfers[1].tx_nbits = addr_nbits;
++ num_xfers++;
++ }
++ }
+
+- t[1].tx_buf = buf;
+- t[1].len = len;
+- spi_message_add_tail(&t[1], &m);
++ xfers[num_xfers].len = len;
++ xfers[num_xfers].tx_buf = buf;
++ xfers[num_xfers].tx_nbits = data_nbits;
++ num_xfers++;
+
++ /* Process command. */
++ spi_message_init_with_transfers(&m, xfers, num_xfers);
+ spi_sync(spi, &m);
+
+ *retlen += m.actual_length - cmd_sz;
+ }
+
+-static inline unsigned int m25p80_rx_nbits(struct spi_nor *nor)
+-{
+- switch (nor->flash_read) {
+- case SPI_NOR_DUAL:
+- return 2;
+- case SPI_NOR_QUAD:
+- return 4;
+- default:
+- return 0;
+- }
+-}
+-
+ /*
+ * Read an address range from the nor chip. The address range
+ * may be any size provided it is within the physical boundaries.
+@@ -124,28 +207,55 @@ static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
+ {
+ struct m25p *flash = nor->priv;
+ struct spi_device *spi = flash->spi;
+- struct spi_transfer t[2];
+- struct spi_message m;
++ unsigned code_nbits, addr_nbits, data_nbits, num_xfers = 1;
+ unsigned int dummy = nor->read_dummy;
++ struct spi_transfer xfers[3];
++ struct spi_message m;
++ int ret;
++
++ /* Get transfer protocols. */
++ ret = m25p80_proto2nbits(nor->read_proto,
++ &code_nbits, &addr_nbits, &data_nbits);
++ if (ret < 0) {
++ *retlen = 0;
++ return ret;
++ }
+
+ /* convert the dummy cycles to the number of bytes */
+- dummy /= 8;
++ dummy = (dummy * addr_nbits) / 8;
+
+- spi_message_init(&m);
+- memset(t, 0, (sizeof t));
++ /* Set up transfers. */
++ memset(xfers, 0, sizeof(xfers));
+
+ flash->command[0] = nor->read_opcode;
+- m25p_addr2cmd(nor, from, flash->command);
++ xfers[0].len = 1;
++ xfers[0].tx_buf = flash->command;
++ xfers[0].tx_nbits = code_nbits;
+
+- t[0].tx_buf = flash->command;
+- t[0].len = m25p_cmdsz(nor) + dummy;
+- spi_message_add_tail(&t[0], &m);
++ m25p_addr2cmd(nor, from, flash->command);
++ /*
++ * Clear all dummy/mode cycle bits to avoid sending some manufacturer
++ * specific pattern, which might make the memory enter its Continuous
++ * Read mode by mistake.
++ */
++ memset(flash->command + 1 + nor->addr_width, 0, dummy);
++
++ if (addr_nbits == code_nbits) {
++ xfers[0].len += nor->addr_width + dummy;
++ } else {
++ xfers[1].len = nor->addr_width + dummy;
++ xfers[1].tx_buf = &flash->command[1];
++ xfers[1].tx_nbits = addr_nbits;
++ num_xfers++;
++ }
+
+- t[1].rx_buf = buf;
+- t[1].rx_nbits = m25p80_rx_nbits(nor);
+- t[1].len = len;
+- spi_message_add_tail(&t[1], &m);
++ xfers[num_xfers].len = len;
++ xfers[num_xfers].rx_buf = buf;
++ xfers[num_xfers].rx_nbits = data_nbits;
++ num_xfers++;
+
++ /* Process command. */
++ spi_message_init_with_transfers(&m, xfers, num_xfers);
+ spi_sync(spi, &m);
+
+ *retlen = m.actual_length - m25p_cmdsz(nor) - dummy;
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0028-mtd-ofpart-grab-device-tree-node-directly-from-maste.patch b/target/linux/socfpga/patches-4.4/0028-mtd-ofpart-grab-device-tree-node-directly-from-maste.patch
new file mode 100644
index 0000000000..3787607236
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0028-mtd-ofpart-grab-device-tree-node-directly-from-maste.patch
@@ -0,0 +1,81 @@
+From 62b613003aa4cef3f8bf9a2ec4c7709daf4dde8a Mon Sep 17 00:00:00 2001
+From: Brian Norris <computersforpeace@gmail.com>
+Date: Fri, 30 Oct 2015 20:33:21 -0700
+Subject: [PATCH 28/33] mtd: ofpart: grab device tree node directly from master
+ device node
+
+It seems more logical to use a device node directly associated with the
+MTD master device (i.e., mtd->dev.of_node field) rather than requiring
+auxiliary partition parser information to be passed in by the driver in
+a separate struct.
+
+This patch supports the mtd->dev.of_node field and deprecates the parser
+data 'of_node' field
+
+Driver conversions may now follow.
+
+Additional side benefit to assigning mtd->dev.of_node rather than using
+parser data: the driver core will automatically create a device -> node
+symlink for us.
+
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+Reviewed-by: Boris Brezillon <boris.brezillon@free-electrons.com>
+---
+ drivers/mtd/ofpart.c | 18 ++++++++++--------
+ include/linux/mtd/partitions.h | 4 +++-
+ 2 files changed, 13 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c
+index 9ed6038..cf4780c 100644
+--- a/drivers/mtd/ofpart.c
++++ b/drivers/mtd/ofpart.c
+@@ -37,10 +37,11 @@ static int parse_ofpart_partitions(struct mtd_info *master,
+ bool dedicated = true;
+
+
+- if (!data)
+- return 0;
+-
+- mtd_node = data->of_node;
++ /*
++ * of_node can be provided through auxiliary parser data or (preferred)
++ * by assigning the master device node
++ */
++ mtd_node = data && data->of_node ? data->of_node : mtd_get_of_node(master);
+ if (!mtd_node)
+ return 0;
+
+@@ -157,10 +158,11 @@ static int parse_ofoldpart_partitions(struct mtd_info *master,
+ } *part;
+ const char *names;
+
+- if (!data)
+- return 0;
+-
+- dp = data->of_node;
++ /*
++ * of_node can be provided through auxiliary parser data or (preferred)
++ * by assigning the master device node
++ */
++ dp = data && data->of_node ? data->of_node : mtd_get_of_node(master);
+ if (!dp)
+ return 0;
+
+diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h
+index 6a35e6d..e742f34 100644
+--- a/include/linux/mtd/partitions.h
++++ b/include/linux/mtd/partitions.h
+@@ -56,7 +56,9 @@ struct device_node;
+ /**
+ * struct mtd_part_parser_data - used to pass data to MTD partition parsers.
+ * @origin: for RedBoot, start address of MTD device
+- * @of_node: for OF parsers, device node containing partitioning information
++ * @of_node: for OF parsers, device node containing partitioning information.
++ * This field is deprecated, as the device node should simply be
++ * assigned to the master struct device.
+ */
+ struct mtd_part_parser_data {
+ unsigned long origin;
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0029-Documentation-atmel-quadspi-add-binding-file-for-Atm.patch b/target/linux/socfpga/patches-4.4/0029-Documentation-atmel-quadspi-add-binding-file-for-Atm.patch
new file mode 100644
index 0000000000..ca8831d15a
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0029-Documentation-atmel-quadspi-add-binding-file-for-Atm.patch
@@ -0,0 +1,58 @@
+From 771ee7cd27c39617ece8727c70f904c31f7415fb Mon Sep 17 00:00:00 2001
+From: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+Date: Fri, 8 Jan 2016 17:10:55 +0100
+Subject: [PATCH 29/33] Documentation: atmel-quadspi: add binding file for
+ Atmel QSPI driver
+
+This patch documents the DT bindings for the driver of the Atmel QSPI
+controller embedded inside sama5d2x SoCs.
+
+Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+Acked-by: Rob Herring <robh@kernel.org>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ .../devicetree/bindings/mtd/atmel-quadspi.txt | 32 ++++++++++++++++++++++
+ 1 file changed, 32 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/mtd/atmel-quadspi.txt
+
+diff --git a/Documentation/devicetree/bindings/mtd/atmel-quadspi.txt b/Documentation/devicetree/bindings/mtd/atmel-quadspi.txt
+new file mode 100644
+index 0000000..4898070
+--- /dev/null
++++ b/Documentation/devicetree/bindings/mtd/atmel-quadspi.txt
+@@ -0,0 +1,32 @@
++* Atmel Quad Serial Peripheral Interface (QSPI)
++
++Required properties:
++- compatible: Should be "atmel,sama5d2-qspi".
++- reg: Should contain the locations and lengths of the base registers
++ and the mapped memory.
++- reg-names: Should contain the resource reg names:
++ - qspi_base: configuration register address space
++ - qspi_mmap: memory mapped address space
++- interrupts: Should contain the interrupt for the device.
++- clocks: The phandle of the clock needed by the QSPI controller.
++- #address-cells: Should be <1>.
++- #size-cells: Should be <0>.
++
++Example:
++
++spi@f0020000 {
++ compatible = "atmel,sama5d2-qspi";
++ reg = <0xf0020000 0x100>, <0xd0000000 0x8000000>;
++ reg-names = "qspi_base", "qspi_mmap";
++ interrupts = <52 IRQ_TYPE_LEVEL_HIGH 7>;
++ clocks = <&spi0_clk>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_spi0_default>;
++ status = "okay";
++
++ m25p80@0 {
++ ...
++ };
++};
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0030-mtd-spi-nor-Bindings-for-Cadence-Quad-SPI-Flash-Cont.patch b/target/linux/socfpga/patches-4.4/0030-mtd-spi-nor-Bindings-for-Cadence-Quad-SPI-Flash-Cont.patch
new file mode 100644
index 0000000000..7b454a84a1
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0030-mtd-spi-nor-Bindings-for-Cadence-Quad-SPI-Flash-Cont.patch
@@ -0,0 +1,99 @@
+From 8e8a7168e89cc978ca14ab74ab20193ca09e3f3a Mon Sep 17 00:00:00 2001
+From: Graham Moore <grmoore@opensource.altera.com>
+Date: Tue, 28 Jul 2015 12:38:02 -0500
+Subject: [PATCH 30/33] mtd: spi-nor: Bindings for Cadence Quad SPI Flash
+ Controller driver.
+
+Add binding document for the Cadence QSPI controller.
+
+Signed-off-by: Graham Moore <grmoore@opensource.altera.com>
+Signed-off-by: Marek Vasut <marex@denx.de>
+Cc: Alan Tull <atull@opensource.altera.com>
+Cc: Brian Norris <computersforpeace@gmail.com>
+Cc: David Woodhouse <dwmw2@infradead.org>
+Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
+Cc: Graham Moore <grmoore@opensource.altera.com>
+Cc: Vignesh R <vigneshr@ti.com>
+Cc: Yves Vandervennet <yvanderv@opensource.altera.com>
+Cc: devicetree@vger.kernel.org
+
+V2: Add cdns prefix to driver-specific bindings.
+V3: Use existing property "is-decoded-cs" instead of creating a
+ duplicate, "ext-decoder". Timing parameters are in nanoseconds,
+ not master reference clocks. Remove bus-num completely.
+V4: Add new properties fifo-width and trigger-address
+V7: - Prefix all of the Cadence-specific properties with cdns prefix,
+ those are in particular "cdns,is-decoded-cs", "cdns,fifo-depth",
+ "cdns,fifo-width", "cdns,trigger-address".
+ - Drop bogus properties which were not used and were incorrect.
+V8: Align lines to 80 chars.
+---
+ .../devicetree/bindings/mtd/cadence-quadspi.txt | 56 ++++++++++++++++++++++
+ 1 file changed, 56 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/mtd/cadence-quadspi.txt
+
+diff --git a/Documentation/devicetree/bindings/mtd/cadence-quadspi.txt b/Documentation/devicetree/bindings/mtd/cadence-quadspi.txt
+new file mode 100644
+index 0000000..f248056
+--- /dev/null
++++ b/Documentation/devicetree/bindings/mtd/cadence-quadspi.txt
+@@ -0,0 +1,56 @@
++* Cadence Quad SPI controller
++
++Required properties:
++- compatible : Should be "cdns,qspi-nor".
++- reg : Contains two entries, each of which is a tuple consisting of a
++ physical address and length. The first entry is the address and
++ length of the controller register set. The second entry is the
++ address and length of the QSPI Controller data area.
++- interrupts : Unit interrupt specifier for the controller interrupt.
++- clocks : phandle to the Quad SPI clock.
++- cdns,fifo-depth : Size of the data FIFO in words.
++- cdns,fifo-width : Bus width of the data FIFO in bytes.
++- cdns,trigger-address : 32-bit indirect AHB trigger address.
++
++Optional properties:
++- cdns,is-decoded-cs : Flag to indicate whether decoder is used or not.
++
++Optional subnodes:
++Subnodes of the Cadence Quad SPI controller are spi slave nodes with additional
++custom properties:
++- cdns,read-delay : Delay for read capture logic, in clock cycles
++- cdns,tshsl-ns : Delay in nanoseconds for the length that the master
++ mode chip select outputs are de-asserted between
++ transactions.
++- cdns,tsd2d-ns : Delay in nanoseconds between one chip select being
++ de-activated and the activation of another.
++- cdns,tchsh-ns : Delay in nanoseconds between last bit of current
++ transaction and deasserting the device chip select
++ (qspi_n_ss_out).
++- cdns,tslch-ns : Delay in nanoseconds between setting qspi_n_ss_out low
++ and first bit transfer.
++
++Example:
++
++ qspi: spi@ff705000 {
++ compatible = "cdns,qspi-nor";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0xff705000 0x1000>,
++ <0xffa00000 0x1000>;
++ interrupts = <0 151 4>;
++ clocks = <&qspi_clk>;
++ cdns,is-decoded-cs;
++ cdns,fifo-depth = <128>;
++ cdns,fifo-width = <4>;
++ cdns,trigger-address = <0x00000000>;
++
++ flash0: n25q00@0 {
++ ...
++ cdns,read-delay = <4>;
++ cdns,tshsl-ns = <50>;
++ cdns,tsd2d-ns = <50>;
++ cdns,tchsh-ns = <4>;
++ cdns,tslch-ns = <4>;
++ };
++ };
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0031-mtd-spi-nor-Add-driver-for-Cadence-Quad-SPI-Flash-Co.patch b/target/linux/socfpga/patches-4.4/0031-mtd-spi-nor-Add-driver-for-Cadence-Quad-SPI-Flash-Co.patch
new file mode 100644
index 0000000000..1a55ee2dd6
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0031-mtd-spi-nor-Add-driver-for-Cadence-Quad-SPI-Flash-Co.patch
@@ -0,0 +1,1431 @@
+From 30e33517815b3c518fc2483a23bfe1445c0ae92d Mon Sep 17 00:00:00 2001
+From: Graham Moore <grmoore@opensource.altera.com>
+Date: Tue, 28 Jul 2015 12:38:03 -0500
+Subject: [PATCH 31/33] mtd: spi-nor: Add driver for Cadence Quad SPI Flash
+ Controller.
+
+Add support for the Cadence QSPI controller. This controller is
+present in the Altera SoCFPGA SoCs and this driver has been tested
+on the Cyclone V SoC.
+
+Signed-off-by: Graham Moore <grmoore@opensource.altera.com>
+Signed-off-by: Marek Vasut <marex@denx.de>
+Cc: Alan Tull <atull@opensource.altera.com>
+Cc: Brian Norris <computersforpeace@gmail.com>
+Cc: David Woodhouse <dwmw2@infradead.org>
+Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
+Cc: Graham Moore <grmoore@opensource.altera.com>
+Cc: Vignesh R <vigneshr@ti.com>
+Cc: Yves Vandervennet <yvanderv@opensource.altera.com>
+Cc: devicetree@vger.kernel.org
+
+V2: use NULL instead of modalias in spi_nor_scan call
+V3: Use existing property is-decoded-cs instead of creating duplicate.
+V4: Support Micron quad mode by snooping command stream for EVCR command
+ and subsequently configuring Cadence controller for quad mode.
+V5: Clean up sparse and smatch complaints. Remove snooping of Micron
+ quad mode. Add comment on XIP mode bit and dummy clock cycles. Set
+ up SRAM partition at 1:1 during init.
+V6: Remove dts patch that was included by mistake. Incorporate Vikas's
+ comments regarding fifo width, SRAM partition setting, and trigger
+ address. Trigger address was added as an unsigned int, as it is not
+ an IO resource per se, and does not need to be mapped. Also add
+ Marek Vasut's workaround for picking up OF properties on subnodes.
+V7: - Perform coding-style cleanup and type fixes. Remove ugly QSPI_*()
+ macros and replace them with functions. Get rid of unused variables.
+ - Implement support for nor->set_protocol() to handle Quad-command,
+ this patch now depends on the following patch:
+ mtd: spi-nor: notify (Q)SPI controller about protocol change
+ - Replace that cqspi_fifo_read() disaster with plain old readsl()
+ and cqspi_fifo_write() tentacle horror with pretty writesl().
+ - Remove CQSPI_SUPPORT_XIP_CHIPS, which is broken.
+ - Get rid of cqspi_find_chipselect() mess, instead just place the
+ struct cqspi_st and chipselect number into struct cqspi_flash_pdata
+ and set nor->priv to the struct cqspi_flash_pdata of that particular
+ chip.
+ - Replace the odd math in calculate_ticks_for_ns() with DIV_ROUND_UP().
+ - Make variables const where applicable.
+V8: - Implement a function to wait for bit being set/unset for a given
+ period of time and use it to replace the ad-hoc bits of code.
+ - Configure the write underflow watermark to be 1/8 if FIFO size.
+ - Extract out the SPI NOR flash probing code into separate function
+ to clearly mark what will soon be considered a boilerplate code.
+ - Repair the handling of mode bits, which caused instability in V7.
+ - Clean up the interrupt handling
+ - Fix Kconfig help text and make the patch depend on OF and COMPILE_TEST.
+V9: - Rename CQSPI_REG_IRQ_IND_RD_OVERFLOW to CQSPI_REG_IRQ_IND_SRAM_FULL
+ - Merge cqspi_controller_disable() into cqspi_controller_enable() and
+ make the mode selectable via parameter.
+V10: - Update against Cyrille's new patchset and changes to linux-mtd.
+ - Repair problem with multiple QSPI NOR devices having the same mtd->name,
+ they are now named devname.cs , where cs is the chipselect ID.
+V11: - Replace dependency on ARCH_SOCFPGA with dependency on ARM
+---
+ drivers/mtd/spi-nor/Kconfig | 11 +
+ drivers/mtd/spi-nor/Makefile | 1 +
+ drivers/mtd/spi-nor/cadence-quadspi.c | 1324 +++++++++++++++++++++++++++++++++
+ 3 files changed, 1336 insertions(+)
+ create mode 100644 drivers/mtd/spi-nor/cadence-quadspi.c
+
+diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig
+index 2fe2a7e..02082ae 100644
+--- a/drivers/mtd/spi-nor/Kconfig
++++ b/drivers/mtd/spi-nor/Kconfig
+@@ -41,4 +41,15 @@ config SPI_NXP_SPIFI
+ Flash. Enable this option if you have a device with a SPIFI
+ controller and want to access the Flash as a mtd device.
+
++config SPI_CADENCE_QUADSPI
++ tristate "Cadence Quad SPI controller"
++ depends on OF && (ARM || COMPILE_TEST)
++ help
++ Enable support for the Cadence Quad SPI Flash controller.
++
++ Cadence QSPI is a specialized controller for connecting an SPI
++ Flash over 1/2/4-bit wide bus. Enable this option if you have a
++ device with a Cadence QSPI controller and want to access the
++ Flash as an MTD device.
++
+ endif # MTD_SPI_NOR
+diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile
+index e53333e..446c6b9 100644
+--- a/drivers/mtd/spi-nor/Makefile
++++ b/drivers/mtd/spi-nor/Makefile
+@@ -1,3 +1,4 @@
+ obj-$(CONFIG_MTD_SPI_NOR) += spi-nor.o
++obj-$(CONFIG_SPI_CADENCE_QUADSPI) += cadence-quadspi.o
+ obj-$(CONFIG_SPI_FSL_QUADSPI) += fsl-quadspi.o
+ obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o
+diff --git a/drivers/mtd/spi-nor/cadence-quadspi.c b/drivers/mtd/spi-nor/cadence-quadspi.c
+new file mode 100644
+index 0000000..7e61fba
+--- /dev/null
++++ b/drivers/mtd/spi-nor/cadence-quadspi.c
+@@ -0,0 +1,1324 @@
++/*
++ * Driver for Cadence QSPI Controller
++ *
++ * Copyright Altera Corporation (C) 2012-2014. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program. If not, see <http://www.gnu.org/licenses/>.
++ */
++#include <linux/clk.h>
++#include <linux/completion.h>
++#include <linux/delay.h>
++#include <linux/err.h>
++#include <linux/errno.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/jiffies.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/mtd/spi-nor.h>
++#include <linux/of_device.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/sched.h>
++#include <linux/spi/spi.h>
++#include <linux/timer.h>
++
++#define CQSPI_NAME "cadence-qspi"
++#define CQSPI_MAX_CHIPSELECT 16
++
++struct cqspi_st;
++
++struct cqspi_flash_pdata {
++ struct spi_nor nor;
++ struct cqspi_st *cqspi;
++ u32 clk_rate;
++ u32 read_delay;
++ u32 tshsl_ns;
++ u32 tsd2d_ns;
++ u32 tchsh_ns;
++ u32 tslch_ns;
++ u8 inst_width;
++ u8 addr_width;
++ u8 cs;
++};
++
++struct cqspi_st {
++ struct platform_device *pdev;
++
++ struct clk *clk;
++ unsigned int sclk;
++
++ void __iomem *iobase;
++ void __iomem *ahb_base;
++ struct completion transfer_complete;
++ struct mutex bus_mutex;
++
++ int current_cs;
++ unsigned long master_ref_clk_hz;
++ bool is_decoded_cs;
++ u32 fifo_depth;
++ u32 fifo_width;
++ u32 trigger_address;
++ struct cqspi_flash_pdata f_pdata[CQSPI_MAX_CHIPSELECT];
++};
++
++/* Operation timeout value */
++#define CQSPI_TIMEOUT_MS 500
++#define CQSPI_READ_TIMEOUT_MS 10
++
++/* Instruction type */
++#define CQSPI_INST_TYPE_SINGLE 0
++#define CQSPI_INST_TYPE_DUAL 1
++#define CQSPI_INST_TYPE_QUAD 2
++
++#define CQSPI_DUMMY_CLKS_PER_BYTE 8
++#define CQSPI_DUMMY_BYTES_MAX 4
++#define CQSPI_DUMMY_CLKS_MAX 31
++
++#define CQSPI_STIG_DATA_LEN_MAX 8
++
++/* Register map */
++#define CQSPI_REG_CONFIG 0x00
++#define CQSPI_REG_CONFIG_ENABLE_MASK BIT(0)
++#define CQSPI_REG_CONFIG_DECODE_MASK BIT(9)
++#define CQSPI_REG_CONFIG_CHIPSELECT_LSB 10
++#define CQSPI_REG_CONFIG_DMA_MASK BIT(15)
++#define CQSPI_REG_CONFIG_BAUD_LSB 19
++#define CQSPI_REG_CONFIG_IDLE_LSB 31
++#define CQSPI_REG_CONFIG_CHIPSELECT_MASK 0xF
++#define CQSPI_REG_CONFIG_BAUD_MASK 0xF
++
++#define CQSPI_REG_RD_INSTR 0x04
++#define CQSPI_REG_RD_INSTR_OPCODE_LSB 0
++#define CQSPI_REG_RD_INSTR_TYPE_INSTR_LSB 8
++#define CQSPI_REG_RD_INSTR_TYPE_ADDR_LSB 12
++#define CQSPI_REG_RD_INSTR_TYPE_DATA_LSB 16
++#define CQSPI_REG_RD_INSTR_MODE_EN_LSB 20
++#define CQSPI_REG_RD_INSTR_DUMMY_LSB 24
++#define CQSPI_REG_RD_INSTR_TYPE_INSTR_MASK 0x3
++#define CQSPI_REG_RD_INSTR_TYPE_ADDR_MASK 0x3
++#define CQSPI_REG_RD_INSTR_TYPE_DATA_MASK 0x3
++#define CQSPI_REG_RD_INSTR_DUMMY_MASK 0x1F
++
++#define CQSPI_REG_WR_INSTR 0x08
++#define CQSPI_REG_WR_INSTR_OPCODE_LSB 0
++#define CQSPI_REG_WR_INSTR_TYPE_ADDR_LSB 12
++#define CQSPI_REG_WR_INSTR_TYPE_DATA_LSB 16
++
++#define CQSPI_REG_DELAY 0x0C
++#define CQSPI_REG_DELAY_TSLCH_LSB 0
++#define CQSPI_REG_DELAY_TCHSH_LSB 8
++#define CQSPI_REG_DELAY_TSD2D_LSB 16
++#define CQSPI_REG_DELAY_TSHSL_LSB 24
++#define CQSPI_REG_DELAY_TSLCH_MASK 0xFF
++#define CQSPI_REG_DELAY_TCHSH_MASK 0xFF
++#define CQSPI_REG_DELAY_TSD2D_MASK 0xFF
++#define CQSPI_REG_DELAY_TSHSL_MASK 0xFF
++
++#define CQSPI_REG_READCAPTURE 0x10
++#define CQSPI_REG_READCAPTURE_BYPASS_LSB 0
++#define CQSPI_REG_READCAPTURE_DELAY_LSB 1
++#define CQSPI_REG_READCAPTURE_DELAY_MASK 0xF
++
++#define CQSPI_REG_SIZE 0x14
++#define CQSPI_REG_SIZE_ADDRESS_LSB 0
++#define CQSPI_REG_SIZE_PAGE_LSB 4
++#define CQSPI_REG_SIZE_BLOCK_LSB 16
++#define CQSPI_REG_SIZE_ADDRESS_MASK 0xF
++#define CQSPI_REG_SIZE_PAGE_MASK 0xFFF
++#define CQSPI_REG_SIZE_BLOCK_MASK 0x3F
++
++#define CQSPI_REG_SRAMPARTITION 0x18
++#define CQSPI_REG_INDIRECTTRIGGER 0x1C
++
++#define CQSPI_REG_DMA 0x20
++#define CQSPI_REG_DMA_SINGLE_LSB 0
++#define CQSPI_REG_DMA_BURST_LSB 8
++#define CQSPI_REG_DMA_SINGLE_MASK 0xFF
++#define CQSPI_REG_DMA_BURST_MASK 0xFF
++
++#define CQSPI_REG_REMAP 0x24
++#define CQSPI_REG_MODE_BIT 0x28
++
++#define CQSPI_REG_SDRAMLEVEL 0x2C
++#define CQSPI_REG_SDRAMLEVEL_RD_LSB 0
++#define CQSPI_REG_SDRAMLEVEL_WR_LSB 16
++#define CQSPI_REG_SDRAMLEVEL_RD_MASK 0xFFFF
++#define CQSPI_REG_SDRAMLEVEL_WR_MASK 0xFFFF
++
++#define CQSPI_REG_IRQSTATUS 0x40
++#define CQSPI_REG_IRQMASK 0x44
++
++#define CQSPI_REG_INDIRECTRD 0x60
++#define CQSPI_REG_INDIRECTRD_START_MASK BIT(0)
++#define CQSPI_REG_INDIRECTRD_CANCEL_MASK BIT(1)
++#define CQSPI_REG_INDIRECTRD_DONE_MASK BIT(5)
++
++#define CQSPI_REG_INDIRECTRDWATERMARK 0x64
++#define CQSPI_REG_INDIRECTRDSTARTADDR 0x68
++#define CQSPI_REG_INDIRECTRDBYTES 0x6C
++
++#define CQSPI_REG_CMDCTRL 0x90
++#define CQSPI_REG_CMDCTRL_EXECUTE_MASK BIT(0)
++#define CQSPI_REG_CMDCTRL_INPROGRESS_MASK BIT(1)
++#define CQSPI_REG_CMDCTRL_WR_BYTES_LSB 12
++#define CQSPI_REG_CMDCTRL_WR_EN_LSB 15
++#define CQSPI_REG_CMDCTRL_ADD_BYTES_LSB 16
++#define CQSPI_REG_CMDCTRL_ADDR_EN_LSB 19
++#define CQSPI_REG_CMDCTRL_RD_BYTES_LSB 20
++#define CQSPI_REG_CMDCTRL_RD_EN_LSB 23
++#define CQSPI_REG_CMDCTRL_OPCODE_LSB 24
++#define CQSPI_REG_CMDCTRL_WR_BYTES_MASK 0x7
++#define CQSPI_REG_CMDCTRL_ADD_BYTES_MASK 0x3
++#define CQSPI_REG_CMDCTRL_RD_BYTES_MASK 0x7
++
++#define CQSPI_REG_INDIRECTWR 0x70
++#define CQSPI_REG_INDIRECTWR_START_MASK BIT(0)
++#define CQSPI_REG_INDIRECTWR_CANCEL_MASK BIT(1)
++#define CQSPI_REG_INDIRECTWR_DONE_MASK BIT(5)
++
++#define CQSPI_REG_INDIRECTWRWATERMARK 0x74
++#define CQSPI_REG_INDIRECTWRSTARTADDR 0x78
++#define CQSPI_REG_INDIRECTWRBYTES 0x7C
++
++#define CQSPI_REG_CMDADDRESS 0x94
++#define CQSPI_REG_CMDREADDATALOWER 0xA0
++#define CQSPI_REG_CMDREADDATAUPPER 0xA4
++#define CQSPI_REG_CMDWRITEDATALOWER 0xA8
++#define CQSPI_REG_CMDWRITEDATAUPPER 0xAC
++
++/* Interrupt status bits */
++#define CQSPI_REG_IRQ_MODE_ERR BIT(0)
++#define CQSPI_REG_IRQ_UNDERFLOW BIT(1)
++#define CQSPI_REG_IRQ_IND_COMP BIT(2)
++#define CQSPI_REG_IRQ_IND_RD_REJECT BIT(3)
++#define CQSPI_REG_IRQ_WR_PROTECTED_ERR BIT(4)
++#define CQSPI_REG_IRQ_ILLEGAL_AHB_ERR BIT(5)
++#define CQSPI_REG_IRQ_WATERMARK BIT(6)
++#define CQSPI_REG_IRQ_IND_SRAM_FULL BIT(12)
++
++#define CQSPI_IRQ_MASK_RD (CQSPI_REG_IRQ_WATERMARK | \
++ CQSPI_REG_IRQ_IND_SRAM_FULL | \
++ CQSPI_REG_IRQ_IND_COMP)
++
++#define CQSPI_IRQ_MASK_WR (CQSPI_REG_IRQ_IND_COMP | \
++ CQSPI_REG_IRQ_WATERMARK | \
++ CQSPI_REG_IRQ_UNDERFLOW)
++
++#define CQSPI_IRQ_STATUS_MASK 0x1FFFF
++
++static int cqspi_wait_for_bit(void __iomem *reg, const u32 mask, bool clear)
++{
++ unsigned long end = jiffies + msecs_to_jiffies(CQSPI_TIMEOUT_MS);
++ u32 val;
++
++ while (1) {
++ val = readl(reg);
++ if (clear)
++ val = ~val;
++ val &= mask;
++
++ if (val == mask)
++ return 0;
++
++ if (time_after(jiffies, end))
++ return -ETIMEDOUT;
++ }
++}
++
++static bool cqspi_is_idle(struct cqspi_st *cqspi)
++{
++ u32 reg = readl(cqspi->iobase + CQSPI_REG_CONFIG);
++
++ return reg & (1 << CQSPI_REG_CONFIG_IDLE_LSB);
++}
++
++static u32 cqspi_get_rd_sram_level(struct cqspi_st *cqspi)
++{
++ u32 reg = readl(cqspi->iobase + CQSPI_REG_SDRAMLEVEL);
++
++ reg >>= CQSPI_REG_SDRAMLEVEL_RD_LSB;
++ return reg & CQSPI_REG_SDRAMLEVEL_RD_MASK;
++}
++
++static irqreturn_t cqspi_irq_handler(int this_irq, void *dev)
++{
++ struct cqspi_st *cqspi = dev;
++ unsigned int irq_status;
++
++ /* Read interrupt status */
++ irq_status = readl(cqspi->iobase + CQSPI_REG_IRQSTATUS);
++
++ /* Clear interrupt */
++ writel(irq_status, cqspi->iobase + CQSPI_REG_IRQSTATUS);
++
++ irq_status &= CQSPI_IRQ_MASK_RD | CQSPI_IRQ_MASK_WR;
++
++ if (irq_status)
++ complete(&cqspi->transfer_complete);
++
++ return IRQ_HANDLED;
++}
++
++static unsigned int cqspi_calc_rdreg(struct spi_nor *nor, const u8 opcode)
++{
++ unsigned int rdreg = 0;
++ struct cqspi_flash_pdata *f_pdata = nor->priv;
++
++ rdreg |= f_pdata->inst_width << CQSPI_REG_RD_INSTR_TYPE_INSTR_LSB;
++ rdreg |= f_pdata->addr_width << CQSPI_REG_RD_INSTR_TYPE_ADDR_LSB;
++
++ if (nor->flash_read == SPI_NOR_QUAD)
++ rdreg |= CQSPI_INST_TYPE_QUAD
++ << CQSPI_REG_RD_INSTR_TYPE_DATA_LSB;
++ return rdreg;
++}
++
++static int cqspi_wait_idle(struct cqspi_st *cqspi)
++{
++ const unsigned int poll_idle_retry = 3;
++ unsigned int count = 0;
++ unsigned long timeout;
++
++ timeout = jiffies + msecs_to_jiffies(CQSPI_TIMEOUT_MS);
++ while (1) {
++ /*
++ * Read few times in succession to ensure the controller
++ * is indeed idle, that is, the bit does not transition
++ * low again.
++ */
++ if (cqspi_is_idle(cqspi))
++ count++;
++ else
++ count = 0;
++
++ if (count >= poll_idle_retry)
++ return 0;
++
++ if (time_after(jiffies, timeout)) {
++ /* Timeout, in busy mode. */
++ dev_err(&cqspi->pdev->dev,
++ "QSPI is still busy after %dms timeout.\n",
++ CQSPI_TIMEOUT_MS);
++ return -ETIMEDOUT;
++ }
++
++ cpu_relax();
++ }
++}
++
++static int cqspi_exec_flash_cmd(struct cqspi_st *cqspi, unsigned int reg)
++{
++ void __iomem *reg_base = cqspi->iobase;
++ int ret;
++
++ /* Write the CMDCTRL without start execution. */
++ writel(reg, reg_base + CQSPI_REG_CMDCTRL);
++ /* Start execute */
++ reg |= CQSPI_REG_CMDCTRL_EXECUTE_MASK;
++ writel(reg, reg_base + CQSPI_REG_CMDCTRL);
++
++ /* Polling for completion. */
++ ret = cqspi_wait_for_bit(reg_base + CQSPI_REG_CMDCTRL,
++ CQSPI_REG_CMDCTRL_INPROGRESS_MASK, 1);
++ if (ret) {
++ dev_err(&cqspi->pdev->dev,
++ "Flash command execution timed out.\n");
++ return ret;
++ }
++
++ /* Polling QSPI idle status. */
++ return cqspi_wait_idle(cqspi);
++}
++
++static int cqspi_command_read(struct spi_nor *nor,
++ const u8 *txbuf, const unsigned n_tx,
++ u8 *rxbuf, const unsigned n_rx)
++{
++ struct cqspi_flash_pdata *f_pdata = nor->priv;
++ struct cqspi_st *cqspi = f_pdata->cqspi;
++ void __iomem *reg_base = cqspi->iobase;
++ unsigned int rdreg;
++ unsigned int reg;
++ unsigned int read_len;
++ int status;
++
++ if (!n_rx || n_rx > CQSPI_STIG_DATA_LEN_MAX || !rxbuf) {
++ dev_err(nor->dev, "Invalid input argument, len %d rxbuf 0x%p\n",
++ n_rx, rxbuf);
++ return -EINVAL;
++ }
++
++ reg = txbuf[0] << CQSPI_REG_CMDCTRL_OPCODE_LSB;
++
++ rdreg = cqspi_calc_rdreg(nor, txbuf[0]);
++ writel(rdreg, reg_base + CQSPI_REG_RD_INSTR);
++
++ reg |= (0x1 << CQSPI_REG_CMDCTRL_RD_EN_LSB);
++
++ /* 0 means 1 byte. */
++ reg |= (((n_rx - 1) & CQSPI_REG_CMDCTRL_RD_BYTES_MASK)
++ << CQSPI_REG_CMDCTRL_RD_BYTES_LSB);
++ status = cqspi_exec_flash_cmd(cqspi, reg);
++ if (status)
++ return status;
++
++ reg = readl(reg_base + CQSPI_REG_CMDREADDATALOWER);
++
++ /* Put the read value into rx_buf */
++ read_len = (n_rx > 4) ? 4 : n_rx;
++ memcpy(rxbuf, &reg, read_len);
++ rxbuf += read_len;
++
++ if (n_rx > 4) {
++ reg = readl(reg_base + CQSPI_REG_CMDREADDATAUPPER);
++
++ read_len = n_rx - read_len;
++ memcpy(rxbuf, &reg, read_len);
++ }
++
++ return 0;
++}
++
++static int cqspi_command_write(struct spi_nor *nor, const u8 opcode,
++ const u8 *txbuf, const unsigned n_tx)
++{
++ struct cqspi_flash_pdata *f_pdata = nor->priv;
++ struct cqspi_st *cqspi = f_pdata->cqspi;
++ void __iomem *reg_base = cqspi->iobase;
++ unsigned int reg;
++ unsigned int data;
++ int ret;
++
++ if (n_tx > 4 || (n_tx && !txbuf)) {
++ dev_err(nor->dev,
++ "Invalid input argument, cmdlen %d txbuf 0x%p\n",
++ n_tx, txbuf);
++ return -EINVAL;
++ }
++
++ reg = opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB;
++ if (n_tx) {
++ reg |= (0x1 << CQSPI_REG_CMDCTRL_WR_EN_LSB);
++ reg |= ((n_tx - 1) & CQSPI_REG_CMDCTRL_WR_BYTES_MASK)
++ << CQSPI_REG_CMDCTRL_WR_BYTES_LSB;
++ data = 0;
++ memcpy(&data, txbuf, n_tx);
++ writel(data, reg_base + CQSPI_REG_CMDWRITEDATALOWER);
++ }
++
++ ret = cqspi_exec_flash_cmd(cqspi, reg);
++ return ret;
++}
++
++static int cqspi_command_write_addr(struct spi_nor *nor,
++ const u8 opcode, const unsigned int addr)
++{
++ struct cqspi_flash_pdata *f_pdata = nor->priv;
++ struct cqspi_st *cqspi = f_pdata->cqspi;
++ void __iomem *reg_base = cqspi->iobase;
++ unsigned int reg;
++
++ reg = opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB;
++ reg |= (0x1 << CQSPI_REG_CMDCTRL_ADDR_EN_LSB);
++ reg |= ((nor->addr_width - 1) & CQSPI_REG_CMDCTRL_ADD_BYTES_MASK)
++ << CQSPI_REG_CMDCTRL_ADD_BYTES_LSB;
++
++ writel(addr, reg_base + CQSPI_REG_CMDADDRESS);
++
++ return cqspi_exec_flash_cmd(cqspi, reg);
++}
++
++static int cqspi_indirect_read_setup(struct spi_nor *nor,
++ const unsigned int from_addr)
++{
++ struct cqspi_flash_pdata *f_pdata = nor->priv;
++ struct cqspi_st *cqspi = f_pdata->cqspi;
++ void __iomem *reg_base = cqspi->iobase;
++ unsigned int dummy_clk = 0;
++ unsigned int reg;
++
++ writel(from_addr, reg_base + CQSPI_REG_INDIRECTRDSTARTADDR);
++
++ reg = nor->read_opcode << CQSPI_REG_RD_INSTR_OPCODE_LSB;
++ reg |= cqspi_calc_rdreg(nor, nor->read_opcode);
++
++ /* Setup dummy clock cycles */
++ dummy_clk = nor->read_dummy;
++ if (dummy_clk > CQSPI_DUMMY_CLKS_MAX)
++ dummy_clk = CQSPI_DUMMY_CLKS_MAX;
++
++ if (dummy_clk / 8) {
++ reg |= (1 << CQSPI_REG_RD_INSTR_MODE_EN_LSB);
++ /* Set mode bits high to ensure chip doesn't enter XIP */
++ writel(0xFF, reg_base + CQSPI_REG_MODE_BIT);
++
++ /* Need to subtract the mode byte (8 clocks). */
++ if (f_pdata->inst_width != CQSPI_INST_TYPE_QUAD)
++ dummy_clk -= 8;
++
++ if (dummy_clk)
++ reg |= (dummy_clk & CQSPI_REG_RD_INSTR_DUMMY_MASK)
++ << CQSPI_REG_RD_INSTR_DUMMY_LSB;
++ }
++
++ writel(reg, reg_base + CQSPI_REG_RD_INSTR);
++
++ /* Set address width */
++ reg = readl(reg_base + CQSPI_REG_SIZE);
++ reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
++ reg |= (nor->addr_width - 1);
++ writel(reg, reg_base + CQSPI_REG_SIZE);
++ return 0;
++}
++
++static int cqspi_indirect_read_execute(struct spi_nor *nor,
++ u8 *rxbuf, const unsigned n_rx)
++{
++ struct cqspi_flash_pdata *f_pdata = nor->priv;
++ struct cqspi_st *cqspi = f_pdata->cqspi;
++ void __iomem *reg_base = cqspi->iobase;
++ void __iomem *ahb_base = cqspi->ahb_base;
++ unsigned int remaining = n_rx;
++ unsigned int bytes_to_read = 0;
++ int ret = 0;
++
++ writel(remaining, reg_base + CQSPI_REG_INDIRECTRDBYTES);
++
++ /* Clear all interrupts. */
++ writel(CQSPI_IRQ_STATUS_MASK, reg_base + CQSPI_REG_IRQSTATUS);
++
++ writel(CQSPI_IRQ_MASK_RD, reg_base + CQSPI_REG_IRQMASK);
++
++ reinit_completion(&cqspi->transfer_complete);
++ writel(CQSPI_REG_INDIRECTRD_START_MASK,
++ reg_base + CQSPI_REG_INDIRECTRD);
++
++ while (remaining > 0) {
++ ret = wait_for_completion_timeout(&cqspi->transfer_complete,
++ msecs_to_jiffies
++ (CQSPI_READ_TIMEOUT_MS));
++
++ bytes_to_read = cqspi_get_rd_sram_level(cqspi);
++
++ if (!ret && bytes_to_read == 0) {
++ dev_err(nor->dev, "Indirect read timeout, no bytes\n");
++ ret = -ETIMEDOUT;
++ goto failrd;
++ }
++
++ while (bytes_to_read != 0) {
++ bytes_to_read *= cqspi->fifo_width;
++ bytes_to_read = bytes_to_read > remaining ?
++ remaining : bytes_to_read;
++ readsl(ahb_base, rxbuf, DIV_ROUND_UP(bytes_to_read, 4));
++ rxbuf += bytes_to_read;
++ remaining -= bytes_to_read;
++ bytes_to_read = cqspi_get_rd_sram_level(cqspi);
++ }
++
++ if (remaining > 0)
++ reinit_completion(&cqspi->transfer_complete);
++ }
++
++ /* Check indirect done status */
++ ret = cqspi_wait_for_bit(reg_base + CQSPI_REG_INDIRECTRD,
++ CQSPI_REG_INDIRECTRD_DONE_MASK, 0);
++ if (ret) {
++ dev_err(nor->dev,
++ "Indirect read completion error (%i)\n", ret);
++ goto failrd;
++ }
++
++ /* Disable interrupt */
++ writel(0, reg_base + CQSPI_REG_IRQMASK);
++
++ /* Clear indirect completion status */
++ writel(CQSPI_REG_INDIRECTRD_DONE_MASK, reg_base + CQSPI_REG_INDIRECTRD);
++
++ return 0;
++
++failrd:
++ /* Disable interrupt */
++ writel(0, reg_base + CQSPI_REG_IRQMASK);
++
++ /* Cancel the indirect read */
++ writel(CQSPI_REG_INDIRECTWR_CANCEL_MASK,
++ reg_base + CQSPI_REG_INDIRECTRD);
++ return ret;
++}
++
++static int cqspi_indirect_write_setup(struct spi_nor *nor,
++ const unsigned int to_addr)
++{
++ unsigned int reg;
++ struct cqspi_flash_pdata *f_pdata = nor->priv;
++ struct cqspi_st *cqspi = f_pdata->cqspi;
++ void __iomem *reg_base = cqspi->iobase;
++
++ /* Set opcode. */
++ reg = nor->program_opcode << CQSPI_REG_WR_INSTR_OPCODE_LSB;
++ writel(reg, reg_base + CQSPI_REG_WR_INSTR);
++ reg = cqspi_calc_rdreg(nor, nor->program_opcode);
++ writel(reg, reg_base + CQSPI_REG_RD_INSTR);
++
++ writel(to_addr, reg_base + CQSPI_REG_INDIRECTWRSTARTADDR);
++
++ reg = readl(reg_base + CQSPI_REG_SIZE);
++ reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
++ reg |= (nor->addr_width - 1);
++ writel(reg, reg_base + CQSPI_REG_SIZE);
++ return 0;
++}
++
++static int cqspi_indirect_write_execute(struct spi_nor *nor,
++ const u8 *txbuf, const unsigned n_tx)
++{
++ const unsigned int page_size = nor->page_size;
++ struct cqspi_flash_pdata *f_pdata = nor->priv;
++ struct cqspi_st *cqspi = f_pdata->cqspi;
++ void __iomem *reg_base = cqspi->iobase;
++ unsigned int remaining = n_tx;
++ unsigned int write_bytes;
++ int ret;
++
++ writel(remaining, reg_base + CQSPI_REG_INDIRECTWRBYTES);
++
++ /* Clear all interrupts. */
++ writel(CQSPI_IRQ_STATUS_MASK, reg_base + CQSPI_REG_IRQSTATUS);
++
++ writel(CQSPI_IRQ_MASK_WR, reg_base + CQSPI_REG_IRQMASK);
++
++ reinit_completion(&cqspi->transfer_complete);
++ writel(CQSPI_REG_INDIRECTWR_START_MASK,
++ reg_base + CQSPI_REG_INDIRECTWR);
++
++ while (remaining > 0) {
++ write_bytes = remaining > page_size ? page_size : remaining;
++ writesl(cqspi->ahb_base, txbuf, DIV_ROUND_UP(write_bytes, 4));
++
++ ret = wait_for_completion_timeout(&cqspi->transfer_complete,
++ msecs_to_jiffies
++ (CQSPI_TIMEOUT_MS));
++ if (!ret) {
++ dev_err(nor->dev, "Indirect write timeout\n");
++ ret = -ETIMEDOUT;
++ goto failwr;
++ }
++
++ txbuf += write_bytes;
++ remaining -= write_bytes;
++
++ if (remaining > 0)
++ reinit_completion(&cqspi->transfer_complete);
++ }
++
++ /* Check indirect done status */
++ ret = cqspi_wait_for_bit(reg_base + CQSPI_REG_INDIRECTWR,
++ CQSPI_REG_INDIRECTWR_DONE_MASK, 0);
++ if (ret) {
++ dev_err(nor->dev,
++ "Indirect write completion error (%i)\n", ret);
++ goto failwr;
++ }
++
++ /* Disable interrupt. */
++ writel(0, reg_base + CQSPI_REG_IRQMASK);
++
++ /* Clear indirect completion status */
++ writel(CQSPI_REG_INDIRECTWR_DONE_MASK, reg_base + CQSPI_REG_INDIRECTWR);
++
++ cqspi_wait_idle(cqspi);
++
++ return 0;
++
++failwr:
++ /* Disable interrupt. */
++ writel(0, reg_base + CQSPI_REG_IRQMASK);
++
++ /* Cancel the indirect write */
++ writel(CQSPI_REG_INDIRECTWR_CANCEL_MASK,
++ reg_base + CQSPI_REG_INDIRECTWR);
++ return ret;
++}
++
++static int cqspi_set_protocol(struct spi_nor *nor, enum spi_nor_protocol proto)
++{
++ struct cqspi_flash_pdata *f_pdata = nor->priv;
++
++ switch (proto) {
++ case SNOR_PROTO_1_1_1:
++ case SNOR_PROTO_1_1_2:
++ case SNOR_PROTO_1_1_4:
++ case SNOR_PROTO_1_2_2:
++ case SNOR_PROTO_1_4_4:
++ f_pdata->inst_width = CQSPI_INST_TYPE_SINGLE;
++ break;
++ case SNOR_PROTO_2_2_2:
++ f_pdata->inst_width = CQSPI_INST_TYPE_DUAL;
++ break;
++ case SNOR_PROTO_4_4_4:
++ f_pdata->inst_width = CQSPI_INST_TYPE_QUAD;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ switch (proto) {
++ case SNOR_PROTO_1_1_1:
++ case SNOR_PROTO_1_1_2:
++ case SNOR_PROTO_1_1_4:
++ f_pdata->addr_width = CQSPI_INST_TYPE_SINGLE;
++ break;
++ case SNOR_PROTO_1_2_2:
++ case SNOR_PROTO_2_2_2:
++ f_pdata->addr_width = CQSPI_INST_TYPE_DUAL;
++ break;
++ case SNOR_PROTO_1_4_4:
++ case SNOR_PROTO_4_4_4:
++ f_pdata->addr_width = CQSPI_INST_TYPE_QUAD;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static void cqspi_write(struct spi_nor *nor, loff_t to,
++ size_t len, size_t *retlen, const u_char *buf)
++{
++ int ret;
++
++ ret = cqspi_set_protocol(nor, nor->write_proto);
++ if (ret)
++ return;
++
++ ret = cqspi_indirect_write_setup(nor, to);
++ if (ret)
++ return;
++
++ ret = cqspi_indirect_write_execute(nor, buf, len);
++ if (ret)
++ return;
++
++ *retlen += len;
++}
++
++static int cqspi_read(struct spi_nor *nor, loff_t from,
++ size_t len, size_t *retlen, u_char *buf)
++{
++ int ret;
++
++ ret = cqspi_set_protocol(nor, nor->read_proto);
++ if (ret)
++ return ret;
++
++ ret = cqspi_indirect_read_setup(nor, from);
++ if (ret)
++ return ret;
++
++ ret = cqspi_indirect_read_execute(nor, buf, len);
++ if (ret)
++ return ret;
++
++ *retlen += len;
++ return ret;
++}
++
++static int cqspi_erase(struct spi_nor *nor, loff_t offs)
++{
++ int ret;
++
++ ret = cqspi_set_protocol(nor, nor->erase_proto);
++ if (ret)
++ return ret;
++
++ /* Send write enable, then erase commands. */
++ ret = nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0);
++ if (ret)
++ return ret;
++
++ /* Set up command buffer. */
++ ret = cqspi_command_write_addr(nor, nor->erase_opcode, offs);
++ if (ret)
++ return ret;
++
++ return 0;
++}
++
++static unsigned int calculate_ticks_for_ns(const unsigned int ref_clk_hz,
++ const unsigned int ns_val)
++{
++ unsigned int ticks;
++
++ ticks = ref_clk_hz / 1000; /* kHz */
++ ticks = DIV_ROUND_UP(ticks * ns_val, 1000000);
++
++ return ticks;
++}
++
++static void cqspi_delay(struct spi_nor *nor, const unsigned int sclk_hz)
++{
++ struct cqspi_flash_pdata *f_pdata = nor->priv;
++ struct cqspi_st *cqspi = f_pdata->cqspi;
++ void __iomem *iobase = cqspi->iobase;
++ const unsigned int ref_clk_hz = cqspi->master_ref_clk_hz;
++ unsigned int tshsl, tchsh, tslch, tsd2d;
++ unsigned int reg;
++ unsigned int tsclk;
++
++ /* calculate the number of ref ticks for one sclk tick */
++ tsclk = (ref_clk_hz + sclk_hz - 1) / sclk_hz;
++
++ tshsl = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tshsl_ns);
++ /* this particular value must be at least one sclk */
++ if (tshsl < tsclk)
++ tshsl = tsclk;
++
++ tchsh = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tchsh_ns);
++ tslch = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tslch_ns);
++ tsd2d = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tsd2d_ns);
++
++ reg = (tshsl & CQSPI_REG_DELAY_TSHSL_MASK)
++ << CQSPI_REG_DELAY_TSHSL_LSB;
++ reg |= (tchsh & CQSPI_REG_DELAY_TCHSH_MASK)
++ << CQSPI_REG_DELAY_TCHSH_LSB;
++ reg |= (tslch & CQSPI_REG_DELAY_TSLCH_MASK)
++ << CQSPI_REG_DELAY_TSLCH_LSB;
++ reg |= (tsd2d & CQSPI_REG_DELAY_TSD2D_MASK)
++ << CQSPI_REG_DELAY_TSD2D_LSB;
++ writel(reg, iobase + CQSPI_REG_DELAY);
++}
++
++static void cqspi_config_baudrate_div(struct cqspi_st *cqspi,
++ const unsigned int sclk_hz)
++{
++ const unsigned int ref_clk_hz = cqspi->master_ref_clk_hz;
++ void __iomem *reg_base = cqspi->iobase;
++ unsigned int reg;
++ unsigned int div;
++
++ reg = readl(reg_base + CQSPI_REG_CONFIG);
++ reg &= ~(CQSPI_REG_CONFIG_BAUD_MASK << CQSPI_REG_CONFIG_BAUD_LSB);
++
++ div = ref_clk_hz / sclk_hz;
++
++ /* Recalculate the baudrate divisor based on QSPI specification. */
++ if (div > 32)
++ div = 32;
++
++ /* Check if even number. */
++ if (div & 1)
++ div = (div / 2);
++ else
++ div = (div / 2) - 1;
++
++ div = (div & CQSPI_REG_CONFIG_BAUD_MASK) << CQSPI_REG_CONFIG_BAUD_LSB;
++ reg |= div;
++ writel(reg, reg_base + CQSPI_REG_CONFIG);
++}
++
++static void cqspi_readdata_capture(struct cqspi_st *cqspi,
++ const unsigned int bypass,
++ const unsigned int delay)
++{
++ void __iomem *reg_base = cqspi->iobase;
++ unsigned int reg;
++
++ reg = readl(reg_base + CQSPI_REG_READCAPTURE);
++
++ if (bypass)
++ reg |= (1 << CQSPI_REG_READCAPTURE_BYPASS_LSB);
++ else
++ reg &= ~(1 << CQSPI_REG_READCAPTURE_BYPASS_LSB);
++
++ reg &= ~(CQSPI_REG_READCAPTURE_DELAY_MASK
++ << CQSPI_REG_READCAPTURE_DELAY_LSB);
++
++ reg |= (delay & CQSPI_REG_READCAPTURE_DELAY_MASK)
++ << CQSPI_REG_READCAPTURE_DELAY_LSB;
++
++ writel(reg, reg_base + CQSPI_REG_READCAPTURE);
++}
++
++static void cqspi_chipselect(struct spi_nor *nor)
++{
++ struct cqspi_flash_pdata *f_pdata = nor->priv;
++ struct cqspi_st *cqspi = f_pdata->cqspi;
++ void __iomem *reg_base = cqspi->iobase;
++ unsigned int chip_select = f_pdata->cs;
++ unsigned int reg;
++
++ reg = readl(reg_base + CQSPI_REG_CONFIG);
++ if (cqspi->is_decoded_cs) {
++ reg |= CQSPI_REG_CONFIG_DECODE_MASK;
++ } else {
++ reg &= ~CQSPI_REG_CONFIG_DECODE_MASK;
++
++ /* Convert CS if without decoder.
++ * CS0 to 4b'1110
++ * CS1 to 4b'1101
++ * CS2 to 4b'1011
++ * CS3 to 4b'0111
++ */
++ chip_select = 0xF & ~(1 << chip_select);
++ }
++
++ reg &= ~(CQSPI_REG_CONFIG_CHIPSELECT_MASK
++ << CQSPI_REG_CONFIG_CHIPSELECT_LSB);
++ reg |= (chip_select & CQSPI_REG_CONFIG_CHIPSELECT_MASK)
++ << CQSPI_REG_CONFIG_CHIPSELECT_LSB;
++ writel(reg, reg_base + CQSPI_REG_CONFIG);
++}
++
++static void cqspi_controller_enable(struct cqspi_st *cqspi, bool enable)
++{
++ void __iomem *reg_base = cqspi->iobase;
++ unsigned int reg;
++
++ reg = readl(reg_base + CQSPI_REG_CONFIG);
++
++ if (enable)
++ reg |= CQSPI_REG_CONFIG_ENABLE_MASK;
++ else
++ reg &= ~CQSPI_REG_CONFIG_ENABLE_MASK;
++
++ writel(reg, reg_base + CQSPI_REG_CONFIG);
++}
++
++static void cqspi_switch_cs(struct spi_nor *nor)
++{
++ struct cqspi_flash_pdata *f_pdata = nor->priv;
++ struct cqspi_st *cqspi = f_pdata->cqspi;
++ void __iomem *iobase = cqspi->iobase;
++ unsigned int reg;
++
++ /* configure page size and block size. */
++ reg = readl(iobase + CQSPI_REG_SIZE);
++ reg &= ~(CQSPI_REG_SIZE_PAGE_MASK << CQSPI_REG_SIZE_PAGE_LSB);
++ reg &= ~(CQSPI_REG_SIZE_BLOCK_MASK << CQSPI_REG_SIZE_BLOCK_LSB);
++ reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
++ reg |= (nor->page_size << CQSPI_REG_SIZE_PAGE_LSB);
++ reg |= (ilog2(nor->mtd.erasesize) << CQSPI_REG_SIZE_BLOCK_LSB);
++ reg |= (nor->addr_width - 1);
++ writel(reg, iobase + CQSPI_REG_SIZE);
++
++ /* configure the chip select */
++ cqspi_chipselect(nor);
++}
++
++static int cqspi_prep_unlocked(struct spi_nor *nor, enum spi_nor_ops ops)
++{
++ struct cqspi_flash_pdata *f_pdata = nor->priv;
++ struct cqspi_st *cqspi = f_pdata->cqspi;
++ const unsigned int sclk = f_pdata->clk_rate;
++ const int switch_cs = (cqspi->current_cs != f_pdata->cs);
++ const int switch_ck = (cqspi->sclk != sclk);
++
++ if (switch_cs || switch_ck)
++ cqspi_controller_enable(cqspi, 0);
++
++ /* Switch chip select. */
++ if (switch_cs) {
++ cqspi->current_cs = f_pdata->cs;
++ cqspi_switch_cs(nor);
++ }
++
++ /* Setup baudrate divisor and delays */
++ if (switch_ck) {
++ cqspi->sclk = sclk;
++ cqspi_config_baudrate_div(cqspi, sclk);
++ cqspi_delay(nor, sclk);
++ cqspi_readdata_capture(cqspi, 1, f_pdata->read_delay);
++ }
++
++ if (switch_cs || switch_ck)
++ cqspi_controller_enable(cqspi, 1);
++
++ return 0;
++}
++
++static int cqspi_prep(struct spi_nor *nor, enum spi_nor_ops ops)
++{
++ struct cqspi_flash_pdata *f_pdata = nor->priv;
++ struct cqspi_st *cqspi = f_pdata->cqspi;
++
++ mutex_lock(&cqspi->bus_mutex);
++
++ return cqspi_prep_unlocked(nor, ops);
++}
++
++static void cqspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
++{
++ struct cqspi_flash_pdata *f_pdata = nor->priv;
++ struct cqspi_st *cqspi = f_pdata->cqspi;
++
++ mutex_unlock(&cqspi->bus_mutex);
++}
++
++static int cqspi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
++{
++ int ret;
++
++ ret = cqspi_set_protocol(nor, nor->reg_proto);
++ if (ret)
++ goto exit;
++
++ cqspi_prep_unlocked(nor, SPI_NOR_OPS_READ);
++
++ ret = cqspi_command_read(nor, &opcode, 1, buf, len);
++exit:
++ return ret;
++}
++
++static int cqspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
++{
++ int ret;
++
++ ret = cqspi_set_protocol(nor, nor->reg_proto);
++ if (ret)
++ goto exit;
++
++ cqspi_prep_unlocked(nor, SPI_NOR_OPS_WRITE);
++
++ ret = cqspi_command_write(nor, opcode, buf, len);
++exit:
++ return ret;
++}
++
++static int cqspi_of_get_flash_pdata(struct platform_device *pdev,
++ struct cqspi_flash_pdata *f_pdata,
++ struct device_node *np)
++{
++ if (of_property_read_u32(np, "cdns,read-delay", &f_pdata->read_delay)) {
++ dev_err(&pdev->dev, "couldn't determine read-delay\n");
++ return -ENXIO;
++ }
++
++ if (of_property_read_u32(np, "cdns,tshsl-ns", &f_pdata->tshsl_ns)) {
++ dev_err(&pdev->dev, "couldn't determine tshsl-ns\n");
++ return -ENXIO;
++ }
++
++ if (of_property_read_u32(np, "cdns,tsd2d-ns", &f_pdata->tsd2d_ns)) {
++ dev_err(&pdev->dev, "couldn't determine tsd2d-ns\n");
++ return -ENXIO;
++ }
++
++ if (of_property_read_u32(np, "cdns,tchsh-ns", &f_pdata->tchsh_ns)) {
++ dev_err(&pdev->dev, "couldn't determine tchsh-ns\n");
++ return -ENXIO;
++ }
++
++ if (of_property_read_u32(np, "cdns,tslch-ns", &f_pdata->tslch_ns)) {
++ dev_err(&pdev->dev, "couldn't determine tslch-ns\n");
++ return -ENXIO;
++ }
++
++ if (of_property_read_u32(np, "spi-max-frequency", &f_pdata->clk_rate)) {
++ dev_err(&pdev->dev, "couldn't determine spi-max-frequency\n");
++ return -ENXIO;
++ }
++
++ return 0;
++}
++
++static int cqspi_of_get_pdata(struct platform_device *pdev)
++{
++ struct device_node *np = pdev->dev.of_node;
++ struct cqspi_st *cqspi = platform_get_drvdata(pdev);
++
++ cqspi->is_decoded_cs = of_property_read_bool(np, "cdns,is-decoded-cs");
++
++ if (of_property_read_u32(np, "cdns,fifo-depth", &cqspi->fifo_depth)) {
++ dev_err(&pdev->dev, "couldn't determine fifo-depth\n");
++ return -ENXIO;
++ }
++
++ if (of_property_read_u32(np, "cdns,fifo-width", &cqspi->fifo_width)) {
++ dev_err(&pdev->dev, "couldn't determine fifo-width\n");
++ return -ENXIO;
++ }
++
++ if (of_property_read_u32(np, "cdns,trigger-address",
++ &cqspi->trigger_address)) {
++ dev_err(&pdev->dev, "couldn't determine trigger-address\n");
++ return -ENXIO;
++ }
++
++ return 0;
++}
++
++static void cqspi_controller_init(struct cqspi_st *cqspi)
++{
++ cqspi_controller_enable(cqspi, 0);
++
++ /* Configure the remap address register, no remap */
++ writel(0, cqspi->iobase + CQSPI_REG_REMAP);
++
++ /* Disable all interrupts. */
++ writel(0, cqspi->iobase + CQSPI_REG_IRQMASK);
++
++ /* Configure the SRAM split to 1:1 . */
++ writel(cqspi->fifo_depth / 2, cqspi->iobase + CQSPI_REG_SRAMPARTITION);
++
++ /* Load indirect trigger address. */
++ writel(cqspi->trigger_address,
++ cqspi->iobase + CQSPI_REG_INDIRECTTRIGGER);
++
++ /* Program read watermark -- 1/2 of the FIFO. */
++ writel(cqspi->fifo_depth * cqspi->fifo_width / 2,
++ cqspi->iobase + CQSPI_REG_INDIRECTRDWATERMARK);
++ /* Program write watermark -- 1/8 of the FIFO. */
++ writel(cqspi->fifo_depth * cqspi->fifo_width / 8,
++ cqspi->iobase + CQSPI_REG_INDIRECTWRWATERMARK);
++
++ cqspi_controller_enable(cqspi, 1);
++}
++
++static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np)
++{
++ struct platform_device *pdev = cqspi->pdev;
++ struct device *dev = &pdev->dev;
++ struct cqspi_flash_pdata *f_pdata;
++ struct spi_nor *nor;
++ struct mtd_info *mtd;
++ unsigned int cs;
++ int i, ret;
++
++ /* Get flash device data */
++ for_each_available_child_of_node(dev->of_node, np) {
++ if (of_property_read_u32(np, "reg", &cs)) {
++ dev_err(dev, "Couldn't determine chip select.\n");
++ goto err;
++ }
++
++ if (cs > CQSPI_MAX_CHIPSELECT) {
++ dev_err(dev, "Chip select %d out of range.\n", cs);
++ goto err;
++ }
++
++ f_pdata = &cqspi->f_pdata[cs];
++ f_pdata->cqspi = cqspi;
++ f_pdata->cs = cs;
++
++ ret = cqspi_of_get_flash_pdata(pdev, f_pdata, np);
++ if (ret)
++ goto err;
++
++ nor = &f_pdata->nor;
++ mtd = &nor->mtd;
++
++ mtd->priv = nor;
++
++ nor->dev = dev;
++ spi_nor_set_flash_node(nor, np);
++ nor->priv = f_pdata;
++
++ nor->read_reg = cqspi_read_reg;
++ nor->write_reg = cqspi_write_reg;
++ nor->read = cqspi_read;
++ nor->write = cqspi_write;
++ nor->erase = cqspi_erase;
++ nor->prepare = cqspi_prep;
++ nor->unprepare = cqspi_unprep;
++
++ mtd->name = kasprintf(GFP_KERNEL, "%s.%d", dev_name(dev), cs);
++ if (!mtd->name) {
++ ret = -ENOMEM;
++ goto err;
++ }
++
++ ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
++ if (ret)
++ goto err;
++
++ ret = mtd_device_register(mtd, NULL, 0);
++ if (ret)
++ goto err;
++ }
++
++ return 0;
++
++err:
++ for (i = 0; i < CQSPI_MAX_CHIPSELECT; i++)
++ if (cqspi->f_pdata[i].nor.mtd.name) {
++ mtd_device_unregister(&cqspi->f_pdata[i].nor.mtd);
++ kfree(cqspi->f_pdata[i].nor.mtd.name);
++ }
++ return ret;
++}
++
++static int cqspi_probe(struct platform_device *pdev)
++{
++ struct device_node *np = pdev->dev.of_node;
++ struct device *dev = &pdev->dev;
++ struct cqspi_st *cqspi;
++ struct resource *res;
++ struct resource *res_ahb;
++ int ret;
++ int irq;
++
++ cqspi = devm_kzalloc(dev, sizeof(*cqspi), GFP_KERNEL);
++ if (!cqspi)
++ return -ENOMEM;
++
++ mutex_init(&cqspi->bus_mutex);
++ cqspi->pdev = pdev;
++ platform_set_drvdata(pdev, cqspi);
++
++ /* Obtain configuration from OF. */
++ ret = cqspi_of_get_pdata(pdev);
++ if (ret) {
++ dev_err(dev, "Cannot get mandatory OF data.\n");
++ return -ENODEV;
++ }
++
++ /* Obtain QSPI clock. */
++ cqspi->clk = devm_clk_get(dev, NULL);
++ if (IS_ERR(cqspi->clk)) {
++ dev_err(dev, "Cannot claim QSPI clock.\n");
++ return PTR_ERR(cqspi->clk);
++ }
++
++ /* Obtain and remap controller address. */
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ cqspi->iobase = devm_ioremap_resource(dev, res);
++ if (IS_ERR(cqspi->iobase)) {
++ dev_err(dev, "Cannot remap controller address.\n");
++ return PTR_ERR(cqspi->iobase);
++ }
++
++ /* Obtain and remap AHB address. */
++ res_ahb = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++ cqspi->ahb_base = devm_ioremap_resource(dev, res_ahb);
++ if (IS_ERR(cqspi->ahb_base)) {
++ dev_err(dev, "Cannot remap AHB address.\n");
++ return PTR_ERR(cqspi->ahb_base);
++ }
++
++ init_completion(&cqspi->transfer_complete);
++
++ /* Obtain IRQ line. */
++ irq = platform_get_irq(pdev, 0);
++ if (irq < 0) {
++ dev_err(dev, "Cannot obtain IRQ.\n");
++ return -ENXIO;
++ }
++
++ ret = clk_prepare_enable(cqspi->clk);
++ if (ret) {
++ dev_err(dev, "Cannot enable QSPI clock.\n");
++ return ret;
++ }
++
++ cqspi->master_ref_clk_hz = clk_get_rate(cqspi->clk);
++
++ ret = devm_request_irq(dev, irq, cqspi_irq_handler, 0,
++ pdev->name, cqspi);
++ if (ret) {
++ dev_err(dev, "Cannot request IRQ.\n");
++ goto probe_irq_failed;
++ }
++
++ cqspi_wait_idle(cqspi);
++ cqspi_controller_init(cqspi);
++ cqspi->current_cs = -1;
++ cqspi->sclk = 0;
++
++ ret = cqspi_setup_flash(cqspi, np);
++ if (ret) {
++ dev_err(dev, "Cadence QSPI NOR probe failed %d\n", ret);
++ goto probe_setup_failed;
++ }
++
++ return ret;
++probe_irq_failed:
++ cqspi_controller_enable(cqspi, 0);
++probe_setup_failed:
++ clk_disable_unprepare(cqspi->clk);
++ return ret;
++}
++
++static int cqspi_remove(struct platform_device *pdev)
++{
++ struct cqspi_st *cqspi = platform_get_drvdata(pdev);
++ int i;
++
++ cqspi_controller_enable(cqspi, 0);
++
++ for (i = 0; i < CQSPI_MAX_CHIPSELECT; i++)
++ if (cqspi->f_pdata[i].nor.mtd.name) {
++ mtd_device_unregister(&cqspi->f_pdata[i].nor.mtd);
++ kfree(cqspi->f_pdata[i].nor.mtd.name);
++ }
++
++ clk_disable_unprepare(cqspi->clk);
++
++ return 0;
++}
++
++#ifdef CONFIG_PM_SLEEP
++static int cqspi_suspend(struct device *dev)
++{
++ struct cqspi_st *cqspi = dev_get_drvdata(dev);
++
++ cqspi_controller_enable(cqspi, 0);
++ return 0;
++}
++
++static int cqspi_resume(struct device *dev)
++{
++ struct cqspi_st *cqspi = dev_get_drvdata(dev);
++
++ cqspi_controller_enable(cqspi, 1);
++ return 0;
++}
++
++static const struct dev_pm_ops cqspi__dev_pm_ops = {
++ .suspend = cqspi_suspend,
++ .resume = cqspi_resume,
++};
++
++#define CQSPI_DEV_PM_OPS (&cqspi__dev_pm_ops)
++#else
++#define CQSPI_DEV_PM_OPS NULL
++#endif
++
++static struct of_device_id const cqspi_dt_ids[] = {
++ {.compatible = "cdns,qspi-nor",},
++ { /* end of table */ }
++};
++
++MODULE_DEVICE_TABLE(of, cqspi_dt_ids);
++
++static struct platform_driver cqspi_platform_driver = {
++ .probe = cqspi_probe,
++ .remove = cqspi_remove,
++ .driver = {
++ .name = CQSPI_NAME,
++ .pm = CQSPI_DEV_PM_OPS,
++ .of_match_table = cqspi_dt_ids,
++ },
++};
++
++module_platform_driver(cqspi_platform_driver);
++
++MODULE_DESCRIPTION("Cadence QSPI Controller Driver");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:" CQSPI_NAME);
++MODULE_AUTHOR("Ley Foon Tan <lftan@altera.com>");
++MODULE_AUTHOR("Graham Moore <grmoore@opensource.altera.com>");
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0032-ARM-socfpga-Add-Candence-QSPI-controller-DT-node.patch b/target/linux/socfpga/patches-4.4/0032-ARM-socfpga-Add-Candence-QSPI-controller-DT-node.patch
new file mode 100644
index 0000000000..e6b4ec7a44
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0032-ARM-socfpga-Add-Candence-QSPI-controller-DT-node.patch
@@ -0,0 +1,42 @@
+From 8abee0bfd7bc652e028e51e2b95cbb3bf42fc152 Mon Sep 17 00:00:00 2001
+From: Stefan Roese <sr@denx.de>
+Date: Wed, 20 May 2015 10:32:03 +0200
+Subject: [PATCH 32/33] ARM: socfpga: Add Candence QSPI controller DT node
+
+Now that the device driver is available, lets add the controller node
+to the socfpga dtsi. So that the SPI NOR flash can be used.
+
+Signed-off-by: Stefan Roese <sr@denx.de>
+Signed-off-by: Marek Vasut <marex@denx.de>
+---
+ arch/arm/boot/dts/socfpga.dtsi | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi
+index 3ed4abd..ebcd081 100644
+--- a/arch/arm/boot/dts/socfpga.dtsi
++++ b/arch/arm/boot/dts/socfpga.dtsi
+@@ -685,6 +685,20 @@
+ reg = <0xffff0000 0x10000>;
+ };
+
++ qspi: spi@ff705000 {
++ compatible = "cdns,qspi-nor";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0xff705000 0x1000>,
++ <0xffa00000 0x1000>;
++ interrupts = <0 151 4>;
++ clocks = <&qspi_clk>;
++ cdns,fifo-depth = <128>;
++ cdns,fifo-width = <4>;
++ cdns,trigger-address = <0x00000000>;
++ status = "disabled";
++ };
++
+ rst: rstmgr@ffd05000 {
+ #reset-cells = <1>;
+ compatible = "altr,rst-mgr";
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0033-ARM-socfpga-Enable-QSPI-flash-on-SoCKit.patch b/target/linux/socfpga/patches-4.4/0033-ARM-socfpga-Enable-QSPI-flash-on-SoCKit.patch
new file mode 100644
index 0000000000..f242d8cb72
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0033-ARM-socfpga-Enable-QSPI-flash-on-SoCKit.patch
@@ -0,0 +1,47 @@
+From 8c1cd66d13406533f9948dbcd25d4b53d389c109 Mon Sep 17 00:00:00 2001
+From: Marek Vasut <marex@denx.de>
+Date: Sun, 21 Jun 2015 23:00:06 +0200
+Subject: [PATCH 33/33] ARM: socfpga: Enable QSPI flash on SoCKit
+
+Add the QSPI NOR node on SoCkit.
+
+Signed-off-by: Marek Vasut <marex@denx.de>
+---
+ arch/arm/boot/dts/socfpga_cyclone5_sockit.dts | 21 +++++++++++++++++++++
+ 1 file changed, 21 insertions(+)
+
+diff --git a/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts b/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts
+index 02e22f5..d706348 100644
+--- a/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts
++++ b/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts
+@@ -175,6 +175,27 @@
+ status = "okay";
+ };
+
++&qspi {
++ status = "okay";
++
++ flash0: n25q00@0 {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ compatible = "n25q00";
++ reg = <0>; /* chip select */
++ spi-max-frequency = <100000000>;
++ m25p,fast-read;
++
++ cdns,page-size = <256>;
++ cdns,block-size = <16>;
++ cdns,read-delay = <4>;
++ cdns,tshsl-ns = <50>;
++ cdns,tsd2d-ns = <50>;
++ cdns,tchsh-ns = <4>;
++ cdns,tslch-ns = <4>;
++ };
++};
++
+ &usb1 {
+ status = "okay";
+ };
+--
+2.8.1
+
diff --git a/toolchain/binutils/Config.in b/toolchain/binutils/Config.in
index c32f43cdd4..2960c947d2 100644
--- a/toolchain/binutils/Config.in
+++ b/toolchain/binutils/Config.in
@@ -3,7 +3,7 @@
choice
prompt "Binutils Version" if TOOLCHAINOPTS
default BINUTILS_USE_VERSION_2_25_1 if !arc
- default BINUTILS_USE_VERSION_2_23_ARC if arc
+ default BINUTILS_USE_VERSION_2_26_ARC if arc
help
Select the version of binutils you wish to use.
@@ -17,10 +17,10 @@ choice
bool "Binutils 2.25.1"
select BINUTILS_VERSION_2_25_1
- config BINUTILS_USE_VERSION_2_23_ARC
+ config BINUTILS_USE_VERSION_2_26_ARC
depends on arc
- bool "ARC binutils 2.23"
- select BINUTILS_VERSION_2_23_ARC
+ bool "ARC binutils 2.26"
+ select BINUTILS_VERSION_2_26_ARC
endchoice
diff --git a/toolchain/binutils/Config.version b/toolchain/binutils/Config.version
index bea748b902..fc7a1f37c0 100644
--- a/toolchain/binutils/Config.version
+++ b/toolchain/binutils/Config.version
@@ -5,7 +5,7 @@ config BINUTILS_VERSION_2_25_1
default y if (!TOOLCHAINOPTS && !arc)
bool
-config BINUTILS_VERSION_2_23_ARC
+config BINUTILS_VERSION_2_26_ARC
default y if (!TOOLCHAINOPTS && arc)
bool
@@ -13,5 +13,5 @@ config BINUTILS_VERSION
string
default "2.24-linaro" if BINUTILS_VERSION_2_24_LINARO
default "2.25.1" if BINUTILS_VERSION_2_25_1
- default "arc-2015.06" if BINUTILS_VERSION_2_23_ARC
+ default "arc-2016.03" if BINUTILS_VERSION_2_26_ARC
diff --git a/toolchain/binutils/Makefile b/toolchain/binutils/Makefile
index c37148eedd..03fc76abdd 100644
--- a/toolchain/binutils/Makefile
+++ b/toolchain/binutils/Makefile
@@ -26,11 +26,11 @@ ifeq ($(findstring linaro, $(CONFIG_BINUTILS_VERSION)),linaro)
HOST_BUILD_DIR:=$(BUILD_DIR_TOOLCHAIN)/$(BINUTILS_DIR)
endif
-ifneq ($(CONFIG_BINUTILS_VERSION_2_23_ARC),)
- PKG_SOURCE_URL:=https://github.com/foss-for-synopsys-dwc-arc-processors/binutils-gdb/archive/arc-2015.06/
- PKG_REV:=2015.06
+ifneq ($(CONFIG_BINUTILS_VERSION_2_26_ARC),)
+ PKG_SOURCE_URL:=https://github.com/foss-for-synopsys-dwc-arc-processors/binutils-gdb/archive/arc-2016.03/
+ PKG_REV:=2016.03
PKG_SOURCE:=$(PKG_NAME)-arc-$(PKG_REV).tar.gz
- PKG_MD5SUM:=961a3564de857238c255c381f8e4360b
+ PKG_MD5SUM:=d4387bab089df77a8049c81980b9fa12
BINUTILS_DIR:=$(PKG_NAME)-gdb-arc-$(PKG_REV)
HOST_BUILD_DIR:=$(BUILD_DIR_TOOLCHAIN)/$(BINUTILS_DIR)
endif
diff --git a/toolchain/binutils/patches/arc-2016.03/200-arc-fix-target-mask.patch b/toolchain/binutils/patches/arc-2016.03/200-arc-fix-target-mask.patch
new file mode 100644
index 0000000000..7e51d588ae
--- /dev/null
+++ b/toolchain/binutils/patches/arc-2016.03/200-arc-fix-target-mask.patch
@@ -0,0 +1,13 @@
+diff --git a/bfd/config.bfd b/bfd/config.bfd
+index 5145d4a..a9c9c99 100644
+--- a/bfd/config.bfd
++++ b/bfd/config.bfd
+@@ -275,7 +275,7 @@ case "${targ}" in
+ targ_defvec=am33_elf32_linux_vec
+ ;;
+
+- arc*-*-elf* | arc*-*-linux-uclibc*)
++ arc*-*-elf* | arc*-*-linux-*)
+ targ_defvec=arc_elf32_le_vec
+ targ_selvecs=arc_elf32_be_vec
+ ;;
diff --git a/toolchain/gcc/Config.version b/toolchain/gcc/Config.version
index 5d393c54d0..f9e8c47c6f 100644
--- a/toolchain/gcc/Config.version
+++ b/toolchain/gcc/Config.version
@@ -5,7 +5,7 @@ config GCC_VERSION_4_8_ARC
config GCC_VERSION
string
default "4.8-linaro" if GCC_VERSION_4_8_LINARO
- default "arc-2015.06" if GCC_VERSION_4_8_ARC
+ default "arc-2016.03" if GCC_VERSION_4_8_ARC
default "5.3.0"
config GCC_VERSION_4_8
diff --git a/toolchain/gcc/common.mk b/toolchain/gcc/common.mk
index 3610d064b3..b6bafd1e58 100644
--- a/toolchain/gcc/common.mk
+++ b/toolchain/gcc/common.mk
@@ -33,11 +33,11 @@ ifeq ($(PKG_VERSION),5.3.0)
endif
ifneq ($(CONFIG_GCC_VERSION_4_8_ARC),)
- PKG_VERSION:=4.8.4
- PKG_SOURCE_URL:=https://github.com/foss-for-synopsys-dwc-arc-processors/gcc/archive/arc-2015.06
+ PKG_VERSION:=4.8.5
+ PKG_SOURCE_URL:=https://github.com/foss-for-synopsys-dwc-arc-processors/gcc/archive/arc-2016.03
PKG_SOURCE:=$(PKG_NAME)-$(GCC_VERSION).tar.gz
- PKG_MD5SUM:=25007ebb02a5f6c32532b103bb5984a0
- PKG_REV:=2015.06
+ PKG_MD5SUM:=ca59c8140d6efd07b97a18869bddbb53
+ PKG_REV:=2016.03
GCC_DIR:=gcc-arc-$(PKG_REV)
HOST_BUILD_DIR = $(BUILD_DIR_HOST)/$(PKG_NAME)-$(GCC_VERSION)
endif
diff --git a/toolchain/gcc/patches/arc-2015.06/001-revert_register_mode_search.patch b/toolchain/gcc/patches/arc-2016.03/001-revert_register_mode_search.patch
index 162d651394..162d651394 100644
--- a/toolchain/gcc/patches/arc-2015.06/001-revert_register_mode_search.patch
+++ b/toolchain/gcc/patches/arc-2016.03/001-revert_register_mode_search.patch
diff --git a/toolchain/gcc/patches/arc-2015.06/002-weak_data_fix.patch b/toolchain/gcc/patches/arc-2016.03/002-weak_data_fix.patch
index a740b4ce9e..a740b4ce9e 100644
--- a/toolchain/gcc/patches/arc-2015.06/002-weak_data_fix.patch
+++ b/toolchain/gcc/patches/arc-2016.03/002-weak_data_fix.patch
diff --git a/toolchain/gcc/patches/arc-2015.06/003-universal_initializer.patch b/toolchain/gcc/patches/arc-2016.03/003-universal_initializer.patch
index 1b9a5b3081..1b9a5b3081 100644
--- a/toolchain/gcc/patches/arc-2015.06/003-universal_initializer.patch
+++ b/toolchain/gcc/patches/arc-2016.03/003-universal_initializer.patch
diff --git a/toolchain/gcc/patches/arc-2015.06/004-case_insensitive.patch b/toolchain/gcc/patches/arc-2016.03/004-case_insensitive.patch
index b3d2dbe291..b3d2dbe291 100644
--- a/toolchain/gcc/patches/arc-2015.06/004-case_insensitive.patch
+++ b/toolchain/gcc/patches/arc-2016.03/004-case_insensitive.patch
diff --git a/toolchain/gcc/patches/arc-2015.06/010-documentation.patch b/toolchain/gcc/patches/arc-2016.03/010-documentation.patch
index 5548069d1b..5548069d1b 100644
--- a/toolchain/gcc/patches/arc-2015.06/010-documentation.patch
+++ b/toolchain/gcc/patches/arc-2016.03/010-documentation.patch
diff --git a/toolchain/gcc/patches/arc-2015.06/020-no-plt-backport.patch b/toolchain/gcc/patches/arc-2016.03/020-no-plt-backport.patch
index b225376865..b225376865 100644
--- a/toolchain/gcc/patches/arc-2015.06/020-no-plt-backport.patch
+++ b/toolchain/gcc/patches/arc-2016.03/020-no-plt-backport.patch
diff --git a/toolchain/gcc/patches/arc-2015.06/100-uclibc-conf.patch b/toolchain/gcc/patches/arc-2016.03/100-uclibc-conf.patch
index ff9ad94f62..ff9ad94f62 100644
--- a/toolchain/gcc/patches/arc-2015.06/100-uclibc-conf.patch
+++ b/toolchain/gcc/patches/arc-2016.03/100-uclibc-conf.patch
diff --git a/toolchain/gcc/patches/arc-2015.06/210-disable_libsanitizer_off_t_check.patch b/toolchain/gcc/patches/arc-2016.03/210-disable_libsanitizer_off_t_check.patch
index 56084692a1..56084692a1 100644
--- a/toolchain/gcc/patches/arc-2015.06/210-disable_libsanitizer_off_t_check.patch
+++ b/toolchain/gcc/patches/arc-2016.03/210-disable_libsanitizer_off_t_check.patch
diff --git a/toolchain/gcc/patches/arc-2015.06/800-arc-disablelibgmon.patch b/toolchain/gcc/patches/arc-2016.03/800-arc-disablelibgmon.patch
index 612883c98c..612883c98c 100644
--- a/toolchain/gcc/patches/arc-2015.06/800-arc-disablelibgmon.patch
+++ b/toolchain/gcc/patches/arc-2016.03/800-arc-disablelibgmon.patch
diff --git a/toolchain/gcc/patches/arc-2015.06/820-libgcc_pic.patch b/toolchain/gcc/patches/arc-2016.03/820-libgcc_pic.patch
index 7a0ac7353e..7a0ac7353e 100644
--- a/toolchain/gcc/patches/arc-2015.06/820-libgcc_pic.patch
+++ b/toolchain/gcc/patches/arc-2016.03/820-libgcc_pic.patch
diff --git a/toolchain/gcc/patches/arc-2015.06/850-use_shared_libgcc.patch b/toolchain/gcc/patches/arc-2016.03/850-use_shared_libgcc.patch
index 6934bc97f6..6934bc97f6 100644
--- a/toolchain/gcc/patches/arc-2015.06/850-use_shared_libgcc.patch
+++ b/toolchain/gcc/patches/arc-2016.03/850-use_shared_libgcc.patch
diff --git a/toolchain/gcc/patches/arc-2015.06/851-libgcc_no_compat.patch b/toolchain/gcc/patches/arc-2016.03/851-libgcc_no_compat.patch
index 80c3476841..80c3476841 100644
--- a/toolchain/gcc/patches/arc-2015.06/851-libgcc_no_compat.patch
+++ b/toolchain/gcc/patches/arc-2016.03/851-libgcc_no_compat.patch
diff --git a/toolchain/gcc/patches/arc-2015.06/860-use_eh_frame.patch b/toolchain/gcc/patches/arc-2016.03/860-use_eh_frame.patch
index 1ac83fe4dc..1ac83fe4dc 100644
--- a/toolchain/gcc/patches/arc-2015.06/860-use_eh_frame.patch
+++ b/toolchain/gcc/patches/arc-2016.03/860-use_eh_frame.patch
diff --git a/toolchain/gcc/patches/arc-2015.06/870-ppc_no_crtsavres.patch b/toolchain/gcc/patches/arc-2016.03/870-ppc_no_crtsavres.patch
index 4b7fcbd5e1..4b7fcbd5e1 100644
--- a/toolchain/gcc/patches/arc-2015.06/870-ppc_no_crtsavres.patch
+++ b/toolchain/gcc/patches/arc-2016.03/870-ppc_no_crtsavres.patch
diff --git a/toolchain/gcc/patches/arc-2015.06/880-no_java_section.patch b/toolchain/gcc/patches/arc-2016.03/880-no_java_section.patch
index def6c9f4a0..def6c9f4a0 100644
--- a/toolchain/gcc/patches/arc-2015.06/880-no_java_section.patch
+++ b/toolchain/gcc/patches/arc-2016.03/880-no_java_section.patch
diff --git a/toolchain/gcc/patches/arc-2015.06/910-mbsd_multi.patch b/toolchain/gcc/patches/arc-2016.03/910-mbsd_multi.patch
index 5387f8e86f..5387f8e86f 100644
--- a/toolchain/gcc/patches/arc-2015.06/910-mbsd_multi.patch
+++ b/toolchain/gcc/patches/arc-2016.03/910-mbsd_multi.patch
diff --git a/toolchain/gcc/patches/arc-2015.06/920-specs_nonfatal_getenv.patch b/toolchain/gcc/patches/arc-2016.03/920-specs_nonfatal_getenv.patch
index 09768f525b..09768f525b 100644
--- a/toolchain/gcc/patches/arc-2015.06/920-specs_nonfatal_getenv.patch
+++ b/toolchain/gcc/patches/arc-2016.03/920-specs_nonfatal_getenv.patch
diff --git a/toolchain/gcc/patches/arc-2015.06/940-no-clobber-stamp-bits.patch b/toolchain/gcc/patches/arc-2016.03/940-no-clobber-stamp-bits.patch
index dbecef2d57..dbecef2d57 100644
--- a/toolchain/gcc/patches/arc-2015.06/940-no-clobber-stamp-bits.patch
+++ b/toolchain/gcc/patches/arc-2016.03/940-no-clobber-stamp-bits.patch
diff --git a/toolchain/gdb/Makefile b/toolchain/gdb/Makefile
index 0e1b0a27bc..97d88d65a6 100644
--- a/toolchain/gdb/Makefile
+++ b/toolchain/gdb/Makefile
@@ -9,11 +9,11 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=gdb
ifeq ($(CONFIG_arc),y)
-PKG_VERSION:=arc-2015.06-gdb
+PKG_VERSION:=arc-2016.03-gdb
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
-PKG_SOURCE_URL:=https://github.com/foss-for-synopsys-dwc-arc-processors/binutils-gdb/archive/arc-2015.06-gdb/
-PKG_MD5SUM:=d318829bfd2ed62714817f0d25706825
+PKG_SOURCE_URL:=https://github.com/foss-for-synopsys-dwc-arc-processors/binutils-gdb/archive/arc-2016.03-gdb
+PKG_MD5SUM:=775caaf6385c16f20b6f53c0a2b95f79
GDB_DIR:=binutils-$(PKG_NAME)-$(PKG_VERSION)
else
PKG_VERSION:=7.11
diff --git a/toolchain/gdb/patches/arc-2015.06-gdb/100-no_extern_inline.patch b/toolchain/gdb/patches/arc-2015.06-gdb/100-no_extern_inline.patch
deleted file mode 100644
index bbae1d774d..0000000000
--- a/toolchain/gdb/patches/arc-2015.06-gdb/100-no_extern_inline.patch
+++ /dev/null
@@ -1,32 +0,0 @@
---- a/sim/common/sim-arange.c
-+++ b/sim/common/sim-arange.c
-@@ -280,11 +280,7 @@ sim_addr_range_delete (ADDR_RANGE *ar, a
- build_search_tree (ar);
- }
-
--#endif /* DEFINE_NON_INLINE_P */
--
--#if DEFINE_INLINE_P
--
--SIM_ARANGE_INLINE int
-+int
- sim_addr_range_hit_p (ADDR_RANGE *ar, address_word addr)
- {
- ADDR_RANGE_TREE *t = ar->range_tree;
-@@ -301,4 +297,4 @@ sim_addr_range_hit_p (ADDR_RANGE *ar, ad
- return 0;
- }
-
--#endif /* DEFINE_INLINE_P */
-+#endif /* DEFINE_NON_INLINE_P */
---- a/sim/common/sim-arange.h
-+++ b/sim/common/sim-arange.h
-@@ -62,7 +62,7 @@ extern void sim_addr_range_delete (ADDR_
-
- /* Return non-zero if ADDR is in range AR, traversing the entire tree.
- If no range is specified, that is defined to mean "everything". */
--extern INLINE int
-+extern int
- sim_addr_range_hit_p (ADDR_RANGE * /*ar*/, address_word /*addr*/);
- #define ADDR_RANGE_HIT_P(ar, addr) \
- ((ar)->range_tree == NULL || sim_addr_range_hit_p ((ar), (addr)))
diff --git a/toolchain/gdb/patches/arc-2015.06-gdb/110-no_testsuite.patch b/toolchain/gdb/patches/arc-2015.06-gdb/110-no_testsuite.patch
deleted file mode 100644
index 5c5d15c5b8..0000000000
--- a/toolchain/gdb/patches/arc-2015.06-gdb/110-no_testsuite.patch
+++ /dev/null
@@ -1,21 +0,0 @@
---- a/gdb/configure
-+++ b/gdb/configure
-@@ -855,8 +855,7 @@ MAKEINFOFLAGS
- YACC
- YFLAGS
- XMKMF'
--ac_subdirs_all='testsuite
--gdbtk
-+ac_subdirs_all='gdbtk
- multi-ice
- gdbserver'
-
-@@ -5168,7 +5167,7 @@ $as_echo "$with_auto_load_safe_path" >&6
-
-
-
--subdirs="$subdirs testsuite"
-+subdirs="$subdirs"
-
-
- # Check whether to support alternative target configurations
diff --git a/toolchain/gdb/patches/arc-2015.06-gdb/120-fix-compile-flag-mismatch.patch b/toolchain/gdb/patches/arc-2015.06-gdb/120-fix-compile-flag-mismatch.patch
deleted file mode 100644
index ce34c95b19..0000000000
--- a/toolchain/gdb/patches/arc-2015.06-gdb/120-fix-compile-flag-mismatch.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- a/gdb/gdbserver/configure
-+++ b/gdb/gdbserver/configure
-@@ -2183,7 +2183,7 @@ $as_echo "$as_me: error: \`$ac_var' was
- ac_cache_corrupted=: ;;
- ,);;
- *)
-- if test "x$ac_old_val" != "x$ac_new_val"; then
-+ if test "`echo x$ac_old_val`" != "`echo x$ac_new_val`"; then
- # differences in whitespace do not lead to failure.
- ac_old_val_w=`echo x $ac_old_val`
- ac_new_val_w=`echo x $ac_new_val`
diff --git a/toolchain/gdb/patches/arc-2016.03-gdb/100-no_extern_inline.patch b/toolchain/gdb/patches/arc-2016.03-gdb/100-no_extern_inline.patch
new file mode 100644
index 0000000000..8c18c6e2e7
--- /dev/null
+++ b/toolchain/gdb/patches/arc-2016.03-gdb/100-no_extern_inline.patch
@@ -0,0 +1,32 @@
+--- a/sim/common/sim-arange.c
++++ b/sim/common/sim-arange.c
+@@ -280,11 +280,7 @@ sim_addr_range_delete (ADDR_RANGE *ar, a
+ build_search_tree (ar);
+ }
+
+-#endif /* DEFINE_NON_INLINE_P */
+-
+-#if DEFINE_INLINE_P
+-
+-SIM_ARANGE_INLINE int
++int
+ sim_addr_range_hit_p (ADDR_RANGE *ar, address_word addr)
+ {
+ ADDR_RANGE_TREE *t = ar->range_tree;
+@@ -301,4 +297,4 @@ sim_addr_range_hit_p (ADDR_RANGE *ar, ad
+ return 0;
+ }
+
+-#endif /* DEFINE_INLINE_P */
++#endif /* DEFINE_NON_INLINE_P */
+--- a/sim/common/sim-arange.h
++++ b/sim/common/sim-arange.h
+@@ -73,7 +73,7 @@ extern void sim_addr_range_delete (ADDR_
+
+ /* Return non-zero if ADDR is in range AR, traversing the entire tree.
+ If no range is specified, that is defined to mean "everything". */
+-SIM_ARANGE_INLINE int
++extern int
+ sim_addr_range_hit_p (ADDR_RANGE * /*ar*/, address_word /*addr*/);
+ #define ADDR_RANGE_HIT_P(ar, addr) \
+ ((ar)->range_tree == NULL || sim_addr_range_hit_p ((ar), (addr)))
diff --git a/toolchain/gdb/patches/arc-2016.03-gdb/110-no_testsuite.patch b/toolchain/gdb/patches/arc-2016.03-gdb/110-no_testsuite.patch
new file mode 100644
index 0000000000..1b284ea767
--- /dev/null
+++ b/toolchain/gdb/patches/arc-2016.03-gdb/110-no_testsuite.patch
@@ -0,0 +1,21 @@
+--- a/gdb/configure
++++ b/gdb/configure
+@@ -870,8 +870,7 @@ MAKEINFOFLAGS
+ YACC
+ YFLAGS
+ XMKMF'
+-ac_subdirs_all='testsuite
+-gdbtk
++ac_subdirs_all='gdbtk
+ multi-ice
+ gdbserver'
+
+@@ -5610,7 +5610,7 @@ $as_echo "$with_auto_load_safe_path" >&6
+
+
+
+-subdirs="$subdirs testsuite"
++subdirs="$subdirs"
+
+
+ # Check whether to support alternative target configurations
diff --git a/toolchain/gdb/patches/arc-2016.03-gdb/120-fix-compile-flag-mismatch.patch b/toolchain/gdb/patches/arc-2016.03-gdb/120-fix-compile-flag-mismatch.patch
new file mode 100644
index 0000000000..c8b41f264a
--- /dev/null
+++ b/toolchain/gdb/patches/arc-2016.03-gdb/120-fix-compile-flag-mismatch.patch
@@ -0,0 +1,11 @@
+--- a/gdb/gdbserver/configure
++++ b/gdb/gdbserver/configure
+@@ -2468,7 +2468,7 @@ $as_echo "$as_me: error: \`$ac_var' was
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+- if test "x$ac_old_val" != "x$ac_new_val"; then
++ if test "`echo x$ac_old_val`" != "`echo x$ac_new_val`"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
diff --git a/tools/cmake/Makefile b/tools/cmake/Makefile
index 3cbc09ea15..da62f70745 100644
--- a/tools/cmake/Makefile
+++ b/tools/cmake/Makefile
@@ -7,12 +7,12 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=cmake
-PKG_VERSION:=3.5.1
+PKG_VERSION:=3.5.2
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://cmake.org/files/v3.5/ \
https://fossies.org/linux/misc/
-PKG_MD5SUM:=ca051f4a66375c89d1a524e726da0296
+PKG_MD5SUM:=701386a1b5ec95f8d1075ecf96383e02
HOST_BUILD_PARALLEL:=1
HOST_CONFIGURE_PARALLEL:=1