Kaynağa Gözat

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 yıl önce
ebeveyn
işleme
1f068588ef
92 değiştirilmiş dosya ile 10641 ekleme ve 599 silme
  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"
 
 	case $board in
+	'bananapi,bpi-r2' | \
 	'mediatek,mt7623-rfb-emmc' | \
 	'mediatek,mt7623-rfb-nand-ephy')
 		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
 		return $?
 		;;
+	bananapi,bpi-r2 |\
 	mediatek,mt7623-rfb-emmc)
 		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`

+ 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_ATAGS=y
 CONFIG_AUTO_ZRELADDR=y
-# CONFIG_BINFMT_FLAT is not set
 CONFIG_BLK_MQ_PCI=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
@@ -104,13 +103,29 @@ CONFIG_CRC32_SLICEBY8=y
 CONFIG_CROSS_MEMORY_ATTACH=y
 CONFIG_CRYPTO_AEAD=y
 CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_CTR=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_HMAC=y
+CONFIG_CRYPTO_HW=y
+CONFIG_CRYPTO_JITTERENTROPY=y
 CONFIG_CRYPTO_LZO=y
 CONFIG_CRYPTO_MANAGER=y
 CONFIG_CRYPTO_MANAGER2=y
+CONFIG_CRYPTO_NULL=y
 CONFIG_CRYPTO_NULL2=y
+CONFIG_CRYPTO_RNG=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_DCACHE_WORD_ACCESS=y
 CONFIG_DEBUG_BUGVERBOSE=y
@@ -213,6 +228,7 @@ CONFIG_HIGHMEM=y
 CONFIG_HOTPLUG_CPU=y
 CONFIG_HWMON=y
 CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MTK=y
 CONFIG_HZ_FIXED=0
 CONFIG_I2C=y
 CONFIG_I2C_BOARDINFO=y
@@ -254,7 +270,6 @@ CONFIG_MDIO_GPIO=y
 CONFIG_MEDIATEK_MT6577_AUXADC=y
 CONFIG_MEDIATEK_WATCHDOG=y
 CONFIG_MFD_CORE=y
-# CONFIG_MFD_MAX77620 is not set
 CONFIG_MFD_MT6397=y
 CONFIG_MFD_SYSCON=y
 CONFIG_MIGHT_HAVE_CACHE_L2X0=y
@@ -275,7 +290,6 @@ CONFIG_MTD_MT81xx_NOR=y
 CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_ECC=y
 CONFIG_MTD_NAND_MTK=y
-# CONFIG_MTD_PHYSMAP_OF_VERSATILE is not set
 CONFIG_MTD_SPI_NOR=y
 CONFIG_MTD_UBI=y
 CONFIG_MTD_UBI_BEB_LIMIT=20
@@ -300,6 +314,8 @@ CONFIG_NET_DSA=y
 CONFIG_NET_DSA_MT7530=y
 CONFIG_NET_DSA_TAG_MTK=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_SWITCHDEV=y
 # CONFIG_NET_VENDOR_AURORA is not set
@@ -329,7 +345,10 @@ CONFIG_OLD_SIGSUSPEND3=y
 CONFIG_PADATA=y
 CONFIG_PAGE_OFFSET=0xC0000000
 CONFIG_PCI=y
+CONFIG_PCIEAER=y
+CONFIG_PCIEPORTBUS=y
 CONFIG_PCIE_MTK=y
+CONFIG_PCIE_PME=y
 CONFIG_PCI_DOMAINS=y
 CONFIG_PCI_DOMAINS_GENERIC=y
 CONFIG_PCI_MSI=y
@@ -366,6 +385,7 @@ CONFIG_PWM=y
 CONFIG_PWM_MEDIATEK=y
 # CONFIG_PWM_MTK_DISP is not set
 CONFIG_PWM_SYSFS=y
+CONFIG_RAS=y
 CONFIG_RATIONAL=y
 CONFIG_RCU_CPU_STALL_TIMEOUT=21
 # 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/reset/mt2701-resets.h>
 #include <dt-bindings/pinctrl/mt7623-pinfunc.h>
+#include <dt-bindings/gpio/gpio.h>
 #include "skeleton64.dtsi"
 
 
@@ -151,7 +152,7 @@
 	};
 
 	pio: pinctrl@10005000 {
-		compatible = "mediatek,mt2701-pinctrl";
+		compatible = "mediatek,mt7623-pinctrl";
 		reg = <0 0x1000b000 0 0x1000>;
 		mediatek,pctl-regmap = <&syscfg_pctl_a>;
 		pins-are-numbered;
@@ -211,6 +212,15 @@
 		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 {
 		compatible = "mediatek,mt7623-sysirq",
 			     "mediatek,mt6577-sysirq";
@@ -240,6 +250,13 @@
 		#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 {
 		compatible = "arm,cortex-a7-gic";
 		interrupt-controller;
@@ -370,7 +387,7 @@
 		status = "disabled";
 	};
 
-	spi: spi@1100a000 {
+	spi0: spi@1100a000 {
 		compatible = "mediatek,mt7623-spi",
 			     "mediatek,mt6589-spi";
 		reg = <0 0x1100a000 0 0x1000>;
@@ -399,6 +416,34 @@
 		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 {
 		compatible = "mediatek,mt7623-nfc",
 			     "mediatek,mt2701-nfc";
@@ -424,6 +469,104 @@
 		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 {
 		compatible = "mediatek,mt7623-mmc",
 			     "mediatek,mt8135-mmc";
@@ -636,4 +779,26 @@
 			#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>;
 		};
 
-		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 {
 			pinmux = <MT7623_PIN_15_GPIO15_FUNC_GPIO15>;
 			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>;
 		};
 
-		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 {
 			pinmux = <MT7623_PIN_15_GPIO15_FUNC_GPIO15>;
 			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>;
 		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 {
@@ -428,7 +483,6 @@
 				 <MT7623_PIN_270_G2_RXD1_FUNC_G2_RXD1>,
 				 <MT7623_PIN_271_G2_RXD2_FUNC_G2_RXD2>,
 				 <MT7623_PIN_272_G2_RXD3_FUNC_G2_RXD3>,
-				 <MT7623_PIN_273_ESW_INT_FUNC_ESW_INT>,
 				 <MT7623_PIN_274_G2_RXDV_FUNC_G2_RXDV>;
 		};
 
@@ -480,59 +534,6 @@
 };
 
 &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 {
 		reg = <5>;
 		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
 	$(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)
 endef
 
@@ -20,6 +20,7 @@ endif
 	)
 endef
 
+COMPAT_BPI-R2:=bananapi,bpi-r2
 COMPAT_EMMC:=mediatek,mt7623-rfb-emmc
 COMPAT_NAND:=mediatek,mt7623-rfb-nand
 COMPAT_NAND_EPHY:=mediatek,mt7623-rfb-nand-ephy
@@ -28,16 +29,17 @@ define Image/Build/squashfs
 	$(call prepare_generic_squashfs,$(KDIR)/root.squashfs)
 	$(CP) $(KDIR)/root.squashfs $(BIN_DIR)/$(IMG_PREFIX)-root.squashfs
 
-	$(call Image/Build/SysupgradeCombined,eMMC,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),)
-	$(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
-	$(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

+ 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]>
 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]>
 ---
- .../devicetree/bindings/pci/mediatek-pcie.txt      |  140 ++++++++++++++++++++
+ .../devicetree/bindings/pci/mediatek-pcie.txt      | 140 +++++++++++++++++++++
  1 file changed, 140 insertions(+)
  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]>
 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
 
 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]>
 ---
- 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(+)
  create mode 100644 drivers/pci/host/pcie-mediatek.c
 
 --- a/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
  	bool "MediaTek MT7623 SoCs support"
  	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]>
 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.
 
@@ -11,9 +11,9 @@ Acked-by: Rob Herring <[email protected]>
 Reviewed-by: Kevin Hilman <[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
 
 --- 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]>
 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,
 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]>
 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
 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]>
 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(+)
 
 --- 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]>
 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
 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]>
 Acked-by: Linus Walleij <[email protected]>
 ---
- arch/arm/mach-mediatek/Kconfig |    4 ++++
+ arch/arm/mach-mediatek/Kconfig | 4 ++++
  1 file changed, 4 insertions(+)
 
 --- 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]>
 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.
 

+ 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]>
 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.
 
@@ -14,8 +14,8 @@ Reviewed-by: Kevin Hilman <[email protected]>
 Signed-off-by: Matthias Brugger <[email protected]>
 ---
  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
 +++ 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]>
 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,
 
@@ -14,9 +14,8 @@ thanks,
 
 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
 +++ 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]>
 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
 +++ 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]>
 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]>
 ---
- drivers/clk/clk.c |    2 +-
+ drivers/clk/clk.c | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)
 
 --- 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]>
 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]>
 ---
- drivers/clk/mediatek/clk-mt2701.c |   22 ++++++++++++++++++++--
+ drivers/clk/mediatek/clk-mt2701.c | 22 ++++++++++++++++++++--
  1 file changed, 20 insertions(+), 2 deletions(-)
 
 --- 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]>
 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
 for intermediate clock source switching.
 
 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(-)
  create mode 100644 drivers/clk/mediatek/clk-cpumux.c
  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]>
 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]>
 ---
- 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(+)
  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]>
 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]>
 ---
- 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
 
 --- 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]>
+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
 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]>
+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.
 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]>
 ---
  drivers/leds/Kconfig       |   8 +
- drivers/leds/Makefile      |   1 +
  drivers/leds/leds-mt6323.c | 502 +++++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 511 insertions(+)
+ 2 files changed, 510 insertions(+)
  create mode 100644 drivers/leds/leds-mt6323.c
 
 --- 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
 +++ b/drivers/mtd/nand/mtk_nand.c
 @@ -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]>
+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.
 

+ 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]>
 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
 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]>
 ---
- 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
 +++ 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)) |
  				(!nr_frags * TX_DMA_LS0)));
  
@@ -36,7 +36,7 @@ Signed-off-by: John Crispin <[email protected]>
  	skb_tx_timestamp(skb);
  
  	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 sk_buff *skb;
  	struct mtk_tx_buf *tx_buf;
@@ -60,9 +60,9 @@ Signed-off-by: John Crispin <[email protected]>
 -	while ((cpu != dma) && budget) {
 +	while ((cpu != dma) && done < budget) {
  		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) {
@@ -74,7 +74,7 @@ Signed-off-by: John Crispin <[email protected]>
  		}
  		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);
  

+ 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]>
+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
 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]>
+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
 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
 +++ 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
 +	 * 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
 +++ 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 */
 +#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]>
+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
 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
 +++ b/drivers/net/dsa/mt7530.c
 @@ -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
 +++ b/drivers/net/dsa/mt7530.c
 @@ -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
 +++ b/drivers/net/dsa/mt7530.c
 @@ -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
 +++ b/drivers/net/dsa/mt7530.c
 @@ -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;
- 	}