Browse Source

mediatek: update to latest kernel patchset from v4.13-rc

Signed-off-by: Muciri Gatimu <[email protected]>
Signed-off-by: Shashidhar Lakkavalli <[email protected]>
Signed-off-by: John Crispin <[email protected]>
John Crispin 8 years ago
parent
commit
1f068588ef
92 changed files with 10641 additions and 599 deletions
  1. 1 0
      target/linux/mediatek/base-files/etc/board.d/02_network
  2. 60 0
      target/linux/mediatek/base-files/etc/config/mtkhnat
  3. 13 0
      target/linux/mediatek/base-files/etc/init.d/mtkhnat
  4. 9 0
      target/linux/mediatek/base-files/etc/uci-defaults/99-firewall
  5. 16 0
      target/linux/mediatek/base-files/etc/uci-defaults/99-net-ps
  6. 8 0
      target/linux/mediatek/base-files/lib/preinit/06_set_rps_sock_flow
  7. 1 0
      target/linux/mediatek/base-files/lib/upgrade/platform.sh
  8. 64 0
      target/linux/mediatek/base-files/sbin/mtkhnat
  9. 23 3
      target/linux/mediatek/config-4.9
  10. 167 2
      target/linux/mediatek/files/arch/arm/boot/dts/_mt7623.dtsi
  11. 241 0
      target/linux/mediatek/files/arch/arm/boot/dts/mt6323.dtsi
  12. 0 7
      target/linux/mediatek/files/arch/arm/boot/dts/mt7623-NAND-ePHY.dts
  13. 0 7
      target/linux/mediatek/files/arch/arm/boot/dts/mt7623-NAND.dts
  14. 55 54
      target/linux/mediatek/files/arch/arm/boot/dts/mt7623-eMMC.dts
  15. 443 0
      target/linux/mediatek/files/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts
  16. 168 0
      target/linux/mediatek/files/drivers/char/hw_random/mtk-rng.c
  17. 2 0
      target/linux/mediatek/files/drivers/crypto/mediatek/Makefile
  18. 1304 0
      target/linux/mediatek/files/drivers/crypto/mediatek/mtk-aes.c
  19. 607 0
      target/linux/mediatek/files/drivers/crypto/mediatek/mtk-platform.c
  20. 237 0
      target/linux/mediatek/files/drivers/crypto/mediatek/mtk-platform.h
  21. 194 0
      target/linux/mediatek/files/drivers/crypto/mediatek/mtk-regs.h
  22. 1358 0
      target/linux/mediatek/files/drivers/crypto/mediatek/mtk-sha.c
  23. 12 10
      target/linux/mediatek/image/32.mk
  24. 14 0
      target/linux/mediatek/modules.mk
  25. 0 26
      target/linux/mediatek/patches-4.9/0000-pinctrl-esw.patch
  26. 0 53
      target/linux/mediatek/patches-4.9/0001-NET-multi-phy-support.patch
  27. 23 0
      target/linux/mediatek/patches-4.9/0001-arch-arm-add-dts-build-code.patch
  28. 3 3
      target/linux/mediatek/patches-4.9/0002-dt-bindings-add-MediaTek-PCIe-binding-documentation.patch
  29. 7 7
      target/linux/mediatek/patches-4.9/0003-PCI-mediatek-add-support-for-PCIe-found-on-MT7623-MT.patch
  30. 5 5
      target/linux/mediatek/patches-4.9/0004-soc-mediatek-Add-MT2701-power-dt-bindings.patch
  31. 2 2
      target/linux/mediatek/patches-4.9/0005-clk-mediatek-Add-MT2701-clock-support.patch
  32. 3 3
      target/linux/mediatek/patches-4.9/0006-reset-mediatek-mt2701-reset-driver.patch
  33. 4 4
      target/linux/mediatek/patches-4.9/0007-ARM-mediatek-Add-MT2701-config-options-for-mediatek-.patch
  34. 3 2
      target/linux/mediatek/patches-4.9/0008-soc-mediatek-Refine-scpsys-to-support-multiple-platf.patch
  35. 4 4
      target/linux/mediatek/patches-4.9/0009-soc-mediatek-Add-MT2701-scpsys-driver.patch
  36. 4 5
      target/linux/mediatek/patches-4.9/0010-clk-add-hifsys-reset.patch
  37. 4 6
      target/linux/mediatek/patches-4.9/0011-scpsys-various-fixes.patch
  38. 3 3
      target/linux/mediatek/patches-4.9/0012-clk-dont-disable-unused-clocks.patch
  39. 3 3
      target/linux/mediatek/patches-4.9/0013-clk-mediatek-enable-critical-clocks.patch
  40. 10 10
      target/linux/mediatek/patches-4.9/0014-clk-mediatek-Export-CPU-mux-clocks-for-CPU-frequency.patch
  41. 5 5
      target/linux/mediatek/patches-4.9/0015-cpufreq-mediatek-add-driver.patch
  42. 6 8
      target/linux/mediatek/patches-4.9/0016-pwm-add-pwm-mediatek.patch
  43. 27 0
      target/linux/mediatek/patches-4.9/0017-mfd-mt6397-Add-MT6323-LED-support-into-MT6397-driver.patch
  44. 4 17
      target/linux/mediatek/patches-4.9/0018-dt-bindings-leds-Add-document-bindings-for-leds-mt63.patch
  45. 24 0
      target/linux/mediatek/patches-4.9/0019-dt-bindings-mfd-Add-the-description-for-LED-as-the-s.patch
  46. 4 19
      target/linux/mediatek/patches-4.9/0020-leds-Add-LED-support-for-MT6323-PMIC.patch
  47. 27 0
      target/linux/mediatek/patches-4.9/0021-mfd-mt6397-Align-the-placement-at-which-the-mfd_cell.patch
  48. 10 0
      target/linux/mediatek/patches-4.9/0022-nand-make-bootrom-work-with-upstream-driver.patch
  49. 81 0
      target/linux/mediatek/patches-4.9/0023-rng-add-mediatek-hw-rng.patch
  50. 1034 0
      target/linux/mediatek/patches-4.9/0024-media-rc-add-driver-for-IR-remote-receiver-on-MT7623.patch
  51. 3 17
      target/linux/mediatek/patches-4.9/0025-dt-bindings-net-dsa-add-Mediatek-MT7530-binding.patch
  52. 1788 0
      target/linux/mediatek/patches-4.9/0026-net-mediatek-backport-v4.10-driver.patch
  53. 9 9
      target/linux/mediatek/patches-4.9/0027-net-next-mediatek-fix-DQL-support.patch
  54. 3 17
      target/linux/mediatek/patches-4.9/0028-net-next-dsa-add-Mediatek-tag-RX-TX-handler.patch
  55. 10 25
      target/linux/mediatek/patches-4.9/0029-net-next-ethernet-mediatek-add-CDM-able-to-recognize.patch
  56. 4 18
      target/linux/mediatek/patches-4.9/0030-net-next-dsa-add-dsa-support-for-Mediatek-MT7530-swi.patch
  57. 14 0
      target/linux/mediatek/patches-4.9/0031-net-dsa-dsa-api-compat.patch
  58. 12 0
      target/linux/mediatek/patches-4.9/0032-net-dsa-mediatek-add-support-for-GMAC2-wired-to-ext-.patch
  59. 14 0
      target/linux/mediatek/patches-4.9/0033-net-dsa-add-multi-gmac-support.patch
  60. 10 0
      target/linux/mediatek/patches-4.9/0034-net-dsa-mediatek-add-dual-gmac-support.patch
  61. 47 0
      target/linux/mediatek/patches-4.9/0035-net-mediatek-disable-RX-VLan-offloading.patch
  62. 25 0
      target/linux/mediatek/patches-4.9/0036-net-next-mediatek-fix-typos-inside-the-header-file.patch
  63. 128 0
      target/linux/mediatek/patches-4.9/0037-net-next-mediatek-bring-up-QDMA-RX-ring-0.patch
  64. 46 0
      target/linux/mediatek/patches-4.9/0038-net-next-dsa-move-struct-dsa_device_ops-to-the-globa.patch
  65. 32 0
      target/linux/mediatek/patches-4.9/0039-net-next-dsa-add-flow_dissect-callback-to-struct-dsa.patch
  66. 39 0
      target/linux/mediatek/patches-4.9/0040-net-next-tag_mtk-add-flow_dissect-callback-to-the-op.patch
  67. 65 0
      target/linux/mediatek/patches-4.9/0041-net-next-dsa-fix-flow-dissection.patch
  68. 50 0
      target/linux/mediatek/patches-4.9/0042-net-next-mediatek-honour-special-tag-bit-inside-RX-D.patch
  69. 41 0
      target/linux/mediatek/patches-4.9/0043-net-next-mediatek-enable-special-tag-indication-for-.patch
  70. 43 0
      target/linux/mediatek/patches-4.9/0044-net-next-dsa-mediatek-tell-GDMA-when-we-are-turning-.patch
  71. 79 0
      target/linux/mediatek/patches-4.9/0045-net-dsa-mediatek-turn-into-platform-driver.patch
  72. 56 0
      target/linux/mediatek/patches-4.9/0046-net-mediatek-add-irq-delay.patch
  73. 208 0
      target/linux/mediatek/patches-4.9/0047-net-next-mediatek-split-IRQ-register-locking-into-TX.patch
  74. 90 0
      target/linux/mediatek/patches-4.9/0048-net-core-add-RPS-balancer.patch
  75. 20 0
      target/linux/mediatek/patches-4.9/0049-net-mediatek-add-rx-queue.patch
  76. 21 0
      target/linux/mediatek/patches-4.9/0050-net-mediatek-add-trgmii-clock.patch
  77. 21 0
      target/linux/mediatek/patches-4.9/0051-net-mediatek-increase-tx_timeout.patch
  78. 21 0
      target/linux/mediatek/patches-4.9/0052-net-phy-add-FC.patch
  79. 68 0
      target/linux/mediatek/patches-4.9/0053-net-dsa-mediatek-add-software-phy-polling.patch
  80. 105 0
      target/linux/mediatek/patches-4.9/0054-net-ethernet-mediatek-fixed-deadlock-captured-by-loc.patch
  81. 31 0
      target/linux/mediatek/patches-4.9/0055-net-ethernet-mediatek-avoid-potential-invalid-memory.patch
  82. 119 0
      target/linux/mediatek/patches-4.9/0056-net-mediatek-add-hw-nat-support.patch
  83. 121 0
      target/linux/mediatek/patches-4.9/0057-net-mediatek-add-HW-QoS-support.patch
  84. 470 0
      target/linux/mediatek/patches-4.9/0058-pinctrl-update.patch
  85. 531 0
      target/linux/mediatek/patches-4.9/0059-eth-fixes.patch
  86. 0 41
      target/linux/mediatek/patches-4.9/0083-mfd-led3.patch
  87. 0 38
      target/linux/mediatek/patches-4.9/0086-pmic-led1.patch
  88. 0 42
      target/linux/mediatek/patches-4.9/0088-pmic-led3.patch
  89. 0 44
      target/linux/mediatek/patches-4.9/0092-dsa4.patch
  90. 0 36
      target/linux/mediatek/patches-4.9/0094-net-affinity.patch
  91. 0 12
      target/linux/mediatek/patches-4.9/0200-devicetree.patch
  92. 0 32
      target/linux/mediatek/patches-4.9/0201-block2mtd.patch

+ 1 - 0
target/linux/mediatek/base-files/etc/board.d/02_network

@@ -9,6 +9,7 @@ mediatek_setup_interfaces()
 	local board="$1"
 	local board="$1"
 
 
 	case $board in
 	case $board in
+	'bananapi,bpi-r2' | \
 	'mediatek,mt7623-rfb-emmc' | \
 	'mediatek,mt7623-rfb-emmc' | \
 	'mediatek,mt7623-rfb-nand-ephy')
 	'mediatek,mt7623-rfb-nand-ephy')
 		ucidef_set_interface_lan "lan0 lan1 lan2 lan3"
 		ucidef_set_interface_lan "lan0 lan1 lan2 lan3"

+ 60 - 0
target/linux/mediatek/base-files/etc/config/mtkhnat

@@ -0,0 +1,60 @@
+config global global
+	option enable 0
+	option upstream 1000000
+	option downstream 1000000
+
+config queue
+	option id 0
+	option minrate 10
+	option maxrate 50
+	option weight 7
+	option resv 32
+
+config queue
+	option id 1
+	option minrate 30
+	option maxrate 100
+	option weight 7
+	option resv 32
+
+config queue
+	option id 2
+	option minrate 30
+	option maxrate 100
+	option weight 7
+	option resv 32
+
+config queue
+	option id 3
+	option minrate 30
+	option maxrate 100
+	option weight 7
+	option resv 32
+
+config queue
+	option id 4
+	option minrate 25
+	option maxrate 100
+	option weight 7
+	option resv 32
+
+config queue
+	option id 5
+	option minrate 25
+	option maxrate 100
+	option weight 7
+	option resv 32
+
+config queue
+	option id 6
+	option minrate 25
+	option maxrate 100
+	option weight 7
+	option resv 32
+
+config queue
+	option id 7
+	option minrate 25
+	option maxrate 100
+	option weight 7
+	option resv 32

+ 13 - 0
target/linux/mediatek/base-files/etc/init.d/mtkhnat

@@ -0,0 +1,13 @@
+#!/bin/sh /etc/rc.common
+
+START=90
+
+USE_PROCD=1
+NAME=mtkhnat
+PROG=/sbin/mtkhnat
+
+start_service() {
+	procd_open_instance
+	procd_set_param command "${PROG}"
+	procd_close_instance
+}

+ 9 - 0
target/linux/mediatek/base-files/etc/uci-defaults/99-firewall

@@ -0,0 +1,9 @@
+echo "iptables -t mangle -A FORWARD -i br-lan -o eth1 -p tcp -m mark --mark 0/0x7 -j MARK --set-mark 4/0x7" >> /etc/firewall.user
+echo "iptables -t mangle -A FORWARD -i br-lan -o eth1 -p udp -m mark --mark 0/0x7 -j MARK --set-mark 5/0x7" >> /etc/firewall.user
+echo "iptables -t mangle -A FORWARD -i eth1 -o br-lan -p tcp -m mark --mark 0/0x7 -j MARK --set-mark 4/0x7" >> /etc/firewall.user
+echo "iptables -t mangle -A FORWARD -i eth1 -o br-lan -p udp -m mark --mark 0/0x7 -j MARK --set-mark 5/0x7" >> /etc/firewall.user
+
+echo "iptables -t mangle -A FORWARD -p udp -m mark --mark 0/0xf8 -j MARK --or-mark 0x60" >> /etc/firewall.user
+echo "iptables -t mangle -A FORWARD -p tcp -m mark --mark 0/0xf8 -j MARK --or-mark 0xc0" >> /etc/firewall.user
+
+exit 0

+ 16 - 0
target/linux/mediatek/base-files/etc/uci-defaults/99-net-ps

@@ -0,0 +1,16 @@
+uci set network.globals.default_rps_val=14
+uci set network.globals.default_rps_flow_cnt=256
+uci set network.globals.default_xps_val=14
+uci set network.globals.default_ps=1
+uci set network.eth0=device
+uci set network.eth0.name=eth0
+uci set network.lan0=device
+uci set network.lan0.name=lan0
+uci set network.lan1=device
+uci set network.lan1.name=lan1
+uci set network.lan2=device
+uci set network.lan2.name=lan2
+uci set network.lan3=device
+uci set network.lan3.name=lan3
+uci commit
+exit 0

+ 8 - 0
target/linux/mediatek/base-files/lib/preinit/06_set_rps_sock_flow

@@ -0,0 +1,8 @@
+#!/bin/sh
+
+set_rps_sock_flow() {
+	echo 1024 > /proc/sys/net/core/rps_sock_flow_entries
+}
+
+boot_hook_add preinit_main set_rps_sock_flow
+

+ 1 - 0
target/linux/mediatek/base-files/lib/upgrade/platform.sh

@@ -25,6 +25,7 @@ platform_check_image() {
 		nand_do_platform_check $board $1
 		nand_do_platform_check $board $1
 		return $?
 		return $?
 		;;
 		;;
+	bananapi,bpi-r2 |\
 	mediatek,mt7623-rfb-emmc)
 	mediatek,mt7623-rfb-emmc)
 		local kernel_length=`(tar xf $tar_file sysupgrade-$board/kernel -O | wc -c) 2> /dev/null`
 		local kernel_length=`(tar xf $tar_file sysupgrade-$board/kernel -O | wc -c) 2> /dev/null`
 		local rootfs_length=`(tar xf $tar_file sysupgrade-$board/root -O | wc -c) 2> /dev/null`
 		local rootfs_length=`(tar xf $tar_file sysupgrade-$board/root -O | wc -c) 2> /dev/null`

+ 64 - 0
target/linux/mediatek/base-files/sbin/mtkhnat

@@ -0,0 +1,64 @@
+#!/bin/sh
+
+. /lib/functions.sh
+
+config_load mtkhnat
+config_get enable global enable 0
+
+[ "${enable}" -eq 1 ] || {
+	echo 0 ${sch_upstream} > /sys/kernel/debug/hnat/scheduler0
+	echo 0 ${sch_downstream} > /sys/kernel/debug/hnat/scheduler1
+
+	rmmod mtkhnat
+	exit 0
+}
+
+insmod mtkhnat
+
+sleep 1
+
+config_get sch_upstream global upstream 100000
+config_get sch_downstream global downstream 100000
+
+echo 1 ${sch_upstream} > /sys/kernel/debug/hnat/scheduler0
+echo 1 ${sch_downstream} > /sys/kernel/debug/hnat/scheduler1
+
+setup_queue() {
+	local queue_id queue_scheduler queue_minebl queue_maxebl queue_minrate queue_maxrate queue_resv minrate maxrate queue_weight
+
+	config_get queue_id $1 id 0
+	config_get queue_minrate $1 minrate 0
+	config_get queue_maxrate $1 maxrate 0
+	config_get queue_resv $1 resv 22
+	config_get queue_weight $1 weight 7
+
+	[ "${queue_id}" -gt 7 ] && return 0
+
+	queue_minebl=1
+	queue_maxebl=1
+	queue_scheduler=0
+
+	[ "${queue_minrate}" -eq 0 ] && queue_minebl=0
+	[ "${queue_maxrate}" -eq 0 ] && queue_maxebl=0
+
+	minrate=$((sch_upstream * $queue_minrate))
+	minrate=$((minrate / 100))
+
+	maxrate=$((sch_upstream * $queue_maxrate))
+	maxrate=$((maxrate / 100))
+
+	echo 0 ${queue_minebl} ${minrate} ${queue_maxebl} ${maxrate} ${queue_weight} ${queue_resv} > /sys/kernel/debug/hnat/queue${queue_id} 
+
+	queue_id=$((queue_id + 8))
+
+	minrate=$((sch_downstream * $queue_minrate))
+	minrate=$((minrate / 100))
+
+	maxrate=$((sch_downstream * $queue_maxrate))
+	maxrate=$((maxrate / 100))
+
+	echo 1 ${queue_minebl} ${minrate} ${queue_maxebl} ${maxrate} ${queue_weight} ${queue_resv} > /sys/kernel/debug/hnat/queue${queue_id} 
+}
+
+config_foreach setup_scheduler scheduler
+config_foreach setup_queue queue

+ 23 - 3
target/linux/mediatek/config-4.9

@@ -45,7 +45,6 @@ CONFIG_ARM_UNWIND=y
 CONFIG_ARM_VIRT_EXT=y
 CONFIG_ARM_VIRT_EXT=y
 CONFIG_ATAGS=y
 CONFIG_ATAGS=y
 CONFIG_AUTO_ZRELADDR=y
 CONFIG_AUTO_ZRELADDR=y
-# CONFIG_BINFMT_FLAT is not set
 CONFIG_BLK_MQ_PCI=y
 CONFIG_BLK_MQ_PCI=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
@@ -104,13 +103,29 @@ CONFIG_CRC32_SLICEBY8=y
 CONFIG_CROSS_MEMORY_ATTACH=y
 CONFIG_CROSS_MEMORY_ATTACH=y
 CONFIG_CRYPTO_AEAD=y
 CONFIG_CRYPTO_AEAD=y
 CONFIG_CRYPTO_AEAD2=y
 CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_CTR=y
 CONFIG_CRYPTO_DEFLATE=y
 CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_DEV_MEDIATEK=y
+CONFIG_CRYPTO_DRBG=y
+CONFIG_CRYPTO_DRBG_HMAC=y
+CONFIG_CRYPTO_DRBG_MENU=y
+CONFIG_CRYPTO_HASH=y
 CONFIG_CRYPTO_HASH2=y
 CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_HW=y
+CONFIG_CRYPTO_JITTERENTROPY=y
 CONFIG_CRYPTO_LZO=y
 CONFIG_CRYPTO_LZO=y
 CONFIG_CRYPTO_MANAGER=y
 CONFIG_CRYPTO_MANAGER=y
 CONFIG_CRYPTO_MANAGER2=y
 CONFIG_CRYPTO_MANAGER2=y
+CONFIG_CRYPTO_NULL=y
 CONFIG_CRYPTO_NULL2=y
 CONFIG_CRYPTO_NULL2=y
+CONFIG_CRYPTO_RNG=y
 CONFIG_CRYPTO_RNG2=y
 CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_RNG_DEFAULT=y
+CONFIG_CRYPTO_SEQIV=y
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_SHA512=y
 CONFIG_CRYPTO_WORKQUEUE=y
 CONFIG_CRYPTO_WORKQUEUE=y
 CONFIG_DCACHE_WORD_ACCESS=y
 CONFIG_DCACHE_WORD_ACCESS=y
 CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_DEBUG_BUGVERBOSE=y
@@ -213,6 +228,7 @@ CONFIG_HIGHMEM=y
 CONFIG_HOTPLUG_CPU=y
 CONFIG_HOTPLUG_CPU=y
 CONFIG_HWMON=y
 CONFIG_HWMON=y
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MTK=y
 CONFIG_HZ_FIXED=0
 CONFIG_HZ_FIXED=0
 CONFIG_I2C=y
 CONFIG_I2C=y
 CONFIG_I2C_BOARDINFO=y
 CONFIG_I2C_BOARDINFO=y
@@ -254,7 +270,6 @@ CONFIG_MDIO_GPIO=y
 CONFIG_MEDIATEK_MT6577_AUXADC=y
 CONFIG_MEDIATEK_MT6577_AUXADC=y
 CONFIG_MEDIATEK_WATCHDOG=y
 CONFIG_MEDIATEK_WATCHDOG=y
 CONFIG_MFD_CORE=y
 CONFIG_MFD_CORE=y
-# CONFIG_MFD_MAX77620 is not set
 CONFIG_MFD_MT6397=y
 CONFIG_MFD_MT6397=y
 CONFIG_MFD_SYSCON=y
 CONFIG_MFD_SYSCON=y
 CONFIG_MIGHT_HAVE_CACHE_L2X0=y
 CONFIG_MIGHT_HAVE_CACHE_L2X0=y
@@ -275,7 +290,6 @@ CONFIG_MTD_MT81xx_NOR=y
 CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_ECC=y
 CONFIG_MTD_NAND_ECC=y
 CONFIG_MTD_NAND_MTK=y
 CONFIG_MTD_NAND_MTK=y
-# CONFIG_MTD_PHYSMAP_OF_VERSATILE is not set
 CONFIG_MTD_SPI_NOR=y
 CONFIG_MTD_SPI_NOR=y
 CONFIG_MTD_UBI=y
 CONFIG_MTD_UBI=y
 CONFIG_MTD_UBI_BEB_LIMIT=20
 CONFIG_MTD_UBI_BEB_LIMIT=20
@@ -300,6 +314,8 @@ CONFIG_NET_DSA=y
 CONFIG_NET_DSA_MT7530=y
 CONFIG_NET_DSA_MT7530=y
 CONFIG_NET_DSA_TAG_MTK=y
 CONFIG_NET_DSA_TAG_MTK=y
 CONFIG_NET_FLOW_LIMIT=y
 CONFIG_NET_FLOW_LIMIT=y
+# CONFIG_NET_MEDIATEK_HNAT is not set
+CONFIG_NET_MEDIATEK_HW_QOS=y
 CONFIG_NET_MEDIATEK_SOC=y
 CONFIG_NET_MEDIATEK_SOC=y
 CONFIG_NET_SWITCHDEV=y
 CONFIG_NET_SWITCHDEV=y
 # CONFIG_NET_VENDOR_AURORA is not set
 # CONFIG_NET_VENDOR_AURORA is not set
@@ -329,7 +345,10 @@ CONFIG_OLD_SIGSUSPEND3=y
 CONFIG_PADATA=y
 CONFIG_PADATA=y
 CONFIG_PAGE_OFFSET=0xC0000000
 CONFIG_PAGE_OFFSET=0xC0000000
 CONFIG_PCI=y
 CONFIG_PCI=y
+CONFIG_PCIEAER=y
+CONFIG_PCIEPORTBUS=y
 CONFIG_PCIE_MTK=y
 CONFIG_PCIE_MTK=y
+CONFIG_PCIE_PME=y
 CONFIG_PCI_DOMAINS=y
 CONFIG_PCI_DOMAINS=y
 CONFIG_PCI_DOMAINS_GENERIC=y
 CONFIG_PCI_DOMAINS_GENERIC=y
 CONFIG_PCI_MSI=y
 CONFIG_PCI_MSI=y
@@ -366,6 +385,7 @@ CONFIG_PWM=y
 CONFIG_PWM_MEDIATEK=y
 CONFIG_PWM_MEDIATEK=y
 # CONFIG_PWM_MTK_DISP is not set
 # CONFIG_PWM_MTK_DISP is not set
 CONFIG_PWM_SYSFS=y
 CONFIG_PWM_SYSFS=y
+CONFIG_RAS=y
 CONFIG_RATIONAL=y
 CONFIG_RATIONAL=y
 CONFIG_RCU_CPU_STALL_TIMEOUT=21
 CONFIG_RCU_CPU_STALL_TIMEOUT=21
 # CONFIG_RCU_EXPERT is not set
 # CONFIG_RCU_EXPERT is not set

+ 167 - 2
target/linux/mediatek/files/arch/arm/boot/dts/_mt7623.dtsi

@@ -19,6 +19,7 @@
 #include <dt-bindings/phy/phy.h>
 #include <dt-bindings/phy/phy.h>
 #include <dt-bindings/reset/mt2701-resets.h>
 #include <dt-bindings/reset/mt2701-resets.h>
 #include <dt-bindings/pinctrl/mt7623-pinfunc.h>
 #include <dt-bindings/pinctrl/mt7623-pinfunc.h>
+#include <dt-bindings/gpio/gpio.h>
 #include "skeleton64.dtsi"
 #include "skeleton64.dtsi"
 
 
 
 
@@ -151,7 +152,7 @@
 	};
 	};
 
 
 	pio: pinctrl@10005000 {
 	pio: pinctrl@10005000 {
-		compatible = "mediatek,mt2701-pinctrl";
+		compatible = "mediatek,mt7623-pinctrl";
 		reg = <0 0x1000b000 0 0x1000>;
 		reg = <0 0x1000b000 0 0x1000>;
 		mediatek,pctl-regmap = <&syscfg_pctl_a>;
 		mediatek,pctl-regmap = <&syscfg_pctl_a>;
 		pins-are-numbered;
 		pins-are-numbered;
@@ -211,6 +212,15 @@
 		clock-names = "spi", "wrap";
 		clock-names = "spi", "wrap";
 	};
 	};
 
 
+	cir: cir@10013000 {
+		compatible = "mediatek,mt7623-cir";
+		reg = <0 0x10013000 0 0x1000>;
+		interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&infracfg CLK_INFRA_IRRX>;
+		clock-names = "clk";
+		status = "disabled";
+	};
+
 	sysirq: interrupt-controller@10200100 {
 	sysirq: interrupt-controller@10200100 {
 		compatible = "mediatek,mt7623-sysirq",
 		compatible = "mediatek,mt7623-sysirq",
 			     "mediatek,mt6577-sysirq";
 			     "mediatek,mt6577-sysirq";
@@ -240,6 +250,13 @@
 		#clock-cells = <1>;
 		#clock-cells = <1>;
 	};
 	};
 
 
+	rng: rng@1020f000 {
+		compatible = "mediatek,mt7623-rng";
+		reg = <0 0x1020f000 0 0x1000>;
+		clocks = <&infracfg CLK_INFRA_TRNG>;
+		clock-names = "rng";
+	};
+
 	gic: interrupt-controller@10211000 {
 	gic: interrupt-controller@10211000 {
 		compatible = "arm,cortex-a7-gic";
 		compatible = "arm,cortex-a7-gic";
 		interrupt-controller;
 		interrupt-controller;
@@ -370,7 +387,7 @@
 		status = "disabled";
 		status = "disabled";
 	};
 	};
 
 
-	spi: spi@1100a000 {
+	spi0: spi@1100a000 {
 		compatible = "mediatek,mt7623-spi",
 		compatible = "mediatek,mt7623-spi",
 			     "mediatek,mt6589-spi";
 			     "mediatek,mt6589-spi";
 		reg = <0 0x1100a000 0 0x1000>;
 		reg = <0 0x1100a000 0 0x1000>;
@@ -399,6 +416,34 @@
 		nvmem-cell-names = "calibration-data";
 		nvmem-cell-names = "calibration-data";
 	};
 	};
 
 
+	spi1: spi@11016000 {
+		compatible = "mediatek,mt7623-spi",
+			     "mediatek,mt2701-spi";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0 0x11016000 0 0x100>;
+		interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&topckgen CLK_TOP_SYSPLL3_D2>,
+			 <&topckgen CLK_TOP_SPI1_SEL>,
+			 <&pericfg CLK_PERI_SPI1>;
+		clock-names = "parent-clk", "sel-clk", "spi-clk";
+		status = "disabled";
+	};
+
+	spi2: spi@11017000 {
+		compatible = "mediatek,mt7623-spi",
+			"mediatek,mt2701-spi";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0 0x11017000 0 0x1000>;
+		interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&topckgen CLK_TOP_SYSPLL3_D2>,
+			 <&topckgen CLK_TOP_SPI2_SEL>,
+			 <&pericfg CLK_PERI_SPI2>;
+		clock-names = "parent-clk", "sel-clk", "spi-clk";
+		status = "disabled";
+	};
+
 	nandc: nfi@1100d000 {
 	nandc: nfi@1100d000 {
 		compatible = "mediatek,mt7623-nfc",
 		compatible = "mediatek,mt7623-nfc",
 			     "mediatek,mt2701-nfc";
 			     "mediatek,mt2701-nfc";
@@ -424,6 +469,104 @@
 		status = "disabled";
 		status = "disabled";
 	};
 	};
 
 
+	afe: audio-controller@11220000 {
+	compatible = "mediatek,mt7623-audio",
+		     "mediatek,mt2701-audio";
+	reg = <0 0x11220000 0 0x2000>,
+	      <0 0x112a0000 0 0x20000>;
+	interrupts = <GIC_SPI 132 IRQ_TYPE_LEVEL_LOW>;
+	power-domains = <&scpsys MT2701_POWER_DOMAIN_IFR_MSC>;
+	
+	clocks = <&infracfg CLK_INFRA_AUDIO>,
+		 <&topckgen CLK_TOP_AUD_MUX1_SEL>,
+		 <&topckgen CLK_TOP_AUD_MUX2_SEL>,
+		 <&topckgen CLK_TOP_AUD_MUX1_DIV>,
+		 <&topckgen CLK_TOP_AUD_MUX2_DIV>,
+		 <&topckgen CLK_TOP_AUD_48K_TIMING>,
+		 <&topckgen CLK_TOP_AUD_44K_TIMING>,
+		 <&topckgen CLK_TOP_AUDPLL_MUX_SEL>,
+		 <&topckgen CLK_TOP_APLL_SEL>,
+		 <&topckgen CLK_TOP_AUD1PLL_98M>,
+		 <&topckgen CLK_TOP_AUD2PLL_90M>,
+		 <&topckgen CLK_TOP_HADDS2PLL_98M>,
+		 <&topckgen CLK_TOP_HADDS2PLL_294M>,
+		 <&topckgen CLK_TOP_AUDPLL>,
+		 <&topckgen CLK_TOP_AUDPLL_D4>,
+		 <&topckgen CLK_TOP_AUDPLL_D8>,
+		 <&topckgen CLK_TOP_AUDPLL_D16>,
+		 <&topckgen CLK_TOP_AUDPLL_D24>,
+		 <&topckgen CLK_TOP_AUDINTBUS_SEL>,
+		 <&clk26m>,
+		 <&topckgen CLK_TOP_SYSPLL1_D4>,
+		 <&topckgen CLK_TOP_AUD_K1_SRC_SEL>,
+		 <&topckgen CLK_TOP_AUD_K2_SRC_SEL>,
+		 <&topckgen CLK_TOP_AUD_K3_SRC_SEL>,
+		 <&topckgen CLK_TOP_AUD_K4_SRC_SEL>,
+		 <&topckgen CLK_TOP_AUD_K5_SRC_SEL>,
+		 <&topckgen CLK_TOP_AUD_K6_SRC_SEL>,
+		 <&topckgen CLK_TOP_AUD_K1_SRC_DIV>,
+		 <&topckgen CLK_TOP_AUD_K2_SRC_DIV>,
+		 <&topckgen CLK_TOP_AUD_K3_SRC_DIV>,
+		 <&topckgen CLK_TOP_AUD_K4_SRC_DIV>,
+		 <&topckgen CLK_TOP_AUD_K5_SRC_DIV>,
+		 <&topckgen CLK_TOP_AUD_K6_SRC_DIV>,
+		 <&topckgen CLK_TOP_AUD_I2S1_MCLK>,
+		 <&topckgen CLK_TOP_AUD_I2S2_MCLK>,
+		 <&topckgen CLK_TOP_AUD_I2S3_MCLK>,
+		 <&topckgen CLK_TOP_AUD_I2S4_MCLK>,
+		 <&topckgen CLK_TOP_AUD_I2S5_MCLK>,
+		 <&topckgen CLK_TOP_AUD_I2S6_MCLK>,
+		 <&topckgen CLK_TOP_ASM_M_SEL>,
+		 <&topckgen CLK_TOP_ASM_H_SEL>,
+		 <&topckgen CLK_TOP_UNIVPLL2_D4>,
+		 <&topckgen CLK_TOP_UNIVPLL2_D2>,
+		 <&topckgen CLK_TOP_SYSPLL_D5>;
+	clock-names = "infra_sys_audio_clk",
+		"top_audio_mux1_sel",
+		"top_audio_mux2_sel",
+		"top_audio_mux1_div",
+		"top_audio_mux2_div",
+		"top_audio_48k_timing",
+		"top_audio_44k_timing",
+		"top_audpll_mux_sel",
+		"top_apll_sel",
+		"top_aud1_pll_98M",
+		"top_aud2_pll_90M",
+		"top_hadds2_pll_98M",
+		"top_hadds2_pll_294M",
+		"top_audpll",
+		"top_audpll_d4",
+		"top_audpll_d8",
+		"top_audpll_d16",
+		"top_audpll_d24",
+		"top_audintbus_sel",
+		"clk_26m",
+		"top_syspll1_d4",
+		"top_aud_k1_src_sel",
+		"top_aud_k2_src_sel",
+		"top_aud_k3_src_sel",
+		"top_aud_k4_src_sel",
+		"top_aud_k5_src_sel",
+		"top_aud_k6_src_sel",
+		"top_aud_k1_src_div",
+		"top_aud_k2_src_div",
+		"top_aud_k3_src_div",
+		"top_aud_k4_src_div",
+		"top_aud_k5_src_div",
+		"top_aud_k6_src_div",
+		"top_aud_i2s1_mclk",
+		"top_aud_i2s2_mclk",
+		"top_aud_i2s3_mclk",
+		"top_aud_i2s4_mclk",
+		"top_aud_i2s5_mclk",
+		"top_aud_i2s6_mclk",
+		"top_asm_m_sel",
+		"top_asm_h_sel",
+		"top_univpll2_d4",
+		"top_univpll2_d2",
+		"top_syspll_d5";
+	};
+
 	mmc0: mmc@11230000 {
 	mmc0: mmc@11230000 {
 		compatible = "mediatek,mt7623-mmc",
 		compatible = "mediatek,mt7623-mmc",
 			     "mediatek,mt8135-mmc";
 			     "mediatek,mt8135-mmc";
@@ -636,4 +779,26 @@
 			#size-cells = <0>;
 			#size-cells = <0>;
 		};
 		};
 	};
 	};
+
+	hnat: hnat@1b000000 {
+		compatible = "mediatek,mt7623-hnat";
+		reg = <0 0x1b100000 0 0x3000>;
+		mtketh-wan = "eth1";
+		resets = <&ethsys 0>;
+		reset-names = "mtketh";
+	};
+
+	crypto: crypto@1b240000 {
+		compatible = "mediatek,mt7623-crypto", "mediatek,eip97-crypto";
+		reg = <0 0x1b240000 0 0x20000>;
+		interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_SPI 83 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_SPI 84 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_SPI 91 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_SPI 97 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&topckgen CLK_TOP_ETHIF_SEL>,
+			 <&ethsys CLK_ETHSYS_CRYPTO>;
+		clock-names = "ethif","cryp";
+		power-domains = <&scpsys MT2701_POWER_DOMAIN_ETH>;
+	};
 };
 };

+ 241 - 0
target/linux/mediatek/files/arch/arm/boot/dts/mt6323.dtsi

@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2017 MediaTek Inc.
+ * Author: John Crispin <[email protected]>
+ *	   Sean Wang <[email protected]>
+ * 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.
+ */
+
+&pwrap {
+	pmic: mt6323 {
+		compatible = "mediatek,mt6323";
+		interrupt-parent = <&pio>;
+		interrupts = <150 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		mt6323regulator: mt6323regulator{
+			compatible = "mediatek,mt6323-regulator";
+
+			mt6323_vproc_reg: buck_vproc{
+				regulator-name = "vproc";
+				regulator-min-microvolt = < 700000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-ramp-delay = <12500>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vsys_reg: buck_vsys{
+				regulator-name = "vsys";
+				regulator-min-microvolt = <1400000>;
+				regulator-max-microvolt = <2987500>;
+				regulator-ramp-delay = <25000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vpa_reg: buck_vpa{
+				regulator-name = "vpa";
+				regulator-min-microvolt = < 500000>;
+				regulator-max-microvolt = <3650000>;
+			};
+
+			mt6323_vtcxo_reg: ldo_vtcxo{
+				regulator-name = "vtcxo";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-enable-ramp-delay = <90>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vcn28_reg: ldo_vcn28{
+				regulator-name = "vcn28";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-enable-ramp-delay = <185>;
+			};
+
+			mt6323_vcn33_bt_reg: ldo_vcn33_bt{
+				regulator-name = "vcn33_bt";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3600000>;
+				regulator-enable-ramp-delay = <185>;
+			};
+
+			mt6323_vcn33_wifi_reg: ldo_vcn33_wifi{
+				regulator-name = "vcn33_wifi";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3600000>;
+				regulator-enable-ramp-delay = <185>;
+			};
+
+			mt6323_va_reg: ldo_va{
+				regulator-name = "va";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-enable-ramp-delay = <216>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vcama_reg: ldo_vcama{
+				regulator-name = "vcama";
+				regulator-min-microvolt = <1500000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vio28_reg: ldo_vio28{
+				regulator-name = "vio28";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-enable-ramp-delay = <216>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vusb_reg: ldo_vusb{
+				regulator-name = "vusb";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <216>;
+				regulator-boot-on;
+			};
+
+			mt6323_vmc_reg: ldo_vmc{
+				regulator-name = "vmc";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <36>;
+				regulator-boot-on;
+			};
+
+			mt6323_vmch_reg: ldo_vmch{
+				regulator-name = "vmch";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <36>;
+				regulator-boot-on;
+			};
+
+			mt6323_vemc3v3_reg: ldo_vemc3v3{
+				regulator-name = "vemc3v3";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <36>;
+				regulator-boot-on;
+			};
+
+			mt6323_vgp1_reg: ldo_vgp1{
+				regulator-name = "vgp1";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vgp2_reg: ldo_vgp2{
+				regulator-name = "vgp2";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <3000000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vgp3_reg: ldo_vgp3{
+				regulator-name = "vgp3";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vcn18_reg: ldo_vcn18{
+				regulator-name = "vcn18";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vsim1_reg: ldo_vsim1{
+				regulator-name = "vsim1";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3000000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vsim2_reg: ldo_vsim2{
+				regulator-name = "vsim2";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3000000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vrtc_reg: ldo_vrtc{
+				regulator-name = "vrtc";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vcamaf_reg: ldo_vcamaf{
+				regulator-name = "vcamaf";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vibr_reg: ldo_vibr{
+				regulator-name = "vibr";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <36>;
+			};
+
+			mt6323_vrf18_reg: ldo_vrf18{
+				regulator-name = "vrf18";
+				regulator-min-microvolt = <1825000>;
+				regulator-max-microvolt = <1825000>;
+				regulator-enable-ramp-delay = <187>;
+			};
+
+			mt6323_vm_reg: ldo_vm{
+				regulator-name = "vm";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-enable-ramp-delay = <216>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vio18_reg: ldo_vio18{
+				regulator-name = "vio18";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-enable-ramp-delay = <216>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			mt6323_vcamd_reg: ldo_vcamd{
+				regulator-name = "vcamd";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+
+			mt6323_vcamio_reg: ldo_vcamio{
+				regulator-name = "vcamio";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-enable-ramp-delay = <216>;
+			};
+		};
+	};
+};

+ 0 - 7
target/linux/mediatek/files/arch/arm/boot/dts/mt7623-NAND-ePHY.dts

@@ -363,13 +363,6 @@
 				 <MT7623_PIN_274_G2_RXDV_FUNC_G2_RXDV>;
 				 <MT7623_PIN_274_G2_RXDV_FUNC_G2_RXDV>;
 		};
 		};
 
 
-		pins_eth_esw {
-			pinmux = <MT7623_PIN_273_ESW_INT_FUNC_ESW_INT>;
-			input-enable;
-			drive-strength = <MTK_DRIVE_8mA>;
-			bias-pull-up;
-		};
-
 		pins_eth_rst {
 		pins_eth_rst {
 			pinmux = <MT7623_PIN_15_GPIO15_FUNC_GPIO15>;
 			pinmux = <MT7623_PIN_15_GPIO15_FUNC_GPIO15>;
 			output-low;
 			output-low;

+ 0 - 7
target/linux/mediatek/files/arch/arm/boot/dts/mt7623-NAND.dts

@@ -363,13 +363,6 @@
 				 <MT7623_PIN_274_G2_RXDV_FUNC_G2_RXDV>;
 				 <MT7623_PIN_274_G2_RXDV_FUNC_G2_RXDV>;
 		};
 		};
 
 
-		pins_eth_esw {
-			pinmux = <MT7623_PIN_273_ESW_INT_FUNC_ESW_INT>;
-			input-enable;
-			drive-strength = <MTK_DRIVE_8mA>;
-			bias-pull-up;
-		};
-
 		pins_eth_rst {
 		pins_eth_rst {
 			pinmux = <MT7623_PIN_15_GPIO15_FUNC_GPIO15>;
 			pinmux = <MT7623_PIN_15_GPIO15_FUNC_GPIO15>;
 			output-low;
 			output-low;

+ 55 - 54
target/linux/mediatek/files/arch/arm/boot/dts/mt7623-eMMC.dts

@@ -38,6 +38,61 @@
 		gpio = <&pio 135 GPIO_ACTIVE_HIGH>;
 		gpio = <&pio 135 GPIO_ACTIVE_HIGH>;
 		enable-active-high;
 		enable-active-high;
 	};
 	};
+
+	switch {
+		compatible = "mediatek,mt7530";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0>;
+
+		dsa,mii-bus = <&mdio0>;
+
+		pinctrl-names = "default";
+		pinctrl-0 = <&eth_default>;
+
+		core-supply = <&mt6323_vpa_reg>;
+		io-supply = <&mt6323_vemc3v3_reg>;
+
+		mediatek,mcm;
+		resets = <&ethsys 2>;
+		reset-names = "mcm";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+			port@0 {
+				reg = <0>;
+				label = "lan0";
+			};
+
+			port@1 {
+				reg = <1>;
+				label = "lan1";
+			};
+
+			port@2 {
+				reg = <2>;
+				label = "lan2";
+			};
+
+			port@3 {
+				reg = <3>;
+				label = "lan3";
+			};
+
+			port@6 {
+				reg = <6>;
+				label = "cpu";
+				ethernet = <&gmac1>;
+				phy-mode = "trgmii";
+				fixed-link {
+					speed = <1000>;
+					full-duplex;
+				};
+			};
+		};
+	};
 };
 };
 
 
 &cpu0 {
 &cpu0 {
@@ -428,7 +483,6 @@
 				 <MT7623_PIN_270_G2_RXD1_FUNC_G2_RXD1>,
 				 <MT7623_PIN_270_G2_RXD1_FUNC_G2_RXD1>,
 				 <MT7623_PIN_271_G2_RXD2_FUNC_G2_RXD2>,
 				 <MT7623_PIN_271_G2_RXD2_FUNC_G2_RXD2>,
 				 <MT7623_PIN_272_G2_RXD3_FUNC_G2_RXD3>,
 				 <MT7623_PIN_272_G2_RXD3_FUNC_G2_RXD3>,
-				 <MT7623_PIN_273_ESW_INT_FUNC_ESW_INT>,
 				 <MT7623_PIN_274_G2_RXDV_FUNC_G2_RXDV>;
 				 <MT7623_PIN_274_G2_RXDV_FUNC_G2_RXDV>;
 		};
 		};
 
 
@@ -480,59 +534,6 @@
 };
 };
 
 
 &mdio0 {
 &mdio0 {
-	switch@0 {
-		compatible = "mediatek,mt7530";
-		#address-cells = <1>;
-		#size-cells = <0>;
-		reg = <0>;
-
-		pinctrl-names = "default";
-		pinctrl-0 = <&eth_default>;
-
-		core-supply = <&mt6323_vpa_reg>;
-		io-supply = <&mt6323_vemc3v3_reg>;
-
-		mediatek,mcm;
-		resets = <&ethsys 2>;
-		reset-names = "mcm";
-
-		ports {
-			#address-cells = <1>;
-			#size-cells = <0>;
-			reg = <0>;
-			port@0 {
-				reg = <0>;
-				label = "lan0";
-			};
-
-			port@1 {
-				reg = <1>;
-				label = "lan1";
-			};
-
-			port@2 {
-				reg = <2>;
-				label = "lan2";
-			};
-
-			port@3 {
-				reg = <3>;
-				label = "lan3";
-			};
-
-			port@6 {
-				reg = <6>;
-				label = "cpu";
-				ethernet = <&gmac1>;
-				phy-mode = "trgmii";
-				fixed-link {
-					speed = <1000>;
-					full-duplex;
-				};
-			};
-		};
-	};
-
 	phy5: ethernet-phy@5 {
 	phy5: ethernet-phy@5 {
 		reg = <5>;
 		reg = <5>;
 		phy-mode = "rgmii-rxid";
 		phy-mode = "rgmii-rxid";

+ 443 - 0
target/linux/mediatek/files/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts

@@ -0,0 +1,443 @@
+/*
+ * Copyright 2017 Sean Wang <[email protected]>
+ *
+ * SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+ */
+
+/dts-v1/;
+#include <dt-bindings/input/input.h>
+#include "_mt7623.dtsi"
+#include "mt6323.dtsi"
+
+/ {
+	model = "Bananapi BPI-R2";
+	compatible = "bananapi,bpi-r2", "mediatek,mt7623";
+
+	aliases {
+		serial2 = &uart2;
+	};
+
+	chosen {
+		stdout-path = "serial2:115200n8";
+	};
+
+	cpus {
+		cpu@0 {
+			proc-supply = <&mt6323_vproc_reg>;
+		};
+
+		cpu@1 {
+			proc-supply = <&mt6323_vproc_reg>;
+		};
+
+		cpu@2 {
+			proc-supply = <&mt6323_vproc_reg>;
+		};
+
+		cpu@3 {
+			proc-supply = <&mt6323_vproc_reg>;
+		};
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		pinctrl-names = "default";
+		pinctrl-0 = <&key_pins_a>;
+
+		factory {
+			label = "factory";
+			linux,code = <BTN_0>;
+			gpios = <&pio 256 GPIO_ACTIVE_LOW>;
+		};
+
+		wps {
+			label = "wps";
+			linux,code = <KEY_WPS_BUTTON>;
+			gpios = <&pio 257 GPIO_ACTIVE_HIGH>;
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&led_pins_a>;
+
+		red {
+			label = "bpi-r2:pio:red";
+			gpios = <&pio 239 GPIO_ACTIVE_HIGH>;
+			default-state = "off";
+		};
+
+		green {
+			label = "bpi-r2:pio:green";
+			gpios = <&pio 240 GPIO_ACTIVE_HIGH>;
+			default-state = "off";
+		};
+
+		blue {
+			label = "bpi-r2:pio:blue";
+			gpios = <&pio 241 GPIO_ACTIVE_HIGH>;
+			default-state = "off";
+		};
+	};
+
+	memory@80000000 {
+		reg = <0 0x80000000 0 0x40000000>;
+	};
+};
+
+&cir {
+	pinctrl-names = "default";
+	pinctrl-0 = <&cir_pins_a>;
+	status = "okay";
+};
+
+&crypto {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "trgmii";
+		fixed-link {
+			speed = <1000>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		switch@0 {
+			compatible = "mediatek,mt7530";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+
+			pinctrl-names = "default";
+			reset-gpios = <&pio 33 0>;
+			core-supply = <&mt6323_vpa_reg>;
+			io-supply = <&mt6323_vemc3v3_reg>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				reg = <0>;
+				port@0 {
+					reg = <0>;
+					label = "wan";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan0";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan1";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan2";
+				};
+
+				port@4 {
+					reg = <4>;
+					label = "lan3";
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "trgmii";
+					fixed-link {
+						speed = <1000>;
+						full-duplex;
+					};
+				};
+			};
+		};
+	};
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c0_pins_a>;
+	status = "okay";
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins_a>;
+	status = "okay";
+};
+
+&pio {
+	cir_pins_a:cir@0 {
+		pins_cir {
+			pinmux = <MT7623_PIN_46_IR_FUNC_IR>;
+			bias-disable;
+		};
+	};
+
+	i2c0_pins_a: i2c@0 {
+		pins_i2c0 {
+			pinmux = <MT7623_PIN_75_SDA0_FUNC_SDA0>,
+				 <MT7623_PIN_76_SCL0_FUNC_SCL0>;
+			bias-disable;
+		};
+	};
+
+	i2c1_pins_a: i2c@1 {
+		pin_i2c1 {
+			pinmux = <MT7623_PIN_57_SDA1_FUNC_SDA1>,
+				 <MT7623_PIN_58_SCL1_FUNC_SCL1>;
+			bias-disable;
+		};
+	};
+
+	i2s0_pins_a: i2s@0 {
+		pin_i2s0 {
+			pinmux = <MT7623_PIN_49_I2S0_DATA_FUNC_I2S0_DATA>,
+				 <MT7623_PIN_72_I2S0_DATA_IN_FUNC_I2S0_DATA_IN>,
+				 <MT7623_PIN_73_I2S0_LRCK_FUNC_I2S0_LRCK>,
+				 <MT7623_PIN_74_I2S0_BCK_FUNC_I2S0_BCK>,
+				 <MT7623_PIN_126_I2S0_MCLK_FUNC_I2S0_MCLK>;
+			drive-strength = <MTK_DRIVE_12mA>;
+			bias-pull-down;
+		};
+	};
+
+	i2s1_pins_a: i2s@1 {
+		pin_i2s1 {
+			pinmux = <MT7623_PIN_33_I2S1_DATA_FUNC_I2S1_DATA>,
+				 <MT7623_PIN_34_I2S1_DATA_IN_FUNC_I2S1_DATA_IN>,
+				 <MT7623_PIN_35_I2S1_BCK_FUNC_I2S1_BCK>,
+				 <MT7623_PIN_36_I2S1_LRCK_FUNC_I2S1_LRCK>,
+				 <MT7623_PIN_37_I2S1_MCLK_FUNC_I2S1_MCLK>;
+			drive-strength = <MTK_DRIVE_12mA>;
+			bias-pull-down;
+		};
+	};
+
+	key_pins_a: keys@0 {
+		pins_keys {
+			pinmux = <MT7623_PIN_256_GPIO256_FUNC_GPIO256>,
+				 <MT7623_PIN_257_GPIO257_FUNC_GPIO257> ;
+			input-enable;
+		};
+	};
+
+	led_pins_a: leds@0 {
+		pins_leds {
+			pinmux = <MT7623_PIN_239_EXT_SDIO0_FUNC_GPIO239>,
+				 <MT7623_PIN_240_EXT_XCS_FUNC_GPIO240>,
+				 <MT7623_PIN_241_EXT_SCK_FUNC_GPIO241>;
+		};
+	};
+
+	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;
+		};
+	};
+
+	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>;
+			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>;
+		};
+	};
+
+	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>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+	};
+
+	spi0_pins_a: spi@0 {
+		pins_spi {
+			pinmux = <MT7623_PIN_53_SPI0_CSN_FUNC_SPI0_CS>,
+				<MT7623_PIN_54_SPI0_CK_FUNC_SPI0_CK>,
+				<MT7623_PIN_55_SPI0_MI_FUNC_SPI0_MI>,
+				<MT7623_PIN_56_SPI0_MO_FUNC_SPI0_MO>;
+			bias-disable;
+		};
+	};
+
+	pwm_pins_a: pwm@0 {
+		pins_pwm {
+			pinmux = <MT7623_PIN_203_PWM0_FUNC_PWM0>,
+				 <MT7623_PIN_204_PWM1_FUNC_PWM1>,
+				 <MT7623_PIN_205_PWM2_FUNC_PWM2>,
+				 <MT7623_PIN_206_PWM3_FUNC_PWM3>,
+				 <MT7623_PIN_207_PWM4_FUNC_PWM4>;
+		};
+	};
+
+	uart0_pins_a: uart@0 {
+		pins_dat {
+			pinmux = <MT7623_PIN_79_URXD0_FUNC_URXD0>,
+				 <MT7623_PIN_80_UTXD0_FUNC_UTXD0>;
+		};
+	};
+
+	uart1_pins_a: uart@1 {
+		pins_dat {
+			pinmux = <MT7623_PIN_81_URXD1_FUNC_URXD1>,
+				 <MT7623_PIN_82_UTXD1_FUNC_UTXD1>;
+		};
+	};
+};
+
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm_pins_a>;
+	status = "okay";
+};
+
+&pwrap {
+	mt6323 {
+		mt6323led: led {
+			compatible = "mediatek,mt6323-led";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			led@0 {
+				reg = <0>;
+				label = "bpi-r2:isink:green";
+				default-state = "off";
+			};
+			led@1 {
+				reg = <1>;
+				label = "bpi-r2:isink:red";
+				default-state = "off";
+			};
+			led@2 {
+				reg = <2>;
+				label = "bpi-r2:isink:blue";
+				default-state = "off";
+			};
+		};
+	};
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi0_pins_a>;
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins_a>;
+	status = "disabled";
+};
+
+&u3phy1 {
+	status = "okay";
+};
+
+&u3phy2 {
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins_a>;
+	status = "disabled";
+};
+
+&uart2 {
+	status = "okay";
+};
+
+&usb1 {
+	vusb33-supply = <&mt6323_vusb_reg>;
+	status = "okay";
+};
+
+&usb2 {
+	vusb33-supply = <&mt6323_vusb_reg>;
+	status = "okay";
+};

+ 168 - 0
target/linux/mediatek/files/drivers/char/hw_random/mtk-rng.c

@@ -0,0 +1,168 @@
+/*
+ * Driver for Mediatek Hardware Random Number Generator
+ *
+ * Copyright (C) 2017 Sean Wang <[email protected]>
+ *
+ * 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.
+ */
+#define MTK_RNG_DEV KBUILD_MODNAME
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/hw_random.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#define USEC_POLL			2
+#define TIMEOUT_POLL			20
+
+#define RNG_CTRL			0x00
+#define RNG_EN				BIT(0)
+#define RNG_READY			BIT(31)
+
+#define RNG_DATA			0x08
+
+#define to_mtk_rng(p)	container_of(p, struct mtk_rng, rng)
+
+struct mtk_rng {
+	void __iomem *base;
+	struct clk *clk;
+	struct hwrng rng;
+};
+
+static int mtk_rng_init(struct hwrng *rng)
+{
+	struct mtk_rng *priv = to_mtk_rng(rng);
+	u32 val;
+	int err;
+
+	err = clk_prepare_enable(priv->clk);
+	if (err)
+		return err;
+
+	val = readl(priv->base + RNG_CTRL);
+	val |= RNG_EN;
+	writel(val, priv->base + RNG_CTRL);
+
+	return 0;
+}
+
+static void mtk_rng_cleanup(struct hwrng *rng)
+{
+	struct mtk_rng *priv = to_mtk_rng(rng);
+	u32 val;
+
+	val = readl(priv->base + RNG_CTRL);
+	val &= ~RNG_EN;
+	writel(val, priv->base + RNG_CTRL);
+
+	clk_disable_unprepare(priv->clk);
+}
+
+static bool mtk_rng_wait_ready(struct hwrng *rng, bool wait)
+{
+	struct mtk_rng *priv = to_mtk_rng(rng);
+	int ready;
+
+	ready = readl(priv->base + RNG_CTRL) & RNG_READY;
+	if (!ready && wait)
+		readl_poll_timeout_atomic(priv->base + RNG_CTRL, ready,
+					  ready & RNG_READY, USEC_POLL,
+					  TIMEOUT_POLL);
+	return !!ready;
+}
+
+static int mtk_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
+{
+	struct mtk_rng *priv = to_mtk_rng(rng);
+	int retval = 0;
+
+	while (max >= sizeof(u32)) {
+		if (!mtk_rng_wait_ready(rng, wait))
+			break;
+
+		*(u32 *)buf = readl(priv->base + RNG_DATA);
+		retval += sizeof(u32);
+		buf += sizeof(u32);
+		max -= sizeof(u32);
+	}
+
+	return retval || !wait ? retval : -EIO;
+}
+
+static int mtk_rng_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	int ret;
+	struct mtk_rng *priv;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "no iomem resource\n");
+		return -ENXIO;
+	}
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->rng.name = pdev->name;
+	priv->rng.init = mtk_rng_init;
+	priv->rng.cleanup = mtk_rng_cleanup;
+	priv->rng.read = mtk_rng_read;
+
+	priv->clk = devm_clk_get(&pdev->dev, "rng");
+	if (IS_ERR(priv->clk)) {
+		ret = PTR_ERR(priv->clk);
+		dev_err(&pdev->dev, "no clock for device: %d\n", ret);
+		return ret;
+	}
+
+	priv->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(priv->base))
+		return PTR_ERR(priv->base);
+
+	ret = devm_hwrng_register(&pdev->dev, &priv->rng);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register rng device: %d\n",
+			ret);
+		return ret;
+	}
+
+	dev_info(&pdev->dev, "registered RNG driver\n");
+
+	return 0;
+}
+
+static const struct of_device_id mtk_rng_match[] = {
+	{ .compatible = "mediatek,mt7623-rng" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, mtk_rng_match);
+
+static struct platform_driver mtk_rng_driver = {
+	.probe          = mtk_rng_probe,
+	.driver = {
+		.name = MTK_RNG_DEV,
+		.of_match_table = mtk_rng_match,
+	},
+};
+
+module_platform_driver(mtk_rng_driver);
+
+MODULE_DESCRIPTION("Mediatek Random Number Generator Driver");
+MODULE_AUTHOR("Sean Wang <[email protected]>");
+MODULE_LICENSE("GPL");

+ 2 - 0
target/linux/mediatek/files/drivers/crypto/mediatek/Makefile

@@ -0,0 +1,2 @@
+obj-$(CONFIG_CRYPTO_DEV_MEDIATEK) += mtk-crypto.o
+mtk-crypto-objs:= mtk-platform.o mtk-aes.o mtk-sha.o

+ 1304 - 0
target/linux/mediatek/files/drivers/crypto/mediatek/mtk-aes.c

@@ -0,0 +1,1304 @@
+/*
+ * Cryptographic API.
+ *
+ * Driver for EIP97 AES acceleration.
+ *
+ * Copyright (c) 2016 Ryder Lee <[email protected]>
+ *
+ * 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.
+ *
+ * Some ideas are from atmel-aes.c drivers.
+ */
+
+#include <crypto/aes.h>
+#include "mtk-platform.h"
+
+#define AES_QUEUE_SIZE		512
+#define AES_BUF_ORDER		2
+#define AES_BUF_SIZE		((PAGE_SIZE << AES_BUF_ORDER) \
+				& ~(AES_BLOCK_SIZE - 1))
+#define AES_MAX_STATE_BUF_SIZE	SIZE_IN_WORDS(AES_KEYSIZE_256 + \
+				AES_BLOCK_SIZE * 2)
+#define AES_MAX_CT_SIZE		6
+
+#define AES_CT_CTRL_HDR		cpu_to_le32(0x00220000)
+
+/* AES-CBC/ECB/CTR command token */
+#define AES_CMD0		cpu_to_le32(0x05000000)
+#define AES_CMD1		cpu_to_le32(0x2d060000)
+#define AES_CMD2		cpu_to_le32(0xe4a63806)
+/* AES-GCM command token */
+#define AES_GCM_CMD0		cpu_to_le32(0x0b000000)
+#define AES_GCM_CMD1		cpu_to_le32(0xa0800000)
+#define AES_GCM_CMD2		cpu_to_le32(0x25000010)
+#define AES_GCM_CMD3		cpu_to_le32(0x0f020000)
+#define AES_GCM_CMD4		cpu_to_le32(0x21e60000)
+#define AES_GCM_CMD5		cpu_to_le32(0x40e60000)
+#define AES_GCM_CMD6		cpu_to_le32(0xd0070000)
+
+/* AES transform information word 0 fields */
+#define AES_TFM_BASIC_OUT	cpu_to_le32(0x4 << 0)
+#define AES_TFM_BASIC_IN	cpu_to_le32(0x5 << 0)
+#define AES_TFM_GCM_OUT		cpu_to_le32(0x6 << 0)
+#define AES_TFM_GCM_IN		cpu_to_le32(0xf << 0)
+#define AES_TFM_SIZE(x)		cpu_to_le32((x) << 8)
+#define AES_TFM_128BITS		cpu_to_le32(0xb << 16)
+#define AES_TFM_192BITS		cpu_to_le32(0xd << 16)
+#define AES_TFM_256BITS		cpu_to_le32(0xf << 16)
+#define AES_TFM_GHASH_DIGEST	cpu_to_le32(0x2 << 21)
+#define AES_TFM_GHASH		cpu_to_le32(0x4 << 23)
+/* AES transform information word 1 fields */
+#define AES_TFM_ECB		cpu_to_le32(0x0 << 0)
+#define AES_TFM_CBC		cpu_to_le32(0x1 << 0)
+#define AES_TFM_CTR_INIT	cpu_to_le32(0x2 << 0)	/* init counter to 1 */
+#define AES_TFM_CTR_LOAD	cpu_to_le32(0x6 << 0)	/* load/reuse counter */
+#define AES_TFM_3IV		cpu_to_le32(0x7 << 5)	/* using IV 0-2 */
+#define AES_TFM_FULL_IV		cpu_to_le32(0xf << 5)	/* using IV 0-3 */
+#define AES_TFM_IV_CTR_MODE	cpu_to_le32(0x1 << 10)
+#define AES_TFM_ENC_HASH	cpu_to_le32(0x1 << 17)
+
+/* AES flags */
+#define AES_FLAGS_CIPHER_MSK	GENMASK(2, 0)
+#define AES_FLAGS_ECB		BIT(0)
+#define AES_FLAGS_CBC		BIT(1)
+#define AES_FLAGS_CTR		BIT(2)
+#define AES_FLAGS_GCM		BIT(3)
+#define AES_FLAGS_ENCRYPT	BIT(4)
+#define AES_FLAGS_BUSY		BIT(5)
+
+#define AES_AUTH_TAG_ERR	cpu_to_le32(BIT(26))
+
+/**
+ * mtk_aes_info - hardware information of AES
+ * @cmd:	command token, hardware instruction
+ * @tfm:	transform state of cipher algorithm.
+ * @state:	contains keys and initial vectors.
+ *
+ * Memory layout of GCM buffer:
+ * /-----------\
+ * |  AES KEY  | 128/196/256 bits
+ * |-----------|
+ * |  HASH KEY | a string 128 zero bits encrypted using the block cipher
+ * |-----------|
+ * |    IVs    | 4 * 4 bytes
+ * \-----------/
+ *
+ * The engine requires all these info to do:
+ * - Commands decoding and control of the engine's data path.
+ * - Coordinating hardware data fetch and store operations.
+ * - Result token construction and output.
+ */
+struct mtk_aes_info {
+	__le32 cmd[AES_MAX_CT_SIZE];
+	__le32 tfm[2];
+	__le32 state[AES_MAX_STATE_BUF_SIZE];
+};
+
+struct mtk_aes_reqctx {
+	u64 mode;
+};
+
+struct mtk_aes_base_ctx {
+	struct mtk_cryp *cryp;
+	u32 keylen;
+	__le32 keymode;
+
+	mtk_aes_fn start;
+
+	struct mtk_aes_info info;
+	dma_addr_t ct_dma;
+	dma_addr_t tfm_dma;
+
+	__le32 ct_hdr;
+	u32 ct_size;
+};
+
+struct mtk_aes_ctx {
+	struct mtk_aes_base_ctx	base;
+};
+
+struct mtk_aes_ctr_ctx {
+	struct mtk_aes_base_ctx base;
+
+	u32	iv[AES_BLOCK_SIZE / sizeof(u32)];
+	size_t offset;
+	struct scatterlist src[2];
+	struct scatterlist dst[2];
+};
+
+struct mtk_aes_gcm_ctx {
+	struct mtk_aes_base_ctx base;
+
+	u32 authsize;
+	size_t textlen;
+
+	struct crypto_skcipher *ctr;
+};
+
+struct mtk_aes_gcm_setkey_result {
+	int err;
+	struct completion completion;
+};
+
+struct mtk_aes_drv {
+	struct list_head dev_list;
+	/* Device list lock */
+	spinlock_t lock;
+};
+
+static struct mtk_aes_drv mtk_aes = {
+	.dev_list = LIST_HEAD_INIT(mtk_aes.dev_list),
+	.lock = __SPIN_LOCK_UNLOCKED(mtk_aes.lock),
+};
+
+static inline u32 mtk_aes_read(struct mtk_cryp *cryp, u32 offset)
+{
+	return readl_relaxed(cryp->base + offset);
+}
+
+static inline void mtk_aes_write(struct mtk_cryp *cryp,
+				 u32 offset, u32 value)
+{
+	writel_relaxed(value, cryp->base + offset);
+}
+
+static struct mtk_cryp *mtk_aes_find_dev(struct mtk_aes_base_ctx *ctx)
+{
+	struct mtk_cryp *cryp = NULL;
+	struct mtk_cryp *tmp;
+
+	spin_lock_bh(&mtk_aes.lock);
+	if (!ctx->cryp) {
+		list_for_each_entry(tmp, &mtk_aes.dev_list, aes_list) {
+			cryp = tmp;
+			break;
+		}
+		ctx->cryp = cryp;
+	} else {
+		cryp = ctx->cryp;
+	}
+	spin_unlock_bh(&mtk_aes.lock);
+
+	return cryp;
+}
+
+static inline size_t mtk_aes_padlen(size_t len)
+{
+	len &= AES_BLOCK_SIZE - 1;
+	return len ? AES_BLOCK_SIZE - len : 0;
+}
+
+static bool mtk_aes_check_aligned(struct scatterlist *sg, size_t len,
+				  struct mtk_aes_dma *dma)
+{
+	int nents;
+
+	if (!IS_ALIGNED(len, AES_BLOCK_SIZE))
+		return false;
+
+	for (nents = 0; sg; sg = sg_next(sg), ++nents) {
+		if (!IS_ALIGNED(sg->offset, sizeof(u32)))
+			return false;
+
+		if (len <= sg->length) {
+			if (!IS_ALIGNED(len, AES_BLOCK_SIZE))
+				return false;
+
+			dma->nents = nents + 1;
+			dma->remainder = sg->length - len;
+			sg->length = len;
+			return true;
+		}
+
+		if (!IS_ALIGNED(sg->length, AES_BLOCK_SIZE))
+			return false;
+
+		len -= sg->length;
+	}
+
+	return false;
+}
+
+static inline void mtk_aes_set_mode(struct mtk_aes_rec *aes,
+				    const struct mtk_aes_reqctx *rctx)
+{
+	/* Clear all but persistent flags and set request flags. */
+	aes->flags = (aes->flags & AES_FLAGS_BUSY) | rctx->mode;
+}
+
+static inline void mtk_aes_restore_sg(const struct mtk_aes_dma *dma)
+{
+	struct scatterlist *sg = dma->sg;
+	int nents = dma->nents;
+
+	if (!dma->remainder)
+		return;
+
+	while (--nents > 0 && sg)
+		sg = sg_next(sg);
+
+	if (!sg)
+		return;
+
+	sg->length += dma->remainder;
+}
+
+static inline void mtk_aes_write_state_le(__le32 *dst, const u32 *src, u32 size)
+{
+	int i;
+
+	for (i = 0; i < SIZE_IN_WORDS(size); i++)
+		dst[i] = cpu_to_le32(src[i]);
+}
+
+static inline void mtk_aes_write_state_be(__be32 *dst, const u32 *src, u32 size)
+{
+	int i;
+
+	for (i = 0; i < SIZE_IN_WORDS(size); i++)
+		dst[i] = cpu_to_be32(src[i]);
+}
+
+static inline int mtk_aes_complete(struct mtk_cryp *cryp,
+				   struct mtk_aes_rec *aes,
+				   int err)
+{
+	aes->flags &= ~AES_FLAGS_BUSY;
+	aes->areq->complete(aes->areq, err);
+	/* Handle new request */
+	tasklet_schedule(&aes->queue_task);
+	return err;
+}
+
+/*
+ * Write descriptors for processing. This will configure the engine, load
+ * the transform information and then start the packet processing.
+ */
+static int mtk_aes_xmit(struct mtk_cryp *cryp, struct mtk_aes_rec *aes)
+{
+	struct mtk_ring *ring = cryp->ring[aes->id];
+	struct mtk_desc *cmd = NULL, *res = NULL;
+	struct scatterlist *ssg = aes->src.sg, *dsg = aes->dst.sg;
+	u32 slen = aes->src.sg_len, dlen = aes->dst.sg_len;
+	int nents;
+
+	/* Write command descriptors */
+	for (nents = 0; nents < slen; ++nents, ssg = sg_next(ssg)) {
+		cmd = ring->cmd_next;
+		cmd->hdr = MTK_DESC_BUF_LEN(ssg->length);
+		cmd->buf = cpu_to_le32(sg_dma_address(ssg));
+
+		if (nents == 0) {
+			cmd->hdr |= MTK_DESC_FIRST |
+				    MTK_DESC_CT_LEN(aes->ctx->ct_size);
+			cmd->ct = cpu_to_le32(aes->ctx->ct_dma);
+			cmd->ct_hdr = aes->ctx->ct_hdr;
+			cmd->tfm = cpu_to_le32(aes->ctx->tfm_dma);
+		}
+
+		/* Shift ring buffer and check boundary */
+		if (++ring->cmd_next == ring->cmd_base + MTK_DESC_NUM)
+			ring->cmd_next = ring->cmd_base;
+	}
+	cmd->hdr |= MTK_DESC_LAST;
+
+	/* Prepare result descriptors */
+	for (nents = 0; nents < dlen; ++nents, dsg = sg_next(dsg)) {
+		res = ring->res_next;
+		res->hdr = MTK_DESC_BUF_LEN(dsg->length);
+		res->buf = cpu_to_le32(sg_dma_address(dsg));
+
+		if (nents == 0)
+			res->hdr |= MTK_DESC_FIRST;
+
+		/* Shift ring buffer and check boundary */
+		if (++ring->res_next == ring->res_base + MTK_DESC_NUM)
+			ring->res_next = ring->res_base;
+	}
+	res->hdr |= MTK_DESC_LAST;
+
+	/* Pointer to current result descriptor */
+	ring->res_prev = res;
+
+	/* Prepare enough space for authenticated tag */
+	if (aes->flags & AES_FLAGS_GCM)
+		res->hdr += AES_BLOCK_SIZE;
+
+	/*
+	 * Make sure that all changes to the DMA ring are done before we
+	 * start engine.
+	 */
+	wmb();
+	/* Start DMA transfer */
+	mtk_aes_write(cryp, RDR_PREP_COUNT(aes->id), MTK_DESC_CNT(dlen));
+	mtk_aes_write(cryp, CDR_PREP_COUNT(aes->id), MTK_DESC_CNT(slen));
+
+	return -EINPROGRESS;
+}
+
+static void mtk_aes_unmap(struct mtk_cryp *cryp, struct mtk_aes_rec *aes)
+{
+	struct mtk_aes_base_ctx *ctx = aes->ctx;
+
+	dma_unmap_single(cryp->dev, ctx->ct_dma, sizeof(ctx->info),
+			 DMA_TO_DEVICE);
+
+	if (aes->src.sg == aes->dst.sg) {
+		dma_unmap_sg(cryp->dev, aes->src.sg, aes->src.nents,
+			     DMA_BIDIRECTIONAL);
+
+		if (aes->src.sg != &aes->aligned_sg)
+			mtk_aes_restore_sg(&aes->src);
+	} else {
+		dma_unmap_sg(cryp->dev, aes->dst.sg, aes->dst.nents,
+			     DMA_FROM_DEVICE);
+
+		if (aes->dst.sg != &aes->aligned_sg)
+			mtk_aes_restore_sg(&aes->dst);
+
+		dma_unmap_sg(cryp->dev, aes->src.sg, aes->src.nents,
+			     DMA_TO_DEVICE);
+
+		if (aes->src.sg != &aes->aligned_sg)
+			mtk_aes_restore_sg(&aes->src);
+	}
+
+	if (aes->dst.sg == &aes->aligned_sg)
+		sg_copy_from_buffer(aes->real_dst, sg_nents(aes->real_dst),
+				    aes->buf, aes->total);
+}
+
+static int mtk_aes_map(struct mtk_cryp *cryp, struct mtk_aes_rec *aes)
+{
+	struct mtk_aes_base_ctx *ctx = aes->ctx;
+	struct mtk_aes_info *info = &ctx->info;
+
+	ctx->ct_dma = dma_map_single(cryp->dev, info, sizeof(*info),
+				     DMA_TO_DEVICE);
+	if (unlikely(dma_mapping_error(cryp->dev, ctx->ct_dma)))
+		goto exit;
+
+	ctx->tfm_dma = ctx->ct_dma + sizeof(info->cmd);
+
+	if (aes->src.sg == aes->dst.sg) {
+		aes->src.sg_len = dma_map_sg(cryp->dev, aes->src.sg,
+					     aes->src.nents,
+					     DMA_BIDIRECTIONAL);
+		aes->dst.sg_len = aes->src.sg_len;
+		if (unlikely(!aes->src.sg_len))
+			goto sg_map_err;
+	} else {
+		aes->src.sg_len = dma_map_sg(cryp->dev, aes->src.sg,
+					     aes->src.nents, DMA_TO_DEVICE);
+		if (unlikely(!aes->src.sg_len))
+			goto sg_map_err;
+
+		aes->dst.sg_len = dma_map_sg(cryp->dev, aes->dst.sg,
+					     aes->dst.nents, DMA_FROM_DEVICE);
+		if (unlikely(!aes->dst.sg_len)) {
+			dma_unmap_sg(cryp->dev, aes->src.sg, aes->src.nents,
+				     DMA_TO_DEVICE);
+			goto sg_map_err;
+		}
+	}
+
+	return mtk_aes_xmit(cryp, aes);
+
+sg_map_err:
+	dma_unmap_single(cryp->dev, ctx->ct_dma, sizeof(*info), DMA_TO_DEVICE);
+exit:
+	return mtk_aes_complete(cryp, aes, -EINVAL);
+}
+
+/* Initialize transform information of CBC/ECB/CTR mode */
+static void mtk_aes_info_init(struct mtk_cryp *cryp, struct mtk_aes_rec *aes,
+			      size_t len)
+{
+	struct ablkcipher_request *req = ablkcipher_request_cast(aes->areq);
+	struct mtk_aes_base_ctx *ctx = aes->ctx;
+	struct mtk_aes_info *info = &ctx->info;
+	u32 cnt = 0;
+
+	ctx->ct_hdr = AES_CT_CTRL_HDR | cpu_to_le32(len);
+	info->cmd[cnt++] = AES_CMD0 | cpu_to_le32(len);
+	info->cmd[cnt++] = AES_CMD1;
+
+	info->tfm[0] = AES_TFM_SIZE(ctx->keylen) | ctx->keymode;
+	if (aes->flags & AES_FLAGS_ENCRYPT)
+		info->tfm[0] |= AES_TFM_BASIC_OUT;
+	else
+		info->tfm[0] |= AES_TFM_BASIC_IN;
+
+	switch (aes->flags & AES_FLAGS_CIPHER_MSK) {
+	case AES_FLAGS_CBC:
+		info->tfm[1] = AES_TFM_CBC;
+		break;
+	case AES_FLAGS_ECB:
+		info->tfm[1] = AES_TFM_ECB;
+		goto ecb;
+	case AES_FLAGS_CTR:
+		info->tfm[1] = AES_TFM_CTR_LOAD;
+		goto ctr;
+
+	default:
+		/* Should not happen... */
+		return;
+	}
+
+	mtk_aes_write_state_le(info->state + ctx->keylen, req->info,
+			       AES_BLOCK_SIZE);
+ctr:
+	info->tfm[0] += AES_TFM_SIZE(SIZE_IN_WORDS(AES_BLOCK_SIZE));
+	info->tfm[1] |= AES_TFM_FULL_IV;
+	info->cmd[cnt++] = AES_CMD2;
+ecb:
+	ctx->ct_size = cnt;
+}
+
+static int mtk_aes_dma(struct mtk_cryp *cryp, struct mtk_aes_rec *aes,
+		       struct scatterlist *src, struct scatterlist *dst,
+		       size_t len)
+{
+	size_t padlen = 0;
+	bool src_aligned, dst_aligned;
+
+	aes->total = len;
+	aes->src.sg = src;
+	aes->dst.sg = dst;
+	aes->real_dst = dst;
+
+	src_aligned = mtk_aes_check_aligned(src, len, &aes->src);
+	if (src == dst)
+		dst_aligned = src_aligned;
+	else
+		dst_aligned = mtk_aes_check_aligned(dst, len, &aes->dst);
+
+	if (!src_aligned || !dst_aligned) {
+		padlen = mtk_aes_padlen(len);
+
+		if (len + padlen > AES_BUF_SIZE)
+			return mtk_aes_complete(cryp, aes, -ENOMEM);
+
+		if (!src_aligned) {
+			sg_copy_to_buffer(src, sg_nents(src), aes->buf, len);
+			aes->src.sg = &aes->aligned_sg;
+			aes->src.nents = 1;
+			aes->src.remainder = 0;
+		}
+
+		if (!dst_aligned) {
+			aes->dst.sg = &aes->aligned_sg;
+			aes->dst.nents = 1;
+			aes->dst.remainder = 0;
+		}
+
+		sg_init_table(&aes->aligned_sg, 1);
+		sg_set_buf(&aes->aligned_sg, aes->buf, len + padlen);
+	}
+
+	mtk_aes_info_init(cryp, aes, len + padlen);
+
+	return mtk_aes_map(cryp, aes);
+}
+
+static int mtk_aes_handle_queue(struct mtk_cryp *cryp, u8 id,
+				struct crypto_async_request *new_areq)
+{
+	struct mtk_aes_rec *aes = cryp->aes[id];
+	struct crypto_async_request *areq, *backlog;
+	struct mtk_aes_base_ctx *ctx;
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&aes->lock, flags);
+	if (new_areq)
+		ret = crypto_enqueue_request(&aes->queue, new_areq);
+	if (aes->flags & AES_FLAGS_BUSY) {
+		spin_unlock_irqrestore(&aes->lock, flags);
+		return ret;
+	}
+	backlog = crypto_get_backlog(&aes->queue);
+	areq = crypto_dequeue_request(&aes->queue);
+	if (areq)
+		aes->flags |= AES_FLAGS_BUSY;
+	spin_unlock_irqrestore(&aes->lock, flags);
+
+	if (!areq)
+		return ret;
+
+	if (backlog)
+		backlog->complete(backlog, -EINPROGRESS);
+
+	ctx = crypto_tfm_ctx(areq->tfm);
+
+	aes->areq = areq;
+	aes->ctx = ctx;
+
+	return ctx->start(cryp, aes);
+}
+
+static int mtk_aes_transfer_complete(struct mtk_cryp *cryp,
+				     struct mtk_aes_rec *aes)
+{
+	return mtk_aes_complete(cryp, aes, 0);
+}
+
+static int mtk_aes_start(struct mtk_cryp *cryp, struct mtk_aes_rec *aes)
+{
+	struct ablkcipher_request *req = ablkcipher_request_cast(aes->areq);
+	struct mtk_aes_reqctx *rctx = ablkcipher_request_ctx(req);
+
+	mtk_aes_set_mode(aes, rctx);
+	aes->resume = mtk_aes_transfer_complete;
+
+	return mtk_aes_dma(cryp, aes, req->src, req->dst, req->nbytes);
+}
+
+static inline struct mtk_aes_ctr_ctx *
+mtk_aes_ctr_ctx_cast(struct mtk_aes_base_ctx *ctx)
+{
+	return container_of(ctx, struct mtk_aes_ctr_ctx, base);
+}
+
+static int mtk_aes_ctr_transfer(struct mtk_cryp *cryp, struct mtk_aes_rec *aes)
+{
+	struct mtk_aes_base_ctx *ctx = aes->ctx;
+	struct mtk_aes_ctr_ctx *cctx = mtk_aes_ctr_ctx_cast(ctx);
+	struct ablkcipher_request *req = ablkcipher_request_cast(aes->areq);
+	struct scatterlist *src, *dst;
+	u32 start, end, ctr, blocks;
+	size_t datalen;
+	bool fragmented = false;
+
+	/* Check for transfer completion. */
+	cctx->offset += aes->total;
+	if (cctx->offset >= req->nbytes)
+		return mtk_aes_transfer_complete(cryp, aes);
+
+	/* Compute data length. */
+	datalen = req->nbytes - cctx->offset;
+	blocks = DIV_ROUND_UP(datalen, AES_BLOCK_SIZE);
+	ctr = be32_to_cpu(cctx->iv[3]);
+
+	/* Check 32bit counter overflow. */
+	start = ctr;
+	end = start + blocks - 1;
+	if (end < start) {
+		ctr |= 0xffffffff;
+		datalen = AES_BLOCK_SIZE * -start;
+		fragmented = true;
+	}
+
+	/* Jump to offset. */
+	src = scatterwalk_ffwd(cctx->src, req->src, cctx->offset);
+	dst = ((req->src == req->dst) ? src :
+	       scatterwalk_ffwd(cctx->dst, req->dst, cctx->offset));
+
+	/* Write IVs into transform state buffer. */
+	mtk_aes_write_state_le(ctx->info.state + ctx->keylen, cctx->iv,
+			       AES_BLOCK_SIZE);
+
+	if (unlikely(fragmented)) {
+	/*
+	 * Increment the counter manually to cope with the hardware
+	 * counter overflow.
+	 */
+		cctx->iv[3] = cpu_to_be32(ctr);
+		crypto_inc((u8 *)cctx->iv, AES_BLOCK_SIZE);
+	}
+
+	return mtk_aes_dma(cryp, aes, src, dst, datalen);
+}
+
+static int mtk_aes_ctr_start(struct mtk_cryp *cryp, struct mtk_aes_rec *aes)
+{
+	struct mtk_aes_ctr_ctx *cctx = mtk_aes_ctr_ctx_cast(aes->ctx);
+	struct ablkcipher_request *req = ablkcipher_request_cast(aes->areq);
+	struct mtk_aes_reqctx *rctx = ablkcipher_request_ctx(req);
+
+	mtk_aes_set_mode(aes, rctx);
+
+	memcpy(cctx->iv, req->info, AES_BLOCK_SIZE);
+	cctx->offset = 0;
+	aes->total = 0;
+	aes->resume = mtk_aes_ctr_transfer;
+
+	return mtk_aes_ctr_transfer(cryp, aes);
+}
+
+/* Check and set the AES key to transform state buffer */
+static int mtk_aes_setkey(struct crypto_ablkcipher *tfm,
+			  const u8 *key, u32 keylen)
+{
+	struct mtk_aes_base_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+
+	switch (keylen) {
+	case AES_KEYSIZE_128:
+		ctx->keymode = AES_TFM_128BITS;
+		break;
+	case AES_KEYSIZE_192:
+		ctx->keymode = AES_TFM_192BITS;
+		break;
+	case AES_KEYSIZE_256:
+		ctx->keymode = AES_TFM_256BITS;
+		break;
+
+	default:
+		crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+		return -EINVAL;
+	}
+
+	ctx->keylen = SIZE_IN_WORDS(keylen);
+	mtk_aes_write_state_le(ctx->info.state, (const u32 *)key, keylen);
+
+	return 0;
+}
+
+static int mtk_aes_crypt(struct ablkcipher_request *req, u64 mode)
+{
+	struct mtk_aes_base_ctx *ctx;
+	struct mtk_aes_reqctx *rctx;
+
+	ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req));
+	rctx = ablkcipher_request_ctx(req);
+	rctx->mode = mode;
+
+	return mtk_aes_handle_queue(ctx->cryp, !(mode & AES_FLAGS_ENCRYPT),
+				    &req->base);
+}
+
+static int mtk_aes_ecb_encrypt(struct ablkcipher_request *req)
+{
+	return mtk_aes_crypt(req, AES_FLAGS_ENCRYPT | AES_FLAGS_ECB);
+}
+
+static int mtk_aes_ecb_decrypt(struct ablkcipher_request *req)
+{
+	return mtk_aes_crypt(req, AES_FLAGS_ECB);
+}
+
+static int mtk_aes_cbc_encrypt(struct ablkcipher_request *req)
+{
+	return mtk_aes_crypt(req, AES_FLAGS_ENCRYPT | AES_FLAGS_CBC);
+}
+
+static int mtk_aes_cbc_decrypt(struct ablkcipher_request *req)
+{
+	return mtk_aes_crypt(req, AES_FLAGS_CBC);
+}
+
+static int mtk_aes_ctr_encrypt(struct ablkcipher_request *req)
+{
+	return mtk_aes_crypt(req, AES_FLAGS_ENCRYPT | AES_FLAGS_CTR);
+}
+
+static int mtk_aes_ctr_decrypt(struct ablkcipher_request *req)
+{
+	return mtk_aes_crypt(req, AES_FLAGS_CTR);
+}
+
+static int mtk_aes_cra_init(struct crypto_tfm *tfm)
+{
+	struct mtk_aes_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct mtk_cryp *cryp = NULL;
+
+	cryp = mtk_aes_find_dev(&ctx->base);
+	if (!cryp) {
+		pr_err("can't find crypto device\n");
+		return -ENODEV;
+	}
+
+	tfm->crt_ablkcipher.reqsize = sizeof(struct mtk_aes_reqctx);
+	ctx->base.start = mtk_aes_start;
+	return 0;
+}
+
+static int mtk_aes_ctr_cra_init(struct crypto_tfm *tfm)
+{
+	struct mtk_aes_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct mtk_cryp *cryp = NULL;
+
+	cryp = mtk_aes_find_dev(&ctx->base);
+	if (!cryp) {
+		pr_err("can't find crypto device\n");
+		return -ENODEV;
+	}
+
+	tfm->crt_ablkcipher.reqsize = sizeof(struct mtk_aes_reqctx);
+	ctx->base.start = mtk_aes_ctr_start;
+	return 0;
+}
+
+static struct crypto_alg aes_algs[] = {
+{
+	.cra_name		= "cbc(aes)",
+	.cra_driver_name	= "cbc-aes-mtk",
+	.cra_priority		= 400,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER |
+				  CRYPTO_ALG_ASYNC,
+	.cra_init		= mtk_aes_cra_init,
+	.cra_blocksize		= AES_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct mtk_aes_ctx),
+	.cra_alignmask		= 0xf,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_u.ablkcipher = {
+		.min_keysize	= AES_MIN_KEY_SIZE,
+		.max_keysize	= AES_MAX_KEY_SIZE,
+		.setkey		= mtk_aes_setkey,
+		.encrypt	= mtk_aes_cbc_encrypt,
+		.decrypt	= mtk_aes_cbc_decrypt,
+		.ivsize		= AES_BLOCK_SIZE,
+	}
+},
+{
+	.cra_name		= "ecb(aes)",
+	.cra_driver_name	= "ecb-aes-mtk",
+	.cra_priority		= 400,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER |
+				  CRYPTO_ALG_ASYNC,
+	.cra_init		= mtk_aes_cra_init,
+	.cra_blocksize		= AES_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct mtk_aes_ctx),
+	.cra_alignmask		= 0xf,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_u.ablkcipher = {
+		.min_keysize	= AES_MIN_KEY_SIZE,
+		.max_keysize	= AES_MAX_KEY_SIZE,
+		.setkey		= mtk_aes_setkey,
+		.encrypt	= mtk_aes_ecb_encrypt,
+		.decrypt	= mtk_aes_ecb_decrypt,
+	}
+},
+{
+	.cra_name		= "ctr(aes)",
+	.cra_driver_name	= "ctr-aes-mtk",
+	.cra_priority		= 400,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER |
+				  CRYPTO_ALG_ASYNC,
+	.cra_init		= mtk_aes_ctr_cra_init,
+	.cra_blocksize		= 1,
+	.cra_ctxsize		= sizeof(struct mtk_aes_ctr_ctx),
+	.cra_alignmask		= 0xf,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_u.ablkcipher = {
+		.min_keysize	= AES_MIN_KEY_SIZE,
+		.max_keysize	= AES_MAX_KEY_SIZE,
+		.ivsize		= AES_BLOCK_SIZE,
+		.setkey		= mtk_aes_setkey,
+		.encrypt	= mtk_aes_ctr_encrypt,
+		.decrypt	= mtk_aes_ctr_decrypt,
+	}
+},
+};
+
+static inline struct mtk_aes_gcm_ctx *
+mtk_aes_gcm_ctx_cast(struct mtk_aes_base_ctx *ctx)
+{
+	return container_of(ctx, struct mtk_aes_gcm_ctx, base);
+}
+
+/*
+ * Engine will verify and compare tag automatically, so we just need
+ * to check returned status which stored in the result descriptor.
+ */
+static int mtk_aes_gcm_tag_verify(struct mtk_cryp *cryp,
+				  struct mtk_aes_rec *aes)
+{
+	u32 status = cryp->ring[aes->id]->res_prev->ct;
+
+	return mtk_aes_complete(cryp, aes, (status & AES_AUTH_TAG_ERR) ?
+				-EBADMSG : 0);
+}
+
+/* Initialize transform information of GCM mode */
+static void mtk_aes_gcm_info_init(struct mtk_cryp *cryp,
+				  struct mtk_aes_rec *aes,
+				  size_t len)
+{
+	struct aead_request *req = aead_request_cast(aes->areq);
+	struct mtk_aes_base_ctx *ctx = aes->ctx;
+	struct mtk_aes_gcm_ctx *gctx = mtk_aes_gcm_ctx_cast(ctx);
+	struct mtk_aes_info *info = &ctx->info;
+	u32 ivsize = crypto_aead_ivsize(crypto_aead_reqtfm(req));
+	u32 cnt = 0;
+
+	ctx->ct_hdr = AES_CT_CTRL_HDR | len;
+
+	info->cmd[cnt++] = AES_GCM_CMD0 | cpu_to_le32(req->assoclen);
+	info->cmd[cnt++] = AES_GCM_CMD1 | cpu_to_le32(req->assoclen);
+	info->cmd[cnt++] = AES_GCM_CMD2;
+	info->cmd[cnt++] = AES_GCM_CMD3 | cpu_to_le32(gctx->textlen);
+
+	if (aes->flags & AES_FLAGS_ENCRYPT) {
+		info->cmd[cnt++] = AES_GCM_CMD4 | cpu_to_le32(gctx->authsize);
+		info->tfm[0] = AES_TFM_GCM_OUT;
+	} else {
+		info->cmd[cnt++] = AES_GCM_CMD5 | cpu_to_le32(gctx->authsize);
+		info->cmd[cnt++] = AES_GCM_CMD6 | cpu_to_le32(gctx->authsize);
+		info->tfm[0] = AES_TFM_GCM_IN;
+	}
+	ctx->ct_size = cnt;
+
+	info->tfm[0] |= AES_TFM_GHASH_DIGEST | AES_TFM_GHASH | AES_TFM_SIZE(
+			ctx->keylen + SIZE_IN_WORDS(AES_BLOCK_SIZE + ivsize)) |
+			ctx->keymode;
+	info->tfm[1] = AES_TFM_CTR_INIT | AES_TFM_IV_CTR_MODE | AES_TFM_3IV |
+		       AES_TFM_ENC_HASH;
+
+	mtk_aes_write_state_le(info->state + ctx->keylen + SIZE_IN_WORDS(
+			       AES_BLOCK_SIZE), (const u32 *)req->iv, ivsize);
+}
+
+static int mtk_aes_gcm_dma(struct mtk_cryp *cryp, struct mtk_aes_rec *aes,
+			   struct scatterlist *src, struct scatterlist *dst,
+			   size_t len)
+{
+	bool src_aligned, dst_aligned;
+
+	aes->src.sg = src;
+	aes->dst.sg = dst;
+	aes->real_dst = dst;
+
+	src_aligned = mtk_aes_check_aligned(src, len, &aes->src);
+	if (src == dst)
+		dst_aligned = src_aligned;
+	else
+		dst_aligned = mtk_aes_check_aligned(dst, len, &aes->dst);
+
+	if (!src_aligned || !dst_aligned) {
+		if (aes->total > AES_BUF_SIZE)
+			return mtk_aes_complete(cryp, aes, -ENOMEM);
+
+		if (!src_aligned) {
+			sg_copy_to_buffer(src, sg_nents(src), aes->buf, len);
+			aes->src.sg = &aes->aligned_sg;
+			aes->src.nents = 1;
+			aes->src.remainder = 0;
+		}
+
+		if (!dst_aligned) {
+			aes->dst.sg = &aes->aligned_sg;
+			aes->dst.nents = 1;
+			aes->dst.remainder = 0;
+		}
+
+		sg_init_table(&aes->aligned_sg, 1);
+		sg_set_buf(&aes->aligned_sg, aes->buf, aes->total);
+	}
+
+	mtk_aes_gcm_info_init(cryp, aes, len);
+
+	return mtk_aes_map(cryp, aes);
+}
+
+/* Todo: GMAC */
+static int mtk_aes_gcm_start(struct mtk_cryp *cryp, struct mtk_aes_rec *aes)
+{
+	struct mtk_aes_gcm_ctx *gctx = mtk_aes_gcm_ctx_cast(aes->ctx);
+	struct aead_request *req = aead_request_cast(aes->areq);
+	struct mtk_aes_reqctx *rctx = aead_request_ctx(req);
+	u32 len = req->assoclen + req->cryptlen;
+
+	mtk_aes_set_mode(aes, rctx);
+
+	if (aes->flags & AES_FLAGS_ENCRYPT) {
+		u32 tag[4];
+
+		aes->resume = mtk_aes_transfer_complete;
+		/* Compute total process length. */
+		aes->total = len + gctx->authsize;
+		/* Compute text length. */
+		gctx->textlen = req->cryptlen;
+		/* Hardware will append authenticated tag to output buffer */
+		scatterwalk_map_and_copy(tag, req->dst, len, gctx->authsize, 1);
+	} else {
+		aes->resume = mtk_aes_gcm_tag_verify;
+		aes->total = len;
+		gctx->textlen = req->cryptlen - gctx->authsize;
+	}
+
+	return mtk_aes_gcm_dma(cryp, aes, req->src, req->dst, len);
+}
+
+static int mtk_aes_gcm_crypt(struct aead_request *req, u64 mode)
+{
+	struct mtk_aes_base_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
+	struct mtk_aes_reqctx *rctx = aead_request_ctx(req);
+
+	rctx->mode = AES_FLAGS_GCM | mode;
+
+	return mtk_aes_handle_queue(ctx->cryp, !!(mode & AES_FLAGS_ENCRYPT),
+				    &req->base);
+}
+
+static void mtk_gcm_setkey_done(struct crypto_async_request *req, int err)
+{
+	struct mtk_aes_gcm_setkey_result *result = req->data;
+
+	if (err == -EINPROGRESS)
+		return;
+
+	result->err = err;
+	complete(&result->completion);
+}
+
+/*
+ * Because of the hardware limitation, we need to pre-calculate key(H)
+ * for the GHASH operation. The result of the encryption operation
+ * need to be stored in the transform state buffer.
+ */
+static int mtk_aes_gcm_setkey(struct crypto_aead *aead, const u8 *key,
+			      u32 keylen)
+{
+	struct mtk_aes_base_ctx *ctx = crypto_aead_ctx(aead);
+	struct mtk_aes_gcm_ctx *gctx = mtk_aes_gcm_ctx_cast(ctx);
+	struct crypto_skcipher *ctr = gctx->ctr;
+	struct {
+		u32 hash[4];
+		u8 iv[8];
+
+		struct mtk_aes_gcm_setkey_result result;
+
+		struct scatterlist sg[1];
+		struct skcipher_request req;
+	} *data;
+	int err;
+
+	switch (keylen) {
+	case AES_KEYSIZE_128:
+		ctx->keymode = AES_TFM_128BITS;
+		break;
+	case AES_KEYSIZE_192:
+		ctx->keymode = AES_TFM_192BITS;
+		break;
+	case AES_KEYSIZE_256:
+		ctx->keymode = AES_TFM_256BITS;
+		break;
+
+	default:
+		crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN);
+		return -EINVAL;
+	}
+
+	ctx->keylen = SIZE_IN_WORDS(keylen);
+
+	/* Same as crypto_gcm_setkey() from crypto/gcm.c */
+	crypto_skcipher_clear_flags(ctr, CRYPTO_TFM_REQ_MASK);
+	crypto_skcipher_set_flags(ctr, crypto_aead_get_flags(aead) &
+				  CRYPTO_TFM_REQ_MASK);
+	err = crypto_skcipher_setkey(ctr, key, keylen);
+	crypto_aead_set_flags(aead, crypto_skcipher_get_flags(ctr) &
+			      CRYPTO_TFM_RES_MASK);
+	if (err)
+		return err;
+
+	data = kzalloc(sizeof(*data) + crypto_skcipher_reqsize(ctr),
+		       GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	init_completion(&data->result.completion);
+	sg_init_one(data->sg, &data->hash, AES_BLOCK_SIZE);
+	skcipher_request_set_tfm(&data->req, ctr);
+	skcipher_request_set_callback(&data->req, CRYPTO_TFM_REQ_MAY_SLEEP |
+				      CRYPTO_TFM_REQ_MAY_BACKLOG,
+				      mtk_gcm_setkey_done, &data->result);
+	skcipher_request_set_crypt(&data->req, data->sg, data->sg,
+				   AES_BLOCK_SIZE, data->iv);
+
+	err = crypto_skcipher_encrypt(&data->req);
+	if (err == -EINPROGRESS || err == -EBUSY) {
+		err = wait_for_completion_interruptible(
+			&data->result.completion);
+		if (!err)
+			err = data->result.err;
+	}
+	if (err)
+		goto out;
+
+	/* Write key into state buffer */
+	mtk_aes_write_state_le(ctx->info.state, (const u32 *)key, keylen);
+	/* Write key(H) into state buffer */
+	mtk_aes_write_state_be(ctx->info.state + ctx->keylen, data->hash,
+			       AES_BLOCK_SIZE);
+out:
+	kzfree(data);
+	return err;
+}
+
+static int mtk_aes_gcm_setauthsize(struct crypto_aead *aead,
+				   u32 authsize)
+{
+	struct mtk_aes_base_ctx *ctx = crypto_aead_ctx(aead);
+	struct mtk_aes_gcm_ctx *gctx = mtk_aes_gcm_ctx_cast(ctx);
+
+	/* Same as crypto_gcm_authsize() from crypto/gcm.c */
+	switch (authsize) {
+	case 8:
+	case 12:
+	case 16:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	gctx->authsize = authsize;
+	return 0;
+}
+
+static int mtk_aes_gcm_encrypt(struct aead_request *req)
+{
+	return mtk_aes_gcm_crypt(req, AES_FLAGS_ENCRYPT);
+}
+
+static int mtk_aes_gcm_decrypt(struct aead_request *req)
+{
+	return mtk_aes_gcm_crypt(req, 0);
+}
+
+static int mtk_aes_gcm_init(struct crypto_aead *aead)
+{
+	struct mtk_aes_gcm_ctx *ctx = crypto_aead_ctx(aead);
+	struct mtk_cryp *cryp = NULL;
+
+	cryp = mtk_aes_find_dev(&ctx->base);
+	if (!cryp) {
+		pr_err("can't find crypto device\n");
+		return -ENODEV;
+	}
+
+	ctx->ctr = crypto_alloc_skcipher("ctr(aes)", 0,
+					 CRYPTO_ALG_ASYNC);
+	if (IS_ERR(ctx->ctr)) {
+		pr_err("Error allocating ctr(aes)\n");
+		return PTR_ERR(ctx->ctr);
+	}
+
+	crypto_aead_set_reqsize(aead, sizeof(struct mtk_aes_reqctx));
+	ctx->base.start = mtk_aes_gcm_start;
+	return 0;
+}
+
+static void mtk_aes_gcm_exit(struct crypto_aead *aead)
+{
+	struct mtk_aes_gcm_ctx *ctx = crypto_aead_ctx(aead);
+
+	crypto_free_skcipher(ctx->ctr);
+}
+
+static struct aead_alg aes_gcm_alg = {
+	.setkey		= mtk_aes_gcm_setkey,
+	.setauthsize	= mtk_aes_gcm_setauthsize,
+	.encrypt	= mtk_aes_gcm_encrypt,
+	.decrypt	= mtk_aes_gcm_decrypt,
+	.init		= mtk_aes_gcm_init,
+	.exit		= mtk_aes_gcm_exit,
+	.ivsize		= 12,
+	.maxauthsize	= AES_BLOCK_SIZE,
+
+	.base = {
+		.cra_name		= "gcm(aes)",
+		.cra_driver_name	= "gcm-aes-mtk",
+		.cra_priority		= 400,
+		.cra_flags		= CRYPTO_ALG_ASYNC,
+		.cra_blocksize		= 1,
+		.cra_ctxsize		= sizeof(struct mtk_aes_gcm_ctx),
+		.cra_alignmask		= 0xf,
+		.cra_module		= THIS_MODULE,
+	},
+};
+
+static void mtk_aes_queue_task(unsigned long data)
+{
+	struct mtk_aes_rec *aes = (struct mtk_aes_rec *)data;
+
+	mtk_aes_handle_queue(aes->cryp, aes->id, NULL);
+}
+
+static void mtk_aes_done_task(unsigned long data)
+{
+	struct mtk_aes_rec *aes = (struct mtk_aes_rec *)data;
+	struct mtk_cryp *cryp = aes->cryp;
+
+	mtk_aes_unmap(cryp, aes);
+	aes->resume(cryp, aes);
+}
+
+static irqreturn_t mtk_aes_irq(int irq, void *dev_id)
+{
+	struct mtk_aes_rec *aes  = (struct mtk_aes_rec *)dev_id;
+	struct mtk_cryp *cryp = aes->cryp;
+	u32 val = mtk_aes_read(cryp, RDR_STAT(aes->id));
+
+	mtk_aes_write(cryp, RDR_STAT(aes->id), val);
+
+	if (likely(AES_FLAGS_BUSY & aes->flags)) {
+		mtk_aes_write(cryp, RDR_PROC_COUNT(aes->id), MTK_CNT_RST);
+		mtk_aes_write(cryp, RDR_THRESH(aes->id),
+			      MTK_RDR_PROC_THRESH | MTK_RDR_PROC_MODE);
+
+		tasklet_schedule(&aes->done_task);
+	} else {
+		dev_warn(cryp->dev, "AES interrupt when no active requests.\n");
+	}
+	return IRQ_HANDLED;
+}
+
+/*
+ * The purpose of creating encryption and decryption records is
+ * to process outbound/inbound data in parallel, it can improve
+ * performance in most use cases, such as IPSec VPN, especially
+ * under heavy network traffic.
+ */
+static int mtk_aes_record_init(struct mtk_cryp *cryp)
+{
+	struct mtk_aes_rec **aes = cryp->aes;
+	int i, err = -ENOMEM;
+
+	for (i = 0; i < MTK_REC_NUM; i++) {
+		aes[i] = kzalloc(sizeof(**aes), GFP_KERNEL);
+		if (!aes[i])
+			goto err_cleanup;
+
+		aes[i]->buf = (void *)__get_free_pages(GFP_KERNEL,
+						AES_BUF_ORDER);
+		if (!aes[i]->buf)
+			goto err_cleanup;
+
+		aes[i]->cryp = cryp;
+
+		spin_lock_init(&aes[i]->lock);
+		crypto_init_queue(&aes[i]->queue, AES_QUEUE_SIZE);
+
+		tasklet_init(&aes[i]->queue_task, mtk_aes_queue_task,
+			     (unsigned long)aes[i]);
+		tasklet_init(&aes[i]->done_task, mtk_aes_done_task,
+			     (unsigned long)aes[i]);
+	}
+
+	/* Link to ring0 and ring1 respectively */
+	aes[0]->id = MTK_RING0;
+	aes[1]->id = MTK_RING1;
+
+	return 0;
+
+err_cleanup:
+	for (; i--; ) {
+		free_page((unsigned long)aes[i]->buf);
+		kfree(aes[i]);
+	}
+
+	return err;
+}
+
+static void mtk_aes_record_free(struct mtk_cryp *cryp)
+{
+	int i;
+
+	for (i = 0; i < MTK_REC_NUM; i++) {
+		tasklet_kill(&cryp->aes[i]->done_task);
+		tasklet_kill(&cryp->aes[i]->queue_task);
+
+		free_page((unsigned long)cryp->aes[i]->buf);
+		kfree(cryp->aes[i]);
+	}
+}
+
+static void mtk_aes_unregister_algs(void)
+{
+	int i;
+
+	crypto_unregister_aead(&aes_gcm_alg);
+
+	for (i = 0; i < ARRAY_SIZE(aes_algs); i++)
+		crypto_unregister_alg(&aes_algs[i]);
+}
+
+static int mtk_aes_register_algs(void)
+{
+	int err, i;
+
+	for (i = 0; i < ARRAY_SIZE(aes_algs); i++) {
+		err = crypto_register_alg(&aes_algs[i]);
+		if (err)
+			goto err_aes_algs;
+	}
+
+	err = crypto_register_aead(&aes_gcm_alg);
+	if (err)
+		goto err_aes_algs;
+
+	return 0;
+
+err_aes_algs:
+	for (; i--; )
+		crypto_unregister_alg(&aes_algs[i]);
+
+	return err;
+}
+
+int mtk_cipher_alg_register(struct mtk_cryp *cryp)
+{
+	int ret;
+
+	INIT_LIST_HEAD(&cryp->aes_list);
+
+	/* Initialize two cipher records */
+	ret = mtk_aes_record_init(cryp);
+	if (ret)
+		goto err_record;
+
+	ret = devm_request_irq(cryp->dev, cryp->irq[MTK_RING0], mtk_aes_irq,
+			       0, "mtk-aes", cryp->aes[0]);
+	if (ret) {
+		dev_err(cryp->dev, "unable to request AES irq.\n");
+		goto err_res;
+	}
+
+	ret = devm_request_irq(cryp->dev, cryp->irq[MTK_RING1], mtk_aes_irq,
+			       0, "mtk-aes", cryp->aes[1]);
+	if (ret) {
+		dev_err(cryp->dev, "unable to request AES irq.\n");
+		goto err_res;
+	}
+
+	/* Enable ring0 and ring1 interrupt */
+	mtk_aes_write(cryp, AIC_ENABLE_SET(MTK_RING0), MTK_IRQ_RDR0);
+	mtk_aes_write(cryp, AIC_ENABLE_SET(MTK_RING1), MTK_IRQ_RDR1);
+
+	spin_lock(&mtk_aes.lock);
+	list_add_tail(&cryp->aes_list, &mtk_aes.dev_list);
+	spin_unlock(&mtk_aes.lock);
+
+	ret = mtk_aes_register_algs();
+	if (ret)
+		goto err_algs;
+
+	return 0;
+
+err_algs:
+	spin_lock(&mtk_aes.lock);
+	list_del(&cryp->aes_list);
+	spin_unlock(&mtk_aes.lock);
+err_res:
+	mtk_aes_record_free(cryp);
+err_record:
+
+	dev_err(cryp->dev, "mtk-aes initialization failed.\n");
+	return ret;
+}
+
+void mtk_cipher_alg_release(struct mtk_cryp *cryp)
+{
+	spin_lock(&mtk_aes.lock);
+	list_del(&cryp->aes_list);
+	spin_unlock(&mtk_aes.lock);
+
+	mtk_aes_unregister_algs();
+	mtk_aes_record_free(cryp);
+}

+ 607 - 0
target/linux/mediatek/files/drivers/crypto/mediatek/mtk-platform.c

@@ -0,0 +1,607 @@
+/*
+ * Driver for EIP97 cryptographic accelerator.
+ *
+ * Copyright (c) 2016 Ryder Lee <[email protected]>
+ *
+ * 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/clk.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include "mtk-platform.h"
+
+#define MTK_BURST_SIZE_MSK		GENMASK(7, 4)
+#define MTK_BURST_SIZE(x)		((x) << 4)
+#define MTK_DESC_SIZE(x)		((x) << 0)
+#define MTK_DESC_OFFSET(x)		((x) << 16)
+#define MTK_DESC_FETCH_SIZE(x)		((x) << 0)
+#define MTK_DESC_FETCH_THRESH(x)	((x) << 16)
+#define MTK_DESC_OVL_IRQ_EN		BIT(25)
+#define MTK_DESC_ATP_PRESENT		BIT(30)
+
+#define MTK_DFSE_IDLE			GENMASK(3, 0)
+#define MTK_DFSE_THR_CTRL_EN		BIT(30)
+#define MTK_DFSE_THR_CTRL_RESET		BIT(31)
+#define MTK_DFSE_RING_ID(x)		(((x) >> 12) & GENMASK(3, 0))
+#define MTK_DFSE_MIN_DATA(x)		((x) << 0)
+#define MTK_DFSE_MAX_DATA(x)		((x) << 8)
+#define MTK_DFE_MIN_CTRL(x)		((x) << 16)
+#define MTK_DFE_MAX_CTRL(x)		((x) << 24)
+
+#define MTK_IN_BUF_MIN_THRESH(x)	((x) << 8)
+#define MTK_IN_BUF_MAX_THRESH(x)	((x) << 12)
+#define MTK_OUT_BUF_MIN_THRESH(x)	((x) << 0)
+#define MTK_OUT_BUF_MAX_THRESH(x)	((x) << 4)
+#define MTK_IN_TBUF_SIZE(x)		(((x) >> 4) & GENMASK(3, 0))
+#define MTK_IN_DBUF_SIZE(x)		(((x) >> 8) & GENMASK(3, 0))
+#define MTK_OUT_DBUF_SIZE(x)		(((x) >> 16) & GENMASK(3, 0))
+#define MTK_CMD_FIFO_SIZE(x)		(((x) >> 8) & GENMASK(3, 0))
+#define MTK_RES_FIFO_SIZE(x)		(((x) >> 12) & GENMASK(3, 0))
+
+#define MTK_PE_TK_LOC_AVL		BIT(2)
+#define MTK_PE_PROC_HELD		BIT(14)
+#define MTK_PE_TK_TIMEOUT_EN		BIT(22)
+#define MTK_PE_INPUT_DMA_ERR		BIT(0)
+#define MTK_PE_OUTPUT_DMA_ERR		BIT(1)
+#define MTK_PE_PKT_PORC_ERR		BIT(2)
+#define MTK_PE_PKT_TIMEOUT		BIT(3)
+#define MTK_PE_FATAL_ERR		BIT(14)
+#define MTK_PE_INPUT_DMA_ERR_EN		BIT(16)
+#define MTK_PE_OUTPUT_DMA_ERR_EN	BIT(17)
+#define MTK_PE_PKT_PORC_ERR_EN		BIT(18)
+#define MTK_PE_PKT_TIMEOUT_EN		BIT(19)
+#define MTK_PE_FATAL_ERR_EN		BIT(30)
+#define MTK_PE_INT_OUT_EN		BIT(31)
+
+#define MTK_HIA_SIGNATURE		((u16)0x35ca)
+#define MTK_HIA_DATA_WIDTH(x)		(((x) >> 25) & GENMASK(1, 0))
+#define MTK_HIA_DMA_LENGTH(x)		(((x) >> 20) & GENMASK(4, 0))
+#define MTK_CDR_STAT_CLR		GENMASK(4, 0)
+#define MTK_RDR_STAT_CLR		GENMASK(7, 0)
+
+#define MTK_AIC_INT_MSK			GENMASK(5, 0)
+#define MTK_AIC_VER_MSK			(GENMASK(15, 0) | GENMASK(27, 20))
+#define MTK_AIC_VER11			0x011036c9
+#define MTK_AIC_VER12			0x012036c9
+#define MTK_AIC_G_CLR			GENMASK(30, 20)
+
+/**
+ * EIP97 is an integrated security subsystem to accelerate cryptographic
+ * functions and protocols to offload the host processor.
+ * Some important hardware modules are briefly introduced below:
+ *
+ * Host Interface Adapter(HIA) - the main interface between the host
+ * system and the hardware subsystem. It is responsible for attaching
+ * processing engine to the specific host bus interface and provides a
+ * standardized software view for off loading tasks to the engine.
+ *
+ * Command Descriptor Ring Manager(CDR Manager) - keeps track of how many
+ * CD the host has prepared in the CDR. It monitors the fill level of its
+ * CD-FIFO and if there's sufficient space for the next block of descriptors,
+ * then it fires off a DMA request to fetch a block of CDs.
+ *
+ * Data fetch engine(DFE) - It is responsible for parsing the CD and
+ * setting up the required control and packet data DMA transfers from
+ * system memory to the processing engine.
+ *
+ * Result Descriptor Ring Manager(RDR Manager) - same as CDR Manager,
+ * but target is result descriptors, Moreover, it also handles the RD
+ * updates under control of the DSE. For each packet data segment
+ * processed, the DSE triggers the RDR Manager to write the updated RD.
+ * If triggered to update, the RDR Manager sets up a DMA operation to
+ * copy the RD from the DSE to the correct location in the RDR.
+ *
+ * Data Store Engine(DSE) - It is responsible for parsing the prepared RD
+ * and setting up the required control and packet data DMA transfers from
+ * the processing engine to system memory.
+ *
+ * Advanced Interrupt Controllers(AICs) - receive interrupt request signals
+ * from various sources and combine them into one interrupt output.
+ * The AICs are used by:
+ * - One for the HIA global and processing engine interrupts.
+ * - The others for the descriptor ring interrupts.
+ */
+
+/* Cryptographic engine capabilities */
+struct mtk_sys_cap {
+	/* host interface adapter */
+	u32 hia_ver;
+	u32 hia_opt;
+	/* packet engine */
+	u32 pkt_eng_opt;
+	/* global hardware */
+	u32 hw_opt;
+};
+
+static void mtk_desc_ring_link(struct mtk_cryp *cryp, u32 mask)
+{
+	/* Assign rings to DFE/DSE thread and enable it */
+	writel(MTK_DFSE_THR_CTRL_EN | mask, cryp->base + DFE_THR_CTRL);
+	writel(MTK_DFSE_THR_CTRL_EN | mask, cryp->base + DSE_THR_CTRL);
+}
+
+static void mtk_dfe_dse_buf_setup(struct mtk_cryp *cryp,
+				  struct mtk_sys_cap *cap)
+{
+	u32 width = MTK_HIA_DATA_WIDTH(cap->hia_opt) + 2;
+	u32 len = MTK_HIA_DMA_LENGTH(cap->hia_opt) - 1;
+	u32 ipbuf = min((u32)MTK_IN_DBUF_SIZE(cap->hw_opt) + width, len);
+	u32 opbuf = min((u32)MTK_OUT_DBUF_SIZE(cap->hw_opt) + width, len);
+	u32 itbuf = min((u32)MTK_IN_TBUF_SIZE(cap->hw_opt) + width, len);
+
+	writel(MTK_DFSE_MIN_DATA(ipbuf - 1) |
+	       MTK_DFSE_MAX_DATA(ipbuf) |
+	       MTK_DFE_MIN_CTRL(itbuf - 1) |
+	       MTK_DFE_MAX_CTRL(itbuf),
+	       cryp->base + DFE_CFG);
+
+	writel(MTK_DFSE_MIN_DATA(opbuf - 1) |
+	       MTK_DFSE_MAX_DATA(opbuf),
+	       cryp->base + DSE_CFG);
+
+	writel(MTK_IN_BUF_MIN_THRESH(ipbuf - 1) |
+	       MTK_IN_BUF_MAX_THRESH(ipbuf),
+	       cryp->base + PE_IN_DBUF_THRESH);
+
+	writel(MTK_IN_BUF_MIN_THRESH(itbuf - 1) |
+	       MTK_IN_BUF_MAX_THRESH(itbuf),
+	       cryp->base + PE_IN_TBUF_THRESH);
+
+	writel(MTK_OUT_BUF_MIN_THRESH(opbuf - 1) |
+	       MTK_OUT_BUF_MAX_THRESH(opbuf),
+	       cryp->base + PE_OUT_DBUF_THRESH);
+
+	writel(0, cryp->base + PE_OUT_TBUF_THRESH);
+	writel(0, cryp->base + PE_OUT_BUF_CTRL);
+}
+
+static int mtk_dfe_dse_state_check(struct mtk_cryp *cryp)
+{
+	int ret = -EINVAL;
+	u32 val;
+
+	/* Check for completion of all DMA transfers */
+	val = readl(cryp->base + DFE_THR_STAT);
+	if (MTK_DFSE_RING_ID(val) == MTK_DFSE_IDLE) {
+		val = readl(cryp->base + DSE_THR_STAT);
+		if (MTK_DFSE_RING_ID(val) == MTK_DFSE_IDLE)
+			ret = 0;
+	}
+
+	if (!ret) {
+		/* Take DFE/DSE thread out of reset */
+		writel(0, cryp->base + DFE_THR_CTRL);
+		writel(0, cryp->base + DSE_THR_CTRL);
+	} else {
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static int mtk_dfe_dse_reset(struct mtk_cryp *cryp)
+{
+	int err;
+
+	/* Reset DSE/DFE and correct system priorities for all rings. */
+	writel(MTK_DFSE_THR_CTRL_RESET, cryp->base + DFE_THR_CTRL);
+	writel(0, cryp->base + DFE_PRIO_0);
+	writel(0, cryp->base + DFE_PRIO_1);
+	writel(0, cryp->base + DFE_PRIO_2);
+	writel(0, cryp->base + DFE_PRIO_3);
+
+	writel(MTK_DFSE_THR_CTRL_RESET, cryp->base + DSE_THR_CTRL);
+	writel(0, cryp->base + DSE_PRIO_0);
+	writel(0, cryp->base + DSE_PRIO_1);
+	writel(0, cryp->base + DSE_PRIO_2);
+	writel(0, cryp->base + DSE_PRIO_3);
+
+	err = mtk_dfe_dse_state_check(cryp);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static void mtk_cmd_desc_ring_setup(struct mtk_cryp *cryp,
+				    int i, struct mtk_sys_cap *cap)
+{
+	/* Full descriptor that fits FIFO minus one */
+	u32 count =
+		((1 << MTK_CMD_FIFO_SIZE(cap->hia_opt)) / MTK_DESC_SZ) - 1;
+
+	/* Temporarily disable external triggering */
+	writel(0, cryp->base + CDR_CFG(i));
+
+	/* Clear CDR count */
+	writel(MTK_CNT_RST, cryp->base + CDR_PREP_COUNT(i));
+	writel(MTK_CNT_RST, cryp->base + CDR_PROC_COUNT(i));
+
+	writel(0, cryp->base + CDR_PREP_PNTR(i));
+	writel(0, cryp->base + CDR_PROC_PNTR(i));
+	writel(0, cryp->base + CDR_DMA_CFG(i));
+
+	/* Configure CDR host address space */
+	writel(0, cryp->base + CDR_BASE_ADDR_HI(i));
+	writel(cryp->ring[i]->cmd_dma, cryp->base + CDR_BASE_ADDR_LO(i));
+
+	writel(MTK_DESC_RING_SZ, cryp->base + CDR_RING_SIZE(i));
+
+	/* Clear and disable all CDR interrupts */
+	writel(MTK_CDR_STAT_CLR, cryp->base + CDR_STAT(i));
+
+	/*
+	 * Set command descriptor offset and enable additional
+	 * token present in descriptor.
+	 */
+	writel(MTK_DESC_SIZE(MTK_DESC_SZ) |
+		   MTK_DESC_OFFSET(MTK_DESC_OFF) |
+	       MTK_DESC_ATP_PRESENT,
+	       cryp->base + CDR_DESC_SIZE(i));
+
+	writel(MTK_DESC_FETCH_SIZE(count * MTK_DESC_OFF) |
+		   MTK_DESC_FETCH_THRESH(count * MTK_DESC_SZ),
+		   cryp->base + CDR_CFG(i));
+}
+
+static void mtk_res_desc_ring_setup(struct mtk_cryp *cryp,
+				    int i, struct mtk_sys_cap *cap)
+{
+	u32 rndup = 2;
+	u32 count = ((1 << MTK_RES_FIFO_SIZE(cap->hia_opt)) / rndup) - 1;
+
+	/* Temporarily disable external triggering */
+	writel(0, cryp->base + RDR_CFG(i));
+
+	/* Clear RDR count */
+	writel(MTK_CNT_RST, cryp->base + RDR_PREP_COUNT(i));
+	writel(MTK_CNT_RST, cryp->base + RDR_PROC_COUNT(i));
+
+	writel(0, cryp->base + RDR_PREP_PNTR(i));
+	writel(0, cryp->base + RDR_PROC_PNTR(i));
+	writel(0, cryp->base + RDR_DMA_CFG(i));
+
+	/* Configure RDR host address space */
+	writel(0, cryp->base + RDR_BASE_ADDR_HI(i));
+	writel(cryp->ring[i]->res_dma, cryp->base + RDR_BASE_ADDR_LO(i));
+
+	writel(MTK_DESC_RING_SZ, cryp->base + RDR_RING_SIZE(i));
+	writel(MTK_RDR_STAT_CLR, cryp->base + RDR_STAT(i));
+
+	/*
+	 * RDR manager generates update interrupts on a per-completed-packet,
+	 * and the rd_proc_thresh_irq interrupt is fired when proc_pkt_count
+	 * for the RDR exceeds the number of packets.
+	 */
+	writel(MTK_RDR_PROC_THRESH | MTK_RDR_PROC_MODE,
+	       cryp->base + RDR_THRESH(i));
+
+	/*
+	 * Configure a threshold and time-out value for the processed
+	 * result descriptors (or complete packets) that are written to
+	 * the RDR.
+	 */
+	writel(MTK_DESC_SIZE(MTK_DESC_SZ) | MTK_DESC_OFFSET(MTK_DESC_OFF),
+	       cryp->base + RDR_DESC_SIZE(i));
+
+	/*
+	 * Configure HIA fetch size and fetch threshold that are used to
+	 * fetch blocks of multiple descriptors.
+	 */
+	writel(MTK_DESC_FETCH_SIZE(count * MTK_DESC_OFF) |
+	       MTK_DESC_FETCH_THRESH(count * rndup) |
+	       MTK_DESC_OVL_IRQ_EN,
+		   cryp->base + RDR_CFG(i));
+}
+
+static int mtk_packet_engine_setup(struct mtk_cryp *cryp)
+{
+	struct mtk_sys_cap cap;
+	int i, err;
+	u32 val;
+
+	cap.hia_ver = readl(cryp->base + HIA_VERSION);
+	cap.hia_opt = readl(cryp->base + HIA_OPTIONS);
+	cap.hw_opt = readl(cryp->base + EIP97_OPTIONS);
+
+	if (!(((u16)cap.hia_ver) == MTK_HIA_SIGNATURE))
+		return -EINVAL;
+
+	/* Configure endianness conversion method for master (DMA) interface */
+	writel(0, cryp->base + EIP97_MST_CTRL);
+
+	/* Set HIA burst size */
+	val = readl(cryp->base + HIA_MST_CTRL);
+	val &= ~MTK_BURST_SIZE_MSK;
+	val |= MTK_BURST_SIZE(5);
+	writel(val, cryp->base + HIA_MST_CTRL);
+
+	err = mtk_dfe_dse_reset(cryp);
+	if (err) {
+		dev_err(cryp->dev, "Failed to reset DFE and DSE.\n");
+		return err;
+	}
+
+	mtk_dfe_dse_buf_setup(cryp, &cap);
+
+	/* Enable the 4 rings for the packet engines. */
+	mtk_desc_ring_link(cryp, 0xf);
+
+	for (i = 0; i < MTK_RING_MAX; i++) {
+		mtk_cmd_desc_ring_setup(cryp, i, &cap);
+		mtk_res_desc_ring_setup(cryp, i, &cap);
+	}
+
+	writel(MTK_PE_TK_LOC_AVL | MTK_PE_PROC_HELD | MTK_PE_TK_TIMEOUT_EN,
+	       cryp->base + PE_TOKEN_CTRL_STAT);
+
+	/* Clear all pending interrupts */
+	writel(MTK_AIC_G_CLR, cryp->base + AIC_G_ACK);
+	writel(MTK_PE_INPUT_DMA_ERR | MTK_PE_OUTPUT_DMA_ERR |
+	       MTK_PE_PKT_PORC_ERR | MTK_PE_PKT_TIMEOUT |
+	       MTK_PE_FATAL_ERR | MTK_PE_INPUT_DMA_ERR_EN |
+	       MTK_PE_OUTPUT_DMA_ERR_EN | MTK_PE_PKT_PORC_ERR_EN |
+	       MTK_PE_PKT_TIMEOUT_EN | MTK_PE_FATAL_ERR_EN |
+	       MTK_PE_INT_OUT_EN,
+	       cryp->base + PE_INTERRUPT_CTRL_STAT);
+
+	return 0;
+}
+
+static int mtk_aic_cap_check(struct mtk_cryp *cryp, int hw)
+{
+	u32 val;
+
+	if (hw == MTK_RING_MAX)
+		val = readl(cryp->base + AIC_G_VERSION);
+	else
+		val = readl(cryp->base + AIC_VERSION(hw));
+
+	val &= MTK_AIC_VER_MSK;
+	if (val != MTK_AIC_VER11 && val != MTK_AIC_VER12)
+		return -ENXIO;
+
+	if (hw == MTK_RING_MAX)
+		val = readl(cryp->base + AIC_G_OPTIONS);
+	else
+		val = readl(cryp->base + AIC_OPTIONS(hw));
+
+	val &= MTK_AIC_INT_MSK;
+	if (!val || val > 32)
+		return -ENXIO;
+
+	return 0;
+}
+
+static int mtk_aic_init(struct mtk_cryp *cryp, int hw)
+{
+	int err;
+
+	err = mtk_aic_cap_check(cryp, hw);
+	if (err)
+		return err;
+
+	/* Disable all interrupts and set initial configuration */
+	if (hw == MTK_RING_MAX) {
+		writel(0, cryp->base + AIC_G_ENABLE_CTRL);
+		writel(0, cryp->base + AIC_G_POL_CTRL);
+		writel(0, cryp->base + AIC_G_TYPE_CTRL);
+		writel(0, cryp->base + AIC_G_ENABLE_SET);
+	} else {
+		writel(0, cryp->base + AIC_ENABLE_CTRL(hw));
+		writel(0, cryp->base + AIC_POL_CTRL(hw));
+		writel(0, cryp->base + AIC_TYPE_CTRL(hw));
+		writel(0, cryp->base + AIC_ENABLE_SET(hw));
+	}
+
+	return 0;
+}
+
+static int mtk_accelerator_init(struct mtk_cryp *cryp)
+{
+	int i, err;
+
+	/* Initialize advanced interrupt controller(AIC) */
+	for (i = 0; i < MTK_IRQ_NUM; i++) {
+		err = mtk_aic_init(cryp, i);
+		if (err) {
+			dev_err(cryp->dev, "Failed to initialize AIC.\n");
+			return err;
+		}
+	}
+
+	/* Initialize packet engine */
+	err = mtk_packet_engine_setup(cryp);
+	if (err) {
+		dev_err(cryp->dev, "Failed to configure packet engine.\n");
+		return err;
+	}
+
+	return 0;
+}
+
+static void mtk_desc_dma_free(struct mtk_cryp *cryp)
+{
+	int i;
+
+	for (i = 0; i < MTK_RING_MAX; i++) {
+		dma_free_coherent(cryp->dev, MTK_DESC_RING_SZ,
+				  cryp->ring[i]->res_base,
+				  cryp->ring[i]->res_dma);
+		dma_free_coherent(cryp->dev, MTK_DESC_RING_SZ,
+				  cryp->ring[i]->cmd_base,
+				  cryp->ring[i]->cmd_dma);
+		kfree(cryp->ring[i]);
+	}
+}
+
+static int mtk_desc_ring_alloc(struct mtk_cryp *cryp)
+{
+	struct mtk_ring **ring = cryp->ring;
+	int i, err = ENOMEM;
+
+	for (i = 0; i < MTK_RING_MAX; i++) {
+		ring[i] = kzalloc(sizeof(**ring), GFP_KERNEL);
+		if (!ring[i])
+			goto err_cleanup;
+
+		ring[i]->cmd_base = dma_zalloc_coherent(cryp->dev,
+					   MTK_DESC_RING_SZ,
+					   &ring[i]->cmd_dma,
+					   GFP_KERNEL);
+		if (!ring[i]->cmd_base)
+			goto err_cleanup;
+
+		ring[i]->res_base = dma_zalloc_coherent(cryp->dev,
+					   MTK_DESC_RING_SZ,
+					   &ring[i]->res_dma,
+					   GFP_KERNEL);
+		if (!ring[i]->res_base)
+			goto err_cleanup;
+
+		ring[i]->cmd_next = ring[i]->cmd_base;
+		ring[i]->res_next = ring[i]->res_base;
+	}
+	return 0;
+
+err_cleanup:
+	for (; i--; ) {
+		dma_free_coherent(cryp->dev, MTK_DESC_RING_SZ,
+				  ring[i]->res_base, ring[i]->res_dma);
+		dma_free_coherent(cryp->dev, MTK_DESC_RING_SZ,
+				  ring[i]->cmd_base, ring[i]->cmd_dma);
+		kfree(ring[i]);
+	}
+	return err;
+}
+
+static int mtk_crypto_probe(struct platform_device *pdev)
+{
+	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	struct mtk_cryp *cryp;
+	int i, err;
+
+	cryp = devm_kzalloc(&pdev->dev, sizeof(*cryp), GFP_KERNEL);
+	if (!cryp)
+		return -ENOMEM;
+
+	cryp->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(cryp->base))
+		return PTR_ERR(cryp->base);
+
+	for (i = 0; i < MTK_IRQ_NUM; i++) {
+		cryp->irq[i] = platform_get_irq(pdev, i);
+		if (cryp->irq[i] < 0) {
+			dev_err(cryp->dev, "no IRQ:%d resource info\n", i);
+			return -ENXIO;
+		}
+	}
+
+	cryp->clk_ethif = devm_clk_get(&pdev->dev, "ethif");
+	cryp->clk_cryp = devm_clk_get(&pdev->dev, "cryp");
+	if (IS_ERR(cryp->clk_ethif) || IS_ERR(cryp->clk_cryp))
+		return -EPROBE_DEFER;
+
+	cryp->dev = &pdev->dev;
+	pm_runtime_enable(cryp->dev);
+	pm_runtime_get_sync(cryp->dev);
+
+	err = clk_prepare_enable(cryp->clk_ethif);
+	if (err)
+		goto err_clk_ethif;
+
+	err = clk_prepare_enable(cryp->clk_cryp);
+	if (err)
+		goto err_clk_cryp;
+
+	/* Allocate four command/result descriptor rings */
+	err = mtk_desc_ring_alloc(cryp);
+	if (err) {
+		dev_err(cryp->dev, "Unable to allocate descriptor rings.\n");
+		goto err_resource;
+	}
+
+	/* Initialize hardware modules */
+	err = mtk_accelerator_init(cryp);
+	if (err) {
+		dev_err(cryp->dev, "Failed to initialize cryptographic engine.\n");
+		goto err_engine;
+	}
+
+	err = mtk_cipher_alg_register(cryp);
+	if (err) {
+		dev_err(cryp->dev, "Unable to register cipher algorithm.\n");
+		goto err_cipher;
+	}
+
+	err = mtk_hash_alg_register(cryp);
+	if (err) {
+		dev_err(cryp->dev, "Unable to register hash algorithm.\n");
+		goto err_hash;
+	}
+
+	platform_set_drvdata(pdev, cryp);
+	return 0;
+
+err_hash:
+	mtk_cipher_alg_release(cryp);
+err_cipher:
+	mtk_dfe_dse_reset(cryp);
+err_engine:
+	mtk_desc_dma_free(cryp);
+err_resource:
+	clk_disable_unprepare(cryp->clk_cryp);
+err_clk_cryp:
+	clk_disable_unprepare(cryp->clk_ethif);
+err_clk_ethif:
+	pm_runtime_put_sync(cryp->dev);
+	pm_runtime_disable(cryp->dev);
+
+	return err;
+}
+
+static int mtk_crypto_remove(struct platform_device *pdev)
+{
+	struct mtk_cryp *cryp = platform_get_drvdata(pdev);
+
+	mtk_hash_alg_release(cryp);
+	mtk_cipher_alg_release(cryp);
+	mtk_desc_dma_free(cryp);
+
+	clk_disable_unprepare(cryp->clk_cryp);
+	clk_disable_unprepare(cryp->clk_ethif);
+
+	pm_runtime_put_sync(cryp->dev);
+	pm_runtime_disable(cryp->dev);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static const struct of_device_id of_crypto_id[] = {
+	{ .compatible = "mediatek,eip97-crypto" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, of_crypto_id);
+
+static struct platform_driver mtk_crypto_driver = {
+	.probe = mtk_crypto_probe,
+	.remove = mtk_crypto_remove,
+	.driver = {
+		   .name = "mtk-crypto",
+		   .owner = THIS_MODULE,
+		   .of_match_table = of_crypto_id,
+	},
+};
+module_platform_driver(mtk_crypto_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ryder Lee <[email protected]>");
+MODULE_DESCRIPTION("Cryptographic accelerator driver for EIP97");

+ 237 - 0
target/linux/mediatek/files/drivers/crypto/mediatek/mtk-platform.h

@@ -0,0 +1,237 @@
+/*
+ * Driver for EIP97 cryptographic accelerator.
+ *
+ * Copyright (c) 2016 Ryder Lee <[email protected]>
+ *
+ * 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 __MTK_PLATFORM_H_
+#define __MTK_PLATFORM_H_
+
+#include <crypto/algapi.h>
+#include <crypto/internal/aead.h>
+#include <crypto/internal/hash.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/skcipher.h>
+#include <linux/crypto.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/scatterlist.h>
+#include "mtk-regs.h"
+
+#define MTK_RDR_PROC_THRESH	BIT(0)
+#define MTK_RDR_PROC_MODE	BIT(23)
+#define MTK_CNT_RST		BIT(31)
+#define MTK_IRQ_RDR0		BIT(1)
+#define MTK_IRQ_RDR1		BIT(3)
+#define MTK_IRQ_RDR2		BIT(5)
+#define MTK_IRQ_RDR3		BIT(7)
+
+#define SIZE_IN_WORDS(x)	((x) >> 2)
+
+/**
+ * Ring 0/1 are used by AES encrypt and decrypt.
+ * Ring 2/3 are used by SHA.
+ */
+enum {
+	MTK_RING0,
+	MTK_RING1,
+	MTK_RING2,
+	MTK_RING3,
+	MTK_RING_MAX
+};
+
+#define MTK_REC_NUM		(MTK_RING_MAX / 2)
+#define MTK_IRQ_NUM		5
+
+/**
+ * struct mtk_desc - DMA descriptor
+ * @hdr:	the descriptor control header
+ * @buf:	DMA address of input buffer segment
+ * @ct:		DMA address of command token that control operation flow
+ * @ct_hdr:	the command token control header
+ * @tag:	the user-defined field
+ * @tfm:	DMA address of transform state
+ * @bound:	align descriptors offset boundary
+ *
+ * Structure passed to the crypto engine to describe where source
+ * data needs to be fetched and how it needs to be processed.
+ */
+struct mtk_desc {
+	__le32 hdr;
+	__le32 buf;
+	__le32 ct;
+	__le32 ct_hdr;
+	__le32 tag;
+	__le32 tfm;
+	__le32 bound[2];
+};
+
+#define MTK_DESC_NUM		512
+#define MTK_DESC_OFF		SIZE_IN_WORDS(sizeof(struct mtk_desc))
+#define MTK_DESC_SZ		(MTK_DESC_OFF - 2)
+#define MTK_DESC_RING_SZ	((sizeof(struct mtk_desc) * MTK_DESC_NUM))
+#define MTK_DESC_CNT(x)		((MTK_DESC_OFF * (x)) << 2)
+#define MTK_DESC_LAST		cpu_to_le32(BIT(22))
+#define MTK_DESC_FIRST		cpu_to_le32(BIT(23))
+#define MTK_DESC_BUF_LEN(x)	cpu_to_le32(x)
+#define MTK_DESC_CT_LEN(x)	cpu_to_le32((x) << 24)
+
+/**
+ * struct mtk_ring - Descriptor ring
+ * @cmd_base:	pointer to command descriptor ring base
+ * @cmd_next:	pointer to the next command descriptor
+ * @cmd_dma:	DMA address of command descriptor ring
+ * @res_base:	pointer to result descriptor ring base
+ * @res_next:	pointer to the next result descriptor
+ * @res_prev:	pointer to the previous result descriptor
+ * @res_dma:	DMA address of result descriptor ring
+ *
+ * A descriptor ring is a circular buffer that is used to manage
+ * one or more descriptors. There are two type of descriptor rings;
+ * the command descriptor ring and result descriptor ring.
+ */
+struct mtk_ring {
+	struct mtk_desc *cmd_base;
+	struct mtk_desc *cmd_next;
+	dma_addr_t cmd_dma;
+	struct mtk_desc *res_base;
+	struct mtk_desc *res_next;
+	struct mtk_desc *res_prev;
+	dma_addr_t res_dma;
+};
+
+/**
+ * struct mtk_aes_dma - Structure that holds sg list info
+ * @sg:		pointer to scatter-gather list
+ * @nents:	number of entries in the sg list
+ * @remainder:	remainder of sg list
+ * @sg_len:	number of entries in the sg mapped list
+ */
+struct mtk_aes_dma {
+	struct scatterlist *sg;
+	int nents;
+	u32 remainder;
+	u32 sg_len;
+};
+
+struct mtk_aes_base_ctx;
+struct mtk_aes_rec;
+struct mtk_cryp;
+
+typedef int (*mtk_aes_fn)(struct mtk_cryp *cryp, struct mtk_aes_rec *aes);
+
+/**
+ * struct mtk_aes_rec - AES operation record
+ * @cryp:	pointer to Cryptographic device
+ * @queue:	crypto request queue
+ * @areq:	pointer to async request
+ * @done_task:	the tasklet is use in AES interrupt
+ * @queue_task:	the tasklet is used to dequeue request
+ * @ctx:	pointer to current context
+ * @src:	the structure that holds source sg list info
+ * @dst:	the structure that holds destination sg list info
+ * @aligned_sg:	the scatter list is use to alignment
+ * @real_dst:	pointer to the destination sg list
+ * @resume:	pointer to resume function
+ * @total:	request buffer length
+ * @buf:	pointer to page buffer
+ * @id:		the current use of ring
+ * @flags:	it's describing AES operation state
+ * @lock:	the async queue lock
+ *
+ * Structure used to record AES execution state.
+ */
+struct mtk_aes_rec {
+	struct mtk_cryp *cryp;
+	struct crypto_queue queue;
+	struct crypto_async_request *areq;
+	struct tasklet_struct done_task;
+	struct tasklet_struct queue_task;
+	struct mtk_aes_base_ctx *ctx;
+	struct mtk_aes_dma src;
+	struct mtk_aes_dma dst;
+
+	struct scatterlist aligned_sg;
+	struct scatterlist *real_dst;
+
+	mtk_aes_fn resume;
+
+	size_t total;
+	void *buf;
+
+	u8 id;
+	unsigned long flags;
+	/* queue lock */
+	spinlock_t lock;
+};
+
+/**
+ * struct mtk_sha_rec - SHA operation record
+ * @cryp:	pointer to Cryptographic device
+ * @queue:	crypto request queue
+ * @req:	pointer to ahash request
+ * @done_task:	the tasklet is use in SHA interrupt
+ * @queue_task:	the tasklet is used to dequeue request
+ * @id:		the current use of ring
+ * @flags:	it's describing SHA operation state
+ * @lock:	the async queue lock
+ *
+ * Structure used to record SHA execution state.
+ */
+struct mtk_sha_rec {
+	struct mtk_cryp *cryp;
+	struct crypto_queue queue;
+	struct ahash_request *req;
+	struct tasklet_struct done_task;
+	struct tasklet_struct queue_task;
+
+	u8 id;
+	unsigned long flags;
+	/* queue lock */
+	spinlock_t lock;
+};
+
+/**
+ * struct mtk_cryp - Cryptographic device
+ * @base:	pointer to mapped register I/O base
+ * @dev:	pointer to device
+ * @clk_ethif:	pointer to ethif clock
+ * @clk_cryp:	pointer to crypto clock
+ * @irq:	global system and rings IRQ
+ * @ring:	pointer to descriptor rings
+ * @aes:	pointer to operation record of AES
+ * @sha:	pointer to operation record of SHA
+ * @aes_list:	device list of AES
+ * @sha_list:	device list of SHA
+ * @rec:	it's used to select SHA record for tfm
+ *
+ * Structure storing cryptographic device information.
+ */
+struct mtk_cryp {
+	void __iomem *base;
+	struct device *dev;
+	struct clk *clk_ethif;
+	struct clk *clk_cryp;
+	int irq[MTK_IRQ_NUM];
+
+	struct mtk_ring *ring[MTK_RING_MAX];
+	struct mtk_aes_rec *aes[MTK_REC_NUM];
+	struct mtk_sha_rec *sha[MTK_REC_NUM];
+
+	struct list_head aes_list;
+	struct list_head sha_list;
+
+	bool rec;
+};
+
+int mtk_cipher_alg_register(struct mtk_cryp *cryp);
+void mtk_cipher_alg_release(struct mtk_cryp *cryp);
+int mtk_hash_alg_register(struct mtk_cryp *cryp);
+void mtk_hash_alg_release(struct mtk_cryp *cryp);
+
+#endif /* __MTK_PLATFORM_H_ */

+ 194 - 0
target/linux/mediatek/files/drivers/crypto/mediatek/mtk-regs.h

@@ -0,0 +1,194 @@
+/*
+ * Support for MediaTek cryptographic accelerator.
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ryder Lee <[email protected]>
+ *
+ * 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.
+ *
+ */
+
+#ifndef __MTK_REGS_H__
+#define __MTK_REGS_H__
+
+/* HIA, Command Descriptor Ring Manager */
+#define CDR_BASE_ADDR_LO(x)		(0x0 + ((x) << 12))
+#define CDR_BASE_ADDR_HI(x)		(0x4 + ((x) << 12))
+#define CDR_DATA_BASE_ADDR_LO(x)	(0x8 + ((x) << 12))
+#define CDR_DATA_BASE_ADDR_HI(x)	(0xC + ((x) << 12))
+#define CDR_ACD_BASE_ADDR_LO(x)		(0x10 + ((x) << 12))
+#define CDR_ACD_BASE_ADDR_HI(x)		(0x14 + ((x) << 12))
+#define CDR_RING_SIZE(x)		(0x18 + ((x) << 12))
+#define CDR_DESC_SIZE(x)		(0x1C + ((x) << 12))
+#define CDR_CFG(x)			(0x20 + ((x) << 12))
+#define CDR_DMA_CFG(x)			(0x24 + ((x) << 12))
+#define CDR_THRESH(x)			(0x28 + ((x) << 12))
+#define CDR_PREP_COUNT(x)		(0x2C + ((x) << 12))
+#define CDR_PROC_COUNT(x)		(0x30 + ((x) << 12))
+#define CDR_PREP_PNTR(x)		(0x34 + ((x) << 12))
+#define CDR_PROC_PNTR(x)		(0x38 + ((x) << 12))
+#define CDR_STAT(x)			(0x3C + ((x) << 12))
+
+/* HIA, Result Descriptor Ring Manager */
+#define RDR_BASE_ADDR_LO(x)		(0x800 + ((x) << 12))
+#define RDR_BASE_ADDR_HI(x)		(0x804 + ((x) << 12))
+#define RDR_DATA_BASE_ADDR_LO(x)	(0x808 + ((x) << 12))
+#define RDR_DATA_BASE_ADDR_HI(x)	(0x80C + ((x) << 12))
+#define RDR_ACD_BASE_ADDR_LO(x)		(0x810 + ((x) << 12))
+#define RDR_ACD_BASE_ADDR_HI(x)		(0x814 + ((x) << 12))
+#define RDR_RING_SIZE(x)		(0x818 + ((x) << 12))
+#define RDR_DESC_SIZE(x)		(0x81C + ((x) << 12))
+#define RDR_CFG(x)			(0x820 + ((x) << 12))
+#define RDR_DMA_CFG(x)			(0x824 + ((x) << 12))
+#define RDR_THRESH(x)			(0x828 + ((x) << 12))
+#define RDR_PREP_COUNT(x)		(0x82C + ((x) << 12))
+#define RDR_PROC_COUNT(x)		(0x830 + ((x) << 12))
+#define RDR_PREP_PNTR(x)		(0x834 + ((x) << 12))
+#define RDR_PROC_PNTR(x)		(0x838 + ((x) << 12))
+#define RDR_STAT(x)			(0x83C + ((x) << 12))
+
+/* HIA, Ring AIC */
+#define AIC_POL_CTRL(x)			(0xE000 - ((x) << 12))
+#define	AIC_TYPE_CTRL(x)		(0xE004 - ((x) << 12))
+#define	AIC_ENABLE_CTRL(x)		(0xE008 - ((x) << 12))
+#define	AIC_RAW_STAL(x)			(0xE00C - ((x) << 12))
+#define	AIC_ENABLE_SET(x)		(0xE00C - ((x) << 12))
+#define	AIC_ENABLED_STAT(x)		(0xE010 - ((x) << 12))
+#define	AIC_ACK(x)			(0xE010 - ((x) << 12))
+#define	AIC_ENABLE_CLR(x)		(0xE014 - ((x) << 12))
+#define	AIC_OPTIONS(x)			(0xE018 - ((x) << 12))
+#define	AIC_VERSION(x)			(0xE01C - ((x) << 12))
+
+/* HIA, Global AIC */
+#define AIC_G_POL_CTRL			0xF800
+#define AIC_G_TYPE_CTRL			0xF804
+#define AIC_G_ENABLE_CTRL		0xF808
+#define AIC_G_RAW_STAT			0xF80C
+#define AIC_G_ENABLE_SET		0xF80C
+#define AIC_G_ENABLED_STAT		0xF810
+#define AIC_G_ACK			0xF810
+#define AIC_G_ENABLE_CLR		0xF814
+#define AIC_G_OPTIONS			0xF818
+#define AIC_G_VERSION			0xF81C
+
+/* HIA, Data Fetch Engine */
+#define DFE_CFG				0xF000
+#define DFE_PRIO_0			0xF010
+#define DFE_PRIO_1			0xF014
+#define DFE_PRIO_2			0xF018
+#define DFE_PRIO_3			0xF01C
+
+/* HIA, Data Fetch Engine access monitoring for CDR */
+#define DFE_RING_REGION_LO(x)		(0xF080 + ((x) << 3))
+#define DFE_RING_REGION_HI(x)		(0xF084 + ((x) << 3))
+
+/* HIA, Data Fetch Engine thread control and status for thread */
+#define DFE_THR_CTRL			0xF200
+#define DFE_THR_STAT			0xF204
+#define DFE_THR_DESC_CTRL		0xF208
+#define DFE_THR_DESC_DPTR_LO		0xF210
+#define DFE_THR_DESC_DPTR_HI		0xF214
+#define DFE_THR_DESC_ACDPTR_LO		0xF218
+#define DFE_THR_DESC_ACDPTR_HI		0xF21C
+
+/* HIA, Data Store Engine */
+#define DSE_CFG				0xF400
+#define DSE_PRIO_0			0xF410
+#define DSE_PRIO_1			0xF414
+#define DSE_PRIO_2			0xF418
+#define DSE_PRIO_3			0xF41C
+
+/* HIA, Data Store Engine access monitoring for RDR */
+#define DSE_RING_REGION_LO(x)		(0xF480 + ((x) << 3))
+#define DSE_RING_REGION_HI(x)		(0xF484 + ((x) << 3))
+
+/* HIA, Data Store Engine thread control and status for thread */
+#define DSE_THR_CTRL			0xF600
+#define DSE_THR_STAT			0xF604
+#define DSE_THR_DESC_CTRL		0xF608
+#define DSE_THR_DESC_DPTR_LO		0xF610
+#define DSE_THR_DESC_DPTR_HI		0xF614
+#define DSE_THR_DESC_S_DPTR_LO		0xF618
+#define DSE_THR_DESC_S_DPTR_HI		0xF61C
+#define DSE_THR_ERROR_STAT		0xF620
+
+/* HIA Global */
+#define HIA_MST_CTRL			0xFFF4
+#define HIA_OPTIONS			0xFFF8
+#define HIA_VERSION			0xFFFC
+
+/* Processing Engine Input Side, Processing Engine */
+#define PE_IN_DBUF_THRESH		0x10000
+#define PE_IN_TBUF_THRESH		0x10100
+
+/* Packet Engine Configuration / Status Registers */
+#define PE_TOKEN_CTRL_STAT		0x11000
+#define PE_FUNCTION_EN			0x11004
+#define PE_CONTEXT_CTRL			0x11008
+#define PE_INTERRUPT_CTRL_STAT		0x11010
+#define PE_CONTEXT_STAT			0x1100C
+#define PE_OUT_TRANS_CTRL_STAT		0x11018
+#define PE_OUT_BUF_CTRL			0x1101C
+
+/* Packet Engine PRNG Registers */
+#define PE_PRNG_STAT			0x11040
+#define PE_PRNG_CTRL			0x11044
+#define PE_PRNG_SEED_L			0x11048
+#define PE_PRNG_SEED_H			0x1104C
+#define PE_PRNG_KEY_0_L			0x11050
+#define PE_PRNG_KEY_0_H			0x11054
+#define PE_PRNG_KEY_1_L			0x11058
+#define PE_PRNG_KEY_1_H			0x1105C
+#define PE_PRNG_RES_0			0x11060
+#define PE_PRNG_RES_1			0x11064
+#define PE_PRNG_RES_2			0x11068
+#define PE_PRNG_RES_3			0x1106C
+#define PE_PRNG_LFSR_L			0x11070
+#define PE_PRNG_LFSR_H			0x11074
+
+/* Packet Engine AIC */
+#define PE_EIP96_AIC_POL_CTRL		0x113C0
+#define PE_EIP96_AIC_TYPE_CTRL		0x113C4
+#define PE_EIP96_AIC_ENABLE_CTRL	0x113C8
+#define PE_EIP96_AIC_RAW_STAT		0x113CC
+#define PE_EIP96_AIC_ENABLE_SET		0x113CC
+#define PE_EIP96_AIC_ENABLED_STAT	0x113D0
+#define PE_EIP96_AIC_ACK		0x113D0
+#define PE_EIP96_AIC_ENABLE_CLR		0x113D4
+#define PE_EIP96_AIC_OPTIONS		0x113D8
+#define PE_EIP96_AIC_VERSION		0x113DC
+
+/* Packet Engine Options & Version Registers */
+#define PE_EIP96_OPTIONS		0x113F8
+#define PE_EIP96_VERSION		0x113FC
+
+/* Processing Engine Output Side */
+#define PE_OUT_DBUF_THRESH		0x11C00
+#define PE_OUT_TBUF_THRESH		0x11D00
+
+/* Processing Engine Local AIC */
+#define PE_AIC_POL_CTRL			0x11F00
+#define PE_AIC_TYPE_CTRL		0x11F04
+#define PE_AIC_ENABLE_CTRL		0x11F08
+#define PE_AIC_RAW_STAT			0x11F0C
+#define PE_AIC_ENABLE_SET		0x11F0C
+#define PE_AIC_ENABLED_STAT		0x11F10
+#define PE_AIC_ENABLE_CLR		0x11F14
+#define PE_AIC_OPTIONS			0x11F18
+#define PE_AIC_VERSION			0x11F1C
+
+/* Processing Engine General Configuration and Version */
+#define PE_IN_FLIGHT			0x11FF0
+#define PE_OPTIONS			0x11FF8
+#define PE_VERSION			0x11FFC
+
+/* EIP-97 - Global */
+#define EIP97_CLOCK_STATE		0x1FFE4
+#define EIP97_FORCE_CLOCK_ON		0x1FFE8
+#define EIP97_FORCE_CLOCK_OFF		0x1FFEC
+#define EIP97_MST_CTRL			0x1FFF4
+#define EIP97_OPTIONS			0x1FFF8
+#define EIP97_VERSION			0x1FFFC
+#endif /* __MTK_REGS_H__ */

+ 1358 - 0
target/linux/mediatek/files/drivers/crypto/mediatek/mtk-sha.c

@@ -0,0 +1,1358 @@
+/*
+ * Cryptographic API.
+ *
+ * Driver for EIP97 SHA1/SHA2(HMAC) acceleration.
+ *
+ * Copyright (c) 2016 Ryder Lee <[email protected]>
+ *
+ * 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.
+ *
+ * Some ideas are from atmel-sha.c and omap-sham.c drivers.
+ */
+
+#include <crypto/sha.h>
+#include "mtk-platform.h"
+
+#define SHA_ALIGN_MSK		(sizeof(u32) - 1)
+#define SHA_QUEUE_SIZE		512
+#define SHA_BUF_SIZE		((u32)PAGE_SIZE)
+
+#define SHA_OP_UPDATE		1
+#define SHA_OP_FINAL		2
+
+#define SHA_DATA_LEN_MSK	cpu_to_le32(GENMASK(16, 0))
+#define SHA_MAX_DIGEST_BUF_SIZE	32
+
+/* SHA command token */
+#define SHA_CT_SIZE		5
+#define SHA_CT_CTRL_HDR		cpu_to_le32(0x02220000)
+#define SHA_CMD0		cpu_to_le32(0x03020000)
+#define SHA_CMD1		cpu_to_le32(0x21060000)
+#define SHA_CMD2		cpu_to_le32(0xe0e63802)
+
+/* SHA transform information */
+#define SHA_TFM_HASH		cpu_to_le32(0x2 << 0)
+#define SHA_TFM_SIZE(x)		cpu_to_le32((x) << 8)
+#define SHA_TFM_START		cpu_to_le32(0x1 << 4)
+#define SHA_TFM_CONTINUE	cpu_to_le32(0x1 << 5)
+#define SHA_TFM_HASH_STORE	cpu_to_le32(0x1 << 19)
+#define SHA_TFM_SHA1		cpu_to_le32(0x2 << 23)
+#define SHA_TFM_SHA256		cpu_to_le32(0x3 << 23)
+#define SHA_TFM_SHA224		cpu_to_le32(0x4 << 23)
+#define SHA_TFM_SHA512		cpu_to_le32(0x5 << 23)
+#define SHA_TFM_SHA384		cpu_to_le32(0x6 << 23)
+#define SHA_TFM_DIGEST(x)	cpu_to_le32(((x) & GENMASK(3, 0)) << 24)
+
+/* SHA flags */
+#define SHA_FLAGS_BUSY		BIT(0)
+#define	SHA_FLAGS_FINAL		BIT(1)
+#define SHA_FLAGS_FINUP		BIT(2)
+#define SHA_FLAGS_SG		BIT(3)
+#define SHA_FLAGS_ALGO_MSK	GENMASK(8, 4)
+#define SHA_FLAGS_SHA1		BIT(4)
+#define SHA_FLAGS_SHA224	BIT(5)
+#define SHA_FLAGS_SHA256	BIT(6)
+#define SHA_FLAGS_SHA384	BIT(7)
+#define SHA_FLAGS_SHA512	BIT(8)
+#define SHA_FLAGS_HMAC		BIT(9)
+#define SHA_FLAGS_PAD		BIT(10)
+
+/**
+ * mtk_sha_info - hardware information of AES
+ * @cmd:	command token, hardware instruction
+ * @tfm:	transform state of cipher algorithm.
+ * @state:	contains keys and initial vectors.
+ *
+ */
+struct mtk_sha_info {
+	__le32 ctrl[2];
+	__le32 cmd[3];
+	__le32 tfm[2];
+	__le32 digest[SHA_MAX_DIGEST_BUF_SIZE];
+};
+
+struct mtk_sha_reqctx {
+	struct mtk_sha_info info;
+	unsigned long flags;
+	unsigned long op;
+
+	u64 digcnt;
+	size_t bufcnt;
+	dma_addr_t dma_addr;
+
+	__le32 ct_hdr;
+	u32 ct_size;
+	dma_addr_t ct_dma;
+	dma_addr_t tfm_dma;
+
+	/* Walk state */
+	struct scatterlist *sg;
+	u32 offset;	/* Offset in current sg */
+	u32 total;	/* Total request */
+	size_t ds;
+	size_t bs;
+
+	u8 *buffer;
+};
+
+struct mtk_sha_hmac_ctx {
+	struct crypto_shash	*shash;
+	u8 ipad[SHA512_BLOCK_SIZE] __aligned(sizeof(u32));
+	u8 opad[SHA512_BLOCK_SIZE] __aligned(sizeof(u32));
+};
+
+struct mtk_sha_ctx {
+	struct mtk_cryp *cryp;
+	unsigned long flags;
+	u8 id;
+	u8 buf[SHA_BUF_SIZE] __aligned(sizeof(u32));
+
+	struct mtk_sha_hmac_ctx	base[0];
+};
+
+struct mtk_sha_drv {
+	struct list_head dev_list;
+	/* Device list lock */
+	spinlock_t lock;
+};
+
+static struct mtk_sha_drv mtk_sha = {
+	.dev_list = LIST_HEAD_INIT(mtk_sha.dev_list),
+	.lock = __SPIN_LOCK_UNLOCKED(mtk_sha.lock),
+};
+
+static int mtk_sha_handle_queue(struct mtk_cryp *cryp, u8 id,
+				struct ahash_request *req);
+
+static inline u32 mtk_sha_read(struct mtk_cryp *cryp, u32 offset)
+{
+	return readl_relaxed(cryp->base + offset);
+}
+
+static inline void mtk_sha_write(struct mtk_cryp *cryp,
+				 u32 offset, u32 value)
+{
+	writel_relaxed(value, cryp->base + offset);
+}
+
+static inline void mtk_sha_ring_shift(struct mtk_ring *ring,
+				      struct mtk_desc **cmd_curr,
+				      struct mtk_desc **res_curr,
+				      int *count)
+{
+	*cmd_curr = ring->cmd_next++;
+	*res_curr = ring->res_next++;
+	(*count)++;
+
+	if (ring->cmd_next == ring->cmd_base + MTK_DESC_NUM) {
+		ring->cmd_next = ring->cmd_base;
+		ring->res_next = ring->res_base;
+	}
+}
+
+static struct mtk_cryp *mtk_sha_find_dev(struct mtk_sha_ctx *tctx)
+{
+	struct mtk_cryp *cryp = NULL;
+	struct mtk_cryp *tmp;
+
+	spin_lock_bh(&mtk_sha.lock);
+	if (!tctx->cryp) {
+		list_for_each_entry(tmp, &mtk_sha.dev_list, sha_list) {
+			cryp = tmp;
+			break;
+		}
+		tctx->cryp = cryp;
+	} else {
+		cryp = tctx->cryp;
+	}
+
+	/*
+	 * Assign record id to tfm in round-robin fashion, and this
+	 * will help tfm to bind  to corresponding descriptor rings.
+	 */
+	tctx->id = cryp->rec;
+	cryp->rec = !cryp->rec;
+
+	spin_unlock_bh(&mtk_sha.lock);
+
+	return cryp;
+}
+
+static int mtk_sha_append_sg(struct mtk_sha_reqctx *ctx)
+{
+	size_t count;
+
+	while ((ctx->bufcnt < SHA_BUF_SIZE) && ctx->total) {
+		count = min(ctx->sg->length - ctx->offset, ctx->total);
+		count = min(count, SHA_BUF_SIZE - ctx->bufcnt);
+
+		if (count <= 0) {
+			/*
+			 * Check if count <= 0 because the buffer is full or
+			 * because the sg length is 0. In the latest case,
+			 * check if there is another sg in the list, a 0 length
+			 * sg doesn't necessarily mean the end of the sg list.
+			 */
+			if ((ctx->sg->length == 0) && !sg_is_last(ctx->sg)) {
+				ctx->sg = sg_next(ctx->sg);
+				continue;
+			} else {
+				break;
+			}
+		}
+
+		scatterwalk_map_and_copy(ctx->buffer + ctx->bufcnt, ctx->sg,
+					 ctx->offset, count, 0);
+
+		ctx->bufcnt += count;
+		ctx->offset += count;
+		ctx->total -= count;
+
+		if (ctx->offset == ctx->sg->length) {
+			ctx->sg = sg_next(ctx->sg);
+			if (ctx->sg)
+				ctx->offset = 0;
+			else
+				ctx->total = 0;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * The purpose of this padding is to ensure that the padded message is a
+ * multiple of 512 bits (SHA1/SHA224/SHA256) or 1024 bits (SHA384/SHA512).
+ * The bit "1" is appended at the end of the message followed by
+ * "padlen-1" zero bits. Then a 64 bits block (SHA1/SHA224/SHA256) or
+ * 128 bits block (SHA384/SHA512) equals to the message length in bits
+ * is appended.
+ *
+ * For SHA1/SHA224/SHA256, padlen is calculated as followed:
+ *  - if message length < 56 bytes then padlen = 56 - message length
+ *  - else padlen = 64 + 56 - message length
+ *
+ * For SHA384/SHA512, padlen is calculated as followed:
+ *  - if message length < 112 bytes then padlen = 112 - message length
+ *  - else padlen = 128 + 112 - message length
+ */
+static void mtk_sha_fill_padding(struct mtk_sha_reqctx *ctx, u32 len)
+{
+	u32 index, padlen;
+	u64 bits[2];
+	u64 size = ctx->digcnt;
+
+	size += ctx->bufcnt;
+	size += len;
+
+	bits[1] = cpu_to_be64(size << 3);
+	bits[0] = cpu_to_be64(size >> 61);
+
+	switch (ctx->flags & SHA_FLAGS_ALGO_MSK) {
+	case SHA_FLAGS_SHA384:
+	case SHA_FLAGS_SHA512:
+		index = ctx->bufcnt & 0x7f;
+		padlen = (index < 112) ? (112 - index) : ((128 + 112) - index);
+		*(ctx->buffer + ctx->bufcnt) = 0x80;
+		memset(ctx->buffer + ctx->bufcnt + 1, 0, padlen - 1);
+		memcpy(ctx->buffer + ctx->bufcnt + padlen, bits, 16);
+		ctx->bufcnt += padlen + 16;
+		ctx->flags |= SHA_FLAGS_PAD;
+		break;
+
+	default:
+		index = ctx->bufcnt & 0x3f;
+		padlen = (index < 56) ? (56 - index) : ((64 + 56) - index);
+		*(ctx->buffer + ctx->bufcnt) = 0x80;
+		memset(ctx->buffer + ctx->bufcnt + 1, 0, padlen - 1);
+		memcpy(ctx->buffer + ctx->bufcnt + padlen, &bits[1], 8);
+		ctx->bufcnt += padlen + 8;
+		ctx->flags |= SHA_FLAGS_PAD;
+		break;
+	}
+}
+
+/* Initialize basic transform information of SHA */
+static void mtk_sha_info_init(struct mtk_sha_reqctx *ctx)
+{
+	struct mtk_sha_info *info = &ctx->info;
+
+	ctx->ct_hdr = SHA_CT_CTRL_HDR;
+	ctx->ct_size = SHA_CT_SIZE;
+
+	info->tfm[0] = SHA_TFM_HASH | SHA_TFM_SIZE(SIZE_IN_WORDS(ctx->ds));
+
+	switch (ctx->flags & SHA_FLAGS_ALGO_MSK) {
+	case SHA_FLAGS_SHA1:
+		info->tfm[0] |= SHA_TFM_SHA1;
+		break;
+	case SHA_FLAGS_SHA224:
+		info->tfm[0] |= SHA_TFM_SHA224;
+		break;
+	case SHA_FLAGS_SHA256:
+		info->tfm[0] |= SHA_TFM_SHA256;
+		break;
+	case SHA_FLAGS_SHA384:
+		info->tfm[0] |= SHA_TFM_SHA384;
+		break;
+	case SHA_FLAGS_SHA512:
+		info->tfm[0] |= SHA_TFM_SHA512;
+		break;
+
+	default:
+		/* Should not happen... */
+		return;
+	}
+
+	info->tfm[1] = SHA_TFM_HASH_STORE;
+	info->ctrl[0] = info->tfm[0] | SHA_TFM_CONTINUE | SHA_TFM_START;
+	info->ctrl[1] = info->tfm[1];
+
+	info->cmd[0] = SHA_CMD0;
+	info->cmd[1] = SHA_CMD1;
+	info->cmd[2] = SHA_CMD2 | SHA_TFM_DIGEST(SIZE_IN_WORDS(ctx->ds));
+}
+
+/*
+ * Update input data length field of transform information and
+ * map it to DMA region.
+ */
+static int mtk_sha_info_update(struct mtk_cryp *cryp,
+			       struct mtk_sha_rec *sha,
+			       size_t len1, size_t len2)
+{
+	struct mtk_sha_reqctx *ctx = ahash_request_ctx(sha->req);
+	struct mtk_sha_info *info = &ctx->info;
+
+	ctx->ct_hdr &= ~SHA_DATA_LEN_MSK;
+	ctx->ct_hdr |= cpu_to_le32(len1 + len2);
+	info->cmd[0] &= ~SHA_DATA_LEN_MSK;
+	info->cmd[0] |= cpu_to_le32(len1 + len2);
+
+	/* Setting SHA_TFM_START only for the first iteration */
+	if (ctx->digcnt)
+		info->ctrl[0] &= ~SHA_TFM_START;
+
+	ctx->digcnt += len1;
+
+	ctx->ct_dma = dma_map_single(cryp->dev, info, sizeof(*info),
+				     DMA_BIDIRECTIONAL);
+	if (unlikely(dma_mapping_error(cryp->dev, ctx->ct_dma))) {
+		dev_err(cryp->dev, "dma %zu bytes error\n", sizeof(*info));
+		return -EINVAL;
+	}
+
+	ctx->tfm_dma = ctx->ct_dma + sizeof(info->ctrl) + sizeof(info->cmd);
+
+	return 0;
+}
+
+/*
+ * Because of hardware limitation, we must pre-calculate the inner
+ * and outer digest that need to be processed firstly by engine, then
+ * apply the result digest to the input message. These complex hashing
+ * procedures limits HMAC performance, so we use fallback SW encoding.
+ */
+static int mtk_sha_finish_hmac(struct ahash_request *req)
+{
+	struct mtk_sha_ctx *tctx = crypto_tfm_ctx(req->base.tfm);
+	struct mtk_sha_hmac_ctx *bctx = tctx->base;
+	struct mtk_sha_reqctx *ctx = ahash_request_ctx(req);
+
+	SHASH_DESC_ON_STACK(shash, bctx->shash);
+
+	shash->tfm = bctx->shash;
+	shash->flags = 0; /* not CRYPTO_TFM_REQ_MAY_SLEEP */
+
+	return crypto_shash_init(shash) ?:
+	       crypto_shash_update(shash, bctx->opad, ctx->bs) ?:
+	       crypto_shash_finup(shash, req->result, ctx->ds, req->result);
+}
+
+/* Initialize request context */
+static int mtk_sha_init(struct ahash_request *req)
+{
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct mtk_sha_ctx *tctx = crypto_ahash_ctx(tfm);
+	struct mtk_sha_reqctx *ctx = ahash_request_ctx(req);
+
+	ctx->flags = 0;
+	ctx->ds = crypto_ahash_digestsize(tfm);
+
+	switch (ctx->ds) {
+	case SHA1_DIGEST_SIZE:
+		ctx->flags |= SHA_FLAGS_SHA1;
+		ctx->bs = SHA1_BLOCK_SIZE;
+		break;
+	case SHA224_DIGEST_SIZE:
+		ctx->flags |= SHA_FLAGS_SHA224;
+		ctx->bs = SHA224_BLOCK_SIZE;
+		break;
+	case SHA256_DIGEST_SIZE:
+		ctx->flags |= SHA_FLAGS_SHA256;
+		ctx->bs = SHA256_BLOCK_SIZE;
+		break;
+	case SHA384_DIGEST_SIZE:
+		ctx->flags |= SHA_FLAGS_SHA384;
+		ctx->bs = SHA384_BLOCK_SIZE;
+		break;
+	case SHA512_DIGEST_SIZE:
+		ctx->flags |= SHA_FLAGS_SHA512;
+		ctx->bs = SHA512_BLOCK_SIZE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ctx->bufcnt = 0;
+	ctx->digcnt = 0;
+	ctx->buffer = tctx->buf;
+
+	if (tctx->flags & SHA_FLAGS_HMAC) {
+		struct mtk_sha_hmac_ctx *bctx = tctx->base;
+
+		memcpy(ctx->buffer, bctx->ipad, ctx->bs);
+		ctx->bufcnt = ctx->bs;
+		ctx->flags |= SHA_FLAGS_HMAC;
+	}
+
+	return 0;
+}
+
+static int mtk_sha_xmit(struct mtk_cryp *cryp, struct mtk_sha_rec *sha,
+			dma_addr_t addr1, size_t len1,
+			dma_addr_t addr2, size_t len2)
+{
+	struct mtk_sha_reqctx *ctx = ahash_request_ctx(sha->req);
+	struct mtk_ring *ring = cryp->ring[sha->id];
+	struct mtk_desc *cmd, *res;
+	int err, count = 0;
+
+	err = mtk_sha_info_update(cryp, sha, len1, len2);
+	if (err)
+		return err;
+
+	/* Fill in the command/result descriptors */
+	mtk_sha_ring_shift(ring, &cmd, &res, &count);
+
+	res->hdr = MTK_DESC_FIRST | MTK_DESC_BUF_LEN(len1);
+	cmd->hdr = MTK_DESC_FIRST | MTK_DESC_BUF_LEN(len1) |
+		   MTK_DESC_CT_LEN(ctx->ct_size);
+	cmd->buf = cpu_to_le32(addr1);
+	cmd->ct = cpu_to_le32(ctx->ct_dma);
+	cmd->ct_hdr = ctx->ct_hdr;
+	cmd->tfm = cpu_to_le32(ctx->tfm_dma);
+
+	if (len2) {
+		mtk_sha_ring_shift(ring, &cmd, &res, &count);
+
+		res->hdr = MTK_DESC_BUF_LEN(len2);
+		cmd->hdr = MTK_DESC_BUF_LEN(len2);
+		cmd->buf = cpu_to_le32(addr2);
+	}
+
+	cmd->hdr |= MTK_DESC_LAST;
+	res->hdr |= MTK_DESC_LAST;
+
+	/*
+	 * Make sure that all changes to the DMA ring are done before we
+	 * start engine.
+	 */
+	wmb();
+	/* Start DMA transfer */
+	mtk_sha_write(cryp, RDR_PREP_COUNT(sha->id), MTK_DESC_CNT(count));
+	mtk_sha_write(cryp, CDR_PREP_COUNT(sha->id), MTK_DESC_CNT(count));
+
+	return -EINPROGRESS;
+}
+
+static int mtk_sha_dma_map(struct mtk_cryp *cryp,
+			   struct mtk_sha_rec *sha,
+			   struct mtk_sha_reqctx *ctx,
+			   size_t count)
+{
+	ctx->dma_addr = dma_map_single(cryp->dev, ctx->buffer,
+				       SHA_BUF_SIZE, DMA_TO_DEVICE);
+	if (unlikely(dma_mapping_error(cryp->dev, ctx->dma_addr))) {
+		dev_err(cryp->dev, "dma map error\n");
+		return -EINVAL;
+	}
+
+	ctx->flags &= ~SHA_FLAGS_SG;
+
+	return mtk_sha_xmit(cryp, sha, ctx->dma_addr, count, 0, 0);
+}
+
+static int mtk_sha_update_slow(struct mtk_cryp *cryp,
+			       struct mtk_sha_rec *sha)
+{
+	struct mtk_sha_reqctx *ctx = ahash_request_ctx(sha->req);
+	size_t count;
+	u32 final;
+
+	mtk_sha_append_sg(ctx);
+
+	final = (ctx->flags & SHA_FLAGS_FINUP) && !ctx->total;
+
+	dev_dbg(cryp->dev, "slow: bufcnt: %zu\n", ctx->bufcnt);
+
+	if (final) {
+		sha->flags |= SHA_FLAGS_FINAL;
+		mtk_sha_fill_padding(ctx, 0);
+	}
+
+	if (final || (ctx->bufcnt == SHA_BUF_SIZE && ctx->total)) {
+		count = ctx->bufcnt;
+		ctx->bufcnt = 0;
+
+		return mtk_sha_dma_map(cryp, sha, ctx, count);
+	}
+	return 0;
+}
+
+static int mtk_sha_update_start(struct mtk_cryp *cryp,
+				struct mtk_sha_rec *sha)
+{
+	struct mtk_sha_reqctx *ctx = ahash_request_ctx(sha->req);
+	u32 len, final, tail;
+	struct scatterlist *sg;
+
+	if (!ctx->total)
+		return 0;
+
+	if (ctx->bufcnt || ctx->offset)
+		return mtk_sha_update_slow(cryp, sha);
+
+	sg = ctx->sg;
+
+	if (!IS_ALIGNED(sg->offset, sizeof(u32)))
+		return mtk_sha_update_slow(cryp, sha);
+
+	if (!sg_is_last(sg) && !IS_ALIGNED(sg->length, ctx->bs))
+		/* size is not ctx->bs aligned */
+		return mtk_sha_update_slow(cryp, sha);
+
+	len = min(ctx->total, sg->length);
+
+	if (sg_is_last(sg)) {
+		if (!(ctx->flags & SHA_FLAGS_FINUP)) {
+			/* not last sg must be ctx->bs aligned */
+			tail = len & (ctx->bs - 1);
+			len -= tail;
+		}
+	}
+
+	ctx->total -= len;
+	ctx->offset = len; /* offset where to start slow */
+
+	final = (ctx->flags & SHA_FLAGS_FINUP) && !ctx->total;
+
+	/* Add padding */
+	if (final) {
+		size_t count;
+
+		tail = len & (ctx->bs - 1);
+		len -= tail;
+		ctx->total += tail;
+		ctx->offset = len; /* offset where to start slow */
+
+		sg = ctx->sg;
+		mtk_sha_append_sg(ctx);
+		mtk_sha_fill_padding(ctx, len);
+
+		ctx->dma_addr = dma_map_single(cryp->dev, ctx->buffer,
+					       SHA_BUF_SIZE, DMA_TO_DEVICE);
+		if (unlikely(dma_mapping_error(cryp->dev, ctx->dma_addr))) {
+			dev_err(cryp->dev, "dma map bytes error\n");
+			return -EINVAL;
+		}
+
+		sha->flags |= SHA_FLAGS_FINAL;
+		count = ctx->bufcnt;
+		ctx->bufcnt = 0;
+
+		if (len == 0) {
+			ctx->flags &= ~SHA_FLAGS_SG;
+			return mtk_sha_xmit(cryp, sha, ctx->dma_addr,
+					    count, 0, 0);
+
+		} else {
+			ctx->sg = sg;
+			if (!dma_map_sg(cryp->dev, ctx->sg, 1, DMA_TO_DEVICE)) {
+				dev_err(cryp->dev, "dma_map_sg error\n");
+				return -EINVAL;
+			}
+
+			ctx->flags |= SHA_FLAGS_SG;
+			return mtk_sha_xmit(cryp, sha, sg_dma_address(ctx->sg),
+					    len, ctx->dma_addr, count);
+		}
+	}
+
+	if (!dma_map_sg(cryp->dev, ctx->sg, 1, DMA_TO_DEVICE)) {
+		dev_err(cryp->dev, "dma_map_sg  error\n");
+		return -EINVAL;
+	}
+
+	ctx->flags |= SHA_FLAGS_SG;
+
+	return mtk_sha_xmit(cryp, sha, sg_dma_address(ctx->sg),
+			    len, 0, 0);
+}
+
+static int mtk_sha_final_req(struct mtk_cryp *cryp,
+			     struct mtk_sha_rec *sha)
+{
+	struct mtk_sha_reqctx *ctx = ahash_request_ctx(sha->req);
+	size_t count;
+
+	mtk_sha_fill_padding(ctx, 0);
+
+	sha->flags |= SHA_FLAGS_FINAL;
+	count = ctx->bufcnt;
+	ctx->bufcnt = 0;
+
+	return mtk_sha_dma_map(cryp, sha, ctx, count);
+}
+
+/* Copy ready hash (+ finalize hmac) */
+static int mtk_sha_finish(struct ahash_request *req)
+{
+	struct mtk_sha_reqctx *ctx = ahash_request_ctx(req);
+	__le32 *digest = ctx->info.digest;
+	u32 *result = (u32 *)req->result;
+	int i;
+
+	/* Get the hash from the digest buffer */
+	for (i = 0; i < SIZE_IN_WORDS(ctx->ds); i++)
+		result[i] = le32_to_cpu(digest[i]);
+
+	if (ctx->flags & SHA_FLAGS_HMAC)
+		return mtk_sha_finish_hmac(req);
+
+	return 0;
+}
+
+static void mtk_sha_finish_req(struct mtk_cryp *cryp,
+			       struct mtk_sha_rec *sha,
+			       int err)
+{
+	if (likely(!err && (SHA_FLAGS_FINAL & sha->flags)))
+		err = mtk_sha_finish(sha->req);
+
+	sha->flags &= ~(SHA_FLAGS_BUSY | SHA_FLAGS_FINAL);
+
+	sha->req->base.complete(&sha->req->base, err);
+
+	/* Handle new request */
+	tasklet_schedule(&sha->queue_task);
+}
+
+static int mtk_sha_handle_queue(struct mtk_cryp *cryp, u8 id,
+				struct ahash_request *req)
+{
+	struct mtk_sha_rec *sha = cryp->sha[id];
+	struct crypto_async_request *async_req, *backlog;
+	struct mtk_sha_reqctx *ctx;
+	unsigned long flags;
+	int err = 0, ret = 0;
+
+	spin_lock_irqsave(&sha->lock, flags);
+	if (req)
+		ret = ahash_enqueue_request(&sha->queue, req);
+
+	if (SHA_FLAGS_BUSY & sha->flags) {
+		spin_unlock_irqrestore(&sha->lock, flags);
+		return ret;
+	}
+
+	backlog = crypto_get_backlog(&sha->queue);
+	async_req = crypto_dequeue_request(&sha->queue);
+	if (async_req)
+		sha->flags |= SHA_FLAGS_BUSY;
+	spin_unlock_irqrestore(&sha->lock, flags);
+
+	if (!async_req)
+		return ret;
+
+	if (backlog)
+		backlog->complete(backlog, -EINPROGRESS);
+
+	req = ahash_request_cast(async_req);
+	ctx = ahash_request_ctx(req);
+
+	sha->req = req;
+
+	mtk_sha_info_init(ctx);
+
+	if (ctx->op == SHA_OP_UPDATE) {
+		err = mtk_sha_update_start(cryp, sha);
+		if (err != -EINPROGRESS && (ctx->flags & SHA_FLAGS_FINUP))
+			/* No final() after finup() */
+			err = mtk_sha_final_req(cryp, sha);
+	} else if (ctx->op == SHA_OP_FINAL) {
+		err = mtk_sha_final_req(cryp, sha);
+	}
+
+	if (unlikely(err != -EINPROGRESS))
+		/* Task will not finish it, so do it here */
+		mtk_sha_finish_req(cryp, sha, err);
+
+	return ret;
+}
+
+static int mtk_sha_enqueue(struct ahash_request *req, u32 op)
+{
+	struct mtk_sha_reqctx *ctx = ahash_request_ctx(req);
+	struct mtk_sha_ctx *tctx = crypto_tfm_ctx(req->base.tfm);
+
+	ctx->op = op;
+
+	return mtk_sha_handle_queue(tctx->cryp, tctx->id, req);
+}
+
+static void mtk_sha_unmap(struct mtk_cryp *cryp, struct mtk_sha_rec *sha)
+{
+	struct mtk_sha_reqctx *ctx = ahash_request_ctx(sha->req);
+
+	dma_unmap_single(cryp->dev, ctx->ct_dma, sizeof(ctx->info),
+			 DMA_BIDIRECTIONAL);
+
+	if (ctx->flags & SHA_FLAGS_SG) {
+		dma_unmap_sg(cryp->dev, ctx->sg, 1, DMA_TO_DEVICE);
+		if (ctx->sg->length == ctx->offset) {
+			ctx->sg = sg_next(ctx->sg);
+			if (ctx->sg)
+				ctx->offset = 0;
+		}
+		if (ctx->flags & SHA_FLAGS_PAD) {
+			dma_unmap_single(cryp->dev, ctx->dma_addr,
+					 SHA_BUF_SIZE, DMA_TO_DEVICE);
+		}
+	} else
+		dma_unmap_single(cryp->dev, ctx->dma_addr,
+				 SHA_BUF_SIZE, DMA_TO_DEVICE);
+}
+
+static void mtk_sha_complete(struct mtk_cryp *cryp,
+			     struct mtk_sha_rec *sha)
+{
+	int err = 0;
+
+	err = mtk_sha_update_start(cryp, sha);
+	if (err != -EINPROGRESS)
+		mtk_sha_finish_req(cryp, sha, err);
+}
+
+static int mtk_sha_update(struct ahash_request *req)
+{
+	struct mtk_sha_reqctx *ctx = ahash_request_ctx(req);
+
+	ctx->total = req->nbytes;
+	ctx->sg = req->src;
+	ctx->offset = 0;
+
+	if ((ctx->bufcnt + ctx->total < SHA_BUF_SIZE) &&
+	    !(ctx->flags & SHA_FLAGS_FINUP))
+		return mtk_sha_append_sg(ctx);
+
+	return mtk_sha_enqueue(req, SHA_OP_UPDATE);
+}
+
+static int mtk_sha_final(struct ahash_request *req)
+{
+	struct mtk_sha_reqctx *ctx = ahash_request_ctx(req);
+
+	ctx->flags |= SHA_FLAGS_FINUP;
+
+	if (ctx->flags & SHA_FLAGS_PAD)
+		return mtk_sha_finish(req);
+
+	return mtk_sha_enqueue(req, SHA_OP_FINAL);
+}
+
+static int mtk_sha_finup(struct ahash_request *req)
+{
+	struct mtk_sha_reqctx *ctx = ahash_request_ctx(req);
+	int err1, err2;
+
+	ctx->flags |= SHA_FLAGS_FINUP;
+
+	err1 = mtk_sha_update(req);
+	if (err1 == -EINPROGRESS || err1 == -EBUSY)
+		return err1;
+	/*
+	 * final() has to be always called to cleanup resources
+	 * even if update() failed
+	 */
+	err2 = mtk_sha_final(req);
+
+	return err1 ?: err2;
+}
+
+static int mtk_sha_digest(struct ahash_request *req)
+{
+	return mtk_sha_init(req) ?: mtk_sha_finup(req);
+}
+
+static int mtk_sha_setkey(struct crypto_ahash *tfm, const u8 *key,
+			  u32 keylen)
+{
+	struct mtk_sha_ctx *tctx = crypto_ahash_ctx(tfm);
+	struct mtk_sha_hmac_ctx *bctx = tctx->base;
+	size_t bs = crypto_shash_blocksize(bctx->shash);
+	size_t ds = crypto_shash_digestsize(bctx->shash);
+	int err, i;
+
+	SHASH_DESC_ON_STACK(shash, bctx->shash);
+
+	shash->tfm = bctx->shash;
+	shash->flags = crypto_shash_get_flags(bctx->shash) &
+		       CRYPTO_TFM_REQ_MAY_SLEEP;
+
+	if (keylen > bs) {
+		err = crypto_shash_digest(shash, key, keylen, bctx->ipad);
+		if (err)
+			return err;
+		keylen = ds;
+	} else {
+		memcpy(bctx->ipad, key, keylen);
+	}
+
+	memset(bctx->ipad + keylen, 0, bs - keylen);
+	memcpy(bctx->opad, bctx->ipad, bs);
+
+	for (i = 0; i < bs; i++) {
+		bctx->ipad[i] ^= 0x36;
+		bctx->opad[i] ^= 0x5c;
+	}
+
+	return 0;
+}
+
+static int mtk_sha_export(struct ahash_request *req, void *out)
+{
+	const struct mtk_sha_reqctx *ctx = ahash_request_ctx(req);
+
+	memcpy(out, ctx, sizeof(*ctx));
+	return 0;
+}
+
+static int mtk_sha_import(struct ahash_request *req, const void *in)
+{
+	struct mtk_sha_reqctx *ctx = ahash_request_ctx(req);
+
+	memcpy(ctx, in, sizeof(*ctx));
+	return 0;
+}
+
+static int mtk_sha_cra_init_alg(struct crypto_tfm *tfm,
+				const char *alg_base)
+{
+	struct mtk_sha_ctx *tctx = crypto_tfm_ctx(tfm);
+	struct mtk_cryp *cryp = NULL;
+
+	cryp = mtk_sha_find_dev(tctx);
+	if (!cryp)
+		return -ENODEV;
+
+	crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+				 sizeof(struct mtk_sha_reqctx));
+
+	if (alg_base) {
+		struct mtk_sha_hmac_ctx *bctx = tctx->base;
+
+		tctx->flags |= SHA_FLAGS_HMAC;
+		bctx->shash = crypto_alloc_shash(alg_base, 0,
+					CRYPTO_ALG_NEED_FALLBACK);
+		if (IS_ERR(bctx->shash)) {
+			pr_err("base driver %s could not be loaded.\n",
+			       alg_base);
+
+			return PTR_ERR(bctx->shash);
+		}
+	}
+	return 0;
+}
+
+static int mtk_sha_cra_init(struct crypto_tfm *tfm)
+{
+	return mtk_sha_cra_init_alg(tfm, NULL);
+}
+
+static int mtk_sha_cra_sha1_init(struct crypto_tfm *tfm)
+{
+	return mtk_sha_cra_init_alg(tfm, "sha1");
+}
+
+static int mtk_sha_cra_sha224_init(struct crypto_tfm *tfm)
+{
+	return mtk_sha_cra_init_alg(tfm, "sha224");
+}
+
+static int mtk_sha_cra_sha256_init(struct crypto_tfm *tfm)
+{
+	return mtk_sha_cra_init_alg(tfm, "sha256");
+}
+
+static int mtk_sha_cra_sha384_init(struct crypto_tfm *tfm)
+{
+	return mtk_sha_cra_init_alg(tfm, "sha384");
+}
+
+static int mtk_sha_cra_sha512_init(struct crypto_tfm *tfm)
+{
+	return mtk_sha_cra_init_alg(tfm, "sha512");
+}
+
+static void mtk_sha_cra_exit(struct crypto_tfm *tfm)
+{
+	struct mtk_sha_ctx *tctx = crypto_tfm_ctx(tfm);
+
+	if (tctx->flags & SHA_FLAGS_HMAC) {
+		struct mtk_sha_hmac_ctx *bctx = tctx->base;
+
+		crypto_free_shash(bctx->shash);
+	}
+}
+
+static struct ahash_alg algs_sha1_sha224_sha256[] = {
+{
+	.init		= mtk_sha_init,
+	.update		= mtk_sha_update,
+	.final		= mtk_sha_final,
+	.finup		= mtk_sha_finup,
+	.digest		= mtk_sha_digest,
+	.export		= mtk_sha_export,
+	.import		= mtk_sha_import,
+	.halg.digestsize	= SHA1_DIGEST_SIZE,
+	.halg.statesize = sizeof(struct mtk_sha_reqctx),
+	.halg.base	= {
+		.cra_name		= "sha1",
+		.cra_driver_name	= "mtk-sha1",
+		.cra_priority		= 400,
+		.cra_flags		= CRYPTO_ALG_ASYNC,
+		.cra_blocksize		= SHA1_BLOCK_SIZE,
+		.cra_ctxsize		= sizeof(struct mtk_sha_ctx),
+		.cra_alignmask		= SHA_ALIGN_MSK,
+		.cra_module		= THIS_MODULE,
+		.cra_init		= mtk_sha_cra_init,
+		.cra_exit		= mtk_sha_cra_exit,
+	}
+},
+{
+	.init		= mtk_sha_init,
+	.update		= mtk_sha_update,
+	.final		= mtk_sha_final,
+	.finup		= mtk_sha_finup,
+	.digest		= mtk_sha_digest,
+	.export		= mtk_sha_export,
+	.import		= mtk_sha_import,
+	.halg.digestsize	= SHA224_DIGEST_SIZE,
+	.halg.statesize = sizeof(struct mtk_sha_reqctx),
+	.halg.base	= {
+		.cra_name		= "sha224",
+		.cra_driver_name	= "mtk-sha224",
+		.cra_priority		= 400,
+		.cra_flags		= CRYPTO_ALG_ASYNC,
+		.cra_blocksize		= SHA224_BLOCK_SIZE,
+		.cra_ctxsize		= sizeof(struct mtk_sha_ctx),
+		.cra_alignmask		= SHA_ALIGN_MSK,
+		.cra_module		= THIS_MODULE,
+		.cra_init		= mtk_sha_cra_init,
+		.cra_exit		= mtk_sha_cra_exit,
+	}
+},
+{
+	.init		= mtk_sha_init,
+	.update		= mtk_sha_update,
+	.final		= mtk_sha_final,
+	.finup		= mtk_sha_finup,
+	.digest		= mtk_sha_digest,
+	.export		= mtk_sha_export,
+	.import		= mtk_sha_import,
+	.halg.digestsize	= SHA256_DIGEST_SIZE,
+	.halg.statesize = sizeof(struct mtk_sha_reqctx),
+	.halg.base	= {
+		.cra_name		= "sha256",
+		.cra_driver_name	= "mtk-sha256",
+		.cra_priority		= 400,
+		.cra_flags		= CRYPTO_ALG_ASYNC,
+		.cra_blocksize		= SHA256_BLOCK_SIZE,
+		.cra_ctxsize		= sizeof(struct mtk_sha_ctx),
+		.cra_alignmask		= SHA_ALIGN_MSK,
+		.cra_module		= THIS_MODULE,
+		.cra_init		= mtk_sha_cra_init,
+		.cra_exit		= mtk_sha_cra_exit,
+	}
+},
+{
+	.init		= mtk_sha_init,
+	.update		= mtk_sha_update,
+	.final		= mtk_sha_final,
+	.finup		= mtk_sha_finup,
+	.digest		= mtk_sha_digest,
+	.export		= mtk_sha_export,
+	.import		= mtk_sha_import,
+	.setkey		= mtk_sha_setkey,
+	.halg.digestsize	= SHA1_DIGEST_SIZE,
+	.halg.statesize = sizeof(struct mtk_sha_reqctx),
+	.halg.base	= {
+		.cra_name		= "hmac(sha1)",
+		.cra_driver_name	= "mtk-hmac-sha1",
+		.cra_priority		= 400,
+		.cra_flags		= CRYPTO_ALG_ASYNC |
+					  CRYPTO_ALG_NEED_FALLBACK,
+		.cra_blocksize		= SHA1_BLOCK_SIZE,
+		.cra_ctxsize		= sizeof(struct mtk_sha_ctx) +
+					sizeof(struct mtk_sha_hmac_ctx),
+		.cra_alignmask		= SHA_ALIGN_MSK,
+		.cra_module		= THIS_MODULE,
+		.cra_init		= mtk_sha_cra_sha1_init,
+		.cra_exit		= mtk_sha_cra_exit,
+	}
+},
+{
+	.init		= mtk_sha_init,
+	.update		= mtk_sha_update,
+	.final		= mtk_sha_final,
+	.finup		= mtk_sha_finup,
+	.digest		= mtk_sha_digest,
+	.export		= mtk_sha_export,
+	.import		= mtk_sha_import,
+	.setkey		= mtk_sha_setkey,
+	.halg.digestsize	= SHA224_DIGEST_SIZE,
+	.halg.statesize = sizeof(struct mtk_sha_reqctx),
+	.halg.base	= {
+		.cra_name		= "hmac(sha224)",
+		.cra_driver_name	= "mtk-hmac-sha224",
+		.cra_priority		= 400,
+		.cra_flags		= CRYPTO_ALG_ASYNC |
+					  CRYPTO_ALG_NEED_FALLBACK,
+		.cra_blocksize		= SHA224_BLOCK_SIZE,
+		.cra_ctxsize		= sizeof(struct mtk_sha_ctx) +
+					sizeof(struct mtk_sha_hmac_ctx),
+		.cra_alignmask		= SHA_ALIGN_MSK,
+		.cra_module		= THIS_MODULE,
+		.cra_init		= mtk_sha_cra_sha224_init,
+		.cra_exit		= mtk_sha_cra_exit,
+	}
+},
+{
+	.init		= mtk_sha_init,
+	.update		= mtk_sha_update,
+	.final		= mtk_sha_final,
+	.finup		= mtk_sha_finup,
+	.digest		= mtk_sha_digest,
+	.export		= mtk_sha_export,
+	.import		= mtk_sha_import,
+	.setkey		= mtk_sha_setkey,
+	.halg.digestsize	= SHA256_DIGEST_SIZE,
+	.halg.statesize = sizeof(struct mtk_sha_reqctx),
+	.halg.base	= {
+		.cra_name		= "hmac(sha256)",
+		.cra_driver_name	= "mtk-hmac-sha256",
+		.cra_priority		= 400,
+		.cra_flags		= CRYPTO_ALG_ASYNC |
+					  CRYPTO_ALG_NEED_FALLBACK,
+		.cra_blocksize		= SHA256_BLOCK_SIZE,
+		.cra_ctxsize		= sizeof(struct mtk_sha_ctx) +
+					sizeof(struct mtk_sha_hmac_ctx),
+		.cra_alignmask		= SHA_ALIGN_MSK,
+		.cra_module		= THIS_MODULE,
+		.cra_init		= mtk_sha_cra_sha256_init,
+		.cra_exit		= mtk_sha_cra_exit,
+	}
+},
+};
+
+static struct ahash_alg algs_sha384_sha512[] = {
+{
+	.init		= mtk_sha_init,
+	.update		= mtk_sha_update,
+	.final		= mtk_sha_final,
+	.finup		= mtk_sha_finup,
+	.digest		= mtk_sha_digest,
+	.export		= mtk_sha_export,
+	.import		= mtk_sha_import,
+	.halg.digestsize	= SHA384_DIGEST_SIZE,
+	.halg.statesize = sizeof(struct mtk_sha_reqctx),
+	.halg.base	= {
+		.cra_name		= "sha384",
+		.cra_driver_name	= "mtk-sha384",
+		.cra_priority		= 400,
+		.cra_flags		= CRYPTO_ALG_ASYNC,
+		.cra_blocksize		= SHA384_BLOCK_SIZE,
+		.cra_ctxsize		= sizeof(struct mtk_sha_ctx),
+		.cra_alignmask		= SHA_ALIGN_MSK,
+		.cra_module		= THIS_MODULE,
+		.cra_init		= mtk_sha_cra_init,
+		.cra_exit		= mtk_sha_cra_exit,
+	}
+},
+{
+	.init		= mtk_sha_init,
+	.update		= mtk_sha_update,
+	.final		= mtk_sha_final,
+	.finup		= mtk_sha_finup,
+	.digest		= mtk_sha_digest,
+	.export		= mtk_sha_export,
+	.import		= mtk_sha_import,
+	.halg.digestsize	= SHA512_DIGEST_SIZE,
+	.halg.statesize = sizeof(struct mtk_sha_reqctx),
+	.halg.base	= {
+		.cra_name		= "sha512",
+		.cra_driver_name	= "mtk-sha512",
+		.cra_priority		= 400,
+		.cra_flags		= CRYPTO_ALG_ASYNC,
+		.cra_blocksize		= SHA512_BLOCK_SIZE,
+		.cra_ctxsize		= sizeof(struct mtk_sha_ctx),
+		.cra_alignmask		= SHA_ALIGN_MSK,
+		.cra_module		= THIS_MODULE,
+		.cra_init		= mtk_sha_cra_init,
+		.cra_exit		= mtk_sha_cra_exit,
+	}
+},
+{
+	.init		= mtk_sha_init,
+	.update		= mtk_sha_update,
+	.final		= mtk_sha_final,
+	.finup		= mtk_sha_finup,
+	.digest		= mtk_sha_digest,
+	.export		= mtk_sha_export,
+	.import		= mtk_sha_import,
+	.setkey		= mtk_sha_setkey,
+	.halg.digestsize	= SHA384_DIGEST_SIZE,
+	.halg.statesize = sizeof(struct mtk_sha_reqctx),
+	.halg.base	= {
+		.cra_name		= "hmac(sha384)",
+		.cra_driver_name	= "mtk-hmac-sha384",
+		.cra_priority		= 400,
+		.cra_flags		= CRYPTO_ALG_ASYNC |
+					  CRYPTO_ALG_NEED_FALLBACK,
+		.cra_blocksize		= SHA384_BLOCK_SIZE,
+		.cra_ctxsize		= sizeof(struct mtk_sha_ctx) +
+					sizeof(struct mtk_sha_hmac_ctx),
+		.cra_alignmask		= SHA_ALIGN_MSK,
+		.cra_module		= THIS_MODULE,
+		.cra_init		= mtk_sha_cra_sha384_init,
+		.cra_exit		= mtk_sha_cra_exit,
+	}
+},
+{
+	.init		= mtk_sha_init,
+	.update		= mtk_sha_update,
+	.final		= mtk_sha_final,
+	.finup		= mtk_sha_finup,
+	.digest		= mtk_sha_digest,
+	.export		= mtk_sha_export,
+	.import		= mtk_sha_import,
+	.setkey		= mtk_sha_setkey,
+	.halg.digestsize	= SHA512_DIGEST_SIZE,
+	.halg.statesize = sizeof(struct mtk_sha_reqctx),
+	.halg.base	= {
+		.cra_name		= "hmac(sha512)",
+		.cra_driver_name	= "mtk-hmac-sha512",
+		.cra_priority		= 400,
+		.cra_flags		= CRYPTO_ALG_ASYNC |
+					  CRYPTO_ALG_NEED_FALLBACK,
+		.cra_blocksize		= SHA512_BLOCK_SIZE,
+		.cra_ctxsize		= sizeof(struct mtk_sha_ctx) +
+					sizeof(struct mtk_sha_hmac_ctx),
+		.cra_alignmask		= SHA_ALIGN_MSK,
+		.cra_module		= THIS_MODULE,
+		.cra_init		= mtk_sha_cra_sha512_init,
+		.cra_exit		= mtk_sha_cra_exit,
+	}
+},
+};
+
+static void mtk_sha_queue_task(unsigned long data)
+{
+	struct mtk_sha_rec *sha = (struct mtk_sha_rec *)data;
+
+	mtk_sha_handle_queue(sha->cryp, sha->id - MTK_RING2, NULL);
+}
+
+static void mtk_sha_done_task(unsigned long data)
+{
+	struct mtk_sha_rec *sha = (struct mtk_sha_rec *)data;
+	struct mtk_cryp *cryp = sha->cryp;
+
+	mtk_sha_unmap(cryp, sha);
+	mtk_sha_complete(cryp, sha);
+}
+
+static irqreturn_t mtk_sha_irq(int irq, void *dev_id)
+{
+	struct mtk_sha_rec *sha = (struct mtk_sha_rec *)dev_id;
+	struct mtk_cryp *cryp = sha->cryp;
+	u32 val = mtk_sha_read(cryp, RDR_STAT(sha->id));
+
+	mtk_sha_write(cryp, RDR_STAT(sha->id), val);
+
+	if (likely((SHA_FLAGS_BUSY & sha->flags))) {
+		mtk_sha_write(cryp, RDR_PROC_COUNT(sha->id), MTK_CNT_RST);
+		mtk_sha_write(cryp, RDR_THRESH(sha->id),
+			      MTK_RDR_PROC_THRESH | MTK_RDR_PROC_MODE);
+
+		tasklet_schedule(&sha->done_task);
+	} else {
+		dev_warn(cryp->dev, "SHA interrupt when no active requests.\n");
+	}
+	return IRQ_HANDLED;
+}
+
+/*
+ * The purpose of two SHA records is used to get extra performance.
+ * It is similar to mtk_aes_record_init().
+ */
+static int mtk_sha_record_init(struct mtk_cryp *cryp)
+{
+	struct mtk_sha_rec **sha = cryp->sha;
+	int i, err = -ENOMEM;
+
+	for (i = 0; i < MTK_REC_NUM; i++) {
+		sha[i] = kzalloc(sizeof(**sha), GFP_KERNEL);
+		if (!sha[i])
+			goto err_cleanup;
+
+		sha[i]->cryp = cryp;
+
+		spin_lock_init(&sha[i]->lock);
+		crypto_init_queue(&sha[i]->queue, SHA_QUEUE_SIZE);
+
+		tasklet_init(&sha[i]->queue_task, mtk_sha_queue_task,
+			     (unsigned long)sha[i]);
+		tasklet_init(&sha[i]->done_task, mtk_sha_done_task,
+			     (unsigned long)sha[i]);
+	}
+
+	/* Link to ring2 and ring3 respectively */
+	sha[0]->id = MTK_RING2;
+	sha[1]->id = MTK_RING3;
+
+	cryp->rec = 1;
+
+	return 0;
+
+err_cleanup:
+	for (; i--; )
+		kfree(sha[i]);
+	return err;
+}
+
+static void mtk_sha_record_free(struct mtk_cryp *cryp)
+{
+	int i;
+
+	for (i = 0; i < MTK_REC_NUM; i++) {
+		tasklet_kill(&cryp->sha[i]->done_task);
+		tasklet_kill(&cryp->sha[i]->queue_task);
+
+		kfree(cryp->sha[i]);
+	}
+}
+
+static void mtk_sha_unregister_algs(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(algs_sha1_sha224_sha256); i++)
+		crypto_unregister_ahash(&algs_sha1_sha224_sha256[i]);
+
+	for (i = 0; i < ARRAY_SIZE(algs_sha384_sha512); i++)
+		crypto_unregister_ahash(&algs_sha384_sha512[i]);
+}
+
+static int mtk_sha_register_algs(void)
+{
+	int err, i;
+
+	for (i = 0; i < ARRAY_SIZE(algs_sha1_sha224_sha256); i++) {
+		err = crypto_register_ahash(&algs_sha1_sha224_sha256[i]);
+		if (err)
+			goto err_sha_224_256_algs;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(algs_sha384_sha512); i++) {
+		err = crypto_register_ahash(&algs_sha384_sha512[i]);
+		if (err)
+			goto err_sha_384_512_algs;
+	}
+
+	return 0;
+
+err_sha_384_512_algs:
+	for (; i--; )
+		crypto_unregister_ahash(&algs_sha384_sha512[i]);
+	i = ARRAY_SIZE(algs_sha1_sha224_sha256);
+err_sha_224_256_algs:
+	for (; i--; )
+		crypto_unregister_ahash(&algs_sha1_sha224_sha256[i]);
+
+	return err;
+}
+
+int mtk_hash_alg_register(struct mtk_cryp *cryp)
+{
+	int err;
+
+	INIT_LIST_HEAD(&cryp->sha_list);
+
+	/* Initialize two hash records */
+	err = mtk_sha_record_init(cryp);
+	if (err)
+		goto err_record;
+
+	err = devm_request_irq(cryp->dev, cryp->irq[MTK_RING2], mtk_sha_irq,
+			       0, "mtk-sha", cryp->sha[0]);
+	if (err) {
+		dev_err(cryp->dev, "unable to request sha irq0.\n");
+		goto err_res;
+	}
+
+	err = devm_request_irq(cryp->dev, cryp->irq[MTK_RING3], mtk_sha_irq,
+			       0, "mtk-sha", cryp->sha[1]);
+	if (err) {
+		dev_err(cryp->dev, "unable to request sha irq1.\n");
+		goto err_res;
+	}
+
+	/* Enable ring2 and ring3 interrupt for hash */
+	mtk_sha_write(cryp, AIC_ENABLE_SET(MTK_RING2), MTK_IRQ_RDR2);
+	mtk_sha_write(cryp, AIC_ENABLE_SET(MTK_RING3), MTK_IRQ_RDR3);
+
+	spin_lock(&mtk_sha.lock);
+	list_add_tail(&cryp->sha_list, &mtk_sha.dev_list);
+	spin_unlock(&mtk_sha.lock);
+
+	err = mtk_sha_register_algs();
+	if (err)
+		goto err_algs;
+
+	return 0;
+
+err_algs:
+	spin_lock(&mtk_sha.lock);
+	list_del(&cryp->sha_list);
+	spin_unlock(&mtk_sha.lock);
+err_res:
+	mtk_sha_record_free(cryp);
+err_record:
+
+	dev_err(cryp->dev, "mtk-sha initialization failed.\n");
+	return err;
+}
+
+void mtk_hash_alg_release(struct mtk_cryp *cryp)
+{
+	spin_lock(&mtk_sha.lock);
+	list_del(&cryp->sha_list);
+	spin_unlock(&mtk_sha.lock);
+
+	mtk_sha_unregister_algs();
+	mtk_sha_record_free(cryp);
+}

+ 12 - 10
target/linux/mediatek/image/32.mk

@@ -1,6 +1,6 @@
 define Image/BuilduImage
 define Image/BuilduImage
 	$(CP) $(KDIR)/zImage$(2) $(KDIR)/zImage-$(1)$(2)
 	$(CP) $(KDIR)/zImage$(2) $(KDIR)/zImage-$(1)$(2)
-	cat $(LINUX_DIR)/arch/arm/boot/dts/mt7623-$1.dtb >> $(KDIR)/zImage-$(1)$(2)
+	cat $(LINUX_DIR)/arch/arm/boot/dts/$1.dtb >> $(KDIR)/zImage-$(1)$(2)
 	mkimage -A arm -O linux -T kernel -C none -a 0x80008000 -e 0x80008000 -n 'MIPS OpenWrt Linux-$(LINUX_VERSION)'  -d $(KDIR)/zImage-$(1)$(2) $(KDIR)/uImage-$(1)$(2)
 	mkimage -A arm -O linux -T kernel -C none -a 0x80008000 -e 0x80008000 -n 'MIPS OpenWrt Linux-$(LINUX_VERSION)'  -d $(KDIR)/zImage-$(1)$(2) $(KDIR)/uImage-$(1)$(2)
 endef
 endef
 
 
@@ -20,6 +20,7 @@ endif
 	)
 	)
 endef
 endef
 
 
+COMPAT_BPI-R2:=bananapi,bpi-r2
 COMPAT_EMMC:=mediatek,mt7623-rfb-emmc
 COMPAT_EMMC:=mediatek,mt7623-rfb-emmc
 COMPAT_NAND:=mediatek,mt7623-rfb-nand
 COMPAT_NAND:=mediatek,mt7623-rfb-nand
 COMPAT_NAND_EPHY:=mediatek,mt7623-rfb-nand-ephy
 COMPAT_NAND_EPHY:=mediatek,mt7623-rfb-nand-ephy
@@ -28,16 +29,17 @@ define Image/Build/squashfs
 	$(call prepare_generic_squashfs,$(KDIR)/root.squashfs)
 	$(call prepare_generic_squashfs,$(KDIR)/root.squashfs)
 	$(CP) $(KDIR)/root.squashfs $(BIN_DIR)/$(IMG_PREFIX)-root.squashfs
 	$(CP) $(KDIR)/root.squashfs $(BIN_DIR)/$(IMG_PREFIX)-root.squashfs
 
 
-	$(call Image/Build/SysupgradeCombined,eMMC,squashfs,$$(COMPAT_EMMC))
+	$(call Image/Build/SysupgradeCombined,mt7623n-bananapi-bpi-r2,squashfs,$$(COMPAT_EMMC))
+	$(call Image/Build/SysupgradeCombined,mt7623-eMMC,squashfs,$$(COMPAT_BPI-R2))
 
 
-	$(call Image/BuilduImage,NAND)
-	$(call Image/BuilduImage,NAND-ePHY)
+	$(call Image/BuilduImage,mt7623-NAND)
+	$(call Image/BuilduImage,mt7623-NAND-ePHY)
 ifneq ($(CONFIG_TARGET_ROOTFS_INITRAMFS),)
 ifneq ($(CONFIG_TARGET_ROOTFS_INITRAMFS),)
-	$(call Image/BuilduImage,NAND,-initramfs)
-	$(call Image/BuilduImage,NAND-ePHY,-initramfs)
-	$(CP) $(KDIR)/uImage-NAND-initramfs $(BIN_DIR)/$(IMG_PREFIX)-uImage-NAND-initramfs
-	$(CP) $(KDIR)/uImage-NAND-ePHY-initramfs $(BIN_DIR)/$(IMG_PREFIX)-uImage-NAND-ePHY-initramfs
+	$(call Image/BuilduImage,mt7623-NAND,-initramfs)
+	$(call Image/BuilduImage,mt7623-NAND-ePHY,-initramfs)
+	$(CP) $(KDIR)/uImage-mt7623-NAND-initramfs $(BIN_DIR)/$(IMG_PREFIX)-uImage-NAND-initramfs
+	$(CP) $(KDIR)/uImage-mt7623-NAND-ePHY-initramfs $(BIN_DIR)/$(IMG_PREFIX)-uImage-NAND-ePHY-initramfs
 endif
 endif
-	$(call Image/Build/SysupgradeNAND,NAND,$(1),$(KDIR)/uImage-NAND,$$(COMPAT_NAND))
-	$(call Image/Build/SysupgradeNAND,NAND-ePHY,$(1),$(KDIR)/uImage-NAND-ePHY,$$(COMPAT_NAND_EPHY))
+	$(call Image/Build/SysupgradeNAND,mt7623-NAND,$(1),$(KDIR)/uImage-mt7623-NAND,$$(COMPAT_NAND))
+	$(call Image/Build/SysupgradeNAND,mt7623-NAND-ePHY,$(1),$(KDIR)/uImage-mt7623-NAND-ePHY,$$(COMPAT_NAND_EPHY))
 endef
 endef

+ 14 - 0
target/linux/mediatek/modules.mk

@@ -0,0 +1,14 @@
+define KernelPackage/mediatek_hnat
+  SUBMENU:=Network Devices
+  TITLE:=MT7623 HNAT
+  DEPENDS:=@TARGET_mediatek +kmod-nf-conntrack +iptables-mod-ipmark
+  KCONFIG:= CONFIG_NET_MEDIATEK_HNAT=y
+  FILES:= \
+	$(LINUX_DIR)/drivers/net/ethernet/mediatek/mtk_hnat/mtkhnat.ko
+endef
+
+define KernelPackage/mediatek_hnat/description
+  Kernel modules for MediaTek HW NAT offloading
+endef
+
+$(eval $(call KernelPackage,mediatek_hnat))

+ 0 - 26
target/linux/mediatek/patches-4.9/0000-pinctrl-esw.patch

@@ -1,26 +0,0 @@
---- a/include/dt-bindings/pinctrl/mt7623-pinfunc.h
-+++ b/include/dt-bindings/pinctrl/mt7623-pinfunc.h
-@@ -505,6 +505,9 @@
- #define MT7623_PIN_272_G2_RXD3_FUNC_GPIO272 (MTK_PIN_NO(272) | 0)
- #define MT7623_PIN_272_G2_RXD3_FUNC_G2_RXD3 (MTK_PIN_NO(272) | 1)
- 
-+#define MT7623_PIN_273_ESW_INT_FUNC_GPIO273 (MTK_PIN_NO(273) | 0)
-+#define MT7623_PIN_273_ESW_INT_FUNC_ESW_INT (MTK_PIN_NO(273) | 1)
-+
- #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)
- 
---- a/drivers/pinctrl/mediatek/pinctrl-mtk-mt7623.h
-+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-mt7623.h
-@@ -1894,8 +1894,9 @@ static const struct mtk_desc_pin mtk_pin
- 	MTK_PIN(
- 		PINCTRL_PIN(273, "GPIO273"),
- 		NULL, "mt7623",
--		MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
--		MTK_FUNCTION(0, "GPIO273")
-+		MTK_EINT_FUNCTION(0, 168),
-+		MTK_FUNCTION(0, "GPIO273"),
-+		MTK_FUNCTION(1, "ESW_INT")
- 	),
- 	MTK_PIN(
- 		PINCTRL_PIN(274, "G2_RXDV"),

+ 0 - 53
target/linux/mediatek/patches-4.9/0001-NET-multi-phy-support.patch

@@ -1,53 +0,0 @@
-From 1e021917e634b173d466bf0dd3d2ae84e51a77ff Mon Sep 17 00:00:00 2001
-From: John Crispin <[email protected]>
-Date: Sun, 27 Jul 2014 09:38:50 +0100
-Subject: [PATCH 001/102] NET: multi phy support
-
-Signed-off-by: John Crispin <[email protected]>
----
- drivers/net/phy/phy.c |    9 ++++++---
- include/linux/phy.h   |    1 +
- 2 files changed, 7 insertions(+), 3 deletions(-)
-
---- a/drivers/net/phy/phy.c
-+++ b/drivers/net/phy/phy.c
-@@ -1035,7 +1035,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;
--			netif_carrier_off(phydev->attached_dev);
-+			if (!phydev->no_auto_carrier_off)
-+				netif_carrier_off(phydev->attached_dev);
- 			phydev->adjust_link(phydev->attached_dev);
- 			break;
- 		}
-@@ -1127,7 +1128,8 @@ void phy_state_machine(struct work_struc
- 			netif_carrier_on(phydev->attached_dev);
- 		} else {
- 			phydev->state = PHY_NOLINK;
--			netif_carrier_off(phydev->attached_dev);
-+			if (!phydev->no_auto_carrier_off)
-+				netif_carrier_off(phydev->attached_dev);
- 		}
- 
- 		phydev->adjust_link(phydev->attached_dev);
-@@ -1139,7 +1141,8 @@ void phy_state_machine(struct work_struc
- 	case PHY_HALTED:
- 		if (phydev->link) {
- 			phydev->link = 0;
--			netif_carrier_off(phydev->attached_dev);
-+			if (!phydev->no_auto_carrier_off)
-+				netif_carrier_off(phydev->attached_dev);
- 			phydev->adjust_link(phydev->attached_dev);
- 			do_suspend = true;
- 		}
---- a/include/linux/phy.h
-+++ b/include/linux/phy.h
-@@ -373,6 +373,7 @@ struct phy_device {
- 	bool is_pseudo_fixed_link;
- 	bool has_fixups;
- 	bool suspended;
-+	bool no_auto_carrier_off;
- 
- 	enum phy_state state;
- 

+ 23 - 0
target/linux/mediatek/patches-4.9/0001-arch-arm-add-dts-build-code.patch

@@ -0,0 +1,23 @@
+From 9fdcf63545855f3a6f82dee109510f4735e861c8 Mon Sep 17 00:00:00 2001
+From: John Crispin <[email protected]>
+Date: Thu, 10 Aug 2017 15:54:13 +0200
+Subject: [PATCH 01/57] arch: arm: add dts build code
+
+Signed-off-by: John Crispin <[email protected]>
+---
+ arch/arm/boot/dts/Makefile | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -950,6 +950,10 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \
+ 	mt6589-aquaris5.dtb \
+ 	mt6592-evb.dtb \
+ 	mt7623-evb.dtb \
++	mt7623-eMMC.dtb \
++	mt7623-NAND.dtb \
++	mt7623-NAND-ePHY.dtb \
++	mt7623n-bananapi-bpi-r2.dtb \
+ 	mt8127-moose.dtb \
+ 	mt8135-evbp1.dtb
+ dtb-$(CONFIG_ARCH_ZX) += zx296702-ad1.dtb

+ 3 - 3
target/linux/mediatek/patches-4.9/0024-dt-bindings-add-MediaTek-PCIe-binding-documentation.patch → target/linux/mediatek/patches-4.9/0002-dt-bindings-add-MediaTek-PCIe-binding-documentation.patch

@@ -1,11 +1,11 @@
-From 05be818061b9f2a0fa5ad0cde6881917ff14a2f2 Mon Sep 17 00:00:00 2001
+From ad2d4df46d8ef6a7aab20f0b668fa7db5257cbea Mon Sep 17 00:00:00 2001
 From: John Crispin <[email protected]>
 From: John Crispin <[email protected]>
 Date: Wed, 6 Jan 2016 21:55:10 +0100
 Date: Wed, 6 Jan 2016 21:55:10 +0100
-Subject: [PATCH 024/102] dt-bindings: add MediaTek PCIe binding documentation
+Subject: [PATCH 02/57] dt-bindings: add MediaTek PCIe binding documentation
 
 
 Signed-off-by: John Crispin <[email protected]>
 Signed-off-by: John Crispin <[email protected]>
 ---
 ---
- .../devicetree/bindings/pci/mediatek-pcie.txt      |  140 ++++++++++++++++++++
+ .../devicetree/bindings/pci/mediatek-pcie.txt      | 140 +++++++++++++++++++++
  1 file changed, 140 insertions(+)
  1 file changed, 140 insertions(+)
  create mode 100644 Documentation/devicetree/bindings/pci/mediatek-pcie.txt
  create mode 100644 Documentation/devicetree/bindings/pci/mediatek-pcie.txt
 
 

+ 7 - 7
target/linux/mediatek/patches-4.9/0025-PCI-mediatek-add-support-for-PCIe-found-on-MT7623-MT.patch → target/linux/mediatek/patches-4.9/0003-PCI-mediatek-add-support-for-PCIe-found-on-MT7623-MT.patch

@@ -1,7 +1,7 @@
-From 8ab1d4e0a9a68e03f472dee1c036a01d0198c20c Mon Sep 17 00:00:00 2001
+From 950bd9b0691dd10209c333086a6bdda0108ed3a8 Mon Sep 17 00:00:00 2001
 From: John Crispin <[email protected]>
 From: John Crispin <[email protected]>
 Date: Tue, 5 Jan 2016 20:20:04 +0100
 Date: Tue, 5 Jan 2016 20:20:04 +0100
-Subject: [PATCH 025/102] PCI: mediatek: add support for PCIe found on
+Subject: [PATCH 03/57] PCI: mediatek: add support for PCIe found on
  MT7623/MT2701
  MT7623/MT2701
 
 
 Add PCIe controller support on MediaTek MT2701/MT7623. The driver supports
 Add PCIe controller support on MediaTek MT2701/MT7623. The driver supports
@@ -10,16 +10,16 @@ a single Root complex (RC) with 3 Root Ports. The SoCs supports a Gen2
 
 
 Signed-off-by: John Crispin <[email protected]>
 Signed-off-by: John Crispin <[email protected]>
 ---
 ---
- arch/arm/mach-mediatek/Kconfig   |    1 +
- drivers/pci/host/Kconfig         |   11 +
- drivers/pci/host/Makefile        |    1 +
- drivers/pci/host/pcie-mediatek.c |  641 ++++++++++++++++++++++++++++++++++++++
+ arch/arm/mach-mediatek/Kconfig   |   1 +
+ drivers/pci/host/Kconfig         |  11 +
+ drivers/pci/host/Makefile        |   1 +
+ drivers/pci/host/pcie-mediatek.c | 641 +++++++++++++++++++++++++++++++++++++++
  4 files changed, 654 insertions(+)
  4 files changed, 654 insertions(+)
  create mode 100644 drivers/pci/host/pcie-mediatek.c
  create mode 100644 drivers/pci/host/pcie-mediatek.c
 
 
 --- a/arch/arm/mach-mediatek/Kconfig
 --- a/arch/arm/mach-mediatek/Kconfig
 +++ b/arch/arm/mach-mediatek/Kconfig
 +++ b/arch/arm/mach-mediatek/Kconfig
-@@ -29,6 +29,7 @@ config MACH_MT6592
+@@ -25,6 +25,7 @@ config MACH_MT6592
  config MACH_MT7623
  config MACH_MT7623
  	bool "MediaTek MT7623 SoCs support"
  	bool "MediaTek MT7623 SoCs support"
  	default ARCH_MEDIATEK
  	default ARCH_MEDIATEK

+ 5 - 5
target/linux/mediatek/patches-4.9/00013-soc-mediatek-Add-MT2701-power-dt-bindings.patch → target/linux/mediatek/patches-4.9/0004-soc-mediatek-Add-MT2701-power-dt-bindings.patch

@@ -1,7 +1,7 @@
-From 3e96c653372d8852c45dcd3bd856975157a0fd6a Mon Sep 17 00:00:00 2001
+From 2f47c01fe3015f4c649849ddffe04f12a122abe2 Mon Sep 17 00:00:00 2001
 From: Shunli Wang <[email protected]>
 From: Shunli Wang <[email protected]>
 Date: Thu, 20 Oct 2016 16:56:37 +0800
 Date: Thu, 20 Oct 2016 16:56:37 +0800
-Subject: [PATCH] soc: mediatek: Add MT2701 power dt-bindings
+Subject: [PATCH 04/57] soc: mediatek: Add MT2701 power dt-bindings
 
 
 Add power dt-bindings for MT2701.
 Add power dt-bindings for MT2701.
 
 
@@ -11,9 +11,9 @@ Acked-by: Rob Herring <[email protected]>
 Reviewed-by: Kevin Hilman <[email protected]>
 Reviewed-by: Kevin Hilman <[email protected]>
 Signed-off-by: Matthias Brugger <[email protected]>
 Signed-off-by: Matthias Brugger <[email protected]>
 ---
 ---
- .../devicetree/bindings/soc/mediatek/scpsys.txt    | 13 +++++++----
- include/dt-bindings/power/mt2701-power.h           | 27 ++++++++++++++++++++++
- 2 files changed, 35 insertions(+), 5 deletions(-)
+ .../devicetree/bindings/soc/mediatek/scpsys.txt    | 13 ++++++-----
+ include/dt-bindings/power/mt2701-power.h           | 26 ++++++++++++++++++++++
+ 2 files changed, 34 insertions(+), 5 deletions(-)
  create mode 100644 include/dt-bindings/power/mt2701-power.h
  create mode 100644 include/dt-bindings/power/mt2701-power.h
 
 
 --- a/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt
 --- a/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt

+ 2 - 2
target/linux/mediatek/patches-4.9/0009-clk-mediatek-Add-MT2701-clock-support.patch → target/linux/mediatek/patches-4.9/0005-clk-mediatek-Add-MT2701-clock-support.patch

@@ -1,7 +1,7 @@
-From a4c507d052390b42d7e8c59241e3c336796f730f Mon Sep 17 00:00:00 2001
+From f76b34c799d87ab241432b1241f6fc6d9db3ecb6 Mon Sep 17 00:00:00 2001
 From: Shunli Wang <[email protected]>
 From: Shunli Wang <[email protected]>
 Date: Tue, 5 Jan 2016 14:30:20 +0800
 Date: Tue, 5 Jan 2016 14:30:20 +0800
-Subject: [PATCH 009/102] clk: mediatek: Add MT2701 clock support
+Subject: [PATCH 05/57] clk: mediatek: Add MT2701 clock support
 
 
 Add MT2701 clock support, include topckgen, apmixedsys,
 Add MT2701 clock support, include topckgen, apmixedsys,
 infracfg, pericfg and subsystem clocks.
 infracfg, pericfg and subsystem clocks.

+ 3 - 3
target/linux/mediatek/patches-4.9/0011-reset-mediatek-mt2701-reset-driver.patch → target/linux/mediatek/patches-4.9/0006-reset-mediatek-mt2701-reset-driver.patch

@@ -1,7 +1,7 @@
-From 3ba0020ea70ffb5503eff1823be7fa5ceda38286 Mon Sep 17 00:00:00 2001
+From 596c3a7300c0419dba71d58cbd4136e0d1e12a4e Mon Sep 17 00:00:00 2001
 From: Shunli Wang <[email protected]>
 From: Shunli Wang <[email protected]>
 Date: Tue, 5 Jan 2016 14:30:22 +0800
 Date: Tue, 5 Jan 2016 14:30:22 +0800
-Subject: [PATCH 011/102] reset: mediatek: mt2701 reset driver
+Subject: [PATCH 06/57] reset: mediatek: mt2701 reset driver
 
 
 In infrasys and perifsys, there are many reset
 In infrasys and perifsys, there are many reset
 control bits for kinds of modules. These bits are
 control bits for kinds of modules. These bits are
@@ -11,7 +11,7 @@ into kernel's generic reset controller framework.
 Signed-off-by: Shunli Wang <[email protected]>
 Signed-off-by: Shunli Wang <[email protected]>
 Acked-by: Philipp Zabel <[email protected]>
 Acked-by: Philipp Zabel <[email protected]>
 ---
 ---
- drivers/clk/mediatek/clk-mt2701.c |    4 ++++
+ drivers/clk/mediatek/clk-mt2701.c | 4 ++++
  1 file changed, 4 insertions(+)
  1 file changed, 4 insertions(+)
 
 
 --- a/drivers/clk/mediatek/clk-mt2701.c
 --- a/drivers/clk/mediatek/clk-mt2701.c

+ 4 - 4
target/linux/mediatek/patches-4.9/0012-ARM-mediatek-Add-MT2701-config-options-for-mediatek-.patch → target/linux/mediatek/patches-4.9/0007-ARM-mediatek-Add-MT2701-config-options-for-mediatek-.patch

@@ -1,8 +1,8 @@
-From 32fa899c6ab79953e4f470fb23c38bcc40edc5c8 Mon Sep 17 00:00:00 2001
+From 60c14df3cc898b6b03d66ec725f9705bf431b677 Mon Sep 17 00:00:00 2001
 From: Erin Lo <[email protected]>
 From: Erin Lo <[email protected]>
 Date: Mon, 28 Dec 2015 15:09:02 +0800
 Date: Mon, 28 Dec 2015 15:09:02 +0800
-Subject: [PATCH 012/102] ARM: mediatek: Add MT2701 config options for
- mediatek SoCs.
+Subject: [PATCH 07/57] ARM: mediatek: Add MT2701 config options for mediatek
+ SoCs.
 
 
 The upcoming MTK pinctrl driver have a big pin table for each SoC
 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.
 and we don't want to bloat the kernel binary if we don't need it.
@@ -11,7 +11,7 @@ Add config options so we can build for one SoC only. Add MT2701.
 Signed-off-by: Erin Lo <[email protected]>
 Signed-off-by: Erin Lo <[email protected]>
 Acked-by: Linus Walleij <[email protected]>
 Acked-by: Linus Walleij <[email protected]>
 ---
 ---
- arch/arm/mach-mediatek/Kconfig |    4 ++++
+ arch/arm/mach-mediatek/Kconfig | 4 ++++
  1 file changed, 4 insertions(+)
  1 file changed, 4 insertions(+)
 
 
 --- a/arch/arm/mach-mediatek/Kconfig
 --- a/arch/arm/mach-mediatek/Kconfig

+ 3 - 2
target/linux/mediatek/patches-4.9/0014-soc-mediatek-Refine-scpsys-to-support-multiple-platf.patch → target/linux/mediatek/patches-4.9/0008-soc-mediatek-Refine-scpsys-to-support-multiple-platf.patch

@@ -1,7 +1,8 @@
-From 6078c651947a148c1de543b54fe55af43a63043a Mon Sep 17 00:00:00 2001
+From b5a1e520d8039c242b2157b511f684ce464d6e21 Mon Sep 17 00:00:00 2001
 From: James Liao <[email protected]>
 From: James Liao <[email protected]>
 Date: Thu, 20 Oct 2016 16:56:35 +0800
 Date: Thu, 20 Oct 2016 16:56:35 +0800
-Subject: [PATCH 1/2] soc: mediatek: Refine scpsys to support multiple platform
+Subject: [PATCH 08/57] soc: mediatek: Refine scpsys to support multiple
+ platform
 
 
 Refine scpsys driver common code to support multiple SoC / platform.
 Refine scpsys driver common code to support multiple SoC / platform.
 
 

+ 4 - 4
target/linux/mediatek/patches-4.9/0015-soc-mediatek-Add-MT2701-scpsys-driver.patch → target/linux/mediatek/patches-4.9/0009-soc-mediatek-Add-MT2701-scpsys-driver.patch

@@ -1,7 +1,7 @@
-From 112ef1882e12094c823937f9d72f2f598db02df7 Mon Sep 17 00:00:00 2001
+From fb9f97e047f5a831a54cd61529b8cfdc4d413bb6 Mon Sep 17 00:00:00 2001
 From: Shunli Wang <[email protected]>
 From: Shunli Wang <[email protected]>
 Date: Thu, 20 Oct 2016 16:56:38 +0800
 Date: Thu, 20 Oct 2016 16:56:38 +0800
-Subject: [PATCH 2/2] soc: mediatek: Add MT2701 scpsys driver
+Subject: [PATCH 09/57] soc: mediatek: Add MT2701 scpsys driver
 
 
 Add scpsys driver for MT2701.
 Add scpsys driver for MT2701.
 
 
@@ -14,8 +14,8 @@ Reviewed-by: Kevin Hilman <[email protected]>
 Signed-off-by: Matthias Brugger <[email protected]>
 Signed-off-by: Matthias Brugger <[email protected]>
 ---
 ---
  drivers/soc/mediatek/Kconfig      |   2 +-
  drivers/soc/mediatek/Kconfig      |   2 +-
- drivers/soc/mediatek/mtk-scpsys.c | 117 +++++++++++++++++++++++++++++++++++++-
- 2 files changed, 117 insertions(+), 2 deletions(-)
+ drivers/soc/mediatek/mtk-scpsys.c | 108 +++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 108 insertions(+), 2 deletions(-)
 
 
 --- a/drivers/soc/mediatek/Kconfig
 --- a/drivers/soc/mediatek/Kconfig
 +++ b/drivers/soc/mediatek/Kconfig
 +++ b/drivers/soc/mediatek/Kconfig

+ 4 - 5
target/linux/mediatek/patches-4.9/0017-clk-add-hifsys-reset.patch → target/linux/mediatek/patches-4.9/0010-clk-add-hifsys-reset.patch

@@ -1,7 +1,7 @@
-From f7121d2b19ddad33a09408a2c5923bfd95da8533 Mon Sep 17 00:00:00 2001
+From 600e2bd5c3019f31e90ec876f4efb6c209cf0d73 Mon Sep 17 00:00:00 2001
 From: John Crispin <[email protected]>
 From: John Crispin <[email protected]>
 Date: Wed, 6 Jan 2016 20:06:49 +0100
 Date: Wed, 6 Jan 2016 20:06:49 +0100
-Subject: [PATCH 017/102] clk: add hifsys reset
+Subject: [PATCH 10/57] clk: add hifsys reset
 
 
 Hi,
 Hi,
 
 
@@ -14,9 +14,8 @@ thanks,
 
 
 Signed-off-by: John Crispin <[email protected]>
 Signed-off-by: John Crispin <[email protected]>
 ---
 ---
- drivers/clk/mediatek/clk-mt2701.c                    |    2 ++
- include/dt-bindings/reset-controller/mt2701-resets.h |    9 +++++++++
- 2 files changed, 11 insertions(+)
+ drivers/clk/mediatek/clk-mt2701.c | 2 ++
+ 1 file changed, 2 insertions(+)
 
 
 --- a/drivers/clk/mediatek/clk-mt2701.c
 --- a/drivers/clk/mediatek/clk-mt2701.c
 +++ b/drivers/clk/mediatek/clk-mt2701.c
 +++ b/drivers/clk/mediatek/clk-mt2701.c

+ 4 - 6
target/linux/mediatek/patches-4.9/0026-scpsys-various-fixes.patch → target/linux/mediatek/patches-4.9/0011-scpsys-various-fixes.patch

@@ -1,13 +1,11 @@
-From 59aafd667d2880c90776931b6102b8252214d93c Mon Sep 17 00:00:00 2001
+From 1e889b3d38ab5fb425762da57313b4cc8fc2f165 Mon Sep 17 00:00:00 2001
 From: John Crispin <[email protected]>
 From: John Crispin <[email protected]>
 Date: Sun, 21 Feb 2016 13:52:12 +0100
 Date: Sun, 21 Feb 2016 13:52:12 +0100
-Subject: [PATCH 026/102] scpsys: various fixes
+Subject: [PATCH 11/57] scpsys: various fixes
 
 
 ---
 ---
- drivers/clk/mediatek/clk-mt2701.c        |    2 ++
- drivers/soc/mediatek/mtk-scpsys-mt2701.c |    8 --------
- include/dt-bindings/power/mt2701-power.h |    4 ++--
- 3 files changed, 4 insertions(+), 10 deletions(-)
+ drivers/clk/mediatek/clk-mt2701.c | 2 ++
+ 1 file changed, 2 insertions(+)
 
 
 --- a/drivers/clk/mediatek/clk-mt2701.c
 --- a/drivers/clk/mediatek/clk-mt2701.c
 +++ b/drivers/clk/mediatek/clk-mt2701.c
 +++ b/drivers/clk/mediatek/clk-mt2701.c

+ 3 - 3
target/linux/mediatek/patches-4.9/0052-clk-dont-disable-unused-clocks.patch → target/linux/mediatek/patches-4.9/0012-clk-dont-disable-unused-clocks.patch

@@ -1,11 +1,11 @@
-From 5238c5d1d38661955ed3b52f45c46e00bfc9eb6e Mon Sep 17 00:00:00 2001
+From 0e60d2112968ccb2570535bf19fb5020c9b28c08 Mon Sep 17 00:00:00 2001
 From: John Crispin <[email protected]>
 From: John Crispin <[email protected]>
 Date: Thu, 7 Apr 2016 07:18:35 +0200
 Date: Thu, 7 Apr 2016 07:18:35 +0200
-Subject: [PATCH 052/102] clk: dont disable unused clocks
+Subject: [PATCH 12/57] clk: dont disable unused clocks
 
 
 Signed-off-by: John Crispin <[email protected]>
 Signed-off-by: John Crispin <[email protected]>
 ---
 ---
- drivers/clk/clk.c |    2 +-
+ drivers/clk/clk.c | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)
  1 file changed, 1 insertion(+), 1 deletion(-)
 
 
 --- a/drivers/clk/clk.c
 --- a/drivers/clk/clk.c

+ 3 - 3
target/linux/mediatek/patches-4.9/0053-clk-mediatek-enable-critical-clocks.patch → target/linux/mediatek/patches-4.9/0013-clk-mediatek-enable-critical-clocks.patch

@@ -1,11 +1,11 @@
-From c8fd103d6c07af5db47f061b70759b7c69169656 Mon Sep 17 00:00:00 2001
+From 03bead9276653dc842f6970250bc7eba41faf777 Mon Sep 17 00:00:00 2001
 From: John Crispin <[email protected]>
 From: John Crispin <[email protected]>
 Date: Thu, 31 Mar 2016 06:46:51 +0200
 Date: Thu, 31 Mar 2016 06:46:51 +0200
-Subject: [PATCH 053/102] clk: mediatek: enable critical clocks
+Subject: [PATCH 13/57] clk: mediatek: enable critical clocks
 
 
 Signed-off-by: John Crispin <[email protected]>
 Signed-off-by: John Crispin <[email protected]>
 ---
 ---
- drivers/clk/mediatek/clk-mt2701.c |   22 ++++++++++++++++++++--
+ drivers/clk/mediatek/clk-mt2701.c | 22 ++++++++++++++++++++--
  1 file changed, 20 insertions(+), 2 deletions(-)
  1 file changed, 20 insertions(+), 2 deletions(-)
 
 
 --- a/drivers/clk/mediatek/clk-mt2701.c
 --- a/drivers/clk/mediatek/clk-mt2701.c

+ 10 - 10
target/linux/mediatek/patches-4.9/0054-clk-mediatek-Export-CPU-mux-clocks-for-CPU-frequency.patch → target/linux/mediatek/patches-4.9/0014-clk-mediatek-Export-CPU-mux-clocks-for-CPU-frequency.patch

@@ -1,21 +1,21 @@
-From 1387d4f0ebf4b48c09f2ea0d27a02936c3fa0010 Mon Sep 17 00:00:00 2001
+From 3a947321d72af191ee87a390295c661c876cc6f4 Mon Sep 17 00:00:00 2001
 From: John Crispin <[email protected]>
 From: John Crispin <[email protected]>
 Date: Thu, 31 Mar 2016 02:26:37 +0200
 Date: Thu, 31 Mar 2016 02:26:37 +0200
-Subject: [PATCH 054/102] clk: mediatek: Export CPU mux clocks for CPU
- frequency control
+Subject: [PATCH 14/57] clk: mediatek: Export CPU mux clocks for CPU frequency
+ control
 
 
 This patch adds CPU mux clocks which are used by Mediatek cpufreq driver
 This patch adds CPU mux clocks which are used by Mediatek cpufreq driver
 for intermediate clock source switching.
 for intermediate clock source switching.
 
 
 Signed-off-by: Pi-Cheng Chen <[email protected]>
 Signed-off-by: Pi-Cheng Chen <[email protected]>
 ---
 ---
- 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 +-
+ 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(-)
  7 files changed, 186 insertions(+), 3 deletions(-)
  create mode 100644 drivers/clk/mediatek/clk-cpumux.c
  create mode 100644 drivers/clk/mediatek/clk-cpumux.c
  create mode 100644 drivers/clk/mediatek/clk-cpumux.h
  create mode 100644 drivers/clk/mediatek/clk-cpumux.h

+ 5 - 5
target/linux/mediatek/patches-4.9/0055-cpufreq-mediatek-add-driver.patch → target/linux/mediatek/patches-4.9/0015-cpufreq-mediatek-add-driver.patch

@@ -1,13 +1,13 @@
-From 60f4e41b367bdb29530468c91c1e613b17a37755 Mon Sep 17 00:00:00 2001
+From 8aa2c6c4d8b20c0e9c69b15db4a0039d33f8b365 Mon Sep 17 00:00:00 2001
 From: John Crispin <[email protected]>
 From: John Crispin <[email protected]>
 Date: Wed, 30 Mar 2016 23:48:53 +0200
 Date: Wed, 30 Mar 2016 23:48:53 +0200
-Subject: [PATCH 055/102] cpufreq: mediatek: add driver
+Subject: [PATCH 15/57] cpufreq: mediatek: add driver
 
 
 Signed-off-by: John Crispin <[email protected]>
 Signed-off-by: John Crispin <[email protected]>
 ---
 ---
- drivers/cpufreq/Kconfig.arm      |    9 +
- drivers/cpufreq/Makefile         |    1 +
- drivers/cpufreq/mt7623-cpufreq.c |  389 ++++++++++++++++++++++++++++++++++++++
+ drivers/cpufreq/Kconfig.arm      |   9 +
+ drivers/cpufreq/Makefile         |   1 +
+ drivers/cpufreq/mt7623-cpufreq.c | 389 +++++++++++++++++++++++++++++++++++++++
  3 files changed, 399 insertions(+)
  3 files changed, 399 insertions(+)
  create mode 100644 drivers/cpufreq/mt7623-cpufreq.c
  create mode 100644 drivers/cpufreq/mt7623-cpufreq.c
 
 

+ 6 - 8
target/linux/mediatek/patches-4.9/0071-pwm-add-pwm-mediatek.patch → target/linux/mediatek/patches-4.9/0016-pwm-add-pwm-mediatek.patch

@@ -1,16 +1,14 @@
-From 6f5941c93bdf7649f392f1263b9068d360ceab4d Mon Sep 17 00:00:00 2001
+From 201be68268eddb1568c41780a62868cc1666a2de Mon Sep 17 00:00:00 2001
 From: John Crispin <[email protected]>
 From: John Crispin <[email protected]>
 Date: Fri, 6 May 2016 02:55:48 +0200
 Date: Fri, 6 May 2016 02:55:48 +0200
-Subject: [PATCH 071/102] pwm: add pwm-mediatek
+Subject: [PATCH 16/57] pwm: add pwm-mediatek
 
 
 Signed-off-by: John Crispin <[email protected]>
 Signed-off-by: John Crispin <[email protected]>
 ---
 ---
- 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(+)
+ drivers/pwm/Kconfig        |   9 ++
+ drivers/pwm/Makefile       |   1 +
+ drivers/pwm/pwm-mediatek.c | 230 +++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 240 insertions(+)
  create mode 100644 drivers/pwm/pwm-mediatek.c
  create mode 100644 drivers/pwm/pwm-mediatek.c
 
 
 --- a/drivers/pwm/Kconfig
 --- a/drivers/pwm/Kconfig

+ 27 - 0
target/linux/mediatek/patches-4.9/0017-mfd-mt6397-Add-MT6323-LED-support-into-MT6397-driver.patch

@@ -0,0 +1,27 @@
+From 2b866d69f6198701457d29c5886c0ad7865c785f Mon Sep 17 00:00:00 2001
+From: Sean Wang <[email protected]>
+Date: Sat, 25 Feb 2017 02:47:21 +0800
+Subject: [PATCH 17/57] mfd: mt6397: Add MT6323 LED support into MT6397 driver
+
+Add compatible string as "mt6323-led" that will make
+the OF core spawn child devices for the LED subnode
+of that MT6323 MFD device.
+
+Signed-off-by: Sean Wang <[email protected]>
+---
+ drivers/mfd/mt6397-core.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/mfd/mt6397-core.c
++++ b/drivers/mfd/mt6397-core.c
+@@ -48,6 +48,10 @@ static const struct mfd_cell mt6323_devs
+ 		.name = "mt6323-regulator",
+ 		.of_compatible = "mediatek,mt6323-regulator"
+ 	},
++	{
++		.name = "mt6323-led",
++		.of_compatible = "mediatek,mt6323-led"
++	},
+ };
+ 
+ static const struct mfd_cell mt6397_devs[] = {

+ 4 - 17
target/linux/mediatek/patches-4.9/0085-pmic-led0.patch → target/linux/mediatek/patches-4.9/0018-dt-bindings-leds-Add-document-bindings-for-leds-mt63.patch

@@ -1,21 +1,8 @@
-From patchwork Mon Mar 20 06:47:24 2017
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v6,1/4] dt-bindings: leds: Add document bindings for leds-mt6323
-From: [email protected]
-X-Patchwork-Id: 9633073
-Message-Id: <[email protected]>
-To: <[email protected]>, <[email protected]>, <[email protected]>, 
- <[email protected]>, <[email protected]>, <[email protected]>,
- <[email protected]>
-Cc: [email protected], [email protected],
- Sean Wang <[email protected]>, [email protected],
- [email protected], [email protected],
- [email protected]
-Date: Mon, 20 Mar 2017 14:47:24 +0800
-
+From 424ca23e68b043ce26d6981839ca825ef8637aba Mon Sep 17 00:00:00 2001
 From: Sean Wang <[email protected]>
 From: Sean Wang <[email protected]>
+Date: Mon, 20 Mar 2017 14:47:24 +0800
+Subject: [PATCH 18/57] dt-bindings: leds: Add document bindings for
+ leds-mt6323
 
 
 This patch adds documentation for devicetree bindings for LED support on
 This patch adds documentation for devicetree bindings for LED support on
 MT6323 PMIC.
 MT6323 PMIC.

+ 24 - 0
target/linux/mediatek/patches-4.9/0019-dt-bindings-mfd-Add-the-description-for-LED-as-the-s.patch

@@ -0,0 +1,24 @@
+From 7c137e4b83f32a67ccf6b39fa455aca71980a21f Mon Sep 17 00:00:00 2001
+From: Sean Wang <[email protected]>
+Date: Mon, 20 Mar 2017 14:47:25 +0800
+Subject: [PATCH 19/57] dt-bindings: mfd: Add the description for LED as the
+ sub module
+
+This patch adds description for LED as the sub-module on MT6397/MT6323
+multifunction device.
+
+Signed-off-by: Sean Wang <[email protected]>
+---
+ Documentation/devicetree/bindings/mfd/mt6397.txt | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/Documentation/devicetree/bindings/mfd/mt6397.txt
++++ b/Documentation/devicetree/bindings/mfd/mt6397.txt
+@@ -6,6 +6,7 @@ MT6397/MT6323 is a multifunction device
+ - Audio codec
+ - GPIO
+ - Clock
++- LED
+ 
+ It is interfaced to host controller using SPI interface by a proprietary hardware
+ called PMIC wrapper or pwrap. MT6397/MT6323 MFD is a child device of pwrap.

+ 4 - 19
target/linux/mediatek/patches-4.9/0087-pmic-led2.patch → target/linux/mediatek/patches-4.9/0020-leds-Add-LED-support-for-MT6323-PMIC.patch

@@ -1,21 +1,7 @@
-From patchwork Mon Mar 20 06:47:26 2017
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v6,3/4] leds: Add LED support for MT6323 PMIC
-From: [email protected]
-X-Patchwork-Id: 9633081
-Message-Id: <[email protected]>
-To: <[email protected]>, <[email protected]>, <[email protected]>, 
- <[email protected]>, <[email protected]>, <[email protected]>,
- <[email protected]>
-Cc: [email protected], [email protected],
- Sean Wang <[email protected]>, [email protected],
- [email protected], [email protected],
- [email protected]
-Date: Mon, 20 Mar 2017 14:47:26 +0800
-
+From e482f9590f2e831c68bcf85e3f9f4c88bbd3329f Mon Sep 17 00:00:00 2001
 From: Sean Wang <[email protected]>
 From: Sean Wang <[email protected]>
+Date: Mon, 20 Mar 2017 14:47:26 +0800
+Subject: [PATCH 20/57] leds: Add LED support for MT6323 PMIC
 
 
 MT6323 PMIC is a multi-function device that includes LED function.
 MT6323 PMIC is a multi-function device that includes LED function.
 It allows attaching up to 4 LEDs which can either be on, off or dimmed
 It allows attaching up to 4 LEDs which can either be on, off or dimmed
@@ -25,9 +11,8 @@ Signed-off-by: Sean Wang <[email protected]>
 Reviewed-by: Jacek Anaszewski <[email protected]>
 Reviewed-by: Jacek Anaszewski <[email protected]>
 ---
 ---
  drivers/leds/Kconfig       |   8 +
  drivers/leds/Kconfig       |   8 +
- drivers/leds/Makefile      |   1 +
  drivers/leds/leds-mt6323.c | 502 +++++++++++++++++++++++++++++++++++++++++++++
  drivers/leds/leds-mt6323.c | 502 +++++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 511 insertions(+)
+ 2 files changed, 510 insertions(+)
  create mode 100644 drivers/leds/leds-mt6323.c
  create mode 100644 drivers/leds/leds-mt6323.c
 
 
 --- a/drivers/leds/Kconfig
 --- a/drivers/leds/Kconfig

+ 27 - 0
target/linux/mediatek/patches-4.9/0021-mfd-mt6397-Align-the-placement-at-which-the-mfd_cell.patch

@@ -0,0 +1,27 @@
+From 6e81b4fee93c004078465589128ba07b6855be02 Mon Sep 17 00:00:00 2001
+From: Sean Wang <[email protected]>
+Date: Mon, 20 Mar 2017 14:47:27 +0800
+Subject: [PATCH 21/57] mfd: mt6397: Align the placement at which the mfd_cell
+ of LED is defined
+
+Align the placement as which the mfd_cell of LED is defined as the other
+members done on the structure.
+
+Signed-off-by: Sean Wang <[email protected]>
+Acked-by: Lee Jones <[email protected]>
+---
+ drivers/mfd/mt6397-core.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/mfd/mt6397-core.c
++++ b/drivers/mfd/mt6397-core.c
+@@ -47,8 +47,7 @@ static const struct mfd_cell mt6323_devs
+ 	{
+ 		.name = "mt6323-regulator",
+ 		.of_compatible = "mediatek,mt6323-regulator"
+-	},
+-	{
++	}, {
+ 		.name = "mt6323-led",
+ 		.of_compatible = "mediatek,mt6323-led"
+ 	},

+ 10 - 0
target/linux/mediatek/patches-4.9/0103-nand_fixes.patch → target/linux/mediatek/patches-4.9/0022-nand-make-bootrom-work-with-upstream-driver.patch

@@ -1,3 +1,13 @@
+From 453ebd5d6b535388972fcea747025ced3afca5cc Mon Sep 17 00:00:00 2001
+From: John Crispin <[email protected]>
+Date: Thu, 10 Aug 2017 14:47:06 +0200
+Subject: [PATCH 22/57] nand: make bootrom work with upstream driver
+
+Signed-off-by: John Crispin <[email protected]>
+---
+ drivers/mtd/nand/mtk_nand.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
 --- a/drivers/mtd/nand/mtk_nand.c
 --- a/drivers/mtd/nand/mtk_nand.c
 +++ b/drivers/mtd/nand/mtk_nand.c
 +++ b/drivers/mtd/nand/mtk_nand.c
 @@ -1073,8 +1073,8 @@ static int mtk_nfc_ooblayout_free(struct
 @@ -1073,8 +1073,8 @@ static int mtk_nfc_ooblayout_free(struct

+ 81 - 0
target/linux/mediatek/patches-4.9/0023-rng-add-mediatek-hw-rng.patch

@@ -0,0 +1,81 @@
+From 4ad0accdfb0941de1440906461c08bee715378d5 Mon Sep 17 00:00:00 2001
+From: John Crispin <[email protected]>
+Date: Thu, 10 Aug 2017 15:57:44 +0200
+Subject: [PATCH 23/57] rng: add mediatek hw rng
+
+Signed-off-by: John Crispin <[email protected]>
+---
+ drivers/char/hw_random/Kconfig  | 14 ++++++++++++++
+ drivers/char/hw_random/Makefile |  1 +
+ drivers/crypto/Kconfig          | 18 ++++++++++++++++++
+ drivers/crypto/Makefile         |  1 +
+ 4 files changed, 34 insertions(+)
+
+--- a/drivers/char/hw_random/Kconfig
++++ b/drivers/char/hw_random/Kconfig
+@@ -166,6 +166,20 @@ config HW_RANDOM_IXP4XX
+ 
+ 	  If unsure, say Y.
+ 
++config HW_RANDOM_MTK
++	tristate "Mediatek Random Number Generator support"
++	depends on HW_RANDOM
++	depends on ARCH_MEDIATEK || COMPILE_TEST
++	default y
++	---help---
++	  This driver provides kernel-side support for the Random Number
++	  Generator hardware found on Mediatek SoCs.
++
++	  To compile this driver as a module, choose M here. the
++	  module will be called mtk-rng.
++
++	  If unsure, say Y.
++
+ config HW_RANDOM_OMAP
+ 	tristate "OMAP Random Number Generator support"
+ 	depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS
+--- a/drivers/char/hw_random/Makefile
++++ b/drivers/char/hw_random/Makefile
+@@ -35,4 +35,5 @@ obj-$(CONFIG_HW_RANDOM_XGENE) += xgene-r
+ obj-$(CONFIG_HW_RANDOM_STM32) += stm32-rng.o
+ obj-$(CONFIG_HW_RANDOM_PIC32) += pic32-rng.o
+ obj-$(CONFIG_HW_RANDOM_MESON) += meson-rng.o
++obj-$(CONFIG_HW_RANDOM_MTK)	+= mtk-rng.o
+ obj-$(CONFIG_HW_RANDOM_CAVIUM) += cavium-rng.o cavium-rng-vf.o
+--- a/drivers/crypto/Kconfig
++++ b/drivers/crypto/Kconfig
+@@ -553,6 +553,24 @@ config CRYPTO_DEV_ROCKCHIP
+ 	  This driver interfaces with the hardware crypto accelerator.
+ 	  Supporting cbc/ecb chainmode, and aes/des/des3_ede cipher mode.
+ 
++config CRYPTO_DEV_MEDIATEK
++	tristate "MediaTek's EIP97 Cryptographic Engine driver"
++	depends on HAS_DMA
++	depends on (ARM && ARCH_MEDIATEK) || COMPILE_TEST
++	select CRYPTO_AES
++	select CRYPTO_AEAD
++	select CRYPTO_BLKCIPHER
++	select CRYPTO_CTR
++	select CRYPTO_SHA1
++	select CRYPTO_SHA256
++	select CRYPTO_SHA512
++	select CRYPTO_HMAC
++	help
++	  This driver allows you to utilize the hardware crypto accelerator
++	  EIP97 which can be found on the MT7623 MT2701, MT8521p, etc ....
++	  Select this if you want to use it for AES/SHA1/SHA2 algorithms.
++
++
+ source "drivers/crypto/chelsio/Kconfig"
+ 
+ endif # CRYPTO_HW
+--- a/drivers/crypto/Makefile
++++ b/drivers/crypto/Makefile
+@@ -10,6 +10,7 @@ obj-$(CONFIG_CRYPTO_DEV_IMGTEC_HASH) +=
+ obj-$(CONFIG_CRYPTO_DEV_IXP4XX) += ixp4xx_crypto.o
+ obj-$(CONFIG_CRYPTO_DEV_MV_CESA) += mv_cesa.o
+ obj-$(CONFIG_CRYPTO_DEV_MARVELL_CESA) += marvell/
++obj-$(CONFIG_CRYPTO_DEV_MEDIATEK) += mediatek/
+ obj-$(CONFIG_CRYPTO_DEV_MXS_DCP) += mxs-dcp.o
+ obj-$(CONFIG_CRYPTO_DEV_NIAGARA2) += n2_crypto.o
+ n2_crypto-y := n2_core.o n2_asm.o

+ 1034 - 0
target/linux/mediatek/patches-4.9/0024-media-rc-add-driver-for-IR-remote-receiver-on-MT7623.patch

@@ -0,0 +1,1034 @@
+From 6e0336d1660725c06b6ab4f5361873538dbaa9f9 Mon Sep 17 00:00:00 2001
+From: Sean Wang <[email protected]>
+Date: Fri, 13 Jan 2017 15:35:39 +0800
+Subject: [PATCH 24/57] media: rc: add driver for IR remote receiver on MT7623
+ SoC
+
+This patch adds driver for IR controller on MT7623 SoC.
+and should also work on similar Mediatek SoC. Currently
+testing successfully on NEC and SONY remote controller
+only but it should work on others (lirc, rc-5 and rc-6).
+
+Signed-off-by: Sean Wang <[email protected]>
+Reviewed-by: Sean Young <[email protected]>
+---
+ drivers/media/rc/Kconfig   |  11 ++
+ drivers/media/rc/mtk-cir.c | 329 +++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 340 insertions(+)
+ create mode 100644 drivers/media/rc/mtk-cir.c
+
+--- a/drivers/media/rc/Kconfig
++++ b/drivers/media/rc/Kconfig
+@@ -235,6 +235,17 @@ config IR_MESON
+ 	   To compile this driver as a module, choose M here: the
+ 	   module will be called meson-ir.
+ 
++config IR_MTK
++	tristate "Mediatek IR remote receiver"
++	depends on RC_CORE
++	depends on ARCH_MEDIATEK || COMPILE_TEST
++	---help---
++	   Say Y if you want to use the IR remote receiver available
++	   on Mediatek SoCs.
++
++	   To compile this driver as a module, choose M here: the
++	   module will be called mtk-cir.
++
+ config IR_NUVOTON
+ 	tristate "Nuvoton w836x7hg Consumer Infrared Transceiver"
+ 	depends on PNP
+--- /dev/null
++++ b/drivers/media/rc/mtk-cir.c
+@@ -0,0 +1,329 @@
++/*
++ * Driver for Mediatek IR Receiver Controller
++ *
++ * Copyright (C) 2017 Sean Wang <[email protected]>
++ *
++ * 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/interrupt.h>
++#include <linux/module.h>
++#include <linux/of_platform.h>
++#include <linux/reset.h>
++#include <media/rc-core.h>
++
++#define MTK_IR_DEV KBUILD_MODNAME
++
++/* Register to enable PWM and IR */
++#define MTK_CONFIG_HIGH_REG       0x0c
++/* Enable IR pulse width detection */
++#define MTK_PWM_EN		  BIT(13)
++/* Enable IR hardware function */
++#define MTK_IR_EN		  BIT(0)
++
++/* Register to setting sample period */
++#define MTK_CONFIG_LOW_REG        0x10
++/* Field to set sample period */
++#define CHK_PERIOD		  DIV_ROUND_CLOSEST(MTK_IR_SAMPLE,  \
++						    MTK_IR_CLK_PERIOD)
++#define MTK_CHK_PERIOD            (((CHK_PERIOD) << 8) & (GENMASK(20, 8)))
++#define MTK_CHK_PERIOD_MASK	  (GENMASK(20, 8))
++
++/* Register to clear state of state machine */
++#define MTK_IRCLR_REG             0x20
++/* Bit to restart IR receiving */
++#define MTK_IRCLR		  BIT(0)
++
++/* Register containing pulse width data */
++#define MTK_CHKDATA_REG(i)        (0x88 + 4 * (i))
++#define MTK_WIDTH_MASK		  (GENMASK(7, 0))
++
++/* Register to enable IR interrupt */
++#define MTK_IRINT_EN_REG          0xcc
++/* Bit to enable interrupt */
++#define MTK_IRINT_EN		  BIT(0)
++
++/* Register to ack IR interrupt */
++#define MTK_IRINT_CLR_REG         0xd0
++/* Bit to clear interrupt status */
++#define MTK_IRINT_CLR		  BIT(0)
++
++/* Maximum count of samples */
++#define MTK_MAX_SAMPLES		  0xff
++/* Indicate the end of IR message */
++#define MTK_IR_END(v, p)	  ((v) == MTK_MAX_SAMPLES && (p) == 0)
++/* Number of registers to record the pulse width */
++#define MTK_CHKDATA_SZ		  17
++/* Source clock frequency */
++#define MTK_IR_BASE_CLK		  273000000
++/* Frequency after IR internal divider */
++#define MTK_IR_CLK_FREQ		  (MTK_IR_BASE_CLK / 4)
++/* Period for MTK_IR_CLK in ns*/
++#define MTK_IR_CLK_PERIOD	  DIV_ROUND_CLOSEST(1000000000ul,  \
++						    MTK_IR_CLK_FREQ)
++/* Sample period in ns */
++#define MTK_IR_SAMPLE		  (MTK_IR_CLK_PERIOD * 0xc00)
++
++/* struct mtk_ir -	This is the main datasructure for holding the state
++ *			of the driver
++ * @dev:		The device pointer
++ * @rc:			The rc instrance
++ * @irq:		The IRQ that we are using
++ * @base:		The mapped register i/o base
++ * @clk:		The clock that we are using
++ */
++struct mtk_ir {
++	struct device	*dev;
++	struct rc_dev	*rc;
++	void __iomem	*base;
++	int		irq;
++	struct clk	*clk;
++};
++
++static void mtk_w32_mask(struct mtk_ir *ir, u32 val, u32 mask, unsigned int reg)
++{
++	u32 tmp;
++
++	tmp = __raw_readl(ir->base + reg);
++	tmp = (tmp & ~mask) | val;
++	__raw_writel(tmp, ir->base + reg);
++}
++
++static void mtk_w32(struct mtk_ir *ir, u32 val, unsigned int reg)
++{
++	__raw_writel(val, ir->base + reg);
++}
++
++static u32 mtk_r32(struct mtk_ir *ir, unsigned int reg)
++{
++	return __raw_readl(ir->base + reg);
++}
++
++static inline void mtk_irq_disable(struct mtk_ir *ir, u32 mask)
++{
++	u32 val;
++
++	val = mtk_r32(ir, MTK_IRINT_EN_REG);
++	mtk_w32(ir, val & ~mask, MTK_IRINT_EN_REG);
++}
++
++static inline void mtk_irq_enable(struct mtk_ir *ir, u32 mask)
++{
++	u32 val;
++
++	val = mtk_r32(ir, MTK_IRINT_EN_REG);
++	mtk_w32(ir, val | mask, MTK_IRINT_EN_REG);
++}
++
++static irqreturn_t mtk_ir_irq(int irqno, void *dev_id)
++{
++	struct mtk_ir *ir = dev_id;
++	u8  wid = 0;
++	u32 i, j, val;
++	DEFINE_IR_RAW_EVENT(rawir);
++
++	/* Reset decoder state machine explicitly is required
++	 * because 1) the longest duration for space MTK IR hardware
++	 * could record is not safely long. e.g  12ms if rx resolution
++	 * is 46us by default. There is still the risk to satisfying
++	 * every decoder to reset themselves through long enough
++	 * trailing spaces and 2) the IRQ handler guarantees that
++	 * start of IR message is always contained in and starting
++	 * from register MTK_CHKDATA_REG(0).
++	 */
++	ir_raw_event_reset(ir->rc);
++
++	/* First message must be pulse */
++	rawir.pulse = false;
++
++	/* Handle all pulse and space IR controller captures */
++	for (i = 0 ; i < MTK_CHKDATA_SZ ; i++) {
++		val = mtk_r32(ir, MTK_CHKDATA_REG(i));
++		dev_dbg(ir->dev, "@reg%d=0x%08x\n", i, val);
++
++		for (j = 0 ; j < 4 ; j++) {
++			wid = (val & (MTK_WIDTH_MASK << j * 8)) >> j * 8;
++			rawir.pulse = !rawir.pulse;
++			rawir.duration = wid * (MTK_IR_SAMPLE + 1);
++			ir_raw_event_store_with_filter(ir->rc, &rawir);
++		}
++	}
++
++	/* The maximum number of edges the IR controller can
++	 * hold is MTK_CHKDATA_SZ * 4. So if received IR messages
++	 * is over the limit, the last incomplete IR message would
++	 * be appended trailing space and still would be sent into
++	 * ir-rc-raw to decode. That helps it is possible that it
++	 * has enough information to decode a scancode even if the
++	 * trailing end of the message is missing.
++	 */
++	if (!MTK_IR_END(wid, rawir.pulse)) {
++		rawir.pulse = false;
++		rawir.duration = MTK_MAX_SAMPLES * (MTK_IR_SAMPLE + 1);
++		ir_raw_event_store_with_filter(ir->rc, &rawir);
++	}
++
++	ir_raw_event_handle(ir->rc);
++
++	/* Restart controller for the next receive that would
++	 * clear up all CHKDATA registers
++	 */
++	mtk_w32_mask(ir, 0x1, MTK_IRCLR, MTK_IRCLR_REG);
++
++	/* Clear interrupt status */
++	mtk_w32_mask(ir, 0x1, MTK_IRINT_CLR, MTK_IRINT_CLR_REG);
++
++	return IRQ_HANDLED;
++}
++
++static int mtk_ir_probe(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	struct device_node *dn = dev->of_node;
++	struct resource *res;
++	struct mtk_ir *ir;
++	u32 val;
++	int ret = 0;
++	const char *map_name;
++
++	ir = devm_kzalloc(dev, sizeof(struct mtk_ir), GFP_KERNEL);
++	if (!ir)
++		return -ENOMEM;
++
++	ir->dev = dev;
++
++	if (!of_device_is_compatible(dn, "mediatek,mt7623-cir"))
++		return -ENODEV;
++
++	ir->clk = devm_clk_get(dev, "clk");
++	if (IS_ERR(ir->clk)) {
++		dev_err(dev, "failed to get a ir clock.\n");
++		return PTR_ERR(ir->clk);
++	}
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	ir->base = devm_ioremap_resource(dev, res);
++	if (IS_ERR(ir->base)) {
++		dev_err(dev, "failed to map registers\n");
++		return PTR_ERR(ir->base);
++	}
++
++	ir->rc = devm_rc_allocate_device(dev, RC_DRIVER_IR_RAW);
++	if (!ir->rc) {
++		dev_err(dev, "failed to allocate device\n");
++		return -ENOMEM;
++	}
++
++	ir->rc->priv = ir;
++	ir->rc->input_name = MTK_IR_DEV;
++	ir->rc->input_phys = MTK_IR_DEV "/input0";
++	ir->rc->input_id.bustype = BUS_HOST;
++	ir->rc->input_id.vendor = 0x0001;
++	ir->rc->input_id.product = 0x0001;
++	ir->rc->input_id.version = 0x0001;
++	map_name = of_get_property(dn, "linux,rc-map-name", NULL);
++	ir->rc->map_name = map_name ?: RC_MAP_EMPTY;
++	ir->rc->dev.parent = dev;
++	ir->rc->driver_name = MTK_IR_DEV;
++	ir->rc->allowed_protocols = RC_BIT_ALL;
++	ir->rc->rx_resolution = MTK_IR_SAMPLE;
++	ir->rc->timeout = MTK_MAX_SAMPLES * (MTK_IR_SAMPLE + 1);
++
++	ret = devm_rc_register_device(dev, ir->rc);
++	if (ret) {
++		dev_err(dev, "failed to register rc device\n");
++		return ret;
++	}
++
++	platform_set_drvdata(pdev, ir);
++
++	ir->irq = platform_get_irq(pdev, 0);
++	if (ir->irq < 0) {
++		dev_err(dev, "no irq resource\n");
++		return -ENODEV;
++	}
++
++	/* Enable interrupt after proper hardware
++	 * setup and IRQ handler registration
++	 */
++	if (clk_prepare_enable(ir->clk)) {
++		dev_err(dev, "try to enable ir_clk failed\n");
++		ret = -EINVAL;
++		goto exit_clkdisable_clk;
++	}
++
++	mtk_irq_disable(ir, MTK_IRINT_EN);
++
++	ret = devm_request_irq(dev, ir->irq, mtk_ir_irq, 0, MTK_IR_DEV, ir);
++	if (ret) {
++		dev_err(dev, "failed request irq\n");
++		goto exit_clkdisable_clk;
++	}
++
++	/* Enable IR and PWM */
++	val = mtk_r32(ir, MTK_CONFIG_HIGH_REG);
++	val |= MTK_PWM_EN | MTK_IR_EN;
++	mtk_w32(ir, val, MTK_CONFIG_HIGH_REG);
++
++	/* Setting sample period */
++	mtk_w32_mask(ir, MTK_CHK_PERIOD, MTK_CHK_PERIOD_MASK,
++		     MTK_CONFIG_LOW_REG);
++
++	mtk_irq_enable(ir, MTK_IRINT_EN);
++
++	dev_info(dev, "Initialized MT7623 IR driver, sample period = %luus\n",
++		 DIV_ROUND_CLOSEST(MTK_IR_SAMPLE, 1000));
++
++	return 0;
++
++exit_clkdisable_clk:
++	clk_disable_unprepare(ir->clk);
++
++	return ret;
++}
++
++static int mtk_ir_remove(struct platform_device *pdev)
++{
++	struct mtk_ir *ir = platform_get_drvdata(pdev);
++
++	/* Avoid contention between remove handler and
++	 * IRQ handler so that disabling IR interrupt and
++	 * waiting for pending IRQ handler to complete
++	 */
++	mtk_irq_disable(ir, MTK_IRINT_EN);
++	synchronize_irq(ir->irq);
++
++	clk_disable_unprepare(ir->clk);
++
++	return 0;
++}
++
++static const struct of_device_id mtk_ir_match[] = {
++	{ .compatible = "mediatek,mt7623-cir" },
++	{},
++};
++MODULE_DEVICE_TABLE(of, mtk_ir_match);
++
++static struct platform_driver mtk_ir_driver = {
++	.probe          = mtk_ir_probe,
++	.remove         = mtk_ir_remove,
++	.driver = {
++		.name = MTK_IR_DEV,
++		.of_match_table = mtk_ir_match,
++	},
++};
++
++module_platform_driver(mtk_ir_driver);
++
++MODULE_DESCRIPTION("Mediatek IR Receiver Controller Driver");
++MODULE_AUTHOR("Sean Wang <[email protected]>");
++MODULE_LICENSE("GPL");
+--- a/drivers/media/rc/Makefile
++++ b/drivers/media/rc/Makefile
+@@ -37,3 +37,4 @@ obj-$(CONFIG_IR_TTUSBIR) += ttusbir.o
+ obj-$(CONFIG_RC_ST) += st_rc.o
+ obj-$(CONFIG_IR_SUNXI) += sunxi-cir.o
+ obj-$(CONFIG_IR_IMG) += img-ir/
++obj-$(CONFIG_IR_MTK) += mtk-cir.o
+--- a/drivers/media/rc/rc-main.c
++++ b/drivers/media/rc/rc-main.c
+@@ -1355,7 +1355,7 @@ static struct device_type rc_dev_type =
+ 	.uevent		= rc_dev_uevent,
+ };
+ 
+-struct rc_dev *rc_allocate_device(void)
++struct rc_dev *rc_allocate_device(enum rc_driver_type type)
+ {
+ 	struct rc_dev *dev;
+ 
+@@ -1382,6 +1382,8 @@ struct rc_dev *rc_allocate_device(void)
+ 	dev->dev.class = &rc_class;
+ 	device_initialize(&dev->dev);
+ 
++	dev->driver_type = type;
++
+ 	__module_get(THIS_MODULE);
+ 	return dev;
+ }
+@@ -1403,6 +1405,35 @@ void rc_free_device(struct rc_dev *dev)
+ }
+ EXPORT_SYMBOL_GPL(rc_free_device);
+ 
++static void devm_rc_alloc_release(struct device *dev, void *res)
++{
++	rc_free_device(*(struct rc_dev **)res);
++}
++
++struct rc_dev *devm_rc_allocate_device(struct device *dev,
++				       enum rc_driver_type type)
++{
++	struct rc_dev **dr, *rc;
++
++	dr = devres_alloc(devm_rc_alloc_release, sizeof(*dr), GFP_KERNEL);
++	if (!dr)
++		return NULL;
++
++	rc = rc_allocate_device(type);
++	if (!rc) {
++		devres_free(dr);
++		return NULL;
++	}
++
++	rc->dev.parent = dev;
++	rc->managed_alloc = true;
++	*dr = rc;
++	devres_add(dev, dr);
++
++	return rc;
++}
++EXPORT_SYMBOL_GPL(devm_rc_allocate_device);
++
+ int rc_register_device(struct rc_dev *dev)
+ {
+ 	static bool raw_init = false; /* raw decoders loaded? */
+@@ -1536,6 +1567,33 @@ out_unlock:
+ }
+ EXPORT_SYMBOL_GPL(rc_register_device);
+ 
++static void devm_rc_release(struct device *dev, void *res)
++{
++	rc_unregister_device(*(struct rc_dev **)res);
++}
++
++int devm_rc_register_device(struct device *parent, struct rc_dev *dev)
++{
++	struct rc_dev **dr;
++	int ret;
++
++	dr = devres_alloc(devm_rc_release, sizeof(*dr), GFP_KERNEL);
++	if (!dr)
++		return -ENOMEM;
++
++	ret = rc_register_device(dev);
++	if (ret) {
++		devres_free(dr);
++		return ret;
++	}
++
++	*dr = dev;
++	devres_add(parent, dr);
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(devm_rc_register_device);
++
+ void rc_unregister_device(struct rc_dev *dev)
+ {
+ 	if (!dev)
+@@ -1557,7 +1615,8 @@ void rc_unregister_device(struct rc_dev
+ 
+ 	ida_simple_remove(&rc_ida, dev->minor);
+ 
+-	rc_free_device(dev);
++	if (!dev->managed_alloc)
++		rc_free_device(dev);
+ }
+ 
+ EXPORT_SYMBOL_GPL(rc_unregister_device);
+--- a/include/media/rc-core.h
++++ b/include/media/rc-core.h
+@@ -68,6 +68,7 @@ enum rc_filter_type {
+  * struct rc_dev - represents a remote control device
+  * @dev: driver model's view of this device
+  * @initialized: 1 if the device init has completed, 0 otherwise
++ * @managed_alloc: devm_rc_allocate_device was used to create rc_dev
+  * @sysfs_groups: sysfs attribute groups
+  * @input_name: name of the input child device
+  * @input_phys: physical path to the input child device
+@@ -131,6 +132,7 @@ enum rc_filter_type {
+ struct rc_dev {
+ 	struct device			dev;
+ 	atomic_t			initialized;
++	bool				managed_alloc;
+ 	const struct attribute_group	*sysfs_groups[5];
+ 	const char			*input_name;
+ 	const char			*input_phys;
+@@ -198,9 +200,19 @@ struct rc_dev {
+ /**
+  * rc_allocate_device - Allocates a RC device
+  *
++ * @rc_driver_type: specifies the type of the RC output to be allocated
+  * returns a pointer to struct rc_dev.
+  */
+-struct rc_dev *rc_allocate_device(void);
++struct rc_dev *rc_allocate_device(enum rc_driver_type);
++
++/**
++ * devm_rc_allocate_device - Managed RC device allocation
++ *
++ * @dev: pointer to struct device
++ * @rc_driver_type: specifies the type of the RC output to be allocated
++ * returns a pointer to struct rc_dev.
++ */
++struct rc_dev *devm_rc_allocate_device(struct device *dev, enum rc_driver_type);
+ 
+ /**
+  * rc_free_device - Frees a RC device
+@@ -217,6 +229,14 @@ void rc_free_device(struct rc_dev *dev);
+ int rc_register_device(struct rc_dev *dev);
+ 
+ /**
++ * devm_rc_register_device - Manageded registering of a RC device
++ *
++ * @parent: pointer to struct device.
++ * @dev: pointer to struct rc_dev.
++ */
++int devm_rc_register_device(struct device *parent, struct rc_dev *dev);
++
++/**
+  * rc_unregister_device - Unregisters a RC device
+  *
+  * @dev: pointer to struct rc_dev.
+--- a/drivers/media/common/siano/smsir.c
++++ b/drivers/media/common/siano/smsir.c
+@@ -58,7 +58,7 @@ int sms_ir_init(struct smscore_device_t
+ 	struct rc_dev *dev;
+ 
+ 	pr_debug("Allocating rc device\n");
+-	dev = rc_allocate_device();
++	dev = rc_allocate_device(RC_DRIVER_IR_RAW);
+ 	if (!dev)
+ 		return -ENOMEM;
+ 
+--- a/drivers/media/i2c/ir-kbd-i2c.c
++++ b/drivers/media/i2c/ir-kbd-i2c.c
+@@ -428,7 +428,7 @@ static int ir_probe(struct i2c_client *c
+ 		 * If platform_data doesn't specify rc_dev, initialize it
+ 		 * internally
+ 		 */
+-		rc = rc_allocate_device();
++		rc = rc_allocate_device(RC_DRIVER_SCANCODE);
+ 		if (!rc)
+ 			return -ENOMEM;
+ 	}
+--- a/drivers/media/pci/bt8xx/bttv-input.c
++++ b/drivers/media/pci/bt8xx/bttv-input.c
+@@ -424,7 +424,7 @@ int bttv_input_init(struct bttv *btv)
+ 		return -ENODEV;
+ 
+ 	ir = kzalloc(sizeof(*ir),GFP_KERNEL);
+-	rc = rc_allocate_device();
++	rc = rc_allocate_device(RC_DRIVER_SCANCODE);
+ 	if (!ir || !rc)
+ 		goto err_out_free;
+ 
+--- a/drivers/media/pci/cx23885/cx23885-input.c
++++ b/drivers/media/pci/cx23885/cx23885-input.c
+@@ -267,7 +267,6 @@ int cx23885_input_init(struct cx23885_de
+ 	struct cx23885_kernel_ir *kernel_ir;
+ 	struct rc_dev *rc;
+ 	char *rc_map;
+-	enum rc_driver_type driver_type;
+ 	u64 allowed_protos;
+ 
+ 	int ret;
+@@ -352,7 +351,7 @@ int cx23885_input_init(struct cx23885_de
+ 				    pci_name(dev->pci));
+ 
+ 	/* input device */
+-	rc = rc_allocate_device();
++	rc = rc_allocate_device(RC_DRIVER_IR_RAW);
+ 	if (!rc) {
+ 		ret = -ENOMEM;
+ 		goto err_out_free;
+@@ -371,7 +370,6 @@ int cx23885_input_init(struct cx23885_de
+ 		rc->input_id.product = dev->pci->device;
+ 	}
+ 	rc->dev.parent = &dev->pci->dev;
+-	rc->driver_type = driver_type;
+ 	rc->allowed_protocols = allowed_protos;
+ 	rc->priv = kernel_ir;
+ 	rc->open = cx23885_input_ir_open;
+--- a/drivers/media/pci/cx88/cx88-input.c
++++ b/drivers/media/pci/cx88/cx88-input.c
+@@ -272,7 +272,7 @@ int cx88_ir_init(struct cx88_core *core,
+ 				 */
+ 
+ 	ir = kzalloc(sizeof(*ir), GFP_KERNEL);
+-	dev = rc_allocate_device();
++	dev = rc_allocate_device(RC_DRIVER_IR_RAW);
+ 	if (!ir || !dev)
+ 		goto err_out_free;
+ 
+@@ -482,7 +482,6 @@ int cx88_ir_init(struct cx88_core *core,
+ 	dev->scancode_mask = hardware_mask;
+ 
+ 	if (ir->sampling) {
+-		dev->driver_type = RC_DRIVER_IR_RAW;
+ 		dev->timeout = 10 * 1000 * 1000; /* 10 ms */
+ 	} else {
+ 		dev->driver_type = RC_DRIVER_SCANCODE;
+--- a/drivers/media/pci/dm1105/dm1105.c
++++ b/drivers/media/pci/dm1105/dm1105.c
+@@ -744,7 +744,7 @@ static int dm1105_ir_init(struct dm1105_
+ 	struct rc_dev *dev;
+ 	int err = -ENOMEM;
+ 
+-	dev = rc_allocate_device();
++	dev = rc_allocate_device(RC_DRIVER_SCANCODE);
+ 	if (!dev)
+ 		return -ENOMEM;
+ 
+@@ -753,7 +753,6 @@ static int dm1105_ir_init(struct dm1105_
+ 
+ 	dev->driver_name = MODULE_NAME;
+ 	dev->map_name = RC_MAP_DM1105_NEC;
+-	dev->driver_type = RC_DRIVER_SCANCODE;
+ 	dev->input_name = "DVB on-card IR receiver";
+ 	dev->input_phys = dm1105->ir.input_phys;
+ 	dev->input_id.bustype = BUS_PCI;
+--- a/drivers/media/pci/mantis/mantis_input.c
++++ b/drivers/media/pci/mantis/mantis_input.c
+@@ -39,7 +39,7 @@ int mantis_input_init(struct mantis_pci
+ 	struct rc_dev *dev;
+ 	int err;
+ 
+-	dev = rc_allocate_device();
++	dev = rc_allocate_device(RC_DRIVER_SCANCODE);
+ 	if (!dev) {
+ 		dprintk(MANTIS_ERROR, 1, "Remote device allocation failed");
+ 		err = -ENOMEM;
+--- a/drivers/media/pci/saa7134/saa7134-input.c
++++ b/drivers/media/pci/saa7134/saa7134-input.c
+@@ -849,7 +849,7 @@ int saa7134_input_init1(struct saa7134_d
+ 	}
+ 
+ 	ir = kzalloc(sizeof(*ir), GFP_KERNEL);
+-	rc = rc_allocate_device();
++	rc = rc_allocate_device(RC_DRIVER_SCANCODE);
+ 	if (!ir || !rc) {
+ 		err = -ENOMEM;
+ 		goto err_out_free;
+--- a/drivers/media/pci/smipcie/smipcie-ir.c
++++ b/drivers/media/pci/smipcie/smipcie-ir.c
+@@ -183,7 +183,7 @@ int smi_ir_init(struct smi_dev *dev)
+ 	struct rc_dev *rc_dev;
+ 	struct smi_rc *ir = &dev->ir;
+ 
+-	rc_dev = rc_allocate_device();
++	rc_dev = rc_allocate_device(RC_DRIVER_SCANCODE);
+ 	if (!rc_dev)
+ 		return -ENOMEM;
+ 
+@@ -202,7 +202,6 @@ int smi_ir_init(struct smi_dev *dev)
+ 	rc_dev->input_id.product = dev->pci_dev->subsystem_device;
+ 	rc_dev->dev.parent = &dev->pci_dev->dev;
+ 
+-	rc_dev->driver_type = RC_DRIVER_SCANCODE;
+ 	rc_dev->map_name = dev->info->rc_map;
+ 
+ 	ir->rc_dev = rc_dev;
+--- a/drivers/media/pci/ttpci/budget-ci.c
++++ b/drivers/media/pci/ttpci/budget-ci.c
+@@ -177,7 +177,7 @@ static int msp430_ir_init(struct budget_
+ 	struct rc_dev *dev;
+ 	int error;
+ 
+-	dev = rc_allocate_device();
++	dev = rc_allocate_device(RC_DRIVER_SCANCODE);
+ 	if (!dev) {
+ 		printk(KERN_ERR "budget_ci: IR interface initialisation failed\n");
+ 		return -ENOMEM;
+--- a/drivers/media/rc/ati_remote.c
++++ b/drivers/media/rc/ati_remote.c
+@@ -765,7 +765,6 @@ static void ati_remote_rc_init(struct at
+ 	struct rc_dev *rdev = ati_remote->rdev;
+ 
+ 	rdev->priv = ati_remote;
+-	rdev->driver_type = RC_DRIVER_SCANCODE;
+ 	rdev->allowed_protocols = RC_BIT_OTHER;
+ 	rdev->driver_name = "ati_remote";
+ 
+@@ -852,7 +851,7 @@ static int ati_remote_probe(struct usb_i
+ 	}
+ 
+ 	ati_remote = kzalloc(sizeof (struct ati_remote), GFP_KERNEL);
+-	rc_dev = rc_allocate_device();
++	rc_dev = rc_allocate_device(RC_DRIVER_SCANCODE);
+ 	if (!ati_remote || !rc_dev)
+ 		goto exit_free_dev_rdev;
+ 
+--- a/drivers/media/rc/ene_ir.c
++++ b/drivers/media/rc/ene_ir.c
+@@ -1012,7 +1012,7 @@ static int ene_probe(struct pnp_dev *pnp
+ 
+ 	/* allocate memory */
+ 	dev = kzalloc(sizeof(struct ene_device), GFP_KERNEL);
+-	rdev = rc_allocate_device();
++	rdev = rc_allocate_device(RC_DRIVER_IR_RAW);
+ 	if (!dev || !rdev)
+ 		goto exit_free_dev_rdev;
+ 
+--- a/drivers/media/rc/fintek-cir.c
++++ b/drivers/media/rc/fintek-cir.c
+@@ -496,7 +496,7 @@ static int fintek_probe(struct pnp_dev *
+ 		return ret;
+ 
+ 	/* input device for IR remote (and tx) */
+-	rdev = rc_allocate_device();
++	rdev = rc_allocate_device(RC_DRIVER_IR_RAW);
+ 	if (!rdev)
+ 		goto exit_free_dev_rdev;
+ 
+--- a/drivers/media/rc/gpio-ir-recv.c
++++ b/drivers/media/rc/gpio-ir-recv.c
+@@ -143,14 +143,13 @@ static int gpio_ir_recv_probe(struct pla
+ 	if (!gpio_dev)
+ 		return -ENOMEM;
+ 
+-	rcdev = rc_allocate_device();
++	rcdev = rc_allocate_device(RC_DRIVER_IR_RAW);
+ 	if (!rcdev) {
+ 		rc = -ENOMEM;
+ 		goto err_allocate_device;
+ 	}
+ 
+ 	rcdev->priv = gpio_dev;
+-	rcdev->driver_type = RC_DRIVER_IR_RAW;
+ 	rcdev->input_name = GPIO_IR_DEVICE_NAME;
+ 	rcdev->input_phys = GPIO_IR_DEVICE_NAME "/input0";
+ 	rcdev->input_id.bustype = BUS_HOST;
+--- a/drivers/media/rc/igorplugusb.c
++++ b/drivers/media/rc/igorplugusb.c
+@@ -190,7 +190,7 @@ static int igorplugusb_probe(struct usb_
+ 
+ 	usb_make_path(udev, ir->phys, sizeof(ir->phys));
+ 
+-	rc = rc_allocate_device();
++	rc = rc_allocate_device(RC_DRIVER_IR_RAW);
+ 	if (!rc)
+ 		goto fail;
+ 
+@@ -198,7 +198,6 @@ static int igorplugusb_probe(struct usb_
+ 	rc->input_phys = ir->phys;
+ 	usb_to_input_id(udev, &rc->input_id);
+ 	rc->dev.parent = &intf->dev;
+-	rc->driver_type = RC_DRIVER_IR_RAW;
+ 	/*
+ 	 * This device can only store 36 pulses + spaces, which is not enough
+ 	 * for the NEC protocol and many others.
+--- a/drivers/media/rc/iguanair.c
++++ b/drivers/media/rc/iguanair.c
+@@ -431,7 +431,7 @@ static int iguanair_probe(struct usb_int
+ 	struct usb_host_interface *idesc;
+ 
+ 	ir = kzalloc(sizeof(*ir), GFP_KERNEL);
+-	rc = rc_allocate_device();
++	rc = rc_allocate_device(RC_DRIVER_IR_RAW);
+ 	if (!ir || !rc) {
+ 		ret = -ENOMEM;
+ 		goto out;
+--- a/drivers/media/rc/img-ir/img-ir-hw.c
++++ b/drivers/media/rc/img-ir/img-ir-hw.c
+@@ -1071,7 +1071,7 @@ int img_ir_probe_hw(struct img_ir_priv *
+ 	}
+ 
+ 	/* Allocate hardware decoder */
+-	hw->rdev = rdev = rc_allocate_device();
++	hw->rdev = rdev = rc_allocate_device(RC_DRIVER_SCANCODE);
+ 	if (!rdev) {
+ 		dev_err(priv->dev, "cannot allocate input device\n");
+ 		error = -ENOMEM;
+--- a/drivers/media/rc/img-ir/img-ir-raw.c
++++ b/drivers/media/rc/img-ir/img-ir-raw.c
+@@ -110,7 +110,7 @@ int img_ir_probe_raw(struct img_ir_priv
+ 	setup_timer(&raw->timer, img_ir_echo_timer, (unsigned long)priv);
+ 
+ 	/* Allocate raw decoder */
+-	raw->rdev = rdev = rc_allocate_device();
++	raw->rdev = rdev = rc_allocate_device(RC_DRIVER_IR_RAW);
+ 	if (!rdev) {
+ 		dev_err(priv->dev, "cannot allocate raw input device\n");
+ 		return -ENOMEM;
+@@ -118,7 +118,6 @@ int img_ir_probe_raw(struct img_ir_priv
+ 	rdev->priv = priv;
+ 	rdev->map_name = RC_MAP_EMPTY;
+ 	rdev->input_name = "IMG Infrared Decoder Raw";
+-	rdev->driver_type = RC_DRIVER_IR_RAW;
+ 
+ 	/* Register raw decoder */
+ 	error = rc_register_device(rdev);
+--- a/drivers/media/rc/imon.c
++++ b/drivers/media/rc/imon.c
+@@ -1951,7 +1951,7 @@ static struct rc_dev *imon_init_rdev(str
+ 	const unsigned char fp_packet[] = { 0x40, 0x00, 0x00, 0x00,
+ 					    0x00, 0x00, 0x00, 0x88 };
+ 
+-	rdev = rc_allocate_device();
++	rdev = rc_allocate_device(RC_DRIVER_SCANCODE);
+ 	if (!rdev) {
+ 		dev_err(ictx->dev, "remote control dev allocation failed\n");
+ 		goto out;
+@@ -1969,7 +1969,6 @@ static struct rc_dev *imon_init_rdev(str
+ 	rdev->dev.parent = ictx->dev;
+ 
+ 	rdev->priv = ictx;
+-	rdev->driver_type = RC_DRIVER_SCANCODE;
+ 	rdev->allowed_protocols = RC_BIT_OTHER | RC_BIT_RC6_MCE; /* iMON PAD or MCE */
+ 	rdev->change_protocol = imon_ir_change_protocol;
+ 	rdev->driver_name = MOD_NAME;
+--- a/drivers/media/rc/ir-hix5hd2.c
++++ b/drivers/media/rc/ir-hix5hd2.c
+@@ -222,7 +222,7 @@ static int hix5hd2_ir_probe(struct platf
+ 		return priv->irq;
+ 	}
+ 
+-	rdev = rc_allocate_device();
++	rdev = rc_allocate_device(RC_DRIVER_IR_RAW);
+ 	if (!rdev)
+ 		return -ENOMEM;
+ 
+--- a/drivers/media/rc/ite-cir.c
++++ b/drivers/media/rc/ite-cir.c
+@@ -1472,7 +1472,7 @@ static int ite_probe(struct pnp_dev *pde
+ 		return ret;
+ 
+ 	/* input device for IR remote (and tx) */
+-	rdev = rc_allocate_device();
++	rdev = rc_allocate_device(RC_DRIVER_IR_RAW);
+ 	if (!rdev)
+ 		goto exit_free_dev_rdev;
+ 	itdev->rdev = rdev;
+--- a/drivers/media/rc/mceusb.c
++++ b/drivers/media/rc/mceusb.c
+@@ -1220,7 +1220,7 @@ static struct rc_dev *mceusb_init_rc_dev
+ 	struct rc_dev *rc;
+ 	int ret;
+ 
+-	rc = rc_allocate_device();
++	rc = rc_allocate_device(RC_DRIVER_IR_RAW);
+ 	if (!rc) {
+ 		dev_err(dev, "remote dev allocation failed");
+ 		goto out;
+--- a/drivers/media/rc/meson-ir.c
++++ b/drivers/media/rc/meson-ir.c
+@@ -131,7 +131,7 @@ static int meson_ir_probe(struct platfor
+ 		return ir->irq;
+ 	}
+ 
+-	ir->rc = rc_allocate_device();
++	ir->rc = rc_allocate_device(RC_DRIVER_IR_RAW);
+ 	if (!ir->rc) {
+ 		dev_err(dev, "failed to allocate rc device\n");
+ 		return -ENOMEM;
+--- a/drivers/media/rc/rc-loopback.c
++++ b/drivers/media/rc/rc-loopback.c
+@@ -181,7 +181,7 @@ static int __init loop_init(void)
+ 	struct rc_dev *rc;
+ 	int ret;
+ 
+-	rc = rc_allocate_device();
++	rc = rc_allocate_device(RC_DRIVER_IR_RAW);
+ 	if (!rc) {
+ 		printk(KERN_ERR DRIVER_NAME ": rc_dev allocation failed\n");
+ 		return -ENOMEM;
+--- a/drivers/media/rc/st_rc.c
++++ b/drivers/media/rc/st_rc.c
+@@ -235,7 +235,7 @@ static int st_rc_probe(struct platform_d
+ 	if (!rc_dev)
+ 		return -ENOMEM;
+ 
+-	rdev = rc_allocate_device();
++	rdev = rc_allocate_device(RC_DRIVER_IR_RAW);
+ 
+ 	if (!rdev)
+ 		return -ENOMEM;
+--- a/drivers/media/rc/streamzap.c
++++ b/drivers/media/rc/streamzap.c
+@@ -291,7 +291,7 @@ static struct rc_dev *streamzap_init_rc_
+ 	struct device *dev = sz->dev;
+ 	int ret;
+ 
+-	rdev = rc_allocate_device();
++	rdev = rc_allocate_device(RC_DRIVER_IR_RAW);
+ 	if (!rdev) {
+ 		dev_err(dev, "remote dev allocation failed\n");
+ 		goto out;
+--- a/drivers/media/rc/sunxi-cir.c
++++ b/drivers/media/rc/sunxi-cir.c
+@@ -212,7 +212,7 @@ static int sunxi_ir_probe(struct platfor
+ 		goto exit_clkdisable_clk;
+ 	}
+ 
+-	ir->rc = rc_allocate_device();
++	ir->rc = rc_allocate_device(RC_DRIVER_IR_RAW);
+ 	if (!ir->rc) {
+ 		dev_err(dev, "failed to allocate device\n");
+ 		ret = -ENOMEM;
+--- a/drivers/media/rc/ttusbir.c
++++ b/drivers/media/rc/ttusbir.c
+@@ -205,7 +205,7 @@ static int ttusbir_probe(struct usb_inte
+ 	int altsetting = -1;
+ 
+ 	tt = kzalloc(sizeof(*tt), GFP_KERNEL);
+-	rc = rc_allocate_device();
++	rc = rc_allocate_device(RC_DRIVER_IR_RAW);
+ 	if (!tt || !rc) {
+ 		ret = -ENOMEM;
+ 		goto out;
+--- a/drivers/media/rc/winbond-cir.c
++++ b/drivers/media/rc/winbond-cir.c
+@@ -1062,13 +1062,12 @@ wbcir_probe(struct pnp_dev *device, cons
+ 	if (err)
+ 		goto exit_free_data;
+ 
+-	data->dev = rc_allocate_device();
++	data->dev = rc_allocate_device(RC_DRIVER_IR_RAW);
+ 	if (!data->dev) {
+ 		err = -ENOMEM;
+ 		goto exit_unregister_led;
+ 	}
+ 
+-	data->dev->driver_type = RC_DRIVER_IR_RAW;
+ 	data->dev->driver_name = DRVNAME;
+ 	data->dev->input_name = WBCIR_NAME;
+ 	data->dev->input_phys = "wbcir/cir0";
+--- a/drivers/media/usb/au0828/au0828-input.c
++++ b/drivers/media/usb/au0828/au0828-input.c
+@@ -298,7 +298,7 @@ int au0828_rc_register(struct au0828_dev
+ 		return -ENODEV;
+ 
+ 	ir = kzalloc(sizeof(*ir), GFP_KERNEL);
+-	rc = rc_allocate_device();
++	rc = rc_allocate_device(RC_DRIVER_IR_RAW);
+ 	if (!ir || !rc)
+ 		goto error;
+ 
+@@ -343,7 +343,6 @@ int au0828_rc_register(struct au0828_dev
+ 	rc->input_id.product = le16_to_cpu(dev->usbdev->descriptor.idProduct);
+ 	rc->dev.parent = &dev->usbdev->dev;
+ 	rc->driver_name = "au0828-input";
+-	rc->driver_type = RC_DRIVER_IR_RAW;
+ 	rc->allowed_protocols = RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32 |
+ 								RC_BIT_RC5;
+ 
+--- a/drivers/media/usb/cx231xx/cx231xx-input.c
++++ b/drivers/media/usb/cx231xx/cx231xx-input.c
+@@ -72,7 +72,7 @@ int cx231xx_ir_init(struct cx231xx *dev)
+ 
+ 	memset(&info, 0, sizeof(struct i2c_board_info));
+ 	memset(&dev->init_data, 0, sizeof(dev->init_data));
+-	dev->init_data.rc_dev = rc_allocate_device();
++	dev->init_data.rc_dev = rc_allocate_device(RC_DRIVER_SCANCODE);
+ 	if (!dev->init_data.rc_dev)
+ 		return -ENOMEM;
+ 
+--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
++++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
+@@ -147,7 +147,7 @@ static int dvb_usbv2_remote_init(struct
+ 	if (!d->rc.map_name)
+ 		return 0;
+ 
+-	dev = rc_allocate_device();
++	dev = rc_allocate_device(d->rc.driver_type);
+ 	if (!dev) {
+ 		ret = -ENOMEM;
+ 		goto err;
+@@ -162,7 +162,6 @@ static int dvb_usbv2_remote_init(struct
+ 	/* TODO: likely RC-core should took const char * */
+ 	dev->driver_name = (char *) d->props->driver_name;
+ 	dev->map_name = d->rc.map_name;
+-	dev->driver_type = d->rc.driver_type;
+ 	dev->allowed_protocols = d->rc.allowed_protos;
+ 	dev->change_protocol = d->rc.change_protocol;
+ 	dev->priv = d;
+--- a/drivers/media/usb/dvb-usb/dvb-usb-remote.c
++++ b/drivers/media/usb/dvb-usb/dvb-usb-remote.c
+@@ -265,7 +265,7 @@ static int rc_core_dvb_usb_remote_init(s
+ 	int err, rc_interval;
+ 	struct rc_dev *dev;
+ 
+-	dev = rc_allocate_device();
++	dev = rc_allocate_device(d->props.rc.core.driver_type);
+ 	if (!dev)
+ 		return -ENOMEM;
+ 
+@@ -273,7 +273,6 @@ static int rc_core_dvb_usb_remote_init(s
+ 	dev->map_name = d->props.rc.core.rc_codes;
+ 	dev->change_protocol = d->props.rc.core.change_protocol;
+ 	dev->allowed_protocols = d->props.rc.core.allowed_protos;
+-	dev->driver_type = d->props.rc.core.driver_type;
+ 	usb_to_input_id(d->udev, &dev->input_id);
+ 	dev->input_name = "IR-receiver inside an USB DVB receiver";
+ 	dev->input_phys = d->rc_phys;
+--- a/drivers/media/usb/em28xx/em28xx-input.c
++++ b/drivers/media/usb/em28xx/em28xx-input.c
+@@ -713,7 +713,7 @@ static int em28xx_ir_init(struct em28xx
+ 	ir = kzalloc(sizeof(*ir), GFP_KERNEL);
+ 	if (!ir)
+ 		return -ENOMEM;
+-	rc = rc_allocate_device();
++	rc = rc_allocate_device(RC_DRIVER_SCANCODE);
+ 	if (!rc)
+ 		goto error;
+ 
+--- a/drivers/media/usb/tm6000/tm6000-input.c
++++ b/drivers/media/usb/tm6000/tm6000-input.c
+@@ -429,7 +429,7 @@ int tm6000_ir_init(struct tm6000_core *d
+ 		return 0;
+ 
+ 	ir = kzalloc(sizeof(*ir), GFP_ATOMIC);
+-	rc = rc_allocate_device();
++	rc = rc_allocate_device(RC_DRIVER_SCANCODE);
+ 	if (!ir || !rc)
+ 		goto out;
+ 
+@@ -456,7 +456,6 @@ int tm6000_ir_init(struct tm6000_core *d
+ 		ir->polling = 50;
+ 		INIT_DELAYED_WORK(&ir->work, tm6000_ir_handle_key);
+ 	}
+-	rc->driver_type = RC_DRIVER_SCANCODE;
+ 
+ 	snprintf(ir->name, sizeof(ir->name), "tm5600/60x0 IR (%s)",
+ 						dev->name);

+ 3 - 17
target/linux/mediatek/patches-4.9/0091-dsa1.patch → target/linux/mediatek/patches-4.9/0025-dt-bindings-net-dsa-add-Mediatek-MT7530-binding.patch

@@ -1,21 +1,7 @@
-From patchwork Wed Mar 29 09:38:19 2017
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [net-next,v3,1/5] dt-bindings: net: dsa: add Mediatek MT7530 binding
-From: [email protected]
-X-Patchwork-Id: 9651093
-Message-Id: <[email protected]>
-To: <[email protected]>, <[email protected]>,
- <[email protected]>, <[email protected]>,
- <[email protected]>, <[email protected]>
-Cc: [email protected], [email protected], [email protected], 
- [email protected], [email protected],
- [email protected], 
- [email protected], [email protected], [email protected]
-Date: Wed, 29 Mar 2017 17:38:19 +0800
-
+From 3b9b46b5705214b16c5356284ad68be32ae56a26 Mon Sep 17 00:00:00 2001
 From: Sean Wang <[email protected]>
 From: Sean Wang <[email protected]>
+Date: Wed, 29 Mar 2017 17:38:19 +0800
+Subject: [PATCH 25/57] dt-bindings: net: dsa: add Mediatek MT7530 binding
 
 
 Add device-tree binding for Mediatek MT7530 switch.
 Add device-tree binding for Mediatek MT7530 switch.
 
 

+ 1788 - 0
target/linux/mediatek/patches-4.9/0026-net-mediatek-backport-v4.10-driver.patch

@@ -0,0 +1,1788 @@
+From 99d9d02a05df503184be094de336e7515fe3e235 Mon Sep 17 00:00:00 2001
+From: John Crispin <[email protected]>
+Date: Thu, 10 Aug 2017 14:26:29 +0200
+Subject: [PATCH 26/57] net: mediatek: backport v4.10 driver
+
+Signed-off-by: John Crispin <[email protected]>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c        |  49 ++-
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h        |  16 +-
+ drivers/net/ethernet/mediatek/mtk_hnat/Makefile    |   4 +
+ drivers/net/ethernet/mediatek/mtk_hnat/hnat.c      | 315 +++++++++++++++
+ drivers/net/ethernet/mediatek/mtk_hnat/hnat.h      | 425 +++++++++++++++++++++
+ .../net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c  | 259 +++++++++++++
+ .../net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c  | 289 ++++++++++++++
+ .../net/ethernet/mediatek/mtk_hnat/nf_hnat_mtk.h   |  44 +++
+ 8 files changed, 1378 insertions(+), 23 deletions(-)
+ create mode 100644 drivers/net/ethernet/mediatek/mtk_hnat/Makefile
+ create mode 100644 drivers/net/ethernet/mediatek/mtk_hnat/hnat.c
+ create mode 100644 drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
+ create mode 100644 drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c
+ create mode 100644 drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
+ create mode 100644 drivers/net/ethernet/mediatek/mtk_hnat/nf_hnat_mtk.h
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -462,8 +462,8 @@ static void mtk_stats_update(struct mtk_
+ 	}
+ }
+ 
+-static struct rtnl_link_stats64 *mtk_get_stats64(struct net_device *dev,
+-					struct rtnl_link_stats64 *storage)
++static struct rtnl_link_stats64 * mtk_get_stats64(struct net_device *dev,
++			    struct rtnl_link_stats64 *storage)
+ {
+ 	struct mtk_mac *mac = netdev_priv(dev);
+ 	struct mtk_hw_stats *hw_stats = mac->hw_stats;
+@@ -615,7 +615,7 @@ static int mtk_tx_map(struct sk_buff *sk
+ 	struct mtk_mac *mac = netdev_priv(dev);
+ 	struct mtk_eth *eth = mac->hw;
+ 	struct mtk_tx_dma *itxd, *txd;
+-	struct mtk_tx_buf *tx_buf;
++	struct mtk_tx_buf *itx_buf, *tx_buf;
+ 	dma_addr_t mapped_addr;
+ 	unsigned int nr_frags;
+ 	int i, n_desc = 1;
+@@ -629,8 +629,8 @@ static int mtk_tx_map(struct sk_buff *sk
+ 	fport = (mac->id + 1) << TX_DMA_FPORT_SHIFT;
+ 	txd4 |= fport;
+ 
+-	tx_buf = mtk_desc_to_tx_buf(ring, itxd);
+-	memset(tx_buf, 0, sizeof(*tx_buf));
++	itx_buf = mtk_desc_to_tx_buf(ring, itxd);
++	memset(itx_buf, 0, sizeof(*itx_buf));
+ 
+ 	if (gso)
+ 		txd4 |= TX_DMA_TSO;
+@@ -649,9 +649,11 @@ static int mtk_tx_map(struct sk_buff *sk
+ 		return -ENOMEM;
+ 
+ 	WRITE_ONCE(itxd->txd1, mapped_addr);
+-	tx_buf->flags |= MTK_TX_FLAGS_SINGLE0;
+-	dma_unmap_addr_set(tx_buf, dma_addr0, mapped_addr);
+-	dma_unmap_len_set(tx_buf, dma_len0, skb_headlen(skb));
++	itx_buf->flags |= MTK_TX_FLAGS_SINGLE0;
++	itx_buf->flags |= (!mac->id) ? MTK_TX_FLAGS_FPORT0 :
++			  MTK_TX_FLAGS_FPORT1;
++	dma_unmap_addr_set(itx_buf, dma_addr0, mapped_addr);
++	dma_unmap_len_set(itx_buf, dma_len0, skb_headlen(skb));
+ 
+ 	/* TX SG offload */
+ 	txd = itxd;
+@@ -687,11 +689,13 @@ static int mtk_tx_map(struct sk_buff *sk
+ 					       last_frag * TX_DMA_LS0));
+ 			WRITE_ONCE(txd->txd4, fport);
+ 
+-			tx_buf->skb = (struct sk_buff *)MTK_DMA_DUMMY_DESC;
+ 			tx_buf = mtk_desc_to_tx_buf(ring, txd);
+ 			memset(tx_buf, 0, sizeof(*tx_buf));
+-
++			tx_buf->skb = (struct sk_buff *)MTK_DMA_DUMMY_DESC;
+ 			tx_buf->flags |= MTK_TX_FLAGS_PAGE0;
++			tx_buf->flags |= (!mac->id) ? MTK_TX_FLAGS_FPORT0 :
++					 MTK_TX_FLAGS_FPORT1;
++
+ 			dma_unmap_addr_set(tx_buf, dma_addr0, mapped_addr);
+ 			dma_unmap_len_set(tx_buf, dma_len0, frag_map_size);
+ 			frag_size -= frag_map_size;
+@@ -700,7 +704,7 @@ static int mtk_tx_map(struct sk_buff *sk
+ 	}
+ 
+ 	/* store skb to cleanup */
+-	tx_buf->skb = skb;
++	itx_buf->skb = skb;
+ 
+ 	WRITE_ONCE(itxd->txd4, txd4);
+ 	WRITE_ONCE(itxd->txd3, (TX_DMA_SWC | TX_DMA_PLEN0(skb_headlen(skb)) |
+@@ -845,7 +849,7 @@ static int mtk_start_xmit(struct sk_buff
+ drop:
+ 	spin_unlock(&eth->page_lock);
+ 	stats->tx_dropped++;
+-	dev_kfree_skb(skb);
++	dev_kfree_skb_any(skb);
+ 	return NETDEV_TX_OK;
+ }
+ 
+@@ -1014,17 +1018,16 @@ static int mtk_poll_tx(struct mtk_eth *e
+ 
+ 	while ((cpu != dma) && budget) {
+ 		u32 next_cpu = desc->txd2;
+-		int mac;
++		int mac = 0;
+ 
+ 		desc = mtk_qdma_phys_to_virt(ring, desc->txd2);
+ 		if ((desc->txd3 & TX_DMA_OWNER_CPU) == 0)
+ 			break;
+ 
+-		mac = (desc->txd4 >> TX_DMA_FPORT_SHIFT) &
+-		       TX_DMA_FPORT_MASK;
+-		mac--;
+-
+ 		tx_buf = mtk_desc_to_tx_buf(ring, desc);
++		if (tx_buf->flags & MTK_TX_FLAGS_FPORT1)
++			mac = 1;
++
+ 		skb = tx_buf->skb;
+ 		if (!skb) {
+ 			condition = 1;
+@@ -1848,6 +1851,12 @@ static int mtk_hw_init(struct mtk_eth *e
+ 	/* GE2, Force 1000M/FD, FC ON */
+ 	mtk_w32(eth, MAC_MCR_FIXED_LINK, MTK_MAC_MCR(1));
+ 
++	/* Indicates CDM to parse the MTK special tag from CPU
++	 * which also is working out for untag packets.
++	 */
++	val = mtk_r32(eth, MTK_CDMQ_IG_CTRL);
++	mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL);
++
+ 	/* Enable RX VLan Offloading */
+ 	mtk_w32(eth, 1, MTK_CDMP_EG_CTRL);
+ 
+@@ -1910,10 +1919,9 @@ static int __init mtk_init(struct net_de
+ 
+ 	/* If the mac address is invalid, use random mac address  */
+ 	if (!is_valid_ether_addr(dev->dev_addr)) {
+-		random_ether_addr(dev->dev_addr);
++		eth_hw_addr_random(dev);
+ 		dev_err(eth->dev, "generated random MAC address %pM\n",
+ 			dev->dev_addr);
+-		dev->addr_assign_type = NET_ADDR_RANDOM;
+ 	}
+ 
+ 	return mtk_phy_connect(dev);
+@@ -2247,7 +2255,6 @@ static const struct net_device_ops mtk_n
+ 	.ndo_set_mac_address	= mtk_set_mac_address,
+ 	.ndo_validate_addr	= eth_validate_addr,
+ 	.ndo_do_ioctl		= mtk_do_ioctl,
+-	.ndo_change_mtu		= eth_change_mtu,
+ 	.ndo_tx_timeout		= mtk_tx_timeout,
+ 	.ndo_get_stats64        = mtk_get_stats64,
+ 	.ndo_fix_features	= mtk_fix_features,
+@@ -2320,6 +2327,8 @@ static int mtk_add_mac(struct mtk_eth *e
+ 	eth->netdev[id]->ethtool_ops = &mtk_ethtool_ops;
+ 
+ 	eth->netdev[id]->irq = eth->irq[0];
++	eth->netdev[id]->dev.of_node = np;
++
+ 	return 0;
+ 
+ free_netdev:
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -70,6 +70,10 @@
+ /* Frame Engine Interrupt Grouping Register */
+ #define MTK_FE_INT_GRP		0x20
+ 
++/* CDMP Ingress Control Register */
++#define MTK_CDMQ_IG_CTRL	0x1400
++#define MTK_CDMQ_STAG_EN	BIT(0)
++
+ /* CDMP Exgress Control Register */
+ #define MTK_CDMP_EG_CTRL	0x404
+ 
+@@ -406,12 +410,18 @@ struct mtk_hw_stats {
+ 	struct u64_stats_sync	syncp;
+ };
+ 
+-/* PDMA descriptor can point at 1-2 segments. This enum allows us to track how
+- * memory was allocated so that it can be freed properly
+- */
+ enum mtk_tx_flags {
++	/* PDMA descriptor can point at 1-2 segments. This enum allows us to
++	 * track how memory was allocated so that it can be freed properly.
++	 */
+ 	MTK_TX_FLAGS_SINGLE0	= 0x01,
+ 	MTK_TX_FLAGS_PAGE0	= 0x02,
++
++	/* MTK_TX_FLAGS_FPORTx allows tracking which port the transmitted
++	 * SKB out instead of looking up through hardware TX descriptor.
++	 */
++	MTK_TX_FLAGS_FPORT0	= 0x04,
++	MTK_TX_FLAGS_FPORT1	= 0x08,
+ };
+ 
+ /* This enum allows us to identify how the clock is defined on the array of the
+--- /dev/null
++++ b/drivers/net/ethernet/mediatek/mtk_hnat/Makefile
+@@ -0,0 +1,4 @@
++ccflags-y=-Werror
++
++obj-$(CONFIG_NET_MEDIATEK_HNAT)         += mtkhnat.o
++mtkhnat-objs := hnat.o hnat_nf_hook.o hnat_debugfs.o
+--- /dev/null
++++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat.c
+@@ -0,0 +1,315 @@
++/*   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) 2014-2016 Sean Wang <[email protected]>
++ *   Copyright (C) 2016-2017 John Crispin <[email protected]>
++ */
++
++#include <linux/dma-mapping.h>
++#include <linux/delay.h>
++#include <linux/if.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include <linux/reset.h>
++
++#include "hnat.h"
++
++struct hnat_priv *host;
++
++static void cr_set_bits(void __iomem * reg, u32 bs)
++{
++	u32 val = readl(reg);
++
++	val |= bs;
++	writel(val, reg);
++}
++
++static void cr_clr_bits(void __iomem * reg, u32 bs)
++{
++	u32 val = readl(reg);
++
++	val &= ~bs;
++	writel(val, reg);
++}
++
++static void cr_set_field(void __iomem * reg, u32 field, u32 val)
++{
++	unsigned int tv = readl(reg);
++
++	tv &= ~field;
++	tv |= ((val) << (ffs((unsigned int)field) - 1));
++	writel(tv, reg);
++}
++
++static int hnat_start(void)
++{
++	u32 foe_table_sz;
++
++	/* mapp the FOE table */
++	foe_table_sz = FOE_4TB_SIZ * sizeof(struct foe_entry);
++	host->foe_table_cpu =
++	    dma_alloc_coherent(host->dev, foe_table_sz, &host->foe_table_dev,
++			       GFP_KERNEL);
++	if (!host->foe_table_cpu)
++		return -1;
++
++	writel(host->foe_table_dev, host->ppe_base + PPE_TB_BASE);
++	memset(host->foe_table_cpu, 0, foe_table_sz);
++
++	/* setup hashing */
++	cr_set_field(host->ppe_base + PPE_TB_CFG, TB_ETRY_NUM, TABLE_4K);
++	cr_set_field(host->ppe_base + PPE_TB_CFG, HASH_MODE, HASH_MODE_1);
++	writel(HASH_SEED_KEY, host->ppe_base + PPE_HASH_SEED);
++	cr_set_field(host->ppe_base + PPE_TB_CFG, XMODE, 0);
++	cr_set_field(host->ppe_base + PPE_TB_CFG, TB_ENTRY_SIZE, ENTRY_64B);
++	cr_set_field(host->ppe_base + PPE_TB_CFG, SMA, SMA_FWD_CPU_BUILD_ENTRY);
++
++	/* set ip proto */
++	writel(0xFFFFFFFF, host->ppe_base + PPE_IP_PROT_CHK);
++
++	/* setup caching */
++	cr_set_field(host->ppe_base + PPE_CAH_CTRL, CAH_X_MODE, 1);
++	cr_set_field(host->ppe_base + PPE_CAH_CTRL, CAH_X_MODE, 0);
++	cr_set_field(host->ppe_base + PPE_CAH_CTRL, CAH_EN, 1);
++
++	/* enable FOE */
++	cr_set_bits(host->ppe_base + PPE_FLOW_CFG,
++			    BIT_IPV4_NAT_EN | BIT_IPV4_NAPT_EN |
++			    BIT_IPV4_NAT_FRAG_EN | BIT_IPV4_HASH_GREK);
++
++	/* setup FOE aging */
++	cr_set_field(host->ppe_base + PPE_TB_CFG, NTU_AGE, 1);
++	cr_set_field(host->ppe_base + PPE_TB_CFG, UNBD_AGE, 1);
++	cr_set_field(host->ppe_base + PPE_UNB_AGE, UNB_MNP, 1000);
++	cr_set_field(host->ppe_base + PPE_UNB_AGE, UNB_DLTA, 3);
++	cr_set_field(host->ppe_base + PPE_TB_CFG, TCP_AGE, 1);
++	cr_set_field(host->ppe_base + PPE_TB_CFG, UDP_AGE, 1);
++	cr_set_field(host->ppe_base + PPE_TB_CFG, FIN_AGE, 1);
++	cr_set_field(host->ppe_base + PPE_BND_AGE_0, UDP_DLTA, 5);
++	cr_set_field(host->ppe_base + PPE_BND_AGE_0, NTU_DLTA, 5);
++	cr_set_field(host->ppe_base + PPE_BND_AGE_1, FIN_DLTA, 5);
++	cr_set_field(host->ppe_base + PPE_BND_AGE_1, TCP_DLTA, 5);
++
++	/* setup FOE ka */
++	cr_set_field(host->ppe_base + PPE_TB_CFG, KA_CFG, 3);
++	cr_set_field(host->ppe_base + PPE_KA, KA_T, 1);
++	cr_set_field(host->ppe_base + PPE_KA, TCP_KA, 1);
++	cr_set_field(host->ppe_base + PPE_KA, UDP_KA, 1);
++	cr_set_field(host->ppe_base + PPE_BIND_LMT_1, NTU_KA, 1);
++
++	/* setup FOE rate limit */
++	cr_set_field(host->ppe_base + PPE_BIND_LMT_0, QURT_LMT, 16383);
++	cr_set_field(host->ppe_base + PPE_BIND_LMT_0, HALF_LMT, 16383);
++	cr_set_field(host->ppe_base + PPE_BIND_LMT_1, FULL_LMT, 16383);
++	cr_set_field(host->ppe_base + PPE_BNDR, BIND_RATE, 1);
++
++	/* setup FOE cf gen */
++	cr_set_field(host->ppe_base + PPE_GLO_CFG, PPE_EN, 1);
++	writel(0, host->ppe_base + PPE_DFT_CPORT); // pdma
++	//writel(0x55555555, host->ppe_base + PPE_DFT_CPORT); //qdma
++	cr_set_field(host->ppe_base + PPE_GLO_CFG, TTL0_DRP, 1);
++
++	/* fwd packets from gmac to PPE */
++	cr_clr_bits(host->fe_base + GDMA1_FWD_CFG, GDM1_ALL_FRC_MASK);
++	cr_set_bits(host->fe_base + GDMA1_FWD_CFG,
++		    BITS_GDM1_ALL_FRC_P_PPE);
++	cr_clr_bits(host->fe_base + GDMA2_FWD_CFG, GDM2_ALL_FRC_MASK);
++	cr_set_bits(host->fe_base + GDMA2_FWD_CFG,
++		    BITS_GDM2_ALL_FRC_P_PPE);
++
++	dev_info(host->dev, "hwnat start\n");
++
++	return 0;
++}
++
++static int ppe_busy_wait(void)
++{
++	unsigned long t_start = jiffies;
++	u32 r = 0;
++
++	while (1) {
++		r = readl((host->ppe_base + 0x0));
++		if (!(r & BIT(31)))
++			return 0;
++		if (time_after(jiffies, t_start + HZ))
++			break;
++		usleep_range(10, 20);
++	}
++
++	dev_err(host->dev, "ppe:%s timeout\n", __func__);
++
++	return -1;
++}
++
++static void hnat_stop(void)
++{
++	u32 foe_table_sz;
++	struct foe_entry *entry, *end;
++	u32 r1 = 0, r2 = 0;
++
++	/* discard all traffic while we disable the PPE */
++	cr_clr_bits(host->fe_base + GDMA1_FWD_CFG, GDM1_ALL_FRC_MASK);
++	cr_set_bits(host->fe_base + GDMA1_FWD_CFG,
++		    BITS_GDM1_ALL_FRC_P_DISCARD);
++	cr_clr_bits(host->fe_base + GDMA2_FWD_CFG, GDM2_ALL_FRC_MASK);
++	cr_set_bits(host->fe_base + GDMA2_FWD_CFG,
++		    BITS_GDM2_ALL_FRC_P_DISCARD);
++
++	if (ppe_busy_wait()) {
++		reset_control_reset(host->rstc);
++		msleep(2000);
++		return;
++	}
++
++	entry = host->foe_table_cpu;
++        end = host->foe_table_cpu + FOE_4TB_SIZ;
++        while (entry < end) {
++		entry->bfib1.state = INVALID;
++                entry++;
++        }
++
++	/* disable caching */
++	cr_set_field(host->ppe_base + PPE_CAH_CTRL, CAH_X_MODE, 1);
++	cr_set_field(host->ppe_base + PPE_CAH_CTRL, CAH_X_MODE, 0);
++	cr_set_field(host->ppe_base + PPE_CAH_CTRL, CAH_EN, 0);
++
++	/* flush cache has to be ahead of hnat diable --*/
++	cr_set_field(host->ppe_base + PPE_GLO_CFG, PPE_EN, 0);
++
++	/* disable FOE */
++	cr_clr_bits(host->ppe_base + PPE_FLOW_CFG,
++			    BIT_IPV4_NAPT_EN | BIT_IPV4_NAT_EN |
++			    BIT_IPV4_NAT_FRAG_EN |
++			    BIT_FUC_FOE | BIT_FMC_FOE | BIT_FUC_FOE);
++
++	/* disable FOE aging */
++	cr_set_field(host->ppe_base + PPE_TB_CFG, NTU_AGE, 0);
++	cr_set_field(host->ppe_base + PPE_TB_CFG, UNBD_AGE, 0);
++	cr_set_field(host->ppe_base + PPE_TB_CFG, TCP_AGE, 0);
++	cr_set_field(host->ppe_base + PPE_TB_CFG, UDP_AGE, 0);
++	cr_set_field(host->ppe_base + PPE_TB_CFG, FIN_AGE, 0);
++
++	r1 = readl(host->fe_base + 0x100);
++	r2 = readl(host->fe_base + 0x10c);
++
++	dev_info(host->dev, "0x100 = 0x%x, 0x10c = 0x%x\n", r1, r2);
++
++	if (((r1 & 0xff00) >> 0x8) >= (r1 & 0xff) ||
++	    ((r1 & 0xff00) >> 0x8) >= (r2 & 0xff)) {
++		dev_info(host->dev, "reset pse\n");
++		writel(0x1, host->fe_base + 0x4);
++	}
++
++	/* free the FOE table */
++	foe_table_sz = FOE_4TB_SIZ * sizeof(struct foe_entry);
++	dma_free_coherent(NULL, foe_table_sz, host->foe_table_cpu,
++			  host->foe_table_dev);
++	writel(0, host->ppe_base + PPE_TB_BASE);
++
++	if (ppe_busy_wait()) {
++		reset_control_reset(host->rstc);
++		msleep(2000);
++		return;
++	}
++
++	/* send all traffic back to the DMA engine */
++	cr_clr_bits(host->fe_base + GDMA1_FWD_CFG, GDM1_ALL_FRC_MASK);
++	cr_set_bits(host->fe_base + GDMA1_FWD_CFG,
++		    BITS_GDM1_ALL_FRC_P_CPU_PDMA);
++	cr_clr_bits(host->fe_base + GDMA2_FWD_CFG, GDM2_ALL_FRC_MASK);
++	cr_set_bits(host->fe_base + GDMA2_FWD_CFG,
++		    BITS_GDM2_ALL_FRC_P_CPU_PDMA);
++}
++
++static int hnat_probe(struct platform_device *pdev)
++{
++	int err = 0;
++	struct resource *res ;
++	const char *name;
++	struct device_node *np;
++
++	host = devm_kzalloc(&pdev->dev, sizeof(struct hnat_priv), GFP_KERNEL);
++	if (!host)
++		return -ENOMEM;
++
++	host->dev = &pdev->dev;
++	np = host->dev->of_node;
++
++	err = of_property_read_string(np, "mtketh-wan", &name);
++	if (err < 0)
++		return -EINVAL;
++
++	strncpy(host->wan, (char *)name, IFNAMSIZ);
++	dev_info(&pdev->dev, "wan = %s\n", host->wan);
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res)
++		return -ENOENT;
++
++	host->fe_base = devm_ioremap_nocache(&pdev->dev, res->start,
++					     res->end - res->start + 1);
++	if (!host->fe_base)
++		return -EADDRNOTAVAIL;
++
++	host->ppe_base = host->fe_base + 0xe00;
++	err = hnat_init_debugfs(host);
++	if (err)
++		return err;
++
++	host->rstc = devm_reset_control_get(&pdev->dev, NULL);
++	if (IS_ERR(host->rstc))
++		return PTR_ERR(host->rstc);
++
++	err = hnat_start();
++	if (err)
++		goto err_out;
++
++	err = hnat_register_nf_hooks();
++	if (err)
++		goto err_out;
++
++	return 0;
++
++err_out:
++	hnat_stop();
++	hnat_deinit_debugfs(host);
++	return err;
++}
++
++static int hnat_remove(struct platform_device *pdev)
++{
++	hnat_unregister_nf_hooks();
++	hnat_stop();
++	hnat_deinit_debugfs(host);
++
++	return 0;
++}
++
++const struct of_device_id of_hnat_match[] = {
++	{ .compatible = "mediatek,mt7623-hnat" },
++	{},
++};
++
++static struct platform_driver hnat_driver = {
++	.probe = hnat_probe,
++	.remove = hnat_remove,
++	.driver = {
++		.name = "mediatek_soc_hnat",
++		.of_match_table = of_hnat_match,
++	},
++};
++
++module_platform_driver(hnat_driver);
++
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Sean Wang <[email protected]>");
++MODULE_AUTHOR("John Crispin <[email protected]>");
++MODULE_DESCRIPTION("Mediatek Hardware NAT");
+--- /dev/null
++++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
+@@ -0,0 +1,425 @@
++/*   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) 2014-2016 Sean Wang <[email protected]>
++ *   Copyright (C) 2016-2017 John Crispin <[email protected]>
++ */
++
++#include <linux/debugfs.h>
++#include <linux/string.h>
++#include <linux/if.h>
++#include <linux/if_ether.h>
++
++/*--------------------------------------------------------------------------*/
++/* Register Offset*/
++/*--------------------------------------------------------------------------*/
++#define PPE_GLO_CFG		0x00
++#define PPE_FLOW_CFG		0x04
++#define PPE_IP_PROT_CHK		0x08
++#define PPE_IP_PROT_0		0x0C
++#define PPE_IP_PROT_1		0x10
++#define PPE_IP_PROT_2		0x14
++#define PPE_IP_PROT_3		0x18
++#define PPE_TB_CFG		0x1C
++#define PPE_TB_BASE		0x20
++#define PPE_TB_USED		0x24
++#define PPE_BNDR		0x28
++#define PPE_BIND_LMT_0		0x2C
++#define PPE_BIND_LMT_1		0x30
++#define PPE_KA			0x34
++#define PPE_UNB_AGE		0x38
++#define PPE_BND_AGE_0		0x3C
++#define PPE_BND_AGE_1		0x40
++#define PPE_HASH_SEED		0x44
++#define PPE_DFT_CPORT		0x48
++#define PPE_MCAST_PPSE		0x84
++#define PPE_MCAST_L_0		0x88
++#define PPE_MCAST_H_0		0x8C
++#define PPE_MCAST_L_1		0x90
++#define PPE_MCAST_H_1		0x94
++#define PPE_MCAST_L_2		0x98
++#define PPE_MCAST_H_2		0x9C
++#define PPE_MCAST_L_3		0xA0
++#define PPE_MCAST_H_3		0xA4
++#define PPE_MCAST_L_4		0xA8
++#define PPE_MCAST_H_4		0xAC
++#define PPE_MCAST_L_5		0xB0
++#define PPE_MCAST_H_5		0xB4
++#define PPE_MCAST_L_6		0xBC
++#define PPE_MCAST_H_6		0xC0
++#define PPE_MCAST_L_7		0xC4
++#define PPE_MCAST_H_7		0xC8
++#define PPE_MCAST_L_8		0xCC
++#define PPE_MCAST_H_8		0xD0
++#define PPE_MCAST_L_9		0xD4
++#define PPE_MCAST_H_9		0xD8
++#define PPE_MCAST_L_A		0xDC
++#define PPE_MCAST_H_A		0xE0
++#define PPE_MCAST_L_B		0xE4
++#define PPE_MCAST_H_B		0xE8
++#define PPE_MCAST_L_C		0xEC
++#define PPE_MCAST_H_C		0xF0
++#define PPE_MCAST_L_D		0xF4
++#define PPE_MCAST_H_D		0xF8
++#define PPE_MCAST_L_E		0xFC
++#define PPE_MCAST_H_E		0xE0
++#define PPE_MCAST_L_F		0x100
++#define PPE_MCAST_H_F		0x104
++#define PPE_MTU_DRP		0x108
++#define PPE_MTU_VLYR_0		0x10C
++#define PPE_MTU_VLYR_1		0x110
++#define PPE_MTU_VLYR_2		0x114
++#define PPE_VPM_TPID		0x118
++#define PPE_CAH_CTRL		0x120
++#define PPE_CAH_TAG_SRH		0x124
++#define PPE_CAH_LINE_RW		0x128
++#define PPE_CAH_WDATA		0x12C
++#define PPE_CAH_RDATA		0x130
++
++#define GDMA1_FWD_CFG		0x500
++#define GDMA2_FWD_CFG		0x1500
++/*--------------------------------------------------------------------------*/
++/* Register Mask*/
++/*--------------------------------------------------------------------------*/
++/* PPE_TB_CFG mask */
++#define TB_ETRY_NUM		(0x7 << 0)	/* RW */
++#define TB_ENTRY_SIZE		(0x1 << 3)	/* RW */
++#define SMA			(0x3 << 4)		/* RW */
++#define NTU_AGE			(0x1 << 7)	/* RW */
++#define UNBD_AGE		(0x1 << 8)	/* RW */
++#define TCP_AGE			(0x1 << 9)	/* RW */
++#define UDP_AGE			(0x1 << 10)	/* RW */
++#define FIN_AGE			(0x1 << 11)	/* RW */
++#define KA_CFG			(0x3<< 12)
++#define HASH_MODE		(0x3 << 14)	/* RW */
++#define XMODE			(0x3 << 18)	/* RW */
++
++/*PPE_CAH_CTRL mask*/
++#define CAH_EN			(0x1 << 0)	/* RW */
++#define CAH_X_MODE		(0x1 << 9)	/* RW */
++
++/*PPE_UNB_AGE mask*/
++#define UNB_DLTA		(0xff << 0)	/* RW */
++#define UNB_MNP			(0xffff << 16)	/* RW */
++
++/*PPE_BND_AGE_0 mask*/
++#define UDP_DLTA		(0xffff << 0)	/* RW */
++#define NTU_DLTA		(0xffff << 16)	/* RW */
++
++/*PPE_BND_AGE_1 mask*/
++#define TCP_DLTA		(0xffff << 0)	/* RW */
++#define FIN_DLTA		(0xffff << 16)	/* RW */
++
++/*PPE_KA mask*/
++#define KA_T			(0xffff << 0)	/* RW */
++#define TCP_KA			(0xff << 16)	/* RW */
++#define UDP_KA			(0xff << 24)	/* RW */
++
++/*PPE_BIND_LMT_0 mask*/
++#define QURT_LMT		(0x3ff << 0)	/* RW */
++#define HALF_LMT		(0x3ff << 16)	/* RW */
++
++/*PPE_BIND_LMT_1 mask*/
++#define FULL_LMT		(0x3fff << 0)	/* RW */
++#define NTU_KA			(0xff << 16)	/* RW */
++
++/*PPE_BNDR mask*/
++#define BIND_RATE		(0xffff << 0)	/* RW */
++#define PBND_RD_PRD		(0xffff << 16)	/* RW */
++
++/*PPE_GLO_CFG mask*/
++#define PPE_EN			(0x1 << 0)	/* RW */
++#define TTL0_DRP		(0x1 << 4)	/* RW */
++
++/*GDMA1_FWD_CFG mask */
++#define GDM1_UFRC_MASK		(0x7 << 12)	/* RW */
++#define GDM1_BFRC_MASK		(0x7 << 8) /*RW*/
++#define GDM1_MFRC_MASK		(0x7 << 4) /*RW*/
++#define GDM1_OFRC_MASK		(0x7 << 0) /*RW*/
++#define GDM1_ALL_FRC_MASK	(GDM1_UFRC_MASK | GDM1_BFRC_MASK | GDM1_MFRC_MASK | GDM1_OFRC_MASK)
++
++#define GDM2_UFRC_MASK		(0x7 << 12)	/* RW */
++#define GDM2_BFRC_MASK		(0x7 << 8) /*RW*/
++#define GDM2_MFRC_MASK		(0x7 << 4) /*RW*/
++#define GDM2_OFRC_MASK		(0x7 << 0) /*RW*/
++#define GDM2_ALL_FRC_MASK	(GDM2_UFRC_MASK | GDM2_BFRC_MASK | GDM2_MFRC_MASK | GDM2_OFRC_MASK)
++
++/*--------------------------------------------------------------------------*/
++/* Descriptor Structure */
++/*--------------------------------------------------------------------------*/
++#define HNAT_SKB_CB(__skb) ((struct hnat_skb_cb *)&((__skb)->cb[40]))
++struct hnat_skb_cb {
++	__u16 iif;
++};
++
++struct hnat_unbind_info_blk {
++	u32 time_stamp:8;
++	u32 pcnt:16;		/* packet count */
++	u32 preb:1;
++	u32 pkt_type:3;
++	u32 state:2;
++	u32 udp:1;
++	u32 sta:1;		/* static entry */
++} __attribute__ ((packed));
++
++struct hnat_bind_info_blk {
++	u32 time_stamp:15;
++	u32 ka:1;		/* keep alive */
++	u32 vlan_layer:3;
++	u32 psn:1;		/* egress packet has PPPoE session */
++	u32 vpm:1;		/* 0:ethertype remark, 1:0x8100(CR default) */
++	u32 ps:1;		/* packet sampling */
++	u32 cah:1;		/* cacheable flag */
++	u32 rmt:1;		/* remove tunnel ip header (6rd/dslite only) */
++	u32 ttl:1;
++	u32 pkt_type:3;
++	u32 state:2;
++	u32 udp:1;
++	u32 sta:1;		/* static entry */
++} __attribute__ ((packed));
++
++struct hnat_info_blk2 {
++	u32 qid:4;		/* QID in Qos Port */
++	u32 fqos:1;		/* force to PSE QoS port */
++	u32 dp:3;		/* force to PSE port x 
++				 0:PSE,1:GSW, 2:GMAC,4:PPE,5:QDMA,7=DROP */
++	u32 mcast:1;		/* multicast this packet to CPU */
++	u32 pcpl:1;		/* OSBN */
++	u32 mlen:1;		/* 0:post 1:pre packet length in meter */
++	u32 alen:1;		/* 0:post 1:pre packet length in accounting */
++	u32 port_mg:6;		/* port meter group */
++	u32 port_ag:6;		/* port account group */
++	u32 dscp:8;		/* DSCP value */
++} __attribute__ ((packed));
++
++struct hnat_ipv4_hnapt {
++	union {
++		struct hnat_bind_info_blk bfib1;
++		struct hnat_unbind_info_blk udib1;
++		u32 info_blk1;
++	};
++	u32 sip;
++	u32 dip;
++	u16 dport;
++	u16 sport;
++	union {
++		struct hnat_info_blk2 iblk2;
++		u32 info_blk2;
++	};
++	u32 new_sip;
++	u32 new_dip;
++	u16 new_dport;
++	u16 new_sport;
++	u32 resv1;
++	u32 resv2;
++	u32 resv3:26;
++	u32 act_dp:6;		/* UDF */
++	u16 vlan1;
++	u16 etype;
++	u32 dmac_hi;
++	u16 vlan2;
++	u16 dmac_lo;
++	u32 smac_hi;
++	u16 pppoe_id;
++	u16 smac_lo;
++} __attribute__ ((packed));
++
++struct foe_entry {
++	union {
++		struct hnat_unbind_info_blk udib1;
++		struct hnat_bind_info_blk bfib1;
++		struct hnat_ipv4_hnapt ipv4_hnapt;
++	};
++};
++
++#define HNAT_AC_BYTE_LO(x)		(0x2000 + (x * 16))
++#define HNAT_AC_BYTE_HI(x)		(0x2004 + (x * 16))
++#define HNAT_AC_PACKET(x)		(0x2008 + (x * 16))
++#define HNAT_COUNTER_MAX		64
++#define HNAT_AC_TIMER_INTERVAL		(HZ)
++
++struct hnat_accounting {
++	u64 bytes;
++	u64 packets;
++};
++
++struct hnat_priv {
++	struct device *dev;
++	void __iomem *fe_base;
++	void __iomem *ppe_base;
++	struct foe_entry *foe_table_cpu;
++	dma_addr_t foe_table_dev;
++	u8 enable;
++	u8 enable1;
++	struct dentry *root;
++	struct debugfs_regset32 *regset;
++
++	struct timer_list ac_timer;
++	struct hnat_accounting acct[HNAT_COUNTER_MAX];
++
++	/*devices we plays for*/
++	char wan[IFNAMSIZ];
++
++	struct reset_control	*rstc;
++};
++
++enum FoeEntryState {
++	INVALID = 0,
++	UNBIND = 1,
++	BIND = 2,
++	FIN = 3
++};
++/*--------------------------------------------------------------------------*/
++/* Common Definition*/
++/*--------------------------------------------------------------------------*/
++
++#define FOE_4TB_SIZ		4096
++#define HASH_SEED_KEY		0x12345678
++
++/*PPE_TB_CFG value*/
++#define ENTRY_80B		1
++#define ENTRY_64B		0
++#define TABLE_1K		0
++#define TABLE_2K		1
++#define TABLE_4K		2
++#define TABLE_8K		3
++#define TABLE_16K		4
++#define SMA_DROP		0		/* Drop the packet */
++#define SMA_DROP2		1		/* Drop the packet */
++#define SMA_ONLY_FWD_CPU	2	/* Only Forward to CPU */
++#define SMA_FWD_CPU_BUILD_ENTRY	3	/* Forward to CPU and build new FOE entry */
++#define HASH_MODE_0		0
++#define HASH_MODE_1		1
++#define HASH_MODE_2		2
++#define HASH_MODE_3		3
++
++/*PPE_FLOW_CFG*/
++#define BIT_FUC_FOE		BIT(2)
++#define BIT_FMC_FOE		BIT(1)
++#define BIT_FBC_FOE		BIT(0)
++#define BIT_IPV4_NAT_EN		BIT(12)
++#define BIT_IPV4_NAPT_EN	BIT(13)
++#define BIT_IPV4_NAT_FRAG_EN	BIT(17)
++#define BIT_IPV4_HASH_GREK	BIT(19)
++
++/*GDMA1_FWD_CFG value */
++#define BITS_GDM1_UFRC_P_PPE	(NR_PPE_PORT << 12)
++#define BITS_GDM1_BFRC_P_PPE	(NR_PPE_PORT << 8)
++#define BITS_GDM1_MFRC_P_PPE	(NR_PPE_PORT << 4)
++#define BITS_GDM1_OFRC_P_PPE	(NR_PPE_PORT << 0)
++#define BITS_GDM1_ALL_FRC_P_PPE	(BITS_GDM1_UFRC_P_PPE | BITS_GDM1_BFRC_P_PPE | BITS_GDM1_MFRC_P_PPE | BITS_GDM1_OFRC_P_PPE)
++
++#define BITS_GDM1_UFRC_P_CPU_PDMA	(NR_PDMA_PORT << 12)
++#define BITS_GDM1_BFRC_P_CPU_PDMA	(NR_PDMA_PORT << 8)
++#define BITS_GDM1_MFRC_P_CPU_PDMA	(NR_PDMA_PORT << 4)
++#define BITS_GDM1_OFRC_P_CPU_PDMA	(NR_PDMA_PORT << 0)
++#define BITS_GDM1_ALL_FRC_P_CPU_PDMA	(BITS_GDM1_UFRC_P_CPU_PDMA | BITS_GDM1_BFRC_P_CPU_PDMA | BITS_GDM1_MFRC_P_CPU_PDMA | BITS_GDM1_OFRC_P_CPU_PDMA)
++
++#define BITS_GDM1_UFRC_P_CPU_QDMA	(NR_QDMA_PORT << 12)
++#define BITS_GDM1_BFRC_P_CPU_QDMA	(NR_QDMA_PORT << 8)
++#define BITS_GDM1_MFRC_P_CPU_QDMA	(NR_QDMA_PORT << 4)
++#define BITS_GDM1_OFRC_P_CPU_QDMA	(NR_QDMA_PORT << 0)
++#define BITS_GDM1_ALL_FRC_P_CPU_QDMA	(BITS_GDM1_UFRC_P_CPU_QDMA | BITS_GDM1_BFRC_P_CPU_QDMA | BITS_GDM1_MFRC_P_CPU_QDMA | BITS_GDM1_OFRC_P_CPU_QDMA)
++
++#define BITS_GDM1_UFRC_P_DISCARD	(NR_DISCARD << 12)
++#define BITS_GDM1_BFRC_P_DISCARD	(NR_DISCARD << 8)
++#define BITS_GDM1_MFRC_P_DISCARD	(NR_DISCARD << 4)
++#define BITS_GDM1_OFRC_P_DISCARD	(NR_DISCARD << 0)
++#define BITS_GDM1_ALL_FRC_P_DISCARD	(BITS_GDM1_UFRC_P_DISCARD | BITS_GDM1_BFRC_P_DISCARD | BITS_GDM1_MFRC_P_DISCARD | BITS_GDM1_OFRC_P_DISCARD)
++
++#define BITS_GDM2_UFRC_P_PPE	(NR_PPE_PORT << 12)
++#define BITS_GDM2_BFRC_P_PPE	(NR_PPE_PORT << 8)
++#define BITS_GDM2_MFRC_P_PPE	(NR_PPE_PORT << 4)
++#define BITS_GDM2_OFRC_P_PPE	(NR_PPE_PORT << 0)
++#define BITS_GDM2_ALL_FRC_P_PPE	(BITS_GDM2_UFRC_P_PPE | BITS_GDM2_BFRC_P_PPE | BITS_GDM2_MFRC_P_PPE | BITS_GDM2_OFRC_P_PPE)
++
++#define BITS_GDM2_UFRC_P_CPU_PDMA	(NR_PDMA_PORT << 12)
++#define BITS_GDM2_BFRC_P_CPU_PDMA	(NR_PDMA_PORT << 8)
++#define BITS_GDM2_MFRC_P_CPU_PDMA	(NR_PDMA_PORT << 4)
++#define BITS_GDM2_OFRC_P_CPU_PDMA	(NR_PDMA_PORT << 0)
++#define BITS_GDM2_ALL_FRC_P_CPU_PDMA	(BITS_GDM2_UFRC_P_CPU_PDMA | BITS_GDM2_BFRC_P_CPU_PDMA | BITS_GDM2_MFRC_P_CPU_PDMA | BITS_GDM2_OFRC_P_CPU_PDMA)
++
++#define BITS_GDM2_UFRC_P_CPU_QDMA	(NR_QDMA_PORT << 12)
++#define BITS_GDM2_BFRC_P_CPU_QDMA	(NR_QDMA_PORT << 8)
++#define BITS_GDM2_MFRC_P_CPU_QDMA	(NR_QDMA_PORT << 4)
++#define BITS_GDM2_OFRC_P_CPU_QDMA	(NR_QDMA_PORT << 0)
++#define BITS_GDM2_ALL_FRC_P_CPU_QDMA	(BITS_GDM2_UFRC_P_CPU_QDMA | BITS_GDM2_BFRC_P_CPU_QDMA | BITS_GDM2_MFRC_P_CPU_QDMA | BITS_GDM2_OFRC_P_CPU_QDMA)
++
++#define BITS_GDM2_UFRC_P_DISCARD	(NR_DISCARD << 12)
++#define BITS_GDM2_BFRC_P_DISCARD	(NR_DISCARD << 8)
++#define BITS_GDM2_MFRC_P_DISCARD	(NR_DISCARD << 4)
++#define BITS_GDM2_OFRC_P_DISCARD	(NR_DISCARD << 0)
++#define BITS_GDM2_ALL_FRC_P_DISCARD	(BITS_GDM2_UFRC_P_DISCARD | BITS_GDM2_BFRC_P_DISCARD | BITS_GDM2_MFRC_P_DISCARD | BITS_GDM2_OFRC_P_DISCARD)
++
++#define hnat_is_enabled(host)	(host->enable)
++#define hnat_enabled(host)	(host->enable = 1)
++#define hnat_disabled(host)	(host->enable = 0)
++#define hnat_is_enabled1(host)	(host->enable1)
++#define hnat_enabled1(host)	(host->enable1 = 1)
++#define hnat_disabled1(host)	(host->enable1 = 0)
++
++#define entry_hnat_is_bound(e)	(e->bfib1.state == BIND)
++#define entry_hnat_state(e)	(e->bfib1.state)
++
++#define skb_hnat_is_hashed(skb)	(skb_hnat_entry(skb)!=0x3fff && skb_hnat_entry(skb)< FOE_4TB_SIZ)
++#define FROM_GE_LAN(skb)	(HNAT_SKB_CB(skb)->iif == FOE_MAGIC_GE_LAN)
++#define FROM_GE_WAN(skb)	(HNAT_SKB_CB(skb)->iif == FOE_MAGIC_GE_WAN)
++#define FROM_GE_PPD(skb)	(HNAT_SKB_CB(skb)->iif == FOE_MAGIC_GE_PPD)
++#define FOE_MAGIC_GE_WAN	0x7273
++#define FOE_MAGIC_GE_LAN	0x7272
++#define FOE_INVALID		0xffff
++
++#define TCP_FIN_SYN_RST		0x0C /* Ingress packet is TCP fin/syn/rst (for IPv4 NAPT/DS-Lite or IPv6 5T-route/6RD) */
++#define UN_HIT			0x0D/* FOE Un-hit */
++#define HIT_UNBIND		0x0E/* FOE Hit unbind */
++#define HIT_UNBIND_RATE_REACH	0xf
++#define HNAT_HIT_BIND_OLD_DUP_HDR	0x15
++#define HNAT_HIT_BIND_FORCE_TO_CPU	0x16
++
++#define HIT_BIND_KEEPALIVE_MC_NEW_HDR	0x14
++#define HIT_BIND_KEEPALIVE_DUP_OLD_HDR	0x15
++#define IPV4_HNAPT			0
++#define IPV4_HNAT			1
++#define IP_FORMAT(addr) \
++		((unsigned char *)&addr)[3], \
++		((unsigned char *)&addr)[2], \
++		((unsigned char *)&addr)[1], \
++		((unsigned char *)&addr)[0]
++
++/*PSE Ports*/
++#define NR_PDMA_PORT		0
++#define NR_GMAC1_PORT		1
++#define NR_GMAC2_PORT		2
++#define NR_PPE_PORT		4
++#define NR_QDMA_PORT		5
++#define NR_DISCARD		7
++#define IS_LAN(dev)		(!strncmp(dev->name, "lan", 3))
++#define IS_WAN(dev)		(!strcmp(dev->name, host->wan))
++#define IS_BR(dev)		(!strncmp(dev->name, "br", 2))
++#define IS_IPV4_HNAPT(x)	(((x)->bfib1.pkt_type == IPV4_HNAPT) ? 1: 0)
++#define IS_IPV4_HNAT(x)		(((x)->bfib1.pkt_type == IPV4_HNAT) ? 1 : 0)
++#define IS_IPV4_GRP(x)		(IS_IPV4_HNAPT(x) | IS_IPV4_HNAT(x))
++
++#define es(entry)		(entry_state[entry->bfib1.state])
++#define ei(entry, end)		(FOE_4TB_SIZ - (int)(end - entry))
++#define pt(entry)		(packet_type[entry->ipv4_hnapt.bfib1.pkt_type])
++#define ipv4_smac(mac,e)	({mac[0]=e->ipv4_hnapt.smac_hi[3]; mac[1]=e->ipv4_hnapt.smac_hi[2];\
++				 mac[2]=e->ipv4_hnapt.smac_hi[1]; mac[3]=e->ipv4_hnapt.smac_hi[0];\
++				 mac[4]=e->ipv4_hnapt.smac_lo[1]; mac[5]=e->ipv4_hnapt.smac_lo[0];})
++#define ipv4_dmac(mac,e)	({mac[0]=e->ipv4_hnapt.dmac_hi[3]; mac[1]=e->ipv4_hnapt.dmac_hi[2];\
++				 mac[2]=e->ipv4_hnapt.dmac_hi[1]; mac[3]=e->ipv4_hnapt.dmac_hi[0];\
++				 mac[4]=e->ipv4_hnapt.dmac_lo[1]; mac[5]=e->ipv4_hnapt.dmac_lo[0];})
++
++extern struct hnat_priv *host;
++
++extern void hnat_deinit_debugfs(struct hnat_priv *h);
++extern int __init hnat_init_debugfs(struct hnat_priv *h);
++extern int hnat_register_nf_hooks(void);
++extern void hnat_unregister_nf_hooks(void);
++
+--- /dev/null
++++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c
+@@ -0,0 +1,489 @@
++/*   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) 2014-2016 Sean Wang <[email protected]>
++ *   Copyright (C) 2016-2017 John Crispin <[email protected]>
++ */
++
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/dma-mapping.h>
++
++#include "hnat.h"
++
++static const char *entry_state[] = {
++	"INVALID",
++	"UNBIND",
++	"BIND",
++	"FIN"
++};
++
++static const char *packet_type[] = {
++	"IPV4_HNAPT",
++	"IPV4_HNAT",
++	"IPV6_1T_ROUTE",
++	"IPV4_DSLITE",
++	"IPV6_3T_ROUTE",
++	"IPV6_5T_ROUTE",
++	"IPV6_6RD",
++};
++
++static int hnat_debug_show(struct seq_file *m, void *private)
++{
++	struct hnat_priv *h = host;
++	struct foe_entry *entry, *end;
++
++	entry = h->foe_table_cpu;
++	end = h->foe_table_cpu + FOE_4TB_SIZ;
++	while (entry < end) {
++		if (!entry->bfib1.state) {
++			entry++;
++			continue;
++		}
++
++		if (IS_IPV4_HNAPT(entry)) {
++			__be32 saddr = htonl(entry->ipv4_hnapt.sip);
++			__be32 daddr = htonl(entry->ipv4_hnapt.dip);
++			__be32 nsaddr = htonl(entry->ipv4_hnapt.new_sip);
++			__be32 ndaddr = htonl(entry->ipv4_hnapt.new_dip);
++			unsigned char h_dest[ETH_ALEN];
++			unsigned char h_source[ETH_ALEN];
++
++			*((u32*) h_source) = swab32(entry->ipv4_hnapt.smac_hi);
++			*((u16*) &h_source[4]) = swab16(entry->ipv4_hnapt.smac_lo);
++			*((u32*) h_dest) = swab32(entry->ipv4_hnapt.dmac_hi);
++			*((u16*) &h_dest[4]) = swab16(entry->ipv4_hnapt.dmac_lo);
++			seq_printf(m,
++				   "(%p)0x%05x|state=%s|type=%s|%pI4:%d->%pI4:%d=>%pI4:%d->%pI4:%d|%pM=>%pM|etype=0x%04x|info1=0x%x|info2=0x%x|vlan1=%d|vlan2=%d\n",
++				   (void *)h->foe_table_dev + ((void *)(entry) - (void *)h->foe_table_cpu),
++				   ei(entry, end), es(entry), pt(entry),
++				   &saddr, entry->ipv4_hnapt.sport,
++				   &daddr, entry->ipv4_hnapt.dport,
++				   &nsaddr, entry->ipv4_hnapt.new_sport,
++				   &ndaddr, entry->ipv4_hnapt.new_dport, h_source,
++				   h_dest, ntohs(entry->ipv4_hnapt.etype),
++				   entry->ipv4_hnapt.info_blk1,
++				   entry->ipv4_hnapt.info_blk2,
++				   entry->ipv4_hnapt.vlan1,
++				   entry->ipv4_hnapt.vlan2);
++		} else
++			seq_printf(m, "0x%05x state=%s\n",
++				   ei(entry, end), es(entry));
++		entry++;
++	}
++
++	return 0;
++}
++
++static int hnat_debug_open(struct inode *inode, struct file *file)
++{
++	return single_open(file, hnat_debug_show, file->private_data);
++}
++
++static const struct file_operations hnat_debug_fops = {
++	.open = hnat_debug_open,
++	.read = seq_read,
++	.llseek = seq_lseek,
++	.release = single_release,
++};
++
++#define QDMA_TX_SCH_TX		0x1a14
++
++static ssize_t hnat_sched_show(struct file *file, char __user *user_buf,
++			       size_t count, loff_t *ppos)
++{
++	int id = (int) file->private_data;
++	struct hnat_priv *h = host;
++	u32 reg = readl(h->fe_base + QDMA_TX_SCH_TX);
++	int enable;
++	int max_rate;
++	char *buf;
++	unsigned int len = 0, buf_len = 1500;
++	ssize_t ret_cnt;
++
++	buf = kzalloc(buf_len, GFP_KERNEL);
++	if (!buf)
++		return -ENOMEM;
++
++
++	if (id)
++		reg >>= 16;
++	reg &= 0xffff;
++	enable = !! (reg & BIT(11));
++	max_rate = ((reg >> 4) & 0x7f);
++	reg &= 0xf;
++	while (reg--)
++		max_rate *= 10;
++
++	len += scnprintf(buf + len, buf_len - len,
++			 "EN\tMAX\n%d\t%d\n", enable, max_rate);
++
++	if (len > buf_len)
++		len = buf_len;
++
++	ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
++
++	kfree(buf);
++	return ret_cnt;
++}
++
++static ssize_t hnat_sched_write(struct file *file,
++				const char __user *buf, size_t length, loff_t *offset)
++{
++	int id = (int) file->private_data;
++	struct hnat_priv *h = host;
++	char line[64];
++	int enable, rate, exp = 0, shift = 0;
++	size_t size;
++	u32 reg = readl(h->fe_base + QDMA_TX_SCH_TX);
++	u32 val = 0;
++
++	if (length > sizeof(line))
++		return -EINVAL;
++
++        if (copy_from_user(line, buf, length))
++		return -EFAULT;
++
++	sscanf(line, "%d %d", &enable, &rate);
++
++	while (rate > 127) {
++		rate /= 10;
++		exp++;
++	}
++
++	if (enable)
++		val |= BIT(11);
++	val |= (rate & 0x7f) << 4;
++	val |= exp & 0xf;
++	if (id)
++		shift = 16;
++	reg &= ~(0xffff << shift);
++	reg |= val << shift;
++	writel(reg, h->fe_base + QDMA_TX_SCH_TX);
++
++	size = strlen(line);
++	*offset += size;
++
++	return length;
++}
++
++static const struct file_operations hnat_sched_fops = {
++	.open = simple_open,
++	.read = hnat_sched_show,
++	.write = hnat_sched_write,
++	.llseek = default_llseek,
++};
++
++#define QTX_CFG(x)	(0x1800 + (x * 0x10))
++#define QTX_SCH(x)	(0x1804 + (x * 0x10))
++
++static ssize_t hnat_queue_show(struct file *file, char __user *user_buf,
++			       size_t count, loff_t *ppos)
++{
++	struct hnat_priv *h = host;
++	int id = (int) file->private_data;
++	u32 reg = readl(h->fe_base + QTX_SCH(id));
++	u32 cfg = readl(h->fe_base + QTX_CFG(id));
++	int scheduler = !!(reg & BIT(31));
++	int min_rate_en = !!(reg & BIT(27));
++	int min_rate = (reg >> 20) & 0x7f;
++	int min_rate_exp = (reg >> 16) & 0xf;
++	int max_rate_en = !!(reg & BIT(11));
++	int max_weight = (reg >> 12) & 0xf;
++	int max_rate = (reg >> 4) & 0x7f;
++	int max_rate_exp = reg & 0xf;
++	char *buf;
++	unsigned int len = 0, buf_len = 1500;
++	ssize_t ret_cnt;
++
++	buf = kzalloc(buf_len, GFP_KERNEL);
++	if (!buf)
++		return -ENOMEM;
++
++	while (min_rate_exp--)
++		min_rate *= 10;
++
++	while (max_rate_exp--)
++		max_rate *= 10;
++
++	len += scnprintf(buf + len, buf_len - len,
++			"scheduler: %d\nhw resv: %d\nsw resv: %d\n",
++			scheduler, (cfg >> 8) & 0xff, cfg & 0xff);
++	len += scnprintf(buf + len, buf_len - len,
++			"\tEN\tRATE\t\tWEIGHT\n");
++	len += scnprintf(buf + len, buf_len - len,
++			"max\t%d\t%8d\t%d\n", max_rate_en, max_rate, max_weight);
++	len += scnprintf(buf + len, buf_len - len,
++			"min\t%d\t%8d\t-\n", min_rate_en, min_rate);
++
++	if (len > buf_len)
++		len = buf_len;
++
++	ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
++
++	kfree(buf);
++	return ret_cnt;
++}
++
++static ssize_t hnat_queue_write(struct file *file,
++				const char __user *buf, size_t length, loff_t *offset)
++{
++	int id = (int) file->private_data;
++	struct hnat_priv *h = host;
++	char line[64];
++	int max_enable, max_rate, max_exp = 0;
++	int min_enable, min_rate, min_exp = 0;
++	int weight;
++	int resv;
++	int scheduler;
++	size_t size;
++	u32 reg = readl(h->fe_base + QTX_SCH(id));
++
++	if (length > sizeof(line))
++		return -EINVAL;
++
++        if (copy_from_user(line, buf, length))
++		return -EFAULT;
++
++	sscanf(line, "%d %d %d %d %d %d %d", &scheduler, &min_enable, &min_rate, &max_enable, &max_rate, &weight, &resv);
++
++	while (max_rate > 127) {
++		max_rate /= 10;
++		max_exp++;
++	}
++
++	while (min_rate > 127) {
++		min_rate /= 10;
++		min_exp++;
++	}
++
++	reg &= 0x70000000;
++	if (scheduler)
++		reg |= BIT(31);
++	if (min_enable)
++		reg |= BIT(27);
++	reg |= (min_rate & 0x7f) << 20;
++	reg |= (min_exp & 0xf) << 16;
++	if (max_enable)
++		reg |= BIT(11);
++	reg |= (weight & 0xf) << 12;
++	reg |= (max_rate & 0x7f) << 4;
++	reg |= max_exp & 0xf;
++	writel(reg, h->fe_base + QTX_SCH(id));
++
++	resv &= 0xff;
++	reg = readl(h->fe_base + QTX_CFG(id));
++	reg &= 0xffff0000;
++	reg |= (resv << 8) | resv;
++	writel(reg, h->fe_base + QTX_CFG(id));
++
++	size = strlen(line);
++	*offset += size;
++
++	return length;
++}
++
++static const struct file_operations hnat_queue_fops = {
++	.open = simple_open,
++	.read = hnat_queue_show,
++	.write = hnat_queue_write,
++	.llseek = default_llseek,
++};
++
++static void hnat_ac_timer_handle(unsigned long priv)
++{
++	struct hnat_priv *h = (struct hnat_priv*) priv;
++	int i;
++
++	for (i = 0; i < HNAT_COUNTER_MAX; i++) {
++		u32 b_hi, b_lo;
++		u64 b;
++
++		b_lo = readl(h->fe_base + HNAT_AC_BYTE_LO(i));
++		b_hi = readl(h->fe_base + HNAT_AC_BYTE_HI(i));
++		b = b_hi;
++		b <<= 32;
++		b += b_lo;
++		h->acct[i].bytes += b;
++		h->acct[i].packets += readl(h->fe_base + HNAT_AC_PACKET(i));
++	}
++
++	mod_timer(&h->ac_timer, jiffies + HNAT_AC_TIMER_INTERVAL);
++}
++
++static ssize_t hnat_counter_show(struct file *file, char __user *user_buf,
++				 size_t count, loff_t *ppos)
++{
++	struct hnat_priv *h = host;
++	int id = (int) file->private_data;
++	char *buf;
++	unsigned int len = 0, buf_len = 1500;
++	ssize_t ret_cnt;
++	int id2 = id + (HNAT_COUNTER_MAX / 2);
++
++	buf = kzalloc(buf_len, GFP_KERNEL);
++	if (!buf)
++		return -ENOMEM;
++
++	len += scnprintf(buf + len, buf_len - len,
++			 "tx pkts : %llu\ntx bytes: %llu\nrx pktks : %llu\nrx bytes : %llu\n",
++			 h->acct[id].packets, h->acct[id].bytes,
++			 h->acct[id2].packets, h->acct[id2].bytes);
++
++	if (len > buf_len)
++		len = buf_len;
++
++	ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
++
++	kfree(buf);
++	return ret_cnt;
++}
++
++static const struct file_operations hnat_counter_fops = {
++	.open = simple_open,
++	.read = hnat_counter_show,
++	.llseek = default_llseek,
++};
++
++#define dump_register(nm)				\
++{							\
++	.name	= __stringify(nm),			\
++	.offset	= PPE_ ##nm ,	\
++}
++
++static const struct debugfs_reg32 hnat_regs[] = {
++	dump_register(GLO_CFG),
++	dump_register(FLOW_CFG),
++	dump_register(IP_PROT_CHK),
++	dump_register(IP_PROT_0),
++	dump_register(IP_PROT_1),
++	dump_register(IP_PROT_2),
++	dump_register(IP_PROT_3),
++	dump_register(TB_CFG),
++	dump_register(TB_BASE),
++	dump_register(TB_USED),
++	dump_register(BNDR),
++	dump_register(BIND_LMT_0),
++	dump_register(BIND_LMT_1),
++	dump_register(KA),
++	dump_register(UNB_AGE),
++	dump_register(BND_AGE_0),
++	dump_register(BND_AGE_1),
++	dump_register(HASH_SEED),
++	dump_register(DFT_CPORT),
++	dump_register(MCAST_PPSE),
++	dump_register(MCAST_L_0),
++	dump_register(MCAST_H_0),
++	dump_register(MCAST_L_1),
++	dump_register(MCAST_H_1),
++	dump_register(MCAST_L_2),
++	dump_register(MCAST_H_2),
++	dump_register(MCAST_L_3),
++	dump_register(MCAST_H_3),
++	dump_register(MCAST_L_4),
++	dump_register(MCAST_H_4),
++	dump_register(MCAST_L_5),
++	dump_register(MCAST_H_5),
++	dump_register(MCAST_L_6),
++	dump_register(MCAST_H_6),
++	dump_register(MCAST_L_7),
++	dump_register(MCAST_H_7),
++	dump_register(MCAST_L_8),
++	dump_register(MCAST_H_8),
++	dump_register(MCAST_L_9),
++	dump_register(MCAST_H_9),
++	dump_register(MCAST_L_A),
++	dump_register(MCAST_H_A),
++	dump_register(MCAST_L_B),
++	dump_register(MCAST_H_B),
++	dump_register(MCAST_L_C),
++	dump_register(MCAST_H_C),
++	dump_register(MCAST_L_D),
++	dump_register(MCAST_H_D),
++	dump_register(MCAST_L_E),
++	dump_register(MCAST_H_E),
++	dump_register(MCAST_L_F),
++	dump_register(MCAST_H_F),
++	dump_register(MTU_DRP),
++	dump_register(MTU_VLYR_0),
++	dump_register(MTU_VLYR_1),
++	dump_register(MTU_VLYR_2),
++	dump_register(VPM_TPID),
++	dump_register(VPM_TPID),
++	dump_register(CAH_CTRL),
++	dump_register(CAH_TAG_SRH),
++	dump_register(CAH_LINE_RW),
++	dump_register(CAH_WDATA),
++	dump_register(CAH_RDATA),
++};
++
++int __init hnat_init_debugfs(struct hnat_priv *h)
++{
++	int ret = 0;
++	struct dentry *root;
++	struct dentry *file;
++	int i;
++	char name[16];
++
++	root = debugfs_create_dir("hnat", NULL);
++	if (!root) {
++		dev_err(h->dev, "%s:err at %d\n", __func__, __LINE__);
++		ret = -ENOMEM;
++		goto err0;
++	}
++	h->root = root;
++	h->regset = kzalloc(sizeof(*h->regset), GFP_KERNEL);
++	if (!h->regset) {
++		dev_err(h->dev, "%s:err at %d\n", __func__, __LINE__);
++		ret = -ENOMEM;
++		goto err1;
++	}
++	h->regset->regs = hnat_regs;
++	h->regset->nregs = ARRAY_SIZE(hnat_regs);
++	h->regset->base = h->ppe_base;
++
++	file = debugfs_create_regset32("regdump", S_IRUGO, root, h->regset);
++	if (!file) {
++		dev_err(h->dev, "%s:err at %d\n", __func__, __LINE__);
++		ret = -ENOMEM;
++		goto err1;
++	}
++	debugfs_create_file("all_entry", S_IRUGO, root, h, &hnat_debug_fops);
++	for (i = 0; i < HNAT_COUNTER_MAX / 2; i++) {
++		snprintf(name, sizeof(name), "counter%d", i);
++		debugfs_create_file(name, S_IRUGO, root, (void *)i, &hnat_counter_fops);
++	}
++
++	for (i = 0; i < 2; i++) {
++		snprintf(name, sizeof(name), "scheduler%d", i);
++		debugfs_create_file(name, S_IRUGO, root, (void *)i, &hnat_sched_fops);
++	}
++
++	for (i = 0; i < 16; i++) {
++		snprintf(name, sizeof(name), "queue%d", i);
++		debugfs_create_file(name, S_IRUGO, root, (void *)i, &hnat_queue_fops);
++	}
++
++	setup_timer(&h->ac_timer, hnat_ac_timer_handle, (unsigned long) h);
++	mod_timer(&h->ac_timer, jiffies + HNAT_AC_TIMER_INTERVAL);
++
++	return 0;
++
++ err1:
++	debugfs_remove_recursive(root);
++ err0:
++	return ret;
++}
++
++void hnat_deinit_debugfs(struct hnat_priv *h)
++{
++	del_timer(&h->ac_timer);
++	debugfs_remove_recursive(h->root);
++	h->root = NULL;
++}
+--- /dev/null
++++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
+@@ -0,0 +1,289 @@
++/*   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) 2014-2016 Sean Wang <[email protected]>
++ *   Copyright (C) 2016-2017 John Crispin <[email protected]>
++ */
++
++#include <linux/netfilter_bridge.h>
++
++#include <net/arp.h>
++#include <net/neighbour.h>
++#include <net/netfilter/nf_conntrack_helper.h>
++
++#include "nf_hnat_mtk.h"
++#include "hnat.h"
++
++#include "../mtk_eth_soc.h"
++
++static unsigned int skb_to_hnat_info(struct sk_buff *skb,
++				     const struct net_device *dev,
++				     struct foe_entry *foe)
++{
++	struct foe_entry entry = { 0 };
++	int lan = IS_LAN(dev);
++	struct ethhdr *eth;
++	struct iphdr *iph;
++	struct tcphdr *tcph;
++	struct udphdr *udph;
++	int tcp = 0;
++	int ipv4 = 0;
++	u32 gmac;
++
++	eth = eth_hdr(skb);
++	switch (ntohs(eth->h_proto)) {
++	case ETH_P_IP:
++		ipv4 = 1;
++		break;
++
++	default:
++		return -1;
++	}
++
++	iph = ip_hdr(skb);
++	switch (iph->protocol) {
++	case IPPROTO_TCP:
++		tcph = tcp_hdr(skb);
++		tcp = 1;
++		break;
++
++	case IPPROTO_UDP:
++		udph = udp_hdr(skb);
++		break;
++
++	default:
++		return -1;
++	}
++
++	entry.ipv4_hnapt.etype = htons(ETH_P_IP);
++
++	if (lan) {
++		entry.ipv4_hnapt.etype = htons(ETH_P_8021Q);
++		entry.bfib1.vlan_layer = 1;
++		entry.ipv4_hnapt.vlan1 = BIT(dev->name[3] - '0');
++	}
++
++	if (dev->priv_flags & IFF_802_1Q_VLAN) {
++		struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
++
++		entry.ipv4_hnapt.etype = htons(ETH_P_8021Q);
++		entry.bfib1.vlan_layer = 1;
++		if (lan)
++			entry.ipv4_hnapt.vlan2 = vlan->vlan_id;
++		else
++			entry.ipv4_hnapt.vlan1 = vlan->vlan_id;
++	}
++
++	entry.ipv4_hnapt.dmac_hi = swab32(*((u32*) eth->h_dest));
++	entry.ipv4_hnapt.dmac_lo = swab16(*((u16*) &eth->h_dest[4]));
++	entry.ipv4_hnapt.smac_hi = swab32(*((u32*) eth->h_source));
++	entry.ipv4_hnapt.smac_lo = swab16(*((u16*) &eth->h_source[4]));
++	entry.ipv4_hnapt.pppoe_id = 0;
++	entry.bfib1.psn = 0;
++	entry.ipv4_hnapt.bfib1.vpm = 1;
++
++	if (ipv4)
++		entry.ipv4_hnapt.bfib1.pkt_type = IPV4_HNAPT;
++
++	entry.ipv4_hnapt.new_sip = ntohl(iph->saddr);
++	entry.ipv4_hnapt.new_dip = ntohl(iph->daddr);
++	entry.ipv4_hnapt.iblk2.dscp = iph->tos;
++#if defined(CONFIG_NET_MEDIATEK_HW_QOS)
++	entry.ipv4_hnapt.iblk2.qid = skb->mark & 0x7;
++	if (lan)
++		entry.ipv4_hnapt.iblk2.qid += 8;
++	entry.ipv4_hnapt.iblk2.fqos = 1;
++#endif
++	if (tcp) {
++		entry.ipv4_hnapt.new_sport = ntohs(tcph->source);
++		entry.ipv4_hnapt.new_dport = ntohs(tcph->dest);
++		entry.ipv4_hnapt.bfib1.udp = 0;
++	} else {
++		entry.ipv4_hnapt.new_sport = ntohs(udph->source);
++		entry.ipv4_hnapt.new_dport = ntohs(udph->dest);
++		entry.ipv4_hnapt.bfib1.udp = 1;
++	}
++
++	if (IS_LAN(dev))
++		gmac = NR_GMAC1_PORT;
++	else if (IS_WAN(dev))
++		gmac = NR_GMAC2_PORT;
++
++	if (is_multicast_ether_addr(&eth->h_dest[0]))
++		entry.ipv4_hnapt.iblk2.mcast = 1;
++	else
++		entry.ipv4_hnapt.iblk2.mcast = 0;
++
++	entry.ipv4_hnapt.iblk2.dp = gmac;
++	entry.ipv4_hnapt.iblk2.port_mg = 0x3f;
++	entry.ipv4_hnapt.iblk2.port_ag = (skb->mark >> 3) & 0x1f;
++	if (IS_LAN(dev))
++		entry.ipv4_hnapt.iblk2.port_ag += 32;
++	entry.bfib1.time_stamp = readl((host->fe_base + 0x0010)) & (0xFFFF);
++	entry.ipv4_hnapt.bfib1.ttl = 1;
++	entry.ipv4_hnapt.bfib1.cah = 1;
++	entry.ipv4_hnapt.bfib1.ka = 1;
++	entry.bfib1.state = BIND;
++
++	entry.ipv4_hnapt.sip = foe->ipv4_hnapt.sip;
++	entry.ipv4_hnapt.dip = foe->ipv4_hnapt.dip;
++	entry.ipv4_hnapt.sport = foe->ipv4_hnapt.sport;
++	entry.ipv4_hnapt.dport = foe->ipv4_hnapt.dport;
++
++	memcpy(foe, &entry, sizeof(entry));
++
++	return 0;
++}
++
++static unsigned int mtk_hnat_nf_post_routing(struct sk_buff *skb,
++					     const struct net_device *out,
++					     unsigned int (*fn)(struct sk_buff *, const struct net_device *),
++					     const char *func)
++{
++	struct foe_entry *entry;
++	struct nf_conn *ct;
++	enum ip_conntrack_info ctinfo;
++	const struct nf_conn_help *help;
++
++	if ((skb->mark & 0x7) < 4)
++		return 0;
++
++	ct = nf_ct_get(skb, &ctinfo);
++	if (!ct)
++		return 0;
++
++	/* rcu_read_lock()ed by nf_hook_slow */
++	help = nfct_help(ct);
++	if (help && rcu_dereference(help->helper))
++		return 0;
++
++	if ((FROM_GE_WAN(skb) || FROM_GE_LAN(skb)) &&
++	    skb_hnat_is_hashed(skb) &&
++	    (skb_hnat_reason(skb) == HIT_BIND_KEEPALIVE_DUP_OLD_HDR))
++		return -1;
++
++	if ((IS_LAN(out) && FROM_GE_WAN(skb)) ||
++	    (IS_WAN(out) && FROM_GE_LAN(skb))) {
++		if (!skb_hnat_is_hashed(skb))
++			return 0;
++
++		entry = &host->foe_table_cpu[skb_hnat_entry(skb)];
++		if (entry_hnat_is_bound(entry))
++			return 0;
++
++		if (skb_hnat_reason(skb) == HIT_UNBIND_RATE_REACH &&
++		    skb_hnat_alg(skb) == 0) {
++			if (fn && fn(skb, out))
++				return 0;
++			skb_to_hnat_info(skb, out, entry);
++		}
++	}
++
++	return 0;
++}
++
++static unsigned int mtk_hnat_nf_pre_routing(void *priv,
++					    struct sk_buff *skb,
++					    const struct nf_hook_state *state)
++{
++	if (IS_WAN(state->in))
++		HNAT_SKB_CB(skb)->iif = FOE_MAGIC_GE_WAN;
++	else if (IS_LAN(state->in))
++		HNAT_SKB_CB(skb)->iif = FOE_MAGIC_GE_LAN;
++	else if (!IS_BR(state->in))
++		HNAT_SKB_CB(skb)->iif = FOE_INVALID;
++
++	return NF_ACCEPT;
++}
++
++static unsigned int hnat_get_nexthop(struct sk_buff *skb, const struct net_device *out) {
++
++	u32 nexthop;
++	struct neighbour *neigh;
++	struct dst_entry *dst = skb_dst(skb);
++	struct rtable *rt = (struct rtable *)dst;
++	struct net_device *dev = (__force struct net_device *)out;
++
++	rcu_read_lock_bh();
++	nexthop = (__force u32) rt_nexthop(rt, ip_hdr(skb)->daddr);
++	neigh = __ipv4_neigh_lookup_noref(dev, nexthop);
++	if (unlikely(!neigh)) {
++		dev_err(host->dev, "%s:++ no neigh\n", __func__);
++		return -1;
++	}
++
++	/* why do we get all zero ethernet address ? */
++	if (!is_valid_ether_addr(neigh->ha)){
++		rcu_read_unlock_bh();
++		return -1;
++	}
++
++	memcpy(eth_hdr(skb)->h_dest, neigh->ha, ETH_ALEN);
++	memcpy(eth_hdr(skb)->h_source, out->dev_addr, ETH_ALEN);
++
++	rcu_read_unlock_bh();
++
++	return 0;
++}
++
++static unsigned int mtk_hnat_ipv4_nf_post_routing(void *priv,
++						 struct sk_buff *skb,
++						 const struct nf_hook_state *state)
++{
++	if (!mtk_hnat_nf_post_routing(skb, state->out, hnat_get_nexthop, __func__))
++		return NF_ACCEPT;
++
++	return NF_DROP;
++}
++
++static unsigned int mtk_hnat_br_nf_post_routing(void *priv,
++						 struct sk_buff *skb,
++						 const struct nf_hook_state *state)
++{
++	if (!mtk_hnat_nf_post_routing(skb, state->out , 0, __func__))
++		return NF_ACCEPT;
++
++	return NF_DROP;
++}
++
++static struct nf_hook_ops mtk_hnat_nf_ops[] __read_mostly = {
++	{
++		.hook = mtk_hnat_nf_pre_routing,
++		.pf = NFPROTO_IPV4,
++		.hooknum = NF_INET_PRE_ROUTING,
++		.priority = NF_IP_PRI_FIRST,
++	}, {
++		.hook = mtk_hnat_ipv4_nf_post_routing,
++		.pf = NFPROTO_IPV4,
++		.hooknum = NF_INET_POST_ROUTING,
++		.priority = NF_IP_PRI_LAST,
++	}, {
++		.hook = mtk_hnat_nf_pre_routing,
++		.pf = NFPROTO_BRIDGE,
++		.hooknum = NF_BR_PRE_ROUTING,
++		.priority = NF_BR_PRI_FIRST,
++	}, {
++		.hook = mtk_hnat_br_nf_post_routing,
++		.pf = NFPROTO_BRIDGE,
++		.hooknum = NF_BR_POST_ROUTING,
++		.priority = NF_BR_PRI_LAST - 1,
++	},
++};
++
++int hnat_register_nf_hooks(void)
++{
++	return nf_register_hooks(mtk_hnat_nf_ops,
++				 ARRAY_SIZE(mtk_hnat_nf_ops));
++}
++
++void hnat_unregister_nf_hooks(void)
++{
++	nf_unregister_hooks(mtk_hnat_nf_ops,
++			    ARRAY_SIZE(mtk_hnat_nf_ops));
++}
+--- /dev/null
++++ b/drivers/net/ethernet/mediatek/mtk_hnat/nf_hnat_mtk.h
+@@ -0,0 +1,44 @@
++/*   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) 2014-2016 Sean Wang <[email protected]>
++ *   Copyright (C) 2016-2017 John Crispin <[email protected]>
++ */
++
++#ifndef NF_HNAT_MTK_H
++#define NF_HNAT_MTK_H
++
++#include <asm/dma-mapping.h>
++#include <linux/netdevice.h>
++
++#define HNAT_SKB_CB2(__skb)		((struct hnat_skb_cb2 *)&((__skb)->cb[44]))
++struct hnat_skb_cb2 {
++	__u32  magic;
++};
++
++struct hnat_desc {
++	u32 entry:14;
++	u32 crsn:5;
++	u32 sport:4;
++	u32 alg:9;
++} __attribute__ ((packed));
++
++#define skb_hnat_magic(skb)  (((struct hnat_desc *)(skb->head))->magic)
++#define skb_hnat_reason(skb) (((struct hnat_desc *)(skb->head))->crsn)
++#define skb_hnat_entry(skb)  (((struct hnat_desc *)(skb->head))->entry)
++#define skb_hnat_sport(skb)  (((struct hnat_desc *)(skb->head))->sport)
++#define skb_hnat_alg(skb)  (((struct hnat_desc *)(skb->head))->alg)
++
++u32 hnat_tx(struct sk_buff *skb);
++u32 hnat_set_skb_info(struct sk_buff *skb, u32 *rxd);
++u32 hnat_reg(struct net_device *, void __iomem *);
++u32 hnat_unreg(void);
++
++#endif
++

+ 9 - 9
target/linux/mediatek/patches-4.9/0091-net-next-mediatek-fix-DQL-support.patch → target/linux/mediatek/patches-4.9/0027-net-next-mediatek-fix-DQL-support.patch

@@ -1,7 +1,7 @@
-From 81cdbda2a08375b9d5915567d2210bf2433e7332 Mon Sep 17 00:00:00 2001
+From f974e397b806f7b16d11cc1542538616291924f1 Mon Sep 17 00:00:00 2001
 From: John Crispin <[email protected]>
 From: John Crispin <[email protected]>
 Date: Sat, 23 Apr 2016 11:57:21 +0200
 Date: Sat, 23 Apr 2016 11:57:21 +0200
-Subject: [PATCH 081/102] net-next: mediatek: fix DQL support
+Subject: [PATCH 27/57] net-next: mediatek: fix DQL support
 
 
 The MTK ethernet core has 2 MACs both sitting on the same DMA ring. The
 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
 current code will assign the TX traffic of each MAC to its own DQL. This
@@ -13,12 +13,12 @@ using the DMA.
 
 
 Signed-off-by: John Crispin <[email protected]>
 Signed-off-by: John Crispin <[email protected]>
 ---
 ---
- drivers/net/ethernet/mediatek/mtk_eth_soc.c |   33 ++++++++++++++++-----------
- 1 file changed, 20 insertions(+), 13 deletions(-)
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 35 +++++++++++++++++------------
+ 1 file changed, 21 insertions(+), 14 deletions(-)
 
 
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -706,7 +706,16 @@ static int mtk_tx_map(struct sk_buff *sk
+@@ -710,7 +710,16 @@ static int mtk_tx_map(struct sk_buff *sk
  	WRITE_ONCE(itxd->txd3, (TX_DMA_SWC | TX_DMA_PLEN0(skb_headlen(skb)) |
  	WRITE_ONCE(itxd->txd3, (TX_DMA_SWC | TX_DMA_PLEN0(skb_headlen(skb)) |
  				(!nr_frags * TX_DMA_LS0)));
  				(!nr_frags * TX_DMA_LS0)));
  
  
@@ -36,7 +36,7 @@ Signed-off-by: John Crispin <[email protected]>
  	skb_tx_timestamp(skb);
  	skb_tx_timestamp(skb);
  
  
  	ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2);
  	ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2);
-@@ -998,21 +1007,18 @@ static int mtk_poll_tx(struct mtk_eth *e
+@@ -1002,21 +1011,18 @@ static int mtk_poll_tx(struct mtk_eth *e
  	struct mtk_tx_dma *desc;
  	struct mtk_tx_dma *desc;
  	struct sk_buff *skb;
  	struct sk_buff *skb;
  	struct mtk_tx_buf *tx_buf;
  	struct mtk_tx_buf *tx_buf;
@@ -60,9 +60,9 @@ Signed-off-by: John Crispin <[email protected]>
 -	while ((cpu != dma) && budget) {
 -	while ((cpu != dma) && budget) {
 +	while ((cpu != dma) && done < budget) {
 +	while ((cpu != dma) && done < budget) {
  		u32 next_cpu = desc->txd2;
  		u32 next_cpu = desc->txd2;
- 		int mac;
+ 		int mac = 0;
  
  
-@@ -1032,9 +1038,8 @@ static int mtk_poll_tx(struct mtk_eth *e
+@@ -1035,9 +1041,8 @@ static int mtk_poll_tx(struct mtk_eth *e
  		}
  		}
  
  
  		if (skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC) {
  		if (skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC) {
@@ -74,7 +74,7 @@ Signed-off-by: John Crispin <[email protected]>
  		}
  		}
  		mtk_tx_unmap(eth, tx_buf);
  		mtk_tx_unmap(eth, tx_buf);
  
  
-@@ -1046,11 +1051,13 @@ static int mtk_poll_tx(struct mtk_eth *e
+@@ -1049,11 +1054,13 @@ static int mtk_poll_tx(struct mtk_eth *e
  
  
  	mtk_w32(eth, cpu, MTK_QTX_CRX_PTR);
  	mtk_w32(eth, cpu, MTK_QTX_CRX_PTR);
  
  

+ 3 - 17
target/linux/mediatek/patches-4.9/0092-dsa2.patch → target/linux/mediatek/patches-4.9/0028-net-next-dsa-add-Mediatek-tag-RX-TX-handler.patch

@@ -1,21 +1,7 @@
-From patchwork Wed Mar 29 09:38:20 2017
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [net-next,v3,2/5] net-next: dsa: add Mediatek tag RX/TX handler
-From: [email protected]
-X-Patchwork-Id: 9651099
-Message-Id: <[email protected]>
-To: <[email protected]>, <[email protected]>,
- <[email protected]>, <[email protected]>,
- <[email protected]>, <[email protected]>
-Cc: [email protected], [email protected], [email protected], 
- [email protected], [email protected],
- [email protected], 
- [email protected], [email protected], [email protected]
-Date: Wed, 29 Mar 2017 17:38:20 +0800
-
+From 5c01c03920c63630864d2b8641924a8c7c6cb62f Mon Sep 17 00:00:00 2001
 From: Sean Wang <[email protected]>
 From: Sean Wang <[email protected]>
+Date: Wed, 29 Mar 2017 17:38:20 +0800
+Subject: [PATCH 28/57] net-next: dsa: add Mediatek tag RX/TX handler
 
 
 Add the support for the 4-bytes tag for DSA port distinguishing inserted
 Add the support for the 4-bytes tag for DSA port distinguishing inserted
 allowing receiving and transmitting the packet via the particular port.
 allowing receiving and transmitting the packet via the particular port.

+ 10 - 25
target/linux/mediatek/patches-4.9/0092-dsa3.patch → target/linux/mediatek/patches-4.9/0029-net-next-ethernet-mediatek-add-CDM-able-to-recognize.patch

@@ -1,23 +1,8 @@
-From patchwork Wed Mar 29 09:38:21 2017
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [net-next, v3,
- 3/5] net-next: ethernet: mediatek: add CDM able to recognize the tag
- for DSA
-From: [email protected]
-X-Patchwork-Id: 9651091
-Message-Id: <[email protected]>
-To: <[email protected]>, <[email protected]>,
- <[email protected]>, <[email protected]>,
- <[email protected]>, <[email protected]>
-Cc: [email protected], [email protected], [email protected], 
- [email protected], [email protected],
- [email protected], 
- [email protected], [email protected], [email protected]
-Date: Wed, 29 Mar 2017 17:38:21 +0800
-
+From de3c04b820e1d396bf12e88ea87271a84f6fedb7 Mon Sep 17 00:00:00 2001
 From: Sean Wang <[email protected]>
 From: Sean Wang <[email protected]>
+Date: Wed, 29 Mar 2017 17:38:21 +0800
+Subject: [PATCH 29/57] net-next: ethernet: mediatek: add CDM able to recognize
+ the tag for DSA
 
 
 The patch adds the setup for allowing CDM can recognize these packets with
 The patch adds the setup for allowing CDM can recognize these packets with
 carrying port-distinguishing tag. Otherwise, these tagging packets will be
 carrying port-distinguishing tag. Otherwise, these tagging packets will be
@@ -35,9 +20,9 @@ Reviewed-by: Florian Fainelli <[email protected]>
 
 
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -1855,6 +1855,12 @@ static int mtk_hw_init(struct mtk_eth *e
- 	/* GE2, Force 1000M/FD, FC ON */
- 	mtk_w32(eth, MAC_MCR_FIXED_LINK, MTK_MAC_MCR(1));
+@@ -1864,6 +1864,12 @@ static int mtk_hw_init(struct mtk_eth *e
+ 	val = mtk_r32(eth, MTK_CDMQ_IG_CTRL);
+ 	mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL);
  
  
 +	/* Indicates CDM to parse the MTK special tag from CPU
 +	/* Indicates CDM to parse the MTK special tag from CPU
 +	 * which also is working out for untag packets.
 +	 * which also is working out for untag packets.
@@ -50,9 +35,9 @@ Reviewed-by: Florian Fainelli <[email protected]>
  
  
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -70,6 +70,10 @@
- /* Frame Engine Interrupt Grouping Register */
- #define MTK_FE_INT_GRP		0x20
+@@ -74,6 +74,10 @@
+ #define MTK_CDMQ_IG_CTRL	0x1400
+ #define MTK_CDMQ_STAG_EN	BIT(0)
  
  
 +/* CDMP Ingress Control Register */
 +/* CDMP Ingress Control Register */
 +#define MTK_CDMQ_IG_CTRL	0x1400
 +#define MTK_CDMQ_IG_CTRL	0x1400

+ 4 - 18
target/linux/mediatek/patches-4.9/0092-dsa5.patch → target/linux/mediatek/patches-4.9/0030-net-next-dsa-add-dsa-support-for-Mediatek-MT7530-swi.patch

@@ -1,22 +1,8 @@
-From patchwork Wed Mar 29 09:38:23 2017
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [net-next, v3,
- 5/5] net-next: dsa: add dsa support for Mediatek MT7530 switch
-From: [email protected]
-X-Patchwork-Id: 9651095
-Message-Id: <[email protected]>
-To: <[email protected]>, <[email protected]>,
- <[email protected]>, <[email protected]>,
- <[email protected]>, <[email protected]>
-Cc: [email protected], [email protected], [email protected], 
- [email protected], [email protected],
- [email protected], 
- [email protected], [email protected], [email protected]
-Date: Wed, 29 Mar 2017 17:38:23 +0800
-
+From 6a0a62dec3c582db4260f411294770448efc3d6c Mon Sep 17 00:00:00 2001
 From: Sean Wang <[email protected]>
 From: Sean Wang <[email protected]>
+Date: Wed, 29 Mar 2017 17:38:23 +0800
+Subject: [PATCH 30/57] net-next: dsa: add dsa support for Mediatek MT7530
+ switch
 
 
 MT7530 is a 7-ports Gigabit Ethernet Switch that could be found on
 MT7530 is a 7-ports Gigabit Ethernet Switch that could be found on
 Mediatek router platforms such as MT7623A or MT7623N platform which
 Mediatek router platforms such as MT7623A or MT7623N platform which

+ 14 - 0
target/linux/mediatek/patches-4.9/0093-dsa-compat.patch → target/linux/mediatek/patches-4.9/0031-net-dsa-dsa-api-compat.patch

@@ -1,3 +1,17 @@
+From a319687ac18dcc557a88054282508e061ad8495f Mon Sep 17 00:00:00 2001
+From: John Crispin <[email protected]>
+Date: Thu, 10 Aug 2017 14:42:19 +0200
+Subject: [PATCH 31/57] net: dsa: dsa api compat
+
+make the latest driver work on the old API
+
+Signed-off-by: John Crispin <[email protected]>
+---
+ drivers/net/dsa/mt7530.c | 14 ++++++++------
+ drivers/net/dsa/mt7530.h |  2 ++
+ net/dsa/tag_mtk.c        |  2 +-
+ 3 files changed, 11 insertions(+), 7 deletions(-)
+
 --- a/drivers/net/dsa/mt7530.c
 --- a/drivers/net/dsa/mt7530.c
 +++ b/drivers/net/dsa/mt7530.c
 +++ b/drivers/net/dsa/mt7530.c
 @@ -834,6 +834,7 @@ mt7530_port_bridge_join(struct dsa_switc
 @@ -834,6 +834,7 @@ mt7530_port_bridge_join(struct dsa_switc

+ 12 - 0
target/linux/mediatek/patches-4.9/0095-ephy.patch → target/linux/mediatek/patches-4.9/0032-net-dsa-mediatek-add-support-for-GMAC2-wired-to-ext-.patch

@@ -1,3 +1,15 @@
+From 52e9ce30a2b3c414e0efb20632fefa7cfc5096e6 Mon Sep 17 00:00:00 2001
+From: John Crispin <[email protected]>
+Date: Thu, 10 Aug 2017 14:44:18 +0200
+Subject: [PATCH 32/57] net: dsa: mediatek: add support for GMAC2 wired to ext
+ phy
+
+Signed-off-by: John Crispin <[email protected]>
+---
+ drivers/net/dsa/mt7530.c                    | 5 +++++
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 3 +++
+ 2 files changed, 8 insertions(+)
+
 --- a/drivers/net/dsa/mt7530.c
 --- a/drivers/net/dsa/mt7530.c
 +++ b/drivers/net/dsa/mt7530.c
 +++ b/drivers/net/dsa/mt7530.c
 @@ -629,6 +629,11 @@ mt7530_setup(struct dsa_switch *ds)
 @@ -629,6 +629,11 @@ mt7530_setup(struct dsa_switch *ds)

+ 14 - 0
target/linux/mediatek/patches-4.9/0096-dsa-multi-cpu.patch → target/linux/mediatek/patches-4.9/0033-net-dsa-add-multi-gmac-support.patch

@@ -1,3 +1,17 @@
+From cce5dd6034ed1651ee25c910edee708e6b84a44a Mon Sep 17 00:00:00 2001
+From: John Crispin <[email protected]>
+Date: Thu, 10 Aug 2017 14:45:08 +0200
+Subject: [PATCH 33/57] net: dsa: add multi gmac support
+
+Signed-off-by: John Crispin <[email protected]>
+---
+ drivers/net/dsa/mt7530.c | 10 +---------
+ include/net/dsa.h        | 21 ++++++++++++++++++++-
+ net/dsa/dsa2.c           | 40 +++++++++++++++++++++++++++++++++-------
+ net/dsa/dsa_priv.h       |  1 +
+ net/dsa/slave.c          | 26 ++++++++++++++++----------
+ 5 files changed, 71 insertions(+), 27 deletions(-)
+
 --- a/drivers/net/dsa/mt7530.c
 --- a/drivers/net/dsa/mt7530.c
 +++ b/drivers/net/dsa/mt7530.c
 +++ b/drivers/net/dsa/mt7530.c
 @@ -996,15 +996,7 @@ err:
 @@ -996,15 +996,7 @@ err:

+ 10 - 0
target/linux/mediatek/patches-4.9/0097-dsa-mt7530.patch → target/linux/mediatek/patches-4.9/0034-net-dsa-mediatek-add-dual-gmac-support.patch

@@ -1,3 +1,13 @@
+From dcb751a52b2ee69c16db2fef8f92a96ab13b6bb4 Mon Sep 17 00:00:00 2001
+From: John Crispin <[email protected]>
+Date: Thu, 10 Aug 2017 14:45:34 +0200
+Subject: [PATCH 34/57] net: dsa: mediatek: add dual gmac support
+
+Signed-off-by: John Crispin <[email protected]>
+---
+ drivers/net/dsa/mt7530.c | 22 ++++++++++++++++------
+ 1 file changed, 16 insertions(+), 6 deletions(-)
+
 --- a/drivers/net/dsa/mt7530.c
 --- a/drivers/net/dsa/mt7530.c
 +++ b/drivers/net/dsa/mt7530.c
 +++ b/drivers/net/dsa/mt7530.c
 @@ -627,7 +627,7 @@ mt7530_setup(struct dsa_switch *ds)
 @@ -627,7 +627,7 @@ mt7530_setup(struct dsa_switch *ds)

+ 47 - 0
target/linux/mediatek/patches-4.9/0035-net-mediatek-disable-RX-VLan-offloading.patch

@@ -0,0 +1,47 @@
+From 35b83b85e752a6660b92f08c0fb912308f25cf6d Mon Sep 17 00:00:00 2001
+From: John Crispin <[email protected]>
+Date: Thu, 10 Aug 2017 15:56:40 +0200
+Subject: [PATCH 35/57] net: mediatek: disable RX VLan offloading
+
+Signed-off-by: John Crispin <[email protected]>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 9 ++++++---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h | 2 --
+ 2 files changed, 6 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -643,8 +643,8 @@ static int mtk_tx_map(struct sk_buff *sk
+ 		txd4 |= TX_DMA_CHKSUM;
+ 
+ 	/* VLAN header offload */
+-	if (skb_vlan_tag_present(skb))
+-		txd4 |= TX_DMA_INS_VLAN | skb_vlan_tag_get(skb);
++//	if (skb_vlan_tag_present(skb))
++//		txd4 |= TX_DMA_INS_VLAN | skb_vlan_tag_get(skb);
+ 
+ 	mapped_addr = dma_map_single(eth->dev, skb->data,
+ 				     skb_headlen(skb), DMA_TO_DEVICE);
+@@ -1874,7 +1874,10 @@ static int mtk_hw_init(struct mtk_eth *e
+ 	mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL);
+ 
+ 	/* Enable RX VLan Offloading */
+-	mtk_w32(eth, 1, MTK_CDMP_EG_CTRL);
++	if (MTK_HW_FEATURES & NETIF_F_HW_VLAN_CTAG_RX)
++		mtk_w32(eth, 1, MTK_CDMP_EG_CTRL);
++	else
++		mtk_w32(eth, 0, MTK_CDMP_EG_CTRL);
+ 
+ 	/* disable delay and normal interrupt */
+ 	mtk_w32(eth, 0, MTK_QDMA_DELAY_INT);
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -34,8 +34,6 @@
+ 				 NETIF_MSG_TX_ERR)
+ #define MTK_HW_FEATURES		(NETIF_F_IP_CSUM | \
+ 				 NETIF_F_RXCSUM | \
+-				 NETIF_F_HW_VLAN_CTAG_TX | \
+-				 NETIF_F_HW_VLAN_CTAG_RX | \
+ 				 NETIF_F_SG | NETIF_F_TSO | \
+ 				 NETIF_F_TSO6 | \
+ 				 NETIF_F_IPV6_CSUM)

+ 25 - 0
target/linux/mediatek/patches-4.9/0036-net-next-mediatek-fix-typos-inside-the-header-file.patch

@@ -0,0 +1,25 @@
+From bf25fbdc7dfb256f267725336e29e232aadd5123 Mon Sep 17 00:00:00 2001
+From: John Crispin <[email protected]>
+Date: Fri, 21 Jul 2017 08:43:58 +0200
+Subject: [PATCH 36/57] net-next: mediatek: fix typos inside the header file
+
+Trivial patch fixing 2 typos.
+
+Signed-off-by: John Crispin <[email protected]>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -525,8 +525,8 @@ struct mtk_rx_ring {
+  * @pctl:		The register map pointing at the range used to setup
+  *			GMAC port drive/slew values
+  * @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
++ * @tx_ring:		Pointer to the memory holding info about the TX ring
++ * @rx_ring:		Pointer to the memory holding info about the RX ring
+  * @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

+ 128 - 0
target/linux/mediatek/patches-4.9/0037-net-next-mediatek-bring-up-QDMA-RX-ring-0.patch

@@ -0,0 +1,128 @@
+From 047a4e7b17322c1b32d8db32a0df9899cb4963a3 Mon Sep 17 00:00:00 2001
+From: John Crispin <[email protected]>
+Date: Fri, 21 Jul 2017 08:48:38 +0200
+Subject: [PATCH 37/57] net-next: mediatek: bring up QDMA RX ring 0
+
+This patch is in peparation for adding HW flow and QoS offloading. For
+those features to work, the driver needs to bring up the first QDMA RX
+ring. This ring is used by the PPE offloading HW.
+
+Signed-off-by: John Crispin <[email protected]>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 38 ++++++++++++++++++++---------
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h |  3 +++
+ 2 files changed, 30 insertions(+), 11 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -1224,11 +1224,21 @@ static void mtk_tx_clean(struct mtk_eth
+ 
+ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag)
+ {
+-	struct mtk_rx_ring *ring = &eth->rx_ring[ring_no];
++	struct mtk_rx_ring *ring;
+ 	int rx_data_len, rx_dma_size;
+ 	int i;
++	u32 offset = 0;
+ 
+-	if (rx_flag == MTK_RX_FLAGS_HWLRO) {
++	if (rx_flag & MTK_RX_FLAGS_QDMA) {
++		if (ring_no)
++			return -EINVAL;
++		ring = &eth->rx_ring_qdma;
++		offset = 0x1000;
++	} else {
++		ring = &eth->rx_ring[ring_no];
++	}
++
++	if (rx_flag & MTK_RX_FLAGS_HWLRO) {
+ 		rx_data_len = MTK_MAX_LRO_RX_LENGTH;
+ 		rx_dma_size = MTK_HW_LRO_DMA_SIZE;
+ 	} else {
+@@ -1276,17 +1286,16 @@ static int mtk_rx_alloc(struct mtk_eth *
+ 	 */
+ 	wmb();
+ 
+-	mtk_w32(eth, ring->phys, MTK_PRX_BASE_PTR_CFG(ring_no));
+-	mtk_w32(eth, rx_dma_size, MTK_PRX_MAX_CNT_CFG(ring_no));
+-	mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg);
+-	mtk_w32(eth, MTK_PST_DRX_IDX_CFG(ring_no), MTK_PDMA_RST_IDX);
++	mtk_w32(eth, ring->phys, MTK_PRX_BASE_PTR_CFG(ring_no) + offset);
++	mtk_w32(eth, rx_dma_size, MTK_PRX_MAX_CNT_CFG(ring_no) + offset);
++	mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg + offset);
++	mtk_w32(eth, MTK_PST_DRX_IDX_CFG(ring_no), MTK_PDMA_RST_IDX + offset);
+ 
+ 	return 0;
+ }
+ 
+-static void mtk_rx_clean(struct mtk_eth *eth, int ring_no)
++static void mtk_rx_clean(struct mtk_eth *eth, struct mtk_rx_ring *ring)
+ {
+-	struct mtk_rx_ring *ring = &eth->rx_ring[ring_no];
+ 	int i;
+ 
+ 	if (ring->data && ring->dma) {
+@@ -1612,6 +1621,10 @@ static int mtk_dma_init(struct mtk_eth *
+ 	if (err)
+ 		return err;
+ 
++	err = mtk_rx_alloc(eth, 0, MTK_RX_FLAGS_QDMA);
++	if (err)
++		return err;
++
+ 	err = mtk_rx_alloc(eth, 0, MTK_RX_FLAGS_NORMAL);
+ 	if (err)
+ 		return err;
+@@ -1651,12 +1664,13 @@ static void mtk_dma_free(struct mtk_eth
+ 		eth->phy_scratch_ring = 0;
+ 	}
+ 	mtk_tx_clean(eth);
+-	mtk_rx_clean(eth, 0);
++	mtk_rx_clean(eth, &eth->rx_ring[0]);
++	mtk_rx_clean(eth, &eth->rx_ring_qdma);
+ 
+ 	if (eth->hwlro) {
+ 		mtk_hwlro_rx_uninit(eth);
+ 		for (i = 1; i < MTK_MAX_RX_RING_NUM; i++)
+-			mtk_rx_clean(eth, i);
++			mtk_rx_clean(eth, &eth->rx_ring[i]);
+ 	}
+ 
+ 	kfree(eth->scratch_head);
+@@ -1723,7 +1737,9 @@ static int mtk_start_dma(struct mtk_eth
+ 
+ 	mtk_w32(eth,
+ 		MTK_TX_WB_DDONE | MTK_TX_DMA_EN |
+-		MTK_DMA_SIZE_16DWORDS | MTK_NDP_CO_PRO,
++		MTK_DMA_SIZE_16DWORDS | MTK_NDP_CO_PRO |
++		MTK_RX_DMA_EN | MTK_RX_2B_OFFSET |
++		MTK_RX_BT_32DWORDS,
+ 		MTK_QDMA_GLO_CFG);
+ 
+ 	mtk_w32(eth,
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -484,6 +484,7 @@ struct mtk_tx_ring {
+ enum mtk_rx_flags {
+ 	MTK_RX_FLAGS_NORMAL = 0,
+ 	MTK_RX_FLAGS_HWLRO,
++	MTK_RX_FLAGS_QDMA,
+ };
+ 
+ /* struct mtk_rx_ring -	This struct holds info describing a RX ring
+@@ -527,6 +528,7 @@ struct mtk_rx_ring {
+  * @dma_refcnt:		track how many netdevs are using the DMA engine
+  * @tx_ring:		Pointer to the memory holding info about the TX ring
+  * @rx_ring:		Pointer to the memory holding info about the RX ring
++ * @rx_ring_qdma:	Pointer to the memory holding info about the QDMA RX ring
+  * @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
+@@ -556,6 +558,7 @@ struct mtk_eth {
+ 	atomic_t			dma_refcnt;
+ 	struct mtk_tx_ring		tx_ring;
+ 	struct mtk_rx_ring		rx_ring[MTK_MAX_RX_RING_NUM];
++	struct mtk_rx_ring		rx_ring_qdma;
+ 	struct napi_struct		tx_napi;
+ 	struct napi_struct		rx_napi;
+ 	struct mtk_tx_dma		*scratch_ring;

+ 46 - 0
target/linux/mediatek/patches-4.9/0038-net-next-dsa-move-struct-dsa_device_ops-to-the-globa.patch

@@ -0,0 +1,46 @@
+From b58bf0220f666705e63fe8d361f37c913aee2d8f Mon Sep 17 00:00:00 2001
+From: John Crispin <[email protected]>
+Date: Fri, 21 Jul 2017 09:32:54 +0200
+Subject: [PATCH 38/57] net-next: dsa: move struct dsa_device_ops to the global
+ header file
+
+We need to access this struct from within the flow_dissector to fix
+dissection for packets coming in on DSA devices.
+
+Signed-off-by: John Crispin <[email protected]>
+---
+ include/net/dsa.h  | 7 +++++++
+ net/dsa/dsa_priv.h | 6 ------
+ 2 files changed, 7 insertions(+), 6 deletions(-)
+
+--- a/include/net/dsa.h
++++ b/include/net/dsa.h
+@@ -88,6 +88,13 @@ struct dsa_platform_data {
+ 
+ struct packet_type;
+ 
++struct dsa_device_ops {
++	struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev);
++	int sk_buff *(*rcv)(struct sk_buff *skb, struct net_device *dev,
++			       struct packet_type *pt,
++			       struct net_device *orig_dev);
++};
++
+ struct dsa_switch_tree {
+ 	struct list_head	list;
+ 
+--- a/net/dsa/dsa_priv.h
++++ b/net/dsa/dsa_priv.h
+@@ -15,12 +15,6 @@
+ #include <linux/netdevice.h>
+ #include <linux/netpoll.h>
+ 
+-struct dsa_device_ops {
+-	struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev);
+-	int (*rcv)(struct sk_buff *skb, struct net_device *dev,
+-		   struct packet_type *pt, struct net_device *orig_dev);
+-};
+-
+ struct dsa_slave_priv {
+ 	struct sk_buff *	(*xmit)(struct sk_buff *skb,
+ 					struct net_device *dev);

+ 32 - 0
target/linux/mediatek/patches-4.9/0039-net-next-dsa-add-flow_dissect-callback-to-struct-dsa.patch

@@ -0,0 +1,32 @@
+From 22e8b65ea4bf8a1fa757137bdcbdefe505fa4044 Mon Sep 17 00:00:00 2001
+From: John Crispin <[email protected]>
+Date: Mon, 7 Aug 2017 16:35:43 +0200
+Subject: [PATCH 39/57] net-next: dsa: add flow_dissect callback to struct
+ dsa_device_ops
+
+When the flow dissector first sees packets coming in on a DSA devices the
+802.3 header wont be located where the code expects it to be as the tag
+is still present. Adding this new callback allows a DSA device to provide a
+new function that the flow_disscetor can use to get the correct offsets
+for the protocol field and network header offset.
+
+Signed-off-by: John Crispin <[email protected]>
+---
+ include/net/dsa.h | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/include/net/dsa.h
++++ b/include/net/dsa.h
+@@ -90,9 +90,11 @@ struct packet_type;
+ 
+ struct dsa_device_ops {
+ 	struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev);
+-	int sk_buff *(*rcv)(struct sk_buff *skb, struct net_device *dev,
++	int (*rcv)(struct sk_buff *skb, struct net_device *dev,
+ 			       struct packet_type *pt,
+ 			       struct net_device *orig_dev);
++	int (*flow_dissect)(const struct sk_buff *skb, __be16 *proto,
++			    int *offset);
+ };
+ 
+ struct dsa_switch_tree {

+ 39 - 0
target/linux/mediatek/patches-4.9/0040-net-next-tag_mtk-add-flow_dissect-callback-to-the-op.patch

@@ -0,0 +1,39 @@
+From 9d6806e16e5ea68a49225da1ab065ef0b5d7704b Mon Sep 17 00:00:00 2001
+From: John Crispin <[email protected]>
+Date: Mon, 7 Aug 2017 16:55:56 +0200
+Subject: [PATCH 40/57] net-next: tag_mtk: add flow_dissect callback to the ops
+ struct
+
+The MT7530 inserts the 4 magic header in between the 802.3 address and
+protocol field. The patch implements the callback that can be called by
+the flow dissector to figure out the real protocol and offset of the
+network header. With this patch applied we can properly parse the packet
+and thus make hashing function properly.
+
+Signed-off-by: John Crispin <[email protected]>
+---
+ net/dsa/tag_mtk.c | 14 ++++++++++++--
+ 1 file changed, 12 insertions(+), 2 deletions(-)
+
+--- a/net/dsa/tag_mtk.c
++++ b/net/dsa/tag_mtk.c
+@@ -111,7 +111,17 @@ out:
+ 	return 0;
+ }
+ 
++static int mtk_tag_flow_dissect(const struct sk_buff *skb, __be16 *proto,
++				int *offset)
++{
++	*offset = 4;
++	*proto = ((__be16 *)skb->data)[1];
++
++	return 0;
++}
++
+ const struct dsa_device_ops mtk_netdev_ops = {
+-	.xmit	= mtk_tag_xmit,
+-	.rcv	= mtk_tag_rcv,
++	.xmit		= mtk_tag_xmit,
++	.rcv		= mtk_tag_rcv,
++	.flow_dissect	= mtk_tag_flow_dissect,
+ };

+ 65 - 0
target/linux/mediatek/patches-4.9/0041-net-next-dsa-fix-flow-dissection.patch

@@ -0,0 +1,65 @@
+From 04c825484d6ecdcc8ce09b350235c9077eaca6e3 Mon Sep 17 00:00:00 2001
+From: John Crispin <[email protected]>
+Date: Wed, 9 Aug 2017 08:20:21 +0200
+Subject: [PATCH 41/57] net-next: dsa: fix flow dissection
+
+RPS and probably other kernel features are currently broken on some if not
+all DSA devices. The root cause of this is that skb_hash will call the
+flow_dissector. At this point the skb still contains the magic switch
+header and the skb->protocol field is not set up to the correct 802.3
+value yet. By the time the tag specific code is called, removing the header
+and =roperly setting the protocol an invalid hash is already set. In the
+case of the mt7530 this will result in all flows always having the same
+hash.
+
+This patch makes the flow dissector honour the nh and protocol offset
+defined by the dsa tag driver thus fixing dissection, hashing and RPS.
+
+Signed-off-by: John Crispin <[email protected]>
+---
+ net/core/flow_dissector.c | 14 +++++++++++++-
+ 1 file changed, 13 insertions(+), 1 deletion(-)
+
+--- a/net/core/flow_dissector.c
++++ b/net/core/flow_dissector.c
+@@ -4,6 +4,7 @@
+ #include <linux/ip.h>
+ #include <linux/ipv6.h>
+ #include <linux/if_vlan.h>
++#include <net/dsa.h>
+ #include <net/ip.h>
+ #include <net/ipv6.h>
+ #include <net/gre.h>
+@@ -123,13 +124,23 @@ bool __skb_flow_dissect(const struct sk_
+ 	bool skip_vlan = false;
+ 	u8 ip_proto = 0;
+ 	bool ret;
+-
+ 	if (!data) {
+ 		data = skb->data;
+ 		proto = skb_vlan_tag_present(skb) ?
+ 			 skb->vlan_proto : skb->protocol;
+ 		nhoff = skb_network_offset(skb);
+ 		hlen = skb_headlen(skb);
++		if (unlikely(netdev_uses_dsa(skb->dev))) {
++			const struct dsa_device_ops *ops;
++			int offset;
++
++			ops = skb->dev->dsa_ptr->tag_ops;
++			if (ops->flow_dissect &&
++			    !ops->flow_dissect(skb, &proto, &offset)) {
++				hlen -= offset;
++				nhoff += offset;
++			}
++		}
+ 	}
+ 
+ 	/* It is ensured by skb_flow_dissector_init() that control key will
+@@ -162,6 +173,7 @@ again:
+ 	case htons(ETH_P_IP): {
+ 		const struct iphdr *iph;
+ 		struct iphdr _iph;
++
+ ip:
+ 		iph = __skb_header_pointer(skb, nhoff, sizeof(_iph), data, hlen, &_iph);
+ 		if (!iph || iph->ihl < 5)

+ 50 - 0
target/linux/mediatek/patches-4.9/0042-net-next-mediatek-honour-special-tag-bit-inside-RX-D.patch

@@ -0,0 +1,50 @@
+From a306af3b97c56b9e224a2f9ee04838a2d32ff60b Mon Sep 17 00:00:00 2001
+From: John Crispin <[email protected]>
+Date: Wed, 9 Aug 2017 14:44:07 +0200
+Subject: [PATCH 42/57] net-next: mediatek: honour special tag bit inside RX
+ DMA descriptor
+
+For HW NAT/QoS to work the DSA driver needs to turn the special tag bit
+inside the ingress control register on. This has the side effect that
+the code working out which ingress gmac we have breaks. Fix this by
+honouring the special tag bit inside the RX free descriptor.
+
+Signed-off-by: John Crispin <[email protected]>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 14 ++++++++++----
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h |  1 +
+ 2 files changed, 11 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -933,10 +933,16 @@ static int mtk_poll_rx(struct napi_struc
+ 		if (!(trxd.rxd2 & RX_DMA_DONE))
+ 			break;
+ 
+-		/* find out which mac the packet come from. values start at 1 */
+-		mac = (trxd.rxd4 >> RX_DMA_FPORT_SHIFT) &
+-		      RX_DMA_FPORT_MASK;
+-		mac--;
++		/* find out which mac the packet comes from. If the special tag is
++		 * we can assume that the traffic is coming from the builtin mt7530
++		 * and the DSA driver has loaded. FPORT will be the physical switch
++		 * port in this case rather than the FE forward port id. */
++		if (!(trxd.rxd4 & RX_DMA_SP_TAG)) {
++			/* values start at 1 */
++			mac = (trxd.rxd4 >> RX_DMA_FPORT_SHIFT) &
++			      RX_DMA_FPORT_MASK;
++			mac--;
++		}
+ 
+ 		netdev = eth->netdev[mac];
+ 
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -284,6 +284,7 @@
+ 
+ /* QDMA descriptor rxd4 */
+ #define RX_DMA_L4_VALID		BIT(24)
++#define RX_DMA_SP_TAG		BIT(22)
+ #define RX_DMA_FPORT_SHIFT	19
+ #define RX_DMA_FPORT_MASK	0x7
+ 

+ 41 - 0
target/linux/mediatek/patches-4.9/0043-net-next-mediatek-enable-special-tag-indication-for-.patch

@@ -0,0 +1,41 @@
+From 53e3d9af39805a7e1ba81a047a9ab433be0e82f5 Mon Sep 17 00:00:00 2001
+From: John Crispin <[email protected]>
+Date: Wed, 9 Aug 2017 14:56:53 +0200
+Subject: [PATCH 43/57] net-next: mediatek: enable special tag indication for
+ PDMA
+
+The Ingress special tag indication was only enabled for QDMA and not PDMA.
+Properly initialize the STAG bit. This broke HW NAT and Qos from working
+for traffic coming in via a DSA device. The PPE failed to properly parse
+the traffic as it was not expecting the special tag.
+
+Signed-off-by: John Crispin <[email protected]>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 ++
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h | 4 ++++
+ 2 files changed, 6 insertions(+)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -1894,6 +1894,8 @@ static int mtk_hw_init(struct mtk_eth *e
+ 	 */
+ 	val = mtk_r32(eth, MTK_CDMQ_IG_CTRL);
+ 	mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL);
++	val = mtk_r32(eth, MTK_CDMP_IG_CTRL);
++	mtk_w32(eth, val | MTK_CDMP_STAG_EN, MTK_CDMP_IG_CTRL);
+ 
+ 	/* Enable RX VLan Offloading */
+ 	if (MTK_HW_FEATURES & NETIF_F_HW_VLAN_CTAG_RX)
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -76,6 +76,10 @@
+ #define MTK_CDMQ_IG_CTRL	0x1400
+ #define MTK_CDMQ_STAG_EN	BIT(0)
+ 
++/* CDMP Ingress Control Register */
++#define MTK_CDMP_IG_CTRL	0x400
++#define MTK_CDMP_STAG_EN	BIT(0)
++
+ /* CDMP Exgress Control Register */
+ #define MTK_CDMP_EG_CTRL	0x404
+ 

+ 43 - 0
target/linux/mediatek/patches-4.9/0044-net-next-dsa-mediatek-tell-GDMA-when-we-are-turning-.patch

@@ -0,0 +1,43 @@
+From 6a5932028a4f3217ed7c9d602f269611d95dd8ca Mon Sep 17 00:00:00 2001
+From: John Crispin <[email protected]>
+Date: Wed, 9 Aug 2017 15:13:19 +0200
+Subject: [PATCH 44/57] net-next: dsa: mediatek: tell GDMA when we are turning
+ on the special tag
+
+Enabling this bit will make the RX DMA descriptor enable the SP bit for all
+ingress traffic inside the return descriptor. The PPE needs this to know
+that a SP is present.
+
+Signed-off-by: John Crispin <[email protected]>
+---
+ drivers/net/dsa/mt7530.c | 5 +++++
+ drivers/net/dsa/mt7530.h | 4 ++++
+ 2 files changed, 9 insertions(+)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -742,6 +742,11 @@ mt7530_cpu_port_enable(struct mt7530_pri
+ 	mt7530_write(priv, MT7530_PVC_P(port),
+ 		     PORT_SPEC_TAG);
+ 
++	/* Enable Mediatek header mode on the GMAC that the cpu port
++	 * connects to */
++	regmap_write_bits(priv->ethernet, MTK_GDMA_FWD_CFG(port),
++			  GDMA_SPEC_TAG, GDMA_SPEC_TAG);
++
+ 	/* Setup the MAC by default for the cpu port */
+ 	mt7530_write(priv, MT7530_PMCR_P(port), PMCR_CPUP_LINK);
+ 
+--- a/drivers/net/dsa/mt7530.h
++++ b/drivers/net/dsa/mt7530.h
+@@ -22,6 +22,10 @@
+ 
+ #define TRGMII_BASE(x)			(0x10000 + (x))
+ 
++/* Registers for GDMA configuration access */
++#define MTK_GDMA_FWD_CFG(x)		(0x500 + (x * 0x1000))
++#define GDMA_SPEC_TAG			BIT(24)
++
+ /* Registers to ethsys access */
+ #define ETHSYS_CLKCFG0			0x2c
+ #define  ETHSYS_TRGMII_CLK_SEL362_5	BIT(11)

+ 79 - 0
target/linux/mediatek/patches-4.9/0045-net-dsa-mediatek-turn-into-platform-driver.patch

@@ -0,0 +1,79 @@
+From 1e33784f665cb95c2af5481d3e776d2d3099921b Mon Sep 17 00:00:00 2001
+From: John Crispin <[email protected]>
+Date: Thu, 10 Aug 2017 15:57:17 +0200
+Subject: [PATCH 45/57] net: dsa: mediatek: turn into platform driver
+
+Signed-off-by: John Crispin <[email protected]>
+---
+ drivers/net/dsa/mt7530.c | 23 +++++++++++++++--------
+ 1 file changed, 15 insertions(+), 8 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -1035,10 +1035,10 @@ static struct dsa_switch_ops mt7530_swit
+ };
+ 
+ static int
+-mt7530_probe(struct mdio_device *mdiodev)
++mt7530_probe(struct platform_device *mdiodev)
+ {
+ 	struct mt7530_priv *priv;
+-	struct device_node *dn;
++	struct device_node *dn, *mdio;
+ 
+ 	dn = mdiodev->dev.of_node;
+ 
+@@ -1086,7 +1086,12 @@ mt7530_probe(struct mdio_device *mdiodev
+ 		}
+ 	}
+ 
+-	priv->bus = mdiodev->bus;
++	mdio = of_parse_phandle(dn, "dsa,mii-bus", 0);
++	if (!mdio)
++		return -EINVAL;
++	priv->bus = of_mdio_find_bus(mdio);
++	if (!priv->bus)
++		return -EPROBE_DEFER;
+ 	priv->dev = &mdiodev->dev;
+ 	priv->ds->priv = priv;
+ 	priv->ds->dev = &mdiodev->dev;
+@@ -1098,8 +1103,8 @@ mt7530_probe(struct mdio_device *mdiodev
+ 	return dsa_register_switch(priv->ds, priv->ds->dev->of_node);
+ }
+ 
+-static void
+-mt7530_remove(struct mdio_device *mdiodev)
++static int
++mt7530_remove(struct platform_device *mdiodev)
+ {
+ 	struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev);
+ 	int ret = 0;
+@@ -1116,6 +1121,8 @@ mt7530_remove(struct mdio_device *mdiode
+ 
+ 	dsa_unregister_switch(priv->ds);
+ 	mutex_destroy(&priv->reg_mutex);
++
++	return 0;
+ }
+ 
+ static const struct of_device_id mt7530_of_match[] = {
+@@ -1123,16 +1130,16 @@ static const struct of_device_id mt7530_
+ 	{ /* sentinel */ },
+ };
+ 
+-static struct mdio_driver mt7530_mdio_driver = {
++static struct platform_driver mtk_mt7530_driver = {
+ 	.probe  = mt7530_probe,
+ 	.remove = mt7530_remove,
+-	.mdiodrv.driver = {
++	.driver = {
+ 		.name = "mt7530",
+ 		.of_match_table = mt7530_of_match,
+ 	},
+ };
++module_platform_driver(mtk_mt7530_driver);
+ 
+-mdio_module_driver(mt7530_mdio_driver);
+ 
+ MODULE_AUTHOR("Sean Wang <[email protected]>");
+ MODULE_DESCRIPTION("Driver for Mediatek MT7530 Switch");

+ 56 - 0
target/linux/mediatek/patches-4.9/0046-net-mediatek-add-irq-delay.patch

@@ -0,0 +1,56 @@
+From 6e081074df96bf3762c2e6438c383f11a56b0a7e Mon Sep 17 00:00:00 2001
+From: John Crispin <[email protected]>
+Date: Thu, 10 Aug 2017 15:58:04 +0200
+Subject: [PATCH 46/57] net: mediatek: add irq delay
+
+Signed-off-by: John Crispin <[email protected]>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 7 ++++++-
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h | 8 +++++++-
+ 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
+@@ -1904,8 +1904,13 @@ static int mtk_hw_init(struct mtk_eth *e
+ 		mtk_w32(eth, 0, MTK_CDMP_EG_CTRL);
+ 
+ 	/* disable delay and normal interrupt */
+-	mtk_w32(eth, 0, MTK_QDMA_DELAY_INT);
++#ifdef MTK_IRQ_DLY
++	mtk_w32(eth, 0x84048404, MTK_PDMA_DELAY_INT);
++	mtk_w32(eth, 0x84048404, MTK_QDMA_DELAY_INT);
++#else
+ 	mtk_w32(eth, 0, MTK_PDMA_DELAY_INT);
++	mtk_w32(eth, 0, MTK_QDMA_DELAY_INT);
++#endif
+ 	mtk_irq_disable(eth, MTK_QDMA_INT_MASK, ~0);
+ 	mtk_irq_disable(eth, MTK_PDMA_INT_MASK, ~0);
+ 	mtk_w32(eth, RST_GL_PSE, MTK_RST_GL);
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -12,6 +12,8 @@
+  *   Copyright (C) 2013-2016 Michael Lee <[email protected]>
+  */
+ 
++#define MTK_IRQ_DLY
++
+ #ifndef MTK_ETH_H
+ #define MTK_ETH_H
+ 
+@@ -220,11 +222,15 @@
+ #define MTK_TX_DONE_INT2	BIT(2)
+ #define MTK_TX_DONE_INT1	BIT(1)
+ #define MTK_TX_DONE_INT0	BIT(0)
++#ifdef MTK_IRQ_DLY
++#define MTK_RX_DONE_INT		BIT(30)
++#define MTK_TX_DONE_INT		BIT(28)
++#else
+ #define MTK_RX_DONE_INT		(MTK_RX_DONE_INT0 | MTK_RX_DONE_INT1 | \
+ 				 MTK_RX_DONE_INT2 | MTK_RX_DONE_INT3)
+ #define MTK_TX_DONE_INT		(MTK_TX_DONE_INT0 | MTK_TX_DONE_INT1 | \
+ 				 MTK_TX_DONE_INT2 | MTK_TX_DONE_INT3)
+-
++#endif
+ /* QDMA Interrupt grouping registers */
+ #define MTK_QDMA_INT_GRP1	0x1a20
+ #define MTK_QDMA_INT_GRP2	0x1a24

+ 208 - 0
target/linux/mediatek/patches-4.9/0047-net-next-mediatek-split-IRQ-register-locking-into-TX.patch

@@ -0,0 +1,208 @@
+From 5afceece38fa30e3c71e7ed9ac62aa70ba8cfbb1 Mon Sep 17 00:00:00 2001
+From: John Crispin <[email protected]>
+Date: Fri, 16 Jun 2017 10:00:30 +0200
+Subject: [PATCH 47/57] net-next: mediatek: split IRQ register locking into TX
+ and RX
+
+Originally the driver only utilized the new QDMA engine. The current code
+still assumes this is the case when locking the IRQ mask register. Since
+RX now runs on the old style PDMA engine we can add a second lock. This
+patch reduces the IRQ latency as the TX and RX path no longer need to wait
+on each other under heavy load.
+
+Signed-off-by: John Crispin <[email protected]>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 79 ++++++++++++++++++-----------
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h |  5 +-
+ 2 files changed, 54 insertions(+), 30 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -372,28 +372,48 @@ static void mtk_mdio_cleanup(struct mtk_
+ 	mdiobus_unregister(eth->mii_bus);
+ }
+ 
+-static inline void mtk_irq_disable(struct mtk_eth *eth,
+-				   unsigned reg, u32 mask)
++static inline void mtk_tx_irq_disable(struct mtk_eth *eth, u32 mask)
+ {
+ 	unsigned long flags;
+ 	u32 val;
+ 
+-	spin_lock_irqsave(&eth->irq_lock, flags);
+-	val = mtk_r32(eth, reg);
+-	mtk_w32(eth, val & ~mask, reg);
+-	spin_unlock_irqrestore(&eth->irq_lock, flags);
++	spin_lock_irqsave(&eth->tx_irq_lock, flags);
++	val = mtk_r32(eth, MTK_QDMA_INT_MASK);
++	mtk_w32(eth, val & ~mask, MTK_QDMA_INT_MASK);
++	spin_unlock_irqrestore(&eth->tx_irq_lock, flags);
+ }
+ 
+-static inline void mtk_irq_enable(struct mtk_eth *eth,
+-				  unsigned reg, u32 mask)
++static inline void mtk_tx_irq_enable(struct mtk_eth *eth, u32 mask)
+ {
+ 	unsigned long flags;
+ 	u32 val;
+ 
+-	spin_lock_irqsave(&eth->irq_lock, flags);
+-	val = mtk_r32(eth, reg);
+-	mtk_w32(eth, val | mask, reg);
+-	spin_unlock_irqrestore(&eth->irq_lock, flags);
++	spin_lock_irqsave(&eth->tx_irq_lock, flags);
++	val = mtk_r32(eth, MTK_QDMA_INT_MASK);
++	mtk_w32(eth, val | mask, MTK_QDMA_INT_MASK);
++	spin_unlock_irqrestore(&eth->tx_irq_lock, flags);
++}
++
++static inline void mtk_rx_irq_disable(struct mtk_eth *eth, u32 mask)
++{
++	unsigned long flags;
++	u32 val;
++
++	spin_lock_irqsave(&eth->rx_irq_lock, flags);
++	val = mtk_r32(eth, MTK_PDMA_INT_MASK);
++	mtk_w32(eth, val & ~mask, MTK_PDMA_INT_MASK);
++	spin_unlock_irqrestore(&eth->rx_irq_lock, flags);
++}
++
++static inline void mtk_rx_irq_enable(struct mtk_eth *eth, u32 mask)
++{
++	unsigned long flags;
++	u32 val;
++
++	spin_lock_irqsave(&eth->rx_irq_lock, flags);
++	val = mtk_r32(eth, MTK_PDMA_INT_MASK);
++	mtk_w32(eth, val | mask, MTK_PDMA_INT_MASK);
++	spin_unlock_irqrestore(&eth->rx_irq_lock, flags);
+ }
+ 
+ static int mtk_set_mac_address(struct net_device *dev, void *p)
+@@ -1116,7 +1136,7 @@ static int mtk_napi_tx(struct napi_struc
+ 		return budget;
+ 
+ 	napi_complete(napi);
+-	mtk_irq_enable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
++	mtk_tx_irq_enable(eth, MTK_TX_DONE_INT);
+ 
+ 	return tx_done;
+ }
+@@ -1150,7 +1170,7 @@ poll_again:
+ 		goto poll_again;
+ 	}
+ 	napi_complete(napi);
+-	mtk_irq_enable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
++	mtk_rx_irq_enable(eth, MTK_RX_DONE_INT);
+ 
+ 	return rx_done + budget - remain_budget;
+ }
+@@ -1699,7 +1719,7 @@ static irqreturn_t mtk_handle_irq_rx(int
+ 
+ 	if (likely(napi_schedule_prep(&eth->rx_napi))) {
+ 		__napi_schedule(&eth->rx_napi);
+-		mtk_irq_disable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
++		mtk_rx_irq_disable(eth, MTK_RX_DONE_INT);
+ 	}
+ 
+ 	return IRQ_HANDLED;
+@@ -1711,7 +1731,7 @@ static irqreturn_t mtk_handle_irq_tx(int
+ 
+ 	if (likely(napi_schedule_prep(&eth->tx_napi))) {
+ 		__napi_schedule(&eth->tx_napi);
+-		mtk_irq_disable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
++		mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
+ 	}
+ 
+ 	return IRQ_HANDLED;
+@@ -1723,11 +1743,11 @@ static void mtk_poll_controller(struct n
+ 	struct mtk_mac *mac = netdev_priv(dev);
+ 	struct mtk_eth *eth = mac->hw;
+ 
+-	mtk_irq_disable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
+-	mtk_irq_disable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
++	mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
++	mtk_rx_irq_disable(eth, MTK_RX_DONE_INT);
+ 	mtk_handle_irq_rx(eth->irq[2], dev);
+-	mtk_irq_enable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
+-	mtk_irq_enable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
++	mtk_tx_irq_enable(eth, MTK_TX_DONE_INT);
++	mtk_rx_irq_enable(eth, MTK_RX_DONE_INT);
+ }
+ #endif
+ 
+@@ -1770,8 +1790,8 @@ static int mtk_open(struct net_device *d
+ 
+ 		napi_enable(&eth->tx_napi);
+ 		napi_enable(&eth->rx_napi);
+-		mtk_irq_enable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
+-		mtk_irq_enable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
++		mtk_tx_irq_enable(eth, MTK_TX_DONE_INT);
++		mtk_rx_irq_enable(eth, MTK_RX_DONE_INT);
+ 	}
+ 	atomic_inc(&eth->dma_refcnt);
+ 
+@@ -1816,8 +1836,8 @@ static int mtk_stop(struct net_device *d
+ 	if (!atomic_dec_and_test(&eth->dma_refcnt))
+ 		return 0;
+ 
+-	mtk_irq_disable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
+-	mtk_irq_disable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
++	mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
++	mtk_rx_irq_disable(eth, MTK_RX_DONE_INT);
+ 	napi_disable(&eth->tx_napi);
+ 	napi_disable(&eth->rx_napi);
+ 
+@@ -1911,8 +1931,8 @@ static int mtk_hw_init(struct mtk_eth *e
+ 	mtk_w32(eth, 0, MTK_PDMA_DELAY_INT);
+ 	mtk_w32(eth, 0, MTK_QDMA_DELAY_INT);
+ #endif
+-	mtk_irq_disable(eth, MTK_QDMA_INT_MASK, ~0);
+-	mtk_irq_disable(eth, MTK_PDMA_INT_MASK, ~0);
++	mtk_tx_irq_disable(eth, ~0);
++	mtk_rx_irq_disable(eth, ~0);
+ 	mtk_w32(eth, RST_GL_PSE, MTK_RST_GL);
+ 	mtk_w32(eth, 0, MTK_RST_GL);
+ 
+@@ -1983,8 +2003,8 @@ static void mtk_uninit(struct net_device
+ 	phy_disconnect(dev->phydev);
+ 	if (of_phy_is_fixed_link(mac->of_node))
+ 		of_phy_deregister_fixed_link(mac->of_node);
+-	mtk_irq_disable(eth, MTK_QDMA_INT_MASK, ~0);
+-	mtk_irq_disable(eth, MTK_PDMA_INT_MASK, ~0);
++	mtk_tx_irq_disable(eth, ~0);
++	mtk_rx_irq_disable(eth, ~0);
+ }
+ 
+ static int mtk_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+@@ -2442,7 +2462,8 @@ static int mtk_probe(struct platform_dev
+ 		return PTR_ERR(eth->base);
+ 
+ 	spin_lock_init(&eth->page_lock);
+-	spin_lock_init(&eth->irq_lock);
++	spin_lock_init(&eth->tx_irq_lock);
++	spin_lock_init(&eth->rx_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
+@@ -526,6 +526,8 @@ struct mtk_rx_ring {
+  * @dev:		The device pointer
+  * @base:		The mapped register i/o base
+  * @page_lock:		Make sure that register operations are atomic
++ * @tx_irq__lock:	Make sure that IRQ register operations are atomic
++ * @rx_irq__lock:	Make sure that IRQ register operations are atomic
+  * @dummy_dev:		we run 2 netdevs on 1 physical DMA ring and need a
+  *			dummy for NAPI to work
+  * @netdev:		The netdev instances
+@@ -555,7 +557,8 @@ struct mtk_eth {
+ 	struct device			*dev;
+ 	void __iomem			*base;
+ 	spinlock_t			page_lock;
+-	spinlock_t			irq_lock;
++	spinlock_t			tx_irq_lock;
++	spinlock_t			rx_irq_lock;
+ 	struct net_device		dummy_dev;
+ 	struct net_device		*netdev[MTK_MAX_DEVS];
+ 	struct mtk_mac			*mac[MTK_MAX_DEVS];

+ 90 - 0
target/linux/mediatek/patches-4.9/0048-net-core-add-RPS-balancer.patch

@@ -0,0 +1,90 @@
+From 3e969c9695b45e1a052d43b367096ec99f2f0aac Mon Sep 17 00:00:00 2001
+From: John Crispin <[email protected]>
+Date: Thu, 10 Aug 2017 15:58:29 +0200
+Subject: [PATCH 48/57] net: core: add RPS balancer
+
+Signed-off-by: John Crispin <[email protected]>
+---
+ net/core/dev.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 56 insertions(+), 1 deletion(-)
+
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -3547,6 +3547,58 @@ set_rps_cpu(struct net_device *dev, stru
+ 	return rflow;
+ }
+ 
++#define RPS_TBL_SIZE_SHIFT	10
++#define RPS_TBL_SIZE		(1 << RPS_TBL_SIZE_SHIFT)
++struct rps_table {
++	int			core;
++	struct timer_list	expire;
++};
++static struct rps_table rps_table[RPS_TBL_SIZE];
++static int rps_table_last_core;
++
++static void rps_table_expire(unsigned long data)
++{
++	struct rps_table *entry = (struct rps_table *) data;
++
++	entry->core = -1;
++}
++
++static int rps_table_core(struct rps_map *map)
++{
++	int i;
++
++	for (i = 0; i < map->len; i++) {
++		int cpu = map->cpus[(rps_table_last_core + i + 1) % map->len];
++		if (cpu_online(cpu)) {
++			rps_table_last_core = cpu;
++			return cpu;
++		}
++	}
++	return map->cpus[0];
++}
++
++static int rps_table_lookup(struct rps_map *map, u32 hash)
++{
++	int bucket = hash & 0x3ff;
++
++	if (rps_table[bucket].core < 0)
++		rps_table[bucket].core = rps_table_core(map);
++	mod_timer(&rps_table[bucket].expire, jiffies + HZ);
++
++	return rps_table[bucket].core;
++}
++
++static void rps_table_init(void)
++{
++	int i;
++
++	for (i = 0; i < RPS_TBL_SIZE; i++) {
++		rps_table[i].core = -1;
++		setup_timer(&rps_table[i].expire, rps_table_expire,
++			    (unsigned long) &rps_table[i]);
++	}
++}
++
+ /*
+  * get_rps_cpu is called from netif_receive_skb and returns the target
+  * CPU from the RPS map of the receiving queue for a given skb.
+@@ -3636,7 +3688,7 @@ static int get_rps_cpu(struct net_device
+ try_rps:
+ 
+ 	if (map) {
+-		tcpu = map->cpus[reciprocal_scale(hash, map->len)];
++		tcpu = rps_table_lookup(map, hash);
+ 		if (cpu_online(tcpu)) {
+ 			cpu = tcpu;
+ 			goto done;
+@@ -8426,6 +8478,9 @@ static int __init net_dev_init(void)
+ 		sd->backlog.weight = weight_p;
+ 	}
+ 
++	if (IS_ENABLED(CONFIG_RPS))
++		rps_table_init();
++
+ 	dev_boot_phase = 0;
+ 
+ 	/* The loopback device is special if any other network devices

+ 20 - 0
target/linux/mediatek/patches-4.9/0049-net-mediatek-add-rx-queue.patch

@@ -0,0 +1,20 @@
+From 066b30a76a0d13cbd2c0d463f9a1e87efc352679 Mon Sep 17 00:00:00 2001
+From: John Crispin <[email protected]>
+Date: Thu, 10 Aug 2017 15:58:46 +0200
+Subject: [PATCH 49/57] net: mediatek: add rx queue
+
+Signed-off-by: John Crispin <[email protected]>
+---
+ 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
+@@ -1009,6 +1009,7 @@ static int mtk_poll_rx(struct napi_struc
+ 		    RX_DMA_VID(trxd.rxd3))
+ 			__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
+ 					       RX_DMA_VID(trxd.rxd3));
++		skb_record_rx_queue(skb, 0);
+ 		napi_gro_receive(napi, skb);
+ 
+ 		ring->data[idx] = new_data;

+ 21 - 0
target/linux/mediatek/patches-4.9/0050-net-mediatek-add-trgmii-clock.patch

@@ -0,0 +1,21 @@
+From 67c4af99af02d86b627a8cde2e99cc4c9699d2ce Mon Sep 17 00:00:00 2001
+From: John Crispin <[email protected]>
+Date: Thu, 10 Aug 2017 15:59:08 +0200
+Subject: [PATCH 50/57] net: mediatek: add trgmii clock
+
+Signed-off-by: John Crispin <[email protected]>
+---
+ 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
+@@ -1873,6 +1873,8 @@ static int mtk_hw_init(struct mtk_eth *e
+ 	pm_runtime_enable(eth->dev);
+ 	pm_runtime_get_sync(eth->dev);
+ 
++	clk_set_rate(eth->clks[MTK_CLK_TRGPLL], 250000000);
++
+ 	clk_prepare_enable(eth->clks[MTK_CLK_ETHIF]);
+ 	clk_prepare_enable(eth->clks[MTK_CLK_ESW]);
+ 	clk_prepare_enable(eth->clks[MTK_CLK_GP1]);

+ 21 - 0
target/linux/mediatek/patches-4.9/0051-net-mediatek-increase-tx_timeout.patch

@@ -0,0 +1,21 @@
+From 5cbf53c7e5eac5bacc409461888789accdaf8eec Mon Sep 17 00:00:00 2001
+From: John Crispin <[email protected]>
+Date: Thu, 10 Aug 2017 16:00:06 +0200
+Subject: [PATCH 51/57] net: mediatek: increase tx_timeout
+
+Signed-off-by: John Crispin <[email protected]>
+---
+ 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
+@@ -2384,7 +2384,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 = 30 * HZ;
+ 	eth->netdev[id]->netdev_ops = &mtk_netdev_ops;
+ 	eth->netdev[id]->base_addr = (unsigned long)eth->base;
+ 

+ 21 - 0
target/linux/mediatek/patches-4.9/0052-net-phy-add-FC.patch

@@ -0,0 +1,21 @@
+From 18b2169d84b47a3414164e5e40f23fb7e875707c Mon Sep 17 00:00:00 2001
+From: John Crispin <[email protected]>
+Date: Thu, 10 Aug 2017 16:00:28 +0200
+Subject: [PATCH 52/57] net: phy: add FC
+
+Signed-off-by: John Crispin <[email protected]>
+---
+ drivers/net/phy/phy_device.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/phy/phy_device.c
++++ b/drivers/net/phy/phy_device.c
+@@ -1799,7 +1799,7 @@ static struct phy_driver genphy_driver[]
+ 	.config_init	= genphy_config_init,
+ 	.features	= PHY_GBIT_FEATURES | SUPPORTED_MII |
+ 			  SUPPORTED_AUI | SUPPORTED_FIBRE |
+-			  SUPPORTED_BNC,
++			  SUPPORTED_BNC | SUPPORTED_Pause | SUPPORTED_Asym_Pause,
+ 	.config_aneg	= genphy_config_aneg,
+ 	.aneg_done	= genphy_aneg_done,
+ 	.read_status	= genphy_read_status,

+ 68 - 0
target/linux/mediatek/patches-4.9/0053-net-dsa-mediatek-add-software-phy-polling.patch

@@ -0,0 +1,68 @@
+From 53eec2c3580e63fdebfc25ae324f30cd8aa4403b Mon Sep 17 00:00:00 2001
+From: John Crispin <[email protected]>
+Date: Thu, 10 Aug 2017 16:00:46 +0200
+Subject: [PATCH 53/57] net: dsa: mediatek: add software phy polling
+
+Signed-off-by: John Crispin <[email protected]>
+---
+ drivers/net/dsa/mt7530.c | 38 ++++++++++++++++++++++++++++++++++++++
+ drivers/net/dsa/mt7530.h |  1 +
+ 2 files changed, 39 insertions(+)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -728,6 +728,44 @@ static void mt7530_adjust_link(struct ds
+ 		 * all finished.
+ 		 */
+ 		mt7623_pad_clk_setup(ds);
++	} else {
++		u16 lcl_adv = 0, rmt_adv = 0;
++		u8 flowctrl;
++		u32 mcr = PMCR_USERP_LINK | PMCR_FORCE_MODE;
++
++		switch (phydev->speed) {
++		case SPEED_1000:
++			mcr |= PMCR_FORCE_SPEED_1000;
++			break;
++		case SPEED_100:
++			mcr |= PMCR_FORCE_SPEED_100;
++			break;
++		};
++
++		if (phydev->link)
++			mcr |= PMCR_FORCE_LNK;
++
++		if (phydev->duplex) {
++			mcr |= PMCR_FORCE_FDX;
++
++			if (phydev->pause)
++				rmt_adv = LPA_PAUSE_CAP;
++			if (phydev->asym_pause)
++				rmt_adv |= LPA_PAUSE_ASYM;
++
++			if (phydev->advertising & ADVERTISED_Pause)
++				lcl_adv |= ADVERTISE_PAUSE_CAP;
++			if (phydev->advertising & ADVERTISED_Asym_Pause)
++				lcl_adv |= ADVERTISE_PAUSE_ASYM;
++
++			flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
++
++			if (flowctrl & FLOW_CTRL_TX)
++				mcr |= PMCR_TX_FC_EN;
++			if (flowctrl & FLOW_CTRL_RX)
++				mcr |= PMCR_RX_FC_EN;
++		}
++		mt7530_write(priv, MT7530_PMCR_P(port), mcr);
+ 	}
+ }
+ 
+--- a/drivers/net/dsa/mt7530.h
++++ b/drivers/net/dsa/mt7530.h
+@@ -155,6 +155,7 @@ enum mt7530_stp_state {
+ #define  PMCR_TX_FC_EN			BIT(5)
+ #define  PMCR_RX_FC_EN			BIT(4)
+ #define  PMCR_FORCE_SPEED_1000		BIT(3)
++#define  PMCR_FORCE_SPEED_100		BIT(2)
+ #define  PMCR_FORCE_FDX			BIT(1)
+ #define  PMCR_FORCE_LNK			BIT(0)
+ #define  PMCR_COMMON_LINK		(PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | \

+ 105 - 0
target/linux/mediatek/patches-4.9/0054-net-ethernet-mediatek-fixed-deadlock-captured-by-loc.patch

@@ -0,0 +1,105 @@
+From 746bf1c3e561aba396cd40e6540245646461117d Mon Sep 17 00:00:00 2001
+From: Sean Wang <[email protected]>
+Date: Tue, 4 Jul 2017 11:17:36 +0800
+Subject: [PATCH 54/57] net: ethernet: mediatek: fixed deadlock captured by
+ lockdep
+
+Lockdep found an inconsistent lock state when mtk_get_stats64 is called
+in user context while NAPI updates MAC statistics in softirq.
+
+Use spin_trylock_bh/spin_unlock_bh fix following lockdep warning.
+
+[   81.321030] WARNING: inconsistent lock state
+[   81.325266] 4.12.0-rc1-00035-gd9dda65 #32 Not tainted
+[   81.330273] --------------------------------
+[   81.334505] inconsistent {SOFTIRQ-ON-W} -> {IN-SOFTIRQ-W} usage.
+[   81.340464] ksoftirqd/0/7 [HC0[0]:SC1[1]:HE1:SE0] takes:
+[   81.345731]  (&syncp->seq#2){+.?...}, at: [<c054ba3c>] mtk_handle_status_irq.part.6+0x70/0x84
+[   81.354219] {SOFTIRQ-ON-W} state was registered at:
+[   81.359062]   lock_acquire+0xfc/0x2b0
+[   81.362696]   mtk_stats_update_mac+0x60/0x2c0
+[   81.367017]   mtk_get_stats64+0x17c/0x18c
+[   81.370995]   dev_get_stats+0x48/0xbc
+[   81.374628]   rtnl_fill_stats+0x48/0x128
+[   81.378520]   rtnl_fill_ifinfo+0x4ac/0xd1c
+[   81.382584]   rtmsg_ifinfo_build_skb+0x7c/0xe0
+[   81.386991]   rtmsg_ifinfo.part.5+0x24/0x54
+[   81.391139]   rtmsg_ifinfo+0x24/0x28
+[   81.394685]   __dev_notify_flags+0xa4/0xac
+[   81.398749]   dev_change_flags+0x50/0x58
+[   81.402640]   devinet_ioctl+0x768/0x85c
+[   81.406444]   inet_ioctl+0x1a4/0x1d0
+[   81.409990]   sock_ioctl+0x16c/0x33c
+[   81.413538]   do_vfs_ioctl+0xb4/0xa34
+[   81.417169]   SyS_ioctl+0x44/0x6c
+[   81.420458]   ret_fast_syscall+0x0/0x1c
+[   81.424260] irq event stamp: 3354692
+[   81.427806] hardirqs last  enabled at (3354692): [<c0678168>] net_rx_action+0xc0/0x504
+[   81.435660] hardirqs last disabled at (3354691): [<c0678134>] net_rx_action+0x8c/0x504
+[   81.443515] softirqs last  enabled at (3354106): [<c0101944>] __do_softirq+0x4b4/0x614
+[   81.451370] softirqs last disabled at (3354109): [<c012f0c4>] run_ksoftirqd+0x44/0x80
+[   81.459134]
+[   81.459134] other info that might help us debug this:
+[   81.465608]  Possible unsafe locking scenario:
+[   81.465608]
+[   81.471478]        CPU0
+[   81.473900]        ----
+[   81.476321]   lock(&syncp->seq#2);
+[   81.479701]   <Interrupt>
+[   81.482294]     lock(&syncp->seq#2);
+[   81.485847]
+[   81.485847]  *** DEADLOCK ***
+[   81.485847]
+[   81.491720] 1 lock held by ksoftirqd/0/7:
+[   81.495693]  #0:  (&(&mac->hw_stats->stats_lock)->rlock){+.+...}, at: [<c054ba14>] mtk_handle_status_irq.part.6+0x48/0x84
+[   81.506579]
+[   81.506579] stack backtrace:
+[   81.510904] CPU: 0 PID: 7 Comm: ksoftirqd/0 Not tainted 4.12.0-rc1-00035-gd9dda65 #32
+[   81.518668] Hardware name: Mediatek Cortex-A7 (Device Tree)
+[   81.524208] [<c0113dc4>] (unwind_backtrace) from [<c010e3f0>] (show_stack+0x20/0x24)
+[   81.531899] [<c010e3f0>] (show_stack) from [<c03f9c64>] (dump_stack+0xb4/0xe0)
+[   81.539072] [<c03f9c64>] (dump_stack) from [<c017e970>] (print_usage_bug+0x234/0x2e0)
+[   81.546846] [<c017e970>] (print_usage_bug) from [<c017f058>] (mark_lock+0x63c/0x7bc)
+[   81.554532] [<c017f058>] (mark_lock) from [<c017fe90>] (__lock_acquire+0x654/0x1bfc)
+[   81.562217] [<c017fe90>] (__lock_acquire) from [<c0181d04>] (lock_acquire+0xfc/0x2b0)
+[   81.569990] [<c0181d04>] (lock_acquire) from [<c054b76c>] (mtk_stats_update_mac+0x60/0x2c0)
+[   81.578283] [<c054b76c>] (mtk_stats_update_mac) from [<c054ba3c>] (mtk_handle_status_irq.part.6+0x70/0x84)
+[   81.587865] [<c054ba3c>] (mtk_handle_status_irq.part.6) from [<c054c2b8>] (mtk_napi_tx+0x358/0x37c)
+[   81.596845] [<c054c2b8>] (mtk_napi_tx) from [<c06782ec>] (net_rx_action+0x244/0x504)
+[   81.604533] [<c06782ec>] (net_rx_action) from [<c01015c4>] (__do_softirq+0x134/0x614)
+[   81.612306] [<c01015c4>] (__do_softirq) from [<c012f0c4>] (run_ksoftirqd+0x44/0x80)
+[   81.619907] [<c012f0c4>] (run_ksoftirqd) from [<c0154680>] (smpboot_thread_fn+0x14c/0x25c)
+[   81.628110] [<c0154680>] (smpboot_thread_fn) from [<c014f8cc>] (kthread+0x150/0x180)
+[   81.635798] [<c014f8cc>] (kthread) from [<c0109290>] (ret_from_fork+0x14/0x24)
+
+Signed-off-by: Sean Wang <[email protected]>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -493,9 +493,9 @@ static struct rtnl_link_stats64 * mtk_ge
+ 	unsigned int start;
+ 
+ 	if (netif_running(dev) && netif_device_present(dev)) {
+-		if (spin_trylock(&hw_stats->stats_lock)) {
++		if (spin_trylock_bh(&hw_stats->stats_lock)) {
+ 			mtk_stats_update_mac(mac);
+-			spin_unlock(&hw_stats->stats_lock);
++			spin_unlock_bh(&hw_stats->stats_lock);
+ 		}
+ 	}
+ 
+@@ -2229,9 +2229,9 @@ static void mtk_get_ethtool_stats(struct
+ 		return;
+ 
+ 	if (netif_running(dev) && netif_device_present(dev)) {
+-		if (spin_trylock(&hwstats->stats_lock)) {
++		if (spin_trylock_bh(&hwstats->stats_lock)) {
+ 			mtk_stats_update_mac(mac);
+-			spin_unlock(&hwstats->stats_lock);
++			spin_unlock_bh(&hwstats->stats_lock);
+ 		}
+ 	}
+ 

+ 31 - 0
target/linux/mediatek/patches-4.9/0055-net-ethernet-mediatek-avoid-potential-invalid-memory.patch

@@ -0,0 +1,31 @@
+From a3360b3543b9fb833ba691019e396e72293a313f Mon Sep 17 00:00:00 2001
+From: John Crispin <[email protected]>
+Date: Thu, 10 Aug 2017 16:31:45 +0200
+Subject: [PATCH 55/57] net: ethernet: mediatek: avoid potential invalid memory
+ access
+
+Potential dangerous invalid memory might be accessed if invalid mac value
+reflected from the forward port field in rxd4 caused by possible potential
+hardware defects. So added a simple sanity checker to avoid the kind of
+situation happening.
+
+Signed-off-by: Sean Wang <[email protected]>
+Acked-by: John Crispin <[email protected]>
+Signed-off-by: David S. Miller <[email protected]>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -964,6 +964,10 @@ static int mtk_poll_rx(struct napi_struc
+ 			mac--;
+ 		}
+ 
++		if (unlikely(mac < 0 || mac >= MTK_MAC_COUNT ||
++			     !eth->netdev[mac]))
++			goto release_desc;
++
+ 		netdev = eth->netdev[mac];
+ 
+ 		if (unlikely(test_bit(MTK_RESETTING, &eth->state)))

+ 119 - 0
target/linux/mediatek/patches-4.9/0056-net-mediatek-add-hw-nat-support.patch

@@ -0,0 +1,119 @@
+From 043efc0e619e04661be2b1889382db2fdd378145 Mon Sep 17 00:00:00 2001
+From: John Crispin <[email protected]>
+Date: Thu, 10 Aug 2017 16:34:36 +0200
+Subject: [PATCH 56/57] net: mediatek: add hw nat support
+
+Signed-off-by: John Crispin <[email protected]>
+---
+ drivers/net/ethernet/mediatek/Kconfig       |  7 +++++++
+ drivers/net/ethernet/mediatek/Makefile      |  1 +
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 13 +++++++++++++
+ net/netfilter/nf_conntrack_proto_tcp.c      | 19 +++++++++++++++++++
+ 4 files changed, 40 insertions(+)
+
+--- a/drivers/net/ethernet/mediatek/Kconfig
++++ b/drivers/net/ethernet/mediatek/Kconfig
+@@ -14,4 +14,11 @@ config NET_MEDIATEK_SOC
+ 	  This driver supports the gigabit ethernet MACs in the
+ 	  MediaTek MT2701/MT7623 chipset family.
+ 
++config NET_MEDIATEK_HNAT
++	tristate "MediaTek MT7623 hardware NAT support"
++	depends on NET_MEDIATEK_SOC && NF_CONNTRACK && NF_CONNTRACK_IPV4 && IP_NF_NAT && IP_NF_TARGET_MASQUERADE
++	---help---
++	  This driver supports the hardwaer NAT in the
++	  MediaTek MT2701/MT7623 chipset family.
++
+ endif #NET_VENDOR_MEDIATEK
+--- a/drivers/net/ethernet/mediatek/Makefile
++++ b/drivers/net/ethernet/mediatek/Makefile
+@@ -3,3 +3,4 @@
+ #
+ 
+ obj-$(CONFIG_NET_MEDIATEK_SOC)			+= mtk_eth_soc.o
++obj-$(CONFIG_NET_MEDIATEK_HNAT)			+= mtk_hnat/
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -23,6 +23,10 @@
+ #include <linux/reset.h>
+ #include <linux/tcp.h>
+ 
++#if defined(CONFIG_NET_MEDIATEK_HNAT) || defined(CONFIG_NET_MEDIATEK_HNAT_MODULE)
++#include "mtk_hnat/nf_hnat_mtk.h"
++#endif
++
+ #include "mtk_eth_soc.h"
+ 
+ static int mtk_msg_level = -1;
+@@ -649,6 +653,11 @@ static int mtk_tx_map(struct sk_buff *sk
+ 		return -ENOMEM;
+ 
+ 	/* set the forward port */
++#if defined(CONFIG_NET_MEDIATEK_HNAT) || defined(CONFIG_NET_MEDIATEK_HNAT_MODULE)
++	if (HNAT_SKB_CB2(skb)->magic == 0x78681415)
++		fport |= 0x4 << TX_DMA_FPORT_SHIFT;
++	else
++#endif
+ 	fport = (mac->id + 1) << TX_DMA_FPORT_SHIFT;
+ 	txd4 |= fport;
+ 
+@@ -1013,6 +1022,10 @@ static int mtk_poll_rx(struct napi_struc
+ 		    RX_DMA_VID(trxd.rxd3))
+ 			__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
+ 					       RX_DMA_VID(trxd.rxd3));
++#if defined(CONFIG_NET_MEDIATEK_HNAT) || defined(CONFIG_NET_MEDIATEK_HNAT_MODULE)
++		*(u32 *)(skb->head) = trxd.rxd4;
++		skb_hnat_alg(skb) = 0;
++#endif
+ 		skb_record_rx_queue(skb, 0);
+ 		napi_gro_receive(napi, skb);
+ 
+--- a/net/netfilter/nf_conntrack_proto_tcp.c
++++ b/net/netfilter/nf_conntrack_proto_tcp.c
+@@ -11,6 +11,7 @@
+ #include <linux/types.h>
+ #include <linux/timer.h>
+ #include <linux/module.h>
++#include <linux/inetdevice.h>
+ #include <linux/in.h>
+ #include <linux/tcp.h>
+ #include <linux/spinlock.h>
+@@ -19,6 +20,7 @@
+ #include <net/ip6_checksum.h>
+ #include <asm/unaligned.h>
+ 
++#include <net/ip.h>
+ #include <net/tcp.h>
+ 
+ #include <linux/netfilter.h>
+@@ -53,6 +55,11 @@ static int nf_ct_tcp_max_retrans __read_
+   /* FIXME: Examine ipfilter's timeouts and conntrack transitions more
+      closely.  They're more complex. --RR */
+ 
++#ifndef IPV4_DEVCONF_DFLT
++	#define IPV4_DEVCONF_DFLT(net, attr) \
++	IPV4_DEVCONF((*net->ipv4.devconf_dflt), attr)
++#endif
++
+ static const char *const tcp_conntrack_names[] = {
+ 	"NONE",
+ 	"SYN_SENT",
+@@ -519,6 +526,18 @@ static bool tcp_in_window(const struct n
+ 	if (nf_ct_tcp_no_window_check)
+ 		return true;
+ 
++	if (net) {
++		if ((net->ipv4.devconf_all && net->ipv4.devconf_dflt && net->ipv6.devconf_all) &&
++		    net->ipv6.devconf_dflt) {
++			if ((IPV4_DEVCONF_DFLT(net, FORWARDING) ||
++			     IPV4_DEVCONF_ALL(net, FORWARDING)) ||
++			     (net->ipv6.devconf_all->forwarding ||
++			      net->ipv6.devconf_dflt->forwarding)) {
++				return true;
++			}
++		}
++	}
++
+ 	/*
+ 	 * Get the required data from the packet.
+ 	 */

+ 121 - 0
target/linux/mediatek/patches-4.9/0057-net-mediatek-add-HW-QoS-support.patch

@@ -0,0 +1,121 @@
+From 660c13dfbacbf37f090a66a2b14f0c5ce7cbec81 Mon Sep 17 00:00:00 2001
+From: John Crispin <[email protected]>
+Date: Thu, 10 Aug 2017 16:38:27 +0200
+Subject: [PATCH 57/57] net: mediatek: add HW QoS support
+
+Signed-off-by: John Crispin <[email protected]>
+---
+ drivers/net/ethernet/mediatek/Kconfig       |  7 ++++
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 60 ++++++++++++++++++++++++++++-
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h |  2 +-
+ 3 files changed, 66 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/Kconfig
++++ b/drivers/net/ethernet/mediatek/Kconfig
+@@ -21,4 +21,11 @@ config NET_MEDIATEK_HNAT
+ 	  This driver supports the hardwaer NAT in the
+ 	  MediaTek MT2701/MT7623 chipset family.
+ 
++config NET_MEDIATEK_HW_QOS
++	tristate "MediaTek MT7623 hardware QoS support"
++	depends on NET_MEDIATEK_SOC
++	---help---
++	  This driver supports the hardware QoS in the
++	  MediaTek MT2701/MT7623 chipset family.
++
+ endif #NET_VENDOR_MEDIATEK
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -23,6 +23,17 @@
+ #include <linux/reset.h>
+ #include <linux/tcp.h>
+ 
++#if defined(CONFIG_NET_MEDIATEK_HW_QOS)
++struct mtk_ioctl_reg {
++	unsigned int off;
++	unsigned int val;
++};
++
++#define REG_HQOS_MAX			0x3FFF
++#define RAETH_QDMA_REG_READ		0x89F8
++#define RAETH_QDMA_REG_WRITE		0x89F9
++#endif
++
+ #if defined(CONFIG_NET_MEDIATEK_HNAT) || defined(CONFIG_NET_MEDIATEK_HNAT_MODULE)
+ #include "mtk_hnat/nf_hnat_mtk.h"
+ #endif
+@@ -646,7 +657,7 @@ static int mtk_tx_map(struct sk_buff *sk
+ 	dma_addr_t mapped_addr;
+ 	unsigned int nr_frags;
+ 	int i, n_desc = 1;
+-	u32 txd4 = 0, fport;
++	u32 txd3 = 0, txd4 = 0, fport;
+ 
+ 	itxd = ring->next_free;
+ 	if (itxd == ring->last_free)
+@@ -675,6 +686,12 @@ static int mtk_tx_map(struct sk_buff *sk
+ //	if (skb_vlan_tag_present(skb))
+ //		txd4 |= TX_DMA_INS_VLAN | skb_vlan_tag_get(skb);
+ 
++#ifdef CONFIG_NET_MEDIATEK_HW_QOS
++	txd3 |= skb->mark & 0x7;
++	if (mac->id)
++		txd3 += 8;
++#endif
++
+ 	mapped_addr = dma_map_single(eth->dev, skb->data,
+ 				     skb_headlen(skb), DMA_TO_DEVICE);
+ 	if (unlikely(dma_mapping_error(eth->dev, mapped_addr)))
+@@ -718,7 +735,8 @@ 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));
++					       last_frag * TX_DMA_LS0 |
++					       txd3));
+ 			WRITE_ONCE(txd->txd4, fport);
+ 
+ 			tx_buf = mtk_desc_to_tx_buf(ring, txd);
+@@ -2029,7 +2047,31 @@ static void mtk_uninit(struct net_device
+ 
+ static int mtk_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+ {
++#if defined(CONFIG_NET_MEDIATEK_HW_QOS)
++	struct mtk_mac *mac = netdev_priv(dev);
++	struct mtk_eth *eth = mac->hw;
++	struct mtk_ioctl_reg reg;
++#endif
++
+ 	switch (cmd) {
++#if defined(CONFIG_NET_MEDIATEK_HW_QOS)
++	case RAETH_QDMA_REG_READ:
++		copy_from_user(&reg, ifr->ifr_data, sizeof(reg));
++		if (reg.off > REG_HQOS_MAX)
++			return -EINVAL;
++		reg.val = mtk_r32(eth, 0x1800 + reg.off);
++//		printk("read reg off:%x val:%x\n", reg.off, reg.val);
++		copy_to_user(ifr->ifr_data, &reg, sizeof(reg));
++		return 0;
++
++	case RAETH_QDMA_REG_WRITE:
++		copy_from_user(&reg, ifr->ifr_data, sizeof(reg));
++		if (reg.off > REG_HQOS_MAX)
++			return -EINVAL;
++		mtk_w32(eth, reg.val, 0x1800 + reg.off);
++//		printk("write reg off:%x val:%x\n", reg.off, reg.val);
++		return 0;
++#endif
+ 	case SIOCGMIIPHY:
+ 	case SIOCGMIIREG:
+ 	case SIOCSMIIREG:
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -20,7 +20,7 @@
+ #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_DMA_SIZE		2048
+ #define MTK_NAPI_WEIGHT		64
+ #define MTK_MAC_COUNT		2
+ #define MTK_RX_ETH_HLEN		(VLAN_ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN)

+ 470 - 0
target/linux/mediatek/patches-4.9/0058-pinctrl-update.patch

@@ -0,0 +1,470 @@
+--- a/drivers/pinctrl/mediatek/Kconfig
++++ b/drivers/pinctrl/mediatek/Kconfig
+@@ -15,12 +15,6 @@ config PINCTRL_MT2701
+ 	default MACH_MT2701
+ 	select PINCTRL_MTK
+ 
+-config PINCTRL_MT7623
+-	bool "Mediatek MT7623 pin control" if COMPILE_TEST && !MACH_MT7623
+-	depends on OF
+-	default MACH_MT7623
+-	select PINCTRL_MTK_COMMON
+-
+ config PINCTRL_MT8135
+ 	bool "Mediatek MT8135 pin control" if COMPILE_TEST && !MACH_MT8135
+ 	depends on OF
+--- a/drivers/pinctrl/mediatek/Makefile
++++ b/drivers/pinctrl/mediatek/Makefile
+@@ -3,7 +3,6 @@ obj-y				+= pinctrl-mtk-common.o
+ 
+ # SoC Drivers
+ obj-$(CONFIG_PINCTRL_MT2701)	+= pinctrl-mt2701.o
+-obj-$(CONFIG_PINCTRL_MT7623)	+= pinctrl-mt7623.o
+ obj-$(CONFIG_PINCTRL_MT8135)	+= pinctrl-mt8135.o
+ obj-$(CONFIG_PINCTRL_MT8127)	+= pinctrl-mt8127.o
+ obj-$(CONFIG_PINCTRL_MT8173)	+= pinctrl-mt8173.o
+--- a/drivers/pinctrl/mediatek/pinctrl-mt2701.c
++++ b/drivers/pinctrl/mediatek/pinctrl-mt2701.c
+@@ -565,6 +565,7 @@ static int mt2701_pinctrl_probe(struct p
+ 
+ static const struct of_device_id mt2701_pctrl_match[] = {
+ 	{ .compatible = "mediatek,mt2701-pinctrl", },
++	{ .compatible = "mediatek,mt7623-pinctrl", },
+ 	{}
+ };
+ MODULE_DEVICE_TABLE(of, mt2701_pctrl_match);
+--- a/drivers/pinctrl/mediatek/pinctrl-mt7623.c
++++ /dev/null
+@@ -1,379 +0,0 @@
+-/*
+- * Copyright (c) 2016 John Crispin <[email protected]>
+- *
+- * 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/pinctrl/mt65xx.h>
+-#include <linux/module.h>
+-#include <linux/of.h>
+-#include <linux/of_device.h>
+-#include <linux/platform_device.h>
+-#include <linux/pinctrl/pinctrl.h>
+-#include <linux/regmap.h>
+-
+-#include "pinctrl-mtk-common.h"
+-#include "pinctrl-mtk-mt7623.h"
+-
+-static const struct mtk_drv_group_desc mt7623_drv_grp[] =  {
+-	/* 0E4E8SR 4/8/12/16 */
+-	MTK_DRV_GRP(4, 16, 1, 2, 4),
+-	/* 0E2E4SR  2/4/6/8 */
+-	MTK_DRV_GRP(2, 8, 1, 2, 2),
+-	/* E8E4E2  2/4/6/8/10/12/14/16 */
+-	MTK_DRV_GRP(2, 16, 0, 2, 2)
+-};
+-
+-#define DRV_SEL0	0xf50
+-#define DRV_SEL1	0xf60
+-#define DRV_SEL2	0xf70
+-#define DRV_SEL3	0xf80
+-#define DRV_SEL4	0xf90
+-#define DRV_SEL5	0xfa0
+-#define DRV_SEL6	0xfb0
+-#define DRV_SEL7	0xfe0
+-#define DRV_SEL8	0xfd0
+-#define DRV_SEL9	0xff0
+-#define DRV_SEL10	0xf00
+-
+-#define MSDC0_CTRL0	0xcc0
+-#define MSDC0_CTRL1	0xcd0
+-#define MSDC0_CTRL2	0xce0
+-#define MSDC0_CTRL3	0xcf0
+-#define MSDC0_CTRL4	0xd00
+-#define MSDC0_CTRL5	0xd10
+-#define MSDC0_CTRL6	0xd20
+-#define MSDC1_CTRL0	0xd30
+-#define MSDC1_CTRL1	0xd40
+-#define MSDC1_CTRL2	0xd50
+-#define MSDC1_CTRL3	0xd60
+-#define MSDC1_CTRL4	0xd70
+-#define MSDC1_CTRL5	0xd80
+-#define MSDC1_CTRL6	0xd90
+-
+-#define IES_EN0		0xb20
+-#define IES_EN1		0xb30
+-#define IES_EN2		0xb40
+-
+-#define SMT_EN0		0xb50
+-#define SMT_EN1		0xb60
+-#define SMT_EN2		0xb70
+-
+-static const struct mtk_pin_drv_grp mt7623_pin_drv[] = {
+-	MTK_PIN_DRV_GRP(0, DRV_SEL0, 0, 1),
+-	MTK_PIN_DRV_GRP(1, DRV_SEL0, 0, 1),
+-	MTK_PIN_DRV_GRP(2, DRV_SEL0, 0, 1),
+-	MTK_PIN_DRV_GRP(3, DRV_SEL0, 0, 1),
+-	MTK_PIN_DRV_GRP(4, DRV_SEL0, 0, 1),
+-	MTK_PIN_DRV_GRP(5, DRV_SEL0, 0, 1),
+-	MTK_PIN_DRV_GRP(6, DRV_SEL0, 0, 1),
+-	MTK_PIN_DRV_GRP(7, DRV_SEL0, 4, 1),
+-	MTK_PIN_DRV_GRP(8, DRV_SEL0, 4, 1),
+-	MTK_PIN_DRV_GRP(9, DRV_SEL0, 4, 1),
+-	MTK_PIN_DRV_GRP(10, DRV_SEL0, 8, 1),
+-	MTK_PIN_DRV_GRP(11, DRV_SEL0, 8, 1),
+-	MTK_PIN_DRV_GRP(12, DRV_SEL0, 8, 1),
+-	MTK_PIN_DRV_GRP(13, DRV_SEL0, 8, 1),
+-	MTK_PIN_DRV_GRP(14, DRV_SEL0, 12, 0),
+-	MTK_PIN_DRV_GRP(15, DRV_SEL0, 12, 0),
+-	MTK_PIN_DRV_GRP(18, DRV_SEL1, 4, 0),
+-	MTK_PIN_DRV_GRP(19, DRV_SEL1, 4, 0),
+-	MTK_PIN_DRV_GRP(20, DRV_SEL1, 4, 0),
+-	MTK_PIN_DRV_GRP(21, DRV_SEL1, 4, 0),
+-	MTK_PIN_DRV_GRP(22, DRV_SEL1, 8, 0),
+-	MTK_PIN_DRV_GRP(23, DRV_SEL1, 8, 0),
+-	MTK_PIN_DRV_GRP(24, DRV_SEL1, 8, 0),
+-	MTK_PIN_DRV_GRP(25, DRV_SEL1, 8, 0),
+-	MTK_PIN_DRV_GRP(26, DRV_SEL1, 8, 0),
+-	MTK_PIN_DRV_GRP(27, DRV_SEL1, 12, 0),
+-	MTK_PIN_DRV_GRP(28, DRV_SEL1, 12, 0),
+-	MTK_PIN_DRV_GRP(29, DRV_SEL1, 12, 0),
+-	MTK_PIN_DRV_GRP(33, DRV_SEL2, 0, 0),
+-	MTK_PIN_DRV_GRP(34, DRV_SEL2, 0, 0),
+-	MTK_PIN_DRV_GRP(35, DRV_SEL2, 0, 0),
+-	MTK_PIN_DRV_GRP(36, DRV_SEL2, 0, 0),
+-	MTK_PIN_DRV_GRP(37, DRV_SEL2, 0, 0),
+-	MTK_PIN_DRV_GRP(39, DRV_SEL2, 8, 1),
+-	MTK_PIN_DRV_GRP(40, DRV_SEL2, 8, 1),
+-	MTK_PIN_DRV_GRP(41, DRV_SEL2, 8, 1),
+-	MTK_PIN_DRV_GRP(42, DRV_SEL2, 8, 1),
+-	MTK_PIN_DRV_GRP(43, DRV_SEL2, 12, 0),
+-	MTK_PIN_DRV_GRP(44, DRV_SEL2, 12, 0),
+-	MTK_PIN_DRV_GRP(45, DRV_SEL2, 12, 0),
+-	MTK_PIN_DRV_GRP(47, DRV_SEL3, 0, 0),
+-	MTK_PIN_DRV_GRP(48, DRV_SEL3, 0, 0),
+-	MTK_PIN_DRV_GRP(49, DRV_SEL3, 4, 0),
+-	MTK_PIN_DRV_GRP(53, DRV_SEL3, 12, 0),
+-	MTK_PIN_DRV_GRP(54, DRV_SEL3, 12, 0),
+-	MTK_PIN_DRV_GRP(55, DRV_SEL3, 12, 0),
+-	MTK_PIN_DRV_GRP(56, DRV_SEL3, 12, 0),
+-	MTK_PIN_DRV_GRP(60, DRV_SEL4, 8, 1),
+-	MTK_PIN_DRV_GRP(61, DRV_SEL4, 8, 1),
+-	MTK_PIN_DRV_GRP(62, DRV_SEL4, 8, 1),
+-	MTK_PIN_DRV_GRP(63, DRV_SEL4, 12, 1),
+-	MTK_PIN_DRV_GRP(64, DRV_SEL4, 12, 1),
+-	MTK_PIN_DRV_GRP(65, DRV_SEL4, 12, 1),
+-	MTK_PIN_DRV_GRP(66, DRV_SEL5, 0, 1),
+-	MTK_PIN_DRV_GRP(67, DRV_SEL5, 0, 1),
+-	MTK_PIN_DRV_GRP(68, DRV_SEL5, 0, 1),
+-	MTK_PIN_DRV_GRP(69, DRV_SEL5, 0, 1),
+-	MTK_PIN_DRV_GRP(70, DRV_SEL5, 0, 1),
+-	MTK_PIN_DRV_GRP(71, DRV_SEL5, 0, 1),
+-	MTK_PIN_DRV_GRP(72, DRV_SEL3, 4, 0),
+-	MTK_PIN_DRV_GRP(73, DRV_SEL3, 4, 0),
+-	MTK_PIN_DRV_GRP(74, DRV_SEL3, 4, 0),
+-	MTK_PIN_DRV_GRP(83, DRV_SEL5, 0, 1),
+-	MTK_PIN_DRV_GRP(84, DRV_SEL5, 0, 1),
+-	MTK_PIN_DRV_GRP(105, MSDC1_CTRL1, 0, 1),
+-	MTK_PIN_DRV_GRP(106, MSDC1_CTRL0, 0, 1),
+-	MTK_PIN_DRV_GRP(107, MSDC1_CTRL2, 0, 1),
+-	MTK_PIN_DRV_GRP(108, MSDC1_CTRL2, 0, 1),
+-	MTK_PIN_DRV_GRP(109, MSDC1_CTRL2, 0, 1),
+-	MTK_PIN_DRV_GRP(110, MSDC1_CTRL2, 0, 1),
+-	MTK_PIN_DRV_GRP(111, MSDC0_CTRL2, 0, 1),
+-	MTK_PIN_DRV_GRP(112, MSDC0_CTRL2, 0, 1),
+-	MTK_PIN_DRV_GRP(113, MSDC0_CTRL2, 0, 1),
+-	MTK_PIN_DRV_GRP(114, MSDC0_CTRL2, 0, 1),
+-	MTK_PIN_DRV_GRP(115, MSDC0_CTRL2, 0, 1),
+-	MTK_PIN_DRV_GRP(116, MSDC0_CTRL1, 0, 1),
+-	MTK_PIN_DRV_GRP(117, MSDC0_CTRL0, 0, 1),
+-	MTK_PIN_DRV_GRP(118, MSDC0_CTRL2, 0, 1),
+-	MTK_PIN_DRV_GRP(119, MSDC0_CTRL2, 0, 1),
+-	MTK_PIN_DRV_GRP(120, MSDC0_CTRL2, 0, 1),
+-	MTK_PIN_DRV_GRP(121, MSDC0_CTRL2, 0, 1),
+-	MTK_PIN_DRV_GRP(126, DRV_SEL3, 4, 0),
+-	MTK_PIN_DRV_GRP(199, DRV_SEL0, 4, 1),
+-	MTK_PIN_DRV_GRP(200, DRV_SEL8, 0, 0),
+-	MTK_PIN_DRV_GRP(201, DRV_SEL8, 0, 0),
+-	MTK_PIN_DRV_GRP(203, DRV_SEL8, 4, 0),
+-	MTK_PIN_DRV_GRP(204, DRV_SEL8, 4, 0),
+-	MTK_PIN_DRV_GRP(205, DRV_SEL8, 4, 0),
+-	MTK_PIN_DRV_GRP(206, DRV_SEL8, 4, 0),
+-	MTK_PIN_DRV_GRP(207, DRV_SEL8, 4, 0),
+-	MTK_PIN_DRV_GRP(208, DRV_SEL8, 8, 0),
+-	MTK_PIN_DRV_GRP(209, DRV_SEL8, 8, 0),
+-	MTK_PIN_DRV_GRP(236, DRV_SEL9, 4, 0),
+-	MTK_PIN_DRV_GRP(237, DRV_SEL9, 4, 0),
+-	MTK_PIN_DRV_GRP(238, DRV_SEL9, 4, 0),
+-	MTK_PIN_DRV_GRP(239, DRV_SEL9, 4, 0),
+-	MTK_PIN_DRV_GRP(240, DRV_SEL9, 4, 0),
+-	MTK_PIN_DRV_GRP(241, DRV_SEL9, 4, 0),
+-	MTK_PIN_DRV_GRP(242, DRV_SEL9, 8, 0),
+-	MTK_PIN_DRV_GRP(243, DRV_SEL9, 8, 0),
+-	MTK_PIN_DRV_GRP(257, MSDC0_CTRL2, 0, 1),
+-	MTK_PIN_DRV_GRP(261, MSDC1_CTRL2, 0, 1),
+-	MTK_PIN_DRV_GRP(262, DRV_SEL10, 8, 0),
+-	MTK_PIN_DRV_GRP(263, DRV_SEL10, 8, 0),
+-	MTK_PIN_DRV_GRP(264, DRV_SEL10, 8, 0),
+-	MTK_PIN_DRV_GRP(265, DRV_SEL10, 8, 0),
+-	MTK_PIN_DRV_GRP(266, DRV_SEL10, 8, 0),
+-	MTK_PIN_DRV_GRP(267, DRV_SEL10, 8, 0),
+-	MTK_PIN_DRV_GRP(268, DRV_SEL10, 8, 0),
+-	MTK_PIN_DRV_GRP(269, DRV_SEL10, 8, 0),
+-	MTK_PIN_DRV_GRP(270, DRV_SEL10, 8, 0),
+-	MTK_PIN_DRV_GRP(271, DRV_SEL10, 8, 0),
+-	MTK_PIN_DRV_GRP(272, DRV_SEL10, 8, 0),
+-	MTK_PIN_DRV_GRP(274, DRV_SEL10, 8, 0),
+-	MTK_PIN_DRV_GRP(275, DRV_SEL10, 8, 0),
+-	MTK_PIN_DRV_GRP(276, DRV_SEL10, 8, 0),
+-	MTK_PIN_DRV_GRP(278, DRV_SEL2, 8, 1),
+-};
+-
+-static const struct mtk_pin_spec_pupd_set_samereg mt7623_spec_pupd[] = {
+-	MTK_PIN_PUPD_SPEC_SR(105, MSDC1_CTRL1, 8, 9, 10),
+-	MTK_PIN_PUPD_SPEC_SR(106, MSDC1_CTRL0, 8, 9, 10),
+-	MTK_PIN_PUPD_SPEC_SR(107, MSDC1_CTRL3, 0, 1, 2),
+-	MTK_PIN_PUPD_SPEC_SR(108, MSDC1_CTRL3, 4, 5, 6),
+-	MTK_PIN_PUPD_SPEC_SR(109, MSDC1_CTRL3, 8, 9, 10),
+-	MTK_PIN_PUPD_SPEC_SR(110, MSDC1_CTRL3, 12, 13, 14),
+-	MTK_PIN_PUPD_SPEC_SR(111, MSDC0_CTRL4, 12, 13, 14),
+-	MTK_PIN_PUPD_SPEC_SR(112, MSDC0_CTRL4, 8, 9, 10),
+-	MTK_PIN_PUPD_SPEC_SR(113, MSDC0_CTRL4, 4, 5, 6),
+-	MTK_PIN_PUPD_SPEC_SR(114, MSDC0_CTRL4, 0, 1, 2),
+-	MTK_PIN_PUPD_SPEC_SR(115, MSDC0_CTRL5, 0, 1, 2),
+-	MTK_PIN_PUPD_SPEC_SR(116, MSDC0_CTRL1, 8, 9, 10),
+-	MTK_PIN_PUPD_SPEC_SR(117, MSDC0_CTRL0, 8, 9, 10),
+-	MTK_PIN_PUPD_SPEC_SR(118, MSDC0_CTRL3, 12, 13, 14),
+-	MTK_PIN_PUPD_SPEC_SR(119, MSDC0_CTRL3, 8, 9, 10),
+-	MTK_PIN_PUPD_SPEC_SR(120, MSDC0_CTRL3, 4, 5, 6),
+-	MTK_PIN_PUPD_SPEC_SR(121, MSDC0_CTRL3, 0, 1, 2),
+-};
+-
+-static int mt7623_spec_pull_set(struct regmap *regmap, unsigned int pin,
+-		unsigned char align, bool isup, unsigned int r1r0)
+-{
+-	return mtk_pctrl_spec_pull_set_samereg(regmap, mt7623_spec_pupd,
+-		ARRAY_SIZE(mt7623_spec_pupd), pin, align, isup, r1r0);
+-}
+-
+-static const struct mtk_pin_ies_smt_set mt7623_ies_set[] = {
+-	MTK_PIN_IES_SMT_SPEC(0, 6, IES_EN0, 0),
+-	MTK_PIN_IES_SMT_SPEC(7, 9, IES_EN0, 1),
+-	MTK_PIN_IES_SMT_SPEC(10, 13, IES_EN0, 2),
+-	MTK_PIN_IES_SMT_SPEC(14, 15, IES_EN0, 3),
+-	MTK_PIN_IES_SMT_SPEC(18, 21, IES_EN0, 5),
+-	MTK_PIN_IES_SMT_SPEC(22, 26, IES_EN0, 6),
+-	MTK_PIN_IES_SMT_SPEC(27, 29, IES_EN0, 7),
+-	MTK_PIN_IES_SMT_SPEC(33, 37, IES_EN0, 8),
+-	MTK_PIN_IES_SMT_SPEC(39, 42, IES_EN0, 9),
+-	MTK_PIN_IES_SMT_SPEC(43, 45, IES_EN0, 10),
+-	MTK_PIN_IES_SMT_SPEC(47, 48, IES_EN0, 11),
+-	MTK_PIN_IES_SMT_SPEC(49, 49, IES_EN0, 12),
+-	MTK_PIN_IES_SMT_SPEC(53, 56, IES_EN0, 14),
+-	MTK_PIN_IES_SMT_SPEC(60, 62, IES_EN1, 0),
+-	MTK_PIN_IES_SMT_SPEC(63, 65, IES_EN1, 1),
+-	MTK_PIN_IES_SMT_SPEC(66, 71, IES_EN1, 2),
+-	MTK_PIN_IES_SMT_SPEC(72, 74, IES_EN0, 12),
+-	MTK_PIN_IES_SMT_SPEC(75, 76, IES_EN1, 3),
+-	MTK_PIN_IES_SMT_SPEC(83, 84, IES_EN1, 2),
+-	MTK_PIN_IES_SMT_SPEC(105, 121, MSDC1_CTRL1, 4),
+-	MTK_PIN_IES_SMT_SPEC(122, 125, IES_EN1, 7),
+-	MTK_PIN_IES_SMT_SPEC(126, 126, IES_EN0, 12),
+-	MTK_PIN_IES_SMT_SPEC(199, 201, IES_EN0, 1),
+-	MTK_PIN_IES_SMT_SPEC(203, 207, IES_EN2, 2),
+-	MTK_PIN_IES_SMT_SPEC(208, 209, IES_EN2, 3),
+-	MTK_PIN_IES_SMT_SPEC(236, 241, IES_EN2, 6),
+-	MTK_PIN_IES_SMT_SPEC(242, 243, IES_EN2, 7),
+-	MTK_PIN_IES_SMT_SPEC(261, 261, MSDC1_CTRL2, 4),
+-	MTK_PIN_IES_SMT_SPEC(262, 272, IES_EN2, 12),
+-	MTK_PIN_IES_SMT_SPEC(274, 276, IES_EN2, 12),
+-	MTK_PIN_IES_SMT_SPEC(278, 278, IES_EN2, 13),
+-};
+-
+-static const struct mtk_pin_ies_smt_set mt7623_smt_set[] = {
+-	MTK_PIN_IES_SMT_SPEC(0, 6, SMT_EN0, 0),
+-	MTK_PIN_IES_SMT_SPEC(7, 9, SMT_EN0, 1),
+-	MTK_PIN_IES_SMT_SPEC(10, 13, SMT_EN0, 2),
+-	MTK_PIN_IES_SMT_SPEC(14, 15, SMT_EN0, 3),
+-	MTK_PIN_IES_SMT_SPEC(18, 21, SMT_EN0, 5),
+-	MTK_PIN_IES_SMT_SPEC(22, 26, SMT_EN0, 6),
+-	MTK_PIN_IES_SMT_SPEC(27, 29, SMT_EN0, 7),
+-	MTK_PIN_IES_SMT_SPEC(33, 37, SMT_EN0, 8),
+-	MTK_PIN_IES_SMT_SPEC(39, 42, SMT_EN0, 9),
+-	MTK_PIN_IES_SMT_SPEC(43, 45, SMT_EN0, 10),
+-	MTK_PIN_IES_SMT_SPEC(47, 48, SMT_EN0, 11),
+-	MTK_PIN_IES_SMT_SPEC(49, 49, SMT_EN0, 12),
+-	MTK_PIN_IES_SMT_SPEC(53, 56, SMT_EN0, 14),
+-	MTK_PIN_IES_SMT_SPEC(60, 62, SMT_EN1, 0),
+-	MTK_PIN_IES_SMT_SPEC(63, 65, SMT_EN1, 1),
+-	MTK_PIN_IES_SMT_SPEC(66, 71, SMT_EN1, 2),
+-	MTK_PIN_IES_SMT_SPEC(72, 74, SMT_EN0, 12),
+-	MTK_PIN_IES_SMT_SPEC(75, 76, SMT_EN1, 3),
+-	MTK_PIN_IES_SMT_SPEC(83, 84, SMT_EN1, 2),
+-	MTK_PIN_IES_SMT_SPEC(105, 106, MSDC1_CTRL1, 11),
+-	MTK_PIN_IES_SMT_SPEC(107, 107, MSDC1_CTRL3, 3),
+-	MTK_PIN_IES_SMT_SPEC(108, 108, MSDC1_CTRL3, 7),
+-	MTK_PIN_IES_SMT_SPEC(109, 109, MSDC1_CTRL3, 11),
+-	MTK_PIN_IES_SMT_SPEC(110, 111, MSDC1_CTRL3, 15),
+-	MTK_PIN_IES_SMT_SPEC(112, 112, MSDC0_CTRL4, 11),
+-	MTK_PIN_IES_SMT_SPEC(113, 113, MSDC0_CTRL4, 7),
+-	MTK_PIN_IES_SMT_SPEC(114, 115, MSDC0_CTRL4, 3),
+-	MTK_PIN_IES_SMT_SPEC(116, 117, MSDC0_CTRL1, 11),
+-	MTK_PIN_IES_SMT_SPEC(118, 118, MSDC0_CTRL3, 15),
+-	MTK_PIN_IES_SMT_SPEC(119, 119, MSDC0_CTRL3, 11),
+-	MTK_PIN_IES_SMT_SPEC(120, 120, MSDC0_CTRL3, 7),
+-	MTK_PIN_IES_SMT_SPEC(121, 121, MSDC0_CTRL3, 3),
+-	MTK_PIN_IES_SMT_SPEC(122, 125, SMT_EN1, 7),
+-	MTK_PIN_IES_SMT_SPEC(126, 126, SMT_EN0, 12),
+-	MTK_PIN_IES_SMT_SPEC(199, 201, SMT_EN0, 1),
+-	MTK_PIN_IES_SMT_SPEC(203, 207, SMT_EN2, 2),
+-	MTK_PIN_IES_SMT_SPEC(208, 209, SMT_EN2, 3),
+-	MTK_PIN_IES_SMT_SPEC(236, 241, SMT_EN2, 6),
+-	MTK_PIN_IES_SMT_SPEC(242, 243, SMT_EN2, 7),
+-	MTK_PIN_IES_SMT_SPEC(261, 261, MSDC1_CTRL6, 3),
+-	MTK_PIN_IES_SMT_SPEC(262, 272, SMT_EN2, 12),
+-	MTK_PIN_IES_SMT_SPEC(274, 276, SMT_EN2, 12),
+-	MTK_PIN_IES_SMT_SPEC(278, 278, SMT_EN2, 13),
+-};
+-
+-static int mt7623_ies_smt_set(struct regmap *regmap, unsigned int pin,
+-		unsigned char align, int value, enum pin_config_param arg)
+-{
+-	if (arg == PIN_CONFIG_INPUT_ENABLE)
+-		return mtk_pconf_spec_set_ies_smt_range(regmap, mt7623_ies_set,
+-			ARRAY_SIZE(mt7623_ies_set), pin, align, value);
+-	else if (arg == PIN_CONFIG_INPUT_SCHMITT_ENABLE)
+-		return mtk_pconf_spec_set_ies_smt_range(regmap, mt7623_smt_set,
+-			ARRAY_SIZE(mt7623_smt_set), pin, align, value);
+-	return -EINVAL;
+-}
+-
+-static const struct mtk_pinctrl_devdata mt7623_pinctrl_data = {
+-	.pins = mtk_pins_mt7623,
+-	.npins = ARRAY_SIZE(mtk_pins_mt7623),
+-	.grp_desc = mt7623_drv_grp,
+-	.n_grp_cls = ARRAY_SIZE(mt7623_drv_grp),
+-	.pin_drv_grp = mt7623_pin_drv,
+-	.n_pin_drv_grps = ARRAY_SIZE(mt7623_pin_drv),
+-	.spec_pull_set = mt7623_spec_pull_set,
+-	.spec_ies_smt_set = mt7623_ies_smt_set,
+-	.dir_offset = 0x0000,
+-	.pullen_offset = 0x0150,
+-	.pullsel_offset = 0x0280,
+-	.dout_offset = 0x0500,
+-	.din_offset = 0x0630,
+-	.pinmux_offset = 0x0760,
+-	.type1_start = 280,
+-	.type1_end = 280,
+-	.port_shf = 4,
+-	.port_mask = 0x1f,
+-	.port_align = 4,
+-	.eint_offsets = {
+-		.name = "mt7623_eint",
+-		.stat      = 0x000,
+-		.ack       = 0x040,
+-		.mask      = 0x080,
+-		.mask_set  = 0x0c0,
+-		.mask_clr  = 0x100,
+-		.sens      = 0x140,
+-		.sens_set  = 0x180,
+-		.sens_clr  = 0x1c0,
+-		.soft      = 0x200,
+-		.soft_set  = 0x240,
+-		.soft_clr  = 0x280,
+-		.pol       = 0x300,
+-		.pol_set   = 0x340,
+-		.pol_clr   = 0x380,
+-		.dom_en    = 0x400,
+-		.dbnc_ctrl = 0x500,
+-		.dbnc_set  = 0x600,
+-		.dbnc_clr  = 0x700,
+-		.port_mask = 6,
+-		.ports     = 6,
+-	},
+-	.ap_num = 169,
+-	.db_cnt = 16,
+-};
+-
+-static int mt7623_pinctrl_probe(struct platform_device *pdev)
+-{
+-	return mtk_pctrl_init(pdev, &mt7623_pinctrl_data, NULL);
+-}
+-
+-static const struct of_device_id mt7623_pctrl_match[] = {
+-	{ .compatible = "mediatek,mt7623-pinctrl", },
+-	{}
+-};
+-MODULE_DEVICE_TABLE(of, mt7623_pctrl_match);
+-
+-static struct platform_driver mtk_pinctrl_driver = {
+-	.probe = mt7623_pinctrl_probe,
+-	.driver = {
+-		.name = "mediatek-mt7623-pinctrl",
+-		.of_match_table = mt7623_pctrl_match,
+-	},
+-};
+-
+-static int __init mtk_pinctrl_init(void)
+-{
+-	return platform_driver_register(&mtk_pinctrl_driver);
+-}
+-
+-arch_initcall(mtk_pinctrl_init);
+--- a/include/dt-bindings/pinctrl/mt7623-pinfunc.h
++++ b/include/dt-bindings/pinctrl/mt7623-pinfunc.h
+@@ -185,6 +185,12 @@
+ #define MT7623_PIN_56_SPI0_MO_FUNC_SPI0_MO (MTK_PIN_NO(56) | 1)
+ #define MT7623_PIN_56_SPI0_MO_FUNC_SPI0_MI (MTK_PIN_NO(56) | 2)
+ 
++#define MT7623_PIN_57_SDA1_FUNC_GPIO57 (MTK_PIN_NO(57) | 0)
++#define MT7623_PIN_57_SDA1_FUNC_SDA1 (MTK_PIN_NO(57) | 1)
++
++#define MT7623_PIN_58_SCL1_FUNC_GPIO58 (MTK_PIN_NO(58) | 0)
++#define MT7623_PIN_58_SCL1_FUNC_SCL1 (MTK_PIN_NO(58) | 1)
++
+ #define MT7623_PIN_60_WB_RSTB_FUNC_GPIO60 (MTK_PIN_NO(60) | 0)
+ #define MT7623_PIN_60_WB_RSTB_FUNC_WB_RSTB (MTK_PIN_NO(60) | 1)
+ 
+@@ -244,6 +250,22 @@
+ #define MT7623_PIN_76_SCL0_FUNC_GPIO76 (MTK_PIN_NO(76) | 0)
+ #define MT7623_PIN_76_SCL0_FUNC_SCL0 (MTK_PIN_NO(76) | 1)
+ 
++#define MT7623_PIN_79_URXD0_FUNC_GPIO79 (MTK_PIN_NO(79) | 0)
++#define MT7623_PIN_79_URXD0_FUNC_URXD0 (MTK_PIN_NO(79) | 1)
++#define MT7623_PIN_79_URXD0_FUNC_UTXD0 (MTK_PIN_NO(79) | 2)
++
++#define MT7623_PIN_80_UTXD0_FUNC_GPIO80 (MTK_PIN_NO(80) | 0)
++#define MT7623_PIN_80_UTXD0_FUNC_UTXD0 (MTK_PIN_NO(80) | 1)
++#define MT7623_PIN_80_UTXD0_FUNC_URXD0 (MTK_PIN_NO(80) | 2)
++
++#define MT7623_PIN_81_URXD1_FUNC_GPIO81 (MTK_PIN_NO(81) | 0)
++#define MT7623_PIN_81_URXD1_FUNC_URXD1 (MTK_PIN_NO(81) | 1)
++#define MT7623_PIN_81_URXD1_FUNC_UTXD1 (MTK_PIN_NO(81) | 2)
++
++#define MT7623_PIN_82_UTXD1_FUNC_GPIO82 (MTK_PIN_NO(82) | 0)
++#define MT7623_PIN_82_UTXD1_FUNC_UTXD1 (MTK_PIN_NO(82) | 1)
++#define MT7623_PIN_82_UTXD1_FUNC_URXD1 (MTK_PIN_NO(82) | 2)
++
+ #define MT7623_PIN_83_LCM_RST_FUNC_GPIO83 (MTK_PIN_NO(83) | 0)
+ #define MT7623_PIN_83_LCM_RST_FUNC_LCM_RST (MTK_PIN_NO(83) | 1)
+ 
+@@ -351,10 +373,10 @@
+ #define MT7623_PIN_122_GPIO122_FUNC_SDA2 (MTK_PIN_NO(122) | 4)
+ #define MT7623_PIN_122_GPIO122_FUNC_URXD0 (MTK_PIN_NO(122) | 5)
+ 
+-#define MT7623_PIN_123_GPIO123_FUNC_GPIO123 (MTK_PIN_NO(123) | 0)
+-#define MT7623_PIN_123_GPIO123_FUNC_TEST (MTK_PIN_NO(123) | 1)
+-#define MT7623_PIN_123_GPIO123_FUNC_SCL2 (MTK_PIN_NO(123) | 4)
+-#define MT7623_PIN_123_GPIO123_FUNC_UTXD0 (MTK_PIN_NO(123) | 5)
++#define MT7623_PIN_123_HTPLG_FUNC_GPIO123 (MTK_PIN_NO(123) | 0)
++#define MT7623_PIN_123_HTPLG_FUNC_HTPLG (MTK_PIN_NO(123) | 1)
++#define MT7623_PIN_123_HTPLG_FUNC_SCL2 (MTK_PIN_NO(123) | 4)
++#define MT7623_PIN_123_HTPLG_FUNC_UTXD0 (MTK_PIN_NO(123) | 5)
+ 
+ #define MT7623_PIN_124_GPIO124_FUNC_GPIO124 (MTK_PIN_NO(124) | 0)
+ #define MT7623_PIN_124_GPIO124_FUNC_TEST (MTK_PIN_NO(124) | 1)

+ 531 - 0
target/linux/mediatek/patches-4.9/0059-eth-fixes.patch

@@ -0,0 +1,531 @@
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -24,6 +24,7 @@
+ #include <linux/tcp.h>
+ 
+ #if defined(CONFIG_NET_MEDIATEK_HW_QOS)
++
+ struct mtk_ioctl_reg {
+ 	unsigned int off;
+ 	unsigned int val;
+@@ -32,6 +33,13 @@ struct mtk_ioctl_reg {
+ #define REG_HQOS_MAX			0x3FFF
+ #define RAETH_QDMA_REG_READ		0x89F8
+ #define RAETH_QDMA_REG_WRITE		0x89F9
++#define RAETH_QDMA_QUEUE_MAPPING        0x89FA
++
++unsigned int M2Q_table[16] = {0};
++unsigned int lan_wan_separate = 0;
++
++EXPORT_SYMBOL_GPL(M2Q_table);
++
+ #endif
+ 
+ #if defined(CONFIG_NET_MEDIATEK_HNAT) || defined(CONFIG_NET_MEDIATEK_HNAT_MODULE)
+@@ -225,7 +233,7 @@ static void mtk_phy_link_adjust(struct n
+ 		if (flowctrl & FLOW_CTRL_RX)
+ 			mcr |= MAC_MCR_FORCE_RX_FC;
+ 
+-		netif_dbg(mac->hw, link, dev, "rx pause %s, tx pause %s\n",
++		netif_info(mac->hw, link, dev, "rx pause %s, tx pause %s\n",
+ 			  flowctrl & FLOW_CTRL_RX ? "enabled" : "disabled",
+ 			  flowctrl & FLOW_CTRL_TX ? "enabled" : "disabled");
+ 	}
+@@ -508,9 +516,9 @@ static struct rtnl_link_stats64 * mtk_ge
+ 	unsigned int start;
+ 
+ 	if (netif_running(dev) && netif_device_present(dev)) {
+-		if (spin_trylock_bh(&hw_stats->stats_lock)) {
++		if (spin_trylock(&hw_stats->stats_lock)) {
+ 			mtk_stats_update_mac(mac);
+-			spin_unlock_bh(&hw_stats->stats_lock);
++			spin_unlock(&hw_stats->stats_lock);
+ 		}
+ 	}
+ 
+@@ -690,6 +698,7 @@ static int mtk_tx_map(struct sk_buff *sk
+ 	txd3 |= skb->mark & 0x7;
+ 	if (mac->id)
+ 		txd3 += 8;
++	txd3 = 0;
+ #endif
+ 
+ 	mapped_addr = dma_map_single(eth->dev, skb->data,
+@@ -760,16 +769,7 @@ 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)));
+ 
+-	/* 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);
+-	}
+-
++	netdev_sent_queue(dev, skb->len);
+ 	skb_tx_timestamp(skb);
+ 
+ 	ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2);
+@@ -980,20 +980,9 @@ static int mtk_poll_rx(struct napi_struc
+ 		if (!(trxd.rxd2 & RX_DMA_DONE))
+ 			break;
+ 
+-		/* find out which mac the packet comes from. If the special tag is
+-		 * we can assume that the traffic is coming from the builtin mt7530
+-		 * and the DSA driver has loaded. FPORT will be the physical switch
+-		 * port in this case rather than the FE forward port id. */
+-		if (!(trxd.rxd4 & RX_DMA_SP_TAG)) {
+-			/* values start at 1 */
+-			mac = (trxd.rxd4 >> RX_DMA_FPORT_SHIFT) &
+-			      RX_DMA_FPORT_MASK;
+-			mac--;
+-		}
+-
+-		if (unlikely(mac < 0 || mac >= MTK_MAC_COUNT ||
+-			     !eth->netdev[mac]))
+-			goto release_desc;
++		/* find out which mac the packet come from. values start at 1 */
++		mac = (trxd.rxd4 >> 22) & 0x1;
++		mac = (mac + 1) % 2;
+ 
+ 		netdev = eth->netdev[mac];
+ 
+@@ -1017,6 +1006,9 @@ static int mtk_poll_rx(struct napi_struc
+ 		}
+ 
+ 		/* receive data */
++		if (mac < 0 || mac > 2)
++			mac = 0;
++
+ 		skb = build_skb(data, ring->frag_size);
+ 		if (unlikely(!skb)) {
+ 			skb_free_frag(new_data);
+@@ -1076,18 +1068,21 @@ 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 = 0;
+-	unsigned int bytes = 0;
++	unsigned int done[MTK_MAX_DEVS];
++	unsigned int bytes[MTK_MAX_DEVS];
+ 	u32 cpu, dma;
+ 	static int condition;
+-	int i;
++	int total = 0, 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) && done < budget) {
++	while ((cpu != dma) && budget) {
+ 		u32 next_cpu = desc->txd2;
+ 		int mac = 0;
+ 
+@@ -1106,8 +1101,9 @@ static int mtk_poll_tx(struct mtk_eth *e
+ 		}
+ 
+ 		if (skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC) {
+-			bytes += skb->len;
+-			done++;
++			bytes[mac] += skb->len;
++			done[mac]++;
++			budget--;
+ 		}
+ 		mtk_tx_unmap(eth, tx_buf);
+ 
+@@ -1119,13 +1115,11 @@ 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])
++		if (!eth->netdev[i] || !done[i])
+ 			continue;
+-		netdev_completed_queue(eth->netdev[i], done, bytes);
++		netdev_completed_queue(eth->netdev[i], done[i], bytes[i]);
++		total += done[i];
+ 	}
+ 
+ 	if (mtk_queue_stopped(eth) &&
+@@ -1286,21 +1280,11 @@ static void mtk_tx_clean(struct mtk_eth
+ 
+ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag)
+ {
+-	struct mtk_rx_ring *ring;
++	struct mtk_rx_ring *ring = &eth->rx_ring[ring_no];
+ 	int rx_data_len, rx_dma_size;
+ 	int i;
+-	u32 offset = 0;
+-
+-	if (rx_flag & MTK_RX_FLAGS_QDMA) {
+-		if (ring_no)
+-			return -EINVAL;
+-		ring = &eth->rx_ring_qdma;
+-		offset = 0x1000;
+-	} else {
+-		ring = &eth->rx_ring[ring_no];
+-	}
+ 
+-	if (rx_flag & MTK_RX_FLAGS_HWLRO) {
++	if (rx_flag == MTK_RX_FLAGS_HWLRO) {
+ 		rx_data_len = MTK_MAX_LRO_RX_LENGTH;
+ 		rx_dma_size = MTK_HW_LRO_DMA_SIZE;
+ 	} else {
+@@ -1348,16 +1332,104 @@ static int mtk_rx_alloc(struct mtk_eth *
+ 	 */
+ 	wmb();
+ 
+-	mtk_w32(eth, ring->phys, MTK_PRX_BASE_PTR_CFG(ring_no) + offset);
+-	mtk_w32(eth, rx_dma_size, MTK_PRX_MAX_CNT_CFG(ring_no) + offset);
+-	mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg + offset);
+-	mtk_w32(eth, MTK_PST_DRX_IDX_CFG(ring_no), MTK_PDMA_RST_IDX + offset);
++	mtk_w32(eth, ring->phys, MTK_PRX_BASE_PTR_CFG(ring_no));
++	mtk_w32(eth, rx_dma_size, MTK_PRX_MAX_CNT_CFG(ring_no));
++	mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg);
++	mtk_w32(eth, MTK_PST_DRX_IDX_CFG(ring_no), MTK_PDMA_RST_IDX);
+ 
+ 	return 0;
+ }
+ 
+-static void mtk_rx_clean(struct mtk_eth *eth, struct mtk_rx_ring *ring)
++static int mtk_rx_alloc_qdma(struct mtk_eth *eth, int rx_flag)
+ {
++	struct mtk_rx_ring *ring = &eth->rx_ring_qdma;
++	int rx_data_len, rx_dma_size;
++	int i;
++
++	rx_data_len = ETH_DATA_LEN;
++	rx_dma_size = MTK_DMA_SIZE;
++
++	ring->frag_size = mtk_max_frag_size(rx_data_len);
++	ring->buf_size = mtk_max_buf_size(ring->frag_size);
++	ring->data = kcalloc(rx_dma_size, sizeof(*ring->data),
++			     GFP_KERNEL);
++	if (!ring->data)
++		return -ENOMEM;
++
++	for (i = 0; i < rx_dma_size; i++) {
++		ring->data[i] = netdev_alloc_frag(ring->frag_size);
++		if (!ring->data[i])
++			return -ENOMEM;
++	}
++
++	ring->dma = dma_alloc_coherent(eth->dev,
++				       rx_dma_size * sizeof(*ring->dma),
++				       &ring->phys,
++				       GFP_ATOMIC | __GFP_ZERO);
++	if (!ring->dma)
++		return -ENOMEM;
++
++	for (i = 0; i < rx_dma_size; i++) {
++		dma_addr_t dma_addr = dma_map_single(eth->dev,
++				ring->data[i] + NET_SKB_PAD,
++				ring->buf_size,
++				DMA_FROM_DEVICE);
++		if (unlikely(dma_mapping_error(eth->dev, dma_addr)))
++			return -ENOMEM;
++		ring->dma[i].rxd1 = (unsigned int)dma_addr;
++
++		ring->dma[i].rxd2 = RX_DMA_PLEN0(ring->buf_size);
++	}
++	ring->dma_size = rx_dma_size;
++	ring->calc_idx_update = false;
++	ring->calc_idx = rx_dma_size - 1;
++	ring->crx_idx_reg = MTK_QRX_CRX_IDX_CFG(0);
++	/* make sure that all changes to the dma ring are flushed before we
++	 * continue
++	 */
++	wmb();
++
++	mtk_w32(eth, ring->phys, MTK_QRX_BASE_PTR_CFG(0));
++	mtk_w32(eth, rx_dma_size, MTK_QRX_MAX_CNT_CFG(0));
++	mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg);
++	mtk_w32(eth, MTK_PST_DRX_IDX_CFG(0), MTK_QDMA_RST_IDX);
++
++	return 0;
++}
++
++static void mtk_rx_clean(struct mtk_eth *eth, int ring_no)
++{
++	struct mtk_rx_ring *ring = &eth->rx_ring[ring_no];
++	int i;
++
++	if (ring->data && ring->dma) {
++		for (i = 0; i < ring->dma_size; i++) {
++			if (!ring->data[i])
++				continue;
++			if (!ring->dma[i].rxd1)
++				continue;
++			dma_unmap_single(eth->dev,
++					 ring->dma[i].rxd1,
++					 ring->buf_size,
++					 DMA_FROM_DEVICE);
++			skb_free_frag(ring->data[i]);
++		}
++		kfree(ring->data);
++		ring->data = NULL;
++	}
++
++	if (ring->dma) {
++		dma_free_coherent(eth->dev,
++				  ring->dma_size * sizeof(*ring->dma),
++				  ring->dma,
++				  ring->phys);
++		ring->dma = NULL;
++	}
++}
++
++static void mtk_rx_clean_qdma(struct mtk_eth *eth)
++{
++	struct mtk_rx_ring *ring = &eth->rx_ring_qdma;
+ 	int i;
+ 
+ 	if (ring->data && ring->dma) {
+@@ -1683,7 +1755,7 @@ static int mtk_dma_init(struct mtk_eth *
+ 	if (err)
+ 		return err;
+ 
+-	err = mtk_rx_alloc(eth, 0, MTK_RX_FLAGS_QDMA);
++	err = mtk_rx_alloc_qdma(eth, MTK_RX_FLAGS_NORMAL);
+ 	if (err)
+ 		return err;
+ 
+@@ -1702,6 +1774,7 @@ static int mtk_dma_init(struct mtk_eth *
+ 			return err;
+ 	}
+ 
++
+ 	/* Enable random early drop and set drop threshold automatically */
+ 	mtk_w32(eth, FC_THRES_DROP_MODE | FC_THRES_DROP_EN | FC_THRES_MIN,
+ 		MTK_QDMA_FC_THRES);
+@@ -1726,13 +1799,13 @@ static void mtk_dma_free(struct mtk_eth
+ 		eth->phy_scratch_ring = 0;
+ 	}
+ 	mtk_tx_clean(eth);
+-	mtk_rx_clean(eth, &eth->rx_ring[0]);
+-	mtk_rx_clean(eth, &eth->rx_ring_qdma);
++	mtk_rx_clean(eth, 0);
++	mtk_rx_clean_qdma(eth);
+ 
+ 	if (eth->hwlro) {
+ 		mtk_hwlro_rx_uninit(eth);
+ 		for (i = 1; i < MTK_MAX_RX_RING_NUM; i++)
+-			mtk_rx_clean(eth, &eth->rx_ring[i]);
++			mtk_rx_clean(eth, i);
+ 	}
+ 
+ 	kfree(eth->scratch_head);
+@@ -1947,20 +2020,14 @@ static int mtk_hw_init(struct mtk_eth *e
+ 	val = mtk_r32(eth, MTK_CDMQ_IG_CTRL);
+ 	mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL);
+ 
+-	/* Indicates CDM to parse the MTK special tag from CPU
+-	 * which also is working out for untag packets.
+-	 */
+-	val = mtk_r32(eth, MTK_CDMQ_IG_CTRL);
+-	mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL);
+-	val = mtk_r32(eth, MTK_CDMP_IG_CTRL);
+-	mtk_w32(eth, val | MTK_CDMP_STAG_EN, MTK_CDMP_IG_CTRL);
+-
+ 	/* Enable RX VLan Offloading */
+ 	if (MTK_HW_FEATURES & NETIF_F_HW_VLAN_CTAG_RX)
+ 		mtk_w32(eth, 1, MTK_CDMP_EG_CTRL);
+ 	else
+ 		mtk_w32(eth, 0, MTK_CDMP_EG_CTRL);
+ 
++	mtk_w32(eth, 0x81000001, MTK_CDMP_IG_CTRL);
++
+ 	/* disable delay and normal interrupt */
+ #ifdef MTK_IRQ_DLY
+ 	mtk_w32(eth, 0x84048404, MTK_PDMA_DELAY_INT);
+@@ -1990,6 +2057,9 @@ static int mtk_hw_init(struct mtk_eth *e
+ 		/* Enable RX checksum */
+ 		val |= MTK_GDMA_ICS_EN | MTK_GDMA_TCS_EN | MTK_GDMA_UCS_EN;
+ 
++		if (!i)
++			val |= BIT(24);
++
+ 		/* setup the mac dma */
+ 		mtk_w32(eth, val, MTK_GDMA_FWD_CFG(i));
+ 	}
+@@ -2069,7 +2139,18 @@ static int mtk_do_ioctl(struct net_devic
+ 		if (reg.off > REG_HQOS_MAX)
+ 			return -EINVAL;
+ 		mtk_w32(eth, reg.val, 0x1800 + reg.off);
+-//		printk("write reg off:%x val:%x\n", reg.off, reg.val);
++		printk("write reg off:%x val:%x\n", reg.off, reg.val);
++		return 0;
++
++	case RAETH_QDMA_QUEUE_MAPPING:
++		copy_from_user(&reg, ifr->ifr_data, sizeof(reg));
++		if ((reg.off & 0x100) == 0x100) {
++			lan_wan_separate = 1;
++			reg.off &= 0xff;
++		} else {
++			lan_wan_separate = 0;
++		}
++		M2Q_table[reg.off] = reg.val;
+ 		return 0;
+ #endif
+ 	case SIOCGMIIPHY:
+@@ -2288,9 +2369,9 @@ static void mtk_get_ethtool_stats(struct
+ 		return;
+ 
+ 	if (netif_running(dev) && netif_device_present(dev)) {
+-		if (spin_trylock_bh(&hwstats->stats_lock)) {
++		if (spin_trylock(&hwstats->stats_lock)) {
+ 			mtk_stats_update_mac(mac);
+-			spin_unlock_bh(&hwstats->stats_lock);
++			spin_unlock(&hwstats->stats_lock);
+ 		}
+ 	}
+ 
+@@ -2443,7 +2524,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 = 30 * HZ;
++	eth->netdev[id]->watchdog_timeo = 15 * HZ;
+ 	eth->netdev[id]->netdev_ops = &mtk_netdev_ops;
+ 	eth->netdev[id]->base_addr = (unsigned long)eth->base;
+ 
+@@ -2584,15 +2665,19 @@ static int mtk_probe(struct platform_dev
+ 			goto err_deinit_hw;
+ 	}
+ 
++	cpumask_set_cpu(1, &eth->affinity_mask[1]);
++	cpumask_set_cpu(0, &eth->affinity_mask[2]);
+ 	err = devm_request_irq(eth->dev, eth->irq[1], mtk_handle_irq_tx, 0,
+ 			       dev_name(eth->dev), eth);
+ 	if (err)
+ 		goto err_free_dev;
++	irq_set_affinity_hint(eth->irq[1], &eth->affinity_mask[1]);
+ 
+ 	err = devm_request_irq(eth->dev, eth->irq[2], mtk_handle_irq_rx, 0,
+ 			       dev_name(eth->dev), eth);
+ 	if (err)
+ 		goto err_free_dev;
++	irq_set_affinity_hint(eth->irq[2], &eth->affinity_mask[2]);
+ 
+ 	err = mtk_mdio_init(eth);
+ 	if (err)
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -80,7 +80,6 @@
+ 
+ /* CDMP Ingress Control Register */
+ #define MTK_CDMP_IG_CTRL	0x400
+-#define MTK_CDMP_STAG_EN	BIT(0)
+ 
+ /* CDMP Exgress Control Register */
+ #define MTK_CDMP_EG_CTRL	0x404
+@@ -91,12 +90,27 @@
+ #define MTK_GDMA_TCS_EN		BIT(21)
+ #define MTK_GDMA_UCS_EN		BIT(20)
+ 
++/* GDMA Ingress Control Register */
++#define MTK_GDMA1_IG_CTRL(x)	(0x500 + (x * 0x1000))
++
+ /* Unicast Filter MAC Address Register - Low */
+ #define MTK_GDMA_MAC_ADRL(x)	(0x508 + (x * 0x1000))
+ 
+ /* Unicast Filter MAC Address Register - High */
+ #define MTK_GDMA_MAC_ADRH(x)	(0x50C + (x * 0x1000))
+ 
++/* QDMA RX Base Pointer Register */
++#define MTK_QRX_BASE_PTR0	0x1900
++#define MTK_QRX_BASE_PTR_CFG(x)	(MTK_QRX_BASE_PTR0 + (x * 0x10))
++
++/* QDMA RX Maximum Count Register */
++#define MTK_QRX_MAX_CNT0	0x1904
++#define MTK_QRX_MAX_CNT_CFG(x)	(MTK_QRX_MAX_CNT0 + (x * 0x10))
++
++/* QDMA RX CPU Pointer Register */
++#define MTK_QRX_CRX_IDX0	0x1908
++#define MTK_QRX_CRX_IDX_CFG(x)	(MTK_QRX_CRX_IDX0 + (x * 0x10))
++
+ /* PDMA RX Base Pointer Register */
+ #define MTK_PRX_BASE_PTR0	0x900
+ #define MTK_PRX_BASE_PTR_CFG(x)	(MTK_PRX_BASE_PTR0 + (x * 0x10))
+@@ -240,7 +254,10 @@
+ #define MTK_QDMA_INT_MASK	0x1A1C
+ 
+ /* QDMA Interrupt Mask Register */
++#define MTK_QDMA_HRED1		0x1A40
+ #define MTK_QDMA_HRED2		0x1A44
++#define MTK_QDMA_SRED1		0x1A48
++#define MTK_QDMA_SRED2		0x1A4c
+ 
+ /* QDMA TX Forward CPU Pointer Register */
+ #define MTK_QTX_CTX_PTR		0x1B00
+@@ -275,6 +292,7 @@
+ #define TX_DMA_TSO		BIT(28)
+ #define TX_DMA_FPORT_SHIFT	25
+ #define TX_DMA_FPORT_MASK	0x7
++#define TX_DMA_VQID0		BIT(17)
+ #define TX_DMA_INS_VLAN		BIT(16)
+ 
+ /* QDMA descriptor txd3 */
+@@ -294,7 +312,6 @@
+ 
+ /* QDMA descriptor rxd4 */
+ #define RX_DMA_L4_VALID		BIT(24)
+-#define RX_DMA_SP_TAG		BIT(22)
+ #define RX_DMA_FPORT_SHIFT	19
+ #define RX_DMA_FPORT_MASK	0x7
+ 
+@@ -310,6 +327,7 @@
+ 
+ /* Mac control registers */
+ #define MTK_MAC_MCR(x)		(0x10100 + (x * 0x100))
++#define MTK_MAC_MSR(x)		(0x10108 + (x * 0x100))
+ #define MAC_MCR_MAX_RX_1536	BIT(24)
+ #define MAC_MCR_IPG_CFG		(BIT(18) | BIT(16))
+ #define MAC_MCR_FORCE_MODE	BIT(15)
+@@ -495,7 +513,6 @@ struct mtk_tx_ring {
+ enum mtk_rx_flags {
+ 	MTK_RX_FLAGS_NORMAL = 0,
+ 	MTK_RX_FLAGS_HWLRO,
+-	MTK_RX_FLAGS_QDMA,
+ };
+ 
+ /* struct mtk_rx_ring -	This struct holds info describing a RX ring
+@@ -539,9 +556,9 @@ struct mtk_rx_ring {
+  * @pctl:		The register map pointing at the range used to setup
+  *			GMAC port drive/slew values
+  * @dma_refcnt:		track how many netdevs are using the DMA engine
+- * @tx_ring:		Pointer to the memory holding info about the TX ring
+- * @rx_ring:		Pointer to the memory holding info about the RX ring
+- * @rx_ring_qdma:	Pointer to the memory holding info about the QDMA RX ring
++ * @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_ring_qdma:	Pointer to the memore holding info about the RX ring (QDMA)
+  * @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
+@@ -563,6 +580,7 @@ struct mtk_eth {
+ 	struct net_device		*netdev[MTK_MAX_DEVS];
+ 	struct mtk_mac			*mac[MTK_MAX_DEVS];
+ 	int				irq[3];
++	cpumask_t			affinity_mask[3];
+ 	u32				msg_enable;
+ 	unsigned long			sysclk;
+ 	struct regmap			*ethsys;
+@@ -615,4 +633,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);
+ 
++extern unsigned int M2Q_table[16];
++
+ #endif /* MTK_ETH_H */

+ 0 - 41
target/linux/mediatek/patches-4.9/0083-mfd-led3.patch

@@ -1,41 +0,0 @@
-From patchwork Fri Feb 24 18:47:21 2017
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v4,4/4] mfd: mt6397: Add MT6323 LED support into MT6397 driver
-From: [email protected]
-X-Patchwork-Id: 9591021
-Message-Id: <[email protected]>
-To: <[email protected]>, <[email protected]>, <[email protected]>, 
- <[email protected]>, <[email protected]>, <[email protected]>,
- <[email protected]>
-Cc: [email protected], [email protected],
- Sean Wang <[email protected]>, [email protected],
- [email protected], [email protected],
- [email protected]
-Date: Sat, 25 Feb 2017 02:47:21 +0800
-
-From: Sean Wang <[email protected]>
-
-Add compatible string as "mt6323-led" that will make
-the OF core spawn child devices for the LED subnode
-of that MT6323 MFD device.
-
-Signed-off-by: Sean Wang <[email protected]>
----
- drivers/mfd/mt6397-core.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/drivers/mfd/mt6397-core.c
-+++ b/drivers/mfd/mt6397-core.c
-@@ -48,6 +48,10 @@ static const struct mfd_cell mt6323_devs
- 		.name = "mt6323-regulator",
- 		.of_compatible = "mediatek,mt6323-regulator"
- 	},
-+	{
-+		.name = "mt6323-led",
-+		.of_compatible = "mediatek,mt6323-led"
-+	},
- };
- 
- static const struct mfd_cell mt6397_devs[] = {

+ 0 - 38
target/linux/mediatek/patches-4.9/0086-pmic-led1.patch

@@ -1,38 +0,0 @@
-From patchwork Mon Mar 20 06:47:25 2017
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v6,
- 2/4] dt-bindings: mfd: Add the description for LED as the sub module
-From: [email protected]
-X-Patchwork-Id: 9633089
-Message-Id: <[email protected]>
-To: <[email protected]>, <[email protected]>, <[email protected]>, 
- <[email protected]>, <[email protected]>, <[email protected]>,
- <[email protected]>
-Cc: [email protected], [email protected],
- Sean Wang <[email protected]>, [email protected],
- [email protected], [email protected],
- [email protected]
-Date: Mon, 20 Mar 2017 14:47:25 +0800
-
-From: Sean Wang <[email protected]>
-
-This patch adds description for LED as the sub-module on MT6397/MT6323
-multifunction device.
-
-Signed-off-by: Sean Wang <[email protected]>
----
- Documentation/devicetree/bindings/mfd/mt6397.txt | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/Documentation/devicetree/bindings/mfd/mt6397.txt
-+++ b/Documentation/devicetree/bindings/mfd/mt6397.txt
-@@ -6,6 +6,7 @@ MT6397/MT6323 is a multifunction device
- - Audio codec
- - GPIO
- - Clock
-+- LED
- 
- It is interfaced to host controller using SPI interface by a proprietary hardware
- called PMIC wrapper or pwrap. MT6397/MT6323 MFD is a child device of pwrap.

+ 0 - 42
target/linux/mediatek/patches-4.9/0088-pmic-led3.patch

@@ -1,42 +0,0 @@
-From patchwork Mon Mar 20 06:47:27 2017
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v6,
- 4/4] mfd: mt6397: Align the placement at which the mfd_cell of LED is
- defined
-From: [email protected]
-X-Patchwork-Id: 9633079
-Message-Id: <[email protected]>
-To: <[email protected]>, <[email protected]>, <[email protected]>, 
- <[email protected]>, <[email protected]>, <[email protected]>,
- <[email protected]>
-Cc: [email protected], [email protected],
- Sean Wang <[email protected]>, [email protected],
- [email protected], [email protected],
- [email protected]
-Date: Mon, 20 Mar 2017 14:47:27 +0800
-
-From: Sean Wang <[email protected]>
-
-Align the placement as which the mfd_cell of LED is defined as the other
-members done on the structure.
-
-Signed-off-by: Sean Wang <[email protected]>
-Acked-by: Lee Jones <[email protected]>
----
- drivers/mfd/mt6397-core.c | 3 +--
- 1 file changed, 1 insertion(+), 2 deletions(-)
-
---- a/drivers/mfd/mt6397-core.c
-+++ b/drivers/mfd/mt6397-core.c
-@@ -47,8 +47,7 @@ static const struct mfd_cell mt6323_devs
- 	{
- 		.name = "mt6323-regulator",
- 		.of_compatible = "mediatek,mt6323-regulator"
--	},
--	{
-+	}, {
- 		.name = "mt6323-led",
- 		.of_compatible = "mediatek,mt6323-led"
- 	},

+ 0 - 44
target/linux/mediatek/patches-4.9/0092-dsa4.patch

@@ -1,44 +0,0 @@
-From patchwork Wed Mar 29 09:38:22 2017
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [net-next, v3,
- 4/5] net-next: ethernet: mediatek: add device_node of GMAC pointing
- into the netdev instance
-From: [email protected]
-X-Patchwork-Id: 9651097
-Message-Id: <[email protected]>
-To: <[email protected]>, <[email protected]>,
- <[email protected]>, <[email protected]>,
- <[email protected]>, <[email protected]>
-Cc: [email protected], [email protected], [email protected], 
- [email protected], [email protected],
- [email protected], 
- [email protected], [email protected], [email protected]
-Date: Wed, 29 Mar 2017 17:38:22 +0800
-
-From: Sean Wang <[email protected]>
-
-the patch adds the setup of the corresponding device node of GMAC into the
-netdev instance which could allow other modules such as DSA to find the
-instance through the node in dt-bindings using of_find_net_device_by_node()
-call.
-
-Signed-off-by: Sean Wang <[email protected]>
-Reviewed-by: Andrew Lunn <[email protected]>
-Reviewed-by: Florian Fainelli <[email protected]>
----
- 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
-@@ -2333,6 +2333,8 @@ static int mtk_add_mac(struct mtk_eth *e
- 	eth->netdev[id]->ethtool_ops = &mtk_ethtool_ops;
- 
- 	eth->netdev[id]->irq = eth->irq[0];
-+	eth->netdev[id]->dev.of_node = np;
-+
- 	return 0;
- 
- free_netdev:

+ 0 - 36
target/linux/mediatek/patches-4.9/0094-net-affinity.patch

@@ -1,36 +0,0 @@
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -2459,15 +2459,23 @@ static int mtk_probe(struct platform_dev
- 			goto err_deinit_hw;
- 	}
- 
-+	for (i = 0; i < 3; i++) {
-+		int cpu = i % num_online_cpus();
-+
-+		cpumask_set_cpu(cpu, &eth->affinity_mask[i]);
-+	}
-+
- 	err = devm_request_irq(eth->dev, eth->irq[1], mtk_handle_irq_tx, 0,
- 			       dev_name(eth->dev), eth);
- 	if (err)
- 		goto err_free_dev;
-+	irq_set_affinity_hint(eth->irq[1], &eth->affinity_mask[1]);
- 
- 	err = devm_request_irq(eth->dev, eth->irq[2], mtk_handle_irq_rx, 0,
- 			       dev_name(eth->dev), eth);
- 	if (err)
- 		goto err_free_dev;
-+	irq_set_affinity_hint(eth->irq[2], &eth->affinity_mask[2]);
- 
- 	err = mtk_mdio_init(eth);
- 	if (err)
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -539,6 +539,7 @@ struct mtk_eth {
- 	struct net_device		*netdev[MTK_MAX_DEVS];
- 	struct mtk_mac			*mac[MTK_MAX_DEVS];
- 	int				irq[3];
-+	cpumask_t			affinity_mask[3];
- 	u32				msg_enable;
- 	unsigned long			sysclk;
- 	struct regmap			*ethsys;

+ 0 - 12
target/linux/mediatek/patches-4.9/0200-devicetree.patch

@@ -1,12 +0,0 @@
---- a/arch/arm/boot/dts/Makefile
-+++ b/arch/arm/boot/dts/Makefile
-@@ -950,6 +950,9 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \
- 	mt6589-aquaris5.dtb \
- 	mt6592-evb.dtb \
- 	mt7623-evb.dtb \
-+	mt7623-eMMC.dtb \
-+	mt7623-NAND.dtb \
-+	mt7623-NAND-ePHY.dtb \
- 	mt8127-moose.dtb \
- 	mt8135-evbp1.dtb
- dtb-$(CONFIG_ARCH_ZX) += zx296702-ad1.dtb

+ 0 - 32
target/linux/mediatek/patches-4.9/0201-block2mtd.patch

@@ -1,32 +0,0 @@
---- a/drivers/mtd/devices/block2mtd.c
-+++ b/drivers/mtd/devices/block2mtd.c
-@@ -32,6 +32,8 @@
- #include <linux/slab.h>
- #include <linux/major.h>
- 
-+static const char * const block2mtd_probe_types[] = { "cmdlinepart", NULL };
-+
- /* Info for the block device */
- struct block2mtd_dev {
- 	struct list_head list;
-@@ -227,6 +229,7 @@ static struct block2mtd_dev *add_device(
- #endif
- 	const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL;
- 	struct block_device *bdev = ERR_PTR(-ENODEV);
-+	struct mtd_part_parser_data ppdata = { 0 };
- 	struct block2mtd_dev *dev;
- 	struct mtd_partition *part;
- 	char *name;
-@@ -307,11 +310,7 @@ static struct block2mtd_dev *add_device(
- 	dev->mtd.priv = dev;
- 	dev->mtd.owner = THIS_MODULE;
- 
--	part = kzalloc(sizeof(struct mtd_partition), GFP_KERNEL);
--	part->name = name;
--	part->offset = 0;
--	part->size = dev->mtd.size;
--	if (mtd_device_register(&dev->mtd, part, 1)) {
-+	if (mtd_device_parse_register(&dev->mtd, block2mtd_probe_types, &ppdata, NULL, 0)) {
- 		/* Device didn't get added, so free the entry */
- 		goto err_destroy_mutex;
- 	}